diff --git a/android/app/build.gradle b/android/app/build.gradle new file mode 100644 index 000000000..ece3df2a0 --- /dev/null +++ b/android/app/build.gradle @@ -0,0 +1,52 @@ +apply plugin: 'com.android.application' + +repositories { + mavenCentral() +} + +android { + compileSdkVersion 19 + buildToolsVersion "21.1.1" + + defaultConfig { + applicationId "com.mogujie.tt" + minSdkVersion 11 + targetSdkVersion 19 + } + + buildTypes { + release { + minifyEnabled false + proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.txt' + } + } + + sourceSets.main.jni.srcDirs = [] //disable automatic ndk-build call + + compileOptions { + sourceCompatibility JavaVersion.VERSION_1_7 + targetCompatibility JavaVersion.VERSION_1_7 + } + + lintOptions { + abortOnError false + } + + packagingOptions { + exclude 'META-INF/LICENSE.txt' + exclude 'META-INF/NOTICE.txt' + } +} + +dependencies { + compile project(':mgimlibs') + compile fileTree(dir: 'libs', include: ['*.jar']) + compile 'com.android.support:appcompat-v7:19.+' + compile 'com.google.protobuf:protobuf-java:2.6.1' + compile 'de.greenrobot:eventbus:2.4.0' + compile 'de.greenrobot:greendao:1.3.7' + compile 'com.google.code.gson:gson:2.3.1' + compile 'com.squareup.okhttp:okhttp:2.0.0' + compile 'com.squareup.okhttp:okhttp-urlconnection:2.0.0' + compile 'commons-io:commons-io:2.4' +} diff --git a/android/app/libs/android-async-http-1.4.6.jar b/android/app/libs/android-async-http-1.4.6.jar new file mode 100644 index 000000000..70391cb95 Binary files /dev/null and b/android/app/libs/android-async-http-1.4.6.jar differ diff --git a/android/app/libs/netty-3.6.6.Final.jar b/android/app/libs/netty-3.6.6.Final.jar new file mode 100644 index 000000000..35cb0730c Binary files /dev/null and b/android/app/libs/netty-3.6.6.Final.jar differ diff --git a/android/app/libs/universal-image-loader-1.9.3.jar b/android/app/libs/universal-image-loader-1.9.3.jar new file mode 100644 index 000000000..e8ca33b75 Binary files /dev/null and b/android/app/libs/universal-image-loader-1.9.3.jar differ diff --git a/android/app/src/main/AndroidManifest.xml b/android/app/src/main/AndroidManifest.xml new file mode 100644 index 000000000..540df7cc4 --- /dev/null +++ b/android/app/src/main/AndroidManifest.xml @@ -0,0 +1,155 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/android/app/src/main/java/com/mogujie/tt/DB/DBInterface.java b/android/app/src/main/java/com/mogujie/tt/DB/DBInterface.java new file mode 100644 index 000000000..9c3474d00 --- /dev/null +++ b/android/app/src/main/java/com/mogujie/tt/DB/DBInterface.java @@ -0,0 +1,490 @@ +package com.mogujie.tt.DB; + +import android.content.Context; +import android.database.Cursor; +import android.database.sqlite.SQLiteDatabase; + +import com.mogujie.tt.DB.dao.DaoMaster; +import com.mogujie.tt.DB.dao.DaoSession; +import com.mogujie.tt.DB.dao.DepartmentDao; +import com.mogujie.tt.DB.dao.GroupDao; +import com.mogujie.tt.DB.dao.MessageDao; +import com.mogujie.tt.DB.dao.SessionDao; +import com.mogujie.tt.DB.dao.UserDao; +import com.mogujie.tt.DB.entity.DepartmentEntity; +import com.mogujie.tt.DB.entity.GroupEntity; +import com.mogujie.tt.DB.entity.MessageEntity; +import com.mogujie.tt.DB.entity.SessionEntity; +import com.mogujie.tt.DB.entity.UserEntity; +import com.mogujie.tt.config.DBConstant; +import com.mogujie.tt.config.MessageConstant; +import com.mogujie.tt.imservice.entity.AudioMessage; +import com.mogujie.tt.imservice.entity.ImageMessage; +import com.mogujie.tt.imservice.entity.MixMessage; +import com.mogujie.tt.imservice.entity.TextMessage; +import com.mogujie.tt.utils.Logger; + +import org.json.JSONException; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import java.util.Set; +import java.util.TreeSet; + +import de.greenrobot.dao.query.DeleteQuery; +import de.greenrobot.dao.query.Query; +import de.greenrobot.dao.query.QueryBuilder; +/** + * @author : yingmu on 15-1-5. + * @email : yingmu@mogujie.com. + * + * 有两个静态标识可开启QueryBuilder的SQL和参数的日志输出: + * QueryBuilder.LOG_SQL = true; + * QueryBuilder.LOG_VALUES = true; + */ +public class DBInterface { + private Logger logger = Logger.getLogger(DBInterface.class); + private static DBInterface dbInterface = null; + private DaoMaster.DevOpenHelper openHelper; + private Context context = null; + private int loginUserId =0; + + public static DBInterface instance(){ + if (dbInterface == null) { + synchronized (DBInterface.class) { + if (dbInterface == null) { + dbInterface = new DBInterface(); + } + } + } + return dbInterface; + } + + private DBInterface(){ + } + + /** + * 上下文环境的更新 + * 1. 环境变量的clear + * check + */ + public void close() { + if(openHelper !=null) { + openHelper.close(); + openHelper = null; + context = null; + loginUserId = 0; + } + } + + + public void initDbHelp(Context ctx,int loginId){ + if(ctx == null || loginId <=0 ){ + throw new RuntimeException("#DBInterface# init DB exception!"); + } + // 临时处理,为了解决离线登陆db实例初始化的过程 + if(context != ctx || loginUserId !=loginId ){ + context = ctx; + loginUserId = loginId; + close(); + logger.i("DB init,loginId:%d",loginId); + String DBName = "tt_"+loginId+".db"; + DaoMaster.DevOpenHelper helper = new DaoMaster.DevOpenHelper(ctx, DBName, null); + this.openHelper = helper; + } + } + + /** + * Query for readable DB + */ + private DaoSession openReadableDb() { + isInitOk(); + SQLiteDatabase db = openHelper.getReadableDatabase(); + DaoMaster daoMaster = new DaoMaster(db); + DaoSession daoSession = daoMaster.newSession(); + return daoSession; + } + + /** + * Query for writable DB + */ + private DaoSession openWritableDb(){ + isInitOk(); + SQLiteDatabase db = openHelper.getWritableDatabase(); + DaoMaster daoMaster = new DaoMaster(db); + DaoSession daoSession = daoMaster.newSession(); + return daoSession; + } + + + private void isInitOk(){ + if(openHelper ==null){ + logger.e("DBInterface#isInit not success or start,cause by openHelper is null"); + // 抛出异常 todo + throw new RuntimeException("DBInterface#isInit not success or start,cause by openHelper is null"); + } + } + + + /**-------------------------下面开始department 操作相关---------------------------------------*/ + public void batchInsertOrUpdateDepart(List entityList){ + if(entityList.size() <=0){ + return ; + } + DepartmentDao dao = openWritableDb().getDepartmentDao(); + dao.insertOrReplaceInTx(entityList); + } + + /**update*/ + public int getDeptLastTime(){ + DepartmentDao dao = openReadableDb().getDepartmentDao(); + DepartmentEntity entity = dao.queryBuilder() + .orderDesc(DepartmentDao.Properties.Updated) + .limit(1) + .unique(); + if(entity == null){ + return 0; + }else{ + return entity.getUpdated(); + } + } + + // 部门被删除的情况 + public List loadAllDept(){ + DepartmentDao dao = openReadableDb().getDepartmentDao(); + List result = dao.loadAll(); + return result; + } + + /**-------------------------下面开始User 操作相关---------------------------------------*/ + /** + * @return + * todo USER_STATUS_LEAVE + */ + public List loadAllUsers(){ + UserDao dao = openReadableDb().getUserDao(); + List result = dao.loadAll(); + return result; + } + + public UserEntity getByUserName(String uName){ + UserDao dao = openReadableDb().getUserDao(); + UserEntity entity = dao.queryBuilder().where(UserDao.Properties.PinyinName.eq(uName)).unique(); + return entity; + } + + public UserEntity getByLoginId(int loginId){ + UserDao dao = openReadableDb().getUserDao(); + UserEntity entity = dao.queryBuilder().where(UserDao.Properties.PeerId.eq(loginId)).unique(); + return entity; + } + + + public void insertOrUpdateUser(UserEntity entity){ + UserDao userDao = openWritableDb().getUserDao(); + long rowId = userDao.insertOrReplace(entity); + } + + public void batchInsertOrUpdateUser(List entityList){ + if(entityList.size() <=0){ + return ; + } + UserDao userDao = openWritableDb().getUserDao(); + userDao.insertOrReplaceInTx(entityList); + } + + /**update*/ + public int getUserInfoLastTime(){ + UserDao sessionDao = openReadableDb().getUserDao(); + UserEntity userEntity = sessionDao.queryBuilder() + .orderDesc(UserDao.Properties.Updated) + .limit(1) + .unique(); + if(userEntity == null){ + return 0; + }else{ + return userEntity.getUpdated(); + } + } + + /**-------------------------下面开始Group 操作相关---------------------------------------*/ + /** + * 载入Group的所有数据 + * @return + */ + public List loadAllGroup(){ + GroupDao dao = openReadableDb().getGroupDao(); + List result = dao.loadAll(); + return result; + } + public long insertOrUpdateGroup(GroupEntity groupEntity){ + GroupDao dao = openWritableDb().getGroupDao(); + long pkId = dao.insertOrReplace(groupEntity); + return pkId; + } + public void batchInsertOrUpdateGroup(List entityList){ + if(entityList.size() <=0){ + return; + } + GroupDao dao = openWritableDb().getGroupDao(); + dao.insertOrReplaceInTx(entityList); + } + + /**-------------------------下面开始session 操作相关---------------------------------------*/ + /** + * 载入session 表中的所有数据 + * @return + */ + public List loadAllSession(){ + SessionDao dao = openReadableDb().getSessionDao(); + List result = dao.queryBuilder() + .orderDesc(SessionDao.Properties.Updated) + .list(); + return result; + } + + public long insertOrUpdateSession(SessionEntity sessionEntity){ + SessionDao dao = openWritableDb().getSessionDao(); + long pkId = dao.insertOrReplace(sessionEntity); + return pkId; + } + public void batchInsertOrUpdateSession(List entityList){ + if(entityList.size() <=0){ + return; + } + SessionDao dao = openWritableDb().getSessionDao(); + dao.insertOrReplaceInTx(entityList); + } + + public void deleteSession(String sessionKey){ + SessionDao sessionDao = openWritableDb().getSessionDao(); + DeleteQuery bd = sessionDao.queryBuilder() + .where(SessionDao.Properties.SessionKey.eq(sessionKey)) + .buildDelete(); + + bd.executeDeleteWithoutDetachingEntities(); + } + + /** + * 获取最后回话的时间,便于获取联系人列表变化 + * 问题: 本地消息发送失败,依旧会更新session的时间 [存在会话、不存在的会话] + * 本质上还是最后一条成功消息的时间 + * @return + */ + public int getSessionLastTime(){ + int timeLine = 0; + MessageDao messageDao = openReadableDb().getMessageDao(); + String successType = String.valueOf(MessageConstant.MSG_SUCCESS); + String sql = "select created from Message where status=? order by created desc limit 1"; + Cursor cursor = messageDao.getDatabase().rawQuery(sql, new String[]{successType}); + try { + if(cursor!=null && cursor.getCount() ==1){ + cursor.moveToFirst(); + timeLine = cursor.getInt(0); + } + }catch (Exception e){ + logger.e("DBInterface#getSessionLastTime cursor 查询异常"); + }finally { + cursor.close(); + } + return timeLine; + } + + /**-------------------------下面开始message 操作相关---------------------------------------*/ + + // where (msgId >= startMsgId and msgId<=lastMsgId) or + // (msgId=0 and status = 0) + // order by created desc + // limit count; + // 按照时间排序 + public List getHistoryMsg(String chatKey,int lastMsgId,int lastCreateTime,int count){ + /**解决消息重复的问题*/ + int preMsgId = lastMsgId +1; + MessageDao dao = openReadableDb().getMessageDao(); + List listMsg = dao.queryBuilder().where(MessageDao.Properties.Created.le(lastCreateTime) + , MessageDao.Properties.SessionKey.eq(chatKey) + ,MessageDao.Properties.MsgId.notEq(preMsgId)) + .whereOr(MessageDao.Properties.MsgId.le(lastMsgId), + MessageDao.Properties.MsgId.gt(90000000)) + .orderDesc(MessageDao.Properties.Created) + .orderDesc(MessageDao.Properties.MsgId) + .limit(count) + .list(); + + return formatMessage(listMsg); + } + + /** + * IMGetLatestMsgIdReq 后去最后一条合法的msgid + * */ + public List refreshHistoryMsgId(String chatKey, int beginMsgId, int lastMsgId){ + MessageDao dao = openReadableDb().getMessageDao(); + + String sql = "select MSG_ID from Message where SESSION_KEY = ? and MSG_ID >= ? and MSG_ID <= ? order by MSG_ID asc"; + Cursor cursor = dao.getDatabase().rawQuery(sql, new String[]{chatKey, String.valueOf(beginMsgId), String.valueOf(lastMsgId)}); + + List msgIdList = new ArrayList<>(); + try { + for (cursor.moveToFirst(); !cursor.isAfterLast(); cursor.moveToNext()) { + int msgId = cursor.getInt(0); + msgIdList.add(msgId); + } + }finally { + cursor.close(); + } + return msgIdList; + } + + + public long insertOrUpdateMix(MessageEntity message){ + MessageDao dao = openWritableDb().getMessageDao(); + MessageEntity parent = dao.queryBuilder().where(MessageDao.Properties.MsgId.eq(message.getMsgId()) + ,MessageDao.Properties.SessionKey.eq(message.getSessionKey())).unique(); + + long resId = parent.getId(); + if(parent.getDisplayType() != DBConstant.SHOW_MIX_TEXT){ + return resId; + } + + boolean needUpdate = false; + MixMessage mixParent = (MixMessage) formatMessage(parent); + List msgList = mixParent.getMsgList(); + for(int index =0;index < msgList.size(); index ++){ + if(msgList.get(index).getId() == message.getId()){ + msgList.set(index, message); + needUpdate = true; + break; + } + } + + if(needUpdate){ + mixParent.setMsgList(msgList); + long pkId = dao.insertOrReplace(mixParent); + return pkId; + } + return resId; + } + + /**有可能是混合消息 + * 批量接口{batchInsertOrUpdateMessage} 没有存在场景 + * */ + public long insertOrUpdateMessage(MessageEntity message){ + if(message.getId()!=null && message.getId() < 0){ + // mix消息 + return insertOrUpdateMix(message); + } + MessageDao dao = openWritableDb().getMessageDao(); + long pkId = dao.insertOrReplace(message); + return pkId; + } + + /** + * todo 这个地方调用存在特殊场景,如果list中包含Id为负Mix子类型,更新就有问题 + * 现在的调用列表没有这个情景,使用的时候注意 + * */ + public void batchInsertOrUpdateMessage(List entityList){ + MessageDao dao = openWritableDb().getMessageDao(); + dao.insertOrReplaceInTx(entityList); + } + + + public void deleteMessageById(long localId){ + if(localId<=0){return;} + Set setIds = new TreeSet<>(); + setIds.add(localId); + batchDeleteMessageById(setIds); + } + + public void batchDeleteMessageById(Set pkIds){ + if(pkIds.size() <=0){ + return; + } + MessageDao dao = openWritableDb().getMessageDao(); + dao.deleteByKeyInTx(pkIds); + } + + public void deleteMessageByMsgId(int msgId){ + if(msgId <= 0){ + return; + } + MessageDao messageDao = openWritableDb().getMessageDao(); + QueryBuilder qb = openWritableDb().getMessageDao().queryBuilder(); + DeleteQuery bd = qb.where(MessageDao.Properties.MsgId.eq(msgId)).buildDelete(); + bd.executeDeleteWithoutDetachingEntities(); + } + + public MessageEntity getMessageByMsgId(int messageId){ + MessageDao dao = openReadableDb().getMessageDao(); + Query query = dao.queryBuilder().where( + MessageDao.Properties.Id.eq(messageId)) + .build(); + return formatMessage((MessageEntity)query.unique()); + } + + /**根据主键查询 + * not use + * */ + public MessageEntity getMessageById(long localId){ + MessageDao dao = openReadableDb().getMessageDao(); + MessageEntity messageEntity= + dao.queryBuilder().where(MessageDao.Properties.Id.eq(localId)).unique(); + return formatMessage(messageEntity); + } + + + private MessageEntity formatMessage(MessageEntity msg){ + MessageEntity messageEntity = null; + int displayType = msg.getDisplayType(); + switch (displayType){ + case DBConstant.SHOW_MIX_TEXT: + try { + messageEntity = MixMessage.parseFromDB(msg); + } catch (JSONException e) { + logger.e(e.toString()); + } + break; + case DBConstant.SHOW_AUDIO_TYPE: + messageEntity = AudioMessage.parseFromDB(msg); + break; + case DBConstant.SHOW_IMAGE_TYPE: + messageEntity = ImageMessage.parseFromDB(msg); + break; + case DBConstant.SHOW_ORIGIN_TEXT_TYPE: + messageEntity = TextMessage.parseFromDB(msg); + break; + } + return messageEntity; + } + + + public List formatMessage(List msgList){ + if(msgList.size() <= 0){ + return Collections.emptyList(); + } + ArrayList newList = new ArrayList<>(); + for(MessageEntity info:msgList){ + int displayType = info.getDisplayType(); + switch (displayType){ + case DBConstant.SHOW_MIX_TEXT: + try { + newList.add(MixMessage.parseFromDB(info)); + } catch (JSONException e) { + logger.e(e.toString()); + } + break; + case DBConstant.SHOW_AUDIO_TYPE: + newList.add(AudioMessage.parseFromDB(info)); + break; + case DBConstant.SHOW_IMAGE_TYPE: + newList.add(ImageMessage.parseFromDB(info)); + break; + case DBConstant.SHOW_ORIGIN_TEXT_TYPE: + newList.add(TextMessage.parseFromDB(info)); + break; + } + } + return newList; + } + +} diff --git a/android/app/src/main/java/com/mogujie/tt/DB/dao/DaoMaster.java b/android/app/src/main/java/com/mogujie/tt/DB/dao/DaoMaster.java new file mode 100644 index 000000000..ef2a62a00 --- /dev/null +++ b/android/app/src/main/java/com/mogujie/tt/DB/dao/DaoMaster.java @@ -0,0 +1,86 @@ +package com.mogujie.tt.DB.dao; + +import android.content.Context; +import android.database.sqlite.SQLiteDatabase; +import android.database.sqlite.SQLiteDatabase.CursorFactory; +import android.database.sqlite.SQLiteOpenHelper; +import android.util.Log; +import de.greenrobot.dao.AbstractDaoMaster; +import de.greenrobot.dao.identityscope.IdentityScopeType; + +import com.mogujie.tt.DB.dao.DepartmentDao; +import com.mogujie.tt.DB.dao.UserDao; +import com.mogujie.tt.DB.dao.GroupDao; +import com.mogujie.tt.DB.dao.MessageDao; +import com.mogujie.tt.DB.dao.SessionDao; + +// THIS CODE IS GENERATED BY greenDAO, DO NOT EDIT. +/** + * Master of DAO (schema version 12): knows all DAOs. +*/ +public class DaoMaster extends AbstractDaoMaster { + public static final int SCHEMA_VERSION = 12; + + /** Creates underlying database table using DAOs. */ + public static void createAllTables(SQLiteDatabase db, boolean ifNotExists) { + DepartmentDao.createTable(db, ifNotExists); + UserDao.createTable(db, ifNotExists); + GroupDao.createTable(db, ifNotExists); + MessageDao.createTable(db, ifNotExists); + SessionDao.createTable(db, ifNotExists); + } + + /** Drops underlying database table using DAOs. */ + public static void dropAllTables(SQLiteDatabase db, boolean ifExists) { + DepartmentDao.dropTable(db, ifExists); + UserDao.dropTable(db, ifExists); + GroupDao.dropTable(db, ifExists); + MessageDao.dropTable(db, ifExists); + SessionDao.dropTable(db, ifExists); + } + + public static abstract class OpenHelper extends SQLiteOpenHelper { + + public OpenHelper(Context context, String name, CursorFactory factory) { + super(context, name, factory, SCHEMA_VERSION); + } + + @Override + public void onCreate(SQLiteDatabase db) { + Log.i("greenDAO", "Creating tables for schema version " + SCHEMA_VERSION); + createAllTables(db, false); + } + } + + /** WARNING: Drops all table on Upgrade! Use only during development. */ + public static class DevOpenHelper extends OpenHelper { + public DevOpenHelper(Context context, String name, CursorFactory factory) { + super(context, name, factory); + } + + @Override + public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) { + Log.i("greenDAO", "Upgrading schema from version " + oldVersion + " to " + newVersion + " by dropping all tables"); + dropAllTables(db, true); + onCreate(db); + } + } + + public DaoMaster(SQLiteDatabase db) { + super(db, SCHEMA_VERSION); + registerDaoClass(DepartmentDao.class); + registerDaoClass(UserDao.class); + registerDaoClass(GroupDao.class); + registerDaoClass(MessageDao.class); + registerDaoClass(SessionDao.class); + } + + public DaoSession newSession() { + return new DaoSession(db, IdentityScopeType.Session, daoConfigMap); + } + + public DaoSession newSession(IdentityScopeType type) { + return new DaoSession(db, type, daoConfigMap); + } + +} diff --git a/android/app/src/main/java/com/mogujie/tt/DB/dao/DaoSession.java b/android/app/src/main/java/com/mogujie/tt/DB/dao/DaoSession.java new file mode 100644 index 000000000..7faef4a25 --- /dev/null +++ b/android/app/src/main/java/com/mogujie/tt/DB/dao/DaoSession.java @@ -0,0 +1,105 @@ +package com.mogujie.tt.DB.dao; + +import android.database.sqlite.SQLiteDatabase; + +import java.util.Map; + +import de.greenrobot.dao.AbstractDao; +import de.greenrobot.dao.AbstractDaoSession; +import de.greenrobot.dao.identityscope.IdentityScopeType; +import de.greenrobot.dao.internal.DaoConfig; + +import com.mogujie.tt.DB.entity.DepartmentEntity; +import com.mogujie.tt.DB.entity.UserEntity; +import com.mogujie.tt.DB.entity.GroupEntity; +import com.mogujie.tt.DB.entity.MessageEntity; +import com.mogujie.tt.DB.entity.SessionEntity; + +import com.mogujie.tt.DB.dao.DepartmentDao; +import com.mogujie.tt.DB.dao.UserDao; +import com.mogujie.tt.DB.dao.GroupDao; +import com.mogujie.tt.DB.dao.MessageDao; +import com.mogujie.tt.DB.dao.SessionDao; + +// THIS CODE IS GENERATED BY greenDAO, DO NOT EDIT. + +/** + * {@inheritDoc} + * + * @see de.greenrobot.dao.AbstractDaoSession + */ +public class DaoSession extends AbstractDaoSession { + + private final DaoConfig departmentDaoConfig; + private final DaoConfig userDaoConfig; + private final DaoConfig groupDaoConfig; + private final DaoConfig messageDaoConfig; + private final DaoConfig sessionDaoConfig; + + private final DepartmentDao departmentDao; + private final UserDao userDao; + private final GroupDao groupDao; + private final MessageDao messageDao; + private final SessionDao sessionDao; + + public DaoSession(SQLiteDatabase db, IdentityScopeType type, Map>, DaoConfig> + daoConfigMap) { + super(db); + + departmentDaoConfig = daoConfigMap.get(DepartmentDao.class).clone(); + departmentDaoConfig.initIdentityScope(type); + + userDaoConfig = daoConfigMap.get(UserDao.class).clone(); + userDaoConfig.initIdentityScope(type); + + groupDaoConfig = daoConfigMap.get(GroupDao.class).clone(); + groupDaoConfig.initIdentityScope(type); + + messageDaoConfig = daoConfigMap.get(MessageDao.class).clone(); + messageDaoConfig.initIdentityScope(type); + + sessionDaoConfig = daoConfigMap.get(SessionDao.class).clone(); + sessionDaoConfig.initIdentityScope(type); + + departmentDao = new DepartmentDao(departmentDaoConfig, this); + userDao = new UserDao(userDaoConfig, this); + groupDao = new GroupDao(groupDaoConfig, this); + messageDao = new MessageDao(messageDaoConfig, this); + sessionDao = new SessionDao(sessionDaoConfig, this); + + registerDao(DepartmentEntity.class, departmentDao); + registerDao(UserEntity.class, userDao); + registerDao(GroupEntity.class, groupDao); + registerDao(MessageEntity.class, messageDao); + registerDao(SessionEntity.class, sessionDao); + } + + public void clear() { + departmentDaoConfig.getIdentityScope().clear(); + userDaoConfig.getIdentityScope().clear(); + groupDaoConfig.getIdentityScope().clear(); + messageDaoConfig.getIdentityScope().clear(); + sessionDaoConfig.getIdentityScope().clear(); + } + + public DepartmentDao getDepartmentDao() { + return departmentDao; + } + + public UserDao getUserDao() { + return userDao; + } + + public GroupDao getGroupDao() { + return groupDao; + } + + public MessageDao getMessageDao() { + return messageDao; + } + + public SessionDao getSessionDao() { + return sessionDao; + } + +} diff --git a/android/app/src/main/java/com/mogujie/tt/DB/dao/DepartmentDao.java b/android/app/src/main/java/com/mogujie/tt/DB/dao/DepartmentDao.java new file mode 100644 index 000000000..ce195ebca --- /dev/null +++ b/android/app/src/main/java/com/mogujie/tt/DB/dao/DepartmentDao.java @@ -0,0 +1,141 @@ +package com.mogujie.tt.DB.dao; + +import android.database.Cursor; +import android.database.sqlite.SQLiteDatabase; +import android.database.sqlite.SQLiteStatement; + +import de.greenrobot.dao.AbstractDao; +import de.greenrobot.dao.Property; +import de.greenrobot.dao.internal.DaoConfig; + +import com.mogujie.tt.DB.entity.DepartmentEntity; + +// THIS CODE IS GENERATED BY greenDAO, DO NOT EDIT. +/** + * DAO for table Department. +*/ +public class DepartmentDao extends AbstractDao { + + public static final String TABLENAME = "Department"; + + /** + * Properties of entity DepartmentEntity.
+ * Can be used for QueryBuilder and for referencing column names. + */ + public static class Properties { + public final static Property Id = new Property(0, Long.class, "id", true, "_id"); + public final static Property DepartId = new Property(1, int.class, "departId", false, "DEPART_ID"); + public final static Property DepartName = new Property(2, String.class, "departName", false, "DEPART_NAME"); + public final static Property Priority = new Property(3, int.class, "priority", false, "PRIORITY"); + public final static Property Status = new Property(4, int.class, "status", false, "STATUS"); + public final static Property Created = new Property(5, int.class, "created", false, "CREATED"); + public final static Property Updated = new Property(6, int.class, "updated", false, "UPDATED"); + }; + + + public DepartmentDao(DaoConfig config) { + super(config); + } + + public DepartmentDao(DaoConfig config, DaoSession daoSession) { + super(config, daoSession); + } + + /** Creates the underlying database table. */ + public static void createTable(SQLiteDatabase db, boolean ifNotExists) { + String constraint = ifNotExists? "IF NOT EXISTS ": ""; + db.execSQL("CREATE TABLE " + constraint + "'Department' (" + // + "'_id' INTEGER PRIMARY KEY AUTOINCREMENT ," + // 0: id + "'DEPART_ID' INTEGER NOT NULL UNIQUE ," + // 1: departId + "'DEPART_NAME' TEXT NOT NULL UNIQUE ," + // 2: departName + "'PRIORITY' INTEGER NOT NULL ," + // 3: priority + "'STATUS' INTEGER NOT NULL ," + // 4: status + "'CREATED' INTEGER NOT NULL ," + // 5: created + "'UPDATED' INTEGER NOT NULL );"); // 6: updated + // Add Indexes + db.execSQL("CREATE INDEX " + constraint + "IDX_Department_DEPART_ID ON Department" + + " (DEPART_ID);"); + db.execSQL("CREATE INDEX " + constraint + "IDX_Department_DEPART_NAME ON Department" + + " (DEPART_NAME);"); + } + + /** Drops the underlying database table. */ + public static void dropTable(SQLiteDatabase db, boolean ifExists) { + String sql = "DROP TABLE " + (ifExists ? "IF EXISTS " : "") + "'Department'"; + db.execSQL(sql); + } + + /** @inheritdoc */ + @Override + protected void bindValues(SQLiteStatement stmt, DepartmentEntity entity) { + stmt.clearBindings(); + + Long id = entity.getId(); + if (id != null) { + stmt.bindLong(1, id); + } + stmt.bindLong(2, entity.getDepartId()); + stmt.bindString(3, entity.getDepartName()); + stmt.bindLong(4, entity.getPriority()); + stmt.bindLong(5, entity.getStatus()); + stmt.bindLong(6, entity.getCreated()); + stmt.bindLong(7, entity.getUpdated()); + } + + /** @inheritdoc */ + @Override + public Long readKey(Cursor cursor, int offset) { + return cursor.isNull(offset + 0) ? null : cursor.getLong(offset + 0); + } + + /** @inheritdoc */ + @Override + public DepartmentEntity readEntity(Cursor cursor, int offset) { + DepartmentEntity entity = new DepartmentEntity( // + cursor.isNull(offset + 0) ? null : cursor.getLong(offset + 0), // id + cursor.getInt(offset + 1), // departId + cursor.getString(offset + 2), // departName + cursor.getInt(offset + 3), // priority + cursor.getInt(offset + 4), // status + cursor.getInt(offset + 5), // created + cursor.getInt(offset + 6) // updated + ); + return entity; + } + + /** @inheritdoc */ + @Override + public void readEntity(Cursor cursor, DepartmentEntity entity, int offset) { + entity.setId(cursor.isNull(offset + 0) ? null : cursor.getLong(offset + 0)); + entity.setDepartId(cursor.getInt(offset + 1)); + entity.setDepartName(cursor.getString(offset + 2)); + entity.setPriority(cursor.getInt(offset + 3)); + entity.setStatus(cursor.getInt(offset + 4)); + entity.setCreated(cursor.getInt(offset + 5)); + entity.setUpdated(cursor.getInt(offset + 6)); + } + + /** @inheritdoc */ + @Override + protected Long updateKeyAfterInsert(DepartmentEntity entity, long rowId) { + entity.setId(rowId); + return rowId; + } + + /** @inheritdoc */ + @Override + public Long getKey(DepartmentEntity entity) { + if(entity != null) { + return entity.getId(); + } else { + return null; + } + } + + /** @inheritdoc */ + @Override + protected boolean isEntityUpdateable() { + return true; + } + +} diff --git a/android/app/src/main/java/com/mogujie/tt/DB/dao/GroupDao.java b/android/app/src/main/java/com/mogujie/tt/DB/dao/GroupDao.java new file mode 100644 index 000000000..f2ad4034b --- /dev/null +++ b/android/app/src/main/java/com/mogujie/tt/DB/dao/GroupDao.java @@ -0,0 +1,161 @@ +package com.mogujie.tt.DB.dao; + +import android.database.Cursor; +import android.database.sqlite.SQLiteDatabase; +import android.database.sqlite.SQLiteStatement; + +import de.greenrobot.dao.AbstractDao; +import de.greenrobot.dao.Property; +import de.greenrobot.dao.internal.DaoConfig; + +import com.mogujie.tt.DB.entity.GroupEntity; + +// THIS CODE IS GENERATED BY greenDAO, DO NOT EDIT. +/** + * DAO for table GroupInfo. +*/ +public class GroupDao extends AbstractDao { + + public static final String TABLENAME = "GroupInfo"; + + /** + * Properties of entity GroupEntity.
+ * Can be used for QueryBuilder and for referencing column names. + */ + public static class Properties { + public final static Property Id = new Property(0, Long.class, "id", true, "_id"); + public final static Property PeerId = new Property(1, int.class, "peerId", false, "PEER_ID"); + public final static Property GroupType = new Property(2, int.class, "groupType", false, "GROUP_TYPE"); + public final static Property MainName = new Property(3, String.class, "mainName", false, "MAIN_NAME"); + public final static Property Avatar = new Property(4, String.class, "avatar", false, "AVATAR"); + public final static Property CreatorId = new Property(5, int.class, "creatorId", false, "CREATOR_ID"); + public final static Property UserCnt = new Property(6, int.class, "userCnt", false, "USER_CNT"); + public final static Property UserList = new Property(7, String.class, "userList", false, "USER_LIST"); + public final static Property Version = new Property(8, int.class, "version", false, "VERSION"); + public final static Property Status = new Property(9, int.class, "status", false, "STATUS"); + public final static Property Created = new Property(10, int.class, "created", false, "CREATED"); + public final static Property Updated = new Property(11, int.class, "updated", false, "UPDATED"); + }; + + + public GroupDao(DaoConfig config) { + super(config); + } + + public GroupDao(DaoConfig config, DaoSession daoSession) { + super(config, daoSession); + } + + /** Creates the underlying database table. */ + public static void createTable(SQLiteDatabase db, boolean ifNotExists) { + String constraint = ifNotExists? "IF NOT EXISTS ": ""; + db.execSQL("CREATE TABLE " + constraint + "'GroupInfo' (" + // + "'_id' INTEGER PRIMARY KEY AUTOINCREMENT ," + // 0: id + "'PEER_ID' INTEGER NOT NULL UNIQUE ," + // 1: peerId + "'GROUP_TYPE' INTEGER NOT NULL ," + // 2: groupType + "'MAIN_NAME' TEXT NOT NULL ," + // 3: mainName + "'AVATAR' TEXT NOT NULL ," + // 4: avatar + "'CREATOR_ID' INTEGER NOT NULL ," + // 5: creatorId + "'USER_CNT' INTEGER NOT NULL ," + // 6: userCnt + "'USER_LIST' TEXT NOT NULL ," + // 7: userList + "'VERSION' INTEGER NOT NULL ," + // 8: version + "'STATUS' INTEGER NOT NULL ," + // 9: status + "'CREATED' INTEGER NOT NULL ," + // 10: created + "'UPDATED' INTEGER NOT NULL );"); // 11: updated + } + + /** Drops the underlying database table. */ + public static void dropTable(SQLiteDatabase db, boolean ifExists) { + String sql = "DROP TABLE " + (ifExists ? "IF EXISTS " : "") + "'GroupInfo'"; + db.execSQL(sql); + } + + /** @inheritdoc */ + @Override + protected void bindValues(SQLiteStatement stmt, GroupEntity entity) { + stmt.clearBindings(); + + Long id = entity.getId(); + if (id != null) { + stmt.bindLong(1, id); + } + stmt.bindLong(2, entity.getPeerId()); + stmt.bindLong(3, entity.getGroupType()); + stmt.bindString(4, entity.getMainName()); + stmt.bindString(5, entity.getAvatar()); + stmt.bindLong(6, entity.getCreatorId()); + stmt.bindLong(7, entity.getUserCnt()); + stmt.bindString(8, entity.getUserList()); + stmt.bindLong(9, entity.getVersion()); + stmt.bindLong(10, entity.getStatus()); + stmt.bindLong(11, entity.getCreated()); + stmt.bindLong(12, entity.getUpdated()); + } + + /** @inheritdoc */ + @Override + public Long readKey(Cursor cursor, int offset) { + return cursor.isNull(offset + 0) ? null : cursor.getLong(offset + 0); + } + + /** @inheritdoc */ + @Override + public GroupEntity readEntity(Cursor cursor, int offset) { + GroupEntity entity = new GroupEntity( // + cursor.isNull(offset + 0) ? null : cursor.getLong(offset + 0), // id + cursor.getInt(offset + 1), // peerId + cursor.getInt(offset + 2), // groupType + cursor.getString(offset + 3), // mainName + cursor.getString(offset + 4), // avatar + cursor.getInt(offset + 5), // creatorId + cursor.getInt(offset + 6), // userCnt + cursor.getString(offset + 7), // userList + cursor.getInt(offset + 8), // version + cursor.getInt(offset + 9), // status + cursor.getInt(offset + 10), // created + cursor.getInt(offset + 11) // updated + ); + return entity; + } + + /** @inheritdoc */ + @Override + public void readEntity(Cursor cursor, GroupEntity entity, int offset) { + entity.setId(cursor.isNull(offset + 0) ? null : cursor.getLong(offset + 0)); + entity.setPeerId(cursor.getInt(offset + 1)); + entity.setGroupType(cursor.getInt(offset + 2)); + entity.setMainName(cursor.getString(offset + 3)); + entity.setAvatar(cursor.getString(offset + 4)); + entity.setCreatorId(cursor.getInt(offset + 5)); + entity.setUserCnt(cursor.getInt(offset + 6)); + entity.setUserList(cursor.getString(offset + 7)); + entity.setVersion(cursor.getInt(offset + 8)); + entity.setStatus(cursor.getInt(offset + 9)); + entity.setCreated(cursor.getInt(offset + 10)); + entity.setUpdated(cursor.getInt(offset + 11)); + } + + /** @inheritdoc */ + @Override + protected Long updateKeyAfterInsert(GroupEntity entity, long rowId) { + entity.setId(rowId); + return rowId; + } + + /** @inheritdoc */ + @Override + public Long getKey(GroupEntity entity) { + if(entity != null) { + return entity.getId(); + } else { + return null; + } + } + + /** @inheritdoc */ + @Override + protected boolean isEntityUpdateable() { + return true; + } + +} diff --git a/android/app/src/main/java/com/mogujie/tt/DB/dao/MessageDao.java b/android/app/src/main/java/com/mogujie/tt/DB/dao/MessageDao.java new file mode 100644 index 000000000..2b2c54bd5 --- /dev/null +++ b/android/app/src/main/java/com/mogujie/tt/DB/dao/MessageDao.java @@ -0,0 +1,163 @@ +package com.mogujie.tt.DB.dao; + +import android.database.Cursor; +import android.database.sqlite.SQLiteDatabase; +import android.database.sqlite.SQLiteStatement; + +import de.greenrobot.dao.AbstractDao; +import de.greenrobot.dao.Property; +import de.greenrobot.dao.internal.DaoConfig; + +import com.mogujie.tt.DB.entity.MessageEntity; + +// THIS CODE IS GENERATED BY greenDAO, DO NOT EDIT. +/** + * DAO for table Message. +*/ +public class MessageDao extends AbstractDao { + + public static final String TABLENAME = "Message"; + + /** + * Properties of entity MessageEntity.
+ * Can be used for QueryBuilder and for referencing column names. + */ + public static class Properties { + public final static Property Id = new Property(0, Long.class, "id", true, "_id"); + public final static Property MsgId = new Property(1, int.class, "msgId", false, "MSG_ID"); + public final static Property FromId = new Property(2, int.class, "fromId", false, "FROM_ID"); + public final static Property ToId = new Property(3, int.class, "toId", false, "TO_ID"); + public final static Property SessionKey = new Property(4, String.class, "sessionKey", false, "SESSION_KEY"); + public final static Property Content = new Property(5, String.class, "content", false, "CONTENT"); + public final static Property MsgType = new Property(6, int.class, "msgType", false, "MSG_TYPE"); + public final static Property DisplayType = new Property(7, int.class, "displayType", false, "DISPLAY_TYPE"); + public final static Property Status = new Property(8, int.class, "status", false, "STATUS"); + public final static Property Created = new Property(9, int.class, "created", false, "CREATED"); + public final static Property Updated = new Property(10, int.class, "updated", false, "UPDATED"); + }; + + + public MessageDao(DaoConfig config) { + super(config); + } + + public MessageDao(DaoConfig config, DaoSession daoSession) { + super(config, daoSession); + } + + /** Creates the underlying database table. */ + public static void createTable(SQLiteDatabase db, boolean ifNotExists) { + String constraint = ifNotExists? "IF NOT EXISTS ": ""; + db.execSQL("CREATE TABLE " + constraint + "'Message' (" + // + "'_id' INTEGER PRIMARY KEY AUTOINCREMENT ," + // 0: id + "'MSG_ID' INTEGER NOT NULL ," + // 1: msgId + "'FROM_ID' INTEGER NOT NULL ," + // 2: fromId + "'TO_ID' INTEGER NOT NULL ," + // 3: toId + "'SESSION_KEY' TEXT NOT NULL ," + // 4: sessionKey + "'CONTENT' TEXT NOT NULL ," + // 5: content + "'MSG_TYPE' INTEGER NOT NULL ," + // 6: msgType + "'DISPLAY_TYPE' INTEGER NOT NULL ," + // 7: displayType + "'STATUS' INTEGER NOT NULL ," + // 8: status + "'CREATED' INTEGER NOT NULL ," + // 9: created + "'UPDATED' INTEGER NOT NULL );"); // 10: updated + // Add Indexes + db.execSQL("CREATE INDEX " + constraint + "IDX_Message_STATUS ON Message" + + " (STATUS);"); + db.execSQL("CREATE INDEX " + constraint + "IDX_Message_CREATED ON Message" + + " (CREATED);"); + db.execSQL("CREATE UNIQUE INDEX " + constraint + "IDX_Message_MSG_ID_SESSION_KEY ON Message" + + " (MSG_ID,SESSION_KEY);"); + } + + /** Drops the underlying database table. */ + public static void dropTable(SQLiteDatabase db, boolean ifExists) { + String sql = "DROP TABLE " + (ifExists ? "IF EXISTS " : "") + "'Message'"; + db.execSQL(sql); + } + + /** @inheritdoc */ + @Override + protected void bindValues(SQLiteStatement stmt, MessageEntity entity) { + stmt.clearBindings(); + + Long id = entity.getId(); + if (id != null) { + stmt.bindLong(1, id); + } + stmt.bindLong(2, entity.getMsgId()); + stmt.bindLong(3, entity.getFromId()); + stmt.bindLong(4, entity.getToId()); + stmt.bindString(5, entity.getSessionKey()); + stmt.bindString(6, entity.getContent()); + stmt.bindLong(7, entity.getMsgType()); + stmt.bindLong(8, entity.getDisplayType()); + stmt.bindLong(9, entity.getStatus()); + stmt.bindLong(10, entity.getCreated()); + stmt.bindLong(11, entity.getUpdated()); + } + + /** @inheritdoc */ + @Override + public Long readKey(Cursor cursor, int offset) { + return cursor.isNull(offset + 0) ? null : cursor.getLong(offset + 0); + } + + /** @inheritdoc */ + @Override + public MessageEntity readEntity(Cursor cursor, int offset) { + MessageEntity entity = new MessageEntity( // + cursor.isNull(offset + 0) ? null : cursor.getLong(offset + 0), // id + cursor.getInt(offset + 1), // msgId + cursor.getInt(offset + 2), // fromId + cursor.getInt(offset + 3), // toId + cursor.getString(offset + 4), // sessionKey + cursor.getString(offset + 5), // content + cursor.getInt(offset + 6), // msgType + cursor.getInt(offset + 7), // displayType + cursor.getInt(offset + 8), // status + cursor.getInt(offset + 9), // created + cursor.getInt(offset + 10) // updated + ); + return entity; + } + + /** @inheritdoc */ + @Override + public void readEntity(Cursor cursor, MessageEntity entity, int offset) { + entity.setId(cursor.isNull(offset + 0) ? null : cursor.getLong(offset + 0)); + entity.setMsgId(cursor.getInt(offset + 1)); + entity.setFromId(cursor.getInt(offset + 2)); + entity.setToId(cursor.getInt(offset + 3)); + entity.setSessionKey(cursor.getString(offset + 4)); + entity.setContent(cursor.getString(offset + 5)); + entity.setMsgType(cursor.getInt(offset + 6)); + entity.setDisplayType(cursor.getInt(offset + 7)); + entity.setStatus(cursor.getInt(offset + 8)); + entity.setCreated(cursor.getInt(offset + 9)); + entity.setUpdated(cursor.getInt(offset + 10)); + } + + /** @inheritdoc */ + @Override + protected Long updateKeyAfterInsert(MessageEntity entity, long rowId) { + entity.setId(rowId); + return rowId; + } + + /** @inheritdoc */ + @Override + public Long getKey(MessageEntity entity) { + if(entity != null) { + return entity.getId(); + } else { + return null; + } + } + + /** @inheritdoc */ + @Override + protected boolean isEntityUpdateable() { + return true; + } + +} diff --git a/android/app/src/main/java/com/mogujie/tt/DB/dao/SessionDao.java b/android/app/src/main/java/com/mogujie/tt/DB/dao/SessionDao.java new file mode 100644 index 000000000..958eab325 --- /dev/null +++ b/android/app/src/main/java/com/mogujie/tt/DB/dao/SessionDao.java @@ -0,0 +1,151 @@ +package com.mogujie.tt.DB.dao; + +import android.database.Cursor; +import android.database.sqlite.SQLiteDatabase; +import android.database.sqlite.SQLiteStatement; + +import de.greenrobot.dao.AbstractDao; +import de.greenrobot.dao.Property; +import de.greenrobot.dao.internal.DaoConfig; + +import com.mogujie.tt.DB.entity.SessionEntity; + +// THIS CODE IS GENERATED BY greenDAO, DO NOT EDIT. +/** + * DAO for table Session. +*/ +public class SessionDao extends AbstractDao { + + public static final String TABLENAME = "Session"; + + /** + * Properties of entity SessionEntity.
+ * Can be used for QueryBuilder and for referencing column names. + */ + public static class Properties { + public final static Property Id = new Property(0, Long.class, "id", true, "_id"); + public final static Property SessionKey = new Property(1, String.class, "sessionKey", false, "SESSION_KEY"); + public final static Property PeerId = new Property(2, int.class, "peerId", false, "PEER_ID"); + public final static Property PeerType = new Property(3, int.class, "peerType", false, "PEER_TYPE"); + public final static Property LatestMsgType = new Property(4, int.class, "latestMsgType", false, "LATEST_MSG_TYPE"); + public final static Property LatestMsgId = new Property(5, int.class, "latestMsgId", false, "LATEST_MSG_ID"); + public final static Property LatestMsgData = new Property(6, String.class, "latestMsgData", false, "LATEST_MSG_DATA"); + public final static Property TalkId = new Property(7, int.class, "talkId", false, "TALK_ID"); + public final static Property Created = new Property(8, int.class, "created", false, "CREATED"); + public final static Property Updated = new Property(9, int.class, "updated", false, "UPDATED"); + }; + + + public SessionDao(DaoConfig config) { + super(config); + } + + public SessionDao(DaoConfig config, DaoSession daoSession) { + super(config, daoSession); + } + + /** Creates the underlying database table. */ + public static void createTable(SQLiteDatabase db, boolean ifNotExists) { + String constraint = ifNotExists? "IF NOT EXISTS ": ""; + db.execSQL("CREATE TABLE " + constraint + "'Session' (" + // + "'_id' INTEGER PRIMARY KEY AUTOINCREMENT ," + // 0: id + "'SESSION_KEY' TEXT NOT NULL UNIQUE ," + // 1: sessionKey + "'PEER_ID' INTEGER NOT NULL ," + // 2: peerId + "'PEER_TYPE' INTEGER NOT NULL ," + // 3: peerType + "'LATEST_MSG_TYPE' INTEGER NOT NULL ," + // 4: latestMsgType + "'LATEST_MSG_ID' INTEGER NOT NULL ," + // 5: latestMsgId + "'LATEST_MSG_DATA' TEXT NOT NULL ," + // 6: latestMsgData + "'TALK_ID' INTEGER NOT NULL ," + // 7: talkId + "'CREATED' INTEGER NOT NULL ," + // 8: created + "'UPDATED' INTEGER NOT NULL );"); // 9: updated + } + + /** Drops the underlying database table. */ + public static void dropTable(SQLiteDatabase db, boolean ifExists) { + String sql = "DROP TABLE " + (ifExists ? "IF EXISTS " : "") + "'Session'"; + db.execSQL(sql); + } + + /** @inheritdoc */ + @Override + protected void bindValues(SQLiteStatement stmt, SessionEntity entity) { + stmt.clearBindings(); + + Long id = entity.getId(); + if (id != null) { + stmt.bindLong(1, id); + } + stmt.bindString(2, entity.getSessionKey()); + stmt.bindLong(3, entity.getPeerId()); + stmt.bindLong(4, entity.getPeerType()); + stmt.bindLong(5, entity.getLatestMsgType()); + stmt.bindLong(6, entity.getLatestMsgId()); + stmt.bindString(7, entity.getLatestMsgData()); + stmt.bindLong(8, entity.getTalkId()); + stmt.bindLong(9, entity.getCreated()); + stmt.bindLong(10, entity.getUpdated()); + } + + /** @inheritdoc */ + @Override + public Long readKey(Cursor cursor, int offset) { + return cursor.isNull(offset + 0) ? null : cursor.getLong(offset + 0); + } + + /** @inheritdoc */ + @Override + public SessionEntity readEntity(Cursor cursor, int offset) { + SessionEntity entity = new SessionEntity( // + cursor.isNull(offset + 0) ? null : cursor.getLong(offset + 0), // id + cursor.getString(offset + 1), // sessionKey + cursor.getInt(offset + 2), // peerId + cursor.getInt(offset + 3), // peerType + cursor.getInt(offset + 4), // latestMsgType + cursor.getInt(offset + 5), // latestMsgId + cursor.getString(offset + 6), // latestMsgData + cursor.getInt(offset + 7), // talkId + cursor.getInt(offset + 8), // created + cursor.getInt(offset + 9) // updated + ); + return entity; + } + + /** @inheritdoc */ + @Override + public void readEntity(Cursor cursor, SessionEntity entity, int offset) { + entity.setId(cursor.isNull(offset + 0) ? null : cursor.getLong(offset + 0)); + entity.setSessionKey(cursor.getString(offset + 1)); + entity.setPeerId(cursor.getInt(offset + 2)); + entity.setPeerType(cursor.getInt(offset + 3)); + entity.setLatestMsgType(cursor.getInt(offset + 4)); + entity.setLatestMsgId(cursor.getInt(offset + 5)); + entity.setLatestMsgData(cursor.getString(offset + 6)); + entity.setTalkId(cursor.getInt(offset + 7)); + entity.setCreated(cursor.getInt(offset + 8)); + entity.setUpdated(cursor.getInt(offset + 9)); + } + + /** @inheritdoc */ + @Override + protected Long updateKeyAfterInsert(SessionEntity entity, long rowId) { + entity.setId(rowId); + return rowId; + } + + /** @inheritdoc */ + @Override + public Long getKey(SessionEntity entity) { + if(entity != null) { + return entity.getId(); + } else { + return null; + } + } + + /** @inheritdoc */ + @Override + protected boolean isEntityUpdateable() { + return true; + } + +} diff --git a/android/app/src/main/java/com/mogujie/tt/DB/dao/UserDao.java b/android/app/src/main/java/com/mogujie/tt/DB/dao/UserDao.java new file mode 100644 index 000000000..1c807e855 --- /dev/null +++ b/android/app/src/main/java/com/mogujie/tt/DB/dao/UserDao.java @@ -0,0 +1,169 @@ +package com.mogujie.tt.DB.dao; + +import android.database.Cursor; +import android.database.sqlite.SQLiteDatabase; +import android.database.sqlite.SQLiteStatement; + +import de.greenrobot.dao.AbstractDao; +import de.greenrobot.dao.Property; +import de.greenrobot.dao.internal.DaoConfig; + +import com.mogujie.tt.DB.entity.UserEntity; + +// THIS CODE IS GENERATED BY greenDAO, DO NOT EDIT. +/** + * DAO for table UserInfo. +*/ +public class UserDao extends AbstractDao { + + public static final String TABLENAME = "UserInfo"; + + /** + * Properties of entity UserEntity.
+ * Can be used for QueryBuilder and for referencing column names. + */ + public static class Properties { + public final static Property Id = new Property(0, Long.class, "id", true, "_id"); + public final static Property PeerId = new Property(1, int.class, "peerId", false, "PEER_ID"); + public final static Property Gender = new Property(2, int.class, "gender", false, "GENDER"); + public final static Property MainName = new Property(3, String.class, "mainName", false, "MAIN_NAME"); + public final static Property PinyinName = new Property(4, String.class, "pinyinName", false, "PINYIN_NAME"); + public final static Property RealName = new Property(5, String.class, "realName", false, "REAL_NAME"); + public final static Property Avatar = new Property(6, String.class, "avatar", false, "AVATAR"); + public final static Property Phone = new Property(7, String.class, "phone", false, "PHONE"); + public final static Property Email = new Property(8, String.class, "email", false, "EMAIL"); + public final static Property DepartmentId = new Property(9, int.class, "departmentId", false, "DEPARTMENT_ID"); + public final static Property Status = new Property(10, int.class, "status", false, "STATUS"); + public final static Property Created = new Property(11, int.class, "created", false, "CREATED"); + public final static Property Updated = new Property(12, int.class, "updated", false, "UPDATED"); + }; + + + public UserDao(DaoConfig config) { + super(config); + } + + public UserDao(DaoConfig config, DaoSession daoSession) { + super(config, daoSession); + } + + /** Creates the underlying database table. */ + public static void createTable(SQLiteDatabase db, boolean ifNotExists) { + String constraint = ifNotExists? "IF NOT EXISTS ": ""; + db.execSQL("CREATE TABLE " + constraint + "'UserInfo' (" + // + "'_id' INTEGER PRIMARY KEY AUTOINCREMENT ," + // 0: id + "'PEER_ID' INTEGER NOT NULL UNIQUE ," + // 1: peerId + "'GENDER' INTEGER NOT NULL ," + // 2: gender + "'MAIN_NAME' TEXT NOT NULL ," + // 3: mainName + "'PINYIN_NAME' TEXT NOT NULL ," + // 4: pinyinName + "'REAL_NAME' TEXT NOT NULL ," + // 5: realName + "'AVATAR' TEXT NOT NULL ," + // 6: avatar + "'PHONE' TEXT NOT NULL ," + // 7: phone + "'EMAIL' TEXT NOT NULL ," + // 8: email + "'DEPARTMENT_ID' INTEGER NOT NULL ," + // 9: departmentId + "'STATUS' INTEGER NOT NULL ," + // 10: status + "'CREATED' INTEGER NOT NULL ," + // 11: created + "'UPDATED' INTEGER NOT NULL );"); // 12: updated + // Add Indexes + db.execSQL("CREATE INDEX " + constraint + "IDX_UserInfo_PEER_ID ON UserInfo" + + " (PEER_ID);"); + } + + /** Drops the underlying database table. */ + public static void dropTable(SQLiteDatabase db, boolean ifExists) { + String sql = "DROP TABLE " + (ifExists ? "IF EXISTS " : "") + "'UserInfo'"; + db.execSQL(sql); + } + + /** @inheritdoc */ + @Override + protected void bindValues(SQLiteStatement stmt, UserEntity entity) { + stmt.clearBindings(); + + Long id = entity.getId(); + if (id != null) { + stmt.bindLong(1, id); + } + stmt.bindLong(2, entity.getPeerId()); + stmt.bindLong(3, entity.getGender()); + stmt.bindString(4, entity.getMainName()); + stmt.bindString(5, entity.getPinyinName()); + stmt.bindString(6, entity.getRealName()); + stmt.bindString(7, entity.getAvatar()); + stmt.bindString(8, entity.getPhone()); + stmt.bindString(9, entity.getEmail()); + stmt.bindLong(10, entity.getDepartmentId()); + stmt.bindLong(11, entity.getStatus()); + stmt.bindLong(12, entity.getCreated()); + stmt.bindLong(13, entity.getUpdated()); + } + + /** @inheritdoc */ + @Override + public Long readKey(Cursor cursor, int offset) { + return cursor.isNull(offset + 0) ? null : cursor.getLong(offset + 0); + } + + /** @inheritdoc */ + @Override + public UserEntity readEntity(Cursor cursor, int offset) { + UserEntity entity = new UserEntity( // + cursor.isNull(offset + 0) ? null : cursor.getLong(offset + 0), // id + cursor.getInt(offset + 1), // peerId + cursor.getInt(offset + 2), // gender + cursor.getString(offset + 3), // mainName + cursor.getString(offset + 4), // pinyinName + cursor.getString(offset + 5), // realName + cursor.getString(offset + 6), // avatar + cursor.getString(offset + 7), // phone + cursor.getString(offset + 8), // email + cursor.getInt(offset + 9), // departmentId + cursor.getInt(offset + 10), // status + cursor.getInt(offset + 11), // created + cursor.getInt(offset + 12) // updated + ); + return entity; + } + + /** @inheritdoc */ + @Override + public void readEntity(Cursor cursor, UserEntity entity, int offset) { + entity.setId(cursor.isNull(offset + 0) ? null : cursor.getLong(offset + 0)); + entity.setPeerId(cursor.getInt(offset + 1)); + entity.setGender(cursor.getInt(offset + 2)); + entity.setMainName(cursor.getString(offset + 3)); + entity.setPinyinName(cursor.getString(offset + 4)); + entity.setRealName(cursor.getString(offset + 5)); + entity.setAvatar(cursor.getString(offset + 6)); + entity.setPhone(cursor.getString(offset + 7)); + entity.setEmail(cursor.getString(offset + 8)); + entity.setDepartmentId(cursor.getInt(offset + 9)); + entity.setStatus(cursor.getInt(offset + 10)); + entity.setCreated(cursor.getInt(offset + 11)); + entity.setUpdated(cursor.getInt(offset + 12)); + } + + /** @inheritdoc */ + @Override + protected Long updateKeyAfterInsert(UserEntity entity, long rowId) { + entity.setId(rowId); + return rowId; + } + + /** @inheritdoc */ + @Override + public Long getKey(UserEntity entity) { + if(entity != null) { + return entity.getId(); + } else { + return null; + } + } + + /** @inheritdoc */ + @Override + protected boolean isEntityUpdateable() { + return true; + } + +} diff --git a/android/app/src/main/java/com/mogujie/tt/DB/entity/DepartmentEntity.java b/android/app/src/main/java/com/mogujie/tt/DB/entity/DepartmentEntity.java new file mode 100644 index 000000000..b58e4dc37 --- /dev/null +++ b/android/app/src/main/java/com/mogujie/tt/DB/entity/DepartmentEntity.java @@ -0,0 +1,114 @@ +package com.mogujie.tt.DB.entity; + +// THIS CODE IS GENERATED BY greenDAO, EDIT ONLY INSIDE THE "KEEP"-SECTIONS + +// KEEP INCLUDES - put your custom includes here +import com.mogujie.tt.imservice.entity.SearchElement; +import com.mogujie.tt.utils.pinyin.PinYin; +// KEEP INCLUDES END +/** + * Entity mapped to table Department. + */ +public class DepartmentEntity { + + private Long id; + private int departId; + /** Not-null value. */ + private String departName; + private int priority; + private int status; + private int created; + private int updated; + + // KEEP FIELDS - put your custom fields here + private PinYin.PinYinElement pinyinElement = new PinYin.PinYinElement(); + private SearchElement searchElement = new SearchElement(); + // KEEP FIELDS END + + public DepartmentEntity() { + } + + public DepartmentEntity(Long id) { + this.id = id; + } + + public DepartmentEntity(Long id, int departId, String departName, int priority, int status, int created, int updated) { + this.id = id; + this.departId = departId; + this.departName = departName; + this.priority = priority; + this.status = status; + this.created = created; + this.updated = updated; + } + + public Long getId() { + return id; + } + + public void setId(Long id) { + this.id = id; + } + + public int getDepartId() { + return departId; + } + + public void setDepartId(int departId) { + this.departId = departId; + } + + /** Not-null value. */ + public String getDepartName() { + return departName; + } + + /** Not-null value; ensure this value is available before it is saved to the database. */ + public void setDepartName(String departName) { + this.departName = departName; + } + + public int getPriority() { + return priority; + } + + public void setPriority(int priority) { + this.priority = priority; + } + + public int getStatus() { + return status; + } + + public void setStatus(int status) { + this.status = status; + } + + public int getCreated() { + return created; + } + + public void setCreated(int created) { + this.created = created; + } + + public int getUpdated() { + return updated; + } + + public void setUpdated(int updated) { + this.updated = updated; + } + + // KEEP METHODS - put your custom methods here + + public PinYin.PinYinElement getPinyinElement() { + return pinyinElement; + } + + public SearchElement getSearchElement() { + return searchElement; + } + // KEEP METHODS END + +} diff --git a/android/app/src/main/java/com/mogujie/tt/DB/entity/GroupEntity.java b/android/app/src/main/java/com/mogujie/tt/DB/entity/GroupEntity.java new file mode 100644 index 000000000..59c6ccc12 --- /dev/null +++ b/android/app/src/main/java/com/mogujie/tt/DB/entity/GroupEntity.java @@ -0,0 +1,212 @@ +package com.mogujie.tt.DB.entity; + +// THIS CODE IS GENERATED BY greenDAO, EDIT ONLY INSIDE THE "KEEP"-SECTIONS + +// KEEP INCLUDES - put your custom includes here +import android.text.TextUtils; + +import com.mogujie.tt.config.DBConstant; +import com.mogujie.tt.imservice.entity.SearchElement; +import com.mogujie.tt.utils.pinyin.PinYin; + +import java.util.Collections; +import java.util.List; +import java.util.Set; +import java.util.TreeSet; +// KEEP INCLUDES END +/** + * Entity mapped to table GroupInfo. + */ +public class GroupEntity extends PeerEntity { + + private int groupType; + private int creatorId; + private int userCnt; + /** Not-null value. */ + private String userList; + private int version; + private int status; + + // KEEP FIELDS - put your custom fields here + + private PinYin.PinYinElement pinyinElement = new PinYin.PinYinElement(); + private SearchElement searchElement = new SearchElement(); + // KEEP FIELDS END + + public GroupEntity() { + } + + public GroupEntity(Long id) { + this.id = id; + } + + public GroupEntity(Long id, int peerId, int groupType, String mainName, String avatar, int creatorId, int userCnt, String userList, int version, int status, int created, int updated) { + this.id = id; + this.peerId = peerId; + this.groupType = groupType; + this.mainName = mainName; + this.avatar = avatar; + this.creatorId = creatorId; + this.userCnt = userCnt; + this.userList = userList; + this.version = version; + this.status = status; + this.created = created; + this.updated = updated; + } + + public Long getId() { + return id; + } + + public void setId(Long id) { + this.id = id; + } + + public int getPeerId() { + return peerId; + } + + public void setPeerId(int peerId) { + this.peerId = peerId; + } + + public int getGroupType() { + return groupType; + } + + public void setGroupType(int groupType) { + this.groupType = groupType; + } + + /** Not-null value. */ + public String getMainName() { + return mainName; + } + + /** Not-null value; ensure this value is available before it is saved to the database. */ + public void setMainName(String mainName) { + this.mainName = mainName; + } + + /** Not-null value. */ + public String getAvatar() { + return avatar; + } + + /** Not-null value; ensure this value is available before it is saved to the database. */ + public void setAvatar(String avatar) { + this.avatar = avatar; + } + + public int getCreatorId() { + return creatorId; + } + + public void setCreatorId(int creatorId) { + this.creatorId = creatorId; + } + + public int getUserCnt() { + return userCnt; + } + + public void setUserCnt(int userCnt) { + this.userCnt = userCnt; + } + + /** Not-null value. */ + public String getUserList() { + return userList; + } + + /** Not-null value; ensure this value is available before it is saved to the database. */ + public void setUserList(String userList) { + this.userList = userList; + } + + public int getVersion() { + return version; + } + + public void setVersion(int version) { + this.version = version; + } + + public int getStatus() { + return status; + } + + public void setStatus(int status) { + this.status = status; + } + + public int getCreated() { + return created; + } + + public void setCreated(int created) { + this.created = created; + } + + public int getUpdated() { + return updated; + } + + public void setUpdated(int updated) { + this.updated = updated; + } + + // KEEP METHODS - put your custom methods here + + + @Override + public int getType() { + return DBConstant.SESSION_TYPE_GROUP; + } + + /** + * yingmu + * 获取群组成员的list + * -- userList 前后去空格,按照逗号区分, 不检测空的成员(非法) + */ + public Set getlistGroupMemberIds(){ + if(TextUtils.isEmpty(userList)){ + return Collections.emptySet(); + } + String[] arrayUserIds = userList.trim().split(","); + if(arrayUserIds.length <=0){ + return Collections.emptySet(); + } + /**zhe'g*/ + Set result = new TreeSet(); + for(int index=0;index < arrayUserIds.length;index++){ + int userId = Integer.parseInt(arrayUserIds[index]); + result.add(userId); + } + return result; + } + //todo 入参变为 set【自动去重】 + // 每次都要转换 性能不是太好,todo + public void setlistGroupMemberIds(List memberList){ + String userList = TextUtils.join(",",memberList); + setUserList(userList); + } + + public PinYin.PinYinElement getPinyinElement() { + return pinyinElement; + } + + public void setPinyinElement(PinYin.PinYinElement pinyinElement) { + this.pinyinElement = pinyinElement; + } + + public SearchElement getSearchElement() { + return searchElement; + } + + public void setSearchElement(SearchElement searchElement) { + this.searchElement = searchElement; + } + // KEEP METHODS END +} diff --git a/android/app/src/main/java/com/mogujie/tt/DB/entity/MessageEntity.java b/android/app/src/main/java/com/mogujie/tt/DB/entity/MessageEntity.java new file mode 100644 index 000000000..50344fc1f --- /dev/null +++ b/android/app/src/main/java/com/mogujie/tt/DB/entity/MessageEntity.java @@ -0,0 +1,287 @@ +package com.mogujie.tt.DB.entity; + +// THIS CODE IS GENERATED BY greenDAO, EDIT ONLY INSIDE THE "KEEP"-SECTIONS + +// KEEP INCLUDES - put your custom includes here + +import com.mogujie.tt.config.DBConstant; +import com.mogujie.tt.protobuf.helper.EntityChangeEngine; +/** + * 这个类不同与其他自动生成代码 + * 需要依赖conten与display 依赖不同的状态 + * */ +// KEEP INCLUDES END +/** + * Entity mapped to table Message. + */ +public class MessageEntity implements java.io.Serializable { + + protected Long id; + protected int msgId; + protected int fromId; + protected int toId; + /** Not-null value. */ + protected String sessionKey; + /** Not-null value. */ + protected String content; + protected int msgType; + protected int displayType; + protected int status; + protected int created; + protected int updated; + + // KEEP FIELDS - put your custom fields here + + protected boolean isGIfEmo; + // KEEP FIELDS END + + public MessageEntity() { + } + + public MessageEntity(Long id) { + this.id = id; + } + + public MessageEntity(Long id, int msgId, int fromId, int toId, String sessionKey, String content, int msgType, int displayType, int status, int created, int updated) { + this.id = id; + this.msgId = msgId; + this.fromId = fromId; + this.toId = toId; + this.sessionKey = sessionKey; + this.content = content; + this.msgType = msgType; + this.displayType = displayType; + this.status = status; + this.created = created; + this.updated = updated; + } + + public Long getId() { + return id; + } + + public void setId(Long id) { + this.id = id; + } + + public int getMsgId() { + return msgId; + } + + public void setMsgId(int msgId) { + this.msgId = msgId; + } + + public int getFromId() { + return fromId; + } + + public void setFromId(int fromId) { + this.fromId = fromId; + } + + public int getToId() { + return toId; + } + + public void setToId(int toId) { + this.toId = toId; + } + + /** Not-null value. */ + public String getSessionKey() { + return sessionKey; + } + + /** Not-null value; ensure this value is available before it is saved to the database. */ + public void setSessionKey(String sessionKey) { + this.sessionKey = sessionKey; + } + + /** Not-null value. */ + public String getContent() { + return content; + } + + /** Not-null value; ensure this value is available before it is saved to the database. */ + public void setContent(String content) { + this.content = content; + } + + public int getMsgType() { + return msgType; + } + + public void setMsgType(int msgType) { + this.msgType = msgType; + } + + public int getDisplayType() { + return displayType; + } + + public void setDisplayType(int displayType) { + this.displayType = displayType; + } + + public int getStatus() { + return status; + } + + public void setStatus(int status) { + this.status = status; + } + + public int getCreated() { + return created; + } + + public void setCreated(int created) { + this.created = created; + } + + public int getUpdated() { + return updated; + } + + public void setUpdated(int updated) { + this.updated = updated; + } + + // KEEP METHODS - put your custom methods here + /** + * -----根据自身状态判断的--------- + */ + public int getSessionType() { + switch (msgType) { + case DBConstant.MSG_TYPE_SINGLE_TEXT: + case DBConstant.MSG_TYPE_SINGLE_AUDIO: + return DBConstant.SESSION_TYPE_SINGLE; + case DBConstant.MSG_TYPE_GROUP_TEXT: + case DBConstant.MSG_TYPE_GROUP_AUDIO: + return DBConstant.SESSION_TYPE_GROUP; + default: + //todo 有问题 + return DBConstant.SESSION_TYPE_SINGLE; + } + } + + + public String getMessageDisplay() { + switch (displayType){ + case DBConstant.SHOW_AUDIO_TYPE: + return DBConstant.DISPLAY_FOR_AUDIO; + case DBConstant.SHOW_ORIGIN_TEXT_TYPE: + return content; + case DBConstant.SHOW_IMAGE_TYPE: + return DBConstant.DISPLAY_FOR_IMAGE; + case DBConstant.SHOW_MIX_TEXT: + return DBConstant.DISPLAY_FOR_MIX; + default: + return DBConstant.DISPLAY_FOR_ERROR; + } + } + + @Override + public String toString() { + return "MessageEntity{" + + "id=" + id + + ", msgId=" + msgId + + ", fromId=" + fromId + + ", toId=" + toId + + ", content='" + content + '\'' + + ", msgType=" + msgType + + ", displayType=" + displayType + + ", status=" + status + + ", created=" + created + + ", updated=" + updated + + '}'; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (!(o instanceof MessageEntity)) return false; + + MessageEntity that = (MessageEntity) o; + + if (created != that.created) return false; + if (displayType != that.displayType) return false; + if (fromId != that.fromId) return false; + if (msgId != that.msgId) return false; + if (msgType != that.msgType) return false; + if (status != that.status) return false; + if (toId != that.toId) return false; + if (updated != that.updated) return false; + if (!content.equals(that.content)) return false; + if (!id.equals(that.id)) return false; + if (!sessionKey.equals(that.sessionKey)) return false; + + return true; + } + + @Override + public int hashCode() { + int result = id.hashCode(); + result = 31 * result + msgId; + result = 31 * result + fromId; + result = 31 * result + toId; + result = 31 * result + sessionKey.hashCode(); + result = 31 * result + content.hashCode(); + result = 31 * result + msgType; + result = 31 * result + displayType; + result = 31 * result + status; + result = 31 * result + created; + result = 31 * result + updated; + return result; + } + + + /** + * 获取会话的sessionId + * @param isSend + * @return + */ + public int getPeerId(boolean isSend){ + if(isSend){ + /**自己发出去的*/ + return toId; + }else{ + /**接受到的*/ + switch (getSessionType()){ + case DBConstant.SESSION_TYPE_SINGLE: + return fromId; + case DBConstant.SESSION_TYPE_GROUP: + return toId; + default: + return toId; + } + } + } + + public byte[] getSendContent(){ + return null; + } + + public boolean isGIfEmo() { + return isGIfEmo; + } + + public void setGIfEmo(boolean isGIfEmo) { + this.isGIfEmo = isGIfEmo; + } + + public boolean isSend(int loginId){ + boolean isSend = (loginId==fromId)?true:false; + return isSend; + } + + public String buildSessionKey(boolean isSend){ + int sessionType = getSessionType(); + int peerId = getPeerId(isSend); + sessionKey = EntityChangeEngine.getSessionKey(peerId,sessionType); + return sessionKey; + } + // KEEP METHODS END + +} diff --git a/android/app/src/main/java/com/mogujie/tt/DB/entity/PeerEntity.java b/android/app/src/main/java/com/mogujie/tt/DB/entity/PeerEntity.java new file mode 100644 index 000000000..fc20a30ab --- /dev/null +++ b/android/app/src/main/java/com/mogujie/tt/DB/entity/PeerEntity.java @@ -0,0 +1,78 @@ +package com.mogujie.tt.DB.entity; + +import com.mogujie.tt.protobuf.helper.EntityChangeEngine; + +/** + * @author : yingmu on 15-3-25. + * @email : yingmu@mogujie.com. + * + * 聊天对象抽象类 may be user/group + */ +public abstract class PeerEntity { + protected Long id; + protected int peerId; + /** Not-null value. + * userEntity --> nickName + * groupEntity --> groupName + * */ + protected String mainName; + /** Not-null value.*/ + protected String avatar; + protected int created; + protected int updated; + + public Long getId() { + return id; + } + + public void setId(Long id) { + this.id = id; + } + + public int getPeerId() { + return peerId; + } + + public void setPeerId(int peerId) { + this.peerId = peerId; + } + + public String getMainName() { + return mainName; + } + + public void setMainName(String mainName) { + this.mainName = mainName; + } + + public String getAvatar() { + return avatar; + } + + public void setAvatar(String avatar) { + this.avatar = avatar; + } + + public int getCreated() { + return created; + } + + public void setCreated(int created) { + this.created = created; + } + + public int getUpdated() { + return updated; + } + + public void setUpdated(int updated) { + this.updated = updated; + } + + // peer就能生成sessionKey + public String getSessionKey(){ + return EntityChangeEngine.getSessionKey(peerId,getType()); + } + + public abstract int getType(); +} diff --git a/android/app/src/main/java/com/mogujie/tt/DB/entity/SessionEntity.java b/android/app/src/main/java/com/mogujie/tt/DB/entity/SessionEntity.java new file mode 100644 index 000000000..3e98dd00f --- /dev/null +++ b/android/app/src/main/java/com/mogujie/tt/DB/entity/SessionEntity.java @@ -0,0 +1,145 @@ +package com.mogujie.tt.DB.entity; + +// THIS CODE IS GENERATED BY greenDAO, EDIT ONLY INSIDE THE "KEEP"-SECTIONS + +// KEEP INCLUDES - put your custom includes here +import com.mogujie.tt.protobuf.helper.EntityChangeEngine; +// KEEP INCLUDES END + +/** + * Entity mapped to table Session. + */ +public class SessionEntity { + + private Long id; + /** Not-null value. */ + private String sessionKey; + private int peerId; + private int peerType; + private int latestMsgType; + private int latestMsgId; + /** Not-null value. */ + private String latestMsgData; + private int talkId; + private int created; + private int updated; + + // KEEP FIELDS - put your custom fields here + // KEEP FIELDS END + + public SessionEntity() { + } + + public SessionEntity(Long id) { + this.id = id; + } + + public SessionEntity(Long id, String sessionKey, int peerId, int peerType, int latestMsgType, int latestMsgId, String latestMsgData, int talkId, int created, int updated) { + this.id = id; + this.sessionKey = sessionKey; + this.peerId = peerId; + this.peerType = peerType; + this.latestMsgType = latestMsgType; + this.latestMsgId = latestMsgId; + this.latestMsgData = latestMsgData; + this.talkId = talkId; + this.created = created; + this.updated = updated; + } + + public Long getId() { + return id; + } + + public void setId(Long id) { + this.id = id; + } + + /** Not-null value. */ + public String getSessionKey() { + return sessionKey; + } + + /** Not-null value; ensure this value is available before it is saved to the database. */ + public void setSessionKey(String sessionKey) { + this.sessionKey = sessionKey; + } + + public int getPeerId() { + return peerId; + } + + public void setPeerId(int peerId) { + this.peerId = peerId; + } + + public int getPeerType() { + return peerType; + } + + public void setPeerType(int peerType) { + this.peerType = peerType; + } + + public int getLatestMsgType() { + return latestMsgType; + } + + public void setLatestMsgType(int latestMsgType) { + this.latestMsgType = latestMsgType; + } + + public int getLatestMsgId() { + return latestMsgId; + } + + public void setLatestMsgId(int latestMsgId) { + this.latestMsgId = latestMsgId; + } + + /** Not-null value. */ + public String getLatestMsgData() { + return latestMsgData; + } + + /** Not-null value; ensure this value is available before it is saved to the database. */ + public void setLatestMsgData(String latestMsgData) { + this.latestMsgData = latestMsgData; + } + + public int getTalkId() { + return talkId; + } + + public void setTalkId(int talkId) { + this.talkId = talkId; + } + + public int getCreated() { + return created; + } + + public void setCreated(int created) { + this.created = created; + } + + public int getUpdated() { + return updated; + } + + public void setUpdated(int updated) { + this.updated = updated; + } + + // KEEP METHODS - put your custom methods here + public String buildSessionKey(){ + if(peerType <=0 || peerId <=0){ + throw new IllegalArgumentException( + "SessionEntity buildSessionKey error,cause by some params <=0"); + } + sessionKey = EntityChangeEngine.getSessionKey(peerId, peerType); + return sessionKey; + } + // KEEP METHODS END + +} diff --git a/android/app/src/main/java/com/mogujie/tt/DB/entity/UserEntity.java b/android/app/src/main/java/com/mogujie/tt/DB/entity/UserEntity.java new file mode 100644 index 000000000..eafcea7b0 --- /dev/null +++ b/android/app/src/main/java/com/mogujie/tt/DB/entity/UserEntity.java @@ -0,0 +1,260 @@ +package com.mogujie.tt.DB.entity; + +// THIS CODE IS GENERATED BY greenDAO, EDIT ONLY INSIDE THE "KEEP"-SECTIONS + +// KEEP INCLUDES - put your custom includes here + +import android.text.TextUtils; + +import com.mogujie.tt.config.DBConstant; +import com.mogujie.tt.imservice.entity.SearchElement; +import com.mogujie.tt.utils.pinyin.PinYin.PinYinElement; +// KEEP INCLUDES END +/** + * Entity mapped to table UserInfo. + */ +public class UserEntity extends PeerEntity{ + + private int gender; + /** Not-null value. */ + private String pinyinName; + /** Not-null value. */ + private String realName; + /** Not-null value. */ + private String phone; + /** Not-null value. */ + private String email; + private int departmentId; + private int status; + + // KEEP FIELDS - put your custom fields here + private PinYinElement pinyinElement = new PinYinElement(); + private SearchElement searchElement = new SearchElement(); + // KEEP FIELDS END + + public UserEntity() { + } + + public UserEntity(Long id) { + this.id = id; + } + + public UserEntity(Long id, int peerId, int gender, String mainName, String pinyinName, String realName, String avatar, String phone, String email, int departmentId, int status, int created, int updated) { + this.id = id; + this.peerId = peerId; + this.gender = gender; + this.mainName = mainName; + this.pinyinName = pinyinName; + this.realName = realName; + this.avatar = avatar; + this.phone = phone; + this.email = email; + this.departmentId = departmentId; + this.status = status; + this.created = created; + this.updated = updated; + } + + public Long getId() { + return id; + } + + public void setId(Long id) { + this.id = id; + } + + public int getPeerId() { + return peerId; + } + + public void setPeerId(int peerId) { + this.peerId = peerId; + } + + public int getGender() { + return gender; + } + + public void setGender(int gender) { + this.gender = gender; + } + + /** Not-null value. */ + public String getMainName() { + return mainName; + } + + /** Not-null value; ensure this value is available before it is saved to the database. */ + public void setMainName(String mainName) { + this.mainName = mainName; + } + + /** Not-null value. */ + public String getPinyinName() { + return pinyinName; + } + + /** Not-null value; ensure this value is available before it is saved to the database. */ + public void setPinyinName(String pinyinName) { + this.pinyinName = pinyinName; + } + + /** Not-null value. */ + public String getRealName() { + return realName; + } + + /** Not-null value; ensure this value is available before it is saved to the database. */ + public void setRealName(String realName) { + this.realName = realName; + } + + /** Not-null value. */ + public String getAvatar() { + return avatar; + } + + /** Not-null value; ensure this value is available before it is saved to the database. */ + public void setAvatar(String avatar) { + this.avatar = avatar; + } + + /** Not-null value. */ + public String getPhone() { + return phone; + } + + /** Not-null value; ensure this value is available before it is saved to the database. */ + public void setPhone(String phone) { + this.phone = phone; + } + + /** Not-null value. */ + public String getEmail() { + return email; + } + + /** Not-null value; ensure this value is available before it is saved to the database. */ + public void setEmail(String email) { + this.email = email; + } + + public int getDepartmentId() { + return departmentId; + } + + public void setDepartmentId(int departmentId) { + this.departmentId = departmentId; + } + + public int getStatus() { + return status; + } + + public void setStatus(int status) { + this.status = status; + } + + public int getCreated() { + return created; + } + + public void setCreated(int created) { + this.created = created; + } + + public int getUpdated() { + return updated; + } + + public void setUpdated(int updated) { + this.updated = updated; + } + + // KEEP METHODS - put your custom methods here + + + @Override + public String toString() { + return "UserEntity{" + + "id=" + id + + ", peerId=" + peerId + + ", gender=" + gender + + ", mainName='" + mainName + '\'' + + ", pinyinName='" + pinyinName + '\'' + + ", realName='" + realName + '\'' + + ", avatar='" + avatar + '\'' + + ", phone='" + phone + '\'' + + ", email='" + email + '\'' + + ", departmentId=" + departmentId + + ", status=" + status + + ", created=" + created + + ", updated=" + updated + + ", pinyinElement=" + pinyinElement + + ", searchElement=" + searchElement + + '}'; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (!(o instanceof UserEntity)) return false; + + UserEntity entity = (UserEntity) o; + + if (departmentId != entity.departmentId) return false; + if (gender != entity.gender) return false; + if (peerId != entity.peerId) return false; + if (status != entity.status) return false; + if (avatar != null ? !avatar.equals(entity.avatar) : entity.avatar != null) return false; + if (email != null ? !email.equals(entity.email) : entity.email != null) return false; + if (mainName != null ? !mainName.equals(entity.mainName) : entity.mainName != null) + return false; + if (phone != null ? !phone.equals(entity.phone) : entity.phone != null) return false; + if (pinyinName != null ? !pinyinName.equals(entity.pinyinName) : entity.pinyinName != null) + return false; + if (realName != null ? !realName.equals(entity.realName) : entity.realName != null) + return false; + + return true; + } + + @Override + public int hashCode() { + int result = peerId; + result = 31 * result + gender; + result = 31 * result + (mainName != null ? mainName.hashCode() : 0); + result = 31 * result + (pinyinName != null ? pinyinName.hashCode() : 0); + result = 31 * result + (realName != null ? realName.hashCode() : 0); + result = 31 * result + (avatar != null ? avatar.hashCode() : 0); + result = 31 * result + (phone != null ? phone.hashCode() : 0); + result = 31 * result + (email != null ? email.hashCode() : 0); + result = 31 * result + departmentId; + result = 31 * result + status; + return result; + } + + public PinYinElement getPinyinElement() { + return pinyinElement; + } + + + public SearchElement getSearchElement() { + return searchElement; + } + + public String getSectionName() { + if (TextUtils.isEmpty(pinyinElement.pinyin)) { + return ""; + } + return pinyinElement.pinyin.substring(0, 1); + } + + @Override + public int getType() { + return DBConstant.SESSION_TYPE_SINGLE; + } + + // KEEP METHODS END + +} diff --git a/android/app/src/main/java/com/mogujie/tt/DB/sp/ConfigurationSp.java b/android/app/src/main/java/com/mogujie/tt/DB/sp/ConfigurationSp.java new file mode 100644 index 000000000..5ef2b3da7 --- /dev/null +++ b/android/app/src/main/java/com/mogujie/tt/DB/sp/ConfigurationSp.java @@ -0,0 +1,152 @@ +package com.mogujie.tt.DB.sp; + +import android.content.Context; +import android.content.SharedPreferences; +import android.text.TextUtils; + +import com.mogujie.tt.imservice.event.SessionEvent; + +import java.util.HashSet; +import java.util.Set; + +import de.greenrobot.event.EventBus; + +/** + * @author : yingmu on 15-1-6. + * @email : yingmu@mogujie.com. + *

+ * 特定用户的配置文件 + * User_userId.ini + *

+ * todo + * 1.lastUpdate 2.lastVersion 3.listMsg 需要保存嘛 + *

+ *

+ * 群置顶的功能也会放在这里 + * 现在的有两种key sessionKey 以及 DBConstant的Global + * 多端的状态最好不放在这里。备注: 例如屏蔽的状态 + */ +public class ConfigurationSp { + private Context ctx; + private int loginId; + private String fileName; + private SharedPreferences sharedPreferences; + + private static ConfigurationSp configurationSp = null; + + public static ConfigurationSp instance(Context ctx, int loginId) { + if (configurationSp == null || configurationSp.loginId != loginId) { + synchronized (ConfigurationSp.class) { + configurationSp = new ConfigurationSp(ctx, loginId); + return configurationSp; + } + } + return configurationSp; + } + + private ConfigurationSp(Context ctx, int loginId) { + this.ctx = ctx; + this.loginId = loginId; + this.fileName = "User_" + loginId + ".ini"; + this.sharedPreferences = ctx.getSharedPreferences(fileName, ctx.MODE_PRIVATE); + } + + // 获取全部置顶的session + public HashSet getSessionTopList() { + Set topList = sharedPreferences.getStringSet(CfgDimension.SESSIONTOP.name(), null); + if (null == topList) { + return null; + } + return (HashSet) topList; + } + + + public boolean isTopSession(String sessionKey) { + HashSet list = getSessionTopList(); + if (list != null && list.size() > 0 && list.contains(sessionKey)) { + return true; + } + return false; + } + + /** + * shareF 在设定set的时候有个蛋疼的点 + * 参考:http://stackoverflow.com/questions/12528836/shared-preferences-only-saved-first-time + * + * @param sessionKey + * @param isTop + */ + public void setSessionTop(String sessionKey, boolean isTop) { + if (TextUtils.isEmpty(sessionKey)) { + return; + } + Set topList = sharedPreferences.getStringSet(CfgDimension.SESSIONTOP.name(), null); + Set newList = new HashSet<>(); + if (topList != null && topList.size() > 0) { + newList.addAll(topList); + } + + if (isTop) { + newList.add(sessionKey); + } else { + if (newList.contains(sessionKey)) { + newList.remove(sessionKey); + } + } + + SharedPreferences.Editor editor = sharedPreferences.edit(); + editor.putStringSet(CfgDimension.SESSIONTOP.name(), newList); + //提交当前数据 + editor.apply(); + EventBus.getDefault().post(SessionEvent.SET_SESSION_TOP); + } + + + public boolean getCfg(String key, CfgDimension dimension) { + boolean defaultOnff = dimension == CfgDimension.NOTIFICATION ? false : true; + boolean onOff = sharedPreferences.getBoolean(dimension.name() + key, defaultOnff); + return onOff; + } + + + public void setCfg(String key, CfgDimension dimension, boolean onoff) { + SharedPreferences.Editor editor = sharedPreferences.edit(); + editor.putBoolean(dimension.name() + key, onoff); + //提交当前数据 + editor.commit(); + } + + // 更新时间基准点, 暂时没有使用! + public int getTimeLine(TimeLine timeLine) { + int updateTime = sharedPreferences.getInt(timeLine.name(), 0); + return updateTime; + } + + public void setTimeLine(TimeLine timeLine, int newTimePoint) { + SharedPreferences.Editor editor = sharedPreferences.edit(); + editor.putInt(timeLine.name(), newTimePoint); + //提交当前数据 + editor.commit(); + } + + /** + * 1. 勿扰 + * 2. 声音 + * 3. 自动 + * 4. 通知的方式 one session/ one message + */ + public enum CfgDimension { + NOTIFICATION, + SOUND, + VIBRATION, + + //置顶session 设定 + SESSIONTOP, + } + + public enum TimeLine { + // session回话增量更新的时间点 + SESSION_UPDATE_TIME + } + +} diff --git a/android/app/src/main/java/com/mogujie/tt/DB/sp/LoginSp.java b/android/app/src/main/java/com/mogujie/tt/DB/sp/LoginSp.java new file mode 100644 index 000000000..c9e3e6cd3 --- /dev/null +++ b/android/app/src/main/java/com/mogujie/tt/DB/sp/LoginSp.java @@ -0,0 +1,91 @@ +package com.mogujie.tt.DB.sp; + +import android.content.Context; +import android.content.SharedPreferences; +import android.text.TextUtils; + +/** + * @author : yingmu on 15-1-6. + * @email : yingmu@mogujie.com. + * + * todo need Encryption + */ +public class LoginSp { + + private final String fileName = "login.ini"; + private Context ctx; + private final String KEY_LOGIN_NAME = "loginName"; + private final String KEY_PWD = "pwd"; + private final String KEY_LOGIN_ID = "loginId"; + + + SharedPreferences sharedPreferences; + + private static LoginSp loginSp = null; + public static LoginSp instance(){ + if(loginSp ==null){ + synchronized (LoginSp.class){ + loginSp = new LoginSp(); + } + } + return loginSp; + } + private LoginSp(){ + } + + + public void init(Context ctx){ + this.ctx = ctx; + sharedPreferences= ctx.getSharedPreferences + (fileName,ctx.MODE_PRIVATE); + } + + public void setLoginInfo(String userName,String pwd,int loginId){ + // 横写 + SharedPreferences.Editor editor = sharedPreferences.edit(); + editor.putString(KEY_LOGIN_NAME, userName); + editor.putString(KEY_PWD, pwd); + editor.putInt(KEY_LOGIN_ID, loginId); + //提交当前数据 + editor.commit(); + } + + public SpLoginIdentity getLoginIdentity(){ + String userName = sharedPreferences.getString(KEY_LOGIN_NAME,null); + String pwd = sharedPreferences.getString(KEY_PWD,null); + int loginId = sharedPreferences.getInt(KEY_LOGIN_ID,0); + /**pwd不判空: loginOut的时候会将pwd清空*/ + if(TextUtils.isEmpty(userName) || loginId == 0){ + return null; + } + return new SpLoginIdentity(userName,pwd,loginId); + } + + public class SpLoginIdentity{ + private String loginName; + private String pwd; + private int loginId; + + public SpLoginIdentity(String mUserName,String mPwd,int mLoginId){ + loginName = mUserName; + pwd = mPwd; + loginId = mLoginId; + } + + public int getLoginId() { + return loginId; + } + + public void setLoginId(int loginId) { + this.loginId = loginId; + } + + public String getLoginName() { + return loginName; + } + + public String getPwd() { + return pwd; + } + } +} diff --git a/android/app/src/main/java/com/mogujie/tt/DB/sp/SystemConfigSp.java b/android/app/src/main/java/com/mogujie/tt/DB/sp/SystemConfigSp.java new file mode 100644 index 000000000..315e00b4f --- /dev/null +++ b/android/app/src/main/java/com/mogujie/tt/DB/sp/SystemConfigSp.java @@ -0,0 +1,68 @@ +package com.mogujie.tt.DB.sp; + +import android.content.Context; +import android.content.SharedPreferences; + +/** + * Created by zhujian on 15/3/20. + *

+ * 保存系统配置类信息 + */ +public class SystemConfigSp { + private final String fileName = "systemconfig.ini"; + private Context ctx; + SharedPreferences sharedPreferences; + private static SystemConfigSp systemConfigSp = null; + + public static SystemConfigSp instance() { + if (systemConfigSp == null) { + synchronized (LoginSp.class) { + systemConfigSp = new SystemConfigSp(); + } + } + return systemConfigSp; + } + + private SystemConfigSp() { + + } + + public void init(Context ctx) { + this.ctx = ctx; + sharedPreferences = ctx.getSharedPreferences + (fileName, ctx.MODE_PRIVATE); + } + + public String getStrConfig(SysCfgDimension dimension) { + String strValue = sharedPreferences.getString(dimension.name(), ""); + return strValue; + } + + public void setStrConfig(SysCfgDimension dimension, String value) { + SharedPreferences.Editor editor = sharedPreferences.edit(); + editor.putString(dimension.name(), value); + //提交当前数据 + editor.commit(); + } + + public int getIntConfig(SysCfgDimension dimension) { + int strValue = sharedPreferences.getInt(dimension.name(), 0); + return strValue; + } + + public void setIntConfig(SysCfgDimension dimension, int value) { + SharedPreferences.Editor editor = sharedPreferences.edit(); + editor.putInt(dimension.name(), value); + //提交当前数据 + editor.commit(); + } + + public enum SysCfgDimension { + KEYBOARDHEIGHT, + DEFAULTINPUTMETHOD, + DISCOVERYURI, + LOGINSERVER, + DISCOVERYDATA, + MSFSSERVER + } +} diff --git a/android/app/src/main/java/com/mogujie/tt/Security.java b/android/app/src/main/java/com/mogujie/tt/Security.java new file mode 100644 index 000000000..78e46b534 --- /dev/null +++ b/android/app/src/main/java/com/mogujie/tt/Security.java @@ -0,0 +1,25 @@ +package com.mogujie.tt; + +public class Security { + + public native byte[] DecryptMsg(String strMsg); + public native byte[] EncryptMsg(String strMsg); + + public native byte[] EncryptPass(String strPass); + + static{ + System.loadLibrary("security"); + } + + private static Security m_pInstance; + + public static Security getInstance() { + synchronized (Security.class) { + if (m_pInstance == null) { + m_pInstance = new Security(); + } + + return m_pInstance; + } + } +} diff --git a/android/app/src/main/java/com/mogujie/tt/app/IMApplication.java b/android/app/src/main/java/com/mogujie/tt/app/IMApplication.java new file mode 100644 index 000000000..255a4ae56 --- /dev/null +++ b/android/app/src/main/java/com/mogujie/tt/app/IMApplication.java @@ -0,0 +1,36 @@ +package com.mogujie.tt.app; + +import android.app.Application; +import android.content.Intent; +import com.mogujie.tt.imservice.service.IMService; +import com.mogujie.tt.utils.ImageLoaderUtil; +import com.mogujie.tt.utils.Logger; + + +public class IMApplication extends Application { + + private Logger logger = Logger.getLogger(IMApplication.class); + + /** + * @param args + */ + public static void main(String[] args) { + } + + @Override + public void onCreate() { + super.onCreate(); + logger.i("Application starts"); + startIMService(); + ImageLoaderUtil.initImageLoaderConfig(getApplicationContext()); + } + + private void startIMService() { + logger.i("start IMService"); + Intent intent = new Intent(); + intent.setClass(this, IMService.class); + startService(intent); + } + + public static boolean gifRunning = true;//gif是否运行 +} diff --git a/android/app/src/main/java/com/mogujie/tt/app/UpdateDetection.java b/android/app/src/main/java/com/mogujie/tt/app/UpdateDetection.java new file mode 100644 index 000000000..c4979b4bf --- /dev/null +++ b/android/app/src/main/java/com/mogujie/tt/app/UpdateDetection.java @@ -0,0 +1,237 @@ +package com.mogujie.tt.app; + +import android.app.AlertDialog; +import android.app.Dialog; +import android.content.Context; +import android.content.DialogInterface; +import android.content.Intent; +import android.content.pm.PackageInfo; +import android.content.pm.PackageManager; +import android.net.Uri; +import android.os.Environment; +import android.os.Handler; +import android.os.Message; +import android.view.LayoutInflater; +import android.view.View; +import android.widget.ProgressBar; + +import com.mogujie.tt.R; + +import java.io.File; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.net.HttpURLConnection; +import java.net.MalformedURLException; +import java.net.URL; + +/** + * @author : yingmu on 15-2-11. + * @email : yingmu@mogujie.com. + * + * 备注: 需要服务端提供接口 + */ +// not use now +public class UpdateDetection { + private Context mContext; + //提示语 + private String updateMsg = "有最新的软件包哦,亲快下载吧~"; + + //返回的安装包url + private String apkVersion; + private String apkUrl; + + // 交互对话框 + private Dialog noticeDialog; + private Dialog downloadDialog; + + /* 下载包安装路径 */ + private String savePath; + private String saveFileName; + + /* 进度条与通知ui刷新的handler和msg常量 */ + private ProgressBar mProgress; + + + private static final int ON_DOWNLOADING = 1; + private static final int DOWNLOAD_FINISH = 2; + private int progress; + + + private Thread downLoadThread; + private boolean interceptFlag = false; + + private Handler mHandler = new Handler(){ + public void handleMessage(Message msg) { + switch (msg.what) { + case ON_DOWNLOADING: + mProgress.setProgress(progress); + break; + case DOWNLOAD_FINISH: + installApk(); + break; + default: + break; + } + }; + }; + + public UpdateDetection(Context context) { + this.mContext = context; + + // 设定下载的文件路径 + if (Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)) { + savePath = Environment.getExternalStorageDirectory() + "/" + "download"; + saveFileName = savePath + "/teamtalk.apk"; + } + } + + // 获取当前的版本号 + // todo you set localinfo in xml + private int getCurrentVersion(){ + String verName = ""; + int verCode = 0; + return verCode; + } + + // todo 另外的方法获取 版本号 + private int getVersionCode() { + // 获取packagemanager的实例 + PackageManager packageManager = mContext.getPackageManager(); + // getPackageName()是你当前类的包名,0代表是获取版本信息 + PackageInfo packInfo = new PackageInfo(); + try { + packInfo = packageManager.getPackageInfo(mContext.getPackageName(),0); + } catch (PackageManager.NameNotFoundException e) { + e.printStackTrace(); + } + return packInfo.versionCode; + } + + //外部接口让主Activity调用 + public void checkUpdateInfo(){ + int curVer = getVersionCode(); + int latest = getNewestInfo(); + if(curVer { + public abstract void onSuccess(T response); + + public abstract void onFaild(); + + public abstract void onTimeout(); +} diff --git a/android/app/src/main/java/com/mogujie/tt/imservice/callback/ListenerQueue.java b/android/app/src/main/java/com/mogujie/tt/imservice/callback/ListenerQueue.java new file mode 100644 index 000000000..7db4b0df9 --- /dev/null +++ b/android/app/src/main/java/com/mogujie/tt/imservice/callback/ListenerQueue.java @@ -0,0 +1,104 @@ +package com.mogujie.tt.imservice.callback; + +import android.os.Handler; + +import com.mogujie.tt.utils.Logger; + +import java.util.ArrayList; +import java.util.List; +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; + +/** + * @author : yingmu on 15-1-7. + * @email : yingmu@mogujie.com. + */ +public class ListenerQueue { + + private static ListenerQueue listenerQueue = new ListenerQueue(); + private Logger logger = Logger.getLogger(ListenerQueue.class); + public static ListenerQueue instance(){ + return listenerQueue; + } + + private volatile boolean stopFlag = false; + private volatile boolean hasTask = false; + + + //callback 队列 + private Map callBackQueue = new ConcurrentHashMap<>(); + private Handler timerHandler = new Handler(); + + + public void onStart(){ + logger.d("ListenerQueue#onStart run"); + stopFlag = false; + startTimer(); + } + public void onDestory(){ + logger.d("ListenerQueue#onDestory "); + callBackQueue.clear(); + stopTimer(); + } + + //以前是TimerTask处理方式 + private void startTimer() { + if(!stopFlag && hasTask == false) { + hasTask = true; + timerHandler.postDelayed(new Runnable() { + @Override + public void run() { + timerImpl(); + hasTask = false; + startTimer(); + } + }, 5 * 1000); + } + } + + private void stopTimer(){ + stopFlag = true; + } + + private void timerImpl() { + long currentRealtime = System.currentTimeMillis();//SystemClock.elapsedRealtime(); + + for (java.util.Map.Entry entry : callBackQueue.entrySet()) { + + Packetlistener packetlistener = entry.getValue(); + Integer seqNo = entry.getKey(); + long timeRange = currentRealtime - packetlistener.getCreateTime(); + + try { + if (timeRange >= packetlistener.getTimeOut()) { + logger.d("ListenerQueue#find timeout msg"); + Packetlistener listener = pop(seqNo); + if (listener != null) { + listener.onTimeout(); + } + } + } catch (Exception e) { + logger.d("ListenerQueue#timerImpl onTimeout is Error,exception is %s", e.getCause()); + } + } + } + + public void push(int seqNo,Packetlistener packetlistener){ + if(seqNo <=0 || null==packetlistener){ + logger.d("ListenerQueue#push error, cause by Illegal params"); + return; + } + callBackQueue.put(seqNo,packetlistener); + } + + + public Packetlistener pop(int seqNo){ + synchronized (ListenerQueue.this) { + if (callBackQueue.containsKey(seqNo)) { + Packetlistener packetlistener = callBackQueue.remove(seqNo); + return packetlistener; + } + return null; + } + } +} diff --git a/android/app/src/main/java/com/mogujie/tt/imservice/callback/Packetlistener.java b/android/app/src/main/java/com/mogujie/tt/imservice/callback/Packetlistener.java new file mode 100644 index 000000000..6fb4816db --- /dev/null +++ b/android/app/src/main/java/com/mogujie/tt/imservice/callback/Packetlistener.java @@ -0,0 +1,43 @@ +package com.mogujie.tt.imservice.callback; + +/** + * @author : yingmu on 15-1-7. + * @email : yingmu@mogujie.com. + */ +public abstract class Packetlistener implements IMListener { + private long createTime; + private long timeOut; + public Packetlistener(long timeOut){ + this.timeOut = timeOut; + long now = System.currentTimeMillis(); + createTime = now; + } + + public Packetlistener(){ + this.timeOut = 8*1000; + long now = System.currentTimeMillis(); + createTime = now; + } + + public long getCreateTime() { + return createTime; + } + + public void setCreateTime(long createTime) { + this.createTime = createTime; + } + + public long getTimeOut() { + return timeOut; + } + + public void setTimeOut(long timeOut) { + this.timeOut = timeOut; + } + + public abstract void onSuccess(Object response); + + public abstract void onFaild(); + + public abstract void onTimeout(); +} diff --git a/android/app/src/main/java/com/mogujie/tt/imservice/entity/AudioMessage.java b/android/app/src/main/java/com/mogujie/tt/imservice/entity/AudioMessage.java new file mode 100644 index 000000000..ede0b17c0 --- /dev/null +++ b/android/app/src/main/java/com/mogujie/tt/imservice/entity/AudioMessage.java @@ -0,0 +1,165 @@ +package com.mogujie.tt.imservice.entity; + +import android.text.TextUtils; + +import com.mogujie.tt.DB.entity.PeerEntity; +import com.mogujie.tt.DB.entity.UserEntity; +import com.mogujie.tt.config.DBConstant; +import com.mogujie.tt.DB.entity.MessageEntity; +import com.mogujie.tt.config.MessageConstant; +import com.mogujie.tt.utils.CommonUtil; +import com.mogujie.tt.utils.FileUtil; +import com.mogujie.tt.imservice.support.SequenceNumberMaker; + +import org.json.JSONException; +import org.json.JSONObject; + +import java.io.Serializable; + +/** + * @author : yingmu on 14-12-31. + * @email : yingmu@mogujie.com. + * + */ +public class AudioMessage extends MessageEntity implements Serializable{ + + private String audioPath = ""; + private int audiolength =0 ; + private int readStatus = MessageConstant.AUDIO_UNREAD; + + public AudioMessage(){ + msgId = SequenceNumberMaker.getInstance().makelocalUniqueMsgId(); + } + + private AudioMessage(MessageEntity entity){ + // 父类主键 + id = entity.getId(); + msgId = entity.getMsgId(); + fromId = entity.getFromId(); + toId = entity.getToId(); + content=entity.getContent(); + msgType=entity.getMsgType(); + sessionKey = entity.getSessionKey(); + displayType=entity.getDisplayType(); + status = entity.getStatus(); + created = entity.getCreated(); + updated = entity.getUpdated(); + } + + + public static AudioMessage parseFromDB(MessageEntity entity) { + if(entity.getDisplayType() != DBConstant.SHOW_AUDIO_TYPE){ + throw new RuntimeException("#AudioMessage# parseFromDB,not SHOW_AUDIO_TYPE"); + } + AudioMessage audioMessage = new AudioMessage(entity); + // 注意坑 啊 + String originContent = entity.getContent(); + + JSONObject extraContent = null; + try { + extraContent = new JSONObject(originContent); + audioMessage.setAudioPath(extraContent.getString("audioPath")); + audioMessage.setAudiolength(extraContent.getInt("audiolength")); + audioMessage.setReadStatus(extraContent.getInt("readStatus")); + } catch (JSONException e) { + e.printStackTrace(); + } + + return audioMessage; + } + + public static AudioMessage buildForSend(float audioLen,String audioSavePath,UserEntity fromUser,PeerEntity peerEntity){ + int tLen = (int) (audioLen + 0.5); + tLen = tLen < 1 ? 1 : tLen; + if (tLen < audioLen) { + ++tLen; + } + + int nowTime = (int) (System.currentTimeMillis() / 1000); + AudioMessage audioMessage = new AudioMessage(); + audioMessage.setFromId(fromUser.getPeerId()); + audioMessage.setToId(peerEntity.getPeerId()); + audioMessage.setCreated(nowTime); + audioMessage.setUpdated(nowTime); + int peerType = peerEntity.getType(); + int msgType = peerType == DBConstant.SESSION_TYPE_GROUP ? DBConstant.MSG_TYPE_GROUP_AUDIO : + DBConstant.MSG_TYPE_SINGLE_AUDIO; + audioMessage.setMsgType(msgType); + + audioMessage.setAudioPath(audioSavePath); + audioMessage.setAudiolength(tLen); + audioMessage.setReadStatus(MessageConstant.AUDIO_READED); + audioMessage.setDisplayType(DBConstant.SHOW_AUDIO_TYPE); + audioMessage.setStatus(MessageConstant.MSG_SENDING); + audioMessage.buildSessionKey(true); + return audioMessage; + } + + + /** + * Not-null value. + * DB 存数解析的时候需要 + */ + @Override + public String getContent() { + JSONObject extraContent = new JSONObject(); + try { + extraContent.put("audioPath",audioPath); + extraContent.put("audiolength",audiolength); + extraContent.put("readStatus",readStatus); + String audioContent = extraContent.toString(); + return audioContent; + } catch (JSONException e) { + e.printStackTrace(); + } + return null; + } + + + @Override + public byte[] getSendContent() { + byte[] result = new byte[4]; + result = CommonUtil.intToBytes(audiolength); + if (TextUtils.isEmpty(audioPath)) { + return result; + } + + byte[] bytes = FileUtil.getFileContent(audioPath); + if (bytes == null) { + return bytes; + } + int contentLength = bytes.length; + byte[] byteAduioContent = new byte[4 + contentLength]; + System.arraycopy(result, 0, byteAduioContent, 0, 4); + System.arraycopy(bytes, 0, byteAduioContent, 4, contentLength); + return byteAduioContent; + } + + + /***-------------------------------set/get----------------------------------*/ + public String getAudioPath() { + return audioPath; + } + + public void setAudioPath(String audioPath) { + this.audioPath = audioPath; + } + + public int getAudiolength() { + return audiolength; + } + + public void setAudiolength(int audiolength) { + this.audiolength = audiolength; + } + + public int getReadStatus() { + return readStatus; + } + + public void setReadStatus(int readStatus) { + this.readStatus = readStatus; + } + + +} diff --git a/android/app/src/main/java/com/mogujie/tt/imservice/entity/ImageMessage.java b/android/app/src/main/java/com/mogujie/tt/imservice/entity/ImageMessage.java new file mode 100644 index 000000000..6d25033be --- /dev/null +++ b/android/app/src/main/java/com/mogujie/tt/imservice/entity/ImageMessage.java @@ -0,0 +1,276 @@ +package com.mogujie.tt.imservice.entity; + +import com.mogujie.tt.DB.entity.MessageEntity; +import com.mogujie.tt.DB.entity.PeerEntity; +import com.mogujie.tt.DB.entity.UserEntity; +import com.mogujie.tt.config.DBConstant; +import com.mogujie.tt.config.MessageConstant; +import com.mogujie.tt.imservice.support.SequenceNumberMaker; +import com.mogujie.tt.ui.adapter.album.ImageItem; + +import org.json.JSONException; +import org.json.JSONObject; + +import java.io.File; +import java.io.Serializable; +import java.io.UnsupportedEncodingException; +import java.util.ArrayList; +import java.util.Collections; +import java.util.Comparator; + +/** + * @author : yingmu on 14-12-31. + * @email : yingmu@mogujie.com. + */ +public class ImageMessage extends MessageEntity implements Serializable { + + /**本地保存的path*/ + private String path = ""; + /**图片的网络地址*/ + private String url = ""; + private int loadStatus; + + //存储图片消息 + private static java.util.HashMap imageMessageMap = new java.util.HashMap(); + private static ArrayList imageList=null; + /** + * 添加一条图片消息 + * @param msg + */ + public static synchronized void addToImageMessageList(ImageMessage msg){ + try { + if(msg!=null && msg.getId()!=null) + { + imageMessageMap.put(msg.getId(),msg); + } + }catch (Exception e){ + } + } + + /** + * 获取图片列表 + * @return + */ + public static ArrayList getImageMessageList(){ + imageList = new ArrayList<>(); + java.util.Iterator it = imageMessageMap.keySet().iterator(); + while (it.hasNext()) { + imageList.add(imageMessageMap.get(it.next())); + } + Collections.sort(imageList, new Comparator(){ + public int compare(ImageMessage image1, ImageMessage image2) { + Integer a = image1.getUpdated(); + Integer b = image2.getUpdated(); + if(a.equals(b)) + { + return image2.getId().compareTo(image1.getId()); + } + // 升序 + //return a.compareTo(b); + // 降序 + return b.compareTo(a); + } + }); + return imageList; + } + + /** + * 清除图片列表 + */ + public static synchronized void clearImageMessageList(){ + imageMessageMap.clear(); + imageMessageMap.clear(); + } + + + + public ImageMessage(){ + msgId = SequenceNumberMaker.getInstance().makelocalUniqueMsgId(); + } + + /**消息拆分的时候需要*/ + private ImageMessage(MessageEntity entity){ + /**父类的id*/ + id = entity.getId(); + msgId = entity.getMsgId(); + fromId = entity.getFromId(); + toId = entity.getToId(); + sessionKey = entity.getSessionKey(); + content=entity.getContent(); + msgType=entity.getMsgType(); + displayType=entity.getDisplayType(); + status = entity.getStatus(); + created = entity.getCreated(); + updated = entity.getUpdated(); + } + + /**接受到网络包,解析成本地的数据*/ + public static ImageMessage parseFromNet(MessageEntity entity) throws JSONException { + String strContent = entity.getContent(); + // 判断开头与结尾 + if (strContent.startsWith(MessageConstant.IMAGE_MSG_START) + && strContent.endsWith(MessageConstant.IMAGE_MSG_END)) { + // image message todo 字符串处理下 + ImageMessage imageMessage = new ImageMessage(entity); + imageMessage.setDisplayType(DBConstant.SHOW_IMAGE_TYPE); + String imageUrl = strContent.substring(MessageConstant.IMAGE_MSG_START.length()); + imageUrl = imageUrl.substring(0,imageUrl.indexOf(MessageConstant.IMAGE_MSG_END)); + + /**抽离出来 或者用gson*/ + JSONObject extraContent = new JSONObject(); + extraContent.put("path",""); + extraContent.put("url",imageUrl); + extraContent.put("loadStatus", MessageConstant.IMAGE_UNLOAD); + String imageContent = extraContent.toString(); + imageMessage.setContent(imageContent); + + imageMessage.setUrl(imageUrl.isEmpty() ? null : imageUrl); + imageMessage.setContent(strContent); + imageMessage.setLoadStatus(MessageConstant.IMAGE_UNLOAD); + imageMessage.setStatus(MessageConstant.MSG_SUCCESS); + return imageMessage; + }else{ + throw new RuntimeException("no image type,cause by [start,end] is wrong!"); + } + } + + + public static ImageMessage parseFromDB(MessageEntity entity) { + if(entity.getDisplayType() != DBConstant.SHOW_IMAGE_TYPE){ + throw new RuntimeException("#ImageMessage# parseFromDB,not SHOW_IMAGE_TYPE"); + } + ImageMessage imageMessage = new ImageMessage(entity); + String originContent = entity.getContent(); + JSONObject extraContent; + try { + extraContent = new JSONObject(originContent); + imageMessage.setPath(extraContent.getString("path")); + imageMessage.setUrl(extraContent.getString("url")); + int loadStatus = extraContent.getInt("loadStatus"); + + //todo temp solution + if(loadStatus == MessageConstant.IMAGE_LOADING){ + loadStatus = MessageConstant.IMAGE_UNLOAD; + } + imageMessage.setLoadStatus(loadStatus); + } catch (JSONException e) { + e.printStackTrace(); + } + + return imageMessage; + } + + // 消息页面,发送图片消息 + public static ImageMessage buildForSend(ImageItem item,UserEntity fromUser,PeerEntity peerEntity){ + ImageMessage msg = new ImageMessage(); + if (new File(item.getImagePath()).exists()) { + msg.setPath(item.getImagePath()); + } else { + if (new File(item.getThumbnailPath()).exists()) { + msg.setPath(item.getThumbnailPath()); + } else { + // 找不到图片路径时使用加载失败的图片展示 + msg.setPath(null); + } + } + // 将图片发送至服务器 + int nowTime = (int) (System.currentTimeMillis() / 1000); + + msg.setFromId(fromUser.getPeerId()); + msg.setToId(peerEntity.getPeerId()); + msg.setCreated(nowTime); + msg.setUpdated(nowTime); + msg.setDisplayType(DBConstant.SHOW_IMAGE_TYPE); + // content 自动生成的 + int peerType = peerEntity.getType(); + int msgType = peerType == DBConstant.SESSION_TYPE_GROUP ? DBConstant.MSG_TYPE_GROUP_TEXT : + DBConstant.MSG_TYPE_SINGLE_TEXT; + msg.setMsgType(msgType); + + msg.setStatus(MessageConstant.MSG_SENDING); + msg.setLoadStatus(MessageConstant.IMAGE_UNLOAD); + msg.buildSessionKey(true); + return msg; + } + + public static ImageMessage buildForSend(String takePhotoSavePath,UserEntity fromUser,PeerEntity peerEntity){ + ImageMessage imageMessage = new ImageMessage(); + int nowTime = (int) (System.currentTimeMillis() / 1000); + imageMessage.setFromId(fromUser.getPeerId()); + imageMessage.setToId(peerEntity.getPeerId()); + imageMessage.setUpdated(nowTime); + imageMessage.setCreated(nowTime); + imageMessage.setDisplayType(DBConstant.SHOW_IMAGE_TYPE); + imageMessage.setPath(takePhotoSavePath); + int peerType = peerEntity.getType(); + int msgType = peerType == DBConstant.SESSION_TYPE_GROUP ? DBConstant.MSG_TYPE_GROUP_TEXT + : DBConstant.MSG_TYPE_SINGLE_TEXT; + imageMessage.setMsgType(msgType); + + imageMessage.setStatus(MessageConstant.MSG_SENDING); + imageMessage.setLoadStatus(MessageConstant.IMAGE_UNLOAD); + imageMessage.buildSessionKey(true); + return imageMessage; + } + + /** + * Not-null value. + */ + @Override + public String getContent() { + JSONObject extraContent = new JSONObject(); + try { + extraContent.put("path",path); + extraContent.put("url",url); + extraContent.put("loadStatus",loadStatus); + String imageContent = extraContent.toString(); + return imageContent; + } catch (JSONException e) { + e.printStackTrace(); + } + return null; + } + + @Override + public byte[] getSendContent() { + // 发送的时候非常关键 + String sendContent = MessageConstant.IMAGE_MSG_START + + url + MessageConstant.IMAGE_MSG_END; + /** + * 加密 + */ + String encrySendContent =new String(com.mogujie.tt.Security.getInstance().EncryptMsg(sendContent)); + + try { + return encrySendContent.getBytes("utf-8"); + } catch (UnsupportedEncodingException e) { + e.printStackTrace(); + } + return null; + } + + /**-----------------------set/get------------------------*/ + public String getPath() { + return path; + } + + public void setPath(String path) { + this.path = path; + } + + public String getUrl() { + return url; + } + + public void setUrl(String url) { + this.url = url; + } + + public int getLoadStatus() { + return loadStatus; + } + + public void setLoadStatus(int loadStatus) { + this.loadStatus = loadStatus; + } +} diff --git a/android/app/src/main/java/com/mogujie/tt/imservice/entity/MixMessage.java b/android/app/src/main/java/com/mogujie/tt/imservice/entity/MixMessage.java new file mode 100644 index 000000000..58dad6a3a --- /dev/null +++ b/android/app/src/main/java/com/mogujie/tt/imservice/entity/MixMessage.java @@ -0,0 +1,148 @@ +package com.mogujie.tt.imservice.entity; + +import com.google.gson.Gson; +import com.google.gson.GsonBuilder; +import com.mogujie.tt.config.DBConstant; +import com.mogujie.tt.DB.entity.MessageEntity; + +import org.json.JSONArray; +import org.json.JSONException; +import org.json.JSONObject; + +import java.util.ArrayList; +import java.util.List; + +/** + * @author : yingmu on 15-1-14. + * @email : yingmu@mogujie.com. + */ +public class MixMessage extends MessageEntity { + + public List msgList ; + + + /** + * 从net端解析需要 + * @param entityList + */ + public MixMessage(List entityList){ + if(entityList ==null || entityList.size()<=1){ + throw new RuntimeException("MixMessage# type is error!"); + } + + MessageEntity justOne = entityList.get(0); + id = justOne.getId(); + msgId = justOne.getMsgId(); + fromId = justOne.getFromId(); + toId = justOne.getToId(); + sessionKey = justOne.getSessionKey(); + msgType = justOne.getMsgType(); + status = justOne.getStatus(); + created = justOne.getCreated(); + updated = justOne.getUpdated(); + msgList = entityList; + displayType= DBConstant.SHOW_MIX_TEXT; + + /**分配主键Id + * 图文混排的之间全部从-1开始 + * 在messageAdapter中 结合msgId进行更新 + * + * dbinterface 结合id sessionKey msgid来替换具体的消息 + * {insertOrUpdateMix} + * */ + long index = -1; + for(MessageEntity msg:entityList){ + msg.setId(index); + index --; + } + } + + /** + * Not-null value. + */ + @Override + public String getContent() { + return getSerializableContent(msgList); + } + + /** + *sessionKey是在外边设定的,所以子对象是没有的 + * 所以在设定的时候,都需要加上 + * */ + @Override + public void setSessionKey(String sessionKey) { + super.setSessionKey(sessionKey); + for(MessageEntity msg:msgList){ + msg.setSessionKey(sessionKey); + } + } + + @Override + public void setToId(int toId) { + super.setToId(toId); + for(MessageEntity msg:msgList){ + msg.setToId(toId); + } + } + + public MixMessage(MessageEntity dbEntity){ + id = dbEntity.getId(); + msgId = dbEntity.getMsgId(); + fromId = dbEntity.getFromId(); + toId = dbEntity.getToId(); + msgType = dbEntity.getMsgType(); + status = dbEntity.getStatus(); + created = dbEntity.getCreated(); + updated = dbEntity.getUpdated(); + content = dbEntity.getContent(); + displayType = dbEntity.getDisplayType(); + sessionKey = dbEntity.getSessionKey(); + + } + + private String getSerializableContent(List entityList){ + Gson gson = new Gson(); + String json = gson.toJson(entityList); + return json; + } + + public static MixMessage parseFromDB(MessageEntity entity) throws JSONException { + if(entity.getDisplayType() != DBConstant.SHOW_MIX_TEXT){ + throw new RuntimeException("#MixMessage# parseFromDB,not SHOW_MIX_TEXT"); + } + Gson gson = new GsonBuilder().create(); + MixMessage mixMessage = new MixMessage(entity); + List msgList = new ArrayList<>(); + JSONArray jsonArray = new JSONArray(entity.getContent()); + + for (int i = 0, length = jsonArray.length(); i < length; i++) { + JSONObject jsonOb = (JSONObject) jsonArray.opt(i); + int displayType = jsonOb.getInt("displayType"); + String jsonMessage = jsonOb.toString(); + switch (displayType){ + case DBConstant.SHOW_ORIGIN_TEXT_TYPE:{ + TextMessage textMessage = gson.fromJson(jsonMessage,TextMessage.class); + textMessage.setSessionKey(entity.getSessionKey()); + msgList.add(textMessage); + }break; + + case DBConstant.SHOW_IMAGE_TYPE: + ImageMessage imageMessage = gson.fromJson(jsonMessage,ImageMessage.class); + imageMessage.setSessionKey(entity.getSessionKey()); + msgList.add(imageMessage); + break; + } + } + mixMessage.setMsgList(msgList); + return mixMessage; + } + + + public List getMsgList() { + return msgList; + } + + public void setMsgList(List msgList) { + this.msgList = msgList; + } +} diff --git a/android/app/src/main/java/com/mogujie/tt/imservice/entity/MsgAnalyzeEngine.java b/android/app/src/main/java/com/mogujie/tt/imservice/entity/MsgAnalyzeEngine.java new file mode 100644 index 000000000..344bda43f --- /dev/null +++ b/android/app/src/main/java/com/mogujie/tt/imservice/entity/MsgAnalyzeEngine.java @@ -0,0 +1,171 @@ +package com.mogujie.tt.imservice.entity; + +import android.text.TextUtils; + +import com.mogujie.tt.DB.entity.MessageEntity; +import com.mogujie.tt.config.DBConstant; +import com.mogujie.tt.config.MessageConstant; +import com.mogujie.tt.protobuf.helper.ProtoBuf2JavaBean; +import com.mogujie.tt.protobuf.IMBaseDefine; + +import org.json.JSONException; + +import java.util.ArrayList; +import java.util.List; + +/** + * @author : yingmu on 15-1-6. + * @email : yingmu@mogujie.com. + * + * historical reasons,没有充分利用msgType字段 + * 多端的富文本的考虑 + */ +public class MsgAnalyzeEngine { + public static String analyzeMessageDisplay(String content){ + String finalRes = content; + String originContent = content; + while (!originContent.isEmpty()) { + int nStart = originContent.indexOf(MessageConstant.IMAGE_MSG_START); + if (nStart < 0) {// 没有头 + break; + } else { + String subContentString = originContent.substring(nStart); + int nEnd = subContentString.indexOf(MessageConstant.IMAGE_MSG_END); + if (nEnd < 0) {// 没有尾 + String strSplitString = originContent; + break; + } else {// 匹配到 + String pre = originContent.substring(0, nStart); + + originContent = subContentString.substring(nEnd + + MessageConstant.IMAGE_MSG_END.length()); + + if(!TextUtils.isEmpty(pre) || !TextUtils.isEmpty(originContent)){ + finalRes = DBConstant.DISPLAY_FOR_MIX; + }else{ + finalRes = DBConstant.DISPLAY_FOR_IMAGE; + } + } + } + } + return finalRes; + } + + + // 抽离放在同一的地方 + public static MessageEntity analyzeMessage(IMBaseDefine.MsgInfo msgInfo) { + MessageEntity messageEntity = new MessageEntity(); + + messageEntity.setCreated(msgInfo.getCreateTime()); + messageEntity.setUpdated(msgInfo.getCreateTime()); + messageEntity.setFromId(msgInfo.getFromSessionId()); + messageEntity.setMsgId(msgInfo.getMsgId()); + messageEntity.setMsgType(ProtoBuf2JavaBean.getJavaMsgType(msgInfo.getMsgType())); + messageEntity.setStatus(MessageConstant.MSG_SUCCESS); + messageEntity.setContent(msgInfo.getMsgData().toStringUtf8()); + /** + * 解密文本信息 + */ + String desMessage = new String(com.mogujie.tt.Security.getInstance().DecryptMsg(msgInfo.getMsgData().toStringUtf8())); + messageEntity.setContent(desMessage); + + // 文本信息不为空 + if(!TextUtils.isEmpty(desMessage)){ + List msgList = textDecode(messageEntity); + if(msgList.size()>1){ + // 混合消息 + MixMessage mixMessage = new MixMessage(msgList); + return mixMessage; + }else if(msgList.size() == 0){ + // 可能解析失败 默认返回文本消息 + return TextMessage.parseFromNet(messageEntity); + }else{ + //简单消息,返回第一个 + return msgList.get(0); + } + }else{ + // 如果为空 + return TextMessage.parseFromNet(messageEntity); + } + } + + + /** + * todo 优化字符串分析 + * @param msg + * @return + */ + private static List textDecode(MessageEntity msg){ + List msgList = new ArrayList<>(); + + String originContent = msg.getContent(); + while (!TextUtils.isEmpty(originContent)) { + int nStart = originContent.indexOf(MessageConstant.IMAGE_MSG_START); + if (nStart < 0) {// 没有头 + String strSplitString = originContent; + + MessageEntity entity = addMessage(msg, strSplitString); + if(entity!=null){ + msgList.add(entity); + } + + originContent = ""; + } else { + String subContentString = originContent.substring(nStart); + int nEnd = subContentString.indexOf(MessageConstant.IMAGE_MSG_END); + if (nEnd < 0) {// 没有尾 + String strSplitString = originContent; + + + MessageEntity entity = addMessage(msg,strSplitString); + if(entity!=null){ + msgList.add(entity); + } + + originContent = ""; + } else {// 匹配到 + String pre = originContent.substring(0, nStart); + MessageEntity entity1 = addMessage(msg,pre); + if(entity1!=null){ + msgList.add(entity1); + } + + String matchString = subContentString.substring(0, nEnd + + MessageConstant.IMAGE_MSG_END.length()); + + MessageEntity entity2 = addMessage(msg,matchString); + if(entity2!=null){ + msgList.add(entity2); + } + + originContent = subContentString.substring(nEnd + + MessageConstant.IMAGE_MSG_END.length()); + } + } + } + + return msgList; + } + + + public static MessageEntity addMessage(MessageEntity msg,String strContent) { + if (TextUtils.isEmpty(strContent.trim())){ + return null; + } + msg.setContent(strContent); + + if (strContent.startsWith(MessageConstant.IMAGE_MSG_START) + && strContent.endsWith(MessageConstant.IMAGE_MSG_END)) { + try { + ImageMessage imageMessage = ImageMessage.parseFromNet(msg); + return imageMessage; + } catch (JSONException e) { + // e.printStackTrace(); + return null; + } + } else { + return TextMessage.parseFromNet(msg); + } + } + +} diff --git a/android/app/src/main/java/com/mogujie/tt/imservice/entity/RecentInfo.java b/android/app/src/main/java/com/mogujie/tt/imservice/entity/RecentInfo.java new file mode 100644 index 000000000..339e8f19a --- /dev/null +++ b/android/app/src/main/java/com/mogujie/tt/imservice/entity/RecentInfo.java @@ -0,0 +1,197 @@ +package com.mogujie.tt.imservice.entity; + +import com.mogujie.tt.config.DBConstant; +import com.mogujie.tt.DB.entity.GroupEntity; +import com.mogujie.tt.DB.entity.SessionEntity; +import com.mogujie.tt.DB.entity.UserEntity; +import com.mogujie.tt.imservice.manager.IMContactManager; +import com.mogujie.tt.utils.pinyin.PinYin; + +import java.util.ArrayList; +import java.util.List; + +/** + * @author : yingmu on 15-1-8. + * @email : yingmu@mogujie.com. + */ +public class RecentInfo { + /**sessionEntity*/ + private String sessionKey; + private int peerId; + private int sessionType; + private int latestMsgType; + private int latestMsgId; + private String latestMsgData; + private int updateTime; + + /**unreadEntity*/ + private int unReadCnt; + + /**group/userEntity*/ + private String name; + private List avatar; + + /**是否置顶*/ + private boolean isTop = false; + /**是否屏蔽信息*/ + private boolean isForbidden = false; + + + public RecentInfo(){} + public RecentInfo(SessionEntity sessionEntity,UserEntity entity,UnreadEntity unreadEntity){ + sessionKey = sessionEntity.getSessionKey(); + peerId = sessionEntity.getPeerId(); + sessionType = DBConstant.SESSION_TYPE_SINGLE; + latestMsgType = sessionEntity.getLatestMsgType(); + latestMsgId = sessionEntity.getLatestMsgId(); + latestMsgData = sessionEntity.getLatestMsgData(); + updateTime = sessionEntity.getUpdated(); + + if(unreadEntity !=null) + unReadCnt = unreadEntity.getUnReadCnt(); + + if(entity != null){ + name = entity.getMainName(); + ArrayList avatarList = new ArrayList<>(); + avatarList.add(entity.getAvatar()); + avatar = avatarList; + } + } + + + public RecentInfo(SessionEntity sessionEntity,GroupEntity groupEntity,UnreadEntity unreadEntity){ + sessionKey = sessionEntity.getSessionKey(); + peerId = sessionEntity.getPeerId(); + sessionType = DBConstant.SESSION_TYPE_GROUP; + latestMsgType = sessionEntity.getLatestMsgType(); + latestMsgId = sessionEntity.getLatestMsgId(); + latestMsgData = sessionEntity.getLatestMsgData(); + updateTime = sessionEntity.getUpdated(); + + if(unreadEntity !=null) + unReadCnt = unreadEntity.getUnReadCnt(); + + if(groupEntity !=null) { + ArrayList avatarList = new ArrayList<>(); + name = groupEntity.getMainName(); + + // 免打扰的设定 + int status = groupEntity.getStatus(); + if (status == DBConstant.GROUP_STATUS_SHIELD){ + isForbidden = true; + } + + ArrayList list = new ArrayList<>(); + list.addAll(groupEntity.getlistGroupMemberIds()); + + for(Integer userId:list){ + UserEntity entity = IMContactManager.instance().findContact(userId); + if(entity!=null){ + avatarList.add(entity.getAvatar()); + } + if(avatarList.size()>=4){ + break; + } + } + avatar = avatarList; + } + //avatar + } + + public String getSessionKey() { + return sessionKey; + } + + public void setSessionKey(String sessionKey) { + this.sessionKey = sessionKey; + } + + public int getPeerId() { + return peerId; + } + + public void setPeerId(int peerId) { + this.peerId = peerId; + } + + public int getSessionType() { + return sessionType; + } + + public void setSessionType(int sessionType) { + this.sessionType = sessionType; + } + + public int getLatestMsgType() { + return latestMsgType; + } + + public void setLatestMsgType(int latestMsgType) { + this.latestMsgType = latestMsgType; + } + + public int getLatestMsgId() { + return latestMsgId; + } + + public void setLatestMsgId(int latestMsgId) { + this.latestMsgId = latestMsgId; + } + + public String getLatestMsgData() { + return latestMsgData; + } + + public void setLatestMsgData(String latestMsgData) { + this.latestMsgData = latestMsgData; + } + + public int getUpdateTime() { + return updateTime; + } + + public void setUpdateTime(int updateTime) { + this.updateTime = updateTime; + } + + public int getUnReadCnt() { + return unReadCnt; + } + + public void setUnReadCnt(int unReadCnt) { + this.unReadCnt = unReadCnt; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public List getAvatar() { + return avatar; + } + + public void setAvatar(List avatar) { + this.avatar = avatar; + } + + public boolean isTop() { + return isTop; + } + public boolean isForbidden() + { + return isForbidden; + } + + public void setTop(boolean isTop) { + this.isTop = isTop; + } + + public void setForbidden(boolean isForbidden) + { + this.isForbidden = isForbidden; + } +} diff --git a/android/app/src/main/java/com/mogujie/tt/imservice/entity/SearchElement.java b/android/app/src/main/java/com/mogujie/tt/imservice/entity/SearchElement.java new file mode 100644 index 000000000..12de44d10 --- /dev/null +++ b/android/app/src/main/java/com/mogujie/tt/imservice/entity/SearchElement.java @@ -0,0 +1,17 @@ +package com.mogujie.tt.imservice.entity; + +public class SearchElement { + public int startIndex = -1; + public int endIndex = -1; + + @Override + public String toString() { + return "SearchElement [startIndex=" + startIndex + ", endIndex=" + + endIndex + "]"; + } + + public void reset() { + startIndex = -1; + endIndex = -1; + } +} \ No newline at end of file diff --git a/android/app/src/main/java/com/mogujie/tt/imservice/entity/TextMessage.java b/android/app/src/main/java/com/mogujie/tt/imservice/entity/TextMessage.java new file mode 100644 index 000000000..78a110ac9 --- /dev/null +++ b/android/app/src/main/java/com/mogujie/tt/imservice/entity/TextMessage.java @@ -0,0 +1,94 @@ +package com.mogujie.tt.imservice.entity; + +import com.mogujie.tt.DB.entity.PeerEntity; +import com.mogujie.tt.DB.entity.UserEntity; +import com.mogujie.tt.config.DBConstant; +import com.mogujie.tt.DB.entity.MessageEntity; +import com.mogujie.tt.config.MessageConstant; +import com.mogujie.tt.imservice.support.SequenceNumberMaker; + +import java.io.Serializable; +import java.io.UnsupportedEncodingException; + +/** + * @author : yingmu on 14-12-31. + * @email : yingmu@mogujie.com. + */ +public class TextMessage extends MessageEntity implements Serializable { + + public TextMessage(){ + msgId = SequenceNumberMaker.getInstance().makelocalUniqueMsgId(); + } + + private TextMessage(MessageEntity entity){ + /**父类的id*/ + id = entity.getId(); + msgId = entity.getMsgId(); + fromId = entity.getFromId(); + toId = entity.getToId(); + sessionKey = entity.getSessionKey(); + content=entity.getContent(); + msgType=entity.getMsgType(); + displayType=entity.getDisplayType(); + status = entity.getStatus(); + created = entity.getCreated(); + updated = entity.getUpdated(); + } + + public static TextMessage parseFromNet(MessageEntity entity){ + TextMessage textMessage = new TextMessage(entity); + textMessage.setStatus(MessageConstant.MSG_SUCCESS); + textMessage.setDisplayType(DBConstant.SHOW_ORIGIN_TEXT_TYPE); + return textMessage; + } + + public static TextMessage parseFromDB(MessageEntity entity){ + if(entity.getDisplayType()!=DBConstant.SHOW_ORIGIN_TEXT_TYPE){ + throw new RuntimeException("#TextMessage# parseFromDB,not SHOW_ORIGIN_TEXT_TYPE"); + } + TextMessage textMessage = new TextMessage(entity); + return textMessage; + } + + public static TextMessage buildForSend(String content,UserEntity fromUser,PeerEntity peerEntity){ + TextMessage textMessage = new TextMessage(); + int nowTime = (int) (System.currentTimeMillis() / 1000); + textMessage.setFromId(fromUser.getPeerId()); + textMessage.setToId(peerEntity.getPeerId()); + textMessage.setUpdated(nowTime); + textMessage.setCreated(nowTime); + textMessage.setDisplayType(DBConstant.SHOW_ORIGIN_TEXT_TYPE); + textMessage.setGIfEmo(true); + int peerType = peerEntity.getType(); + int msgType = peerType == DBConstant.SESSION_TYPE_GROUP ? DBConstant.MSG_TYPE_GROUP_TEXT + : DBConstant.MSG_TYPE_SINGLE_TEXT; + textMessage.setMsgType(msgType); + textMessage.setStatus(MessageConstant.MSG_SENDING); + // 内容的设定 + textMessage.setContent(content); + textMessage.buildSessionKey(true); + return textMessage; + } + + + /** + * Not-null value. + * DB的时候需要 + */ + @Override + public String getContent() { + return content; + } + + @Override + public byte[] getSendContent() { + try { + /** 加密*/ + String sendContent =new String(com.mogujie.tt.Security.getInstance().EncryptMsg(content)); + return sendContent.getBytes("utf-8"); + } catch (UnsupportedEncodingException e) { + e.printStackTrace(); + } + return null; + } +} diff --git a/android/app/src/main/java/com/mogujie/tt/imservice/entity/TimeTileMessage.java b/android/app/src/main/java/com/mogujie/tt/imservice/entity/TimeTileMessage.java new file mode 100644 index 000000000..2df19101d --- /dev/null +++ b/android/app/src/main/java/com/mogujie/tt/imservice/entity/TimeTileMessage.java @@ -0,0 +1,20 @@ +package com.mogujie.tt.imservice.entity; + +/** + * @author : yingmu on 15-1-8. + * @email : yingmu@mogujie.com. + */ +public class TimeTileMessage { + private int time; + public TimeTileMessage(int mTime){ + time= mTime; + } + + public int getTime() { + return time; + } + + public void setTime(int time) { + this.time = time; + } +} diff --git a/android/app/src/main/java/com/mogujie/tt/imservice/entity/UnreadEntity.java b/android/app/src/main/java/com/mogujie/tt/imservice/entity/UnreadEntity.java new file mode 100644 index 000000000..499bc1a64 --- /dev/null +++ b/android/app/src/main/java/com/mogujie/tt/imservice/entity/UnreadEntity.java @@ -0,0 +1,97 @@ +package com.mogujie.tt.imservice.entity; + +import com.mogujie.tt.protobuf.helper.EntityChangeEngine; + +/** + * @author : yingmu on 15-1-6. + * @email : yingmu@mogujie.com. + * + * 未读session实体,并未保存在DB中 + */ +public class UnreadEntity { + private String sessionKey; + private int peerId; + private int sessionType; + private int unReadCnt; + private int laststMsgId; + private String latestMsgData; + private boolean isForbidden = false; + + public String getSessionKey() { + return sessionKey; + } + + public void setSessionKey(String sessionKey) { + this.sessionKey = sessionKey; + } + + public int getPeerId() { + return peerId; + } + + public void setPeerId(int peerId) { + this.peerId = peerId; + } + + public int getSessionType() { + return sessionType; + } + + public void setSessionType(int sessionType) { + this.sessionType = sessionType; + } + + public int getUnReadCnt() { + return unReadCnt; + } + + public void setUnReadCnt(int unReadCnt) { + this.unReadCnt = unReadCnt; + } + + public int getLaststMsgId() { + return laststMsgId; + } + + public void setLaststMsgId(int laststMsgId) { + this.laststMsgId = laststMsgId; + } + + public String getLatestMsgData() { + return latestMsgData; + } + + public void setLatestMsgData(String latestMsgData) { + this.latestMsgData = latestMsgData; + } + + public boolean isForbidden() { + return isForbidden; + } + + public void setForbidden(boolean isForbidden) { + this.isForbidden = isForbidden; + } + + @Override + public String toString() { + return "UnreadEntity{" + + "sessionKey='" + sessionKey + '\'' + + ", peerId=" + peerId + + ", sessionType=" + sessionType + + ", unReadCnt=" + unReadCnt + + ", laststMsgId=" + laststMsgId + + ", latestMsgData='" + latestMsgData + '\'' + + ", isForbidden=" + isForbidden + + '}'; + } + + public String buildSessionKey(){ + if(sessionType <=0 || peerId <=0){ + throw new IllegalArgumentException( + "SessionEntity buildSessionKey error,cause by some params <=0"); + } + sessionKey = EntityChangeEngine.getSessionKey(peerId,sessionType); + return sessionKey; + } +} diff --git a/android/app/src/main/java/com/mogujie/tt/imservice/event/AudioEvent.java b/android/app/src/main/java/com/mogujie/tt/imservice/event/AudioEvent.java new file mode 100644 index 000000000..c7ccaad81 --- /dev/null +++ b/android/app/src/main/java/com/mogujie/tt/imservice/event/AudioEvent.java @@ -0,0 +1,9 @@ +package com.mogujie.tt.imservice.event; + +/** + * @author : yingmu on 15-1-20. + * @email : yingmu@mogujie.com. + */ +public enum AudioEvent { + AUDIO_STOP_PLAY +} diff --git a/android/app/src/main/java/com/mogujie/tt/imservice/event/GroupEvent.java b/android/app/src/main/java/com/mogujie/tt/imservice/event/GroupEvent.java new file mode 100644 index 000000000..aa554f4d0 --- /dev/null +++ b/android/app/src/main/java/com/mogujie/tt/imservice/event/GroupEvent.java @@ -0,0 +1,80 @@ +package com.mogujie.tt.imservice.event; + + +import com.mogujie.tt.DB.entity.GroupEntity; + +import java.util.List; + +/** + * @author : yingmu on 14-12-30. + * @email : yingmu@mogujie.com. + */ +public class GroupEvent { + + private GroupEntity groupEntity; + private Event event; + + /**很多的场景只是关心改变的类型以及change的Ids*/ + private int changeType; + private List changeList; + + public GroupEvent(Event event){ + this.event = event; + } + + public GroupEvent(Event event,GroupEntity groupEntity){ + this.groupEntity = groupEntity; + this.event = event; + } + + public enum Event{ + NONE, + + GROUP_INFO_OK, + GROUP_INFO_UPDATED, + + CHANGE_GROUP_MEMBER_SUCCESS, + CHANGE_GROUP_MEMBER_FAIL, + CHANGE_GROUP_MEMBER_TIMEOUT, + + CREATE_GROUP_OK, + CREATE_GROUP_FAIL, + CREATE_GROUP_TIMEOUT, + + SHIELD_GROUP_OK, + SHIELD_GROUP_TIMEOUT, + SHIELD_GROUP_FAIL + + + } + + public int getChangeType() { + return changeType; + } + + public void setChangeType(int changeType) { + this.changeType = changeType; + } + + public List getChangeList() { + return changeList; + } + + public void setChangeList(List changeList) { + this.changeList = changeList; + } + + public GroupEntity getGroupEntity() { + return groupEntity; + } + public void setGroupEntity(GroupEntity groupEntity) { + this.groupEntity = groupEntity; + } + + public Event getEvent() { + return event; + } + public void setEvent(Event event) { + this.event = event; + } +} diff --git a/android/app/src/main/java/com/mogujie/tt/imservice/event/ImageMsgEvent.java b/android/app/src/main/java/com/mogujie/tt/imservice/event/ImageMsgEvent.java new file mode 100644 index 000000000..b192438d1 --- /dev/null +++ b/android/app/src/main/java/com/mogujie/tt/imservice/event/ImageMsgEvent.java @@ -0,0 +1,10 @@ +package com.mogujie.tt.imservice.event; + +/** + * @author : yingmu on 15-1-7. + * @email : yingmu@mogujie.com. + */ +public enum ImageMsgEvent { + HANDLER_IMAGE_UPLOAD_FAILD, + HANDLER_IMAGE_UPLOAD_SUCESS; +} diff --git a/android/app/src/main/java/com/mogujie/tt/imservice/event/LoginEvent.java b/android/app/src/main/java/com/mogujie/tt/imservice/event/LoginEvent.java new file mode 100644 index 000000000..62d3e53df --- /dev/null +++ b/android/app/src/main/java/com/mogujie/tt/imservice/event/LoginEvent.java @@ -0,0 +1,27 @@ +package com.mogujie.tt.imservice.event; + +/** + * @author : yingmu on 14-12-30. + * @email : yingmu@mogujie.com. + */ +public enum LoginEvent { + NONE, + LOGINING, + // 网络登陆验证成功 + LOGIN_OK, + LOGIN_INNER_FAILED, + LOGIN_AUTH_FAILED, + LOGIN_OUT, + + // 对于离线登陆 + // 如果在此时,网络登陆返回账号密码错误应该怎么处理? todo 强制退出 + // 登陆成功之后触发 LOCAL_LOGIN_MSG_SERVICE + LOCAL_LOGIN_SUCCESS, + LOCAL_LOGIN_MSG_SERVICE, + + + PC_ONLINE, + PC_OFFLINE, + KICK_PC_SUCCESS, + KICK_PC_FAILED +} diff --git a/android/app/src/main/java/com/mogujie/tt/imservice/event/MessageEvent.java b/android/app/src/main/java/com/mogujie/tt/imservice/event/MessageEvent.java new file mode 100644 index 000000000..f6a1dc1b6 --- /dev/null +++ b/android/app/src/main/java/com/mogujie/tt/imservice/event/MessageEvent.java @@ -0,0 +1,78 @@ +package com.mogujie.tt.imservice.event; + +import com.mogujie.tt.DB.entity.MessageEntity; + +import java.util.ArrayList; + +/** + * @author : yingmu on 14-12-30. + * @email : yingmu@mogujie.com. + * + */ +public class MessageEvent { + + private ArrayList msgList; + private Event event; + + public MessageEvent(){ + } + + public MessageEvent(Event event){ + //默认值 初始化使用 + this.event = event; + } + + public MessageEvent(Event event,MessageEntity entity){ + //默认值 初始化使用 + this.event = event; + msgList = new ArrayList<>(1); + msgList.add(entity); + } + + public enum Event{ + NONE, + HISTORY_MSG_OBTAIN, + + SENDING_MESSAGE, + + ACK_SEND_MESSAGE_OK, + ACK_SEND_MESSAGE_TIME_OUT, + ACK_SEND_MESSAGE_FAILURE, + + HANDLER_IMAGE_UPLOAD_FAILD, + IMAGE_UPLOAD_FAILD, + HANDLER_IMAGE_UPLOAD_SUCCESS, + IMAGE_UPLOAD_SUCCESS + } + + public MessageEntity getMessageEntity() { + if(msgList == null || msgList.size() <=0){ + return null; + } + return msgList.get(0); + } + + public void setMessageEntity(MessageEntity messageEntity) { + if(msgList == null){ + msgList = new ArrayList<>(); + } + msgList.clear(); + msgList.add(messageEntity); + } + + public ArrayList getMsgList() { + return msgList; + } + + public void setMsgList(ArrayList msgList) { + this.msgList = msgList; + } + + public Event getEvent() { + return event; + } + + public void setEvent(Event event) { + this.event = event; + } +} diff --git a/android/app/src/main/java/com/mogujie/tt/imservice/event/PriorityEvent.java b/android/app/src/main/java/com/mogujie/tt/imservice/event/PriorityEvent.java new file mode 100644 index 000000000..a8145461a --- /dev/null +++ b/android/app/src/main/java/com/mogujie/tt/imservice/event/PriorityEvent.java @@ -0,0 +1,21 @@ +package com.mogujie.tt.imservice.event; + +/** + * @author : yingmu on 15-1-19. + * @email : yingmu@mogujie.com. + * + * 临时解决 + * 背景: 1.EventBus的cancelEventDelivery的只能在postThread中运行,而且没有办法绕过这一点 + * 2. onEvent(A a) onEventMainThread(A a) 这个两个是没有办法共存的 + * 解决: 抽离出那些需要优先级的event,在onEvent通过handler调用主线程, + * 然后cancelEventDelivery + */ +public class PriorityEvent { + + public Object object; + public Event event; + + public enum Event{ + MSG_RECEIVED_MESSAGE + } +} diff --git a/android/app/src/main/java/com/mogujie/tt/imservice/event/ReconnectEvent.java b/android/app/src/main/java/com/mogujie/tt/imservice/event/ReconnectEvent.java new file mode 100644 index 000000000..87653de27 --- /dev/null +++ b/android/app/src/main/java/com/mogujie/tt/imservice/event/ReconnectEvent.java @@ -0,0 +1,16 @@ +package com.mogujie.tt.imservice.event; + +/** + * @author : yingmu on 15-1-5. + * @email : yingmu@mogujie.com. + * + * 用户是否的登陆: 依赖loginManager的状态 + * 没有: 底层socket重连 + * 有: 底层socket重连,relogin + */ +public enum ReconnectEvent { + NONE, + + SUCCESS, + DISABLE +} diff --git a/android/app/src/main/java/com/mogujie/tt/imservice/event/RefreshHistoryMsgEvent.java b/android/app/src/main/java/com/mogujie/tt/imservice/event/RefreshHistoryMsgEvent.java new file mode 100644 index 000000000..d611b240b --- /dev/null +++ b/android/app/src/main/java/com/mogujie/tt/imservice/event/RefreshHistoryMsgEvent.java @@ -0,0 +1,24 @@ +package com.mogujie.tt.imservice.event; + +import com.mogujie.tt.DB.entity.MessageEntity; + +import java.util.List; + +/** + * @author : yingmu on 15-3-26. + * @email : yingmu@mogujie.com. + * + * 异步刷新历史消息 + */ +public class RefreshHistoryMsgEvent { + public int pullTimes; + public int lastMsgId; + public int count; + public List listMsg; + public int peerId; + public int peerType; + public String sessionKey; + + public RefreshHistoryMsgEvent(){} + +} diff --git a/android/app/src/main/java/com/mogujie/tt/imservice/event/SelectEvent.java b/android/app/src/main/java/com/mogujie/tt/imservice/event/SelectEvent.java new file mode 100644 index 000000000..25226fbe5 --- /dev/null +++ b/android/app/src/main/java/com/mogujie/tt/imservice/event/SelectEvent.java @@ -0,0 +1,24 @@ +package com.mogujie.tt.imservice.event; + +import com.mogujie.tt.ui.adapter.album.ImageItem; + +import java.util.List; + +/** + * @author : yingmu on 15-1-16. + * @email : yingmu@mogujie.com. + */ +public class SelectEvent { + private List list; + public SelectEvent(List list){ + this.list = list; + } + + public List getList() { + return list; + } + + public void setList(List list) { + this.list = list; + } +} diff --git a/android/app/src/main/java/com/mogujie/tt/imservice/event/SessionEvent.java b/android/app/src/main/java/com/mogujie/tt/imservice/event/SessionEvent.java new file mode 100644 index 000000000..9034fa62f --- /dev/null +++ b/android/app/src/main/java/com/mogujie/tt/imservice/event/SessionEvent.java @@ -0,0 +1,17 @@ +package com.mogujie.tt.imservice.event; + +/** + * @author : yingmu on 14-12-30. + * @email : yingmu@mogujie.com. + */ +public enum SessionEvent { + + RECENT_SESSION_LIST_SUCCESS, + RECENT_SESSION_LIST_FAILURE, + + //回话人列表更新 + RECENT_SESSION_LIST_UPDATE, + + SET_SESSION_TOP + +} diff --git a/android/app/src/main/java/com/mogujie/tt/imservice/event/SocketEvent.java b/android/app/src/main/java/com/mogujie/tt/imservice/event/SocketEvent.java new file mode 100644 index 000000000..bc66688dd --- /dev/null +++ b/android/app/src/main/java/com/mogujie/tt/imservice/event/SocketEvent.java @@ -0,0 +1,20 @@ +package com.mogujie.tt.imservice.event; + +/** + * @author : yingmu on 14-12-30. + * @email : yingmu@mogujie.com. + * + */ +public enum SocketEvent { + /**登陆之前的动作*/ + NONE, + REQING_MSG_SERVER_ADDRS, + REQ_MSG_SERVER_ADDRS_FAILED, + REQ_MSG_SERVER_ADDRS_SUCCESS, + + /**请求登陆的过程*/ + CONNECTING_MSG_SERVER, + CONNECT_MSG_SERVER_SUCCESS, + CONNECT_MSG_SERVER_FAILED, + MSG_SERVER_DISCONNECTED //channel disconnect 会触发,再应用开启内,要重连【可能是服务端、客户端断掉】 +} diff --git a/android/app/src/main/java/com/mogujie/tt/imservice/event/UnreadEvent.java b/android/app/src/main/java/com/mogujie/tt/imservice/event/UnreadEvent.java new file mode 100644 index 000000000..05fb22752 --- /dev/null +++ b/android/app/src/main/java/com/mogujie/tt/imservice/event/UnreadEvent.java @@ -0,0 +1,25 @@ +package com.mogujie.tt.imservice.event; + +import com.mogujie.tt.imservice.entity.UnreadEntity; + +/** + * @author : yingmu on 15-1-6. + * @email : yingmu@mogujie.com. + */ +public class UnreadEvent { + + public UnreadEntity entity; + public Event event; + + public UnreadEvent(){} + public UnreadEvent(Event e){ + this.event = e; + } + + public enum Event { + UNREAD_MSG_LIST_OK, + UNREAD_MSG_RECEIVED, + + SESSION_READED_UNREAD_MSG + } +} diff --git a/android/app/src/main/java/com/mogujie/tt/imservice/event/UserInfoEvent.java b/android/app/src/main/java/com/mogujie/tt/imservice/event/UserInfoEvent.java new file mode 100644 index 000000000..7f054cdbc --- /dev/null +++ b/android/app/src/main/java/com/mogujie/tt/imservice/event/UserInfoEvent.java @@ -0,0 +1,15 @@ +package com.mogujie.tt.imservice.event; + +/** + * @author : yingmu on 14-12-31. + * @email : yingmu@mogujie.com. + * + * 用户信息事件 + * 1. 群组的信息 + * 2. 用户的信息 + */ +public enum UserInfoEvent { + USER_INFO_OK, + USER_INFO_UPDATE, + +} diff --git a/android/app/src/main/java/com/mogujie/tt/imservice/manager/IMContactManager.java b/android/app/src/main/java/com/mogujie/tt/imservice/manager/IMContactManager.java new file mode 100644 index 000000000..a6ad3fa9b --- /dev/null +++ b/android/app/src/main/java/com/mogujie/tt/imservice/manager/IMContactManager.java @@ -0,0 +1,417 @@ +package com.mogujie.tt.imservice.manager; + +import com.mogujie.tt.DB.DBInterface; +import com.mogujie.tt.DB.entity.DepartmentEntity; +import com.mogujie.tt.DB.entity.UserEntity; +import com.mogujie.tt.imservice.event.UserInfoEvent; +import com.mogujie.tt.protobuf.helper.ProtoBuf2JavaBean; +import com.mogujie.tt.protobuf.IMBaseDefine; +import com.mogujie.tt.protobuf.IMBuddy; +import com.mogujie.tt.utils.IMUIHelper; +import com.mogujie.tt.utils.Logger; +import com.mogujie.tt.utils.pinyin.PinYin; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.Comparator; +import java.util.List; +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; + +import de.greenrobot.event.EventBus; + +/** + * 负责用户信息的请求 + * 为回话页面以及联系人页面提供服务 + * + * 联系人信息管理 + * 普通用户的version 有总版本 + * 群组没有总version的概念, 每个群有version + * 具体请参见 服务端具体的pd协议 + */ +public class IMContactManager extends IMManager { + private Logger logger = Logger.getLogger(IMContactManager.class); + + // 单例 + private static IMContactManager inst = new IMContactManager(); + public static IMContactManager instance() { + return inst; + } + private IMSocketManager imSocketManager = IMSocketManager.instance(); + private DBInterface dbInterface = DBInterface.instance(); + + // 自身状态字段 + private boolean userDataReady = false; + private Map userMap = new ConcurrentHashMap<>(); + private Map departmentMap = new ConcurrentHashMap<>(); + + + @Override + public void doOnStart() { + } + + /** + * 登陆成功触发 + * auto自动登陆 + * */ + public void onNormalLoginOk(){ + onLocalLoginOk(); + onLocalNetOk(); + } + + /** + * 加载本地DB的状态 + * 不管是离线还是在线登陆,loadFromDb 要运行的 + */ + public void onLocalLoginOk(){ + logger.d("contact#loadAllUserInfo"); + + List deptlist = dbInterface.loadAllDept(); + logger.d("contact#loadAllDept dbsuccess"); + + List userlist = dbInterface.loadAllUsers(); + logger.d("contact#loadAllUserInfo dbsuccess"); + + for(UserEntity userInfo:userlist){ + // todo DB的状态不包含拼音的,这个样每次都要加载啊 + PinYin.getPinYin(userInfo.getMainName(), userInfo.getPinyinElement()); + userMap.put(userInfo.getPeerId(),userInfo); + } + + for(DepartmentEntity deptInfo:deptlist){ + PinYin.getPinYin(deptInfo.getDepartName(), deptInfo.getPinyinElement()); + departmentMap.put(deptInfo.getDepartId(),deptInfo); + } + triggerEvent(UserInfoEvent.USER_INFO_OK); + } + + /** + * 网络链接成功,登陆之后请求 + */ + public void onLocalNetOk(){ + // 部门信息 + int deptUpdateTime = dbInterface.getDeptLastTime(); + reqGetDepartment(deptUpdateTime); + + // 用户信息 + int updateTime = dbInterface.getUserInfoLastTime(); + logger.d("contact#loadAllUserInfo req-updateTime:%d",updateTime); + reqGetAllUsers(updateTime); + } + + + @Override + public void reset() { + userDataReady = false; + userMap.clear(); + } + + + /** + * @param event + */ + public void triggerEvent(UserInfoEvent event) { + //先更新自身的状态 + switch (event){ + case USER_INFO_OK: + userDataReady = true; + break; + } + EventBus.getDefault().postSticky(event); + } + + /**-----------------------事件驱动---end---------*/ + + private void reqGetAllUsers(int lastUpdateTime) { + logger.i("contact#reqGetAllUsers"); + int userId = IMLoginManager.instance().getLoginId(); + + IMBuddy.IMAllUserReq imAllUserReq = IMBuddy.IMAllUserReq.newBuilder() + .setUserId(userId) + .setLatestUpdateTime(lastUpdateTime).build(); + int sid = IMBaseDefine.ServiceID.SID_BUDDY_LIST_VALUE; + int cid = IMBaseDefine.BuddyListCmdID.CID_BUDDY_LIST_ALL_USER_REQUEST_VALUE; + imSocketManager.sendRequest(imAllUserReq,sid,cid); + } + + /** + * yingmu change id from string to int + * @param imAllUserRsp + * + * 1.请求所有用户的信息,总的版本号version + * 2.匹配总的版本号,返回可能存在变更的 + * 3.选取存在变更的,请求用户详细信息 + * 4.更新DB,保存globalVersion 以及用户的信息 + */ + public void onRepAllUsers(IMBuddy.IMAllUserRsp imAllUserRsp) { + logger.i("contact#onRepAllUsers"); + int userId = imAllUserRsp.getUserId(); + int lastTime = imAllUserRsp.getLatestUpdateTime(); + // lastTime 需要保存嘛? 不保存了 + + int count = imAllUserRsp.getUserListCount(); + logger.i("contact#user cnt:%d", count); + if(count <=0){ + return; + } + + int loginId = IMLoginManager.instance().getLoginId(); + if(userId != loginId){ + logger.e("[fatal error] userId not equels loginId ,cause by onRepAllUsers"); + return ; + } + + List changeList = imAllUserRsp.getUserListList(); + ArrayList needDb = new ArrayList<>(); + for(IMBaseDefine.UserInfo userInfo:changeList){ + UserEntity entity = ProtoBuf2JavaBean.getUserEntity(userInfo); + userMap.put(entity.getPeerId(),entity); + needDb.add(entity); + } + + dbInterface.batchInsertOrUpdateUser(needDb); + triggerEvent(UserInfoEvent.USER_INFO_UPDATE); + } + + public UserEntity findContact(int buddyId){ + if(buddyId > 0 && userMap.containsKey(buddyId)){ + return userMap.get(buddyId); + } + return null; + } + + /** + * 请求用户详细信息 + * @param userIds + */ + public void reqGetDetaillUsers(ArrayList userIds){ + logger.i("contact#contact#reqGetDetaillUsers"); + if(null == userIds || userIds.size() <=0){ + logger.i("contact#contact#reqGetDetaillUsers return,cause by null or empty"); + return; + } + int loginId = IMLoginManager.instance().getLoginId(); + IMBuddy.IMUsersInfoReq imUsersInfoReq = IMBuddy.IMUsersInfoReq.newBuilder() + .setUserId(loginId) + .addAllUserIdList(userIds) + .build(); + + int sid = IMBaseDefine.ServiceID.SID_BUDDY_LIST_VALUE; + int cid = IMBaseDefine.BuddyListCmdID.CID_BUDDY_LIST_USER_INFO_REQUEST_VALUE; + imSocketManager.sendRequest(imUsersInfoReq,sid,cid); + } + + /** + * 获取用户详细的信息 + * @param imUsersInfoRsp + */ + public void onRepDetailUsers(IMBuddy.IMUsersInfoRsp imUsersInfoRsp){ + int loginId = imUsersInfoRsp.getUserId(); + boolean needEvent = false; + List userInfoList = imUsersInfoRsp.getUserInfoListList(); + + ArrayList dbNeed = new ArrayList<>(); + for(IMBaseDefine.UserInfo userInfo:userInfoList) { + UserEntity userEntity = ProtoBuf2JavaBean.getUserEntity(userInfo); + int userId = userEntity.getPeerId(); + if (userMap.containsKey(userId) && userMap.get(userId).equals(userEntity)) { + //没有必要通知更新 + } else { + needEvent = true; + userMap.put(userEntity.getPeerId(), userEntity); + dbNeed.add(userEntity); + if (userInfo.getUserId() == loginId) { + IMLoginManager.instance().setLoginInfo(userEntity); + } + } + } + // 负责userMap + dbInterface.batchInsertOrUpdateUser(dbNeed); + + // 判断有没有必要进行推送 + if(needEvent){ + triggerEvent(UserInfoEvent.USER_INFO_UPDATE); + } + } + + + public DepartmentEntity findDepartment(int deptId){ + DepartmentEntity entity = departmentMap.get(deptId); + return entity; + } + + + public List getDepartmentSortedList(){ + // todo eric efficiency + List departmentList = new ArrayList<>(departmentMap.values()); + Collections.sort(departmentList, new Comparator(){ + @Override + public int compare(DepartmentEntity entity1, DepartmentEntity entity2) { + + if(entity1.getPinyinElement().pinyin==null) + { + PinYin.getPinYin(entity1.getDepartName(),entity1.getPinyinElement()); + } + if(entity2.getPinyinElement().pinyin==null) + { + PinYin.getPinYin(entity2.getDepartName(),entity2.getPinyinElement()); + } + return entity1.getPinyinElement().pinyin.compareToIgnoreCase(entity2.getPinyinElement().pinyin); + + } + }); + return departmentList; + } + + + public List getContactSortedList() { + // todo eric efficiency + List contactList = new ArrayList<>(userMap.values()); + Collections.sort(contactList, new Comparator(){ + @Override + public int compare(UserEntity entity1, UserEntity entity2) { + if (entity2.getPinyinElement().pinyin.startsWith("#")) { + return -1; + } else if (entity1.getPinyinElement().pinyin.startsWith("#")) { + // todo eric guess: latter is > 0 + return 1; + } else { + if(entity1.getPinyinElement().pinyin==null) + { + PinYin.getPinYin(entity1.getMainName(),entity1.getPinyinElement()); + } + if(entity2.getPinyinElement().pinyin==null) + { + PinYin.getPinYin(entity2.getMainName(),entity2.getPinyinElement()); + } + return entity1.getPinyinElement().pinyin.compareToIgnoreCase(entity2.getPinyinElement().pinyin); + } + } + }); + return contactList; + } + + + // 通讯录中的部门显示 需要根据优先级 + public List getDepartmentTabSortedList() { + // todo eric efficiency + List contactList = new ArrayList<>(userMap.values()); + Collections.sort(contactList, new Comparator() { + @Override + public int compare(UserEntity entity1, UserEntity entity2) { + DepartmentEntity dept1 = departmentMap.get(entity1.getDepartmentId()); + DepartmentEntity dept2 = departmentMap.get(entity2.getDepartmentId()); + + if (entity1.getDepartmentId() == entity2.getDepartmentId()) { + // start compare + if (entity2.getPinyinElement().pinyin.startsWith("#")) { + return -1; + } else if (entity1.getPinyinElement().pinyin.startsWith("#")) { + // todo eric guess: latter is > 0 + return 1; + } else { + if(entity1.getPinyinElement().pinyin==null) + { + PinYin.getPinYin(entity1.getMainName(), entity1.getPinyinElement()); + } + if(entity2.getPinyinElement().pinyin==null) + { + PinYin.getPinYin(entity2.getMainName(),entity2.getPinyinElement()); + } + return entity1.getPinyinElement().pinyin.compareToIgnoreCase(entity2.getPinyinElement().pinyin); + } + // end compare + } else { + return dept1.getDepartName().compareToIgnoreCase(dept2.getDepartName()); + } + } + }); + return contactList; + } + + + // 确实要将对比的抽离出来 Collections + public List getSearchContactList(String key){ + List searchList = new ArrayList<>(); + for(Map.Entry entry:userMap.entrySet()){ + UserEntity user = entry.getValue(); + if (IMUIHelper.handleContactSearch(key, user)) { + searchList.add(user); + } + } + return searchList; + } + + public List getSearchDepartList(String key) { + List searchList = new ArrayList<>(); + for(Map.Entry entry:departmentMap.entrySet()){ + DepartmentEntity dept = entry.getValue(); + if (IMUIHelper.handleDepartmentSearch(key, dept)) { + searchList.add(dept); + } + } + return searchList; + } + + /**------------------------部门相关的协议 start------------------------------*/ + + // 更新的方式与userInfo一直,根据时间点 + public void reqGetDepartment(int lastUpdateTime){ + logger.i("contact#reqGetDepartment"); + int userId = IMLoginManager.instance().getLoginId(); + + IMBuddy.IMDepartmentReq imDepartmentReq = IMBuddy.IMDepartmentReq.newBuilder() + .setUserId(userId) + .setLatestUpdateTime(lastUpdateTime).build(); + int sid = IMBaseDefine.ServiceID.SID_BUDDY_LIST_VALUE; + int cid = IMBaseDefine.BuddyListCmdID.CID_BUDDY_LIST_DEPARTMENT_REQUEST_VALUE; + imSocketManager.sendRequest(imDepartmentReq,sid,cid); + } + + public void onRepDepartment(IMBuddy.IMDepartmentRsp imDepartmentRsp){ + logger.i("contact#onRepDepartment"); + int userId = imDepartmentRsp.getUserId(); + int lastTime = imDepartmentRsp.getLatestUpdateTime(); + + int count = imDepartmentRsp.getDeptListCount(); + logger.i("contact#department cnt:%d", count); + // 如果用户找不到depart 那么部门显示未知 + if(count <=0){ + return; + } + + int loginId = IMLoginManager.instance().getLoginId(); + if(userId != loginId){ + logger.e("[fatal error] userId not equels loginId ,cause by onRepDepartment"); + return ; + } + List changeList = imDepartmentRsp.getDeptListList(); + ArrayList needDb = new ArrayList<>(); + + for(IMBaseDefine.DepartInfo departInfo:changeList){ + DepartmentEntity entity = ProtoBuf2JavaBean.getDepartEntity(departInfo); + departmentMap.put(entity.getDepartId(),entity); + needDb.add(entity); + } + // 部门信息更新 + dbInterface.batchInsertOrUpdateDepart(needDb); + triggerEvent(UserInfoEvent.USER_INFO_UPDATE); + } + + /**------------------------部门相关的协议 end------------------------------*/ + + /**-----------------------实体 get set 定义-----------------------------------*/ + + public Map getUserMap() { + return userMap; + } + + public Map getDepartmentMap() { + return departmentMap; + } + + public boolean isUserDataReady() { + return userDataReady; + } + +} diff --git a/android/app/src/main/java/com/mogujie/tt/imservice/manager/IMGroupManager.java b/android/app/src/main/java/com/mogujie/tt/imservice/manager/IMGroupManager.java new file mode 100644 index 000000000..d85fa7384 --- /dev/null +++ b/android/app/src/main/java/com/mogujie/tt/imservice/manager/IMGroupManager.java @@ -0,0 +1,569 @@ +package com.mogujie.tt.imservice.manager; + + +import com.google.protobuf.CodedInputStream; +import com.mogujie.tt.config.DBConstant; +import com.mogujie.tt.DB.DBInterface; +import com.mogujie.tt.DB.entity.GroupEntity; +import com.mogujie.tt.DB.entity.SessionEntity; +import com.mogujie.tt.DB.entity.UserEntity; +import com.mogujie.tt.imservice.callback.Packetlistener; +import com.mogujie.tt.imservice.event.GroupEvent; +import com.mogujie.tt.imservice.event.SessionEvent; +import com.mogujie.tt.protobuf.helper.EntityChangeEngine; +import com.mogujie.tt.protobuf.helper.ProtoBuf2JavaBean; +import com.mogujie.tt.protobuf.IMBaseDefine; +import com.mogujie.tt.protobuf.IMGroup; +import com.mogujie.tt.utils.IMUIHelper; +import com.mogujie.tt.utils.Logger; +import com.mogujie.tt.utils.pinyin.PinYin; + +import java.io.IOException; +import java.util.ArrayList; +import java.util.Collections; +import java.util.Comparator; +import java.util.List; +import java.util.Map; +import java.util.Map.Entry; +import java.util.Set; +import java.util.concurrent.ConcurrentHashMap; + +import de.greenrobot.event.EventBus; + + +public class IMGroupManager extends IMManager { + private Logger logger = Logger.getLogger(IMGroupManager.class); + private static IMGroupManager inst = new IMGroupManager(); + public static IMGroupManager instance() { + return inst; + } + + // 依赖的服务管理 + private IMSocketManager imSocketManager = IMSocketManager.instance(); + private IMLoginManager imLoginManager=IMLoginManager.instance(); + private DBInterface dbInterface = DBInterface.instance(); + + + // todo Pinyin的处理 + //正式群,临时群都会有的,存在竞争 如果不同时请求的话 + private Map groupMap = new ConcurrentHashMap<>(); + // 群组状态 + private boolean isGroupReady = false; + + @Override + public void doOnStart() { + groupMap.clear(); + } + + public void onNormalLoginOk(){ + onLocalLoginOk(); + onLocalNetOk(); + } + + /** + * 1. 加载本地信息 + * 2. 请求正规群信息 , 与本地进行对比 + * 3. version groupId 请求 + * */ + public void onLocalLoginOk(){ + logger.i("group#loadFromDb"); + + if(!EventBus.getDefault().isRegistered(inst)){ + EventBus.getDefault().registerSticky(inst); + } + + // 加载本地group + List localGroupInfoList = dbInterface.loadAllGroup(); + for(GroupEntity groupInfo:localGroupInfoList){ + groupMap.put(groupInfo.getPeerId(),groupInfo); + } + + triggerEvent(new GroupEvent(GroupEvent.Event.GROUP_INFO_OK)); + } + + public void onLocalNetOk(){ + reqGetNormalGroupList(); + } + + @Override + public void reset() { + isGroupReady =false; + groupMap.clear(); + EventBus.getDefault().unregister(inst); + } + + public void onEvent(SessionEvent event){ + switch (event){ + case RECENT_SESSION_LIST_UPDATE: + // groupMap 本地已经加载完毕之后才触发 + loadSessionGroupInfo(); + break; + } + } + + /** + * 实现自身的事件驱动 + * @param event + */ + public synchronized void triggerEvent(GroupEvent event) { + switch (event.getEvent()){ + case GROUP_INFO_OK: + isGroupReady = true; + break; + case GROUP_INFO_UPDATED: + isGroupReady = true; + break; + } + EventBus.getDefault().postSticky(event); + } + + /**---------------事件驱动end------------------------------*/ + + /** + * 1. 加载本地信息 + * 2. 从session中获取 群组信息,从本地中获取这些群组的version信息 + * 3. 合并上述的merge结果, version groupId 请求 + * */ + private void loadSessionGroupInfo(){ + logger.i("group#loadSessionGroupInfo"); + + List sessionInfoList = IMSessionManager.instance().getRecentSessionList(); + + List needReqList = new ArrayList<>(); + for(SessionEntity sessionInfo:sessionInfoList){ + int version = 0; + if(sessionInfo.getPeerType() == DBConstant.SESSION_TYPE_GROUP /**群组*/){ + if(groupMap.containsKey(sessionInfo.getPeerId())){ + version = groupMap.get(sessionInfo.getPeerId()).getVersion(); + } + + IMBaseDefine.GroupVersionInfo versionInfo = IMBaseDefine.GroupVersionInfo.newBuilder() + .setVersion(version) + .setGroupId(sessionInfo.getPeerId()) + .build(); + needReqList.add(versionInfo); + } + } + // 事件触发的时候需要注意 + if(needReqList.size() >0){ + reqGetGroupDetailInfo(needReqList); + return ; + } + } + + /** + * 联系人页面正式群的请求 + * todo 正式群与临时群逻辑上的分开的,但是底层应该是想通的 + */ + private void reqGetNormalGroupList() { + logger.i("group#reqGetNormalGroupList"); + int loginId = imLoginManager.getLoginId(); + IMGroup.IMNormalGroupListReq normalGroupListReq = IMGroup.IMNormalGroupListReq.newBuilder() + .setUserId(loginId) + .build(); + int sid = IMBaseDefine.ServiceID.SID_GROUP_VALUE; + int cid = IMBaseDefine.GroupCmdID.CID_GROUP_NORMAL_LIST_REQUEST_VALUE; + imSocketManager.sendRequest(normalGroupListReq,sid,cid); + logger.i("group#send packet to server"); + } + + public void onRepNormalGroupList(IMGroup.IMNormalGroupListRsp normalGroupListRsp) { + logger.i("group#onRepNormalGroupList"); + int groupSize = normalGroupListRsp.getGroupVersionListCount(); + logger.i("group#onRepNormalGroupList cnt:%d",groupSize); + List versionInfoList = normalGroupListRsp.getGroupVersionListList(); + + /**对比DB中的version字段*/ + // 这块对比的可以抽离出来 + List needInfoList = new ArrayList<>(); + + for(IMBaseDefine.GroupVersionInfo groupVersionInfo:versionInfoList ){ + int groupId = groupVersionInfo.getGroupId(); + int version = groupVersionInfo.getVersion(); + if(groupMap.containsKey(groupId) && + groupMap.get(groupId).getVersion() ==version ){ + continue; + } + IMBaseDefine.GroupVersionInfo versionInfo = IMBaseDefine.GroupVersionInfo.newBuilder() + .setVersion(0) + .setGroupId(groupId) + .build(); + needInfoList.add(versionInfo); + } + + // 事件触发的时候需要注意 todo + if(needInfoList.size() >0){ + reqGetGroupDetailInfo(needInfoList); + } + } + + public void reqGroupDetailInfo(int groupId){ + IMBaseDefine.GroupVersionInfo groupVersionInfo = IMBaseDefine.GroupVersionInfo.newBuilder() + .setGroupId(groupId) + .setVersion(0) + .build(); + ArrayList list = new ArrayList<>(); + list.add(groupVersionInfo); + reqGetGroupDetailInfo(list); + } + + /** + * 请求群组的详细信息 + */ + public void reqGetGroupDetailInfo(List versionInfoList){ + logger.i("group#reqGetGroupDetailInfo"); + if(versionInfoList == null || versionInfoList.size()<=0){ + logger.e("group#reqGetGroupDetailInfo# please check your params,cause by empty/null"); + return ; + } + int loginId = imLoginManager.getLoginId(); + IMGroup.IMGroupInfoListReq groupInfoListReq = IMGroup.IMGroupInfoListReq.newBuilder() + .setUserId(loginId) + .addAllGroupVersionList(versionInfoList) + .build(); + + int sid = IMBaseDefine.ServiceID.SID_GROUP_VALUE; + int cid = IMBaseDefine.GroupCmdID.CID_GROUP_INFO_REQUEST_VALUE; + imSocketManager.sendRequest(groupInfoListReq,sid,cid); + } + + + public void onRepGroupDetailInfo(IMGroup.IMGroupInfoListRsp groupInfoListRsp){ + logger.i("group#onRepGroupDetailInfo"); + int groupSize = groupInfoListRsp.getGroupInfoListCount(); + int userId = groupInfoListRsp.getUserId(); + int loginId = imLoginManager.getLoginId(); + logger.i("group#onRepGroupDetailInfo cnt:%d",groupSize); + if(groupSize <=0 || userId!=loginId){ + logger.i("group#onRepGroupDetailInfo size empty or userid[%d]≠ loginId[%d]",userId,loginId); + return; + } + ArrayList needDb = new ArrayList<>(); + for(IMBaseDefine.GroupInfo groupInfo:groupInfoListRsp.getGroupInfoListList()){ + // 群组的详细信息 + // 保存在DB中 + // GroupManager 中的变量 + GroupEntity groupEntity = ProtoBuf2JavaBean.getGroupEntity(groupInfo); + groupMap.put(groupEntity.getPeerId(),groupEntity); + needDb.add(groupEntity); + } + + dbInterface.batchInsertOrUpdateGroup(needDb); + triggerEvent(new GroupEvent(GroupEvent.Event.GROUP_INFO_UPDATED)); + } + + + /** + * 创建群 + * 默认是创建临时群,且客户端只能创建临时群 + */ + public void reqCreateTempGroup(String groupName, Set memberList){ + + logger.i("group#reqCreateTempGroup, tempGroupName = %s", groupName); + + int loginId = imLoginManager.getLoginId(); + + IMGroup.IMGroupCreateReq groupCreateReq = IMGroup.IMGroupCreateReq.newBuilder() + .setUserId(loginId) + .setGroupType(IMBaseDefine.GroupType.GROUP_TYPE_TMP) + .setGroupName(groupName) + .setGroupAvatar("")// todo 群头像 现在是四宫格 + .addAllMemberIdList(memberList) + .build(); + + int sid = IMBaseDefine.ServiceID.SID_GROUP_VALUE; + int cid = IMBaseDefine.GroupCmdID.CID_GROUP_CREATE_REQUEST_VALUE; + imSocketManager.sendRequest(groupCreateReq, sid, cid,new Packetlistener() { + @Override + public void onSuccess(Object response) { + try { + IMGroup.IMGroupCreateRsp groupCreateRsp = IMGroup.IMGroupCreateRsp.parseFrom((CodedInputStream)response); + IMGroupManager.instance().onReqCreateTempGroup(groupCreateRsp); + } catch (IOException e) { + logger.e("reqCreateTempGroup parse error"); + triggerEvent(new GroupEvent(GroupEvent.Event.CREATE_GROUP_FAIL)); + } + } + + @Override + public void onFaild() { + triggerEvent(new GroupEvent(GroupEvent.Event.CREATE_GROUP_FAIL)); + } + + @Override + public void onTimeout() { + triggerEvent(new GroupEvent(GroupEvent.Event.CREATE_GROUP_TIMEOUT)); + } + }); + + } + + public void onReqCreateTempGroup(IMGroup.IMGroupCreateRsp groupCreateRsp){ + logger.d("group#onReqCreateTempGroup"); + + int resultCode = groupCreateRsp.getResultCode(); + if(0 != resultCode){ + logger.e("group#createGroup failed"); + triggerEvent(new GroupEvent(GroupEvent.Event.CREATE_GROUP_FAIL)); + return; + } + GroupEntity groupEntity = ProtoBuf2JavaBean.getGroupEntity(groupCreateRsp); + // 更新DB 更新map + groupMap.put(groupEntity.getPeerId(),groupEntity); + + IMSessionManager.instance().updateSession(groupEntity); + dbInterface.insertOrUpdateGroup(groupEntity); + triggerEvent(new GroupEvent(GroupEvent.Event.CREATE_GROUP_OK, groupEntity)); // 接收到之后修改UI + } + + /** + * 删除群成员 + * REMOVE_CHANGE_MEMBER_TYPE + * 可能会触发头像的修改 + */ + public void reqRemoveGroupMember(int groupId,Set removeMemberlist){ + reqChangeGroupMember(groupId,IMBaseDefine.GroupModifyType.GROUP_MODIFY_TYPE_DEL, removeMemberlist); + } + /** + * 新增群成员 + * ADD_CHANGE_MEMBER_TYPE + * 可能会触发头像的修改 + */ + public void reqAddGroupMember(int groupId,Set addMemberlist){ + reqChangeGroupMember(groupId,IMBaseDefine.GroupModifyType.GROUP_MODIFY_TYPE_ADD, addMemberlist); + } + + private void reqChangeGroupMember(int groupId,IMBaseDefine.GroupModifyType groupModifyType, Set changeMemberlist) { + logger.i("group#reqChangeGroupMember, changeGroupMemberType = %s", groupModifyType.toString()); + + final int loginId = imLoginManager.getLoginId(); + IMGroup.IMGroupChangeMemberReq groupChangeMemberReq = IMGroup.IMGroupChangeMemberReq.newBuilder() + .setUserId(loginId) + .setChangeType(groupModifyType) + .addAllMemberIdList(changeMemberlist) + .setGroupId(groupId) + .build(); + + int sid = IMBaseDefine.ServiceID.SID_GROUP_VALUE; + int cid = IMBaseDefine.GroupCmdID.CID_GROUP_CHANGE_MEMBER_REQUEST_VALUE; + imSocketManager.sendRequest(groupChangeMemberReq, sid, cid,new Packetlistener() { + @Override + public void onSuccess(Object response) { + try { + IMGroup.IMGroupChangeMemberRsp groupChangeMemberRsp = IMGroup.IMGroupChangeMemberRsp.parseFrom((CodedInputStream)response); + IMGroupManager.instance().onReqChangeGroupMember(groupChangeMemberRsp); + } catch (IOException e) { + logger.e("reqChangeGroupMember parse error!"); + triggerEvent(new GroupEvent(GroupEvent.Event.CHANGE_GROUP_MEMBER_FAIL)); + } + } + + @Override + public void onFaild() { + triggerEvent(new GroupEvent(GroupEvent.Event.CHANGE_GROUP_MEMBER_FAIL)); + } + + @Override + public void onTimeout() { + triggerEvent(new GroupEvent(GroupEvent.Event.CHANGE_GROUP_MEMBER_TIMEOUT)); + } + }); + + } + + public void onReqChangeGroupMember(IMGroup.IMGroupChangeMemberRsp groupChangeMemberRsp){ + int resultCode = groupChangeMemberRsp.getResultCode(); + if (0 != resultCode){ + triggerEvent(new GroupEvent(GroupEvent.Event.CHANGE_GROUP_MEMBER_FAIL)); + return; + } + + int groupId = groupChangeMemberRsp.getGroupId(); + List changeUserIdList = groupChangeMemberRsp.getChgUserIdListList(); + IMBaseDefine.GroupModifyType groupModifyType = groupChangeMemberRsp.getChangeType(); + + + GroupEntity groupEntityRet = groupMap.get(groupId); + groupEntityRet.setlistGroupMemberIds(groupChangeMemberRsp.getCurUserIdListList()); + groupMap.put(groupId,groupEntityRet); + dbInterface.insertOrUpdateGroup(groupEntityRet); + + + GroupEvent groupEvent = new GroupEvent(GroupEvent.Event.CHANGE_GROUP_MEMBER_SUCCESS); + groupEvent.setChangeList(changeUserIdList); + groupEvent.setChangeType(ProtoBuf2JavaBean.getGroupChangeType(groupModifyType)); + groupEvent.setGroupEntity(groupEntityRet); + triggerEvent(groupEvent); + } + + /** + * 屏蔽群消息 + * IMGroupShieldReq + * 备注:应为屏蔽之后大部分操作依旧需要客户端做 + * */ + public void reqShieldGroup(final int groupId,final int shieldType){ + final GroupEntity entity = groupMap.get(groupId); + if(entity == null){ + logger.i("GroupEntity do not exist!"); + return; + } + final int loginId = IMLoginManager.instance().getLoginId(); + IMGroup.IMGroupShieldReq shieldReq = IMGroup.IMGroupShieldReq.newBuilder() + .setShieldStatus(shieldType) + .setGroupId(groupId) + .setUserId(loginId) + .build(); + int sid = IMBaseDefine.ServiceID.SID_GROUP_VALUE; + int cid = IMBaseDefine.GroupCmdID.CID_GROUP_SHIELD_GROUP_REQUEST_VALUE; + imSocketManager.sendRequest(shieldReq,sid,cid,new Packetlistener() { + @Override + public void onSuccess(Object response) { + try { + IMGroup.IMGroupShieldRsp groupShieldRsp = IMGroup.IMGroupShieldRsp.parseFrom((CodedInputStream)response); + int resCode = groupShieldRsp.getResultCode(); + if(resCode !=0){ + triggerEvent(new GroupEvent(GroupEvent.Event.SHIELD_GROUP_FAIL)); + return; + } + if(groupShieldRsp.getGroupId() != groupId || groupShieldRsp.getUserId()!=loginId){ + return; + } + // 更新DB状态 + entity.setStatus(shieldType); + dbInterface.insertOrUpdateGroup(entity); + // 更改未读计数状态 + boolean isFor = shieldType == DBConstant.GROUP_STATUS_SHIELD; + IMUnreadMsgManager.instance().setForbidden( + EntityChangeEngine.getSessionKey(groupId,DBConstant.SESSION_TYPE_GROUP),isFor); + triggerEvent(new GroupEvent(GroupEvent.Event.SHIELD_GROUP_OK,entity)); + + } catch (IOException e) { + logger.e("reqChangeGroupMember parse error!"); + triggerEvent(new GroupEvent(GroupEvent.Event.SHIELD_GROUP_FAIL)); + } + } + @Override + public void onFaild() { + triggerEvent(new GroupEvent(GroupEvent.Event.SHIELD_GROUP_FAIL)); + } + + @Override + public void onTimeout() { + triggerEvent(new GroupEvent(GroupEvent.Event.SHIELD_GROUP_TIMEOUT)); + } + }); + } + + + /** + * 收到群成员发生变更消息 + * 服务端主动发出 + * DB + */ + public void receiveGroupChangeMemberNotify(IMGroup.IMGroupChangeMemberNotify notify){ + int groupId = notify.getGroupId(); + int changeType = ProtoBuf2JavaBean.getGroupChangeType(notify.getChangeType()); + List changeList = notify.getChgUserIdListList(); + + List curMemberList = notify.getCurUserIdListList(); + if(groupMap.containsKey(groupId)){ + GroupEntity entity = groupMap.get(groupId); + entity.setlistGroupMemberIds(curMemberList); + dbInterface.insertOrUpdateGroup(entity); + groupMap.put(groupId,entity); + + GroupEvent groupEvent = new GroupEvent(GroupEvent.Event.CHANGE_GROUP_MEMBER_SUCCESS); + groupEvent.setChangeList(changeList); + groupEvent.setChangeType(changeType); + groupEvent.setGroupEntity(entity); + triggerEvent(groupEvent); + }else{ + //todo 没有就暂时不管了,只要聊过天都会显示在回话里面 + } + } + + public List getNormalGroupList() { + List normalGroupList = new ArrayList<>(); + for (Entry entry : groupMap.entrySet()) { + GroupEntity group = entry.getValue(); + if (group == null) { + continue; + } + if (group.getGroupType() == DBConstant.GROUP_TYPE_NORMAL) { + normalGroupList.add(group); + } + } + return normalGroupList; + } + + // 该方法只有正式群 + // todo eric efficiency + public List getNormalGroupSortedList() { + List groupList = getNormalGroupList(); + Collections.sort(groupList, new Comparator(){ + @Override + public int compare(GroupEntity entity1, GroupEntity entity2) { + if(entity1.getPinyinElement().pinyin==null) + { + PinYin.getPinYin(entity1.getMainName(), entity1.getPinyinElement()); + } + if(entity2.getPinyinElement().pinyin==null) + { + PinYin.getPinYin(entity2.getMainName(),entity2.getPinyinElement()); + } + return entity1.getPinyinElement().pinyin.compareToIgnoreCase(entity2.getPinyinElement().pinyin); + } + }); + + return groupList; + } + + public GroupEntity findGroup(int groupId) { + logger.d("group#findGroup groupId:%s", groupId); + if(groupMap.containsKey(groupId)){ + return groupMap.get(groupId); + } + return null; + } + + public List getSearchAllGroupList(String key){ + List searchList = new ArrayList<>(); + for(Map.Entry entry:groupMap.entrySet()){ + GroupEntity groupEntity = entry.getValue(); + if (IMUIHelper.handleGroupSearch(key, groupEntity)) { + searchList.add(groupEntity); + } + } + return searchList; + } + + public List getGroupMembers(int groupId) { + logger.d("group#getGroupMembers groupId:%s", groupId); + + GroupEntity group = findGroup(groupId); + if (group == null) { + logger.e("group#no such group id:%s", groupId); + return null; + } + Set userList = group.getlistGroupMemberIds(); + ArrayList memberList = new ArrayList(); + for (Integer id : userList) { + UserEntity contact = IMContactManager.instance().findContact(id); + if (contact == null) { + logger.e("group#no such contact id:%s", id); + continue; + } + memberList.add(contact); + } + return memberList; + } + + /**------set/get 的定义*/ + public Map getGroupMap() { + return groupMap; + } + + public boolean isGroupReady() { + return isGroupReady; + } +} diff --git a/android/app/src/main/java/com/mogujie/tt/imservice/manager/IMHeartBeatManager.java b/android/app/src/main/java/com/mogujie/tt/imservice/manager/IMHeartBeatManager.java new file mode 100644 index 000000000..84f69f105 --- /dev/null +++ b/android/app/src/main/java/com/mogujie/tt/imservice/manager/IMHeartBeatManager.java @@ -0,0 +1,148 @@ +package com.mogujie.tt.imservice.manager; + +import android.app.AlarmManager; +import android.app.PendingIntent; +import android.content.BroadcastReceiver; +import android.content.Context; +import android.content.Intent; +import android.content.IntentFilter; +import android.os.PowerManager; + +import com.mogujie.tt.imservice.callback.Packetlistener; +import com.mogujie.tt.protobuf.IMBaseDefine; +import com.mogujie.tt.protobuf.IMOther; +import com.mogujie.tt.utils.Logger; + +/** + * @author : yingmu on 15-3-26. + * @email : yingmu@mogujie.com. + * + * 备注: 之前采用netty(3.6.6-fianl)支持通道检测IdleStateHandler,发现有些机型 + * 手机休眠之后IdleStateHandler 定时器HashedWheelTimer可能存在被系统停止关闭的现象 + * 所以采用AlarmManager 进行心跳的检测 + * + * 登陆之后就开始触发心跳检测 【仅仅是在线,重练就会取消的】 + * 退出reset 会释放alarmManager 资源 + */ +public class IMHeartBeatManager extends IMManager{ + // 心跳检测4分钟检测一次,并且发送心跳包 + // 服务端自身存在通道检测,5分钟没有数据会主动断开通道 + + private static IMHeartBeatManager inst = new IMHeartBeatManager(); + public static IMHeartBeatManager instance() { + return inst; + } + + private Logger logger = Logger.getLogger(IMHeartBeatManager.class); + private final int HEARTBEAT_INTERVAL = 4 * 60 * 1000; + private final String ACTION_SENDING_HEARTBEAT = "com.mogujie.tt.imservice.manager.imheartbeatmanager"; + private PendingIntent pendingIntent; + + @Override + public void doOnStart() { + } + + // 登陆成功之后 + public void onloginNetSuccess(){ + logger.e("heartbeat#onLocalNetOk"); + IntentFilter intentFilter = new IntentFilter(); + intentFilter.addAction(ACTION_SENDING_HEARTBEAT); + logger.d("heartbeat#register actions"); + ctx.registerReceiver(imReceiver, intentFilter); + //获取AlarmManager系统服务 + scheduleHeartbeat(HEARTBEAT_INTERVAL); + } + + @Override + public void reset() { + logger.d("heartbeat#reset begin"); + try { + ctx.unregisterReceiver(imReceiver); + cancelHeartbeatTimer(); + logger.d("heartbeat#reset stop"); + }catch (Exception e){ + logger.e("heartbeat#reset error:%s",e.getCause()); + } + } + + // MsgServerHandler 直接调用 + public void onMsgServerDisconn(){ + logger.w("heartbeat#onChannelDisconn"); + cancelHeartbeatTimer(); + } + + private void cancelHeartbeatTimer() { + logger.w("heartbeat#cancelHeartbeatTimer"); + if (pendingIntent == null) { + logger.w("heartbeat#pi is null"); + return; + } + AlarmManager am = (AlarmManager) ctx.getSystemService(Context.ALARM_SERVICE); + am.cancel(pendingIntent); + } + + + private void scheduleHeartbeat(int seconds){ + logger.d("heartbeat#scheduleHeartbeat every %d seconds", seconds); + if (pendingIntent == null) { + logger.w("heartbeat#fill in pendingintent"); + Intent intent = new Intent(ACTION_SENDING_HEARTBEAT); + pendingIntent = PendingIntent.getBroadcast(ctx, 0, intent, 0); + if (pendingIntent == null) { + logger.w("heartbeat#scheduleHeartbeat#pi is null"); + return; + } + } + + AlarmManager am = (AlarmManager) ctx.getSystemService(Context.ALARM_SERVICE); + am.setInexactRepeating(AlarmManager.RTC_WAKEUP, System.currentTimeMillis() + seconds, seconds, pendingIntent); + } + + + /**--------------------boradcast-广播相关-----------------------------*/ + private BroadcastReceiver imReceiver = new BroadcastReceiver(){ + @Override + public void onReceive(Context context, Intent intent) { + String action = intent.getAction(); + logger.w("heartbeat#im#receive action:%s", action); + if (action.equals(ACTION_SENDING_HEARTBEAT)) { + sendHeartBeatPacket(); + } + } + }; + + public void sendHeartBeatPacket(){ + logger.d("heartbeat#reqSendHeartbeat"); + PowerManager pm = (PowerManager) ctx.getSystemService(Context.POWER_SERVICE); + PowerManager.WakeLock wl = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "teamtalk_heartBeat_wakelock"); + wl.acquire(); + try { + final long timeOut = 5*1000; + IMOther.IMHeartBeat imHeartBeat = IMOther.IMHeartBeat.newBuilder() + .build(); + int sid = IMBaseDefine.ServiceID.SID_OTHER_VALUE; + int cid = IMBaseDefine.OtherCmdID.CID_OTHER_HEARTBEAT_VALUE; + IMSocketManager.instance().sendRequest(imHeartBeat,sid,cid,new Packetlistener(timeOut) { + @Override + public void onSuccess(Object response) { + logger.d("heartbeat#心跳成功,链接保活"); + } + + @Override + public void onFaild() { + logger.w("heartbeat#心跳包发送失败"); + IMSocketManager.instance().onMsgServerDisconn(); + } + + @Override + public void onTimeout() { + logger.w("heartbeat#心跳包发送超时"); + IMSocketManager.instance().onMsgServerDisconn(); + } + }); + logger.d("heartbeat#send packet to server"); + } finally { + wl.release(); + } + } +} diff --git a/android/app/src/main/java/com/mogujie/tt/imservice/manager/IMLoginManager.java b/android/app/src/main/java/com/mogujie/tt/imservice/manager/IMLoginManager.java new file mode 100644 index 000000000..d1f4902cc --- /dev/null +++ b/android/app/src/main/java/com/mogujie/tt/imservice/manager/IMLoginManager.java @@ -0,0 +1,435 @@ +package com.mogujie.tt.imservice.manager; + +import android.text.TextUtils; + +import com.google.protobuf.CodedInputStream; +import com.mogujie.tt.DB.DBInterface; +import com.mogujie.tt.DB.entity.UserEntity; +import com.mogujie.tt.DB.sp.LoginSp; +import com.mogujie.tt.imservice.callback.Packetlistener; +import com.mogujie.tt.imservice.event.LoginEvent; +import com.mogujie.tt.protobuf.helper.ProtoBuf2JavaBean; +import com.mogujie.tt.protobuf.IMBaseDefine; +import com.mogujie.tt.protobuf.IMBuddy; +import com.mogujie.tt.protobuf.IMLogin; +import com.mogujie.tt.utils.Logger; + +import java.io.IOException; + +import de.greenrobot.event.EventBus; + +/** + * 很多情况下都是一种权衡 + * 登陆控制 + * @yingmu + */ +public class IMLoginManager extends IMManager { + private Logger logger = Logger.getLogger(IMLoginManager.class); + + /**单例模式*/ + private static IMLoginManager inst = new IMLoginManager(); + public static IMLoginManager instance() { + return inst; + } + public IMLoginManager() { + logger.d("login#creating IMLoginManager"); + } + IMSocketManager imSocketManager = IMSocketManager.instance(); + + /**登陆参数 以便重试*/ + private String loginUserName; + private String loginPwd; + private int loginId; + private UserEntity loginInfo; + + + /**loginManger 自身的状态 todo 状态太多就采用enum的方式*/ + private boolean identityChanged = false; + private boolean isKickout = false; + private boolean isPcOnline = false; + //以前是否登陆过,用户重新登陆的判断 + private boolean everLogined = false; + //本地包含登陆信息了[可以理解为支持离线登陆了] + private boolean isLocalLogin = false; + + private LoginEvent loginStatus= LoginEvent.NONE; + + /**-------------------------------功能方法--------------------------------------*/ + + @Override + public void doOnStart() { + } + + @Override + public void reset() { + loginUserName = null; + loginPwd = null; + loginId = -1; + loginInfo = null; + identityChanged = false; + isKickout=false; + isPcOnline = false; + everLogined = false; + loginStatus= LoginEvent.NONE; + isLocalLogin = false; + } + + /** + * 实现自身的事件驱动 + * @param event + */ + public void triggerEvent(LoginEvent event) { + loginStatus = event; + EventBus.getDefault().postSticky(event); + } + + /** + * if not login, do nothing + send logOuting message, so reconnect won't react abnormally + but when reconnect start to work again?use isEverLogined + close the socket + send logOuteOk message + mainactivity jumps to login page + * + */ + public void logOut() { + logger.d("login#logOut"); + logger.d("login#stop reconnecting"); + // everlogined is enough to stop reconnecting + everLogined = false; + isLocalLogin = false; + reqLoginOut(); + } + + /** + * 退出登陆 + */ + private void reqLoginOut(){ + IMLogin.IMLogoutReq imLogoutReq = IMLogin.IMLogoutReq.newBuilder() + .build(); + int sid = IMBaseDefine.ServiceID.SID_LOGIN_VALUE; + int cid = IMBaseDefine.LoginCmdID.CID_LOGIN_REQ_LOGINOUT_VALUE; + try { + imSocketManager.sendRequest(imLogoutReq, sid, cid); + }catch (Exception e){ + logger.e("#reqLoginOut#sendRequest error,cause by"+e.toString()); + }finally { + LoginSp.instance().setLoginInfo(loginUserName,null,loginId); + logger.d("login#send logout finish message"); + triggerEvent(LoginEvent.LOGIN_OUT); + } + } + + /** + * 现在这种模式 req与rsp之间没有必然的耦合关系。是不是太松散了 + * @param imLogoutRsp + */ + public void onRepLoginOut(IMLogin.IMLogoutRsp imLogoutRsp){ + int code = imLogoutRsp.getResultCode(); + logger.d("login#send logout finish message"); + } + + /** + * 重新请求登陆 IMReconnectManager + * 1. 检测当前的状态 + * 2. 请求msg server的地址 + * 3. 建立链接 + * 4. 验证登陆信息 + * @return + */ + public void relogin() { + if(!TextUtils.isEmpty(loginUserName) && !TextUtils.isEmpty(loginPwd)){ + logger.d("reconnect#login#relogin"); + imSocketManager.reqMsgServerAddrs(); + }else{ + logger.d("reconnect#login#userName or loginPwd is null!!"); + everLogined = false; + triggerEvent(LoginEvent.LOGIN_AUTH_FAILED); + } + } + + // 自动登陆流程 + public void login(LoginSp.SpLoginIdentity identity){ + if(identity == null){ + triggerEvent(LoginEvent.LOGIN_AUTH_FAILED); + return; + } + loginUserName = identity.getLoginName(); + loginPwd = identity.getPwd(); + identityChanged = false; + + int mLoginId = identity.getLoginId(); + // 初始化数据库 + DBInterface.instance().initDbHelp(ctx,mLoginId); + UserEntity loginEntity = DBInterface.instance().getByLoginId(mLoginId); + do{ + if(loginEntity == null){ + break; + } + loginInfo = loginEntity; + loginId = loginEntity.getPeerId(); + // 这两个状态不要忘记掉 + isLocalLogin = true; + everLogined = true; + triggerEvent(LoginEvent.LOCAL_LOGIN_SUCCESS); + }while(false); + // 开始请求网络 + imSocketManager.reqMsgServerAddrs(); + } + + + public void login(String userName, String password) { + logger.i("login#login -> userName:%s", userName); + + //test 使用 + LoginSp.SpLoginIdentity identity = LoginSp.instance().getLoginIdentity(); + if(identity !=null && !TextUtils.isEmpty(identity.getPwd())) { + if (identity.getPwd().equals(password) && identity.getLoginName().equals(userName)) { + login(identity); + return; + } + } + //test end + loginUserName = userName; + loginPwd = password; + identityChanged = true; + imSocketManager.reqMsgServerAddrs(); + } + + /** + * 链接成功之后 + * */ + public void reqLoginMsgServer() { + logger.i("login#reqLoginMsgServer"); + triggerEvent(LoginEvent.LOGINING); + /** 加密 */ + String desPwd = new String(com.mogujie.tt.Security.getInstance().EncryptPass(loginPwd)); + + IMLogin.IMLoginReq imLoginReq = IMLogin.IMLoginReq.newBuilder() + .setUserName(loginUserName) + .setPassword(desPwd) + .setOnlineStatus(IMBaseDefine.UserStatType.USER_STATUS_ONLINE) + .setClientType(IMBaseDefine.ClientType.CLIENT_TYPE_ANDROID) + .setClientVersion("1.0.0").build(); + + int sid = IMBaseDefine.ServiceID.SID_LOGIN_VALUE; + int cid = IMBaseDefine.LoginCmdID.CID_LOGIN_REQ_USERLOGIN_VALUE; + imSocketManager.sendRequest(imLoginReq,sid,cid,new Packetlistener() { + @Override + public void onSuccess(Object response) { + try { + IMLogin.IMLoginRes imLoginRes = IMLogin.IMLoginRes.parseFrom((CodedInputStream)response); + onRepMsgServerLogin(imLoginRes); + } catch (IOException e) { + triggerEvent(LoginEvent.LOGIN_INNER_FAILED); + logger.e("login failed,cause by %s",e.getCause()); + } + } + + @Override + public void onFaild() { + triggerEvent(LoginEvent.LOGIN_INNER_FAILED); + } + + @Override + public void onTimeout() { + triggerEvent(LoginEvent.LOGIN_INNER_FAILED); + } + }); + } + + /** + * 验证登陆信息结果 + * @param loginRes + */ + public void onRepMsgServerLogin(IMLogin.IMLoginRes loginRes) { + logger.i("login#onRepMsgServerLogin"); + + if (loginRes == null) { + logger.e("login#decode LoginResponse failed"); + triggerEvent(LoginEvent.LOGIN_AUTH_FAILED); + return; + } + + IMBaseDefine.ResultType code = loginRes.getResultCode(); + switch (code){ + case REFUSE_REASON_NONE:{ + IMBaseDefine.UserStatType userStatType = loginRes.getOnlineStatus(); + IMBaseDefine.UserInfo userInfo = loginRes.getUserInfo(); + loginId = userInfo.getUserId(); + loginInfo = ProtoBuf2JavaBean.getUserEntity(userInfo); + onLoginOk(); + }break; + + case REFUSE_REASON_DB_VALIDATE_FAILED:{ + logger.e("login#login msg server failed, result:%s", code); + triggerEvent(LoginEvent.LOGIN_AUTH_FAILED); + }break; + + default:{ + logger.e("login#login msg server inner failed, result:%s", code); + triggerEvent(LoginEvent.LOGIN_INNER_FAILED); + }break; + } + } + + public void onLoginOk() { + logger.i("login#onLoginOk"); + everLogined = true; + isKickout = false; + + // 判断登陆的类型 + if(isLocalLogin){ + triggerEvent(LoginEvent.LOCAL_LOGIN_MSG_SERVICE); + }else{ + isLocalLogin = true; + triggerEvent(LoginEvent.LOGIN_OK); + } + + // 发送token +// reqDeviceToken(); + if (identityChanged) { + LoginSp.instance().setLoginInfo(loginUserName,loginPwd,loginId); + identityChanged = false; + } + } + + + + private void reqDeviceToken(){ +// String token = PushManager.getInstance().getToken(); +// IMLogin.IMDeviceTokenReq req = IMLogin.IMDeviceTokenReq.newBuilder() +// .setUserId(loginId) +// .setClientType(IMBaseDefine.ClientType.CLIENT_TYPE_ANDROID) +// .setDeviceToken(token) +// .build(); +// int sid = IMBaseDefine.ServiceID.SID_LOGIN_VALUE; +// int cid = IMBaseDefine.LoginCmdID.CID_LOGIN_REQ_DEVICETOKEN_VALUE; +// +// imSocketManager.sendRequest(req,sid,cid,new Packetlistener() { +// @Override +// public void onSuccess(Object response) { +// //?? nothing to do +//// try { +//// IMLogin.IMDeviceTokenRsp rsp = IMLogin.IMDeviceTokenRsp.parseFrom((CodedInputStream) response); +//// int userId = rsp.getUserId(); +//// } catch (IOException e) { +//// e.printStackTrace(); +//// } +// } +// +// @Override +// public void onFaild() {} +// +// @Override +// public void onTimeout() {} +// }); + } + + + public void onKickout(IMLogin.IMKickUser imKickUser){ + logger.i("login#onKickout"); + int kickUserId = imKickUser.getUserId(); + IMBaseDefine.KickReasonType reason = imKickUser.getKickReason(); + isKickout=true; + imSocketManager.onMsgServerDisconn(); + } + + + // 收到PC端登陆的通知,另外登陆成功之后,如果PC端在线,也会立马收到该通知 + public void onLoginStatusNotify(IMBuddy.IMPCLoginStatusNotify statusNotify){ + int userId = statusNotify.getUserId(); + // todo 由于交互不太友好 暂时先去掉 + if(true || userId !=loginId){ + logger.i("login#onLoginStatusNotify userId ≠ loginId"); + return; + } + + if(isKickout){ + logger.i("login#already isKickout"); + return; + } + + switch (statusNotify.getLoginStat()){ + case USER_STATUS_ONLINE:{ + isPcOnline = true; + EventBus.getDefault().postSticky(LoginEvent.PC_ONLINE); + }break; + + case USER_STATUS_OFFLINE:{ + isPcOnline = false; + EventBus.getDefault().postSticky(LoginEvent.PC_OFFLINE); + }break; + } + } + + // 踢出PC端登陆 + public void reqKickPCClient(){ + IMLogin.IMKickPCClientReq req = IMLogin.IMKickPCClientReq.newBuilder() + .setUserId(loginId) + .build(); + int sid = IMBaseDefine.ServiceID.SID_LOGIN_VALUE; + int cid = IMBaseDefine.LoginCmdID.CID_LOGIN_REQ_KICKPCCLIENT_VALUE; + imSocketManager.sendRequest(req,sid,cid,new Packetlistener() { + @Override + public void onSuccess(Object response) { + triggerEvent(LoginEvent.KICK_PC_SUCCESS); + } + @Override + public void onFaild() { + triggerEvent(LoginEvent.KICK_PC_FAILED); + } + @Override + public void onTimeout() { + triggerEvent(LoginEvent.KICK_PC_FAILED); + } + }); + } + + /**------------------状态的 set get------------------------------*/ + public int getLoginId() { + return loginId; + } + + public void setLoginId(int loginId) { + logger.d("login#setLoginId -> loginId:%d", loginId); + this.loginId = loginId; + + } + + public boolean isEverLogined() { + return everLogined; + } + + public void setEverLogined(boolean everLogined) { + this.everLogined = everLogined; + } + + public UserEntity getLoginInfo() { + return loginInfo; + } + + public void setLoginInfo(UserEntity loginInfo) { + this.loginInfo = loginInfo; + } + + public LoginEvent getLoginStatus() { + return loginStatus; + } + + public boolean isKickout() { + return isKickout; + } + + public void setKickout(boolean isKickout) { + this.isKickout = isKickout; + } + + public boolean isPcOnline() { + return isPcOnline; + } + + public void setPcOnline(boolean isPcOnline) { + this.isPcOnline = isPcOnline; + } +} diff --git a/android/app/src/main/java/com/mogujie/tt/imservice/manager/IMManager.java b/android/app/src/main/java/com/mogujie/tt/imservice/manager/IMManager.java new file mode 100644 index 000000000..2929b542d --- /dev/null +++ b/android/app/src/main/java/com/mogujie/tt/imservice/manager/IMManager.java @@ -0,0 +1,38 @@ +package com.mogujie.tt.imservice.manager; + +import android.content.Context; + +/** + * V3 + * 自身状态有些不是互斥的 + * 事件可以是多种的,触发的事件与自身的状态是两码事 + * 有些manager只能是单个的,例如socket 登陆 + * 但有些可能是多个,group 【正规群,临时群都ok】 + * + * 程序默认使用EventBus做为总线 + */ +public abstract class IMManager { + protected Context ctx; + protected void setContext(Context context) { + if (context == null) { + throw new RuntimeException("context is null"); + } + ctx = context; + } + + public void onStartIMManager(Context ctx){ + setContext(ctx); + doOnStart(); + } + /** + * imService 服务建立的时候 + * 初始化所有的manager 调用onStartIMManager会调用下面的方法 + */ + public abstract void doOnStart(); + /** + * 上下文环境的更新 + * 1. 环境变量的clear + * 2. eventBus的清空 + * */ + public abstract void reset(); +} diff --git a/android/app/src/main/java/com/mogujie/tt/imservice/manager/IMMessageManager.java b/android/app/src/main/java/com/mogujie/tt/imservice/manager/IMMessageManager.java new file mode 100644 index 000000000..4a0c351ce --- /dev/null +++ b/android/app/src/main/java/com/mogujie/tt/imservice/manager/IMMessageManager.java @@ -0,0 +1,698 @@ +package com.mogujie.tt.imservice.manager; + +import android.content.Intent; +import android.text.TextUtils; + +import com.google.protobuf.ByteString; +import com.google.protobuf.CodedInputStream; +import com.mogujie.tt.DB.entity.PeerEntity; +import com.mogujie.tt.DB.entity.SessionEntity; +import com.mogujie.tt.config.DBConstant; +import com.mogujie.tt.DB.DBInterface; +import com.mogujie.tt.DB.entity.MessageEntity; +import com.mogujie.tt.config.MessageConstant; +import com.mogujie.tt.config.SysConstant; +import com.mogujie.tt.imservice.callback.Packetlistener; +import com.mogujie.tt.imservice.entity.AudioMessage; +import com.mogujie.tt.imservice.entity.ImageMessage; +import com.mogujie.tt.imservice.entity.TextMessage; +import com.mogujie.tt.imservice.event.MessageEvent; +import com.mogujie.tt.imservice.event.PriorityEvent; +import com.mogujie.tt.imservice.event.RefreshHistoryMsgEvent; +import com.mogujie.tt.imservice.service.LoadImageService; +import com.mogujie.tt.protobuf.helper.EntityChangeEngine; +import com.mogujie.tt.protobuf.helper.Java2ProtoBuf; +import com.mogujie.tt.protobuf.helper.ProtoBuf2JavaBean; +import com.mogujie.tt.protobuf.IMBaseDefine; +import com.mogujie.tt.protobuf.IMMessage; +import com.mogujie.tt.imservice.support.SequenceNumberMaker; +import com.mogujie.tt.utils.Logger; + +import java.io.IOException; +import java.io.UnsupportedEncodingException; +import java.net.URLDecoder; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + +import de.greenrobot.event.EventBus; + +/** + * 消息的处理 + */ +public class IMMessageManager extends IMManager{ + private Logger logger = Logger.getLogger(IMMessageManager.class); + private static IMMessageManager inst = new IMMessageManager(); + public static IMMessageManager instance() { + return inst; + } + + private IMSocketManager imSocketManager = IMSocketManager.instance(); + private IMSessionManager sessionManager = IMSessionManager.instance(); + private DBInterface dbInterface = DBInterface.instance(); + + // 消息发送超时时间爱你设定 + // todo eric, after testing ok, make it a longer value + private final long TIMEOUT_MILLISECONDS = 6 * 1000; + private final long IMAGE_TIMEOUT_MILLISECONDS = 4 * 60 * 1000; + + + private long getTimeoutTolerance(MessageEntity msg) { + switch (msg.getDisplayType()){ + case DBConstant.SHOW_IMAGE_TYPE: + return IMAGE_TIMEOUT_MILLISECONDS; + default:break; + } + return TIMEOUT_MILLISECONDS; + } + + /** + * 接受到消息,并且向服务端发送确认 + * @param msg + */ + public void ackReceiveMsg(MessageEntity msg){ + logger.d("chat#ackReceiveMsg -> msg:%s", msg); + IMBaseDefine.SessionType sessionType = Java2ProtoBuf.getProtoSessionType(msg.getSessionType()); + IMMessage.IMMsgDataAck imMsgDataAck = IMMessage.IMMsgDataAck.newBuilder() + .setMsgId(msg.getMsgId()) + .setSessionId(msg.getToId()) + .setUserId(msg.getFromId()) + .setSessionType(sessionType) + .build(); + int sid = IMBaseDefine.ServiceID.SID_MSG_VALUE; + int cid = IMBaseDefine.MessageCmdID.CID_MSG_DATA_ACK_VALUE; + imSocketManager.sendRequest(imMsgDataAck,sid,cid); + } + + @Override + public void doOnStart() { + } + + public void onLoginSuccess(){ + if(!EventBus.getDefault().isRegistered(inst)){ + EventBus.getDefault().register(inst); + } + } + + @Override + public void reset() { + EventBus.getDefault().unregister(inst); + } + + /** + * 自身的事件驱动 + * @param event + */ + public void triggerEvent(Object event) { + EventBus.getDefault().post(event); + } + + + /**图片的处理放在这里,因为在发送图片的过程中,很可能messageActivity已经关闭掉*/ + public void onEvent(MessageEvent event){ + MessageEvent.Event type = event.getEvent(); + switch (type){ + case IMAGE_UPLOAD_FAILD:{ + logger.d("pic#onUploadImageFaild"); + ImageMessage imageMessage = (ImageMessage)event.getMessageEntity(); + imageMessage.setLoadStatus(MessageConstant.IMAGE_LOADED_FAILURE); + imageMessage.setStatus(MessageConstant.MSG_FAILURE); + dbInterface.insertOrUpdateMessage(imageMessage); + + /**通知Activity层 失败*/ + event.setEvent(MessageEvent.Event.HANDLER_IMAGE_UPLOAD_FAILD); + event.setMessageEntity(imageMessage); + triggerEvent(event); + }break; + + case IMAGE_UPLOAD_SUCCESS:{ + onImageLoadSuccess(event); + }break; + } + } + + /** + * 事件的处理会在一个后台线程中执行,对应的函数名是onEventBackgroundThread, + * 虽然名字是BackgroundThread,事件处理是在后台线程, + * 但事件处理时间还是不应该太长 + * 因为如果发送事件的线程是后台线程,会直接执行事件, + * 如果当前线程是UI线程,事件会被加到一个队列中,由一个线程依次处理这些事件, + * 如果某个事件处理时间太长,会阻塞后面的事件的派发或处理 + * */ + public void onEventBackgroundThread(RefreshHistoryMsgEvent historyMsgEvent){ + doRefreshLocalMsg(historyMsgEvent); + } + + + /**----------------------底层的接口-------------------------------------*/ + /** + * 发送消息,最终的状态情况 + * MessageManager下面的拆分 + * 应该是自己发的信息,所以msgId为0 + * 这个地方用DB id作为主键 + */ + public void sendMessage(MessageEntity msgEntity) { + logger.d("chat#sendMessage, msg:%s", msgEntity); + // 发送情况下 msg_id 都是0 + // 服务端是从1开始计数的 + if(!SequenceNumberMaker.getInstance().isFailure(msgEntity.getMsgId())){ + throw new RuntimeException("#sendMessage# msgId is wrong,cause by 0!"); + } + + IMBaseDefine.MsgType msgType = Java2ProtoBuf.getProtoMsgType(msgEntity.getMsgType()); + byte[] sendContent = msgEntity.getSendContent(); + + + IMMessage.IMMsgData msgData = IMMessage.IMMsgData.newBuilder() + .setFromUserId(msgEntity.getFromId()) + .setToSessionId(msgEntity.getToId()) + .setMsgId(0) + .setCreateTime(msgEntity.getCreated()) + .setMsgType(msgType) + .setMsgData(ByteString.copyFrom(sendContent)) // 这个点要特别注意 todo ByteString.copyFrom + .build(); + int sid = IMBaseDefine.ServiceID.SID_MSG_VALUE; + int cid = IMBaseDefine.MessageCmdID.CID_MSG_DATA_VALUE; + + + final MessageEntity messageEntity = msgEntity; + imSocketManager.sendRequest(msgData,sid,cid,new Packetlistener(getTimeoutTolerance(messageEntity)) { + @Override + public void onSuccess(Object response) { + try { + IMMessage.IMMsgDataAck imMsgDataAck = IMMessage.IMMsgDataAck.parseFrom((CodedInputStream)response); + logger.i("chat#onAckSendedMsg"); + if(imMsgDataAck.getMsgId() <=0){ + throw new RuntimeException("Msg ack error,cause by msgId <=0"); + } + messageEntity.setStatus(MessageConstant.MSG_SUCCESS); + messageEntity.setMsgId(imMsgDataAck.getMsgId()); + /**主键ID已经存在,直接替换*/ + dbInterface.insertOrUpdateMessage(messageEntity); + /**更新sessionEntity lastMsgId问题*/ + sessionManager.updateSession(messageEntity); + triggerEvent(new MessageEvent(MessageEvent.Event.ACK_SEND_MESSAGE_OK,messageEntity)); + } catch (IOException e) { + e.printStackTrace(); + } + } + @Override + public void onFaild() { + messageEntity.setStatus(MessageConstant.MSG_FAILURE); + dbInterface.insertOrUpdateMessage(messageEntity); + triggerEvent(new MessageEvent(MessageEvent.Event.ACK_SEND_MESSAGE_FAILURE,messageEntity)); + } + @Override + public void onTimeout() { + messageEntity.setStatus(MessageConstant.MSG_FAILURE); + dbInterface.insertOrUpdateMessage(messageEntity); + triggerEvent(new MessageEvent(MessageEvent.Event.ACK_SEND_MESSAGE_TIME_OUT,messageEntity)); + } + }); + } + + /** + * 收到服务端原始信息 + * 1. 解析消息的类型 + * 2. 根据不同的类型,转化成不同的消息 + * 3. 先保存在DB[insertOrreplace]中,session的更新,Unread的更新 + * 4上层通知 + * @param imMsgData + */ + public void onRecvMessage(IMMessage.IMMsgData imMsgData) { + logger.i("chat#onRecvMessage"); + if (imMsgData == null) { + logger.e("chat#decodeMessageInfo failed,cause by is null"); + return; + } + + MessageEntity recvMessage = ProtoBuf2JavaBean.getMessageEntity(imMsgData); + int loginId = IMLoginManager.instance().getLoginId(); + boolean isSend = recvMessage.isSend(loginId); + recvMessage.buildSessionKey(isSend); + recvMessage.setStatus(MessageConstant.MSG_SUCCESS); + /**对于混合消息,未读消息计数还是1,session已经更新*/ + + dbInterface.insertOrUpdateMessage(recvMessage); + sessionManager.updateSession(recvMessage); + + /** + * 发送已读确认由上层的activity处理 特殊处理 + * 1. 未读计数、 通知、session页面 + * 2. 当前会话 + * */ + PriorityEvent notifyEvent = new PriorityEvent(); + notifyEvent.event = PriorityEvent.Event.MSG_RECEIVED_MESSAGE; + notifyEvent.object = recvMessage; + triggerEvent(notifyEvent); + } + + + /**-------------------其实可以继续分层切分---------消息发送相关-------------------------------*/ + /** + * 1. 先保存DB + * 2. push到adapter中 + * 3. 等待ack,更新页面 + * */ + public void sendText(TextMessage textMessage) { + logger.i("chat#text#textMessage"); + textMessage.setStatus(MessageConstant.MSG_SENDING); + long pkId = DBInterface.instance().insertOrUpdateMessage(textMessage); + sessionManager.updateSession(textMessage); + sendMessage(textMessage); + } + + public void sendVoice(AudioMessage audioMessage) { + logger.i("chat#audio#sendVoice"); + audioMessage.setStatus(MessageConstant.MSG_SENDING); + long pkId = DBInterface.instance().insertOrUpdateMessage(audioMessage); + sessionManager.updateSession(audioMessage); + sendMessage(audioMessage); + } + + + public void sendSingleImage(ImageMessage msg){ + logger.d("ImMessageManager#sendImage "); + ArrayList msgList = new ArrayList<>(); + msgList.add(msg); + sendImages(msgList); + } + + /** + * 发送图片消息 + * @param msgList + */ + public void sendImages(List msgList) { + logger.i("chat#image#sendImages size:%d",msgList.size()); + if(null == msgList || msgList.size() <=0){ + return ; + } + + int len = msgList.size(); + ArrayList needDbList = new ArrayList<>(); + for (ImageMessage msg : msgList) { + needDbList.add(msg); + } + DBInterface.instance().batchInsertOrUpdateMessage(needDbList); + + for (ImageMessage msg : msgList) { + logger.d("chat#pic#sendImage msg:%s",msg); + // image message would wrapped as a text message after uploading + int loadStatus = msg.getLoadStatus(); + + switch (loadStatus){ + case MessageConstant.IMAGE_LOADED_FAILURE: + case MessageConstant.IMAGE_UNLOAD: + case MessageConstant.IMAGE_LOADING: + msg.setLoadStatus(MessageConstant.IMAGE_LOADING); + Intent loadImageIntent = new Intent(ctx, LoadImageService.class); + loadImageIntent.putExtra(SysConstant.UPLOAD_IMAGE_INTENT_PARAMS,msg); + ctx.startService(loadImageIntent); + break; + case MessageConstant.IMAGE_LOADED_SUCCESS: + sendMessage(msg); + break; + default: + throw new RuntimeException("sendImages#status不可能出现的状态"); + } + } + /**将最后一条更新到Session上面*/ + sessionManager.updateSession(msgList.get(len-1)); + } + + /** + * 重新发送 message数据包 + * 1.检测DB状态 + * 2.删除DB状态 [不用删除] + * 3.调用对应的发送 + * 判断消息的类型、判断是否是重发的状态 + * */ + public void resendMessage(MessageEntity msgInfo) { + if (msgInfo == null) { + logger.d("chat#resendMessage msgInfo is null or already send success!"); + return; + } + /**check 历史原因处理*/ + if(!SequenceNumberMaker.getInstance().isFailure(msgInfo.getMsgId())){ + // 之前的状态处理有问题 + msgInfo.setStatus(MessageConstant.MSG_SUCCESS); + dbInterface.insertOrUpdateMessage(msgInfo); + triggerEvent(new MessageEvent(MessageEvent.Event.ACK_SEND_MESSAGE_OK,msgInfo)); + return; + } + + logger.d("chat#resendMessage msgInfo %s",msgInfo); + /**重新设定message 的时间,已经从DB中删除*/ + int nowTime = (int) (System.currentTimeMillis()/1000); + msgInfo.setUpdated(nowTime); + msgInfo.setCreated(nowTime); + + /**判断信息的类型*/ + int msgType = msgInfo.getDisplayType(); + switch (msgType){ + case DBConstant.SHOW_ORIGIN_TEXT_TYPE: + sendText((TextMessage)msgInfo); + break; + case DBConstant.SHOW_IMAGE_TYPE: + sendSingleImage((ImageMessage) msgInfo); + break; + case DBConstant.SHOW_AUDIO_TYPE: + sendVoice((AudioMessage)msgInfo); break; + default: + throw new IllegalArgumentException("#resendMessage#enum type is wrong!!,cause by displayType"+msgType); + } + } + + + + // 拉取历史消息 {from MessageActivity} + public List loadHistoryMsg(int pullTimes,String sessionKey,PeerEntity peerEntity){ + int lastMsgId = 99999999; + int lastCreateTime = 1455379200; + int count = SysConstant.MSG_CNT_PER_PAGE; + SessionEntity sessionEntity = IMSessionManager.instance().findSession(sessionKey); + if (sessionEntity != null) { + // 以前已经聊过天,删除之后,sessionEntity不存在 + logger.i("#loadHistoryMsg# sessionEntity is null"); + lastMsgId = sessionEntity.getLatestMsgId(); + // 这个地方设定有问题,先使用最大的时间,session的update设定存在问题 + //lastCreateTime = sessionEntity.getUpdated(); + } + + if(lastMsgId <1 || TextUtils.isEmpty(sessionKey)){ + return Collections.emptyList(); + } + if(count > lastMsgId){ + count = lastMsgId; + } + List msgList = doLoadHistoryMsg( + pullTimes, peerEntity.getPeerId(), + peerEntity.getType(), + sessionKey, lastMsgId, lastCreateTime, count); + + return msgList; + } + + // 根据次数有点粗暴 + public List loadHistoryMsg(MessageEntity entity,int pullTimes){ + logger.d("IMMessageActivity#LoadHistoryMsg"); + // 在滑动的过程中请求,msgId请求下一条的 + int reqLastMsgId = entity.getMsgId() - 1; + int loginId = IMLoginManager.instance().getLoginId(); + int reqLastCreateTime = entity.getCreated(); + String chatKey = entity.getSessionKey(); + int cnt = SysConstant.MSG_CNT_PER_PAGE; + List msgList = doLoadHistoryMsg(pullTimes, + entity.getPeerId(entity.isSend(loginId)), + entity.getSessionType(), + chatKey, reqLastMsgId, reqLastCreateTime, cnt); + return msgList; + } + + /** + * 从DB中请求信息 + * 1. 从最近会话点击进入,拉取消息 + * 2. 在消息页面下拉刷新 + * @param pullTimes + * @param peerId + * @param peerType + * @param sessionKey + * @param lastMsgId + * @param lastCreateTime + * @param count + * @return + */ + private List doLoadHistoryMsg(int pullTimes,final int peerId,final int peerType, final String sessionKey,int lastMsgId,int lastCreateTime,int count){ + if(lastMsgId <1 || TextUtils.isEmpty(sessionKey)){ + return Collections.emptyList(); + } + if(count > lastMsgId){ + count = lastMsgId; + } + // 降序结果输出desc + List listMsg = dbInterface.getHistoryMsg(sessionKey,lastMsgId,lastCreateTime,count); + // asyn task refresh + int resSize = listMsg.size(); + logger.d("LoadHistoryMsg return size is %d",resSize); + if(resSize==0 || pullTimes == 1 || pullTimes %3==0){ + RefreshHistoryMsgEvent historyMsgEvent = new RefreshHistoryMsgEvent(); + historyMsgEvent.pullTimes = pullTimes; + historyMsgEvent.count = count; + historyMsgEvent.lastMsgId = lastMsgId; + historyMsgEvent.listMsg = listMsg; + historyMsgEvent.peerId = peerId; + historyMsgEvent.peerType = peerType; + historyMsgEvent.sessionKey = sessionKey; + triggerEvent(historyMsgEvent); + } + return listMsg; + } + + /** + * asyn task + * 因为是多端同步,本地信息并不一定完成,拉取时提前异步检测 + * */ + private void doRefreshLocalMsg(RefreshHistoryMsgEvent hisEvent){ + /**check DB数据的一致性*/ + int lastSuccessMsgId = hisEvent.lastMsgId; + List listMsg = hisEvent.listMsg; + + int resSize = listMsg.size(); + if(hisEvent.pullTimes > 1) { + for (int index = resSize - 1; index >= 0; index--) { + MessageEntity entity = listMsg.get(index); + if (!SequenceNumberMaker.getInstance().isFailure(entity.getMsgId())) { + lastSuccessMsgId = entity.getMsgId(); + break; + } + } + }else{ + /**是第一次拉取*/ + if(SequenceNumberMaker.getInstance().isFailure(lastSuccessMsgId)) + /**正序第一个*/ + for(MessageEntity entity:listMsg){ + if (!SequenceNumberMaker.getInstance().isFailure(entity.getMsgId())) { + lastSuccessMsgId = entity.getMsgId(); + break; + } + } + } + + final int refreshCnt = hisEvent.count * 3; + int peerId = hisEvent.peerId; + int peerType = hisEvent.peerType; + String sessionKey = hisEvent.sessionKey; + boolean localFailure = SequenceNumberMaker.getInstance().isFailure(lastSuccessMsgId); + if(localFailure){ + logger.e("LoadHistoryMsg# all msg is failure!"); + if(hisEvent.pullTimes ==1){ + reqHistoryMsgNet(peerId,peerType,lastSuccessMsgId,refreshCnt); + } + }else { + /**正常*/ + refreshDBMsg(peerId, peerType, sessionKey, lastSuccessMsgId, refreshCnt); + } + } + + /** + * 历史消息直接从DB中获取。 + * 所以要保证DB数据没有问题 + */ + public void refreshDBMsg(int peerId,int peedType,String chatKey,int lastMsgId,int refreshCnt){ + if(lastMsgId <1){return;} + int beginMsgId = lastMsgId - refreshCnt; + if(beginMsgId<1){beginMsgId=1;} + + // 返回的结果是升序 + List msgIdList = dbInterface.refreshHistoryMsgId(chatKey, beginMsgId, lastMsgId); + if(msgIdList.size() == (lastMsgId-beginMsgId+1)){ + logger.d("refreshDBMsg#do need refresh Message!,cause sizeOfList is right"); + return; + } + // 查找缺失的msgid + List needReqList = new ArrayList<>(); + for(int startIndex=beginMsgId,endIndex=lastMsgId;startIndex<=endIndex;startIndex++){ + if(!msgIdList.contains(startIndex)){ + needReqList.add(startIndex); + } + } + // 请求缺失的消息 + if(needReqList.size()>0){ + reqMsgById(peerId,peedType,needReqList); + } + } + + + private void reqMsgById(int peerId,int sessionType,List msgIds){ + int userId = IMLoginManager.instance().getLoginId(); + IMBaseDefine.SessionType sType = Java2ProtoBuf.getProtoSessionType(sessionType); + IMMessage.IMGetMsgByIdReq imGetMsgByIdReq = IMMessage.IMGetMsgByIdReq.newBuilder() + .setSessionId(peerId) + .setUserId(userId) + .setSessionType(sType) + .addAllMsgIdList(msgIds) + .build(); + int sid = IMBaseDefine.ServiceID.SID_MSG_VALUE; + int cid = IMBaseDefine.MessageCmdID.CID_MSG_GET_BY_MSG_ID_REQ_VALUE; + imSocketManager.sendRequest(imGetMsgByIdReq,sid,cid); + } + + public void onReqMsgById(IMMessage.IMGetMsgByIdRsp rsp){ + int userId = rsp.getUserId(); + int peerId = rsp.getSessionId(); + int sessionType = ProtoBuf2JavaBean.getJavaSessionType(rsp.getSessionType()); + String sessionKey = EntityChangeEngine.getSessionKey(peerId,sessionType); + + List msgList = rsp.getMsgListList(); + if(msgList.size() <=0){ + logger.i("onReqMsgById# have no msgList"); + return; + } + List dbEntity = new ArrayList<>(); + for(IMBaseDefine.MsgInfo msg:msgList){ + MessageEntity entity = ProtoBuf2JavaBean.getMessageEntity(msg); + if(entity == null){ + logger.d("#IMMessageManager# onReqHistoryMsg#analyzeMsg is null,%s",entity); + continue; + } + + entity.setSessionKey(sessionKey); + switch (sessionType){ + case DBConstant.SESSION_TYPE_GROUP:{ + entity.setToId(peerId); + }break; + case DBConstant.SESSION_TYPE_SINGLE:{ + if(entity.getFromId() == userId){ + entity.setToId(peerId); + }else{ + entity.setToId(userId); + } + }break; + } + + dbEntity.add(entity); + } + dbInterface.batchInsertOrUpdateMessage(dbEntity); + /**事件驱动通知*/ + MessageEvent event = new MessageEvent(); + event.setEvent(MessageEvent.Event.HISTORY_MSG_OBTAIN); + triggerEvent(event); + } + + + /** + * network 请求历史消息 + */ + public void reqHistoryMsgNet(int peerId,int peerType, int lastMsgId, int cnt){ + int loginId = IMLoginManager.instance().getLoginId(); + + IMMessage.IMGetMsgListReq req = IMMessage.IMGetMsgListReq.newBuilder() + .setUserId(loginId) + .setSessionType(Java2ProtoBuf.getProtoSessionType(peerType)) + .setSessionId(peerId) + .setMsgIdBegin(lastMsgId) + .setMsgCnt(cnt) + .build(); + + int sid = IMBaseDefine.ServiceID.SID_MSG_VALUE; + int cid = IMBaseDefine.MessageCmdID.CID_MSG_LIST_REQUEST_VALUE; + imSocketManager.sendRequest(req,sid,cid); + } + + /** + * 收到消息的具体信息 + * 保存在DB中 + * 通知上层,请求消息成功 + * + *对于群而言,如果消息数目返回的数值小于请求的cnt,则表示群的消息能拉取的到头了,更早的消息没有权限拉取。 + *如果msg_cnt 和 msg_id_begin计算得到的最早消息id与实际返回的最早消息id不一致,说明服务器消息有缺失,需要 + *客户端做一个缺失标记,避免下次再次拉取。 + * */ + public void onReqHistoryMsg(IMMessage.IMGetMsgListRsp rsp){ + // 判断loginId 判断sessionId + int userId = rsp.getUserId(); + int sessionType = ProtoBuf2JavaBean.getJavaSessionType(rsp.getSessionType()); + int peerId = rsp.getSessionId(); + String sessionKey = EntityChangeEngine.getSessionKey(peerId,sessionType); + int msgBegin = rsp.getMsgIdBegin(); + + List msgList = rsp.getMsgListList(); + + ArrayList result = new ArrayList<>(); + for(IMBaseDefine.MsgInfo msgInfo:msgList){ + MessageEntity messageEntity = ProtoBuf2JavaBean.getMessageEntity(msgInfo); + if(messageEntity == null){ + logger.d("#IMMessageManager# onReqHistoryMsg#analyzeMsg is null,%s",messageEntity); + continue; + } + messageEntity.setSessionKey(sessionKey); + switch (sessionType){ + case DBConstant.SESSION_TYPE_GROUP:{ + messageEntity.setToId(peerId); + }break; + case DBConstant.SESSION_TYPE_SINGLE:{ + if(messageEntity.getFromId() == userId){ + messageEntity.setToId(peerId); + }else{ + messageEntity.setToId(userId); + } + }break; + } + result.add(messageEntity); + } + /**事件的通知 check */ + if(result.size()>0) { + dbInterface.batchInsertOrUpdateMessage(result); + MessageEvent event = new MessageEvent(); + event.setEvent(MessageEvent.Event.HISTORY_MSG_OBTAIN); + triggerEvent(event); + } + } + + /**下载图片的整体迁移出来*/ + private void onImageLoadSuccess(MessageEvent imageEvent){ + + ImageMessage imageMessage = (ImageMessage)imageEvent.getMessageEntity(); + logger.d("pic#onImageUploadFinish"); + String imageUrl = imageMessage.getUrl(); + logger.d("pic#imageUrl:%s", imageUrl); + String realImageURL = ""; + try { + realImageURL = URLDecoder.decode(imageUrl, "utf-8"); + logger.d("pic#realImageUrl:%s", realImageURL); + } catch (UnsupportedEncodingException e) { + logger.e(e.toString()); + } + + imageMessage.setUrl(realImageURL); + imageMessage.setStatus(MessageConstant.MSG_SUCCESS); + imageMessage.setLoadStatus(MessageConstant.IMAGE_LOADED_SUCCESS); + dbInterface.insertOrUpdateMessage(imageMessage); + + /**通知Activity层 成功 , 事件通知*/ + imageEvent.setEvent(MessageEvent.Event.HANDLER_IMAGE_UPLOAD_SUCCESS); + imageEvent.setMessageEntity(imageMessage); + triggerEvent(imageEvent); + + imageMessage.setContent(MessageConstant.IMAGE_MSG_START + + realImageURL + MessageConstant.IMAGE_MSG_END); + sendMessage(imageMessage); + } + +// /**获取session内的最后一条回话*/ +// private void reqSessionLastMsgId(int sessionId,int sessionType,Packetlistener packetlistener){ +// int userId = IMLoginManager.instance().getLoginId(); +// IMMessage.IMGetLatestMsgIdReq latestMsgIdReq = IMMessage.IMGetLatestMsgIdReq.newBuilder() +// .setUserId(userId) +// .setSessionId(sessionId) +// .setSessionType(Java2ProtoBuf.getProtoSessionType(sessionType)) +// .build(); +// int sid = IMBaseDefine.ServiceID.SID_MSG_VALUE; +// int cid = IMBaseDefine.MessageCmdID.CID_MSG_GET_LATEST_MSG_ID_REQ_VALUE; +// imSocketManager.sendRequest(latestMsgIdReq,sid,cid,packetlistener); +// } +// +// public void onReqSessionLastMsgId(IMMessage.IMGetLatestMsgIdRsp latestMsgIdRsp){ +// int lastMsgId = latestMsgIdRsp.getLatestMsgId(); +// } +} diff --git a/android/app/src/main/java/com/mogujie/tt/imservice/manager/IMNotificationManager.java b/android/app/src/main/java/com/mogujie/tt/imservice/manager/IMNotificationManager.java new file mode 100644 index 000000000..d17467498 --- /dev/null +++ b/android/app/src/main/java/com/mogujie/tt/imservice/manager/IMNotificationManager.java @@ -0,0 +1,292 @@ +package com.mogujie.tt.imservice.manager; + +import android.app.Notification; +import android.app.NotificationManager; +import android.app.PendingIntent; +import android.content.Context; +import android.content.Intent; +import android.graphics.Bitmap; +import android.graphics.BitmapFactory; +import android.support.v4.app.NotificationCompat; +import android.support.v4.app.NotificationCompat.Builder; +import android.view.View; + +import com.mogujie.tt.DB.entity.GroupEntity; +import com.mogujie.tt.DB.entity.PeerEntity; +import com.mogujie.tt.DB.entity.UserEntity; +import com.mogujie.tt.DB.sp.ConfigurationSp; +import com.mogujie.tt.R; +import com.mogujie.tt.config.DBConstant; +import com.mogujie.tt.config.IntentConstant; +import com.mogujie.tt.config.SysConstant; +import com.mogujie.tt.imservice.entity.UnreadEntity; +import com.mogujie.tt.imservice.event.GroupEvent; +import com.mogujie.tt.imservice.event.UnreadEvent; +import com.mogujie.tt.protobuf.helper.EntityChangeEngine; +import com.mogujie.tt.ui.activity.MessageActivity; +import com.mogujie.tt.utils.IMUIHelper; +import com.mogujie.tt.utils.Logger; +import com.nostra13.universalimageloader.core.ImageLoader; +import com.nostra13.universalimageloader.core.assist.FailReason; +import com.nostra13.universalimageloader.core.assist.ImageSize; +import com.nostra13.universalimageloader.core.listener.SimpleImageLoadingListener; + +import de.greenrobot.event.EventBus; + +/** + * 伪推送; app退出之后就不会收到推送的信息 + * 通知栏新消息通知 + * a.每个session 只显示一条 + * b.每个msg 信息都显示 + * 配置依赖与 configure + */ +public class IMNotificationManager extends IMManager{ + + private Logger logger = Logger.getLogger(IMNotificationManager.class); + private static IMNotificationManager inst = new IMNotificationManager(); + public static IMNotificationManager instance() { + return inst; + } + private ConfigurationSp configurationSp; + + private IMNotificationManager() { + } + + @Override + public void doOnStart() { + cancelAllNotifications(); + } + + public void onLoginSuccess(){ + int loginId = IMLoginManager.instance().getLoginId(); + configurationSp = ConfigurationSp.instance(ctx,loginId); + if(!EventBus.getDefault().isRegistered(inst)){ + EventBus.getDefault().register(inst); + } + } + + public void reset() { + EventBus.getDefault().unregister(this); + cancelAllNotifications(); + } + + + public void onEventMainThread(UnreadEvent event){ + switch (event.event){ + case UNREAD_MSG_RECEIVED: + UnreadEntity unreadEntity = event.entity; + handleMsgRecv(unreadEntity); + break; + } + } + + // 屏蔽群,相关的通知全部删除 + public void onEventMainThread(GroupEvent event){ + GroupEntity gEntity = event.getGroupEntity(); + if(event.getEvent()== GroupEvent.Event.SHIELD_GROUP_OK){ + if(gEntity == null){ + return; + } + cancelSessionNotifications(gEntity.getSessionKey()); + } + } + + private void handleMsgRecv(UnreadEntity entity) { + logger.d("notification#recv unhandled message"); + int peerId = entity.getPeerId(); + int sessionType = entity.getSessionType(); + logger.d("notification#msg no one handled, peerId:%d, sessionType:%d", peerId, sessionType); + + //判断是否设定了免打扰 + if(entity.isForbidden()){ + logger.d("notification#GROUP_STATUS_SHIELD"); + return; + } + + //PC端是否登陆 取消 【暂时先关闭】 +// if(IMLoginManager.instance().isPcOnline()){ +// logger.d("notification#isPcOnline"); +// return; +// } + + // 全局开关 + boolean globallyOnOff = configurationSp.getCfg(SysConstant.SETTING_GLOBAL,ConfigurationSp.CfgDimension.NOTIFICATION); + if (globallyOnOff) { + logger.d("notification#shouldGloballyShowNotification is false, return"); + return; + } + + // 单独的设置 + boolean singleOnOff = configurationSp.getCfg(entity.getSessionKey(),ConfigurationSp.CfgDimension.NOTIFICATION); + if (singleOnOff) { + logger.d("notification#shouldShowNotificationBySession is false, return"); + return; + } + + //if the message is a multi login message which send from another terminal,not need notificate to status bar + // 判断是否是自己的消息 + if(IMLoginManager.instance().getLoginId() != peerId){ + showNotification(entity); + } + } + + + public void cancelAllNotifications() { + logger.d("notification#cancelAllNotifications"); + if(null == ctx){ + return; + } + NotificationManager notifyMgr = (NotificationManager) ctx.getSystemService(Context.NOTIFICATION_SERVICE); + if (notifyMgr == null) { + return; + } + notifyMgr.cancelAll(); + } + + + /** + * 在通知栏中删除特定回话的状态 + * @param sessionKey + */ + public void cancelSessionNotifications(String sessionKey) { + logger.d("notification#cancelSessionNotifications"); + NotificationManager notifyMgr = (NotificationManager) ctx.getSystemService(Context.NOTIFICATION_SERVICE); + if (null == notifyMgr) { + return; + } + int notificationId = getSessionNotificationId(sessionKey); + notifyMgr.cancel(notificationId); + } + + + private void showNotification(final UnreadEntity unreadEntity) { + // todo eric need to set the exact size of the big icon + // 服务端有些特定的支持 尺寸是不是要调整一下 todo 100*100 下面的就可以不要了 + ImageSize targetSize = new ImageSize(80, 80); + int peerId = unreadEntity.getPeerId(); + int sessionType = unreadEntity.getSessionType(); + String avatarUrl = ""; + String title = ""; + String content = unreadEntity.getLatestMsgData(); + String unit = ctx.getString(R.string.msg_cnt_unit); + int totalUnread = unreadEntity.getUnReadCnt(); + + if(unreadEntity.getSessionType() == DBConstant.SESSION_TYPE_SINGLE){ + UserEntity contact = IMContactManager.instance().findContact(peerId); + if(contact !=null){ + title = contact.getMainName(); + avatarUrl = contact.getAvatar(); + }else{ + title = "User_"+peerId; + avatarUrl = ""; + } + + }else{ + GroupEntity group = IMGroupManager.instance().findGroup(peerId); + if(group !=null){ + title = group.getMainName(); + avatarUrl = group.getAvatar(); + }else{ + title = "Group_"+peerId; + avatarUrl = ""; + } + } + //获取头像 + avatarUrl = IMUIHelper.getRealAvatarUrl(avatarUrl); + final String ticker = String.format("[%d%s]%s: %s", totalUnread, unit, title, content); + final int notificationId = getSessionNotificationId(unreadEntity.getSessionKey()); + final Intent intent = new Intent(ctx, MessageActivity.class); + intent.putExtra(IntentConstant.KEY_SESSION_KEY, unreadEntity.getSessionKey()); + + logger.d("notification#notification avatarUrl:%s", avatarUrl); + final String finalTitle = title; + ImageLoader.getInstance().loadImage(avatarUrl, targetSize, null, new SimpleImageLoadingListener() { + + @Override + public void onLoadingComplete(String imageUri, View view, + Bitmap loadedImage) { + logger.d("notification#icon onLoadComplete"); + // holder.image.setImageBitmap(loadedImage); + showInNotificationBar(finalTitle,ticker,loadedImage,notificationId,intent); + } + + @Override + public void onLoadingFailed(String imageUri, View view, + FailReason failReason) { + logger.d("notification#icon onLoadFailed"); + // 服务器支持的格式有哪些 + // todo eric default avatar is too small, need big size(128 * 128) + Bitmap defaultBitmap = BitmapFactory.decodeResource(ctx.getResources(), IMUIHelper.getDefaultAvatarResId(unreadEntity.getSessionType())); + showInNotificationBar(finalTitle,ticker,defaultBitmap,notificationId,intent); + } + }); + } + + private void showInNotificationBar(String title,String ticker, Bitmap iconBitmap,int notificationId,Intent intent) { + logger.d("notification#showInNotificationBar title:%s ticker:%s",title,ticker); + + NotificationManager notifyMgr = (NotificationManager) ctx.getSystemService(Context.NOTIFICATION_SERVICE); + if (notifyMgr == null) { + return; + } + + Builder builder = new NotificationCompat.Builder(ctx); + builder.setContentTitle(title); + builder.setContentText(ticker); + builder.setSmallIcon(R.drawable.tt_small_icon); + builder.setTicker(ticker); + builder.setWhen(System.currentTimeMillis()); + builder.setAutoCancel(true); + + // this is the content near the right bottom side + // builder.setContentInfo("content info"); + + if (configurationSp.getCfg(SysConstant.SETTING_GLOBAL,ConfigurationSp.CfgDimension.VIBRATION)) { + // delay 0ms, vibrate 200ms, delay 250ms, vibrate 200ms + long[] vibrate = {0, 200, 250, 200}; + builder.setVibrate(vibrate); + } else { + logger.d("notification#setting is not using vibration"); + } + + // sound + if (configurationSp.getCfg(SysConstant.SETTING_GLOBAL,ConfigurationSp.CfgDimension.SOUND)) { + builder.setDefaults(Notification.DEFAULT_SOUND); + } else { + logger.d("notification#setting is not using sound"); + } + if (iconBitmap != null) { + logger.d("notification#fetch icon from network ok"); + builder.setLargeIcon(iconBitmap); + } else { + // do nothint ? + } + // if MessageActivity is in the background, the system would bring it to + // the front + intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); + PendingIntent pendingIntent = PendingIntent.getActivity(ctx, notificationId, intent, PendingIntent.FLAG_UPDATE_CURRENT); + builder.setContentIntent(pendingIntent); + Notification notification = builder.build(); + notifyMgr.notify(notificationId, notification); + } + + // come from + // http://www.partow.net/programming/hashfunctions/index.html#BKDRHashFunction + private long hashBKDR(String str) { + long seed = 131; // 31 131 1313 13131 131313 etc.. + long hash = 0; + + for (int i = 0; i < str.length(); i++) { + hash = (hash * seed) + str.charAt(i); + } + return hash; + } + + /* End Of BKDR Hash Function */ + public int getSessionNotificationId(String sessionKey) { + logger.d("notification#getSessionNotificationId sessionTag:%s", sessionKey); + int hashedNotificationId = (int) hashBKDR(sessionKey); + logger.d("notification#hashedNotificationId:%d", hashedNotificationId); + return hashedNotificationId; + } +} diff --git a/android/app/src/main/java/com/mogujie/tt/imservice/manager/IMPacketDispatcher.java b/android/app/src/main/java/com/mogujie/tt/imservice/manager/IMPacketDispatcher.java new file mode 100644 index 000000000..1c57bb7d8 --- /dev/null +++ b/android/app/src/main/java/com/mogujie/tt/imservice/manager/IMPacketDispatcher.java @@ -0,0 +1,159 @@ +package com.mogujie.tt.imservice.manager; + +import com.google.protobuf.CodedInputStream; +import com.mogujie.tt.protobuf.IMBaseDefine; +import com.mogujie.tt.protobuf.IMBuddy; +import com.mogujie.tt.protobuf.IMGroup; +import com.mogujie.tt.protobuf.IMLogin; +import com.mogujie.tt.protobuf.IMMessage; +import com.mogujie.tt.utils.Logger; + +import java.io.IOException; + +/** + * yingmu + * 消息分发中心,处理消息服务器返回的数据包 + * 1. decode header与body的解析 + * 2. 分发 + */ +public class IMPacketDispatcher { + private static Logger logger = Logger.getLogger(IMPacketDispatcher.class); + + /** + * @param commandId + * @param buffer + * + * 有没有更加优雅的方式 + */ + public static void loginPacketDispatcher(int commandId,CodedInputStream buffer){ + try { + switch (commandId) { +// case IMBaseDefine.LoginCmdID.CID_LOGIN_RES_USERLOGIN_VALUE : +// IMLogin.IMLoginRes imLoginRes = IMLogin.IMLoginRes.parseFrom(buffer); +// IMLoginManager.instance().onRepMsgServerLogin(imLoginRes); +// return; + + case IMBaseDefine.LoginCmdID.CID_LOGIN_RES_LOGINOUT_VALUE: + IMLogin.IMLogoutRsp imLogoutRsp = IMLogin.IMLogoutRsp.parseFrom(buffer); + IMLoginManager.instance().onRepLoginOut(imLogoutRsp); + return; + + case IMBaseDefine.LoginCmdID.CID_LOGIN_KICK_USER_VALUE: + IMLogin.IMKickUser imKickUser = IMLogin.IMKickUser.parseFrom(buffer); + IMLoginManager.instance().onKickout(imKickUser); + } + } catch (IOException e) { + logger.e("loginPacketDispatcher# error,cid:%d",commandId); + } + } + + public static void buddyPacketDispatcher(int commandId,CodedInputStream buffer){ + try { + switch (commandId) { + case IMBaseDefine.BuddyListCmdID.CID_BUDDY_LIST_ALL_USER_RESPONSE_VALUE: + IMBuddy.IMAllUserRsp imAllUserRsp = IMBuddy.IMAllUserRsp.parseFrom(buffer); + IMContactManager.instance().onRepAllUsers(imAllUserRsp); + return; + + case IMBaseDefine.BuddyListCmdID.CID_BUDDY_LIST_USER_INFO_RESPONSE_VALUE: + IMBuddy.IMUsersInfoRsp imUsersInfoRsp = IMBuddy.IMUsersInfoRsp.parseFrom(buffer); + IMContactManager.instance().onRepDetailUsers(imUsersInfoRsp); + return; + case IMBaseDefine.BuddyListCmdID.CID_BUDDY_LIST_RECENT_CONTACT_SESSION_RESPONSE_VALUE: + IMBuddy.IMRecentContactSessionRsp recentContactSessionRsp = IMBuddy.IMRecentContactSessionRsp.parseFrom(buffer); + IMSessionManager.instance().onRepRecentContacts(recentContactSessionRsp); + return; + + case IMBaseDefine.BuddyListCmdID.CID_BUDDY_LIST_REMOVE_SESSION_RES_VALUE: + IMBuddy.IMRemoveSessionRsp removeSessionRsp = IMBuddy.IMRemoveSessionRsp.parseFrom(buffer); + IMSessionManager.instance().onRepRemoveSession(removeSessionRsp); + return; + + case IMBaseDefine.BuddyListCmdID.CID_BUDDY_LIST_PC_LOGIN_STATUS_NOTIFY_VALUE: + IMBuddy.IMPCLoginStatusNotify statusNotify = IMBuddy.IMPCLoginStatusNotify.parseFrom(buffer); + IMLoginManager.instance().onLoginStatusNotify(statusNotify); + return; + + case IMBaseDefine.BuddyListCmdID.CID_BUDDY_LIST_DEPARTMENT_RESPONSE_VALUE: + IMBuddy.IMDepartmentRsp departmentRsp = IMBuddy.IMDepartmentRsp.parseFrom(buffer); + IMContactManager.instance().onRepDepartment(departmentRsp); + return; + + } + } catch (IOException e) { + logger.e("buddyPacketDispatcher# error,cid:%d",commandId); + } + } + + public static void msgPacketDispatcher(int commandId,CodedInputStream buffer){ + try { + switch (commandId) { + case IMBaseDefine.MessageCmdID.CID_MSG_DATA_ACK_VALUE: + // have some problem todo + return; + + case IMBaseDefine.MessageCmdID.CID_MSG_LIST_RESPONSE_VALUE: + IMMessage.IMGetMsgListRsp rsp = IMMessage.IMGetMsgListRsp.parseFrom(buffer); + IMMessageManager.instance().onReqHistoryMsg(rsp); + return; + + case IMBaseDefine.MessageCmdID.CID_MSG_DATA_VALUE: + IMMessage.IMMsgData imMsgData = IMMessage.IMMsgData.parseFrom(buffer); + IMMessageManager.instance().onRecvMessage(imMsgData); + return; + + case IMBaseDefine.MessageCmdID.CID_MSG_READ_NOTIFY_VALUE: + IMMessage.IMMsgDataReadNotify readNotify = IMMessage.IMMsgDataReadNotify.parseFrom(buffer); + IMUnreadMsgManager.instance().onNotifyRead(readNotify); + return; + case IMBaseDefine.MessageCmdID.CID_MSG_UNREAD_CNT_RESPONSE_VALUE: + IMMessage.IMUnreadMsgCntRsp unreadMsgCntRsp = IMMessage.IMUnreadMsgCntRsp.parseFrom(buffer); + IMUnreadMsgManager.instance().onRepUnreadMsgContactList(unreadMsgCntRsp); + return; + + case IMBaseDefine.MessageCmdID.CID_MSG_GET_BY_MSG_ID_RES_VALUE: + IMMessage.IMGetMsgByIdRsp getMsgByIdRsp = IMMessage.IMGetMsgByIdRsp.parseFrom(buffer); + IMMessageManager.instance().onReqMsgById(getMsgByIdRsp); + break; + + } + } catch (IOException e) { + logger.e("msgPacketDispatcher# error,cid:%d",commandId); + } + } + + public static void groupPacketDispatcher(int commandId,CodedInputStream buffer){ + try { + switch (commandId) { +// case IMBaseDefine.GroupCmdID.CID_GROUP_CREATE_RESPONSE_VALUE: +// IMGroup.IMGroupCreateRsp groupCreateRsp = IMGroup.IMGroupCreateRsp.parseFrom(buffer); +// IMGroupManager.instance().onReqCreateTempGroup(groupCreateRsp); +// return; + + case IMBaseDefine.GroupCmdID.CID_GROUP_NORMAL_LIST_RESPONSE_VALUE: + IMGroup.IMNormalGroupListRsp normalGroupListRsp = IMGroup.IMNormalGroupListRsp.parseFrom(buffer); + IMGroupManager.instance().onRepNormalGroupList(normalGroupListRsp); + return; + + case IMBaseDefine.GroupCmdID.CID_GROUP_INFO_RESPONSE_VALUE: + IMGroup.IMGroupInfoListRsp groupInfoListRsp = IMGroup.IMGroupInfoListRsp.parseFrom(buffer); + IMGroupManager.instance().onRepGroupDetailInfo(groupInfoListRsp); + return; + +// case IMBaseDefine.GroupCmdID.CID_GROUP_CHANGE_MEMBER_RESPONSE_VALUE: +// IMGroup.IMGroupChangeMemberRsp groupChangeMemberRsp = IMGroup.IMGroupChangeMemberRsp.parseFrom(buffer); +// IMGroupManager.instance().onReqChangeGroupMember(groupChangeMemberRsp); +// return; + + case IMBaseDefine.GroupCmdID.CID_GROUP_CHANGE_MEMBER_NOTIFY_VALUE: + IMGroup.IMGroupChangeMemberNotify notify = IMGroup.IMGroupChangeMemberNotify.parseFrom(buffer); + IMGroupManager.instance().receiveGroupChangeMemberNotify(notify); + case IMBaseDefine.GroupCmdID.CID_GROUP_SHIELD_GROUP_RESPONSE_VALUE: + //todo + return; + } + }catch(IOException e){ + logger.e("groupPacketDispatcher# error,cid:%d",commandId); + } + } +} diff --git a/android/app/src/main/java/com/mogujie/tt/imservice/manager/IMReconnectManager.java b/android/app/src/main/java/com/mogujie/tt/imservice/manager/IMReconnectManager.java new file mode 100644 index 000000000..01a43fe31 --- /dev/null +++ b/android/app/src/main/java/com/mogujie/tt/imservice/manager/IMReconnectManager.java @@ -0,0 +1,319 @@ +package com.mogujie.tt.imservice.manager; + +import android.app.AlarmManager; +import android.app.PendingIntent; +import android.content.BroadcastReceiver; +import android.content.Context; +import android.content.Intent; +import android.content.IntentFilter; +import android.net.ConnectivityManager; +import android.net.NetworkInfo; +import android.os.Handler; +import android.os.Message; +import android.os.PowerManager; + +import com.mogujie.tt.imservice.event.LoginEvent; +import com.mogujie.tt.imservice.event.ReconnectEvent; +import com.mogujie.tt.imservice.event.SocketEvent; +import com.mogujie.tt.utils.Logger; +import com.mogujie.tt.utils.NetworkUtil; + +import de.greenrobot.event.EventBus; +/** + * @modify yingmu + * @Date 2014-12-28 + * + * [修改重点]: + * 重试的触发点是:1.网络链接的异常 2.请求消息服务器 3链接消息服务器 + */ +public class IMReconnectManager extends IMManager { + private Logger logger = Logger.getLogger(IMReconnectManager.class); + + private static IMReconnectManager inst = new IMReconnectManager(); + public static IMReconnectManager instance() { + return inst; + } + + /**重连所处的状态*/ + private volatile ReconnectEvent status = ReconnectEvent.NONE; + + private final int INIT_RECONNECT_INTERVAL_SECONDS = 3; + private int reconnectInterval = INIT_RECONNECT_INTERVAL_SECONDS; + private final int MAX_RECONNECT_INTERVAL_SECONDS = 60; + + private final int HANDLER_CHECK_NETWORK = 1; + + + private volatile boolean isAlarmTrigger = false; + + /** + * imService 服务建立的时候 + * 初始化所有的manager 调用onStartIMManager会调用下面的方法 + * eventBus 注册可以放在这里 + */ + @Override + public void doOnStart() { + } + + public void onNormalLoginOk(){ + onLocalLoginOk(); + status = ReconnectEvent.SUCCESS; + } + + public void onLocalLoginOk(){ + logger.d("reconnect#LoginEvent onLocalLoginOk"); + + if(!EventBus.getDefault().isRegistered(inst)){ + EventBus.getDefault().register(inst); + } + + IntentFilter intentFilter = new IntentFilter(); + intentFilter.addAction(ACTION_RECONNECT); + intentFilter.addAction(ConnectivityManager.CONNECTIVITY_ACTION); + logger.d("reconnect#register actions"); + ctx.registerReceiver(imReceiver, intentFilter); + } + + /** 网络链接成功*/ + public void onLocalNetOk(){ + logger.d("reconnect#onLoginSuccess 网络链接上来,无需其他操作"); + status = ReconnectEvent.SUCCESS; + } + + + @Override + public void reset() { + logger.d("reconnect#reset begin"); + try { + EventBus.getDefault().unregister(inst); + ctx.unregisterReceiver(imReceiver); + status = ReconnectEvent.NONE; + isAlarmTrigger = false; + logger.d("reconnect#reset stop"); + }catch (Exception e){ + logger.e("reconnect#reset error:%s",e.getCause()); + } + } + + /** + * 网络socket状态监听 + * 并未登陆,请求链接消息服务器失败 + * @param socketEvent + */ + public void onEventMainThread(SocketEvent socketEvent){ + logger.d("reconnect#SocketEvent event:%s",socketEvent.name()); + + //MSG_SERVER_DISCONNECTED 没有必要重连吧。。 + + switch (socketEvent){ + case MSG_SERVER_DISCONNECTED: + case REQ_MSG_SERVER_ADDRS_FAILED: + case CONNECT_MSG_SERVER_FAILED:{ + tryReconnect(); + }break; + } + } + + /** + * + * @param event + */ + public void onEventMainThread(LoginEvent event){ + logger.d("reconnect#LoginEvent event: %s",event.name()); + switch (event){ + case LOGIN_INNER_FAILED: + tryReconnect(); + break; + + case LOCAL_LOGIN_MSG_SERVICE: + resetReconnectTime(); + break; + } + } + + /**EventBus 没有找到延迟发送的*/ + Handler handler = new Handler(){ + @Override + public void handleMessage(Message msg) { + super.handleMessage(msg); + switch (msg.what){ + case HANDLER_CHECK_NETWORK:{ + if(!NetworkUtil.isNetWorkAvalible(ctx)){ + logger.w("reconnect#handleMessage#网络依旧不可用"); + EventBus.getDefault().post(ReconnectEvent.DISABLE); + } + }break; + } + } + }; + + private boolean isReconnecting(){ + SocketEvent socketEvent = IMSocketManager.instance().getSocketStatus(); + LoginEvent loginEvent = IMLoginManager.instance().getLoginStatus(); + + if(socketEvent.equals(SocketEvent.CONNECTING_MSG_SERVER) + || socketEvent.equals(SocketEvent.REQING_MSG_SERVER_ADDRS) + || loginEvent.equals(LoginEvent.LOGINING)){ + return true; + } + return false; + } + + /** + * 可能是网络环境切换 + * 可能是数据包异常 + * 启动快速重连机制 + */ + private void tryReconnect(){ + /**检测网络状态*/ + ConnectivityManager nw = (ConnectivityManager) ctx.getSystemService(Context.CONNECTIVITY_SERVICE); + NetworkInfo netinfo = nw.getActiveNetworkInfo(); + + if(netinfo == null){ + // 延迟检测 + logger.w("reconnect#netinfo 为空延迟检测"); + status = ReconnectEvent.DISABLE; + handler.sendEmptyMessageDelayed(HANDLER_CHECK_NETWORK, 2000); + return ; + } + + synchronized(IMReconnectManager.this) { + // 网络状态可用 当前状态处于重连的过程中 可能会死循环嘛 + if (netinfo.isAvailable()) { + /**网络显示可用*/ + /**判断是否有必要重练*/ + if (status == ReconnectEvent.NONE + || !IMLoginManager.instance().isEverLogined() + || IMLoginManager.instance().isKickout() + || IMSocketManager.instance().isSocketConnect() + ) { + logger.i("reconnect#无需启动重连程序"); + return; + } + if (isReconnecting()) { + /**升级时间,部署下一次的重练*/ + logger.d("reconnect#正在重连中.."); + incrementReconnectInterval(); + scheduleReconnect(reconnectInterval); + logger.d("reconnect#tryReconnect#下次重练时间间隔:%d", reconnectInterval); + return; + } + + /**确保之前的链接已经关闭*/ + IMSocketManager.instance().disconnectMsgServer(); + + if (isAlarmTrigger) { + isAlarmTrigger = false; + logger.d("reconnect#定时器触发重连。。。"); + handleReconnectServer(); + } else { + logger.d("reconnect#正常重连,非定时器"); + IMSocketManager.instance().reconnectMsg(); + } + } else { + //通知上层UI修改 + logger.d("reconnect#网络不可用!! 通知上层"); + status = ReconnectEvent.DISABLE; + EventBus.getDefault().post(ReconnectEvent.DISABLE); + } + } + } + + /** + * 部署下次请求的时间 + * 为什么用这种方式,而不是handler? + * @param seconds + */ + private void scheduleReconnect(int seconds) { + logger.d("reconnect#scheduleReconnect after %d seconds", seconds); + Intent intent = new Intent(ACTION_RECONNECT); + PendingIntent pi = PendingIntent.getBroadcast(ctx, 0, intent,PendingIntent.FLAG_CANCEL_CURRENT); + if (pi == null) { + logger.e("reconnect#pi is null"); + return; + } + AlarmManager am = (AlarmManager) ctx.getSystemService(Context.ALARM_SERVICE); + am.set(AlarmManager.RTC_WAKEUP, System.currentTimeMillis() + seconds + * 1000, pi); + } + + /** + * 在RECONNECT 的时候,时间加成处理 + */ + private void incrementReconnectInterval() { + if (reconnectInterval >= MAX_RECONNECT_INTERVAL_SECONDS) { + reconnectInterval = MAX_RECONNECT_INTERVAL_SECONDS; + } else { + reconnectInterval = reconnectInterval * 2; + } + } + + /** + * 重新设定重连时间 + */ + private void resetReconnectTime() { + logger.d("reconnect#resetReconnectTime"); + reconnectInterval = INIT_RECONNECT_INTERVAL_SECONDS; + } + + + + + /**--------------------boradcast-广播相关-----------------------------*/ + private final String ACTION_RECONNECT = "com.mogujie.tt.imlib.action.reconnect"; + private BroadcastReceiver imReceiver = new BroadcastReceiver(){ + @Override + public void onReceive(Context context, Intent intent) { + String action = intent.getAction(); + logger.d("reconnect#im#receive action:%s", action); + onAction(action, intent); + } + }; + + /** + * 【重要】这个地方作为重连判断的唯一标准 + * 飞行模式: 触发 + * 切换网络状态: 触发 + * 没有网络 : 触发 + * */ + public void onAction(String action, Intent intent) { + logger.d("reconnect#onAction action:%s", action); + if (action.equals(ConnectivityManager.CONNECTIVITY_ACTION)) { + logger.d("reconnect#onAction#网络状态发生变化!!"); + tryReconnect(); + } else if (action.equals(ACTION_RECONNECT)) { + isAlarmTrigger = true; + tryReconnect(); + } + } + + /** + * 设定的调度开始执行 + * todo 其他reconnect需要获取锁嘛 + */ + private void handleReconnectServer() { + logger.d("reconnect#handleReconnectServer#定时任务触发"); + PowerManager pm = (PowerManager) ctx.getSystemService(Context.POWER_SERVICE); + PowerManager.WakeLock wl = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "teamtalk_reconnecting_wakelock"); + wl.acquire(); + try { + if(!IMLoginManager.instance().isEverLogined() || IMLoginManager.instance().isKickout()){ + logger.d("reconnect#isEverLogined return!!!"); + return; + } + logger.d("reconnect#login#reConnect."); + if(reconnectInterval > 24){ + // 重新请求msg地址 + IMLoginManager.instance().relogin(); + }else{ + IMSocketManager.instance().reconnectMsg(); + } + + logger.d("reconnect#trigger event reconnecting"); + } finally { + wl.release(); + } + } +} + + diff --git a/android/app/src/main/java/com/mogujie/tt/imservice/manager/IMSessionManager.java b/android/app/src/main/java/com/mogujie/tt/imservice/manager/IMSessionManager.java new file mode 100644 index 000000000..1d34aea2a --- /dev/null +++ b/android/app/src/main/java/com/mogujie/tt/imservice/manager/IMSessionManager.java @@ -0,0 +1,380 @@ + +package com.mogujie.tt.imservice.manager; + + +import android.text.TextUtils; + +import com.mogujie.tt.DB.entity.PeerEntity; +import com.mogujie.tt.DB.entity.UserEntity; +import com.mogujie.tt.config.DBConstant; +import com.mogujie.tt.DB.DBInterface; +import com.mogujie.tt.DB.entity.GroupEntity; +import com.mogujie.tt.DB.entity.MessageEntity; +import com.mogujie.tt.DB.entity.SessionEntity; +import com.mogujie.tt.DB.sp.ConfigurationSp; +import com.mogujie.tt.imservice.entity.RecentInfo; +import com.mogujie.tt.imservice.entity.UnreadEntity; +import com.mogujie.tt.imservice.event.SessionEvent; +import com.mogujie.tt.protobuf.helper.EntityChangeEngine; +import com.mogujie.tt.protobuf.helper.Java2ProtoBuf; +import com.mogujie.tt.protobuf.helper.ProtoBuf2JavaBean; +import com.mogujie.tt.protobuf.IMBaseDefine; +import com.mogujie.tt.protobuf.IMBuddy; +import com.mogujie.tt.utils.Logger; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.Comparator; +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.TreeSet; +import java.util.concurrent.ConcurrentHashMap; + +import de.greenrobot.event.EventBus; + +/** + * app显示首页 + * 最近联系人列表 + */ +public class IMSessionManager extends IMManager { + private Logger logger = Logger.getLogger(IMSessionManager.class); + private static IMSessionManager inst = new IMSessionManager(); + public static IMSessionManager instance() { + return inst; + } + + private IMSocketManager imSocketManager = IMSocketManager.instance(); + private IMLoginManager imLoginManager = IMLoginManager.instance(); + private DBInterface dbInterface = DBInterface.instance(); + private IMGroupManager groupManager = IMGroupManager.instance(); + + // key = sessionKey --> sessionType_peerId + private Map sessionMap = new ConcurrentHashMap<>(); + //SessionManager 状态字段 + private boolean sessionListReady = false; + + @Override + public void doOnStart() {} + + @Override + public void reset() { + sessionListReady = false; + sessionMap.clear(); + } + + /** + * 实现自身的事件驱动 + * @param event + */ + public void triggerEvent(SessionEvent event) { + switch (event){ + case RECENT_SESSION_LIST_SUCCESS: + sessionListReady = true; + break; + } + EventBus.getDefault().post(event); + } + + public void onNormalLoginOk() { + logger.d("recent#onLogin Successful"); + onLocalLoginOk(); + onLocalNetOk(); + } + + public void onLocalLoginOk(){ + logger.i("session#loadFromDb"); + List sessionInfoList = dbInterface.loadAllSession(); + for(SessionEntity sessionInfo:sessionInfoList){ + sessionMap.put(sessionInfo.getSessionKey(), sessionInfo); + } + + triggerEvent(SessionEvent.RECENT_SESSION_LIST_SUCCESS); + } + + public void onLocalNetOk(){ + int latestUpdateTime = dbInterface.getSessionLastTime(); + logger.d("session#更新时间:%d",latestUpdateTime); + reqGetRecentContacts(latestUpdateTime); + } + + /**----------------------------分割线--------------------------------*/ + + /** + * 请求最近回话 + */ + private void reqGetRecentContacts(int latestUpdateTime) { + logger.i("session#reqGetRecentContacts"); + int loginId = IMLoginManager.instance().getLoginId(); + IMBuddy.IMRecentContactSessionReq recentContactSessionReq = IMBuddy.IMRecentContactSessionReq + .newBuilder() + .setLatestUpdateTime(latestUpdateTime) + .setUserId(loginId) + .build(); + int sid = IMBaseDefine.ServiceID.SID_BUDDY_LIST_VALUE; + int cid = IMBaseDefine.BuddyListCmdID.CID_BUDDY_LIST_RECENT_CONTACT_SESSION_REQUEST_VALUE; + imSocketManager.sendRequest(recentContactSessionReq, sid, cid); + } + + /** + * 最近回话返回 + * 与本地的进行merge + * @param recentContactSessionRsp + */ + public void onRepRecentContacts(IMBuddy.IMRecentContactSessionRsp recentContactSessionRsp) { + logger.i("session#onRepRecentContacts"); + int userId = recentContactSessionRsp.getUserId(); + List contactSessionInfoList = recentContactSessionRsp.getContactSessionListList(); + logger.i("contact#user:%d cnt:%d",userId,contactSessionInfoList.size()); + /**更新最近联系人列表*/ + + ArrayList needDb = new ArrayList<>(); + for(IMBaseDefine.ContactSessionInfo sessionInfo:contactSessionInfoList){ + // 返回的没有主键Id + SessionEntity sessionEntity = ProtoBuf2JavaBean.getSessionEntity(sessionInfo); + //并没有按照时间来排序 + sessionMap.put(sessionEntity.getSessionKey(), sessionEntity); + needDb.add(sessionEntity); + } + logger.d("session#onRepRecentContacts is ready,now broadcast"); + + //将最新的session信息保存在DB中 + dbInterface.batchInsertOrUpdateSession(needDb); + if(needDb.size()>0){ + triggerEvent(SessionEvent.RECENT_SESSION_LIST_UPDATE); + } + } + + /** + * 请求删除会话 + */ + public void reqRemoveSession(RecentInfo recentInfo) { + logger.i("session#reqRemoveSession"); + + int loginId = imLoginManager.getLoginId(); + String sessionKey = recentInfo.getSessionKey(); + /**直接本地先删除,清楚未读消息*/ + if(sessionMap.containsKey(sessionKey)){ + sessionMap.remove(sessionKey); + IMUnreadMsgManager.instance().readUnreadSession(sessionKey); + dbInterface.deleteSession(sessionKey); + ConfigurationSp.instance(ctx,loginId).setSessionTop(sessionKey,false); + triggerEvent(SessionEvent.RECENT_SESSION_LIST_UPDATE); + } + + IMBuddy.IMRemoveSessionReq removeSessionReq = IMBuddy.IMRemoveSessionReq + .newBuilder() + .setUserId(loginId) + .setSessionId(recentInfo.getPeerId()) + .setSessionType(Java2ProtoBuf.getProtoSessionType(recentInfo.getSessionType())) + .build(); + int sid = IMBaseDefine.ServiceID.SID_BUDDY_LIST_VALUE; + int cid = IMBaseDefine.BuddyListCmdID.CID_BUDDY_LIST_REMOVE_SESSION_REQ_VALUE; + imSocketManager.sendRequest(removeSessionReq, sid, cid); + } + + /** + * 删除会话返回 + */ + public void onRepRemoveSession(IMBuddy.IMRemoveSessionRsp removeSessionRsp) { + logger.i("session#onRepRemoveSession"); + int resultCode = removeSessionRsp.getResultCode(); + if(0 != resultCode){ + logger.e("session#removeSession failed"); + return; + } + } + + /**新建群组时候的更新 */ + public void updateSession(GroupEntity entity){ + logger.d("recent#updateSession GroupEntity:%s", entity); + SessionEntity sessionEntity = new SessionEntity(); + sessionEntity.setLatestMsgType(DBConstant.MSG_TYPE_GROUP_TEXT); + sessionEntity.setUpdated(entity.getUpdated()); + sessionEntity.setCreated(entity.getCreated()); + sessionEntity.setLatestMsgData("[你创建的新群喔]"); + sessionEntity.setTalkId(entity.getCreatorId()); + sessionEntity.setLatestMsgId(0); + sessionEntity.setPeerId(entity.getPeerId()); + sessionEntity.setPeerType(DBConstant.SESSION_TYPE_GROUP); + sessionEntity.buildSessionKey(); + + sessionMap.put(sessionEntity.getSessionKey(), sessionEntity); + ArrayList needDb = new ArrayList<>(1); + needDb.add(sessionEntity); + dbInterface.batchInsertOrUpdateSession(needDb); + triggerEvent(SessionEvent.RECENT_SESSION_LIST_UPDATE); + } + + + /** + * 1.自己发送消息 + * 2.收到消息 + * @param msg + */ + public void updateSession(MessageEntity msg) { + logger.d("recent#updateSession msg:%s", msg); + if (msg == null) { + logger.d("recent#updateSession is end,cause by msg is null"); + return; + } + int loginId =imLoginManager.getLoginId(); + boolean isSend = msg.isSend(loginId); + // 因为多端同步的问题 + int peerId = msg.getPeerId(isSend); + + SessionEntity sessionEntity = sessionMap.get(msg.getSessionKey()); + if (sessionEntity == null) { + logger.d("session#updateSession#not found msgSessionEntity"); + sessionEntity = EntityChangeEngine.getSessionEntity(msg); + sessionEntity.setPeerId(peerId); + sessionEntity.buildSessionKey(); + // 判断群组的信息是否存在 + if(sessionEntity.getPeerType() == DBConstant.SESSION_TYPE_GROUP){ + GroupEntity groupEntity = groupManager.findGroup(peerId); + if(groupEntity == null){ + groupManager.reqGroupDetailInfo(peerId); + } + } + }else{ + logger.d("session#updateSession#msgSessionEntity already in Map"); + sessionEntity.setUpdated(msg.getUpdated()); + sessionEntity.setLatestMsgData(msg.getMessageDisplay()); + sessionEntity.setTalkId(msg.getFromId()); + //todo check if msgid is null/0 + sessionEntity.setLatestMsgId(msg.getMsgId()); + sessionEntity.setLatestMsgType(msg.getMsgType()); + } + + /**DB 先更新*/ + ArrayList needDb = new ArrayList<>(1); + needDb.add(sessionEntity); + dbInterface.batchInsertOrUpdateSession(needDb); + + sessionMap.put(sessionEntity.getSessionKey(), sessionEntity); + triggerEvent(SessionEvent.RECENT_SESSION_LIST_UPDATE); + } + + + public List getRecentSessionList() { + List recentInfoList = new ArrayList<>(sessionMap.values()); + return recentInfoList; + } + + private static void sort(List data) { + Collections.sort(data, new Comparator() { + public int compare(RecentInfo o1, RecentInfo o2) { + Integer a = o1.getUpdateTime(); + Integer b = o2.getUpdateTime(); + + boolean isTopA = o1.isTop(); + boolean isTopB = o2.isTop(); + + if(isTopA == isTopB){ + // 升序 + //return a.compareTo(b); + // 降序 + return b.compareTo(a); + }else{ + if(isTopA){ + return -1; + }else{ + return 1; + } + } + + } + }); + } + + // 获取最近联系人列表,RecentInfo 是sessionEntity unreadEntity user/group 等等实体的封装 + // todo every time it has to sort, kind of inefficient, change it + public List getRecentListInfo(){ + /**整理topList*/ + List recentSessionList = new ArrayList<>(); + int loginId = IMLoginManager.instance().getLoginId(); + + List sessionList = getRecentSessionList(); + Map userMap = IMContactManager.instance().getUserMap(); + Map unreadMsgMap = IMUnreadMsgManager.instance().getUnreadMsgMap(); + Map groupEntityMap = IMGroupManager.instance().getGroupMap(); + HashSet topList = ConfigurationSp.instance(ctx,loginId).getSessionTopList(); + + + for(SessionEntity recentSession:sessionList){ + int sessionType = recentSession.getPeerType(); + int peerId = recentSession.getPeerId(); + String sessionKey = recentSession.getSessionKey(); + + UnreadEntity unreadEntity = unreadMsgMap.get(sessionKey); + if(sessionType == DBConstant.SESSION_TYPE_GROUP){ + GroupEntity groupEntity = groupEntityMap.get(peerId); + RecentInfo recentInfo = new RecentInfo(recentSession,groupEntity,unreadEntity); + if(topList !=null && topList.contains(sessionKey)){ + recentInfo.setTop(true); + } + + //谁说的这条信息,只有群组需要,例如 【XXX:您好】 + int lastFromId = recentSession.getTalkId(); + UserEntity talkUser = userMap.get(lastFromId); + // 用户已经不存在了 + if(talkUser !=null){ + String oriContent = recentInfo.getLatestMsgData(); + String finalContent = talkUser.getMainName() + ": "+oriContent; + recentInfo.setLatestMsgData(finalContent); + } + recentSessionList.add(recentInfo); + }else if(sessionType == DBConstant.SESSION_TYPE_SINGLE){ + UserEntity userEntity = userMap.get(peerId); + RecentInfo recentInfo = new RecentInfo(recentSession,userEntity,unreadEntity); + if(topList !=null && topList.contains(sessionKey)){ + recentInfo.setTop(true); + } + recentSessionList.add(recentInfo); + } + } + sort(recentSessionList); + return recentSessionList; + } + + + public SessionEntity findSession(String sessionKey){ + if(sessionMap.size()<=0 || TextUtils.isEmpty(sessionKey)){return null;} + if(sessionMap.containsKey(sessionKey)){ + return sessionMap.get(sessionKey); + } + return null; + } + + public PeerEntity findPeerEntity(String sessionKey){ + if(TextUtils.isEmpty(sessionKey)){ + return null; + } + // 拆分 + PeerEntity peerEntity; + String[] sessionInfo = EntityChangeEngine.spiltSessionKey(sessionKey); + int peerType = Integer.parseInt(sessionInfo[0]); + int peerId = Integer.parseInt(sessionInfo[1]); + switch (peerType){ + case DBConstant.SESSION_TYPE_SINGLE:{ + peerEntity = IMContactManager.instance().findContact(peerId); + }break; + case DBConstant.SESSION_TYPE_GROUP:{ + peerEntity = IMGroupManager.instance().findGroup(peerId); + }break; + default: + throw new IllegalArgumentException("findPeerEntity#peerType is illegal,cause by " +peerType); + } + return peerEntity; + } + + /**------------------------实体的get set-----------------------------*/ + public boolean isSessionListReady() { + return sessionListReady; + } + + public void setSessionListReady(boolean sessionListReady) { + this.sessionListReady = sessionListReady; + } +} diff --git a/android/app/src/main/java/com/mogujie/tt/imservice/manager/IMSocketManager.java b/android/app/src/main/java/com/mogujie/tt/imservice/manager/IMSocketManager.java new file mode 100644 index 000000000..548c8c384 --- /dev/null +++ b/android/app/src/main/java/com/mogujie/tt/imservice/manager/IMSocketManager.java @@ -0,0 +1,369 @@ +package com.mogujie.tt.imservice.manager; + +import android.content.Context; +import android.os.PowerManager; +import android.text.TextUtils; + +import com.google.protobuf.CodedInputStream; +import com.google.protobuf.GeneratedMessageLite; +import com.loopj.android.http.AsyncHttpClient; +import com.loopj.android.http.BaseJsonHttpResponseHandler; +import com.mogujie.tt.DB.sp.SystemConfigSp; +import com.mogujie.tt.config.SysConstant; +import com.mogujie.tt.config.UrlConstant; +import com.mogujie.tt.imservice.callback.ListenerQueue; +import com.mogujie.tt.imservice.callback.Packetlistener; +import com.mogujie.tt.imservice.event.SocketEvent; +import com.mogujie.tt.imservice.network.MsgServerHandler; +import com.mogujie.tt.imservice.network.SocketThread; +import com.mogujie.tt.protobuf.IMBaseDefine; +import com.mogujie.tt.protobuf.IMOther; +import com.mogujie.tt.protobuf.base.DataBuffer; +import com.mogujie.tt.protobuf.base.DefaultHeader; +import com.mogujie.tt.utils.Logger; + +import org.apache.http.Header; +import org.jboss.netty.buffer.ChannelBuffer; +import org.jboss.netty.buffer.ChannelBufferInputStream; +import org.json.JSONException; +import org.json.JSONObject; + +import de.greenrobot.event.EventBus; + +/** + * @author : yingmu on 14-12-30. + * @email : yingmu@mogujie.com. + * + * 业务层面: + * 长连接建立成功之后,就要发送登陆信息,否则15s之内就会断开 + * 所以connMsg 与 login是强耦合的关系 + */ +public class IMSocketManager extends IMManager { + + private Logger logger = Logger.getLogger(IMSocketManager.class); + private static IMSocketManager inst = new IMSocketManager(); + + public static IMSocketManager instance() { + return inst; + } + + public IMSocketManager() { + logger.d("login#creating IMSocketManager"); + } + + private ListenerQueue listenerQueue = ListenerQueue.instance(); + + // 请求消息服务器地址 + private AsyncHttpClient client = new AsyncHttpClient(); + + /**底层socket*/ + private SocketThread msgServerThread; + + /**快速重新连接的时候需要*/ + private MsgServerAddrsEntity currentMsgAddress = null; + + /**自身状态 */ + private SocketEvent socketStatus = SocketEvent.NONE; + + /** + * 获取Msg地址,等待链接 + */ + @Override + public void doOnStart() { + socketStatus = SocketEvent.NONE; + } + + + //todo check + @Override + public void reset() { + disconnectMsgServer(); + socketStatus = SocketEvent.NONE; + currentMsgAddress = null; + } + + /** + * 实现自身的事件驱动 + * @param event + */ + public void triggerEvent(SocketEvent event) { + setSocketStatus(event); + EventBus.getDefault().postSticky(event); + } + + /**-------------------------------功能方法--------------------------------------*/ + + public void sendRequest(GeneratedMessageLite requset,int sid,int cid){ + sendRequest(requset,sid,cid,null); + } + + + /** + * todo check exception + * */ + public void sendRequest(GeneratedMessageLite requset,int sid,int cid,Packetlistener packetlistener){ + int seqNo = 0; + try{ + //组装包头 header + com.mogujie.tt.protobuf.base.Header header = new DefaultHeader(sid, cid); + int bodySize = requset.getSerializedSize(); + header.setLength(SysConstant.PROTOCOL_HEADER_LENGTH + bodySize); + seqNo = header.getSeqnum(); + listenerQueue.push(seqNo,packetlistener); + boolean sendRes = msgServerThread.sendRequest(requset,header); + }catch (Exception e){ + if(packetlistener !=null){ + packetlistener.onFaild(); + } + listenerQueue.pop(seqNo); + logger.e("#sendRequest#channel is close!"); + } + } + + public void packetDispatch(ChannelBuffer channelBuffer){ + DataBuffer buffer = new DataBuffer(channelBuffer); + com.mogujie.tt.protobuf.base.Header header = new com.mogujie.tt.protobuf.base.Header(); + header.decode(buffer); + /**buffer 的指针位于body的地方*/ + int commandId = header.getCommandId(); + int serviceId = header.getServiceId(); + int seqNo = header.getSeqnum(); + logger.d("dispatch packet, serviceId:%d, commandId:%d", serviceId, + commandId); + CodedInputStream codedInputStream = CodedInputStream.newInstance(new ChannelBufferInputStream(buffer.getOrignalBuffer())); + + Packetlistener listener = listenerQueue.pop(seqNo); + if(listener!=null){ + listener.onSuccess(codedInputStream); + return; + } + + // todo eric make it a table + // 抽象 父类执行 + switch (serviceId){ + case IMBaseDefine.ServiceID.SID_LOGIN_VALUE: + IMPacketDispatcher.loginPacketDispatcher(commandId,codedInputStream); + break; + case IMBaseDefine.ServiceID.SID_BUDDY_LIST_VALUE: + IMPacketDispatcher.buddyPacketDispatcher(commandId,codedInputStream); + break; + case IMBaseDefine.ServiceID.SID_MSG_VALUE: + IMPacketDispatcher.msgPacketDispatcher(commandId,codedInputStream); + break; + case IMBaseDefine.ServiceID.SID_GROUP_VALUE: + IMPacketDispatcher.groupPacketDispatcher(commandId,codedInputStream); + break; + default: + logger.e("packet#unhandled serviceId:%d, commandId:%d", serviceId, + commandId); + break; + } + } + + + + /** + * 新版本流程如下 + 1.客户端通过域名获得login_server的地址 + 2.客户端通过login_server获得msg_serv的地址 + 3.客户端带着用户名密码对msg_serv进行登录 + 4.msg_serv转给db_proxy进行认证(do not care on client) + 5.将认证结果返回给客户端 + */ + public void reqMsgServerAddrs() { + logger.d("socket#reqMsgServerAddrs."); + client.setUserAgent("Android-TT"); + client.get(SystemConfigSp.instance().getStrConfig(SystemConfigSp.SysCfgDimension.LOGINSERVER), new BaseJsonHttpResponseHandler(){ + @Override + public void onSuccess(int i, Header[] headers, String s, Object o) { + logger.d("socket#req msgAddress onSuccess, response:%s", s); + MsgServerAddrsEntity msgServer = (MsgServerAddrsEntity) o; + if(msgServer == null){ + triggerEvent(SocketEvent.REQ_MSG_SERVER_ADDRS_FAILED); + return; + } + connectMsgServer(msgServer); + triggerEvent(SocketEvent.REQ_MSG_SERVER_ADDRS_SUCCESS); + } + + @Override + public void onFailure(int i, Header[] headers, Throwable throwable, String responseString, Object o) { + logger.d("socket#req msgAddress Failure, errorResponse:%s", responseString); + triggerEvent(SocketEvent.REQ_MSG_SERVER_ADDRS_FAILED); + } + + @Override + protected Object parseResponse(String s, boolean b) throws Throwable { + /*子类需要提供实现,将请求结果解析成需要的类型 异常怎么处理*/ + JSONObject jsonObject = new JSONObject(s); + MsgServerAddrsEntity msgServerAddrsEntity = onRepLoginServerAddrs(jsonObject); + return msgServerAddrsEntity; + } + }); + } + + /** + * 与登陆login是强耦合的关系 + */ + private void connectMsgServer(MsgServerAddrsEntity currentMsgAddress) { + triggerEvent(SocketEvent.CONNECTING_MSG_SERVER); + this.currentMsgAddress = currentMsgAddress; + + String priorIP = currentMsgAddress.priorIP; + int port = currentMsgAddress.port; + logger.i("login#connectMsgServer -> (%s:%d)",priorIP, port); + + //check again,may be unimportance + if (msgServerThread != null) { + msgServerThread.close(); + msgServerThread = null; + } + + msgServerThread = new SocketThread(priorIP, port,new MsgServerHandler()); + msgServerThread.start(); + } + + public void reconnectMsg(){ + synchronized (IMSocketManager.class) { + if (currentMsgAddress != null) { + connectMsgServer(currentMsgAddress); + } else { + disconnectMsgServer(); + IMLoginManager.instance().relogin(); + } + } + } + + /** + * 断开与msg的链接 + */ + public void disconnectMsgServer() { + listenerQueue.onDestory(); + logger.i("login#disconnectMsgServer"); + if (msgServerThread != null) { + msgServerThread.close(); + msgServerThread = null; + logger.i("login#do real disconnectMsgServer ok"); + } + } + + /**判断链接是否处于断开状态*/ + public boolean isSocketConnect(){ + if(msgServerThread == null || msgServerThread.isClose()){ + return false; + } + return true; + } + + public void onMsgServerConnected() { + logger.i("login#onMsgServerConnected"); + listenerQueue.onStart(); + triggerEvent(SocketEvent.CONNECT_MSG_SERVER_SUCCESS); + IMLoginManager.instance().reqLoginMsgServer(); + } + + /** + * 1. kickout 被踢出会触发这个状态 -- 不需要重连 + * 2. 心跳包没有收到 会触发这个状态 -- 链接断开,重连 + * 3. 链接主动断开 -- 重连 + * 之前的长连接状态 connected + */ + // 先断开链接 + // only 2 threads(ui thread, network thread) would request sending packet + // let the ui thread to close the connection + // so if the ui thread has a sending task, no synchronization issue + public void onMsgServerDisconn(){ + logger.w("login#onMsgServerDisconn"); + disconnectMsgServer(); + triggerEvent(SocketEvent.MSG_SERVER_DISCONNECTED); + } + + /** 之前没有连接成功*/ + public void onConnectMsgServerFail(){ + triggerEvent(SocketEvent.CONNECT_MSG_SERVER_FAILED); + } + + + /**----------------------------请求Msg server地址--实体信息--------------------------------------*/ + /**请求返回的数据*/ + private class MsgServerAddrsEntity { + int code; + String msg; + String priorIP; + String backupIP; + int port; + @Override + public String toString() { + return "LoginServerAddrsEntity{" + + "code=" + code + + ", msg='" + msg + '\'' + + ", priorIP='" + priorIP + '\'' + + ", backupIP='" + backupIP + '\'' + + ", port=" + port + + '}'; + } + } + + private MsgServerAddrsEntity onRepLoginServerAddrs(JSONObject json) + throws JSONException { + + logger.d("login#onRepLoginServerAddrs"); + + if (json == null) { + logger.e("login#json is null"); + return null; + } + + logger.d("login#onRepLoginServerAddrs json:%s", json); + + int code = json.getInt("code"); + if (code != 0) { + logger.e("login#code is not right:%d, json:%s", code, json); + return null; + } + + String priorIP = json.getString("priorIP"); + String backupIP = json.getString("backupIP"); + int port = json.getInt("port"); + + if(json.has("msfsPrior")) + { + String msfsPrior = json.getString("msfsPrior"); + String msfsBackup = json.getString("msfsBackup"); + if(!TextUtils.isEmpty(msfsPrior)) + { + SystemConfigSp.instance().setStrConfig(SystemConfigSp.SysCfgDimension.MSFSSERVER,msfsPrior); + } + else + { + SystemConfigSp.instance().setStrConfig(SystemConfigSp.SysCfgDimension.MSFSSERVER,msfsBackup); + } + } + + if(json.has("discovery")) + { + String discoveryUrl = json.getString("discovery"); + if(!TextUtils.isEmpty(discoveryUrl)) + { + SystemConfigSp.instance().init(ctx.getApplicationContext()); + SystemConfigSp.instance().setStrConfig(SystemConfigSp.SysCfgDimension.DISCOVERYURI,discoveryUrl); + } + } + + MsgServerAddrsEntity addrsEntity = new MsgServerAddrsEntity(); + addrsEntity.priorIP = priorIP; + addrsEntity.backupIP = backupIP; + addrsEntity.port = port; + logger.d("login#got loginserverAddrsEntity:%s", addrsEntity); + return addrsEntity; + } + + /**------------get/set----------------------------*/ + public SocketEvent getSocketStatus() { + return socketStatus; + } + + public void setSocketStatus(SocketEvent socketStatus) { + this.socketStatus = socketStatus; + } +} diff --git a/android/app/src/main/java/com/mogujie/tt/imservice/manager/IMStackManager.java b/android/app/src/main/java/com/mogujie/tt/imservice/manager/IMStackManager.java new file mode 100644 index 000000000..89ab0383b --- /dev/null +++ b/android/app/src/main/java/com/mogujie/tt/imservice/manager/IMStackManager.java @@ -0,0 +1,88 @@ +package com.mogujie.tt.imservice.manager; + +import android.app.Activity; + +/** + * Created by zhujian on 15/1/23. + */ +public class IMStackManager { + /** + * Stack 中对应的Activity列表 (也可以写做 Stack) + */ + private static java.util.Stack mActivityStack; + private static IMStackManager mInstance; + + /** + * @描述 获取栈管理工具 + * @return ActivityManager + */ + public static IMStackManager getStackManager() { + if (mInstance == null) { + mInstance = new IMStackManager(); + } + return mInstance; + } + + /** + * 推出栈顶Activity + */ + public void popActivity(Activity activity) { + if (activity != null) { + activity.finish(); + mActivityStack.remove(activity); + activity = null; + } + } + + /** + * 获得当前栈顶Activity + */ + public Activity currentActivity() { + //lastElement()获取最后个子元素,这里是栈顶的Activity + if(mActivityStack == null || mActivityStack.size() ==0){ + return null; + } + Activity activity = (Activity) mActivityStack.lastElement(); + return activity; + } + + /** + * 将当前Activity推入栈中 + */ + public void pushActivity(Activity activity) { + if (mActivityStack == null) { + mActivityStack = new java.util.Stack(); + } + mActivityStack.add(activity); + } + + /** + * 弹出指定的clsss所在栈顶部的中所有Activity + * @clsss : 指定的类 + */ + public void popTopActivitys(Class clsss) { + while (true) { + Activity activity = currentActivity(); + if (activity == null) { + break; + } + if (activity.getClass().equals(clsss)) { + break; + } + popActivity(activity); + } + } + + /** + * 弹出栈中所有Activity + */ + public void popAllActivitys() { + while (true) { + Activity activity = currentActivity(); + if (activity == null) { + break; + } + popActivity(activity); + } + } +} diff --git a/android/app/src/main/java/com/mogujie/tt/imservice/manager/IMUnreadMsgManager.java b/android/app/src/main/java/com/mogujie/tt/imservice/manager/IMUnreadMsgManager.java new file mode 100644 index 000000000..87e2c06c7 --- /dev/null +++ b/android/app/src/main/java/com/mogujie/tt/imservice/manager/IMUnreadMsgManager.java @@ -0,0 +1,299 @@ +package com.mogujie.tt.imservice.manager; + + +import android.app.NotificationManager; +import android.content.Context; +import android.text.TextUtils; + +import com.mogujie.tt.config.DBConstant; +import com.mogujie.tt.DB.entity.GroupEntity; +import com.mogujie.tt.DB.entity.MessageEntity; +import com.mogujie.tt.imservice.entity.UnreadEntity; +import com.mogujie.tt.imservice.event.UnreadEvent; +import com.mogujie.tt.protobuf.helper.EntityChangeEngine; +import com.mogujie.tt.protobuf.helper.Java2ProtoBuf; +import com.mogujie.tt.protobuf.helper.ProtoBuf2JavaBean; +import com.mogujie.tt.protobuf.IMBaseDefine; +import com.mogujie.tt.protobuf.IMMessage; +import com.mogujie.tt.utils.Logger; + +import java.io.StringBufferInputStream; +import java.util.List; +import java.util.concurrent.ConcurrentHashMap; + +import de.greenrobot.event.EventBus; + +/** + * 未读消息相关的处理,归属于messageEvent中 + * 可以理解为MessageManager的又一次拆分 + * 为session提供未读支持。 + * DB 中不保存 + */ +public class IMUnreadMsgManager extends IMManager { + private Logger logger = Logger.getLogger(IMUnreadMsgManager.class); + private static IMUnreadMsgManager inst = new IMUnreadMsgManager(); + public static IMUnreadMsgManager instance() { + return inst; + } + + private IMSocketManager imSocketManager = IMSocketManager.instance(); + private IMLoginManager loginManager =IMLoginManager.instance(); + + /**key=> sessionKey*/ + private ConcurrentHashMap unreadMsgMap = new ConcurrentHashMap<>(); + private int totalUnreadCount = 0; + + private boolean unreadListReady = false; + + @Override + public void doOnStart() {} + + + // 未读消息控制器,本地是不存状态的 + public void onNormalLoginOk(){ + unreadMsgMap.clear(); + reqUnreadMsgContactList(); + } + + public void onLocalNetOk(){ + unreadMsgMap.clear(); + reqUnreadMsgContactList(); + } + + @Override + public void reset() { + unreadListReady = false; + unreadMsgMap.clear(); + } + + /** + * 继承该方法实现自身的事件驱动 + * @param event + */ + public synchronized void triggerEvent(UnreadEvent event) { + switch (event.event){ + case UNREAD_MSG_LIST_OK: + unreadListReady = true; + break; + } + + EventBus.getDefault().post(event); + } + + /**-------------------------------分割线----------------------------------*/ + /** + * 请求未读消息列表 + */ + private void reqUnreadMsgContactList() { + logger.i("unread#1reqUnreadMsgContactList"); + int loginId = IMLoginManager.instance().getLoginId(); + IMMessage.IMUnreadMsgCntReq unreadMsgCntReq = IMMessage.IMUnreadMsgCntReq + .newBuilder() + .setUserId(loginId) + .build(); + int sid = IMBaseDefine.ServiceID.SID_MSG_VALUE; + int cid = IMBaseDefine.MessageCmdID.CID_MSG_UNREAD_CNT_REQUEST_VALUE; + imSocketManager.sendRequest(unreadMsgCntReq,sid,cid); + } + + public void onRepUnreadMsgContactList(IMMessage.IMUnreadMsgCntRsp unreadMsgCntRsp) { + logger.i("unread#2onRepUnreadMsgContactList"); + totalUnreadCount = unreadMsgCntRsp.getTotalCnt(); + List unreadInfoList = unreadMsgCntRsp.getUnreadinfoListList(); + logger.i("unread#unreadMsgCnt:%d, unreadMsgInfoCnt:%d",unreadInfoList.size(),totalUnreadCount); + + for(IMBaseDefine.UnreadInfo unreadInfo:unreadInfoList){ + UnreadEntity unreadEntity = ProtoBuf2JavaBean.getUnreadEntity(unreadInfo); + //屏蔽的设定 + addIsForbidden(unreadEntity); + unreadMsgMap.put(unreadEntity.getSessionKey(), unreadEntity); + } + triggerEvent(new UnreadEvent(UnreadEvent.Event.UNREAD_MSG_LIST_OK)); + } + + /** + * 回话是否已经被设定为屏蔽 + * @param unreadEntity + */ + private void addIsForbidden(UnreadEntity unreadEntity){ + if(unreadEntity.getSessionType() == DBConstant.SESSION_TYPE_GROUP){ + GroupEntity groupEntity= IMGroupManager.instance().findGroup(unreadEntity.getPeerId()); + if(groupEntity !=null && groupEntity.getStatus() == DBConstant.GROUP_STATUS_SHIELD){ + unreadEntity.setForbidden(true); + } + } + } + + /**设定未读回话为屏蔽回话 仅限于群组 todo*/ + public void setForbidden(String sessionKey,boolean isFor){ + UnreadEntity unreadEntity = unreadMsgMap.get(sessionKey); + if(unreadEntity !=null){ + unreadEntity.setForbidden(isFor); + } + } + + public void add(MessageEntity msg) { + //更新session list中的msg信息 + //更新未读消息计数 + if(msg == null){ + logger.d("unread#unreadMgr#add msg is null!"); + return; + } + // isFirst场景:出现一条未读消息,出现小红点,需要触发 [免打扰的情况下] + boolean isFirst = false; + logger.d("unread#unreadMgr#add unread msg:%s", msg); + UnreadEntity unreadEntity; + int loginId = IMLoginManager.instance().getLoginId(); + String sessionKey = msg.getSessionKey(); + boolean isSend = msg.isSend(loginId); + if(isSend){ + IMNotificationManager.instance().cancelSessionNotifications(sessionKey); + return; + } + + if(unreadMsgMap.containsKey(sessionKey)){ + unreadEntity = unreadMsgMap.get(sessionKey); + // 判断最后一条msgId是否相同 + if(unreadEntity.getLaststMsgId() == msg.getMsgId()){ + return; + } + unreadEntity.setUnReadCnt(unreadEntity.getUnReadCnt()+1); + }else{ + isFirst = true; + unreadEntity = new UnreadEntity(); + unreadEntity.setUnReadCnt(1); + unreadEntity.setPeerId(msg.getPeerId(isSend)); + unreadEntity.setSessionType(msg.getSessionType()); + unreadEntity.buildSessionKey(); + } + + unreadEntity.setLatestMsgData(msg.getMessageDisplay()); + unreadEntity.setLaststMsgId(msg.getMsgId()); + addIsForbidden(unreadEntity); + + /**放入manager 状态中*/ + unreadMsgMap.put(unreadEntity.getSessionKey(),unreadEntity); + + /**没有被屏蔽才会发送广播*/ + if(!unreadEntity.isForbidden() || isFirst) { + UnreadEvent unreadEvent = new UnreadEvent(); + unreadEvent.event = UnreadEvent.Event.UNREAD_MSG_RECEIVED; + unreadEvent.entity = unreadEntity; + triggerEvent(unreadEvent); + } + } + + public void ackReadMsg(MessageEntity entity){ + logger.d("chat#ackReadMsg -> msg:%s", entity); + int loginId = loginManager.getLoginId(); + IMBaseDefine.SessionType sessionType = Java2ProtoBuf.getProtoSessionType(entity.getSessionType()); + IMMessage.IMMsgDataReadAck readAck = IMMessage.IMMsgDataReadAck.newBuilder() + .setMsgId(entity.getMsgId()) + .setSessionId(entity.getPeerId(false)) + .setSessionType(sessionType) + .setUserId(loginId) + .build(); + int sid = IMBaseDefine.ServiceID.SID_MSG_VALUE; + int cid = IMBaseDefine.MessageCmdID.CID_MSG_READ_ACK_VALUE; + imSocketManager.sendRequest(readAck,sid,cid); + } + + public void ackReadMsg(UnreadEntity unreadEntity){ + logger.d("chat#ackReadMsg -> msg:%s", unreadEntity); + int loginId = loginManager.getLoginId(); + IMBaseDefine.SessionType sessionType = Java2ProtoBuf.getProtoSessionType(unreadEntity.getSessionType()); + IMMessage.IMMsgDataReadAck readAck = IMMessage.IMMsgDataReadAck.newBuilder() + .setMsgId(unreadEntity.getLaststMsgId()) + .setSessionId(unreadEntity.getPeerId()) + .setSessionType(sessionType) + .setUserId(loginId) + .build(); + int sid = IMBaseDefine.ServiceID.SID_MSG_VALUE; + int cid = IMBaseDefine.MessageCmdID.CID_MSG_READ_ACK_VALUE; + imSocketManager.sendRequest(readAck,sid,cid); + } + + + /** + * 服务端主动发送已读通知 + * @param readNotify + */ + public void onNotifyRead(IMMessage.IMMsgDataReadNotify readNotify){ + logger.d("chat#onNotifyRead"); + //发送此信令的用户id + int trigerId = readNotify.getUserId(); + int loginId = IMLoginManager.instance().getLoginId(); + if(trigerId != loginId){ + logger.i("onNotifyRead# trigerId:%s,loginId:%s not Equal",trigerId,loginId); + return ; + } + //现在的逻辑是msgId之后的 全部都是已读的 + // 不做复杂判断了,简单处理 + int msgId = readNotify.getMsgId(); + int peerId = readNotify.getSessionId(); + int sessionType = ProtoBuf2JavaBean.getJavaSessionType(readNotify.getSessionType()); + String sessionKey = EntityChangeEngine.getSessionKey(peerId,sessionType); + + // 通知栏也要去除掉 + NotificationManager notifyMgr = (NotificationManager) ctx.getSystemService(Context.NOTIFICATION_SERVICE); + if (notifyMgr == null) { + return; + } + int notificationId = IMNotificationManager.instance().getSessionNotificationId(sessionKey); + notifyMgr.cancel(notificationId); + + UnreadEntity unreadSession = findUnread(sessionKey); + if(unreadSession!=null && unreadSession.getLaststMsgId() <= msgId){ + // 清空会话session + logger.d("chat#onNotifyRead# unreadSession onLoginOut"); + readUnreadSession(sessionKey); + } + } + + /** + * 备注: 先获取最后一条消息 + * 1. 清除回话内的未读计数 + * 2. 发送最后一条msgId的已读确认 + * @param sessionKey + */ + public void readUnreadSession(String sessionKey){ + logger.d("unread#readUnreadSession# sessionKey:%s", sessionKey); + if(unreadMsgMap.containsKey(sessionKey)){ + UnreadEntity entity = unreadMsgMap.remove(sessionKey); + ackReadMsg(entity); + triggerEvent(new UnreadEvent(UnreadEvent.Event.SESSION_READED_UNREAD_MSG)); + } + } + + + public UnreadEntity findUnread(String sessionKey){ + logger.d("unread#findUnread# buddyId:%s", sessionKey); + if(TextUtils.isEmpty(sessionKey) || unreadMsgMap.size()<=0){ + logger.i("unread#findUnread# no unread info"); + return null; + } + if(unreadMsgMap.containsKey(sessionKey)){ + return unreadMsgMap.get(sessionKey); + } + return null; + } + + /**----------------实体set/get-------------------------------*/ + public ConcurrentHashMap getUnreadMsgMap() { + return unreadMsgMap; + } + + public int getTotalUnreadCount() { + int count = 0; + for(UnreadEntity entity:unreadMsgMap.values()){ + if(!entity.isForbidden()){ + count = count + entity.getUnReadCnt(); + } + } + return count; + } + + public boolean isUnreadListReady() { + return unreadListReady; + } +} diff --git a/android/app/src/main/java/com/mogujie/tt/imservice/network/MsgServerHandler.java b/android/app/src/main/java/com/mogujie/tt/imservice/network/MsgServerHandler.java new file mode 100644 index 000000000..eac0660d8 --- /dev/null +++ b/android/app/src/main/java/com/mogujie/tt/imservice/network/MsgServerHandler.java @@ -0,0 +1,70 @@ +package com.mogujie.tt.imservice.network; + +import com.mogujie.tt.imservice.manager.IMHeartBeatManager; +import com.mogujie.tt.imservice.manager.IMSocketManager; +import com.mogujie.tt.utils.Logger; + +import org.jboss.netty.buffer.ChannelBuffer; +import org.jboss.netty.channel.ChannelHandlerContext; +import org.jboss.netty.channel.ChannelStateEvent; +import org.jboss.netty.channel.ExceptionEvent; +import org.jboss.netty.channel.MessageEvent; +import org.jboss.netty.channel.SimpleChannelHandler; + +public class MsgServerHandler extends SimpleChannelHandler { + + private Logger logger = Logger.getLogger(MsgServerHandler.class); + + @Override + public void channelConnected(ChannelHandlerContext ctx, ChannelStateEvent e) + throws Exception { + super.channelConnected(ctx, e); + logger.d("channel#channelConnected"); + IMSocketManager.instance().onMsgServerConnected(); + } + + @Override + public void channelDisconnected(ChannelHandlerContext ctx, + ChannelStateEvent e) throws Exception { + /** + * 1. 已经与远程主机建立的连接,远程主机主动关闭连接,或者网络异常连接被断开的情况 + 2. 已经与远程主机建立的连接,本地客户机主动关闭连接的情况 + 3. 本地客户机在试图与远程主机建立连接时,遇到类似与connection refused这样的异常,未能连接成功时 + 而只有当本地客户机已经成功的与远程主机建立连接(connected)时,连接断开的时候才会触发channelDisconnected事件,即对应上述的1和2两种情况。 + * + **/ + logger.d("channel#channelDisconnected"); + super.channelDisconnected(ctx, e); + IMSocketManager.instance().onMsgServerDisconn(); + IMHeartBeatManager.instance().onMsgServerDisconn(); + // 断线了,先尝试重连。统一入口,否则会产生循环锁 + //IMReconnectManager.instance().tryReconnect(); + } + + @Override + public void messageReceived(ChannelHandlerContext ctx, MessageEvent e) + throws Exception { + super.messageReceived(ctx, e); + logger.d("channel#messageReceived"); + // 重置AlarmManager的时间 + ChannelBuffer channelBuffer = (ChannelBuffer) e.getMessage(); + if(null!=channelBuffer) + IMSocketManager.instance().packetDispatch(channelBuffer); + } + + /** + * bug问题点: + * exceptionCaught会调用断开链接, channelDisconnected 也会调用断开链接,事件通知冗余不合理。 + * a.另外exceptionCaught 之后channelDisconnected 依旧会被调用。 [切花网络方式] + * b.关闭channel 也可能触发exceptionCaught + * recvfrom failed: ETIMEDOUT (Connection timed out) 没有关闭长连接 + * */ + @Override + public void exceptionCaught(ChannelHandlerContext ctx, ExceptionEvent e) throws Exception { + super.exceptionCaught(ctx, e); + if(e.getChannel() == null || !e.getChannel().isConnected()){ + IMSocketManager.instance().onConnectMsgServerFail(); + } + logger.e("channel#[网络异常了]exceptionCaught:%s", e.getCause().toString()); + } +} diff --git a/android/app/src/main/java/com/mogujie/tt/imservice/network/SocketThread.java b/android/app/src/main/java/com/mogujie/tt/imservice/network/SocketThread.java new file mode 100644 index 000000000..e160d8d98 --- /dev/null +++ b/android/app/src/main/java/com/mogujie/tt/imservice/network/SocketThread.java @@ -0,0 +1,165 @@ +package com.mogujie.tt.imservice.network; + +import com.google.protobuf.GeneratedMessageLite; +import com.mogujie.tt.config.SysConstant; +import com.mogujie.tt.protobuf.base.DataBuffer; +import com.mogujie.tt.protobuf.base.Header; +import com.mogujie.tt.utils.Logger; + +import org.jboss.netty.bootstrap.ClientBootstrap; +import org.jboss.netty.channel.Channel; +import org.jboss.netty.channel.ChannelFactory; +import org.jboss.netty.channel.ChannelFuture; +import org.jboss.netty.channel.ChannelPipeline; +import org.jboss.netty.channel.ChannelPipelineFactory; +import org.jboss.netty.channel.Channels; +import org.jboss.netty.channel.SimpleChannelHandler; +import org.jboss.netty.channel.socket.nio.NioClientSocketChannelFactory; +import org.jboss.netty.handler.codec.frame.LengthFieldBasedFrameDecoder; +import org.jboss.netty.handler.timeout.IdleStateHandler; +import org.jboss.netty.util.HashedWheelTimer; + +import java.net.InetSocketAddress; +import java.util.concurrent.Executors; +import java.util.concurrent.TimeUnit; + +public class SocketThread extends Thread { + private ClientBootstrap clientBootstrap = null; + private ChannelFactory channelFactory = null; + private ChannelFuture channelFuture = null; + private Channel channel = null; + private String strHost = null; + private int nPort = 0; + private static Logger logger = Logger.getLogger(SocketThread.class); + + public SocketThread(String strHost, int nPort, SimpleChannelHandler handler) { + this.strHost = strHost; + this.nPort = nPort; + init(handler); + } + + @Override + public void run() { + doConnect(); + } + + private void init(final SimpleChannelHandler handler) { + // only one IO thread + channelFactory = new NioClientSocketChannelFactory( + Executors.newSingleThreadExecutor(), + Executors.newSingleThreadExecutor()); + + clientBootstrap = new ClientBootstrap(channelFactory); + clientBootstrap.setOption("connectTimeoutMillis", 5000); + clientBootstrap.setPipelineFactory(new ChannelPipelineFactory() { + + public ChannelPipeline getPipeline() throws Exception { + ChannelPipeline pipeline = Channels.pipeline(); + // 接收的数据包解码 + pipeline.addLast("decoder", new LengthFieldBasedFrameDecoder( + 400 * 1024, 0, 4, -4, 0)); + // 发送的数据包编码 + //pipeline.addLast("encoder", new PacketEncoder()); + // 具体的业务处理,这个handler只负责接收数据,并传递给dispatcher + pipeline.addLast("handler", handler); + return pipeline; + + } + + }); + + clientBootstrap.setOption("tcpNoDelay", true); + clientBootstrap.setOption("keepAlive", true); + // clientBootstrap.setOption("keepIdle", 20); + // clientBootstrap.setOption("keepInterval", 5); + // clientBootstrap.setOption("keepCount", 3); + } + + public boolean doConnect() { + try { + if ((null == channel || (null != channel && !channel.isConnected())) + && null != this.strHost && this.nPort > 0) { + // Start the connection attempt. + channelFuture = clientBootstrap.connect(new InetSocketAddress( + strHost, nPort)); + // Wait until the connection attempt succeeds or fails. + channel = channelFuture.awaitUninterruptibly().getChannel(); + if (!channelFuture.isSuccess()) { + channelFuture.getCause().printStackTrace(); + clientBootstrap.releaseExternalResources(); + // ReconnectManager.getInstance().setOnRecconnecting(false); + // ReconnectManager.getInstance().setLogining(false); + return false; + } + } + + // Wait until the connection is closed or the connection attemp + // fails. + channelFuture.getChannel().getCloseFuture().awaitUninterruptibly(); + // Shut down thread pools to exit. + clientBootstrap.releaseExternalResources(); + return true; + + } catch (Exception e) { + logger.e("do connect failed. e: %s", e.getStackTrace().toString()); + return false; + } + } + + public Channel getChannel() { + return channel; + } + + public void close() { + if (null == channelFuture) + return; + if (null != channelFuture.getChannel()) { + channelFuture.getChannel().close(); + } + channelFuture.cancel(); + } + + + // todo check + @Deprecated + public boolean isClose(){ + if(channelFuture != null && channelFuture.getChannel() != null){ + return !channelFuture.getChannel().isConnected(); + } + return true; + } + + /** + * @param requset + * @param header + * @return + */ + public boolean sendRequest(GeneratedMessageLite requset,Header header){ + DataBuffer headerBuffer = header.encode(); + DataBuffer bodyBuffer = new DataBuffer(); + int bodySize = requset.getSerializedSize(); + bodyBuffer.writeBytes(requset.toByteArray()); + + + DataBuffer buffer = new DataBuffer(SysConstant.PROTOCOL_HEADER_LENGTH + bodySize); + buffer.writeDataBuffer(headerBuffer); + buffer.writeDataBuffer(bodyBuffer); + + if (null != buffer && null != channelFuture.getChannel()) { + /**底层的状态要提前判断,netty抛出的异常上层catch不到*/ + Channel currentChannel = channelFuture.getChannel(); + boolean isW = currentChannel.isWritable(); + boolean isC = currentChannel.isConnected(); + if(!(isW && isC)){ + throw new RuntimeException("#sendRequest#channel is close!"); + } + channelFuture.getChannel().write(buffer.getOrignalBuffer()); + logger.d("packet#send ok"); + return true; + } else { + logger.e("packet#send failed"); + return false; + } + } + +} diff --git a/android/app/src/main/java/com/mogujie/tt/imservice/service/IMService.java b/android/app/src/main/java/com/mogujie/tt/imservice/service/IMService.java new file mode 100644 index 000000000..55d8219cf --- /dev/null +++ b/android/app/src/main/java/com/mogujie/tt/imservice/service/IMService.java @@ -0,0 +1,284 @@ +package com.mogujie.tt.imservice.service; + +import android.app.Notification; +import android.app.Service; +import android.content.Context; +import android.content.Intent; +import android.os.Binder; +import android.os.IBinder; + +import com.mogujie.tt.DB.DBInterface; +import com.mogujie.tt.DB.entity.MessageEntity; +import com.mogujie.tt.DB.sp.ConfigurationSp; +import com.mogujie.tt.DB.sp.LoginSp; +import com.mogujie.tt.config.SysConstant; +import com.mogujie.tt.imservice.event.LoginEvent; +import com.mogujie.tt.imservice.event.PriorityEvent; +import com.mogujie.tt.imservice.manager.IMContactManager; +import com.mogujie.tt.imservice.manager.IMGroupManager; +import com.mogujie.tt.imservice.manager.IMHeartBeatManager; +import com.mogujie.tt.imservice.manager.IMLoginManager; +import com.mogujie.tt.imservice.manager.IMMessageManager; +import com.mogujie.tt.imservice.manager.IMNotificationManager; +import com.mogujie.tt.imservice.manager.IMReconnectManager; +import com.mogujie.tt.imservice.manager.IMSessionManager; +import com.mogujie.tt.imservice.manager.IMSocketManager; +import com.mogujie.tt.imservice.manager.IMUnreadMsgManager; +import com.mogujie.tt.utils.ImageLoaderUtil; +import com.mogujie.tt.utils.Logger; + +import de.greenrobot.event.EventBus; + +/** + * IMService 负责所有IMManager的初始化与reset + * 并且Manager的状态的改变 也会影响到IMService的操作 + * 备注: 有些服务应该在LOGIN_OK 之后进行 + * todo IMManager reflect or just like ctx.getSystemService() + */ +public class IMService extends Service { + private Logger logger = Logger.getLogger(IMService.class); + + /**binder*/ + private IMServiceBinder binder = new IMServiceBinder(); + public class IMServiceBinder extends Binder { + public IMService getService() { + return IMService.this; + } + } + + @Override + public IBinder onBind(Intent arg0) { + logger.i("IMService onBind"); + return binder; + } + + //所有的管理类 + private IMSocketManager socketMgr = IMSocketManager.instance(); + private IMLoginManager loginMgr = IMLoginManager.instance(); + private IMContactManager contactMgr = IMContactManager.instance(); + private IMGroupManager groupMgr = IMGroupManager.instance(); + private IMMessageManager messageMgr = IMMessageManager.instance(); + private IMSessionManager sessionMgr = IMSessionManager.instance(); + private IMReconnectManager reconnectMgr = IMReconnectManager.instance(); + private IMUnreadMsgManager unReadMsgMgr = IMUnreadMsgManager.instance(); + private IMNotificationManager notificationMgr = IMNotificationManager.instance(); + private IMHeartBeatManager heartBeatManager = IMHeartBeatManager.instance(); + + private ConfigurationSp configSp; + private LoginSp loginSp = LoginSp.instance(); + private DBInterface dbInterface = DBInterface.instance(); + + @Override + public void onCreate() { + logger.i("IMService onCreate"); + super.onCreate(); + EventBus.getDefault().register(this, SysConstant.SERVICE_EVENTBUS_PRIORITY); + // make the service foreground, so stop "360 yi jian qingli"(a clean + // tool) to stop our app + // todo eric study wechat's mechanism, use a better solution + startForeground((int) System.currentTimeMillis(), new Notification()); + } + + @Override + public void onDestroy() { + logger.i("IMService onDestroy"); + // todo 在onCreate中使用startForeground + // 在这个地方是否执行 stopForeground呐 + EventBus.getDefault().unregister(this); + handleLoginout(); + // DB的资源的释放 + dbInterface.close(); + + IMNotificationManager.instance().cancelAllNotifications(); + super.onDestroy(); + } + + /**收到消息需要上层的activity判断 {MessageActicity onEvent(PriorityEvent event)},这个地方是特殊分支*/ + public void onEvent(PriorityEvent event){ + switch (event.event){ + case MSG_RECEIVED_MESSAGE:{ + MessageEntity entity = (MessageEntity) event.object; + /**非当前的会话*/ + logger.d("messageactivity#not this session msg -> id:%s", entity.getFromId()); + messageMgr.ackReceiveMsg(entity); + unReadMsgMgr.add(entity); + }break; + } + } + + // EventBus 事件驱动 + public void onEvent(LoginEvent event){ + switch (event){ + case LOGIN_OK: + onNormalLoginOk();break; + case LOCAL_LOGIN_SUCCESS: + onLocalLoginOk(); + break; + case LOCAL_LOGIN_MSG_SERVICE: + onLocalNetOk(); + break; + case LOGIN_OUT: + handleLoginout();break; + } + } + + // 负责初始化 每个manager + @Override + public int onStartCommand(Intent intent, int flags, int startId) { + logger.i("IMService onStartCommand"); + //应用开启初始化 下面这几个怎么释放 todo + Context ctx = getApplicationContext(); + loginSp.init(ctx); + // 放在这里还有些问题 todo + socketMgr.onStartIMManager(ctx); + loginMgr.onStartIMManager(ctx); + contactMgr.onStartIMManager(ctx); + messageMgr.onStartIMManager(ctx); + groupMgr.onStartIMManager(ctx); + sessionMgr.onStartIMManager(ctx); + unReadMsgMgr.onStartIMManager(ctx); + notificationMgr.onStartIMManager(ctx); + reconnectMgr.onStartIMManager(ctx); + heartBeatManager.onStartIMManager(ctx); + + ImageLoaderUtil.initImageLoaderConfig(ctx); + return START_STICKY; + } + + + /** + * 用户输入登陆流程 + * userName/pwd -> reqMessage ->connect -> loginMessage ->loginSuccess + */ + private void onNormalLoginOk() { + logger.d("imservice#onLogin Successful"); + //初始化其他manager todo 这个地方注意上下文的清除 + Context ctx = getApplicationContext(); + int loginId = loginMgr.getLoginId(); + configSp = ConfigurationSp.instance(ctx,loginId); + dbInterface.initDbHelp(ctx,loginId); + + contactMgr.onNormalLoginOk(); + sessionMgr.onNormalLoginOk(); + groupMgr.onNormalLoginOk(); + unReadMsgMgr.onNormalLoginOk(); + + reconnectMgr.onNormalLoginOk(); + //依赖的状态比较特殊 + messageMgr.onLoginSuccess(); + notificationMgr.onLoginSuccess(); + heartBeatManager.onloginNetSuccess(); + // 这个时候loginManage中的localLogin 被置为true + } + + + /** + * 自动登陆/离线登陆成功 + * autoLogin -> DB(loginInfo,loginId...) -> loginSucsess + */ + private void onLocalLoginOk(){ + Context ctx = getApplicationContext(); + int loginId = loginMgr.getLoginId(); + configSp = ConfigurationSp.instance(ctx,loginId); + dbInterface.initDbHelp(ctx,loginId); + + contactMgr.onLocalLoginOk(); + groupMgr.onLocalLoginOk(); + sessionMgr.onLocalLoginOk(); + reconnectMgr.onLocalLoginOk(); + notificationMgr.onLoginSuccess(); + messageMgr.onLoginSuccess(); + } + + /** + * 1.从本机加载成功之后,请求MessageService建立链接成功(loginMessageSuccess) + * 2. 重练成功之后 + */ + private void onLocalNetOk(){ + /**为了防止逗比直接把loginId与userName的对应直接改了,重刷一遍*/ + Context ctx = getApplicationContext(); + int loginId = loginMgr.getLoginId(); + configSp = ConfigurationSp.instance(ctx,loginId); + dbInterface.initDbHelp(ctx,loginId); + + contactMgr.onLocalNetOk(); + groupMgr.onLocalNetOk(); + sessionMgr.onLocalNetOk(); + unReadMsgMgr.onLocalNetOk(); + reconnectMgr.onLocalNetOk(); + heartBeatManager.onloginNetSuccess(); + } + + private void handleLoginout() { + logger.d("imservice#handleLoginout"); + + // login需要监听socket的变化,在这个地方不能释放,设计上的不合理? + socketMgr.reset(); + loginMgr.reset(); + contactMgr.reset(); + messageMgr.reset(); + groupMgr.reset(); + sessionMgr.reset(); + unReadMsgMgr.reset(); + notificationMgr.reset(); + reconnectMgr.reset(); + heartBeatManager.reset(); + configSp = null; + EventBus.getDefault().removeAllStickyEvents(); + } + + @Override + public void onTaskRemoved(Intent rootIntent) { + logger.d("imservice#onTaskRemoved"); + // super.onTaskRemoved(rootIntent); + this.stopSelf(); + } + + /**-----------------get/set 的实体定义---------------------*/ + public IMLoginManager getLoginManager() { + return loginMgr; + } + + public IMContactManager getContactManager() { + return contactMgr; + } + + public IMMessageManager getMessageManager() { + return messageMgr; + } + + + public IMGroupManager getGroupManager() { + return groupMgr; + } + + public IMSessionManager getSessionManager() { + return sessionMgr; + } + + public IMReconnectManager getReconnectManager() { + return reconnectMgr; + } + + + public IMUnreadMsgManager getUnReadMsgManager() { + return unReadMsgMgr; + } + + public IMNotificationManager getNotificationManager() { + return notificationMgr; + } + + public DBInterface getDbInterface() { + return dbInterface; + } + + public ConfigurationSp getConfigSp() { + return configSp; + } + + public LoginSp getLoginSp() { + return loginSp; + } + +} diff --git a/android/app/src/main/java/com/mogujie/tt/imservice/service/LoadImageService.java b/android/app/src/main/java/com/mogujie/tt/imservice/service/LoadImageService.java new file mode 100644 index 000000000..b55dd90cc --- /dev/null +++ b/android/app/src/main/java/com/mogujie/tt/imservice/service/LoadImageService.java @@ -0,0 +1,91 @@ +package com.mogujie.tt.imservice.service; + +import android.app.IntentService; +import android.content.Intent; +import android.graphics.Bitmap; +import android.text.TextUtils; + +import com.mogujie.tt.DB.sp.SystemConfigSp; +import com.mogujie.tt.config.SysConstant; +import com.mogujie.tt.config.UrlConstant; +import com.mogujie.tt.imservice.entity.ImageMessage; +import com.mogujie.tt.imservice.event.MessageEvent; +import com.mogujie.tt.ui.helper.PhotoHelper; +import com.mogujie.tt.utils.FileUtil; +import com.mogujie.tt.utils.MoGuHttpClient; +import com.mogujie.tt.utils.Logger; + +import java.io.File; +import java.io.IOException; + +import de.greenrobot.event.EventBus; + +/** + * @author : yingmu on 15-1-12. + * @email : yingmu@mogujie.com. + * + */ +public class LoadImageService extends IntentService { + + private static Logger logger = Logger.getLogger(LoadImageService.class); + + public LoadImageService(){ + super("LoadImageService"); + } + + public LoadImageService(String name) { + super(name); + } + + /** + * This method is invoked on the worker thread with a request to process. + * Only one Intent is processed at a time, but the processing happens on a + * worker thread that runs independently from other application logic. + * So, if this code takes a long time, it will hold up other requests to + * the same IntentService, but it will not hold up anything else. + * When all requests have been handled, the IntentService stops itself, + * so you should not call {@link #stopSelf}. + * + * @param intent The value passed to {@link + * android.content.Context#startService(android.content.Intent)}. + */ + @Override + protected void onHandleIntent(Intent intent) { + ImageMessage messageInfo = (ImageMessage)intent.getSerializableExtra(SysConstant.UPLOAD_IMAGE_INTENT_PARAMS); + String result = null; + Bitmap bitmap; + try { + File file= new File(messageInfo.getPath()); + if(file.exists() && FileUtil.getExtensionName(messageInfo.getPath()).toLowerCase().equals(".gif")) + { + MoGuHttpClient httpClient = new MoGuHttpClient(); + SystemConfigSp.instance().init(getApplicationContext()); + result = httpClient.uploadImage3(SystemConfigSp.instance().getStrConfig(SystemConfigSp.SysCfgDimension.MSFSSERVER), FileUtil.File2byte(messageInfo.getPath()), messageInfo.getPath()); + } + else + { + bitmap = PhotoHelper.revitionImage(messageInfo.getPath()); + if (null != bitmap) { + MoGuHttpClient httpClient = new MoGuHttpClient(); + byte[] bytes = PhotoHelper.getBytes(bitmap); + result = httpClient.uploadImage3(SystemConfigSp.instance().getStrConfig(SystemConfigSp.SysCfgDimension.MSFSSERVER), bytes, messageInfo.getPath()); + } + } + + if (TextUtils.isEmpty(result)) { + logger.i("upload image faild,cause by result is empty/null"); + EventBus.getDefault().post(new MessageEvent(MessageEvent.Event.IMAGE_UPLOAD_FAILD + ,messageInfo)); + } else { + logger.i("upload image succcess,imageUrl is %s",result); + String imageUrl = result; + messageInfo.setUrl(imageUrl); + EventBus.getDefault().post(new MessageEvent( + MessageEvent.Event.IMAGE_UPLOAD_SUCCESS + ,messageInfo)); + } + } catch (IOException e) { + logger.e(e.getMessage()); + } + } +} diff --git a/android/app/src/main/java/com/mogujie/tt/imservice/service/PushReceiver.java b/android/app/src/main/java/com/mogujie/tt/imservice/service/PushReceiver.java new file mode 100644 index 000000000..ab51b6aad --- /dev/null +++ b/android/app/src/main/java/com/mogujie/tt/imservice/service/PushReceiver.java @@ -0,0 +1,26 @@ +//package com.mogujie.tt.imv2.service; +// +//import android.content.BroadcastReceiver; +//import android.content.Context; +//import android.content.Intent; +//import android.os.Bundle; +// +////import com.mogujie.sdk.PushConsts; +////import com.mogujie.sdk.PushManager; +// +//public class PushReceiver extends BroadcastReceiver { +// public PushReceiver() { +// } +// +// @Override +// public void onReceive(Context context, Intent intent) { +// +//// String action = intent.getAction(); +//// Bundle bundle = intent.getBundleExtra(PushConsts.MESSAGE_BUNDLE); +//// int message_id = bundle.getInt(PushConsts.MESSAGE_ID); +//// String message_data = new String(bundle.getByteArray(PushConsts.MESSAGE_DATA)); +//// String app_id = new String(bundle.getByteArray(PushConsts.APP_ID)); +//// PushManager.getInstance().readMessage(message_id); +// +// } +//} diff --git a/android/app/src/main/java/com/mogujie/tt/imservice/support/IMServiceConnector.java b/android/app/src/main/java/com/mogujie/tt/imservice/support/IMServiceConnector.java new file mode 100644 index 000000000..da4495437 --- /dev/null +++ b/android/app/src/main/java/com/mogujie/tt/imservice/support/IMServiceConnector.java @@ -0,0 +1,95 @@ +package com.mogujie.tt.imservice.support; + +import android.content.ComponentName; +import android.content.Context; +import android.content.Intent; +import android.content.ServiceConnection; +import android.os.IBinder; + +import com.mogujie.tt.imservice.service.IMService; +import com.mogujie.tt.imservice.service.IMService.IMServiceBinder; +import com.mogujie.tt.utils.Logger; + +/** + * IMService绑定 + * @modify yingmu + * 1. 供上层使用【activity】 + * 同层次的manager没有必要使用。 + */ +public abstract class IMServiceConnector { + protected static Logger logger = Logger.getLogger(IMServiceConnector.class); + + public abstract void onIMServiceConnected(); + public abstract void onServiceDisconnected(); + + private IMService imService; + public IMService getIMService() { + return imService; + } + + // todo eric when to release? + private ServiceConnection imServiceConnection = new ServiceConnection() { + + @Override + public void onServiceDisconnected(ComponentName name) { + // todo eric when to unbind the service? + // TODO Auto-generated method stub + logger.i("onService(imService)Disconnected"); + IMServiceConnector.this.onServiceDisconnected(); + } + + @Override + public void onServiceConnected(ComponentName name, IBinder service) { + // TODO Auto-generated method stub + logger.i("im#onService(imService)Connected"); + + if (imService == null) { + IMServiceBinder binder = (IMServiceBinder) service; + imService = binder.getService(); + + if (imService == null) { + logger.e("im#get imService failed"); + return; + } + logger.d("im#get imService ok"); + } + IMServiceConnector.this.onIMServiceConnected(); + } + }; + + public boolean connect(Context ctx) { + return bindService(ctx); + } + + public void disconnect(Context ctx) { + logger.d("im#disconnect"); + unbindService(ctx); + IMServiceConnector.this.onServiceDisconnected(); + } + + public boolean bindService(Context ctx) { + logger.d("im#bindService"); + + Intent intent = new Intent(); + intent.setClass(ctx, IMService.class); + + if (!ctx.bindService(intent, imServiceConnection, android.content.Context.BIND_AUTO_CREATE)) { + logger.e("im#bindService(imService) failed"); + return false; + } else { + logger.i("im#bindService(imService) ok"); + return true; + } + } + + public void unbindService(Context ctx) { + try { + // todo eric .check the return value .check the right place to call it + ctx.unbindService(imServiceConnection); + } catch (IllegalArgumentException exception) { + logger.w("im#got exception becuase of unmatched bind/unbind, we sould place to onStop next version.e:%s", exception.getMessage()); + } + logger.i("unbindservice ok"); + } + +} diff --git a/android/app/src/main/java/com/mogujie/tt/imservice/support/SequenceNumberMaker.java b/android/app/src/main/java/com/mogujie/tt/imservice/support/SequenceNumberMaker.java new file mode 100644 index 000000000..8a36ce52d --- /dev/null +++ b/android/app/src/main/java/com/mogujie/tt/imservice/support/SequenceNumberMaker.java @@ -0,0 +1,59 @@ + +package com.mogujie.tt.imservice.support; + +/** + * 1.专门用来分配序列号 + * 2. 本地消息的唯一msgId键值 + * todo can use AtomicInteger + */ +public class SequenceNumberMaker { + + private volatile short mSquence = 0; + + private volatile long preMsgId = 0; + + private static SequenceNumberMaker maker = new SequenceNumberMaker(); + + private SequenceNumberMaker() { + } + + public static SequenceNumberMaker getInstance() { + return maker; + } + + public short make() { + synchronized (this) { + mSquence++; + if (mSquence >= Short.MAX_VALUE) + mSquence = 1; + } + return mSquence; + } + + /**依旧比较 Ugly 的解决办法 + * 多线程情况下,生成相同的msgId + * */ + public int makelocalUniqueMsgId(){ + synchronized(SequenceNumberMaker.this) { + int timeStamp = (int) (System.currentTimeMillis() % 10000000); + int localId = timeStamp + 90000000; + //logger.e("#yingmu2#之前的msgId:%d",preMsgId); + if (localId == preMsgId) { + localId++; + if (localId >= 100000000) { + localId = 90000000; + } + } + preMsgId = localId; + return localId; + } + } + + /**比较 Ugly 的解决办法,但是比较实用*/ + public boolean isFailure(int msgId){ + if(msgId>=90000000){ + return true; + } + return false; + } +} diff --git a/android/app/src/main/java/com/mogujie/tt/imservice/support/audio/AudioFileWriter.java b/android/app/src/main/java/com/mogujie/tt/imservice/support/audio/AudioFileWriter.java new file mode 100644 index 000000000..1ba384810 --- /dev/null +++ b/android/app/src/main/java/com/mogujie/tt/imservice/support/audio/AudioFileWriter.java @@ -0,0 +1,384 @@ +/****************************************************************************** + * * + * Copyright (c) 1999-2004 Wimba S.A., All Rights Reserved. * + * * + * COPYRIGHT: * + * This software is the property of Wimba S.A. * + * This software is redistributed under the Xiph.org variant of * + * the BSD license. * + * Redistribution and use in source and binary forms, with or without * + * modification, are permitted provided that the following conditions * + * are met: * + * - Redistributions of source code must retain the above copyright * + * notice, this list of conditions and the following disclaimer. * + * - Redistributions in binary form must reproduce the above copyright * + * notice, this list of conditions and the following disclaimer in the * + * documentation and/or other materials provided with the distribution. * + * - Neither the name of Wimba, the Xiph.org Foundation nor the names of * + * its contributors may be used to endorse or promote products derived * + * from this software without specific prior written permission. * + * * + * WARRANTIES: * + * This software is made available by the authors in the hope * + * that it will be useful, but without any warranty. * + * Wimba S.A. is not liable for any consequence related to the * + * use of the provided software. * + * * + * Class: RawWriter.java * + * * + * Author: Marc GIMPEL * + * * + * Date: 6th January 2004 * + * * + ******************************************************************************/ + +/* $Id: AudioFileWriter.java,v 1.1 2011/12/27 04:39:13 gauss Exp $ */ + +package com.mogujie.tt.imservice.support.audio; + +import java.io.DataOutput; +import java.io.File; +import java.io.IOException; +import java.io.OutputStream; + +/** + * Abstract Class that defines an Audio File Writer. + * + * @author Marc Gimpel, Wimba S.A. (mgimpel@horizonwimba.com) + * @version $Revision: 1.1 $ + */ +public abstract class AudioFileWriter +{ + /** + * Closes the output file. + * + * @exception IOException if there was an exception closing the Audio + * Writer. + */ + public abstract void close() + throws IOException; + + /** + * Open the output file. + * + * @param file - file to open. + * @exception IOException if there was an exception opening the Audio + * Writer. + */ + public abstract void open(File file) + throws IOException; + + /** + * Open the output file. + * + * @param filename - file to open. + * @exception IOException if there was an exception opening the Audio + * Writer. + */ + public abstract void open(String filename) + throws IOException; + + /** + * Writes the header pages that start the Ogg Speex file. Prepares file for + * data to be written. + * + * @param comment description to be included in the header. + * @exception IOException + */ + public abstract void writeHeader(String comment) + throws IOException; + + /** + * Writes a packet of audio. + * + * @param data audio data + * @param offset the offset from which to start reading the data. + * @param len the length of data to read. + * @exception IOException + */ + public abstract void writePacket(byte[] data, int offset, int len) + throws IOException; + + /** + * Writes an Ogg Page Header to the given byte array. + * + * @param buf the buffer to write to. + * @param offset the from which to start writing. + * @param headerType the header type flag (0=normal, 2=bos: beginning of + * stream, 4=eos: end of stream). + * @param granulepos the absolute granule position. + * @param streamSerialNumber + * @param pageCount + * @param packetCount + * @param packetSizes + * @return the amount of data written to the buffer. + */ + public static int writeOggPageHeader(byte[] buf, int offset, int headerType, + long granulepos, int streamSerialNumber, + int pageCount, int packetCount, + byte[] packetSizes) + { + writeString(buf, offset, "OggS"); // 0 - 3: capture_pattern + buf[offset + 4] = 0; // 4: stream_structure_version + buf[offset + 5] = (byte) headerType; // 5: header_type_flag + writeLong(buf, offset + 6, granulepos); // 6 - 13: absolute granule + // position + writeInt(buf, offset + 14, streamSerialNumber); // 14 - 17: stream + // serial number + writeInt(buf, offset + 18, pageCount); // 18 - 21: page sequence no + writeInt(buf, offset + 22, 0); // 22 - 25: page checksum + buf[offset + 26] = (byte) packetCount; // 26: page_segments + System.arraycopy(packetSizes, 0, // 27 - x: segment_table + buf, offset + 27, packetCount); + return packetCount + 27; + } + + /** + * Builds and returns an Ogg Page Header. + * + * @param headerType the header type flag (0=normal, 2=bos: beginning of + * stream, 4=eos: end of stream). + * @param granulepos the absolute granule position. + * @param streamSerialNumber + * @param pageCount + * @param packetCount + * @param packetSizes + * @return an Ogg Page Header. + */ + public static byte[] buildOggPageHeader(int headerType, long granulepos, + int streamSerialNumber, int pageCount, + int packetCount, byte[] packetSizes) + { + byte[] data = new byte[packetCount + 27]; + writeOggPageHeader(data, 0, headerType, granulepos, streamSerialNumber, + pageCount, packetCount, packetSizes); + return data; + } + + /** + * Writes a Speex Header to the given byte array. + * + * @param buf the buffer to write to. + * @param offset the from which to start writing. + * @param sampleRate + * @param mode + * @param channels + * @param vbr + * @param nframes + * @return the amount of data written to the buffer. + */ + public static int writeSpeexHeader(byte[] buf, int offset, int sampleRate, + int mode, int channels, boolean vbr, + int nframes) + { + writeString(buf, offset, "Speex "); // 0 - 7: speex_string + writeString(buf, offset + 8, "speex-1.2rc"); // 8 - 27: speex_version + System.arraycopy(new byte[11], 0, buf, offset + 17, 11); // : + // speex_version + // (fill in up + // to 20 bytes) + writeInt(buf, offset + 28, 1); // 28 - 31: speex_version_id + writeInt(buf, offset + 32, 80); // 32 - 35: header_size + writeInt(buf, offset + 36, sampleRate); // 36 - 39: rate + writeInt(buf, offset + 40, mode); // 40 - 43: mode (0=NB, 1=WB, 2=UWB) + writeInt(buf, offset + 44, 4); // 44 - 47: mode_bitstream_version + writeInt(buf, offset + 48, channels); // 48 - 51: nb_channels + writeInt(buf, offset + 52, -1); // 52 - 55: bitrate + writeInt(buf, offset + 56, 160 << mode); // 56 - 59: frame_size (NB=160, + // WB=320, UWB=640) + writeInt(buf, offset + 60, vbr ? 1 : 0); // 60 - 63: vbr + writeInt(buf, offset + 64, nframes); // 64 - 67: frames_per_packet + writeInt(buf, offset + 68, 0); // 68 - 71: extra_headers + writeInt(buf, offset + 72, 0); // 72 - 75: reserved1 + writeInt(buf, offset + 76, 0); // 76 - 79: reserved2 + return 80; + } + + /** + * Builds a Speex Header. + * + * @param sampleRate + * @param mode + * @param channels + * @param vbr + * @param nframes + * @return a Speex Header. + */ + public static byte[] buildSpeexHeader(int sampleRate, int mode, int channels, + boolean vbr, int nframes) + { + byte[] data = new byte[80]; + writeSpeexHeader(data, 0, sampleRate, mode, channels, vbr, nframes); + return data; + } + + /** + * Writes a Speex Comment to the given byte array. + * + * @param buf the buffer to write to. + * @param offset the from which to start writing. + * @param comment the comment. + * @return the amount of data written to the buffer. + */ + public static int writeSpeexComment(byte[] buf, int offset, String comment) + { + int length = comment.length(); + writeInt(buf, offset, length); // vendor comment size + writeString(buf, offset + 4, comment); // vendor comment + writeInt(buf, offset + length + 4, 0); // user comment list length + return length + 8; + } + + /** + * Builds and returns a Speex Comment. + * + * @param comment the comment. + * @return a Speex Comment. + */ + public static byte[] buildSpeexComment(String comment) + { + byte[] data = new byte[comment.length() + 8]; + writeSpeexComment(data, 0, comment); + return data; + } + + /** + * Writes a Little-endian short. + * + * @param out the data output to write to. + * @param v value to write. + * @exception IOException + */ + public static void writeShort(DataOutput out, short v) + throws IOException + { + out.writeByte((0xff & v)); + out.writeByte((0xff & (v >>> 8))); + } + + /** + * Writes a Little-endian int. + * + * @param out the data output to write to. + * @param v value to write. + * @exception IOException + */ + public static void writeInt(DataOutput out, int v) + throws IOException + { + out.writeByte(0xff & v); + out.writeByte(0xff & (v >>> 8)); + out.writeByte(0xff & (v >>> 16)); + out.writeByte(0xff & (v >>> 24)); + } + + /** + * Writes a Little-endian short. + * + * @param os - the output stream to write to. + * @param v - the value to write. + * @exception IOException + */ + public static void writeShort(OutputStream os, short v) + throws IOException + { + os.write((0xff & v)); + os.write((0xff & (v >>> 8))); + } + + /** + * Writes a Little-endian int. + * + * @param os - the output stream to write to. + * @param v - the value to write. + * @exception IOException + */ + public static void writeInt(OutputStream os, int v) + throws IOException + { + os.write(0xff & v); + os.write(0xff & (v >>> 8)); + os.write(0xff & (v >>> 16)); + os.write(0xff & (v >>> 24)); + } + + /** + * Writes a Little-endian long. + * + * @param os - the output stream to write to. + * @param v - the value to write. + * @exception IOException + */ + public static void writeLong(OutputStream os, long v) + throws IOException + { + os.write((int) (0xff & v)); + os.write((int) (0xff & (v >>> 8))); + os.write((int) (0xff & (v >>> 16))); + os.write((int) (0xff & (v >>> 24))); + os.write((int) (0xff & (v >>> 32))); + os.write((int) (0xff & (v >>> 40))); + os.write((int) (0xff & (v >>> 48))); + os.write((int) (0xff & (v >>> 56))); + } + + /** + * Writes a Little-endian short. + * + * @param data the array into which the data should be written. + * @param offset the offset from which to start writing in the array. + * @param v the value to write. + */ + public static void writeShort(byte[] data, int offset, int v) + { + data[offset] = (byte) (0xff & v); + data[offset + 1] = (byte) (0xff & (v >>> 8)); + } + + /** + * Writes a Little-endian int. + * + * @param data the array into which the data should be written. + * @param offset the offset from which to start writing in the array. + * @param v the value to write. + */ + public static void writeInt(byte[] data, int offset, int v) + { + data[offset] = (byte) (0xff & v); + data[offset + 1] = (byte) (0xff & (v >>> 8)); + data[offset + 2] = (byte) (0xff & (v >>> 16)); + data[offset + 3] = (byte) (0xff & (v >>> 24)); + } + + /** + * Writes a Little-endian long. + * + * @param data the array into which the data should be written. + * @param offset the offset from which to start writing in the array. + * @param v the value to write. + */ + public static void writeLong(byte[] data, int offset, long v) + { + data[offset] = (byte) (0xff & v); + data[offset + 1] = (byte) (0xff & (v >>> 8)); + data[offset + 2] = (byte) (0xff & (v >>> 16)); + data[offset + 3] = (byte) (0xff & (v >>> 24)); + data[offset + 4] = (byte) (0xff & (v >>> 32)); + data[offset + 5] = (byte) (0xff & (v >>> 40)); + data[offset + 6] = (byte) (0xff & (v >>> 48)); + data[offset + 7] = (byte) (0xff & (v >>> 56)); + } + + /** + * Writes a String. + * + * @param data the array into which the data should be written. + * @param offset the offset from which to start writing in the array. + * @param v the value to write. + */ + public static void writeString(byte[] data, int offset, String v) + { + byte[] str = v.getBytes(); + System.arraycopy(str, 0, data, offset, str.length); + } +} diff --git a/android/app/src/main/java/com/mogujie/tt/imservice/support/audio/OggCrc.java b/android/app/src/main/java/com/mogujie/tt/imservice/support/audio/OggCrc.java new file mode 100644 index 000000000..ab74aca58 --- /dev/null +++ b/android/app/src/main/java/com/mogujie/tt/imservice/support/audio/OggCrc.java @@ -0,0 +1,126 @@ +/****************************************************************************** + * * + * Copyright (c) 1999-2003 Wimba S.A., All Rights Reserved. * + * * + * COPYRIGHT: * + * This software is the property of Wimba S.A. * + * This software is redistributed under the Xiph.org variant of * + * the BSD license. * + * Redistribution and use in source and binary forms, with or without * + * modification, are permitted provided that the following conditions * + * are met: * + * - Redistributions of source code must retain the above copyright * + * notice, this list of conditions and the following disclaimer. * + * - Redistributions in binary form must reproduce the above copyright * + * notice, this list of conditions and the following disclaimer in the * + * documentation and/or other materials provided with the distribution. * + * - Neither the name of Wimba, the Xiph.org Foundation nor the names of * + * its contributors may be used to endorse or promote products derived * + * from this software without specific prior written permission. * + * * + * WARRANTIES: * + * This software is made available by the authors in the hope * + * that it will be useful, but without any warranty. * + * Wimba S.A. is not liable for any consequence related to the * + * use of the provided software. * + * * + * Class: OggCrc.java * + * * + * Author: Marc GIMPEL * + * Based on code by: Ross WILLIAMS * + * * + * Date: 20th April 2003 * + * * + ******************************************************************************/ + +/* $Id: OggCrc.java,v 1.1 2011/12/27 04:39:13 gauss Exp $ */ + +/******************************************************************** + * * + * THIS FILE IS PART OF THE OggVorbis SOFTWARE CODEC SOURCE CODE. * + * USE, DISTRIBUTION AND REPRODUCTION OF THIS LIBRARY SOURCE IS * + * GOVERNED BY A BSD-STYLE SOURCE LICENSE INCLUDED WITH THIS SOURCE * + * IN 'COPYING'. PLEASE READ THESE TERMS BEFORE DISTRIBUTING. * + * * + * THE OggVorbis SOURCE CODE IS (C) COPYRIGHT 1994-2002 * + * by the Xiph.Org Foundation http://www.xiph.org/ * + * * + ******************************************************************** + + function: code raw [Vorbis] packets into framed OggSquish stream and + decode Ogg streams back into raw packets + last mod: $Id: OggCrc.java,v 1.1 2011/12/27 04:39:13 gauss Exp $ + + note: The CRC code is directly derived from public domain code by + Ross Williams (ross@guest.adelaide.edu.au). See docs/framing.html + for details. + + ********************************************************************/ + +package com.mogujie.tt.imservice.support.audio; + +/** + * Calculates the CRC checksum for Ogg packets. + *

+ * Ogg uses the same generator polynomial as ethernet, although with an + * unreflected alg and an init/final of 0, not 0xffffffff. + * + * @author Jim Lawrence, helloNetwork.com + * @author Marc Gimpel, Wimba S.A. (mgimpel@horizonwimba.com) + * @version $Revision: 1.1 $ + */ +public class OggCrc +{ + // TODO - implement java.util.zip.Checksum + + /** + * CRC checksum lookup table + */ + private static int[] crc_lookup; + + static { + crc_lookup = new int[256]; + for (int i = 0; i < crc_lookup.length; i++) { + int r = i << 24; + for (int j = 0; j < 8; j++) { + if ((r & 0x80000000) != 0) { + /* + * The same as the ethernet generator polynomial, although + * we use an unreflected alg and an init/final of 0, not + * 0xffffffff + */ + r = (r << 1) ^ 0x04c11db7; + } + else { + r <<= 1; + } + } + crc_lookup[i] = (r & 0xffffffff); + } + } + + /** + * Calculates the checksum on the given data, from the give offset and for + * the given length, using the given initial value. This allows on to + * calculate the checksum iteratively, by reinjecting the last returned + * value as the initial value when the function is called for the next data + * chunk. The initial value should be 0 for the first iteration. + * + * @param crc - the initial value + * @param data - the data + * @param offset - the offset at which to start calculating the checksum. + * @param length - the length of data over which to calculate the checksum. + * @return the checksum. + */ + public static int checksum(int crc, + final byte[] data, + int offset, + final int length) + { + int end = offset + length; + for (; offset < end; offset++) { + crc = (crc << 8) ^ crc_lookup[((crc >>> 24) & 0xff) ^ (data[offset] & 0xff)]; + } + return crc; + } +} diff --git a/android/app/src/main/java/com/mogujie/tt/imservice/support/audio/OggSpeexWriter.java b/android/app/src/main/java/com/mogujie/tt/imservice/support/audio/OggSpeexWriter.java new file mode 100644 index 000000000..c2df31fb3 --- /dev/null +++ b/android/app/src/main/java/com/mogujie/tt/imservice/support/audio/OggSpeexWriter.java @@ -0,0 +1,260 @@ +/****************************************************************************** + * * + * Copyright (c) 1999-2003 Wimba S.A., All Rights Reserved. * + * * + * COPYRIGHT: * + * This software is the property of Wimba S.A. * + * This software is redistributed under the Xiph.org variant of * + * the BSD license. * + * Redistribution and use in source and binary forms, with or without * + * modification, are permitted provided that the following conditions * + * are met: * + * - Redistributions of source code must retain the above copyright * + * notice, this list of conditions and the following disclaimer. * + * - Redistributions in binary form must reproduce the above copyright * + * notice, this list of conditions and the following disclaimer in the * + * documentation and/or other materials provided with the distribution. * + * - Neither the name of Wimba, the Xiph.org Foundation nor the names of * + * its contributors may be used to endorse or promote products derived * + * from this software without specific prior written permission. * + * * + * WARRANTIES: * + * This software is made available by the authors in the hope * + * that it will be useful, but without any warranty. * + * Wimba S.A. is not liable for any consequence related to the * + * use of the provided software. * + * * + * Class: OggSpeexWriter.java * + * * + * Author: Marc GIMPEL * + * * + * Date: 9th April 2003 * + * * + ******************************************************************************/ + +/* $Id: OggSpeexWriter.java,v 1.2 2011/12/28 02:45:11 gauss Exp $ */ + +package com.mogujie.tt.imservice.support.audio; + +import com.mogujie.tt.utils.Logger; + +import java.io.File; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.OutputStream; +import java.util.Random; + +/** + * Ogg Speex Writer + * + * @author Marc Gimpel, Wimba S.A. (mgimpel@horizonwimba.com) + * @version $Revision: 1.2 $ + */ +public class OggSpeexWriter extends AudioFileWriter { + private static Logger log = Logger.getLogger(OggSpeexWriter.class); + /** Number of packets in an Ogg page (must be less than 255) */ + public static final int PACKETS_PER_OGG_PAGE = 250; + + /** The OutputStream */ + private OutputStream out; + + /** Defines the encoder mode (0=NB, 1=WB and 2-UWB). */ + private int mode; + /** Defines the sampling rate of the audio input. */ + private int sampleRate; + /** Defines the number of channels of the audio input (1=mono, 2=stereo). */ + private int channels; + /** Defines the number of frames per speex packet. */ + private int nframes; + /** Defines whether or not to use VBR (Variable Bit Rate). */ + private boolean vbr; + + /** Ogg Stream Serial Number */ + private int streamSerialNumber; + /** Data buffer */ + private byte[] dataBuffer; + /** Pointer within the Data buffer */ + private int dataBufferPtr; + /** Header buffer */ + private byte[] headerBuffer; + /** Pointer within the Header buffer */ + private int headerBufferPtr; + /** Ogg Page count */ + private int pageCount; + /** Speex packet count within an Ogg Page */ + private int packetCount; + /** + * Absolute granule position (the number of audio samples from beginning of + * file to end of Ogg Packet). + */ + private long granulepos; + + /** + * Builds an Ogg Speex Writer. + */ + public OggSpeexWriter() { + if (streamSerialNumber == 0) + streamSerialNumber = new Random().nextInt(); + dataBuffer = new byte[65565]; + dataBufferPtr = 0; + headerBuffer = new byte[255]; + headerBufferPtr = 0; + pageCount = 0; + packetCount = 0; + granulepos = 0; + } + + /** + * Builds an Ogg Speex Writer. + * + * @param mode the mode of the encoder (0=NB, 1=WB, 2=UWB). + * @param sampleRate the number of samples per second. + * @param channels the number of audio channels (1=mono, 2=stereo, ...). + * @param nframes the number of frames per speex packet. + * @param vbr + */ + public OggSpeexWriter(final int mode, final int sampleRate, final int channels, + final int nframes, final boolean vbr) { + this(); + setFormat(mode, sampleRate, channels, nframes, vbr); + } + + /** + * Sets the output format. Must be called before WriteHeader(). + * + * @param mode the mode of the encoder (0=NB, 1=WB, 2=UWB). + * @param sampleRate the number of samples per second. + * @param channels the number of audio channels (1=mono, 2=stereo, ...). + * @param nframes the number of frames per speex packet. + * @param vbr + */ + private void setFormat(final int mode, final int sampleRate, final int channels, + final int nframes, boolean vbr) { + this.mode = mode; + this.sampleRate = sampleRate; + this.channels = channels; + this.nframes = nframes; + this.vbr = vbr; + } + + /** + * Sets the Stream Serial Number. Must not be changed mid stream. + * + * @param serialNumber + */ + public void setSerialNumber(final int serialNumber) { + this.streamSerialNumber = serialNumber; + } + + /** + * Closes the output file. + * + * @exception IOException if there was an exception closing the Audio + * Writer. + */ + public void close() throws IOException { + flush(true); + out.close(); + } + + /** + * Open the output file. + * + * @param file - file to open. + * @exception IOException if there was an exception opening the Audio + * Writer. + */ + public void open(final File file) throws IOException { + file.delete(); + out = new FileOutputStream(file); + } + + /** + * Open the output file. + * + * @param filename - file to open. + * @exception IOException if there was an exception opening the Audio + * Writer. + */ + public void open(final String filename) throws IOException { + open(new File(filename)); + } + + /** + * Writes the header pages that start the Ogg Speex file. Prepares file for + * data to be written. + * + * @param comment description to be included in the header. + * @exception IOException + */ + public void writeHeader(final String comment) throws IOException { + int chksum; + byte[] header; + byte[] data; + /* writes the OGG header page */ + header = buildOggPageHeader(2, 0, streamSerialNumber, pageCount++, 1, new byte[] { + 80 + }); + data = buildSpeexHeader(sampleRate, mode, channels, vbr, nframes); + chksum = OggCrc.checksum(0, header, 0, header.length); + chksum = OggCrc.checksum(chksum, data, 0, data.length); + writeInt(header, 22, chksum); + out.write(header); + out.write(data); + /* writes the OGG comment page */ + header = buildOggPageHeader(0, 0, streamSerialNumber, pageCount++, 1, new byte[] { + (byte) (comment.length() + 8) + }); + data = buildSpeexComment(comment); + chksum = OggCrc.checksum(0, header, 0, header.length); + chksum = OggCrc.checksum(chksum, data, 0, data.length); + writeInt(header, 22, chksum); + out.write(header); + out.write(data); + } + + /** + * Writes a packet of audio. + * + * @param data - audio data. + * @param offset - the offset from which to start reading the data. + * @param len - the length of data to read. + * @exception IOException + */ + public void writePacket(final byte[] data, final int offset, final int len) throws IOException { + log.i("**************************data=" + data.toString() + " len=" + len); + if (len <= 0) { // nothing to write + return; + } + if (packetCount > PACKETS_PER_OGG_PAGE) { + flush(false); + } + System.arraycopy(data, offset, dataBuffer, dataBufferPtr, len); + dataBufferPtr += len; + headerBuffer[headerBufferPtr++] = (byte) len; + packetCount++; + granulepos += nframes * (mode == 2 ? 640 : (mode == 1 ? 320 : 160)); + } + + /** + * Flush the Ogg page out of the buffers into the file. + * + * @param eos - end of stream + * @exception IOException + */ + private void flush(final boolean eos) throws IOException { + int chksum; + byte[] header; + /* writes the OGG header page */ + header = buildOggPageHeader((eos ? 4 : 0), granulepos, streamSerialNumber, pageCount++, + packetCount, headerBuffer); + chksum = OggCrc.checksum(0, header, 0, header.length); + chksum = OggCrc.checksum(chksum, dataBuffer, 0, dataBufferPtr); + writeInt(header, 22, chksum); + out.write(header); + out.write(dataBuffer, 0, dataBufferPtr); + dataBufferPtr = 0; + headerBufferPtr = 0; + packetCount = 0; + } +} diff --git a/android/app/src/main/java/com/mogujie/tt/imservice/support/audio/Speex.java b/android/app/src/main/java/com/mogujie/tt/imservice/support/audio/Speex.java new file mode 100644 index 000000000..70a4b7fb5 --- /dev/null +++ b/android/app/src/main/java/com/mogujie/tt/imservice/support/audio/Speex.java @@ -0,0 +1,63 @@ + +package com.mogujie.tt.imservice.support.audio; + +import com.mogujie.tt.utils.Logger; + +class Speex { + + /* + * quality 1 : 4kbps (very noticeable artifacts, usually intelligible) 2 : + * 6kbps (very noticeable artifacts, good intelligibility) 4 : 8kbps + * (noticeable artifacts sometimes) 6 : 11kpbs (artifacts usually only + * noticeable with headphones) 8 : 15kbps (artifacts not usually noticeable) + */ + private static final int DEFAULT_COMPRESSION = 4; + private Logger log = Logger.getLogger(Speex.class); + + Speex() { + } + + public void init() { + load(); + open(DEFAULT_COMPRESSION); + log.i("AEC INIT " + getAecStatus()); + // if (getAecStatus() == 0) { + // initEcho(240, 1600); + // } + // log.info("AEC INIT " + getAecStatus()); + // if (getAecStatus() == 0) { + // initEcho(320, 1600); + // } + log.i("speex opened"); + } + + private void load() { + try { + System.loadLibrary("speex"); + } catch (Throwable e) { + e.printStackTrace(); + } + + } + + public native int open(int compression); + + public native int getFrameSize(); + + public native int decode(byte encoded[], short lin[], int size); + + public native int encode(short lin[], int offset, byte encoded[], int size); + + public native void close(); + + public native void initEcho(int frameSize, int filterLength); + + public native void echoCancellation(short[] rec, short[] play, short[] out); + + public native int echoCancellationEncode(short[] rec, short[] play, + byte[] encoded); + + public native void destroyEcho(); + + public native int getAecStatus(); +} diff --git a/android/app/src/main/java/com/mogujie/tt/imservice/support/audio/SpeexDecoder.java b/android/app/src/main/java/com/mogujie/tt/imservice/support/audio/SpeexDecoder.java new file mode 100644 index 000000000..5db1602ed --- /dev/null +++ b/android/app/src/main/java/com/mogujie/tt/imservice/support/audio/SpeexDecoder.java @@ -0,0 +1,269 @@ + +package com.mogujie.tt.imservice.support.audio; + +import android.media.AudioFormat; +import android.media.AudioManager; +import android.media.AudioTrack; +import android.os.RecoverySystem.ProgressListener; + +import com.mogujie.tt.ui.adapter.MessageAdapter; +import com.mogujie.tt.imservice.event.AudioEvent; +import com.mogujie.tt.utils.Logger; + +import java.io.EOFException; +import java.io.File; +import java.io.IOException; +import java.io.RandomAccessFile; +import java.util.ArrayList; +import java.util.List; + +import de.greenrobot.event.EventBus; + +public class SpeexDecoder { + protected Speex speexDecoder; + + protected boolean enhanced = false; + + private boolean paused = false; + + protected String srcFile; + + private List listenerList = new ArrayList(); + + private File srcPath; + private AudioTrack track; + + public SpeexDecoder(File srcPath) throws Exception { + this.srcPath = srcPath; + } + + private void initializeAndroidAudio(int sampleRate) throws Exception { + int minBufferSize = AudioTrack.getMinBufferSize(sampleRate, + AudioFormat.CHANNEL_OUT_MONO, AudioFormat.ENCODING_PCM_16BIT); + + if (minBufferSize < 0) { + throw new Exception("Failed to get minimum buffer size: " + + Integer.toString(minBufferSize)); + } + + track = new AudioTrack(AudioManager.STREAM_MUSIC, sampleRate, + AudioFormat.CHANNEL_OUT_MONO, AudioFormat.ENCODING_PCM_16BIT, + minBufferSize, AudioTrack.MODE_STREAM); + + } + + public void addOnMetadataListener(ProgressListener l) { + listenerList.add(l); + } + + public synchronized void setPaused(boolean paused) { + this.paused = paused; + } + + public synchronized boolean isPaused() { + return paused; + } + + @SuppressWarnings("resource") + public void decode() throws Exception { + + byte[] header = new byte[2048]; + byte[] payload = new byte[65536]; + final int OGG_HEADERSIZE = 27; + final int OGG_SEGOFFSET = 26; + final String OGGID = "OggS"; + int segments = 0; + int curseg = 0; + int bodybytes = 0; + int decsize = 0; + int packetNo = 0; + // construct a new decoder + speexDecoder = new Speex(); + speexDecoder.init(); + // open the input stream + RandomAccessFile dis = new RandomAccessFile(srcPath, "r"); + + int origchksum; + int chksum; + try { + // read until we get to EOF + while (true) { + if (Thread.interrupted()) { + dis.close(); + track.stop(); + return; + } + + while (this.isPaused()) { + track.stop(); + Thread.sleep(100); + } + + // read the OGG header + dis.readFully(header, 0, OGG_HEADERSIZE); + origchksum = readInt(header, 22); + readLong(header, 6); + header[22] = 0; + header[23] = 0; + header[24] = 0; + header[25] = 0; + chksum = OggCrc.checksum(0, header, 0, OGG_HEADERSIZE); + + // make sure its a OGG header + if (!OGGID.equals(new String(header, 0, 4))) { + System.err.println("missing ogg id!"); + return; + } + + /* how many segments are there? */ + segments = header[OGG_SEGOFFSET] & 0xFF; + dis.readFully(header, OGG_HEADERSIZE, segments); + chksum = OggCrc.checksum(chksum, header, OGG_HEADERSIZE, + segments); + + /* decode each segment, writing output to wav */ + for (curseg = 0; curseg < segments; curseg++) { + + if (Thread.interrupted()) { + Logger.getLogger(MessageAdapter.class).d( + srcPath + "be interrupted !!! for"); + dis.close(); + track.stop(); + return; + } + + while (this.isPaused()) { + track.stop(); + Thread.sleep(100); + } + + /* get the number of bytes in the segment */ + bodybytes = header[OGG_HEADERSIZE + curseg] & 0xFF; + if (bodybytes == 255) { + System.err.println("sorry, don't handle 255 sizes!"); + return; + } + dis.readFully(payload, 0, bodybytes); + chksum = OggCrc.checksum(chksum, payload, 0, bodybytes); + + /* decode the segment */ + /* if first packet, read the Speex header */ + if (packetNo == 0) { + if (readSpeexHeader(payload, 0, bodybytes, true)) { + + packetNo++; + } else { + packetNo = 0; + } + } else if (packetNo == 1) { // Ogg Comment packet + packetNo++; + } else { + + /* get the amount of decoded data */ + short[] decoded = new short[160]; + if ((decsize = speexDecoder.decode(payload, decoded, + 160)) > 0) { + track.write(decoded, 0, decsize); + track.setStereoVolume(0.7f, 0.7f); + track.play(); + } + packetNo++; + } + } + if (chksum != origchksum) + throw new IOException("Ogg CheckSums do not match"); + } + } catch (EOFException eof) { + } finally { + if (track != null) { + track.stop(); + track.release(); + } + EventBus.getDefault().post(AudioEvent.AUDIO_STOP_PLAY); + } + + dis.close(); + } + + /** + * Reads the header packet. + * + *

+     *  0 -  7: speex_string: "Speex   "
+     *  8 - 27: speex_version: "speex-1.0"
+     * 28 - 31: speex_version_id: 1
+     * 32 - 35: header_size: 80
+     * 36 - 39: rate
+     * 40 - 43: mode: 0=narrowband, 1=wb, 2=uwb
+     * 44 - 47: mode_bitstream_version: 4
+     * 48 - 51: nb_channels
+     * 52 - 55: bitrate: -1
+     * 56 - 59: frame_size: 160
+     * 60 - 63: vbr
+     * 64 - 67: frames_per_packet
+     * 68 - 71: extra_headers: 0
+     * 72 - 75: reserved1
+     * 76 - 79: reserved2
+     * 
+ * + * @param packet + * @param offset + * @param bytes + * @return + * @throws Exception + */ + @SuppressWarnings("unused") + private boolean readSpeexHeader(final byte[] packet, final int offset, + final int bytes, boolean init) throws Exception { + if (bytes != 80) { + return false; + } + if (!"Speex ".equals(new String(packet, offset, 8))) { + return false; + } + int mode = packet[40 + offset] & 0xFF; + int sampleRate = readInt(packet, offset + 36); + int channels = readInt(packet, offset + 48); + int nframes = readInt(packet, offset + 64); + int frameSize = readInt(packet, offset + 56); + // System.out.println("mode=" + mode + " sampleRate==" + sampleRate + // + " channels=" + channels + "nframes=" + nframes + "framesize=" + // + frameSize); + initializeAndroidAudio(sampleRate); + + if (init) { + // return speexDecoder.init(mode, sampleRate, channels, enhanced); + return true; + } else { + return true; + } + } + + protected static int readInt(final byte[] data, final int offset) { + /* + * no 0xff on the last one to keep the sign + */ + return (data[offset] & 0xff) | ((data[offset + 1] & 0xff) << 8) + | ((data[offset + 2] & 0xff) << 16) | (data[offset + 3] << 24); + } + + protected static long readLong(final byte[] data, final int offset) { + /* + * no 0xff on the last one to keep the sign + */ + return (data[offset] & 0xff) | ((data[offset + 1] & 0xff) << 8) + | ((data[offset + 2] & 0xff) << 16) + | ((data[offset + 3] & 0xff) << 24) + | ((data[offset + 4] & 0xff) << 32) + | ((data[offset + 5] & 0xff) << 40) + | ((data[offset + 6] & 0xff) << 48) | (data[offset + 7] << 56); + } + + protected static int readShort(final byte[] data, final int offset) { + /* + * no 0xff on the last one to keep the sign + */ + return (data[offset] & 0xff) | (data[offset + 1] << 8); + } + +} diff --git a/android/app/src/main/java/com/mogujie/tt/imservice/support/audio/SpeexEncoder.java b/android/app/src/main/java/com/mogujie/tt/imservice/support/audio/SpeexEncoder.java new file mode 100644 index 000000000..26db1f3f2 --- /dev/null +++ b/android/app/src/main/java/com/mogujie/tt/imservice/support/audio/SpeexEncoder.java @@ -0,0 +1,97 @@ + +package com.mogujie.tt.imservice.support.audio; + +import com.mogujie.tt.utils.Logger; + +import java.util.Collections; +import java.util.LinkedList; +import java.util.List; + +public class SpeexEncoder implements Runnable { + + private Logger log = Logger.getLogger(SpeexEncoder.class); + private final Object mutex = new Object(); + private Speex speex = new Speex(); + + public static int encoder_packagesize = 1024; + private byte[] processedData = new byte[encoder_packagesize]; + + List list = null; + private volatile boolean isRecording; + private String fileName; + + public SpeexEncoder(String fileName) { + super(); + speex.init(); + list = Collections.synchronizedList(new LinkedList()); + this.fileName = fileName; + } + + public void run() { + SpeexWriter fileWriter = new SpeexWriter(fileName); + Thread consumerThread = new Thread((Runnable) fileWriter); + fileWriter.setRecording(true); + consumerThread.start(); + + android.os.Process + .setThreadPriority(android.os.Process.THREAD_PRIORITY_URGENT_AUDIO); + + int getSize = 0; + while (this.isRecording()) { + if (list.size() == 0) { + log.d("no data need to do encode"); + try { + Thread.sleep(20); + } catch (InterruptedException e) { + e.printStackTrace(); + } + continue; + } + if (list.size() > 0) { + synchronized (mutex) { + ReadData rawdata = list.remove(0); + short[] playData = new short[rawdata.size]; + getSize = speex.encode(rawdata.ready, 0, processedData, + rawdata.size); + log.i("after encode......................before=" + + rawdata.size + " after=" + processedData.length + + " getsize=" + getSize); + } + if (getSize > 0) { + fileWriter.putData(processedData, getSize); + log.i("............onLoginOut...................."); + processedData = new byte[encoder_packagesize]; + } + } + } + log.d("encode thread exit"); + fileWriter.setRecording(false); + speex.close(); + } + + public void putData(short[] data, int size) { + ReadData rd = new ReadData(); + synchronized (mutex) { + rd.size = size; + System.arraycopy(data, 0, rd.ready, 0, size); + list.add(rd); + } + } + + public void setRecording(boolean isRecording) { + synchronized (mutex) { + this.isRecording = isRecording; + } + } + + public boolean isRecording() { + synchronized (mutex) { + return isRecording; + } + } + + class ReadData { + private int size; + private short[] ready = new short[encoder_packagesize]; + } +} diff --git a/android/app/src/main/java/com/mogujie/tt/imservice/support/audio/SpeexWriteClient.java b/android/app/src/main/java/com/mogujie/tt/imservice/support/audio/SpeexWriteClient.java new file mode 100644 index 000000000..27681bb95 --- /dev/null +++ b/android/app/src/main/java/com/mogujie/tt/imservice/support/audio/SpeexWriteClient.java @@ -0,0 +1,95 @@ + +package com.mogujie.tt.imservice.support.audio; + +import com.mogujie.tt.utils.Logger; + +import java.io.IOException; + +/** + * A client write tags to local file. + */ +public class SpeexWriteClient { + private static Logger log = Logger.getLogger(SpeexWriteClient.class); + + // private long timeBase = 0; + // private int sampleRate = 0; + + // (0=NB, 1=WB and 2=UWB) + private int mode = 0; + + // 8000; 16000; 32000; 8000; + protected int sampleRate = 8000; + + /** Defines the number of channels of the audio input (1=mono, 2=stereo). */ + protected int channels = 1; + + /** Defines the number of frames per speex packet. */ + protected int nframes = 1; + + /** Defines whether or not to use VBR (Variable Bit Rate). */ + protected boolean vbr = false; + + OggSpeexWriter speexWriter = null;// new OggSpeexWriter(mode, sampleRate, + // channels, nframes, vbr); + + public SpeexWriteClient() { + + } + + public void start(String fileName) { + + init(fileName); + } + + private void init(String fileName) { + // File file = new File(saveAsFileName); + + // xiaomi + // Decoding 8000 Hz audio using narrowband mode + // Bitrate is use: 2150 bps + + mode = 0; + sampleRate = 8000;// people + // sampleRate=11000;//yong + // sampleRate=13500;//Tom + // sampleRate=5500;//Bee + vbr = true; + + speexWriter = new OggSpeexWriter(mode, sampleRate, channels, nframes, vbr); + + try { + speexWriter.open(fileName); + + speexWriter.writeHeader("Encoded with:test by gauss "); + } catch (IOException e) { + e.printStackTrace(); + } + } + + public void stop() { + if (speexWriter != null) { + try { + speexWriter.close(); + } catch (IOException e) { + e.printStackTrace(); + } + speexWriter = null; + } + log.d("writer closed!"); + } + + public void writeTag(byte[] buf, int size) { + log.i("here should be:===========================640,actual=" + size); + try { + speexWriter.writePacket(buf, 0, size); + } catch (IOException e) { + e.printStackTrace(); + } + + } + + public void setSampleRate(int sampleRate) { + this.sampleRate = sampleRate; + } + +} diff --git a/android/app/src/main/java/com/mogujie/tt/imservice/support/audio/SpeexWriter.java b/android/app/src/main/java/com/mogujie/tt/imservice/support/audio/SpeexWriter.java new file mode 100644 index 000000000..0b38f941c --- /dev/null +++ b/android/app/src/main/java/com/mogujie/tt/imservice/support/audio/SpeexWriter.java @@ -0,0 +1,93 @@ + +package com.mogujie.tt.imservice.support.audio; + +import com.mogujie.tt.utils.Logger; + +import java.util.Collections; +import java.util.LinkedList; +import java.util.List; + +public class SpeexWriter implements Runnable { + + private Logger log = Logger.getLogger(SpeexWriter.class); + private final Object mutex = new Object(); + + private SpeexWriteClient client = new SpeexWriteClient(); + private volatile boolean isRecording; + private processedData pData; + private List list; + + + public static int write_packageSize = 1024; + + public SpeexWriter(String fileName) { + super(); + list = Collections.synchronizedList(new LinkedList()); + client.setSampleRate(8000); + + client.start(fileName); + } + + public void run() { + log.d("write thread runing"); + while (this.isRecording() || list.size() > 0) { + + if (list.size() > 0) { + pData = list.remove(0); + // gauss_packageSize/2 + log.i("pData size=" + pData.size); + + client.writeTag(pData.processed, pData.size); + + log.d("list size = {}" + list.size()); + } else { + try { + Thread.sleep(20); + } catch (InterruptedException e) { + e.printStackTrace(); + } + } + + } + + log.d("write thread exit"); + stop(); + } + + public void putData(final byte[] buf, int size) { + + log.d("after convert. size=====================[640]:" + size); + + processedData data = new processedData(); + // data.ts = ts; + data.size = size; + System.arraycopy(buf, 0, data.processed, 0, size); + list.add(data); + } + + public void stop() { + client.stop(); + } + + public void setRecording(boolean isRecording) { + synchronized (mutex) { + this.isRecording = isRecording; + if (this.isRecording) { + mutex.notify(); + } + } + } + + public boolean isRecording() { + synchronized (mutex) { + return isRecording; + } + } + + class processedData { + // private long ts; + private int size; + private byte[] processed = new byte[write_packageSize]; + } + +} diff --git a/android/app/src/main/java/com/mogujie/tt/protobuf/IMBaseDefine.java b/android/app/src/main/java/com/mogujie/tt/protobuf/IMBaseDefine.java new file mode 100644 index 000000000..450c85f68 --- /dev/null +++ b/android/app/src/main/java/com/mogujie/tt/protobuf/IMBaseDefine.java @@ -0,0 +1,14915 @@ +// Generated by the protocol buffer compiler. DO NOT EDIT! +// source: IM.BaseDefine.proto + +package com.mogujie.tt.protobuf; + +public final class IMBaseDefine { + private IMBaseDefine() {} + public static void registerAllExtensions( + com.google.protobuf.ExtensionRegistryLite registry) { + } + /** + * Protobuf enum {@code IM.BaseDefine.ServiceID} + * + *
+   * service id
+   * 
+ */ + public enum ServiceID + implements com.google.protobuf.Internal.EnumLite { + /** + * SID_LOGIN = 1; + * + *
+     * for login
+     * 
+ */ + SID_LOGIN(0, 1), + /** + * SID_BUDDY_LIST = 2; + * + *
+     * for friend list
+     * 
+ */ + SID_BUDDY_LIST(1, 2), + /** + * SID_MSG = 3; + * + *
+     * 
+ */ + SID_MSG(2, 3), + /** + * SID_GROUP = 4; + * + *
+     * for group message
+     * 
+ */ + SID_GROUP(3, 4), + /** + * SID_FILE = 5; + */ + SID_FILE(4, 5), + /** + * SID_SWITCH_SERVICE = 6; + */ + SID_SWITCH_SERVICE(5, 6), + /** + * SID_OTHER = 7; + */ + SID_OTHER(6, 7), + /** + * SID_INTERNAL = 8; + */ + SID_INTERNAL(7, 8), + ; + + /** + * SID_LOGIN = 1; + * + *
+     * for login
+     * 
+ */ + public static final int SID_LOGIN_VALUE = 1; + /** + * SID_BUDDY_LIST = 2; + * + *
+     * for friend list
+     * 
+ */ + public static final int SID_BUDDY_LIST_VALUE = 2; + /** + * SID_MSG = 3; + * + *
+     * 
+ */ + public static final int SID_MSG_VALUE = 3; + /** + * SID_GROUP = 4; + * + *
+     * for group message
+     * 
+ */ + public static final int SID_GROUP_VALUE = 4; + /** + * SID_FILE = 5; + */ + public static final int SID_FILE_VALUE = 5; + /** + * SID_SWITCH_SERVICE = 6; + */ + public static final int SID_SWITCH_SERVICE_VALUE = 6; + /** + * SID_OTHER = 7; + */ + public static final int SID_OTHER_VALUE = 7; + /** + * SID_INTERNAL = 8; + */ + public static final int SID_INTERNAL_VALUE = 8; + + + public final int getNumber() { return value; } + + public static ServiceID valueOf(int value) { + switch (value) { + case 1: return SID_LOGIN; + case 2: return SID_BUDDY_LIST; + case 3: return SID_MSG; + case 4: return SID_GROUP; + case 5: return SID_FILE; + case 6: return SID_SWITCH_SERVICE; + case 7: return SID_OTHER; + case 8: return SID_INTERNAL; + default: return null; + } + } + + public static com.google.protobuf.Internal.EnumLiteMap + internalGetValueMap() { + return internalValueMap; + } + private static com.google.protobuf.Internal.EnumLiteMap + internalValueMap = + new com.google.protobuf.Internal.EnumLiteMap() { + public ServiceID findValueByNumber(int number) { + return ServiceID.valueOf(number); + } + }; + + private final int value; + + private ServiceID(int index, int value) { + this.value = value; + } + + // @@protoc_insertion_point(enum_scope:IM.BaseDefine.ServiceID) + } + + /** + * Protobuf enum {@code IM.BaseDefine.LoginCmdID} + * + *
+   * command id for login
+   * 
+ */ + public enum LoginCmdID + implements com.google.protobuf.Internal.EnumLite { + /** + * CID_LOGIN_REQ_MSGSERVER = 257; + * + *
+     * 
+ */ + CID_LOGIN_REQ_MSGSERVER(0, 257), + /** + * CID_LOGIN_RES_MSGSERVER = 258; + * + *
+     * 
+ */ + CID_LOGIN_RES_MSGSERVER(1, 258), + /** + * CID_LOGIN_REQ_USERLOGIN = 259; + * + *
+     * 
+ */ + CID_LOGIN_REQ_USERLOGIN(2, 259), + /** + * CID_LOGIN_RES_USERLOGIN = 260; + * + *
+     * 
+ */ + CID_LOGIN_RES_USERLOGIN(3, 260), + /** + * CID_LOGIN_REQ_LOGINOUT = 261; + * + *
+     * 
+ */ + CID_LOGIN_REQ_LOGINOUT(4, 261), + /** + * CID_LOGIN_RES_LOGINOUT = 262; + * + *
+     * 
+ */ + CID_LOGIN_RES_LOGINOUT(5, 262), + /** + * CID_LOGIN_KICK_USER = 263; + * + *
+     * 
+ */ + CID_LOGIN_KICK_USER(6, 263), + /** + * CID_LOGIN_REQ_DEVICETOKEN = 264; + * + *
+     * 
+ */ + CID_LOGIN_REQ_DEVICETOKEN(7, 264), + /** + * CID_LOGIN_RES_DEVICETOKEN = 265; + * + *
+     * 
+ */ + CID_LOGIN_RES_DEVICETOKEN(8, 265), + /** + * CID_LOGIN_REQ_KICKPCCLIENT = 266; + */ + CID_LOGIN_REQ_KICKPCCLIENT(9, 266), + /** + * CID_LOGIN_RES_KICKPCCLIENT = 267; + */ + CID_LOGIN_RES_KICKPCCLIENT(10, 267), + ; + + /** + * CID_LOGIN_REQ_MSGSERVER = 257; + * + *
+     * 
+ */ + public static final int CID_LOGIN_REQ_MSGSERVER_VALUE = 257; + /** + * CID_LOGIN_RES_MSGSERVER = 258; + * + *
+     * 
+ */ + public static final int CID_LOGIN_RES_MSGSERVER_VALUE = 258; + /** + * CID_LOGIN_REQ_USERLOGIN = 259; + * + *
+     * 
+ */ + public static final int CID_LOGIN_REQ_USERLOGIN_VALUE = 259; + /** + * CID_LOGIN_RES_USERLOGIN = 260; + * + *
+     * 
+ */ + public static final int CID_LOGIN_RES_USERLOGIN_VALUE = 260; + /** + * CID_LOGIN_REQ_LOGINOUT = 261; + * + *
+     * 
+ */ + public static final int CID_LOGIN_REQ_LOGINOUT_VALUE = 261; + /** + * CID_LOGIN_RES_LOGINOUT = 262; + * + *
+     * 
+ */ + public static final int CID_LOGIN_RES_LOGINOUT_VALUE = 262; + /** + * CID_LOGIN_KICK_USER = 263; + * + *
+     * 
+ */ + public static final int CID_LOGIN_KICK_USER_VALUE = 263; + /** + * CID_LOGIN_REQ_DEVICETOKEN = 264; + * + *
+     * 
+ */ + public static final int CID_LOGIN_REQ_DEVICETOKEN_VALUE = 264; + /** + * CID_LOGIN_RES_DEVICETOKEN = 265; + * + *
+     * 
+ */ + public static final int CID_LOGIN_RES_DEVICETOKEN_VALUE = 265; + /** + * CID_LOGIN_REQ_KICKPCCLIENT = 266; + */ + public static final int CID_LOGIN_REQ_KICKPCCLIENT_VALUE = 266; + /** + * CID_LOGIN_RES_KICKPCCLIENT = 267; + */ + public static final int CID_LOGIN_RES_KICKPCCLIENT_VALUE = 267; + + + public final int getNumber() { return value; } + + public static LoginCmdID valueOf(int value) { + switch (value) { + case 257: return CID_LOGIN_REQ_MSGSERVER; + case 258: return CID_LOGIN_RES_MSGSERVER; + case 259: return CID_LOGIN_REQ_USERLOGIN; + case 260: return CID_LOGIN_RES_USERLOGIN; + case 261: return CID_LOGIN_REQ_LOGINOUT; + case 262: return CID_LOGIN_RES_LOGINOUT; + case 263: return CID_LOGIN_KICK_USER; + case 264: return CID_LOGIN_REQ_DEVICETOKEN; + case 265: return CID_LOGIN_RES_DEVICETOKEN; + case 266: return CID_LOGIN_REQ_KICKPCCLIENT; + case 267: return CID_LOGIN_RES_KICKPCCLIENT; + default: return null; + } + } + + public static com.google.protobuf.Internal.EnumLiteMap + internalGetValueMap() { + return internalValueMap; + } + private static com.google.protobuf.Internal.EnumLiteMap + internalValueMap = + new com.google.protobuf.Internal.EnumLiteMap() { + public LoginCmdID findValueByNumber(int number) { + return LoginCmdID.valueOf(number); + } + }; + + private final int value; + + private LoginCmdID(int index, int value) { + this.value = value; + } + + // @@protoc_insertion_point(enum_scope:IM.BaseDefine.LoginCmdID) + } + + /** + * Protobuf enum {@code IM.BaseDefine.BuddyListCmdID} + * + *
+   * command id for buddy list
+   * 
+ */ + public enum BuddyListCmdID + implements com.google.protobuf.Internal.EnumLite { + /** + * CID_BUDDY_LIST_RECENT_CONTACT_SESSION_REQUEST = 513; + */ + CID_BUDDY_LIST_RECENT_CONTACT_SESSION_REQUEST(0, 513), + /** + * CID_BUDDY_LIST_RECENT_CONTACT_SESSION_RESPONSE = 514; + */ + CID_BUDDY_LIST_RECENT_CONTACT_SESSION_RESPONSE(1, 514), + /** + * CID_BUDDY_LIST_STATUS_NOTIFY = 515; + * + *
+     * 
+ */ + CID_BUDDY_LIST_STATUS_NOTIFY(2, 515), + /** + * CID_BUDDY_LIST_USER_INFO_REQUEST = 516; + * + *
+     * 
+ */ + CID_BUDDY_LIST_USER_INFO_REQUEST(3, 516), + /** + * CID_BUDDY_LIST_USER_INFO_RESPONSE = 517; + */ + CID_BUDDY_LIST_USER_INFO_RESPONSE(4, 517), + /** + * CID_BUDDY_LIST_REMOVE_SESSION_REQ = 518; + */ + CID_BUDDY_LIST_REMOVE_SESSION_REQ(5, 518), + /** + * CID_BUDDY_LIST_REMOVE_SESSION_RES = 519; + */ + CID_BUDDY_LIST_REMOVE_SESSION_RES(6, 519), + /** + * CID_BUDDY_LIST_ALL_USER_REQUEST = 520; + */ + CID_BUDDY_LIST_ALL_USER_REQUEST(7, 520), + /** + * CID_BUDDY_LIST_ALL_USER_RESPONSE = 521; + */ + CID_BUDDY_LIST_ALL_USER_RESPONSE(8, 521), + /** + * CID_BUDDY_LIST_USERS_STATUS_REQUEST = 522; + */ + CID_BUDDY_LIST_USERS_STATUS_REQUEST(9, 522), + /** + * CID_BUDDY_LIST_USERS_STATUS_RESPONSE = 523; + */ + CID_BUDDY_LIST_USERS_STATUS_RESPONSE(10, 523), + /** + * CID_BUDDY_LIST_CHANGE_AVATAR_REQUEST = 524; + */ + CID_BUDDY_LIST_CHANGE_AVATAR_REQUEST(11, 524), + /** + * CID_BUDDY_LIST_CHANGE_AVATAR_RESPONSE = 525; + */ + CID_BUDDY_LIST_CHANGE_AVATAR_RESPONSE(12, 525), + /** + * CID_BUDDY_LIST_PC_LOGIN_STATUS_NOTIFY = 526; + */ + CID_BUDDY_LIST_PC_LOGIN_STATUS_NOTIFY(13, 526), + /** + * CID_BUDDY_LIST_REMOVE_SESSION_NOTIFY = 527; + */ + CID_BUDDY_LIST_REMOVE_SESSION_NOTIFY(14, 527), + /** + * CID_BUDDY_LIST_DEPARTMENT_REQUEST = 528; + */ + CID_BUDDY_LIST_DEPARTMENT_REQUEST(15, 528), + /** + * CID_BUDDY_LIST_DEPARTMENT_RESPONSE = 529; + */ + CID_BUDDY_LIST_DEPARTMENT_RESPONSE(16, 529), + ; + + /** + * CID_BUDDY_LIST_RECENT_CONTACT_SESSION_REQUEST = 513; + */ + public static final int CID_BUDDY_LIST_RECENT_CONTACT_SESSION_REQUEST_VALUE = 513; + /** + * CID_BUDDY_LIST_RECENT_CONTACT_SESSION_RESPONSE = 514; + */ + public static final int CID_BUDDY_LIST_RECENT_CONTACT_SESSION_RESPONSE_VALUE = 514; + /** + * CID_BUDDY_LIST_STATUS_NOTIFY = 515; + * + *
+     * 
+ */ + public static final int CID_BUDDY_LIST_STATUS_NOTIFY_VALUE = 515; + /** + * CID_BUDDY_LIST_USER_INFO_REQUEST = 516; + * + *
+     * 
+ */ + public static final int CID_BUDDY_LIST_USER_INFO_REQUEST_VALUE = 516; + /** + * CID_BUDDY_LIST_USER_INFO_RESPONSE = 517; + */ + public static final int CID_BUDDY_LIST_USER_INFO_RESPONSE_VALUE = 517; + /** + * CID_BUDDY_LIST_REMOVE_SESSION_REQ = 518; + */ + public static final int CID_BUDDY_LIST_REMOVE_SESSION_REQ_VALUE = 518; + /** + * CID_BUDDY_LIST_REMOVE_SESSION_RES = 519; + */ + public static final int CID_BUDDY_LIST_REMOVE_SESSION_RES_VALUE = 519; + /** + * CID_BUDDY_LIST_ALL_USER_REQUEST = 520; + */ + public static final int CID_BUDDY_LIST_ALL_USER_REQUEST_VALUE = 520; + /** + * CID_BUDDY_LIST_ALL_USER_RESPONSE = 521; + */ + public static final int CID_BUDDY_LIST_ALL_USER_RESPONSE_VALUE = 521; + /** + * CID_BUDDY_LIST_USERS_STATUS_REQUEST = 522; + */ + public static final int CID_BUDDY_LIST_USERS_STATUS_REQUEST_VALUE = 522; + /** + * CID_BUDDY_LIST_USERS_STATUS_RESPONSE = 523; + */ + public static final int CID_BUDDY_LIST_USERS_STATUS_RESPONSE_VALUE = 523; + /** + * CID_BUDDY_LIST_CHANGE_AVATAR_REQUEST = 524; + */ + public static final int CID_BUDDY_LIST_CHANGE_AVATAR_REQUEST_VALUE = 524; + /** + * CID_BUDDY_LIST_CHANGE_AVATAR_RESPONSE = 525; + */ + public static final int CID_BUDDY_LIST_CHANGE_AVATAR_RESPONSE_VALUE = 525; + /** + * CID_BUDDY_LIST_PC_LOGIN_STATUS_NOTIFY = 526; + */ + public static final int CID_BUDDY_LIST_PC_LOGIN_STATUS_NOTIFY_VALUE = 526; + /** + * CID_BUDDY_LIST_REMOVE_SESSION_NOTIFY = 527; + */ + public static final int CID_BUDDY_LIST_REMOVE_SESSION_NOTIFY_VALUE = 527; + /** + * CID_BUDDY_LIST_DEPARTMENT_REQUEST = 528; + */ + public static final int CID_BUDDY_LIST_DEPARTMENT_REQUEST_VALUE = 528; + /** + * CID_BUDDY_LIST_DEPARTMENT_RESPONSE = 529; + */ + public static final int CID_BUDDY_LIST_DEPARTMENT_RESPONSE_VALUE = 529; + + + public final int getNumber() { return value; } + + public static BuddyListCmdID valueOf(int value) { + switch (value) { + case 513: return CID_BUDDY_LIST_RECENT_CONTACT_SESSION_REQUEST; + case 514: return CID_BUDDY_LIST_RECENT_CONTACT_SESSION_RESPONSE; + case 515: return CID_BUDDY_LIST_STATUS_NOTIFY; + case 516: return CID_BUDDY_LIST_USER_INFO_REQUEST; + case 517: return CID_BUDDY_LIST_USER_INFO_RESPONSE; + case 518: return CID_BUDDY_LIST_REMOVE_SESSION_REQ; + case 519: return CID_BUDDY_LIST_REMOVE_SESSION_RES; + case 520: return CID_BUDDY_LIST_ALL_USER_REQUEST; + case 521: return CID_BUDDY_LIST_ALL_USER_RESPONSE; + case 522: return CID_BUDDY_LIST_USERS_STATUS_REQUEST; + case 523: return CID_BUDDY_LIST_USERS_STATUS_RESPONSE; + case 524: return CID_BUDDY_LIST_CHANGE_AVATAR_REQUEST; + case 525: return CID_BUDDY_LIST_CHANGE_AVATAR_RESPONSE; + case 526: return CID_BUDDY_LIST_PC_LOGIN_STATUS_NOTIFY; + case 527: return CID_BUDDY_LIST_REMOVE_SESSION_NOTIFY; + case 528: return CID_BUDDY_LIST_DEPARTMENT_REQUEST; + case 529: return CID_BUDDY_LIST_DEPARTMENT_RESPONSE; + default: return null; + } + } + + public static com.google.protobuf.Internal.EnumLiteMap + internalGetValueMap() { + return internalValueMap; + } + private static com.google.protobuf.Internal.EnumLiteMap + internalValueMap = + new com.google.protobuf.Internal.EnumLiteMap() { + public BuddyListCmdID findValueByNumber(int number) { + return BuddyListCmdID.valueOf(number); + } + }; + + private final int value; + + private BuddyListCmdID(int index, int value) { + this.value = value; + } + + // @@protoc_insertion_point(enum_scope:IM.BaseDefine.BuddyListCmdID) + } + + /** + * Protobuf enum {@code IM.BaseDefine.MessageCmdID} + * + *
+   * command id for msg
+   * 
+ */ + public enum MessageCmdID + implements com.google.protobuf.Internal.EnumLite { + /** + * CID_MSG_DATA = 769; + * + *
+     * 
+ */ + CID_MSG_DATA(0, 769), + /** + * CID_MSG_DATA_ACK = 770; + * + *
+     * 
+ */ + CID_MSG_DATA_ACK(1, 770), + /** + * CID_MSG_READ_ACK = 771; + * + *
+     * 
+ */ + CID_MSG_READ_ACK(2, 771), + /** + * CID_MSG_READ_NOTIFY = 772; + * + *
+     *  已读消息通知
+     * 
+ */ + CID_MSG_READ_NOTIFY(3, 772), + /** + * CID_MSG_TIME_REQUEST = 773; + * + *
+     * 
+ */ + CID_MSG_TIME_REQUEST(4, 773), + /** + * CID_MSG_TIME_RESPONSE = 774; + * + *
+     * 
+ */ + CID_MSG_TIME_RESPONSE(5, 774), + /** + * CID_MSG_UNREAD_CNT_REQUEST = 775; + * + *
+     * 
+ */ + CID_MSG_UNREAD_CNT_REQUEST(6, 775), + /** + * CID_MSG_UNREAD_CNT_RESPONSE = 776; + * + *
+     * 
+ */ + CID_MSG_UNREAD_CNT_RESPONSE(7, 776), + /** + * CID_MSG_LIST_REQUEST = 777; + * + *
+     *获取指定队列消息
+     * 
+ */ + CID_MSG_LIST_REQUEST(8, 777), + /** + * CID_MSG_LIST_RESPONSE = 778; + */ + CID_MSG_LIST_RESPONSE(9, 778), + /** + * CID_MSG_GET_LATEST_MSG_ID_REQ = 779; + */ + CID_MSG_GET_LATEST_MSG_ID_REQ(10, 779), + /** + * CID_MSG_GET_LATEST_MSG_ID_RSP = 780; + */ + CID_MSG_GET_LATEST_MSG_ID_RSP(11, 780), + /** + * CID_MSG_GET_BY_MSG_ID_REQ = 781; + */ + CID_MSG_GET_BY_MSG_ID_REQ(12, 781), + /** + * CID_MSG_GET_BY_MSG_ID_RES = 782; + */ + CID_MSG_GET_BY_MSG_ID_RES(13, 782), + ; + + /** + * CID_MSG_DATA = 769; + * + *
+     * 
+ */ + public static final int CID_MSG_DATA_VALUE = 769; + /** + * CID_MSG_DATA_ACK = 770; + * + *
+     * 
+ */ + public static final int CID_MSG_DATA_ACK_VALUE = 770; + /** + * CID_MSG_READ_ACK = 771; + * + *
+     * 
+ */ + public static final int CID_MSG_READ_ACK_VALUE = 771; + /** + * CID_MSG_READ_NOTIFY = 772; + * + *
+     *  已读消息通知
+     * 
+ */ + public static final int CID_MSG_READ_NOTIFY_VALUE = 772; + /** + * CID_MSG_TIME_REQUEST = 773; + * + *
+     * 
+ */ + public static final int CID_MSG_TIME_REQUEST_VALUE = 773; + /** + * CID_MSG_TIME_RESPONSE = 774; + * + *
+     * 
+ */ + public static final int CID_MSG_TIME_RESPONSE_VALUE = 774; + /** + * CID_MSG_UNREAD_CNT_REQUEST = 775; + * + *
+     * 
+ */ + public static final int CID_MSG_UNREAD_CNT_REQUEST_VALUE = 775; + /** + * CID_MSG_UNREAD_CNT_RESPONSE = 776; + * + *
+     * 
+ */ + public static final int CID_MSG_UNREAD_CNT_RESPONSE_VALUE = 776; + /** + * CID_MSG_LIST_REQUEST = 777; + * + *
+     *获取指定队列消息
+     * 
+ */ + public static final int CID_MSG_LIST_REQUEST_VALUE = 777; + /** + * CID_MSG_LIST_RESPONSE = 778; + */ + public static final int CID_MSG_LIST_RESPONSE_VALUE = 778; + /** + * CID_MSG_GET_LATEST_MSG_ID_REQ = 779; + */ + public static final int CID_MSG_GET_LATEST_MSG_ID_REQ_VALUE = 779; + /** + * CID_MSG_GET_LATEST_MSG_ID_RSP = 780; + */ + public static final int CID_MSG_GET_LATEST_MSG_ID_RSP_VALUE = 780; + /** + * CID_MSG_GET_BY_MSG_ID_REQ = 781; + */ + public static final int CID_MSG_GET_BY_MSG_ID_REQ_VALUE = 781; + /** + * CID_MSG_GET_BY_MSG_ID_RES = 782; + */ + public static final int CID_MSG_GET_BY_MSG_ID_RES_VALUE = 782; + + + public final int getNumber() { return value; } + + public static MessageCmdID valueOf(int value) { + switch (value) { + case 769: return CID_MSG_DATA; + case 770: return CID_MSG_DATA_ACK; + case 771: return CID_MSG_READ_ACK; + case 772: return CID_MSG_READ_NOTIFY; + case 773: return CID_MSG_TIME_REQUEST; + case 774: return CID_MSG_TIME_RESPONSE; + case 775: return CID_MSG_UNREAD_CNT_REQUEST; + case 776: return CID_MSG_UNREAD_CNT_RESPONSE; + case 777: return CID_MSG_LIST_REQUEST; + case 778: return CID_MSG_LIST_RESPONSE; + case 779: return CID_MSG_GET_LATEST_MSG_ID_REQ; + case 780: return CID_MSG_GET_LATEST_MSG_ID_RSP; + case 781: return CID_MSG_GET_BY_MSG_ID_REQ; + case 782: return CID_MSG_GET_BY_MSG_ID_RES; + default: return null; + } + } + + public static com.google.protobuf.Internal.EnumLiteMap + internalGetValueMap() { + return internalValueMap; + } + private static com.google.protobuf.Internal.EnumLiteMap + internalValueMap = + new com.google.protobuf.Internal.EnumLiteMap() { + public MessageCmdID findValueByNumber(int number) { + return MessageCmdID.valueOf(number); + } + }; + + private final int value; + + private MessageCmdID(int index, int value) { + this.value = value; + } + + // @@protoc_insertion_point(enum_scope:IM.BaseDefine.MessageCmdID) + } + + /** + * Protobuf enum {@code IM.BaseDefine.GroupCmdID} + * + *
+   * command id for group message
+   * 
+ */ + public enum GroupCmdID + implements com.google.protobuf.Internal.EnumLite { + /** + * CID_GROUP_NORMAL_LIST_REQUEST = 1025; + */ + CID_GROUP_NORMAL_LIST_REQUEST(0, 1025), + /** + * CID_GROUP_NORMAL_LIST_RESPONSE = 1026; + */ + CID_GROUP_NORMAL_LIST_RESPONSE(1, 1026), + /** + * CID_GROUP_INFO_REQUEST = 1027; + */ + CID_GROUP_INFO_REQUEST(2, 1027), + /** + * CID_GROUP_INFO_RESPONSE = 1028; + */ + CID_GROUP_INFO_RESPONSE(3, 1028), + /** + * CID_GROUP_CREATE_REQUEST = 1029; + */ + CID_GROUP_CREATE_REQUEST(4, 1029), + /** + * CID_GROUP_CREATE_RESPONSE = 1030; + */ + CID_GROUP_CREATE_RESPONSE(5, 1030), + /** + * CID_GROUP_CHANGE_MEMBER_REQUEST = 1031; + */ + CID_GROUP_CHANGE_MEMBER_REQUEST(6, 1031), + /** + * CID_GROUP_CHANGE_MEMBER_RESPONSE = 1032; + */ + CID_GROUP_CHANGE_MEMBER_RESPONSE(7, 1032), + /** + * CID_GROUP_SHIELD_GROUP_REQUEST = 1033; + */ + CID_GROUP_SHIELD_GROUP_REQUEST(8, 1033), + /** + * CID_GROUP_SHIELD_GROUP_RESPONSE = 1034; + */ + CID_GROUP_SHIELD_GROUP_RESPONSE(9, 1034), + /** + * CID_GROUP_CHANGE_MEMBER_NOTIFY = 1035; + */ + CID_GROUP_CHANGE_MEMBER_NOTIFY(10, 1035), + ; + + /** + * CID_GROUP_NORMAL_LIST_REQUEST = 1025; + */ + public static final int CID_GROUP_NORMAL_LIST_REQUEST_VALUE = 1025; + /** + * CID_GROUP_NORMAL_LIST_RESPONSE = 1026; + */ + public static final int CID_GROUP_NORMAL_LIST_RESPONSE_VALUE = 1026; + /** + * CID_GROUP_INFO_REQUEST = 1027; + */ + public static final int CID_GROUP_INFO_REQUEST_VALUE = 1027; + /** + * CID_GROUP_INFO_RESPONSE = 1028; + */ + public static final int CID_GROUP_INFO_RESPONSE_VALUE = 1028; + /** + * CID_GROUP_CREATE_REQUEST = 1029; + */ + public static final int CID_GROUP_CREATE_REQUEST_VALUE = 1029; + /** + * CID_GROUP_CREATE_RESPONSE = 1030; + */ + public static final int CID_GROUP_CREATE_RESPONSE_VALUE = 1030; + /** + * CID_GROUP_CHANGE_MEMBER_REQUEST = 1031; + */ + public static final int CID_GROUP_CHANGE_MEMBER_REQUEST_VALUE = 1031; + /** + * CID_GROUP_CHANGE_MEMBER_RESPONSE = 1032; + */ + public static final int CID_GROUP_CHANGE_MEMBER_RESPONSE_VALUE = 1032; + /** + * CID_GROUP_SHIELD_GROUP_REQUEST = 1033; + */ + public static final int CID_GROUP_SHIELD_GROUP_REQUEST_VALUE = 1033; + /** + * CID_GROUP_SHIELD_GROUP_RESPONSE = 1034; + */ + public static final int CID_GROUP_SHIELD_GROUP_RESPONSE_VALUE = 1034; + /** + * CID_GROUP_CHANGE_MEMBER_NOTIFY = 1035; + */ + public static final int CID_GROUP_CHANGE_MEMBER_NOTIFY_VALUE = 1035; + + + public final int getNumber() { return value; } + + public static GroupCmdID valueOf(int value) { + switch (value) { + case 1025: return CID_GROUP_NORMAL_LIST_REQUEST; + case 1026: return CID_GROUP_NORMAL_LIST_RESPONSE; + case 1027: return CID_GROUP_INFO_REQUEST; + case 1028: return CID_GROUP_INFO_RESPONSE; + case 1029: return CID_GROUP_CREATE_REQUEST; + case 1030: return CID_GROUP_CREATE_RESPONSE; + case 1031: return CID_GROUP_CHANGE_MEMBER_REQUEST; + case 1032: return CID_GROUP_CHANGE_MEMBER_RESPONSE; + case 1033: return CID_GROUP_SHIELD_GROUP_REQUEST; + case 1034: return CID_GROUP_SHIELD_GROUP_RESPONSE; + case 1035: return CID_GROUP_CHANGE_MEMBER_NOTIFY; + default: return null; + } + } + + public static com.google.protobuf.Internal.EnumLiteMap + internalGetValueMap() { + return internalValueMap; + } + private static com.google.protobuf.Internal.EnumLiteMap + internalValueMap = + new com.google.protobuf.Internal.EnumLiteMap() { + public GroupCmdID findValueByNumber(int number) { + return GroupCmdID.valueOf(number); + } + }; + + private final int value; + + private GroupCmdID(int index, int value) { + this.value = value; + } + + // @@protoc_insertion_point(enum_scope:IM.BaseDefine.GroupCmdID) + } + + /** + * Protobuf enum {@code IM.BaseDefine.FileCmdID} + */ + public enum FileCmdID + implements com.google.protobuf.Internal.EnumLite { + /** + * CID_FILE_LOGIN_REQ = 1281; + * + *
+     * sender/receiver need to login to
+     * 
+ */ + CID_FILE_LOGIN_REQ(0, 1281), + /** + * CID_FILE_LOGIN_RES = 1282; + * + *
+     * login success or failure
+     * 
+ */ + CID_FILE_LOGIN_RES(1, 1282), + /** + * CID_FILE_STATE = 1283; + */ + CID_FILE_STATE(2, 1283), + /** + * CID_FILE_PULL_DATA_REQ = 1284; + */ + CID_FILE_PULL_DATA_REQ(3, 1284), + /** + * CID_FILE_PULL_DATA_RSP = 1285; + */ + CID_FILE_PULL_DATA_RSP(4, 1285), + /** + * CID_FILE_REQUEST = 1286; + * + *
+     * To MsgServer
+     * 
+ */ + CID_FILE_REQUEST(5, 1286), + /** + * CID_FILE_RESPONSE = 1287; + * + *
+     * receiver -> sender
+     * 
+ */ + CID_FILE_RESPONSE(6, 1287), + /** + * CID_FILE_NOTIFY = 1288; + */ + CID_FILE_NOTIFY(7, 1288), + /** + * CID_FILE_HAS_OFFLINE_REQ = 1289; + */ + CID_FILE_HAS_OFFLINE_REQ(8, 1289), + /** + * CID_FILE_HAS_OFFLINE_RES = 1290; + */ + CID_FILE_HAS_OFFLINE_RES(9, 1290), + /** + * CID_FILE_ADD_OFFLINE_REQ = 1291; + */ + CID_FILE_ADD_OFFLINE_REQ(10, 1291), + /** + * CID_FILE_DEL_OFFLINE_REQ = 1292; + */ + CID_FILE_DEL_OFFLINE_REQ(11, 1292), + ; + + /** + * CID_FILE_LOGIN_REQ = 1281; + * + *
+     * sender/receiver need to login to
+     * 
+ */ + public static final int CID_FILE_LOGIN_REQ_VALUE = 1281; + /** + * CID_FILE_LOGIN_RES = 1282; + * + *
+     * login success or failure
+     * 
+ */ + public static final int CID_FILE_LOGIN_RES_VALUE = 1282; + /** + * CID_FILE_STATE = 1283; + */ + public static final int CID_FILE_STATE_VALUE = 1283; + /** + * CID_FILE_PULL_DATA_REQ = 1284; + */ + public static final int CID_FILE_PULL_DATA_REQ_VALUE = 1284; + /** + * CID_FILE_PULL_DATA_RSP = 1285; + */ + public static final int CID_FILE_PULL_DATA_RSP_VALUE = 1285; + /** + * CID_FILE_REQUEST = 1286; + * + *
+     * To MsgServer
+     * 
+ */ + public static final int CID_FILE_REQUEST_VALUE = 1286; + /** + * CID_FILE_RESPONSE = 1287; + * + *
+     * receiver -> sender
+     * 
+ */ + public static final int CID_FILE_RESPONSE_VALUE = 1287; + /** + * CID_FILE_NOTIFY = 1288; + */ + public static final int CID_FILE_NOTIFY_VALUE = 1288; + /** + * CID_FILE_HAS_OFFLINE_REQ = 1289; + */ + public static final int CID_FILE_HAS_OFFLINE_REQ_VALUE = 1289; + /** + * CID_FILE_HAS_OFFLINE_RES = 1290; + */ + public static final int CID_FILE_HAS_OFFLINE_RES_VALUE = 1290; + /** + * CID_FILE_ADD_OFFLINE_REQ = 1291; + */ + public static final int CID_FILE_ADD_OFFLINE_REQ_VALUE = 1291; + /** + * CID_FILE_DEL_OFFLINE_REQ = 1292; + */ + public static final int CID_FILE_DEL_OFFLINE_REQ_VALUE = 1292; + + + public final int getNumber() { return value; } + + public static FileCmdID valueOf(int value) { + switch (value) { + case 1281: return CID_FILE_LOGIN_REQ; + case 1282: return CID_FILE_LOGIN_RES; + case 1283: return CID_FILE_STATE; + case 1284: return CID_FILE_PULL_DATA_REQ; + case 1285: return CID_FILE_PULL_DATA_RSP; + case 1286: return CID_FILE_REQUEST; + case 1287: return CID_FILE_RESPONSE; + case 1288: return CID_FILE_NOTIFY; + case 1289: return CID_FILE_HAS_OFFLINE_REQ; + case 1290: return CID_FILE_HAS_OFFLINE_RES; + case 1291: return CID_FILE_ADD_OFFLINE_REQ; + case 1292: return CID_FILE_DEL_OFFLINE_REQ; + default: return null; + } + } + + public static com.google.protobuf.Internal.EnumLiteMap + internalGetValueMap() { + return internalValueMap; + } + private static com.google.protobuf.Internal.EnumLiteMap + internalValueMap = + new com.google.protobuf.Internal.EnumLiteMap() { + public FileCmdID findValueByNumber(int number) { + return FileCmdID.valueOf(number); + } + }; + + private final int value; + + private FileCmdID(int index, int value) { + this.value = value; + } + + // @@protoc_insertion_point(enum_scope:IM.BaseDefine.FileCmdID) + } + + /** + * Protobuf enum {@code IM.BaseDefine.SwitchServiceCmdID} + * + *
+   * command id for switch service
+   * 
+ */ + public enum SwitchServiceCmdID + implements com.google.protobuf.Internal.EnumLite { + /** + * CID_SWITCH_P2P_CMD = 1537; + * + *
+     * 
+ */ + CID_SWITCH_P2P_CMD(0, 1537), + ; + + /** + * CID_SWITCH_P2P_CMD = 1537; + * + *
+     * 
+ */ + public static final int CID_SWITCH_P2P_CMD_VALUE = 1537; + + + public final int getNumber() { return value; } + + public static SwitchServiceCmdID valueOf(int value) { + switch (value) { + case 1537: return CID_SWITCH_P2P_CMD; + default: return null; + } + } + + public static com.google.protobuf.Internal.EnumLiteMap + internalGetValueMap() { + return internalValueMap; + } + private static com.google.protobuf.Internal.EnumLiteMap + internalValueMap = + new com.google.protobuf.Internal.EnumLiteMap() { + public SwitchServiceCmdID findValueByNumber(int number) { + return SwitchServiceCmdID.valueOf(number); + } + }; + + private final int value; + + private SwitchServiceCmdID(int index, int value) { + this.value = value; + } + + // @@protoc_insertion_point(enum_scope:IM.BaseDefine.SwitchServiceCmdID) + } + + /** + * Protobuf enum {@code IM.BaseDefine.OtherCmdID} + */ + public enum OtherCmdID + implements com.google.protobuf.Internal.EnumLite { + /** + * CID_OTHER_HEARTBEAT = 1793; + */ + CID_OTHER_HEARTBEAT(0, 1793), + /** + * CID_OTHER_STOP_RECV_PACKET = 1794; + */ + CID_OTHER_STOP_RECV_PACKET(1, 1794), + /** + * CID_OTHER_VALIDATE_REQ = 1795; + */ + CID_OTHER_VALIDATE_REQ(2, 1795), + /** + * CID_OTHER_VALIDATE_RSP = 1796; + */ + CID_OTHER_VALIDATE_RSP(3, 1796), + /** + * CID_OTHER_GET_DEVICE_TOKEN_REQ = 1797; + */ + CID_OTHER_GET_DEVICE_TOKEN_REQ(4, 1797), + /** + * CID_OTHER_GET_DEVICE_TOKEN_RSP = 1798; + */ + CID_OTHER_GET_DEVICE_TOKEN_RSP(5, 1798), + /** + * CID_OTHER_ROLE_SET = 1799; + */ + CID_OTHER_ROLE_SET(6, 1799), + /** + * CID_OTHER_ONLINE_USER_INFO = 1800; + */ + CID_OTHER_ONLINE_USER_INFO(7, 1800), + /** + * CID_OTHER_MSG_SERV_INFO = 1801; + */ + CID_OTHER_MSG_SERV_INFO(8, 1801), + /** + * CID_OTHER_USER_STATUS_UPDATE = 1802; + */ + CID_OTHER_USER_STATUS_UPDATE(9, 1802), + /** + * CID_OTHER_USER_CNT_UPDATE = 1803; + */ + CID_OTHER_USER_CNT_UPDATE(10, 1803), + /** + * CID_OTHER_SERVER_KICK_USER = 1805; + */ + CID_OTHER_SERVER_KICK_USER(11, 1805), + /** + * CID_OTHER_LOGIN_STATUS_NOTIFY = 1806; + */ + CID_OTHER_LOGIN_STATUS_NOTIFY(12, 1806), + /** + * CID_OTHER_PUSH_TO_USER_REQ = 1807; + */ + CID_OTHER_PUSH_TO_USER_REQ(13, 1807), + /** + * CID_OTHER_PUSH_TO_USER_RSP = 1808; + */ + CID_OTHER_PUSH_TO_USER_RSP(14, 1808), + /** + * CID_OTHER_GET_SHIELD_REQ = 1809; + */ + CID_OTHER_GET_SHIELD_REQ(15, 1809), + /** + * CID_OTHER_GET_SHIELD_RSP = 1810; + */ + CID_OTHER_GET_SHIELD_RSP(16, 1810), + /** + * CID_OTHER_FILE_TRANSFER_REQ = 1841; + */ + CID_OTHER_FILE_TRANSFER_REQ(17, 1841), + /** + * CID_OTHER_FILE_TRANSFER_RSP = 1842; + */ + CID_OTHER_FILE_TRANSFER_RSP(18, 1842), + /** + * CID_OTHER_FILE_SERVER_IP_REQ = 1843; + */ + CID_OTHER_FILE_SERVER_IP_REQ(19, 1843), + /** + * CID_OTHER_FILE_SERVER_IP_RSP = 1844; + */ + CID_OTHER_FILE_SERVER_IP_RSP(20, 1844), + ; + + /** + * CID_OTHER_HEARTBEAT = 1793; + */ + public static final int CID_OTHER_HEARTBEAT_VALUE = 1793; + /** + * CID_OTHER_STOP_RECV_PACKET = 1794; + */ + public static final int CID_OTHER_STOP_RECV_PACKET_VALUE = 1794; + /** + * CID_OTHER_VALIDATE_REQ = 1795; + */ + public static final int CID_OTHER_VALIDATE_REQ_VALUE = 1795; + /** + * CID_OTHER_VALIDATE_RSP = 1796; + */ + public static final int CID_OTHER_VALIDATE_RSP_VALUE = 1796; + /** + * CID_OTHER_GET_DEVICE_TOKEN_REQ = 1797; + */ + public static final int CID_OTHER_GET_DEVICE_TOKEN_REQ_VALUE = 1797; + /** + * CID_OTHER_GET_DEVICE_TOKEN_RSP = 1798; + */ + public static final int CID_OTHER_GET_DEVICE_TOKEN_RSP_VALUE = 1798; + /** + * CID_OTHER_ROLE_SET = 1799; + */ + public static final int CID_OTHER_ROLE_SET_VALUE = 1799; + /** + * CID_OTHER_ONLINE_USER_INFO = 1800; + */ + public static final int CID_OTHER_ONLINE_USER_INFO_VALUE = 1800; + /** + * CID_OTHER_MSG_SERV_INFO = 1801; + */ + public static final int CID_OTHER_MSG_SERV_INFO_VALUE = 1801; + /** + * CID_OTHER_USER_STATUS_UPDATE = 1802; + */ + public static final int CID_OTHER_USER_STATUS_UPDATE_VALUE = 1802; + /** + * CID_OTHER_USER_CNT_UPDATE = 1803; + */ + public static final int CID_OTHER_USER_CNT_UPDATE_VALUE = 1803; + /** + * CID_OTHER_SERVER_KICK_USER = 1805; + */ + public static final int CID_OTHER_SERVER_KICK_USER_VALUE = 1805; + /** + * CID_OTHER_LOGIN_STATUS_NOTIFY = 1806; + */ + public static final int CID_OTHER_LOGIN_STATUS_NOTIFY_VALUE = 1806; + /** + * CID_OTHER_PUSH_TO_USER_REQ = 1807; + */ + public static final int CID_OTHER_PUSH_TO_USER_REQ_VALUE = 1807; + /** + * CID_OTHER_PUSH_TO_USER_RSP = 1808; + */ + public static final int CID_OTHER_PUSH_TO_USER_RSP_VALUE = 1808; + /** + * CID_OTHER_GET_SHIELD_REQ = 1809; + */ + public static final int CID_OTHER_GET_SHIELD_REQ_VALUE = 1809; + /** + * CID_OTHER_GET_SHIELD_RSP = 1810; + */ + public static final int CID_OTHER_GET_SHIELD_RSP_VALUE = 1810; + /** + * CID_OTHER_FILE_TRANSFER_REQ = 1841; + */ + public static final int CID_OTHER_FILE_TRANSFER_REQ_VALUE = 1841; + /** + * CID_OTHER_FILE_TRANSFER_RSP = 1842; + */ + public static final int CID_OTHER_FILE_TRANSFER_RSP_VALUE = 1842; + /** + * CID_OTHER_FILE_SERVER_IP_REQ = 1843; + */ + public static final int CID_OTHER_FILE_SERVER_IP_REQ_VALUE = 1843; + /** + * CID_OTHER_FILE_SERVER_IP_RSP = 1844; + */ + public static final int CID_OTHER_FILE_SERVER_IP_RSP_VALUE = 1844; + + + public final int getNumber() { return value; } + + public static OtherCmdID valueOf(int value) { + switch (value) { + case 1793: return CID_OTHER_HEARTBEAT; + case 1794: return CID_OTHER_STOP_RECV_PACKET; + case 1795: return CID_OTHER_VALIDATE_REQ; + case 1796: return CID_OTHER_VALIDATE_RSP; + case 1797: return CID_OTHER_GET_DEVICE_TOKEN_REQ; + case 1798: return CID_OTHER_GET_DEVICE_TOKEN_RSP; + case 1799: return CID_OTHER_ROLE_SET; + case 1800: return CID_OTHER_ONLINE_USER_INFO; + case 1801: return CID_OTHER_MSG_SERV_INFO; + case 1802: return CID_OTHER_USER_STATUS_UPDATE; + case 1803: return CID_OTHER_USER_CNT_UPDATE; + case 1805: return CID_OTHER_SERVER_KICK_USER; + case 1806: return CID_OTHER_LOGIN_STATUS_NOTIFY; + case 1807: return CID_OTHER_PUSH_TO_USER_REQ; + case 1808: return CID_OTHER_PUSH_TO_USER_RSP; + case 1809: return CID_OTHER_GET_SHIELD_REQ; + case 1810: return CID_OTHER_GET_SHIELD_RSP; + case 1841: return CID_OTHER_FILE_TRANSFER_REQ; + case 1842: return CID_OTHER_FILE_TRANSFER_RSP; + case 1843: return CID_OTHER_FILE_SERVER_IP_REQ; + case 1844: return CID_OTHER_FILE_SERVER_IP_RSP; + default: return null; + } + } + + public static com.google.protobuf.Internal.EnumLiteMap + internalGetValueMap() { + return internalValueMap; + } + private static com.google.protobuf.Internal.EnumLiteMap + internalValueMap = + new com.google.protobuf.Internal.EnumLiteMap() { + public OtherCmdID findValueByNumber(int number) { + return OtherCmdID.valueOf(number); + } + }; + + private final int value; + + private OtherCmdID(int index, int value) { + this.value = value; + } + + // @@protoc_insertion_point(enum_scope:IM.BaseDefine.OtherCmdID) + } + + /** + * Protobuf enum {@code IM.BaseDefine.InternalCmdID} + */ + public enum InternalCmdID + implements com.google.protobuf.Internal.EnumLite { + /** + * CID_INTERNAL_SYNC_AUTH_INFO_REQ = 2049; + */ + CID_INTERNAL_SYNC_AUTH_INFO_REQ(0, 2049), + /** + * CID_INTERNAL_SYNC_AUTH_INFO_RSP = 2050; + */ + CID_INTERNAL_SYNC_AUTH_INFO_RSP(1, 2050), + /** + * CID_INTERNAL_USER_ID_BY_NICK_NAME_REQ = 2051; + */ + CID_INTERNAL_USER_ID_BY_NICK_NAME_REQ(2, 2051), + /** + * CID_INTERNAL_USER_ID_BY_NICK_NAME_RSP = 2052; + */ + CID_INTERNAL_USER_ID_BY_NICK_NAME_RSP(3, 2052), + ; + + /** + * CID_INTERNAL_SYNC_AUTH_INFO_REQ = 2049; + */ + public static final int CID_INTERNAL_SYNC_AUTH_INFO_REQ_VALUE = 2049; + /** + * CID_INTERNAL_SYNC_AUTH_INFO_RSP = 2050; + */ + public static final int CID_INTERNAL_SYNC_AUTH_INFO_RSP_VALUE = 2050; + /** + * CID_INTERNAL_USER_ID_BY_NICK_NAME_REQ = 2051; + */ + public static final int CID_INTERNAL_USER_ID_BY_NICK_NAME_REQ_VALUE = 2051; + /** + * CID_INTERNAL_USER_ID_BY_NICK_NAME_RSP = 2052; + */ + public static final int CID_INTERNAL_USER_ID_BY_NICK_NAME_RSP_VALUE = 2052; + + + public final int getNumber() { return value; } + + public static InternalCmdID valueOf(int value) { + switch (value) { + case 2049: return CID_INTERNAL_SYNC_AUTH_INFO_REQ; + case 2050: return CID_INTERNAL_SYNC_AUTH_INFO_RSP; + case 2051: return CID_INTERNAL_USER_ID_BY_NICK_NAME_REQ; + case 2052: return CID_INTERNAL_USER_ID_BY_NICK_NAME_RSP; + default: return null; + } + } + + public static com.google.protobuf.Internal.EnumLiteMap + internalGetValueMap() { + return internalValueMap; + } + private static com.google.protobuf.Internal.EnumLiteMap + internalValueMap = + new com.google.protobuf.Internal.EnumLiteMap() { + public InternalCmdID findValueByNumber(int number) { + return InternalCmdID.valueOf(number); + } + }; + + private final int value; + + private InternalCmdID(int index, int value) { + this.value = value; + } + + // @@protoc_insertion_point(enum_scope:IM.BaseDefine.InternalCmdID) + } + + /** + * Protobuf enum {@code IM.BaseDefine.ResultType} + */ + public enum ResultType + implements com.google.protobuf.Internal.EnumLite { + /** + * REFUSE_REASON_NONE = 0; + */ + REFUSE_REASON_NONE(0, 0), + /** + * REFUSE_REASON_NO_MSG_SERVER = 1; + */ + REFUSE_REASON_NO_MSG_SERVER(1, 1), + /** + * REFUSE_REASON_MSG_SERVER_FULL = 2; + */ + REFUSE_REASON_MSG_SERVER_FULL(2, 2), + /** + * REFUSE_REASON_NO_DB_SERVER = 3; + */ + REFUSE_REASON_NO_DB_SERVER(3, 3), + /** + * REFUSE_REASON_NO_LOGIN_SERVER = 4; + */ + REFUSE_REASON_NO_LOGIN_SERVER(4, 4), + /** + * REFUSE_REASON_NO_ROUTE_SERVER = 5; + */ + REFUSE_REASON_NO_ROUTE_SERVER(5, 5), + /** + * REFUSE_REASON_DB_VALIDATE_FAILED = 6; + */ + REFUSE_REASON_DB_VALIDATE_FAILED(6, 6), + /** + * REFUSE_REASON_VERSION_TOO_OLD = 7; + */ + REFUSE_REASON_VERSION_TOO_OLD(7, 7), + ; + + /** + * REFUSE_REASON_NONE = 0; + */ + public static final int REFUSE_REASON_NONE_VALUE = 0; + /** + * REFUSE_REASON_NO_MSG_SERVER = 1; + */ + public static final int REFUSE_REASON_NO_MSG_SERVER_VALUE = 1; + /** + * REFUSE_REASON_MSG_SERVER_FULL = 2; + */ + public static final int REFUSE_REASON_MSG_SERVER_FULL_VALUE = 2; + /** + * REFUSE_REASON_NO_DB_SERVER = 3; + */ + public static final int REFUSE_REASON_NO_DB_SERVER_VALUE = 3; + /** + * REFUSE_REASON_NO_LOGIN_SERVER = 4; + */ + public static final int REFUSE_REASON_NO_LOGIN_SERVER_VALUE = 4; + /** + * REFUSE_REASON_NO_ROUTE_SERVER = 5; + */ + public static final int REFUSE_REASON_NO_ROUTE_SERVER_VALUE = 5; + /** + * REFUSE_REASON_DB_VALIDATE_FAILED = 6; + */ + public static final int REFUSE_REASON_DB_VALIDATE_FAILED_VALUE = 6; + /** + * REFUSE_REASON_VERSION_TOO_OLD = 7; + */ + public static final int REFUSE_REASON_VERSION_TOO_OLD_VALUE = 7; + + + public final int getNumber() { return value; } + + public static ResultType valueOf(int value) { + switch (value) { + case 0: return REFUSE_REASON_NONE; + case 1: return REFUSE_REASON_NO_MSG_SERVER; + case 2: return REFUSE_REASON_MSG_SERVER_FULL; + case 3: return REFUSE_REASON_NO_DB_SERVER; + case 4: return REFUSE_REASON_NO_LOGIN_SERVER; + case 5: return REFUSE_REASON_NO_ROUTE_SERVER; + case 6: return REFUSE_REASON_DB_VALIDATE_FAILED; + case 7: return REFUSE_REASON_VERSION_TOO_OLD; + default: return null; + } + } + + public static com.google.protobuf.Internal.EnumLiteMap + internalGetValueMap() { + return internalValueMap; + } + private static com.google.protobuf.Internal.EnumLiteMap + internalValueMap = + new com.google.protobuf.Internal.EnumLiteMap() { + public ResultType findValueByNumber(int number) { + return ResultType.valueOf(number); + } + }; + + private final int value; + + private ResultType(int index, int value) { + this.value = value; + } + + // @@protoc_insertion_point(enum_scope:IM.BaseDefine.ResultType) + } + + /** + * Protobuf enum {@code IM.BaseDefine.KickReasonType} + */ + public enum KickReasonType + implements com.google.protobuf.Internal.EnumLite { + /** + * KICK_REASON_DUPLICATE_USER = 1; + */ + KICK_REASON_DUPLICATE_USER(0, 1), + /** + * KICK_REASON_MOBILE_KICK = 2; + */ + KICK_REASON_MOBILE_KICK(1, 2), + ; + + /** + * KICK_REASON_DUPLICATE_USER = 1; + */ + public static final int KICK_REASON_DUPLICATE_USER_VALUE = 1; + /** + * KICK_REASON_MOBILE_KICK = 2; + */ + public static final int KICK_REASON_MOBILE_KICK_VALUE = 2; + + + public final int getNumber() { return value; } + + public static KickReasonType valueOf(int value) { + switch (value) { + case 1: return KICK_REASON_DUPLICATE_USER; + case 2: return KICK_REASON_MOBILE_KICK; + default: return null; + } + } + + public static com.google.protobuf.Internal.EnumLiteMap + internalGetValueMap() { + return internalValueMap; + } + private static com.google.protobuf.Internal.EnumLiteMap + internalValueMap = + new com.google.protobuf.Internal.EnumLiteMap() { + public KickReasonType findValueByNumber(int number) { + return KickReasonType.valueOf(number); + } + }; + + private final int value; + + private KickReasonType(int index, int value) { + this.value = value; + } + + // @@protoc_insertion_point(enum_scope:IM.BaseDefine.KickReasonType) + } + + /** + * Protobuf enum {@code IM.BaseDefine.OnlineListType} + */ + public enum OnlineListType + implements com.google.protobuf.Internal.EnumLite { + /** + * ONLINE_LIST_TYPE_FRIEND_LIST = 1; + */ + ONLINE_LIST_TYPE_FRIEND_LIST(0, 1), + ; + + /** + * ONLINE_LIST_TYPE_FRIEND_LIST = 1; + */ + public static final int ONLINE_LIST_TYPE_FRIEND_LIST_VALUE = 1; + + + public final int getNumber() { return value; } + + public static OnlineListType valueOf(int value) { + switch (value) { + case 1: return ONLINE_LIST_TYPE_FRIEND_LIST; + default: return null; + } + } + + public static com.google.protobuf.Internal.EnumLiteMap + internalGetValueMap() { + return internalValueMap; + } + private static com.google.protobuf.Internal.EnumLiteMap + internalValueMap = + new com.google.protobuf.Internal.EnumLiteMap() { + public OnlineListType findValueByNumber(int number) { + return OnlineListType.valueOf(number); + } + }; + + private final int value; + + private OnlineListType(int index, int value) { + this.value = value; + } + + // @@protoc_insertion_point(enum_scope:IM.BaseDefine.OnlineListType) + } + + /** + * Protobuf enum {@code IM.BaseDefine.UserStatType} + */ + public enum UserStatType + implements com.google.protobuf.Internal.EnumLite { + /** + * USER_STATUS_ONLINE = 1; + */ + USER_STATUS_ONLINE(0, 1), + /** + * USER_STATUS_OFFLINE = 2; + */ + USER_STATUS_OFFLINE(1, 2), + /** + * USER_STATUS_LEAVE = 3; + */ + USER_STATUS_LEAVE(2, 3), + ; + + /** + * USER_STATUS_ONLINE = 1; + */ + public static final int USER_STATUS_ONLINE_VALUE = 1; + /** + * USER_STATUS_OFFLINE = 2; + */ + public static final int USER_STATUS_OFFLINE_VALUE = 2; + /** + * USER_STATUS_LEAVE = 3; + */ + public static final int USER_STATUS_LEAVE_VALUE = 3; + + + public final int getNumber() { return value; } + + public static UserStatType valueOf(int value) { + switch (value) { + case 1: return USER_STATUS_ONLINE; + case 2: return USER_STATUS_OFFLINE; + case 3: return USER_STATUS_LEAVE; + default: return null; + } + } + + public static com.google.protobuf.Internal.EnumLiteMap + internalGetValueMap() { + return internalValueMap; + } + private static com.google.protobuf.Internal.EnumLiteMap + internalValueMap = + new com.google.protobuf.Internal.EnumLiteMap() { + public UserStatType findValueByNumber(int number) { + return UserStatType.valueOf(number); + } + }; + + private final int value; + + private UserStatType(int index, int value) { + this.value = value; + } + + // @@protoc_insertion_point(enum_scope:IM.BaseDefine.UserStatType) + } + + /** + * Protobuf enum {@code IM.BaseDefine.SessionType} + */ + public enum SessionType + implements com.google.protobuf.Internal.EnumLite { + /** + * SESSION_TYPE_SINGLE = 1; + * + *
+     *单个用户会话
+     * 
+ */ + SESSION_TYPE_SINGLE(0, 1), + /** + * SESSION_TYPE_GROUP = 2; + * + *
+     *群会话
+     * 
+ */ + SESSION_TYPE_GROUP(1, 2), + ; + + /** + * SESSION_TYPE_SINGLE = 1; + * + *
+     *单个用户会话
+     * 
+ */ + public static final int SESSION_TYPE_SINGLE_VALUE = 1; + /** + * SESSION_TYPE_GROUP = 2; + * + *
+     *群会话
+     * 
+ */ + public static final int SESSION_TYPE_GROUP_VALUE = 2; + + + public final int getNumber() { return value; } + + public static SessionType valueOf(int value) { + switch (value) { + case 1: return SESSION_TYPE_SINGLE; + case 2: return SESSION_TYPE_GROUP; + default: return null; + } + } + + public static com.google.protobuf.Internal.EnumLiteMap + internalGetValueMap() { + return internalValueMap; + } + private static com.google.protobuf.Internal.EnumLiteMap + internalValueMap = + new com.google.protobuf.Internal.EnumLiteMap() { + public SessionType findValueByNumber(int number) { + return SessionType.valueOf(number); + } + }; + + private final int value; + + private SessionType(int index, int value) { + this.value = value; + } + + // @@protoc_insertion_point(enum_scope:IM.BaseDefine.SessionType) + } + + /** + * Protobuf enum {@code IM.BaseDefine.MsgType} + */ + public enum MsgType + implements com.google.protobuf.Internal.EnumLite { + /** + * MSG_TYPE_SINGLE_TEXT = 1; + */ + MSG_TYPE_SINGLE_TEXT(0, 1), + /** + * MSG_TYPE_SINGLE_AUDIO = 2; + */ + MSG_TYPE_SINGLE_AUDIO(1, 2), + /** + * MSG_TYPE_GROUP_TEXT = 17; + */ + MSG_TYPE_GROUP_TEXT(2, 17), + /** + * MSG_TYPE_GROUP_AUDIO = 18; + */ + MSG_TYPE_GROUP_AUDIO(3, 18), + ; + + /** + * MSG_TYPE_SINGLE_TEXT = 1; + */ + public static final int MSG_TYPE_SINGLE_TEXT_VALUE = 1; + /** + * MSG_TYPE_SINGLE_AUDIO = 2; + */ + public static final int MSG_TYPE_SINGLE_AUDIO_VALUE = 2; + /** + * MSG_TYPE_GROUP_TEXT = 17; + */ + public static final int MSG_TYPE_GROUP_TEXT_VALUE = 17; + /** + * MSG_TYPE_GROUP_AUDIO = 18; + */ + public static final int MSG_TYPE_GROUP_AUDIO_VALUE = 18; + + + public final int getNumber() { return value; } + + public static MsgType valueOf(int value) { + switch (value) { + case 1: return MSG_TYPE_SINGLE_TEXT; + case 2: return MSG_TYPE_SINGLE_AUDIO; + case 17: return MSG_TYPE_GROUP_TEXT; + case 18: return MSG_TYPE_GROUP_AUDIO; + default: return null; + } + } + + public static com.google.protobuf.Internal.EnumLiteMap + internalGetValueMap() { + return internalValueMap; + } + private static com.google.protobuf.Internal.EnumLiteMap + internalValueMap = + new com.google.protobuf.Internal.EnumLiteMap() { + public MsgType findValueByNumber(int number) { + return MsgType.valueOf(number); + } + }; + + private final int value; + + private MsgType(int index, int value) { + this.value = value; + } + + // @@protoc_insertion_point(enum_scope:IM.BaseDefine.MsgType) + } + + /** + * Protobuf enum {@code IM.BaseDefine.ClientType} + */ + public enum ClientType + implements com.google.protobuf.Internal.EnumLite { + /** + * CLIENT_TYPE_WINDOWS = 1; + */ + CLIENT_TYPE_WINDOWS(0, 1), + /** + * CLIENT_TYPE_MAC = 2; + */ + CLIENT_TYPE_MAC(1, 2), + /** + * CLIENT_TYPE_IOS = 17; + */ + CLIENT_TYPE_IOS(2, 17), + /** + * CLIENT_TYPE_ANDROID = 18; + */ + CLIENT_TYPE_ANDROID(3, 18), + ; + + /** + * CLIENT_TYPE_WINDOWS = 1; + */ + public static final int CLIENT_TYPE_WINDOWS_VALUE = 1; + /** + * CLIENT_TYPE_MAC = 2; + */ + public static final int CLIENT_TYPE_MAC_VALUE = 2; + /** + * CLIENT_TYPE_IOS = 17; + */ + public static final int CLIENT_TYPE_IOS_VALUE = 17; + /** + * CLIENT_TYPE_ANDROID = 18; + */ + public static final int CLIENT_TYPE_ANDROID_VALUE = 18; + + + public final int getNumber() { return value; } + + public static ClientType valueOf(int value) { + switch (value) { + case 1: return CLIENT_TYPE_WINDOWS; + case 2: return CLIENT_TYPE_MAC; + case 17: return CLIENT_TYPE_IOS; + case 18: return CLIENT_TYPE_ANDROID; + default: return null; + } + } + + public static com.google.protobuf.Internal.EnumLiteMap + internalGetValueMap() { + return internalValueMap; + } + private static com.google.protobuf.Internal.EnumLiteMap + internalValueMap = + new com.google.protobuf.Internal.EnumLiteMap() { + public ClientType findValueByNumber(int number) { + return ClientType.valueOf(number); + } + }; + + private final int value; + + private ClientType(int index, int value) { + this.value = value; + } + + // @@protoc_insertion_point(enum_scope:IM.BaseDefine.ClientType) + } + + /** + * Protobuf enum {@code IM.BaseDefine.GroupType} + */ + public enum GroupType + implements com.google.protobuf.Internal.EnumLite { + /** + * GROUP_TYPE_NORMAL = 1; + */ + GROUP_TYPE_NORMAL(0, 1), + /** + * GROUP_TYPE_TMP = 2; + */ + GROUP_TYPE_TMP(1, 2), + ; + + /** + * GROUP_TYPE_NORMAL = 1; + */ + public static final int GROUP_TYPE_NORMAL_VALUE = 1; + /** + * GROUP_TYPE_TMP = 2; + */ + public static final int GROUP_TYPE_TMP_VALUE = 2; + + + public final int getNumber() { return value; } + + public static GroupType valueOf(int value) { + switch (value) { + case 1: return GROUP_TYPE_NORMAL; + case 2: return GROUP_TYPE_TMP; + default: return null; + } + } + + public static com.google.protobuf.Internal.EnumLiteMap + internalGetValueMap() { + return internalValueMap; + } + private static com.google.protobuf.Internal.EnumLiteMap + internalValueMap = + new com.google.protobuf.Internal.EnumLiteMap() { + public GroupType findValueByNumber(int number) { + return GroupType.valueOf(number); + } + }; + + private final int value; + + private GroupType(int index, int value) { + this.value = value; + } + + // @@protoc_insertion_point(enum_scope:IM.BaseDefine.GroupType) + } + + /** + * Protobuf enum {@code IM.BaseDefine.GroupModifyType} + */ + public enum GroupModifyType + implements com.google.protobuf.Internal.EnumLite { + /** + * GROUP_MODIFY_TYPE_ADD = 1; + */ + GROUP_MODIFY_TYPE_ADD(0, 1), + /** + * GROUP_MODIFY_TYPE_DEL = 2; + */ + GROUP_MODIFY_TYPE_DEL(1, 2), + ; + + /** + * GROUP_MODIFY_TYPE_ADD = 1; + */ + public static final int GROUP_MODIFY_TYPE_ADD_VALUE = 1; + /** + * GROUP_MODIFY_TYPE_DEL = 2; + */ + public static final int GROUP_MODIFY_TYPE_DEL_VALUE = 2; + + + public final int getNumber() { return value; } + + public static GroupModifyType valueOf(int value) { + switch (value) { + case 1: return GROUP_MODIFY_TYPE_ADD; + case 2: return GROUP_MODIFY_TYPE_DEL; + default: return null; + } + } + + public static com.google.protobuf.Internal.EnumLiteMap + internalGetValueMap() { + return internalValueMap; + } + private static com.google.protobuf.Internal.EnumLiteMap + internalValueMap = + new com.google.protobuf.Internal.EnumLiteMap() { + public GroupModifyType findValueByNumber(int number) { + return GroupModifyType.valueOf(number); + } + }; + + private final int value; + + private GroupModifyType(int index, int value) { + this.value = value; + } + + // @@protoc_insertion_point(enum_scope:IM.BaseDefine.GroupModifyType) + } + + /** + * Protobuf enum {@code IM.BaseDefine.FileType} + */ + public enum FileType + implements com.google.protobuf.Internal.EnumLite { + /** + * FILE_TYPE_ONLINE = 1; + */ + FILE_TYPE_ONLINE(0, 1), + /** + * FILE_TYPE_OFFLINE = 2; + */ + FILE_TYPE_OFFLINE(1, 2), + ; + + /** + * FILE_TYPE_ONLINE = 1; + */ + public static final int FILE_TYPE_ONLINE_VALUE = 1; + /** + * FILE_TYPE_OFFLINE = 2; + */ + public static final int FILE_TYPE_OFFLINE_VALUE = 2; + + + public final int getNumber() { return value; } + + public static FileType valueOf(int value) { + switch (value) { + case 1: return FILE_TYPE_ONLINE; + case 2: return FILE_TYPE_OFFLINE; + default: return null; + } + } + + public static com.google.protobuf.Internal.EnumLiteMap + internalGetValueMap() { + return internalValueMap; + } + private static com.google.protobuf.Internal.EnumLiteMap + internalValueMap = + new com.google.protobuf.Internal.EnumLiteMap() { + public FileType findValueByNumber(int number) { + return FileType.valueOf(number); + } + }; + + private final int value; + + private FileType(int index, int value) { + this.value = value; + } + + // @@protoc_insertion_point(enum_scope:IM.BaseDefine.FileType) + } + + /** + * Protobuf enum {@code IM.BaseDefine.ClientFileState} + */ + public enum ClientFileState + implements com.google.protobuf.Internal.EnumLite { + /** + * CLIENT_FILE_PEER_READY = 0; + */ + CLIENT_FILE_PEER_READY(0, 0), + /** + * CLIENT_FILE_CANCEL = 1; + */ + CLIENT_FILE_CANCEL(1, 1), + /** + * CLIENT_FILE_REFUSE = 2; + */ + CLIENT_FILE_REFUSE(2, 2), + /** + * CLIENT_FILE_DONE = 3; + */ + CLIENT_FILE_DONE(3, 3), + ; + + /** + * CLIENT_FILE_PEER_READY = 0; + */ + public static final int CLIENT_FILE_PEER_READY_VALUE = 0; + /** + * CLIENT_FILE_CANCEL = 1; + */ + public static final int CLIENT_FILE_CANCEL_VALUE = 1; + /** + * CLIENT_FILE_REFUSE = 2; + */ + public static final int CLIENT_FILE_REFUSE_VALUE = 2; + /** + * CLIENT_FILE_DONE = 3; + */ + public static final int CLIENT_FILE_DONE_VALUE = 3; + + + public final int getNumber() { return value; } + + public static ClientFileState valueOf(int value) { + switch (value) { + case 0: return CLIENT_FILE_PEER_READY; + case 1: return CLIENT_FILE_CANCEL; + case 2: return CLIENT_FILE_REFUSE; + case 3: return CLIENT_FILE_DONE; + default: return null; + } + } + + public static com.google.protobuf.Internal.EnumLiteMap + internalGetValueMap() { + return internalValueMap; + } + private static com.google.protobuf.Internal.EnumLiteMap + internalValueMap = + new com.google.protobuf.Internal.EnumLiteMap() { + public ClientFileState findValueByNumber(int number) { + return ClientFileState.valueOf(number); + } + }; + + private final int value; + + private ClientFileState(int index, int value) { + this.value = value; + } + + // @@protoc_insertion_point(enum_scope:IM.BaseDefine.ClientFileState) + } + + /** + * Protobuf enum {@code IM.BaseDefine.ClientFileRole} + */ + public enum ClientFileRole + implements com.google.protobuf.Internal.EnumLite { + /** + * CLIENT_REALTIME_SENDER = 1; + */ + CLIENT_REALTIME_SENDER(0, 1), + /** + * CLIENT_REALTIME_RECVER = 2; + */ + CLIENT_REALTIME_RECVER(1, 2), + /** + * CLIENT_OFFLINE_UPLOAD = 3; + */ + CLIENT_OFFLINE_UPLOAD(2, 3), + /** + * CLIENT_OFFLINE_DOWNLOAD = 4; + */ + CLIENT_OFFLINE_DOWNLOAD(3, 4), + ; + + /** + * CLIENT_REALTIME_SENDER = 1; + */ + public static final int CLIENT_REALTIME_SENDER_VALUE = 1; + /** + * CLIENT_REALTIME_RECVER = 2; + */ + public static final int CLIENT_REALTIME_RECVER_VALUE = 2; + /** + * CLIENT_OFFLINE_UPLOAD = 3; + */ + public static final int CLIENT_OFFLINE_UPLOAD_VALUE = 3; + /** + * CLIENT_OFFLINE_DOWNLOAD = 4; + */ + public static final int CLIENT_OFFLINE_DOWNLOAD_VALUE = 4; + + + public final int getNumber() { return value; } + + public static ClientFileRole valueOf(int value) { + switch (value) { + case 1: return CLIENT_REALTIME_SENDER; + case 2: return CLIENT_REALTIME_RECVER; + case 3: return CLIENT_OFFLINE_UPLOAD; + case 4: return CLIENT_OFFLINE_DOWNLOAD; + default: return null; + } + } + + public static com.google.protobuf.Internal.EnumLiteMap + internalGetValueMap() { + return internalValueMap; + } + private static com.google.protobuf.Internal.EnumLiteMap + internalValueMap = + new com.google.protobuf.Internal.EnumLiteMap() { + public ClientFileRole findValueByNumber(int number) { + return ClientFileRole.valueOf(number); + } + }; + + private final int value; + + private ClientFileRole(int index, int value) { + this.value = value; + } + + // @@protoc_insertion_point(enum_scope:IM.BaseDefine.ClientFileRole) + } + + /** + * Protobuf enum {@code IM.BaseDefine.FileServerError} + */ + public enum FileServerError + implements com.google.protobuf.Internal.EnumLite { + /** + * FILE_SERVER_ERRNO_OK = 0; + */ + FILE_SERVER_ERRNO_OK(0, 0), + /** + * FILE_SERVER_ERRNO_CREATE_TASK_ID_ERROR = 1; + */ + FILE_SERVER_ERRNO_CREATE_TASK_ID_ERROR(1, 1), + /** + * FILE_SERVER_ERRNO_CREATE_TASK_ERROR = 2; + */ + FILE_SERVER_ERRNO_CREATE_TASK_ERROR(2, 2), + /** + * FILE_SERVER_ERRNO_LOGIN_INVALID_TOKEN = 3; + */ + FILE_SERVER_ERRNO_LOGIN_INVALID_TOKEN(3, 3), + /** + * FILE_SERVER_ERRNO_INVALID_USER_FOR_TASK = 4; + */ + FILE_SERVER_ERRNO_INVALID_USER_FOR_TASK(4, 4), + /** + * FILE_SERVER_ERRNO_PULL_DATA_WITH_INVALID_TASK_ID = 5; + */ + FILE_SERVER_ERRNO_PULL_DATA_WITH_INVALID_TASK_ID(5, 5), + /** + * FILE_SERVER_ERRNO_PULL_DATA_ILLIEAGE_USER = 6; + */ + FILE_SERVER_ERRNO_PULL_DATA_ILLIEAGE_USER(6, 6), + /** + * FILE_SERVER_ERRNO_PULL_DATA_MKDIR_ERROR = 7; + */ + FILE_SERVER_ERRNO_PULL_DATA_MKDIR_ERROR(7, 7), + /** + * FILE_SERVER_ERRNO_PULL_DATA_OPEN_FILE_ERROR = 8; + */ + FILE_SERVER_ERRNO_PULL_DATA_OPEN_FILE_ERROR(8, 8), + /** + * FILE_SERVER_ERRNO_PULL_DATA_READ_FILE_HEADER_ERROR = 9; + */ + FILE_SERVER_ERRNO_PULL_DATA_READ_FILE_HEADER_ERROR(9, 9), + /** + * FILE_SERVER_ERRNO_PULL_DATA_ALLOC_MEM_ERROR = 10; + */ + FILE_SERVER_ERRNO_PULL_DATA_ALLOC_MEM_ERROR(10, 10), + /** + * FILE_SERVER_ERRNO_PULL_DATA_SEEK_OFFSET_ERROR = 11; + */ + FILE_SERVER_ERRNO_PULL_DATA_SEEK_OFFSET_ERROR(11, 11), + /** + * FILE_SERVER_ERRNO_PULL_DATA_FINISHED = 12; + */ + FILE_SERVER_ERRNO_PULL_DATA_FINISHED(12, 12), + ; + + /** + * FILE_SERVER_ERRNO_OK = 0; + */ + public static final int FILE_SERVER_ERRNO_OK_VALUE = 0; + /** + * FILE_SERVER_ERRNO_CREATE_TASK_ID_ERROR = 1; + */ + public static final int FILE_SERVER_ERRNO_CREATE_TASK_ID_ERROR_VALUE = 1; + /** + * FILE_SERVER_ERRNO_CREATE_TASK_ERROR = 2; + */ + public static final int FILE_SERVER_ERRNO_CREATE_TASK_ERROR_VALUE = 2; + /** + * FILE_SERVER_ERRNO_LOGIN_INVALID_TOKEN = 3; + */ + public static final int FILE_SERVER_ERRNO_LOGIN_INVALID_TOKEN_VALUE = 3; + /** + * FILE_SERVER_ERRNO_INVALID_USER_FOR_TASK = 4; + */ + public static final int FILE_SERVER_ERRNO_INVALID_USER_FOR_TASK_VALUE = 4; + /** + * FILE_SERVER_ERRNO_PULL_DATA_WITH_INVALID_TASK_ID = 5; + */ + public static final int FILE_SERVER_ERRNO_PULL_DATA_WITH_INVALID_TASK_ID_VALUE = 5; + /** + * FILE_SERVER_ERRNO_PULL_DATA_ILLIEAGE_USER = 6; + */ + public static final int FILE_SERVER_ERRNO_PULL_DATA_ILLIEAGE_USER_VALUE = 6; + /** + * FILE_SERVER_ERRNO_PULL_DATA_MKDIR_ERROR = 7; + */ + public static final int FILE_SERVER_ERRNO_PULL_DATA_MKDIR_ERROR_VALUE = 7; + /** + * FILE_SERVER_ERRNO_PULL_DATA_OPEN_FILE_ERROR = 8; + */ + public static final int FILE_SERVER_ERRNO_PULL_DATA_OPEN_FILE_ERROR_VALUE = 8; + /** + * FILE_SERVER_ERRNO_PULL_DATA_READ_FILE_HEADER_ERROR = 9; + */ + public static final int FILE_SERVER_ERRNO_PULL_DATA_READ_FILE_HEADER_ERROR_VALUE = 9; + /** + * FILE_SERVER_ERRNO_PULL_DATA_ALLOC_MEM_ERROR = 10; + */ + public static final int FILE_SERVER_ERRNO_PULL_DATA_ALLOC_MEM_ERROR_VALUE = 10; + /** + * FILE_SERVER_ERRNO_PULL_DATA_SEEK_OFFSET_ERROR = 11; + */ + public static final int FILE_SERVER_ERRNO_PULL_DATA_SEEK_OFFSET_ERROR_VALUE = 11; + /** + * FILE_SERVER_ERRNO_PULL_DATA_FINISHED = 12; + */ + public static final int FILE_SERVER_ERRNO_PULL_DATA_FINISHED_VALUE = 12; + + + public final int getNumber() { return value; } + + public static FileServerError valueOf(int value) { + switch (value) { + case 0: return FILE_SERVER_ERRNO_OK; + case 1: return FILE_SERVER_ERRNO_CREATE_TASK_ID_ERROR; + case 2: return FILE_SERVER_ERRNO_CREATE_TASK_ERROR; + case 3: return FILE_SERVER_ERRNO_LOGIN_INVALID_TOKEN; + case 4: return FILE_SERVER_ERRNO_INVALID_USER_FOR_TASK; + case 5: return FILE_SERVER_ERRNO_PULL_DATA_WITH_INVALID_TASK_ID; + case 6: return FILE_SERVER_ERRNO_PULL_DATA_ILLIEAGE_USER; + case 7: return FILE_SERVER_ERRNO_PULL_DATA_MKDIR_ERROR; + case 8: return FILE_SERVER_ERRNO_PULL_DATA_OPEN_FILE_ERROR; + case 9: return FILE_SERVER_ERRNO_PULL_DATA_READ_FILE_HEADER_ERROR; + case 10: return FILE_SERVER_ERRNO_PULL_DATA_ALLOC_MEM_ERROR; + case 11: return FILE_SERVER_ERRNO_PULL_DATA_SEEK_OFFSET_ERROR; + case 12: return FILE_SERVER_ERRNO_PULL_DATA_FINISHED; + default: return null; + } + } + + public static com.google.protobuf.Internal.EnumLiteMap + internalGetValueMap() { + return internalValueMap; + } + private static com.google.protobuf.Internal.EnumLiteMap + internalValueMap = + new com.google.protobuf.Internal.EnumLiteMap() { + public FileServerError findValueByNumber(int number) { + return FileServerError.valueOf(number); + } + }; + + private final int value; + + private FileServerError(int index, int value) { + this.value = value; + } + + // @@protoc_insertion_point(enum_scope:IM.BaseDefine.FileServerError) + } + + /** + * Protobuf enum {@code IM.BaseDefine.SessionStatusType} + */ + public enum SessionStatusType + implements com.google.protobuf.Internal.EnumLite { + /** + * SESSION_STATUS_OK = 0; + */ + SESSION_STATUS_OK(0, 0), + /** + * SESSION_STATUS_DELETE = 1; + */ + SESSION_STATUS_DELETE(1, 1), + ; + + /** + * SESSION_STATUS_OK = 0; + */ + public static final int SESSION_STATUS_OK_VALUE = 0; + /** + * SESSION_STATUS_DELETE = 1; + */ + public static final int SESSION_STATUS_DELETE_VALUE = 1; + + + public final int getNumber() { return value; } + + public static SessionStatusType valueOf(int value) { + switch (value) { + case 0: return SESSION_STATUS_OK; + case 1: return SESSION_STATUS_DELETE; + default: return null; + } + } + + public static com.google.protobuf.Internal.EnumLiteMap + internalGetValueMap() { + return internalValueMap; + } + private static com.google.protobuf.Internal.EnumLiteMap + internalValueMap = + new com.google.protobuf.Internal.EnumLiteMap() { + public SessionStatusType findValueByNumber(int number) { + return SessionStatusType.valueOf(number); + } + }; + + private final int value; + + private SessionStatusType(int index, int value) { + this.value = value; + } + + // @@protoc_insertion_point(enum_scope:IM.BaseDefine.SessionStatusType) + } + + /** + * Protobuf enum {@code IM.BaseDefine.DepartmentStatusType} + */ + public enum DepartmentStatusType + implements com.google.protobuf.Internal.EnumLite { + /** + * DEPT_STATUS_OK = 0; + */ + DEPT_STATUS_OK(0, 0), + /** + * DEPT_STATUS_DELETE = 1; + */ + DEPT_STATUS_DELETE(1, 1), + ; + + /** + * DEPT_STATUS_OK = 0; + */ + public static final int DEPT_STATUS_OK_VALUE = 0; + /** + * DEPT_STATUS_DELETE = 1; + */ + public static final int DEPT_STATUS_DELETE_VALUE = 1; + + + public final int getNumber() { return value; } + + public static DepartmentStatusType valueOf(int value) { + switch (value) { + case 0: return DEPT_STATUS_OK; + case 1: return DEPT_STATUS_DELETE; + default: return null; + } + } + + public static com.google.protobuf.Internal.EnumLiteMap + internalGetValueMap() { + return internalValueMap; + } + private static com.google.protobuf.Internal.EnumLiteMap + internalValueMap = + new com.google.protobuf.Internal.EnumLiteMap() { + public DepartmentStatusType findValueByNumber(int number) { + return DepartmentStatusType.valueOf(number); + } + }; + + private final int value; + + private DepartmentStatusType(int index, int value) { + this.value = value; + } + + // @@protoc_insertion_point(enum_scope:IM.BaseDefine.DepartmentStatusType) + } + + public interface IpAddrOrBuilder extends + // @@protoc_insertion_point(interface_extends:IM.BaseDefine.IpAddr) + com.google.protobuf.MessageLiteOrBuilder { + + /** + * required string ip = 1; + */ + boolean hasIp(); + /** + * required string ip = 1; + */ + java.lang.String getIp(); + /** + * required string ip = 1; + */ + com.google.protobuf.ByteString + getIpBytes(); + + /** + * required uint32 port = 2; + */ + boolean hasPort(); + /** + * required uint32 port = 2; + */ + int getPort(); + } + /** + * Protobuf type {@code IM.BaseDefine.IpAddr} + */ + public static final class IpAddr extends + com.google.protobuf.GeneratedMessageLite implements + // @@protoc_insertion_point(message_implements:IM.BaseDefine.IpAddr) + IpAddrOrBuilder { + // Use IpAddr.newBuilder() to construct. + private IpAddr(com.google.protobuf.GeneratedMessageLite.Builder builder) { + super(builder); + this.unknownFields = builder.getUnknownFields(); + } + private IpAddr(boolean noInit) { this.unknownFields = com.google.protobuf.ByteString.EMPTY;} + + private static final IpAddr defaultInstance; + public static IpAddr getDefaultInstance() { + return defaultInstance; + } + + public IpAddr getDefaultInstanceForType() { + return defaultInstance; + } + + private final com.google.protobuf.ByteString unknownFields; + private IpAddr( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + initFields(); + int mutable_bitField0_ = 0; + com.google.protobuf.ByteString.Output unknownFieldsOutput = + com.google.protobuf.ByteString.newOutput(); + com.google.protobuf.CodedOutputStream unknownFieldsCodedOutput = + com.google.protobuf.CodedOutputStream.newInstance( + unknownFieldsOutput); + try { + boolean done = false; + while (!done) { + int tag = input.readTag(); + switch (tag) { + case 0: + done = true; + break; + default: { + if (!parseUnknownField(input, unknownFieldsCodedOutput, + extensionRegistry, tag)) { + done = true; + } + break; + } + case 10: { + com.google.protobuf.ByteString bs = input.readBytes(); + bitField0_ |= 0x00000001; + ip_ = bs; + break; + } + case 16: { + bitField0_ |= 0x00000002; + port_ = input.readUInt32(); + break; + } + } + } + } catch (com.google.protobuf.InvalidProtocolBufferException e) { + throw e.setUnfinishedMessage(this); + } catch (java.io.IOException e) { + throw new com.google.protobuf.InvalidProtocolBufferException( + e.getMessage()).setUnfinishedMessage(this); + } finally { + try { + unknownFieldsCodedOutput.flush(); + } catch (java.io.IOException e) { + // Should not happen + } finally { + unknownFields = unknownFieldsOutput.toByteString(); + } + makeExtensionsImmutable(); + } + } + public static com.google.protobuf.Parser PARSER = + new com.google.protobuf.AbstractParser() { + public IpAddr parsePartialFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return new IpAddr(input, extensionRegistry); + } + }; + + @java.lang.Override + public com.google.protobuf.Parser getParserForType() { + return PARSER; + } + + private int bitField0_; + public static final int IP_FIELD_NUMBER = 1; + private java.lang.Object ip_; + /** + * required string ip = 1; + */ + public boolean hasIp() { + return ((bitField0_ & 0x00000001) == 0x00000001); + } + /** + * required string ip = 1; + */ + public java.lang.String getIp() { + java.lang.Object ref = ip_; + if (ref instanceof java.lang.String) { + return (java.lang.String) ref; + } else { + com.google.protobuf.ByteString bs = + (com.google.protobuf.ByteString) ref; + java.lang.String s = bs.toStringUtf8(); + if (bs.isValidUtf8()) { + ip_ = s; + } + return s; + } + } + /** + * required string ip = 1; + */ + public com.google.protobuf.ByteString + getIpBytes() { + java.lang.Object ref = ip_; + if (ref instanceof java.lang.String) { + com.google.protobuf.ByteString b = + com.google.protobuf.ByteString.copyFromUtf8( + (java.lang.String) ref); + ip_ = b; + return b; + } else { + return (com.google.protobuf.ByteString) ref; + } + } + + public static final int PORT_FIELD_NUMBER = 2; + private int port_; + /** + * required uint32 port = 2; + */ + public boolean hasPort() { + return ((bitField0_ & 0x00000002) == 0x00000002); + } + /** + * required uint32 port = 2; + */ + public int getPort() { + return port_; + } + + private void initFields() { + ip_ = ""; + port_ = 0; + } + private byte memoizedIsInitialized = -1; + public final boolean isInitialized() { + byte isInitialized = memoizedIsInitialized; + if (isInitialized == 1) return true; + if (isInitialized == 0) return false; + + if (!hasIp()) { + memoizedIsInitialized = 0; + return false; + } + if (!hasPort()) { + memoizedIsInitialized = 0; + return false; + } + memoizedIsInitialized = 1; + return true; + } + + public void writeTo(com.google.protobuf.CodedOutputStream output) + throws java.io.IOException { + getSerializedSize(); + if (((bitField0_ & 0x00000001) == 0x00000001)) { + output.writeBytes(1, getIpBytes()); + } + if (((bitField0_ & 0x00000002) == 0x00000002)) { + output.writeUInt32(2, port_); + } + output.writeRawBytes(unknownFields); + } + + private int memoizedSerializedSize = -1; + public int getSerializedSize() { + int size = memoizedSerializedSize; + if (size != -1) return size; + + size = 0; + if (((bitField0_ & 0x00000001) == 0x00000001)) { + size += com.google.protobuf.CodedOutputStream + .computeBytesSize(1, getIpBytes()); + } + if (((bitField0_ & 0x00000002) == 0x00000002)) { + size += com.google.protobuf.CodedOutputStream + .computeUInt32Size(2, port_); + } + size += unknownFields.size(); + memoizedSerializedSize = size; + return size; + } + + private static final long serialVersionUID = 0L; + @java.lang.Override + protected java.lang.Object writeReplace() + throws java.io.ObjectStreamException { + return super.writeReplace(); + } + + public static com.mogujie.tt.protobuf.IMBaseDefine.IpAddr parseFrom( + com.google.protobuf.ByteString data) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data); + } + public static com.mogujie.tt.protobuf.IMBaseDefine.IpAddr parseFrom( + com.google.protobuf.ByteString data, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data, extensionRegistry); + } + public static com.mogujie.tt.protobuf.IMBaseDefine.IpAddr parseFrom(byte[] data) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data); + } + public static com.mogujie.tt.protobuf.IMBaseDefine.IpAddr parseFrom( + byte[] data, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data, extensionRegistry); + } + public static com.mogujie.tt.protobuf.IMBaseDefine.IpAddr parseFrom(java.io.InputStream input) + throws java.io.IOException { + return PARSER.parseFrom(input); + } + public static com.mogujie.tt.protobuf.IMBaseDefine.IpAddr parseFrom( + java.io.InputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return PARSER.parseFrom(input, extensionRegistry); + } + public static com.mogujie.tt.protobuf.IMBaseDefine.IpAddr parseDelimitedFrom(java.io.InputStream input) + throws java.io.IOException { + return PARSER.parseDelimitedFrom(input); + } + public static com.mogujie.tt.protobuf.IMBaseDefine.IpAddr parseDelimitedFrom( + java.io.InputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return PARSER.parseDelimitedFrom(input, extensionRegistry); + } + public static com.mogujie.tt.protobuf.IMBaseDefine.IpAddr parseFrom( + com.google.protobuf.CodedInputStream input) + throws java.io.IOException { + return PARSER.parseFrom(input); + } + public static com.mogujie.tt.protobuf.IMBaseDefine.IpAddr parseFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return PARSER.parseFrom(input, extensionRegistry); + } + + public static Builder newBuilder() { return Builder.create(); } + public Builder newBuilderForType() { return newBuilder(); } + public static Builder newBuilder(com.mogujie.tt.protobuf.IMBaseDefine.IpAddr prototype) { + return newBuilder().mergeFrom(prototype); + } + public Builder toBuilder() { return newBuilder(this); } + + /** + * Protobuf type {@code IM.BaseDefine.IpAddr} + */ + public static final class Builder extends + com.google.protobuf.GeneratedMessageLite.Builder< + com.mogujie.tt.protobuf.IMBaseDefine.IpAddr, Builder> + implements + // @@protoc_insertion_point(builder_implements:IM.BaseDefine.IpAddr) + com.mogujie.tt.protobuf.IMBaseDefine.IpAddrOrBuilder { + // Construct using com.mogujie.tt.protobuf.IMBaseDefine.IpAddr.newBuilder() + private Builder() { + maybeForceBuilderInitialization(); + } + + private void maybeForceBuilderInitialization() { + } + private static Builder create() { + return new Builder(); + } + + public Builder clear() { + super.clear(); + ip_ = ""; + bitField0_ = (bitField0_ & ~0x00000001); + port_ = 0; + bitField0_ = (bitField0_ & ~0x00000002); + return this; + } + + public Builder clone() { + return create().mergeFrom(buildPartial()); + } + + public com.mogujie.tt.protobuf.IMBaseDefine.IpAddr getDefaultInstanceForType() { + return com.mogujie.tt.protobuf.IMBaseDefine.IpAddr.getDefaultInstance(); + } + + public com.mogujie.tt.protobuf.IMBaseDefine.IpAddr build() { + com.mogujie.tt.protobuf.IMBaseDefine.IpAddr result = buildPartial(); + if (!result.isInitialized()) { + throw newUninitializedMessageException(result); + } + return result; + } + + public com.mogujie.tt.protobuf.IMBaseDefine.IpAddr buildPartial() { + com.mogujie.tt.protobuf.IMBaseDefine.IpAddr result = new com.mogujie.tt.protobuf.IMBaseDefine.IpAddr(this); + int from_bitField0_ = bitField0_; + int to_bitField0_ = 0; + if (((from_bitField0_ & 0x00000001) == 0x00000001)) { + to_bitField0_ |= 0x00000001; + } + result.ip_ = ip_; + if (((from_bitField0_ & 0x00000002) == 0x00000002)) { + to_bitField0_ |= 0x00000002; + } + result.port_ = port_; + result.bitField0_ = to_bitField0_; + return result; + } + + public Builder mergeFrom(com.mogujie.tt.protobuf.IMBaseDefine.IpAddr other) { + if (other == com.mogujie.tt.protobuf.IMBaseDefine.IpAddr.getDefaultInstance()) return this; + if (other.hasIp()) { + bitField0_ |= 0x00000001; + ip_ = other.ip_; + + } + if (other.hasPort()) { + setPort(other.getPort()); + } + setUnknownFields( + getUnknownFields().concat(other.unknownFields)); + return this; + } + + public final boolean isInitialized() { + if (!hasIp()) { + + return false; + } + if (!hasPort()) { + + return false; + } + return true; + } + + public Builder mergeFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + com.mogujie.tt.protobuf.IMBaseDefine.IpAddr parsedMessage = null; + try { + parsedMessage = PARSER.parsePartialFrom(input, extensionRegistry); + } catch (com.google.protobuf.InvalidProtocolBufferException e) { + parsedMessage = (com.mogujie.tt.protobuf.IMBaseDefine.IpAddr) e.getUnfinishedMessage(); + throw e; + } finally { + if (parsedMessage != null) { + mergeFrom(parsedMessage); + } + } + return this; + } + private int bitField0_; + + private java.lang.Object ip_ = ""; + /** + * required string ip = 1; + */ + public boolean hasIp() { + return ((bitField0_ & 0x00000001) == 0x00000001); + } + /** + * required string ip = 1; + */ + public java.lang.String getIp() { + java.lang.Object ref = ip_; + if (!(ref instanceof java.lang.String)) { + com.google.protobuf.ByteString bs = + (com.google.protobuf.ByteString) ref; + java.lang.String s = bs.toStringUtf8(); + if (bs.isValidUtf8()) { + ip_ = s; + } + return s; + } else { + return (java.lang.String) ref; + } + } + /** + * required string ip = 1; + */ + public com.google.protobuf.ByteString + getIpBytes() { + java.lang.Object ref = ip_; + if (ref instanceof String) { + com.google.protobuf.ByteString b = + com.google.protobuf.ByteString.copyFromUtf8( + (java.lang.String) ref); + ip_ = b; + return b; + } else { + return (com.google.protobuf.ByteString) ref; + } + } + /** + * required string ip = 1; + */ + public Builder setIp( + java.lang.String value) { + if (value == null) { + throw new NullPointerException(); + } + bitField0_ |= 0x00000001; + ip_ = value; + + return this; + } + /** + * required string ip = 1; + */ + public Builder clearIp() { + bitField0_ = (bitField0_ & ~0x00000001); + ip_ = getDefaultInstance().getIp(); + + return this; + } + /** + * required string ip = 1; + */ + public Builder setIpBytes( + com.google.protobuf.ByteString value) { + if (value == null) { + throw new NullPointerException(); + } + bitField0_ |= 0x00000001; + ip_ = value; + + return this; + } + + private int port_ ; + /** + * required uint32 port = 2; + */ + public boolean hasPort() { + return ((bitField0_ & 0x00000002) == 0x00000002); + } + /** + * required uint32 port = 2; + */ + public int getPort() { + return port_; + } + /** + * required uint32 port = 2; + */ + public Builder setPort(int value) { + bitField0_ |= 0x00000002; + port_ = value; + + return this; + } + /** + * required uint32 port = 2; + */ + public Builder clearPort() { + bitField0_ = (bitField0_ & ~0x00000002); + port_ = 0; + + return this; + } + + // @@protoc_insertion_point(builder_scope:IM.BaseDefine.IpAddr) + } + + static { + defaultInstance = new IpAddr(true); + defaultInstance.initFields(); + } + + // @@protoc_insertion_point(class_scope:IM.BaseDefine.IpAddr) + } + + public interface UserInfoOrBuilder extends + // @@protoc_insertion_point(interface_extends:IM.BaseDefine.UserInfo) + com.google.protobuf.MessageLiteOrBuilder { + + /** + * required uint32 user_id = 1; + */ + boolean hasUserId(); + /** + * required uint32 user_id = 1; + */ + int getUserId(); + + /** + * required uint32 user_gender = 2; + * + *
+     *// 用户性别,男:1 女:2 人妖/外星人:0
+     * 
+ */ + boolean hasUserGender(); + /** + * required uint32 user_gender = 2; + * + *
+     *// 用户性别,男:1 女:2 人妖/外星人:0
+     * 
+ */ + int getUserGender(); + + /** + * required string user_nick_name = 3; + * + *
+     *绰号
+     * 
+ */ + boolean hasUserNickName(); + /** + * required string user_nick_name = 3; + * + *
+     *绰号
+     * 
+ */ + java.lang.String getUserNickName(); + /** + * required string user_nick_name = 3; + * + *
+     *绰号
+     * 
+ */ + com.google.protobuf.ByteString + getUserNickNameBytes(); + + /** + * required string avatar_url = 4; + */ + boolean hasAvatarUrl(); + /** + * required string avatar_url = 4; + */ + java.lang.String getAvatarUrl(); + /** + * required string avatar_url = 4; + */ + com.google.protobuf.ByteString + getAvatarUrlBytes(); + + /** + * required uint32 department_id = 5; + */ + boolean hasDepartmentId(); + /** + * required uint32 department_id = 5; + */ + int getDepartmentId(); + + /** + * required string email = 6; + */ + boolean hasEmail(); + /** + * required string email = 6; + */ + java.lang.String getEmail(); + /** + * required string email = 6; + */ + com.google.protobuf.ByteString + getEmailBytes(); + + /** + * required string user_real_name = 7; + * + *
+     *真名
+     * 
+ */ + boolean hasUserRealName(); + /** + * required string user_real_name = 7; + * + *
+     *真名
+     * 
+ */ + java.lang.String getUserRealName(); + /** + * required string user_real_name = 7; + * + *
+     *真名
+     * 
+ */ + com.google.protobuf.ByteString + getUserRealNameBytes(); + + /** + * required string user_tel = 8; + */ + boolean hasUserTel(); + /** + * required string user_tel = 8; + */ + java.lang.String getUserTel(); + /** + * required string user_tel = 8; + */ + com.google.protobuf.ByteString + getUserTelBytes(); + + /** + * required string user_domain = 9; + * + *
+     *用户名拼音
+     * 
+ */ + boolean hasUserDomain(); + /** + * required string user_domain = 9; + * + *
+     *用户名拼音
+     * 
+ */ + java.lang.String getUserDomain(); + /** + * required string user_domain = 9; + * + *
+     *用户名拼音
+     * 
+ */ + com.google.protobuf.ByteString + getUserDomainBytes(); + + /** + * required uint32 status = 10; + * + *
+     *0:在职  1. 试用期 2. 正式 3. 离职 4.实习,  client端需要对“离职”进行不展示
+     * 
+ */ + boolean hasStatus(); + /** + * required uint32 status = 10; + * + *
+     *0:在职  1. 试用期 2. 正式 3. 离职 4.实习,  client端需要对“离职”进行不展示
+     * 
+ */ + int getStatus(); + } + /** + * Protobuf type {@code IM.BaseDefine.UserInfo} + */ + public static final class UserInfo extends + com.google.protobuf.GeneratedMessageLite implements + // @@protoc_insertion_point(message_implements:IM.BaseDefine.UserInfo) + UserInfoOrBuilder { + // Use UserInfo.newBuilder() to construct. + private UserInfo(com.google.protobuf.GeneratedMessageLite.Builder builder) { + super(builder); + this.unknownFields = builder.getUnknownFields(); + } + private UserInfo(boolean noInit) { this.unknownFields = com.google.protobuf.ByteString.EMPTY;} + + private static final UserInfo defaultInstance; + public static UserInfo getDefaultInstance() { + return defaultInstance; + } + + public UserInfo getDefaultInstanceForType() { + return defaultInstance; + } + + private final com.google.protobuf.ByteString unknownFields; + private UserInfo( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + initFields(); + int mutable_bitField0_ = 0; + com.google.protobuf.ByteString.Output unknownFieldsOutput = + com.google.protobuf.ByteString.newOutput(); + com.google.protobuf.CodedOutputStream unknownFieldsCodedOutput = + com.google.protobuf.CodedOutputStream.newInstance( + unknownFieldsOutput); + try { + boolean done = false; + while (!done) { + int tag = input.readTag(); + switch (tag) { + case 0: + done = true; + break; + default: { + if (!parseUnknownField(input, unknownFieldsCodedOutput, + extensionRegistry, tag)) { + done = true; + } + break; + } + case 8: { + bitField0_ |= 0x00000001; + userId_ = input.readUInt32(); + break; + } + case 16: { + bitField0_ |= 0x00000002; + userGender_ = input.readUInt32(); + break; + } + case 26: { + com.google.protobuf.ByteString bs = input.readBytes(); + bitField0_ |= 0x00000004; + userNickName_ = bs; + break; + } + case 34: { + com.google.protobuf.ByteString bs = input.readBytes(); + bitField0_ |= 0x00000008; + avatarUrl_ = bs; + break; + } + case 40: { + bitField0_ |= 0x00000010; + departmentId_ = input.readUInt32(); + break; + } + case 50: { + com.google.protobuf.ByteString bs = input.readBytes(); + bitField0_ |= 0x00000020; + email_ = bs; + break; + } + case 58: { + com.google.protobuf.ByteString bs = input.readBytes(); + bitField0_ |= 0x00000040; + userRealName_ = bs; + break; + } + case 66: { + com.google.protobuf.ByteString bs = input.readBytes(); + bitField0_ |= 0x00000080; + userTel_ = bs; + break; + } + case 74: { + com.google.protobuf.ByteString bs = input.readBytes(); + bitField0_ |= 0x00000100; + userDomain_ = bs; + break; + } + case 80: { + bitField0_ |= 0x00000200; + status_ = input.readUInt32(); + break; + } + } + } + } catch (com.google.protobuf.InvalidProtocolBufferException e) { + throw e.setUnfinishedMessage(this); + } catch (java.io.IOException e) { + throw new com.google.protobuf.InvalidProtocolBufferException( + e.getMessage()).setUnfinishedMessage(this); + } finally { + try { + unknownFieldsCodedOutput.flush(); + } catch (java.io.IOException e) { + // Should not happen + } finally { + unknownFields = unknownFieldsOutput.toByteString(); + } + makeExtensionsImmutable(); + } + } + public static com.google.protobuf.Parser PARSER = + new com.google.protobuf.AbstractParser() { + public UserInfo parsePartialFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return new UserInfo(input, extensionRegistry); + } + }; + + @java.lang.Override + public com.google.protobuf.Parser getParserForType() { + return PARSER; + } + + private int bitField0_; + public static final int USER_ID_FIELD_NUMBER = 1; + private int userId_; + /** + * required uint32 user_id = 1; + */ + public boolean hasUserId() { + return ((bitField0_ & 0x00000001) == 0x00000001); + } + /** + * required uint32 user_id = 1; + */ + public int getUserId() { + return userId_; + } + + public static final int USER_GENDER_FIELD_NUMBER = 2; + private int userGender_; + /** + * required uint32 user_gender = 2; + * + *
+     *// 用户性别,男:1 女:2 人妖/外星人:0
+     * 
+ */ + public boolean hasUserGender() { + return ((bitField0_ & 0x00000002) == 0x00000002); + } + /** + * required uint32 user_gender = 2; + * + *
+     *// 用户性别,男:1 女:2 人妖/外星人:0
+     * 
+ */ + public int getUserGender() { + return userGender_; + } + + public static final int USER_NICK_NAME_FIELD_NUMBER = 3; + private java.lang.Object userNickName_; + /** + * required string user_nick_name = 3; + * + *
+     *绰号
+     * 
+ */ + public boolean hasUserNickName() { + return ((bitField0_ & 0x00000004) == 0x00000004); + } + /** + * required string user_nick_name = 3; + * + *
+     *绰号
+     * 
+ */ + public java.lang.String getUserNickName() { + java.lang.Object ref = userNickName_; + if (ref instanceof java.lang.String) { + return (java.lang.String) ref; + } else { + com.google.protobuf.ByteString bs = + (com.google.protobuf.ByteString) ref; + java.lang.String s = bs.toStringUtf8(); + if (bs.isValidUtf8()) { + userNickName_ = s; + } + return s; + } + } + /** + * required string user_nick_name = 3; + * + *
+     *绰号
+     * 
+ */ + public com.google.protobuf.ByteString + getUserNickNameBytes() { + java.lang.Object ref = userNickName_; + if (ref instanceof java.lang.String) { + com.google.protobuf.ByteString b = + com.google.protobuf.ByteString.copyFromUtf8( + (java.lang.String) ref); + userNickName_ = b; + return b; + } else { + return (com.google.protobuf.ByteString) ref; + } + } + + public static final int AVATAR_URL_FIELD_NUMBER = 4; + private java.lang.Object avatarUrl_; + /** + * required string avatar_url = 4; + */ + public boolean hasAvatarUrl() { + return ((bitField0_ & 0x00000008) == 0x00000008); + } + /** + * required string avatar_url = 4; + */ + public java.lang.String getAvatarUrl() { + java.lang.Object ref = avatarUrl_; + if (ref instanceof java.lang.String) { + return (java.lang.String) ref; + } else { + com.google.protobuf.ByteString bs = + (com.google.protobuf.ByteString) ref; + java.lang.String s = bs.toStringUtf8(); + if (bs.isValidUtf8()) { + avatarUrl_ = s; + } + return s; + } + } + /** + * required string avatar_url = 4; + */ + public com.google.protobuf.ByteString + getAvatarUrlBytes() { + java.lang.Object ref = avatarUrl_; + if (ref instanceof java.lang.String) { + com.google.protobuf.ByteString b = + com.google.protobuf.ByteString.copyFromUtf8( + (java.lang.String) ref); + avatarUrl_ = b; + return b; + } else { + return (com.google.protobuf.ByteString) ref; + } + } + + public static final int DEPARTMENT_ID_FIELD_NUMBER = 5; + private int departmentId_; + /** + * required uint32 department_id = 5; + */ + public boolean hasDepartmentId() { + return ((bitField0_ & 0x00000010) == 0x00000010); + } + /** + * required uint32 department_id = 5; + */ + public int getDepartmentId() { + return departmentId_; + } + + public static final int EMAIL_FIELD_NUMBER = 6; + private java.lang.Object email_; + /** + * required string email = 6; + */ + public boolean hasEmail() { + return ((bitField0_ & 0x00000020) == 0x00000020); + } + /** + * required string email = 6; + */ + public java.lang.String getEmail() { + java.lang.Object ref = email_; + if (ref instanceof java.lang.String) { + return (java.lang.String) ref; + } else { + com.google.protobuf.ByteString bs = + (com.google.protobuf.ByteString) ref; + java.lang.String s = bs.toStringUtf8(); + if (bs.isValidUtf8()) { + email_ = s; + } + return s; + } + } + /** + * required string email = 6; + */ + public com.google.protobuf.ByteString + getEmailBytes() { + java.lang.Object ref = email_; + if (ref instanceof java.lang.String) { + com.google.protobuf.ByteString b = + com.google.protobuf.ByteString.copyFromUtf8( + (java.lang.String) ref); + email_ = b; + return b; + } else { + return (com.google.protobuf.ByteString) ref; + } + } + + public static final int USER_REAL_NAME_FIELD_NUMBER = 7; + private java.lang.Object userRealName_; + /** + * required string user_real_name = 7; + * + *
+     *真名
+     * 
+ */ + public boolean hasUserRealName() { + return ((bitField0_ & 0x00000040) == 0x00000040); + } + /** + * required string user_real_name = 7; + * + *
+     *真名
+     * 
+ */ + public java.lang.String getUserRealName() { + java.lang.Object ref = userRealName_; + if (ref instanceof java.lang.String) { + return (java.lang.String) ref; + } else { + com.google.protobuf.ByteString bs = + (com.google.protobuf.ByteString) ref; + java.lang.String s = bs.toStringUtf8(); + if (bs.isValidUtf8()) { + userRealName_ = s; + } + return s; + } + } + /** + * required string user_real_name = 7; + * + *
+     *真名
+     * 
+ */ + public com.google.protobuf.ByteString + getUserRealNameBytes() { + java.lang.Object ref = userRealName_; + if (ref instanceof java.lang.String) { + com.google.protobuf.ByteString b = + com.google.protobuf.ByteString.copyFromUtf8( + (java.lang.String) ref); + userRealName_ = b; + return b; + } else { + return (com.google.protobuf.ByteString) ref; + } + } + + public static final int USER_TEL_FIELD_NUMBER = 8; + private java.lang.Object userTel_; + /** + * required string user_tel = 8; + */ + public boolean hasUserTel() { + return ((bitField0_ & 0x00000080) == 0x00000080); + } + /** + * required string user_tel = 8; + */ + public java.lang.String getUserTel() { + java.lang.Object ref = userTel_; + if (ref instanceof java.lang.String) { + return (java.lang.String) ref; + } else { + com.google.protobuf.ByteString bs = + (com.google.protobuf.ByteString) ref; + java.lang.String s = bs.toStringUtf8(); + if (bs.isValidUtf8()) { + userTel_ = s; + } + return s; + } + } + /** + * required string user_tel = 8; + */ + public com.google.protobuf.ByteString + getUserTelBytes() { + java.lang.Object ref = userTel_; + if (ref instanceof java.lang.String) { + com.google.protobuf.ByteString b = + com.google.protobuf.ByteString.copyFromUtf8( + (java.lang.String) ref); + userTel_ = b; + return b; + } else { + return (com.google.protobuf.ByteString) ref; + } + } + + public static final int USER_DOMAIN_FIELD_NUMBER = 9; + private java.lang.Object userDomain_; + /** + * required string user_domain = 9; + * + *
+     *用户名拼音
+     * 
+ */ + public boolean hasUserDomain() { + return ((bitField0_ & 0x00000100) == 0x00000100); + } + /** + * required string user_domain = 9; + * + *
+     *用户名拼音
+     * 
+ */ + public java.lang.String getUserDomain() { + java.lang.Object ref = userDomain_; + if (ref instanceof java.lang.String) { + return (java.lang.String) ref; + } else { + com.google.protobuf.ByteString bs = + (com.google.protobuf.ByteString) ref; + java.lang.String s = bs.toStringUtf8(); + if (bs.isValidUtf8()) { + userDomain_ = s; + } + return s; + } + } + /** + * required string user_domain = 9; + * + *
+     *用户名拼音
+     * 
+ */ + public com.google.protobuf.ByteString + getUserDomainBytes() { + java.lang.Object ref = userDomain_; + if (ref instanceof java.lang.String) { + com.google.protobuf.ByteString b = + com.google.protobuf.ByteString.copyFromUtf8( + (java.lang.String) ref); + userDomain_ = b; + return b; + } else { + return (com.google.protobuf.ByteString) ref; + } + } + + public static final int STATUS_FIELD_NUMBER = 10; + private int status_; + /** + * required uint32 status = 10; + * + *
+     *0:在职  1. 试用期 2. 正式 3. 离职 4.实习,  client端需要对“离职”进行不展示
+     * 
+ */ + public boolean hasStatus() { + return ((bitField0_ & 0x00000200) == 0x00000200); + } + /** + * required uint32 status = 10; + * + *
+     *0:在职  1. 试用期 2. 正式 3. 离职 4.实习,  client端需要对“离职”进行不展示
+     * 
+ */ + public int getStatus() { + return status_; + } + + private void initFields() { + userId_ = 0; + userGender_ = 0; + userNickName_ = ""; + avatarUrl_ = ""; + departmentId_ = 0; + email_ = ""; + userRealName_ = ""; + userTel_ = ""; + userDomain_ = ""; + status_ = 0; + } + private byte memoizedIsInitialized = -1; + public final boolean isInitialized() { + byte isInitialized = memoizedIsInitialized; + if (isInitialized == 1) return true; + if (isInitialized == 0) return false; + + if (!hasUserId()) { + memoizedIsInitialized = 0; + return false; + } + if (!hasUserGender()) { + memoizedIsInitialized = 0; + return false; + } + if (!hasUserNickName()) { + memoizedIsInitialized = 0; + return false; + } + if (!hasAvatarUrl()) { + memoizedIsInitialized = 0; + return false; + } + if (!hasDepartmentId()) { + memoizedIsInitialized = 0; + return false; + } + if (!hasEmail()) { + memoizedIsInitialized = 0; + return false; + } + if (!hasUserRealName()) { + memoizedIsInitialized = 0; + return false; + } + if (!hasUserTel()) { + memoizedIsInitialized = 0; + return false; + } + if (!hasUserDomain()) { + memoizedIsInitialized = 0; + return false; + } + if (!hasStatus()) { + memoizedIsInitialized = 0; + return false; + } + memoizedIsInitialized = 1; + return true; + } + + public void writeTo(com.google.protobuf.CodedOutputStream output) + throws java.io.IOException { + getSerializedSize(); + if (((bitField0_ & 0x00000001) == 0x00000001)) { + output.writeUInt32(1, userId_); + } + if (((bitField0_ & 0x00000002) == 0x00000002)) { + output.writeUInt32(2, userGender_); + } + if (((bitField0_ & 0x00000004) == 0x00000004)) { + output.writeBytes(3, getUserNickNameBytes()); + } + if (((bitField0_ & 0x00000008) == 0x00000008)) { + output.writeBytes(4, getAvatarUrlBytes()); + } + if (((bitField0_ & 0x00000010) == 0x00000010)) { + output.writeUInt32(5, departmentId_); + } + if (((bitField0_ & 0x00000020) == 0x00000020)) { + output.writeBytes(6, getEmailBytes()); + } + if (((bitField0_ & 0x00000040) == 0x00000040)) { + output.writeBytes(7, getUserRealNameBytes()); + } + if (((bitField0_ & 0x00000080) == 0x00000080)) { + output.writeBytes(8, getUserTelBytes()); + } + if (((bitField0_ & 0x00000100) == 0x00000100)) { + output.writeBytes(9, getUserDomainBytes()); + } + if (((bitField0_ & 0x00000200) == 0x00000200)) { + output.writeUInt32(10, status_); + } + output.writeRawBytes(unknownFields); + } + + private int memoizedSerializedSize = -1; + public int getSerializedSize() { + int size = memoizedSerializedSize; + if (size != -1) return size; + + size = 0; + if (((bitField0_ & 0x00000001) == 0x00000001)) { + size += com.google.protobuf.CodedOutputStream + .computeUInt32Size(1, userId_); + } + if (((bitField0_ & 0x00000002) == 0x00000002)) { + size += com.google.protobuf.CodedOutputStream + .computeUInt32Size(2, userGender_); + } + if (((bitField0_ & 0x00000004) == 0x00000004)) { + size += com.google.protobuf.CodedOutputStream + .computeBytesSize(3, getUserNickNameBytes()); + } + if (((bitField0_ & 0x00000008) == 0x00000008)) { + size += com.google.protobuf.CodedOutputStream + .computeBytesSize(4, getAvatarUrlBytes()); + } + if (((bitField0_ & 0x00000010) == 0x00000010)) { + size += com.google.protobuf.CodedOutputStream + .computeUInt32Size(5, departmentId_); + } + if (((bitField0_ & 0x00000020) == 0x00000020)) { + size += com.google.protobuf.CodedOutputStream + .computeBytesSize(6, getEmailBytes()); + } + if (((bitField0_ & 0x00000040) == 0x00000040)) { + size += com.google.protobuf.CodedOutputStream + .computeBytesSize(7, getUserRealNameBytes()); + } + if (((bitField0_ & 0x00000080) == 0x00000080)) { + size += com.google.protobuf.CodedOutputStream + .computeBytesSize(8, getUserTelBytes()); + } + if (((bitField0_ & 0x00000100) == 0x00000100)) { + size += com.google.protobuf.CodedOutputStream + .computeBytesSize(9, getUserDomainBytes()); + } + if (((bitField0_ & 0x00000200) == 0x00000200)) { + size += com.google.protobuf.CodedOutputStream + .computeUInt32Size(10, status_); + } + size += unknownFields.size(); + memoizedSerializedSize = size; + return size; + } + + private static final long serialVersionUID = 0L; + @java.lang.Override + protected java.lang.Object writeReplace() + throws java.io.ObjectStreamException { + return super.writeReplace(); + } + + public static com.mogujie.tt.protobuf.IMBaseDefine.UserInfo parseFrom( + com.google.protobuf.ByteString data) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data); + } + public static com.mogujie.tt.protobuf.IMBaseDefine.UserInfo parseFrom( + com.google.protobuf.ByteString data, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data, extensionRegistry); + } + public static com.mogujie.tt.protobuf.IMBaseDefine.UserInfo parseFrom(byte[] data) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data); + } + public static com.mogujie.tt.protobuf.IMBaseDefine.UserInfo parseFrom( + byte[] data, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data, extensionRegistry); + } + public static com.mogujie.tt.protobuf.IMBaseDefine.UserInfo parseFrom(java.io.InputStream input) + throws java.io.IOException { + return PARSER.parseFrom(input); + } + public static com.mogujie.tt.protobuf.IMBaseDefine.UserInfo parseFrom( + java.io.InputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return PARSER.parseFrom(input, extensionRegistry); + } + public static com.mogujie.tt.protobuf.IMBaseDefine.UserInfo parseDelimitedFrom(java.io.InputStream input) + throws java.io.IOException { + return PARSER.parseDelimitedFrom(input); + } + public static com.mogujie.tt.protobuf.IMBaseDefine.UserInfo parseDelimitedFrom( + java.io.InputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return PARSER.parseDelimitedFrom(input, extensionRegistry); + } + public static com.mogujie.tt.protobuf.IMBaseDefine.UserInfo parseFrom( + com.google.protobuf.CodedInputStream input) + throws java.io.IOException { + return PARSER.parseFrom(input); + } + public static com.mogujie.tt.protobuf.IMBaseDefine.UserInfo parseFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return PARSER.parseFrom(input, extensionRegistry); + } + + public static Builder newBuilder() { return Builder.create(); } + public Builder newBuilderForType() { return newBuilder(); } + public static Builder newBuilder(com.mogujie.tt.protobuf.IMBaseDefine.UserInfo prototype) { + return newBuilder().mergeFrom(prototype); + } + public Builder toBuilder() { return newBuilder(this); } + + /** + * Protobuf type {@code IM.BaseDefine.UserInfo} + */ + public static final class Builder extends + com.google.protobuf.GeneratedMessageLite.Builder< + com.mogujie.tt.protobuf.IMBaseDefine.UserInfo, Builder> + implements + // @@protoc_insertion_point(builder_implements:IM.BaseDefine.UserInfo) + com.mogujie.tt.protobuf.IMBaseDefine.UserInfoOrBuilder { + // Construct using com.mogujie.tt.protobuf.IMBaseDefine.UserInfo.newBuilder() + private Builder() { + maybeForceBuilderInitialization(); + } + + private void maybeForceBuilderInitialization() { + } + private static Builder create() { + return new Builder(); + } + + public Builder clear() { + super.clear(); + userId_ = 0; + bitField0_ = (bitField0_ & ~0x00000001); + userGender_ = 0; + bitField0_ = (bitField0_ & ~0x00000002); + userNickName_ = ""; + bitField0_ = (bitField0_ & ~0x00000004); + avatarUrl_ = ""; + bitField0_ = (bitField0_ & ~0x00000008); + departmentId_ = 0; + bitField0_ = (bitField0_ & ~0x00000010); + email_ = ""; + bitField0_ = (bitField0_ & ~0x00000020); + userRealName_ = ""; + bitField0_ = (bitField0_ & ~0x00000040); + userTel_ = ""; + bitField0_ = (bitField0_ & ~0x00000080); + userDomain_ = ""; + bitField0_ = (bitField0_ & ~0x00000100); + status_ = 0; + bitField0_ = (bitField0_ & ~0x00000200); + return this; + } + + public Builder clone() { + return create().mergeFrom(buildPartial()); + } + + public com.mogujie.tt.protobuf.IMBaseDefine.UserInfo getDefaultInstanceForType() { + return com.mogujie.tt.protobuf.IMBaseDefine.UserInfo.getDefaultInstance(); + } + + public com.mogujie.tt.protobuf.IMBaseDefine.UserInfo build() { + com.mogujie.tt.protobuf.IMBaseDefine.UserInfo result = buildPartial(); + if (!result.isInitialized()) { + throw newUninitializedMessageException(result); + } + return result; + } + + public com.mogujie.tt.protobuf.IMBaseDefine.UserInfo buildPartial() { + com.mogujie.tt.protobuf.IMBaseDefine.UserInfo result = new com.mogujie.tt.protobuf.IMBaseDefine.UserInfo(this); + int from_bitField0_ = bitField0_; + int to_bitField0_ = 0; + if (((from_bitField0_ & 0x00000001) == 0x00000001)) { + to_bitField0_ |= 0x00000001; + } + result.userId_ = userId_; + if (((from_bitField0_ & 0x00000002) == 0x00000002)) { + to_bitField0_ |= 0x00000002; + } + result.userGender_ = userGender_; + if (((from_bitField0_ & 0x00000004) == 0x00000004)) { + to_bitField0_ |= 0x00000004; + } + result.userNickName_ = userNickName_; + if (((from_bitField0_ & 0x00000008) == 0x00000008)) { + to_bitField0_ |= 0x00000008; + } + result.avatarUrl_ = avatarUrl_; + if (((from_bitField0_ & 0x00000010) == 0x00000010)) { + to_bitField0_ |= 0x00000010; + } + result.departmentId_ = departmentId_; + if (((from_bitField0_ & 0x00000020) == 0x00000020)) { + to_bitField0_ |= 0x00000020; + } + result.email_ = email_; + if (((from_bitField0_ & 0x00000040) == 0x00000040)) { + to_bitField0_ |= 0x00000040; + } + result.userRealName_ = userRealName_; + if (((from_bitField0_ & 0x00000080) == 0x00000080)) { + to_bitField0_ |= 0x00000080; + } + result.userTel_ = userTel_; + if (((from_bitField0_ & 0x00000100) == 0x00000100)) { + to_bitField0_ |= 0x00000100; + } + result.userDomain_ = userDomain_; + if (((from_bitField0_ & 0x00000200) == 0x00000200)) { + to_bitField0_ |= 0x00000200; + } + result.status_ = status_; + result.bitField0_ = to_bitField0_; + return result; + } + + public Builder mergeFrom(com.mogujie.tt.protobuf.IMBaseDefine.UserInfo other) { + if (other == com.mogujie.tt.protobuf.IMBaseDefine.UserInfo.getDefaultInstance()) return this; + if (other.hasUserId()) { + setUserId(other.getUserId()); + } + if (other.hasUserGender()) { + setUserGender(other.getUserGender()); + } + if (other.hasUserNickName()) { + bitField0_ |= 0x00000004; + userNickName_ = other.userNickName_; + + } + if (other.hasAvatarUrl()) { + bitField0_ |= 0x00000008; + avatarUrl_ = other.avatarUrl_; + + } + if (other.hasDepartmentId()) { + setDepartmentId(other.getDepartmentId()); + } + if (other.hasEmail()) { + bitField0_ |= 0x00000020; + email_ = other.email_; + + } + if (other.hasUserRealName()) { + bitField0_ |= 0x00000040; + userRealName_ = other.userRealName_; + + } + if (other.hasUserTel()) { + bitField0_ |= 0x00000080; + userTel_ = other.userTel_; + + } + if (other.hasUserDomain()) { + bitField0_ |= 0x00000100; + userDomain_ = other.userDomain_; + + } + if (other.hasStatus()) { + setStatus(other.getStatus()); + } + setUnknownFields( + getUnknownFields().concat(other.unknownFields)); + return this; + } + + public final boolean isInitialized() { + if (!hasUserId()) { + + return false; + } + if (!hasUserGender()) { + + return false; + } + if (!hasUserNickName()) { + + return false; + } + if (!hasAvatarUrl()) { + + return false; + } + if (!hasDepartmentId()) { + + return false; + } + if (!hasEmail()) { + + return false; + } + if (!hasUserRealName()) { + + return false; + } + if (!hasUserTel()) { + + return false; + } + if (!hasUserDomain()) { + + return false; + } + if (!hasStatus()) { + + return false; + } + return true; + } + + public Builder mergeFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + com.mogujie.tt.protobuf.IMBaseDefine.UserInfo parsedMessage = null; + try { + parsedMessage = PARSER.parsePartialFrom(input, extensionRegistry); + } catch (com.google.protobuf.InvalidProtocolBufferException e) { + parsedMessage = (com.mogujie.tt.protobuf.IMBaseDefine.UserInfo) e.getUnfinishedMessage(); + throw e; + } finally { + if (parsedMessage != null) { + mergeFrom(parsedMessage); + } + } + return this; + } + private int bitField0_; + + private int userId_ ; + /** + * required uint32 user_id = 1; + */ + public boolean hasUserId() { + return ((bitField0_ & 0x00000001) == 0x00000001); + } + /** + * required uint32 user_id = 1; + */ + public int getUserId() { + return userId_; + } + /** + * required uint32 user_id = 1; + */ + public Builder setUserId(int value) { + bitField0_ |= 0x00000001; + userId_ = value; + + return this; + } + /** + * required uint32 user_id = 1; + */ + public Builder clearUserId() { + bitField0_ = (bitField0_ & ~0x00000001); + userId_ = 0; + + return this; + } + + private int userGender_ ; + /** + * required uint32 user_gender = 2; + * + *
+       *// 用户性别,男:1 女:2 人妖/外星人:0
+       * 
+ */ + public boolean hasUserGender() { + return ((bitField0_ & 0x00000002) == 0x00000002); + } + /** + * required uint32 user_gender = 2; + * + *
+       *// 用户性别,男:1 女:2 人妖/外星人:0
+       * 
+ */ + public int getUserGender() { + return userGender_; + } + /** + * required uint32 user_gender = 2; + * + *
+       *// 用户性别,男:1 女:2 人妖/外星人:0
+       * 
+ */ + public Builder setUserGender(int value) { + bitField0_ |= 0x00000002; + userGender_ = value; + + return this; + } + /** + * required uint32 user_gender = 2; + * + *
+       *// 用户性别,男:1 女:2 人妖/外星人:0
+       * 
+ */ + public Builder clearUserGender() { + bitField0_ = (bitField0_ & ~0x00000002); + userGender_ = 0; + + return this; + } + + private java.lang.Object userNickName_ = ""; + /** + * required string user_nick_name = 3; + * + *
+       *绰号
+       * 
+ */ + public boolean hasUserNickName() { + return ((bitField0_ & 0x00000004) == 0x00000004); + } + /** + * required string user_nick_name = 3; + * + *
+       *绰号
+       * 
+ */ + public java.lang.String getUserNickName() { + java.lang.Object ref = userNickName_; + if (!(ref instanceof java.lang.String)) { + com.google.protobuf.ByteString bs = + (com.google.protobuf.ByteString) ref; + java.lang.String s = bs.toStringUtf8(); + if (bs.isValidUtf8()) { + userNickName_ = s; + } + return s; + } else { + return (java.lang.String) ref; + } + } + /** + * required string user_nick_name = 3; + * + *
+       *绰号
+       * 
+ */ + public com.google.protobuf.ByteString + getUserNickNameBytes() { + java.lang.Object ref = userNickName_; + if (ref instanceof String) { + com.google.protobuf.ByteString b = + com.google.protobuf.ByteString.copyFromUtf8( + (java.lang.String) ref); + userNickName_ = b; + return b; + } else { + return (com.google.protobuf.ByteString) ref; + } + } + /** + * required string user_nick_name = 3; + * + *
+       *绰号
+       * 
+ */ + public Builder setUserNickName( + java.lang.String value) { + if (value == null) { + throw new NullPointerException(); + } + bitField0_ |= 0x00000004; + userNickName_ = value; + + return this; + } + /** + * required string user_nick_name = 3; + * + *
+       *绰号
+       * 
+ */ + public Builder clearUserNickName() { + bitField0_ = (bitField0_ & ~0x00000004); + userNickName_ = getDefaultInstance().getUserNickName(); + + return this; + } + /** + * required string user_nick_name = 3; + * + *
+       *绰号
+       * 
+ */ + public Builder setUserNickNameBytes( + com.google.protobuf.ByteString value) { + if (value == null) { + throw new NullPointerException(); + } + bitField0_ |= 0x00000004; + userNickName_ = value; + + return this; + } + + private java.lang.Object avatarUrl_ = ""; + /** + * required string avatar_url = 4; + */ + public boolean hasAvatarUrl() { + return ((bitField0_ & 0x00000008) == 0x00000008); + } + /** + * required string avatar_url = 4; + */ + public java.lang.String getAvatarUrl() { + java.lang.Object ref = avatarUrl_; + if (!(ref instanceof java.lang.String)) { + com.google.protobuf.ByteString bs = + (com.google.protobuf.ByteString) ref; + java.lang.String s = bs.toStringUtf8(); + if (bs.isValidUtf8()) { + avatarUrl_ = s; + } + return s; + } else { + return (java.lang.String) ref; + } + } + /** + * required string avatar_url = 4; + */ + public com.google.protobuf.ByteString + getAvatarUrlBytes() { + java.lang.Object ref = avatarUrl_; + if (ref instanceof String) { + com.google.protobuf.ByteString b = + com.google.protobuf.ByteString.copyFromUtf8( + (java.lang.String) ref); + avatarUrl_ = b; + return b; + } else { + return (com.google.protobuf.ByteString) ref; + } + } + /** + * required string avatar_url = 4; + */ + public Builder setAvatarUrl( + java.lang.String value) { + if (value == null) { + throw new NullPointerException(); + } + bitField0_ |= 0x00000008; + avatarUrl_ = value; + + return this; + } + /** + * required string avatar_url = 4; + */ + public Builder clearAvatarUrl() { + bitField0_ = (bitField0_ & ~0x00000008); + avatarUrl_ = getDefaultInstance().getAvatarUrl(); + + return this; + } + /** + * required string avatar_url = 4; + */ + public Builder setAvatarUrlBytes( + com.google.protobuf.ByteString value) { + if (value == null) { + throw new NullPointerException(); + } + bitField0_ |= 0x00000008; + avatarUrl_ = value; + + return this; + } + + private int departmentId_ ; + /** + * required uint32 department_id = 5; + */ + public boolean hasDepartmentId() { + return ((bitField0_ & 0x00000010) == 0x00000010); + } + /** + * required uint32 department_id = 5; + */ + public int getDepartmentId() { + return departmentId_; + } + /** + * required uint32 department_id = 5; + */ + public Builder setDepartmentId(int value) { + bitField0_ |= 0x00000010; + departmentId_ = value; + + return this; + } + /** + * required uint32 department_id = 5; + */ + public Builder clearDepartmentId() { + bitField0_ = (bitField0_ & ~0x00000010); + departmentId_ = 0; + + return this; + } + + private java.lang.Object email_ = ""; + /** + * required string email = 6; + */ + public boolean hasEmail() { + return ((bitField0_ & 0x00000020) == 0x00000020); + } + /** + * required string email = 6; + */ + public java.lang.String getEmail() { + java.lang.Object ref = email_; + if (!(ref instanceof java.lang.String)) { + com.google.protobuf.ByteString bs = + (com.google.protobuf.ByteString) ref; + java.lang.String s = bs.toStringUtf8(); + if (bs.isValidUtf8()) { + email_ = s; + } + return s; + } else { + return (java.lang.String) ref; + } + } + /** + * required string email = 6; + */ + public com.google.protobuf.ByteString + getEmailBytes() { + java.lang.Object ref = email_; + if (ref instanceof String) { + com.google.protobuf.ByteString b = + com.google.protobuf.ByteString.copyFromUtf8( + (java.lang.String) ref); + email_ = b; + return b; + } else { + return (com.google.protobuf.ByteString) ref; + } + } + /** + * required string email = 6; + */ + public Builder setEmail( + java.lang.String value) { + if (value == null) { + throw new NullPointerException(); + } + bitField0_ |= 0x00000020; + email_ = value; + + return this; + } + /** + * required string email = 6; + */ + public Builder clearEmail() { + bitField0_ = (bitField0_ & ~0x00000020); + email_ = getDefaultInstance().getEmail(); + + return this; + } + /** + * required string email = 6; + */ + public Builder setEmailBytes( + com.google.protobuf.ByteString value) { + if (value == null) { + throw new NullPointerException(); + } + bitField0_ |= 0x00000020; + email_ = value; + + return this; + } + + private java.lang.Object userRealName_ = ""; + /** + * required string user_real_name = 7; + * + *
+       *真名
+       * 
+ */ + public boolean hasUserRealName() { + return ((bitField0_ & 0x00000040) == 0x00000040); + } + /** + * required string user_real_name = 7; + * + *
+       *真名
+       * 
+ */ + public java.lang.String getUserRealName() { + java.lang.Object ref = userRealName_; + if (!(ref instanceof java.lang.String)) { + com.google.protobuf.ByteString bs = + (com.google.protobuf.ByteString) ref; + java.lang.String s = bs.toStringUtf8(); + if (bs.isValidUtf8()) { + userRealName_ = s; + } + return s; + } else { + return (java.lang.String) ref; + } + } + /** + * required string user_real_name = 7; + * + *
+       *真名
+       * 
+ */ + public com.google.protobuf.ByteString + getUserRealNameBytes() { + java.lang.Object ref = userRealName_; + if (ref instanceof String) { + com.google.protobuf.ByteString b = + com.google.protobuf.ByteString.copyFromUtf8( + (java.lang.String) ref); + userRealName_ = b; + return b; + } else { + return (com.google.protobuf.ByteString) ref; + } + } + /** + * required string user_real_name = 7; + * + *
+       *真名
+       * 
+ */ + public Builder setUserRealName( + java.lang.String value) { + if (value == null) { + throw new NullPointerException(); + } + bitField0_ |= 0x00000040; + userRealName_ = value; + + return this; + } + /** + * required string user_real_name = 7; + * + *
+       *真名
+       * 
+ */ + public Builder clearUserRealName() { + bitField0_ = (bitField0_ & ~0x00000040); + userRealName_ = getDefaultInstance().getUserRealName(); + + return this; + } + /** + * required string user_real_name = 7; + * + *
+       *真名
+       * 
+ */ + public Builder setUserRealNameBytes( + com.google.protobuf.ByteString value) { + if (value == null) { + throw new NullPointerException(); + } + bitField0_ |= 0x00000040; + userRealName_ = value; + + return this; + } + + private java.lang.Object userTel_ = ""; + /** + * required string user_tel = 8; + */ + public boolean hasUserTel() { + return ((bitField0_ & 0x00000080) == 0x00000080); + } + /** + * required string user_tel = 8; + */ + public java.lang.String getUserTel() { + java.lang.Object ref = userTel_; + if (!(ref instanceof java.lang.String)) { + com.google.protobuf.ByteString bs = + (com.google.protobuf.ByteString) ref; + java.lang.String s = bs.toStringUtf8(); + if (bs.isValidUtf8()) { + userTel_ = s; + } + return s; + } else { + return (java.lang.String) ref; + } + } + /** + * required string user_tel = 8; + */ + public com.google.protobuf.ByteString + getUserTelBytes() { + java.lang.Object ref = userTel_; + if (ref instanceof String) { + com.google.protobuf.ByteString b = + com.google.protobuf.ByteString.copyFromUtf8( + (java.lang.String) ref); + userTel_ = b; + return b; + } else { + return (com.google.protobuf.ByteString) ref; + } + } + /** + * required string user_tel = 8; + */ + public Builder setUserTel( + java.lang.String value) { + if (value == null) { + throw new NullPointerException(); + } + bitField0_ |= 0x00000080; + userTel_ = value; + + return this; + } + /** + * required string user_tel = 8; + */ + public Builder clearUserTel() { + bitField0_ = (bitField0_ & ~0x00000080); + userTel_ = getDefaultInstance().getUserTel(); + + return this; + } + /** + * required string user_tel = 8; + */ + public Builder setUserTelBytes( + com.google.protobuf.ByteString value) { + if (value == null) { + throw new NullPointerException(); + } + bitField0_ |= 0x00000080; + userTel_ = value; + + return this; + } + + private java.lang.Object userDomain_ = ""; + /** + * required string user_domain = 9; + * + *
+       *用户名拼音
+       * 
+ */ + public boolean hasUserDomain() { + return ((bitField0_ & 0x00000100) == 0x00000100); + } + /** + * required string user_domain = 9; + * + *
+       *用户名拼音
+       * 
+ */ + public java.lang.String getUserDomain() { + java.lang.Object ref = userDomain_; + if (!(ref instanceof java.lang.String)) { + com.google.protobuf.ByteString bs = + (com.google.protobuf.ByteString) ref; + java.lang.String s = bs.toStringUtf8(); + if (bs.isValidUtf8()) { + userDomain_ = s; + } + return s; + } else { + return (java.lang.String) ref; + } + } + /** + * required string user_domain = 9; + * + *
+       *用户名拼音
+       * 
+ */ + public com.google.protobuf.ByteString + getUserDomainBytes() { + java.lang.Object ref = userDomain_; + if (ref instanceof String) { + com.google.protobuf.ByteString b = + com.google.protobuf.ByteString.copyFromUtf8( + (java.lang.String) ref); + userDomain_ = b; + return b; + } else { + return (com.google.protobuf.ByteString) ref; + } + } + /** + * required string user_domain = 9; + * + *
+       *用户名拼音
+       * 
+ */ + public Builder setUserDomain( + java.lang.String value) { + if (value == null) { + throw new NullPointerException(); + } + bitField0_ |= 0x00000100; + userDomain_ = value; + + return this; + } + /** + * required string user_domain = 9; + * + *
+       *用户名拼音
+       * 
+ */ + public Builder clearUserDomain() { + bitField0_ = (bitField0_ & ~0x00000100); + userDomain_ = getDefaultInstance().getUserDomain(); + + return this; + } + /** + * required string user_domain = 9; + * + *
+       *用户名拼音
+       * 
+ */ + public Builder setUserDomainBytes( + com.google.protobuf.ByteString value) { + if (value == null) { + throw new NullPointerException(); + } + bitField0_ |= 0x00000100; + userDomain_ = value; + + return this; + } + + private int status_ ; + /** + * required uint32 status = 10; + * + *
+       *0:在职  1. 试用期 2. 正式 3. 离职 4.实习,  client端需要对“离职”进行不展示
+       * 
+ */ + public boolean hasStatus() { + return ((bitField0_ & 0x00000200) == 0x00000200); + } + /** + * required uint32 status = 10; + * + *
+       *0:在职  1. 试用期 2. 正式 3. 离职 4.实习,  client端需要对“离职”进行不展示
+       * 
+ */ + public int getStatus() { + return status_; + } + /** + * required uint32 status = 10; + * + *
+       *0:在职  1. 试用期 2. 正式 3. 离职 4.实习,  client端需要对“离职”进行不展示
+       * 
+ */ + public Builder setStatus(int value) { + bitField0_ |= 0x00000200; + status_ = value; + + return this; + } + /** + * required uint32 status = 10; + * + *
+       *0:在职  1. 试用期 2. 正式 3. 离职 4.实习,  client端需要对“离职”进行不展示
+       * 
+ */ + public Builder clearStatus() { + bitField0_ = (bitField0_ & ~0x00000200); + status_ = 0; + + return this; + } + + // @@protoc_insertion_point(builder_scope:IM.BaseDefine.UserInfo) + } + + static { + defaultInstance = new UserInfo(true); + defaultInstance.initFields(); + } + + // @@protoc_insertion_point(class_scope:IM.BaseDefine.UserInfo) + } + + public interface ContactSessionInfoOrBuilder extends + // @@protoc_insertion_point(interface_extends:IM.BaseDefine.ContactSessionInfo) + com.google.protobuf.MessageLiteOrBuilder { + + /** + * required uint32 session_id = 1; + */ + boolean hasSessionId(); + /** + * required uint32 session_id = 1; + */ + int getSessionId(); + + /** + * required .IM.BaseDefine.SessionType session_type = 2; + */ + boolean hasSessionType(); + /** + * required .IM.BaseDefine.SessionType session_type = 2; + */ + com.mogujie.tt.protobuf.IMBaseDefine.SessionType getSessionType(); + + /** + * required .IM.BaseDefine.SessionStatusType session_status = 3; + */ + boolean hasSessionStatus(); + /** + * required .IM.BaseDefine.SessionStatusType session_status = 3; + */ + com.mogujie.tt.protobuf.IMBaseDefine.SessionStatusType getSessionStatus(); + + /** + * required uint32 updated_time = 4; + */ + boolean hasUpdatedTime(); + /** + * required uint32 updated_time = 4; + */ + int getUpdatedTime(); + + /** + * required uint32 latest_msg_id = 5; + */ + boolean hasLatestMsgId(); + /** + * required uint32 latest_msg_id = 5; + */ + int getLatestMsgId(); + + /** + * required bytes latest_msg_data = 6; + */ + boolean hasLatestMsgData(); + /** + * required bytes latest_msg_data = 6; + */ + com.google.protobuf.ByteString getLatestMsgData(); + + /** + * required .IM.BaseDefine.MsgType latest_msg_type = 7; + */ + boolean hasLatestMsgType(); + /** + * required .IM.BaseDefine.MsgType latest_msg_type = 7; + */ + com.mogujie.tt.protobuf.IMBaseDefine.MsgType getLatestMsgType(); + + /** + * required uint32 latest_msg_from_user_id = 8; + */ + boolean hasLatestMsgFromUserId(); + /** + * required uint32 latest_msg_from_user_id = 8; + */ + int getLatestMsgFromUserId(); + } + /** + * Protobuf type {@code IM.BaseDefine.ContactSessionInfo} + */ + public static final class ContactSessionInfo extends + com.google.protobuf.GeneratedMessageLite implements + // @@protoc_insertion_point(message_implements:IM.BaseDefine.ContactSessionInfo) + ContactSessionInfoOrBuilder { + // Use ContactSessionInfo.newBuilder() to construct. + private ContactSessionInfo(com.google.protobuf.GeneratedMessageLite.Builder builder) { + super(builder); + this.unknownFields = builder.getUnknownFields(); + } + private ContactSessionInfo(boolean noInit) { this.unknownFields = com.google.protobuf.ByteString.EMPTY;} + + private static final ContactSessionInfo defaultInstance; + public static ContactSessionInfo getDefaultInstance() { + return defaultInstance; + } + + public ContactSessionInfo getDefaultInstanceForType() { + return defaultInstance; + } + + private final com.google.protobuf.ByteString unknownFields; + private ContactSessionInfo( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + initFields(); + int mutable_bitField0_ = 0; + com.google.protobuf.ByteString.Output unknownFieldsOutput = + com.google.protobuf.ByteString.newOutput(); + com.google.protobuf.CodedOutputStream unknownFieldsCodedOutput = + com.google.protobuf.CodedOutputStream.newInstance( + unknownFieldsOutput); + try { + boolean done = false; + while (!done) { + int tag = input.readTag(); + switch (tag) { + case 0: + done = true; + break; + default: { + if (!parseUnknownField(input, unknownFieldsCodedOutput, + extensionRegistry, tag)) { + done = true; + } + break; + } + case 8: { + bitField0_ |= 0x00000001; + sessionId_ = input.readUInt32(); + break; + } + case 16: { + int rawValue = input.readEnum(); + com.mogujie.tt.protobuf.IMBaseDefine.SessionType value = com.mogujie.tt.protobuf.IMBaseDefine.SessionType.valueOf(rawValue); + if (value == null) { + unknownFieldsCodedOutput.writeRawVarint32(tag); + unknownFieldsCodedOutput.writeRawVarint32(rawValue); + } else { + bitField0_ |= 0x00000002; + sessionType_ = value; + } + break; + } + case 24: { + int rawValue = input.readEnum(); + com.mogujie.tt.protobuf.IMBaseDefine.SessionStatusType value = com.mogujie.tt.protobuf.IMBaseDefine.SessionStatusType.valueOf(rawValue); + if (value == null) { + unknownFieldsCodedOutput.writeRawVarint32(tag); + unknownFieldsCodedOutput.writeRawVarint32(rawValue); + } else { + bitField0_ |= 0x00000004; + sessionStatus_ = value; + } + break; + } + case 32: { + bitField0_ |= 0x00000008; + updatedTime_ = input.readUInt32(); + break; + } + case 40: { + bitField0_ |= 0x00000010; + latestMsgId_ = input.readUInt32(); + break; + } + case 50: { + bitField0_ |= 0x00000020; + latestMsgData_ = input.readBytes(); + break; + } + case 56: { + int rawValue = input.readEnum(); + com.mogujie.tt.protobuf.IMBaseDefine.MsgType value = com.mogujie.tt.protobuf.IMBaseDefine.MsgType.valueOf(rawValue); + if (value == null) { + unknownFieldsCodedOutput.writeRawVarint32(tag); + unknownFieldsCodedOutput.writeRawVarint32(rawValue); + } else { + bitField0_ |= 0x00000040; + latestMsgType_ = value; + } + break; + } + case 64: { + bitField0_ |= 0x00000080; + latestMsgFromUserId_ = input.readUInt32(); + break; + } + } + } + } catch (com.google.protobuf.InvalidProtocolBufferException e) { + throw e.setUnfinishedMessage(this); + } catch (java.io.IOException e) { + throw new com.google.protobuf.InvalidProtocolBufferException( + e.getMessage()).setUnfinishedMessage(this); + } finally { + try { + unknownFieldsCodedOutput.flush(); + } catch (java.io.IOException e) { + // Should not happen + } finally { + unknownFields = unknownFieldsOutput.toByteString(); + } + makeExtensionsImmutable(); + } + } + public static com.google.protobuf.Parser PARSER = + new com.google.protobuf.AbstractParser() { + public ContactSessionInfo parsePartialFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return new ContactSessionInfo(input, extensionRegistry); + } + }; + + @java.lang.Override + public com.google.protobuf.Parser getParserForType() { + return PARSER; + } + + private int bitField0_; + public static final int SESSION_ID_FIELD_NUMBER = 1; + private int sessionId_; + /** + * required uint32 session_id = 1; + */ + public boolean hasSessionId() { + return ((bitField0_ & 0x00000001) == 0x00000001); + } + /** + * required uint32 session_id = 1; + */ + public int getSessionId() { + return sessionId_; + } + + public static final int SESSION_TYPE_FIELD_NUMBER = 2; + private com.mogujie.tt.protobuf.IMBaseDefine.SessionType sessionType_; + /** + * required .IM.BaseDefine.SessionType session_type = 2; + */ + public boolean hasSessionType() { + return ((bitField0_ & 0x00000002) == 0x00000002); + } + /** + * required .IM.BaseDefine.SessionType session_type = 2; + */ + public com.mogujie.tt.protobuf.IMBaseDefine.SessionType getSessionType() { + return sessionType_; + } + + public static final int SESSION_STATUS_FIELD_NUMBER = 3; + private com.mogujie.tt.protobuf.IMBaseDefine.SessionStatusType sessionStatus_; + /** + * required .IM.BaseDefine.SessionStatusType session_status = 3; + */ + public boolean hasSessionStatus() { + return ((bitField0_ & 0x00000004) == 0x00000004); + } + /** + * required .IM.BaseDefine.SessionStatusType session_status = 3; + */ + public com.mogujie.tt.protobuf.IMBaseDefine.SessionStatusType getSessionStatus() { + return sessionStatus_; + } + + public static final int UPDATED_TIME_FIELD_NUMBER = 4; + private int updatedTime_; + /** + * required uint32 updated_time = 4; + */ + public boolean hasUpdatedTime() { + return ((bitField0_ & 0x00000008) == 0x00000008); + } + /** + * required uint32 updated_time = 4; + */ + public int getUpdatedTime() { + return updatedTime_; + } + + public static final int LATEST_MSG_ID_FIELD_NUMBER = 5; + private int latestMsgId_; + /** + * required uint32 latest_msg_id = 5; + */ + public boolean hasLatestMsgId() { + return ((bitField0_ & 0x00000010) == 0x00000010); + } + /** + * required uint32 latest_msg_id = 5; + */ + public int getLatestMsgId() { + return latestMsgId_; + } + + public static final int LATEST_MSG_DATA_FIELD_NUMBER = 6; + private com.google.protobuf.ByteString latestMsgData_; + /** + * required bytes latest_msg_data = 6; + */ + public boolean hasLatestMsgData() { + return ((bitField0_ & 0x00000020) == 0x00000020); + } + /** + * required bytes latest_msg_data = 6; + */ + public com.google.protobuf.ByteString getLatestMsgData() { + return latestMsgData_; + } + + public static final int LATEST_MSG_TYPE_FIELD_NUMBER = 7; + private com.mogujie.tt.protobuf.IMBaseDefine.MsgType latestMsgType_; + /** + * required .IM.BaseDefine.MsgType latest_msg_type = 7; + */ + public boolean hasLatestMsgType() { + return ((bitField0_ & 0x00000040) == 0x00000040); + } + /** + * required .IM.BaseDefine.MsgType latest_msg_type = 7; + */ + public com.mogujie.tt.protobuf.IMBaseDefine.MsgType getLatestMsgType() { + return latestMsgType_; + } + + public static final int LATEST_MSG_FROM_USER_ID_FIELD_NUMBER = 8; + private int latestMsgFromUserId_; + /** + * required uint32 latest_msg_from_user_id = 8; + */ + public boolean hasLatestMsgFromUserId() { + return ((bitField0_ & 0x00000080) == 0x00000080); + } + /** + * required uint32 latest_msg_from_user_id = 8; + */ + public int getLatestMsgFromUserId() { + return latestMsgFromUserId_; + } + + private void initFields() { + sessionId_ = 0; + sessionType_ = com.mogujie.tt.protobuf.IMBaseDefine.SessionType.SESSION_TYPE_SINGLE; + sessionStatus_ = com.mogujie.tt.protobuf.IMBaseDefine.SessionStatusType.SESSION_STATUS_OK; + updatedTime_ = 0; + latestMsgId_ = 0; + latestMsgData_ = com.google.protobuf.ByteString.EMPTY; + latestMsgType_ = com.mogujie.tt.protobuf.IMBaseDefine.MsgType.MSG_TYPE_SINGLE_TEXT; + latestMsgFromUserId_ = 0; + } + private byte memoizedIsInitialized = -1; + public final boolean isInitialized() { + byte isInitialized = memoizedIsInitialized; + if (isInitialized == 1) return true; + if (isInitialized == 0) return false; + + if (!hasSessionId()) { + memoizedIsInitialized = 0; + return false; + } + if (!hasSessionType()) { + memoizedIsInitialized = 0; + return false; + } + if (!hasSessionStatus()) { + memoizedIsInitialized = 0; + return false; + } + if (!hasUpdatedTime()) { + memoizedIsInitialized = 0; + return false; + } + if (!hasLatestMsgId()) { + memoizedIsInitialized = 0; + return false; + } + if (!hasLatestMsgData()) { + memoizedIsInitialized = 0; + return false; + } + if (!hasLatestMsgType()) { + memoizedIsInitialized = 0; + return false; + } + if (!hasLatestMsgFromUserId()) { + memoizedIsInitialized = 0; + return false; + } + memoizedIsInitialized = 1; + return true; + } + + public void writeTo(com.google.protobuf.CodedOutputStream output) + throws java.io.IOException { + getSerializedSize(); + if (((bitField0_ & 0x00000001) == 0x00000001)) { + output.writeUInt32(1, sessionId_); + } + if (((bitField0_ & 0x00000002) == 0x00000002)) { + output.writeEnum(2, sessionType_.getNumber()); + } + if (((bitField0_ & 0x00000004) == 0x00000004)) { + output.writeEnum(3, sessionStatus_.getNumber()); + } + if (((bitField0_ & 0x00000008) == 0x00000008)) { + output.writeUInt32(4, updatedTime_); + } + if (((bitField0_ & 0x00000010) == 0x00000010)) { + output.writeUInt32(5, latestMsgId_); + } + if (((bitField0_ & 0x00000020) == 0x00000020)) { + output.writeBytes(6, latestMsgData_); + } + if (((bitField0_ & 0x00000040) == 0x00000040)) { + output.writeEnum(7, latestMsgType_.getNumber()); + } + if (((bitField0_ & 0x00000080) == 0x00000080)) { + output.writeUInt32(8, latestMsgFromUserId_); + } + output.writeRawBytes(unknownFields); + } + + private int memoizedSerializedSize = -1; + public int getSerializedSize() { + int size = memoizedSerializedSize; + if (size != -1) return size; + + size = 0; + if (((bitField0_ & 0x00000001) == 0x00000001)) { + size += com.google.protobuf.CodedOutputStream + .computeUInt32Size(1, sessionId_); + } + if (((bitField0_ & 0x00000002) == 0x00000002)) { + size += com.google.protobuf.CodedOutputStream + .computeEnumSize(2, sessionType_.getNumber()); + } + if (((bitField0_ & 0x00000004) == 0x00000004)) { + size += com.google.protobuf.CodedOutputStream + .computeEnumSize(3, sessionStatus_.getNumber()); + } + if (((bitField0_ & 0x00000008) == 0x00000008)) { + size += com.google.protobuf.CodedOutputStream + .computeUInt32Size(4, updatedTime_); + } + if (((bitField0_ & 0x00000010) == 0x00000010)) { + size += com.google.protobuf.CodedOutputStream + .computeUInt32Size(5, latestMsgId_); + } + if (((bitField0_ & 0x00000020) == 0x00000020)) { + size += com.google.protobuf.CodedOutputStream + .computeBytesSize(6, latestMsgData_); + } + if (((bitField0_ & 0x00000040) == 0x00000040)) { + size += com.google.protobuf.CodedOutputStream + .computeEnumSize(7, latestMsgType_.getNumber()); + } + if (((bitField0_ & 0x00000080) == 0x00000080)) { + size += com.google.protobuf.CodedOutputStream + .computeUInt32Size(8, latestMsgFromUserId_); + } + size += unknownFields.size(); + memoizedSerializedSize = size; + return size; + } + + private static final long serialVersionUID = 0L; + @java.lang.Override + protected java.lang.Object writeReplace() + throws java.io.ObjectStreamException { + return super.writeReplace(); + } + + public static com.mogujie.tt.protobuf.IMBaseDefine.ContactSessionInfo parseFrom( + com.google.protobuf.ByteString data) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data); + } + public static com.mogujie.tt.protobuf.IMBaseDefine.ContactSessionInfo parseFrom( + com.google.protobuf.ByteString data, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data, extensionRegistry); + } + public static com.mogujie.tt.protobuf.IMBaseDefine.ContactSessionInfo parseFrom(byte[] data) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data); + } + public static com.mogujie.tt.protobuf.IMBaseDefine.ContactSessionInfo parseFrom( + byte[] data, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data, extensionRegistry); + } + public static com.mogujie.tt.protobuf.IMBaseDefine.ContactSessionInfo parseFrom(java.io.InputStream input) + throws java.io.IOException { + return PARSER.parseFrom(input); + } + public static com.mogujie.tt.protobuf.IMBaseDefine.ContactSessionInfo parseFrom( + java.io.InputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return PARSER.parseFrom(input, extensionRegistry); + } + public static com.mogujie.tt.protobuf.IMBaseDefine.ContactSessionInfo parseDelimitedFrom(java.io.InputStream input) + throws java.io.IOException { + return PARSER.parseDelimitedFrom(input); + } + public static com.mogujie.tt.protobuf.IMBaseDefine.ContactSessionInfo parseDelimitedFrom( + java.io.InputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return PARSER.parseDelimitedFrom(input, extensionRegistry); + } + public static com.mogujie.tt.protobuf.IMBaseDefine.ContactSessionInfo parseFrom( + com.google.protobuf.CodedInputStream input) + throws java.io.IOException { + return PARSER.parseFrom(input); + } + public static com.mogujie.tt.protobuf.IMBaseDefine.ContactSessionInfo parseFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return PARSER.parseFrom(input, extensionRegistry); + } + + public static Builder newBuilder() { return Builder.create(); } + public Builder newBuilderForType() { return newBuilder(); } + public static Builder newBuilder(com.mogujie.tt.protobuf.IMBaseDefine.ContactSessionInfo prototype) { + return newBuilder().mergeFrom(prototype); + } + public Builder toBuilder() { return newBuilder(this); } + + /** + * Protobuf type {@code IM.BaseDefine.ContactSessionInfo} + */ + public static final class Builder extends + com.google.protobuf.GeneratedMessageLite.Builder< + com.mogujie.tt.protobuf.IMBaseDefine.ContactSessionInfo, Builder> + implements + // @@protoc_insertion_point(builder_implements:IM.BaseDefine.ContactSessionInfo) + com.mogujie.tt.protobuf.IMBaseDefine.ContactSessionInfoOrBuilder { + // Construct using com.mogujie.tt.protobuf.IMBaseDefine.ContactSessionInfo.newBuilder() + private Builder() { + maybeForceBuilderInitialization(); + } + + private void maybeForceBuilderInitialization() { + } + private static Builder create() { + return new Builder(); + } + + public Builder clear() { + super.clear(); + sessionId_ = 0; + bitField0_ = (bitField0_ & ~0x00000001); + sessionType_ = com.mogujie.tt.protobuf.IMBaseDefine.SessionType.SESSION_TYPE_SINGLE; + bitField0_ = (bitField0_ & ~0x00000002); + sessionStatus_ = com.mogujie.tt.protobuf.IMBaseDefine.SessionStatusType.SESSION_STATUS_OK; + bitField0_ = (bitField0_ & ~0x00000004); + updatedTime_ = 0; + bitField0_ = (bitField0_ & ~0x00000008); + latestMsgId_ = 0; + bitField0_ = (bitField0_ & ~0x00000010); + latestMsgData_ = com.google.protobuf.ByteString.EMPTY; + bitField0_ = (bitField0_ & ~0x00000020); + latestMsgType_ = com.mogujie.tt.protobuf.IMBaseDefine.MsgType.MSG_TYPE_SINGLE_TEXT; + bitField0_ = (bitField0_ & ~0x00000040); + latestMsgFromUserId_ = 0; + bitField0_ = (bitField0_ & ~0x00000080); + return this; + } + + public Builder clone() { + return create().mergeFrom(buildPartial()); + } + + public com.mogujie.tt.protobuf.IMBaseDefine.ContactSessionInfo getDefaultInstanceForType() { + return com.mogujie.tt.protobuf.IMBaseDefine.ContactSessionInfo.getDefaultInstance(); + } + + public com.mogujie.tt.protobuf.IMBaseDefine.ContactSessionInfo build() { + com.mogujie.tt.protobuf.IMBaseDefine.ContactSessionInfo result = buildPartial(); + if (!result.isInitialized()) { + throw newUninitializedMessageException(result); + } + return result; + } + + public com.mogujie.tt.protobuf.IMBaseDefine.ContactSessionInfo buildPartial() { + com.mogujie.tt.protobuf.IMBaseDefine.ContactSessionInfo result = new com.mogujie.tt.protobuf.IMBaseDefine.ContactSessionInfo(this); + int from_bitField0_ = bitField0_; + int to_bitField0_ = 0; + if (((from_bitField0_ & 0x00000001) == 0x00000001)) { + to_bitField0_ |= 0x00000001; + } + result.sessionId_ = sessionId_; + if (((from_bitField0_ & 0x00000002) == 0x00000002)) { + to_bitField0_ |= 0x00000002; + } + result.sessionType_ = sessionType_; + if (((from_bitField0_ & 0x00000004) == 0x00000004)) { + to_bitField0_ |= 0x00000004; + } + result.sessionStatus_ = sessionStatus_; + if (((from_bitField0_ & 0x00000008) == 0x00000008)) { + to_bitField0_ |= 0x00000008; + } + result.updatedTime_ = updatedTime_; + if (((from_bitField0_ & 0x00000010) == 0x00000010)) { + to_bitField0_ |= 0x00000010; + } + result.latestMsgId_ = latestMsgId_; + if (((from_bitField0_ & 0x00000020) == 0x00000020)) { + to_bitField0_ |= 0x00000020; + } + result.latestMsgData_ = latestMsgData_; + if (((from_bitField0_ & 0x00000040) == 0x00000040)) { + to_bitField0_ |= 0x00000040; + } + result.latestMsgType_ = latestMsgType_; + if (((from_bitField0_ & 0x00000080) == 0x00000080)) { + to_bitField0_ |= 0x00000080; + } + result.latestMsgFromUserId_ = latestMsgFromUserId_; + result.bitField0_ = to_bitField0_; + return result; + } + + public Builder mergeFrom(com.mogujie.tt.protobuf.IMBaseDefine.ContactSessionInfo other) { + if (other == com.mogujie.tt.protobuf.IMBaseDefine.ContactSessionInfo.getDefaultInstance()) return this; + if (other.hasSessionId()) { + setSessionId(other.getSessionId()); + } + if (other.hasSessionType()) { + setSessionType(other.getSessionType()); + } + if (other.hasSessionStatus()) { + setSessionStatus(other.getSessionStatus()); + } + if (other.hasUpdatedTime()) { + setUpdatedTime(other.getUpdatedTime()); + } + if (other.hasLatestMsgId()) { + setLatestMsgId(other.getLatestMsgId()); + } + if (other.hasLatestMsgData()) { + setLatestMsgData(other.getLatestMsgData()); + } + if (other.hasLatestMsgType()) { + setLatestMsgType(other.getLatestMsgType()); + } + if (other.hasLatestMsgFromUserId()) { + setLatestMsgFromUserId(other.getLatestMsgFromUserId()); + } + setUnknownFields( + getUnknownFields().concat(other.unknownFields)); + return this; + } + + public final boolean isInitialized() { + if (!hasSessionId()) { + + return false; + } + if (!hasSessionType()) { + + return false; + } + if (!hasSessionStatus()) { + + return false; + } + if (!hasUpdatedTime()) { + + return false; + } + if (!hasLatestMsgId()) { + + return false; + } + if (!hasLatestMsgData()) { + + return false; + } + if (!hasLatestMsgType()) { + + return false; + } + if (!hasLatestMsgFromUserId()) { + + return false; + } + return true; + } + + public Builder mergeFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + com.mogujie.tt.protobuf.IMBaseDefine.ContactSessionInfo parsedMessage = null; + try { + parsedMessage = PARSER.parsePartialFrom(input, extensionRegistry); + } catch (com.google.protobuf.InvalidProtocolBufferException e) { + parsedMessage = (com.mogujie.tt.protobuf.IMBaseDefine.ContactSessionInfo) e.getUnfinishedMessage(); + throw e; + } finally { + if (parsedMessage != null) { + mergeFrom(parsedMessage); + } + } + return this; + } + private int bitField0_; + + private int sessionId_ ; + /** + * required uint32 session_id = 1; + */ + public boolean hasSessionId() { + return ((bitField0_ & 0x00000001) == 0x00000001); + } + /** + * required uint32 session_id = 1; + */ + public int getSessionId() { + return sessionId_; + } + /** + * required uint32 session_id = 1; + */ + public Builder setSessionId(int value) { + bitField0_ |= 0x00000001; + sessionId_ = value; + + return this; + } + /** + * required uint32 session_id = 1; + */ + public Builder clearSessionId() { + bitField0_ = (bitField0_ & ~0x00000001); + sessionId_ = 0; + + return this; + } + + private com.mogujie.tt.protobuf.IMBaseDefine.SessionType sessionType_ = com.mogujie.tt.protobuf.IMBaseDefine.SessionType.SESSION_TYPE_SINGLE; + /** + * required .IM.BaseDefine.SessionType session_type = 2; + */ + public boolean hasSessionType() { + return ((bitField0_ & 0x00000002) == 0x00000002); + } + /** + * required .IM.BaseDefine.SessionType session_type = 2; + */ + public com.mogujie.tt.protobuf.IMBaseDefine.SessionType getSessionType() { + return sessionType_; + } + /** + * required .IM.BaseDefine.SessionType session_type = 2; + */ + public Builder setSessionType(com.mogujie.tt.protobuf.IMBaseDefine.SessionType value) { + if (value == null) { + throw new NullPointerException(); + } + bitField0_ |= 0x00000002; + sessionType_ = value; + + return this; + } + /** + * required .IM.BaseDefine.SessionType session_type = 2; + */ + public Builder clearSessionType() { + bitField0_ = (bitField0_ & ~0x00000002); + sessionType_ = com.mogujie.tt.protobuf.IMBaseDefine.SessionType.SESSION_TYPE_SINGLE; + + return this; + } + + private com.mogujie.tt.protobuf.IMBaseDefine.SessionStatusType sessionStatus_ = com.mogujie.tt.protobuf.IMBaseDefine.SessionStatusType.SESSION_STATUS_OK; + /** + * required .IM.BaseDefine.SessionStatusType session_status = 3; + */ + public boolean hasSessionStatus() { + return ((bitField0_ & 0x00000004) == 0x00000004); + } + /** + * required .IM.BaseDefine.SessionStatusType session_status = 3; + */ + public com.mogujie.tt.protobuf.IMBaseDefine.SessionStatusType getSessionStatus() { + return sessionStatus_; + } + /** + * required .IM.BaseDefine.SessionStatusType session_status = 3; + */ + public Builder setSessionStatus(com.mogujie.tt.protobuf.IMBaseDefine.SessionStatusType value) { + if (value == null) { + throw new NullPointerException(); + } + bitField0_ |= 0x00000004; + sessionStatus_ = value; + + return this; + } + /** + * required .IM.BaseDefine.SessionStatusType session_status = 3; + */ + public Builder clearSessionStatus() { + bitField0_ = (bitField0_ & ~0x00000004); + sessionStatus_ = com.mogujie.tt.protobuf.IMBaseDefine.SessionStatusType.SESSION_STATUS_OK; + + return this; + } + + private int updatedTime_ ; + /** + * required uint32 updated_time = 4; + */ + public boolean hasUpdatedTime() { + return ((bitField0_ & 0x00000008) == 0x00000008); + } + /** + * required uint32 updated_time = 4; + */ + public int getUpdatedTime() { + return updatedTime_; + } + /** + * required uint32 updated_time = 4; + */ + public Builder setUpdatedTime(int value) { + bitField0_ |= 0x00000008; + updatedTime_ = value; + + return this; + } + /** + * required uint32 updated_time = 4; + */ + public Builder clearUpdatedTime() { + bitField0_ = (bitField0_ & ~0x00000008); + updatedTime_ = 0; + + return this; + } + + private int latestMsgId_ ; + /** + * required uint32 latest_msg_id = 5; + */ + public boolean hasLatestMsgId() { + return ((bitField0_ & 0x00000010) == 0x00000010); + } + /** + * required uint32 latest_msg_id = 5; + */ + public int getLatestMsgId() { + return latestMsgId_; + } + /** + * required uint32 latest_msg_id = 5; + */ + public Builder setLatestMsgId(int value) { + bitField0_ |= 0x00000010; + latestMsgId_ = value; + + return this; + } + /** + * required uint32 latest_msg_id = 5; + */ + public Builder clearLatestMsgId() { + bitField0_ = (bitField0_ & ~0x00000010); + latestMsgId_ = 0; + + return this; + } + + private com.google.protobuf.ByteString latestMsgData_ = com.google.protobuf.ByteString.EMPTY; + /** + * required bytes latest_msg_data = 6; + */ + public boolean hasLatestMsgData() { + return ((bitField0_ & 0x00000020) == 0x00000020); + } + /** + * required bytes latest_msg_data = 6; + */ + public com.google.protobuf.ByteString getLatestMsgData() { + return latestMsgData_; + } + /** + * required bytes latest_msg_data = 6; + */ + public Builder setLatestMsgData(com.google.protobuf.ByteString value) { + if (value == null) { + throw new NullPointerException(); + } + bitField0_ |= 0x00000020; + latestMsgData_ = value; + + return this; + } + /** + * required bytes latest_msg_data = 6; + */ + public Builder clearLatestMsgData() { + bitField0_ = (bitField0_ & ~0x00000020); + latestMsgData_ = getDefaultInstance().getLatestMsgData(); + + return this; + } + + private com.mogujie.tt.protobuf.IMBaseDefine.MsgType latestMsgType_ = com.mogujie.tt.protobuf.IMBaseDefine.MsgType.MSG_TYPE_SINGLE_TEXT; + /** + * required .IM.BaseDefine.MsgType latest_msg_type = 7; + */ + public boolean hasLatestMsgType() { + return ((bitField0_ & 0x00000040) == 0x00000040); + } + /** + * required .IM.BaseDefine.MsgType latest_msg_type = 7; + */ + public com.mogujie.tt.protobuf.IMBaseDefine.MsgType getLatestMsgType() { + return latestMsgType_; + } + /** + * required .IM.BaseDefine.MsgType latest_msg_type = 7; + */ + public Builder setLatestMsgType(com.mogujie.tt.protobuf.IMBaseDefine.MsgType value) { + if (value == null) { + throw new NullPointerException(); + } + bitField0_ |= 0x00000040; + latestMsgType_ = value; + + return this; + } + /** + * required .IM.BaseDefine.MsgType latest_msg_type = 7; + */ + public Builder clearLatestMsgType() { + bitField0_ = (bitField0_ & ~0x00000040); + latestMsgType_ = com.mogujie.tt.protobuf.IMBaseDefine.MsgType.MSG_TYPE_SINGLE_TEXT; + + return this; + } + + private int latestMsgFromUserId_ ; + /** + * required uint32 latest_msg_from_user_id = 8; + */ + public boolean hasLatestMsgFromUserId() { + return ((bitField0_ & 0x00000080) == 0x00000080); + } + /** + * required uint32 latest_msg_from_user_id = 8; + */ + public int getLatestMsgFromUserId() { + return latestMsgFromUserId_; + } + /** + * required uint32 latest_msg_from_user_id = 8; + */ + public Builder setLatestMsgFromUserId(int value) { + bitField0_ |= 0x00000080; + latestMsgFromUserId_ = value; + + return this; + } + /** + * required uint32 latest_msg_from_user_id = 8; + */ + public Builder clearLatestMsgFromUserId() { + bitField0_ = (bitField0_ & ~0x00000080); + latestMsgFromUserId_ = 0; + + return this; + } + + // @@protoc_insertion_point(builder_scope:IM.BaseDefine.ContactSessionInfo) + } + + static { + defaultInstance = new ContactSessionInfo(true); + defaultInstance.initFields(); + } + + // @@protoc_insertion_point(class_scope:IM.BaseDefine.ContactSessionInfo) + } + + public interface UserStatOrBuilder extends + // @@protoc_insertion_point(interface_extends:IM.BaseDefine.UserStat) + com.google.protobuf.MessageLiteOrBuilder { + + /** + * required uint32 user_id = 1; + */ + boolean hasUserId(); + /** + * required uint32 user_id = 1; + */ + int getUserId(); + + /** + * required .IM.BaseDefine.UserStatType status = 2; + */ + boolean hasStatus(); + /** + * required .IM.BaseDefine.UserStatType status = 2; + */ + com.mogujie.tt.protobuf.IMBaseDefine.UserStatType getStatus(); + } + /** + * Protobuf type {@code IM.BaseDefine.UserStat} + */ + public static final class UserStat extends + com.google.protobuf.GeneratedMessageLite implements + // @@protoc_insertion_point(message_implements:IM.BaseDefine.UserStat) + UserStatOrBuilder { + // Use UserStat.newBuilder() to construct. + private UserStat(com.google.protobuf.GeneratedMessageLite.Builder builder) { + super(builder); + this.unknownFields = builder.getUnknownFields(); + } + private UserStat(boolean noInit) { this.unknownFields = com.google.protobuf.ByteString.EMPTY;} + + private static final UserStat defaultInstance; + public static UserStat getDefaultInstance() { + return defaultInstance; + } + + public UserStat getDefaultInstanceForType() { + return defaultInstance; + } + + private final com.google.protobuf.ByteString unknownFields; + private UserStat( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + initFields(); + int mutable_bitField0_ = 0; + com.google.protobuf.ByteString.Output unknownFieldsOutput = + com.google.protobuf.ByteString.newOutput(); + com.google.protobuf.CodedOutputStream unknownFieldsCodedOutput = + com.google.protobuf.CodedOutputStream.newInstance( + unknownFieldsOutput); + try { + boolean done = false; + while (!done) { + int tag = input.readTag(); + switch (tag) { + case 0: + done = true; + break; + default: { + if (!parseUnknownField(input, unknownFieldsCodedOutput, + extensionRegistry, tag)) { + done = true; + } + break; + } + case 8: { + bitField0_ |= 0x00000001; + userId_ = input.readUInt32(); + break; + } + case 16: { + int rawValue = input.readEnum(); + com.mogujie.tt.protobuf.IMBaseDefine.UserStatType value = com.mogujie.tt.protobuf.IMBaseDefine.UserStatType.valueOf(rawValue); + if (value == null) { + unknownFieldsCodedOutput.writeRawVarint32(tag); + unknownFieldsCodedOutput.writeRawVarint32(rawValue); + } else { + bitField0_ |= 0x00000002; + status_ = value; + } + break; + } + } + } + } catch (com.google.protobuf.InvalidProtocolBufferException e) { + throw e.setUnfinishedMessage(this); + } catch (java.io.IOException e) { + throw new com.google.protobuf.InvalidProtocolBufferException( + e.getMessage()).setUnfinishedMessage(this); + } finally { + try { + unknownFieldsCodedOutput.flush(); + } catch (java.io.IOException e) { + // Should not happen + } finally { + unknownFields = unknownFieldsOutput.toByteString(); + } + makeExtensionsImmutable(); + } + } + public static com.google.protobuf.Parser PARSER = + new com.google.protobuf.AbstractParser() { + public UserStat parsePartialFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return new UserStat(input, extensionRegistry); + } + }; + + @java.lang.Override + public com.google.protobuf.Parser getParserForType() { + return PARSER; + } + + private int bitField0_; + public static final int USER_ID_FIELD_NUMBER = 1; + private int userId_; + /** + * required uint32 user_id = 1; + */ + public boolean hasUserId() { + return ((bitField0_ & 0x00000001) == 0x00000001); + } + /** + * required uint32 user_id = 1; + */ + public int getUserId() { + return userId_; + } + + public static final int STATUS_FIELD_NUMBER = 2; + private com.mogujie.tt.protobuf.IMBaseDefine.UserStatType status_; + /** + * required .IM.BaseDefine.UserStatType status = 2; + */ + public boolean hasStatus() { + return ((bitField0_ & 0x00000002) == 0x00000002); + } + /** + * required .IM.BaseDefine.UserStatType status = 2; + */ + public com.mogujie.tt.protobuf.IMBaseDefine.UserStatType getStatus() { + return status_; + } + + private void initFields() { + userId_ = 0; + status_ = com.mogujie.tt.protobuf.IMBaseDefine.UserStatType.USER_STATUS_ONLINE; + } + private byte memoizedIsInitialized = -1; + public final boolean isInitialized() { + byte isInitialized = memoizedIsInitialized; + if (isInitialized == 1) return true; + if (isInitialized == 0) return false; + + if (!hasUserId()) { + memoizedIsInitialized = 0; + return false; + } + if (!hasStatus()) { + memoizedIsInitialized = 0; + return false; + } + memoizedIsInitialized = 1; + return true; + } + + public void writeTo(com.google.protobuf.CodedOutputStream output) + throws java.io.IOException { + getSerializedSize(); + if (((bitField0_ & 0x00000001) == 0x00000001)) { + output.writeUInt32(1, userId_); + } + if (((bitField0_ & 0x00000002) == 0x00000002)) { + output.writeEnum(2, status_.getNumber()); + } + output.writeRawBytes(unknownFields); + } + + private int memoizedSerializedSize = -1; + public int getSerializedSize() { + int size = memoizedSerializedSize; + if (size != -1) return size; + + size = 0; + if (((bitField0_ & 0x00000001) == 0x00000001)) { + size += com.google.protobuf.CodedOutputStream + .computeUInt32Size(1, userId_); + } + if (((bitField0_ & 0x00000002) == 0x00000002)) { + size += com.google.protobuf.CodedOutputStream + .computeEnumSize(2, status_.getNumber()); + } + size += unknownFields.size(); + memoizedSerializedSize = size; + return size; + } + + private static final long serialVersionUID = 0L; + @java.lang.Override + protected java.lang.Object writeReplace() + throws java.io.ObjectStreamException { + return super.writeReplace(); + } + + public static com.mogujie.tt.protobuf.IMBaseDefine.UserStat parseFrom( + com.google.protobuf.ByteString data) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data); + } + public static com.mogujie.tt.protobuf.IMBaseDefine.UserStat parseFrom( + com.google.protobuf.ByteString data, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data, extensionRegistry); + } + public static com.mogujie.tt.protobuf.IMBaseDefine.UserStat parseFrom(byte[] data) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data); + } + public static com.mogujie.tt.protobuf.IMBaseDefine.UserStat parseFrom( + byte[] data, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data, extensionRegistry); + } + public static com.mogujie.tt.protobuf.IMBaseDefine.UserStat parseFrom(java.io.InputStream input) + throws java.io.IOException { + return PARSER.parseFrom(input); + } + public static com.mogujie.tt.protobuf.IMBaseDefine.UserStat parseFrom( + java.io.InputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return PARSER.parseFrom(input, extensionRegistry); + } + public static com.mogujie.tt.protobuf.IMBaseDefine.UserStat parseDelimitedFrom(java.io.InputStream input) + throws java.io.IOException { + return PARSER.parseDelimitedFrom(input); + } + public static com.mogujie.tt.protobuf.IMBaseDefine.UserStat parseDelimitedFrom( + java.io.InputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return PARSER.parseDelimitedFrom(input, extensionRegistry); + } + public static com.mogujie.tt.protobuf.IMBaseDefine.UserStat parseFrom( + com.google.protobuf.CodedInputStream input) + throws java.io.IOException { + return PARSER.parseFrom(input); + } + public static com.mogujie.tt.protobuf.IMBaseDefine.UserStat parseFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return PARSER.parseFrom(input, extensionRegistry); + } + + public static Builder newBuilder() { return Builder.create(); } + public Builder newBuilderForType() { return newBuilder(); } + public static Builder newBuilder(com.mogujie.tt.protobuf.IMBaseDefine.UserStat prototype) { + return newBuilder().mergeFrom(prototype); + } + public Builder toBuilder() { return newBuilder(this); } + + /** + * Protobuf type {@code IM.BaseDefine.UserStat} + */ + public static final class Builder extends + com.google.protobuf.GeneratedMessageLite.Builder< + com.mogujie.tt.protobuf.IMBaseDefine.UserStat, Builder> + implements + // @@protoc_insertion_point(builder_implements:IM.BaseDefine.UserStat) + com.mogujie.tt.protobuf.IMBaseDefine.UserStatOrBuilder { + // Construct using com.mogujie.tt.protobuf.IMBaseDefine.UserStat.newBuilder() + private Builder() { + maybeForceBuilderInitialization(); + } + + private void maybeForceBuilderInitialization() { + } + private static Builder create() { + return new Builder(); + } + + public Builder clear() { + super.clear(); + userId_ = 0; + bitField0_ = (bitField0_ & ~0x00000001); + status_ = com.mogujie.tt.protobuf.IMBaseDefine.UserStatType.USER_STATUS_ONLINE; + bitField0_ = (bitField0_ & ~0x00000002); + return this; + } + + public Builder clone() { + return create().mergeFrom(buildPartial()); + } + + public com.mogujie.tt.protobuf.IMBaseDefine.UserStat getDefaultInstanceForType() { + return com.mogujie.tt.protobuf.IMBaseDefine.UserStat.getDefaultInstance(); + } + + public com.mogujie.tt.protobuf.IMBaseDefine.UserStat build() { + com.mogujie.tt.protobuf.IMBaseDefine.UserStat result = buildPartial(); + if (!result.isInitialized()) { + throw newUninitializedMessageException(result); + } + return result; + } + + public com.mogujie.tt.protobuf.IMBaseDefine.UserStat buildPartial() { + com.mogujie.tt.protobuf.IMBaseDefine.UserStat result = new com.mogujie.tt.protobuf.IMBaseDefine.UserStat(this); + int from_bitField0_ = bitField0_; + int to_bitField0_ = 0; + if (((from_bitField0_ & 0x00000001) == 0x00000001)) { + to_bitField0_ |= 0x00000001; + } + result.userId_ = userId_; + if (((from_bitField0_ & 0x00000002) == 0x00000002)) { + to_bitField0_ |= 0x00000002; + } + result.status_ = status_; + result.bitField0_ = to_bitField0_; + return result; + } + + public Builder mergeFrom(com.mogujie.tt.protobuf.IMBaseDefine.UserStat other) { + if (other == com.mogujie.tt.protobuf.IMBaseDefine.UserStat.getDefaultInstance()) return this; + if (other.hasUserId()) { + setUserId(other.getUserId()); + } + if (other.hasStatus()) { + setStatus(other.getStatus()); + } + setUnknownFields( + getUnknownFields().concat(other.unknownFields)); + return this; + } + + public final boolean isInitialized() { + if (!hasUserId()) { + + return false; + } + if (!hasStatus()) { + + return false; + } + return true; + } + + public Builder mergeFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + com.mogujie.tt.protobuf.IMBaseDefine.UserStat parsedMessage = null; + try { + parsedMessage = PARSER.parsePartialFrom(input, extensionRegistry); + } catch (com.google.protobuf.InvalidProtocolBufferException e) { + parsedMessage = (com.mogujie.tt.protobuf.IMBaseDefine.UserStat) e.getUnfinishedMessage(); + throw e; + } finally { + if (parsedMessage != null) { + mergeFrom(parsedMessage); + } + } + return this; + } + private int bitField0_; + + private int userId_ ; + /** + * required uint32 user_id = 1; + */ + public boolean hasUserId() { + return ((bitField0_ & 0x00000001) == 0x00000001); + } + /** + * required uint32 user_id = 1; + */ + public int getUserId() { + return userId_; + } + /** + * required uint32 user_id = 1; + */ + public Builder setUserId(int value) { + bitField0_ |= 0x00000001; + userId_ = value; + + return this; + } + /** + * required uint32 user_id = 1; + */ + public Builder clearUserId() { + bitField0_ = (bitField0_ & ~0x00000001); + userId_ = 0; + + return this; + } + + private com.mogujie.tt.protobuf.IMBaseDefine.UserStatType status_ = com.mogujie.tt.protobuf.IMBaseDefine.UserStatType.USER_STATUS_ONLINE; + /** + * required .IM.BaseDefine.UserStatType status = 2; + */ + public boolean hasStatus() { + return ((bitField0_ & 0x00000002) == 0x00000002); + } + /** + * required .IM.BaseDefine.UserStatType status = 2; + */ + public com.mogujie.tt.protobuf.IMBaseDefine.UserStatType getStatus() { + return status_; + } + /** + * required .IM.BaseDefine.UserStatType status = 2; + */ + public Builder setStatus(com.mogujie.tt.protobuf.IMBaseDefine.UserStatType value) { + if (value == null) { + throw new NullPointerException(); + } + bitField0_ |= 0x00000002; + status_ = value; + + return this; + } + /** + * required .IM.BaseDefine.UserStatType status = 2; + */ + public Builder clearStatus() { + bitField0_ = (bitField0_ & ~0x00000002); + status_ = com.mogujie.tt.protobuf.IMBaseDefine.UserStatType.USER_STATUS_ONLINE; + + return this; + } + + // @@protoc_insertion_point(builder_scope:IM.BaseDefine.UserStat) + } + + static { + defaultInstance = new UserStat(true); + defaultInstance.initFields(); + } + + // @@protoc_insertion_point(class_scope:IM.BaseDefine.UserStat) + } + + public interface ServerUserStatOrBuilder extends + // @@protoc_insertion_point(interface_extends:IM.BaseDefine.ServerUserStat) + com.google.protobuf.MessageLiteOrBuilder { + + /** + * required uint32 user_id = 1; + */ + boolean hasUserId(); + /** + * required uint32 user_id = 1; + */ + int getUserId(); + + /** + * required .IM.BaseDefine.UserStatType status = 2; + */ + boolean hasStatus(); + /** + * required .IM.BaseDefine.UserStatType status = 2; + */ + com.mogujie.tt.protobuf.IMBaseDefine.UserStatType getStatus(); + + /** + * required .IM.BaseDefine.ClientType client_type = 3; + */ + boolean hasClientType(); + /** + * required .IM.BaseDefine.ClientType client_type = 3; + */ + com.mogujie.tt.protobuf.IMBaseDefine.ClientType getClientType(); + } + /** + * Protobuf type {@code IM.BaseDefine.ServerUserStat} + */ + public static final class ServerUserStat extends + com.google.protobuf.GeneratedMessageLite implements + // @@protoc_insertion_point(message_implements:IM.BaseDefine.ServerUserStat) + ServerUserStatOrBuilder { + // Use ServerUserStat.newBuilder() to construct. + private ServerUserStat(com.google.protobuf.GeneratedMessageLite.Builder builder) { + super(builder); + this.unknownFields = builder.getUnknownFields(); + } + private ServerUserStat(boolean noInit) { this.unknownFields = com.google.protobuf.ByteString.EMPTY;} + + private static final ServerUserStat defaultInstance; + public static ServerUserStat getDefaultInstance() { + return defaultInstance; + } + + public ServerUserStat getDefaultInstanceForType() { + return defaultInstance; + } + + private final com.google.protobuf.ByteString unknownFields; + private ServerUserStat( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + initFields(); + int mutable_bitField0_ = 0; + com.google.protobuf.ByteString.Output unknownFieldsOutput = + com.google.protobuf.ByteString.newOutput(); + com.google.protobuf.CodedOutputStream unknownFieldsCodedOutput = + com.google.protobuf.CodedOutputStream.newInstance( + unknownFieldsOutput); + try { + boolean done = false; + while (!done) { + int tag = input.readTag(); + switch (tag) { + case 0: + done = true; + break; + default: { + if (!parseUnknownField(input, unknownFieldsCodedOutput, + extensionRegistry, tag)) { + done = true; + } + break; + } + case 8: { + bitField0_ |= 0x00000001; + userId_ = input.readUInt32(); + break; + } + case 16: { + int rawValue = input.readEnum(); + com.mogujie.tt.protobuf.IMBaseDefine.UserStatType value = com.mogujie.tt.protobuf.IMBaseDefine.UserStatType.valueOf(rawValue); + if (value == null) { + unknownFieldsCodedOutput.writeRawVarint32(tag); + unknownFieldsCodedOutput.writeRawVarint32(rawValue); + } else { + bitField0_ |= 0x00000002; + status_ = value; + } + break; + } + case 24: { + int rawValue = input.readEnum(); + com.mogujie.tt.protobuf.IMBaseDefine.ClientType value = com.mogujie.tt.protobuf.IMBaseDefine.ClientType.valueOf(rawValue); + if (value == null) { + unknownFieldsCodedOutput.writeRawVarint32(tag); + unknownFieldsCodedOutput.writeRawVarint32(rawValue); + } else { + bitField0_ |= 0x00000004; + clientType_ = value; + } + break; + } + } + } + } catch (com.google.protobuf.InvalidProtocolBufferException e) { + throw e.setUnfinishedMessage(this); + } catch (java.io.IOException e) { + throw new com.google.protobuf.InvalidProtocolBufferException( + e.getMessage()).setUnfinishedMessage(this); + } finally { + try { + unknownFieldsCodedOutput.flush(); + } catch (java.io.IOException e) { + // Should not happen + } finally { + unknownFields = unknownFieldsOutput.toByteString(); + } + makeExtensionsImmutable(); + } + } + public static com.google.protobuf.Parser PARSER = + new com.google.protobuf.AbstractParser() { + public ServerUserStat parsePartialFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return new ServerUserStat(input, extensionRegistry); + } + }; + + @java.lang.Override + public com.google.protobuf.Parser getParserForType() { + return PARSER; + } + + private int bitField0_; + public static final int USER_ID_FIELD_NUMBER = 1; + private int userId_; + /** + * required uint32 user_id = 1; + */ + public boolean hasUserId() { + return ((bitField0_ & 0x00000001) == 0x00000001); + } + /** + * required uint32 user_id = 1; + */ + public int getUserId() { + return userId_; + } + + public static final int STATUS_FIELD_NUMBER = 2; + private com.mogujie.tt.protobuf.IMBaseDefine.UserStatType status_; + /** + * required .IM.BaseDefine.UserStatType status = 2; + */ + public boolean hasStatus() { + return ((bitField0_ & 0x00000002) == 0x00000002); + } + /** + * required .IM.BaseDefine.UserStatType status = 2; + */ + public com.mogujie.tt.protobuf.IMBaseDefine.UserStatType getStatus() { + return status_; + } + + public static final int CLIENT_TYPE_FIELD_NUMBER = 3; + private com.mogujie.tt.protobuf.IMBaseDefine.ClientType clientType_; + /** + * required .IM.BaseDefine.ClientType client_type = 3; + */ + public boolean hasClientType() { + return ((bitField0_ & 0x00000004) == 0x00000004); + } + /** + * required .IM.BaseDefine.ClientType client_type = 3; + */ + public com.mogujie.tt.protobuf.IMBaseDefine.ClientType getClientType() { + return clientType_; + } + + private void initFields() { + userId_ = 0; + status_ = com.mogujie.tt.protobuf.IMBaseDefine.UserStatType.USER_STATUS_ONLINE; + clientType_ = com.mogujie.tt.protobuf.IMBaseDefine.ClientType.CLIENT_TYPE_WINDOWS; + } + private byte memoizedIsInitialized = -1; + public final boolean isInitialized() { + byte isInitialized = memoizedIsInitialized; + if (isInitialized == 1) return true; + if (isInitialized == 0) return false; + + if (!hasUserId()) { + memoizedIsInitialized = 0; + return false; + } + if (!hasStatus()) { + memoizedIsInitialized = 0; + return false; + } + if (!hasClientType()) { + memoizedIsInitialized = 0; + return false; + } + memoizedIsInitialized = 1; + return true; + } + + public void writeTo(com.google.protobuf.CodedOutputStream output) + throws java.io.IOException { + getSerializedSize(); + if (((bitField0_ & 0x00000001) == 0x00000001)) { + output.writeUInt32(1, userId_); + } + if (((bitField0_ & 0x00000002) == 0x00000002)) { + output.writeEnum(2, status_.getNumber()); + } + if (((bitField0_ & 0x00000004) == 0x00000004)) { + output.writeEnum(3, clientType_.getNumber()); + } + output.writeRawBytes(unknownFields); + } + + private int memoizedSerializedSize = -1; + public int getSerializedSize() { + int size = memoizedSerializedSize; + if (size != -1) return size; + + size = 0; + if (((bitField0_ & 0x00000001) == 0x00000001)) { + size += com.google.protobuf.CodedOutputStream + .computeUInt32Size(1, userId_); + } + if (((bitField0_ & 0x00000002) == 0x00000002)) { + size += com.google.protobuf.CodedOutputStream + .computeEnumSize(2, status_.getNumber()); + } + if (((bitField0_ & 0x00000004) == 0x00000004)) { + size += com.google.protobuf.CodedOutputStream + .computeEnumSize(3, clientType_.getNumber()); + } + size += unknownFields.size(); + memoizedSerializedSize = size; + return size; + } + + private static final long serialVersionUID = 0L; + @java.lang.Override + protected java.lang.Object writeReplace() + throws java.io.ObjectStreamException { + return super.writeReplace(); + } + + public static com.mogujie.tt.protobuf.IMBaseDefine.ServerUserStat parseFrom( + com.google.protobuf.ByteString data) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data); + } + public static com.mogujie.tt.protobuf.IMBaseDefine.ServerUserStat parseFrom( + com.google.protobuf.ByteString data, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data, extensionRegistry); + } + public static com.mogujie.tt.protobuf.IMBaseDefine.ServerUserStat parseFrom(byte[] data) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data); + } + public static com.mogujie.tt.protobuf.IMBaseDefine.ServerUserStat parseFrom( + byte[] data, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data, extensionRegistry); + } + public static com.mogujie.tt.protobuf.IMBaseDefine.ServerUserStat parseFrom(java.io.InputStream input) + throws java.io.IOException { + return PARSER.parseFrom(input); + } + public static com.mogujie.tt.protobuf.IMBaseDefine.ServerUserStat parseFrom( + java.io.InputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return PARSER.parseFrom(input, extensionRegistry); + } + public static com.mogujie.tt.protobuf.IMBaseDefine.ServerUserStat parseDelimitedFrom(java.io.InputStream input) + throws java.io.IOException { + return PARSER.parseDelimitedFrom(input); + } + public static com.mogujie.tt.protobuf.IMBaseDefine.ServerUserStat parseDelimitedFrom( + java.io.InputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return PARSER.parseDelimitedFrom(input, extensionRegistry); + } + public static com.mogujie.tt.protobuf.IMBaseDefine.ServerUserStat parseFrom( + com.google.protobuf.CodedInputStream input) + throws java.io.IOException { + return PARSER.parseFrom(input); + } + public static com.mogujie.tt.protobuf.IMBaseDefine.ServerUserStat parseFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return PARSER.parseFrom(input, extensionRegistry); + } + + public static Builder newBuilder() { return Builder.create(); } + public Builder newBuilderForType() { return newBuilder(); } + public static Builder newBuilder(com.mogujie.tt.protobuf.IMBaseDefine.ServerUserStat prototype) { + return newBuilder().mergeFrom(prototype); + } + public Builder toBuilder() { return newBuilder(this); } + + /** + * Protobuf type {@code IM.BaseDefine.ServerUserStat} + */ + public static final class Builder extends + com.google.protobuf.GeneratedMessageLite.Builder< + com.mogujie.tt.protobuf.IMBaseDefine.ServerUserStat, Builder> + implements + // @@protoc_insertion_point(builder_implements:IM.BaseDefine.ServerUserStat) + com.mogujie.tt.protobuf.IMBaseDefine.ServerUserStatOrBuilder { + // Construct using com.mogujie.tt.protobuf.IMBaseDefine.ServerUserStat.newBuilder() + private Builder() { + maybeForceBuilderInitialization(); + } + + private void maybeForceBuilderInitialization() { + } + private static Builder create() { + return new Builder(); + } + + public Builder clear() { + super.clear(); + userId_ = 0; + bitField0_ = (bitField0_ & ~0x00000001); + status_ = com.mogujie.tt.protobuf.IMBaseDefine.UserStatType.USER_STATUS_ONLINE; + bitField0_ = (bitField0_ & ~0x00000002); + clientType_ = com.mogujie.tt.protobuf.IMBaseDefine.ClientType.CLIENT_TYPE_WINDOWS; + bitField0_ = (bitField0_ & ~0x00000004); + return this; + } + + public Builder clone() { + return create().mergeFrom(buildPartial()); + } + + public com.mogujie.tt.protobuf.IMBaseDefine.ServerUserStat getDefaultInstanceForType() { + return com.mogujie.tt.protobuf.IMBaseDefine.ServerUserStat.getDefaultInstance(); + } + + public com.mogujie.tt.protobuf.IMBaseDefine.ServerUserStat build() { + com.mogujie.tt.protobuf.IMBaseDefine.ServerUserStat result = buildPartial(); + if (!result.isInitialized()) { + throw newUninitializedMessageException(result); + } + return result; + } + + public com.mogujie.tt.protobuf.IMBaseDefine.ServerUserStat buildPartial() { + com.mogujie.tt.protobuf.IMBaseDefine.ServerUserStat result = new com.mogujie.tt.protobuf.IMBaseDefine.ServerUserStat(this); + int from_bitField0_ = bitField0_; + int to_bitField0_ = 0; + if (((from_bitField0_ & 0x00000001) == 0x00000001)) { + to_bitField0_ |= 0x00000001; + } + result.userId_ = userId_; + if (((from_bitField0_ & 0x00000002) == 0x00000002)) { + to_bitField0_ |= 0x00000002; + } + result.status_ = status_; + if (((from_bitField0_ & 0x00000004) == 0x00000004)) { + to_bitField0_ |= 0x00000004; + } + result.clientType_ = clientType_; + result.bitField0_ = to_bitField0_; + return result; + } + + public Builder mergeFrom(com.mogujie.tt.protobuf.IMBaseDefine.ServerUserStat other) { + if (other == com.mogujie.tt.protobuf.IMBaseDefine.ServerUserStat.getDefaultInstance()) return this; + if (other.hasUserId()) { + setUserId(other.getUserId()); + } + if (other.hasStatus()) { + setStatus(other.getStatus()); + } + if (other.hasClientType()) { + setClientType(other.getClientType()); + } + setUnknownFields( + getUnknownFields().concat(other.unknownFields)); + return this; + } + + public final boolean isInitialized() { + if (!hasUserId()) { + + return false; + } + if (!hasStatus()) { + + return false; + } + if (!hasClientType()) { + + return false; + } + return true; + } + + public Builder mergeFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + com.mogujie.tt.protobuf.IMBaseDefine.ServerUserStat parsedMessage = null; + try { + parsedMessage = PARSER.parsePartialFrom(input, extensionRegistry); + } catch (com.google.protobuf.InvalidProtocolBufferException e) { + parsedMessage = (com.mogujie.tt.protobuf.IMBaseDefine.ServerUserStat) e.getUnfinishedMessage(); + throw e; + } finally { + if (parsedMessage != null) { + mergeFrom(parsedMessage); + } + } + return this; + } + private int bitField0_; + + private int userId_ ; + /** + * required uint32 user_id = 1; + */ + public boolean hasUserId() { + return ((bitField0_ & 0x00000001) == 0x00000001); + } + /** + * required uint32 user_id = 1; + */ + public int getUserId() { + return userId_; + } + /** + * required uint32 user_id = 1; + */ + public Builder setUserId(int value) { + bitField0_ |= 0x00000001; + userId_ = value; + + return this; + } + /** + * required uint32 user_id = 1; + */ + public Builder clearUserId() { + bitField0_ = (bitField0_ & ~0x00000001); + userId_ = 0; + + return this; + } + + private com.mogujie.tt.protobuf.IMBaseDefine.UserStatType status_ = com.mogujie.tt.protobuf.IMBaseDefine.UserStatType.USER_STATUS_ONLINE; + /** + * required .IM.BaseDefine.UserStatType status = 2; + */ + public boolean hasStatus() { + return ((bitField0_ & 0x00000002) == 0x00000002); + } + /** + * required .IM.BaseDefine.UserStatType status = 2; + */ + public com.mogujie.tt.protobuf.IMBaseDefine.UserStatType getStatus() { + return status_; + } + /** + * required .IM.BaseDefine.UserStatType status = 2; + */ + public Builder setStatus(com.mogujie.tt.protobuf.IMBaseDefine.UserStatType value) { + if (value == null) { + throw new NullPointerException(); + } + bitField0_ |= 0x00000002; + status_ = value; + + return this; + } + /** + * required .IM.BaseDefine.UserStatType status = 2; + */ + public Builder clearStatus() { + bitField0_ = (bitField0_ & ~0x00000002); + status_ = com.mogujie.tt.protobuf.IMBaseDefine.UserStatType.USER_STATUS_ONLINE; + + return this; + } + + private com.mogujie.tt.protobuf.IMBaseDefine.ClientType clientType_ = com.mogujie.tt.protobuf.IMBaseDefine.ClientType.CLIENT_TYPE_WINDOWS; + /** + * required .IM.BaseDefine.ClientType client_type = 3; + */ + public boolean hasClientType() { + return ((bitField0_ & 0x00000004) == 0x00000004); + } + /** + * required .IM.BaseDefine.ClientType client_type = 3; + */ + public com.mogujie.tt.protobuf.IMBaseDefine.ClientType getClientType() { + return clientType_; + } + /** + * required .IM.BaseDefine.ClientType client_type = 3; + */ + public Builder setClientType(com.mogujie.tt.protobuf.IMBaseDefine.ClientType value) { + if (value == null) { + throw new NullPointerException(); + } + bitField0_ |= 0x00000004; + clientType_ = value; + + return this; + } + /** + * required .IM.BaseDefine.ClientType client_type = 3; + */ + public Builder clearClientType() { + bitField0_ = (bitField0_ & ~0x00000004); + clientType_ = com.mogujie.tt.protobuf.IMBaseDefine.ClientType.CLIENT_TYPE_WINDOWS; + + return this; + } + + // @@protoc_insertion_point(builder_scope:IM.BaseDefine.ServerUserStat) + } + + static { + defaultInstance = new ServerUserStat(true); + defaultInstance.initFields(); + } + + // @@protoc_insertion_point(class_scope:IM.BaseDefine.ServerUserStat) + } + + public interface UnreadInfoOrBuilder extends + // @@protoc_insertion_point(interface_extends:IM.BaseDefine.UnreadInfo) + com.google.protobuf.MessageLiteOrBuilder { + + /** + * required uint32 session_id = 1; + */ + boolean hasSessionId(); + /** + * required uint32 session_id = 1; + */ + int getSessionId(); + + /** + * required .IM.BaseDefine.SessionType session_type = 2; + */ + boolean hasSessionType(); + /** + * required .IM.BaseDefine.SessionType session_type = 2; + */ + com.mogujie.tt.protobuf.IMBaseDefine.SessionType getSessionType(); + + /** + * required uint32 unread_cnt = 3; + */ + boolean hasUnreadCnt(); + /** + * required uint32 unread_cnt = 3; + */ + int getUnreadCnt(); + + /** + * required uint32 latest_msg_id = 4; + */ + boolean hasLatestMsgId(); + /** + * required uint32 latest_msg_id = 4; + */ + int getLatestMsgId(); + + /** + * required bytes latest_msg_data = 5; + */ + boolean hasLatestMsgData(); + /** + * required bytes latest_msg_data = 5; + */ + com.google.protobuf.ByteString getLatestMsgData(); + + /** + * required .IM.BaseDefine.MsgType latest_msg_type = 6; + */ + boolean hasLatestMsgType(); + /** + * required .IM.BaseDefine.MsgType latest_msg_type = 6; + */ + com.mogujie.tt.protobuf.IMBaseDefine.MsgType getLatestMsgType(); + + /** + * required uint32 latest_msg_from_user_id = 7; + * + *
+     *发送得用户id
+     * 
+ */ + boolean hasLatestMsgFromUserId(); + /** + * required uint32 latest_msg_from_user_id = 7; + * + *
+     *发送得用户id
+     * 
+ */ + int getLatestMsgFromUserId(); + } + /** + * Protobuf type {@code IM.BaseDefine.UnreadInfo} + */ + public static final class UnreadInfo extends + com.google.protobuf.GeneratedMessageLite implements + // @@protoc_insertion_point(message_implements:IM.BaseDefine.UnreadInfo) + UnreadInfoOrBuilder { + // Use UnreadInfo.newBuilder() to construct. + private UnreadInfo(com.google.protobuf.GeneratedMessageLite.Builder builder) { + super(builder); + this.unknownFields = builder.getUnknownFields(); + } + private UnreadInfo(boolean noInit) { this.unknownFields = com.google.protobuf.ByteString.EMPTY;} + + private static final UnreadInfo defaultInstance; + public static UnreadInfo getDefaultInstance() { + return defaultInstance; + } + + public UnreadInfo getDefaultInstanceForType() { + return defaultInstance; + } + + private final com.google.protobuf.ByteString unknownFields; + private UnreadInfo( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + initFields(); + int mutable_bitField0_ = 0; + com.google.protobuf.ByteString.Output unknownFieldsOutput = + com.google.protobuf.ByteString.newOutput(); + com.google.protobuf.CodedOutputStream unknownFieldsCodedOutput = + com.google.protobuf.CodedOutputStream.newInstance( + unknownFieldsOutput); + try { + boolean done = false; + while (!done) { + int tag = input.readTag(); + switch (tag) { + case 0: + done = true; + break; + default: { + if (!parseUnknownField(input, unknownFieldsCodedOutput, + extensionRegistry, tag)) { + done = true; + } + break; + } + case 8: { + bitField0_ |= 0x00000001; + sessionId_ = input.readUInt32(); + break; + } + case 16: { + int rawValue = input.readEnum(); + com.mogujie.tt.protobuf.IMBaseDefine.SessionType value = com.mogujie.tt.protobuf.IMBaseDefine.SessionType.valueOf(rawValue); + if (value == null) { + unknownFieldsCodedOutput.writeRawVarint32(tag); + unknownFieldsCodedOutput.writeRawVarint32(rawValue); + } else { + bitField0_ |= 0x00000002; + sessionType_ = value; + } + break; + } + case 24: { + bitField0_ |= 0x00000004; + unreadCnt_ = input.readUInt32(); + break; + } + case 32: { + bitField0_ |= 0x00000008; + latestMsgId_ = input.readUInt32(); + break; + } + case 42: { + bitField0_ |= 0x00000010; + latestMsgData_ = input.readBytes(); + break; + } + case 48: { + int rawValue = input.readEnum(); + com.mogujie.tt.protobuf.IMBaseDefine.MsgType value = com.mogujie.tt.protobuf.IMBaseDefine.MsgType.valueOf(rawValue); + if (value == null) { + unknownFieldsCodedOutput.writeRawVarint32(tag); + unknownFieldsCodedOutput.writeRawVarint32(rawValue); + } else { + bitField0_ |= 0x00000020; + latestMsgType_ = value; + } + break; + } + case 56: { + bitField0_ |= 0x00000040; + latestMsgFromUserId_ = input.readUInt32(); + break; + } + } + } + } catch (com.google.protobuf.InvalidProtocolBufferException e) { + throw e.setUnfinishedMessage(this); + } catch (java.io.IOException e) { + throw new com.google.protobuf.InvalidProtocolBufferException( + e.getMessage()).setUnfinishedMessage(this); + } finally { + try { + unknownFieldsCodedOutput.flush(); + } catch (java.io.IOException e) { + // Should not happen + } finally { + unknownFields = unknownFieldsOutput.toByteString(); + } + makeExtensionsImmutable(); + } + } + public static com.google.protobuf.Parser PARSER = + new com.google.protobuf.AbstractParser() { + public UnreadInfo parsePartialFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return new UnreadInfo(input, extensionRegistry); + } + }; + + @java.lang.Override + public com.google.protobuf.Parser getParserForType() { + return PARSER; + } + + private int bitField0_; + public static final int SESSION_ID_FIELD_NUMBER = 1; + private int sessionId_; + /** + * required uint32 session_id = 1; + */ + public boolean hasSessionId() { + return ((bitField0_ & 0x00000001) == 0x00000001); + } + /** + * required uint32 session_id = 1; + */ + public int getSessionId() { + return sessionId_; + } + + public static final int SESSION_TYPE_FIELD_NUMBER = 2; + private com.mogujie.tt.protobuf.IMBaseDefine.SessionType sessionType_; + /** + * required .IM.BaseDefine.SessionType session_type = 2; + */ + public boolean hasSessionType() { + return ((bitField0_ & 0x00000002) == 0x00000002); + } + /** + * required .IM.BaseDefine.SessionType session_type = 2; + */ + public com.mogujie.tt.protobuf.IMBaseDefine.SessionType getSessionType() { + return sessionType_; + } + + public static final int UNREAD_CNT_FIELD_NUMBER = 3; + private int unreadCnt_; + /** + * required uint32 unread_cnt = 3; + */ + public boolean hasUnreadCnt() { + return ((bitField0_ & 0x00000004) == 0x00000004); + } + /** + * required uint32 unread_cnt = 3; + */ + public int getUnreadCnt() { + return unreadCnt_; + } + + public static final int LATEST_MSG_ID_FIELD_NUMBER = 4; + private int latestMsgId_; + /** + * required uint32 latest_msg_id = 4; + */ + public boolean hasLatestMsgId() { + return ((bitField0_ & 0x00000008) == 0x00000008); + } + /** + * required uint32 latest_msg_id = 4; + */ + public int getLatestMsgId() { + return latestMsgId_; + } + + public static final int LATEST_MSG_DATA_FIELD_NUMBER = 5; + private com.google.protobuf.ByteString latestMsgData_; + /** + * required bytes latest_msg_data = 5; + */ + public boolean hasLatestMsgData() { + return ((bitField0_ & 0x00000010) == 0x00000010); + } + /** + * required bytes latest_msg_data = 5; + */ + public com.google.protobuf.ByteString getLatestMsgData() { + return latestMsgData_; + } + + public static final int LATEST_MSG_TYPE_FIELD_NUMBER = 6; + private com.mogujie.tt.protobuf.IMBaseDefine.MsgType latestMsgType_; + /** + * required .IM.BaseDefine.MsgType latest_msg_type = 6; + */ + public boolean hasLatestMsgType() { + return ((bitField0_ & 0x00000020) == 0x00000020); + } + /** + * required .IM.BaseDefine.MsgType latest_msg_type = 6; + */ + public com.mogujie.tt.protobuf.IMBaseDefine.MsgType getLatestMsgType() { + return latestMsgType_; + } + + public static final int LATEST_MSG_FROM_USER_ID_FIELD_NUMBER = 7; + private int latestMsgFromUserId_; + /** + * required uint32 latest_msg_from_user_id = 7; + * + *
+     *发送得用户id
+     * 
+ */ + public boolean hasLatestMsgFromUserId() { + return ((bitField0_ & 0x00000040) == 0x00000040); + } + /** + * required uint32 latest_msg_from_user_id = 7; + * + *
+     *发送得用户id
+     * 
+ */ + public int getLatestMsgFromUserId() { + return latestMsgFromUserId_; + } + + private void initFields() { + sessionId_ = 0; + sessionType_ = com.mogujie.tt.protobuf.IMBaseDefine.SessionType.SESSION_TYPE_SINGLE; + unreadCnt_ = 0; + latestMsgId_ = 0; + latestMsgData_ = com.google.protobuf.ByteString.EMPTY; + latestMsgType_ = com.mogujie.tt.protobuf.IMBaseDefine.MsgType.MSG_TYPE_SINGLE_TEXT; + latestMsgFromUserId_ = 0; + } + private byte memoizedIsInitialized = -1; + public final boolean isInitialized() { + byte isInitialized = memoizedIsInitialized; + if (isInitialized == 1) return true; + if (isInitialized == 0) return false; + + if (!hasSessionId()) { + memoizedIsInitialized = 0; + return false; + } + if (!hasSessionType()) { + memoizedIsInitialized = 0; + return false; + } + if (!hasUnreadCnt()) { + memoizedIsInitialized = 0; + return false; + } + if (!hasLatestMsgId()) { + memoizedIsInitialized = 0; + return false; + } + if (!hasLatestMsgData()) { + memoizedIsInitialized = 0; + return false; + } + if (!hasLatestMsgType()) { + memoizedIsInitialized = 0; + return false; + } + if (!hasLatestMsgFromUserId()) { + memoizedIsInitialized = 0; + return false; + } + memoizedIsInitialized = 1; + return true; + } + + public void writeTo(com.google.protobuf.CodedOutputStream output) + throws java.io.IOException { + getSerializedSize(); + if (((bitField0_ & 0x00000001) == 0x00000001)) { + output.writeUInt32(1, sessionId_); + } + if (((bitField0_ & 0x00000002) == 0x00000002)) { + output.writeEnum(2, sessionType_.getNumber()); + } + if (((bitField0_ & 0x00000004) == 0x00000004)) { + output.writeUInt32(3, unreadCnt_); + } + if (((bitField0_ & 0x00000008) == 0x00000008)) { + output.writeUInt32(4, latestMsgId_); + } + if (((bitField0_ & 0x00000010) == 0x00000010)) { + output.writeBytes(5, latestMsgData_); + } + if (((bitField0_ & 0x00000020) == 0x00000020)) { + output.writeEnum(6, latestMsgType_.getNumber()); + } + if (((bitField0_ & 0x00000040) == 0x00000040)) { + output.writeUInt32(7, latestMsgFromUserId_); + } + output.writeRawBytes(unknownFields); + } + + private int memoizedSerializedSize = -1; + public int getSerializedSize() { + int size = memoizedSerializedSize; + if (size != -1) return size; + + size = 0; + if (((bitField0_ & 0x00000001) == 0x00000001)) { + size += com.google.protobuf.CodedOutputStream + .computeUInt32Size(1, sessionId_); + } + if (((bitField0_ & 0x00000002) == 0x00000002)) { + size += com.google.protobuf.CodedOutputStream + .computeEnumSize(2, sessionType_.getNumber()); + } + if (((bitField0_ & 0x00000004) == 0x00000004)) { + size += com.google.protobuf.CodedOutputStream + .computeUInt32Size(3, unreadCnt_); + } + if (((bitField0_ & 0x00000008) == 0x00000008)) { + size += com.google.protobuf.CodedOutputStream + .computeUInt32Size(4, latestMsgId_); + } + if (((bitField0_ & 0x00000010) == 0x00000010)) { + size += com.google.protobuf.CodedOutputStream + .computeBytesSize(5, latestMsgData_); + } + if (((bitField0_ & 0x00000020) == 0x00000020)) { + size += com.google.protobuf.CodedOutputStream + .computeEnumSize(6, latestMsgType_.getNumber()); + } + if (((bitField0_ & 0x00000040) == 0x00000040)) { + size += com.google.protobuf.CodedOutputStream + .computeUInt32Size(7, latestMsgFromUserId_); + } + size += unknownFields.size(); + memoizedSerializedSize = size; + return size; + } + + private static final long serialVersionUID = 0L; + @java.lang.Override + protected java.lang.Object writeReplace() + throws java.io.ObjectStreamException { + return super.writeReplace(); + } + + public static com.mogujie.tt.protobuf.IMBaseDefine.UnreadInfo parseFrom( + com.google.protobuf.ByteString data) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data); + } + public static com.mogujie.tt.protobuf.IMBaseDefine.UnreadInfo parseFrom( + com.google.protobuf.ByteString data, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data, extensionRegistry); + } + public static com.mogujie.tt.protobuf.IMBaseDefine.UnreadInfo parseFrom(byte[] data) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data); + } + public static com.mogujie.tt.protobuf.IMBaseDefine.UnreadInfo parseFrom( + byte[] data, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data, extensionRegistry); + } + public static com.mogujie.tt.protobuf.IMBaseDefine.UnreadInfo parseFrom(java.io.InputStream input) + throws java.io.IOException { + return PARSER.parseFrom(input); + } + public static com.mogujie.tt.protobuf.IMBaseDefine.UnreadInfo parseFrom( + java.io.InputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return PARSER.parseFrom(input, extensionRegistry); + } + public static com.mogujie.tt.protobuf.IMBaseDefine.UnreadInfo parseDelimitedFrom(java.io.InputStream input) + throws java.io.IOException { + return PARSER.parseDelimitedFrom(input); + } + public static com.mogujie.tt.protobuf.IMBaseDefine.UnreadInfo parseDelimitedFrom( + java.io.InputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return PARSER.parseDelimitedFrom(input, extensionRegistry); + } + public static com.mogujie.tt.protobuf.IMBaseDefine.UnreadInfo parseFrom( + com.google.protobuf.CodedInputStream input) + throws java.io.IOException { + return PARSER.parseFrom(input); + } + public static com.mogujie.tt.protobuf.IMBaseDefine.UnreadInfo parseFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return PARSER.parseFrom(input, extensionRegistry); + } + + public static Builder newBuilder() { return Builder.create(); } + public Builder newBuilderForType() { return newBuilder(); } + public static Builder newBuilder(com.mogujie.tt.protobuf.IMBaseDefine.UnreadInfo prototype) { + return newBuilder().mergeFrom(prototype); + } + public Builder toBuilder() { return newBuilder(this); } + + /** + * Protobuf type {@code IM.BaseDefine.UnreadInfo} + */ + public static final class Builder extends + com.google.protobuf.GeneratedMessageLite.Builder< + com.mogujie.tt.protobuf.IMBaseDefine.UnreadInfo, Builder> + implements + // @@protoc_insertion_point(builder_implements:IM.BaseDefine.UnreadInfo) + com.mogujie.tt.protobuf.IMBaseDefine.UnreadInfoOrBuilder { + // Construct using com.mogujie.tt.protobuf.IMBaseDefine.UnreadInfo.newBuilder() + private Builder() { + maybeForceBuilderInitialization(); + } + + private void maybeForceBuilderInitialization() { + } + private static Builder create() { + return new Builder(); + } + + public Builder clear() { + super.clear(); + sessionId_ = 0; + bitField0_ = (bitField0_ & ~0x00000001); + sessionType_ = com.mogujie.tt.protobuf.IMBaseDefine.SessionType.SESSION_TYPE_SINGLE; + bitField0_ = (bitField0_ & ~0x00000002); + unreadCnt_ = 0; + bitField0_ = (bitField0_ & ~0x00000004); + latestMsgId_ = 0; + bitField0_ = (bitField0_ & ~0x00000008); + latestMsgData_ = com.google.protobuf.ByteString.EMPTY; + bitField0_ = (bitField0_ & ~0x00000010); + latestMsgType_ = com.mogujie.tt.protobuf.IMBaseDefine.MsgType.MSG_TYPE_SINGLE_TEXT; + bitField0_ = (bitField0_ & ~0x00000020); + latestMsgFromUserId_ = 0; + bitField0_ = (bitField0_ & ~0x00000040); + return this; + } + + public Builder clone() { + return create().mergeFrom(buildPartial()); + } + + public com.mogujie.tt.protobuf.IMBaseDefine.UnreadInfo getDefaultInstanceForType() { + return com.mogujie.tt.protobuf.IMBaseDefine.UnreadInfo.getDefaultInstance(); + } + + public com.mogujie.tt.protobuf.IMBaseDefine.UnreadInfo build() { + com.mogujie.tt.protobuf.IMBaseDefine.UnreadInfo result = buildPartial(); + if (!result.isInitialized()) { + throw newUninitializedMessageException(result); + } + return result; + } + + public com.mogujie.tt.protobuf.IMBaseDefine.UnreadInfo buildPartial() { + com.mogujie.tt.protobuf.IMBaseDefine.UnreadInfo result = new com.mogujie.tt.protobuf.IMBaseDefine.UnreadInfo(this); + int from_bitField0_ = bitField0_; + int to_bitField0_ = 0; + if (((from_bitField0_ & 0x00000001) == 0x00000001)) { + to_bitField0_ |= 0x00000001; + } + result.sessionId_ = sessionId_; + if (((from_bitField0_ & 0x00000002) == 0x00000002)) { + to_bitField0_ |= 0x00000002; + } + result.sessionType_ = sessionType_; + if (((from_bitField0_ & 0x00000004) == 0x00000004)) { + to_bitField0_ |= 0x00000004; + } + result.unreadCnt_ = unreadCnt_; + if (((from_bitField0_ & 0x00000008) == 0x00000008)) { + to_bitField0_ |= 0x00000008; + } + result.latestMsgId_ = latestMsgId_; + if (((from_bitField0_ & 0x00000010) == 0x00000010)) { + to_bitField0_ |= 0x00000010; + } + result.latestMsgData_ = latestMsgData_; + if (((from_bitField0_ & 0x00000020) == 0x00000020)) { + to_bitField0_ |= 0x00000020; + } + result.latestMsgType_ = latestMsgType_; + if (((from_bitField0_ & 0x00000040) == 0x00000040)) { + to_bitField0_ |= 0x00000040; + } + result.latestMsgFromUserId_ = latestMsgFromUserId_; + result.bitField0_ = to_bitField0_; + return result; + } + + public Builder mergeFrom(com.mogujie.tt.protobuf.IMBaseDefine.UnreadInfo other) { + if (other == com.mogujie.tt.protobuf.IMBaseDefine.UnreadInfo.getDefaultInstance()) return this; + if (other.hasSessionId()) { + setSessionId(other.getSessionId()); + } + if (other.hasSessionType()) { + setSessionType(other.getSessionType()); + } + if (other.hasUnreadCnt()) { + setUnreadCnt(other.getUnreadCnt()); + } + if (other.hasLatestMsgId()) { + setLatestMsgId(other.getLatestMsgId()); + } + if (other.hasLatestMsgData()) { + setLatestMsgData(other.getLatestMsgData()); + } + if (other.hasLatestMsgType()) { + setLatestMsgType(other.getLatestMsgType()); + } + if (other.hasLatestMsgFromUserId()) { + setLatestMsgFromUserId(other.getLatestMsgFromUserId()); + } + setUnknownFields( + getUnknownFields().concat(other.unknownFields)); + return this; + } + + public final boolean isInitialized() { + if (!hasSessionId()) { + + return false; + } + if (!hasSessionType()) { + + return false; + } + if (!hasUnreadCnt()) { + + return false; + } + if (!hasLatestMsgId()) { + + return false; + } + if (!hasLatestMsgData()) { + + return false; + } + if (!hasLatestMsgType()) { + + return false; + } + if (!hasLatestMsgFromUserId()) { + + return false; + } + return true; + } + + public Builder mergeFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + com.mogujie.tt.protobuf.IMBaseDefine.UnreadInfo parsedMessage = null; + try { + parsedMessage = PARSER.parsePartialFrom(input, extensionRegistry); + } catch (com.google.protobuf.InvalidProtocolBufferException e) { + parsedMessage = (com.mogujie.tt.protobuf.IMBaseDefine.UnreadInfo) e.getUnfinishedMessage(); + throw e; + } finally { + if (parsedMessage != null) { + mergeFrom(parsedMessage); + } + } + return this; + } + private int bitField0_; + + private int sessionId_ ; + /** + * required uint32 session_id = 1; + */ + public boolean hasSessionId() { + return ((bitField0_ & 0x00000001) == 0x00000001); + } + /** + * required uint32 session_id = 1; + */ + public int getSessionId() { + return sessionId_; + } + /** + * required uint32 session_id = 1; + */ + public Builder setSessionId(int value) { + bitField0_ |= 0x00000001; + sessionId_ = value; + + return this; + } + /** + * required uint32 session_id = 1; + */ + public Builder clearSessionId() { + bitField0_ = (bitField0_ & ~0x00000001); + sessionId_ = 0; + + return this; + } + + private com.mogujie.tt.protobuf.IMBaseDefine.SessionType sessionType_ = com.mogujie.tt.protobuf.IMBaseDefine.SessionType.SESSION_TYPE_SINGLE; + /** + * required .IM.BaseDefine.SessionType session_type = 2; + */ + public boolean hasSessionType() { + return ((bitField0_ & 0x00000002) == 0x00000002); + } + /** + * required .IM.BaseDefine.SessionType session_type = 2; + */ + public com.mogujie.tt.protobuf.IMBaseDefine.SessionType getSessionType() { + return sessionType_; + } + /** + * required .IM.BaseDefine.SessionType session_type = 2; + */ + public Builder setSessionType(com.mogujie.tt.protobuf.IMBaseDefine.SessionType value) { + if (value == null) { + throw new NullPointerException(); + } + bitField0_ |= 0x00000002; + sessionType_ = value; + + return this; + } + /** + * required .IM.BaseDefine.SessionType session_type = 2; + */ + public Builder clearSessionType() { + bitField0_ = (bitField0_ & ~0x00000002); + sessionType_ = com.mogujie.tt.protobuf.IMBaseDefine.SessionType.SESSION_TYPE_SINGLE; + + return this; + } + + private int unreadCnt_ ; + /** + * required uint32 unread_cnt = 3; + */ + public boolean hasUnreadCnt() { + return ((bitField0_ & 0x00000004) == 0x00000004); + } + /** + * required uint32 unread_cnt = 3; + */ + public int getUnreadCnt() { + return unreadCnt_; + } + /** + * required uint32 unread_cnt = 3; + */ + public Builder setUnreadCnt(int value) { + bitField0_ |= 0x00000004; + unreadCnt_ = value; + + return this; + } + /** + * required uint32 unread_cnt = 3; + */ + public Builder clearUnreadCnt() { + bitField0_ = (bitField0_ & ~0x00000004); + unreadCnt_ = 0; + + return this; + } + + private int latestMsgId_ ; + /** + * required uint32 latest_msg_id = 4; + */ + public boolean hasLatestMsgId() { + return ((bitField0_ & 0x00000008) == 0x00000008); + } + /** + * required uint32 latest_msg_id = 4; + */ + public int getLatestMsgId() { + return latestMsgId_; + } + /** + * required uint32 latest_msg_id = 4; + */ + public Builder setLatestMsgId(int value) { + bitField0_ |= 0x00000008; + latestMsgId_ = value; + + return this; + } + /** + * required uint32 latest_msg_id = 4; + */ + public Builder clearLatestMsgId() { + bitField0_ = (bitField0_ & ~0x00000008); + latestMsgId_ = 0; + + return this; + } + + private com.google.protobuf.ByteString latestMsgData_ = com.google.protobuf.ByteString.EMPTY; + /** + * required bytes latest_msg_data = 5; + */ + public boolean hasLatestMsgData() { + return ((bitField0_ & 0x00000010) == 0x00000010); + } + /** + * required bytes latest_msg_data = 5; + */ + public com.google.protobuf.ByteString getLatestMsgData() { + return latestMsgData_; + } + /** + * required bytes latest_msg_data = 5; + */ + public Builder setLatestMsgData(com.google.protobuf.ByteString value) { + if (value == null) { + throw new NullPointerException(); + } + bitField0_ |= 0x00000010; + latestMsgData_ = value; + + return this; + } + /** + * required bytes latest_msg_data = 5; + */ + public Builder clearLatestMsgData() { + bitField0_ = (bitField0_ & ~0x00000010); + latestMsgData_ = getDefaultInstance().getLatestMsgData(); + + return this; + } + + private com.mogujie.tt.protobuf.IMBaseDefine.MsgType latestMsgType_ = com.mogujie.tt.protobuf.IMBaseDefine.MsgType.MSG_TYPE_SINGLE_TEXT; + /** + * required .IM.BaseDefine.MsgType latest_msg_type = 6; + */ + public boolean hasLatestMsgType() { + return ((bitField0_ & 0x00000020) == 0x00000020); + } + /** + * required .IM.BaseDefine.MsgType latest_msg_type = 6; + */ + public com.mogujie.tt.protobuf.IMBaseDefine.MsgType getLatestMsgType() { + return latestMsgType_; + } + /** + * required .IM.BaseDefine.MsgType latest_msg_type = 6; + */ + public Builder setLatestMsgType(com.mogujie.tt.protobuf.IMBaseDefine.MsgType value) { + if (value == null) { + throw new NullPointerException(); + } + bitField0_ |= 0x00000020; + latestMsgType_ = value; + + return this; + } + /** + * required .IM.BaseDefine.MsgType latest_msg_type = 6; + */ + public Builder clearLatestMsgType() { + bitField0_ = (bitField0_ & ~0x00000020); + latestMsgType_ = com.mogujie.tt.protobuf.IMBaseDefine.MsgType.MSG_TYPE_SINGLE_TEXT; + + return this; + } + + private int latestMsgFromUserId_ ; + /** + * required uint32 latest_msg_from_user_id = 7; + * + *
+       *发送得用户id
+       * 
+ */ + public boolean hasLatestMsgFromUserId() { + return ((bitField0_ & 0x00000040) == 0x00000040); + } + /** + * required uint32 latest_msg_from_user_id = 7; + * + *
+       *发送得用户id
+       * 
+ */ + public int getLatestMsgFromUserId() { + return latestMsgFromUserId_; + } + /** + * required uint32 latest_msg_from_user_id = 7; + * + *
+       *发送得用户id
+       * 
+ */ + public Builder setLatestMsgFromUserId(int value) { + bitField0_ |= 0x00000040; + latestMsgFromUserId_ = value; + + return this; + } + /** + * required uint32 latest_msg_from_user_id = 7; + * + *
+       *发送得用户id
+       * 
+ */ + public Builder clearLatestMsgFromUserId() { + bitField0_ = (bitField0_ & ~0x00000040); + latestMsgFromUserId_ = 0; + + return this; + } + + // @@protoc_insertion_point(builder_scope:IM.BaseDefine.UnreadInfo) + } + + static { + defaultInstance = new UnreadInfo(true); + defaultInstance.initFields(); + } + + // @@protoc_insertion_point(class_scope:IM.BaseDefine.UnreadInfo) + } + + public interface MsgInfoOrBuilder extends + // @@protoc_insertion_point(interface_extends:IM.BaseDefine.MsgInfo) + com.google.protobuf.MessageLiteOrBuilder { + + /** + * required uint32 msg_id = 1; + */ + boolean hasMsgId(); + /** + * required uint32 msg_id = 1; + */ + int getMsgId(); + + /** + * required uint32 from_session_id = 2; + * + *
+     *发送的用户id
+     * 
+ */ + boolean hasFromSessionId(); + /** + * required uint32 from_session_id = 2; + * + *
+     *发送的用户id
+     * 
+ */ + int getFromSessionId(); + + /** + * required uint32 create_time = 3; + */ + boolean hasCreateTime(); + /** + * required uint32 create_time = 3; + */ + int getCreateTime(); + + /** + * required .IM.BaseDefine.MsgType msg_type = 4; + */ + boolean hasMsgType(); + /** + * required .IM.BaseDefine.MsgType msg_type = 4; + */ + com.mogujie.tt.protobuf.IMBaseDefine.MsgType getMsgType(); + + /** + * required bytes msg_data = 5; + */ + boolean hasMsgData(); + /** + * required bytes msg_data = 5; + */ + com.google.protobuf.ByteString getMsgData(); + } + /** + * Protobuf type {@code IM.BaseDefine.MsgInfo} + */ + public static final class MsgInfo extends + com.google.protobuf.GeneratedMessageLite implements + // @@protoc_insertion_point(message_implements:IM.BaseDefine.MsgInfo) + MsgInfoOrBuilder { + // Use MsgInfo.newBuilder() to construct. + private MsgInfo(com.google.protobuf.GeneratedMessageLite.Builder builder) { + super(builder); + this.unknownFields = builder.getUnknownFields(); + } + private MsgInfo(boolean noInit) { this.unknownFields = com.google.protobuf.ByteString.EMPTY;} + + private static final MsgInfo defaultInstance; + public static MsgInfo getDefaultInstance() { + return defaultInstance; + } + + public MsgInfo getDefaultInstanceForType() { + return defaultInstance; + } + + private final com.google.protobuf.ByteString unknownFields; + private MsgInfo( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + initFields(); + int mutable_bitField0_ = 0; + com.google.protobuf.ByteString.Output unknownFieldsOutput = + com.google.protobuf.ByteString.newOutput(); + com.google.protobuf.CodedOutputStream unknownFieldsCodedOutput = + com.google.protobuf.CodedOutputStream.newInstance( + unknownFieldsOutput); + try { + boolean done = false; + while (!done) { + int tag = input.readTag(); + switch (tag) { + case 0: + done = true; + break; + default: { + if (!parseUnknownField(input, unknownFieldsCodedOutput, + extensionRegistry, tag)) { + done = true; + } + break; + } + case 8: { + bitField0_ |= 0x00000001; + msgId_ = input.readUInt32(); + break; + } + case 16: { + bitField0_ |= 0x00000002; + fromSessionId_ = input.readUInt32(); + break; + } + case 24: { + bitField0_ |= 0x00000004; + createTime_ = input.readUInt32(); + break; + } + case 32: { + int rawValue = input.readEnum(); + com.mogujie.tt.protobuf.IMBaseDefine.MsgType value = com.mogujie.tt.protobuf.IMBaseDefine.MsgType.valueOf(rawValue); + if (value == null) { + unknownFieldsCodedOutput.writeRawVarint32(tag); + unknownFieldsCodedOutput.writeRawVarint32(rawValue); + } else { + bitField0_ |= 0x00000008; + msgType_ = value; + } + break; + } + case 42: { + bitField0_ |= 0x00000010; + msgData_ = input.readBytes(); + break; + } + } + } + } catch (com.google.protobuf.InvalidProtocolBufferException e) { + throw e.setUnfinishedMessage(this); + } catch (java.io.IOException e) { + throw new com.google.protobuf.InvalidProtocolBufferException( + e.getMessage()).setUnfinishedMessage(this); + } finally { + try { + unknownFieldsCodedOutput.flush(); + } catch (java.io.IOException e) { + // Should not happen + } finally { + unknownFields = unknownFieldsOutput.toByteString(); + } + makeExtensionsImmutable(); + } + } + public static com.google.protobuf.Parser PARSER = + new com.google.protobuf.AbstractParser() { + public MsgInfo parsePartialFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return new MsgInfo(input, extensionRegistry); + } + }; + + @java.lang.Override + public com.google.protobuf.Parser getParserForType() { + return PARSER; + } + + private int bitField0_; + public static final int MSG_ID_FIELD_NUMBER = 1; + private int msgId_; + /** + * required uint32 msg_id = 1; + */ + public boolean hasMsgId() { + return ((bitField0_ & 0x00000001) == 0x00000001); + } + /** + * required uint32 msg_id = 1; + */ + public int getMsgId() { + return msgId_; + } + + public static final int FROM_SESSION_ID_FIELD_NUMBER = 2; + private int fromSessionId_; + /** + * required uint32 from_session_id = 2; + * + *
+     *发送的用户id
+     * 
+ */ + public boolean hasFromSessionId() { + return ((bitField0_ & 0x00000002) == 0x00000002); + } + /** + * required uint32 from_session_id = 2; + * + *
+     *发送的用户id
+     * 
+ */ + public int getFromSessionId() { + return fromSessionId_; + } + + public static final int CREATE_TIME_FIELD_NUMBER = 3; + private int createTime_; + /** + * required uint32 create_time = 3; + */ + public boolean hasCreateTime() { + return ((bitField0_ & 0x00000004) == 0x00000004); + } + /** + * required uint32 create_time = 3; + */ + public int getCreateTime() { + return createTime_; + } + + public static final int MSG_TYPE_FIELD_NUMBER = 4; + private com.mogujie.tt.protobuf.IMBaseDefine.MsgType msgType_; + /** + * required .IM.BaseDefine.MsgType msg_type = 4; + */ + public boolean hasMsgType() { + return ((bitField0_ & 0x00000008) == 0x00000008); + } + /** + * required .IM.BaseDefine.MsgType msg_type = 4; + */ + public com.mogujie.tt.protobuf.IMBaseDefine.MsgType getMsgType() { + return msgType_; + } + + public static final int MSG_DATA_FIELD_NUMBER = 5; + private com.google.protobuf.ByteString msgData_; + /** + * required bytes msg_data = 5; + */ + public boolean hasMsgData() { + return ((bitField0_ & 0x00000010) == 0x00000010); + } + /** + * required bytes msg_data = 5; + */ + public com.google.protobuf.ByteString getMsgData() { + return msgData_; + } + + private void initFields() { + msgId_ = 0; + fromSessionId_ = 0; + createTime_ = 0; + msgType_ = com.mogujie.tt.protobuf.IMBaseDefine.MsgType.MSG_TYPE_SINGLE_TEXT; + msgData_ = com.google.protobuf.ByteString.EMPTY; + } + private byte memoizedIsInitialized = -1; + public final boolean isInitialized() { + byte isInitialized = memoizedIsInitialized; + if (isInitialized == 1) return true; + if (isInitialized == 0) return false; + + if (!hasMsgId()) { + memoizedIsInitialized = 0; + return false; + } + if (!hasFromSessionId()) { + memoizedIsInitialized = 0; + return false; + } + if (!hasCreateTime()) { + memoizedIsInitialized = 0; + return false; + } + if (!hasMsgType()) { + memoizedIsInitialized = 0; + return false; + } + if (!hasMsgData()) { + memoizedIsInitialized = 0; + return false; + } + memoizedIsInitialized = 1; + return true; + } + + public void writeTo(com.google.protobuf.CodedOutputStream output) + throws java.io.IOException { + getSerializedSize(); + if (((bitField0_ & 0x00000001) == 0x00000001)) { + output.writeUInt32(1, msgId_); + } + if (((bitField0_ & 0x00000002) == 0x00000002)) { + output.writeUInt32(2, fromSessionId_); + } + if (((bitField0_ & 0x00000004) == 0x00000004)) { + output.writeUInt32(3, createTime_); + } + if (((bitField0_ & 0x00000008) == 0x00000008)) { + output.writeEnum(4, msgType_.getNumber()); + } + if (((bitField0_ & 0x00000010) == 0x00000010)) { + output.writeBytes(5, msgData_); + } + output.writeRawBytes(unknownFields); + } + + private int memoizedSerializedSize = -1; + public int getSerializedSize() { + int size = memoizedSerializedSize; + if (size != -1) return size; + + size = 0; + if (((bitField0_ & 0x00000001) == 0x00000001)) { + size += com.google.protobuf.CodedOutputStream + .computeUInt32Size(1, msgId_); + } + if (((bitField0_ & 0x00000002) == 0x00000002)) { + size += com.google.protobuf.CodedOutputStream + .computeUInt32Size(2, fromSessionId_); + } + if (((bitField0_ & 0x00000004) == 0x00000004)) { + size += com.google.protobuf.CodedOutputStream + .computeUInt32Size(3, createTime_); + } + if (((bitField0_ & 0x00000008) == 0x00000008)) { + size += com.google.protobuf.CodedOutputStream + .computeEnumSize(4, msgType_.getNumber()); + } + if (((bitField0_ & 0x00000010) == 0x00000010)) { + size += com.google.protobuf.CodedOutputStream + .computeBytesSize(5, msgData_); + } + size += unknownFields.size(); + memoizedSerializedSize = size; + return size; + } + + private static final long serialVersionUID = 0L; + @java.lang.Override + protected java.lang.Object writeReplace() + throws java.io.ObjectStreamException { + return super.writeReplace(); + } + + public static com.mogujie.tt.protobuf.IMBaseDefine.MsgInfo parseFrom( + com.google.protobuf.ByteString data) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data); + } + public static com.mogujie.tt.protobuf.IMBaseDefine.MsgInfo parseFrom( + com.google.protobuf.ByteString data, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data, extensionRegistry); + } + public static com.mogujie.tt.protobuf.IMBaseDefine.MsgInfo parseFrom(byte[] data) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data); + } + public static com.mogujie.tt.protobuf.IMBaseDefine.MsgInfo parseFrom( + byte[] data, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data, extensionRegistry); + } + public static com.mogujie.tt.protobuf.IMBaseDefine.MsgInfo parseFrom(java.io.InputStream input) + throws java.io.IOException { + return PARSER.parseFrom(input); + } + public static com.mogujie.tt.protobuf.IMBaseDefine.MsgInfo parseFrom( + java.io.InputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return PARSER.parseFrom(input, extensionRegistry); + } + public static com.mogujie.tt.protobuf.IMBaseDefine.MsgInfo parseDelimitedFrom(java.io.InputStream input) + throws java.io.IOException { + return PARSER.parseDelimitedFrom(input); + } + public static com.mogujie.tt.protobuf.IMBaseDefine.MsgInfo parseDelimitedFrom( + java.io.InputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return PARSER.parseDelimitedFrom(input, extensionRegistry); + } + public static com.mogujie.tt.protobuf.IMBaseDefine.MsgInfo parseFrom( + com.google.protobuf.CodedInputStream input) + throws java.io.IOException { + return PARSER.parseFrom(input); + } + public static com.mogujie.tt.protobuf.IMBaseDefine.MsgInfo parseFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return PARSER.parseFrom(input, extensionRegistry); + } + + public static Builder newBuilder() { return Builder.create(); } + public Builder newBuilderForType() { return newBuilder(); } + public static Builder newBuilder(com.mogujie.tt.protobuf.IMBaseDefine.MsgInfo prototype) { + return newBuilder().mergeFrom(prototype); + } + public Builder toBuilder() { return newBuilder(this); } + + /** + * Protobuf type {@code IM.BaseDefine.MsgInfo} + */ + public static final class Builder extends + com.google.protobuf.GeneratedMessageLite.Builder< + com.mogujie.tt.protobuf.IMBaseDefine.MsgInfo, Builder> + implements + // @@protoc_insertion_point(builder_implements:IM.BaseDefine.MsgInfo) + com.mogujie.tt.protobuf.IMBaseDefine.MsgInfoOrBuilder { + // Construct using com.mogujie.tt.protobuf.IMBaseDefine.MsgInfo.newBuilder() + private Builder() { + maybeForceBuilderInitialization(); + } + + private void maybeForceBuilderInitialization() { + } + private static Builder create() { + return new Builder(); + } + + public Builder clear() { + super.clear(); + msgId_ = 0; + bitField0_ = (bitField0_ & ~0x00000001); + fromSessionId_ = 0; + bitField0_ = (bitField0_ & ~0x00000002); + createTime_ = 0; + bitField0_ = (bitField0_ & ~0x00000004); + msgType_ = com.mogujie.tt.protobuf.IMBaseDefine.MsgType.MSG_TYPE_SINGLE_TEXT; + bitField0_ = (bitField0_ & ~0x00000008); + msgData_ = com.google.protobuf.ByteString.EMPTY; + bitField0_ = (bitField0_ & ~0x00000010); + return this; + } + + public Builder clone() { + return create().mergeFrom(buildPartial()); + } + + public com.mogujie.tt.protobuf.IMBaseDefine.MsgInfo getDefaultInstanceForType() { + return com.mogujie.tt.protobuf.IMBaseDefine.MsgInfo.getDefaultInstance(); + } + + public com.mogujie.tt.protobuf.IMBaseDefine.MsgInfo build() { + com.mogujie.tt.protobuf.IMBaseDefine.MsgInfo result = buildPartial(); + if (!result.isInitialized()) { + throw newUninitializedMessageException(result); + } + return result; + } + + public com.mogujie.tt.protobuf.IMBaseDefine.MsgInfo buildPartial() { + com.mogujie.tt.protobuf.IMBaseDefine.MsgInfo result = new com.mogujie.tt.protobuf.IMBaseDefine.MsgInfo(this); + int from_bitField0_ = bitField0_; + int to_bitField0_ = 0; + if (((from_bitField0_ & 0x00000001) == 0x00000001)) { + to_bitField0_ |= 0x00000001; + } + result.msgId_ = msgId_; + if (((from_bitField0_ & 0x00000002) == 0x00000002)) { + to_bitField0_ |= 0x00000002; + } + result.fromSessionId_ = fromSessionId_; + if (((from_bitField0_ & 0x00000004) == 0x00000004)) { + to_bitField0_ |= 0x00000004; + } + result.createTime_ = createTime_; + if (((from_bitField0_ & 0x00000008) == 0x00000008)) { + to_bitField0_ |= 0x00000008; + } + result.msgType_ = msgType_; + if (((from_bitField0_ & 0x00000010) == 0x00000010)) { + to_bitField0_ |= 0x00000010; + } + result.msgData_ = msgData_; + result.bitField0_ = to_bitField0_; + return result; + } + + public Builder mergeFrom(com.mogujie.tt.protobuf.IMBaseDefine.MsgInfo other) { + if (other == com.mogujie.tt.protobuf.IMBaseDefine.MsgInfo.getDefaultInstance()) return this; + if (other.hasMsgId()) { + setMsgId(other.getMsgId()); + } + if (other.hasFromSessionId()) { + setFromSessionId(other.getFromSessionId()); + } + if (other.hasCreateTime()) { + setCreateTime(other.getCreateTime()); + } + if (other.hasMsgType()) { + setMsgType(other.getMsgType()); + } + if (other.hasMsgData()) { + setMsgData(other.getMsgData()); + } + setUnknownFields( + getUnknownFields().concat(other.unknownFields)); + return this; + } + + public final boolean isInitialized() { + if (!hasMsgId()) { + + return false; + } + if (!hasFromSessionId()) { + + return false; + } + if (!hasCreateTime()) { + + return false; + } + if (!hasMsgType()) { + + return false; + } + if (!hasMsgData()) { + + return false; + } + return true; + } + + public Builder mergeFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + com.mogujie.tt.protobuf.IMBaseDefine.MsgInfo parsedMessage = null; + try { + parsedMessage = PARSER.parsePartialFrom(input, extensionRegistry); + } catch (com.google.protobuf.InvalidProtocolBufferException e) { + parsedMessage = (com.mogujie.tt.protobuf.IMBaseDefine.MsgInfo) e.getUnfinishedMessage(); + throw e; + } finally { + if (parsedMessage != null) { + mergeFrom(parsedMessage); + } + } + return this; + } + private int bitField0_; + + private int msgId_ ; + /** + * required uint32 msg_id = 1; + */ + public boolean hasMsgId() { + return ((bitField0_ & 0x00000001) == 0x00000001); + } + /** + * required uint32 msg_id = 1; + */ + public int getMsgId() { + return msgId_; + } + /** + * required uint32 msg_id = 1; + */ + public Builder setMsgId(int value) { + bitField0_ |= 0x00000001; + msgId_ = value; + + return this; + } + /** + * required uint32 msg_id = 1; + */ + public Builder clearMsgId() { + bitField0_ = (bitField0_ & ~0x00000001); + msgId_ = 0; + + return this; + } + + private int fromSessionId_ ; + /** + * required uint32 from_session_id = 2; + * + *
+       *发送的用户id
+       * 
+ */ + public boolean hasFromSessionId() { + return ((bitField0_ & 0x00000002) == 0x00000002); + } + /** + * required uint32 from_session_id = 2; + * + *
+       *发送的用户id
+       * 
+ */ + public int getFromSessionId() { + return fromSessionId_; + } + /** + * required uint32 from_session_id = 2; + * + *
+       *发送的用户id
+       * 
+ */ + public Builder setFromSessionId(int value) { + bitField0_ |= 0x00000002; + fromSessionId_ = value; + + return this; + } + /** + * required uint32 from_session_id = 2; + * + *
+       *发送的用户id
+       * 
+ */ + public Builder clearFromSessionId() { + bitField0_ = (bitField0_ & ~0x00000002); + fromSessionId_ = 0; + + return this; + } + + private int createTime_ ; + /** + * required uint32 create_time = 3; + */ + public boolean hasCreateTime() { + return ((bitField0_ & 0x00000004) == 0x00000004); + } + /** + * required uint32 create_time = 3; + */ + public int getCreateTime() { + return createTime_; + } + /** + * required uint32 create_time = 3; + */ + public Builder setCreateTime(int value) { + bitField0_ |= 0x00000004; + createTime_ = value; + + return this; + } + /** + * required uint32 create_time = 3; + */ + public Builder clearCreateTime() { + bitField0_ = (bitField0_ & ~0x00000004); + createTime_ = 0; + + return this; + } + + private com.mogujie.tt.protobuf.IMBaseDefine.MsgType msgType_ = com.mogujie.tt.protobuf.IMBaseDefine.MsgType.MSG_TYPE_SINGLE_TEXT; + /** + * required .IM.BaseDefine.MsgType msg_type = 4; + */ + public boolean hasMsgType() { + return ((bitField0_ & 0x00000008) == 0x00000008); + } + /** + * required .IM.BaseDefine.MsgType msg_type = 4; + */ + public com.mogujie.tt.protobuf.IMBaseDefine.MsgType getMsgType() { + return msgType_; + } + /** + * required .IM.BaseDefine.MsgType msg_type = 4; + */ + public Builder setMsgType(com.mogujie.tt.protobuf.IMBaseDefine.MsgType value) { + if (value == null) { + throw new NullPointerException(); + } + bitField0_ |= 0x00000008; + msgType_ = value; + + return this; + } + /** + * required .IM.BaseDefine.MsgType msg_type = 4; + */ + public Builder clearMsgType() { + bitField0_ = (bitField0_ & ~0x00000008); + msgType_ = com.mogujie.tt.protobuf.IMBaseDefine.MsgType.MSG_TYPE_SINGLE_TEXT; + + return this; + } + + private com.google.protobuf.ByteString msgData_ = com.google.protobuf.ByteString.EMPTY; + /** + * required bytes msg_data = 5; + */ + public boolean hasMsgData() { + return ((bitField0_ & 0x00000010) == 0x00000010); + } + /** + * required bytes msg_data = 5; + */ + public com.google.protobuf.ByteString getMsgData() { + return msgData_; + } + /** + * required bytes msg_data = 5; + */ + public Builder setMsgData(com.google.protobuf.ByteString value) { + if (value == null) { + throw new NullPointerException(); + } + bitField0_ |= 0x00000010; + msgData_ = value; + + return this; + } + /** + * required bytes msg_data = 5; + */ + public Builder clearMsgData() { + bitField0_ = (bitField0_ & ~0x00000010); + msgData_ = getDefaultInstance().getMsgData(); + + return this; + } + + // @@protoc_insertion_point(builder_scope:IM.BaseDefine.MsgInfo) + } + + static { + defaultInstance = new MsgInfo(true); + defaultInstance.initFields(); + } + + // @@protoc_insertion_point(class_scope:IM.BaseDefine.MsgInfo) + } + + public interface GroupVersionInfoOrBuilder extends + // @@protoc_insertion_point(interface_extends:IM.BaseDefine.GroupVersionInfo) + com.google.protobuf.MessageLiteOrBuilder { + + /** + * required uint32 group_id = 1; + */ + boolean hasGroupId(); + /** + * required uint32 group_id = 1; + */ + int getGroupId(); + + /** + * required uint32 version = 2; + */ + boolean hasVersion(); + /** + * required uint32 version = 2; + */ + int getVersion(); + } + /** + * Protobuf type {@code IM.BaseDefine.GroupVersionInfo} + */ + public static final class GroupVersionInfo extends + com.google.protobuf.GeneratedMessageLite implements + // @@protoc_insertion_point(message_implements:IM.BaseDefine.GroupVersionInfo) + GroupVersionInfoOrBuilder { + // Use GroupVersionInfo.newBuilder() to construct. + private GroupVersionInfo(com.google.protobuf.GeneratedMessageLite.Builder builder) { + super(builder); + this.unknownFields = builder.getUnknownFields(); + } + private GroupVersionInfo(boolean noInit) { this.unknownFields = com.google.protobuf.ByteString.EMPTY;} + + private static final GroupVersionInfo defaultInstance; + public static GroupVersionInfo getDefaultInstance() { + return defaultInstance; + } + + public GroupVersionInfo getDefaultInstanceForType() { + return defaultInstance; + } + + private final com.google.protobuf.ByteString unknownFields; + private GroupVersionInfo( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + initFields(); + int mutable_bitField0_ = 0; + com.google.protobuf.ByteString.Output unknownFieldsOutput = + com.google.protobuf.ByteString.newOutput(); + com.google.protobuf.CodedOutputStream unknownFieldsCodedOutput = + com.google.protobuf.CodedOutputStream.newInstance( + unknownFieldsOutput); + try { + boolean done = false; + while (!done) { + int tag = input.readTag(); + switch (tag) { + case 0: + done = true; + break; + default: { + if (!parseUnknownField(input, unknownFieldsCodedOutput, + extensionRegistry, tag)) { + done = true; + } + break; + } + case 8: { + bitField0_ |= 0x00000001; + groupId_ = input.readUInt32(); + break; + } + case 16: { + bitField0_ |= 0x00000002; + version_ = input.readUInt32(); + break; + } + } + } + } catch (com.google.protobuf.InvalidProtocolBufferException e) { + throw e.setUnfinishedMessage(this); + } catch (java.io.IOException e) { + throw new com.google.protobuf.InvalidProtocolBufferException( + e.getMessage()).setUnfinishedMessage(this); + } finally { + try { + unknownFieldsCodedOutput.flush(); + } catch (java.io.IOException e) { + // Should not happen + } finally { + unknownFields = unknownFieldsOutput.toByteString(); + } + makeExtensionsImmutable(); + } + } + public static com.google.protobuf.Parser PARSER = + new com.google.protobuf.AbstractParser() { + public GroupVersionInfo parsePartialFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return new GroupVersionInfo(input, extensionRegistry); + } + }; + + @java.lang.Override + public com.google.protobuf.Parser getParserForType() { + return PARSER; + } + + private int bitField0_; + public static final int GROUP_ID_FIELD_NUMBER = 1; + private int groupId_; + /** + * required uint32 group_id = 1; + */ + public boolean hasGroupId() { + return ((bitField0_ & 0x00000001) == 0x00000001); + } + /** + * required uint32 group_id = 1; + */ + public int getGroupId() { + return groupId_; + } + + public static final int VERSION_FIELD_NUMBER = 2; + private int version_; + /** + * required uint32 version = 2; + */ + public boolean hasVersion() { + return ((bitField0_ & 0x00000002) == 0x00000002); + } + /** + * required uint32 version = 2; + */ + public int getVersion() { + return version_; + } + + private void initFields() { + groupId_ = 0; + version_ = 0; + } + private byte memoizedIsInitialized = -1; + public final boolean isInitialized() { + byte isInitialized = memoizedIsInitialized; + if (isInitialized == 1) return true; + if (isInitialized == 0) return false; + + if (!hasGroupId()) { + memoizedIsInitialized = 0; + return false; + } + if (!hasVersion()) { + memoizedIsInitialized = 0; + return false; + } + memoizedIsInitialized = 1; + return true; + } + + public void writeTo(com.google.protobuf.CodedOutputStream output) + throws java.io.IOException { + getSerializedSize(); + if (((bitField0_ & 0x00000001) == 0x00000001)) { + output.writeUInt32(1, groupId_); + } + if (((bitField0_ & 0x00000002) == 0x00000002)) { + output.writeUInt32(2, version_); + } + output.writeRawBytes(unknownFields); + } + + private int memoizedSerializedSize = -1; + public int getSerializedSize() { + int size = memoizedSerializedSize; + if (size != -1) return size; + + size = 0; + if (((bitField0_ & 0x00000001) == 0x00000001)) { + size += com.google.protobuf.CodedOutputStream + .computeUInt32Size(1, groupId_); + } + if (((bitField0_ & 0x00000002) == 0x00000002)) { + size += com.google.protobuf.CodedOutputStream + .computeUInt32Size(2, version_); + } + size += unknownFields.size(); + memoizedSerializedSize = size; + return size; + } + + private static final long serialVersionUID = 0L; + @java.lang.Override + protected java.lang.Object writeReplace() + throws java.io.ObjectStreamException { + return super.writeReplace(); + } + + public static com.mogujie.tt.protobuf.IMBaseDefine.GroupVersionInfo parseFrom( + com.google.protobuf.ByteString data) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data); + } + public static com.mogujie.tt.protobuf.IMBaseDefine.GroupVersionInfo parseFrom( + com.google.protobuf.ByteString data, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data, extensionRegistry); + } + public static com.mogujie.tt.protobuf.IMBaseDefine.GroupVersionInfo parseFrom(byte[] data) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data); + } + public static com.mogujie.tt.protobuf.IMBaseDefine.GroupVersionInfo parseFrom( + byte[] data, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data, extensionRegistry); + } + public static com.mogujie.tt.protobuf.IMBaseDefine.GroupVersionInfo parseFrom(java.io.InputStream input) + throws java.io.IOException { + return PARSER.parseFrom(input); + } + public static com.mogujie.tt.protobuf.IMBaseDefine.GroupVersionInfo parseFrom( + java.io.InputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return PARSER.parseFrom(input, extensionRegistry); + } + public static com.mogujie.tt.protobuf.IMBaseDefine.GroupVersionInfo parseDelimitedFrom(java.io.InputStream input) + throws java.io.IOException { + return PARSER.parseDelimitedFrom(input); + } + public static com.mogujie.tt.protobuf.IMBaseDefine.GroupVersionInfo parseDelimitedFrom( + java.io.InputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return PARSER.parseDelimitedFrom(input, extensionRegistry); + } + public static com.mogujie.tt.protobuf.IMBaseDefine.GroupVersionInfo parseFrom( + com.google.protobuf.CodedInputStream input) + throws java.io.IOException { + return PARSER.parseFrom(input); + } + public static com.mogujie.tt.protobuf.IMBaseDefine.GroupVersionInfo parseFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return PARSER.parseFrom(input, extensionRegistry); + } + + public static Builder newBuilder() { return Builder.create(); } + public Builder newBuilderForType() { return newBuilder(); } + public static Builder newBuilder(com.mogujie.tt.protobuf.IMBaseDefine.GroupVersionInfo prototype) { + return newBuilder().mergeFrom(prototype); + } + public Builder toBuilder() { return newBuilder(this); } + + /** + * Protobuf type {@code IM.BaseDefine.GroupVersionInfo} + */ + public static final class Builder extends + com.google.protobuf.GeneratedMessageLite.Builder< + com.mogujie.tt.protobuf.IMBaseDefine.GroupVersionInfo, Builder> + implements + // @@protoc_insertion_point(builder_implements:IM.BaseDefine.GroupVersionInfo) + com.mogujie.tt.protobuf.IMBaseDefine.GroupVersionInfoOrBuilder { + // Construct using com.mogujie.tt.protobuf.IMBaseDefine.GroupVersionInfo.newBuilder() + private Builder() { + maybeForceBuilderInitialization(); + } + + private void maybeForceBuilderInitialization() { + } + private static Builder create() { + return new Builder(); + } + + public Builder clear() { + super.clear(); + groupId_ = 0; + bitField0_ = (bitField0_ & ~0x00000001); + version_ = 0; + bitField0_ = (bitField0_ & ~0x00000002); + return this; + } + + public Builder clone() { + return create().mergeFrom(buildPartial()); + } + + public com.mogujie.tt.protobuf.IMBaseDefine.GroupVersionInfo getDefaultInstanceForType() { + return com.mogujie.tt.protobuf.IMBaseDefine.GroupVersionInfo.getDefaultInstance(); + } + + public com.mogujie.tt.protobuf.IMBaseDefine.GroupVersionInfo build() { + com.mogujie.tt.protobuf.IMBaseDefine.GroupVersionInfo result = buildPartial(); + if (!result.isInitialized()) { + throw newUninitializedMessageException(result); + } + return result; + } + + public com.mogujie.tt.protobuf.IMBaseDefine.GroupVersionInfo buildPartial() { + com.mogujie.tt.protobuf.IMBaseDefine.GroupVersionInfo result = new com.mogujie.tt.protobuf.IMBaseDefine.GroupVersionInfo(this); + int from_bitField0_ = bitField0_; + int to_bitField0_ = 0; + if (((from_bitField0_ & 0x00000001) == 0x00000001)) { + to_bitField0_ |= 0x00000001; + } + result.groupId_ = groupId_; + if (((from_bitField0_ & 0x00000002) == 0x00000002)) { + to_bitField0_ |= 0x00000002; + } + result.version_ = version_; + result.bitField0_ = to_bitField0_; + return result; + } + + public Builder mergeFrom(com.mogujie.tt.protobuf.IMBaseDefine.GroupVersionInfo other) { + if (other == com.mogujie.tt.protobuf.IMBaseDefine.GroupVersionInfo.getDefaultInstance()) return this; + if (other.hasGroupId()) { + setGroupId(other.getGroupId()); + } + if (other.hasVersion()) { + setVersion(other.getVersion()); + } + setUnknownFields( + getUnknownFields().concat(other.unknownFields)); + return this; + } + + public final boolean isInitialized() { + if (!hasGroupId()) { + + return false; + } + if (!hasVersion()) { + + return false; + } + return true; + } + + public Builder mergeFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + com.mogujie.tt.protobuf.IMBaseDefine.GroupVersionInfo parsedMessage = null; + try { + parsedMessage = PARSER.parsePartialFrom(input, extensionRegistry); + } catch (com.google.protobuf.InvalidProtocolBufferException e) { + parsedMessage = (com.mogujie.tt.protobuf.IMBaseDefine.GroupVersionInfo) e.getUnfinishedMessage(); + throw e; + } finally { + if (parsedMessage != null) { + mergeFrom(parsedMessage); + } + } + return this; + } + private int bitField0_; + + private int groupId_ ; + /** + * required uint32 group_id = 1; + */ + public boolean hasGroupId() { + return ((bitField0_ & 0x00000001) == 0x00000001); + } + /** + * required uint32 group_id = 1; + */ + public int getGroupId() { + return groupId_; + } + /** + * required uint32 group_id = 1; + */ + public Builder setGroupId(int value) { + bitField0_ |= 0x00000001; + groupId_ = value; + + return this; + } + /** + * required uint32 group_id = 1; + */ + public Builder clearGroupId() { + bitField0_ = (bitField0_ & ~0x00000001); + groupId_ = 0; + + return this; + } + + private int version_ ; + /** + * required uint32 version = 2; + */ + public boolean hasVersion() { + return ((bitField0_ & 0x00000002) == 0x00000002); + } + /** + * required uint32 version = 2; + */ + public int getVersion() { + return version_; + } + /** + * required uint32 version = 2; + */ + public Builder setVersion(int value) { + bitField0_ |= 0x00000002; + version_ = value; + + return this; + } + /** + * required uint32 version = 2; + */ + public Builder clearVersion() { + bitField0_ = (bitField0_ & ~0x00000002); + version_ = 0; + + return this; + } + + // @@protoc_insertion_point(builder_scope:IM.BaseDefine.GroupVersionInfo) + } + + static { + defaultInstance = new GroupVersionInfo(true); + defaultInstance.initFields(); + } + + // @@protoc_insertion_point(class_scope:IM.BaseDefine.GroupVersionInfo) + } + + public interface GroupInfoOrBuilder extends + // @@protoc_insertion_point(interface_extends:IM.BaseDefine.GroupInfo) + com.google.protobuf.MessageLiteOrBuilder { + + /** + * required uint32 group_id = 1; + */ + boolean hasGroupId(); + /** + * required uint32 group_id = 1; + */ + int getGroupId(); + + /** + * required uint32 version = 2; + */ + boolean hasVersion(); + /** + * required uint32 version = 2; + */ + int getVersion(); + + /** + * required string group_name = 3; + */ + boolean hasGroupName(); + /** + * required string group_name = 3; + */ + java.lang.String getGroupName(); + /** + * required string group_name = 3; + */ + com.google.protobuf.ByteString + getGroupNameBytes(); + + /** + * required string group_avatar = 4; + */ + boolean hasGroupAvatar(); + /** + * required string group_avatar = 4; + */ + java.lang.String getGroupAvatar(); + /** + * required string group_avatar = 4; + */ + com.google.protobuf.ByteString + getGroupAvatarBytes(); + + /** + * required uint32 group_creator_id = 5; + */ + boolean hasGroupCreatorId(); + /** + * required uint32 group_creator_id = 5; + */ + int getGroupCreatorId(); + + /** + * required .IM.BaseDefine.GroupType group_type = 6; + */ + boolean hasGroupType(); + /** + * required .IM.BaseDefine.GroupType group_type = 6; + */ + com.mogujie.tt.protobuf.IMBaseDefine.GroupType getGroupType(); + + /** + * required uint32 shield_status = 7; + * + *
+     *1: shield  0: not shield 
+     * 
+ */ + boolean hasShieldStatus(); + /** + * required uint32 shield_status = 7; + * + *
+     *1: shield  0: not shield 
+     * 
+ */ + int getShieldStatus(); + + /** + * repeated uint32 group_member_list = 8; + */ + java.util.List getGroupMemberListList(); + /** + * repeated uint32 group_member_list = 8; + */ + int getGroupMemberListCount(); + /** + * repeated uint32 group_member_list = 8; + */ + int getGroupMemberList(int index); + } + /** + * Protobuf type {@code IM.BaseDefine.GroupInfo} + */ + public static final class GroupInfo extends + com.google.protobuf.GeneratedMessageLite implements + // @@protoc_insertion_point(message_implements:IM.BaseDefine.GroupInfo) + GroupInfoOrBuilder { + // Use GroupInfo.newBuilder() to construct. + private GroupInfo(com.google.protobuf.GeneratedMessageLite.Builder builder) { + super(builder); + this.unknownFields = builder.getUnknownFields(); + } + private GroupInfo(boolean noInit) { this.unknownFields = com.google.protobuf.ByteString.EMPTY;} + + private static final GroupInfo defaultInstance; + public static GroupInfo getDefaultInstance() { + return defaultInstance; + } + + public GroupInfo getDefaultInstanceForType() { + return defaultInstance; + } + + private final com.google.protobuf.ByteString unknownFields; + private GroupInfo( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + initFields(); + int mutable_bitField0_ = 0; + com.google.protobuf.ByteString.Output unknownFieldsOutput = + com.google.protobuf.ByteString.newOutput(); + com.google.protobuf.CodedOutputStream unknownFieldsCodedOutput = + com.google.protobuf.CodedOutputStream.newInstance( + unknownFieldsOutput); + try { + boolean done = false; + while (!done) { + int tag = input.readTag(); + switch (tag) { + case 0: + done = true; + break; + default: { + if (!parseUnknownField(input, unknownFieldsCodedOutput, + extensionRegistry, tag)) { + done = true; + } + break; + } + case 8: { + bitField0_ |= 0x00000001; + groupId_ = input.readUInt32(); + break; + } + case 16: { + bitField0_ |= 0x00000002; + version_ = input.readUInt32(); + break; + } + case 26: { + com.google.protobuf.ByteString bs = input.readBytes(); + bitField0_ |= 0x00000004; + groupName_ = bs; + break; + } + case 34: { + com.google.protobuf.ByteString bs = input.readBytes(); + bitField0_ |= 0x00000008; + groupAvatar_ = bs; + break; + } + case 40: { + bitField0_ |= 0x00000010; + groupCreatorId_ = input.readUInt32(); + break; + } + case 48: { + int rawValue = input.readEnum(); + com.mogujie.tt.protobuf.IMBaseDefine.GroupType value = com.mogujie.tt.protobuf.IMBaseDefine.GroupType.valueOf(rawValue); + if (value == null) { + unknownFieldsCodedOutput.writeRawVarint32(tag); + unknownFieldsCodedOutput.writeRawVarint32(rawValue); + } else { + bitField0_ |= 0x00000020; + groupType_ = value; + } + break; + } + case 56: { + bitField0_ |= 0x00000040; + shieldStatus_ = input.readUInt32(); + break; + } + case 64: { + if (!((mutable_bitField0_ & 0x00000080) == 0x00000080)) { + groupMemberList_ = new java.util.ArrayList(); + mutable_bitField0_ |= 0x00000080; + } + groupMemberList_.add(input.readUInt32()); + break; + } + case 66: { + int length = input.readRawVarint32(); + int limit = input.pushLimit(length); + if (!((mutable_bitField0_ & 0x00000080) == 0x00000080) && input.getBytesUntilLimit() > 0) { + groupMemberList_ = new java.util.ArrayList(); + mutable_bitField0_ |= 0x00000080; + } + while (input.getBytesUntilLimit() > 0) { + groupMemberList_.add(input.readUInt32()); + } + input.popLimit(limit); + break; + } + } + } + } catch (com.google.protobuf.InvalidProtocolBufferException e) { + throw e.setUnfinishedMessage(this); + } catch (java.io.IOException e) { + throw new com.google.protobuf.InvalidProtocolBufferException( + e.getMessage()).setUnfinishedMessage(this); + } finally { + if (((mutable_bitField0_ & 0x00000080) == 0x00000080)) { + groupMemberList_ = java.util.Collections.unmodifiableList(groupMemberList_); + } + try { + unknownFieldsCodedOutput.flush(); + } catch (java.io.IOException e) { + // Should not happen + } finally { + unknownFields = unknownFieldsOutput.toByteString(); + } + makeExtensionsImmutable(); + } + } + public static com.google.protobuf.Parser PARSER = + new com.google.protobuf.AbstractParser() { + public GroupInfo parsePartialFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return new GroupInfo(input, extensionRegistry); + } + }; + + @java.lang.Override + public com.google.protobuf.Parser getParserForType() { + return PARSER; + } + + private int bitField0_; + public static final int GROUP_ID_FIELD_NUMBER = 1; + private int groupId_; + /** + * required uint32 group_id = 1; + */ + public boolean hasGroupId() { + return ((bitField0_ & 0x00000001) == 0x00000001); + } + /** + * required uint32 group_id = 1; + */ + public int getGroupId() { + return groupId_; + } + + public static final int VERSION_FIELD_NUMBER = 2; + private int version_; + /** + * required uint32 version = 2; + */ + public boolean hasVersion() { + return ((bitField0_ & 0x00000002) == 0x00000002); + } + /** + * required uint32 version = 2; + */ + public int getVersion() { + return version_; + } + + public static final int GROUP_NAME_FIELD_NUMBER = 3; + private java.lang.Object groupName_; + /** + * required string group_name = 3; + */ + public boolean hasGroupName() { + return ((bitField0_ & 0x00000004) == 0x00000004); + } + /** + * required string group_name = 3; + */ + public java.lang.String getGroupName() { + java.lang.Object ref = groupName_; + if (ref instanceof java.lang.String) { + return (java.lang.String) ref; + } else { + com.google.protobuf.ByteString bs = + (com.google.protobuf.ByteString) ref; + java.lang.String s = bs.toStringUtf8(); + if (bs.isValidUtf8()) { + groupName_ = s; + } + return s; + } + } + /** + * required string group_name = 3; + */ + public com.google.protobuf.ByteString + getGroupNameBytes() { + java.lang.Object ref = groupName_; + if (ref instanceof java.lang.String) { + com.google.protobuf.ByteString b = + com.google.protobuf.ByteString.copyFromUtf8( + (java.lang.String) ref); + groupName_ = b; + return b; + } else { + return (com.google.protobuf.ByteString) ref; + } + } + + public static final int GROUP_AVATAR_FIELD_NUMBER = 4; + private java.lang.Object groupAvatar_; + /** + * required string group_avatar = 4; + */ + public boolean hasGroupAvatar() { + return ((bitField0_ & 0x00000008) == 0x00000008); + } + /** + * required string group_avatar = 4; + */ + public java.lang.String getGroupAvatar() { + java.lang.Object ref = groupAvatar_; + if (ref instanceof java.lang.String) { + return (java.lang.String) ref; + } else { + com.google.protobuf.ByteString bs = + (com.google.protobuf.ByteString) ref; + java.lang.String s = bs.toStringUtf8(); + if (bs.isValidUtf8()) { + groupAvatar_ = s; + } + return s; + } + } + /** + * required string group_avatar = 4; + */ + public com.google.protobuf.ByteString + getGroupAvatarBytes() { + java.lang.Object ref = groupAvatar_; + if (ref instanceof java.lang.String) { + com.google.protobuf.ByteString b = + com.google.protobuf.ByteString.copyFromUtf8( + (java.lang.String) ref); + groupAvatar_ = b; + return b; + } else { + return (com.google.protobuf.ByteString) ref; + } + } + + public static final int GROUP_CREATOR_ID_FIELD_NUMBER = 5; + private int groupCreatorId_; + /** + * required uint32 group_creator_id = 5; + */ + public boolean hasGroupCreatorId() { + return ((bitField0_ & 0x00000010) == 0x00000010); + } + /** + * required uint32 group_creator_id = 5; + */ + public int getGroupCreatorId() { + return groupCreatorId_; + } + + public static final int GROUP_TYPE_FIELD_NUMBER = 6; + private com.mogujie.tt.protobuf.IMBaseDefine.GroupType groupType_; + /** + * required .IM.BaseDefine.GroupType group_type = 6; + */ + public boolean hasGroupType() { + return ((bitField0_ & 0x00000020) == 0x00000020); + } + /** + * required .IM.BaseDefine.GroupType group_type = 6; + */ + public com.mogujie.tt.protobuf.IMBaseDefine.GroupType getGroupType() { + return groupType_; + } + + public static final int SHIELD_STATUS_FIELD_NUMBER = 7; + private int shieldStatus_; + /** + * required uint32 shield_status = 7; + * + *
+     *1: shield  0: not shield 
+     * 
+ */ + public boolean hasShieldStatus() { + return ((bitField0_ & 0x00000040) == 0x00000040); + } + /** + * required uint32 shield_status = 7; + * + *
+     *1: shield  0: not shield 
+     * 
+ */ + public int getShieldStatus() { + return shieldStatus_; + } + + public static final int GROUP_MEMBER_LIST_FIELD_NUMBER = 8; + private java.util.List groupMemberList_; + /** + * repeated uint32 group_member_list = 8; + */ + public java.util.List + getGroupMemberListList() { + return groupMemberList_; + } + /** + * repeated uint32 group_member_list = 8; + */ + public int getGroupMemberListCount() { + return groupMemberList_.size(); + } + /** + * repeated uint32 group_member_list = 8; + */ + public int getGroupMemberList(int index) { + return groupMemberList_.get(index); + } + + private void initFields() { + groupId_ = 0; + version_ = 0; + groupName_ = ""; + groupAvatar_ = ""; + groupCreatorId_ = 0; + groupType_ = com.mogujie.tt.protobuf.IMBaseDefine.GroupType.GROUP_TYPE_NORMAL; + shieldStatus_ = 0; + groupMemberList_ = java.util.Collections.emptyList(); + } + private byte memoizedIsInitialized = -1; + public final boolean isInitialized() { + byte isInitialized = memoizedIsInitialized; + if (isInitialized == 1) return true; + if (isInitialized == 0) return false; + + if (!hasGroupId()) { + memoizedIsInitialized = 0; + return false; + } + if (!hasVersion()) { + memoizedIsInitialized = 0; + return false; + } + if (!hasGroupName()) { + memoizedIsInitialized = 0; + return false; + } + if (!hasGroupAvatar()) { + memoizedIsInitialized = 0; + return false; + } + if (!hasGroupCreatorId()) { + memoizedIsInitialized = 0; + return false; + } + if (!hasGroupType()) { + memoizedIsInitialized = 0; + return false; + } + if (!hasShieldStatus()) { + memoizedIsInitialized = 0; + return false; + } + memoizedIsInitialized = 1; + return true; + } + + public void writeTo(com.google.protobuf.CodedOutputStream output) + throws java.io.IOException { + getSerializedSize(); + if (((bitField0_ & 0x00000001) == 0x00000001)) { + output.writeUInt32(1, groupId_); + } + if (((bitField0_ & 0x00000002) == 0x00000002)) { + output.writeUInt32(2, version_); + } + if (((bitField0_ & 0x00000004) == 0x00000004)) { + output.writeBytes(3, getGroupNameBytes()); + } + if (((bitField0_ & 0x00000008) == 0x00000008)) { + output.writeBytes(4, getGroupAvatarBytes()); + } + if (((bitField0_ & 0x00000010) == 0x00000010)) { + output.writeUInt32(5, groupCreatorId_); + } + if (((bitField0_ & 0x00000020) == 0x00000020)) { + output.writeEnum(6, groupType_.getNumber()); + } + if (((bitField0_ & 0x00000040) == 0x00000040)) { + output.writeUInt32(7, shieldStatus_); + } + for (int i = 0; i < groupMemberList_.size(); i++) { + output.writeUInt32(8, groupMemberList_.get(i)); + } + output.writeRawBytes(unknownFields); + } + + private int memoizedSerializedSize = -1; + public int getSerializedSize() { + int size = memoizedSerializedSize; + if (size != -1) return size; + + size = 0; + if (((bitField0_ & 0x00000001) == 0x00000001)) { + size += com.google.protobuf.CodedOutputStream + .computeUInt32Size(1, groupId_); + } + if (((bitField0_ & 0x00000002) == 0x00000002)) { + size += com.google.protobuf.CodedOutputStream + .computeUInt32Size(2, version_); + } + if (((bitField0_ & 0x00000004) == 0x00000004)) { + size += com.google.protobuf.CodedOutputStream + .computeBytesSize(3, getGroupNameBytes()); + } + if (((bitField0_ & 0x00000008) == 0x00000008)) { + size += com.google.protobuf.CodedOutputStream + .computeBytesSize(4, getGroupAvatarBytes()); + } + if (((bitField0_ & 0x00000010) == 0x00000010)) { + size += com.google.protobuf.CodedOutputStream + .computeUInt32Size(5, groupCreatorId_); + } + if (((bitField0_ & 0x00000020) == 0x00000020)) { + size += com.google.protobuf.CodedOutputStream + .computeEnumSize(6, groupType_.getNumber()); + } + if (((bitField0_ & 0x00000040) == 0x00000040)) { + size += com.google.protobuf.CodedOutputStream + .computeUInt32Size(7, shieldStatus_); + } + { + int dataSize = 0; + for (int i = 0; i < groupMemberList_.size(); i++) { + dataSize += com.google.protobuf.CodedOutputStream + .computeUInt32SizeNoTag(groupMemberList_.get(i)); + } + size += dataSize; + size += 1 * getGroupMemberListList().size(); + } + size += unknownFields.size(); + memoizedSerializedSize = size; + return size; + } + + private static final long serialVersionUID = 0L; + @java.lang.Override + protected java.lang.Object writeReplace() + throws java.io.ObjectStreamException { + return super.writeReplace(); + } + + public static com.mogujie.tt.protobuf.IMBaseDefine.GroupInfo parseFrom( + com.google.protobuf.ByteString data) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data); + } + public static com.mogujie.tt.protobuf.IMBaseDefine.GroupInfo parseFrom( + com.google.protobuf.ByteString data, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data, extensionRegistry); + } + public static com.mogujie.tt.protobuf.IMBaseDefine.GroupInfo parseFrom(byte[] data) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data); + } + public static com.mogujie.tt.protobuf.IMBaseDefine.GroupInfo parseFrom( + byte[] data, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data, extensionRegistry); + } + public static com.mogujie.tt.protobuf.IMBaseDefine.GroupInfo parseFrom(java.io.InputStream input) + throws java.io.IOException { + return PARSER.parseFrom(input); + } + public static com.mogujie.tt.protobuf.IMBaseDefine.GroupInfo parseFrom( + java.io.InputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return PARSER.parseFrom(input, extensionRegistry); + } + public static com.mogujie.tt.protobuf.IMBaseDefine.GroupInfo parseDelimitedFrom(java.io.InputStream input) + throws java.io.IOException { + return PARSER.parseDelimitedFrom(input); + } + public static com.mogujie.tt.protobuf.IMBaseDefine.GroupInfo parseDelimitedFrom( + java.io.InputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return PARSER.parseDelimitedFrom(input, extensionRegistry); + } + public static com.mogujie.tt.protobuf.IMBaseDefine.GroupInfo parseFrom( + com.google.protobuf.CodedInputStream input) + throws java.io.IOException { + return PARSER.parseFrom(input); + } + public static com.mogujie.tt.protobuf.IMBaseDefine.GroupInfo parseFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return PARSER.parseFrom(input, extensionRegistry); + } + + public static Builder newBuilder() { return Builder.create(); } + public Builder newBuilderForType() { return newBuilder(); } + public static Builder newBuilder(com.mogujie.tt.protobuf.IMBaseDefine.GroupInfo prototype) { + return newBuilder().mergeFrom(prototype); + } + public Builder toBuilder() { return newBuilder(this); } + + /** + * Protobuf type {@code IM.BaseDefine.GroupInfo} + */ + public static final class Builder extends + com.google.protobuf.GeneratedMessageLite.Builder< + com.mogujie.tt.protobuf.IMBaseDefine.GroupInfo, Builder> + implements + // @@protoc_insertion_point(builder_implements:IM.BaseDefine.GroupInfo) + com.mogujie.tt.protobuf.IMBaseDefine.GroupInfoOrBuilder { + // Construct using com.mogujie.tt.protobuf.IMBaseDefine.GroupInfo.newBuilder() + private Builder() { + maybeForceBuilderInitialization(); + } + + private void maybeForceBuilderInitialization() { + } + private static Builder create() { + return new Builder(); + } + + public Builder clear() { + super.clear(); + groupId_ = 0; + bitField0_ = (bitField0_ & ~0x00000001); + version_ = 0; + bitField0_ = (bitField0_ & ~0x00000002); + groupName_ = ""; + bitField0_ = (bitField0_ & ~0x00000004); + groupAvatar_ = ""; + bitField0_ = (bitField0_ & ~0x00000008); + groupCreatorId_ = 0; + bitField0_ = (bitField0_ & ~0x00000010); + groupType_ = com.mogujie.tt.protobuf.IMBaseDefine.GroupType.GROUP_TYPE_NORMAL; + bitField0_ = (bitField0_ & ~0x00000020); + shieldStatus_ = 0; + bitField0_ = (bitField0_ & ~0x00000040); + groupMemberList_ = java.util.Collections.emptyList(); + bitField0_ = (bitField0_ & ~0x00000080); + return this; + } + + public Builder clone() { + return create().mergeFrom(buildPartial()); + } + + public com.mogujie.tt.protobuf.IMBaseDefine.GroupInfo getDefaultInstanceForType() { + return com.mogujie.tt.protobuf.IMBaseDefine.GroupInfo.getDefaultInstance(); + } + + public com.mogujie.tt.protobuf.IMBaseDefine.GroupInfo build() { + com.mogujie.tt.protobuf.IMBaseDefine.GroupInfo result = buildPartial(); + if (!result.isInitialized()) { + throw newUninitializedMessageException(result); + } + return result; + } + + public com.mogujie.tt.protobuf.IMBaseDefine.GroupInfo buildPartial() { + com.mogujie.tt.protobuf.IMBaseDefine.GroupInfo result = new com.mogujie.tt.protobuf.IMBaseDefine.GroupInfo(this); + int from_bitField0_ = bitField0_; + int to_bitField0_ = 0; + if (((from_bitField0_ & 0x00000001) == 0x00000001)) { + to_bitField0_ |= 0x00000001; + } + result.groupId_ = groupId_; + if (((from_bitField0_ & 0x00000002) == 0x00000002)) { + to_bitField0_ |= 0x00000002; + } + result.version_ = version_; + if (((from_bitField0_ & 0x00000004) == 0x00000004)) { + to_bitField0_ |= 0x00000004; + } + result.groupName_ = groupName_; + if (((from_bitField0_ & 0x00000008) == 0x00000008)) { + to_bitField0_ |= 0x00000008; + } + result.groupAvatar_ = groupAvatar_; + if (((from_bitField0_ & 0x00000010) == 0x00000010)) { + to_bitField0_ |= 0x00000010; + } + result.groupCreatorId_ = groupCreatorId_; + if (((from_bitField0_ & 0x00000020) == 0x00000020)) { + to_bitField0_ |= 0x00000020; + } + result.groupType_ = groupType_; + if (((from_bitField0_ & 0x00000040) == 0x00000040)) { + to_bitField0_ |= 0x00000040; + } + result.shieldStatus_ = shieldStatus_; + if (((bitField0_ & 0x00000080) == 0x00000080)) { + groupMemberList_ = java.util.Collections.unmodifiableList(groupMemberList_); + bitField0_ = (bitField0_ & ~0x00000080); + } + result.groupMemberList_ = groupMemberList_; + result.bitField0_ = to_bitField0_; + return result; + } + + public Builder mergeFrom(com.mogujie.tt.protobuf.IMBaseDefine.GroupInfo other) { + if (other == com.mogujie.tt.protobuf.IMBaseDefine.GroupInfo.getDefaultInstance()) return this; + if (other.hasGroupId()) { + setGroupId(other.getGroupId()); + } + if (other.hasVersion()) { + setVersion(other.getVersion()); + } + if (other.hasGroupName()) { + bitField0_ |= 0x00000004; + groupName_ = other.groupName_; + + } + if (other.hasGroupAvatar()) { + bitField0_ |= 0x00000008; + groupAvatar_ = other.groupAvatar_; + + } + if (other.hasGroupCreatorId()) { + setGroupCreatorId(other.getGroupCreatorId()); + } + if (other.hasGroupType()) { + setGroupType(other.getGroupType()); + } + if (other.hasShieldStatus()) { + setShieldStatus(other.getShieldStatus()); + } + if (!other.groupMemberList_.isEmpty()) { + if (groupMemberList_.isEmpty()) { + groupMemberList_ = other.groupMemberList_; + bitField0_ = (bitField0_ & ~0x00000080); + } else { + ensureGroupMemberListIsMutable(); + groupMemberList_.addAll(other.groupMemberList_); + } + + } + setUnknownFields( + getUnknownFields().concat(other.unknownFields)); + return this; + } + + public final boolean isInitialized() { + if (!hasGroupId()) { + + return false; + } + if (!hasVersion()) { + + return false; + } + if (!hasGroupName()) { + + return false; + } + if (!hasGroupAvatar()) { + + return false; + } + if (!hasGroupCreatorId()) { + + return false; + } + if (!hasGroupType()) { + + return false; + } + if (!hasShieldStatus()) { + + return false; + } + return true; + } + + public Builder mergeFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + com.mogujie.tt.protobuf.IMBaseDefine.GroupInfo parsedMessage = null; + try { + parsedMessage = PARSER.parsePartialFrom(input, extensionRegistry); + } catch (com.google.protobuf.InvalidProtocolBufferException e) { + parsedMessage = (com.mogujie.tt.protobuf.IMBaseDefine.GroupInfo) e.getUnfinishedMessage(); + throw e; + } finally { + if (parsedMessage != null) { + mergeFrom(parsedMessage); + } + } + return this; + } + private int bitField0_; + + private int groupId_ ; + /** + * required uint32 group_id = 1; + */ + public boolean hasGroupId() { + return ((bitField0_ & 0x00000001) == 0x00000001); + } + /** + * required uint32 group_id = 1; + */ + public int getGroupId() { + return groupId_; + } + /** + * required uint32 group_id = 1; + */ + public Builder setGroupId(int value) { + bitField0_ |= 0x00000001; + groupId_ = value; + + return this; + } + /** + * required uint32 group_id = 1; + */ + public Builder clearGroupId() { + bitField0_ = (bitField0_ & ~0x00000001); + groupId_ = 0; + + return this; + } + + private int version_ ; + /** + * required uint32 version = 2; + */ + public boolean hasVersion() { + return ((bitField0_ & 0x00000002) == 0x00000002); + } + /** + * required uint32 version = 2; + */ + public int getVersion() { + return version_; + } + /** + * required uint32 version = 2; + */ + public Builder setVersion(int value) { + bitField0_ |= 0x00000002; + version_ = value; + + return this; + } + /** + * required uint32 version = 2; + */ + public Builder clearVersion() { + bitField0_ = (bitField0_ & ~0x00000002); + version_ = 0; + + return this; + } + + private java.lang.Object groupName_ = ""; + /** + * required string group_name = 3; + */ + public boolean hasGroupName() { + return ((bitField0_ & 0x00000004) == 0x00000004); + } + /** + * required string group_name = 3; + */ + public java.lang.String getGroupName() { + java.lang.Object ref = groupName_; + if (!(ref instanceof java.lang.String)) { + com.google.protobuf.ByteString bs = + (com.google.protobuf.ByteString) ref; + java.lang.String s = bs.toStringUtf8(); + if (bs.isValidUtf8()) { + groupName_ = s; + } + return s; + } else { + return (java.lang.String) ref; + } + } + /** + * required string group_name = 3; + */ + public com.google.protobuf.ByteString + getGroupNameBytes() { + java.lang.Object ref = groupName_; + if (ref instanceof String) { + com.google.protobuf.ByteString b = + com.google.protobuf.ByteString.copyFromUtf8( + (java.lang.String) ref); + groupName_ = b; + return b; + } else { + return (com.google.protobuf.ByteString) ref; + } + } + /** + * required string group_name = 3; + */ + public Builder setGroupName( + java.lang.String value) { + if (value == null) { + throw new NullPointerException(); + } + bitField0_ |= 0x00000004; + groupName_ = value; + + return this; + } + /** + * required string group_name = 3; + */ + public Builder clearGroupName() { + bitField0_ = (bitField0_ & ~0x00000004); + groupName_ = getDefaultInstance().getGroupName(); + + return this; + } + /** + * required string group_name = 3; + */ + public Builder setGroupNameBytes( + com.google.protobuf.ByteString value) { + if (value == null) { + throw new NullPointerException(); + } + bitField0_ |= 0x00000004; + groupName_ = value; + + return this; + } + + private java.lang.Object groupAvatar_ = ""; + /** + * required string group_avatar = 4; + */ + public boolean hasGroupAvatar() { + return ((bitField0_ & 0x00000008) == 0x00000008); + } + /** + * required string group_avatar = 4; + */ + public java.lang.String getGroupAvatar() { + java.lang.Object ref = groupAvatar_; + if (!(ref instanceof java.lang.String)) { + com.google.protobuf.ByteString bs = + (com.google.protobuf.ByteString) ref; + java.lang.String s = bs.toStringUtf8(); + if (bs.isValidUtf8()) { + groupAvatar_ = s; + } + return s; + } else { + return (java.lang.String) ref; + } + } + /** + * required string group_avatar = 4; + */ + public com.google.protobuf.ByteString + getGroupAvatarBytes() { + java.lang.Object ref = groupAvatar_; + if (ref instanceof String) { + com.google.protobuf.ByteString b = + com.google.protobuf.ByteString.copyFromUtf8( + (java.lang.String) ref); + groupAvatar_ = b; + return b; + } else { + return (com.google.protobuf.ByteString) ref; + } + } + /** + * required string group_avatar = 4; + */ + public Builder setGroupAvatar( + java.lang.String value) { + if (value == null) { + throw new NullPointerException(); + } + bitField0_ |= 0x00000008; + groupAvatar_ = value; + + return this; + } + /** + * required string group_avatar = 4; + */ + public Builder clearGroupAvatar() { + bitField0_ = (bitField0_ & ~0x00000008); + groupAvatar_ = getDefaultInstance().getGroupAvatar(); + + return this; + } + /** + * required string group_avatar = 4; + */ + public Builder setGroupAvatarBytes( + com.google.protobuf.ByteString value) { + if (value == null) { + throw new NullPointerException(); + } + bitField0_ |= 0x00000008; + groupAvatar_ = value; + + return this; + } + + private int groupCreatorId_ ; + /** + * required uint32 group_creator_id = 5; + */ + public boolean hasGroupCreatorId() { + return ((bitField0_ & 0x00000010) == 0x00000010); + } + /** + * required uint32 group_creator_id = 5; + */ + public int getGroupCreatorId() { + return groupCreatorId_; + } + /** + * required uint32 group_creator_id = 5; + */ + public Builder setGroupCreatorId(int value) { + bitField0_ |= 0x00000010; + groupCreatorId_ = value; + + return this; + } + /** + * required uint32 group_creator_id = 5; + */ + public Builder clearGroupCreatorId() { + bitField0_ = (bitField0_ & ~0x00000010); + groupCreatorId_ = 0; + + return this; + } + + private com.mogujie.tt.protobuf.IMBaseDefine.GroupType groupType_ = com.mogujie.tt.protobuf.IMBaseDefine.GroupType.GROUP_TYPE_NORMAL; + /** + * required .IM.BaseDefine.GroupType group_type = 6; + */ + public boolean hasGroupType() { + return ((bitField0_ & 0x00000020) == 0x00000020); + } + /** + * required .IM.BaseDefine.GroupType group_type = 6; + */ + public com.mogujie.tt.protobuf.IMBaseDefine.GroupType getGroupType() { + return groupType_; + } + /** + * required .IM.BaseDefine.GroupType group_type = 6; + */ + public Builder setGroupType(com.mogujie.tt.protobuf.IMBaseDefine.GroupType value) { + if (value == null) { + throw new NullPointerException(); + } + bitField0_ |= 0x00000020; + groupType_ = value; + + return this; + } + /** + * required .IM.BaseDefine.GroupType group_type = 6; + */ + public Builder clearGroupType() { + bitField0_ = (bitField0_ & ~0x00000020); + groupType_ = com.mogujie.tt.protobuf.IMBaseDefine.GroupType.GROUP_TYPE_NORMAL; + + return this; + } + + private int shieldStatus_ ; + /** + * required uint32 shield_status = 7; + * + *
+       *1: shield  0: not shield 
+       * 
+ */ + public boolean hasShieldStatus() { + return ((bitField0_ & 0x00000040) == 0x00000040); + } + /** + * required uint32 shield_status = 7; + * + *
+       *1: shield  0: not shield 
+       * 
+ */ + public int getShieldStatus() { + return shieldStatus_; + } + /** + * required uint32 shield_status = 7; + * + *
+       *1: shield  0: not shield 
+       * 
+ */ + public Builder setShieldStatus(int value) { + bitField0_ |= 0x00000040; + shieldStatus_ = value; + + return this; + } + /** + * required uint32 shield_status = 7; + * + *
+       *1: shield  0: not shield 
+       * 
+ */ + public Builder clearShieldStatus() { + bitField0_ = (bitField0_ & ~0x00000040); + shieldStatus_ = 0; + + return this; + } + + private java.util.List groupMemberList_ = java.util.Collections.emptyList(); + private void ensureGroupMemberListIsMutable() { + if (!((bitField0_ & 0x00000080) == 0x00000080)) { + groupMemberList_ = new java.util.ArrayList(groupMemberList_); + bitField0_ |= 0x00000080; + } + } + /** + * repeated uint32 group_member_list = 8; + */ + public java.util.List + getGroupMemberListList() { + return java.util.Collections.unmodifiableList(groupMemberList_); + } + /** + * repeated uint32 group_member_list = 8; + */ + public int getGroupMemberListCount() { + return groupMemberList_.size(); + } + /** + * repeated uint32 group_member_list = 8; + */ + public int getGroupMemberList(int index) { + return groupMemberList_.get(index); + } + /** + * repeated uint32 group_member_list = 8; + */ + public Builder setGroupMemberList( + int index, int value) { + ensureGroupMemberListIsMutable(); + groupMemberList_.set(index, value); + + return this; + } + /** + * repeated uint32 group_member_list = 8; + */ + public Builder addGroupMemberList(int value) { + ensureGroupMemberListIsMutable(); + groupMemberList_.add(value); + + return this; + } + /** + * repeated uint32 group_member_list = 8; + */ + public Builder addAllGroupMemberList( + java.lang.Iterable values) { + ensureGroupMemberListIsMutable(); + com.google.protobuf.AbstractMessageLite.Builder.addAll( + values, groupMemberList_); + + return this; + } + /** + * repeated uint32 group_member_list = 8; + */ + public Builder clearGroupMemberList() { + groupMemberList_ = java.util.Collections.emptyList(); + bitField0_ = (bitField0_ & ~0x00000080); + + return this; + } + + // @@protoc_insertion_point(builder_scope:IM.BaseDefine.GroupInfo) + } + + static { + defaultInstance = new GroupInfo(true); + defaultInstance.initFields(); + } + + // @@protoc_insertion_point(class_scope:IM.BaseDefine.GroupInfo) + } + + public interface UserTokenInfoOrBuilder extends + // @@protoc_insertion_point(interface_extends:IM.BaseDefine.UserTokenInfo) + com.google.protobuf.MessageLiteOrBuilder { + + /** + * required uint32 user_id = 1; + */ + boolean hasUserId(); + /** + * required uint32 user_id = 1; + */ + int getUserId(); + + /** + * required .IM.BaseDefine.ClientType user_type = 2; + */ + boolean hasUserType(); + /** + * required .IM.BaseDefine.ClientType user_type = 2; + */ + com.mogujie.tt.protobuf.IMBaseDefine.ClientType getUserType(); + + /** + * required string token = 3; + */ + boolean hasToken(); + /** + * required string token = 3; + */ + java.lang.String getToken(); + /** + * required string token = 3; + */ + com.google.protobuf.ByteString + getTokenBytes(); + + /** + * required uint32 push_count = 4; + */ + boolean hasPushCount(); + /** + * required uint32 push_count = 4; + */ + int getPushCount(); + + /** + * required uint32 push_type = 5; + * + *
+     *1: 正常推送  	2:无打扰式推送
+     * 
+ */ + boolean hasPushType(); + /** + * required uint32 push_type = 5; + * + *
+     *1: 正常推送  	2:无打扰式推送
+     * 
+ */ + int getPushType(); + } + /** + * Protobuf type {@code IM.BaseDefine.UserTokenInfo} + */ + public static final class UserTokenInfo extends + com.google.protobuf.GeneratedMessageLite implements + // @@protoc_insertion_point(message_implements:IM.BaseDefine.UserTokenInfo) + UserTokenInfoOrBuilder { + // Use UserTokenInfo.newBuilder() to construct. + private UserTokenInfo(com.google.protobuf.GeneratedMessageLite.Builder builder) { + super(builder); + this.unknownFields = builder.getUnknownFields(); + } + private UserTokenInfo(boolean noInit) { this.unknownFields = com.google.protobuf.ByteString.EMPTY;} + + private static final UserTokenInfo defaultInstance; + public static UserTokenInfo getDefaultInstance() { + return defaultInstance; + } + + public UserTokenInfo getDefaultInstanceForType() { + return defaultInstance; + } + + private final com.google.protobuf.ByteString unknownFields; + private UserTokenInfo( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + initFields(); + int mutable_bitField0_ = 0; + com.google.protobuf.ByteString.Output unknownFieldsOutput = + com.google.protobuf.ByteString.newOutput(); + com.google.protobuf.CodedOutputStream unknownFieldsCodedOutput = + com.google.protobuf.CodedOutputStream.newInstance( + unknownFieldsOutput); + try { + boolean done = false; + while (!done) { + int tag = input.readTag(); + switch (tag) { + case 0: + done = true; + break; + default: { + if (!parseUnknownField(input, unknownFieldsCodedOutput, + extensionRegistry, tag)) { + done = true; + } + break; + } + case 8: { + bitField0_ |= 0x00000001; + userId_ = input.readUInt32(); + break; + } + case 16: { + int rawValue = input.readEnum(); + com.mogujie.tt.protobuf.IMBaseDefine.ClientType value = com.mogujie.tt.protobuf.IMBaseDefine.ClientType.valueOf(rawValue); + if (value == null) { + unknownFieldsCodedOutput.writeRawVarint32(tag); + unknownFieldsCodedOutput.writeRawVarint32(rawValue); + } else { + bitField0_ |= 0x00000002; + userType_ = value; + } + break; + } + case 26: { + com.google.protobuf.ByteString bs = input.readBytes(); + bitField0_ |= 0x00000004; + token_ = bs; + break; + } + case 32: { + bitField0_ |= 0x00000008; + pushCount_ = input.readUInt32(); + break; + } + case 40: { + bitField0_ |= 0x00000010; + pushType_ = input.readUInt32(); + break; + } + } + } + } catch (com.google.protobuf.InvalidProtocolBufferException e) { + throw e.setUnfinishedMessage(this); + } catch (java.io.IOException e) { + throw new com.google.protobuf.InvalidProtocolBufferException( + e.getMessage()).setUnfinishedMessage(this); + } finally { + try { + unknownFieldsCodedOutput.flush(); + } catch (java.io.IOException e) { + // Should not happen + } finally { + unknownFields = unknownFieldsOutput.toByteString(); + } + makeExtensionsImmutable(); + } + } + public static com.google.protobuf.Parser PARSER = + new com.google.protobuf.AbstractParser() { + public UserTokenInfo parsePartialFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return new UserTokenInfo(input, extensionRegistry); + } + }; + + @java.lang.Override + public com.google.protobuf.Parser getParserForType() { + return PARSER; + } + + private int bitField0_; + public static final int USER_ID_FIELD_NUMBER = 1; + private int userId_; + /** + * required uint32 user_id = 1; + */ + public boolean hasUserId() { + return ((bitField0_ & 0x00000001) == 0x00000001); + } + /** + * required uint32 user_id = 1; + */ + public int getUserId() { + return userId_; + } + + public static final int USER_TYPE_FIELD_NUMBER = 2; + private com.mogujie.tt.protobuf.IMBaseDefine.ClientType userType_; + /** + * required .IM.BaseDefine.ClientType user_type = 2; + */ + public boolean hasUserType() { + return ((bitField0_ & 0x00000002) == 0x00000002); + } + /** + * required .IM.BaseDefine.ClientType user_type = 2; + */ + public com.mogujie.tt.protobuf.IMBaseDefine.ClientType getUserType() { + return userType_; + } + + public static final int TOKEN_FIELD_NUMBER = 3; + private java.lang.Object token_; + /** + * required string token = 3; + */ + public boolean hasToken() { + return ((bitField0_ & 0x00000004) == 0x00000004); + } + /** + * required string token = 3; + */ + public java.lang.String getToken() { + java.lang.Object ref = token_; + if (ref instanceof java.lang.String) { + return (java.lang.String) ref; + } else { + com.google.protobuf.ByteString bs = + (com.google.protobuf.ByteString) ref; + java.lang.String s = bs.toStringUtf8(); + if (bs.isValidUtf8()) { + token_ = s; + } + return s; + } + } + /** + * required string token = 3; + */ + public com.google.protobuf.ByteString + getTokenBytes() { + java.lang.Object ref = token_; + if (ref instanceof java.lang.String) { + com.google.protobuf.ByteString b = + com.google.protobuf.ByteString.copyFromUtf8( + (java.lang.String) ref); + token_ = b; + return b; + } else { + return (com.google.protobuf.ByteString) ref; + } + } + + public static final int PUSH_COUNT_FIELD_NUMBER = 4; + private int pushCount_; + /** + * required uint32 push_count = 4; + */ + public boolean hasPushCount() { + return ((bitField0_ & 0x00000008) == 0x00000008); + } + /** + * required uint32 push_count = 4; + */ + public int getPushCount() { + return pushCount_; + } + + public static final int PUSH_TYPE_FIELD_NUMBER = 5; + private int pushType_; + /** + * required uint32 push_type = 5; + * + *
+     *1: 正常推送  	2:无打扰式推送
+     * 
+ */ + public boolean hasPushType() { + return ((bitField0_ & 0x00000010) == 0x00000010); + } + /** + * required uint32 push_type = 5; + * + *
+     *1: 正常推送  	2:无打扰式推送
+     * 
+ */ + public int getPushType() { + return pushType_; + } + + private void initFields() { + userId_ = 0; + userType_ = com.mogujie.tt.protobuf.IMBaseDefine.ClientType.CLIENT_TYPE_WINDOWS; + token_ = ""; + pushCount_ = 0; + pushType_ = 0; + } + private byte memoizedIsInitialized = -1; + public final boolean isInitialized() { + byte isInitialized = memoizedIsInitialized; + if (isInitialized == 1) return true; + if (isInitialized == 0) return false; + + if (!hasUserId()) { + memoizedIsInitialized = 0; + return false; + } + if (!hasUserType()) { + memoizedIsInitialized = 0; + return false; + } + if (!hasToken()) { + memoizedIsInitialized = 0; + return false; + } + if (!hasPushCount()) { + memoizedIsInitialized = 0; + return false; + } + if (!hasPushType()) { + memoizedIsInitialized = 0; + return false; + } + memoizedIsInitialized = 1; + return true; + } + + public void writeTo(com.google.protobuf.CodedOutputStream output) + throws java.io.IOException { + getSerializedSize(); + if (((bitField0_ & 0x00000001) == 0x00000001)) { + output.writeUInt32(1, userId_); + } + if (((bitField0_ & 0x00000002) == 0x00000002)) { + output.writeEnum(2, userType_.getNumber()); + } + if (((bitField0_ & 0x00000004) == 0x00000004)) { + output.writeBytes(3, getTokenBytes()); + } + if (((bitField0_ & 0x00000008) == 0x00000008)) { + output.writeUInt32(4, pushCount_); + } + if (((bitField0_ & 0x00000010) == 0x00000010)) { + output.writeUInt32(5, pushType_); + } + output.writeRawBytes(unknownFields); + } + + private int memoizedSerializedSize = -1; + public int getSerializedSize() { + int size = memoizedSerializedSize; + if (size != -1) return size; + + size = 0; + if (((bitField0_ & 0x00000001) == 0x00000001)) { + size += com.google.protobuf.CodedOutputStream + .computeUInt32Size(1, userId_); + } + if (((bitField0_ & 0x00000002) == 0x00000002)) { + size += com.google.protobuf.CodedOutputStream + .computeEnumSize(2, userType_.getNumber()); + } + if (((bitField0_ & 0x00000004) == 0x00000004)) { + size += com.google.protobuf.CodedOutputStream + .computeBytesSize(3, getTokenBytes()); + } + if (((bitField0_ & 0x00000008) == 0x00000008)) { + size += com.google.protobuf.CodedOutputStream + .computeUInt32Size(4, pushCount_); + } + if (((bitField0_ & 0x00000010) == 0x00000010)) { + size += com.google.protobuf.CodedOutputStream + .computeUInt32Size(5, pushType_); + } + size += unknownFields.size(); + memoizedSerializedSize = size; + return size; + } + + private static final long serialVersionUID = 0L; + @java.lang.Override + protected java.lang.Object writeReplace() + throws java.io.ObjectStreamException { + return super.writeReplace(); + } + + public static com.mogujie.tt.protobuf.IMBaseDefine.UserTokenInfo parseFrom( + com.google.protobuf.ByteString data) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data); + } + public static com.mogujie.tt.protobuf.IMBaseDefine.UserTokenInfo parseFrom( + com.google.protobuf.ByteString data, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data, extensionRegistry); + } + public static com.mogujie.tt.protobuf.IMBaseDefine.UserTokenInfo parseFrom(byte[] data) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data); + } + public static com.mogujie.tt.protobuf.IMBaseDefine.UserTokenInfo parseFrom( + byte[] data, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data, extensionRegistry); + } + public static com.mogujie.tt.protobuf.IMBaseDefine.UserTokenInfo parseFrom(java.io.InputStream input) + throws java.io.IOException { + return PARSER.parseFrom(input); + } + public static com.mogujie.tt.protobuf.IMBaseDefine.UserTokenInfo parseFrom( + java.io.InputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return PARSER.parseFrom(input, extensionRegistry); + } + public static com.mogujie.tt.protobuf.IMBaseDefine.UserTokenInfo parseDelimitedFrom(java.io.InputStream input) + throws java.io.IOException { + return PARSER.parseDelimitedFrom(input); + } + public static com.mogujie.tt.protobuf.IMBaseDefine.UserTokenInfo parseDelimitedFrom( + java.io.InputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return PARSER.parseDelimitedFrom(input, extensionRegistry); + } + public static com.mogujie.tt.protobuf.IMBaseDefine.UserTokenInfo parseFrom( + com.google.protobuf.CodedInputStream input) + throws java.io.IOException { + return PARSER.parseFrom(input); + } + public static com.mogujie.tt.protobuf.IMBaseDefine.UserTokenInfo parseFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return PARSER.parseFrom(input, extensionRegistry); + } + + public static Builder newBuilder() { return Builder.create(); } + public Builder newBuilderForType() { return newBuilder(); } + public static Builder newBuilder(com.mogujie.tt.protobuf.IMBaseDefine.UserTokenInfo prototype) { + return newBuilder().mergeFrom(prototype); + } + public Builder toBuilder() { return newBuilder(this); } + + /** + * Protobuf type {@code IM.BaseDefine.UserTokenInfo} + */ + public static final class Builder extends + com.google.protobuf.GeneratedMessageLite.Builder< + com.mogujie.tt.protobuf.IMBaseDefine.UserTokenInfo, Builder> + implements + // @@protoc_insertion_point(builder_implements:IM.BaseDefine.UserTokenInfo) + com.mogujie.tt.protobuf.IMBaseDefine.UserTokenInfoOrBuilder { + // Construct using com.mogujie.tt.protobuf.IMBaseDefine.UserTokenInfo.newBuilder() + private Builder() { + maybeForceBuilderInitialization(); + } + + private void maybeForceBuilderInitialization() { + } + private static Builder create() { + return new Builder(); + } + + public Builder clear() { + super.clear(); + userId_ = 0; + bitField0_ = (bitField0_ & ~0x00000001); + userType_ = com.mogujie.tt.protobuf.IMBaseDefine.ClientType.CLIENT_TYPE_WINDOWS; + bitField0_ = (bitField0_ & ~0x00000002); + token_ = ""; + bitField0_ = (bitField0_ & ~0x00000004); + pushCount_ = 0; + bitField0_ = (bitField0_ & ~0x00000008); + pushType_ = 0; + bitField0_ = (bitField0_ & ~0x00000010); + return this; + } + + public Builder clone() { + return create().mergeFrom(buildPartial()); + } + + public com.mogujie.tt.protobuf.IMBaseDefine.UserTokenInfo getDefaultInstanceForType() { + return com.mogujie.tt.protobuf.IMBaseDefine.UserTokenInfo.getDefaultInstance(); + } + + public com.mogujie.tt.protobuf.IMBaseDefine.UserTokenInfo build() { + com.mogujie.tt.protobuf.IMBaseDefine.UserTokenInfo result = buildPartial(); + if (!result.isInitialized()) { + throw newUninitializedMessageException(result); + } + return result; + } + + public com.mogujie.tt.protobuf.IMBaseDefine.UserTokenInfo buildPartial() { + com.mogujie.tt.protobuf.IMBaseDefine.UserTokenInfo result = new com.mogujie.tt.protobuf.IMBaseDefine.UserTokenInfo(this); + int from_bitField0_ = bitField0_; + int to_bitField0_ = 0; + if (((from_bitField0_ & 0x00000001) == 0x00000001)) { + to_bitField0_ |= 0x00000001; + } + result.userId_ = userId_; + if (((from_bitField0_ & 0x00000002) == 0x00000002)) { + to_bitField0_ |= 0x00000002; + } + result.userType_ = userType_; + if (((from_bitField0_ & 0x00000004) == 0x00000004)) { + to_bitField0_ |= 0x00000004; + } + result.token_ = token_; + if (((from_bitField0_ & 0x00000008) == 0x00000008)) { + to_bitField0_ |= 0x00000008; + } + result.pushCount_ = pushCount_; + if (((from_bitField0_ & 0x00000010) == 0x00000010)) { + to_bitField0_ |= 0x00000010; + } + result.pushType_ = pushType_; + result.bitField0_ = to_bitField0_; + return result; + } + + public Builder mergeFrom(com.mogujie.tt.protobuf.IMBaseDefine.UserTokenInfo other) { + if (other == com.mogujie.tt.protobuf.IMBaseDefine.UserTokenInfo.getDefaultInstance()) return this; + if (other.hasUserId()) { + setUserId(other.getUserId()); + } + if (other.hasUserType()) { + setUserType(other.getUserType()); + } + if (other.hasToken()) { + bitField0_ |= 0x00000004; + token_ = other.token_; + + } + if (other.hasPushCount()) { + setPushCount(other.getPushCount()); + } + if (other.hasPushType()) { + setPushType(other.getPushType()); + } + setUnknownFields( + getUnknownFields().concat(other.unknownFields)); + return this; + } + + public final boolean isInitialized() { + if (!hasUserId()) { + + return false; + } + if (!hasUserType()) { + + return false; + } + if (!hasToken()) { + + return false; + } + if (!hasPushCount()) { + + return false; + } + if (!hasPushType()) { + + return false; + } + return true; + } + + public Builder mergeFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + com.mogujie.tt.protobuf.IMBaseDefine.UserTokenInfo parsedMessage = null; + try { + parsedMessage = PARSER.parsePartialFrom(input, extensionRegistry); + } catch (com.google.protobuf.InvalidProtocolBufferException e) { + parsedMessage = (com.mogujie.tt.protobuf.IMBaseDefine.UserTokenInfo) e.getUnfinishedMessage(); + throw e; + } finally { + if (parsedMessage != null) { + mergeFrom(parsedMessage); + } + } + return this; + } + private int bitField0_; + + private int userId_ ; + /** + * required uint32 user_id = 1; + */ + public boolean hasUserId() { + return ((bitField0_ & 0x00000001) == 0x00000001); + } + /** + * required uint32 user_id = 1; + */ + public int getUserId() { + return userId_; + } + /** + * required uint32 user_id = 1; + */ + public Builder setUserId(int value) { + bitField0_ |= 0x00000001; + userId_ = value; + + return this; + } + /** + * required uint32 user_id = 1; + */ + public Builder clearUserId() { + bitField0_ = (bitField0_ & ~0x00000001); + userId_ = 0; + + return this; + } + + private com.mogujie.tt.protobuf.IMBaseDefine.ClientType userType_ = com.mogujie.tt.protobuf.IMBaseDefine.ClientType.CLIENT_TYPE_WINDOWS; + /** + * required .IM.BaseDefine.ClientType user_type = 2; + */ + public boolean hasUserType() { + return ((bitField0_ & 0x00000002) == 0x00000002); + } + /** + * required .IM.BaseDefine.ClientType user_type = 2; + */ + public com.mogujie.tt.protobuf.IMBaseDefine.ClientType getUserType() { + return userType_; + } + /** + * required .IM.BaseDefine.ClientType user_type = 2; + */ + public Builder setUserType(com.mogujie.tt.protobuf.IMBaseDefine.ClientType value) { + if (value == null) { + throw new NullPointerException(); + } + bitField0_ |= 0x00000002; + userType_ = value; + + return this; + } + /** + * required .IM.BaseDefine.ClientType user_type = 2; + */ + public Builder clearUserType() { + bitField0_ = (bitField0_ & ~0x00000002); + userType_ = com.mogujie.tt.protobuf.IMBaseDefine.ClientType.CLIENT_TYPE_WINDOWS; + + return this; + } + + private java.lang.Object token_ = ""; + /** + * required string token = 3; + */ + public boolean hasToken() { + return ((bitField0_ & 0x00000004) == 0x00000004); + } + /** + * required string token = 3; + */ + public java.lang.String getToken() { + java.lang.Object ref = token_; + if (!(ref instanceof java.lang.String)) { + com.google.protobuf.ByteString bs = + (com.google.protobuf.ByteString) ref; + java.lang.String s = bs.toStringUtf8(); + if (bs.isValidUtf8()) { + token_ = s; + } + return s; + } else { + return (java.lang.String) ref; + } + } + /** + * required string token = 3; + */ + public com.google.protobuf.ByteString + getTokenBytes() { + java.lang.Object ref = token_; + if (ref instanceof String) { + com.google.protobuf.ByteString b = + com.google.protobuf.ByteString.copyFromUtf8( + (java.lang.String) ref); + token_ = b; + return b; + } else { + return (com.google.protobuf.ByteString) ref; + } + } + /** + * required string token = 3; + */ + public Builder setToken( + java.lang.String value) { + if (value == null) { + throw new NullPointerException(); + } + bitField0_ |= 0x00000004; + token_ = value; + + return this; + } + /** + * required string token = 3; + */ + public Builder clearToken() { + bitField0_ = (bitField0_ & ~0x00000004); + token_ = getDefaultInstance().getToken(); + + return this; + } + /** + * required string token = 3; + */ + public Builder setTokenBytes( + com.google.protobuf.ByteString value) { + if (value == null) { + throw new NullPointerException(); + } + bitField0_ |= 0x00000004; + token_ = value; + + return this; + } + + private int pushCount_ ; + /** + * required uint32 push_count = 4; + */ + public boolean hasPushCount() { + return ((bitField0_ & 0x00000008) == 0x00000008); + } + /** + * required uint32 push_count = 4; + */ + public int getPushCount() { + return pushCount_; + } + /** + * required uint32 push_count = 4; + */ + public Builder setPushCount(int value) { + bitField0_ |= 0x00000008; + pushCount_ = value; + + return this; + } + /** + * required uint32 push_count = 4; + */ + public Builder clearPushCount() { + bitField0_ = (bitField0_ & ~0x00000008); + pushCount_ = 0; + + return this; + } + + private int pushType_ ; + /** + * required uint32 push_type = 5; + * + *
+       *1: 正常推送  	2:无打扰式推送
+       * 
+ */ + public boolean hasPushType() { + return ((bitField0_ & 0x00000010) == 0x00000010); + } + /** + * required uint32 push_type = 5; + * + *
+       *1: 正常推送  	2:无打扰式推送
+       * 
+ */ + public int getPushType() { + return pushType_; + } + /** + * required uint32 push_type = 5; + * + *
+       *1: 正常推送  	2:无打扰式推送
+       * 
+ */ + public Builder setPushType(int value) { + bitField0_ |= 0x00000010; + pushType_ = value; + + return this; + } + /** + * required uint32 push_type = 5; + * + *
+       *1: 正常推送  	2:无打扰式推送
+       * 
+ */ + public Builder clearPushType() { + bitField0_ = (bitField0_ & ~0x00000010); + pushType_ = 0; + + return this; + } + + // @@protoc_insertion_point(builder_scope:IM.BaseDefine.UserTokenInfo) + } + + static { + defaultInstance = new UserTokenInfo(true); + defaultInstance.initFields(); + } + + // @@protoc_insertion_point(class_scope:IM.BaseDefine.UserTokenInfo) + } + + public interface PushResultOrBuilder extends + // @@protoc_insertion_point(interface_extends:IM.BaseDefine.PushResult) + com.google.protobuf.MessageLiteOrBuilder { + + /** + * required string user_token = 1; + */ + boolean hasUserToken(); + /** + * required string user_token = 1; + */ + java.lang.String getUserToken(); + /** + * required string user_token = 1; + */ + com.google.protobuf.ByteString + getUserTokenBytes(); + + /** + * required uint32 result_code = 2; + */ + boolean hasResultCode(); + /** + * required uint32 result_code = 2; + */ + int getResultCode(); + } + /** + * Protobuf type {@code IM.BaseDefine.PushResult} + */ + public static final class PushResult extends + com.google.protobuf.GeneratedMessageLite implements + // @@protoc_insertion_point(message_implements:IM.BaseDefine.PushResult) + PushResultOrBuilder { + // Use PushResult.newBuilder() to construct. + private PushResult(com.google.protobuf.GeneratedMessageLite.Builder builder) { + super(builder); + this.unknownFields = builder.getUnknownFields(); + } + private PushResult(boolean noInit) { this.unknownFields = com.google.protobuf.ByteString.EMPTY;} + + private static final PushResult defaultInstance; + public static PushResult getDefaultInstance() { + return defaultInstance; + } + + public PushResult getDefaultInstanceForType() { + return defaultInstance; + } + + private final com.google.protobuf.ByteString unknownFields; + private PushResult( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + initFields(); + int mutable_bitField0_ = 0; + com.google.protobuf.ByteString.Output unknownFieldsOutput = + com.google.protobuf.ByteString.newOutput(); + com.google.protobuf.CodedOutputStream unknownFieldsCodedOutput = + com.google.protobuf.CodedOutputStream.newInstance( + unknownFieldsOutput); + try { + boolean done = false; + while (!done) { + int tag = input.readTag(); + switch (tag) { + case 0: + done = true; + break; + default: { + if (!parseUnknownField(input, unknownFieldsCodedOutput, + extensionRegistry, tag)) { + done = true; + } + break; + } + case 10: { + com.google.protobuf.ByteString bs = input.readBytes(); + bitField0_ |= 0x00000001; + userToken_ = bs; + break; + } + case 16: { + bitField0_ |= 0x00000002; + resultCode_ = input.readUInt32(); + break; + } + } + } + } catch (com.google.protobuf.InvalidProtocolBufferException e) { + throw e.setUnfinishedMessage(this); + } catch (java.io.IOException e) { + throw new com.google.protobuf.InvalidProtocolBufferException( + e.getMessage()).setUnfinishedMessage(this); + } finally { + try { + unknownFieldsCodedOutput.flush(); + } catch (java.io.IOException e) { + // Should not happen + } finally { + unknownFields = unknownFieldsOutput.toByteString(); + } + makeExtensionsImmutable(); + } + } + public static com.google.protobuf.Parser PARSER = + new com.google.protobuf.AbstractParser() { + public PushResult parsePartialFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return new PushResult(input, extensionRegistry); + } + }; + + @java.lang.Override + public com.google.protobuf.Parser getParserForType() { + return PARSER; + } + + private int bitField0_; + public static final int USER_TOKEN_FIELD_NUMBER = 1; + private java.lang.Object userToken_; + /** + * required string user_token = 1; + */ + public boolean hasUserToken() { + return ((bitField0_ & 0x00000001) == 0x00000001); + } + /** + * required string user_token = 1; + */ + public java.lang.String getUserToken() { + java.lang.Object ref = userToken_; + if (ref instanceof java.lang.String) { + return (java.lang.String) ref; + } else { + com.google.protobuf.ByteString bs = + (com.google.protobuf.ByteString) ref; + java.lang.String s = bs.toStringUtf8(); + if (bs.isValidUtf8()) { + userToken_ = s; + } + return s; + } + } + /** + * required string user_token = 1; + */ + public com.google.protobuf.ByteString + getUserTokenBytes() { + java.lang.Object ref = userToken_; + if (ref instanceof java.lang.String) { + com.google.protobuf.ByteString b = + com.google.protobuf.ByteString.copyFromUtf8( + (java.lang.String) ref); + userToken_ = b; + return b; + } else { + return (com.google.protobuf.ByteString) ref; + } + } + + public static final int RESULT_CODE_FIELD_NUMBER = 2; + private int resultCode_; + /** + * required uint32 result_code = 2; + */ + public boolean hasResultCode() { + return ((bitField0_ & 0x00000002) == 0x00000002); + } + /** + * required uint32 result_code = 2; + */ + public int getResultCode() { + return resultCode_; + } + + private void initFields() { + userToken_ = ""; + resultCode_ = 0; + } + private byte memoizedIsInitialized = -1; + public final boolean isInitialized() { + byte isInitialized = memoizedIsInitialized; + if (isInitialized == 1) return true; + if (isInitialized == 0) return false; + + if (!hasUserToken()) { + memoizedIsInitialized = 0; + return false; + } + if (!hasResultCode()) { + memoizedIsInitialized = 0; + return false; + } + memoizedIsInitialized = 1; + return true; + } + + public void writeTo(com.google.protobuf.CodedOutputStream output) + throws java.io.IOException { + getSerializedSize(); + if (((bitField0_ & 0x00000001) == 0x00000001)) { + output.writeBytes(1, getUserTokenBytes()); + } + if (((bitField0_ & 0x00000002) == 0x00000002)) { + output.writeUInt32(2, resultCode_); + } + output.writeRawBytes(unknownFields); + } + + private int memoizedSerializedSize = -1; + public int getSerializedSize() { + int size = memoizedSerializedSize; + if (size != -1) return size; + + size = 0; + if (((bitField0_ & 0x00000001) == 0x00000001)) { + size += com.google.protobuf.CodedOutputStream + .computeBytesSize(1, getUserTokenBytes()); + } + if (((bitField0_ & 0x00000002) == 0x00000002)) { + size += com.google.protobuf.CodedOutputStream + .computeUInt32Size(2, resultCode_); + } + size += unknownFields.size(); + memoizedSerializedSize = size; + return size; + } + + private static final long serialVersionUID = 0L; + @java.lang.Override + protected java.lang.Object writeReplace() + throws java.io.ObjectStreamException { + return super.writeReplace(); + } + + public static com.mogujie.tt.protobuf.IMBaseDefine.PushResult parseFrom( + com.google.protobuf.ByteString data) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data); + } + public static com.mogujie.tt.protobuf.IMBaseDefine.PushResult parseFrom( + com.google.protobuf.ByteString data, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data, extensionRegistry); + } + public static com.mogujie.tt.protobuf.IMBaseDefine.PushResult parseFrom(byte[] data) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data); + } + public static com.mogujie.tt.protobuf.IMBaseDefine.PushResult parseFrom( + byte[] data, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data, extensionRegistry); + } + public static com.mogujie.tt.protobuf.IMBaseDefine.PushResult parseFrom(java.io.InputStream input) + throws java.io.IOException { + return PARSER.parseFrom(input); + } + public static com.mogujie.tt.protobuf.IMBaseDefine.PushResult parseFrom( + java.io.InputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return PARSER.parseFrom(input, extensionRegistry); + } + public static com.mogujie.tt.protobuf.IMBaseDefine.PushResult parseDelimitedFrom(java.io.InputStream input) + throws java.io.IOException { + return PARSER.parseDelimitedFrom(input); + } + public static com.mogujie.tt.protobuf.IMBaseDefine.PushResult parseDelimitedFrom( + java.io.InputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return PARSER.parseDelimitedFrom(input, extensionRegistry); + } + public static com.mogujie.tt.protobuf.IMBaseDefine.PushResult parseFrom( + com.google.protobuf.CodedInputStream input) + throws java.io.IOException { + return PARSER.parseFrom(input); + } + public static com.mogujie.tt.protobuf.IMBaseDefine.PushResult parseFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return PARSER.parseFrom(input, extensionRegistry); + } + + public static Builder newBuilder() { return Builder.create(); } + public Builder newBuilderForType() { return newBuilder(); } + public static Builder newBuilder(com.mogujie.tt.protobuf.IMBaseDefine.PushResult prototype) { + return newBuilder().mergeFrom(prototype); + } + public Builder toBuilder() { return newBuilder(this); } + + /** + * Protobuf type {@code IM.BaseDefine.PushResult} + */ + public static final class Builder extends + com.google.protobuf.GeneratedMessageLite.Builder< + com.mogujie.tt.protobuf.IMBaseDefine.PushResult, Builder> + implements + // @@protoc_insertion_point(builder_implements:IM.BaseDefine.PushResult) + com.mogujie.tt.protobuf.IMBaseDefine.PushResultOrBuilder { + // Construct using com.mogujie.tt.protobuf.IMBaseDefine.PushResult.newBuilder() + private Builder() { + maybeForceBuilderInitialization(); + } + + private void maybeForceBuilderInitialization() { + } + private static Builder create() { + return new Builder(); + } + + public Builder clear() { + super.clear(); + userToken_ = ""; + bitField0_ = (bitField0_ & ~0x00000001); + resultCode_ = 0; + bitField0_ = (bitField0_ & ~0x00000002); + return this; + } + + public Builder clone() { + return create().mergeFrom(buildPartial()); + } + + public com.mogujie.tt.protobuf.IMBaseDefine.PushResult getDefaultInstanceForType() { + return com.mogujie.tt.protobuf.IMBaseDefine.PushResult.getDefaultInstance(); + } + + public com.mogujie.tt.protobuf.IMBaseDefine.PushResult build() { + com.mogujie.tt.protobuf.IMBaseDefine.PushResult result = buildPartial(); + if (!result.isInitialized()) { + throw newUninitializedMessageException(result); + } + return result; + } + + public com.mogujie.tt.protobuf.IMBaseDefine.PushResult buildPartial() { + com.mogujie.tt.protobuf.IMBaseDefine.PushResult result = new com.mogujie.tt.protobuf.IMBaseDefine.PushResult(this); + int from_bitField0_ = bitField0_; + int to_bitField0_ = 0; + if (((from_bitField0_ & 0x00000001) == 0x00000001)) { + to_bitField0_ |= 0x00000001; + } + result.userToken_ = userToken_; + if (((from_bitField0_ & 0x00000002) == 0x00000002)) { + to_bitField0_ |= 0x00000002; + } + result.resultCode_ = resultCode_; + result.bitField0_ = to_bitField0_; + return result; + } + + public Builder mergeFrom(com.mogujie.tt.protobuf.IMBaseDefine.PushResult other) { + if (other == com.mogujie.tt.protobuf.IMBaseDefine.PushResult.getDefaultInstance()) return this; + if (other.hasUserToken()) { + bitField0_ |= 0x00000001; + userToken_ = other.userToken_; + + } + if (other.hasResultCode()) { + setResultCode(other.getResultCode()); + } + setUnknownFields( + getUnknownFields().concat(other.unknownFields)); + return this; + } + + public final boolean isInitialized() { + if (!hasUserToken()) { + + return false; + } + if (!hasResultCode()) { + + return false; + } + return true; + } + + public Builder mergeFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + com.mogujie.tt.protobuf.IMBaseDefine.PushResult parsedMessage = null; + try { + parsedMessage = PARSER.parsePartialFrom(input, extensionRegistry); + } catch (com.google.protobuf.InvalidProtocolBufferException e) { + parsedMessage = (com.mogujie.tt.protobuf.IMBaseDefine.PushResult) e.getUnfinishedMessage(); + throw e; + } finally { + if (parsedMessage != null) { + mergeFrom(parsedMessage); + } + } + return this; + } + private int bitField0_; + + private java.lang.Object userToken_ = ""; + /** + * required string user_token = 1; + */ + public boolean hasUserToken() { + return ((bitField0_ & 0x00000001) == 0x00000001); + } + /** + * required string user_token = 1; + */ + public java.lang.String getUserToken() { + java.lang.Object ref = userToken_; + if (!(ref instanceof java.lang.String)) { + com.google.protobuf.ByteString bs = + (com.google.protobuf.ByteString) ref; + java.lang.String s = bs.toStringUtf8(); + if (bs.isValidUtf8()) { + userToken_ = s; + } + return s; + } else { + return (java.lang.String) ref; + } + } + /** + * required string user_token = 1; + */ + public com.google.protobuf.ByteString + getUserTokenBytes() { + java.lang.Object ref = userToken_; + if (ref instanceof String) { + com.google.protobuf.ByteString b = + com.google.protobuf.ByteString.copyFromUtf8( + (java.lang.String) ref); + userToken_ = b; + return b; + } else { + return (com.google.protobuf.ByteString) ref; + } + } + /** + * required string user_token = 1; + */ + public Builder setUserToken( + java.lang.String value) { + if (value == null) { + throw new NullPointerException(); + } + bitField0_ |= 0x00000001; + userToken_ = value; + + return this; + } + /** + * required string user_token = 1; + */ + public Builder clearUserToken() { + bitField0_ = (bitField0_ & ~0x00000001); + userToken_ = getDefaultInstance().getUserToken(); + + return this; + } + /** + * required string user_token = 1; + */ + public Builder setUserTokenBytes( + com.google.protobuf.ByteString value) { + if (value == null) { + throw new NullPointerException(); + } + bitField0_ |= 0x00000001; + userToken_ = value; + + return this; + } + + private int resultCode_ ; + /** + * required uint32 result_code = 2; + */ + public boolean hasResultCode() { + return ((bitField0_ & 0x00000002) == 0x00000002); + } + /** + * required uint32 result_code = 2; + */ + public int getResultCode() { + return resultCode_; + } + /** + * required uint32 result_code = 2; + */ + public Builder setResultCode(int value) { + bitField0_ |= 0x00000002; + resultCode_ = value; + + return this; + } + /** + * required uint32 result_code = 2; + */ + public Builder clearResultCode() { + bitField0_ = (bitField0_ & ~0x00000002); + resultCode_ = 0; + + return this; + } + + // @@protoc_insertion_point(builder_scope:IM.BaseDefine.PushResult) + } + + static { + defaultInstance = new PushResult(true); + defaultInstance.initFields(); + } + + // @@protoc_insertion_point(class_scope:IM.BaseDefine.PushResult) + } + + public interface ShieldStatusOrBuilder extends + // @@protoc_insertion_point(interface_extends:IM.BaseDefine.ShieldStatus) + com.google.protobuf.MessageLiteOrBuilder { + + /** + * required uint32 user_id = 1; + */ + boolean hasUserId(); + /** + * required uint32 user_id = 1; + */ + int getUserId(); + + /** + * required uint32 group_id = 2; + */ + boolean hasGroupId(); + /** + * required uint32 group_id = 2; + */ + int getGroupId(); + + /** + * required uint32 shield_status = 3; + * + *
+     *1: shield  0: not shield 
+     * 
+ */ + boolean hasShieldStatus(); + /** + * required uint32 shield_status = 3; + * + *
+     *1: shield  0: not shield 
+     * 
+ */ + int getShieldStatus(); + } + /** + * Protobuf type {@code IM.BaseDefine.ShieldStatus} + */ + public static final class ShieldStatus extends + com.google.protobuf.GeneratedMessageLite implements + // @@protoc_insertion_point(message_implements:IM.BaseDefine.ShieldStatus) + ShieldStatusOrBuilder { + // Use ShieldStatus.newBuilder() to construct. + private ShieldStatus(com.google.protobuf.GeneratedMessageLite.Builder builder) { + super(builder); + this.unknownFields = builder.getUnknownFields(); + } + private ShieldStatus(boolean noInit) { this.unknownFields = com.google.protobuf.ByteString.EMPTY;} + + private static final ShieldStatus defaultInstance; + public static ShieldStatus getDefaultInstance() { + return defaultInstance; + } + + public ShieldStatus getDefaultInstanceForType() { + return defaultInstance; + } + + private final com.google.protobuf.ByteString unknownFields; + private ShieldStatus( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + initFields(); + int mutable_bitField0_ = 0; + com.google.protobuf.ByteString.Output unknownFieldsOutput = + com.google.protobuf.ByteString.newOutput(); + com.google.protobuf.CodedOutputStream unknownFieldsCodedOutput = + com.google.protobuf.CodedOutputStream.newInstance( + unknownFieldsOutput); + try { + boolean done = false; + while (!done) { + int tag = input.readTag(); + switch (tag) { + case 0: + done = true; + break; + default: { + if (!parseUnknownField(input, unknownFieldsCodedOutput, + extensionRegistry, tag)) { + done = true; + } + break; + } + case 8: { + bitField0_ |= 0x00000001; + userId_ = input.readUInt32(); + break; + } + case 16: { + bitField0_ |= 0x00000002; + groupId_ = input.readUInt32(); + break; + } + case 24: { + bitField0_ |= 0x00000004; + shieldStatus_ = input.readUInt32(); + break; + } + } + } + } catch (com.google.protobuf.InvalidProtocolBufferException e) { + throw e.setUnfinishedMessage(this); + } catch (java.io.IOException e) { + throw new com.google.protobuf.InvalidProtocolBufferException( + e.getMessage()).setUnfinishedMessage(this); + } finally { + try { + unknownFieldsCodedOutput.flush(); + } catch (java.io.IOException e) { + // Should not happen + } finally { + unknownFields = unknownFieldsOutput.toByteString(); + } + makeExtensionsImmutable(); + } + } + public static com.google.protobuf.Parser PARSER = + new com.google.protobuf.AbstractParser() { + public ShieldStatus parsePartialFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return new ShieldStatus(input, extensionRegistry); + } + }; + + @java.lang.Override + public com.google.protobuf.Parser getParserForType() { + return PARSER; + } + + private int bitField0_; + public static final int USER_ID_FIELD_NUMBER = 1; + private int userId_; + /** + * required uint32 user_id = 1; + */ + public boolean hasUserId() { + return ((bitField0_ & 0x00000001) == 0x00000001); + } + /** + * required uint32 user_id = 1; + */ + public int getUserId() { + return userId_; + } + + public static final int GROUP_ID_FIELD_NUMBER = 2; + private int groupId_; + /** + * required uint32 group_id = 2; + */ + public boolean hasGroupId() { + return ((bitField0_ & 0x00000002) == 0x00000002); + } + /** + * required uint32 group_id = 2; + */ + public int getGroupId() { + return groupId_; + } + + public static final int SHIELD_STATUS_FIELD_NUMBER = 3; + private int shieldStatus_; + /** + * required uint32 shield_status = 3; + * + *
+     *1: shield  0: not shield 
+     * 
+ */ + public boolean hasShieldStatus() { + return ((bitField0_ & 0x00000004) == 0x00000004); + } + /** + * required uint32 shield_status = 3; + * + *
+     *1: shield  0: not shield 
+     * 
+ */ + public int getShieldStatus() { + return shieldStatus_; + } + + private void initFields() { + userId_ = 0; + groupId_ = 0; + shieldStatus_ = 0; + } + private byte memoizedIsInitialized = -1; + public final boolean isInitialized() { + byte isInitialized = memoizedIsInitialized; + if (isInitialized == 1) return true; + if (isInitialized == 0) return false; + + if (!hasUserId()) { + memoizedIsInitialized = 0; + return false; + } + if (!hasGroupId()) { + memoizedIsInitialized = 0; + return false; + } + if (!hasShieldStatus()) { + memoizedIsInitialized = 0; + return false; + } + memoizedIsInitialized = 1; + return true; + } + + public void writeTo(com.google.protobuf.CodedOutputStream output) + throws java.io.IOException { + getSerializedSize(); + if (((bitField0_ & 0x00000001) == 0x00000001)) { + output.writeUInt32(1, userId_); + } + if (((bitField0_ & 0x00000002) == 0x00000002)) { + output.writeUInt32(2, groupId_); + } + if (((bitField0_ & 0x00000004) == 0x00000004)) { + output.writeUInt32(3, shieldStatus_); + } + output.writeRawBytes(unknownFields); + } + + private int memoizedSerializedSize = -1; + public int getSerializedSize() { + int size = memoizedSerializedSize; + if (size != -1) return size; + + size = 0; + if (((bitField0_ & 0x00000001) == 0x00000001)) { + size += com.google.protobuf.CodedOutputStream + .computeUInt32Size(1, userId_); + } + if (((bitField0_ & 0x00000002) == 0x00000002)) { + size += com.google.protobuf.CodedOutputStream + .computeUInt32Size(2, groupId_); + } + if (((bitField0_ & 0x00000004) == 0x00000004)) { + size += com.google.protobuf.CodedOutputStream + .computeUInt32Size(3, shieldStatus_); + } + size += unknownFields.size(); + memoizedSerializedSize = size; + return size; + } + + private static final long serialVersionUID = 0L; + @java.lang.Override + protected java.lang.Object writeReplace() + throws java.io.ObjectStreamException { + return super.writeReplace(); + } + + public static com.mogujie.tt.protobuf.IMBaseDefine.ShieldStatus parseFrom( + com.google.protobuf.ByteString data) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data); + } + public static com.mogujie.tt.protobuf.IMBaseDefine.ShieldStatus parseFrom( + com.google.protobuf.ByteString data, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data, extensionRegistry); + } + public static com.mogujie.tt.protobuf.IMBaseDefine.ShieldStatus parseFrom(byte[] data) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data); + } + public static com.mogujie.tt.protobuf.IMBaseDefine.ShieldStatus parseFrom( + byte[] data, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data, extensionRegistry); + } + public static com.mogujie.tt.protobuf.IMBaseDefine.ShieldStatus parseFrom(java.io.InputStream input) + throws java.io.IOException { + return PARSER.parseFrom(input); + } + public static com.mogujie.tt.protobuf.IMBaseDefine.ShieldStatus parseFrom( + java.io.InputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return PARSER.parseFrom(input, extensionRegistry); + } + public static com.mogujie.tt.protobuf.IMBaseDefine.ShieldStatus parseDelimitedFrom(java.io.InputStream input) + throws java.io.IOException { + return PARSER.parseDelimitedFrom(input); + } + public static com.mogujie.tt.protobuf.IMBaseDefine.ShieldStatus parseDelimitedFrom( + java.io.InputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return PARSER.parseDelimitedFrom(input, extensionRegistry); + } + public static com.mogujie.tt.protobuf.IMBaseDefine.ShieldStatus parseFrom( + com.google.protobuf.CodedInputStream input) + throws java.io.IOException { + return PARSER.parseFrom(input); + } + public static com.mogujie.tt.protobuf.IMBaseDefine.ShieldStatus parseFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return PARSER.parseFrom(input, extensionRegistry); + } + + public static Builder newBuilder() { return Builder.create(); } + public Builder newBuilderForType() { return newBuilder(); } + public static Builder newBuilder(com.mogujie.tt.protobuf.IMBaseDefine.ShieldStatus prototype) { + return newBuilder().mergeFrom(prototype); + } + public Builder toBuilder() { return newBuilder(this); } + + /** + * Protobuf type {@code IM.BaseDefine.ShieldStatus} + */ + public static final class Builder extends + com.google.protobuf.GeneratedMessageLite.Builder< + com.mogujie.tt.protobuf.IMBaseDefine.ShieldStatus, Builder> + implements + // @@protoc_insertion_point(builder_implements:IM.BaseDefine.ShieldStatus) + com.mogujie.tt.protobuf.IMBaseDefine.ShieldStatusOrBuilder { + // Construct using com.mogujie.tt.protobuf.IMBaseDefine.ShieldStatus.newBuilder() + private Builder() { + maybeForceBuilderInitialization(); + } + + private void maybeForceBuilderInitialization() { + } + private static Builder create() { + return new Builder(); + } + + public Builder clear() { + super.clear(); + userId_ = 0; + bitField0_ = (bitField0_ & ~0x00000001); + groupId_ = 0; + bitField0_ = (bitField0_ & ~0x00000002); + shieldStatus_ = 0; + bitField0_ = (bitField0_ & ~0x00000004); + return this; + } + + public Builder clone() { + return create().mergeFrom(buildPartial()); + } + + public com.mogujie.tt.protobuf.IMBaseDefine.ShieldStatus getDefaultInstanceForType() { + return com.mogujie.tt.protobuf.IMBaseDefine.ShieldStatus.getDefaultInstance(); + } + + public com.mogujie.tt.protobuf.IMBaseDefine.ShieldStatus build() { + com.mogujie.tt.protobuf.IMBaseDefine.ShieldStatus result = buildPartial(); + if (!result.isInitialized()) { + throw newUninitializedMessageException(result); + } + return result; + } + + public com.mogujie.tt.protobuf.IMBaseDefine.ShieldStatus buildPartial() { + com.mogujie.tt.protobuf.IMBaseDefine.ShieldStatus result = new com.mogujie.tt.protobuf.IMBaseDefine.ShieldStatus(this); + int from_bitField0_ = bitField0_; + int to_bitField0_ = 0; + if (((from_bitField0_ & 0x00000001) == 0x00000001)) { + to_bitField0_ |= 0x00000001; + } + result.userId_ = userId_; + if (((from_bitField0_ & 0x00000002) == 0x00000002)) { + to_bitField0_ |= 0x00000002; + } + result.groupId_ = groupId_; + if (((from_bitField0_ & 0x00000004) == 0x00000004)) { + to_bitField0_ |= 0x00000004; + } + result.shieldStatus_ = shieldStatus_; + result.bitField0_ = to_bitField0_; + return result; + } + + public Builder mergeFrom(com.mogujie.tt.protobuf.IMBaseDefine.ShieldStatus other) { + if (other == com.mogujie.tt.protobuf.IMBaseDefine.ShieldStatus.getDefaultInstance()) return this; + if (other.hasUserId()) { + setUserId(other.getUserId()); + } + if (other.hasGroupId()) { + setGroupId(other.getGroupId()); + } + if (other.hasShieldStatus()) { + setShieldStatus(other.getShieldStatus()); + } + setUnknownFields( + getUnknownFields().concat(other.unknownFields)); + return this; + } + + public final boolean isInitialized() { + if (!hasUserId()) { + + return false; + } + if (!hasGroupId()) { + + return false; + } + if (!hasShieldStatus()) { + + return false; + } + return true; + } + + public Builder mergeFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + com.mogujie.tt.protobuf.IMBaseDefine.ShieldStatus parsedMessage = null; + try { + parsedMessage = PARSER.parsePartialFrom(input, extensionRegistry); + } catch (com.google.protobuf.InvalidProtocolBufferException e) { + parsedMessage = (com.mogujie.tt.protobuf.IMBaseDefine.ShieldStatus) e.getUnfinishedMessage(); + throw e; + } finally { + if (parsedMessage != null) { + mergeFrom(parsedMessage); + } + } + return this; + } + private int bitField0_; + + private int userId_ ; + /** + * required uint32 user_id = 1; + */ + public boolean hasUserId() { + return ((bitField0_ & 0x00000001) == 0x00000001); + } + /** + * required uint32 user_id = 1; + */ + public int getUserId() { + return userId_; + } + /** + * required uint32 user_id = 1; + */ + public Builder setUserId(int value) { + bitField0_ |= 0x00000001; + userId_ = value; + + return this; + } + /** + * required uint32 user_id = 1; + */ + public Builder clearUserId() { + bitField0_ = (bitField0_ & ~0x00000001); + userId_ = 0; + + return this; + } + + private int groupId_ ; + /** + * required uint32 group_id = 2; + */ + public boolean hasGroupId() { + return ((bitField0_ & 0x00000002) == 0x00000002); + } + /** + * required uint32 group_id = 2; + */ + public int getGroupId() { + return groupId_; + } + /** + * required uint32 group_id = 2; + */ + public Builder setGroupId(int value) { + bitField0_ |= 0x00000002; + groupId_ = value; + + return this; + } + /** + * required uint32 group_id = 2; + */ + public Builder clearGroupId() { + bitField0_ = (bitField0_ & ~0x00000002); + groupId_ = 0; + + return this; + } + + private int shieldStatus_ ; + /** + * required uint32 shield_status = 3; + * + *
+       *1: shield  0: not shield 
+       * 
+ */ + public boolean hasShieldStatus() { + return ((bitField0_ & 0x00000004) == 0x00000004); + } + /** + * required uint32 shield_status = 3; + * + *
+       *1: shield  0: not shield 
+       * 
+ */ + public int getShieldStatus() { + return shieldStatus_; + } + /** + * required uint32 shield_status = 3; + * + *
+       *1: shield  0: not shield 
+       * 
+ */ + public Builder setShieldStatus(int value) { + bitField0_ |= 0x00000004; + shieldStatus_ = value; + + return this; + } + /** + * required uint32 shield_status = 3; + * + *
+       *1: shield  0: not shield 
+       * 
+ */ + public Builder clearShieldStatus() { + bitField0_ = (bitField0_ & ~0x00000004); + shieldStatus_ = 0; + + return this; + } + + // @@protoc_insertion_point(builder_scope:IM.BaseDefine.ShieldStatus) + } + + static { + defaultInstance = new ShieldStatus(true); + defaultInstance.initFields(); + } + + // @@protoc_insertion_point(class_scope:IM.BaseDefine.ShieldStatus) + } + + public interface OfflineFileInfoOrBuilder extends + // @@protoc_insertion_point(interface_extends:IM.BaseDefine.OfflineFileInfo) + com.google.protobuf.MessageLiteOrBuilder { + + /** + * required uint32 from_user_id = 1; + */ + boolean hasFromUserId(); + /** + * required uint32 from_user_id = 1; + */ + int getFromUserId(); + + /** + * required string task_id = 2; + */ + boolean hasTaskId(); + /** + * required string task_id = 2; + */ + java.lang.String getTaskId(); + /** + * required string task_id = 2; + */ + com.google.protobuf.ByteString + getTaskIdBytes(); + + /** + * required string file_name = 3; + */ + boolean hasFileName(); + /** + * required string file_name = 3; + */ + java.lang.String getFileName(); + /** + * required string file_name = 3; + */ + com.google.protobuf.ByteString + getFileNameBytes(); + + /** + * required uint32 file_size = 4; + */ + boolean hasFileSize(); + /** + * required uint32 file_size = 4; + */ + int getFileSize(); + } + /** + * Protobuf type {@code IM.BaseDefine.OfflineFileInfo} + */ + public static final class OfflineFileInfo extends + com.google.protobuf.GeneratedMessageLite implements + // @@protoc_insertion_point(message_implements:IM.BaseDefine.OfflineFileInfo) + OfflineFileInfoOrBuilder { + // Use OfflineFileInfo.newBuilder() to construct. + private OfflineFileInfo(com.google.protobuf.GeneratedMessageLite.Builder builder) { + super(builder); + this.unknownFields = builder.getUnknownFields(); + } + private OfflineFileInfo(boolean noInit) { this.unknownFields = com.google.protobuf.ByteString.EMPTY;} + + private static final OfflineFileInfo defaultInstance; + public static OfflineFileInfo getDefaultInstance() { + return defaultInstance; + } + + public OfflineFileInfo getDefaultInstanceForType() { + return defaultInstance; + } + + private final com.google.protobuf.ByteString unknownFields; + private OfflineFileInfo( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + initFields(); + int mutable_bitField0_ = 0; + com.google.protobuf.ByteString.Output unknownFieldsOutput = + com.google.protobuf.ByteString.newOutput(); + com.google.protobuf.CodedOutputStream unknownFieldsCodedOutput = + com.google.protobuf.CodedOutputStream.newInstance( + unknownFieldsOutput); + try { + boolean done = false; + while (!done) { + int tag = input.readTag(); + switch (tag) { + case 0: + done = true; + break; + default: { + if (!parseUnknownField(input, unknownFieldsCodedOutput, + extensionRegistry, tag)) { + done = true; + } + break; + } + case 8: { + bitField0_ |= 0x00000001; + fromUserId_ = input.readUInt32(); + break; + } + case 18: { + com.google.protobuf.ByteString bs = input.readBytes(); + bitField0_ |= 0x00000002; + taskId_ = bs; + break; + } + case 26: { + com.google.protobuf.ByteString bs = input.readBytes(); + bitField0_ |= 0x00000004; + fileName_ = bs; + break; + } + case 32: { + bitField0_ |= 0x00000008; + fileSize_ = input.readUInt32(); + break; + } + } + } + } catch (com.google.protobuf.InvalidProtocolBufferException e) { + throw e.setUnfinishedMessage(this); + } catch (java.io.IOException e) { + throw new com.google.protobuf.InvalidProtocolBufferException( + e.getMessage()).setUnfinishedMessage(this); + } finally { + try { + unknownFieldsCodedOutput.flush(); + } catch (java.io.IOException e) { + // Should not happen + } finally { + unknownFields = unknownFieldsOutput.toByteString(); + } + makeExtensionsImmutable(); + } + } + public static com.google.protobuf.Parser PARSER = + new com.google.protobuf.AbstractParser() { + public OfflineFileInfo parsePartialFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return new OfflineFileInfo(input, extensionRegistry); + } + }; + + @java.lang.Override + public com.google.protobuf.Parser getParserForType() { + return PARSER; + } + + private int bitField0_; + public static final int FROM_USER_ID_FIELD_NUMBER = 1; + private int fromUserId_; + /** + * required uint32 from_user_id = 1; + */ + public boolean hasFromUserId() { + return ((bitField0_ & 0x00000001) == 0x00000001); + } + /** + * required uint32 from_user_id = 1; + */ + public int getFromUserId() { + return fromUserId_; + } + + public static final int TASK_ID_FIELD_NUMBER = 2; + private java.lang.Object taskId_; + /** + * required string task_id = 2; + */ + public boolean hasTaskId() { + return ((bitField0_ & 0x00000002) == 0x00000002); + } + /** + * required string task_id = 2; + */ + public java.lang.String getTaskId() { + java.lang.Object ref = taskId_; + if (ref instanceof java.lang.String) { + return (java.lang.String) ref; + } else { + com.google.protobuf.ByteString bs = + (com.google.protobuf.ByteString) ref; + java.lang.String s = bs.toStringUtf8(); + if (bs.isValidUtf8()) { + taskId_ = s; + } + return s; + } + } + /** + * required string task_id = 2; + */ + public com.google.protobuf.ByteString + getTaskIdBytes() { + java.lang.Object ref = taskId_; + if (ref instanceof java.lang.String) { + com.google.protobuf.ByteString b = + com.google.protobuf.ByteString.copyFromUtf8( + (java.lang.String) ref); + taskId_ = b; + return b; + } else { + return (com.google.protobuf.ByteString) ref; + } + } + + public static final int FILE_NAME_FIELD_NUMBER = 3; + private java.lang.Object fileName_; + /** + * required string file_name = 3; + */ + public boolean hasFileName() { + return ((bitField0_ & 0x00000004) == 0x00000004); + } + /** + * required string file_name = 3; + */ + public java.lang.String getFileName() { + java.lang.Object ref = fileName_; + if (ref instanceof java.lang.String) { + return (java.lang.String) ref; + } else { + com.google.protobuf.ByteString bs = + (com.google.protobuf.ByteString) ref; + java.lang.String s = bs.toStringUtf8(); + if (bs.isValidUtf8()) { + fileName_ = s; + } + return s; + } + } + /** + * required string file_name = 3; + */ + public com.google.protobuf.ByteString + getFileNameBytes() { + java.lang.Object ref = fileName_; + if (ref instanceof java.lang.String) { + com.google.protobuf.ByteString b = + com.google.protobuf.ByteString.copyFromUtf8( + (java.lang.String) ref); + fileName_ = b; + return b; + } else { + return (com.google.protobuf.ByteString) ref; + } + } + + public static final int FILE_SIZE_FIELD_NUMBER = 4; + private int fileSize_; + /** + * required uint32 file_size = 4; + */ + public boolean hasFileSize() { + return ((bitField0_ & 0x00000008) == 0x00000008); + } + /** + * required uint32 file_size = 4; + */ + public int getFileSize() { + return fileSize_; + } + + private void initFields() { + fromUserId_ = 0; + taskId_ = ""; + fileName_ = ""; + fileSize_ = 0; + } + private byte memoizedIsInitialized = -1; + public final boolean isInitialized() { + byte isInitialized = memoizedIsInitialized; + if (isInitialized == 1) return true; + if (isInitialized == 0) return false; + + if (!hasFromUserId()) { + memoizedIsInitialized = 0; + return false; + } + if (!hasTaskId()) { + memoizedIsInitialized = 0; + return false; + } + if (!hasFileName()) { + memoizedIsInitialized = 0; + return false; + } + if (!hasFileSize()) { + memoizedIsInitialized = 0; + return false; + } + memoizedIsInitialized = 1; + return true; + } + + public void writeTo(com.google.protobuf.CodedOutputStream output) + throws java.io.IOException { + getSerializedSize(); + if (((bitField0_ & 0x00000001) == 0x00000001)) { + output.writeUInt32(1, fromUserId_); + } + if (((bitField0_ & 0x00000002) == 0x00000002)) { + output.writeBytes(2, getTaskIdBytes()); + } + if (((bitField0_ & 0x00000004) == 0x00000004)) { + output.writeBytes(3, getFileNameBytes()); + } + if (((bitField0_ & 0x00000008) == 0x00000008)) { + output.writeUInt32(4, fileSize_); + } + output.writeRawBytes(unknownFields); + } + + private int memoizedSerializedSize = -1; + public int getSerializedSize() { + int size = memoizedSerializedSize; + if (size != -1) return size; + + size = 0; + if (((bitField0_ & 0x00000001) == 0x00000001)) { + size += com.google.protobuf.CodedOutputStream + .computeUInt32Size(1, fromUserId_); + } + if (((bitField0_ & 0x00000002) == 0x00000002)) { + size += com.google.protobuf.CodedOutputStream + .computeBytesSize(2, getTaskIdBytes()); + } + if (((bitField0_ & 0x00000004) == 0x00000004)) { + size += com.google.protobuf.CodedOutputStream + .computeBytesSize(3, getFileNameBytes()); + } + if (((bitField0_ & 0x00000008) == 0x00000008)) { + size += com.google.protobuf.CodedOutputStream + .computeUInt32Size(4, fileSize_); + } + size += unknownFields.size(); + memoizedSerializedSize = size; + return size; + } + + private static final long serialVersionUID = 0L; + @java.lang.Override + protected java.lang.Object writeReplace() + throws java.io.ObjectStreamException { + return super.writeReplace(); + } + + public static com.mogujie.tt.protobuf.IMBaseDefine.OfflineFileInfo parseFrom( + com.google.protobuf.ByteString data) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data); + } + public static com.mogujie.tt.protobuf.IMBaseDefine.OfflineFileInfo parseFrom( + com.google.protobuf.ByteString data, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data, extensionRegistry); + } + public static com.mogujie.tt.protobuf.IMBaseDefine.OfflineFileInfo parseFrom(byte[] data) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data); + } + public static com.mogujie.tt.protobuf.IMBaseDefine.OfflineFileInfo parseFrom( + byte[] data, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data, extensionRegistry); + } + public static com.mogujie.tt.protobuf.IMBaseDefine.OfflineFileInfo parseFrom(java.io.InputStream input) + throws java.io.IOException { + return PARSER.parseFrom(input); + } + public static com.mogujie.tt.protobuf.IMBaseDefine.OfflineFileInfo parseFrom( + java.io.InputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return PARSER.parseFrom(input, extensionRegistry); + } + public static com.mogujie.tt.protobuf.IMBaseDefine.OfflineFileInfo parseDelimitedFrom(java.io.InputStream input) + throws java.io.IOException { + return PARSER.parseDelimitedFrom(input); + } + public static com.mogujie.tt.protobuf.IMBaseDefine.OfflineFileInfo parseDelimitedFrom( + java.io.InputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return PARSER.parseDelimitedFrom(input, extensionRegistry); + } + public static com.mogujie.tt.protobuf.IMBaseDefine.OfflineFileInfo parseFrom( + com.google.protobuf.CodedInputStream input) + throws java.io.IOException { + return PARSER.parseFrom(input); + } + public static com.mogujie.tt.protobuf.IMBaseDefine.OfflineFileInfo parseFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return PARSER.parseFrom(input, extensionRegistry); + } + + public static Builder newBuilder() { return Builder.create(); } + public Builder newBuilderForType() { return newBuilder(); } + public static Builder newBuilder(com.mogujie.tt.protobuf.IMBaseDefine.OfflineFileInfo prototype) { + return newBuilder().mergeFrom(prototype); + } + public Builder toBuilder() { return newBuilder(this); } + + /** + * Protobuf type {@code IM.BaseDefine.OfflineFileInfo} + */ + public static final class Builder extends + com.google.protobuf.GeneratedMessageLite.Builder< + com.mogujie.tt.protobuf.IMBaseDefine.OfflineFileInfo, Builder> + implements + // @@protoc_insertion_point(builder_implements:IM.BaseDefine.OfflineFileInfo) + com.mogujie.tt.protobuf.IMBaseDefine.OfflineFileInfoOrBuilder { + // Construct using com.mogujie.tt.protobuf.IMBaseDefine.OfflineFileInfo.newBuilder() + private Builder() { + maybeForceBuilderInitialization(); + } + + private void maybeForceBuilderInitialization() { + } + private static Builder create() { + return new Builder(); + } + + public Builder clear() { + super.clear(); + fromUserId_ = 0; + bitField0_ = (bitField0_ & ~0x00000001); + taskId_ = ""; + bitField0_ = (bitField0_ & ~0x00000002); + fileName_ = ""; + bitField0_ = (bitField0_ & ~0x00000004); + fileSize_ = 0; + bitField0_ = (bitField0_ & ~0x00000008); + return this; + } + + public Builder clone() { + return create().mergeFrom(buildPartial()); + } + + public com.mogujie.tt.protobuf.IMBaseDefine.OfflineFileInfo getDefaultInstanceForType() { + return com.mogujie.tt.protobuf.IMBaseDefine.OfflineFileInfo.getDefaultInstance(); + } + + public com.mogujie.tt.protobuf.IMBaseDefine.OfflineFileInfo build() { + com.mogujie.tt.protobuf.IMBaseDefine.OfflineFileInfo result = buildPartial(); + if (!result.isInitialized()) { + throw newUninitializedMessageException(result); + } + return result; + } + + public com.mogujie.tt.protobuf.IMBaseDefine.OfflineFileInfo buildPartial() { + com.mogujie.tt.protobuf.IMBaseDefine.OfflineFileInfo result = new com.mogujie.tt.protobuf.IMBaseDefine.OfflineFileInfo(this); + int from_bitField0_ = bitField0_; + int to_bitField0_ = 0; + if (((from_bitField0_ & 0x00000001) == 0x00000001)) { + to_bitField0_ |= 0x00000001; + } + result.fromUserId_ = fromUserId_; + if (((from_bitField0_ & 0x00000002) == 0x00000002)) { + to_bitField0_ |= 0x00000002; + } + result.taskId_ = taskId_; + if (((from_bitField0_ & 0x00000004) == 0x00000004)) { + to_bitField0_ |= 0x00000004; + } + result.fileName_ = fileName_; + if (((from_bitField0_ & 0x00000008) == 0x00000008)) { + to_bitField0_ |= 0x00000008; + } + result.fileSize_ = fileSize_; + result.bitField0_ = to_bitField0_; + return result; + } + + public Builder mergeFrom(com.mogujie.tt.protobuf.IMBaseDefine.OfflineFileInfo other) { + if (other == com.mogujie.tt.protobuf.IMBaseDefine.OfflineFileInfo.getDefaultInstance()) return this; + if (other.hasFromUserId()) { + setFromUserId(other.getFromUserId()); + } + if (other.hasTaskId()) { + bitField0_ |= 0x00000002; + taskId_ = other.taskId_; + + } + if (other.hasFileName()) { + bitField0_ |= 0x00000004; + fileName_ = other.fileName_; + + } + if (other.hasFileSize()) { + setFileSize(other.getFileSize()); + } + setUnknownFields( + getUnknownFields().concat(other.unknownFields)); + return this; + } + + public final boolean isInitialized() { + if (!hasFromUserId()) { + + return false; + } + if (!hasTaskId()) { + + return false; + } + if (!hasFileName()) { + + return false; + } + if (!hasFileSize()) { + + return false; + } + return true; + } + + public Builder mergeFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + com.mogujie.tt.protobuf.IMBaseDefine.OfflineFileInfo parsedMessage = null; + try { + parsedMessage = PARSER.parsePartialFrom(input, extensionRegistry); + } catch (com.google.protobuf.InvalidProtocolBufferException e) { + parsedMessage = (com.mogujie.tt.protobuf.IMBaseDefine.OfflineFileInfo) e.getUnfinishedMessage(); + throw e; + } finally { + if (parsedMessage != null) { + mergeFrom(parsedMessage); + } + } + return this; + } + private int bitField0_; + + private int fromUserId_ ; + /** + * required uint32 from_user_id = 1; + */ + public boolean hasFromUserId() { + return ((bitField0_ & 0x00000001) == 0x00000001); + } + /** + * required uint32 from_user_id = 1; + */ + public int getFromUserId() { + return fromUserId_; + } + /** + * required uint32 from_user_id = 1; + */ + public Builder setFromUserId(int value) { + bitField0_ |= 0x00000001; + fromUserId_ = value; + + return this; + } + /** + * required uint32 from_user_id = 1; + */ + public Builder clearFromUserId() { + bitField0_ = (bitField0_ & ~0x00000001); + fromUserId_ = 0; + + return this; + } + + private java.lang.Object taskId_ = ""; + /** + * required string task_id = 2; + */ + public boolean hasTaskId() { + return ((bitField0_ & 0x00000002) == 0x00000002); + } + /** + * required string task_id = 2; + */ + public java.lang.String getTaskId() { + java.lang.Object ref = taskId_; + if (!(ref instanceof java.lang.String)) { + com.google.protobuf.ByteString bs = + (com.google.protobuf.ByteString) ref; + java.lang.String s = bs.toStringUtf8(); + if (bs.isValidUtf8()) { + taskId_ = s; + } + return s; + } else { + return (java.lang.String) ref; + } + } + /** + * required string task_id = 2; + */ + public com.google.protobuf.ByteString + getTaskIdBytes() { + java.lang.Object ref = taskId_; + if (ref instanceof String) { + com.google.protobuf.ByteString b = + com.google.protobuf.ByteString.copyFromUtf8( + (java.lang.String) ref); + taskId_ = b; + return b; + } else { + return (com.google.protobuf.ByteString) ref; + } + } + /** + * required string task_id = 2; + */ + public Builder setTaskId( + java.lang.String value) { + if (value == null) { + throw new NullPointerException(); + } + bitField0_ |= 0x00000002; + taskId_ = value; + + return this; + } + /** + * required string task_id = 2; + */ + public Builder clearTaskId() { + bitField0_ = (bitField0_ & ~0x00000002); + taskId_ = getDefaultInstance().getTaskId(); + + return this; + } + /** + * required string task_id = 2; + */ + public Builder setTaskIdBytes( + com.google.protobuf.ByteString value) { + if (value == null) { + throw new NullPointerException(); + } + bitField0_ |= 0x00000002; + taskId_ = value; + + return this; + } + + private java.lang.Object fileName_ = ""; + /** + * required string file_name = 3; + */ + public boolean hasFileName() { + return ((bitField0_ & 0x00000004) == 0x00000004); + } + /** + * required string file_name = 3; + */ + public java.lang.String getFileName() { + java.lang.Object ref = fileName_; + if (!(ref instanceof java.lang.String)) { + com.google.protobuf.ByteString bs = + (com.google.protobuf.ByteString) ref; + java.lang.String s = bs.toStringUtf8(); + if (bs.isValidUtf8()) { + fileName_ = s; + } + return s; + } else { + return (java.lang.String) ref; + } + } + /** + * required string file_name = 3; + */ + public com.google.protobuf.ByteString + getFileNameBytes() { + java.lang.Object ref = fileName_; + if (ref instanceof String) { + com.google.protobuf.ByteString b = + com.google.protobuf.ByteString.copyFromUtf8( + (java.lang.String) ref); + fileName_ = b; + return b; + } else { + return (com.google.protobuf.ByteString) ref; + } + } + /** + * required string file_name = 3; + */ + public Builder setFileName( + java.lang.String value) { + if (value == null) { + throw new NullPointerException(); + } + bitField0_ |= 0x00000004; + fileName_ = value; + + return this; + } + /** + * required string file_name = 3; + */ + public Builder clearFileName() { + bitField0_ = (bitField0_ & ~0x00000004); + fileName_ = getDefaultInstance().getFileName(); + + return this; + } + /** + * required string file_name = 3; + */ + public Builder setFileNameBytes( + com.google.protobuf.ByteString value) { + if (value == null) { + throw new NullPointerException(); + } + bitField0_ |= 0x00000004; + fileName_ = value; + + return this; + } + + private int fileSize_ ; + /** + * required uint32 file_size = 4; + */ + public boolean hasFileSize() { + return ((bitField0_ & 0x00000008) == 0x00000008); + } + /** + * required uint32 file_size = 4; + */ + public int getFileSize() { + return fileSize_; + } + /** + * required uint32 file_size = 4; + */ + public Builder setFileSize(int value) { + bitField0_ |= 0x00000008; + fileSize_ = value; + + return this; + } + /** + * required uint32 file_size = 4; + */ + public Builder clearFileSize() { + bitField0_ = (bitField0_ & ~0x00000008); + fileSize_ = 0; + + return this; + } + + // @@protoc_insertion_point(builder_scope:IM.BaseDefine.OfflineFileInfo) + } + + static { + defaultInstance = new OfflineFileInfo(true); + defaultInstance.initFields(); + } + + // @@protoc_insertion_point(class_scope:IM.BaseDefine.OfflineFileInfo) + } + + public interface AuthInfoOrBuilder extends + // @@protoc_insertion_point(interface_extends:IM.BaseDefine.AuthInfo) + com.google.protobuf.MessageLiteOrBuilder { + + /** + * required string app_key = 1; + */ + boolean hasAppKey(); + /** + * required string app_key = 1; + */ + java.lang.String getAppKey(); + /** + * required string app_key = 1; + */ + com.google.protobuf.ByteString + getAppKeyBytes(); + + /** + * required uint32 user_id = 2; + */ + boolean hasUserId(); + /** + * required uint32 user_id = 2; + */ + int getUserId(); + + /** + * required string allowd_user_ids = 3; + */ + boolean hasAllowdUserIds(); + /** + * required string allowd_user_ids = 3; + */ + java.lang.String getAllowdUserIds(); + /** + * required string allowd_user_ids = 3; + */ + com.google.protobuf.ByteString + getAllowdUserIdsBytes(); + + /** + * required string allowd_group_ids = 4; + */ + boolean hasAllowdGroupIds(); + /** + * required string allowd_group_ids = 4; + */ + java.lang.String getAllowdGroupIds(); + /** + * required string allowd_group_ids = 4; + */ + com.google.protobuf.ByteString + getAllowdGroupIdsBytes(); + + /** + * required string auth_interfaces = 5; + */ + boolean hasAuthInterfaces(); + /** + * required string auth_interfaces = 5; + */ + java.lang.String getAuthInterfaces(); + /** + * required string auth_interfaces = 5; + */ + com.google.protobuf.ByteString + getAuthInterfacesBytes(); + + /** + * required string auth_ips = 6; + */ + boolean hasAuthIps(); + /** + * required string auth_ips = 6; + */ + java.lang.String getAuthIps(); + /** + * required string auth_ips = 6; + */ + com.google.protobuf.ByteString + getAuthIpsBytes(); + } + /** + * Protobuf type {@code IM.BaseDefine.AuthInfo} + */ + public static final class AuthInfo extends + com.google.protobuf.GeneratedMessageLite implements + // @@protoc_insertion_point(message_implements:IM.BaseDefine.AuthInfo) + AuthInfoOrBuilder { + // Use AuthInfo.newBuilder() to construct. + private AuthInfo(com.google.protobuf.GeneratedMessageLite.Builder builder) { + super(builder); + this.unknownFields = builder.getUnknownFields(); + } + private AuthInfo(boolean noInit) { this.unknownFields = com.google.protobuf.ByteString.EMPTY;} + + private static final AuthInfo defaultInstance; + public static AuthInfo getDefaultInstance() { + return defaultInstance; + } + + public AuthInfo getDefaultInstanceForType() { + return defaultInstance; + } + + private final com.google.protobuf.ByteString unknownFields; + private AuthInfo( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + initFields(); + int mutable_bitField0_ = 0; + com.google.protobuf.ByteString.Output unknownFieldsOutput = + com.google.protobuf.ByteString.newOutput(); + com.google.protobuf.CodedOutputStream unknownFieldsCodedOutput = + com.google.protobuf.CodedOutputStream.newInstance( + unknownFieldsOutput); + try { + boolean done = false; + while (!done) { + int tag = input.readTag(); + switch (tag) { + case 0: + done = true; + break; + default: { + if (!parseUnknownField(input, unknownFieldsCodedOutput, + extensionRegistry, tag)) { + done = true; + } + break; + } + case 10: { + com.google.protobuf.ByteString bs = input.readBytes(); + bitField0_ |= 0x00000001; + appKey_ = bs; + break; + } + case 16: { + bitField0_ |= 0x00000002; + userId_ = input.readUInt32(); + break; + } + case 26: { + com.google.protobuf.ByteString bs = input.readBytes(); + bitField0_ |= 0x00000004; + allowdUserIds_ = bs; + break; + } + case 34: { + com.google.protobuf.ByteString bs = input.readBytes(); + bitField0_ |= 0x00000008; + allowdGroupIds_ = bs; + break; + } + case 42: { + com.google.protobuf.ByteString bs = input.readBytes(); + bitField0_ |= 0x00000010; + authInterfaces_ = bs; + break; + } + case 50: { + com.google.protobuf.ByteString bs = input.readBytes(); + bitField0_ |= 0x00000020; + authIps_ = bs; + break; + } + } + } + } catch (com.google.protobuf.InvalidProtocolBufferException e) { + throw e.setUnfinishedMessage(this); + } catch (java.io.IOException e) { + throw new com.google.protobuf.InvalidProtocolBufferException( + e.getMessage()).setUnfinishedMessage(this); + } finally { + try { + unknownFieldsCodedOutput.flush(); + } catch (java.io.IOException e) { + // Should not happen + } finally { + unknownFields = unknownFieldsOutput.toByteString(); + } + makeExtensionsImmutable(); + } + } + public static com.google.protobuf.Parser PARSER = + new com.google.protobuf.AbstractParser() { + public AuthInfo parsePartialFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return new AuthInfo(input, extensionRegistry); + } + }; + + @java.lang.Override + public com.google.protobuf.Parser getParserForType() { + return PARSER; + } + + private int bitField0_; + public static final int APP_KEY_FIELD_NUMBER = 1; + private java.lang.Object appKey_; + /** + * required string app_key = 1; + */ + public boolean hasAppKey() { + return ((bitField0_ & 0x00000001) == 0x00000001); + } + /** + * required string app_key = 1; + */ + public java.lang.String getAppKey() { + java.lang.Object ref = appKey_; + if (ref instanceof java.lang.String) { + return (java.lang.String) ref; + } else { + com.google.protobuf.ByteString bs = + (com.google.protobuf.ByteString) ref; + java.lang.String s = bs.toStringUtf8(); + if (bs.isValidUtf8()) { + appKey_ = s; + } + return s; + } + } + /** + * required string app_key = 1; + */ + public com.google.protobuf.ByteString + getAppKeyBytes() { + java.lang.Object ref = appKey_; + if (ref instanceof java.lang.String) { + com.google.protobuf.ByteString b = + com.google.protobuf.ByteString.copyFromUtf8( + (java.lang.String) ref); + appKey_ = b; + return b; + } else { + return (com.google.protobuf.ByteString) ref; + } + } + + public static final int USER_ID_FIELD_NUMBER = 2; + private int userId_; + /** + * required uint32 user_id = 2; + */ + public boolean hasUserId() { + return ((bitField0_ & 0x00000002) == 0x00000002); + } + /** + * required uint32 user_id = 2; + */ + public int getUserId() { + return userId_; + } + + public static final int ALLOWD_USER_IDS_FIELD_NUMBER = 3; + private java.lang.Object allowdUserIds_; + /** + * required string allowd_user_ids = 3; + */ + public boolean hasAllowdUserIds() { + return ((bitField0_ & 0x00000004) == 0x00000004); + } + /** + * required string allowd_user_ids = 3; + */ + public java.lang.String getAllowdUserIds() { + java.lang.Object ref = allowdUserIds_; + if (ref instanceof java.lang.String) { + return (java.lang.String) ref; + } else { + com.google.protobuf.ByteString bs = + (com.google.protobuf.ByteString) ref; + java.lang.String s = bs.toStringUtf8(); + if (bs.isValidUtf8()) { + allowdUserIds_ = s; + } + return s; + } + } + /** + * required string allowd_user_ids = 3; + */ + public com.google.protobuf.ByteString + getAllowdUserIdsBytes() { + java.lang.Object ref = allowdUserIds_; + if (ref instanceof java.lang.String) { + com.google.protobuf.ByteString b = + com.google.protobuf.ByteString.copyFromUtf8( + (java.lang.String) ref); + allowdUserIds_ = b; + return b; + } else { + return (com.google.protobuf.ByteString) ref; + } + } + + public static final int ALLOWD_GROUP_IDS_FIELD_NUMBER = 4; + private java.lang.Object allowdGroupIds_; + /** + * required string allowd_group_ids = 4; + */ + public boolean hasAllowdGroupIds() { + return ((bitField0_ & 0x00000008) == 0x00000008); + } + /** + * required string allowd_group_ids = 4; + */ + public java.lang.String getAllowdGroupIds() { + java.lang.Object ref = allowdGroupIds_; + if (ref instanceof java.lang.String) { + return (java.lang.String) ref; + } else { + com.google.protobuf.ByteString bs = + (com.google.protobuf.ByteString) ref; + java.lang.String s = bs.toStringUtf8(); + if (bs.isValidUtf8()) { + allowdGroupIds_ = s; + } + return s; + } + } + /** + * required string allowd_group_ids = 4; + */ + public com.google.protobuf.ByteString + getAllowdGroupIdsBytes() { + java.lang.Object ref = allowdGroupIds_; + if (ref instanceof java.lang.String) { + com.google.protobuf.ByteString b = + com.google.protobuf.ByteString.copyFromUtf8( + (java.lang.String) ref); + allowdGroupIds_ = b; + return b; + } else { + return (com.google.protobuf.ByteString) ref; + } + } + + public static final int AUTH_INTERFACES_FIELD_NUMBER = 5; + private java.lang.Object authInterfaces_; + /** + * required string auth_interfaces = 5; + */ + public boolean hasAuthInterfaces() { + return ((bitField0_ & 0x00000010) == 0x00000010); + } + /** + * required string auth_interfaces = 5; + */ + public java.lang.String getAuthInterfaces() { + java.lang.Object ref = authInterfaces_; + if (ref instanceof java.lang.String) { + return (java.lang.String) ref; + } else { + com.google.protobuf.ByteString bs = + (com.google.protobuf.ByteString) ref; + java.lang.String s = bs.toStringUtf8(); + if (bs.isValidUtf8()) { + authInterfaces_ = s; + } + return s; + } + } + /** + * required string auth_interfaces = 5; + */ + public com.google.protobuf.ByteString + getAuthInterfacesBytes() { + java.lang.Object ref = authInterfaces_; + if (ref instanceof java.lang.String) { + com.google.protobuf.ByteString b = + com.google.protobuf.ByteString.copyFromUtf8( + (java.lang.String) ref); + authInterfaces_ = b; + return b; + } else { + return (com.google.protobuf.ByteString) ref; + } + } + + public static final int AUTH_IPS_FIELD_NUMBER = 6; + private java.lang.Object authIps_; + /** + * required string auth_ips = 6; + */ + public boolean hasAuthIps() { + return ((bitField0_ & 0x00000020) == 0x00000020); + } + /** + * required string auth_ips = 6; + */ + public java.lang.String getAuthIps() { + java.lang.Object ref = authIps_; + if (ref instanceof java.lang.String) { + return (java.lang.String) ref; + } else { + com.google.protobuf.ByteString bs = + (com.google.protobuf.ByteString) ref; + java.lang.String s = bs.toStringUtf8(); + if (bs.isValidUtf8()) { + authIps_ = s; + } + return s; + } + } + /** + * required string auth_ips = 6; + */ + public com.google.protobuf.ByteString + getAuthIpsBytes() { + java.lang.Object ref = authIps_; + if (ref instanceof java.lang.String) { + com.google.protobuf.ByteString b = + com.google.protobuf.ByteString.copyFromUtf8( + (java.lang.String) ref); + authIps_ = b; + return b; + } else { + return (com.google.protobuf.ByteString) ref; + } + } + + private void initFields() { + appKey_ = ""; + userId_ = 0; + allowdUserIds_ = ""; + allowdGroupIds_ = ""; + authInterfaces_ = ""; + authIps_ = ""; + } + private byte memoizedIsInitialized = -1; + public final boolean isInitialized() { + byte isInitialized = memoizedIsInitialized; + if (isInitialized == 1) return true; + if (isInitialized == 0) return false; + + if (!hasAppKey()) { + memoizedIsInitialized = 0; + return false; + } + if (!hasUserId()) { + memoizedIsInitialized = 0; + return false; + } + if (!hasAllowdUserIds()) { + memoizedIsInitialized = 0; + return false; + } + if (!hasAllowdGroupIds()) { + memoizedIsInitialized = 0; + return false; + } + if (!hasAuthInterfaces()) { + memoizedIsInitialized = 0; + return false; + } + if (!hasAuthIps()) { + memoizedIsInitialized = 0; + return false; + } + memoizedIsInitialized = 1; + return true; + } + + public void writeTo(com.google.protobuf.CodedOutputStream output) + throws java.io.IOException { + getSerializedSize(); + if (((bitField0_ & 0x00000001) == 0x00000001)) { + output.writeBytes(1, getAppKeyBytes()); + } + if (((bitField0_ & 0x00000002) == 0x00000002)) { + output.writeUInt32(2, userId_); + } + if (((bitField0_ & 0x00000004) == 0x00000004)) { + output.writeBytes(3, getAllowdUserIdsBytes()); + } + if (((bitField0_ & 0x00000008) == 0x00000008)) { + output.writeBytes(4, getAllowdGroupIdsBytes()); + } + if (((bitField0_ & 0x00000010) == 0x00000010)) { + output.writeBytes(5, getAuthInterfacesBytes()); + } + if (((bitField0_ & 0x00000020) == 0x00000020)) { + output.writeBytes(6, getAuthIpsBytes()); + } + output.writeRawBytes(unknownFields); + } + + private int memoizedSerializedSize = -1; + public int getSerializedSize() { + int size = memoizedSerializedSize; + if (size != -1) return size; + + size = 0; + if (((bitField0_ & 0x00000001) == 0x00000001)) { + size += com.google.protobuf.CodedOutputStream + .computeBytesSize(1, getAppKeyBytes()); + } + if (((bitField0_ & 0x00000002) == 0x00000002)) { + size += com.google.protobuf.CodedOutputStream + .computeUInt32Size(2, userId_); + } + if (((bitField0_ & 0x00000004) == 0x00000004)) { + size += com.google.protobuf.CodedOutputStream + .computeBytesSize(3, getAllowdUserIdsBytes()); + } + if (((bitField0_ & 0x00000008) == 0x00000008)) { + size += com.google.protobuf.CodedOutputStream + .computeBytesSize(4, getAllowdGroupIdsBytes()); + } + if (((bitField0_ & 0x00000010) == 0x00000010)) { + size += com.google.protobuf.CodedOutputStream + .computeBytesSize(5, getAuthInterfacesBytes()); + } + if (((bitField0_ & 0x00000020) == 0x00000020)) { + size += com.google.protobuf.CodedOutputStream + .computeBytesSize(6, getAuthIpsBytes()); + } + size += unknownFields.size(); + memoizedSerializedSize = size; + return size; + } + + private static final long serialVersionUID = 0L; + @java.lang.Override + protected java.lang.Object writeReplace() + throws java.io.ObjectStreamException { + return super.writeReplace(); + } + + public static com.mogujie.tt.protobuf.IMBaseDefine.AuthInfo parseFrom( + com.google.protobuf.ByteString data) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data); + } + public static com.mogujie.tt.protobuf.IMBaseDefine.AuthInfo parseFrom( + com.google.protobuf.ByteString data, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data, extensionRegistry); + } + public static com.mogujie.tt.protobuf.IMBaseDefine.AuthInfo parseFrom(byte[] data) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data); + } + public static com.mogujie.tt.protobuf.IMBaseDefine.AuthInfo parseFrom( + byte[] data, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data, extensionRegistry); + } + public static com.mogujie.tt.protobuf.IMBaseDefine.AuthInfo parseFrom(java.io.InputStream input) + throws java.io.IOException { + return PARSER.parseFrom(input); + } + public static com.mogujie.tt.protobuf.IMBaseDefine.AuthInfo parseFrom( + java.io.InputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return PARSER.parseFrom(input, extensionRegistry); + } + public static com.mogujie.tt.protobuf.IMBaseDefine.AuthInfo parseDelimitedFrom(java.io.InputStream input) + throws java.io.IOException { + return PARSER.parseDelimitedFrom(input); + } + public static com.mogujie.tt.protobuf.IMBaseDefine.AuthInfo parseDelimitedFrom( + java.io.InputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return PARSER.parseDelimitedFrom(input, extensionRegistry); + } + public static com.mogujie.tt.protobuf.IMBaseDefine.AuthInfo parseFrom( + com.google.protobuf.CodedInputStream input) + throws java.io.IOException { + return PARSER.parseFrom(input); + } + public static com.mogujie.tt.protobuf.IMBaseDefine.AuthInfo parseFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return PARSER.parseFrom(input, extensionRegistry); + } + + public static Builder newBuilder() { return Builder.create(); } + public Builder newBuilderForType() { return newBuilder(); } + public static Builder newBuilder(com.mogujie.tt.protobuf.IMBaseDefine.AuthInfo prototype) { + return newBuilder().mergeFrom(prototype); + } + public Builder toBuilder() { return newBuilder(this); } + + /** + * Protobuf type {@code IM.BaseDefine.AuthInfo} + */ + public static final class Builder extends + com.google.protobuf.GeneratedMessageLite.Builder< + com.mogujie.tt.protobuf.IMBaseDefine.AuthInfo, Builder> + implements + // @@protoc_insertion_point(builder_implements:IM.BaseDefine.AuthInfo) + com.mogujie.tt.protobuf.IMBaseDefine.AuthInfoOrBuilder { + // Construct using com.mogujie.tt.protobuf.IMBaseDefine.AuthInfo.newBuilder() + private Builder() { + maybeForceBuilderInitialization(); + } + + private void maybeForceBuilderInitialization() { + } + private static Builder create() { + return new Builder(); + } + + public Builder clear() { + super.clear(); + appKey_ = ""; + bitField0_ = (bitField0_ & ~0x00000001); + userId_ = 0; + bitField0_ = (bitField0_ & ~0x00000002); + allowdUserIds_ = ""; + bitField0_ = (bitField0_ & ~0x00000004); + allowdGroupIds_ = ""; + bitField0_ = (bitField0_ & ~0x00000008); + authInterfaces_ = ""; + bitField0_ = (bitField0_ & ~0x00000010); + authIps_ = ""; + bitField0_ = (bitField0_ & ~0x00000020); + return this; + } + + public Builder clone() { + return create().mergeFrom(buildPartial()); + } + + public com.mogujie.tt.protobuf.IMBaseDefine.AuthInfo getDefaultInstanceForType() { + return com.mogujie.tt.protobuf.IMBaseDefine.AuthInfo.getDefaultInstance(); + } + + public com.mogujie.tt.protobuf.IMBaseDefine.AuthInfo build() { + com.mogujie.tt.protobuf.IMBaseDefine.AuthInfo result = buildPartial(); + if (!result.isInitialized()) { + throw newUninitializedMessageException(result); + } + return result; + } + + public com.mogujie.tt.protobuf.IMBaseDefine.AuthInfo buildPartial() { + com.mogujie.tt.protobuf.IMBaseDefine.AuthInfo result = new com.mogujie.tt.protobuf.IMBaseDefine.AuthInfo(this); + int from_bitField0_ = bitField0_; + int to_bitField0_ = 0; + if (((from_bitField0_ & 0x00000001) == 0x00000001)) { + to_bitField0_ |= 0x00000001; + } + result.appKey_ = appKey_; + if (((from_bitField0_ & 0x00000002) == 0x00000002)) { + to_bitField0_ |= 0x00000002; + } + result.userId_ = userId_; + if (((from_bitField0_ & 0x00000004) == 0x00000004)) { + to_bitField0_ |= 0x00000004; + } + result.allowdUserIds_ = allowdUserIds_; + if (((from_bitField0_ & 0x00000008) == 0x00000008)) { + to_bitField0_ |= 0x00000008; + } + result.allowdGroupIds_ = allowdGroupIds_; + if (((from_bitField0_ & 0x00000010) == 0x00000010)) { + to_bitField0_ |= 0x00000010; + } + result.authInterfaces_ = authInterfaces_; + if (((from_bitField0_ & 0x00000020) == 0x00000020)) { + to_bitField0_ |= 0x00000020; + } + result.authIps_ = authIps_; + result.bitField0_ = to_bitField0_; + return result; + } + + public Builder mergeFrom(com.mogujie.tt.protobuf.IMBaseDefine.AuthInfo other) { + if (other == com.mogujie.tt.protobuf.IMBaseDefine.AuthInfo.getDefaultInstance()) return this; + if (other.hasAppKey()) { + bitField0_ |= 0x00000001; + appKey_ = other.appKey_; + + } + if (other.hasUserId()) { + setUserId(other.getUserId()); + } + if (other.hasAllowdUserIds()) { + bitField0_ |= 0x00000004; + allowdUserIds_ = other.allowdUserIds_; + + } + if (other.hasAllowdGroupIds()) { + bitField0_ |= 0x00000008; + allowdGroupIds_ = other.allowdGroupIds_; + + } + if (other.hasAuthInterfaces()) { + bitField0_ |= 0x00000010; + authInterfaces_ = other.authInterfaces_; + + } + if (other.hasAuthIps()) { + bitField0_ |= 0x00000020; + authIps_ = other.authIps_; + + } + setUnknownFields( + getUnknownFields().concat(other.unknownFields)); + return this; + } + + public final boolean isInitialized() { + if (!hasAppKey()) { + + return false; + } + if (!hasUserId()) { + + return false; + } + if (!hasAllowdUserIds()) { + + return false; + } + if (!hasAllowdGroupIds()) { + + return false; + } + if (!hasAuthInterfaces()) { + + return false; + } + if (!hasAuthIps()) { + + return false; + } + return true; + } + + public Builder mergeFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + com.mogujie.tt.protobuf.IMBaseDefine.AuthInfo parsedMessage = null; + try { + parsedMessage = PARSER.parsePartialFrom(input, extensionRegistry); + } catch (com.google.protobuf.InvalidProtocolBufferException e) { + parsedMessage = (com.mogujie.tt.protobuf.IMBaseDefine.AuthInfo) e.getUnfinishedMessage(); + throw e; + } finally { + if (parsedMessage != null) { + mergeFrom(parsedMessage); + } + } + return this; + } + private int bitField0_; + + private java.lang.Object appKey_ = ""; + /** + * required string app_key = 1; + */ + public boolean hasAppKey() { + return ((bitField0_ & 0x00000001) == 0x00000001); + } + /** + * required string app_key = 1; + */ + public java.lang.String getAppKey() { + java.lang.Object ref = appKey_; + if (!(ref instanceof java.lang.String)) { + com.google.protobuf.ByteString bs = + (com.google.protobuf.ByteString) ref; + java.lang.String s = bs.toStringUtf8(); + if (bs.isValidUtf8()) { + appKey_ = s; + } + return s; + } else { + return (java.lang.String) ref; + } + } + /** + * required string app_key = 1; + */ + public com.google.protobuf.ByteString + getAppKeyBytes() { + java.lang.Object ref = appKey_; + if (ref instanceof String) { + com.google.protobuf.ByteString b = + com.google.protobuf.ByteString.copyFromUtf8( + (java.lang.String) ref); + appKey_ = b; + return b; + } else { + return (com.google.protobuf.ByteString) ref; + } + } + /** + * required string app_key = 1; + */ + public Builder setAppKey( + java.lang.String value) { + if (value == null) { + throw new NullPointerException(); + } + bitField0_ |= 0x00000001; + appKey_ = value; + + return this; + } + /** + * required string app_key = 1; + */ + public Builder clearAppKey() { + bitField0_ = (bitField0_ & ~0x00000001); + appKey_ = getDefaultInstance().getAppKey(); + + return this; + } + /** + * required string app_key = 1; + */ + public Builder setAppKeyBytes( + com.google.protobuf.ByteString value) { + if (value == null) { + throw new NullPointerException(); + } + bitField0_ |= 0x00000001; + appKey_ = value; + + return this; + } + + private int userId_ ; + /** + * required uint32 user_id = 2; + */ + public boolean hasUserId() { + return ((bitField0_ & 0x00000002) == 0x00000002); + } + /** + * required uint32 user_id = 2; + */ + public int getUserId() { + return userId_; + } + /** + * required uint32 user_id = 2; + */ + public Builder setUserId(int value) { + bitField0_ |= 0x00000002; + userId_ = value; + + return this; + } + /** + * required uint32 user_id = 2; + */ + public Builder clearUserId() { + bitField0_ = (bitField0_ & ~0x00000002); + userId_ = 0; + + return this; + } + + private java.lang.Object allowdUserIds_ = ""; + /** + * required string allowd_user_ids = 3; + */ + public boolean hasAllowdUserIds() { + return ((bitField0_ & 0x00000004) == 0x00000004); + } + /** + * required string allowd_user_ids = 3; + */ + public java.lang.String getAllowdUserIds() { + java.lang.Object ref = allowdUserIds_; + if (!(ref instanceof java.lang.String)) { + com.google.protobuf.ByteString bs = + (com.google.protobuf.ByteString) ref; + java.lang.String s = bs.toStringUtf8(); + if (bs.isValidUtf8()) { + allowdUserIds_ = s; + } + return s; + } else { + return (java.lang.String) ref; + } + } + /** + * required string allowd_user_ids = 3; + */ + public com.google.protobuf.ByteString + getAllowdUserIdsBytes() { + java.lang.Object ref = allowdUserIds_; + if (ref instanceof String) { + com.google.protobuf.ByteString b = + com.google.protobuf.ByteString.copyFromUtf8( + (java.lang.String) ref); + allowdUserIds_ = b; + return b; + } else { + return (com.google.protobuf.ByteString) ref; + } + } + /** + * required string allowd_user_ids = 3; + */ + public Builder setAllowdUserIds( + java.lang.String value) { + if (value == null) { + throw new NullPointerException(); + } + bitField0_ |= 0x00000004; + allowdUserIds_ = value; + + return this; + } + /** + * required string allowd_user_ids = 3; + */ + public Builder clearAllowdUserIds() { + bitField0_ = (bitField0_ & ~0x00000004); + allowdUserIds_ = getDefaultInstance().getAllowdUserIds(); + + return this; + } + /** + * required string allowd_user_ids = 3; + */ + public Builder setAllowdUserIdsBytes( + com.google.protobuf.ByteString value) { + if (value == null) { + throw new NullPointerException(); + } + bitField0_ |= 0x00000004; + allowdUserIds_ = value; + + return this; + } + + private java.lang.Object allowdGroupIds_ = ""; + /** + * required string allowd_group_ids = 4; + */ + public boolean hasAllowdGroupIds() { + return ((bitField0_ & 0x00000008) == 0x00000008); + } + /** + * required string allowd_group_ids = 4; + */ + public java.lang.String getAllowdGroupIds() { + java.lang.Object ref = allowdGroupIds_; + if (!(ref instanceof java.lang.String)) { + com.google.protobuf.ByteString bs = + (com.google.protobuf.ByteString) ref; + java.lang.String s = bs.toStringUtf8(); + if (bs.isValidUtf8()) { + allowdGroupIds_ = s; + } + return s; + } else { + return (java.lang.String) ref; + } + } + /** + * required string allowd_group_ids = 4; + */ + public com.google.protobuf.ByteString + getAllowdGroupIdsBytes() { + java.lang.Object ref = allowdGroupIds_; + if (ref instanceof String) { + com.google.protobuf.ByteString b = + com.google.protobuf.ByteString.copyFromUtf8( + (java.lang.String) ref); + allowdGroupIds_ = b; + return b; + } else { + return (com.google.protobuf.ByteString) ref; + } + } + /** + * required string allowd_group_ids = 4; + */ + public Builder setAllowdGroupIds( + java.lang.String value) { + if (value == null) { + throw new NullPointerException(); + } + bitField0_ |= 0x00000008; + allowdGroupIds_ = value; + + return this; + } + /** + * required string allowd_group_ids = 4; + */ + public Builder clearAllowdGroupIds() { + bitField0_ = (bitField0_ & ~0x00000008); + allowdGroupIds_ = getDefaultInstance().getAllowdGroupIds(); + + return this; + } + /** + * required string allowd_group_ids = 4; + */ + public Builder setAllowdGroupIdsBytes( + com.google.protobuf.ByteString value) { + if (value == null) { + throw new NullPointerException(); + } + bitField0_ |= 0x00000008; + allowdGroupIds_ = value; + + return this; + } + + private java.lang.Object authInterfaces_ = ""; + /** + * required string auth_interfaces = 5; + */ + public boolean hasAuthInterfaces() { + return ((bitField0_ & 0x00000010) == 0x00000010); + } + /** + * required string auth_interfaces = 5; + */ + public java.lang.String getAuthInterfaces() { + java.lang.Object ref = authInterfaces_; + if (!(ref instanceof java.lang.String)) { + com.google.protobuf.ByteString bs = + (com.google.protobuf.ByteString) ref; + java.lang.String s = bs.toStringUtf8(); + if (bs.isValidUtf8()) { + authInterfaces_ = s; + } + return s; + } else { + return (java.lang.String) ref; + } + } + /** + * required string auth_interfaces = 5; + */ + public com.google.protobuf.ByteString + getAuthInterfacesBytes() { + java.lang.Object ref = authInterfaces_; + if (ref instanceof String) { + com.google.protobuf.ByteString b = + com.google.protobuf.ByteString.copyFromUtf8( + (java.lang.String) ref); + authInterfaces_ = b; + return b; + } else { + return (com.google.protobuf.ByteString) ref; + } + } + /** + * required string auth_interfaces = 5; + */ + public Builder setAuthInterfaces( + java.lang.String value) { + if (value == null) { + throw new NullPointerException(); + } + bitField0_ |= 0x00000010; + authInterfaces_ = value; + + return this; + } + /** + * required string auth_interfaces = 5; + */ + public Builder clearAuthInterfaces() { + bitField0_ = (bitField0_ & ~0x00000010); + authInterfaces_ = getDefaultInstance().getAuthInterfaces(); + + return this; + } + /** + * required string auth_interfaces = 5; + */ + public Builder setAuthInterfacesBytes( + com.google.protobuf.ByteString value) { + if (value == null) { + throw new NullPointerException(); + } + bitField0_ |= 0x00000010; + authInterfaces_ = value; + + return this; + } + + private java.lang.Object authIps_ = ""; + /** + * required string auth_ips = 6; + */ + public boolean hasAuthIps() { + return ((bitField0_ & 0x00000020) == 0x00000020); + } + /** + * required string auth_ips = 6; + */ + public java.lang.String getAuthIps() { + java.lang.Object ref = authIps_; + if (!(ref instanceof java.lang.String)) { + com.google.protobuf.ByteString bs = + (com.google.protobuf.ByteString) ref; + java.lang.String s = bs.toStringUtf8(); + if (bs.isValidUtf8()) { + authIps_ = s; + } + return s; + } else { + return (java.lang.String) ref; + } + } + /** + * required string auth_ips = 6; + */ + public com.google.protobuf.ByteString + getAuthIpsBytes() { + java.lang.Object ref = authIps_; + if (ref instanceof String) { + com.google.protobuf.ByteString b = + com.google.protobuf.ByteString.copyFromUtf8( + (java.lang.String) ref); + authIps_ = b; + return b; + } else { + return (com.google.protobuf.ByteString) ref; + } + } + /** + * required string auth_ips = 6; + */ + public Builder setAuthIps( + java.lang.String value) { + if (value == null) { + throw new NullPointerException(); + } + bitField0_ |= 0x00000020; + authIps_ = value; + + return this; + } + /** + * required string auth_ips = 6; + */ + public Builder clearAuthIps() { + bitField0_ = (bitField0_ & ~0x00000020); + authIps_ = getDefaultInstance().getAuthIps(); + + return this; + } + /** + * required string auth_ips = 6; + */ + public Builder setAuthIpsBytes( + com.google.protobuf.ByteString value) { + if (value == null) { + throw new NullPointerException(); + } + bitField0_ |= 0x00000020; + authIps_ = value; + + return this; + } + + // @@protoc_insertion_point(builder_scope:IM.BaseDefine.AuthInfo) + } + + static { + defaultInstance = new AuthInfo(true); + defaultInstance.initFields(); + } + + // @@protoc_insertion_point(class_scope:IM.BaseDefine.AuthInfo) + } + + public interface DepartInfoOrBuilder extends + // @@protoc_insertion_point(interface_extends:IM.BaseDefine.DepartInfo) + com.google.protobuf.MessageLiteOrBuilder { + + /** + * required uint32 dept_id = 1; + */ + boolean hasDeptId(); + /** + * required uint32 dept_id = 1; + */ + int getDeptId(); + + /** + * required uint32 priority = 2; + */ + boolean hasPriority(); + /** + * required uint32 priority = 2; + */ + int getPriority(); + + /** + * required string dept_name = 3; + */ + boolean hasDeptName(); + /** + * required string dept_name = 3; + */ + java.lang.String getDeptName(); + /** + * required string dept_name = 3; + */ + com.google.protobuf.ByteString + getDeptNameBytes(); + + /** + * required uint32 parent_dept_id = 4; + */ + boolean hasParentDeptId(); + /** + * required uint32 parent_dept_id = 4; + */ + int getParentDeptId(); + + /** + * required .IM.BaseDefine.DepartmentStatusType dept_status = 5; + */ + boolean hasDeptStatus(); + /** + * required .IM.BaseDefine.DepartmentStatusType dept_status = 5; + */ + com.mogujie.tt.protobuf.IMBaseDefine.DepartmentStatusType getDeptStatus(); + } + /** + * Protobuf type {@code IM.BaseDefine.DepartInfo} + */ + public static final class DepartInfo extends + com.google.protobuf.GeneratedMessageLite implements + // @@protoc_insertion_point(message_implements:IM.BaseDefine.DepartInfo) + DepartInfoOrBuilder { + // Use DepartInfo.newBuilder() to construct. + private DepartInfo(com.google.protobuf.GeneratedMessageLite.Builder builder) { + super(builder); + this.unknownFields = builder.getUnknownFields(); + } + private DepartInfo(boolean noInit) { this.unknownFields = com.google.protobuf.ByteString.EMPTY;} + + private static final DepartInfo defaultInstance; + public static DepartInfo getDefaultInstance() { + return defaultInstance; + } + + public DepartInfo getDefaultInstanceForType() { + return defaultInstance; + } + + private final com.google.protobuf.ByteString unknownFields; + private DepartInfo( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + initFields(); + int mutable_bitField0_ = 0; + com.google.protobuf.ByteString.Output unknownFieldsOutput = + com.google.protobuf.ByteString.newOutput(); + com.google.protobuf.CodedOutputStream unknownFieldsCodedOutput = + com.google.protobuf.CodedOutputStream.newInstance( + unknownFieldsOutput); + try { + boolean done = false; + while (!done) { + int tag = input.readTag(); + switch (tag) { + case 0: + done = true; + break; + default: { + if (!parseUnknownField(input, unknownFieldsCodedOutput, + extensionRegistry, tag)) { + done = true; + } + break; + } + case 8: { + bitField0_ |= 0x00000001; + deptId_ = input.readUInt32(); + break; + } + case 16: { + bitField0_ |= 0x00000002; + priority_ = input.readUInt32(); + break; + } + case 26: { + com.google.protobuf.ByteString bs = input.readBytes(); + bitField0_ |= 0x00000004; + deptName_ = bs; + break; + } + case 32: { + bitField0_ |= 0x00000008; + parentDeptId_ = input.readUInt32(); + break; + } + case 40: { + int rawValue = input.readEnum(); + com.mogujie.tt.protobuf.IMBaseDefine.DepartmentStatusType value = com.mogujie.tt.protobuf.IMBaseDefine.DepartmentStatusType.valueOf(rawValue); + if (value == null) { + unknownFieldsCodedOutput.writeRawVarint32(tag); + unknownFieldsCodedOutput.writeRawVarint32(rawValue); + } else { + bitField0_ |= 0x00000010; + deptStatus_ = value; + } + break; + } + } + } + } catch (com.google.protobuf.InvalidProtocolBufferException e) { + throw e.setUnfinishedMessage(this); + } catch (java.io.IOException e) { + throw new com.google.protobuf.InvalidProtocolBufferException( + e.getMessage()).setUnfinishedMessage(this); + } finally { + try { + unknownFieldsCodedOutput.flush(); + } catch (java.io.IOException e) { + // Should not happen + } finally { + unknownFields = unknownFieldsOutput.toByteString(); + } + makeExtensionsImmutable(); + } + } + public static com.google.protobuf.Parser PARSER = + new com.google.protobuf.AbstractParser() { + public DepartInfo parsePartialFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return new DepartInfo(input, extensionRegistry); + } + }; + + @java.lang.Override + public com.google.protobuf.Parser getParserForType() { + return PARSER; + } + + private int bitField0_; + public static final int DEPT_ID_FIELD_NUMBER = 1; + private int deptId_; + /** + * required uint32 dept_id = 1; + */ + public boolean hasDeptId() { + return ((bitField0_ & 0x00000001) == 0x00000001); + } + /** + * required uint32 dept_id = 1; + */ + public int getDeptId() { + return deptId_; + } + + public static final int PRIORITY_FIELD_NUMBER = 2; + private int priority_; + /** + * required uint32 priority = 2; + */ + public boolean hasPriority() { + return ((bitField0_ & 0x00000002) == 0x00000002); + } + /** + * required uint32 priority = 2; + */ + public int getPriority() { + return priority_; + } + + public static final int DEPT_NAME_FIELD_NUMBER = 3; + private java.lang.Object deptName_; + /** + * required string dept_name = 3; + */ + public boolean hasDeptName() { + return ((bitField0_ & 0x00000004) == 0x00000004); + } + /** + * required string dept_name = 3; + */ + public java.lang.String getDeptName() { + java.lang.Object ref = deptName_; + if (ref instanceof java.lang.String) { + return (java.lang.String) ref; + } else { + com.google.protobuf.ByteString bs = + (com.google.protobuf.ByteString) ref; + java.lang.String s = bs.toStringUtf8(); + if (bs.isValidUtf8()) { + deptName_ = s; + } + return s; + } + } + /** + * required string dept_name = 3; + */ + public com.google.protobuf.ByteString + getDeptNameBytes() { + java.lang.Object ref = deptName_; + if (ref instanceof java.lang.String) { + com.google.protobuf.ByteString b = + com.google.protobuf.ByteString.copyFromUtf8( + (java.lang.String) ref); + deptName_ = b; + return b; + } else { + return (com.google.protobuf.ByteString) ref; + } + } + + public static final int PARENT_DEPT_ID_FIELD_NUMBER = 4; + private int parentDeptId_; + /** + * required uint32 parent_dept_id = 4; + */ + public boolean hasParentDeptId() { + return ((bitField0_ & 0x00000008) == 0x00000008); + } + /** + * required uint32 parent_dept_id = 4; + */ + public int getParentDeptId() { + return parentDeptId_; + } + + public static final int DEPT_STATUS_FIELD_NUMBER = 5; + private com.mogujie.tt.protobuf.IMBaseDefine.DepartmentStatusType deptStatus_; + /** + * required .IM.BaseDefine.DepartmentStatusType dept_status = 5; + */ + public boolean hasDeptStatus() { + return ((bitField0_ & 0x00000010) == 0x00000010); + } + /** + * required .IM.BaseDefine.DepartmentStatusType dept_status = 5; + */ + public com.mogujie.tt.protobuf.IMBaseDefine.DepartmentStatusType getDeptStatus() { + return deptStatus_; + } + + private void initFields() { + deptId_ = 0; + priority_ = 0; + deptName_ = ""; + parentDeptId_ = 0; + deptStatus_ = com.mogujie.tt.protobuf.IMBaseDefine.DepartmentStatusType.DEPT_STATUS_OK; + } + private byte memoizedIsInitialized = -1; + public final boolean isInitialized() { + byte isInitialized = memoizedIsInitialized; + if (isInitialized == 1) return true; + if (isInitialized == 0) return false; + + if (!hasDeptId()) { + memoizedIsInitialized = 0; + return false; + } + if (!hasPriority()) { + memoizedIsInitialized = 0; + return false; + } + if (!hasDeptName()) { + memoizedIsInitialized = 0; + return false; + } + if (!hasParentDeptId()) { + memoizedIsInitialized = 0; + return false; + } + if (!hasDeptStatus()) { + memoizedIsInitialized = 0; + return false; + } + memoizedIsInitialized = 1; + return true; + } + + public void writeTo(com.google.protobuf.CodedOutputStream output) + throws java.io.IOException { + getSerializedSize(); + if (((bitField0_ & 0x00000001) == 0x00000001)) { + output.writeUInt32(1, deptId_); + } + if (((bitField0_ & 0x00000002) == 0x00000002)) { + output.writeUInt32(2, priority_); + } + if (((bitField0_ & 0x00000004) == 0x00000004)) { + output.writeBytes(3, getDeptNameBytes()); + } + if (((bitField0_ & 0x00000008) == 0x00000008)) { + output.writeUInt32(4, parentDeptId_); + } + if (((bitField0_ & 0x00000010) == 0x00000010)) { + output.writeEnum(5, deptStatus_.getNumber()); + } + output.writeRawBytes(unknownFields); + } + + private int memoizedSerializedSize = -1; + public int getSerializedSize() { + int size = memoizedSerializedSize; + if (size != -1) return size; + + size = 0; + if (((bitField0_ & 0x00000001) == 0x00000001)) { + size += com.google.protobuf.CodedOutputStream + .computeUInt32Size(1, deptId_); + } + if (((bitField0_ & 0x00000002) == 0x00000002)) { + size += com.google.protobuf.CodedOutputStream + .computeUInt32Size(2, priority_); + } + if (((bitField0_ & 0x00000004) == 0x00000004)) { + size += com.google.protobuf.CodedOutputStream + .computeBytesSize(3, getDeptNameBytes()); + } + if (((bitField0_ & 0x00000008) == 0x00000008)) { + size += com.google.protobuf.CodedOutputStream + .computeUInt32Size(4, parentDeptId_); + } + if (((bitField0_ & 0x00000010) == 0x00000010)) { + size += com.google.protobuf.CodedOutputStream + .computeEnumSize(5, deptStatus_.getNumber()); + } + size += unknownFields.size(); + memoizedSerializedSize = size; + return size; + } + + private static final long serialVersionUID = 0L; + @java.lang.Override + protected java.lang.Object writeReplace() + throws java.io.ObjectStreamException { + return super.writeReplace(); + } + + public static com.mogujie.tt.protobuf.IMBaseDefine.DepartInfo parseFrom( + com.google.protobuf.ByteString data) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data); + } + public static com.mogujie.tt.protobuf.IMBaseDefine.DepartInfo parseFrom( + com.google.protobuf.ByteString data, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data, extensionRegistry); + } + public static com.mogujie.tt.protobuf.IMBaseDefine.DepartInfo parseFrom(byte[] data) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data); + } + public static com.mogujie.tt.protobuf.IMBaseDefine.DepartInfo parseFrom( + byte[] data, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data, extensionRegistry); + } + public static com.mogujie.tt.protobuf.IMBaseDefine.DepartInfo parseFrom(java.io.InputStream input) + throws java.io.IOException { + return PARSER.parseFrom(input); + } + public static com.mogujie.tt.protobuf.IMBaseDefine.DepartInfo parseFrom( + java.io.InputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return PARSER.parseFrom(input, extensionRegistry); + } + public static com.mogujie.tt.protobuf.IMBaseDefine.DepartInfo parseDelimitedFrom(java.io.InputStream input) + throws java.io.IOException { + return PARSER.parseDelimitedFrom(input); + } + public static com.mogujie.tt.protobuf.IMBaseDefine.DepartInfo parseDelimitedFrom( + java.io.InputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return PARSER.parseDelimitedFrom(input, extensionRegistry); + } + public static com.mogujie.tt.protobuf.IMBaseDefine.DepartInfo parseFrom( + com.google.protobuf.CodedInputStream input) + throws java.io.IOException { + return PARSER.parseFrom(input); + } + public static com.mogujie.tt.protobuf.IMBaseDefine.DepartInfo parseFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return PARSER.parseFrom(input, extensionRegistry); + } + + public static Builder newBuilder() { return Builder.create(); } + public Builder newBuilderForType() { return newBuilder(); } + public static Builder newBuilder(com.mogujie.tt.protobuf.IMBaseDefine.DepartInfo prototype) { + return newBuilder().mergeFrom(prototype); + } + public Builder toBuilder() { return newBuilder(this); } + + /** + * Protobuf type {@code IM.BaseDefine.DepartInfo} + */ + public static final class Builder extends + com.google.protobuf.GeneratedMessageLite.Builder< + com.mogujie.tt.protobuf.IMBaseDefine.DepartInfo, Builder> + implements + // @@protoc_insertion_point(builder_implements:IM.BaseDefine.DepartInfo) + com.mogujie.tt.protobuf.IMBaseDefine.DepartInfoOrBuilder { + // Construct using com.mogujie.tt.protobuf.IMBaseDefine.DepartInfo.newBuilder() + private Builder() { + maybeForceBuilderInitialization(); + } + + private void maybeForceBuilderInitialization() { + } + private static Builder create() { + return new Builder(); + } + + public Builder clear() { + super.clear(); + deptId_ = 0; + bitField0_ = (bitField0_ & ~0x00000001); + priority_ = 0; + bitField0_ = (bitField0_ & ~0x00000002); + deptName_ = ""; + bitField0_ = (bitField0_ & ~0x00000004); + parentDeptId_ = 0; + bitField0_ = (bitField0_ & ~0x00000008); + deptStatus_ = com.mogujie.tt.protobuf.IMBaseDefine.DepartmentStatusType.DEPT_STATUS_OK; + bitField0_ = (bitField0_ & ~0x00000010); + return this; + } + + public Builder clone() { + return create().mergeFrom(buildPartial()); + } + + public com.mogujie.tt.protobuf.IMBaseDefine.DepartInfo getDefaultInstanceForType() { + return com.mogujie.tt.protobuf.IMBaseDefine.DepartInfo.getDefaultInstance(); + } + + public com.mogujie.tt.protobuf.IMBaseDefine.DepartInfo build() { + com.mogujie.tt.protobuf.IMBaseDefine.DepartInfo result = buildPartial(); + if (!result.isInitialized()) { + throw newUninitializedMessageException(result); + } + return result; + } + + public com.mogujie.tt.protobuf.IMBaseDefine.DepartInfo buildPartial() { + com.mogujie.tt.protobuf.IMBaseDefine.DepartInfo result = new com.mogujie.tt.protobuf.IMBaseDefine.DepartInfo(this); + int from_bitField0_ = bitField0_; + int to_bitField0_ = 0; + if (((from_bitField0_ & 0x00000001) == 0x00000001)) { + to_bitField0_ |= 0x00000001; + } + result.deptId_ = deptId_; + if (((from_bitField0_ & 0x00000002) == 0x00000002)) { + to_bitField0_ |= 0x00000002; + } + result.priority_ = priority_; + if (((from_bitField0_ & 0x00000004) == 0x00000004)) { + to_bitField0_ |= 0x00000004; + } + result.deptName_ = deptName_; + if (((from_bitField0_ & 0x00000008) == 0x00000008)) { + to_bitField0_ |= 0x00000008; + } + result.parentDeptId_ = parentDeptId_; + if (((from_bitField0_ & 0x00000010) == 0x00000010)) { + to_bitField0_ |= 0x00000010; + } + result.deptStatus_ = deptStatus_; + result.bitField0_ = to_bitField0_; + return result; + } + + public Builder mergeFrom(com.mogujie.tt.protobuf.IMBaseDefine.DepartInfo other) { + if (other == com.mogujie.tt.protobuf.IMBaseDefine.DepartInfo.getDefaultInstance()) return this; + if (other.hasDeptId()) { + setDeptId(other.getDeptId()); + } + if (other.hasPriority()) { + setPriority(other.getPriority()); + } + if (other.hasDeptName()) { + bitField0_ |= 0x00000004; + deptName_ = other.deptName_; + + } + if (other.hasParentDeptId()) { + setParentDeptId(other.getParentDeptId()); + } + if (other.hasDeptStatus()) { + setDeptStatus(other.getDeptStatus()); + } + setUnknownFields( + getUnknownFields().concat(other.unknownFields)); + return this; + } + + public final boolean isInitialized() { + if (!hasDeptId()) { + + return false; + } + if (!hasPriority()) { + + return false; + } + if (!hasDeptName()) { + + return false; + } + if (!hasParentDeptId()) { + + return false; + } + if (!hasDeptStatus()) { + + return false; + } + return true; + } + + public Builder mergeFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + com.mogujie.tt.protobuf.IMBaseDefine.DepartInfo parsedMessage = null; + try { + parsedMessage = PARSER.parsePartialFrom(input, extensionRegistry); + } catch (com.google.protobuf.InvalidProtocolBufferException e) { + parsedMessage = (com.mogujie.tt.protobuf.IMBaseDefine.DepartInfo) e.getUnfinishedMessage(); + throw e; + } finally { + if (parsedMessage != null) { + mergeFrom(parsedMessage); + } + } + return this; + } + private int bitField0_; + + private int deptId_ ; + /** + * required uint32 dept_id = 1; + */ + public boolean hasDeptId() { + return ((bitField0_ & 0x00000001) == 0x00000001); + } + /** + * required uint32 dept_id = 1; + */ + public int getDeptId() { + return deptId_; + } + /** + * required uint32 dept_id = 1; + */ + public Builder setDeptId(int value) { + bitField0_ |= 0x00000001; + deptId_ = value; + + return this; + } + /** + * required uint32 dept_id = 1; + */ + public Builder clearDeptId() { + bitField0_ = (bitField0_ & ~0x00000001); + deptId_ = 0; + + return this; + } + + private int priority_ ; + /** + * required uint32 priority = 2; + */ + public boolean hasPriority() { + return ((bitField0_ & 0x00000002) == 0x00000002); + } + /** + * required uint32 priority = 2; + */ + public int getPriority() { + return priority_; + } + /** + * required uint32 priority = 2; + */ + public Builder setPriority(int value) { + bitField0_ |= 0x00000002; + priority_ = value; + + return this; + } + /** + * required uint32 priority = 2; + */ + public Builder clearPriority() { + bitField0_ = (bitField0_ & ~0x00000002); + priority_ = 0; + + return this; + } + + private java.lang.Object deptName_ = ""; + /** + * required string dept_name = 3; + */ + public boolean hasDeptName() { + return ((bitField0_ & 0x00000004) == 0x00000004); + } + /** + * required string dept_name = 3; + */ + public java.lang.String getDeptName() { + java.lang.Object ref = deptName_; + if (!(ref instanceof java.lang.String)) { + com.google.protobuf.ByteString bs = + (com.google.protobuf.ByteString) ref; + java.lang.String s = bs.toStringUtf8(); + if (bs.isValidUtf8()) { + deptName_ = s; + } + return s; + } else { + return (java.lang.String) ref; + } + } + /** + * required string dept_name = 3; + */ + public com.google.protobuf.ByteString + getDeptNameBytes() { + java.lang.Object ref = deptName_; + if (ref instanceof String) { + com.google.protobuf.ByteString b = + com.google.protobuf.ByteString.copyFromUtf8( + (java.lang.String) ref); + deptName_ = b; + return b; + } else { + return (com.google.protobuf.ByteString) ref; + } + } + /** + * required string dept_name = 3; + */ + public Builder setDeptName( + java.lang.String value) { + if (value == null) { + throw new NullPointerException(); + } + bitField0_ |= 0x00000004; + deptName_ = value; + + return this; + } + /** + * required string dept_name = 3; + */ + public Builder clearDeptName() { + bitField0_ = (bitField0_ & ~0x00000004); + deptName_ = getDefaultInstance().getDeptName(); + + return this; + } + /** + * required string dept_name = 3; + */ + public Builder setDeptNameBytes( + com.google.protobuf.ByteString value) { + if (value == null) { + throw new NullPointerException(); + } + bitField0_ |= 0x00000004; + deptName_ = value; + + return this; + } + + private int parentDeptId_ ; + /** + * required uint32 parent_dept_id = 4; + */ + public boolean hasParentDeptId() { + return ((bitField0_ & 0x00000008) == 0x00000008); + } + /** + * required uint32 parent_dept_id = 4; + */ + public int getParentDeptId() { + return parentDeptId_; + } + /** + * required uint32 parent_dept_id = 4; + */ + public Builder setParentDeptId(int value) { + bitField0_ |= 0x00000008; + parentDeptId_ = value; + + return this; + } + /** + * required uint32 parent_dept_id = 4; + */ + public Builder clearParentDeptId() { + bitField0_ = (bitField0_ & ~0x00000008); + parentDeptId_ = 0; + + return this; + } + + private com.mogujie.tt.protobuf.IMBaseDefine.DepartmentStatusType deptStatus_ = com.mogujie.tt.protobuf.IMBaseDefine.DepartmentStatusType.DEPT_STATUS_OK; + /** + * required .IM.BaseDefine.DepartmentStatusType dept_status = 5; + */ + public boolean hasDeptStatus() { + return ((bitField0_ & 0x00000010) == 0x00000010); + } + /** + * required .IM.BaseDefine.DepartmentStatusType dept_status = 5; + */ + public com.mogujie.tt.protobuf.IMBaseDefine.DepartmentStatusType getDeptStatus() { + return deptStatus_; + } + /** + * required .IM.BaseDefine.DepartmentStatusType dept_status = 5; + */ + public Builder setDeptStatus(com.mogujie.tt.protobuf.IMBaseDefine.DepartmentStatusType value) { + if (value == null) { + throw new NullPointerException(); + } + bitField0_ |= 0x00000010; + deptStatus_ = value; + + return this; + } + /** + * required .IM.BaseDefine.DepartmentStatusType dept_status = 5; + */ + public Builder clearDeptStatus() { + bitField0_ = (bitField0_ & ~0x00000010); + deptStatus_ = com.mogujie.tt.protobuf.IMBaseDefine.DepartmentStatusType.DEPT_STATUS_OK; + + return this; + } + + // @@protoc_insertion_point(builder_scope:IM.BaseDefine.DepartInfo) + } + + static { + defaultInstance = new DepartInfo(true); + defaultInstance.initFields(); + } + + // @@protoc_insertion_point(class_scope:IM.BaseDefine.DepartInfo) + } + + + static { + } + + // @@protoc_insertion_point(outer_class_scope) +} diff --git a/android/app/src/main/java/com/mogujie/tt/protobuf/IMBuddy.java b/android/app/src/main/java/com/mogujie/tt/protobuf/IMBuddy.java new file mode 100644 index 000000000..c3bb67045 --- /dev/null +++ b/android/app/src/main/java/com/mogujie/tt/protobuf/IMBuddy.java @@ -0,0 +1,10703 @@ +// Generated by the protocol buffer compiler. DO NOT EDIT! +// source: IM.Buddy.proto + +package com.mogujie.tt.protobuf; + +public final class IMBuddy { + private IMBuddy() {} + public static void registerAllExtensions( + com.google.protobuf.ExtensionRegistryLite registry) { + } + public interface IMRecentContactSessionReqOrBuilder extends + // @@protoc_insertion_point(interface_extends:IM.Buddy.IMRecentContactSessionReq) + com.google.protobuf.MessageLiteOrBuilder { + + /** + * required uint32 user_id = 1; + * + *
+     *cmd id:		0x0201
+     * 
+ */ + boolean hasUserId(); + /** + * required uint32 user_id = 1; + * + *
+     *cmd id:		0x0201
+     * 
+ */ + int getUserId(); + + /** + * required uint32 latest_update_time = 2; + */ + boolean hasLatestUpdateTime(); + /** + * required uint32 latest_update_time = 2; + */ + int getLatestUpdateTime(); + + /** + * optional bytes attach_data = 20; + */ + boolean hasAttachData(); + /** + * optional bytes attach_data = 20; + */ + com.google.protobuf.ByteString getAttachData(); + } + /** + * Protobuf type {@code IM.Buddy.IMRecentContactSessionReq} + */ + public static final class IMRecentContactSessionReq extends + com.google.protobuf.GeneratedMessageLite implements + // @@protoc_insertion_point(message_implements:IM.Buddy.IMRecentContactSessionReq) + IMRecentContactSessionReqOrBuilder { + // Use IMRecentContactSessionReq.newBuilder() to construct. + private IMRecentContactSessionReq(com.google.protobuf.GeneratedMessageLite.Builder builder) { + super(builder); + this.unknownFields = builder.getUnknownFields(); + } + private IMRecentContactSessionReq(boolean noInit) { this.unknownFields = com.google.protobuf.ByteString.EMPTY;} + + private static final IMRecentContactSessionReq defaultInstance; + public static IMRecentContactSessionReq getDefaultInstance() { + return defaultInstance; + } + + public IMRecentContactSessionReq getDefaultInstanceForType() { + return defaultInstance; + } + + private final com.google.protobuf.ByteString unknownFields; + private IMRecentContactSessionReq( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + initFields(); + int mutable_bitField0_ = 0; + com.google.protobuf.ByteString.Output unknownFieldsOutput = + com.google.protobuf.ByteString.newOutput(); + com.google.protobuf.CodedOutputStream unknownFieldsCodedOutput = + com.google.protobuf.CodedOutputStream.newInstance( + unknownFieldsOutput); + try { + boolean done = false; + while (!done) { + int tag = input.readTag(); + switch (tag) { + case 0: + done = true; + break; + default: { + if (!parseUnknownField(input, unknownFieldsCodedOutput, + extensionRegistry, tag)) { + done = true; + } + break; + } + case 8: { + bitField0_ |= 0x00000001; + userId_ = input.readUInt32(); + break; + } + case 16: { + bitField0_ |= 0x00000002; + latestUpdateTime_ = input.readUInt32(); + break; + } + case 162: { + bitField0_ |= 0x00000004; + attachData_ = input.readBytes(); + break; + } + } + } + } catch (com.google.protobuf.InvalidProtocolBufferException e) { + throw e.setUnfinishedMessage(this); + } catch (java.io.IOException e) { + throw new com.google.protobuf.InvalidProtocolBufferException( + e.getMessage()).setUnfinishedMessage(this); + } finally { + try { + unknownFieldsCodedOutput.flush(); + } catch (java.io.IOException e) { + // Should not happen + } finally { + unknownFields = unknownFieldsOutput.toByteString(); + } + makeExtensionsImmutable(); + } + } + public static com.google.protobuf.Parser PARSER = + new com.google.protobuf.AbstractParser() { + public IMRecentContactSessionReq parsePartialFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return new IMRecentContactSessionReq(input, extensionRegistry); + } + }; + + @java.lang.Override + public com.google.protobuf.Parser getParserForType() { + return PARSER; + } + + private int bitField0_; + public static final int USER_ID_FIELD_NUMBER = 1; + private int userId_; + /** + * required uint32 user_id = 1; + * + *
+     *cmd id:		0x0201
+     * 
+ */ + public boolean hasUserId() { + return ((bitField0_ & 0x00000001) == 0x00000001); + } + /** + * required uint32 user_id = 1; + * + *
+     *cmd id:		0x0201
+     * 
+ */ + public int getUserId() { + return userId_; + } + + public static final int LATEST_UPDATE_TIME_FIELD_NUMBER = 2; + private int latestUpdateTime_; + /** + * required uint32 latest_update_time = 2; + */ + public boolean hasLatestUpdateTime() { + return ((bitField0_ & 0x00000002) == 0x00000002); + } + /** + * required uint32 latest_update_time = 2; + */ + public int getLatestUpdateTime() { + return latestUpdateTime_; + } + + public static final int ATTACH_DATA_FIELD_NUMBER = 20; + private com.google.protobuf.ByteString attachData_; + /** + * optional bytes attach_data = 20; + */ + public boolean hasAttachData() { + return ((bitField0_ & 0x00000004) == 0x00000004); + } + /** + * optional bytes attach_data = 20; + */ + public com.google.protobuf.ByteString getAttachData() { + return attachData_; + } + + private void initFields() { + userId_ = 0; + latestUpdateTime_ = 0; + attachData_ = com.google.protobuf.ByteString.EMPTY; + } + private byte memoizedIsInitialized = -1; + public final boolean isInitialized() { + byte isInitialized = memoizedIsInitialized; + if (isInitialized == 1) return true; + if (isInitialized == 0) return false; + + if (!hasUserId()) { + memoizedIsInitialized = 0; + return false; + } + if (!hasLatestUpdateTime()) { + memoizedIsInitialized = 0; + return false; + } + memoizedIsInitialized = 1; + return true; + } + + public void writeTo(com.google.protobuf.CodedOutputStream output) + throws java.io.IOException { + getSerializedSize(); + if (((bitField0_ & 0x00000001) == 0x00000001)) { + output.writeUInt32(1, userId_); + } + if (((bitField0_ & 0x00000002) == 0x00000002)) { + output.writeUInt32(2, latestUpdateTime_); + } + if (((bitField0_ & 0x00000004) == 0x00000004)) { + output.writeBytes(20, attachData_); + } + output.writeRawBytes(unknownFields); + } + + private int memoizedSerializedSize = -1; + public int getSerializedSize() { + int size = memoizedSerializedSize; + if (size != -1) return size; + + size = 0; + if (((bitField0_ & 0x00000001) == 0x00000001)) { + size += com.google.protobuf.CodedOutputStream + .computeUInt32Size(1, userId_); + } + if (((bitField0_ & 0x00000002) == 0x00000002)) { + size += com.google.protobuf.CodedOutputStream + .computeUInt32Size(2, latestUpdateTime_); + } + if (((bitField0_ & 0x00000004) == 0x00000004)) { + size += com.google.protobuf.CodedOutputStream + .computeBytesSize(20, attachData_); + } + size += unknownFields.size(); + memoizedSerializedSize = size; + return size; + } + + private static final long serialVersionUID = 0L; + @java.lang.Override + protected java.lang.Object writeReplace() + throws java.io.ObjectStreamException { + return super.writeReplace(); + } + + public static com.mogujie.tt.protobuf.IMBuddy.IMRecentContactSessionReq parseFrom( + com.google.protobuf.ByteString data) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data); + } + public static com.mogujie.tt.protobuf.IMBuddy.IMRecentContactSessionReq parseFrom( + com.google.protobuf.ByteString data, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data, extensionRegistry); + } + public static com.mogujie.tt.protobuf.IMBuddy.IMRecentContactSessionReq parseFrom(byte[] data) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data); + } + public static com.mogujie.tt.protobuf.IMBuddy.IMRecentContactSessionReq parseFrom( + byte[] data, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data, extensionRegistry); + } + public static com.mogujie.tt.protobuf.IMBuddy.IMRecentContactSessionReq parseFrom(java.io.InputStream input) + throws java.io.IOException { + return PARSER.parseFrom(input); + } + public static com.mogujie.tt.protobuf.IMBuddy.IMRecentContactSessionReq parseFrom( + java.io.InputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return PARSER.parseFrom(input, extensionRegistry); + } + public static com.mogujie.tt.protobuf.IMBuddy.IMRecentContactSessionReq parseDelimitedFrom(java.io.InputStream input) + throws java.io.IOException { + return PARSER.parseDelimitedFrom(input); + } + public static com.mogujie.tt.protobuf.IMBuddy.IMRecentContactSessionReq parseDelimitedFrom( + java.io.InputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return PARSER.parseDelimitedFrom(input, extensionRegistry); + } + public static com.mogujie.tt.protobuf.IMBuddy.IMRecentContactSessionReq parseFrom( + com.google.protobuf.CodedInputStream input) + throws java.io.IOException { + return PARSER.parseFrom(input); + } + public static com.mogujie.tt.protobuf.IMBuddy.IMRecentContactSessionReq parseFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return PARSER.parseFrom(input, extensionRegistry); + } + + public static Builder newBuilder() { return Builder.create(); } + public Builder newBuilderForType() { return newBuilder(); } + public static Builder newBuilder(com.mogujie.tt.protobuf.IMBuddy.IMRecentContactSessionReq prototype) { + return newBuilder().mergeFrom(prototype); + } + public Builder toBuilder() { return newBuilder(this); } + + /** + * Protobuf type {@code IM.Buddy.IMRecentContactSessionReq} + */ + public static final class Builder extends + com.google.protobuf.GeneratedMessageLite.Builder< + com.mogujie.tt.protobuf.IMBuddy.IMRecentContactSessionReq, Builder> + implements + // @@protoc_insertion_point(builder_implements:IM.Buddy.IMRecentContactSessionReq) + com.mogujie.tt.protobuf.IMBuddy.IMRecentContactSessionReqOrBuilder { + // Construct using com.mogujie.tt.protobuf.IMBuddy.IMRecentContactSessionReq.newBuilder() + private Builder() { + maybeForceBuilderInitialization(); + } + + private void maybeForceBuilderInitialization() { + } + private static Builder create() { + return new Builder(); + } + + public Builder clear() { + super.clear(); + userId_ = 0; + bitField0_ = (bitField0_ & ~0x00000001); + latestUpdateTime_ = 0; + bitField0_ = (bitField0_ & ~0x00000002); + attachData_ = com.google.protobuf.ByteString.EMPTY; + bitField0_ = (bitField0_ & ~0x00000004); + return this; + } + + public Builder clone() { + return create().mergeFrom(buildPartial()); + } + + public com.mogujie.tt.protobuf.IMBuddy.IMRecentContactSessionReq getDefaultInstanceForType() { + return com.mogujie.tt.protobuf.IMBuddy.IMRecentContactSessionReq.getDefaultInstance(); + } + + public com.mogujie.tt.protobuf.IMBuddy.IMRecentContactSessionReq build() { + com.mogujie.tt.protobuf.IMBuddy.IMRecentContactSessionReq result = buildPartial(); + if (!result.isInitialized()) { + throw newUninitializedMessageException(result); + } + return result; + } + + public com.mogujie.tt.protobuf.IMBuddy.IMRecentContactSessionReq buildPartial() { + com.mogujie.tt.protobuf.IMBuddy.IMRecentContactSessionReq result = new com.mogujie.tt.protobuf.IMBuddy.IMRecentContactSessionReq(this); + int from_bitField0_ = bitField0_; + int to_bitField0_ = 0; + if (((from_bitField0_ & 0x00000001) == 0x00000001)) { + to_bitField0_ |= 0x00000001; + } + result.userId_ = userId_; + if (((from_bitField0_ & 0x00000002) == 0x00000002)) { + to_bitField0_ |= 0x00000002; + } + result.latestUpdateTime_ = latestUpdateTime_; + if (((from_bitField0_ & 0x00000004) == 0x00000004)) { + to_bitField0_ |= 0x00000004; + } + result.attachData_ = attachData_; + result.bitField0_ = to_bitField0_; + return result; + } + + public Builder mergeFrom(com.mogujie.tt.protobuf.IMBuddy.IMRecentContactSessionReq other) { + if (other == com.mogujie.tt.protobuf.IMBuddy.IMRecentContactSessionReq.getDefaultInstance()) return this; + if (other.hasUserId()) { + setUserId(other.getUserId()); + } + if (other.hasLatestUpdateTime()) { + setLatestUpdateTime(other.getLatestUpdateTime()); + } + if (other.hasAttachData()) { + setAttachData(other.getAttachData()); + } + setUnknownFields( + getUnknownFields().concat(other.unknownFields)); + return this; + } + + public final boolean isInitialized() { + if (!hasUserId()) { + + return false; + } + if (!hasLatestUpdateTime()) { + + return false; + } + return true; + } + + public Builder mergeFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + com.mogujie.tt.protobuf.IMBuddy.IMRecentContactSessionReq parsedMessage = null; + try { + parsedMessage = PARSER.parsePartialFrom(input, extensionRegistry); + } catch (com.google.protobuf.InvalidProtocolBufferException e) { + parsedMessage = (com.mogujie.tt.protobuf.IMBuddy.IMRecentContactSessionReq) e.getUnfinishedMessage(); + throw e; + } finally { + if (parsedMessage != null) { + mergeFrom(parsedMessage); + } + } + return this; + } + private int bitField0_; + + private int userId_ ; + /** + * required uint32 user_id = 1; + * + *
+       *cmd id:		0x0201
+       * 
+ */ + public boolean hasUserId() { + return ((bitField0_ & 0x00000001) == 0x00000001); + } + /** + * required uint32 user_id = 1; + * + *
+       *cmd id:		0x0201
+       * 
+ */ + public int getUserId() { + return userId_; + } + /** + * required uint32 user_id = 1; + * + *
+       *cmd id:		0x0201
+       * 
+ */ + public Builder setUserId(int value) { + bitField0_ |= 0x00000001; + userId_ = value; + + return this; + } + /** + * required uint32 user_id = 1; + * + *
+       *cmd id:		0x0201
+       * 
+ */ + public Builder clearUserId() { + bitField0_ = (bitField0_ & ~0x00000001); + userId_ = 0; + + return this; + } + + private int latestUpdateTime_ ; + /** + * required uint32 latest_update_time = 2; + */ + public boolean hasLatestUpdateTime() { + return ((bitField0_ & 0x00000002) == 0x00000002); + } + /** + * required uint32 latest_update_time = 2; + */ + public int getLatestUpdateTime() { + return latestUpdateTime_; + } + /** + * required uint32 latest_update_time = 2; + */ + public Builder setLatestUpdateTime(int value) { + bitField0_ |= 0x00000002; + latestUpdateTime_ = value; + + return this; + } + /** + * required uint32 latest_update_time = 2; + */ + public Builder clearLatestUpdateTime() { + bitField0_ = (bitField0_ & ~0x00000002); + latestUpdateTime_ = 0; + + return this; + } + + private com.google.protobuf.ByteString attachData_ = com.google.protobuf.ByteString.EMPTY; + /** + * optional bytes attach_data = 20; + */ + public boolean hasAttachData() { + return ((bitField0_ & 0x00000004) == 0x00000004); + } + /** + * optional bytes attach_data = 20; + */ + public com.google.protobuf.ByteString getAttachData() { + return attachData_; + } + /** + * optional bytes attach_data = 20; + */ + public Builder setAttachData(com.google.protobuf.ByteString value) { + if (value == null) { + throw new NullPointerException(); + } + bitField0_ |= 0x00000004; + attachData_ = value; + + return this; + } + /** + * optional bytes attach_data = 20; + */ + public Builder clearAttachData() { + bitField0_ = (bitField0_ & ~0x00000004); + attachData_ = getDefaultInstance().getAttachData(); + + return this; + } + + // @@protoc_insertion_point(builder_scope:IM.Buddy.IMRecentContactSessionReq) + } + + static { + defaultInstance = new IMRecentContactSessionReq(true); + defaultInstance.initFields(); + } + + // @@protoc_insertion_point(class_scope:IM.Buddy.IMRecentContactSessionReq) + } + + public interface IMRecentContactSessionRspOrBuilder extends + // @@protoc_insertion_point(interface_extends:IM.Buddy.IMRecentContactSessionRsp) + com.google.protobuf.MessageLiteOrBuilder { + + /** + * required uint32 user_id = 1; + * + *
+     *cmd id:		0x0202
+     * 
+ */ + boolean hasUserId(); + /** + * required uint32 user_id = 1; + * + *
+     *cmd id:		0x0202
+     * 
+ */ + int getUserId(); + + /** + * repeated .IM.BaseDefine.ContactSessionInfo contact_session_list = 2; + */ + java.util.List + getContactSessionListList(); + /** + * repeated .IM.BaseDefine.ContactSessionInfo contact_session_list = 2; + */ + com.mogujie.tt.protobuf.IMBaseDefine.ContactSessionInfo getContactSessionList(int index); + /** + * repeated .IM.BaseDefine.ContactSessionInfo contact_session_list = 2; + */ + int getContactSessionListCount(); + + /** + * optional bytes attach_data = 20; + */ + boolean hasAttachData(); + /** + * optional bytes attach_data = 20; + */ + com.google.protobuf.ByteString getAttachData(); + } + /** + * Protobuf type {@code IM.Buddy.IMRecentContactSessionRsp} + */ + public static final class IMRecentContactSessionRsp extends + com.google.protobuf.GeneratedMessageLite implements + // @@protoc_insertion_point(message_implements:IM.Buddy.IMRecentContactSessionRsp) + IMRecentContactSessionRspOrBuilder { + // Use IMRecentContactSessionRsp.newBuilder() to construct. + private IMRecentContactSessionRsp(com.google.protobuf.GeneratedMessageLite.Builder builder) { + super(builder); + this.unknownFields = builder.getUnknownFields(); + } + private IMRecentContactSessionRsp(boolean noInit) { this.unknownFields = com.google.protobuf.ByteString.EMPTY;} + + private static final IMRecentContactSessionRsp defaultInstance; + public static IMRecentContactSessionRsp getDefaultInstance() { + return defaultInstance; + } + + public IMRecentContactSessionRsp getDefaultInstanceForType() { + return defaultInstance; + } + + private final com.google.protobuf.ByteString unknownFields; + private IMRecentContactSessionRsp( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + initFields(); + int mutable_bitField0_ = 0; + com.google.protobuf.ByteString.Output unknownFieldsOutput = + com.google.protobuf.ByteString.newOutput(); + com.google.protobuf.CodedOutputStream unknownFieldsCodedOutput = + com.google.protobuf.CodedOutputStream.newInstance( + unknownFieldsOutput); + try { + boolean done = false; + while (!done) { + int tag = input.readTag(); + switch (tag) { + case 0: + done = true; + break; + default: { + if (!parseUnknownField(input, unknownFieldsCodedOutput, + extensionRegistry, tag)) { + done = true; + } + break; + } + case 8: { + bitField0_ |= 0x00000001; + userId_ = input.readUInt32(); + break; + } + case 18: { + if (!((mutable_bitField0_ & 0x00000002) == 0x00000002)) { + contactSessionList_ = new java.util.ArrayList(); + mutable_bitField0_ |= 0x00000002; + } + contactSessionList_.add(input.readMessage(com.mogujie.tt.protobuf.IMBaseDefine.ContactSessionInfo.PARSER, extensionRegistry)); + break; + } + case 162: { + bitField0_ |= 0x00000002; + attachData_ = input.readBytes(); + break; + } + } + } + } catch (com.google.protobuf.InvalidProtocolBufferException e) { + throw e.setUnfinishedMessage(this); + } catch (java.io.IOException e) { + throw new com.google.protobuf.InvalidProtocolBufferException( + e.getMessage()).setUnfinishedMessage(this); + } finally { + if (((mutable_bitField0_ & 0x00000002) == 0x00000002)) { + contactSessionList_ = java.util.Collections.unmodifiableList(contactSessionList_); + } + try { + unknownFieldsCodedOutput.flush(); + } catch (java.io.IOException e) { + // Should not happen + } finally { + unknownFields = unknownFieldsOutput.toByteString(); + } + makeExtensionsImmutable(); + } + } + public static com.google.protobuf.Parser PARSER = + new com.google.protobuf.AbstractParser() { + public IMRecentContactSessionRsp parsePartialFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return new IMRecentContactSessionRsp(input, extensionRegistry); + } + }; + + @java.lang.Override + public com.google.protobuf.Parser getParserForType() { + return PARSER; + } + + private int bitField0_; + public static final int USER_ID_FIELD_NUMBER = 1; + private int userId_; + /** + * required uint32 user_id = 1; + * + *
+     *cmd id:		0x0202
+     * 
+ */ + public boolean hasUserId() { + return ((bitField0_ & 0x00000001) == 0x00000001); + } + /** + * required uint32 user_id = 1; + * + *
+     *cmd id:		0x0202
+     * 
+ */ + public int getUserId() { + return userId_; + } + + public static final int CONTACT_SESSION_LIST_FIELD_NUMBER = 2; + private java.util.List contactSessionList_; + /** + * repeated .IM.BaseDefine.ContactSessionInfo contact_session_list = 2; + */ + public java.util.List getContactSessionListList() { + return contactSessionList_; + } + /** + * repeated .IM.BaseDefine.ContactSessionInfo contact_session_list = 2; + */ + public java.util.List + getContactSessionListOrBuilderList() { + return contactSessionList_; + } + /** + * repeated .IM.BaseDefine.ContactSessionInfo contact_session_list = 2; + */ + public int getContactSessionListCount() { + return contactSessionList_.size(); + } + /** + * repeated .IM.BaseDefine.ContactSessionInfo contact_session_list = 2; + */ + public com.mogujie.tt.protobuf.IMBaseDefine.ContactSessionInfo getContactSessionList(int index) { + return contactSessionList_.get(index); + } + /** + * repeated .IM.BaseDefine.ContactSessionInfo contact_session_list = 2; + */ + public com.mogujie.tt.protobuf.IMBaseDefine.ContactSessionInfoOrBuilder getContactSessionListOrBuilder( + int index) { + return contactSessionList_.get(index); + } + + public static final int ATTACH_DATA_FIELD_NUMBER = 20; + private com.google.protobuf.ByteString attachData_; + /** + * optional bytes attach_data = 20; + */ + public boolean hasAttachData() { + return ((bitField0_ & 0x00000002) == 0x00000002); + } + /** + * optional bytes attach_data = 20; + */ + public com.google.protobuf.ByteString getAttachData() { + return attachData_; + } + + private void initFields() { + userId_ = 0; + contactSessionList_ = java.util.Collections.emptyList(); + attachData_ = com.google.protobuf.ByteString.EMPTY; + } + private byte memoizedIsInitialized = -1; + public final boolean isInitialized() { + byte isInitialized = memoizedIsInitialized; + if (isInitialized == 1) return true; + if (isInitialized == 0) return false; + + if (!hasUserId()) { + memoizedIsInitialized = 0; + return false; + } + for (int i = 0; i < getContactSessionListCount(); i++) { + if (!getContactSessionList(i).isInitialized()) { + memoizedIsInitialized = 0; + return false; + } + } + memoizedIsInitialized = 1; + return true; + } + + public void writeTo(com.google.protobuf.CodedOutputStream output) + throws java.io.IOException { + getSerializedSize(); + if (((bitField0_ & 0x00000001) == 0x00000001)) { + output.writeUInt32(1, userId_); + } + for (int i = 0; i < contactSessionList_.size(); i++) { + output.writeMessage(2, contactSessionList_.get(i)); + } + if (((bitField0_ & 0x00000002) == 0x00000002)) { + output.writeBytes(20, attachData_); + } + output.writeRawBytes(unknownFields); + } + + private int memoizedSerializedSize = -1; + public int getSerializedSize() { + int size = memoizedSerializedSize; + if (size != -1) return size; + + size = 0; + if (((bitField0_ & 0x00000001) == 0x00000001)) { + size += com.google.protobuf.CodedOutputStream + .computeUInt32Size(1, userId_); + } + for (int i = 0; i < contactSessionList_.size(); i++) { + size += com.google.protobuf.CodedOutputStream + .computeMessageSize(2, contactSessionList_.get(i)); + } + if (((bitField0_ & 0x00000002) == 0x00000002)) { + size += com.google.protobuf.CodedOutputStream + .computeBytesSize(20, attachData_); + } + size += unknownFields.size(); + memoizedSerializedSize = size; + return size; + } + + private static final long serialVersionUID = 0L; + @java.lang.Override + protected java.lang.Object writeReplace() + throws java.io.ObjectStreamException { + return super.writeReplace(); + } + + public static com.mogujie.tt.protobuf.IMBuddy.IMRecentContactSessionRsp parseFrom( + com.google.protobuf.ByteString data) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data); + } + public static com.mogujie.tt.protobuf.IMBuddy.IMRecentContactSessionRsp parseFrom( + com.google.protobuf.ByteString data, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data, extensionRegistry); + } + public static com.mogujie.tt.protobuf.IMBuddy.IMRecentContactSessionRsp parseFrom(byte[] data) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data); + } + public static com.mogujie.tt.protobuf.IMBuddy.IMRecentContactSessionRsp parseFrom( + byte[] data, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data, extensionRegistry); + } + public static com.mogujie.tt.protobuf.IMBuddy.IMRecentContactSessionRsp parseFrom(java.io.InputStream input) + throws java.io.IOException { + return PARSER.parseFrom(input); + } + public static com.mogujie.tt.protobuf.IMBuddy.IMRecentContactSessionRsp parseFrom( + java.io.InputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return PARSER.parseFrom(input, extensionRegistry); + } + public static com.mogujie.tt.protobuf.IMBuddy.IMRecentContactSessionRsp parseDelimitedFrom(java.io.InputStream input) + throws java.io.IOException { + return PARSER.parseDelimitedFrom(input); + } + public static com.mogujie.tt.protobuf.IMBuddy.IMRecentContactSessionRsp parseDelimitedFrom( + java.io.InputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return PARSER.parseDelimitedFrom(input, extensionRegistry); + } + public static com.mogujie.tt.protobuf.IMBuddy.IMRecentContactSessionRsp parseFrom( + com.google.protobuf.CodedInputStream input) + throws java.io.IOException { + return PARSER.parseFrom(input); + } + public static com.mogujie.tt.protobuf.IMBuddy.IMRecentContactSessionRsp parseFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return PARSER.parseFrom(input, extensionRegistry); + } + + public static Builder newBuilder() { return Builder.create(); } + public Builder newBuilderForType() { return newBuilder(); } + public static Builder newBuilder(com.mogujie.tt.protobuf.IMBuddy.IMRecentContactSessionRsp prototype) { + return newBuilder().mergeFrom(prototype); + } + public Builder toBuilder() { return newBuilder(this); } + + /** + * Protobuf type {@code IM.Buddy.IMRecentContactSessionRsp} + */ + public static final class Builder extends + com.google.protobuf.GeneratedMessageLite.Builder< + com.mogujie.tt.protobuf.IMBuddy.IMRecentContactSessionRsp, Builder> + implements + // @@protoc_insertion_point(builder_implements:IM.Buddy.IMRecentContactSessionRsp) + com.mogujie.tt.protobuf.IMBuddy.IMRecentContactSessionRspOrBuilder { + // Construct using com.mogujie.tt.protobuf.IMBuddy.IMRecentContactSessionRsp.newBuilder() + private Builder() { + maybeForceBuilderInitialization(); + } + + private void maybeForceBuilderInitialization() { + } + private static Builder create() { + return new Builder(); + } + + public Builder clear() { + super.clear(); + userId_ = 0; + bitField0_ = (bitField0_ & ~0x00000001); + contactSessionList_ = java.util.Collections.emptyList(); + bitField0_ = (bitField0_ & ~0x00000002); + attachData_ = com.google.protobuf.ByteString.EMPTY; + bitField0_ = (bitField0_ & ~0x00000004); + return this; + } + + public Builder clone() { + return create().mergeFrom(buildPartial()); + } + + public com.mogujie.tt.protobuf.IMBuddy.IMRecentContactSessionRsp getDefaultInstanceForType() { + return com.mogujie.tt.protobuf.IMBuddy.IMRecentContactSessionRsp.getDefaultInstance(); + } + + public com.mogujie.tt.protobuf.IMBuddy.IMRecentContactSessionRsp build() { + com.mogujie.tt.protobuf.IMBuddy.IMRecentContactSessionRsp result = buildPartial(); + if (!result.isInitialized()) { + throw newUninitializedMessageException(result); + } + return result; + } + + public com.mogujie.tt.protobuf.IMBuddy.IMRecentContactSessionRsp buildPartial() { + com.mogujie.tt.protobuf.IMBuddy.IMRecentContactSessionRsp result = new com.mogujie.tt.protobuf.IMBuddy.IMRecentContactSessionRsp(this); + int from_bitField0_ = bitField0_; + int to_bitField0_ = 0; + if (((from_bitField0_ & 0x00000001) == 0x00000001)) { + to_bitField0_ |= 0x00000001; + } + result.userId_ = userId_; + if (((bitField0_ & 0x00000002) == 0x00000002)) { + contactSessionList_ = java.util.Collections.unmodifiableList(contactSessionList_); + bitField0_ = (bitField0_ & ~0x00000002); + } + result.contactSessionList_ = contactSessionList_; + if (((from_bitField0_ & 0x00000004) == 0x00000004)) { + to_bitField0_ |= 0x00000002; + } + result.attachData_ = attachData_; + result.bitField0_ = to_bitField0_; + return result; + } + + public Builder mergeFrom(com.mogujie.tt.protobuf.IMBuddy.IMRecentContactSessionRsp other) { + if (other == com.mogujie.tt.protobuf.IMBuddy.IMRecentContactSessionRsp.getDefaultInstance()) return this; + if (other.hasUserId()) { + setUserId(other.getUserId()); + } + if (!other.contactSessionList_.isEmpty()) { + if (contactSessionList_.isEmpty()) { + contactSessionList_ = other.contactSessionList_; + bitField0_ = (bitField0_ & ~0x00000002); + } else { + ensureContactSessionListIsMutable(); + contactSessionList_.addAll(other.contactSessionList_); + } + + } + if (other.hasAttachData()) { + setAttachData(other.getAttachData()); + } + setUnknownFields( + getUnknownFields().concat(other.unknownFields)); + return this; + } + + public final boolean isInitialized() { + if (!hasUserId()) { + + return false; + } + for (int i = 0; i < getContactSessionListCount(); i++) { + if (!getContactSessionList(i).isInitialized()) { + + return false; + } + } + return true; + } + + public Builder mergeFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + com.mogujie.tt.protobuf.IMBuddy.IMRecentContactSessionRsp parsedMessage = null; + try { + parsedMessage = PARSER.parsePartialFrom(input, extensionRegistry); + } catch (com.google.protobuf.InvalidProtocolBufferException e) { + parsedMessage = (com.mogujie.tt.protobuf.IMBuddy.IMRecentContactSessionRsp) e.getUnfinishedMessage(); + throw e; + } finally { + if (parsedMessage != null) { + mergeFrom(parsedMessage); + } + } + return this; + } + private int bitField0_; + + private int userId_ ; + /** + * required uint32 user_id = 1; + * + *
+       *cmd id:		0x0202
+       * 
+ */ + public boolean hasUserId() { + return ((bitField0_ & 0x00000001) == 0x00000001); + } + /** + * required uint32 user_id = 1; + * + *
+       *cmd id:		0x0202
+       * 
+ */ + public int getUserId() { + return userId_; + } + /** + * required uint32 user_id = 1; + * + *
+       *cmd id:		0x0202
+       * 
+ */ + public Builder setUserId(int value) { + bitField0_ |= 0x00000001; + userId_ = value; + + return this; + } + /** + * required uint32 user_id = 1; + * + *
+       *cmd id:		0x0202
+       * 
+ */ + public Builder clearUserId() { + bitField0_ = (bitField0_ & ~0x00000001); + userId_ = 0; + + return this; + } + + private java.util.List contactSessionList_ = + java.util.Collections.emptyList(); + private void ensureContactSessionListIsMutable() { + if (!((bitField0_ & 0x00000002) == 0x00000002)) { + contactSessionList_ = new java.util.ArrayList(contactSessionList_); + bitField0_ |= 0x00000002; + } + } + + /** + * repeated .IM.BaseDefine.ContactSessionInfo contact_session_list = 2; + */ + public java.util.List getContactSessionListList() { + return java.util.Collections.unmodifiableList(contactSessionList_); + } + /** + * repeated .IM.BaseDefine.ContactSessionInfo contact_session_list = 2; + */ + public int getContactSessionListCount() { + return contactSessionList_.size(); + } + /** + * repeated .IM.BaseDefine.ContactSessionInfo contact_session_list = 2; + */ + public com.mogujie.tt.protobuf.IMBaseDefine.ContactSessionInfo getContactSessionList(int index) { + return contactSessionList_.get(index); + } + /** + * repeated .IM.BaseDefine.ContactSessionInfo contact_session_list = 2; + */ + public Builder setContactSessionList( + int index, com.mogujie.tt.protobuf.IMBaseDefine.ContactSessionInfo value) { + if (value == null) { + throw new NullPointerException(); + } + ensureContactSessionListIsMutable(); + contactSessionList_.set(index, value); + + return this; + } + /** + * repeated .IM.BaseDefine.ContactSessionInfo contact_session_list = 2; + */ + public Builder setContactSessionList( + int index, com.mogujie.tt.protobuf.IMBaseDefine.ContactSessionInfo.Builder builderForValue) { + ensureContactSessionListIsMutable(); + contactSessionList_.set(index, builderForValue.build()); + + return this; + } + /** + * repeated .IM.BaseDefine.ContactSessionInfo contact_session_list = 2; + */ + public Builder addContactSessionList(com.mogujie.tt.protobuf.IMBaseDefine.ContactSessionInfo value) { + if (value == null) { + throw new NullPointerException(); + } + ensureContactSessionListIsMutable(); + contactSessionList_.add(value); + + return this; + } + /** + * repeated .IM.BaseDefine.ContactSessionInfo contact_session_list = 2; + */ + public Builder addContactSessionList( + int index, com.mogujie.tt.protobuf.IMBaseDefine.ContactSessionInfo value) { + if (value == null) { + throw new NullPointerException(); + } + ensureContactSessionListIsMutable(); + contactSessionList_.add(index, value); + + return this; + } + /** + * repeated .IM.BaseDefine.ContactSessionInfo contact_session_list = 2; + */ + public Builder addContactSessionList( + com.mogujie.tt.protobuf.IMBaseDefine.ContactSessionInfo.Builder builderForValue) { + ensureContactSessionListIsMutable(); + contactSessionList_.add(builderForValue.build()); + + return this; + } + /** + * repeated .IM.BaseDefine.ContactSessionInfo contact_session_list = 2; + */ + public Builder addContactSessionList( + int index, com.mogujie.tt.protobuf.IMBaseDefine.ContactSessionInfo.Builder builderForValue) { + ensureContactSessionListIsMutable(); + contactSessionList_.add(index, builderForValue.build()); + + return this; + } + /** + * repeated .IM.BaseDefine.ContactSessionInfo contact_session_list = 2; + */ + public Builder addAllContactSessionList( + java.lang.Iterable values) { + ensureContactSessionListIsMutable(); + com.google.protobuf.AbstractMessageLite.Builder.addAll( + values, contactSessionList_); + + return this; + } + /** + * repeated .IM.BaseDefine.ContactSessionInfo contact_session_list = 2; + */ + public Builder clearContactSessionList() { + contactSessionList_ = java.util.Collections.emptyList(); + bitField0_ = (bitField0_ & ~0x00000002); + + return this; + } + /** + * repeated .IM.BaseDefine.ContactSessionInfo contact_session_list = 2; + */ + public Builder removeContactSessionList(int index) { + ensureContactSessionListIsMutable(); + contactSessionList_.remove(index); + + return this; + } + + private com.google.protobuf.ByteString attachData_ = com.google.protobuf.ByteString.EMPTY; + /** + * optional bytes attach_data = 20; + */ + public boolean hasAttachData() { + return ((bitField0_ & 0x00000004) == 0x00000004); + } + /** + * optional bytes attach_data = 20; + */ + public com.google.protobuf.ByteString getAttachData() { + return attachData_; + } + /** + * optional bytes attach_data = 20; + */ + public Builder setAttachData(com.google.protobuf.ByteString value) { + if (value == null) { + throw new NullPointerException(); + } + bitField0_ |= 0x00000004; + attachData_ = value; + + return this; + } + /** + * optional bytes attach_data = 20; + */ + public Builder clearAttachData() { + bitField0_ = (bitField0_ & ~0x00000004); + attachData_ = getDefaultInstance().getAttachData(); + + return this; + } + + // @@protoc_insertion_point(builder_scope:IM.Buddy.IMRecentContactSessionRsp) + } + + static { + defaultInstance = new IMRecentContactSessionRsp(true); + defaultInstance.initFields(); + } + + // @@protoc_insertion_point(class_scope:IM.Buddy.IMRecentContactSessionRsp) + } + + public interface IMUserStatNotifyOrBuilder extends + // @@protoc_insertion_point(interface_extends:IM.Buddy.IMUserStatNotify) + com.google.protobuf.MessageLiteOrBuilder { + + /** + * required .IM.BaseDefine.UserStat user_stat = 1; + * + *
+     *cmd id:		0x0203
+     * 
+ */ + boolean hasUserStat(); + /** + * required .IM.BaseDefine.UserStat user_stat = 1; + * + *
+     *cmd id:		0x0203
+     * 
+ */ + com.mogujie.tt.protobuf.IMBaseDefine.UserStat getUserStat(); + } + /** + * Protobuf type {@code IM.Buddy.IMUserStatNotify} + */ + public static final class IMUserStatNotify extends + com.google.protobuf.GeneratedMessageLite implements + // @@protoc_insertion_point(message_implements:IM.Buddy.IMUserStatNotify) + IMUserStatNotifyOrBuilder { + // Use IMUserStatNotify.newBuilder() to construct. + private IMUserStatNotify(com.google.protobuf.GeneratedMessageLite.Builder builder) { + super(builder); + this.unknownFields = builder.getUnknownFields(); + } + private IMUserStatNotify(boolean noInit) { this.unknownFields = com.google.protobuf.ByteString.EMPTY;} + + private static final IMUserStatNotify defaultInstance; + public static IMUserStatNotify getDefaultInstance() { + return defaultInstance; + } + + public IMUserStatNotify getDefaultInstanceForType() { + return defaultInstance; + } + + private final com.google.protobuf.ByteString unknownFields; + private IMUserStatNotify( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + initFields(); + int mutable_bitField0_ = 0; + com.google.protobuf.ByteString.Output unknownFieldsOutput = + com.google.protobuf.ByteString.newOutput(); + com.google.protobuf.CodedOutputStream unknownFieldsCodedOutput = + com.google.protobuf.CodedOutputStream.newInstance( + unknownFieldsOutput); + try { + boolean done = false; + while (!done) { + int tag = input.readTag(); + switch (tag) { + case 0: + done = true; + break; + default: { + if (!parseUnknownField(input, unknownFieldsCodedOutput, + extensionRegistry, tag)) { + done = true; + } + break; + } + case 10: { + com.mogujie.tt.protobuf.IMBaseDefine.UserStat.Builder subBuilder = null; + if (((bitField0_ & 0x00000001) == 0x00000001)) { + subBuilder = userStat_.toBuilder(); + } + userStat_ = input.readMessage(com.mogujie.tt.protobuf.IMBaseDefine.UserStat.PARSER, extensionRegistry); + if (subBuilder != null) { + subBuilder.mergeFrom(userStat_); + userStat_ = subBuilder.buildPartial(); + } + bitField0_ |= 0x00000001; + break; + } + } + } + } catch (com.google.protobuf.InvalidProtocolBufferException e) { + throw e.setUnfinishedMessage(this); + } catch (java.io.IOException e) { + throw new com.google.protobuf.InvalidProtocolBufferException( + e.getMessage()).setUnfinishedMessage(this); + } finally { + try { + unknownFieldsCodedOutput.flush(); + } catch (java.io.IOException e) { + // Should not happen + } finally { + unknownFields = unknownFieldsOutput.toByteString(); + } + makeExtensionsImmutable(); + } + } + public static com.google.protobuf.Parser PARSER = + new com.google.protobuf.AbstractParser() { + public IMUserStatNotify parsePartialFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return new IMUserStatNotify(input, extensionRegistry); + } + }; + + @java.lang.Override + public com.google.protobuf.Parser getParserForType() { + return PARSER; + } + + private int bitField0_; + public static final int USER_STAT_FIELD_NUMBER = 1; + private com.mogujie.tt.protobuf.IMBaseDefine.UserStat userStat_; + /** + * required .IM.BaseDefine.UserStat user_stat = 1; + * + *
+     *cmd id:		0x0203
+     * 
+ */ + public boolean hasUserStat() { + return ((bitField0_ & 0x00000001) == 0x00000001); + } + /** + * required .IM.BaseDefine.UserStat user_stat = 1; + * + *
+     *cmd id:		0x0203
+     * 
+ */ + public com.mogujie.tt.protobuf.IMBaseDefine.UserStat getUserStat() { + return userStat_; + } + + private void initFields() { + userStat_ = com.mogujie.tt.protobuf.IMBaseDefine.UserStat.getDefaultInstance(); + } + private byte memoizedIsInitialized = -1; + public final boolean isInitialized() { + byte isInitialized = memoizedIsInitialized; + if (isInitialized == 1) return true; + if (isInitialized == 0) return false; + + if (!hasUserStat()) { + memoizedIsInitialized = 0; + return false; + } + if (!getUserStat().isInitialized()) { + memoizedIsInitialized = 0; + return false; + } + memoizedIsInitialized = 1; + return true; + } + + public void writeTo(com.google.protobuf.CodedOutputStream output) + throws java.io.IOException { + getSerializedSize(); + if (((bitField0_ & 0x00000001) == 0x00000001)) { + output.writeMessage(1, userStat_); + } + output.writeRawBytes(unknownFields); + } + + private int memoizedSerializedSize = -1; + public int getSerializedSize() { + int size = memoizedSerializedSize; + if (size != -1) return size; + + size = 0; + if (((bitField0_ & 0x00000001) == 0x00000001)) { + size += com.google.protobuf.CodedOutputStream + .computeMessageSize(1, userStat_); + } + size += unknownFields.size(); + memoizedSerializedSize = size; + return size; + } + + private static final long serialVersionUID = 0L; + @java.lang.Override + protected java.lang.Object writeReplace() + throws java.io.ObjectStreamException { + return super.writeReplace(); + } + + public static com.mogujie.tt.protobuf.IMBuddy.IMUserStatNotify parseFrom( + com.google.protobuf.ByteString data) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data); + } + public static com.mogujie.tt.protobuf.IMBuddy.IMUserStatNotify parseFrom( + com.google.protobuf.ByteString data, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data, extensionRegistry); + } + public static com.mogujie.tt.protobuf.IMBuddy.IMUserStatNotify parseFrom(byte[] data) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data); + } + public static com.mogujie.tt.protobuf.IMBuddy.IMUserStatNotify parseFrom( + byte[] data, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data, extensionRegistry); + } + public static com.mogujie.tt.protobuf.IMBuddy.IMUserStatNotify parseFrom(java.io.InputStream input) + throws java.io.IOException { + return PARSER.parseFrom(input); + } + public static com.mogujie.tt.protobuf.IMBuddy.IMUserStatNotify parseFrom( + java.io.InputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return PARSER.parseFrom(input, extensionRegistry); + } + public static com.mogujie.tt.protobuf.IMBuddy.IMUserStatNotify parseDelimitedFrom(java.io.InputStream input) + throws java.io.IOException { + return PARSER.parseDelimitedFrom(input); + } + public static com.mogujie.tt.protobuf.IMBuddy.IMUserStatNotify parseDelimitedFrom( + java.io.InputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return PARSER.parseDelimitedFrom(input, extensionRegistry); + } + public static com.mogujie.tt.protobuf.IMBuddy.IMUserStatNotify parseFrom( + com.google.protobuf.CodedInputStream input) + throws java.io.IOException { + return PARSER.parseFrom(input); + } + public static com.mogujie.tt.protobuf.IMBuddy.IMUserStatNotify parseFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return PARSER.parseFrom(input, extensionRegistry); + } + + public static Builder newBuilder() { return Builder.create(); } + public Builder newBuilderForType() { return newBuilder(); } + public static Builder newBuilder(com.mogujie.tt.protobuf.IMBuddy.IMUserStatNotify prototype) { + return newBuilder().mergeFrom(prototype); + } + public Builder toBuilder() { return newBuilder(this); } + + /** + * Protobuf type {@code IM.Buddy.IMUserStatNotify} + */ + public static final class Builder extends + com.google.protobuf.GeneratedMessageLite.Builder< + com.mogujie.tt.protobuf.IMBuddy.IMUserStatNotify, Builder> + implements + // @@protoc_insertion_point(builder_implements:IM.Buddy.IMUserStatNotify) + com.mogujie.tt.protobuf.IMBuddy.IMUserStatNotifyOrBuilder { + // Construct using com.mogujie.tt.protobuf.IMBuddy.IMUserStatNotify.newBuilder() + private Builder() { + maybeForceBuilderInitialization(); + } + + private void maybeForceBuilderInitialization() { + } + private static Builder create() { + return new Builder(); + } + + public Builder clear() { + super.clear(); + userStat_ = com.mogujie.tt.protobuf.IMBaseDefine.UserStat.getDefaultInstance(); + bitField0_ = (bitField0_ & ~0x00000001); + return this; + } + + public Builder clone() { + return create().mergeFrom(buildPartial()); + } + + public com.mogujie.tt.protobuf.IMBuddy.IMUserStatNotify getDefaultInstanceForType() { + return com.mogujie.tt.protobuf.IMBuddy.IMUserStatNotify.getDefaultInstance(); + } + + public com.mogujie.tt.protobuf.IMBuddy.IMUserStatNotify build() { + com.mogujie.tt.protobuf.IMBuddy.IMUserStatNotify result = buildPartial(); + if (!result.isInitialized()) { + throw newUninitializedMessageException(result); + } + return result; + } + + public com.mogujie.tt.protobuf.IMBuddy.IMUserStatNotify buildPartial() { + com.mogujie.tt.protobuf.IMBuddy.IMUserStatNotify result = new com.mogujie.tt.protobuf.IMBuddy.IMUserStatNotify(this); + int from_bitField0_ = bitField0_; + int to_bitField0_ = 0; + if (((from_bitField0_ & 0x00000001) == 0x00000001)) { + to_bitField0_ |= 0x00000001; + } + result.userStat_ = userStat_; + result.bitField0_ = to_bitField0_; + return result; + } + + public Builder mergeFrom(com.mogujie.tt.protobuf.IMBuddy.IMUserStatNotify other) { + if (other == com.mogujie.tt.protobuf.IMBuddy.IMUserStatNotify.getDefaultInstance()) return this; + if (other.hasUserStat()) { + mergeUserStat(other.getUserStat()); + } + setUnknownFields( + getUnknownFields().concat(other.unknownFields)); + return this; + } + + public final boolean isInitialized() { + if (!hasUserStat()) { + + return false; + } + if (!getUserStat().isInitialized()) { + + return false; + } + return true; + } + + public Builder mergeFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + com.mogujie.tt.protobuf.IMBuddy.IMUserStatNotify parsedMessage = null; + try { + parsedMessage = PARSER.parsePartialFrom(input, extensionRegistry); + } catch (com.google.protobuf.InvalidProtocolBufferException e) { + parsedMessage = (com.mogujie.tt.protobuf.IMBuddy.IMUserStatNotify) e.getUnfinishedMessage(); + throw e; + } finally { + if (parsedMessage != null) { + mergeFrom(parsedMessage); + } + } + return this; + } + private int bitField0_; + + private com.mogujie.tt.protobuf.IMBaseDefine.UserStat userStat_ = com.mogujie.tt.protobuf.IMBaseDefine.UserStat.getDefaultInstance(); + /** + * required .IM.BaseDefine.UserStat user_stat = 1; + * + *
+       *cmd id:		0x0203
+       * 
+ */ + public boolean hasUserStat() { + return ((bitField0_ & 0x00000001) == 0x00000001); + } + /** + * required .IM.BaseDefine.UserStat user_stat = 1; + * + *
+       *cmd id:		0x0203
+       * 
+ */ + public com.mogujie.tt.protobuf.IMBaseDefine.UserStat getUserStat() { + return userStat_; + } + /** + * required .IM.BaseDefine.UserStat user_stat = 1; + * + *
+       *cmd id:		0x0203
+       * 
+ */ + public Builder setUserStat(com.mogujie.tt.protobuf.IMBaseDefine.UserStat value) { + if (value == null) { + throw new NullPointerException(); + } + userStat_ = value; + + bitField0_ |= 0x00000001; + return this; + } + /** + * required .IM.BaseDefine.UserStat user_stat = 1; + * + *
+       *cmd id:		0x0203
+       * 
+ */ + public Builder setUserStat( + com.mogujie.tt.protobuf.IMBaseDefine.UserStat.Builder builderForValue) { + userStat_ = builderForValue.build(); + + bitField0_ |= 0x00000001; + return this; + } + /** + * required .IM.BaseDefine.UserStat user_stat = 1; + * + *
+       *cmd id:		0x0203
+       * 
+ */ + public Builder mergeUserStat(com.mogujie.tt.protobuf.IMBaseDefine.UserStat value) { + if (((bitField0_ & 0x00000001) == 0x00000001) && + userStat_ != com.mogujie.tt.protobuf.IMBaseDefine.UserStat.getDefaultInstance()) { + userStat_ = + com.mogujie.tt.protobuf.IMBaseDefine.UserStat.newBuilder(userStat_).mergeFrom(value).buildPartial(); + } else { + userStat_ = value; + } + + bitField0_ |= 0x00000001; + return this; + } + /** + * required .IM.BaseDefine.UserStat user_stat = 1; + * + *
+       *cmd id:		0x0203
+       * 
+ */ + public Builder clearUserStat() { + userStat_ = com.mogujie.tt.protobuf.IMBaseDefine.UserStat.getDefaultInstance(); + + bitField0_ = (bitField0_ & ~0x00000001); + return this; + } + + // @@protoc_insertion_point(builder_scope:IM.Buddy.IMUserStatNotify) + } + + static { + defaultInstance = new IMUserStatNotify(true); + defaultInstance.initFields(); + } + + // @@protoc_insertion_point(class_scope:IM.Buddy.IMUserStatNotify) + } + + public interface IMUsersInfoReqOrBuilder extends + // @@protoc_insertion_point(interface_extends:IM.Buddy.IMUsersInfoReq) + com.google.protobuf.MessageLiteOrBuilder { + + /** + * required uint32 user_id = 1; + * + *
+     *cmd id:		0x0204
+     * 
+ */ + boolean hasUserId(); + /** + * required uint32 user_id = 1; + * + *
+     *cmd id:		0x0204
+     * 
+ */ + int getUserId(); + + /** + * repeated uint32 user_id_list = 2; + */ + java.util.List getUserIdListList(); + /** + * repeated uint32 user_id_list = 2; + */ + int getUserIdListCount(); + /** + * repeated uint32 user_id_list = 2; + */ + int getUserIdList(int index); + + /** + * optional bytes attach_data = 20; + */ + boolean hasAttachData(); + /** + * optional bytes attach_data = 20; + */ + com.google.protobuf.ByteString getAttachData(); + } + /** + * Protobuf type {@code IM.Buddy.IMUsersInfoReq} + */ + public static final class IMUsersInfoReq extends + com.google.protobuf.GeneratedMessageLite implements + // @@protoc_insertion_point(message_implements:IM.Buddy.IMUsersInfoReq) + IMUsersInfoReqOrBuilder { + // Use IMUsersInfoReq.newBuilder() to construct. + private IMUsersInfoReq(com.google.protobuf.GeneratedMessageLite.Builder builder) { + super(builder); + this.unknownFields = builder.getUnknownFields(); + } + private IMUsersInfoReq(boolean noInit) { this.unknownFields = com.google.protobuf.ByteString.EMPTY;} + + private static final IMUsersInfoReq defaultInstance; + public static IMUsersInfoReq getDefaultInstance() { + return defaultInstance; + } + + public IMUsersInfoReq getDefaultInstanceForType() { + return defaultInstance; + } + + private final com.google.protobuf.ByteString unknownFields; + private IMUsersInfoReq( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + initFields(); + int mutable_bitField0_ = 0; + com.google.protobuf.ByteString.Output unknownFieldsOutput = + com.google.protobuf.ByteString.newOutput(); + com.google.protobuf.CodedOutputStream unknownFieldsCodedOutput = + com.google.protobuf.CodedOutputStream.newInstance( + unknownFieldsOutput); + try { + boolean done = false; + while (!done) { + int tag = input.readTag(); + switch (tag) { + case 0: + done = true; + break; + default: { + if (!parseUnknownField(input, unknownFieldsCodedOutput, + extensionRegistry, tag)) { + done = true; + } + break; + } + case 8: { + bitField0_ |= 0x00000001; + userId_ = input.readUInt32(); + break; + } + case 16: { + if (!((mutable_bitField0_ & 0x00000002) == 0x00000002)) { + userIdList_ = new java.util.ArrayList(); + mutable_bitField0_ |= 0x00000002; + } + userIdList_.add(input.readUInt32()); + break; + } + case 18: { + int length = input.readRawVarint32(); + int limit = input.pushLimit(length); + if (!((mutable_bitField0_ & 0x00000002) == 0x00000002) && input.getBytesUntilLimit() > 0) { + userIdList_ = new java.util.ArrayList(); + mutable_bitField0_ |= 0x00000002; + } + while (input.getBytesUntilLimit() > 0) { + userIdList_.add(input.readUInt32()); + } + input.popLimit(limit); + break; + } + case 162: { + bitField0_ |= 0x00000002; + attachData_ = input.readBytes(); + break; + } + } + } + } catch (com.google.protobuf.InvalidProtocolBufferException e) { + throw e.setUnfinishedMessage(this); + } catch (java.io.IOException e) { + throw new com.google.protobuf.InvalidProtocolBufferException( + e.getMessage()).setUnfinishedMessage(this); + } finally { + if (((mutable_bitField0_ & 0x00000002) == 0x00000002)) { + userIdList_ = java.util.Collections.unmodifiableList(userIdList_); + } + try { + unknownFieldsCodedOutput.flush(); + } catch (java.io.IOException e) { + // Should not happen + } finally { + unknownFields = unknownFieldsOutput.toByteString(); + } + makeExtensionsImmutable(); + } + } + public static com.google.protobuf.Parser PARSER = + new com.google.protobuf.AbstractParser() { + public IMUsersInfoReq parsePartialFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return new IMUsersInfoReq(input, extensionRegistry); + } + }; + + @java.lang.Override + public com.google.protobuf.Parser getParserForType() { + return PARSER; + } + + private int bitField0_; + public static final int USER_ID_FIELD_NUMBER = 1; + private int userId_; + /** + * required uint32 user_id = 1; + * + *
+     *cmd id:		0x0204
+     * 
+ */ + public boolean hasUserId() { + return ((bitField0_ & 0x00000001) == 0x00000001); + } + /** + * required uint32 user_id = 1; + * + *
+     *cmd id:		0x0204
+     * 
+ */ + public int getUserId() { + return userId_; + } + + public static final int USER_ID_LIST_FIELD_NUMBER = 2; + private java.util.List userIdList_; + /** + * repeated uint32 user_id_list = 2; + */ + public java.util.List + getUserIdListList() { + return userIdList_; + } + /** + * repeated uint32 user_id_list = 2; + */ + public int getUserIdListCount() { + return userIdList_.size(); + } + /** + * repeated uint32 user_id_list = 2; + */ + public int getUserIdList(int index) { + return userIdList_.get(index); + } + + public static final int ATTACH_DATA_FIELD_NUMBER = 20; + private com.google.protobuf.ByteString attachData_; + /** + * optional bytes attach_data = 20; + */ + public boolean hasAttachData() { + return ((bitField0_ & 0x00000002) == 0x00000002); + } + /** + * optional bytes attach_data = 20; + */ + public com.google.protobuf.ByteString getAttachData() { + return attachData_; + } + + private void initFields() { + userId_ = 0; + userIdList_ = java.util.Collections.emptyList(); + attachData_ = com.google.protobuf.ByteString.EMPTY; + } + private byte memoizedIsInitialized = -1; + public final boolean isInitialized() { + byte isInitialized = memoizedIsInitialized; + if (isInitialized == 1) return true; + if (isInitialized == 0) return false; + + if (!hasUserId()) { + memoizedIsInitialized = 0; + return false; + } + memoizedIsInitialized = 1; + return true; + } + + public void writeTo(com.google.protobuf.CodedOutputStream output) + throws java.io.IOException { + getSerializedSize(); + if (((bitField0_ & 0x00000001) == 0x00000001)) { + output.writeUInt32(1, userId_); + } + for (int i = 0; i < userIdList_.size(); i++) { + output.writeUInt32(2, userIdList_.get(i)); + } + if (((bitField0_ & 0x00000002) == 0x00000002)) { + output.writeBytes(20, attachData_); + } + output.writeRawBytes(unknownFields); + } + + private int memoizedSerializedSize = -1; + public int getSerializedSize() { + int size = memoizedSerializedSize; + if (size != -1) return size; + + size = 0; + if (((bitField0_ & 0x00000001) == 0x00000001)) { + size += com.google.protobuf.CodedOutputStream + .computeUInt32Size(1, userId_); + } + { + int dataSize = 0; + for (int i = 0; i < userIdList_.size(); i++) { + dataSize += com.google.protobuf.CodedOutputStream + .computeUInt32SizeNoTag(userIdList_.get(i)); + } + size += dataSize; + size += 1 * getUserIdListList().size(); + } + if (((bitField0_ & 0x00000002) == 0x00000002)) { + size += com.google.protobuf.CodedOutputStream + .computeBytesSize(20, attachData_); + } + size += unknownFields.size(); + memoizedSerializedSize = size; + return size; + } + + private static final long serialVersionUID = 0L; + @java.lang.Override + protected java.lang.Object writeReplace() + throws java.io.ObjectStreamException { + return super.writeReplace(); + } + + public static com.mogujie.tt.protobuf.IMBuddy.IMUsersInfoReq parseFrom( + com.google.protobuf.ByteString data) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data); + } + public static com.mogujie.tt.protobuf.IMBuddy.IMUsersInfoReq parseFrom( + com.google.protobuf.ByteString data, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data, extensionRegistry); + } + public static com.mogujie.tt.protobuf.IMBuddy.IMUsersInfoReq parseFrom(byte[] data) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data); + } + public static com.mogujie.tt.protobuf.IMBuddy.IMUsersInfoReq parseFrom( + byte[] data, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data, extensionRegistry); + } + public static com.mogujie.tt.protobuf.IMBuddy.IMUsersInfoReq parseFrom(java.io.InputStream input) + throws java.io.IOException { + return PARSER.parseFrom(input); + } + public static com.mogujie.tt.protobuf.IMBuddy.IMUsersInfoReq parseFrom( + java.io.InputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return PARSER.parseFrom(input, extensionRegistry); + } + public static com.mogujie.tt.protobuf.IMBuddy.IMUsersInfoReq parseDelimitedFrom(java.io.InputStream input) + throws java.io.IOException { + return PARSER.parseDelimitedFrom(input); + } + public static com.mogujie.tt.protobuf.IMBuddy.IMUsersInfoReq parseDelimitedFrom( + java.io.InputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return PARSER.parseDelimitedFrom(input, extensionRegistry); + } + public static com.mogujie.tt.protobuf.IMBuddy.IMUsersInfoReq parseFrom( + com.google.protobuf.CodedInputStream input) + throws java.io.IOException { + return PARSER.parseFrom(input); + } + public static com.mogujie.tt.protobuf.IMBuddy.IMUsersInfoReq parseFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return PARSER.parseFrom(input, extensionRegistry); + } + + public static Builder newBuilder() { return Builder.create(); } + public Builder newBuilderForType() { return newBuilder(); } + public static Builder newBuilder(com.mogujie.tt.protobuf.IMBuddy.IMUsersInfoReq prototype) { + return newBuilder().mergeFrom(prototype); + } + public Builder toBuilder() { return newBuilder(this); } + + /** + * Protobuf type {@code IM.Buddy.IMUsersInfoReq} + */ + public static final class Builder extends + com.google.protobuf.GeneratedMessageLite.Builder< + com.mogujie.tt.protobuf.IMBuddy.IMUsersInfoReq, Builder> + implements + // @@protoc_insertion_point(builder_implements:IM.Buddy.IMUsersInfoReq) + com.mogujie.tt.protobuf.IMBuddy.IMUsersInfoReqOrBuilder { + // Construct using com.mogujie.tt.protobuf.IMBuddy.IMUsersInfoReq.newBuilder() + private Builder() { + maybeForceBuilderInitialization(); + } + + private void maybeForceBuilderInitialization() { + } + private static Builder create() { + return new Builder(); + } + + public Builder clear() { + super.clear(); + userId_ = 0; + bitField0_ = (bitField0_ & ~0x00000001); + userIdList_ = java.util.Collections.emptyList(); + bitField0_ = (bitField0_ & ~0x00000002); + attachData_ = com.google.protobuf.ByteString.EMPTY; + bitField0_ = (bitField0_ & ~0x00000004); + return this; + } + + public Builder clone() { + return create().mergeFrom(buildPartial()); + } + + public com.mogujie.tt.protobuf.IMBuddy.IMUsersInfoReq getDefaultInstanceForType() { + return com.mogujie.tt.protobuf.IMBuddy.IMUsersInfoReq.getDefaultInstance(); + } + + public com.mogujie.tt.protobuf.IMBuddy.IMUsersInfoReq build() { + com.mogujie.tt.protobuf.IMBuddy.IMUsersInfoReq result = buildPartial(); + if (!result.isInitialized()) { + throw newUninitializedMessageException(result); + } + return result; + } + + public com.mogujie.tt.protobuf.IMBuddy.IMUsersInfoReq buildPartial() { + com.mogujie.tt.protobuf.IMBuddy.IMUsersInfoReq result = new com.mogujie.tt.protobuf.IMBuddy.IMUsersInfoReq(this); + int from_bitField0_ = bitField0_; + int to_bitField0_ = 0; + if (((from_bitField0_ & 0x00000001) == 0x00000001)) { + to_bitField0_ |= 0x00000001; + } + result.userId_ = userId_; + if (((bitField0_ & 0x00000002) == 0x00000002)) { + userIdList_ = java.util.Collections.unmodifiableList(userIdList_); + bitField0_ = (bitField0_ & ~0x00000002); + } + result.userIdList_ = userIdList_; + if (((from_bitField0_ & 0x00000004) == 0x00000004)) { + to_bitField0_ |= 0x00000002; + } + result.attachData_ = attachData_; + result.bitField0_ = to_bitField0_; + return result; + } + + public Builder mergeFrom(com.mogujie.tt.protobuf.IMBuddy.IMUsersInfoReq other) { + if (other == com.mogujie.tt.protobuf.IMBuddy.IMUsersInfoReq.getDefaultInstance()) return this; + if (other.hasUserId()) { + setUserId(other.getUserId()); + } + if (!other.userIdList_.isEmpty()) { + if (userIdList_.isEmpty()) { + userIdList_ = other.userIdList_; + bitField0_ = (bitField0_ & ~0x00000002); + } else { + ensureUserIdListIsMutable(); + userIdList_.addAll(other.userIdList_); + } + + } + if (other.hasAttachData()) { + setAttachData(other.getAttachData()); + } + setUnknownFields( + getUnknownFields().concat(other.unknownFields)); + return this; + } + + public final boolean isInitialized() { + if (!hasUserId()) { + + return false; + } + return true; + } + + public Builder mergeFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + com.mogujie.tt.protobuf.IMBuddy.IMUsersInfoReq parsedMessage = null; + try { + parsedMessage = PARSER.parsePartialFrom(input, extensionRegistry); + } catch (com.google.protobuf.InvalidProtocolBufferException e) { + parsedMessage = (com.mogujie.tt.protobuf.IMBuddy.IMUsersInfoReq) e.getUnfinishedMessage(); + throw e; + } finally { + if (parsedMessage != null) { + mergeFrom(parsedMessage); + } + } + return this; + } + private int bitField0_; + + private int userId_ ; + /** + * required uint32 user_id = 1; + * + *
+       *cmd id:		0x0204
+       * 
+ */ + public boolean hasUserId() { + return ((bitField0_ & 0x00000001) == 0x00000001); + } + /** + * required uint32 user_id = 1; + * + *
+       *cmd id:		0x0204
+       * 
+ */ + public int getUserId() { + return userId_; + } + /** + * required uint32 user_id = 1; + * + *
+       *cmd id:		0x0204
+       * 
+ */ + public Builder setUserId(int value) { + bitField0_ |= 0x00000001; + userId_ = value; + + return this; + } + /** + * required uint32 user_id = 1; + * + *
+       *cmd id:		0x0204
+       * 
+ */ + public Builder clearUserId() { + bitField0_ = (bitField0_ & ~0x00000001); + userId_ = 0; + + return this; + } + + private java.util.List userIdList_ = java.util.Collections.emptyList(); + private void ensureUserIdListIsMutable() { + if (!((bitField0_ & 0x00000002) == 0x00000002)) { + userIdList_ = new java.util.ArrayList(userIdList_); + bitField0_ |= 0x00000002; + } + } + /** + * repeated uint32 user_id_list = 2; + */ + public java.util.List + getUserIdListList() { + return java.util.Collections.unmodifiableList(userIdList_); + } + /** + * repeated uint32 user_id_list = 2; + */ + public int getUserIdListCount() { + return userIdList_.size(); + } + /** + * repeated uint32 user_id_list = 2; + */ + public int getUserIdList(int index) { + return userIdList_.get(index); + } + /** + * repeated uint32 user_id_list = 2; + */ + public Builder setUserIdList( + int index, int value) { + ensureUserIdListIsMutable(); + userIdList_.set(index, value); + + return this; + } + /** + * repeated uint32 user_id_list = 2; + */ + public Builder addUserIdList(int value) { + ensureUserIdListIsMutable(); + userIdList_.add(value); + + return this; + } + /** + * repeated uint32 user_id_list = 2; + */ + public Builder addAllUserIdList( + java.lang.Iterable values) { + ensureUserIdListIsMutable(); + com.google.protobuf.AbstractMessageLite.Builder.addAll( + values, userIdList_); + + return this; + } + /** + * repeated uint32 user_id_list = 2; + */ + public Builder clearUserIdList() { + userIdList_ = java.util.Collections.emptyList(); + bitField0_ = (bitField0_ & ~0x00000002); + + return this; + } + + private com.google.protobuf.ByteString attachData_ = com.google.protobuf.ByteString.EMPTY; + /** + * optional bytes attach_data = 20; + */ + public boolean hasAttachData() { + return ((bitField0_ & 0x00000004) == 0x00000004); + } + /** + * optional bytes attach_data = 20; + */ + public com.google.protobuf.ByteString getAttachData() { + return attachData_; + } + /** + * optional bytes attach_data = 20; + */ + public Builder setAttachData(com.google.protobuf.ByteString value) { + if (value == null) { + throw new NullPointerException(); + } + bitField0_ |= 0x00000004; + attachData_ = value; + + return this; + } + /** + * optional bytes attach_data = 20; + */ + public Builder clearAttachData() { + bitField0_ = (bitField0_ & ~0x00000004); + attachData_ = getDefaultInstance().getAttachData(); + + return this; + } + + // @@protoc_insertion_point(builder_scope:IM.Buddy.IMUsersInfoReq) + } + + static { + defaultInstance = new IMUsersInfoReq(true); + defaultInstance.initFields(); + } + + // @@protoc_insertion_point(class_scope:IM.Buddy.IMUsersInfoReq) + } + + public interface IMUsersInfoRspOrBuilder extends + // @@protoc_insertion_point(interface_extends:IM.Buddy.IMUsersInfoRsp) + com.google.protobuf.MessageLiteOrBuilder { + + /** + * required uint32 user_id = 1; + * + *
+     *cmd id:		0x0205
+     * 
+ */ + boolean hasUserId(); + /** + * required uint32 user_id = 1; + * + *
+     *cmd id:		0x0205
+     * 
+ */ + int getUserId(); + + /** + * repeated .IM.BaseDefine.UserInfo user_info_list = 2; + */ + java.util.List + getUserInfoListList(); + /** + * repeated .IM.BaseDefine.UserInfo user_info_list = 2; + */ + com.mogujie.tt.protobuf.IMBaseDefine.UserInfo getUserInfoList(int index); + /** + * repeated .IM.BaseDefine.UserInfo user_info_list = 2; + */ + int getUserInfoListCount(); + + /** + * optional bytes attach_data = 20; + */ + boolean hasAttachData(); + /** + * optional bytes attach_data = 20; + */ + com.google.protobuf.ByteString getAttachData(); + } + /** + * Protobuf type {@code IM.Buddy.IMUsersInfoRsp} + */ + public static final class IMUsersInfoRsp extends + com.google.protobuf.GeneratedMessageLite implements + // @@protoc_insertion_point(message_implements:IM.Buddy.IMUsersInfoRsp) + IMUsersInfoRspOrBuilder { + // Use IMUsersInfoRsp.newBuilder() to construct. + private IMUsersInfoRsp(com.google.protobuf.GeneratedMessageLite.Builder builder) { + super(builder); + this.unknownFields = builder.getUnknownFields(); + } + private IMUsersInfoRsp(boolean noInit) { this.unknownFields = com.google.protobuf.ByteString.EMPTY;} + + private static final IMUsersInfoRsp defaultInstance; + public static IMUsersInfoRsp getDefaultInstance() { + return defaultInstance; + } + + public IMUsersInfoRsp getDefaultInstanceForType() { + return defaultInstance; + } + + private final com.google.protobuf.ByteString unknownFields; + private IMUsersInfoRsp( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + initFields(); + int mutable_bitField0_ = 0; + com.google.protobuf.ByteString.Output unknownFieldsOutput = + com.google.protobuf.ByteString.newOutput(); + com.google.protobuf.CodedOutputStream unknownFieldsCodedOutput = + com.google.protobuf.CodedOutputStream.newInstance( + unknownFieldsOutput); + try { + boolean done = false; + while (!done) { + int tag = input.readTag(); + switch (tag) { + case 0: + done = true; + break; + default: { + if (!parseUnknownField(input, unknownFieldsCodedOutput, + extensionRegistry, tag)) { + done = true; + } + break; + } + case 8: { + bitField0_ |= 0x00000001; + userId_ = input.readUInt32(); + break; + } + case 18: { + if (!((mutable_bitField0_ & 0x00000002) == 0x00000002)) { + userInfoList_ = new java.util.ArrayList(); + mutable_bitField0_ |= 0x00000002; + } + userInfoList_.add(input.readMessage(com.mogujie.tt.protobuf.IMBaseDefine.UserInfo.PARSER, extensionRegistry)); + break; + } + case 162: { + bitField0_ |= 0x00000002; + attachData_ = input.readBytes(); + break; + } + } + } + } catch (com.google.protobuf.InvalidProtocolBufferException e) { + throw e.setUnfinishedMessage(this); + } catch (java.io.IOException e) { + throw new com.google.protobuf.InvalidProtocolBufferException( + e.getMessage()).setUnfinishedMessage(this); + } finally { + if (((mutable_bitField0_ & 0x00000002) == 0x00000002)) { + userInfoList_ = java.util.Collections.unmodifiableList(userInfoList_); + } + try { + unknownFieldsCodedOutput.flush(); + } catch (java.io.IOException e) { + // Should not happen + } finally { + unknownFields = unknownFieldsOutput.toByteString(); + } + makeExtensionsImmutable(); + } + } + public static com.google.protobuf.Parser PARSER = + new com.google.protobuf.AbstractParser() { + public IMUsersInfoRsp parsePartialFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return new IMUsersInfoRsp(input, extensionRegistry); + } + }; + + @java.lang.Override + public com.google.protobuf.Parser getParserForType() { + return PARSER; + } + + private int bitField0_; + public static final int USER_ID_FIELD_NUMBER = 1; + private int userId_; + /** + * required uint32 user_id = 1; + * + *
+     *cmd id:		0x0205
+     * 
+ */ + public boolean hasUserId() { + return ((bitField0_ & 0x00000001) == 0x00000001); + } + /** + * required uint32 user_id = 1; + * + *
+     *cmd id:		0x0205
+     * 
+ */ + public int getUserId() { + return userId_; + } + + public static final int USER_INFO_LIST_FIELD_NUMBER = 2; + private java.util.List userInfoList_; + /** + * repeated .IM.BaseDefine.UserInfo user_info_list = 2; + */ + public java.util.List getUserInfoListList() { + return userInfoList_; + } + /** + * repeated .IM.BaseDefine.UserInfo user_info_list = 2; + */ + public java.util.List + getUserInfoListOrBuilderList() { + return userInfoList_; + } + /** + * repeated .IM.BaseDefine.UserInfo user_info_list = 2; + */ + public int getUserInfoListCount() { + return userInfoList_.size(); + } + /** + * repeated .IM.BaseDefine.UserInfo user_info_list = 2; + */ + public com.mogujie.tt.protobuf.IMBaseDefine.UserInfo getUserInfoList(int index) { + return userInfoList_.get(index); + } + /** + * repeated .IM.BaseDefine.UserInfo user_info_list = 2; + */ + public com.mogujie.tt.protobuf.IMBaseDefine.UserInfoOrBuilder getUserInfoListOrBuilder( + int index) { + return userInfoList_.get(index); + } + + public static final int ATTACH_DATA_FIELD_NUMBER = 20; + private com.google.protobuf.ByteString attachData_; + /** + * optional bytes attach_data = 20; + */ + public boolean hasAttachData() { + return ((bitField0_ & 0x00000002) == 0x00000002); + } + /** + * optional bytes attach_data = 20; + */ + public com.google.protobuf.ByteString getAttachData() { + return attachData_; + } + + private void initFields() { + userId_ = 0; + userInfoList_ = java.util.Collections.emptyList(); + attachData_ = com.google.protobuf.ByteString.EMPTY; + } + private byte memoizedIsInitialized = -1; + public final boolean isInitialized() { + byte isInitialized = memoizedIsInitialized; + if (isInitialized == 1) return true; + if (isInitialized == 0) return false; + + if (!hasUserId()) { + memoizedIsInitialized = 0; + return false; + } + for (int i = 0; i < getUserInfoListCount(); i++) { + if (!getUserInfoList(i).isInitialized()) { + memoizedIsInitialized = 0; + return false; + } + } + memoizedIsInitialized = 1; + return true; + } + + public void writeTo(com.google.protobuf.CodedOutputStream output) + throws java.io.IOException { + getSerializedSize(); + if (((bitField0_ & 0x00000001) == 0x00000001)) { + output.writeUInt32(1, userId_); + } + for (int i = 0; i < userInfoList_.size(); i++) { + output.writeMessage(2, userInfoList_.get(i)); + } + if (((bitField0_ & 0x00000002) == 0x00000002)) { + output.writeBytes(20, attachData_); + } + output.writeRawBytes(unknownFields); + } + + private int memoizedSerializedSize = -1; + public int getSerializedSize() { + int size = memoizedSerializedSize; + if (size != -1) return size; + + size = 0; + if (((bitField0_ & 0x00000001) == 0x00000001)) { + size += com.google.protobuf.CodedOutputStream + .computeUInt32Size(1, userId_); + } + for (int i = 0; i < userInfoList_.size(); i++) { + size += com.google.protobuf.CodedOutputStream + .computeMessageSize(2, userInfoList_.get(i)); + } + if (((bitField0_ & 0x00000002) == 0x00000002)) { + size += com.google.protobuf.CodedOutputStream + .computeBytesSize(20, attachData_); + } + size += unknownFields.size(); + memoizedSerializedSize = size; + return size; + } + + private static final long serialVersionUID = 0L; + @java.lang.Override + protected java.lang.Object writeReplace() + throws java.io.ObjectStreamException { + return super.writeReplace(); + } + + public static com.mogujie.tt.protobuf.IMBuddy.IMUsersInfoRsp parseFrom( + com.google.protobuf.ByteString data) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data); + } + public static com.mogujie.tt.protobuf.IMBuddy.IMUsersInfoRsp parseFrom( + com.google.protobuf.ByteString data, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data, extensionRegistry); + } + public static com.mogujie.tt.protobuf.IMBuddy.IMUsersInfoRsp parseFrom(byte[] data) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data); + } + public static com.mogujie.tt.protobuf.IMBuddy.IMUsersInfoRsp parseFrom( + byte[] data, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data, extensionRegistry); + } + public static com.mogujie.tt.protobuf.IMBuddy.IMUsersInfoRsp parseFrom(java.io.InputStream input) + throws java.io.IOException { + return PARSER.parseFrom(input); + } + public static com.mogujie.tt.protobuf.IMBuddy.IMUsersInfoRsp parseFrom( + java.io.InputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return PARSER.parseFrom(input, extensionRegistry); + } + public static com.mogujie.tt.protobuf.IMBuddy.IMUsersInfoRsp parseDelimitedFrom(java.io.InputStream input) + throws java.io.IOException { + return PARSER.parseDelimitedFrom(input); + } + public static com.mogujie.tt.protobuf.IMBuddy.IMUsersInfoRsp parseDelimitedFrom( + java.io.InputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return PARSER.parseDelimitedFrom(input, extensionRegistry); + } + public static com.mogujie.tt.protobuf.IMBuddy.IMUsersInfoRsp parseFrom( + com.google.protobuf.CodedInputStream input) + throws java.io.IOException { + return PARSER.parseFrom(input); + } + public static com.mogujie.tt.protobuf.IMBuddy.IMUsersInfoRsp parseFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return PARSER.parseFrom(input, extensionRegistry); + } + + public static Builder newBuilder() { return Builder.create(); } + public Builder newBuilderForType() { return newBuilder(); } + public static Builder newBuilder(com.mogujie.tt.protobuf.IMBuddy.IMUsersInfoRsp prototype) { + return newBuilder().mergeFrom(prototype); + } + public Builder toBuilder() { return newBuilder(this); } + + /** + * Protobuf type {@code IM.Buddy.IMUsersInfoRsp} + */ + public static final class Builder extends + com.google.protobuf.GeneratedMessageLite.Builder< + com.mogujie.tt.protobuf.IMBuddy.IMUsersInfoRsp, Builder> + implements + // @@protoc_insertion_point(builder_implements:IM.Buddy.IMUsersInfoRsp) + com.mogujie.tt.protobuf.IMBuddy.IMUsersInfoRspOrBuilder { + // Construct using com.mogujie.tt.protobuf.IMBuddy.IMUsersInfoRsp.newBuilder() + private Builder() { + maybeForceBuilderInitialization(); + } + + private void maybeForceBuilderInitialization() { + } + private static Builder create() { + return new Builder(); + } + + public Builder clear() { + super.clear(); + userId_ = 0; + bitField0_ = (bitField0_ & ~0x00000001); + userInfoList_ = java.util.Collections.emptyList(); + bitField0_ = (bitField0_ & ~0x00000002); + attachData_ = com.google.protobuf.ByteString.EMPTY; + bitField0_ = (bitField0_ & ~0x00000004); + return this; + } + + public Builder clone() { + return create().mergeFrom(buildPartial()); + } + + public com.mogujie.tt.protobuf.IMBuddy.IMUsersInfoRsp getDefaultInstanceForType() { + return com.mogujie.tt.protobuf.IMBuddy.IMUsersInfoRsp.getDefaultInstance(); + } + + public com.mogujie.tt.protobuf.IMBuddy.IMUsersInfoRsp build() { + com.mogujie.tt.protobuf.IMBuddy.IMUsersInfoRsp result = buildPartial(); + if (!result.isInitialized()) { + throw newUninitializedMessageException(result); + } + return result; + } + + public com.mogujie.tt.protobuf.IMBuddy.IMUsersInfoRsp buildPartial() { + com.mogujie.tt.protobuf.IMBuddy.IMUsersInfoRsp result = new com.mogujie.tt.protobuf.IMBuddy.IMUsersInfoRsp(this); + int from_bitField0_ = bitField0_; + int to_bitField0_ = 0; + if (((from_bitField0_ & 0x00000001) == 0x00000001)) { + to_bitField0_ |= 0x00000001; + } + result.userId_ = userId_; + if (((bitField0_ & 0x00000002) == 0x00000002)) { + userInfoList_ = java.util.Collections.unmodifiableList(userInfoList_); + bitField0_ = (bitField0_ & ~0x00000002); + } + result.userInfoList_ = userInfoList_; + if (((from_bitField0_ & 0x00000004) == 0x00000004)) { + to_bitField0_ |= 0x00000002; + } + result.attachData_ = attachData_; + result.bitField0_ = to_bitField0_; + return result; + } + + public Builder mergeFrom(com.mogujie.tt.protobuf.IMBuddy.IMUsersInfoRsp other) { + if (other == com.mogujie.tt.protobuf.IMBuddy.IMUsersInfoRsp.getDefaultInstance()) return this; + if (other.hasUserId()) { + setUserId(other.getUserId()); + } + if (!other.userInfoList_.isEmpty()) { + if (userInfoList_.isEmpty()) { + userInfoList_ = other.userInfoList_; + bitField0_ = (bitField0_ & ~0x00000002); + } else { + ensureUserInfoListIsMutable(); + userInfoList_.addAll(other.userInfoList_); + } + + } + if (other.hasAttachData()) { + setAttachData(other.getAttachData()); + } + setUnknownFields( + getUnknownFields().concat(other.unknownFields)); + return this; + } + + public final boolean isInitialized() { + if (!hasUserId()) { + + return false; + } + for (int i = 0; i < getUserInfoListCount(); i++) { + if (!getUserInfoList(i).isInitialized()) { + + return false; + } + } + return true; + } + + public Builder mergeFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + com.mogujie.tt.protobuf.IMBuddy.IMUsersInfoRsp parsedMessage = null; + try { + parsedMessage = PARSER.parsePartialFrom(input, extensionRegistry); + } catch (com.google.protobuf.InvalidProtocolBufferException e) { + parsedMessage = (com.mogujie.tt.protobuf.IMBuddy.IMUsersInfoRsp) e.getUnfinishedMessage(); + throw e; + } finally { + if (parsedMessage != null) { + mergeFrom(parsedMessage); + } + } + return this; + } + private int bitField0_; + + private int userId_ ; + /** + * required uint32 user_id = 1; + * + *
+       *cmd id:		0x0205
+       * 
+ */ + public boolean hasUserId() { + return ((bitField0_ & 0x00000001) == 0x00000001); + } + /** + * required uint32 user_id = 1; + * + *
+       *cmd id:		0x0205
+       * 
+ */ + public int getUserId() { + return userId_; + } + /** + * required uint32 user_id = 1; + * + *
+       *cmd id:		0x0205
+       * 
+ */ + public Builder setUserId(int value) { + bitField0_ |= 0x00000001; + userId_ = value; + + return this; + } + /** + * required uint32 user_id = 1; + * + *
+       *cmd id:		0x0205
+       * 
+ */ + public Builder clearUserId() { + bitField0_ = (bitField0_ & ~0x00000001); + userId_ = 0; + + return this; + } + + private java.util.List userInfoList_ = + java.util.Collections.emptyList(); + private void ensureUserInfoListIsMutable() { + if (!((bitField0_ & 0x00000002) == 0x00000002)) { + userInfoList_ = new java.util.ArrayList(userInfoList_); + bitField0_ |= 0x00000002; + } + } + + /** + * repeated .IM.BaseDefine.UserInfo user_info_list = 2; + */ + public java.util.List getUserInfoListList() { + return java.util.Collections.unmodifiableList(userInfoList_); + } + /** + * repeated .IM.BaseDefine.UserInfo user_info_list = 2; + */ + public int getUserInfoListCount() { + return userInfoList_.size(); + } + /** + * repeated .IM.BaseDefine.UserInfo user_info_list = 2; + */ + public com.mogujie.tt.protobuf.IMBaseDefine.UserInfo getUserInfoList(int index) { + return userInfoList_.get(index); + } + /** + * repeated .IM.BaseDefine.UserInfo user_info_list = 2; + */ + public Builder setUserInfoList( + int index, com.mogujie.tt.protobuf.IMBaseDefine.UserInfo value) { + if (value == null) { + throw new NullPointerException(); + } + ensureUserInfoListIsMutable(); + userInfoList_.set(index, value); + + return this; + } + /** + * repeated .IM.BaseDefine.UserInfo user_info_list = 2; + */ + public Builder setUserInfoList( + int index, com.mogujie.tt.protobuf.IMBaseDefine.UserInfo.Builder builderForValue) { + ensureUserInfoListIsMutable(); + userInfoList_.set(index, builderForValue.build()); + + return this; + } + /** + * repeated .IM.BaseDefine.UserInfo user_info_list = 2; + */ + public Builder addUserInfoList(com.mogujie.tt.protobuf.IMBaseDefine.UserInfo value) { + if (value == null) { + throw new NullPointerException(); + } + ensureUserInfoListIsMutable(); + userInfoList_.add(value); + + return this; + } + /** + * repeated .IM.BaseDefine.UserInfo user_info_list = 2; + */ + public Builder addUserInfoList( + int index, com.mogujie.tt.protobuf.IMBaseDefine.UserInfo value) { + if (value == null) { + throw new NullPointerException(); + } + ensureUserInfoListIsMutable(); + userInfoList_.add(index, value); + + return this; + } + /** + * repeated .IM.BaseDefine.UserInfo user_info_list = 2; + */ + public Builder addUserInfoList( + com.mogujie.tt.protobuf.IMBaseDefine.UserInfo.Builder builderForValue) { + ensureUserInfoListIsMutable(); + userInfoList_.add(builderForValue.build()); + + return this; + } + /** + * repeated .IM.BaseDefine.UserInfo user_info_list = 2; + */ + public Builder addUserInfoList( + int index, com.mogujie.tt.protobuf.IMBaseDefine.UserInfo.Builder builderForValue) { + ensureUserInfoListIsMutable(); + userInfoList_.add(index, builderForValue.build()); + + return this; + } + /** + * repeated .IM.BaseDefine.UserInfo user_info_list = 2; + */ + public Builder addAllUserInfoList( + java.lang.Iterable values) { + ensureUserInfoListIsMutable(); + com.google.protobuf.AbstractMessageLite.Builder.addAll( + values, userInfoList_); + + return this; + } + /** + * repeated .IM.BaseDefine.UserInfo user_info_list = 2; + */ + public Builder clearUserInfoList() { + userInfoList_ = java.util.Collections.emptyList(); + bitField0_ = (bitField0_ & ~0x00000002); + + return this; + } + /** + * repeated .IM.BaseDefine.UserInfo user_info_list = 2; + */ + public Builder removeUserInfoList(int index) { + ensureUserInfoListIsMutable(); + userInfoList_.remove(index); + + return this; + } + + private com.google.protobuf.ByteString attachData_ = com.google.protobuf.ByteString.EMPTY; + /** + * optional bytes attach_data = 20; + */ + public boolean hasAttachData() { + return ((bitField0_ & 0x00000004) == 0x00000004); + } + /** + * optional bytes attach_data = 20; + */ + public com.google.protobuf.ByteString getAttachData() { + return attachData_; + } + /** + * optional bytes attach_data = 20; + */ + public Builder setAttachData(com.google.protobuf.ByteString value) { + if (value == null) { + throw new NullPointerException(); + } + bitField0_ |= 0x00000004; + attachData_ = value; + + return this; + } + /** + * optional bytes attach_data = 20; + */ + public Builder clearAttachData() { + bitField0_ = (bitField0_ & ~0x00000004); + attachData_ = getDefaultInstance().getAttachData(); + + return this; + } + + // @@protoc_insertion_point(builder_scope:IM.Buddy.IMUsersInfoRsp) + } + + static { + defaultInstance = new IMUsersInfoRsp(true); + defaultInstance.initFields(); + } + + // @@protoc_insertion_point(class_scope:IM.Buddy.IMUsersInfoRsp) + } + + public interface IMRemoveSessionReqOrBuilder extends + // @@protoc_insertion_point(interface_extends:IM.Buddy.IMRemoveSessionReq) + com.google.protobuf.MessageLiteOrBuilder { + + /** + * required uint32 user_id = 1; + * + *
+     *cmd id:		0x0206
+     * 
+ */ + boolean hasUserId(); + /** + * required uint32 user_id = 1; + * + *
+     *cmd id:		0x0206
+     * 
+ */ + int getUserId(); + + /** + * required .IM.BaseDefine.SessionType session_type = 2; + */ + boolean hasSessionType(); + /** + * required .IM.BaseDefine.SessionType session_type = 2; + */ + com.mogujie.tt.protobuf.IMBaseDefine.SessionType getSessionType(); + + /** + * required uint32 session_id = 3; + */ + boolean hasSessionId(); + /** + * required uint32 session_id = 3; + */ + int getSessionId(); + + /** + * optional bytes attach_data = 20; + */ + boolean hasAttachData(); + /** + * optional bytes attach_data = 20; + */ + com.google.protobuf.ByteString getAttachData(); + } + /** + * Protobuf type {@code IM.Buddy.IMRemoveSessionReq} + */ + public static final class IMRemoveSessionReq extends + com.google.protobuf.GeneratedMessageLite implements + // @@protoc_insertion_point(message_implements:IM.Buddy.IMRemoveSessionReq) + IMRemoveSessionReqOrBuilder { + // Use IMRemoveSessionReq.newBuilder() to construct. + private IMRemoveSessionReq(com.google.protobuf.GeneratedMessageLite.Builder builder) { + super(builder); + this.unknownFields = builder.getUnknownFields(); + } + private IMRemoveSessionReq(boolean noInit) { this.unknownFields = com.google.protobuf.ByteString.EMPTY;} + + private static final IMRemoveSessionReq defaultInstance; + public static IMRemoveSessionReq getDefaultInstance() { + return defaultInstance; + } + + public IMRemoveSessionReq getDefaultInstanceForType() { + return defaultInstance; + } + + private final com.google.protobuf.ByteString unknownFields; + private IMRemoveSessionReq( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + initFields(); + int mutable_bitField0_ = 0; + com.google.protobuf.ByteString.Output unknownFieldsOutput = + com.google.protobuf.ByteString.newOutput(); + com.google.protobuf.CodedOutputStream unknownFieldsCodedOutput = + com.google.protobuf.CodedOutputStream.newInstance( + unknownFieldsOutput); + try { + boolean done = false; + while (!done) { + int tag = input.readTag(); + switch (tag) { + case 0: + done = true; + break; + default: { + if (!parseUnknownField(input, unknownFieldsCodedOutput, + extensionRegistry, tag)) { + done = true; + } + break; + } + case 8: { + bitField0_ |= 0x00000001; + userId_ = input.readUInt32(); + break; + } + case 16: { + int rawValue = input.readEnum(); + com.mogujie.tt.protobuf.IMBaseDefine.SessionType value = com.mogujie.tt.protobuf.IMBaseDefine.SessionType.valueOf(rawValue); + if (value == null) { + unknownFieldsCodedOutput.writeRawVarint32(tag); + unknownFieldsCodedOutput.writeRawVarint32(rawValue); + } else { + bitField0_ |= 0x00000002; + sessionType_ = value; + } + break; + } + case 24: { + bitField0_ |= 0x00000004; + sessionId_ = input.readUInt32(); + break; + } + case 162: { + bitField0_ |= 0x00000008; + attachData_ = input.readBytes(); + break; + } + } + } + } catch (com.google.protobuf.InvalidProtocolBufferException e) { + throw e.setUnfinishedMessage(this); + } catch (java.io.IOException e) { + throw new com.google.protobuf.InvalidProtocolBufferException( + e.getMessage()).setUnfinishedMessage(this); + } finally { + try { + unknownFieldsCodedOutput.flush(); + } catch (java.io.IOException e) { + // Should not happen + } finally { + unknownFields = unknownFieldsOutput.toByteString(); + } + makeExtensionsImmutable(); + } + } + public static com.google.protobuf.Parser PARSER = + new com.google.protobuf.AbstractParser() { + public IMRemoveSessionReq parsePartialFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return new IMRemoveSessionReq(input, extensionRegistry); + } + }; + + @java.lang.Override + public com.google.protobuf.Parser getParserForType() { + return PARSER; + } + + private int bitField0_; + public static final int USER_ID_FIELD_NUMBER = 1; + private int userId_; + /** + * required uint32 user_id = 1; + * + *
+     *cmd id:		0x0206
+     * 
+ */ + public boolean hasUserId() { + return ((bitField0_ & 0x00000001) == 0x00000001); + } + /** + * required uint32 user_id = 1; + * + *
+     *cmd id:		0x0206
+     * 
+ */ + public int getUserId() { + return userId_; + } + + public static final int SESSION_TYPE_FIELD_NUMBER = 2; + private com.mogujie.tt.protobuf.IMBaseDefine.SessionType sessionType_; + /** + * required .IM.BaseDefine.SessionType session_type = 2; + */ + public boolean hasSessionType() { + return ((bitField0_ & 0x00000002) == 0x00000002); + } + /** + * required .IM.BaseDefine.SessionType session_type = 2; + */ + public com.mogujie.tt.protobuf.IMBaseDefine.SessionType getSessionType() { + return sessionType_; + } + + public static final int SESSION_ID_FIELD_NUMBER = 3; + private int sessionId_; + /** + * required uint32 session_id = 3; + */ + public boolean hasSessionId() { + return ((bitField0_ & 0x00000004) == 0x00000004); + } + /** + * required uint32 session_id = 3; + */ + public int getSessionId() { + return sessionId_; + } + + public static final int ATTACH_DATA_FIELD_NUMBER = 20; + private com.google.protobuf.ByteString attachData_; + /** + * optional bytes attach_data = 20; + */ + public boolean hasAttachData() { + return ((bitField0_ & 0x00000008) == 0x00000008); + } + /** + * optional bytes attach_data = 20; + */ + public com.google.protobuf.ByteString getAttachData() { + return attachData_; + } + + private void initFields() { + userId_ = 0; + sessionType_ = com.mogujie.tt.protobuf.IMBaseDefine.SessionType.SESSION_TYPE_SINGLE; + sessionId_ = 0; + attachData_ = com.google.protobuf.ByteString.EMPTY; + } + private byte memoizedIsInitialized = -1; + public final boolean isInitialized() { + byte isInitialized = memoizedIsInitialized; + if (isInitialized == 1) return true; + if (isInitialized == 0) return false; + + if (!hasUserId()) { + memoizedIsInitialized = 0; + return false; + } + if (!hasSessionType()) { + memoizedIsInitialized = 0; + return false; + } + if (!hasSessionId()) { + memoizedIsInitialized = 0; + return false; + } + memoizedIsInitialized = 1; + return true; + } + + public void writeTo(com.google.protobuf.CodedOutputStream output) + throws java.io.IOException { + getSerializedSize(); + if (((bitField0_ & 0x00000001) == 0x00000001)) { + output.writeUInt32(1, userId_); + } + if (((bitField0_ & 0x00000002) == 0x00000002)) { + output.writeEnum(2, sessionType_.getNumber()); + } + if (((bitField0_ & 0x00000004) == 0x00000004)) { + output.writeUInt32(3, sessionId_); + } + if (((bitField0_ & 0x00000008) == 0x00000008)) { + output.writeBytes(20, attachData_); + } + output.writeRawBytes(unknownFields); + } + + private int memoizedSerializedSize = -1; + public int getSerializedSize() { + int size = memoizedSerializedSize; + if (size != -1) return size; + + size = 0; + if (((bitField0_ & 0x00000001) == 0x00000001)) { + size += com.google.protobuf.CodedOutputStream + .computeUInt32Size(1, userId_); + } + if (((bitField0_ & 0x00000002) == 0x00000002)) { + size += com.google.protobuf.CodedOutputStream + .computeEnumSize(2, sessionType_.getNumber()); + } + if (((bitField0_ & 0x00000004) == 0x00000004)) { + size += com.google.protobuf.CodedOutputStream + .computeUInt32Size(3, sessionId_); + } + if (((bitField0_ & 0x00000008) == 0x00000008)) { + size += com.google.protobuf.CodedOutputStream + .computeBytesSize(20, attachData_); + } + size += unknownFields.size(); + memoizedSerializedSize = size; + return size; + } + + private static final long serialVersionUID = 0L; + @java.lang.Override + protected java.lang.Object writeReplace() + throws java.io.ObjectStreamException { + return super.writeReplace(); + } + + public static com.mogujie.tt.protobuf.IMBuddy.IMRemoveSessionReq parseFrom( + com.google.protobuf.ByteString data) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data); + } + public static com.mogujie.tt.protobuf.IMBuddy.IMRemoveSessionReq parseFrom( + com.google.protobuf.ByteString data, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data, extensionRegistry); + } + public static com.mogujie.tt.protobuf.IMBuddy.IMRemoveSessionReq parseFrom(byte[] data) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data); + } + public static com.mogujie.tt.protobuf.IMBuddy.IMRemoveSessionReq parseFrom( + byte[] data, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data, extensionRegistry); + } + public static com.mogujie.tt.protobuf.IMBuddy.IMRemoveSessionReq parseFrom(java.io.InputStream input) + throws java.io.IOException { + return PARSER.parseFrom(input); + } + public static com.mogujie.tt.protobuf.IMBuddy.IMRemoveSessionReq parseFrom( + java.io.InputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return PARSER.parseFrom(input, extensionRegistry); + } + public static com.mogujie.tt.protobuf.IMBuddy.IMRemoveSessionReq parseDelimitedFrom(java.io.InputStream input) + throws java.io.IOException { + return PARSER.parseDelimitedFrom(input); + } + public static com.mogujie.tt.protobuf.IMBuddy.IMRemoveSessionReq parseDelimitedFrom( + java.io.InputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return PARSER.parseDelimitedFrom(input, extensionRegistry); + } + public static com.mogujie.tt.protobuf.IMBuddy.IMRemoveSessionReq parseFrom( + com.google.protobuf.CodedInputStream input) + throws java.io.IOException { + return PARSER.parseFrom(input); + } + public static com.mogujie.tt.protobuf.IMBuddy.IMRemoveSessionReq parseFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return PARSER.parseFrom(input, extensionRegistry); + } + + public static Builder newBuilder() { return Builder.create(); } + public Builder newBuilderForType() { return newBuilder(); } + public static Builder newBuilder(com.mogujie.tt.protobuf.IMBuddy.IMRemoveSessionReq prototype) { + return newBuilder().mergeFrom(prototype); + } + public Builder toBuilder() { return newBuilder(this); } + + /** + * Protobuf type {@code IM.Buddy.IMRemoveSessionReq} + */ + public static final class Builder extends + com.google.protobuf.GeneratedMessageLite.Builder< + com.mogujie.tt.protobuf.IMBuddy.IMRemoveSessionReq, Builder> + implements + // @@protoc_insertion_point(builder_implements:IM.Buddy.IMRemoveSessionReq) + com.mogujie.tt.protobuf.IMBuddy.IMRemoveSessionReqOrBuilder { + // Construct using com.mogujie.tt.protobuf.IMBuddy.IMRemoveSessionReq.newBuilder() + private Builder() { + maybeForceBuilderInitialization(); + } + + private void maybeForceBuilderInitialization() { + } + private static Builder create() { + return new Builder(); + } + + public Builder clear() { + super.clear(); + userId_ = 0; + bitField0_ = (bitField0_ & ~0x00000001); + sessionType_ = com.mogujie.tt.protobuf.IMBaseDefine.SessionType.SESSION_TYPE_SINGLE; + bitField0_ = (bitField0_ & ~0x00000002); + sessionId_ = 0; + bitField0_ = (bitField0_ & ~0x00000004); + attachData_ = com.google.protobuf.ByteString.EMPTY; + bitField0_ = (bitField0_ & ~0x00000008); + return this; + } + + public Builder clone() { + return create().mergeFrom(buildPartial()); + } + + public com.mogujie.tt.protobuf.IMBuddy.IMRemoveSessionReq getDefaultInstanceForType() { + return com.mogujie.tt.protobuf.IMBuddy.IMRemoveSessionReq.getDefaultInstance(); + } + + public com.mogujie.tt.protobuf.IMBuddy.IMRemoveSessionReq build() { + com.mogujie.tt.protobuf.IMBuddy.IMRemoveSessionReq result = buildPartial(); + if (!result.isInitialized()) { + throw newUninitializedMessageException(result); + } + return result; + } + + public com.mogujie.tt.protobuf.IMBuddy.IMRemoveSessionReq buildPartial() { + com.mogujie.tt.protobuf.IMBuddy.IMRemoveSessionReq result = new com.mogujie.tt.protobuf.IMBuddy.IMRemoveSessionReq(this); + int from_bitField0_ = bitField0_; + int to_bitField0_ = 0; + if (((from_bitField0_ & 0x00000001) == 0x00000001)) { + to_bitField0_ |= 0x00000001; + } + result.userId_ = userId_; + if (((from_bitField0_ & 0x00000002) == 0x00000002)) { + to_bitField0_ |= 0x00000002; + } + result.sessionType_ = sessionType_; + if (((from_bitField0_ & 0x00000004) == 0x00000004)) { + to_bitField0_ |= 0x00000004; + } + result.sessionId_ = sessionId_; + if (((from_bitField0_ & 0x00000008) == 0x00000008)) { + to_bitField0_ |= 0x00000008; + } + result.attachData_ = attachData_; + result.bitField0_ = to_bitField0_; + return result; + } + + public Builder mergeFrom(com.mogujie.tt.protobuf.IMBuddy.IMRemoveSessionReq other) { + if (other == com.mogujie.tt.protobuf.IMBuddy.IMRemoveSessionReq.getDefaultInstance()) return this; + if (other.hasUserId()) { + setUserId(other.getUserId()); + } + if (other.hasSessionType()) { + setSessionType(other.getSessionType()); + } + if (other.hasSessionId()) { + setSessionId(other.getSessionId()); + } + if (other.hasAttachData()) { + setAttachData(other.getAttachData()); + } + setUnknownFields( + getUnknownFields().concat(other.unknownFields)); + return this; + } + + public final boolean isInitialized() { + if (!hasUserId()) { + + return false; + } + if (!hasSessionType()) { + + return false; + } + if (!hasSessionId()) { + + return false; + } + return true; + } + + public Builder mergeFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + com.mogujie.tt.protobuf.IMBuddy.IMRemoveSessionReq parsedMessage = null; + try { + parsedMessage = PARSER.parsePartialFrom(input, extensionRegistry); + } catch (com.google.protobuf.InvalidProtocolBufferException e) { + parsedMessage = (com.mogujie.tt.protobuf.IMBuddy.IMRemoveSessionReq) e.getUnfinishedMessage(); + throw e; + } finally { + if (parsedMessage != null) { + mergeFrom(parsedMessage); + } + } + return this; + } + private int bitField0_; + + private int userId_ ; + /** + * required uint32 user_id = 1; + * + *
+       *cmd id:		0x0206
+       * 
+ */ + public boolean hasUserId() { + return ((bitField0_ & 0x00000001) == 0x00000001); + } + /** + * required uint32 user_id = 1; + * + *
+       *cmd id:		0x0206
+       * 
+ */ + public int getUserId() { + return userId_; + } + /** + * required uint32 user_id = 1; + * + *
+       *cmd id:		0x0206
+       * 
+ */ + public Builder setUserId(int value) { + bitField0_ |= 0x00000001; + userId_ = value; + + return this; + } + /** + * required uint32 user_id = 1; + * + *
+       *cmd id:		0x0206
+       * 
+ */ + public Builder clearUserId() { + bitField0_ = (bitField0_ & ~0x00000001); + userId_ = 0; + + return this; + } + + private com.mogujie.tt.protobuf.IMBaseDefine.SessionType sessionType_ = com.mogujie.tt.protobuf.IMBaseDefine.SessionType.SESSION_TYPE_SINGLE; + /** + * required .IM.BaseDefine.SessionType session_type = 2; + */ + public boolean hasSessionType() { + return ((bitField0_ & 0x00000002) == 0x00000002); + } + /** + * required .IM.BaseDefine.SessionType session_type = 2; + */ + public com.mogujie.tt.protobuf.IMBaseDefine.SessionType getSessionType() { + return sessionType_; + } + /** + * required .IM.BaseDefine.SessionType session_type = 2; + */ + public Builder setSessionType(com.mogujie.tt.protobuf.IMBaseDefine.SessionType value) { + if (value == null) { + throw new NullPointerException(); + } + bitField0_ |= 0x00000002; + sessionType_ = value; + + return this; + } + /** + * required .IM.BaseDefine.SessionType session_type = 2; + */ + public Builder clearSessionType() { + bitField0_ = (bitField0_ & ~0x00000002); + sessionType_ = com.mogujie.tt.protobuf.IMBaseDefine.SessionType.SESSION_TYPE_SINGLE; + + return this; + } + + private int sessionId_ ; + /** + * required uint32 session_id = 3; + */ + public boolean hasSessionId() { + return ((bitField0_ & 0x00000004) == 0x00000004); + } + /** + * required uint32 session_id = 3; + */ + public int getSessionId() { + return sessionId_; + } + /** + * required uint32 session_id = 3; + */ + public Builder setSessionId(int value) { + bitField0_ |= 0x00000004; + sessionId_ = value; + + return this; + } + /** + * required uint32 session_id = 3; + */ + public Builder clearSessionId() { + bitField0_ = (bitField0_ & ~0x00000004); + sessionId_ = 0; + + return this; + } + + private com.google.protobuf.ByteString attachData_ = com.google.protobuf.ByteString.EMPTY; + /** + * optional bytes attach_data = 20; + */ + public boolean hasAttachData() { + return ((bitField0_ & 0x00000008) == 0x00000008); + } + /** + * optional bytes attach_data = 20; + */ + public com.google.protobuf.ByteString getAttachData() { + return attachData_; + } + /** + * optional bytes attach_data = 20; + */ + public Builder setAttachData(com.google.protobuf.ByteString value) { + if (value == null) { + throw new NullPointerException(); + } + bitField0_ |= 0x00000008; + attachData_ = value; + + return this; + } + /** + * optional bytes attach_data = 20; + */ + public Builder clearAttachData() { + bitField0_ = (bitField0_ & ~0x00000008); + attachData_ = getDefaultInstance().getAttachData(); + + return this; + } + + // @@protoc_insertion_point(builder_scope:IM.Buddy.IMRemoveSessionReq) + } + + static { + defaultInstance = new IMRemoveSessionReq(true); + defaultInstance.initFields(); + } + + // @@protoc_insertion_point(class_scope:IM.Buddy.IMRemoveSessionReq) + } + + public interface IMRemoveSessionRspOrBuilder extends + // @@protoc_insertion_point(interface_extends:IM.Buddy.IMRemoveSessionRsp) + com.google.protobuf.MessageLiteOrBuilder { + + /** + * required uint32 user_id = 1; + * + *
+     *cmd id:		0x0207
+     * 
+ */ + boolean hasUserId(); + /** + * required uint32 user_id = 1; + * + *
+     *cmd id:		0x0207
+     * 
+ */ + int getUserId(); + + /** + * required uint32 result_code = 2; + */ + boolean hasResultCode(); + /** + * required uint32 result_code = 2; + */ + int getResultCode(); + + /** + * required .IM.BaseDefine.SessionType session_type = 3; + */ + boolean hasSessionType(); + /** + * required .IM.BaseDefine.SessionType session_type = 3; + */ + com.mogujie.tt.protobuf.IMBaseDefine.SessionType getSessionType(); + + /** + * required uint32 session_id = 4; + */ + boolean hasSessionId(); + /** + * required uint32 session_id = 4; + */ + int getSessionId(); + + /** + * optional bytes attach_data = 20; + */ + boolean hasAttachData(); + /** + * optional bytes attach_data = 20; + */ + com.google.protobuf.ByteString getAttachData(); + } + /** + * Protobuf type {@code IM.Buddy.IMRemoveSessionRsp} + */ + public static final class IMRemoveSessionRsp extends + com.google.protobuf.GeneratedMessageLite implements + // @@protoc_insertion_point(message_implements:IM.Buddy.IMRemoveSessionRsp) + IMRemoveSessionRspOrBuilder { + // Use IMRemoveSessionRsp.newBuilder() to construct. + private IMRemoveSessionRsp(com.google.protobuf.GeneratedMessageLite.Builder builder) { + super(builder); + this.unknownFields = builder.getUnknownFields(); + } + private IMRemoveSessionRsp(boolean noInit) { this.unknownFields = com.google.protobuf.ByteString.EMPTY;} + + private static final IMRemoveSessionRsp defaultInstance; + public static IMRemoveSessionRsp getDefaultInstance() { + return defaultInstance; + } + + public IMRemoveSessionRsp getDefaultInstanceForType() { + return defaultInstance; + } + + private final com.google.protobuf.ByteString unknownFields; + private IMRemoveSessionRsp( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + initFields(); + int mutable_bitField0_ = 0; + com.google.protobuf.ByteString.Output unknownFieldsOutput = + com.google.protobuf.ByteString.newOutput(); + com.google.protobuf.CodedOutputStream unknownFieldsCodedOutput = + com.google.protobuf.CodedOutputStream.newInstance( + unknownFieldsOutput); + try { + boolean done = false; + while (!done) { + int tag = input.readTag(); + switch (tag) { + case 0: + done = true; + break; + default: { + if (!parseUnknownField(input, unknownFieldsCodedOutput, + extensionRegistry, tag)) { + done = true; + } + break; + } + case 8: { + bitField0_ |= 0x00000001; + userId_ = input.readUInt32(); + break; + } + case 16: { + bitField0_ |= 0x00000002; + resultCode_ = input.readUInt32(); + break; + } + case 24: { + int rawValue = input.readEnum(); + com.mogujie.tt.protobuf.IMBaseDefine.SessionType value = com.mogujie.tt.protobuf.IMBaseDefine.SessionType.valueOf(rawValue); + if (value == null) { + unknownFieldsCodedOutput.writeRawVarint32(tag); + unknownFieldsCodedOutput.writeRawVarint32(rawValue); + } else { + bitField0_ |= 0x00000004; + sessionType_ = value; + } + break; + } + case 32: { + bitField0_ |= 0x00000008; + sessionId_ = input.readUInt32(); + break; + } + case 162: { + bitField0_ |= 0x00000010; + attachData_ = input.readBytes(); + break; + } + } + } + } catch (com.google.protobuf.InvalidProtocolBufferException e) { + throw e.setUnfinishedMessage(this); + } catch (java.io.IOException e) { + throw new com.google.protobuf.InvalidProtocolBufferException( + e.getMessage()).setUnfinishedMessage(this); + } finally { + try { + unknownFieldsCodedOutput.flush(); + } catch (java.io.IOException e) { + // Should not happen + } finally { + unknownFields = unknownFieldsOutput.toByteString(); + } + makeExtensionsImmutable(); + } + } + public static com.google.protobuf.Parser PARSER = + new com.google.protobuf.AbstractParser() { + public IMRemoveSessionRsp parsePartialFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return new IMRemoveSessionRsp(input, extensionRegistry); + } + }; + + @java.lang.Override + public com.google.protobuf.Parser getParserForType() { + return PARSER; + } + + private int bitField0_; + public static final int USER_ID_FIELD_NUMBER = 1; + private int userId_; + /** + * required uint32 user_id = 1; + * + *
+     *cmd id:		0x0207
+     * 
+ */ + public boolean hasUserId() { + return ((bitField0_ & 0x00000001) == 0x00000001); + } + /** + * required uint32 user_id = 1; + * + *
+     *cmd id:		0x0207
+     * 
+ */ + public int getUserId() { + return userId_; + } + + public static final int RESULT_CODE_FIELD_NUMBER = 2; + private int resultCode_; + /** + * required uint32 result_code = 2; + */ + public boolean hasResultCode() { + return ((bitField0_ & 0x00000002) == 0x00000002); + } + /** + * required uint32 result_code = 2; + */ + public int getResultCode() { + return resultCode_; + } + + public static final int SESSION_TYPE_FIELD_NUMBER = 3; + private com.mogujie.tt.protobuf.IMBaseDefine.SessionType sessionType_; + /** + * required .IM.BaseDefine.SessionType session_type = 3; + */ + public boolean hasSessionType() { + return ((bitField0_ & 0x00000004) == 0x00000004); + } + /** + * required .IM.BaseDefine.SessionType session_type = 3; + */ + public com.mogujie.tt.protobuf.IMBaseDefine.SessionType getSessionType() { + return sessionType_; + } + + public static final int SESSION_ID_FIELD_NUMBER = 4; + private int sessionId_; + /** + * required uint32 session_id = 4; + */ + public boolean hasSessionId() { + return ((bitField0_ & 0x00000008) == 0x00000008); + } + /** + * required uint32 session_id = 4; + */ + public int getSessionId() { + return sessionId_; + } + + public static final int ATTACH_DATA_FIELD_NUMBER = 20; + private com.google.protobuf.ByteString attachData_; + /** + * optional bytes attach_data = 20; + */ + public boolean hasAttachData() { + return ((bitField0_ & 0x00000010) == 0x00000010); + } + /** + * optional bytes attach_data = 20; + */ + public com.google.protobuf.ByteString getAttachData() { + return attachData_; + } + + private void initFields() { + userId_ = 0; + resultCode_ = 0; + sessionType_ = com.mogujie.tt.protobuf.IMBaseDefine.SessionType.SESSION_TYPE_SINGLE; + sessionId_ = 0; + attachData_ = com.google.protobuf.ByteString.EMPTY; + } + private byte memoizedIsInitialized = -1; + public final boolean isInitialized() { + byte isInitialized = memoizedIsInitialized; + if (isInitialized == 1) return true; + if (isInitialized == 0) return false; + + if (!hasUserId()) { + memoizedIsInitialized = 0; + return false; + } + if (!hasResultCode()) { + memoizedIsInitialized = 0; + return false; + } + if (!hasSessionType()) { + memoizedIsInitialized = 0; + return false; + } + if (!hasSessionId()) { + memoizedIsInitialized = 0; + return false; + } + memoizedIsInitialized = 1; + return true; + } + + public void writeTo(com.google.protobuf.CodedOutputStream output) + throws java.io.IOException { + getSerializedSize(); + if (((bitField0_ & 0x00000001) == 0x00000001)) { + output.writeUInt32(1, userId_); + } + if (((bitField0_ & 0x00000002) == 0x00000002)) { + output.writeUInt32(2, resultCode_); + } + if (((bitField0_ & 0x00000004) == 0x00000004)) { + output.writeEnum(3, sessionType_.getNumber()); + } + if (((bitField0_ & 0x00000008) == 0x00000008)) { + output.writeUInt32(4, sessionId_); + } + if (((bitField0_ & 0x00000010) == 0x00000010)) { + output.writeBytes(20, attachData_); + } + output.writeRawBytes(unknownFields); + } + + private int memoizedSerializedSize = -1; + public int getSerializedSize() { + int size = memoizedSerializedSize; + if (size != -1) return size; + + size = 0; + if (((bitField0_ & 0x00000001) == 0x00000001)) { + size += com.google.protobuf.CodedOutputStream + .computeUInt32Size(1, userId_); + } + if (((bitField0_ & 0x00000002) == 0x00000002)) { + size += com.google.protobuf.CodedOutputStream + .computeUInt32Size(2, resultCode_); + } + if (((bitField0_ & 0x00000004) == 0x00000004)) { + size += com.google.protobuf.CodedOutputStream + .computeEnumSize(3, sessionType_.getNumber()); + } + if (((bitField0_ & 0x00000008) == 0x00000008)) { + size += com.google.protobuf.CodedOutputStream + .computeUInt32Size(4, sessionId_); + } + if (((bitField0_ & 0x00000010) == 0x00000010)) { + size += com.google.protobuf.CodedOutputStream + .computeBytesSize(20, attachData_); + } + size += unknownFields.size(); + memoizedSerializedSize = size; + return size; + } + + private static final long serialVersionUID = 0L; + @java.lang.Override + protected java.lang.Object writeReplace() + throws java.io.ObjectStreamException { + return super.writeReplace(); + } + + public static com.mogujie.tt.protobuf.IMBuddy.IMRemoveSessionRsp parseFrom( + com.google.protobuf.ByteString data) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data); + } + public static com.mogujie.tt.protobuf.IMBuddy.IMRemoveSessionRsp parseFrom( + com.google.protobuf.ByteString data, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data, extensionRegistry); + } + public static com.mogujie.tt.protobuf.IMBuddy.IMRemoveSessionRsp parseFrom(byte[] data) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data); + } + public static com.mogujie.tt.protobuf.IMBuddy.IMRemoveSessionRsp parseFrom( + byte[] data, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data, extensionRegistry); + } + public static com.mogujie.tt.protobuf.IMBuddy.IMRemoveSessionRsp parseFrom(java.io.InputStream input) + throws java.io.IOException { + return PARSER.parseFrom(input); + } + public static com.mogujie.tt.protobuf.IMBuddy.IMRemoveSessionRsp parseFrom( + java.io.InputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return PARSER.parseFrom(input, extensionRegistry); + } + public static com.mogujie.tt.protobuf.IMBuddy.IMRemoveSessionRsp parseDelimitedFrom(java.io.InputStream input) + throws java.io.IOException { + return PARSER.parseDelimitedFrom(input); + } + public static com.mogujie.tt.protobuf.IMBuddy.IMRemoveSessionRsp parseDelimitedFrom( + java.io.InputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return PARSER.parseDelimitedFrom(input, extensionRegistry); + } + public static com.mogujie.tt.protobuf.IMBuddy.IMRemoveSessionRsp parseFrom( + com.google.protobuf.CodedInputStream input) + throws java.io.IOException { + return PARSER.parseFrom(input); + } + public static com.mogujie.tt.protobuf.IMBuddy.IMRemoveSessionRsp parseFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return PARSER.parseFrom(input, extensionRegistry); + } + + public static Builder newBuilder() { return Builder.create(); } + public Builder newBuilderForType() { return newBuilder(); } + public static Builder newBuilder(com.mogujie.tt.protobuf.IMBuddy.IMRemoveSessionRsp prototype) { + return newBuilder().mergeFrom(prototype); + } + public Builder toBuilder() { return newBuilder(this); } + + /** + * Protobuf type {@code IM.Buddy.IMRemoveSessionRsp} + */ + public static final class Builder extends + com.google.protobuf.GeneratedMessageLite.Builder< + com.mogujie.tt.protobuf.IMBuddy.IMRemoveSessionRsp, Builder> + implements + // @@protoc_insertion_point(builder_implements:IM.Buddy.IMRemoveSessionRsp) + com.mogujie.tt.protobuf.IMBuddy.IMRemoveSessionRspOrBuilder { + // Construct using com.mogujie.tt.protobuf.IMBuddy.IMRemoveSessionRsp.newBuilder() + private Builder() { + maybeForceBuilderInitialization(); + } + + private void maybeForceBuilderInitialization() { + } + private static Builder create() { + return new Builder(); + } + + public Builder clear() { + super.clear(); + userId_ = 0; + bitField0_ = (bitField0_ & ~0x00000001); + resultCode_ = 0; + bitField0_ = (bitField0_ & ~0x00000002); + sessionType_ = com.mogujie.tt.protobuf.IMBaseDefine.SessionType.SESSION_TYPE_SINGLE; + bitField0_ = (bitField0_ & ~0x00000004); + sessionId_ = 0; + bitField0_ = (bitField0_ & ~0x00000008); + attachData_ = com.google.protobuf.ByteString.EMPTY; + bitField0_ = (bitField0_ & ~0x00000010); + return this; + } + + public Builder clone() { + return create().mergeFrom(buildPartial()); + } + + public com.mogujie.tt.protobuf.IMBuddy.IMRemoveSessionRsp getDefaultInstanceForType() { + return com.mogujie.tt.protobuf.IMBuddy.IMRemoveSessionRsp.getDefaultInstance(); + } + + public com.mogujie.tt.protobuf.IMBuddy.IMRemoveSessionRsp build() { + com.mogujie.tt.protobuf.IMBuddy.IMRemoveSessionRsp result = buildPartial(); + if (!result.isInitialized()) { + throw newUninitializedMessageException(result); + } + return result; + } + + public com.mogujie.tt.protobuf.IMBuddy.IMRemoveSessionRsp buildPartial() { + com.mogujie.tt.protobuf.IMBuddy.IMRemoveSessionRsp result = new com.mogujie.tt.protobuf.IMBuddy.IMRemoveSessionRsp(this); + int from_bitField0_ = bitField0_; + int to_bitField0_ = 0; + if (((from_bitField0_ & 0x00000001) == 0x00000001)) { + to_bitField0_ |= 0x00000001; + } + result.userId_ = userId_; + if (((from_bitField0_ & 0x00000002) == 0x00000002)) { + to_bitField0_ |= 0x00000002; + } + result.resultCode_ = resultCode_; + if (((from_bitField0_ & 0x00000004) == 0x00000004)) { + to_bitField0_ |= 0x00000004; + } + result.sessionType_ = sessionType_; + if (((from_bitField0_ & 0x00000008) == 0x00000008)) { + to_bitField0_ |= 0x00000008; + } + result.sessionId_ = sessionId_; + if (((from_bitField0_ & 0x00000010) == 0x00000010)) { + to_bitField0_ |= 0x00000010; + } + result.attachData_ = attachData_; + result.bitField0_ = to_bitField0_; + return result; + } + + public Builder mergeFrom(com.mogujie.tt.protobuf.IMBuddy.IMRemoveSessionRsp other) { + if (other == com.mogujie.tt.protobuf.IMBuddy.IMRemoveSessionRsp.getDefaultInstance()) return this; + if (other.hasUserId()) { + setUserId(other.getUserId()); + } + if (other.hasResultCode()) { + setResultCode(other.getResultCode()); + } + if (other.hasSessionType()) { + setSessionType(other.getSessionType()); + } + if (other.hasSessionId()) { + setSessionId(other.getSessionId()); + } + if (other.hasAttachData()) { + setAttachData(other.getAttachData()); + } + setUnknownFields( + getUnknownFields().concat(other.unknownFields)); + return this; + } + + public final boolean isInitialized() { + if (!hasUserId()) { + + return false; + } + if (!hasResultCode()) { + + return false; + } + if (!hasSessionType()) { + + return false; + } + if (!hasSessionId()) { + + return false; + } + return true; + } + + public Builder mergeFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + com.mogujie.tt.protobuf.IMBuddy.IMRemoveSessionRsp parsedMessage = null; + try { + parsedMessage = PARSER.parsePartialFrom(input, extensionRegistry); + } catch (com.google.protobuf.InvalidProtocolBufferException e) { + parsedMessage = (com.mogujie.tt.protobuf.IMBuddy.IMRemoveSessionRsp) e.getUnfinishedMessage(); + throw e; + } finally { + if (parsedMessage != null) { + mergeFrom(parsedMessage); + } + } + return this; + } + private int bitField0_; + + private int userId_ ; + /** + * required uint32 user_id = 1; + * + *
+       *cmd id:		0x0207
+       * 
+ */ + public boolean hasUserId() { + return ((bitField0_ & 0x00000001) == 0x00000001); + } + /** + * required uint32 user_id = 1; + * + *
+       *cmd id:		0x0207
+       * 
+ */ + public int getUserId() { + return userId_; + } + /** + * required uint32 user_id = 1; + * + *
+       *cmd id:		0x0207
+       * 
+ */ + public Builder setUserId(int value) { + bitField0_ |= 0x00000001; + userId_ = value; + + return this; + } + /** + * required uint32 user_id = 1; + * + *
+       *cmd id:		0x0207
+       * 
+ */ + public Builder clearUserId() { + bitField0_ = (bitField0_ & ~0x00000001); + userId_ = 0; + + return this; + } + + private int resultCode_ ; + /** + * required uint32 result_code = 2; + */ + public boolean hasResultCode() { + return ((bitField0_ & 0x00000002) == 0x00000002); + } + /** + * required uint32 result_code = 2; + */ + public int getResultCode() { + return resultCode_; + } + /** + * required uint32 result_code = 2; + */ + public Builder setResultCode(int value) { + bitField0_ |= 0x00000002; + resultCode_ = value; + + return this; + } + /** + * required uint32 result_code = 2; + */ + public Builder clearResultCode() { + bitField0_ = (bitField0_ & ~0x00000002); + resultCode_ = 0; + + return this; + } + + private com.mogujie.tt.protobuf.IMBaseDefine.SessionType sessionType_ = com.mogujie.tt.protobuf.IMBaseDefine.SessionType.SESSION_TYPE_SINGLE; + /** + * required .IM.BaseDefine.SessionType session_type = 3; + */ + public boolean hasSessionType() { + return ((bitField0_ & 0x00000004) == 0x00000004); + } + /** + * required .IM.BaseDefine.SessionType session_type = 3; + */ + public com.mogujie.tt.protobuf.IMBaseDefine.SessionType getSessionType() { + return sessionType_; + } + /** + * required .IM.BaseDefine.SessionType session_type = 3; + */ + public Builder setSessionType(com.mogujie.tt.protobuf.IMBaseDefine.SessionType value) { + if (value == null) { + throw new NullPointerException(); + } + bitField0_ |= 0x00000004; + sessionType_ = value; + + return this; + } + /** + * required .IM.BaseDefine.SessionType session_type = 3; + */ + public Builder clearSessionType() { + bitField0_ = (bitField0_ & ~0x00000004); + sessionType_ = com.mogujie.tt.protobuf.IMBaseDefine.SessionType.SESSION_TYPE_SINGLE; + + return this; + } + + private int sessionId_ ; + /** + * required uint32 session_id = 4; + */ + public boolean hasSessionId() { + return ((bitField0_ & 0x00000008) == 0x00000008); + } + /** + * required uint32 session_id = 4; + */ + public int getSessionId() { + return sessionId_; + } + /** + * required uint32 session_id = 4; + */ + public Builder setSessionId(int value) { + bitField0_ |= 0x00000008; + sessionId_ = value; + + return this; + } + /** + * required uint32 session_id = 4; + */ + public Builder clearSessionId() { + bitField0_ = (bitField0_ & ~0x00000008); + sessionId_ = 0; + + return this; + } + + private com.google.protobuf.ByteString attachData_ = com.google.protobuf.ByteString.EMPTY; + /** + * optional bytes attach_data = 20; + */ + public boolean hasAttachData() { + return ((bitField0_ & 0x00000010) == 0x00000010); + } + /** + * optional bytes attach_data = 20; + */ + public com.google.protobuf.ByteString getAttachData() { + return attachData_; + } + /** + * optional bytes attach_data = 20; + */ + public Builder setAttachData(com.google.protobuf.ByteString value) { + if (value == null) { + throw new NullPointerException(); + } + bitField0_ |= 0x00000010; + attachData_ = value; + + return this; + } + /** + * optional bytes attach_data = 20; + */ + public Builder clearAttachData() { + bitField0_ = (bitField0_ & ~0x00000010); + attachData_ = getDefaultInstance().getAttachData(); + + return this; + } + + // @@protoc_insertion_point(builder_scope:IM.Buddy.IMRemoveSessionRsp) + } + + static { + defaultInstance = new IMRemoveSessionRsp(true); + defaultInstance.initFields(); + } + + // @@protoc_insertion_point(class_scope:IM.Buddy.IMRemoveSessionRsp) + } + + public interface IMAllUserReqOrBuilder extends + // @@protoc_insertion_point(interface_extends:IM.Buddy.IMAllUserReq) + com.google.protobuf.MessageLiteOrBuilder { + + /** + * required uint32 user_id = 1; + * + *
+     *cmd id:		0x0208
+     * 
+ */ + boolean hasUserId(); + /** + * required uint32 user_id = 1; + * + *
+     *cmd id:		0x0208
+     * 
+ */ + int getUserId(); + + /** + * required uint32 latest_update_time = 2; + */ + boolean hasLatestUpdateTime(); + /** + * required uint32 latest_update_time = 2; + */ + int getLatestUpdateTime(); + + /** + * optional bytes attach_data = 20; + */ + boolean hasAttachData(); + /** + * optional bytes attach_data = 20; + */ + com.google.protobuf.ByteString getAttachData(); + } + /** + * Protobuf type {@code IM.Buddy.IMAllUserReq} + */ + public static final class IMAllUserReq extends + com.google.protobuf.GeneratedMessageLite implements + // @@protoc_insertion_point(message_implements:IM.Buddy.IMAllUserReq) + IMAllUserReqOrBuilder { + // Use IMAllUserReq.newBuilder() to construct. + private IMAllUserReq(com.google.protobuf.GeneratedMessageLite.Builder builder) { + super(builder); + this.unknownFields = builder.getUnknownFields(); + } + private IMAllUserReq(boolean noInit) { this.unknownFields = com.google.protobuf.ByteString.EMPTY;} + + private static final IMAllUserReq defaultInstance; + public static IMAllUserReq getDefaultInstance() { + return defaultInstance; + } + + public IMAllUserReq getDefaultInstanceForType() { + return defaultInstance; + } + + private final com.google.protobuf.ByteString unknownFields; + private IMAllUserReq( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + initFields(); + int mutable_bitField0_ = 0; + com.google.protobuf.ByteString.Output unknownFieldsOutput = + com.google.protobuf.ByteString.newOutput(); + com.google.protobuf.CodedOutputStream unknownFieldsCodedOutput = + com.google.protobuf.CodedOutputStream.newInstance( + unknownFieldsOutput); + try { + boolean done = false; + while (!done) { + int tag = input.readTag(); + switch (tag) { + case 0: + done = true; + break; + default: { + if (!parseUnknownField(input, unknownFieldsCodedOutput, + extensionRegistry, tag)) { + done = true; + } + break; + } + case 8: { + bitField0_ |= 0x00000001; + userId_ = input.readUInt32(); + break; + } + case 16: { + bitField0_ |= 0x00000002; + latestUpdateTime_ = input.readUInt32(); + break; + } + case 162: { + bitField0_ |= 0x00000004; + attachData_ = input.readBytes(); + break; + } + } + } + } catch (com.google.protobuf.InvalidProtocolBufferException e) { + throw e.setUnfinishedMessage(this); + } catch (java.io.IOException e) { + throw new com.google.protobuf.InvalidProtocolBufferException( + e.getMessage()).setUnfinishedMessage(this); + } finally { + try { + unknownFieldsCodedOutput.flush(); + } catch (java.io.IOException e) { + // Should not happen + } finally { + unknownFields = unknownFieldsOutput.toByteString(); + } + makeExtensionsImmutable(); + } + } + public static com.google.protobuf.Parser PARSER = + new com.google.protobuf.AbstractParser() { + public IMAllUserReq parsePartialFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return new IMAllUserReq(input, extensionRegistry); + } + }; + + @java.lang.Override + public com.google.protobuf.Parser getParserForType() { + return PARSER; + } + + private int bitField0_; + public static final int USER_ID_FIELD_NUMBER = 1; + private int userId_; + /** + * required uint32 user_id = 1; + * + *
+     *cmd id:		0x0208
+     * 
+ */ + public boolean hasUserId() { + return ((bitField0_ & 0x00000001) == 0x00000001); + } + /** + * required uint32 user_id = 1; + * + *
+     *cmd id:		0x0208
+     * 
+ */ + public int getUserId() { + return userId_; + } + + public static final int LATEST_UPDATE_TIME_FIELD_NUMBER = 2; + private int latestUpdateTime_; + /** + * required uint32 latest_update_time = 2; + */ + public boolean hasLatestUpdateTime() { + return ((bitField0_ & 0x00000002) == 0x00000002); + } + /** + * required uint32 latest_update_time = 2; + */ + public int getLatestUpdateTime() { + return latestUpdateTime_; + } + + public static final int ATTACH_DATA_FIELD_NUMBER = 20; + private com.google.protobuf.ByteString attachData_; + /** + * optional bytes attach_data = 20; + */ + public boolean hasAttachData() { + return ((bitField0_ & 0x00000004) == 0x00000004); + } + /** + * optional bytes attach_data = 20; + */ + public com.google.protobuf.ByteString getAttachData() { + return attachData_; + } + + private void initFields() { + userId_ = 0; + latestUpdateTime_ = 0; + attachData_ = com.google.protobuf.ByteString.EMPTY; + } + private byte memoizedIsInitialized = -1; + public final boolean isInitialized() { + byte isInitialized = memoizedIsInitialized; + if (isInitialized == 1) return true; + if (isInitialized == 0) return false; + + if (!hasUserId()) { + memoizedIsInitialized = 0; + return false; + } + if (!hasLatestUpdateTime()) { + memoizedIsInitialized = 0; + return false; + } + memoizedIsInitialized = 1; + return true; + } + + public void writeTo(com.google.protobuf.CodedOutputStream output) + throws java.io.IOException { + getSerializedSize(); + if (((bitField0_ & 0x00000001) == 0x00000001)) { + output.writeUInt32(1, userId_); + } + if (((bitField0_ & 0x00000002) == 0x00000002)) { + output.writeUInt32(2, latestUpdateTime_); + } + if (((bitField0_ & 0x00000004) == 0x00000004)) { + output.writeBytes(20, attachData_); + } + output.writeRawBytes(unknownFields); + } + + private int memoizedSerializedSize = -1; + public int getSerializedSize() { + int size = memoizedSerializedSize; + if (size != -1) return size; + + size = 0; + if (((bitField0_ & 0x00000001) == 0x00000001)) { + size += com.google.protobuf.CodedOutputStream + .computeUInt32Size(1, userId_); + } + if (((bitField0_ & 0x00000002) == 0x00000002)) { + size += com.google.protobuf.CodedOutputStream + .computeUInt32Size(2, latestUpdateTime_); + } + if (((bitField0_ & 0x00000004) == 0x00000004)) { + size += com.google.protobuf.CodedOutputStream + .computeBytesSize(20, attachData_); + } + size += unknownFields.size(); + memoizedSerializedSize = size; + return size; + } + + private static final long serialVersionUID = 0L; + @java.lang.Override + protected java.lang.Object writeReplace() + throws java.io.ObjectStreamException { + return super.writeReplace(); + } + + public static com.mogujie.tt.protobuf.IMBuddy.IMAllUserReq parseFrom( + com.google.protobuf.ByteString data) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data); + } + public static com.mogujie.tt.protobuf.IMBuddy.IMAllUserReq parseFrom( + com.google.protobuf.ByteString data, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data, extensionRegistry); + } + public static com.mogujie.tt.protobuf.IMBuddy.IMAllUserReq parseFrom(byte[] data) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data); + } + public static com.mogujie.tt.protobuf.IMBuddy.IMAllUserReq parseFrom( + byte[] data, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data, extensionRegistry); + } + public static com.mogujie.tt.protobuf.IMBuddy.IMAllUserReq parseFrom(java.io.InputStream input) + throws java.io.IOException { + return PARSER.parseFrom(input); + } + public static com.mogujie.tt.protobuf.IMBuddy.IMAllUserReq parseFrom( + java.io.InputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return PARSER.parseFrom(input, extensionRegistry); + } + public static com.mogujie.tt.protobuf.IMBuddy.IMAllUserReq parseDelimitedFrom(java.io.InputStream input) + throws java.io.IOException { + return PARSER.parseDelimitedFrom(input); + } + public static com.mogujie.tt.protobuf.IMBuddy.IMAllUserReq parseDelimitedFrom( + java.io.InputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return PARSER.parseDelimitedFrom(input, extensionRegistry); + } + public static com.mogujie.tt.protobuf.IMBuddy.IMAllUserReq parseFrom( + com.google.protobuf.CodedInputStream input) + throws java.io.IOException { + return PARSER.parseFrom(input); + } + public static com.mogujie.tt.protobuf.IMBuddy.IMAllUserReq parseFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return PARSER.parseFrom(input, extensionRegistry); + } + + public static Builder newBuilder() { return Builder.create(); } + public Builder newBuilderForType() { return newBuilder(); } + public static Builder newBuilder(com.mogujie.tt.protobuf.IMBuddy.IMAllUserReq prototype) { + return newBuilder().mergeFrom(prototype); + } + public Builder toBuilder() { return newBuilder(this); } + + /** + * Protobuf type {@code IM.Buddy.IMAllUserReq} + */ + public static final class Builder extends + com.google.protobuf.GeneratedMessageLite.Builder< + com.mogujie.tt.protobuf.IMBuddy.IMAllUserReq, Builder> + implements + // @@protoc_insertion_point(builder_implements:IM.Buddy.IMAllUserReq) + com.mogujie.tt.protobuf.IMBuddy.IMAllUserReqOrBuilder { + // Construct using com.mogujie.tt.protobuf.IMBuddy.IMAllUserReq.newBuilder() + private Builder() { + maybeForceBuilderInitialization(); + } + + private void maybeForceBuilderInitialization() { + } + private static Builder create() { + return new Builder(); + } + + public Builder clear() { + super.clear(); + userId_ = 0; + bitField0_ = (bitField0_ & ~0x00000001); + latestUpdateTime_ = 0; + bitField0_ = (bitField0_ & ~0x00000002); + attachData_ = com.google.protobuf.ByteString.EMPTY; + bitField0_ = (bitField0_ & ~0x00000004); + return this; + } + + public Builder clone() { + return create().mergeFrom(buildPartial()); + } + + public com.mogujie.tt.protobuf.IMBuddy.IMAllUserReq getDefaultInstanceForType() { + return com.mogujie.tt.protobuf.IMBuddy.IMAllUserReq.getDefaultInstance(); + } + + public com.mogujie.tt.protobuf.IMBuddy.IMAllUserReq build() { + com.mogujie.tt.protobuf.IMBuddy.IMAllUserReq result = buildPartial(); + if (!result.isInitialized()) { + throw newUninitializedMessageException(result); + } + return result; + } + + public com.mogujie.tt.protobuf.IMBuddy.IMAllUserReq buildPartial() { + com.mogujie.tt.protobuf.IMBuddy.IMAllUserReq result = new com.mogujie.tt.protobuf.IMBuddy.IMAllUserReq(this); + int from_bitField0_ = bitField0_; + int to_bitField0_ = 0; + if (((from_bitField0_ & 0x00000001) == 0x00000001)) { + to_bitField0_ |= 0x00000001; + } + result.userId_ = userId_; + if (((from_bitField0_ & 0x00000002) == 0x00000002)) { + to_bitField0_ |= 0x00000002; + } + result.latestUpdateTime_ = latestUpdateTime_; + if (((from_bitField0_ & 0x00000004) == 0x00000004)) { + to_bitField0_ |= 0x00000004; + } + result.attachData_ = attachData_; + result.bitField0_ = to_bitField0_; + return result; + } + + public Builder mergeFrom(com.mogujie.tt.protobuf.IMBuddy.IMAllUserReq other) { + if (other == com.mogujie.tt.protobuf.IMBuddy.IMAllUserReq.getDefaultInstance()) return this; + if (other.hasUserId()) { + setUserId(other.getUserId()); + } + if (other.hasLatestUpdateTime()) { + setLatestUpdateTime(other.getLatestUpdateTime()); + } + if (other.hasAttachData()) { + setAttachData(other.getAttachData()); + } + setUnknownFields( + getUnknownFields().concat(other.unknownFields)); + return this; + } + + public final boolean isInitialized() { + if (!hasUserId()) { + + return false; + } + if (!hasLatestUpdateTime()) { + + return false; + } + return true; + } + + public Builder mergeFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + com.mogujie.tt.protobuf.IMBuddy.IMAllUserReq parsedMessage = null; + try { + parsedMessage = PARSER.parsePartialFrom(input, extensionRegistry); + } catch (com.google.protobuf.InvalidProtocolBufferException e) { + parsedMessage = (com.mogujie.tt.protobuf.IMBuddy.IMAllUserReq) e.getUnfinishedMessage(); + throw e; + } finally { + if (parsedMessage != null) { + mergeFrom(parsedMessage); + } + } + return this; + } + private int bitField0_; + + private int userId_ ; + /** + * required uint32 user_id = 1; + * + *
+       *cmd id:		0x0208
+       * 
+ */ + public boolean hasUserId() { + return ((bitField0_ & 0x00000001) == 0x00000001); + } + /** + * required uint32 user_id = 1; + * + *
+       *cmd id:		0x0208
+       * 
+ */ + public int getUserId() { + return userId_; + } + /** + * required uint32 user_id = 1; + * + *
+       *cmd id:		0x0208
+       * 
+ */ + public Builder setUserId(int value) { + bitField0_ |= 0x00000001; + userId_ = value; + + return this; + } + /** + * required uint32 user_id = 1; + * + *
+       *cmd id:		0x0208
+       * 
+ */ + public Builder clearUserId() { + bitField0_ = (bitField0_ & ~0x00000001); + userId_ = 0; + + return this; + } + + private int latestUpdateTime_ ; + /** + * required uint32 latest_update_time = 2; + */ + public boolean hasLatestUpdateTime() { + return ((bitField0_ & 0x00000002) == 0x00000002); + } + /** + * required uint32 latest_update_time = 2; + */ + public int getLatestUpdateTime() { + return latestUpdateTime_; + } + /** + * required uint32 latest_update_time = 2; + */ + public Builder setLatestUpdateTime(int value) { + bitField0_ |= 0x00000002; + latestUpdateTime_ = value; + + return this; + } + /** + * required uint32 latest_update_time = 2; + */ + public Builder clearLatestUpdateTime() { + bitField0_ = (bitField0_ & ~0x00000002); + latestUpdateTime_ = 0; + + return this; + } + + private com.google.protobuf.ByteString attachData_ = com.google.protobuf.ByteString.EMPTY; + /** + * optional bytes attach_data = 20; + */ + public boolean hasAttachData() { + return ((bitField0_ & 0x00000004) == 0x00000004); + } + /** + * optional bytes attach_data = 20; + */ + public com.google.protobuf.ByteString getAttachData() { + return attachData_; + } + /** + * optional bytes attach_data = 20; + */ + public Builder setAttachData(com.google.protobuf.ByteString value) { + if (value == null) { + throw new NullPointerException(); + } + bitField0_ |= 0x00000004; + attachData_ = value; + + return this; + } + /** + * optional bytes attach_data = 20; + */ + public Builder clearAttachData() { + bitField0_ = (bitField0_ & ~0x00000004); + attachData_ = getDefaultInstance().getAttachData(); + + return this; + } + + // @@protoc_insertion_point(builder_scope:IM.Buddy.IMAllUserReq) + } + + static { + defaultInstance = new IMAllUserReq(true); + defaultInstance.initFields(); + } + + // @@protoc_insertion_point(class_scope:IM.Buddy.IMAllUserReq) + } + + public interface IMAllUserRspOrBuilder extends + // @@protoc_insertion_point(interface_extends:IM.Buddy.IMAllUserRsp) + com.google.protobuf.MessageLiteOrBuilder { + + /** + * required uint32 user_id = 1; + * + *
+     *cmd id:		0x0209
+     * 
+ */ + boolean hasUserId(); + /** + * required uint32 user_id = 1; + * + *
+     *cmd id:		0x0209
+     * 
+ */ + int getUserId(); + + /** + * required uint32 latest_update_time = 2; + */ + boolean hasLatestUpdateTime(); + /** + * required uint32 latest_update_time = 2; + */ + int getLatestUpdateTime(); + + /** + * repeated .IM.BaseDefine.UserInfo user_list = 3; + */ + java.util.List + getUserListList(); + /** + * repeated .IM.BaseDefine.UserInfo user_list = 3; + */ + com.mogujie.tt.protobuf.IMBaseDefine.UserInfo getUserList(int index); + /** + * repeated .IM.BaseDefine.UserInfo user_list = 3; + */ + int getUserListCount(); + + /** + * optional bytes attach_data = 20; + */ + boolean hasAttachData(); + /** + * optional bytes attach_data = 20; + */ + com.google.protobuf.ByteString getAttachData(); + } + /** + * Protobuf type {@code IM.Buddy.IMAllUserRsp} + */ + public static final class IMAllUserRsp extends + com.google.protobuf.GeneratedMessageLite implements + // @@protoc_insertion_point(message_implements:IM.Buddy.IMAllUserRsp) + IMAllUserRspOrBuilder { + // Use IMAllUserRsp.newBuilder() to construct. + private IMAllUserRsp(com.google.protobuf.GeneratedMessageLite.Builder builder) { + super(builder); + this.unknownFields = builder.getUnknownFields(); + } + private IMAllUserRsp(boolean noInit) { this.unknownFields = com.google.protobuf.ByteString.EMPTY;} + + private static final IMAllUserRsp defaultInstance; + public static IMAllUserRsp getDefaultInstance() { + return defaultInstance; + } + + public IMAllUserRsp getDefaultInstanceForType() { + return defaultInstance; + } + + private final com.google.protobuf.ByteString unknownFields; + private IMAllUserRsp( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + initFields(); + int mutable_bitField0_ = 0; + com.google.protobuf.ByteString.Output unknownFieldsOutput = + com.google.protobuf.ByteString.newOutput(); + com.google.protobuf.CodedOutputStream unknownFieldsCodedOutput = + com.google.protobuf.CodedOutputStream.newInstance( + unknownFieldsOutput); + try { + boolean done = false; + while (!done) { + int tag = input.readTag(); + switch (tag) { + case 0: + done = true; + break; + default: { + if (!parseUnknownField(input, unknownFieldsCodedOutput, + extensionRegistry, tag)) { + done = true; + } + break; + } + case 8: { + bitField0_ |= 0x00000001; + userId_ = input.readUInt32(); + break; + } + case 16: { + bitField0_ |= 0x00000002; + latestUpdateTime_ = input.readUInt32(); + break; + } + case 26: { + if (!((mutable_bitField0_ & 0x00000004) == 0x00000004)) { + userList_ = new java.util.ArrayList(); + mutable_bitField0_ |= 0x00000004; + } + userList_.add(input.readMessage(com.mogujie.tt.protobuf.IMBaseDefine.UserInfo.PARSER, extensionRegistry)); + break; + } + case 162: { + bitField0_ |= 0x00000004; + attachData_ = input.readBytes(); + break; + } + } + } + } catch (com.google.protobuf.InvalidProtocolBufferException e) { + throw e.setUnfinishedMessage(this); + } catch (java.io.IOException e) { + throw new com.google.protobuf.InvalidProtocolBufferException( + e.getMessage()).setUnfinishedMessage(this); + } finally { + if (((mutable_bitField0_ & 0x00000004) == 0x00000004)) { + userList_ = java.util.Collections.unmodifiableList(userList_); + } + try { + unknownFieldsCodedOutput.flush(); + } catch (java.io.IOException e) { + // Should not happen + } finally { + unknownFields = unknownFieldsOutput.toByteString(); + } + makeExtensionsImmutable(); + } + } + public static com.google.protobuf.Parser PARSER = + new com.google.protobuf.AbstractParser() { + public IMAllUserRsp parsePartialFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return new IMAllUserRsp(input, extensionRegistry); + } + }; + + @java.lang.Override + public com.google.protobuf.Parser getParserForType() { + return PARSER; + } + + private int bitField0_; + public static final int USER_ID_FIELD_NUMBER = 1; + private int userId_; + /** + * required uint32 user_id = 1; + * + *
+     *cmd id:		0x0209
+     * 
+ */ + public boolean hasUserId() { + return ((bitField0_ & 0x00000001) == 0x00000001); + } + /** + * required uint32 user_id = 1; + * + *
+     *cmd id:		0x0209
+     * 
+ */ + public int getUserId() { + return userId_; + } + + public static final int LATEST_UPDATE_TIME_FIELD_NUMBER = 2; + private int latestUpdateTime_; + /** + * required uint32 latest_update_time = 2; + */ + public boolean hasLatestUpdateTime() { + return ((bitField0_ & 0x00000002) == 0x00000002); + } + /** + * required uint32 latest_update_time = 2; + */ + public int getLatestUpdateTime() { + return latestUpdateTime_; + } + + public static final int USER_LIST_FIELD_NUMBER = 3; + private java.util.List userList_; + /** + * repeated .IM.BaseDefine.UserInfo user_list = 3; + */ + public java.util.List getUserListList() { + return userList_; + } + /** + * repeated .IM.BaseDefine.UserInfo user_list = 3; + */ + public java.util.List + getUserListOrBuilderList() { + return userList_; + } + /** + * repeated .IM.BaseDefine.UserInfo user_list = 3; + */ + public int getUserListCount() { + return userList_.size(); + } + /** + * repeated .IM.BaseDefine.UserInfo user_list = 3; + */ + public com.mogujie.tt.protobuf.IMBaseDefine.UserInfo getUserList(int index) { + return userList_.get(index); + } + /** + * repeated .IM.BaseDefine.UserInfo user_list = 3; + */ + public com.mogujie.tt.protobuf.IMBaseDefine.UserInfoOrBuilder getUserListOrBuilder( + int index) { + return userList_.get(index); + } + + public static final int ATTACH_DATA_FIELD_NUMBER = 20; + private com.google.protobuf.ByteString attachData_; + /** + * optional bytes attach_data = 20; + */ + public boolean hasAttachData() { + return ((bitField0_ & 0x00000004) == 0x00000004); + } + /** + * optional bytes attach_data = 20; + */ + public com.google.protobuf.ByteString getAttachData() { + return attachData_; + } + + private void initFields() { + userId_ = 0; + latestUpdateTime_ = 0; + userList_ = java.util.Collections.emptyList(); + attachData_ = com.google.protobuf.ByteString.EMPTY; + } + private byte memoizedIsInitialized = -1; + public final boolean isInitialized() { + byte isInitialized = memoizedIsInitialized; + if (isInitialized == 1) return true; + if (isInitialized == 0) return false; + + if (!hasUserId()) { + memoizedIsInitialized = 0; + return false; + } + if (!hasLatestUpdateTime()) { + memoizedIsInitialized = 0; + return false; + } + for (int i = 0; i < getUserListCount(); i++) { + if (!getUserList(i).isInitialized()) { + memoizedIsInitialized = 0; + return false; + } + } + memoizedIsInitialized = 1; + return true; + } + + public void writeTo(com.google.protobuf.CodedOutputStream output) + throws java.io.IOException { + getSerializedSize(); + if (((bitField0_ & 0x00000001) == 0x00000001)) { + output.writeUInt32(1, userId_); + } + if (((bitField0_ & 0x00000002) == 0x00000002)) { + output.writeUInt32(2, latestUpdateTime_); + } + for (int i = 0; i < userList_.size(); i++) { + output.writeMessage(3, userList_.get(i)); + } + if (((bitField0_ & 0x00000004) == 0x00000004)) { + output.writeBytes(20, attachData_); + } + output.writeRawBytes(unknownFields); + } + + private int memoizedSerializedSize = -1; + public int getSerializedSize() { + int size = memoizedSerializedSize; + if (size != -1) return size; + + size = 0; + if (((bitField0_ & 0x00000001) == 0x00000001)) { + size += com.google.protobuf.CodedOutputStream + .computeUInt32Size(1, userId_); + } + if (((bitField0_ & 0x00000002) == 0x00000002)) { + size += com.google.protobuf.CodedOutputStream + .computeUInt32Size(2, latestUpdateTime_); + } + for (int i = 0; i < userList_.size(); i++) { + size += com.google.protobuf.CodedOutputStream + .computeMessageSize(3, userList_.get(i)); + } + if (((bitField0_ & 0x00000004) == 0x00000004)) { + size += com.google.protobuf.CodedOutputStream + .computeBytesSize(20, attachData_); + } + size += unknownFields.size(); + memoizedSerializedSize = size; + return size; + } + + private static final long serialVersionUID = 0L; + @java.lang.Override + protected java.lang.Object writeReplace() + throws java.io.ObjectStreamException { + return super.writeReplace(); + } + + public static com.mogujie.tt.protobuf.IMBuddy.IMAllUserRsp parseFrom( + com.google.protobuf.ByteString data) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data); + } + public static com.mogujie.tt.protobuf.IMBuddy.IMAllUserRsp parseFrom( + com.google.protobuf.ByteString data, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data, extensionRegistry); + } + public static com.mogujie.tt.protobuf.IMBuddy.IMAllUserRsp parseFrom(byte[] data) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data); + } + public static com.mogujie.tt.protobuf.IMBuddy.IMAllUserRsp parseFrom( + byte[] data, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data, extensionRegistry); + } + public static com.mogujie.tt.protobuf.IMBuddy.IMAllUserRsp parseFrom(java.io.InputStream input) + throws java.io.IOException { + return PARSER.parseFrom(input); + } + public static com.mogujie.tt.protobuf.IMBuddy.IMAllUserRsp parseFrom( + java.io.InputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return PARSER.parseFrom(input, extensionRegistry); + } + public static com.mogujie.tt.protobuf.IMBuddy.IMAllUserRsp parseDelimitedFrom(java.io.InputStream input) + throws java.io.IOException { + return PARSER.parseDelimitedFrom(input); + } + public static com.mogujie.tt.protobuf.IMBuddy.IMAllUserRsp parseDelimitedFrom( + java.io.InputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return PARSER.parseDelimitedFrom(input, extensionRegistry); + } + public static com.mogujie.tt.protobuf.IMBuddy.IMAllUserRsp parseFrom( + com.google.protobuf.CodedInputStream input) + throws java.io.IOException { + return PARSER.parseFrom(input); + } + public static com.mogujie.tt.protobuf.IMBuddy.IMAllUserRsp parseFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return PARSER.parseFrom(input, extensionRegistry); + } + + public static Builder newBuilder() { return Builder.create(); } + public Builder newBuilderForType() { return newBuilder(); } + public static Builder newBuilder(com.mogujie.tt.protobuf.IMBuddy.IMAllUserRsp prototype) { + return newBuilder().mergeFrom(prototype); + } + public Builder toBuilder() { return newBuilder(this); } + + /** + * Protobuf type {@code IM.Buddy.IMAllUserRsp} + */ + public static final class Builder extends + com.google.protobuf.GeneratedMessageLite.Builder< + com.mogujie.tt.protobuf.IMBuddy.IMAllUserRsp, Builder> + implements + // @@protoc_insertion_point(builder_implements:IM.Buddy.IMAllUserRsp) + com.mogujie.tt.protobuf.IMBuddy.IMAllUserRspOrBuilder { + // Construct using com.mogujie.tt.protobuf.IMBuddy.IMAllUserRsp.newBuilder() + private Builder() { + maybeForceBuilderInitialization(); + } + + private void maybeForceBuilderInitialization() { + } + private static Builder create() { + return new Builder(); + } + + public Builder clear() { + super.clear(); + userId_ = 0; + bitField0_ = (bitField0_ & ~0x00000001); + latestUpdateTime_ = 0; + bitField0_ = (bitField0_ & ~0x00000002); + userList_ = java.util.Collections.emptyList(); + bitField0_ = (bitField0_ & ~0x00000004); + attachData_ = com.google.protobuf.ByteString.EMPTY; + bitField0_ = (bitField0_ & ~0x00000008); + return this; + } + + public Builder clone() { + return create().mergeFrom(buildPartial()); + } + + public com.mogujie.tt.protobuf.IMBuddy.IMAllUserRsp getDefaultInstanceForType() { + return com.mogujie.tt.protobuf.IMBuddy.IMAllUserRsp.getDefaultInstance(); + } + + public com.mogujie.tt.protobuf.IMBuddy.IMAllUserRsp build() { + com.mogujie.tt.protobuf.IMBuddy.IMAllUserRsp result = buildPartial(); + if (!result.isInitialized()) { + throw newUninitializedMessageException(result); + } + return result; + } + + public com.mogujie.tt.protobuf.IMBuddy.IMAllUserRsp buildPartial() { + com.mogujie.tt.protobuf.IMBuddy.IMAllUserRsp result = new com.mogujie.tt.protobuf.IMBuddy.IMAllUserRsp(this); + int from_bitField0_ = bitField0_; + int to_bitField0_ = 0; + if (((from_bitField0_ & 0x00000001) == 0x00000001)) { + to_bitField0_ |= 0x00000001; + } + result.userId_ = userId_; + if (((from_bitField0_ & 0x00000002) == 0x00000002)) { + to_bitField0_ |= 0x00000002; + } + result.latestUpdateTime_ = latestUpdateTime_; + if (((bitField0_ & 0x00000004) == 0x00000004)) { + userList_ = java.util.Collections.unmodifiableList(userList_); + bitField0_ = (bitField0_ & ~0x00000004); + } + result.userList_ = userList_; + if (((from_bitField0_ & 0x00000008) == 0x00000008)) { + to_bitField0_ |= 0x00000004; + } + result.attachData_ = attachData_; + result.bitField0_ = to_bitField0_; + return result; + } + + public Builder mergeFrom(com.mogujie.tt.protobuf.IMBuddy.IMAllUserRsp other) { + if (other == com.mogujie.tt.protobuf.IMBuddy.IMAllUserRsp.getDefaultInstance()) return this; + if (other.hasUserId()) { + setUserId(other.getUserId()); + } + if (other.hasLatestUpdateTime()) { + setLatestUpdateTime(other.getLatestUpdateTime()); + } + if (!other.userList_.isEmpty()) { + if (userList_.isEmpty()) { + userList_ = other.userList_; + bitField0_ = (bitField0_ & ~0x00000004); + } else { + ensureUserListIsMutable(); + userList_.addAll(other.userList_); + } + + } + if (other.hasAttachData()) { + setAttachData(other.getAttachData()); + } + setUnknownFields( + getUnknownFields().concat(other.unknownFields)); + return this; + } + + public final boolean isInitialized() { + if (!hasUserId()) { + + return false; + } + if (!hasLatestUpdateTime()) { + + return false; + } + for (int i = 0; i < getUserListCount(); i++) { + if (!getUserList(i).isInitialized()) { + + return false; + } + } + return true; + } + + public Builder mergeFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + com.mogujie.tt.protobuf.IMBuddy.IMAllUserRsp parsedMessage = null; + try { + parsedMessage = PARSER.parsePartialFrom(input, extensionRegistry); + } catch (com.google.protobuf.InvalidProtocolBufferException e) { + parsedMessage = (com.mogujie.tt.protobuf.IMBuddy.IMAllUserRsp) e.getUnfinishedMessage(); + throw e; + } finally { + if (parsedMessage != null) { + mergeFrom(parsedMessage); + } + } + return this; + } + private int bitField0_; + + private int userId_ ; + /** + * required uint32 user_id = 1; + * + *
+       *cmd id:		0x0209
+       * 
+ */ + public boolean hasUserId() { + return ((bitField0_ & 0x00000001) == 0x00000001); + } + /** + * required uint32 user_id = 1; + * + *
+       *cmd id:		0x0209
+       * 
+ */ + public int getUserId() { + return userId_; + } + /** + * required uint32 user_id = 1; + * + *
+       *cmd id:		0x0209
+       * 
+ */ + public Builder setUserId(int value) { + bitField0_ |= 0x00000001; + userId_ = value; + + return this; + } + /** + * required uint32 user_id = 1; + * + *
+       *cmd id:		0x0209
+       * 
+ */ + public Builder clearUserId() { + bitField0_ = (bitField0_ & ~0x00000001); + userId_ = 0; + + return this; + } + + private int latestUpdateTime_ ; + /** + * required uint32 latest_update_time = 2; + */ + public boolean hasLatestUpdateTime() { + return ((bitField0_ & 0x00000002) == 0x00000002); + } + /** + * required uint32 latest_update_time = 2; + */ + public int getLatestUpdateTime() { + return latestUpdateTime_; + } + /** + * required uint32 latest_update_time = 2; + */ + public Builder setLatestUpdateTime(int value) { + bitField0_ |= 0x00000002; + latestUpdateTime_ = value; + + return this; + } + /** + * required uint32 latest_update_time = 2; + */ + public Builder clearLatestUpdateTime() { + bitField0_ = (bitField0_ & ~0x00000002); + latestUpdateTime_ = 0; + + return this; + } + + private java.util.List userList_ = + java.util.Collections.emptyList(); + private void ensureUserListIsMutable() { + if (!((bitField0_ & 0x00000004) == 0x00000004)) { + userList_ = new java.util.ArrayList(userList_); + bitField0_ |= 0x00000004; + } + } + + /** + * repeated .IM.BaseDefine.UserInfo user_list = 3; + */ + public java.util.List getUserListList() { + return java.util.Collections.unmodifiableList(userList_); + } + /** + * repeated .IM.BaseDefine.UserInfo user_list = 3; + */ + public int getUserListCount() { + return userList_.size(); + } + /** + * repeated .IM.BaseDefine.UserInfo user_list = 3; + */ + public com.mogujie.tt.protobuf.IMBaseDefine.UserInfo getUserList(int index) { + return userList_.get(index); + } + /** + * repeated .IM.BaseDefine.UserInfo user_list = 3; + */ + public Builder setUserList( + int index, com.mogujie.tt.protobuf.IMBaseDefine.UserInfo value) { + if (value == null) { + throw new NullPointerException(); + } + ensureUserListIsMutable(); + userList_.set(index, value); + + return this; + } + /** + * repeated .IM.BaseDefine.UserInfo user_list = 3; + */ + public Builder setUserList( + int index, com.mogujie.tt.protobuf.IMBaseDefine.UserInfo.Builder builderForValue) { + ensureUserListIsMutable(); + userList_.set(index, builderForValue.build()); + + return this; + } + /** + * repeated .IM.BaseDefine.UserInfo user_list = 3; + */ + public Builder addUserList(com.mogujie.tt.protobuf.IMBaseDefine.UserInfo value) { + if (value == null) { + throw new NullPointerException(); + } + ensureUserListIsMutable(); + userList_.add(value); + + return this; + } + /** + * repeated .IM.BaseDefine.UserInfo user_list = 3; + */ + public Builder addUserList( + int index, com.mogujie.tt.protobuf.IMBaseDefine.UserInfo value) { + if (value == null) { + throw new NullPointerException(); + } + ensureUserListIsMutable(); + userList_.add(index, value); + + return this; + } + /** + * repeated .IM.BaseDefine.UserInfo user_list = 3; + */ + public Builder addUserList( + com.mogujie.tt.protobuf.IMBaseDefine.UserInfo.Builder builderForValue) { + ensureUserListIsMutable(); + userList_.add(builderForValue.build()); + + return this; + } + /** + * repeated .IM.BaseDefine.UserInfo user_list = 3; + */ + public Builder addUserList( + int index, com.mogujie.tt.protobuf.IMBaseDefine.UserInfo.Builder builderForValue) { + ensureUserListIsMutable(); + userList_.add(index, builderForValue.build()); + + return this; + } + /** + * repeated .IM.BaseDefine.UserInfo user_list = 3; + */ + public Builder addAllUserList( + java.lang.Iterable values) { + ensureUserListIsMutable(); + com.google.protobuf.AbstractMessageLite.Builder.addAll( + values, userList_); + + return this; + } + /** + * repeated .IM.BaseDefine.UserInfo user_list = 3; + */ + public Builder clearUserList() { + userList_ = java.util.Collections.emptyList(); + bitField0_ = (bitField0_ & ~0x00000004); + + return this; + } + /** + * repeated .IM.BaseDefine.UserInfo user_list = 3; + */ + public Builder removeUserList(int index) { + ensureUserListIsMutable(); + userList_.remove(index); + + return this; + } + + private com.google.protobuf.ByteString attachData_ = com.google.protobuf.ByteString.EMPTY; + /** + * optional bytes attach_data = 20; + */ + public boolean hasAttachData() { + return ((bitField0_ & 0x00000008) == 0x00000008); + } + /** + * optional bytes attach_data = 20; + */ + public com.google.protobuf.ByteString getAttachData() { + return attachData_; + } + /** + * optional bytes attach_data = 20; + */ + public Builder setAttachData(com.google.protobuf.ByteString value) { + if (value == null) { + throw new NullPointerException(); + } + bitField0_ |= 0x00000008; + attachData_ = value; + + return this; + } + /** + * optional bytes attach_data = 20; + */ + public Builder clearAttachData() { + bitField0_ = (bitField0_ & ~0x00000008); + attachData_ = getDefaultInstance().getAttachData(); + + return this; + } + + // @@protoc_insertion_point(builder_scope:IM.Buddy.IMAllUserRsp) + } + + static { + defaultInstance = new IMAllUserRsp(true); + defaultInstance.initFields(); + } + + // @@protoc_insertion_point(class_scope:IM.Buddy.IMAllUserRsp) + } + + public interface IMUsersStatReqOrBuilder extends + // @@protoc_insertion_point(interface_extends:IM.Buddy.IMUsersStatReq) + com.google.protobuf.MessageLiteOrBuilder { + + /** + * required uint32 user_id = 1; + * + *
+     *cmd id:		0x020a
+     * 
+ */ + boolean hasUserId(); + /** + * required uint32 user_id = 1; + * + *
+     *cmd id:		0x020a
+     * 
+ */ + int getUserId(); + + /** + * repeated uint32 user_id_list = 2; + */ + java.util.List getUserIdListList(); + /** + * repeated uint32 user_id_list = 2; + */ + int getUserIdListCount(); + /** + * repeated uint32 user_id_list = 2; + */ + int getUserIdList(int index); + + /** + * optional bytes attach_data = 20; + */ + boolean hasAttachData(); + /** + * optional bytes attach_data = 20; + */ + com.google.protobuf.ByteString getAttachData(); + } + /** + * Protobuf type {@code IM.Buddy.IMUsersStatReq} + */ + public static final class IMUsersStatReq extends + com.google.protobuf.GeneratedMessageLite implements + // @@protoc_insertion_point(message_implements:IM.Buddy.IMUsersStatReq) + IMUsersStatReqOrBuilder { + // Use IMUsersStatReq.newBuilder() to construct. + private IMUsersStatReq(com.google.protobuf.GeneratedMessageLite.Builder builder) { + super(builder); + this.unknownFields = builder.getUnknownFields(); + } + private IMUsersStatReq(boolean noInit) { this.unknownFields = com.google.protobuf.ByteString.EMPTY;} + + private static final IMUsersStatReq defaultInstance; + public static IMUsersStatReq getDefaultInstance() { + return defaultInstance; + } + + public IMUsersStatReq getDefaultInstanceForType() { + return defaultInstance; + } + + private final com.google.protobuf.ByteString unknownFields; + private IMUsersStatReq( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + initFields(); + int mutable_bitField0_ = 0; + com.google.protobuf.ByteString.Output unknownFieldsOutput = + com.google.protobuf.ByteString.newOutput(); + com.google.protobuf.CodedOutputStream unknownFieldsCodedOutput = + com.google.protobuf.CodedOutputStream.newInstance( + unknownFieldsOutput); + try { + boolean done = false; + while (!done) { + int tag = input.readTag(); + switch (tag) { + case 0: + done = true; + break; + default: { + if (!parseUnknownField(input, unknownFieldsCodedOutput, + extensionRegistry, tag)) { + done = true; + } + break; + } + case 8: { + bitField0_ |= 0x00000001; + userId_ = input.readUInt32(); + break; + } + case 16: { + if (!((mutable_bitField0_ & 0x00000002) == 0x00000002)) { + userIdList_ = new java.util.ArrayList(); + mutable_bitField0_ |= 0x00000002; + } + userIdList_.add(input.readUInt32()); + break; + } + case 18: { + int length = input.readRawVarint32(); + int limit = input.pushLimit(length); + if (!((mutable_bitField0_ & 0x00000002) == 0x00000002) && input.getBytesUntilLimit() > 0) { + userIdList_ = new java.util.ArrayList(); + mutable_bitField0_ |= 0x00000002; + } + while (input.getBytesUntilLimit() > 0) { + userIdList_.add(input.readUInt32()); + } + input.popLimit(limit); + break; + } + case 162: { + bitField0_ |= 0x00000002; + attachData_ = input.readBytes(); + break; + } + } + } + } catch (com.google.protobuf.InvalidProtocolBufferException e) { + throw e.setUnfinishedMessage(this); + } catch (java.io.IOException e) { + throw new com.google.protobuf.InvalidProtocolBufferException( + e.getMessage()).setUnfinishedMessage(this); + } finally { + if (((mutable_bitField0_ & 0x00000002) == 0x00000002)) { + userIdList_ = java.util.Collections.unmodifiableList(userIdList_); + } + try { + unknownFieldsCodedOutput.flush(); + } catch (java.io.IOException e) { + // Should not happen + } finally { + unknownFields = unknownFieldsOutput.toByteString(); + } + makeExtensionsImmutable(); + } + } + public static com.google.protobuf.Parser PARSER = + new com.google.protobuf.AbstractParser() { + public IMUsersStatReq parsePartialFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return new IMUsersStatReq(input, extensionRegistry); + } + }; + + @java.lang.Override + public com.google.protobuf.Parser getParserForType() { + return PARSER; + } + + private int bitField0_; + public static final int USER_ID_FIELD_NUMBER = 1; + private int userId_; + /** + * required uint32 user_id = 1; + * + *
+     *cmd id:		0x020a
+     * 
+ */ + public boolean hasUserId() { + return ((bitField0_ & 0x00000001) == 0x00000001); + } + /** + * required uint32 user_id = 1; + * + *
+     *cmd id:		0x020a
+     * 
+ */ + public int getUserId() { + return userId_; + } + + public static final int USER_ID_LIST_FIELD_NUMBER = 2; + private java.util.List userIdList_; + /** + * repeated uint32 user_id_list = 2; + */ + public java.util.List + getUserIdListList() { + return userIdList_; + } + /** + * repeated uint32 user_id_list = 2; + */ + public int getUserIdListCount() { + return userIdList_.size(); + } + /** + * repeated uint32 user_id_list = 2; + */ + public int getUserIdList(int index) { + return userIdList_.get(index); + } + + public static final int ATTACH_DATA_FIELD_NUMBER = 20; + private com.google.protobuf.ByteString attachData_; + /** + * optional bytes attach_data = 20; + */ + public boolean hasAttachData() { + return ((bitField0_ & 0x00000002) == 0x00000002); + } + /** + * optional bytes attach_data = 20; + */ + public com.google.protobuf.ByteString getAttachData() { + return attachData_; + } + + private void initFields() { + userId_ = 0; + userIdList_ = java.util.Collections.emptyList(); + attachData_ = com.google.protobuf.ByteString.EMPTY; + } + private byte memoizedIsInitialized = -1; + public final boolean isInitialized() { + byte isInitialized = memoizedIsInitialized; + if (isInitialized == 1) return true; + if (isInitialized == 0) return false; + + if (!hasUserId()) { + memoizedIsInitialized = 0; + return false; + } + memoizedIsInitialized = 1; + return true; + } + + public void writeTo(com.google.protobuf.CodedOutputStream output) + throws java.io.IOException { + getSerializedSize(); + if (((bitField0_ & 0x00000001) == 0x00000001)) { + output.writeUInt32(1, userId_); + } + for (int i = 0; i < userIdList_.size(); i++) { + output.writeUInt32(2, userIdList_.get(i)); + } + if (((bitField0_ & 0x00000002) == 0x00000002)) { + output.writeBytes(20, attachData_); + } + output.writeRawBytes(unknownFields); + } + + private int memoizedSerializedSize = -1; + public int getSerializedSize() { + int size = memoizedSerializedSize; + if (size != -1) return size; + + size = 0; + if (((bitField0_ & 0x00000001) == 0x00000001)) { + size += com.google.protobuf.CodedOutputStream + .computeUInt32Size(1, userId_); + } + { + int dataSize = 0; + for (int i = 0; i < userIdList_.size(); i++) { + dataSize += com.google.protobuf.CodedOutputStream + .computeUInt32SizeNoTag(userIdList_.get(i)); + } + size += dataSize; + size += 1 * getUserIdListList().size(); + } + if (((bitField0_ & 0x00000002) == 0x00000002)) { + size += com.google.protobuf.CodedOutputStream + .computeBytesSize(20, attachData_); + } + size += unknownFields.size(); + memoizedSerializedSize = size; + return size; + } + + private static final long serialVersionUID = 0L; + @java.lang.Override + protected java.lang.Object writeReplace() + throws java.io.ObjectStreamException { + return super.writeReplace(); + } + + public static com.mogujie.tt.protobuf.IMBuddy.IMUsersStatReq parseFrom( + com.google.protobuf.ByteString data) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data); + } + public static com.mogujie.tt.protobuf.IMBuddy.IMUsersStatReq parseFrom( + com.google.protobuf.ByteString data, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data, extensionRegistry); + } + public static com.mogujie.tt.protobuf.IMBuddy.IMUsersStatReq parseFrom(byte[] data) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data); + } + public static com.mogujie.tt.protobuf.IMBuddy.IMUsersStatReq parseFrom( + byte[] data, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data, extensionRegistry); + } + public static com.mogujie.tt.protobuf.IMBuddy.IMUsersStatReq parseFrom(java.io.InputStream input) + throws java.io.IOException { + return PARSER.parseFrom(input); + } + public static com.mogujie.tt.protobuf.IMBuddy.IMUsersStatReq parseFrom( + java.io.InputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return PARSER.parseFrom(input, extensionRegistry); + } + public static com.mogujie.tt.protobuf.IMBuddy.IMUsersStatReq parseDelimitedFrom(java.io.InputStream input) + throws java.io.IOException { + return PARSER.parseDelimitedFrom(input); + } + public static com.mogujie.tt.protobuf.IMBuddy.IMUsersStatReq parseDelimitedFrom( + java.io.InputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return PARSER.parseDelimitedFrom(input, extensionRegistry); + } + public static com.mogujie.tt.protobuf.IMBuddy.IMUsersStatReq parseFrom( + com.google.protobuf.CodedInputStream input) + throws java.io.IOException { + return PARSER.parseFrom(input); + } + public static com.mogujie.tt.protobuf.IMBuddy.IMUsersStatReq parseFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return PARSER.parseFrom(input, extensionRegistry); + } + + public static Builder newBuilder() { return Builder.create(); } + public Builder newBuilderForType() { return newBuilder(); } + public static Builder newBuilder(com.mogujie.tt.protobuf.IMBuddy.IMUsersStatReq prototype) { + return newBuilder().mergeFrom(prototype); + } + public Builder toBuilder() { return newBuilder(this); } + + /** + * Protobuf type {@code IM.Buddy.IMUsersStatReq} + */ + public static final class Builder extends + com.google.protobuf.GeneratedMessageLite.Builder< + com.mogujie.tt.protobuf.IMBuddy.IMUsersStatReq, Builder> + implements + // @@protoc_insertion_point(builder_implements:IM.Buddy.IMUsersStatReq) + com.mogujie.tt.protobuf.IMBuddy.IMUsersStatReqOrBuilder { + // Construct using com.mogujie.tt.protobuf.IMBuddy.IMUsersStatReq.newBuilder() + private Builder() { + maybeForceBuilderInitialization(); + } + + private void maybeForceBuilderInitialization() { + } + private static Builder create() { + return new Builder(); + } + + public Builder clear() { + super.clear(); + userId_ = 0; + bitField0_ = (bitField0_ & ~0x00000001); + userIdList_ = java.util.Collections.emptyList(); + bitField0_ = (bitField0_ & ~0x00000002); + attachData_ = com.google.protobuf.ByteString.EMPTY; + bitField0_ = (bitField0_ & ~0x00000004); + return this; + } + + public Builder clone() { + return create().mergeFrom(buildPartial()); + } + + public com.mogujie.tt.protobuf.IMBuddy.IMUsersStatReq getDefaultInstanceForType() { + return com.mogujie.tt.protobuf.IMBuddy.IMUsersStatReq.getDefaultInstance(); + } + + public com.mogujie.tt.protobuf.IMBuddy.IMUsersStatReq build() { + com.mogujie.tt.protobuf.IMBuddy.IMUsersStatReq result = buildPartial(); + if (!result.isInitialized()) { + throw newUninitializedMessageException(result); + } + return result; + } + + public com.mogujie.tt.protobuf.IMBuddy.IMUsersStatReq buildPartial() { + com.mogujie.tt.protobuf.IMBuddy.IMUsersStatReq result = new com.mogujie.tt.protobuf.IMBuddy.IMUsersStatReq(this); + int from_bitField0_ = bitField0_; + int to_bitField0_ = 0; + if (((from_bitField0_ & 0x00000001) == 0x00000001)) { + to_bitField0_ |= 0x00000001; + } + result.userId_ = userId_; + if (((bitField0_ & 0x00000002) == 0x00000002)) { + userIdList_ = java.util.Collections.unmodifiableList(userIdList_); + bitField0_ = (bitField0_ & ~0x00000002); + } + result.userIdList_ = userIdList_; + if (((from_bitField0_ & 0x00000004) == 0x00000004)) { + to_bitField0_ |= 0x00000002; + } + result.attachData_ = attachData_; + result.bitField0_ = to_bitField0_; + return result; + } + + public Builder mergeFrom(com.mogujie.tt.protobuf.IMBuddy.IMUsersStatReq other) { + if (other == com.mogujie.tt.protobuf.IMBuddy.IMUsersStatReq.getDefaultInstance()) return this; + if (other.hasUserId()) { + setUserId(other.getUserId()); + } + if (!other.userIdList_.isEmpty()) { + if (userIdList_.isEmpty()) { + userIdList_ = other.userIdList_; + bitField0_ = (bitField0_ & ~0x00000002); + } else { + ensureUserIdListIsMutable(); + userIdList_.addAll(other.userIdList_); + } + + } + if (other.hasAttachData()) { + setAttachData(other.getAttachData()); + } + setUnknownFields( + getUnknownFields().concat(other.unknownFields)); + return this; + } + + public final boolean isInitialized() { + if (!hasUserId()) { + + return false; + } + return true; + } + + public Builder mergeFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + com.mogujie.tt.protobuf.IMBuddy.IMUsersStatReq parsedMessage = null; + try { + parsedMessage = PARSER.parsePartialFrom(input, extensionRegistry); + } catch (com.google.protobuf.InvalidProtocolBufferException e) { + parsedMessage = (com.mogujie.tt.protobuf.IMBuddy.IMUsersStatReq) e.getUnfinishedMessage(); + throw e; + } finally { + if (parsedMessage != null) { + mergeFrom(parsedMessage); + } + } + return this; + } + private int bitField0_; + + private int userId_ ; + /** + * required uint32 user_id = 1; + * + *
+       *cmd id:		0x020a
+       * 
+ */ + public boolean hasUserId() { + return ((bitField0_ & 0x00000001) == 0x00000001); + } + /** + * required uint32 user_id = 1; + * + *
+       *cmd id:		0x020a
+       * 
+ */ + public int getUserId() { + return userId_; + } + /** + * required uint32 user_id = 1; + * + *
+       *cmd id:		0x020a
+       * 
+ */ + public Builder setUserId(int value) { + bitField0_ |= 0x00000001; + userId_ = value; + + return this; + } + /** + * required uint32 user_id = 1; + * + *
+       *cmd id:		0x020a
+       * 
+ */ + public Builder clearUserId() { + bitField0_ = (bitField0_ & ~0x00000001); + userId_ = 0; + + return this; + } + + private java.util.List userIdList_ = java.util.Collections.emptyList(); + private void ensureUserIdListIsMutable() { + if (!((bitField0_ & 0x00000002) == 0x00000002)) { + userIdList_ = new java.util.ArrayList(userIdList_); + bitField0_ |= 0x00000002; + } + } + /** + * repeated uint32 user_id_list = 2; + */ + public java.util.List + getUserIdListList() { + return java.util.Collections.unmodifiableList(userIdList_); + } + /** + * repeated uint32 user_id_list = 2; + */ + public int getUserIdListCount() { + return userIdList_.size(); + } + /** + * repeated uint32 user_id_list = 2; + */ + public int getUserIdList(int index) { + return userIdList_.get(index); + } + /** + * repeated uint32 user_id_list = 2; + */ + public Builder setUserIdList( + int index, int value) { + ensureUserIdListIsMutable(); + userIdList_.set(index, value); + + return this; + } + /** + * repeated uint32 user_id_list = 2; + */ + public Builder addUserIdList(int value) { + ensureUserIdListIsMutable(); + userIdList_.add(value); + + return this; + } + /** + * repeated uint32 user_id_list = 2; + */ + public Builder addAllUserIdList( + java.lang.Iterable values) { + ensureUserIdListIsMutable(); + com.google.protobuf.AbstractMessageLite.Builder.addAll( + values, userIdList_); + + return this; + } + /** + * repeated uint32 user_id_list = 2; + */ + public Builder clearUserIdList() { + userIdList_ = java.util.Collections.emptyList(); + bitField0_ = (bitField0_ & ~0x00000002); + + return this; + } + + private com.google.protobuf.ByteString attachData_ = com.google.protobuf.ByteString.EMPTY; + /** + * optional bytes attach_data = 20; + */ + public boolean hasAttachData() { + return ((bitField0_ & 0x00000004) == 0x00000004); + } + /** + * optional bytes attach_data = 20; + */ + public com.google.protobuf.ByteString getAttachData() { + return attachData_; + } + /** + * optional bytes attach_data = 20; + */ + public Builder setAttachData(com.google.protobuf.ByteString value) { + if (value == null) { + throw new NullPointerException(); + } + bitField0_ |= 0x00000004; + attachData_ = value; + + return this; + } + /** + * optional bytes attach_data = 20; + */ + public Builder clearAttachData() { + bitField0_ = (bitField0_ & ~0x00000004); + attachData_ = getDefaultInstance().getAttachData(); + + return this; + } + + // @@protoc_insertion_point(builder_scope:IM.Buddy.IMUsersStatReq) + } + + static { + defaultInstance = new IMUsersStatReq(true); + defaultInstance.initFields(); + } + + // @@protoc_insertion_point(class_scope:IM.Buddy.IMUsersStatReq) + } + + public interface IMUsersStatRspOrBuilder extends + // @@protoc_insertion_point(interface_extends:IM.Buddy.IMUsersStatRsp) + com.google.protobuf.MessageLiteOrBuilder { + + /** + * required uint32 user_id = 1; + * + *
+     *cmd id:		0x020b
+     * 
+ */ + boolean hasUserId(); + /** + * required uint32 user_id = 1; + * + *
+     *cmd id:		0x020b
+     * 
+ */ + int getUserId(); + + /** + * repeated .IM.BaseDefine.UserStat user_stat_list = 2; + */ + java.util.List + getUserStatListList(); + /** + * repeated .IM.BaseDefine.UserStat user_stat_list = 2; + */ + com.mogujie.tt.protobuf.IMBaseDefine.UserStat getUserStatList(int index); + /** + * repeated .IM.BaseDefine.UserStat user_stat_list = 2; + */ + int getUserStatListCount(); + + /** + * optional bytes attach_data = 20; + */ + boolean hasAttachData(); + /** + * optional bytes attach_data = 20; + */ + com.google.protobuf.ByteString getAttachData(); + } + /** + * Protobuf type {@code IM.Buddy.IMUsersStatRsp} + */ + public static final class IMUsersStatRsp extends + com.google.protobuf.GeneratedMessageLite implements + // @@protoc_insertion_point(message_implements:IM.Buddy.IMUsersStatRsp) + IMUsersStatRspOrBuilder { + // Use IMUsersStatRsp.newBuilder() to construct. + private IMUsersStatRsp(com.google.protobuf.GeneratedMessageLite.Builder builder) { + super(builder); + this.unknownFields = builder.getUnknownFields(); + } + private IMUsersStatRsp(boolean noInit) { this.unknownFields = com.google.protobuf.ByteString.EMPTY;} + + private static final IMUsersStatRsp defaultInstance; + public static IMUsersStatRsp getDefaultInstance() { + return defaultInstance; + } + + public IMUsersStatRsp getDefaultInstanceForType() { + return defaultInstance; + } + + private final com.google.protobuf.ByteString unknownFields; + private IMUsersStatRsp( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + initFields(); + int mutable_bitField0_ = 0; + com.google.protobuf.ByteString.Output unknownFieldsOutput = + com.google.protobuf.ByteString.newOutput(); + com.google.protobuf.CodedOutputStream unknownFieldsCodedOutput = + com.google.protobuf.CodedOutputStream.newInstance( + unknownFieldsOutput); + try { + boolean done = false; + while (!done) { + int tag = input.readTag(); + switch (tag) { + case 0: + done = true; + break; + default: { + if (!parseUnknownField(input, unknownFieldsCodedOutput, + extensionRegistry, tag)) { + done = true; + } + break; + } + case 8: { + bitField0_ |= 0x00000001; + userId_ = input.readUInt32(); + break; + } + case 18: { + if (!((mutable_bitField0_ & 0x00000002) == 0x00000002)) { + userStatList_ = new java.util.ArrayList(); + mutable_bitField0_ |= 0x00000002; + } + userStatList_.add(input.readMessage(com.mogujie.tt.protobuf.IMBaseDefine.UserStat.PARSER, extensionRegistry)); + break; + } + case 162: { + bitField0_ |= 0x00000002; + attachData_ = input.readBytes(); + break; + } + } + } + } catch (com.google.protobuf.InvalidProtocolBufferException e) { + throw e.setUnfinishedMessage(this); + } catch (java.io.IOException e) { + throw new com.google.protobuf.InvalidProtocolBufferException( + e.getMessage()).setUnfinishedMessage(this); + } finally { + if (((mutable_bitField0_ & 0x00000002) == 0x00000002)) { + userStatList_ = java.util.Collections.unmodifiableList(userStatList_); + } + try { + unknownFieldsCodedOutput.flush(); + } catch (java.io.IOException e) { + // Should not happen + } finally { + unknownFields = unknownFieldsOutput.toByteString(); + } + makeExtensionsImmutable(); + } + } + public static com.google.protobuf.Parser PARSER = + new com.google.protobuf.AbstractParser() { + public IMUsersStatRsp parsePartialFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return new IMUsersStatRsp(input, extensionRegistry); + } + }; + + @java.lang.Override + public com.google.protobuf.Parser getParserForType() { + return PARSER; + } + + private int bitField0_; + public static final int USER_ID_FIELD_NUMBER = 1; + private int userId_; + /** + * required uint32 user_id = 1; + * + *
+     *cmd id:		0x020b
+     * 
+ */ + public boolean hasUserId() { + return ((bitField0_ & 0x00000001) == 0x00000001); + } + /** + * required uint32 user_id = 1; + * + *
+     *cmd id:		0x020b
+     * 
+ */ + public int getUserId() { + return userId_; + } + + public static final int USER_STAT_LIST_FIELD_NUMBER = 2; + private java.util.List userStatList_; + /** + * repeated .IM.BaseDefine.UserStat user_stat_list = 2; + */ + public java.util.List getUserStatListList() { + return userStatList_; + } + /** + * repeated .IM.BaseDefine.UserStat user_stat_list = 2; + */ + public java.util.List + getUserStatListOrBuilderList() { + return userStatList_; + } + /** + * repeated .IM.BaseDefine.UserStat user_stat_list = 2; + */ + public int getUserStatListCount() { + return userStatList_.size(); + } + /** + * repeated .IM.BaseDefine.UserStat user_stat_list = 2; + */ + public com.mogujie.tt.protobuf.IMBaseDefine.UserStat getUserStatList(int index) { + return userStatList_.get(index); + } + /** + * repeated .IM.BaseDefine.UserStat user_stat_list = 2; + */ + public com.mogujie.tt.protobuf.IMBaseDefine.UserStatOrBuilder getUserStatListOrBuilder( + int index) { + return userStatList_.get(index); + } + + public static final int ATTACH_DATA_FIELD_NUMBER = 20; + private com.google.protobuf.ByteString attachData_; + /** + * optional bytes attach_data = 20; + */ + public boolean hasAttachData() { + return ((bitField0_ & 0x00000002) == 0x00000002); + } + /** + * optional bytes attach_data = 20; + */ + public com.google.protobuf.ByteString getAttachData() { + return attachData_; + } + + private void initFields() { + userId_ = 0; + userStatList_ = java.util.Collections.emptyList(); + attachData_ = com.google.protobuf.ByteString.EMPTY; + } + private byte memoizedIsInitialized = -1; + public final boolean isInitialized() { + byte isInitialized = memoizedIsInitialized; + if (isInitialized == 1) return true; + if (isInitialized == 0) return false; + + if (!hasUserId()) { + memoizedIsInitialized = 0; + return false; + } + for (int i = 0; i < getUserStatListCount(); i++) { + if (!getUserStatList(i).isInitialized()) { + memoizedIsInitialized = 0; + return false; + } + } + memoizedIsInitialized = 1; + return true; + } + + public void writeTo(com.google.protobuf.CodedOutputStream output) + throws java.io.IOException { + getSerializedSize(); + if (((bitField0_ & 0x00000001) == 0x00000001)) { + output.writeUInt32(1, userId_); + } + for (int i = 0; i < userStatList_.size(); i++) { + output.writeMessage(2, userStatList_.get(i)); + } + if (((bitField0_ & 0x00000002) == 0x00000002)) { + output.writeBytes(20, attachData_); + } + output.writeRawBytes(unknownFields); + } + + private int memoizedSerializedSize = -1; + public int getSerializedSize() { + int size = memoizedSerializedSize; + if (size != -1) return size; + + size = 0; + if (((bitField0_ & 0x00000001) == 0x00000001)) { + size += com.google.protobuf.CodedOutputStream + .computeUInt32Size(1, userId_); + } + for (int i = 0; i < userStatList_.size(); i++) { + size += com.google.protobuf.CodedOutputStream + .computeMessageSize(2, userStatList_.get(i)); + } + if (((bitField0_ & 0x00000002) == 0x00000002)) { + size += com.google.protobuf.CodedOutputStream + .computeBytesSize(20, attachData_); + } + size += unknownFields.size(); + memoizedSerializedSize = size; + return size; + } + + private static final long serialVersionUID = 0L; + @java.lang.Override + protected java.lang.Object writeReplace() + throws java.io.ObjectStreamException { + return super.writeReplace(); + } + + public static com.mogujie.tt.protobuf.IMBuddy.IMUsersStatRsp parseFrom( + com.google.protobuf.ByteString data) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data); + } + public static com.mogujie.tt.protobuf.IMBuddy.IMUsersStatRsp parseFrom( + com.google.protobuf.ByteString data, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data, extensionRegistry); + } + public static com.mogujie.tt.protobuf.IMBuddy.IMUsersStatRsp parseFrom(byte[] data) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data); + } + public static com.mogujie.tt.protobuf.IMBuddy.IMUsersStatRsp parseFrom( + byte[] data, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data, extensionRegistry); + } + public static com.mogujie.tt.protobuf.IMBuddy.IMUsersStatRsp parseFrom(java.io.InputStream input) + throws java.io.IOException { + return PARSER.parseFrom(input); + } + public static com.mogujie.tt.protobuf.IMBuddy.IMUsersStatRsp parseFrom( + java.io.InputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return PARSER.parseFrom(input, extensionRegistry); + } + public static com.mogujie.tt.protobuf.IMBuddy.IMUsersStatRsp parseDelimitedFrom(java.io.InputStream input) + throws java.io.IOException { + return PARSER.parseDelimitedFrom(input); + } + public static com.mogujie.tt.protobuf.IMBuddy.IMUsersStatRsp parseDelimitedFrom( + java.io.InputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return PARSER.parseDelimitedFrom(input, extensionRegistry); + } + public static com.mogujie.tt.protobuf.IMBuddy.IMUsersStatRsp parseFrom( + com.google.protobuf.CodedInputStream input) + throws java.io.IOException { + return PARSER.parseFrom(input); + } + public static com.mogujie.tt.protobuf.IMBuddy.IMUsersStatRsp parseFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return PARSER.parseFrom(input, extensionRegistry); + } + + public static Builder newBuilder() { return Builder.create(); } + public Builder newBuilderForType() { return newBuilder(); } + public static Builder newBuilder(com.mogujie.tt.protobuf.IMBuddy.IMUsersStatRsp prototype) { + return newBuilder().mergeFrom(prototype); + } + public Builder toBuilder() { return newBuilder(this); } + + /** + * Protobuf type {@code IM.Buddy.IMUsersStatRsp} + */ + public static final class Builder extends + com.google.protobuf.GeneratedMessageLite.Builder< + com.mogujie.tt.protobuf.IMBuddy.IMUsersStatRsp, Builder> + implements + // @@protoc_insertion_point(builder_implements:IM.Buddy.IMUsersStatRsp) + com.mogujie.tt.protobuf.IMBuddy.IMUsersStatRspOrBuilder { + // Construct using com.mogujie.tt.protobuf.IMBuddy.IMUsersStatRsp.newBuilder() + private Builder() { + maybeForceBuilderInitialization(); + } + + private void maybeForceBuilderInitialization() { + } + private static Builder create() { + return new Builder(); + } + + public Builder clear() { + super.clear(); + userId_ = 0; + bitField0_ = (bitField0_ & ~0x00000001); + userStatList_ = java.util.Collections.emptyList(); + bitField0_ = (bitField0_ & ~0x00000002); + attachData_ = com.google.protobuf.ByteString.EMPTY; + bitField0_ = (bitField0_ & ~0x00000004); + return this; + } + + public Builder clone() { + return create().mergeFrom(buildPartial()); + } + + public com.mogujie.tt.protobuf.IMBuddy.IMUsersStatRsp getDefaultInstanceForType() { + return com.mogujie.tt.protobuf.IMBuddy.IMUsersStatRsp.getDefaultInstance(); + } + + public com.mogujie.tt.protobuf.IMBuddy.IMUsersStatRsp build() { + com.mogujie.tt.protobuf.IMBuddy.IMUsersStatRsp result = buildPartial(); + if (!result.isInitialized()) { + throw newUninitializedMessageException(result); + } + return result; + } + + public com.mogujie.tt.protobuf.IMBuddy.IMUsersStatRsp buildPartial() { + com.mogujie.tt.protobuf.IMBuddy.IMUsersStatRsp result = new com.mogujie.tt.protobuf.IMBuddy.IMUsersStatRsp(this); + int from_bitField0_ = bitField0_; + int to_bitField0_ = 0; + if (((from_bitField0_ & 0x00000001) == 0x00000001)) { + to_bitField0_ |= 0x00000001; + } + result.userId_ = userId_; + if (((bitField0_ & 0x00000002) == 0x00000002)) { + userStatList_ = java.util.Collections.unmodifiableList(userStatList_); + bitField0_ = (bitField0_ & ~0x00000002); + } + result.userStatList_ = userStatList_; + if (((from_bitField0_ & 0x00000004) == 0x00000004)) { + to_bitField0_ |= 0x00000002; + } + result.attachData_ = attachData_; + result.bitField0_ = to_bitField0_; + return result; + } + + public Builder mergeFrom(com.mogujie.tt.protobuf.IMBuddy.IMUsersStatRsp other) { + if (other == com.mogujie.tt.protobuf.IMBuddy.IMUsersStatRsp.getDefaultInstance()) return this; + if (other.hasUserId()) { + setUserId(other.getUserId()); + } + if (!other.userStatList_.isEmpty()) { + if (userStatList_.isEmpty()) { + userStatList_ = other.userStatList_; + bitField0_ = (bitField0_ & ~0x00000002); + } else { + ensureUserStatListIsMutable(); + userStatList_.addAll(other.userStatList_); + } + + } + if (other.hasAttachData()) { + setAttachData(other.getAttachData()); + } + setUnknownFields( + getUnknownFields().concat(other.unknownFields)); + return this; + } + + public final boolean isInitialized() { + if (!hasUserId()) { + + return false; + } + for (int i = 0; i < getUserStatListCount(); i++) { + if (!getUserStatList(i).isInitialized()) { + + return false; + } + } + return true; + } + + public Builder mergeFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + com.mogujie.tt.protobuf.IMBuddy.IMUsersStatRsp parsedMessage = null; + try { + parsedMessage = PARSER.parsePartialFrom(input, extensionRegistry); + } catch (com.google.protobuf.InvalidProtocolBufferException e) { + parsedMessage = (com.mogujie.tt.protobuf.IMBuddy.IMUsersStatRsp) e.getUnfinishedMessage(); + throw e; + } finally { + if (parsedMessage != null) { + mergeFrom(parsedMessage); + } + } + return this; + } + private int bitField0_; + + private int userId_ ; + /** + * required uint32 user_id = 1; + * + *
+       *cmd id:		0x020b
+       * 
+ */ + public boolean hasUserId() { + return ((bitField0_ & 0x00000001) == 0x00000001); + } + /** + * required uint32 user_id = 1; + * + *
+       *cmd id:		0x020b
+       * 
+ */ + public int getUserId() { + return userId_; + } + /** + * required uint32 user_id = 1; + * + *
+       *cmd id:		0x020b
+       * 
+ */ + public Builder setUserId(int value) { + bitField0_ |= 0x00000001; + userId_ = value; + + return this; + } + /** + * required uint32 user_id = 1; + * + *
+       *cmd id:		0x020b
+       * 
+ */ + public Builder clearUserId() { + bitField0_ = (bitField0_ & ~0x00000001); + userId_ = 0; + + return this; + } + + private java.util.List userStatList_ = + java.util.Collections.emptyList(); + private void ensureUserStatListIsMutable() { + if (!((bitField0_ & 0x00000002) == 0x00000002)) { + userStatList_ = new java.util.ArrayList(userStatList_); + bitField0_ |= 0x00000002; + } + } + + /** + * repeated .IM.BaseDefine.UserStat user_stat_list = 2; + */ + public java.util.List getUserStatListList() { + return java.util.Collections.unmodifiableList(userStatList_); + } + /** + * repeated .IM.BaseDefine.UserStat user_stat_list = 2; + */ + public int getUserStatListCount() { + return userStatList_.size(); + } + /** + * repeated .IM.BaseDefine.UserStat user_stat_list = 2; + */ + public com.mogujie.tt.protobuf.IMBaseDefine.UserStat getUserStatList(int index) { + return userStatList_.get(index); + } + /** + * repeated .IM.BaseDefine.UserStat user_stat_list = 2; + */ + public Builder setUserStatList( + int index, com.mogujie.tt.protobuf.IMBaseDefine.UserStat value) { + if (value == null) { + throw new NullPointerException(); + } + ensureUserStatListIsMutable(); + userStatList_.set(index, value); + + return this; + } + /** + * repeated .IM.BaseDefine.UserStat user_stat_list = 2; + */ + public Builder setUserStatList( + int index, com.mogujie.tt.protobuf.IMBaseDefine.UserStat.Builder builderForValue) { + ensureUserStatListIsMutable(); + userStatList_.set(index, builderForValue.build()); + + return this; + } + /** + * repeated .IM.BaseDefine.UserStat user_stat_list = 2; + */ + public Builder addUserStatList(com.mogujie.tt.protobuf.IMBaseDefine.UserStat value) { + if (value == null) { + throw new NullPointerException(); + } + ensureUserStatListIsMutable(); + userStatList_.add(value); + + return this; + } + /** + * repeated .IM.BaseDefine.UserStat user_stat_list = 2; + */ + public Builder addUserStatList( + int index, com.mogujie.tt.protobuf.IMBaseDefine.UserStat value) { + if (value == null) { + throw new NullPointerException(); + } + ensureUserStatListIsMutable(); + userStatList_.add(index, value); + + return this; + } + /** + * repeated .IM.BaseDefine.UserStat user_stat_list = 2; + */ + public Builder addUserStatList( + com.mogujie.tt.protobuf.IMBaseDefine.UserStat.Builder builderForValue) { + ensureUserStatListIsMutable(); + userStatList_.add(builderForValue.build()); + + return this; + } + /** + * repeated .IM.BaseDefine.UserStat user_stat_list = 2; + */ + public Builder addUserStatList( + int index, com.mogujie.tt.protobuf.IMBaseDefine.UserStat.Builder builderForValue) { + ensureUserStatListIsMutable(); + userStatList_.add(index, builderForValue.build()); + + return this; + } + /** + * repeated .IM.BaseDefine.UserStat user_stat_list = 2; + */ + public Builder addAllUserStatList( + java.lang.Iterable values) { + ensureUserStatListIsMutable(); + com.google.protobuf.AbstractMessageLite.Builder.addAll( + values, userStatList_); + + return this; + } + /** + * repeated .IM.BaseDefine.UserStat user_stat_list = 2; + */ + public Builder clearUserStatList() { + userStatList_ = java.util.Collections.emptyList(); + bitField0_ = (bitField0_ & ~0x00000002); + + return this; + } + /** + * repeated .IM.BaseDefine.UserStat user_stat_list = 2; + */ + public Builder removeUserStatList(int index) { + ensureUserStatListIsMutable(); + userStatList_.remove(index); + + return this; + } + + private com.google.protobuf.ByteString attachData_ = com.google.protobuf.ByteString.EMPTY; + /** + * optional bytes attach_data = 20; + */ + public boolean hasAttachData() { + return ((bitField0_ & 0x00000004) == 0x00000004); + } + /** + * optional bytes attach_data = 20; + */ + public com.google.protobuf.ByteString getAttachData() { + return attachData_; + } + /** + * optional bytes attach_data = 20; + */ + public Builder setAttachData(com.google.protobuf.ByteString value) { + if (value == null) { + throw new NullPointerException(); + } + bitField0_ |= 0x00000004; + attachData_ = value; + + return this; + } + /** + * optional bytes attach_data = 20; + */ + public Builder clearAttachData() { + bitField0_ = (bitField0_ & ~0x00000004); + attachData_ = getDefaultInstance().getAttachData(); + + return this; + } + + // @@protoc_insertion_point(builder_scope:IM.Buddy.IMUsersStatRsp) + } + + static { + defaultInstance = new IMUsersStatRsp(true); + defaultInstance.initFields(); + } + + // @@protoc_insertion_point(class_scope:IM.Buddy.IMUsersStatRsp) + } + + public interface IMChangeAvatarReqOrBuilder extends + // @@protoc_insertion_point(interface_extends:IM.Buddy.IMChangeAvatarReq) + com.google.protobuf.MessageLiteOrBuilder { + + /** + * required uint32 user_id = 1; + * + *
+     *cmd id:		0x020c
+     * 
+ */ + boolean hasUserId(); + /** + * required uint32 user_id = 1; + * + *
+     *cmd id:		0x020c
+     * 
+ */ + int getUserId(); + + /** + * required string avatar_url = 2; + */ + boolean hasAvatarUrl(); + /** + * required string avatar_url = 2; + */ + java.lang.String getAvatarUrl(); + /** + * required string avatar_url = 2; + */ + com.google.protobuf.ByteString + getAvatarUrlBytes(); + + /** + * optional bytes attach_data = 20; + */ + boolean hasAttachData(); + /** + * optional bytes attach_data = 20; + */ + com.google.protobuf.ByteString getAttachData(); + } + /** + * Protobuf type {@code IM.Buddy.IMChangeAvatarReq} + */ + public static final class IMChangeAvatarReq extends + com.google.protobuf.GeneratedMessageLite implements + // @@protoc_insertion_point(message_implements:IM.Buddy.IMChangeAvatarReq) + IMChangeAvatarReqOrBuilder { + // Use IMChangeAvatarReq.newBuilder() to construct. + private IMChangeAvatarReq(com.google.protobuf.GeneratedMessageLite.Builder builder) { + super(builder); + this.unknownFields = builder.getUnknownFields(); + } + private IMChangeAvatarReq(boolean noInit) { this.unknownFields = com.google.protobuf.ByteString.EMPTY;} + + private static final IMChangeAvatarReq defaultInstance; + public static IMChangeAvatarReq getDefaultInstance() { + return defaultInstance; + } + + public IMChangeAvatarReq getDefaultInstanceForType() { + return defaultInstance; + } + + private final com.google.protobuf.ByteString unknownFields; + private IMChangeAvatarReq( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + initFields(); + int mutable_bitField0_ = 0; + com.google.protobuf.ByteString.Output unknownFieldsOutput = + com.google.protobuf.ByteString.newOutput(); + com.google.protobuf.CodedOutputStream unknownFieldsCodedOutput = + com.google.protobuf.CodedOutputStream.newInstance( + unknownFieldsOutput); + try { + boolean done = false; + while (!done) { + int tag = input.readTag(); + switch (tag) { + case 0: + done = true; + break; + default: { + if (!parseUnknownField(input, unknownFieldsCodedOutput, + extensionRegistry, tag)) { + done = true; + } + break; + } + case 8: { + bitField0_ |= 0x00000001; + userId_ = input.readUInt32(); + break; + } + case 18: { + com.google.protobuf.ByteString bs = input.readBytes(); + bitField0_ |= 0x00000002; + avatarUrl_ = bs; + break; + } + case 162: { + bitField0_ |= 0x00000004; + attachData_ = input.readBytes(); + break; + } + } + } + } catch (com.google.protobuf.InvalidProtocolBufferException e) { + throw e.setUnfinishedMessage(this); + } catch (java.io.IOException e) { + throw new com.google.protobuf.InvalidProtocolBufferException( + e.getMessage()).setUnfinishedMessage(this); + } finally { + try { + unknownFieldsCodedOutput.flush(); + } catch (java.io.IOException e) { + // Should not happen + } finally { + unknownFields = unknownFieldsOutput.toByteString(); + } + makeExtensionsImmutable(); + } + } + public static com.google.protobuf.Parser PARSER = + new com.google.protobuf.AbstractParser() { + public IMChangeAvatarReq parsePartialFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return new IMChangeAvatarReq(input, extensionRegistry); + } + }; + + @java.lang.Override + public com.google.protobuf.Parser getParserForType() { + return PARSER; + } + + private int bitField0_; + public static final int USER_ID_FIELD_NUMBER = 1; + private int userId_; + /** + * required uint32 user_id = 1; + * + *
+     *cmd id:		0x020c
+     * 
+ */ + public boolean hasUserId() { + return ((bitField0_ & 0x00000001) == 0x00000001); + } + /** + * required uint32 user_id = 1; + * + *
+     *cmd id:		0x020c
+     * 
+ */ + public int getUserId() { + return userId_; + } + + public static final int AVATAR_URL_FIELD_NUMBER = 2; + private java.lang.Object avatarUrl_; + /** + * required string avatar_url = 2; + */ + public boolean hasAvatarUrl() { + return ((bitField0_ & 0x00000002) == 0x00000002); + } + /** + * required string avatar_url = 2; + */ + public java.lang.String getAvatarUrl() { + java.lang.Object ref = avatarUrl_; + if (ref instanceof java.lang.String) { + return (java.lang.String) ref; + } else { + com.google.protobuf.ByteString bs = + (com.google.protobuf.ByteString) ref; + java.lang.String s = bs.toStringUtf8(); + if (bs.isValidUtf8()) { + avatarUrl_ = s; + } + return s; + } + } + /** + * required string avatar_url = 2; + */ + public com.google.protobuf.ByteString + getAvatarUrlBytes() { + java.lang.Object ref = avatarUrl_; + if (ref instanceof java.lang.String) { + com.google.protobuf.ByteString b = + com.google.protobuf.ByteString.copyFromUtf8( + (java.lang.String) ref); + avatarUrl_ = b; + return b; + } else { + return (com.google.protobuf.ByteString) ref; + } + } + + public static final int ATTACH_DATA_FIELD_NUMBER = 20; + private com.google.protobuf.ByteString attachData_; + /** + * optional bytes attach_data = 20; + */ + public boolean hasAttachData() { + return ((bitField0_ & 0x00000004) == 0x00000004); + } + /** + * optional bytes attach_data = 20; + */ + public com.google.protobuf.ByteString getAttachData() { + return attachData_; + } + + private void initFields() { + userId_ = 0; + avatarUrl_ = ""; + attachData_ = com.google.protobuf.ByteString.EMPTY; + } + private byte memoizedIsInitialized = -1; + public final boolean isInitialized() { + byte isInitialized = memoizedIsInitialized; + if (isInitialized == 1) return true; + if (isInitialized == 0) return false; + + if (!hasUserId()) { + memoizedIsInitialized = 0; + return false; + } + if (!hasAvatarUrl()) { + memoizedIsInitialized = 0; + return false; + } + memoizedIsInitialized = 1; + return true; + } + + public void writeTo(com.google.protobuf.CodedOutputStream output) + throws java.io.IOException { + getSerializedSize(); + if (((bitField0_ & 0x00000001) == 0x00000001)) { + output.writeUInt32(1, userId_); + } + if (((bitField0_ & 0x00000002) == 0x00000002)) { + output.writeBytes(2, getAvatarUrlBytes()); + } + if (((bitField0_ & 0x00000004) == 0x00000004)) { + output.writeBytes(20, attachData_); + } + output.writeRawBytes(unknownFields); + } + + private int memoizedSerializedSize = -1; + public int getSerializedSize() { + int size = memoizedSerializedSize; + if (size != -1) return size; + + size = 0; + if (((bitField0_ & 0x00000001) == 0x00000001)) { + size += com.google.protobuf.CodedOutputStream + .computeUInt32Size(1, userId_); + } + if (((bitField0_ & 0x00000002) == 0x00000002)) { + size += com.google.protobuf.CodedOutputStream + .computeBytesSize(2, getAvatarUrlBytes()); + } + if (((bitField0_ & 0x00000004) == 0x00000004)) { + size += com.google.protobuf.CodedOutputStream + .computeBytesSize(20, attachData_); + } + size += unknownFields.size(); + memoizedSerializedSize = size; + return size; + } + + private static final long serialVersionUID = 0L; + @java.lang.Override + protected java.lang.Object writeReplace() + throws java.io.ObjectStreamException { + return super.writeReplace(); + } + + public static com.mogujie.tt.protobuf.IMBuddy.IMChangeAvatarReq parseFrom( + com.google.protobuf.ByteString data) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data); + } + public static com.mogujie.tt.protobuf.IMBuddy.IMChangeAvatarReq parseFrom( + com.google.protobuf.ByteString data, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data, extensionRegistry); + } + public static com.mogujie.tt.protobuf.IMBuddy.IMChangeAvatarReq parseFrom(byte[] data) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data); + } + public static com.mogujie.tt.protobuf.IMBuddy.IMChangeAvatarReq parseFrom( + byte[] data, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data, extensionRegistry); + } + public static com.mogujie.tt.protobuf.IMBuddy.IMChangeAvatarReq parseFrom(java.io.InputStream input) + throws java.io.IOException { + return PARSER.parseFrom(input); + } + public static com.mogujie.tt.protobuf.IMBuddy.IMChangeAvatarReq parseFrom( + java.io.InputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return PARSER.parseFrom(input, extensionRegistry); + } + public static com.mogujie.tt.protobuf.IMBuddy.IMChangeAvatarReq parseDelimitedFrom(java.io.InputStream input) + throws java.io.IOException { + return PARSER.parseDelimitedFrom(input); + } + public static com.mogujie.tt.protobuf.IMBuddy.IMChangeAvatarReq parseDelimitedFrom( + java.io.InputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return PARSER.parseDelimitedFrom(input, extensionRegistry); + } + public static com.mogujie.tt.protobuf.IMBuddy.IMChangeAvatarReq parseFrom( + com.google.protobuf.CodedInputStream input) + throws java.io.IOException { + return PARSER.parseFrom(input); + } + public static com.mogujie.tt.protobuf.IMBuddy.IMChangeAvatarReq parseFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return PARSER.parseFrom(input, extensionRegistry); + } + + public static Builder newBuilder() { return Builder.create(); } + public Builder newBuilderForType() { return newBuilder(); } + public static Builder newBuilder(com.mogujie.tt.protobuf.IMBuddy.IMChangeAvatarReq prototype) { + return newBuilder().mergeFrom(prototype); + } + public Builder toBuilder() { return newBuilder(this); } + + /** + * Protobuf type {@code IM.Buddy.IMChangeAvatarReq} + */ + public static final class Builder extends + com.google.protobuf.GeneratedMessageLite.Builder< + com.mogujie.tt.protobuf.IMBuddy.IMChangeAvatarReq, Builder> + implements + // @@protoc_insertion_point(builder_implements:IM.Buddy.IMChangeAvatarReq) + com.mogujie.tt.protobuf.IMBuddy.IMChangeAvatarReqOrBuilder { + // Construct using com.mogujie.tt.protobuf.IMBuddy.IMChangeAvatarReq.newBuilder() + private Builder() { + maybeForceBuilderInitialization(); + } + + private void maybeForceBuilderInitialization() { + } + private static Builder create() { + return new Builder(); + } + + public Builder clear() { + super.clear(); + userId_ = 0; + bitField0_ = (bitField0_ & ~0x00000001); + avatarUrl_ = ""; + bitField0_ = (bitField0_ & ~0x00000002); + attachData_ = com.google.protobuf.ByteString.EMPTY; + bitField0_ = (bitField0_ & ~0x00000004); + return this; + } + + public Builder clone() { + return create().mergeFrom(buildPartial()); + } + + public com.mogujie.tt.protobuf.IMBuddy.IMChangeAvatarReq getDefaultInstanceForType() { + return com.mogujie.tt.protobuf.IMBuddy.IMChangeAvatarReq.getDefaultInstance(); + } + + public com.mogujie.tt.protobuf.IMBuddy.IMChangeAvatarReq build() { + com.mogujie.tt.protobuf.IMBuddy.IMChangeAvatarReq result = buildPartial(); + if (!result.isInitialized()) { + throw newUninitializedMessageException(result); + } + return result; + } + + public com.mogujie.tt.protobuf.IMBuddy.IMChangeAvatarReq buildPartial() { + com.mogujie.tt.protobuf.IMBuddy.IMChangeAvatarReq result = new com.mogujie.tt.protobuf.IMBuddy.IMChangeAvatarReq(this); + int from_bitField0_ = bitField0_; + int to_bitField0_ = 0; + if (((from_bitField0_ & 0x00000001) == 0x00000001)) { + to_bitField0_ |= 0x00000001; + } + result.userId_ = userId_; + if (((from_bitField0_ & 0x00000002) == 0x00000002)) { + to_bitField0_ |= 0x00000002; + } + result.avatarUrl_ = avatarUrl_; + if (((from_bitField0_ & 0x00000004) == 0x00000004)) { + to_bitField0_ |= 0x00000004; + } + result.attachData_ = attachData_; + result.bitField0_ = to_bitField0_; + return result; + } + + public Builder mergeFrom(com.mogujie.tt.protobuf.IMBuddy.IMChangeAvatarReq other) { + if (other == com.mogujie.tt.protobuf.IMBuddy.IMChangeAvatarReq.getDefaultInstance()) return this; + if (other.hasUserId()) { + setUserId(other.getUserId()); + } + if (other.hasAvatarUrl()) { + bitField0_ |= 0x00000002; + avatarUrl_ = other.avatarUrl_; + + } + if (other.hasAttachData()) { + setAttachData(other.getAttachData()); + } + setUnknownFields( + getUnknownFields().concat(other.unknownFields)); + return this; + } + + public final boolean isInitialized() { + if (!hasUserId()) { + + return false; + } + if (!hasAvatarUrl()) { + + return false; + } + return true; + } + + public Builder mergeFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + com.mogujie.tt.protobuf.IMBuddy.IMChangeAvatarReq parsedMessage = null; + try { + parsedMessage = PARSER.parsePartialFrom(input, extensionRegistry); + } catch (com.google.protobuf.InvalidProtocolBufferException e) { + parsedMessage = (com.mogujie.tt.protobuf.IMBuddy.IMChangeAvatarReq) e.getUnfinishedMessage(); + throw e; + } finally { + if (parsedMessage != null) { + mergeFrom(parsedMessage); + } + } + return this; + } + private int bitField0_; + + private int userId_ ; + /** + * required uint32 user_id = 1; + * + *
+       *cmd id:		0x020c
+       * 
+ */ + public boolean hasUserId() { + return ((bitField0_ & 0x00000001) == 0x00000001); + } + /** + * required uint32 user_id = 1; + * + *
+       *cmd id:		0x020c
+       * 
+ */ + public int getUserId() { + return userId_; + } + /** + * required uint32 user_id = 1; + * + *
+       *cmd id:		0x020c
+       * 
+ */ + public Builder setUserId(int value) { + bitField0_ |= 0x00000001; + userId_ = value; + + return this; + } + /** + * required uint32 user_id = 1; + * + *
+       *cmd id:		0x020c
+       * 
+ */ + public Builder clearUserId() { + bitField0_ = (bitField0_ & ~0x00000001); + userId_ = 0; + + return this; + } + + private java.lang.Object avatarUrl_ = ""; + /** + * required string avatar_url = 2; + */ + public boolean hasAvatarUrl() { + return ((bitField0_ & 0x00000002) == 0x00000002); + } + /** + * required string avatar_url = 2; + */ + public java.lang.String getAvatarUrl() { + java.lang.Object ref = avatarUrl_; + if (!(ref instanceof java.lang.String)) { + com.google.protobuf.ByteString bs = + (com.google.protobuf.ByteString) ref; + java.lang.String s = bs.toStringUtf8(); + if (bs.isValidUtf8()) { + avatarUrl_ = s; + } + return s; + } else { + return (java.lang.String) ref; + } + } + /** + * required string avatar_url = 2; + */ + public com.google.protobuf.ByteString + getAvatarUrlBytes() { + java.lang.Object ref = avatarUrl_; + if (ref instanceof String) { + com.google.protobuf.ByteString b = + com.google.protobuf.ByteString.copyFromUtf8( + (java.lang.String) ref); + avatarUrl_ = b; + return b; + } else { + return (com.google.protobuf.ByteString) ref; + } + } + /** + * required string avatar_url = 2; + */ + public Builder setAvatarUrl( + java.lang.String value) { + if (value == null) { + throw new NullPointerException(); + } + bitField0_ |= 0x00000002; + avatarUrl_ = value; + + return this; + } + /** + * required string avatar_url = 2; + */ + public Builder clearAvatarUrl() { + bitField0_ = (bitField0_ & ~0x00000002); + avatarUrl_ = getDefaultInstance().getAvatarUrl(); + + return this; + } + /** + * required string avatar_url = 2; + */ + public Builder setAvatarUrlBytes( + com.google.protobuf.ByteString value) { + if (value == null) { + throw new NullPointerException(); + } + bitField0_ |= 0x00000002; + avatarUrl_ = value; + + return this; + } + + private com.google.protobuf.ByteString attachData_ = com.google.protobuf.ByteString.EMPTY; + /** + * optional bytes attach_data = 20; + */ + public boolean hasAttachData() { + return ((bitField0_ & 0x00000004) == 0x00000004); + } + /** + * optional bytes attach_data = 20; + */ + public com.google.protobuf.ByteString getAttachData() { + return attachData_; + } + /** + * optional bytes attach_data = 20; + */ + public Builder setAttachData(com.google.protobuf.ByteString value) { + if (value == null) { + throw new NullPointerException(); + } + bitField0_ |= 0x00000004; + attachData_ = value; + + return this; + } + /** + * optional bytes attach_data = 20; + */ + public Builder clearAttachData() { + bitField0_ = (bitField0_ & ~0x00000004); + attachData_ = getDefaultInstance().getAttachData(); + + return this; + } + + // @@protoc_insertion_point(builder_scope:IM.Buddy.IMChangeAvatarReq) + } + + static { + defaultInstance = new IMChangeAvatarReq(true); + defaultInstance.initFields(); + } + + // @@protoc_insertion_point(class_scope:IM.Buddy.IMChangeAvatarReq) + } + + public interface IMChangeAvatarRspOrBuilder extends + // @@protoc_insertion_point(interface_extends:IM.Buddy.IMChangeAvatarRsp) + com.google.protobuf.MessageLiteOrBuilder { + + /** + * required uint32 user_id = 1; + * + *
+     *cmd id:		0x020d
+     * 
+ */ + boolean hasUserId(); + /** + * required uint32 user_id = 1; + * + *
+     *cmd id:		0x020d
+     * 
+ */ + int getUserId(); + + /** + * required uint32 result_code = 2; + */ + boolean hasResultCode(); + /** + * required uint32 result_code = 2; + */ + int getResultCode(); + + /** + * optional bytes attach_data = 20; + */ + boolean hasAttachData(); + /** + * optional bytes attach_data = 20; + */ + com.google.protobuf.ByteString getAttachData(); + } + /** + * Protobuf type {@code IM.Buddy.IMChangeAvatarRsp} + */ + public static final class IMChangeAvatarRsp extends + com.google.protobuf.GeneratedMessageLite implements + // @@protoc_insertion_point(message_implements:IM.Buddy.IMChangeAvatarRsp) + IMChangeAvatarRspOrBuilder { + // Use IMChangeAvatarRsp.newBuilder() to construct. + private IMChangeAvatarRsp(com.google.protobuf.GeneratedMessageLite.Builder builder) { + super(builder); + this.unknownFields = builder.getUnknownFields(); + } + private IMChangeAvatarRsp(boolean noInit) { this.unknownFields = com.google.protobuf.ByteString.EMPTY;} + + private static final IMChangeAvatarRsp defaultInstance; + public static IMChangeAvatarRsp getDefaultInstance() { + return defaultInstance; + } + + public IMChangeAvatarRsp getDefaultInstanceForType() { + return defaultInstance; + } + + private final com.google.protobuf.ByteString unknownFields; + private IMChangeAvatarRsp( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + initFields(); + int mutable_bitField0_ = 0; + com.google.protobuf.ByteString.Output unknownFieldsOutput = + com.google.protobuf.ByteString.newOutput(); + com.google.protobuf.CodedOutputStream unknownFieldsCodedOutput = + com.google.protobuf.CodedOutputStream.newInstance( + unknownFieldsOutput); + try { + boolean done = false; + while (!done) { + int tag = input.readTag(); + switch (tag) { + case 0: + done = true; + break; + default: { + if (!parseUnknownField(input, unknownFieldsCodedOutput, + extensionRegistry, tag)) { + done = true; + } + break; + } + case 8: { + bitField0_ |= 0x00000001; + userId_ = input.readUInt32(); + break; + } + case 16: { + bitField0_ |= 0x00000002; + resultCode_ = input.readUInt32(); + break; + } + case 162: { + bitField0_ |= 0x00000004; + attachData_ = input.readBytes(); + break; + } + } + } + } catch (com.google.protobuf.InvalidProtocolBufferException e) { + throw e.setUnfinishedMessage(this); + } catch (java.io.IOException e) { + throw new com.google.protobuf.InvalidProtocolBufferException( + e.getMessage()).setUnfinishedMessage(this); + } finally { + try { + unknownFieldsCodedOutput.flush(); + } catch (java.io.IOException e) { + // Should not happen + } finally { + unknownFields = unknownFieldsOutput.toByteString(); + } + makeExtensionsImmutable(); + } + } + public static com.google.protobuf.Parser PARSER = + new com.google.protobuf.AbstractParser() { + public IMChangeAvatarRsp parsePartialFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return new IMChangeAvatarRsp(input, extensionRegistry); + } + }; + + @java.lang.Override + public com.google.protobuf.Parser getParserForType() { + return PARSER; + } + + private int bitField0_; + public static final int USER_ID_FIELD_NUMBER = 1; + private int userId_; + /** + * required uint32 user_id = 1; + * + *
+     *cmd id:		0x020d
+     * 
+ */ + public boolean hasUserId() { + return ((bitField0_ & 0x00000001) == 0x00000001); + } + /** + * required uint32 user_id = 1; + * + *
+     *cmd id:		0x020d
+     * 
+ */ + public int getUserId() { + return userId_; + } + + public static final int RESULT_CODE_FIELD_NUMBER = 2; + private int resultCode_; + /** + * required uint32 result_code = 2; + */ + public boolean hasResultCode() { + return ((bitField0_ & 0x00000002) == 0x00000002); + } + /** + * required uint32 result_code = 2; + */ + public int getResultCode() { + return resultCode_; + } + + public static final int ATTACH_DATA_FIELD_NUMBER = 20; + private com.google.protobuf.ByteString attachData_; + /** + * optional bytes attach_data = 20; + */ + public boolean hasAttachData() { + return ((bitField0_ & 0x00000004) == 0x00000004); + } + /** + * optional bytes attach_data = 20; + */ + public com.google.protobuf.ByteString getAttachData() { + return attachData_; + } + + private void initFields() { + userId_ = 0; + resultCode_ = 0; + attachData_ = com.google.protobuf.ByteString.EMPTY; + } + private byte memoizedIsInitialized = -1; + public final boolean isInitialized() { + byte isInitialized = memoizedIsInitialized; + if (isInitialized == 1) return true; + if (isInitialized == 0) return false; + + if (!hasUserId()) { + memoizedIsInitialized = 0; + return false; + } + if (!hasResultCode()) { + memoizedIsInitialized = 0; + return false; + } + memoizedIsInitialized = 1; + return true; + } + + public void writeTo(com.google.protobuf.CodedOutputStream output) + throws java.io.IOException { + getSerializedSize(); + if (((bitField0_ & 0x00000001) == 0x00000001)) { + output.writeUInt32(1, userId_); + } + if (((bitField0_ & 0x00000002) == 0x00000002)) { + output.writeUInt32(2, resultCode_); + } + if (((bitField0_ & 0x00000004) == 0x00000004)) { + output.writeBytes(20, attachData_); + } + output.writeRawBytes(unknownFields); + } + + private int memoizedSerializedSize = -1; + public int getSerializedSize() { + int size = memoizedSerializedSize; + if (size != -1) return size; + + size = 0; + if (((bitField0_ & 0x00000001) == 0x00000001)) { + size += com.google.protobuf.CodedOutputStream + .computeUInt32Size(1, userId_); + } + if (((bitField0_ & 0x00000002) == 0x00000002)) { + size += com.google.protobuf.CodedOutputStream + .computeUInt32Size(2, resultCode_); + } + if (((bitField0_ & 0x00000004) == 0x00000004)) { + size += com.google.protobuf.CodedOutputStream + .computeBytesSize(20, attachData_); + } + size += unknownFields.size(); + memoizedSerializedSize = size; + return size; + } + + private static final long serialVersionUID = 0L; + @java.lang.Override + protected java.lang.Object writeReplace() + throws java.io.ObjectStreamException { + return super.writeReplace(); + } + + public static com.mogujie.tt.protobuf.IMBuddy.IMChangeAvatarRsp parseFrom( + com.google.protobuf.ByteString data) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data); + } + public static com.mogujie.tt.protobuf.IMBuddy.IMChangeAvatarRsp parseFrom( + com.google.protobuf.ByteString data, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data, extensionRegistry); + } + public static com.mogujie.tt.protobuf.IMBuddy.IMChangeAvatarRsp parseFrom(byte[] data) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data); + } + public static com.mogujie.tt.protobuf.IMBuddy.IMChangeAvatarRsp parseFrom( + byte[] data, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data, extensionRegistry); + } + public static com.mogujie.tt.protobuf.IMBuddy.IMChangeAvatarRsp parseFrom(java.io.InputStream input) + throws java.io.IOException { + return PARSER.parseFrom(input); + } + public static com.mogujie.tt.protobuf.IMBuddy.IMChangeAvatarRsp parseFrom( + java.io.InputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return PARSER.parseFrom(input, extensionRegistry); + } + public static com.mogujie.tt.protobuf.IMBuddy.IMChangeAvatarRsp parseDelimitedFrom(java.io.InputStream input) + throws java.io.IOException { + return PARSER.parseDelimitedFrom(input); + } + public static com.mogujie.tt.protobuf.IMBuddy.IMChangeAvatarRsp parseDelimitedFrom( + java.io.InputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return PARSER.parseDelimitedFrom(input, extensionRegistry); + } + public static com.mogujie.tt.protobuf.IMBuddy.IMChangeAvatarRsp parseFrom( + com.google.protobuf.CodedInputStream input) + throws java.io.IOException { + return PARSER.parseFrom(input); + } + public static com.mogujie.tt.protobuf.IMBuddy.IMChangeAvatarRsp parseFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return PARSER.parseFrom(input, extensionRegistry); + } + + public static Builder newBuilder() { return Builder.create(); } + public Builder newBuilderForType() { return newBuilder(); } + public static Builder newBuilder(com.mogujie.tt.protobuf.IMBuddy.IMChangeAvatarRsp prototype) { + return newBuilder().mergeFrom(prototype); + } + public Builder toBuilder() { return newBuilder(this); } + + /** + * Protobuf type {@code IM.Buddy.IMChangeAvatarRsp} + */ + public static final class Builder extends + com.google.protobuf.GeneratedMessageLite.Builder< + com.mogujie.tt.protobuf.IMBuddy.IMChangeAvatarRsp, Builder> + implements + // @@protoc_insertion_point(builder_implements:IM.Buddy.IMChangeAvatarRsp) + com.mogujie.tt.protobuf.IMBuddy.IMChangeAvatarRspOrBuilder { + // Construct using com.mogujie.tt.protobuf.IMBuddy.IMChangeAvatarRsp.newBuilder() + private Builder() { + maybeForceBuilderInitialization(); + } + + private void maybeForceBuilderInitialization() { + } + private static Builder create() { + return new Builder(); + } + + public Builder clear() { + super.clear(); + userId_ = 0; + bitField0_ = (bitField0_ & ~0x00000001); + resultCode_ = 0; + bitField0_ = (bitField0_ & ~0x00000002); + attachData_ = com.google.protobuf.ByteString.EMPTY; + bitField0_ = (bitField0_ & ~0x00000004); + return this; + } + + public Builder clone() { + return create().mergeFrom(buildPartial()); + } + + public com.mogujie.tt.protobuf.IMBuddy.IMChangeAvatarRsp getDefaultInstanceForType() { + return com.mogujie.tt.protobuf.IMBuddy.IMChangeAvatarRsp.getDefaultInstance(); + } + + public com.mogujie.tt.protobuf.IMBuddy.IMChangeAvatarRsp build() { + com.mogujie.tt.protobuf.IMBuddy.IMChangeAvatarRsp result = buildPartial(); + if (!result.isInitialized()) { + throw newUninitializedMessageException(result); + } + return result; + } + + public com.mogujie.tt.protobuf.IMBuddy.IMChangeAvatarRsp buildPartial() { + com.mogujie.tt.protobuf.IMBuddy.IMChangeAvatarRsp result = new com.mogujie.tt.protobuf.IMBuddy.IMChangeAvatarRsp(this); + int from_bitField0_ = bitField0_; + int to_bitField0_ = 0; + if (((from_bitField0_ & 0x00000001) == 0x00000001)) { + to_bitField0_ |= 0x00000001; + } + result.userId_ = userId_; + if (((from_bitField0_ & 0x00000002) == 0x00000002)) { + to_bitField0_ |= 0x00000002; + } + result.resultCode_ = resultCode_; + if (((from_bitField0_ & 0x00000004) == 0x00000004)) { + to_bitField0_ |= 0x00000004; + } + result.attachData_ = attachData_; + result.bitField0_ = to_bitField0_; + return result; + } + + public Builder mergeFrom(com.mogujie.tt.protobuf.IMBuddy.IMChangeAvatarRsp other) { + if (other == com.mogujie.tt.protobuf.IMBuddy.IMChangeAvatarRsp.getDefaultInstance()) return this; + if (other.hasUserId()) { + setUserId(other.getUserId()); + } + if (other.hasResultCode()) { + setResultCode(other.getResultCode()); + } + if (other.hasAttachData()) { + setAttachData(other.getAttachData()); + } + setUnknownFields( + getUnknownFields().concat(other.unknownFields)); + return this; + } + + public final boolean isInitialized() { + if (!hasUserId()) { + + return false; + } + if (!hasResultCode()) { + + return false; + } + return true; + } + + public Builder mergeFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + com.mogujie.tt.protobuf.IMBuddy.IMChangeAvatarRsp parsedMessage = null; + try { + parsedMessage = PARSER.parsePartialFrom(input, extensionRegistry); + } catch (com.google.protobuf.InvalidProtocolBufferException e) { + parsedMessage = (com.mogujie.tt.protobuf.IMBuddy.IMChangeAvatarRsp) e.getUnfinishedMessage(); + throw e; + } finally { + if (parsedMessage != null) { + mergeFrom(parsedMessage); + } + } + return this; + } + private int bitField0_; + + private int userId_ ; + /** + * required uint32 user_id = 1; + * + *
+       *cmd id:		0x020d
+       * 
+ */ + public boolean hasUserId() { + return ((bitField0_ & 0x00000001) == 0x00000001); + } + /** + * required uint32 user_id = 1; + * + *
+       *cmd id:		0x020d
+       * 
+ */ + public int getUserId() { + return userId_; + } + /** + * required uint32 user_id = 1; + * + *
+       *cmd id:		0x020d
+       * 
+ */ + public Builder setUserId(int value) { + bitField0_ |= 0x00000001; + userId_ = value; + + return this; + } + /** + * required uint32 user_id = 1; + * + *
+       *cmd id:		0x020d
+       * 
+ */ + public Builder clearUserId() { + bitField0_ = (bitField0_ & ~0x00000001); + userId_ = 0; + + return this; + } + + private int resultCode_ ; + /** + * required uint32 result_code = 2; + */ + public boolean hasResultCode() { + return ((bitField0_ & 0x00000002) == 0x00000002); + } + /** + * required uint32 result_code = 2; + */ + public int getResultCode() { + return resultCode_; + } + /** + * required uint32 result_code = 2; + */ + public Builder setResultCode(int value) { + bitField0_ |= 0x00000002; + resultCode_ = value; + + return this; + } + /** + * required uint32 result_code = 2; + */ + public Builder clearResultCode() { + bitField0_ = (bitField0_ & ~0x00000002); + resultCode_ = 0; + + return this; + } + + private com.google.protobuf.ByteString attachData_ = com.google.protobuf.ByteString.EMPTY; + /** + * optional bytes attach_data = 20; + */ + public boolean hasAttachData() { + return ((bitField0_ & 0x00000004) == 0x00000004); + } + /** + * optional bytes attach_data = 20; + */ + public com.google.protobuf.ByteString getAttachData() { + return attachData_; + } + /** + * optional bytes attach_data = 20; + */ + public Builder setAttachData(com.google.protobuf.ByteString value) { + if (value == null) { + throw new NullPointerException(); + } + bitField0_ |= 0x00000004; + attachData_ = value; + + return this; + } + /** + * optional bytes attach_data = 20; + */ + public Builder clearAttachData() { + bitField0_ = (bitField0_ & ~0x00000004); + attachData_ = getDefaultInstance().getAttachData(); + + return this; + } + + // @@protoc_insertion_point(builder_scope:IM.Buddy.IMChangeAvatarRsp) + } + + static { + defaultInstance = new IMChangeAvatarRsp(true); + defaultInstance.initFields(); + } + + // @@protoc_insertion_point(class_scope:IM.Buddy.IMChangeAvatarRsp) + } + + public interface IMPCLoginStatusNotifyOrBuilder extends + // @@protoc_insertion_point(interface_extends:IM.Buddy.IMPCLoginStatusNotify) + com.google.protobuf.MessageLiteOrBuilder { + + /** + * required uint32 user_id = 1; + * + *
+     *cmd id:		0x020e
+     * 
+ */ + boolean hasUserId(); + /** + * required uint32 user_id = 1; + * + *
+     *cmd id:		0x020e
+     * 
+ */ + int getUserId(); + + /** + * required .IM.BaseDefine.UserStatType login_stat = 2; + */ + boolean hasLoginStat(); + /** + * required .IM.BaseDefine.UserStatType login_stat = 2; + */ + com.mogujie.tt.protobuf.IMBaseDefine.UserStatType getLoginStat(); + } + /** + * Protobuf type {@code IM.Buddy.IMPCLoginStatusNotify} + * + *
+   *只给移动端通知
+   * 
+ */ + public static final class IMPCLoginStatusNotify extends + com.google.protobuf.GeneratedMessageLite implements + // @@protoc_insertion_point(message_implements:IM.Buddy.IMPCLoginStatusNotify) + IMPCLoginStatusNotifyOrBuilder { + // Use IMPCLoginStatusNotify.newBuilder() to construct. + private IMPCLoginStatusNotify(com.google.protobuf.GeneratedMessageLite.Builder builder) { + super(builder); + this.unknownFields = builder.getUnknownFields(); + } + private IMPCLoginStatusNotify(boolean noInit) { this.unknownFields = com.google.protobuf.ByteString.EMPTY;} + + private static final IMPCLoginStatusNotify defaultInstance; + public static IMPCLoginStatusNotify getDefaultInstance() { + return defaultInstance; + } + + public IMPCLoginStatusNotify getDefaultInstanceForType() { + return defaultInstance; + } + + private final com.google.protobuf.ByteString unknownFields; + private IMPCLoginStatusNotify( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + initFields(); + int mutable_bitField0_ = 0; + com.google.protobuf.ByteString.Output unknownFieldsOutput = + com.google.protobuf.ByteString.newOutput(); + com.google.protobuf.CodedOutputStream unknownFieldsCodedOutput = + com.google.protobuf.CodedOutputStream.newInstance( + unknownFieldsOutput); + try { + boolean done = false; + while (!done) { + int tag = input.readTag(); + switch (tag) { + case 0: + done = true; + break; + default: { + if (!parseUnknownField(input, unknownFieldsCodedOutput, + extensionRegistry, tag)) { + done = true; + } + break; + } + case 8: { + bitField0_ |= 0x00000001; + userId_ = input.readUInt32(); + break; + } + case 16: { + int rawValue = input.readEnum(); + com.mogujie.tt.protobuf.IMBaseDefine.UserStatType value = com.mogujie.tt.protobuf.IMBaseDefine.UserStatType.valueOf(rawValue); + if (value == null) { + unknownFieldsCodedOutput.writeRawVarint32(tag); + unknownFieldsCodedOutput.writeRawVarint32(rawValue); + } else { + bitField0_ |= 0x00000002; + loginStat_ = value; + } + break; + } + } + } + } catch (com.google.protobuf.InvalidProtocolBufferException e) { + throw e.setUnfinishedMessage(this); + } catch (java.io.IOException e) { + throw new com.google.protobuf.InvalidProtocolBufferException( + e.getMessage()).setUnfinishedMessage(this); + } finally { + try { + unknownFieldsCodedOutput.flush(); + } catch (java.io.IOException e) { + // Should not happen + } finally { + unknownFields = unknownFieldsOutput.toByteString(); + } + makeExtensionsImmutable(); + } + } + public static com.google.protobuf.Parser PARSER = + new com.google.protobuf.AbstractParser() { + public IMPCLoginStatusNotify parsePartialFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return new IMPCLoginStatusNotify(input, extensionRegistry); + } + }; + + @java.lang.Override + public com.google.protobuf.Parser getParserForType() { + return PARSER; + } + + private int bitField0_; + public static final int USER_ID_FIELD_NUMBER = 1; + private int userId_; + /** + * required uint32 user_id = 1; + * + *
+     *cmd id:		0x020e
+     * 
+ */ + public boolean hasUserId() { + return ((bitField0_ & 0x00000001) == 0x00000001); + } + /** + * required uint32 user_id = 1; + * + *
+     *cmd id:		0x020e
+     * 
+ */ + public int getUserId() { + return userId_; + } + + public static final int LOGIN_STAT_FIELD_NUMBER = 2; + private com.mogujie.tt.protobuf.IMBaseDefine.UserStatType loginStat_; + /** + * required .IM.BaseDefine.UserStatType login_stat = 2; + */ + public boolean hasLoginStat() { + return ((bitField0_ & 0x00000002) == 0x00000002); + } + /** + * required .IM.BaseDefine.UserStatType login_stat = 2; + */ + public com.mogujie.tt.protobuf.IMBaseDefine.UserStatType getLoginStat() { + return loginStat_; + } + + private void initFields() { + userId_ = 0; + loginStat_ = com.mogujie.tt.protobuf.IMBaseDefine.UserStatType.USER_STATUS_ONLINE; + } + private byte memoizedIsInitialized = -1; + public final boolean isInitialized() { + byte isInitialized = memoizedIsInitialized; + if (isInitialized == 1) return true; + if (isInitialized == 0) return false; + + if (!hasUserId()) { + memoizedIsInitialized = 0; + return false; + } + if (!hasLoginStat()) { + memoizedIsInitialized = 0; + return false; + } + memoizedIsInitialized = 1; + return true; + } + + public void writeTo(com.google.protobuf.CodedOutputStream output) + throws java.io.IOException { + getSerializedSize(); + if (((bitField0_ & 0x00000001) == 0x00000001)) { + output.writeUInt32(1, userId_); + } + if (((bitField0_ & 0x00000002) == 0x00000002)) { + output.writeEnum(2, loginStat_.getNumber()); + } + output.writeRawBytes(unknownFields); + } + + private int memoizedSerializedSize = -1; + public int getSerializedSize() { + int size = memoizedSerializedSize; + if (size != -1) return size; + + size = 0; + if (((bitField0_ & 0x00000001) == 0x00000001)) { + size += com.google.protobuf.CodedOutputStream + .computeUInt32Size(1, userId_); + } + if (((bitField0_ & 0x00000002) == 0x00000002)) { + size += com.google.protobuf.CodedOutputStream + .computeEnumSize(2, loginStat_.getNumber()); + } + size += unknownFields.size(); + memoizedSerializedSize = size; + return size; + } + + private static final long serialVersionUID = 0L; + @java.lang.Override + protected java.lang.Object writeReplace() + throws java.io.ObjectStreamException { + return super.writeReplace(); + } + + public static com.mogujie.tt.protobuf.IMBuddy.IMPCLoginStatusNotify parseFrom( + com.google.protobuf.ByteString data) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data); + } + public static com.mogujie.tt.protobuf.IMBuddy.IMPCLoginStatusNotify parseFrom( + com.google.protobuf.ByteString data, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data, extensionRegistry); + } + public static com.mogujie.tt.protobuf.IMBuddy.IMPCLoginStatusNotify parseFrom(byte[] data) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data); + } + public static com.mogujie.tt.protobuf.IMBuddy.IMPCLoginStatusNotify parseFrom( + byte[] data, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data, extensionRegistry); + } + public static com.mogujie.tt.protobuf.IMBuddy.IMPCLoginStatusNotify parseFrom(java.io.InputStream input) + throws java.io.IOException { + return PARSER.parseFrom(input); + } + public static com.mogujie.tt.protobuf.IMBuddy.IMPCLoginStatusNotify parseFrom( + java.io.InputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return PARSER.parseFrom(input, extensionRegistry); + } + public static com.mogujie.tt.protobuf.IMBuddy.IMPCLoginStatusNotify parseDelimitedFrom(java.io.InputStream input) + throws java.io.IOException { + return PARSER.parseDelimitedFrom(input); + } + public static com.mogujie.tt.protobuf.IMBuddy.IMPCLoginStatusNotify parseDelimitedFrom( + java.io.InputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return PARSER.parseDelimitedFrom(input, extensionRegistry); + } + public static com.mogujie.tt.protobuf.IMBuddy.IMPCLoginStatusNotify parseFrom( + com.google.protobuf.CodedInputStream input) + throws java.io.IOException { + return PARSER.parseFrom(input); + } + public static com.mogujie.tt.protobuf.IMBuddy.IMPCLoginStatusNotify parseFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return PARSER.parseFrom(input, extensionRegistry); + } + + public static Builder newBuilder() { return Builder.create(); } + public Builder newBuilderForType() { return newBuilder(); } + public static Builder newBuilder(com.mogujie.tt.protobuf.IMBuddy.IMPCLoginStatusNotify prototype) { + return newBuilder().mergeFrom(prototype); + } + public Builder toBuilder() { return newBuilder(this); } + + /** + * Protobuf type {@code IM.Buddy.IMPCLoginStatusNotify} + * + *
+     *只给移动端通知
+     * 
+ */ + public static final class Builder extends + com.google.protobuf.GeneratedMessageLite.Builder< + com.mogujie.tt.protobuf.IMBuddy.IMPCLoginStatusNotify, Builder> + implements + // @@protoc_insertion_point(builder_implements:IM.Buddy.IMPCLoginStatusNotify) + com.mogujie.tt.protobuf.IMBuddy.IMPCLoginStatusNotifyOrBuilder { + // Construct using com.mogujie.tt.protobuf.IMBuddy.IMPCLoginStatusNotify.newBuilder() + private Builder() { + maybeForceBuilderInitialization(); + } + + private void maybeForceBuilderInitialization() { + } + private static Builder create() { + return new Builder(); + } + + public Builder clear() { + super.clear(); + userId_ = 0; + bitField0_ = (bitField0_ & ~0x00000001); + loginStat_ = com.mogujie.tt.protobuf.IMBaseDefine.UserStatType.USER_STATUS_ONLINE; + bitField0_ = (bitField0_ & ~0x00000002); + return this; + } + + public Builder clone() { + return create().mergeFrom(buildPartial()); + } + + public com.mogujie.tt.protobuf.IMBuddy.IMPCLoginStatusNotify getDefaultInstanceForType() { + return com.mogujie.tt.protobuf.IMBuddy.IMPCLoginStatusNotify.getDefaultInstance(); + } + + public com.mogujie.tt.protobuf.IMBuddy.IMPCLoginStatusNotify build() { + com.mogujie.tt.protobuf.IMBuddy.IMPCLoginStatusNotify result = buildPartial(); + if (!result.isInitialized()) { + throw newUninitializedMessageException(result); + } + return result; + } + + public com.mogujie.tt.protobuf.IMBuddy.IMPCLoginStatusNotify buildPartial() { + com.mogujie.tt.protobuf.IMBuddy.IMPCLoginStatusNotify result = new com.mogujie.tt.protobuf.IMBuddy.IMPCLoginStatusNotify(this); + int from_bitField0_ = bitField0_; + int to_bitField0_ = 0; + if (((from_bitField0_ & 0x00000001) == 0x00000001)) { + to_bitField0_ |= 0x00000001; + } + result.userId_ = userId_; + if (((from_bitField0_ & 0x00000002) == 0x00000002)) { + to_bitField0_ |= 0x00000002; + } + result.loginStat_ = loginStat_; + result.bitField0_ = to_bitField0_; + return result; + } + + public Builder mergeFrom(com.mogujie.tt.protobuf.IMBuddy.IMPCLoginStatusNotify other) { + if (other == com.mogujie.tt.protobuf.IMBuddy.IMPCLoginStatusNotify.getDefaultInstance()) return this; + if (other.hasUserId()) { + setUserId(other.getUserId()); + } + if (other.hasLoginStat()) { + setLoginStat(other.getLoginStat()); + } + setUnknownFields( + getUnknownFields().concat(other.unknownFields)); + return this; + } + + public final boolean isInitialized() { + if (!hasUserId()) { + + return false; + } + if (!hasLoginStat()) { + + return false; + } + return true; + } + + public Builder mergeFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + com.mogujie.tt.protobuf.IMBuddy.IMPCLoginStatusNotify parsedMessage = null; + try { + parsedMessage = PARSER.parsePartialFrom(input, extensionRegistry); + } catch (com.google.protobuf.InvalidProtocolBufferException e) { + parsedMessage = (com.mogujie.tt.protobuf.IMBuddy.IMPCLoginStatusNotify) e.getUnfinishedMessage(); + throw e; + } finally { + if (parsedMessage != null) { + mergeFrom(parsedMessage); + } + } + return this; + } + private int bitField0_; + + private int userId_ ; + /** + * required uint32 user_id = 1; + * + *
+       *cmd id:		0x020e
+       * 
+ */ + public boolean hasUserId() { + return ((bitField0_ & 0x00000001) == 0x00000001); + } + /** + * required uint32 user_id = 1; + * + *
+       *cmd id:		0x020e
+       * 
+ */ + public int getUserId() { + return userId_; + } + /** + * required uint32 user_id = 1; + * + *
+       *cmd id:		0x020e
+       * 
+ */ + public Builder setUserId(int value) { + bitField0_ |= 0x00000001; + userId_ = value; + + return this; + } + /** + * required uint32 user_id = 1; + * + *
+       *cmd id:		0x020e
+       * 
+ */ + public Builder clearUserId() { + bitField0_ = (bitField0_ & ~0x00000001); + userId_ = 0; + + return this; + } + + private com.mogujie.tt.protobuf.IMBaseDefine.UserStatType loginStat_ = com.mogujie.tt.protobuf.IMBaseDefine.UserStatType.USER_STATUS_ONLINE; + /** + * required .IM.BaseDefine.UserStatType login_stat = 2; + */ + public boolean hasLoginStat() { + return ((bitField0_ & 0x00000002) == 0x00000002); + } + /** + * required .IM.BaseDefine.UserStatType login_stat = 2; + */ + public com.mogujie.tt.protobuf.IMBaseDefine.UserStatType getLoginStat() { + return loginStat_; + } + /** + * required .IM.BaseDefine.UserStatType login_stat = 2; + */ + public Builder setLoginStat(com.mogujie.tt.protobuf.IMBaseDefine.UserStatType value) { + if (value == null) { + throw new NullPointerException(); + } + bitField0_ |= 0x00000002; + loginStat_ = value; + + return this; + } + /** + * required .IM.BaseDefine.UserStatType login_stat = 2; + */ + public Builder clearLoginStat() { + bitField0_ = (bitField0_ & ~0x00000002); + loginStat_ = com.mogujie.tt.protobuf.IMBaseDefine.UserStatType.USER_STATUS_ONLINE; + + return this; + } + + // @@protoc_insertion_point(builder_scope:IM.Buddy.IMPCLoginStatusNotify) + } + + static { + defaultInstance = new IMPCLoginStatusNotify(true); + defaultInstance.initFields(); + } + + // @@protoc_insertion_point(class_scope:IM.Buddy.IMPCLoginStatusNotify) + } + + public interface IMRemoveSessionNotifyOrBuilder extends + // @@protoc_insertion_point(interface_extends:IM.Buddy.IMRemoveSessionNotify) + com.google.protobuf.MessageLiteOrBuilder { + + /** + * required uint32 user_id = 1; + * + *
+     *cmd id:		0x020f
+     * 
+ */ + boolean hasUserId(); + /** + * required uint32 user_id = 1; + * + *
+     *cmd id:		0x020f
+     * 
+ */ + int getUserId(); + + /** + * required .IM.BaseDefine.SessionType session_type = 2; + */ + boolean hasSessionType(); + /** + * required .IM.BaseDefine.SessionType session_type = 2; + */ + com.mogujie.tt.protobuf.IMBaseDefine.SessionType getSessionType(); + + /** + * required uint32 session_id = 3; + */ + boolean hasSessionId(); + /** + * required uint32 session_id = 3; + */ + int getSessionId(); + } + /** + * Protobuf type {@code IM.Buddy.IMRemoveSessionNotify} + */ + public static final class IMRemoveSessionNotify extends + com.google.protobuf.GeneratedMessageLite implements + // @@protoc_insertion_point(message_implements:IM.Buddy.IMRemoveSessionNotify) + IMRemoveSessionNotifyOrBuilder { + // Use IMRemoveSessionNotify.newBuilder() to construct. + private IMRemoveSessionNotify(com.google.protobuf.GeneratedMessageLite.Builder builder) { + super(builder); + this.unknownFields = builder.getUnknownFields(); + } + private IMRemoveSessionNotify(boolean noInit) { this.unknownFields = com.google.protobuf.ByteString.EMPTY;} + + private static final IMRemoveSessionNotify defaultInstance; + public static IMRemoveSessionNotify getDefaultInstance() { + return defaultInstance; + } + + public IMRemoveSessionNotify getDefaultInstanceForType() { + return defaultInstance; + } + + private final com.google.protobuf.ByteString unknownFields; + private IMRemoveSessionNotify( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + initFields(); + int mutable_bitField0_ = 0; + com.google.protobuf.ByteString.Output unknownFieldsOutput = + com.google.protobuf.ByteString.newOutput(); + com.google.protobuf.CodedOutputStream unknownFieldsCodedOutput = + com.google.protobuf.CodedOutputStream.newInstance( + unknownFieldsOutput); + try { + boolean done = false; + while (!done) { + int tag = input.readTag(); + switch (tag) { + case 0: + done = true; + break; + default: { + if (!parseUnknownField(input, unknownFieldsCodedOutput, + extensionRegistry, tag)) { + done = true; + } + break; + } + case 8: { + bitField0_ |= 0x00000001; + userId_ = input.readUInt32(); + break; + } + case 16: { + int rawValue = input.readEnum(); + com.mogujie.tt.protobuf.IMBaseDefine.SessionType value = com.mogujie.tt.protobuf.IMBaseDefine.SessionType.valueOf(rawValue); + if (value == null) { + unknownFieldsCodedOutput.writeRawVarint32(tag); + unknownFieldsCodedOutput.writeRawVarint32(rawValue); + } else { + bitField0_ |= 0x00000002; + sessionType_ = value; + } + break; + } + case 24: { + bitField0_ |= 0x00000004; + sessionId_ = input.readUInt32(); + break; + } + } + } + } catch (com.google.protobuf.InvalidProtocolBufferException e) { + throw e.setUnfinishedMessage(this); + } catch (java.io.IOException e) { + throw new com.google.protobuf.InvalidProtocolBufferException( + e.getMessage()).setUnfinishedMessage(this); + } finally { + try { + unknownFieldsCodedOutput.flush(); + } catch (java.io.IOException e) { + // Should not happen + } finally { + unknownFields = unknownFieldsOutput.toByteString(); + } + makeExtensionsImmutable(); + } + } + public static com.google.protobuf.Parser PARSER = + new com.google.protobuf.AbstractParser() { + public IMRemoveSessionNotify parsePartialFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return new IMRemoveSessionNotify(input, extensionRegistry); + } + }; + + @java.lang.Override + public com.google.protobuf.Parser getParserForType() { + return PARSER; + } + + private int bitField0_; + public static final int USER_ID_FIELD_NUMBER = 1; + private int userId_; + /** + * required uint32 user_id = 1; + * + *
+     *cmd id:		0x020f
+     * 
+ */ + public boolean hasUserId() { + return ((bitField0_ & 0x00000001) == 0x00000001); + } + /** + * required uint32 user_id = 1; + * + *
+     *cmd id:		0x020f
+     * 
+ */ + public int getUserId() { + return userId_; + } + + public static final int SESSION_TYPE_FIELD_NUMBER = 2; + private com.mogujie.tt.protobuf.IMBaseDefine.SessionType sessionType_; + /** + * required .IM.BaseDefine.SessionType session_type = 2; + */ + public boolean hasSessionType() { + return ((bitField0_ & 0x00000002) == 0x00000002); + } + /** + * required .IM.BaseDefine.SessionType session_type = 2; + */ + public com.mogujie.tt.protobuf.IMBaseDefine.SessionType getSessionType() { + return sessionType_; + } + + public static final int SESSION_ID_FIELD_NUMBER = 3; + private int sessionId_; + /** + * required uint32 session_id = 3; + */ + public boolean hasSessionId() { + return ((bitField0_ & 0x00000004) == 0x00000004); + } + /** + * required uint32 session_id = 3; + */ + public int getSessionId() { + return sessionId_; + } + + private void initFields() { + userId_ = 0; + sessionType_ = com.mogujie.tt.protobuf.IMBaseDefine.SessionType.SESSION_TYPE_SINGLE; + sessionId_ = 0; + } + private byte memoizedIsInitialized = -1; + public final boolean isInitialized() { + byte isInitialized = memoizedIsInitialized; + if (isInitialized == 1) return true; + if (isInitialized == 0) return false; + + if (!hasUserId()) { + memoizedIsInitialized = 0; + return false; + } + if (!hasSessionType()) { + memoizedIsInitialized = 0; + return false; + } + if (!hasSessionId()) { + memoizedIsInitialized = 0; + return false; + } + memoizedIsInitialized = 1; + return true; + } + + public void writeTo(com.google.protobuf.CodedOutputStream output) + throws java.io.IOException { + getSerializedSize(); + if (((bitField0_ & 0x00000001) == 0x00000001)) { + output.writeUInt32(1, userId_); + } + if (((bitField0_ & 0x00000002) == 0x00000002)) { + output.writeEnum(2, sessionType_.getNumber()); + } + if (((bitField0_ & 0x00000004) == 0x00000004)) { + output.writeUInt32(3, sessionId_); + } + output.writeRawBytes(unknownFields); + } + + private int memoizedSerializedSize = -1; + public int getSerializedSize() { + int size = memoizedSerializedSize; + if (size != -1) return size; + + size = 0; + if (((bitField0_ & 0x00000001) == 0x00000001)) { + size += com.google.protobuf.CodedOutputStream + .computeUInt32Size(1, userId_); + } + if (((bitField0_ & 0x00000002) == 0x00000002)) { + size += com.google.protobuf.CodedOutputStream + .computeEnumSize(2, sessionType_.getNumber()); + } + if (((bitField0_ & 0x00000004) == 0x00000004)) { + size += com.google.protobuf.CodedOutputStream + .computeUInt32Size(3, sessionId_); + } + size += unknownFields.size(); + memoizedSerializedSize = size; + return size; + } + + private static final long serialVersionUID = 0L; + @java.lang.Override + protected java.lang.Object writeReplace() + throws java.io.ObjectStreamException { + return super.writeReplace(); + } + + public static com.mogujie.tt.protobuf.IMBuddy.IMRemoveSessionNotify parseFrom( + com.google.protobuf.ByteString data) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data); + } + public static com.mogujie.tt.protobuf.IMBuddy.IMRemoveSessionNotify parseFrom( + com.google.protobuf.ByteString data, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data, extensionRegistry); + } + public static com.mogujie.tt.protobuf.IMBuddy.IMRemoveSessionNotify parseFrom(byte[] data) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data); + } + public static com.mogujie.tt.protobuf.IMBuddy.IMRemoveSessionNotify parseFrom( + byte[] data, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data, extensionRegistry); + } + public static com.mogujie.tt.protobuf.IMBuddy.IMRemoveSessionNotify parseFrom(java.io.InputStream input) + throws java.io.IOException { + return PARSER.parseFrom(input); + } + public static com.mogujie.tt.protobuf.IMBuddy.IMRemoveSessionNotify parseFrom( + java.io.InputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return PARSER.parseFrom(input, extensionRegistry); + } + public static com.mogujie.tt.protobuf.IMBuddy.IMRemoveSessionNotify parseDelimitedFrom(java.io.InputStream input) + throws java.io.IOException { + return PARSER.parseDelimitedFrom(input); + } + public static com.mogujie.tt.protobuf.IMBuddy.IMRemoveSessionNotify parseDelimitedFrom( + java.io.InputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return PARSER.parseDelimitedFrom(input, extensionRegistry); + } + public static com.mogujie.tt.protobuf.IMBuddy.IMRemoveSessionNotify parseFrom( + com.google.protobuf.CodedInputStream input) + throws java.io.IOException { + return PARSER.parseFrom(input); + } + public static com.mogujie.tt.protobuf.IMBuddy.IMRemoveSessionNotify parseFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return PARSER.parseFrom(input, extensionRegistry); + } + + public static Builder newBuilder() { return Builder.create(); } + public Builder newBuilderForType() { return newBuilder(); } + public static Builder newBuilder(com.mogujie.tt.protobuf.IMBuddy.IMRemoveSessionNotify prototype) { + return newBuilder().mergeFrom(prototype); + } + public Builder toBuilder() { return newBuilder(this); } + + /** + * Protobuf type {@code IM.Buddy.IMRemoveSessionNotify} + */ + public static final class Builder extends + com.google.protobuf.GeneratedMessageLite.Builder< + com.mogujie.tt.protobuf.IMBuddy.IMRemoveSessionNotify, Builder> + implements + // @@protoc_insertion_point(builder_implements:IM.Buddy.IMRemoveSessionNotify) + com.mogujie.tt.protobuf.IMBuddy.IMRemoveSessionNotifyOrBuilder { + // Construct using com.mogujie.tt.protobuf.IMBuddy.IMRemoveSessionNotify.newBuilder() + private Builder() { + maybeForceBuilderInitialization(); + } + + private void maybeForceBuilderInitialization() { + } + private static Builder create() { + return new Builder(); + } + + public Builder clear() { + super.clear(); + userId_ = 0; + bitField0_ = (bitField0_ & ~0x00000001); + sessionType_ = com.mogujie.tt.protobuf.IMBaseDefine.SessionType.SESSION_TYPE_SINGLE; + bitField0_ = (bitField0_ & ~0x00000002); + sessionId_ = 0; + bitField0_ = (bitField0_ & ~0x00000004); + return this; + } + + public Builder clone() { + return create().mergeFrom(buildPartial()); + } + + public com.mogujie.tt.protobuf.IMBuddy.IMRemoveSessionNotify getDefaultInstanceForType() { + return com.mogujie.tt.protobuf.IMBuddy.IMRemoveSessionNotify.getDefaultInstance(); + } + + public com.mogujie.tt.protobuf.IMBuddy.IMRemoveSessionNotify build() { + com.mogujie.tt.protobuf.IMBuddy.IMRemoveSessionNotify result = buildPartial(); + if (!result.isInitialized()) { + throw newUninitializedMessageException(result); + } + return result; + } + + public com.mogujie.tt.protobuf.IMBuddy.IMRemoveSessionNotify buildPartial() { + com.mogujie.tt.protobuf.IMBuddy.IMRemoveSessionNotify result = new com.mogujie.tt.protobuf.IMBuddy.IMRemoveSessionNotify(this); + int from_bitField0_ = bitField0_; + int to_bitField0_ = 0; + if (((from_bitField0_ & 0x00000001) == 0x00000001)) { + to_bitField0_ |= 0x00000001; + } + result.userId_ = userId_; + if (((from_bitField0_ & 0x00000002) == 0x00000002)) { + to_bitField0_ |= 0x00000002; + } + result.sessionType_ = sessionType_; + if (((from_bitField0_ & 0x00000004) == 0x00000004)) { + to_bitField0_ |= 0x00000004; + } + result.sessionId_ = sessionId_; + result.bitField0_ = to_bitField0_; + return result; + } + + public Builder mergeFrom(com.mogujie.tt.protobuf.IMBuddy.IMRemoveSessionNotify other) { + if (other == com.mogujie.tt.protobuf.IMBuddy.IMRemoveSessionNotify.getDefaultInstance()) return this; + if (other.hasUserId()) { + setUserId(other.getUserId()); + } + if (other.hasSessionType()) { + setSessionType(other.getSessionType()); + } + if (other.hasSessionId()) { + setSessionId(other.getSessionId()); + } + setUnknownFields( + getUnknownFields().concat(other.unknownFields)); + return this; + } + + public final boolean isInitialized() { + if (!hasUserId()) { + + return false; + } + if (!hasSessionType()) { + + return false; + } + if (!hasSessionId()) { + + return false; + } + return true; + } + + public Builder mergeFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + com.mogujie.tt.protobuf.IMBuddy.IMRemoveSessionNotify parsedMessage = null; + try { + parsedMessage = PARSER.parsePartialFrom(input, extensionRegistry); + } catch (com.google.protobuf.InvalidProtocolBufferException e) { + parsedMessage = (com.mogujie.tt.protobuf.IMBuddy.IMRemoveSessionNotify) e.getUnfinishedMessage(); + throw e; + } finally { + if (parsedMessage != null) { + mergeFrom(parsedMessage); + } + } + return this; + } + private int bitField0_; + + private int userId_ ; + /** + * required uint32 user_id = 1; + * + *
+       *cmd id:		0x020f
+       * 
+ */ + public boolean hasUserId() { + return ((bitField0_ & 0x00000001) == 0x00000001); + } + /** + * required uint32 user_id = 1; + * + *
+       *cmd id:		0x020f
+       * 
+ */ + public int getUserId() { + return userId_; + } + /** + * required uint32 user_id = 1; + * + *
+       *cmd id:		0x020f
+       * 
+ */ + public Builder setUserId(int value) { + bitField0_ |= 0x00000001; + userId_ = value; + + return this; + } + /** + * required uint32 user_id = 1; + * + *
+       *cmd id:		0x020f
+       * 
+ */ + public Builder clearUserId() { + bitField0_ = (bitField0_ & ~0x00000001); + userId_ = 0; + + return this; + } + + private com.mogujie.tt.protobuf.IMBaseDefine.SessionType sessionType_ = com.mogujie.tt.protobuf.IMBaseDefine.SessionType.SESSION_TYPE_SINGLE; + /** + * required .IM.BaseDefine.SessionType session_type = 2; + */ + public boolean hasSessionType() { + return ((bitField0_ & 0x00000002) == 0x00000002); + } + /** + * required .IM.BaseDefine.SessionType session_type = 2; + */ + public com.mogujie.tt.protobuf.IMBaseDefine.SessionType getSessionType() { + return sessionType_; + } + /** + * required .IM.BaseDefine.SessionType session_type = 2; + */ + public Builder setSessionType(com.mogujie.tt.protobuf.IMBaseDefine.SessionType value) { + if (value == null) { + throw new NullPointerException(); + } + bitField0_ |= 0x00000002; + sessionType_ = value; + + return this; + } + /** + * required .IM.BaseDefine.SessionType session_type = 2; + */ + public Builder clearSessionType() { + bitField0_ = (bitField0_ & ~0x00000002); + sessionType_ = com.mogujie.tt.protobuf.IMBaseDefine.SessionType.SESSION_TYPE_SINGLE; + + return this; + } + + private int sessionId_ ; + /** + * required uint32 session_id = 3; + */ + public boolean hasSessionId() { + return ((bitField0_ & 0x00000004) == 0x00000004); + } + /** + * required uint32 session_id = 3; + */ + public int getSessionId() { + return sessionId_; + } + /** + * required uint32 session_id = 3; + */ + public Builder setSessionId(int value) { + bitField0_ |= 0x00000004; + sessionId_ = value; + + return this; + } + /** + * required uint32 session_id = 3; + */ + public Builder clearSessionId() { + bitField0_ = (bitField0_ & ~0x00000004); + sessionId_ = 0; + + return this; + } + + // @@protoc_insertion_point(builder_scope:IM.Buddy.IMRemoveSessionNotify) + } + + static { + defaultInstance = new IMRemoveSessionNotify(true); + defaultInstance.initFields(); + } + + // @@protoc_insertion_point(class_scope:IM.Buddy.IMRemoveSessionNotify) + } + + public interface IMDepartmentReqOrBuilder extends + // @@protoc_insertion_point(interface_extends:IM.Buddy.IMDepartmentReq) + com.google.protobuf.MessageLiteOrBuilder { + + /** + * required uint32 user_id = 1; + * + *
+     *cmd id:		0x0210
+     * 
+ */ + boolean hasUserId(); + /** + * required uint32 user_id = 1; + * + *
+     *cmd id:		0x0210
+     * 
+ */ + int getUserId(); + + /** + * required uint32 latest_update_time = 2; + */ + boolean hasLatestUpdateTime(); + /** + * required uint32 latest_update_time = 2; + */ + int getLatestUpdateTime(); + + /** + * optional bytes attach_data = 20; + */ + boolean hasAttachData(); + /** + * optional bytes attach_data = 20; + */ + com.google.protobuf.ByteString getAttachData(); + } + /** + * Protobuf type {@code IM.Buddy.IMDepartmentReq} + */ + public static final class IMDepartmentReq extends + com.google.protobuf.GeneratedMessageLite implements + // @@protoc_insertion_point(message_implements:IM.Buddy.IMDepartmentReq) + IMDepartmentReqOrBuilder { + // Use IMDepartmentReq.newBuilder() to construct. + private IMDepartmentReq(com.google.protobuf.GeneratedMessageLite.Builder builder) { + super(builder); + this.unknownFields = builder.getUnknownFields(); + } + private IMDepartmentReq(boolean noInit) { this.unknownFields = com.google.protobuf.ByteString.EMPTY;} + + private static final IMDepartmentReq defaultInstance; + public static IMDepartmentReq getDefaultInstance() { + return defaultInstance; + } + + public IMDepartmentReq getDefaultInstanceForType() { + return defaultInstance; + } + + private final com.google.protobuf.ByteString unknownFields; + private IMDepartmentReq( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + initFields(); + int mutable_bitField0_ = 0; + com.google.protobuf.ByteString.Output unknownFieldsOutput = + com.google.protobuf.ByteString.newOutput(); + com.google.protobuf.CodedOutputStream unknownFieldsCodedOutput = + com.google.protobuf.CodedOutputStream.newInstance( + unknownFieldsOutput); + try { + boolean done = false; + while (!done) { + int tag = input.readTag(); + switch (tag) { + case 0: + done = true; + break; + default: { + if (!parseUnknownField(input, unknownFieldsCodedOutput, + extensionRegistry, tag)) { + done = true; + } + break; + } + case 8: { + bitField0_ |= 0x00000001; + userId_ = input.readUInt32(); + break; + } + case 16: { + bitField0_ |= 0x00000002; + latestUpdateTime_ = input.readUInt32(); + break; + } + case 162: { + bitField0_ |= 0x00000004; + attachData_ = input.readBytes(); + break; + } + } + } + } catch (com.google.protobuf.InvalidProtocolBufferException e) { + throw e.setUnfinishedMessage(this); + } catch (java.io.IOException e) { + throw new com.google.protobuf.InvalidProtocolBufferException( + e.getMessage()).setUnfinishedMessage(this); + } finally { + try { + unknownFieldsCodedOutput.flush(); + } catch (java.io.IOException e) { + // Should not happen + } finally { + unknownFields = unknownFieldsOutput.toByteString(); + } + makeExtensionsImmutable(); + } + } + public static com.google.protobuf.Parser PARSER = + new com.google.protobuf.AbstractParser() { + public IMDepartmentReq parsePartialFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return new IMDepartmentReq(input, extensionRegistry); + } + }; + + @java.lang.Override + public com.google.protobuf.Parser getParserForType() { + return PARSER; + } + + private int bitField0_; + public static final int USER_ID_FIELD_NUMBER = 1; + private int userId_; + /** + * required uint32 user_id = 1; + * + *
+     *cmd id:		0x0210
+     * 
+ */ + public boolean hasUserId() { + return ((bitField0_ & 0x00000001) == 0x00000001); + } + /** + * required uint32 user_id = 1; + * + *
+     *cmd id:		0x0210
+     * 
+ */ + public int getUserId() { + return userId_; + } + + public static final int LATEST_UPDATE_TIME_FIELD_NUMBER = 2; + private int latestUpdateTime_; + /** + * required uint32 latest_update_time = 2; + */ + public boolean hasLatestUpdateTime() { + return ((bitField0_ & 0x00000002) == 0x00000002); + } + /** + * required uint32 latest_update_time = 2; + */ + public int getLatestUpdateTime() { + return latestUpdateTime_; + } + + public static final int ATTACH_DATA_FIELD_NUMBER = 20; + private com.google.protobuf.ByteString attachData_; + /** + * optional bytes attach_data = 20; + */ + public boolean hasAttachData() { + return ((bitField0_ & 0x00000004) == 0x00000004); + } + /** + * optional bytes attach_data = 20; + */ + public com.google.protobuf.ByteString getAttachData() { + return attachData_; + } + + private void initFields() { + userId_ = 0; + latestUpdateTime_ = 0; + attachData_ = com.google.protobuf.ByteString.EMPTY; + } + private byte memoizedIsInitialized = -1; + public final boolean isInitialized() { + byte isInitialized = memoizedIsInitialized; + if (isInitialized == 1) return true; + if (isInitialized == 0) return false; + + if (!hasUserId()) { + memoizedIsInitialized = 0; + return false; + } + if (!hasLatestUpdateTime()) { + memoizedIsInitialized = 0; + return false; + } + memoizedIsInitialized = 1; + return true; + } + + public void writeTo(com.google.protobuf.CodedOutputStream output) + throws java.io.IOException { + getSerializedSize(); + if (((bitField0_ & 0x00000001) == 0x00000001)) { + output.writeUInt32(1, userId_); + } + if (((bitField0_ & 0x00000002) == 0x00000002)) { + output.writeUInt32(2, latestUpdateTime_); + } + if (((bitField0_ & 0x00000004) == 0x00000004)) { + output.writeBytes(20, attachData_); + } + output.writeRawBytes(unknownFields); + } + + private int memoizedSerializedSize = -1; + public int getSerializedSize() { + int size = memoizedSerializedSize; + if (size != -1) return size; + + size = 0; + if (((bitField0_ & 0x00000001) == 0x00000001)) { + size += com.google.protobuf.CodedOutputStream + .computeUInt32Size(1, userId_); + } + if (((bitField0_ & 0x00000002) == 0x00000002)) { + size += com.google.protobuf.CodedOutputStream + .computeUInt32Size(2, latestUpdateTime_); + } + if (((bitField0_ & 0x00000004) == 0x00000004)) { + size += com.google.protobuf.CodedOutputStream + .computeBytesSize(20, attachData_); + } + size += unknownFields.size(); + memoizedSerializedSize = size; + return size; + } + + private static final long serialVersionUID = 0L; + @java.lang.Override + protected java.lang.Object writeReplace() + throws java.io.ObjectStreamException { + return super.writeReplace(); + } + + public static com.mogujie.tt.protobuf.IMBuddy.IMDepartmentReq parseFrom( + com.google.protobuf.ByteString data) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data); + } + public static com.mogujie.tt.protobuf.IMBuddy.IMDepartmentReq parseFrom( + com.google.protobuf.ByteString data, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data, extensionRegistry); + } + public static com.mogujie.tt.protobuf.IMBuddy.IMDepartmentReq parseFrom(byte[] data) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data); + } + public static com.mogujie.tt.protobuf.IMBuddy.IMDepartmentReq parseFrom( + byte[] data, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data, extensionRegistry); + } + public static com.mogujie.tt.protobuf.IMBuddy.IMDepartmentReq parseFrom(java.io.InputStream input) + throws java.io.IOException { + return PARSER.parseFrom(input); + } + public static com.mogujie.tt.protobuf.IMBuddy.IMDepartmentReq parseFrom( + java.io.InputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return PARSER.parseFrom(input, extensionRegistry); + } + public static com.mogujie.tt.protobuf.IMBuddy.IMDepartmentReq parseDelimitedFrom(java.io.InputStream input) + throws java.io.IOException { + return PARSER.parseDelimitedFrom(input); + } + public static com.mogujie.tt.protobuf.IMBuddy.IMDepartmentReq parseDelimitedFrom( + java.io.InputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return PARSER.parseDelimitedFrom(input, extensionRegistry); + } + public static com.mogujie.tt.protobuf.IMBuddy.IMDepartmentReq parseFrom( + com.google.protobuf.CodedInputStream input) + throws java.io.IOException { + return PARSER.parseFrom(input); + } + public static com.mogujie.tt.protobuf.IMBuddy.IMDepartmentReq parseFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return PARSER.parseFrom(input, extensionRegistry); + } + + public static Builder newBuilder() { return Builder.create(); } + public Builder newBuilderForType() { return newBuilder(); } + public static Builder newBuilder(com.mogujie.tt.protobuf.IMBuddy.IMDepartmentReq prototype) { + return newBuilder().mergeFrom(prototype); + } + public Builder toBuilder() { return newBuilder(this); } + + /** + * Protobuf type {@code IM.Buddy.IMDepartmentReq} + */ + public static final class Builder extends + com.google.protobuf.GeneratedMessageLite.Builder< + com.mogujie.tt.protobuf.IMBuddy.IMDepartmentReq, Builder> + implements + // @@protoc_insertion_point(builder_implements:IM.Buddy.IMDepartmentReq) + com.mogujie.tt.protobuf.IMBuddy.IMDepartmentReqOrBuilder { + // Construct using com.mogujie.tt.protobuf.IMBuddy.IMDepartmentReq.newBuilder() + private Builder() { + maybeForceBuilderInitialization(); + } + + private void maybeForceBuilderInitialization() { + } + private static Builder create() { + return new Builder(); + } + + public Builder clear() { + super.clear(); + userId_ = 0; + bitField0_ = (bitField0_ & ~0x00000001); + latestUpdateTime_ = 0; + bitField0_ = (bitField0_ & ~0x00000002); + attachData_ = com.google.protobuf.ByteString.EMPTY; + bitField0_ = (bitField0_ & ~0x00000004); + return this; + } + + public Builder clone() { + return create().mergeFrom(buildPartial()); + } + + public com.mogujie.tt.protobuf.IMBuddy.IMDepartmentReq getDefaultInstanceForType() { + return com.mogujie.tt.protobuf.IMBuddy.IMDepartmentReq.getDefaultInstance(); + } + + public com.mogujie.tt.protobuf.IMBuddy.IMDepartmentReq build() { + com.mogujie.tt.protobuf.IMBuddy.IMDepartmentReq result = buildPartial(); + if (!result.isInitialized()) { + throw newUninitializedMessageException(result); + } + return result; + } + + public com.mogujie.tt.protobuf.IMBuddy.IMDepartmentReq buildPartial() { + com.mogujie.tt.protobuf.IMBuddy.IMDepartmentReq result = new com.mogujie.tt.protobuf.IMBuddy.IMDepartmentReq(this); + int from_bitField0_ = bitField0_; + int to_bitField0_ = 0; + if (((from_bitField0_ & 0x00000001) == 0x00000001)) { + to_bitField0_ |= 0x00000001; + } + result.userId_ = userId_; + if (((from_bitField0_ & 0x00000002) == 0x00000002)) { + to_bitField0_ |= 0x00000002; + } + result.latestUpdateTime_ = latestUpdateTime_; + if (((from_bitField0_ & 0x00000004) == 0x00000004)) { + to_bitField0_ |= 0x00000004; + } + result.attachData_ = attachData_; + result.bitField0_ = to_bitField0_; + return result; + } + + public Builder mergeFrom(com.mogujie.tt.protobuf.IMBuddy.IMDepartmentReq other) { + if (other == com.mogujie.tt.protobuf.IMBuddy.IMDepartmentReq.getDefaultInstance()) return this; + if (other.hasUserId()) { + setUserId(other.getUserId()); + } + if (other.hasLatestUpdateTime()) { + setLatestUpdateTime(other.getLatestUpdateTime()); + } + if (other.hasAttachData()) { + setAttachData(other.getAttachData()); + } + setUnknownFields( + getUnknownFields().concat(other.unknownFields)); + return this; + } + + public final boolean isInitialized() { + if (!hasUserId()) { + + return false; + } + if (!hasLatestUpdateTime()) { + + return false; + } + return true; + } + + public Builder mergeFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + com.mogujie.tt.protobuf.IMBuddy.IMDepartmentReq parsedMessage = null; + try { + parsedMessage = PARSER.parsePartialFrom(input, extensionRegistry); + } catch (com.google.protobuf.InvalidProtocolBufferException e) { + parsedMessage = (com.mogujie.tt.protobuf.IMBuddy.IMDepartmentReq) e.getUnfinishedMessage(); + throw e; + } finally { + if (parsedMessage != null) { + mergeFrom(parsedMessage); + } + } + return this; + } + private int bitField0_; + + private int userId_ ; + /** + * required uint32 user_id = 1; + * + *
+       *cmd id:		0x0210
+       * 
+ */ + public boolean hasUserId() { + return ((bitField0_ & 0x00000001) == 0x00000001); + } + /** + * required uint32 user_id = 1; + * + *
+       *cmd id:		0x0210
+       * 
+ */ + public int getUserId() { + return userId_; + } + /** + * required uint32 user_id = 1; + * + *
+       *cmd id:		0x0210
+       * 
+ */ + public Builder setUserId(int value) { + bitField0_ |= 0x00000001; + userId_ = value; + + return this; + } + /** + * required uint32 user_id = 1; + * + *
+       *cmd id:		0x0210
+       * 
+ */ + public Builder clearUserId() { + bitField0_ = (bitField0_ & ~0x00000001); + userId_ = 0; + + return this; + } + + private int latestUpdateTime_ ; + /** + * required uint32 latest_update_time = 2; + */ + public boolean hasLatestUpdateTime() { + return ((bitField0_ & 0x00000002) == 0x00000002); + } + /** + * required uint32 latest_update_time = 2; + */ + public int getLatestUpdateTime() { + return latestUpdateTime_; + } + /** + * required uint32 latest_update_time = 2; + */ + public Builder setLatestUpdateTime(int value) { + bitField0_ |= 0x00000002; + latestUpdateTime_ = value; + + return this; + } + /** + * required uint32 latest_update_time = 2; + */ + public Builder clearLatestUpdateTime() { + bitField0_ = (bitField0_ & ~0x00000002); + latestUpdateTime_ = 0; + + return this; + } + + private com.google.protobuf.ByteString attachData_ = com.google.protobuf.ByteString.EMPTY; + /** + * optional bytes attach_data = 20; + */ + public boolean hasAttachData() { + return ((bitField0_ & 0x00000004) == 0x00000004); + } + /** + * optional bytes attach_data = 20; + */ + public com.google.protobuf.ByteString getAttachData() { + return attachData_; + } + /** + * optional bytes attach_data = 20; + */ + public Builder setAttachData(com.google.protobuf.ByteString value) { + if (value == null) { + throw new NullPointerException(); + } + bitField0_ |= 0x00000004; + attachData_ = value; + + return this; + } + /** + * optional bytes attach_data = 20; + */ + public Builder clearAttachData() { + bitField0_ = (bitField0_ & ~0x00000004); + attachData_ = getDefaultInstance().getAttachData(); + + return this; + } + + // @@protoc_insertion_point(builder_scope:IM.Buddy.IMDepartmentReq) + } + + static { + defaultInstance = new IMDepartmentReq(true); + defaultInstance.initFields(); + } + + // @@protoc_insertion_point(class_scope:IM.Buddy.IMDepartmentReq) + } + + public interface IMDepartmentRspOrBuilder extends + // @@protoc_insertion_point(interface_extends:IM.Buddy.IMDepartmentRsp) + com.google.protobuf.MessageLiteOrBuilder { + + /** + * required uint32 user_id = 1; + * + *
+     *cmd id:		0x0211
+     * 
+ */ + boolean hasUserId(); + /** + * required uint32 user_id = 1; + * + *
+     *cmd id:		0x0211
+     * 
+ */ + int getUserId(); + + /** + * required uint32 latest_update_time = 2; + */ + boolean hasLatestUpdateTime(); + /** + * required uint32 latest_update_time = 2; + */ + int getLatestUpdateTime(); + + /** + * repeated .IM.BaseDefine.DepartInfo dept_list = 3; + */ + java.util.List + getDeptListList(); + /** + * repeated .IM.BaseDefine.DepartInfo dept_list = 3; + */ + com.mogujie.tt.protobuf.IMBaseDefine.DepartInfo getDeptList(int index); + /** + * repeated .IM.BaseDefine.DepartInfo dept_list = 3; + */ + int getDeptListCount(); + + /** + * optional bytes attach_data = 20; + */ + boolean hasAttachData(); + /** + * optional bytes attach_data = 20; + */ + com.google.protobuf.ByteString getAttachData(); + } + /** + * Protobuf type {@code IM.Buddy.IMDepartmentRsp} + */ + public static final class IMDepartmentRsp extends + com.google.protobuf.GeneratedMessageLite implements + // @@protoc_insertion_point(message_implements:IM.Buddy.IMDepartmentRsp) + IMDepartmentRspOrBuilder { + // Use IMDepartmentRsp.newBuilder() to construct. + private IMDepartmentRsp(com.google.protobuf.GeneratedMessageLite.Builder builder) { + super(builder); + this.unknownFields = builder.getUnknownFields(); + } + private IMDepartmentRsp(boolean noInit) { this.unknownFields = com.google.protobuf.ByteString.EMPTY;} + + private static final IMDepartmentRsp defaultInstance; + public static IMDepartmentRsp getDefaultInstance() { + return defaultInstance; + } + + public IMDepartmentRsp getDefaultInstanceForType() { + return defaultInstance; + } + + private final com.google.protobuf.ByteString unknownFields; + private IMDepartmentRsp( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + initFields(); + int mutable_bitField0_ = 0; + com.google.protobuf.ByteString.Output unknownFieldsOutput = + com.google.protobuf.ByteString.newOutput(); + com.google.protobuf.CodedOutputStream unknownFieldsCodedOutput = + com.google.protobuf.CodedOutputStream.newInstance( + unknownFieldsOutput); + try { + boolean done = false; + while (!done) { + int tag = input.readTag(); + switch (tag) { + case 0: + done = true; + break; + default: { + if (!parseUnknownField(input, unknownFieldsCodedOutput, + extensionRegistry, tag)) { + done = true; + } + break; + } + case 8: { + bitField0_ |= 0x00000001; + userId_ = input.readUInt32(); + break; + } + case 16: { + bitField0_ |= 0x00000002; + latestUpdateTime_ = input.readUInt32(); + break; + } + case 26: { + if (!((mutable_bitField0_ & 0x00000004) == 0x00000004)) { + deptList_ = new java.util.ArrayList(); + mutable_bitField0_ |= 0x00000004; + } + deptList_.add(input.readMessage(com.mogujie.tt.protobuf.IMBaseDefine.DepartInfo.PARSER, extensionRegistry)); + break; + } + case 162: { + bitField0_ |= 0x00000004; + attachData_ = input.readBytes(); + break; + } + } + } + } catch (com.google.protobuf.InvalidProtocolBufferException e) { + throw e.setUnfinishedMessage(this); + } catch (java.io.IOException e) { + throw new com.google.protobuf.InvalidProtocolBufferException( + e.getMessage()).setUnfinishedMessage(this); + } finally { + if (((mutable_bitField0_ & 0x00000004) == 0x00000004)) { + deptList_ = java.util.Collections.unmodifiableList(deptList_); + } + try { + unknownFieldsCodedOutput.flush(); + } catch (java.io.IOException e) { + // Should not happen + } finally { + unknownFields = unknownFieldsOutput.toByteString(); + } + makeExtensionsImmutable(); + } + } + public static com.google.protobuf.Parser PARSER = + new com.google.protobuf.AbstractParser() { + public IMDepartmentRsp parsePartialFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return new IMDepartmentRsp(input, extensionRegistry); + } + }; + + @java.lang.Override + public com.google.protobuf.Parser getParserForType() { + return PARSER; + } + + private int bitField0_; + public static final int USER_ID_FIELD_NUMBER = 1; + private int userId_; + /** + * required uint32 user_id = 1; + * + *
+     *cmd id:		0x0211
+     * 
+ */ + public boolean hasUserId() { + return ((bitField0_ & 0x00000001) == 0x00000001); + } + /** + * required uint32 user_id = 1; + * + *
+     *cmd id:		0x0211
+     * 
+ */ + public int getUserId() { + return userId_; + } + + public static final int LATEST_UPDATE_TIME_FIELD_NUMBER = 2; + private int latestUpdateTime_; + /** + * required uint32 latest_update_time = 2; + */ + public boolean hasLatestUpdateTime() { + return ((bitField0_ & 0x00000002) == 0x00000002); + } + /** + * required uint32 latest_update_time = 2; + */ + public int getLatestUpdateTime() { + return latestUpdateTime_; + } + + public static final int DEPT_LIST_FIELD_NUMBER = 3; + private java.util.List deptList_; + /** + * repeated .IM.BaseDefine.DepartInfo dept_list = 3; + */ + public java.util.List getDeptListList() { + return deptList_; + } + /** + * repeated .IM.BaseDefine.DepartInfo dept_list = 3; + */ + public java.util.List + getDeptListOrBuilderList() { + return deptList_; + } + /** + * repeated .IM.BaseDefine.DepartInfo dept_list = 3; + */ + public int getDeptListCount() { + return deptList_.size(); + } + /** + * repeated .IM.BaseDefine.DepartInfo dept_list = 3; + */ + public com.mogujie.tt.protobuf.IMBaseDefine.DepartInfo getDeptList(int index) { + return deptList_.get(index); + } + /** + * repeated .IM.BaseDefine.DepartInfo dept_list = 3; + */ + public com.mogujie.tt.protobuf.IMBaseDefine.DepartInfoOrBuilder getDeptListOrBuilder( + int index) { + return deptList_.get(index); + } + + public static final int ATTACH_DATA_FIELD_NUMBER = 20; + private com.google.protobuf.ByteString attachData_; + /** + * optional bytes attach_data = 20; + */ + public boolean hasAttachData() { + return ((bitField0_ & 0x00000004) == 0x00000004); + } + /** + * optional bytes attach_data = 20; + */ + public com.google.protobuf.ByteString getAttachData() { + return attachData_; + } + + private void initFields() { + userId_ = 0; + latestUpdateTime_ = 0; + deptList_ = java.util.Collections.emptyList(); + attachData_ = com.google.protobuf.ByteString.EMPTY; + } + private byte memoizedIsInitialized = -1; + public final boolean isInitialized() { + byte isInitialized = memoizedIsInitialized; + if (isInitialized == 1) return true; + if (isInitialized == 0) return false; + + if (!hasUserId()) { + memoizedIsInitialized = 0; + return false; + } + if (!hasLatestUpdateTime()) { + memoizedIsInitialized = 0; + return false; + } + for (int i = 0; i < getDeptListCount(); i++) { + if (!getDeptList(i).isInitialized()) { + memoizedIsInitialized = 0; + return false; + } + } + memoizedIsInitialized = 1; + return true; + } + + public void writeTo(com.google.protobuf.CodedOutputStream output) + throws java.io.IOException { + getSerializedSize(); + if (((bitField0_ & 0x00000001) == 0x00000001)) { + output.writeUInt32(1, userId_); + } + if (((bitField0_ & 0x00000002) == 0x00000002)) { + output.writeUInt32(2, latestUpdateTime_); + } + for (int i = 0; i < deptList_.size(); i++) { + output.writeMessage(3, deptList_.get(i)); + } + if (((bitField0_ & 0x00000004) == 0x00000004)) { + output.writeBytes(20, attachData_); + } + output.writeRawBytes(unknownFields); + } + + private int memoizedSerializedSize = -1; + public int getSerializedSize() { + int size = memoizedSerializedSize; + if (size != -1) return size; + + size = 0; + if (((bitField0_ & 0x00000001) == 0x00000001)) { + size += com.google.protobuf.CodedOutputStream + .computeUInt32Size(1, userId_); + } + if (((bitField0_ & 0x00000002) == 0x00000002)) { + size += com.google.protobuf.CodedOutputStream + .computeUInt32Size(2, latestUpdateTime_); + } + for (int i = 0; i < deptList_.size(); i++) { + size += com.google.protobuf.CodedOutputStream + .computeMessageSize(3, deptList_.get(i)); + } + if (((bitField0_ & 0x00000004) == 0x00000004)) { + size += com.google.protobuf.CodedOutputStream + .computeBytesSize(20, attachData_); + } + size += unknownFields.size(); + memoizedSerializedSize = size; + return size; + } + + private static final long serialVersionUID = 0L; + @java.lang.Override + protected java.lang.Object writeReplace() + throws java.io.ObjectStreamException { + return super.writeReplace(); + } + + public static com.mogujie.tt.protobuf.IMBuddy.IMDepartmentRsp parseFrom( + com.google.protobuf.ByteString data) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data); + } + public static com.mogujie.tt.protobuf.IMBuddy.IMDepartmentRsp parseFrom( + com.google.protobuf.ByteString data, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data, extensionRegistry); + } + public static com.mogujie.tt.protobuf.IMBuddy.IMDepartmentRsp parseFrom(byte[] data) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data); + } + public static com.mogujie.tt.protobuf.IMBuddy.IMDepartmentRsp parseFrom( + byte[] data, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data, extensionRegistry); + } + public static com.mogujie.tt.protobuf.IMBuddy.IMDepartmentRsp parseFrom(java.io.InputStream input) + throws java.io.IOException { + return PARSER.parseFrom(input); + } + public static com.mogujie.tt.protobuf.IMBuddy.IMDepartmentRsp parseFrom( + java.io.InputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return PARSER.parseFrom(input, extensionRegistry); + } + public static com.mogujie.tt.protobuf.IMBuddy.IMDepartmentRsp parseDelimitedFrom(java.io.InputStream input) + throws java.io.IOException { + return PARSER.parseDelimitedFrom(input); + } + public static com.mogujie.tt.protobuf.IMBuddy.IMDepartmentRsp parseDelimitedFrom( + java.io.InputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return PARSER.parseDelimitedFrom(input, extensionRegistry); + } + public static com.mogujie.tt.protobuf.IMBuddy.IMDepartmentRsp parseFrom( + com.google.protobuf.CodedInputStream input) + throws java.io.IOException { + return PARSER.parseFrom(input); + } + public static com.mogujie.tt.protobuf.IMBuddy.IMDepartmentRsp parseFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return PARSER.parseFrom(input, extensionRegistry); + } + + public static Builder newBuilder() { return Builder.create(); } + public Builder newBuilderForType() { return newBuilder(); } + public static Builder newBuilder(com.mogujie.tt.protobuf.IMBuddy.IMDepartmentRsp prototype) { + return newBuilder().mergeFrom(prototype); + } + public Builder toBuilder() { return newBuilder(this); } + + /** + * Protobuf type {@code IM.Buddy.IMDepartmentRsp} + */ + public static final class Builder extends + com.google.protobuf.GeneratedMessageLite.Builder< + com.mogujie.tt.protobuf.IMBuddy.IMDepartmentRsp, Builder> + implements + // @@protoc_insertion_point(builder_implements:IM.Buddy.IMDepartmentRsp) + com.mogujie.tt.protobuf.IMBuddy.IMDepartmentRspOrBuilder { + // Construct using com.mogujie.tt.protobuf.IMBuddy.IMDepartmentRsp.newBuilder() + private Builder() { + maybeForceBuilderInitialization(); + } + + private void maybeForceBuilderInitialization() { + } + private static Builder create() { + return new Builder(); + } + + public Builder clear() { + super.clear(); + userId_ = 0; + bitField0_ = (bitField0_ & ~0x00000001); + latestUpdateTime_ = 0; + bitField0_ = (bitField0_ & ~0x00000002); + deptList_ = java.util.Collections.emptyList(); + bitField0_ = (bitField0_ & ~0x00000004); + attachData_ = com.google.protobuf.ByteString.EMPTY; + bitField0_ = (bitField0_ & ~0x00000008); + return this; + } + + public Builder clone() { + return create().mergeFrom(buildPartial()); + } + + public com.mogujie.tt.protobuf.IMBuddy.IMDepartmentRsp getDefaultInstanceForType() { + return com.mogujie.tt.protobuf.IMBuddy.IMDepartmentRsp.getDefaultInstance(); + } + + public com.mogujie.tt.protobuf.IMBuddy.IMDepartmentRsp build() { + com.mogujie.tt.protobuf.IMBuddy.IMDepartmentRsp result = buildPartial(); + if (!result.isInitialized()) { + throw newUninitializedMessageException(result); + } + return result; + } + + public com.mogujie.tt.protobuf.IMBuddy.IMDepartmentRsp buildPartial() { + com.mogujie.tt.protobuf.IMBuddy.IMDepartmentRsp result = new com.mogujie.tt.protobuf.IMBuddy.IMDepartmentRsp(this); + int from_bitField0_ = bitField0_; + int to_bitField0_ = 0; + if (((from_bitField0_ & 0x00000001) == 0x00000001)) { + to_bitField0_ |= 0x00000001; + } + result.userId_ = userId_; + if (((from_bitField0_ & 0x00000002) == 0x00000002)) { + to_bitField0_ |= 0x00000002; + } + result.latestUpdateTime_ = latestUpdateTime_; + if (((bitField0_ & 0x00000004) == 0x00000004)) { + deptList_ = java.util.Collections.unmodifiableList(deptList_); + bitField0_ = (bitField0_ & ~0x00000004); + } + result.deptList_ = deptList_; + if (((from_bitField0_ & 0x00000008) == 0x00000008)) { + to_bitField0_ |= 0x00000004; + } + result.attachData_ = attachData_; + result.bitField0_ = to_bitField0_; + return result; + } + + public Builder mergeFrom(com.mogujie.tt.protobuf.IMBuddy.IMDepartmentRsp other) { + if (other == com.mogujie.tt.protobuf.IMBuddy.IMDepartmentRsp.getDefaultInstance()) return this; + if (other.hasUserId()) { + setUserId(other.getUserId()); + } + if (other.hasLatestUpdateTime()) { + setLatestUpdateTime(other.getLatestUpdateTime()); + } + if (!other.deptList_.isEmpty()) { + if (deptList_.isEmpty()) { + deptList_ = other.deptList_; + bitField0_ = (bitField0_ & ~0x00000004); + } else { + ensureDeptListIsMutable(); + deptList_.addAll(other.deptList_); + } + + } + if (other.hasAttachData()) { + setAttachData(other.getAttachData()); + } + setUnknownFields( + getUnknownFields().concat(other.unknownFields)); + return this; + } + + public final boolean isInitialized() { + if (!hasUserId()) { + + return false; + } + if (!hasLatestUpdateTime()) { + + return false; + } + for (int i = 0; i < getDeptListCount(); i++) { + if (!getDeptList(i).isInitialized()) { + + return false; + } + } + return true; + } + + public Builder mergeFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + com.mogujie.tt.protobuf.IMBuddy.IMDepartmentRsp parsedMessage = null; + try { + parsedMessage = PARSER.parsePartialFrom(input, extensionRegistry); + } catch (com.google.protobuf.InvalidProtocolBufferException e) { + parsedMessage = (com.mogujie.tt.protobuf.IMBuddy.IMDepartmentRsp) e.getUnfinishedMessage(); + throw e; + } finally { + if (parsedMessage != null) { + mergeFrom(parsedMessage); + } + } + return this; + } + private int bitField0_; + + private int userId_ ; + /** + * required uint32 user_id = 1; + * + *
+       *cmd id:		0x0211
+       * 
+ */ + public boolean hasUserId() { + return ((bitField0_ & 0x00000001) == 0x00000001); + } + /** + * required uint32 user_id = 1; + * + *
+       *cmd id:		0x0211
+       * 
+ */ + public int getUserId() { + return userId_; + } + /** + * required uint32 user_id = 1; + * + *
+       *cmd id:		0x0211
+       * 
+ */ + public Builder setUserId(int value) { + bitField0_ |= 0x00000001; + userId_ = value; + + return this; + } + /** + * required uint32 user_id = 1; + * + *
+       *cmd id:		0x0211
+       * 
+ */ + public Builder clearUserId() { + bitField0_ = (bitField0_ & ~0x00000001); + userId_ = 0; + + return this; + } + + private int latestUpdateTime_ ; + /** + * required uint32 latest_update_time = 2; + */ + public boolean hasLatestUpdateTime() { + return ((bitField0_ & 0x00000002) == 0x00000002); + } + /** + * required uint32 latest_update_time = 2; + */ + public int getLatestUpdateTime() { + return latestUpdateTime_; + } + /** + * required uint32 latest_update_time = 2; + */ + public Builder setLatestUpdateTime(int value) { + bitField0_ |= 0x00000002; + latestUpdateTime_ = value; + + return this; + } + /** + * required uint32 latest_update_time = 2; + */ + public Builder clearLatestUpdateTime() { + bitField0_ = (bitField0_ & ~0x00000002); + latestUpdateTime_ = 0; + + return this; + } + + private java.util.List deptList_ = + java.util.Collections.emptyList(); + private void ensureDeptListIsMutable() { + if (!((bitField0_ & 0x00000004) == 0x00000004)) { + deptList_ = new java.util.ArrayList(deptList_); + bitField0_ |= 0x00000004; + } + } + + /** + * repeated .IM.BaseDefine.DepartInfo dept_list = 3; + */ + public java.util.List getDeptListList() { + return java.util.Collections.unmodifiableList(deptList_); + } + /** + * repeated .IM.BaseDefine.DepartInfo dept_list = 3; + */ + public int getDeptListCount() { + return deptList_.size(); + } + /** + * repeated .IM.BaseDefine.DepartInfo dept_list = 3; + */ + public com.mogujie.tt.protobuf.IMBaseDefine.DepartInfo getDeptList(int index) { + return deptList_.get(index); + } + /** + * repeated .IM.BaseDefine.DepartInfo dept_list = 3; + */ + public Builder setDeptList( + int index, com.mogujie.tt.protobuf.IMBaseDefine.DepartInfo value) { + if (value == null) { + throw new NullPointerException(); + } + ensureDeptListIsMutable(); + deptList_.set(index, value); + + return this; + } + /** + * repeated .IM.BaseDefine.DepartInfo dept_list = 3; + */ + public Builder setDeptList( + int index, com.mogujie.tt.protobuf.IMBaseDefine.DepartInfo.Builder builderForValue) { + ensureDeptListIsMutable(); + deptList_.set(index, builderForValue.build()); + + return this; + } + /** + * repeated .IM.BaseDefine.DepartInfo dept_list = 3; + */ + public Builder addDeptList(com.mogujie.tt.protobuf.IMBaseDefine.DepartInfo value) { + if (value == null) { + throw new NullPointerException(); + } + ensureDeptListIsMutable(); + deptList_.add(value); + + return this; + } + /** + * repeated .IM.BaseDefine.DepartInfo dept_list = 3; + */ + public Builder addDeptList( + int index, com.mogujie.tt.protobuf.IMBaseDefine.DepartInfo value) { + if (value == null) { + throw new NullPointerException(); + } + ensureDeptListIsMutable(); + deptList_.add(index, value); + + return this; + } + /** + * repeated .IM.BaseDefine.DepartInfo dept_list = 3; + */ + public Builder addDeptList( + com.mogujie.tt.protobuf.IMBaseDefine.DepartInfo.Builder builderForValue) { + ensureDeptListIsMutable(); + deptList_.add(builderForValue.build()); + + return this; + } + /** + * repeated .IM.BaseDefine.DepartInfo dept_list = 3; + */ + public Builder addDeptList( + int index, com.mogujie.tt.protobuf.IMBaseDefine.DepartInfo.Builder builderForValue) { + ensureDeptListIsMutable(); + deptList_.add(index, builderForValue.build()); + + return this; + } + /** + * repeated .IM.BaseDefine.DepartInfo dept_list = 3; + */ + public Builder addAllDeptList( + java.lang.Iterable values) { + ensureDeptListIsMutable(); + com.google.protobuf.AbstractMessageLite.Builder.addAll( + values, deptList_); + + return this; + } + /** + * repeated .IM.BaseDefine.DepartInfo dept_list = 3; + */ + public Builder clearDeptList() { + deptList_ = java.util.Collections.emptyList(); + bitField0_ = (bitField0_ & ~0x00000004); + + return this; + } + /** + * repeated .IM.BaseDefine.DepartInfo dept_list = 3; + */ + public Builder removeDeptList(int index) { + ensureDeptListIsMutable(); + deptList_.remove(index); + + return this; + } + + private com.google.protobuf.ByteString attachData_ = com.google.protobuf.ByteString.EMPTY; + /** + * optional bytes attach_data = 20; + */ + public boolean hasAttachData() { + return ((bitField0_ & 0x00000008) == 0x00000008); + } + /** + * optional bytes attach_data = 20; + */ + public com.google.protobuf.ByteString getAttachData() { + return attachData_; + } + /** + * optional bytes attach_data = 20; + */ + public Builder setAttachData(com.google.protobuf.ByteString value) { + if (value == null) { + throw new NullPointerException(); + } + bitField0_ |= 0x00000008; + attachData_ = value; + + return this; + } + /** + * optional bytes attach_data = 20; + */ + public Builder clearAttachData() { + bitField0_ = (bitField0_ & ~0x00000008); + attachData_ = getDefaultInstance().getAttachData(); + + return this; + } + + // @@protoc_insertion_point(builder_scope:IM.Buddy.IMDepartmentRsp) + } + + static { + defaultInstance = new IMDepartmentRsp(true); + defaultInstance.initFields(); + } + + // @@protoc_insertion_point(class_scope:IM.Buddy.IMDepartmentRsp) + } + + + static { + } + + // @@protoc_insertion_point(outer_class_scope) +} diff --git a/android/app/src/main/java/com/mogujie/tt/protobuf/IMFile.java b/android/app/src/main/java/com/mogujie/tt/protobuf/IMFile.java new file mode 100644 index 000000000..23c54f35e --- /dev/null +++ b/android/app/src/main/java/com/mogujie/tt/protobuf/IMFile.java @@ -0,0 +1,9832 @@ +// Generated by the protocol buffer compiler. DO NOT EDIT! +// source: IM.File.proto + +package com.mogujie.tt.protobuf; + +public final class IMFile { + private IMFile() {} + public static void registerAllExtensions( + com.google.protobuf.ExtensionRegistryLite registry) { + } + public interface IMFileLoginReqOrBuilder extends + // @@protoc_insertion_point(interface_extends:IM.File.IMFileLoginReq) + com.google.protobuf.MessageLiteOrBuilder { + + /** + * required uint32 user_id = 1; + * + *
+     *cmd id:	0x0501
+     * 
+ */ + boolean hasUserId(); + /** + * required uint32 user_id = 1; + * + *
+     *cmd id:	0x0501
+     * 
+ */ + int getUserId(); + + /** + * required string task_id = 2; + */ + boolean hasTaskId(); + /** + * required string task_id = 2; + */ + java.lang.String getTaskId(); + /** + * required string task_id = 2; + */ + com.google.protobuf.ByteString + getTaskIdBytes(); + + /** + * required .IM.BaseDefine.ClientFileRole file_role = 3; + */ + boolean hasFileRole(); + /** + * required .IM.BaseDefine.ClientFileRole file_role = 3; + */ + com.mogujie.tt.protobuf.IMBaseDefine.ClientFileRole getFileRole(); + } + /** + * Protobuf type {@code IM.File.IMFileLoginReq} + */ + public static final class IMFileLoginReq extends + com.google.protobuf.GeneratedMessageLite implements + // @@protoc_insertion_point(message_implements:IM.File.IMFileLoginReq) + IMFileLoginReqOrBuilder { + // Use IMFileLoginReq.newBuilder() to construct. + private IMFileLoginReq(com.google.protobuf.GeneratedMessageLite.Builder builder) { + super(builder); + this.unknownFields = builder.getUnknownFields(); + } + private IMFileLoginReq(boolean noInit) { this.unknownFields = com.google.protobuf.ByteString.EMPTY;} + + private static final IMFileLoginReq defaultInstance; + public static IMFileLoginReq getDefaultInstance() { + return defaultInstance; + } + + public IMFileLoginReq getDefaultInstanceForType() { + return defaultInstance; + } + + private final com.google.protobuf.ByteString unknownFields; + private IMFileLoginReq( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + initFields(); + int mutable_bitField0_ = 0; + com.google.protobuf.ByteString.Output unknownFieldsOutput = + com.google.protobuf.ByteString.newOutput(); + com.google.protobuf.CodedOutputStream unknownFieldsCodedOutput = + com.google.protobuf.CodedOutputStream.newInstance( + unknownFieldsOutput); + try { + boolean done = false; + while (!done) { + int tag = input.readTag(); + switch (tag) { + case 0: + done = true; + break; + default: { + if (!parseUnknownField(input, unknownFieldsCodedOutput, + extensionRegistry, tag)) { + done = true; + } + break; + } + case 8: { + bitField0_ |= 0x00000001; + userId_ = input.readUInt32(); + break; + } + case 18: { + com.google.protobuf.ByteString bs = input.readBytes(); + bitField0_ |= 0x00000002; + taskId_ = bs; + break; + } + case 24: { + int rawValue = input.readEnum(); + com.mogujie.tt.protobuf.IMBaseDefine.ClientFileRole value = com.mogujie.tt.protobuf.IMBaseDefine.ClientFileRole.valueOf(rawValue); + if (value == null) { + unknownFieldsCodedOutput.writeRawVarint32(tag); + unknownFieldsCodedOutput.writeRawVarint32(rawValue); + } else { + bitField0_ |= 0x00000004; + fileRole_ = value; + } + break; + } + } + } + } catch (com.google.protobuf.InvalidProtocolBufferException e) { + throw e.setUnfinishedMessage(this); + } catch (java.io.IOException e) { + throw new com.google.protobuf.InvalidProtocolBufferException( + e.getMessage()).setUnfinishedMessage(this); + } finally { + try { + unknownFieldsCodedOutput.flush(); + } catch (java.io.IOException e) { + // Should not happen + } finally { + unknownFields = unknownFieldsOutput.toByteString(); + } + makeExtensionsImmutable(); + } + } + public static com.google.protobuf.Parser PARSER = + new com.google.protobuf.AbstractParser() { + public IMFileLoginReq parsePartialFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return new IMFileLoginReq(input, extensionRegistry); + } + }; + + @java.lang.Override + public com.google.protobuf.Parser getParserForType() { + return PARSER; + } + + private int bitField0_; + public static final int USER_ID_FIELD_NUMBER = 1; + private int userId_; + /** + * required uint32 user_id = 1; + * + *
+     *cmd id:	0x0501
+     * 
+ */ + public boolean hasUserId() { + return ((bitField0_ & 0x00000001) == 0x00000001); + } + /** + * required uint32 user_id = 1; + * + *
+     *cmd id:	0x0501
+     * 
+ */ + public int getUserId() { + return userId_; + } + + public static final int TASK_ID_FIELD_NUMBER = 2; + private java.lang.Object taskId_; + /** + * required string task_id = 2; + */ + public boolean hasTaskId() { + return ((bitField0_ & 0x00000002) == 0x00000002); + } + /** + * required string task_id = 2; + */ + public java.lang.String getTaskId() { + java.lang.Object ref = taskId_; + if (ref instanceof java.lang.String) { + return (java.lang.String) ref; + } else { + com.google.protobuf.ByteString bs = + (com.google.protobuf.ByteString) ref; + java.lang.String s = bs.toStringUtf8(); + if (bs.isValidUtf8()) { + taskId_ = s; + } + return s; + } + } + /** + * required string task_id = 2; + */ + public com.google.protobuf.ByteString + getTaskIdBytes() { + java.lang.Object ref = taskId_; + if (ref instanceof java.lang.String) { + com.google.protobuf.ByteString b = + com.google.protobuf.ByteString.copyFromUtf8( + (java.lang.String) ref); + taskId_ = b; + return b; + } else { + return (com.google.protobuf.ByteString) ref; + } + } + + public static final int FILE_ROLE_FIELD_NUMBER = 3; + private com.mogujie.tt.protobuf.IMBaseDefine.ClientFileRole fileRole_; + /** + * required .IM.BaseDefine.ClientFileRole file_role = 3; + */ + public boolean hasFileRole() { + return ((bitField0_ & 0x00000004) == 0x00000004); + } + /** + * required .IM.BaseDefine.ClientFileRole file_role = 3; + */ + public com.mogujie.tt.protobuf.IMBaseDefine.ClientFileRole getFileRole() { + return fileRole_; + } + + private void initFields() { + userId_ = 0; + taskId_ = ""; + fileRole_ = com.mogujie.tt.protobuf.IMBaseDefine.ClientFileRole.CLIENT_REALTIME_SENDER; + } + private byte memoizedIsInitialized = -1; + public final boolean isInitialized() { + byte isInitialized = memoizedIsInitialized; + if (isInitialized == 1) return true; + if (isInitialized == 0) return false; + + if (!hasUserId()) { + memoizedIsInitialized = 0; + return false; + } + if (!hasTaskId()) { + memoizedIsInitialized = 0; + return false; + } + if (!hasFileRole()) { + memoizedIsInitialized = 0; + return false; + } + memoizedIsInitialized = 1; + return true; + } + + public void writeTo(com.google.protobuf.CodedOutputStream output) + throws java.io.IOException { + getSerializedSize(); + if (((bitField0_ & 0x00000001) == 0x00000001)) { + output.writeUInt32(1, userId_); + } + if (((bitField0_ & 0x00000002) == 0x00000002)) { + output.writeBytes(2, getTaskIdBytes()); + } + if (((bitField0_ & 0x00000004) == 0x00000004)) { + output.writeEnum(3, fileRole_.getNumber()); + } + output.writeRawBytes(unknownFields); + } + + private int memoizedSerializedSize = -1; + public int getSerializedSize() { + int size = memoizedSerializedSize; + if (size != -1) return size; + + size = 0; + if (((bitField0_ & 0x00000001) == 0x00000001)) { + size += com.google.protobuf.CodedOutputStream + .computeUInt32Size(1, userId_); + } + if (((bitField0_ & 0x00000002) == 0x00000002)) { + size += com.google.protobuf.CodedOutputStream + .computeBytesSize(2, getTaskIdBytes()); + } + if (((bitField0_ & 0x00000004) == 0x00000004)) { + size += com.google.protobuf.CodedOutputStream + .computeEnumSize(3, fileRole_.getNumber()); + } + size += unknownFields.size(); + memoizedSerializedSize = size; + return size; + } + + private static final long serialVersionUID = 0L; + @java.lang.Override + protected java.lang.Object writeReplace() + throws java.io.ObjectStreamException { + return super.writeReplace(); + } + + public static com.mogujie.tt.protobuf.IMFile.IMFileLoginReq parseFrom( + com.google.protobuf.ByteString data) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data); + } + public static com.mogujie.tt.protobuf.IMFile.IMFileLoginReq parseFrom( + com.google.protobuf.ByteString data, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data, extensionRegistry); + } + public static com.mogujie.tt.protobuf.IMFile.IMFileLoginReq parseFrom(byte[] data) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data); + } + public static com.mogujie.tt.protobuf.IMFile.IMFileLoginReq parseFrom( + byte[] data, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data, extensionRegistry); + } + public static com.mogujie.tt.protobuf.IMFile.IMFileLoginReq parseFrom(java.io.InputStream input) + throws java.io.IOException { + return PARSER.parseFrom(input); + } + public static com.mogujie.tt.protobuf.IMFile.IMFileLoginReq parseFrom( + java.io.InputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return PARSER.parseFrom(input, extensionRegistry); + } + public static com.mogujie.tt.protobuf.IMFile.IMFileLoginReq parseDelimitedFrom(java.io.InputStream input) + throws java.io.IOException { + return PARSER.parseDelimitedFrom(input); + } + public static com.mogujie.tt.protobuf.IMFile.IMFileLoginReq parseDelimitedFrom( + java.io.InputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return PARSER.parseDelimitedFrom(input, extensionRegistry); + } + public static com.mogujie.tt.protobuf.IMFile.IMFileLoginReq parseFrom( + com.google.protobuf.CodedInputStream input) + throws java.io.IOException { + return PARSER.parseFrom(input); + } + public static com.mogujie.tt.protobuf.IMFile.IMFileLoginReq parseFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return PARSER.parseFrom(input, extensionRegistry); + } + + public static Builder newBuilder() { return Builder.create(); } + public Builder newBuilderForType() { return newBuilder(); } + public static Builder newBuilder(com.mogujie.tt.protobuf.IMFile.IMFileLoginReq prototype) { + return newBuilder().mergeFrom(prototype); + } + public Builder toBuilder() { return newBuilder(this); } + + /** + * Protobuf type {@code IM.File.IMFileLoginReq} + */ + public static final class Builder extends + com.google.protobuf.GeneratedMessageLite.Builder< + com.mogujie.tt.protobuf.IMFile.IMFileLoginReq, Builder> + implements + // @@protoc_insertion_point(builder_implements:IM.File.IMFileLoginReq) + com.mogujie.tt.protobuf.IMFile.IMFileLoginReqOrBuilder { + // Construct using com.mogujie.tt.protobuf.IMFile.IMFileLoginReq.newBuilder() + private Builder() { + maybeForceBuilderInitialization(); + } + + private void maybeForceBuilderInitialization() { + } + private static Builder create() { + return new Builder(); + } + + public Builder clear() { + super.clear(); + userId_ = 0; + bitField0_ = (bitField0_ & ~0x00000001); + taskId_ = ""; + bitField0_ = (bitField0_ & ~0x00000002); + fileRole_ = com.mogujie.tt.protobuf.IMBaseDefine.ClientFileRole.CLIENT_REALTIME_SENDER; + bitField0_ = (bitField0_ & ~0x00000004); + return this; + } + + public Builder clone() { + return create().mergeFrom(buildPartial()); + } + + public com.mogujie.tt.protobuf.IMFile.IMFileLoginReq getDefaultInstanceForType() { + return com.mogujie.tt.protobuf.IMFile.IMFileLoginReq.getDefaultInstance(); + } + + public com.mogujie.tt.protobuf.IMFile.IMFileLoginReq build() { + com.mogujie.tt.protobuf.IMFile.IMFileLoginReq result = buildPartial(); + if (!result.isInitialized()) { + throw newUninitializedMessageException(result); + } + return result; + } + + public com.mogujie.tt.protobuf.IMFile.IMFileLoginReq buildPartial() { + com.mogujie.tt.protobuf.IMFile.IMFileLoginReq result = new com.mogujie.tt.protobuf.IMFile.IMFileLoginReq(this); + int from_bitField0_ = bitField0_; + int to_bitField0_ = 0; + if (((from_bitField0_ & 0x00000001) == 0x00000001)) { + to_bitField0_ |= 0x00000001; + } + result.userId_ = userId_; + if (((from_bitField0_ & 0x00000002) == 0x00000002)) { + to_bitField0_ |= 0x00000002; + } + result.taskId_ = taskId_; + if (((from_bitField0_ & 0x00000004) == 0x00000004)) { + to_bitField0_ |= 0x00000004; + } + result.fileRole_ = fileRole_; + result.bitField0_ = to_bitField0_; + return result; + } + + public Builder mergeFrom(com.mogujie.tt.protobuf.IMFile.IMFileLoginReq other) { + if (other == com.mogujie.tt.protobuf.IMFile.IMFileLoginReq.getDefaultInstance()) return this; + if (other.hasUserId()) { + setUserId(other.getUserId()); + } + if (other.hasTaskId()) { + bitField0_ |= 0x00000002; + taskId_ = other.taskId_; + + } + if (other.hasFileRole()) { + setFileRole(other.getFileRole()); + } + setUnknownFields( + getUnknownFields().concat(other.unknownFields)); + return this; + } + + public final boolean isInitialized() { + if (!hasUserId()) { + + return false; + } + if (!hasTaskId()) { + + return false; + } + if (!hasFileRole()) { + + return false; + } + return true; + } + + public Builder mergeFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + com.mogujie.tt.protobuf.IMFile.IMFileLoginReq parsedMessage = null; + try { + parsedMessage = PARSER.parsePartialFrom(input, extensionRegistry); + } catch (com.google.protobuf.InvalidProtocolBufferException e) { + parsedMessage = (com.mogujie.tt.protobuf.IMFile.IMFileLoginReq) e.getUnfinishedMessage(); + throw e; + } finally { + if (parsedMessage != null) { + mergeFrom(parsedMessage); + } + } + return this; + } + private int bitField0_; + + private int userId_ ; + /** + * required uint32 user_id = 1; + * + *
+       *cmd id:	0x0501
+       * 
+ */ + public boolean hasUserId() { + return ((bitField0_ & 0x00000001) == 0x00000001); + } + /** + * required uint32 user_id = 1; + * + *
+       *cmd id:	0x0501
+       * 
+ */ + public int getUserId() { + return userId_; + } + /** + * required uint32 user_id = 1; + * + *
+       *cmd id:	0x0501
+       * 
+ */ + public Builder setUserId(int value) { + bitField0_ |= 0x00000001; + userId_ = value; + + return this; + } + /** + * required uint32 user_id = 1; + * + *
+       *cmd id:	0x0501
+       * 
+ */ + public Builder clearUserId() { + bitField0_ = (bitField0_ & ~0x00000001); + userId_ = 0; + + return this; + } + + private java.lang.Object taskId_ = ""; + /** + * required string task_id = 2; + */ + public boolean hasTaskId() { + return ((bitField0_ & 0x00000002) == 0x00000002); + } + /** + * required string task_id = 2; + */ + public java.lang.String getTaskId() { + java.lang.Object ref = taskId_; + if (!(ref instanceof java.lang.String)) { + com.google.protobuf.ByteString bs = + (com.google.protobuf.ByteString) ref; + java.lang.String s = bs.toStringUtf8(); + if (bs.isValidUtf8()) { + taskId_ = s; + } + return s; + } else { + return (java.lang.String) ref; + } + } + /** + * required string task_id = 2; + */ + public com.google.protobuf.ByteString + getTaskIdBytes() { + java.lang.Object ref = taskId_; + if (ref instanceof String) { + com.google.protobuf.ByteString b = + com.google.protobuf.ByteString.copyFromUtf8( + (java.lang.String) ref); + taskId_ = b; + return b; + } else { + return (com.google.protobuf.ByteString) ref; + } + } + /** + * required string task_id = 2; + */ + public Builder setTaskId( + java.lang.String value) { + if (value == null) { + throw new NullPointerException(); + } + bitField0_ |= 0x00000002; + taskId_ = value; + + return this; + } + /** + * required string task_id = 2; + */ + public Builder clearTaskId() { + bitField0_ = (bitField0_ & ~0x00000002); + taskId_ = getDefaultInstance().getTaskId(); + + return this; + } + /** + * required string task_id = 2; + */ + public Builder setTaskIdBytes( + com.google.protobuf.ByteString value) { + if (value == null) { + throw new NullPointerException(); + } + bitField0_ |= 0x00000002; + taskId_ = value; + + return this; + } + + private com.mogujie.tt.protobuf.IMBaseDefine.ClientFileRole fileRole_ = com.mogujie.tt.protobuf.IMBaseDefine.ClientFileRole.CLIENT_REALTIME_SENDER; + /** + * required .IM.BaseDefine.ClientFileRole file_role = 3; + */ + public boolean hasFileRole() { + return ((bitField0_ & 0x00000004) == 0x00000004); + } + /** + * required .IM.BaseDefine.ClientFileRole file_role = 3; + */ + public com.mogujie.tt.protobuf.IMBaseDefine.ClientFileRole getFileRole() { + return fileRole_; + } + /** + * required .IM.BaseDefine.ClientFileRole file_role = 3; + */ + public Builder setFileRole(com.mogujie.tt.protobuf.IMBaseDefine.ClientFileRole value) { + if (value == null) { + throw new NullPointerException(); + } + bitField0_ |= 0x00000004; + fileRole_ = value; + + return this; + } + /** + * required .IM.BaseDefine.ClientFileRole file_role = 3; + */ + public Builder clearFileRole() { + bitField0_ = (bitField0_ & ~0x00000004); + fileRole_ = com.mogujie.tt.protobuf.IMBaseDefine.ClientFileRole.CLIENT_REALTIME_SENDER; + + return this; + } + + // @@protoc_insertion_point(builder_scope:IM.File.IMFileLoginReq) + } + + static { + defaultInstance = new IMFileLoginReq(true); + defaultInstance.initFields(); + } + + // @@protoc_insertion_point(class_scope:IM.File.IMFileLoginReq) + } + + public interface IMFileLoginRspOrBuilder extends + // @@protoc_insertion_point(interface_extends:IM.File.IMFileLoginRsp) + com.google.protobuf.MessageLiteOrBuilder { + + /** + * required uint32 result_code = 1; + * + *
+     *cmd id:	0x0502
+     * 
+ */ + boolean hasResultCode(); + /** + * required uint32 result_code = 1; + * + *
+     *cmd id:	0x0502
+     * 
+ */ + int getResultCode(); + + /** + * required string task_id = 2; + */ + boolean hasTaskId(); + /** + * required string task_id = 2; + */ + java.lang.String getTaskId(); + /** + * required string task_id = 2; + */ + com.google.protobuf.ByteString + getTaskIdBytes(); + } + /** + * Protobuf type {@code IM.File.IMFileLoginRsp} + */ + public static final class IMFileLoginRsp extends + com.google.protobuf.GeneratedMessageLite implements + // @@protoc_insertion_point(message_implements:IM.File.IMFileLoginRsp) + IMFileLoginRspOrBuilder { + // Use IMFileLoginRsp.newBuilder() to construct. + private IMFileLoginRsp(com.google.protobuf.GeneratedMessageLite.Builder builder) { + super(builder); + this.unknownFields = builder.getUnknownFields(); + } + private IMFileLoginRsp(boolean noInit) { this.unknownFields = com.google.protobuf.ByteString.EMPTY;} + + private static final IMFileLoginRsp defaultInstance; + public static IMFileLoginRsp getDefaultInstance() { + return defaultInstance; + } + + public IMFileLoginRsp getDefaultInstanceForType() { + return defaultInstance; + } + + private final com.google.protobuf.ByteString unknownFields; + private IMFileLoginRsp( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + initFields(); + int mutable_bitField0_ = 0; + com.google.protobuf.ByteString.Output unknownFieldsOutput = + com.google.protobuf.ByteString.newOutput(); + com.google.protobuf.CodedOutputStream unknownFieldsCodedOutput = + com.google.protobuf.CodedOutputStream.newInstance( + unknownFieldsOutput); + try { + boolean done = false; + while (!done) { + int tag = input.readTag(); + switch (tag) { + case 0: + done = true; + break; + default: { + if (!parseUnknownField(input, unknownFieldsCodedOutput, + extensionRegistry, tag)) { + done = true; + } + break; + } + case 8: { + bitField0_ |= 0x00000001; + resultCode_ = input.readUInt32(); + break; + } + case 18: { + com.google.protobuf.ByteString bs = input.readBytes(); + bitField0_ |= 0x00000002; + taskId_ = bs; + break; + } + } + } + } catch (com.google.protobuf.InvalidProtocolBufferException e) { + throw e.setUnfinishedMessage(this); + } catch (java.io.IOException e) { + throw new com.google.protobuf.InvalidProtocolBufferException( + e.getMessage()).setUnfinishedMessage(this); + } finally { + try { + unknownFieldsCodedOutput.flush(); + } catch (java.io.IOException e) { + // Should not happen + } finally { + unknownFields = unknownFieldsOutput.toByteString(); + } + makeExtensionsImmutable(); + } + } + public static com.google.protobuf.Parser PARSER = + new com.google.protobuf.AbstractParser() { + public IMFileLoginRsp parsePartialFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return new IMFileLoginRsp(input, extensionRegistry); + } + }; + + @java.lang.Override + public com.google.protobuf.Parser getParserForType() { + return PARSER; + } + + private int bitField0_; + public static final int RESULT_CODE_FIELD_NUMBER = 1; + private int resultCode_; + /** + * required uint32 result_code = 1; + * + *
+     *cmd id:	0x0502
+     * 
+ */ + public boolean hasResultCode() { + return ((bitField0_ & 0x00000001) == 0x00000001); + } + /** + * required uint32 result_code = 1; + * + *
+     *cmd id:	0x0502
+     * 
+ */ + public int getResultCode() { + return resultCode_; + } + + public static final int TASK_ID_FIELD_NUMBER = 2; + private java.lang.Object taskId_; + /** + * required string task_id = 2; + */ + public boolean hasTaskId() { + return ((bitField0_ & 0x00000002) == 0x00000002); + } + /** + * required string task_id = 2; + */ + public java.lang.String getTaskId() { + java.lang.Object ref = taskId_; + if (ref instanceof java.lang.String) { + return (java.lang.String) ref; + } else { + com.google.protobuf.ByteString bs = + (com.google.protobuf.ByteString) ref; + java.lang.String s = bs.toStringUtf8(); + if (bs.isValidUtf8()) { + taskId_ = s; + } + return s; + } + } + /** + * required string task_id = 2; + */ + public com.google.protobuf.ByteString + getTaskIdBytes() { + java.lang.Object ref = taskId_; + if (ref instanceof java.lang.String) { + com.google.protobuf.ByteString b = + com.google.protobuf.ByteString.copyFromUtf8( + (java.lang.String) ref); + taskId_ = b; + return b; + } else { + return (com.google.protobuf.ByteString) ref; + } + } + + private void initFields() { + resultCode_ = 0; + taskId_ = ""; + } + private byte memoizedIsInitialized = -1; + public final boolean isInitialized() { + byte isInitialized = memoizedIsInitialized; + if (isInitialized == 1) return true; + if (isInitialized == 0) return false; + + if (!hasResultCode()) { + memoizedIsInitialized = 0; + return false; + } + if (!hasTaskId()) { + memoizedIsInitialized = 0; + return false; + } + memoizedIsInitialized = 1; + return true; + } + + public void writeTo(com.google.protobuf.CodedOutputStream output) + throws java.io.IOException { + getSerializedSize(); + if (((bitField0_ & 0x00000001) == 0x00000001)) { + output.writeUInt32(1, resultCode_); + } + if (((bitField0_ & 0x00000002) == 0x00000002)) { + output.writeBytes(2, getTaskIdBytes()); + } + output.writeRawBytes(unknownFields); + } + + private int memoizedSerializedSize = -1; + public int getSerializedSize() { + int size = memoizedSerializedSize; + if (size != -1) return size; + + size = 0; + if (((bitField0_ & 0x00000001) == 0x00000001)) { + size += com.google.protobuf.CodedOutputStream + .computeUInt32Size(1, resultCode_); + } + if (((bitField0_ & 0x00000002) == 0x00000002)) { + size += com.google.protobuf.CodedOutputStream + .computeBytesSize(2, getTaskIdBytes()); + } + size += unknownFields.size(); + memoizedSerializedSize = size; + return size; + } + + private static final long serialVersionUID = 0L; + @java.lang.Override + protected java.lang.Object writeReplace() + throws java.io.ObjectStreamException { + return super.writeReplace(); + } + + public static com.mogujie.tt.protobuf.IMFile.IMFileLoginRsp parseFrom( + com.google.protobuf.ByteString data) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data); + } + public static com.mogujie.tt.protobuf.IMFile.IMFileLoginRsp parseFrom( + com.google.protobuf.ByteString data, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data, extensionRegistry); + } + public static com.mogujie.tt.protobuf.IMFile.IMFileLoginRsp parseFrom(byte[] data) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data); + } + public static com.mogujie.tt.protobuf.IMFile.IMFileLoginRsp parseFrom( + byte[] data, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data, extensionRegistry); + } + public static com.mogujie.tt.protobuf.IMFile.IMFileLoginRsp parseFrom(java.io.InputStream input) + throws java.io.IOException { + return PARSER.parseFrom(input); + } + public static com.mogujie.tt.protobuf.IMFile.IMFileLoginRsp parseFrom( + java.io.InputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return PARSER.parseFrom(input, extensionRegistry); + } + public static com.mogujie.tt.protobuf.IMFile.IMFileLoginRsp parseDelimitedFrom(java.io.InputStream input) + throws java.io.IOException { + return PARSER.parseDelimitedFrom(input); + } + public static com.mogujie.tt.protobuf.IMFile.IMFileLoginRsp parseDelimitedFrom( + java.io.InputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return PARSER.parseDelimitedFrom(input, extensionRegistry); + } + public static com.mogujie.tt.protobuf.IMFile.IMFileLoginRsp parseFrom( + com.google.protobuf.CodedInputStream input) + throws java.io.IOException { + return PARSER.parseFrom(input); + } + public static com.mogujie.tt.protobuf.IMFile.IMFileLoginRsp parseFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return PARSER.parseFrom(input, extensionRegistry); + } + + public static Builder newBuilder() { return Builder.create(); } + public Builder newBuilderForType() { return newBuilder(); } + public static Builder newBuilder(com.mogujie.tt.protobuf.IMFile.IMFileLoginRsp prototype) { + return newBuilder().mergeFrom(prototype); + } + public Builder toBuilder() { return newBuilder(this); } + + /** + * Protobuf type {@code IM.File.IMFileLoginRsp} + */ + public static final class Builder extends + com.google.protobuf.GeneratedMessageLite.Builder< + com.mogujie.tt.protobuf.IMFile.IMFileLoginRsp, Builder> + implements + // @@protoc_insertion_point(builder_implements:IM.File.IMFileLoginRsp) + com.mogujie.tt.protobuf.IMFile.IMFileLoginRspOrBuilder { + // Construct using com.mogujie.tt.protobuf.IMFile.IMFileLoginRsp.newBuilder() + private Builder() { + maybeForceBuilderInitialization(); + } + + private void maybeForceBuilderInitialization() { + } + private static Builder create() { + return new Builder(); + } + + public Builder clear() { + super.clear(); + resultCode_ = 0; + bitField0_ = (bitField0_ & ~0x00000001); + taskId_ = ""; + bitField0_ = (bitField0_ & ~0x00000002); + return this; + } + + public Builder clone() { + return create().mergeFrom(buildPartial()); + } + + public com.mogujie.tt.protobuf.IMFile.IMFileLoginRsp getDefaultInstanceForType() { + return com.mogujie.tt.protobuf.IMFile.IMFileLoginRsp.getDefaultInstance(); + } + + public com.mogujie.tt.protobuf.IMFile.IMFileLoginRsp build() { + com.mogujie.tt.protobuf.IMFile.IMFileLoginRsp result = buildPartial(); + if (!result.isInitialized()) { + throw newUninitializedMessageException(result); + } + return result; + } + + public com.mogujie.tt.protobuf.IMFile.IMFileLoginRsp buildPartial() { + com.mogujie.tt.protobuf.IMFile.IMFileLoginRsp result = new com.mogujie.tt.protobuf.IMFile.IMFileLoginRsp(this); + int from_bitField0_ = bitField0_; + int to_bitField0_ = 0; + if (((from_bitField0_ & 0x00000001) == 0x00000001)) { + to_bitField0_ |= 0x00000001; + } + result.resultCode_ = resultCode_; + if (((from_bitField0_ & 0x00000002) == 0x00000002)) { + to_bitField0_ |= 0x00000002; + } + result.taskId_ = taskId_; + result.bitField0_ = to_bitField0_; + return result; + } + + public Builder mergeFrom(com.mogujie.tt.protobuf.IMFile.IMFileLoginRsp other) { + if (other == com.mogujie.tt.protobuf.IMFile.IMFileLoginRsp.getDefaultInstance()) return this; + if (other.hasResultCode()) { + setResultCode(other.getResultCode()); + } + if (other.hasTaskId()) { + bitField0_ |= 0x00000002; + taskId_ = other.taskId_; + + } + setUnknownFields( + getUnknownFields().concat(other.unknownFields)); + return this; + } + + public final boolean isInitialized() { + if (!hasResultCode()) { + + return false; + } + if (!hasTaskId()) { + + return false; + } + return true; + } + + public Builder mergeFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + com.mogujie.tt.protobuf.IMFile.IMFileLoginRsp parsedMessage = null; + try { + parsedMessage = PARSER.parsePartialFrom(input, extensionRegistry); + } catch (com.google.protobuf.InvalidProtocolBufferException e) { + parsedMessage = (com.mogujie.tt.protobuf.IMFile.IMFileLoginRsp) e.getUnfinishedMessage(); + throw e; + } finally { + if (parsedMessage != null) { + mergeFrom(parsedMessage); + } + } + return this; + } + private int bitField0_; + + private int resultCode_ ; + /** + * required uint32 result_code = 1; + * + *
+       *cmd id:	0x0502
+       * 
+ */ + public boolean hasResultCode() { + return ((bitField0_ & 0x00000001) == 0x00000001); + } + /** + * required uint32 result_code = 1; + * + *
+       *cmd id:	0x0502
+       * 
+ */ + public int getResultCode() { + return resultCode_; + } + /** + * required uint32 result_code = 1; + * + *
+       *cmd id:	0x0502
+       * 
+ */ + public Builder setResultCode(int value) { + bitField0_ |= 0x00000001; + resultCode_ = value; + + return this; + } + /** + * required uint32 result_code = 1; + * + *
+       *cmd id:	0x0502
+       * 
+ */ + public Builder clearResultCode() { + bitField0_ = (bitField0_ & ~0x00000001); + resultCode_ = 0; + + return this; + } + + private java.lang.Object taskId_ = ""; + /** + * required string task_id = 2; + */ + public boolean hasTaskId() { + return ((bitField0_ & 0x00000002) == 0x00000002); + } + /** + * required string task_id = 2; + */ + public java.lang.String getTaskId() { + java.lang.Object ref = taskId_; + if (!(ref instanceof java.lang.String)) { + com.google.protobuf.ByteString bs = + (com.google.protobuf.ByteString) ref; + java.lang.String s = bs.toStringUtf8(); + if (bs.isValidUtf8()) { + taskId_ = s; + } + return s; + } else { + return (java.lang.String) ref; + } + } + /** + * required string task_id = 2; + */ + public com.google.protobuf.ByteString + getTaskIdBytes() { + java.lang.Object ref = taskId_; + if (ref instanceof String) { + com.google.protobuf.ByteString b = + com.google.protobuf.ByteString.copyFromUtf8( + (java.lang.String) ref); + taskId_ = b; + return b; + } else { + return (com.google.protobuf.ByteString) ref; + } + } + /** + * required string task_id = 2; + */ + public Builder setTaskId( + java.lang.String value) { + if (value == null) { + throw new NullPointerException(); + } + bitField0_ |= 0x00000002; + taskId_ = value; + + return this; + } + /** + * required string task_id = 2; + */ + public Builder clearTaskId() { + bitField0_ = (bitField0_ & ~0x00000002); + taskId_ = getDefaultInstance().getTaskId(); + + return this; + } + /** + * required string task_id = 2; + */ + public Builder setTaskIdBytes( + com.google.protobuf.ByteString value) { + if (value == null) { + throw new NullPointerException(); + } + bitField0_ |= 0x00000002; + taskId_ = value; + + return this; + } + + // @@protoc_insertion_point(builder_scope:IM.File.IMFileLoginRsp) + } + + static { + defaultInstance = new IMFileLoginRsp(true); + defaultInstance.initFields(); + } + + // @@protoc_insertion_point(class_scope:IM.File.IMFileLoginRsp) + } + + public interface IMFileStateOrBuilder extends + // @@protoc_insertion_point(interface_extends:IM.File.IMFileState) + com.google.protobuf.MessageLiteOrBuilder { + + /** + * required .IM.BaseDefine.ClientFileState state = 1; + * + *
+     *cmd id: 	0x0503
+     * 
+ */ + boolean hasState(); + /** + * required .IM.BaseDefine.ClientFileState state = 1; + * + *
+     *cmd id: 	0x0503
+     * 
+ */ + com.mogujie.tt.protobuf.IMBaseDefine.ClientFileState getState(); + + /** + * required string task_id = 2; + */ + boolean hasTaskId(); + /** + * required string task_id = 2; + */ + java.lang.String getTaskId(); + /** + * required string task_id = 2; + */ + com.google.protobuf.ByteString + getTaskIdBytes(); + + /** + * required uint32 user_id = 3; + */ + boolean hasUserId(); + /** + * required uint32 user_id = 3; + */ + int getUserId(); + } + /** + * Protobuf type {@code IM.File.IMFileState} + */ + public static final class IMFileState extends + com.google.protobuf.GeneratedMessageLite implements + // @@protoc_insertion_point(message_implements:IM.File.IMFileState) + IMFileStateOrBuilder { + // Use IMFileState.newBuilder() to construct. + private IMFileState(com.google.protobuf.GeneratedMessageLite.Builder builder) { + super(builder); + this.unknownFields = builder.getUnknownFields(); + } + private IMFileState(boolean noInit) { this.unknownFields = com.google.protobuf.ByteString.EMPTY;} + + private static final IMFileState defaultInstance; + public static IMFileState getDefaultInstance() { + return defaultInstance; + } + + public IMFileState getDefaultInstanceForType() { + return defaultInstance; + } + + private final com.google.protobuf.ByteString unknownFields; + private IMFileState( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + initFields(); + int mutable_bitField0_ = 0; + com.google.protobuf.ByteString.Output unknownFieldsOutput = + com.google.protobuf.ByteString.newOutput(); + com.google.protobuf.CodedOutputStream unknownFieldsCodedOutput = + com.google.protobuf.CodedOutputStream.newInstance( + unknownFieldsOutput); + try { + boolean done = false; + while (!done) { + int tag = input.readTag(); + switch (tag) { + case 0: + done = true; + break; + default: { + if (!parseUnknownField(input, unknownFieldsCodedOutput, + extensionRegistry, tag)) { + done = true; + } + break; + } + case 8: { + int rawValue = input.readEnum(); + com.mogujie.tt.protobuf.IMBaseDefine.ClientFileState value = com.mogujie.tt.protobuf.IMBaseDefine.ClientFileState.valueOf(rawValue); + if (value == null) { + unknownFieldsCodedOutput.writeRawVarint32(tag); + unknownFieldsCodedOutput.writeRawVarint32(rawValue); + } else { + bitField0_ |= 0x00000001; + state_ = value; + } + break; + } + case 18: { + com.google.protobuf.ByteString bs = input.readBytes(); + bitField0_ |= 0x00000002; + taskId_ = bs; + break; + } + case 24: { + bitField0_ |= 0x00000004; + userId_ = input.readUInt32(); + break; + } + } + } + } catch (com.google.protobuf.InvalidProtocolBufferException e) { + throw e.setUnfinishedMessage(this); + } catch (java.io.IOException e) { + throw new com.google.protobuf.InvalidProtocolBufferException( + e.getMessage()).setUnfinishedMessage(this); + } finally { + try { + unknownFieldsCodedOutput.flush(); + } catch (java.io.IOException e) { + // Should not happen + } finally { + unknownFields = unknownFieldsOutput.toByteString(); + } + makeExtensionsImmutable(); + } + } + public static com.google.protobuf.Parser PARSER = + new com.google.protobuf.AbstractParser() { + public IMFileState parsePartialFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return new IMFileState(input, extensionRegistry); + } + }; + + @java.lang.Override + public com.google.protobuf.Parser getParserForType() { + return PARSER; + } + + private int bitField0_; + public static final int STATE_FIELD_NUMBER = 1; + private com.mogujie.tt.protobuf.IMBaseDefine.ClientFileState state_; + /** + * required .IM.BaseDefine.ClientFileState state = 1; + * + *
+     *cmd id: 	0x0503
+     * 
+ */ + public boolean hasState() { + return ((bitField0_ & 0x00000001) == 0x00000001); + } + /** + * required .IM.BaseDefine.ClientFileState state = 1; + * + *
+     *cmd id: 	0x0503
+     * 
+ */ + public com.mogujie.tt.protobuf.IMBaseDefine.ClientFileState getState() { + return state_; + } + + public static final int TASK_ID_FIELD_NUMBER = 2; + private java.lang.Object taskId_; + /** + * required string task_id = 2; + */ + public boolean hasTaskId() { + return ((bitField0_ & 0x00000002) == 0x00000002); + } + /** + * required string task_id = 2; + */ + public java.lang.String getTaskId() { + java.lang.Object ref = taskId_; + if (ref instanceof java.lang.String) { + return (java.lang.String) ref; + } else { + com.google.protobuf.ByteString bs = + (com.google.protobuf.ByteString) ref; + java.lang.String s = bs.toStringUtf8(); + if (bs.isValidUtf8()) { + taskId_ = s; + } + return s; + } + } + /** + * required string task_id = 2; + */ + public com.google.protobuf.ByteString + getTaskIdBytes() { + java.lang.Object ref = taskId_; + if (ref instanceof java.lang.String) { + com.google.protobuf.ByteString b = + com.google.protobuf.ByteString.copyFromUtf8( + (java.lang.String) ref); + taskId_ = b; + return b; + } else { + return (com.google.protobuf.ByteString) ref; + } + } + + public static final int USER_ID_FIELD_NUMBER = 3; + private int userId_; + /** + * required uint32 user_id = 3; + */ + public boolean hasUserId() { + return ((bitField0_ & 0x00000004) == 0x00000004); + } + /** + * required uint32 user_id = 3; + */ + public int getUserId() { + return userId_; + } + + private void initFields() { + state_ = com.mogujie.tt.protobuf.IMBaseDefine.ClientFileState.CLIENT_FILE_PEER_READY; + taskId_ = ""; + userId_ = 0; + } + private byte memoizedIsInitialized = -1; + public final boolean isInitialized() { + byte isInitialized = memoizedIsInitialized; + if (isInitialized == 1) return true; + if (isInitialized == 0) return false; + + if (!hasState()) { + memoizedIsInitialized = 0; + return false; + } + if (!hasTaskId()) { + memoizedIsInitialized = 0; + return false; + } + if (!hasUserId()) { + memoizedIsInitialized = 0; + return false; + } + memoizedIsInitialized = 1; + return true; + } + + public void writeTo(com.google.protobuf.CodedOutputStream output) + throws java.io.IOException { + getSerializedSize(); + if (((bitField0_ & 0x00000001) == 0x00000001)) { + output.writeEnum(1, state_.getNumber()); + } + if (((bitField0_ & 0x00000002) == 0x00000002)) { + output.writeBytes(2, getTaskIdBytes()); + } + if (((bitField0_ & 0x00000004) == 0x00000004)) { + output.writeUInt32(3, userId_); + } + output.writeRawBytes(unknownFields); + } + + private int memoizedSerializedSize = -1; + public int getSerializedSize() { + int size = memoizedSerializedSize; + if (size != -1) return size; + + size = 0; + if (((bitField0_ & 0x00000001) == 0x00000001)) { + size += com.google.protobuf.CodedOutputStream + .computeEnumSize(1, state_.getNumber()); + } + if (((bitField0_ & 0x00000002) == 0x00000002)) { + size += com.google.protobuf.CodedOutputStream + .computeBytesSize(2, getTaskIdBytes()); + } + if (((bitField0_ & 0x00000004) == 0x00000004)) { + size += com.google.protobuf.CodedOutputStream + .computeUInt32Size(3, userId_); + } + size += unknownFields.size(); + memoizedSerializedSize = size; + return size; + } + + private static final long serialVersionUID = 0L; + @java.lang.Override + protected java.lang.Object writeReplace() + throws java.io.ObjectStreamException { + return super.writeReplace(); + } + + public static com.mogujie.tt.protobuf.IMFile.IMFileState parseFrom( + com.google.protobuf.ByteString data) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data); + } + public static com.mogujie.tt.protobuf.IMFile.IMFileState parseFrom( + com.google.protobuf.ByteString data, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data, extensionRegistry); + } + public static com.mogujie.tt.protobuf.IMFile.IMFileState parseFrom(byte[] data) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data); + } + public static com.mogujie.tt.protobuf.IMFile.IMFileState parseFrom( + byte[] data, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data, extensionRegistry); + } + public static com.mogujie.tt.protobuf.IMFile.IMFileState parseFrom(java.io.InputStream input) + throws java.io.IOException { + return PARSER.parseFrom(input); + } + public static com.mogujie.tt.protobuf.IMFile.IMFileState parseFrom( + java.io.InputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return PARSER.parseFrom(input, extensionRegistry); + } + public static com.mogujie.tt.protobuf.IMFile.IMFileState parseDelimitedFrom(java.io.InputStream input) + throws java.io.IOException { + return PARSER.parseDelimitedFrom(input); + } + public static com.mogujie.tt.protobuf.IMFile.IMFileState parseDelimitedFrom( + java.io.InputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return PARSER.parseDelimitedFrom(input, extensionRegistry); + } + public static com.mogujie.tt.protobuf.IMFile.IMFileState parseFrom( + com.google.protobuf.CodedInputStream input) + throws java.io.IOException { + return PARSER.parseFrom(input); + } + public static com.mogujie.tt.protobuf.IMFile.IMFileState parseFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return PARSER.parseFrom(input, extensionRegistry); + } + + public static Builder newBuilder() { return Builder.create(); } + public Builder newBuilderForType() { return newBuilder(); } + public static Builder newBuilder(com.mogujie.tt.protobuf.IMFile.IMFileState prototype) { + return newBuilder().mergeFrom(prototype); + } + public Builder toBuilder() { return newBuilder(this); } + + /** + * Protobuf type {@code IM.File.IMFileState} + */ + public static final class Builder extends + com.google.protobuf.GeneratedMessageLite.Builder< + com.mogujie.tt.protobuf.IMFile.IMFileState, Builder> + implements + // @@protoc_insertion_point(builder_implements:IM.File.IMFileState) + com.mogujie.tt.protobuf.IMFile.IMFileStateOrBuilder { + // Construct using com.mogujie.tt.protobuf.IMFile.IMFileState.newBuilder() + private Builder() { + maybeForceBuilderInitialization(); + } + + private void maybeForceBuilderInitialization() { + } + private static Builder create() { + return new Builder(); + } + + public Builder clear() { + super.clear(); + state_ = com.mogujie.tt.protobuf.IMBaseDefine.ClientFileState.CLIENT_FILE_PEER_READY; + bitField0_ = (bitField0_ & ~0x00000001); + taskId_ = ""; + bitField0_ = (bitField0_ & ~0x00000002); + userId_ = 0; + bitField0_ = (bitField0_ & ~0x00000004); + return this; + } + + public Builder clone() { + return create().mergeFrom(buildPartial()); + } + + public com.mogujie.tt.protobuf.IMFile.IMFileState getDefaultInstanceForType() { + return com.mogujie.tt.protobuf.IMFile.IMFileState.getDefaultInstance(); + } + + public com.mogujie.tt.protobuf.IMFile.IMFileState build() { + com.mogujie.tt.protobuf.IMFile.IMFileState result = buildPartial(); + if (!result.isInitialized()) { + throw newUninitializedMessageException(result); + } + return result; + } + + public com.mogujie.tt.protobuf.IMFile.IMFileState buildPartial() { + com.mogujie.tt.protobuf.IMFile.IMFileState result = new com.mogujie.tt.protobuf.IMFile.IMFileState(this); + int from_bitField0_ = bitField0_; + int to_bitField0_ = 0; + if (((from_bitField0_ & 0x00000001) == 0x00000001)) { + to_bitField0_ |= 0x00000001; + } + result.state_ = state_; + if (((from_bitField0_ & 0x00000002) == 0x00000002)) { + to_bitField0_ |= 0x00000002; + } + result.taskId_ = taskId_; + if (((from_bitField0_ & 0x00000004) == 0x00000004)) { + to_bitField0_ |= 0x00000004; + } + result.userId_ = userId_; + result.bitField0_ = to_bitField0_; + return result; + } + + public Builder mergeFrom(com.mogujie.tt.protobuf.IMFile.IMFileState other) { + if (other == com.mogujie.tt.protobuf.IMFile.IMFileState.getDefaultInstance()) return this; + if (other.hasState()) { + setState(other.getState()); + } + if (other.hasTaskId()) { + bitField0_ |= 0x00000002; + taskId_ = other.taskId_; + + } + if (other.hasUserId()) { + setUserId(other.getUserId()); + } + setUnknownFields( + getUnknownFields().concat(other.unknownFields)); + return this; + } + + public final boolean isInitialized() { + if (!hasState()) { + + return false; + } + if (!hasTaskId()) { + + return false; + } + if (!hasUserId()) { + + return false; + } + return true; + } + + public Builder mergeFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + com.mogujie.tt.protobuf.IMFile.IMFileState parsedMessage = null; + try { + parsedMessage = PARSER.parsePartialFrom(input, extensionRegistry); + } catch (com.google.protobuf.InvalidProtocolBufferException e) { + parsedMessage = (com.mogujie.tt.protobuf.IMFile.IMFileState) e.getUnfinishedMessage(); + throw e; + } finally { + if (parsedMessage != null) { + mergeFrom(parsedMessage); + } + } + return this; + } + private int bitField0_; + + private com.mogujie.tt.protobuf.IMBaseDefine.ClientFileState state_ = com.mogujie.tt.protobuf.IMBaseDefine.ClientFileState.CLIENT_FILE_PEER_READY; + /** + * required .IM.BaseDefine.ClientFileState state = 1; + * + *
+       *cmd id: 	0x0503
+       * 
+ */ + public boolean hasState() { + return ((bitField0_ & 0x00000001) == 0x00000001); + } + /** + * required .IM.BaseDefine.ClientFileState state = 1; + * + *
+       *cmd id: 	0x0503
+       * 
+ */ + public com.mogujie.tt.protobuf.IMBaseDefine.ClientFileState getState() { + return state_; + } + /** + * required .IM.BaseDefine.ClientFileState state = 1; + * + *
+       *cmd id: 	0x0503
+       * 
+ */ + public Builder setState(com.mogujie.tt.protobuf.IMBaseDefine.ClientFileState value) { + if (value == null) { + throw new NullPointerException(); + } + bitField0_ |= 0x00000001; + state_ = value; + + return this; + } + /** + * required .IM.BaseDefine.ClientFileState state = 1; + * + *
+       *cmd id: 	0x0503
+       * 
+ */ + public Builder clearState() { + bitField0_ = (bitField0_ & ~0x00000001); + state_ = com.mogujie.tt.protobuf.IMBaseDefine.ClientFileState.CLIENT_FILE_PEER_READY; + + return this; + } + + private java.lang.Object taskId_ = ""; + /** + * required string task_id = 2; + */ + public boolean hasTaskId() { + return ((bitField0_ & 0x00000002) == 0x00000002); + } + /** + * required string task_id = 2; + */ + public java.lang.String getTaskId() { + java.lang.Object ref = taskId_; + if (!(ref instanceof java.lang.String)) { + com.google.protobuf.ByteString bs = + (com.google.protobuf.ByteString) ref; + java.lang.String s = bs.toStringUtf8(); + if (bs.isValidUtf8()) { + taskId_ = s; + } + return s; + } else { + return (java.lang.String) ref; + } + } + /** + * required string task_id = 2; + */ + public com.google.protobuf.ByteString + getTaskIdBytes() { + java.lang.Object ref = taskId_; + if (ref instanceof String) { + com.google.protobuf.ByteString b = + com.google.protobuf.ByteString.copyFromUtf8( + (java.lang.String) ref); + taskId_ = b; + return b; + } else { + return (com.google.protobuf.ByteString) ref; + } + } + /** + * required string task_id = 2; + */ + public Builder setTaskId( + java.lang.String value) { + if (value == null) { + throw new NullPointerException(); + } + bitField0_ |= 0x00000002; + taskId_ = value; + + return this; + } + /** + * required string task_id = 2; + */ + public Builder clearTaskId() { + bitField0_ = (bitField0_ & ~0x00000002); + taskId_ = getDefaultInstance().getTaskId(); + + return this; + } + /** + * required string task_id = 2; + */ + public Builder setTaskIdBytes( + com.google.protobuf.ByteString value) { + if (value == null) { + throw new NullPointerException(); + } + bitField0_ |= 0x00000002; + taskId_ = value; + + return this; + } + + private int userId_ ; + /** + * required uint32 user_id = 3; + */ + public boolean hasUserId() { + return ((bitField0_ & 0x00000004) == 0x00000004); + } + /** + * required uint32 user_id = 3; + */ + public int getUserId() { + return userId_; + } + /** + * required uint32 user_id = 3; + */ + public Builder setUserId(int value) { + bitField0_ |= 0x00000004; + userId_ = value; + + return this; + } + /** + * required uint32 user_id = 3; + */ + public Builder clearUserId() { + bitField0_ = (bitField0_ & ~0x00000004); + userId_ = 0; + + return this; + } + + // @@protoc_insertion_point(builder_scope:IM.File.IMFileState) + } + + static { + defaultInstance = new IMFileState(true); + defaultInstance.initFields(); + } + + // @@protoc_insertion_point(class_scope:IM.File.IMFileState) + } + + public interface IMFilePullDataReqOrBuilder extends + // @@protoc_insertion_point(interface_extends:IM.File.IMFilePullDataReq) + com.google.protobuf.MessageLiteOrBuilder { + + /** + * required string task_id = 1; + * + *
+     *cmd id:	0x0504
+     * 
+ */ + boolean hasTaskId(); + /** + * required string task_id = 1; + * + *
+     *cmd id:	0x0504
+     * 
+ */ + java.lang.String getTaskId(); + /** + * required string task_id = 1; + * + *
+     *cmd id:	0x0504
+     * 
+ */ + com.google.protobuf.ByteString + getTaskIdBytes(); + + /** + * required uint32 user_id = 2; + */ + boolean hasUserId(); + /** + * required uint32 user_id = 2; + */ + int getUserId(); + + /** + * required .IM.BaseDefine.FileType trans_mode = 3; + */ + boolean hasTransMode(); + /** + * required .IM.BaseDefine.FileType trans_mode = 3; + */ + com.mogujie.tt.protobuf.IMBaseDefine.FileType getTransMode(); + + /** + * required uint32 offset = 4; + */ + boolean hasOffset(); + /** + * required uint32 offset = 4; + */ + int getOffset(); + + /** + * required uint32 data_size = 5; + */ + boolean hasDataSize(); + /** + * required uint32 data_size = 5; + */ + int getDataSize(); + } + /** + * Protobuf type {@code IM.File.IMFilePullDataReq} + */ + public static final class IMFilePullDataReq extends + com.google.protobuf.GeneratedMessageLite implements + // @@protoc_insertion_point(message_implements:IM.File.IMFilePullDataReq) + IMFilePullDataReqOrBuilder { + // Use IMFilePullDataReq.newBuilder() to construct. + private IMFilePullDataReq(com.google.protobuf.GeneratedMessageLite.Builder builder) { + super(builder); + this.unknownFields = builder.getUnknownFields(); + } + private IMFilePullDataReq(boolean noInit) { this.unknownFields = com.google.protobuf.ByteString.EMPTY;} + + private static final IMFilePullDataReq defaultInstance; + public static IMFilePullDataReq getDefaultInstance() { + return defaultInstance; + } + + public IMFilePullDataReq getDefaultInstanceForType() { + return defaultInstance; + } + + private final com.google.protobuf.ByteString unknownFields; + private IMFilePullDataReq( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + initFields(); + int mutable_bitField0_ = 0; + com.google.protobuf.ByteString.Output unknownFieldsOutput = + com.google.protobuf.ByteString.newOutput(); + com.google.protobuf.CodedOutputStream unknownFieldsCodedOutput = + com.google.protobuf.CodedOutputStream.newInstance( + unknownFieldsOutput); + try { + boolean done = false; + while (!done) { + int tag = input.readTag(); + switch (tag) { + case 0: + done = true; + break; + default: { + if (!parseUnknownField(input, unknownFieldsCodedOutput, + extensionRegistry, tag)) { + done = true; + } + break; + } + case 10: { + com.google.protobuf.ByteString bs = input.readBytes(); + bitField0_ |= 0x00000001; + taskId_ = bs; + break; + } + case 16: { + bitField0_ |= 0x00000002; + userId_ = input.readUInt32(); + break; + } + case 24: { + int rawValue = input.readEnum(); + com.mogujie.tt.protobuf.IMBaseDefine.FileType value = com.mogujie.tt.protobuf.IMBaseDefine.FileType.valueOf(rawValue); + if (value == null) { + unknownFieldsCodedOutput.writeRawVarint32(tag); + unknownFieldsCodedOutput.writeRawVarint32(rawValue); + } else { + bitField0_ |= 0x00000004; + transMode_ = value; + } + break; + } + case 32: { + bitField0_ |= 0x00000008; + offset_ = input.readUInt32(); + break; + } + case 40: { + bitField0_ |= 0x00000010; + dataSize_ = input.readUInt32(); + break; + } + } + } + } catch (com.google.protobuf.InvalidProtocolBufferException e) { + throw e.setUnfinishedMessage(this); + } catch (java.io.IOException e) { + throw new com.google.protobuf.InvalidProtocolBufferException( + e.getMessage()).setUnfinishedMessage(this); + } finally { + try { + unknownFieldsCodedOutput.flush(); + } catch (java.io.IOException e) { + // Should not happen + } finally { + unknownFields = unknownFieldsOutput.toByteString(); + } + makeExtensionsImmutable(); + } + } + public static com.google.protobuf.Parser PARSER = + new com.google.protobuf.AbstractParser() { + public IMFilePullDataReq parsePartialFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return new IMFilePullDataReq(input, extensionRegistry); + } + }; + + @java.lang.Override + public com.google.protobuf.Parser getParserForType() { + return PARSER; + } + + private int bitField0_; + public static final int TASK_ID_FIELD_NUMBER = 1; + private java.lang.Object taskId_; + /** + * required string task_id = 1; + * + *
+     *cmd id:	0x0504
+     * 
+ */ + public boolean hasTaskId() { + return ((bitField0_ & 0x00000001) == 0x00000001); + } + /** + * required string task_id = 1; + * + *
+     *cmd id:	0x0504
+     * 
+ */ + public java.lang.String getTaskId() { + java.lang.Object ref = taskId_; + if (ref instanceof java.lang.String) { + return (java.lang.String) ref; + } else { + com.google.protobuf.ByteString bs = + (com.google.protobuf.ByteString) ref; + java.lang.String s = bs.toStringUtf8(); + if (bs.isValidUtf8()) { + taskId_ = s; + } + return s; + } + } + /** + * required string task_id = 1; + * + *
+     *cmd id:	0x0504
+     * 
+ */ + public com.google.protobuf.ByteString + getTaskIdBytes() { + java.lang.Object ref = taskId_; + if (ref instanceof java.lang.String) { + com.google.protobuf.ByteString b = + com.google.protobuf.ByteString.copyFromUtf8( + (java.lang.String) ref); + taskId_ = b; + return b; + } else { + return (com.google.protobuf.ByteString) ref; + } + } + + public static final int USER_ID_FIELD_NUMBER = 2; + private int userId_; + /** + * required uint32 user_id = 2; + */ + public boolean hasUserId() { + return ((bitField0_ & 0x00000002) == 0x00000002); + } + /** + * required uint32 user_id = 2; + */ + public int getUserId() { + return userId_; + } + + public static final int TRANS_MODE_FIELD_NUMBER = 3; + private com.mogujie.tt.protobuf.IMBaseDefine.FileType transMode_; + /** + * required .IM.BaseDefine.FileType trans_mode = 3; + */ + public boolean hasTransMode() { + return ((bitField0_ & 0x00000004) == 0x00000004); + } + /** + * required .IM.BaseDefine.FileType trans_mode = 3; + */ + public com.mogujie.tt.protobuf.IMBaseDefine.FileType getTransMode() { + return transMode_; + } + + public static final int OFFSET_FIELD_NUMBER = 4; + private int offset_; + /** + * required uint32 offset = 4; + */ + public boolean hasOffset() { + return ((bitField0_ & 0x00000008) == 0x00000008); + } + /** + * required uint32 offset = 4; + */ + public int getOffset() { + return offset_; + } + + public static final int DATA_SIZE_FIELD_NUMBER = 5; + private int dataSize_; + /** + * required uint32 data_size = 5; + */ + public boolean hasDataSize() { + return ((bitField0_ & 0x00000010) == 0x00000010); + } + /** + * required uint32 data_size = 5; + */ + public int getDataSize() { + return dataSize_; + } + + private void initFields() { + taskId_ = ""; + userId_ = 0; + transMode_ = com.mogujie.tt.protobuf.IMBaseDefine.FileType.FILE_TYPE_ONLINE; + offset_ = 0; + dataSize_ = 0; + } + private byte memoizedIsInitialized = -1; + public final boolean isInitialized() { + byte isInitialized = memoizedIsInitialized; + if (isInitialized == 1) return true; + if (isInitialized == 0) return false; + + if (!hasTaskId()) { + memoizedIsInitialized = 0; + return false; + } + if (!hasUserId()) { + memoizedIsInitialized = 0; + return false; + } + if (!hasTransMode()) { + memoizedIsInitialized = 0; + return false; + } + if (!hasOffset()) { + memoizedIsInitialized = 0; + return false; + } + if (!hasDataSize()) { + memoizedIsInitialized = 0; + return false; + } + memoizedIsInitialized = 1; + return true; + } + + public void writeTo(com.google.protobuf.CodedOutputStream output) + throws java.io.IOException { + getSerializedSize(); + if (((bitField0_ & 0x00000001) == 0x00000001)) { + output.writeBytes(1, getTaskIdBytes()); + } + if (((bitField0_ & 0x00000002) == 0x00000002)) { + output.writeUInt32(2, userId_); + } + if (((bitField0_ & 0x00000004) == 0x00000004)) { + output.writeEnum(3, transMode_.getNumber()); + } + if (((bitField0_ & 0x00000008) == 0x00000008)) { + output.writeUInt32(4, offset_); + } + if (((bitField0_ & 0x00000010) == 0x00000010)) { + output.writeUInt32(5, dataSize_); + } + output.writeRawBytes(unknownFields); + } + + private int memoizedSerializedSize = -1; + public int getSerializedSize() { + int size = memoizedSerializedSize; + if (size != -1) return size; + + size = 0; + if (((bitField0_ & 0x00000001) == 0x00000001)) { + size += com.google.protobuf.CodedOutputStream + .computeBytesSize(1, getTaskIdBytes()); + } + if (((bitField0_ & 0x00000002) == 0x00000002)) { + size += com.google.protobuf.CodedOutputStream + .computeUInt32Size(2, userId_); + } + if (((bitField0_ & 0x00000004) == 0x00000004)) { + size += com.google.protobuf.CodedOutputStream + .computeEnumSize(3, transMode_.getNumber()); + } + if (((bitField0_ & 0x00000008) == 0x00000008)) { + size += com.google.protobuf.CodedOutputStream + .computeUInt32Size(4, offset_); + } + if (((bitField0_ & 0x00000010) == 0x00000010)) { + size += com.google.protobuf.CodedOutputStream + .computeUInt32Size(5, dataSize_); + } + size += unknownFields.size(); + memoizedSerializedSize = size; + return size; + } + + private static final long serialVersionUID = 0L; + @java.lang.Override + protected java.lang.Object writeReplace() + throws java.io.ObjectStreamException { + return super.writeReplace(); + } + + public static com.mogujie.tt.protobuf.IMFile.IMFilePullDataReq parseFrom( + com.google.protobuf.ByteString data) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data); + } + public static com.mogujie.tt.protobuf.IMFile.IMFilePullDataReq parseFrom( + com.google.protobuf.ByteString data, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data, extensionRegistry); + } + public static com.mogujie.tt.protobuf.IMFile.IMFilePullDataReq parseFrom(byte[] data) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data); + } + public static com.mogujie.tt.protobuf.IMFile.IMFilePullDataReq parseFrom( + byte[] data, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data, extensionRegistry); + } + public static com.mogujie.tt.protobuf.IMFile.IMFilePullDataReq parseFrom(java.io.InputStream input) + throws java.io.IOException { + return PARSER.parseFrom(input); + } + public static com.mogujie.tt.protobuf.IMFile.IMFilePullDataReq parseFrom( + java.io.InputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return PARSER.parseFrom(input, extensionRegistry); + } + public static com.mogujie.tt.protobuf.IMFile.IMFilePullDataReq parseDelimitedFrom(java.io.InputStream input) + throws java.io.IOException { + return PARSER.parseDelimitedFrom(input); + } + public static com.mogujie.tt.protobuf.IMFile.IMFilePullDataReq parseDelimitedFrom( + java.io.InputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return PARSER.parseDelimitedFrom(input, extensionRegistry); + } + public static com.mogujie.tt.protobuf.IMFile.IMFilePullDataReq parseFrom( + com.google.protobuf.CodedInputStream input) + throws java.io.IOException { + return PARSER.parseFrom(input); + } + public static com.mogujie.tt.protobuf.IMFile.IMFilePullDataReq parseFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return PARSER.parseFrom(input, extensionRegistry); + } + + public static Builder newBuilder() { return Builder.create(); } + public Builder newBuilderForType() { return newBuilder(); } + public static Builder newBuilder(com.mogujie.tt.protobuf.IMFile.IMFilePullDataReq prototype) { + return newBuilder().mergeFrom(prototype); + } + public Builder toBuilder() { return newBuilder(this); } + + /** + * Protobuf type {@code IM.File.IMFilePullDataReq} + */ + public static final class Builder extends + com.google.protobuf.GeneratedMessageLite.Builder< + com.mogujie.tt.protobuf.IMFile.IMFilePullDataReq, Builder> + implements + // @@protoc_insertion_point(builder_implements:IM.File.IMFilePullDataReq) + com.mogujie.tt.protobuf.IMFile.IMFilePullDataReqOrBuilder { + // Construct using com.mogujie.tt.protobuf.IMFile.IMFilePullDataReq.newBuilder() + private Builder() { + maybeForceBuilderInitialization(); + } + + private void maybeForceBuilderInitialization() { + } + private static Builder create() { + return new Builder(); + } + + public Builder clear() { + super.clear(); + taskId_ = ""; + bitField0_ = (bitField0_ & ~0x00000001); + userId_ = 0; + bitField0_ = (bitField0_ & ~0x00000002); + transMode_ = com.mogujie.tt.protobuf.IMBaseDefine.FileType.FILE_TYPE_ONLINE; + bitField0_ = (bitField0_ & ~0x00000004); + offset_ = 0; + bitField0_ = (bitField0_ & ~0x00000008); + dataSize_ = 0; + bitField0_ = (bitField0_ & ~0x00000010); + return this; + } + + public Builder clone() { + return create().mergeFrom(buildPartial()); + } + + public com.mogujie.tt.protobuf.IMFile.IMFilePullDataReq getDefaultInstanceForType() { + return com.mogujie.tt.protobuf.IMFile.IMFilePullDataReq.getDefaultInstance(); + } + + public com.mogujie.tt.protobuf.IMFile.IMFilePullDataReq build() { + com.mogujie.tt.protobuf.IMFile.IMFilePullDataReq result = buildPartial(); + if (!result.isInitialized()) { + throw newUninitializedMessageException(result); + } + return result; + } + + public com.mogujie.tt.protobuf.IMFile.IMFilePullDataReq buildPartial() { + com.mogujie.tt.protobuf.IMFile.IMFilePullDataReq result = new com.mogujie.tt.protobuf.IMFile.IMFilePullDataReq(this); + int from_bitField0_ = bitField0_; + int to_bitField0_ = 0; + if (((from_bitField0_ & 0x00000001) == 0x00000001)) { + to_bitField0_ |= 0x00000001; + } + result.taskId_ = taskId_; + if (((from_bitField0_ & 0x00000002) == 0x00000002)) { + to_bitField0_ |= 0x00000002; + } + result.userId_ = userId_; + if (((from_bitField0_ & 0x00000004) == 0x00000004)) { + to_bitField0_ |= 0x00000004; + } + result.transMode_ = transMode_; + if (((from_bitField0_ & 0x00000008) == 0x00000008)) { + to_bitField0_ |= 0x00000008; + } + result.offset_ = offset_; + if (((from_bitField0_ & 0x00000010) == 0x00000010)) { + to_bitField0_ |= 0x00000010; + } + result.dataSize_ = dataSize_; + result.bitField0_ = to_bitField0_; + return result; + } + + public Builder mergeFrom(com.mogujie.tt.protobuf.IMFile.IMFilePullDataReq other) { + if (other == com.mogujie.tt.protobuf.IMFile.IMFilePullDataReq.getDefaultInstance()) return this; + if (other.hasTaskId()) { + bitField0_ |= 0x00000001; + taskId_ = other.taskId_; + + } + if (other.hasUserId()) { + setUserId(other.getUserId()); + } + if (other.hasTransMode()) { + setTransMode(other.getTransMode()); + } + if (other.hasOffset()) { + setOffset(other.getOffset()); + } + if (other.hasDataSize()) { + setDataSize(other.getDataSize()); + } + setUnknownFields( + getUnknownFields().concat(other.unknownFields)); + return this; + } + + public final boolean isInitialized() { + if (!hasTaskId()) { + + return false; + } + if (!hasUserId()) { + + return false; + } + if (!hasTransMode()) { + + return false; + } + if (!hasOffset()) { + + return false; + } + if (!hasDataSize()) { + + return false; + } + return true; + } + + public Builder mergeFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + com.mogujie.tt.protobuf.IMFile.IMFilePullDataReq parsedMessage = null; + try { + parsedMessage = PARSER.parsePartialFrom(input, extensionRegistry); + } catch (com.google.protobuf.InvalidProtocolBufferException e) { + parsedMessage = (com.mogujie.tt.protobuf.IMFile.IMFilePullDataReq) e.getUnfinishedMessage(); + throw e; + } finally { + if (parsedMessage != null) { + mergeFrom(parsedMessage); + } + } + return this; + } + private int bitField0_; + + private java.lang.Object taskId_ = ""; + /** + * required string task_id = 1; + * + *
+       *cmd id:	0x0504
+       * 
+ */ + public boolean hasTaskId() { + return ((bitField0_ & 0x00000001) == 0x00000001); + } + /** + * required string task_id = 1; + * + *
+       *cmd id:	0x0504
+       * 
+ */ + public java.lang.String getTaskId() { + java.lang.Object ref = taskId_; + if (!(ref instanceof java.lang.String)) { + com.google.protobuf.ByteString bs = + (com.google.protobuf.ByteString) ref; + java.lang.String s = bs.toStringUtf8(); + if (bs.isValidUtf8()) { + taskId_ = s; + } + return s; + } else { + return (java.lang.String) ref; + } + } + /** + * required string task_id = 1; + * + *
+       *cmd id:	0x0504
+       * 
+ */ + public com.google.protobuf.ByteString + getTaskIdBytes() { + java.lang.Object ref = taskId_; + if (ref instanceof String) { + com.google.protobuf.ByteString b = + com.google.protobuf.ByteString.copyFromUtf8( + (java.lang.String) ref); + taskId_ = b; + return b; + } else { + return (com.google.protobuf.ByteString) ref; + } + } + /** + * required string task_id = 1; + * + *
+       *cmd id:	0x0504
+       * 
+ */ + public Builder setTaskId( + java.lang.String value) { + if (value == null) { + throw new NullPointerException(); + } + bitField0_ |= 0x00000001; + taskId_ = value; + + return this; + } + /** + * required string task_id = 1; + * + *
+       *cmd id:	0x0504
+       * 
+ */ + public Builder clearTaskId() { + bitField0_ = (bitField0_ & ~0x00000001); + taskId_ = getDefaultInstance().getTaskId(); + + return this; + } + /** + * required string task_id = 1; + * + *
+       *cmd id:	0x0504
+       * 
+ */ + public Builder setTaskIdBytes( + com.google.protobuf.ByteString value) { + if (value == null) { + throw new NullPointerException(); + } + bitField0_ |= 0x00000001; + taskId_ = value; + + return this; + } + + private int userId_ ; + /** + * required uint32 user_id = 2; + */ + public boolean hasUserId() { + return ((bitField0_ & 0x00000002) == 0x00000002); + } + /** + * required uint32 user_id = 2; + */ + public int getUserId() { + return userId_; + } + /** + * required uint32 user_id = 2; + */ + public Builder setUserId(int value) { + bitField0_ |= 0x00000002; + userId_ = value; + + return this; + } + /** + * required uint32 user_id = 2; + */ + public Builder clearUserId() { + bitField0_ = (bitField0_ & ~0x00000002); + userId_ = 0; + + return this; + } + + private com.mogujie.tt.protobuf.IMBaseDefine.FileType transMode_ = com.mogujie.tt.protobuf.IMBaseDefine.FileType.FILE_TYPE_ONLINE; + /** + * required .IM.BaseDefine.FileType trans_mode = 3; + */ + public boolean hasTransMode() { + return ((bitField0_ & 0x00000004) == 0x00000004); + } + /** + * required .IM.BaseDefine.FileType trans_mode = 3; + */ + public com.mogujie.tt.protobuf.IMBaseDefine.FileType getTransMode() { + return transMode_; + } + /** + * required .IM.BaseDefine.FileType trans_mode = 3; + */ + public Builder setTransMode(com.mogujie.tt.protobuf.IMBaseDefine.FileType value) { + if (value == null) { + throw new NullPointerException(); + } + bitField0_ |= 0x00000004; + transMode_ = value; + + return this; + } + /** + * required .IM.BaseDefine.FileType trans_mode = 3; + */ + public Builder clearTransMode() { + bitField0_ = (bitField0_ & ~0x00000004); + transMode_ = com.mogujie.tt.protobuf.IMBaseDefine.FileType.FILE_TYPE_ONLINE; + + return this; + } + + private int offset_ ; + /** + * required uint32 offset = 4; + */ + public boolean hasOffset() { + return ((bitField0_ & 0x00000008) == 0x00000008); + } + /** + * required uint32 offset = 4; + */ + public int getOffset() { + return offset_; + } + /** + * required uint32 offset = 4; + */ + public Builder setOffset(int value) { + bitField0_ |= 0x00000008; + offset_ = value; + + return this; + } + /** + * required uint32 offset = 4; + */ + public Builder clearOffset() { + bitField0_ = (bitField0_ & ~0x00000008); + offset_ = 0; + + return this; + } + + private int dataSize_ ; + /** + * required uint32 data_size = 5; + */ + public boolean hasDataSize() { + return ((bitField0_ & 0x00000010) == 0x00000010); + } + /** + * required uint32 data_size = 5; + */ + public int getDataSize() { + return dataSize_; + } + /** + * required uint32 data_size = 5; + */ + public Builder setDataSize(int value) { + bitField0_ |= 0x00000010; + dataSize_ = value; + + return this; + } + /** + * required uint32 data_size = 5; + */ + public Builder clearDataSize() { + bitField0_ = (bitField0_ & ~0x00000010); + dataSize_ = 0; + + return this; + } + + // @@protoc_insertion_point(builder_scope:IM.File.IMFilePullDataReq) + } + + static { + defaultInstance = new IMFilePullDataReq(true); + defaultInstance.initFields(); + } + + // @@protoc_insertion_point(class_scope:IM.File.IMFilePullDataReq) + } + + public interface IMFilePullDataRspOrBuilder extends + // @@protoc_insertion_point(interface_extends:IM.File.IMFilePullDataRsp) + com.google.protobuf.MessageLiteOrBuilder { + + /** + * required uint32 result_code = 1; + * + *
+     *cmd id: 	0x0505
+     * 
+ */ + boolean hasResultCode(); + /** + * required uint32 result_code = 1; + * + *
+     *cmd id: 	0x0505
+     * 
+ */ + int getResultCode(); + + /** + * required string task_id = 2; + */ + boolean hasTaskId(); + /** + * required string task_id = 2; + */ + java.lang.String getTaskId(); + /** + * required string task_id = 2; + */ + com.google.protobuf.ByteString + getTaskIdBytes(); + + /** + * required uint32 user_id = 3; + */ + boolean hasUserId(); + /** + * required uint32 user_id = 3; + */ + int getUserId(); + + /** + * required uint32 offset = 4; + */ + boolean hasOffset(); + /** + * required uint32 offset = 4; + */ + int getOffset(); + + /** + * required bytes data = 5; + */ + boolean hasData(); + /** + * required bytes data = 5; + */ + com.google.protobuf.ByteString getData(); + } + /** + * Protobuf type {@code IM.File.IMFilePullDataRsp} + */ + public static final class IMFilePullDataRsp extends + com.google.protobuf.GeneratedMessageLite implements + // @@protoc_insertion_point(message_implements:IM.File.IMFilePullDataRsp) + IMFilePullDataRspOrBuilder { + // Use IMFilePullDataRsp.newBuilder() to construct. + private IMFilePullDataRsp(com.google.protobuf.GeneratedMessageLite.Builder builder) { + super(builder); + this.unknownFields = builder.getUnknownFields(); + } + private IMFilePullDataRsp(boolean noInit) { this.unknownFields = com.google.protobuf.ByteString.EMPTY;} + + private static final IMFilePullDataRsp defaultInstance; + public static IMFilePullDataRsp getDefaultInstance() { + return defaultInstance; + } + + public IMFilePullDataRsp getDefaultInstanceForType() { + return defaultInstance; + } + + private final com.google.protobuf.ByteString unknownFields; + private IMFilePullDataRsp( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + initFields(); + int mutable_bitField0_ = 0; + com.google.protobuf.ByteString.Output unknownFieldsOutput = + com.google.protobuf.ByteString.newOutput(); + com.google.protobuf.CodedOutputStream unknownFieldsCodedOutput = + com.google.protobuf.CodedOutputStream.newInstance( + unknownFieldsOutput); + try { + boolean done = false; + while (!done) { + int tag = input.readTag(); + switch (tag) { + case 0: + done = true; + break; + default: { + if (!parseUnknownField(input, unknownFieldsCodedOutput, + extensionRegistry, tag)) { + done = true; + } + break; + } + case 8: { + bitField0_ |= 0x00000001; + resultCode_ = input.readUInt32(); + break; + } + case 18: { + com.google.protobuf.ByteString bs = input.readBytes(); + bitField0_ |= 0x00000002; + taskId_ = bs; + break; + } + case 24: { + bitField0_ |= 0x00000004; + userId_ = input.readUInt32(); + break; + } + case 32: { + bitField0_ |= 0x00000008; + offset_ = input.readUInt32(); + break; + } + case 42: { + bitField0_ |= 0x00000010; + data_ = input.readBytes(); + break; + } + } + } + } catch (com.google.protobuf.InvalidProtocolBufferException e) { + throw e.setUnfinishedMessage(this); + } catch (java.io.IOException e) { + throw new com.google.protobuf.InvalidProtocolBufferException( + e.getMessage()).setUnfinishedMessage(this); + } finally { + try { + unknownFieldsCodedOutput.flush(); + } catch (java.io.IOException e) { + // Should not happen + } finally { + unknownFields = unknownFieldsOutput.toByteString(); + } + makeExtensionsImmutable(); + } + } + public static com.google.protobuf.Parser PARSER = + new com.google.protobuf.AbstractParser() { + public IMFilePullDataRsp parsePartialFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return new IMFilePullDataRsp(input, extensionRegistry); + } + }; + + @java.lang.Override + public com.google.protobuf.Parser getParserForType() { + return PARSER; + } + + private int bitField0_; + public static final int RESULT_CODE_FIELD_NUMBER = 1; + private int resultCode_; + /** + * required uint32 result_code = 1; + * + *
+     *cmd id: 	0x0505
+     * 
+ */ + public boolean hasResultCode() { + return ((bitField0_ & 0x00000001) == 0x00000001); + } + /** + * required uint32 result_code = 1; + * + *
+     *cmd id: 	0x0505
+     * 
+ */ + public int getResultCode() { + return resultCode_; + } + + public static final int TASK_ID_FIELD_NUMBER = 2; + private java.lang.Object taskId_; + /** + * required string task_id = 2; + */ + public boolean hasTaskId() { + return ((bitField0_ & 0x00000002) == 0x00000002); + } + /** + * required string task_id = 2; + */ + public java.lang.String getTaskId() { + java.lang.Object ref = taskId_; + if (ref instanceof java.lang.String) { + return (java.lang.String) ref; + } else { + com.google.protobuf.ByteString bs = + (com.google.protobuf.ByteString) ref; + java.lang.String s = bs.toStringUtf8(); + if (bs.isValidUtf8()) { + taskId_ = s; + } + return s; + } + } + /** + * required string task_id = 2; + */ + public com.google.protobuf.ByteString + getTaskIdBytes() { + java.lang.Object ref = taskId_; + if (ref instanceof java.lang.String) { + com.google.protobuf.ByteString b = + com.google.protobuf.ByteString.copyFromUtf8( + (java.lang.String) ref); + taskId_ = b; + return b; + } else { + return (com.google.protobuf.ByteString) ref; + } + } + + public static final int USER_ID_FIELD_NUMBER = 3; + private int userId_; + /** + * required uint32 user_id = 3; + */ + public boolean hasUserId() { + return ((bitField0_ & 0x00000004) == 0x00000004); + } + /** + * required uint32 user_id = 3; + */ + public int getUserId() { + return userId_; + } + + public static final int OFFSET_FIELD_NUMBER = 4; + private int offset_; + /** + * required uint32 offset = 4; + */ + public boolean hasOffset() { + return ((bitField0_ & 0x00000008) == 0x00000008); + } + /** + * required uint32 offset = 4; + */ + public int getOffset() { + return offset_; + } + + public static final int DATA_FIELD_NUMBER = 5; + private com.google.protobuf.ByteString data_; + /** + * required bytes data = 5; + */ + public boolean hasData() { + return ((bitField0_ & 0x00000010) == 0x00000010); + } + /** + * required bytes data = 5; + */ + public com.google.protobuf.ByteString getData() { + return data_; + } + + private void initFields() { + resultCode_ = 0; + taskId_ = ""; + userId_ = 0; + offset_ = 0; + data_ = com.google.protobuf.ByteString.EMPTY; + } + private byte memoizedIsInitialized = -1; + public final boolean isInitialized() { + byte isInitialized = memoizedIsInitialized; + if (isInitialized == 1) return true; + if (isInitialized == 0) return false; + + if (!hasResultCode()) { + memoizedIsInitialized = 0; + return false; + } + if (!hasTaskId()) { + memoizedIsInitialized = 0; + return false; + } + if (!hasUserId()) { + memoizedIsInitialized = 0; + return false; + } + if (!hasOffset()) { + memoizedIsInitialized = 0; + return false; + } + if (!hasData()) { + memoizedIsInitialized = 0; + return false; + } + memoizedIsInitialized = 1; + return true; + } + + public void writeTo(com.google.protobuf.CodedOutputStream output) + throws java.io.IOException { + getSerializedSize(); + if (((bitField0_ & 0x00000001) == 0x00000001)) { + output.writeUInt32(1, resultCode_); + } + if (((bitField0_ & 0x00000002) == 0x00000002)) { + output.writeBytes(2, getTaskIdBytes()); + } + if (((bitField0_ & 0x00000004) == 0x00000004)) { + output.writeUInt32(3, userId_); + } + if (((bitField0_ & 0x00000008) == 0x00000008)) { + output.writeUInt32(4, offset_); + } + if (((bitField0_ & 0x00000010) == 0x00000010)) { + output.writeBytes(5, data_); + } + output.writeRawBytes(unknownFields); + } + + private int memoizedSerializedSize = -1; + public int getSerializedSize() { + int size = memoizedSerializedSize; + if (size != -1) return size; + + size = 0; + if (((bitField0_ & 0x00000001) == 0x00000001)) { + size += com.google.protobuf.CodedOutputStream + .computeUInt32Size(1, resultCode_); + } + if (((bitField0_ & 0x00000002) == 0x00000002)) { + size += com.google.protobuf.CodedOutputStream + .computeBytesSize(2, getTaskIdBytes()); + } + if (((bitField0_ & 0x00000004) == 0x00000004)) { + size += com.google.protobuf.CodedOutputStream + .computeUInt32Size(3, userId_); + } + if (((bitField0_ & 0x00000008) == 0x00000008)) { + size += com.google.protobuf.CodedOutputStream + .computeUInt32Size(4, offset_); + } + if (((bitField0_ & 0x00000010) == 0x00000010)) { + size += com.google.protobuf.CodedOutputStream + .computeBytesSize(5, data_); + } + size += unknownFields.size(); + memoizedSerializedSize = size; + return size; + } + + private static final long serialVersionUID = 0L; + @java.lang.Override + protected java.lang.Object writeReplace() + throws java.io.ObjectStreamException { + return super.writeReplace(); + } + + public static com.mogujie.tt.protobuf.IMFile.IMFilePullDataRsp parseFrom( + com.google.protobuf.ByteString data) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data); + } + public static com.mogujie.tt.protobuf.IMFile.IMFilePullDataRsp parseFrom( + com.google.protobuf.ByteString data, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data, extensionRegistry); + } + public static com.mogujie.tt.protobuf.IMFile.IMFilePullDataRsp parseFrom(byte[] data) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data); + } + public static com.mogujie.tt.protobuf.IMFile.IMFilePullDataRsp parseFrom( + byte[] data, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data, extensionRegistry); + } + public static com.mogujie.tt.protobuf.IMFile.IMFilePullDataRsp parseFrom(java.io.InputStream input) + throws java.io.IOException { + return PARSER.parseFrom(input); + } + public static com.mogujie.tt.protobuf.IMFile.IMFilePullDataRsp parseFrom( + java.io.InputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return PARSER.parseFrom(input, extensionRegistry); + } + public static com.mogujie.tt.protobuf.IMFile.IMFilePullDataRsp parseDelimitedFrom(java.io.InputStream input) + throws java.io.IOException { + return PARSER.parseDelimitedFrom(input); + } + public static com.mogujie.tt.protobuf.IMFile.IMFilePullDataRsp parseDelimitedFrom( + java.io.InputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return PARSER.parseDelimitedFrom(input, extensionRegistry); + } + public static com.mogujie.tt.protobuf.IMFile.IMFilePullDataRsp parseFrom( + com.google.protobuf.CodedInputStream input) + throws java.io.IOException { + return PARSER.parseFrom(input); + } + public static com.mogujie.tt.protobuf.IMFile.IMFilePullDataRsp parseFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return PARSER.parseFrom(input, extensionRegistry); + } + + public static Builder newBuilder() { return Builder.create(); } + public Builder newBuilderForType() { return newBuilder(); } + public static Builder newBuilder(com.mogujie.tt.protobuf.IMFile.IMFilePullDataRsp prototype) { + return newBuilder().mergeFrom(prototype); + } + public Builder toBuilder() { return newBuilder(this); } + + /** + * Protobuf type {@code IM.File.IMFilePullDataRsp} + */ + public static final class Builder extends + com.google.protobuf.GeneratedMessageLite.Builder< + com.mogujie.tt.protobuf.IMFile.IMFilePullDataRsp, Builder> + implements + // @@protoc_insertion_point(builder_implements:IM.File.IMFilePullDataRsp) + com.mogujie.tt.protobuf.IMFile.IMFilePullDataRspOrBuilder { + // Construct using com.mogujie.tt.protobuf.IMFile.IMFilePullDataRsp.newBuilder() + private Builder() { + maybeForceBuilderInitialization(); + } + + private void maybeForceBuilderInitialization() { + } + private static Builder create() { + return new Builder(); + } + + public Builder clear() { + super.clear(); + resultCode_ = 0; + bitField0_ = (bitField0_ & ~0x00000001); + taskId_ = ""; + bitField0_ = (bitField0_ & ~0x00000002); + userId_ = 0; + bitField0_ = (bitField0_ & ~0x00000004); + offset_ = 0; + bitField0_ = (bitField0_ & ~0x00000008); + data_ = com.google.protobuf.ByteString.EMPTY; + bitField0_ = (bitField0_ & ~0x00000010); + return this; + } + + public Builder clone() { + return create().mergeFrom(buildPartial()); + } + + public com.mogujie.tt.protobuf.IMFile.IMFilePullDataRsp getDefaultInstanceForType() { + return com.mogujie.tt.protobuf.IMFile.IMFilePullDataRsp.getDefaultInstance(); + } + + public com.mogujie.tt.protobuf.IMFile.IMFilePullDataRsp build() { + com.mogujie.tt.protobuf.IMFile.IMFilePullDataRsp result = buildPartial(); + if (!result.isInitialized()) { + throw newUninitializedMessageException(result); + } + return result; + } + + public com.mogujie.tt.protobuf.IMFile.IMFilePullDataRsp buildPartial() { + com.mogujie.tt.protobuf.IMFile.IMFilePullDataRsp result = new com.mogujie.tt.protobuf.IMFile.IMFilePullDataRsp(this); + int from_bitField0_ = bitField0_; + int to_bitField0_ = 0; + if (((from_bitField0_ & 0x00000001) == 0x00000001)) { + to_bitField0_ |= 0x00000001; + } + result.resultCode_ = resultCode_; + if (((from_bitField0_ & 0x00000002) == 0x00000002)) { + to_bitField0_ |= 0x00000002; + } + result.taskId_ = taskId_; + if (((from_bitField0_ & 0x00000004) == 0x00000004)) { + to_bitField0_ |= 0x00000004; + } + result.userId_ = userId_; + if (((from_bitField0_ & 0x00000008) == 0x00000008)) { + to_bitField0_ |= 0x00000008; + } + result.offset_ = offset_; + if (((from_bitField0_ & 0x00000010) == 0x00000010)) { + to_bitField0_ |= 0x00000010; + } + result.data_ = data_; + result.bitField0_ = to_bitField0_; + return result; + } + + public Builder mergeFrom(com.mogujie.tt.protobuf.IMFile.IMFilePullDataRsp other) { + if (other == com.mogujie.tt.protobuf.IMFile.IMFilePullDataRsp.getDefaultInstance()) return this; + if (other.hasResultCode()) { + setResultCode(other.getResultCode()); + } + if (other.hasTaskId()) { + bitField0_ |= 0x00000002; + taskId_ = other.taskId_; + + } + if (other.hasUserId()) { + setUserId(other.getUserId()); + } + if (other.hasOffset()) { + setOffset(other.getOffset()); + } + if (other.hasData()) { + setData(other.getData()); + } + setUnknownFields( + getUnknownFields().concat(other.unknownFields)); + return this; + } + + public final boolean isInitialized() { + if (!hasResultCode()) { + + return false; + } + if (!hasTaskId()) { + + return false; + } + if (!hasUserId()) { + + return false; + } + if (!hasOffset()) { + + return false; + } + if (!hasData()) { + + return false; + } + return true; + } + + public Builder mergeFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + com.mogujie.tt.protobuf.IMFile.IMFilePullDataRsp parsedMessage = null; + try { + parsedMessage = PARSER.parsePartialFrom(input, extensionRegistry); + } catch (com.google.protobuf.InvalidProtocolBufferException e) { + parsedMessage = (com.mogujie.tt.protobuf.IMFile.IMFilePullDataRsp) e.getUnfinishedMessage(); + throw e; + } finally { + if (parsedMessage != null) { + mergeFrom(parsedMessage); + } + } + return this; + } + private int bitField0_; + + private int resultCode_ ; + /** + * required uint32 result_code = 1; + * + *
+       *cmd id: 	0x0505
+       * 
+ */ + public boolean hasResultCode() { + return ((bitField0_ & 0x00000001) == 0x00000001); + } + /** + * required uint32 result_code = 1; + * + *
+       *cmd id: 	0x0505
+       * 
+ */ + public int getResultCode() { + return resultCode_; + } + /** + * required uint32 result_code = 1; + * + *
+       *cmd id: 	0x0505
+       * 
+ */ + public Builder setResultCode(int value) { + bitField0_ |= 0x00000001; + resultCode_ = value; + + return this; + } + /** + * required uint32 result_code = 1; + * + *
+       *cmd id: 	0x0505
+       * 
+ */ + public Builder clearResultCode() { + bitField0_ = (bitField0_ & ~0x00000001); + resultCode_ = 0; + + return this; + } + + private java.lang.Object taskId_ = ""; + /** + * required string task_id = 2; + */ + public boolean hasTaskId() { + return ((bitField0_ & 0x00000002) == 0x00000002); + } + /** + * required string task_id = 2; + */ + public java.lang.String getTaskId() { + java.lang.Object ref = taskId_; + if (!(ref instanceof java.lang.String)) { + com.google.protobuf.ByteString bs = + (com.google.protobuf.ByteString) ref; + java.lang.String s = bs.toStringUtf8(); + if (bs.isValidUtf8()) { + taskId_ = s; + } + return s; + } else { + return (java.lang.String) ref; + } + } + /** + * required string task_id = 2; + */ + public com.google.protobuf.ByteString + getTaskIdBytes() { + java.lang.Object ref = taskId_; + if (ref instanceof String) { + com.google.protobuf.ByteString b = + com.google.protobuf.ByteString.copyFromUtf8( + (java.lang.String) ref); + taskId_ = b; + return b; + } else { + return (com.google.protobuf.ByteString) ref; + } + } + /** + * required string task_id = 2; + */ + public Builder setTaskId( + java.lang.String value) { + if (value == null) { + throw new NullPointerException(); + } + bitField0_ |= 0x00000002; + taskId_ = value; + + return this; + } + /** + * required string task_id = 2; + */ + public Builder clearTaskId() { + bitField0_ = (bitField0_ & ~0x00000002); + taskId_ = getDefaultInstance().getTaskId(); + + return this; + } + /** + * required string task_id = 2; + */ + public Builder setTaskIdBytes( + com.google.protobuf.ByteString value) { + if (value == null) { + throw new NullPointerException(); + } + bitField0_ |= 0x00000002; + taskId_ = value; + + return this; + } + + private int userId_ ; + /** + * required uint32 user_id = 3; + */ + public boolean hasUserId() { + return ((bitField0_ & 0x00000004) == 0x00000004); + } + /** + * required uint32 user_id = 3; + */ + public int getUserId() { + return userId_; + } + /** + * required uint32 user_id = 3; + */ + public Builder setUserId(int value) { + bitField0_ |= 0x00000004; + userId_ = value; + + return this; + } + /** + * required uint32 user_id = 3; + */ + public Builder clearUserId() { + bitField0_ = (bitField0_ & ~0x00000004); + userId_ = 0; + + return this; + } + + private int offset_ ; + /** + * required uint32 offset = 4; + */ + public boolean hasOffset() { + return ((bitField0_ & 0x00000008) == 0x00000008); + } + /** + * required uint32 offset = 4; + */ + public int getOffset() { + return offset_; + } + /** + * required uint32 offset = 4; + */ + public Builder setOffset(int value) { + bitField0_ |= 0x00000008; + offset_ = value; + + return this; + } + /** + * required uint32 offset = 4; + */ + public Builder clearOffset() { + bitField0_ = (bitField0_ & ~0x00000008); + offset_ = 0; + + return this; + } + + private com.google.protobuf.ByteString data_ = com.google.protobuf.ByteString.EMPTY; + /** + * required bytes data = 5; + */ + public boolean hasData() { + return ((bitField0_ & 0x00000010) == 0x00000010); + } + /** + * required bytes data = 5; + */ + public com.google.protobuf.ByteString getData() { + return data_; + } + /** + * required bytes data = 5; + */ + public Builder setData(com.google.protobuf.ByteString value) { + if (value == null) { + throw new NullPointerException(); + } + bitField0_ |= 0x00000010; + data_ = value; + + return this; + } + /** + * required bytes data = 5; + */ + public Builder clearData() { + bitField0_ = (bitField0_ & ~0x00000010); + data_ = getDefaultInstance().getData(); + + return this; + } + + // @@protoc_insertion_point(builder_scope:IM.File.IMFilePullDataRsp) + } + + static { + defaultInstance = new IMFilePullDataRsp(true); + defaultInstance.initFields(); + } + + // @@protoc_insertion_point(class_scope:IM.File.IMFilePullDataRsp) + } + + public interface IMFileReqOrBuilder extends + // @@protoc_insertion_point(interface_extends:IM.File.IMFileReq) + com.google.protobuf.MessageLiteOrBuilder { + + /** + * required uint32 from_user_id = 1; + * + *
+     *cmd id: 	0x0506
+     * 
+ */ + boolean hasFromUserId(); + /** + * required uint32 from_user_id = 1; + * + *
+     *cmd id: 	0x0506
+     * 
+ */ + int getFromUserId(); + + /** + * required uint32 to_user_id = 2; + */ + boolean hasToUserId(); + /** + * required uint32 to_user_id = 2; + */ + int getToUserId(); + + /** + * required string file_name = 3; + */ + boolean hasFileName(); + /** + * required string file_name = 3; + */ + java.lang.String getFileName(); + /** + * required string file_name = 3; + */ + com.google.protobuf.ByteString + getFileNameBytes(); + + /** + * required uint32 file_size = 4; + */ + boolean hasFileSize(); + /** + * required uint32 file_size = 4; + */ + int getFileSize(); + + /** + * required .IM.BaseDefine.FileType trans_mode = 5; + */ + boolean hasTransMode(); + /** + * required .IM.BaseDefine.FileType trans_mode = 5; + */ + com.mogujie.tt.protobuf.IMBaseDefine.FileType getTransMode(); + } + /** + * Protobuf type {@code IM.File.IMFileReq} + */ + public static final class IMFileReq extends + com.google.protobuf.GeneratedMessageLite implements + // @@protoc_insertion_point(message_implements:IM.File.IMFileReq) + IMFileReqOrBuilder { + // Use IMFileReq.newBuilder() to construct. + private IMFileReq(com.google.protobuf.GeneratedMessageLite.Builder builder) { + super(builder); + this.unknownFields = builder.getUnknownFields(); + } + private IMFileReq(boolean noInit) { this.unknownFields = com.google.protobuf.ByteString.EMPTY;} + + private static final IMFileReq defaultInstance; + public static IMFileReq getDefaultInstance() { + return defaultInstance; + } + + public IMFileReq getDefaultInstanceForType() { + return defaultInstance; + } + + private final com.google.protobuf.ByteString unknownFields; + private IMFileReq( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + initFields(); + int mutable_bitField0_ = 0; + com.google.protobuf.ByteString.Output unknownFieldsOutput = + com.google.protobuf.ByteString.newOutput(); + com.google.protobuf.CodedOutputStream unknownFieldsCodedOutput = + com.google.protobuf.CodedOutputStream.newInstance( + unknownFieldsOutput); + try { + boolean done = false; + while (!done) { + int tag = input.readTag(); + switch (tag) { + case 0: + done = true; + break; + default: { + if (!parseUnknownField(input, unknownFieldsCodedOutput, + extensionRegistry, tag)) { + done = true; + } + break; + } + case 8: { + bitField0_ |= 0x00000001; + fromUserId_ = input.readUInt32(); + break; + } + case 16: { + bitField0_ |= 0x00000002; + toUserId_ = input.readUInt32(); + break; + } + case 26: { + com.google.protobuf.ByteString bs = input.readBytes(); + bitField0_ |= 0x00000004; + fileName_ = bs; + break; + } + case 32: { + bitField0_ |= 0x00000008; + fileSize_ = input.readUInt32(); + break; + } + case 40: { + int rawValue = input.readEnum(); + com.mogujie.tt.protobuf.IMBaseDefine.FileType value = com.mogujie.tt.protobuf.IMBaseDefine.FileType.valueOf(rawValue); + if (value == null) { + unknownFieldsCodedOutput.writeRawVarint32(tag); + unknownFieldsCodedOutput.writeRawVarint32(rawValue); + } else { + bitField0_ |= 0x00000010; + transMode_ = value; + } + break; + } + } + } + } catch (com.google.protobuf.InvalidProtocolBufferException e) { + throw e.setUnfinishedMessage(this); + } catch (java.io.IOException e) { + throw new com.google.protobuf.InvalidProtocolBufferException( + e.getMessage()).setUnfinishedMessage(this); + } finally { + try { + unknownFieldsCodedOutput.flush(); + } catch (java.io.IOException e) { + // Should not happen + } finally { + unknownFields = unknownFieldsOutput.toByteString(); + } + makeExtensionsImmutable(); + } + } + public static com.google.protobuf.Parser PARSER = + new com.google.protobuf.AbstractParser() { + public IMFileReq parsePartialFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return new IMFileReq(input, extensionRegistry); + } + }; + + @java.lang.Override + public com.google.protobuf.Parser getParserForType() { + return PARSER; + } + + private int bitField0_; + public static final int FROM_USER_ID_FIELD_NUMBER = 1; + private int fromUserId_; + /** + * required uint32 from_user_id = 1; + * + *
+     *cmd id: 	0x0506
+     * 
+ */ + public boolean hasFromUserId() { + return ((bitField0_ & 0x00000001) == 0x00000001); + } + /** + * required uint32 from_user_id = 1; + * + *
+     *cmd id: 	0x0506
+     * 
+ */ + public int getFromUserId() { + return fromUserId_; + } + + public static final int TO_USER_ID_FIELD_NUMBER = 2; + private int toUserId_; + /** + * required uint32 to_user_id = 2; + */ + public boolean hasToUserId() { + return ((bitField0_ & 0x00000002) == 0x00000002); + } + /** + * required uint32 to_user_id = 2; + */ + public int getToUserId() { + return toUserId_; + } + + public static final int FILE_NAME_FIELD_NUMBER = 3; + private java.lang.Object fileName_; + /** + * required string file_name = 3; + */ + public boolean hasFileName() { + return ((bitField0_ & 0x00000004) == 0x00000004); + } + /** + * required string file_name = 3; + */ + public java.lang.String getFileName() { + java.lang.Object ref = fileName_; + if (ref instanceof java.lang.String) { + return (java.lang.String) ref; + } else { + com.google.protobuf.ByteString bs = + (com.google.protobuf.ByteString) ref; + java.lang.String s = bs.toStringUtf8(); + if (bs.isValidUtf8()) { + fileName_ = s; + } + return s; + } + } + /** + * required string file_name = 3; + */ + public com.google.protobuf.ByteString + getFileNameBytes() { + java.lang.Object ref = fileName_; + if (ref instanceof java.lang.String) { + com.google.protobuf.ByteString b = + com.google.protobuf.ByteString.copyFromUtf8( + (java.lang.String) ref); + fileName_ = b; + return b; + } else { + return (com.google.protobuf.ByteString) ref; + } + } + + public static final int FILE_SIZE_FIELD_NUMBER = 4; + private int fileSize_; + /** + * required uint32 file_size = 4; + */ + public boolean hasFileSize() { + return ((bitField0_ & 0x00000008) == 0x00000008); + } + /** + * required uint32 file_size = 4; + */ + public int getFileSize() { + return fileSize_; + } + + public static final int TRANS_MODE_FIELD_NUMBER = 5; + private com.mogujie.tt.protobuf.IMBaseDefine.FileType transMode_; + /** + * required .IM.BaseDefine.FileType trans_mode = 5; + */ + public boolean hasTransMode() { + return ((bitField0_ & 0x00000010) == 0x00000010); + } + /** + * required .IM.BaseDefine.FileType trans_mode = 5; + */ + public com.mogujie.tt.protobuf.IMBaseDefine.FileType getTransMode() { + return transMode_; + } + + private void initFields() { + fromUserId_ = 0; + toUserId_ = 0; + fileName_ = ""; + fileSize_ = 0; + transMode_ = com.mogujie.tt.protobuf.IMBaseDefine.FileType.FILE_TYPE_ONLINE; + } + private byte memoizedIsInitialized = -1; + public final boolean isInitialized() { + byte isInitialized = memoizedIsInitialized; + if (isInitialized == 1) return true; + if (isInitialized == 0) return false; + + if (!hasFromUserId()) { + memoizedIsInitialized = 0; + return false; + } + if (!hasToUserId()) { + memoizedIsInitialized = 0; + return false; + } + if (!hasFileName()) { + memoizedIsInitialized = 0; + return false; + } + if (!hasFileSize()) { + memoizedIsInitialized = 0; + return false; + } + if (!hasTransMode()) { + memoizedIsInitialized = 0; + return false; + } + memoizedIsInitialized = 1; + return true; + } + + public void writeTo(com.google.protobuf.CodedOutputStream output) + throws java.io.IOException { + getSerializedSize(); + if (((bitField0_ & 0x00000001) == 0x00000001)) { + output.writeUInt32(1, fromUserId_); + } + if (((bitField0_ & 0x00000002) == 0x00000002)) { + output.writeUInt32(2, toUserId_); + } + if (((bitField0_ & 0x00000004) == 0x00000004)) { + output.writeBytes(3, getFileNameBytes()); + } + if (((bitField0_ & 0x00000008) == 0x00000008)) { + output.writeUInt32(4, fileSize_); + } + if (((bitField0_ & 0x00000010) == 0x00000010)) { + output.writeEnum(5, transMode_.getNumber()); + } + output.writeRawBytes(unknownFields); + } + + private int memoizedSerializedSize = -1; + public int getSerializedSize() { + int size = memoizedSerializedSize; + if (size != -1) return size; + + size = 0; + if (((bitField0_ & 0x00000001) == 0x00000001)) { + size += com.google.protobuf.CodedOutputStream + .computeUInt32Size(1, fromUserId_); + } + if (((bitField0_ & 0x00000002) == 0x00000002)) { + size += com.google.protobuf.CodedOutputStream + .computeUInt32Size(2, toUserId_); + } + if (((bitField0_ & 0x00000004) == 0x00000004)) { + size += com.google.protobuf.CodedOutputStream + .computeBytesSize(3, getFileNameBytes()); + } + if (((bitField0_ & 0x00000008) == 0x00000008)) { + size += com.google.protobuf.CodedOutputStream + .computeUInt32Size(4, fileSize_); + } + if (((bitField0_ & 0x00000010) == 0x00000010)) { + size += com.google.protobuf.CodedOutputStream + .computeEnumSize(5, transMode_.getNumber()); + } + size += unknownFields.size(); + memoizedSerializedSize = size; + return size; + } + + private static final long serialVersionUID = 0L; + @java.lang.Override + protected java.lang.Object writeReplace() + throws java.io.ObjectStreamException { + return super.writeReplace(); + } + + public static com.mogujie.tt.protobuf.IMFile.IMFileReq parseFrom( + com.google.protobuf.ByteString data) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data); + } + public static com.mogujie.tt.protobuf.IMFile.IMFileReq parseFrom( + com.google.protobuf.ByteString data, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data, extensionRegistry); + } + public static com.mogujie.tt.protobuf.IMFile.IMFileReq parseFrom(byte[] data) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data); + } + public static com.mogujie.tt.protobuf.IMFile.IMFileReq parseFrom( + byte[] data, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data, extensionRegistry); + } + public static com.mogujie.tt.protobuf.IMFile.IMFileReq parseFrom(java.io.InputStream input) + throws java.io.IOException { + return PARSER.parseFrom(input); + } + public static com.mogujie.tt.protobuf.IMFile.IMFileReq parseFrom( + java.io.InputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return PARSER.parseFrom(input, extensionRegistry); + } + public static com.mogujie.tt.protobuf.IMFile.IMFileReq parseDelimitedFrom(java.io.InputStream input) + throws java.io.IOException { + return PARSER.parseDelimitedFrom(input); + } + public static com.mogujie.tt.protobuf.IMFile.IMFileReq parseDelimitedFrom( + java.io.InputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return PARSER.parseDelimitedFrom(input, extensionRegistry); + } + public static com.mogujie.tt.protobuf.IMFile.IMFileReq parseFrom( + com.google.protobuf.CodedInputStream input) + throws java.io.IOException { + return PARSER.parseFrom(input); + } + public static com.mogujie.tt.protobuf.IMFile.IMFileReq parseFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return PARSER.parseFrom(input, extensionRegistry); + } + + public static Builder newBuilder() { return Builder.create(); } + public Builder newBuilderForType() { return newBuilder(); } + public static Builder newBuilder(com.mogujie.tt.protobuf.IMFile.IMFileReq prototype) { + return newBuilder().mergeFrom(prototype); + } + public Builder toBuilder() { return newBuilder(this); } + + /** + * Protobuf type {@code IM.File.IMFileReq} + */ + public static final class Builder extends + com.google.protobuf.GeneratedMessageLite.Builder< + com.mogujie.tt.protobuf.IMFile.IMFileReq, Builder> + implements + // @@protoc_insertion_point(builder_implements:IM.File.IMFileReq) + com.mogujie.tt.protobuf.IMFile.IMFileReqOrBuilder { + // Construct using com.mogujie.tt.protobuf.IMFile.IMFileReq.newBuilder() + private Builder() { + maybeForceBuilderInitialization(); + } + + private void maybeForceBuilderInitialization() { + } + private static Builder create() { + return new Builder(); + } + + public Builder clear() { + super.clear(); + fromUserId_ = 0; + bitField0_ = (bitField0_ & ~0x00000001); + toUserId_ = 0; + bitField0_ = (bitField0_ & ~0x00000002); + fileName_ = ""; + bitField0_ = (bitField0_ & ~0x00000004); + fileSize_ = 0; + bitField0_ = (bitField0_ & ~0x00000008); + transMode_ = com.mogujie.tt.protobuf.IMBaseDefine.FileType.FILE_TYPE_ONLINE; + bitField0_ = (bitField0_ & ~0x00000010); + return this; + } + + public Builder clone() { + return create().mergeFrom(buildPartial()); + } + + public com.mogujie.tt.protobuf.IMFile.IMFileReq getDefaultInstanceForType() { + return com.mogujie.tt.protobuf.IMFile.IMFileReq.getDefaultInstance(); + } + + public com.mogujie.tt.protobuf.IMFile.IMFileReq build() { + com.mogujie.tt.protobuf.IMFile.IMFileReq result = buildPartial(); + if (!result.isInitialized()) { + throw newUninitializedMessageException(result); + } + return result; + } + + public com.mogujie.tt.protobuf.IMFile.IMFileReq buildPartial() { + com.mogujie.tt.protobuf.IMFile.IMFileReq result = new com.mogujie.tt.protobuf.IMFile.IMFileReq(this); + int from_bitField0_ = bitField0_; + int to_bitField0_ = 0; + if (((from_bitField0_ & 0x00000001) == 0x00000001)) { + to_bitField0_ |= 0x00000001; + } + result.fromUserId_ = fromUserId_; + if (((from_bitField0_ & 0x00000002) == 0x00000002)) { + to_bitField0_ |= 0x00000002; + } + result.toUserId_ = toUserId_; + if (((from_bitField0_ & 0x00000004) == 0x00000004)) { + to_bitField0_ |= 0x00000004; + } + result.fileName_ = fileName_; + if (((from_bitField0_ & 0x00000008) == 0x00000008)) { + to_bitField0_ |= 0x00000008; + } + result.fileSize_ = fileSize_; + if (((from_bitField0_ & 0x00000010) == 0x00000010)) { + to_bitField0_ |= 0x00000010; + } + result.transMode_ = transMode_; + result.bitField0_ = to_bitField0_; + return result; + } + + public Builder mergeFrom(com.mogujie.tt.protobuf.IMFile.IMFileReq other) { + if (other == com.mogujie.tt.protobuf.IMFile.IMFileReq.getDefaultInstance()) return this; + if (other.hasFromUserId()) { + setFromUserId(other.getFromUserId()); + } + if (other.hasToUserId()) { + setToUserId(other.getToUserId()); + } + if (other.hasFileName()) { + bitField0_ |= 0x00000004; + fileName_ = other.fileName_; + + } + if (other.hasFileSize()) { + setFileSize(other.getFileSize()); + } + if (other.hasTransMode()) { + setTransMode(other.getTransMode()); + } + setUnknownFields( + getUnknownFields().concat(other.unknownFields)); + return this; + } + + public final boolean isInitialized() { + if (!hasFromUserId()) { + + return false; + } + if (!hasToUserId()) { + + return false; + } + if (!hasFileName()) { + + return false; + } + if (!hasFileSize()) { + + return false; + } + if (!hasTransMode()) { + + return false; + } + return true; + } + + public Builder mergeFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + com.mogujie.tt.protobuf.IMFile.IMFileReq parsedMessage = null; + try { + parsedMessage = PARSER.parsePartialFrom(input, extensionRegistry); + } catch (com.google.protobuf.InvalidProtocolBufferException e) { + parsedMessage = (com.mogujie.tt.protobuf.IMFile.IMFileReq) e.getUnfinishedMessage(); + throw e; + } finally { + if (parsedMessage != null) { + mergeFrom(parsedMessage); + } + } + return this; + } + private int bitField0_; + + private int fromUserId_ ; + /** + * required uint32 from_user_id = 1; + * + *
+       *cmd id: 	0x0506
+       * 
+ */ + public boolean hasFromUserId() { + return ((bitField0_ & 0x00000001) == 0x00000001); + } + /** + * required uint32 from_user_id = 1; + * + *
+       *cmd id: 	0x0506
+       * 
+ */ + public int getFromUserId() { + return fromUserId_; + } + /** + * required uint32 from_user_id = 1; + * + *
+       *cmd id: 	0x0506
+       * 
+ */ + public Builder setFromUserId(int value) { + bitField0_ |= 0x00000001; + fromUserId_ = value; + + return this; + } + /** + * required uint32 from_user_id = 1; + * + *
+       *cmd id: 	0x0506
+       * 
+ */ + public Builder clearFromUserId() { + bitField0_ = (bitField0_ & ~0x00000001); + fromUserId_ = 0; + + return this; + } + + private int toUserId_ ; + /** + * required uint32 to_user_id = 2; + */ + public boolean hasToUserId() { + return ((bitField0_ & 0x00000002) == 0x00000002); + } + /** + * required uint32 to_user_id = 2; + */ + public int getToUserId() { + return toUserId_; + } + /** + * required uint32 to_user_id = 2; + */ + public Builder setToUserId(int value) { + bitField0_ |= 0x00000002; + toUserId_ = value; + + return this; + } + /** + * required uint32 to_user_id = 2; + */ + public Builder clearToUserId() { + bitField0_ = (bitField0_ & ~0x00000002); + toUserId_ = 0; + + return this; + } + + private java.lang.Object fileName_ = ""; + /** + * required string file_name = 3; + */ + public boolean hasFileName() { + return ((bitField0_ & 0x00000004) == 0x00000004); + } + /** + * required string file_name = 3; + */ + public java.lang.String getFileName() { + java.lang.Object ref = fileName_; + if (!(ref instanceof java.lang.String)) { + com.google.protobuf.ByteString bs = + (com.google.protobuf.ByteString) ref; + java.lang.String s = bs.toStringUtf8(); + if (bs.isValidUtf8()) { + fileName_ = s; + } + return s; + } else { + return (java.lang.String) ref; + } + } + /** + * required string file_name = 3; + */ + public com.google.protobuf.ByteString + getFileNameBytes() { + java.lang.Object ref = fileName_; + if (ref instanceof String) { + com.google.protobuf.ByteString b = + com.google.protobuf.ByteString.copyFromUtf8( + (java.lang.String) ref); + fileName_ = b; + return b; + } else { + return (com.google.protobuf.ByteString) ref; + } + } + /** + * required string file_name = 3; + */ + public Builder setFileName( + java.lang.String value) { + if (value == null) { + throw new NullPointerException(); + } + bitField0_ |= 0x00000004; + fileName_ = value; + + return this; + } + /** + * required string file_name = 3; + */ + public Builder clearFileName() { + bitField0_ = (bitField0_ & ~0x00000004); + fileName_ = getDefaultInstance().getFileName(); + + return this; + } + /** + * required string file_name = 3; + */ + public Builder setFileNameBytes( + com.google.protobuf.ByteString value) { + if (value == null) { + throw new NullPointerException(); + } + bitField0_ |= 0x00000004; + fileName_ = value; + + return this; + } + + private int fileSize_ ; + /** + * required uint32 file_size = 4; + */ + public boolean hasFileSize() { + return ((bitField0_ & 0x00000008) == 0x00000008); + } + /** + * required uint32 file_size = 4; + */ + public int getFileSize() { + return fileSize_; + } + /** + * required uint32 file_size = 4; + */ + public Builder setFileSize(int value) { + bitField0_ |= 0x00000008; + fileSize_ = value; + + return this; + } + /** + * required uint32 file_size = 4; + */ + public Builder clearFileSize() { + bitField0_ = (bitField0_ & ~0x00000008); + fileSize_ = 0; + + return this; + } + + private com.mogujie.tt.protobuf.IMBaseDefine.FileType transMode_ = com.mogujie.tt.protobuf.IMBaseDefine.FileType.FILE_TYPE_ONLINE; + /** + * required .IM.BaseDefine.FileType trans_mode = 5; + */ + public boolean hasTransMode() { + return ((bitField0_ & 0x00000010) == 0x00000010); + } + /** + * required .IM.BaseDefine.FileType trans_mode = 5; + */ + public com.mogujie.tt.protobuf.IMBaseDefine.FileType getTransMode() { + return transMode_; + } + /** + * required .IM.BaseDefine.FileType trans_mode = 5; + */ + public Builder setTransMode(com.mogujie.tt.protobuf.IMBaseDefine.FileType value) { + if (value == null) { + throw new NullPointerException(); + } + bitField0_ |= 0x00000010; + transMode_ = value; + + return this; + } + /** + * required .IM.BaseDefine.FileType trans_mode = 5; + */ + public Builder clearTransMode() { + bitField0_ = (bitField0_ & ~0x00000010); + transMode_ = com.mogujie.tt.protobuf.IMBaseDefine.FileType.FILE_TYPE_ONLINE; + + return this; + } + + // @@protoc_insertion_point(builder_scope:IM.File.IMFileReq) + } + + static { + defaultInstance = new IMFileReq(true); + defaultInstance.initFields(); + } + + // @@protoc_insertion_point(class_scope:IM.File.IMFileReq) + } + + public interface IMFileRspOrBuilder extends + // @@protoc_insertion_point(interface_extends:IM.File.IMFileRsp) + com.google.protobuf.MessageLiteOrBuilder { + + /** + * required uint32 result_code = 1; + * + *
+     *cmd id: 	0x0507
+     * 
+ */ + boolean hasResultCode(); + /** + * required uint32 result_code = 1; + * + *
+     *cmd id: 	0x0507
+     * 
+ */ + int getResultCode(); + + /** + * required uint32 from_user_id = 2; + */ + boolean hasFromUserId(); + /** + * required uint32 from_user_id = 2; + */ + int getFromUserId(); + + /** + * required uint32 to_user_id = 3; + */ + boolean hasToUserId(); + /** + * required uint32 to_user_id = 3; + */ + int getToUserId(); + + /** + * required string file_name = 4; + */ + boolean hasFileName(); + /** + * required string file_name = 4; + */ + java.lang.String getFileName(); + /** + * required string file_name = 4; + */ + com.google.protobuf.ByteString + getFileNameBytes(); + + /** + * required string task_id = 5; + */ + boolean hasTaskId(); + /** + * required string task_id = 5; + */ + java.lang.String getTaskId(); + /** + * required string task_id = 5; + */ + com.google.protobuf.ByteString + getTaskIdBytes(); + + /** + * repeated .IM.BaseDefine.IpAddr ip_addr_list = 6; + */ + java.util.List + getIpAddrListList(); + /** + * repeated .IM.BaseDefine.IpAddr ip_addr_list = 6; + */ + com.mogujie.tt.protobuf.IMBaseDefine.IpAddr getIpAddrList(int index); + /** + * repeated .IM.BaseDefine.IpAddr ip_addr_list = 6; + */ + int getIpAddrListCount(); + + /** + * required .IM.BaseDefine.FileType trans_mode = 7; + */ + boolean hasTransMode(); + /** + * required .IM.BaseDefine.FileType trans_mode = 7; + */ + com.mogujie.tt.protobuf.IMBaseDefine.FileType getTransMode(); + } + /** + * Protobuf type {@code IM.File.IMFileRsp} + */ + public static final class IMFileRsp extends + com.google.protobuf.GeneratedMessageLite implements + // @@protoc_insertion_point(message_implements:IM.File.IMFileRsp) + IMFileRspOrBuilder { + // Use IMFileRsp.newBuilder() to construct. + private IMFileRsp(com.google.protobuf.GeneratedMessageLite.Builder builder) { + super(builder); + this.unknownFields = builder.getUnknownFields(); + } + private IMFileRsp(boolean noInit) { this.unknownFields = com.google.protobuf.ByteString.EMPTY;} + + private static final IMFileRsp defaultInstance; + public static IMFileRsp getDefaultInstance() { + return defaultInstance; + } + + public IMFileRsp getDefaultInstanceForType() { + return defaultInstance; + } + + private final com.google.protobuf.ByteString unknownFields; + private IMFileRsp( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + initFields(); + int mutable_bitField0_ = 0; + com.google.protobuf.ByteString.Output unknownFieldsOutput = + com.google.protobuf.ByteString.newOutput(); + com.google.protobuf.CodedOutputStream unknownFieldsCodedOutput = + com.google.protobuf.CodedOutputStream.newInstance( + unknownFieldsOutput); + try { + boolean done = false; + while (!done) { + int tag = input.readTag(); + switch (tag) { + case 0: + done = true; + break; + default: { + if (!parseUnknownField(input, unknownFieldsCodedOutput, + extensionRegistry, tag)) { + done = true; + } + break; + } + case 8: { + bitField0_ |= 0x00000001; + resultCode_ = input.readUInt32(); + break; + } + case 16: { + bitField0_ |= 0x00000002; + fromUserId_ = input.readUInt32(); + break; + } + case 24: { + bitField0_ |= 0x00000004; + toUserId_ = input.readUInt32(); + break; + } + case 34: { + com.google.protobuf.ByteString bs = input.readBytes(); + bitField0_ |= 0x00000008; + fileName_ = bs; + break; + } + case 42: { + com.google.protobuf.ByteString bs = input.readBytes(); + bitField0_ |= 0x00000010; + taskId_ = bs; + break; + } + case 50: { + if (!((mutable_bitField0_ & 0x00000020) == 0x00000020)) { + ipAddrList_ = new java.util.ArrayList(); + mutable_bitField0_ |= 0x00000020; + } + ipAddrList_.add(input.readMessage(com.mogujie.tt.protobuf.IMBaseDefine.IpAddr.PARSER, extensionRegistry)); + break; + } + case 56: { + int rawValue = input.readEnum(); + com.mogujie.tt.protobuf.IMBaseDefine.FileType value = com.mogujie.tt.protobuf.IMBaseDefine.FileType.valueOf(rawValue); + if (value == null) { + unknownFieldsCodedOutput.writeRawVarint32(tag); + unknownFieldsCodedOutput.writeRawVarint32(rawValue); + } else { + bitField0_ |= 0x00000020; + transMode_ = value; + } + break; + } + } + } + } catch (com.google.protobuf.InvalidProtocolBufferException e) { + throw e.setUnfinishedMessage(this); + } catch (java.io.IOException e) { + throw new com.google.protobuf.InvalidProtocolBufferException( + e.getMessage()).setUnfinishedMessage(this); + } finally { + if (((mutable_bitField0_ & 0x00000020) == 0x00000020)) { + ipAddrList_ = java.util.Collections.unmodifiableList(ipAddrList_); + } + try { + unknownFieldsCodedOutput.flush(); + } catch (java.io.IOException e) { + // Should not happen + } finally { + unknownFields = unknownFieldsOutput.toByteString(); + } + makeExtensionsImmutable(); + } + } + public static com.google.protobuf.Parser PARSER = + new com.google.protobuf.AbstractParser() { + public IMFileRsp parsePartialFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return new IMFileRsp(input, extensionRegistry); + } + }; + + @java.lang.Override + public com.google.protobuf.Parser getParserForType() { + return PARSER; + } + + private int bitField0_; + public static final int RESULT_CODE_FIELD_NUMBER = 1; + private int resultCode_; + /** + * required uint32 result_code = 1; + * + *
+     *cmd id: 	0x0507
+     * 
+ */ + public boolean hasResultCode() { + return ((bitField0_ & 0x00000001) == 0x00000001); + } + /** + * required uint32 result_code = 1; + * + *
+     *cmd id: 	0x0507
+     * 
+ */ + public int getResultCode() { + return resultCode_; + } + + public static final int FROM_USER_ID_FIELD_NUMBER = 2; + private int fromUserId_; + /** + * required uint32 from_user_id = 2; + */ + public boolean hasFromUserId() { + return ((bitField0_ & 0x00000002) == 0x00000002); + } + /** + * required uint32 from_user_id = 2; + */ + public int getFromUserId() { + return fromUserId_; + } + + public static final int TO_USER_ID_FIELD_NUMBER = 3; + private int toUserId_; + /** + * required uint32 to_user_id = 3; + */ + public boolean hasToUserId() { + return ((bitField0_ & 0x00000004) == 0x00000004); + } + /** + * required uint32 to_user_id = 3; + */ + public int getToUserId() { + return toUserId_; + } + + public static final int FILE_NAME_FIELD_NUMBER = 4; + private java.lang.Object fileName_; + /** + * required string file_name = 4; + */ + public boolean hasFileName() { + return ((bitField0_ & 0x00000008) == 0x00000008); + } + /** + * required string file_name = 4; + */ + public java.lang.String getFileName() { + java.lang.Object ref = fileName_; + if (ref instanceof java.lang.String) { + return (java.lang.String) ref; + } else { + com.google.protobuf.ByteString bs = + (com.google.protobuf.ByteString) ref; + java.lang.String s = bs.toStringUtf8(); + if (bs.isValidUtf8()) { + fileName_ = s; + } + return s; + } + } + /** + * required string file_name = 4; + */ + public com.google.protobuf.ByteString + getFileNameBytes() { + java.lang.Object ref = fileName_; + if (ref instanceof java.lang.String) { + com.google.protobuf.ByteString b = + com.google.protobuf.ByteString.copyFromUtf8( + (java.lang.String) ref); + fileName_ = b; + return b; + } else { + return (com.google.protobuf.ByteString) ref; + } + } + + public static final int TASK_ID_FIELD_NUMBER = 5; + private java.lang.Object taskId_; + /** + * required string task_id = 5; + */ + public boolean hasTaskId() { + return ((bitField0_ & 0x00000010) == 0x00000010); + } + /** + * required string task_id = 5; + */ + public java.lang.String getTaskId() { + java.lang.Object ref = taskId_; + if (ref instanceof java.lang.String) { + return (java.lang.String) ref; + } else { + com.google.protobuf.ByteString bs = + (com.google.protobuf.ByteString) ref; + java.lang.String s = bs.toStringUtf8(); + if (bs.isValidUtf8()) { + taskId_ = s; + } + return s; + } + } + /** + * required string task_id = 5; + */ + public com.google.protobuf.ByteString + getTaskIdBytes() { + java.lang.Object ref = taskId_; + if (ref instanceof java.lang.String) { + com.google.protobuf.ByteString b = + com.google.protobuf.ByteString.copyFromUtf8( + (java.lang.String) ref); + taskId_ = b; + return b; + } else { + return (com.google.protobuf.ByteString) ref; + } + } + + public static final int IP_ADDR_LIST_FIELD_NUMBER = 6; + private java.util.List ipAddrList_; + /** + * repeated .IM.BaseDefine.IpAddr ip_addr_list = 6; + */ + public java.util.List getIpAddrListList() { + return ipAddrList_; + } + /** + * repeated .IM.BaseDefine.IpAddr ip_addr_list = 6; + */ + public java.util.List + getIpAddrListOrBuilderList() { + return ipAddrList_; + } + /** + * repeated .IM.BaseDefine.IpAddr ip_addr_list = 6; + */ + public int getIpAddrListCount() { + return ipAddrList_.size(); + } + /** + * repeated .IM.BaseDefine.IpAddr ip_addr_list = 6; + */ + public com.mogujie.tt.protobuf.IMBaseDefine.IpAddr getIpAddrList(int index) { + return ipAddrList_.get(index); + } + /** + * repeated .IM.BaseDefine.IpAddr ip_addr_list = 6; + */ + public com.mogujie.tt.protobuf.IMBaseDefine.IpAddrOrBuilder getIpAddrListOrBuilder( + int index) { + return ipAddrList_.get(index); + } + + public static final int TRANS_MODE_FIELD_NUMBER = 7; + private com.mogujie.tt.protobuf.IMBaseDefine.FileType transMode_; + /** + * required .IM.BaseDefine.FileType trans_mode = 7; + */ + public boolean hasTransMode() { + return ((bitField0_ & 0x00000020) == 0x00000020); + } + /** + * required .IM.BaseDefine.FileType trans_mode = 7; + */ + public com.mogujie.tt.protobuf.IMBaseDefine.FileType getTransMode() { + return transMode_; + } + + private void initFields() { + resultCode_ = 0; + fromUserId_ = 0; + toUserId_ = 0; + fileName_ = ""; + taskId_ = ""; + ipAddrList_ = java.util.Collections.emptyList(); + transMode_ = com.mogujie.tt.protobuf.IMBaseDefine.FileType.FILE_TYPE_ONLINE; + } + private byte memoizedIsInitialized = -1; + public final boolean isInitialized() { + byte isInitialized = memoizedIsInitialized; + if (isInitialized == 1) return true; + if (isInitialized == 0) return false; + + if (!hasResultCode()) { + memoizedIsInitialized = 0; + return false; + } + if (!hasFromUserId()) { + memoizedIsInitialized = 0; + return false; + } + if (!hasToUserId()) { + memoizedIsInitialized = 0; + return false; + } + if (!hasFileName()) { + memoizedIsInitialized = 0; + return false; + } + if (!hasTaskId()) { + memoizedIsInitialized = 0; + return false; + } + if (!hasTransMode()) { + memoizedIsInitialized = 0; + return false; + } + for (int i = 0; i < getIpAddrListCount(); i++) { + if (!getIpAddrList(i).isInitialized()) { + memoizedIsInitialized = 0; + return false; + } + } + memoizedIsInitialized = 1; + return true; + } + + public void writeTo(com.google.protobuf.CodedOutputStream output) + throws java.io.IOException { + getSerializedSize(); + if (((bitField0_ & 0x00000001) == 0x00000001)) { + output.writeUInt32(1, resultCode_); + } + if (((bitField0_ & 0x00000002) == 0x00000002)) { + output.writeUInt32(2, fromUserId_); + } + if (((bitField0_ & 0x00000004) == 0x00000004)) { + output.writeUInt32(3, toUserId_); + } + if (((bitField0_ & 0x00000008) == 0x00000008)) { + output.writeBytes(4, getFileNameBytes()); + } + if (((bitField0_ & 0x00000010) == 0x00000010)) { + output.writeBytes(5, getTaskIdBytes()); + } + for (int i = 0; i < ipAddrList_.size(); i++) { + output.writeMessage(6, ipAddrList_.get(i)); + } + if (((bitField0_ & 0x00000020) == 0x00000020)) { + output.writeEnum(7, transMode_.getNumber()); + } + output.writeRawBytes(unknownFields); + } + + private int memoizedSerializedSize = -1; + public int getSerializedSize() { + int size = memoizedSerializedSize; + if (size != -1) return size; + + size = 0; + if (((bitField0_ & 0x00000001) == 0x00000001)) { + size += com.google.protobuf.CodedOutputStream + .computeUInt32Size(1, resultCode_); + } + if (((bitField0_ & 0x00000002) == 0x00000002)) { + size += com.google.protobuf.CodedOutputStream + .computeUInt32Size(2, fromUserId_); + } + if (((bitField0_ & 0x00000004) == 0x00000004)) { + size += com.google.protobuf.CodedOutputStream + .computeUInt32Size(3, toUserId_); + } + if (((bitField0_ & 0x00000008) == 0x00000008)) { + size += com.google.protobuf.CodedOutputStream + .computeBytesSize(4, getFileNameBytes()); + } + if (((bitField0_ & 0x00000010) == 0x00000010)) { + size += com.google.protobuf.CodedOutputStream + .computeBytesSize(5, getTaskIdBytes()); + } + for (int i = 0; i < ipAddrList_.size(); i++) { + size += com.google.protobuf.CodedOutputStream + .computeMessageSize(6, ipAddrList_.get(i)); + } + if (((bitField0_ & 0x00000020) == 0x00000020)) { + size += com.google.protobuf.CodedOutputStream + .computeEnumSize(7, transMode_.getNumber()); + } + size += unknownFields.size(); + memoizedSerializedSize = size; + return size; + } + + private static final long serialVersionUID = 0L; + @java.lang.Override + protected java.lang.Object writeReplace() + throws java.io.ObjectStreamException { + return super.writeReplace(); + } + + public static com.mogujie.tt.protobuf.IMFile.IMFileRsp parseFrom( + com.google.protobuf.ByteString data) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data); + } + public static com.mogujie.tt.protobuf.IMFile.IMFileRsp parseFrom( + com.google.protobuf.ByteString data, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data, extensionRegistry); + } + public static com.mogujie.tt.protobuf.IMFile.IMFileRsp parseFrom(byte[] data) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data); + } + public static com.mogujie.tt.protobuf.IMFile.IMFileRsp parseFrom( + byte[] data, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data, extensionRegistry); + } + public static com.mogujie.tt.protobuf.IMFile.IMFileRsp parseFrom(java.io.InputStream input) + throws java.io.IOException { + return PARSER.parseFrom(input); + } + public static com.mogujie.tt.protobuf.IMFile.IMFileRsp parseFrom( + java.io.InputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return PARSER.parseFrom(input, extensionRegistry); + } + public static com.mogujie.tt.protobuf.IMFile.IMFileRsp parseDelimitedFrom(java.io.InputStream input) + throws java.io.IOException { + return PARSER.parseDelimitedFrom(input); + } + public static com.mogujie.tt.protobuf.IMFile.IMFileRsp parseDelimitedFrom( + java.io.InputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return PARSER.parseDelimitedFrom(input, extensionRegistry); + } + public static com.mogujie.tt.protobuf.IMFile.IMFileRsp parseFrom( + com.google.protobuf.CodedInputStream input) + throws java.io.IOException { + return PARSER.parseFrom(input); + } + public static com.mogujie.tt.protobuf.IMFile.IMFileRsp parseFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return PARSER.parseFrom(input, extensionRegistry); + } + + public static Builder newBuilder() { return Builder.create(); } + public Builder newBuilderForType() { return newBuilder(); } + public static Builder newBuilder(com.mogujie.tt.protobuf.IMFile.IMFileRsp prototype) { + return newBuilder().mergeFrom(prototype); + } + public Builder toBuilder() { return newBuilder(this); } + + /** + * Protobuf type {@code IM.File.IMFileRsp} + */ + public static final class Builder extends + com.google.protobuf.GeneratedMessageLite.Builder< + com.mogujie.tt.protobuf.IMFile.IMFileRsp, Builder> + implements + // @@protoc_insertion_point(builder_implements:IM.File.IMFileRsp) + com.mogujie.tt.protobuf.IMFile.IMFileRspOrBuilder { + // Construct using com.mogujie.tt.protobuf.IMFile.IMFileRsp.newBuilder() + private Builder() { + maybeForceBuilderInitialization(); + } + + private void maybeForceBuilderInitialization() { + } + private static Builder create() { + return new Builder(); + } + + public Builder clear() { + super.clear(); + resultCode_ = 0; + bitField0_ = (bitField0_ & ~0x00000001); + fromUserId_ = 0; + bitField0_ = (bitField0_ & ~0x00000002); + toUserId_ = 0; + bitField0_ = (bitField0_ & ~0x00000004); + fileName_ = ""; + bitField0_ = (bitField0_ & ~0x00000008); + taskId_ = ""; + bitField0_ = (bitField0_ & ~0x00000010); + ipAddrList_ = java.util.Collections.emptyList(); + bitField0_ = (bitField0_ & ~0x00000020); + transMode_ = com.mogujie.tt.protobuf.IMBaseDefine.FileType.FILE_TYPE_ONLINE; + bitField0_ = (bitField0_ & ~0x00000040); + return this; + } + + public Builder clone() { + return create().mergeFrom(buildPartial()); + } + + public com.mogujie.tt.protobuf.IMFile.IMFileRsp getDefaultInstanceForType() { + return com.mogujie.tt.protobuf.IMFile.IMFileRsp.getDefaultInstance(); + } + + public com.mogujie.tt.protobuf.IMFile.IMFileRsp build() { + com.mogujie.tt.protobuf.IMFile.IMFileRsp result = buildPartial(); + if (!result.isInitialized()) { + throw newUninitializedMessageException(result); + } + return result; + } + + public com.mogujie.tt.protobuf.IMFile.IMFileRsp buildPartial() { + com.mogujie.tt.protobuf.IMFile.IMFileRsp result = new com.mogujie.tt.protobuf.IMFile.IMFileRsp(this); + int from_bitField0_ = bitField0_; + int to_bitField0_ = 0; + if (((from_bitField0_ & 0x00000001) == 0x00000001)) { + to_bitField0_ |= 0x00000001; + } + result.resultCode_ = resultCode_; + if (((from_bitField0_ & 0x00000002) == 0x00000002)) { + to_bitField0_ |= 0x00000002; + } + result.fromUserId_ = fromUserId_; + if (((from_bitField0_ & 0x00000004) == 0x00000004)) { + to_bitField0_ |= 0x00000004; + } + result.toUserId_ = toUserId_; + if (((from_bitField0_ & 0x00000008) == 0x00000008)) { + to_bitField0_ |= 0x00000008; + } + result.fileName_ = fileName_; + if (((from_bitField0_ & 0x00000010) == 0x00000010)) { + to_bitField0_ |= 0x00000010; + } + result.taskId_ = taskId_; + if (((bitField0_ & 0x00000020) == 0x00000020)) { + ipAddrList_ = java.util.Collections.unmodifiableList(ipAddrList_); + bitField0_ = (bitField0_ & ~0x00000020); + } + result.ipAddrList_ = ipAddrList_; + if (((from_bitField0_ & 0x00000040) == 0x00000040)) { + to_bitField0_ |= 0x00000020; + } + result.transMode_ = transMode_; + result.bitField0_ = to_bitField0_; + return result; + } + + public Builder mergeFrom(com.mogujie.tt.protobuf.IMFile.IMFileRsp other) { + if (other == com.mogujie.tt.protobuf.IMFile.IMFileRsp.getDefaultInstance()) return this; + if (other.hasResultCode()) { + setResultCode(other.getResultCode()); + } + if (other.hasFromUserId()) { + setFromUserId(other.getFromUserId()); + } + if (other.hasToUserId()) { + setToUserId(other.getToUserId()); + } + if (other.hasFileName()) { + bitField0_ |= 0x00000008; + fileName_ = other.fileName_; + + } + if (other.hasTaskId()) { + bitField0_ |= 0x00000010; + taskId_ = other.taskId_; + + } + if (!other.ipAddrList_.isEmpty()) { + if (ipAddrList_.isEmpty()) { + ipAddrList_ = other.ipAddrList_; + bitField0_ = (bitField0_ & ~0x00000020); + } else { + ensureIpAddrListIsMutable(); + ipAddrList_.addAll(other.ipAddrList_); + } + + } + if (other.hasTransMode()) { + setTransMode(other.getTransMode()); + } + setUnknownFields( + getUnknownFields().concat(other.unknownFields)); + return this; + } + + public final boolean isInitialized() { + if (!hasResultCode()) { + + return false; + } + if (!hasFromUserId()) { + + return false; + } + if (!hasToUserId()) { + + return false; + } + if (!hasFileName()) { + + return false; + } + if (!hasTaskId()) { + + return false; + } + if (!hasTransMode()) { + + return false; + } + for (int i = 0; i < getIpAddrListCount(); i++) { + if (!getIpAddrList(i).isInitialized()) { + + return false; + } + } + return true; + } + + public Builder mergeFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + com.mogujie.tt.protobuf.IMFile.IMFileRsp parsedMessage = null; + try { + parsedMessage = PARSER.parsePartialFrom(input, extensionRegistry); + } catch (com.google.protobuf.InvalidProtocolBufferException e) { + parsedMessage = (com.mogujie.tt.protobuf.IMFile.IMFileRsp) e.getUnfinishedMessage(); + throw e; + } finally { + if (parsedMessage != null) { + mergeFrom(parsedMessage); + } + } + return this; + } + private int bitField0_; + + private int resultCode_ ; + /** + * required uint32 result_code = 1; + * + *
+       *cmd id: 	0x0507
+       * 
+ */ + public boolean hasResultCode() { + return ((bitField0_ & 0x00000001) == 0x00000001); + } + /** + * required uint32 result_code = 1; + * + *
+       *cmd id: 	0x0507
+       * 
+ */ + public int getResultCode() { + return resultCode_; + } + /** + * required uint32 result_code = 1; + * + *
+       *cmd id: 	0x0507
+       * 
+ */ + public Builder setResultCode(int value) { + bitField0_ |= 0x00000001; + resultCode_ = value; + + return this; + } + /** + * required uint32 result_code = 1; + * + *
+       *cmd id: 	0x0507
+       * 
+ */ + public Builder clearResultCode() { + bitField0_ = (bitField0_ & ~0x00000001); + resultCode_ = 0; + + return this; + } + + private int fromUserId_ ; + /** + * required uint32 from_user_id = 2; + */ + public boolean hasFromUserId() { + return ((bitField0_ & 0x00000002) == 0x00000002); + } + /** + * required uint32 from_user_id = 2; + */ + public int getFromUserId() { + return fromUserId_; + } + /** + * required uint32 from_user_id = 2; + */ + public Builder setFromUserId(int value) { + bitField0_ |= 0x00000002; + fromUserId_ = value; + + return this; + } + /** + * required uint32 from_user_id = 2; + */ + public Builder clearFromUserId() { + bitField0_ = (bitField0_ & ~0x00000002); + fromUserId_ = 0; + + return this; + } + + private int toUserId_ ; + /** + * required uint32 to_user_id = 3; + */ + public boolean hasToUserId() { + return ((bitField0_ & 0x00000004) == 0x00000004); + } + /** + * required uint32 to_user_id = 3; + */ + public int getToUserId() { + return toUserId_; + } + /** + * required uint32 to_user_id = 3; + */ + public Builder setToUserId(int value) { + bitField0_ |= 0x00000004; + toUserId_ = value; + + return this; + } + /** + * required uint32 to_user_id = 3; + */ + public Builder clearToUserId() { + bitField0_ = (bitField0_ & ~0x00000004); + toUserId_ = 0; + + return this; + } + + private java.lang.Object fileName_ = ""; + /** + * required string file_name = 4; + */ + public boolean hasFileName() { + return ((bitField0_ & 0x00000008) == 0x00000008); + } + /** + * required string file_name = 4; + */ + public java.lang.String getFileName() { + java.lang.Object ref = fileName_; + if (!(ref instanceof java.lang.String)) { + com.google.protobuf.ByteString bs = + (com.google.protobuf.ByteString) ref; + java.lang.String s = bs.toStringUtf8(); + if (bs.isValidUtf8()) { + fileName_ = s; + } + return s; + } else { + return (java.lang.String) ref; + } + } + /** + * required string file_name = 4; + */ + public com.google.protobuf.ByteString + getFileNameBytes() { + java.lang.Object ref = fileName_; + if (ref instanceof String) { + com.google.protobuf.ByteString b = + com.google.protobuf.ByteString.copyFromUtf8( + (java.lang.String) ref); + fileName_ = b; + return b; + } else { + return (com.google.protobuf.ByteString) ref; + } + } + /** + * required string file_name = 4; + */ + public Builder setFileName( + java.lang.String value) { + if (value == null) { + throw new NullPointerException(); + } + bitField0_ |= 0x00000008; + fileName_ = value; + + return this; + } + /** + * required string file_name = 4; + */ + public Builder clearFileName() { + bitField0_ = (bitField0_ & ~0x00000008); + fileName_ = getDefaultInstance().getFileName(); + + return this; + } + /** + * required string file_name = 4; + */ + public Builder setFileNameBytes( + com.google.protobuf.ByteString value) { + if (value == null) { + throw new NullPointerException(); + } + bitField0_ |= 0x00000008; + fileName_ = value; + + return this; + } + + private java.lang.Object taskId_ = ""; + /** + * required string task_id = 5; + */ + public boolean hasTaskId() { + return ((bitField0_ & 0x00000010) == 0x00000010); + } + /** + * required string task_id = 5; + */ + public java.lang.String getTaskId() { + java.lang.Object ref = taskId_; + if (!(ref instanceof java.lang.String)) { + com.google.protobuf.ByteString bs = + (com.google.protobuf.ByteString) ref; + java.lang.String s = bs.toStringUtf8(); + if (bs.isValidUtf8()) { + taskId_ = s; + } + return s; + } else { + return (java.lang.String) ref; + } + } + /** + * required string task_id = 5; + */ + public com.google.protobuf.ByteString + getTaskIdBytes() { + java.lang.Object ref = taskId_; + if (ref instanceof String) { + com.google.protobuf.ByteString b = + com.google.protobuf.ByteString.copyFromUtf8( + (java.lang.String) ref); + taskId_ = b; + return b; + } else { + return (com.google.protobuf.ByteString) ref; + } + } + /** + * required string task_id = 5; + */ + public Builder setTaskId( + java.lang.String value) { + if (value == null) { + throw new NullPointerException(); + } + bitField0_ |= 0x00000010; + taskId_ = value; + + return this; + } + /** + * required string task_id = 5; + */ + public Builder clearTaskId() { + bitField0_ = (bitField0_ & ~0x00000010); + taskId_ = getDefaultInstance().getTaskId(); + + return this; + } + /** + * required string task_id = 5; + */ + public Builder setTaskIdBytes( + com.google.protobuf.ByteString value) { + if (value == null) { + throw new NullPointerException(); + } + bitField0_ |= 0x00000010; + taskId_ = value; + + return this; + } + + private java.util.List ipAddrList_ = + java.util.Collections.emptyList(); + private void ensureIpAddrListIsMutable() { + if (!((bitField0_ & 0x00000020) == 0x00000020)) { + ipAddrList_ = new java.util.ArrayList(ipAddrList_); + bitField0_ |= 0x00000020; + } + } + + /** + * repeated .IM.BaseDefine.IpAddr ip_addr_list = 6; + */ + public java.util.List getIpAddrListList() { + return java.util.Collections.unmodifiableList(ipAddrList_); + } + /** + * repeated .IM.BaseDefine.IpAddr ip_addr_list = 6; + */ + public int getIpAddrListCount() { + return ipAddrList_.size(); + } + /** + * repeated .IM.BaseDefine.IpAddr ip_addr_list = 6; + */ + public com.mogujie.tt.protobuf.IMBaseDefine.IpAddr getIpAddrList(int index) { + return ipAddrList_.get(index); + } + /** + * repeated .IM.BaseDefine.IpAddr ip_addr_list = 6; + */ + public Builder setIpAddrList( + int index, com.mogujie.tt.protobuf.IMBaseDefine.IpAddr value) { + if (value == null) { + throw new NullPointerException(); + } + ensureIpAddrListIsMutable(); + ipAddrList_.set(index, value); + + return this; + } + /** + * repeated .IM.BaseDefine.IpAddr ip_addr_list = 6; + */ + public Builder setIpAddrList( + int index, com.mogujie.tt.protobuf.IMBaseDefine.IpAddr.Builder builderForValue) { + ensureIpAddrListIsMutable(); + ipAddrList_.set(index, builderForValue.build()); + + return this; + } + /** + * repeated .IM.BaseDefine.IpAddr ip_addr_list = 6; + */ + public Builder addIpAddrList(com.mogujie.tt.protobuf.IMBaseDefine.IpAddr value) { + if (value == null) { + throw new NullPointerException(); + } + ensureIpAddrListIsMutable(); + ipAddrList_.add(value); + + return this; + } + /** + * repeated .IM.BaseDefine.IpAddr ip_addr_list = 6; + */ + public Builder addIpAddrList( + int index, com.mogujie.tt.protobuf.IMBaseDefine.IpAddr value) { + if (value == null) { + throw new NullPointerException(); + } + ensureIpAddrListIsMutable(); + ipAddrList_.add(index, value); + + return this; + } + /** + * repeated .IM.BaseDefine.IpAddr ip_addr_list = 6; + */ + public Builder addIpAddrList( + com.mogujie.tt.protobuf.IMBaseDefine.IpAddr.Builder builderForValue) { + ensureIpAddrListIsMutable(); + ipAddrList_.add(builderForValue.build()); + + return this; + } + /** + * repeated .IM.BaseDefine.IpAddr ip_addr_list = 6; + */ + public Builder addIpAddrList( + int index, com.mogujie.tt.protobuf.IMBaseDefine.IpAddr.Builder builderForValue) { + ensureIpAddrListIsMutable(); + ipAddrList_.add(index, builderForValue.build()); + + return this; + } + /** + * repeated .IM.BaseDefine.IpAddr ip_addr_list = 6; + */ + public Builder addAllIpAddrList( + java.lang.Iterable values) { + ensureIpAddrListIsMutable(); + com.google.protobuf.AbstractMessageLite.Builder.addAll( + values, ipAddrList_); + + return this; + } + /** + * repeated .IM.BaseDefine.IpAddr ip_addr_list = 6; + */ + public Builder clearIpAddrList() { + ipAddrList_ = java.util.Collections.emptyList(); + bitField0_ = (bitField0_ & ~0x00000020); + + return this; + } + /** + * repeated .IM.BaseDefine.IpAddr ip_addr_list = 6; + */ + public Builder removeIpAddrList(int index) { + ensureIpAddrListIsMutable(); + ipAddrList_.remove(index); + + return this; + } + + private com.mogujie.tt.protobuf.IMBaseDefine.FileType transMode_ = com.mogujie.tt.protobuf.IMBaseDefine.FileType.FILE_TYPE_ONLINE; + /** + * required .IM.BaseDefine.FileType trans_mode = 7; + */ + public boolean hasTransMode() { + return ((bitField0_ & 0x00000040) == 0x00000040); + } + /** + * required .IM.BaseDefine.FileType trans_mode = 7; + */ + public com.mogujie.tt.protobuf.IMBaseDefine.FileType getTransMode() { + return transMode_; + } + /** + * required .IM.BaseDefine.FileType trans_mode = 7; + */ + public Builder setTransMode(com.mogujie.tt.protobuf.IMBaseDefine.FileType value) { + if (value == null) { + throw new NullPointerException(); + } + bitField0_ |= 0x00000040; + transMode_ = value; + + return this; + } + /** + * required .IM.BaseDefine.FileType trans_mode = 7; + */ + public Builder clearTransMode() { + bitField0_ = (bitField0_ & ~0x00000040); + transMode_ = com.mogujie.tt.protobuf.IMBaseDefine.FileType.FILE_TYPE_ONLINE; + + return this; + } + + // @@protoc_insertion_point(builder_scope:IM.File.IMFileRsp) + } + + static { + defaultInstance = new IMFileRsp(true); + defaultInstance.initFields(); + } + + // @@protoc_insertion_point(class_scope:IM.File.IMFileRsp) + } + + public interface IMFileNotifyOrBuilder extends + // @@protoc_insertion_point(interface_extends:IM.File.IMFileNotify) + com.google.protobuf.MessageLiteOrBuilder { + + /** + * required uint32 from_user_id = 1; + * + *
+     *cmd id: 	0x0508
+     * 
+ */ + boolean hasFromUserId(); + /** + * required uint32 from_user_id = 1; + * + *
+     *cmd id: 	0x0508
+     * 
+ */ + int getFromUserId(); + + /** + * required uint32 to_user_id = 2; + */ + boolean hasToUserId(); + /** + * required uint32 to_user_id = 2; + */ + int getToUserId(); + + /** + * required string file_name = 3; + */ + boolean hasFileName(); + /** + * required string file_name = 3; + */ + java.lang.String getFileName(); + /** + * required string file_name = 3; + */ + com.google.protobuf.ByteString + getFileNameBytes(); + + /** + * required uint32 file_size = 4; + */ + boolean hasFileSize(); + /** + * required uint32 file_size = 4; + */ + int getFileSize(); + + /** + * required string task_id = 5; + */ + boolean hasTaskId(); + /** + * required string task_id = 5; + */ + java.lang.String getTaskId(); + /** + * required string task_id = 5; + */ + com.google.protobuf.ByteString + getTaskIdBytes(); + + /** + * repeated .IM.BaseDefine.IpAddr ip_addr_list = 6; + */ + java.util.List + getIpAddrListList(); + /** + * repeated .IM.BaseDefine.IpAddr ip_addr_list = 6; + */ + com.mogujie.tt.protobuf.IMBaseDefine.IpAddr getIpAddrList(int index); + /** + * repeated .IM.BaseDefine.IpAddr ip_addr_list = 6; + */ + int getIpAddrListCount(); + + /** + * required .IM.BaseDefine.FileType trans_mode = 7; + */ + boolean hasTransMode(); + /** + * required .IM.BaseDefine.FileType trans_mode = 7; + */ + com.mogujie.tt.protobuf.IMBaseDefine.FileType getTransMode(); + + /** + * required uint32 offline_ready = 8; + * + *
+     *1:True 0:False
+     * 
+ */ + boolean hasOfflineReady(); + /** + * required uint32 offline_ready = 8; + * + *
+     *1:True 0:False
+     * 
+ */ + int getOfflineReady(); + } + /** + * Protobuf type {@code IM.File.IMFileNotify} + */ + public static final class IMFileNotify extends + com.google.protobuf.GeneratedMessageLite implements + // @@protoc_insertion_point(message_implements:IM.File.IMFileNotify) + IMFileNotifyOrBuilder { + // Use IMFileNotify.newBuilder() to construct. + private IMFileNotify(com.google.protobuf.GeneratedMessageLite.Builder builder) { + super(builder); + this.unknownFields = builder.getUnknownFields(); + } + private IMFileNotify(boolean noInit) { this.unknownFields = com.google.protobuf.ByteString.EMPTY;} + + private static final IMFileNotify defaultInstance; + public static IMFileNotify getDefaultInstance() { + return defaultInstance; + } + + public IMFileNotify getDefaultInstanceForType() { + return defaultInstance; + } + + private final com.google.protobuf.ByteString unknownFields; + private IMFileNotify( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + initFields(); + int mutable_bitField0_ = 0; + com.google.protobuf.ByteString.Output unknownFieldsOutput = + com.google.protobuf.ByteString.newOutput(); + com.google.protobuf.CodedOutputStream unknownFieldsCodedOutput = + com.google.protobuf.CodedOutputStream.newInstance( + unknownFieldsOutput); + try { + boolean done = false; + while (!done) { + int tag = input.readTag(); + switch (tag) { + case 0: + done = true; + break; + default: { + if (!parseUnknownField(input, unknownFieldsCodedOutput, + extensionRegistry, tag)) { + done = true; + } + break; + } + case 8: { + bitField0_ |= 0x00000001; + fromUserId_ = input.readUInt32(); + break; + } + case 16: { + bitField0_ |= 0x00000002; + toUserId_ = input.readUInt32(); + break; + } + case 26: { + com.google.protobuf.ByteString bs = input.readBytes(); + bitField0_ |= 0x00000004; + fileName_ = bs; + break; + } + case 32: { + bitField0_ |= 0x00000008; + fileSize_ = input.readUInt32(); + break; + } + case 42: { + com.google.protobuf.ByteString bs = input.readBytes(); + bitField0_ |= 0x00000010; + taskId_ = bs; + break; + } + case 50: { + if (!((mutable_bitField0_ & 0x00000020) == 0x00000020)) { + ipAddrList_ = new java.util.ArrayList(); + mutable_bitField0_ |= 0x00000020; + } + ipAddrList_.add(input.readMessage(com.mogujie.tt.protobuf.IMBaseDefine.IpAddr.PARSER, extensionRegistry)); + break; + } + case 56: { + int rawValue = input.readEnum(); + com.mogujie.tt.protobuf.IMBaseDefine.FileType value = com.mogujie.tt.protobuf.IMBaseDefine.FileType.valueOf(rawValue); + if (value == null) { + unknownFieldsCodedOutput.writeRawVarint32(tag); + unknownFieldsCodedOutput.writeRawVarint32(rawValue); + } else { + bitField0_ |= 0x00000020; + transMode_ = value; + } + break; + } + case 64: { + bitField0_ |= 0x00000040; + offlineReady_ = input.readUInt32(); + break; + } + } + } + } catch (com.google.protobuf.InvalidProtocolBufferException e) { + throw e.setUnfinishedMessage(this); + } catch (java.io.IOException e) { + throw new com.google.protobuf.InvalidProtocolBufferException( + e.getMessage()).setUnfinishedMessage(this); + } finally { + if (((mutable_bitField0_ & 0x00000020) == 0x00000020)) { + ipAddrList_ = java.util.Collections.unmodifiableList(ipAddrList_); + } + try { + unknownFieldsCodedOutput.flush(); + } catch (java.io.IOException e) { + // Should not happen + } finally { + unknownFields = unknownFieldsOutput.toByteString(); + } + makeExtensionsImmutable(); + } + } + public static com.google.protobuf.Parser PARSER = + new com.google.protobuf.AbstractParser() { + public IMFileNotify parsePartialFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return new IMFileNotify(input, extensionRegistry); + } + }; + + @java.lang.Override + public com.google.protobuf.Parser getParserForType() { + return PARSER; + } + + private int bitField0_; + public static final int FROM_USER_ID_FIELD_NUMBER = 1; + private int fromUserId_; + /** + * required uint32 from_user_id = 1; + * + *
+     *cmd id: 	0x0508
+     * 
+ */ + public boolean hasFromUserId() { + return ((bitField0_ & 0x00000001) == 0x00000001); + } + /** + * required uint32 from_user_id = 1; + * + *
+     *cmd id: 	0x0508
+     * 
+ */ + public int getFromUserId() { + return fromUserId_; + } + + public static final int TO_USER_ID_FIELD_NUMBER = 2; + private int toUserId_; + /** + * required uint32 to_user_id = 2; + */ + public boolean hasToUserId() { + return ((bitField0_ & 0x00000002) == 0x00000002); + } + /** + * required uint32 to_user_id = 2; + */ + public int getToUserId() { + return toUserId_; + } + + public static final int FILE_NAME_FIELD_NUMBER = 3; + private java.lang.Object fileName_; + /** + * required string file_name = 3; + */ + public boolean hasFileName() { + return ((bitField0_ & 0x00000004) == 0x00000004); + } + /** + * required string file_name = 3; + */ + public java.lang.String getFileName() { + java.lang.Object ref = fileName_; + if (ref instanceof java.lang.String) { + return (java.lang.String) ref; + } else { + com.google.protobuf.ByteString bs = + (com.google.protobuf.ByteString) ref; + java.lang.String s = bs.toStringUtf8(); + if (bs.isValidUtf8()) { + fileName_ = s; + } + return s; + } + } + /** + * required string file_name = 3; + */ + public com.google.protobuf.ByteString + getFileNameBytes() { + java.lang.Object ref = fileName_; + if (ref instanceof java.lang.String) { + com.google.protobuf.ByteString b = + com.google.protobuf.ByteString.copyFromUtf8( + (java.lang.String) ref); + fileName_ = b; + return b; + } else { + return (com.google.protobuf.ByteString) ref; + } + } + + public static final int FILE_SIZE_FIELD_NUMBER = 4; + private int fileSize_; + /** + * required uint32 file_size = 4; + */ + public boolean hasFileSize() { + return ((bitField0_ & 0x00000008) == 0x00000008); + } + /** + * required uint32 file_size = 4; + */ + public int getFileSize() { + return fileSize_; + } + + public static final int TASK_ID_FIELD_NUMBER = 5; + private java.lang.Object taskId_; + /** + * required string task_id = 5; + */ + public boolean hasTaskId() { + return ((bitField0_ & 0x00000010) == 0x00000010); + } + /** + * required string task_id = 5; + */ + public java.lang.String getTaskId() { + java.lang.Object ref = taskId_; + if (ref instanceof java.lang.String) { + return (java.lang.String) ref; + } else { + com.google.protobuf.ByteString bs = + (com.google.protobuf.ByteString) ref; + java.lang.String s = bs.toStringUtf8(); + if (bs.isValidUtf8()) { + taskId_ = s; + } + return s; + } + } + /** + * required string task_id = 5; + */ + public com.google.protobuf.ByteString + getTaskIdBytes() { + java.lang.Object ref = taskId_; + if (ref instanceof java.lang.String) { + com.google.protobuf.ByteString b = + com.google.protobuf.ByteString.copyFromUtf8( + (java.lang.String) ref); + taskId_ = b; + return b; + } else { + return (com.google.protobuf.ByteString) ref; + } + } + + public static final int IP_ADDR_LIST_FIELD_NUMBER = 6; + private java.util.List ipAddrList_; + /** + * repeated .IM.BaseDefine.IpAddr ip_addr_list = 6; + */ + public java.util.List getIpAddrListList() { + return ipAddrList_; + } + /** + * repeated .IM.BaseDefine.IpAddr ip_addr_list = 6; + */ + public java.util.List + getIpAddrListOrBuilderList() { + return ipAddrList_; + } + /** + * repeated .IM.BaseDefine.IpAddr ip_addr_list = 6; + */ + public int getIpAddrListCount() { + return ipAddrList_.size(); + } + /** + * repeated .IM.BaseDefine.IpAddr ip_addr_list = 6; + */ + public com.mogujie.tt.protobuf.IMBaseDefine.IpAddr getIpAddrList(int index) { + return ipAddrList_.get(index); + } + /** + * repeated .IM.BaseDefine.IpAddr ip_addr_list = 6; + */ + public com.mogujie.tt.protobuf.IMBaseDefine.IpAddrOrBuilder getIpAddrListOrBuilder( + int index) { + return ipAddrList_.get(index); + } + + public static final int TRANS_MODE_FIELD_NUMBER = 7; + private com.mogujie.tt.protobuf.IMBaseDefine.FileType transMode_; + /** + * required .IM.BaseDefine.FileType trans_mode = 7; + */ + public boolean hasTransMode() { + return ((bitField0_ & 0x00000020) == 0x00000020); + } + /** + * required .IM.BaseDefine.FileType trans_mode = 7; + */ + public com.mogujie.tt.protobuf.IMBaseDefine.FileType getTransMode() { + return transMode_; + } + + public static final int OFFLINE_READY_FIELD_NUMBER = 8; + private int offlineReady_; + /** + * required uint32 offline_ready = 8; + * + *
+     *1:True 0:False
+     * 
+ */ + public boolean hasOfflineReady() { + return ((bitField0_ & 0x00000040) == 0x00000040); + } + /** + * required uint32 offline_ready = 8; + * + *
+     *1:True 0:False
+     * 
+ */ + public int getOfflineReady() { + return offlineReady_; + } + + private void initFields() { + fromUserId_ = 0; + toUserId_ = 0; + fileName_ = ""; + fileSize_ = 0; + taskId_ = ""; + ipAddrList_ = java.util.Collections.emptyList(); + transMode_ = com.mogujie.tt.protobuf.IMBaseDefine.FileType.FILE_TYPE_ONLINE; + offlineReady_ = 0; + } + private byte memoizedIsInitialized = -1; + public final boolean isInitialized() { + byte isInitialized = memoizedIsInitialized; + if (isInitialized == 1) return true; + if (isInitialized == 0) return false; + + if (!hasFromUserId()) { + memoizedIsInitialized = 0; + return false; + } + if (!hasToUserId()) { + memoizedIsInitialized = 0; + return false; + } + if (!hasFileName()) { + memoizedIsInitialized = 0; + return false; + } + if (!hasFileSize()) { + memoizedIsInitialized = 0; + return false; + } + if (!hasTaskId()) { + memoizedIsInitialized = 0; + return false; + } + if (!hasTransMode()) { + memoizedIsInitialized = 0; + return false; + } + if (!hasOfflineReady()) { + memoizedIsInitialized = 0; + return false; + } + for (int i = 0; i < getIpAddrListCount(); i++) { + if (!getIpAddrList(i).isInitialized()) { + memoizedIsInitialized = 0; + return false; + } + } + memoizedIsInitialized = 1; + return true; + } + + public void writeTo(com.google.protobuf.CodedOutputStream output) + throws java.io.IOException { + getSerializedSize(); + if (((bitField0_ & 0x00000001) == 0x00000001)) { + output.writeUInt32(1, fromUserId_); + } + if (((bitField0_ & 0x00000002) == 0x00000002)) { + output.writeUInt32(2, toUserId_); + } + if (((bitField0_ & 0x00000004) == 0x00000004)) { + output.writeBytes(3, getFileNameBytes()); + } + if (((bitField0_ & 0x00000008) == 0x00000008)) { + output.writeUInt32(4, fileSize_); + } + if (((bitField0_ & 0x00000010) == 0x00000010)) { + output.writeBytes(5, getTaskIdBytes()); + } + for (int i = 0; i < ipAddrList_.size(); i++) { + output.writeMessage(6, ipAddrList_.get(i)); + } + if (((bitField0_ & 0x00000020) == 0x00000020)) { + output.writeEnum(7, transMode_.getNumber()); + } + if (((bitField0_ & 0x00000040) == 0x00000040)) { + output.writeUInt32(8, offlineReady_); + } + output.writeRawBytes(unknownFields); + } + + private int memoizedSerializedSize = -1; + public int getSerializedSize() { + int size = memoizedSerializedSize; + if (size != -1) return size; + + size = 0; + if (((bitField0_ & 0x00000001) == 0x00000001)) { + size += com.google.protobuf.CodedOutputStream + .computeUInt32Size(1, fromUserId_); + } + if (((bitField0_ & 0x00000002) == 0x00000002)) { + size += com.google.protobuf.CodedOutputStream + .computeUInt32Size(2, toUserId_); + } + if (((bitField0_ & 0x00000004) == 0x00000004)) { + size += com.google.protobuf.CodedOutputStream + .computeBytesSize(3, getFileNameBytes()); + } + if (((bitField0_ & 0x00000008) == 0x00000008)) { + size += com.google.protobuf.CodedOutputStream + .computeUInt32Size(4, fileSize_); + } + if (((bitField0_ & 0x00000010) == 0x00000010)) { + size += com.google.protobuf.CodedOutputStream + .computeBytesSize(5, getTaskIdBytes()); + } + for (int i = 0; i < ipAddrList_.size(); i++) { + size += com.google.protobuf.CodedOutputStream + .computeMessageSize(6, ipAddrList_.get(i)); + } + if (((bitField0_ & 0x00000020) == 0x00000020)) { + size += com.google.protobuf.CodedOutputStream + .computeEnumSize(7, transMode_.getNumber()); + } + if (((bitField0_ & 0x00000040) == 0x00000040)) { + size += com.google.protobuf.CodedOutputStream + .computeUInt32Size(8, offlineReady_); + } + size += unknownFields.size(); + memoizedSerializedSize = size; + return size; + } + + private static final long serialVersionUID = 0L; + @java.lang.Override + protected java.lang.Object writeReplace() + throws java.io.ObjectStreamException { + return super.writeReplace(); + } + + public static com.mogujie.tt.protobuf.IMFile.IMFileNotify parseFrom( + com.google.protobuf.ByteString data) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data); + } + public static com.mogujie.tt.protobuf.IMFile.IMFileNotify parseFrom( + com.google.protobuf.ByteString data, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data, extensionRegistry); + } + public static com.mogujie.tt.protobuf.IMFile.IMFileNotify parseFrom(byte[] data) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data); + } + public static com.mogujie.tt.protobuf.IMFile.IMFileNotify parseFrom( + byte[] data, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data, extensionRegistry); + } + public static com.mogujie.tt.protobuf.IMFile.IMFileNotify parseFrom(java.io.InputStream input) + throws java.io.IOException { + return PARSER.parseFrom(input); + } + public static com.mogujie.tt.protobuf.IMFile.IMFileNotify parseFrom( + java.io.InputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return PARSER.parseFrom(input, extensionRegistry); + } + public static com.mogujie.tt.protobuf.IMFile.IMFileNotify parseDelimitedFrom(java.io.InputStream input) + throws java.io.IOException { + return PARSER.parseDelimitedFrom(input); + } + public static com.mogujie.tt.protobuf.IMFile.IMFileNotify parseDelimitedFrom( + java.io.InputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return PARSER.parseDelimitedFrom(input, extensionRegistry); + } + public static com.mogujie.tt.protobuf.IMFile.IMFileNotify parseFrom( + com.google.protobuf.CodedInputStream input) + throws java.io.IOException { + return PARSER.parseFrom(input); + } + public static com.mogujie.tt.protobuf.IMFile.IMFileNotify parseFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return PARSER.parseFrom(input, extensionRegistry); + } + + public static Builder newBuilder() { return Builder.create(); } + public Builder newBuilderForType() { return newBuilder(); } + public static Builder newBuilder(com.mogujie.tt.protobuf.IMFile.IMFileNotify prototype) { + return newBuilder().mergeFrom(prototype); + } + public Builder toBuilder() { return newBuilder(this); } + + /** + * Protobuf type {@code IM.File.IMFileNotify} + */ + public static final class Builder extends + com.google.protobuf.GeneratedMessageLite.Builder< + com.mogujie.tt.protobuf.IMFile.IMFileNotify, Builder> + implements + // @@protoc_insertion_point(builder_implements:IM.File.IMFileNotify) + com.mogujie.tt.protobuf.IMFile.IMFileNotifyOrBuilder { + // Construct using com.mogujie.tt.protobuf.IMFile.IMFileNotify.newBuilder() + private Builder() { + maybeForceBuilderInitialization(); + } + + private void maybeForceBuilderInitialization() { + } + private static Builder create() { + return new Builder(); + } + + public Builder clear() { + super.clear(); + fromUserId_ = 0; + bitField0_ = (bitField0_ & ~0x00000001); + toUserId_ = 0; + bitField0_ = (bitField0_ & ~0x00000002); + fileName_ = ""; + bitField0_ = (bitField0_ & ~0x00000004); + fileSize_ = 0; + bitField0_ = (bitField0_ & ~0x00000008); + taskId_ = ""; + bitField0_ = (bitField0_ & ~0x00000010); + ipAddrList_ = java.util.Collections.emptyList(); + bitField0_ = (bitField0_ & ~0x00000020); + transMode_ = com.mogujie.tt.protobuf.IMBaseDefine.FileType.FILE_TYPE_ONLINE; + bitField0_ = (bitField0_ & ~0x00000040); + offlineReady_ = 0; + bitField0_ = (bitField0_ & ~0x00000080); + return this; + } + + public Builder clone() { + return create().mergeFrom(buildPartial()); + } + + public com.mogujie.tt.protobuf.IMFile.IMFileNotify getDefaultInstanceForType() { + return com.mogujie.tt.protobuf.IMFile.IMFileNotify.getDefaultInstance(); + } + + public com.mogujie.tt.protobuf.IMFile.IMFileNotify build() { + com.mogujie.tt.protobuf.IMFile.IMFileNotify result = buildPartial(); + if (!result.isInitialized()) { + throw newUninitializedMessageException(result); + } + return result; + } + + public com.mogujie.tt.protobuf.IMFile.IMFileNotify buildPartial() { + com.mogujie.tt.protobuf.IMFile.IMFileNotify result = new com.mogujie.tt.protobuf.IMFile.IMFileNotify(this); + int from_bitField0_ = bitField0_; + int to_bitField0_ = 0; + if (((from_bitField0_ & 0x00000001) == 0x00000001)) { + to_bitField0_ |= 0x00000001; + } + result.fromUserId_ = fromUserId_; + if (((from_bitField0_ & 0x00000002) == 0x00000002)) { + to_bitField0_ |= 0x00000002; + } + result.toUserId_ = toUserId_; + if (((from_bitField0_ & 0x00000004) == 0x00000004)) { + to_bitField0_ |= 0x00000004; + } + result.fileName_ = fileName_; + if (((from_bitField0_ & 0x00000008) == 0x00000008)) { + to_bitField0_ |= 0x00000008; + } + result.fileSize_ = fileSize_; + if (((from_bitField0_ & 0x00000010) == 0x00000010)) { + to_bitField0_ |= 0x00000010; + } + result.taskId_ = taskId_; + if (((bitField0_ & 0x00000020) == 0x00000020)) { + ipAddrList_ = java.util.Collections.unmodifiableList(ipAddrList_); + bitField0_ = (bitField0_ & ~0x00000020); + } + result.ipAddrList_ = ipAddrList_; + if (((from_bitField0_ & 0x00000040) == 0x00000040)) { + to_bitField0_ |= 0x00000020; + } + result.transMode_ = transMode_; + if (((from_bitField0_ & 0x00000080) == 0x00000080)) { + to_bitField0_ |= 0x00000040; + } + result.offlineReady_ = offlineReady_; + result.bitField0_ = to_bitField0_; + return result; + } + + public Builder mergeFrom(com.mogujie.tt.protobuf.IMFile.IMFileNotify other) { + if (other == com.mogujie.tt.protobuf.IMFile.IMFileNotify.getDefaultInstance()) return this; + if (other.hasFromUserId()) { + setFromUserId(other.getFromUserId()); + } + if (other.hasToUserId()) { + setToUserId(other.getToUserId()); + } + if (other.hasFileName()) { + bitField0_ |= 0x00000004; + fileName_ = other.fileName_; + + } + if (other.hasFileSize()) { + setFileSize(other.getFileSize()); + } + if (other.hasTaskId()) { + bitField0_ |= 0x00000010; + taskId_ = other.taskId_; + + } + if (!other.ipAddrList_.isEmpty()) { + if (ipAddrList_.isEmpty()) { + ipAddrList_ = other.ipAddrList_; + bitField0_ = (bitField0_ & ~0x00000020); + } else { + ensureIpAddrListIsMutable(); + ipAddrList_.addAll(other.ipAddrList_); + } + + } + if (other.hasTransMode()) { + setTransMode(other.getTransMode()); + } + if (other.hasOfflineReady()) { + setOfflineReady(other.getOfflineReady()); + } + setUnknownFields( + getUnknownFields().concat(other.unknownFields)); + return this; + } + + public final boolean isInitialized() { + if (!hasFromUserId()) { + + return false; + } + if (!hasToUserId()) { + + return false; + } + if (!hasFileName()) { + + return false; + } + if (!hasFileSize()) { + + return false; + } + if (!hasTaskId()) { + + return false; + } + if (!hasTransMode()) { + + return false; + } + if (!hasOfflineReady()) { + + return false; + } + for (int i = 0; i < getIpAddrListCount(); i++) { + if (!getIpAddrList(i).isInitialized()) { + + return false; + } + } + return true; + } + + public Builder mergeFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + com.mogujie.tt.protobuf.IMFile.IMFileNotify parsedMessage = null; + try { + parsedMessage = PARSER.parsePartialFrom(input, extensionRegistry); + } catch (com.google.protobuf.InvalidProtocolBufferException e) { + parsedMessage = (com.mogujie.tt.protobuf.IMFile.IMFileNotify) e.getUnfinishedMessage(); + throw e; + } finally { + if (parsedMessage != null) { + mergeFrom(parsedMessage); + } + } + return this; + } + private int bitField0_; + + private int fromUserId_ ; + /** + * required uint32 from_user_id = 1; + * + *
+       *cmd id: 	0x0508
+       * 
+ */ + public boolean hasFromUserId() { + return ((bitField0_ & 0x00000001) == 0x00000001); + } + /** + * required uint32 from_user_id = 1; + * + *
+       *cmd id: 	0x0508
+       * 
+ */ + public int getFromUserId() { + return fromUserId_; + } + /** + * required uint32 from_user_id = 1; + * + *
+       *cmd id: 	0x0508
+       * 
+ */ + public Builder setFromUserId(int value) { + bitField0_ |= 0x00000001; + fromUserId_ = value; + + return this; + } + /** + * required uint32 from_user_id = 1; + * + *
+       *cmd id: 	0x0508
+       * 
+ */ + public Builder clearFromUserId() { + bitField0_ = (bitField0_ & ~0x00000001); + fromUserId_ = 0; + + return this; + } + + private int toUserId_ ; + /** + * required uint32 to_user_id = 2; + */ + public boolean hasToUserId() { + return ((bitField0_ & 0x00000002) == 0x00000002); + } + /** + * required uint32 to_user_id = 2; + */ + public int getToUserId() { + return toUserId_; + } + /** + * required uint32 to_user_id = 2; + */ + public Builder setToUserId(int value) { + bitField0_ |= 0x00000002; + toUserId_ = value; + + return this; + } + /** + * required uint32 to_user_id = 2; + */ + public Builder clearToUserId() { + bitField0_ = (bitField0_ & ~0x00000002); + toUserId_ = 0; + + return this; + } + + private java.lang.Object fileName_ = ""; + /** + * required string file_name = 3; + */ + public boolean hasFileName() { + return ((bitField0_ & 0x00000004) == 0x00000004); + } + /** + * required string file_name = 3; + */ + public java.lang.String getFileName() { + java.lang.Object ref = fileName_; + if (!(ref instanceof java.lang.String)) { + com.google.protobuf.ByteString bs = + (com.google.protobuf.ByteString) ref; + java.lang.String s = bs.toStringUtf8(); + if (bs.isValidUtf8()) { + fileName_ = s; + } + return s; + } else { + return (java.lang.String) ref; + } + } + /** + * required string file_name = 3; + */ + public com.google.protobuf.ByteString + getFileNameBytes() { + java.lang.Object ref = fileName_; + if (ref instanceof String) { + com.google.protobuf.ByteString b = + com.google.protobuf.ByteString.copyFromUtf8( + (java.lang.String) ref); + fileName_ = b; + return b; + } else { + return (com.google.protobuf.ByteString) ref; + } + } + /** + * required string file_name = 3; + */ + public Builder setFileName( + java.lang.String value) { + if (value == null) { + throw new NullPointerException(); + } + bitField0_ |= 0x00000004; + fileName_ = value; + + return this; + } + /** + * required string file_name = 3; + */ + public Builder clearFileName() { + bitField0_ = (bitField0_ & ~0x00000004); + fileName_ = getDefaultInstance().getFileName(); + + return this; + } + /** + * required string file_name = 3; + */ + public Builder setFileNameBytes( + com.google.protobuf.ByteString value) { + if (value == null) { + throw new NullPointerException(); + } + bitField0_ |= 0x00000004; + fileName_ = value; + + return this; + } + + private int fileSize_ ; + /** + * required uint32 file_size = 4; + */ + public boolean hasFileSize() { + return ((bitField0_ & 0x00000008) == 0x00000008); + } + /** + * required uint32 file_size = 4; + */ + public int getFileSize() { + return fileSize_; + } + /** + * required uint32 file_size = 4; + */ + public Builder setFileSize(int value) { + bitField0_ |= 0x00000008; + fileSize_ = value; + + return this; + } + /** + * required uint32 file_size = 4; + */ + public Builder clearFileSize() { + bitField0_ = (bitField0_ & ~0x00000008); + fileSize_ = 0; + + return this; + } + + private java.lang.Object taskId_ = ""; + /** + * required string task_id = 5; + */ + public boolean hasTaskId() { + return ((bitField0_ & 0x00000010) == 0x00000010); + } + /** + * required string task_id = 5; + */ + public java.lang.String getTaskId() { + java.lang.Object ref = taskId_; + if (!(ref instanceof java.lang.String)) { + com.google.protobuf.ByteString bs = + (com.google.protobuf.ByteString) ref; + java.lang.String s = bs.toStringUtf8(); + if (bs.isValidUtf8()) { + taskId_ = s; + } + return s; + } else { + return (java.lang.String) ref; + } + } + /** + * required string task_id = 5; + */ + public com.google.protobuf.ByteString + getTaskIdBytes() { + java.lang.Object ref = taskId_; + if (ref instanceof String) { + com.google.protobuf.ByteString b = + com.google.protobuf.ByteString.copyFromUtf8( + (java.lang.String) ref); + taskId_ = b; + return b; + } else { + return (com.google.protobuf.ByteString) ref; + } + } + /** + * required string task_id = 5; + */ + public Builder setTaskId( + java.lang.String value) { + if (value == null) { + throw new NullPointerException(); + } + bitField0_ |= 0x00000010; + taskId_ = value; + + return this; + } + /** + * required string task_id = 5; + */ + public Builder clearTaskId() { + bitField0_ = (bitField0_ & ~0x00000010); + taskId_ = getDefaultInstance().getTaskId(); + + return this; + } + /** + * required string task_id = 5; + */ + public Builder setTaskIdBytes( + com.google.protobuf.ByteString value) { + if (value == null) { + throw new NullPointerException(); + } + bitField0_ |= 0x00000010; + taskId_ = value; + + return this; + } + + private java.util.List ipAddrList_ = + java.util.Collections.emptyList(); + private void ensureIpAddrListIsMutable() { + if (!((bitField0_ & 0x00000020) == 0x00000020)) { + ipAddrList_ = new java.util.ArrayList(ipAddrList_); + bitField0_ |= 0x00000020; + } + } + + /** + * repeated .IM.BaseDefine.IpAddr ip_addr_list = 6; + */ + public java.util.List getIpAddrListList() { + return java.util.Collections.unmodifiableList(ipAddrList_); + } + /** + * repeated .IM.BaseDefine.IpAddr ip_addr_list = 6; + */ + public int getIpAddrListCount() { + return ipAddrList_.size(); + } + /** + * repeated .IM.BaseDefine.IpAddr ip_addr_list = 6; + */ + public com.mogujie.tt.protobuf.IMBaseDefine.IpAddr getIpAddrList(int index) { + return ipAddrList_.get(index); + } + /** + * repeated .IM.BaseDefine.IpAddr ip_addr_list = 6; + */ + public Builder setIpAddrList( + int index, com.mogujie.tt.protobuf.IMBaseDefine.IpAddr value) { + if (value == null) { + throw new NullPointerException(); + } + ensureIpAddrListIsMutable(); + ipAddrList_.set(index, value); + + return this; + } + /** + * repeated .IM.BaseDefine.IpAddr ip_addr_list = 6; + */ + public Builder setIpAddrList( + int index, com.mogujie.tt.protobuf.IMBaseDefine.IpAddr.Builder builderForValue) { + ensureIpAddrListIsMutable(); + ipAddrList_.set(index, builderForValue.build()); + + return this; + } + /** + * repeated .IM.BaseDefine.IpAddr ip_addr_list = 6; + */ + public Builder addIpAddrList(com.mogujie.tt.protobuf.IMBaseDefine.IpAddr value) { + if (value == null) { + throw new NullPointerException(); + } + ensureIpAddrListIsMutable(); + ipAddrList_.add(value); + + return this; + } + /** + * repeated .IM.BaseDefine.IpAddr ip_addr_list = 6; + */ + public Builder addIpAddrList( + int index, com.mogujie.tt.protobuf.IMBaseDefine.IpAddr value) { + if (value == null) { + throw new NullPointerException(); + } + ensureIpAddrListIsMutable(); + ipAddrList_.add(index, value); + + return this; + } + /** + * repeated .IM.BaseDefine.IpAddr ip_addr_list = 6; + */ + public Builder addIpAddrList( + com.mogujie.tt.protobuf.IMBaseDefine.IpAddr.Builder builderForValue) { + ensureIpAddrListIsMutable(); + ipAddrList_.add(builderForValue.build()); + + return this; + } + /** + * repeated .IM.BaseDefine.IpAddr ip_addr_list = 6; + */ + public Builder addIpAddrList( + int index, com.mogujie.tt.protobuf.IMBaseDefine.IpAddr.Builder builderForValue) { + ensureIpAddrListIsMutable(); + ipAddrList_.add(index, builderForValue.build()); + + return this; + } + /** + * repeated .IM.BaseDefine.IpAddr ip_addr_list = 6; + */ + public Builder addAllIpAddrList( + java.lang.Iterable values) { + ensureIpAddrListIsMutable(); + com.google.protobuf.AbstractMessageLite.Builder.addAll( + values, ipAddrList_); + + return this; + } + /** + * repeated .IM.BaseDefine.IpAddr ip_addr_list = 6; + */ + public Builder clearIpAddrList() { + ipAddrList_ = java.util.Collections.emptyList(); + bitField0_ = (bitField0_ & ~0x00000020); + + return this; + } + /** + * repeated .IM.BaseDefine.IpAddr ip_addr_list = 6; + */ + public Builder removeIpAddrList(int index) { + ensureIpAddrListIsMutable(); + ipAddrList_.remove(index); + + return this; + } + + private com.mogujie.tt.protobuf.IMBaseDefine.FileType transMode_ = com.mogujie.tt.protobuf.IMBaseDefine.FileType.FILE_TYPE_ONLINE; + /** + * required .IM.BaseDefine.FileType trans_mode = 7; + */ + public boolean hasTransMode() { + return ((bitField0_ & 0x00000040) == 0x00000040); + } + /** + * required .IM.BaseDefine.FileType trans_mode = 7; + */ + public com.mogujie.tt.protobuf.IMBaseDefine.FileType getTransMode() { + return transMode_; + } + /** + * required .IM.BaseDefine.FileType trans_mode = 7; + */ + public Builder setTransMode(com.mogujie.tt.protobuf.IMBaseDefine.FileType value) { + if (value == null) { + throw new NullPointerException(); + } + bitField0_ |= 0x00000040; + transMode_ = value; + + return this; + } + /** + * required .IM.BaseDefine.FileType trans_mode = 7; + */ + public Builder clearTransMode() { + bitField0_ = (bitField0_ & ~0x00000040); + transMode_ = com.mogujie.tt.protobuf.IMBaseDefine.FileType.FILE_TYPE_ONLINE; + + return this; + } + + private int offlineReady_ ; + /** + * required uint32 offline_ready = 8; + * + *
+       *1:True 0:False
+       * 
+ */ + public boolean hasOfflineReady() { + return ((bitField0_ & 0x00000080) == 0x00000080); + } + /** + * required uint32 offline_ready = 8; + * + *
+       *1:True 0:False
+       * 
+ */ + public int getOfflineReady() { + return offlineReady_; + } + /** + * required uint32 offline_ready = 8; + * + *
+       *1:True 0:False
+       * 
+ */ + public Builder setOfflineReady(int value) { + bitField0_ |= 0x00000080; + offlineReady_ = value; + + return this; + } + /** + * required uint32 offline_ready = 8; + * + *
+       *1:True 0:False
+       * 
+ */ + public Builder clearOfflineReady() { + bitField0_ = (bitField0_ & ~0x00000080); + offlineReady_ = 0; + + return this; + } + + // @@protoc_insertion_point(builder_scope:IM.File.IMFileNotify) + } + + static { + defaultInstance = new IMFileNotify(true); + defaultInstance.initFields(); + } + + // @@protoc_insertion_point(class_scope:IM.File.IMFileNotify) + } + + public interface IMFileHasOfflineReqOrBuilder extends + // @@protoc_insertion_point(interface_extends:IM.File.IMFileHasOfflineReq) + com.google.protobuf.MessageLiteOrBuilder { + + /** + * required uint32 user_id = 1; + * + *
+     *cmd id: 	0x0509
+     * 
+ */ + boolean hasUserId(); + /** + * required uint32 user_id = 1; + * + *
+     *cmd id: 	0x0509
+     * 
+ */ + int getUserId(); + + /** + * optional bytes attach_data = 20; + */ + boolean hasAttachData(); + /** + * optional bytes attach_data = 20; + */ + com.google.protobuf.ByteString getAttachData(); + } + /** + * Protobuf type {@code IM.File.IMFileHasOfflineReq} + */ + public static final class IMFileHasOfflineReq extends + com.google.protobuf.GeneratedMessageLite implements + // @@protoc_insertion_point(message_implements:IM.File.IMFileHasOfflineReq) + IMFileHasOfflineReqOrBuilder { + // Use IMFileHasOfflineReq.newBuilder() to construct. + private IMFileHasOfflineReq(com.google.protobuf.GeneratedMessageLite.Builder builder) { + super(builder); + this.unknownFields = builder.getUnknownFields(); + } + private IMFileHasOfflineReq(boolean noInit) { this.unknownFields = com.google.protobuf.ByteString.EMPTY;} + + private static final IMFileHasOfflineReq defaultInstance; + public static IMFileHasOfflineReq getDefaultInstance() { + return defaultInstance; + } + + public IMFileHasOfflineReq getDefaultInstanceForType() { + return defaultInstance; + } + + private final com.google.protobuf.ByteString unknownFields; + private IMFileHasOfflineReq( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + initFields(); + int mutable_bitField0_ = 0; + com.google.protobuf.ByteString.Output unknownFieldsOutput = + com.google.protobuf.ByteString.newOutput(); + com.google.protobuf.CodedOutputStream unknownFieldsCodedOutput = + com.google.protobuf.CodedOutputStream.newInstance( + unknownFieldsOutput); + try { + boolean done = false; + while (!done) { + int tag = input.readTag(); + switch (tag) { + case 0: + done = true; + break; + default: { + if (!parseUnknownField(input, unknownFieldsCodedOutput, + extensionRegistry, tag)) { + done = true; + } + break; + } + case 8: { + bitField0_ |= 0x00000001; + userId_ = input.readUInt32(); + break; + } + case 162: { + bitField0_ |= 0x00000002; + attachData_ = input.readBytes(); + break; + } + } + } + } catch (com.google.protobuf.InvalidProtocolBufferException e) { + throw e.setUnfinishedMessage(this); + } catch (java.io.IOException e) { + throw new com.google.protobuf.InvalidProtocolBufferException( + e.getMessage()).setUnfinishedMessage(this); + } finally { + try { + unknownFieldsCodedOutput.flush(); + } catch (java.io.IOException e) { + // Should not happen + } finally { + unknownFields = unknownFieldsOutput.toByteString(); + } + makeExtensionsImmutable(); + } + } + public static com.google.protobuf.Parser PARSER = + new com.google.protobuf.AbstractParser() { + public IMFileHasOfflineReq parsePartialFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return new IMFileHasOfflineReq(input, extensionRegistry); + } + }; + + @java.lang.Override + public com.google.protobuf.Parser getParserForType() { + return PARSER; + } + + private int bitField0_; + public static final int USER_ID_FIELD_NUMBER = 1; + private int userId_; + /** + * required uint32 user_id = 1; + * + *
+     *cmd id: 	0x0509
+     * 
+ */ + public boolean hasUserId() { + return ((bitField0_ & 0x00000001) == 0x00000001); + } + /** + * required uint32 user_id = 1; + * + *
+     *cmd id: 	0x0509
+     * 
+ */ + public int getUserId() { + return userId_; + } + + public static final int ATTACH_DATA_FIELD_NUMBER = 20; + private com.google.protobuf.ByteString attachData_; + /** + * optional bytes attach_data = 20; + */ + public boolean hasAttachData() { + return ((bitField0_ & 0x00000002) == 0x00000002); + } + /** + * optional bytes attach_data = 20; + */ + public com.google.protobuf.ByteString getAttachData() { + return attachData_; + } + + private void initFields() { + userId_ = 0; + attachData_ = com.google.protobuf.ByteString.EMPTY; + } + private byte memoizedIsInitialized = -1; + public final boolean isInitialized() { + byte isInitialized = memoizedIsInitialized; + if (isInitialized == 1) return true; + if (isInitialized == 0) return false; + + if (!hasUserId()) { + memoizedIsInitialized = 0; + return false; + } + memoizedIsInitialized = 1; + return true; + } + + public void writeTo(com.google.protobuf.CodedOutputStream output) + throws java.io.IOException { + getSerializedSize(); + if (((bitField0_ & 0x00000001) == 0x00000001)) { + output.writeUInt32(1, userId_); + } + if (((bitField0_ & 0x00000002) == 0x00000002)) { + output.writeBytes(20, attachData_); + } + output.writeRawBytes(unknownFields); + } + + private int memoizedSerializedSize = -1; + public int getSerializedSize() { + int size = memoizedSerializedSize; + if (size != -1) return size; + + size = 0; + if (((bitField0_ & 0x00000001) == 0x00000001)) { + size += com.google.protobuf.CodedOutputStream + .computeUInt32Size(1, userId_); + } + if (((bitField0_ & 0x00000002) == 0x00000002)) { + size += com.google.protobuf.CodedOutputStream + .computeBytesSize(20, attachData_); + } + size += unknownFields.size(); + memoizedSerializedSize = size; + return size; + } + + private static final long serialVersionUID = 0L; + @java.lang.Override + protected java.lang.Object writeReplace() + throws java.io.ObjectStreamException { + return super.writeReplace(); + } + + public static com.mogujie.tt.protobuf.IMFile.IMFileHasOfflineReq parseFrom( + com.google.protobuf.ByteString data) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data); + } + public static com.mogujie.tt.protobuf.IMFile.IMFileHasOfflineReq parseFrom( + com.google.protobuf.ByteString data, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data, extensionRegistry); + } + public static com.mogujie.tt.protobuf.IMFile.IMFileHasOfflineReq parseFrom(byte[] data) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data); + } + public static com.mogujie.tt.protobuf.IMFile.IMFileHasOfflineReq parseFrom( + byte[] data, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data, extensionRegistry); + } + public static com.mogujie.tt.protobuf.IMFile.IMFileHasOfflineReq parseFrom(java.io.InputStream input) + throws java.io.IOException { + return PARSER.parseFrom(input); + } + public static com.mogujie.tt.protobuf.IMFile.IMFileHasOfflineReq parseFrom( + java.io.InputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return PARSER.parseFrom(input, extensionRegistry); + } + public static com.mogujie.tt.protobuf.IMFile.IMFileHasOfflineReq parseDelimitedFrom(java.io.InputStream input) + throws java.io.IOException { + return PARSER.parseDelimitedFrom(input); + } + public static com.mogujie.tt.protobuf.IMFile.IMFileHasOfflineReq parseDelimitedFrom( + java.io.InputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return PARSER.parseDelimitedFrom(input, extensionRegistry); + } + public static com.mogujie.tt.protobuf.IMFile.IMFileHasOfflineReq parseFrom( + com.google.protobuf.CodedInputStream input) + throws java.io.IOException { + return PARSER.parseFrom(input); + } + public static com.mogujie.tt.protobuf.IMFile.IMFileHasOfflineReq parseFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return PARSER.parseFrom(input, extensionRegistry); + } + + public static Builder newBuilder() { return Builder.create(); } + public Builder newBuilderForType() { return newBuilder(); } + public static Builder newBuilder(com.mogujie.tt.protobuf.IMFile.IMFileHasOfflineReq prototype) { + return newBuilder().mergeFrom(prototype); + } + public Builder toBuilder() { return newBuilder(this); } + + /** + * Protobuf type {@code IM.File.IMFileHasOfflineReq} + */ + public static final class Builder extends + com.google.protobuf.GeneratedMessageLite.Builder< + com.mogujie.tt.protobuf.IMFile.IMFileHasOfflineReq, Builder> + implements + // @@protoc_insertion_point(builder_implements:IM.File.IMFileHasOfflineReq) + com.mogujie.tt.protobuf.IMFile.IMFileHasOfflineReqOrBuilder { + // Construct using com.mogujie.tt.protobuf.IMFile.IMFileHasOfflineReq.newBuilder() + private Builder() { + maybeForceBuilderInitialization(); + } + + private void maybeForceBuilderInitialization() { + } + private static Builder create() { + return new Builder(); + } + + public Builder clear() { + super.clear(); + userId_ = 0; + bitField0_ = (bitField0_ & ~0x00000001); + attachData_ = com.google.protobuf.ByteString.EMPTY; + bitField0_ = (bitField0_ & ~0x00000002); + return this; + } + + public Builder clone() { + return create().mergeFrom(buildPartial()); + } + + public com.mogujie.tt.protobuf.IMFile.IMFileHasOfflineReq getDefaultInstanceForType() { + return com.mogujie.tt.protobuf.IMFile.IMFileHasOfflineReq.getDefaultInstance(); + } + + public com.mogujie.tt.protobuf.IMFile.IMFileHasOfflineReq build() { + com.mogujie.tt.protobuf.IMFile.IMFileHasOfflineReq result = buildPartial(); + if (!result.isInitialized()) { + throw newUninitializedMessageException(result); + } + return result; + } + + public com.mogujie.tt.protobuf.IMFile.IMFileHasOfflineReq buildPartial() { + com.mogujie.tt.protobuf.IMFile.IMFileHasOfflineReq result = new com.mogujie.tt.protobuf.IMFile.IMFileHasOfflineReq(this); + int from_bitField0_ = bitField0_; + int to_bitField0_ = 0; + if (((from_bitField0_ & 0x00000001) == 0x00000001)) { + to_bitField0_ |= 0x00000001; + } + result.userId_ = userId_; + if (((from_bitField0_ & 0x00000002) == 0x00000002)) { + to_bitField0_ |= 0x00000002; + } + result.attachData_ = attachData_; + result.bitField0_ = to_bitField0_; + return result; + } + + public Builder mergeFrom(com.mogujie.tt.protobuf.IMFile.IMFileHasOfflineReq other) { + if (other == com.mogujie.tt.protobuf.IMFile.IMFileHasOfflineReq.getDefaultInstance()) return this; + if (other.hasUserId()) { + setUserId(other.getUserId()); + } + if (other.hasAttachData()) { + setAttachData(other.getAttachData()); + } + setUnknownFields( + getUnknownFields().concat(other.unknownFields)); + return this; + } + + public final boolean isInitialized() { + if (!hasUserId()) { + + return false; + } + return true; + } + + public Builder mergeFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + com.mogujie.tt.protobuf.IMFile.IMFileHasOfflineReq parsedMessage = null; + try { + parsedMessage = PARSER.parsePartialFrom(input, extensionRegistry); + } catch (com.google.protobuf.InvalidProtocolBufferException e) { + parsedMessage = (com.mogujie.tt.protobuf.IMFile.IMFileHasOfflineReq) e.getUnfinishedMessage(); + throw e; + } finally { + if (parsedMessage != null) { + mergeFrom(parsedMessage); + } + } + return this; + } + private int bitField0_; + + private int userId_ ; + /** + * required uint32 user_id = 1; + * + *
+       *cmd id: 	0x0509
+       * 
+ */ + public boolean hasUserId() { + return ((bitField0_ & 0x00000001) == 0x00000001); + } + /** + * required uint32 user_id = 1; + * + *
+       *cmd id: 	0x0509
+       * 
+ */ + public int getUserId() { + return userId_; + } + /** + * required uint32 user_id = 1; + * + *
+       *cmd id: 	0x0509
+       * 
+ */ + public Builder setUserId(int value) { + bitField0_ |= 0x00000001; + userId_ = value; + + return this; + } + /** + * required uint32 user_id = 1; + * + *
+       *cmd id: 	0x0509
+       * 
+ */ + public Builder clearUserId() { + bitField0_ = (bitField0_ & ~0x00000001); + userId_ = 0; + + return this; + } + + private com.google.protobuf.ByteString attachData_ = com.google.protobuf.ByteString.EMPTY; + /** + * optional bytes attach_data = 20; + */ + public boolean hasAttachData() { + return ((bitField0_ & 0x00000002) == 0x00000002); + } + /** + * optional bytes attach_data = 20; + */ + public com.google.protobuf.ByteString getAttachData() { + return attachData_; + } + /** + * optional bytes attach_data = 20; + */ + public Builder setAttachData(com.google.protobuf.ByteString value) { + if (value == null) { + throw new NullPointerException(); + } + bitField0_ |= 0x00000002; + attachData_ = value; + + return this; + } + /** + * optional bytes attach_data = 20; + */ + public Builder clearAttachData() { + bitField0_ = (bitField0_ & ~0x00000002); + attachData_ = getDefaultInstance().getAttachData(); + + return this; + } + + // @@protoc_insertion_point(builder_scope:IM.File.IMFileHasOfflineReq) + } + + static { + defaultInstance = new IMFileHasOfflineReq(true); + defaultInstance.initFields(); + } + + // @@protoc_insertion_point(class_scope:IM.File.IMFileHasOfflineReq) + } + + public interface IMFileHasOfflineRspOrBuilder extends + // @@protoc_insertion_point(interface_extends:IM.File.IMFileHasOfflineRsp) + com.google.protobuf.MessageLiteOrBuilder { + + /** + * required uint32 user_id = 1; + * + *
+     *cmd id:	0x050a
+     * 
+ */ + boolean hasUserId(); + /** + * required uint32 user_id = 1; + * + *
+     *cmd id:	0x050a
+     * 
+ */ + int getUserId(); + + /** + * repeated .IM.BaseDefine.OfflineFileInfo offline_file_list = 2; + */ + java.util.List + getOfflineFileListList(); + /** + * repeated .IM.BaseDefine.OfflineFileInfo offline_file_list = 2; + */ + com.mogujie.tt.protobuf.IMBaseDefine.OfflineFileInfo getOfflineFileList(int index); + /** + * repeated .IM.BaseDefine.OfflineFileInfo offline_file_list = 2; + */ + int getOfflineFileListCount(); + + /** + * repeated .IM.BaseDefine.IpAddr ip_addr_list = 3; + */ + java.util.List + getIpAddrListList(); + /** + * repeated .IM.BaseDefine.IpAddr ip_addr_list = 3; + */ + com.mogujie.tt.protobuf.IMBaseDefine.IpAddr getIpAddrList(int index); + /** + * repeated .IM.BaseDefine.IpAddr ip_addr_list = 3; + */ + int getIpAddrListCount(); + + /** + * optional bytes attach_data = 20; + */ + boolean hasAttachData(); + /** + * optional bytes attach_data = 20; + */ + com.google.protobuf.ByteString getAttachData(); + } + /** + * Protobuf type {@code IM.File.IMFileHasOfflineRsp} + */ + public static final class IMFileHasOfflineRsp extends + com.google.protobuf.GeneratedMessageLite implements + // @@protoc_insertion_point(message_implements:IM.File.IMFileHasOfflineRsp) + IMFileHasOfflineRspOrBuilder { + // Use IMFileHasOfflineRsp.newBuilder() to construct. + private IMFileHasOfflineRsp(com.google.protobuf.GeneratedMessageLite.Builder builder) { + super(builder); + this.unknownFields = builder.getUnknownFields(); + } + private IMFileHasOfflineRsp(boolean noInit) { this.unknownFields = com.google.protobuf.ByteString.EMPTY;} + + private static final IMFileHasOfflineRsp defaultInstance; + public static IMFileHasOfflineRsp getDefaultInstance() { + return defaultInstance; + } + + public IMFileHasOfflineRsp getDefaultInstanceForType() { + return defaultInstance; + } + + private final com.google.protobuf.ByteString unknownFields; + private IMFileHasOfflineRsp( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + initFields(); + int mutable_bitField0_ = 0; + com.google.protobuf.ByteString.Output unknownFieldsOutput = + com.google.protobuf.ByteString.newOutput(); + com.google.protobuf.CodedOutputStream unknownFieldsCodedOutput = + com.google.protobuf.CodedOutputStream.newInstance( + unknownFieldsOutput); + try { + boolean done = false; + while (!done) { + int tag = input.readTag(); + switch (tag) { + case 0: + done = true; + break; + default: { + if (!parseUnknownField(input, unknownFieldsCodedOutput, + extensionRegistry, tag)) { + done = true; + } + break; + } + case 8: { + bitField0_ |= 0x00000001; + userId_ = input.readUInt32(); + break; + } + case 18: { + if (!((mutable_bitField0_ & 0x00000002) == 0x00000002)) { + offlineFileList_ = new java.util.ArrayList(); + mutable_bitField0_ |= 0x00000002; + } + offlineFileList_.add(input.readMessage(com.mogujie.tt.protobuf.IMBaseDefine.OfflineFileInfo.PARSER, extensionRegistry)); + break; + } + case 26: { + if (!((mutable_bitField0_ & 0x00000004) == 0x00000004)) { + ipAddrList_ = new java.util.ArrayList(); + mutable_bitField0_ |= 0x00000004; + } + ipAddrList_.add(input.readMessage(com.mogujie.tt.protobuf.IMBaseDefine.IpAddr.PARSER, extensionRegistry)); + break; + } + case 162: { + bitField0_ |= 0x00000002; + attachData_ = input.readBytes(); + break; + } + } + } + } catch (com.google.protobuf.InvalidProtocolBufferException e) { + throw e.setUnfinishedMessage(this); + } catch (java.io.IOException e) { + throw new com.google.protobuf.InvalidProtocolBufferException( + e.getMessage()).setUnfinishedMessage(this); + } finally { + if (((mutable_bitField0_ & 0x00000002) == 0x00000002)) { + offlineFileList_ = java.util.Collections.unmodifiableList(offlineFileList_); + } + if (((mutable_bitField0_ & 0x00000004) == 0x00000004)) { + ipAddrList_ = java.util.Collections.unmodifiableList(ipAddrList_); + } + try { + unknownFieldsCodedOutput.flush(); + } catch (java.io.IOException e) { + // Should not happen + } finally { + unknownFields = unknownFieldsOutput.toByteString(); + } + makeExtensionsImmutable(); + } + } + public static com.google.protobuf.Parser PARSER = + new com.google.protobuf.AbstractParser() { + public IMFileHasOfflineRsp parsePartialFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return new IMFileHasOfflineRsp(input, extensionRegistry); + } + }; + + @java.lang.Override + public com.google.protobuf.Parser getParserForType() { + return PARSER; + } + + private int bitField0_; + public static final int USER_ID_FIELD_NUMBER = 1; + private int userId_; + /** + * required uint32 user_id = 1; + * + *
+     *cmd id:	0x050a
+     * 
+ */ + public boolean hasUserId() { + return ((bitField0_ & 0x00000001) == 0x00000001); + } + /** + * required uint32 user_id = 1; + * + *
+     *cmd id:	0x050a
+     * 
+ */ + public int getUserId() { + return userId_; + } + + public static final int OFFLINE_FILE_LIST_FIELD_NUMBER = 2; + private java.util.List offlineFileList_; + /** + * repeated .IM.BaseDefine.OfflineFileInfo offline_file_list = 2; + */ + public java.util.List getOfflineFileListList() { + return offlineFileList_; + } + /** + * repeated .IM.BaseDefine.OfflineFileInfo offline_file_list = 2; + */ + public java.util.List + getOfflineFileListOrBuilderList() { + return offlineFileList_; + } + /** + * repeated .IM.BaseDefine.OfflineFileInfo offline_file_list = 2; + */ + public int getOfflineFileListCount() { + return offlineFileList_.size(); + } + /** + * repeated .IM.BaseDefine.OfflineFileInfo offline_file_list = 2; + */ + public com.mogujie.tt.protobuf.IMBaseDefine.OfflineFileInfo getOfflineFileList(int index) { + return offlineFileList_.get(index); + } + /** + * repeated .IM.BaseDefine.OfflineFileInfo offline_file_list = 2; + */ + public com.mogujie.tt.protobuf.IMBaseDefine.OfflineFileInfoOrBuilder getOfflineFileListOrBuilder( + int index) { + return offlineFileList_.get(index); + } + + public static final int IP_ADDR_LIST_FIELD_NUMBER = 3; + private java.util.List ipAddrList_; + /** + * repeated .IM.BaseDefine.IpAddr ip_addr_list = 3; + */ + public java.util.List getIpAddrListList() { + return ipAddrList_; + } + /** + * repeated .IM.BaseDefine.IpAddr ip_addr_list = 3; + */ + public java.util.List + getIpAddrListOrBuilderList() { + return ipAddrList_; + } + /** + * repeated .IM.BaseDefine.IpAddr ip_addr_list = 3; + */ + public int getIpAddrListCount() { + return ipAddrList_.size(); + } + /** + * repeated .IM.BaseDefine.IpAddr ip_addr_list = 3; + */ + public com.mogujie.tt.protobuf.IMBaseDefine.IpAddr getIpAddrList(int index) { + return ipAddrList_.get(index); + } + /** + * repeated .IM.BaseDefine.IpAddr ip_addr_list = 3; + */ + public com.mogujie.tt.protobuf.IMBaseDefine.IpAddrOrBuilder getIpAddrListOrBuilder( + int index) { + return ipAddrList_.get(index); + } + + public static final int ATTACH_DATA_FIELD_NUMBER = 20; + private com.google.protobuf.ByteString attachData_; + /** + * optional bytes attach_data = 20; + */ + public boolean hasAttachData() { + return ((bitField0_ & 0x00000002) == 0x00000002); + } + /** + * optional bytes attach_data = 20; + */ + public com.google.protobuf.ByteString getAttachData() { + return attachData_; + } + + private void initFields() { + userId_ = 0; + offlineFileList_ = java.util.Collections.emptyList(); + ipAddrList_ = java.util.Collections.emptyList(); + attachData_ = com.google.protobuf.ByteString.EMPTY; + } + private byte memoizedIsInitialized = -1; + public final boolean isInitialized() { + byte isInitialized = memoizedIsInitialized; + if (isInitialized == 1) return true; + if (isInitialized == 0) return false; + + if (!hasUserId()) { + memoizedIsInitialized = 0; + return false; + } + for (int i = 0; i < getOfflineFileListCount(); i++) { + if (!getOfflineFileList(i).isInitialized()) { + memoizedIsInitialized = 0; + return false; + } + } + for (int i = 0; i < getIpAddrListCount(); i++) { + if (!getIpAddrList(i).isInitialized()) { + memoizedIsInitialized = 0; + return false; + } + } + memoizedIsInitialized = 1; + return true; + } + + public void writeTo(com.google.protobuf.CodedOutputStream output) + throws java.io.IOException { + getSerializedSize(); + if (((bitField0_ & 0x00000001) == 0x00000001)) { + output.writeUInt32(1, userId_); + } + for (int i = 0; i < offlineFileList_.size(); i++) { + output.writeMessage(2, offlineFileList_.get(i)); + } + for (int i = 0; i < ipAddrList_.size(); i++) { + output.writeMessage(3, ipAddrList_.get(i)); + } + if (((bitField0_ & 0x00000002) == 0x00000002)) { + output.writeBytes(20, attachData_); + } + output.writeRawBytes(unknownFields); + } + + private int memoizedSerializedSize = -1; + public int getSerializedSize() { + int size = memoizedSerializedSize; + if (size != -1) return size; + + size = 0; + if (((bitField0_ & 0x00000001) == 0x00000001)) { + size += com.google.protobuf.CodedOutputStream + .computeUInt32Size(1, userId_); + } + for (int i = 0; i < offlineFileList_.size(); i++) { + size += com.google.protobuf.CodedOutputStream + .computeMessageSize(2, offlineFileList_.get(i)); + } + for (int i = 0; i < ipAddrList_.size(); i++) { + size += com.google.protobuf.CodedOutputStream + .computeMessageSize(3, ipAddrList_.get(i)); + } + if (((bitField0_ & 0x00000002) == 0x00000002)) { + size += com.google.protobuf.CodedOutputStream + .computeBytesSize(20, attachData_); + } + size += unknownFields.size(); + memoizedSerializedSize = size; + return size; + } + + private static final long serialVersionUID = 0L; + @java.lang.Override + protected java.lang.Object writeReplace() + throws java.io.ObjectStreamException { + return super.writeReplace(); + } + + public static com.mogujie.tt.protobuf.IMFile.IMFileHasOfflineRsp parseFrom( + com.google.protobuf.ByteString data) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data); + } + public static com.mogujie.tt.protobuf.IMFile.IMFileHasOfflineRsp parseFrom( + com.google.protobuf.ByteString data, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data, extensionRegistry); + } + public static com.mogujie.tt.protobuf.IMFile.IMFileHasOfflineRsp parseFrom(byte[] data) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data); + } + public static com.mogujie.tt.protobuf.IMFile.IMFileHasOfflineRsp parseFrom( + byte[] data, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data, extensionRegistry); + } + public static com.mogujie.tt.protobuf.IMFile.IMFileHasOfflineRsp parseFrom(java.io.InputStream input) + throws java.io.IOException { + return PARSER.parseFrom(input); + } + public static com.mogujie.tt.protobuf.IMFile.IMFileHasOfflineRsp parseFrom( + java.io.InputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return PARSER.parseFrom(input, extensionRegistry); + } + public static com.mogujie.tt.protobuf.IMFile.IMFileHasOfflineRsp parseDelimitedFrom(java.io.InputStream input) + throws java.io.IOException { + return PARSER.parseDelimitedFrom(input); + } + public static com.mogujie.tt.protobuf.IMFile.IMFileHasOfflineRsp parseDelimitedFrom( + java.io.InputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return PARSER.parseDelimitedFrom(input, extensionRegistry); + } + public static com.mogujie.tt.protobuf.IMFile.IMFileHasOfflineRsp parseFrom( + com.google.protobuf.CodedInputStream input) + throws java.io.IOException { + return PARSER.parseFrom(input); + } + public static com.mogujie.tt.protobuf.IMFile.IMFileHasOfflineRsp parseFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return PARSER.parseFrom(input, extensionRegistry); + } + + public static Builder newBuilder() { return Builder.create(); } + public Builder newBuilderForType() { return newBuilder(); } + public static Builder newBuilder(com.mogujie.tt.protobuf.IMFile.IMFileHasOfflineRsp prototype) { + return newBuilder().mergeFrom(prototype); + } + public Builder toBuilder() { return newBuilder(this); } + + /** + * Protobuf type {@code IM.File.IMFileHasOfflineRsp} + */ + public static final class Builder extends + com.google.protobuf.GeneratedMessageLite.Builder< + com.mogujie.tt.protobuf.IMFile.IMFileHasOfflineRsp, Builder> + implements + // @@protoc_insertion_point(builder_implements:IM.File.IMFileHasOfflineRsp) + com.mogujie.tt.protobuf.IMFile.IMFileHasOfflineRspOrBuilder { + // Construct using com.mogujie.tt.protobuf.IMFile.IMFileHasOfflineRsp.newBuilder() + private Builder() { + maybeForceBuilderInitialization(); + } + + private void maybeForceBuilderInitialization() { + } + private static Builder create() { + return new Builder(); + } + + public Builder clear() { + super.clear(); + userId_ = 0; + bitField0_ = (bitField0_ & ~0x00000001); + offlineFileList_ = java.util.Collections.emptyList(); + bitField0_ = (bitField0_ & ~0x00000002); + ipAddrList_ = java.util.Collections.emptyList(); + bitField0_ = (bitField0_ & ~0x00000004); + attachData_ = com.google.protobuf.ByteString.EMPTY; + bitField0_ = (bitField0_ & ~0x00000008); + return this; + } + + public Builder clone() { + return create().mergeFrom(buildPartial()); + } + + public com.mogujie.tt.protobuf.IMFile.IMFileHasOfflineRsp getDefaultInstanceForType() { + return com.mogujie.tt.protobuf.IMFile.IMFileHasOfflineRsp.getDefaultInstance(); + } + + public com.mogujie.tt.protobuf.IMFile.IMFileHasOfflineRsp build() { + com.mogujie.tt.protobuf.IMFile.IMFileHasOfflineRsp result = buildPartial(); + if (!result.isInitialized()) { + throw newUninitializedMessageException(result); + } + return result; + } + + public com.mogujie.tt.protobuf.IMFile.IMFileHasOfflineRsp buildPartial() { + com.mogujie.tt.protobuf.IMFile.IMFileHasOfflineRsp result = new com.mogujie.tt.protobuf.IMFile.IMFileHasOfflineRsp(this); + int from_bitField0_ = bitField0_; + int to_bitField0_ = 0; + if (((from_bitField0_ & 0x00000001) == 0x00000001)) { + to_bitField0_ |= 0x00000001; + } + result.userId_ = userId_; + if (((bitField0_ & 0x00000002) == 0x00000002)) { + offlineFileList_ = java.util.Collections.unmodifiableList(offlineFileList_); + bitField0_ = (bitField0_ & ~0x00000002); + } + result.offlineFileList_ = offlineFileList_; + if (((bitField0_ & 0x00000004) == 0x00000004)) { + ipAddrList_ = java.util.Collections.unmodifiableList(ipAddrList_); + bitField0_ = (bitField0_ & ~0x00000004); + } + result.ipAddrList_ = ipAddrList_; + if (((from_bitField0_ & 0x00000008) == 0x00000008)) { + to_bitField0_ |= 0x00000002; + } + result.attachData_ = attachData_; + result.bitField0_ = to_bitField0_; + return result; + } + + public Builder mergeFrom(com.mogujie.tt.protobuf.IMFile.IMFileHasOfflineRsp other) { + if (other == com.mogujie.tt.protobuf.IMFile.IMFileHasOfflineRsp.getDefaultInstance()) return this; + if (other.hasUserId()) { + setUserId(other.getUserId()); + } + if (!other.offlineFileList_.isEmpty()) { + if (offlineFileList_.isEmpty()) { + offlineFileList_ = other.offlineFileList_; + bitField0_ = (bitField0_ & ~0x00000002); + } else { + ensureOfflineFileListIsMutable(); + offlineFileList_.addAll(other.offlineFileList_); + } + + } + if (!other.ipAddrList_.isEmpty()) { + if (ipAddrList_.isEmpty()) { + ipAddrList_ = other.ipAddrList_; + bitField0_ = (bitField0_ & ~0x00000004); + } else { + ensureIpAddrListIsMutable(); + ipAddrList_.addAll(other.ipAddrList_); + } + + } + if (other.hasAttachData()) { + setAttachData(other.getAttachData()); + } + setUnknownFields( + getUnknownFields().concat(other.unknownFields)); + return this; + } + + public final boolean isInitialized() { + if (!hasUserId()) { + + return false; + } + for (int i = 0; i < getOfflineFileListCount(); i++) { + if (!getOfflineFileList(i).isInitialized()) { + + return false; + } + } + for (int i = 0; i < getIpAddrListCount(); i++) { + if (!getIpAddrList(i).isInitialized()) { + + return false; + } + } + return true; + } + + public Builder mergeFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + com.mogujie.tt.protobuf.IMFile.IMFileHasOfflineRsp parsedMessage = null; + try { + parsedMessage = PARSER.parsePartialFrom(input, extensionRegistry); + } catch (com.google.protobuf.InvalidProtocolBufferException e) { + parsedMessage = (com.mogujie.tt.protobuf.IMFile.IMFileHasOfflineRsp) e.getUnfinishedMessage(); + throw e; + } finally { + if (parsedMessage != null) { + mergeFrom(parsedMessage); + } + } + return this; + } + private int bitField0_; + + private int userId_ ; + /** + * required uint32 user_id = 1; + * + *
+       *cmd id:	0x050a
+       * 
+ */ + public boolean hasUserId() { + return ((bitField0_ & 0x00000001) == 0x00000001); + } + /** + * required uint32 user_id = 1; + * + *
+       *cmd id:	0x050a
+       * 
+ */ + public int getUserId() { + return userId_; + } + /** + * required uint32 user_id = 1; + * + *
+       *cmd id:	0x050a
+       * 
+ */ + public Builder setUserId(int value) { + bitField0_ |= 0x00000001; + userId_ = value; + + return this; + } + /** + * required uint32 user_id = 1; + * + *
+       *cmd id:	0x050a
+       * 
+ */ + public Builder clearUserId() { + bitField0_ = (bitField0_ & ~0x00000001); + userId_ = 0; + + return this; + } + + private java.util.List offlineFileList_ = + java.util.Collections.emptyList(); + private void ensureOfflineFileListIsMutable() { + if (!((bitField0_ & 0x00000002) == 0x00000002)) { + offlineFileList_ = new java.util.ArrayList(offlineFileList_); + bitField0_ |= 0x00000002; + } + } + + /** + * repeated .IM.BaseDefine.OfflineFileInfo offline_file_list = 2; + */ + public java.util.List getOfflineFileListList() { + return java.util.Collections.unmodifiableList(offlineFileList_); + } + /** + * repeated .IM.BaseDefine.OfflineFileInfo offline_file_list = 2; + */ + public int getOfflineFileListCount() { + return offlineFileList_.size(); + } + /** + * repeated .IM.BaseDefine.OfflineFileInfo offline_file_list = 2; + */ + public com.mogujie.tt.protobuf.IMBaseDefine.OfflineFileInfo getOfflineFileList(int index) { + return offlineFileList_.get(index); + } + /** + * repeated .IM.BaseDefine.OfflineFileInfo offline_file_list = 2; + */ + public Builder setOfflineFileList( + int index, com.mogujie.tt.protobuf.IMBaseDefine.OfflineFileInfo value) { + if (value == null) { + throw new NullPointerException(); + } + ensureOfflineFileListIsMutable(); + offlineFileList_.set(index, value); + + return this; + } + /** + * repeated .IM.BaseDefine.OfflineFileInfo offline_file_list = 2; + */ + public Builder setOfflineFileList( + int index, com.mogujie.tt.protobuf.IMBaseDefine.OfflineFileInfo.Builder builderForValue) { + ensureOfflineFileListIsMutable(); + offlineFileList_.set(index, builderForValue.build()); + + return this; + } + /** + * repeated .IM.BaseDefine.OfflineFileInfo offline_file_list = 2; + */ + public Builder addOfflineFileList(com.mogujie.tt.protobuf.IMBaseDefine.OfflineFileInfo value) { + if (value == null) { + throw new NullPointerException(); + } + ensureOfflineFileListIsMutable(); + offlineFileList_.add(value); + + return this; + } + /** + * repeated .IM.BaseDefine.OfflineFileInfo offline_file_list = 2; + */ + public Builder addOfflineFileList( + int index, com.mogujie.tt.protobuf.IMBaseDefine.OfflineFileInfo value) { + if (value == null) { + throw new NullPointerException(); + } + ensureOfflineFileListIsMutable(); + offlineFileList_.add(index, value); + + return this; + } + /** + * repeated .IM.BaseDefine.OfflineFileInfo offline_file_list = 2; + */ + public Builder addOfflineFileList( + com.mogujie.tt.protobuf.IMBaseDefine.OfflineFileInfo.Builder builderForValue) { + ensureOfflineFileListIsMutable(); + offlineFileList_.add(builderForValue.build()); + + return this; + } + /** + * repeated .IM.BaseDefine.OfflineFileInfo offline_file_list = 2; + */ + public Builder addOfflineFileList( + int index, com.mogujie.tt.protobuf.IMBaseDefine.OfflineFileInfo.Builder builderForValue) { + ensureOfflineFileListIsMutable(); + offlineFileList_.add(index, builderForValue.build()); + + return this; + } + /** + * repeated .IM.BaseDefine.OfflineFileInfo offline_file_list = 2; + */ + public Builder addAllOfflineFileList( + java.lang.Iterable values) { + ensureOfflineFileListIsMutable(); + com.google.protobuf.AbstractMessageLite.Builder.addAll( + values, offlineFileList_); + + return this; + } + /** + * repeated .IM.BaseDefine.OfflineFileInfo offline_file_list = 2; + */ + public Builder clearOfflineFileList() { + offlineFileList_ = java.util.Collections.emptyList(); + bitField0_ = (bitField0_ & ~0x00000002); + + return this; + } + /** + * repeated .IM.BaseDefine.OfflineFileInfo offline_file_list = 2; + */ + public Builder removeOfflineFileList(int index) { + ensureOfflineFileListIsMutable(); + offlineFileList_.remove(index); + + return this; + } + + private java.util.List ipAddrList_ = + java.util.Collections.emptyList(); + private void ensureIpAddrListIsMutable() { + if (!((bitField0_ & 0x00000004) == 0x00000004)) { + ipAddrList_ = new java.util.ArrayList(ipAddrList_); + bitField0_ |= 0x00000004; + } + } + + /** + * repeated .IM.BaseDefine.IpAddr ip_addr_list = 3; + */ + public java.util.List getIpAddrListList() { + return java.util.Collections.unmodifiableList(ipAddrList_); + } + /** + * repeated .IM.BaseDefine.IpAddr ip_addr_list = 3; + */ + public int getIpAddrListCount() { + return ipAddrList_.size(); + } + /** + * repeated .IM.BaseDefine.IpAddr ip_addr_list = 3; + */ + public com.mogujie.tt.protobuf.IMBaseDefine.IpAddr getIpAddrList(int index) { + return ipAddrList_.get(index); + } + /** + * repeated .IM.BaseDefine.IpAddr ip_addr_list = 3; + */ + public Builder setIpAddrList( + int index, com.mogujie.tt.protobuf.IMBaseDefine.IpAddr value) { + if (value == null) { + throw new NullPointerException(); + } + ensureIpAddrListIsMutable(); + ipAddrList_.set(index, value); + + return this; + } + /** + * repeated .IM.BaseDefine.IpAddr ip_addr_list = 3; + */ + public Builder setIpAddrList( + int index, com.mogujie.tt.protobuf.IMBaseDefine.IpAddr.Builder builderForValue) { + ensureIpAddrListIsMutable(); + ipAddrList_.set(index, builderForValue.build()); + + return this; + } + /** + * repeated .IM.BaseDefine.IpAddr ip_addr_list = 3; + */ + public Builder addIpAddrList(com.mogujie.tt.protobuf.IMBaseDefine.IpAddr value) { + if (value == null) { + throw new NullPointerException(); + } + ensureIpAddrListIsMutable(); + ipAddrList_.add(value); + + return this; + } + /** + * repeated .IM.BaseDefine.IpAddr ip_addr_list = 3; + */ + public Builder addIpAddrList( + int index, com.mogujie.tt.protobuf.IMBaseDefine.IpAddr value) { + if (value == null) { + throw new NullPointerException(); + } + ensureIpAddrListIsMutable(); + ipAddrList_.add(index, value); + + return this; + } + /** + * repeated .IM.BaseDefine.IpAddr ip_addr_list = 3; + */ + public Builder addIpAddrList( + com.mogujie.tt.protobuf.IMBaseDefine.IpAddr.Builder builderForValue) { + ensureIpAddrListIsMutable(); + ipAddrList_.add(builderForValue.build()); + + return this; + } + /** + * repeated .IM.BaseDefine.IpAddr ip_addr_list = 3; + */ + public Builder addIpAddrList( + int index, com.mogujie.tt.protobuf.IMBaseDefine.IpAddr.Builder builderForValue) { + ensureIpAddrListIsMutable(); + ipAddrList_.add(index, builderForValue.build()); + + return this; + } + /** + * repeated .IM.BaseDefine.IpAddr ip_addr_list = 3; + */ + public Builder addAllIpAddrList( + java.lang.Iterable values) { + ensureIpAddrListIsMutable(); + com.google.protobuf.AbstractMessageLite.Builder.addAll( + values, ipAddrList_); + + return this; + } + /** + * repeated .IM.BaseDefine.IpAddr ip_addr_list = 3; + */ + public Builder clearIpAddrList() { + ipAddrList_ = java.util.Collections.emptyList(); + bitField0_ = (bitField0_ & ~0x00000004); + + return this; + } + /** + * repeated .IM.BaseDefine.IpAddr ip_addr_list = 3; + */ + public Builder removeIpAddrList(int index) { + ensureIpAddrListIsMutable(); + ipAddrList_.remove(index); + + return this; + } + + private com.google.protobuf.ByteString attachData_ = com.google.protobuf.ByteString.EMPTY; + /** + * optional bytes attach_data = 20; + */ + public boolean hasAttachData() { + return ((bitField0_ & 0x00000008) == 0x00000008); + } + /** + * optional bytes attach_data = 20; + */ + public com.google.protobuf.ByteString getAttachData() { + return attachData_; + } + /** + * optional bytes attach_data = 20; + */ + public Builder setAttachData(com.google.protobuf.ByteString value) { + if (value == null) { + throw new NullPointerException(); + } + bitField0_ |= 0x00000008; + attachData_ = value; + + return this; + } + /** + * optional bytes attach_data = 20; + */ + public Builder clearAttachData() { + bitField0_ = (bitField0_ & ~0x00000008); + attachData_ = getDefaultInstance().getAttachData(); + + return this; + } + + // @@protoc_insertion_point(builder_scope:IM.File.IMFileHasOfflineRsp) + } + + static { + defaultInstance = new IMFileHasOfflineRsp(true); + defaultInstance.initFields(); + } + + // @@protoc_insertion_point(class_scope:IM.File.IMFileHasOfflineRsp) + } + + public interface IMFileAddOfflineReqOrBuilder extends + // @@protoc_insertion_point(interface_extends:IM.File.IMFileAddOfflineReq) + com.google.protobuf.MessageLiteOrBuilder { + + /** + * required uint32 from_user_id = 1; + * + *
+     *cmd id:	0x050b
+     * 
+ */ + boolean hasFromUserId(); + /** + * required uint32 from_user_id = 1; + * + *
+     *cmd id:	0x050b
+     * 
+ */ + int getFromUserId(); + + /** + * required uint32 to_user_id = 2; + */ + boolean hasToUserId(); + /** + * required uint32 to_user_id = 2; + */ + int getToUserId(); + + /** + * required string task_id = 3; + */ + boolean hasTaskId(); + /** + * required string task_id = 3; + */ + java.lang.String getTaskId(); + /** + * required string task_id = 3; + */ + com.google.protobuf.ByteString + getTaskIdBytes(); + + /** + * required string file_name = 4; + */ + boolean hasFileName(); + /** + * required string file_name = 4; + */ + java.lang.String getFileName(); + /** + * required string file_name = 4; + */ + com.google.protobuf.ByteString + getFileNameBytes(); + + /** + * required uint32 file_size = 5; + */ + boolean hasFileSize(); + /** + * required uint32 file_size = 5; + */ + int getFileSize(); + } + /** + * Protobuf type {@code IM.File.IMFileAddOfflineReq} + */ + public static final class IMFileAddOfflineReq extends + com.google.protobuf.GeneratedMessageLite implements + // @@protoc_insertion_point(message_implements:IM.File.IMFileAddOfflineReq) + IMFileAddOfflineReqOrBuilder { + // Use IMFileAddOfflineReq.newBuilder() to construct. + private IMFileAddOfflineReq(com.google.protobuf.GeneratedMessageLite.Builder builder) { + super(builder); + this.unknownFields = builder.getUnknownFields(); + } + private IMFileAddOfflineReq(boolean noInit) { this.unknownFields = com.google.protobuf.ByteString.EMPTY;} + + private static final IMFileAddOfflineReq defaultInstance; + public static IMFileAddOfflineReq getDefaultInstance() { + return defaultInstance; + } + + public IMFileAddOfflineReq getDefaultInstanceForType() { + return defaultInstance; + } + + private final com.google.protobuf.ByteString unknownFields; + private IMFileAddOfflineReq( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + initFields(); + int mutable_bitField0_ = 0; + com.google.protobuf.ByteString.Output unknownFieldsOutput = + com.google.protobuf.ByteString.newOutput(); + com.google.protobuf.CodedOutputStream unknownFieldsCodedOutput = + com.google.protobuf.CodedOutputStream.newInstance( + unknownFieldsOutput); + try { + boolean done = false; + while (!done) { + int tag = input.readTag(); + switch (tag) { + case 0: + done = true; + break; + default: { + if (!parseUnknownField(input, unknownFieldsCodedOutput, + extensionRegistry, tag)) { + done = true; + } + break; + } + case 8: { + bitField0_ |= 0x00000001; + fromUserId_ = input.readUInt32(); + break; + } + case 16: { + bitField0_ |= 0x00000002; + toUserId_ = input.readUInt32(); + break; + } + case 26: { + com.google.protobuf.ByteString bs = input.readBytes(); + bitField0_ |= 0x00000004; + taskId_ = bs; + break; + } + case 34: { + com.google.protobuf.ByteString bs = input.readBytes(); + bitField0_ |= 0x00000008; + fileName_ = bs; + break; + } + case 40: { + bitField0_ |= 0x00000010; + fileSize_ = input.readUInt32(); + break; + } + } + } + } catch (com.google.protobuf.InvalidProtocolBufferException e) { + throw e.setUnfinishedMessage(this); + } catch (java.io.IOException e) { + throw new com.google.protobuf.InvalidProtocolBufferException( + e.getMessage()).setUnfinishedMessage(this); + } finally { + try { + unknownFieldsCodedOutput.flush(); + } catch (java.io.IOException e) { + // Should not happen + } finally { + unknownFields = unknownFieldsOutput.toByteString(); + } + makeExtensionsImmutable(); + } + } + public static com.google.protobuf.Parser PARSER = + new com.google.protobuf.AbstractParser() { + public IMFileAddOfflineReq parsePartialFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return new IMFileAddOfflineReq(input, extensionRegistry); + } + }; + + @java.lang.Override + public com.google.protobuf.Parser getParserForType() { + return PARSER; + } + + private int bitField0_; + public static final int FROM_USER_ID_FIELD_NUMBER = 1; + private int fromUserId_; + /** + * required uint32 from_user_id = 1; + * + *
+     *cmd id:	0x050b
+     * 
+ */ + public boolean hasFromUserId() { + return ((bitField0_ & 0x00000001) == 0x00000001); + } + /** + * required uint32 from_user_id = 1; + * + *
+     *cmd id:	0x050b
+     * 
+ */ + public int getFromUserId() { + return fromUserId_; + } + + public static final int TO_USER_ID_FIELD_NUMBER = 2; + private int toUserId_; + /** + * required uint32 to_user_id = 2; + */ + public boolean hasToUserId() { + return ((bitField0_ & 0x00000002) == 0x00000002); + } + /** + * required uint32 to_user_id = 2; + */ + public int getToUserId() { + return toUserId_; + } + + public static final int TASK_ID_FIELD_NUMBER = 3; + private java.lang.Object taskId_; + /** + * required string task_id = 3; + */ + public boolean hasTaskId() { + return ((bitField0_ & 0x00000004) == 0x00000004); + } + /** + * required string task_id = 3; + */ + public java.lang.String getTaskId() { + java.lang.Object ref = taskId_; + if (ref instanceof java.lang.String) { + return (java.lang.String) ref; + } else { + com.google.protobuf.ByteString bs = + (com.google.protobuf.ByteString) ref; + java.lang.String s = bs.toStringUtf8(); + if (bs.isValidUtf8()) { + taskId_ = s; + } + return s; + } + } + /** + * required string task_id = 3; + */ + public com.google.protobuf.ByteString + getTaskIdBytes() { + java.lang.Object ref = taskId_; + if (ref instanceof java.lang.String) { + com.google.protobuf.ByteString b = + com.google.protobuf.ByteString.copyFromUtf8( + (java.lang.String) ref); + taskId_ = b; + return b; + } else { + return (com.google.protobuf.ByteString) ref; + } + } + + public static final int FILE_NAME_FIELD_NUMBER = 4; + private java.lang.Object fileName_; + /** + * required string file_name = 4; + */ + public boolean hasFileName() { + return ((bitField0_ & 0x00000008) == 0x00000008); + } + /** + * required string file_name = 4; + */ + public java.lang.String getFileName() { + java.lang.Object ref = fileName_; + if (ref instanceof java.lang.String) { + return (java.lang.String) ref; + } else { + com.google.protobuf.ByteString bs = + (com.google.protobuf.ByteString) ref; + java.lang.String s = bs.toStringUtf8(); + if (bs.isValidUtf8()) { + fileName_ = s; + } + return s; + } + } + /** + * required string file_name = 4; + */ + public com.google.protobuf.ByteString + getFileNameBytes() { + java.lang.Object ref = fileName_; + if (ref instanceof java.lang.String) { + com.google.protobuf.ByteString b = + com.google.protobuf.ByteString.copyFromUtf8( + (java.lang.String) ref); + fileName_ = b; + return b; + } else { + return (com.google.protobuf.ByteString) ref; + } + } + + public static final int FILE_SIZE_FIELD_NUMBER = 5; + private int fileSize_; + /** + * required uint32 file_size = 5; + */ + public boolean hasFileSize() { + return ((bitField0_ & 0x00000010) == 0x00000010); + } + /** + * required uint32 file_size = 5; + */ + public int getFileSize() { + return fileSize_; + } + + private void initFields() { + fromUserId_ = 0; + toUserId_ = 0; + taskId_ = ""; + fileName_ = ""; + fileSize_ = 0; + } + private byte memoizedIsInitialized = -1; + public final boolean isInitialized() { + byte isInitialized = memoizedIsInitialized; + if (isInitialized == 1) return true; + if (isInitialized == 0) return false; + + if (!hasFromUserId()) { + memoizedIsInitialized = 0; + return false; + } + if (!hasToUserId()) { + memoizedIsInitialized = 0; + return false; + } + if (!hasTaskId()) { + memoizedIsInitialized = 0; + return false; + } + if (!hasFileName()) { + memoizedIsInitialized = 0; + return false; + } + if (!hasFileSize()) { + memoizedIsInitialized = 0; + return false; + } + memoizedIsInitialized = 1; + return true; + } + + public void writeTo(com.google.protobuf.CodedOutputStream output) + throws java.io.IOException { + getSerializedSize(); + if (((bitField0_ & 0x00000001) == 0x00000001)) { + output.writeUInt32(1, fromUserId_); + } + if (((bitField0_ & 0x00000002) == 0x00000002)) { + output.writeUInt32(2, toUserId_); + } + if (((bitField0_ & 0x00000004) == 0x00000004)) { + output.writeBytes(3, getTaskIdBytes()); + } + if (((bitField0_ & 0x00000008) == 0x00000008)) { + output.writeBytes(4, getFileNameBytes()); + } + if (((bitField0_ & 0x00000010) == 0x00000010)) { + output.writeUInt32(5, fileSize_); + } + output.writeRawBytes(unknownFields); + } + + private int memoizedSerializedSize = -1; + public int getSerializedSize() { + int size = memoizedSerializedSize; + if (size != -1) return size; + + size = 0; + if (((bitField0_ & 0x00000001) == 0x00000001)) { + size += com.google.protobuf.CodedOutputStream + .computeUInt32Size(1, fromUserId_); + } + if (((bitField0_ & 0x00000002) == 0x00000002)) { + size += com.google.protobuf.CodedOutputStream + .computeUInt32Size(2, toUserId_); + } + if (((bitField0_ & 0x00000004) == 0x00000004)) { + size += com.google.protobuf.CodedOutputStream + .computeBytesSize(3, getTaskIdBytes()); + } + if (((bitField0_ & 0x00000008) == 0x00000008)) { + size += com.google.protobuf.CodedOutputStream + .computeBytesSize(4, getFileNameBytes()); + } + if (((bitField0_ & 0x00000010) == 0x00000010)) { + size += com.google.protobuf.CodedOutputStream + .computeUInt32Size(5, fileSize_); + } + size += unknownFields.size(); + memoizedSerializedSize = size; + return size; + } + + private static final long serialVersionUID = 0L; + @java.lang.Override + protected java.lang.Object writeReplace() + throws java.io.ObjectStreamException { + return super.writeReplace(); + } + + public static com.mogujie.tt.protobuf.IMFile.IMFileAddOfflineReq parseFrom( + com.google.protobuf.ByteString data) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data); + } + public static com.mogujie.tt.protobuf.IMFile.IMFileAddOfflineReq parseFrom( + com.google.protobuf.ByteString data, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data, extensionRegistry); + } + public static com.mogujie.tt.protobuf.IMFile.IMFileAddOfflineReq parseFrom(byte[] data) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data); + } + public static com.mogujie.tt.protobuf.IMFile.IMFileAddOfflineReq parseFrom( + byte[] data, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data, extensionRegistry); + } + public static com.mogujie.tt.protobuf.IMFile.IMFileAddOfflineReq parseFrom(java.io.InputStream input) + throws java.io.IOException { + return PARSER.parseFrom(input); + } + public static com.mogujie.tt.protobuf.IMFile.IMFileAddOfflineReq parseFrom( + java.io.InputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return PARSER.parseFrom(input, extensionRegistry); + } + public static com.mogujie.tt.protobuf.IMFile.IMFileAddOfflineReq parseDelimitedFrom(java.io.InputStream input) + throws java.io.IOException { + return PARSER.parseDelimitedFrom(input); + } + public static com.mogujie.tt.protobuf.IMFile.IMFileAddOfflineReq parseDelimitedFrom( + java.io.InputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return PARSER.parseDelimitedFrom(input, extensionRegistry); + } + public static com.mogujie.tt.protobuf.IMFile.IMFileAddOfflineReq parseFrom( + com.google.protobuf.CodedInputStream input) + throws java.io.IOException { + return PARSER.parseFrom(input); + } + public static com.mogujie.tt.protobuf.IMFile.IMFileAddOfflineReq parseFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return PARSER.parseFrom(input, extensionRegistry); + } + + public static Builder newBuilder() { return Builder.create(); } + public Builder newBuilderForType() { return newBuilder(); } + public static Builder newBuilder(com.mogujie.tt.protobuf.IMFile.IMFileAddOfflineReq prototype) { + return newBuilder().mergeFrom(prototype); + } + public Builder toBuilder() { return newBuilder(this); } + + /** + * Protobuf type {@code IM.File.IMFileAddOfflineReq} + */ + public static final class Builder extends + com.google.protobuf.GeneratedMessageLite.Builder< + com.mogujie.tt.protobuf.IMFile.IMFileAddOfflineReq, Builder> + implements + // @@protoc_insertion_point(builder_implements:IM.File.IMFileAddOfflineReq) + com.mogujie.tt.protobuf.IMFile.IMFileAddOfflineReqOrBuilder { + // Construct using com.mogujie.tt.protobuf.IMFile.IMFileAddOfflineReq.newBuilder() + private Builder() { + maybeForceBuilderInitialization(); + } + + private void maybeForceBuilderInitialization() { + } + private static Builder create() { + return new Builder(); + } + + public Builder clear() { + super.clear(); + fromUserId_ = 0; + bitField0_ = (bitField0_ & ~0x00000001); + toUserId_ = 0; + bitField0_ = (bitField0_ & ~0x00000002); + taskId_ = ""; + bitField0_ = (bitField0_ & ~0x00000004); + fileName_ = ""; + bitField0_ = (bitField0_ & ~0x00000008); + fileSize_ = 0; + bitField0_ = (bitField0_ & ~0x00000010); + return this; + } + + public Builder clone() { + return create().mergeFrom(buildPartial()); + } + + public com.mogujie.tt.protobuf.IMFile.IMFileAddOfflineReq getDefaultInstanceForType() { + return com.mogujie.tt.protobuf.IMFile.IMFileAddOfflineReq.getDefaultInstance(); + } + + public com.mogujie.tt.protobuf.IMFile.IMFileAddOfflineReq build() { + com.mogujie.tt.protobuf.IMFile.IMFileAddOfflineReq result = buildPartial(); + if (!result.isInitialized()) { + throw newUninitializedMessageException(result); + } + return result; + } + + public com.mogujie.tt.protobuf.IMFile.IMFileAddOfflineReq buildPartial() { + com.mogujie.tt.protobuf.IMFile.IMFileAddOfflineReq result = new com.mogujie.tt.protobuf.IMFile.IMFileAddOfflineReq(this); + int from_bitField0_ = bitField0_; + int to_bitField0_ = 0; + if (((from_bitField0_ & 0x00000001) == 0x00000001)) { + to_bitField0_ |= 0x00000001; + } + result.fromUserId_ = fromUserId_; + if (((from_bitField0_ & 0x00000002) == 0x00000002)) { + to_bitField0_ |= 0x00000002; + } + result.toUserId_ = toUserId_; + if (((from_bitField0_ & 0x00000004) == 0x00000004)) { + to_bitField0_ |= 0x00000004; + } + result.taskId_ = taskId_; + if (((from_bitField0_ & 0x00000008) == 0x00000008)) { + to_bitField0_ |= 0x00000008; + } + result.fileName_ = fileName_; + if (((from_bitField0_ & 0x00000010) == 0x00000010)) { + to_bitField0_ |= 0x00000010; + } + result.fileSize_ = fileSize_; + result.bitField0_ = to_bitField0_; + return result; + } + + public Builder mergeFrom(com.mogujie.tt.protobuf.IMFile.IMFileAddOfflineReq other) { + if (other == com.mogujie.tt.protobuf.IMFile.IMFileAddOfflineReq.getDefaultInstance()) return this; + if (other.hasFromUserId()) { + setFromUserId(other.getFromUserId()); + } + if (other.hasToUserId()) { + setToUserId(other.getToUserId()); + } + if (other.hasTaskId()) { + bitField0_ |= 0x00000004; + taskId_ = other.taskId_; + + } + if (other.hasFileName()) { + bitField0_ |= 0x00000008; + fileName_ = other.fileName_; + + } + if (other.hasFileSize()) { + setFileSize(other.getFileSize()); + } + setUnknownFields( + getUnknownFields().concat(other.unknownFields)); + return this; + } + + public final boolean isInitialized() { + if (!hasFromUserId()) { + + return false; + } + if (!hasToUserId()) { + + return false; + } + if (!hasTaskId()) { + + return false; + } + if (!hasFileName()) { + + return false; + } + if (!hasFileSize()) { + + return false; + } + return true; + } + + public Builder mergeFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + com.mogujie.tt.protobuf.IMFile.IMFileAddOfflineReq parsedMessage = null; + try { + parsedMessage = PARSER.parsePartialFrom(input, extensionRegistry); + } catch (com.google.protobuf.InvalidProtocolBufferException e) { + parsedMessage = (com.mogujie.tt.protobuf.IMFile.IMFileAddOfflineReq) e.getUnfinishedMessage(); + throw e; + } finally { + if (parsedMessage != null) { + mergeFrom(parsedMessage); + } + } + return this; + } + private int bitField0_; + + private int fromUserId_ ; + /** + * required uint32 from_user_id = 1; + * + *
+       *cmd id:	0x050b
+       * 
+ */ + public boolean hasFromUserId() { + return ((bitField0_ & 0x00000001) == 0x00000001); + } + /** + * required uint32 from_user_id = 1; + * + *
+       *cmd id:	0x050b
+       * 
+ */ + public int getFromUserId() { + return fromUserId_; + } + /** + * required uint32 from_user_id = 1; + * + *
+       *cmd id:	0x050b
+       * 
+ */ + public Builder setFromUserId(int value) { + bitField0_ |= 0x00000001; + fromUserId_ = value; + + return this; + } + /** + * required uint32 from_user_id = 1; + * + *
+       *cmd id:	0x050b
+       * 
+ */ + public Builder clearFromUserId() { + bitField0_ = (bitField0_ & ~0x00000001); + fromUserId_ = 0; + + return this; + } + + private int toUserId_ ; + /** + * required uint32 to_user_id = 2; + */ + public boolean hasToUserId() { + return ((bitField0_ & 0x00000002) == 0x00000002); + } + /** + * required uint32 to_user_id = 2; + */ + public int getToUserId() { + return toUserId_; + } + /** + * required uint32 to_user_id = 2; + */ + public Builder setToUserId(int value) { + bitField0_ |= 0x00000002; + toUserId_ = value; + + return this; + } + /** + * required uint32 to_user_id = 2; + */ + public Builder clearToUserId() { + bitField0_ = (bitField0_ & ~0x00000002); + toUserId_ = 0; + + return this; + } + + private java.lang.Object taskId_ = ""; + /** + * required string task_id = 3; + */ + public boolean hasTaskId() { + return ((bitField0_ & 0x00000004) == 0x00000004); + } + /** + * required string task_id = 3; + */ + public java.lang.String getTaskId() { + java.lang.Object ref = taskId_; + if (!(ref instanceof java.lang.String)) { + com.google.protobuf.ByteString bs = + (com.google.protobuf.ByteString) ref; + java.lang.String s = bs.toStringUtf8(); + if (bs.isValidUtf8()) { + taskId_ = s; + } + return s; + } else { + return (java.lang.String) ref; + } + } + /** + * required string task_id = 3; + */ + public com.google.protobuf.ByteString + getTaskIdBytes() { + java.lang.Object ref = taskId_; + if (ref instanceof String) { + com.google.protobuf.ByteString b = + com.google.protobuf.ByteString.copyFromUtf8( + (java.lang.String) ref); + taskId_ = b; + return b; + } else { + return (com.google.protobuf.ByteString) ref; + } + } + /** + * required string task_id = 3; + */ + public Builder setTaskId( + java.lang.String value) { + if (value == null) { + throw new NullPointerException(); + } + bitField0_ |= 0x00000004; + taskId_ = value; + + return this; + } + /** + * required string task_id = 3; + */ + public Builder clearTaskId() { + bitField0_ = (bitField0_ & ~0x00000004); + taskId_ = getDefaultInstance().getTaskId(); + + return this; + } + /** + * required string task_id = 3; + */ + public Builder setTaskIdBytes( + com.google.protobuf.ByteString value) { + if (value == null) { + throw new NullPointerException(); + } + bitField0_ |= 0x00000004; + taskId_ = value; + + return this; + } + + private java.lang.Object fileName_ = ""; + /** + * required string file_name = 4; + */ + public boolean hasFileName() { + return ((bitField0_ & 0x00000008) == 0x00000008); + } + /** + * required string file_name = 4; + */ + public java.lang.String getFileName() { + java.lang.Object ref = fileName_; + if (!(ref instanceof java.lang.String)) { + com.google.protobuf.ByteString bs = + (com.google.protobuf.ByteString) ref; + java.lang.String s = bs.toStringUtf8(); + if (bs.isValidUtf8()) { + fileName_ = s; + } + return s; + } else { + return (java.lang.String) ref; + } + } + /** + * required string file_name = 4; + */ + public com.google.protobuf.ByteString + getFileNameBytes() { + java.lang.Object ref = fileName_; + if (ref instanceof String) { + com.google.protobuf.ByteString b = + com.google.protobuf.ByteString.copyFromUtf8( + (java.lang.String) ref); + fileName_ = b; + return b; + } else { + return (com.google.protobuf.ByteString) ref; + } + } + /** + * required string file_name = 4; + */ + public Builder setFileName( + java.lang.String value) { + if (value == null) { + throw new NullPointerException(); + } + bitField0_ |= 0x00000008; + fileName_ = value; + + return this; + } + /** + * required string file_name = 4; + */ + public Builder clearFileName() { + bitField0_ = (bitField0_ & ~0x00000008); + fileName_ = getDefaultInstance().getFileName(); + + return this; + } + /** + * required string file_name = 4; + */ + public Builder setFileNameBytes( + com.google.protobuf.ByteString value) { + if (value == null) { + throw new NullPointerException(); + } + bitField0_ |= 0x00000008; + fileName_ = value; + + return this; + } + + private int fileSize_ ; + /** + * required uint32 file_size = 5; + */ + public boolean hasFileSize() { + return ((bitField0_ & 0x00000010) == 0x00000010); + } + /** + * required uint32 file_size = 5; + */ + public int getFileSize() { + return fileSize_; + } + /** + * required uint32 file_size = 5; + */ + public Builder setFileSize(int value) { + bitField0_ |= 0x00000010; + fileSize_ = value; + + return this; + } + /** + * required uint32 file_size = 5; + */ + public Builder clearFileSize() { + bitField0_ = (bitField0_ & ~0x00000010); + fileSize_ = 0; + + return this; + } + + // @@protoc_insertion_point(builder_scope:IM.File.IMFileAddOfflineReq) + } + + static { + defaultInstance = new IMFileAddOfflineReq(true); + defaultInstance.initFields(); + } + + // @@protoc_insertion_point(class_scope:IM.File.IMFileAddOfflineReq) + } + + public interface IMFileDelOfflineReqOrBuilder extends + // @@protoc_insertion_point(interface_extends:IM.File.IMFileDelOfflineReq) + com.google.protobuf.MessageLiteOrBuilder { + + /** + * required uint32 from_user_id = 1; + * + *
+     *cmd id:	0x050c
+     * 
+ */ + boolean hasFromUserId(); + /** + * required uint32 from_user_id = 1; + * + *
+     *cmd id:	0x050c
+     * 
+ */ + int getFromUserId(); + + /** + * required uint32 to_user_id = 2; + */ + boolean hasToUserId(); + /** + * required uint32 to_user_id = 2; + */ + int getToUserId(); + + /** + * required string task_id = 3; + */ + boolean hasTaskId(); + /** + * required string task_id = 3; + */ + java.lang.String getTaskId(); + /** + * required string task_id = 3; + */ + com.google.protobuf.ByteString + getTaskIdBytes(); + } + /** + * Protobuf type {@code IM.File.IMFileDelOfflineReq} + */ + public static final class IMFileDelOfflineReq extends + com.google.protobuf.GeneratedMessageLite implements + // @@protoc_insertion_point(message_implements:IM.File.IMFileDelOfflineReq) + IMFileDelOfflineReqOrBuilder { + // Use IMFileDelOfflineReq.newBuilder() to construct. + private IMFileDelOfflineReq(com.google.protobuf.GeneratedMessageLite.Builder builder) { + super(builder); + this.unknownFields = builder.getUnknownFields(); + } + private IMFileDelOfflineReq(boolean noInit) { this.unknownFields = com.google.protobuf.ByteString.EMPTY;} + + private static final IMFileDelOfflineReq defaultInstance; + public static IMFileDelOfflineReq getDefaultInstance() { + return defaultInstance; + } + + public IMFileDelOfflineReq getDefaultInstanceForType() { + return defaultInstance; + } + + private final com.google.protobuf.ByteString unknownFields; + private IMFileDelOfflineReq( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + initFields(); + int mutable_bitField0_ = 0; + com.google.protobuf.ByteString.Output unknownFieldsOutput = + com.google.protobuf.ByteString.newOutput(); + com.google.protobuf.CodedOutputStream unknownFieldsCodedOutput = + com.google.protobuf.CodedOutputStream.newInstance( + unknownFieldsOutput); + try { + boolean done = false; + while (!done) { + int tag = input.readTag(); + switch (tag) { + case 0: + done = true; + break; + default: { + if (!parseUnknownField(input, unknownFieldsCodedOutput, + extensionRegistry, tag)) { + done = true; + } + break; + } + case 8: { + bitField0_ |= 0x00000001; + fromUserId_ = input.readUInt32(); + break; + } + case 16: { + bitField0_ |= 0x00000002; + toUserId_ = input.readUInt32(); + break; + } + case 26: { + com.google.protobuf.ByteString bs = input.readBytes(); + bitField0_ |= 0x00000004; + taskId_ = bs; + break; + } + } + } + } catch (com.google.protobuf.InvalidProtocolBufferException e) { + throw e.setUnfinishedMessage(this); + } catch (java.io.IOException e) { + throw new com.google.protobuf.InvalidProtocolBufferException( + e.getMessage()).setUnfinishedMessage(this); + } finally { + try { + unknownFieldsCodedOutput.flush(); + } catch (java.io.IOException e) { + // Should not happen + } finally { + unknownFields = unknownFieldsOutput.toByteString(); + } + makeExtensionsImmutable(); + } + } + public static com.google.protobuf.Parser PARSER = + new com.google.protobuf.AbstractParser() { + public IMFileDelOfflineReq parsePartialFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return new IMFileDelOfflineReq(input, extensionRegistry); + } + }; + + @java.lang.Override + public com.google.protobuf.Parser getParserForType() { + return PARSER; + } + + private int bitField0_; + public static final int FROM_USER_ID_FIELD_NUMBER = 1; + private int fromUserId_; + /** + * required uint32 from_user_id = 1; + * + *
+     *cmd id:	0x050c
+     * 
+ */ + public boolean hasFromUserId() { + return ((bitField0_ & 0x00000001) == 0x00000001); + } + /** + * required uint32 from_user_id = 1; + * + *
+     *cmd id:	0x050c
+     * 
+ */ + public int getFromUserId() { + return fromUserId_; + } + + public static final int TO_USER_ID_FIELD_NUMBER = 2; + private int toUserId_; + /** + * required uint32 to_user_id = 2; + */ + public boolean hasToUserId() { + return ((bitField0_ & 0x00000002) == 0x00000002); + } + /** + * required uint32 to_user_id = 2; + */ + public int getToUserId() { + return toUserId_; + } + + public static final int TASK_ID_FIELD_NUMBER = 3; + private java.lang.Object taskId_; + /** + * required string task_id = 3; + */ + public boolean hasTaskId() { + return ((bitField0_ & 0x00000004) == 0x00000004); + } + /** + * required string task_id = 3; + */ + public java.lang.String getTaskId() { + java.lang.Object ref = taskId_; + if (ref instanceof java.lang.String) { + return (java.lang.String) ref; + } else { + com.google.protobuf.ByteString bs = + (com.google.protobuf.ByteString) ref; + java.lang.String s = bs.toStringUtf8(); + if (bs.isValidUtf8()) { + taskId_ = s; + } + return s; + } + } + /** + * required string task_id = 3; + */ + public com.google.protobuf.ByteString + getTaskIdBytes() { + java.lang.Object ref = taskId_; + if (ref instanceof java.lang.String) { + com.google.protobuf.ByteString b = + com.google.protobuf.ByteString.copyFromUtf8( + (java.lang.String) ref); + taskId_ = b; + return b; + } else { + return (com.google.protobuf.ByteString) ref; + } + } + + private void initFields() { + fromUserId_ = 0; + toUserId_ = 0; + taskId_ = ""; + } + private byte memoizedIsInitialized = -1; + public final boolean isInitialized() { + byte isInitialized = memoizedIsInitialized; + if (isInitialized == 1) return true; + if (isInitialized == 0) return false; + + if (!hasFromUserId()) { + memoizedIsInitialized = 0; + return false; + } + if (!hasToUserId()) { + memoizedIsInitialized = 0; + return false; + } + if (!hasTaskId()) { + memoizedIsInitialized = 0; + return false; + } + memoizedIsInitialized = 1; + return true; + } + + public void writeTo(com.google.protobuf.CodedOutputStream output) + throws java.io.IOException { + getSerializedSize(); + if (((bitField0_ & 0x00000001) == 0x00000001)) { + output.writeUInt32(1, fromUserId_); + } + if (((bitField0_ & 0x00000002) == 0x00000002)) { + output.writeUInt32(2, toUserId_); + } + if (((bitField0_ & 0x00000004) == 0x00000004)) { + output.writeBytes(3, getTaskIdBytes()); + } + output.writeRawBytes(unknownFields); + } + + private int memoizedSerializedSize = -1; + public int getSerializedSize() { + int size = memoizedSerializedSize; + if (size != -1) return size; + + size = 0; + if (((bitField0_ & 0x00000001) == 0x00000001)) { + size += com.google.protobuf.CodedOutputStream + .computeUInt32Size(1, fromUserId_); + } + if (((bitField0_ & 0x00000002) == 0x00000002)) { + size += com.google.protobuf.CodedOutputStream + .computeUInt32Size(2, toUserId_); + } + if (((bitField0_ & 0x00000004) == 0x00000004)) { + size += com.google.protobuf.CodedOutputStream + .computeBytesSize(3, getTaskIdBytes()); + } + size += unknownFields.size(); + memoizedSerializedSize = size; + return size; + } + + private static final long serialVersionUID = 0L; + @java.lang.Override + protected java.lang.Object writeReplace() + throws java.io.ObjectStreamException { + return super.writeReplace(); + } + + public static com.mogujie.tt.protobuf.IMFile.IMFileDelOfflineReq parseFrom( + com.google.protobuf.ByteString data) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data); + } + public static com.mogujie.tt.protobuf.IMFile.IMFileDelOfflineReq parseFrom( + com.google.protobuf.ByteString data, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data, extensionRegistry); + } + public static com.mogujie.tt.protobuf.IMFile.IMFileDelOfflineReq parseFrom(byte[] data) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data); + } + public static com.mogujie.tt.protobuf.IMFile.IMFileDelOfflineReq parseFrom( + byte[] data, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data, extensionRegistry); + } + public static com.mogujie.tt.protobuf.IMFile.IMFileDelOfflineReq parseFrom(java.io.InputStream input) + throws java.io.IOException { + return PARSER.parseFrom(input); + } + public static com.mogujie.tt.protobuf.IMFile.IMFileDelOfflineReq parseFrom( + java.io.InputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return PARSER.parseFrom(input, extensionRegistry); + } + public static com.mogujie.tt.protobuf.IMFile.IMFileDelOfflineReq parseDelimitedFrom(java.io.InputStream input) + throws java.io.IOException { + return PARSER.parseDelimitedFrom(input); + } + public static com.mogujie.tt.protobuf.IMFile.IMFileDelOfflineReq parseDelimitedFrom( + java.io.InputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return PARSER.parseDelimitedFrom(input, extensionRegistry); + } + public static com.mogujie.tt.protobuf.IMFile.IMFileDelOfflineReq parseFrom( + com.google.protobuf.CodedInputStream input) + throws java.io.IOException { + return PARSER.parseFrom(input); + } + public static com.mogujie.tt.protobuf.IMFile.IMFileDelOfflineReq parseFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return PARSER.parseFrom(input, extensionRegistry); + } + + public static Builder newBuilder() { return Builder.create(); } + public Builder newBuilderForType() { return newBuilder(); } + public static Builder newBuilder(com.mogujie.tt.protobuf.IMFile.IMFileDelOfflineReq prototype) { + return newBuilder().mergeFrom(prototype); + } + public Builder toBuilder() { return newBuilder(this); } + + /** + * Protobuf type {@code IM.File.IMFileDelOfflineReq} + */ + public static final class Builder extends + com.google.protobuf.GeneratedMessageLite.Builder< + com.mogujie.tt.protobuf.IMFile.IMFileDelOfflineReq, Builder> + implements + // @@protoc_insertion_point(builder_implements:IM.File.IMFileDelOfflineReq) + com.mogujie.tt.protobuf.IMFile.IMFileDelOfflineReqOrBuilder { + // Construct using com.mogujie.tt.protobuf.IMFile.IMFileDelOfflineReq.newBuilder() + private Builder() { + maybeForceBuilderInitialization(); + } + + private void maybeForceBuilderInitialization() { + } + private static Builder create() { + return new Builder(); + } + + public Builder clear() { + super.clear(); + fromUserId_ = 0; + bitField0_ = (bitField0_ & ~0x00000001); + toUserId_ = 0; + bitField0_ = (bitField0_ & ~0x00000002); + taskId_ = ""; + bitField0_ = (bitField0_ & ~0x00000004); + return this; + } + + public Builder clone() { + return create().mergeFrom(buildPartial()); + } + + public com.mogujie.tt.protobuf.IMFile.IMFileDelOfflineReq getDefaultInstanceForType() { + return com.mogujie.tt.protobuf.IMFile.IMFileDelOfflineReq.getDefaultInstance(); + } + + public com.mogujie.tt.protobuf.IMFile.IMFileDelOfflineReq build() { + com.mogujie.tt.protobuf.IMFile.IMFileDelOfflineReq result = buildPartial(); + if (!result.isInitialized()) { + throw newUninitializedMessageException(result); + } + return result; + } + + public com.mogujie.tt.protobuf.IMFile.IMFileDelOfflineReq buildPartial() { + com.mogujie.tt.protobuf.IMFile.IMFileDelOfflineReq result = new com.mogujie.tt.protobuf.IMFile.IMFileDelOfflineReq(this); + int from_bitField0_ = bitField0_; + int to_bitField0_ = 0; + if (((from_bitField0_ & 0x00000001) == 0x00000001)) { + to_bitField0_ |= 0x00000001; + } + result.fromUserId_ = fromUserId_; + if (((from_bitField0_ & 0x00000002) == 0x00000002)) { + to_bitField0_ |= 0x00000002; + } + result.toUserId_ = toUserId_; + if (((from_bitField0_ & 0x00000004) == 0x00000004)) { + to_bitField0_ |= 0x00000004; + } + result.taskId_ = taskId_; + result.bitField0_ = to_bitField0_; + return result; + } + + public Builder mergeFrom(com.mogujie.tt.protobuf.IMFile.IMFileDelOfflineReq other) { + if (other == com.mogujie.tt.protobuf.IMFile.IMFileDelOfflineReq.getDefaultInstance()) return this; + if (other.hasFromUserId()) { + setFromUserId(other.getFromUserId()); + } + if (other.hasToUserId()) { + setToUserId(other.getToUserId()); + } + if (other.hasTaskId()) { + bitField0_ |= 0x00000004; + taskId_ = other.taskId_; + + } + setUnknownFields( + getUnknownFields().concat(other.unknownFields)); + return this; + } + + public final boolean isInitialized() { + if (!hasFromUserId()) { + + return false; + } + if (!hasToUserId()) { + + return false; + } + if (!hasTaskId()) { + + return false; + } + return true; + } + + public Builder mergeFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + com.mogujie.tt.protobuf.IMFile.IMFileDelOfflineReq parsedMessage = null; + try { + parsedMessage = PARSER.parsePartialFrom(input, extensionRegistry); + } catch (com.google.protobuf.InvalidProtocolBufferException e) { + parsedMessage = (com.mogujie.tt.protobuf.IMFile.IMFileDelOfflineReq) e.getUnfinishedMessage(); + throw e; + } finally { + if (parsedMessage != null) { + mergeFrom(parsedMessage); + } + } + return this; + } + private int bitField0_; + + private int fromUserId_ ; + /** + * required uint32 from_user_id = 1; + * + *
+       *cmd id:	0x050c
+       * 
+ */ + public boolean hasFromUserId() { + return ((bitField0_ & 0x00000001) == 0x00000001); + } + /** + * required uint32 from_user_id = 1; + * + *
+       *cmd id:	0x050c
+       * 
+ */ + public int getFromUserId() { + return fromUserId_; + } + /** + * required uint32 from_user_id = 1; + * + *
+       *cmd id:	0x050c
+       * 
+ */ + public Builder setFromUserId(int value) { + bitField0_ |= 0x00000001; + fromUserId_ = value; + + return this; + } + /** + * required uint32 from_user_id = 1; + * + *
+       *cmd id:	0x050c
+       * 
+ */ + public Builder clearFromUserId() { + bitField0_ = (bitField0_ & ~0x00000001); + fromUserId_ = 0; + + return this; + } + + private int toUserId_ ; + /** + * required uint32 to_user_id = 2; + */ + public boolean hasToUserId() { + return ((bitField0_ & 0x00000002) == 0x00000002); + } + /** + * required uint32 to_user_id = 2; + */ + public int getToUserId() { + return toUserId_; + } + /** + * required uint32 to_user_id = 2; + */ + public Builder setToUserId(int value) { + bitField0_ |= 0x00000002; + toUserId_ = value; + + return this; + } + /** + * required uint32 to_user_id = 2; + */ + public Builder clearToUserId() { + bitField0_ = (bitField0_ & ~0x00000002); + toUserId_ = 0; + + return this; + } + + private java.lang.Object taskId_ = ""; + /** + * required string task_id = 3; + */ + public boolean hasTaskId() { + return ((bitField0_ & 0x00000004) == 0x00000004); + } + /** + * required string task_id = 3; + */ + public java.lang.String getTaskId() { + java.lang.Object ref = taskId_; + if (!(ref instanceof java.lang.String)) { + com.google.protobuf.ByteString bs = + (com.google.protobuf.ByteString) ref; + java.lang.String s = bs.toStringUtf8(); + if (bs.isValidUtf8()) { + taskId_ = s; + } + return s; + } else { + return (java.lang.String) ref; + } + } + /** + * required string task_id = 3; + */ + public com.google.protobuf.ByteString + getTaskIdBytes() { + java.lang.Object ref = taskId_; + if (ref instanceof String) { + com.google.protobuf.ByteString b = + com.google.protobuf.ByteString.copyFromUtf8( + (java.lang.String) ref); + taskId_ = b; + return b; + } else { + return (com.google.protobuf.ByteString) ref; + } + } + /** + * required string task_id = 3; + */ + public Builder setTaskId( + java.lang.String value) { + if (value == null) { + throw new NullPointerException(); + } + bitField0_ |= 0x00000004; + taskId_ = value; + + return this; + } + /** + * required string task_id = 3; + */ + public Builder clearTaskId() { + bitField0_ = (bitField0_ & ~0x00000004); + taskId_ = getDefaultInstance().getTaskId(); + + return this; + } + /** + * required string task_id = 3; + */ + public Builder setTaskIdBytes( + com.google.protobuf.ByteString value) { + if (value == null) { + throw new NullPointerException(); + } + bitField0_ |= 0x00000004; + taskId_ = value; + + return this; + } + + // @@protoc_insertion_point(builder_scope:IM.File.IMFileDelOfflineReq) + } + + static { + defaultInstance = new IMFileDelOfflineReq(true); + defaultInstance.initFields(); + } + + // @@protoc_insertion_point(class_scope:IM.File.IMFileDelOfflineReq) + } + + + static { + } + + // @@protoc_insertion_point(outer_class_scope) +} diff --git a/android/app/src/main/java/com/mogujie/tt/protobuf/IMGroup.java b/android/app/src/main/java/com/mogujie/tt/protobuf/IMGroup.java new file mode 100644 index 000000000..8c6539201 --- /dev/null +++ b/android/app/src/main/java/com/mogujie/tt/protobuf/IMGroup.java @@ -0,0 +1,8892 @@ +// Generated by the protocol buffer compiler. DO NOT EDIT! +// source: IM.Group.proto + +package com.mogujie.tt.protobuf; + +public final class IMGroup { + private IMGroup() {} + public static void registerAllExtensions( + com.google.protobuf.ExtensionRegistryLite registry) { + } + public interface IMNormalGroupListReqOrBuilder extends + // @@protoc_insertion_point(interface_extends:IM.Group.IMNormalGroupListReq) + com.google.protobuf.MessageLiteOrBuilder { + + /** + * required uint32 user_id = 1; + * + *
+     *cmd id:			0x0401
+     * 
+ */ + boolean hasUserId(); + /** + * required uint32 user_id = 1; + * + *
+     *cmd id:			0x0401
+     * 
+ */ + int getUserId(); + + /** + * optional bytes attach_data = 20; + */ + boolean hasAttachData(); + /** + * optional bytes attach_data = 20; + */ + com.google.protobuf.ByteString getAttachData(); + } + /** + * Protobuf type {@code IM.Group.IMNormalGroupListReq} + */ + public static final class IMNormalGroupListReq extends + com.google.protobuf.GeneratedMessageLite implements + // @@protoc_insertion_point(message_implements:IM.Group.IMNormalGroupListReq) + IMNormalGroupListReqOrBuilder { + // Use IMNormalGroupListReq.newBuilder() to construct. + private IMNormalGroupListReq(com.google.protobuf.GeneratedMessageLite.Builder builder) { + super(builder); + this.unknownFields = builder.getUnknownFields(); + } + private IMNormalGroupListReq(boolean noInit) { this.unknownFields = com.google.protobuf.ByteString.EMPTY;} + + private static final IMNormalGroupListReq defaultInstance; + public static IMNormalGroupListReq getDefaultInstance() { + return defaultInstance; + } + + public IMNormalGroupListReq getDefaultInstanceForType() { + return defaultInstance; + } + + private final com.google.protobuf.ByteString unknownFields; + private IMNormalGroupListReq( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + initFields(); + int mutable_bitField0_ = 0; + com.google.protobuf.ByteString.Output unknownFieldsOutput = + com.google.protobuf.ByteString.newOutput(); + com.google.protobuf.CodedOutputStream unknownFieldsCodedOutput = + com.google.protobuf.CodedOutputStream.newInstance( + unknownFieldsOutput); + try { + boolean done = false; + while (!done) { + int tag = input.readTag(); + switch (tag) { + case 0: + done = true; + break; + default: { + if (!parseUnknownField(input, unknownFieldsCodedOutput, + extensionRegistry, tag)) { + done = true; + } + break; + } + case 8: { + bitField0_ |= 0x00000001; + userId_ = input.readUInt32(); + break; + } + case 162: { + bitField0_ |= 0x00000002; + attachData_ = input.readBytes(); + break; + } + } + } + } catch (com.google.protobuf.InvalidProtocolBufferException e) { + throw e.setUnfinishedMessage(this); + } catch (java.io.IOException e) { + throw new com.google.protobuf.InvalidProtocolBufferException( + e.getMessage()).setUnfinishedMessage(this); + } finally { + try { + unknownFieldsCodedOutput.flush(); + } catch (java.io.IOException e) { + // Should not happen + } finally { + unknownFields = unknownFieldsOutput.toByteString(); + } + makeExtensionsImmutable(); + } + } + public static com.google.protobuf.Parser PARSER = + new com.google.protobuf.AbstractParser() { + public IMNormalGroupListReq parsePartialFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return new IMNormalGroupListReq(input, extensionRegistry); + } + }; + + @java.lang.Override + public com.google.protobuf.Parser getParserForType() { + return PARSER; + } + + private int bitField0_; + public static final int USER_ID_FIELD_NUMBER = 1; + private int userId_; + /** + * required uint32 user_id = 1; + * + *
+     *cmd id:			0x0401
+     * 
+ */ + public boolean hasUserId() { + return ((bitField0_ & 0x00000001) == 0x00000001); + } + /** + * required uint32 user_id = 1; + * + *
+     *cmd id:			0x0401
+     * 
+ */ + public int getUserId() { + return userId_; + } + + public static final int ATTACH_DATA_FIELD_NUMBER = 20; + private com.google.protobuf.ByteString attachData_; + /** + * optional bytes attach_data = 20; + */ + public boolean hasAttachData() { + return ((bitField0_ & 0x00000002) == 0x00000002); + } + /** + * optional bytes attach_data = 20; + */ + public com.google.protobuf.ByteString getAttachData() { + return attachData_; + } + + private void initFields() { + userId_ = 0; + attachData_ = com.google.protobuf.ByteString.EMPTY; + } + private byte memoizedIsInitialized = -1; + public final boolean isInitialized() { + byte isInitialized = memoizedIsInitialized; + if (isInitialized == 1) return true; + if (isInitialized == 0) return false; + + if (!hasUserId()) { + memoizedIsInitialized = 0; + return false; + } + memoizedIsInitialized = 1; + return true; + } + + public void writeTo(com.google.protobuf.CodedOutputStream output) + throws java.io.IOException { + getSerializedSize(); + if (((bitField0_ & 0x00000001) == 0x00000001)) { + output.writeUInt32(1, userId_); + } + if (((bitField0_ & 0x00000002) == 0x00000002)) { + output.writeBytes(20, attachData_); + } + output.writeRawBytes(unknownFields); + } + + private int memoizedSerializedSize = -1; + public int getSerializedSize() { + int size = memoizedSerializedSize; + if (size != -1) return size; + + size = 0; + if (((bitField0_ & 0x00000001) == 0x00000001)) { + size += com.google.protobuf.CodedOutputStream + .computeUInt32Size(1, userId_); + } + if (((bitField0_ & 0x00000002) == 0x00000002)) { + size += com.google.protobuf.CodedOutputStream + .computeBytesSize(20, attachData_); + } + size += unknownFields.size(); + memoizedSerializedSize = size; + return size; + } + + private static final long serialVersionUID = 0L; + @java.lang.Override + protected java.lang.Object writeReplace() + throws java.io.ObjectStreamException { + return super.writeReplace(); + } + + public static com.mogujie.tt.protobuf.IMGroup.IMNormalGroupListReq parseFrom( + com.google.protobuf.ByteString data) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data); + } + public static com.mogujie.tt.protobuf.IMGroup.IMNormalGroupListReq parseFrom( + com.google.protobuf.ByteString data, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data, extensionRegistry); + } + public static com.mogujie.tt.protobuf.IMGroup.IMNormalGroupListReq parseFrom(byte[] data) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data); + } + public static com.mogujie.tt.protobuf.IMGroup.IMNormalGroupListReq parseFrom( + byte[] data, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data, extensionRegistry); + } + public static com.mogujie.tt.protobuf.IMGroup.IMNormalGroupListReq parseFrom(java.io.InputStream input) + throws java.io.IOException { + return PARSER.parseFrom(input); + } + public static com.mogujie.tt.protobuf.IMGroup.IMNormalGroupListReq parseFrom( + java.io.InputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return PARSER.parseFrom(input, extensionRegistry); + } + public static com.mogujie.tt.protobuf.IMGroup.IMNormalGroupListReq parseDelimitedFrom(java.io.InputStream input) + throws java.io.IOException { + return PARSER.parseDelimitedFrom(input); + } + public static com.mogujie.tt.protobuf.IMGroup.IMNormalGroupListReq parseDelimitedFrom( + java.io.InputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return PARSER.parseDelimitedFrom(input, extensionRegistry); + } + public static com.mogujie.tt.protobuf.IMGroup.IMNormalGroupListReq parseFrom( + com.google.protobuf.CodedInputStream input) + throws java.io.IOException { + return PARSER.parseFrom(input); + } + public static com.mogujie.tt.protobuf.IMGroup.IMNormalGroupListReq parseFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return PARSER.parseFrom(input, extensionRegistry); + } + + public static Builder newBuilder() { return Builder.create(); } + public Builder newBuilderForType() { return newBuilder(); } + public static Builder newBuilder(com.mogujie.tt.protobuf.IMGroup.IMNormalGroupListReq prototype) { + return newBuilder().mergeFrom(prototype); + } + public Builder toBuilder() { return newBuilder(this); } + + /** + * Protobuf type {@code IM.Group.IMNormalGroupListReq} + */ + public static final class Builder extends + com.google.protobuf.GeneratedMessageLite.Builder< + com.mogujie.tt.protobuf.IMGroup.IMNormalGroupListReq, Builder> + implements + // @@protoc_insertion_point(builder_implements:IM.Group.IMNormalGroupListReq) + com.mogujie.tt.protobuf.IMGroup.IMNormalGroupListReqOrBuilder { + // Construct using com.mogujie.tt.protobuf.IMGroup.IMNormalGroupListReq.newBuilder() + private Builder() { + maybeForceBuilderInitialization(); + } + + private void maybeForceBuilderInitialization() { + } + private static Builder create() { + return new Builder(); + } + + public Builder clear() { + super.clear(); + userId_ = 0; + bitField0_ = (bitField0_ & ~0x00000001); + attachData_ = com.google.protobuf.ByteString.EMPTY; + bitField0_ = (bitField0_ & ~0x00000002); + return this; + } + + public Builder clone() { + return create().mergeFrom(buildPartial()); + } + + public com.mogujie.tt.protobuf.IMGroup.IMNormalGroupListReq getDefaultInstanceForType() { + return com.mogujie.tt.protobuf.IMGroup.IMNormalGroupListReq.getDefaultInstance(); + } + + public com.mogujie.tt.protobuf.IMGroup.IMNormalGroupListReq build() { + com.mogujie.tt.protobuf.IMGroup.IMNormalGroupListReq result = buildPartial(); + if (!result.isInitialized()) { + throw newUninitializedMessageException(result); + } + return result; + } + + public com.mogujie.tt.protobuf.IMGroup.IMNormalGroupListReq buildPartial() { + com.mogujie.tt.protobuf.IMGroup.IMNormalGroupListReq result = new com.mogujie.tt.protobuf.IMGroup.IMNormalGroupListReq(this); + int from_bitField0_ = bitField0_; + int to_bitField0_ = 0; + if (((from_bitField0_ & 0x00000001) == 0x00000001)) { + to_bitField0_ |= 0x00000001; + } + result.userId_ = userId_; + if (((from_bitField0_ & 0x00000002) == 0x00000002)) { + to_bitField0_ |= 0x00000002; + } + result.attachData_ = attachData_; + result.bitField0_ = to_bitField0_; + return result; + } + + public Builder mergeFrom(com.mogujie.tt.protobuf.IMGroup.IMNormalGroupListReq other) { + if (other == com.mogujie.tt.protobuf.IMGroup.IMNormalGroupListReq.getDefaultInstance()) return this; + if (other.hasUserId()) { + setUserId(other.getUserId()); + } + if (other.hasAttachData()) { + setAttachData(other.getAttachData()); + } + setUnknownFields( + getUnknownFields().concat(other.unknownFields)); + return this; + } + + public final boolean isInitialized() { + if (!hasUserId()) { + + return false; + } + return true; + } + + public Builder mergeFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + com.mogujie.tt.protobuf.IMGroup.IMNormalGroupListReq parsedMessage = null; + try { + parsedMessage = PARSER.parsePartialFrom(input, extensionRegistry); + } catch (com.google.protobuf.InvalidProtocolBufferException e) { + parsedMessage = (com.mogujie.tt.protobuf.IMGroup.IMNormalGroupListReq) e.getUnfinishedMessage(); + throw e; + } finally { + if (parsedMessage != null) { + mergeFrom(parsedMessage); + } + } + return this; + } + private int bitField0_; + + private int userId_ ; + /** + * required uint32 user_id = 1; + * + *
+       *cmd id:			0x0401
+       * 
+ */ + public boolean hasUserId() { + return ((bitField0_ & 0x00000001) == 0x00000001); + } + /** + * required uint32 user_id = 1; + * + *
+       *cmd id:			0x0401
+       * 
+ */ + public int getUserId() { + return userId_; + } + /** + * required uint32 user_id = 1; + * + *
+       *cmd id:			0x0401
+       * 
+ */ + public Builder setUserId(int value) { + bitField0_ |= 0x00000001; + userId_ = value; + + return this; + } + /** + * required uint32 user_id = 1; + * + *
+       *cmd id:			0x0401
+       * 
+ */ + public Builder clearUserId() { + bitField0_ = (bitField0_ & ~0x00000001); + userId_ = 0; + + return this; + } + + private com.google.protobuf.ByteString attachData_ = com.google.protobuf.ByteString.EMPTY; + /** + * optional bytes attach_data = 20; + */ + public boolean hasAttachData() { + return ((bitField0_ & 0x00000002) == 0x00000002); + } + /** + * optional bytes attach_data = 20; + */ + public com.google.protobuf.ByteString getAttachData() { + return attachData_; + } + /** + * optional bytes attach_data = 20; + */ + public Builder setAttachData(com.google.protobuf.ByteString value) { + if (value == null) { + throw new NullPointerException(); + } + bitField0_ |= 0x00000002; + attachData_ = value; + + return this; + } + /** + * optional bytes attach_data = 20; + */ + public Builder clearAttachData() { + bitField0_ = (bitField0_ & ~0x00000002); + attachData_ = getDefaultInstance().getAttachData(); + + return this; + } + + // @@protoc_insertion_point(builder_scope:IM.Group.IMNormalGroupListReq) + } + + static { + defaultInstance = new IMNormalGroupListReq(true); + defaultInstance.initFields(); + } + + // @@protoc_insertion_point(class_scope:IM.Group.IMNormalGroupListReq) + } + + public interface IMNormalGroupListRspOrBuilder extends + // @@protoc_insertion_point(interface_extends:IM.Group.IMNormalGroupListRsp) + com.google.protobuf.MessageLiteOrBuilder { + + /** + * required uint32 user_id = 1; + * + *
+     *cmd id:			0x0402
+     * 
+ */ + boolean hasUserId(); + /** + * required uint32 user_id = 1; + * + *
+     *cmd id:			0x0402
+     * 
+ */ + int getUserId(); + + /** + * repeated .IM.BaseDefine.GroupVersionInfo group_version_list = 2; + */ + java.util.List + getGroupVersionListList(); + /** + * repeated .IM.BaseDefine.GroupVersionInfo group_version_list = 2; + */ + com.mogujie.tt.protobuf.IMBaseDefine.GroupVersionInfo getGroupVersionList(int index); + /** + * repeated .IM.BaseDefine.GroupVersionInfo group_version_list = 2; + */ + int getGroupVersionListCount(); + + /** + * optional bytes attach_data = 20; + */ + boolean hasAttachData(); + /** + * optional bytes attach_data = 20; + */ + com.google.protobuf.ByteString getAttachData(); + } + /** + * Protobuf type {@code IM.Group.IMNormalGroupListRsp} + */ + public static final class IMNormalGroupListRsp extends + com.google.protobuf.GeneratedMessageLite implements + // @@protoc_insertion_point(message_implements:IM.Group.IMNormalGroupListRsp) + IMNormalGroupListRspOrBuilder { + // Use IMNormalGroupListRsp.newBuilder() to construct. + private IMNormalGroupListRsp(com.google.protobuf.GeneratedMessageLite.Builder builder) { + super(builder); + this.unknownFields = builder.getUnknownFields(); + } + private IMNormalGroupListRsp(boolean noInit) { this.unknownFields = com.google.protobuf.ByteString.EMPTY;} + + private static final IMNormalGroupListRsp defaultInstance; + public static IMNormalGroupListRsp getDefaultInstance() { + return defaultInstance; + } + + public IMNormalGroupListRsp getDefaultInstanceForType() { + return defaultInstance; + } + + private final com.google.protobuf.ByteString unknownFields; + private IMNormalGroupListRsp( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + initFields(); + int mutable_bitField0_ = 0; + com.google.protobuf.ByteString.Output unknownFieldsOutput = + com.google.protobuf.ByteString.newOutput(); + com.google.protobuf.CodedOutputStream unknownFieldsCodedOutput = + com.google.protobuf.CodedOutputStream.newInstance( + unknownFieldsOutput); + try { + boolean done = false; + while (!done) { + int tag = input.readTag(); + switch (tag) { + case 0: + done = true; + break; + default: { + if (!parseUnknownField(input, unknownFieldsCodedOutput, + extensionRegistry, tag)) { + done = true; + } + break; + } + case 8: { + bitField0_ |= 0x00000001; + userId_ = input.readUInt32(); + break; + } + case 18: { + if (!((mutable_bitField0_ & 0x00000002) == 0x00000002)) { + groupVersionList_ = new java.util.ArrayList(); + mutable_bitField0_ |= 0x00000002; + } + groupVersionList_.add(input.readMessage(com.mogujie.tt.protobuf.IMBaseDefine.GroupVersionInfo.PARSER, extensionRegistry)); + break; + } + case 162: { + bitField0_ |= 0x00000002; + attachData_ = input.readBytes(); + break; + } + } + } + } catch (com.google.protobuf.InvalidProtocolBufferException e) { + throw e.setUnfinishedMessage(this); + } catch (java.io.IOException e) { + throw new com.google.protobuf.InvalidProtocolBufferException( + e.getMessage()).setUnfinishedMessage(this); + } finally { + if (((mutable_bitField0_ & 0x00000002) == 0x00000002)) { + groupVersionList_ = java.util.Collections.unmodifiableList(groupVersionList_); + } + try { + unknownFieldsCodedOutput.flush(); + } catch (java.io.IOException e) { + // Should not happen + } finally { + unknownFields = unknownFieldsOutput.toByteString(); + } + makeExtensionsImmutable(); + } + } + public static com.google.protobuf.Parser PARSER = + new com.google.protobuf.AbstractParser() { + public IMNormalGroupListRsp parsePartialFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return new IMNormalGroupListRsp(input, extensionRegistry); + } + }; + + @java.lang.Override + public com.google.protobuf.Parser getParserForType() { + return PARSER; + } + + private int bitField0_; + public static final int USER_ID_FIELD_NUMBER = 1; + private int userId_; + /** + * required uint32 user_id = 1; + * + *
+     *cmd id:			0x0402
+     * 
+ */ + public boolean hasUserId() { + return ((bitField0_ & 0x00000001) == 0x00000001); + } + /** + * required uint32 user_id = 1; + * + *
+     *cmd id:			0x0402
+     * 
+ */ + public int getUserId() { + return userId_; + } + + public static final int GROUP_VERSION_LIST_FIELD_NUMBER = 2; + private java.util.List groupVersionList_; + /** + * repeated .IM.BaseDefine.GroupVersionInfo group_version_list = 2; + */ + public java.util.List getGroupVersionListList() { + return groupVersionList_; + } + /** + * repeated .IM.BaseDefine.GroupVersionInfo group_version_list = 2; + */ + public java.util.List + getGroupVersionListOrBuilderList() { + return groupVersionList_; + } + /** + * repeated .IM.BaseDefine.GroupVersionInfo group_version_list = 2; + */ + public int getGroupVersionListCount() { + return groupVersionList_.size(); + } + /** + * repeated .IM.BaseDefine.GroupVersionInfo group_version_list = 2; + */ + public com.mogujie.tt.protobuf.IMBaseDefine.GroupVersionInfo getGroupVersionList(int index) { + return groupVersionList_.get(index); + } + /** + * repeated .IM.BaseDefine.GroupVersionInfo group_version_list = 2; + */ + public com.mogujie.tt.protobuf.IMBaseDefine.GroupVersionInfoOrBuilder getGroupVersionListOrBuilder( + int index) { + return groupVersionList_.get(index); + } + + public static final int ATTACH_DATA_FIELD_NUMBER = 20; + private com.google.protobuf.ByteString attachData_; + /** + * optional bytes attach_data = 20; + */ + public boolean hasAttachData() { + return ((bitField0_ & 0x00000002) == 0x00000002); + } + /** + * optional bytes attach_data = 20; + */ + public com.google.protobuf.ByteString getAttachData() { + return attachData_; + } + + private void initFields() { + userId_ = 0; + groupVersionList_ = java.util.Collections.emptyList(); + attachData_ = com.google.protobuf.ByteString.EMPTY; + } + private byte memoizedIsInitialized = -1; + public final boolean isInitialized() { + byte isInitialized = memoizedIsInitialized; + if (isInitialized == 1) return true; + if (isInitialized == 0) return false; + + if (!hasUserId()) { + memoizedIsInitialized = 0; + return false; + } + for (int i = 0; i < getGroupVersionListCount(); i++) { + if (!getGroupVersionList(i).isInitialized()) { + memoizedIsInitialized = 0; + return false; + } + } + memoizedIsInitialized = 1; + return true; + } + + public void writeTo(com.google.protobuf.CodedOutputStream output) + throws java.io.IOException { + getSerializedSize(); + if (((bitField0_ & 0x00000001) == 0x00000001)) { + output.writeUInt32(1, userId_); + } + for (int i = 0; i < groupVersionList_.size(); i++) { + output.writeMessage(2, groupVersionList_.get(i)); + } + if (((bitField0_ & 0x00000002) == 0x00000002)) { + output.writeBytes(20, attachData_); + } + output.writeRawBytes(unknownFields); + } + + private int memoizedSerializedSize = -1; + public int getSerializedSize() { + int size = memoizedSerializedSize; + if (size != -1) return size; + + size = 0; + if (((bitField0_ & 0x00000001) == 0x00000001)) { + size += com.google.protobuf.CodedOutputStream + .computeUInt32Size(1, userId_); + } + for (int i = 0; i < groupVersionList_.size(); i++) { + size += com.google.protobuf.CodedOutputStream + .computeMessageSize(2, groupVersionList_.get(i)); + } + if (((bitField0_ & 0x00000002) == 0x00000002)) { + size += com.google.protobuf.CodedOutputStream + .computeBytesSize(20, attachData_); + } + size += unknownFields.size(); + memoizedSerializedSize = size; + return size; + } + + private static final long serialVersionUID = 0L; + @java.lang.Override + protected java.lang.Object writeReplace() + throws java.io.ObjectStreamException { + return super.writeReplace(); + } + + public static com.mogujie.tt.protobuf.IMGroup.IMNormalGroupListRsp parseFrom( + com.google.protobuf.ByteString data) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data); + } + public static com.mogujie.tt.protobuf.IMGroup.IMNormalGroupListRsp parseFrom( + com.google.protobuf.ByteString data, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data, extensionRegistry); + } + public static com.mogujie.tt.protobuf.IMGroup.IMNormalGroupListRsp parseFrom(byte[] data) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data); + } + public static com.mogujie.tt.protobuf.IMGroup.IMNormalGroupListRsp parseFrom( + byte[] data, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data, extensionRegistry); + } + public static com.mogujie.tt.protobuf.IMGroup.IMNormalGroupListRsp parseFrom(java.io.InputStream input) + throws java.io.IOException { + return PARSER.parseFrom(input); + } + public static com.mogujie.tt.protobuf.IMGroup.IMNormalGroupListRsp parseFrom( + java.io.InputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return PARSER.parseFrom(input, extensionRegistry); + } + public static com.mogujie.tt.protobuf.IMGroup.IMNormalGroupListRsp parseDelimitedFrom(java.io.InputStream input) + throws java.io.IOException { + return PARSER.parseDelimitedFrom(input); + } + public static com.mogujie.tt.protobuf.IMGroup.IMNormalGroupListRsp parseDelimitedFrom( + java.io.InputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return PARSER.parseDelimitedFrom(input, extensionRegistry); + } + public static com.mogujie.tt.protobuf.IMGroup.IMNormalGroupListRsp parseFrom( + com.google.protobuf.CodedInputStream input) + throws java.io.IOException { + return PARSER.parseFrom(input); + } + public static com.mogujie.tt.protobuf.IMGroup.IMNormalGroupListRsp parseFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return PARSER.parseFrom(input, extensionRegistry); + } + + public static Builder newBuilder() { return Builder.create(); } + public Builder newBuilderForType() { return newBuilder(); } + public static Builder newBuilder(com.mogujie.tt.protobuf.IMGroup.IMNormalGroupListRsp prototype) { + return newBuilder().mergeFrom(prototype); + } + public Builder toBuilder() { return newBuilder(this); } + + /** + * Protobuf type {@code IM.Group.IMNormalGroupListRsp} + */ + public static final class Builder extends + com.google.protobuf.GeneratedMessageLite.Builder< + com.mogujie.tt.protobuf.IMGroup.IMNormalGroupListRsp, Builder> + implements + // @@protoc_insertion_point(builder_implements:IM.Group.IMNormalGroupListRsp) + com.mogujie.tt.protobuf.IMGroup.IMNormalGroupListRspOrBuilder { + // Construct using com.mogujie.tt.protobuf.IMGroup.IMNormalGroupListRsp.newBuilder() + private Builder() { + maybeForceBuilderInitialization(); + } + + private void maybeForceBuilderInitialization() { + } + private static Builder create() { + return new Builder(); + } + + public Builder clear() { + super.clear(); + userId_ = 0; + bitField0_ = (bitField0_ & ~0x00000001); + groupVersionList_ = java.util.Collections.emptyList(); + bitField0_ = (bitField0_ & ~0x00000002); + attachData_ = com.google.protobuf.ByteString.EMPTY; + bitField0_ = (bitField0_ & ~0x00000004); + return this; + } + + public Builder clone() { + return create().mergeFrom(buildPartial()); + } + + public com.mogujie.tt.protobuf.IMGroup.IMNormalGroupListRsp getDefaultInstanceForType() { + return com.mogujie.tt.protobuf.IMGroup.IMNormalGroupListRsp.getDefaultInstance(); + } + + public com.mogujie.tt.protobuf.IMGroup.IMNormalGroupListRsp build() { + com.mogujie.tt.protobuf.IMGroup.IMNormalGroupListRsp result = buildPartial(); + if (!result.isInitialized()) { + throw newUninitializedMessageException(result); + } + return result; + } + + public com.mogujie.tt.protobuf.IMGroup.IMNormalGroupListRsp buildPartial() { + com.mogujie.tt.protobuf.IMGroup.IMNormalGroupListRsp result = new com.mogujie.tt.protobuf.IMGroup.IMNormalGroupListRsp(this); + int from_bitField0_ = bitField0_; + int to_bitField0_ = 0; + if (((from_bitField0_ & 0x00000001) == 0x00000001)) { + to_bitField0_ |= 0x00000001; + } + result.userId_ = userId_; + if (((bitField0_ & 0x00000002) == 0x00000002)) { + groupVersionList_ = java.util.Collections.unmodifiableList(groupVersionList_); + bitField0_ = (bitField0_ & ~0x00000002); + } + result.groupVersionList_ = groupVersionList_; + if (((from_bitField0_ & 0x00000004) == 0x00000004)) { + to_bitField0_ |= 0x00000002; + } + result.attachData_ = attachData_; + result.bitField0_ = to_bitField0_; + return result; + } + + public Builder mergeFrom(com.mogujie.tt.protobuf.IMGroup.IMNormalGroupListRsp other) { + if (other == com.mogujie.tt.protobuf.IMGroup.IMNormalGroupListRsp.getDefaultInstance()) return this; + if (other.hasUserId()) { + setUserId(other.getUserId()); + } + if (!other.groupVersionList_.isEmpty()) { + if (groupVersionList_.isEmpty()) { + groupVersionList_ = other.groupVersionList_; + bitField0_ = (bitField0_ & ~0x00000002); + } else { + ensureGroupVersionListIsMutable(); + groupVersionList_.addAll(other.groupVersionList_); + } + + } + if (other.hasAttachData()) { + setAttachData(other.getAttachData()); + } + setUnknownFields( + getUnknownFields().concat(other.unknownFields)); + return this; + } + + public final boolean isInitialized() { + if (!hasUserId()) { + + return false; + } + for (int i = 0; i < getGroupVersionListCount(); i++) { + if (!getGroupVersionList(i).isInitialized()) { + + return false; + } + } + return true; + } + + public Builder mergeFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + com.mogujie.tt.protobuf.IMGroup.IMNormalGroupListRsp parsedMessage = null; + try { + parsedMessage = PARSER.parsePartialFrom(input, extensionRegistry); + } catch (com.google.protobuf.InvalidProtocolBufferException e) { + parsedMessage = (com.mogujie.tt.protobuf.IMGroup.IMNormalGroupListRsp) e.getUnfinishedMessage(); + throw e; + } finally { + if (parsedMessage != null) { + mergeFrom(parsedMessage); + } + } + return this; + } + private int bitField0_; + + private int userId_ ; + /** + * required uint32 user_id = 1; + * + *
+       *cmd id:			0x0402
+       * 
+ */ + public boolean hasUserId() { + return ((bitField0_ & 0x00000001) == 0x00000001); + } + /** + * required uint32 user_id = 1; + * + *
+       *cmd id:			0x0402
+       * 
+ */ + public int getUserId() { + return userId_; + } + /** + * required uint32 user_id = 1; + * + *
+       *cmd id:			0x0402
+       * 
+ */ + public Builder setUserId(int value) { + bitField0_ |= 0x00000001; + userId_ = value; + + return this; + } + /** + * required uint32 user_id = 1; + * + *
+       *cmd id:			0x0402
+       * 
+ */ + public Builder clearUserId() { + bitField0_ = (bitField0_ & ~0x00000001); + userId_ = 0; + + return this; + } + + private java.util.List groupVersionList_ = + java.util.Collections.emptyList(); + private void ensureGroupVersionListIsMutable() { + if (!((bitField0_ & 0x00000002) == 0x00000002)) { + groupVersionList_ = new java.util.ArrayList(groupVersionList_); + bitField0_ |= 0x00000002; + } + } + + /** + * repeated .IM.BaseDefine.GroupVersionInfo group_version_list = 2; + */ + public java.util.List getGroupVersionListList() { + return java.util.Collections.unmodifiableList(groupVersionList_); + } + /** + * repeated .IM.BaseDefine.GroupVersionInfo group_version_list = 2; + */ + public int getGroupVersionListCount() { + return groupVersionList_.size(); + } + /** + * repeated .IM.BaseDefine.GroupVersionInfo group_version_list = 2; + */ + public com.mogujie.tt.protobuf.IMBaseDefine.GroupVersionInfo getGroupVersionList(int index) { + return groupVersionList_.get(index); + } + /** + * repeated .IM.BaseDefine.GroupVersionInfo group_version_list = 2; + */ + public Builder setGroupVersionList( + int index, com.mogujie.tt.protobuf.IMBaseDefine.GroupVersionInfo value) { + if (value == null) { + throw new NullPointerException(); + } + ensureGroupVersionListIsMutable(); + groupVersionList_.set(index, value); + + return this; + } + /** + * repeated .IM.BaseDefine.GroupVersionInfo group_version_list = 2; + */ + public Builder setGroupVersionList( + int index, com.mogujie.tt.protobuf.IMBaseDefine.GroupVersionInfo.Builder builderForValue) { + ensureGroupVersionListIsMutable(); + groupVersionList_.set(index, builderForValue.build()); + + return this; + } + /** + * repeated .IM.BaseDefine.GroupVersionInfo group_version_list = 2; + */ + public Builder addGroupVersionList(com.mogujie.tt.protobuf.IMBaseDefine.GroupVersionInfo value) { + if (value == null) { + throw new NullPointerException(); + } + ensureGroupVersionListIsMutable(); + groupVersionList_.add(value); + + return this; + } + /** + * repeated .IM.BaseDefine.GroupVersionInfo group_version_list = 2; + */ + public Builder addGroupVersionList( + int index, com.mogujie.tt.protobuf.IMBaseDefine.GroupVersionInfo value) { + if (value == null) { + throw new NullPointerException(); + } + ensureGroupVersionListIsMutable(); + groupVersionList_.add(index, value); + + return this; + } + /** + * repeated .IM.BaseDefine.GroupVersionInfo group_version_list = 2; + */ + public Builder addGroupVersionList( + com.mogujie.tt.protobuf.IMBaseDefine.GroupVersionInfo.Builder builderForValue) { + ensureGroupVersionListIsMutable(); + groupVersionList_.add(builderForValue.build()); + + return this; + } + /** + * repeated .IM.BaseDefine.GroupVersionInfo group_version_list = 2; + */ + public Builder addGroupVersionList( + int index, com.mogujie.tt.protobuf.IMBaseDefine.GroupVersionInfo.Builder builderForValue) { + ensureGroupVersionListIsMutable(); + groupVersionList_.add(index, builderForValue.build()); + + return this; + } + /** + * repeated .IM.BaseDefine.GroupVersionInfo group_version_list = 2; + */ + public Builder addAllGroupVersionList( + java.lang.Iterable values) { + ensureGroupVersionListIsMutable(); + com.google.protobuf.AbstractMessageLite.Builder.addAll( + values, groupVersionList_); + + return this; + } + /** + * repeated .IM.BaseDefine.GroupVersionInfo group_version_list = 2; + */ + public Builder clearGroupVersionList() { + groupVersionList_ = java.util.Collections.emptyList(); + bitField0_ = (bitField0_ & ~0x00000002); + + return this; + } + /** + * repeated .IM.BaseDefine.GroupVersionInfo group_version_list = 2; + */ + public Builder removeGroupVersionList(int index) { + ensureGroupVersionListIsMutable(); + groupVersionList_.remove(index); + + return this; + } + + private com.google.protobuf.ByteString attachData_ = com.google.protobuf.ByteString.EMPTY; + /** + * optional bytes attach_data = 20; + */ + public boolean hasAttachData() { + return ((bitField0_ & 0x00000004) == 0x00000004); + } + /** + * optional bytes attach_data = 20; + */ + public com.google.protobuf.ByteString getAttachData() { + return attachData_; + } + /** + * optional bytes attach_data = 20; + */ + public Builder setAttachData(com.google.protobuf.ByteString value) { + if (value == null) { + throw new NullPointerException(); + } + bitField0_ |= 0x00000004; + attachData_ = value; + + return this; + } + /** + * optional bytes attach_data = 20; + */ + public Builder clearAttachData() { + bitField0_ = (bitField0_ & ~0x00000004); + attachData_ = getDefaultInstance().getAttachData(); + + return this; + } + + // @@protoc_insertion_point(builder_scope:IM.Group.IMNormalGroupListRsp) + } + + static { + defaultInstance = new IMNormalGroupListRsp(true); + defaultInstance.initFields(); + } + + // @@protoc_insertion_point(class_scope:IM.Group.IMNormalGroupListRsp) + } + + public interface IMGroupInfoListReqOrBuilder extends + // @@protoc_insertion_point(interface_extends:IM.Group.IMGroupInfoListReq) + com.google.protobuf.MessageLiteOrBuilder { + + /** + * required uint32 user_id = 1; + * + *
+     *cmd id:			0x0403
+     * 
+ */ + boolean hasUserId(); + /** + * required uint32 user_id = 1; + * + *
+     *cmd id:			0x0403
+     * 
+ */ + int getUserId(); + + /** + * repeated .IM.BaseDefine.GroupVersionInfo group_version_list = 2; + */ + java.util.List + getGroupVersionListList(); + /** + * repeated .IM.BaseDefine.GroupVersionInfo group_version_list = 2; + */ + com.mogujie.tt.protobuf.IMBaseDefine.GroupVersionInfo getGroupVersionList(int index); + /** + * repeated .IM.BaseDefine.GroupVersionInfo group_version_list = 2; + */ + int getGroupVersionListCount(); + + /** + * optional bytes attach_data = 20; + */ + boolean hasAttachData(); + /** + * optional bytes attach_data = 20; + */ + com.google.protobuf.ByteString getAttachData(); + } + /** + * Protobuf type {@code IM.Group.IMGroupInfoListReq} + */ + public static final class IMGroupInfoListReq extends + com.google.protobuf.GeneratedMessageLite implements + // @@protoc_insertion_point(message_implements:IM.Group.IMGroupInfoListReq) + IMGroupInfoListReqOrBuilder { + // Use IMGroupInfoListReq.newBuilder() to construct. + private IMGroupInfoListReq(com.google.protobuf.GeneratedMessageLite.Builder builder) { + super(builder); + this.unknownFields = builder.getUnknownFields(); + } + private IMGroupInfoListReq(boolean noInit) { this.unknownFields = com.google.protobuf.ByteString.EMPTY;} + + private static final IMGroupInfoListReq defaultInstance; + public static IMGroupInfoListReq getDefaultInstance() { + return defaultInstance; + } + + public IMGroupInfoListReq getDefaultInstanceForType() { + return defaultInstance; + } + + private final com.google.protobuf.ByteString unknownFields; + private IMGroupInfoListReq( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + initFields(); + int mutable_bitField0_ = 0; + com.google.protobuf.ByteString.Output unknownFieldsOutput = + com.google.protobuf.ByteString.newOutput(); + com.google.protobuf.CodedOutputStream unknownFieldsCodedOutput = + com.google.protobuf.CodedOutputStream.newInstance( + unknownFieldsOutput); + try { + boolean done = false; + while (!done) { + int tag = input.readTag(); + switch (tag) { + case 0: + done = true; + break; + default: { + if (!parseUnknownField(input, unknownFieldsCodedOutput, + extensionRegistry, tag)) { + done = true; + } + break; + } + case 8: { + bitField0_ |= 0x00000001; + userId_ = input.readUInt32(); + break; + } + case 18: { + if (!((mutable_bitField0_ & 0x00000002) == 0x00000002)) { + groupVersionList_ = new java.util.ArrayList(); + mutable_bitField0_ |= 0x00000002; + } + groupVersionList_.add(input.readMessage(com.mogujie.tt.protobuf.IMBaseDefine.GroupVersionInfo.PARSER, extensionRegistry)); + break; + } + case 162: { + bitField0_ |= 0x00000002; + attachData_ = input.readBytes(); + break; + } + } + } + } catch (com.google.protobuf.InvalidProtocolBufferException e) { + throw e.setUnfinishedMessage(this); + } catch (java.io.IOException e) { + throw new com.google.protobuf.InvalidProtocolBufferException( + e.getMessage()).setUnfinishedMessage(this); + } finally { + if (((mutable_bitField0_ & 0x00000002) == 0x00000002)) { + groupVersionList_ = java.util.Collections.unmodifiableList(groupVersionList_); + } + try { + unknownFieldsCodedOutput.flush(); + } catch (java.io.IOException e) { + // Should not happen + } finally { + unknownFields = unknownFieldsOutput.toByteString(); + } + makeExtensionsImmutable(); + } + } + public static com.google.protobuf.Parser PARSER = + new com.google.protobuf.AbstractParser() { + public IMGroupInfoListReq parsePartialFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return new IMGroupInfoListReq(input, extensionRegistry); + } + }; + + @java.lang.Override + public com.google.protobuf.Parser getParserForType() { + return PARSER; + } + + private int bitField0_; + public static final int USER_ID_FIELD_NUMBER = 1; + private int userId_; + /** + * required uint32 user_id = 1; + * + *
+     *cmd id:			0x0403
+     * 
+ */ + public boolean hasUserId() { + return ((bitField0_ & 0x00000001) == 0x00000001); + } + /** + * required uint32 user_id = 1; + * + *
+     *cmd id:			0x0403
+     * 
+ */ + public int getUserId() { + return userId_; + } + + public static final int GROUP_VERSION_LIST_FIELD_NUMBER = 2; + private java.util.List groupVersionList_; + /** + * repeated .IM.BaseDefine.GroupVersionInfo group_version_list = 2; + */ + public java.util.List getGroupVersionListList() { + return groupVersionList_; + } + /** + * repeated .IM.BaseDefine.GroupVersionInfo group_version_list = 2; + */ + public java.util.List + getGroupVersionListOrBuilderList() { + return groupVersionList_; + } + /** + * repeated .IM.BaseDefine.GroupVersionInfo group_version_list = 2; + */ + public int getGroupVersionListCount() { + return groupVersionList_.size(); + } + /** + * repeated .IM.BaseDefine.GroupVersionInfo group_version_list = 2; + */ + public com.mogujie.tt.protobuf.IMBaseDefine.GroupVersionInfo getGroupVersionList(int index) { + return groupVersionList_.get(index); + } + /** + * repeated .IM.BaseDefine.GroupVersionInfo group_version_list = 2; + */ + public com.mogujie.tt.protobuf.IMBaseDefine.GroupVersionInfoOrBuilder getGroupVersionListOrBuilder( + int index) { + return groupVersionList_.get(index); + } + + public static final int ATTACH_DATA_FIELD_NUMBER = 20; + private com.google.protobuf.ByteString attachData_; + /** + * optional bytes attach_data = 20; + */ + public boolean hasAttachData() { + return ((bitField0_ & 0x00000002) == 0x00000002); + } + /** + * optional bytes attach_data = 20; + */ + public com.google.protobuf.ByteString getAttachData() { + return attachData_; + } + + private void initFields() { + userId_ = 0; + groupVersionList_ = java.util.Collections.emptyList(); + attachData_ = com.google.protobuf.ByteString.EMPTY; + } + private byte memoizedIsInitialized = -1; + public final boolean isInitialized() { + byte isInitialized = memoizedIsInitialized; + if (isInitialized == 1) return true; + if (isInitialized == 0) return false; + + if (!hasUserId()) { + memoizedIsInitialized = 0; + return false; + } + for (int i = 0; i < getGroupVersionListCount(); i++) { + if (!getGroupVersionList(i).isInitialized()) { + memoizedIsInitialized = 0; + return false; + } + } + memoizedIsInitialized = 1; + return true; + } + + public void writeTo(com.google.protobuf.CodedOutputStream output) + throws java.io.IOException { + getSerializedSize(); + if (((bitField0_ & 0x00000001) == 0x00000001)) { + output.writeUInt32(1, userId_); + } + for (int i = 0; i < groupVersionList_.size(); i++) { + output.writeMessage(2, groupVersionList_.get(i)); + } + if (((bitField0_ & 0x00000002) == 0x00000002)) { + output.writeBytes(20, attachData_); + } + output.writeRawBytes(unknownFields); + } + + private int memoizedSerializedSize = -1; + public int getSerializedSize() { + int size = memoizedSerializedSize; + if (size != -1) return size; + + size = 0; + if (((bitField0_ & 0x00000001) == 0x00000001)) { + size += com.google.protobuf.CodedOutputStream + .computeUInt32Size(1, userId_); + } + for (int i = 0; i < groupVersionList_.size(); i++) { + size += com.google.protobuf.CodedOutputStream + .computeMessageSize(2, groupVersionList_.get(i)); + } + if (((bitField0_ & 0x00000002) == 0x00000002)) { + size += com.google.protobuf.CodedOutputStream + .computeBytesSize(20, attachData_); + } + size += unknownFields.size(); + memoizedSerializedSize = size; + return size; + } + + private static final long serialVersionUID = 0L; + @java.lang.Override + protected java.lang.Object writeReplace() + throws java.io.ObjectStreamException { + return super.writeReplace(); + } + + public static com.mogujie.tt.protobuf.IMGroup.IMGroupInfoListReq parseFrom( + com.google.protobuf.ByteString data) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data); + } + public static com.mogujie.tt.protobuf.IMGroup.IMGroupInfoListReq parseFrom( + com.google.protobuf.ByteString data, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data, extensionRegistry); + } + public static com.mogujie.tt.protobuf.IMGroup.IMGroupInfoListReq parseFrom(byte[] data) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data); + } + public static com.mogujie.tt.protobuf.IMGroup.IMGroupInfoListReq parseFrom( + byte[] data, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data, extensionRegistry); + } + public static com.mogujie.tt.protobuf.IMGroup.IMGroupInfoListReq parseFrom(java.io.InputStream input) + throws java.io.IOException { + return PARSER.parseFrom(input); + } + public static com.mogujie.tt.protobuf.IMGroup.IMGroupInfoListReq parseFrom( + java.io.InputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return PARSER.parseFrom(input, extensionRegistry); + } + public static com.mogujie.tt.protobuf.IMGroup.IMGroupInfoListReq parseDelimitedFrom(java.io.InputStream input) + throws java.io.IOException { + return PARSER.parseDelimitedFrom(input); + } + public static com.mogujie.tt.protobuf.IMGroup.IMGroupInfoListReq parseDelimitedFrom( + java.io.InputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return PARSER.parseDelimitedFrom(input, extensionRegistry); + } + public static com.mogujie.tt.protobuf.IMGroup.IMGroupInfoListReq parseFrom( + com.google.protobuf.CodedInputStream input) + throws java.io.IOException { + return PARSER.parseFrom(input); + } + public static com.mogujie.tt.protobuf.IMGroup.IMGroupInfoListReq parseFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return PARSER.parseFrom(input, extensionRegistry); + } + + public static Builder newBuilder() { return Builder.create(); } + public Builder newBuilderForType() { return newBuilder(); } + public static Builder newBuilder(com.mogujie.tt.protobuf.IMGroup.IMGroupInfoListReq prototype) { + return newBuilder().mergeFrom(prototype); + } + public Builder toBuilder() { return newBuilder(this); } + + /** + * Protobuf type {@code IM.Group.IMGroupInfoListReq} + */ + public static final class Builder extends + com.google.protobuf.GeneratedMessageLite.Builder< + com.mogujie.tt.protobuf.IMGroup.IMGroupInfoListReq, Builder> + implements + // @@protoc_insertion_point(builder_implements:IM.Group.IMGroupInfoListReq) + com.mogujie.tt.protobuf.IMGroup.IMGroupInfoListReqOrBuilder { + // Construct using com.mogujie.tt.protobuf.IMGroup.IMGroupInfoListReq.newBuilder() + private Builder() { + maybeForceBuilderInitialization(); + } + + private void maybeForceBuilderInitialization() { + } + private static Builder create() { + return new Builder(); + } + + public Builder clear() { + super.clear(); + userId_ = 0; + bitField0_ = (bitField0_ & ~0x00000001); + groupVersionList_ = java.util.Collections.emptyList(); + bitField0_ = (bitField0_ & ~0x00000002); + attachData_ = com.google.protobuf.ByteString.EMPTY; + bitField0_ = (bitField0_ & ~0x00000004); + return this; + } + + public Builder clone() { + return create().mergeFrom(buildPartial()); + } + + public com.mogujie.tt.protobuf.IMGroup.IMGroupInfoListReq getDefaultInstanceForType() { + return com.mogujie.tt.protobuf.IMGroup.IMGroupInfoListReq.getDefaultInstance(); + } + + public com.mogujie.tt.protobuf.IMGroup.IMGroupInfoListReq build() { + com.mogujie.tt.protobuf.IMGroup.IMGroupInfoListReq result = buildPartial(); + if (!result.isInitialized()) { + throw newUninitializedMessageException(result); + } + return result; + } + + public com.mogujie.tt.protobuf.IMGroup.IMGroupInfoListReq buildPartial() { + com.mogujie.tt.protobuf.IMGroup.IMGroupInfoListReq result = new com.mogujie.tt.protobuf.IMGroup.IMGroupInfoListReq(this); + int from_bitField0_ = bitField0_; + int to_bitField0_ = 0; + if (((from_bitField0_ & 0x00000001) == 0x00000001)) { + to_bitField0_ |= 0x00000001; + } + result.userId_ = userId_; + if (((bitField0_ & 0x00000002) == 0x00000002)) { + groupVersionList_ = java.util.Collections.unmodifiableList(groupVersionList_); + bitField0_ = (bitField0_ & ~0x00000002); + } + result.groupVersionList_ = groupVersionList_; + if (((from_bitField0_ & 0x00000004) == 0x00000004)) { + to_bitField0_ |= 0x00000002; + } + result.attachData_ = attachData_; + result.bitField0_ = to_bitField0_; + return result; + } + + public Builder mergeFrom(com.mogujie.tt.protobuf.IMGroup.IMGroupInfoListReq other) { + if (other == com.mogujie.tt.protobuf.IMGroup.IMGroupInfoListReq.getDefaultInstance()) return this; + if (other.hasUserId()) { + setUserId(other.getUserId()); + } + if (!other.groupVersionList_.isEmpty()) { + if (groupVersionList_.isEmpty()) { + groupVersionList_ = other.groupVersionList_; + bitField0_ = (bitField0_ & ~0x00000002); + } else { + ensureGroupVersionListIsMutable(); + groupVersionList_.addAll(other.groupVersionList_); + } + + } + if (other.hasAttachData()) { + setAttachData(other.getAttachData()); + } + setUnknownFields( + getUnknownFields().concat(other.unknownFields)); + return this; + } + + public final boolean isInitialized() { + if (!hasUserId()) { + + return false; + } + for (int i = 0; i < getGroupVersionListCount(); i++) { + if (!getGroupVersionList(i).isInitialized()) { + + return false; + } + } + return true; + } + + public Builder mergeFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + com.mogujie.tt.protobuf.IMGroup.IMGroupInfoListReq parsedMessage = null; + try { + parsedMessage = PARSER.parsePartialFrom(input, extensionRegistry); + } catch (com.google.protobuf.InvalidProtocolBufferException e) { + parsedMessage = (com.mogujie.tt.protobuf.IMGroup.IMGroupInfoListReq) e.getUnfinishedMessage(); + throw e; + } finally { + if (parsedMessage != null) { + mergeFrom(parsedMessage); + } + } + return this; + } + private int bitField0_; + + private int userId_ ; + /** + * required uint32 user_id = 1; + * + *
+       *cmd id:			0x0403
+       * 
+ */ + public boolean hasUserId() { + return ((bitField0_ & 0x00000001) == 0x00000001); + } + /** + * required uint32 user_id = 1; + * + *
+       *cmd id:			0x0403
+       * 
+ */ + public int getUserId() { + return userId_; + } + /** + * required uint32 user_id = 1; + * + *
+       *cmd id:			0x0403
+       * 
+ */ + public Builder setUserId(int value) { + bitField0_ |= 0x00000001; + userId_ = value; + + return this; + } + /** + * required uint32 user_id = 1; + * + *
+       *cmd id:			0x0403
+       * 
+ */ + public Builder clearUserId() { + bitField0_ = (bitField0_ & ~0x00000001); + userId_ = 0; + + return this; + } + + private java.util.List groupVersionList_ = + java.util.Collections.emptyList(); + private void ensureGroupVersionListIsMutable() { + if (!((bitField0_ & 0x00000002) == 0x00000002)) { + groupVersionList_ = new java.util.ArrayList(groupVersionList_); + bitField0_ |= 0x00000002; + } + } + + /** + * repeated .IM.BaseDefine.GroupVersionInfo group_version_list = 2; + */ + public java.util.List getGroupVersionListList() { + return java.util.Collections.unmodifiableList(groupVersionList_); + } + /** + * repeated .IM.BaseDefine.GroupVersionInfo group_version_list = 2; + */ + public int getGroupVersionListCount() { + return groupVersionList_.size(); + } + /** + * repeated .IM.BaseDefine.GroupVersionInfo group_version_list = 2; + */ + public com.mogujie.tt.protobuf.IMBaseDefine.GroupVersionInfo getGroupVersionList(int index) { + return groupVersionList_.get(index); + } + /** + * repeated .IM.BaseDefine.GroupVersionInfo group_version_list = 2; + */ + public Builder setGroupVersionList( + int index, com.mogujie.tt.protobuf.IMBaseDefine.GroupVersionInfo value) { + if (value == null) { + throw new NullPointerException(); + } + ensureGroupVersionListIsMutable(); + groupVersionList_.set(index, value); + + return this; + } + /** + * repeated .IM.BaseDefine.GroupVersionInfo group_version_list = 2; + */ + public Builder setGroupVersionList( + int index, com.mogujie.tt.protobuf.IMBaseDefine.GroupVersionInfo.Builder builderForValue) { + ensureGroupVersionListIsMutable(); + groupVersionList_.set(index, builderForValue.build()); + + return this; + } + /** + * repeated .IM.BaseDefine.GroupVersionInfo group_version_list = 2; + */ + public Builder addGroupVersionList(com.mogujie.tt.protobuf.IMBaseDefine.GroupVersionInfo value) { + if (value == null) { + throw new NullPointerException(); + } + ensureGroupVersionListIsMutable(); + groupVersionList_.add(value); + + return this; + } + /** + * repeated .IM.BaseDefine.GroupVersionInfo group_version_list = 2; + */ + public Builder addGroupVersionList( + int index, com.mogujie.tt.protobuf.IMBaseDefine.GroupVersionInfo value) { + if (value == null) { + throw new NullPointerException(); + } + ensureGroupVersionListIsMutable(); + groupVersionList_.add(index, value); + + return this; + } + /** + * repeated .IM.BaseDefine.GroupVersionInfo group_version_list = 2; + */ + public Builder addGroupVersionList( + com.mogujie.tt.protobuf.IMBaseDefine.GroupVersionInfo.Builder builderForValue) { + ensureGroupVersionListIsMutable(); + groupVersionList_.add(builderForValue.build()); + + return this; + } + /** + * repeated .IM.BaseDefine.GroupVersionInfo group_version_list = 2; + */ + public Builder addGroupVersionList( + int index, com.mogujie.tt.protobuf.IMBaseDefine.GroupVersionInfo.Builder builderForValue) { + ensureGroupVersionListIsMutable(); + groupVersionList_.add(index, builderForValue.build()); + + return this; + } + /** + * repeated .IM.BaseDefine.GroupVersionInfo group_version_list = 2; + */ + public Builder addAllGroupVersionList( + java.lang.Iterable values) { + ensureGroupVersionListIsMutable(); + com.google.protobuf.AbstractMessageLite.Builder.addAll( + values, groupVersionList_); + + return this; + } + /** + * repeated .IM.BaseDefine.GroupVersionInfo group_version_list = 2; + */ + public Builder clearGroupVersionList() { + groupVersionList_ = java.util.Collections.emptyList(); + bitField0_ = (bitField0_ & ~0x00000002); + + return this; + } + /** + * repeated .IM.BaseDefine.GroupVersionInfo group_version_list = 2; + */ + public Builder removeGroupVersionList(int index) { + ensureGroupVersionListIsMutable(); + groupVersionList_.remove(index); + + return this; + } + + private com.google.protobuf.ByteString attachData_ = com.google.protobuf.ByteString.EMPTY; + /** + * optional bytes attach_data = 20; + */ + public boolean hasAttachData() { + return ((bitField0_ & 0x00000004) == 0x00000004); + } + /** + * optional bytes attach_data = 20; + */ + public com.google.protobuf.ByteString getAttachData() { + return attachData_; + } + /** + * optional bytes attach_data = 20; + */ + public Builder setAttachData(com.google.protobuf.ByteString value) { + if (value == null) { + throw new NullPointerException(); + } + bitField0_ |= 0x00000004; + attachData_ = value; + + return this; + } + /** + * optional bytes attach_data = 20; + */ + public Builder clearAttachData() { + bitField0_ = (bitField0_ & ~0x00000004); + attachData_ = getDefaultInstance().getAttachData(); + + return this; + } + + // @@protoc_insertion_point(builder_scope:IM.Group.IMGroupInfoListReq) + } + + static { + defaultInstance = new IMGroupInfoListReq(true); + defaultInstance.initFields(); + } + + // @@protoc_insertion_point(class_scope:IM.Group.IMGroupInfoListReq) + } + + public interface IMGroupInfoListRspOrBuilder extends + // @@protoc_insertion_point(interface_extends:IM.Group.IMGroupInfoListRsp) + com.google.protobuf.MessageLiteOrBuilder { + + /** + * required uint32 user_id = 1; + * + *
+     *cmd id:			0x0404
+     * 
+ */ + boolean hasUserId(); + /** + * required uint32 user_id = 1; + * + *
+     *cmd id:			0x0404
+     * 
+ */ + int getUserId(); + + /** + * repeated .IM.BaseDefine.GroupInfo group_info_list = 2; + */ + java.util.List + getGroupInfoListList(); + /** + * repeated .IM.BaseDefine.GroupInfo group_info_list = 2; + */ + com.mogujie.tt.protobuf.IMBaseDefine.GroupInfo getGroupInfoList(int index); + /** + * repeated .IM.BaseDefine.GroupInfo group_info_list = 2; + */ + int getGroupInfoListCount(); + + /** + * optional bytes attach_data = 20; + */ + boolean hasAttachData(); + /** + * optional bytes attach_data = 20; + */ + com.google.protobuf.ByteString getAttachData(); + } + /** + * Protobuf type {@code IM.Group.IMGroupInfoListRsp} + */ + public static final class IMGroupInfoListRsp extends + com.google.protobuf.GeneratedMessageLite implements + // @@protoc_insertion_point(message_implements:IM.Group.IMGroupInfoListRsp) + IMGroupInfoListRspOrBuilder { + // Use IMGroupInfoListRsp.newBuilder() to construct. + private IMGroupInfoListRsp(com.google.protobuf.GeneratedMessageLite.Builder builder) { + super(builder); + this.unknownFields = builder.getUnknownFields(); + } + private IMGroupInfoListRsp(boolean noInit) { this.unknownFields = com.google.protobuf.ByteString.EMPTY;} + + private static final IMGroupInfoListRsp defaultInstance; + public static IMGroupInfoListRsp getDefaultInstance() { + return defaultInstance; + } + + public IMGroupInfoListRsp getDefaultInstanceForType() { + return defaultInstance; + } + + private final com.google.protobuf.ByteString unknownFields; + private IMGroupInfoListRsp( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + initFields(); + int mutable_bitField0_ = 0; + com.google.protobuf.ByteString.Output unknownFieldsOutput = + com.google.protobuf.ByteString.newOutput(); + com.google.protobuf.CodedOutputStream unknownFieldsCodedOutput = + com.google.protobuf.CodedOutputStream.newInstance( + unknownFieldsOutput); + try { + boolean done = false; + while (!done) { + int tag = input.readTag(); + switch (tag) { + case 0: + done = true; + break; + default: { + if (!parseUnknownField(input, unknownFieldsCodedOutput, + extensionRegistry, tag)) { + done = true; + } + break; + } + case 8: { + bitField0_ |= 0x00000001; + userId_ = input.readUInt32(); + break; + } + case 18: { + if (!((mutable_bitField0_ & 0x00000002) == 0x00000002)) { + groupInfoList_ = new java.util.ArrayList(); + mutable_bitField0_ |= 0x00000002; + } + groupInfoList_.add(input.readMessage(com.mogujie.tt.protobuf.IMBaseDefine.GroupInfo.PARSER, extensionRegistry)); + break; + } + case 162: { + bitField0_ |= 0x00000002; + attachData_ = input.readBytes(); + break; + } + } + } + } catch (com.google.protobuf.InvalidProtocolBufferException e) { + throw e.setUnfinishedMessage(this); + } catch (java.io.IOException e) { + throw new com.google.protobuf.InvalidProtocolBufferException( + e.getMessage()).setUnfinishedMessage(this); + } finally { + if (((mutable_bitField0_ & 0x00000002) == 0x00000002)) { + groupInfoList_ = java.util.Collections.unmodifiableList(groupInfoList_); + } + try { + unknownFieldsCodedOutput.flush(); + } catch (java.io.IOException e) { + // Should not happen + } finally { + unknownFields = unknownFieldsOutput.toByteString(); + } + makeExtensionsImmutable(); + } + } + public static com.google.protobuf.Parser PARSER = + new com.google.protobuf.AbstractParser() { + public IMGroupInfoListRsp parsePartialFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return new IMGroupInfoListRsp(input, extensionRegistry); + } + }; + + @java.lang.Override + public com.google.protobuf.Parser getParserForType() { + return PARSER; + } + + private int bitField0_; + public static final int USER_ID_FIELD_NUMBER = 1; + private int userId_; + /** + * required uint32 user_id = 1; + * + *
+     *cmd id:			0x0404
+     * 
+ */ + public boolean hasUserId() { + return ((bitField0_ & 0x00000001) == 0x00000001); + } + /** + * required uint32 user_id = 1; + * + *
+     *cmd id:			0x0404
+     * 
+ */ + public int getUserId() { + return userId_; + } + + public static final int GROUP_INFO_LIST_FIELD_NUMBER = 2; + private java.util.List groupInfoList_; + /** + * repeated .IM.BaseDefine.GroupInfo group_info_list = 2; + */ + public java.util.List getGroupInfoListList() { + return groupInfoList_; + } + /** + * repeated .IM.BaseDefine.GroupInfo group_info_list = 2; + */ + public java.util.List + getGroupInfoListOrBuilderList() { + return groupInfoList_; + } + /** + * repeated .IM.BaseDefine.GroupInfo group_info_list = 2; + */ + public int getGroupInfoListCount() { + return groupInfoList_.size(); + } + /** + * repeated .IM.BaseDefine.GroupInfo group_info_list = 2; + */ + public com.mogujie.tt.protobuf.IMBaseDefine.GroupInfo getGroupInfoList(int index) { + return groupInfoList_.get(index); + } + /** + * repeated .IM.BaseDefine.GroupInfo group_info_list = 2; + */ + public com.mogujie.tt.protobuf.IMBaseDefine.GroupInfoOrBuilder getGroupInfoListOrBuilder( + int index) { + return groupInfoList_.get(index); + } + + public static final int ATTACH_DATA_FIELD_NUMBER = 20; + private com.google.protobuf.ByteString attachData_; + /** + * optional bytes attach_data = 20; + */ + public boolean hasAttachData() { + return ((bitField0_ & 0x00000002) == 0x00000002); + } + /** + * optional bytes attach_data = 20; + */ + public com.google.protobuf.ByteString getAttachData() { + return attachData_; + } + + private void initFields() { + userId_ = 0; + groupInfoList_ = java.util.Collections.emptyList(); + attachData_ = com.google.protobuf.ByteString.EMPTY; + } + private byte memoizedIsInitialized = -1; + public final boolean isInitialized() { + byte isInitialized = memoizedIsInitialized; + if (isInitialized == 1) return true; + if (isInitialized == 0) return false; + + if (!hasUserId()) { + memoizedIsInitialized = 0; + return false; + } + for (int i = 0; i < getGroupInfoListCount(); i++) { + if (!getGroupInfoList(i).isInitialized()) { + memoizedIsInitialized = 0; + return false; + } + } + memoizedIsInitialized = 1; + return true; + } + + public void writeTo(com.google.protobuf.CodedOutputStream output) + throws java.io.IOException { + getSerializedSize(); + if (((bitField0_ & 0x00000001) == 0x00000001)) { + output.writeUInt32(1, userId_); + } + for (int i = 0; i < groupInfoList_.size(); i++) { + output.writeMessage(2, groupInfoList_.get(i)); + } + if (((bitField0_ & 0x00000002) == 0x00000002)) { + output.writeBytes(20, attachData_); + } + output.writeRawBytes(unknownFields); + } + + private int memoizedSerializedSize = -1; + public int getSerializedSize() { + int size = memoizedSerializedSize; + if (size != -1) return size; + + size = 0; + if (((bitField0_ & 0x00000001) == 0x00000001)) { + size += com.google.protobuf.CodedOutputStream + .computeUInt32Size(1, userId_); + } + for (int i = 0; i < groupInfoList_.size(); i++) { + size += com.google.protobuf.CodedOutputStream + .computeMessageSize(2, groupInfoList_.get(i)); + } + if (((bitField0_ & 0x00000002) == 0x00000002)) { + size += com.google.protobuf.CodedOutputStream + .computeBytesSize(20, attachData_); + } + size += unknownFields.size(); + memoizedSerializedSize = size; + return size; + } + + private static final long serialVersionUID = 0L; + @java.lang.Override + protected java.lang.Object writeReplace() + throws java.io.ObjectStreamException { + return super.writeReplace(); + } + + public static com.mogujie.tt.protobuf.IMGroup.IMGroupInfoListRsp parseFrom( + com.google.protobuf.ByteString data) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data); + } + public static com.mogujie.tt.protobuf.IMGroup.IMGroupInfoListRsp parseFrom( + com.google.protobuf.ByteString data, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data, extensionRegistry); + } + public static com.mogujie.tt.protobuf.IMGroup.IMGroupInfoListRsp parseFrom(byte[] data) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data); + } + public static com.mogujie.tt.protobuf.IMGroup.IMGroupInfoListRsp parseFrom( + byte[] data, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data, extensionRegistry); + } + public static com.mogujie.tt.protobuf.IMGroup.IMGroupInfoListRsp parseFrom(java.io.InputStream input) + throws java.io.IOException { + return PARSER.parseFrom(input); + } + public static com.mogujie.tt.protobuf.IMGroup.IMGroupInfoListRsp parseFrom( + java.io.InputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return PARSER.parseFrom(input, extensionRegistry); + } + public static com.mogujie.tt.protobuf.IMGroup.IMGroupInfoListRsp parseDelimitedFrom(java.io.InputStream input) + throws java.io.IOException { + return PARSER.parseDelimitedFrom(input); + } + public static com.mogujie.tt.protobuf.IMGroup.IMGroupInfoListRsp parseDelimitedFrom( + java.io.InputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return PARSER.parseDelimitedFrom(input, extensionRegistry); + } + public static com.mogujie.tt.protobuf.IMGroup.IMGroupInfoListRsp parseFrom( + com.google.protobuf.CodedInputStream input) + throws java.io.IOException { + return PARSER.parseFrom(input); + } + public static com.mogujie.tt.protobuf.IMGroup.IMGroupInfoListRsp parseFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return PARSER.parseFrom(input, extensionRegistry); + } + + public static Builder newBuilder() { return Builder.create(); } + public Builder newBuilderForType() { return newBuilder(); } + public static Builder newBuilder(com.mogujie.tt.protobuf.IMGroup.IMGroupInfoListRsp prototype) { + return newBuilder().mergeFrom(prototype); + } + public Builder toBuilder() { return newBuilder(this); } + + /** + * Protobuf type {@code IM.Group.IMGroupInfoListRsp} + */ + public static final class Builder extends + com.google.protobuf.GeneratedMessageLite.Builder< + com.mogujie.tt.protobuf.IMGroup.IMGroupInfoListRsp, Builder> + implements + // @@protoc_insertion_point(builder_implements:IM.Group.IMGroupInfoListRsp) + com.mogujie.tt.protobuf.IMGroup.IMGroupInfoListRspOrBuilder { + // Construct using com.mogujie.tt.protobuf.IMGroup.IMGroupInfoListRsp.newBuilder() + private Builder() { + maybeForceBuilderInitialization(); + } + + private void maybeForceBuilderInitialization() { + } + private static Builder create() { + return new Builder(); + } + + public Builder clear() { + super.clear(); + userId_ = 0; + bitField0_ = (bitField0_ & ~0x00000001); + groupInfoList_ = java.util.Collections.emptyList(); + bitField0_ = (bitField0_ & ~0x00000002); + attachData_ = com.google.protobuf.ByteString.EMPTY; + bitField0_ = (bitField0_ & ~0x00000004); + return this; + } + + public Builder clone() { + return create().mergeFrom(buildPartial()); + } + + public com.mogujie.tt.protobuf.IMGroup.IMGroupInfoListRsp getDefaultInstanceForType() { + return com.mogujie.tt.protobuf.IMGroup.IMGroupInfoListRsp.getDefaultInstance(); + } + + public com.mogujie.tt.protobuf.IMGroup.IMGroupInfoListRsp build() { + com.mogujie.tt.protobuf.IMGroup.IMGroupInfoListRsp result = buildPartial(); + if (!result.isInitialized()) { + throw newUninitializedMessageException(result); + } + return result; + } + + public com.mogujie.tt.protobuf.IMGroup.IMGroupInfoListRsp buildPartial() { + com.mogujie.tt.protobuf.IMGroup.IMGroupInfoListRsp result = new com.mogujie.tt.protobuf.IMGroup.IMGroupInfoListRsp(this); + int from_bitField0_ = bitField0_; + int to_bitField0_ = 0; + if (((from_bitField0_ & 0x00000001) == 0x00000001)) { + to_bitField0_ |= 0x00000001; + } + result.userId_ = userId_; + if (((bitField0_ & 0x00000002) == 0x00000002)) { + groupInfoList_ = java.util.Collections.unmodifiableList(groupInfoList_); + bitField0_ = (bitField0_ & ~0x00000002); + } + result.groupInfoList_ = groupInfoList_; + if (((from_bitField0_ & 0x00000004) == 0x00000004)) { + to_bitField0_ |= 0x00000002; + } + result.attachData_ = attachData_; + result.bitField0_ = to_bitField0_; + return result; + } + + public Builder mergeFrom(com.mogujie.tt.protobuf.IMGroup.IMGroupInfoListRsp other) { + if (other == com.mogujie.tt.protobuf.IMGroup.IMGroupInfoListRsp.getDefaultInstance()) return this; + if (other.hasUserId()) { + setUserId(other.getUserId()); + } + if (!other.groupInfoList_.isEmpty()) { + if (groupInfoList_.isEmpty()) { + groupInfoList_ = other.groupInfoList_; + bitField0_ = (bitField0_ & ~0x00000002); + } else { + ensureGroupInfoListIsMutable(); + groupInfoList_.addAll(other.groupInfoList_); + } + + } + if (other.hasAttachData()) { + setAttachData(other.getAttachData()); + } + setUnknownFields( + getUnknownFields().concat(other.unknownFields)); + return this; + } + + public final boolean isInitialized() { + if (!hasUserId()) { + + return false; + } + for (int i = 0; i < getGroupInfoListCount(); i++) { + if (!getGroupInfoList(i).isInitialized()) { + + return false; + } + } + return true; + } + + public Builder mergeFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + com.mogujie.tt.protobuf.IMGroup.IMGroupInfoListRsp parsedMessage = null; + try { + parsedMessage = PARSER.parsePartialFrom(input, extensionRegistry); + } catch (com.google.protobuf.InvalidProtocolBufferException e) { + parsedMessage = (com.mogujie.tt.protobuf.IMGroup.IMGroupInfoListRsp) e.getUnfinishedMessage(); + throw e; + } finally { + if (parsedMessage != null) { + mergeFrom(parsedMessage); + } + } + return this; + } + private int bitField0_; + + private int userId_ ; + /** + * required uint32 user_id = 1; + * + *
+       *cmd id:			0x0404
+       * 
+ */ + public boolean hasUserId() { + return ((bitField0_ & 0x00000001) == 0x00000001); + } + /** + * required uint32 user_id = 1; + * + *
+       *cmd id:			0x0404
+       * 
+ */ + public int getUserId() { + return userId_; + } + /** + * required uint32 user_id = 1; + * + *
+       *cmd id:			0x0404
+       * 
+ */ + public Builder setUserId(int value) { + bitField0_ |= 0x00000001; + userId_ = value; + + return this; + } + /** + * required uint32 user_id = 1; + * + *
+       *cmd id:			0x0404
+       * 
+ */ + public Builder clearUserId() { + bitField0_ = (bitField0_ & ~0x00000001); + userId_ = 0; + + return this; + } + + private java.util.List groupInfoList_ = + java.util.Collections.emptyList(); + private void ensureGroupInfoListIsMutable() { + if (!((bitField0_ & 0x00000002) == 0x00000002)) { + groupInfoList_ = new java.util.ArrayList(groupInfoList_); + bitField0_ |= 0x00000002; + } + } + + /** + * repeated .IM.BaseDefine.GroupInfo group_info_list = 2; + */ + public java.util.List getGroupInfoListList() { + return java.util.Collections.unmodifiableList(groupInfoList_); + } + /** + * repeated .IM.BaseDefine.GroupInfo group_info_list = 2; + */ + public int getGroupInfoListCount() { + return groupInfoList_.size(); + } + /** + * repeated .IM.BaseDefine.GroupInfo group_info_list = 2; + */ + public com.mogujie.tt.protobuf.IMBaseDefine.GroupInfo getGroupInfoList(int index) { + return groupInfoList_.get(index); + } + /** + * repeated .IM.BaseDefine.GroupInfo group_info_list = 2; + */ + public Builder setGroupInfoList( + int index, com.mogujie.tt.protobuf.IMBaseDefine.GroupInfo value) { + if (value == null) { + throw new NullPointerException(); + } + ensureGroupInfoListIsMutable(); + groupInfoList_.set(index, value); + + return this; + } + /** + * repeated .IM.BaseDefine.GroupInfo group_info_list = 2; + */ + public Builder setGroupInfoList( + int index, com.mogujie.tt.protobuf.IMBaseDefine.GroupInfo.Builder builderForValue) { + ensureGroupInfoListIsMutable(); + groupInfoList_.set(index, builderForValue.build()); + + return this; + } + /** + * repeated .IM.BaseDefine.GroupInfo group_info_list = 2; + */ + public Builder addGroupInfoList(com.mogujie.tt.protobuf.IMBaseDefine.GroupInfo value) { + if (value == null) { + throw new NullPointerException(); + } + ensureGroupInfoListIsMutable(); + groupInfoList_.add(value); + + return this; + } + /** + * repeated .IM.BaseDefine.GroupInfo group_info_list = 2; + */ + public Builder addGroupInfoList( + int index, com.mogujie.tt.protobuf.IMBaseDefine.GroupInfo value) { + if (value == null) { + throw new NullPointerException(); + } + ensureGroupInfoListIsMutable(); + groupInfoList_.add(index, value); + + return this; + } + /** + * repeated .IM.BaseDefine.GroupInfo group_info_list = 2; + */ + public Builder addGroupInfoList( + com.mogujie.tt.protobuf.IMBaseDefine.GroupInfo.Builder builderForValue) { + ensureGroupInfoListIsMutable(); + groupInfoList_.add(builderForValue.build()); + + return this; + } + /** + * repeated .IM.BaseDefine.GroupInfo group_info_list = 2; + */ + public Builder addGroupInfoList( + int index, com.mogujie.tt.protobuf.IMBaseDefine.GroupInfo.Builder builderForValue) { + ensureGroupInfoListIsMutable(); + groupInfoList_.add(index, builderForValue.build()); + + return this; + } + /** + * repeated .IM.BaseDefine.GroupInfo group_info_list = 2; + */ + public Builder addAllGroupInfoList( + java.lang.Iterable values) { + ensureGroupInfoListIsMutable(); + com.google.protobuf.AbstractMessageLite.Builder.addAll( + values, groupInfoList_); + + return this; + } + /** + * repeated .IM.BaseDefine.GroupInfo group_info_list = 2; + */ + public Builder clearGroupInfoList() { + groupInfoList_ = java.util.Collections.emptyList(); + bitField0_ = (bitField0_ & ~0x00000002); + + return this; + } + /** + * repeated .IM.BaseDefine.GroupInfo group_info_list = 2; + */ + public Builder removeGroupInfoList(int index) { + ensureGroupInfoListIsMutable(); + groupInfoList_.remove(index); + + return this; + } + + private com.google.protobuf.ByteString attachData_ = com.google.protobuf.ByteString.EMPTY; + /** + * optional bytes attach_data = 20; + */ + public boolean hasAttachData() { + return ((bitField0_ & 0x00000004) == 0x00000004); + } + /** + * optional bytes attach_data = 20; + */ + public com.google.protobuf.ByteString getAttachData() { + return attachData_; + } + /** + * optional bytes attach_data = 20; + */ + public Builder setAttachData(com.google.protobuf.ByteString value) { + if (value == null) { + throw new NullPointerException(); + } + bitField0_ |= 0x00000004; + attachData_ = value; + + return this; + } + /** + * optional bytes attach_data = 20; + */ + public Builder clearAttachData() { + bitField0_ = (bitField0_ & ~0x00000004); + attachData_ = getDefaultInstance().getAttachData(); + + return this; + } + + // @@protoc_insertion_point(builder_scope:IM.Group.IMGroupInfoListRsp) + } + + static { + defaultInstance = new IMGroupInfoListRsp(true); + defaultInstance.initFields(); + } + + // @@protoc_insertion_point(class_scope:IM.Group.IMGroupInfoListRsp) + } + + public interface IMGroupCreateReqOrBuilder extends + // @@protoc_insertion_point(interface_extends:IM.Group.IMGroupCreateReq) + com.google.protobuf.MessageLiteOrBuilder { + + /** + * required uint32 user_id = 1; + * + *
+     *cmd id:			0x0405
+     * 
+ */ + boolean hasUserId(); + /** + * required uint32 user_id = 1; + * + *
+     *cmd id:			0x0405
+     * 
+ */ + int getUserId(); + + /** + * required .IM.BaseDefine.GroupType group_type = 2 [default = GROUP_TYPE_TMP]; + * + *
+     *默认是创建临时群,且客户端只能创建临时群
+     * 
+ */ + boolean hasGroupType(); + /** + * required .IM.BaseDefine.GroupType group_type = 2 [default = GROUP_TYPE_TMP]; + * + *
+     *默认是创建临时群,且客户端只能创建临时群
+     * 
+ */ + com.mogujie.tt.protobuf.IMBaseDefine.GroupType getGroupType(); + + /** + * required string group_name = 3; + */ + boolean hasGroupName(); + /** + * required string group_name = 3; + */ + java.lang.String getGroupName(); + /** + * required string group_name = 3; + */ + com.google.protobuf.ByteString + getGroupNameBytes(); + + /** + * required string group_avatar = 4; + */ + boolean hasGroupAvatar(); + /** + * required string group_avatar = 4; + */ + java.lang.String getGroupAvatar(); + /** + * required string group_avatar = 4; + */ + com.google.protobuf.ByteString + getGroupAvatarBytes(); + + /** + * repeated uint32 member_id_list = 5; + */ + java.util.List getMemberIdListList(); + /** + * repeated uint32 member_id_list = 5; + */ + int getMemberIdListCount(); + /** + * repeated uint32 member_id_list = 5; + */ + int getMemberIdList(int index); + + /** + * optional bytes attach_data = 20; + */ + boolean hasAttachData(); + /** + * optional bytes attach_data = 20; + */ + com.google.protobuf.ByteString getAttachData(); + } + /** + * Protobuf type {@code IM.Group.IMGroupCreateReq} + */ + public static final class IMGroupCreateReq extends + com.google.protobuf.GeneratedMessageLite implements + // @@protoc_insertion_point(message_implements:IM.Group.IMGroupCreateReq) + IMGroupCreateReqOrBuilder { + // Use IMGroupCreateReq.newBuilder() to construct. + private IMGroupCreateReq(com.google.protobuf.GeneratedMessageLite.Builder builder) { + super(builder); + this.unknownFields = builder.getUnknownFields(); + } + private IMGroupCreateReq(boolean noInit) { this.unknownFields = com.google.protobuf.ByteString.EMPTY;} + + private static final IMGroupCreateReq defaultInstance; + public static IMGroupCreateReq getDefaultInstance() { + return defaultInstance; + } + + public IMGroupCreateReq getDefaultInstanceForType() { + return defaultInstance; + } + + private final com.google.protobuf.ByteString unknownFields; + private IMGroupCreateReq( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + initFields(); + int mutable_bitField0_ = 0; + com.google.protobuf.ByteString.Output unknownFieldsOutput = + com.google.protobuf.ByteString.newOutput(); + com.google.protobuf.CodedOutputStream unknownFieldsCodedOutput = + com.google.protobuf.CodedOutputStream.newInstance( + unknownFieldsOutput); + try { + boolean done = false; + while (!done) { + int tag = input.readTag(); + switch (tag) { + case 0: + done = true; + break; + default: { + if (!parseUnknownField(input, unknownFieldsCodedOutput, + extensionRegistry, tag)) { + done = true; + } + break; + } + case 8: { + bitField0_ |= 0x00000001; + userId_ = input.readUInt32(); + break; + } + case 16: { + int rawValue = input.readEnum(); + com.mogujie.tt.protobuf.IMBaseDefine.GroupType value = com.mogujie.tt.protobuf.IMBaseDefine.GroupType.valueOf(rawValue); + if (value == null) { + unknownFieldsCodedOutput.writeRawVarint32(tag); + unknownFieldsCodedOutput.writeRawVarint32(rawValue); + } else { + bitField0_ |= 0x00000002; + groupType_ = value; + } + break; + } + case 26: { + com.google.protobuf.ByteString bs = input.readBytes(); + bitField0_ |= 0x00000004; + groupName_ = bs; + break; + } + case 34: { + com.google.protobuf.ByteString bs = input.readBytes(); + bitField0_ |= 0x00000008; + groupAvatar_ = bs; + break; + } + case 40: { + if (!((mutable_bitField0_ & 0x00000010) == 0x00000010)) { + memberIdList_ = new java.util.ArrayList(); + mutable_bitField0_ |= 0x00000010; + } + memberIdList_.add(input.readUInt32()); + break; + } + case 42: { + int length = input.readRawVarint32(); + int limit = input.pushLimit(length); + if (!((mutable_bitField0_ & 0x00000010) == 0x00000010) && input.getBytesUntilLimit() > 0) { + memberIdList_ = new java.util.ArrayList(); + mutable_bitField0_ |= 0x00000010; + } + while (input.getBytesUntilLimit() > 0) { + memberIdList_.add(input.readUInt32()); + } + input.popLimit(limit); + break; + } + case 162: { + bitField0_ |= 0x00000010; + attachData_ = input.readBytes(); + break; + } + } + } + } catch (com.google.protobuf.InvalidProtocolBufferException e) { + throw e.setUnfinishedMessage(this); + } catch (java.io.IOException e) { + throw new com.google.protobuf.InvalidProtocolBufferException( + e.getMessage()).setUnfinishedMessage(this); + } finally { + if (((mutable_bitField0_ & 0x00000010) == 0x00000010)) { + memberIdList_ = java.util.Collections.unmodifiableList(memberIdList_); + } + try { + unknownFieldsCodedOutput.flush(); + } catch (java.io.IOException e) { + // Should not happen + } finally { + unknownFields = unknownFieldsOutput.toByteString(); + } + makeExtensionsImmutable(); + } + } + public static com.google.protobuf.Parser PARSER = + new com.google.protobuf.AbstractParser() { + public IMGroupCreateReq parsePartialFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return new IMGroupCreateReq(input, extensionRegistry); + } + }; + + @java.lang.Override + public com.google.protobuf.Parser getParserForType() { + return PARSER; + } + + private int bitField0_; + public static final int USER_ID_FIELD_NUMBER = 1; + private int userId_; + /** + * required uint32 user_id = 1; + * + *
+     *cmd id:			0x0405
+     * 
+ */ + public boolean hasUserId() { + return ((bitField0_ & 0x00000001) == 0x00000001); + } + /** + * required uint32 user_id = 1; + * + *
+     *cmd id:			0x0405
+     * 
+ */ + public int getUserId() { + return userId_; + } + + public static final int GROUP_TYPE_FIELD_NUMBER = 2; + private com.mogujie.tt.protobuf.IMBaseDefine.GroupType groupType_; + /** + * required .IM.BaseDefine.GroupType group_type = 2 [default = GROUP_TYPE_TMP]; + * + *
+     *默认是创建临时群,且客户端只能创建临时群
+     * 
+ */ + public boolean hasGroupType() { + return ((bitField0_ & 0x00000002) == 0x00000002); + } + /** + * required .IM.BaseDefine.GroupType group_type = 2 [default = GROUP_TYPE_TMP]; + * + *
+     *默认是创建临时群,且客户端只能创建临时群
+     * 
+ */ + public com.mogujie.tt.protobuf.IMBaseDefine.GroupType getGroupType() { + return groupType_; + } + + public static final int GROUP_NAME_FIELD_NUMBER = 3; + private java.lang.Object groupName_; + /** + * required string group_name = 3; + */ + public boolean hasGroupName() { + return ((bitField0_ & 0x00000004) == 0x00000004); + } + /** + * required string group_name = 3; + */ + public java.lang.String getGroupName() { + java.lang.Object ref = groupName_; + if (ref instanceof java.lang.String) { + return (java.lang.String) ref; + } else { + com.google.protobuf.ByteString bs = + (com.google.protobuf.ByteString) ref; + java.lang.String s = bs.toStringUtf8(); + if (bs.isValidUtf8()) { + groupName_ = s; + } + return s; + } + } + /** + * required string group_name = 3; + */ + public com.google.protobuf.ByteString + getGroupNameBytes() { + java.lang.Object ref = groupName_; + if (ref instanceof java.lang.String) { + com.google.protobuf.ByteString b = + com.google.protobuf.ByteString.copyFromUtf8( + (java.lang.String) ref); + groupName_ = b; + return b; + } else { + return (com.google.protobuf.ByteString) ref; + } + } + + public static final int GROUP_AVATAR_FIELD_NUMBER = 4; + private java.lang.Object groupAvatar_; + /** + * required string group_avatar = 4; + */ + public boolean hasGroupAvatar() { + return ((bitField0_ & 0x00000008) == 0x00000008); + } + /** + * required string group_avatar = 4; + */ + public java.lang.String getGroupAvatar() { + java.lang.Object ref = groupAvatar_; + if (ref instanceof java.lang.String) { + return (java.lang.String) ref; + } else { + com.google.protobuf.ByteString bs = + (com.google.protobuf.ByteString) ref; + java.lang.String s = bs.toStringUtf8(); + if (bs.isValidUtf8()) { + groupAvatar_ = s; + } + return s; + } + } + /** + * required string group_avatar = 4; + */ + public com.google.protobuf.ByteString + getGroupAvatarBytes() { + java.lang.Object ref = groupAvatar_; + if (ref instanceof java.lang.String) { + com.google.protobuf.ByteString b = + com.google.protobuf.ByteString.copyFromUtf8( + (java.lang.String) ref); + groupAvatar_ = b; + return b; + } else { + return (com.google.protobuf.ByteString) ref; + } + } + + public static final int MEMBER_ID_LIST_FIELD_NUMBER = 5; + private java.util.List memberIdList_; + /** + * repeated uint32 member_id_list = 5; + */ + public java.util.List + getMemberIdListList() { + return memberIdList_; + } + /** + * repeated uint32 member_id_list = 5; + */ + public int getMemberIdListCount() { + return memberIdList_.size(); + } + /** + * repeated uint32 member_id_list = 5; + */ + public int getMemberIdList(int index) { + return memberIdList_.get(index); + } + + public static final int ATTACH_DATA_FIELD_NUMBER = 20; + private com.google.protobuf.ByteString attachData_; + /** + * optional bytes attach_data = 20; + */ + public boolean hasAttachData() { + return ((bitField0_ & 0x00000010) == 0x00000010); + } + /** + * optional bytes attach_data = 20; + */ + public com.google.protobuf.ByteString getAttachData() { + return attachData_; + } + + private void initFields() { + userId_ = 0; + groupType_ = com.mogujie.tt.protobuf.IMBaseDefine.GroupType.GROUP_TYPE_TMP; + groupName_ = ""; + groupAvatar_ = ""; + memberIdList_ = java.util.Collections.emptyList(); + attachData_ = com.google.protobuf.ByteString.EMPTY; + } + private byte memoizedIsInitialized = -1; + public final boolean isInitialized() { + byte isInitialized = memoizedIsInitialized; + if (isInitialized == 1) return true; + if (isInitialized == 0) return false; + + if (!hasUserId()) { + memoizedIsInitialized = 0; + return false; + } + if (!hasGroupType()) { + memoizedIsInitialized = 0; + return false; + } + if (!hasGroupName()) { + memoizedIsInitialized = 0; + return false; + } + if (!hasGroupAvatar()) { + memoizedIsInitialized = 0; + return false; + } + memoizedIsInitialized = 1; + return true; + } + + public void writeTo(com.google.protobuf.CodedOutputStream output) + throws java.io.IOException { + getSerializedSize(); + if (((bitField0_ & 0x00000001) == 0x00000001)) { + output.writeUInt32(1, userId_); + } + if (((bitField0_ & 0x00000002) == 0x00000002)) { + output.writeEnum(2, groupType_.getNumber()); + } + if (((bitField0_ & 0x00000004) == 0x00000004)) { + output.writeBytes(3, getGroupNameBytes()); + } + if (((bitField0_ & 0x00000008) == 0x00000008)) { + output.writeBytes(4, getGroupAvatarBytes()); + } + for (int i = 0; i < memberIdList_.size(); i++) { + output.writeUInt32(5, memberIdList_.get(i)); + } + if (((bitField0_ & 0x00000010) == 0x00000010)) { + output.writeBytes(20, attachData_); + } + output.writeRawBytes(unknownFields); + } + + private int memoizedSerializedSize = -1; + public int getSerializedSize() { + int size = memoizedSerializedSize; + if (size != -1) return size; + + size = 0; + if (((bitField0_ & 0x00000001) == 0x00000001)) { + size += com.google.protobuf.CodedOutputStream + .computeUInt32Size(1, userId_); + } + if (((bitField0_ & 0x00000002) == 0x00000002)) { + size += com.google.protobuf.CodedOutputStream + .computeEnumSize(2, groupType_.getNumber()); + } + if (((bitField0_ & 0x00000004) == 0x00000004)) { + size += com.google.protobuf.CodedOutputStream + .computeBytesSize(3, getGroupNameBytes()); + } + if (((bitField0_ & 0x00000008) == 0x00000008)) { + size += com.google.protobuf.CodedOutputStream + .computeBytesSize(4, getGroupAvatarBytes()); + } + { + int dataSize = 0; + for (int i = 0; i < memberIdList_.size(); i++) { + dataSize += com.google.protobuf.CodedOutputStream + .computeUInt32SizeNoTag(memberIdList_.get(i)); + } + size += dataSize; + size += 1 * getMemberIdListList().size(); + } + if (((bitField0_ & 0x00000010) == 0x00000010)) { + size += com.google.protobuf.CodedOutputStream + .computeBytesSize(20, attachData_); + } + size += unknownFields.size(); + memoizedSerializedSize = size; + return size; + } + + private static final long serialVersionUID = 0L; + @java.lang.Override + protected java.lang.Object writeReplace() + throws java.io.ObjectStreamException { + return super.writeReplace(); + } + + public static com.mogujie.tt.protobuf.IMGroup.IMGroupCreateReq parseFrom( + com.google.protobuf.ByteString data) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data); + } + public static com.mogujie.tt.protobuf.IMGroup.IMGroupCreateReq parseFrom( + com.google.protobuf.ByteString data, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data, extensionRegistry); + } + public static com.mogujie.tt.protobuf.IMGroup.IMGroupCreateReq parseFrom(byte[] data) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data); + } + public static com.mogujie.tt.protobuf.IMGroup.IMGroupCreateReq parseFrom( + byte[] data, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data, extensionRegistry); + } + public static com.mogujie.tt.protobuf.IMGroup.IMGroupCreateReq parseFrom(java.io.InputStream input) + throws java.io.IOException { + return PARSER.parseFrom(input); + } + public static com.mogujie.tt.protobuf.IMGroup.IMGroupCreateReq parseFrom( + java.io.InputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return PARSER.parseFrom(input, extensionRegistry); + } + public static com.mogujie.tt.protobuf.IMGroup.IMGroupCreateReq parseDelimitedFrom(java.io.InputStream input) + throws java.io.IOException { + return PARSER.parseDelimitedFrom(input); + } + public static com.mogujie.tt.protobuf.IMGroup.IMGroupCreateReq parseDelimitedFrom( + java.io.InputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return PARSER.parseDelimitedFrom(input, extensionRegistry); + } + public static com.mogujie.tt.protobuf.IMGroup.IMGroupCreateReq parseFrom( + com.google.protobuf.CodedInputStream input) + throws java.io.IOException { + return PARSER.parseFrom(input); + } + public static com.mogujie.tt.protobuf.IMGroup.IMGroupCreateReq parseFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return PARSER.parseFrom(input, extensionRegistry); + } + + public static Builder newBuilder() { return Builder.create(); } + public Builder newBuilderForType() { return newBuilder(); } + public static Builder newBuilder(com.mogujie.tt.protobuf.IMGroup.IMGroupCreateReq prototype) { + return newBuilder().mergeFrom(prototype); + } + public Builder toBuilder() { return newBuilder(this); } + + /** + * Protobuf type {@code IM.Group.IMGroupCreateReq} + */ + public static final class Builder extends + com.google.protobuf.GeneratedMessageLite.Builder< + com.mogujie.tt.protobuf.IMGroup.IMGroupCreateReq, Builder> + implements + // @@protoc_insertion_point(builder_implements:IM.Group.IMGroupCreateReq) + com.mogujie.tt.protobuf.IMGroup.IMGroupCreateReqOrBuilder { + // Construct using com.mogujie.tt.protobuf.IMGroup.IMGroupCreateReq.newBuilder() + private Builder() { + maybeForceBuilderInitialization(); + } + + private void maybeForceBuilderInitialization() { + } + private static Builder create() { + return new Builder(); + } + + public Builder clear() { + super.clear(); + userId_ = 0; + bitField0_ = (bitField0_ & ~0x00000001); + groupType_ = com.mogujie.tt.protobuf.IMBaseDefine.GroupType.GROUP_TYPE_TMP; + bitField0_ = (bitField0_ & ~0x00000002); + groupName_ = ""; + bitField0_ = (bitField0_ & ~0x00000004); + groupAvatar_ = ""; + bitField0_ = (bitField0_ & ~0x00000008); + memberIdList_ = java.util.Collections.emptyList(); + bitField0_ = (bitField0_ & ~0x00000010); + attachData_ = com.google.protobuf.ByteString.EMPTY; + bitField0_ = (bitField0_ & ~0x00000020); + return this; + } + + public Builder clone() { + return create().mergeFrom(buildPartial()); + } + + public com.mogujie.tt.protobuf.IMGroup.IMGroupCreateReq getDefaultInstanceForType() { + return com.mogujie.tt.protobuf.IMGroup.IMGroupCreateReq.getDefaultInstance(); + } + + public com.mogujie.tt.protobuf.IMGroup.IMGroupCreateReq build() { + com.mogujie.tt.protobuf.IMGroup.IMGroupCreateReq result = buildPartial(); + if (!result.isInitialized()) { + throw newUninitializedMessageException(result); + } + return result; + } + + public com.mogujie.tt.protobuf.IMGroup.IMGroupCreateReq buildPartial() { + com.mogujie.tt.protobuf.IMGroup.IMGroupCreateReq result = new com.mogujie.tt.protobuf.IMGroup.IMGroupCreateReq(this); + int from_bitField0_ = bitField0_; + int to_bitField0_ = 0; + if (((from_bitField0_ & 0x00000001) == 0x00000001)) { + to_bitField0_ |= 0x00000001; + } + result.userId_ = userId_; + if (((from_bitField0_ & 0x00000002) == 0x00000002)) { + to_bitField0_ |= 0x00000002; + } + result.groupType_ = groupType_; + if (((from_bitField0_ & 0x00000004) == 0x00000004)) { + to_bitField0_ |= 0x00000004; + } + result.groupName_ = groupName_; + if (((from_bitField0_ & 0x00000008) == 0x00000008)) { + to_bitField0_ |= 0x00000008; + } + result.groupAvatar_ = groupAvatar_; + if (((bitField0_ & 0x00000010) == 0x00000010)) { + memberIdList_ = java.util.Collections.unmodifiableList(memberIdList_); + bitField0_ = (bitField0_ & ~0x00000010); + } + result.memberIdList_ = memberIdList_; + if (((from_bitField0_ & 0x00000020) == 0x00000020)) { + to_bitField0_ |= 0x00000010; + } + result.attachData_ = attachData_; + result.bitField0_ = to_bitField0_; + return result; + } + + public Builder mergeFrom(com.mogujie.tt.protobuf.IMGroup.IMGroupCreateReq other) { + if (other == com.mogujie.tt.protobuf.IMGroup.IMGroupCreateReq.getDefaultInstance()) return this; + if (other.hasUserId()) { + setUserId(other.getUserId()); + } + if (other.hasGroupType()) { + setGroupType(other.getGroupType()); + } + if (other.hasGroupName()) { + bitField0_ |= 0x00000004; + groupName_ = other.groupName_; + + } + if (other.hasGroupAvatar()) { + bitField0_ |= 0x00000008; + groupAvatar_ = other.groupAvatar_; + + } + if (!other.memberIdList_.isEmpty()) { + if (memberIdList_.isEmpty()) { + memberIdList_ = other.memberIdList_; + bitField0_ = (bitField0_ & ~0x00000010); + } else { + ensureMemberIdListIsMutable(); + memberIdList_.addAll(other.memberIdList_); + } + + } + if (other.hasAttachData()) { + setAttachData(other.getAttachData()); + } + setUnknownFields( + getUnknownFields().concat(other.unknownFields)); + return this; + } + + public final boolean isInitialized() { + if (!hasUserId()) { + + return false; + } + if (!hasGroupType()) { + + return false; + } + if (!hasGroupName()) { + + return false; + } + if (!hasGroupAvatar()) { + + return false; + } + return true; + } + + public Builder mergeFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + com.mogujie.tt.protobuf.IMGroup.IMGroupCreateReq parsedMessage = null; + try { + parsedMessage = PARSER.parsePartialFrom(input, extensionRegistry); + } catch (com.google.protobuf.InvalidProtocolBufferException e) { + parsedMessage = (com.mogujie.tt.protobuf.IMGroup.IMGroupCreateReq) e.getUnfinishedMessage(); + throw e; + } finally { + if (parsedMessage != null) { + mergeFrom(parsedMessage); + } + } + return this; + } + private int bitField0_; + + private int userId_ ; + /** + * required uint32 user_id = 1; + * + *
+       *cmd id:			0x0405
+       * 
+ */ + public boolean hasUserId() { + return ((bitField0_ & 0x00000001) == 0x00000001); + } + /** + * required uint32 user_id = 1; + * + *
+       *cmd id:			0x0405
+       * 
+ */ + public int getUserId() { + return userId_; + } + /** + * required uint32 user_id = 1; + * + *
+       *cmd id:			0x0405
+       * 
+ */ + public Builder setUserId(int value) { + bitField0_ |= 0x00000001; + userId_ = value; + + return this; + } + /** + * required uint32 user_id = 1; + * + *
+       *cmd id:			0x0405
+       * 
+ */ + public Builder clearUserId() { + bitField0_ = (bitField0_ & ~0x00000001); + userId_ = 0; + + return this; + } + + private com.mogujie.tt.protobuf.IMBaseDefine.GroupType groupType_ = com.mogujie.tt.protobuf.IMBaseDefine.GroupType.GROUP_TYPE_TMP; + /** + * required .IM.BaseDefine.GroupType group_type = 2 [default = GROUP_TYPE_TMP]; + * + *
+       *默认是创建临时群,且客户端只能创建临时群
+       * 
+ */ + public boolean hasGroupType() { + return ((bitField0_ & 0x00000002) == 0x00000002); + } + /** + * required .IM.BaseDefine.GroupType group_type = 2 [default = GROUP_TYPE_TMP]; + * + *
+       *默认是创建临时群,且客户端只能创建临时群
+       * 
+ */ + public com.mogujie.tt.protobuf.IMBaseDefine.GroupType getGroupType() { + return groupType_; + } + /** + * required .IM.BaseDefine.GroupType group_type = 2 [default = GROUP_TYPE_TMP]; + * + *
+       *默认是创建临时群,且客户端只能创建临时群
+       * 
+ */ + public Builder setGroupType(com.mogujie.tt.protobuf.IMBaseDefine.GroupType value) { + if (value == null) { + throw new NullPointerException(); + } + bitField0_ |= 0x00000002; + groupType_ = value; + + return this; + } + /** + * required .IM.BaseDefine.GroupType group_type = 2 [default = GROUP_TYPE_TMP]; + * + *
+       *默认是创建临时群,且客户端只能创建临时群
+       * 
+ */ + public Builder clearGroupType() { + bitField0_ = (bitField0_ & ~0x00000002); + groupType_ = com.mogujie.tt.protobuf.IMBaseDefine.GroupType.GROUP_TYPE_TMP; + + return this; + } + + private java.lang.Object groupName_ = ""; + /** + * required string group_name = 3; + */ + public boolean hasGroupName() { + return ((bitField0_ & 0x00000004) == 0x00000004); + } + /** + * required string group_name = 3; + */ + public java.lang.String getGroupName() { + java.lang.Object ref = groupName_; + if (!(ref instanceof java.lang.String)) { + com.google.protobuf.ByteString bs = + (com.google.protobuf.ByteString) ref; + java.lang.String s = bs.toStringUtf8(); + if (bs.isValidUtf8()) { + groupName_ = s; + } + return s; + } else { + return (java.lang.String) ref; + } + } + /** + * required string group_name = 3; + */ + public com.google.protobuf.ByteString + getGroupNameBytes() { + java.lang.Object ref = groupName_; + if (ref instanceof String) { + com.google.protobuf.ByteString b = + com.google.protobuf.ByteString.copyFromUtf8( + (java.lang.String) ref); + groupName_ = b; + return b; + } else { + return (com.google.protobuf.ByteString) ref; + } + } + /** + * required string group_name = 3; + */ + public Builder setGroupName( + java.lang.String value) { + if (value == null) { + throw new NullPointerException(); + } + bitField0_ |= 0x00000004; + groupName_ = value; + + return this; + } + /** + * required string group_name = 3; + */ + public Builder clearGroupName() { + bitField0_ = (bitField0_ & ~0x00000004); + groupName_ = getDefaultInstance().getGroupName(); + + return this; + } + /** + * required string group_name = 3; + */ + public Builder setGroupNameBytes( + com.google.protobuf.ByteString value) { + if (value == null) { + throw new NullPointerException(); + } + bitField0_ |= 0x00000004; + groupName_ = value; + + return this; + } + + private java.lang.Object groupAvatar_ = ""; + /** + * required string group_avatar = 4; + */ + public boolean hasGroupAvatar() { + return ((bitField0_ & 0x00000008) == 0x00000008); + } + /** + * required string group_avatar = 4; + */ + public java.lang.String getGroupAvatar() { + java.lang.Object ref = groupAvatar_; + if (!(ref instanceof java.lang.String)) { + com.google.protobuf.ByteString bs = + (com.google.protobuf.ByteString) ref; + java.lang.String s = bs.toStringUtf8(); + if (bs.isValidUtf8()) { + groupAvatar_ = s; + } + return s; + } else { + return (java.lang.String) ref; + } + } + /** + * required string group_avatar = 4; + */ + public com.google.protobuf.ByteString + getGroupAvatarBytes() { + java.lang.Object ref = groupAvatar_; + if (ref instanceof String) { + com.google.protobuf.ByteString b = + com.google.protobuf.ByteString.copyFromUtf8( + (java.lang.String) ref); + groupAvatar_ = b; + return b; + } else { + return (com.google.protobuf.ByteString) ref; + } + } + /** + * required string group_avatar = 4; + */ + public Builder setGroupAvatar( + java.lang.String value) { + if (value == null) { + throw new NullPointerException(); + } + bitField0_ |= 0x00000008; + groupAvatar_ = value; + + return this; + } + /** + * required string group_avatar = 4; + */ + public Builder clearGroupAvatar() { + bitField0_ = (bitField0_ & ~0x00000008); + groupAvatar_ = getDefaultInstance().getGroupAvatar(); + + return this; + } + /** + * required string group_avatar = 4; + */ + public Builder setGroupAvatarBytes( + com.google.protobuf.ByteString value) { + if (value == null) { + throw new NullPointerException(); + } + bitField0_ |= 0x00000008; + groupAvatar_ = value; + + return this; + } + + private java.util.List memberIdList_ = java.util.Collections.emptyList(); + private void ensureMemberIdListIsMutable() { + if (!((bitField0_ & 0x00000010) == 0x00000010)) { + memberIdList_ = new java.util.ArrayList(memberIdList_); + bitField0_ |= 0x00000010; + } + } + /** + * repeated uint32 member_id_list = 5; + */ + public java.util.List + getMemberIdListList() { + return java.util.Collections.unmodifiableList(memberIdList_); + } + /** + * repeated uint32 member_id_list = 5; + */ + public int getMemberIdListCount() { + return memberIdList_.size(); + } + /** + * repeated uint32 member_id_list = 5; + */ + public int getMemberIdList(int index) { + return memberIdList_.get(index); + } + /** + * repeated uint32 member_id_list = 5; + */ + public Builder setMemberIdList( + int index, int value) { + ensureMemberIdListIsMutable(); + memberIdList_.set(index, value); + + return this; + } + /** + * repeated uint32 member_id_list = 5; + */ + public Builder addMemberIdList(int value) { + ensureMemberIdListIsMutable(); + memberIdList_.add(value); + + return this; + } + /** + * repeated uint32 member_id_list = 5; + */ + public Builder addAllMemberIdList( + java.lang.Iterable values) { + ensureMemberIdListIsMutable(); + com.google.protobuf.AbstractMessageLite.Builder.addAll( + values, memberIdList_); + + return this; + } + /** + * repeated uint32 member_id_list = 5; + */ + public Builder clearMemberIdList() { + memberIdList_ = java.util.Collections.emptyList(); + bitField0_ = (bitField0_ & ~0x00000010); + + return this; + } + + private com.google.protobuf.ByteString attachData_ = com.google.protobuf.ByteString.EMPTY; + /** + * optional bytes attach_data = 20; + */ + public boolean hasAttachData() { + return ((bitField0_ & 0x00000020) == 0x00000020); + } + /** + * optional bytes attach_data = 20; + */ + public com.google.protobuf.ByteString getAttachData() { + return attachData_; + } + /** + * optional bytes attach_data = 20; + */ + public Builder setAttachData(com.google.protobuf.ByteString value) { + if (value == null) { + throw new NullPointerException(); + } + bitField0_ |= 0x00000020; + attachData_ = value; + + return this; + } + /** + * optional bytes attach_data = 20; + */ + public Builder clearAttachData() { + bitField0_ = (bitField0_ & ~0x00000020); + attachData_ = getDefaultInstance().getAttachData(); + + return this; + } + + // @@protoc_insertion_point(builder_scope:IM.Group.IMGroupCreateReq) + } + + static { + defaultInstance = new IMGroupCreateReq(true); + defaultInstance.initFields(); + } + + // @@protoc_insertion_point(class_scope:IM.Group.IMGroupCreateReq) + } + + public interface IMGroupCreateRspOrBuilder extends + // @@protoc_insertion_point(interface_extends:IM.Group.IMGroupCreateRsp) + com.google.protobuf.MessageLiteOrBuilder { + + /** + * required uint32 user_id = 1; + * + *
+     *cmd id:			0x0406
+     * 
+ */ + boolean hasUserId(); + /** + * required uint32 user_id = 1; + * + *
+     *cmd id:			0x0406
+     * 
+ */ + int getUserId(); + + /** + * required uint32 result_code = 2; + */ + boolean hasResultCode(); + /** + * required uint32 result_code = 2; + */ + int getResultCode(); + + /** + * optional uint32 group_id = 3; + */ + boolean hasGroupId(); + /** + * optional uint32 group_id = 3; + */ + int getGroupId(); + + /** + * required string group_name = 4; + */ + boolean hasGroupName(); + /** + * required string group_name = 4; + */ + java.lang.String getGroupName(); + /** + * required string group_name = 4; + */ + com.google.protobuf.ByteString + getGroupNameBytes(); + + /** + * repeated uint32 user_id_list = 5; + */ + java.util.List getUserIdListList(); + /** + * repeated uint32 user_id_list = 5; + */ + int getUserIdListCount(); + /** + * repeated uint32 user_id_list = 5; + */ + int getUserIdList(int index); + + /** + * optional bytes attach_data = 20; + */ + boolean hasAttachData(); + /** + * optional bytes attach_data = 20; + */ + com.google.protobuf.ByteString getAttachData(); + } + /** + * Protobuf type {@code IM.Group.IMGroupCreateRsp} + */ + public static final class IMGroupCreateRsp extends + com.google.protobuf.GeneratedMessageLite implements + // @@protoc_insertion_point(message_implements:IM.Group.IMGroupCreateRsp) + IMGroupCreateRspOrBuilder { + // Use IMGroupCreateRsp.newBuilder() to construct. + private IMGroupCreateRsp(com.google.protobuf.GeneratedMessageLite.Builder builder) { + super(builder); + this.unknownFields = builder.getUnknownFields(); + } + private IMGroupCreateRsp(boolean noInit) { this.unknownFields = com.google.protobuf.ByteString.EMPTY;} + + private static final IMGroupCreateRsp defaultInstance; + public static IMGroupCreateRsp getDefaultInstance() { + return defaultInstance; + } + + public IMGroupCreateRsp getDefaultInstanceForType() { + return defaultInstance; + } + + private final com.google.protobuf.ByteString unknownFields; + private IMGroupCreateRsp( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + initFields(); + int mutable_bitField0_ = 0; + com.google.protobuf.ByteString.Output unknownFieldsOutput = + com.google.protobuf.ByteString.newOutput(); + com.google.protobuf.CodedOutputStream unknownFieldsCodedOutput = + com.google.protobuf.CodedOutputStream.newInstance( + unknownFieldsOutput); + try { + boolean done = false; + while (!done) { + int tag = input.readTag(); + switch (tag) { + case 0: + done = true; + break; + default: { + if (!parseUnknownField(input, unknownFieldsCodedOutput, + extensionRegistry, tag)) { + done = true; + } + break; + } + case 8: { + bitField0_ |= 0x00000001; + userId_ = input.readUInt32(); + break; + } + case 16: { + bitField0_ |= 0x00000002; + resultCode_ = input.readUInt32(); + break; + } + case 24: { + bitField0_ |= 0x00000004; + groupId_ = input.readUInt32(); + break; + } + case 34: { + com.google.protobuf.ByteString bs = input.readBytes(); + bitField0_ |= 0x00000008; + groupName_ = bs; + break; + } + case 40: { + if (!((mutable_bitField0_ & 0x00000010) == 0x00000010)) { + userIdList_ = new java.util.ArrayList(); + mutable_bitField0_ |= 0x00000010; + } + userIdList_.add(input.readUInt32()); + break; + } + case 42: { + int length = input.readRawVarint32(); + int limit = input.pushLimit(length); + if (!((mutable_bitField0_ & 0x00000010) == 0x00000010) && input.getBytesUntilLimit() > 0) { + userIdList_ = new java.util.ArrayList(); + mutable_bitField0_ |= 0x00000010; + } + while (input.getBytesUntilLimit() > 0) { + userIdList_.add(input.readUInt32()); + } + input.popLimit(limit); + break; + } + case 162: { + bitField0_ |= 0x00000010; + attachData_ = input.readBytes(); + break; + } + } + } + } catch (com.google.protobuf.InvalidProtocolBufferException e) { + throw e.setUnfinishedMessage(this); + } catch (java.io.IOException e) { + throw new com.google.protobuf.InvalidProtocolBufferException( + e.getMessage()).setUnfinishedMessage(this); + } finally { + if (((mutable_bitField0_ & 0x00000010) == 0x00000010)) { + userIdList_ = java.util.Collections.unmodifiableList(userIdList_); + } + try { + unknownFieldsCodedOutput.flush(); + } catch (java.io.IOException e) { + // Should not happen + } finally { + unknownFields = unknownFieldsOutput.toByteString(); + } + makeExtensionsImmutable(); + } + } + public static com.google.protobuf.Parser PARSER = + new com.google.protobuf.AbstractParser() { + public IMGroupCreateRsp parsePartialFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return new IMGroupCreateRsp(input, extensionRegistry); + } + }; + + @java.lang.Override + public com.google.protobuf.Parser getParserForType() { + return PARSER; + } + + private int bitField0_; + public static final int USER_ID_FIELD_NUMBER = 1; + private int userId_; + /** + * required uint32 user_id = 1; + * + *
+     *cmd id:			0x0406
+     * 
+ */ + public boolean hasUserId() { + return ((bitField0_ & 0x00000001) == 0x00000001); + } + /** + * required uint32 user_id = 1; + * + *
+     *cmd id:			0x0406
+     * 
+ */ + public int getUserId() { + return userId_; + } + + public static final int RESULT_CODE_FIELD_NUMBER = 2; + private int resultCode_; + /** + * required uint32 result_code = 2; + */ + public boolean hasResultCode() { + return ((bitField0_ & 0x00000002) == 0x00000002); + } + /** + * required uint32 result_code = 2; + */ + public int getResultCode() { + return resultCode_; + } + + public static final int GROUP_ID_FIELD_NUMBER = 3; + private int groupId_; + /** + * optional uint32 group_id = 3; + */ + public boolean hasGroupId() { + return ((bitField0_ & 0x00000004) == 0x00000004); + } + /** + * optional uint32 group_id = 3; + */ + public int getGroupId() { + return groupId_; + } + + public static final int GROUP_NAME_FIELD_NUMBER = 4; + private java.lang.Object groupName_; + /** + * required string group_name = 4; + */ + public boolean hasGroupName() { + return ((bitField0_ & 0x00000008) == 0x00000008); + } + /** + * required string group_name = 4; + */ + public java.lang.String getGroupName() { + java.lang.Object ref = groupName_; + if (ref instanceof java.lang.String) { + return (java.lang.String) ref; + } else { + com.google.protobuf.ByteString bs = + (com.google.protobuf.ByteString) ref; + java.lang.String s = bs.toStringUtf8(); + if (bs.isValidUtf8()) { + groupName_ = s; + } + return s; + } + } + /** + * required string group_name = 4; + */ + public com.google.protobuf.ByteString + getGroupNameBytes() { + java.lang.Object ref = groupName_; + if (ref instanceof java.lang.String) { + com.google.protobuf.ByteString b = + com.google.protobuf.ByteString.copyFromUtf8( + (java.lang.String) ref); + groupName_ = b; + return b; + } else { + return (com.google.protobuf.ByteString) ref; + } + } + + public static final int USER_ID_LIST_FIELD_NUMBER = 5; + private java.util.List userIdList_; + /** + * repeated uint32 user_id_list = 5; + */ + public java.util.List + getUserIdListList() { + return userIdList_; + } + /** + * repeated uint32 user_id_list = 5; + */ + public int getUserIdListCount() { + return userIdList_.size(); + } + /** + * repeated uint32 user_id_list = 5; + */ + public int getUserIdList(int index) { + return userIdList_.get(index); + } + + public static final int ATTACH_DATA_FIELD_NUMBER = 20; + private com.google.protobuf.ByteString attachData_; + /** + * optional bytes attach_data = 20; + */ + public boolean hasAttachData() { + return ((bitField0_ & 0x00000010) == 0x00000010); + } + /** + * optional bytes attach_data = 20; + */ + public com.google.protobuf.ByteString getAttachData() { + return attachData_; + } + + private void initFields() { + userId_ = 0; + resultCode_ = 0; + groupId_ = 0; + groupName_ = ""; + userIdList_ = java.util.Collections.emptyList(); + attachData_ = com.google.protobuf.ByteString.EMPTY; + } + private byte memoizedIsInitialized = -1; + public final boolean isInitialized() { + byte isInitialized = memoizedIsInitialized; + if (isInitialized == 1) return true; + if (isInitialized == 0) return false; + + if (!hasUserId()) { + memoizedIsInitialized = 0; + return false; + } + if (!hasResultCode()) { + memoizedIsInitialized = 0; + return false; + } + if (!hasGroupName()) { + memoizedIsInitialized = 0; + return false; + } + memoizedIsInitialized = 1; + return true; + } + + public void writeTo(com.google.protobuf.CodedOutputStream output) + throws java.io.IOException { + getSerializedSize(); + if (((bitField0_ & 0x00000001) == 0x00000001)) { + output.writeUInt32(1, userId_); + } + if (((bitField0_ & 0x00000002) == 0x00000002)) { + output.writeUInt32(2, resultCode_); + } + if (((bitField0_ & 0x00000004) == 0x00000004)) { + output.writeUInt32(3, groupId_); + } + if (((bitField0_ & 0x00000008) == 0x00000008)) { + output.writeBytes(4, getGroupNameBytes()); + } + for (int i = 0; i < userIdList_.size(); i++) { + output.writeUInt32(5, userIdList_.get(i)); + } + if (((bitField0_ & 0x00000010) == 0x00000010)) { + output.writeBytes(20, attachData_); + } + output.writeRawBytes(unknownFields); + } + + private int memoizedSerializedSize = -1; + public int getSerializedSize() { + int size = memoizedSerializedSize; + if (size != -1) return size; + + size = 0; + if (((bitField0_ & 0x00000001) == 0x00000001)) { + size += com.google.protobuf.CodedOutputStream + .computeUInt32Size(1, userId_); + } + if (((bitField0_ & 0x00000002) == 0x00000002)) { + size += com.google.protobuf.CodedOutputStream + .computeUInt32Size(2, resultCode_); + } + if (((bitField0_ & 0x00000004) == 0x00000004)) { + size += com.google.protobuf.CodedOutputStream + .computeUInt32Size(3, groupId_); + } + if (((bitField0_ & 0x00000008) == 0x00000008)) { + size += com.google.protobuf.CodedOutputStream + .computeBytesSize(4, getGroupNameBytes()); + } + { + int dataSize = 0; + for (int i = 0; i < userIdList_.size(); i++) { + dataSize += com.google.protobuf.CodedOutputStream + .computeUInt32SizeNoTag(userIdList_.get(i)); + } + size += dataSize; + size += 1 * getUserIdListList().size(); + } + if (((bitField0_ & 0x00000010) == 0x00000010)) { + size += com.google.protobuf.CodedOutputStream + .computeBytesSize(20, attachData_); + } + size += unknownFields.size(); + memoizedSerializedSize = size; + return size; + } + + private static final long serialVersionUID = 0L; + @java.lang.Override + protected java.lang.Object writeReplace() + throws java.io.ObjectStreamException { + return super.writeReplace(); + } + + public static com.mogujie.tt.protobuf.IMGroup.IMGroupCreateRsp parseFrom( + com.google.protobuf.ByteString data) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data); + } + public static com.mogujie.tt.protobuf.IMGroup.IMGroupCreateRsp parseFrom( + com.google.protobuf.ByteString data, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data, extensionRegistry); + } + public static com.mogujie.tt.protobuf.IMGroup.IMGroupCreateRsp parseFrom(byte[] data) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data); + } + public static com.mogujie.tt.protobuf.IMGroup.IMGroupCreateRsp parseFrom( + byte[] data, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data, extensionRegistry); + } + public static com.mogujie.tt.protobuf.IMGroup.IMGroupCreateRsp parseFrom(java.io.InputStream input) + throws java.io.IOException { + return PARSER.parseFrom(input); + } + public static com.mogujie.tt.protobuf.IMGroup.IMGroupCreateRsp parseFrom( + java.io.InputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return PARSER.parseFrom(input, extensionRegistry); + } + public static com.mogujie.tt.protobuf.IMGroup.IMGroupCreateRsp parseDelimitedFrom(java.io.InputStream input) + throws java.io.IOException { + return PARSER.parseDelimitedFrom(input); + } + public static com.mogujie.tt.protobuf.IMGroup.IMGroupCreateRsp parseDelimitedFrom( + java.io.InputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return PARSER.parseDelimitedFrom(input, extensionRegistry); + } + public static com.mogujie.tt.protobuf.IMGroup.IMGroupCreateRsp parseFrom( + com.google.protobuf.CodedInputStream input) + throws java.io.IOException { + return PARSER.parseFrom(input); + } + public static com.mogujie.tt.protobuf.IMGroup.IMGroupCreateRsp parseFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return PARSER.parseFrom(input, extensionRegistry); + } + + public static Builder newBuilder() { return Builder.create(); } + public Builder newBuilderForType() { return newBuilder(); } + public static Builder newBuilder(com.mogujie.tt.protobuf.IMGroup.IMGroupCreateRsp prototype) { + return newBuilder().mergeFrom(prototype); + } + public Builder toBuilder() { return newBuilder(this); } + + /** + * Protobuf type {@code IM.Group.IMGroupCreateRsp} + */ + public static final class Builder extends + com.google.protobuf.GeneratedMessageLite.Builder< + com.mogujie.tt.protobuf.IMGroup.IMGroupCreateRsp, Builder> + implements + // @@protoc_insertion_point(builder_implements:IM.Group.IMGroupCreateRsp) + com.mogujie.tt.protobuf.IMGroup.IMGroupCreateRspOrBuilder { + // Construct using com.mogujie.tt.protobuf.IMGroup.IMGroupCreateRsp.newBuilder() + private Builder() { + maybeForceBuilderInitialization(); + } + + private void maybeForceBuilderInitialization() { + } + private static Builder create() { + return new Builder(); + } + + public Builder clear() { + super.clear(); + userId_ = 0; + bitField0_ = (bitField0_ & ~0x00000001); + resultCode_ = 0; + bitField0_ = (bitField0_ & ~0x00000002); + groupId_ = 0; + bitField0_ = (bitField0_ & ~0x00000004); + groupName_ = ""; + bitField0_ = (bitField0_ & ~0x00000008); + userIdList_ = java.util.Collections.emptyList(); + bitField0_ = (bitField0_ & ~0x00000010); + attachData_ = com.google.protobuf.ByteString.EMPTY; + bitField0_ = (bitField0_ & ~0x00000020); + return this; + } + + public Builder clone() { + return create().mergeFrom(buildPartial()); + } + + public com.mogujie.tt.protobuf.IMGroup.IMGroupCreateRsp getDefaultInstanceForType() { + return com.mogujie.tt.protobuf.IMGroup.IMGroupCreateRsp.getDefaultInstance(); + } + + public com.mogujie.tt.protobuf.IMGroup.IMGroupCreateRsp build() { + com.mogujie.tt.protobuf.IMGroup.IMGroupCreateRsp result = buildPartial(); + if (!result.isInitialized()) { + throw newUninitializedMessageException(result); + } + return result; + } + + public com.mogujie.tt.protobuf.IMGroup.IMGroupCreateRsp buildPartial() { + com.mogujie.tt.protobuf.IMGroup.IMGroupCreateRsp result = new com.mogujie.tt.protobuf.IMGroup.IMGroupCreateRsp(this); + int from_bitField0_ = bitField0_; + int to_bitField0_ = 0; + if (((from_bitField0_ & 0x00000001) == 0x00000001)) { + to_bitField0_ |= 0x00000001; + } + result.userId_ = userId_; + if (((from_bitField0_ & 0x00000002) == 0x00000002)) { + to_bitField0_ |= 0x00000002; + } + result.resultCode_ = resultCode_; + if (((from_bitField0_ & 0x00000004) == 0x00000004)) { + to_bitField0_ |= 0x00000004; + } + result.groupId_ = groupId_; + if (((from_bitField0_ & 0x00000008) == 0x00000008)) { + to_bitField0_ |= 0x00000008; + } + result.groupName_ = groupName_; + if (((bitField0_ & 0x00000010) == 0x00000010)) { + userIdList_ = java.util.Collections.unmodifiableList(userIdList_); + bitField0_ = (bitField0_ & ~0x00000010); + } + result.userIdList_ = userIdList_; + if (((from_bitField0_ & 0x00000020) == 0x00000020)) { + to_bitField0_ |= 0x00000010; + } + result.attachData_ = attachData_; + result.bitField0_ = to_bitField0_; + return result; + } + + public Builder mergeFrom(com.mogujie.tt.protobuf.IMGroup.IMGroupCreateRsp other) { + if (other == com.mogujie.tt.protobuf.IMGroup.IMGroupCreateRsp.getDefaultInstance()) return this; + if (other.hasUserId()) { + setUserId(other.getUserId()); + } + if (other.hasResultCode()) { + setResultCode(other.getResultCode()); + } + if (other.hasGroupId()) { + setGroupId(other.getGroupId()); + } + if (other.hasGroupName()) { + bitField0_ |= 0x00000008; + groupName_ = other.groupName_; + + } + if (!other.userIdList_.isEmpty()) { + if (userIdList_.isEmpty()) { + userIdList_ = other.userIdList_; + bitField0_ = (bitField0_ & ~0x00000010); + } else { + ensureUserIdListIsMutable(); + userIdList_.addAll(other.userIdList_); + } + + } + if (other.hasAttachData()) { + setAttachData(other.getAttachData()); + } + setUnknownFields( + getUnknownFields().concat(other.unknownFields)); + return this; + } + + public final boolean isInitialized() { + if (!hasUserId()) { + + return false; + } + if (!hasResultCode()) { + + return false; + } + if (!hasGroupName()) { + + return false; + } + return true; + } + + public Builder mergeFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + com.mogujie.tt.protobuf.IMGroup.IMGroupCreateRsp parsedMessage = null; + try { + parsedMessage = PARSER.parsePartialFrom(input, extensionRegistry); + } catch (com.google.protobuf.InvalidProtocolBufferException e) { + parsedMessage = (com.mogujie.tt.protobuf.IMGroup.IMGroupCreateRsp) e.getUnfinishedMessage(); + throw e; + } finally { + if (parsedMessage != null) { + mergeFrom(parsedMessage); + } + } + return this; + } + private int bitField0_; + + private int userId_ ; + /** + * required uint32 user_id = 1; + * + *
+       *cmd id:			0x0406
+       * 
+ */ + public boolean hasUserId() { + return ((bitField0_ & 0x00000001) == 0x00000001); + } + /** + * required uint32 user_id = 1; + * + *
+       *cmd id:			0x0406
+       * 
+ */ + public int getUserId() { + return userId_; + } + /** + * required uint32 user_id = 1; + * + *
+       *cmd id:			0x0406
+       * 
+ */ + public Builder setUserId(int value) { + bitField0_ |= 0x00000001; + userId_ = value; + + return this; + } + /** + * required uint32 user_id = 1; + * + *
+       *cmd id:			0x0406
+       * 
+ */ + public Builder clearUserId() { + bitField0_ = (bitField0_ & ~0x00000001); + userId_ = 0; + + return this; + } + + private int resultCode_ ; + /** + * required uint32 result_code = 2; + */ + public boolean hasResultCode() { + return ((bitField0_ & 0x00000002) == 0x00000002); + } + /** + * required uint32 result_code = 2; + */ + public int getResultCode() { + return resultCode_; + } + /** + * required uint32 result_code = 2; + */ + public Builder setResultCode(int value) { + bitField0_ |= 0x00000002; + resultCode_ = value; + + return this; + } + /** + * required uint32 result_code = 2; + */ + public Builder clearResultCode() { + bitField0_ = (bitField0_ & ~0x00000002); + resultCode_ = 0; + + return this; + } + + private int groupId_ ; + /** + * optional uint32 group_id = 3; + */ + public boolean hasGroupId() { + return ((bitField0_ & 0x00000004) == 0x00000004); + } + /** + * optional uint32 group_id = 3; + */ + public int getGroupId() { + return groupId_; + } + /** + * optional uint32 group_id = 3; + */ + public Builder setGroupId(int value) { + bitField0_ |= 0x00000004; + groupId_ = value; + + return this; + } + /** + * optional uint32 group_id = 3; + */ + public Builder clearGroupId() { + bitField0_ = (bitField0_ & ~0x00000004); + groupId_ = 0; + + return this; + } + + private java.lang.Object groupName_ = ""; + /** + * required string group_name = 4; + */ + public boolean hasGroupName() { + return ((bitField0_ & 0x00000008) == 0x00000008); + } + /** + * required string group_name = 4; + */ + public java.lang.String getGroupName() { + java.lang.Object ref = groupName_; + if (!(ref instanceof java.lang.String)) { + com.google.protobuf.ByteString bs = + (com.google.protobuf.ByteString) ref; + java.lang.String s = bs.toStringUtf8(); + if (bs.isValidUtf8()) { + groupName_ = s; + } + return s; + } else { + return (java.lang.String) ref; + } + } + /** + * required string group_name = 4; + */ + public com.google.protobuf.ByteString + getGroupNameBytes() { + java.lang.Object ref = groupName_; + if (ref instanceof String) { + com.google.protobuf.ByteString b = + com.google.protobuf.ByteString.copyFromUtf8( + (java.lang.String) ref); + groupName_ = b; + return b; + } else { + return (com.google.protobuf.ByteString) ref; + } + } + /** + * required string group_name = 4; + */ + public Builder setGroupName( + java.lang.String value) { + if (value == null) { + throw new NullPointerException(); + } + bitField0_ |= 0x00000008; + groupName_ = value; + + return this; + } + /** + * required string group_name = 4; + */ + public Builder clearGroupName() { + bitField0_ = (bitField0_ & ~0x00000008); + groupName_ = getDefaultInstance().getGroupName(); + + return this; + } + /** + * required string group_name = 4; + */ + public Builder setGroupNameBytes( + com.google.protobuf.ByteString value) { + if (value == null) { + throw new NullPointerException(); + } + bitField0_ |= 0x00000008; + groupName_ = value; + + return this; + } + + private java.util.List userIdList_ = java.util.Collections.emptyList(); + private void ensureUserIdListIsMutable() { + if (!((bitField0_ & 0x00000010) == 0x00000010)) { + userIdList_ = new java.util.ArrayList(userIdList_); + bitField0_ |= 0x00000010; + } + } + /** + * repeated uint32 user_id_list = 5; + */ + public java.util.List + getUserIdListList() { + return java.util.Collections.unmodifiableList(userIdList_); + } + /** + * repeated uint32 user_id_list = 5; + */ + public int getUserIdListCount() { + return userIdList_.size(); + } + /** + * repeated uint32 user_id_list = 5; + */ + public int getUserIdList(int index) { + return userIdList_.get(index); + } + /** + * repeated uint32 user_id_list = 5; + */ + public Builder setUserIdList( + int index, int value) { + ensureUserIdListIsMutable(); + userIdList_.set(index, value); + + return this; + } + /** + * repeated uint32 user_id_list = 5; + */ + public Builder addUserIdList(int value) { + ensureUserIdListIsMutable(); + userIdList_.add(value); + + return this; + } + /** + * repeated uint32 user_id_list = 5; + */ + public Builder addAllUserIdList( + java.lang.Iterable values) { + ensureUserIdListIsMutable(); + com.google.protobuf.AbstractMessageLite.Builder.addAll( + values, userIdList_); + + return this; + } + /** + * repeated uint32 user_id_list = 5; + */ + public Builder clearUserIdList() { + userIdList_ = java.util.Collections.emptyList(); + bitField0_ = (bitField0_ & ~0x00000010); + + return this; + } + + private com.google.protobuf.ByteString attachData_ = com.google.protobuf.ByteString.EMPTY; + /** + * optional bytes attach_data = 20; + */ + public boolean hasAttachData() { + return ((bitField0_ & 0x00000020) == 0x00000020); + } + /** + * optional bytes attach_data = 20; + */ + public com.google.protobuf.ByteString getAttachData() { + return attachData_; + } + /** + * optional bytes attach_data = 20; + */ + public Builder setAttachData(com.google.protobuf.ByteString value) { + if (value == null) { + throw new NullPointerException(); + } + bitField0_ |= 0x00000020; + attachData_ = value; + + return this; + } + /** + * optional bytes attach_data = 20; + */ + public Builder clearAttachData() { + bitField0_ = (bitField0_ & ~0x00000020); + attachData_ = getDefaultInstance().getAttachData(); + + return this; + } + + // @@protoc_insertion_point(builder_scope:IM.Group.IMGroupCreateRsp) + } + + static { + defaultInstance = new IMGroupCreateRsp(true); + defaultInstance.initFields(); + } + + // @@protoc_insertion_point(class_scope:IM.Group.IMGroupCreateRsp) + } + + public interface IMGroupChangeMemberReqOrBuilder extends + // @@protoc_insertion_point(interface_extends:IM.Group.IMGroupChangeMemberReq) + com.google.protobuf.MessageLiteOrBuilder { + + /** + * required uint32 user_id = 1; + * + *
+     *cmd id:			0x0407
+     * 
+ */ + boolean hasUserId(); + /** + * required uint32 user_id = 1; + * + *
+     *cmd id:			0x0407
+     * 
+ */ + int getUserId(); + + /** + * required .IM.BaseDefine.GroupModifyType change_type = 2; + */ + boolean hasChangeType(); + /** + * required .IM.BaseDefine.GroupModifyType change_type = 2; + */ + com.mogujie.tt.protobuf.IMBaseDefine.GroupModifyType getChangeType(); + + /** + * required uint32 group_id = 3; + */ + boolean hasGroupId(); + /** + * required uint32 group_id = 3; + */ + int getGroupId(); + + /** + * repeated uint32 member_id_list = 4; + */ + java.util.List getMemberIdListList(); + /** + * repeated uint32 member_id_list = 4; + */ + int getMemberIdListCount(); + /** + * repeated uint32 member_id_list = 4; + */ + int getMemberIdList(int index); + + /** + * optional bytes attach_data = 20; + */ + boolean hasAttachData(); + /** + * optional bytes attach_data = 20; + */ + com.google.protobuf.ByteString getAttachData(); + } + /** + * Protobuf type {@code IM.Group.IMGroupChangeMemberReq} + */ + public static final class IMGroupChangeMemberReq extends + com.google.protobuf.GeneratedMessageLite implements + // @@protoc_insertion_point(message_implements:IM.Group.IMGroupChangeMemberReq) + IMGroupChangeMemberReqOrBuilder { + // Use IMGroupChangeMemberReq.newBuilder() to construct. + private IMGroupChangeMemberReq(com.google.protobuf.GeneratedMessageLite.Builder builder) { + super(builder); + this.unknownFields = builder.getUnknownFields(); + } + private IMGroupChangeMemberReq(boolean noInit) { this.unknownFields = com.google.protobuf.ByteString.EMPTY;} + + private static final IMGroupChangeMemberReq defaultInstance; + public static IMGroupChangeMemberReq getDefaultInstance() { + return defaultInstance; + } + + public IMGroupChangeMemberReq getDefaultInstanceForType() { + return defaultInstance; + } + + private final com.google.protobuf.ByteString unknownFields; + private IMGroupChangeMemberReq( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + initFields(); + int mutable_bitField0_ = 0; + com.google.protobuf.ByteString.Output unknownFieldsOutput = + com.google.protobuf.ByteString.newOutput(); + com.google.protobuf.CodedOutputStream unknownFieldsCodedOutput = + com.google.protobuf.CodedOutputStream.newInstance( + unknownFieldsOutput); + try { + boolean done = false; + while (!done) { + int tag = input.readTag(); + switch (tag) { + case 0: + done = true; + break; + default: { + if (!parseUnknownField(input, unknownFieldsCodedOutput, + extensionRegistry, tag)) { + done = true; + } + break; + } + case 8: { + bitField0_ |= 0x00000001; + userId_ = input.readUInt32(); + break; + } + case 16: { + int rawValue = input.readEnum(); + com.mogujie.tt.protobuf.IMBaseDefine.GroupModifyType value = com.mogujie.tt.protobuf.IMBaseDefine.GroupModifyType.valueOf(rawValue); + if (value == null) { + unknownFieldsCodedOutput.writeRawVarint32(tag); + unknownFieldsCodedOutput.writeRawVarint32(rawValue); + } else { + bitField0_ |= 0x00000002; + changeType_ = value; + } + break; + } + case 24: { + bitField0_ |= 0x00000004; + groupId_ = input.readUInt32(); + break; + } + case 32: { + if (!((mutable_bitField0_ & 0x00000008) == 0x00000008)) { + memberIdList_ = new java.util.ArrayList(); + mutable_bitField0_ |= 0x00000008; + } + memberIdList_.add(input.readUInt32()); + break; + } + case 34: { + int length = input.readRawVarint32(); + int limit = input.pushLimit(length); + if (!((mutable_bitField0_ & 0x00000008) == 0x00000008) && input.getBytesUntilLimit() > 0) { + memberIdList_ = new java.util.ArrayList(); + mutable_bitField0_ |= 0x00000008; + } + while (input.getBytesUntilLimit() > 0) { + memberIdList_.add(input.readUInt32()); + } + input.popLimit(limit); + break; + } + case 162: { + bitField0_ |= 0x00000008; + attachData_ = input.readBytes(); + break; + } + } + } + } catch (com.google.protobuf.InvalidProtocolBufferException e) { + throw e.setUnfinishedMessage(this); + } catch (java.io.IOException e) { + throw new com.google.protobuf.InvalidProtocolBufferException( + e.getMessage()).setUnfinishedMessage(this); + } finally { + if (((mutable_bitField0_ & 0x00000008) == 0x00000008)) { + memberIdList_ = java.util.Collections.unmodifiableList(memberIdList_); + } + try { + unknownFieldsCodedOutput.flush(); + } catch (java.io.IOException e) { + // Should not happen + } finally { + unknownFields = unknownFieldsOutput.toByteString(); + } + makeExtensionsImmutable(); + } + } + public static com.google.protobuf.Parser PARSER = + new com.google.protobuf.AbstractParser() { + public IMGroupChangeMemberReq parsePartialFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return new IMGroupChangeMemberReq(input, extensionRegistry); + } + }; + + @java.lang.Override + public com.google.protobuf.Parser getParserForType() { + return PARSER; + } + + private int bitField0_; + public static final int USER_ID_FIELD_NUMBER = 1; + private int userId_; + /** + * required uint32 user_id = 1; + * + *
+     *cmd id:			0x0407
+     * 
+ */ + public boolean hasUserId() { + return ((bitField0_ & 0x00000001) == 0x00000001); + } + /** + * required uint32 user_id = 1; + * + *
+     *cmd id:			0x0407
+     * 
+ */ + public int getUserId() { + return userId_; + } + + public static final int CHANGE_TYPE_FIELD_NUMBER = 2; + private com.mogujie.tt.protobuf.IMBaseDefine.GroupModifyType changeType_; + /** + * required .IM.BaseDefine.GroupModifyType change_type = 2; + */ + public boolean hasChangeType() { + return ((bitField0_ & 0x00000002) == 0x00000002); + } + /** + * required .IM.BaseDefine.GroupModifyType change_type = 2; + */ + public com.mogujie.tt.protobuf.IMBaseDefine.GroupModifyType getChangeType() { + return changeType_; + } + + public static final int GROUP_ID_FIELD_NUMBER = 3; + private int groupId_; + /** + * required uint32 group_id = 3; + */ + public boolean hasGroupId() { + return ((bitField0_ & 0x00000004) == 0x00000004); + } + /** + * required uint32 group_id = 3; + */ + public int getGroupId() { + return groupId_; + } + + public static final int MEMBER_ID_LIST_FIELD_NUMBER = 4; + private java.util.List memberIdList_; + /** + * repeated uint32 member_id_list = 4; + */ + public java.util.List + getMemberIdListList() { + return memberIdList_; + } + /** + * repeated uint32 member_id_list = 4; + */ + public int getMemberIdListCount() { + return memberIdList_.size(); + } + /** + * repeated uint32 member_id_list = 4; + */ + public int getMemberIdList(int index) { + return memberIdList_.get(index); + } + + public static final int ATTACH_DATA_FIELD_NUMBER = 20; + private com.google.protobuf.ByteString attachData_; + /** + * optional bytes attach_data = 20; + */ + public boolean hasAttachData() { + return ((bitField0_ & 0x00000008) == 0x00000008); + } + /** + * optional bytes attach_data = 20; + */ + public com.google.protobuf.ByteString getAttachData() { + return attachData_; + } + + private void initFields() { + userId_ = 0; + changeType_ = com.mogujie.tt.protobuf.IMBaseDefine.GroupModifyType.GROUP_MODIFY_TYPE_ADD; + groupId_ = 0; + memberIdList_ = java.util.Collections.emptyList(); + attachData_ = com.google.protobuf.ByteString.EMPTY; + } + private byte memoizedIsInitialized = -1; + public final boolean isInitialized() { + byte isInitialized = memoizedIsInitialized; + if (isInitialized == 1) return true; + if (isInitialized == 0) return false; + + if (!hasUserId()) { + memoizedIsInitialized = 0; + return false; + } + if (!hasChangeType()) { + memoizedIsInitialized = 0; + return false; + } + if (!hasGroupId()) { + memoizedIsInitialized = 0; + return false; + } + memoizedIsInitialized = 1; + return true; + } + + public void writeTo(com.google.protobuf.CodedOutputStream output) + throws java.io.IOException { + getSerializedSize(); + if (((bitField0_ & 0x00000001) == 0x00000001)) { + output.writeUInt32(1, userId_); + } + if (((bitField0_ & 0x00000002) == 0x00000002)) { + output.writeEnum(2, changeType_.getNumber()); + } + if (((bitField0_ & 0x00000004) == 0x00000004)) { + output.writeUInt32(3, groupId_); + } + for (int i = 0; i < memberIdList_.size(); i++) { + output.writeUInt32(4, memberIdList_.get(i)); + } + if (((bitField0_ & 0x00000008) == 0x00000008)) { + output.writeBytes(20, attachData_); + } + output.writeRawBytes(unknownFields); + } + + private int memoizedSerializedSize = -1; + public int getSerializedSize() { + int size = memoizedSerializedSize; + if (size != -1) return size; + + size = 0; + if (((bitField0_ & 0x00000001) == 0x00000001)) { + size += com.google.protobuf.CodedOutputStream + .computeUInt32Size(1, userId_); + } + if (((bitField0_ & 0x00000002) == 0x00000002)) { + size += com.google.protobuf.CodedOutputStream + .computeEnumSize(2, changeType_.getNumber()); + } + if (((bitField0_ & 0x00000004) == 0x00000004)) { + size += com.google.protobuf.CodedOutputStream + .computeUInt32Size(3, groupId_); + } + { + int dataSize = 0; + for (int i = 0; i < memberIdList_.size(); i++) { + dataSize += com.google.protobuf.CodedOutputStream + .computeUInt32SizeNoTag(memberIdList_.get(i)); + } + size += dataSize; + size += 1 * getMemberIdListList().size(); + } + if (((bitField0_ & 0x00000008) == 0x00000008)) { + size += com.google.protobuf.CodedOutputStream + .computeBytesSize(20, attachData_); + } + size += unknownFields.size(); + memoizedSerializedSize = size; + return size; + } + + private static final long serialVersionUID = 0L; + @java.lang.Override + protected java.lang.Object writeReplace() + throws java.io.ObjectStreamException { + return super.writeReplace(); + } + + public static com.mogujie.tt.protobuf.IMGroup.IMGroupChangeMemberReq parseFrom( + com.google.protobuf.ByteString data) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data); + } + public static com.mogujie.tt.protobuf.IMGroup.IMGroupChangeMemberReq parseFrom( + com.google.protobuf.ByteString data, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data, extensionRegistry); + } + public static com.mogujie.tt.protobuf.IMGroup.IMGroupChangeMemberReq parseFrom(byte[] data) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data); + } + public static com.mogujie.tt.protobuf.IMGroup.IMGroupChangeMemberReq parseFrom( + byte[] data, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data, extensionRegistry); + } + public static com.mogujie.tt.protobuf.IMGroup.IMGroupChangeMemberReq parseFrom(java.io.InputStream input) + throws java.io.IOException { + return PARSER.parseFrom(input); + } + public static com.mogujie.tt.protobuf.IMGroup.IMGroupChangeMemberReq parseFrom( + java.io.InputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return PARSER.parseFrom(input, extensionRegistry); + } + public static com.mogujie.tt.protobuf.IMGroup.IMGroupChangeMemberReq parseDelimitedFrom(java.io.InputStream input) + throws java.io.IOException { + return PARSER.parseDelimitedFrom(input); + } + public static com.mogujie.tt.protobuf.IMGroup.IMGroupChangeMemberReq parseDelimitedFrom( + java.io.InputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return PARSER.parseDelimitedFrom(input, extensionRegistry); + } + public static com.mogujie.tt.protobuf.IMGroup.IMGroupChangeMemberReq parseFrom( + com.google.protobuf.CodedInputStream input) + throws java.io.IOException { + return PARSER.parseFrom(input); + } + public static com.mogujie.tt.protobuf.IMGroup.IMGroupChangeMemberReq parseFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return PARSER.parseFrom(input, extensionRegistry); + } + + public static Builder newBuilder() { return Builder.create(); } + public Builder newBuilderForType() { return newBuilder(); } + public static Builder newBuilder(com.mogujie.tt.protobuf.IMGroup.IMGroupChangeMemberReq prototype) { + return newBuilder().mergeFrom(prototype); + } + public Builder toBuilder() { return newBuilder(this); } + + /** + * Protobuf type {@code IM.Group.IMGroupChangeMemberReq} + */ + public static final class Builder extends + com.google.protobuf.GeneratedMessageLite.Builder< + com.mogujie.tt.protobuf.IMGroup.IMGroupChangeMemberReq, Builder> + implements + // @@protoc_insertion_point(builder_implements:IM.Group.IMGroupChangeMemberReq) + com.mogujie.tt.protobuf.IMGroup.IMGroupChangeMemberReqOrBuilder { + // Construct using com.mogujie.tt.protobuf.IMGroup.IMGroupChangeMemberReq.newBuilder() + private Builder() { + maybeForceBuilderInitialization(); + } + + private void maybeForceBuilderInitialization() { + } + private static Builder create() { + return new Builder(); + } + + public Builder clear() { + super.clear(); + userId_ = 0; + bitField0_ = (bitField0_ & ~0x00000001); + changeType_ = com.mogujie.tt.protobuf.IMBaseDefine.GroupModifyType.GROUP_MODIFY_TYPE_ADD; + bitField0_ = (bitField0_ & ~0x00000002); + groupId_ = 0; + bitField0_ = (bitField0_ & ~0x00000004); + memberIdList_ = java.util.Collections.emptyList(); + bitField0_ = (bitField0_ & ~0x00000008); + attachData_ = com.google.protobuf.ByteString.EMPTY; + bitField0_ = (bitField0_ & ~0x00000010); + return this; + } + + public Builder clone() { + return create().mergeFrom(buildPartial()); + } + + public com.mogujie.tt.protobuf.IMGroup.IMGroupChangeMemberReq getDefaultInstanceForType() { + return com.mogujie.tt.protobuf.IMGroup.IMGroupChangeMemberReq.getDefaultInstance(); + } + + public com.mogujie.tt.protobuf.IMGroup.IMGroupChangeMemberReq build() { + com.mogujie.tt.protobuf.IMGroup.IMGroupChangeMemberReq result = buildPartial(); + if (!result.isInitialized()) { + throw newUninitializedMessageException(result); + } + return result; + } + + public com.mogujie.tt.protobuf.IMGroup.IMGroupChangeMemberReq buildPartial() { + com.mogujie.tt.protobuf.IMGroup.IMGroupChangeMemberReq result = new com.mogujie.tt.protobuf.IMGroup.IMGroupChangeMemberReq(this); + int from_bitField0_ = bitField0_; + int to_bitField0_ = 0; + if (((from_bitField0_ & 0x00000001) == 0x00000001)) { + to_bitField0_ |= 0x00000001; + } + result.userId_ = userId_; + if (((from_bitField0_ & 0x00000002) == 0x00000002)) { + to_bitField0_ |= 0x00000002; + } + result.changeType_ = changeType_; + if (((from_bitField0_ & 0x00000004) == 0x00000004)) { + to_bitField0_ |= 0x00000004; + } + result.groupId_ = groupId_; + if (((bitField0_ & 0x00000008) == 0x00000008)) { + memberIdList_ = java.util.Collections.unmodifiableList(memberIdList_); + bitField0_ = (bitField0_ & ~0x00000008); + } + result.memberIdList_ = memberIdList_; + if (((from_bitField0_ & 0x00000010) == 0x00000010)) { + to_bitField0_ |= 0x00000008; + } + result.attachData_ = attachData_; + result.bitField0_ = to_bitField0_; + return result; + } + + public Builder mergeFrom(com.mogujie.tt.protobuf.IMGroup.IMGroupChangeMemberReq other) { + if (other == com.mogujie.tt.protobuf.IMGroup.IMGroupChangeMemberReq.getDefaultInstance()) return this; + if (other.hasUserId()) { + setUserId(other.getUserId()); + } + if (other.hasChangeType()) { + setChangeType(other.getChangeType()); + } + if (other.hasGroupId()) { + setGroupId(other.getGroupId()); + } + if (!other.memberIdList_.isEmpty()) { + if (memberIdList_.isEmpty()) { + memberIdList_ = other.memberIdList_; + bitField0_ = (bitField0_ & ~0x00000008); + } else { + ensureMemberIdListIsMutable(); + memberIdList_.addAll(other.memberIdList_); + } + + } + if (other.hasAttachData()) { + setAttachData(other.getAttachData()); + } + setUnknownFields( + getUnknownFields().concat(other.unknownFields)); + return this; + } + + public final boolean isInitialized() { + if (!hasUserId()) { + + return false; + } + if (!hasChangeType()) { + + return false; + } + if (!hasGroupId()) { + + return false; + } + return true; + } + + public Builder mergeFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + com.mogujie.tt.protobuf.IMGroup.IMGroupChangeMemberReq parsedMessage = null; + try { + parsedMessage = PARSER.parsePartialFrom(input, extensionRegistry); + } catch (com.google.protobuf.InvalidProtocolBufferException e) { + parsedMessage = (com.mogujie.tt.protobuf.IMGroup.IMGroupChangeMemberReq) e.getUnfinishedMessage(); + throw e; + } finally { + if (parsedMessage != null) { + mergeFrom(parsedMessage); + } + } + return this; + } + private int bitField0_; + + private int userId_ ; + /** + * required uint32 user_id = 1; + * + *
+       *cmd id:			0x0407
+       * 
+ */ + public boolean hasUserId() { + return ((bitField0_ & 0x00000001) == 0x00000001); + } + /** + * required uint32 user_id = 1; + * + *
+       *cmd id:			0x0407
+       * 
+ */ + public int getUserId() { + return userId_; + } + /** + * required uint32 user_id = 1; + * + *
+       *cmd id:			0x0407
+       * 
+ */ + public Builder setUserId(int value) { + bitField0_ |= 0x00000001; + userId_ = value; + + return this; + } + /** + * required uint32 user_id = 1; + * + *
+       *cmd id:			0x0407
+       * 
+ */ + public Builder clearUserId() { + bitField0_ = (bitField0_ & ~0x00000001); + userId_ = 0; + + return this; + } + + private com.mogujie.tt.protobuf.IMBaseDefine.GroupModifyType changeType_ = com.mogujie.tt.protobuf.IMBaseDefine.GroupModifyType.GROUP_MODIFY_TYPE_ADD; + /** + * required .IM.BaseDefine.GroupModifyType change_type = 2; + */ + public boolean hasChangeType() { + return ((bitField0_ & 0x00000002) == 0x00000002); + } + /** + * required .IM.BaseDefine.GroupModifyType change_type = 2; + */ + public com.mogujie.tt.protobuf.IMBaseDefine.GroupModifyType getChangeType() { + return changeType_; + } + /** + * required .IM.BaseDefine.GroupModifyType change_type = 2; + */ + public Builder setChangeType(com.mogujie.tt.protobuf.IMBaseDefine.GroupModifyType value) { + if (value == null) { + throw new NullPointerException(); + } + bitField0_ |= 0x00000002; + changeType_ = value; + + return this; + } + /** + * required .IM.BaseDefine.GroupModifyType change_type = 2; + */ + public Builder clearChangeType() { + bitField0_ = (bitField0_ & ~0x00000002); + changeType_ = com.mogujie.tt.protobuf.IMBaseDefine.GroupModifyType.GROUP_MODIFY_TYPE_ADD; + + return this; + } + + private int groupId_ ; + /** + * required uint32 group_id = 3; + */ + public boolean hasGroupId() { + return ((bitField0_ & 0x00000004) == 0x00000004); + } + /** + * required uint32 group_id = 3; + */ + public int getGroupId() { + return groupId_; + } + /** + * required uint32 group_id = 3; + */ + public Builder setGroupId(int value) { + bitField0_ |= 0x00000004; + groupId_ = value; + + return this; + } + /** + * required uint32 group_id = 3; + */ + public Builder clearGroupId() { + bitField0_ = (bitField0_ & ~0x00000004); + groupId_ = 0; + + return this; + } + + private java.util.List memberIdList_ = java.util.Collections.emptyList(); + private void ensureMemberIdListIsMutable() { + if (!((bitField0_ & 0x00000008) == 0x00000008)) { + memberIdList_ = new java.util.ArrayList(memberIdList_); + bitField0_ |= 0x00000008; + } + } + /** + * repeated uint32 member_id_list = 4; + */ + public java.util.List + getMemberIdListList() { + return java.util.Collections.unmodifiableList(memberIdList_); + } + /** + * repeated uint32 member_id_list = 4; + */ + public int getMemberIdListCount() { + return memberIdList_.size(); + } + /** + * repeated uint32 member_id_list = 4; + */ + public int getMemberIdList(int index) { + return memberIdList_.get(index); + } + /** + * repeated uint32 member_id_list = 4; + */ + public Builder setMemberIdList( + int index, int value) { + ensureMemberIdListIsMutable(); + memberIdList_.set(index, value); + + return this; + } + /** + * repeated uint32 member_id_list = 4; + */ + public Builder addMemberIdList(int value) { + ensureMemberIdListIsMutable(); + memberIdList_.add(value); + + return this; + } + /** + * repeated uint32 member_id_list = 4; + */ + public Builder addAllMemberIdList( + java.lang.Iterable values) { + ensureMemberIdListIsMutable(); + com.google.protobuf.AbstractMessageLite.Builder.addAll( + values, memberIdList_); + + return this; + } + /** + * repeated uint32 member_id_list = 4; + */ + public Builder clearMemberIdList() { + memberIdList_ = java.util.Collections.emptyList(); + bitField0_ = (bitField0_ & ~0x00000008); + + return this; + } + + private com.google.protobuf.ByteString attachData_ = com.google.protobuf.ByteString.EMPTY; + /** + * optional bytes attach_data = 20; + */ + public boolean hasAttachData() { + return ((bitField0_ & 0x00000010) == 0x00000010); + } + /** + * optional bytes attach_data = 20; + */ + public com.google.protobuf.ByteString getAttachData() { + return attachData_; + } + /** + * optional bytes attach_data = 20; + */ + public Builder setAttachData(com.google.protobuf.ByteString value) { + if (value == null) { + throw new NullPointerException(); + } + bitField0_ |= 0x00000010; + attachData_ = value; + + return this; + } + /** + * optional bytes attach_data = 20; + */ + public Builder clearAttachData() { + bitField0_ = (bitField0_ & ~0x00000010); + attachData_ = getDefaultInstance().getAttachData(); + + return this; + } + + // @@protoc_insertion_point(builder_scope:IM.Group.IMGroupChangeMemberReq) + } + + static { + defaultInstance = new IMGroupChangeMemberReq(true); + defaultInstance.initFields(); + } + + // @@protoc_insertion_point(class_scope:IM.Group.IMGroupChangeMemberReq) + } + + public interface IMGroupChangeMemberRspOrBuilder extends + // @@protoc_insertion_point(interface_extends:IM.Group.IMGroupChangeMemberRsp) + com.google.protobuf.MessageLiteOrBuilder { + + /** + * required uint32 user_id = 1; + * + *
+     *cmd id:			0x0408
+     * 
+ */ + boolean hasUserId(); + /** + * required uint32 user_id = 1; + * + *
+     *cmd id:			0x0408
+     * 
+ */ + int getUserId(); + + /** + * required .IM.BaseDefine.GroupModifyType change_type = 2; + */ + boolean hasChangeType(); + /** + * required .IM.BaseDefine.GroupModifyType change_type = 2; + */ + com.mogujie.tt.protobuf.IMBaseDefine.GroupModifyType getChangeType(); + + /** + * required uint32 result_code = 3; + */ + boolean hasResultCode(); + /** + * required uint32 result_code = 3; + */ + int getResultCode(); + + /** + * required uint32 group_id = 4; + */ + boolean hasGroupId(); + /** + * required uint32 group_id = 4; + */ + int getGroupId(); + + /** + * repeated uint32 cur_user_id_list = 5; + * + *
+     *现有的成员id		
+     * 
+ */ + java.util.List getCurUserIdListList(); + /** + * repeated uint32 cur_user_id_list = 5; + * + *
+     *现有的成员id		
+     * 
+ */ + int getCurUserIdListCount(); + /** + * repeated uint32 cur_user_id_list = 5; + * + *
+     *现有的成员id		
+     * 
+ */ + int getCurUserIdList(int index); + + /** + * repeated uint32 chg_user_id_list = 6; + * + *
+     *变动的成员id,add: 表示添加成功的id,   del: 表示删除的id
+     * 
+ */ + java.util.List getChgUserIdListList(); + /** + * repeated uint32 chg_user_id_list = 6; + * + *
+     *变动的成员id,add: 表示添加成功的id,   del: 表示删除的id
+     * 
+ */ + int getChgUserIdListCount(); + /** + * repeated uint32 chg_user_id_list = 6; + * + *
+     *变动的成员id,add: 表示添加成功的id,   del: 表示删除的id
+     * 
+ */ + int getChgUserIdList(int index); + + /** + * optional bytes attach_data = 20; + */ + boolean hasAttachData(); + /** + * optional bytes attach_data = 20; + */ + com.google.protobuf.ByteString getAttachData(); + } + /** + * Protobuf type {@code IM.Group.IMGroupChangeMemberRsp} + */ + public static final class IMGroupChangeMemberRsp extends + com.google.protobuf.GeneratedMessageLite implements + // @@protoc_insertion_point(message_implements:IM.Group.IMGroupChangeMemberRsp) + IMGroupChangeMemberRspOrBuilder { + // Use IMGroupChangeMemberRsp.newBuilder() to construct. + private IMGroupChangeMemberRsp(com.google.protobuf.GeneratedMessageLite.Builder builder) { + super(builder); + this.unknownFields = builder.getUnknownFields(); + } + private IMGroupChangeMemberRsp(boolean noInit) { this.unknownFields = com.google.protobuf.ByteString.EMPTY;} + + private static final IMGroupChangeMemberRsp defaultInstance; + public static IMGroupChangeMemberRsp getDefaultInstance() { + return defaultInstance; + } + + public IMGroupChangeMemberRsp getDefaultInstanceForType() { + return defaultInstance; + } + + private final com.google.protobuf.ByteString unknownFields; + private IMGroupChangeMemberRsp( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + initFields(); + int mutable_bitField0_ = 0; + com.google.protobuf.ByteString.Output unknownFieldsOutput = + com.google.protobuf.ByteString.newOutput(); + com.google.protobuf.CodedOutputStream unknownFieldsCodedOutput = + com.google.protobuf.CodedOutputStream.newInstance( + unknownFieldsOutput); + try { + boolean done = false; + while (!done) { + int tag = input.readTag(); + switch (tag) { + case 0: + done = true; + break; + default: { + if (!parseUnknownField(input, unknownFieldsCodedOutput, + extensionRegistry, tag)) { + done = true; + } + break; + } + case 8: { + bitField0_ |= 0x00000001; + userId_ = input.readUInt32(); + break; + } + case 16: { + int rawValue = input.readEnum(); + com.mogujie.tt.protobuf.IMBaseDefine.GroupModifyType value = com.mogujie.tt.protobuf.IMBaseDefine.GroupModifyType.valueOf(rawValue); + if (value == null) { + unknownFieldsCodedOutput.writeRawVarint32(tag); + unknownFieldsCodedOutput.writeRawVarint32(rawValue); + } else { + bitField0_ |= 0x00000002; + changeType_ = value; + } + break; + } + case 24: { + bitField0_ |= 0x00000004; + resultCode_ = input.readUInt32(); + break; + } + case 32: { + bitField0_ |= 0x00000008; + groupId_ = input.readUInt32(); + break; + } + case 40: { + if (!((mutable_bitField0_ & 0x00000010) == 0x00000010)) { + curUserIdList_ = new java.util.ArrayList(); + mutable_bitField0_ |= 0x00000010; + } + curUserIdList_.add(input.readUInt32()); + break; + } + case 42: { + int length = input.readRawVarint32(); + int limit = input.pushLimit(length); + if (!((mutable_bitField0_ & 0x00000010) == 0x00000010) && input.getBytesUntilLimit() > 0) { + curUserIdList_ = new java.util.ArrayList(); + mutable_bitField0_ |= 0x00000010; + } + while (input.getBytesUntilLimit() > 0) { + curUserIdList_.add(input.readUInt32()); + } + input.popLimit(limit); + break; + } + case 48: { + if (!((mutable_bitField0_ & 0x00000020) == 0x00000020)) { + chgUserIdList_ = new java.util.ArrayList(); + mutable_bitField0_ |= 0x00000020; + } + chgUserIdList_.add(input.readUInt32()); + break; + } + case 50: { + int length = input.readRawVarint32(); + int limit = input.pushLimit(length); + if (!((mutable_bitField0_ & 0x00000020) == 0x00000020) && input.getBytesUntilLimit() > 0) { + chgUserIdList_ = new java.util.ArrayList(); + mutable_bitField0_ |= 0x00000020; + } + while (input.getBytesUntilLimit() > 0) { + chgUserIdList_.add(input.readUInt32()); + } + input.popLimit(limit); + break; + } + case 162: { + bitField0_ |= 0x00000010; + attachData_ = input.readBytes(); + break; + } + } + } + } catch (com.google.protobuf.InvalidProtocolBufferException e) { + throw e.setUnfinishedMessage(this); + } catch (java.io.IOException e) { + throw new com.google.protobuf.InvalidProtocolBufferException( + e.getMessage()).setUnfinishedMessage(this); + } finally { + if (((mutable_bitField0_ & 0x00000010) == 0x00000010)) { + curUserIdList_ = java.util.Collections.unmodifiableList(curUserIdList_); + } + if (((mutable_bitField0_ & 0x00000020) == 0x00000020)) { + chgUserIdList_ = java.util.Collections.unmodifiableList(chgUserIdList_); + } + try { + unknownFieldsCodedOutput.flush(); + } catch (java.io.IOException e) { + // Should not happen + } finally { + unknownFields = unknownFieldsOutput.toByteString(); + } + makeExtensionsImmutable(); + } + } + public static com.google.protobuf.Parser PARSER = + new com.google.protobuf.AbstractParser() { + public IMGroupChangeMemberRsp parsePartialFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return new IMGroupChangeMemberRsp(input, extensionRegistry); + } + }; + + @java.lang.Override + public com.google.protobuf.Parser getParserForType() { + return PARSER; + } + + private int bitField0_; + public static final int USER_ID_FIELD_NUMBER = 1; + private int userId_; + /** + * required uint32 user_id = 1; + * + *
+     *cmd id:			0x0408
+     * 
+ */ + public boolean hasUserId() { + return ((bitField0_ & 0x00000001) == 0x00000001); + } + /** + * required uint32 user_id = 1; + * + *
+     *cmd id:			0x0408
+     * 
+ */ + public int getUserId() { + return userId_; + } + + public static final int CHANGE_TYPE_FIELD_NUMBER = 2; + private com.mogujie.tt.protobuf.IMBaseDefine.GroupModifyType changeType_; + /** + * required .IM.BaseDefine.GroupModifyType change_type = 2; + */ + public boolean hasChangeType() { + return ((bitField0_ & 0x00000002) == 0x00000002); + } + /** + * required .IM.BaseDefine.GroupModifyType change_type = 2; + */ + public com.mogujie.tt.protobuf.IMBaseDefine.GroupModifyType getChangeType() { + return changeType_; + } + + public static final int RESULT_CODE_FIELD_NUMBER = 3; + private int resultCode_; + /** + * required uint32 result_code = 3; + */ + public boolean hasResultCode() { + return ((bitField0_ & 0x00000004) == 0x00000004); + } + /** + * required uint32 result_code = 3; + */ + public int getResultCode() { + return resultCode_; + } + + public static final int GROUP_ID_FIELD_NUMBER = 4; + private int groupId_; + /** + * required uint32 group_id = 4; + */ + public boolean hasGroupId() { + return ((bitField0_ & 0x00000008) == 0x00000008); + } + /** + * required uint32 group_id = 4; + */ + public int getGroupId() { + return groupId_; + } + + public static final int CUR_USER_ID_LIST_FIELD_NUMBER = 5; + private java.util.List curUserIdList_; + /** + * repeated uint32 cur_user_id_list = 5; + * + *
+     *现有的成员id		
+     * 
+ */ + public java.util.List + getCurUserIdListList() { + return curUserIdList_; + } + /** + * repeated uint32 cur_user_id_list = 5; + * + *
+     *现有的成员id		
+     * 
+ */ + public int getCurUserIdListCount() { + return curUserIdList_.size(); + } + /** + * repeated uint32 cur_user_id_list = 5; + * + *
+     *现有的成员id		
+     * 
+ */ + public int getCurUserIdList(int index) { + return curUserIdList_.get(index); + } + + public static final int CHG_USER_ID_LIST_FIELD_NUMBER = 6; + private java.util.List chgUserIdList_; + /** + * repeated uint32 chg_user_id_list = 6; + * + *
+     *变动的成员id,add: 表示添加成功的id,   del: 表示删除的id
+     * 
+ */ + public java.util.List + getChgUserIdListList() { + return chgUserIdList_; + } + /** + * repeated uint32 chg_user_id_list = 6; + * + *
+     *变动的成员id,add: 表示添加成功的id,   del: 表示删除的id
+     * 
+ */ + public int getChgUserIdListCount() { + return chgUserIdList_.size(); + } + /** + * repeated uint32 chg_user_id_list = 6; + * + *
+     *变动的成员id,add: 表示添加成功的id,   del: 表示删除的id
+     * 
+ */ + public int getChgUserIdList(int index) { + return chgUserIdList_.get(index); + } + + public static final int ATTACH_DATA_FIELD_NUMBER = 20; + private com.google.protobuf.ByteString attachData_; + /** + * optional bytes attach_data = 20; + */ + public boolean hasAttachData() { + return ((bitField0_ & 0x00000010) == 0x00000010); + } + /** + * optional bytes attach_data = 20; + */ + public com.google.protobuf.ByteString getAttachData() { + return attachData_; + } + + private void initFields() { + userId_ = 0; + changeType_ = com.mogujie.tt.protobuf.IMBaseDefine.GroupModifyType.GROUP_MODIFY_TYPE_ADD; + resultCode_ = 0; + groupId_ = 0; + curUserIdList_ = java.util.Collections.emptyList(); + chgUserIdList_ = java.util.Collections.emptyList(); + attachData_ = com.google.protobuf.ByteString.EMPTY; + } + private byte memoizedIsInitialized = -1; + public final boolean isInitialized() { + byte isInitialized = memoizedIsInitialized; + if (isInitialized == 1) return true; + if (isInitialized == 0) return false; + + if (!hasUserId()) { + memoizedIsInitialized = 0; + return false; + } + if (!hasChangeType()) { + memoizedIsInitialized = 0; + return false; + } + if (!hasResultCode()) { + memoizedIsInitialized = 0; + return false; + } + if (!hasGroupId()) { + memoizedIsInitialized = 0; + return false; + } + memoizedIsInitialized = 1; + return true; + } + + public void writeTo(com.google.protobuf.CodedOutputStream output) + throws java.io.IOException { + getSerializedSize(); + if (((bitField0_ & 0x00000001) == 0x00000001)) { + output.writeUInt32(1, userId_); + } + if (((bitField0_ & 0x00000002) == 0x00000002)) { + output.writeEnum(2, changeType_.getNumber()); + } + if (((bitField0_ & 0x00000004) == 0x00000004)) { + output.writeUInt32(3, resultCode_); + } + if (((bitField0_ & 0x00000008) == 0x00000008)) { + output.writeUInt32(4, groupId_); + } + for (int i = 0; i < curUserIdList_.size(); i++) { + output.writeUInt32(5, curUserIdList_.get(i)); + } + for (int i = 0; i < chgUserIdList_.size(); i++) { + output.writeUInt32(6, chgUserIdList_.get(i)); + } + if (((bitField0_ & 0x00000010) == 0x00000010)) { + output.writeBytes(20, attachData_); + } + output.writeRawBytes(unknownFields); + } + + private int memoizedSerializedSize = -1; + public int getSerializedSize() { + int size = memoizedSerializedSize; + if (size != -1) return size; + + size = 0; + if (((bitField0_ & 0x00000001) == 0x00000001)) { + size += com.google.protobuf.CodedOutputStream + .computeUInt32Size(1, userId_); + } + if (((bitField0_ & 0x00000002) == 0x00000002)) { + size += com.google.protobuf.CodedOutputStream + .computeEnumSize(2, changeType_.getNumber()); + } + if (((bitField0_ & 0x00000004) == 0x00000004)) { + size += com.google.protobuf.CodedOutputStream + .computeUInt32Size(3, resultCode_); + } + if (((bitField0_ & 0x00000008) == 0x00000008)) { + size += com.google.protobuf.CodedOutputStream + .computeUInt32Size(4, groupId_); + } + { + int dataSize = 0; + for (int i = 0; i < curUserIdList_.size(); i++) { + dataSize += com.google.protobuf.CodedOutputStream + .computeUInt32SizeNoTag(curUserIdList_.get(i)); + } + size += dataSize; + size += 1 * getCurUserIdListList().size(); + } + { + int dataSize = 0; + for (int i = 0; i < chgUserIdList_.size(); i++) { + dataSize += com.google.protobuf.CodedOutputStream + .computeUInt32SizeNoTag(chgUserIdList_.get(i)); + } + size += dataSize; + size += 1 * getChgUserIdListList().size(); + } + if (((bitField0_ & 0x00000010) == 0x00000010)) { + size += com.google.protobuf.CodedOutputStream + .computeBytesSize(20, attachData_); + } + size += unknownFields.size(); + memoizedSerializedSize = size; + return size; + } + + private static final long serialVersionUID = 0L; + @java.lang.Override + protected java.lang.Object writeReplace() + throws java.io.ObjectStreamException { + return super.writeReplace(); + } + + public static com.mogujie.tt.protobuf.IMGroup.IMGroupChangeMemberRsp parseFrom( + com.google.protobuf.ByteString data) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data); + } + public static com.mogujie.tt.protobuf.IMGroup.IMGroupChangeMemberRsp parseFrom( + com.google.protobuf.ByteString data, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data, extensionRegistry); + } + public static com.mogujie.tt.protobuf.IMGroup.IMGroupChangeMemberRsp parseFrom(byte[] data) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data); + } + public static com.mogujie.tt.protobuf.IMGroup.IMGroupChangeMemberRsp parseFrom( + byte[] data, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data, extensionRegistry); + } + public static com.mogujie.tt.protobuf.IMGroup.IMGroupChangeMemberRsp parseFrom(java.io.InputStream input) + throws java.io.IOException { + return PARSER.parseFrom(input); + } + public static com.mogujie.tt.protobuf.IMGroup.IMGroupChangeMemberRsp parseFrom( + java.io.InputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return PARSER.parseFrom(input, extensionRegistry); + } + public static com.mogujie.tt.protobuf.IMGroup.IMGroupChangeMemberRsp parseDelimitedFrom(java.io.InputStream input) + throws java.io.IOException { + return PARSER.parseDelimitedFrom(input); + } + public static com.mogujie.tt.protobuf.IMGroup.IMGroupChangeMemberRsp parseDelimitedFrom( + java.io.InputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return PARSER.parseDelimitedFrom(input, extensionRegistry); + } + public static com.mogujie.tt.protobuf.IMGroup.IMGroupChangeMemberRsp parseFrom( + com.google.protobuf.CodedInputStream input) + throws java.io.IOException { + return PARSER.parseFrom(input); + } + public static com.mogujie.tt.protobuf.IMGroup.IMGroupChangeMemberRsp parseFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return PARSER.parseFrom(input, extensionRegistry); + } + + public static Builder newBuilder() { return Builder.create(); } + public Builder newBuilderForType() { return newBuilder(); } + public static Builder newBuilder(com.mogujie.tt.protobuf.IMGroup.IMGroupChangeMemberRsp prototype) { + return newBuilder().mergeFrom(prototype); + } + public Builder toBuilder() { return newBuilder(this); } + + /** + * Protobuf type {@code IM.Group.IMGroupChangeMemberRsp} + */ + public static final class Builder extends + com.google.protobuf.GeneratedMessageLite.Builder< + com.mogujie.tt.protobuf.IMGroup.IMGroupChangeMemberRsp, Builder> + implements + // @@protoc_insertion_point(builder_implements:IM.Group.IMGroupChangeMemberRsp) + com.mogujie.tt.protobuf.IMGroup.IMGroupChangeMemberRspOrBuilder { + // Construct using com.mogujie.tt.protobuf.IMGroup.IMGroupChangeMemberRsp.newBuilder() + private Builder() { + maybeForceBuilderInitialization(); + } + + private void maybeForceBuilderInitialization() { + } + private static Builder create() { + return new Builder(); + } + + public Builder clear() { + super.clear(); + userId_ = 0; + bitField0_ = (bitField0_ & ~0x00000001); + changeType_ = com.mogujie.tt.protobuf.IMBaseDefine.GroupModifyType.GROUP_MODIFY_TYPE_ADD; + bitField0_ = (bitField0_ & ~0x00000002); + resultCode_ = 0; + bitField0_ = (bitField0_ & ~0x00000004); + groupId_ = 0; + bitField0_ = (bitField0_ & ~0x00000008); + curUserIdList_ = java.util.Collections.emptyList(); + bitField0_ = (bitField0_ & ~0x00000010); + chgUserIdList_ = java.util.Collections.emptyList(); + bitField0_ = (bitField0_ & ~0x00000020); + attachData_ = com.google.protobuf.ByteString.EMPTY; + bitField0_ = (bitField0_ & ~0x00000040); + return this; + } + + public Builder clone() { + return create().mergeFrom(buildPartial()); + } + + public com.mogujie.tt.protobuf.IMGroup.IMGroupChangeMemberRsp getDefaultInstanceForType() { + return com.mogujie.tt.protobuf.IMGroup.IMGroupChangeMemberRsp.getDefaultInstance(); + } + + public com.mogujie.tt.protobuf.IMGroup.IMGroupChangeMemberRsp build() { + com.mogujie.tt.protobuf.IMGroup.IMGroupChangeMemberRsp result = buildPartial(); + if (!result.isInitialized()) { + throw newUninitializedMessageException(result); + } + return result; + } + + public com.mogujie.tt.protobuf.IMGroup.IMGroupChangeMemberRsp buildPartial() { + com.mogujie.tt.protobuf.IMGroup.IMGroupChangeMemberRsp result = new com.mogujie.tt.protobuf.IMGroup.IMGroupChangeMemberRsp(this); + int from_bitField0_ = bitField0_; + int to_bitField0_ = 0; + if (((from_bitField0_ & 0x00000001) == 0x00000001)) { + to_bitField0_ |= 0x00000001; + } + result.userId_ = userId_; + if (((from_bitField0_ & 0x00000002) == 0x00000002)) { + to_bitField0_ |= 0x00000002; + } + result.changeType_ = changeType_; + if (((from_bitField0_ & 0x00000004) == 0x00000004)) { + to_bitField0_ |= 0x00000004; + } + result.resultCode_ = resultCode_; + if (((from_bitField0_ & 0x00000008) == 0x00000008)) { + to_bitField0_ |= 0x00000008; + } + result.groupId_ = groupId_; + if (((bitField0_ & 0x00000010) == 0x00000010)) { + curUserIdList_ = java.util.Collections.unmodifiableList(curUserIdList_); + bitField0_ = (bitField0_ & ~0x00000010); + } + result.curUserIdList_ = curUserIdList_; + if (((bitField0_ & 0x00000020) == 0x00000020)) { + chgUserIdList_ = java.util.Collections.unmodifiableList(chgUserIdList_); + bitField0_ = (bitField0_ & ~0x00000020); + } + result.chgUserIdList_ = chgUserIdList_; + if (((from_bitField0_ & 0x00000040) == 0x00000040)) { + to_bitField0_ |= 0x00000010; + } + result.attachData_ = attachData_; + result.bitField0_ = to_bitField0_; + return result; + } + + public Builder mergeFrom(com.mogujie.tt.protobuf.IMGroup.IMGroupChangeMemberRsp other) { + if (other == com.mogujie.tt.protobuf.IMGroup.IMGroupChangeMemberRsp.getDefaultInstance()) return this; + if (other.hasUserId()) { + setUserId(other.getUserId()); + } + if (other.hasChangeType()) { + setChangeType(other.getChangeType()); + } + if (other.hasResultCode()) { + setResultCode(other.getResultCode()); + } + if (other.hasGroupId()) { + setGroupId(other.getGroupId()); + } + if (!other.curUserIdList_.isEmpty()) { + if (curUserIdList_.isEmpty()) { + curUserIdList_ = other.curUserIdList_; + bitField0_ = (bitField0_ & ~0x00000010); + } else { + ensureCurUserIdListIsMutable(); + curUserIdList_.addAll(other.curUserIdList_); + } + + } + if (!other.chgUserIdList_.isEmpty()) { + if (chgUserIdList_.isEmpty()) { + chgUserIdList_ = other.chgUserIdList_; + bitField0_ = (bitField0_ & ~0x00000020); + } else { + ensureChgUserIdListIsMutable(); + chgUserIdList_.addAll(other.chgUserIdList_); + } + + } + if (other.hasAttachData()) { + setAttachData(other.getAttachData()); + } + setUnknownFields( + getUnknownFields().concat(other.unknownFields)); + return this; + } + + public final boolean isInitialized() { + if (!hasUserId()) { + + return false; + } + if (!hasChangeType()) { + + return false; + } + if (!hasResultCode()) { + + return false; + } + if (!hasGroupId()) { + + return false; + } + return true; + } + + public Builder mergeFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + com.mogujie.tt.protobuf.IMGroup.IMGroupChangeMemberRsp parsedMessage = null; + try { + parsedMessage = PARSER.parsePartialFrom(input, extensionRegistry); + } catch (com.google.protobuf.InvalidProtocolBufferException e) { + parsedMessage = (com.mogujie.tt.protobuf.IMGroup.IMGroupChangeMemberRsp) e.getUnfinishedMessage(); + throw e; + } finally { + if (parsedMessage != null) { + mergeFrom(parsedMessage); + } + } + return this; + } + private int bitField0_; + + private int userId_ ; + /** + * required uint32 user_id = 1; + * + *
+       *cmd id:			0x0408
+       * 
+ */ + public boolean hasUserId() { + return ((bitField0_ & 0x00000001) == 0x00000001); + } + /** + * required uint32 user_id = 1; + * + *
+       *cmd id:			0x0408
+       * 
+ */ + public int getUserId() { + return userId_; + } + /** + * required uint32 user_id = 1; + * + *
+       *cmd id:			0x0408
+       * 
+ */ + public Builder setUserId(int value) { + bitField0_ |= 0x00000001; + userId_ = value; + + return this; + } + /** + * required uint32 user_id = 1; + * + *
+       *cmd id:			0x0408
+       * 
+ */ + public Builder clearUserId() { + bitField0_ = (bitField0_ & ~0x00000001); + userId_ = 0; + + return this; + } + + private com.mogujie.tt.protobuf.IMBaseDefine.GroupModifyType changeType_ = com.mogujie.tt.protobuf.IMBaseDefine.GroupModifyType.GROUP_MODIFY_TYPE_ADD; + /** + * required .IM.BaseDefine.GroupModifyType change_type = 2; + */ + public boolean hasChangeType() { + return ((bitField0_ & 0x00000002) == 0x00000002); + } + /** + * required .IM.BaseDefine.GroupModifyType change_type = 2; + */ + public com.mogujie.tt.protobuf.IMBaseDefine.GroupModifyType getChangeType() { + return changeType_; + } + /** + * required .IM.BaseDefine.GroupModifyType change_type = 2; + */ + public Builder setChangeType(com.mogujie.tt.protobuf.IMBaseDefine.GroupModifyType value) { + if (value == null) { + throw new NullPointerException(); + } + bitField0_ |= 0x00000002; + changeType_ = value; + + return this; + } + /** + * required .IM.BaseDefine.GroupModifyType change_type = 2; + */ + public Builder clearChangeType() { + bitField0_ = (bitField0_ & ~0x00000002); + changeType_ = com.mogujie.tt.protobuf.IMBaseDefine.GroupModifyType.GROUP_MODIFY_TYPE_ADD; + + return this; + } + + private int resultCode_ ; + /** + * required uint32 result_code = 3; + */ + public boolean hasResultCode() { + return ((bitField0_ & 0x00000004) == 0x00000004); + } + /** + * required uint32 result_code = 3; + */ + public int getResultCode() { + return resultCode_; + } + /** + * required uint32 result_code = 3; + */ + public Builder setResultCode(int value) { + bitField0_ |= 0x00000004; + resultCode_ = value; + + return this; + } + /** + * required uint32 result_code = 3; + */ + public Builder clearResultCode() { + bitField0_ = (bitField0_ & ~0x00000004); + resultCode_ = 0; + + return this; + } + + private int groupId_ ; + /** + * required uint32 group_id = 4; + */ + public boolean hasGroupId() { + return ((bitField0_ & 0x00000008) == 0x00000008); + } + /** + * required uint32 group_id = 4; + */ + public int getGroupId() { + return groupId_; + } + /** + * required uint32 group_id = 4; + */ + public Builder setGroupId(int value) { + bitField0_ |= 0x00000008; + groupId_ = value; + + return this; + } + /** + * required uint32 group_id = 4; + */ + public Builder clearGroupId() { + bitField0_ = (bitField0_ & ~0x00000008); + groupId_ = 0; + + return this; + } + + private java.util.List curUserIdList_ = java.util.Collections.emptyList(); + private void ensureCurUserIdListIsMutable() { + if (!((bitField0_ & 0x00000010) == 0x00000010)) { + curUserIdList_ = new java.util.ArrayList(curUserIdList_); + bitField0_ |= 0x00000010; + } + } + /** + * repeated uint32 cur_user_id_list = 5; + * + *
+       *现有的成员id		
+       * 
+ */ + public java.util.List + getCurUserIdListList() { + return java.util.Collections.unmodifiableList(curUserIdList_); + } + /** + * repeated uint32 cur_user_id_list = 5; + * + *
+       *现有的成员id		
+       * 
+ */ + public int getCurUserIdListCount() { + return curUserIdList_.size(); + } + /** + * repeated uint32 cur_user_id_list = 5; + * + *
+       *现有的成员id		
+       * 
+ */ + public int getCurUserIdList(int index) { + return curUserIdList_.get(index); + } + /** + * repeated uint32 cur_user_id_list = 5; + * + *
+       *现有的成员id		
+       * 
+ */ + public Builder setCurUserIdList( + int index, int value) { + ensureCurUserIdListIsMutable(); + curUserIdList_.set(index, value); + + return this; + } + /** + * repeated uint32 cur_user_id_list = 5; + * + *
+       *现有的成员id		
+       * 
+ */ + public Builder addCurUserIdList(int value) { + ensureCurUserIdListIsMutable(); + curUserIdList_.add(value); + + return this; + } + /** + * repeated uint32 cur_user_id_list = 5; + * + *
+       *现有的成员id		
+       * 
+ */ + public Builder addAllCurUserIdList( + java.lang.Iterable values) { + ensureCurUserIdListIsMutable(); + com.google.protobuf.AbstractMessageLite.Builder.addAll( + values, curUserIdList_); + + return this; + } + /** + * repeated uint32 cur_user_id_list = 5; + * + *
+       *现有的成员id		
+       * 
+ */ + public Builder clearCurUserIdList() { + curUserIdList_ = java.util.Collections.emptyList(); + bitField0_ = (bitField0_ & ~0x00000010); + + return this; + } + + private java.util.List chgUserIdList_ = java.util.Collections.emptyList(); + private void ensureChgUserIdListIsMutable() { + if (!((bitField0_ & 0x00000020) == 0x00000020)) { + chgUserIdList_ = new java.util.ArrayList(chgUserIdList_); + bitField0_ |= 0x00000020; + } + } + /** + * repeated uint32 chg_user_id_list = 6; + * + *
+       *变动的成员id,add: 表示添加成功的id,   del: 表示删除的id
+       * 
+ */ + public java.util.List + getChgUserIdListList() { + return java.util.Collections.unmodifiableList(chgUserIdList_); + } + /** + * repeated uint32 chg_user_id_list = 6; + * + *
+       *变动的成员id,add: 表示添加成功的id,   del: 表示删除的id
+       * 
+ */ + public int getChgUserIdListCount() { + return chgUserIdList_.size(); + } + /** + * repeated uint32 chg_user_id_list = 6; + * + *
+       *变动的成员id,add: 表示添加成功的id,   del: 表示删除的id
+       * 
+ */ + public int getChgUserIdList(int index) { + return chgUserIdList_.get(index); + } + /** + * repeated uint32 chg_user_id_list = 6; + * + *
+       *变动的成员id,add: 表示添加成功的id,   del: 表示删除的id
+       * 
+ */ + public Builder setChgUserIdList( + int index, int value) { + ensureChgUserIdListIsMutable(); + chgUserIdList_.set(index, value); + + return this; + } + /** + * repeated uint32 chg_user_id_list = 6; + * + *
+       *变动的成员id,add: 表示添加成功的id,   del: 表示删除的id
+       * 
+ */ + public Builder addChgUserIdList(int value) { + ensureChgUserIdListIsMutable(); + chgUserIdList_.add(value); + + return this; + } + /** + * repeated uint32 chg_user_id_list = 6; + * + *
+       *变动的成员id,add: 表示添加成功的id,   del: 表示删除的id
+       * 
+ */ + public Builder addAllChgUserIdList( + java.lang.Iterable values) { + ensureChgUserIdListIsMutable(); + com.google.protobuf.AbstractMessageLite.Builder.addAll( + values, chgUserIdList_); + + return this; + } + /** + * repeated uint32 chg_user_id_list = 6; + * + *
+       *变动的成员id,add: 表示添加成功的id,   del: 表示删除的id
+       * 
+ */ + public Builder clearChgUserIdList() { + chgUserIdList_ = java.util.Collections.emptyList(); + bitField0_ = (bitField0_ & ~0x00000020); + + return this; + } + + private com.google.protobuf.ByteString attachData_ = com.google.protobuf.ByteString.EMPTY; + /** + * optional bytes attach_data = 20; + */ + public boolean hasAttachData() { + return ((bitField0_ & 0x00000040) == 0x00000040); + } + /** + * optional bytes attach_data = 20; + */ + public com.google.protobuf.ByteString getAttachData() { + return attachData_; + } + /** + * optional bytes attach_data = 20; + */ + public Builder setAttachData(com.google.protobuf.ByteString value) { + if (value == null) { + throw new NullPointerException(); + } + bitField0_ |= 0x00000040; + attachData_ = value; + + return this; + } + /** + * optional bytes attach_data = 20; + */ + public Builder clearAttachData() { + bitField0_ = (bitField0_ & ~0x00000040); + attachData_ = getDefaultInstance().getAttachData(); + + return this; + } + + // @@protoc_insertion_point(builder_scope:IM.Group.IMGroupChangeMemberRsp) + } + + static { + defaultInstance = new IMGroupChangeMemberRsp(true); + defaultInstance.initFields(); + } + + // @@protoc_insertion_point(class_scope:IM.Group.IMGroupChangeMemberRsp) + } + + public interface IMGroupShieldReqOrBuilder extends + // @@protoc_insertion_point(interface_extends:IM.Group.IMGroupShieldReq) + com.google.protobuf.MessageLiteOrBuilder { + + /** + * required uint32 user_id = 1; + * + *
+     *cmd id:			0x0409
+     * 
+ */ + boolean hasUserId(); + /** + * required uint32 user_id = 1; + * + *
+     *cmd id:			0x0409
+     * 
+ */ + int getUserId(); + + /** + * required uint32 group_id = 2; + */ + boolean hasGroupId(); + /** + * required uint32 group_id = 2; + */ + int getGroupId(); + + /** + * required uint32 shield_status = 3; + */ + boolean hasShieldStatus(); + /** + * required uint32 shield_status = 3; + */ + int getShieldStatus(); + + /** + * optional bytes attach_data = 20; + */ + boolean hasAttachData(); + /** + * optional bytes attach_data = 20; + */ + com.google.protobuf.ByteString getAttachData(); + } + /** + * Protobuf type {@code IM.Group.IMGroupShieldReq} + */ + public static final class IMGroupShieldReq extends + com.google.protobuf.GeneratedMessageLite implements + // @@protoc_insertion_point(message_implements:IM.Group.IMGroupShieldReq) + IMGroupShieldReqOrBuilder { + // Use IMGroupShieldReq.newBuilder() to construct. + private IMGroupShieldReq(com.google.protobuf.GeneratedMessageLite.Builder builder) { + super(builder); + this.unknownFields = builder.getUnknownFields(); + } + private IMGroupShieldReq(boolean noInit) { this.unknownFields = com.google.protobuf.ByteString.EMPTY;} + + private static final IMGroupShieldReq defaultInstance; + public static IMGroupShieldReq getDefaultInstance() { + return defaultInstance; + } + + public IMGroupShieldReq getDefaultInstanceForType() { + return defaultInstance; + } + + private final com.google.protobuf.ByteString unknownFields; + private IMGroupShieldReq( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + initFields(); + int mutable_bitField0_ = 0; + com.google.protobuf.ByteString.Output unknownFieldsOutput = + com.google.protobuf.ByteString.newOutput(); + com.google.protobuf.CodedOutputStream unknownFieldsCodedOutput = + com.google.protobuf.CodedOutputStream.newInstance( + unknownFieldsOutput); + try { + boolean done = false; + while (!done) { + int tag = input.readTag(); + switch (tag) { + case 0: + done = true; + break; + default: { + if (!parseUnknownField(input, unknownFieldsCodedOutput, + extensionRegistry, tag)) { + done = true; + } + break; + } + case 8: { + bitField0_ |= 0x00000001; + userId_ = input.readUInt32(); + break; + } + case 16: { + bitField0_ |= 0x00000002; + groupId_ = input.readUInt32(); + break; + } + case 24: { + bitField0_ |= 0x00000004; + shieldStatus_ = input.readUInt32(); + break; + } + case 162: { + bitField0_ |= 0x00000008; + attachData_ = input.readBytes(); + break; + } + } + } + } catch (com.google.protobuf.InvalidProtocolBufferException e) { + throw e.setUnfinishedMessage(this); + } catch (java.io.IOException e) { + throw new com.google.protobuf.InvalidProtocolBufferException( + e.getMessage()).setUnfinishedMessage(this); + } finally { + try { + unknownFieldsCodedOutput.flush(); + } catch (java.io.IOException e) { + // Should not happen + } finally { + unknownFields = unknownFieldsOutput.toByteString(); + } + makeExtensionsImmutable(); + } + } + public static com.google.protobuf.Parser PARSER = + new com.google.protobuf.AbstractParser() { + public IMGroupShieldReq parsePartialFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return new IMGroupShieldReq(input, extensionRegistry); + } + }; + + @java.lang.Override + public com.google.protobuf.Parser getParserForType() { + return PARSER; + } + + private int bitField0_; + public static final int USER_ID_FIELD_NUMBER = 1; + private int userId_; + /** + * required uint32 user_id = 1; + * + *
+     *cmd id:			0x0409
+     * 
+ */ + public boolean hasUserId() { + return ((bitField0_ & 0x00000001) == 0x00000001); + } + /** + * required uint32 user_id = 1; + * + *
+     *cmd id:			0x0409
+     * 
+ */ + public int getUserId() { + return userId_; + } + + public static final int GROUP_ID_FIELD_NUMBER = 2; + private int groupId_; + /** + * required uint32 group_id = 2; + */ + public boolean hasGroupId() { + return ((bitField0_ & 0x00000002) == 0x00000002); + } + /** + * required uint32 group_id = 2; + */ + public int getGroupId() { + return groupId_; + } + + public static final int SHIELD_STATUS_FIELD_NUMBER = 3; + private int shieldStatus_; + /** + * required uint32 shield_status = 3; + */ + public boolean hasShieldStatus() { + return ((bitField0_ & 0x00000004) == 0x00000004); + } + /** + * required uint32 shield_status = 3; + */ + public int getShieldStatus() { + return shieldStatus_; + } + + public static final int ATTACH_DATA_FIELD_NUMBER = 20; + private com.google.protobuf.ByteString attachData_; + /** + * optional bytes attach_data = 20; + */ + public boolean hasAttachData() { + return ((bitField0_ & 0x00000008) == 0x00000008); + } + /** + * optional bytes attach_data = 20; + */ + public com.google.protobuf.ByteString getAttachData() { + return attachData_; + } + + private void initFields() { + userId_ = 0; + groupId_ = 0; + shieldStatus_ = 0; + attachData_ = com.google.protobuf.ByteString.EMPTY; + } + private byte memoizedIsInitialized = -1; + public final boolean isInitialized() { + byte isInitialized = memoizedIsInitialized; + if (isInitialized == 1) return true; + if (isInitialized == 0) return false; + + if (!hasUserId()) { + memoizedIsInitialized = 0; + return false; + } + if (!hasGroupId()) { + memoizedIsInitialized = 0; + return false; + } + if (!hasShieldStatus()) { + memoizedIsInitialized = 0; + return false; + } + memoizedIsInitialized = 1; + return true; + } + + public void writeTo(com.google.protobuf.CodedOutputStream output) + throws java.io.IOException { + getSerializedSize(); + if (((bitField0_ & 0x00000001) == 0x00000001)) { + output.writeUInt32(1, userId_); + } + if (((bitField0_ & 0x00000002) == 0x00000002)) { + output.writeUInt32(2, groupId_); + } + if (((bitField0_ & 0x00000004) == 0x00000004)) { + output.writeUInt32(3, shieldStatus_); + } + if (((bitField0_ & 0x00000008) == 0x00000008)) { + output.writeBytes(20, attachData_); + } + output.writeRawBytes(unknownFields); + } + + private int memoizedSerializedSize = -1; + public int getSerializedSize() { + int size = memoizedSerializedSize; + if (size != -1) return size; + + size = 0; + if (((bitField0_ & 0x00000001) == 0x00000001)) { + size += com.google.protobuf.CodedOutputStream + .computeUInt32Size(1, userId_); + } + if (((bitField0_ & 0x00000002) == 0x00000002)) { + size += com.google.protobuf.CodedOutputStream + .computeUInt32Size(2, groupId_); + } + if (((bitField0_ & 0x00000004) == 0x00000004)) { + size += com.google.protobuf.CodedOutputStream + .computeUInt32Size(3, shieldStatus_); + } + if (((bitField0_ & 0x00000008) == 0x00000008)) { + size += com.google.protobuf.CodedOutputStream + .computeBytesSize(20, attachData_); + } + size += unknownFields.size(); + memoizedSerializedSize = size; + return size; + } + + private static final long serialVersionUID = 0L; + @java.lang.Override + protected java.lang.Object writeReplace() + throws java.io.ObjectStreamException { + return super.writeReplace(); + } + + public static com.mogujie.tt.protobuf.IMGroup.IMGroupShieldReq parseFrom( + com.google.protobuf.ByteString data) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data); + } + public static com.mogujie.tt.protobuf.IMGroup.IMGroupShieldReq parseFrom( + com.google.protobuf.ByteString data, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data, extensionRegistry); + } + public static com.mogujie.tt.protobuf.IMGroup.IMGroupShieldReq parseFrom(byte[] data) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data); + } + public static com.mogujie.tt.protobuf.IMGroup.IMGroupShieldReq parseFrom( + byte[] data, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data, extensionRegistry); + } + public static com.mogujie.tt.protobuf.IMGroup.IMGroupShieldReq parseFrom(java.io.InputStream input) + throws java.io.IOException { + return PARSER.parseFrom(input); + } + public static com.mogujie.tt.protobuf.IMGroup.IMGroupShieldReq parseFrom( + java.io.InputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return PARSER.parseFrom(input, extensionRegistry); + } + public static com.mogujie.tt.protobuf.IMGroup.IMGroupShieldReq parseDelimitedFrom(java.io.InputStream input) + throws java.io.IOException { + return PARSER.parseDelimitedFrom(input); + } + public static com.mogujie.tt.protobuf.IMGroup.IMGroupShieldReq parseDelimitedFrom( + java.io.InputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return PARSER.parseDelimitedFrom(input, extensionRegistry); + } + public static com.mogujie.tt.protobuf.IMGroup.IMGroupShieldReq parseFrom( + com.google.protobuf.CodedInputStream input) + throws java.io.IOException { + return PARSER.parseFrom(input); + } + public static com.mogujie.tt.protobuf.IMGroup.IMGroupShieldReq parseFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return PARSER.parseFrom(input, extensionRegistry); + } + + public static Builder newBuilder() { return Builder.create(); } + public Builder newBuilderForType() { return newBuilder(); } + public static Builder newBuilder(com.mogujie.tt.protobuf.IMGroup.IMGroupShieldReq prototype) { + return newBuilder().mergeFrom(prototype); + } + public Builder toBuilder() { return newBuilder(this); } + + /** + * Protobuf type {@code IM.Group.IMGroupShieldReq} + */ + public static final class Builder extends + com.google.protobuf.GeneratedMessageLite.Builder< + com.mogujie.tt.protobuf.IMGroup.IMGroupShieldReq, Builder> + implements + // @@protoc_insertion_point(builder_implements:IM.Group.IMGroupShieldReq) + com.mogujie.tt.protobuf.IMGroup.IMGroupShieldReqOrBuilder { + // Construct using com.mogujie.tt.protobuf.IMGroup.IMGroupShieldReq.newBuilder() + private Builder() { + maybeForceBuilderInitialization(); + } + + private void maybeForceBuilderInitialization() { + } + private static Builder create() { + return new Builder(); + } + + public Builder clear() { + super.clear(); + userId_ = 0; + bitField0_ = (bitField0_ & ~0x00000001); + groupId_ = 0; + bitField0_ = (bitField0_ & ~0x00000002); + shieldStatus_ = 0; + bitField0_ = (bitField0_ & ~0x00000004); + attachData_ = com.google.protobuf.ByteString.EMPTY; + bitField0_ = (bitField0_ & ~0x00000008); + return this; + } + + public Builder clone() { + return create().mergeFrom(buildPartial()); + } + + public com.mogujie.tt.protobuf.IMGroup.IMGroupShieldReq getDefaultInstanceForType() { + return com.mogujie.tt.protobuf.IMGroup.IMGroupShieldReq.getDefaultInstance(); + } + + public com.mogujie.tt.protobuf.IMGroup.IMGroupShieldReq build() { + com.mogujie.tt.protobuf.IMGroup.IMGroupShieldReq result = buildPartial(); + if (!result.isInitialized()) { + throw newUninitializedMessageException(result); + } + return result; + } + + public com.mogujie.tt.protobuf.IMGroup.IMGroupShieldReq buildPartial() { + com.mogujie.tt.protobuf.IMGroup.IMGroupShieldReq result = new com.mogujie.tt.protobuf.IMGroup.IMGroupShieldReq(this); + int from_bitField0_ = bitField0_; + int to_bitField0_ = 0; + if (((from_bitField0_ & 0x00000001) == 0x00000001)) { + to_bitField0_ |= 0x00000001; + } + result.userId_ = userId_; + if (((from_bitField0_ & 0x00000002) == 0x00000002)) { + to_bitField0_ |= 0x00000002; + } + result.groupId_ = groupId_; + if (((from_bitField0_ & 0x00000004) == 0x00000004)) { + to_bitField0_ |= 0x00000004; + } + result.shieldStatus_ = shieldStatus_; + if (((from_bitField0_ & 0x00000008) == 0x00000008)) { + to_bitField0_ |= 0x00000008; + } + result.attachData_ = attachData_; + result.bitField0_ = to_bitField0_; + return result; + } + + public Builder mergeFrom(com.mogujie.tt.protobuf.IMGroup.IMGroupShieldReq other) { + if (other == com.mogujie.tt.protobuf.IMGroup.IMGroupShieldReq.getDefaultInstance()) return this; + if (other.hasUserId()) { + setUserId(other.getUserId()); + } + if (other.hasGroupId()) { + setGroupId(other.getGroupId()); + } + if (other.hasShieldStatus()) { + setShieldStatus(other.getShieldStatus()); + } + if (other.hasAttachData()) { + setAttachData(other.getAttachData()); + } + setUnknownFields( + getUnknownFields().concat(other.unknownFields)); + return this; + } + + public final boolean isInitialized() { + if (!hasUserId()) { + + return false; + } + if (!hasGroupId()) { + + return false; + } + if (!hasShieldStatus()) { + + return false; + } + return true; + } + + public Builder mergeFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + com.mogujie.tt.protobuf.IMGroup.IMGroupShieldReq parsedMessage = null; + try { + parsedMessage = PARSER.parsePartialFrom(input, extensionRegistry); + } catch (com.google.protobuf.InvalidProtocolBufferException e) { + parsedMessage = (com.mogujie.tt.protobuf.IMGroup.IMGroupShieldReq) e.getUnfinishedMessage(); + throw e; + } finally { + if (parsedMessage != null) { + mergeFrom(parsedMessage); + } + } + return this; + } + private int bitField0_; + + private int userId_ ; + /** + * required uint32 user_id = 1; + * + *
+       *cmd id:			0x0409
+       * 
+ */ + public boolean hasUserId() { + return ((bitField0_ & 0x00000001) == 0x00000001); + } + /** + * required uint32 user_id = 1; + * + *
+       *cmd id:			0x0409
+       * 
+ */ + public int getUserId() { + return userId_; + } + /** + * required uint32 user_id = 1; + * + *
+       *cmd id:			0x0409
+       * 
+ */ + public Builder setUserId(int value) { + bitField0_ |= 0x00000001; + userId_ = value; + + return this; + } + /** + * required uint32 user_id = 1; + * + *
+       *cmd id:			0x0409
+       * 
+ */ + public Builder clearUserId() { + bitField0_ = (bitField0_ & ~0x00000001); + userId_ = 0; + + return this; + } + + private int groupId_ ; + /** + * required uint32 group_id = 2; + */ + public boolean hasGroupId() { + return ((bitField0_ & 0x00000002) == 0x00000002); + } + /** + * required uint32 group_id = 2; + */ + public int getGroupId() { + return groupId_; + } + /** + * required uint32 group_id = 2; + */ + public Builder setGroupId(int value) { + bitField0_ |= 0x00000002; + groupId_ = value; + + return this; + } + /** + * required uint32 group_id = 2; + */ + public Builder clearGroupId() { + bitField0_ = (bitField0_ & ~0x00000002); + groupId_ = 0; + + return this; + } + + private int shieldStatus_ ; + /** + * required uint32 shield_status = 3; + */ + public boolean hasShieldStatus() { + return ((bitField0_ & 0x00000004) == 0x00000004); + } + /** + * required uint32 shield_status = 3; + */ + public int getShieldStatus() { + return shieldStatus_; + } + /** + * required uint32 shield_status = 3; + */ + public Builder setShieldStatus(int value) { + bitField0_ |= 0x00000004; + shieldStatus_ = value; + + return this; + } + /** + * required uint32 shield_status = 3; + */ + public Builder clearShieldStatus() { + bitField0_ = (bitField0_ & ~0x00000004); + shieldStatus_ = 0; + + return this; + } + + private com.google.protobuf.ByteString attachData_ = com.google.protobuf.ByteString.EMPTY; + /** + * optional bytes attach_data = 20; + */ + public boolean hasAttachData() { + return ((bitField0_ & 0x00000008) == 0x00000008); + } + /** + * optional bytes attach_data = 20; + */ + public com.google.protobuf.ByteString getAttachData() { + return attachData_; + } + /** + * optional bytes attach_data = 20; + */ + public Builder setAttachData(com.google.protobuf.ByteString value) { + if (value == null) { + throw new NullPointerException(); + } + bitField0_ |= 0x00000008; + attachData_ = value; + + return this; + } + /** + * optional bytes attach_data = 20; + */ + public Builder clearAttachData() { + bitField0_ = (bitField0_ & ~0x00000008); + attachData_ = getDefaultInstance().getAttachData(); + + return this; + } + + // @@protoc_insertion_point(builder_scope:IM.Group.IMGroupShieldReq) + } + + static { + defaultInstance = new IMGroupShieldReq(true); + defaultInstance.initFields(); + } + + // @@protoc_insertion_point(class_scope:IM.Group.IMGroupShieldReq) + } + + public interface IMGroupShieldRspOrBuilder extends + // @@protoc_insertion_point(interface_extends:IM.Group.IMGroupShieldRsp) + com.google.protobuf.MessageLiteOrBuilder { + + /** + * required uint32 user_id = 1; + * + *
+     *cmd id:			0x040a
+     * 
+ */ + boolean hasUserId(); + /** + * required uint32 user_id = 1; + * + *
+     *cmd id:			0x040a
+     * 
+ */ + int getUserId(); + + /** + * required uint32 group_id = 2; + */ + boolean hasGroupId(); + /** + * required uint32 group_id = 2; + */ + int getGroupId(); + + /** + * required uint32 result_code = 3; + * + *
+     *0:successed 1:failed
+     * 
+ */ + boolean hasResultCode(); + /** + * required uint32 result_code = 3; + * + *
+     *0:successed 1:failed
+     * 
+ */ + int getResultCode(); + + /** + * optional bytes attach_data = 20; + */ + boolean hasAttachData(); + /** + * optional bytes attach_data = 20; + */ + com.google.protobuf.ByteString getAttachData(); + } + /** + * Protobuf type {@code IM.Group.IMGroupShieldRsp} + */ + public static final class IMGroupShieldRsp extends + com.google.protobuf.GeneratedMessageLite implements + // @@protoc_insertion_point(message_implements:IM.Group.IMGroupShieldRsp) + IMGroupShieldRspOrBuilder { + // Use IMGroupShieldRsp.newBuilder() to construct. + private IMGroupShieldRsp(com.google.protobuf.GeneratedMessageLite.Builder builder) { + super(builder); + this.unknownFields = builder.getUnknownFields(); + } + private IMGroupShieldRsp(boolean noInit) { this.unknownFields = com.google.protobuf.ByteString.EMPTY;} + + private static final IMGroupShieldRsp defaultInstance; + public static IMGroupShieldRsp getDefaultInstance() { + return defaultInstance; + } + + public IMGroupShieldRsp getDefaultInstanceForType() { + return defaultInstance; + } + + private final com.google.protobuf.ByteString unknownFields; + private IMGroupShieldRsp( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + initFields(); + int mutable_bitField0_ = 0; + com.google.protobuf.ByteString.Output unknownFieldsOutput = + com.google.protobuf.ByteString.newOutput(); + com.google.protobuf.CodedOutputStream unknownFieldsCodedOutput = + com.google.protobuf.CodedOutputStream.newInstance( + unknownFieldsOutput); + try { + boolean done = false; + while (!done) { + int tag = input.readTag(); + switch (tag) { + case 0: + done = true; + break; + default: { + if (!parseUnknownField(input, unknownFieldsCodedOutput, + extensionRegistry, tag)) { + done = true; + } + break; + } + case 8: { + bitField0_ |= 0x00000001; + userId_ = input.readUInt32(); + break; + } + case 16: { + bitField0_ |= 0x00000002; + groupId_ = input.readUInt32(); + break; + } + case 24: { + bitField0_ |= 0x00000004; + resultCode_ = input.readUInt32(); + break; + } + case 162: { + bitField0_ |= 0x00000008; + attachData_ = input.readBytes(); + break; + } + } + } + } catch (com.google.protobuf.InvalidProtocolBufferException e) { + throw e.setUnfinishedMessage(this); + } catch (java.io.IOException e) { + throw new com.google.protobuf.InvalidProtocolBufferException( + e.getMessage()).setUnfinishedMessage(this); + } finally { + try { + unknownFieldsCodedOutput.flush(); + } catch (java.io.IOException e) { + // Should not happen + } finally { + unknownFields = unknownFieldsOutput.toByteString(); + } + makeExtensionsImmutable(); + } + } + public static com.google.protobuf.Parser PARSER = + new com.google.protobuf.AbstractParser() { + public IMGroupShieldRsp parsePartialFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return new IMGroupShieldRsp(input, extensionRegistry); + } + }; + + @java.lang.Override + public com.google.protobuf.Parser getParserForType() { + return PARSER; + } + + private int bitField0_; + public static final int USER_ID_FIELD_NUMBER = 1; + private int userId_; + /** + * required uint32 user_id = 1; + * + *
+     *cmd id:			0x040a
+     * 
+ */ + public boolean hasUserId() { + return ((bitField0_ & 0x00000001) == 0x00000001); + } + /** + * required uint32 user_id = 1; + * + *
+     *cmd id:			0x040a
+     * 
+ */ + public int getUserId() { + return userId_; + } + + public static final int GROUP_ID_FIELD_NUMBER = 2; + private int groupId_; + /** + * required uint32 group_id = 2; + */ + public boolean hasGroupId() { + return ((bitField0_ & 0x00000002) == 0x00000002); + } + /** + * required uint32 group_id = 2; + */ + public int getGroupId() { + return groupId_; + } + + public static final int RESULT_CODE_FIELD_NUMBER = 3; + private int resultCode_; + /** + * required uint32 result_code = 3; + * + *
+     *0:successed 1:failed
+     * 
+ */ + public boolean hasResultCode() { + return ((bitField0_ & 0x00000004) == 0x00000004); + } + /** + * required uint32 result_code = 3; + * + *
+     *0:successed 1:failed
+     * 
+ */ + public int getResultCode() { + return resultCode_; + } + + public static final int ATTACH_DATA_FIELD_NUMBER = 20; + private com.google.protobuf.ByteString attachData_; + /** + * optional bytes attach_data = 20; + */ + public boolean hasAttachData() { + return ((bitField0_ & 0x00000008) == 0x00000008); + } + /** + * optional bytes attach_data = 20; + */ + public com.google.protobuf.ByteString getAttachData() { + return attachData_; + } + + private void initFields() { + userId_ = 0; + groupId_ = 0; + resultCode_ = 0; + attachData_ = com.google.protobuf.ByteString.EMPTY; + } + private byte memoizedIsInitialized = -1; + public final boolean isInitialized() { + byte isInitialized = memoizedIsInitialized; + if (isInitialized == 1) return true; + if (isInitialized == 0) return false; + + if (!hasUserId()) { + memoizedIsInitialized = 0; + return false; + } + if (!hasGroupId()) { + memoizedIsInitialized = 0; + return false; + } + if (!hasResultCode()) { + memoizedIsInitialized = 0; + return false; + } + memoizedIsInitialized = 1; + return true; + } + + public void writeTo(com.google.protobuf.CodedOutputStream output) + throws java.io.IOException { + getSerializedSize(); + if (((bitField0_ & 0x00000001) == 0x00000001)) { + output.writeUInt32(1, userId_); + } + if (((bitField0_ & 0x00000002) == 0x00000002)) { + output.writeUInt32(2, groupId_); + } + if (((bitField0_ & 0x00000004) == 0x00000004)) { + output.writeUInt32(3, resultCode_); + } + if (((bitField0_ & 0x00000008) == 0x00000008)) { + output.writeBytes(20, attachData_); + } + output.writeRawBytes(unknownFields); + } + + private int memoizedSerializedSize = -1; + public int getSerializedSize() { + int size = memoizedSerializedSize; + if (size != -1) return size; + + size = 0; + if (((bitField0_ & 0x00000001) == 0x00000001)) { + size += com.google.protobuf.CodedOutputStream + .computeUInt32Size(1, userId_); + } + if (((bitField0_ & 0x00000002) == 0x00000002)) { + size += com.google.protobuf.CodedOutputStream + .computeUInt32Size(2, groupId_); + } + if (((bitField0_ & 0x00000004) == 0x00000004)) { + size += com.google.protobuf.CodedOutputStream + .computeUInt32Size(3, resultCode_); + } + if (((bitField0_ & 0x00000008) == 0x00000008)) { + size += com.google.protobuf.CodedOutputStream + .computeBytesSize(20, attachData_); + } + size += unknownFields.size(); + memoizedSerializedSize = size; + return size; + } + + private static final long serialVersionUID = 0L; + @java.lang.Override + protected java.lang.Object writeReplace() + throws java.io.ObjectStreamException { + return super.writeReplace(); + } + + public static com.mogujie.tt.protobuf.IMGroup.IMGroupShieldRsp parseFrom( + com.google.protobuf.ByteString data) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data); + } + public static com.mogujie.tt.protobuf.IMGroup.IMGroupShieldRsp parseFrom( + com.google.protobuf.ByteString data, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data, extensionRegistry); + } + public static com.mogujie.tt.protobuf.IMGroup.IMGroupShieldRsp parseFrom(byte[] data) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data); + } + public static com.mogujie.tt.protobuf.IMGroup.IMGroupShieldRsp parseFrom( + byte[] data, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data, extensionRegistry); + } + public static com.mogujie.tt.protobuf.IMGroup.IMGroupShieldRsp parseFrom(java.io.InputStream input) + throws java.io.IOException { + return PARSER.parseFrom(input); + } + public static com.mogujie.tt.protobuf.IMGroup.IMGroupShieldRsp parseFrom( + java.io.InputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return PARSER.parseFrom(input, extensionRegistry); + } + public static com.mogujie.tt.protobuf.IMGroup.IMGroupShieldRsp parseDelimitedFrom(java.io.InputStream input) + throws java.io.IOException { + return PARSER.parseDelimitedFrom(input); + } + public static com.mogujie.tt.protobuf.IMGroup.IMGroupShieldRsp parseDelimitedFrom( + java.io.InputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return PARSER.parseDelimitedFrom(input, extensionRegistry); + } + public static com.mogujie.tt.protobuf.IMGroup.IMGroupShieldRsp parseFrom( + com.google.protobuf.CodedInputStream input) + throws java.io.IOException { + return PARSER.parseFrom(input); + } + public static com.mogujie.tt.protobuf.IMGroup.IMGroupShieldRsp parseFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return PARSER.parseFrom(input, extensionRegistry); + } + + public static Builder newBuilder() { return Builder.create(); } + public Builder newBuilderForType() { return newBuilder(); } + public static Builder newBuilder(com.mogujie.tt.protobuf.IMGroup.IMGroupShieldRsp prototype) { + return newBuilder().mergeFrom(prototype); + } + public Builder toBuilder() { return newBuilder(this); } + + /** + * Protobuf type {@code IM.Group.IMGroupShieldRsp} + */ + public static final class Builder extends + com.google.protobuf.GeneratedMessageLite.Builder< + com.mogujie.tt.protobuf.IMGroup.IMGroupShieldRsp, Builder> + implements + // @@protoc_insertion_point(builder_implements:IM.Group.IMGroupShieldRsp) + com.mogujie.tt.protobuf.IMGroup.IMGroupShieldRspOrBuilder { + // Construct using com.mogujie.tt.protobuf.IMGroup.IMGroupShieldRsp.newBuilder() + private Builder() { + maybeForceBuilderInitialization(); + } + + private void maybeForceBuilderInitialization() { + } + private static Builder create() { + return new Builder(); + } + + public Builder clear() { + super.clear(); + userId_ = 0; + bitField0_ = (bitField0_ & ~0x00000001); + groupId_ = 0; + bitField0_ = (bitField0_ & ~0x00000002); + resultCode_ = 0; + bitField0_ = (bitField0_ & ~0x00000004); + attachData_ = com.google.protobuf.ByteString.EMPTY; + bitField0_ = (bitField0_ & ~0x00000008); + return this; + } + + public Builder clone() { + return create().mergeFrom(buildPartial()); + } + + public com.mogujie.tt.protobuf.IMGroup.IMGroupShieldRsp getDefaultInstanceForType() { + return com.mogujie.tt.protobuf.IMGroup.IMGroupShieldRsp.getDefaultInstance(); + } + + public com.mogujie.tt.protobuf.IMGroup.IMGroupShieldRsp build() { + com.mogujie.tt.protobuf.IMGroup.IMGroupShieldRsp result = buildPartial(); + if (!result.isInitialized()) { + throw newUninitializedMessageException(result); + } + return result; + } + + public com.mogujie.tt.protobuf.IMGroup.IMGroupShieldRsp buildPartial() { + com.mogujie.tt.protobuf.IMGroup.IMGroupShieldRsp result = new com.mogujie.tt.protobuf.IMGroup.IMGroupShieldRsp(this); + int from_bitField0_ = bitField0_; + int to_bitField0_ = 0; + if (((from_bitField0_ & 0x00000001) == 0x00000001)) { + to_bitField0_ |= 0x00000001; + } + result.userId_ = userId_; + if (((from_bitField0_ & 0x00000002) == 0x00000002)) { + to_bitField0_ |= 0x00000002; + } + result.groupId_ = groupId_; + if (((from_bitField0_ & 0x00000004) == 0x00000004)) { + to_bitField0_ |= 0x00000004; + } + result.resultCode_ = resultCode_; + if (((from_bitField0_ & 0x00000008) == 0x00000008)) { + to_bitField0_ |= 0x00000008; + } + result.attachData_ = attachData_; + result.bitField0_ = to_bitField0_; + return result; + } + + public Builder mergeFrom(com.mogujie.tt.protobuf.IMGroup.IMGroupShieldRsp other) { + if (other == com.mogujie.tt.protobuf.IMGroup.IMGroupShieldRsp.getDefaultInstance()) return this; + if (other.hasUserId()) { + setUserId(other.getUserId()); + } + if (other.hasGroupId()) { + setGroupId(other.getGroupId()); + } + if (other.hasResultCode()) { + setResultCode(other.getResultCode()); + } + if (other.hasAttachData()) { + setAttachData(other.getAttachData()); + } + setUnknownFields( + getUnknownFields().concat(other.unknownFields)); + return this; + } + + public final boolean isInitialized() { + if (!hasUserId()) { + + return false; + } + if (!hasGroupId()) { + + return false; + } + if (!hasResultCode()) { + + return false; + } + return true; + } + + public Builder mergeFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + com.mogujie.tt.protobuf.IMGroup.IMGroupShieldRsp parsedMessage = null; + try { + parsedMessage = PARSER.parsePartialFrom(input, extensionRegistry); + } catch (com.google.protobuf.InvalidProtocolBufferException e) { + parsedMessage = (com.mogujie.tt.protobuf.IMGroup.IMGroupShieldRsp) e.getUnfinishedMessage(); + throw e; + } finally { + if (parsedMessage != null) { + mergeFrom(parsedMessage); + } + } + return this; + } + private int bitField0_; + + private int userId_ ; + /** + * required uint32 user_id = 1; + * + *
+       *cmd id:			0x040a
+       * 
+ */ + public boolean hasUserId() { + return ((bitField0_ & 0x00000001) == 0x00000001); + } + /** + * required uint32 user_id = 1; + * + *
+       *cmd id:			0x040a
+       * 
+ */ + public int getUserId() { + return userId_; + } + /** + * required uint32 user_id = 1; + * + *
+       *cmd id:			0x040a
+       * 
+ */ + public Builder setUserId(int value) { + bitField0_ |= 0x00000001; + userId_ = value; + + return this; + } + /** + * required uint32 user_id = 1; + * + *
+       *cmd id:			0x040a
+       * 
+ */ + public Builder clearUserId() { + bitField0_ = (bitField0_ & ~0x00000001); + userId_ = 0; + + return this; + } + + private int groupId_ ; + /** + * required uint32 group_id = 2; + */ + public boolean hasGroupId() { + return ((bitField0_ & 0x00000002) == 0x00000002); + } + /** + * required uint32 group_id = 2; + */ + public int getGroupId() { + return groupId_; + } + /** + * required uint32 group_id = 2; + */ + public Builder setGroupId(int value) { + bitField0_ |= 0x00000002; + groupId_ = value; + + return this; + } + /** + * required uint32 group_id = 2; + */ + public Builder clearGroupId() { + bitField0_ = (bitField0_ & ~0x00000002); + groupId_ = 0; + + return this; + } + + private int resultCode_ ; + /** + * required uint32 result_code = 3; + * + *
+       *0:successed 1:failed
+       * 
+ */ + public boolean hasResultCode() { + return ((bitField0_ & 0x00000004) == 0x00000004); + } + /** + * required uint32 result_code = 3; + * + *
+       *0:successed 1:failed
+       * 
+ */ + public int getResultCode() { + return resultCode_; + } + /** + * required uint32 result_code = 3; + * + *
+       *0:successed 1:failed
+       * 
+ */ + public Builder setResultCode(int value) { + bitField0_ |= 0x00000004; + resultCode_ = value; + + return this; + } + /** + * required uint32 result_code = 3; + * + *
+       *0:successed 1:failed
+       * 
+ */ + public Builder clearResultCode() { + bitField0_ = (bitField0_ & ~0x00000004); + resultCode_ = 0; + + return this; + } + + private com.google.protobuf.ByteString attachData_ = com.google.protobuf.ByteString.EMPTY; + /** + * optional bytes attach_data = 20; + */ + public boolean hasAttachData() { + return ((bitField0_ & 0x00000008) == 0x00000008); + } + /** + * optional bytes attach_data = 20; + */ + public com.google.protobuf.ByteString getAttachData() { + return attachData_; + } + /** + * optional bytes attach_data = 20; + */ + public Builder setAttachData(com.google.protobuf.ByteString value) { + if (value == null) { + throw new NullPointerException(); + } + bitField0_ |= 0x00000008; + attachData_ = value; + + return this; + } + /** + * optional bytes attach_data = 20; + */ + public Builder clearAttachData() { + bitField0_ = (bitField0_ & ~0x00000008); + attachData_ = getDefaultInstance().getAttachData(); + + return this; + } + + // @@protoc_insertion_point(builder_scope:IM.Group.IMGroupShieldRsp) + } + + static { + defaultInstance = new IMGroupShieldRsp(true); + defaultInstance.initFields(); + } + + // @@protoc_insertion_point(class_scope:IM.Group.IMGroupShieldRsp) + } + + public interface IMGroupChangeMemberNotifyOrBuilder extends + // @@protoc_insertion_point(interface_extends:IM.Group.IMGroupChangeMemberNotify) + com.google.protobuf.MessageLiteOrBuilder { + + /** + * required uint32 user_id = 1; + * + *
+     *cmd id: 			0x040b
+     * 
+ */ + boolean hasUserId(); + /** + * required uint32 user_id = 1; + * + *
+     *cmd id: 			0x040b
+     * 
+ */ + int getUserId(); + + /** + * required .IM.BaseDefine.GroupModifyType change_type = 2; + */ + boolean hasChangeType(); + /** + * required .IM.BaseDefine.GroupModifyType change_type = 2; + */ + com.mogujie.tt.protobuf.IMBaseDefine.GroupModifyType getChangeType(); + + /** + * required uint32 group_id = 3; + */ + boolean hasGroupId(); + /** + * required uint32 group_id = 3; + */ + int getGroupId(); + + /** + * repeated uint32 cur_user_id_list = 4; + * + *
+     *现有的成员id
+     * 
+ */ + java.util.List getCurUserIdListList(); + /** + * repeated uint32 cur_user_id_list = 4; + * + *
+     *现有的成员id
+     * 
+ */ + int getCurUserIdListCount(); + /** + * repeated uint32 cur_user_id_list = 4; + * + *
+     *现有的成员id
+     * 
+ */ + int getCurUserIdList(int index); + + /** + * repeated uint32 chg_user_id_list = 5; + * + *
+     *add: 表示添加成功的id,   del: 表示删除的id
+     * 
+ */ + java.util.List getChgUserIdListList(); + /** + * repeated uint32 chg_user_id_list = 5; + * + *
+     *add: 表示添加成功的id,   del: 表示删除的id
+     * 
+ */ + int getChgUserIdListCount(); + /** + * repeated uint32 chg_user_id_list = 5; + * + *
+     *add: 表示添加成功的id,   del: 表示删除的id
+     * 
+ */ + int getChgUserIdList(int index); + } + /** + * Protobuf type {@code IM.Group.IMGroupChangeMemberNotify} + */ + public static final class IMGroupChangeMemberNotify extends + com.google.protobuf.GeneratedMessageLite implements + // @@protoc_insertion_point(message_implements:IM.Group.IMGroupChangeMemberNotify) + IMGroupChangeMemberNotifyOrBuilder { + // Use IMGroupChangeMemberNotify.newBuilder() to construct. + private IMGroupChangeMemberNotify(com.google.protobuf.GeneratedMessageLite.Builder builder) { + super(builder); + this.unknownFields = builder.getUnknownFields(); + } + private IMGroupChangeMemberNotify(boolean noInit) { this.unknownFields = com.google.protobuf.ByteString.EMPTY;} + + private static final IMGroupChangeMemberNotify defaultInstance; + public static IMGroupChangeMemberNotify getDefaultInstance() { + return defaultInstance; + } + + public IMGroupChangeMemberNotify getDefaultInstanceForType() { + return defaultInstance; + } + + private final com.google.protobuf.ByteString unknownFields; + private IMGroupChangeMemberNotify( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + initFields(); + int mutable_bitField0_ = 0; + com.google.protobuf.ByteString.Output unknownFieldsOutput = + com.google.protobuf.ByteString.newOutput(); + com.google.protobuf.CodedOutputStream unknownFieldsCodedOutput = + com.google.protobuf.CodedOutputStream.newInstance( + unknownFieldsOutput); + try { + boolean done = false; + while (!done) { + int tag = input.readTag(); + switch (tag) { + case 0: + done = true; + break; + default: { + if (!parseUnknownField(input, unknownFieldsCodedOutput, + extensionRegistry, tag)) { + done = true; + } + break; + } + case 8: { + bitField0_ |= 0x00000001; + userId_ = input.readUInt32(); + break; + } + case 16: { + int rawValue = input.readEnum(); + com.mogujie.tt.protobuf.IMBaseDefine.GroupModifyType value = com.mogujie.tt.protobuf.IMBaseDefine.GroupModifyType.valueOf(rawValue); + if (value == null) { + unknownFieldsCodedOutput.writeRawVarint32(tag); + unknownFieldsCodedOutput.writeRawVarint32(rawValue); + } else { + bitField0_ |= 0x00000002; + changeType_ = value; + } + break; + } + case 24: { + bitField0_ |= 0x00000004; + groupId_ = input.readUInt32(); + break; + } + case 32: { + if (!((mutable_bitField0_ & 0x00000008) == 0x00000008)) { + curUserIdList_ = new java.util.ArrayList(); + mutable_bitField0_ |= 0x00000008; + } + curUserIdList_.add(input.readUInt32()); + break; + } + case 34: { + int length = input.readRawVarint32(); + int limit = input.pushLimit(length); + if (!((mutable_bitField0_ & 0x00000008) == 0x00000008) && input.getBytesUntilLimit() > 0) { + curUserIdList_ = new java.util.ArrayList(); + mutable_bitField0_ |= 0x00000008; + } + while (input.getBytesUntilLimit() > 0) { + curUserIdList_.add(input.readUInt32()); + } + input.popLimit(limit); + break; + } + case 40: { + if (!((mutable_bitField0_ & 0x00000010) == 0x00000010)) { + chgUserIdList_ = new java.util.ArrayList(); + mutable_bitField0_ |= 0x00000010; + } + chgUserIdList_.add(input.readUInt32()); + break; + } + case 42: { + int length = input.readRawVarint32(); + int limit = input.pushLimit(length); + if (!((mutable_bitField0_ & 0x00000010) == 0x00000010) && input.getBytesUntilLimit() > 0) { + chgUserIdList_ = new java.util.ArrayList(); + mutable_bitField0_ |= 0x00000010; + } + while (input.getBytesUntilLimit() > 0) { + chgUserIdList_.add(input.readUInt32()); + } + input.popLimit(limit); + break; + } + } + } + } catch (com.google.protobuf.InvalidProtocolBufferException e) { + throw e.setUnfinishedMessage(this); + } catch (java.io.IOException e) { + throw new com.google.protobuf.InvalidProtocolBufferException( + e.getMessage()).setUnfinishedMessage(this); + } finally { + if (((mutable_bitField0_ & 0x00000008) == 0x00000008)) { + curUserIdList_ = java.util.Collections.unmodifiableList(curUserIdList_); + } + if (((mutable_bitField0_ & 0x00000010) == 0x00000010)) { + chgUserIdList_ = java.util.Collections.unmodifiableList(chgUserIdList_); + } + try { + unknownFieldsCodedOutput.flush(); + } catch (java.io.IOException e) { + // Should not happen + } finally { + unknownFields = unknownFieldsOutput.toByteString(); + } + makeExtensionsImmutable(); + } + } + public static com.google.protobuf.Parser PARSER = + new com.google.protobuf.AbstractParser() { + public IMGroupChangeMemberNotify parsePartialFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return new IMGroupChangeMemberNotify(input, extensionRegistry); + } + }; + + @java.lang.Override + public com.google.protobuf.Parser getParserForType() { + return PARSER; + } + + private int bitField0_; + public static final int USER_ID_FIELD_NUMBER = 1; + private int userId_; + /** + * required uint32 user_id = 1; + * + *
+     *cmd id: 			0x040b
+     * 
+ */ + public boolean hasUserId() { + return ((bitField0_ & 0x00000001) == 0x00000001); + } + /** + * required uint32 user_id = 1; + * + *
+     *cmd id: 			0x040b
+     * 
+ */ + public int getUserId() { + return userId_; + } + + public static final int CHANGE_TYPE_FIELD_NUMBER = 2; + private com.mogujie.tt.protobuf.IMBaseDefine.GroupModifyType changeType_; + /** + * required .IM.BaseDefine.GroupModifyType change_type = 2; + */ + public boolean hasChangeType() { + return ((bitField0_ & 0x00000002) == 0x00000002); + } + /** + * required .IM.BaseDefine.GroupModifyType change_type = 2; + */ + public com.mogujie.tt.protobuf.IMBaseDefine.GroupModifyType getChangeType() { + return changeType_; + } + + public static final int GROUP_ID_FIELD_NUMBER = 3; + private int groupId_; + /** + * required uint32 group_id = 3; + */ + public boolean hasGroupId() { + return ((bitField0_ & 0x00000004) == 0x00000004); + } + /** + * required uint32 group_id = 3; + */ + public int getGroupId() { + return groupId_; + } + + public static final int CUR_USER_ID_LIST_FIELD_NUMBER = 4; + private java.util.List curUserIdList_; + /** + * repeated uint32 cur_user_id_list = 4; + * + *
+     *现有的成员id
+     * 
+ */ + public java.util.List + getCurUserIdListList() { + return curUserIdList_; + } + /** + * repeated uint32 cur_user_id_list = 4; + * + *
+     *现有的成员id
+     * 
+ */ + public int getCurUserIdListCount() { + return curUserIdList_.size(); + } + /** + * repeated uint32 cur_user_id_list = 4; + * + *
+     *现有的成员id
+     * 
+ */ + public int getCurUserIdList(int index) { + return curUserIdList_.get(index); + } + + public static final int CHG_USER_ID_LIST_FIELD_NUMBER = 5; + private java.util.List chgUserIdList_; + /** + * repeated uint32 chg_user_id_list = 5; + * + *
+     *add: 表示添加成功的id,   del: 表示删除的id
+     * 
+ */ + public java.util.List + getChgUserIdListList() { + return chgUserIdList_; + } + /** + * repeated uint32 chg_user_id_list = 5; + * + *
+     *add: 表示添加成功的id,   del: 表示删除的id
+     * 
+ */ + public int getChgUserIdListCount() { + return chgUserIdList_.size(); + } + /** + * repeated uint32 chg_user_id_list = 5; + * + *
+     *add: 表示添加成功的id,   del: 表示删除的id
+     * 
+ */ + public int getChgUserIdList(int index) { + return chgUserIdList_.get(index); + } + + private void initFields() { + userId_ = 0; + changeType_ = com.mogujie.tt.protobuf.IMBaseDefine.GroupModifyType.GROUP_MODIFY_TYPE_ADD; + groupId_ = 0; + curUserIdList_ = java.util.Collections.emptyList(); + chgUserIdList_ = java.util.Collections.emptyList(); + } + private byte memoizedIsInitialized = -1; + public final boolean isInitialized() { + byte isInitialized = memoizedIsInitialized; + if (isInitialized == 1) return true; + if (isInitialized == 0) return false; + + if (!hasUserId()) { + memoizedIsInitialized = 0; + return false; + } + if (!hasChangeType()) { + memoizedIsInitialized = 0; + return false; + } + if (!hasGroupId()) { + memoizedIsInitialized = 0; + return false; + } + memoizedIsInitialized = 1; + return true; + } + + public void writeTo(com.google.protobuf.CodedOutputStream output) + throws java.io.IOException { + getSerializedSize(); + if (((bitField0_ & 0x00000001) == 0x00000001)) { + output.writeUInt32(1, userId_); + } + if (((bitField0_ & 0x00000002) == 0x00000002)) { + output.writeEnum(2, changeType_.getNumber()); + } + if (((bitField0_ & 0x00000004) == 0x00000004)) { + output.writeUInt32(3, groupId_); + } + for (int i = 0; i < curUserIdList_.size(); i++) { + output.writeUInt32(4, curUserIdList_.get(i)); + } + for (int i = 0; i < chgUserIdList_.size(); i++) { + output.writeUInt32(5, chgUserIdList_.get(i)); + } + output.writeRawBytes(unknownFields); + } + + private int memoizedSerializedSize = -1; + public int getSerializedSize() { + int size = memoizedSerializedSize; + if (size != -1) return size; + + size = 0; + if (((bitField0_ & 0x00000001) == 0x00000001)) { + size += com.google.protobuf.CodedOutputStream + .computeUInt32Size(1, userId_); + } + if (((bitField0_ & 0x00000002) == 0x00000002)) { + size += com.google.protobuf.CodedOutputStream + .computeEnumSize(2, changeType_.getNumber()); + } + if (((bitField0_ & 0x00000004) == 0x00000004)) { + size += com.google.protobuf.CodedOutputStream + .computeUInt32Size(3, groupId_); + } + { + int dataSize = 0; + for (int i = 0; i < curUserIdList_.size(); i++) { + dataSize += com.google.protobuf.CodedOutputStream + .computeUInt32SizeNoTag(curUserIdList_.get(i)); + } + size += dataSize; + size += 1 * getCurUserIdListList().size(); + } + { + int dataSize = 0; + for (int i = 0; i < chgUserIdList_.size(); i++) { + dataSize += com.google.protobuf.CodedOutputStream + .computeUInt32SizeNoTag(chgUserIdList_.get(i)); + } + size += dataSize; + size += 1 * getChgUserIdListList().size(); + } + size += unknownFields.size(); + memoizedSerializedSize = size; + return size; + } + + private static final long serialVersionUID = 0L; + @java.lang.Override + protected java.lang.Object writeReplace() + throws java.io.ObjectStreamException { + return super.writeReplace(); + } + + public static com.mogujie.tt.protobuf.IMGroup.IMGroupChangeMemberNotify parseFrom( + com.google.protobuf.ByteString data) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data); + } + public static com.mogujie.tt.protobuf.IMGroup.IMGroupChangeMemberNotify parseFrom( + com.google.protobuf.ByteString data, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data, extensionRegistry); + } + public static com.mogujie.tt.protobuf.IMGroup.IMGroupChangeMemberNotify parseFrom(byte[] data) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data); + } + public static com.mogujie.tt.protobuf.IMGroup.IMGroupChangeMemberNotify parseFrom( + byte[] data, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data, extensionRegistry); + } + public static com.mogujie.tt.protobuf.IMGroup.IMGroupChangeMemberNotify parseFrom(java.io.InputStream input) + throws java.io.IOException { + return PARSER.parseFrom(input); + } + public static com.mogujie.tt.protobuf.IMGroup.IMGroupChangeMemberNotify parseFrom( + java.io.InputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return PARSER.parseFrom(input, extensionRegistry); + } + public static com.mogujie.tt.protobuf.IMGroup.IMGroupChangeMemberNotify parseDelimitedFrom(java.io.InputStream input) + throws java.io.IOException { + return PARSER.parseDelimitedFrom(input); + } + public static com.mogujie.tt.protobuf.IMGroup.IMGroupChangeMemberNotify parseDelimitedFrom( + java.io.InputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return PARSER.parseDelimitedFrom(input, extensionRegistry); + } + public static com.mogujie.tt.protobuf.IMGroup.IMGroupChangeMemberNotify parseFrom( + com.google.protobuf.CodedInputStream input) + throws java.io.IOException { + return PARSER.parseFrom(input); + } + public static com.mogujie.tt.protobuf.IMGroup.IMGroupChangeMemberNotify parseFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return PARSER.parseFrom(input, extensionRegistry); + } + + public static Builder newBuilder() { return Builder.create(); } + public Builder newBuilderForType() { return newBuilder(); } + public static Builder newBuilder(com.mogujie.tt.protobuf.IMGroup.IMGroupChangeMemberNotify prototype) { + return newBuilder().mergeFrom(prototype); + } + public Builder toBuilder() { return newBuilder(this); } + + /** + * Protobuf type {@code IM.Group.IMGroupChangeMemberNotify} + */ + public static final class Builder extends + com.google.protobuf.GeneratedMessageLite.Builder< + com.mogujie.tt.protobuf.IMGroup.IMGroupChangeMemberNotify, Builder> + implements + // @@protoc_insertion_point(builder_implements:IM.Group.IMGroupChangeMemberNotify) + com.mogujie.tt.protobuf.IMGroup.IMGroupChangeMemberNotifyOrBuilder { + // Construct using com.mogujie.tt.protobuf.IMGroup.IMGroupChangeMemberNotify.newBuilder() + private Builder() { + maybeForceBuilderInitialization(); + } + + private void maybeForceBuilderInitialization() { + } + private static Builder create() { + return new Builder(); + } + + public Builder clear() { + super.clear(); + userId_ = 0; + bitField0_ = (bitField0_ & ~0x00000001); + changeType_ = com.mogujie.tt.protobuf.IMBaseDefine.GroupModifyType.GROUP_MODIFY_TYPE_ADD; + bitField0_ = (bitField0_ & ~0x00000002); + groupId_ = 0; + bitField0_ = (bitField0_ & ~0x00000004); + curUserIdList_ = java.util.Collections.emptyList(); + bitField0_ = (bitField0_ & ~0x00000008); + chgUserIdList_ = java.util.Collections.emptyList(); + bitField0_ = (bitField0_ & ~0x00000010); + return this; + } + + public Builder clone() { + return create().mergeFrom(buildPartial()); + } + + public com.mogujie.tt.protobuf.IMGroup.IMGroupChangeMemberNotify getDefaultInstanceForType() { + return com.mogujie.tt.protobuf.IMGroup.IMGroupChangeMemberNotify.getDefaultInstance(); + } + + public com.mogujie.tt.protobuf.IMGroup.IMGroupChangeMemberNotify build() { + com.mogujie.tt.protobuf.IMGroup.IMGroupChangeMemberNotify result = buildPartial(); + if (!result.isInitialized()) { + throw newUninitializedMessageException(result); + } + return result; + } + + public com.mogujie.tt.protobuf.IMGroup.IMGroupChangeMemberNotify buildPartial() { + com.mogujie.tt.protobuf.IMGroup.IMGroupChangeMemberNotify result = new com.mogujie.tt.protobuf.IMGroup.IMGroupChangeMemberNotify(this); + int from_bitField0_ = bitField0_; + int to_bitField0_ = 0; + if (((from_bitField0_ & 0x00000001) == 0x00000001)) { + to_bitField0_ |= 0x00000001; + } + result.userId_ = userId_; + if (((from_bitField0_ & 0x00000002) == 0x00000002)) { + to_bitField0_ |= 0x00000002; + } + result.changeType_ = changeType_; + if (((from_bitField0_ & 0x00000004) == 0x00000004)) { + to_bitField0_ |= 0x00000004; + } + result.groupId_ = groupId_; + if (((bitField0_ & 0x00000008) == 0x00000008)) { + curUserIdList_ = java.util.Collections.unmodifiableList(curUserIdList_); + bitField0_ = (bitField0_ & ~0x00000008); + } + result.curUserIdList_ = curUserIdList_; + if (((bitField0_ & 0x00000010) == 0x00000010)) { + chgUserIdList_ = java.util.Collections.unmodifiableList(chgUserIdList_); + bitField0_ = (bitField0_ & ~0x00000010); + } + result.chgUserIdList_ = chgUserIdList_; + result.bitField0_ = to_bitField0_; + return result; + } + + public Builder mergeFrom(com.mogujie.tt.protobuf.IMGroup.IMGroupChangeMemberNotify other) { + if (other == com.mogujie.tt.protobuf.IMGroup.IMGroupChangeMemberNotify.getDefaultInstance()) return this; + if (other.hasUserId()) { + setUserId(other.getUserId()); + } + if (other.hasChangeType()) { + setChangeType(other.getChangeType()); + } + if (other.hasGroupId()) { + setGroupId(other.getGroupId()); + } + if (!other.curUserIdList_.isEmpty()) { + if (curUserIdList_.isEmpty()) { + curUserIdList_ = other.curUserIdList_; + bitField0_ = (bitField0_ & ~0x00000008); + } else { + ensureCurUserIdListIsMutable(); + curUserIdList_.addAll(other.curUserIdList_); + } + + } + if (!other.chgUserIdList_.isEmpty()) { + if (chgUserIdList_.isEmpty()) { + chgUserIdList_ = other.chgUserIdList_; + bitField0_ = (bitField0_ & ~0x00000010); + } else { + ensureChgUserIdListIsMutable(); + chgUserIdList_.addAll(other.chgUserIdList_); + } + + } + setUnknownFields( + getUnknownFields().concat(other.unknownFields)); + return this; + } + + public final boolean isInitialized() { + if (!hasUserId()) { + + return false; + } + if (!hasChangeType()) { + + return false; + } + if (!hasGroupId()) { + + return false; + } + return true; + } + + public Builder mergeFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + com.mogujie.tt.protobuf.IMGroup.IMGroupChangeMemberNotify parsedMessage = null; + try { + parsedMessage = PARSER.parsePartialFrom(input, extensionRegistry); + } catch (com.google.protobuf.InvalidProtocolBufferException e) { + parsedMessage = (com.mogujie.tt.protobuf.IMGroup.IMGroupChangeMemberNotify) e.getUnfinishedMessage(); + throw e; + } finally { + if (parsedMessage != null) { + mergeFrom(parsedMessage); + } + } + return this; + } + private int bitField0_; + + private int userId_ ; + /** + * required uint32 user_id = 1; + * + *
+       *cmd id: 			0x040b
+       * 
+ */ + public boolean hasUserId() { + return ((bitField0_ & 0x00000001) == 0x00000001); + } + /** + * required uint32 user_id = 1; + * + *
+       *cmd id: 			0x040b
+       * 
+ */ + public int getUserId() { + return userId_; + } + /** + * required uint32 user_id = 1; + * + *
+       *cmd id: 			0x040b
+       * 
+ */ + public Builder setUserId(int value) { + bitField0_ |= 0x00000001; + userId_ = value; + + return this; + } + /** + * required uint32 user_id = 1; + * + *
+       *cmd id: 			0x040b
+       * 
+ */ + public Builder clearUserId() { + bitField0_ = (bitField0_ & ~0x00000001); + userId_ = 0; + + return this; + } + + private com.mogujie.tt.protobuf.IMBaseDefine.GroupModifyType changeType_ = com.mogujie.tt.protobuf.IMBaseDefine.GroupModifyType.GROUP_MODIFY_TYPE_ADD; + /** + * required .IM.BaseDefine.GroupModifyType change_type = 2; + */ + public boolean hasChangeType() { + return ((bitField0_ & 0x00000002) == 0x00000002); + } + /** + * required .IM.BaseDefine.GroupModifyType change_type = 2; + */ + public com.mogujie.tt.protobuf.IMBaseDefine.GroupModifyType getChangeType() { + return changeType_; + } + /** + * required .IM.BaseDefine.GroupModifyType change_type = 2; + */ + public Builder setChangeType(com.mogujie.tt.protobuf.IMBaseDefine.GroupModifyType value) { + if (value == null) { + throw new NullPointerException(); + } + bitField0_ |= 0x00000002; + changeType_ = value; + + return this; + } + /** + * required .IM.BaseDefine.GroupModifyType change_type = 2; + */ + public Builder clearChangeType() { + bitField0_ = (bitField0_ & ~0x00000002); + changeType_ = com.mogujie.tt.protobuf.IMBaseDefine.GroupModifyType.GROUP_MODIFY_TYPE_ADD; + + return this; + } + + private int groupId_ ; + /** + * required uint32 group_id = 3; + */ + public boolean hasGroupId() { + return ((bitField0_ & 0x00000004) == 0x00000004); + } + /** + * required uint32 group_id = 3; + */ + public int getGroupId() { + return groupId_; + } + /** + * required uint32 group_id = 3; + */ + public Builder setGroupId(int value) { + bitField0_ |= 0x00000004; + groupId_ = value; + + return this; + } + /** + * required uint32 group_id = 3; + */ + public Builder clearGroupId() { + bitField0_ = (bitField0_ & ~0x00000004); + groupId_ = 0; + + return this; + } + + private java.util.List curUserIdList_ = java.util.Collections.emptyList(); + private void ensureCurUserIdListIsMutable() { + if (!((bitField0_ & 0x00000008) == 0x00000008)) { + curUserIdList_ = new java.util.ArrayList(curUserIdList_); + bitField0_ |= 0x00000008; + } + } + /** + * repeated uint32 cur_user_id_list = 4; + * + *
+       *现有的成员id
+       * 
+ */ + public java.util.List + getCurUserIdListList() { + return java.util.Collections.unmodifiableList(curUserIdList_); + } + /** + * repeated uint32 cur_user_id_list = 4; + * + *
+       *现有的成员id
+       * 
+ */ + public int getCurUserIdListCount() { + return curUserIdList_.size(); + } + /** + * repeated uint32 cur_user_id_list = 4; + * + *
+       *现有的成员id
+       * 
+ */ + public int getCurUserIdList(int index) { + return curUserIdList_.get(index); + } + /** + * repeated uint32 cur_user_id_list = 4; + * + *
+       *现有的成员id
+       * 
+ */ + public Builder setCurUserIdList( + int index, int value) { + ensureCurUserIdListIsMutable(); + curUserIdList_.set(index, value); + + return this; + } + /** + * repeated uint32 cur_user_id_list = 4; + * + *
+       *现有的成员id
+       * 
+ */ + public Builder addCurUserIdList(int value) { + ensureCurUserIdListIsMutable(); + curUserIdList_.add(value); + + return this; + } + /** + * repeated uint32 cur_user_id_list = 4; + * + *
+       *现有的成员id
+       * 
+ */ + public Builder addAllCurUserIdList( + java.lang.Iterable values) { + ensureCurUserIdListIsMutable(); + com.google.protobuf.AbstractMessageLite.Builder.addAll( + values, curUserIdList_); + + return this; + } + /** + * repeated uint32 cur_user_id_list = 4; + * + *
+       *现有的成员id
+       * 
+ */ + public Builder clearCurUserIdList() { + curUserIdList_ = java.util.Collections.emptyList(); + bitField0_ = (bitField0_ & ~0x00000008); + + return this; + } + + private java.util.List chgUserIdList_ = java.util.Collections.emptyList(); + private void ensureChgUserIdListIsMutable() { + if (!((bitField0_ & 0x00000010) == 0x00000010)) { + chgUserIdList_ = new java.util.ArrayList(chgUserIdList_); + bitField0_ |= 0x00000010; + } + } + /** + * repeated uint32 chg_user_id_list = 5; + * + *
+       *add: 表示添加成功的id,   del: 表示删除的id
+       * 
+ */ + public java.util.List + getChgUserIdListList() { + return java.util.Collections.unmodifiableList(chgUserIdList_); + } + /** + * repeated uint32 chg_user_id_list = 5; + * + *
+       *add: 表示添加成功的id,   del: 表示删除的id
+       * 
+ */ + public int getChgUserIdListCount() { + return chgUserIdList_.size(); + } + /** + * repeated uint32 chg_user_id_list = 5; + * + *
+       *add: 表示添加成功的id,   del: 表示删除的id
+       * 
+ */ + public int getChgUserIdList(int index) { + return chgUserIdList_.get(index); + } + /** + * repeated uint32 chg_user_id_list = 5; + * + *
+       *add: 表示添加成功的id,   del: 表示删除的id
+       * 
+ */ + public Builder setChgUserIdList( + int index, int value) { + ensureChgUserIdListIsMutable(); + chgUserIdList_.set(index, value); + + return this; + } + /** + * repeated uint32 chg_user_id_list = 5; + * + *
+       *add: 表示添加成功的id,   del: 表示删除的id
+       * 
+ */ + public Builder addChgUserIdList(int value) { + ensureChgUserIdListIsMutable(); + chgUserIdList_.add(value); + + return this; + } + /** + * repeated uint32 chg_user_id_list = 5; + * + *
+       *add: 表示添加成功的id,   del: 表示删除的id
+       * 
+ */ + public Builder addAllChgUserIdList( + java.lang.Iterable values) { + ensureChgUserIdListIsMutable(); + com.google.protobuf.AbstractMessageLite.Builder.addAll( + values, chgUserIdList_); + + return this; + } + /** + * repeated uint32 chg_user_id_list = 5; + * + *
+       *add: 表示添加成功的id,   del: 表示删除的id
+       * 
+ */ + public Builder clearChgUserIdList() { + chgUserIdList_ = java.util.Collections.emptyList(); + bitField0_ = (bitField0_ & ~0x00000010); + + return this; + } + + // @@protoc_insertion_point(builder_scope:IM.Group.IMGroupChangeMemberNotify) + } + + static { + defaultInstance = new IMGroupChangeMemberNotify(true); + defaultInstance.initFields(); + } + + // @@protoc_insertion_point(class_scope:IM.Group.IMGroupChangeMemberNotify) + } + + + static { + } + + // @@protoc_insertion_point(outer_class_scope) +} diff --git a/android/app/src/main/java/com/mogujie/tt/protobuf/IMLogin.java b/android/app/src/main/java/com/mogujie/tt/protobuf/IMLogin.java new file mode 100644 index 000000000..b27ed860e --- /dev/null +++ b/android/app/src/main/java/com/mogujie/tt/protobuf/IMLogin.java @@ -0,0 +1,6179 @@ +// Generated by the protocol buffer compiler. DO NOT EDIT! +// source: IM.Login.proto + +package com.mogujie.tt.protobuf; + +public final class IMLogin { + private IMLogin() {} + public static void registerAllExtensions( + com.google.protobuf.ExtensionRegistryLite registry) { + } + public interface IMMsgServReqOrBuilder extends + // @@protoc_insertion_point(interface_extends:IM.Login.IMMsgServReq) + com.google.protobuf.MessageLiteOrBuilder { + } + /** + * Protobuf type {@code IM.Login.IMMsgServReq} + * + *
+   *cmd id:		0x0101
+   * 
+ */ + public static final class IMMsgServReq extends + com.google.protobuf.GeneratedMessageLite implements + // @@protoc_insertion_point(message_implements:IM.Login.IMMsgServReq) + IMMsgServReqOrBuilder { + // Use IMMsgServReq.newBuilder() to construct. + private IMMsgServReq(com.google.protobuf.GeneratedMessageLite.Builder builder) { + super(builder); + this.unknownFields = builder.getUnknownFields(); + } + private IMMsgServReq(boolean noInit) { this.unknownFields = com.google.protobuf.ByteString.EMPTY;} + + private static final IMMsgServReq defaultInstance; + public static IMMsgServReq getDefaultInstance() { + return defaultInstance; + } + + public IMMsgServReq getDefaultInstanceForType() { + return defaultInstance; + } + + private final com.google.protobuf.ByteString unknownFields; + private IMMsgServReq( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + initFields(); + com.google.protobuf.ByteString.Output unknownFieldsOutput = + com.google.protobuf.ByteString.newOutput(); + com.google.protobuf.CodedOutputStream unknownFieldsCodedOutput = + com.google.protobuf.CodedOutputStream.newInstance( + unknownFieldsOutput); + try { + boolean done = false; + while (!done) { + int tag = input.readTag(); + switch (tag) { + case 0: + done = true; + break; + default: { + if (!parseUnknownField(input, unknownFieldsCodedOutput, + extensionRegistry, tag)) { + done = true; + } + break; + } + } + } + } catch (com.google.protobuf.InvalidProtocolBufferException e) { + throw e.setUnfinishedMessage(this); + } catch (java.io.IOException e) { + throw new com.google.protobuf.InvalidProtocolBufferException( + e.getMessage()).setUnfinishedMessage(this); + } finally { + try { + unknownFieldsCodedOutput.flush(); + } catch (java.io.IOException e) { + // Should not happen + } finally { + unknownFields = unknownFieldsOutput.toByteString(); + } + makeExtensionsImmutable(); + } + } + public static com.google.protobuf.Parser PARSER = + new com.google.protobuf.AbstractParser() { + public IMMsgServReq parsePartialFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return new IMMsgServReq(input, extensionRegistry); + } + }; + + @java.lang.Override + public com.google.protobuf.Parser getParserForType() { + return PARSER; + } + + private void initFields() { + } + private byte memoizedIsInitialized = -1; + public final boolean isInitialized() { + byte isInitialized = memoizedIsInitialized; + if (isInitialized == 1) return true; + if (isInitialized == 0) return false; + + memoizedIsInitialized = 1; + return true; + } + + public void writeTo(com.google.protobuf.CodedOutputStream output) + throws java.io.IOException { + getSerializedSize(); + output.writeRawBytes(unknownFields); + } + + private int memoizedSerializedSize = -1; + public int getSerializedSize() { + int size = memoizedSerializedSize; + if (size != -1) return size; + + size = 0; + size += unknownFields.size(); + memoizedSerializedSize = size; + return size; + } + + private static final long serialVersionUID = 0L; + @java.lang.Override + protected java.lang.Object writeReplace() + throws java.io.ObjectStreamException { + return super.writeReplace(); + } + + public static com.mogujie.tt.protobuf.IMLogin.IMMsgServReq parseFrom( + com.google.protobuf.ByteString data) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data); + } + public static com.mogujie.tt.protobuf.IMLogin.IMMsgServReq parseFrom( + com.google.protobuf.ByteString data, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data, extensionRegistry); + } + public static com.mogujie.tt.protobuf.IMLogin.IMMsgServReq parseFrom(byte[] data) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data); + } + public static com.mogujie.tt.protobuf.IMLogin.IMMsgServReq parseFrom( + byte[] data, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data, extensionRegistry); + } + public static com.mogujie.tt.protobuf.IMLogin.IMMsgServReq parseFrom(java.io.InputStream input) + throws java.io.IOException { + return PARSER.parseFrom(input); + } + public static com.mogujie.tt.protobuf.IMLogin.IMMsgServReq parseFrom( + java.io.InputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return PARSER.parseFrom(input, extensionRegistry); + } + public static com.mogujie.tt.protobuf.IMLogin.IMMsgServReq parseDelimitedFrom(java.io.InputStream input) + throws java.io.IOException { + return PARSER.parseDelimitedFrom(input); + } + public static com.mogujie.tt.protobuf.IMLogin.IMMsgServReq parseDelimitedFrom( + java.io.InputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return PARSER.parseDelimitedFrom(input, extensionRegistry); + } + public static com.mogujie.tt.protobuf.IMLogin.IMMsgServReq parseFrom( + com.google.protobuf.CodedInputStream input) + throws java.io.IOException { + return PARSER.parseFrom(input); + } + public static com.mogujie.tt.protobuf.IMLogin.IMMsgServReq parseFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return PARSER.parseFrom(input, extensionRegistry); + } + + public static Builder newBuilder() { return Builder.create(); } + public Builder newBuilderForType() { return newBuilder(); } + public static Builder newBuilder(com.mogujie.tt.protobuf.IMLogin.IMMsgServReq prototype) { + return newBuilder().mergeFrom(prototype); + } + public Builder toBuilder() { return newBuilder(this); } + + /** + * Protobuf type {@code IM.Login.IMMsgServReq} + * + *
+     *cmd id:		0x0101
+     * 
+ */ + public static final class Builder extends + com.google.protobuf.GeneratedMessageLite.Builder< + com.mogujie.tt.protobuf.IMLogin.IMMsgServReq, Builder> + implements + // @@protoc_insertion_point(builder_implements:IM.Login.IMMsgServReq) + com.mogujie.tt.protobuf.IMLogin.IMMsgServReqOrBuilder { + // Construct using com.mogujie.tt.protobuf.IMLogin.IMMsgServReq.newBuilder() + private Builder() { + maybeForceBuilderInitialization(); + } + + private void maybeForceBuilderInitialization() { + } + private static Builder create() { + return new Builder(); + } + + public Builder clear() { + super.clear(); + return this; + } + + public Builder clone() { + return create().mergeFrom(buildPartial()); + } + + public com.mogujie.tt.protobuf.IMLogin.IMMsgServReq getDefaultInstanceForType() { + return com.mogujie.tt.protobuf.IMLogin.IMMsgServReq.getDefaultInstance(); + } + + public com.mogujie.tt.protobuf.IMLogin.IMMsgServReq build() { + com.mogujie.tt.protobuf.IMLogin.IMMsgServReq result = buildPartial(); + if (!result.isInitialized()) { + throw newUninitializedMessageException(result); + } + return result; + } + + public com.mogujie.tt.protobuf.IMLogin.IMMsgServReq buildPartial() { + com.mogujie.tt.protobuf.IMLogin.IMMsgServReq result = new com.mogujie.tt.protobuf.IMLogin.IMMsgServReq(this); + return result; + } + + public Builder mergeFrom(com.mogujie.tt.protobuf.IMLogin.IMMsgServReq other) { + if (other == com.mogujie.tt.protobuf.IMLogin.IMMsgServReq.getDefaultInstance()) return this; + setUnknownFields( + getUnknownFields().concat(other.unknownFields)); + return this; + } + + public final boolean isInitialized() { + return true; + } + + public Builder mergeFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + com.mogujie.tt.protobuf.IMLogin.IMMsgServReq parsedMessage = null; + try { + parsedMessage = PARSER.parsePartialFrom(input, extensionRegistry); + } catch (com.google.protobuf.InvalidProtocolBufferException e) { + parsedMessage = (com.mogujie.tt.protobuf.IMLogin.IMMsgServReq) e.getUnfinishedMessage(); + throw e; + } finally { + if (parsedMessage != null) { + mergeFrom(parsedMessage); + } + } + return this; + } + + // @@protoc_insertion_point(builder_scope:IM.Login.IMMsgServReq) + } + + static { + defaultInstance = new IMMsgServReq(true); + defaultInstance.initFields(); + } + + // @@protoc_insertion_point(class_scope:IM.Login.IMMsgServReq) + } + + public interface IMMsgServRspOrBuilder extends + // @@protoc_insertion_point(interface_extends:IM.Login.IMMsgServRsp) + com.google.protobuf.MessageLiteOrBuilder { + + /** + * required .IM.BaseDefine.ResultType result_code = 1; + * + *
+     *cmd id:		0x0102
+     * 
+ */ + boolean hasResultCode(); + /** + * required .IM.BaseDefine.ResultType result_code = 1; + * + *
+     *cmd id:		0x0102
+     * 
+ */ + com.mogujie.tt.protobuf.IMBaseDefine.ResultType getResultCode(); + + /** + * optional string prior_ip = 2; + */ + boolean hasPriorIp(); + /** + * optional string prior_ip = 2; + */ + java.lang.String getPriorIp(); + /** + * optional string prior_ip = 2; + */ + com.google.protobuf.ByteString + getPriorIpBytes(); + + /** + * optional string backip_ip = 3; + */ + boolean hasBackipIp(); + /** + * optional string backip_ip = 3; + */ + java.lang.String getBackipIp(); + /** + * optional string backip_ip = 3; + */ + com.google.protobuf.ByteString + getBackipIpBytes(); + + /** + * optional uint32 port = 4; + */ + boolean hasPort(); + /** + * optional uint32 port = 4; + */ + int getPort(); + } + /** + * Protobuf type {@code IM.Login.IMMsgServRsp} + */ + public static final class IMMsgServRsp extends + com.google.protobuf.GeneratedMessageLite implements + // @@protoc_insertion_point(message_implements:IM.Login.IMMsgServRsp) + IMMsgServRspOrBuilder { + // Use IMMsgServRsp.newBuilder() to construct. + private IMMsgServRsp(com.google.protobuf.GeneratedMessageLite.Builder builder) { + super(builder); + this.unknownFields = builder.getUnknownFields(); + } + private IMMsgServRsp(boolean noInit) { this.unknownFields = com.google.protobuf.ByteString.EMPTY;} + + private static final IMMsgServRsp defaultInstance; + public static IMMsgServRsp getDefaultInstance() { + return defaultInstance; + } + + public IMMsgServRsp getDefaultInstanceForType() { + return defaultInstance; + } + + private final com.google.protobuf.ByteString unknownFields; + private IMMsgServRsp( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + initFields(); + int mutable_bitField0_ = 0; + com.google.protobuf.ByteString.Output unknownFieldsOutput = + com.google.protobuf.ByteString.newOutput(); + com.google.protobuf.CodedOutputStream unknownFieldsCodedOutput = + com.google.protobuf.CodedOutputStream.newInstance( + unknownFieldsOutput); + try { + boolean done = false; + while (!done) { + int tag = input.readTag(); + switch (tag) { + case 0: + done = true; + break; + default: { + if (!parseUnknownField(input, unknownFieldsCodedOutput, + extensionRegistry, tag)) { + done = true; + } + break; + } + case 8: { + int rawValue = input.readEnum(); + com.mogujie.tt.protobuf.IMBaseDefine.ResultType value = com.mogujie.tt.protobuf.IMBaseDefine.ResultType.valueOf(rawValue); + if (value == null) { + unknownFieldsCodedOutput.writeRawVarint32(tag); + unknownFieldsCodedOutput.writeRawVarint32(rawValue); + } else { + bitField0_ |= 0x00000001; + resultCode_ = value; + } + break; + } + case 18: { + com.google.protobuf.ByteString bs = input.readBytes(); + bitField0_ |= 0x00000002; + priorIp_ = bs; + break; + } + case 26: { + com.google.protobuf.ByteString bs = input.readBytes(); + bitField0_ |= 0x00000004; + backipIp_ = bs; + break; + } + case 32: { + bitField0_ |= 0x00000008; + port_ = input.readUInt32(); + break; + } + } + } + } catch (com.google.protobuf.InvalidProtocolBufferException e) { + throw e.setUnfinishedMessage(this); + } catch (java.io.IOException e) { + throw new com.google.protobuf.InvalidProtocolBufferException( + e.getMessage()).setUnfinishedMessage(this); + } finally { + try { + unknownFieldsCodedOutput.flush(); + } catch (java.io.IOException e) { + // Should not happen + } finally { + unknownFields = unknownFieldsOutput.toByteString(); + } + makeExtensionsImmutable(); + } + } + public static com.google.protobuf.Parser PARSER = + new com.google.protobuf.AbstractParser() { + public IMMsgServRsp parsePartialFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return new IMMsgServRsp(input, extensionRegistry); + } + }; + + @java.lang.Override + public com.google.protobuf.Parser getParserForType() { + return PARSER; + } + + private int bitField0_; + public static final int RESULT_CODE_FIELD_NUMBER = 1; + private com.mogujie.tt.protobuf.IMBaseDefine.ResultType resultCode_; + /** + * required .IM.BaseDefine.ResultType result_code = 1; + * + *
+     *cmd id:		0x0102
+     * 
+ */ + public boolean hasResultCode() { + return ((bitField0_ & 0x00000001) == 0x00000001); + } + /** + * required .IM.BaseDefine.ResultType result_code = 1; + * + *
+     *cmd id:		0x0102
+     * 
+ */ + public com.mogujie.tt.protobuf.IMBaseDefine.ResultType getResultCode() { + return resultCode_; + } + + public static final int PRIOR_IP_FIELD_NUMBER = 2; + private java.lang.Object priorIp_; + /** + * optional string prior_ip = 2; + */ + public boolean hasPriorIp() { + return ((bitField0_ & 0x00000002) == 0x00000002); + } + /** + * optional string prior_ip = 2; + */ + public java.lang.String getPriorIp() { + java.lang.Object ref = priorIp_; + if (ref instanceof java.lang.String) { + return (java.lang.String) ref; + } else { + com.google.protobuf.ByteString bs = + (com.google.protobuf.ByteString) ref; + java.lang.String s = bs.toStringUtf8(); + if (bs.isValidUtf8()) { + priorIp_ = s; + } + return s; + } + } + /** + * optional string prior_ip = 2; + */ + public com.google.protobuf.ByteString + getPriorIpBytes() { + java.lang.Object ref = priorIp_; + if (ref instanceof java.lang.String) { + com.google.protobuf.ByteString b = + com.google.protobuf.ByteString.copyFromUtf8( + (java.lang.String) ref); + priorIp_ = b; + return b; + } else { + return (com.google.protobuf.ByteString) ref; + } + } + + public static final int BACKIP_IP_FIELD_NUMBER = 3; + private java.lang.Object backipIp_; + /** + * optional string backip_ip = 3; + */ + public boolean hasBackipIp() { + return ((bitField0_ & 0x00000004) == 0x00000004); + } + /** + * optional string backip_ip = 3; + */ + public java.lang.String getBackipIp() { + java.lang.Object ref = backipIp_; + if (ref instanceof java.lang.String) { + return (java.lang.String) ref; + } else { + com.google.protobuf.ByteString bs = + (com.google.protobuf.ByteString) ref; + java.lang.String s = bs.toStringUtf8(); + if (bs.isValidUtf8()) { + backipIp_ = s; + } + return s; + } + } + /** + * optional string backip_ip = 3; + */ + public com.google.protobuf.ByteString + getBackipIpBytes() { + java.lang.Object ref = backipIp_; + if (ref instanceof java.lang.String) { + com.google.protobuf.ByteString b = + com.google.protobuf.ByteString.copyFromUtf8( + (java.lang.String) ref); + backipIp_ = b; + return b; + } else { + return (com.google.protobuf.ByteString) ref; + } + } + + public static final int PORT_FIELD_NUMBER = 4; + private int port_; + /** + * optional uint32 port = 4; + */ + public boolean hasPort() { + return ((bitField0_ & 0x00000008) == 0x00000008); + } + /** + * optional uint32 port = 4; + */ + public int getPort() { + return port_; + } + + private void initFields() { + resultCode_ = com.mogujie.tt.protobuf.IMBaseDefine.ResultType.REFUSE_REASON_NONE; + priorIp_ = ""; + backipIp_ = ""; + port_ = 0; + } + private byte memoizedIsInitialized = -1; + public final boolean isInitialized() { + byte isInitialized = memoizedIsInitialized; + if (isInitialized == 1) return true; + if (isInitialized == 0) return false; + + if (!hasResultCode()) { + memoizedIsInitialized = 0; + return false; + } + memoizedIsInitialized = 1; + return true; + } + + public void writeTo(com.google.protobuf.CodedOutputStream output) + throws java.io.IOException { + getSerializedSize(); + if (((bitField0_ & 0x00000001) == 0x00000001)) { + output.writeEnum(1, resultCode_.getNumber()); + } + if (((bitField0_ & 0x00000002) == 0x00000002)) { + output.writeBytes(2, getPriorIpBytes()); + } + if (((bitField0_ & 0x00000004) == 0x00000004)) { + output.writeBytes(3, getBackipIpBytes()); + } + if (((bitField0_ & 0x00000008) == 0x00000008)) { + output.writeUInt32(4, port_); + } + output.writeRawBytes(unknownFields); + } + + private int memoizedSerializedSize = -1; + public int getSerializedSize() { + int size = memoizedSerializedSize; + if (size != -1) return size; + + size = 0; + if (((bitField0_ & 0x00000001) == 0x00000001)) { + size += com.google.protobuf.CodedOutputStream + .computeEnumSize(1, resultCode_.getNumber()); + } + if (((bitField0_ & 0x00000002) == 0x00000002)) { + size += com.google.protobuf.CodedOutputStream + .computeBytesSize(2, getPriorIpBytes()); + } + if (((bitField0_ & 0x00000004) == 0x00000004)) { + size += com.google.protobuf.CodedOutputStream + .computeBytesSize(3, getBackipIpBytes()); + } + if (((bitField0_ & 0x00000008) == 0x00000008)) { + size += com.google.protobuf.CodedOutputStream + .computeUInt32Size(4, port_); + } + size += unknownFields.size(); + memoizedSerializedSize = size; + return size; + } + + private static final long serialVersionUID = 0L; + @java.lang.Override + protected java.lang.Object writeReplace() + throws java.io.ObjectStreamException { + return super.writeReplace(); + } + + public static com.mogujie.tt.protobuf.IMLogin.IMMsgServRsp parseFrom( + com.google.protobuf.ByteString data) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data); + } + public static com.mogujie.tt.protobuf.IMLogin.IMMsgServRsp parseFrom( + com.google.protobuf.ByteString data, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data, extensionRegistry); + } + public static com.mogujie.tt.protobuf.IMLogin.IMMsgServRsp parseFrom(byte[] data) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data); + } + public static com.mogujie.tt.protobuf.IMLogin.IMMsgServRsp parseFrom( + byte[] data, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data, extensionRegistry); + } + public static com.mogujie.tt.protobuf.IMLogin.IMMsgServRsp parseFrom(java.io.InputStream input) + throws java.io.IOException { + return PARSER.parseFrom(input); + } + public static com.mogujie.tt.protobuf.IMLogin.IMMsgServRsp parseFrom( + java.io.InputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return PARSER.parseFrom(input, extensionRegistry); + } + public static com.mogujie.tt.protobuf.IMLogin.IMMsgServRsp parseDelimitedFrom(java.io.InputStream input) + throws java.io.IOException { + return PARSER.parseDelimitedFrom(input); + } + public static com.mogujie.tt.protobuf.IMLogin.IMMsgServRsp parseDelimitedFrom( + java.io.InputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return PARSER.parseDelimitedFrom(input, extensionRegistry); + } + public static com.mogujie.tt.protobuf.IMLogin.IMMsgServRsp parseFrom( + com.google.protobuf.CodedInputStream input) + throws java.io.IOException { + return PARSER.parseFrom(input); + } + public static com.mogujie.tt.protobuf.IMLogin.IMMsgServRsp parseFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return PARSER.parseFrom(input, extensionRegistry); + } + + public static Builder newBuilder() { return Builder.create(); } + public Builder newBuilderForType() { return newBuilder(); } + public static Builder newBuilder(com.mogujie.tt.protobuf.IMLogin.IMMsgServRsp prototype) { + return newBuilder().mergeFrom(prototype); + } + public Builder toBuilder() { return newBuilder(this); } + + /** + * Protobuf type {@code IM.Login.IMMsgServRsp} + */ + public static final class Builder extends + com.google.protobuf.GeneratedMessageLite.Builder< + com.mogujie.tt.protobuf.IMLogin.IMMsgServRsp, Builder> + implements + // @@protoc_insertion_point(builder_implements:IM.Login.IMMsgServRsp) + com.mogujie.tt.protobuf.IMLogin.IMMsgServRspOrBuilder { + // Construct using com.mogujie.tt.protobuf.IMLogin.IMMsgServRsp.newBuilder() + private Builder() { + maybeForceBuilderInitialization(); + } + + private void maybeForceBuilderInitialization() { + } + private static Builder create() { + return new Builder(); + } + + public Builder clear() { + super.clear(); + resultCode_ = com.mogujie.tt.protobuf.IMBaseDefine.ResultType.REFUSE_REASON_NONE; + bitField0_ = (bitField0_ & ~0x00000001); + priorIp_ = ""; + bitField0_ = (bitField0_ & ~0x00000002); + backipIp_ = ""; + bitField0_ = (bitField0_ & ~0x00000004); + port_ = 0; + bitField0_ = (bitField0_ & ~0x00000008); + return this; + } + + public Builder clone() { + return create().mergeFrom(buildPartial()); + } + + public com.mogujie.tt.protobuf.IMLogin.IMMsgServRsp getDefaultInstanceForType() { + return com.mogujie.tt.protobuf.IMLogin.IMMsgServRsp.getDefaultInstance(); + } + + public com.mogujie.tt.protobuf.IMLogin.IMMsgServRsp build() { + com.mogujie.tt.protobuf.IMLogin.IMMsgServRsp result = buildPartial(); + if (!result.isInitialized()) { + throw newUninitializedMessageException(result); + } + return result; + } + + public com.mogujie.tt.protobuf.IMLogin.IMMsgServRsp buildPartial() { + com.mogujie.tt.protobuf.IMLogin.IMMsgServRsp result = new com.mogujie.tt.protobuf.IMLogin.IMMsgServRsp(this); + int from_bitField0_ = bitField0_; + int to_bitField0_ = 0; + if (((from_bitField0_ & 0x00000001) == 0x00000001)) { + to_bitField0_ |= 0x00000001; + } + result.resultCode_ = resultCode_; + if (((from_bitField0_ & 0x00000002) == 0x00000002)) { + to_bitField0_ |= 0x00000002; + } + result.priorIp_ = priorIp_; + if (((from_bitField0_ & 0x00000004) == 0x00000004)) { + to_bitField0_ |= 0x00000004; + } + result.backipIp_ = backipIp_; + if (((from_bitField0_ & 0x00000008) == 0x00000008)) { + to_bitField0_ |= 0x00000008; + } + result.port_ = port_; + result.bitField0_ = to_bitField0_; + return result; + } + + public Builder mergeFrom(com.mogujie.tt.protobuf.IMLogin.IMMsgServRsp other) { + if (other == com.mogujie.tt.protobuf.IMLogin.IMMsgServRsp.getDefaultInstance()) return this; + if (other.hasResultCode()) { + setResultCode(other.getResultCode()); + } + if (other.hasPriorIp()) { + bitField0_ |= 0x00000002; + priorIp_ = other.priorIp_; + + } + if (other.hasBackipIp()) { + bitField0_ |= 0x00000004; + backipIp_ = other.backipIp_; + + } + if (other.hasPort()) { + setPort(other.getPort()); + } + setUnknownFields( + getUnknownFields().concat(other.unknownFields)); + return this; + } + + public final boolean isInitialized() { + if (!hasResultCode()) { + + return false; + } + return true; + } + + public Builder mergeFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + com.mogujie.tt.protobuf.IMLogin.IMMsgServRsp parsedMessage = null; + try { + parsedMessage = PARSER.parsePartialFrom(input, extensionRegistry); + } catch (com.google.protobuf.InvalidProtocolBufferException e) { + parsedMessage = (com.mogujie.tt.protobuf.IMLogin.IMMsgServRsp) e.getUnfinishedMessage(); + throw e; + } finally { + if (parsedMessage != null) { + mergeFrom(parsedMessage); + } + } + return this; + } + private int bitField0_; + + private com.mogujie.tt.protobuf.IMBaseDefine.ResultType resultCode_ = com.mogujie.tt.protobuf.IMBaseDefine.ResultType.REFUSE_REASON_NONE; + /** + * required .IM.BaseDefine.ResultType result_code = 1; + * + *
+       *cmd id:		0x0102
+       * 
+ */ + public boolean hasResultCode() { + return ((bitField0_ & 0x00000001) == 0x00000001); + } + /** + * required .IM.BaseDefine.ResultType result_code = 1; + * + *
+       *cmd id:		0x0102
+       * 
+ */ + public com.mogujie.tt.protobuf.IMBaseDefine.ResultType getResultCode() { + return resultCode_; + } + /** + * required .IM.BaseDefine.ResultType result_code = 1; + * + *
+       *cmd id:		0x0102
+       * 
+ */ + public Builder setResultCode(com.mogujie.tt.protobuf.IMBaseDefine.ResultType value) { + if (value == null) { + throw new NullPointerException(); + } + bitField0_ |= 0x00000001; + resultCode_ = value; + + return this; + } + /** + * required .IM.BaseDefine.ResultType result_code = 1; + * + *
+       *cmd id:		0x0102
+       * 
+ */ + public Builder clearResultCode() { + bitField0_ = (bitField0_ & ~0x00000001); + resultCode_ = com.mogujie.tt.protobuf.IMBaseDefine.ResultType.REFUSE_REASON_NONE; + + return this; + } + + private java.lang.Object priorIp_ = ""; + /** + * optional string prior_ip = 2; + */ + public boolean hasPriorIp() { + return ((bitField0_ & 0x00000002) == 0x00000002); + } + /** + * optional string prior_ip = 2; + */ + public java.lang.String getPriorIp() { + java.lang.Object ref = priorIp_; + if (!(ref instanceof java.lang.String)) { + com.google.protobuf.ByteString bs = + (com.google.protobuf.ByteString) ref; + java.lang.String s = bs.toStringUtf8(); + if (bs.isValidUtf8()) { + priorIp_ = s; + } + return s; + } else { + return (java.lang.String) ref; + } + } + /** + * optional string prior_ip = 2; + */ + public com.google.protobuf.ByteString + getPriorIpBytes() { + java.lang.Object ref = priorIp_; + if (ref instanceof String) { + com.google.protobuf.ByteString b = + com.google.protobuf.ByteString.copyFromUtf8( + (java.lang.String) ref); + priorIp_ = b; + return b; + } else { + return (com.google.protobuf.ByteString) ref; + } + } + /** + * optional string prior_ip = 2; + */ + public Builder setPriorIp( + java.lang.String value) { + if (value == null) { + throw new NullPointerException(); + } + bitField0_ |= 0x00000002; + priorIp_ = value; + + return this; + } + /** + * optional string prior_ip = 2; + */ + public Builder clearPriorIp() { + bitField0_ = (bitField0_ & ~0x00000002); + priorIp_ = getDefaultInstance().getPriorIp(); + + return this; + } + /** + * optional string prior_ip = 2; + */ + public Builder setPriorIpBytes( + com.google.protobuf.ByteString value) { + if (value == null) { + throw new NullPointerException(); + } + bitField0_ |= 0x00000002; + priorIp_ = value; + + return this; + } + + private java.lang.Object backipIp_ = ""; + /** + * optional string backip_ip = 3; + */ + public boolean hasBackipIp() { + return ((bitField0_ & 0x00000004) == 0x00000004); + } + /** + * optional string backip_ip = 3; + */ + public java.lang.String getBackipIp() { + java.lang.Object ref = backipIp_; + if (!(ref instanceof java.lang.String)) { + com.google.protobuf.ByteString bs = + (com.google.protobuf.ByteString) ref; + java.lang.String s = bs.toStringUtf8(); + if (bs.isValidUtf8()) { + backipIp_ = s; + } + return s; + } else { + return (java.lang.String) ref; + } + } + /** + * optional string backip_ip = 3; + */ + public com.google.protobuf.ByteString + getBackipIpBytes() { + java.lang.Object ref = backipIp_; + if (ref instanceof String) { + com.google.protobuf.ByteString b = + com.google.protobuf.ByteString.copyFromUtf8( + (java.lang.String) ref); + backipIp_ = b; + return b; + } else { + return (com.google.protobuf.ByteString) ref; + } + } + /** + * optional string backip_ip = 3; + */ + public Builder setBackipIp( + java.lang.String value) { + if (value == null) { + throw new NullPointerException(); + } + bitField0_ |= 0x00000004; + backipIp_ = value; + + return this; + } + /** + * optional string backip_ip = 3; + */ + public Builder clearBackipIp() { + bitField0_ = (bitField0_ & ~0x00000004); + backipIp_ = getDefaultInstance().getBackipIp(); + + return this; + } + /** + * optional string backip_ip = 3; + */ + public Builder setBackipIpBytes( + com.google.protobuf.ByteString value) { + if (value == null) { + throw new NullPointerException(); + } + bitField0_ |= 0x00000004; + backipIp_ = value; + + return this; + } + + private int port_ ; + /** + * optional uint32 port = 4; + */ + public boolean hasPort() { + return ((bitField0_ & 0x00000008) == 0x00000008); + } + /** + * optional uint32 port = 4; + */ + public int getPort() { + return port_; + } + /** + * optional uint32 port = 4; + */ + public Builder setPort(int value) { + bitField0_ |= 0x00000008; + port_ = value; + + return this; + } + /** + * optional uint32 port = 4; + */ + public Builder clearPort() { + bitField0_ = (bitField0_ & ~0x00000008); + port_ = 0; + + return this; + } + + // @@protoc_insertion_point(builder_scope:IM.Login.IMMsgServRsp) + } + + static { + defaultInstance = new IMMsgServRsp(true); + defaultInstance.initFields(); + } + + // @@protoc_insertion_point(class_scope:IM.Login.IMMsgServRsp) + } + + public interface IMLoginReqOrBuilder extends + // @@protoc_insertion_point(interface_extends:IM.Login.IMLoginReq) + com.google.protobuf.MessageLiteOrBuilder { + + /** + * required string user_name = 1; + * + *
+     *cmd id:		0x0103
+     * 
+ */ + boolean hasUserName(); + /** + * required string user_name = 1; + * + *
+     *cmd id:		0x0103
+     * 
+ */ + java.lang.String getUserName(); + /** + * required string user_name = 1; + * + *
+     *cmd id:		0x0103
+     * 
+ */ + com.google.protobuf.ByteString + getUserNameBytes(); + + /** + * required string password = 2; + */ + boolean hasPassword(); + /** + * required string password = 2; + */ + java.lang.String getPassword(); + /** + * required string password = 2; + */ + com.google.protobuf.ByteString + getPasswordBytes(); + + /** + * required .IM.BaseDefine.UserStatType online_status = 3; + */ + boolean hasOnlineStatus(); + /** + * required .IM.BaseDefine.UserStatType online_status = 3; + */ + com.mogujie.tt.protobuf.IMBaseDefine.UserStatType getOnlineStatus(); + + /** + * required .IM.BaseDefine.ClientType client_type = 4; + */ + boolean hasClientType(); + /** + * required .IM.BaseDefine.ClientType client_type = 4; + */ + com.mogujie.tt.protobuf.IMBaseDefine.ClientType getClientType(); + + /** + * optional string client_version = 5; + */ + boolean hasClientVersion(); + /** + * optional string client_version = 5; + */ + java.lang.String getClientVersion(); + /** + * optional string client_version = 5; + */ + com.google.protobuf.ByteString + getClientVersionBytes(); + } + /** + * Protobuf type {@code IM.Login.IMLoginReq} + */ + public static final class IMLoginReq extends + com.google.protobuf.GeneratedMessageLite implements + // @@protoc_insertion_point(message_implements:IM.Login.IMLoginReq) + IMLoginReqOrBuilder { + // Use IMLoginReq.newBuilder() to construct. + private IMLoginReq(com.google.protobuf.GeneratedMessageLite.Builder builder) { + super(builder); + this.unknownFields = builder.getUnknownFields(); + } + private IMLoginReq(boolean noInit) { this.unknownFields = com.google.protobuf.ByteString.EMPTY;} + + private static final IMLoginReq defaultInstance; + public static IMLoginReq getDefaultInstance() { + return defaultInstance; + } + + public IMLoginReq getDefaultInstanceForType() { + return defaultInstance; + } + + private final com.google.protobuf.ByteString unknownFields; + private IMLoginReq( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + initFields(); + int mutable_bitField0_ = 0; + com.google.protobuf.ByteString.Output unknownFieldsOutput = + com.google.protobuf.ByteString.newOutput(); + com.google.protobuf.CodedOutputStream unknownFieldsCodedOutput = + com.google.protobuf.CodedOutputStream.newInstance( + unknownFieldsOutput); + try { + boolean done = false; + while (!done) { + int tag = input.readTag(); + switch (tag) { + case 0: + done = true; + break; + default: { + if (!parseUnknownField(input, unknownFieldsCodedOutput, + extensionRegistry, tag)) { + done = true; + } + break; + } + case 10: { + com.google.protobuf.ByteString bs = input.readBytes(); + bitField0_ |= 0x00000001; + userName_ = bs; + break; + } + case 18: { + com.google.protobuf.ByteString bs = input.readBytes(); + bitField0_ |= 0x00000002; + password_ = bs; + break; + } + case 24: { + int rawValue = input.readEnum(); + com.mogujie.tt.protobuf.IMBaseDefine.UserStatType value = com.mogujie.tt.protobuf.IMBaseDefine.UserStatType.valueOf(rawValue); + if (value == null) { + unknownFieldsCodedOutput.writeRawVarint32(tag); + unknownFieldsCodedOutput.writeRawVarint32(rawValue); + } else { + bitField0_ |= 0x00000004; + onlineStatus_ = value; + } + break; + } + case 32: { + int rawValue = input.readEnum(); + com.mogujie.tt.protobuf.IMBaseDefine.ClientType value = com.mogujie.tt.protobuf.IMBaseDefine.ClientType.valueOf(rawValue); + if (value == null) { + unknownFieldsCodedOutput.writeRawVarint32(tag); + unknownFieldsCodedOutput.writeRawVarint32(rawValue); + } else { + bitField0_ |= 0x00000008; + clientType_ = value; + } + break; + } + case 42: { + com.google.protobuf.ByteString bs = input.readBytes(); + bitField0_ |= 0x00000010; + clientVersion_ = bs; + break; + } + } + } + } catch (com.google.protobuf.InvalidProtocolBufferException e) { + throw e.setUnfinishedMessage(this); + } catch (java.io.IOException e) { + throw new com.google.protobuf.InvalidProtocolBufferException( + e.getMessage()).setUnfinishedMessage(this); + } finally { + try { + unknownFieldsCodedOutput.flush(); + } catch (java.io.IOException e) { + // Should not happen + } finally { + unknownFields = unknownFieldsOutput.toByteString(); + } + makeExtensionsImmutable(); + } + } + public static com.google.protobuf.Parser PARSER = + new com.google.protobuf.AbstractParser() { + public IMLoginReq parsePartialFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return new IMLoginReq(input, extensionRegistry); + } + }; + + @java.lang.Override + public com.google.protobuf.Parser getParserForType() { + return PARSER; + } + + private int bitField0_; + public static final int USER_NAME_FIELD_NUMBER = 1; + private java.lang.Object userName_; + /** + * required string user_name = 1; + * + *
+     *cmd id:		0x0103
+     * 
+ */ + public boolean hasUserName() { + return ((bitField0_ & 0x00000001) == 0x00000001); + } + /** + * required string user_name = 1; + * + *
+     *cmd id:		0x0103
+     * 
+ */ + public java.lang.String getUserName() { + java.lang.Object ref = userName_; + if (ref instanceof java.lang.String) { + return (java.lang.String) ref; + } else { + com.google.protobuf.ByteString bs = + (com.google.protobuf.ByteString) ref; + java.lang.String s = bs.toStringUtf8(); + if (bs.isValidUtf8()) { + userName_ = s; + } + return s; + } + } + /** + * required string user_name = 1; + * + *
+     *cmd id:		0x0103
+     * 
+ */ + public com.google.protobuf.ByteString + getUserNameBytes() { + java.lang.Object ref = userName_; + if (ref instanceof java.lang.String) { + com.google.protobuf.ByteString b = + com.google.protobuf.ByteString.copyFromUtf8( + (java.lang.String) ref); + userName_ = b; + return b; + } else { + return (com.google.protobuf.ByteString) ref; + } + } + + public static final int PASSWORD_FIELD_NUMBER = 2; + private java.lang.Object password_; + /** + * required string password = 2; + */ + public boolean hasPassword() { + return ((bitField0_ & 0x00000002) == 0x00000002); + } + /** + * required string password = 2; + */ + public java.lang.String getPassword() { + java.lang.Object ref = password_; + if (ref instanceof java.lang.String) { + return (java.lang.String) ref; + } else { + com.google.protobuf.ByteString bs = + (com.google.protobuf.ByteString) ref; + java.lang.String s = bs.toStringUtf8(); + if (bs.isValidUtf8()) { + password_ = s; + } + return s; + } + } + /** + * required string password = 2; + */ + public com.google.protobuf.ByteString + getPasswordBytes() { + java.lang.Object ref = password_; + if (ref instanceof java.lang.String) { + com.google.protobuf.ByteString b = + com.google.protobuf.ByteString.copyFromUtf8( + (java.lang.String) ref); + password_ = b; + return b; + } else { + return (com.google.protobuf.ByteString) ref; + } + } + + public static final int ONLINE_STATUS_FIELD_NUMBER = 3; + private com.mogujie.tt.protobuf.IMBaseDefine.UserStatType onlineStatus_; + /** + * required .IM.BaseDefine.UserStatType online_status = 3; + */ + public boolean hasOnlineStatus() { + return ((bitField0_ & 0x00000004) == 0x00000004); + } + /** + * required .IM.BaseDefine.UserStatType online_status = 3; + */ + public com.mogujie.tt.protobuf.IMBaseDefine.UserStatType getOnlineStatus() { + return onlineStatus_; + } + + public static final int CLIENT_TYPE_FIELD_NUMBER = 4; + private com.mogujie.tt.protobuf.IMBaseDefine.ClientType clientType_; + /** + * required .IM.BaseDefine.ClientType client_type = 4; + */ + public boolean hasClientType() { + return ((bitField0_ & 0x00000008) == 0x00000008); + } + /** + * required .IM.BaseDefine.ClientType client_type = 4; + */ + public com.mogujie.tt.protobuf.IMBaseDefine.ClientType getClientType() { + return clientType_; + } + + public static final int CLIENT_VERSION_FIELD_NUMBER = 5; + private java.lang.Object clientVersion_; + /** + * optional string client_version = 5; + */ + public boolean hasClientVersion() { + return ((bitField0_ & 0x00000010) == 0x00000010); + } + /** + * optional string client_version = 5; + */ + public java.lang.String getClientVersion() { + java.lang.Object ref = clientVersion_; + if (ref instanceof java.lang.String) { + return (java.lang.String) ref; + } else { + com.google.protobuf.ByteString bs = + (com.google.protobuf.ByteString) ref; + java.lang.String s = bs.toStringUtf8(); + if (bs.isValidUtf8()) { + clientVersion_ = s; + } + return s; + } + } + /** + * optional string client_version = 5; + */ + public com.google.protobuf.ByteString + getClientVersionBytes() { + java.lang.Object ref = clientVersion_; + if (ref instanceof java.lang.String) { + com.google.protobuf.ByteString b = + com.google.protobuf.ByteString.copyFromUtf8( + (java.lang.String) ref); + clientVersion_ = b; + return b; + } else { + return (com.google.protobuf.ByteString) ref; + } + } + + private void initFields() { + userName_ = ""; + password_ = ""; + onlineStatus_ = com.mogujie.tt.protobuf.IMBaseDefine.UserStatType.USER_STATUS_ONLINE; + clientType_ = com.mogujie.tt.protobuf.IMBaseDefine.ClientType.CLIENT_TYPE_WINDOWS; + clientVersion_ = ""; + } + private byte memoizedIsInitialized = -1; + public final boolean isInitialized() { + byte isInitialized = memoizedIsInitialized; + if (isInitialized == 1) return true; + if (isInitialized == 0) return false; + + if (!hasUserName()) { + memoizedIsInitialized = 0; + return false; + } + if (!hasPassword()) { + memoizedIsInitialized = 0; + return false; + } + if (!hasOnlineStatus()) { + memoizedIsInitialized = 0; + return false; + } + if (!hasClientType()) { + memoizedIsInitialized = 0; + return false; + } + memoizedIsInitialized = 1; + return true; + } + + public void writeTo(com.google.protobuf.CodedOutputStream output) + throws java.io.IOException { + getSerializedSize(); + if (((bitField0_ & 0x00000001) == 0x00000001)) { + output.writeBytes(1, getUserNameBytes()); + } + if (((bitField0_ & 0x00000002) == 0x00000002)) { + output.writeBytes(2, getPasswordBytes()); + } + if (((bitField0_ & 0x00000004) == 0x00000004)) { + output.writeEnum(3, onlineStatus_.getNumber()); + } + if (((bitField0_ & 0x00000008) == 0x00000008)) { + output.writeEnum(4, clientType_.getNumber()); + } + if (((bitField0_ & 0x00000010) == 0x00000010)) { + output.writeBytes(5, getClientVersionBytes()); + } + output.writeRawBytes(unknownFields); + } + + private int memoizedSerializedSize = -1; + public int getSerializedSize() { + int size = memoizedSerializedSize; + if (size != -1) return size; + + size = 0; + if (((bitField0_ & 0x00000001) == 0x00000001)) { + size += com.google.protobuf.CodedOutputStream + .computeBytesSize(1, getUserNameBytes()); + } + if (((bitField0_ & 0x00000002) == 0x00000002)) { + size += com.google.protobuf.CodedOutputStream + .computeBytesSize(2, getPasswordBytes()); + } + if (((bitField0_ & 0x00000004) == 0x00000004)) { + size += com.google.protobuf.CodedOutputStream + .computeEnumSize(3, onlineStatus_.getNumber()); + } + if (((bitField0_ & 0x00000008) == 0x00000008)) { + size += com.google.protobuf.CodedOutputStream + .computeEnumSize(4, clientType_.getNumber()); + } + if (((bitField0_ & 0x00000010) == 0x00000010)) { + size += com.google.protobuf.CodedOutputStream + .computeBytesSize(5, getClientVersionBytes()); + } + size += unknownFields.size(); + memoizedSerializedSize = size; + return size; + } + + private static final long serialVersionUID = 0L; + @java.lang.Override + protected java.lang.Object writeReplace() + throws java.io.ObjectStreamException { + return super.writeReplace(); + } + + public static com.mogujie.tt.protobuf.IMLogin.IMLoginReq parseFrom( + com.google.protobuf.ByteString data) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data); + } + public static com.mogujie.tt.protobuf.IMLogin.IMLoginReq parseFrom( + com.google.protobuf.ByteString data, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data, extensionRegistry); + } + public static com.mogujie.tt.protobuf.IMLogin.IMLoginReq parseFrom(byte[] data) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data); + } + public static com.mogujie.tt.protobuf.IMLogin.IMLoginReq parseFrom( + byte[] data, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data, extensionRegistry); + } + public static com.mogujie.tt.protobuf.IMLogin.IMLoginReq parseFrom(java.io.InputStream input) + throws java.io.IOException { + return PARSER.parseFrom(input); + } + public static com.mogujie.tt.protobuf.IMLogin.IMLoginReq parseFrom( + java.io.InputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return PARSER.parseFrom(input, extensionRegistry); + } + public static com.mogujie.tt.protobuf.IMLogin.IMLoginReq parseDelimitedFrom(java.io.InputStream input) + throws java.io.IOException { + return PARSER.parseDelimitedFrom(input); + } + public static com.mogujie.tt.protobuf.IMLogin.IMLoginReq parseDelimitedFrom( + java.io.InputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return PARSER.parseDelimitedFrom(input, extensionRegistry); + } + public static com.mogujie.tt.protobuf.IMLogin.IMLoginReq parseFrom( + com.google.protobuf.CodedInputStream input) + throws java.io.IOException { + return PARSER.parseFrom(input); + } + public static com.mogujie.tt.protobuf.IMLogin.IMLoginReq parseFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return PARSER.parseFrom(input, extensionRegistry); + } + + public static Builder newBuilder() { return Builder.create(); } + public Builder newBuilderForType() { return newBuilder(); } + public static Builder newBuilder(com.mogujie.tt.protobuf.IMLogin.IMLoginReq prototype) { + return newBuilder().mergeFrom(prototype); + } + public Builder toBuilder() { return newBuilder(this); } + + /** + * Protobuf type {@code IM.Login.IMLoginReq} + */ + public static final class Builder extends + com.google.protobuf.GeneratedMessageLite.Builder< + com.mogujie.tt.protobuf.IMLogin.IMLoginReq, Builder> + implements + // @@protoc_insertion_point(builder_implements:IM.Login.IMLoginReq) + com.mogujie.tt.protobuf.IMLogin.IMLoginReqOrBuilder { + // Construct using com.mogujie.tt.protobuf.IMLogin.IMLoginReq.newBuilder() + private Builder() { + maybeForceBuilderInitialization(); + } + + private void maybeForceBuilderInitialization() { + } + private static Builder create() { + return new Builder(); + } + + public Builder clear() { + super.clear(); + userName_ = ""; + bitField0_ = (bitField0_ & ~0x00000001); + password_ = ""; + bitField0_ = (bitField0_ & ~0x00000002); + onlineStatus_ = com.mogujie.tt.protobuf.IMBaseDefine.UserStatType.USER_STATUS_ONLINE; + bitField0_ = (bitField0_ & ~0x00000004); + clientType_ = com.mogujie.tt.protobuf.IMBaseDefine.ClientType.CLIENT_TYPE_WINDOWS; + bitField0_ = (bitField0_ & ~0x00000008); + clientVersion_ = ""; + bitField0_ = (bitField0_ & ~0x00000010); + return this; + } + + public Builder clone() { + return create().mergeFrom(buildPartial()); + } + + public com.mogujie.tt.protobuf.IMLogin.IMLoginReq getDefaultInstanceForType() { + return com.mogujie.tt.protobuf.IMLogin.IMLoginReq.getDefaultInstance(); + } + + public com.mogujie.tt.protobuf.IMLogin.IMLoginReq build() { + com.mogujie.tt.protobuf.IMLogin.IMLoginReq result = buildPartial(); + if (!result.isInitialized()) { + throw newUninitializedMessageException(result); + } + return result; + } + + public com.mogujie.tt.protobuf.IMLogin.IMLoginReq buildPartial() { + com.mogujie.tt.protobuf.IMLogin.IMLoginReq result = new com.mogujie.tt.protobuf.IMLogin.IMLoginReq(this); + int from_bitField0_ = bitField0_; + int to_bitField0_ = 0; + if (((from_bitField0_ & 0x00000001) == 0x00000001)) { + to_bitField0_ |= 0x00000001; + } + result.userName_ = userName_; + if (((from_bitField0_ & 0x00000002) == 0x00000002)) { + to_bitField0_ |= 0x00000002; + } + result.password_ = password_; + if (((from_bitField0_ & 0x00000004) == 0x00000004)) { + to_bitField0_ |= 0x00000004; + } + result.onlineStatus_ = onlineStatus_; + if (((from_bitField0_ & 0x00000008) == 0x00000008)) { + to_bitField0_ |= 0x00000008; + } + result.clientType_ = clientType_; + if (((from_bitField0_ & 0x00000010) == 0x00000010)) { + to_bitField0_ |= 0x00000010; + } + result.clientVersion_ = clientVersion_; + result.bitField0_ = to_bitField0_; + return result; + } + + public Builder mergeFrom(com.mogujie.tt.protobuf.IMLogin.IMLoginReq other) { + if (other == com.mogujie.tt.protobuf.IMLogin.IMLoginReq.getDefaultInstance()) return this; + if (other.hasUserName()) { + bitField0_ |= 0x00000001; + userName_ = other.userName_; + + } + if (other.hasPassword()) { + bitField0_ |= 0x00000002; + password_ = other.password_; + + } + if (other.hasOnlineStatus()) { + setOnlineStatus(other.getOnlineStatus()); + } + if (other.hasClientType()) { + setClientType(other.getClientType()); + } + if (other.hasClientVersion()) { + bitField0_ |= 0x00000010; + clientVersion_ = other.clientVersion_; + + } + setUnknownFields( + getUnknownFields().concat(other.unknownFields)); + return this; + } + + public final boolean isInitialized() { + if (!hasUserName()) { + + return false; + } + if (!hasPassword()) { + + return false; + } + if (!hasOnlineStatus()) { + + return false; + } + if (!hasClientType()) { + + return false; + } + return true; + } + + public Builder mergeFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + com.mogujie.tt.protobuf.IMLogin.IMLoginReq parsedMessage = null; + try { + parsedMessage = PARSER.parsePartialFrom(input, extensionRegistry); + } catch (com.google.protobuf.InvalidProtocolBufferException e) { + parsedMessage = (com.mogujie.tt.protobuf.IMLogin.IMLoginReq) e.getUnfinishedMessage(); + throw e; + } finally { + if (parsedMessage != null) { + mergeFrom(parsedMessage); + } + } + return this; + } + private int bitField0_; + + private java.lang.Object userName_ = ""; + /** + * required string user_name = 1; + * + *
+       *cmd id:		0x0103
+       * 
+ */ + public boolean hasUserName() { + return ((bitField0_ & 0x00000001) == 0x00000001); + } + /** + * required string user_name = 1; + * + *
+       *cmd id:		0x0103
+       * 
+ */ + public java.lang.String getUserName() { + java.lang.Object ref = userName_; + if (!(ref instanceof java.lang.String)) { + com.google.protobuf.ByteString bs = + (com.google.protobuf.ByteString) ref; + java.lang.String s = bs.toStringUtf8(); + if (bs.isValidUtf8()) { + userName_ = s; + } + return s; + } else { + return (java.lang.String) ref; + } + } + /** + * required string user_name = 1; + * + *
+       *cmd id:		0x0103
+       * 
+ */ + public com.google.protobuf.ByteString + getUserNameBytes() { + java.lang.Object ref = userName_; + if (ref instanceof String) { + com.google.protobuf.ByteString b = + com.google.protobuf.ByteString.copyFromUtf8( + (java.lang.String) ref); + userName_ = b; + return b; + } else { + return (com.google.protobuf.ByteString) ref; + } + } + /** + * required string user_name = 1; + * + *
+       *cmd id:		0x0103
+       * 
+ */ + public Builder setUserName( + java.lang.String value) { + if (value == null) { + throw new NullPointerException(); + } + bitField0_ |= 0x00000001; + userName_ = value; + + return this; + } + /** + * required string user_name = 1; + * + *
+       *cmd id:		0x0103
+       * 
+ */ + public Builder clearUserName() { + bitField0_ = (bitField0_ & ~0x00000001); + userName_ = getDefaultInstance().getUserName(); + + return this; + } + /** + * required string user_name = 1; + * + *
+       *cmd id:		0x0103
+       * 
+ */ + public Builder setUserNameBytes( + com.google.protobuf.ByteString value) { + if (value == null) { + throw new NullPointerException(); + } + bitField0_ |= 0x00000001; + userName_ = value; + + return this; + } + + private java.lang.Object password_ = ""; + /** + * required string password = 2; + */ + public boolean hasPassword() { + return ((bitField0_ & 0x00000002) == 0x00000002); + } + /** + * required string password = 2; + */ + public java.lang.String getPassword() { + java.lang.Object ref = password_; + if (!(ref instanceof java.lang.String)) { + com.google.protobuf.ByteString bs = + (com.google.protobuf.ByteString) ref; + java.lang.String s = bs.toStringUtf8(); + if (bs.isValidUtf8()) { + password_ = s; + } + return s; + } else { + return (java.lang.String) ref; + } + } + /** + * required string password = 2; + */ + public com.google.protobuf.ByteString + getPasswordBytes() { + java.lang.Object ref = password_; + if (ref instanceof String) { + com.google.protobuf.ByteString b = + com.google.protobuf.ByteString.copyFromUtf8( + (java.lang.String) ref); + password_ = b; + return b; + } else { + return (com.google.protobuf.ByteString) ref; + } + } + /** + * required string password = 2; + */ + public Builder setPassword( + java.lang.String value) { + if (value == null) { + throw new NullPointerException(); + } + bitField0_ |= 0x00000002; + password_ = value; + + return this; + } + /** + * required string password = 2; + */ + public Builder clearPassword() { + bitField0_ = (bitField0_ & ~0x00000002); + password_ = getDefaultInstance().getPassword(); + + return this; + } + /** + * required string password = 2; + */ + public Builder setPasswordBytes( + com.google.protobuf.ByteString value) { + if (value == null) { + throw new NullPointerException(); + } + bitField0_ |= 0x00000002; + password_ = value; + + return this; + } + + private com.mogujie.tt.protobuf.IMBaseDefine.UserStatType onlineStatus_ = com.mogujie.tt.protobuf.IMBaseDefine.UserStatType.USER_STATUS_ONLINE; + /** + * required .IM.BaseDefine.UserStatType online_status = 3; + */ + public boolean hasOnlineStatus() { + return ((bitField0_ & 0x00000004) == 0x00000004); + } + /** + * required .IM.BaseDefine.UserStatType online_status = 3; + */ + public com.mogujie.tt.protobuf.IMBaseDefine.UserStatType getOnlineStatus() { + return onlineStatus_; + } + /** + * required .IM.BaseDefine.UserStatType online_status = 3; + */ + public Builder setOnlineStatus(com.mogujie.tt.protobuf.IMBaseDefine.UserStatType value) { + if (value == null) { + throw new NullPointerException(); + } + bitField0_ |= 0x00000004; + onlineStatus_ = value; + + return this; + } + /** + * required .IM.BaseDefine.UserStatType online_status = 3; + */ + public Builder clearOnlineStatus() { + bitField0_ = (bitField0_ & ~0x00000004); + onlineStatus_ = com.mogujie.tt.protobuf.IMBaseDefine.UserStatType.USER_STATUS_ONLINE; + + return this; + } + + private com.mogujie.tt.protobuf.IMBaseDefine.ClientType clientType_ = com.mogujie.tt.protobuf.IMBaseDefine.ClientType.CLIENT_TYPE_WINDOWS; + /** + * required .IM.BaseDefine.ClientType client_type = 4; + */ + public boolean hasClientType() { + return ((bitField0_ & 0x00000008) == 0x00000008); + } + /** + * required .IM.BaseDefine.ClientType client_type = 4; + */ + public com.mogujie.tt.protobuf.IMBaseDefine.ClientType getClientType() { + return clientType_; + } + /** + * required .IM.BaseDefine.ClientType client_type = 4; + */ + public Builder setClientType(com.mogujie.tt.protobuf.IMBaseDefine.ClientType value) { + if (value == null) { + throw new NullPointerException(); + } + bitField0_ |= 0x00000008; + clientType_ = value; + + return this; + } + /** + * required .IM.BaseDefine.ClientType client_type = 4; + */ + public Builder clearClientType() { + bitField0_ = (bitField0_ & ~0x00000008); + clientType_ = com.mogujie.tt.protobuf.IMBaseDefine.ClientType.CLIENT_TYPE_WINDOWS; + + return this; + } + + private java.lang.Object clientVersion_ = ""; + /** + * optional string client_version = 5; + */ + public boolean hasClientVersion() { + return ((bitField0_ & 0x00000010) == 0x00000010); + } + /** + * optional string client_version = 5; + */ + public java.lang.String getClientVersion() { + java.lang.Object ref = clientVersion_; + if (!(ref instanceof java.lang.String)) { + com.google.protobuf.ByteString bs = + (com.google.protobuf.ByteString) ref; + java.lang.String s = bs.toStringUtf8(); + if (bs.isValidUtf8()) { + clientVersion_ = s; + } + return s; + } else { + return (java.lang.String) ref; + } + } + /** + * optional string client_version = 5; + */ + public com.google.protobuf.ByteString + getClientVersionBytes() { + java.lang.Object ref = clientVersion_; + if (ref instanceof String) { + com.google.protobuf.ByteString b = + com.google.protobuf.ByteString.copyFromUtf8( + (java.lang.String) ref); + clientVersion_ = b; + return b; + } else { + return (com.google.protobuf.ByteString) ref; + } + } + /** + * optional string client_version = 5; + */ + public Builder setClientVersion( + java.lang.String value) { + if (value == null) { + throw new NullPointerException(); + } + bitField0_ |= 0x00000010; + clientVersion_ = value; + + return this; + } + /** + * optional string client_version = 5; + */ + public Builder clearClientVersion() { + bitField0_ = (bitField0_ & ~0x00000010); + clientVersion_ = getDefaultInstance().getClientVersion(); + + return this; + } + /** + * optional string client_version = 5; + */ + public Builder setClientVersionBytes( + com.google.protobuf.ByteString value) { + if (value == null) { + throw new NullPointerException(); + } + bitField0_ |= 0x00000010; + clientVersion_ = value; + + return this; + } + + // @@protoc_insertion_point(builder_scope:IM.Login.IMLoginReq) + } + + static { + defaultInstance = new IMLoginReq(true); + defaultInstance.initFields(); + } + + // @@protoc_insertion_point(class_scope:IM.Login.IMLoginReq) + } + + public interface IMLoginResOrBuilder extends + // @@protoc_insertion_point(interface_extends:IM.Login.IMLoginRes) + com.google.protobuf.MessageLiteOrBuilder { + + /** + * required uint32 server_time = 1; + * + *
+     *cmd id:		0x0104
+     * 
+ */ + boolean hasServerTime(); + /** + * required uint32 server_time = 1; + * + *
+     *cmd id:		0x0104
+     * 
+ */ + int getServerTime(); + + /** + * required .IM.BaseDefine.ResultType result_code = 2; + */ + boolean hasResultCode(); + /** + * required .IM.BaseDefine.ResultType result_code = 2; + */ + com.mogujie.tt.protobuf.IMBaseDefine.ResultType getResultCode(); + + /** + * optional string result_string = 3; + */ + boolean hasResultString(); + /** + * optional string result_string = 3; + */ + java.lang.String getResultString(); + /** + * optional string result_string = 3; + */ + com.google.protobuf.ByteString + getResultStringBytes(); + + /** + * optional .IM.BaseDefine.UserStatType online_status = 4; + */ + boolean hasOnlineStatus(); + /** + * optional .IM.BaseDefine.UserStatType online_status = 4; + */ + com.mogujie.tt.protobuf.IMBaseDefine.UserStatType getOnlineStatus(); + + /** + * optional .IM.BaseDefine.UserInfo user_info = 5; + */ + boolean hasUserInfo(); + /** + * optional .IM.BaseDefine.UserInfo user_info = 5; + */ + com.mogujie.tt.protobuf.IMBaseDefine.UserInfo getUserInfo(); + } + /** + * Protobuf type {@code IM.Login.IMLoginRes} + */ + public static final class IMLoginRes extends + com.google.protobuf.GeneratedMessageLite implements + // @@protoc_insertion_point(message_implements:IM.Login.IMLoginRes) + IMLoginResOrBuilder { + // Use IMLoginRes.newBuilder() to construct. + private IMLoginRes(com.google.protobuf.GeneratedMessageLite.Builder builder) { + super(builder); + this.unknownFields = builder.getUnknownFields(); + } + private IMLoginRes(boolean noInit) { this.unknownFields = com.google.protobuf.ByteString.EMPTY;} + + private static final IMLoginRes defaultInstance; + public static IMLoginRes getDefaultInstance() { + return defaultInstance; + } + + public IMLoginRes getDefaultInstanceForType() { + return defaultInstance; + } + + private final com.google.protobuf.ByteString unknownFields; + private IMLoginRes( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + initFields(); + int mutable_bitField0_ = 0; + com.google.protobuf.ByteString.Output unknownFieldsOutput = + com.google.protobuf.ByteString.newOutput(); + com.google.protobuf.CodedOutputStream unknownFieldsCodedOutput = + com.google.protobuf.CodedOutputStream.newInstance( + unknownFieldsOutput); + try { + boolean done = false; + while (!done) { + int tag = input.readTag(); + switch (tag) { + case 0: + done = true; + break; + default: { + if (!parseUnknownField(input, unknownFieldsCodedOutput, + extensionRegistry, tag)) { + done = true; + } + break; + } + case 8: { + bitField0_ |= 0x00000001; + serverTime_ = input.readUInt32(); + break; + } + case 16: { + int rawValue = input.readEnum(); + com.mogujie.tt.protobuf.IMBaseDefine.ResultType value = com.mogujie.tt.protobuf.IMBaseDefine.ResultType.valueOf(rawValue); + if (value == null) { + unknownFieldsCodedOutput.writeRawVarint32(tag); + unknownFieldsCodedOutput.writeRawVarint32(rawValue); + } else { + bitField0_ |= 0x00000002; + resultCode_ = value; + } + break; + } + case 26: { + com.google.protobuf.ByteString bs = input.readBytes(); + bitField0_ |= 0x00000004; + resultString_ = bs; + break; + } + case 32: { + int rawValue = input.readEnum(); + com.mogujie.tt.protobuf.IMBaseDefine.UserStatType value = com.mogujie.tt.protobuf.IMBaseDefine.UserStatType.valueOf(rawValue); + if (value == null) { + unknownFieldsCodedOutput.writeRawVarint32(tag); + unknownFieldsCodedOutput.writeRawVarint32(rawValue); + } else { + bitField0_ |= 0x00000008; + onlineStatus_ = value; + } + break; + } + case 42: { + com.mogujie.tt.protobuf.IMBaseDefine.UserInfo.Builder subBuilder = null; + if (((bitField0_ & 0x00000010) == 0x00000010)) { + subBuilder = userInfo_.toBuilder(); + } + userInfo_ = input.readMessage(com.mogujie.tt.protobuf.IMBaseDefine.UserInfo.PARSER, extensionRegistry); + if (subBuilder != null) { + subBuilder.mergeFrom(userInfo_); + userInfo_ = subBuilder.buildPartial(); + } + bitField0_ |= 0x00000010; + break; + } + } + } + } catch (com.google.protobuf.InvalidProtocolBufferException e) { + throw e.setUnfinishedMessage(this); + } catch (java.io.IOException e) { + throw new com.google.protobuf.InvalidProtocolBufferException( + e.getMessage()).setUnfinishedMessage(this); + } finally { + try { + unknownFieldsCodedOutput.flush(); + } catch (java.io.IOException e) { + // Should not happen + } finally { + unknownFields = unknownFieldsOutput.toByteString(); + } + makeExtensionsImmutable(); + } + } + public static com.google.protobuf.Parser PARSER = + new com.google.protobuf.AbstractParser() { + public IMLoginRes parsePartialFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return new IMLoginRes(input, extensionRegistry); + } + }; + + @java.lang.Override + public com.google.protobuf.Parser getParserForType() { + return PARSER; + } + + private int bitField0_; + public static final int SERVER_TIME_FIELD_NUMBER = 1; + private int serverTime_; + /** + * required uint32 server_time = 1; + * + *
+     *cmd id:		0x0104
+     * 
+ */ + public boolean hasServerTime() { + return ((bitField0_ & 0x00000001) == 0x00000001); + } + /** + * required uint32 server_time = 1; + * + *
+     *cmd id:		0x0104
+     * 
+ */ + public int getServerTime() { + return serverTime_; + } + + public static final int RESULT_CODE_FIELD_NUMBER = 2; + private com.mogujie.tt.protobuf.IMBaseDefine.ResultType resultCode_; + /** + * required .IM.BaseDefine.ResultType result_code = 2; + */ + public boolean hasResultCode() { + return ((bitField0_ & 0x00000002) == 0x00000002); + } + /** + * required .IM.BaseDefine.ResultType result_code = 2; + */ + public com.mogujie.tt.protobuf.IMBaseDefine.ResultType getResultCode() { + return resultCode_; + } + + public static final int RESULT_STRING_FIELD_NUMBER = 3; + private java.lang.Object resultString_; + /** + * optional string result_string = 3; + */ + public boolean hasResultString() { + return ((bitField0_ & 0x00000004) == 0x00000004); + } + /** + * optional string result_string = 3; + */ + public java.lang.String getResultString() { + java.lang.Object ref = resultString_; + if (ref instanceof java.lang.String) { + return (java.lang.String) ref; + } else { + com.google.protobuf.ByteString bs = + (com.google.protobuf.ByteString) ref; + java.lang.String s = bs.toStringUtf8(); + if (bs.isValidUtf8()) { + resultString_ = s; + } + return s; + } + } + /** + * optional string result_string = 3; + */ + public com.google.protobuf.ByteString + getResultStringBytes() { + java.lang.Object ref = resultString_; + if (ref instanceof java.lang.String) { + com.google.protobuf.ByteString b = + com.google.protobuf.ByteString.copyFromUtf8( + (java.lang.String) ref); + resultString_ = b; + return b; + } else { + return (com.google.protobuf.ByteString) ref; + } + } + + public static final int ONLINE_STATUS_FIELD_NUMBER = 4; + private com.mogujie.tt.protobuf.IMBaseDefine.UserStatType onlineStatus_; + /** + * optional .IM.BaseDefine.UserStatType online_status = 4; + */ + public boolean hasOnlineStatus() { + return ((bitField0_ & 0x00000008) == 0x00000008); + } + /** + * optional .IM.BaseDefine.UserStatType online_status = 4; + */ + public com.mogujie.tt.protobuf.IMBaseDefine.UserStatType getOnlineStatus() { + return onlineStatus_; + } + + public static final int USER_INFO_FIELD_NUMBER = 5; + private com.mogujie.tt.protobuf.IMBaseDefine.UserInfo userInfo_; + /** + * optional .IM.BaseDefine.UserInfo user_info = 5; + */ + public boolean hasUserInfo() { + return ((bitField0_ & 0x00000010) == 0x00000010); + } + /** + * optional .IM.BaseDefine.UserInfo user_info = 5; + */ + public com.mogujie.tt.protobuf.IMBaseDefine.UserInfo getUserInfo() { + return userInfo_; + } + + private void initFields() { + serverTime_ = 0; + resultCode_ = com.mogujie.tt.protobuf.IMBaseDefine.ResultType.REFUSE_REASON_NONE; + resultString_ = ""; + onlineStatus_ = com.mogujie.tt.protobuf.IMBaseDefine.UserStatType.USER_STATUS_ONLINE; + userInfo_ = com.mogujie.tt.protobuf.IMBaseDefine.UserInfo.getDefaultInstance(); + } + private byte memoizedIsInitialized = -1; + public final boolean isInitialized() { + byte isInitialized = memoizedIsInitialized; + if (isInitialized == 1) return true; + if (isInitialized == 0) return false; + + if (!hasServerTime()) { + memoizedIsInitialized = 0; + return false; + } + if (!hasResultCode()) { + memoizedIsInitialized = 0; + return false; + } + if (hasUserInfo()) { + if (!getUserInfo().isInitialized()) { + memoizedIsInitialized = 0; + return false; + } + } + memoizedIsInitialized = 1; + return true; + } + + public void writeTo(com.google.protobuf.CodedOutputStream output) + throws java.io.IOException { + getSerializedSize(); + if (((bitField0_ & 0x00000001) == 0x00000001)) { + output.writeUInt32(1, serverTime_); + } + if (((bitField0_ & 0x00000002) == 0x00000002)) { + output.writeEnum(2, resultCode_.getNumber()); + } + if (((bitField0_ & 0x00000004) == 0x00000004)) { + output.writeBytes(3, getResultStringBytes()); + } + if (((bitField0_ & 0x00000008) == 0x00000008)) { + output.writeEnum(4, onlineStatus_.getNumber()); + } + if (((bitField0_ & 0x00000010) == 0x00000010)) { + output.writeMessage(5, userInfo_); + } + output.writeRawBytes(unknownFields); + } + + private int memoizedSerializedSize = -1; + public int getSerializedSize() { + int size = memoizedSerializedSize; + if (size != -1) return size; + + size = 0; + if (((bitField0_ & 0x00000001) == 0x00000001)) { + size += com.google.protobuf.CodedOutputStream + .computeUInt32Size(1, serverTime_); + } + if (((bitField0_ & 0x00000002) == 0x00000002)) { + size += com.google.protobuf.CodedOutputStream + .computeEnumSize(2, resultCode_.getNumber()); + } + if (((bitField0_ & 0x00000004) == 0x00000004)) { + size += com.google.protobuf.CodedOutputStream + .computeBytesSize(3, getResultStringBytes()); + } + if (((bitField0_ & 0x00000008) == 0x00000008)) { + size += com.google.protobuf.CodedOutputStream + .computeEnumSize(4, onlineStatus_.getNumber()); + } + if (((bitField0_ & 0x00000010) == 0x00000010)) { + size += com.google.protobuf.CodedOutputStream + .computeMessageSize(5, userInfo_); + } + size += unknownFields.size(); + memoizedSerializedSize = size; + return size; + } + + private static final long serialVersionUID = 0L; + @java.lang.Override + protected java.lang.Object writeReplace() + throws java.io.ObjectStreamException { + return super.writeReplace(); + } + + public static com.mogujie.tt.protobuf.IMLogin.IMLoginRes parseFrom( + com.google.protobuf.ByteString data) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data); + } + public static com.mogujie.tt.protobuf.IMLogin.IMLoginRes parseFrom( + com.google.protobuf.ByteString data, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data, extensionRegistry); + } + public static com.mogujie.tt.protobuf.IMLogin.IMLoginRes parseFrom(byte[] data) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data); + } + public static com.mogujie.tt.protobuf.IMLogin.IMLoginRes parseFrom( + byte[] data, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data, extensionRegistry); + } + public static com.mogujie.tt.protobuf.IMLogin.IMLoginRes parseFrom(java.io.InputStream input) + throws java.io.IOException { + return PARSER.parseFrom(input); + } + public static com.mogujie.tt.protobuf.IMLogin.IMLoginRes parseFrom( + java.io.InputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return PARSER.parseFrom(input, extensionRegistry); + } + public static com.mogujie.tt.protobuf.IMLogin.IMLoginRes parseDelimitedFrom(java.io.InputStream input) + throws java.io.IOException { + return PARSER.parseDelimitedFrom(input); + } + public static com.mogujie.tt.protobuf.IMLogin.IMLoginRes parseDelimitedFrom( + java.io.InputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return PARSER.parseDelimitedFrom(input, extensionRegistry); + } + public static com.mogujie.tt.protobuf.IMLogin.IMLoginRes parseFrom( + com.google.protobuf.CodedInputStream input) + throws java.io.IOException { + return PARSER.parseFrom(input); + } + public static com.mogujie.tt.protobuf.IMLogin.IMLoginRes parseFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return PARSER.parseFrom(input, extensionRegistry); + } + + public static Builder newBuilder() { return Builder.create(); } + public Builder newBuilderForType() { return newBuilder(); } + public static Builder newBuilder(com.mogujie.tt.protobuf.IMLogin.IMLoginRes prototype) { + return newBuilder().mergeFrom(prototype); + } + public Builder toBuilder() { return newBuilder(this); } + + /** + * Protobuf type {@code IM.Login.IMLoginRes} + */ + public static final class Builder extends + com.google.protobuf.GeneratedMessageLite.Builder< + com.mogujie.tt.protobuf.IMLogin.IMLoginRes, Builder> + implements + // @@protoc_insertion_point(builder_implements:IM.Login.IMLoginRes) + com.mogujie.tt.protobuf.IMLogin.IMLoginResOrBuilder { + // Construct using com.mogujie.tt.protobuf.IMLogin.IMLoginRes.newBuilder() + private Builder() { + maybeForceBuilderInitialization(); + } + + private void maybeForceBuilderInitialization() { + } + private static Builder create() { + return new Builder(); + } + + public Builder clear() { + super.clear(); + serverTime_ = 0; + bitField0_ = (bitField0_ & ~0x00000001); + resultCode_ = com.mogujie.tt.protobuf.IMBaseDefine.ResultType.REFUSE_REASON_NONE; + bitField0_ = (bitField0_ & ~0x00000002); + resultString_ = ""; + bitField0_ = (bitField0_ & ~0x00000004); + onlineStatus_ = com.mogujie.tt.protobuf.IMBaseDefine.UserStatType.USER_STATUS_ONLINE; + bitField0_ = (bitField0_ & ~0x00000008); + userInfo_ = com.mogujie.tt.protobuf.IMBaseDefine.UserInfo.getDefaultInstance(); + bitField0_ = (bitField0_ & ~0x00000010); + return this; + } + + public Builder clone() { + return create().mergeFrom(buildPartial()); + } + + public com.mogujie.tt.protobuf.IMLogin.IMLoginRes getDefaultInstanceForType() { + return com.mogujie.tt.protobuf.IMLogin.IMLoginRes.getDefaultInstance(); + } + + public com.mogujie.tt.protobuf.IMLogin.IMLoginRes build() { + com.mogujie.tt.protobuf.IMLogin.IMLoginRes result = buildPartial(); + if (!result.isInitialized()) { + throw newUninitializedMessageException(result); + } + return result; + } + + public com.mogujie.tt.protobuf.IMLogin.IMLoginRes buildPartial() { + com.mogujie.tt.protobuf.IMLogin.IMLoginRes result = new com.mogujie.tt.protobuf.IMLogin.IMLoginRes(this); + int from_bitField0_ = bitField0_; + int to_bitField0_ = 0; + if (((from_bitField0_ & 0x00000001) == 0x00000001)) { + to_bitField0_ |= 0x00000001; + } + result.serverTime_ = serverTime_; + if (((from_bitField0_ & 0x00000002) == 0x00000002)) { + to_bitField0_ |= 0x00000002; + } + result.resultCode_ = resultCode_; + if (((from_bitField0_ & 0x00000004) == 0x00000004)) { + to_bitField0_ |= 0x00000004; + } + result.resultString_ = resultString_; + if (((from_bitField0_ & 0x00000008) == 0x00000008)) { + to_bitField0_ |= 0x00000008; + } + result.onlineStatus_ = onlineStatus_; + if (((from_bitField0_ & 0x00000010) == 0x00000010)) { + to_bitField0_ |= 0x00000010; + } + result.userInfo_ = userInfo_; + result.bitField0_ = to_bitField0_; + return result; + } + + public Builder mergeFrom(com.mogujie.tt.protobuf.IMLogin.IMLoginRes other) { + if (other == com.mogujie.tt.protobuf.IMLogin.IMLoginRes.getDefaultInstance()) return this; + if (other.hasServerTime()) { + setServerTime(other.getServerTime()); + } + if (other.hasResultCode()) { + setResultCode(other.getResultCode()); + } + if (other.hasResultString()) { + bitField0_ |= 0x00000004; + resultString_ = other.resultString_; + + } + if (other.hasOnlineStatus()) { + setOnlineStatus(other.getOnlineStatus()); + } + if (other.hasUserInfo()) { + mergeUserInfo(other.getUserInfo()); + } + setUnknownFields( + getUnknownFields().concat(other.unknownFields)); + return this; + } + + public final boolean isInitialized() { + if (!hasServerTime()) { + + return false; + } + if (!hasResultCode()) { + + return false; + } + if (hasUserInfo()) { + if (!getUserInfo().isInitialized()) { + + return false; + } + } + return true; + } + + public Builder mergeFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + com.mogujie.tt.protobuf.IMLogin.IMLoginRes parsedMessage = null; + try { + parsedMessage = PARSER.parsePartialFrom(input, extensionRegistry); + } catch (com.google.protobuf.InvalidProtocolBufferException e) { + parsedMessage = (com.mogujie.tt.protobuf.IMLogin.IMLoginRes) e.getUnfinishedMessage(); + throw e; + } finally { + if (parsedMessage != null) { + mergeFrom(parsedMessage); + } + } + return this; + } + private int bitField0_; + + private int serverTime_ ; + /** + * required uint32 server_time = 1; + * + *
+       *cmd id:		0x0104
+       * 
+ */ + public boolean hasServerTime() { + return ((bitField0_ & 0x00000001) == 0x00000001); + } + /** + * required uint32 server_time = 1; + * + *
+       *cmd id:		0x0104
+       * 
+ */ + public int getServerTime() { + return serverTime_; + } + /** + * required uint32 server_time = 1; + * + *
+       *cmd id:		0x0104
+       * 
+ */ + public Builder setServerTime(int value) { + bitField0_ |= 0x00000001; + serverTime_ = value; + + return this; + } + /** + * required uint32 server_time = 1; + * + *
+       *cmd id:		0x0104
+       * 
+ */ + public Builder clearServerTime() { + bitField0_ = (bitField0_ & ~0x00000001); + serverTime_ = 0; + + return this; + } + + private com.mogujie.tt.protobuf.IMBaseDefine.ResultType resultCode_ = com.mogujie.tt.protobuf.IMBaseDefine.ResultType.REFUSE_REASON_NONE; + /** + * required .IM.BaseDefine.ResultType result_code = 2; + */ + public boolean hasResultCode() { + return ((bitField0_ & 0x00000002) == 0x00000002); + } + /** + * required .IM.BaseDefine.ResultType result_code = 2; + */ + public com.mogujie.tt.protobuf.IMBaseDefine.ResultType getResultCode() { + return resultCode_; + } + /** + * required .IM.BaseDefine.ResultType result_code = 2; + */ + public Builder setResultCode(com.mogujie.tt.protobuf.IMBaseDefine.ResultType value) { + if (value == null) { + throw new NullPointerException(); + } + bitField0_ |= 0x00000002; + resultCode_ = value; + + return this; + } + /** + * required .IM.BaseDefine.ResultType result_code = 2; + */ + public Builder clearResultCode() { + bitField0_ = (bitField0_ & ~0x00000002); + resultCode_ = com.mogujie.tt.protobuf.IMBaseDefine.ResultType.REFUSE_REASON_NONE; + + return this; + } + + private java.lang.Object resultString_ = ""; + /** + * optional string result_string = 3; + */ + public boolean hasResultString() { + return ((bitField0_ & 0x00000004) == 0x00000004); + } + /** + * optional string result_string = 3; + */ + public java.lang.String getResultString() { + java.lang.Object ref = resultString_; + if (!(ref instanceof java.lang.String)) { + com.google.protobuf.ByteString bs = + (com.google.protobuf.ByteString) ref; + java.lang.String s = bs.toStringUtf8(); + if (bs.isValidUtf8()) { + resultString_ = s; + } + return s; + } else { + return (java.lang.String) ref; + } + } + /** + * optional string result_string = 3; + */ + public com.google.protobuf.ByteString + getResultStringBytes() { + java.lang.Object ref = resultString_; + if (ref instanceof String) { + com.google.protobuf.ByteString b = + com.google.protobuf.ByteString.copyFromUtf8( + (java.lang.String) ref); + resultString_ = b; + return b; + } else { + return (com.google.protobuf.ByteString) ref; + } + } + /** + * optional string result_string = 3; + */ + public Builder setResultString( + java.lang.String value) { + if (value == null) { + throw new NullPointerException(); + } + bitField0_ |= 0x00000004; + resultString_ = value; + + return this; + } + /** + * optional string result_string = 3; + */ + public Builder clearResultString() { + bitField0_ = (bitField0_ & ~0x00000004); + resultString_ = getDefaultInstance().getResultString(); + + return this; + } + /** + * optional string result_string = 3; + */ + public Builder setResultStringBytes( + com.google.protobuf.ByteString value) { + if (value == null) { + throw new NullPointerException(); + } + bitField0_ |= 0x00000004; + resultString_ = value; + + return this; + } + + private com.mogujie.tt.protobuf.IMBaseDefine.UserStatType onlineStatus_ = com.mogujie.tt.protobuf.IMBaseDefine.UserStatType.USER_STATUS_ONLINE; + /** + * optional .IM.BaseDefine.UserStatType online_status = 4; + */ + public boolean hasOnlineStatus() { + return ((bitField0_ & 0x00000008) == 0x00000008); + } + /** + * optional .IM.BaseDefine.UserStatType online_status = 4; + */ + public com.mogujie.tt.protobuf.IMBaseDefine.UserStatType getOnlineStatus() { + return onlineStatus_; + } + /** + * optional .IM.BaseDefine.UserStatType online_status = 4; + */ + public Builder setOnlineStatus(com.mogujie.tt.protobuf.IMBaseDefine.UserStatType value) { + if (value == null) { + throw new NullPointerException(); + } + bitField0_ |= 0x00000008; + onlineStatus_ = value; + + return this; + } + /** + * optional .IM.BaseDefine.UserStatType online_status = 4; + */ + public Builder clearOnlineStatus() { + bitField0_ = (bitField0_ & ~0x00000008); + onlineStatus_ = com.mogujie.tt.protobuf.IMBaseDefine.UserStatType.USER_STATUS_ONLINE; + + return this; + } + + private com.mogujie.tt.protobuf.IMBaseDefine.UserInfo userInfo_ = com.mogujie.tt.protobuf.IMBaseDefine.UserInfo.getDefaultInstance(); + /** + * optional .IM.BaseDefine.UserInfo user_info = 5; + */ + public boolean hasUserInfo() { + return ((bitField0_ & 0x00000010) == 0x00000010); + } + /** + * optional .IM.BaseDefine.UserInfo user_info = 5; + */ + public com.mogujie.tt.protobuf.IMBaseDefine.UserInfo getUserInfo() { + return userInfo_; + } + /** + * optional .IM.BaseDefine.UserInfo user_info = 5; + */ + public Builder setUserInfo(com.mogujie.tt.protobuf.IMBaseDefine.UserInfo value) { + if (value == null) { + throw new NullPointerException(); + } + userInfo_ = value; + + bitField0_ |= 0x00000010; + return this; + } + /** + * optional .IM.BaseDefine.UserInfo user_info = 5; + */ + public Builder setUserInfo( + com.mogujie.tt.protobuf.IMBaseDefine.UserInfo.Builder builderForValue) { + userInfo_ = builderForValue.build(); + + bitField0_ |= 0x00000010; + return this; + } + /** + * optional .IM.BaseDefine.UserInfo user_info = 5; + */ + public Builder mergeUserInfo(com.mogujie.tt.protobuf.IMBaseDefine.UserInfo value) { + if (((bitField0_ & 0x00000010) == 0x00000010) && + userInfo_ != com.mogujie.tt.protobuf.IMBaseDefine.UserInfo.getDefaultInstance()) { + userInfo_ = + com.mogujie.tt.protobuf.IMBaseDefine.UserInfo.newBuilder(userInfo_).mergeFrom(value).buildPartial(); + } else { + userInfo_ = value; + } + + bitField0_ |= 0x00000010; + return this; + } + /** + * optional .IM.BaseDefine.UserInfo user_info = 5; + */ + public Builder clearUserInfo() { + userInfo_ = com.mogujie.tt.protobuf.IMBaseDefine.UserInfo.getDefaultInstance(); + + bitField0_ = (bitField0_ & ~0x00000010); + return this; + } + + // @@protoc_insertion_point(builder_scope:IM.Login.IMLoginRes) + } + + static { + defaultInstance = new IMLoginRes(true); + defaultInstance.initFields(); + } + + // @@protoc_insertion_point(class_scope:IM.Login.IMLoginRes) + } + + public interface IMLogoutReqOrBuilder extends + // @@protoc_insertion_point(interface_extends:IM.Login.IMLogoutReq) + com.google.protobuf.MessageLiteOrBuilder { + } + /** + * Protobuf type {@code IM.Login.IMLogoutReq} + * + *
+   *cmd id:		0x0105
+   * 
+ */ + public static final class IMLogoutReq extends + com.google.protobuf.GeneratedMessageLite implements + // @@protoc_insertion_point(message_implements:IM.Login.IMLogoutReq) + IMLogoutReqOrBuilder { + // Use IMLogoutReq.newBuilder() to construct. + private IMLogoutReq(com.google.protobuf.GeneratedMessageLite.Builder builder) { + super(builder); + this.unknownFields = builder.getUnknownFields(); + } + private IMLogoutReq(boolean noInit) { this.unknownFields = com.google.protobuf.ByteString.EMPTY;} + + private static final IMLogoutReq defaultInstance; + public static IMLogoutReq getDefaultInstance() { + return defaultInstance; + } + + public IMLogoutReq getDefaultInstanceForType() { + return defaultInstance; + } + + private final com.google.protobuf.ByteString unknownFields; + private IMLogoutReq( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + initFields(); + com.google.protobuf.ByteString.Output unknownFieldsOutput = + com.google.protobuf.ByteString.newOutput(); + com.google.protobuf.CodedOutputStream unknownFieldsCodedOutput = + com.google.protobuf.CodedOutputStream.newInstance( + unknownFieldsOutput); + try { + boolean done = false; + while (!done) { + int tag = input.readTag(); + switch (tag) { + case 0: + done = true; + break; + default: { + if (!parseUnknownField(input, unknownFieldsCodedOutput, + extensionRegistry, tag)) { + done = true; + } + break; + } + } + } + } catch (com.google.protobuf.InvalidProtocolBufferException e) { + throw e.setUnfinishedMessage(this); + } catch (java.io.IOException e) { + throw new com.google.protobuf.InvalidProtocolBufferException( + e.getMessage()).setUnfinishedMessage(this); + } finally { + try { + unknownFieldsCodedOutput.flush(); + } catch (java.io.IOException e) { + // Should not happen + } finally { + unknownFields = unknownFieldsOutput.toByteString(); + } + makeExtensionsImmutable(); + } + } + public static com.google.protobuf.Parser PARSER = + new com.google.protobuf.AbstractParser() { + public IMLogoutReq parsePartialFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return new IMLogoutReq(input, extensionRegistry); + } + }; + + @java.lang.Override + public com.google.protobuf.Parser getParserForType() { + return PARSER; + } + + private void initFields() { + } + private byte memoizedIsInitialized = -1; + public final boolean isInitialized() { + byte isInitialized = memoizedIsInitialized; + if (isInitialized == 1) return true; + if (isInitialized == 0) return false; + + memoizedIsInitialized = 1; + return true; + } + + public void writeTo(com.google.protobuf.CodedOutputStream output) + throws java.io.IOException { + getSerializedSize(); + output.writeRawBytes(unknownFields); + } + + private int memoizedSerializedSize = -1; + public int getSerializedSize() { + int size = memoizedSerializedSize; + if (size != -1) return size; + + size = 0; + size += unknownFields.size(); + memoizedSerializedSize = size; + return size; + } + + private static final long serialVersionUID = 0L; + @java.lang.Override + protected java.lang.Object writeReplace() + throws java.io.ObjectStreamException { + return super.writeReplace(); + } + + public static com.mogujie.tt.protobuf.IMLogin.IMLogoutReq parseFrom( + com.google.protobuf.ByteString data) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data); + } + public static com.mogujie.tt.protobuf.IMLogin.IMLogoutReq parseFrom( + com.google.protobuf.ByteString data, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data, extensionRegistry); + } + public static com.mogujie.tt.protobuf.IMLogin.IMLogoutReq parseFrom(byte[] data) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data); + } + public static com.mogujie.tt.protobuf.IMLogin.IMLogoutReq parseFrom( + byte[] data, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data, extensionRegistry); + } + public static com.mogujie.tt.protobuf.IMLogin.IMLogoutReq parseFrom(java.io.InputStream input) + throws java.io.IOException { + return PARSER.parseFrom(input); + } + public static com.mogujie.tt.protobuf.IMLogin.IMLogoutReq parseFrom( + java.io.InputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return PARSER.parseFrom(input, extensionRegistry); + } + public static com.mogujie.tt.protobuf.IMLogin.IMLogoutReq parseDelimitedFrom(java.io.InputStream input) + throws java.io.IOException { + return PARSER.parseDelimitedFrom(input); + } + public static com.mogujie.tt.protobuf.IMLogin.IMLogoutReq parseDelimitedFrom( + java.io.InputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return PARSER.parseDelimitedFrom(input, extensionRegistry); + } + public static com.mogujie.tt.protobuf.IMLogin.IMLogoutReq parseFrom( + com.google.protobuf.CodedInputStream input) + throws java.io.IOException { + return PARSER.parseFrom(input); + } + public static com.mogujie.tt.protobuf.IMLogin.IMLogoutReq parseFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return PARSER.parseFrom(input, extensionRegistry); + } + + public static Builder newBuilder() { return Builder.create(); } + public Builder newBuilderForType() { return newBuilder(); } + public static Builder newBuilder(com.mogujie.tt.protobuf.IMLogin.IMLogoutReq prototype) { + return newBuilder().mergeFrom(prototype); + } + public Builder toBuilder() { return newBuilder(this); } + + /** + * Protobuf type {@code IM.Login.IMLogoutReq} + * + *
+     *cmd id:		0x0105
+     * 
+ */ + public static final class Builder extends + com.google.protobuf.GeneratedMessageLite.Builder< + com.mogujie.tt.protobuf.IMLogin.IMLogoutReq, Builder> + implements + // @@protoc_insertion_point(builder_implements:IM.Login.IMLogoutReq) + com.mogujie.tt.protobuf.IMLogin.IMLogoutReqOrBuilder { + // Construct using com.mogujie.tt.protobuf.IMLogin.IMLogoutReq.newBuilder() + private Builder() { + maybeForceBuilderInitialization(); + } + + private void maybeForceBuilderInitialization() { + } + private static Builder create() { + return new Builder(); + } + + public Builder clear() { + super.clear(); + return this; + } + + public Builder clone() { + return create().mergeFrom(buildPartial()); + } + + public com.mogujie.tt.protobuf.IMLogin.IMLogoutReq getDefaultInstanceForType() { + return com.mogujie.tt.protobuf.IMLogin.IMLogoutReq.getDefaultInstance(); + } + + public com.mogujie.tt.protobuf.IMLogin.IMLogoutReq build() { + com.mogujie.tt.protobuf.IMLogin.IMLogoutReq result = buildPartial(); + if (!result.isInitialized()) { + throw newUninitializedMessageException(result); + } + return result; + } + + public com.mogujie.tt.protobuf.IMLogin.IMLogoutReq buildPartial() { + com.mogujie.tt.protobuf.IMLogin.IMLogoutReq result = new com.mogujie.tt.protobuf.IMLogin.IMLogoutReq(this); + return result; + } + + public Builder mergeFrom(com.mogujie.tt.protobuf.IMLogin.IMLogoutReq other) { + if (other == com.mogujie.tt.protobuf.IMLogin.IMLogoutReq.getDefaultInstance()) return this; + setUnknownFields( + getUnknownFields().concat(other.unknownFields)); + return this; + } + + public final boolean isInitialized() { + return true; + } + + public Builder mergeFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + com.mogujie.tt.protobuf.IMLogin.IMLogoutReq parsedMessage = null; + try { + parsedMessage = PARSER.parsePartialFrom(input, extensionRegistry); + } catch (com.google.protobuf.InvalidProtocolBufferException e) { + parsedMessage = (com.mogujie.tt.protobuf.IMLogin.IMLogoutReq) e.getUnfinishedMessage(); + throw e; + } finally { + if (parsedMessage != null) { + mergeFrom(parsedMessage); + } + } + return this; + } + + // @@protoc_insertion_point(builder_scope:IM.Login.IMLogoutReq) + } + + static { + defaultInstance = new IMLogoutReq(true); + defaultInstance.initFields(); + } + + // @@protoc_insertion_point(class_scope:IM.Login.IMLogoutReq) + } + + public interface IMLogoutRspOrBuilder extends + // @@protoc_insertion_point(interface_extends:IM.Login.IMLogoutRsp) + com.google.protobuf.MessageLiteOrBuilder { + + /** + * required uint32 result_code = 1; + * + *
+     *cmd id:		0x0106
+     * 
+ */ + boolean hasResultCode(); + /** + * required uint32 result_code = 1; + * + *
+     *cmd id:		0x0106
+     * 
+ */ + int getResultCode(); + } + /** + * Protobuf type {@code IM.Login.IMLogoutRsp} + */ + public static final class IMLogoutRsp extends + com.google.protobuf.GeneratedMessageLite implements + // @@protoc_insertion_point(message_implements:IM.Login.IMLogoutRsp) + IMLogoutRspOrBuilder { + // Use IMLogoutRsp.newBuilder() to construct. + private IMLogoutRsp(com.google.protobuf.GeneratedMessageLite.Builder builder) { + super(builder); + this.unknownFields = builder.getUnknownFields(); + } + private IMLogoutRsp(boolean noInit) { this.unknownFields = com.google.protobuf.ByteString.EMPTY;} + + private static final IMLogoutRsp defaultInstance; + public static IMLogoutRsp getDefaultInstance() { + return defaultInstance; + } + + public IMLogoutRsp getDefaultInstanceForType() { + return defaultInstance; + } + + private final com.google.protobuf.ByteString unknownFields; + private IMLogoutRsp( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + initFields(); + int mutable_bitField0_ = 0; + com.google.protobuf.ByteString.Output unknownFieldsOutput = + com.google.protobuf.ByteString.newOutput(); + com.google.protobuf.CodedOutputStream unknownFieldsCodedOutput = + com.google.protobuf.CodedOutputStream.newInstance( + unknownFieldsOutput); + try { + boolean done = false; + while (!done) { + int tag = input.readTag(); + switch (tag) { + case 0: + done = true; + break; + default: { + if (!parseUnknownField(input, unknownFieldsCodedOutput, + extensionRegistry, tag)) { + done = true; + } + break; + } + case 8: { + bitField0_ |= 0x00000001; + resultCode_ = input.readUInt32(); + break; + } + } + } + } catch (com.google.protobuf.InvalidProtocolBufferException e) { + throw e.setUnfinishedMessage(this); + } catch (java.io.IOException e) { + throw new com.google.protobuf.InvalidProtocolBufferException( + e.getMessage()).setUnfinishedMessage(this); + } finally { + try { + unknownFieldsCodedOutput.flush(); + } catch (java.io.IOException e) { + // Should not happen + } finally { + unknownFields = unknownFieldsOutput.toByteString(); + } + makeExtensionsImmutable(); + } + } + public static com.google.protobuf.Parser PARSER = + new com.google.protobuf.AbstractParser() { + public IMLogoutRsp parsePartialFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return new IMLogoutRsp(input, extensionRegistry); + } + }; + + @java.lang.Override + public com.google.protobuf.Parser getParserForType() { + return PARSER; + } + + private int bitField0_; + public static final int RESULT_CODE_FIELD_NUMBER = 1; + private int resultCode_; + /** + * required uint32 result_code = 1; + * + *
+     *cmd id:		0x0106
+     * 
+ */ + public boolean hasResultCode() { + return ((bitField0_ & 0x00000001) == 0x00000001); + } + /** + * required uint32 result_code = 1; + * + *
+     *cmd id:		0x0106
+     * 
+ */ + public int getResultCode() { + return resultCode_; + } + + private void initFields() { + resultCode_ = 0; + } + private byte memoizedIsInitialized = -1; + public final boolean isInitialized() { + byte isInitialized = memoizedIsInitialized; + if (isInitialized == 1) return true; + if (isInitialized == 0) return false; + + if (!hasResultCode()) { + memoizedIsInitialized = 0; + return false; + } + memoizedIsInitialized = 1; + return true; + } + + public void writeTo(com.google.protobuf.CodedOutputStream output) + throws java.io.IOException { + getSerializedSize(); + if (((bitField0_ & 0x00000001) == 0x00000001)) { + output.writeUInt32(1, resultCode_); + } + output.writeRawBytes(unknownFields); + } + + private int memoizedSerializedSize = -1; + public int getSerializedSize() { + int size = memoizedSerializedSize; + if (size != -1) return size; + + size = 0; + if (((bitField0_ & 0x00000001) == 0x00000001)) { + size += com.google.protobuf.CodedOutputStream + .computeUInt32Size(1, resultCode_); + } + size += unknownFields.size(); + memoizedSerializedSize = size; + return size; + } + + private static final long serialVersionUID = 0L; + @java.lang.Override + protected java.lang.Object writeReplace() + throws java.io.ObjectStreamException { + return super.writeReplace(); + } + + public static com.mogujie.tt.protobuf.IMLogin.IMLogoutRsp parseFrom( + com.google.protobuf.ByteString data) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data); + } + public static com.mogujie.tt.protobuf.IMLogin.IMLogoutRsp parseFrom( + com.google.protobuf.ByteString data, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data, extensionRegistry); + } + public static com.mogujie.tt.protobuf.IMLogin.IMLogoutRsp parseFrom(byte[] data) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data); + } + public static com.mogujie.tt.protobuf.IMLogin.IMLogoutRsp parseFrom( + byte[] data, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data, extensionRegistry); + } + public static com.mogujie.tt.protobuf.IMLogin.IMLogoutRsp parseFrom(java.io.InputStream input) + throws java.io.IOException { + return PARSER.parseFrom(input); + } + public static com.mogujie.tt.protobuf.IMLogin.IMLogoutRsp parseFrom( + java.io.InputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return PARSER.parseFrom(input, extensionRegistry); + } + public static com.mogujie.tt.protobuf.IMLogin.IMLogoutRsp parseDelimitedFrom(java.io.InputStream input) + throws java.io.IOException { + return PARSER.parseDelimitedFrom(input); + } + public static com.mogujie.tt.protobuf.IMLogin.IMLogoutRsp parseDelimitedFrom( + java.io.InputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return PARSER.parseDelimitedFrom(input, extensionRegistry); + } + public static com.mogujie.tt.protobuf.IMLogin.IMLogoutRsp parseFrom( + com.google.protobuf.CodedInputStream input) + throws java.io.IOException { + return PARSER.parseFrom(input); + } + public static com.mogujie.tt.protobuf.IMLogin.IMLogoutRsp parseFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return PARSER.parseFrom(input, extensionRegistry); + } + + public static Builder newBuilder() { return Builder.create(); } + public Builder newBuilderForType() { return newBuilder(); } + public static Builder newBuilder(com.mogujie.tt.protobuf.IMLogin.IMLogoutRsp prototype) { + return newBuilder().mergeFrom(prototype); + } + public Builder toBuilder() { return newBuilder(this); } + + /** + * Protobuf type {@code IM.Login.IMLogoutRsp} + */ + public static final class Builder extends + com.google.protobuf.GeneratedMessageLite.Builder< + com.mogujie.tt.protobuf.IMLogin.IMLogoutRsp, Builder> + implements + // @@protoc_insertion_point(builder_implements:IM.Login.IMLogoutRsp) + com.mogujie.tt.protobuf.IMLogin.IMLogoutRspOrBuilder { + // Construct using com.mogujie.tt.protobuf.IMLogin.IMLogoutRsp.newBuilder() + private Builder() { + maybeForceBuilderInitialization(); + } + + private void maybeForceBuilderInitialization() { + } + private static Builder create() { + return new Builder(); + } + + public Builder clear() { + super.clear(); + resultCode_ = 0; + bitField0_ = (bitField0_ & ~0x00000001); + return this; + } + + public Builder clone() { + return create().mergeFrom(buildPartial()); + } + + public com.mogujie.tt.protobuf.IMLogin.IMLogoutRsp getDefaultInstanceForType() { + return com.mogujie.tt.protobuf.IMLogin.IMLogoutRsp.getDefaultInstance(); + } + + public com.mogujie.tt.protobuf.IMLogin.IMLogoutRsp build() { + com.mogujie.tt.protobuf.IMLogin.IMLogoutRsp result = buildPartial(); + if (!result.isInitialized()) { + throw newUninitializedMessageException(result); + } + return result; + } + + public com.mogujie.tt.protobuf.IMLogin.IMLogoutRsp buildPartial() { + com.mogujie.tt.protobuf.IMLogin.IMLogoutRsp result = new com.mogujie.tt.protobuf.IMLogin.IMLogoutRsp(this); + int from_bitField0_ = bitField0_; + int to_bitField0_ = 0; + if (((from_bitField0_ & 0x00000001) == 0x00000001)) { + to_bitField0_ |= 0x00000001; + } + result.resultCode_ = resultCode_; + result.bitField0_ = to_bitField0_; + return result; + } + + public Builder mergeFrom(com.mogujie.tt.protobuf.IMLogin.IMLogoutRsp other) { + if (other == com.mogujie.tt.protobuf.IMLogin.IMLogoutRsp.getDefaultInstance()) return this; + if (other.hasResultCode()) { + setResultCode(other.getResultCode()); + } + setUnknownFields( + getUnknownFields().concat(other.unknownFields)); + return this; + } + + public final boolean isInitialized() { + if (!hasResultCode()) { + + return false; + } + return true; + } + + public Builder mergeFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + com.mogujie.tt.protobuf.IMLogin.IMLogoutRsp parsedMessage = null; + try { + parsedMessage = PARSER.parsePartialFrom(input, extensionRegistry); + } catch (com.google.protobuf.InvalidProtocolBufferException e) { + parsedMessage = (com.mogujie.tt.protobuf.IMLogin.IMLogoutRsp) e.getUnfinishedMessage(); + throw e; + } finally { + if (parsedMessage != null) { + mergeFrom(parsedMessage); + } + } + return this; + } + private int bitField0_; + + private int resultCode_ ; + /** + * required uint32 result_code = 1; + * + *
+       *cmd id:		0x0106
+       * 
+ */ + public boolean hasResultCode() { + return ((bitField0_ & 0x00000001) == 0x00000001); + } + /** + * required uint32 result_code = 1; + * + *
+       *cmd id:		0x0106
+       * 
+ */ + public int getResultCode() { + return resultCode_; + } + /** + * required uint32 result_code = 1; + * + *
+       *cmd id:		0x0106
+       * 
+ */ + public Builder setResultCode(int value) { + bitField0_ |= 0x00000001; + resultCode_ = value; + + return this; + } + /** + * required uint32 result_code = 1; + * + *
+       *cmd id:		0x0106
+       * 
+ */ + public Builder clearResultCode() { + bitField0_ = (bitField0_ & ~0x00000001); + resultCode_ = 0; + + return this; + } + + // @@protoc_insertion_point(builder_scope:IM.Login.IMLogoutRsp) + } + + static { + defaultInstance = new IMLogoutRsp(true); + defaultInstance.initFields(); + } + + // @@protoc_insertion_point(class_scope:IM.Login.IMLogoutRsp) + } + + public interface IMKickUserOrBuilder extends + // @@protoc_insertion_point(interface_extends:IM.Login.IMKickUser) + com.google.protobuf.MessageLiteOrBuilder { + + /** + * required uint32 user_id = 1; + * + *
+     *cmd id:		0x0107
+     * 
+ */ + boolean hasUserId(); + /** + * required uint32 user_id = 1; + * + *
+     *cmd id:		0x0107
+     * 
+ */ + int getUserId(); + + /** + * required .IM.BaseDefine.KickReasonType kick_reason = 2; + */ + boolean hasKickReason(); + /** + * required .IM.BaseDefine.KickReasonType kick_reason = 2; + */ + com.mogujie.tt.protobuf.IMBaseDefine.KickReasonType getKickReason(); + } + /** + * Protobuf type {@code IM.Login.IMKickUser} + */ + public static final class IMKickUser extends + com.google.protobuf.GeneratedMessageLite implements + // @@protoc_insertion_point(message_implements:IM.Login.IMKickUser) + IMKickUserOrBuilder { + // Use IMKickUser.newBuilder() to construct. + private IMKickUser(com.google.protobuf.GeneratedMessageLite.Builder builder) { + super(builder); + this.unknownFields = builder.getUnknownFields(); + } + private IMKickUser(boolean noInit) { this.unknownFields = com.google.protobuf.ByteString.EMPTY;} + + private static final IMKickUser defaultInstance; + public static IMKickUser getDefaultInstance() { + return defaultInstance; + } + + public IMKickUser getDefaultInstanceForType() { + return defaultInstance; + } + + private final com.google.protobuf.ByteString unknownFields; + private IMKickUser( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + initFields(); + int mutable_bitField0_ = 0; + com.google.protobuf.ByteString.Output unknownFieldsOutput = + com.google.protobuf.ByteString.newOutput(); + com.google.protobuf.CodedOutputStream unknownFieldsCodedOutput = + com.google.protobuf.CodedOutputStream.newInstance( + unknownFieldsOutput); + try { + boolean done = false; + while (!done) { + int tag = input.readTag(); + switch (tag) { + case 0: + done = true; + break; + default: { + if (!parseUnknownField(input, unknownFieldsCodedOutput, + extensionRegistry, tag)) { + done = true; + } + break; + } + case 8: { + bitField0_ |= 0x00000001; + userId_ = input.readUInt32(); + break; + } + case 16: { + int rawValue = input.readEnum(); + com.mogujie.tt.protobuf.IMBaseDefine.KickReasonType value = com.mogujie.tt.protobuf.IMBaseDefine.KickReasonType.valueOf(rawValue); + if (value == null) { + unknownFieldsCodedOutput.writeRawVarint32(tag); + unknownFieldsCodedOutput.writeRawVarint32(rawValue); + } else { + bitField0_ |= 0x00000002; + kickReason_ = value; + } + break; + } + } + } + } catch (com.google.protobuf.InvalidProtocolBufferException e) { + throw e.setUnfinishedMessage(this); + } catch (java.io.IOException e) { + throw new com.google.protobuf.InvalidProtocolBufferException( + e.getMessage()).setUnfinishedMessage(this); + } finally { + try { + unknownFieldsCodedOutput.flush(); + } catch (java.io.IOException e) { + // Should not happen + } finally { + unknownFields = unknownFieldsOutput.toByteString(); + } + makeExtensionsImmutable(); + } + } + public static com.google.protobuf.Parser PARSER = + new com.google.protobuf.AbstractParser() { + public IMKickUser parsePartialFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return new IMKickUser(input, extensionRegistry); + } + }; + + @java.lang.Override + public com.google.protobuf.Parser getParserForType() { + return PARSER; + } + + private int bitField0_; + public static final int USER_ID_FIELD_NUMBER = 1; + private int userId_; + /** + * required uint32 user_id = 1; + * + *
+     *cmd id:		0x0107
+     * 
+ */ + public boolean hasUserId() { + return ((bitField0_ & 0x00000001) == 0x00000001); + } + /** + * required uint32 user_id = 1; + * + *
+     *cmd id:		0x0107
+     * 
+ */ + public int getUserId() { + return userId_; + } + + public static final int KICK_REASON_FIELD_NUMBER = 2; + private com.mogujie.tt.protobuf.IMBaseDefine.KickReasonType kickReason_; + /** + * required .IM.BaseDefine.KickReasonType kick_reason = 2; + */ + public boolean hasKickReason() { + return ((bitField0_ & 0x00000002) == 0x00000002); + } + /** + * required .IM.BaseDefine.KickReasonType kick_reason = 2; + */ + public com.mogujie.tt.protobuf.IMBaseDefine.KickReasonType getKickReason() { + return kickReason_; + } + + private void initFields() { + userId_ = 0; + kickReason_ = com.mogujie.tt.protobuf.IMBaseDefine.KickReasonType.KICK_REASON_DUPLICATE_USER; + } + private byte memoizedIsInitialized = -1; + public final boolean isInitialized() { + byte isInitialized = memoizedIsInitialized; + if (isInitialized == 1) return true; + if (isInitialized == 0) return false; + + if (!hasUserId()) { + memoizedIsInitialized = 0; + return false; + } + if (!hasKickReason()) { + memoizedIsInitialized = 0; + return false; + } + memoizedIsInitialized = 1; + return true; + } + + public void writeTo(com.google.protobuf.CodedOutputStream output) + throws java.io.IOException { + getSerializedSize(); + if (((bitField0_ & 0x00000001) == 0x00000001)) { + output.writeUInt32(1, userId_); + } + if (((bitField0_ & 0x00000002) == 0x00000002)) { + output.writeEnum(2, kickReason_.getNumber()); + } + output.writeRawBytes(unknownFields); + } + + private int memoizedSerializedSize = -1; + public int getSerializedSize() { + int size = memoizedSerializedSize; + if (size != -1) return size; + + size = 0; + if (((bitField0_ & 0x00000001) == 0x00000001)) { + size += com.google.protobuf.CodedOutputStream + .computeUInt32Size(1, userId_); + } + if (((bitField0_ & 0x00000002) == 0x00000002)) { + size += com.google.protobuf.CodedOutputStream + .computeEnumSize(2, kickReason_.getNumber()); + } + size += unknownFields.size(); + memoizedSerializedSize = size; + return size; + } + + private static final long serialVersionUID = 0L; + @java.lang.Override + protected java.lang.Object writeReplace() + throws java.io.ObjectStreamException { + return super.writeReplace(); + } + + public static com.mogujie.tt.protobuf.IMLogin.IMKickUser parseFrom( + com.google.protobuf.ByteString data) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data); + } + public static com.mogujie.tt.protobuf.IMLogin.IMKickUser parseFrom( + com.google.protobuf.ByteString data, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data, extensionRegistry); + } + public static com.mogujie.tt.protobuf.IMLogin.IMKickUser parseFrom(byte[] data) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data); + } + public static com.mogujie.tt.protobuf.IMLogin.IMKickUser parseFrom( + byte[] data, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data, extensionRegistry); + } + public static com.mogujie.tt.protobuf.IMLogin.IMKickUser parseFrom(java.io.InputStream input) + throws java.io.IOException { + return PARSER.parseFrom(input); + } + public static com.mogujie.tt.protobuf.IMLogin.IMKickUser parseFrom( + java.io.InputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return PARSER.parseFrom(input, extensionRegistry); + } + public static com.mogujie.tt.protobuf.IMLogin.IMKickUser parseDelimitedFrom(java.io.InputStream input) + throws java.io.IOException { + return PARSER.parseDelimitedFrom(input); + } + public static com.mogujie.tt.protobuf.IMLogin.IMKickUser parseDelimitedFrom( + java.io.InputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return PARSER.parseDelimitedFrom(input, extensionRegistry); + } + public static com.mogujie.tt.protobuf.IMLogin.IMKickUser parseFrom( + com.google.protobuf.CodedInputStream input) + throws java.io.IOException { + return PARSER.parseFrom(input); + } + public static com.mogujie.tt.protobuf.IMLogin.IMKickUser parseFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return PARSER.parseFrom(input, extensionRegistry); + } + + public static Builder newBuilder() { return Builder.create(); } + public Builder newBuilderForType() { return newBuilder(); } + public static Builder newBuilder(com.mogujie.tt.protobuf.IMLogin.IMKickUser prototype) { + return newBuilder().mergeFrom(prototype); + } + public Builder toBuilder() { return newBuilder(this); } + + /** + * Protobuf type {@code IM.Login.IMKickUser} + */ + public static final class Builder extends + com.google.protobuf.GeneratedMessageLite.Builder< + com.mogujie.tt.protobuf.IMLogin.IMKickUser, Builder> + implements + // @@protoc_insertion_point(builder_implements:IM.Login.IMKickUser) + com.mogujie.tt.protobuf.IMLogin.IMKickUserOrBuilder { + // Construct using com.mogujie.tt.protobuf.IMLogin.IMKickUser.newBuilder() + private Builder() { + maybeForceBuilderInitialization(); + } + + private void maybeForceBuilderInitialization() { + } + private static Builder create() { + return new Builder(); + } + + public Builder clear() { + super.clear(); + userId_ = 0; + bitField0_ = (bitField0_ & ~0x00000001); + kickReason_ = com.mogujie.tt.protobuf.IMBaseDefine.KickReasonType.KICK_REASON_DUPLICATE_USER; + bitField0_ = (bitField0_ & ~0x00000002); + return this; + } + + public Builder clone() { + return create().mergeFrom(buildPartial()); + } + + public com.mogujie.tt.protobuf.IMLogin.IMKickUser getDefaultInstanceForType() { + return com.mogujie.tt.protobuf.IMLogin.IMKickUser.getDefaultInstance(); + } + + public com.mogujie.tt.protobuf.IMLogin.IMKickUser build() { + com.mogujie.tt.protobuf.IMLogin.IMKickUser result = buildPartial(); + if (!result.isInitialized()) { + throw newUninitializedMessageException(result); + } + return result; + } + + public com.mogujie.tt.protobuf.IMLogin.IMKickUser buildPartial() { + com.mogujie.tt.protobuf.IMLogin.IMKickUser result = new com.mogujie.tt.protobuf.IMLogin.IMKickUser(this); + int from_bitField0_ = bitField0_; + int to_bitField0_ = 0; + if (((from_bitField0_ & 0x00000001) == 0x00000001)) { + to_bitField0_ |= 0x00000001; + } + result.userId_ = userId_; + if (((from_bitField0_ & 0x00000002) == 0x00000002)) { + to_bitField0_ |= 0x00000002; + } + result.kickReason_ = kickReason_; + result.bitField0_ = to_bitField0_; + return result; + } + + public Builder mergeFrom(com.mogujie.tt.protobuf.IMLogin.IMKickUser other) { + if (other == com.mogujie.tt.protobuf.IMLogin.IMKickUser.getDefaultInstance()) return this; + if (other.hasUserId()) { + setUserId(other.getUserId()); + } + if (other.hasKickReason()) { + setKickReason(other.getKickReason()); + } + setUnknownFields( + getUnknownFields().concat(other.unknownFields)); + return this; + } + + public final boolean isInitialized() { + if (!hasUserId()) { + + return false; + } + if (!hasKickReason()) { + + return false; + } + return true; + } + + public Builder mergeFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + com.mogujie.tt.protobuf.IMLogin.IMKickUser parsedMessage = null; + try { + parsedMessage = PARSER.parsePartialFrom(input, extensionRegistry); + } catch (com.google.protobuf.InvalidProtocolBufferException e) { + parsedMessage = (com.mogujie.tt.protobuf.IMLogin.IMKickUser) e.getUnfinishedMessage(); + throw e; + } finally { + if (parsedMessage != null) { + mergeFrom(parsedMessage); + } + } + return this; + } + private int bitField0_; + + private int userId_ ; + /** + * required uint32 user_id = 1; + * + *
+       *cmd id:		0x0107
+       * 
+ */ + public boolean hasUserId() { + return ((bitField0_ & 0x00000001) == 0x00000001); + } + /** + * required uint32 user_id = 1; + * + *
+       *cmd id:		0x0107
+       * 
+ */ + public int getUserId() { + return userId_; + } + /** + * required uint32 user_id = 1; + * + *
+       *cmd id:		0x0107
+       * 
+ */ + public Builder setUserId(int value) { + bitField0_ |= 0x00000001; + userId_ = value; + + return this; + } + /** + * required uint32 user_id = 1; + * + *
+       *cmd id:		0x0107
+       * 
+ */ + public Builder clearUserId() { + bitField0_ = (bitField0_ & ~0x00000001); + userId_ = 0; + + return this; + } + + private com.mogujie.tt.protobuf.IMBaseDefine.KickReasonType kickReason_ = com.mogujie.tt.protobuf.IMBaseDefine.KickReasonType.KICK_REASON_DUPLICATE_USER; + /** + * required .IM.BaseDefine.KickReasonType kick_reason = 2; + */ + public boolean hasKickReason() { + return ((bitField0_ & 0x00000002) == 0x00000002); + } + /** + * required .IM.BaseDefine.KickReasonType kick_reason = 2; + */ + public com.mogujie.tt.protobuf.IMBaseDefine.KickReasonType getKickReason() { + return kickReason_; + } + /** + * required .IM.BaseDefine.KickReasonType kick_reason = 2; + */ + public Builder setKickReason(com.mogujie.tt.protobuf.IMBaseDefine.KickReasonType value) { + if (value == null) { + throw new NullPointerException(); + } + bitField0_ |= 0x00000002; + kickReason_ = value; + + return this; + } + /** + * required .IM.BaseDefine.KickReasonType kick_reason = 2; + */ + public Builder clearKickReason() { + bitField0_ = (bitField0_ & ~0x00000002); + kickReason_ = com.mogujie.tt.protobuf.IMBaseDefine.KickReasonType.KICK_REASON_DUPLICATE_USER; + + return this; + } + + // @@protoc_insertion_point(builder_scope:IM.Login.IMKickUser) + } + + static { + defaultInstance = new IMKickUser(true); + defaultInstance.initFields(); + } + + // @@protoc_insertion_point(class_scope:IM.Login.IMKickUser) + } + + public interface IMDeviceTokenReqOrBuilder extends + // @@protoc_insertion_point(interface_extends:IM.Login.IMDeviceTokenReq) + com.google.protobuf.MessageLiteOrBuilder { + + /** + * required uint32 user_id = 1; + * + *
+     *cmd id:		0x0108
+     * 
+ */ + boolean hasUserId(); + /** + * required uint32 user_id = 1; + * + *
+     *cmd id:		0x0108
+     * 
+ */ + int getUserId(); + + /** + * required string device_token = 2; + */ + boolean hasDeviceToken(); + /** + * required string device_token = 2; + */ + java.lang.String getDeviceToken(); + /** + * required string device_token = 2; + */ + com.google.protobuf.ByteString + getDeviceTokenBytes(); + + /** + * optional .IM.BaseDefine.ClientType client_type = 3; + */ + boolean hasClientType(); + /** + * optional .IM.BaseDefine.ClientType client_type = 3; + */ + com.mogujie.tt.protobuf.IMBaseDefine.ClientType getClientType(); + + /** + * optional bytes attach_data = 20; + */ + boolean hasAttachData(); + /** + * optional bytes attach_data = 20; + */ + com.google.protobuf.ByteString getAttachData(); + } + /** + * Protobuf type {@code IM.Login.IMDeviceTokenReq} + */ + public static final class IMDeviceTokenReq extends + com.google.protobuf.GeneratedMessageLite implements + // @@protoc_insertion_point(message_implements:IM.Login.IMDeviceTokenReq) + IMDeviceTokenReqOrBuilder { + // Use IMDeviceTokenReq.newBuilder() to construct. + private IMDeviceTokenReq(com.google.protobuf.GeneratedMessageLite.Builder builder) { + super(builder); + this.unknownFields = builder.getUnknownFields(); + } + private IMDeviceTokenReq(boolean noInit) { this.unknownFields = com.google.protobuf.ByteString.EMPTY;} + + private static final IMDeviceTokenReq defaultInstance; + public static IMDeviceTokenReq getDefaultInstance() { + return defaultInstance; + } + + public IMDeviceTokenReq getDefaultInstanceForType() { + return defaultInstance; + } + + private final com.google.protobuf.ByteString unknownFields; + private IMDeviceTokenReq( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + initFields(); + int mutable_bitField0_ = 0; + com.google.protobuf.ByteString.Output unknownFieldsOutput = + com.google.protobuf.ByteString.newOutput(); + com.google.protobuf.CodedOutputStream unknownFieldsCodedOutput = + com.google.protobuf.CodedOutputStream.newInstance( + unknownFieldsOutput); + try { + boolean done = false; + while (!done) { + int tag = input.readTag(); + switch (tag) { + case 0: + done = true; + break; + default: { + if (!parseUnknownField(input, unknownFieldsCodedOutput, + extensionRegistry, tag)) { + done = true; + } + break; + } + case 8: { + bitField0_ |= 0x00000001; + userId_ = input.readUInt32(); + break; + } + case 18: { + com.google.protobuf.ByteString bs = input.readBytes(); + bitField0_ |= 0x00000002; + deviceToken_ = bs; + break; + } + case 24: { + int rawValue = input.readEnum(); + com.mogujie.tt.protobuf.IMBaseDefine.ClientType value = com.mogujie.tt.protobuf.IMBaseDefine.ClientType.valueOf(rawValue); + if (value == null) { + unknownFieldsCodedOutput.writeRawVarint32(tag); + unknownFieldsCodedOutput.writeRawVarint32(rawValue); + } else { + bitField0_ |= 0x00000004; + clientType_ = value; + } + break; + } + case 162: { + bitField0_ |= 0x00000008; + attachData_ = input.readBytes(); + break; + } + } + } + } catch (com.google.protobuf.InvalidProtocolBufferException e) { + throw e.setUnfinishedMessage(this); + } catch (java.io.IOException e) { + throw new com.google.protobuf.InvalidProtocolBufferException( + e.getMessage()).setUnfinishedMessage(this); + } finally { + try { + unknownFieldsCodedOutput.flush(); + } catch (java.io.IOException e) { + // Should not happen + } finally { + unknownFields = unknownFieldsOutput.toByteString(); + } + makeExtensionsImmutable(); + } + } + public static com.google.protobuf.Parser PARSER = + new com.google.protobuf.AbstractParser() { + public IMDeviceTokenReq parsePartialFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return new IMDeviceTokenReq(input, extensionRegistry); + } + }; + + @java.lang.Override + public com.google.protobuf.Parser getParserForType() { + return PARSER; + } + + private int bitField0_; + public static final int USER_ID_FIELD_NUMBER = 1; + private int userId_; + /** + * required uint32 user_id = 1; + * + *
+     *cmd id:		0x0108
+     * 
+ */ + public boolean hasUserId() { + return ((bitField0_ & 0x00000001) == 0x00000001); + } + /** + * required uint32 user_id = 1; + * + *
+     *cmd id:		0x0108
+     * 
+ */ + public int getUserId() { + return userId_; + } + + public static final int DEVICE_TOKEN_FIELD_NUMBER = 2; + private java.lang.Object deviceToken_; + /** + * required string device_token = 2; + */ + public boolean hasDeviceToken() { + return ((bitField0_ & 0x00000002) == 0x00000002); + } + /** + * required string device_token = 2; + */ + public java.lang.String getDeviceToken() { + java.lang.Object ref = deviceToken_; + if (ref instanceof java.lang.String) { + return (java.lang.String) ref; + } else { + com.google.protobuf.ByteString bs = + (com.google.protobuf.ByteString) ref; + java.lang.String s = bs.toStringUtf8(); + if (bs.isValidUtf8()) { + deviceToken_ = s; + } + return s; + } + } + /** + * required string device_token = 2; + */ + public com.google.protobuf.ByteString + getDeviceTokenBytes() { + java.lang.Object ref = deviceToken_; + if (ref instanceof java.lang.String) { + com.google.protobuf.ByteString b = + com.google.protobuf.ByteString.copyFromUtf8( + (java.lang.String) ref); + deviceToken_ = b; + return b; + } else { + return (com.google.protobuf.ByteString) ref; + } + } + + public static final int CLIENT_TYPE_FIELD_NUMBER = 3; + private com.mogujie.tt.protobuf.IMBaseDefine.ClientType clientType_; + /** + * optional .IM.BaseDefine.ClientType client_type = 3; + */ + public boolean hasClientType() { + return ((bitField0_ & 0x00000004) == 0x00000004); + } + /** + * optional .IM.BaseDefine.ClientType client_type = 3; + */ + public com.mogujie.tt.protobuf.IMBaseDefine.ClientType getClientType() { + return clientType_; + } + + public static final int ATTACH_DATA_FIELD_NUMBER = 20; + private com.google.protobuf.ByteString attachData_; + /** + * optional bytes attach_data = 20; + */ + public boolean hasAttachData() { + return ((bitField0_ & 0x00000008) == 0x00000008); + } + /** + * optional bytes attach_data = 20; + */ + public com.google.protobuf.ByteString getAttachData() { + return attachData_; + } + + private void initFields() { + userId_ = 0; + deviceToken_ = ""; + clientType_ = com.mogujie.tt.protobuf.IMBaseDefine.ClientType.CLIENT_TYPE_WINDOWS; + attachData_ = com.google.protobuf.ByteString.EMPTY; + } + private byte memoizedIsInitialized = -1; + public final boolean isInitialized() { + byte isInitialized = memoizedIsInitialized; + if (isInitialized == 1) return true; + if (isInitialized == 0) return false; + + if (!hasUserId()) { + memoizedIsInitialized = 0; + return false; + } + if (!hasDeviceToken()) { + memoizedIsInitialized = 0; + return false; + } + memoizedIsInitialized = 1; + return true; + } + + public void writeTo(com.google.protobuf.CodedOutputStream output) + throws java.io.IOException { + getSerializedSize(); + if (((bitField0_ & 0x00000001) == 0x00000001)) { + output.writeUInt32(1, userId_); + } + if (((bitField0_ & 0x00000002) == 0x00000002)) { + output.writeBytes(2, getDeviceTokenBytes()); + } + if (((bitField0_ & 0x00000004) == 0x00000004)) { + output.writeEnum(3, clientType_.getNumber()); + } + if (((bitField0_ & 0x00000008) == 0x00000008)) { + output.writeBytes(20, attachData_); + } + output.writeRawBytes(unknownFields); + } + + private int memoizedSerializedSize = -1; + public int getSerializedSize() { + int size = memoizedSerializedSize; + if (size != -1) return size; + + size = 0; + if (((bitField0_ & 0x00000001) == 0x00000001)) { + size += com.google.protobuf.CodedOutputStream + .computeUInt32Size(1, userId_); + } + if (((bitField0_ & 0x00000002) == 0x00000002)) { + size += com.google.protobuf.CodedOutputStream + .computeBytesSize(2, getDeviceTokenBytes()); + } + if (((bitField0_ & 0x00000004) == 0x00000004)) { + size += com.google.protobuf.CodedOutputStream + .computeEnumSize(3, clientType_.getNumber()); + } + if (((bitField0_ & 0x00000008) == 0x00000008)) { + size += com.google.protobuf.CodedOutputStream + .computeBytesSize(20, attachData_); + } + size += unknownFields.size(); + memoizedSerializedSize = size; + return size; + } + + private static final long serialVersionUID = 0L; + @java.lang.Override + protected java.lang.Object writeReplace() + throws java.io.ObjectStreamException { + return super.writeReplace(); + } + + public static com.mogujie.tt.protobuf.IMLogin.IMDeviceTokenReq parseFrom( + com.google.protobuf.ByteString data) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data); + } + public static com.mogujie.tt.protobuf.IMLogin.IMDeviceTokenReq parseFrom( + com.google.protobuf.ByteString data, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data, extensionRegistry); + } + public static com.mogujie.tt.protobuf.IMLogin.IMDeviceTokenReq parseFrom(byte[] data) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data); + } + public static com.mogujie.tt.protobuf.IMLogin.IMDeviceTokenReq parseFrom( + byte[] data, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data, extensionRegistry); + } + public static com.mogujie.tt.protobuf.IMLogin.IMDeviceTokenReq parseFrom(java.io.InputStream input) + throws java.io.IOException { + return PARSER.parseFrom(input); + } + public static com.mogujie.tt.protobuf.IMLogin.IMDeviceTokenReq parseFrom( + java.io.InputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return PARSER.parseFrom(input, extensionRegistry); + } + public static com.mogujie.tt.protobuf.IMLogin.IMDeviceTokenReq parseDelimitedFrom(java.io.InputStream input) + throws java.io.IOException { + return PARSER.parseDelimitedFrom(input); + } + public static com.mogujie.tt.protobuf.IMLogin.IMDeviceTokenReq parseDelimitedFrom( + java.io.InputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return PARSER.parseDelimitedFrom(input, extensionRegistry); + } + public static com.mogujie.tt.protobuf.IMLogin.IMDeviceTokenReq parseFrom( + com.google.protobuf.CodedInputStream input) + throws java.io.IOException { + return PARSER.parseFrom(input); + } + public static com.mogujie.tt.protobuf.IMLogin.IMDeviceTokenReq parseFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return PARSER.parseFrom(input, extensionRegistry); + } + + public static Builder newBuilder() { return Builder.create(); } + public Builder newBuilderForType() { return newBuilder(); } + public static Builder newBuilder(com.mogujie.tt.protobuf.IMLogin.IMDeviceTokenReq prototype) { + return newBuilder().mergeFrom(prototype); + } + public Builder toBuilder() { return newBuilder(this); } + + /** + * Protobuf type {@code IM.Login.IMDeviceTokenReq} + */ + public static final class Builder extends + com.google.protobuf.GeneratedMessageLite.Builder< + com.mogujie.tt.protobuf.IMLogin.IMDeviceTokenReq, Builder> + implements + // @@protoc_insertion_point(builder_implements:IM.Login.IMDeviceTokenReq) + com.mogujie.tt.protobuf.IMLogin.IMDeviceTokenReqOrBuilder { + // Construct using com.mogujie.tt.protobuf.IMLogin.IMDeviceTokenReq.newBuilder() + private Builder() { + maybeForceBuilderInitialization(); + } + + private void maybeForceBuilderInitialization() { + } + private static Builder create() { + return new Builder(); + } + + public Builder clear() { + super.clear(); + userId_ = 0; + bitField0_ = (bitField0_ & ~0x00000001); + deviceToken_ = ""; + bitField0_ = (bitField0_ & ~0x00000002); + clientType_ = com.mogujie.tt.protobuf.IMBaseDefine.ClientType.CLIENT_TYPE_WINDOWS; + bitField0_ = (bitField0_ & ~0x00000004); + attachData_ = com.google.protobuf.ByteString.EMPTY; + bitField0_ = (bitField0_ & ~0x00000008); + return this; + } + + public Builder clone() { + return create().mergeFrom(buildPartial()); + } + + public com.mogujie.tt.protobuf.IMLogin.IMDeviceTokenReq getDefaultInstanceForType() { + return com.mogujie.tt.protobuf.IMLogin.IMDeviceTokenReq.getDefaultInstance(); + } + + public com.mogujie.tt.protobuf.IMLogin.IMDeviceTokenReq build() { + com.mogujie.tt.protobuf.IMLogin.IMDeviceTokenReq result = buildPartial(); + if (!result.isInitialized()) { + throw newUninitializedMessageException(result); + } + return result; + } + + public com.mogujie.tt.protobuf.IMLogin.IMDeviceTokenReq buildPartial() { + com.mogujie.tt.protobuf.IMLogin.IMDeviceTokenReq result = new com.mogujie.tt.protobuf.IMLogin.IMDeviceTokenReq(this); + int from_bitField0_ = bitField0_; + int to_bitField0_ = 0; + if (((from_bitField0_ & 0x00000001) == 0x00000001)) { + to_bitField0_ |= 0x00000001; + } + result.userId_ = userId_; + if (((from_bitField0_ & 0x00000002) == 0x00000002)) { + to_bitField0_ |= 0x00000002; + } + result.deviceToken_ = deviceToken_; + if (((from_bitField0_ & 0x00000004) == 0x00000004)) { + to_bitField0_ |= 0x00000004; + } + result.clientType_ = clientType_; + if (((from_bitField0_ & 0x00000008) == 0x00000008)) { + to_bitField0_ |= 0x00000008; + } + result.attachData_ = attachData_; + result.bitField0_ = to_bitField0_; + return result; + } + + public Builder mergeFrom(com.mogujie.tt.protobuf.IMLogin.IMDeviceTokenReq other) { + if (other == com.mogujie.tt.protobuf.IMLogin.IMDeviceTokenReq.getDefaultInstance()) return this; + if (other.hasUserId()) { + setUserId(other.getUserId()); + } + if (other.hasDeviceToken()) { + bitField0_ |= 0x00000002; + deviceToken_ = other.deviceToken_; + + } + if (other.hasClientType()) { + setClientType(other.getClientType()); + } + if (other.hasAttachData()) { + setAttachData(other.getAttachData()); + } + setUnknownFields( + getUnknownFields().concat(other.unknownFields)); + return this; + } + + public final boolean isInitialized() { + if (!hasUserId()) { + + return false; + } + if (!hasDeviceToken()) { + + return false; + } + return true; + } + + public Builder mergeFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + com.mogujie.tt.protobuf.IMLogin.IMDeviceTokenReq parsedMessage = null; + try { + parsedMessage = PARSER.parsePartialFrom(input, extensionRegistry); + } catch (com.google.protobuf.InvalidProtocolBufferException e) { + parsedMessage = (com.mogujie.tt.protobuf.IMLogin.IMDeviceTokenReq) e.getUnfinishedMessage(); + throw e; + } finally { + if (parsedMessage != null) { + mergeFrom(parsedMessage); + } + } + return this; + } + private int bitField0_; + + private int userId_ ; + /** + * required uint32 user_id = 1; + * + *
+       *cmd id:		0x0108
+       * 
+ */ + public boolean hasUserId() { + return ((bitField0_ & 0x00000001) == 0x00000001); + } + /** + * required uint32 user_id = 1; + * + *
+       *cmd id:		0x0108
+       * 
+ */ + public int getUserId() { + return userId_; + } + /** + * required uint32 user_id = 1; + * + *
+       *cmd id:		0x0108
+       * 
+ */ + public Builder setUserId(int value) { + bitField0_ |= 0x00000001; + userId_ = value; + + return this; + } + /** + * required uint32 user_id = 1; + * + *
+       *cmd id:		0x0108
+       * 
+ */ + public Builder clearUserId() { + bitField0_ = (bitField0_ & ~0x00000001); + userId_ = 0; + + return this; + } + + private java.lang.Object deviceToken_ = ""; + /** + * required string device_token = 2; + */ + public boolean hasDeviceToken() { + return ((bitField0_ & 0x00000002) == 0x00000002); + } + /** + * required string device_token = 2; + */ + public java.lang.String getDeviceToken() { + java.lang.Object ref = deviceToken_; + if (!(ref instanceof java.lang.String)) { + com.google.protobuf.ByteString bs = + (com.google.protobuf.ByteString) ref; + java.lang.String s = bs.toStringUtf8(); + if (bs.isValidUtf8()) { + deviceToken_ = s; + } + return s; + } else { + return (java.lang.String) ref; + } + } + /** + * required string device_token = 2; + */ + public com.google.protobuf.ByteString + getDeviceTokenBytes() { + java.lang.Object ref = deviceToken_; + if (ref instanceof String) { + com.google.protobuf.ByteString b = + com.google.protobuf.ByteString.copyFromUtf8( + (java.lang.String) ref); + deviceToken_ = b; + return b; + } else { + return (com.google.protobuf.ByteString) ref; + } + } + /** + * required string device_token = 2; + */ + public Builder setDeviceToken( + java.lang.String value) { + if (value == null) { + throw new NullPointerException(); + } + bitField0_ |= 0x00000002; + deviceToken_ = value; + + return this; + } + /** + * required string device_token = 2; + */ + public Builder clearDeviceToken() { + bitField0_ = (bitField0_ & ~0x00000002); + deviceToken_ = getDefaultInstance().getDeviceToken(); + + return this; + } + /** + * required string device_token = 2; + */ + public Builder setDeviceTokenBytes( + com.google.protobuf.ByteString value) { + if (value == null) { + throw new NullPointerException(); + } + bitField0_ |= 0x00000002; + deviceToken_ = value; + + return this; + } + + private com.mogujie.tt.protobuf.IMBaseDefine.ClientType clientType_ = com.mogujie.tt.protobuf.IMBaseDefine.ClientType.CLIENT_TYPE_WINDOWS; + /** + * optional .IM.BaseDefine.ClientType client_type = 3; + */ + public boolean hasClientType() { + return ((bitField0_ & 0x00000004) == 0x00000004); + } + /** + * optional .IM.BaseDefine.ClientType client_type = 3; + */ + public com.mogujie.tt.protobuf.IMBaseDefine.ClientType getClientType() { + return clientType_; + } + /** + * optional .IM.BaseDefine.ClientType client_type = 3; + */ + public Builder setClientType(com.mogujie.tt.protobuf.IMBaseDefine.ClientType value) { + if (value == null) { + throw new NullPointerException(); + } + bitField0_ |= 0x00000004; + clientType_ = value; + + return this; + } + /** + * optional .IM.BaseDefine.ClientType client_type = 3; + */ + public Builder clearClientType() { + bitField0_ = (bitField0_ & ~0x00000004); + clientType_ = com.mogujie.tt.protobuf.IMBaseDefine.ClientType.CLIENT_TYPE_WINDOWS; + + return this; + } + + private com.google.protobuf.ByteString attachData_ = com.google.protobuf.ByteString.EMPTY; + /** + * optional bytes attach_data = 20; + */ + public boolean hasAttachData() { + return ((bitField0_ & 0x00000008) == 0x00000008); + } + /** + * optional bytes attach_data = 20; + */ + public com.google.protobuf.ByteString getAttachData() { + return attachData_; + } + /** + * optional bytes attach_data = 20; + */ + public Builder setAttachData(com.google.protobuf.ByteString value) { + if (value == null) { + throw new NullPointerException(); + } + bitField0_ |= 0x00000008; + attachData_ = value; + + return this; + } + /** + * optional bytes attach_data = 20; + */ + public Builder clearAttachData() { + bitField0_ = (bitField0_ & ~0x00000008); + attachData_ = getDefaultInstance().getAttachData(); + + return this; + } + + // @@protoc_insertion_point(builder_scope:IM.Login.IMDeviceTokenReq) + } + + static { + defaultInstance = new IMDeviceTokenReq(true); + defaultInstance.initFields(); + } + + // @@protoc_insertion_point(class_scope:IM.Login.IMDeviceTokenReq) + } + + public interface IMDeviceTokenRspOrBuilder extends + // @@protoc_insertion_point(interface_extends:IM.Login.IMDeviceTokenRsp) + com.google.protobuf.MessageLiteOrBuilder { + + /** + * required uint32 user_id = 1; + * + *
+     *cmd id: 		0x0109
+     * 
+ */ + boolean hasUserId(); + /** + * required uint32 user_id = 1; + * + *
+     *cmd id: 		0x0109
+     * 
+ */ + int getUserId(); + + /** + * optional bytes attach_data = 20; + */ + boolean hasAttachData(); + /** + * optional bytes attach_data = 20; + */ + com.google.protobuf.ByteString getAttachData(); + } + /** + * Protobuf type {@code IM.Login.IMDeviceTokenRsp} + */ + public static final class IMDeviceTokenRsp extends + com.google.protobuf.GeneratedMessageLite implements + // @@protoc_insertion_point(message_implements:IM.Login.IMDeviceTokenRsp) + IMDeviceTokenRspOrBuilder { + // Use IMDeviceTokenRsp.newBuilder() to construct. + private IMDeviceTokenRsp(com.google.protobuf.GeneratedMessageLite.Builder builder) { + super(builder); + this.unknownFields = builder.getUnknownFields(); + } + private IMDeviceTokenRsp(boolean noInit) { this.unknownFields = com.google.protobuf.ByteString.EMPTY;} + + private static final IMDeviceTokenRsp defaultInstance; + public static IMDeviceTokenRsp getDefaultInstance() { + return defaultInstance; + } + + public IMDeviceTokenRsp getDefaultInstanceForType() { + return defaultInstance; + } + + private final com.google.protobuf.ByteString unknownFields; + private IMDeviceTokenRsp( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + initFields(); + int mutable_bitField0_ = 0; + com.google.protobuf.ByteString.Output unknownFieldsOutput = + com.google.protobuf.ByteString.newOutput(); + com.google.protobuf.CodedOutputStream unknownFieldsCodedOutput = + com.google.protobuf.CodedOutputStream.newInstance( + unknownFieldsOutput); + try { + boolean done = false; + while (!done) { + int tag = input.readTag(); + switch (tag) { + case 0: + done = true; + break; + default: { + if (!parseUnknownField(input, unknownFieldsCodedOutput, + extensionRegistry, tag)) { + done = true; + } + break; + } + case 8: { + bitField0_ |= 0x00000001; + userId_ = input.readUInt32(); + break; + } + case 162: { + bitField0_ |= 0x00000002; + attachData_ = input.readBytes(); + break; + } + } + } + } catch (com.google.protobuf.InvalidProtocolBufferException e) { + throw e.setUnfinishedMessage(this); + } catch (java.io.IOException e) { + throw new com.google.protobuf.InvalidProtocolBufferException( + e.getMessage()).setUnfinishedMessage(this); + } finally { + try { + unknownFieldsCodedOutput.flush(); + } catch (java.io.IOException e) { + // Should not happen + } finally { + unknownFields = unknownFieldsOutput.toByteString(); + } + makeExtensionsImmutable(); + } + } + public static com.google.protobuf.Parser PARSER = + new com.google.protobuf.AbstractParser() { + public IMDeviceTokenRsp parsePartialFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return new IMDeviceTokenRsp(input, extensionRegistry); + } + }; + + @java.lang.Override + public com.google.protobuf.Parser getParserForType() { + return PARSER; + } + + private int bitField0_; + public static final int USER_ID_FIELD_NUMBER = 1; + private int userId_; + /** + * required uint32 user_id = 1; + * + *
+     *cmd id: 		0x0109
+     * 
+ */ + public boolean hasUserId() { + return ((bitField0_ & 0x00000001) == 0x00000001); + } + /** + * required uint32 user_id = 1; + * + *
+     *cmd id: 		0x0109
+     * 
+ */ + public int getUserId() { + return userId_; + } + + public static final int ATTACH_DATA_FIELD_NUMBER = 20; + private com.google.protobuf.ByteString attachData_; + /** + * optional bytes attach_data = 20; + */ + public boolean hasAttachData() { + return ((bitField0_ & 0x00000002) == 0x00000002); + } + /** + * optional bytes attach_data = 20; + */ + public com.google.protobuf.ByteString getAttachData() { + return attachData_; + } + + private void initFields() { + userId_ = 0; + attachData_ = com.google.protobuf.ByteString.EMPTY; + } + private byte memoizedIsInitialized = -1; + public final boolean isInitialized() { + byte isInitialized = memoizedIsInitialized; + if (isInitialized == 1) return true; + if (isInitialized == 0) return false; + + if (!hasUserId()) { + memoizedIsInitialized = 0; + return false; + } + memoizedIsInitialized = 1; + return true; + } + + public void writeTo(com.google.protobuf.CodedOutputStream output) + throws java.io.IOException { + getSerializedSize(); + if (((bitField0_ & 0x00000001) == 0x00000001)) { + output.writeUInt32(1, userId_); + } + if (((bitField0_ & 0x00000002) == 0x00000002)) { + output.writeBytes(20, attachData_); + } + output.writeRawBytes(unknownFields); + } + + private int memoizedSerializedSize = -1; + public int getSerializedSize() { + int size = memoizedSerializedSize; + if (size != -1) return size; + + size = 0; + if (((bitField0_ & 0x00000001) == 0x00000001)) { + size += com.google.protobuf.CodedOutputStream + .computeUInt32Size(1, userId_); + } + if (((bitField0_ & 0x00000002) == 0x00000002)) { + size += com.google.protobuf.CodedOutputStream + .computeBytesSize(20, attachData_); + } + size += unknownFields.size(); + memoizedSerializedSize = size; + return size; + } + + private static final long serialVersionUID = 0L; + @java.lang.Override + protected java.lang.Object writeReplace() + throws java.io.ObjectStreamException { + return super.writeReplace(); + } + + public static com.mogujie.tt.protobuf.IMLogin.IMDeviceTokenRsp parseFrom( + com.google.protobuf.ByteString data) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data); + } + public static com.mogujie.tt.protobuf.IMLogin.IMDeviceTokenRsp parseFrom( + com.google.protobuf.ByteString data, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data, extensionRegistry); + } + public static com.mogujie.tt.protobuf.IMLogin.IMDeviceTokenRsp parseFrom(byte[] data) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data); + } + public static com.mogujie.tt.protobuf.IMLogin.IMDeviceTokenRsp parseFrom( + byte[] data, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data, extensionRegistry); + } + public static com.mogujie.tt.protobuf.IMLogin.IMDeviceTokenRsp parseFrom(java.io.InputStream input) + throws java.io.IOException { + return PARSER.parseFrom(input); + } + public static com.mogujie.tt.protobuf.IMLogin.IMDeviceTokenRsp parseFrom( + java.io.InputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return PARSER.parseFrom(input, extensionRegistry); + } + public static com.mogujie.tt.protobuf.IMLogin.IMDeviceTokenRsp parseDelimitedFrom(java.io.InputStream input) + throws java.io.IOException { + return PARSER.parseDelimitedFrom(input); + } + public static com.mogujie.tt.protobuf.IMLogin.IMDeviceTokenRsp parseDelimitedFrom( + java.io.InputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return PARSER.parseDelimitedFrom(input, extensionRegistry); + } + public static com.mogujie.tt.protobuf.IMLogin.IMDeviceTokenRsp parseFrom( + com.google.protobuf.CodedInputStream input) + throws java.io.IOException { + return PARSER.parseFrom(input); + } + public static com.mogujie.tt.protobuf.IMLogin.IMDeviceTokenRsp parseFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return PARSER.parseFrom(input, extensionRegistry); + } + + public static Builder newBuilder() { return Builder.create(); } + public Builder newBuilderForType() { return newBuilder(); } + public static Builder newBuilder(com.mogujie.tt.protobuf.IMLogin.IMDeviceTokenRsp prototype) { + return newBuilder().mergeFrom(prototype); + } + public Builder toBuilder() { return newBuilder(this); } + + /** + * Protobuf type {@code IM.Login.IMDeviceTokenRsp} + */ + public static final class Builder extends + com.google.protobuf.GeneratedMessageLite.Builder< + com.mogujie.tt.protobuf.IMLogin.IMDeviceTokenRsp, Builder> + implements + // @@protoc_insertion_point(builder_implements:IM.Login.IMDeviceTokenRsp) + com.mogujie.tt.protobuf.IMLogin.IMDeviceTokenRspOrBuilder { + // Construct using com.mogujie.tt.protobuf.IMLogin.IMDeviceTokenRsp.newBuilder() + private Builder() { + maybeForceBuilderInitialization(); + } + + private void maybeForceBuilderInitialization() { + } + private static Builder create() { + return new Builder(); + } + + public Builder clear() { + super.clear(); + userId_ = 0; + bitField0_ = (bitField0_ & ~0x00000001); + attachData_ = com.google.protobuf.ByteString.EMPTY; + bitField0_ = (bitField0_ & ~0x00000002); + return this; + } + + public Builder clone() { + return create().mergeFrom(buildPartial()); + } + + public com.mogujie.tt.protobuf.IMLogin.IMDeviceTokenRsp getDefaultInstanceForType() { + return com.mogujie.tt.protobuf.IMLogin.IMDeviceTokenRsp.getDefaultInstance(); + } + + public com.mogujie.tt.protobuf.IMLogin.IMDeviceTokenRsp build() { + com.mogujie.tt.protobuf.IMLogin.IMDeviceTokenRsp result = buildPartial(); + if (!result.isInitialized()) { + throw newUninitializedMessageException(result); + } + return result; + } + + public com.mogujie.tt.protobuf.IMLogin.IMDeviceTokenRsp buildPartial() { + com.mogujie.tt.protobuf.IMLogin.IMDeviceTokenRsp result = new com.mogujie.tt.protobuf.IMLogin.IMDeviceTokenRsp(this); + int from_bitField0_ = bitField0_; + int to_bitField0_ = 0; + if (((from_bitField0_ & 0x00000001) == 0x00000001)) { + to_bitField0_ |= 0x00000001; + } + result.userId_ = userId_; + if (((from_bitField0_ & 0x00000002) == 0x00000002)) { + to_bitField0_ |= 0x00000002; + } + result.attachData_ = attachData_; + result.bitField0_ = to_bitField0_; + return result; + } + + public Builder mergeFrom(com.mogujie.tt.protobuf.IMLogin.IMDeviceTokenRsp other) { + if (other == com.mogujie.tt.protobuf.IMLogin.IMDeviceTokenRsp.getDefaultInstance()) return this; + if (other.hasUserId()) { + setUserId(other.getUserId()); + } + if (other.hasAttachData()) { + setAttachData(other.getAttachData()); + } + setUnknownFields( + getUnknownFields().concat(other.unknownFields)); + return this; + } + + public final boolean isInitialized() { + if (!hasUserId()) { + + return false; + } + return true; + } + + public Builder mergeFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + com.mogujie.tt.protobuf.IMLogin.IMDeviceTokenRsp parsedMessage = null; + try { + parsedMessage = PARSER.parsePartialFrom(input, extensionRegistry); + } catch (com.google.protobuf.InvalidProtocolBufferException e) { + parsedMessage = (com.mogujie.tt.protobuf.IMLogin.IMDeviceTokenRsp) e.getUnfinishedMessage(); + throw e; + } finally { + if (parsedMessage != null) { + mergeFrom(parsedMessage); + } + } + return this; + } + private int bitField0_; + + private int userId_ ; + /** + * required uint32 user_id = 1; + * + *
+       *cmd id: 		0x0109
+       * 
+ */ + public boolean hasUserId() { + return ((bitField0_ & 0x00000001) == 0x00000001); + } + /** + * required uint32 user_id = 1; + * + *
+       *cmd id: 		0x0109
+       * 
+ */ + public int getUserId() { + return userId_; + } + /** + * required uint32 user_id = 1; + * + *
+       *cmd id: 		0x0109
+       * 
+ */ + public Builder setUserId(int value) { + bitField0_ |= 0x00000001; + userId_ = value; + + return this; + } + /** + * required uint32 user_id = 1; + * + *
+       *cmd id: 		0x0109
+       * 
+ */ + public Builder clearUserId() { + bitField0_ = (bitField0_ & ~0x00000001); + userId_ = 0; + + return this; + } + + private com.google.protobuf.ByteString attachData_ = com.google.protobuf.ByteString.EMPTY; + /** + * optional bytes attach_data = 20; + */ + public boolean hasAttachData() { + return ((bitField0_ & 0x00000002) == 0x00000002); + } + /** + * optional bytes attach_data = 20; + */ + public com.google.protobuf.ByteString getAttachData() { + return attachData_; + } + /** + * optional bytes attach_data = 20; + */ + public Builder setAttachData(com.google.protobuf.ByteString value) { + if (value == null) { + throw new NullPointerException(); + } + bitField0_ |= 0x00000002; + attachData_ = value; + + return this; + } + /** + * optional bytes attach_data = 20; + */ + public Builder clearAttachData() { + bitField0_ = (bitField0_ & ~0x00000002); + attachData_ = getDefaultInstance().getAttachData(); + + return this; + } + + // @@protoc_insertion_point(builder_scope:IM.Login.IMDeviceTokenRsp) + } + + static { + defaultInstance = new IMDeviceTokenRsp(true); + defaultInstance.initFields(); + } + + // @@protoc_insertion_point(class_scope:IM.Login.IMDeviceTokenRsp) + } + + public interface IMKickPCClientReqOrBuilder extends + // @@protoc_insertion_point(interface_extends:IM.Login.IMKickPCClientReq) + com.google.protobuf.MessageLiteOrBuilder { + + /** + * required uint32 user_id = 1; + * + *
+     *cmd id:		0x010a
+     * 
+ */ + boolean hasUserId(); + /** + * required uint32 user_id = 1; + * + *
+     *cmd id:		0x010a
+     * 
+ */ + int getUserId(); + } + /** + * Protobuf type {@code IM.Login.IMKickPCClientReq} + * + *
+   *只给移动端请求
+   * 
+ */ + public static final class IMKickPCClientReq extends + com.google.protobuf.GeneratedMessageLite implements + // @@protoc_insertion_point(message_implements:IM.Login.IMKickPCClientReq) + IMKickPCClientReqOrBuilder { + // Use IMKickPCClientReq.newBuilder() to construct. + private IMKickPCClientReq(com.google.protobuf.GeneratedMessageLite.Builder builder) { + super(builder); + this.unknownFields = builder.getUnknownFields(); + } + private IMKickPCClientReq(boolean noInit) { this.unknownFields = com.google.protobuf.ByteString.EMPTY;} + + private static final IMKickPCClientReq defaultInstance; + public static IMKickPCClientReq getDefaultInstance() { + return defaultInstance; + } + + public IMKickPCClientReq getDefaultInstanceForType() { + return defaultInstance; + } + + private final com.google.protobuf.ByteString unknownFields; + private IMKickPCClientReq( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + initFields(); + int mutable_bitField0_ = 0; + com.google.protobuf.ByteString.Output unknownFieldsOutput = + com.google.protobuf.ByteString.newOutput(); + com.google.protobuf.CodedOutputStream unknownFieldsCodedOutput = + com.google.protobuf.CodedOutputStream.newInstance( + unknownFieldsOutput); + try { + boolean done = false; + while (!done) { + int tag = input.readTag(); + switch (tag) { + case 0: + done = true; + break; + default: { + if (!parseUnknownField(input, unknownFieldsCodedOutput, + extensionRegistry, tag)) { + done = true; + } + break; + } + case 8: { + bitField0_ |= 0x00000001; + userId_ = input.readUInt32(); + break; + } + } + } + } catch (com.google.protobuf.InvalidProtocolBufferException e) { + throw e.setUnfinishedMessage(this); + } catch (java.io.IOException e) { + throw new com.google.protobuf.InvalidProtocolBufferException( + e.getMessage()).setUnfinishedMessage(this); + } finally { + try { + unknownFieldsCodedOutput.flush(); + } catch (java.io.IOException e) { + // Should not happen + } finally { + unknownFields = unknownFieldsOutput.toByteString(); + } + makeExtensionsImmutable(); + } + } + public static com.google.protobuf.Parser PARSER = + new com.google.protobuf.AbstractParser() { + public IMKickPCClientReq parsePartialFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return new IMKickPCClientReq(input, extensionRegistry); + } + }; + + @java.lang.Override + public com.google.protobuf.Parser getParserForType() { + return PARSER; + } + + private int bitField0_; + public static final int USER_ID_FIELD_NUMBER = 1; + private int userId_; + /** + * required uint32 user_id = 1; + * + *
+     *cmd id:		0x010a
+     * 
+ */ + public boolean hasUserId() { + return ((bitField0_ & 0x00000001) == 0x00000001); + } + /** + * required uint32 user_id = 1; + * + *
+     *cmd id:		0x010a
+     * 
+ */ + public int getUserId() { + return userId_; + } + + private void initFields() { + userId_ = 0; + } + private byte memoizedIsInitialized = -1; + public final boolean isInitialized() { + byte isInitialized = memoizedIsInitialized; + if (isInitialized == 1) return true; + if (isInitialized == 0) return false; + + if (!hasUserId()) { + memoizedIsInitialized = 0; + return false; + } + memoizedIsInitialized = 1; + return true; + } + + public void writeTo(com.google.protobuf.CodedOutputStream output) + throws java.io.IOException { + getSerializedSize(); + if (((bitField0_ & 0x00000001) == 0x00000001)) { + output.writeUInt32(1, userId_); + } + output.writeRawBytes(unknownFields); + } + + private int memoizedSerializedSize = -1; + public int getSerializedSize() { + int size = memoizedSerializedSize; + if (size != -1) return size; + + size = 0; + if (((bitField0_ & 0x00000001) == 0x00000001)) { + size += com.google.protobuf.CodedOutputStream + .computeUInt32Size(1, userId_); + } + size += unknownFields.size(); + memoizedSerializedSize = size; + return size; + } + + private static final long serialVersionUID = 0L; + @java.lang.Override + protected java.lang.Object writeReplace() + throws java.io.ObjectStreamException { + return super.writeReplace(); + } + + public static com.mogujie.tt.protobuf.IMLogin.IMKickPCClientReq parseFrom( + com.google.protobuf.ByteString data) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data); + } + public static com.mogujie.tt.protobuf.IMLogin.IMKickPCClientReq parseFrom( + com.google.protobuf.ByteString data, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data, extensionRegistry); + } + public static com.mogujie.tt.protobuf.IMLogin.IMKickPCClientReq parseFrom(byte[] data) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data); + } + public static com.mogujie.tt.protobuf.IMLogin.IMKickPCClientReq parseFrom( + byte[] data, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data, extensionRegistry); + } + public static com.mogujie.tt.protobuf.IMLogin.IMKickPCClientReq parseFrom(java.io.InputStream input) + throws java.io.IOException { + return PARSER.parseFrom(input); + } + public static com.mogujie.tt.protobuf.IMLogin.IMKickPCClientReq parseFrom( + java.io.InputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return PARSER.parseFrom(input, extensionRegistry); + } + public static com.mogujie.tt.protobuf.IMLogin.IMKickPCClientReq parseDelimitedFrom(java.io.InputStream input) + throws java.io.IOException { + return PARSER.parseDelimitedFrom(input); + } + public static com.mogujie.tt.protobuf.IMLogin.IMKickPCClientReq parseDelimitedFrom( + java.io.InputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return PARSER.parseDelimitedFrom(input, extensionRegistry); + } + public static com.mogujie.tt.protobuf.IMLogin.IMKickPCClientReq parseFrom( + com.google.protobuf.CodedInputStream input) + throws java.io.IOException { + return PARSER.parseFrom(input); + } + public static com.mogujie.tt.protobuf.IMLogin.IMKickPCClientReq parseFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return PARSER.parseFrom(input, extensionRegistry); + } + + public static Builder newBuilder() { return Builder.create(); } + public Builder newBuilderForType() { return newBuilder(); } + public static Builder newBuilder(com.mogujie.tt.protobuf.IMLogin.IMKickPCClientReq prototype) { + return newBuilder().mergeFrom(prototype); + } + public Builder toBuilder() { return newBuilder(this); } + + /** + * Protobuf type {@code IM.Login.IMKickPCClientReq} + * + *
+     *只给移动端请求
+     * 
+ */ + public static final class Builder extends + com.google.protobuf.GeneratedMessageLite.Builder< + com.mogujie.tt.protobuf.IMLogin.IMKickPCClientReq, Builder> + implements + // @@protoc_insertion_point(builder_implements:IM.Login.IMKickPCClientReq) + com.mogujie.tt.protobuf.IMLogin.IMKickPCClientReqOrBuilder { + // Construct using com.mogujie.tt.protobuf.IMLogin.IMKickPCClientReq.newBuilder() + private Builder() { + maybeForceBuilderInitialization(); + } + + private void maybeForceBuilderInitialization() { + } + private static Builder create() { + return new Builder(); + } + + public Builder clear() { + super.clear(); + userId_ = 0; + bitField0_ = (bitField0_ & ~0x00000001); + return this; + } + + public Builder clone() { + return create().mergeFrom(buildPartial()); + } + + public com.mogujie.tt.protobuf.IMLogin.IMKickPCClientReq getDefaultInstanceForType() { + return com.mogujie.tt.protobuf.IMLogin.IMKickPCClientReq.getDefaultInstance(); + } + + public com.mogujie.tt.protobuf.IMLogin.IMKickPCClientReq build() { + com.mogujie.tt.protobuf.IMLogin.IMKickPCClientReq result = buildPartial(); + if (!result.isInitialized()) { + throw newUninitializedMessageException(result); + } + return result; + } + + public com.mogujie.tt.protobuf.IMLogin.IMKickPCClientReq buildPartial() { + com.mogujie.tt.protobuf.IMLogin.IMKickPCClientReq result = new com.mogujie.tt.protobuf.IMLogin.IMKickPCClientReq(this); + int from_bitField0_ = bitField0_; + int to_bitField0_ = 0; + if (((from_bitField0_ & 0x00000001) == 0x00000001)) { + to_bitField0_ |= 0x00000001; + } + result.userId_ = userId_; + result.bitField0_ = to_bitField0_; + return result; + } + + public Builder mergeFrom(com.mogujie.tt.protobuf.IMLogin.IMKickPCClientReq other) { + if (other == com.mogujie.tt.protobuf.IMLogin.IMKickPCClientReq.getDefaultInstance()) return this; + if (other.hasUserId()) { + setUserId(other.getUserId()); + } + setUnknownFields( + getUnknownFields().concat(other.unknownFields)); + return this; + } + + public final boolean isInitialized() { + if (!hasUserId()) { + + return false; + } + return true; + } + + public Builder mergeFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + com.mogujie.tt.protobuf.IMLogin.IMKickPCClientReq parsedMessage = null; + try { + parsedMessage = PARSER.parsePartialFrom(input, extensionRegistry); + } catch (com.google.protobuf.InvalidProtocolBufferException e) { + parsedMessage = (com.mogujie.tt.protobuf.IMLogin.IMKickPCClientReq) e.getUnfinishedMessage(); + throw e; + } finally { + if (parsedMessage != null) { + mergeFrom(parsedMessage); + } + } + return this; + } + private int bitField0_; + + private int userId_ ; + /** + * required uint32 user_id = 1; + * + *
+       *cmd id:		0x010a
+       * 
+ */ + public boolean hasUserId() { + return ((bitField0_ & 0x00000001) == 0x00000001); + } + /** + * required uint32 user_id = 1; + * + *
+       *cmd id:		0x010a
+       * 
+ */ + public int getUserId() { + return userId_; + } + /** + * required uint32 user_id = 1; + * + *
+       *cmd id:		0x010a
+       * 
+ */ + public Builder setUserId(int value) { + bitField0_ |= 0x00000001; + userId_ = value; + + return this; + } + /** + * required uint32 user_id = 1; + * + *
+       *cmd id:		0x010a
+       * 
+ */ + public Builder clearUserId() { + bitField0_ = (bitField0_ & ~0x00000001); + userId_ = 0; + + return this; + } + + // @@protoc_insertion_point(builder_scope:IM.Login.IMKickPCClientReq) + } + + static { + defaultInstance = new IMKickPCClientReq(true); + defaultInstance.initFields(); + } + + // @@protoc_insertion_point(class_scope:IM.Login.IMKickPCClientReq) + } + + public interface IMKickPCClientRspOrBuilder extends + // @@protoc_insertion_point(interface_extends:IM.Login.IMKickPCClientRsp) + com.google.protobuf.MessageLiteOrBuilder { + + /** + * required uint32 user_id = 1; + * + *
+     *cmd id: 		0x010b
+     * 
+ */ + boolean hasUserId(); + /** + * required uint32 user_id = 1; + * + *
+     *cmd id: 		0x010b
+     * 
+ */ + int getUserId(); + + /** + * required uint32 result_code = 2; + */ + boolean hasResultCode(); + /** + * required uint32 result_code = 2; + */ + int getResultCode(); + } + /** + * Protobuf type {@code IM.Login.IMKickPCClientRsp} + */ + public static final class IMKickPCClientRsp extends + com.google.protobuf.GeneratedMessageLite implements + // @@protoc_insertion_point(message_implements:IM.Login.IMKickPCClientRsp) + IMKickPCClientRspOrBuilder { + // Use IMKickPCClientRsp.newBuilder() to construct. + private IMKickPCClientRsp(com.google.protobuf.GeneratedMessageLite.Builder builder) { + super(builder); + this.unknownFields = builder.getUnknownFields(); + } + private IMKickPCClientRsp(boolean noInit) { this.unknownFields = com.google.protobuf.ByteString.EMPTY;} + + private static final IMKickPCClientRsp defaultInstance; + public static IMKickPCClientRsp getDefaultInstance() { + return defaultInstance; + } + + public IMKickPCClientRsp getDefaultInstanceForType() { + return defaultInstance; + } + + private final com.google.protobuf.ByteString unknownFields; + private IMKickPCClientRsp( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + initFields(); + int mutable_bitField0_ = 0; + com.google.protobuf.ByteString.Output unknownFieldsOutput = + com.google.protobuf.ByteString.newOutput(); + com.google.protobuf.CodedOutputStream unknownFieldsCodedOutput = + com.google.protobuf.CodedOutputStream.newInstance( + unknownFieldsOutput); + try { + boolean done = false; + while (!done) { + int tag = input.readTag(); + switch (tag) { + case 0: + done = true; + break; + default: { + if (!parseUnknownField(input, unknownFieldsCodedOutput, + extensionRegistry, tag)) { + done = true; + } + break; + } + case 8: { + bitField0_ |= 0x00000001; + userId_ = input.readUInt32(); + break; + } + case 16: { + bitField0_ |= 0x00000002; + resultCode_ = input.readUInt32(); + break; + } + } + } + } catch (com.google.protobuf.InvalidProtocolBufferException e) { + throw e.setUnfinishedMessage(this); + } catch (java.io.IOException e) { + throw new com.google.protobuf.InvalidProtocolBufferException( + e.getMessage()).setUnfinishedMessage(this); + } finally { + try { + unknownFieldsCodedOutput.flush(); + } catch (java.io.IOException e) { + // Should not happen + } finally { + unknownFields = unknownFieldsOutput.toByteString(); + } + makeExtensionsImmutable(); + } + } + public static com.google.protobuf.Parser PARSER = + new com.google.protobuf.AbstractParser() { + public IMKickPCClientRsp parsePartialFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return new IMKickPCClientRsp(input, extensionRegistry); + } + }; + + @java.lang.Override + public com.google.protobuf.Parser getParserForType() { + return PARSER; + } + + private int bitField0_; + public static final int USER_ID_FIELD_NUMBER = 1; + private int userId_; + /** + * required uint32 user_id = 1; + * + *
+     *cmd id: 		0x010b
+     * 
+ */ + public boolean hasUserId() { + return ((bitField0_ & 0x00000001) == 0x00000001); + } + /** + * required uint32 user_id = 1; + * + *
+     *cmd id: 		0x010b
+     * 
+ */ + public int getUserId() { + return userId_; + } + + public static final int RESULT_CODE_FIELD_NUMBER = 2; + private int resultCode_; + /** + * required uint32 result_code = 2; + */ + public boolean hasResultCode() { + return ((bitField0_ & 0x00000002) == 0x00000002); + } + /** + * required uint32 result_code = 2; + */ + public int getResultCode() { + return resultCode_; + } + + private void initFields() { + userId_ = 0; + resultCode_ = 0; + } + private byte memoizedIsInitialized = -1; + public final boolean isInitialized() { + byte isInitialized = memoizedIsInitialized; + if (isInitialized == 1) return true; + if (isInitialized == 0) return false; + + if (!hasUserId()) { + memoizedIsInitialized = 0; + return false; + } + if (!hasResultCode()) { + memoizedIsInitialized = 0; + return false; + } + memoizedIsInitialized = 1; + return true; + } + + public void writeTo(com.google.protobuf.CodedOutputStream output) + throws java.io.IOException { + getSerializedSize(); + if (((bitField0_ & 0x00000001) == 0x00000001)) { + output.writeUInt32(1, userId_); + } + if (((bitField0_ & 0x00000002) == 0x00000002)) { + output.writeUInt32(2, resultCode_); + } + output.writeRawBytes(unknownFields); + } + + private int memoizedSerializedSize = -1; + public int getSerializedSize() { + int size = memoizedSerializedSize; + if (size != -1) return size; + + size = 0; + if (((bitField0_ & 0x00000001) == 0x00000001)) { + size += com.google.protobuf.CodedOutputStream + .computeUInt32Size(1, userId_); + } + if (((bitField0_ & 0x00000002) == 0x00000002)) { + size += com.google.protobuf.CodedOutputStream + .computeUInt32Size(2, resultCode_); + } + size += unknownFields.size(); + memoizedSerializedSize = size; + return size; + } + + private static final long serialVersionUID = 0L; + @java.lang.Override + protected java.lang.Object writeReplace() + throws java.io.ObjectStreamException { + return super.writeReplace(); + } + + public static com.mogujie.tt.protobuf.IMLogin.IMKickPCClientRsp parseFrom( + com.google.protobuf.ByteString data) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data); + } + public static com.mogujie.tt.protobuf.IMLogin.IMKickPCClientRsp parseFrom( + com.google.protobuf.ByteString data, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data, extensionRegistry); + } + public static com.mogujie.tt.protobuf.IMLogin.IMKickPCClientRsp parseFrom(byte[] data) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data); + } + public static com.mogujie.tt.protobuf.IMLogin.IMKickPCClientRsp parseFrom( + byte[] data, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data, extensionRegistry); + } + public static com.mogujie.tt.protobuf.IMLogin.IMKickPCClientRsp parseFrom(java.io.InputStream input) + throws java.io.IOException { + return PARSER.parseFrom(input); + } + public static com.mogujie.tt.protobuf.IMLogin.IMKickPCClientRsp parseFrom( + java.io.InputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return PARSER.parseFrom(input, extensionRegistry); + } + public static com.mogujie.tt.protobuf.IMLogin.IMKickPCClientRsp parseDelimitedFrom(java.io.InputStream input) + throws java.io.IOException { + return PARSER.parseDelimitedFrom(input); + } + public static com.mogujie.tt.protobuf.IMLogin.IMKickPCClientRsp parseDelimitedFrom( + java.io.InputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return PARSER.parseDelimitedFrom(input, extensionRegistry); + } + public static com.mogujie.tt.protobuf.IMLogin.IMKickPCClientRsp parseFrom( + com.google.protobuf.CodedInputStream input) + throws java.io.IOException { + return PARSER.parseFrom(input); + } + public static com.mogujie.tt.protobuf.IMLogin.IMKickPCClientRsp parseFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return PARSER.parseFrom(input, extensionRegistry); + } + + public static Builder newBuilder() { return Builder.create(); } + public Builder newBuilderForType() { return newBuilder(); } + public static Builder newBuilder(com.mogujie.tt.protobuf.IMLogin.IMKickPCClientRsp prototype) { + return newBuilder().mergeFrom(prototype); + } + public Builder toBuilder() { return newBuilder(this); } + + /** + * Protobuf type {@code IM.Login.IMKickPCClientRsp} + */ + public static final class Builder extends + com.google.protobuf.GeneratedMessageLite.Builder< + com.mogujie.tt.protobuf.IMLogin.IMKickPCClientRsp, Builder> + implements + // @@protoc_insertion_point(builder_implements:IM.Login.IMKickPCClientRsp) + com.mogujie.tt.protobuf.IMLogin.IMKickPCClientRspOrBuilder { + // Construct using com.mogujie.tt.protobuf.IMLogin.IMKickPCClientRsp.newBuilder() + private Builder() { + maybeForceBuilderInitialization(); + } + + private void maybeForceBuilderInitialization() { + } + private static Builder create() { + return new Builder(); + } + + public Builder clear() { + super.clear(); + userId_ = 0; + bitField0_ = (bitField0_ & ~0x00000001); + resultCode_ = 0; + bitField0_ = (bitField0_ & ~0x00000002); + return this; + } + + public Builder clone() { + return create().mergeFrom(buildPartial()); + } + + public com.mogujie.tt.protobuf.IMLogin.IMKickPCClientRsp getDefaultInstanceForType() { + return com.mogujie.tt.protobuf.IMLogin.IMKickPCClientRsp.getDefaultInstance(); + } + + public com.mogujie.tt.protobuf.IMLogin.IMKickPCClientRsp build() { + com.mogujie.tt.protobuf.IMLogin.IMKickPCClientRsp result = buildPartial(); + if (!result.isInitialized()) { + throw newUninitializedMessageException(result); + } + return result; + } + + public com.mogujie.tt.protobuf.IMLogin.IMKickPCClientRsp buildPartial() { + com.mogujie.tt.protobuf.IMLogin.IMKickPCClientRsp result = new com.mogujie.tt.protobuf.IMLogin.IMKickPCClientRsp(this); + int from_bitField0_ = bitField0_; + int to_bitField0_ = 0; + if (((from_bitField0_ & 0x00000001) == 0x00000001)) { + to_bitField0_ |= 0x00000001; + } + result.userId_ = userId_; + if (((from_bitField0_ & 0x00000002) == 0x00000002)) { + to_bitField0_ |= 0x00000002; + } + result.resultCode_ = resultCode_; + result.bitField0_ = to_bitField0_; + return result; + } + + public Builder mergeFrom(com.mogujie.tt.protobuf.IMLogin.IMKickPCClientRsp other) { + if (other == com.mogujie.tt.protobuf.IMLogin.IMKickPCClientRsp.getDefaultInstance()) return this; + if (other.hasUserId()) { + setUserId(other.getUserId()); + } + if (other.hasResultCode()) { + setResultCode(other.getResultCode()); + } + setUnknownFields( + getUnknownFields().concat(other.unknownFields)); + return this; + } + + public final boolean isInitialized() { + if (!hasUserId()) { + + return false; + } + if (!hasResultCode()) { + + return false; + } + return true; + } + + public Builder mergeFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + com.mogujie.tt.protobuf.IMLogin.IMKickPCClientRsp parsedMessage = null; + try { + parsedMessage = PARSER.parsePartialFrom(input, extensionRegistry); + } catch (com.google.protobuf.InvalidProtocolBufferException e) { + parsedMessage = (com.mogujie.tt.protobuf.IMLogin.IMKickPCClientRsp) e.getUnfinishedMessage(); + throw e; + } finally { + if (parsedMessage != null) { + mergeFrom(parsedMessage); + } + } + return this; + } + private int bitField0_; + + private int userId_ ; + /** + * required uint32 user_id = 1; + * + *
+       *cmd id: 		0x010b
+       * 
+ */ + public boolean hasUserId() { + return ((bitField0_ & 0x00000001) == 0x00000001); + } + /** + * required uint32 user_id = 1; + * + *
+       *cmd id: 		0x010b
+       * 
+ */ + public int getUserId() { + return userId_; + } + /** + * required uint32 user_id = 1; + * + *
+       *cmd id: 		0x010b
+       * 
+ */ + public Builder setUserId(int value) { + bitField0_ |= 0x00000001; + userId_ = value; + + return this; + } + /** + * required uint32 user_id = 1; + * + *
+       *cmd id: 		0x010b
+       * 
+ */ + public Builder clearUserId() { + bitField0_ = (bitField0_ & ~0x00000001); + userId_ = 0; + + return this; + } + + private int resultCode_ ; + /** + * required uint32 result_code = 2; + */ + public boolean hasResultCode() { + return ((bitField0_ & 0x00000002) == 0x00000002); + } + /** + * required uint32 result_code = 2; + */ + public int getResultCode() { + return resultCode_; + } + /** + * required uint32 result_code = 2; + */ + public Builder setResultCode(int value) { + bitField0_ |= 0x00000002; + resultCode_ = value; + + return this; + } + /** + * required uint32 result_code = 2; + */ + public Builder clearResultCode() { + bitField0_ = (bitField0_ & ~0x00000002); + resultCode_ = 0; + + return this; + } + + // @@protoc_insertion_point(builder_scope:IM.Login.IMKickPCClientRsp) + } + + static { + defaultInstance = new IMKickPCClientRsp(true); + defaultInstance.initFields(); + } + + // @@protoc_insertion_point(class_scope:IM.Login.IMKickPCClientRsp) + } + + + static { + } + + // @@protoc_insertion_point(outer_class_scope) +} diff --git a/android/app/src/main/java/com/mogujie/tt/protobuf/IMMessage.java b/android/app/src/main/java/com/mogujie/tt/protobuf/IMMessage.java new file mode 100644 index 000000000..e11a18773 --- /dev/null +++ b/android/app/src/main/java/com/mogujie/tt/protobuf/IMMessage.java @@ -0,0 +1,9759 @@ +// Generated by the protocol buffer compiler. DO NOT EDIT! +// source: IM.Message.proto + +package com.mogujie.tt.protobuf; + +public final class IMMessage { + private IMMessage() {} + public static void registerAllExtensions( + com.google.protobuf.ExtensionRegistryLite registry) { + } + public interface IMMsgDataOrBuilder extends + // @@protoc_insertion_point(interface_extends:IM.Message.IMMsgData) + com.google.protobuf.MessageLiteOrBuilder { + + /** + * required uint32 from_user_id = 1; + * + *
+     *cmd id:		0x0301
+     * 
+ */ + boolean hasFromUserId(); + /** + * required uint32 from_user_id = 1; + * + *
+     *cmd id:		0x0301
+     * 
+ */ + int getFromUserId(); + + /** + * required uint32 to_session_id = 2; + * + *
+     *消息接受方
+     * 
+ */ + boolean hasToSessionId(); + /** + * required uint32 to_session_id = 2; + * + *
+     *消息接受方
+     * 
+ */ + int getToSessionId(); + + /** + * required uint32 msg_id = 3; + */ + boolean hasMsgId(); + /** + * required uint32 msg_id = 3; + */ + int getMsgId(); + + /** + * required uint32 create_time = 4; + */ + boolean hasCreateTime(); + /** + * required uint32 create_time = 4; + */ + int getCreateTime(); + + /** + * required .IM.BaseDefine.MsgType msg_type = 5; + */ + boolean hasMsgType(); + /** + * required .IM.BaseDefine.MsgType msg_type = 5; + */ + com.mogujie.tt.protobuf.IMBaseDefine.MsgType getMsgType(); + + /** + * required bytes msg_data = 6; + */ + boolean hasMsgData(); + /** + * required bytes msg_data = 6; + */ + com.google.protobuf.ByteString getMsgData(); + + /** + * optional bytes attach_data = 20; + */ + boolean hasAttachData(); + /** + * optional bytes attach_data = 20; + */ + com.google.protobuf.ByteString getAttachData(); + } + /** + * Protobuf type {@code IM.Message.IMMsgData} + * + *
+   *service id  0x0003
+   * 
+ */ + public static final class IMMsgData extends + com.google.protobuf.GeneratedMessageLite implements + // @@protoc_insertion_point(message_implements:IM.Message.IMMsgData) + IMMsgDataOrBuilder { + // Use IMMsgData.newBuilder() to construct. + private IMMsgData(com.google.protobuf.GeneratedMessageLite.Builder builder) { + super(builder); + this.unknownFields = builder.getUnknownFields(); + } + private IMMsgData(boolean noInit) { this.unknownFields = com.google.protobuf.ByteString.EMPTY;} + + private static final IMMsgData defaultInstance; + public static IMMsgData getDefaultInstance() { + return defaultInstance; + } + + public IMMsgData getDefaultInstanceForType() { + return defaultInstance; + } + + private final com.google.protobuf.ByteString unknownFields; + private IMMsgData( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + initFields(); + int mutable_bitField0_ = 0; + com.google.protobuf.ByteString.Output unknownFieldsOutput = + com.google.protobuf.ByteString.newOutput(); + com.google.protobuf.CodedOutputStream unknownFieldsCodedOutput = + com.google.protobuf.CodedOutputStream.newInstance( + unknownFieldsOutput); + try { + boolean done = false; + while (!done) { + int tag = input.readTag(); + switch (tag) { + case 0: + done = true; + break; + default: { + if (!parseUnknownField(input, unknownFieldsCodedOutput, + extensionRegistry, tag)) { + done = true; + } + break; + } + case 8: { + bitField0_ |= 0x00000001; + fromUserId_ = input.readUInt32(); + break; + } + case 16: { + bitField0_ |= 0x00000002; + toSessionId_ = input.readUInt32(); + break; + } + case 24: { + bitField0_ |= 0x00000004; + msgId_ = input.readUInt32(); + break; + } + case 32: { + bitField0_ |= 0x00000008; + createTime_ = input.readUInt32(); + break; + } + case 40: { + int rawValue = input.readEnum(); + com.mogujie.tt.protobuf.IMBaseDefine.MsgType value = com.mogujie.tt.protobuf.IMBaseDefine.MsgType.valueOf(rawValue); + if (value == null) { + unknownFieldsCodedOutput.writeRawVarint32(tag); + unknownFieldsCodedOutput.writeRawVarint32(rawValue); + } else { + bitField0_ |= 0x00000010; + msgType_ = value; + } + break; + } + case 50: { + bitField0_ |= 0x00000020; + msgData_ = input.readBytes(); + break; + } + case 162: { + bitField0_ |= 0x00000040; + attachData_ = input.readBytes(); + break; + } + } + } + } catch (com.google.protobuf.InvalidProtocolBufferException e) { + throw e.setUnfinishedMessage(this); + } catch (java.io.IOException e) { + throw new com.google.protobuf.InvalidProtocolBufferException( + e.getMessage()).setUnfinishedMessage(this); + } finally { + try { + unknownFieldsCodedOutput.flush(); + } catch (java.io.IOException e) { + // Should not happen + } finally { + unknownFields = unknownFieldsOutput.toByteString(); + } + makeExtensionsImmutable(); + } + } + public static com.google.protobuf.Parser PARSER = + new com.google.protobuf.AbstractParser() { + public IMMsgData parsePartialFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return new IMMsgData(input, extensionRegistry); + } + }; + + @java.lang.Override + public com.google.protobuf.Parser getParserForType() { + return PARSER; + } + + private int bitField0_; + public static final int FROM_USER_ID_FIELD_NUMBER = 1; + private int fromUserId_; + /** + * required uint32 from_user_id = 1; + * + *
+     *cmd id:		0x0301
+     * 
+ */ + public boolean hasFromUserId() { + return ((bitField0_ & 0x00000001) == 0x00000001); + } + /** + * required uint32 from_user_id = 1; + * + *
+     *cmd id:		0x0301
+     * 
+ */ + public int getFromUserId() { + return fromUserId_; + } + + public static final int TO_SESSION_ID_FIELD_NUMBER = 2; + private int toSessionId_; + /** + * required uint32 to_session_id = 2; + * + *
+     *消息接受方
+     * 
+ */ + public boolean hasToSessionId() { + return ((bitField0_ & 0x00000002) == 0x00000002); + } + /** + * required uint32 to_session_id = 2; + * + *
+     *消息接受方
+     * 
+ */ + public int getToSessionId() { + return toSessionId_; + } + + public static final int MSG_ID_FIELD_NUMBER = 3; + private int msgId_; + /** + * required uint32 msg_id = 3; + */ + public boolean hasMsgId() { + return ((bitField0_ & 0x00000004) == 0x00000004); + } + /** + * required uint32 msg_id = 3; + */ + public int getMsgId() { + return msgId_; + } + + public static final int CREATE_TIME_FIELD_NUMBER = 4; + private int createTime_; + /** + * required uint32 create_time = 4; + */ + public boolean hasCreateTime() { + return ((bitField0_ & 0x00000008) == 0x00000008); + } + /** + * required uint32 create_time = 4; + */ + public int getCreateTime() { + return createTime_; + } + + public static final int MSG_TYPE_FIELD_NUMBER = 5; + private com.mogujie.tt.protobuf.IMBaseDefine.MsgType msgType_; + /** + * required .IM.BaseDefine.MsgType msg_type = 5; + */ + public boolean hasMsgType() { + return ((bitField0_ & 0x00000010) == 0x00000010); + } + /** + * required .IM.BaseDefine.MsgType msg_type = 5; + */ + public com.mogujie.tt.protobuf.IMBaseDefine.MsgType getMsgType() { + return msgType_; + } + + public static final int MSG_DATA_FIELD_NUMBER = 6; + private com.google.protobuf.ByteString msgData_; + /** + * required bytes msg_data = 6; + */ + public boolean hasMsgData() { + return ((bitField0_ & 0x00000020) == 0x00000020); + } + /** + * required bytes msg_data = 6; + */ + public com.google.protobuf.ByteString getMsgData() { + return msgData_; + } + + public static final int ATTACH_DATA_FIELD_NUMBER = 20; + private com.google.protobuf.ByteString attachData_; + /** + * optional bytes attach_data = 20; + */ + public boolean hasAttachData() { + return ((bitField0_ & 0x00000040) == 0x00000040); + } + /** + * optional bytes attach_data = 20; + */ + public com.google.protobuf.ByteString getAttachData() { + return attachData_; + } + + private void initFields() { + fromUserId_ = 0; + toSessionId_ = 0; + msgId_ = 0; + createTime_ = 0; + msgType_ = com.mogujie.tt.protobuf.IMBaseDefine.MsgType.MSG_TYPE_SINGLE_TEXT; + msgData_ = com.google.protobuf.ByteString.EMPTY; + attachData_ = com.google.protobuf.ByteString.EMPTY; + } + private byte memoizedIsInitialized = -1; + public final boolean isInitialized() { + byte isInitialized = memoizedIsInitialized; + if (isInitialized == 1) return true; + if (isInitialized == 0) return false; + + if (!hasFromUserId()) { + memoizedIsInitialized = 0; + return false; + } + if (!hasToSessionId()) { + memoizedIsInitialized = 0; + return false; + } + if (!hasMsgId()) { + memoizedIsInitialized = 0; + return false; + } + if (!hasCreateTime()) { + memoizedIsInitialized = 0; + return false; + } + if (!hasMsgType()) { + memoizedIsInitialized = 0; + return false; + } + if (!hasMsgData()) { + memoizedIsInitialized = 0; + return false; + } + memoizedIsInitialized = 1; + return true; + } + + public void writeTo(com.google.protobuf.CodedOutputStream output) + throws java.io.IOException { + getSerializedSize(); + if (((bitField0_ & 0x00000001) == 0x00000001)) { + output.writeUInt32(1, fromUserId_); + } + if (((bitField0_ & 0x00000002) == 0x00000002)) { + output.writeUInt32(2, toSessionId_); + } + if (((bitField0_ & 0x00000004) == 0x00000004)) { + output.writeUInt32(3, msgId_); + } + if (((bitField0_ & 0x00000008) == 0x00000008)) { + output.writeUInt32(4, createTime_); + } + if (((bitField0_ & 0x00000010) == 0x00000010)) { + output.writeEnum(5, msgType_.getNumber()); + } + if (((bitField0_ & 0x00000020) == 0x00000020)) { + output.writeBytes(6, msgData_); + } + if (((bitField0_ & 0x00000040) == 0x00000040)) { + output.writeBytes(20, attachData_); + } + output.writeRawBytes(unknownFields); + } + + private int memoizedSerializedSize = -1; + public int getSerializedSize() { + int size = memoizedSerializedSize; + if (size != -1) return size; + + size = 0; + if (((bitField0_ & 0x00000001) == 0x00000001)) { + size += com.google.protobuf.CodedOutputStream + .computeUInt32Size(1, fromUserId_); + } + if (((bitField0_ & 0x00000002) == 0x00000002)) { + size += com.google.protobuf.CodedOutputStream + .computeUInt32Size(2, toSessionId_); + } + if (((bitField0_ & 0x00000004) == 0x00000004)) { + size += com.google.protobuf.CodedOutputStream + .computeUInt32Size(3, msgId_); + } + if (((bitField0_ & 0x00000008) == 0x00000008)) { + size += com.google.protobuf.CodedOutputStream + .computeUInt32Size(4, createTime_); + } + if (((bitField0_ & 0x00000010) == 0x00000010)) { + size += com.google.protobuf.CodedOutputStream + .computeEnumSize(5, msgType_.getNumber()); + } + if (((bitField0_ & 0x00000020) == 0x00000020)) { + size += com.google.protobuf.CodedOutputStream + .computeBytesSize(6, msgData_); + } + if (((bitField0_ & 0x00000040) == 0x00000040)) { + size += com.google.protobuf.CodedOutputStream + .computeBytesSize(20, attachData_); + } + size += unknownFields.size(); + memoizedSerializedSize = size; + return size; + } + + private static final long serialVersionUID = 0L; + @java.lang.Override + protected java.lang.Object writeReplace() + throws java.io.ObjectStreamException { + return super.writeReplace(); + } + + public static com.mogujie.tt.protobuf.IMMessage.IMMsgData parseFrom( + com.google.protobuf.ByteString data) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data); + } + public static com.mogujie.tt.protobuf.IMMessage.IMMsgData parseFrom( + com.google.protobuf.ByteString data, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data, extensionRegistry); + } + public static com.mogujie.tt.protobuf.IMMessage.IMMsgData parseFrom(byte[] data) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data); + } + public static com.mogujie.tt.protobuf.IMMessage.IMMsgData parseFrom( + byte[] data, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data, extensionRegistry); + } + public static com.mogujie.tt.protobuf.IMMessage.IMMsgData parseFrom(java.io.InputStream input) + throws java.io.IOException { + return PARSER.parseFrom(input); + } + public static com.mogujie.tt.protobuf.IMMessage.IMMsgData parseFrom( + java.io.InputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return PARSER.parseFrom(input, extensionRegistry); + } + public static com.mogujie.tt.protobuf.IMMessage.IMMsgData parseDelimitedFrom(java.io.InputStream input) + throws java.io.IOException { + return PARSER.parseDelimitedFrom(input); + } + public static com.mogujie.tt.protobuf.IMMessage.IMMsgData parseDelimitedFrom( + java.io.InputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return PARSER.parseDelimitedFrom(input, extensionRegistry); + } + public static com.mogujie.tt.protobuf.IMMessage.IMMsgData parseFrom( + com.google.protobuf.CodedInputStream input) + throws java.io.IOException { + return PARSER.parseFrom(input); + } + public static com.mogujie.tt.protobuf.IMMessage.IMMsgData parseFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return PARSER.parseFrom(input, extensionRegistry); + } + + public static Builder newBuilder() { return Builder.create(); } + public Builder newBuilderForType() { return newBuilder(); } + public static Builder newBuilder(com.mogujie.tt.protobuf.IMMessage.IMMsgData prototype) { + return newBuilder().mergeFrom(prototype); + } + public Builder toBuilder() { return newBuilder(this); } + + /** + * Protobuf type {@code IM.Message.IMMsgData} + * + *
+     *service id  0x0003
+     * 
+ */ + public static final class Builder extends + com.google.protobuf.GeneratedMessageLite.Builder< + com.mogujie.tt.protobuf.IMMessage.IMMsgData, Builder> + implements + // @@protoc_insertion_point(builder_implements:IM.Message.IMMsgData) + com.mogujie.tt.protobuf.IMMessage.IMMsgDataOrBuilder { + // Construct using com.mogujie.tt.protobuf.IMMessage.IMMsgData.newBuilder() + private Builder() { + maybeForceBuilderInitialization(); + } + + private void maybeForceBuilderInitialization() { + } + private static Builder create() { + return new Builder(); + } + + public Builder clear() { + super.clear(); + fromUserId_ = 0; + bitField0_ = (bitField0_ & ~0x00000001); + toSessionId_ = 0; + bitField0_ = (bitField0_ & ~0x00000002); + msgId_ = 0; + bitField0_ = (bitField0_ & ~0x00000004); + createTime_ = 0; + bitField0_ = (bitField0_ & ~0x00000008); + msgType_ = com.mogujie.tt.protobuf.IMBaseDefine.MsgType.MSG_TYPE_SINGLE_TEXT; + bitField0_ = (bitField0_ & ~0x00000010); + msgData_ = com.google.protobuf.ByteString.EMPTY; + bitField0_ = (bitField0_ & ~0x00000020); + attachData_ = com.google.protobuf.ByteString.EMPTY; + bitField0_ = (bitField0_ & ~0x00000040); + return this; + } + + public Builder clone() { + return create().mergeFrom(buildPartial()); + } + + public com.mogujie.tt.protobuf.IMMessage.IMMsgData getDefaultInstanceForType() { + return com.mogujie.tt.protobuf.IMMessage.IMMsgData.getDefaultInstance(); + } + + public com.mogujie.tt.protobuf.IMMessage.IMMsgData build() { + com.mogujie.tt.protobuf.IMMessage.IMMsgData result = buildPartial(); + if (!result.isInitialized()) { + throw newUninitializedMessageException(result); + } + return result; + } + + public com.mogujie.tt.protobuf.IMMessage.IMMsgData buildPartial() { + com.mogujie.tt.protobuf.IMMessage.IMMsgData result = new com.mogujie.tt.protobuf.IMMessage.IMMsgData(this); + int from_bitField0_ = bitField0_; + int to_bitField0_ = 0; + if (((from_bitField0_ & 0x00000001) == 0x00000001)) { + to_bitField0_ |= 0x00000001; + } + result.fromUserId_ = fromUserId_; + if (((from_bitField0_ & 0x00000002) == 0x00000002)) { + to_bitField0_ |= 0x00000002; + } + result.toSessionId_ = toSessionId_; + if (((from_bitField0_ & 0x00000004) == 0x00000004)) { + to_bitField0_ |= 0x00000004; + } + result.msgId_ = msgId_; + if (((from_bitField0_ & 0x00000008) == 0x00000008)) { + to_bitField0_ |= 0x00000008; + } + result.createTime_ = createTime_; + if (((from_bitField0_ & 0x00000010) == 0x00000010)) { + to_bitField0_ |= 0x00000010; + } + result.msgType_ = msgType_; + if (((from_bitField0_ & 0x00000020) == 0x00000020)) { + to_bitField0_ |= 0x00000020; + } + result.msgData_ = msgData_; + if (((from_bitField0_ & 0x00000040) == 0x00000040)) { + to_bitField0_ |= 0x00000040; + } + result.attachData_ = attachData_; + result.bitField0_ = to_bitField0_; + return result; + } + + public Builder mergeFrom(com.mogujie.tt.protobuf.IMMessage.IMMsgData other) { + if (other == com.mogujie.tt.protobuf.IMMessage.IMMsgData.getDefaultInstance()) return this; + if (other.hasFromUserId()) { + setFromUserId(other.getFromUserId()); + } + if (other.hasToSessionId()) { + setToSessionId(other.getToSessionId()); + } + if (other.hasMsgId()) { + setMsgId(other.getMsgId()); + } + if (other.hasCreateTime()) { + setCreateTime(other.getCreateTime()); + } + if (other.hasMsgType()) { + setMsgType(other.getMsgType()); + } + if (other.hasMsgData()) { + setMsgData(other.getMsgData()); + } + if (other.hasAttachData()) { + setAttachData(other.getAttachData()); + } + setUnknownFields( + getUnknownFields().concat(other.unknownFields)); + return this; + } + + public final boolean isInitialized() { + if (!hasFromUserId()) { + + return false; + } + if (!hasToSessionId()) { + + return false; + } + if (!hasMsgId()) { + + return false; + } + if (!hasCreateTime()) { + + return false; + } + if (!hasMsgType()) { + + return false; + } + if (!hasMsgData()) { + + return false; + } + return true; + } + + public Builder mergeFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + com.mogujie.tt.protobuf.IMMessage.IMMsgData parsedMessage = null; + try { + parsedMessage = PARSER.parsePartialFrom(input, extensionRegistry); + } catch (com.google.protobuf.InvalidProtocolBufferException e) { + parsedMessage = (com.mogujie.tt.protobuf.IMMessage.IMMsgData) e.getUnfinishedMessage(); + throw e; + } finally { + if (parsedMessage != null) { + mergeFrom(parsedMessage); + } + } + return this; + } + private int bitField0_; + + private int fromUserId_ ; + /** + * required uint32 from_user_id = 1; + * + *
+       *cmd id:		0x0301
+       * 
+ */ + public boolean hasFromUserId() { + return ((bitField0_ & 0x00000001) == 0x00000001); + } + /** + * required uint32 from_user_id = 1; + * + *
+       *cmd id:		0x0301
+       * 
+ */ + public int getFromUserId() { + return fromUserId_; + } + /** + * required uint32 from_user_id = 1; + * + *
+       *cmd id:		0x0301
+       * 
+ */ + public Builder setFromUserId(int value) { + bitField0_ |= 0x00000001; + fromUserId_ = value; + + return this; + } + /** + * required uint32 from_user_id = 1; + * + *
+       *cmd id:		0x0301
+       * 
+ */ + public Builder clearFromUserId() { + bitField0_ = (bitField0_ & ~0x00000001); + fromUserId_ = 0; + + return this; + } + + private int toSessionId_ ; + /** + * required uint32 to_session_id = 2; + * + *
+       *消息接受方
+       * 
+ */ + public boolean hasToSessionId() { + return ((bitField0_ & 0x00000002) == 0x00000002); + } + /** + * required uint32 to_session_id = 2; + * + *
+       *消息接受方
+       * 
+ */ + public int getToSessionId() { + return toSessionId_; + } + /** + * required uint32 to_session_id = 2; + * + *
+       *消息接受方
+       * 
+ */ + public Builder setToSessionId(int value) { + bitField0_ |= 0x00000002; + toSessionId_ = value; + + return this; + } + /** + * required uint32 to_session_id = 2; + * + *
+       *消息接受方
+       * 
+ */ + public Builder clearToSessionId() { + bitField0_ = (bitField0_ & ~0x00000002); + toSessionId_ = 0; + + return this; + } + + private int msgId_ ; + /** + * required uint32 msg_id = 3; + */ + public boolean hasMsgId() { + return ((bitField0_ & 0x00000004) == 0x00000004); + } + /** + * required uint32 msg_id = 3; + */ + public int getMsgId() { + return msgId_; + } + /** + * required uint32 msg_id = 3; + */ + public Builder setMsgId(int value) { + bitField0_ |= 0x00000004; + msgId_ = value; + + return this; + } + /** + * required uint32 msg_id = 3; + */ + public Builder clearMsgId() { + bitField0_ = (bitField0_ & ~0x00000004); + msgId_ = 0; + + return this; + } + + private int createTime_ ; + /** + * required uint32 create_time = 4; + */ + public boolean hasCreateTime() { + return ((bitField0_ & 0x00000008) == 0x00000008); + } + /** + * required uint32 create_time = 4; + */ + public int getCreateTime() { + return createTime_; + } + /** + * required uint32 create_time = 4; + */ + public Builder setCreateTime(int value) { + bitField0_ |= 0x00000008; + createTime_ = value; + + return this; + } + /** + * required uint32 create_time = 4; + */ + public Builder clearCreateTime() { + bitField0_ = (bitField0_ & ~0x00000008); + createTime_ = 0; + + return this; + } + + private com.mogujie.tt.protobuf.IMBaseDefine.MsgType msgType_ = com.mogujie.tt.protobuf.IMBaseDefine.MsgType.MSG_TYPE_SINGLE_TEXT; + /** + * required .IM.BaseDefine.MsgType msg_type = 5; + */ + public boolean hasMsgType() { + return ((bitField0_ & 0x00000010) == 0x00000010); + } + /** + * required .IM.BaseDefine.MsgType msg_type = 5; + */ + public com.mogujie.tt.protobuf.IMBaseDefine.MsgType getMsgType() { + return msgType_; + } + /** + * required .IM.BaseDefine.MsgType msg_type = 5; + */ + public Builder setMsgType(com.mogujie.tt.protobuf.IMBaseDefine.MsgType value) { + if (value == null) { + throw new NullPointerException(); + } + bitField0_ |= 0x00000010; + msgType_ = value; + + return this; + } + /** + * required .IM.BaseDefine.MsgType msg_type = 5; + */ + public Builder clearMsgType() { + bitField0_ = (bitField0_ & ~0x00000010); + msgType_ = com.mogujie.tt.protobuf.IMBaseDefine.MsgType.MSG_TYPE_SINGLE_TEXT; + + return this; + } + + private com.google.protobuf.ByteString msgData_ = com.google.protobuf.ByteString.EMPTY; + /** + * required bytes msg_data = 6; + */ + public boolean hasMsgData() { + return ((bitField0_ & 0x00000020) == 0x00000020); + } + /** + * required bytes msg_data = 6; + */ + public com.google.protobuf.ByteString getMsgData() { + return msgData_; + } + /** + * required bytes msg_data = 6; + */ + public Builder setMsgData(com.google.protobuf.ByteString value) { + if (value == null) { + throw new NullPointerException(); + } + bitField0_ |= 0x00000020; + msgData_ = value; + + return this; + } + /** + * required bytes msg_data = 6; + */ + public Builder clearMsgData() { + bitField0_ = (bitField0_ & ~0x00000020); + msgData_ = getDefaultInstance().getMsgData(); + + return this; + } + + private com.google.protobuf.ByteString attachData_ = com.google.protobuf.ByteString.EMPTY; + /** + * optional bytes attach_data = 20; + */ + public boolean hasAttachData() { + return ((bitField0_ & 0x00000040) == 0x00000040); + } + /** + * optional bytes attach_data = 20; + */ + public com.google.protobuf.ByteString getAttachData() { + return attachData_; + } + /** + * optional bytes attach_data = 20; + */ + public Builder setAttachData(com.google.protobuf.ByteString value) { + if (value == null) { + throw new NullPointerException(); + } + bitField0_ |= 0x00000040; + attachData_ = value; + + return this; + } + /** + * optional bytes attach_data = 20; + */ + public Builder clearAttachData() { + bitField0_ = (bitField0_ & ~0x00000040); + attachData_ = getDefaultInstance().getAttachData(); + + return this; + } + + // @@protoc_insertion_point(builder_scope:IM.Message.IMMsgData) + } + + static { + defaultInstance = new IMMsgData(true); + defaultInstance.initFields(); + } + + // @@protoc_insertion_point(class_scope:IM.Message.IMMsgData) + } + + public interface IMMsgDataAckOrBuilder extends + // @@protoc_insertion_point(interface_extends:IM.Message.IMMsgDataAck) + com.google.protobuf.MessageLiteOrBuilder { + + /** + * required uint32 user_id = 1; + * + *
+     *cmd id:		0x0302
+     * 
+ */ + boolean hasUserId(); + /** + * required uint32 user_id = 1; + * + *
+     *cmd id:		0x0302
+     * 
+ */ + int getUserId(); + + /** + * required uint32 session_id = 2; + */ + boolean hasSessionId(); + /** + * required uint32 session_id = 2; + */ + int getSessionId(); + + /** + * required uint32 msg_id = 3; + */ + boolean hasMsgId(); + /** + * required uint32 msg_id = 3; + */ + int getMsgId(); + + /** + * required .IM.BaseDefine.SessionType session_type = 4; + */ + boolean hasSessionType(); + /** + * required .IM.BaseDefine.SessionType session_type = 4; + */ + com.mogujie.tt.protobuf.IMBaseDefine.SessionType getSessionType(); + } + /** + * Protobuf type {@code IM.Message.IMMsgDataAck} + */ + public static final class IMMsgDataAck extends + com.google.protobuf.GeneratedMessageLite implements + // @@protoc_insertion_point(message_implements:IM.Message.IMMsgDataAck) + IMMsgDataAckOrBuilder { + // Use IMMsgDataAck.newBuilder() to construct. + private IMMsgDataAck(com.google.protobuf.GeneratedMessageLite.Builder builder) { + super(builder); + this.unknownFields = builder.getUnknownFields(); + } + private IMMsgDataAck(boolean noInit) { this.unknownFields = com.google.protobuf.ByteString.EMPTY;} + + private static final IMMsgDataAck defaultInstance; + public static IMMsgDataAck getDefaultInstance() { + return defaultInstance; + } + + public IMMsgDataAck getDefaultInstanceForType() { + return defaultInstance; + } + + private final com.google.protobuf.ByteString unknownFields; + private IMMsgDataAck( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + initFields(); + int mutable_bitField0_ = 0; + com.google.protobuf.ByteString.Output unknownFieldsOutput = + com.google.protobuf.ByteString.newOutput(); + com.google.protobuf.CodedOutputStream unknownFieldsCodedOutput = + com.google.protobuf.CodedOutputStream.newInstance( + unknownFieldsOutput); + try { + boolean done = false; + while (!done) { + int tag = input.readTag(); + switch (tag) { + case 0: + done = true; + break; + default: { + if (!parseUnknownField(input, unknownFieldsCodedOutput, + extensionRegistry, tag)) { + done = true; + } + break; + } + case 8: { + bitField0_ |= 0x00000001; + userId_ = input.readUInt32(); + break; + } + case 16: { + bitField0_ |= 0x00000002; + sessionId_ = input.readUInt32(); + break; + } + case 24: { + bitField0_ |= 0x00000004; + msgId_ = input.readUInt32(); + break; + } + case 32: { + int rawValue = input.readEnum(); + com.mogujie.tt.protobuf.IMBaseDefine.SessionType value = com.mogujie.tt.protobuf.IMBaseDefine.SessionType.valueOf(rawValue); + if (value == null) { + unknownFieldsCodedOutput.writeRawVarint32(tag); + unknownFieldsCodedOutput.writeRawVarint32(rawValue); + } else { + bitField0_ |= 0x00000008; + sessionType_ = value; + } + break; + } + } + } + } catch (com.google.protobuf.InvalidProtocolBufferException e) { + throw e.setUnfinishedMessage(this); + } catch (java.io.IOException e) { + throw new com.google.protobuf.InvalidProtocolBufferException( + e.getMessage()).setUnfinishedMessage(this); + } finally { + try { + unknownFieldsCodedOutput.flush(); + } catch (java.io.IOException e) { + // Should not happen + } finally { + unknownFields = unknownFieldsOutput.toByteString(); + } + makeExtensionsImmutable(); + } + } + public static com.google.protobuf.Parser PARSER = + new com.google.protobuf.AbstractParser() { + public IMMsgDataAck parsePartialFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return new IMMsgDataAck(input, extensionRegistry); + } + }; + + @java.lang.Override + public com.google.protobuf.Parser getParserForType() { + return PARSER; + } + + private int bitField0_; + public static final int USER_ID_FIELD_NUMBER = 1; + private int userId_; + /** + * required uint32 user_id = 1; + * + *
+     *cmd id:		0x0302
+     * 
+ */ + public boolean hasUserId() { + return ((bitField0_ & 0x00000001) == 0x00000001); + } + /** + * required uint32 user_id = 1; + * + *
+     *cmd id:		0x0302
+     * 
+ */ + public int getUserId() { + return userId_; + } + + public static final int SESSION_ID_FIELD_NUMBER = 2; + private int sessionId_; + /** + * required uint32 session_id = 2; + */ + public boolean hasSessionId() { + return ((bitField0_ & 0x00000002) == 0x00000002); + } + /** + * required uint32 session_id = 2; + */ + public int getSessionId() { + return sessionId_; + } + + public static final int MSG_ID_FIELD_NUMBER = 3; + private int msgId_; + /** + * required uint32 msg_id = 3; + */ + public boolean hasMsgId() { + return ((bitField0_ & 0x00000004) == 0x00000004); + } + /** + * required uint32 msg_id = 3; + */ + public int getMsgId() { + return msgId_; + } + + public static final int SESSION_TYPE_FIELD_NUMBER = 4; + private com.mogujie.tt.protobuf.IMBaseDefine.SessionType sessionType_; + /** + * required .IM.BaseDefine.SessionType session_type = 4; + */ + public boolean hasSessionType() { + return ((bitField0_ & 0x00000008) == 0x00000008); + } + /** + * required .IM.BaseDefine.SessionType session_type = 4; + */ + public com.mogujie.tt.protobuf.IMBaseDefine.SessionType getSessionType() { + return sessionType_; + } + + private void initFields() { + userId_ = 0; + sessionId_ = 0; + msgId_ = 0; + sessionType_ = com.mogujie.tt.protobuf.IMBaseDefine.SessionType.SESSION_TYPE_SINGLE; + } + private byte memoizedIsInitialized = -1; + public final boolean isInitialized() { + byte isInitialized = memoizedIsInitialized; + if (isInitialized == 1) return true; + if (isInitialized == 0) return false; + + if (!hasUserId()) { + memoizedIsInitialized = 0; + return false; + } + if (!hasSessionId()) { + memoizedIsInitialized = 0; + return false; + } + if (!hasMsgId()) { + memoizedIsInitialized = 0; + return false; + } + if (!hasSessionType()) { + memoizedIsInitialized = 0; + return false; + } + memoizedIsInitialized = 1; + return true; + } + + public void writeTo(com.google.protobuf.CodedOutputStream output) + throws java.io.IOException { + getSerializedSize(); + if (((bitField0_ & 0x00000001) == 0x00000001)) { + output.writeUInt32(1, userId_); + } + if (((bitField0_ & 0x00000002) == 0x00000002)) { + output.writeUInt32(2, sessionId_); + } + if (((bitField0_ & 0x00000004) == 0x00000004)) { + output.writeUInt32(3, msgId_); + } + if (((bitField0_ & 0x00000008) == 0x00000008)) { + output.writeEnum(4, sessionType_.getNumber()); + } + output.writeRawBytes(unknownFields); + } + + private int memoizedSerializedSize = -1; + public int getSerializedSize() { + int size = memoizedSerializedSize; + if (size != -1) return size; + + size = 0; + if (((bitField0_ & 0x00000001) == 0x00000001)) { + size += com.google.protobuf.CodedOutputStream + .computeUInt32Size(1, userId_); + } + if (((bitField0_ & 0x00000002) == 0x00000002)) { + size += com.google.protobuf.CodedOutputStream + .computeUInt32Size(2, sessionId_); + } + if (((bitField0_ & 0x00000004) == 0x00000004)) { + size += com.google.protobuf.CodedOutputStream + .computeUInt32Size(3, msgId_); + } + if (((bitField0_ & 0x00000008) == 0x00000008)) { + size += com.google.protobuf.CodedOutputStream + .computeEnumSize(4, sessionType_.getNumber()); + } + size += unknownFields.size(); + memoizedSerializedSize = size; + return size; + } + + private static final long serialVersionUID = 0L; + @java.lang.Override + protected java.lang.Object writeReplace() + throws java.io.ObjectStreamException { + return super.writeReplace(); + } + + public static com.mogujie.tt.protobuf.IMMessage.IMMsgDataAck parseFrom( + com.google.protobuf.ByteString data) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data); + } + public static com.mogujie.tt.protobuf.IMMessage.IMMsgDataAck parseFrom( + com.google.protobuf.ByteString data, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data, extensionRegistry); + } + public static com.mogujie.tt.protobuf.IMMessage.IMMsgDataAck parseFrom(byte[] data) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data); + } + public static com.mogujie.tt.protobuf.IMMessage.IMMsgDataAck parseFrom( + byte[] data, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data, extensionRegistry); + } + public static com.mogujie.tt.protobuf.IMMessage.IMMsgDataAck parseFrom(java.io.InputStream input) + throws java.io.IOException { + return PARSER.parseFrom(input); + } + public static com.mogujie.tt.protobuf.IMMessage.IMMsgDataAck parseFrom( + java.io.InputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return PARSER.parseFrom(input, extensionRegistry); + } + public static com.mogujie.tt.protobuf.IMMessage.IMMsgDataAck parseDelimitedFrom(java.io.InputStream input) + throws java.io.IOException { + return PARSER.parseDelimitedFrom(input); + } + public static com.mogujie.tt.protobuf.IMMessage.IMMsgDataAck parseDelimitedFrom( + java.io.InputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return PARSER.parseDelimitedFrom(input, extensionRegistry); + } + public static com.mogujie.tt.protobuf.IMMessage.IMMsgDataAck parseFrom( + com.google.protobuf.CodedInputStream input) + throws java.io.IOException { + return PARSER.parseFrom(input); + } + public static com.mogujie.tt.protobuf.IMMessage.IMMsgDataAck parseFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return PARSER.parseFrom(input, extensionRegistry); + } + + public static Builder newBuilder() { return Builder.create(); } + public Builder newBuilderForType() { return newBuilder(); } + public static Builder newBuilder(com.mogujie.tt.protobuf.IMMessage.IMMsgDataAck prototype) { + return newBuilder().mergeFrom(prototype); + } + public Builder toBuilder() { return newBuilder(this); } + + /** + * Protobuf type {@code IM.Message.IMMsgDataAck} + */ + public static final class Builder extends + com.google.protobuf.GeneratedMessageLite.Builder< + com.mogujie.tt.protobuf.IMMessage.IMMsgDataAck, Builder> + implements + // @@protoc_insertion_point(builder_implements:IM.Message.IMMsgDataAck) + com.mogujie.tt.protobuf.IMMessage.IMMsgDataAckOrBuilder { + // Construct using com.mogujie.tt.protobuf.IMMessage.IMMsgDataAck.newBuilder() + private Builder() { + maybeForceBuilderInitialization(); + } + + private void maybeForceBuilderInitialization() { + } + private static Builder create() { + return new Builder(); + } + + public Builder clear() { + super.clear(); + userId_ = 0; + bitField0_ = (bitField0_ & ~0x00000001); + sessionId_ = 0; + bitField0_ = (bitField0_ & ~0x00000002); + msgId_ = 0; + bitField0_ = (bitField0_ & ~0x00000004); + sessionType_ = com.mogujie.tt.protobuf.IMBaseDefine.SessionType.SESSION_TYPE_SINGLE; + bitField0_ = (bitField0_ & ~0x00000008); + return this; + } + + public Builder clone() { + return create().mergeFrom(buildPartial()); + } + + public com.mogujie.tt.protobuf.IMMessage.IMMsgDataAck getDefaultInstanceForType() { + return com.mogujie.tt.protobuf.IMMessage.IMMsgDataAck.getDefaultInstance(); + } + + public com.mogujie.tt.protobuf.IMMessage.IMMsgDataAck build() { + com.mogujie.tt.protobuf.IMMessage.IMMsgDataAck result = buildPartial(); + if (!result.isInitialized()) { + throw newUninitializedMessageException(result); + } + return result; + } + + public com.mogujie.tt.protobuf.IMMessage.IMMsgDataAck buildPartial() { + com.mogujie.tt.protobuf.IMMessage.IMMsgDataAck result = new com.mogujie.tt.protobuf.IMMessage.IMMsgDataAck(this); + int from_bitField0_ = bitField0_; + int to_bitField0_ = 0; + if (((from_bitField0_ & 0x00000001) == 0x00000001)) { + to_bitField0_ |= 0x00000001; + } + result.userId_ = userId_; + if (((from_bitField0_ & 0x00000002) == 0x00000002)) { + to_bitField0_ |= 0x00000002; + } + result.sessionId_ = sessionId_; + if (((from_bitField0_ & 0x00000004) == 0x00000004)) { + to_bitField0_ |= 0x00000004; + } + result.msgId_ = msgId_; + if (((from_bitField0_ & 0x00000008) == 0x00000008)) { + to_bitField0_ |= 0x00000008; + } + result.sessionType_ = sessionType_; + result.bitField0_ = to_bitField0_; + return result; + } + + public Builder mergeFrom(com.mogujie.tt.protobuf.IMMessage.IMMsgDataAck other) { + if (other == com.mogujie.tt.protobuf.IMMessage.IMMsgDataAck.getDefaultInstance()) return this; + if (other.hasUserId()) { + setUserId(other.getUserId()); + } + if (other.hasSessionId()) { + setSessionId(other.getSessionId()); + } + if (other.hasMsgId()) { + setMsgId(other.getMsgId()); + } + if (other.hasSessionType()) { + setSessionType(other.getSessionType()); + } + setUnknownFields( + getUnknownFields().concat(other.unknownFields)); + return this; + } + + public final boolean isInitialized() { + if (!hasUserId()) { + + return false; + } + if (!hasSessionId()) { + + return false; + } + if (!hasMsgId()) { + + return false; + } + if (!hasSessionType()) { + + return false; + } + return true; + } + + public Builder mergeFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + com.mogujie.tt.protobuf.IMMessage.IMMsgDataAck parsedMessage = null; + try { + parsedMessage = PARSER.parsePartialFrom(input, extensionRegistry); + } catch (com.google.protobuf.InvalidProtocolBufferException e) { + parsedMessage = (com.mogujie.tt.protobuf.IMMessage.IMMsgDataAck) e.getUnfinishedMessage(); + throw e; + } finally { + if (parsedMessage != null) { + mergeFrom(parsedMessage); + } + } + return this; + } + private int bitField0_; + + private int userId_ ; + /** + * required uint32 user_id = 1; + * + *
+       *cmd id:		0x0302
+       * 
+ */ + public boolean hasUserId() { + return ((bitField0_ & 0x00000001) == 0x00000001); + } + /** + * required uint32 user_id = 1; + * + *
+       *cmd id:		0x0302
+       * 
+ */ + public int getUserId() { + return userId_; + } + /** + * required uint32 user_id = 1; + * + *
+       *cmd id:		0x0302
+       * 
+ */ + public Builder setUserId(int value) { + bitField0_ |= 0x00000001; + userId_ = value; + + return this; + } + /** + * required uint32 user_id = 1; + * + *
+       *cmd id:		0x0302
+       * 
+ */ + public Builder clearUserId() { + bitField0_ = (bitField0_ & ~0x00000001); + userId_ = 0; + + return this; + } + + private int sessionId_ ; + /** + * required uint32 session_id = 2; + */ + public boolean hasSessionId() { + return ((bitField0_ & 0x00000002) == 0x00000002); + } + /** + * required uint32 session_id = 2; + */ + public int getSessionId() { + return sessionId_; + } + /** + * required uint32 session_id = 2; + */ + public Builder setSessionId(int value) { + bitField0_ |= 0x00000002; + sessionId_ = value; + + return this; + } + /** + * required uint32 session_id = 2; + */ + public Builder clearSessionId() { + bitField0_ = (bitField0_ & ~0x00000002); + sessionId_ = 0; + + return this; + } + + private int msgId_ ; + /** + * required uint32 msg_id = 3; + */ + public boolean hasMsgId() { + return ((bitField0_ & 0x00000004) == 0x00000004); + } + /** + * required uint32 msg_id = 3; + */ + public int getMsgId() { + return msgId_; + } + /** + * required uint32 msg_id = 3; + */ + public Builder setMsgId(int value) { + bitField0_ |= 0x00000004; + msgId_ = value; + + return this; + } + /** + * required uint32 msg_id = 3; + */ + public Builder clearMsgId() { + bitField0_ = (bitField0_ & ~0x00000004); + msgId_ = 0; + + return this; + } + + private com.mogujie.tt.protobuf.IMBaseDefine.SessionType sessionType_ = com.mogujie.tt.protobuf.IMBaseDefine.SessionType.SESSION_TYPE_SINGLE; + /** + * required .IM.BaseDefine.SessionType session_type = 4; + */ + public boolean hasSessionType() { + return ((bitField0_ & 0x00000008) == 0x00000008); + } + /** + * required .IM.BaseDefine.SessionType session_type = 4; + */ + public com.mogujie.tt.protobuf.IMBaseDefine.SessionType getSessionType() { + return sessionType_; + } + /** + * required .IM.BaseDefine.SessionType session_type = 4; + */ + public Builder setSessionType(com.mogujie.tt.protobuf.IMBaseDefine.SessionType value) { + if (value == null) { + throw new NullPointerException(); + } + bitField0_ |= 0x00000008; + sessionType_ = value; + + return this; + } + /** + * required .IM.BaseDefine.SessionType session_type = 4; + */ + public Builder clearSessionType() { + bitField0_ = (bitField0_ & ~0x00000008); + sessionType_ = com.mogujie.tt.protobuf.IMBaseDefine.SessionType.SESSION_TYPE_SINGLE; + + return this; + } + + // @@protoc_insertion_point(builder_scope:IM.Message.IMMsgDataAck) + } + + static { + defaultInstance = new IMMsgDataAck(true); + defaultInstance.initFields(); + } + + // @@protoc_insertion_point(class_scope:IM.Message.IMMsgDataAck) + } + + public interface IMMsgDataReadAckOrBuilder extends + // @@protoc_insertion_point(interface_extends:IM.Message.IMMsgDataReadAck) + com.google.protobuf.MessageLiteOrBuilder { + + /** + * required uint32 user_id = 1; + * + *
+     *cmd id:		0x0303
+     * 
+ */ + boolean hasUserId(); + /** + * required uint32 user_id = 1; + * + *
+     *cmd id:		0x0303
+     * 
+ */ + int getUserId(); + + /** + * required uint32 session_id = 2; + */ + boolean hasSessionId(); + /** + * required uint32 session_id = 2; + */ + int getSessionId(); + + /** + * required uint32 msg_id = 3; + */ + boolean hasMsgId(); + /** + * required uint32 msg_id = 3; + */ + int getMsgId(); + + /** + * required .IM.BaseDefine.SessionType session_type = 4; + */ + boolean hasSessionType(); + /** + * required .IM.BaseDefine.SessionType session_type = 4; + */ + com.mogujie.tt.protobuf.IMBaseDefine.SessionType getSessionType(); + } + /** + * Protobuf type {@code IM.Message.IMMsgDataReadAck} + */ + public static final class IMMsgDataReadAck extends + com.google.protobuf.GeneratedMessageLite implements + // @@protoc_insertion_point(message_implements:IM.Message.IMMsgDataReadAck) + IMMsgDataReadAckOrBuilder { + // Use IMMsgDataReadAck.newBuilder() to construct. + private IMMsgDataReadAck(com.google.protobuf.GeneratedMessageLite.Builder builder) { + super(builder); + this.unknownFields = builder.getUnknownFields(); + } + private IMMsgDataReadAck(boolean noInit) { this.unknownFields = com.google.protobuf.ByteString.EMPTY;} + + private static final IMMsgDataReadAck defaultInstance; + public static IMMsgDataReadAck getDefaultInstance() { + return defaultInstance; + } + + public IMMsgDataReadAck getDefaultInstanceForType() { + return defaultInstance; + } + + private final com.google.protobuf.ByteString unknownFields; + private IMMsgDataReadAck( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + initFields(); + int mutable_bitField0_ = 0; + com.google.protobuf.ByteString.Output unknownFieldsOutput = + com.google.protobuf.ByteString.newOutput(); + com.google.protobuf.CodedOutputStream unknownFieldsCodedOutput = + com.google.protobuf.CodedOutputStream.newInstance( + unknownFieldsOutput); + try { + boolean done = false; + while (!done) { + int tag = input.readTag(); + switch (tag) { + case 0: + done = true; + break; + default: { + if (!parseUnknownField(input, unknownFieldsCodedOutput, + extensionRegistry, tag)) { + done = true; + } + break; + } + case 8: { + bitField0_ |= 0x00000001; + userId_ = input.readUInt32(); + break; + } + case 16: { + bitField0_ |= 0x00000002; + sessionId_ = input.readUInt32(); + break; + } + case 24: { + bitField0_ |= 0x00000004; + msgId_ = input.readUInt32(); + break; + } + case 32: { + int rawValue = input.readEnum(); + com.mogujie.tt.protobuf.IMBaseDefine.SessionType value = com.mogujie.tt.protobuf.IMBaseDefine.SessionType.valueOf(rawValue); + if (value == null) { + unknownFieldsCodedOutput.writeRawVarint32(tag); + unknownFieldsCodedOutput.writeRawVarint32(rawValue); + } else { + bitField0_ |= 0x00000008; + sessionType_ = value; + } + break; + } + } + } + } catch (com.google.protobuf.InvalidProtocolBufferException e) { + throw e.setUnfinishedMessage(this); + } catch (java.io.IOException e) { + throw new com.google.protobuf.InvalidProtocolBufferException( + e.getMessage()).setUnfinishedMessage(this); + } finally { + try { + unknownFieldsCodedOutput.flush(); + } catch (java.io.IOException e) { + // Should not happen + } finally { + unknownFields = unknownFieldsOutput.toByteString(); + } + makeExtensionsImmutable(); + } + } + public static com.google.protobuf.Parser PARSER = + new com.google.protobuf.AbstractParser() { + public IMMsgDataReadAck parsePartialFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return new IMMsgDataReadAck(input, extensionRegistry); + } + }; + + @java.lang.Override + public com.google.protobuf.Parser getParserForType() { + return PARSER; + } + + private int bitField0_; + public static final int USER_ID_FIELD_NUMBER = 1; + private int userId_; + /** + * required uint32 user_id = 1; + * + *
+     *cmd id:		0x0303
+     * 
+ */ + public boolean hasUserId() { + return ((bitField0_ & 0x00000001) == 0x00000001); + } + /** + * required uint32 user_id = 1; + * + *
+     *cmd id:		0x0303
+     * 
+ */ + public int getUserId() { + return userId_; + } + + public static final int SESSION_ID_FIELD_NUMBER = 2; + private int sessionId_; + /** + * required uint32 session_id = 2; + */ + public boolean hasSessionId() { + return ((bitField0_ & 0x00000002) == 0x00000002); + } + /** + * required uint32 session_id = 2; + */ + public int getSessionId() { + return sessionId_; + } + + public static final int MSG_ID_FIELD_NUMBER = 3; + private int msgId_; + /** + * required uint32 msg_id = 3; + */ + public boolean hasMsgId() { + return ((bitField0_ & 0x00000004) == 0x00000004); + } + /** + * required uint32 msg_id = 3; + */ + public int getMsgId() { + return msgId_; + } + + public static final int SESSION_TYPE_FIELD_NUMBER = 4; + private com.mogujie.tt.protobuf.IMBaseDefine.SessionType sessionType_; + /** + * required .IM.BaseDefine.SessionType session_type = 4; + */ + public boolean hasSessionType() { + return ((bitField0_ & 0x00000008) == 0x00000008); + } + /** + * required .IM.BaseDefine.SessionType session_type = 4; + */ + public com.mogujie.tt.protobuf.IMBaseDefine.SessionType getSessionType() { + return sessionType_; + } + + private void initFields() { + userId_ = 0; + sessionId_ = 0; + msgId_ = 0; + sessionType_ = com.mogujie.tt.protobuf.IMBaseDefine.SessionType.SESSION_TYPE_SINGLE; + } + private byte memoizedIsInitialized = -1; + public final boolean isInitialized() { + byte isInitialized = memoizedIsInitialized; + if (isInitialized == 1) return true; + if (isInitialized == 0) return false; + + if (!hasUserId()) { + memoizedIsInitialized = 0; + return false; + } + if (!hasSessionId()) { + memoizedIsInitialized = 0; + return false; + } + if (!hasMsgId()) { + memoizedIsInitialized = 0; + return false; + } + if (!hasSessionType()) { + memoizedIsInitialized = 0; + return false; + } + memoizedIsInitialized = 1; + return true; + } + + public void writeTo(com.google.protobuf.CodedOutputStream output) + throws java.io.IOException { + getSerializedSize(); + if (((bitField0_ & 0x00000001) == 0x00000001)) { + output.writeUInt32(1, userId_); + } + if (((bitField0_ & 0x00000002) == 0x00000002)) { + output.writeUInt32(2, sessionId_); + } + if (((bitField0_ & 0x00000004) == 0x00000004)) { + output.writeUInt32(3, msgId_); + } + if (((bitField0_ & 0x00000008) == 0x00000008)) { + output.writeEnum(4, sessionType_.getNumber()); + } + output.writeRawBytes(unknownFields); + } + + private int memoizedSerializedSize = -1; + public int getSerializedSize() { + int size = memoizedSerializedSize; + if (size != -1) return size; + + size = 0; + if (((bitField0_ & 0x00000001) == 0x00000001)) { + size += com.google.protobuf.CodedOutputStream + .computeUInt32Size(1, userId_); + } + if (((bitField0_ & 0x00000002) == 0x00000002)) { + size += com.google.protobuf.CodedOutputStream + .computeUInt32Size(2, sessionId_); + } + if (((bitField0_ & 0x00000004) == 0x00000004)) { + size += com.google.protobuf.CodedOutputStream + .computeUInt32Size(3, msgId_); + } + if (((bitField0_ & 0x00000008) == 0x00000008)) { + size += com.google.protobuf.CodedOutputStream + .computeEnumSize(4, sessionType_.getNumber()); + } + size += unknownFields.size(); + memoizedSerializedSize = size; + return size; + } + + private static final long serialVersionUID = 0L; + @java.lang.Override + protected java.lang.Object writeReplace() + throws java.io.ObjectStreamException { + return super.writeReplace(); + } + + public static com.mogujie.tt.protobuf.IMMessage.IMMsgDataReadAck parseFrom( + com.google.protobuf.ByteString data) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data); + } + public static com.mogujie.tt.protobuf.IMMessage.IMMsgDataReadAck parseFrom( + com.google.protobuf.ByteString data, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data, extensionRegistry); + } + public static com.mogujie.tt.protobuf.IMMessage.IMMsgDataReadAck parseFrom(byte[] data) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data); + } + public static com.mogujie.tt.protobuf.IMMessage.IMMsgDataReadAck parseFrom( + byte[] data, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data, extensionRegistry); + } + public static com.mogujie.tt.protobuf.IMMessage.IMMsgDataReadAck parseFrom(java.io.InputStream input) + throws java.io.IOException { + return PARSER.parseFrom(input); + } + public static com.mogujie.tt.protobuf.IMMessage.IMMsgDataReadAck parseFrom( + java.io.InputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return PARSER.parseFrom(input, extensionRegistry); + } + public static com.mogujie.tt.protobuf.IMMessage.IMMsgDataReadAck parseDelimitedFrom(java.io.InputStream input) + throws java.io.IOException { + return PARSER.parseDelimitedFrom(input); + } + public static com.mogujie.tt.protobuf.IMMessage.IMMsgDataReadAck parseDelimitedFrom( + java.io.InputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return PARSER.parseDelimitedFrom(input, extensionRegistry); + } + public static com.mogujie.tt.protobuf.IMMessage.IMMsgDataReadAck parseFrom( + com.google.protobuf.CodedInputStream input) + throws java.io.IOException { + return PARSER.parseFrom(input); + } + public static com.mogujie.tt.protobuf.IMMessage.IMMsgDataReadAck parseFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return PARSER.parseFrom(input, extensionRegistry); + } + + public static Builder newBuilder() { return Builder.create(); } + public Builder newBuilderForType() { return newBuilder(); } + public static Builder newBuilder(com.mogujie.tt.protobuf.IMMessage.IMMsgDataReadAck prototype) { + return newBuilder().mergeFrom(prototype); + } + public Builder toBuilder() { return newBuilder(this); } + + /** + * Protobuf type {@code IM.Message.IMMsgDataReadAck} + */ + public static final class Builder extends + com.google.protobuf.GeneratedMessageLite.Builder< + com.mogujie.tt.protobuf.IMMessage.IMMsgDataReadAck, Builder> + implements + // @@protoc_insertion_point(builder_implements:IM.Message.IMMsgDataReadAck) + com.mogujie.tt.protobuf.IMMessage.IMMsgDataReadAckOrBuilder { + // Construct using com.mogujie.tt.protobuf.IMMessage.IMMsgDataReadAck.newBuilder() + private Builder() { + maybeForceBuilderInitialization(); + } + + private void maybeForceBuilderInitialization() { + } + private static Builder create() { + return new Builder(); + } + + public Builder clear() { + super.clear(); + userId_ = 0; + bitField0_ = (bitField0_ & ~0x00000001); + sessionId_ = 0; + bitField0_ = (bitField0_ & ~0x00000002); + msgId_ = 0; + bitField0_ = (bitField0_ & ~0x00000004); + sessionType_ = com.mogujie.tt.protobuf.IMBaseDefine.SessionType.SESSION_TYPE_SINGLE; + bitField0_ = (bitField0_ & ~0x00000008); + return this; + } + + public Builder clone() { + return create().mergeFrom(buildPartial()); + } + + public com.mogujie.tt.protobuf.IMMessage.IMMsgDataReadAck getDefaultInstanceForType() { + return com.mogujie.tt.protobuf.IMMessage.IMMsgDataReadAck.getDefaultInstance(); + } + + public com.mogujie.tt.protobuf.IMMessage.IMMsgDataReadAck build() { + com.mogujie.tt.protobuf.IMMessage.IMMsgDataReadAck result = buildPartial(); + if (!result.isInitialized()) { + throw newUninitializedMessageException(result); + } + return result; + } + + public com.mogujie.tt.protobuf.IMMessage.IMMsgDataReadAck buildPartial() { + com.mogujie.tt.protobuf.IMMessage.IMMsgDataReadAck result = new com.mogujie.tt.protobuf.IMMessage.IMMsgDataReadAck(this); + int from_bitField0_ = bitField0_; + int to_bitField0_ = 0; + if (((from_bitField0_ & 0x00000001) == 0x00000001)) { + to_bitField0_ |= 0x00000001; + } + result.userId_ = userId_; + if (((from_bitField0_ & 0x00000002) == 0x00000002)) { + to_bitField0_ |= 0x00000002; + } + result.sessionId_ = sessionId_; + if (((from_bitField0_ & 0x00000004) == 0x00000004)) { + to_bitField0_ |= 0x00000004; + } + result.msgId_ = msgId_; + if (((from_bitField0_ & 0x00000008) == 0x00000008)) { + to_bitField0_ |= 0x00000008; + } + result.sessionType_ = sessionType_; + result.bitField0_ = to_bitField0_; + return result; + } + + public Builder mergeFrom(com.mogujie.tt.protobuf.IMMessage.IMMsgDataReadAck other) { + if (other == com.mogujie.tt.protobuf.IMMessage.IMMsgDataReadAck.getDefaultInstance()) return this; + if (other.hasUserId()) { + setUserId(other.getUserId()); + } + if (other.hasSessionId()) { + setSessionId(other.getSessionId()); + } + if (other.hasMsgId()) { + setMsgId(other.getMsgId()); + } + if (other.hasSessionType()) { + setSessionType(other.getSessionType()); + } + setUnknownFields( + getUnknownFields().concat(other.unknownFields)); + return this; + } + + public final boolean isInitialized() { + if (!hasUserId()) { + + return false; + } + if (!hasSessionId()) { + + return false; + } + if (!hasMsgId()) { + + return false; + } + if (!hasSessionType()) { + + return false; + } + return true; + } + + public Builder mergeFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + com.mogujie.tt.protobuf.IMMessage.IMMsgDataReadAck parsedMessage = null; + try { + parsedMessage = PARSER.parsePartialFrom(input, extensionRegistry); + } catch (com.google.protobuf.InvalidProtocolBufferException e) { + parsedMessage = (com.mogujie.tt.protobuf.IMMessage.IMMsgDataReadAck) e.getUnfinishedMessage(); + throw e; + } finally { + if (parsedMessage != null) { + mergeFrom(parsedMessage); + } + } + return this; + } + private int bitField0_; + + private int userId_ ; + /** + * required uint32 user_id = 1; + * + *
+       *cmd id:		0x0303
+       * 
+ */ + public boolean hasUserId() { + return ((bitField0_ & 0x00000001) == 0x00000001); + } + /** + * required uint32 user_id = 1; + * + *
+       *cmd id:		0x0303
+       * 
+ */ + public int getUserId() { + return userId_; + } + /** + * required uint32 user_id = 1; + * + *
+       *cmd id:		0x0303
+       * 
+ */ + public Builder setUserId(int value) { + bitField0_ |= 0x00000001; + userId_ = value; + + return this; + } + /** + * required uint32 user_id = 1; + * + *
+       *cmd id:		0x0303
+       * 
+ */ + public Builder clearUserId() { + bitField0_ = (bitField0_ & ~0x00000001); + userId_ = 0; + + return this; + } + + private int sessionId_ ; + /** + * required uint32 session_id = 2; + */ + public boolean hasSessionId() { + return ((bitField0_ & 0x00000002) == 0x00000002); + } + /** + * required uint32 session_id = 2; + */ + public int getSessionId() { + return sessionId_; + } + /** + * required uint32 session_id = 2; + */ + public Builder setSessionId(int value) { + bitField0_ |= 0x00000002; + sessionId_ = value; + + return this; + } + /** + * required uint32 session_id = 2; + */ + public Builder clearSessionId() { + bitField0_ = (bitField0_ & ~0x00000002); + sessionId_ = 0; + + return this; + } + + private int msgId_ ; + /** + * required uint32 msg_id = 3; + */ + public boolean hasMsgId() { + return ((bitField0_ & 0x00000004) == 0x00000004); + } + /** + * required uint32 msg_id = 3; + */ + public int getMsgId() { + return msgId_; + } + /** + * required uint32 msg_id = 3; + */ + public Builder setMsgId(int value) { + bitField0_ |= 0x00000004; + msgId_ = value; + + return this; + } + /** + * required uint32 msg_id = 3; + */ + public Builder clearMsgId() { + bitField0_ = (bitField0_ & ~0x00000004); + msgId_ = 0; + + return this; + } + + private com.mogujie.tt.protobuf.IMBaseDefine.SessionType sessionType_ = com.mogujie.tt.protobuf.IMBaseDefine.SessionType.SESSION_TYPE_SINGLE; + /** + * required .IM.BaseDefine.SessionType session_type = 4; + */ + public boolean hasSessionType() { + return ((bitField0_ & 0x00000008) == 0x00000008); + } + /** + * required .IM.BaseDefine.SessionType session_type = 4; + */ + public com.mogujie.tt.protobuf.IMBaseDefine.SessionType getSessionType() { + return sessionType_; + } + /** + * required .IM.BaseDefine.SessionType session_type = 4; + */ + public Builder setSessionType(com.mogujie.tt.protobuf.IMBaseDefine.SessionType value) { + if (value == null) { + throw new NullPointerException(); + } + bitField0_ |= 0x00000008; + sessionType_ = value; + + return this; + } + /** + * required .IM.BaseDefine.SessionType session_type = 4; + */ + public Builder clearSessionType() { + bitField0_ = (bitField0_ & ~0x00000008); + sessionType_ = com.mogujie.tt.protobuf.IMBaseDefine.SessionType.SESSION_TYPE_SINGLE; + + return this; + } + + // @@protoc_insertion_point(builder_scope:IM.Message.IMMsgDataReadAck) + } + + static { + defaultInstance = new IMMsgDataReadAck(true); + defaultInstance.initFields(); + } + + // @@protoc_insertion_point(class_scope:IM.Message.IMMsgDataReadAck) + } + + public interface IMMsgDataReadNotifyOrBuilder extends + // @@protoc_insertion_point(interface_extends:IM.Message.IMMsgDataReadNotify) + com.google.protobuf.MessageLiteOrBuilder { + + /** + * required uint32 user_id = 1; + * + *
+     *cmd id:		0x0304
+     * 
+ */ + boolean hasUserId(); + /** + * required uint32 user_id = 1; + * + *
+     *cmd id:		0x0304
+     * 
+ */ + int getUserId(); + + /** + * required uint32 session_id = 2; + */ + boolean hasSessionId(); + /** + * required uint32 session_id = 2; + */ + int getSessionId(); + + /** + * required uint32 msg_id = 3; + */ + boolean hasMsgId(); + /** + * required uint32 msg_id = 3; + */ + int getMsgId(); + + /** + * required .IM.BaseDefine.SessionType session_type = 4; + */ + boolean hasSessionType(); + /** + * required .IM.BaseDefine.SessionType session_type = 4; + */ + com.mogujie.tt.protobuf.IMBaseDefine.SessionType getSessionType(); + } + /** + * Protobuf type {@code IM.Message.IMMsgDataReadNotify} + */ + public static final class IMMsgDataReadNotify extends + com.google.protobuf.GeneratedMessageLite implements + // @@protoc_insertion_point(message_implements:IM.Message.IMMsgDataReadNotify) + IMMsgDataReadNotifyOrBuilder { + // Use IMMsgDataReadNotify.newBuilder() to construct. + private IMMsgDataReadNotify(com.google.protobuf.GeneratedMessageLite.Builder builder) { + super(builder); + this.unknownFields = builder.getUnknownFields(); + } + private IMMsgDataReadNotify(boolean noInit) { this.unknownFields = com.google.protobuf.ByteString.EMPTY;} + + private static final IMMsgDataReadNotify defaultInstance; + public static IMMsgDataReadNotify getDefaultInstance() { + return defaultInstance; + } + + public IMMsgDataReadNotify getDefaultInstanceForType() { + return defaultInstance; + } + + private final com.google.protobuf.ByteString unknownFields; + private IMMsgDataReadNotify( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + initFields(); + int mutable_bitField0_ = 0; + com.google.protobuf.ByteString.Output unknownFieldsOutput = + com.google.protobuf.ByteString.newOutput(); + com.google.protobuf.CodedOutputStream unknownFieldsCodedOutput = + com.google.protobuf.CodedOutputStream.newInstance( + unknownFieldsOutput); + try { + boolean done = false; + while (!done) { + int tag = input.readTag(); + switch (tag) { + case 0: + done = true; + break; + default: { + if (!parseUnknownField(input, unknownFieldsCodedOutput, + extensionRegistry, tag)) { + done = true; + } + break; + } + case 8: { + bitField0_ |= 0x00000001; + userId_ = input.readUInt32(); + break; + } + case 16: { + bitField0_ |= 0x00000002; + sessionId_ = input.readUInt32(); + break; + } + case 24: { + bitField0_ |= 0x00000004; + msgId_ = input.readUInt32(); + break; + } + case 32: { + int rawValue = input.readEnum(); + com.mogujie.tt.protobuf.IMBaseDefine.SessionType value = com.mogujie.tt.protobuf.IMBaseDefine.SessionType.valueOf(rawValue); + if (value == null) { + unknownFieldsCodedOutput.writeRawVarint32(tag); + unknownFieldsCodedOutput.writeRawVarint32(rawValue); + } else { + bitField0_ |= 0x00000008; + sessionType_ = value; + } + break; + } + } + } + } catch (com.google.protobuf.InvalidProtocolBufferException e) { + throw e.setUnfinishedMessage(this); + } catch (java.io.IOException e) { + throw new com.google.protobuf.InvalidProtocolBufferException( + e.getMessage()).setUnfinishedMessage(this); + } finally { + try { + unknownFieldsCodedOutput.flush(); + } catch (java.io.IOException e) { + // Should not happen + } finally { + unknownFields = unknownFieldsOutput.toByteString(); + } + makeExtensionsImmutable(); + } + } + public static com.google.protobuf.Parser PARSER = + new com.google.protobuf.AbstractParser() { + public IMMsgDataReadNotify parsePartialFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return new IMMsgDataReadNotify(input, extensionRegistry); + } + }; + + @java.lang.Override + public com.google.protobuf.Parser getParserForType() { + return PARSER; + } + + private int bitField0_; + public static final int USER_ID_FIELD_NUMBER = 1; + private int userId_; + /** + * required uint32 user_id = 1; + * + *
+     *cmd id:		0x0304
+     * 
+ */ + public boolean hasUserId() { + return ((bitField0_ & 0x00000001) == 0x00000001); + } + /** + * required uint32 user_id = 1; + * + *
+     *cmd id:		0x0304
+     * 
+ */ + public int getUserId() { + return userId_; + } + + public static final int SESSION_ID_FIELD_NUMBER = 2; + private int sessionId_; + /** + * required uint32 session_id = 2; + */ + public boolean hasSessionId() { + return ((bitField0_ & 0x00000002) == 0x00000002); + } + /** + * required uint32 session_id = 2; + */ + public int getSessionId() { + return sessionId_; + } + + public static final int MSG_ID_FIELD_NUMBER = 3; + private int msgId_; + /** + * required uint32 msg_id = 3; + */ + public boolean hasMsgId() { + return ((bitField0_ & 0x00000004) == 0x00000004); + } + /** + * required uint32 msg_id = 3; + */ + public int getMsgId() { + return msgId_; + } + + public static final int SESSION_TYPE_FIELD_NUMBER = 4; + private com.mogujie.tt.protobuf.IMBaseDefine.SessionType sessionType_; + /** + * required .IM.BaseDefine.SessionType session_type = 4; + */ + public boolean hasSessionType() { + return ((bitField0_ & 0x00000008) == 0x00000008); + } + /** + * required .IM.BaseDefine.SessionType session_type = 4; + */ + public com.mogujie.tt.protobuf.IMBaseDefine.SessionType getSessionType() { + return sessionType_; + } + + private void initFields() { + userId_ = 0; + sessionId_ = 0; + msgId_ = 0; + sessionType_ = com.mogujie.tt.protobuf.IMBaseDefine.SessionType.SESSION_TYPE_SINGLE; + } + private byte memoizedIsInitialized = -1; + public final boolean isInitialized() { + byte isInitialized = memoizedIsInitialized; + if (isInitialized == 1) return true; + if (isInitialized == 0) return false; + + if (!hasUserId()) { + memoizedIsInitialized = 0; + return false; + } + if (!hasSessionId()) { + memoizedIsInitialized = 0; + return false; + } + if (!hasMsgId()) { + memoizedIsInitialized = 0; + return false; + } + if (!hasSessionType()) { + memoizedIsInitialized = 0; + return false; + } + memoizedIsInitialized = 1; + return true; + } + + public void writeTo(com.google.protobuf.CodedOutputStream output) + throws java.io.IOException { + getSerializedSize(); + if (((bitField0_ & 0x00000001) == 0x00000001)) { + output.writeUInt32(1, userId_); + } + if (((bitField0_ & 0x00000002) == 0x00000002)) { + output.writeUInt32(2, sessionId_); + } + if (((bitField0_ & 0x00000004) == 0x00000004)) { + output.writeUInt32(3, msgId_); + } + if (((bitField0_ & 0x00000008) == 0x00000008)) { + output.writeEnum(4, sessionType_.getNumber()); + } + output.writeRawBytes(unknownFields); + } + + private int memoizedSerializedSize = -1; + public int getSerializedSize() { + int size = memoizedSerializedSize; + if (size != -1) return size; + + size = 0; + if (((bitField0_ & 0x00000001) == 0x00000001)) { + size += com.google.protobuf.CodedOutputStream + .computeUInt32Size(1, userId_); + } + if (((bitField0_ & 0x00000002) == 0x00000002)) { + size += com.google.protobuf.CodedOutputStream + .computeUInt32Size(2, sessionId_); + } + if (((bitField0_ & 0x00000004) == 0x00000004)) { + size += com.google.protobuf.CodedOutputStream + .computeUInt32Size(3, msgId_); + } + if (((bitField0_ & 0x00000008) == 0x00000008)) { + size += com.google.protobuf.CodedOutputStream + .computeEnumSize(4, sessionType_.getNumber()); + } + size += unknownFields.size(); + memoizedSerializedSize = size; + return size; + } + + private static final long serialVersionUID = 0L; + @java.lang.Override + protected java.lang.Object writeReplace() + throws java.io.ObjectStreamException { + return super.writeReplace(); + } + + public static com.mogujie.tt.protobuf.IMMessage.IMMsgDataReadNotify parseFrom( + com.google.protobuf.ByteString data) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data); + } + public static com.mogujie.tt.protobuf.IMMessage.IMMsgDataReadNotify parseFrom( + com.google.protobuf.ByteString data, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data, extensionRegistry); + } + public static com.mogujie.tt.protobuf.IMMessage.IMMsgDataReadNotify parseFrom(byte[] data) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data); + } + public static com.mogujie.tt.protobuf.IMMessage.IMMsgDataReadNotify parseFrom( + byte[] data, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data, extensionRegistry); + } + public static com.mogujie.tt.protobuf.IMMessage.IMMsgDataReadNotify parseFrom(java.io.InputStream input) + throws java.io.IOException { + return PARSER.parseFrom(input); + } + public static com.mogujie.tt.protobuf.IMMessage.IMMsgDataReadNotify parseFrom( + java.io.InputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return PARSER.parseFrom(input, extensionRegistry); + } + public static com.mogujie.tt.protobuf.IMMessage.IMMsgDataReadNotify parseDelimitedFrom(java.io.InputStream input) + throws java.io.IOException { + return PARSER.parseDelimitedFrom(input); + } + public static com.mogujie.tt.protobuf.IMMessage.IMMsgDataReadNotify parseDelimitedFrom( + java.io.InputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return PARSER.parseDelimitedFrom(input, extensionRegistry); + } + public static com.mogujie.tt.protobuf.IMMessage.IMMsgDataReadNotify parseFrom( + com.google.protobuf.CodedInputStream input) + throws java.io.IOException { + return PARSER.parseFrom(input); + } + public static com.mogujie.tt.protobuf.IMMessage.IMMsgDataReadNotify parseFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return PARSER.parseFrom(input, extensionRegistry); + } + + public static Builder newBuilder() { return Builder.create(); } + public Builder newBuilderForType() { return newBuilder(); } + public static Builder newBuilder(com.mogujie.tt.protobuf.IMMessage.IMMsgDataReadNotify prototype) { + return newBuilder().mergeFrom(prototype); + } + public Builder toBuilder() { return newBuilder(this); } + + /** + * Protobuf type {@code IM.Message.IMMsgDataReadNotify} + */ + public static final class Builder extends + com.google.protobuf.GeneratedMessageLite.Builder< + com.mogujie.tt.protobuf.IMMessage.IMMsgDataReadNotify, Builder> + implements + // @@protoc_insertion_point(builder_implements:IM.Message.IMMsgDataReadNotify) + com.mogujie.tt.protobuf.IMMessage.IMMsgDataReadNotifyOrBuilder { + // Construct using com.mogujie.tt.protobuf.IMMessage.IMMsgDataReadNotify.newBuilder() + private Builder() { + maybeForceBuilderInitialization(); + } + + private void maybeForceBuilderInitialization() { + } + private static Builder create() { + return new Builder(); + } + + public Builder clear() { + super.clear(); + userId_ = 0; + bitField0_ = (bitField0_ & ~0x00000001); + sessionId_ = 0; + bitField0_ = (bitField0_ & ~0x00000002); + msgId_ = 0; + bitField0_ = (bitField0_ & ~0x00000004); + sessionType_ = com.mogujie.tt.protobuf.IMBaseDefine.SessionType.SESSION_TYPE_SINGLE; + bitField0_ = (bitField0_ & ~0x00000008); + return this; + } + + public Builder clone() { + return create().mergeFrom(buildPartial()); + } + + public com.mogujie.tt.protobuf.IMMessage.IMMsgDataReadNotify getDefaultInstanceForType() { + return com.mogujie.tt.protobuf.IMMessage.IMMsgDataReadNotify.getDefaultInstance(); + } + + public com.mogujie.tt.protobuf.IMMessage.IMMsgDataReadNotify build() { + com.mogujie.tt.protobuf.IMMessage.IMMsgDataReadNotify result = buildPartial(); + if (!result.isInitialized()) { + throw newUninitializedMessageException(result); + } + return result; + } + + public com.mogujie.tt.protobuf.IMMessage.IMMsgDataReadNotify buildPartial() { + com.mogujie.tt.protobuf.IMMessage.IMMsgDataReadNotify result = new com.mogujie.tt.protobuf.IMMessage.IMMsgDataReadNotify(this); + int from_bitField0_ = bitField0_; + int to_bitField0_ = 0; + if (((from_bitField0_ & 0x00000001) == 0x00000001)) { + to_bitField0_ |= 0x00000001; + } + result.userId_ = userId_; + if (((from_bitField0_ & 0x00000002) == 0x00000002)) { + to_bitField0_ |= 0x00000002; + } + result.sessionId_ = sessionId_; + if (((from_bitField0_ & 0x00000004) == 0x00000004)) { + to_bitField0_ |= 0x00000004; + } + result.msgId_ = msgId_; + if (((from_bitField0_ & 0x00000008) == 0x00000008)) { + to_bitField0_ |= 0x00000008; + } + result.sessionType_ = sessionType_; + result.bitField0_ = to_bitField0_; + return result; + } + + public Builder mergeFrom(com.mogujie.tt.protobuf.IMMessage.IMMsgDataReadNotify other) { + if (other == com.mogujie.tt.protobuf.IMMessage.IMMsgDataReadNotify.getDefaultInstance()) return this; + if (other.hasUserId()) { + setUserId(other.getUserId()); + } + if (other.hasSessionId()) { + setSessionId(other.getSessionId()); + } + if (other.hasMsgId()) { + setMsgId(other.getMsgId()); + } + if (other.hasSessionType()) { + setSessionType(other.getSessionType()); + } + setUnknownFields( + getUnknownFields().concat(other.unknownFields)); + return this; + } + + public final boolean isInitialized() { + if (!hasUserId()) { + + return false; + } + if (!hasSessionId()) { + + return false; + } + if (!hasMsgId()) { + + return false; + } + if (!hasSessionType()) { + + return false; + } + return true; + } + + public Builder mergeFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + com.mogujie.tt.protobuf.IMMessage.IMMsgDataReadNotify parsedMessage = null; + try { + parsedMessage = PARSER.parsePartialFrom(input, extensionRegistry); + } catch (com.google.protobuf.InvalidProtocolBufferException e) { + parsedMessage = (com.mogujie.tt.protobuf.IMMessage.IMMsgDataReadNotify) e.getUnfinishedMessage(); + throw e; + } finally { + if (parsedMessage != null) { + mergeFrom(parsedMessage); + } + } + return this; + } + private int bitField0_; + + private int userId_ ; + /** + * required uint32 user_id = 1; + * + *
+       *cmd id:		0x0304
+       * 
+ */ + public boolean hasUserId() { + return ((bitField0_ & 0x00000001) == 0x00000001); + } + /** + * required uint32 user_id = 1; + * + *
+       *cmd id:		0x0304
+       * 
+ */ + public int getUserId() { + return userId_; + } + /** + * required uint32 user_id = 1; + * + *
+       *cmd id:		0x0304
+       * 
+ */ + public Builder setUserId(int value) { + bitField0_ |= 0x00000001; + userId_ = value; + + return this; + } + /** + * required uint32 user_id = 1; + * + *
+       *cmd id:		0x0304
+       * 
+ */ + public Builder clearUserId() { + bitField0_ = (bitField0_ & ~0x00000001); + userId_ = 0; + + return this; + } + + private int sessionId_ ; + /** + * required uint32 session_id = 2; + */ + public boolean hasSessionId() { + return ((bitField0_ & 0x00000002) == 0x00000002); + } + /** + * required uint32 session_id = 2; + */ + public int getSessionId() { + return sessionId_; + } + /** + * required uint32 session_id = 2; + */ + public Builder setSessionId(int value) { + bitField0_ |= 0x00000002; + sessionId_ = value; + + return this; + } + /** + * required uint32 session_id = 2; + */ + public Builder clearSessionId() { + bitField0_ = (bitField0_ & ~0x00000002); + sessionId_ = 0; + + return this; + } + + private int msgId_ ; + /** + * required uint32 msg_id = 3; + */ + public boolean hasMsgId() { + return ((bitField0_ & 0x00000004) == 0x00000004); + } + /** + * required uint32 msg_id = 3; + */ + public int getMsgId() { + return msgId_; + } + /** + * required uint32 msg_id = 3; + */ + public Builder setMsgId(int value) { + bitField0_ |= 0x00000004; + msgId_ = value; + + return this; + } + /** + * required uint32 msg_id = 3; + */ + public Builder clearMsgId() { + bitField0_ = (bitField0_ & ~0x00000004); + msgId_ = 0; + + return this; + } + + private com.mogujie.tt.protobuf.IMBaseDefine.SessionType sessionType_ = com.mogujie.tt.protobuf.IMBaseDefine.SessionType.SESSION_TYPE_SINGLE; + /** + * required .IM.BaseDefine.SessionType session_type = 4; + */ + public boolean hasSessionType() { + return ((bitField0_ & 0x00000008) == 0x00000008); + } + /** + * required .IM.BaseDefine.SessionType session_type = 4; + */ + public com.mogujie.tt.protobuf.IMBaseDefine.SessionType getSessionType() { + return sessionType_; + } + /** + * required .IM.BaseDefine.SessionType session_type = 4; + */ + public Builder setSessionType(com.mogujie.tt.protobuf.IMBaseDefine.SessionType value) { + if (value == null) { + throw new NullPointerException(); + } + bitField0_ |= 0x00000008; + sessionType_ = value; + + return this; + } + /** + * required .IM.BaseDefine.SessionType session_type = 4; + */ + public Builder clearSessionType() { + bitField0_ = (bitField0_ & ~0x00000008); + sessionType_ = com.mogujie.tt.protobuf.IMBaseDefine.SessionType.SESSION_TYPE_SINGLE; + + return this; + } + + // @@protoc_insertion_point(builder_scope:IM.Message.IMMsgDataReadNotify) + } + + static { + defaultInstance = new IMMsgDataReadNotify(true); + defaultInstance.initFields(); + } + + // @@protoc_insertion_point(class_scope:IM.Message.IMMsgDataReadNotify) + } + + public interface IMClientTimeReqOrBuilder extends + // @@protoc_insertion_point(interface_extends:IM.Message.IMClientTimeReq) + com.google.protobuf.MessageLiteOrBuilder { + } + /** + * Protobuf type {@code IM.Message.IMClientTimeReq} + * + *
+   *cmd id:		0x0305
+   * 
+ */ + public static final class IMClientTimeReq extends + com.google.protobuf.GeneratedMessageLite implements + // @@protoc_insertion_point(message_implements:IM.Message.IMClientTimeReq) + IMClientTimeReqOrBuilder { + // Use IMClientTimeReq.newBuilder() to construct. + private IMClientTimeReq(com.google.protobuf.GeneratedMessageLite.Builder builder) { + super(builder); + this.unknownFields = builder.getUnknownFields(); + } + private IMClientTimeReq(boolean noInit) { this.unknownFields = com.google.protobuf.ByteString.EMPTY;} + + private static final IMClientTimeReq defaultInstance; + public static IMClientTimeReq getDefaultInstance() { + return defaultInstance; + } + + public IMClientTimeReq getDefaultInstanceForType() { + return defaultInstance; + } + + private final com.google.protobuf.ByteString unknownFields; + private IMClientTimeReq( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + initFields(); + com.google.protobuf.ByteString.Output unknownFieldsOutput = + com.google.protobuf.ByteString.newOutput(); + com.google.protobuf.CodedOutputStream unknownFieldsCodedOutput = + com.google.protobuf.CodedOutputStream.newInstance( + unknownFieldsOutput); + try { + boolean done = false; + while (!done) { + int tag = input.readTag(); + switch (tag) { + case 0: + done = true; + break; + default: { + if (!parseUnknownField(input, unknownFieldsCodedOutput, + extensionRegistry, tag)) { + done = true; + } + break; + } + } + } + } catch (com.google.protobuf.InvalidProtocolBufferException e) { + throw e.setUnfinishedMessage(this); + } catch (java.io.IOException e) { + throw new com.google.protobuf.InvalidProtocolBufferException( + e.getMessage()).setUnfinishedMessage(this); + } finally { + try { + unknownFieldsCodedOutput.flush(); + } catch (java.io.IOException e) { + // Should not happen + } finally { + unknownFields = unknownFieldsOutput.toByteString(); + } + makeExtensionsImmutable(); + } + } + public static com.google.protobuf.Parser PARSER = + new com.google.protobuf.AbstractParser() { + public IMClientTimeReq parsePartialFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return new IMClientTimeReq(input, extensionRegistry); + } + }; + + @java.lang.Override + public com.google.protobuf.Parser getParserForType() { + return PARSER; + } + + private void initFields() { + } + private byte memoizedIsInitialized = -1; + public final boolean isInitialized() { + byte isInitialized = memoizedIsInitialized; + if (isInitialized == 1) return true; + if (isInitialized == 0) return false; + + memoizedIsInitialized = 1; + return true; + } + + public void writeTo(com.google.protobuf.CodedOutputStream output) + throws java.io.IOException { + getSerializedSize(); + output.writeRawBytes(unknownFields); + } + + private int memoizedSerializedSize = -1; + public int getSerializedSize() { + int size = memoizedSerializedSize; + if (size != -1) return size; + + size = 0; + size += unknownFields.size(); + memoizedSerializedSize = size; + return size; + } + + private static final long serialVersionUID = 0L; + @java.lang.Override + protected java.lang.Object writeReplace() + throws java.io.ObjectStreamException { + return super.writeReplace(); + } + + public static com.mogujie.tt.protobuf.IMMessage.IMClientTimeReq parseFrom( + com.google.protobuf.ByteString data) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data); + } + public static com.mogujie.tt.protobuf.IMMessage.IMClientTimeReq parseFrom( + com.google.protobuf.ByteString data, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data, extensionRegistry); + } + public static com.mogujie.tt.protobuf.IMMessage.IMClientTimeReq parseFrom(byte[] data) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data); + } + public static com.mogujie.tt.protobuf.IMMessage.IMClientTimeReq parseFrom( + byte[] data, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data, extensionRegistry); + } + public static com.mogujie.tt.protobuf.IMMessage.IMClientTimeReq parseFrom(java.io.InputStream input) + throws java.io.IOException { + return PARSER.parseFrom(input); + } + public static com.mogujie.tt.protobuf.IMMessage.IMClientTimeReq parseFrom( + java.io.InputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return PARSER.parseFrom(input, extensionRegistry); + } + public static com.mogujie.tt.protobuf.IMMessage.IMClientTimeReq parseDelimitedFrom(java.io.InputStream input) + throws java.io.IOException { + return PARSER.parseDelimitedFrom(input); + } + public static com.mogujie.tt.protobuf.IMMessage.IMClientTimeReq parseDelimitedFrom( + java.io.InputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return PARSER.parseDelimitedFrom(input, extensionRegistry); + } + public static com.mogujie.tt.protobuf.IMMessage.IMClientTimeReq parseFrom( + com.google.protobuf.CodedInputStream input) + throws java.io.IOException { + return PARSER.parseFrom(input); + } + public static com.mogujie.tt.protobuf.IMMessage.IMClientTimeReq parseFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return PARSER.parseFrom(input, extensionRegistry); + } + + public static Builder newBuilder() { return Builder.create(); } + public Builder newBuilderForType() { return newBuilder(); } + public static Builder newBuilder(com.mogujie.tt.protobuf.IMMessage.IMClientTimeReq prototype) { + return newBuilder().mergeFrom(prototype); + } + public Builder toBuilder() { return newBuilder(this); } + + /** + * Protobuf type {@code IM.Message.IMClientTimeReq} + * + *
+     *cmd id:		0x0305
+     * 
+ */ + public static final class Builder extends + com.google.protobuf.GeneratedMessageLite.Builder< + com.mogujie.tt.protobuf.IMMessage.IMClientTimeReq, Builder> + implements + // @@protoc_insertion_point(builder_implements:IM.Message.IMClientTimeReq) + com.mogujie.tt.protobuf.IMMessage.IMClientTimeReqOrBuilder { + // Construct using com.mogujie.tt.protobuf.IMMessage.IMClientTimeReq.newBuilder() + private Builder() { + maybeForceBuilderInitialization(); + } + + private void maybeForceBuilderInitialization() { + } + private static Builder create() { + return new Builder(); + } + + public Builder clear() { + super.clear(); + return this; + } + + public Builder clone() { + return create().mergeFrom(buildPartial()); + } + + public com.mogujie.tt.protobuf.IMMessage.IMClientTimeReq getDefaultInstanceForType() { + return com.mogujie.tt.protobuf.IMMessage.IMClientTimeReq.getDefaultInstance(); + } + + public com.mogujie.tt.protobuf.IMMessage.IMClientTimeReq build() { + com.mogujie.tt.protobuf.IMMessage.IMClientTimeReq result = buildPartial(); + if (!result.isInitialized()) { + throw newUninitializedMessageException(result); + } + return result; + } + + public com.mogujie.tt.protobuf.IMMessage.IMClientTimeReq buildPartial() { + com.mogujie.tt.protobuf.IMMessage.IMClientTimeReq result = new com.mogujie.tt.protobuf.IMMessage.IMClientTimeReq(this); + return result; + } + + public Builder mergeFrom(com.mogujie.tt.protobuf.IMMessage.IMClientTimeReq other) { + if (other == com.mogujie.tt.protobuf.IMMessage.IMClientTimeReq.getDefaultInstance()) return this; + setUnknownFields( + getUnknownFields().concat(other.unknownFields)); + return this; + } + + public final boolean isInitialized() { + return true; + } + + public Builder mergeFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + com.mogujie.tt.protobuf.IMMessage.IMClientTimeReq parsedMessage = null; + try { + parsedMessage = PARSER.parsePartialFrom(input, extensionRegistry); + } catch (com.google.protobuf.InvalidProtocolBufferException e) { + parsedMessage = (com.mogujie.tt.protobuf.IMMessage.IMClientTimeReq) e.getUnfinishedMessage(); + throw e; + } finally { + if (parsedMessage != null) { + mergeFrom(parsedMessage); + } + } + return this; + } + + // @@protoc_insertion_point(builder_scope:IM.Message.IMClientTimeReq) + } + + static { + defaultInstance = new IMClientTimeReq(true); + defaultInstance.initFields(); + } + + // @@protoc_insertion_point(class_scope:IM.Message.IMClientTimeReq) + } + + public interface IMClientTimeRspOrBuilder extends + // @@protoc_insertion_point(interface_extends:IM.Message.IMClientTimeRsp) + com.google.protobuf.MessageLiteOrBuilder { + + /** + * required uint32 server_time = 1; + * + *
+     *cmd id:		0x0306
+     * 
+ */ + boolean hasServerTime(); + /** + * required uint32 server_time = 1; + * + *
+     *cmd id:		0x0306
+     * 
+ */ + int getServerTime(); + } + /** + * Protobuf type {@code IM.Message.IMClientTimeRsp} + */ + public static final class IMClientTimeRsp extends + com.google.protobuf.GeneratedMessageLite implements + // @@protoc_insertion_point(message_implements:IM.Message.IMClientTimeRsp) + IMClientTimeRspOrBuilder { + // Use IMClientTimeRsp.newBuilder() to construct. + private IMClientTimeRsp(com.google.protobuf.GeneratedMessageLite.Builder builder) { + super(builder); + this.unknownFields = builder.getUnknownFields(); + } + private IMClientTimeRsp(boolean noInit) { this.unknownFields = com.google.protobuf.ByteString.EMPTY;} + + private static final IMClientTimeRsp defaultInstance; + public static IMClientTimeRsp getDefaultInstance() { + return defaultInstance; + } + + public IMClientTimeRsp getDefaultInstanceForType() { + return defaultInstance; + } + + private final com.google.protobuf.ByteString unknownFields; + private IMClientTimeRsp( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + initFields(); + int mutable_bitField0_ = 0; + com.google.protobuf.ByteString.Output unknownFieldsOutput = + com.google.protobuf.ByteString.newOutput(); + com.google.protobuf.CodedOutputStream unknownFieldsCodedOutput = + com.google.protobuf.CodedOutputStream.newInstance( + unknownFieldsOutput); + try { + boolean done = false; + while (!done) { + int tag = input.readTag(); + switch (tag) { + case 0: + done = true; + break; + default: { + if (!parseUnknownField(input, unknownFieldsCodedOutput, + extensionRegistry, tag)) { + done = true; + } + break; + } + case 8: { + bitField0_ |= 0x00000001; + serverTime_ = input.readUInt32(); + break; + } + } + } + } catch (com.google.protobuf.InvalidProtocolBufferException e) { + throw e.setUnfinishedMessage(this); + } catch (java.io.IOException e) { + throw new com.google.protobuf.InvalidProtocolBufferException( + e.getMessage()).setUnfinishedMessage(this); + } finally { + try { + unknownFieldsCodedOutput.flush(); + } catch (java.io.IOException e) { + // Should not happen + } finally { + unknownFields = unknownFieldsOutput.toByteString(); + } + makeExtensionsImmutable(); + } + } + public static com.google.protobuf.Parser PARSER = + new com.google.protobuf.AbstractParser() { + public IMClientTimeRsp parsePartialFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return new IMClientTimeRsp(input, extensionRegistry); + } + }; + + @java.lang.Override + public com.google.protobuf.Parser getParserForType() { + return PARSER; + } + + private int bitField0_; + public static final int SERVER_TIME_FIELD_NUMBER = 1; + private int serverTime_; + /** + * required uint32 server_time = 1; + * + *
+     *cmd id:		0x0306
+     * 
+ */ + public boolean hasServerTime() { + return ((bitField0_ & 0x00000001) == 0x00000001); + } + /** + * required uint32 server_time = 1; + * + *
+     *cmd id:		0x0306
+     * 
+ */ + public int getServerTime() { + return serverTime_; + } + + private void initFields() { + serverTime_ = 0; + } + private byte memoizedIsInitialized = -1; + public final boolean isInitialized() { + byte isInitialized = memoizedIsInitialized; + if (isInitialized == 1) return true; + if (isInitialized == 0) return false; + + if (!hasServerTime()) { + memoizedIsInitialized = 0; + return false; + } + memoizedIsInitialized = 1; + return true; + } + + public void writeTo(com.google.protobuf.CodedOutputStream output) + throws java.io.IOException { + getSerializedSize(); + if (((bitField0_ & 0x00000001) == 0x00000001)) { + output.writeUInt32(1, serverTime_); + } + output.writeRawBytes(unknownFields); + } + + private int memoizedSerializedSize = -1; + public int getSerializedSize() { + int size = memoizedSerializedSize; + if (size != -1) return size; + + size = 0; + if (((bitField0_ & 0x00000001) == 0x00000001)) { + size += com.google.protobuf.CodedOutputStream + .computeUInt32Size(1, serverTime_); + } + size += unknownFields.size(); + memoizedSerializedSize = size; + return size; + } + + private static final long serialVersionUID = 0L; + @java.lang.Override + protected java.lang.Object writeReplace() + throws java.io.ObjectStreamException { + return super.writeReplace(); + } + + public static com.mogujie.tt.protobuf.IMMessage.IMClientTimeRsp parseFrom( + com.google.protobuf.ByteString data) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data); + } + public static com.mogujie.tt.protobuf.IMMessage.IMClientTimeRsp parseFrom( + com.google.protobuf.ByteString data, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data, extensionRegistry); + } + public static com.mogujie.tt.protobuf.IMMessage.IMClientTimeRsp parseFrom(byte[] data) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data); + } + public static com.mogujie.tt.protobuf.IMMessage.IMClientTimeRsp parseFrom( + byte[] data, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data, extensionRegistry); + } + public static com.mogujie.tt.protobuf.IMMessage.IMClientTimeRsp parseFrom(java.io.InputStream input) + throws java.io.IOException { + return PARSER.parseFrom(input); + } + public static com.mogujie.tt.protobuf.IMMessage.IMClientTimeRsp parseFrom( + java.io.InputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return PARSER.parseFrom(input, extensionRegistry); + } + public static com.mogujie.tt.protobuf.IMMessage.IMClientTimeRsp parseDelimitedFrom(java.io.InputStream input) + throws java.io.IOException { + return PARSER.parseDelimitedFrom(input); + } + public static com.mogujie.tt.protobuf.IMMessage.IMClientTimeRsp parseDelimitedFrom( + java.io.InputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return PARSER.parseDelimitedFrom(input, extensionRegistry); + } + public static com.mogujie.tt.protobuf.IMMessage.IMClientTimeRsp parseFrom( + com.google.protobuf.CodedInputStream input) + throws java.io.IOException { + return PARSER.parseFrom(input); + } + public static com.mogujie.tt.protobuf.IMMessage.IMClientTimeRsp parseFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return PARSER.parseFrom(input, extensionRegistry); + } + + public static Builder newBuilder() { return Builder.create(); } + public Builder newBuilderForType() { return newBuilder(); } + public static Builder newBuilder(com.mogujie.tt.protobuf.IMMessage.IMClientTimeRsp prototype) { + return newBuilder().mergeFrom(prototype); + } + public Builder toBuilder() { return newBuilder(this); } + + /** + * Protobuf type {@code IM.Message.IMClientTimeRsp} + */ + public static final class Builder extends + com.google.protobuf.GeneratedMessageLite.Builder< + com.mogujie.tt.protobuf.IMMessage.IMClientTimeRsp, Builder> + implements + // @@protoc_insertion_point(builder_implements:IM.Message.IMClientTimeRsp) + com.mogujie.tt.protobuf.IMMessage.IMClientTimeRspOrBuilder { + // Construct using com.mogujie.tt.protobuf.IMMessage.IMClientTimeRsp.newBuilder() + private Builder() { + maybeForceBuilderInitialization(); + } + + private void maybeForceBuilderInitialization() { + } + private static Builder create() { + return new Builder(); + } + + public Builder clear() { + super.clear(); + serverTime_ = 0; + bitField0_ = (bitField0_ & ~0x00000001); + return this; + } + + public Builder clone() { + return create().mergeFrom(buildPartial()); + } + + public com.mogujie.tt.protobuf.IMMessage.IMClientTimeRsp getDefaultInstanceForType() { + return com.mogujie.tt.protobuf.IMMessage.IMClientTimeRsp.getDefaultInstance(); + } + + public com.mogujie.tt.protobuf.IMMessage.IMClientTimeRsp build() { + com.mogujie.tt.protobuf.IMMessage.IMClientTimeRsp result = buildPartial(); + if (!result.isInitialized()) { + throw newUninitializedMessageException(result); + } + return result; + } + + public com.mogujie.tt.protobuf.IMMessage.IMClientTimeRsp buildPartial() { + com.mogujie.tt.protobuf.IMMessage.IMClientTimeRsp result = new com.mogujie.tt.protobuf.IMMessage.IMClientTimeRsp(this); + int from_bitField0_ = bitField0_; + int to_bitField0_ = 0; + if (((from_bitField0_ & 0x00000001) == 0x00000001)) { + to_bitField0_ |= 0x00000001; + } + result.serverTime_ = serverTime_; + result.bitField0_ = to_bitField0_; + return result; + } + + public Builder mergeFrom(com.mogujie.tt.protobuf.IMMessage.IMClientTimeRsp other) { + if (other == com.mogujie.tt.protobuf.IMMessage.IMClientTimeRsp.getDefaultInstance()) return this; + if (other.hasServerTime()) { + setServerTime(other.getServerTime()); + } + setUnknownFields( + getUnknownFields().concat(other.unknownFields)); + return this; + } + + public final boolean isInitialized() { + if (!hasServerTime()) { + + return false; + } + return true; + } + + public Builder mergeFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + com.mogujie.tt.protobuf.IMMessage.IMClientTimeRsp parsedMessage = null; + try { + parsedMessage = PARSER.parsePartialFrom(input, extensionRegistry); + } catch (com.google.protobuf.InvalidProtocolBufferException e) { + parsedMessage = (com.mogujie.tt.protobuf.IMMessage.IMClientTimeRsp) e.getUnfinishedMessage(); + throw e; + } finally { + if (parsedMessage != null) { + mergeFrom(parsedMessage); + } + } + return this; + } + private int bitField0_; + + private int serverTime_ ; + /** + * required uint32 server_time = 1; + * + *
+       *cmd id:		0x0306
+       * 
+ */ + public boolean hasServerTime() { + return ((bitField0_ & 0x00000001) == 0x00000001); + } + /** + * required uint32 server_time = 1; + * + *
+       *cmd id:		0x0306
+       * 
+ */ + public int getServerTime() { + return serverTime_; + } + /** + * required uint32 server_time = 1; + * + *
+       *cmd id:		0x0306
+       * 
+ */ + public Builder setServerTime(int value) { + bitField0_ |= 0x00000001; + serverTime_ = value; + + return this; + } + /** + * required uint32 server_time = 1; + * + *
+       *cmd id:		0x0306
+       * 
+ */ + public Builder clearServerTime() { + bitField0_ = (bitField0_ & ~0x00000001); + serverTime_ = 0; + + return this; + } + + // @@protoc_insertion_point(builder_scope:IM.Message.IMClientTimeRsp) + } + + static { + defaultInstance = new IMClientTimeRsp(true); + defaultInstance.initFields(); + } + + // @@protoc_insertion_point(class_scope:IM.Message.IMClientTimeRsp) + } + + public interface IMUnreadMsgCntReqOrBuilder extends + // @@protoc_insertion_point(interface_extends:IM.Message.IMUnreadMsgCntReq) + com.google.protobuf.MessageLiteOrBuilder { + + /** + * required uint32 user_id = 1; + * + *
+     *cmd id:		0x0307
+     * 
+ */ + boolean hasUserId(); + /** + * required uint32 user_id = 1; + * + *
+     *cmd id:		0x0307
+     * 
+ */ + int getUserId(); + + /** + * optional bytes attach_data = 20; + */ + boolean hasAttachData(); + /** + * optional bytes attach_data = 20; + */ + com.google.protobuf.ByteString getAttachData(); + } + /** + * Protobuf type {@code IM.Message.IMUnreadMsgCntReq} + */ + public static final class IMUnreadMsgCntReq extends + com.google.protobuf.GeneratedMessageLite implements + // @@protoc_insertion_point(message_implements:IM.Message.IMUnreadMsgCntReq) + IMUnreadMsgCntReqOrBuilder { + // Use IMUnreadMsgCntReq.newBuilder() to construct. + private IMUnreadMsgCntReq(com.google.protobuf.GeneratedMessageLite.Builder builder) { + super(builder); + this.unknownFields = builder.getUnknownFields(); + } + private IMUnreadMsgCntReq(boolean noInit) { this.unknownFields = com.google.protobuf.ByteString.EMPTY;} + + private static final IMUnreadMsgCntReq defaultInstance; + public static IMUnreadMsgCntReq getDefaultInstance() { + return defaultInstance; + } + + public IMUnreadMsgCntReq getDefaultInstanceForType() { + return defaultInstance; + } + + private final com.google.protobuf.ByteString unknownFields; + private IMUnreadMsgCntReq( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + initFields(); + int mutable_bitField0_ = 0; + com.google.protobuf.ByteString.Output unknownFieldsOutput = + com.google.protobuf.ByteString.newOutput(); + com.google.protobuf.CodedOutputStream unknownFieldsCodedOutput = + com.google.protobuf.CodedOutputStream.newInstance( + unknownFieldsOutput); + try { + boolean done = false; + while (!done) { + int tag = input.readTag(); + switch (tag) { + case 0: + done = true; + break; + default: { + if (!parseUnknownField(input, unknownFieldsCodedOutput, + extensionRegistry, tag)) { + done = true; + } + break; + } + case 8: { + bitField0_ |= 0x00000001; + userId_ = input.readUInt32(); + break; + } + case 162: { + bitField0_ |= 0x00000002; + attachData_ = input.readBytes(); + break; + } + } + } + } catch (com.google.protobuf.InvalidProtocolBufferException e) { + throw e.setUnfinishedMessage(this); + } catch (java.io.IOException e) { + throw new com.google.protobuf.InvalidProtocolBufferException( + e.getMessage()).setUnfinishedMessage(this); + } finally { + try { + unknownFieldsCodedOutput.flush(); + } catch (java.io.IOException e) { + // Should not happen + } finally { + unknownFields = unknownFieldsOutput.toByteString(); + } + makeExtensionsImmutable(); + } + } + public static com.google.protobuf.Parser PARSER = + new com.google.protobuf.AbstractParser() { + public IMUnreadMsgCntReq parsePartialFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return new IMUnreadMsgCntReq(input, extensionRegistry); + } + }; + + @java.lang.Override + public com.google.protobuf.Parser getParserForType() { + return PARSER; + } + + private int bitField0_; + public static final int USER_ID_FIELD_NUMBER = 1; + private int userId_; + /** + * required uint32 user_id = 1; + * + *
+     *cmd id:		0x0307
+     * 
+ */ + public boolean hasUserId() { + return ((bitField0_ & 0x00000001) == 0x00000001); + } + /** + * required uint32 user_id = 1; + * + *
+     *cmd id:		0x0307
+     * 
+ */ + public int getUserId() { + return userId_; + } + + public static final int ATTACH_DATA_FIELD_NUMBER = 20; + private com.google.protobuf.ByteString attachData_; + /** + * optional bytes attach_data = 20; + */ + public boolean hasAttachData() { + return ((bitField0_ & 0x00000002) == 0x00000002); + } + /** + * optional bytes attach_data = 20; + */ + public com.google.protobuf.ByteString getAttachData() { + return attachData_; + } + + private void initFields() { + userId_ = 0; + attachData_ = com.google.protobuf.ByteString.EMPTY; + } + private byte memoizedIsInitialized = -1; + public final boolean isInitialized() { + byte isInitialized = memoizedIsInitialized; + if (isInitialized == 1) return true; + if (isInitialized == 0) return false; + + if (!hasUserId()) { + memoizedIsInitialized = 0; + return false; + } + memoizedIsInitialized = 1; + return true; + } + + public void writeTo(com.google.protobuf.CodedOutputStream output) + throws java.io.IOException { + getSerializedSize(); + if (((bitField0_ & 0x00000001) == 0x00000001)) { + output.writeUInt32(1, userId_); + } + if (((bitField0_ & 0x00000002) == 0x00000002)) { + output.writeBytes(20, attachData_); + } + output.writeRawBytes(unknownFields); + } + + private int memoizedSerializedSize = -1; + public int getSerializedSize() { + int size = memoizedSerializedSize; + if (size != -1) return size; + + size = 0; + if (((bitField0_ & 0x00000001) == 0x00000001)) { + size += com.google.protobuf.CodedOutputStream + .computeUInt32Size(1, userId_); + } + if (((bitField0_ & 0x00000002) == 0x00000002)) { + size += com.google.protobuf.CodedOutputStream + .computeBytesSize(20, attachData_); + } + size += unknownFields.size(); + memoizedSerializedSize = size; + return size; + } + + private static final long serialVersionUID = 0L; + @java.lang.Override + protected java.lang.Object writeReplace() + throws java.io.ObjectStreamException { + return super.writeReplace(); + } + + public static com.mogujie.tt.protobuf.IMMessage.IMUnreadMsgCntReq parseFrom( + com.google.protobuf.ByteString data) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data); + } + public static com.mogujie.tt.protobuf.IMMessage.IMUnreadMsgCntReq parseFrom( + com.google.protobuf.ByteString data, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data, extensionRegistry); + } + public static com.mogujie.tt.protobuf.IMMessage.IMUnreadMsgCntReq parseFrom(byte[] data) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data); + } + public static com.mogujie.tt.protobuf.IMMessage.IMUnreadMsgCntReq parseFrom( + byte[] data, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data, extensionRegistry); + } + public static com.mogujie.tt.protobuf.IMMessage.IMUnreadMsgCntReq parseFrom(java.io.InputStream input) + throws java.io.IOException { + return PARSER.parseFrom(input); + } + public static com.mogujie.tt.protobuf.IMMessage.IMUnreadMsgCntReq parseFrom( + java.io.InputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return PARSER.parseFrom(input, extensionRegistry); + } + public static com.mogujie.tt.protobuf.IMMessage.IMUnreadMsgCntReq parseDelimitedFrom(java.io.InputStream input) + throws java.io.IOException { + return PARSER.parseDelimitedFrom(input); + } + public static com.mogujie.tt.protobuf.IMMessage.IMUnreadMsgCntReq parseDelimitedFrom( + java.io.InputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return PARSER.parseDelimitedFrom(input, extensionRegistry); + } + public static com.mogujie.tt.protobuf.IMMessage.IMUnreadMsgCntReq parseFrom( + com.google.protobuf.CodedInputStream input) + throws java.io.IOException { + return PARSER.parseFrom(input); + } + public static com.mogujie.tt.protobuf.IMMessage.IMUnreadMsgCntReq parseFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return PARSER.parseFrom(input, extensionRegistry); + } + + public static Builder newBuilder() { return Builder.create(); } + public Builder newBuilderForType() { return newBuilder(); } + public static Builder newBuilder(com.mogujie.tt.protobuf.IMMessage.IMUnreadMsgCntReq prototype) { + return newBuilder().mergeFrom(prototype); + } + public Builder toBuilder() { return newBuilder(this); } + + /** + * Protobuf type {@code IM.Message.IMUnreadMsgCntReq} + */ + public static final class Builder extends + com.google.protobuf.GeneratedMessageLite.Builder< + com.mogujie.tt.protobuf.IMMessage.IMUnreadMsgCntReq, Builder> + implements + // @@protoc_insertion_point(builder_implements:IM.Message.IMUnreadMsgCntReq) + com.mogujie.tt.protobuf.IMMessage.IMUnreadMsgCntReqOrBuilder { + // Construct using com.mogujie.tt.protobuf.IMMessage.IMUnreadMsgCntReq.newBuilder() + private Builder() { + maybeForceBuilderInitialization(); + } + + private void maybeForceBuilderInitialization() { + } + private static Builder create() { + return new Builder(); + } + + public Builder clear() { + super.clear(); + userId_ = 0; + bitField0_ = (bitField0_ & ~0x00000001); + attachData_ = com.google.protobuf.ByteString.EMPTY; + bitField0_ = (bitField0_ & ~0x00000002); + return this; + } + + public Builder clone() { + return create().mergeFrom(buildPartial()); + } + + public com.mogujie.tt.protobuf.IMMessage.IMUnreadMsgCntReq getDefaultInstanceForType() { + return com.mogujie.tt.protobuf.IMMessage.IMUnreadMsgCntReq.getDefaultInstance(); + } + + public com.mogujie.tt.protobuf.IMMessage.IMUnreadMsgCntReq build() { + com.mogujie.tt.protobuf.IMMessage.IMUnreadMsgCntReq result = buildPartial(); + if (!result.isInitialized()) { + throw newUninitializedMessageException(result); + } + return result; + } + + public com.mogujie.tt.protobuf.IMMessage.IMUnreadMsgCntReq buildPartial() { + com.mogujie.tt.protobuf.IMMessage.IMUnreadMsgCntReq result = new com.mogujie.tt.protobuf.IMMessage.IMUnreadMsgCntReq(this); + int from_bitField0_ = bitField0_; + int to_bitField0_ = 0; + if (((from_bitField0_ & 0x00000001) == 0x00000001)) { + to_bitField0_ |= 0x00000001; + } + result.userId_ = userId_; + if (((from_bitField0_ & 0x00000002) == 0x00000002)) { + to_bitField0_ |= 0x00000002; + } + result.attachData_ = attachData_; + result.bitField0_ = to_bitField0_; + return result; + } + + public Builder mergeFrom(com.mogujie.tt.protobuf.IMMessage.IMUnreadMsgCntReq other) { + if (other == com.mogujie.tt.protobuf.IMMessage.IMUnreadMsgCntReq.getDefaultInstance()) return this; + if (other.hasUserId()) { + setUserId(other.getUserId()); + } + if (other.hasAttachData()) { + setAttachData(other.getAttachData()); + } + setUnknownFields( + getUnknownFields().concat(other.unknownFields)); + return this; + } + + public final boolean isInitialized() { + if (!hasUserId()) { + + return false; + } + return true; + } + + public Builder mergeFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + com.mogujie.tt.protobuf.IMMessage.IMUnreadMsgCntReq parsedMessage = null; + try { + parsedMessage = PARSER.parsePartialFrom(input, extensionRegistry); + } catch (com.google.protobuf.InvalidProtocolBufferException e) { + parsedMessage = (com.mogujie.tt.protobuf.IMMessage.IMUnreadMsgCntReq) e.getUnfinishedMessage(); + throw e; + } finally { + if (parsedMessage != null) { + mergeFrom(parsedMessage); + } + } + return this; + } + private int bitField0_; + + private int userId_ ; + /** + * required uint32 user_id = 1; + * + *
+       *cmd id:		0x0307
+       * 
+ */ + public boolean hasUserId() { + return ((bitField0_ & 0x00000001) == 0x00000001); + } + /** + * required uint32 user_id = 1; + * + *
+       *cmd id:		0x0307
+       * 
+ */ + public int getUserId() { + return userId_; + } + /** + * required uint32 user_id = 1; + * + *
+       *cmd id:		0x0307
+       * 
+ */ + public Builder setUserId(int value) { + bitField0_ |= 0x00000001; + userId_ = value; + + return this; + } + /** + * required uint32 user_id = 1; + * + *
+       *cmd id:		0x0307
+       * 
+ */ + public Builder clearUserId() { + bitField0_ = (bitField0_ & ~0x00000001); + userId_ = 0; + + return this; + } + + private com.google.protobuf.ByteString attachData_ = com.google.protobuf.ByteString.EMPTY; + /** + * optional bytes attach_data = 20; + */ + public boolean hasAttachData() { + return ((bitField0_ & 0x00000002) == 0x00000002); + } + /** + * optional bytes attach_data = 20; + */ + public com.google.protobuf.ByteString getAttachData() { + return attachData_; + } + /** + * optional bytes attach_data = 20; + */ + public Builder setAttachData(com.google.protobuf.ByteString value) { + if (value == null) { + throw new NullPointerException(); + } + bitField0_ |= 0x00000002; + attachData_ = value; + + return this; + } + /** + * optional bytes attach_data = 20; + */ + public Builder clearAttachData() { + bitField0_ = (bitField0_ & ~0x00000002); + attachData_ = getDefaultInstance().getAttachData(); + + return this; + } + + // @@protoc_insertion_point(builder_scope:IM.Message.IMUnreadMsgCntReq) + } + + static { + defaultInstance = new IMUnreadMsgCntReq(true); + defaultInstance.initFields(); + } + + // @@protoc_insertion_point(class_scope:IM.Message.IMUnreadMsgCntReq) + } + + public interface IMUnreadMsgCntRspOrBuilder extends + // @@protoc_insertion_point(interface_extends:IM.Message.IMUnreadMsgCntRsp) + com.google.protobuf.MessageLiteOrBuilder { + + /** + * required uint32 user_id = 1; + * + *
+     *cmd id:		0x0308
+     * 
+ */ + boolean hasUserId(); + /** + * required uint32 user_id = 1; + * + *
+     *cmd id:		0x0308
+     * 
+ */ + int getUserId(); + + /** + * required uint32 total_cnt = 2; + */ + boolean hasTotalCnt(); + /** + * required uint32 total_cnt = 2; + */ + int getTotalCnt(); + + /** + * repeated .IM.BaseDefine.UnreadInfo unreadinfo_list = 3; + */ + java.util.List + getUnreadinfoListList(); + /** + * repeated .IM.BaseDefine.UnreadInfo unreadinfo_list = 3; + */ + com.mogujie.tt.protobuf.IMBaseDefine.UnreadInfo getUnreadinfoList(int index); + /** + * repeated .IM.BaseDefine.UnreadInfo unreadinfo_list = 3; + */ + int getUnreadinfoListCount(); + + /** + * optional bytes attach_data = 20; + */ + boolean hasAttachData(); + /** + * optional bytes attach_data = 20; + */ + com.google.protobuf.ByteString getAttachData(); + } + /** + * Protobuf type {@code IM.Message.IMUnreadMsgCntRsp} + */ + public static final class IMUnreadMsgCntRsp extends + com.google.protobuf.GeneratedMessageLite implements + // @@protoc_insertion_point(message_implements:IM.Message.IMUnreadMsgCntRsp) + IMUnreadMsgCntRspOrBuilder { + // Use IMUnreadMsgCntRsp.newBuilder() to construct. + private IMUnreadMsgCntRsp(com.google.protobuf.GeneratedMessageLite.Builder builder) { + super(builder); + this.unknownFields = builder.getUnknownFields(); + } + private IMUnreadMsgCntRsp(boolean noInit) { this.unknownFields = com.google.protobuf.ByteString.EMPTY;} + + private static final IMUnreadMsgCntRsp defaultInstance; + public static IMUnreadMsgCntRsp getDefaultInstance() { + return defaultInstance; + } + + public IMUnreadMsgCntRsp getDefaultInstanceForType() { + return defaultInstance; + } + + private final com.google.protobuf.ByteString unknownFields; + private IMUnreadMsgCntRsp( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + initFields(); + int mutable_bitField0_ = 0; + com.google.protobuf.ByteString.Output unknownFieldsOutput = + com.google.protobuf.ByteString.newOutput(); + com.google.protobuf.CodedOutputStream unknownFieldsCodedOutput = + com.google.protobuf.CodedOutputStream.newInstance( + unknownFieldsOutput); + try { + boolean done = false; + while (!done) { + int tag = input.readTag(); + switch (tag) { + case 0: + done = true; + break; + default: { + if (!parseUnknownField(input, unknownFieldsCodedOutput, + extensionRegistry, tag)) { + done = true; + } + break; + } + case 8: { + bitField0_ |= 0x00000001; + userId_ = input.readUInt32(); + break; + } + case 16: { + bitField0_ |= 0x00000002; + totalCnt_ = input.readUInt32(); + break; + } + case 26: { + if (!((mutable_bitField0_ & 0x00000004) == 0x00000004)) { + unreadinfoList_ = new java.util.ArrayList(); + mutable_bitField0_ |= 0x00000004; + } + unreadinfoList_.add(input.readMessage(com.mogujie.tt.protobuf.IMBaseDefine.UnreadInfo.PARSER, extensionRegistry)); + break; + } + case 162: { + bitField0_ |= 0x00000004; + attachData_ = input.readBytes(); + break; + } + } + } + } catch (com.google.protobuf.InvalidProtocolBufferException e) { + throw e.setUnfinishedMessage(this); + } catch (java.io.IOException e) { + throw new com.google.protobuf.InvalidProtocolBufferException( + e.getMessage()).setUnfinishedMessage(this); + } finally { + if (((mutable_bitField0_ & 0x00000004) == 0x00000004)) { + unreadinfoList_ = java.util.Collections.unmodifiableList(unreadinfoList_); + } + try { + unknownFieldsCodedOutput.flush(); + } catch (java.io.IOException e) { + // Should not happen + } finally { + unknownFields = unknownFieldsOutput.toByteString(); + } + makeExtensionsImmutable(); + } + } + public static com.google.protobuf.Parser PARSER = + new com.google.protobuf.AbstractParser() { + public IMUnreadMsgCntRsp parsePartialFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return new IMUnreadMsgCntRsp(input, extensionRegistry); + } + }; + + @java.lang.Override + public com.google.protobuf.Parser getParserForType() { + return PARSER; + } + + private int bitField0_; + public static final int USER_ID_FIELD_NUMBER = 1; + private int userId_; + /** + * required uint32 user_id = 1; + * + *
+     *cmd id:		0x0308
+     * 
+ */ + public boolean hasUserId() { + return ((bitField0_ & 0x00000001) == 0x00000001); + } + /** + * required uint32 user_id = 1; + * + *
+     *cmd id:		0x0308
+     * 
+ */ + public int getUserId() { + return userId_; + } + + public static final int TOTAL_CNT_FIELD_NUMBER = 2; + private int totalCnt_; + /** + * required uint32 total_cnt = 2; + */ + public boolean hasTotalCnt() { + return ((bitField0_ & 0x00000002) == 0x00000002); + } + /** + * required uint32 total_cnt = 2; + */ + public int getTotalCnt() { + return totalCnt_; + } + + public static final int UNREADINFO_LIST_FIELD_NUMBER = 3; + private java.util.List unreadinfoList_; + /** + * repeated .IM.BaseDefine.UnreadInfo unreadinfo_list = 3; + */ + public java.util.List getUnreadinfoListList() { + return unreadinfoList_; + } + /** + * repeated .IM.BaseDefine.UnreadInfo unreadinfo_list = 3; + */ + public java.util.List + getUnreadinfoListOrBuilderList() { + return unreadinfoList_; + } + /** + * repeated .IM.BaseDefine.UnreadInfo unreadinfo_list = 3; + */ + public int getUnreadinfoListCount() { + return unreadinfoList_.size(); + } + /** + * repeated .IM.BaseDefine.UnreadInfo unreadinfo_list = 3; + */ + public com.mogujie.tt.protobuf.IMBaseDefine.UnreadInfo getUnreadinfoList(int index) { + return unreadinfoList_.get(index); + } + /** + * repeated .IM.BaseDefine.UnreadInfo unreadinfo_list = 3; + */ + public com.mogujie.tt.protobuf.IMBaseDefine.UnreadInfoOrBuilder getUnreadinfoListOrBuilder( + int index) { + return unreadinfoList_.get(index); + } + + public static final int ATTACH_DATA_FIELD_NUMBER = 20; + private com.google.protobuf.ByteString attachData_; + /** + * optional bytes attach_data = 20; + */ + public boolean hasAttachData() { + return ((bitField0_ & 0x00000004) == 0x00000004); + } + /** + * optional bytes attach_data = 20; + */ + public com.google.protobuf.ByteString getAttachData() { + return attachData_; + } + + private void initFields() { + userId_ = 0; + totalCnt_ = 0; + unreadinfoList_ = java.util.Collections.emptyList(); + attachData_ = com.google.protobuf.ByteString.EMPTY; + } + private byte memoizedIsInitialized = -1; + public final boolean isInitialized() { + byte isInitialized = memoizedIsInitialized; + if (isInitialized == 1) return true; + if (isInitialized == 0) return false; + + if (!hasUserId()) { + memoizedIsInitialized = 0; + return false; + } + if (!hasTotalCnt()) { + memoizedIsInitialized = 0; + return false; + } + for (int i = 0; i < getUnreadinfoListCount(); i++) { + if (!getUnreadinfoList(i).isInitialized()) { + memoizedIsInitialized = 0; + return false; + } + } + memoizedIsInitialized = 1; + return true; + } + + public void writeTo(com.google.protobuf.CodedOutputStream output) + throws java.io.IOException { + getSerializedSize(); + if (((bitField0_ & 0x00000001) == 0x00000001)) { + output.writeUInt32(1, userId_); + } + if (((bitField0_ & 0x00000002) == 0x00000002)) { + output.writeUInt32(2, totalCnt_); + } + for (int i = 0; i < unreadinfoList_.size(); i++) { + output.writeMessage(3, unreadinfoList_.get(i)); + } + if (((bitField0_ & 0x00000004) == 0x00000004)) { + output.writeBytes(20, attachData_); + } + output.writeRawBytes(unknownFields); + } + + private int memoizedSerializedSize = -1; + public int getSerializedSize() { + int size = memoizedSerializedSize; + if (size != -1) return size; + + size = 0; + if (((bitField0_ & 0x00000001) == 0x00000001)) { + size += com.google.protobuf.CodedOutputStream + .computeUInt32Size(1, userId_); + } + if (((bitField0_ & 0x00000002) == 0x00000002)) { + size += com.google.protobuf.CodedOutputStream + .computeUInt32Size(2, totalCnt_); + } + for (int i = 0; i < unreadinfoList_.size(); i++) { + size += com.google.protobuf.CodedOutputStream + .computeMessageSize(3, unreadinfoList_.get(i)); + } + if (((bitField0_ & 0x00000004) == 0x00000004)) { + size += com.google.protobuf.CodedOutputStream + .computeBytesSize(20, attachData_); + } + size += unknownFields.size(); + memoizedSerializedSize = size; + return size; + } + + private static final long serialVersionUID = 0L; + @java.lang.Override + protected java.lang.Object writeReplace() + throws java.io.ObjectStreamException { + return super.writeReplace(); + } + + public static com.mogujie.tt.protobuf.IMMessage.IMUnreadMsgCntRsp parseFrom( + com.google.protobuf.ByteString data) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data); + } + public static com.mogujie.tt.protobuf.IMMessage.IMUnreadMsgCntRsp parseFrom( + com.google.protobuf.ByteString data, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data, extensionRegistry); + } + public static com.mogujie.tt.protobuf.IMMessage.IMUnreadMsgCntRsp parseFrom(byte[] data) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data); + } + public static com.mogujie.tt.protobuf.IMMessage.IMUnreadMsgCntRsp parseFrom( + byte[] data, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data, extensionRegistry); + } + public static com.mogujie.tt.protobuf.IMMessage.IMUnreadMsgCntRsp parseFrom(java.io.InputStream input) + throws java.io.IOException { + return PARSER.parseFrom(input); + } + public static com.mogujie.tt.protobuf.IMMessage.IMUnreadMsgCntRsp parseFrom( + java.io.InputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return PARSER.parseFrom(input, extensionRegistry); + } + public static com.mogujie.tt.protobuf.IMMessage.IMUnreadMsgCntRsp parseDelimitedFrom(java.io.InputStream input) + throws java.io.IOException { + return PARSER.parseDelimitedFrom(input); + } + public static com.mogujie.tt.protobuf.IMMessage.IMUnreadMsgCntRsp parseDelimitedFrom( + java.io.InputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return PARSER.parseDelimitedFrom(input, extensionRegistry); + } + public static com.mogujie.tt.protobuf.IMMessage.IMUnreadMsgCntRsp parseFrom( + com.google.protobuf.CodedInputStream input) + throws java.io.IOException { + return PARSER.parseFrom(input); + } + public static com.mogujie.tt.protobuf.IMMessage.IMUnreadMsgCntRsp parseFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return PARSER.parseFrom(input, extensionRegistry); + } + + public static Builder newBuilder() { return Builder.create(); } + public Builder newBuilderForType() { return newBuilder(); } + public static Builder newBuilder(com.mogujie.tt.protobuf.IMMessage.IMUnreadMsgCntRsp prototype) { + return newBuilder().mergeFrom(prototype); + } + public Builder toBuilder() { return newBuilder(this); } + + /** + * Protobuf type {@code IM.Message.IMUnreadMsgCntRsp} + */ + public static final class Builder extends + com.google.protobuf.GeneratedMessageLite.Builder< + com.mogujie.tt.protobuf.IMMessage.IMUnreadMsgCntRsp, Builder> + implements + // @@protoc_insertion_point(builder_implements:IM.Message.IMUnreadMsgCntRsp) + com.mogujie.tt.protobuf.IMMessage.IMUnreadMsgCntRspOrBuilder { + // Construct using com.mogujie.tt.protobuf.IMMessage.IMUnreadMsgCntRsp.newBuilder() + private Builder() { + maybeForceBuilderInitialization(); + } + + private void maybeForceBuilderInitialization() { + } + private static Builder create() { + return new Builder(); + } + + public Builder clear() { + super.clear(); + userId_ = 0; + bitField0_ = (bitField0_ & ~0x00000001); + totalCnt_ = 0; + bitField0_ = (bitField0_ & ~0x00000002); + unreadinfoList_ = java.util.Collections.emptyList(); + bitField0_ = (bitField0_ & ~0x00000004); + attachData_ = com.google.protobuf.ByteString.EMPTY; + bitField0_ = (bitField0_ & ~0x00000008); + return this; + } + + public Builder clone() { + return create().mergeFrom(buildPartial()); + } + + public com.mogujie.tt.protobuf.IMMessage.IMUnreadMsgCntRsp getDefaultInstanceForType() { + return com.mogujie.tt.protobuf.IMMessage.IMUnreadMsgCntRsp.getDefaultInstance(); + } + + public com.mogujie.tt.protobuf.IMMessage.IMUnreadMsgCntRsp build() { + com.mogujie.tt.protobuf.IMMessage.IMUnreadMsgCntRsp result = buildPartial(); + if (!result.isInitialized()) { + throw newUninitializedMessageException(result); + } + return result; + } + + public com.mogujie.tt.protobuf.IMMessage.IMUnreadMsgCntRsp buildPartial() { + com.mogujie.tt.protobuf.IMMessage.IMUnreadMsgCntRsp result = new com.mogujie.tt.protobuf.IMMessage.IMUnreadMsgCntRsp(this); + int from_bitField0_ = bitField0_; + int to_bitField0_ = 0; + if (((from_bitField0_ & 0x00000001) == 0x00000001)) { + to_bitField0_ |= 0x00000001; + } + result.userId_ = userId_; + if (((from_bitField0_ & 0x00000002) == 0x00000002)) { + to_bitField0_ |= 0x00000002; + } + result.totalCnt_ = totalCnt_; + if (((bitField0_ & 0x00000004) == 0x00000004)) { + unreadinfoList_ = java.util.Collections.unmodifiableList(unreadinfoList_); + bitField0_ = (bitField0_ & ~0x00000004); + } + result.unreadinfoList_ = unreadinfoList_; + if (((from_bitField0_ & 0x00000008) == 0x00000008)) { + to_bitField0_ |= 0x00000004; + } + result.attachData_ = attachData_; + result.bitField0_ = to_bitField0_; + return result; + } + + public Builder mergeFrom(com.mogujie.tt.protobuf.IMMessage.IMUnreadMsgCntRsp other) { + if (other == com.mogujie.tt.protobuf.IMMessage.IMUnreadMsgCntRsp.getDefaultInstance()) return this; + if (other.hasUserId()) { + setUserId(other.getUserId()); + } + if (other.hasTotalCnt()) { + setTotalCnt(other.getTotalCnt()); + } + if (!other.unreadinfoList_.isEmpty()) { + if (unreadinfoList_.isEmpty()) { + unreadinfoList_ = other.unreadinfoList_; + bitField0_ = (bitField0_ & ~0x00000004); + } else { + ensureUnreadinfoListIsMutable(); + unreadinfoList_.addAll(other.unreadinfoList_); + } + + } + if (other.hasAttachData()) { + setAttachData(other.getAttachData()); + } + setUnknownFields( + getUnknownFields().concat(other.unknownFields)); + return this; + } + + public final boolean isInitialized() { + if (!hasUserId()) { + + return false; + } + if (!hasTotalCnt()) { + + return false; + } + for (int i = 0; i < getUnreadinfoListCount(); i++) { + if (!getUnreadinfoList(i).isInitialized()) { + + return false; + } + } + return true; + } + + public Builder mergeFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + com.mogujie.tt.protobuf.IMMessage.IMUnreadMsgCntRsp parsedMessage = null; + try { + parsedMessage = PARSER.parsePartialFrom(input, extensionRegistry); + } catch (com.google.protobuf.InvalidProtocolBufferException e) { + parsedMessage = (com.mogujie.tt.protobuf.IMMessage.IMUnreadMsgCntRsp) e.getUnfinishedMessage(); + throw e; + } finally { + if (parsedMessage != null) { + mergeFrom(parsedMessage); + } + } + return this; + } + private int bitField0_; + + private int userId_ ; + /** + * required uint32 user_id = 1; + * + *
+       *cmd id:		0x0308
+       * 
+ */ + public boolean hasUserId() { + return ((bitField0_ & 0x00000001) == 0x00000001); + } + /** + * required uint32 user_id = 1; + * + *
+       *cmd id:		0x0308
+       * 
+ */ + public int getUserId() { + return userId_; + } + /** + * required uint32 user_id = 1; + * + *
+       *cmd id:		0x0308
+       * 
+ */ + public Builder setUserId(int value) { + bitField0_ |= 0x00000001; + userId_ = value; + + return this; + } + /** + * required uint32 user_id = 1; + * + *
+       *cmd id:		0x0308
+       * 
+ */ + public Builder clearUserId() { + bitField0_ = (bitField0_ & ~0x00000001); + userId_ = 0; + + return this; + } + + private int totalCnt_ ; + /** + * required uint32 total_cnt = 2; + */ + public boolean hasTotalCnt() { + return ((bitField0_ & 0x00000002) == 0x00000002); + } + /** + * required uint32 total_cnt = 2; + */ + public int getTotalCnt() { + return totalCnt_; + } + /** + * required uint32 total_cnt = 2; + */ + public Builder setTotalCnt(int value) { + bitField0_ |= 0x00000002; + totalCnt_ = value; + + return this; + } + /** + * required uint32 total_cnt = 2; + */ + public Builder clearTotalCnt() { + bitField0_ = (bitField0_ & ~0x00000002); + totalCnt_ = 0; + + return this; + } + + private java.util.List unreadinfoList_ = + java.util.Collections.emptyList(); + private void ensureUnreadinfoListIsMutable() { + if (!((bitField0_ & 0x00000004) == 0x00000004)) { + unreadinfoList_ = new java.util.ArrayList(unreadinfoList_); + bitField0_ |= 0x00000004; + } + } + + /** + * repeated .IM.BaseDefine.UnreadInfo unreadinfo_list = 3; + */ + public java.util.List getUnreadinfoListList() { + return java.util.Collections.unmodifiableList(unreadinfoList_); + } + /** + * repeated .IM.BaseDefine.UnreadInfo unreadinfo_list = 3; + */ + public int getUnreadinfoListCount() { + return unreadinfoList_.size(); + } + /** + * repeated .IM.BaseDefine.UnreadInfo unreadinfo_list = 3; + */ + public com.mogujie.tt.protobuf.IMBaseDefine.UnreadInfo getUnreadinfoList(int index) { + return unreadinfoList_.get(index); + } + /** + * repeated .IM.BaseDefine.UnreadInfo unreadinfo_list = 3; + */ + public Builder setUnreadinfoList( + int index, com.mogujie.tt.protobuf.IMBaseDefine.UnreadInfo value) { + if (value == null) { + throw new NullPointerException(); + } + ensureUnreadinfoListIsMutable(); + unreadinfoList_.set(index, value); + + return this; + } + /** + * repeated .IM.BaseDefine.UnreadInfo unreadinfo_list = 3; + */ + public Builder setUnreadinfoList( + int index, com.mogujie.tt.protobuf.IMBaseDefine.UnreadInfo.Builder builderForValue) { + ensureUnreadinfoListIsMutable(); + unreadinfoList_.set(index, builderForValue.build()); + + return this; + } + /** + * repeated .IM.BaseDefine.UnreadInfo unreadinfo_list = 3; + */ + public Builder addUnreadinfoList(com.mogujie.tt.protobuf.IMBaseDefine.UnreadInfo value) { + if (value == null) { + throw new NullPointerException(); + } + ensureUnreadinfoListIsMutable(); + unreadinfoList_.add(value); + + return this; + } + /** + * repeated .IM.BaseDefine.UnreadInfo unreadinfo_list = 3; + */ + public Builder addUnreadinfoList( + int index, com.mogujie.tt.protobuf.IMBaseDefine.UnreadInfo value) { + if (value == null) { + throw new NullPointerException(); + } + ensureUnreadinfoListIsMutable(); + unreadinfoList_.add(index, value); + + return this; + } + /** + * repeated .IM.BaseDefine.UnreadInfo unreadinfo_list = 3; + */ + public Builder addUnreadinfoList( + com.mogujie.tt.protobuf.IMBaseDefine.UnreadInfo.Builder builderForValue) { + ensureUnreadinfoListIsMutable(); + unreadinfoList_.add(builderForValue.build()); + + return this; + } + /** + * repeated .IM.BaseDefine.UnreadInfo unreadinfo_list = 3; + */ + public Builder addUnreadinfoList( + int index, com.mogujie.tt.protobuf.IMBaseDefine.UnreadInfo.Builder builderForValue) { + ensureUnreadinfoListIsMutable(); + unreadinfoList_.add(index, builderForValue.build()); + + return this; + } + /** + * repeated .IM.BaseDefine.UnreadInfo unreadinfo_list = 3; + */ + public Builder addAllUnreadinfoList( + java.lang.Iterable values) { + ensureUnreadinfoListIsMutable(); + com.google.protobuf.AbstractMessageLite.Builder.addAll( + values, unreadinfoList_); + + return this; + } + /** + * repeated .IM.BaseDefine.UnreadInfo unreadinfo_list = 3; + */ + public Builder clearUnreadinfoList() { + unreadinfoList_ = java.util.Collections.emptyList(); + bitField0_ = (bitField0_ & ~0x00000004); + + return this; + } + /** + * repeated .IM.BaseDefine.UnreadInfo unreadinfo_list = 3; + */ + public Builder removeUnreadinfoList(int index) { + ensureUnreadinfoListIsMutable(); + unreadinfoList_.remove(index); + + return this; + } + + private com.google.protobuf.ByteString attachData_ = com.google.protobuf.ByteString.EMPTY; + /** + * optional bytes attach_data = 20; + */ + public boolean hasAttachData() { + return ((bitField0_ & 0x00000008) == 0x00000008); + } + /** + * optional bytes attach_data = 20; + */ + public com.google.protobuf.ByteString getAttachData() { + return attachData_; + } + /** + * optional bytes attach_data = 20; + */ + public Builder setAttachData(com.google.protobuf.ByteString value) { + if (value == null) { + throw new NullPointerException(); + } + bitField0_ |= 0x00000008; + attachData_ = value; + + return this; + } + /** + * optional bytes attach_data = 20; + */ + public Builder clearAttachData() { + bitField0_ = (bitField0_ & ~0x00000008); + attachData_ = getDefaultInstance().getAttachData(); + + return this; + } + + // @@protoc_insertion_point(builder_scope:IM.Message.IMUnreadMsgCntRsp) + } + + static { + defaultInstance = new IMUnreadMsgCntRsp(true); + defaultInstance.initFields(); + } + + // @@protoc_insertion_point(class_scope:IM.Message.IMUnreadMsgCntRsp) + } + + public interface IMGetMsgListReqOrBuilder extends + // @@protoc_insertion_point(interface_extends:IM.Message.IMGetMsgListReq) + com.google.protobuf.MessageLiteOrBuilder { + + /** + * required uint32 user_id = 1; + * + *
+     *cmd id:		0x0309
+     * 
+ */ + boolean hasUserId(); + /** + * required uint32 user_id = 1; + * + *
+     *cmd id:		0x0309
+     * 
+ */ + int getUserId(); + + /** + * required .IM.BaseDefine.SessionType session_type = 2; + */ + boolean hasSessionType(); + /** + * required .IM.BaseDefine.SessionType session_type = 2; + */ + com.mogujie.tt.protobuf.IMBaseDefine.SessionType getSessionType(); + + /** + * required uint32 session_id = 3; + */ + boolean hasSessionId(); + /** + * required uint32 session_id = 3; + */ + int getSessionId(); + + /** + * required uint32 msg_id_begin = 4; + */ + boolean hasMsgIdBegin(); + /** + * required uint32 msg_id_begin = 4; + */ + int getMsgIdBegin(); + + /** + * required uint32 msg_cnt = 5; + */ + boolean hasMsgCnt(); + /** + * required uint32 msg_cnt = 5; + */ + int getMsgCnt(); + + /** + * optional bytes attach_data = 20; + */ + boolean hasAttachData(); + /** + * optional bytes attach_data = 20; + */ + com.google.protobuf.ByteString getAttachData(); + } + /** + * Protobuf type {@code IM.Message.IMGetMsgListReq} + */ + public static final class IMGetMsgListReq extends + com.google.protobuf.GeneratedMessageLite implements + // @@protoc_insertion_point(message_implements:IM.Message.IMGetMsgListReq) + IMGetMsgListReqOrBuilder { + // Use IMGetMsgListReq.newBuilder() to construct. + private IMGetMsgListReq(com.google.protobuf.GeneratedMessageLite.Builder builder) { + super(builder); + this.unknownFields = builder.getUnknownFields(); + } + private IMGetMsgListReq(boolean noInit) { this.unknownFields = com.google.protobuf.ByteString.EMPTY;} + + private static final IMGetMsgListReq defaultInstance; + public static IMGetMsgListReq getDefaultInstance() { + return defaultInstance; + } + + public IMGetMsgListReq getDefaultInstanceForType() { + return defaultInstance; + } + + private final com.google.protobuf.ByteString unknownFields; + private IMGetMsgListReq( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + initFields(); + int mutable_bitField0_ = 0; + com.google.protobuf.ByteString.Output unknownFieldsOutput = + com.google.protobuf.ByteString.newOutput(); + com.google.protobuf.CodedOutputStream unknownFieldsCodedOutput = + com.google.protobuf.CodedOutputStream.newInstance( + unknownFieldsOutput); + try { + boolean done = false; + while (!done) { + int tag = input.readTag(); + switch (tag) { + case 0: + done = true; + break; + default: { + if (!parseUnknownField(input, unknownFieldsCodedOutput, + extensionRegistry, tag)) { + done = true; + } + break; + } + case 8: { + bitField0_ |= 0x00000001; + userId_ = input.readUInt32(); + break; + } + case 16: { + int rawValue = input.readEnum(); + com.mogujie.tt.protobuf.IMBaseDefine.SessionType value = com.mogujie.tt.protobuf.IMBaseDefine.SessionType.valueOf(rawValue); + if (value == null) { + unknownFieldsCodedOutput.writeRawVarint32(tag); + unknownFieldsCodedOutput.writeRawVarint32(rawValue); + } else { + bitField0_ |= 0x00000002; + sessionType_ = value; + } + break; + } + case 24: { + bitField0_ |= 0x00000004; + sessionId_ = input.readUInt32(); + break; + } + case 32: { + bitField0_ |= 0x00000008; + msgIdBegin_ = input.readUInt32(); + break; + } + case 40: { + bitField0_ |= 0x00000010; + msgCnt_ = input.readUInt32(); + break; + } + case 162: { + bitField0_ |= 0x00000020; + attachData_ = input.readBytes(); + break; + } + } + } + } catch (com.google.protobuf.InvalidProtocolBufferException e) { + throw e.setUnfinishedMessage(this); + } catch (java.io.IOException e) { + throw new com.google.protobuf.InvalidProtocolBufferException( + e.getMessage()).setUnfinishedMessage(this); + } finally { + try { + unknownFieldsCodedOutput.flush(); + } catch (java.io.IOException e) { + // Should not happen + } finally { + unknownFields = unknownFieldsOutput.toByteString(); + } + makeExtensionsImmutable(); + } + } + public static com.google.protobuf.Parser PARSER = + new com.google.protobuf.AbstractParser() { + public IMGetMsgListReq parsePartialFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return new IMGetMsgListReq(input, extensionRegistry); + } + }; + + @java.lang.Override + public com.google.protobuf.Parser getParserForType() { + return PARSER; + } + + private int bitField0_; + public static final int USER_ID_FIELD_NUMBER = 1; + private int userId_; + /** + * required uint32 user_id = 1; + * + *
+     *cmd id:		0x0309
+     * 
+ */ + public boolean hasUserId() { + return ((bitField0_ & 0x00000001) == 0x00000001); + } + /** + * required uint32 user_id = 1; + * + *
+     *cmd id:		0x0309
+     * 
+ */ + public int getUserId() { + return userId_; + } + + public static final int SESSION_TYPE_FIELD_NUMBER = 2; + private com.mogujie.tt.protobuf.IMBaseDefine.SessionType sessionType_; + /** + * required .IM.BaseDefine.SessionType session_type = 2; + */ + public boolean hasSessionType() { + return ((bitField0_ & 0x00000002) == 0x00000002); + } + /** + * required .IM.BaseDefine.SessionType session_type = 2; + */ + public com.mogujie.tt.protobuf.IMBaseDefine.SessionType getSessionType() { + return sessionType_; + } + + public static final int SESSION_ID_FIELD_NUMBER = 3; + private int sessionId_; + /** + * required uint32 session_id = 3; + */ + public boolean hasSessionId() { + return ((bitField0_ & 0x00000004) == 0x00000004); + } + /** + * required uint32 session_id = 3; + */ + public int getSessionId() { + return sessionId_; + } + + public static final int MSG_ID_BEGIN_FIELD_NUMBER = 4; + private int msgIdBegin_; + /** + * required uint32 msg_id_begin = 4; + */ + public boolean hasMsgIdBegin() { + return ((bitField0_ & 0x00000008) == 0x00000008); + } + /** + * required uint32 msg_id_begin = 4; + */ + public int getMsgIdBegin() { + return msgIdBegin_; + } + + public static final int MSG_CNT_FIELD_NUMBER = 5; + private int msgCnt_; + /** + * required uint32 msg_cnt = 5; + */ + public boolean hasMsgCnt() { + return ((bitField0_ & 0x00000010) == 0x00000010); + } + /** + * required uint32 msg_cnt = 5; + */ + public int getMsgCnt() { + return msgCnt_; + } + + public static final int ATTACH_DATA_FIELD_NUMBER = 20; + private com.google.protobuf.ByteString attachData_; + /** + * optional bytes attach_data = 20; + */ + public boolean hasAttachData() { + return ((bitField0_ & 0x00000020) == 0x00000020); + } + /** + * optional bytes attach_data = 20; + */ + public com.google.protobuf.ByteString getAttachData() { + return attachData_; + } + + private void initFields() { + userId_ = 0; + sessionType_ = com.mogujie.tt.protobuf.IMBaseDefine.SessionType.SESSION_TYPE_SINGLE; + sessionId_ = 0; + msgIdBegin_ = 0; + msgCnt_ = 0; + attachData_ = com.google.protobuf.ByteString.EMPTY; + } + private byte memoizedIsInitialized = -1; + public final boolean isInitialized() { + byte isInitialized = memoizedIsInitialized; + if (isInitialized == 1) return true; + if (isInitialized == 0) return false; + + if (!hasUserId()) { + memoizedIsInitialized = 0; + return false; + } + if (!hasSessionType()) { + memoizedIsInitialized = 0; + return false; + } + if (!hasSessionId()) { + memoizedIsInitialized = 0; + return false; + } + if (!hasMsgIdBegin()) { + memoizedIsInitialized = 0; + return false; + } + if (!hasMsgCnt()) { + memoizedIsInitialized = 0; + return false; + } + memoizedIsInitialized = 1; + return true; + } + + public void writeTo(com.google.protobuf.CodedOutputStream output) + throws java.io.IOException { + getSerializedSize(); + if (((bitField0_ & 0x00000001) == 0x00000001)) { + output.writeUInt32(1, userId_); + } + if (((bitField0_ & 0x00000002) == 0x00000002)) { + output.writeEnum(2, sessionType_.getNumber()); + } + if (((bitField0_ & 0x00000004) == 0x00000004)) { + output.writeUInt32(3, sessionId_); + } + if (((bitField0_ & 0x00000008) == 0x00000008)) { + output.writeUInt32(4, msgIdBegin_); + } + if (((bitField0_ & 0x00000010) == 0x00000010)) { + output.writeUInt32(5, msgCnt_); + } + if (((bitField0_ & 0x00000020) == 0x00000020)) { + output.writeBytes(20, attachData_); + } + output.writeRawBytes(unknownFields); + } + + private int memoizedSerializedSize = -1; + public int getSerializedSize() { + int size = memoizedSerializedSize; + if (size != -1) return size; + + size = 0; + if (((bitField0_ & 0x00000001) == 0x00000001)) { + size += com.google.protobuf.CodedOutputStream + .computeUInt32Size(1, userId_); + } + if (((bitField0_ & 0x00000002) == 0x00000002)) { + size += com.google.protobuf.CodedOutputStream + .computeEnumSize(2, sessionType_.getNumber()); + } + if (((bitField0_ & 0x00000004) == 0x00000004)) { + size += com.google.protobuf.CodedOutputStream + .computeUInt32Size(3, sessionId_); + } + if (((bitField0_ & 0x00000008) == 0x00000008)) { + size += com.google.protobuf.CodedOutputStream + .computeUInt32Size(4, msgIdBegin_); + } + if (((bitField0_ & 0x00000010) == 0x00000010)) { + size += com.google.protobuf.CodedOutputStream + .computeUInt32Size(5, msgCnt_); + } + if (((bitField0_ & 0x00000020) == 0x00000020)) { + size += com.google.protobuf.CodedOutputStream + .computeBytesSize(20, attachData_); + } + size += unknownFields.size(); + memoizedSerializedSize = size; + return size; + } + + private static final long serialVersionUID = 0L; + @java.lang.Override + protected java.lang.Object writeReplace() + throws java.io.ObjectStreamException { + return super.writeReplace(); + } + + public static com.mogujie.tt.protobuf.IMMessage.IMGetMsgListReq parseFrom( + com.google.protobuf.ByteString data) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data); + } + public static com.mogujie.tt.protobuf.IMMessage.IMGetMsgListReq parseFrom( + com.google.protobuf.ByteString data, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data, extensionRegistry); + } + public static com.mogujie.tt.protobuf.IMMessage.IMGetMsgListReq parseFrom(byte[] data) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data); + } + public static com.mogujie.tt.protobuf.IMMessage.IMGetMsgListReq parseFrom( + byte[] data, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data, extensionRegistry); + } + public static com.mogujie.tt.protobuf.IMMessage.IMGetMsgListReq parseFrom(java.io.InputStream input) + throws java.io.IOException { + return PARSER.parseFrom(input); + } + public static com.mogujie.tt.protobuf.IMMessage.IMGetMsgListReq parseFrom( + java.io.InputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return PARSER.parseFrom(input, extensionRegistry); + } + public static com.mogujie.tt.protobuf.IMMessage.IMGetMsgListReq parseDelimitedFrom(java.io.InputStream input) + throws java.io.IOException { + return PARSER.parseDelimitedFrom(input); + } + public static com.mogujie.tt.protobuf.IMMessage.IMGetMsgListReq parseDelimitedFrom( + java.io.InputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return PARSER.parseDelimitedFrom(input, extensionRegistry); + } + public static com.mogujie.tt.protobuf.IMMessage.IMGetMsgListReq parseFrom( + com.google.protobuf.CodedInputStream input) + throws java.io.IOException { + return PARSER.parseFrom(input); + } + public static com.mogujie.tt.protobuf.IMMessage.IMGetMsgListReq parseFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return PARSER.parseFrom(input, extensionRegistry); + } + + public static Builder newBuilder() { return Builder.create(); } + public Builder newBuilderForType() { return newBuilder(); } + public static Builder newBuilder(com.mogujie.tt.protobuf.IMMessage.IMGetMsgListReq prototype) { + return newBuilder().mergeFrom(prototype); + } + public Builder toBuilder() { return newBuilder(this); } + + /** + * Protobuf type {@code IM.Message.IMGetMsgListReq} + */ + public static final class Builder extends + com.google.protobuf.GeneratedMessageLite.Builder< + com.mogujie.tt.protobuf.IMMessage.IMGetMsgListReq, Builder> + implements + // @@protoc_insertion_point(builder_implements:IM.Message.IMGetMsgListReq) + com.mogujie.tt.protobuf.IMMessage.IMGetMsgListReqOrBuilder { + // Construct using com.mogujie.tt.protobuf.IMMessage.IMGetMsgListReq.newBuilder() + private Builder() { + maybeForceBuilderInitialization(); + } + + private void maybeForceBuilderInitialization() { + } + private static Builder create() { + return new Builder(); + } + + public Builder clear() { + super.clear(); + userId_ = 0; + bitField0_ = (bitField0_ & ~0x00000001); + sessionType_ = com.mogujie.tt.protobuf.IMBaseDefine.SessionType.SESSION_TYPE_SINGLE; + bitField0_ = (bitField0_ & ~0x00000002); + sessionId_ = 0; + bitField0_ = (bitField0_ & ~0x00000004); + msgIdBegin_ = 0; + bitField0_ = (bitField0_ & ~0x00000008); + msgCnt_ = 0; + bitField0_ = (bitField0_ & ~0x00000010); + attachData_ = com.google.protobuf.ByteString.EMPTY; + bitField0_ = (bitField0_ & ~0x00000020); + return this; + } + + public Builder clone() { + return create().mergeFrom(buildPartial()); + } + + public com.mogujie.tt.protobuf.IMMessage.IMGetMsgListReq getDefaultInstanceForType() { + return com.mogujie.tt.protobuf.IMMessage.IMGetMsgListReq.getDefaultInstance(); + } + + public com.mogujie.tt.protobuf.IMMessage.IMGetMsgListReq build() { + com.mogujie.tt.protobuf.IMMessage.IMGetMsgListReq result = buildPartial(); + if (!result.isInitialized()) { + throw newUninitializedMessageException(result); + } + return result; + } + + public com.mogujie.tt.protobuf.IMMessage.IMGetMsgListReq buildPartial() { + com.mogujie.tt.protobuf.IMMessage.IMGetMsgListReq result = new com.mogujie.tt.protobuf.IMMessage.IMGetMsgListReq(this); + int from_bitField0_ = bitField0_; + int to_bitField0_ = 0; + if (((from_bitField0_ & 0x00000001) == 0x00000001)) { + to_bitField0_ |= 0x00000001; + } + result.userId_ = userId_; + if (((from_bitField0_ & 0x00000002) == 0x00000002)) { + to_bitField0_ |= 0x00000002; + } + result.sessionType_ = sessionType_; + if (((from_bitField0_ & 0x00000004) == 0x00000004)) { + to_bitField0_ |= 0x00000004; + } + result.sessionId_ = sessionId_; + if (((from_bitField0_ & 0x00000008) == 0x00000008)) { + to_bitField0_ |= 0x00000008; + } + result.msgIdBegin_ = msgIdBegin_; + if (((from_bitField0_ & 0x00000010) == 0x00000010)) { + to_bitField0_ |= 0x00000010; + } + result.msgCnt_ = msgCnt_; + if (((from_bitField0_ & 0x00000020) == 0x00000020)) { + to_bitField0_ |= 0x00000020; + } + result.attachData_ = attachData_; + result.bitField0_ = to_bitField0_; + return result; + } + + public Builder mergeFrom(com.mogujie.tt.protobuf.IMMessage.IMGetMsgListReq other) { + if (other == com.mogujie.tt.protobuf.IMMessage.IMGetMsgListReq.getDefaultInstance()) return this; + if (other.hasUserId()) { + setUserId(other.getUserId()); + } + if (other.hasSessionType()) { + setSessionType(other.getSessionType()); + } + if (other.hasSessionId()) { + setSessionId(other.getSessionId()); + } + if (other.hasMsgIdBegin()) { + setMsgIdBegin(other.getMsgIdBegin()); + } + if (other.hasMsgCnt()) { + setMsgCnt(other.getMsgCnt()); + } + if (other.hasAttachData()) { + setAttachData(other.getAttachData()); + } + setUnknownFields( + getUnknownFields().concat(other.unknownFields)); + return this; + } + + public final boolean isInitialized() { + if (!hasUserId()) { + + return false; + } + if (!hasSessionType()) { + + return false; + } + if (!hasSessionId()) { + + return false; + } + if (!hasMsgIdBegin()) { + + return false; + } + if (!hasMsgCnt()) { + + return false; + } + return true; + } + + public Builder mergeFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + com.mogujie.tt.protobuf.IMMessage.IMGetMsgListReq parsedMessage = null; + try { + parsedMessage = PARSER.parsePartialFrom(input, extensionRegistry); + } catch (com.google.protobuf.InvalidProtocolBufferException e) { + parsedMessage = (com.mogujie.tt.protobuf.IMMessage.IMGetMsgListReq) e.getUnfinishedMessage(); + throw e; + } finally { + if (parsedMessage != null) { + mergeFrom(parsedMessage); + } + } + return this; + } + private int bitField0_; + + private int userId_ ; + /** + * required uint32 user_id = 1; + * + *
+       *cmd id:		0x0309
+       * 
+ */ + public boolean hasUserId() { + return ((bitField0_ & 0x00000001) == 0x00000001); + } + /** + * required uint32 user_id = 1; + * + *
+       *cmd id:		0x0309
+       * 
+ */ + public int getUserId() { + return userId_; + } + /** + * required uint32 user_id = 1; + * + *
+       *cmd id:		0x0309
+       * 
+ */ + public Builder setUserId(int value) { + bitField0_ |= 0x00000001; + userId_ = value; + + return this; + } + /** + * required uint32 user_id = 1; + * + *
+       *cmd id:		0x0309
+       * 
+ */ + public Builder clearUserId() { + bitField0_ = (bitField0_ & ~0x00000001); + userId_ = 0; + + return this; + } + + private com.mogujie.tt.protobuf.IMBaseDefine.SessionType sessionType_ = com.mogujie.tt.protobuf.IMBaseDefine.SessionType.SESSION_TYPE_SINGLE; + /** + * required .IM.BaseDefine.SessionType session_type = 2; + */ + public boolean hasSessionType() { + return ((bitField0_ & 0x00000002) == 0x00000002); + } + /** + * required .IM.BaseDefine.SessionType session_type = 2; + */ + public com.mogujie.tt.protobuf.IMBaseDefine.SessionType getSessionType() { + return sessionType_; + } + /** + * required .IM.BaseDefine.SessionType session_type = 2; + */ + public Builder setSessionType(com.mogujie.tt.protobuf.IMBaseDefine.SessionType value) { + if (value == null) { + throw new NullPointerException(); + } + bitField0_ |= 0x00000002; + sessionType_ = value; + + return this; + } + /** + * required .IM.BaseDefine.SessionType session_type = 2; + */ + public Builder clearSessionType() { + bitField0_ = (bitField0_ & ~0x00000002); + sessionType_ = com.mogujie.tt.protobuf.IMBaseDefine.SessionType.SESSION_TYPE_SINGLE; + + return this; + } + + private int sessionId_ ; + /** + * required uint32 session_id = 3; + */ + public boolean hasSessionId() { + return ((bitField0_ & 0x00000004) == 0x00000004); + } + /** + * required uint32 session_id = 3; + */ + public int getSessionId() { + return sessionId_; + } + /** + * required uint32 session_id = 3; + */ + public Builder setSessionId(int value) { + bitField0_ |= 0x00000004; + sessionId_ = value; + + return this; + } + /** + * required uint32 session_id = 3; + */ + public Builder clearSessionId() { + bitField0_ = (bitField0_ & ~0x00000004); + sessionId_ = 0; + + return this; + } + + private int msgIdBegin_ ; + /** + * required uint32 msg_id_begin = 4; + */ + public boolean hasMsgIdBegin() { + return ((bitField0_ & 0x00000008) == 0x00000008); + } + /** + * required uint32 msg_id_begin = 4; + */ + public int getMsgIdBegin() { + return msgIdBegin_; + } + /** + * required uint32 msg_id_begin = 4; + */ + public Builder setMsgIdBegin(int value) { + bitField0_ |= 0x00000008; + msgIdBegin_ = value; + + return this; + } + /** + * required uint32 msg_id_begin = 4; + */ + public Builder clearMsgIdBegin() { + bitField0_ = (bitField0_ & ~0x00000008); + msgIdBegin_ = 0; + + return this; + } + + private int msgCnt_ ; + /** + * required uint32 msg_cnt = 5; + */ + public boolean hasMsgCnt() { + return ((bitField0_ & 0x00000010) == 0x00000010); + } + /** + * required uint32 msg_cnt = 5; + */ + public int getMsgCnt() { + return msgCnt_; + } + /** + * required uint32 msg_cnt = 5; + */ + public Builder setMsgCnt(int value) { + bitField0_ |= 0x00000010; + msgCnt_ = value; + + return this; + } + /** + * required uint32 msg_cnt = 5; + */ + public Builder clearMsgCnt() { + bitField0_ = (bitField0_ & ~0x00000010); + msgCnt_ = 0; + + return this; + } + + private com.google.protobuf.ByteString attachData_ = com.google.protobuf.ByteString.EMPTY; + /** + * optional bytes attach_data = 20; + */ + public boolean hasAttachData() { + return ((bitField0_ & 0x00000020) == 0x00000020); + } + /** + * optional bytes attach_data = 20; + */ + public com.google.protobuf.ByteString getAttachData() { + return attachData_; + } + /** + * optional bytes attach_data = 20; + */ + public Builder setAttachData(com.google.protobuf.ByteString value) { + if (value == null) { + throw new NullPointerException(); + } + bitField0_ |= 0x00000020; + attachData_ = value; + + return this; + } + /** + * optional bytes attach_data = 20; + */ + public Builder clearAttachData() { + bitField0_ = (bitField0_ & ~0x00000020); + attachData_ = getDefaultInstance().getAttachData(); + + return this; + } + + // @@protoc_insertion_point(builder_scope:IM.Message.IMGetMsgListReq) + } + + static { + defaultInstance = new IMGetMsgListReq(true); + defaultInstance.initFields(); + } + + // @@protoc_insertion_point(class_scope:IM.Message.IMGetMsgListReq) + } + + public interface IMGetMsgListRspOrBuilder extends + // @@protoc_insertion_point(interface_extends:IM.Message.IMGetMsgListRsp) + com.google.protobuf.MessageLiteOrBuilder { + + /** + * required uint32 user_id = 1; + * + *
+     *cmd id:		0x030a
+     * 
+ */ + boolean hasUserId(); + /** + * required uint32 user_id = 1; + * + *
+     *cmd id:		0x030a
+     * 
+ */ + int getUserId(); + + /** + * required .IM.BaseDefine.SessionType session_type = 2; + */ + boolean hasSessionType(); + /** + * required .IM.BaseDefine.SessionType session_type = 2; + */ + com.mogujie.tt.protobuf.IMBaseDefine.SessionType getSessionType(); + + /** + * required uint32 session_id = 3; + */ + boolean hasSessionId(); + /** + * required uint32 session_id = 3; + */ + int getSessionId(); + + /** + * required uint32 msg_id_begin = 4; + */ + boolean hasMsgIdBegin(); + /** + * required uint32 msg_id_begin = 4; + */ + int getMsgIdBegin(); + + /** + * repeated .IM.BaseDefine.MsgInfo msg_list = 5; + */ + java.util.List + getMsgListList(); + /** + * repeated .IM.BaseDefine.MsgInfo msg_list = 5; + */ + com.mogujie.tt.protobuf.IMBaseDefine.MsgInfo getMsgList(int index); + /** + * repeated .IM.BaseDefine.MsgInfo msg_list = 5; + */ + int getMsgListCount(); + + /** + * optional bytes attach_data = 20; + */ + boolean hasAttachData(); + /** + * optional bytes attach_data = 20; + */ + com.google.protobuf.ByteString getAttachData(); + } + /** + * Protobuf type {@code IM.Message.IMGetMsgListRsp} + * + *
+   *对于群而言,如果消息数目返回的数值小于请求的cnt,则表示群的消息能拉取的到头了,更早的消息没有权限拉取。
+   *如果msg_cnt 和 msg_id_begin计算得到的最早消息id与实际返回的最早消息id不一致,说明服务器消息有缺失,需要
+   *客户端做一个缺失标记,避免下次再次拉取。
+   * 
+ */ + public static final class IMGetMsgListRsp extends + com.google.protobuf.GeneratedMessageLite implements + // @@protoc_insertion_point(message_implements:IM.Message.IMGetMsgListRsp) + IMGetMsgListRspOrBuilder { + // Use IMGetMsgListRsp.newBuilder() to construct. + private IMGetMsgListRsp(com.google.protobuf.GeneratedMessageLite.Builder builder) { + super(builder); + this.unknownFields = builder.getUnknownFields(); + } + private IMGetMsgListRsp(boolean noInit) { this.unknownFields = com.google.protobuf.ByteString.EMPTY;} + + private static final IMGetMsgListRsp defaultInstance; + public static IMGetMsgListRsp getDefaultInstance() { + return defaultInstance; + } + + public IMGetMsgListRsp getDefaultInstanceForType() { + return defaultInstance; + } + + private final com.google.protobuf.ByteString unknownFields; + private IMGetMsgListRsp( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + initFields(); + int mutable_bitField0_ = 0; + com.google.protobuf.ByteString.Output unknownFieldsOutput = + com.google.protobuf.ByteString.newOutput(); + com.google.protobuf.CodedOutputStream unknownFieldsCodedOutput = + com.google.protobuf.CodedOutputStream.newInstance( + unknownFieldsOutput); + try { + boolean done = false; + while (!done) { + int tag = input.readTag(); + switch (tag) { + case 0: + done = true; + break; + default: { + if (!parseUnknownField(input, unknownFieldsCodedOutput, + extensionRegistry, tag)) { + done = true; + } + break; + } + case 8: { + bitField0_ |= 0x00000001; + userId_ = input.readUInt32(); + break; + } + case 16: { + int rawValue = input.readEnum(); + com.mogujie.tt.protobuf.IMBaseDefine.SessionType value = com.mogujie.tt.protobuf.IMBaseDefine.SessionType.valueOf(rawValue); + if (value == null) { + unknownFieldsCodedOutput.writeRawVarint32(tag); + unknownFieldsCodedOutput.writeRawVarint32(rawValue); + } else { + bitField0_ |= 0x00000002; + sessionType_ = value; + } + break; + } + case 24: { + bitField0_ |= 0x00000004; + sessionId_ = input.readUInt32(); + break; + } + case 32: { + bitField0_ |= 0x00000008; + msgIdBegin_ = input.readUInt32(); + break; + } + case 42: { + if (!((mutable_bitField0_ & 0x00000010) == 0x00000010)) { + msgList_ = new java.util.ArrayList(); + mutable_bitField0_ |= 0x00000010; + } + msgList_.add(input.readMessage(com.mogujie.tt.protobuf.IMBaseDefine.MsgInfo.PARSER, extensionRegistry)); + break; + } + case 162: { + bitField0_ |= 0x00000010; + attachData_ = input.readBytes(); + break; + } + } + } + } catch (com.google.protobuf.InvalidProtocolBufferException e) { + throw e.setUnfinishedMessage(this); + } catch (java.io.IOException e) { + throw new com.google.protobuf.InvalidProtocolBufferException( + e.getMessage()).setUnfinishedMessage(this); + } finally { + if (((mutable_bitField0_ & 0x00000010) == 0x00000010)) { + msgList_ = java.util.Collections.unmodifiableList(msgList_); + } + try { + unknownFieldsCodedOutput.flush(); + } catch (java.io.IOException e) { + // Should not happen + } finally { + unknownFields = unknownFieldsOutput.toByteString(); + } + makeExtensionsImmutable(); + } + } + public static com.google.protobuf.Parser PARSER = + new com.google.protobuf.AbstractParser() { + public IMGetMsgListRsp parsePartialFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return new IMGetMsgListRsp(input, extensionRegistry); + } + }; + + @java.lang.Override + public com.google.protobuf.Parser getParserForType() { + return PARSER; + } + + private int bitField0_; + public static final int USER_ID_FIELD_NUMBER = 1; + private int userId_; + /** + * required uint32 user_id = 1; + * + *
+     *cmd id:		0x030a
+     * 
+ */ + public boolean hasUserId() { + return ((bitField0_ & 0x00000001) == 0x00000001); + } + /** + * required uint32 user_id = 1; + * + *
+     *cmd id:		0x030a
+     * 
+ */ + public int getUserId() { + return userId_; + } + + public static final int SESSION_TYPE_FIELD_NUMBER = 2; + private com.mogujie.tt.protobuf.IMBaseDefine.SessionType sessionType_; + /** + * required .IM.BaseDefine.SessionType session_type = 2; + */ + public boolean hasSessionType() { + return ((bitField0_ & 0x00000002) == 0x00000002); + } + /** + * required .IM.BaseDefine.SessionType session_type = 2; + */ + public com.mogujie.tt.protobuf.IMBaseDefine.SessionType getSessionType() { + return sessionType_; + } + + public static final int SESSION_ID_FIELD_NUMBER = 3; + private int sessionId_; + /** + * required uint32 session_id = 3; + */ + public boolean hasSessionId() { + return ((bitField0_ & 0x00000004) == 0x00000004); + } + /** + * required uint32 session_id = 3; + */ + public int getSessionId() { + return sessionId_; + } + + public static final int MSG_ID_BEGIN_FIELD_NUMBER = 4; + private int msgIdBegin_; + /** + * required uint32 msg_id_begin = 4; + */ + public boolean hasMsgIdBegin() { + return ((bitField0_ & 0x00000008) == 0x00000008); + } + /** + * required uint32 msg_id_begin = 4; + */ + public int getMsgIdBegin() { + return msgIdBegin_; + } + + public static final int MSG_LIST_FIELD_NUMBER = 5; + private java.util.List msgList_; + /** + * repeated .IM.BaseDefine.MsgInfo msg_list = 5; + */ + public java.util.List getMsgListList() { + return msgList_; + } + /** + * repeated .IM.BaseDefine.MsgInfo msg_list = 5; + */ + public java.util.List + getMsgListOrBuilderList() { + return msgList_; + } + /** + * repeated .IM.BaseDefine.MsgInfo msg_list = 5; + */ + public int getMsgListCount() { + return msgList_.size(); + } + /** + * repeated .IM.BaseDefine.MsgInfo msg_list = 5; + */ + public com.mogujie.tt.protobuf.IMBaseDefine.MsgInfo getMsgList(int index) { + return msgList_.get(index); + } + /** + * repeated .IM.BaseDefine.MsgInfo msg_list = 5; + */ + public com.mogujie.tt.protobuf.IMBaseDefine.MsgInfoOrBuilder getMsgListOrBuilder( + int index) { + return msgList_.get(index); + } + + public static final int ATTACH_DATA_FIELD_NUMBER = 20; + private com.google.protobuf.ByteString attachData_; + /** + * optional bytes attach_data = 20; + */ + public boolean hasAttachData() { + return ((bitField0_ & 0x00000010) == 0x00000010); + } + /** + * optional bytes attach_data = 20; + */ + public com.google.protobuf.ByteString getAttachData() { + return attachData_; + } + + private void initFields() { + userId_ = 0; + sessionType_ = com.mogujie.tt.protobuf.IMBaseDefine.SessionType.SESSION_TYPE_SINGLE; + sessionId_ = 0; + msgIdBegin_ = 0; + msgList_ = java.util.Collections.emptyList(); + attachData_ = com.google.protobuf.ByteString.EMPTY; + } + private byte memoizedIsInitialized = -1; + public final boolean isInitialized() { + byte isInitialized = memoizedIsInitialized; + if (isInitialized == 1) return true; + if (isInitialized == 0) return false; + + if (!hasUserId()) { + memoizedIsInitialized = 0; + return false; + } + if (!hasSessionType()) { + memoizedIsInitialized = 0; + return false; + } + if (!hasSessionId()) { + memoizedIsInitialized = 0; + return false; + } + if (!hasMsgIdBegin()) { + memoizedIsInitialized = 0; + return false; + } + for (int i = 0; i < getMsgListCount(); i++) { + if (!getMsgList(i).isInitialized()) { + memoizedIsInitialized = 0; + return false; + } + } + memoizedIsInitialized = 1; + return true; + } + + public void writeTo(com.google.protobuf.CodedOutputStream output) + throws java.io.IOException { + getSerializedSize(); + if (((bitField0_ & 0x00000001) == 0x00000001)) { + output.writeUInt32(1, userId_); + } + if (((bitField0_ & 0x00000002) == 0x00000002)) { + output.writeEnum(2, sessionType_.getNumber()); + } + if (((bitField0_ & 0x00000004) == 0x00000004)) { + output.writeUInt32(3, sessionId_); + } + if (((bitField0_ & 0x00000008) == 0x00000008)) { + output.writeUInt32(4, msgIdBegin_); + } + for (int i = 0; i < msgList_.size(); i++) { + output.writeMessage(5, msgList_.get(i)); + } + if (((bitField0_ & 0x00000010) == 0x00000010)) { + output.writeBytes(20, attachData_); + } + output.writeRawBytes(unknownFields); + } + + private int memoizedSerializedSize = -1; + public int getSerializedSize() { + int size = memoizedSerializedSize; + if (size != -1) return size; + + size = 0; + if (((bitField0_ & 0x00000001) == 0x00000001)) { + size += com.google.protobuf.CodedOutputStream + .computeUInt32Size(1, userId_); + } + if (((bitField0_ & 0x00000002) == 0x00000002)) { + size += com.google.protobuf.CodedOutputStream + .computeEnumSize(2, sessionType_.getNumber()); + } + if (((bitField0_ & 0x00000004) == 0x00000004)) { + size += com.google.protobuf.CodedOutputStream + .computeUInt32Size(3, sessionId_); + } + if (((bitField0_ & 0x00000008) == 0x00000008)) { + size += com.google.protobuf.CodedOutputStream + .computeUInt32Size(4, msgIdBegin_); + } + for (int i = 0; i < msgList_.size(); i++) { + size += com.google.protobuf.CodedOutputStream + .computeMessageSize(5, msgList_.get(i)); + } + if (((bitField0_ & 0x00000010) == 0x00000010)) { + size += com.google.protobuf.CodedOutputStream + .computeBytesSize(20, attachData_); + } + size += unknownFields.size(); + memoizedSerializedSize = size; + return size; + } + + private static final long serialVersionUID = 0L; + @java.lang.Override + protected java.lang.Object writeReplace() + throws java.io.ObjectStreamException { + return super.writeReplace(); + } + + public static com.mogujie.tt.protobuf.IMMessage.IMGetMsgListRsp parseFrom( + com.google.protobuf.ByteString data) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data); + } + public static com.mogujie.tt.protobuf.IMMessage.IMGetMsgListRsp parseFrom( + com.google.protobuf.ByteString data, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data, extensionRegistry); + } + public static com.mogujie.tt.protobuf.IMMessage.IMGetMsgListRsp parseFrom(byte[] data) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data); + } + public static com.mogujie.tt.protobuf.IMMessage.IMGetMsgListRsp parseFrom( + byte[] data, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data, extensionRegistry); + } + public static com.mogujie.tt.protobuf.IMMessage.IMGetMsgListRsp parseFrom(java.io.InputStream input) + throws java.io.IOException { + return PARSER.parseFrom(input); + } + public static com.mogujie.tt.protobuf.IMMessage.IMGetMsgListRsp parseFrom( + java.io.InputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return PARSER.parseFrom(input, extensionRegistry); + } + public static com.mogujie.tt.protobuf.IMMessage.IMGetMsgListRsp parseDelimitedFrom(java.io.InputStream input) + throws java.io.IOException { + return PARSER.parseDelimitedFrom(input); + } + public static com.mogujie.tt.protobuf.IMMessage.IMGetMsgListRsp parseDelimitedFrom( + java.io.InputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return PARSER.parseDelimitedFrom(input, extensionRegistry); + } + public static com.mogujie.tt.protobuf.IMMessage.IMGetMsgListRsp parseFrom( + com.google.protobuf.CodedInputStream input) + throws java.io.IOException { + return PARSER.parseFrom(input); + } + public static com.mogujie.tt.protobuf.IMMessage.IMGetMsgListRsp parseFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return PARSER.parseFrom(input, extensionRegistry); + } + + public static Builder newBuilder() { return Builder.create(); } + public Builder newBuilderForType() { return newBuilder(); } + public static Builder newBuilder(com.mogujie.tt.protobuf.IMMessage.IMGetMsgListRsp prototype) { + return newBuilder().mergeFrom(prototype); + } + public Builder toBuilder() { return newBuilder(this); } + + /** + * Protobuf type {@code IM.Message.IMGetMsgListRsp} + * + *
+     *对于群而言,如果消息数目返回的数值小于请求的cnt,则表示群的消息能拉取的到头了,更早的消息没有权限拉取。
+     *如果msg_cnt 和 msg_id_begin计算得到的最早消息id与实际返回的最早消息id不一致,说明服务器消息有缺失,需要
+     *客户端做一个缺失标记,避免下次再次拉取。
+     * 
+ */ + public static final class Builder extends + com.google.protobuf.GeneratedMessageLite.Builder< + com.mogujie.tt.protobuf.IMMessage.IMGetMsgListRsp, Builder> + implements + // @@protoc_insertion_point(builder_implements:IM.Message.IMGetMsgListRsp) + com.mogujie.tt.protobuf.IMMessage.IMGetMsgListRspOrBuilder { + // Construct using com.mogujie.tt.protobuf.IMMessage.IMGetMsgListRsp.newBuilder() + private Builder() { + maybeForceBuilderInitialization(); + } + + private void maybeForceBuilderInitialization() { + } + private static Builder create() { + return new Builder(); + } + + public Builder clear() { + super.clear(); + userId_ = 0; + bitField0_ = (bitField0_ & ~0x00000001); + sessionType_ = com.mogujie.tt.protobuf.IMBaseDefine.SessionType.SESSION_TYPE_SINGLE; + bitField0_ = (bitField0_ & ~0x00000002); + sessionId_ = 0; + bitField0_ = (bitField0_ & ~0x00000004); + msgIdBegin_ = 0; + bitField0_ = (bitField0_ & ~0x00000008); + msgList_ = java.util.Collections.emptyList(); + bitField0_ = (bitField0_ & ~0x00000010); + attachData_ = com.google.protobuf.ByteString.EMPTY; + bitField0_ = (bitField0_ & ~0x00000020); + return this; + } + + public Builder clone() { + return create().mergeFrom(buildPartial()); + } + + public com.mogujie.tt.protobuf.IMMessage.IMGetMsgListRsp getDefaultInstanceForType() { + return com.mogujie.tt.protobuf.IMMessage.IMGetMsgListRsp.getDefaultInstance(); + } + + public com.mogujie.tt.protobuf.IMMessage.IMGetMsgListRsp build() { + com.mogujie.tt.protobuf.IMMessage.IMGetMsgListRsp result = buildPartial(); + if (!result.isInitialized()) { + throw newUninitializedMessageException(result); + } + return result; + } + + public com.mogujie.tt.protobuf.IMMessage.IMGetMsgListRsp buildPartial() { + com.mogujie.tt.protobuf.IMMessage.IMGetMsgListRsp result = new com.mogujie.tt.protobuf.IMMessage.IMGetMsgListRsp(this); + int from_bitField0_ = bitField0_; + int to_bitField0_ = 0; + if (((from_bitField0_ & 0x00000001) == 0x00000001)) { + to_bitField0_ |= 0x00000001; + } + result.userId_ = userId_; + if (((from_bitField0_ & 0x00000002) == 0x00000002)) { + to_bitField0_ |= 0x00000002; + } + result.sessionType_ = sessionType_; + if (((from_bitField0_ & 0x00000004) == 0x00000004)) { + to_bitField0_ |= 0x00000004; + } + result.sessionId_ = sessionId_; + if (((from_bitField0_ & 0x00000008) == 0x00000008)) { + to_bitField0_ |= 0x00000008; + } + result.msgIdBegin_ = msgIdBegin_; + if (((bitField0_ & 0x00000010) == 0x00000010)) { + msgList_ = java.util.Collections.unmodifiableList(msgList_); + bitField0_ = (bitField0_ & ~0x00000010); + } + result.msgList_ = msgList_; + if (((from_bitField0_ & 0x00000020) == 0x00000020)) { + to_bitField0_ |= 0x00000010; + } + result.attachData_ = attachData_; + result.bitField0_ = to_bitField0_; + return result; + } + + public Builder mergeFrom(com.mogujie.tt.protobuf.IMMessage.IMGetMsgListRsp other) { + if (other == com.mogujie.tt.protobuf.IMMessage.IMGetMsgListRsp.getDefaultInstance()) return this; + if (other.hasUserId()) { + setUserId(other.getUserId()); + } + if (other.hasSessionType()) { + setSessionType(other.getSessionType()); + } + if (other.hasSessionId()) { + setSessionId(other.getSessionId()); + } + if (other.hasMsgIdBegin()) { + setMsgIdBegin(other.getMsgIdBegin()); + } + if (!other.msgList_.isEmpty()) { + if (msgList_.isEmpty()) { + msgList_ = other.msgList_; + bitField0_ = (bitField0_ & ~0x00000010); + } else { + ensureMsgListIsMutable(); + msgList_.addAll(other.msgList_); + } + + } + if (other.hasAttachData()) { + setAttachData(other.getAttachData()); + } + setUnknownFields( + getUnknownFields().concat(other.unknownFields)); + return this; + } + + public final boolean isInitialized() { + if (!hasUserId()) { + + return false; + } + if (!hasSessionType()) { + + return false; + } + if (!hasSessionId()) { + + return false; + } + if (!hasMsgIdBegin()) { + + return false; + } + for (int i = 0; i < getMsgListCount(); i++) { + if (!getMsgList(i).isInitialized()) { + + return false; + } + } + return true; + } + + public Builder mergeFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + com.mogujie.tt.protobuf.IMMessage.IMGetMsgListRsp parsedMessage = null; + try { + parsedMessage = PARSER.parsePartialFrom(input, extensionRegistry); + } catch (com.google.protobuf.InvalidProtocolBufferException e) { + parsedMessage = (com.mogujie.tt.protobuf.IMMessage.IMGetMsgListRsp) e.getUnfinishedMessage(); + throw e; + } finally { + if (parsedMessage != null) { + mergeFrom(parsedMessage); + } + } + return this; + } + private int bitField0_; + + private int userId_ ; + /** + * required uint32 user_id = 1; + * + *
+       *cmd id:		0x030a
+       * 
+ */ + public boolean hasUserId() { + return ((bitField0_ & 0x00000001) == 0x00000001); + } + /** + * required uint32 user_id = 1; + * + *
+       *cmd id:		0x030a
+       * 
+ */ + public int getUserId() { + return userId_; + } + /** + * required uint32 user_id = 1; + * + *
+       *cmd id:		0x030a
+       * 
+ */ + public Builder setUserId(int value) { + bitField0_ |= 0x00000001; + userId_ = value; + + return this; + } + /** + * required uint32 user_id = 1; + * + *
+       *cmd id:		0x030a
+       * 
+ */ + public Builder clearUserId() { + bitField0_ = (bitField0_ & ~0x00000001); + userId_ = 0; + + return this; + } + + private com.mogujie.tt.protobuf.IMBaseDefine.SessionType sessionType_ = com.mogujie.tt.protobuf.IMBaseDefine.SessionType.SESSION_TYPE_SINGLE; + /** + * required .IM.BaseDefine.SessionType session_type = 2; + */ + public boolean hasSessionType() { + return ((bitField0_ & 0x00000002) == 0x00000002); + } + /** + * required .IM.BaseDefine.SessionType session_type = 2; + */ + public com.mogujie.tt.protobuf.IMBaseDefine.SessionType getSessionType() { + return sessionType_; + } + /** + * required .IM.BaseDefine.SessionType session_type = 2; + */ + public Builder setSessionType(com.mogujie.tt.protobuf.IMBaseDefine.SessionType value) { + if (value == null) { + throw new NullPointerException(); + } + bitField0_ |= 0x00000002; + sessionType_ = value; + + return this; + } + /** + * required .IM.BaseDefine.SessionType session_type = 2; + */ + public Builder clearSessionType() { + bitField0_ = (bitField0_ & ~0x00000002); + sessionType_ = com.mogujie.tt.protobuf.IMBaseDefine.SessionType.SESSION_TYPE_SINGLE; + + return this; + } + + private int sessionId_ ; + /** + * required uint32 session_id = 3; + */ + public boolean hasSessionId() { + return ((bitField0_ & 0x00000004) == 0x00000004); + } + /** + * required uint32 session_id = 3; + */ + public int getSessionId() { + return sessionId_; + } + /** + * required uint32 session_id = 3; + */ + public Builder setSessionId(int value) { + bitField0_ |= 0x00000004; + sessionId_ = value; + + return this; + } + /** + * required uint32 session_id = 3; + */ + public Builder clearSessionId() { + bitField0_ = (bitField0_ & ~0x00000004); + sessionId_ = 0; + + return this; + } + + private int msgIdBegin_ ; + /** + * required uint32 msg_id_begin = 4; + */ + public boolean hasMsgIdBegin() { + return ((bitField0_ & 0x00000008) == 0x00000008); + } + /** + * required uint32 msg_id_begin = 4; + */ + public int getMsgIdBegin() { + return msgIdBegin_; + } + /** + * required uint32 msg_id_begin = 4; + */ + public Builder setMsgIdBegin(int value) { + bitField0_ |= 0x00000008; + msgIdBegin_ = value; + + return this; + } + /** + * required uint32 msg_id_begin = 4; + */ + public Builder clearMsgIdBegin() { + bitField0_ = (bitField0_ & ~0x00000008); + msgIdBegin_ = 0; + + return this; + } + + private java.util.List msgList_ = + java.util.Collections.emptyList(); + private void ensureMsgListIsMutable() { + if (!((bitField0_ & 0x00000010) == 0x00000010)) { + msgList_ = new java.util.ArrayList(msgList_); + bitField0_ |= 0x00000010; + } + } + + /** + * repeated .IM.BaseDefine.MsgInfo msg_list = 5; + */ + public java.util.List getMsgListList() { + return java.util.Collections.unmodifiableList(msgList_); + } + /** + * repeated .IM.BaseDefine.MsgInfo msg_list = 5; + */ + public int getMsgListCount() { + return msgList_.size(); + } + /** + * repeated .IM.BaseDefine.MsgInfo msg_list = 5; + */ + public com.mogujie.tt.protobuf.IMBaseDefine.MsgInfo getMsgList(int index) { + return msgList_.get(index); + } + /** + * repeated .IM.BaseDefine.MsgInfo msg_list = 5; + */ + public Builder setMsgList( + int index, com.mogujie.tt.protobuf.IMBaseDefine.MsgInfo value) { + if (value == null) { + throw new NullPointerException(); + } + ensureMsgListIsMutable(); + msgList_.set(index, value); + + return this; + } + /** + * repeated .IM.BaseDefine.MsgInfo msg_list = 5; + */ + public Builder setMsgList( + int index, com.mogujie.tt.protobuf.IMBaseDefine.MsgInfo.Builder builderForValue) { + ensureMsgListIsMutable(); + msgList_.set(index, builderForValue.build()); + + return this; + } + /** + * repeated .IM.BaseDefine.MsgInfo msg_list = 5; + */ + public Builder addMsgList(com.mogujie.tt.protobuf.IMBaseDefine.MsgInfo value) { + if (value == null) { + throw new NullPointerException(); + } + ensureMsgListIsMutable(); + msgList_.add(value); + + return this; + } + /** + * repeated .IM.BaseDefine.MsgInfo msg_list = 5; + */ + public Builder addMsgList( + int index, com.mogujie.tt.protobuf.IMBaseDefine.MsgInfo value) { + if (value == null) { + throw new NullPointerException(); + } + ensureMsgListIsMutable(); + msgList_.add(index, value); + + return this; + } + /** + * repeated .IM.BaseDefine.MsgInfo msg_list = 5; + */ + public Builder addMsgList( + com.mogujie.tt.protobuf.IMBaseDefine.MsgInfo.Builder builderForValue) { + ensureMsgListIsMutable(); + msgList_.add(builderForValue.build()); + + return this; + } + /** + * repeated .IM.BaseDefine.MsgInfo msg_list = 5; + */ + public Builder addMsgList( + int index, com.mogujie.tt.protobuf.IMBaseDefine.MsgInfo.Builder builderForValue) { + ensureMsgListIsMutable(); + msgList_.add(index, builderForValue.build()); + + return this; + } + /** + * repeated .IM.BaseDefine.MsgInfo msg_list = 5; + */ + public Builder addAllMsgList( + java.lang.Iterable values) { + ensureMsgListIsMutable(); + com.google.protobuf.AbstractMessageLite.Builder.addAll( + values, msgList_); + + return this; + } + /** + * repeated .IM.BaseDefine.MsgInfo msg_list = 5; + */ + public Builder clearMsgList() { + msgList_ = java.util.Collections.emptyList(); + bitField0_ = (bitField0_ & ~0x00000010); + + return this; + } + /** + * repeated .IM.BaseDefine.MsgInfo msg_list = 5; + */ + public Builder removeMsgList(int index) { + ensureMsgListIsMutable(); + msgList_.remove(index); + + return this; + } + + private com.google.protobuf.ByteString attachData_ = com.google.protobuf.ByteString.EMPTY; + /** + * optional bytes attach_data = 20; + */ + public boolean hasAttachData() { + return ((bitField0_ & 0x00000020) == 0x00000020); + } + /** + * optional bytes attach_data = 20; + */ + public com.google.protobuf.ByteString getAttachData() { + return attachData_; + } + /** + * optional bytes attach_data = 20; + */ + public Builder setAttachData(com.google.protobuf.ByteString value) { + if (value == null) { + throw new NullPointerException(); + } + bitField0_ |= 0x00000020; + attachData_ = value; + + return this; + } + /** + * optional bytes attach_data = 20; + */ + public Builder clearAttachData() { + bitField0_ = (bitField0_ & ~0x00000020); + attachData_ = getDefaultInstance().getAttachData(); + + return this; + } + + // @@protoc_insertion_point(builder_scope:IM.Message.IMGetMsgListRsp) + } + + static { + defaultInstance = new IMGetMsgListRsp(true); + defaultInstance.initFields(); + } + + // @@protoc_insertion_point(class_scope:IM.Message.IMGetMsgListRsp) + } + + public interface IMGetLatestMsgIdReqOrBuilder extends + // @@protoc_insertion_point(interface_extends:IM.Message.IMGetLatestMsgIdReq) + com.google.protobuf.MessageLiteOrBuilder { + + /** + * required uint32 user_id = 1; + * + *
+     *cmd id: 		0x030b
+     * 
+ */ + boolean hasUserId(); + /** + * required uint32 user_id = 1; + * + *
+     *cmd id: 		0x030b
+     * 
+ */ + int getUserId(); + + /** + * required .IM.BaseDefine.SessionType session_type = 2; + */ + boolean hasSessionType(); + /** + * required .IM.BaseDefine.SessionType session_type = 2; + */ + com.mogujie.tt.protobuf.IMBaseDefine.SessionType getSessionType(); + + /** + * required uint32 session_id = 3; + */ + boolean hasSessionId(); + /** + * required uint32 session_id = 3; + */ + int getSessionId(); + + /** + * optional bytes attach_data = 20; + */ + boolean hasAttachData(); + /** + * optional bytes attach_data = 20; + */ + com.google.protobuf.ByteString getAttachData(); + } + /** + * Protobuf type {@code IM.Message.IMGetLatestMsgIdReq} + */ + public static final class IMGetLatestMsgIdReq extends + com.google.protobuf.GeneratedMessageLite implements + // @@protoc_insertion_point(message_implements:IM.Message.IMGetLatestMsgIdReq) + IMGetLatestMsgIdReqOrBuilder { + // Use IMGetLatestMsgIdReq.newBuilder() to construct. + private IMGetLatestMsgIdReq(com.google.protobuf.GeneratedMessageLite.Builder builder) { + super(builder); + this.unknownFields = builder.getUnknownFields(); + } + private IMGetLatestMsgIdReq(boolean noInit) { this.unknownFields = com.google.protobuf.ByteString.EMPTY;} + + private static final IMGetLatestMsgIdReq defaultInstance; + public static IMGetLatestMsgIdReq getDefaultInstance() { + return defaultInstance; + } + + public IMGetLatestMsgIdReq getDefaultInstanceForType() { + return defaultInstance; + } + + private final com.google.protobuf.ByteString unknownFields; + private IMGetLatestMsgIdReq( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + initFields(); + int mutable_bitField0_ = 0; + com.google.protobuf.ByteString.Output unknownFieldsOutput = + com.google.protobuf.ByteString.newOutput(); + com.google.protobuf.CodedOutputStream unknownFieldsCodedOutput = + com.google.protobuf.CodedOutputStream.newInstance( + unknownFieldsOutput); + try { + boolean done = false; + while (!done) { + int tag = input.readTag(); + switch (tag) { + case 0: + done = true; + break; + default: { + if (!parseUnknownField(input, unknownFieldsCodedOutput, + extensionRegistry, tag)) { + done = true; + } + break; + } + case 8: { + bitField0_ |= 0x00000001; + userId_ = input.readUInt32(); + break; + } + case 16: { + int rawValue = input.readEnum(); + com.mogujie.tt.protobuf.IMBaseDefine.SessionType value = com.mogujie.tt.protobuf.IMBaseDefine.SessionType.valueOf(rawValue); + if (value == null) { + unknownFieldsCodedOutput.writeRawVarint32(tag); + unknownFieldsCodedOutput.writeRawVarint32(rawValue); + } else { + bitField0_ |= 0x00000002; + sessionType_ = value; + } + break; + } + case 24: { + bitField0_ |= 0x00000004; + sessionId_ = input.readUInt32(); + break; + } + case 162: { + bitField0_ |= 0x00000008; + attachData_ = input.readBytes(); + break; + } + } + } + } catch (com.google.protobuf.InvalidProtocolBufferException e) { + throw e.setUnfinishedMessage(this); + } catch (java.io.IOException e) { + throw new com.google.protobuf.InvalidProtocolBufferException( + e.getMessage()).setUnfinishedMessage(this); + } finally { + try { + unknownFieldsCodedOutput.flush(); + } catch (java.io.IOException e) { + // Should not happen + } finally { + unknownFields = unknownFieldsOutput.toByteString(); + } + makeExtensionsImmutable(); + } + } + public static com.google.protobuf.Parser PARSER = + new com.google.protobuf.AbstractParser() { + public IMGetLatestMsgIdReq parsePartialFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return new IMGetLatestMsgIdReq(input, extensionRegistry); + } + }; + + @java.lang.Override + public com.google.protobuf.Parser getParserForType() { + return PARSER; + } + + private int bitField0_; + public static final int USER_ID_FIELD_NUMBER = 1; + private int userId_; + /** + * required uint32 user_id = 1; + * + *
+     *cmd id: 		0x030b
+     * 
+ */ + public boolean hasUserId() { + return ((bitField0_ & 0x00000001) == 0x00000001); + } + /** + * required uint32 user_id = 1; + * + *
+     *cmd id: 		0x030b
+     * 
+ */ + public int getUserId() { + return userId_; + } + + public static final int SESSION_TYPE_FIELD_NUMBER = 2; + private com.mogujie.tt.protobuf.IMBaseDefine.SessionType sessionType_; + /** + * required .IM.BaseDefine.SessionType session_type = 2; + */ + public boolean hasSessionType() { + return ((bitField0_ & 0x00000002) == 0x00000002); + } + /** + * required .IM.BaseDefine.SessionType session_type = 2; + */ + public com.mogujie.tt.protobuf.IMBaseDefine.SessionType getSessionType() { + return sessionType_; + } + + public static final int SESSION_ID_FIELD_NUMBER = 3; + private int sessionId_; + /** + * required uint32 session_id = 3; + */ + public boolean hasSessionId() { + return ((bitField0_ & 0x00000004) == 0x00000004); + } + /** + * required uint32 session_id = 3; + */ + public int getSessionId() { + return sessionId_; + } + + public static final int ATTACH_DATA_FIELD_NUMBER = 20; + private com.google.protobuf.ByteString attachData_; + /** + * optional bytes attach_data = 20; + */ + public boolean hasAttachData() { + return ((bitField0_ & 0x00000008) == 0x00000008); + } + /** + * optional bytes attach_data = 20; + */ + public com.google.protobuf.ByteString getAttachData() { + return attachData_; + } + + private void initFields() { + userId_ = 0; + sessionType_ = com.mogujie.tt.protobuf.IMBaseDefine.SessionType.SESSION_TYPE_SINGLE; + sessionId_ = 0; + attachData_ = com.google.protobuf.ByteString.EMPTY; + } + private byte memoizedIsInitialized = -1; + public final boolean isInitialized() { + byte isInitialized = memoizedIsInitialized; + if (isInitialized == 1) return true; + if (isInitialized == 0) return false; + + if (!hasUserId()) { + memoizedIsInitialized = 0; + return false; + } + if (!hasSessionType()) { + memoizedIsInitialized = 0; + return false; + } + if (!hasSessionId()) { + memoizedIsInitialized = 0; + return false; + } + memoizedIsInitialized = 1; + return true; + } + + public void writeTo(com.google.protobuf.CodedOutputStream output) + throws java.io.IOException { + getSerializedSize(); + if (((bitField0_ & 0x00000001) == 0x00000001)) { + output.writeUInt32(1, userId_); + } + if (((bitField0_ & 0x00000002) == 0x00000002)) { + output.writeEnum(2, sessionType_.getNumber()); + } + if (((bitField0_ & 0x00000004) == 0x00000004)) { + output.writeUInt32(3, sessionId_); + } + if (((bitField0_ & 0x00000008) == 0x00000008)) { + output.writeBytes(20, attachData_); + } + output.writeRawBytes(unknownFields); + } + + private int memoizedSerializedSize = -1; + public int getSerializedSize() { + int size = memoizedSerializedSize; + if (size != -1) return size; + + size = 0; + if (((bitField0_ & 0x00000001) == 0x00000001)) { + size += com.google.protobuf.CodedOutputStream + .computeUInt32Size(1, userId_); + } + if (((bitField0_ & 0x00000002) == 0x00000002)) { + size += com.google.protobuf.CodedOutputStream + .computeEnumSize(2, sessionType_.getNumber()); + } + if (((bitField0_ & 0x00000004) == 0x00000004)) { + size += com.google.protobuf.CodedOutputStream + .computeUInt32Size(3, sessionId_); + } + if (((bitField0_ & 0x00000008) == 0x00000008)) { + size += com.google.protobuf.CodedOutputStream + .computeBytesSize(20, attachData_); + } + size += unknownFields.size(); + memoizedSerializedSize = size; + return size; + } + + private static final long serialVersionUID = 0L; + @java.lang.Override + protected java.lang.Object writeReplace() + throws java.io.ObjectStreamException { + return super.writeReplace(); + } + + public static com.mogujie.tt.protobuf.IMMessage.IMGetLatestMsgIdReq parseFrom( + com.google.protobuf.ByteString data) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data); + } + public static com.mogujie.tt.protobuf.IMMessage.IMGetLatestMsgIdReq parseFrom( + com.google.protobuf.ByteString data, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data, extensionRegistry); + } + public static com.mogujie.tt.protobuf.IMMessage.IMGetLatestMsgIdReq parseFrom(byte[] data) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data); + } + public static com.mogujie.tt.protobuf.IMMessage.IMGetLatestMsgIdReq parseFrom( + byte[] data, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data, extensionRegistry); + } + public static com.mogujie.tt.protobuf.IMMessage.IMGetLatestMsgIdReq parseFrom(java.io.InputStream input) + throws java.io.IOException { + return PARSER.parseFrom(input); + } + public static com.mogujie.tt.protobuf.IMMessage.IMGetLatestMsgIdReq parseFrom( + java.io.InputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return PARSER.parseFrom(input, extensionRegistry); + } + public static com.mogujie.tt.protobuf.IMMessage.IMGetLatestMsgIdReq parseDelimitedFrom(java.io.InputStream input) + throws java.io.IOException { + return PARSER.parseDelimitedFrom(input); + } + public static com.mogujie.tt.protobuf.IMMessage.IMGetLatestMsgIdReq parseDelimitedFrom( + java.io.InputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return PARSER.parseDelimitedFrom(input, extensionRegistry); + } + public static com.mogujie.tt.protobuf.IMMessage.IMGetLatestMsgIdReq parseFrom( + com.google.protobuf.CodedInputStream input) + throws java.io.IOException { + return PARSER.parseFrom(input); + } + public static com.mogujie.tt.protobuf.IMMessage.IMGetLatestMsgIdReq parseFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return PARSER.parseFrom(input, extensionRegistry); + } + + public static Builder newBuilder() { return Builder.create(); } + public Builder newBuilderForType() { return newBuilder(); } + public static Builder newBuilder(com.mogujie.tt.protobuf.IMMessage.IMGetLatestMsgIdReq prototype) { + return newBuilder().mergeFrom(prototype); + } + public Builder toBuilder() { return newBuilder(this); } + + /** + * Protobuf type {@code IM.Message.IMGetLatestMsgIdReq} + */ + public static final class Builder extends + com.google.protobuf.GeneratedMessageLite.Builder< + com.mogujie.tt.protobuf.IMMessage.IMGetLatestMsgIdReq, Builder> + implements + // @@protoc_insertion_point(builder_implements:IM.Message.IMGetLatestMsgIdReq) + com.mogujie.tt.protobuf.IMMessage.IMGetLatestMsgIdReqOrBuilder { + // Construct using com.mogujie.tt.protobuf.IMMessage.IMGetLatestMsgIdReq.newBuilder() + private Builder() { + maybeForceBuilderInitialization(); + } + + private void maybeForceBuilderInitialization() { + } + private static Builder create() { + return new Builder(); + } + + public Builder clear() { + super.clear(); + userId_ = 0; + bitField0_ = (bitField0_ & ~0x00000001); + sessionType_ = com.mogujie.tt.protobuf.IMBaseDefine.SessionType.SESSION_TYPE_SINGLE; + bitField0_ = (bitField0_ & ~0x00000002); + sessionId_ = 0; + bitField0_ = (bitField0_ & ~0x00000004); + attachData_ = com.google.protobuf.ByteString.EMPTY; + bitField0_ = (bitField0_ & ~0x00000008); + return this; + } + + public Builder clone() { + return create().mergeFrom(buildPartial()); + } + + public com.mogujie.tt.protobuf.IMMessage.IMGetLatestMsgIdReq getDefaultInstanceForType() { + return com.mogujie.tt.protobuf.IMMessage.IMGetLatestMsgIdReq.getDefaultInstance(); + } + + public com.mogujie.tt.protobuf.IMMessage.IMGetLatestMsgIdReq build() { + com.mogujie.tt.protobuf.IMMessage.IMGetLatestMsgIdReq result = buildPartial(); + if (!result.isInitialized()) { + throw newUninitializedMessageException(result); + } + return result; + } + + public com.mogujie.tt.protobuf.IMMessage.IMGetLatestMsgIdReq buildPartial() { + com.mogujie.tt.protobuf.IMMessage.IMGetLatestMsgIdReq result = new com.mogujie.tt.protobuf.IMMessage.IMGetLatestMsgIdReq(this); + int from_bitField0_ = bitField0_; + int to_bitField0_ = 0; + if (((from_bitField0_ & 0x00000001) == 0x00000001)) { + to_bitField0_ |= 0x00000001; + } + result.userId_ = userId_; + if (((from_bitField0_ & 0x00000002) == 0x00000002)) { + to_bitField0_ |= 0x00000002; + } + result.sessionType_ = sessionType_; + if (((from_bitField0_ & 0x00000004) == 0x00000004)) { + to_bitField0_ |= 0x00000004; + } + result.sessionId_ = sessionId_; + if (((from_bitField0_ & 0x00000008) == 0x00000008)) { + to_bitField0_ |= 0x00000008; + } + result.attachData_ = attachData_; + result.bitField0_ = to_bitField0_; + return result; + } + + public Builder mergeFrom(com.mogujie.tt.protobuf.IMMessage.IMGetLatestMsgIdReq other) { + if (other == com.mogujie.tt.protobuf.IMMessage.IMGetLatestMsgIdReq.getDefaultInstance()) return this; + if (other.hasUserId()) { + setUserId(other.getUserId()); + } + if (other.hasSessionType()) { + setSessionType(other.getSessionType()); + } + if (other.hasSessionId()) { + setSessionId(other.getSessionId()); + } + if (other.hasAttachData()) { + setAttachData(other.getAttachData()); + } + setUnknownFields( + getUnknownFields().concat(other.unknownFields)); + return this; + } + + public final boolean isInitialized() { + if (!hasUserId()) { + + return false; + } + if (!hasSessionType()) { + + return false; + } + if (!hasSessionId()) { + + return false; + } + return true; + } + + public Builder mergeFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + com.mogujie.tt.protobuf.IMMessage.IMGetLatestMsgIdReq parsedMessage = null; + try { + parsedMessage = PARSER.parsePartialFrom(input, extensionRegistry); + } catch (com.google.protobuf.InvalidProtocolBufferException e) { + parsedMessage = (com.mogujie.tt.protobuf.IMMessage.IMGetLatestMsgIdReq) e.getUnfinishedMessage(); + throw e; + } finally { + if (parsedMessage != null) { + mergeFrom(parsedMessage); + } + } + return this; + } + private int bitField0_; + + private int userId_ ; + /** + * required uint32 user_id = 1; + * + *
+       *cmd id: 		0x030b
+       * 
+ */ + public boolean hasUserId() { + return ((bitField0_ & 0x00000001) == 0x00000001); + } + /** + * required uint32 user_id = 1; + * + *
+       *cmd id: 		0x030b
+       * 
+ */ + public int getUserId() { + return userId_; + } + /** + * required uint32 user_id = 1; + * + *
+       *cmd id: 		0x030b
+       * 
+ */ + public Builder setUserId(int value) { + bitField0_ |= 0x00000001; + userId_ = value; + + return this; + } + /** + * required uint32 user_id = 1; + * + *
+       *cmd id: 		0x030b
+       * 
+ */ + public Builder clearUserId() { + bitField0_ = (bitField0_ & ~0x00000001); + userId_ = 0; + + return this; + } + + private com.mogujie.tt.protobuf.IMBaseDefine.SessionType sessionType_ = com.mogujie.tt.protobuf.IMBaseDefine.SessionType.SESSION_TYPE_SINGLE; + /** + * required .IM.BaseDefine.SessionType session_type = 2; + */ + public boolean hasSessionType() { + return ((bitField0_ & 0x00000002) == 0x00000002); + } + /** + * required .IM.BaseDefine.SessionType session_type = 2; + */ + public com.mogujie.tt.protobuf.IMBaseDefine.SessionType getSessionType() { + return sessionType_; + } + /** + * required .IM.BaseDefine.SessionType session_type = 2; + */ + public Builder setSessionType(com.mogujie.tt.protobuf.IMBaseDefine.SessionType value) { + if (value == null) { + throw new NullPointerException(); + } + bitField0_ |= 0x00000002; + sessionType_ = value; + + return this; + } + /** + * required .IM.BaseDefine.SessionType session_type = 2; + */ + public Builder clearSessionType() { + bitField0_ = (bitField0_ & ~0x00000002); + sessionType_ = com.mogujie.tt.protobuf.IMBaseDefine.SessionType.SESSION_TYPE_SINGLE; + + return this; + } + + private int sessionId_ ; + /** + * required uint32 session_id = 3; + */ + public boolean hasSessionId() { + return ((bitField0_ & 0x00000004) == 0x00000004); + } + /** + * required uint32 session_id = 3; + */ + public int getSessionId() { + return sessionId_; + } + /** + * required uint32 session_id = 3; + */ + public Builder setSessionId(int value) { + bitField0_ |= 0x00000004; + sessionId_ = value; + + return this; + } + /** + * required uint32 session_id = 3; + */ + public Builder clearSessionId() { + bitField0_ = (bitField0_ & ~0x00000004); + sessionId_ = 0; + + return this; + } + + private com.google.protobuf.ByteString attachData_ = com.google.protobuf.ByteString.EMPTY; + /** + * optional bytes attach_data = 20; + */ + public boolean hasAttachData() { + return ((bitField0_ & 0x00000008) == 0x00000008); + } + /** + * optional bytes attach_data = 20; + */ + public com.google.protobuf.ByteString getAttachData() { + return attachData_; + } + /** + * optional bytes attach_data = 20; + */ + public Builder setAttachData(com.google.protobuf.ByteString value) { + if (value == null) { + throw new NullPointerException(); + } + bitField0_ |= 0x00000008; + attachData_ = value; + + return this; + } + /** + * optional bytes attach_data = 20; + */ + public Builder clearAttachData() { + bitField0_ = (bitField0_ & ~0x00000008); + attachData_ = getDefaultInstance().getAttachData(); + + return this; + } + + // @@protoc_insertion_point(builder_scope:IM.Message.IMGetLatestMsgIdReq) + } + + static { + defaultInstance = new IMGetLatestMsgIdReq(true); + defaultInstance.initFields(); + } + + // @@protoc_insertion_point(class_scope:IM.Message.IMGetLatestMsgIdReq) + } + + public interface IMGetLatestMsgIdRspOrBuilder extends + // @@protoc_insertion_point(interface_extends:IM.Message.IMGetLatestMsgIdRsp) + com.google.protobuf.MessageLiteOrBuilder { + + /** + * required uint32 user_id = 1; + * + *
+     *cmd id:		0x030c
+     * 
+ */ + boolean hasUserId(); + /** + * required uint32 user_id = 1; + * + *
+     *cmd id:		0x030c
+     * 
+ */ + int getUserId(); + + /** + * required .IM.BaseDefine.SessionType session_type = 2; + */ + boolean hasSessionType(); + /** + * required .IM.BaseDefine.SessionType session_type = 2; + */ + com.mogujie.tt.protobuf.IMBaseDefine.SessionType getSessionType(); + + /** + * required uint32 session_id = 3; + */ + boolean hasSessionId(); + /** + * required uint32 session_id = 3; + */ + int getSessionId(); + + /** + * required uint32 latest_msg_id = 4; + */ + boolean hasLatestMsgId(); + /** + * required uint32 latest_msg_id = 4; + */ + int getLatestMsgId(); + + /** + * optional bytes attach_data = 20; + */ + boolean hasAttachData(); + /** + * optional bytes attach_data = 20; + */ + com.google.protobuf.ByteString getAttachData(); + } + /** + * Protobuf type {@code IM.Message.IMGetLatestMsgIdRsp} + */ + public static final class IMGetLatestMsgIdRsp extends + com.google.protobuf.GeneratedMessageLite implements + // @@protoc_insertion_point(message_implements:IM.Message.IMGetLatestMsgIdRsp) + IMGetLatestMsgIdRspOrBuilder { + // Use IMGetLatestMsgIdRsp.newBuilder() to construct. + private IMGetLatestMsgIdRsp(com.google.protobuf.GeneratedMessageLite.Builder builder) { + super(builder); + this.unknownFields = builder.getUnknownFields(); + } + private IMGetLatestMsgIdRsp(boolean noInit) { this.unknownFields = com.google.protobuf.ByteString.EMPTY;} + + private static final IMGetLatestMsgIdRsp defaultInstance; + public static IMGetLatestMsgIdRsp getDefaultInstance() { + return defaultInstance; + } + + public IMGetLatestMsgIdRsp getDefaultInstanceForType() { + return defaultInstance; + } + + private final com.google.protobuf.ByteString unknownFields; + private IMGetLatestMsgIdRsp( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + initFields(); + int mutable_bitField0_ = 0; + com.google.protobuf.ByteString.Output unknownFieldsOutput = + com.google.protobuf.ByteString.newOutput(); + com.google.protobuf.CodedOutputStream unknownFieldsCodedOutput = + com.google.protobuf.CodedOutputStream.newInstance( + unknownFieldsOutput); + try { + boolean done = false; + while (!done) { + int tag = input.readTag(); + switch (tag) { + case 0: + done = true; + break; + default: { + if (!parseUnknownField(input, unknownFieldsCodedOutput, + extensionRegistry, tag)) { + done = true; + } + break; + } + case 8: { + bitField0_ |= 0x00000001; + userId_ = input.readUInt32(); + break; + } + case 16: { + int rawValue = input.readEnum(); + com.mogujie.tt.protobuf.IMBaseDefine.SessionType value = com.mogujie.tt.protobuf.IMBaseDefine.SessionType.valueOf(rawValue); + if (value == null) { + unknownFieldsCodedOutput.writeRawVarint32(tag); + unknownFieldsCodedOutput.writeRawVarint32(rawValue); + } else { + bitField0_ |= 0x00000002; + sessionType_ = value; + } + break; + } + case 24: { + bitField0_ |= 0x00000004; + sessionId_ = input.readUInt32(); + break; + } + case 32: { + bitField0_ |= 0x00000008; + latestMsgId_ = input.readUInt32(); + break; + } + case 162: { + bitField0_ |= 0x00000010; + attachData_ = input.readBytes(); + break; + } + } + } + } catch (com.google.protobuf.InvalidProtocolBufferException e) { + throw e.setUnfinishedMessage(this); + } catch (java.io.IOException e) { + throw new com.google.protobuf.InvalidProtocolBufferException( + e.getMessage()).setUnfinishedMessage(this); + } finally { + try { + unknownFieldsCodedOutput.flush(); + } catch (java.io.IOException e) { + // Should not happen + } finally { + unknownFields = unknownFieldsOutput.toByteString(); + } + makeExtensionsImmutable(); + } + } + public static com.google.protobuf.Parser PARSER = + new com.google.protobuf.AbstractParser() { + public IMGetLatestMsgIdRsp parsePartialFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return new IMGetLatestMsgIdRsp(input, extensionRegistry); + } + }; + + @java.lang.Override + public com.google.protobuf.Parser getParserForType() { + return PARSER; + } + + private int bitField0_; + public static final int USER_ID_FIELD_NUMBER = 1; + private int userId_; + /** + * required uint32 user_id = 1; + * + *
+     *cmd id:		0x030c
+     * 
+ */ + public boolean hasUserId() { + return ((bitField0_ & 0x00000001) == 0x00000001); + } + /** + * required uint32 user_id = 1; + * + *
+     *cmd id:		0x030c
+     * 
+ */ + public int getUserId() { + return userId_; + } + + public static final int SESSION_TYPE_FIELD_NUMBER = 2; + private com.mogujie.tt.protobuf.IMBaseDefine.SessionType sessionType_; + /** + * required .IM.BaseDefine.SessionType session_type = 2; + */ + public boolean hasSessionType() { + return ((bitField0_ & 0x00000002) == 0x00000002); + } + /** + * required .IM.BaseDefine.SessionType session_type = 2; + */ + public com.mogujie.tt.protobuf.IMBaseDefine.SessionType getSessionType() { + return sessionType_; + } + + public static final int SESSION_ID_FIELD_NUMBER = 3; + private int sessionId_; + /** + * required uint32 session_id = 3; + */ + public boolean hasSessionId() { + return ((bitField0_ & 0x00000004) == 0x00000004); + } + /** + * required uint32 session_id = 3; + */ + public int getSessionId() { + return sessionId_; + } + + public static final int LATEST_MSG_ID_FIELD_NUMBER = 4; + private int latestMsgId_; + /** + * required uint32 latest_msg_id = 4; + */ + public boolean hasLatestMsgId() { + return ((bitField0_ & 0x00000008) == 0x00000008); + } + /** + * required uint32 latest_msg_id = 4; + */ + public int getLatestMsgId() { + return latestMsgId_; + } + + public static final int ATTACH_DATA_FIELD_NUMBER = 20; + private com.google.protobuf.ByteString attachData_; + /** + * optional bytes attach_data = 20; + */ + public boolean hasAttachData() { + return ((bitField0_ & 0x00000010) == 0x00000010); + } + /** + * optional bytes attach_data = 20; + */ + public com.google.protobuf.ByteString getAttachData() { + return attachData_; + } + + private void initFields() { + userId_ = 0; + sessionType_ = com.mogujie.tt.protobuf.IMBaseDefine.SessionType.SESSION_TYPE_SINGLE; + sessionId_ = 0; + latestMsgId_ = 0; + attachData_ = com.google.protobuf.ByteString.EMPTY; + } + private byte memoizedIsInitialized = -1; + public final boolean isInitialized() { + byte isInitialized = memoizedIsInitialized; + if (isInitialized == 1) return true; + if (isInitialized == 0) return false; + + if (!hasUserId()) { + memoizedIsInitialized = 0; + return false; + } + if (!hasSessionType()) { + memoizedIsInitialized = 0; + return false; + } + if (!hasSessionId()) { + memoizedIsInitialized = 0; + return false; + } + if (!hasLatestMsgId()) { + memoizedIsInitialized = 0; + return false; + } + memoizedIsInitialized = 1; + return true; + } + + public void writeTo(com.google.protobuf.CodedOutputStream output) + throws java.io.IOException { + getSerializedSize(); + if (((bitField0_ & 0x00000001) == 0x00000001)) { + output.writeUInt32(1, userId_); + } + if (((bitField0_ & 0x00000002) == 0x00000002)) { + output.writeEnum(2, sessionType_.getNumber()); + } + if (((bitField0_ & 0x00000004) == 0x00000004)) { + output.writeUInt32(3, sessionId_); + } + if (((bitField0_ & 0x00000008) == 0x00000008)) { + output.writeUInt32(4, latestMsgId_); + } + if (((bitField0_ & 0x00000010) == 0x00000010)) { + output.writeBytes(20, attachData_); + } + output.writeRawBytes(unknownFields); + } + + private int memoizedSerializedSize = -1; + public int getSerializedSize() { + int size = memoizedSerializedSize; + if (size != -1) return size; + + size = 0; + if (((bitField0_ & 0x00000001) == 0x00000001)) { + size += com.google.protobuf.CodedOutputStream + .computeUInt32Size(1, userId_); + } + if (((bitField0_ & 0x00000002) == 0x00000002)) { + size += com.google.protobuf.CodedOutputStream + .computeEnumSize(2, sessionType_.getNumber()); + } + if (((bitField0_ & 0x00000004) == 0x00000004)) { + size += com.google.protobuf.CodedOutputStream + .computeUInt32Size(3, sessionId_); + } + if (((bitField0_ & 0x00000008) == 0x00000008)) { + size += com.google.protobuf.CodedOutputStream + .computeUInt32Size(4, latestMsgId_); + } + if (((bitField0_ & 0x00000010) == 0x00000010)) { + size += com.google.protobuf.CodedOutputStream + .computeBytesSize(20, attachData_); + } + size += unknownFields.size(); + memoizedSerializedSize = size; + return size; + } + + private static final long serialVersionUID = 0L; + @java.lang.Override + protected java.lang.Object writeReplace() + throws java.io.ObjectStreamException { + return super.writeReplace(); + } + + public static com.mogujie.tt.protobuf.IMMessage.IMGetLatestMsgIdRsp parseFrom( + com.google.protobuf.ByteString data) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data); + } + public static com.mogujie.tt.protobuf.IMMessage.IMGetLatestMsgIdRsp parseFrom( + com.google.protobuf.ByteString data, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data, extensionRegistry); + } + public static com.mogujie.tt.protobuf.IMMessage.IMGetLatestMsgIdRsp parseFrom(byte[] data) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data); + } + public static com.mogujie.tt.protobuf.IMMessage.IMGetLatestMsgIdRsp parseFrom( + byte[] data, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data, extensionRegistry); + } + public static com.mogujie.tt.protobuf.IMMessage.IMGetLatestMsgIdRsp parseFrom(java.io.InputStream input) + throws java.io.IOException { + return PARSER.parseFrom(input); + } + public static com.mogujie.tt.protobuf.IMMessage.IMGetLatestMsgIdRsp parseFrom( + java.io.InputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return PARSER.parseFrom(input, extensionRegistry); + } + public static com.mogujie.tt.protobuf.IMMessage.IMGetLatestMsgIdRsp parseDelimitedFrom(java.io.InputStream input) + throws java.io.IOException { + return PARSER.parseDelimitedFrom(input); + } + public static com.mogujie.tt.protobuf.IMMessage.IMGetLatestMsgIdRsp parseDelimitedFrom( + java.io.InputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return PARSER.parseDelimitedFrom(input, extensionRegistry); + } + public static com.mogujie.tt.protobuf.IMMessage.IMGetLatestMsgIdRsp parseFrom( + com.google.protobuf.CodedInputStream input) + throws java.io.IOException { + return PARSER.parseFrom(input); + } + public static com.mogujie.tt.protobuf.IMMessage.IMGetLatestMsgIdRsp parseFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return PARSER.parseFrom(input, extensionRegistry); + } + + public static Builder newBuilder() { return Builder.create(); } + public Builder newBuilderForType() { return newBuilder(); } + public static Builder newBuilder(com.mogujie.tt.protobuf.IMMessage.IMGetLatestMsgIdRsp prototype) { + return newBuilder().mergeFrom(prototype); + } + public Builder toBuilder() { return newBuilder(this); } + + /** + * Protobuf type {@code IM.Message.IMGetLatestMsgIdRsp} + */ + public static final class Builder extends + com.google.protobuf.GeneratedMessageLite.Builder< + com.mogujie.tt.protobuf.IMMessage.IMGetLatestMsgIdRsp, Builder> + implements + // @@protoc_insertion_point(builder_implements:IM.Message.IMGetLatestMsgIdRsp) + com.mogujie.tt.protobuf.IMMessage.IMGetLatestMsgIdRspOrBuilder { + // Construct using com.mogujie.tt.protobuf.IMMessage.IMGetLatestMsgIdRsp.newBuilder() + private Builder() { + maybeForceBuilderInitialization(); + } + + private void maybeForceBuilderInitialization() { + } + private static Builder create() { + return new Builder(); + } + + public Builder clear() { + super.clear(); + userId_ = 0; + bitField0_ = (bitField0_ & ~0x00000001); + sessionType_ = com.mogujie.tt.protobuf.IMBaseDefine.SessionType.SESSION_TYPE_SINGLE; + bitField0_ = (bitField0_ & ~0x00000002); + sessionId_ = 0; + bitField0_ = (bitField0_ & ~0x00000004); + latestMsgId_ = 0; + bitField0_ = (bitField0_ & ~0x00000008); + attachData_ = com.google.protobuf.ByteString.EMPTY; + bitField0_ = (bitField0_ & ~0x00000010); + return this; + } + + public Builder clone() { + return create().mergeFrom(buildPartial()); + } + + public com.mogujie.tt.protobuf.IMMessage.IMGetLatestMsgIdRsp getDefaultInstanceForType() { + return com.mogujie.tt.protobuf.IMMessage.IMGetLatestMsgIdRsp.getDefaultInstance(); + } + + public com.mogujie.tt.protobuf.IMMessage.IMGetLatestMsgIdRsp build() { + com.mogujie.tt.protobuf.IMMessage.IMGetLatestMsgIdRsp result = buildPartial(); + if (!result.isInitialized()) { + throw newUninitializedMessageException(result); + } + return result; + } + + public com.mogujie.tt.protobuf.IMMessage.IMGetLatestMsgIdRsp buildPartial() { + com.mogujie.tt.protobuf.IMMessage.IMGetLatestMsgIdRsp result = new com.mogujie.tt.protobuf.IMMessage.IMGetLatestMsgIdRsp(this); + int from_bitField0_ = bitField0_; + int to_bitField0_ = 0; + if (((from_bitField0_ & 0x00000001) == 0x00000001)) { + to_bitField0_ |= 0x00000001; + } + result.userId_ = userId_; + if (((from_bitField0_ & 0x00000002) == 0x00000002)) { + to_bitField0_ |= 0x00000002; + } + result.sessionType_ = sessionType_; + if (((from_bitField0_ & 0x00000004) == 0x00000004)) { + to_bitField0_ |= 0x00000004; + } + result.sessionId_ = sessionId_; + if (((from_bitField0_ & 0x00000008) == 0x00000008)) { + to_bitField0_ |= 0x00000008; + } + result.latestMsgId_ = latestMsgId_; + if (((from_bitField0_ & 0x00000010) == 0x00000010)) { + to_bitField0_ |= 0x00000010; + } + result.attachData_ = attachData_; + result.bitField0_ = to_bitField0_; + return result; + } + + public Builder mergeFrom(com.mogujie.tt.protobuf.IMMessage.IMGetLatestMsgIdRsp other) { + if (other == com.mogujie.tt.protobuf.IMMessage.IMGetLatestMsgIdRsp.getDefaultInstance()) return this; + if (other.hasUserId()) { + setUserId(other.getUserId()); + } + if (other.hasSessionType()) { + setSessionType(other.getSessionType()); + } + if (other.hasSessionId()) { + setSessionId(other.getSessionId()); + } + if (other.hasLatestMsgId()) { + setLatestMsgId(other.getLatestMsgId()); + } + if (other.hasAttachData()) { + setAttachData(other.getAttachData()); + } + setUnknownFields( + getUnknownFields().concat(other.unknownFields)); + return this; + } + + public final boolean isInitialized() { + if (!hasUserId()) { + + return false; + } + if (!hasSessionType()) { + + return false; + } + if (!hasSessionId()) { + + return false; + } + if (!hasLatestMsgId()) { + + return false; + } + return true; + } + + public Builder mergeFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + com.mogujie.tt.protobuf.IMMessage.IMGetLatestMsgIdRsp parsedMessage = null; + try { + parsedMessage = PARSER.parsePartialFrom(input, extensionRegistry); + } catch (com.google.protobuf.InvalidProtocolBufferException e) { + parsedMessage = (com.mogujie.tt.protobuf.IMMessage.IMGetLatestMsgIdRsp) e.getUnfinishedMessage(); + throw e; + } finally { + if (parsedMessage != null) { + mergeFrom(parsedMessage); + } + } + return this; + } + private int bitField0_; + + private int userId_ ; + /** + * required uint32 user_id = 1; + * + *
+       *cmd id:		0x030c
+       * 
+ */ + public boolean hasUserId() { + return ((bitField0_ & 0x00000001) == 0x00000001); + } + /** + * required uint32 user_id = 1; + * + *
+       *cmd id:		0x030c
+       * 
+ */ + public int getUserId() { + return userId_; + } + /** + * required uint32 user_id = 1; + * + *
+       *cmd id:		0x030c
+       * 
+ */ + public Builder setUserId(int value) { + bitField0_ |= 0x00000001; + userId_ = value; + + return this; + } + /** + * required uint32 user_id = 1; + * + *
+       *cmd id:		0x030c
+       * 
+ */ + public Builder clearUserId() { + bitField0_ = (bitField0_ & ~0x00000001); + userId_ = 0; + + return this; + } + + private com.mogujie.tt.protobuf.IMBaseDefine.SessionType sessionType_ = com.mogujie.tt.protobuf.IMBaseDefine.SessionType.SESSION_TYPE_SINGLE; + /** + * required .IM.BaseDefine.SessionType session_type = 2; + */ + public boolean hasSessionType() { + return ((bitField0_ & 0x00000002) == 0x00000002); + } + /** + * required .IM.BaseDefine.SessionType session_type = 2; + */ + public com.mogujie.tt.protobuf.IMBaseDefine.SessionType getSessionType() { + return sessionType_; + } + /** + * required .IM.BaseDefine.SessionType session_type = 2; + */ + public Builder setSessionType(com.mogujie.tt.protobuf.IMBaseDefine.SessionType value) { + if (value == null) { + throw new NullPointerException(); + } + bitField0_ |= 0x00000002; + sessionType_ = value; + + return this; + } + /** + * required .IM.BaseDefine.SessionType session_type = 2; + */ + public Builder clearSessionType() { + bitField0_ = (bitField0_ & ~0x00000002); + sessionType_ = com.mogujie.tt.protobuf.IMBaseDefine.SessionType.SESSION_TYPE_SINGLE; + + return this; + } + + private int sessionId_ ; + /** + * required uint32 session_id = 3; + */ + public boolean hasSessionId() { + return ((bitField0_ & 0x00000004) == 0x00000004); + } + /** + * required uint32 session_id = 3; + */ + public int getSessionId() { + return sessionId_; + } + /** + * required uint32 session_id = 3; + */ + public Builder setSessionId(int value) { + bitField0_ |= 0x00000004; + sessionId_ = value; + + return this; + } + /** + * required uint32 session_id = 3; + */ + public Builder clearSessionId() { + bitField0_ = (bitField0_ & ~0x00000004); + sessionId_ = 0; + + return this; + } + + private int latestMsgId_ ; + /** + * required uint32 latest_msg_id = 4; + */ + public boolean hasLatestMsgId() { + return ((bitField0_ & 0x00000008) == 0x00000008); + } + /** + * required uint32 latest_msg_id = 4; + */ + public int getLatestMsgId() { + return latestMsgId_; + } + /** + * required uint32 latest_msg_id = 4; + */ + public Builder setLatestMsgId(int value) { + bitField0_ |= 0x00000008; + latestMsgId_ = value; + + return this; + } + /** + * required uint32 latest_msg_id = 4; + */ + public Builder clearLatestMsgId() { + bitField0_ = (bitField0_ & ~0x00000008); + latestMsgId_ = 0; + + return this; + } + + private com.google.protobuf.ByteString attachData_ = com.google.protobuf.ByteString.EMPTY; + /** + * optional bytes attach_data = 20; + */ + public boolean hasAttachData() { + return ((bitField0_ & 0x00000010) == 0x00000010); + } + /** + * optional bytes attach_data = 20; + */ + public com.google.protobuf.ByteString getAttachData() { + return attachData_; + } + /** + * optional bytes attach_data = 20; + */ + public Builder setAttachData(com.google.protobuf.ByteString value) { + if (value == null) { + throw new NullPointerException(); + } + bitField0_ |= 0x00000010; + attachData_ = value; + + return this; + } + /** + * optional bytes attach_data = 20; + */ + public Builder clearAttachData() { + bitField0_ = (bitField0_ & ~0x00000010); + attachData_ = getDefaultInstance().getAttachData(); + + return this; + } + + // @@protoc_insertion_point(builder_scope:IM.Message.IMGetLatestMsgIdRsp) + } + + static { + defaultInstance = new IMGetLatestMsgIdRsp(true); + defaultInstance.initFields(); + } + + // @@protoc_insertion_point(class_scope:IM.Message.IMGetLatestMsgIdRsp) + } + + public interface IMGetMsgByIdReqOrBuilder extends + // @@protoc_insertion_point(interface_extends:IM.Message.IMGetMsgByIdReq) + com.google.protobuf.MessageLiteOrBuilder { + + /** + * required uint32 user_id = 1; + * + *
+     *cmd id: 		0x030d
+     * 
+ */ + boolean hasUserId(); + /** + * required uint32 user_id = 1; + * + *
+     *cmd id: 		0x030d
+     * 
+ */ + int getUserId(); + + /** + * required .IM.BaseDefine.SessionType session_type = 2; + */ + boolean hasSessionType(); + /** + * required .IM.BaseDefine.SessionType session_type = 2; + */ + com.mogujie.tt.protobuf.IMBaseDefine.SessionType getSessionType(); + + /** + * required uint32 session_id = 3; + */ + boolean hasSessionId(); + /** + * required uint32 session_id = 3; + */ + int getSessionId(); + + /** + * repeated uint32 msg_id_list = 4; + */ + java.util.List getMsgIdListList(); + /** + * repeated uint32 msg_id_list = 4; + */ + int getMsgIdListCount(); + /** + * repeated uint32 msg_id_list = 4; + */ + int getMsgIdList(int index); + + /** + * optional bytes attach_data = 20; + */ + boolean hasAttachData(); + /** + * optional bytes attach_data = 20; + */ + com.google.protobuf.ByteString getAttachData(); + } + /** + * Protobuf type {@code IM.Message.IMGetMsgByIdReq} + */ + public static final class IMGetMsgByIdReq extends + com.google.protobuf.GeneratedMessageLite implements + // @@protoc_insertion_point(message_implements:IM.Message.IMGetMsgByIdReq) + IMGetMsgByIdReqOrBuilder { + // Use IMGetMsgByIdReq.newBuilder() to construct. + private IMGetMsgByIdReq(com.google.protobuf.GeneratedMessageLite.Builder builder) { + super(builder); + this.unknownFields = builder.getUnknownFields(); + } + private IMGetMsgByIdReq(boolean noInit) { this.unknownFields = com.google.protobuf.ByteString.EMPTY;} + + private static final IMGetMsgByIdReq defaultInstance; + public static IMGetMsgByIdReq getDefaultInstance() { + return defaultInstance; + } + + public IMGetMsgByIdReq getDefaultInstanceForType() { + return defaultInstance; + } + + private final com.google.protobuf.ByteString unknownFields; + private IMGetMsgByIdReq( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + initFields(); + int mutable_bitField0_ = 0; + com.google.protobuf.ByteString.Output unknownFieldsOutput = + com.google.protobuf.ByteString.newOutput(); + com.google.protobuf.CodedOutputStream unknownFieldsCodedOutput = + com.google.protobuf.CodedOutputStream.newInstance( + unknownFieldsOutput); + try { + boolean done = false; + while (!done) { + int tag = input.readTag(); + switch (tag) { + case 0: + done = true; + break; + default: { + if (!parseUnknownField(input, unknownFieldsCodedOutput, + extensionRegistry, tag)) { + done = true; + } + break; + } + case 8: { + bitField0_ |= 0x00000001; + userId_ = input.readUInt32(); + break; + } + case 16: { + int rawValue = input.readEnum(); + com.mogujie.tt.protobuf.IMBaseDefine.SessionType value = com.mogujie.tt.protobuf.IMBaseDefine.SessionType.valueOf(rawValue); + if (value == null) { + unknownFieldsCodedOutput.writeRawVarint32(tag); + unknownFieldsCodedOutput.writeRawVarint32(rawValue); + } else { + bitField0_ |= 0x00000002; + sessionType_ = value; + } + break; + } + case 24: { + bitField0_ |= 0x00000004; + sessionId_ = input.readUInt32(); + break; + } + case 32: { + if (!((mutable_bitField0_ & 0x00000008) == 0x00000008)) { + msgIdList_ = new java.util.ArrayList(); + mutable_bitField0_ |= 0x00000008; + } + msgIdList_.add(input.readUInt32()); + break; + } + case 34: { + int length = input.readRawVarint32(); + int limit = input.pushLimit(length); + if (!((mutable_bitField0_ & 0x00000008) == 0x00000008) && input.getBytesUntilLimit() > 0) { + msgIdList_ = new java.util.ArrayList(); + mutable_bitField0_ |= 0x00000008; + } + while (input.getBytesUntilLimit() > 0) { + msgIdList_.add(input.readUInt32()); + } + input.popLimit(limit); + break; + } + case 162: { + bitField0_ |= 0x00000008; + attachData_ = input.readBytes(); + break; + } + } + } + } catch (com.google.protobuf.InvalidProtocolBufferException e) { + throw e.setUnfinishedMessage(this); + } catch (java.io.IOException e) { + throw new com.google.protobuf.InvalidProtocolBufferException( + e.getMessage()).setUnfinishedMessage(this); + } finally { + if (((mutable_bitField0_ & 0x00000008) == 0x00000008)) { + msgIdList_ = java.util.Collections.unmodifiableList(msgIdList_); + } + try { + unknownFieldsCodedOutput.flush(); + } catch (java.io.IOException e) { + // Should not happen + } finally { + unknownFields = unknownFieldsOutput.toByteString(); + } + makeExtensionsImmutable(); + } + } + public static com.google.protobuf.Parser PARSER = + new com.google.protobuf.AbstractParser() { + public IMGetMsgByIdReq parsePartialFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return new IMGetMsgByIdReq(input, extensionRegistry); + } + }; + + @java.lang.Override + public com.google.protobuf.Parser getParserForType() { + return PARSER; + } + + private int bitField0_; + public static final int USER_ID_FIELD_NUMBER = 1; + private int userId_; + /** + * required uint32 user_id = 1; + * + *
+     *cmd id: 		0x030d
+     * 
+ */ + public boolean hasUserId() { + return ((bitField0_ & 0x00000001) == 0x00000001); + } + /** + * required uint32 user_id = 1; + * + *
+     *cmd id: 		0x030d
+     * 
+ */ + public int getUserId() { + return userId_; + } + + public static final int SESSION_TYPE_FIELD_NUMBER = 2; + private com.mogujie.tt.protobuf.IMBaseDefine.SessionType sessionType_; + /** + * required .IM.BaseDefine.SessionType session_type = 2; + */ + public boolean hasSessionType() { + return ((bitField0_ & 0x00000002) == 0x00000002); + } + /** + * required .IM.BaseDefine.SessionType session_type = 2; + */ + public com.mogujie.tt.protobuf.IMBaseDefine.SessionType getSessionType() { + return sessionType_; + } + + public static final int SESSION_ID_FIELD_NUMBER = 3; + private int sessionId_; + /** + * required uint32 session_id = 3; + */ + public boolean hasSessionId() { + return ((bitField0_ & 0x00000004) == 0x00000004); + } + /** + * required uint32 session_id = 3; + */ + public int getSessionId() { + return sessionId_; + } + + public static final int MSG_ID_LIST_FIELD_NUMBER = 4; + private java.util.List msgIdList_; + /** + * repeated uint32 msg_id_list = 4; + */ + public java.util.List + getMsgIdListList() { + return msgIdList_; + } + /** + * repeated uint32 msg_id_list = 4; + */ + public int getMsgIdListCount() { + return msgIdList_.size(); + } + /** + * repeated uint32 msg_id_list = 4; + */ + public int getMsgIdList(int index) { + return msgIdList_.get(index); + } + + public static final int ATTACH_DATA_FIELD_NUMBER = 20; + private com.google.protobuf.ByteString attachData_; + /** + * optional bytes attach_data = 20; + */ + public boolean hasAttachData() { + return ((bitField0_ & 0x00000008) == 0x00000008); + } + /** + * optional bytes attach_data = 20; + */ + public com.google.protobuf.ByteString getAttachData() { + return attachData_; + } + + private void initFields() { + userId_ = 0; + sessionType_ = com.mogujie.tt.protobuf.IMBaseDefine.SessionType.SESSION_TYPE_SINGLE; + sessionId_ = 0; + msgIdList_ = java.util.Collections.emptyList(); + attachData_ = com.google.protobuf.ByteString.EMPTY; + } + private byte memoizedIsInitialized = -1; + public final boolean isInitialized() { + byte isInitialized = memoizedIsInitialized; + if (isInitialized == 1) return true; + if (isInitialized == 0) return false; + + if (!hasUserId()) { + memoizedIsInitialized = 0; + return false; + } + if (!hasSessionType()) { + memoizedIsInitialized = 0; + return false; + } + if (!hasSessionId()) { + memoizedIsInitialized = 0; + return false; + } + memoizedIsInitialized = 1; + return true; + } + + public void writeTo(com.google.protobuf.CodedOutputStream output) + throws java.io.IOException { + getSerializedSize(); + if (((bitField0_ & 0x00000001) == 0x00000001)) { + output.writeUInt32(1, userId_); + } + if (((bitField0_ & 0x00000002) == 0x00000002)) { + output.writeEnum(2, sessionType_.getNumber()); + } + if (((bitField0_ & 0x00000004) == 0x00000004)) { + output.writeUInt32(3, sessionId_); + } + for (int i = 0; i < msgIdList_.size(); i++) { + output.writeUInt32(4, msgIdList_.get(i)); + } + if (((bitField0_ & 0x00000008) == 0x00000008)) { + output.writeBytes(20, attachData_); + } + output.writeRawBytes(unknownFields); + } + + private int memoizedSerializedSize = -1; + public int getSerializedSize() { + int size = memoizedSerializedSize; + if (size != -1) return size; + + size = 0; + if (((bitField0_ & 0x00000001) == 0x00000001)) { + size += com.google.protobuf.CodedOutputStream + .computeUInt32Size(1, userId_); + } + if (((bitField0_ & 0x00000002) == 0x00000002)) { + size += com.google.protobuf.CodedOutputStream + .computeEnumSize(2, sessionType_.getNumber()); + } + if (((bitField0_ & 0x00000004) == 0x00000004)) { + size += com.google.protobuf.CodedOutputStream + .computeUInt32Size(3, sessionId_); + } + { + int dataSize = 0; + for (int i = 0; i < msgIdList_.size(); i++) { + dataSize += com.google.protobuf.CodedOutputStream + .computeUInt32SizeNoTag(msgIdList_.get(i)); + } + size += dataSize; + size += 1 * getMsgIdListList().size(); + } + if (((bitField0_ & 0x00000008) == 0x00000008)) { + size += com.google.protobuf.CodedOutputStream + .computeBytesSize(20, attachData_); + } + size += unknownFields.size(); + memoizedSerializedSize = size; + return size; + } + + private static final long serialVersionUID = 0L; + @java.lang.Override + protected java.lang.Object writeReplace() + throws java.io.ObjectStreamException { + return super.writeReplace(); + } + + public static com.mogujie.tt.protobuf.IMMessage.IMGetMsgByIdReq parseFrom( + com.google.protobuf.ByteString data) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data); + } + public static com.mogujie.tt.protobuf.IMMessage.IMGetMsgByIdReq parseFrom( + com.google.protobuf.ByteString data, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data, extensionRegistry); + } + public static com.mogujie.tt.protobuf.IMMessage.IMGetMsgByIdReq parseFrom(byte[] data) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data); + } + public static com.mogujie.tt.protobuf.IMMessage.IMGetMsgByIdReq parseFrom( + byte[] data, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data, extensionRegistry); + } + public static com.mogujie.tt.protobuf.IMMessage.IMGetMsgByIdReq parseFrom(java.io.InputStream input) + throws java.io.IOException { + return PARSER.parseFrom(input); + } + public static com.mogujie.tt.protobuf.IMMessage.IMGetMsgByIdReq parseFrom( + java.io.InputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return PARSER.parseFrom(input, extensionRegistry); + } + public static com.mogujie.tt.protobuf.IMMessage.IMGetMsgByIdReq parseDelimitedFrom(java.io.InputStream input) + throws java.io.IOException { + return PARSER.parseDelimitedFrom(input); + } + public static com.mogujie.tt.protobuf.IMMessage.IMGetMsgByIdReq parseDelimitedFrom( + java.io.InputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return PARSER.parseDelimitedFrom(input, extensionRegistry); + } + public static com.mogujie.tt.protobuf.IMMessage.IMGetMsgByIdReq parseFrom( + com.google.protobuf.CodedInputStream input) + throws java.io.IOException { + return PARSER.parseFrom(input); + } + public static com.mogujie.tt.protobuf.IMMessage.IMGetMsgByIdReq parseFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return PARSER.parseFrom(input, extensionRegistry); + } + + public static Builder newBuilder() { return Builder.create(); } + public Builder newBuilderForType() { return newBuilder(); } + public static Builder newBuilder(com.mogujie.tt.protobuf.IMMessage.IMGetMsgByIdReq prototype) { + return newBuilder().mergeFrom(prototype); + } + public Builder toBuilder() { return newBuilder(this); } + + /** + * Protobuf type {@code IM.Message.IMGetMsgByIdReq} + */ + public static final class Builder extends + com.google.protobuf.GeneratedMessageLite.Builder< + com.mogujie.tt.protobuf.IMMessage.IMGetMsgByIdReq, Builder> + implements + // @@protoc_insertion_point(builder_implements:IM.Message.IMGetMsgByIdReq) + com.mogujie.tt.protobuf.IMMessage.IMGetMsgByIdReqOrBuilder { + // Construct using com.mogujie.tt.protobuf.IMMessage.IMGetMsgByIdReq.newBuilder() + private Builder() { + maybeForceBuilderInitialization(); + } + + private void maybeForceBuilderInitialization() { + } + private static Builder create() { + return new Builder(); + } + + public Builder clear() { + super.clear(); + userId_ = 0; + bitField0_ = (bitField0_ & ~0x00000001); + sessionType_ = com.mogujie.tt.protobuf.IMBaseDefine.SessionType.SESSION_TYPE_SINGLE; + bitField0_ = (bitField0_ & ~0x00000002); + sessionId_ = 0; + bitField0_ = (bitField0_ & ~0x00000004); + msgIdList_ = java.util.Collections.emptyList(); + bitField0_ = (bitField0_ & ~0x00000008); + attachData_ = com.google.protobuf.ByteString.EMPTY; + bitField0_ = (bitField0_ & ~0x00000010); + return this; + } + + public Builder clone() { + return create().mergeFrom(buildPartial()); + } + + public com.mogujie.tt.protobuf.IMMessage.IMGetMsgByIdReq getDefaultInstanceForType() { + return com.mogujie.tt.protobuf.IMMessage.IMGetMsgByIdReq.getDefaultInstance(); + } + + public com.mogujie.tt.protobuf.IMMessage.IMGetMsgByIdReq build() { + com.mogujie.tt.protobuf.IMMessage.IMGetMsgByIdReq result = buildPartial(); + if (!result.isInitialized()) { + throw newUninitializedMessageException(result); + } + return result; + } + + public com.mogujie.tt.protobuf.IMMessage.IMGetMsgByIdReq buildPartial() { + com.mogujie.tt.protobuf.IMMessage.IMGetMsgByIdReq result = new com.mogujie.tt.protobuf.IMMessage.IMGetMsgByIdReq(this); + int from_bitField0_ = bitField0_; + int to_bitField0_ = 0; + if (((from_bitField0_ & 0x00000001) == 0x00000001)) { + to_bitField0_ |= 0x00000001; + } + result.userId_ = userId_; + if (((from_bitField0_ & 0x00000002) == 0x00000002)) { + to_bitField0_ |= 0x00000002; + } + result.sessionType_ = sessionType_; + if (((from_bitField0_ & 0x00000004) == 0x00000004)) { + to_bitField0_ |= 0x00000004; + } + result.sessionId_ = sessionId_; + if (((bitField0_ & 0x00000008) == 0x00000008)) { + msgIdList_ = java.util.Collections.unmodifiableList(msgIdList_); + bitField0_ = (bitField0_ & ~0x00000008); + } + result.msgIdList_ = msgIdList_; + if (((from_bitField0_ & 0x00000010) == 0x00000010)) { + to_bitField0_ |= 0x00000008; + } + result.attachData_ = attachData_; + result.bitField0_ = to_bitField0_; + return result; + } + + public Builder mergeFrom(com.mogujie.tt.protobuf.IMMessage.IMGetMsgByIdReq other) { + if (other == com.mogujie.tt.protobuf.IMMessage.IMGetMsgByIdReq.getDefaultInstance()) return this; + if (other.hasUserId()) { + setUserId(other.getUserId()); + } + if (other.hasSessionType()) { + setSessionType(other.getSessionType()); + } + if (other.hasSessionId()) { + setSessionId(other.getSessionId()); + } + if (!other.msgIdList_.isEmpty()) { + if (msgIdList_.isEmpty()) { + msgIdList_ = other.msgIdList_; + bitField0_ = (bitField0_ & ~0x00000008); + } else { + ensureMsgIdListIsMutable(); + msgIdList_.addAll(other.msgIdList_); + } + + } + if (other.hasAttachData()) { + setAttachData(other.getAttachData()); + } + setUnknownFields( + getUnknownFields().concat(other.unknownFields)); + return this; + } + + public final boolean isInitialized() { + if (!hasUserId()) { + + return false; + } + if (!hasSessionType()) { + + return false; + } + if (!hasSessionId()) { + + return false; + } + return true; + } + + public Builder mergeFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + com.mogujie.tt.protobuf.IMMessage.IMGetMsgByIdReq parsedMessage = null; + try { + parsedMessage = PARSER.parsePartialFrom(input, extensionRegistry); + } catch (com.google.protobuf.InvalidProtocolBufferException e) { + parsedMessage = (com.mogujie.tt.protobuf.IMMessage.IMGetMsgByIdReq) e.getUnfinishedMessage(); + throw e; + } finally { + if (parsedMessage != null) { + mergeFrom(parsedMessage); + } + } + return this; + } + private int bitField0_; + + private int userId_ ; + /** + * required uint32 user_id = 1; + * + *
+       *cmd id: 		0x030d
+       * 
+ */ + public boolean hasUserId() { + return ((bitField0_ & 0x00000001) == 0x00000001); + } + /** + * required uint32 user_id = 1; + * + *
+       *cmd id: 		0x030d
+       * 
+ */ + public int getUserId() { + return userId_; + } + /** + * required uint32 user_id = 1; + * + *
+       *cmd id: 		0x030d
+       * 
+ */ + public Builder setUserId(int value) { + bitField0_ |= 0x00000001; + userId_ = value; + + return this; + } + /** + * required uint32 user_id = 1; + * + *
+       *cmd id: 		0x030d
+       * 
+ */ + public Builder clearUserId() { + bitField0_ = (bitField0_ & ~0x00000001); + userId_ = 0; + + return this; + } + + private com.mogujie.tt.protobuf.IMBaseDefine.SessionType sessionType_ = com.mogujie.tt.protobuf.IMBaseDefine.SessionType.SESSION_TYPE_SINGLE; + /** + * required .IM.BaseDefine.SessionType session_type = 2; + */ + public boolean hasSessionType() { + return ((bitField0_ & 0x00000002) == 0x00000002); + } + /** + * required .IM.BaseDefine.SessionType session_type = 2; + */ + public com.mogujie.tt.protobuf.IMBaseDefine.SessionType getSessionType() { + return sessionType_; + } + /** + * required .IM.BaseDefine.SessionType session_type = 2; + */ + public Builder setSessionType(com.mogujie.tt.protobuf.IMBaseDefine.SessionType value) { + if (value == null) { + throw new NullPointerException(); + } + bitField0_ |= 0x00000002; + sessionType_ = value; + + return this; + } + /** + * required .IM.BaseDefine.SessionType session_type = 2; + */ + public Builder clearSessionType() { + bitField0_ = (bitField0_ & ~0x00000002); + sessionType_ = com.mogujie.tt.protobuf.IMBaseDefine.SessionType.SESSION_TYPE_SINGLE; + + return this; + } + + private int sessionId_ ; + /** + * required uint32 session_id = 3; + */ + public boolean hasSessionId() { + return ((bitField0_ & 0x00000004) == 0x00000004); + } + /** + * required uint32 session_id = 3; + */ + public int getSessionId() { + return sessionId_; + } + /** + * required uint32 session_id = 3; + */ + public Builder setSessionId(int value) { + bitField0_ |= 0x00000004; + sessionId_ = value; + + return this; + } + /** + * required uint32 session_id = 3; + */ + public Builder clearSessionId() { + bitField0_ = (bitField0_ & ~0x00000004); + sessionId_ = 0; + + return this; + } + + private java.util.List msgIdList_ = java.util.Collections.emptyList(); + private void ensureMsgIdListIsMutable() { + if (!((bitField0_ & 0x00000008) == 0x00000008)) { + msgIdList_ = new java.util.ArrayList(msgIdList_); + bitField0_ |= 0x00000008; + } + } + /** + * repeated uint32 msg_id_list = 4; + */ + public java.util.List + getMsgIdListList() { + return java.util.Collections.unmodifiableList(msgIdList_); + } + /** + * repeated uint32 msg_id_list = 4; + */ + public int getMsgIdListCount() { + return msgIdList_.size(); + } + /** + * repeated uint32 msg_id_list = 4; + */ + public int getMsgIdList(int index) { + return msgIdList_.get(index); + } + /** + * repeated uint32 msg_id_list = 4; + */ + public Builder setMsgIdList( + int index, int value) { + ensureMsgIdListIsMutable(); + msgIdList_.set(index, value); + + return this; + } + /** + * repeated uint32 msg_id_list = 4; + */ + public Builder addMsgIdList(int value) { + ensureMsgIdListIsMutable(); + msgIdList_.add(value); + + return this; + } + /** + * repeated uint32 msg_id_list = 4; + */ + public Builder addAllMsgIdList( + java.lang.Iterable values) { + ensureMsgIdListIsMutable(); + com.google.protobuf.AbstractMessageLite.Builder.addAll( + values, msgIdList_); + + return this; + } + /** + * repeated uint32 msg_id_list = 4; + */ + public Builder clearMsgIdList() { + msgIdList_ = java.util.Collections.emptyList(); + bitField0_ = (bitField0_ & ~0x00000008); + + return this; + } + + private com.google.protobuf.ByteString attachData_ = com.google.protobuf.ByteString.EMPTY; + /** + * optional bytes attach_data = 20; + */ + public boolean hasAttachData() { + return ((bitField0_ & 0x00000010) == 0x00000010); + } + /** + * optional bytes attach_data = 20; + */ + public com.google.protobuf.ByteString getAttachData() { + return attachData_; + } + /** + * optional bytes attach_data = 20; + */ + public Builder setAttachData(com.google.protobuf.ByteString value) { + if (value == null) { + throw new NullPointerException(); + } + bitField0_ |= 0x00000010; + attachData_ = value; + + return this; + } + /** + * optional bytes attach_data = 20; + */ + public Builder clearAttachData() { + bitField0_ = (bitField0_ & ~0x00000010); + attachData_ = getDefaultInstance().getAttachData(); + + return this; + } + + // @@protoc_insertion_point(builder_scope:IM.Message.IMGetMsgByIdReq) + } + + static { + defaultInstance = new IMGetMsgByIdReq(true); + defaultInstance.initFields(); + } + + // @@protoc_insertion_point(class_scope:IM.Message.IMGetMsgByIdReq) + } + + public interface IMGetMsgByIdRspOrBuilder extends + // @@protoc_insertion_point(interface_extends:IM.Message.IMGetMsgByIdRsp) + com.google.protobuf.MessageLiteOrBuilder { + + /** + * required uint32 user_id = 1; + * + *
+     *cmd id:		0x030e
+     * 
+ */ + boolean hasUserId(); + /** + * required uint32 user_id = 1; + * + *
+     *cmd id:		0x030e
+     * 
+ */ + int getUserId(); + + /** + * required .IM.BaseDefine.SessionType session_type = 2; + */ + boolean hasSessionType(); + /** + * required .IM.BaseDefine.SessionType session_type = 2; + */ + com.mogujie.tt.protobuf.IMBaseDefine.SessionType getSessionType(); + + /** + * required uint32 session_id = 3; + */ + boolean hasSessionId(); + /** + * required uint32 session_id = 3; + */ + int getSessionId(); + + /** + * repeated .IM.BaseDefine.MsgInfo msg_list = 4; + */ + java.util.List + getMsgListList(); + /** + * repeated .IM.BaseDefine.MsgInfo msg_list = 4; + */ + com.mogujie.tt.protobuf.IMBaseDefine.MsgInfo getMsgList(int index); + /** + * repeated .IM.BaseDefine.MsgInfo msg_list = 4; + */ + int getMsgListCount(); + + /** + * optional bytes attach_data = 20; + */ + boolean hasAttachData(); + /** + * optional bytes attach_data = 20; + */ + com.google.protobuf.ByteString getAttachData(); + } + /** + * Protobuf type {@code IM.Message.IMGetMsgByIdRsp} + */ + public static final class IMGetMsgByIdRsp extends + com.google.protobuf.GeneratedMessageLite implements + // @@protoc_insertion_point(message_implements:IM.Message.IMGetMsgByIdRsp) + IMGetMsgByIdRspOrBuilder { + // Use IMGetMsgByIdRsp.newBuilder() to construct. + private IMGetMsgByIdRsp(com.google.protobuf.GeneratedMessageLite.Builder builder) { + super(builder); + this.unknownFields = builder.getUnknownFields(); + } + private IMGetMsgByIdRsp(boolean noInit) { this.unknownFields = com.google.protobuf.ByteString.EMPTY;} + + private static final IMGetMsgByIdRsp defaultInstance; + public static IMGetMsgByIdRsp getDefaultInstance() { + return defaultInstance; + } + + public IMGetMsgByIdRsp getDefaultInstanceForType() { + return defaultInstance; + } + + private final com.google.protobuf.ByteString unknownFields; + private IMGetMsgByIdRsp( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + initFields(); + int mutable_bitField0_ = 0; + com.google.protobuf.ByteString.Output unknownFieldsOutput = + com.google.protobuf.ByteString.newOutput(); + com.google.protobuf.CodedOutputStream unknownFieldsCodedOutput = + com.google.protobuf.CodedOutputStream.newInstance( + unknownFieldsOutput); + try { + boolean done = false; + while (!done) { + int tag = input.readTag(); + switch (tag) { + case 0: + done = true; + break; + default: { + if (!parseUnknownField(input, unknownFieldsCodedOutput, + extensionRegistry, tag)) { + done = true; + } + break; + } + case 8: { + bitField0_ |= 0x00000001; + userId_ = input.readUInt32(); + break; + } + case 16: { + int rawValue = input.readEnum(); + com.mogujie.tt.protobuf.IMBaseDefine.SessionType value = com.mogujie.tt.protobuf.IMBaseDefine.SessionType.valueOf(rawValue); + if (value == null) { + unknownFieldsCodedOutput.writeRawVarint32(tag); + unknownFieldsCodedOutput.writeRawVarint32(rawValue); + } else { + bitField0_ |= 0x00000002; + sessionType_ = value; + } + break; + } + case 24: { + bitField0_ |= 0x00000004; + sessionId_ = input.readUInt32(); + break; + } + case 34: { + if (!((mutable_bitField0_ & 0x00000008) == 0x00000008)) { + msgList_ = new java.util.ArrayList(); + mutable_bitField0_ |= 0x00000008; + } + msgList_.add(input.readMessage(com.mogujie.tt.protobuf.IMBaseDefine.MsgInfo.PARSER, extensionRegistry)); + break; + } + case 162: { + bitField0_ |= 0x00000008; + attachData_ = input.readBytes(); + break; + } + } + } + } catch (com.google.protobuf.InvalidProtocolBufferException e) { + throw e.setUnfinishedMessage(this); + } catch (java.io.IOException e) { + throw new com.google.protobuf.InvalidProtocolBufferException( + e.getMessage()).setUnfinishedMessage(this); + } finally { + if (((mutable_bitField0_ & 0x00000008) == 0x00000008)) { + msgList_ = java.util.Collections.unmodifiableList(msgList_); + } + try { + unknownFieldsCodedOutput.flush(); + } catch (java.io.IOException e) { + // Should not happen + } finally { + unknownFields = unknownFieldsOutput.toByteString(); + } + makeExtensionsImmutable(); + } + } + public static com.google.protobuf.Parser PARSER = + new com.google.protobuf.AbstractParser() { + public IMGetMsgByIdRsp parsePartialFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return new IMGetMsgByIdRsp(input, extensionRegistry); + } + }; + + @java.lang.Override + public com.google.protobuf.Parser getParserForType() { + return PARSER; + } + + private int bitField0_; + public static final int USER_ID_FIELD_NUMBER = 1; + private int userId_; + /** + * required uint32 user_id = 1; + * + *
+     *cmd id:		0x030e
+     * 
+ */ + public boolean hasUserId() { + return ((bitField0_ & 0x00000001) == 0x00000001); + } + /** + * required uint32 user_id = 1; + * + *
+     *cmd id:		0x030e
+     * 
+ */ + public int getUserId() { + return userId_; + } + + public static final int SESSION_TYPE_FIELD_NUMBER = 2; + private com.mogujie.tt.protobuf.IMBaseDefine.SessionType sessionType_; + /** + * required .IM.BaseDefine.SessionType session_type = 2; + */ + public boolean hasSessionType() { + return ((bitField0_ & 0x00000002) == 0x00000002); + } + /** + * required .IM.BaseDefine.SessionType session_type = 2; + */ + public com.mogujie.tt.protobuf.IMBaseDefine.SessionType getSessionType() { + return sessionType_; + } + + public static final int SESSION_ID_FIELD_NUMBER = 3; + private int sessionId_; + /** + * required uint32 session_id = 3; + */ + public boolean hasSessionId() { + return ((bitField0_ & 0x00000004) == 0x00000004); + } + /** + * required uint32 session_id = 3; + */ + public int getSessionId() { + return sessionId_; + } + + public static final int MSG_LIST_FIELD_NUMBER = 4; + private java.util.List msgList_; + /** + * repeated .IM.BaseDefine.MsgInfo msg_list = 4; + */ + public java.util.List getMsgListList() { + return msgList_; + } + /** + * repeated .IM.BaseDefine.MsgInfo msg_list = 4; + */ + public java.util.List + getMsgListOrBuilderList() { + return msgList_; + } + /** + * repeated .IM.BaseDefine.MsgInfo msg_list = 4; + */ + public int getMsgListCount() { + return msgList_.size(); + } + /** + * repeated .IM.BaseDefine.MsgInfo msg_list = 4; + */ + public com.mogujie.tt.protobuf.IMBaseDefine.MsgInfo getMsgList(int index) { + return msgList_.get(index); + } + /** + * repeated .IM.BaseDefine.MsgInfo msg_list = 4; + */ + public com.mogujie.tt.protobuf.IMBaseDefine.MsgInfoOrBuilder getMsgListOrBuilder( + int index) { + return msgList_.get(index); + } + + public static final int ATTACH_DATA_FIELD_NUMBER = 20; + private com.google.protobuf.ByteString attachData_; + /** + * optional bytes attach_data = 20; + */ + public boolean hasAttachData() { + return ((bitField0_ & 0x00000008) == 0x00000008); + } + /** + * optional bytes attach_data = 20; + */ + public com.google.protobuf.ByteString getAttachData() { + return attachData_; + } + + private void initFields() { + userId_ = 0; + sessionType_ = com.mogujie.tt.protobuf.IMBaseDefine.SessionType.SESSION_TYPE_SINGLE; + sessionId_ = 0; + msgList_ = java.util.Collections.emptyList(); + attachData_ = com.google.protobuf.ByteString.EMPTY; + } + private byte memoizedIsInitialized = -1; + public final boolean isInitialized() { + byte isInitialized = memoizedIsInitialized; + if (isInitialized == 1) return true; + if (isInitialized == 0) return false; + + if (!hasUserId()) { + memoizedIsInitialized = 0; + return false; + } + if (!hasSessionType()) { + memoizedIsInitialized = 0; + return false; + } + if (!hasSessionId()) { + memoizedIsInitialized = 0; + return false; + } + for (int i = 0; i < getMsgListCount(); i++) { + if (!getMsgList(i).isInitialized()) { + memoizedIsInitialized = 0; + return false; + } + } + memoizedIsInitialized = 1; + return true; + } + + public void writeTo(com.google.protobuf.CodedOutputStream output) + throws java.io.IOException { + getSerializedSize(); + if (((bitField0_ & 0x00000001) == 0x00000001)) { + output.writeUInt32(1, userId_); + } + if (((bitField0_ & 0x00000002) == 0x00000002)) { + output.writeEnum(2, sessionType_.getNumber()); + } + if (((bitField0_ & 0x00000004) == 0x00000004)) { + output.writeUInt32(3, sessionId_); + } + for (int i = 0; i < msgList_.size(); i++) { + output.writeMessage(4, msgList_.get(i)); + } + if (((bitField0_ & 0x00000008) == 0x00000008)) { + output.writeBytes(20, attachData_); + } + output.writeRawBytes(unknownFields); + } + + private int memoizedSerializedSize = -1; + public int getSerializedSize() { + int size = memoizedSerializedSize; + if (size != -1) return size; + + size = 0; + if (((bitField0_ & 0x00000001) == 0x00000001)) { + size += com.google.protobuf.CodedOutputStream + .computeUInt32Size(1, userId_); + } + if (((bitField0_ & 0x00000002) == 0x00000002)) { + size += com.google.protobuf.CodedOutputStream + .computeEnumSize(2, sessionType_.getNumber()); + } + if (((bitField0_ & 0x00000004) == 0x00000004)) { + size += com.google.protobuf.CodedOutputStream + .computeUInt32Size(3, sessionId_); + } + for (int i = 0; i < msgList_.size(); i++) { + size += com.google.protobuf.CodedOutputStream + .computeMessageSize(4, msgList_.get(i)); + } + if (((bitField0_ & 0x00000008) == 0x00000008)) { + size += com.google.protobuf.CodedOutputStream + .computeBytesSize(20, attachData_); + } + size += unknownFields.size(); + memoizedSerializedSize = size; + return size; + } + + private static final long serialVersionUID = 0L; + @java.lang.Override + protected java.lang.Object writeReplace() + throws java.io.ObjectStreamException { + return super.writeReplace(); + } + + public static com.mogujie.tt.protobuf.IMMessage.IMGetMsgByIdRsp parseFrom( + com.google.protobuf.ByteString data) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data); + } + public static com.mogujie.tt.protobuf.IMMessage.IMGetMsgByIdRsp parseFrom( + com.google.protobuf.ByteString data, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data, extensionRegistry); + } + public static com.mogujie.tt.protobuf.IMMessage.IMGetMsgByIdRsp parseFrom(byte[] data) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data); + } + public static com.mogujie.tt.protobuf.IMMessage.IMGetMsgByIdRsp parseFrom( + byte[] data, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data, extensionRegistry); + } + public static com.mogujie.tt.protobuf.IMMessage.IMGetMsgByIdRsp parseFrom(java.io.InputStream input) + throws java.io.IOException { + return PARSER.parseFrom(input); + } + public static com.mogujie.tt.protobuf.IMMessage.IMGetMsgByIdRsp parseFrom( + java.io.InputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return PARSER.parseFrom(input, extensionRegistry); + } + public static com.mogujie.tt.protobuf.IMMessage.IMGetMsgByIdRsp parseDelimitedFrom(java.io.InputStream input) + throws java.io.IOException { + return PARSER.parseDelimitedFrom(input); + } + public static com.mogujie.tt.protobuf.IMMessage.IMGetMsgByIdRsp parseDelimitedFrom( + java.io.InputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return PARSER.parseDelimitedFrom(input, extensionRegistry); + } + public static com.mogujie.tt.protobuf.IMMessage.IMGetMsgByIdRsp parseFrom( + com.google.protobuf.CodedInputStream input) + throws java.io.IOException { + return PARSER.parseFrom(input); + } + public static com.mogujie.tt.protobuf.IMMessage.IMGetMsgByIdRsp parseFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return PARSER.parseFrom(input, extensionRegistry); + } + + public static Builder newBuilder() { return Builder.create(); } + public Builder newBuilderForType() { return newBuilder(); } + public static Builder newBuilder(com.mogujie.tt.protobuf.IMMessage.IMGetMsgByIdRsp prototype) { + return newBuilder().mergeFrom(prototype); + } + public Builder toBuilder() { return newBuilder(this); } + + /** + * Protobuf type {@code IM.Message.IMGetMsgByIdRsp} + */ + public static final class Builder extends + com.google.protobuf.GeneratedMessageLite.Builder< + com.mogujie.tt.protobuf.IMMessage.IMGetMsgByIdRsp, Builder> + implements + // @@protoc_insertion_point(builder_implements:IM.Message.IMGetMsgByIdRsp) + com.mogujie.tt.protobuf.IMMessage.IMGetMsgByIdRspOrBuilder { + // Construct using com.mogujie.tt.protobuf.IMMessage.IMGetMsgByIdRsp.newBuilder() + private Builder() { + maybeForceBuilderInitialization(); + } + + private void maybeForceBuilderInitialization() { + } + private static Builder create() { + return new Builder(); + } + + public Builder clear() { + super.clear(); + userId_ = 0; + bitField0_ = (bitField0_ & ~0x00000001); + sessionType_ = com.mogujie.tt.protobuf.IMBaseDefine.SessionType.SESSION_TYPE_SINGLE; + bitField0_ = (bitField0_ & ~0x00000002); + sessionId_ = 0; + bitField0_ = (bitField0_ & ~0x00000004); + msgList_ = java.util.Collections.emptyList(); + bitField0_ = (bitField0_ & ~0x00000008); + attachData_ = com.google.protobuf.ByteString.EMPTY; + bitField0_ = (bitField0_ & ~0x00000010); + return this; + } + + public Builder clone() { + return create().mergeFrom(buildPartial()); + } + + public com.mogujie.tt.protobuf.IMMessage.IMGetMsgByIdRsp getDefaultInstanceForType() { + return com.mogujie.tt.protobuf.IMMessage.IMGetMsgByIdRsp.getDefaultInstance(); + } + + public com.mogujie.tt.protobuf.IMMessage.IMGetMsgByIdRsp build() { + com.mogujie.tt.protobuf.IMMessage.IMGetMsgByIdRsp result = buildPartial(); + if (!result.isInitialized()) { + throw newUninitializedMessageException(result); + } + return result; + } + + public com.mogujie.tt.protobuf.IMMessage.IMGetMsgByIdRsp buildPartial() { + com.mogujie.tt.protobuf.IMMessage.IMGetMsgByIdRsp result = new com.mogujie.tt.protobuf.IMMessage.IMGetMsgByIdRsp(this); + int from_bitField0_ = bitField0_; + int to_bitField0_ = 0; + if (((from_bitField0_ & 0x00000001) == 0x00000001)) { + to_bitField0_ |= 0x00000001; + } + result.userId_ = userId_; + if (((from_bitField0_ & 0x00000002) == 0x00000002)) { + to_bitField0_ |= 0x00000002; + } + result.sessionType_ = sessionType_; + if (((from_bitField0_ & 0x00000004) == 0x00000004)) { + to_bitField0_ |= 0x00000004; + } + result.sessionId_ = sessionId_; + if (((bitField0_ & 0x00000008) == 0x00000008)) { + msgList_ = java.util.Collections.unmodifiableList(msgList_); + bitField0_ = (bitField0_ & ~0x00000008); + } + result.msgList_ = msgList_; + if (((from_bitField0_ & 0x00000010) == 0x00000010)) { + to_bitField0_ |= 0x00000008; + } + result.attachData_ = attachData_; + result.bitField0_ = to_bitField0_; + return result; + } + + public Builder mergeFrom(com.mogujie.tt.protobuf.IMMessage.IMGetMsgByIdRsp other) { + if (other == com.mogujie.tt.protobuf.IMMessage.IMGetMsgByIdRsp.getDefaultInstance()) return this; + if (other.hasUserId()) { + setUserId(other.getUserId()); + } + if (other.hasSessionType()) { + setSessionType(other.getSessionType()); + } + if (other.hasSessionId()) { + setSessionId(other.getSessionId()); + } + if (!other.msgList_.isEmpty()) { + if (msgList_.isEmpty()) { + msgList_ = other.msgList_; + bitField0_ = (bitField0_ & ~0x00000008); + } else { + ensureMsgListIsMutable(); + msgList_.addAll(other.msgList_); + } + + } + if (other.hasAttachData()) { + setAttachData(other.getAttachData()); + } + setUnknownFields( + getUnknownFields().concat(other.unknownFields)); + return this; + } + + public final boolean isInitialized() { + if (!hasUserId()) { + + return false; + } + if (!hasSessionType()) { + + return false; + } + if (!hasSessionId()) { + + return false; + } + for (int i = 0; i < getMsgListCount(); i++) { + if (!getMsgList(i).isInitialized()) { + + return false; + } + } + return true; + } + + public Builder mergeFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + com.mogujie.tt.protobuf.IMMessage.IMGetMsgByIdRsp parsedMessage = null; + try { + parsedMessage = PARSER.parsePartialFrom(input, extensionRegistry); + } catch (com.google.protobuf.InvalidProtocolBufferException e) { + parsedMessage = (com.mogujie.tt.protobuf.IMMessage.IMGetMsgByIdRsp) e.getUnfinishedMessage(); + throw e; + } finally { + if (parsedMessage != null) { + mergeFrom(parsedMessage); + } + } + return this; + } + private int bitField0_; + + private int userId_ ; + /** + * required uint32 user_id = 1; + * + *
+       *cmd id:		0x030e
+       * 
+ */ + public boolean hasUserId() { + return ((bitField0_ & 0x00000001) == 0x00000001); + } + /** + * required uint32 user_id = 1; + * + *
+       *cmd id:		0x030e
+       * 
+ */ + public int getUserId() { + return userId_; + } + /** + * required uint32 user_id = 1; + * + *
+       *cmd id:		0x030e
+       * 
+ */ + public Builder setUserId(int value) { + bitField0_ |= 0x00000001; + userId_ = value; + + return this; + } + /** + * required uint32 user_id = 1; + * + *
+       *cmd id:		0x030e
+       * 
+ */ + public Builder clearUserId() { + bitField0_ = (bitField0_ & ~0x00000001); + userId_ = 0; + + return this; + } + + private com.mogujie.tt.protobuf.IMBaseDefine.SessionType sessionType_ = com.mogujie.tt.protobuf.IMBaseDefine.SessionType.SESSION_TYPE_SINGLE; + /** + * required .IM.BaseDefine.SessionType session_type = 2; + */ + public boolean hasSessionType() { + return ((bitField0_ & 0x00000002) == 0x00000002); + } + /** + * required .IM.BaseDefine.SessionType session_type = 2; + */ + public com.mogujie.tt.protobuf.IMBaseDefine.SessionType getSessionType() { + return sessionType_; + } + /** + * required .IM.BaseDefine.SessionType session_type = 2; + */ + public Builder setSessionType(com.mogujie.tt.protobuf.IMBaseDefine.SessionType value) { + if (value == null) { + throw new NullPointerException(); + } + bitField0_ |= 0x00000002; + sessionType_ = value; + + return this; + } + /** + * required .IM.BaseDefine.SessionType session_type = 2; + */ + public Builder clearSessionType() { + bitField0_ = (bitField0_ & ~0x00000002); + sessionType_ = com.mogujie.tt.protobuf.IMBaseDefine.SessionType.SESSION_TYPE_SINGLE; + + return this; + } + + private int sessionId_ ; + /** + * required uint32 session_id = 3; + */ + public boolean hasSessionId() { + return ((bitField0_ & 0x00000004) == 0x00000004); + } + /** + * required uint32 session_id = 3; + */ + public int getSessionId() { + return sessionId_; + } + /** + * required uint32 session_id = 3; + */ + public Builder setSessionId(int value) { + bitField0_ |= 0x00000004; + sessionId_ = value; + + return this; + } + /** + * required uint32 session_id = 3; + */ + public Builder clearSessionId() { + bitField0_ = (bitField0_ & ~0x00000004); + sessionId_ = 0; + + return this; + } + + private java.util.List msgList_ = + java.util.Collections.emptyList(); + private void ensureMsgListIsMutable() { + if (!((bitField0_ & 0x00000008) == 0x00000008)) { + msgList_ = new java.util.ArrayList(msgList_); + bitField0_ |= 0x00000008; + } + } + + /** + * repeated .IM.BaseDefine.MsgInfo msg_list = 4; + */ + public java.util.List getMsgListList() { + return java.util.Collections.unmodifiableList(msgList_); + } + /** + * repeated .IM.BaseDefine.MsgInfo msg_list = 4; + */ + public int getMsgListCount() { + return msgList_.size(); + } + /** + * repeated .IM.BaseDefine.MsgInfo msg_list = 4; + */ + public com.mogujie.tt.protobuf.IMBaseDefine.MsgInfo getMsgList(int index) { + return msgList_.get(index); + } + /** + * repeated .IM.BaseDefine.MsgInfo msg_list = 4; + */ + public Builder setMsgList( + int index, com.mogujie.tt.protobuf.IMBaseDefine.MsgInfo value) { + if (value == null) { + throw new NullPointerException(); + } + ensureMsgListIsMutable(); + msgList_.set(index, value); + + return this; + } + /** + * repeated .IM.BaseDefine.MsgInfo msg_list = 4; + */ + public Builder setMsgList( + int index, com.mogujie.tt.protobuf.IMBaseDefine.MsgInfo.Builder builderForValue) { + ensureMsgListIsMutable(); + msgList_.set(index, builderForValue.build()); + + return this; + } + /** + * repeated .IM.BaseDefine.MsgInfo msg_list = 4; + */ + public Builder addMsgList(com.mogujie.tt.protobuf.IMBaseDefine.MsgInfo value) { + if (value == null) { + throw new NullPointerException(); + } + ensureMsgListIsMutable(); + msgList_.add(value); + + return this; + } + /** + * repeated .IM.BaseDefine.MsgInfo msg_list = 4; + */ + public Builder addMsgList( + int index, com.mogujie.tt.protobuf.IMBaseDefine.MsgInfo value) { + if (value == null) { + throw new NullPointerException(); + } + ensureMsgListIsMutable(); + msgList_.add(index, value); + + return this; + } + /** + * repeated .IM.BaseDefine.MsgInfo msg_list = 4; + */ + public Builder addMsgList( + com.mogujie.tt.protobuf.IMBaseDefine.MsgInfo.Builder builderForValue) { + ensureMsgListIsMutable(); + msgList_.add(builderForValue.build()); + + return this; + } + /** + * repeated .IM.BaseDefine.MsgInfo msg_list = 4; + */ + public Builder addMsgList( + int index, com.mogujie.tt.protobuf.IMBaseDefine.MsgInfo.Builder builderForValue) { + ensureMsgListIsMutable(); + msgList_.add(index, builderForValue.build()); + + return this; + } + /** + * repeated .IM.BaseDefine.MsgInfo msg_list = 4; + */ + public Builder addAllMsgList( + java.lang.Iterable values) { + ensureMsgListIsMutable(); + com.google.protobuf.AbstractMessageLite.Builder.addAll( + values, msgList_); + + return this; + } + /** + * repeated .IM.BaseDefine.MsgInfo msg_list = 4; + */ + public Builder clearMsgList() { + msgList_ = java.util.Collections.emptyList(); + bitField0_ = (bitField0_ & ~0x00000008); + + return this; + } + /** + * repeated .IM.BaseDefine.MsgInfo msg_list = 4; + */ + public Builder removeMsgList(int index) { + ensureMsgListIsMutable(); + msgList_.remove(index); + + return this; + } + + private com.google.protobuf.ByteString attachData_ = com.google.protobuf.ByteString.EMPTY; + /** + * optional bytes attach_data = 20; + */ + public boolean hasAttachData() { + return ((bitField0_ & 0x00000010) == 0x00000010); + } + /** + * optional bytes attach_data = 20; + */ + public com.google.protobuf.ByteString getAttachData() { + return attachData_; + } + /** + * optional bytes attach_data = 20; + */ + public Builder setAttachData(com.google.protobuf.ByteString value) { + if (value == null) { + throw new NullPointerException(); + } + bitField0_ |= 0x00000010; + attachData_ = value; + + return this; + } + /** + * optional bytes attach_data = 20; + */ + public Builder clearAttachData() { + bitField0_ = (bitField0_ & ~0x00000010); + attachData_ = getDefaultInstance().getAttachData(); + + return this; + } + + // @@protoc_insertion_point(builder_scope:IM.Message.IMGetMsgByIdRsp) + } + + static { + defaultInstance = new IMGetMsgByIdRsp(true); + defaultInstance.initFields(); + } + + // @@protoc_insertion_point(class_scope:IM.Message.IMGetMsgByIdRsp) + } + + + static { + } + + // @@protoc_insertion_point(outer_class_scope) +} diff --git a/android/app/src/main/java/com/mogujie/tt/protobuf/IMOther.java b/android/app/src/main/java/com/mogujie/tt/protobuf/IMOther.java new file mode 100644 index 000000000..2455b6023 --- /dev/null +++ b/android/app/src/main/java/com/mogujie/tt/protobuf/IMOther.java @@ -0,0 +1,292 @@ +// Generated by the protocol buffer compiler. DO NOT EDIT! +// source: IM.Other.proto + +package com.mogujie.tt.protobuf; + +public final class IMOther { + private IMOther() {} + public static void registerAllExtensions( + com.google.protobuf.ExtensionRegistryLite registry) { + } + public interface IMHeartBeatOrBuilder extends + // @@protoc_insertion_point(interface_extends:IM.Other.IMHeartBeat) + com.google.protobuf.MessageLiteOrBuilder { + } + /** + * Protobuf type {@code IM.Other.IMHeartBeat} + * + *
+   *cmd id:  		0x0701
+   * 
+ */ + public static final class IMHeartBeat extends + com.google.protobuf.GeneratedMessageLite implements + // @@protoc_insertion_point(message_implements:IM.Other.IMHeartBeat) + IMHeartBeatOrBuilder { + // Use IMHeartBeat.newBuilder() to construct. + private IMHeartBeat(com.google.protobuf.GeneratedMessageLite.Builder builder) { + super(builder); + this.unknownFields = builder.getUnknownFields(); + } + private IMHeartBeat(boolean noInit) { this.unknownFields = com.google.protobuf.ByteString.EMPTY;} + + private static final IMHeartBeat defaultInstance; + public static IMHeartBeat getDefaultInstance() { + return defaultInstance; + } + + public IMHeartBeat getDefaultInstanceForType() { + return defaultInstance; + } + + private final com.google.protobuf.ByteString unknownFields; + private IMHeartBeat( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + initFields(); + com.google.protobuf.ByteString.Output unknownFieldsOutput = + com.google.protobuf.ByteString.newOutput(); + com.google.protobuf.CodedOutputStream unknownFieldsCodedOutput = + com.google.protobuf.CodedOutputStream.newInstance( + unknownFieldsOutput); + try { + boolean done = false; + while (!done) { + int tag = input.readTag(); + switch (tag) { + case 0: + done = true; + break; + default: { + if (!parseUnknownField(input, unknownFieldsCodedOutput, + extensionRegistry, tag)) { + done = true; + } + break; + } + } + } + } catch (com.google.protobuf.InvalidProtocolBufferException e) { + throw e.setUnfinishedMessage(this); + } catch (java.io.IOException e) { + throw new com.google.protobuf.InvalidProtocolBufferException( + e.getMessage()).setUnfinishedMessage(this); + } finally { + try { + unknownFieldsCodedOutput.flush(); + } catch (java.io.IOException e) { + // Should not happen + } finally { + unknownFields = unknownFieldsOutput.toByteString(); + } + makeExtensionsImmutable(); + } + } + public static com.google.protobuf.Parser PARSER = + new com.google.protobuf.AbstractParser() { + public IMHeartBeat parsePartialFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return new IMHeartBeat(input, extensionRegistry); + } + }; + + @java.lang.Override + public com.google.protobuf.Parser getParserForType() { + return PARSER; + } + + private void initFields() { + } + private byte memoizedIsInitialized = -1; + public final boolean isInitialized() { + byte isInitialized = memoizedIsInitialized; + if (isInitialized == 1) return true; + if (isInitialized == 0) return false; + + memoizedIsInitialized = 1; + return true; + } + + public void writeTo(com.google.protobuf.CodedOutputStream output) + throws java.io.IOException { + getSerializedSize(); + output.writeRawBytes(unknownFields); + } + + private int memoizedSerializedSize = -1; + public int getSerializedSize() { + int size = memoizedSerializedSize; + if (size != -1) return size; + + size = 0; + size += unknownFields.size(); + memoizedSerializedSize = size; + return size; + } + + private static final long serialVersionUID = 0L; + @java.lang.Override + protected java.lang.Object writeReplace() + throws java.io.ObjectStreamException { + return super.writeReplace(); + } + + public static com.mogujie.tt.protobuf.IMOther.IMHeartBeat parseFrom( + com.google.protobuf.ByteString data) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data); + } + public static com.mogujie.tt.protobuf.IMOther.IMHeartBeat parseFrom( + com.google.protobuf.ByteString data, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data, extensionRegistry); + } + public static com.mogujie.tt.protobuf.IMOther.IMHeartBeat parseFrom(byte[] data) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data); + } + public static com.mogujie.tt.protobuf.IMOther.IMHeartBeat parseFrom( + byte[] data, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data, extensionRegistry); + } + public static com.mogujie.tt.protobuf.IMOther.IMHeartBeat parseFrom(java.io.InputStream input) + throws java.io.IOException { + return PARSER.parseFrom(input); + } + public static com.mogujie.tt.protobuf.IMOther.IMHeartBeat parseFrom( + java.io.InputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return PARSER.parseFrom(input, extensionRegistry); + } + public static com.mogujie.tt.protobuf.IMOther.IMHeartBeat parseDelimitedFrom(java.io.InputStream input) + throws java.io.IOException { + return PARSER.parseDelimitedFrom(input); + } + public static com.mogujie.tt.protobuf.IMOther.IMHeartBeat parseDelimitedFrom( + java.io.InputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return PARSER.parseDelimitedFrom(input, extensionRegistry); + } + public static com.mogujie.tt.protobuf.IMOther.IMHeartBeat parseFrom( + com.google.protobuf.CodedInputStream input) + throws java.io.IOException { + return PARSER.parseFrom(input); + } + public static com.mogujie.tt.protobuf.IMOther.IMHeartBeat parseFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return PARSER.parseFrom(input, extensionRegistry); + } + + public static Builder newBuilder() { return Builder.create(); } + public Builder newBuilderForType() { return newBuilder(); } + public static Builder newBuilder(com.mogujie.tt.protobuf.IMOther.IMHeartBeat prototype) { + return newBuilder().mergeFrom(prototype); + } + public Builder toBuilder() { return newBuilder(this); } + + /** + * Protobuf type {@code IM.Other.IMHeartBeat} + * + *
+     *cmd id:  		0x0701
+     * 
+ */ + public static final class Builder extends + com.google.protobuf.GeneratedMessageLite.Builder< + com.mogujie.tt.protobuf.IMOther.IMHeartBeat, Builder> + implements + // @@protoc_insertion_point(builder_implements:IM.Other.IMHeartBeat) + com.mogujie.tt.protobuf.IMOther.IMHeartBeatOrBuilder { + // Construct using com.mogujie.tt.protobuf.IMOther.IMHeartBeat.newBuilder() + private Builder() { + maybeForceBuilderInitialization(); + } + + private void maybeForceBuilderInitialization() { + } + private static Builder create() { + return new Builder(); + } + + public Builder clear() { + super.clear(); + return this; + } + + public Builder clone() { + return create().mergeFrom(buildPartial()); + } + + public com.mogujie.tt.protobuf.IMOther.IMHeartBeat getDefaultInstanceForType() { + return com.mogujie.tt.protobuf.IMOther.IMHeartBeat.getDefaultInstance(); + } + + public com.mogujie.tt.protobuf.IMOther.IMHeartBeat build() { + com.mogujie.tt.protobuf.IMOther.IMHeartBeat result = buildPartial(); + if (!result.isInitialized()) { + throw newUninitializedMessageException(result); + } + return result; + } + + public com.mogujie.tt.protobuf.IMOther.IMHeartBeat buildPartial() { + com.mogujie.tt.protobuf.IMOther.IMHeartBeat result = new com.mogujie.tt.protobuf.IMOther.IMHeartBeat(this); + return result; + } + + public Builder mergeFrom(com.mogujie.tt.protobuf.IMOther.IMHeartBeat other) { + if (other == com.mogujie.tt.protobuf.IMOther.IMHeartBeat.getDefaultInstance()) return this; + setUnknownFields( + getUnknownFields().concat(other.unknownFields)); + return this; + } + + public final boolean isInitialized() { + return true; + } + + public Builder mergeFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + com.mogujie.tt.protobuf.IMOther.IMHeartBeat parsedMessage = null; + try { + parsedMessage = PARSER.parsePartialFrom(input, extensionRegistry); + } catch (com.google.protobuf.InvalidProtocolBufferException e) { + parsedMessage = (com.mogujie.tt.protobuf.IMOther.IMHeartBeat) e.getUnfinishedMessage(); + throw e; + } finally { + if (parsedMessage != null) { + mergeFrom(parsedMessage); + } + } + return this; + } + + // @@protoc_insertion_point(builder_scope:IM.Other.IMHeartBeat) + } + + static { + defaultInstance = new IMHeartBeat(true); + defaultInstance.initFields(); + } + + // @@protoc_insertion_point(class_scope:IM.Other.IMHeartBeat) + } + + + static { + } + + // @@protoc_insertion_point(outer_class_scope) +} diff --git a/android/app/src/main/java/com/mogujie/tt/protobuf/IMSwitchService.java b/android/app/src/main/java/com/mogujie/tt/protobuf/IMSwitchService.java new file mode 100644 index 000000000..24d57f25b --- /dev/null +++ b/android/app/src/main/java/com/mogujie/tt/protobuf/IMSwitchService.java @@ -0,0 +1,659 @@ +// Generated by the protocol buffer compiler. DO NOT EDIT! +// source: IM.SwitchService.proto + +package com.mogujie.tt.protobuf; + +public final class IMSwitchService { + private IMSwitchService() {} + public static void registerAllExtensions( + com.google.protobuf.ExtensionRegistryLite registry) { + } + public interface IMP2PCmdMsgOrBuilder extends + // @@protoc_insertion_point(interface_extends:IM.SwitchService.IMP2PCmdMsg) + com.google.protobuf.MessageLiteOrBuilder { + + /** + * required uint32 from_user_id = 1; + * + *
+     *cmd id:		0x0601
+     * 
+ */ + boolean hasFromUserId(); + /** + * required uint32 from_user_id = 1; + * + *
+     *cmd id:		0x0601
+     * 
+ */ + int getFromUserId(); + + /** + * required uint32 to_user_id = 2; + */ + boolean hasToUserId(); + /** + * required uint32 to_user_id = 2; + */ + int getToUserId(); + + /** + * required string cmd_msg_data = 3; + */ + boolean hasCmdMsgData(); + /** + * required string cmd_msg_data = 3; + */ + java.lang.String getCmdMsgData(); + /** + * required string cmd_msg_data = 3; + */ + com.google.protobuf.ByteString + getCmdMsgDataBytes(); + } + /** + * Protobuf type {@code IM.SwitchService.IMP2PCmdMsg} + */ + public static final class IMP2PCmdMsg extends + com.google.protobuf.GeneratedMessageLite implements + // @@protoc_insertion_point(message_implements:IM.SwitchService.IMP2PCmdMsg) + IMP2PCmdMsgOrBuilder { + // Use IMP2PCmdMsg.newBuilder() to construct. + private IMP2PCmdMsg(com.google.protobuf.GeneratedMessageLite.Builder builder) { + super(builder); + this.unknownFields = builder.getUnknownFields(); + } + private IMP2PCmdMsg(boolean noInit) { this.unknownFields = com.google.protobuf.ByteString.EMPTY;} + + private static final IMP2PCmdMsg defaultInstance; + public static IMP2PCmdMsg getDefaultInstance() { + return defaultInstance; + } + + public IMP2PCmdMsg getDefaultInstanceForType() { + return defaultInstance; + } + + private final com.google.protobuf.ByteString unknownFields; + private IMP2PCmdMsg( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + initFields(); + int mutable_bitField0_ = 0; + com.google.protobuf.ByteString.Output unknownFieldsOutput = + com.google.protobuf.ByteString.newOutput(); + com.google.protobuf.CodedOutputStream unknownFieldsCodedOutput = + com.google.protobuf.CodedOutputStream.newInstance( + unknownFieldsOutput); + try { + boolean done = false; + while (!done) { + int tag = input.readTag(); + switch (tag) { + case 0: + done = true; + break; + default: { + if (!parseUnknownField(input, unknownFieldsCodedOutput, + extensionRegistry, tag)) { + done = true; + } + break; + } + case 8: { + bitField0_ |= 0x00000001; + fromUserId_ = input.readUInt32(); + break; + } + case 16: { + bitField0_ |= 0x00000002; + toUserId_ = input.readUInt32(); + break; + } + case 26: { + com.google.protobuf.ByteString bs = input.readBytes(); + bitField0_ |= 0x00000004; + cmdMsgData_ = bs; + break; + } + } + } + } catch (com.google.protobuf.InvalidProtocolBufferException e) { + throw e.setUnfinishedMessage(this); + } catch (java.io.IOException e) { + throw new com.google.protobuf.InvalidProtocolBufferException( + e.getMessage()).setUnfinishedMessage(this); + } finally { + try { + unknownFieldsCodedOutput.flush(); + } catch (java.io.IOException e) { + // Should not happen + } finally { + unknownFields = unknownFieldsOutput.toByteString(); + } + makeExtensionsImmutable(); + } + } + public static com.google.protobuf.Parser PARSER = + new com.google.protobuf.AbstractParser() { + public IMP2PCmdMsg parsePartialFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return new IMP2PCmdMsg(input, extensionRegistry); + } + }; + + @java.lang.Override + public com.google.protobuf.Parser getParserForType() { + return PARSER; + } + + private int bitField0_; + public static final int FROM_USER_ID_FIELD_NUMBER = 1; + private int fromUserId_; + /** + * required uint32 from_user_id = 1; + * + *
+     *cmd id:		0x0601
+     * 
+ */ + public boolean hasFromUserId() { + return ((bitField0_ & 0x00000001) == 0x00000001); + } + /** + * required uint32 from_user_id = 1; + * + *
+     *cmd id:		0x0601
+     * 
+ */ + public int getFromUserId() { + return fromUserId_; + } + + public static final int TO_USER_ID_FIELD_NUMBER = 2; + private int toUserId_; + /** + * required uint32 to_user_id = 2; + */ + public boolean hasToUserId() { + return ((bitField0_ & 0x00000002) == 0x00000002); + } + /** + * required uint32 to_user_id = 2; + */ + public int getToUserId() { + return toUserId_; + } + + public static final int CMD_MSG_DATA_FIELD_NUMBER = 3; + private java.lang.Object cmdMsgData_; + /** + * required string cmd_msg_data = 3; + */ + public boolean hasCmdMsgData() { + return ((bitField0_ & 0x00000004) == 0x00000004); + } + /** + * required string cmd_msg_data = 3; + */ + public java.lang.String getCmdMsgData() { + java.lang.Object ref = cmdMsgData_; + if (ref instanceof java.lang.String) { + return (java.lang.String) ref; + } else { + com.google.protobuf.ByteString bs = + (com.google.protobuf.ByteString) ref; + java.lang.String s = bs.toStringUtf8(); + if (bs.isValidUtf8()) { + cmdMsgData_ = s; + } + return s; + } + } + /** + * required string cmd_msg_data = 3; + */ + public com.google.protobuf.ByteString + getCmdMsgDataBytes() { + java.lang.Object ref = cmdMsgData_; + if (ref instanceof java.lang.String) { + com.google.protobuf.ByteString b = + com.google.protobuf.ByteString.copyFromUtf8( + (java.lang.String) ref); + cmdMsgData_ = b; + return b; + } else { + return (com.google.protobuf.ByteString) ref; + } + } + + private void initFields() { + fromUserId_ = 0; + toUserId_ = 0; + cmdMsgData_ = ""; + } + private byte memoizedIsInitialized = -1; + public final boolean isInitialized() { + byte isInitialized = memoizedIsInitialized; + if (isInitialized == 1) return true; + if (isInitialized == 0) return false; + + if (!hasFromUserId()) { + memoizedIsInitialized = 0; + return false; + } + if (!hasToUserId()) { + memoizedIsInitialized = 0; + return false; + } + if (!hasCmdMsgData()) { + memoizedIsInitialized = 0; + return false; + } + memoizedIsInitialized = 1; + return true; + } + + public void writeTo(com.google.protobuf.CodedOutputStream output) + throws java.io.IOException { + getSerializedSize(); + if (((bitField0_ & 0x00000001) == 0x00000001)) { + output.writeUInt32(1, fromUserId_); + } + if (((bitField0_ & 0x00000002) == 0x00000002)) { + output.writeUInt32(2, toUserId_); + } + if (((bitField0_ & 0x00000004) == 0x00000004)) { + output.writeBytes(3, getCmdMsgDataBytes()); + } + output.writeRawBytes(unknownFields); + } + + private int memoizedSerializedSize = -1; + public int getSerializedSize() { + int size = memoizedSerializedSize; + if (size != -1) return size; + + size = 0; + if (((bitField0_ & 0x00000001) == 0x00000001)) { + size += com.google.protobuf.CodedOutputStream + .computeUInt32Size(1, fromUserId_); + } + if (((bitField0_ & 0x00000002) == 0x00000002)) { + size += com.google.protobuf.CodedOutputStream + .computeUInt32Size(2, toUserId_); + } + if (((bitField0_ & 0x00000004) == 0x00000004)) { + size += com.google.protobuf.CodedOutputStream + .computeBytesSize(3, getCmdMsgDataBytes()); + } + size += unknownFields.size(); + memoizedSerializedSize = size; + return size; + } + + private static final long serialVersionUID = 0L; + @java.lang.Override + protected java.lang.Object writeReplace() + throws java.io.ObjectStreamException { + return super.writeReplace(); + } + + public static com.mogujie.tt.protobuf.IMSwitchService.IMP2PCmdMsg parseFrom( + com.google.protobuf.ByteString data) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data); + } + public static com.mogujie.tt.protobuf.IMSwitchService.IMP2PCmdMsg parseFrom( + com.google.protobuf.ByteString data, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data, extensionRegistry); + } + public static com.mogujie.tt.protobuf.IMSwitchService.IMP2PCmdMsg parseFrom(byte[] data) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data); + } + public static com.mogujie.tt.protobuf.IMSwitchService.IMP2PCmdMsg parseFrom( + byte[] data, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data, extensionRegistry); + } + public static com.mogujie.tt.protobuf.IMSwitchService.IMP2PCmdMsg parseFrom(java.io.InputStream input) + throws java.io.IOException { + return PARSER.parseFrom(input); + } + public static com.mogujie.tt.protobuf.IMSwitchService.IMP2PCmdMsg parseFrom( + java.io.InputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return PARSER.parseFrom(input, extensionRegistry); + } + public static com.mogujie.tt.protobuf.IMSwitchService.IMP2PCmdMsg parseDelimitedFrom(java.io.InputStream input) + throws java.io.IOException { + return PARSER.parseDelimitedFrom(input); + } + public static com.mogujie.tt.protobuf.IMSwitchService.IMP2PCmdMsg parseDelimitedFrom( + java.io.InputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return PARSER.parseDelimitedFrom(input, extensionRegistry); + } + public static com.mogujie.tt.protobuf.IMSwitchService.IMP2PCmdMsg parseFrom( + com.google.protobuf.CodedInputStream input) + throws java.io.IOException { + return PARSER.parseFrom(input); + } + public static com.mogujie.tt.protobuf.IMSwitchService.IMP2PCmdMsg parseFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return PARSER.parseFrom(input, extensionRegistry); + } + + public static Builder newBuilder() { return Builder.create(); } + public Builder newBuilderForType() { return newBuilder(); } + public static Builder newBuilder(com.mogujie.tt.protobuf.IMSwitchService.IMP2PCmdMsg prototype) { + return newBuilder().mergeFrom(prototype); + } + public Builder toBuilder() { return newBuilder(this); } + + /** + * Protobuf type {@code IM.SwitchService.IMP2PCmdMsg} + */ + public static final class Builder extends + com.google.protobuf.GeneratedMessageLite.Builder< + com.mogujie.tt.protobuf.IMSwitchService.IMP2PCmdMsg, Builder> + implements + // @@protoc_insertion_point(builder_implements:IM.SwitchService.IMP2PCmdMsg) + com.mogujie.tt.protobuf.IMSwitchService.IMP2PCmdMsgOrBuilder { + // Construct using com.mogujie.tt.protobuf.IMSwitchService.IMP2PCmdMsg.newBuilder() + private Builder() { + maybeForceBuilderInitialization(); + } + + private void maybeForceBuilderInitialization() { + } + private static Builder create() { + return new Builder(); + } + + public Builder clear() { + super.clear(); + fromUserId_ = 0; + bitField0_ = (bitField0_ & ~0x00000001); + toUserId_ = 0; + bitField0_ = (bitField0_ & ~0x00000002); + cmdMsgData_ = ""; + bitField0_ = (bitField0_ & ~0x00000004); + return this; + } + + public Builder clone() { + return create().mergeFrom(buildPartial()); + } + + public com.mogujie.tt.protobuf.IMSwitchService.IMP2PCmdMsg getDefaultInstanceForType() { + return com.mogujie.tt.protobuf.IMSwitchService.IMP2PCmdMsg.getDefaultInstance(); + } + + public com.mogujie.tt.protobuf.IMSwitchService.IMP2PCmdMsg build() { + com.mogujie.tt.protobuf.IMSwitchService.IMP2PCmdMsg result = buildPartial(); + if (!result.isInitialized()) { + throw newUninitializedMessageException(result); + } + return result; + } + + public com.mogujie.tt.protobuf.IMSwitchService.IMP2PCmdMsg buildPartial() { + com.mogujie.tt.protobuf.IMSwitchService.IMP2PCmdMsg result = new com.mogujie.tt.protobuf.IMSwitchService.IMP2PCmdMsg(this); + int from_bitField0_ = bitField0_; + int to_bitField0_ = 0; + if (((from_bitField0_ & 0x00000001) == 0x00000001)) { + to_bitField0_ |= 0x00000001; + } + result.fromUserId_ = fromUserId_; + if (((from_bitField0_ & 0x00000002) == 0x00000002)) { + to_bitField0_ |= 0x00000002; + } + result.toUserId_ = toUserId_; + if (((from_bitField0_ & 0x00000004) == 0x00000004)) { + to_bitField0_ |= 0x00000004; + } + result.cmdMsgData_ = cmdMsgData_; + result.bitField0_ = to_bitField0_; + return result; + } + + public Builder mergeFrom(com.mogujie.tt.protobuf.IMSwitchService.IMP2PCmdMsg other) { + if (other == com.mogujie.tt.protobuf.IMSwitchService.IMP2PCmdMsg.getDefaultInstance()) return this; + if (other.hasFromUserId()) { + setFromUserId(other.getFromUserId()); + } + if (other.hasToUserId()) { + setToUserId(other.getToUserId()); + } + if (other.hasCmdMsgData()) { + bitField0_ |= 0x00000004; + cmdMsgData_ = other.cmdMsgData_; + + } + setUnknownFields( + getUnknownFields().concat(other.unknownFields)); + return this; + } + + public final boolean isInitialized() { + if (!hasFromUserId()) { + + return false; + } + if (!hasToUserId()) { + + return false; + } + if (!hasCmdMsgData()) { + + return false; + } + return true; + } + + public Builder mergeFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + com.mogujie.tt.protobuf.IMSwitchService.IMP2PCmdMsg parsedMessage = null; + try { + parsedMessage = PARSER.parsePartialFrom(input, extensionRegistry); + } catch (com.google.protobuf.InvalidProtocolBufferException e) { + parsedMessage = (com.mogujie.tt.protobuf.IMSwitchService.IMP2PCmdMsg) e.getUnfinishedMessage(); + throw e; + } finally { + if (parsedMessage != null) { + mergeFrom(parsedMessage); + } + } + return this; + } + private int bitField0_; + + private int fromUserId_ ; + /** + * required uint32 from_user_id = 1; + * + *
+       *cmd id:		0x0601
+       * 
+ */ + public boolean hasFromUserId() { + return ((bitField0_ & 0x00000001) == 0x00000001); + } + /** + * required uint32 from_user_id = 1; + * + *
+       *cmd id:		0x0601
+       * 
+ */ + public int getFromUserId() { + return fromUserId_; + } + /** + * required uint32 from_user_id = 1; + * + *
+       *cmd id:		0x0601
+       * 
+ */ + public Builder setFromUserId(int value) { + bitField0_ |= 0x00000001; + fromUserId_ = value; + + return this; + } + /** + * required uint32 from_user_id = 1; + * + *
+       *cmd id:		0x0601
+       * 
+ */ + public Builder clearFromUserId() { + bitField0_ = (bitField0_ & ~0x00000001); + fromUserId_ = 0; + + return this; + } + + private int toUserId_ ; + /** + * required uint32 to_user_id = 2; + */ + public boolean hasToUserId() { + return ((bitField0_ & 0x00000002) == 0x00000002); + } + /** + * required uint32 to_user_id = 2; + */ + public int getToUserId() { + return toUserId_; + } + /** + * required uint32 to_user_id = 2; + */ + public Builder setToUserId(int value) { + bitField0_ |= 0x00000002; + toUserId_ = value; + + return this; + } + /** + * required uint32 to_user_id = 2; + */ + public Builder clearToUserId() { + bitField0_ = (bitField0_ & ~0x00000002); + toUserId_ = 0; + + return this; + } + + private java.lang.Object cmdMsgData_ = ""; + /** + * required string cmd_msg_data = 3; + */ + public boolean hasCmdMsgData() { + return ((bitField0_ & 0x00000004) == 0x00000004); + } + /** + * required string cmd_msg_data = 3; + */ + public java.lang.String getCmdMsgData() { + java.lang.Object ref = cmdMsgData_; + if (!(ref instanceof java.lang.String)) { + com.google.protobuf.ByteString bs = + (com.google.protobuf.ByteString) ref; + java.lang.String s = bs.toStringUtf8(); + if (bs.isValidUtf8()) { + cmdMsgData_ = s; + } + return s; + } else { + return (java.lang.String) ref; + } + } + /** + * required string cmd_msg_data = 3; + */ + public com.google.protobuf.ByteString + getCmdMsgDataBytes() { + java.lang.Object ref = cmdMsgData_; + if (ref instanceof String) { + com.google.protobuf.ByteString b = + com.google.protobuf.ByteString.copyFromUtf8( + (java.lang.String) ref); + cmdMsgData_ = b; + return b; + } else { + return (com.google.protobuf.ByteString) ref; + } + } + /** + * required string cmd_msg_data = 3; + */ + public Builder setCmdMsgData( + java.lang.String value) { + if (value == null) { + throw new NullPointerException(); + } + bitField0_ |= 0x00000004; + cmdMsgData_ = value; + + return this; + } + /** + * required string cmd_msg_data = 3; + */ + public Builder clearCmdMsgData() { + bitField0_ = (bitField0_ & ~0x00000004); + cmdMsgData_ = getDefaultInstance().getCmdMsgData(); + + return this; + } + /** + * required string cmd_msg_data = 3; + */ + public Builder setCmdMsgDataBytes( + com.google.protobuf.ByteString value) { + if (value == null) { + throw new NullPointerException(); + } + bitField0_ |= 0x00000004; + cmdMsgData_ = value; + + return this; + } + + // @@protoc_insertion_point(builder_scope:IM.SwitchService.IMP2PCmdMsg) + } + + static { + defaultInstance = new IMP2PCmdMsg(true); + defaultInstance.initFields(); + } + + // @@protoc_insertion_point(class_scope:IM.SwitchService.IMP2PCmdMsg) + } + + + static { + } + + // @@protoc_insertion_point(outer_class_scope) +} diff --git a/android/app/src/main/java/com/mogujie/tt/protobuf/base/DataBuffer.java b/android/app/src/main/java/com/mogujie/tt/protobuf/base/DataBuffer.java new file mode 100644 index 000000000..b0a6e43c6 --- /dev/null +++ b/android/app/src/main/java/com/mogujie/tt/protobuf/base/DataBuffer.java @@ -0,0 +1,196 @@ +package com.mogujie.tt.protobuf.base; + +import com.mogujie.tt.utils.Logger; + +import org.jboss.netty.buffer.ChannelBuffer; +import org.jboss.netty.buffer.ChannelBuffers; + +import java.nio.charset.Charset; + +/** + * 数据缓冲区对象(ChannelBuffer) + * + * @author Nana + */ +public class DataBuffer { + + public ChannelBuffer buffer; + private static Logger logger = Logger.getLogger(DataBuffer.class); + + public DataBuffer() { + buffer = ChannelBuffers.dynamicBuffer(); + } + + public DataBuffer(ChannelBuffer binaryBuffer) { + buffer = binaryBuffer; + } + + public DataBuffer(int length) { + buffer = ChannelBuffers.buffer(length); + } + + public byte[] array() { + return buffer.array(); + } + + public void setOrignalBuffer(ChannelBuffer buffer) { + this.buffer = buffer; + } + + public ChannelBuffer getOrignalBuffer() { + return buffer; + } + + public void writeByte(int value) { + buffer.writeByte(value); + } + + public byte readByte() { + return buffer.readByte(); + } + + public byte[] readBytes(int length) { + byte[] bytes = new byte[length]; + buffer.readBytes(bytes); + return bytes; + } + + public int readInt() { + if (buffer.readable()) { + return buffer.readInt(); + } else { + return 0; + } + } + + public void writeShort(short value) { + buffer.writeShort(value); + } + + public short readShort() { + if (buffer.readable()) { + return buffer.readShort(); + } else { + return 0; + } + } + + public void writeInt(int value) { + buffer.writeInt(value); + } + + public char readChar() { + return buffer.readChar(); + } + + public void writeChar(char c) { + buffer.writeChar(c); + } + + public long readLong() { + return buffer.readLong(); + } + + public void writeLong(long value) { + buffer.writeLong(value); + } + + public double readDouble() { + return buffer.readDouble(); + } + + public void writeDouble(double value) { + buffer.writeDouble(value); + } + + /** + * 读取一个字符串 + * + * @return 格式:前导length表示字符串的byte数 length(4字节)string(length字节) + */ + public String readString() { + int length = readInt(); +// logger.d("debug#length:%d", length); + + byte[] bytes = readBytes(length); + + return new String(bytes, Charset.forName("utf8")); + } + + public String readString(int length) { + byte[] bytes = readBytes(length); + + return new String(bytes); + } + + public void writeBytes(byte[] bytes) { + buffer.writeBytes(bytes); + } + + public void writeSourceBytes(byte[] bytes) { + writeInt(bytes.length); + buffer.writeBytes(bytes); + } + + /** + * 读取int数组 + * + * @return 格式:前导count表示数组中有多少个元素 count(4字节)int1(4字节)...intCount(4字节) + */ + public int[] readIntArray() { + int count = readInt(); + int[] intArray = new int[count]; + for (int i = 0; i < count; i++) { + intArray[i] = readInt(); + } + return intArray; + } + + /** + * 写入int数组 + * + * @param intArray + * 格式见readIntArray() + */ + public void writeIntArray(int[] intArray) { + int count = intArray.length; + writeInt(count); + for (int i = 0; i < count; i++) { + writeInt(intArray[i]); + } + } + + /** + * 获取有效(可读取)的byte数 + * + * @return + */ + public int readableBytes() { + return buffer.readableBytes(); + } + + public DataBuffer readDataBuffer() { + if (null == buffer || buffer.readableBytes() == 0) { + return new DataBuffer(0); + } + int length = readInt(); + DataBuffer dataBuffer = new DataBuffer(0); + dataBuffer.setOrignalBuffer(buffer.readBytes(length)); + return dataBuffer; + } + + public void writeDataBuffer(DataBuffer inputBuffer) { + if (null == inputBuffer || inputBuffer.readableBytes() == 0) { + return; + } + buffer.writeBytes(inputBuffer.buffer); + } + + public void resetReaderIndex() { + buffer.resetReaderIndex(); + } + + public void resetWriterIndex() { + buffer.resetWriterIndex(); + } +} diff --git a/android/app/src/main/java/com/mogujie/tt/protobuf/base/DefaultHeader.java b/android/app/src/main/java/com/mogujie/tt/protobuf/base/DefaultHeader.java new file mode 100644 index 000000000..4d474b344 --- /dev/null +++ b/android/app/src/main/java/com/mogujie/tt/protobuf/base/DefaultHeader.java @@ -0,0 +1,21 @@ +package com.mogujie.tt.protobuf.base; + +import com.mogujie.tt.config.SysConstant; +import com.mogujie.tt.imservice.support.SequenceNumberMaker; +import com.mogujie.tt.utils.Logger; + +public class DefaultHeader extends Header { + private Logger logger = Logger.getLogger(DefaultHeader.class); + + public DefaultHeader(int serviceId, int commandId) { + setVersion((short) SysConstant.PROTOCOL_VERSION); + setFlag((short) SysConstant.PROTOCOL_FLAG); + setServiceId((short)serviceId); + setCommandId((short)commandId); + short seqNo = SequenceNumberMaker.getInstance().make(); + setSeqnum(seqNo); + setReserved((short)SysConstant.PROTOCOL_RESERVED); + + logger.d("packet#construct Default Header -> serviceId:%d, commandId:%d, seqNo:%d", serviceId, commandId, seqNo); + } +} diff --git a/android/app/src/main/java/com/mogujie/tt/protobuf/base/Header.java b/android/app/src/main/java/com/mogujie/tt/protobuf/base/Header.java new file mode 100644 index 000000000..54dc7aba3 --- /dev/null +++ b/android/app/src/main/java/com/mogujie/tt/protobuf/base/Header.java @@ -0,0 +1,182 @@ +package com.mogujie.tt.protobuf.base; + +import com.mogujie.tt.config.SysConstant; +import com.mogujie.tt.utils.Logger; + +/** + * TCP协议的头文件 + * + * @author dolphinWang + * @time 2014/04/30 + */ +public class Header { + + private Logger logger = Logger.getLogger(Header.class); + + + private int length; // 数据包长度,包括包头 + + private short version; // 版本号 + + private short flag; + + private short serviceId; // SID + + private short commandId; // CID + + private short seqnum; + + private short reserved; // 保留,可用于如序列号等 + + + public Header() { + + length = 0; + + version = 0; + + serviceId = 0; + + commandId = 0; + + reserved = 0; + + flag = 0; + + seqnum = 0; + + } + + + public short getFlag() { + + return flag; + + } + + + public void setFlag(short flag) { + + this.flag = flag; + + } + + + public short getSeqnum() { + + return seqnum; + + } + + + public void setSeqnum(short seq) { + + this.seqnum = seq; + + } + + + /** + * 头文件的压包函数 + * + * @return 数据包 + */ + + public DataBuffer encode() { + DataBuffer db = new DataBuffer(SysConstant.PROTOCOL_HEADER_LENGTH); + db.writeInt(length); + db.writeShort(version); + db.writeShort(flag); + db.writeShort(serviceId); + db.writeShort(commandId); + db.writeShort(seqnum); + db.writeShort(reserved); + return db; + + } + + + /** + * 头文件的解包函数 + * + * @param buffer + */ + + public void decode(DataBuffer buffer) { + + if (null == buffer) + return; + try { + length = buffer.readInt(); + version = buffer.readShort(); + flag = buffer.readShort(); + serviceId = buffer.readShort(); + commandId = buffer.readShort(); + seqnum = buffer.readShort(); + reserved = buffer.readShort(); + logger.d( + + "decode header, length:%d, version:%d, flag:%d serviceId:%d, commandId:%d, reserved:%d,seq:%d", + + length, version, flag, serviceId, commandId, + + seqnum, reserved); + } catch (Exception e) { + logger.e(e.getMessage()); + } + } + + + @Override + + public String toString() { + + return "Header [length=" + length + ", version=" + version + ", flag=" + + + flag + ", serviceId=" + serviceId + ", commandId=" + + + commandId + ", seq=" + seqnum + ", reserved=" + reserved + + + "]"; + } + + public short getCommandId() { + return commandId; + } + + public void setCommandId(short commandID) { + this.commandId = commandID; + } + + public short getServiceId() { + return serviceId; + } + + public void setServiceId(short serviceID) { + this.serviceId = serviceID; + } + + public int getLength() { + return length; + } + + public void setLength(int length) { + this.length = length; + } + + public short getVersion() { + return version; + } + + public void setVersion(short version) { + this.version = version; + } + + public int getReserved() { + return reserved; + } + + public void setReserved(short reserved) { + this.reserved = reserved; + } +} diff --git a/android/app/src/main/java/com/mogujie/tt/protobuf/helper/EntityChangeEngine.java b/android/app/src/main/java/com/mogujie/tt/protobuf/helper/EntityChangeEngine.java new file mode 100644 index 000000000..ec5b0da45 --- /dev/null +++ b/android/app/src/main/java/com/mogujie/tt/protobuf/helper/EntityChangeEngine.java @@ -0,0 +1,43 @@ +package com.mogujie.tt.protobuf.helper; + +import android.text.TextUtils; + +import com.mogujie.tt.DB.entity.MessageEntity; +import com.mogujie.tt.DB.entity.SessionEntity; + +/** + * @author : yingmu on 15-1-5. + * @email : yingmu@mogujie.com. + */ +public class EntityChangeEngine { + + public static SessionEntity getSessionEntity(MessageEntity msg){ + SessionEntity sessionEntity = new SessionEntity(); + + // [图文消息] [图片] [语音] + sessionEntity.setLatestMsgData(msg.getMessageDisplay()); + sessionEntity.setUpdated(msg.getUpdated()); + sessionEntity.setCreated(msg.getUpdated()); + sessionEntity.setLatestMsgId(msg.getMsgId()); + //sessionEntity.setPeerId(msg.getFromId()); + sessionEntity.setTalkId(msg.getFromId()); + sessionEntity.setPeerType(msg.getSessionType()); + sessionEntity.setLatestMsgType(msg.getMsgType()); + return sessionEntity; + } + + // todo enum + // 组建与解析统一地方,方便以后维护 + public static String getSessionKey(int peerId,int sessionType){ + String sessionKey = sessionType + "_" + peerId; + return sessionKey; + } + + public static String[] spiltSessionKey(String sessionKey){ + if(TextUtils.isEmpty(sessionKey)){ + throw new IllegalArgumentException("spiltSessionKey error,cause by empty sessionKey"); + } + String[] sessionInfo = sessionKey.split("_",2); + return sessionInfo; + } +} diff --git a/android/app/src/main/java/com/mogujie/tt/protobuf/helper/Java2ProtoBuf.java b/android/app/src/main/java/com/mogujie/tt/protobuf/helper/Java2ProtoBuf.java new file mode 100644 index 000000000..58efdc270 --- /dev/null +++ b/android/app/src/main/java/com/mogujie/tt/protobuf/helper/Java2ProtoBuf.java @@ -0,0 +1,38 @@ +package com.mogujie.tt.protobuf.helper; + +import com.mogujie.tt.config.DBConstant; +import com.mogujie.tt.protobuf.IMBaseDefine; + +/** + * @author : yingmu on 15-1-6. + * @email : yingmu@mogujie.com. + */ +public class Java2ProtoBuf { + /**----enum 转化接口--*/ + public static IMBaseDefine.MsgType getProtoMsgType(int msgType){ + switch (msgType){ + case DBConstant.MSG_TYPE_GROUP_TEXT: + return IMBaseDefine.MsgType.MSG_TYPE_GROUP_TEXT; + case DBConstant.MSG_TYPE_GROUP_AUDIO: + return IMBaseDefine.MsgType.MSG_TYPE_GROUP_AUDIO; + case DBConstant.MSG_TYPE_SINGLE_AUDIO: + return IMBaseDefine.MsgType.MSG_TYPE_SINGLE_AUDIO; + case DBConstant.MSG_TYPE_SINGLE_TEXT: + return IMBaseDefine.MsgType.MSG_TYPE_SINGLE_TEXT; + default: + throw new IllegalArgumentException("msgType is illegal,cause by #getProtoMsgType#" +msgType); + } + } + + + public static IMBaseDefine.SessionType getProtoSessionType(int sessionType){ + switch (sessionType){ + case DBConstant.SESSION_TYPE_SINGLE: + return IMBaseDefine.SessionType.SESSION_TYPE_SINGLE; + case DBConstant.SESSION_TYPE_GROUP: + return IMBaseDefine.SessionType.SESSION_TYPE_GROUP; + default: + throw new IllegalArgumentException("sessionType is illegal,cause by #getProtoSessionType#" +sessionType); + } + } +} diff --git a/android/app/src/main/java/com/mogujie/tt/protobuf/helper/ProtoBuf2JavaBean.java b/android/app/src/main/java/com/mogujie/tt/protobuf/helper/ProtoBuf2JavaBean.java new file mode 100644 index 000000000..e575f71f4 --- /dev/null +++ b/android/app/src/main/java/com/mogujie/tt/protobuf/helper/ProtoBuf2JavaBean.java @@ -0,0 +1,339 @@ +package com.mogujie.tt.protobuf.helper; + +import com.google.protobuf.ByteString; +import com.mogujie.tt.DB.entity.DepartmentEntity; +import com.mogujie.tt.config.DBConstant; +import com.mogujie.tt.DB.entity.GroupEntity; +import com.mogujie.tt.DB.entity.MessageEntity; +import com.mogujie.tt.DB.entity.SessionEntity; +import com.mogujie.tt.DB.entity.UserEntity; +import com.mogujie.tt.config.MessageConstant; +import com.mogujie.tt.imservice.entity.AudioMessage; +import com.mogujie.tt.imservice.entity.MsgAnalyzeEngine; +import com.mogujie.tt.imservice.entity.UnreadEntity; +import com.mogujie.tt.protobuf.IMBaseDefine; +import com.mogujie.tt.protobuf.IMGroup; +import com.mogujie.tt.protobuf.IMMessage; +import com.mogujie.tt.utils.CommonUtil; +import com.mogujie.tt.utils.FileUtil; +import com.mogujie.tt.utils.pinyin.PinYin; + +import org.json.JSONException; +import org.json.JSONObject; + +import java.io.UnsupportedEncodingException; + +/** + * @author : yingmu on 15-1-5. + * @email : yingmu@mogujie.com. + * + */ +public class ProtoBuf2JavaBean { + + public static DepartmentEntity getDepartEntity(IMBaseDefine.DepartInfo departInfo){ + DepartmentEntity departmentEntity = new DepartmentEntity(); + + int timeNow = (int) (System.currentTimeMillis()/1000); + + departmentEntity.setDepartId(departInfo.getDeptId()); + departmentEntity.setDepartName(departInfo.getDeptName()); + departmentEntity.setPriority(departInfo.getPriority()); + departmentEntity.setStatus(getDepartStatus(departInfo.getDeptStatus())); + + departmentEntity.setCreated(timeNow); + departmentEntity.setUpdated(timeNow); + + // 设定pinyin 相关 + PinYin.getPinYin(departInfo.getDeptName(), departmentEntity.getPinyinElement()); + + return departmentEntity; + } + + public static UserEntity getUserEntity(IMBaseDefine.UserInfo userInfo){ + UserEntity userEntity = new UserEntity(); + int timeNow = (int) (System.currentTimeMillis()/1000); + + userEntity.setStatus(userInfo.getStatus()); + userEntity.setAvatar(userInfo.getAvatarUrl()); + userEntity.setCreated(timeNow); + userEntity.setDepartmentId(userInfo.getDepartmentId()); + userEntity.setEmail(userInfo.getEmail()); + userEntity.setGender(userInfo.getUserGender()); + userEntity.setMainName(userInfo.getUserNickName()); + userEntity.setPhone(userInfo.getUserTel()); + userEntity.setPinyinName(userInfo.getUserDomain()); + userEntity.setRealName(userInfo.getUserRealName()); + userEntity.setUpdated(timeNow); + userEntity.setPeerId(userInfo.getUserId()); + + PinYin.getPinYin(userEntity.getMainName(), userEntity.getPinyinElement()); + return userEntity; + } + + public static SessionEntity getSessionEntity(IMBaseDefine.ContactSessionInfo sessionInfo){ + SessionEntity sessionEntity = new SessionEntity(); + + int msgType = getJavaMsgType(sessionInfo.getLatestMsgType()); + sessionEntity.setLatestMsgType(msgType); + sessionEntity.setPeerType(getJavaSessionType(sessionInfo.getSessionType())); + sessionEntity.setPeerId(sessionInfo.getSessionId()); + sessionEntity.buildSessionKey(); + sessionEntity.setTalkId(sessionInfo.getLatestMsgFromUserId()); + sessionEntity.setLatestMsgId(sessionInfo.getLatestMsgId()); + sessionEntity.setCreated(sessionInfo.getUpdatedTime()); + + String content = sessionInfo.getLatestMsgData().toStringUtf8(); + String desMessage = new String(com.mogujie.tt.Security.getInstance().DecryptMsg(content)); + // 判断具体的类型是什么 + if(msgType == DBConstant.MSG_TYPE_GROUP_TEXT || + msgType ==DBConstant.MSG_TYPE_SINGLE_TEXT){ + desMessage = MsgAnalyzeEngine.analyzeMessageDisplay(desMessage); + } + + sessionEntity.setLatestMsgData(desMessage); + sessionEntity.setUpdated(sessionInfo.getUpdatedTime()); + + return sessionEntity; + } + + + public static GroupEntity getGroupEntity(IMBaseDefine.GroupInfo groupInfo){ + GroupEntity groupEntity = new GroupEntity(); + int timeNow = (int) (System.currentTimeMillis()/1000); + groupEntity.setUpdated(timeNow); + groupEntity.setCreated(timeNow); + groupEntity.setMainName(groupInfo.getGroupName()); + groupEntity.setAvatar(groupInfo.getGroupAvatar()); + groupEntity.setCreatorId(groupInfo.getGroupCreatorId()); + groupEntity.setPeerId(groupInfo.getGroupId()); + groupEntity.setGroupType(getJavaGroupType(groupInfo.getGroupType())); + groupEntity.setStatus(groupInfo.getShieldStatus()); + groupEntity.setUserCnt(groupInfo.getGroupMemberListCount()); + groupEntity.setVersion(groupInfo.getVersion()); + groupEntity.setlistGroupMemberIds(groupInfo.getGroupMemberListList()); + + // may be not good place + PinYin.getPinYin(groupEntity.getMainName(), groupEntity.getPinyinElement()); + + return groupEntity; + } + + + /** + * 创建群时候的转化 + * @param groupCreateRsp + * @return + */ + public static GroupEntity getGroupEntity(IMGroup.IMGroupCreateRsp groupCreateRsp){ + GroupEntity groupEntity = new GroupEntity(); + int timeNow = (int) (System.currentTimeMillis()/1000); + groupEntity.setMainName(groupCreateRsp.getGroupName()); + groupEntity.setlistGroupMemberIds(groupCreateRsp.getUserIdListList()); + groupEntity.setCreatorId(groupCreateRsp.getUserId()); + groupEntity.setPeerId(groupCreateRsp.getGroupId()); + + groupEntity.setUpdated(timeNow); + groupEntity.setCreated(timeNow); + groupEntity.setAvatar(""); + groupEntity.setGroupType(DBConstant.GROUP_TYPE_TEMP); + groupEntity.setStatus(DBConstant.GROUP_STATUS_ONLINE); + groupEntity.setUserCnt(groupCreateRsp.getUserIdListCount()); + groupEntity.setVersion(1); + + PinYin.getPinYin(groupEntity.getMainName(), groupEntity.getPinyinElement()); + return groupEntity; + } + + + /** + * 拆分消息在上层做掉 图文混排 + * 在这判断 + */ + public static MessageEntity getMessageEntity(IMBaseDefine.MsgInfo msgInfo) { + MessageEntity messageEntity = null; + IMBaseDefine.MsgType msgType = msgInfo.getMsgType(); + switch (msgType) { + case MSG_TYPE_SINGLE_AUDIO: + case MSG_TYPE_GROUP_AUDIO: + try { + /**语音的解析不能转自 string再返回来*/ + messageEntity = analyzeAudio(msgInfo); + } catch (JSONException e) { + return null; + } catch (UnsupportedEncodingException e) { + return null; + } + break; + + case MSG_TYPE_GROUP_TEXT: + case MSG_TYPE_SINGLE_TEXT: + messageEntity = analyzeText(msgInfo); + break; + default: + throw new RuntimeException("ProtoBuf2JavaBean#getMessageEntity wrong type!"); + } + return messageEntity; + } + + public static MessageEntity analyzeText(IMBaseDefine.MsgInfo msgInfo){ + return MsgAnalyzeEngine.analyzeMessage(msgInfo); + } + + + public static AudioMessage analyzeAudio(IMBaseDefine.MsgInfo msgInfo) throws JSONException, UnsupportedEncodingException { + AudioMessage audioMessage = new AudioMessage(); + audioMessage.setFromId(msgInfo.getFromSessionId()); + audioMessage.setMsgId(msgInfo.getMsgId()); + audioMessage.setMsgType(getJavaMsgType(msgInfo.getMsgType())); + audioMessage.setStatus(MessageConstant.MSG_SUCCESS); + audioMessage.setReadStatus(MessageConstant.AUDIO_UNREAD); + audioMessage.setDisplayType(DBConstant.SHOW_AUDIO_TYPE); + audioMessage.setCreated(msgInfo.getCreateTime()); + audioMessage.setUpdated(msgInfo.getCreateTime()); + + ByteString bytes = msgInfo.getMsgData(); + + byte[] audioStream = bytes.toByteArray(); + if(audioStream.length < 4){ + audioMessage.setReadStatus(MessageConstant.AUDIO_READED); + audioMessage.setAudioPath(""); + audioMessage.setAudiolength(0); + }else { + int msgLen = audioStream.length; + byte[] playTimeByte = new byte[4]; + byte[] audioContent = new byte[msgLen - 4]; + + System.arraycopy(audioStream, 0, playTimeByte, 0, 4); + System.arraycopy(audioStream, 4, audioContent, 0, msgLen - 4); + int playTime = CommonUtil.byteArray2int(playTimeByte); + String audioSavePath = FileUtil.saveAudioResourceToFile(audioContent, audioMessage.getFromId()); + audioMessage.setAudiolength(playTime); + audioMessage.setAudioPath(audioSavePath); + } + + /**抽离出来 或者用gson*/ + JSONObject extraContent = new JSONObject(); + extraContent.put("audioPath",audioMessage.getAudioPath()); + extraContent.put("audiolength",audioMessage.getAudiolength()); + extraContent.put("readStatus",audioMessage.getReadStatus()); + String audioContent = extraContent.toString(); + audioMessage.setContent(audioContent); + + return audioMessage; + } + + + public static MessageEntity getMessageEntity(IMMessage.IMMsgData msgData){ + + MessageEntity messageEntity = null; + IMBaseDefine.MsgType msgType = msgData.getMsgType(); + IMBaseDefine.MsgInfo msgInfo = IMBaseDefine.MsgInfo.newBuilder() + .setMsgData(msgData.getMsgData()) + .setMsgId(msgData.getMsgId()) + .setMsgType(msgType) + .setCreateTime(msgData.getCreateTime()) + .setFromSessionId(msgData.getFromUserId()) + .build(); + + switch (msgType) { + case MSG_TYPE_SINGLE_AUDIO: + case MSG_TYPE_GROUP_AUDIO: + try { + messageEntity = analyzeAudio(msgInfo); + } catch (JSONException e) { + e.printStackTrace(); + } catch (UnsupportedEncodingException e) { + e.printStackTrace(); + } + break; + case MSG_TYPE_GROUP_TEXT: + case MSG_TYPE_SINGLE_TEXT: + messageEntity = analyzeText(msgInfo); + break; + default: + throw new RuntimeException("ProtoBuf2JavaBean#getMessageEntity wrong type!"); + } + if(messageEntity != null){ + messageEntity.setToId(msgData.getToSessionId()); + } + + /** + 消息的发送状态与 展示类型需要在上层做掉 + messageEntity.setStatus(); + messageEntity.setDisplayType(); + */ + return messageEntity; + } + + public static UnreadEntity getUnreadEntity(IMBaseDefine.UnreadInfo pbInfo){ + UnreadEntity unreadEntity = new UnreadEntity(); + unreadEntity.setSessionType(getJavaSessionType(pbInfo.getSessionType())); + unreadEntity.setLatestMsgData(pbInfo.getLatestMsgData().toString()); + unreadEntity.setPeerId(pbInfo.getSessionId()); + unreadEntity.setLaststMsgId(pbInfo.getLatestMsgId()); + unreadEntity.setUnReadCnt(pbInfo.getUnreadCnt()); + unreadEntity.buildSessionKey(); + return unreadEntity; + } + + /**----enum 转化接口--*/ + public static int getJavaMsgType(IMBaseDefine.MsgType msgType){ + switch (msgType){ + case MSG_TYPE_GROUP_TEXT: + return DBConstant.MSG_TYPE_GROUP_TEXT; + case MSG_TYPE_GROUP_AUDIO: + return DBConstant.MSG_TYPE_GROUP_AUDIO; + case MSG_TYPE_SINGLE_AUDIO: + return DBConstant.MSG_TYPE_SINGLE_AUDIO; + case MSG_TYPE_SINGLE_TEXT: + return DBConstant.MSG_TYPE_SINGLE_TEXT; + default: + throw new IllegalArgumentException("msgType is illegal,cause by #getProtoMsgType#" +msgType); + } + } + + public static int getJavaSessionType(IMBaseDefine.SessionType sessionType){ + switch (sessionType){ + case SESSION_TYPE_SINGLE: + return DBConstant.SESSION_TYPE_SINGLE; + case SESSION_TYPE_GROUP: + return DBConstant.SESSION_TYPE_GROUP; + default: + throw new IllegalArgumentException("sessionType is illegal,cause by #getProtoSessionType#" +sessionType); + } + } + + public static int getJavaGroupType(IMBaseDefine.GroupType groupType){ + switch (groupType){ + case GROUP_TYPE_NORMAL: + return DBConstant.GROUP_TYPE_NORMAL; + case GROUP_TYPE_TMP: + return DBConstant.GROUP_TYPE_TEMP; + default: + throw new IllegalArgumentException("sessionType is illegal,cause by #getProtoSessionType#" +groupType); + } + } + + public static int getGroupChangeType(IMBaseDefine.GroupModifyType modifyType){ + switch (modifyType){ + case GROUP_MODIFY_TYPE_ADD: + return DBConstant.GROUP_MODIFY_TYPE_ADD; + case GROUP_MODIFY_TYPE_DEL: + return DBConstant.GROUP_MODIFY_TYPE_DEL; + default: + throw new IllegalArgumentException("GroupModifyType is illegal,cause by " +modifyType); + } + } + + public static int getDepartStatus(IMBaseDefine.DepartmentStatusType statusType){ + switch (statusType){ + case DEPT_STATUS_OK: + return DBConstant.DEPT_STATUS_OK; + case DEPT_STATUS_DELETE: + return DBConstant.DEPT_STATUS_DELETE; + default: + throw new IllegalArgumentException("getDepartStatus is illegal,cause by " +statusType); + } + + } +} diff --git a/android/app/src/main/java/com/mogujie/tt/ui/activity/ChatFragmentActivity.java b/android/app/src/main/java/com/mogujie/tt/ui/activity/ChatFragmentActivity.java new file mode 100644 index 000000000..82ea4481c --- /dev/null +++ b/android/app/src/main/java/com/mogujie/tt/ui/activity/ChatFragmentActivity.java @@ -0,0 +1,16 @@ + +package com.mogujie.tt.ui.activity; + +import android.os.Bundle; + +import com.mogujie.tt.R; +import com.mogujie.tt.ui.base.TTBaseFragmentActivity; + +public class ChatFragmentActivity extends TTBaseFragmentActivity { + + @Override + public void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.tt_fragment_activity_chat); + } +} diff --git a/android/app/src/main/java/com/mogujie/tt/ui/activity/ContactFragmentActivity.java b/android/app/src/main/java/com/mogujie/tt/ui/activity/ContactFragmentActivity.java new file mode 100644 index 000000000..307e29391 --- /dev/null +++ b/android/app/src/main/java/com/mogujie/tt/ui/activity/ContactFragmentActivity.java @@ -0,0 +1,17 @@ + +package com.mogujie.tt.ui.activity; + +import android.os.Bundle; + +import com.mogujie.tt.R; +import com.mogujie.tt.ui.base.TTBaseFragmentActivity; + +public class ContactFragmentActivity extends TTBaseFragmentActivity { + + @Override + public void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.tt_fragment_activity_contact); + } + +} diff --git a/android/app/src/main/java/com/mogujie/tt/ui/activity/DetailPortraitActivity.java b/android/app/src/main/java/com/mogujie/tt/ui/activity/DetailPortraitActivity.java new file mode 100644 index 000000000..d0d66b7f8 --- /dev/null +++ b/android/app/src/main/java/com/mogujie/tt/ui/activity/DetailPortraitActivity.java @@ -0,0 +1,82 @@ +package com.mogujie.tt.ui.activity; + +import android.app.Activity; +import android.content.Intent; +import android.os.Bundle; +import android.os.Handler; + +import com.mogujie.tt.config.DBConstant; +import com.mogujie.tt.R; +import com.mogujie.tt.config.IntentConstant; +import com.mogujie.tt.utils.IMUIHelper; +import com.mogujie.tt.utils.Logger; +import com.mogujie.tt.ui.widget.ZoomableImageView; + +public class DetailPortraitActivity extends Activity { + + private Logger logger = Logger.getLogger(DetailPortraitActivity.class); + public static String imageUri = ""; + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.tt_activity_detail_portrait); + + Intent intent = getIntent(); + if (intent == null) { + logger.e("detailPortrait#displayimage#null intent"); + return; + } + + String resUri = intent.getStringExtra(IntentConstant.KEY_AVATAR_URL); + imageUri = resUri; + logger.d("detailPortrait#displayimage#resUri:%s", resUri); + + boolean isContactAvatar = intent.getBooleanExtra(IntentConstant.KEY_IS_IMAGE_CONTACT_AVATAR, false); + logger.d("displayimage#isContactAvatar:%s", isContactAvatar); + + final ZoomableImageView portraitView = (ZoomableImageView) findViewById(R.id.detail_portrait); + + + if (portraitView == null) { + logger.e("detailPortrait#displayimage#portraitView is null"); + return; + } + + logger.d("detailPortrait#displayimage#going to load the detail portrait"); + + + if (isContactAvatar) { + IMUIHelper.setEntityImageViewAvatarNoDefaultPortrait(portraitView, resUri, DBConstant.SESSION_TYPE_SINGLE, 0); + } else { + IMUIHelper.displayImageNoOptions(portraitView, resUri, -1, 0); + } + + new Handler().postDelayed(new Runnable() { + @Override + public void run() { + portraitView.setFinishActivity(new finishActivity() { + @Override + public void finish() { + if(DetailPortraitActivity.this!=null) + { + DetailPortraitActivity.this.finish(); + overridePendingTransition( + R.anim.tt_stay, R.anim.tt_image_exit); + } + } + }); + } + },500); + + } + @Override + protected void onDestroy() { + super.onDestroy(); + } + + public interface finishActivity{ + public void finish(); + } + +} diff --git a/android/app/src/main/java/com/mogujie/tt/ui/activity/GroupManagermentActivity.java b/android/app/src/main/java/com/mogujie/tt/ui/activity/GroupManagermentActivity.java new file mode 100644 index 000000000..34699bc9e --- /dev/null +++ b/android/app/src/main/java/com/mogujie/tt/ui/activity/GroupManagermentActivity.java @@ -0,0 +1,22 @@ + +package com.mogujie.tt.ui.activity; + +import android.content.Intent; +import android.os.Bundle; +import android.support.v4.app.FragmentActivity; +import com.mogujie.tt.R; + +public class GroupManagermentActivity extends FragmentActivity { + + @Override + protected void onCreate(Bundle bundle) { + super.onCreate(bundle); + setContentView(R.layout.tt_activity_groupmanage); + } + + @Override + protected void onActivityResult(int requestCode, int resultCode, Intent data) { + if (RESULT_OK != resultCode) + return; + } +} diff --git a/android/app/src/main/java/com/mogujie/tt/ui/activity/GroupMemberSelectActivity.java b/android/app/src/main/java/com/mogujie/tt/ui/activity/GroupMemberSelectActivity.java new file mode 100644 index 000000000..e921dec85 --- /dev/null +++ b/android/app/src/main/java/com/mogujie/tt/ui/activity/GroupMemberSelectActivity.java @@ -0,0 +1,22 @@ + +package com.mogujie.tt.ui.activity; + +import android.content.Intent; +import android.os.Bundle; +import android.support.v4.app.FragmentActivity; +import com.mogujie.tt.R; + +public class GroupMemberSelectActivity extends FragmentActivity { + + @Override + protected void onCreate(Bundle bundle) { + super.onCreate(bundle); + setContentView(R.layout.tt_activity_group_member_select); + } + + @Override + protected void onActivityResult(int requestCode, int resultCode, Intent data) { + if (RESULT_OK != resultCode) + return; + } +} diff --git a/android/app/src/main/java/com/mogujie/tt/ui/activity/ImageGridActivity.java b/android/app/src/main/java/com/mogujie/tt/ui/activity/ImageGridActivity.java new file mode 100644 index 000000000..d43a60aa5 --- /dev/null +++ b/android/app/src/main/java/com/mogujie/tt/ui/activity/ImageGridActivity.java @@ -0,0 +1,281 @@ + +package com.mogujie.tt.ui.activity; + +import android.app.Activity; +import android.content.Context; +import android.content.Intent; +import android.graphics.Color; +import android.graphics.drawable.ColorDrawable; +import android.os.Bundle; +import android.os.Handler; +import android.os.Message; +import android.view.MotionEvent; +import android.view.View; +import android.view.View.OnClickListener; +import android.view.View.OnTouchListener; +import android.widget.AbsListView; +import android.widget.AbsListView.OnScrollListener; +import android.widget.AdapterView; +import android.widget.AdapterView.OnItemClickListener; +import android.widget.GridView; +import android.widget.ImageView; +import android.widget.TextView; +import android.widget.Toast; + +import com.mogujie.tt.R; +import com.mogujie.tt.ui.adapter.album.ImageGridAdapter; +import com.mogujie.tt.ui.adapter.album.ImageGridAdapter.TextCallback; +import com.mogujie.tt.ui.adapter.album.ImageItem; +import com.mogujie.tt.config.IntentConstant; +import com.mogujie.tt.config.SysConstant; +import com.mogujie.tt.imservice.event.SelectEvent; +import com.mogujie.tt.imservice.service.IMService; +import com.mogujie.tt.imservice.support.IMServiceConnector; +import com.mogujie.tt.utils.Logger; + +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; +import java.util.Map; + +import de.greenrobot.event.EventBus; + +/** + * @Description 相册图片列表 + * @author Nana + * @date 2014-5-9 + */ +public class ImageGridActivity extends Activity implements OnTouchListener { + private List dataList = null; + private GridView gridView = null; + private TextView title = null; + private TextView cancel = null; + private static TextView finish = null; + private TextView preview = null; + private String name = null; + private ImageView leftBtn = null; + private static Context context = null; + private static ImageGridAdapter adapter = null; + private Logger logger = Logger.getLogger(ImageGridActivity.class); + + private IMService imService; + + private IMServiceConnector imServiceConnector = new IMServiceConnector(){ + @Override + public void onIMServiceConnected() { + imService = imServiceConnector.getIMService(); + if(imService == null){ + throw new RuntimeException("#connect imservice success,but is null"); + } + } + + @Override + public void onServiceDisconnected() { + + } + }; + + private Handler mHandler = new Handler() { + @Override + public void handleMessage(Message msg) { + switch (msg.what) { + case 0: + Toast.makeText(ImageGridActivity.this, + "最多选择" + SysConstant.MAX_SELECT_IMAGE_COUNT + "张图片", + Toast.LENGTH_LONG).show(); + break; + default: + break; + } + } + }; + + OnScrollListener onScrollListener = new OnScrollListener() { + @Override + public void onScrollStateChanged(AbsListView view, int scrollState) { + switch (scrollState) { + case OnScrollListener.SCROLL_STATE_FLING: + adapter.lock(); + break; + case OnScrollListener.SCROLL_STATE_IDLE: + adapter.unlock(); + break; + case OnScrollListener.SCROLL_STATE_TOUCH_SCROLL: + adapter.lock(); + break; + default: + break; + } + } + + @Override + public void onScroll(AbsListView view, int firstVisibleItem, + int visibleItemCount, int totalItemCount) { + } + }; + + @SuppressWarnings("unchecked") + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + imServiceConnector.connect(this); + setContentView(R.layout.tt_activity_image_grid); + context = this; + name = (String) getIntent().getSerializableExtra( + IntentConstant.EXTRA_ALBUM_NAME); + dataList = (List) getIntent().getSerializableExtra( + IntentConstant.EXTRA_IMAGE_LIST); + initView(); + initAdapter(); + } + + private void initAdapter() { + adapter = new ImageGridAdapter(ImageGridActivity.this, dataList, + mHandler); + adapter.setTextCallback(new TextCallback() { + public void onListen(int count) { + setSendText(count); + } + }); + gridView.setAdapter(adapter); + gridView.setOnScrollListener(onScrollListener); + } + + private void initView() { + gridView = (GridView) findViewById(R.id.gridview); + gridView.setSelector(new ColorDrawable(Color.TRANSPARENT)); + gridView.setOnItemClickListener(new OnItemClickListener() { + @Override + public void onItemClick(AdapterView parent, View view, + int position, long id) { + adapter.notifyDataSetChanged(); + } + }); + + title = (TextView) findViewById(R.id.base_fragment_title); + if (name.length() > 12) { + name = name.substring(0, 11) + "..."; + } + title.setText(name); + leftBtn = (ImageView) findViewById(R.id.back_btn); + leftBtn.setOnClickListener(new OnClickListener() { + @Override + public void onClick(View v) { + ImageGridActivity.this.finish(); + } + }); + cancel = (TextView) findViewById(R.id.cancel); + cancel.setOnClickListener(new OnClickListener() { + @Override + public void onClick(View v) { + adapter.setSelectMap(null); + ImageGridActivity.this.finish(); + } + }); + finish = (TextView) findViewById(R.id.finish); + finish.setOnClickListener(new OnClickListener() { + + public void onClick(View v) { + logger.d("pic#click send image btn"); + if (adapter.getSelectMap().size() > 0) { + List itemList = new ArrayList<>(); + Iterator iter = adapter.getSelectMap().keySet() + .iterator(); + + for(Map.Entry entity :adapter.getSelectMap().entrySet()){ + int position = entity.getKey(); + ImageItem imageItem = entity.getValue(); + + } + while (iter.hasNext()) { + int position = iter.next(); + ImageItem imgItem = adapter.getSelectMap() + .get(position); + itemList.add(imgItem); + } + + setSendText(0); + EventBus.getDefault().post(new SelectEvent(itemList)); + ImageGridActivity.this.setResult(RESULT_OK, null); + ImageGridActivity.this.finish(); + } else { + Toast.makeText(ImageGridActivity.this, + R.string.need_choose_images, Toast.LENGTH_SHORT) + .show(); + } + } + + }); + preview = (TextView) findViewById(R.id.preview); + preview.setOnClickListener(new OnClickListener() { + + public void onClick(View v) { + + if (adapter.getSelectMap().size() > 0) { + Intent intent = new Intent(ImageGridActivity.this, + PreviewActivity.class); + startActivityForResult(intent, + SysConstant.ALBUM_PREVIEW_BACK); + } else { + Toast.makeText(ImageGridActivity.this, + R.string.need_choose_images, Toast.LENGTH_SHORT) + .show(); + } + } + }); + } + + @Override + protected void onDestroy() { + setAdapterSelectedMap(null); + imServiceConnector.disconnect(this); + super.onStop(); + } + + public static void setSendText(int selNum) { + if (selNum == 0) { + finish.setText(context.getResources().getString(R.string.send)); + } else { + finish.setText(context.getResources().getString(R.string.send) + + "(" + selNum + ")"); + } + } + + public static void setAdapterSelectedMap(Map map) { + Iterator it = adapter.getSelectMap().keySet().iterator(); + if (map != null) { + while (it.hasNext()) { + int key = (Integer) it.next(); + if (map.containsKey(key)) { + adapter.updateSelectedStatus(key, true); + } else { + adapter.updateSelectedStatus(key, false); + } + } + adapter.setSelectMap(map); + adapter.setSelectTotalNum(map.size()); + } else { + while (it.hasNext()) { + int key = (Integer) it.next(); + adapter.updateSelectedStatus(key, false); + } + adapter.setSelectMap(null); + adapter.setSelectTotalNum(0); + } + adapter.notifyDataSetChanged(); + } + + public static ImageGridAdapter getAdapter() { + return adapter; + } + + @Override + public boolean onTouch(View view, MotionEvent motionEvent) { + switch (motionEvent.getAction()) { + case MotionEvent.ACTION_DOWN: + adapter.unlock(); + break; + } + return false; + } +} diff --git a/android/app/src/main/java/com/mogujie/tt/ui/activity/LoginActivity.java b/android/app/src/main/java/com/mogujie/tt/ui/activity/LoginActivity.java new file mode 100644 index 000000000..c27cbefb7 --- /dev/null +++ b/android/app/src/main/java/com/mogujie/tt/ui/activity/LoginActivity.java @@ -0,0 +1,415 @@ +package com.mogujie.tt.ui.activity; + +import android.app.AlertDialog; +import android.content.Context; +import android.content.DialogInterface; +import android.content.Intent; +import android.os.Bundle; +import android.os.Handler; +import android.text.TextUtils; +import android.view.ContextThemeWrapper; +import android.view.KeyEvent; +import android.view.LayoutInflater; +import android.view.MotionEvent; +import android.view.View; +import android.view.View.OnTouchListener; +import android.view.animation.Animation; +import android.view.animation.AnimationUtils; +import android.view.inputmethod.EditorInfo; +import android.view.inputmethod.InputMethodManager; +import android.widget.EditText; +import android.widget.TextView; +import android.widget.Toast; + +import com.mogujie.tt.DB.sp.LoginSp; +import com.mogujie.tt.DB.sp.SystemConfigSp; +import com.mogujie.tt.R; +import com.mogujie.tt.config.IntentConstant; +import com.mogujie.tt.config.UrlConstant; +import com.mogujie.tt.utils.IMUIHelper; +import com.mogujie.tt.imservice.event.LoginEvent; +import com.mogujie.tt.imservice.event.SocketEvent; +import com.mogujie.tt.imservice.manager.IMLoginManager; +import com.mogujie.tt.imservice.service.IMService; +import com.mogujie.tt.ui.base.TTBaseActivity; +import com.mogujie.tt.imservice.support.IMServiceConnector; +import com.mogujie.tt.utils.Logger; + +import de.greenrobot.event.EventBus; + + +/** + * @YM 1. 链接成功之后,直接判断是否loginSp是否可以直接登陆 + * true: 1.可以登陆,从DB中获取历史的状态 + * 2.建立长连接,请求最新的数据状态 【网络断开没有这个状态】 + * 3.完成 + *

+ * false:1. 不能直接登陆,跳转到登陆页面 + * 2. 请求消息服务器地址,链接,验证,触发loginSuccess + * 3. 保存登陆状态 + */ +public class LoginActivity extends TTBaseActivity { + + private Logger logger = Logger.getLogger(LoginActivity.class); + private Handler uiHandler = new Handler(); + private EditText mNameView; + private EditText mPasswordView; + private View loginPage; + private View splashPage; + private View mLoginStatusView; + private TextView mSwitchLoginServer; + private InputMethodManager intputManager; + + + private IMService imService; + private boolean autoLogin = true; + private boolean loginSuccess = false; + + private IMServiceConnector imServiceConnector = new IMServiceConnector() { + @Override + public void onServiceDisconnected() { + } + + @Override + public void onIMServiceConnected() { + logger.d("login#onIMServiceConnected"); + imService = imServiceConnector.getIMService(); + try { + do { + if (imService == null) { + //后台服务启动链接失败 + break; + } + IMLoginManager loginManager = imService.getLoginManager(); + LoginSp loginSp = imService.getLoginSp(); + if (loginManager == null || loginSp == null) { + // 无法获取登陆控制器 + break; + } + + LoginSp.SpLoginIdentity loginIdentity = loginSp.getLoginIdentity(); + if (loginIdentity == null) { + // 之前没有保存任何登陆相关的,跳转到登陆页面 + break; + } + + mNameView.setText(loginIdentity.getLoginName()); + if (TextUtils.isEmpty(loginIdentity.getPwd())) { + // 密码为空,可能是loginOut + break; + } + mPasswordView.setText(loginIdentity.getPwd()); + + if (autoLogin == false) { + break; + } + + handleGotLoginIdentity(loginIdentity); + return; + } while (false); + + // 异常分支都会执行这个 + handleNoLoginIdentity(); + } catch (Exception e) { + // 任何未知的异常 + logger.w("loadIdentity failed"); + handleNoLoginIdentity(); + } + } + }; + + + /** + * 跳转到登陆的页面 + */ + private void handleNoLoginIdentity() { + logger.i("login#handleNoLoginIdentity"); + uiHandler.postDelayed(new Runnable() { + @Override + public void run() { + showLoginPage(); + } + }, 1000); + } + + /** + * 自动登陆 + */ + private void handleGotLoginIdentity(final LoginSp.SpLoginIdentity loginIdentity) { + logger.i("login#handleGotLoginIdentity"); + + uiHandler.postDelayed(new Runnable() { + @Override + public void run() { + logger.d("login#start auto login"); + if (imService == null || imService.getLoginManager() == null) { + Toast.makeText(LoginActivity.this, getString(R.string.login_failed), Toast.LENGTH_SHORT).show(); + showLoginPage(); + } + imService.getLoginManager().login(loginIdentity); + } + }, 500); + } + + + private void showLoginPage() { + splashPage.setVisibility(View.GONE); + loginPage.setVisibility(View.VISIBLE); + } + + + @Override + protected void onCreate(Bundle savedInstanceState) { + + super.onCreate(savedInstanceState); + intputManager = (InputMethodManager) getSystemService(this.INPUT_METHOD_SERVICE); + logger.d("login#onCreate"); + + SystemConfigSp.instance().init(getApplicationContext()); + if (TextUtils.isEmpty(SystemConfigSp.instance().getStrConfig(SystemConfigSp.SysCfgDimension.LOGINSERVER))) { + SystemConfigSp.instance().setStrConfig(SystemConfigSp.SysCfgDimension.LOGINSERVER, UrlConstant.ACCESS_MSG_ADDRESS); + } + + imServiceConnector.connect(LoginActivity.this); + EventBus.getDefault().register(this); + + setContentView(R.layout.tt_activity_login); + mSwitchLoginServer = (TextView)findViewById(R.id.sign_switch_login_server); + mSwitchLoginServer.setOnClickListener(new View.OnClickListener(){ + @Override + public void onClick(View view) { + AlertDialog.Builder builder = new AlertDialog.Builder(new ContextThemeWrapper(LoginActivity.this, android.R.style.Theme_Holo_Light_Dialog)); + LayoutInflater inflater = (LayoutInflater)getSystemService(Context.LAYOUT_INFLATER_SERVICE); + View dialog_view = inflater.inflate(R.layout.tt_custom_dialog, null); + final EditText editText = (EditText)dialog_view.findViewById(R.id.dialog_edit_content); + editText.setText(SystemConfigSp.instance().getStrConfig(SystemConfigSp.SysCfgDimension.LOGINSERVER)); + TextView textText = (TextView)dialog_view.findViewById(R.id.dialog_title); + textText.setText(R.string.switch_login_server_title); + builder.setView(dialog_view); + builder.setPositiveButton(getString(R.string.tt_ok), new DialogInterface.OnClickListener() { + @Override + public void onClick(DialogInterface dialog, int which) { + + if(!TextUtils.isEmpty(editText.getText().toString().trim())) + { + SystemConfigSp.instance().setStrConfig(SystemConfigSp.SysCfgDimension.LOGINSERVER,editText.getText().toString().trim()); + dialog.dismiss(); + } + } + }); + builder.setNegativeButton(getString(R.string.tt_cancel), new DialogInterface.OnClickListener() { + @Override + public void onClick(DialogInterface dialogInterface, int i) { + dialogInterface.dismiss(); + } + }); + builder.show(); + } + }); + + mNameView = (EditText) findViewById(R.id.name); + mPasswordView = (EditText) findViewById(R.id.password); + mPasswordView.setOnEditorActionListener(new TextView.OnEditorActionListener() { + @Override + public boolean onEditorAction(TextView textView, int id, KeyEvent keyEvent) { + + if (id == R.id.login || id == EditorInfo.IME_NULL) { + attemptLogin(); + return true; + } + return false; + } + }); + mLoginStatusView = findViewById(R.id.login_status); + findViewById(R.id.sign_in_button).setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View view) { + intputManager.hideSoftInputFromWindow(mPasswordView.getWindowToken(), 0); + attemptLogin(); + } + }); + initAutoLogin(); + } + + private void initAutoLogin() { + logger.i("login#initAutoLogin"); + + splashPage = findViewById(R.id.splash_page); + loginPage = findViewById(R.id.login_page); + autoLogin = shouldAutoLogin(); + + splashPage.setVisibility(autoLogin ? View.VISIBLE : View.GONE); + loginPage.setVisibility(autoLogin ? View.GONE : View.VISIBLE); + + loginPage.setOnTouchListener(new OnTouchListener() { + + @Override + public boolean onTouch(View v, MotionEvent event) { + + if (mPasswordView != null) { + intputManager.hideSoftInputFromWindow(mPasswordView.getWindowToken(), 0); + } + + if (mNameView != null) { + intputManager.hideSoftInputFromWindow(mNameView.getWindowToken(), 0); + } + + return false; + } + }); + + if (autoLogin) { + Animation splashAnimation = AnimationUtils.loadAnimation(this, R.anim.login_splash); + if (splashAnimation == null) { + logger.e("login#loadAnimation login_splash failed"); + return; + } + + splashPage.startAnimation(splashAnimation); + } + } + + // 主动退出的时候, 这个地方会有值,更具pwd来判断 + private boolean shouldAutoLogin() { + Intent intent = getIntent(); + if (intent != null) { + boolean notAutoLogin = intent.getBooleanExtra(IntentConstant.KEY_LOGIN_NOT_AUTO, false); + logger.d("login#notAutoLogin:%s", notAutoLogin); + if (notAutoLogin) { + return false; + } + } + return true; + } + + + @Override + protected void onDestroy() { + super.onDestroy(); + + imServiceConnector.disconnect(LoginActivity.this); + EventBus.getDefault().unregister(this); + splashPage = null; + loginPage = null; + } + + + public void attemptLogin() { + String loginName = mNameView.getText().toString(); + String mPassword = mPasswordView.getText().toString(); + boolean cancel = false; + View focusView = null; + + if (TextUtils.isEmpty(mPassword)) { + Toast.makeText(this, getString(R.string.error_pwd_required), Toast.LENGTH_SHORT).show(); + focusView = mPasswordView; + cancel = true; + } + + if (TextUtils.isEmpty(loginName)) { + Toast.makeText(this, getString(R.string.error_name_required), Toast.LENGTH_SHORT).show(); + focusView = mNameView; + cancel = true; + } + + if (cancel) { + focusView.requestFocus(); + } else { + showProgress(true); + if (imService != null) { +// boolean userNameChanged = true; +// boolean pwdChanged = true; + loginName = loginName.trim(); + mPassword = mPassword.trim(); + imService.getLoginManager().login(loginName, mPassword); + } + } + } + + private void showProgress(final boolean show) { + if (show) { + mLoginStatusView.setVisibility(View.VISIBLE); + } else { + mLoginStatusView.setVisibility(View.GONE); + } + } + + // 为什么会有两个这个 + // 可能是 兼容性的问题 导致两种方法onBackPressed + @Override + public void onBackPressed() { + logger.d("login#onBackPressed"); + //imLoginMgr.cancel(); + // TODO Auto-generated method stub + super.onBackPressed(); + } + + @Override + public boolean onKeyDown(int keyCode, KeyEvent event) { +// if (keyCode == KeyEvent.KEYCODE_BACK && event.getRepeatCount() == 0) { +// LoginActivity.this.finish(); +// return true; +// } + return super.onKeyDown(keyCode, event); + } + + + @Override + protected void onStop() { + super.onStop(); + } + + /** + * ----------------------------event 事件驱动---------------------------- + */ + public void onEventMainThread(LoginEvent event) { + switch (event) { + case LOCAL_LOGIN_SUCCESS: + case LOGIN_OK: + onLoginSuccess(); + break; + case LOGIN_AUTH_FAILED: + case LOGIN_INNER_FAILED: + if (!loginSuccess) + onLoginFailure(event); + break; + } + } + + + public void onEventMainThread(SocketEvent event) { + switch (event) { + case CONNECT_MSG_SERVER_FAILED: + case REQ_MSG_SERVER_ADDRS_FAILED: + if (!loginSuccess) + onSocketFailure(event); + break; + } + } + + private void onLoginSuccess() { + logger.i("login#onLoginSuccess"); + loginSuccess = true; + Intent intent = new Intent(LoginActivity.this, MainActivity.class); + startActivity(intent); + LoginActivity.this.finish(); + } + + private void onLoginFailure(LoginEvent event) { + logger.e("login#onLoginError -> errorCode:%s", event.name()); + showLoginPage(); + String errorTip = getString(IMUIHelper.getLoginErrorTip(event)); + logger.d("login#errorTip:%s", errorTip); + mLoginStatusView.setVisibility(View.GONE); + Toast.makeText(this, errorTip, Toast.LENGTH_SHORT).show(); + } + + private void onSocketFailure(SocketEvent event) { + logger.e("login#onLoginError -> errorCode:%s,", event.name()); + showLoginPage(); + String errorTip = getString(IMUIHelper.getSocketErrorTip(event)); + logger.d("login#errorTip:%s", errorTip); + mLoginStatusView.setVisibility(View.GONE); + Toast.makeText(this, errorTip, Toast.LENGTH_SHORT).show(); + } +} diff --git a/android/app/src/main/java/com/mogujie/tt/ui/activity/MainActivity.java b/android/app/src/main/java/com/mogujie/tt/ui/activity/MainActivity.java new file mode 100644 index 000000000..d24d73474 --- /dev/null +++ b/android/app/src/main/java/com/mogujie/tt/ui/activity/MainActivity.java @@ -0,0 +1,225 @@ +package com.mogujie.tt.ui.activity; + +import android.content.Intent; +import android.os.Bundle; +import android.support.v4.app.Fragment; +import android.support.v4.app.FragmentActivity; +import android.view.Window; + +import com.mogujie.tt.R; +import com.mogujie.tt.config.IntentConstant; +import com.mogujie.tt.imservice.event.LoginEvent; +import com.mogujie.tt.imservice.event.UnreadEvent; +import com.mogujie.tt.imservice.service.IMService; +import com.mogujie.tt.ui.fragment.ChatFragment; +import com.mogujie.tt.ui.fragment.ContactFragment; +import com.mogujie.tt.imservice.support.IMServiceConnector; +import com.mogujie.tt.utils.Logger; +import com.mogujie.tt.ui.widget.NaviTabButton; + +import de.greenrobot.event.EventBus; + + +public class MainActivity extends FragmentActivity{ + private Fragment[] mFragments; + private NaviTabButton[] mTabButtons; + private Logger logger = Logger.getLogger(MainActivity.class); + private IMService imService; + private IMServiceConnector imServiceConnector = new IMServiceConnector(){ + @Override + public void onIMServiceConnected() { + imService = imServiceConnector.getIMService(); + } + + @Override + public void onServiceDisconnected() { + } + }; + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + + logger.d("MainActivity#savedInstanceState:%s", savedInstanceState); + //todo eric when crash, this will be called, why? + if (savedInstanceState != null) { + logger.w("MainActivity#crashed and restarted, just exit"); + jumpToLoginPage(); + finish(); + } + + // 在这个地方加可能会有问题吧 + EventBus.getDefault().register(this); + imServiceConnector.connect(this); + + requestWindowFeature(Window.FEATURE_NO_TITLE); + setContentView(R.layout.tt_activity_main); + + initTab(); + initFragment(); + setFragmentIndicator(0); + } + + @Override + public void onBackPressed() { + //don't let it exit + //super.onBackPressed(); + + //nonRoot If false then this only works if the activity is the root of a task; if true it will work for any activity in a task. + //document http://developer.android.com/reference/android/app/Activity.html + + //moveTaskToBack(true); + + Intent i = new Intent(Intent.ACTION_MAIN); + i.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); + i.addCategory(Intent.CATEGORY_HOME); + startActivity(i); + + } + + + private void initFragment() { + mFragments = new Fragment[4]; + mFragments[0] = getSupportFragmentManager().findFragmentById(R.id.fragment_chat); + mFragments[1] = getSupportFragmentManager().findFragmentById(R.id.fragment_contact); + mFragments[2] = getSupportFragmentManager().findFragmentById(R.id.fragment_internal); + mFragments[3] = getSupportFragmentManager().findFragmentById(R.id.fragment_my); + } + + private void initTab() { + mTabButtons = new NaviTabButton[4]; + + mTabButtons[0] = (NaviTabButton) findViewById(R.id.tabbutton_chat); + mTabButtons[1] = (NaviTabButton) findViewById(R.id.tabbutton_contact); + mTabButtons[2] = (NaviTabButton) findViewById(R.id.tabbutton_internal); + mTabButtons[3] = (NaviTabButton) findViewById(R.id.tabbutton_my); + + mTabButtons[0].setTitle(getString(R.string.main_chat)); + mTabButtons[0].setIndex(0); + mTabButtons[0].setSelectedImage(getResources().getDrawable(R.drawable.tt_tab_chat_sel)); + mTabButtons[0].setUnselectedImage(getResources().getDrawable(R.drawable.tt_tab_chat_nor)); + + mTabButtons[1].setTitle(getString(R.string.main_contact)); + mTabButtons[1].setIndex(1); + mTabButtons[1].setSelectedImage(getResources().getDrawable(R.drawable.tt_tab_contact_sel)); + mTabButtons[1].setUnselectedImage(getResources().getDrawable(R.drawable.tt_tab_contact_nor)); + + mTabButtons[2].setTitle(getString(R.string.main_innernet)); + mTabButtons[2].setIndex(2); + mTabButtons[2].setSelectedImage(getResources().getDrawable(R.drawable.tt_tab_internal_select)); + mTabButtons[2].setUnselectedImage(getResources().getDrawable(R.drawable.tt_tab_internal_nor)); + + mTabButtons[3].setTitle(getString(R.string.main_me_tab)); + mTabButtons[3].setIndex(3); + mTabButtons[3].setSelectedImage(getResources().getDrawable(R.drawable.tt_tab_me_sel)); + mTabButtons[3].setUnselectedImage(getResources().getDrawable(R.drawable.tt_tab_me_nor)); + } + + public void setFragmentIndicator(int which) { + getSupportFragmentManager().beginTransaction().hide(mFragments[0]).hide(mFragments[1]).hide(mFragments[2]).hide(mFragments[3]).show(mFragments[which]).commit(); + + mTabButtons[0].setSelectedButton(false); + mTabButtons[1].setSelectedButton(false); + mTabButtons[2].setSelectedButton(false); + mTabButtons[3].setSelectedButton(false); + + mTabButtons[which].setSelectedButton(true); + } + + public void setUnreadMessageCnt(int unreadCnt) { + mTabButtons[0].setUnreadNotify(unreadCnt); + } + + + + /**双击事件*/ + public void chatDoubleListener() { + setFragmentIndicator(0); + ((ChatFragment) mFragments[0]).scrollToUnreadPosition(); + } + + @Override + protected void onNewIntent(Intent intent) { + super.onNewIntent(intent); + handleLocateDepratment(intent); + } + + + @Override + protected void onResume() { + super.onResume(); + } + + private void handleLocateDepratment(Intent intent) { + int departmentIdToLocate= intent.getIntExtra(IntentConstant.KEY_LOCATE_DEPARTMENT,-1); + if (departmentIdToLocate == -1) { + return; + } + + logger.d("department#got department to locate id:%d", departmentIdToLocate); + setFragmentIndicator(1); + ContactFragment fragment = (ContactFragment) mFragments[1]; + if (fragment == null) { + logger.e("department#fragment is null"); + return; + } + fragment.locateDepartment(departmentIdToLocate); + } + + @Override + protected void onPause() { + super.onPause(); + } + + @Override + protected void onDestroy() { + logger.d("mainactivity#onDestroy"); + EventBus.getDefault().unregister(this); + imServiceConnector.disconnect(this); + super.onDestroy(); + } + + + + public void onEventMainThread(UnreadEvent event){ + switch (event.event){ + case SESSION_READED_UNREAD_MSG: + case UNREAD_MSG_LIST_OK: + case UNREAD_MSG_RECEIVED: + showUnreadMessageCount(); + break; + } + } + + private void showUnreadMessageCount() { + //todo eric when to + if(imService!=null) + { + int unreadNum = imService.getUnReadMsgManager().getTotalUnreadCount(); + mTabButtons[0].setUnreadNotify(unreadNum); + } + + } + + public void onEventMainThread(LoginEvent event){ + switch (event){ + case LOGIN_OUT: + handleOnLogout(); + break; + } + } + + private void handleOnLogout() { + logger.d("mainactivity#login#handleOnLogout"); + finish(); + logger.d("mainactivity#login#kill self, and start login activity"); + jumpToLoginPage(); + + } + + private void jumpToLoginPage() { + Intent intent = new Intent(this, LoginActivity.class); + intent.putExtra(IntentConstant.KEY_LOGIN_NOT_AUTO, true); + startActivity(intent); + } +} diff --git a/android/app/src/main/java/com/mogujie/tt/ui/activity/MessageActivity.java b/android/app/src/main/java/com/mogujie/tt/ui/activity/MessageActivity.java new file mode 100644 index 000000000..f96c30269 --- /dev/null +++ b/android/app/src/main/java/com/mogujie/tt/ui/activity/MessageActivity.java @@ -0,0 +1,1319 @@ + +package com.mogujie.tt.ui.activity; + +import android.app.Dialog; +import android.content.BroadcastReceiver; +import android.content.Context; +import android.content.Intent; +import android.content.IntentFilter; +import android.content.res.Configuration; +import android.graphics.Color; +import android.graphics.Rect; +import android.graphics.drawable.ColorDrawable; +import android.graphics.drawable.Drawable; +import android.hardware.Sensor; +import android.hardware.SensorEvent; +import android.hardware.SensorEventListener; +import android.hardware.SensorManager; +import android.media.AudioManager; +import android.net.Uri; +import android.os.Bundle; +import android.os.Handler; +import android.os.Message; +import android.provider.MediaStore; +import android.provider.Settings; +import android.text.Editable; +import android.text.Selection; +import android.text.TextWatcher; +import android.util.TypedValue; +import android.view.Gravity; +import android.view.LayoutInflater; +import android.view.MotionEvent; +import android.view.View; +import android.view.View.OnTouchListener; +import android.view.ViewGroup; +import android.view.ViewTreeObserver; +import android.view.Window; +import android.view.WindowManager; +import android.view.inputmethod.InputMethodManager; +import android.widget.AbsListView; +import android.widget.Button; +import android.widget.ImageView; +import android.widget.LinearLayout; +import android.widget.ListView; +import android.widget.RadioGroup; +import android.widget.RelativeLayout; +import android.widget.RelativeLayout.LayoutParams; +import android.widget.TextView; +import android.widget.Toast; + +import com.handmark.pulltorefresh.library.PullToRefreshBase; +import com.handmark.pulltorefresh.library.PullToRefreshBase.OnRefreshListener2; +import com.handmark.pulltorefresh.library.PullToRefreshListView; +import com.mogujie.tt.DB.entity.GroupEntity; +import com.mogujie.tt.DB.entity.MessageEntity; +import com.mogujie.tt.DB.entity.PeerEntity; +import com.mogujie.tt.DB.entity.UserEntity; +import com.mogujie.tt.DB.sp.SystemConfigSp; +import com.mogujie.tt.R; +import com.mogujie.tt.app.IMApplication; +import com.mogujie.tt.config.DBConstant; +import com.mogujie.tt.config.HandlerConstant; +import com.mogujie.tt.config.IntentConstant; +import com.mogujie.tt.config.SysConstant; +import com.mogujie.tt.imservice.entity.AudioMessage; +import com.mogujie.tt.imservice.entity.ImageMessage; +import com.mogujie.tt.imservice.entity.TextMessage; +import com.mogujie.tt.imservice.entity.UnreadEntity; +import com.mogujie.tt.imservice.event.MessageEvent; +import com.mogujie.tt.imservice.event.PriorityEvent; +import com.mogujie.tt.imservice.event.SelectEvent; +import com.mogujie.tt.imservice.manager.IMLoginManager; +import com.mogujie.tt.imservice.manager.IMStackManager; +import com.mogujie.tt.imservice.service.IMService; +import com.mogujie.tt.imservice.support.IMServiceConnector; +import com.mogujie.tt.ui.adapter.MessageAdapter; +import com.mogujie.tt.ui.adapter.album.AlbumHelper; +import com.mogujie.tt.ui.adapter.album.ImageBucket; +import com.mogujie.tt.ui.adapter.album.ImageItem; +import com.mogujie.tt.ui.base.TTBaseActivity; +import com.mogujie.tt.ui.helper.AudioPlayerHandler; +import com.mogujie.tt.ui.helper.AudioRecordHandler; +import com.mogujie.tt.ui.helper.Emoparser; +import com.mogujie.tt.ui.widget.CustomEditView; +import com.mogujie.tt.ui.widget.EmoGridView; +import com.mogujie.tt.ui.widget.EmoGridView.OnEmoGridViewItemClick; +import com.mogujie.tt.ui.widget.MGProgressbar; +import com.mogujie.tt.ui.widget.YayaEmoGridView; +import com.mogujie.tt.utils.CommonUtil; +import com.mogujie.tt.utils.IMUIHelper; +import com.mogujie.tt.utils.Logger; +import com.nostra13.universalimageloader.core.ImageLoader; +import com.nostra13.universalimageloader.core.listener.PauseOnScrollListener; + +import java.io.File; +import java.util.ArrayList; +import java.util.List; +import java.util.Set; +import java.util.Timer; +import java.util.TimerTask; + +import de.greenrobot.event.EventBus; + +/** + * @author Nana + * @Description 主消息界面 + * @date 2014-7-15 + *

+ */ +public class MessageActivity extends TTBaseActivity + implements + OnRefreshListener2, + View.OnClickListener, + OnTouchListener, + TextWatcher, + SensorEventListener { + + private static Handler uiHandler = null;// 处理语音 + + + private PullToRefreshListView lvPTR = null; + private CustomEditView messageEdt = null; + private TextView sendBtn = null; + private Button recordAudioBtn = null; + private ImageView keyboardInputImg = null; + private ImageView soundVolumeImg = null; + private LinearLayout soundVolumeLayout = null; + + + private ImageView audioInputImg = null; + private ImageView addPhotoBtn = null; + private ImageView addEmoBtn = null; + private LinearLayout emoLayout = null; + private EmoGridView emoGridView = null; + private YayaEmoGridView yayaEmoGridView = null; + private RadioGroup emoRadioGroup = null; + private String audioSavePath = null; + private InputMethodManager inputManager = null; + private AudioRecordHandler audioRecorderInstance = null; + private TextView textView_new_msg_tip = null; + + private MessageAdapter adapter = null; + private Thread audioRecorderThread = null; + private Dialog soundVolumeDialog = null; + private View addOthersPanelView = null; + private AlbumHelper albumHelper = null; + + + private List albumList = null; + MGProgressbar progressbar = null; + + //private boolean audioReday = false; 语音先关的 + private SensorManager sensorManager = null; + private Sensor sensor = null; + + + private String takePhotoSavePath = ""; + private Logger logger = Logger.getLogger(MessageActivity.class); + private IMService imService; + private UserEntity loginUser; + private PeerEntity peerEntity; + + // 当前的session + private String currentSessionKey; + private int historyTimes = 0; + + //键盘布局相关参数 + int rootBottom = Integer.MIN_VALUE, keyboardHeight = 0; + switchInputMethodReceiver receiver; + private String currentInputMethod; + + /** + * 全局Toast + */ + private Toast mToast; + + public void showToast(int resId) { + String text = getResources().getString(resId); + if (mToast == null) { + mToast = Toast.makeText(MessageActivity.this, text, Toast.LENGTH_SHORT); + } else { + mToast.setText(text); + mToast.setDuration(Toast.LENGTH_SHORT); + } + mToast.setGravity(Gravity.CENTER, 0, 0); + mToast.show(); + } + + public void cancelToast() { + if (mToast != null) { + mToast.cancel(); + } + } + + @Override + public void onBackPressed() { + IMApplication.gifRunning = false; + cancelToast(); + super.onBackPressed(); + } + + /** + * end 全局Toast + */ + private IMServiceConnector imServiceConnector = new IMServiceConnector() { + @Override + public void onIMServiceConnected() { + logger.d("message_activity#onIMServiceConnected"); + imService = imServiceConnector.getIMService(); + initData(); + } + + @Override + public void onServiceDisconnected() { + } + }; + + @Override + protected void onCreate(Bundle savedInstanceState) { + logger.d("message_activity#onCreate:%s", this); + super.onCreate(savedInstanceState); + currentSessionKey = getIntent().getStringExtra(IntentConstant.KEY_SESSION_KEY); + initSoftInputMethod(); + initEmo(); + initAlbumHelper(); + initAudioHandler(); + initAudioSensor(); + initView(); + imServiceConnector.connect(this); + EventBus.getDefault().register(this, SysConstant.MESSAGE_EVENTBUS_PRIORITY); + logger.d("message_activity#register im service and eventBus"); + } + + // 触发条件,imservice链接成功,或者newIntent + private void initData() { + historyTimes = 0; + adapter.clearItem(); + ImageMessage.clearImageMessageList(); + loginUser = imService.getLoginManager().getLoginInfo(); + peerEntity = imService.getSessionManager().findPeerEntity(currentSessionKey); + // 头像、历史消息加载、取消通知 + setTitleByUser(); + reqHistoryMsg(); + adapter.setImService(imService, loginUser); + imService.getUnReadMsgManager().readUnreadSession(currentSessionKey); + imService.getNotificationManager().cancelSessionNotifications(currentSessionKey); + } + + private void initSoftInputMethod() { + this.getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE); + inputManager = (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE); + + receiver = new switchInputMethodReceiver(); + IntentFilter filter = new IntentFilter(); + filter.addAction("android.intent.action.INPUT_METHOD_CHANGED"); + registerReceiver(receiver, filter); + + SystemConfigSp.instance().init(this); + String str = Settings.Secure.getString(MessageActivity.this.getContentResolver(), Settings.Secure.DEFAULT_INPUT_METHOD); + String[] strArr = str.split("\\."); + if (strArr.length >= 3) { + currentInputMethod = strArr[1]; + if (SystemConfigSp.instance().getStrConfig(SystemConfigSp.SysCfgDimension.DEFAULTINPUTMETHOD).equals(currentInputMethod)) { + keyboardHeight = SystemConfigSp.instance().getIntConfig(SystemConfigSp.SysCfgDimension.KEYBOARDHEIGHT); + } else { + SystemConfigSp.instance().setStrConfig(SystemConfigSp.SysCfgDimension.DEFAULTINPUTMETHOD, currentInputMethod); + } + } + } + + /** + * 本身位于Message页面,点击通知栏其他session的消息 + */ + @Override + protected void onNewIntent(Intent intent) { + logger.d("message_activity#onNewIntent:%s", this); + super.onNewIntent(intent); + setIntent(intent); + historyTimes = 0; + if (intent == null) { + return; + } + String newSessionKey = getIntent().getStringExtra(IntentConstant.KEY_SESSION_KEY); + if (newSessionKey == null) { + return; + } + logger.d("chat#newSessionInfo:%s", newSessionKey); + if (!newSessionKey.equals(currentSessionKey)) { + currentSessionKey = newSessionKey; + initData(); + } + } + + @Override + protected void onResume() { + logger.d("message_activity#onresume:%s", this); + super.onResume(); + IMApplication.gifRunning = true; + historyTimes = 0; + // not the first time + if (imService != null) { + // 处理session的未读信息 + handleUnreadMsgs(); + } + } + + @Override + protected void onDestroy() { + logger.d("message_activity#onDestroy:%s", this); + historyTimes = 0; + imServiceConnector.disconnect(this); + EventBus.getDefault().unregister(this); + adapter.clearItem(); + albumList.clear(); + sensorManager.unregisterListener(this, sensor); + ImageMessage.clearImageMessageList(); + unregisterReceiver(receiver); + super.onDestroy(); + } + + /** + * 设定聊天名称 + * 1. 如果是user类型, 点击触发UserProfile + * 2. 如果是群组,检测自己是不是还在群中 + */ + private void setTitleByUser() { + setTitle(peerEntity.getMainName()); + int peerType = peerEntity.getType(); + switch (peerType) { + case DBConstant.SESSION_TYPE_GROUP: { + GroupEntity group = (GroupEntity) peerEntity; + Set memberLists = group.getlistGroupMemberIds(); + if (!memberLists.contains(loginUser.getPeerId())) { + Toast.makeText(MessageActivity.this, R.string.no_group_member, Toast.LENGTH_SHORT).show(); + } + } + break; + case DBConstant.SESSION_TYPE_SINGLE: { + topTitleTxt.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + IMUIHelper.openUserProfileActivity(MessageActivity.this, peerEntity.getPeerId()); + } + }); + } + break; + } + } + + @Override + protected void onActivityResult(int requestCode, int resultCode, Intent data) { + if (RESULT_OK != resultCode) + return; + switch (requestCode) { + case SysConstant.CAMERA_WITH_DATA: + handleTakePhotoData(data); + break; + case SysConstant.ALBUM_BACK_DATA: + logger.d("pic#ALBUM_BACK_DATA"); + setIntent(data); + break; + } + super.onActivityResult(requestCode, resultCode, data); + } + + private void handleImagePickData(List list) { + ArrayList listMsg = new ArrayList<>(); + ArrayList itemList = (ArrayList) list; + for (ImageItem item : itemList) { + ImageMessage imageMessage = ImageMessage.buildForSend(item, loginUser, peerEntity); + listMsg.add(imageMessage); + pushList(imageMessage); + } + imService.getMessageManager().sendImages(listMsg); + } + + + public void onEventMainThread(SelectEvent event) { + List itemList = event.getList(); + if (itemList != null || itemList.size() > 0) + handleImagePickData(itemList); + } + + /** + * 背景: 1.EventBus的cancelEventDelivery的只能在postThread中运行,而且没有办法绕过这一点 + * 2. onEvent(A a) onEventMainThread(A a) 这个两个是没有办法共存的 + * 解决: 抽离出那些需要优先级的event,在onEvent通过handler调用主线程, + * 然后cancelEventDelivery + *

+ * todo need find good solution + */ + public void onEvent(PriorityEvent event) { + switch (event.event) { + case MSG_RECEIVED_MESSAGE: { + MessageEntity entity = (MessageEntity) event.object; + /**正式当前的会话*/ + if (currentSessionKey.equals(entity.getSessionKey())) { + Message message = Message.obtain(); + message.what = HandlerConstant.MSG_RECEIVED_MESSAGE; + message.obj = entity; + uiHandler.sendMessage(message); + EventBus.getDefault().cancelEventDelivery(event); + } + } + break; + } + } + + public void onEventMainThread(MessageEvent event) { + MessageEvent.Event type = event.getEvent(); + MessageEntity entity = event.getMessageEntity(); + switch (type) { + case ACK_SEND_MESSAGE_OK: { + onMsgAck(event.getMessageEntity()); + } + break; + + case ACK_SEND_MESSAGE_FAILURE: + // 失败情况下新添提醒 + showToast(R.string.message_send_failed); + case ACK_SEND_MESSAGE_TIME_OUT: { + onMsgUnAckTimeoutOrFailure(event.getMessageEntity()); + } + break; + + case HANDLER_IMAGE_UPLOAD_FAILD: { + logger.d("pic#onUploadImageFaild"); + ImageMessage imageMessage = (ImageMessage) event.getMessageEntity(); + adapter.updateItemState(imageMessage); + showToast(R.string.message_send_failed); + } + break; + + case HANDLER_IMAGE_UPLOAD_SUCCESS: { + ImageMessage imageMessage = (ImageMessage) event.getMessageEntity(); + adapter.updateItemState(imageMessage); + } + break; + + case HISTORY_MSG_OBTAIN: { + if (historyTimes == 1) { + adapter.clearItem(); + reqHistoryMsg(); + } + } + break; + } + } + + /** + * audio状态的语音还在使用这个 + */ + protected void initAudioHandler() { + uiHandler = new Handler() { + public void handleMessage(Message msg) { + super.handleMessage(msg); + switch (msg.what) { + case HandlerConstant.HANDLER_RECORD_FINISHED: + onRecordVoiceEnd((Float) msg.obj); + break; + + // 录音结束 + case HandlerConstant.HANDLER_STOP_PLAY: + // 其他地方处理了 + //adapter.stopVoicePlayAnim((String) msg.obj); + break; + + case HandlerConstant.RECEIVE_MAX_VOLUME: + onReceiveMaxVolume((Integer) msg.obj); + break; + + case HandlerConstant.RECORD_AUDIO_TOO_LONG: + doFinishRecordAudio(); + break; + + case HandlerConstant.MSG_RECEIVED_MESSAGE: + MessageEntity entity = (MessageEntity) msg.obj; + onMsgRecv(entity); + break; + + default: + break; + } + } + }; + } + + /** + * [备注] DB保存,与session的更新manager已经做了 + * + * @param messageEntity + */ + private void onMsgAck(MessageEntity messageEntity) { + logger.d("message_activity#onMsgAck"); + int msgId = messageEntity.getMsgId(); + logger.d("chat#onMsgAck, msgId:%d", msgId); + + /**到底采用哪种ID呐??*/ + long localId = messageEntity.getId(); + adapter.updateItemState(messageEntity); + } + + + private void handleUnreadMsgs() { + logger.d("messageacitivity#handleUnreadMsgs sessionId:%s", currentSessionKey); + // 清除未读消息 + UnreadEntity unreadEntity = imService.getUnReadMsgManager().findUnread(currentSessionKey); + if (null == unreadEntity) { + return; + } + int unReadCnt = unreadEntity.getUnReadCnt(); + if (unReadCnt > 0) { + imService.getNotificationManager().cancelSessionNotifications(currentSessionKey); + adapter.notifyDataSetChanged(); + scrollToBottomListItem(); + } + } + + + // 肯定是在当前的session内 + private void onMsgRecv(MessageEntity entity) { + logger.d("message_activity#onMsgRecv"); + + imService.getUnReadMsgManager().ackReadMsg(entity); + logger.d("chat#start pushList"); + pushList(entity); + ListView lv = lvPTR.getRefreshableView(); + if (lv != null) { + + if (lv.getLastVisiblePosition() < adapter.getCount()) { + textView_new_msg_tip.setVisibility(View.VISIBLE); + } else { + scrollToBottomListItem(); + } + } + } + + + private void onMsgUnAckTimeoutOrFailure(MessageEntity messageEntity) { + logger.d("chat#onMsgUnAckTimeoutOrFailure, msgId:%s", messageEntity.getMsgId()); + // msgId 应该还是为0 + adapter.updateItemState(messageEntity); + } + + + /** + * @Description 显示联系人界面 + */ + private void showGroupManageActivity() { + Intent i = new Intent(this, GroupManagermentActivity.class); + i.putExtra(IntentConstant.KEY_SESSION_KEY, currentSessionKey); + startActivity(i); + } + + /** + * @Description 初始化AudioManager,用于访问控制音量和钤声模式 + */ + private void initAudioSensor() { + sensorManager = (SensorManager) getSystemService(Context.SENSOR_SERVICE); + sensor = sensorManager.getDefaultSensor(Sensor.TYPE_PROXIMITY); + sensorManager.registerListener(this, sensor, SensorManager.SENSOR_DELAY_NORMAL); + } + + /** + * @Description 初始化数据(相册,表情,数据库相关) + */ + private void initAlbumHelper() { + albumHelper = AlbumHelper.getHelper(MessageActivity.this); + albumList = albumHelper.getImagesBucketList(false); + } + + private void initEmo() { + Emoparser.getInstance(MessageActivity.this); + IMApplication.gifRunning = true; + } + + /** + * @Description 初始化界面控件 + * 有点庞大 todo + */ + private void initView() { + // 绑定布局资源(注意放所有资源初始化之前) + LayoutInflater.from(this).inflate(R.layout.tt_activity_message, topContentView); + + //TOP_CONTENT_VIEW + setLeftButton(R.drawable.tt_top_back); + setLeftText(getResources().getString(R.string.top_left_back)); + setRightButton(R.drawable.tt_top_right_group_manager); + topLeftBtn.setOnClickListener(this); + letTitleTxt.setOnClickListener(this); + topRightBtn.setOnClickListener(this); + + // 列表控件(开源PTR) + lvPTR = (PullToRefreshListView) this.findViewById(R.id.message_list); + textView_new_msg_tip = (TextView) findViewById(R.id.tt_new_msg_tip); + lvPTR.getRefreshableView().addHeaderView(LayoutInflater.from(this).inflate(R.layout.tt_messagelist_header,lvPTR.getRefreshableView(), false)); + Drawable loadingDrawable = getResources().getDrawable(R.drawable.pull_to_refresh_indicator); + final int indicatorWidth = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 29, + getResources().getDisplayMetrics()); + loadingDrawable.setBounds(new Rect(0, indicatorWidth, 0, indicatorWidth)); + lvPTR.getLoadingLayoutProxy().setLoadingDrawable(loadingDrawable); + lvPTR.getRefreshableView().setCacheColorHint(Color.WHITE); + lvPTR.getRefreshableView().setSelector(new ColorDrawable(Color.WHITE)); + lvPTR.getRefreshableView().setOnTouchListener(lvPTROnTouchListener); + adapter = new MessageAdapter(this); + lvPTR.setAdapter(adapter); + lvPTR.setOnRefreshListener(this); + lvPTR.setOnScrollListener(new PauseOnScrollListener(ImageLoader.getInstance(), true, true) { + @Override + public void onScrollStateChanged(AbsListView view, int scrollState) { + switch (scrollState) { + case AbsListView.OnScrollListener.SCROLL_STATE_IDLE: + if (view.getLastVisiblePosition() == (view.getCount() - 1)) { + textView_new_msg_tip.setVisibility(View.GONE); + } + break; + } + } + }); + textView_new_msg_tip.setOnClickListener(this); + + // 界面底部输入框布局 + sendBtn = (TextView) this.findViewById(R.id.send_message_btn); + recordAudioBtn = (Button) this.findViewById(R.id.record_voice_btn); + audioInputImg = (ImageView) this.findViewById(R.id.voice_btn); + messageEdt = (CustomEditView) this.findViewById(R.id.message_text); + RelativeLayout.LayoutParams messageEdtParam = (LayoutParams) messageEdt.getLayoutParams(); + messageEdtParam.addRule(RelativeLayout.LEFT_OF, R.id.show_emo_btn); + messageEdtParam.addRule(RelativeLayout.RIGHT_OF, R.id.voice_btn); + keyboardInputImg = (ImageView) this.findViewById(R.id.show_keyboard_btn); + addPhotoBtn = (ImageView) this.findViewById(R.id.show_add_photo_btn); + addEmoBtn = (ImageView) this.findViewById(R.id.show_emo_btn); + messageEdt.setOnFocusChangeListener(msgEditOnFocusChangeListener); + messageEdt.setOnClickListener(this); + messageEdt.addTextChangedListener(this); + addPhotoBtn.setOnClickListener(this); + addEmoBtn.setOnClickListener(this); + keyboardInputImg.setOnClickListener(this); + audioInputImg.setOnClickListener(this); + recordAudioBtn.setOnTouchListener(this); + sendBtn.setOnClickListener(this); + initSoundVolumeDlg(); + + //OTHER_PANEL_VIEW + addOthersPanelView = findViewById(R.id.add_others_panel); + LayoutParams params = (LayoutParams) addOthersPanelView.getLayoutParams(); + if (keyboardHeight > 0) { + params.height = keyboardHeight; + addOthersPanelView.setLayoutParams(params); + } + View takePhotoBtn = findViewById(R.id.take_photo_btn); + View takeCameraBtn = findViewById(R.id.take_camera_btn); + takePhotoBtn.setOnClickListener(this); + takeCameraBtn.setOnClickListener(this); + + //EMO_LAYOUT + emoLayout = (LinearLayout) findViewById(R.id.emo_layout); + LayoutParams paramEmoLayout = (LayoutParams) emoLayout.getLayoutParams(); + if (keyboardHeight > 0) { + paramEmoLayout.height = keyboardHeight; + emoLayout.setLayoutParams(paramEmoLayout); + } + emoGridView = (EmoGridView) findViewById(R.id.emo_gridview); + yayaEmoGridView = (YayaEmoGridView) findViewById(R.id.yaya_emo_gridview); + emoRadioGroup = (RadioGroup) findViewById(R.id.emo_tab_group); + emoGridView.setOnEmoGridViewItemClick(onEmoGridViewItemClick); + emoGridView.setAdapter(); + yayaEmoGridView.setOnEmoGridViewItemClick(yayaOnEmoGridViewItemClick); + yayaEmoGridView.setAdapter(); + emoRadioGroup.setOnCheckedChangeListener(emoOnCheckedChangeListener); + + + //LOADING + View view = LayoutInflater.from(MessageActivity.this) + .inflate(R.layout.tt_progress_ly, null); + progressbar = (MGProgressbar) view.findViewById(R.id.tt_progress); + LayoutParams pgParms = new LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, + ViewGroup.LayoutParams.MATCH_PARENT); + pgParms.bottomMargin = 50; + addContentView(view, pgParms); + + //ROOT_LAYOUT_LISTENER + baseRoot.getViewTreeObserver().addOnGlobalLayoutListener(onGlobalLayoutListener); + } + + /** + * @Description 初始化音量对话框 + */ + private void initSoundVolumeDlg() { + soundVolumeDialog = new Dialog(this, R.style.SoundVolumeStyle); + soundVolumeDialog.requestWindowFeature(Window.FEATURE_NO_TITLE); + soundVolumeDialog.getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN, + WindowManager.LayoutParams.FLAG_FULLSCREEN); + soundVolumeDialog.setContentView(R.layout.tt_sound_volume_dialog); + soundVolumeDialog.setCanceledOnTouchOutside(true); + soundVolumeImg = (ImageView) soundVolumeDialog.findViewById(R.id.sound_volume_img); + soundVolumeLayout = (LinearLayout) soundVolumeDialog.findViewById(R.id.sound_volume_bk); + } + + /** + * 1.初始化请求历史消息 + * 2.本地消息不全,也会触发 + */ + private void reqHistoryMsg() { + historyTimes++; + List msgList = imService.getMessageManager().loadHistoryMsg(historyTimes,currentSessionKey,peerEntity); + pushList(msgList); + scrollToBottomListItem(); + } + /** + * @param msg + */ + public void pushList(MessageEntity msg) { + logger.d("chat#pushList msgInfo:%s", msg); + adapter.addItem(msg); + } + + public void pushList(List entityList) { + logger.d("chat#pushList list:%d", entityList.size()); + adapter.loadHistoryList(entityList); + } + + + /** + * @Description 录音超时(60s),发消息调用该方法 + */ + public void doFinishRecordAudio() { + try { + if (audioRecorderInstance.isRecording()) { + audioRecorderInstance.setRecording(false); + } + if (soundVolumeDialog.isShowing()) { + soundVolumeDialog.dismiss(); + } + + recordAudioBtn.setBackgroundResource(R.drawable.tt_pannel_btn_voiceforward_normal); + + audioRecorderInstance.setRecordTime(SysConstant.MAX_SOUND_RECORD_TIME); + onRecordVoiceEnd(SysConstant.MAX_SOUND_RECORD_TIME); + } catch (Exception e) { + } + } + + /** + * @param voiceValue + * @Description 根据分贝值设置录音时的音量动画 + */ + private void onReceiveMaxVolume(int voiceValue) { + if (voiceValue < 200.0) { + soundVolumeImg.setImageResource(R.drawable.tt_sound_volume_01); + } else if (voiceValue > 200.0 && voiceValue < 600) { + soundVolumeImg.setImageResource(R.drawable.tt_sound_volume_02); + } else if (voiceValue > 600.0 && voiceValue < 1200) { + soundVolumeImg.setImageResource(R.drawable.tt_sound_volume_03); + } else if (voiceValue > 1200.0 && voiceValue < 2400) { + soundVolumeImg.setImageResource(R.drawable.tt_sound_volume_04); + } else if (voiceValue > 2400.0 && voiceValue < 10000) { + soundVolumeImg.setImageResource(R.drawable.tt_sound_volume_05); + } else if (voiceValue > 10000.0 && voiceValue < 28000.0) { + soundVolumeImg.setImageResource(R.drawable.tt_sound_volume_06); + } else if (voiceValue > 28000.0) { + soundVolumeImg.setImageResource(R.drawable.tt_sound_volume_07); + } + } + + + @Override + public void onConfigurationChanged(Configuration config) { + super.onConfigurationChanged(config); + } + + /** + * @param data + * @Description 处理拍照后的数据 + * 应该是从某个 activity回来的 + */ + private void handleTakePhotoData(Intent data) { + ImageMessage imageMessage = ImageMessage.buildForSend(takePhotoSavePath, loginUser, peerEntity); + List sendList = new ArrayList<>(1); + sendList.add(imageMessage); + imService.getMessageManager().sendImages(sendList); + // 格式有些问题 + pushList(imageMessage); + messageEdt.clearFocus();//消除焦点 + } + + /** + * @param audioLen + * @Description 录音结束后处理录音数据 + */ + private void onRecordVoiceEnd(float audioLen) { + logger.d("message_activity#chat#audio#onRecordVoiceEnd audioLen:%f", audioLen); + AudioMessage audioMessage = AudioMessage.buildForSend(audioLen, audioSavePath, loginUser, peerEntity); + imService.getMessageManager().sendVoice(audioMessage); + pushList(audioMessage); + } + + @Override + public void onPullUpToRefresh(PullToRefreshBase refreshView) { + } + + @Override + public void onPullDownToRefresh( + final PullToRefreshBase refreshView) { + // 获取消息 + refreshView.postDelayed(new Runnable() { + @Override + public void run() { + ListView mlist = lvPTR.getRefreshableView(); + int preSum = mlist.getCount(); + MessageEntity messageEntity = adapter.getTopMsgEntity(); + if (messageEntity != null) { + List historyMsgInfo = imService.getMessageManager().loadHistoryMsg(messageEntity, historyTimes); + if (historyMsgInfo.size() > 0) { + historyTimes++; + adapter.loadHistoryList(historyMsgInfo); + } + } + + int afterSum = mlist.getCount(); + mlist.setSelection(afterSum - preSum); + /**展示位置为这次消息的最末尾*/ + //mlist.setSelection(size); + // 展示顶部 +// if (!(mlist).isStackFromBottom()) { +// mlist.setStackFromBottom(true); +// } +// mlist.setStackFromBottom(false); + refreshView.onRefreshComplete(); + } + }, 200); + } + + + @Override + public void onClick(View v) { + final int id = v.getId(); + switch (id) { + case R.id.left_btn: + case R.id.left_txt: + actFinish(); + break; + case R.id.right_btn: + showGroupManageActivity(); + break; + case R.id.show_add_photo_btn: { + recordAudioBtn.setVisibility(View.GONE); + keyboardInputImg.setVisibility(View.GONE); + messageEdt.setVisibility(View.VISIBLE); + audioInputImg.setVisibility(View.VISIBLE); + addEmoBtn.setVisibility(View.VISIBLE); + + if (keyboardHeight != 0) { + this.getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_ADJUST_NOTHING); + } + if (addOthersPanelView.getVisibility() == View.VISIBLE) { + if (!messageEdt.hasFocus()) { + messageEdt.requestFocus(); + } + inputManager.toggleSoftInputFromWindow(messageEdt.getWindowToken(), 1, 0); + if (keyboardHeight == 0) { + addOthersPanelView.setVisibility(View.GONE); + } + } else if (addOthersPanelView.getVisibility() == View.GONE) { + addOthersPanelView.setVisibility(View.VISIBLE); + inputManager.hideSoftInputFromWindow(messageEdt.getWindowToken(), 0); + } + if (null != emoLayout + && emoLayout.getVisibility() == View.VISIBLE) { + emoLayout.setVisibility(View.GONE); + } + + scrollToBottomListItem(); + } + break; + case R.id.take_photo_btn: { + if (albumList.size() < 1) { + Toast.makeText(MessageActivity.this, + getResources().getString(R.string.not_found_album), Toast.LENGTH_LONG) + .show(); + return; + } + // 选择图片的时候要将session的整个回话 传过来 + Intent intent = new Intent(MessageActivity.this, PickPhotoActivity.class); + intent.putExtra(IntentConstant.KEY_SESSION_KEY, currentSessionKey); + startActivityForResult(intent, SysConstant.ALBUM_BACK_DATA); + + MessageActivity.this.overridePendingTransition(R.anim.tt_album_enter, R.anim.tt_stay); + //addOthersPanelView.setVisibility(View.GONE); + messageEdt.clearFocus();//切记清除焦点 + scrollToBottomListItem(); + } + break; + case R.id.take_camera_btn: { + Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE); + takePhotoSavePath = CommonUtil.getImageSavePath(String.valueOf(System + .currentTimeMillis()) + + ".jpg"); + intent.putExtra(MediaStore.EXTRA_OUTPUT, Uri.fromFile(new File(takePhotoSavePath))); + startActivityForResult(intent, SysConstant.CAMERA_WITH_DATA); + //addOthersPanelView.setVisibility(View.GONE); + messageEdt.clearFocus();//切记清除焦点 + scrollToBottomListItem(); + } + break; + case R.id.show_emo_btn: { + /**yingmu 调整成键盘输出*/ + recordAudioBtn.setVisibility(View.GONE); + keyboardInputImg.setVisibility(View.GONE); + messageEdt.setVisibility(View.VISIBLE); + audioInputImg.setVisibility(View.VISIBLE); + addEmoBtn.setVisibility(View.VISIBLE); + /**end*/ + if (keyboardHeight != 0) { + this.getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_ADJUST_NOTHING); + } + if (emoLayout.getVisibility() == View.VISIBLE) { + if (!messageEdt.hasFocus()) { + messageEdt.requestFocus(); + } + inputManager.toggleSoftInputFromWindow(messageEdt.getWindowToken(), 1, 0); + if (keyboardHeight == 0) { + emoLayout.setVisibility(View.GONE); + } + } else if (emoLayout.getVisibility() == View.GONE) { + emoLayout.setVisibility(View.VISIBLE); + yayaEmoGridView.setVisibility(View.VISIBLE); + emoRadioGroup.check(R.id.tab1); + emoGridView.setVisibility(View.GONE); + inputManager.hideSoftInputFromWindow(messageEdt.getWindowToken(), 0); + } + if (addOthersPanelView.getVisibility() == View.VISIBLE) { + addOthersPanelView.setVisibility(View.GONE); + } + } + break; + case R.id.send_message_btn: { + logger.d("message_activity#send btn clicked"); + + String content = messageEdt.getText().toString(); + logger.d("message_activity#chat content:%s", content); + if (content.trim().equals("")) { + Toast.makeText(MessageActivity.this, + getResources().getString(R.string.message_null), Toast.LENGTH_LONG).show(); + return; + } + TextMessage textMessage = TextMessage.buildForSend(content, loginUser, peerEntity); + imService.getMessageManager().sendText(textMessage); + messageEdt.setText(""); + pushList(textMessage); + scrollToBottomListItem(); + } + break; + case R.id.voice_btn: { + inputManager.hideSoftInputFromWindow(messageEdt.getWindowToken(), 0); + messageEdt.setVisibility(View.GONE); + audioInputImg.setVisibility(View.GONE); + recordAudioBtn.setVisibility(View.VISIBLE); + keyboardInputImg.setVisibility(View.VISIBLE); + emoLayout.setVisibility(View.GONE); + addOthersPanelView.setVisibility(View.GONE); + messageEdt.setText(""); + } + break; + case R.id.show_keyboard_btn: { + recordAudioBtn.setVisibility(View.GONE); + keyboardInputImg.setVisibility(View.GONE); + messageEdt.setVisibility(View.VISIBLE); + audioInputImg.setVisibility(View.VISIBLE); + addEmoBtn.setVisibility(View.VISIBLE); + } + break; + case R.id.message_text: + break; + case R.id.tt_new_msg_tip: + { + scrollToBottomListItem(); + textView_new_msg_tip.setVisibility(View.GONE); + } + break; + } + } + + // 主要是录制语音的 + @Override + public boolean onTouch(View v, MotionEvent event) { + int id = v.getId(); + scrollToBottomListItem(); + if (id == R.id.record_voice_btn) { + if (event.getAction() == MotionEvent.ACTION_DOWN) { + + if (AudioPlayerHandler.getInstance().isPlaying()) + AudioPlayerHandler.getInstance().stopPlayer(); + y1 = event.getY(); + recordAudioBtn.setBackgroundResource(R.drawable.tt_pannel_btn_voiceforward_pressed); + recordAudioBtn.setText(MessageActivity.this.getResources().getString( + R.string.release_to_send_voice)); + + soundVolumeImg.setImageResource(R.drawable.tt_sound_volume_01); + soundVolumeImg.setVisibility(View.VISIBLE); + soundVolumeLayout.setBackgroundResource(R.drawable.tt_sound_volume_default_bk); + soundVolumeDialog.show(); + audioSavePath = CommonUtil + .getAudioSavePath(IMLoginManager.instance().getLoginId()); + + // 这个callback很蛋疼,发送消息从MotionEvent.ACTION_UP 判断 + audioRecorderInstance = new AudioRecordHandler(audioSavePath); + + audioRecorderThread = new Thread(audioRecorderInstance); + audioRecorderInstance.setRecording(true); + logger.d("message_activity#audio#audio record thread starts"); + audioRecorderThread.start(); + } else if (event.getAction() == MotionEvent.ACTION_MOVE) { + y2 = event.getY(); + if (y1 - y2 > 180) { + soundVolumeImg.setVisibility(View.GONE); + soundVolumeLayout.setBackgroundResource(R.drawable.tt_sound_volume_cancel_bk); + } else { + soundVolumeImg.setVisibility(View.VISIBLE); + soundVolumeLayout.setBackgroundResource(R.drawable.tt_sound_volume_default_bk); + } + } else if (event.getAction() == MotionEvent.ACTION_UP) { + y2 = event.getY(); + if (audioRecorderInstance.isRecording()) { + audioRecorderInstance.setRecording(false); + } + if (soundVolumeDialog.isShowing()) { + soundVolumeDialog.dismiss(); + } + recordAudioBtn.setBackgroundResource(R.drawable.tt_pannel_btn_voiceforward_normal); + recordAudioBtn.setText(MessageActivity.this.getResources().getString( + R.string.tip_for_voice_forward)); + if (y1 - y2 <= 180) { + if (audioRecorderInstance.getRecordTime() >= 0.5) { + if (audioRecorderInstance.getRecordTime() < SysConstant.MAX_SOUND_RECORD_TIME) { + Message msg = uiHandler.obtainMessage(); + msg.what = HandlerConstant.HANDLER_RECORD_FINISHED; + msg.obj = audioRecorderInstance.getRecordTime(); + uiHandler.sendMessage(msg); + } + } else { + soundVolumeImg.setVisibility(View.GONE); + soundVolumeLayout + .setBackgroundResource(R.drawable.tt_sound_volume_short_tip_bk); + soundVolumeDialog.show(); + Timer timer = new Timer(); + timer.schedule(new TimerTask() { + public void run() { + if (soundVolumeDialog.isShowing()) + soundVolumeDialog.dismiss(); + this.cancel(); + } + }, 700); + } + } + } + } + return false; + } + + @Override + protected void onStop() { + logger.d("message_activity#onStop:%s", this); + + if (null != adapter) { + adapter.hidePopup(); + } + + AudioPlayerHandler.getInstance().clear(); + super.onStop(); + } + + @Override + protected void onStart() { + logger.d("message_activity#onStart:%s", this); + super.onStart(); + } + + @Override + public void afterTextChanged(Editable s) { + } + + @Override + public void beforeTextChanged(CharSequence s, int start, int count, + int after) { + } + + @Override + public void onTextChanged(CharSequence s, int start, int before, int count) { + if (s.length() > 0) { + sendBtn.setVisibility(View.VISIBLE); + RelativeLayout.LayoutParams param = (LayoutParams) messageEdt + .getLayoutParams(); + param.addRule(RelativeLayout.LEFT_OF, R.id.show_emo_btn); + addPhotoBtn.setVisibility(View.GONE); + } else { + addPhotoBtn.setVisibility(View.VISIBLE); + RelativeLayout.LayoutParams param = (LayoutParams) messageEdt + .getLayoutParams(); + param.addRule(RelativeLayout.LEFT_OF, R.id.show_emo_btn); + sendBtn.setVisibility(View.GONE); + } + } + + /** + * @Description 滑动到列表底部 + */ + private void scrollToBottomListItem() { + logger.d("message_activity#scrollToBottomListItem"); + + // todo eric, why use the last one index + 2 can real scroll to the + // bottom? + ListView lv = lvPTR.getRefreshableView(); + if (lv != null) { + lv.setSelection(adapter.getCount() + 1); + } + textView_new_msg_tip.setVisibility(View.GONE); + } + + @Override + protected void onPause() { + logger.d("message_activity#onPause:%s", this); + super.onPause(); + } + + @Override + public void onAccuracyChanged(Sensor arg0, int arg1) { + } + + @Override + public void onSensorChanged(SensorEvent arg0) { + try { + if (!AudioPlayerHandler.getInstance().isPlaying()) { + return; + } + float range = arg0.values[0]; + if (null != sensor && range == sensor.getMaximumRange()) { + // 屏幕恢复亮度 + AudioPlayerHandler.getInstance().setAudioMode(AudioManager.MODE_NORMAL, this); + } else { + // 屏幕变黑 + AudioPlayerHandler.getInstance().setAudioMode(AudioManager.MODE_IN_CALL, this); + } + } catch (Exception e) { + logger.error(e); + } + } + + public static Handler getUiHandler() { + return uiHandler; + } + + private void actFinish() { + inputManager.hideSoftInputFromWindow(messageEdt.getWindowToken(), 0); + IMStackManager.getStackManager().popTopActivitys(MainActivity.class); + IMApplication.gifRunning = false; + MessageActivity.this.finish(); + } + + private RadioGroup.OnCheckedChangeListener emoOnCheckedChangeListener = new RadioGroup.OnCheckedChangeListener() { + @Override + public void onCheckedChanged(RadioGroup radioGroup, int id) { + switch (id) { + case R.id.tab2: + if (emoGridView.getVisibility() != View.VISIBLE) { + yayaEmoGridView.setVisibility(View.GONE); + emoGridView.setVisibility(View.VISIBLE); + } + break; + case R.id.tab1: + if (yayaEmoGridView.getVisibility() != View.VISIBLE) { + emoGridView.setVisibility(View.GONE); + yayaEmoGridView.setVisibility(View.VISIBLE); + } + break; + } + } + }; + + private YayaEmoGridView.OnEmoGridViewItemClick yayaOnEmoGridViewItemClick = new YayaEmoGridView.OnEmoGridViewItemClick() { + @Override + public void onItemClick(int facesPos, int viewIndex) { + int resId = Emoparser.getInstance(MessageActivity.this).getYayaResIdList()[facesPos]; + logger.d("message_activity#yayaEmoGridView be clicked"); + + String content = Emoparser.getInstance(MessageActivity.this).getYayaIdPhraseMap() + .get(resId); + if (content.equals("")) { + Toast.makeText(MessageActivity.this, + getResources().getString(R.string.message_null), Toast.LENGTH_LONG).show(); + return; + } + + TextMessage textMessage = TextMessage.buildForSend(content, loginUser, peerEntity); + imService.getMessageManager().sendText(textMessage); + pushList(textMessage); + scrollToBottomListItem(); + } + }; + + private OnEmoGridViewItemClick onEmoGridViewItemClick = new OnEmoGridViewItemClick() { + @Override + public void onItemClick(int facesPos, int viewIndex) { + int deleteId = (++viewIndex) * (SysConstant.pageSize - 1); + if (deleteId > Emoparser.getInstance(MessageActivity.this).getResIdList().length) { + deleteId = Emoparser.getInstance(MessageActivity.this).getResIdList().length; + } + if (deleteId == facesPos) { + String msgContent = messageEdt.getText().toString(); + if (msgContent.isEmpty()) + return; + if (msgContent.contains("[")) + msgContent = msgContent.substring(0, msgContent.lastIndexOf("[")); + messageEdt.setText(msgContent); + } else { + int resId = Emoparser.getInstance(MessageActivity.this).getResIdList()[facesPos]; + String pharse = Emoparser.getInstance(MessageActivity.this).getIdPhraseMap() + .get(resId); + int startIndex = messageEdt.getSelectionStart(); + Editable edit = messageEdt.getEditableText(); + if (startIndex < 0 || startIndex >= edit.length()) { + if (null != pharse) { + edit.append(pharse); + } + } else { + if (null != pharse) { + edit.insert(startIndex, pharse); + } + } + } + Editable edtable = messageEdt.getText(); + int position = edtable.length(); + Selection.setSelection(edtable, position); + } + }; + + private OnTouchListener lvPTROnTouchListener = new View.OnTouchListener() { + + @Override + public boolean onTouch(View v, MotionEvent event) { + if (event.getAction() == MotionEvent.ACTION_DOWN) { + messageEdt.clearFocus(); + if (emoLayout.getVisibility() == View.VISIBLE) { + emoLayout.setVisibility(View.GONE); + } + + if (addOthersPanelView.getVisibility() == View.VISIBLE) { + addOthersPanelView.setVisibility(View.GONE); + } + inputManager.hideSoftInputFromWindow(messageEdt.getWindowToken(), 0); + } + return false; + } + }; + + private View.OnFocusChangeListener msgEditOnFocusChangeListener = new android.view.View.OnFocusChangeListener() { + @Override + public void onFocusChange(View v, boolean hasFocus) { + if (hasFocus) { + if (keyboardHeight == 0) { + addOthersPanelView.setVisibility(View.GONE); + emoLayout.setVisibility(View.GONE); + } else { + MessageActivity.this.getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_ADJUST_NOTHING); + if (addOthersPanelView.getVisibility() == View.GONE) { + addOthersPanelView.setVisibility(View.VISIBLE); + } + } + } + } + }; + + private ViewTreeObserver.OnGlobalLayoutListener onGlobalLayoutListener = new ViewTreeObserver.OnGlobalLayoutListener() { + @Override + public void onGlobalLayout() { + Rect r = new Rect(); + baseRoot.getGlobalVisibleRect(r); + // 进入Activity时会布局,第一次调用onGlobalLayout,先记录开始软键盘没有弹出时底部的位置 + if (rootBottom == Integer.MIN_VALUE) { + rootBottom = r.bottom; + return; + } + // adjustResize,软键盘弹出后高度会变小 + if (r.bottom < rootBottom) { + //按照键盘高度设置表情框和发送图片按钮框的高度 + keyboardHeight = rootBottom - r.bottom; + SystemConfigSp.instance().init(MessageActivity.this); + SystemConfigSp.instance().setIntConfig(SystemConfigSp.SysCfgDimension.KEYBOARDHEIGHT, keyboardHeight); + LayoutParams params = (LayoutParams) addOthersPanelView.getLayoutParams(); + params.height = keyboardHeight; + LayoutParams params1 = (LayoutParams) emoLayout.getLayoutParams(); + params1.height = keyboardHeight; + } + } + }; + + private class switchInputMethodReceiver extends BroadcastReceiver { + + @Override + public void onReceive(Context context, Intent intent) { + if (intent.getAction().equals("android.intent.action.INPUT_METHOD_CHANGED")) { + String str = Settings.Secure.getString(MessageActivity.this.getContentResolver(), Settings.Secure.DEFAULT_INPUT_METHOD); + String[] strArr = str.split("\\."); + if (strArr.length >= 3) { + String strCompany = strArr[1]; + if (!strCompany.equals(currentInputMethod)) { + currentInputMethod = strCompany; + SystemConfigSp.instance().setStrConfig(SystemConfigSp.SysCfgDimension.DEFAULTINPUTMETHOD, currentInputMethod); + keyboardHeight = 0; + addOthersPanelView.setVisibility(View.GONE); + emoLayout.setVisibility(View.GONE); + MessageActivity.this.getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE); +// inputManager.showSoftInput(messageEdt,0); + messageEdt.requestFocus(); + } + } + } + } + } +} diff --git a/android/app/src/main/java/com/mogujie/tt/ui/activity/PickPhotoActivity.java b/android/app/src/main/java/com/mogujie/tt/ui/activity/PickPhotoActivity.java new file mode 100644 index 000000000..1000f1b86 --- /dev/null +++ b/android/app/src/main/java/com/mogujie/tt/ui/activity/PickPhotoActivity.java @@ -0,0 +1,108 @@ + +package com.mogujie.tt.ui.activity; + +import android.app.Activity; +import android.content.Intent; +import android.graphics.Bitmap; +import android.graphics.BitmapFactory; +import android.os.Bundle; +import android.view.View; +import android.view.View.OnClickListener; +import android.widget.AdapterView; +import android.widget.AdapterView.OnItemClickListener; +import android.widget.ListView; +import android.widget.TextView; + +import com.mogujie.tt.R; +import com.mogujie.tt.ui.adapter.album.AlbumHelper; +import com.mogujie.tt.ui.adapter.album.ImageBucket; +import com.mogujie.tt.ui.adapter.album.ImageBucketAdapter; +import com.mogujie.tt.config.IntentConstant; +import com.mogujie.tt.utils.Logger; + +import java.io.Serializable; +import java.util.List; + +/** + * @Description 相册列表 + * @author Nana + * @date 2014-5-6 + */ +public class PickPhotoActivity extends Activity { + List dataList = null; + ListView listView = null; + ImageBucketAdapter adapter = null; + AlbumHelper helper = null; + TextView cancel = null; + public static Bitmap bimap = null; + boolean touchable = true; + private String currentSessionKey; + private Logger logger = Logger.getLogger(PickPhotoActivity.class); + + @Override + protected void onActivityResult(int requestCode, int resultCode, Intent data) { + if(resultCode==Activity.RESULT_OK) + { + this.finish(); + } + } + + @Override + protected void onCreate(Bundle savedInstanceState) { + logger.d("pic#PickPhotoActivity onCreate"); + super.onCreate(savedInstanceState); + setContentView(R.layout.tt_activity_pick_photo); + initData(); + initView(); + } + + /** + * 初始化数据 + */ + private void initData() { + Bundle bundle = getIntent().getExtras(); + currentSessionKey = bundle.getString(IntentConstant.KEY_SESSION_KEY); + helper = AlbumHelper.getHelper(getApplicationContext()); + dataList = helper.getImagesBucketList(true); + bimap = BitmapFactory.decodeResource(getResources(), + R.drawable.tt_default_album_grid_image); + } + + /** + * 初始化view + */ + private void initView() { + listView = (ListView) findViewById(R.id.list); + adapter = new ImageBucketAdapter(this, dataList); + + listView.setAdapter(adapter); +// listView.setOnTouchListener(this); + + listView.setOnItemClickListener(new OnItemClickListener() { + @Override + public void onItemClick(AdapterView parent, View view, + int position, long id) { + Intent intent = new Intent(PickPhotoActivity.this, + ImageGridActivity.class); + intent.putExtra(IntentConstant.EXTRA_IMAGE_LIST, + (Serializable) dataList.get(position).imageList); + intent.putExtra(IntentConstant.EXTRA_ALBUM_NAME, + dataList.get(position).bucketName); + intent.putExtra(IntentConstant.KEY_SESSION_KEY,currentSessionKey); + startActivityForResult(intent, 1);//requestcode》=0 +// PickPhotoActivity.this.finish(); + } + }); + cancel = (TextView) findViewById(R.id.cancel); + cancel.setOnClickListener(new OnClickListener() { + @Override + public void onClick(View v) { + setResult(Activity.RESULT_OK, null); + PickPhotoActivity.this.finish(); + overridePendingTransition(R.anim.tt_stay, R.anim.tt_album_exit); + } + }); + + } + +} diff --git a/android/app/src/main/java/com/mogujie/tt/ui/activity/PreviewActivity.java b/android/app/src/main/java/com/mogujie/tt/ui/activity/PreviewActivity.java new file mode 100644 index 000000000..63f3b3ff9 --- /dev/null +++ b/android/app/src/main/java/com/mogujie/tt/ui/activity/PreviewActivity.java @@ -0,0 +1,221 @@ +package com.mogujie.tt.ui.activity; + +import android.app.Activity; +import android.graphics.Bitmap; +import android.os.Bundle; +import android.support.v4.view.PagerAdapter; +import android.support.v4.view.ViewPager.OnPageChangeListener; +import android.view.View; +import android.view.View.OnClickListener; +import android.view.ViewGroup; +import android.view.ViewGroup.LayoutParams; +import android.widget.ImageView; +import android.widget.LinearLayout; + +import com.mogujie.tt.R; +import com.mogujie.tt.ui.adapter.album.ImageGridAdapter; +import com.mogujie.tt.ui.adapter.album.ImageItem; +import com.mogujie.tt.utils.ImageUtil; +import com.mogujie.tt.utils.Logger; +import com.mogujie.tt.ui.widget.CustomViewPager; + +import java.util.HashMap; +import java.util.Iterator; +import java.util.Map; + +/** + * @author Nana + * @Description 图片预览 + * @date 2014-5-9 + */ +public class PreviewActivity extends Activity + implements + OnPageChangeListener { + + private CustomViewPager viewPager; + private ImageView[] tips; + private ImageView[] mImageViews; + private ViewGroup group; + private ImageView back; + private ImageView select; + private final ImageGridAdapter adapter = ImageGridActivity.getAdapter(); + private Map removePosition = new HashMap(); + private int curImagePosition = -1; + private Logger logger = Logger.getLogger(PreviewActivity.class); + + @Override + protected void onCreate(Bundle savedInstanceState) { + logger.d("pic#PreviewActivity onCreate"); + super.onCreate(savedInstanceState); + + setContentView(R.layout.tt_activity_preview); + initView(); + loadView(); + } + + private void initView() { + viewPager = (CustomViewPager) findViewById(R.id.viewPager); + group = (ViewGroup) findViewById(R.id.viewGroup); + back = (ImageView) findViewById(R.id.back_btn); + select = (ImageView) findViewById(R.id.select_btn); + back.setOnClickListener(new OnClickListener() { + @Override + public void onClick(View v) { + @SuppressWarnings("rawtypes") + Iterator it = removePosition.keySet().iterator(); + while (it.hasNext()) { + int key = (Integer) it.next(); + if (adapter.getSelectMap().containsKey(key)) + adapter.getSelectMap().remove(key); + } + ImageGridActivity.setAdapterSelectedMap(ImageGridActivity.getAdapter().getSelectMap()); + removePosition.clear(); + PreviewActivity.this.finish(); + } + }); + select.setOnClickListener(new OnClickListener() { + @Override + public void onClick(View v) { + if (adapter.getSelectMap().containsKey(curImagePosition)) { + ImageItem item = adapter.getSelectMap().get(curImagePosition); + item.setSelected(!item.isSelected()); + if (item.isSelected()) { + int selTotal = adapter.getSelectTotalNum(); + adapter.setSelectTotalNum(++selTotal); + if (removePosition.containsKey(curImagePosition)) { + removePosition.remove(curImagePosition); + } + ImageGridActivity.setSendText(selTotal); + select.setImageResource(R.drawable.tt_album_img_selected); + } else { + int selTotal = adapter.getSelectTotalNum(); + adapter.setSelectTotalNum(--selTotal); + removePosition.put(curImagePosition, curImagePosition); + ImageGridActivity.setSendText(selTotal); + select.setImageResource(R.drawable.tt_album_img_select_nor); + } + } + } + }); + } + + @Override + protected void onDestroy() { + super.onDestroy(); + } + + private void loadView() { + mImageViews = new ImageView[adapter.getSelectMap().size()]; + + if (adapter.getSelectMap().size() > 1) { + tips = new ImageView[adapter.getSelectMap().size()]; + for (int i = 0; i < tips.length; i++) { + ImageView imageView = new ImageView(this); + imageView.setLayoutParams(new LayoutParams(10, 10)); + tips[i] = imageView; + if (i == 0) { + tips[i].setBackgroundResource(R.drawable.tt_default_dot_down); + } else { + tips[i].setBackgroundResource(R.drawable.tt_default_dot_up); + } + LinearLayout.LayoutParams layoutParams = new LinearLayout.LayoutParams(new ViewGroup.LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT)); + layoutParams.leftMargin = 5; + layoutParams.rightMargin = 5; + group.addView(imageView, layoutParams); + } + } + + Iterator it = adapter.getSelectMap().keySet().iterator(); + int index = -1; + while (it.hasNext()) { + int key = (Integer) it.next(); + ImageItem item = adapter.getSelectMap().get(key); + ImageView imageView = new ImageView(this); + mImageViews[++index] = imageView; + Bitmap bmp = ImageUtil.getBigBitmapForDisplay(item.getImagePath(), PreviewActivity.this); + if (bmp == null) + bmp = ImageUtil.getBigBitmapForDisplay(item.getThumbnailPath(), PreviewActivity.this); + if (bmp != null) + imageView.setImageBitmap(bmp); + if (index == 0) { + curImagePosition = key; + } + } + + // 设置view pager + viewPager.setAdapter(new PreviewAdapter()); + viewPager.setOnPageChangeListener(this); + if (adapter.getSelectMap().size() == 1) { + viewPager.setScanScroll(false); + } else { + viewPager.setScanScroll(true); + } + viewPager.setCurrentItem(0); + } + + @Override + public void onPageScrollStateChanged(int arg0) { + } + + @Override + public void onPageScrolled(int arg0, float arg1, int arg2) { + + } + + private void setImageBackground(int selectItems) { + for (int i = 0; i < tips.length; i++) { + if (i == selectItems) { + tips[i].setBackgroundResource(R.drawable.tt_default_dot_down); + } else { + tips[i].setBackgroundResource(R.drawable.tt_default_dot_up); + } + } + } + + @Override + public void onPageSelected(int position) { + @SuppressWarnings("rawtypes") + Iterator it = adapter.getSelectMap().keySet().iterator(); + int index = -1; + while (it.hasNext()) { + int key = (Integer) it.next(); + if (++index == position) { + curImagePosition = key;// 对应适配器中图片列表的真实位置 + if (adapter.getSelectMap().get(key).isSelected()) { + select.setImageResource(R.drawable.tt_album_img_selected); + } else { + select.setImageResource(R.drawable.tt_album_img_select_nor); + } + } + } + setImageBackground(position); + } + + public class PreviewAdapter extends PagerAdapter { + + @Override + public int getCount() { + return mImageViews.length; + } + + @Override + public boolean isViewFromObject(View view, Object obj) { + return view == obj; + } + + @Override + public void destroyItem(ViewGroup container, int position, Object object) { + container.removeView((View) object); + } + + @Override + public Object instantiateItem(View container, int position) { + try { + ((ViewGroup) container).addView(mImageViews[position]); + } catch (Exception e) { + } + return mImageViews[position]; + } + } + +} diff --git a/android/app/src/main/java/com/mogujie/tt/ui/activity/PreviewGifActivity.java b/android/app/src/main/java/com/mogujie/tt/ui/activity/PreviewGifActivity.java new file mode 100644 index 000000000..45e93d814 --- /dev/null +++ b/android/app/src/main/java/com/mogujie/tt/ui/activity/PreviewGifActivity.java @@ -0,0 +1,74 @@ + +package com.mogujie.tt.ui.activity; + +import android.app.Activity; +import android.os.Bundle; +import android.view.View; +import android.widget.ImageView; + +import com.mogujie.tt.R; +import com.mogujie.tt.config.IntentConstant; +import com.mogujie.tt.ui.helper.Emoparser; +import com.mogujie.tt.ui.helper.GifAnimationDrawable; +import com.mogujie.tt.ui.widget.GifLoadTask; +import com.mogujie.tt.ui.widget.GifView; + +import java.io.IOException; +import java.io.InputStream; +import java.nio.ByteBuffer; + +/** + * @author : fengzi on 15-1-25. + * @email : fengzi@mogujie.com. + * + * preview a GIF image when click on the gif message + */ +public class PreviewGifActivity extends Activity implements View.OnClickListener { + GifView gifView = null; + ImageView backView = null; + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.tt_activity_preview_gif); + gifView = (GifView) findViewById(R.id.gif); + backView = (ImageView)findViewById(R.id.back_btn); + backView.setOnClickListener(this); + String content = getIntent().getStringExtra(IntentConstant.PREVIEW_TEXT_CONTENT); + if(Emoparser.getInstance(this).isMessageGif(content)) + { + InputStream is = getResources().openRawResource(Emoparser.getInstance(this).getResIdByCharSequence(content)); + int lenght = 0; + try { + lenght = is.available(); + byte[] buffer = ByteBuffer.allocate(lenght).array(); + is.read(buffer); + gifView.setBytes(buffer); + gifView.startAnimation(); + } catch (IOException e) { + e.printStackTrace(); + } + } + else + { + new GifLoadTask() { + @Override + protected void onPostExecute(byte[] bytes) { + gifView.setBytes(bytes); + gifView.startAnimation(); + } + @Override + protected void onPreExecute() { + super.onPreExecute(); + } + }.execute(content); + } + + + } + + @Override + public void onClick(View view) { + gifView.stopAnimation(); + PreviewGifActivity.this.finish(); + } +} diff --git a/android/app/src/main/java/com/mogujie/tt/ui/activity/PreviewMessageImagesActivity.java b/android/app/src/main/java/com/mogujie/tt/ui/activity/PreviewMessageImagesActivity.java new file mode 100644 index 000000000..675222dbc --- /dev/null +++ b/android/app/src/main/java/com/mogujie/tt/ui/activity/PreviewMessageImagesActivity.java @@ -0,0 +1,205 @@ +package com.mogujie.tt.ui.activity; +import android.os.Bundle; +import android.support.v4.app.Fragment; +import android.support.v4.app.FragmentActivity; +import android.support.v4.app.FragmentManager; +import android.support.v4.app.FragmentPagerAdapter; +import android.support.v4.view.ViewPager; +import android.view.View; +import android.view.ViewGroup; +import android.widget.ImageView; +import android.widget.LinearLayout; + +import com.mogujie.tt.R; +import com.mogujie.tt.config.IntentConstant; +import com.mogujie.tt.imservice.entity.ImageMessage; +import com.mogujie.tt.imservice.support.IMServiceConnector; +import com.mogujie.tt.imservice.service.IMService; +import com.mogujie.tt.ui.fragment.MessageImageFragment; + +import java.util.ArrayList; + +public class PreviewMessageImagesActivity extends FragmentActivity implements ViewPager.OnPageChangeListener { + private ViewPager viewPager; + private LinearLayout group; + private ImageView back; + private int curImagePosition = -1; + private ImageMessage messageInfo; + ArrayList tips=new ArrayList(); + ArrayList fragments=new ArrayList<>(); + private ArrayList imageList= null; + public IMService imService; + + IMServiceConnector imServiceConnector = new IMServiceConnector() { + @Override + public void onIMServiceConnected() { + imService = imServiceConnector.getIMService(); + if(imService!=null) + { + loadFragments(); +// loadTips(); + } + } + @Override + public void onServiceDisconnected() { + } + }; + + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.activity_preview_message_images); + imageList=ImageMessage.getImageMessageList(); + try { + messageInfo = (ImageMessage) getIntent().getSerializableExtra(IntentConstant.CUR_MESSAGE); + initRes(); + imServiceConnector.connect(this); + }catch (Exception e){ + } + } + + /** + * 初始化资源 + */ + private void initRes() { + try { + viewPager = (ViewPager) findViewById(R.id.viewpager); + viewPager.setOnPageChangeListener(this); + group = (LinearLayout) findViewById(R.id.viewGroup); + back = (ImageView) findViewById(R.id.back_btn); + back.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + PreviewMessageImagesActivity.this.finish(); + } + }); + + //加载页面 + //loadFragments(); + //设置点点 + //loadTips(); + }catch (Exception e){ + } + } + + /** + * 加载页面 + */ + private void loadFragments(){ + if (null == viewPager||null==fragments) { + return; + } + try { + viewPager.removeAllViews(); + fragments.clear(); + if (null != imageList && null != messageInfo) { + for (int i = 0; i < imageList.size(); i++) { + ImageMessage item =imageList.get(imageList.size()-i-1); + if(null==item){ + continue; + } + MessageImageFragment fragment = new MessageImageFragment(); + fragment.setImageInfo(item); + fragment.setImService(imService); + fragments.add(fragment); + if (item.getMsgId()==messageInfo.getMsgId()&&messageInfo.getId().equals(item.getId())) { + curImagePosition = i; + } + } + } + viewPager.setAdapter(new FragmentAdapter(getSupportFragmentManager(), fragments)); + if (curImagePosition >= 0) { + viewPager.setCurrentItem(curImagePosition); + } + }catch (Exception e){ + } + } + + /** + * 加载点点 + */ + private void loadTips(){ + try { + if (null==imageList||imageList.size()==0){ + return; + } + group.removeAllViews(); + tips.clear(); + for (int i = 0; i < imageList.size(); i++) { + ImageMessage item =imageList.get(i); + if(null==item){ + continue; + } + ImageView imageView = new ImageView(this); + if (i == curImagePosition) { + imageView.setBackgroundResource(R.drawable.tt_default_dot_down); + } else { + imageView.setBackgroundResource(R.drawable.tt_default_dot_up); + } + tips.add(imageView); + LinearLayout.LayoutParams layoutParams = new LinearLayout.LayoutParams( + new ViewGroup.LayoutParams(12, 12)); + layoutParams.leftMargin = 5; + layoutParams.rightMargin = 5; + group.addView(imageView, layoutParams); + } + }catch (Exception e){ + } + } + + @Override + public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) { + + } + + @Override + public void onPageSelected(int position) { + try { + if (null==tips){ + loadTips(); + } + if (null!=tips) { + for (int i = 0; i < tips.size(); i++) { + if (i == position) { + tips.get(i).setBackgroundResource(R.drawable.tt_default_dot_down); + } else { + tips.get(i).setBackgroundResource(R.drawable.tt_default_dot_up); + } + } + } + }catch (Exception e){ + } + } + + @Override + public void onPageScrollStateChanged(int state) { + + } + + public class FragmentAdapter extends FragmentPagerAdapter { + ArrayList list; + public FragmentAdapter(FragmentManager fm,ArrayList list) { + super(fm); + this.list = list; + } + + @Override + public int getCount() { + return list.size(); + } + + @Override + public android.support.v4.app.Fragment getItem(int arg0) { + return list.get(arg0); + } + } + + + @Override + protected void onDestroy() { + fragments.clear(); + imServiceConnector.disconnect(this); + super.onDestroy(); + } +} diff --git a/android/app/src/main/java/com/mogujie/tt/ui/activity/PreviewTextActivity.java b/android/app/src/main/java/com/mogujie/tt/ui/activity/PreviewTextActivity.java new file mode 100644 index 000000000..296f474ca --- /dev/null +++ b/android/app/src/main/java/com/mogujie/tt/ui/activity/PreviewTextActivity.java @@ -0,0 +1,33 @@ + +package com.mogujie.tt.ui.activity; + +import android.app.Activity; +import android.os.Bundle; +import android.view.View; +import android.widget.TextView; + +import com.mogujie.tt.R; +import com.mogujie.tt.config.IntentConstant; + +public class PreviewTextActivity extends Activity { + TextView txtContent = null; + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.tt_activity_preview_text); + + txtContent = (TextView) findViewById(R.id.content); + + String displayText = getIntent().getStringExtra(IntentConstant.PREVIEW_TEXT_CONTENT); + txtContent.setText(displayText); + + ((View) txtContent.getParent()).setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + PreviewTextActivity.this.finish(); + } + }); + } + +} diff --git a/android/app/src/main/java/com/mogujie/tt/ui/activity/SearchActivity.java b/android/app/src/main/java/com/mogujie/tt/ui/activity/SearchActivity.java new file mode 100644 index 000000000..84b495443 --- /dev/null +++ b/android/app/src/main/java/com/mogujie/tt/ui/activity/SearchActivity.java @@ -0,0 +1,26 @@ +package com.mogujie.tt.ui.activity; + +import android.os.Bundle; + +import com.mogujie.tt.R; +import com.mogujie.tt.imservice.manager.IMStackManager; +import com.mogujie.tt.ui.base.TTBaseFragmentActivity; + +public class SearchActivity extends TTBaseFragmentActivity { + + @Override + protected void onCreate(Bundle savedInstanceState) { + // TODO Auto-generated method stub + super.onCreate(savedInstanceState); + IMStackManager.getStackManager().pushActivity(this); + setContentView(R.layout.tt_fragment_activity_search); + } + + @Override + protected void onDestroy() { + // TODO Auto-generated method stub + IMStackManager.getStackManager().popActivity(this); + super.onDestroy(); + } + +} diff --git a/android/app/src/main/java/com/mogujie/tt/ui/activity/SettingActivity.java b/android/app/src/main/java/com/mogujie/tt/ui/activity/SettingActivity.java new file mode 100644 index 000000000..ed2a522a5 --- /dev/null +++ b/android/app/src/main/java/com/mogujie/tt/ui/activity/SettingActivity.java @@ -0,0 +1,23 @@ +package com.mogujie.tt.ui.activity; + +import android.os.Bundle; + +import com.mogujie.tt.R; +import com.mogujie.tt.ui.base.TTBaseFragmentActivity; + +public class SettingActivity extends TTBaseFragmentActivity { + + @Override + protected void onCreate(Bundle savedInstanceState) { + // TODO Auto-generated method stub + super.onCreate(savedInstanceState); + setContentView(R.layout.tt_fragment_activity_setting); + } + + @Override + protected void onDestroy() { + // TODO Auto-generated method stub + super.onDestroy(); + } + +} diff --git a/android/app/src/main/java/com/mogujie/tt/ui/activity/UserInfoActivity.java b/android/app/src/main/java/com/mogujie/tt/ui/activity/UserInfoActivity.java new file mode 100644 index 000000000..39336cb1f --- /dev/null +++ b/android/app/src/main/java/com/mogujie/tt/ui/activity/UserInfoActivity.java @@ -0,0 +1,14 @@ +package com.mogujie.tt.ui.activity; + +import android.os.Bundle; + +import com.mogujie.tt.R; +import com.mogujie.tt.ui.base.TTBaseFragmentActivity; + +public class UserInfoActivity extends TTBaseFragmentActivity{ + @Override + public void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.tt_fragment_activity_userinfo); + } +} diff --git a/android/app/src/main/java/com/mogujie/tt/ui/activity/WebViewFragmentActivity.java b/android/app/src/main/java/com/mogujie/tt/ui/activity/WebViewFragmentActivity.java new file mode 100644 index 000000000..92018e33e --- /dev/null +++ b/android/app/src/main/java/com/mogujie/tt/ui/activity/WebViewFragmentActivity.java @@ -0,0 +1,26 @@ +package com.mogujie.tt.ui.activity; + +import android.content.Intent; +import android.os.Bundle; + +import com.mogujie.tt.R; +import com.mogujie.tt.config.IntentConstant; +import com.mogujie.tt.ui.base.TTBaseFragmentActivity; +import com.mogujie.tt.ui.fragment.WebviewFragment; + +public class WebViewFragmentActivity extends TTBaseFragmentActivity { + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + Intent intent=getIntent(); + if (intent.hasExtra(IntentConstant.WEBVIEW_URL)) { + WebviewFragment.setUrl(intent.getStringExtra(IntentConstant.WEBVIEW_URL)); + } + setContentView(R.layout.tt_fragment_activity_webview); + } + + @Override + protected void onDestroy() { + super.onDestroy(); + } +} diff --git a/android/app/src/main/java/com/mogujie/tt/ui/adapter/ChatAdapter.java b/android/app/src/main/java/com/mogujie/tt/ui/adapter/ChatAdapter.java new file mode 100644 index 000000000..ba50bf5dc --- /dev/null +++ b/android/app/src/main/java/com/mogujie/tt/ui/adapter/ChatAdapter.java @@ -0,0 +1,386 @@ +package com.mogujie.tt.ui.adapter; + +import android.annotation.SuppressLint; +import android.content.Context; +import android.graphics.Color; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.BaseAdapter; +import android.widget.ImageView; +import android.widget.RelativeLayout; +import android.widget.TextView; + +import com.mogujie.tools.ScreenTools; +import com.mogujie.tt.config.DBConstant; +import com.mogujie.tt.DB.entity.GroupEntity; +import com.mogujie.tt.R; +import com.mogujie.tt.config.SysConstant; +import com.mogujie.tt.imservice.entity.RecentInfo; +import com.mogujie.tt.utils.DateUtil; +import com.mogujie.tt.utils.Logger; +import com.mogujie.tt.ui.widget.IMBaseImageView; +import com.mogujie.tt.ui.widget.IMGroupAvatar; + +import java.util.ArrayList; +import java.util.List; + +/** + * @Description 联系人列表适配器 + */ +@SuppressLint("ResourceAsColor") +public class ChatAdapter extends BaseAdapter { + private LayoutInflater mInflater = null; + private List recentSessionList = new ArrayList<>(); + private Logger logger = Logger.getLogger(ChatAdapter.class); + + private static final int CONTACT_TYPE_INVALID = 0; + private static final int CONTACT_TYPE_USER=1; + private static final int CONTACT_TYPE_GROUP =2; + + public ChatAdapter(Context context) { + this.mInflater = LayoutInflater.from(context); + } + + @Override + public int getCount() { + return recentSessionList.size(); + } + + @Override + public RecentInfo getItem(int position) { + logger.d("recent#getItem position:%d", position); + if (position >= recentSessionList.size() || position < 0) { + return null; + } + return recentSessionList.get(position); + } + + /**更新单个RecentInfo 屏蔽群组信息*/ + public void updateRecentInfoByShield(GroupEntity entity){ + String sessionKey = entity.getSessionKey(); + for(RecentInfo recentInfo:recentSessionList){ + if(recentInfo.getSessionKey().equals(sessionKey)){ + int status = entity.getStatus(); + boolean isFor = status==DBConstant.GROUP_STATUS_SHIELD; + recentInfo.setForbidden(isFor); + notifyDataSetChanged(); + break; + } + } + } + + /**置顶状态的更新 not use now*/ + public void updateRecentInfoByTop(String sessionKey,boolean isTop){ + for(RecentInfo recentInfo:recentSessionList){ + if(recentInfo.getSessionKey().equals(sessionKey)){ + recentInfo.setTop(isTop); + notifyDataSetChanged(); + break; + } + } + } + + + public int getUnreadPositionOnView(int currentPostion){ + int nextIndex = currentPostion +1; + int sum =getCount(); + if(nextIndex > sum){ + currentPostion = 0; + } + /**从当前点到末尾*/ + for(int index=nextIndex;index < sum;index++){ + int unCnt = recentSessionList.get(index).getUnReadCnt(); + if(unCnt > 0){ + return index; + } + } + /**从末尾到当前点*/ + for(int index =0;index < currentPostion;index++){ + int unCnt = recentSessionList.get(index).getUnReadCnt(); + if(unCnt > 0){ + return index; + } + } + //最后返回到最上面 + return 0; + } + + + + @Override + public long getItemId(int position) { + return position; + } + + /** + * 用户HOLDER + */ + private final class ContactViewHolder extends ContactHolderBase { + public IMBaseImageView avatar; + } + + /** + * 基本HOLDER + */ + public static class ContactHolderBase{ + public TextView uname; + public TextView lastContent; + public TextView lastTime; + public TextView msgCount; + public ImageView noDisturb; + } + + /** + * 群组HOLDER + */ + private final static class GroupViewHolder extends ContactHolderBase{ + public IMGroupAvatar avatarLayout; + } + + private View renderUser(int position,View convertView, ViewGroup parent){ + RecentInfo recentInfo = recentSessionList.get(position); + ContactViewHolder holder; + if (null == convertView) { + convertView = mInflater.inflate(R.layout.tt_item_chat,parent,false); + holder = new ContactViewHolder(); + holder.avatar = (IMBaseImageView) convertView.findViewById(R.id.contact_portrait); + holder.uname = (TextView) convertView.findViewById(R.id.shop_name); + holder.lastContent = (TextView) convertView.findViewById(R.id.message_body); + holder.lastTime = (TextView) convertView.findViewById(R.id.message_time); + holder.msgCount = (TextView) convertView.findViewById(R.id.message_count_notify); + holder.noDisturb = (ImageView)convertView.findViewById(R.id.message_time_no_disturb_view); + holder.avatar.setImageResource(R.drawable.tt_default_user_portrait_corner); + convertView.setTag(holder); + }else{ + holder = (ContactViewHolder)convertView.getTag(); + } + + if(recentInfo.isTop()){ + // todo R.color.top_session_background + convertView.setBackgroundColor(Color.parseColor("#f4f4f4f4")); + }else{ + convertView.setBackgroundColor(Color.WHITE); + } + + handleCommonContact(holder,recentInfo); + return convertView; + } + + private View renderGroup(int position,View convertView, ViewGroup parent){ + RecentInfo recentInfo = recentSessionList.get(position); + GroupViewHolder holder; + if (null == convertView) { + convertView = mInflater.inflate(R.layout.tt_item_chat_group, parent,false); + holder = new GroupViewHolder(); + holder.avatarLayout = (IMGroupAvatar) convertView.findViewById(R.id.contact_portrait); + holder.uname = (TextView) convertView.findViewById(R.id.shop_name); + holder.lastContent = (TextView) convertView.findViewById(R.id.message_body); + holder.lastTime = (TextView) convertView.findViewById(R.id.message_time); + holder.msgCount = (TextView) convertView.findViewById(R.id.message_count_notify); + holder.noDisturb = (ImageView)convertView.findViewById(R.id.message_time_no_disturb_view); + convertView.setTag(holder); + }else{ + holder = (GroupViewHolder)convertView.getTag(); + } + + if(recentInfo.isTop()){ + // todo R.color.top_session_background + convertView.setBackgroundColor(Color.parseColor("#f4f4f4f4")); + }else{ + convertView.setBackgroundColor(Color.WHITE); + } + + /**群屏蔽的设定*/ + if(recentInfo.isForbidden()) + { + holder.noDisturb.setVisibility(View.VISIBLE); + } + else + { + holder.noDisturb.setVisibility(View.GONE); + } + + handleGroupContact( holder,recentInfo); + return convertView; + } + + + //yingmu base-adapter-helper 了解一下 + @Override + public View getView(int position, View convertView, ViewGroup parent) { + // logger.d("recent#getview position:%d", position); + try { + final int type = getItemViewType(position); + ContactHolderBase holder = null; + + switch (type){ + case CONTACT_TYPE_USER: + convertView = renderUser(position,convertView,parent); + break; + case CONTACT_TYPE_GROUP: + convertView =renderGroup(position,convertView,parent); + break; + } + return convertView; + } catch (Exception e) { + logger.e(e.toString()); + return null; + } + } + + @Override + public int getViewTypeCount() { + return 3; + } + + @Override + public int getItemViewType(int position) { + try { + if (position >= recentSessionList.size()) { + return CONTACT_TYPE_INVALID; + } + RecentInfo recentInfo = recentSessionList.get(position); + if (recentInfo.getSessionType()==DBConstant.SESSION_TYPE_SINGLE){ + return CONTACT_TYPE_USER; + }else if(recentInfo.getSessionType()==DBConstant.SESSION_TYPE_GROUP){ + return CONTACT_TYPE_GROUP; + }else{ + return CONTACT_TYPE_INVALID; + } + }catch (Exception e){ + logger.e(e.toString()); + return CONTACT_TYPE_INVALID; + } + } + + public void setData(List recentSessionList) { + logger.d("recent#set New recent session list"); + logger.d("recent#notifyDataSetChanged"); + this.recentSessionList = recentSessionList; + notifyDataSetChanged(); + } + + private void handleCommonContact(ContactViewHolder contactViewHolder,RecentInfo recentInfo) + { + String avatarUrl = null; + String userName = ""; + String lastContent = ""; + String lastTime = ""; + int unReadCount = 0; + int sessionType = DBConstant.SESSION_TYPE_SINGLE; + + userName = recentInfo.getName(); + lastContent = recentInfo.getLatestMsgData(); + // todo 是不是每次都需要计算 + lastTime = DateUtil.getSessionTime(recentInfo.getUpdateTime()); + unReadCount = recentInfo.getUnReadCnt(); + if(null!=recentInfo.getAvatar()&&recentInfo.getAvatar().size()>0) + { + avatarUrl = recentInfo.getAvatar().get(0); + + } + // 设置未读消息计数 + if (unReadCount > 0) { + String strCountString=String.valueOf(unReadCount); + if (unReadCount>99) { + strCountString = "99+"; + } + contactViewHolder.msgCount.setVisibility(View.VISIBLE); + contactViewHolder.msgCount.setText(strCountString); + } else { + contactViewHolder.msgCount.setVisibility(View.GONE); + } + //头像设置 + contactViewHolder.avatar.setDefaultImageRes(R.drawable.tt_default_user_portrait_corner); + contactViewHolder.avatar.setCorner(8); + contactViewHolder.avatar.setAvatarAppend(SysConstant.AVATAR_APPEND_100); + contactViewHolder.avatar.setImageUrl(avatarUrl); + // 设置其它信息 + contactViewHolder.uname.setText(userName); + contactViewHolder.lastContent.setText(lastContent); + contactViewHolder.lastTime.setText(lastTime); + + } + + private void handleGroupContact(GroupViewHolder groupViewHolder,RecentInfo recentInfo) + { + String avatarUrl = null; + String userName = ""; + String lastContent = ""; + String lastTime = ""; + int unReadCount = 0; + int sessionType = DBConstant.SESSION_TYPE_SINGLE; + + userName = recentInfo.getName(); + lastContent = recentInfo.getLatestMsgData(); + // todo 是不是每次都需要计算 + lastTime = DateUtil.getSessionTime(recentInfo.getUpdateTime()); + unReadCount = recentInfo.getUnReadCnt(); +// sessionType = recentInfo.getSessionType(); + // 设置未读消息计数 只有群组有的 + + if (unReadCount > 0) { + if(recentInfo.isForbidden()) + { + groupViewHolder.msgCount.setBackgroundResource(R.drawable.tt_message_botify_no_disturb); + groupViewHolder.msgCount.setVisibility(View.VISIBLE); + groupViewHolder.msgCount.setText(""); + ((RelativeLayout.LayoutParams)groupViewHolder.msgCount.getLayoutParams()).leftMargin=ScreenTools.instance(this.mInflater.getContext()).dip2px(-7); + ((RelativeLayout.LayoutParams)groupViewHolder.msgCount.getLayoutParams()).topMargin=ScreenTools.instance(this.mInflater.getContext()).dip2px(6); + groupViewHolder.msgCount.getLayoutParams().width = ScreenTools.instance(this.mInflater.getContext()).dip2px(10); + groupViewHolder.msgCount.getLayoutParams().height = ScreenTools.instance(this.mInflater.getContext()).dip2px(10); + + } + else + { + groupViewHolder.msgCount.setBackgroundResource(R.drawable.tt_message_notify); + groupViewHolder.msgCount.setVisibility(View.VISIBLE); + ((RelativeLayout.LayoutParams)groupViewHolder.msgCount.getLayoutParams()).leftMargin=ScreenTools.instance(this.mInflater.getContext()).dip2px(-10); + ((RelativeLayout.LayoutParams)groupViewHolder.msgCount.getLayoutParams()).topMargin=ScreenTools.instance(this.mInflater.getContext()).dip2px(3); + groupViewHolder.msgCount.getLayoutParams().width = RelativeLayout.LayoutParams.WRAP_CONTENT; + groupViewHolder.msgCount.getLayoutParams().height = RelativeLayout.LayoutParams.WRAP_CONTENT; + groupViewHolder.msgCount.setPadding(ScreenTools.instance(this.mInflater.getContext()).dip2px(3),0,ScreenTools.instance(this.mInflater.getContext()).dip2px(3),0); + + String strCountString=String.valueOf(unReadCount); + if (unReadCount>99) { + strCountString = "99+"; + } + groupViewHolder.msgCount.setVisibility(View.VISIBLE); + groupViewHolder.msgCount.setText(strCountString); + } + + } else { + groupViewHolder.msgCount.setVisibility(View.GONE); + } + + //头像设置 + setGroupAvatar(groupViewHolder, recentInfo.getAvatar()); + // 设置其它信息 + groupViewHolder.uname.setText(userName); + groupViewHolder.lastContent.setText(lastContent); + groupViewHolder.lastTime.setText(lastTime); + } + + /** + * 设置群头像 + * @param holder + * @param avatarUrlList + */ + private void setGroupAvatar(GroupViewHolder holder,List avatarUrlList){ + try { + if (null == avatarUrlList) { + return; + } + holder.avatarLayout.setAvatarUrlAppend(SysConstant.AVATAR_APPEND_32); + holder.avatarLayout.setChildCorner(3); + if (null != avatarUrlList) { + holder.avatarLayout.setAvatarUrls(new ArrayList(avatarUrlList)); + } + }catch (Exception e){ + logger.e(e.toString()); + } + + } + +} diff --git a/android/app/src/main/java/com/mogujie/tt/ui/adapter/ContactAdapter.java b/android/app/src/main/java/com/mogujie/tt/ui/adapter/ContactAdapter.java new file mode 100644 index 000000000..ebabaa983 --- /dev/null +++ b/android/app/src/main/java/com/mogujie/tt/ui/adapter/ContactAdapter.java @@ -0,0 +1,391 @@ +package com.mogujie.tt.ui.adapter; + +import android.content.Context; +import android.text.TextUtils; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.AdapterView; +import android.widget.BaseAdapter; +import android.widget.SectionIndexer; +import android.widget.TextView; + +import com.mogujie.tt.DB.entity.GroupEntity; +import com.mogujie.tt.DB.entity.UserEntity; +import com.mogujie.tt.R; +import com.mogujie.tt.config.DBConstant; +import com.mogujie.tt.config.SysConstant; +import com.mogujie.tt.imservice.service.IMService; +import com.mogujie.tt.ui.widget.IMBaseImageView; +import com.mogujie.tt.ui.widget.IMGroupAvatar; +import com.mogujie.tt.utils.IMUIHelper; +import com.mogujie.tt.utils.Logger; +import com.mogujie.tt.utils.ScreenUtil; + +import java.util.ArrayList; +import java.util.List; +import java.util.Set; + +/** + * @author : yingmu on 15-3-18. + * @email : yingmu@mogujie.com. + * + * 通讯录默认页 “全部”展示 + * 包含字母序 + * + * todo 这几个adapter都有公用的部分,今后如果需求变更有需要,抽离父类adapter + * [DeptAdapter] [GroupSelectAdapter] [SearchAdapter] + */ +public class ContactAdapter extends BaseAdapter implements + SectionIndexer, + AdapterView.OnItemClickListener, + AdapterView.OnItemLongClickListener{ + + private Logger logger = Logger.getLogger(ContactAdapter.class); + public List groupList = new ArrayList<>(); + public List userList = new ArrayList<>(); + + private Context ctx; + private IMService imService; + + public ContactAdapter(Context context,IMService imService){ + this.ctx = context; + this.imService = imService; + } + + public void putUserList(List pUserList){ + this.userList.clear(); + if(pUserList == null || pUserList.size() <=0){ + return; + } + this.userList = pUserList; + notifyDataSetChanged(); + } + public void putGroupList(List pGroupList){ + this.groupList.clear(); + if(pGroupList == null || pGroupList.size() <=0) { + return; + } + this.groupList = pGroupList; + notifyDataSetChanged(); + } + + /** + * Returns an array of objects representing sections of the list. The + * returned array and its contents should be non-null. + *

+ * The list view will call toString() on the objects to get the preview text + * to display while scrolling. For example, an adapter may return an array + * of Strings representing letters of the alphabet. Or, it may return an + * array of objects whose toString() methods return their section titles. + * + * @return the array of section objects + */ + @Override + public Object[] getSections() { + return new Object[0]; + } + + /** + * Given the index of a section within the array of section objects, returns + * the starting position of that section within the adapter. + *

+ * If the section's starting position is outside of the adapter bounds, the + * position must be clipped to fall within the size of the adapter. + * + * @param section the index of the section within the array of section + * objects + * @return the starting position of that section within the adapter, + * constrained to fall within the adapter bounds + */ + @Override + public int getPositionForSection(int section) { + logger.d("pinyin#getPositionForSection secton:%d", section); + + // 用户列表的起始位置是群组结束的位置,要特别注意 + int index = groupList==null?0:groupList.size(); + for(UserEntity entity:userList){ + int firstCharacter = entity.getPinyinElement().pinyin.charAt(0); + // logger.d("firstCharacter:%d", firstCharacter); + if (firstCharacter == section) { + logger.d("pinyin#find sectionName"); + return index; + } + index++; + } + logger.e("pinyin#can't find such section:%d", section); + return -1; + } + + /** + * Given a position within the adapter, returns the index of the + * corresponding section within the array of section objects. + *

+ * If the section index is outside of the section array bounds, the index + * must be clipped to fall within the size of the section array. + *

+ * For example, consider an indexer where the section at array index 0 + * starts at adapter position 100. Calling this method with position 10, + * which is before the first section, must return index 0. + * + * @param position the position within the adapter for which to return the + * corresponding section index + * @return the index of the corresponding section within the array of + * section objects, constrained to fall within the array bounds + */ + @Override + public int getSectionForPosition(int position) { + return 0; + } + + + @Override + public void onItemClick(AdapterView parent, View view, int position, long id) { + Object object = getItem(position); + if(object instanceof UserEntity){ + UserEntity userEntity = (UserEntity) object; + IMUIHelper.openUserProfileActivity(ctx, userEntity.getPeerId()); + }else if(object instanceof GroupEntity){ + GroupEntity groupEntity = (GroupEntity) object; + IMUIHelper.openChatActivity(ctx,groupEntity.getSessionKey()); + }else{ + } + } + + @Override + public boolean onItemLongClick(AdapterView parent, View view, int position, long id) { + Object object = getItem(position); + if(object instanceof UserEntity){ + UserEntity contact = (UserEntity) object; + IMUIHelper.handleContactItemLongClick(contact, ctx); + }else{ + } + return true; + } + + @Override + public int getItemViewType(int position) { + int groupSize = groupList==null?0:groupList.size(); + if(groupSize > position){ + return ContactType.GROUP.ordinal(); + } + return ContactType.USER.ordinal(); + } + + @Override + public int getViewTypeCount() { + return ContactType.values().length; + } + + @Override + public int getCount() { + int groupSize = groupList==null?0:groupList.size(); + int userSize = userList==null?0:userList.size(); + int sum = groupSize + userSize; + return sum; + } + + + @Override + public Object getItem(int position) { + int typeIndex = getItemViewType(position); + ContactType renderType = ContactType.values()[typeIndex]; + switch (renderType){ + case USER:{ + int groupSize = groupList==null?0:groupList.size(); + int realIndex = position - groupSize; + if(realIndex <0){ + throw new IllegalArgumentException("ContactAdapter#getItem#user类型判断错误!"); + } + return userList.get(realIndex); + } + case GROUP:{ + int groupSize = groupList==null?0:groupList.size(); + if(position > groupSize){ + throw new IllegalArgumentException("ContactAdapter#getItem#group类型判断错误"); + } + return groupList.get(position); + } + default: + throw new IllegalArgumentException("ContactAdapter#getItem#不存在的类型" + renderType.name()); + } + } + + + @Override + public long getItemId(int position) { + return position; + } + + + @Override + public View getView(int position, View convertView, ViewGroup parent) { + int typeIndex = getItemViewType(position); + ContactType renderType = ContactType.values()[typeIndex]; + View view = null; + switch (renderType){ + case USER:{ + view = renderUser(position,convertView,parent); + } + break; + case GROUP:{ + view = renderGroup(position,convertView,parent); + } + break; + } + return view; + } + + + public View renderUser(int position, View view, ViewGroup parent){ + UserHolder userHolder = null; + UserEntity userEntity= (UserEntity)getItem(position); + if(userEntity == null){ + logger.e("ContactAdapter#renderUser#userEntity is null!position:%d",position); + // todo 这个会报错误的,怎么处理 + return null; + } + if (view == null) { + userHolder = new UserHolder(); + view = LayoutInflater.from(ctx).inflate(R.layout.tt_item_contact, parent,false); + userHolder.nameView = (TextView) view.findViewById(R.id.contact_item_title); + userHolder.realNameView = (TextView) view.findViewById(R.id.contact_realname_title); + userHolder.sectionView = (TextView) view.findViewById(R.id.contact_category_title); + userHolder.avatar = (IMBaseImageView)view.findViewById(R.id.contact_portrait); + userHolder.divider = view.findViewById(R.id.contact_divider); + view.setTag(userHolder); + } else { + userHolder = (UserHolder) view.getTag(); + } + + /***reset-- 控件的默认值*/ + userHolder.nameView.setText(userEntity.getMainName()); + userHolder.avatar.setImageResource(R.drawable.tt_default_user_portrait_corner); + userHolder.divider.setVisibility(View.VISIBLE); + userHolder.sectionView.setVisibility(View.GONE); + + // 字母序第一个要展示 + // todo pinyin控件不能处理多音字的情况,或者UserEntity类型的统统用pinyin字段进行判断 + String sectionName = userEntity.getSectionName(); + // 正式群在用户列表的上方展示 + int groupSize = groupList == null?0:groupList.size(); + if (position == groupSize) { + userHolder.sectionView.setVisibility(View.VISIBLE); + userHolder.sectionView.setText(sectionName); + + //分栏已经显示,最上面的分割线不用显示 + userHolder.divider.setVisibility(View.GONE); + }else{ + // 获取上一个实体的preSectionName,这个时候position > groupSize + UserEntity preUser = (UserEntity)getItem(position-1); + String preSectionName = preUser.getSectionName(); + if(TextUtils.isEmpty(preSectionName) || !preSectionName.equals(sectionName)){ + userHolder.sectionView.setVisibility(View.VISIBLE); + userHolder.sectionView.setText(sectionName); + // 不显示分割线 + userHolder.divider.setVisibility(View.GONE); + }else{ + userHolder.sectionView.setVisibility(View.GONE); + } + } + + userHolder.avatar.setDefaultImageRes(R.drawable.tt_default_user_portrait_corner); + userHolder.avatar.setCorner(0); + userHolder.avatar.setAvatarAppend(SysConstant.AVATAR_APPEND_100); + userHolder.avatar.setImageUrl(userEntity.getAvatar()); + + userHolder.realNameView.setText(userEntity.getRealName()); + userHolder.realNameView.setVisibility(View.GONE); + return view; + } + + + public View renderGroup(int position, View view, ViewGroup parent){ + GroupHolder groupHolder = null; + GroupEntity groupEntity = (GroupEntity) getItem(position); + if(groupEntity == null){ + logger.e("ContactAdapter#renderGroup#groupEntity is null!position:%d",position); + return null; + } + if (view == null) { + groupHolder = new GroupHolder(); + view = LayoutInflater.from(ctx).inflate(R.layout.tt_item_contact_group, parent,false); + groupHolder.nameView = (TextView) view.findViewById(R.id.contact_item_title); + groupHolder.sectionView = (TextView) view.findViewById(R.id.contact_category_title); + groupHolder.avatar = (IMGroupAvatar)view.findViewById(R.id.contact_portrait); + groupHolder.divider = view.findViewById(R.id.contact_divider); + view.setTag(groupHolder); + } else { + groupHolder = (GroupHolder) view.getTag(); + } + + groupHolder.nameView.setText(groupEntity.getMainName()); + groupHolder.sectionView.setVisibility(View.GONE); + + // 分割线的处理【位于控件的最上面】 + groupHolder.divider.setVisibility(View.VISIBLE); + if(position == 0){ + groupHolder.divider.setVisibility(View.GONE); + } + + groupHolder.avatar.setVisibility(View.VISIBLE); + List avatarUrlList = new ArrayList<>(); + Set userIds = groupEntity.getlistGroupMemberIds(); + int i = 0; + for(Integer buddyId:userIds){ + UserEntity entity = imService.getContactManager().findContact(buddyId); + if (entity == null) { + //logger.d("已经离职。userId:%d", buddyId); + continue; + } + avatarUrlList.add(entity.getAvatar()); + if (i >= 3) { + break; + } + i++; + } + setGroupAvatar(groupHolder.avatar,avatarUrlList); + return view; + } + + + /** + * 与search 有公用的地方,可以抽取IMUIHelper + * 设置群头像 + * @param avatar + * @param avatarUrlList + */ + private void setGroupAvatar(IMGroupAvatar avatar,List avatarUrlList){ + try { + avatar.setViewSize(ScreenUtil.instance(ctx).dip2px(38)); + avatar.setChildCorner(2); + avatar.setAvatarUrlAppend(SysConstant.AVATAR_APPEND_32); + avatar.setParentPadding(3); + avatar.setAvatarUrls((ArrayList) avatarUrlList); + }catch (Exception e){ + logger.e(e.toString()); + } + } + + + // 将分割线放在上面,利于判断 + public static class UserHolder { + View divider; + TextView sectionView; + TextView nameView; + TextView realNameView; + IMBaseImageView avatar; + } + + public static class GroupHolder { + View divider; + TextView sectionView; + TextView nameView; + IMGroupAvatar avatar; + } + + private enum ContactType{ + USER, + GROUP + } +} diff --git a/android/app/src/main/java/com/mogujie/tt/ui/adapter/DeptAdapter.java b/android/app/src/main/java/com/mogujie/tt/ui/adapter/DeptAdapter.java new file mode 100644 index 000000000..b330e666f --- /dev/null +++ b/android/app/src/main/java/com/mogujie/tt/ui/adapter/DeptAdapter.java @@ -0,0 +1,245 @@ +package com.mogujie.tt.ui.adapter; + +import android.content.Context; +import android.text.TextUtils; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.AdapterView; +import android.widget.BaseAdapter; +import android.widget.SectionIndexer; +import android.widget.TextView; + +import com.mogujie.tt.DB.entity.DepartmentEntity; +import com.mogujie.tt.DB.entity.UserEntity; +import com.mogujie.tt.R; +import com.mogujie.tt.config.SysConstant; +import com.mogujie.tt.imservice.manager.IMContactManager; +import com.mogujie.tt.imservice.service.IMService; +import com.mogujie.tt.ui.widget.IMBaseImageView; +import com.mogujie.tt.utils.IMUIHelper; +import com.mogujie.tt.utils.Logger; + +import java.util.ArrayList; +import java.util.List; +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; + +/** + * @author : yingmu on 15-3-18. + * @email : yingmu@mogujie.com. + */ +public class DeptAdapter extends BaseAdapter implements SectionIndexer, + AdapterView.OnItemClickListener, + AdapterView.OnItemLongClickListener{ + + private Logger logger = Logger.getLogger(DeptAdapter.class); + private List userList = new ArrayList<>(); + + private Context ctx; + private IMService imService; + + public DeptAdapter(Context context,IMService imService){ + this.ctx = context; + this.imService = imService; + } + + public void putUserList(List pUserList){ + this.userList.clear(); + if(pUserList == null || pUserList.size() <=0){ + return; + } + this.userList = pUserList; + notifyDataSetChanged(); + } + + /** + * Returns an array of objects representing sections of the list. The + * returned array and its contents should be non-null. + *

+ * The list view will call toString() on the objects to get the preview text + * to display while scrolling. For example, an adapter may return an array + * of Strings representing letters of the alphabet. Or, it may return an + * array of objects whose toString() methods return their section titles. + * + * @return the array of section objects + */ + @Override + public Object[] getSections() { + return new Object[0]; + } + + /** + * Given the index of a section within the array of section objects, returns + * the starting position of that section within the adapter. + *

+ * If the section's starting position is outside of the adapter bounds, the + * position must be clipped to fall within the size of the adapter. + * + * @param sectionIndex the index of the section within the array of section + * objects + * @return the starting position of that section within the adapter, + * constrained to fall within the adapter bounds + */ + @Override + public int getPositionForSection(int sectionIndex) { + logger.d("pinyin#getPositionForSection secton:%d", sectionIndex); + int index = 0; + IMContactManager imContactManager = imService.getContactManager(); + for(UserEntity entity:userList){ + DepartmentEntity department = imContactManager.findDepartment(entity.getDepartmentId()); + if (department == null) { + return 0; + } + String deptPinyin = department.getPinyinElement().pinyin; + int firstCharacter = TextUtils.isEmpty(deptPinyin)?-1:deptPinyin.charAt(0); + // logger.d("firstCharacter:%d", firstCharacter); + if (firstCharacter == sectionIndex) { + logger.d("pinyin#find sectionName"); + return index; + } + index++; + } + logger.e("pinyin#can't find such section:%d", sectionIndex); + return -1; + } + + /** + * Given a position within the adapter, returns the index of the + * corresponding section within the array of section objects. + *

+ * If the section index is outside of the section array bounds, the index + * must be clipped to fall within the size of the section array. + *

+ * For example, consider an indexer where the section at array index 0 + * starts at adapter position 100. Calling this method with position 10, + * which is before the first section, must return index 0. + * + * @param position the position within the adapter for which to return the + * corresponding section index + * @return the index of the corresponding section within the array of + * section objects, constrained to fall within the array bounds + */ + @Override + public int getSectionForPosition(int position) { + return 0; + } + + + @Override + public void onItemClick(AdapterView parent, View view, int position, long id) { + UserEntity userEntity = (UserEntity) getItem(position); + IMUIHelper.openUserProfileActivity(ctx, userEntity.getPeerId()); + } + + @Override + public boolean onItemLongClick(AdapterView parent, View view, int position, long id) { + UserEntity userEntity = (UserEntity) getItem(position); + IMUIHelper.handleContactItemLongClick(userEntity, ctx); + return true; + } + + @Override + public int getCount() { + if(userList != null){ + return userList.size(); + } + return 0; + } + + + @Override + public Object getItem(int position) { + if(userList != null && position < userList.size()){ + return userList.get(position); + } + return null; + } + + + @Override + public long getItemId(int position) { + return position; + } + + + @Override + public View getView(int position, View view, ViewGroup parent) { + UserEntity userEntity = (UserEntity) getItem(position); + if(userEntity == null){ + logger.e("DeptAdapter#renderUser#userEntity is null!position:%d",position); + return null; + } + UserHolder userHolder = null; + if (view == null) { + userHolder = new UserHolder(); + view = LayoutInflater.from(ctx).inflate(R.layout.tt_item_contact, parent,false); + userHolder.nameView = (TextView) view.findViewById(R.id.contact_item_title); + userHolder.realNameView = (TextView) view.findViewById(R.id.contact_realname_title); + userHolder.sectionView = (TextView) view.findViewById(R.id.contact_category_title); + userHolder.avatar = (IMBaseImageView)view.findViewById(R.id.contact_portrait); + userHolder.divider = view.findViewById(R.id.contact_divider); + view.setTag(userHolder); + } else { + userHolder = (UserHolder) view.getTag(); + } + + /**reset--- 控件默认值-*/ + userHolder.nameView.setText(userEntity.getMainName()); + userHolder.avatar.setImageResource(R.drawable.tt_default_user_portrait_corner); + userHolder.divider.setVisibility(View.VISIBLE); + userHolder.sectionView.setVisibility(View.GONE); + + // 字母序第一个要展示 + DepartmentEntity deptEntity = imService.getContactManager().findDepartment(userEntity.getDepartmentId()); + String sectionName = deptEntity==null?"":deptEntity.getDepartName(); + + String preSectionName = null; + if(position > 0){ + int preDeptId = ((UserEntity)getItem(position-1)).getDepartmentId(); + DepartmentEntity preDept = imService.getContactManager().findDepartment(preDeptId); + preSectionName = preDept==null?"":preDept.getDepartName(); + } + + if(TextUtils.isEmpty(preSectionName) || !preSectionName.equals(sectionName)){ + userHolder.sectionView.setVisibility(View.VISIBLE); + userHolder.sectionView.setText(sectionName); + // 最上面的分割线不展示 + userHolder.divider.setVisibility(View.GONE); + }else{ + userHolder.sectionView.setVisibility(View.GONE); + } + + userHolder.avatar.setDefaultImageRes(R.drawable.tt_default_user_portrait_corner); + userHolder.avatar.setCorner(0); + userHolder.avatar.setAvatarAppend(SysConstant.AVATAR_APPEND_100); + userHolder.avatar.setImageUrl(userEntity.getAvatar()); + + userHolder.realNameView.setText(userEntity.getRealName()); + userHolder.realNameView.setVisibility(View.GONE); + return view; + } + + public static class UserHolder { + View divider; + TextView sectionView; + TextView nameView; + TextView realNameView; + IMBaseImageView avatar; + } + + /**-------搜索栏----部门定位------------*/ + public int locateDepartment(String departmentTitle) { + logger.d("department#locateDepartment departmentTitle:%s", departmentTitle); + int index = 0; + for (UserEntity entity:userList) { + DepartmentEntity deptEntity = imService.getContactManager().findDepartment(entity.getDepartmentId()); + String sectionName = deptEntity==null?"":deptEntity.getDepartName(); + if (sectionName != null && !sectionName.isEmpty() && (0 == sectionName.compareToIgnoreCase(departmentTitle)) ) { + return index; + } + index++; + } + return -1; + } +} diff --git a/android/app/src/main/java/com/mogujie/tt/ui/adapter/EmoGridViewAdapter.java b/android/app/src/main/java/com/mogujie/tt/ui/adapter/EmoGridViewAdapter.java new file mode 100644 index 000000000..704694284 --- /dev/null +++ b/android/app/src/main/java/com/mogujie/tt/ui/adapter/EmoGridViewAdapter.java @@ -0,0 +1,113 @@ + +package com.mogujie.tt.ui.adapter; + +import android.content.Context; +import android.graphics.Bitmap; +import android.graphics.BitmapFactory; +import android.view.Gravity; +import android.view.View; +import android.view.ViewGroup; +import android.widget.AbsListView.LayoutParams; +import android.widget.BaseAdapter; +import android.widget.ImageView; +import android.widget.LinearLayout; + +import com.mogujie.tt.utils.CommonUtil; +import com.mogujie.tt.utils.Logger; + +/** + * @Description 表情适配器 + * @author Nana + * @date 2014-4-16 + */ +public class EmoGridViewAdapter extends BaseAdapter { + private Context context = null; + private int[] emoResIds = null; + private static Logger logger = Logger.getLogger(EmoGridViewAdapter.class); + + public EmoGridViewAdapter(Context cxt, int[] ids) { + this.context = cxt; + this.emoResIds = ids; + } + + @Override + public int getCount() { + return emoResIds.length; + } + + @Override + public Object getItem(int position) { + return emoResIds[position]; + } + + @Override + public long getItemId(int position) { + return emoResIds[position]; + } + + @Override + public View getView(int position, View convertView, ViewGroup parent) { + try { + GridViewHolder gridViewHolder = null; + if (null == convertView && null != context) { + gridViewHolder = new GridViewHolder(); + convertView = gridViewHolder.layoutView; + if (convertView != null) { + convertView.setTag(gridViewHolder); + } + } else { + gridViewHolder = (GridViewHolder) convertView.getTag(); + } + if (null == gridViewHolder || null == convertView) { + return null; + } + gridViewHolder.faceIv.setImageBitmap(getBitmap(position)); + + if (position == emoResIds.length - 1) { + LinearLayout.LayoutParams params = new LinearLayout.LayoutParams( + LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT); + params.topMargin = CommonUtil.getElementSzie(context) / 3; + gridViewHolder.faceIv.setLayoutParams(params); + } + return convertView; + } catch (Exception e) { + logger.e(e.getMessage()); + return null; + } + } + + private Bitmap getBitmap(int position) { + Bitmap bitmap = null; + try { + bitmap = BitmapFactory.decodeResource(context.getResources(), + emoResIds[position]); + } catch (Exception e) { + logger.e(e.getMessage()); + } + return bitmap; + } + + public class GridViewHolder { + public LinearLayout layoutView; + public ImageView faceIv; + + public GridViewHolder() { + try { + LayoutParams layoutParams = new LayoutParams( + LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT); + layoutView = new LinearLayout(context); + faceIv = new ImageView(context); + layoutView.setLayoutParams(layoutParams); + layoutView.setOrientation(LinearLayout.VERTICAL); + layoutView.setGravity(Gravity.CENTER); + LinearLayout.LayoutParams params = new LinearLayout.LayoutParams( + CommonUtil.getElementSzie(context), + CommonUtil.getElementSzie(context)); + params.gravity = Gravity.CENTER; + layoutView.addView(faceIv, params); + } catch (Exception e) { + logger.e(e.getMessage()); + } + } + } +} diff --git a/android/app/src/main/java/com/mogujie/tt/ui/adapter/GroupManagerAdapter.java b/android/app/src/main/java/com/mogujie/tt/ui/adapter/GroupManagerAdapter.java new file mode 100644 index 000000000..1a4274e5c --- /dev/null +++ b/android/app/src/main/java/com/mogujie/tt/ui/adapter/GroupManagerAdapter.java @@ -0,0 +1,307 @@ +package com.mogujie.tt.ui.adapter; + +import android.content.Context; +import android.view.LayoutInflater; +import android.view.View; +import android.view.View.OnClickListener; +import android.view.ViewGroup; +import android.widget.BaseAdapter; +import android.widget.ImageView; +import android.widget.TextView; + +import com.mogujie.tt.DB.entity.GroupEntity; +import com.mogujie.tt.DB.entity.PeerEntity; +import com.mogujie.tt.DB.entity.UserEntity; +import com.mogujie.tt.R; +import com.mogujie.tt.config.DBConstant; +import com.mogujie.tt.config.SysConstant; +import com.mogujie.tt.imservice.manager.IMContactManager; +import com.mogujie.tt.imservice.service.IMService; +import com.mogujie.tt.ui.widget.IMBaseImageView; +import com.mogujie.tt.utils.IMUIHelper; +import com.mogujie.tt.utils.Logger; + +import java.util.ArrayList; +import java.util.HashSet; +import java.util.List; +import java.util.Set; + + +/** + * @YM 改造 + */ +public class GroupManagerAdapter extends BaseAdapter { + private Logger logger = Logger.getLogger(GroupManagerAdapter.class); + private Context context; + + // 用于控制是否是删除状态,也就是那个减号是否出现 + private boolean removeState = false; + private boolean showMinusTag = false; + private boolean showPlusTag = false; + + + private List memberList = new ArrayList<>(); + private IMService imService; + private int groupCreatorId = -1; + private PeerEntity peerEntity; + + public GroupManagerAdapter(Context c,IMService imService,PeerEntity peerEntity) { + memberList.clear(); + this.context = c; + this.imService = imService; + this.peerEntity = peerEntity; + setData(); + } + + //todo 在选择添加人页面,currentGroupEntity 的值没有设定 + public void setData() { + int sessionType = peerEntity.getType(); + switch (sessionType){ + case DBConstant.SESSION_TYPE_GROUP:{ + GroupEntity groupEntity = (GroupEntity)peerEntity; + setGroupData(groupEntity); + }break; + case DBConstant.SESSION_TYPE_SINGLE:{ + setSingleData((UserEntity)peerEntity); + }break; + } + notifyDataSetChanged(); + } + + private void setGroupData(GroupEntity entity){ + int loginId = imService.getLoginManager().getLoginId(); + int ownerId = entity.getCreatorId(); + IMContactManager manager = imService.getContactManager(); + for(Integer memId:entity.getlistGroupMemberIds()){ + UserEntity user = manager.findContact(memId); + if(user!=null){ + if(ownerId == user.getPeerId()){ + // 群主放在第一个 + groupCreatorId =ownerId; + memberList.add(0, user); + }else { + memberList.add(user); + } + } + } + //按钮状态的判断 + switch (entity.getGroupType()){ + case DBConstant.GROUP_TYPE_TEMP:{ + if(loginId == entity.getCreatorId()){ + showMinusTag = true; + showPlusTag = true; + }else{ + //展示 + + showPlusTag = true; + } + } + break; + case DBConstant.GROUP_TYPE_NORMAL:{ + if(loginId == entity.getCreatorId()){ + // 展示加减 + showMinusTag = true; + showPlusTag = true; + }else{ + // 什么也不展示 + } + } + break; + } + } + + private void setSingleData(UserEntity userEntity){ + if(userEntity != null){ + memberList.add(userEntity); + showPlusTag = true; + } + } + + public int getCount() { + if (null != memberList ) { + int memberListSize = memberList.size(); + if(showPlusTag){ + memberListSize = memberListSize +1; + } + // 现在的情况是有减 一定有加 + if(showMinusTag){ + memberListSize = memberListSize +1; + } + return memberListSize; + } + return 0; + } + + public Object getItem(int position) { + return null; + } + + public long getItemId(int position) { + return position; + } + + + public void removeById(int contactId) { + for (UserEntity contact : memberList) { + if (contact.getPeerId() == contactId) { + memberList.remove(contact); + break; + } + } + notifyDataSetChanged(); + } + + public void add(UserEntity contact) { + removeState = false; + memberList.add(contact); + notifyDataSetChanged(); + } + + public void add(List list){ + removeState = false; + // 群成员的展示没有去重,在收到IMGroupChangeMemberNotify 可能会造成重复数据 + for(UserEntity userEntity:list){ + if(!memberList.contains(userEntity)){ + memberList.add(userEntity); + } + } + notifyDataSetChanged(); + } + + + public View getView(int position, View convertView, ViewGroup parent) { + logger.d("debug#getView position:%d, member size:%d", position, memberList.size()); + + GroupHolder holder; + if(convertView==null) + { + LayoutInflater inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE); + convertView = inflater.inflate(R.layout.tt_group_manage_grid_item, null); + + holder = new GroupHolder(); + holder.imageView = (IMBaseImageView) convertView.findViewById(R.id.grid_item_image); + holder.userTitle = (TextView) convertView.findViewById(R.id.group_manager_user_title); + holder.role = (ImageView)convertView.findViewById(R.id.grid_item_image_role); + holder.deleteImg = convertView.findViewById(R.id.deleteLayout); + holder.imageView.setDefaultImageRes(R.drawable.tt_default_user_portrait_corner); + convertView.setTag(holder); + } + else + { + holder = (GroupHolder)convertView.getTag(); + } + + holder.role.setVisibility(View.GONE); + if (position >= 0 && memberList.size() > position) { + logger.d("groupmgr#in mebers area"); + final UserEntity userEntity = memberList.get(position); + setHolder(holder, position, userEntity.getAvatar(), 0, userEntity.getMainName(), userEntity); + + if (holder.imageView != null) { + holder.imageView.setOnClickListener( new View.OnClickListener() { + @Override + public void onClick(View v) { + IMUIHelper.openUserProfileActivity(context, userEntity.getPeerId()); + } + }); + } + if(groupCreatorId > 0 && groupCreatorId ==userEntity.getPeerId()){ + holder.role.setVisibility(View.VISIBLE); + } + + if (removeState && userEntity.getPeerId()!= groupCreatorId) { + holder.deleteImg.setVisibility(View.VISIBLE); + } else { + holder.deleteImg.setVisibility(View.INVISIBLE); + } + + } else if (position == memberList.size() && showPlusTag) { + logger.d("groupmgr#onAddMsg + button"); + setHolder(holder, position, null, R.drawable.tt_group_manager_add_user, "", null); + holder.imageView.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View view) { + logger.d("groupmgr#click onAddMsg MemberButton"); + IMUIHelper.openGroupMemberSelectActivity(context,peerEntity.getSessionKey()); + } + }); + holder.deleteImg.setVisibility(View.INVISIBLE); + + } else if (position == memberList.size() + 1 && showMinusTag) { + logger.d("groupmgr#onAddMsg - button"); + setHolder(holder, position, null, R.drawable.tt_group_manager_delete_user, "", null); + + holder.imageView.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View view) { + logger.d("groupmgr#click delete MemberButton"); + toggleDeleteIcon(); + } + }); + holder.deleteImg.setVisibility(View.INVISIBLE); + } + return convertView; + } + + private void setHolder(final GroupHolder holder, int position, + String avatarUrl, int avatarResourceId, String name, + UserEntity contactEntity) { + logger.d("debug#setHolder position:%d", position); + + if (null != holder) { + + // holder.imageView.setAdjustViewBounds(false); + // holder.imageView.setScaleType(ImageView.ScaleType.CENTER_CROP); + if (avatarUrl != null) { + //头像设置 + holder.imageView.setDefaultImageRes(R.drawable.tt_default_user_portrait_corner); + holder.imageView.setCorner(8); + holder.imageView.setAvatarAppend(SysConstant.AVATAR_APPEND_120); + holder.imageView.setImageResource(R.drawable.tt_default_user_portrait_corner); + holder.imageView.setImageUrl(avatarUrl); + + } else { + logger.d("groupmgr#setimageresid %d", avatarResourceId); + holder.imageView.setImageId(0); + holder.imageView.setImageId(avatarResourceId); + holder.imageView.setImageUrl(avatarUrl); + } + + holder.contactEntity = contactEntity; + if (contactEntity != null) { + logger.d("debug#setHolderContact name:%s", contactEntity.getMainName()); + + holder.deleteImg.setOnClickListener(new OnClickListener() { + + @Override + public void onClick(View v) { + if(holder.contactEntity == null){return;} + int userId = holder.contactEntity.getPeerId(); + removeById(userId); + Set removeMemberlist = new HashSet<>(1); + removeMemberlist.add(userId); + imService.getGroupManager().reqRemoveGroupMember(peerEntity.getPeerId(), removeMemberlist); + } + }); + } + + holder.userTitle.setText(name); + holder.imageView.setVisibility(View.VISIBLE); + holder.userTitle.setVisibility(View.VISIBLE); + } + } + + + final class GroupHolder { + IMBaseImageView imageView; + TextView userTitle; + View deleteImg; + UserEntity contactEntity; + ImageView role; + } + + public void toggleDeleteIcon(){ + removeState = !removeState; + notifyDataSetChanged(); + } + +} diff --git a/android/app/src/main/java/com/mogujie/tt/ui/adapter/GroupSelectAdapter.java b/android/app/src/main/java/com/mogujie/tt/ui/adapter/GroupSelectAdapter.java new file mode 100644 index 000000000..981e1a018 --- /dev/null +++ b/android/app/src/main/java/com/mogujie/tt/ui/adapter/GroupSelectAdapter.java @@ -0,0 +1,251 @@ +package com.mogujie.tt.ui.adapter; + +import android.content.Context; +import android.text.TextUtils; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.AdapterView; +import android.widget.BaseAdapter; +import android.widget.CheckBox; +import android.widget.SectionIndexer; +import android.widget.TextView; + +import com.mogujie.tt.DB.entity.UserEntity; +import com.mogujie.tt.R; +import com.mogujie.tt.config.SysConstant; +import com.mogujie.tt.imservice.service.IMService; +import com.mogujie.tt.ui.widget.IMBaseImageView; +import com.mogujie.tt.utils.IMUIHelper; +import com.mogujie.tt.utils.Logger; + +import java.util.ArrayList; +import java.util.HashSet; +import java.util.List; +import java.util.Set; + +/** + * @author : yingmu on 15-3-18. + * @email : yingmu@mogujie.com. + * + * 搜索模式下,边边的字母序查找不显示 + */ +public class GroupSelectAdapter extends BaseAdapter implements SectionIndexer, + AdapterView.OnItemClickListener, + AdapterView.OnItemLongClickListener{ + private Logger logger = Logger.getLogger(GroupSelectAdapter.class); + + private List allUserList = new ArrayList<>(); + private List backupList = new ArrayList<>(); + + /**已经选中的,不能操作*/ + private Set alreadyListSet = new HashSet<>(); + /**在选择面板里面选择的*/ + private Set checkListSet= new HashSet<>(); + + private boolean isSearchMode= false; + private String searchKey; + private Context ctx; + private IMService imService; + + public GroupSelectAdapter(Context ctx,IMService service){ + this.ctx = ctx; + this.imService = service; + } + + public void setAllUserList(List allUserList) { + this.allUserList = allUserList; + this.backupList = allUserList; + } + + public void recover(){ + isSearchMode = false; + allUserList = backupList; + notifyDataSetChanged(); + } + + public void onSearch(String key){ + isSearchMode = true; + searchKey = key; + //allUserList.clear(); + List searchList = new ArrayList<>(); + for(UserEntity entity:backupList){ + if(IMUIHelper.handleContactSearch(searchKey,entity)){ + searchList.add(entity); + } + } + allUserList = searchList; + notifyDataSetChanged(); + } + + @Override + public Object[] getSections() { + return new Object[0]; + } + + + // 在搜索模式下,直接返回 + @Override + public int getPositionForSection(int sectionIndex) { + logger.d("pinyin#getPositionForSection secton:%d", sectionIndex); + int index = 0; + for(UserEntity entity:allUserList){ + int firstCharacter = entity.getSectionName().charAt(0); + // logger.d("firstCharacter:%d", firstCharacter); + if (firstCharacter == sectionIndex) { + logger.d("pinyin#find sectionName"); + return index; + } + index++; + } + logger.e("pinyin#can't find such section:%d", sectionIndex); + return -1; + } + + + @Override + public int getSectionForPosition(int position) { + return 0; + } + + @Override + public void onItemClick(AdapterView parent, View view, int position, long id) { + UserEntity contact = (UserEntity) getItem(position); + UserHolder viewHolder = (UserHolder) view.getTag(); + + if (viewHolder == null || alreadyListSet.contains(contact.getPeerId())) { + return; + } + viewHolder.checkBox.toggle(); + boolean checked = viewHolder.checkBox.isChecked(); + int userId = contact.getPeerId(); + if (checked) { + checkListSet.add(userId); + } else { + checkListSet.remove(userId); + } + } + + @Override + public boolean onItemLongClick(AdapterView parent, View view, int position, long id) { + UserEntity contact = (UserEntity) getItem(position); + IMUIHelper.handleContactItemLongClick(contact, ctx); + return true; + } + + @Override + public int getCount() { + int size = allUserList==null?0:allUserList.size(); + return size; + } + + @Override + public Object getItem(int position) { + return allUserList.get(position); + } + + @Override + public long getItemId(int position) { + return position; + } + + @Override + public View getView(int position, View view, ViewGroup parent) { + UserEntity userEntity = (UserEntity) getItem(position); + if(userEntity == null){ + logger.e("GroupSelectAdapter#getView#userEntity is null!position:%d",position); + return null; + } + + + + UserHolder userHolder = null; + if (view == null) { + userHolder = new UserHolder(); + view = LayoutInflater.from(ctx).inflate(R.layout.tt_item_contact, parent,false); + userHolder.nameView = (TextView) view.findViewById(R.id.contact_item_title); + userHolder.realNameView = (TextView) view.findViewById(R.id.contact_realname_title); + userHolder.sectionView = (TextView) view.findViewById(R.id.contact_category_title); + userHolder.avatar = (IMBaseImageView)view.findViewById(R.id.contact_portrait); + userHolder.checkBox = (CheckBox) view.findViewById(R.id.checkBox); + userHolder.divider = view.findViewById(R.id.contact_divider); + view.setTag(userHolder); + } else { + userHolder = (UserHolder) view.getTag(); + } + + userHolder.checkBox.setVisibility(View.VISIBLE); + if(isSearchMode){ + // 高亮显示 + IMUIHelper.setTextHilighted(userHolder.nameView, userEntity.getMainName(), + userEntity.getSearchElement()); + }else{ + userHolder.nameView.setText(userEntity.getMainName()); + } + + userHolder.avatar.setImageResource(R.drawable.tt_default_user_portrait_corner); + userHolder.divider.setVisibility(View.VISIBLE); + + // 字母序第一个要展示 ,搜索模式下不展示sectionName + if(!isSearchMode) { + String sectionName = userEntity.getSectionName(); + String preSectionName = null; + if (position > 0) { + preSectionName = ((UserEntity) getItem(position - 1)).getSectionName(); + } + if (TextUtils.isEmpty(preSectionName) || !preSectionName.equals(sectionName)) { + userHolder.sectionView.setVisibility(View.VISIBLE); + userHolder.sectionView.setText(sectionName); + userHolder.divider.setVisibility(View.GONE); + } else { + userHolder.sectionView.setVisibility(View.GONE); + } + }else{ + userHolder.sectionView.setVisibility(View.GONE); + } + + // checkBox 状态的设定 + boolean checked = checkListSet.contains(userEntity.getPeerId()); + userHolder.checkBox.setChecked(checked); + boolean disable = alreadyListSet.contains(userEntity.getPeerId()); + if(disable){ + userHolder.checkBox.setEnabled(false); + }else{ + userHolder.checkBox.setEnabled(true); + } + + userHolder.avatar.setDefaultImageRes(R.drawable.tt_default_user_portrait_corner); + userHolder.avatar.setCorner(0); + userHolder.avatar.setAvatarAppend(SysConstant.AVATAR_APPEND_100); + userHolder.avatar.setImageUrl(userEntity.getAvatar()); + + userHolder.realNameView.setText(userEntity.getRealName()); + userHolder.realNameView.setVisibility(View.GONE); + return view; + } + + + public static class UserHolder { + View divider; + TextView sectionView; + TextView nameView; + TextView realNameView; + IMBaseImageView avatar; + CheckBox checkBox; + } + + + /**------------------set/get------------------*/ + + public Set getAlreadyListSet() { + return alreadyListSet; + } + + public void setAlreadyListSet(Set alreadyListSet) { + this.alreadyListSet = alreadyListSet; + } + + public Set getCheckListSet() { + return checkListSet; + } +} diff --git a/android/app/src/main/java/com/mogujie/tt/ui/adapter/InternalAdapter.java b/android/app/src/main/java/com/mogujie/tt/ui/adapter/InternalAdapter.java new file mode 100644 index 000000000..61fe197b7 --- /dev/null +++ b/android/app/src/main/java/com/mogujie/tt/ui/adapter/InternalAdapter.java @@ -0,0 +1,212 @@ +package com.mogujie.tt.ui.adapter; + +import android.content.Context; +import android.text.TextUtils; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.BaseAdapter; +import android.widget.TextView; +import com.loopj.android.http.AsyncHttpClient; +import com.loopj.android.http.BaseJsonHttpResponseHandler; +import com.mogujie.tt.DB.sp.SystemConfigSp; +import com.mogujie.tt.R; +import com.mogujie.tt.utils.Logger; + +import org.apache.http.Header; +import org.json.JSONArray; +import org.json.JSONException; +import org.json.JSONObject; +import java.util.ArrayList; +import java.util.List; +import java.util.Comparator; +import java.util.Collections; + +/** + * Created by zhujian on 15/3/12. + */ +public class InternalAdapter extends BaseAdapter { + private Context ctx = null; + private List datalist = new ArrayList<>(); + private Logger logger = Logger.getLogger(ChatAdapter.class); + private AsyncHttpClient client; + + public InternalAdapter(Context context) { + ctx = context; + client = new AsyncHttpClient(); + } + + @Override + public int getCount() { + return datalist.size(); + } + + @Override + public InternalItem getItem(int position) { + logger.d("recent#getItem position:%d", position); + if (position >= datalist.size() || position < 0) { + return null; + } + return datalist.get(position); + } + + @Override + public long getItemId(int position) { + return position; + } + + /** + * 基本HOLDER + */ + public static class ViewHoler { + public TextView title; + } + + @Override + public View getView(int position, View convertView, ViewGroup parent) { + try { + InternalItem info = datalist.get(position); + ViewHoler holder; + if (null == convertView) { + convertView = LayoutInflater.from(ctx).inflate(R.layout.tt_item_internalitem, parent, false); + holder = new ViewHoler(); + holder.title = (TextView) convertView.findViewById(R.id.tt_internal_item_title); + convertView.setTag(holder); + } else { + holder = (ViewHoler) convertView.getTag(); + } + holder.title.setText(info.getItemName()); + return convertView; + } catch (Exception e) { + logger.e(e.toString()); + return null; + } + } + + public void update() { + client.setUserAgent("Android-TT"); + SystemConfigSp.instance().init(ctx.getApplicationContext()); + client.get(SystemConfigSp.instance().getStrConfig(SystemConfigSp.SysCfgDimension.DISCOVERYURI), new BaseJsonHttpResponseHandler() { + @Override + public void onSuccess(int i, Header[] headers, String s, Object o) { + } + + @Override + public void onFailure(int i, Header[] headers, Throwable throwable, String responseString, Object o) { + try { + convertJson2Data(); + } catch (JSONException e) { + e.printStackTrace(); + } + } + + @Override + protected Object parseResponse(String s, boolean b) throws Throwable { + /*子类需要提供实现,将请求结果解析成需要的类型 异常怎么处理*/ + SystemConfigSp.instance().setStrConfig(SystemConfigSp.SysCfgDimension.DISCOVERYDATA, s); + convertJson2Data(); + return null; + } + }); + } + + private void convertJson2Data() throws JSONException { + String strData = SystemConfigSp.instance().getStrConfig(SystemConfigSp.SysCfgDimension.DISCOVERYDATA); + if (!TextUtils.isEmpty(strData)) { + JSONArray jsonArray = new JSONArray(strData); + int len = jsonArray.length(); + datalist.clear(); + for (int i = 0; i < len; i++) { + JSONObject item = (JSONObject) jsonArray.get(i); + InternalItem info = new InternalItem(); + info.setItemName(item.getString("itemName")); + info.setItemUrl(item.getString("itemUrl")); + info.setItemPriority(item.getInt("itemPriority")); + datalist.add(info); + } + Collections.sort(datalist, new SortByPriority()); + } else { + datalist.clear(); + } + notifyDataSetChanged(); + } + + public class InternalItem { + + private int id; + private String itemName; + private String itemUrl; + private int itemPriority; + private int status; + private int created; + private int updated; + + public void setId(int id) { + this.id = id; + } + + public int getId() { + return this.id; + } + + public String getItemName() { + return itemName; + } + + public void setItemName(String name) { + this.itemName = name; + } + + public String getItemUrl() { + return this.itemUrl; + } + + public void setItemUrl(String url) { + this.itemUrl = url; + } + + public int getItemPriority() { + return this.itemPriority; + } + + public void setItemPriority(int priority) { + this.itemPriority = priority; + } + + public int getStatus() { + return this.status; + } + + public void setStatus(int status) { + this.status = status; + } + + public int getCreated() { + return this.created; + } + + public void setCreated(int created) { + this.created = created; + } + + public int getUpdated() { + return this.updated; + } + + public void setUpdated(int updated) { + this.updated = updated; + } + + } + + class SortByPriority implements Comparator { + public int compare(Object o1, Object o2) { + InternalItem s1 = (InternalItem) o1; + InternalItem s2 = (InternalItem) o2; + if (s1.getItemPriority() > s2.getItemPriority()) + return 1; + return 0; + } + } + +} diff --git a/android/app/src/main/java/com/mogujie/tt/ui/adapter/MessageAdapter.java b/android/app/src/main/java/com/mogujie/tt/ui/adapter/MessageAdapter.java new file mode 100644 index 000000000..be299dbb9 --- /dev/null +++ b/android/app/src/main/java/com/mogujie/tt/ui/adapter/MessageAdapter.java @@ -0,0 +1,835 @@ +package com.mogujie.tt.ui.adapter; + +import android.annotation.SuppressLint; +import android.app.Activity; +import android.content.ClipData; +import android.content.ClipboardManager; +import android.content.Context; +import android.content.Intent; +import android.media.AudioManager; +import android.os.Bundle; +import android.text.TextUtils; +import android.view.View; +import android.view.ViewGroup; +import android.widget.BaseAdapter; +import android.widget.FrameLayout; +import android.widget.ImageView; +import android.widget.TextView; +import android.widget.Toast; + +import com.mogujie.tt.config.DBConstant; +import com.mogujie.tt.DB.entity.MessageEntity; +import com.mogujie.tt.DB.entity.UserEntity; +import com.mogujie.tt.R; +import com.mogujie.tt.config.MessageConstant; +import com.mogujie.tt.ui.helper.AudioPlayerHandler; +import com.mogujie.tt.config.IntentConstant; +import com.mogujie.tt.imservice.entity.AudioMessage; +import com.mogujie.tt.imservice.entity.ImageMessage; +import com.mogujie.tt.imservice.entity.MixMessage; +import com.mogujie.tt.imservice.entity.TextMessage; +import com.mogujie.tt.imservice.service.IMService; +import com.mogujie.tt.ui.activity.PreviewGifActivity; +import com.mogujie.tt.ui.activity.PreviewMessageImagesActivity; +import com.mogujie.tt.ui.activity.PreviewTextActivity; +import com.mogujie.tt.ui.helper.Emoparser; +import com.mogujie.tt.ui.widget.GifView; +import com.mogujie.tt.ui.widget.message.GifImageRenderView; +import com.mogujie.tt.utils.CommonUtil; +import com.mogujie.tt.utils.DateUtil; +import com.mogujie.tt.utils.FileUtil; +import com.mogujie.tt.utils.Logger; +import com.mogujie.tt.ui.widget.SpeekerToast; +import com.mogujie.tt.ui.widget.message.AudioRenderView; +import com.mogujie.tt.ui.widget.message.EmojiRenderView; +import com.mogujie.tt.ui.widget.message.ImageRenderView; +import com.mogujie.tt.ui.widget.message.MessageOperatePopup; +import com.mogujie.tt.ui.widget.message.RenderType; +import com.mogujie.tt.ui.widget.message.TextRenderView; +import com.mogujie.tt.ui.widget.message.TimeRenderView; +import com.mogujie.tt.ui.helper.listener.OnDoubleClickListener; +import com.mogujie.tt.utils.ScreenUtil; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.Comparator; +import java.util.List; + +/** + * @author : yingmu on 15-1-8. + * @email : yingmu@mogujie.com. + */ +public class MessageAdapter extends BaseAdapter { + private Logger logger = Logger.getLogger(MessageAdapter.class); + + private ArrayList msgObjectList = new ArrayList<>(); + + /** + * 弹出气泡 + */ + private MessageOperatePopup currentPop; + private Context ctx; + /** + * 依赖整体session状态的 + */ + private UserEntity loginUser; + private IMService imService; + + public MessageAdapter(Context ctx) { + this.ctx = ctx; + } + + /** + * ----------------------init 的时候需要设定----------------- + */ + + public void setImService(IMService imService,UserEntity loginUser) { + this.imService = imService; + this.loginUser = loginUser; + } + + /** + * ----------------------添加历史消息----------------- + */ + public void addItem(final MessageEntity msg) { + if (msg.getDisplayType() == DBConstant.MSG_TYPE_SINGLE_TEXT) { + if (isMsgGif(msg)) { + msg.setGIfEmo(true); + } else { + msg.setGIfEmo(false); + } + } + int nextTime = msg.getCreated(); + if (getCount() > 0) { + Object object = msgObjectList.get(getCount() - 1); + if (object instanceof MessageEntity) { + int preTime = ((MessageEntity) object).getCreated(); + boolean needTime = DateUtil.needDisplayTime(preTime, nextTime); + if (needTime) { + Integer in = nextTime; + msgObjectList.add(in); + } + } + } else { + Integer in = msg.getCreated(); + msgObjectList.add(in); + } + /**消息的判断*/ + if (msg.getDisplayType() == DBConstant.SHOW_MIX_TEXT) { + MixMessage mixMessage = (MixMessage) msg; + msgObjectList.addAll(mixMessage.getMsgList()); + } else { + msgObjectList.add(msg); + } + if (msg instanceof ImageMessage) { + ImageMessage.addToImageMessageList((ImageMessage) msg); + } + logger.d("#messageAdapter#addItem"); + notifyDataSetChanged(); + + } + + private boolean isMsgGif(MessageEntity msg) { + String content = msg.getContent(); + // @YM 临时处理 牙牙表情与消息混合出现的消息丢失 + if (TextUtils.isEmpty(content) + || !(content.startsWith("[") && content.endsWith("]"))) { + return false; + } + return Emoparser.getInstance(this.ctx).isMessageGif(msg.getContent()); + } + + public MessageEntity getTopMsgEntity() { + if (msgObjectList.size() <= 0) { + return null; + } + for (Object result : msgObjectList) { + if (result instanceof MessageEntity) { + return (MessageEntity) result; + } + } + return null; + } + + public static class MessageTimeComparator implements Comparator { + @Override + public int compare(MessageEntity lhs, MessageEntity rhs) { + if (lhs.getCreated() == rhs.getCreated()) { + return lhs.getMsgId() - rhs.getMsgId(); + } + return lhs.getCreated() - rhs.getCreated(); + } + } + + ; + + /** + * 下拉载入历史消息,从最上面开始添加 + */ + public void loadHistoryList(final List historyList) { + logger.d("#messageAdapter#loadHistoryList"); + if (null == historyList || historyList.size() <= 0) { + return; + } + Collections.sort(historyList, new MessageTimeComparator()); + ArrayList chatList = new ArrayList<>(); + int preTime = 0; + int nextTime = 0; + for (MessageEntity msg : historyList) { + if (msg.getDisplayType() == DBConstant.MSG_TYPE_SINGLE_TEXT) { + if (isMsgGif(msg)) { + msg.setGIfEmo(true); + } else { + msg.setGIfEmo(false); + } + } + nextTime = msg.getCreated(); + boolean needTimeBubble = DateUtil.needDisplayTime(preTime, nextTime); + if (needTimeBubble) { + Integer in = nextTime; + chatList.add(in); + } + preTime = nextTime; + if (msg.getDisplayType() == DBConstant.SHOW_MIX_TEXT) { + MixMessage mixMessage = (MixMessage) msg; + chatList.addAll(mixMessage.getMsgList()); + } else { + chatList.add(msg); + } + } + // 如果是历史消息,从头开始加 + msgObjectList.addAll(0, chatList); + getImageList(); + logger.d("#messageAdapter#addItem"); + notifyDataSetChanged(); + } + + /** + * 获取图片消息列表 + */ + private void getImageList() { + for (int i = msgObjectList.size() - 1; i >= 0; --i) { + Object item = msgObjectList.get(i); + if (item instanceof ImageMessage) { + ImageMessage.addToImageMessageList((ImageMessage) item); + } + } + } + + /** + * 临时处理,一定要干掉 + */ + public void hidePopup() { + if (currentPop != null) { + currentPop.hidePopup(); + } + } + + + public void clearItem() { + msgObjectList.clear(); + } + + /** + * msgId 是消息ID + * localId是本地的ID + * position 是list 的位置 + *

+ * 只更新item的状态 + * 刷新单条记录 + *

+ */ + public void updateItemState(int position, final MessageEntity messageEntity) { + //更新DB + //更新单条记录 + imService.getDbInterface().insertOrUpdateMessage(messageEntity); + notifyDataSetChanged(); + } + + /** + * 对于混合消息的特殊处理 + */ + public void updateItemState(final MessageEntity messageEntity) { + long dbId = messageEntity.getId(); + int msgId = messageEntity.getMsgId(); + int len = msgObjectList.size(); + for (int index = len - 1; index > 0; index--) { + Object object = msgObjectList.get(index); + if (object instanceof MessageEntity) { + MessageEntity entity = (MessageEntity) object; + if (object instanceof ImageMessage) { + ImageMessage.addToImageMessageList((ImageMessage) object); + } + if (entity.getId() == dbId && entity.getMsgId() == msgId) { + msgObjectList.set(index, messageEntity); + break; + } + } + } + notifyDataSetChanged(); + } + + @Override + public int getCount() { + if (null == msgObjectList) { + return 0; + } else { + return msgObjectList.size(); + } + } + + @Override + public int getViewTypeCount() { + return RenderType.values().length; + } + + + @Override + public int getItemViewType(int position) { + try { + /**默认是失败类型*/ + RenderType type = RenderType.MESSAGE_TYPE_INVALID; + + Object obj = msgObjectList.get(position); + if (obj instanceof Integer) { + type = RenderType.MESSAGE_TYPE_TIME_TITLE; + } else if (obj instanceof MessageEntity) { + MessageEntity info = (MessageEntity) obj; + boolean isMine = info.getFromId() == loginUser.getPeerId(); + switch (info.getDisplayType()) { + case DBConstant.SHOW_AUDIO_TYPE: + type = isMine ? RenderType.MESSAGE_TYPE_MINE_AUDIO + : RenderType.MESSAGE_TYPE_OTHER_AUDIO; + break; + case DBConstant.SHOW_IMAGE_TYPE: + ImageMessage imageMessage = (ImageMessage) info; + if (CommonUtil.gifCheck(imageMessage.getUrl())) { + type = isMine ? RenderType.MESSAGE_TYPE_MINE_GIF_IMAGE + : RenderType.MESSAGE_TYPE_OTHER_GIF_IMAGE; + } else { + type = isMine ? RenderType.MESSAGE_TYPE_MINE_IMAGE + : RenderType.MESSAGE_TYPE_OTHER_IMAGE; + } + + break; + case DBConstant.SHOW_ORIGIN_TEXT_TYPE: + if (info.isGIfEmo()) { + type = isMine ? RenderType.MESSAGE_TYPE_MINE_GIF + : RenderType.MESSAGE_TYPE_OTHER_GIF; + } else { + type = isMine ? RenderType.MESSAGE_TYPE_MINE_TETX + : RenderType.MESSAGE_TYPE_OTHER_TEXT; + } + + break; + case DBConstant.SHOW_MIX_TEXT: + // + logger.e("混合的消息类型%s", obj); + default: + break; + } + } + return type.ordinal(); + } catch (Exception e) { + logger.e(e.getMessage()); + return RenderType.MESSAGE_TYPE_INVALID.ordinal(); + } + } + + @Override + public Object getItem(int position) { + if (position >= getCount() || position < 0) { + return null; + } + return msgObjectList.get(position); + } + + @Override + public long getItemId(int position) { + return position; + } + + + /** + * 时间气泡的渲染展示 + */ + private View timeBubbleRender(int position, View convertView, ViewGroup parent) { + TimeRenderView timeRenderView; + Integer timeBubble = (Integer) msgObjectList.get(position); + if (null == convertView) { + timeRenderView = TimeRenderView.inflater(ctx, parent); + } else { + // 不用再使用tag 标签了 + timeRenderView = (TimeRenderView) convertView; + } + timeRenderView.setTime(timeBubble); + return timeRenderView; + } + + /** + * 1.头像事件 + * mine:事件 other事件 + * 图片的状态 消息收到,没收到,图片展示成功,没有成功 + * 触发图片的事件 【长按】 + *

+ * 图片消息类型的render + * + * @param position + * @param convertView + * @param parent + * @param isMine + * @return + */ + private View imageMsgRender(final int position, View convertView, final ViewGroup parent, final boolean isMine) { + ImageRenderView imageRenderView; + final ImageMessage imageMessage = (ImageMessage) msgObjectList.get(position); + UserEntity userEntity = imService.getContactManager().findContact(imageMessage.getFromId()); + + /**保存在本地的path*/ + final String imagePath = imageMessage.getPath(); + /**消息中的image路径*/ + final String imageUrl = imageMessage.getUrl(); + + if (null == convertView) { + imageRenderView = ImageRenderView.inflater(ctx, parent, isMine); + } else { + imageRenderView = (ImageRenderView) convertView; + } + + final ImageView messageImage = imageRenderView.getMessageImage(); + final int msgId = imageMessage.getMsgId(); + imageRenderView.setBtnImageListener(new ImageRenderView.BtnImageListener() { + @Override + public void onMsgFailure() { + /** + * 多端同步也不会拉到本地失败的数据 + * 只有isMine才有的状态,消息发送失败 + * 1. 图片上传失败。点击图片重新上传??[也是重新发送] + * 2. 图片上传成功,但是发送失败。 点击重新发送?? + */ + if (FileUtil.isSdCardAvailuable()) { +// imageMessage.setLoadStatus(MessageStatus.IMAGE_UNLOAD);//如果是图片已经上传成功呢? + imageMessage.setStatus(MessageConstant.MSG_SENDING); + if (imService != null) { + imService.getMessageManager().resendMessage(imageMessage); + } + updateItemState(msgId, imageMessage); + } else { + Toast.makeText(ctx, ctx.getString(R.string.sdcard_unavaluable), Toast.LENGTH_LONG).show(); + } + } + + //DetailPortraitActivity 以前用的是DisplayImageActivity 这个类 + @Override + public void onMsgSuccess() { + Intent i = new Intent(ctx, PreviewMessageImagesActivity.class); + Bundle bundle = new Bundle(); + bundle.putSerializable(IntentConstant.CUR_MESSAGE, imageMessage); + i.putExtras(bundle); + ctx.startActivity(i); + ((Activity) ctx).overridePendingTransition(R.anim.tt_image_enter, R.anim.tt_stay); + } + }); + + // 设定触发loadImage的事件 + imageRenderView.setImageLoadListener(new ImageRenderView.ImageLoadListener() { + + @Override + public void onLoadComplete(String loaclPath) { + logger.d("chat#pic#save image ok"); + logger.d("pic#setsavepath:%s", loaclPath); +// imageMessage.setPath(loaclPath);//下载的本地路径不再存储 + imageMessage.setLoadStatus(MessageConstant.IMAGE_LOADED_SUCCESS); + updateItemState(imageMessage); + } + + @Override + public void onLoadFailed() { + logger.d("chat#pic#onBitmapFailed"); + imageMessage.setLoadStatus(MessageConstant.IMAGE_LOADED_FAILURE); + updateItemState(imageMessage); + logger.d("download failed"); + } + }); + + final View messageLayout = imageRenderView.getMessageLayout(); + messageImage.setOnLongClickListener(new View.OnLongClickListener() { + @Override + public boolean onLongClick(View v) { + // 创建一个pop对象,然后 分支判断状态,然后显示需要的内容 + MessageOperatePopup popup = getPopMenu(parent, new OperateItemClickListener(imageMessage, position)); + boolean bResend = (imageMessage.getStatus() == MessageConstant.MSG_FAILURE) + || (imageMessage.getLoadStatus() == MessageConstant.IMAGE_UNLOAD); + popup.show(messageLayout, DBConstant.SHOW_IMAGE_TYPE, bResend, isMine); + return true; + } + }); + + /**父类控件中的发送失败view*/ + imageRenderView.getMessageFailed().setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View arg0) { + // 重发或者重新加载 + MessageOperatePopup popup = getPopMenu(parent, new OperateItemClickListener(imageMessage, position)); + popup.show(messageLayout, DBConstant.SHOW_IMAGE_TYPE, true, isMine); + } + }); + imageRenderView.render(imageMessage, userEntity, ctx); + + return imageRenderView; + } + + private View GifImageMsgRender(final int position, View convertView, final ViewGroup parent, final boolean isMine) { + GifImageRenderView imageRenderView; + final ImageMessage imageMessage = (ImageMessage) msgObjectList.get(position); + UserEntity userEntity = imService.getContactManager().findContact(imageMessage.getFromId()); + if (null == convertView) { + imageRenderView = GifImageRenderView.inflater(ctx, parent, isMine); + } else { + imageRenderView = (GifImageRenderView) convertView; + } + GifView imageView = imageRenderView.getMessageContent(); + imageView.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View arg0) { + final String url = imageMessage.getUrl(); + Intent intent = new Intent(ctx, PreviewGifActivity.class); + intent.putExtra(IntentConstant.PREVIEW_TEXT_CONTENT, url); + ctx.startActivity(intent); + ((Activity) ctx).overridePendingTransition(R.anim.tt_image_enter, R.anim.tt_stay); + } + }); + imageRenderView.render(imageMessage, userEntity, ctx); + return imageRenderView; + } + + /** + * 语音的路径,判断收发的状态 + * 展现的状态 + * 播放动画相关 + * 获取语音的读取状态/ + * 语音长按事件 + * + * @param position + * @param convertView + * @param parent + * @param isMine + * @return + */ + private View audioMsgRender(final int position, View convertView, final ViewGroup parent, final boolean isMine) { + AudioRenderView audioRenderView; + final AudioMessage audioMessage = (AudioMessage) msgObjectList.get(position); + UserEntity entity = imService.getContactManager().findContact(audioMessage.getFromId()); + if (null == convertView) { + audioRenderView = AudioRenderView.inflater(ctx, parent, isMine); + } else { + audioRenderView = (AudioRenderView) convertView; + } + final String audioPath = audioMessage.getAudioPath(); + + final View messageLayout = audioRenderView.getMessageLayout(); + if (!TextUtils.isEmpty(audioPath)) { + // 播放的路径为空,这个消息应该如何展示 + messageLayout.setOnLongClickListener(new View.OnLongClickListener() { + @Override + public boolean onLongClick(View v) { + MessageOperatePopup popup = getPopMenu(parent, new OperateItemClickListener(audioMessage, position)); + boolean bResend = audioMessage.getStatus() == MessageConstant.MSG_FAILURE; + popup.show(messageLayout, DBConstant.SHOW_AUDIO_TYPE, bResend, isMine); + return true; + } + }); + } + + + audioRenderView.getMessageFailed().setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View arg0) { + MessageOperatePopup popup = getPopMenu(parent, new OperateItemClickListener(audioMessage, position)); + popup.show(messageLayout, DBConstant.SHOW_AUDIO_TYPE, true, isMine); + } + }); + + + audioRenderView.setBtnImageListener(new AudioRenderView.BtnImageListener() { + @Override + public void onClickUnread() { + logger.d("chat#audio#set audio meessage read status"); + audioMessage.setReadStatus(MessageConstant.AUDIO_READED); + imService.getDbInterface().insertOrUpdateMessage(audioMessage); + } + + @Override + public void onClickReaded() { + } + }); + audioRenderView.render(audioMessage, entity, ctx); + return audioRenderView; + } + + + /** + * text类型的: 1. 设定内容Emoparser + * 2. 点击事件 单击跳转、 双击方法、长按pop menu + * 点击头像的事件 跳转 + * + * @param position + * @param convertView + * @param viewGroup + * @param isMine + * @return + */ + private View textMsgRender(final int position, View convertView, final ViewGroup viewGroup, final boolean isMine) { + TextRenderView textRenderView; + final TextMessage textMessage = (TextMessage) msgObjectList.get(position); + UserEntity userEntity = imService.getContactManager().findContact(textMessage.getFromId()); + + if (null == convertView) { + textRenderView = TextRenderView.inflater(ctx, viewGroup, isMine); //new TextRenderView(ctx,viewGroup,isMine); + } else { + textRenderView = (TextRenderView) convertView; + } + + final TextView textView = textRenderView.getMessageContent(); + + // 失败事件添加 + textRenderView.getMessageFailed().setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View arg0) { + MessageOperatePopup popup = getPopMenu(viewGroup, new OperateItemClickListener(textMessage, position)); + popup.show(textView, DBConstant.SHOW_ORIGIN_TEXT_TYPE, true, isMine); + } + }); + + textView.setOnLongClickListener(new View.OnLongClickListener() { + @Override + public boolean onLongClick(View v) { + // 弹窗类型 + MessageOperatePopup popup = getPopMenu(viewGroup, new OperateItemClickListener(textMessage, position)); + boolean bResend = textMessage.getStatus() == MessageConstant.MSG_FAILURE; + popup.show(textView, DBConstant.SHOW_ORIGIN_TEXT_TYPE, bResend, isMine); + return true; + } + }); + + // url 路径可以设定 跳转哦哦 + final String content = textMessage.getContent(); + textView.setOnTouchListener(new OnDoubleClickListener() { + @Override + public void onClick(View view) { + //todo + } + + @Override + public void onDoubleClick(View view) { + Intent intent = new Intent(ctx, PreviewTextActivity.class); + intent.putExtra(IntentConstant.PREVIEW_TEXT_CONTENT, content); + ctx.startActivity(intent); + } + }); + textRenderView.render(textMessage, userEntity, ctx); + return textRenderView; + } + + /** + * 牙牙表情等gif类型的消息: 1. 设定内容Emoparser + * 2. 点击事件 单击跳转、 双击方法、长按pop menu + * 点击头像的事件 跳转 + * + * @param position + * @param convertView + * @param viewGroup + * @param isMine + * @return + */ + private View gifMsgRender(final int position, View convertView, final ViewGroup viewGroup, final boolean isMine) { + EmojiRenderView gifRenderView; + final TextMessage textMessage = (TextMessage) msgObjectList.get(position); + UserEntity userEntity = imService.getContactManager().findContact(textMessage.getFromId()); + if (null == convertView) { + gifRenderView = EmojiRenderView.inflater(ctx, viewGroup, isMine); //new TextRenderView(ctx,viewGroup,isMine); + } else { + gifRenderView = (EmojiRenderView) convertView; + } + + final ImageView imageView = gifRenderView.getMessageContent(); + // 失败事件添加 + gifRenderView.getMessageFailed().setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View arg0) { + MessageOperatePopup popup = getPopMenu(viewGroup, new OperateItemClickListener(textMessage, position)); + popup.show(imageView, DBConstant.SHOW_GIF_TYPE, true, isMine); + } + }); + + imageView.setOnLongClickListener(new View.OnLongClickListener() { + @Override + public boolean onLongClick(View v) { + MessageOperatePopup popup = getPopMenu(viewGroup, new OperateItemClickListener(textMessage, position)); + boolean bResend = textMessage.getStatus() == MessageConstant.MSG_FAILURE; + popup.show(imageView, DBConstant.SHOW_GIF_TYPE, bResend, isMine); + + return true; + } + }); + + imageView.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View arg0) { + final String content = textMessage.getContent(); + Intent intent = new Intent(ctx, PreviewGifActivity.class); + intent.putExtra(IntentConstant.PREVIEW_TEXT_CONTENT, content); + ctx.startActivity(intent); + ((Activity) ctx).overridePendingTransition(R.anim.tt_image_enter, R.anim.tt_stay); + } + }); + + gifRenderView.render(textMessage, userEntity, ctx); + return gifRenderView; + } + + + @Override + public View getView(int position, View convertView, ViewGroup parent) { + try { + final int typeIndex = getItemViewType(position); + RenderType renderType = RenderType.values()[typeIndex]; + // 改用map的形式 + switch (renderType) { + case MESSAGE_TYPE_INVALID: + // 直接返回 + logger.e("[fatal erro] render type:MESSAGE_TYPE_INVALID"); + break; + + case MESSAGE_TYPE_TIME_TITLE: + convertView = timeBubbleRender(position, convertView, parent); + break; + + case MESSAGE_TYPE_MINE_AUDIO: + convertView = audioMsgRender(position, convertView, parent, true); + break; + case MESSAGE_TYPE_OTHER_AUDIO: + convertView = audioMsgRender(position, convertView, parent, false); + break; + case MESSAGE_TYPE_MINE_GIF_IMAGE: + convertView = GifImageMsgRender(position, convertView, parent, true); + break; + case MESSAGE_TYPE_OTHER_GIF_IMAGE: + convertView = GifImageMsgRender(position, convertView, parent, false); + break; + case MESSAGE_TYPE_MINE_IMAGE: + convertView = imageMsgRender(position, convertView, parent, true); + break; + case MESSAGE_TYPE_OTHER_IMAGE: + convertView = imageMsgRender(position, convertView, parent, false); + break; + case MESSAGE_TYPE_MINE_TETX: + convertView = textMsgRender(position, convertView, parent, true); + break; + case MESSAGE_TYPE_OTHER_TEXT: + convertView = textMsgRender(position, convertView, parent, false); + break; + + case MESSAGE_TYPE_MINE_GIF: + convertView = gifMsgRender(position, convertView, parent, true); + break; + case MESSAGE_TYPE_OTHER_GIF: + convertView = gifMsgRender(position, convertView, parent, false); + break; + } + return convertView; + } catch (Exception e) { + logger.e("chat#%s", e); + return null; + } + } + + /** + * 点击事件的定义 + */ + private MessageOperatePopup getPopMenu(ViewGroup parent, MessageOperatePopup.OnItemClickListener listener) { + MessageOperatePopup popupView = MessageOperatePopup.instance(ctx, parent); + currentPop = popupView; + popupView.setOnItemClickListener(listener); + return popupView; + } + + private class OperateItemClickListener + implements + MessageOperatePopup.OnItemClickListener { + + private MessageEntity mMsgInfo; + private int mType; + private int mPosition; + + public OperateItemClickListener(MessageEntity msgInfo, int position) { + mMsgInfo = msgInfo; + mType = msgInfo.getDisplayType(); + mPosition = position; + } + + @SuppressWarnings("deprecation") + @SuppressLint("NewApi") + @Override + public void onCopyClick() { + try { + ClipboardManager manager = (ClipboardManager) ctx.getSystemService(Context.CLIPBOARD_SERVICE); + + logger.d("menu#onCopyClick content:%s", mMsgInfo.getContent()); + if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.HONEYCOMB) { + ClipData data = ClipData.newPlainText("data", mMsgInfo.getContent()); + manager.setPrimaryClip(data); + } else { + manager.setText(mMsgInfo.getContent()); + } + } catch (Exception e) { + logger.e(e.getMessage()); + } + } + + @Override + public void onResendClick() { + try { + if (mType == DBConstant.SHOW_AUDIO_TYPE + || mType == DBConstant.SHOW_ORIGIN_TEXT_TYPE) { + + if (mMsgInfo.getDisplayType() == DBConstant.SHOW_AUDIO_TYPE) { + if (mMsgInfo.getSendContent().length < 4) { + return; + } + } + } else if (mType == DBConstant.SHOW_IMAGE_TYPE) { + logger.d("pic#resend"); + // 之前的状态是什么 上传没有成功继续上传 + // 上传成功,发送消息 + ImageMessage imageMessage = (ImageMessage) mMsgInfo; + if (TextUtils.isEmpty(imageMessage.getPath())) { + Toast.makeText(ctx, ctx.getString(R.string.image_path_unavaluable), Toast.LENGTH_LONG).show(); + return; + } + } + mMsgInfo.setStatus(MessageConstant.MSG_SENDING); + msgObjectList.remove(mPosition); + addItem(mMsgInfo); + if (imService != null) { + imService.getMessageManager().resendMessage(mMsgInfo); + } + + } catch (Exception e) { + logger.e("chat#exception:" + e.toString()); + } + } + + @Override + public void onSpeakerClick() { + AudioPlayerHandler audioPlayerHandler = AudioPlayerHandler.getInstance(); + if (audioPlayerHandler.getAudioMode(ctx) == AudioManager.MODE_NORMAL) { + audioPlayerHandler.setAudioMode(AudioManager.MODE_IN_CALL, ctx); + SpeekerToast.show(ctx, ctx.getText(R.string.audio_in_call), Toast.LENGTH_SHORT); + } else { + audioPlayerHandler.setAudioMode(AudioManager.MODE_NORMAL, ctx); + SpeekerToast.show(ctx, ctx.getText(R.string.audio_in_speeker), Toast.LENGTH_SHORT); + } + } + } +} diff --git a/android/app/src/main/java/com/mogujie/tt/ui/adapter/SearchAdapter.java b/android/app/src/main/java/com/mogujie/tt/ui/adapter/SearchAdapter.java new file mode 100644 index 000000000..ec74894d3 --- /dev/null +++ b/android/app/src/main/java/com/mogujie/tt/ui/adapter/SearchAdapter.java @@ -0,0 +1,415 @@ +package com.mogujie.tt.ui.adapter; + +import android.content.Context; +import android.content.Intent; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.AdapterView; +import android.widget.BaseAdapter; +import android.widget.TextView; + +import com.mogujie.tt.DB.entity.DepartmentEntity; +import com.mogujie.tt.DB.entity.GroupEntity; +import com.mogujie.tt.DB.entity.UserEntity; +import com.mogujie.tt.R; +import com.mogujie.tt.config.DBConstant; +import com.mogujie.tt.config.IntentConstant; +import com.mogujie.tt.config.SysConstant; +import com.mogujie.tt.imservice.service.IMService; +import com.mogujie.tt.ui.activity.MainActivity; +import com.mogujie.tt.ui.widget.IMBaseImageView; +import com.mogujie.tt.ui.widget.IMGroupAvatar; +import com.mogujie.tt.utils.IMUIHelper; +import com.mogujie.tt.utils.Logger; +import com.mogujie.tt.utils.ScreenUtil; + +import java.util.ArrayList; +import java.util.List; +import java.util.Set; + +/** + * @author : yingmu on 15-3-18. + * @email : yingmu@mogujie.com. + * + * 列表的顺序是: 用户-->群组-->部门 + */ +public class SearchAdapter extends BaseAdapter implements + AdapterView.OnItemClickListener, + AdapterView.OnItemLongClickListener{ + + private Logger logger = Logger.getLogger(SearchAdapter.class); + + private List userList = new ArrayList<>(); + private List deptList = new ArrayList<>(); + private List groupList = new ArrayList<>(); + + private String searchKey; + private Context ctx; + private IMService imService; + public SearchAdapter(Context context,IMService pimService){ + this.ctx = context; + this.imService = pimService; + } + + public void clear(){ + this.userList.clear(); + this.groupList.clear(); + this.deptList.clear(); + notifyDataSetChanged(); + } + + public void putUserList(List pUserList){ + this.userList.clear(); + if(pUserList == null || pUserList.size() <=0){ + return; + } + this.userList = pUserList; + } + + public void putGroupList(List pGroupList){ + this.groupList.clear(); + if(pGroupList == null || pGroupList.size() <=0){ + return; + } + this.groupList = pGroupList; + } + + public void putDeptList(List pDeptList){ + this.deptList.clear(); + if(pDeptList == null || pDeptList.size() <=0){ + return; + } + this.deptList = pDeptList; + } + + @Override + public void onItemClick(AdapterView parent, View view, int position, long id) { + Object object = getItem(position); + if(object instanceof UserEntity){ + UserEntity userEntity = (UserEntity) object; + IMUIHelper.openChatActivity(ctx, userEntity.getSessionKey()); + }else if(object instanceof GroupEntity){ + GroupEntity groupEntity = (GroupEntity) object; + IMUIHelper.openChatActivity(ctx, groupEntity.getSessionKey()); + }else if(object instanceof DepartmentEntity){ + // 定位 + DepartmentEntity department = (DepartmentEntity) object; + locateDepartment(ctx, department); + }else{ + + } + } + + private void locateDepartment(Context ctx, DepartmentEntity department) { + Intent intent = new Intent(ctx, MainActivity.class); + intent.putExtra(IntentConstant.KEY_LOCATE_DEPARTMENT, department.getDepartId()); + ctx.startActivity(intent); + } + + @Override + public boolean onItemLongClick(AdapterView parent, View view, int position, long id) { + Object object = getItem(position); + if(object instanceof UserEntity){ + UserEntity userEntity = (UserEntity) object; + IMUIHelper.handleContactItemLongClick(userEntity, ctx); + }else{ + } + return true; + } + + @Override + public int getItemViewType(int position) { + // 根据entity的类型进行判断, 或者根据长度判断 + int userSize = userList==null?0:userList.size(); + int groupSize = groupList==null?0:groupList.size(); + int deptSize = deptList==null?0:deptList.size(); + + if(position < userSize){ + return SearchType.USER.ordinal(); + }else if(position < userSize + groupSize){ + return SearchType.GROUP.ordinal(); + }else{ + return SearchType.DEPT.ordinal(); + } + } + + @Override + public int getViewTypeCount() { + return SearchType.values().length; + } + + @Override + public int getCount() { + // todo Elegant code + int groupSize = groupList==null?0:groupList.size(); + int userSize = userList==null?0:userList.size(); + int deptSize = deptList==null?0:deptList.size(); + int sum = groupSize + userSize + deptSize; + return sum; + } + + @Override + public Object getItem(int position) { + int typeIndex = getItemViewType(position); + SearchType renderType = SearchType.values()[typeIndex]; + switch (renderType){ + case USER:{ + return userList.get(position); + } + case GROUP:{ + int userSize = userList==null?0:userList.size(); + int realIndex = position - userSize; + if(realIndex < 0){ + throw new IllegalArgumentException("SearchAdapter#getItem#group类型判断错误"); + } + return groupList.get(realIndex); + } + case DEPT:{ + int userSize = userList==null?0:userList.size(); + int groupSize = groupList==null?0:groupList.size(); + + int realIndex = position - userSize - groupSize; + if(realIndex < 0){ + throw new IllegalArgumentException("SearchAdapter#getItem#group类型判断错误"); + } + return deptList.get(realIndex); + } + + default: + throw new IllegalArgumentException("SearchAdapter#getItem#不存在的类型" + renderType.name()); + } + } + + + @Override + public long getItemId(int position) { + return position; + } + + @Override + public View getView(int position, View convertView, ViewGroup parent) { + int typeIndex = getItemViewType(position); + SearchType renderType = SearchType.values()[typeIndex]; + View view = null; + switch (renderType){ + case USER:{ + view = renderUser(position,convertView,parent); + } + break; + case GROUP:{ + view = renderGroup(position,convertView,parent); + } + break; + case DEPT:{ + view = renderDept(position, convertView, parent); + } + break; + } + return view; + } + + public View renderUser(int position, View view, ViewGroup parent){ + UserHolder userHolder = null; + UserEntity userEntity= (UserEntity)getItem(position); + if(userEntity == null){ + logger.e("SearchAdapter#renderUser#userEntity is null!position:%d",position); + return null; + } + if (view == null) { + userHolder = new UserHolder(); + view = LayoutInflater.from(ctx).inflate(R.layout.tt_item_contact, parent,false); + userHolder.nameView = (TextView) view.findViewById(R.id.contact_item_title); + userHolder.realNameView = (TextView) view.findViewById(R.id.contact_realname_title); + userHolder.sectionView = (TextView) view.findViewById(R.id.contact_category_title); + userHolder.avatar = (IMBaseImageView)view.findViewById(R.id.contact_portrait); + userHolder.divider = view.findViewById(R.id.contact_divider); + view.setTag(userHolder); + } else { + userHolder = (UserHolder) view.getTag(); + } + + IMUIHelper.setTextHilighted(userHolder.nameView,userEntity.getMainName(),userEntity.getSearchElement()); + //userHolder.nameView.setText(userEntity.getNickName()); + + userHolder.avatar.setImageResource(R.drawable.tt_default_user_portrait_corner); + userHolder.divider.setVisibility(View.VISIBLE); + + // 分栏显示“联系人” + if (position == 0) { + userHolder.sectionView.setVisibility(View.VISIBLE); + userHolder.sectionView.setText(ctx.getString(R.string.contact)); + + //分栏已经显示,最上面的分割线不用显示 + userHolder.divider.setVisibility(View.GONE); + }else{ + userHolder.sectionView.setVisibility(View.GONE); + userHolder.divider.setVisibility(View.VISIBLE); + } + + userHolder.avatar.setDefaultImageRes(R.drawable.tt_default_user_portrait_corner); + userHolder.avatar.setCorner(0); + userHolder.avatar.setAvatarAppend(SysConstant.AVATAR_APPEND_100); + userHolder.avatar.setImageUrl(userEntity.getAvatar()); + + userHolder.realNameView.setText(userEntity.getRealName()); + userHolder.realNameView.setVisibility(View.GONE); + return view; + } + + public View renderGroup(int position, View view, ViewGroup parent){ + GroupHolder groupHolder = null; + GroupEntity groupEntity = (GroupEntity) getItem(position); + if(groupEntity == null){ + logger.e("SearchAdapter#renderGroup#groupEntity is null!position:%d",position); + return null; + } + if (view == null) { + groupHolder = new GroupHolder(); + view = LayoutInflater.from(ctx).inflate(R.layout.tt_item_contact_group, parent,false); + groupHolder.nameView = (TextView) view.findViewById(R.id.contact_item_title); + groupHolder.sectionView = (TextView) view.findViewById(R.id.contact_category_title); + groupHolder.avatar = (IMGroupAvatar)view.findViewById(R.id.contact_portrait); + groupHolder.divider = view.findViewById(R.id.contact_divider); + view.setTag(groupHolder); + } else { + groupHolder = (GroupHolder) view.getTag(); + } + + //groupHolder.nameView.setText(groupEntity.getGroupName()); + IMUIHelper.setTextHilighted(groupHolder.nameView,groupEntity.getMainName(),groupEntity.getSearchElement()); + + groupHolder.sectionView.setVisibility(View.GONE); + // 分割线的处理【位于控件的最上面】 + groupHolder.divider.setVisibility(View.VISIBLE); + + // 分栏显示“群或讨论组” + int userSize = userList==null?0:userList.size(); + if (position == userSize) { + groupHolder.sectionView.setVisibility(View.VISIBLE); + groupHolder.sectionView.setText(ctx.getString(R.string.fixed_group_or_temp_group)); + //分栏已经显示,最上面的分割线不用显示 + groupHolder.divider.setVisibility(View.GONE); + }else{ + groupHolder.sectionView.setVisibility(View.GONE); + } + + groupHolder.avatar.setVisibility(View.VISIBLE); + List avatarUrlList = new ArrayList<>(); + Set userIds = groupEntity.getlistGroupMemberIds(); + int i = 0; + for(Integer buddyId:userIds){ + UserEntity entity = imService.getContactManager().findContact(buddyId); + if (entity == null) { + //logger.d("已经离职。userId:%d", buddyId); + continue; + } + avatarUrlList.add(entity.getAvatar()); + if (i >= 3) { + break; + } + i++; + } + setGroupAvatar(groupHolder.avatar,avatarUrlList); + return view; + } + + public View renderDept(int position, View view, ViewGroup parent){ + DeptHolder deptHolder = null; + DepartmentEntity deptEntity= (DepartmentEntity)getItem(position); + if(deptEntity == null){ + logger.e("SearchAdapter#renderDept#deptEntity is null!position:%d",position); + return null; + } + if (view == null) { + deptHolder = new DeptHolder(); + view = LayoutInflater.from(ctx).inflate(R.layout.tt_item_contact, parent,false); + deptHolder.avatar = (IMBaseImageView)view.findViewById(R.id.contact_portrait); + deptHolder.nameView = (TextView) view.findViewById(R.id.contact_item_title); + deptHolder.sectionView = (TextView) view.findViewById(R.id.contact_category_title); + deptHolder.divider = view.findViewById(R.id.contact_divider); + view.setTag(deptHolder); + } else { + deptHolder = (DeptHolder) view.getTag(); + } + deptHolder.avatar.setVisibility(View.INVISIBLE); + //deptHolder.nameView.setText(deptEntity.getDepartName()); + IMUIHelper.setTextHilighted(deptHolder.nameView,deptEntity.getDepartName(),deptEntity.getSearchElement()); + deptHolder.divider.setVisibility(View.VISIBLE); + + // 分栏信息的展示 可以保存结果,优化 + int groupSize = groupList==null?0:groupList.size(); + int userSize = userList==null?0:userList.size(); + int realIndex = position - groupSize - userSize; + if (realIndex == 0) { + deptHolder.sectionView.setVisibility(View.VISIBLE); + deptHolder.sectionView.setText(ctx.getString(R.string.department)); + + //分栏已经显示,最上面的分割线不用显示 + deptHolder.divider.setVisibility(View.GONE); + }else{ + deptHolder.sectionView.setVisibility(View.GONE); + } + return view; + } + + + /** + * 与contactAdapter 有公用的地方,可以抽取到IMUIHelper + * 设置群头像 + * @param avatar + * @param avatarUrlList + */ + private void setGroupAvatar(IMGroupAvatar avatar,List avatarUrlList){ + try { + avatar.setViewSize(ScreenUtil.instance(ctx).dip2px(38)); + avatar.setChildCorner(2); + avatar.setAvatarUrlAppend(SysConstant.AVATAR_APPEND_32); + avatar.setParentPadding(3); + avatar.setAvatarUrls((ArrayList) avatarUrlList); + }catch (Exception e){ + logger.e(e.toString()); + } + } + + + + // 将分割线放在上面,利于判断 + public static class UserHolder { + View divider; + TextView sectionView; + TextView nameView; + TextView realNameView; + IMBaseImageView avatar; + } + + public static class DeptHolder { + View divider; + TextView sectionView; + TextView nameView; + IMBaseImageView avatar; + } + + public static class GroupHolder { + View divider; + TextView sectionView; + TextView nameView; + IMGroupAvatar avatar; + } + + private enum SearchType{ + USER, + GROUP, + DEPT, + ILLEGAL + } + + /**---------------------------set/get--------------------------*/ + public String getSearchKey() { + return searchKey; + } + + public void setSearchKey(String searchKey) { + this.searchKey = searchKey; + } +} diff --git a/android/app/src/main/java/com/mogujie/tt/ui/adapter/ViewPageAdapter.java b/android/app/src/main/java/com/mogujie/tt/ui/adapter/ViewPageAdapter.java new file mode 100644 index 000000000..4395da897 --- /dev/null +++ b/android/app/src/main/java/com/mogujie/tt/ui/adapter/ViewPageAdapter.java @@ -0,0 +1,54 @@ + +package com.mogujie.tt.ui.adapter; + +import android.support.v4.view.PagerAdapter; +import android.view.View; +import android.view.ViewGroup; +import android.widget.GridView; +import com.mogujie.tt.utils.Logger; +import java.util.List; + +public class ViewPageAdapter extends PagerAdapter { + private List mListViews; + private Logger logger = Logger.getLogger(ViewPageAdapter.class); + + public ViewPageAdapter(List mListViews) { + this.mListViews = mListViews;// 构造方法,参数是我们的页卡,这样比较方便。 + } + + @Override + public int getCount() { + return mListViews.size();// 返回页卡的数量 + } + + @Override + public int getItemPosition(Object object) { + return super.getItemPosition(object); + } + + @Override + public void destroyItem(ViewGroup container, int position, Object object) { + try { + container.removeView(mListViews.get(position));// 删除页卡 + } catch (Exception e) { + logger.e(e.getMessage()); + } + } + + @Override + public Object instantiateItem(ViewGroup container, int position) { + try { + container.addView(mListViews.get(position), 0);// 添加页卡 + return mListViews.get(position); + } catch (Exception e) { + logger.e(e.getMessage()); + return null; + } + } + + @Override + public boolean isViewFromObject(View arg0, Object arg1) { + return arg0 == arg1;// 官方建议这样写 + } + +} diff --git a/android/app/src/main/java/com/mogujie/tt/ui/adapter/YayaEmoGridViewAdapter.java b/android/app/src/main/java/com/mogujie/tt/ui/adapter/YayaEmoGridViewAdapter.java new file mode 100644 index 000000000..82b373b82 --- /dev/null +++ b/android/app/src/main/java/com/mogujie/tt/ui/adapter/YayaEmoGridViewAdapter.java @@ -0,0 +1,105 @@ + +package com.mogujie.tt.ui.adapter; + +import android.content.Context; +import android.graphics.Bitmap; +import android.graphics.BitmapFactory; +import android.view.Gravity; +import android.view.View; +import android.view.ViewGroup; +import android.widget.AbsListView.LayoutParams; +import android.widget.BaseAdapter; +import android.widget.ImageView; +import android.widget.LinearLayout; + +import com.mogujie.tt.utils.Logger; + +/** + * @Description 牙牙表情 + * @author fengzi / zhujian + * @date 2015-1-1 + */ +public class YayaEmoGridViewAdapter extends BaseAdapter { + private Context context = null; + private int[] emoResIds = null; + private static Logger logger = Logger.getLogger(YayaEmoGridViewAdapter.class); + + public YayaEmoGridViewAdapter(Context cxt, int[] ids) { + this.context = cxt; + this.emoResIds = ids; + } + + @Override + public int getCount() { + return emoResIds.length; + } + + @Override + public Object getItem(int position) { + return emoResIds[position]; + } + + @Override + public long getItemId(int position) { + return emoResIds[position]; + } + + @Override + public View getView(int position, View convertView, ViewGroup parent) { + try { + GridViewHolder gridViewHolder = null; + if (null == convertView && null != context) { + gridViewHolder = new GridViewHolder(); + convertView = gridViewHolder.layoutView; + if (convertView != null) { + convertView.setTag(gridViewHolder); + } + } else { + gridViewHolder = (GridViewHolder) convertView.getTag(); + } + if (null == gridViewHolder || null == convertView) { + return null; + } + gridViewHolder.faceIv.setImageBitmap(getBitmap(position)); + return convertView; + } catch (Exception e) { + logger.e(e.getMessage()); + return null; + } + } + + private Bitmap getBitmap(int position) { + Bitmap bitmap = null; + try { + bitmap = BitmapFactory.decodeResource(context.getResources(), + emoResIds[position]); + } catch (Exception e) { + logger.e(e.getMessage()); + } + return bitmap; + } + + public class GridViewHolder { + public LinearLayout layoutView; + public ImageView faceIv; + + public GridViewHolder() { + try { + LayoutParams layoutParams = new LayoutParams( + LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT); + layoutView = new LinearLayout(context); + faceIv = new ImageView(context); + layoutView.setLayoutParams(layoutParams); + layoutView.setOrientation(LinearLayout.VERTICAL); + layoutView.setGravity(Gravity.CENTER); + LinearLayout.LayoutParams params = new LinearLayout.LayoutParams( + 105, + 115); + params.gravity = Gravity.CENTER; + layoutView.addView(faceIv, params); + } catch (Exception e) { + logger.e(e.getMessage()); + } + } + } +} diff --git a/android/app/src/main/java/com/mogujie/tt/ui/adapter/album/AlbumHelper.java b/android/app/src/main/java/com/mogujie/tt/ui/adapter/album/AlbumHelper.java new file mode 100644 index 000000000..28849b3d1 --- /dev/null +++ b/android/app/src/main/java/com/mogujie/tt/ui/adapter/album/AlbumHelper.java @@ -0,0 +1,367 @@ + +package com.mogujie.tt.ui.adapter.album; + +import android.content.ContentResolver; +import android.content.Context; +import android.database.Cursor; +import android.provider.MediaStore.Audio.Albums; +import android.provider.MediaStore.Images.Media; +import android.provider.MediaStore.Images.Thumbnails; + +import com.mogujie.tt.utils.Logger; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.Comparator; +import java.util.HashMap; +import java.util.Iterator; +import java.util.List; +import java.util.Map; +import java.util.Map.Entry; + +/** + * @Description 相册相关处理 + * @author Nana + * @date 2014-5-6 + */ +public class AlbumHelper { + Context context = null; + ContentResolver contentResolver = null; + + // 缩略图列表 + HashMap thumbnailList = new HashMap(); + List> albumList = new ArrayList>(); + HashMap bucketList = new HashMap(); + private Logger logger = Logger.getLogger(AlbumHelper.class); + + private static AlbumHelper instance = null; + + private AlbumHelper(Context cxt) { + if (null == this.context && null != cxt) { + this.context = cxt; + contentResolver = context.getContentResolver(); + } + } + + public static AlbumHelper getHelper(Context cxt) { + if (null == instance) { + instance = new AlbumHelper(cxt); + } + return instance; + } + + /** + * 得到缩略图 + */ + private void getThumbnail() { + String[] projection = { + Thumbnails._ID, Thumbnails.IMAGE_ID, + Thumbnails.DATA + }; + Cursor cursor = null; + try { + cursor = contentResolver.query(Thumbnails.EXTERNAL_CONTENT_URI, + projection, null, null, null); + getThumbnailColumnData(cursor); + } catch (Exception e) { + logger.e(e.getMessage()); + } finally { + if (null != cursor) { + cursor.close(); + } + } + } + + /** + * 从数据库中得到缩略图 + * + * @param cur + */ + private void getThumbnailColumnData(Cursor cur) { + try { + if (null == cur) + return; + if (cur.moveToFirst()) { + @SuppressWarnings("unused") + int cId; + int image_id; + String image_path; + int _idColumn = cur.getColumnIndex(Thumbnails._ID); + int image_idColumn = cur.getColumnIndex(Thumbnails.IMAGE_ID); + int dataColumn = cur.getColumnIndex(Thumbnails.DATA); + + do { + cId = cur.getInt(_idColumn); + image_id = cur.getInt(image_idColumn); + image_path = cur.getString(dataColumn); + thumbnailList.put("" + image_id, image_path); + } while (cur.moveToNext()); + } + } catch (Exception e) { + logger.e(e.getMessage()); + } + } + + /** + * @Description 得到原图 + */ + @SuppressWarnings("unused") + private void getAlbum() { + String[] projection = { + Albums._ID, Albums.ALBUM, Albums.ALBUM_ART, + Albums.ALBUM_KEY, Albums.ARTIST, Albums.NUMBER_OF_SONGS + }; + Cursor cursor = null; + try { + cursor = contentResolver.query(Albums.EXTERNAL_CONTENT_URI, + projection, null, null, null); + getAlbumColumnData(cursor); + } catch (Exception e) { + logger.e(e.getMessage()); + } finally { + if (null != cursor) { + cursor.close(); + } + } + + } + + /** + * 从数据库中得到原图 + * + * @param cur + */ + private void getAlbumColumnData(Cursor cur) { + try { + if (cur.moveToFirst()) { + int _id; + String album; + String albumArt; + String albumKey; + String artist; + int numOfSongs; + + int _idColumn = cur.getColumnIndex(Albums._ID); + int albumColumn = cur.getColumnIndex(Albums.ALBUM); + int albumArtColumn = cur.getColumnIndex(Albums.ALBUM_ART); + int albumKeyColumn = cur.getColumnIndex(Albums.ALBUM_KEY); + int artistColumn = cur.getColumnIndex(Albums.ARTIST); + int numOfSongsColumn = cur.getColumnIndex(Albums.NUMBER_OF_SONGS); + + do { + _id = cur.getInt(_idColumn); + album = cur.getString(albumColumn); + albumArt = cur.getString(albumArtColumn); + albumKey = cur.getString(albumKeyColumn); + artist = cur.getString(artistColumn); + numOfSongs = cur.getInt(numOfSongsColumn); + HashMap hash = new HashMap(); + hash.put("_id", _id + ""); + hash.put("album", album); + hash.put("albumArt", albumArt); + hash.put("albumKey", albumKey); + hash.put("artist", artist); + hash.put("numOfSongs", numOfSongs + ""); + albumList.add(hash); + } while (cur.moveToNext()); + + } + } catch (Exception e) { + logger.e(e.getMessage()); + } + } + + // 是否创建图片集 + boolean hasBuildImagesBucketList = false; + + /** + * @Description 获取图片集 + */ + private void buildImagesBucketList() { + bucketList.clear(); + Cursor cur = null; + // long startTime = System.currentTimeMillis(); + try { + // 构造缩略图索引 + getThumbnail(); + + // 构造相册索引 + String columns[] = new String[] { + Media._ID, Media.BUCKET_ID, + Media.PICASA_ID, Media.DATA, Media.DISPLAY_NAME, Media.TITLE, + Media.SIZE, Media.BUCKET_DISPLAY_NAME + }; + + // 得到一个游标 + cur = contentResolver.query(Media.EXTERNAL_CONTENT_URI, columns, + null, null, null); + if (null == cur) + return; + + if (cur.moveToFirst()) { + // 获取指定列的索引 + int photoIDIndex = cur.getColumnIndexOrThrow(Media._ID); + int photoPathIndex = cur.getColumnIndexOrThrow(Media.DATA); + // int photoNameIndex = + // cur.getColumnIndexOrThrow(Media.DISPLAY_NAME); + // int photoTitleIndex = cur.getColumnIndexOrThrow(Media.TITLE); + // int photoSizeIndex = cur.getColumnIndexOrThrow(Media.SIZE); + int bucketDisplayNameIndex = cur + .getColumnIndexOrThrow(Media.BUCKET_DISPLAY_NAME); + int bucketIdIndex = cur.getColumnIndexOrThrow(Media.BUCKET_ID); + // int picasaIdIndex = + // cur.getColumnIndexOrThrow(Media.PICASA_ID); + // 获取图片总数 + @SuppressWarnings("unused") + int totalNum = cur.getCount(); + + do { + String id = cur.getString(photoIDIndex); + // String name = cur.getString(photoNameIndex); + String path = cur.getString(photoPathIndex); + // String title = cur.getString(photoTitleIndex); + // String size = cur.getString(photoSizeIndex); + String bucketName = cur.getString(bucketDisplayNameIndex); + String bucketId = cur.getString(bucketIdIndex); + // String picasaId = cur.getString(picasaIdIndex); + + ImageBucket bucket = bucketList.get(bucketId); + if (bucket == null) { + bucket = new ImageBucket(); + bucketList.put(bucketId, bucket); + bucket.imageList = new ArrayList(); + bucket.bucketName = bucketName; + } + bucket.count++; + ImageItem imageItem = new ImageItem(); + imageItem.setImageId(id); + imageItem.setImagePath(path); + imageItem.setThumbnailPath(thumbnailList.get(id)); + bucket.imageList.add(0, imageItem); + + } while (cur.moveToNext()); + } + } catch (Exception e) { + logger.e(e.getMessage()); + } finally { + cur.close(); + } + + try { + Iterator> itr = bucketList.entrySet() + .iterator(); + while (itr.hasNext()) { + Map.Entry entry = (Map.Entry) itr + .next(); + ImageBucket bucket = entry.getValue(); + for (int i = 0; i < bucket.imageList.size(); ++i) { + @SuppressWarnings("unused") + ImageItem image = bucket.imageList.get(i); + } + } + hasBuildImagesBucketList = true; + } catch (Exception e) { + logger.e(e.getMessage()); + } + } + + /** + * 得到图片集 + * @param refresh + * @return + */ + public List getImagesBucketList(boolean refresh) { + try { + if (refresh || (!refresh && !hasBuildImagesBucketList)) { + buildImagesBucketList(); + } + List imageList = new ArrayList(bucketList.values()); + Collections.sort(imageList, new Comparator() { + + @Override + public int compare(ImageBucket lhs, ImageBucket rhs) { +// logger.d("pic#photo set name:%s", lhs.bucketName); + boolean lhsDefaultCameraSet = probablyDefaultCameraPhotoSet(lhs.bucketName); + boolean rhsDefaultCameraSet = probablyDefaultCameraPhotoSet(rhs.bucketName); + + logger.d("pic#name:%s, lhsDefaultCameraSet:%s", lhs.bucketName, lhsDefaultCameraSet); + logger.d("pic#name:%s, rhsDefaultCameraSet:%s", rhs.bucketName, rhsDefaultCameraSet); + + if (lhsDefaultCameraSet && !rhsDefaultCameraSet) { + return -1; + } + + if (rhsDefaultCameraSet && !lhsDefaultCameraSet) { + return 1; + } + + return Integer.valueOf(rhs.count).compareTo(Integer.valueOf(lhs.count)); + } + }); + + return imageList; +// List tmpList = new ArrayList(); +// Iterator> itr = bucketList.entrySet() +// .iterator(); +// while (itr.hasNext()) { +// Map.Entry entry = (Map.Entry) itr +// .next(); +// ImageBucket bucket = entry.getValue(); +// if (bucket.bucketName.equals("Camera")) { +// tmpList.onAddMsg(0, bucket); +// } else { +// tmpList.onAddMsg(bucket); +// } +// } +// return tmpList; + } catch (Exception e) { + logger.e(e.getMessage()); + return null; + } + } + + boolean probablyDefaultCameraPhotoSet(String photoSetName) { + //from my test result, different phones use different names to represent + //default photo set + if (photoSetName == null || photoSetName.isEmpty()) { + return false; + } + + String lowerCaseName = photoSetName.toLowerCase(); + + //todo eric i18n + return lowerCaseName.contains("camera") || lowerCaseName.contains("相机"); + } + + /** + * 得到原始图像路径 + * + * @param image_id + * @return + */ + @SuppressWarnings("unused") + private String getOriginalImagePath(String image_id) { + try { + String path = null; + String[] projection = { + Media._ID, Media.DATA + }; + Cursor cursor = contentResolver.query(Media.EXTERNAL_CONTENT_URI, + projection, Media._ID + "=" + image_id, null, null); + if (cursor != null) { + try { + cursor.moveToFirst(); + path = cursor.getString(cursor.getColumnIndex(Media.DATA)); + } catch (Exception e) { + } finally { + cursor.close(); + } + } + return path; + } catch (Exception e) { + logger.e(e.getMessage()); + return null; + } + } + +} diff --git a/android/app/src/main/java/com/mogujie/tt/ui/adapter/album/BitmapCache.java b/android/app/src/main/java/com/mogujie/tt/ui/adapter/album/BitmapCache.java new file mode 100644 index 000000000..d960bf86e --- /dev/null +++ b/android/app/src/main/java/com/mogujie/tt/ui/adapter/album/BitmapCache.java @@ -0,0 +1,182 @@ + +package com.mogujie.tt.ui.adapter.album; + +import android.app.Activity; +import android.graphics.Bitmap; +import android.graphics.BitmapFactory; +import android.os.Handler; +import android.text.TextUtils; +import android.widget.ImageView; + +import com.mogujie.tt.ui.activity.PickPhotoActivity; +import com.mogujie.tt.utils.Logger; + +import java.io.BufferedInputStream; +import java.io.File; +import java.io.FileInputStream; +import java.io.IOException; +import java.lang.ref.SoftReference; +import java.util.HashMap; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; + +/** + * @Description 相册图片缓存 + * @author Nana + * @date 2014-5-9 + */ +public class BitmapCache extends Activity { + + public Handler handler = new Handler(); + public final String TAG = getClass().getSimpleName(); + private static HashMap> imageCache = new HashMap>(); + int threadCount = Runtime.getRuntime().availableProcessors(); + ExecutorService executorService = Executors + .newFixedThreadPool(threadCount + 1); + + private static BitmapCache instance = null; + + private Logger logger = Logger.getLogger(BitmapCache.class); + + public static synchronized BitmapCache getInstance() { + if (null == instance) { + instance = new BitmapCache(); + } + return instance; + } + + private BitmapCache() { + } + + private void put(String path, Bitmap bmp) { + if (!TextUtils.isEmpty(path) && null != bmp) { + imageCache.put(path, new SoftReference(bmp)); + } + } + + public Bitmap getCacheBitmap(String thumbPath, String sourcePath) { + try { + if (TextUtils.isEmpty(thumbPath) && TextUtils.isEmpty(sourcePath)) { + return null; + } + + final String path; + if (!TextUtils.isEmpty(thumbPath)) { + path = thumbPath; + } else if (!TextUtils.isEmpty(sourcePath)) { + path = sourcePath; + } else { + return null; + } + + if (imageCache.containsKey(path)) { + SoftReference reference = imageCache.get(path); + Bitmap bmp = reference.get(); + return bmp; + } + return null; + } catch (Exception e) { + logger.e(e.getMessage()); + return null; + } + } + + public void displayBmp(final ImageView iv, final String thumbPath, + final String sourcePath, final ImageCallback callback) { + try { + if (TextUtils.isEmpty(thumbPath) && TextUtils.isEmpty(sourcePath)) { + return; + } + + final String path; + final boolean isThumbPath; + if (!TextUtils.isEmpty(thumbPath)) { + path = thumbPath; + isThumbPath = true; + } else if (!TextUtils.isEmpty(sourcePath)) { + path = sourcePath; + isThumbPath = false; + } else { + return; + } + + iv.setImageBitmap(null); + + Runnable calculateBitmapWorker = new Runnable() { + @Override + public void run() { + Bitmap thumb = null; + try { + if (isThumbPath) { + thumb = BitmapFactory.decodeFile(thumbPath); + if (null == thumb) { + thumb = revitionImageSize(sourcePath); + } + } else { + thumb = revitionImageSize(sourcePath); + } + } catch (Exception e) { + + } + if (null == thumb) { + thumb = PickPhotoActivity.bimap; + } + put(path, thumb); + final Bitmap bmpToCallback = thumb; + if (null != callback) { + handler.post(new Runnable() { + @Override + public void run() { + callback.imageLoad(iv, bmpToCallback, sourcePath); + } + }); + } + } + }; + + executorService.execute(calculateBitmapWorker); + } catch (Exception e) { + logger.e(e.getMessage()); + } + } + + public Bitmap revitionImageSize(String path) throws IOException { + BufferedInputStream in = null; + try { + in = new BufferedInputStream(new FileInputStream(new File(path))); + BitmapFactory.Options options = new BitmapFactory.Options(); + options.inJustDecodeBounds = true; + BitmapFactory.decodeStream(in, null, options); + in.close(); + in = null; + int i = 0; + Bitmap bitmap = null; + while (true) { + if ((options.outWidth >> i <= 256) + && (options.outHeight >> i <= 256)) { + in = new BufferedInputStream(new FileInputStream(new File( + path))); + options.inSampleSize = (int) Math.pow(2.0D, i); + options.inJustDecodeBounds = false; + bitmap = BitmapFactory.decodeStream(in, null, options); + break; + } + i += 1; + } + return bitmap; + } catch (Exception e) { + logger.e(e.getMessage()); + return null; + } finally { + if (null != in) { + in.close(); + in = null; + } + } + } + + public interface ImageCallback { + public void imageLoad(ImageView imageView, Bitmap bitmap, + Object... params); + } +} diff --git a/android/app/src/main/java/com/mogujie/tt/ui/adapter/album/ImageBucket.java b/android/app/src/main/java/com/mogujie/tt/ui/adapter/album/ImageBucket.java new file mode 100644 index 000000000..c983f1eba --- /dev/null +++ b/android/app/src/main/java/com/mogujie/tt/ui/adapter/album/ImageBucket.java @@ -0,0 +1,16 @@ + +package com.mogujie.tt.ui.adapter.album; + +import java.util.List; + +/** + * @Description 相册数据体 + * @author Nana + * @date 2014-5-9 + */ +public class ImageBucket { + public int count = 0; + public String bucketName; + public List imageList; + +} diff --git a/android/app/src/main/java/com/mogujie/tt/ui/adapter/album/ImageBucketAdapter.java b/android/app/src/main/java/com/mogujie/tt/ui/adapter/album/ImageBucketAdapter.java new file mode 100644 index 000000000..b074cc2b7 --- /dev/null +++ b/android/app/src/main/java/com/mogujie/tt/ui/adapter/album/ImageBucketAdapter.java @@ -0,0 +1,142 @@ + +package com.mogujie.tt.ui.adapter.album; + +import android.app.Activity; +import android.graphics.Bitmap; +import android.graphics.Color; +import android.view.View; +import android.view.ViewGroup; +import android.widget.BaseAdapter; +import android.widget.ImageView; +import android.widget.TextView; + +import com.mogujie.tt.R; +import com.mogujie.tt.ui.adapter.album.BitmapCache.ImageCallback; +import com.mogujie.tt.utils.Logger; + +import java.util.List; + +/** + * @Description 相册适配器 + * @author Nana + * @date 2014-5-9 + */ +public class ImageBucketAdapter extends BaseAdapter { + + private Activity act; + private Logger logger = Logger.getLogger(ImageBucketAdapter.class); + public static int selectedPosition = -1; + + // 图片集列表 + List dataList; + BitmapCache cache; + ImageCallback callback = new ImageCallback() { + @Override + public void imageLoad(ImageView imageView, Bitmap bitmap, + Object... params) { + try { + if (null != imageView && null != bitmap) { + String url = (String) params[0]; + if (null != url && url.equals((String) imageView.getTag())) { + ((ImageView) imageView).setImageBitmap(bitmap); + } else { + logger.e("callback, bmp not match"); + } + } else { + logger.e("callback, bmp null"); + } + } catch (Exception e) { + logger.e(e.getMessage()); + } + } + }; + + public ImageBucketAdapter(Activity act, List list) { + this.act = act; + dataList = list; + cache = BitmapCache.getInstance(); + } + + @Override + public int getCount() { + int count = 0; + if (null != dataList) { + count = dataList.size(); + } + return count; + } + + @Override + public Object getItem(int arg0) { + return null; + } + + @Override + public long getItemId(int arg0) { + return arg0; + } + + public void setSelectedPosition(int position) { + selectedPosition = position; + } + + @Override + public View getView(int position, View convertView, ViewGroup parent) { + Holder holder = null; + try { + if (null == convertView) { + holder = new Holder(); + convertView = View.inflate(act, R.layout.tt_item_image_pick, null); + holder.iv = (ImageView) convertView.findViewById(R.id.image); + holder.name = (TextView) convertView.findViewById(R.id.name); + holder.count = (TextView) convertView.findViewById(R.id.count); + holder.albumArrow = (ImageView) convertView + .findViewById(R.id.im_album_arrow); + convertView.setTag(holder); + } else { + holder = (Holder) convertView.getTag(); + } + ImageBucket item = dataList.get(position); + holder.count.setText("(" + item.count + ")"); + String nameStr = item.bucketName; + if (nameStr.length() > 14) { + nameStr = nameStr.substring(0, 14) + "..."; + } + holder.name.setText(nameStr); + if (item.imageList != null && item.imageList.size() > 0) { + String thumbPath = item.imageList.get(0).getThumbnailPath(); + String sourcePath = item.imageList.get(0).getImagePath(); + holder.iv.setTag(sourcePath); + Bitmap bmp = cache.getCacheBitmap(thumbPath, sourcePath); + if (bmp != null) { + holder.iv.setImageBitmap(bmp); + } else { + cache.displayBmp(holder.iv, thumbPath, sourcePath, callback); + } + } else { + holder.iv.setImageBitmap(null); + logger.e("no images in bucket " + item.bucketName); + } + if (position == selectedPosition) { + holder.albumArrow.setImageResource(R.drawable.tt_album_arrow_sel); + holder.name.setTextColor(Color.WHITE); + holder.count.setTextColor(Color.WHITE); + } else { + holder.albumArrow.setImageResource(R.drawable.tt_album_arrow); + holder.name.setTextColor(Color.BLACK); + holder.count.setTextColor(R.color.album_list_item_count_color); + } + return convertView; + } catch (Exception e) { + logger.e(e.getMessage()); + return null; + } + } + + class Holder { + private ImageView iv; + private TextView name; + private TextView count; + private ImageView albumArrow; + } +} diff --git a/android/app/src/main/java/com/mogujie/tt/ui/adapter/album/ImageGridAdapter.java b/android/app/src/main/java/com/mogujie/tt/ui/adapter/album/ImageGridAdapter.java new file mode 100644 index 000000000..8ed233d36 --- /dev/null +++ b/android/app/src/main/java/com/mogujie/tt/ui/adapter/album/ImageGridAdapter.java @@ -0,0 +1,247 @@ + +package com.mogujie.tt.ui.adapter.album; + +import android.app.Activity; +import android.graphics.Bitmap; +import android.os.Handler; +import android.os.Message; +import android.view.View; +import android.view.View.OnClickListener; +import android.view.ViewGroup; +import android.widget.BaseAdapter; +import android.widget.ImageView; +import android.widget.Toast; + +import com.mogujie.tt.R; +import com.mogujie.tt.ui.adapter.album.BitmapCache.ImageCallback; +import com.mogujie.tt.config.SysConstant; +import com.mogujie.tt.ui.activity.PickPhotoActivity; +import com.mogujie.tt.utils.Logger; + +import java.util.List; +import java.util.Map; +import java.util.TreeMap; + +/** + * @Description 图片列表适配器 + * @author Nana + * @date 2014-5-9 + */ +public class ImageGridAdapter extends BaseAdapter { + + private TextCallback textcallback = null; + Activity activity = null; + List dataList = null; + private Map selectedMap = new TreeMap(); + BitmapCache cache = null; + private Handler mHandler = null; + private int selectTotal = 0; + private Logger logger = Logger.getLogger(ImageGridAdapter.class); + private boolean allowLoad = true; + + public void lock() { + this.allowLoad = false; + notifyDataSetChanged(); + } + + public void unlock() { + this.allowLoad = true; + notifyDataSetChanged(); + } + + ImageCallback callback = new ImageCallback() { + @Override + public void imageLoad(ImageView imageView, Bitmap bitmap, + Object... params) { + try { + if (null != imageView && null != bitmap) { + String url = (String) params[0]; + if (null != url && url.equals((String) imageView.getTag())) { + ((ImageView) imageView).setImageBitmap(bitmap); + } else { + logger.e("callback, bmp not match"); + } + } else { + logger.e("callback, bmp null"); + } + } catch (Exception e) { + logger.e(e.getMessage()); + } + } + }; + + public ImageGridAdapter(Activity act, List list, Handler mHandler) { + this.activity = act; + cache = BitmapCache.getInstance(); + this.dataList = list; + this.mHandler = mHandler; + } + + @Override + public int getCount() { + int count = 0; + if (null != dataList) { + count = dataList.size(); + } + return count; + } + + @Override + public Object getItem(int position) { + return null; + } + + @Override + public long getItemId(int position) { + return position; + } + + public void updateSelectedStatus(int position, boolean selected) { + if (null != dataList) { + ImageItem item = dataList.get(position); + item.setSelected(selected); + } + } + + public void setSelectTotalNum(int num) { + selectTotal = num; + } + + public int getSelectTotalNum() { + return selectTotal; + } + + @Override + public View getView(final int position, View convertView, ViewGroup parent) { + Holder holder = null; + try { + if (null == convertView) { + holder = new Holder(); + convertView = View.inflate(activity, R.layout.tt_item_image_grid, + null); + holder.iv = (ImageView) convertView.findViewById(R.id.image); + holder.selected = (ImageView) convertView + .findViewById(R.id.isselected); + convertView.setTag(holder); + } else { + holder = (Holder) convertView.getTag(); + } + + setHolder(holder, position); + + if (getCount() - 1 == position) { + convertView.setPadding(0, 0, 0, 30); + } else { + convertView.setPadding(0, 0, 0, 0); + } + + return convertView; + } catch (Exception e) { + logger.e(e.getMessage()); + return null; + } + } + + private void setHolder(final Holder holder, final int position) { + try { + final ImageItem item = dataList.get(position); + holder.iv.setTag(item.getImagePath()); + + Bitmap bmp = cache.getCacheBitmap(item.getThumbnailPath(), + item.getImagePath()); + if (null != bmp) { + holder.iv.setImageBitmap(bmp); + } else { + if (allowLoad) { + cache.displayBmp(holder.iv, item.getThumbnailPath(), + item.getImagePath(), callback); + } else { + holder.iv + .setImageResource(R.drawable.tt_default_album_grid_image); + } + } + + if (item.isSelected()) { + holder.selected.setImageResource(R.drawable.tt_album_img_selected); + } else { + holder.selected + .setImageResource(R.drawable.tt_album_img_select_nor); + } + holder.iv.setOnClickListener(new OnClickListener() { + + @Override + public void onClick(View v) { + String path = dataList.get(position).getImagePath(); + Bitmap bmp = cache.getCacheBitmap(path, path); + if (null != bmp && bmp == PickPhotoActivity.bimap) { + Toast.makeText( + activity, + activity.getResources().getString( + R.string.unavailable_image_file), + Toast.LENGTH_LONG).show(); + return; + } + if (selectTotal < SysConstant.MAX_SELECT_IMAGE_COUNT) { + item.setSelected(!item.isSelected()); + if (item.isSelected()) { + holder.selected + .setImageResource(R.drawable.tt_album_img_selected); + selectTotal++; + if (null != textcallback) + textcallback.onListen(selectTotal); + selectedMap.put(position, dataList.get(position)); + + } else if (!item.isSelected()) { + holder.selected + .setImageResource(R.drawable.tt_album_img_select_nor); + selectTotal--; + if (null != textcallback) + textcallback.onListen(selectTotal); + selectedMap.remove(position); + } + } else if (selectTotal >= SysConstant.MAX_SELECT_IMAGE_COUNT) { + if (item.isSelected() == true) { + item.setSelected(!item.isSelected()); + holder.selected + .setImageResource(R.drawable.tt_album_img_select_nor); + selectTotal--; + selectedMap.remove(position); + } else { + Message message = Message.obtain(mHandler, 0); + message.sendToTarget(); + } + } + } + + }); + } catch (Exception e) { + logger.e(e.getMessage()); + } + } + + public Map getSelectMap() { + return selectedMap; + } + + public void setSelectMap(Map map) { + if (null == map) { + selectedMap.clear(); + return; + } + selectedMap = map; + } + + public void setTextCallback(TextCallback listener) { + textcallback = listener; + } + + class Holder { + private ImageView iv; + private ImageView selected; + } + + public static interface TextCallback { + public void onListen(int count); + } + +} diff --git a/android/app/src/main/java/com/mogujie/tt/ui/adapter/album/ImageItem.java b/android/app/src/main/java/com/mogujie/tt/ui/adapter/album/ImageItem.java new file mode 100644 index 000000000..308932a83 --- /dev/null +++ b/android/app/src/main/java/com/mogujie/tt/ui/adapter/album/ImageItem.java @@ -0,0 +1,51 @@ + +package com.mogujie.tt.ui.adapter.album; + +import java.io.Serializable; + +/** + * + * @Description 图片对象 + * @author Nana + * @date 2014-5-9 + * + */ +@SuppressWarnings("serial") +public class ImageItem implements Serializable { + private String imageId; + private String thumbnailPath; + private String imagePath; + private boolean isSelected = false; + + public String getImageId() { + return imageId; + } + + public void setImageId(String imageId) { + this.imageId = imageId; + } + + public String getThumbnailPath() { + return thumbnailPath; + } + + public void setThumbnailPath(String thumbnailPath) { + this.thumbnailPath = thumbnailPath; + } + + public String getImagePath() { + return imagePath; + } + + public void setImagePath(String imagePath) { + this.imagePath = imagePath; + } + + public boolean isSelected() { + return isSelected; + } + + public void setSelected(boolean isSelected) { + this.isSelected = isSelected; + } +} diff --git a/android/app/src/main/java/com/mogujie/tt/ui/base/TTBaseActivity.java b/android/app/src/main/java/com/mogujie/tt/ui/base/TTBaseActivity.java new file mode 100644 index 000000000..7fed3616b --- /dev/null +++ b/android/app/src/main/java/com/mogujie/tt/ui/base/TTBaseActivity.java @@ -0,0 +1,102 @@ + +package com.mogujie.tt.ui.base; + +import android.app.Activity; +import android.os.Bundle; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.view.Window; +import android.widget.ImageView; +import android.widget.LinearLayout; +import android.widget.TextView; + +import com.mogujie.tt.R; + +/** + * @Description + * @author Nana + * @date 2014-4-10 + */ +public abstract class TTBaseActivity extends Activity { + protected ImageView topLeftBtn; + protected ImageView topRightBtn; + protected TextView topTitleTxt; + protected TextView letTitleTxt; + protected ViewGroup topBar; + protected ViewGroup topContentView; + protected LinearLayout baseRoot; + protected float x1, y1, x2, y2 = 0; + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + requestWindowFeature(Window.FEATURE_NO_TITLE); + + topContentView = (ViewGroup) LayoutInflater.from(this).inflate( + R.layout.tt_activity_base, null); + topBar = (ViewGroup) topContentView.findViewById(R.id.topbar); + topTitleTxt = (TextView) topContentView.findViewById(R.id.base_activity_title); + topLeftBtn = (ImageView) topContentView.findViewById(R.id.left_btn); + topRightBtn = (ImageView) topContentView.findViewById(R.id.right_btn); + letTitleTxt = (TextView) topContentView.findViewById(R.id.left_txt); + baseRoot = (LinearLayout)topContentView.findViewById(R.id.act_base_root); + + topTitleTxt.setVisibility(View.GONE); + topRightBtn.setVisibility(View.GONE); + letTitleTxt.setVisibility(View.GONE); + topLeftBtn.setVisibility(View.GONE); + + setContentView(topContentView); + } + + protected void setLeftText(String text) { + if (null == text) { + return; + } + letTitleTxt.setText(text); + letTitleTxt.setVisibility(View.VISIBLE); + } + + protected void setTitle(String title) { + if (title == null) { + return; + } + if (title.length() > 12) { + title = title.substring(0, 11) + "..."; + } + topTitleTxt.setText(title); + topTitleTxt.setVisibility(View.VISIBLE); + } + + @Override + public void setTitle(int id) { + String strTitle = getResources().getString(id); + setTitle(strTitle); + } + + protected void setLeftButton(int resID) { + if (resID <= 0) { + return; + } + + topLeftBtn.setImageResource(resID); + topLeftBtn.setVisibility(View.VISIBLE); + } + + protected void setRightButton(int resID) { + if (resID <= 0) { + return; + } + + topRightBtn.setImageResource(resID); + topRightBtn.setVisibility(View.VISIBLE); + } + + protected void setTopBar(int resID) { + if (resID <= 0) { + return; + } + topBar.setBackgroundResource(resID); + } +} diff --git a/android/app/src/main/java/com/mogujie/tt/ui/base/TTBaseFragment.java b/android/app/src/main/java/com/mogujie/tt/ui/base/TTBaseFragment.java new file mode 100644 index 000000000..d09dfc2dd --- /dev/null +++ b/android/app/src/main/java/com/mogujie/tt/ui/base/TTBaseFragment.java @@ -0,0 +1,242 @@ +package com.mogujie.tt.ui.base; + +import android.content.Intent; +import android.os.Bundle; +import android.support.v4.app.Fragment; +import android.text.TextPaint; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.FrameLayout; +import android.widget.ImageView; +import android.widget.LinearLayout; +import android.widget.RelativeLayout; +import android.widget.TextView; + +import com.mogujie.tools.ScreenTools; +import com.mogujie.tt.R; +import com.mogujie.tt.ui.activity.SearchActivity; +import com.mogujie.tt.utils.Logger; +import com.mogujie.tt.ui.widget.SearchEditText; +import com.mogujie.tt.ui.widget.TopTabButton; + +public abstract class TTBaseFragment extends Fragment { + protected ImageView topLeftBtn; + protected ImageView topRightBtn; + protected TextView topTitleTxt; + protected TextView topLetTitleTxt; + protected TextView topRightTitleTxt; + + protected ViewGroup topBar; + protected TopTabButton topContactTitle; + protected SearchEditText topSearchEdt; + protected ViewGroup topContentView; + protected RelativeLayout topLeftContainerLayout; + protected FrameLayout searchFrameLayout; + protected FrameLayout topContactFrame; + + protected float x1, y1, x2, y2 = 0; + protected static Logger logger = Logger.getLogger(TTBaseFragment.class); + + @Override + public void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + + topContentView = (ViewGroup) LayoutInflater.from(getActivity()).inflate(R.layout.tt_fragment_base, null); + + topBar = (ViewGroup) topContentView.findViewById(R.id.topbar); + topTitleTxt = (TextView) topContentView.findViewById(R.id.base_fragment_title); + topLetTitleTxt = (TextView) topContentView.findViewById(R.id.left_txt); + topRightTitleTxt = (TextView) topContentView.findViewById(R.id.right_txt); + topLeftBtn = (ImageView) topContentView.findViewById(R.id.left_btn); + topRightBtn = (ImageView) topContentView.findViewById(R.id.right_btn); + topContactTitle = (TopTabButton) topContentView.findViewById(R.id.contact_tile); + topSearchEdt = (SearchEditText) topContentView.findViewById(R.id.chat_title_search); + topLeftContainerLayout=(RelativeLayout)topContentView.findViewById(R.id.top_left_container); + searchFrameLayout = (FrameLayout)topContentView.findViewById(R.id.searchbar); + topContactFrame = (FrameLayout)topContentView.findViewById(R.id.contactTopBar); + + topTitleTxt.setVisibility(View.GONE); + topRightBtn.setVisibility(View.GONE); + topLeftBtn.setVisibility(View.GONE); + topLetTitleTxt.setVisibility(View.GONE); + topRightTitleTxt.setVisibility(View.GONE); + topContactTitle.setVisibility(View.GONE); + topSearchEdt.setVisibility(View.GONE); + } + + @Override + public View onCreateView(LayoutInflater inflater, ViewGroup vg, + Bundle bundle) { + if (null != topContentView) { + ((ViewGroup) topContentView.getParent()).removeView(topContentView); + return topContentView; + } + return topContentView; + } + + protected void setTopTitleBold(String title) { + if (title == null) { + return; + } + if (title.length() > 12) { + title = title.substring(0, 11) + "..."; + } + // 设置字体为加粗 + TextPaint paint = topTitleTxt.getPaint(); + paint.setFakeBoldText(true); + + topTitleTxt.setText(title); + topTitleTxt.setVisibility(View.VISIBLE); + + } + + protected void setTopTitle(String title) { + if (title == null) { + return; + } + if (title.length() > 12) { + title = title.substring(0, 11) + "..."; + } + topTitleTxt.setText(title); + topTitleTxt.setVisibility(View.VISIBLE); + } + + protected void hideTopTitle() { + topTitleTxt.setVisibility(View.GONE); + } + + protected void showContactTopBar() { + topContactFrame.setVisibility(View.VISIBLE); + topContactTitle.setVisibility(View.VISIBLE); + } + + protected void setTopLeftButton(int resID) { + if (resID <= 0) { + return; + } + + topLeftBtn.setImageResource(resID); + topLeftBtn.setVisibility(View.VISIBLE); + } + + protected void setTopLeftButtonPadding(int l,int t,int r,int b) { + topLeftBtn.setPadding(l,t,r,b); + } + + protected void hideTopLeftButton() { + topLeftBtn.setVisibility(View.GONE); + } + + protected void setTopLeftText(String text) { + if (null == text) { + return; + } + topLetTitleTxt.setText(text); + topLetTitleTxt.setVisibility(View.VISIBLE); + } + + protected void setTopRightText(String text) { + if (null == text) { + return; + } + topRightTitleTxt.setText(text); + topRightTitleTxt.setVisibility(View.VISIBLE); + } + + protected void setTopRightButton(int resID) { + if (resID <= 0) { + return; + } + + topRightBtn.setImageResource(resID); + topRightBtn.setVisibility(View.VISIBLE); + } + + protected void hideTopRightButton() { + topRightBtn.setVisibility(View.GONE); + } + + protected void setTopBar(int resID) { + if (resID <= 0) { + return; + } + topBar.setBackgroundResource(resID); + } + + protected void hideTopBar() + { + topBar.setVisibility(View.GONE); + LinearLayout.LayoutParams linearParams =(LinearLayout.LayoutParams) topContactFrame.getLayoutParams(); + linearParams.height = ScreenTools.instance(getActivity()).dip2px(45); + topContactFrame.setLayoutParams(linearParams); + topContactFrame.setPadding(0,ScreenTools.instance(getActivity()).dip2px(10),0,0); + } + + protected void showTopSearchBar() { + topSearchEdt.setVisibility(View.VISIBLE); + } + + protected void hideTopSearchBar() { + topSearchEdt.setVisibility(View.GONE); + } + + protected void showSearchFrameLayout(){ + searchFrameLayout.setVisibility(View.VISIBLE); + /**还是以前的页面,没有看psd是否改过*/ + searchFrameLayout.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View arg0) { + showSearchView(); + } + }); + //下面的历史代码 + //tryHandleSearchAction(action); + } + + protected abstract void initHandler(); + + @Override + public void onActivityCreated(Bundle bundle) { + logger.d("Fragment onActivityCreate:" + getClass().getName()); + super.onActivityCreated(bundle); + } + + @Override + public void onStart() { + super.onStart(); + } + + @Override + public void onStop() { + super.onStop(); + } + + @Override + public void onResume() { + super.onResume(); + } + + @Override + public void onPause() { + super.onPause(); + } + + protected void initSearch() { + setTopRightButton(R.drawable.tt_top_search); + topRightBtn.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View arg0) { + showSearchView(); + } + }); + } + + public void showSearchView() { + startActivity(new Intent(getActivity(), SearchActivity.class)); + } + + protected void onSearchDataReady() { + initSearch(); + } +} diff --git a/android/app/src/main/java/com/mogujie/tt/ui/base/TTBaseFragmentActivity.java b/android/app/src/main/java/com/mogujie/tt/ui/base/TTBaseFragmentActivity.java new file mode 100644 index 000000000..70aecc28e --- /dev/null +++ b/android/app/src/main/java/com/mogujie/tt/ui/base/TTBaseFragmentActivity.java @@ -0,0 +1,7 @@ +package com.mogujie.tt.ui.base; + +import android.support.v4.app.FragmentActivity; + +public abstract class TTBaseFragmentActivity extends FragmentActivity{ + +} diff --git a/android/app/src/main/java/com/mogujie/tt/ui/fragment/ChatFragment.java b/android/app/src/main/java/com/mogujie/tt/ui/fragment/ChatFragment.java new file mode 100644 index 000000000..ce1734483 --- /dev/null +++ b/android/app/src/main/java/com/mogujie/tt/ui/fragment/ChatFragment.java @@ -0,0 +1,566 @@ + +package com.mogujie.tt.ui.fragment; + +import android.app.Activity; +import android.app.AlertDialog; +import android.content.Context; +import android.content.DialogInterface; +import android.os.Bundle; +import android.view.ContextThemeWrapper; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.AdapterView; +import android.widget.AdapterView.OnItemClickListener; +import android.widget.AdapterView.OnItemLongClickListener; +import android.widget.AdapterView.OnItemSelectedListener; +import android.widget.ImageView; +import android.widget.ListView; +import android.widget.ProgressBar; +import android.widget.TextView; +import android.widget.Toast; + +import com.mogujie.tt.config.DBConstant; +import com.mogujie.tt.DB.entity.GroupEntity; +import com.mogujie.tt.DB.entity.UserEntity; +import com.mogujie.tt.R; +import com.mogujie.tt.protobuf.helper.EntityChangeEngine; +import com.mogujie.tt.ui.adapter.ChatAdapter; +import com.mogujie.tt.utils.IMUIHelper; +import com.mogujie.tt.imservice.entity.RecentInfo; +import com.mogujie.tt.imservice.event.GroupEvent; +import com.mogujie.tt.imservice.event.LoginEvent; +import com.mogujie.tt.imservice.event.ReconnectEvent; +import com.mogujie.tt.imservice.event.SessionEvent; +import com.mogujie.tt.imservice.event.SocketEvent; +import com.mogujie.tt.imservice.event.UnreadEvent; +import com.mogujie.tt.imservice.event.UserInfoEvent; +import com.mogujie.tt.imservice.manager.IMLoginManager; +import com.mogujie.tt.imservice.manager.IMReconnectManager; +import com.mogujie.tt.imservice.manager.IMUnreadMsgManager; +import com.mogujie.tt.imservice.service.IMService; +import com.mogujie.tt.protobuf.IMBaseDefine; +import com.mogujie.tt.ui.activity.MainActivity; +import com.mogujie.tt.imservice.support.IMServiceConnector; +import com.mogujie.tt.utils.NetworkUtil; +import com.nostra13.universalimageloader.core.ImageLoader; +import com.nostra13.universalimageloader.core.listener.PauseOnScrollListener; + +import java.util.List; + +import de.greenrobot.event.EventBus; + +/** + * @Description 最近联系人Fragment页 + * @author Nana + * @date 2014-7-24 + * + */ +public class ChatFragment extends MainFragment + implements + OnItemSelectedListener, + OnItemClickListener, + OnItemLongClickListener { + + private ChatAdapter contactAdapter; + private ListView contactListView; + private View curView = null; + private View noNetworkView; + private View noChatView; + private ImageView notifyImage; + private TextView displayView; + private ProgressBar reconnectingProgressBar; + private IMService imService; + + //是否是手动点击重练。fasle:不显示各种弹出小气泡. true:显示小气泡直到错误出现 + private volatile boolean isManualMConnect = false; + + @Override + public void onAttach(Activity activity) { + super.onAttach(activity); + } + + private IMServiceConnector imServiceConnector = new IMServiceConnector(){ + + @Override + public void onServiceDisconnected() { + if(EventBus.getDefault().isRegistered(ChatFragment.this)){ + EventBus.getDefault().unregister(ChatFragment.this); + } + } + @Override + public void onIMServiceConnected() { + // TODO Auto-generated method stub + logger.d("chatfragment#recent#onIMServiceConnected"); + imService = imServiceConnector.getIMService(); + if (imService == null) { + // why ,some reason + return; + } + // 依赖联系人回话、未读消息、用户的信息三者的状态 + onRecentContactDataReady(); + EventBus.getDefault().registerSticky(ChatFragment.this); + } + }; + + @Override + public void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + imServiceConnector.connect(getActivity()); + logger.d("chatfragment#onCreate"); + } + + @Override + public View onCreateView(LayoutInflater inflater, ViewGroup container, + Bundle bundle) { + logger.d("onCreateView"); + if (null != curView) { + logger.d("curView is not null, remove it"); + ((ViewGroup) curView.getParent()).removeView(curView); + } + curView = inflater.inflate(R.layout.tt_fragment_chat, topContentView); + // 多端登陆也在用这个view + noNetworkView = curView.findViewById(R.id.layout_no_network); + noChatView = curView.findViewById(R.id.layout_no_chat); + reconnectingProgressBar = (ProgressBar) curView.findViewById(R.id.progressbar_reconnect); + displayView = (TextView) curView.findViewById(R.id.disconnect_text); + notifyImage = (ImageView) curView.findViewById(R.id.imageWifi); + + super.init(curView); + initTitleView();// 初始化顶部view + initContactListView(); // 初始化联系人列表视图 + showProgressBar();// 创建时没有数据,显示加载动画 + return curView; + } + /** + * @Description 设置顶部按钮 + */ + private void initTitleView() { + // 设置标题 + setTopTitleBold(getActivity().getString(R.string.chat_title)); + } + private void initContactListView() { + contactListView = (ListView) curView.findViewById(R.id.ContactListView); + contactListView.setOnItemClickListener(this); + contactListView.setOnItemLongClickListener(this); + contactAdapter = new ChatAdapter(getActivity()); + contactListView.setAdapter(contactAdapter); + + // this is critical, disable loading when finger sliding, otherwise + // you'll find sliding is not very smooth + contactListView.setOnScrollListener(new PauseOnScrollListener(ImageLoader.getInstance(), + true, true)); + } + + @Override + public void onStart() { + logger.d("chatfragment#onStart"); + super.onStart(); + } + + @Override + public void onStop() { + logger.d("chatfragment#onStop"); + super.onStop(); + } + + @Override + public void onPause() { + logger.d("chatfragment#onPause"); + super.onPause(); + } + + @Override + public void onDestroy() { + if(EventBus.getDefault().isRegistered(ChatFragment.this)){ + EventBus.getDefault().unregister(ChatFragment.this); + } + imServiceConnector.disconnect(getActivity()); + super.onDestroy(); + } + + @Override + public void onItemSelected(AdapterView parent, View view, int position, + long id) { + } + + @Override + public void onNothingSelected(AdapterView parent) { + } + + // 这个地方跳转一定要快 + @Override + public void onItemClick(AdapterView parent, View view, int position, + long id) { + + RecentInfo recentInfo = contactAdapter.getItem(position); + if (recentInfo == null) { + logger.e("recent#null recentInfo -> position:%d", position); + return; + } + IMUIHelper.openChatActivity(getActivity(),recentInfo.getSessionKey()); + } + + public void onEventMainThread(SessionEvent sessionEvent){ + logger.d("chatfragment#SessionEvent# -> %s", sessionEvent); + switch (sessionEvent){ + case RECENT_SESSION_LIST_UPDATE: + case RECENT_SESSION_LIST_SUCCESS: + case SET_SESSION_TOP: + onRecentContactDataReady(); + break; + } + } + + public void onEventMainThread(GroupEvent event){ + switch (event.getEvent()){ + case GROUP_INFO_OK: + case CHANGE_GROUP_MEMBER_SUCCESS: + onRecentContactDataReady(); + searchDataReady(); + break; + + case GROUP_INFO_UPDATED: + onRecentContactDataReady(); + searchDataReady(); + break; + case SHIELD_GROUP_OK: + // 更新最下栏的未读计数、更新session + onShieldSuccess(event.getGroupEntity()); + break; + case SHIELD_GROUP_FAIL: + case SHIELD_GROUP_TIMEOUT: + onShieldFail(); + break; + } + } + + public void onEventMainThread(UnreadEvent event){ + switch (event.event){ + case UNREAD_MSG_RECEIVED: + case UNREAD_MSG_LIST_OK: + case SESSION_READED_UNREAD_MSG: + onRecentContactDataReady(); + break; + } + } + public void onEventMainThread(UserInfoEvent event){ + switch (event){ + case USER_INFO_UPDATE: + case USER_INFO_OK: + onRecentContactDataReady(); + searchDataReady(); + break; + } + } + + public void onEventMainThread(LoginEvent loginEvent){ + logger.d("chatfragment#LoginEvent# -> %s", loginEvent); + switch (loginEvent){ + case LOCAL_LOGIN_SUCCESS: + case LOGINING: { + logger.d("chatFragment#login#recv handleDoingLogin event"); + if (reconnectingProgressBar != null) { + reconnectingProgressBar.setVisibility(View.VISIBLE); + } + }break; + + case LOCAL_LOGIN_MSG_SERVICE: + case LOGIN_OK: { + isManualMConnect = false; + logger.d("chatfragment#loginOk"); + noNetworkView.setVisibility(View.GONE); + }break; + + case LOGIN_AUTH_FAILED: + case LOGIN_INNER_FAILED:{ + onLoginFailure(loginEvent); + }break; + + case PC_OFFLINE: + case KICK_PC_SUCCESS: + onPCLoginStatusNotify(false); + break; + + case KICK_PC_FAILED: + Toast.makeText(getActivity(),getString(R.string.kick_pc_failed), Toast.LENGTH_SHORT).show(); + break; + case PC_ONLINE: + onPCLoginStatusNotify(true); + break; + + default: reconnectingProgressBar.setVisibility(View.GONE); + break; + } + } + + + public void onEventMainThread(SocketEvent socketEvent){ + switch (socketEvent){ + case MSG_SERVER_DISCONNECTED: + handleServerDisconnected(); + break; + + case CONNECT_MSG_SERVER_FAILED: + case REQ_MSG_SERVER_ADDRS_FAILED: + handleServerDisconnected(); + onSocketFailure(socketEvent);break; + } + } + + public void onEventMainThread(ReconnectEvent reconnectEvent){ + switch (reconnectEvent){ + case DISABLE:{ + handleServerDisconnected(); + }break; + } + } + + private void onLoginFailure(LoginEvent event){ + if(!isManualMConnect){return;} + isManualMConnect = false; + String errorTip = getString(IMUIHelper.getLoginErrorTip(event)); + logger.d("login#errorTip:%s", errorTip); + reconnectingProgressBar.setVisibility(View.GONE); + Toast.makeText(getActivity(), errorTip, Toast.LENGTH_SHORT).show(); + } + + private void onSocketFailure(SocketEvent event){ + if(!isManualMConnect){return;} + isManualMConnect = false; + String errorTip = getString(IMUIHelper.getSocketErrorTip(event)); + logger.d("login#errorTip:%s", errorTip); + reconnectingProgressBar.setVisibility(View.GONE); + Toast.makeText(getActivity(), errorTip, Toast.LENGTH_SHORT).show(); + } + + // 更新页面以及 下面的未读总计数 + private void onShieldSuccess(GroupEntity entity){ + if(entity == null){ + return;} + // 更新某个sessionId + contactAdapter.updateRecentInfoByShield(entity); + IMUnreadMsgManager unreadMsgManager =imService.getUnReadMsgManager(); + + int totalUnreadMsgCnt = unreadMsgManager.getTotalUnreadCount(); + logger.d("unread#total cnt %d", totalUnreadMsgCnt); + ((MainActivity) getActivity()).setUnreadMessageCnt(totalUnreadMsgCnt); + } + + private void onShieldFail(){ + Toast.makeText(getActivity(), R.string.req_msg_failed, Toast.LENGTH_SHORT).show(); + } + + /**搜索数据OK + * 群组数据与 user数据都已经完毕 + * */ + public void searchDataReady(){ + if (imService.getContactManager().isUserDataReady() && + imService.getGroupManager().isGroupReady()) { + showSearchFrameLayout(); + } + } + + /** + * 多端,PC端在线状态通知 + * @param isOnline + */ + public void onPCLoginStatusNotify(boolean isOnline){ + logger.d("chatfragment#onPCLoginStatusNotify"); + if(isOnline){ + reconnectingProgressBar.setVisibility(View.GONE); + noNetworkView.setVisibility(View.VISIBLE); + notifyImage.setImageResource(R.drawable.pc_notify); + displayView.setText(R.string.pc_status_notify); + /**添加踢出事件*/ + noNetworkView.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + reconnectingProgressBar.setVisibility(View.VISIBLE); + imService.getLoginManager().reqKickPCClient(); + } + }); + }else{ + noNetworkView.setVisibility(View.GONE); + } + } + + private void handleServerDisconnected() { + logger.d("chatfragment#handleServerDisconnected"); + + if (reconnectingProgressBar != null) { + reconnectingProgressBar.setVisibility(View.GONE); + } + + if (noNetworkView != null) { + notifyImage.setImageResource(R.drawable.warning); + noNetworkView.setVisibility(View.VISIBLE); + if(imService != null){ + if(imService.getLoginManager().isKickout()){ + displayView.setText(R.string.disconnect_kickout); + }else{ + displayView.setText(R.string.no_network); + } + } + /**重连【断线、被其他移动端挤掉】*/ + noNetworkView.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + logger.d("chatFragment#noNetworkView clicked"); + IMReconnectManager manager = imService.getReconnectManager(); + if(NetworkUtil.isNetWorkAvalible(getActivity())){ + isManualMConnect = true; + IMLoginManager.instance().relogin(); + }else{ + Toast.makeText(getActivity(), R.string.no_network_toast, Toast.LENGTH_SHORT).show(); + return; + } + reconnectingProgressBar.setVisibility(View.VISIBLE); + } + }); + } + } + + /** + * 这个处理有点过于粗暴 + */ + private void onRecentContactDataReady() { + boolean isUserData = imService.getContactManager().isUserDataReady(); + boolean isSessionData = imService.getSessionManager().isSessionListReady(); + boolean isGroupData = imService.getGroupManager().isGroupReady(); + + if ( !(isUserData&&isSessionData&&isGroupData)) { + return; + } + IMUnreadMsgManager unreadMsgManager =imService.getUnReadMsgManager(); + + int totalUnreadMsgCnt = unreadMsgManager.getTotalUnreadCount(); + logger.d("unread#total cnt %d", totalUnreadMsgCnt); + ((MainActivity) getActivity()).setUnreadMessageCnt(totalUnreadMsgCnt); + + List recentSessionList = imService.getSessionManager().getRecentListInfo(); + + setNoChatView(recentSessionList); + contactAdapter.setData(recentSessionList); + hideProgressBar(); + showSearchFrameLayout(); + } + + private void setNoChatView(List recentSessionList) + { + if(recentSessionList.size()==0) + { + noChatView.setVisibility(View.VISIBLE); + } + else + { + noChatView.setVisibility(View.GONE); + } + } + + @Override + public boolean onItemLongClick(AdapterView parent, View view, + int position, long id) { + + RecentInfo recentInfo = contactAdapter.getItem(position); + if (recentInfo == null) { + logger.e("recent#onItemLongClick null recentInfo -> position:%d", position); + return false; + } + if (recentInfo.getSessionType() == DBConstant.SESSION_TYPE_SINGLE) { + handleContactItemLongClick(getActivity(),recentInfo); + } else { + handleGroupItemLongClick(getActivity(),recentInfo); + } + return true; + } + + private void handleContactItemLongClick(final Context ctx, final RecentInfo recentInfo) { + + AlertDialog.Builder builder = new AlertDialog.Builder(new ContextThemeWrapper(ctx, android.R.style.Theme_Holo_Light_Dialog)); + builder.setTitle(recentInfo.getName()); + final boolean isTop = imService.getConfigSp().isTopSession(recentInfo.getSessionKey()); + + int topMessageRes = isTop?R.string.cancel_top_message:R.string.top_message; + String[] items = new String[]{ctx.getString(R.string.check_profile), + ctx.getString(R.string.delete_session), + ctx.getString(topMessageRes)}; + + builder.setItems(items, new DialogInterface.OnClickListener() { + @Override + public void onClick(DialogInterface dialog, int which) { + switch (which) { + case 0 : + IMUIHelper.openUserProfileActivity(ctx, recentInfo.getPeerId()); + break; + case 1 : + imService.getSessionManager().reqRemoveSession(recentInfo); + break; + case 2:{ + imService.getConfigSp().setSessionTop(recentInfo.getSessionKey(),!isTop); + }break; + } + } + }); + AlertDialog alertDialog = builder.create(); + alertDialog.setCanceledOnTouchOutside(true); + alertDialog.show(); + } + + // 现在只有群组存在免打扰的 + private void handleGroupItemLongClick(final Context ctx, final RecentInfo recentInfo) { + + AlertDialog.Builder builder = new AlertDialog.Builder(new ContextThemeWrapper(ctx, android.R.style.Theme_Holo_Light_Dialog)); + builder.setTitle(recentInfo.getName()); + + final boolean isTop = imService.getConfigSp().isTopSession(recentInfo.getSessionKey()); + final boolean isForbidden = recentInfo.isForbidden(); + int topMessageRes = isTop?R.string.cancel_top_message:R.string.top_message; + int forbidMessageRes =isForbidden?R.string.cancel_forbid_group_message:R.string.forbid_group_message; + + String[] items = new String[]{ctx.getString(R.string.delete_session),ctx.getString(topMessageRes),ctx.getString(forbidMessageRes)}; + + builder.setItems(items, new DialogInterface.OnClickListener() { + + @Override + public void onClick(DialogInterface dialog, int which) { + switch (which) { + case 0 : + imService.getSessionManager().reqRemoveSession(recentInfo); + break; + case 1:{ + imService.getConfigSp().setSessionTop(recentInfo.getSessionKey(),!isTop); + }break; + case 2:{ + // 底层成功会事件通知 + int shieldType = isForbidden?DBConstant.GROUP_STATUS_ONLINE:DBConstant.GROUP_STATUS_SHIELD; + imService.getGroupManager().reqShieldGroup(recentInfo.getPeerId(),shieldType); + } + break; + } + } + }); + AlertDialog alertDialog = builder.create(); + alertDialog.setCanceledOnTouchOutside(true); + alertDialog.show(); + } + + @Override + protected void initHandler() { + // TODO Auto-generated method stub + } + + /** + * 滚动到有未读消息的第一个联系人 + * 这个还是可行的 + */ + public void scrollToUnreadPosition() { + if (contactListView != null) { + int currentPosition = contactListView.getFirstVisiblePosition(); + int needPosition = contactAdapter.getUnreadPositionOnView(currentPosition); + // 下面这个不管用!! + //contactListView.smoothScrollToPosition(needPosition); + contactListView.setSelection(needPosition); + } + } +} diff --git a/android/app/src/main/java/com/mogujie/tt/ui/fragment/ContactFragment.java b/android/app/src/main/java/com/mogujie/tt/ui/fragment/ContactFragment.java new file mode 100644 index 000000000..8aa2782b6 --- /dev/null +++ b/android/app/src/main/java/com/mogujie/tt/ui/fragment/ContactFragment.java @@ -0,0 +1,320 @@ +package com.mogujie.tt.ui.fragment; + +import android.annotation.SuppressLint; +import android.os.Bundle; +import android.os.Handler; +import android.os.Message; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.Button; +import android.widget.ListView; +import android.widget.TextView; + +import com.mogujie.tt.DB.entity.DepartmentEntity; +import com.mogujie.tt.DB.entity.GroupEntity; +import com.mogujie.tt.DB.entity.UserEntity; +import com.mogujie.tt.R; +import com.mogujie.tt.config.HandlerConstant; +import com.mogujie.tt.imservice.event.GroupEvent; +import com.mogujie.tt.imservice.event.UserInfoEvent; +import com.mogujie.tt.imservice.support.IMServiceConnector; +import com.mogujie.tt.imservice.manager.IMContactManager; +import com.mogujie.tt.imservice.service.IMService; +import com.mogujie.tt.ui.adapter.ContactAdapter; +import com.mogujie.tt.ui.adapter.DeptAdapter; +import com.mogujie.tt.ui.widget.SortSideBar; +import com.mogujie.tt.ui.widget.SortSideBar.OnTouchingLetterChangedListener; +import com.nostra13.universalimageloader.core.ImageLoader; +import com.nostra13.universalimageloader.core.listener.PauseOnScrollListener; + +import java.util.List; + +import de.greenrobot.event.EventBus; + +/** + * 通讯录 (全部、部门) + */ +public class ContactFragment extends MainFragment implements OnTouchingLetterChangedListener { + private View curView = null; + private static Handler uiHandler = null; + private ListView allContactListView; + private ListView departmentContactListView; + private SortSideBar sortSideBar; + private TextView dialog; + + private ContactAdapter contactAdapter; + private DeptAdapter departmentAdapter; + + private IMService imService; + private IMContactManager contactMgr; + private int curTabIndex = 0; + + private IMServiceConnector imServiceConnector = new IMServiceConnector() { + @Override + public void onIMServiceConnected() { + logger.d("contactUI#onIMServiceConnected"); + + imService = imServiceConnector.getIMService(); + if (imService == null) { + logger.e("ContactFragment#onIMServiceConnected# imservice is null!!"); + return; + } + contactMgr = imService.getContactManager(); + + // 初始化视图 + initAdapter(); + renderEntityList(); + EventBus.getDefault().registerSticky(ContactFragment.this); + } + + @Override + public void onServiceDisconnected() { + if (EventBus.getDefault().isRegistered(ContactFragment.this)) { + EventBus.getDefault().unregister(ContactFragment.this); + } + } + }; + + + @Override + public void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + imServiceConnector.connect(getActivity()); + initHandler(); + } + + @Override + public void onDestroy() { + super.onDestroy(); + if (EventBus.getDefault().isRegistered(ContactFragment.this)) { + EventBus.getDefault().unregister(ContactFragment.this); + } + imServiceConnector.disconnect(getActivity()); + } + + + @SuppressLint("HandlerLeak") + @Override + protected void initHandler() { + uiHandler = new Handler() { + @Override + public void handleMessage(Message msg) { + super.handleMessage(msg); + switch (msg.what) { + case HandlerConstant.HANDLER_CHANGE_CONTACT_TAB: + if (null != msg.obj) { + curTabIndex = (Integer) msg.obj; + if (0 == curTabIndex) { + allContactListView.setVisibility(View.VISIBLE); + departmentContactListView.setVisibility(View.GONE); + } else { + departmentContactListView.setVisibility(View.VISIBLE); + allContactListView.setVisibility(View.GONE); + } + } + break; + } + } + }; + } + + @Override + public View onCreateView(LayoutInflater inflater, ViewGroup container, + Bundle savedInstanceState) { + + if (null != curView) { + ((ViewGroup) curView.getParent()).removeView(curView); + return curView; + } + curView = inflater.inflate(R.layout.tt_fragment_contact, topContentView); + initRes(); + return curView; + } + + /** + * @Description 初始化界面资源 + */ + private void initRes() { + // 设置顶部标题栏 + showContactTopBar(); + hideTopBar(); + + super.init(curView); + showProgressBar(); + + sortSideBar = (SortSideBar) curView.findViewById(R.id.sidrbar); + dialog = (TextView) curView.findViewById(R.id.dialog); + sortSideBar.setTextView(dialog); + sortSideBar.setOnTouchingLetterChangedListener(this); + + allContactListView = (ListView) curView.findViewById(R.id.all_contact_list); + departmentContactListView = (ListView) curView.findViewById(R.id.department_contact_list); + + //this is critical, disable loading when finger sliding, otherwise you'll find sliding is not very smooth + allContactListView.setOnScrollListener(new PauseOnScrollListener(ImageLoader.getInstance(), true, true)); + departmentContactListView.setOnScrollListener(new PauseOnScrollListener(ImageLoader.getInstance(), true, true)); + // todo eric + // showLoadingProgressBar(true); + } + + private void initAdapter(){ + contactAdapter = new ContactAdapter(getActivity(),imService); + departmentAdapter = new DeptAdapter(getActivity(),imService); + allContactListView.setAdapter(contactAdapter); + departmentContactListView.setAdapter(departmentAdapter); + + // 单击视图事件 + allContactListView.setOnItemClickListener(contactAdapter); + allContactListView.setOnItemLongClickListener(contactAdapter); + + departmentContactListView.setOnItemClickListener(departmentAdapter); + departmentContactListView.setOnItemLongClickListener(departmentAdapter); + } + + public void locateDepartment(int departmentId) { + logger.d("department#locateDepartment id:%s", departmentId); + + if (topContactTitle == null) { + logger.e("department#TopTabButton is null"); + return; + } + Button tabDepartmentBtn = topContactTitle.getTabDepartmentBtn(); + if (tabDepartmentBtn == null) { + return; + } + tabDepartmentBtn.performClick(); + locateDepartmentImpl(departmentId); + } + + private void locateDepartmentImpl(int departmentId) { + if (imService == null) { + return; + } + DepartmentEntity department = imService.getContactManager().findDepartment(departmentId); + if (department == null) { + logger.e("department#no such id:%s", departmentId); + return; + } + + logger.d("department#go to locate department:%s", department); + final int position = departmentAdapter.locateDepartment(department.getDepartName()); + logger.d("department#located position:%d", position); + + if (position < 0) { + logger.i("department#locateDepartment id:%s failed", departmentId); + return; + } + //the first time locate works + //from the second time, the locating operations fail ever since + departmentContactListView.post(new Runnable() { + + @Override + public void run() { + departmentContactListView.setSelection(position); + } + }); + } + + + /** + * 刷新单个entity + * 很消耗性能 + */ + private void renderEntityList() { + hideProgressBar(); + logger.d("contact#renderEntityList"); + + if (contactMgr.isUserDataReady() ) { + renderUserList(); + renderDeptList(); + } + if (imService.getGroupManager().isGroupReady()) { + renderGroupList(); + } + showSearchFrameLayout(); + } + + + private void renderDeptList(){ + /**---------------------部门数据的渲染------------------------------------------*/ + List departmentList = contactMgr.getDepartmentTabSortedList(); + departmentAdapter.putUserList(departmentList); + } + + private void renderUserList(){ + List contactList = contactMgr.getContactSortedList(); + // 没有任何的联系人数据 + if (contactList.size() <= 0) { + return; + } + contactAdapter.putUserList(contactList); + } + + private void renderGroupList() { + logger.d("group#onGroupReady"); + List originList = imService.getGroupManager().getNormalGroupSortedList(); + if(originList.size() <= 0){ + return; + } + contactAdapter.putGroupList(originList); + } + + private ListView getCurListView() { + if (0 == curTabIndex) { + return allContactListView; + } else { + return departmentContactListView; + } + } + + @Override + public void onTouchingLetterChanged(String s) { + int position = -1; + if (0 == curTabIndex) { + position = contactAdapter.getPositionForSection(s.charAt(0)); + } else { + position = departmentAdapter.getPositionForSection(s.charAt(0)); + } + if (position != -1) { + getCurListView().setSelection(position); + } + } + + public static Handler getHandler() { + return uiHandler; + } + + @Override + public void onActivityCreated(Bundle savedInstanceState) { + super.onActivityCreated(savedInstanceState); + } + + public void onEventMainThread(GroupEvent event) { + switch (event.getEvent()) { + case GROUP_INFO_UPDATED: + case GROUP_INFO_OK: + renderGroupList(); + searchDataReady(); + break; + } + } + + public void onEventMainThread(UserInfoEvent event) { + switch (event) { + case USER_INFO_UPDATE: + case USER_INFO_OK: + renderDeptList(); + renderUserList(); + searchDataReady(); + break; + } + } + + public void searchDataReady() { + if (imService.getContactManager().isUserDataReady() && + imService.getGroupManager().isGroupReady()) { + showSearchFrameLayout(); + } + } +} diff --git a/android/app/src/main/java/com/mogujie/tt/ui/fragment/GroupManagerFragment.java b/android/app/src/main/java/com/mogujie/tt/ui/fragment/GroupManagerFragment.java new file mode 100644 index 000000000..f7759678d --- /dev/null +++ b/android/app/src/main/java/com/mogujie/tt/ui/fragment/GroupManagerFragment.java @@ -0,0 +1,233 @@ +package com.mogujie.tt.ui.fragment; + +import android.graphics.Color; +import android.graphics.drawable.ColorDrawable; +import android.os.Bundle; +import android.text.TextUtils; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.CheckBox; +import android.widget.GridView; +import android.widget.TextView; +import android.widget.Toast; + +import com.mogujie.tt.DB.entity.PeerEntity; +import com.mogujie.tt.config.DBConstant; +import com.mogujie.tt.DB.entity.GroupEntity; +import com.mogujie.tt.DB.entity.UserEntity; +import com.mogujie.tt.DB.sp.ConfigurationSp; +import com.mogujie.tt.R; +import com.mogujie.tt.config.IntentConstant; +import com.mogujie.tt.ui.adapter.GroupManagerAdapter; +import com.mogujie.tt.ui.helper.CheckboxConfigHelper; +import com.mogujie.tt.imservice.event.GroupEvent; +import com.mogujie.tt.imservice.service.IMService; +import com.mogujie.tt.ui.base.TTBaseFragment; +import com.mogujie.tt.imservice.support.IMServiceConnector; +import com.nostra13.universalimageloader.core.ImageLoader; +import com.nostra13.universalimageloader.core.listener.PauseOnScrollListener; + +import java.util.ArrayList; +import java.util.List; + +import de.greenrobot.event.EventBus; + + +/** + * @YM + * 个人与群组的聊天详情都会来到这个页面 + * single: 这有sessionId的头像,以及加号"+" , 创建群成功之后,跳到聊天的页面 + * group: 群成员,加减号 , 修改成功之后,跳到群管理页面 + * 临时群任何人都可以加人,但是只有群主可以踢人”这个逻辑修改下,正式群暂时只给createId开放 + */ +public class GroupManagerFragment extends TTBaseFragment{ + private View curView = null; + /**adapter配置*/ + private GridView gridView; + private GroupManagerAdapter adapter; + + + /**详情的配置 勿扰以及指定聊天*/ + CheckboxConfigHelper checkBoxConfiger = new CheckboxConfigHelper(); + CheckBox noDisturbCheckbox; + CheckBox topSessionCheckBox; + + /**需要的状态参数*/ + private IMService imService; + private String curSessionKey; + private PeerEntity peerEntity; + + + @Override + public void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + imServiceConnector.connect(getActivity()); + EventBus.getDefault().register(this); + } + + + @Override + public View onCreateView(LayoutInflater inflater, ViewGroup container,Bundle savedInstanceState) { + if (null != curView) { + ((ViewGroup) curView.getParent()).removeView(curView); + return curView; + } + curView = inflater.inflate(R.layout.tt_fragment_group_manage, topContentView); + noDisturbCheckbox = (CheckBox) curView.findViewById(R.id.NotificationNoDisturbCheckbox); + topSessionCheckBox = (CheckBox) curView.findViewById(R.id.NotificationTopMessageCheckbox); + initRes(); + return curView; + } + + private void initRes() { + // 设置标题栏 + setTopLeftButton(R.drawable.tt_top_back); + setTopLeftText(getActivity().getString(R.string.top_left_back)); + topLeftContainerLayout.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View view) { + getActivity().finish(); + } + }); + } + + + @Override + public void onDestroyView() { + super.onDestroyView(); + } + + /** + * Called when the fragment is no longer in use. This is called + * after {@link #onStop()} and before {@link #onDetach()}. + */ + @Override + public void onDestroy() { + super.onDestroy(); + EventBus.getDefault().unregister(this); + imServiceConnector.disconnect(getActivity()); + } + + @Override + protected void initHandler() { + } + + + private IMServiceConnector imServiceConnector = new IMServiceConnector(){ + @Override + public void onServiceDisconnected() { + } + + @Override + public void onIMServiceConnected() { + logger.d("groupmgr#onIMServiceConnected"); + imService = imServiceConnector.getIMService(); + if(imService == null){ + Toast.makeText(GroupManagerFragment.this.getActivity(), + getResources().getString(R.string.im_service_disconnected), Toast.LENGTH_SHORT).show(); + return; + } + checkBoxConfiger.init(imService.getConfigSp()); + initView(); + initAdapter(); + } + }; + + + private void initView() { + setTopTitle(getString(R.string.chat_detail)); + if (null == imService || null == curView ) { + logger.e("groupmgr#init failed,cause by imService or curView is null"); + return; + } + + curSessionKey = getActivity().getIntent().getStringExtra(IntentConstant.KEY_SESSION_KEY); + if (TextUtils.isEmpty(curSessionKey)) { + logger.e("groupmgr#getSessionInfoFromIntent failed"); + return; + } + peerEntity = imService.getSessionManager().findPeerEntity(curSessionKey); + if(peerEntity == null){ + logger.e("groupmgr#findPeerEntity failed,sessionKey:%s",curSessionKey); + return; + } + switch (peerEntity.getType()){ + case DBConstant.SESSION_TYPE_GROUP:{ + GroupEntity groupEntity = (GroupEntity) peerEntity; + // 群组名称的展示 + TextView groupNameView = (TextView) curView.findViewById(R.id.group_manager_title); + groupNameView.setText(groupEntity.getMainName()); + }break; + + case DBConstant.SESSION_TYPE_SINGLE:{ + // 个人不显示群聊名称 + View groupNameContainerView = curView.findViewById(R.id.group_manager_name); + groupNameContainerView.setVisibility(View.GONE); + }break; + } + // 初始化配置checkBox + initCheckbox(); + } + + private void initAdapter(){ + logger.d("groupmgr#initAdapter"); + + gridView = (GridView) curView.findViewById(R.id.group_manager_grid); + gridView.setSelector(new ColorDrawable(Color.TRANSPARENT));// 去掉点击时的黄色背影 + gridView.setOnScrollListener(new PauseOnScrollListener(ImageLoader.getInstance(), true, true)); + + adapter = new GroupManagerAdapter(getActivity(),imService,peerEntity); + gridView.setAdapter(adapter); + } + + /**事件驱动通知*/ + public void onEventMainThread(GroupEvent event){ + switch (event.getEvent()){ + + case CHANGE_GROUP_MEMBER_FAIL: + case CHANGE_GROUP_MEMBER_TIMEOUT:{ + Toast.makeText(getActivity(), getString(R.string.change_temp_group_failed), Toast.LENGTH_SHORT).show(); + return; + } + case CHANGE_GROUP_MEMBER_SUCCESS:{ + onMemberChangeSuccess(event); + }break; + } + } + + private void onMemberChangeSuccess(GroupEvent event){ + int groupId = event.getGroupEntity().getPeerId(); + if(groupId != peerEntity.getPeerId()){ + return; + } + List changeList = event.getChangeList(); + if(changeList == null || changeList.size()<=0){ + return; + } + int changeType = event.getChangeType(); + + switch (changeType){ + case DBConstant.GROUP_MODIFY_TYPE_ADD: + ArrayList newList = new ArrayList<>(); + for(Integer userId:changeList){ + UserEntity userEntity = imService.getContactManager().findContact(userId); + if(userEntity!=null) { + newList.add(userEntity); + } + } + adapter.add(newList); + break; + case DBConstant.GROUP_MODIFY_TYPE_DEL: + for(Integer userId:changeList){ + adapter.removeById(userId); + } + break; + } + } + + private void initCheckbox() { + checkBoxConfiger.initCheckBox(noDisturbCheckbox, curSessionKey, ConfigurationSp.CfgDimension.NOTIFICATION); + checkBoxConfiger.initTopCheckBox(topSessionCheckBox,curSessionKey); + } +} diff --git a/android/app/src/main/java/com/mogujie/tt/ui/fragment/GroupMemberSelectFragment.java b/android/app/src/main/java/com/mogujie/tt/ui/fragment/GroupMemberSelectFragment.java new file mode 100644 index 000000000..98d7d9049 --- /dev/null +++ b/android/app/src/main/java/com/mogujie/tt/ui/fragment/GroupMemberSelectFragment.java @@ -0,0 +1,402 @@ +package com.mogujie.tt.ui.fragment; + +import android.app.AlertDialog; +import android.content.Context; +import android.content.DialogInterface; +import android.content.Intent; +import android.os.Bundle; +import android.text.Editable; +import android.text.TextUtils; +import android.text.TextWatcher; +import android.view.ContextThemeWrapper; +import android.view.LayoutInflater; +import android.view.View; +import android.view.View.OnClickListener; +import android.view.ViewGroup; +import android.view.inputmethod.InputMethodManager; +import android.widget.AbsListView; +import android.widget.EditText; +import android.widget.ListView; +import android.widget.TextView; +import android.widget.Toast; + +import com.mogujie.tt.DB.entity.GroupEntity; +import com.mogujie.tt.DB.entity.PeerEntity; +import com.mogujie.tt.DB.entity.UserEntity; +import com.mogujie.tt.R; +import com.mogujie.tt.config.DBConstant; +import com.mogujie.tt.config.IntentConstant; +import com.mogujie.tt.imservice.event.GroupEvent; +import com.mogujie.tt.imservice.support.IMServiceConnector; +import com.mogujie.tt.imservice.manager.IMGroupManager; +import com.mogujie.tt.imservice.service.IMService; +import com.mogujie.tt.ui.adapter.GroupSelectAdapter; +import com.mogujie.tt.ui.widget.SearchEditText; +import com.mogujie.tt.ui.widget.SortSideBar; +import com.mogujie.tt.ui.widget.SortSideBar.OnTouchingLetterChangedListener; +import com.mogujie.tt.utils.IMUIHelper; +import com.mogujie.tt.utils.Logger; + +import java.util.Collections; +import java.util.HashSet; +import java.util.List; +import java.util.Set; +import java.util.Timer; +import java.util.TimerTask; + +import de.greenrobot.event.EventBus; + + +/** + * @YM - -! + * 1. 创建群的时候,跳到聊天页面 + * 2. 新增人员的时候,返回到聊天详情页面 + */ +public class GroupMemberSelectFragment extends MainFragment + implements OnTouchingLetterChangedListener { + + private static Logger logger = Logger.getLogger(GroupMemberSelectFragment.class); + + private View curView = null; + private IMService imService; + + /**列表视图 + * 1. 需要两种状态:选中的成员List --》确定之后才会回话页面或者详情 + * 2. 已经被选的状态 -->已经在群中的成员 + * */ + private GroupSelectAdapter adapter; + private ListView contactListView; + + private SortSideBar sortSideBar; + private TextView dialog; + private SearchEditText searchEditText; + + private String curSessionKey; + private PeerEntity peerEntity; + + @Override + public void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + EventBus.getDefault().register(this); + imServiceConnector.connect(getActivity()); + } + + @Override + public void onDestroy() { + super.onDestroy(); + EventBus.getDefault().unregister(this); + imServiceConnector.disconnect(getActivity()); + } + + @Override + public View onCreateView(LayoutInflater inflater, ViewGroup container, + Bundle savedInstanceState) { + if (null != curView) { + ((ViewGroup) curView.getParent()).removeView(curView); + return curView; + } + curView = inflater.inflate(R.layout.tt_fragment_group_member_select, topContentView); + super.init(curView); + initRes(); + return curView; + } + + + @Override + public void onDestroyView() { + super.onDestroyView(); + } + + + /** + * 获取列表中 默认选中成员列表 + * @return + */ + private Set getAlreadyCheckList(){ + Set alreadyListSet = new HashSet<>(); + if(peerEntity == null){ + Toast.makeText(getActivity(), getString(R.string.error_group_info), Toast.LENGTH_SHORT).show(); + getActivity().finish(); + logger.e("[fatal error,groupInfo is null,cause by SESSION_TYPE_GROUP]"); + //return Collections.emptySet(); + } + switch (peerEntity.getType()){ + case DBConstant.SESSION_TYPE_GROUP:{ + GroupEntity entity = (GroupEntity) peerEntity; + alreadyListSet.addAll(entity.getlistGroupMemberIds()); + }break; + + case DBConstant.SESSION_TYPE_SINGLE:{ + int loginId = imService.getLoginManager().getLoginId(); + alreadyListSet.add(loginId); + alreadyListSet.add(peerEntity.getPeerId()); + }break; + } + return alreadyListSet; + } + + private IMServiceConnector imServiceConnector = new IMServiceConnector(){ + @Override + public void onIMServiceConnected() { + logger.d("groupselmgr#onIMServiceConnected"); + + imService = imServiceConnector.getIMService(); + Intent intent = getActivity().getIntent(); + curSessionKey = intent.getStringExtra(IntentConstant.KEY_SESSION_KEY); + peerEntity = imService.getSessionManager().findPeerEntity(curSessionKey); + /**已经处于选中状态的list*/ + Set alreadyList = getAlreadyCheckList(); + initContactList(alreadyList); + } + + @Override + public void onServiceDisconnected() {} + }; + + + private void initContactList(final Set alreadyList) { + // 根据拼音排序 + adapter = new GroupSelectAdapter(getActivity(),imService); + contactListView.setAdapter(adapter); + + contactListView.setOnItemClickListener(adapter); + contactListView.setOnItemLongClickListener(adapter); + + List contactList = imService.getContactManager().getContactSortedList(); + adapter.setAllUserList(contactList); + adapter.setAlreadyListSet(alreadyList); + } + + + /** + * @Description 初始化资源 + */ + private void initRes() { + // 设置标题栏 + // todo eric + setTopTitle(getString(R.string.choose_contact)); + setTopRightText(getActivity().getString(R.string.confirm)); + topLeftContainerLayout.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View view) { + getActivity().finish(); + } + }); + setTopLeftText(getResources().getString(R.string.cancel)); + + topRightTitleTxt.setOnClickListener(new OnClickListener() { + + @Override + public void onClick(View arg0) { + logger.d("tempgroup#on 'save' btn clicked"); + + if(adapter.getCheckListSet().size()<=0){ + Toast.makeText(getActivity(), getString(R.string.select_group_member_empty), Toast.LENGTH_SHORT).show(); + return; + } + + Set checkListSet = adapter.getCheckListSet(); + IMGroupManager groupMgr = imService.getGroupManager(); + //从个人过来的,创建群,默认自己是加入的,对方的sessionId也是加入的 + //自己与自己对话,也能创建群的,这个时候要判断,群组成员一定要大于2个 + int sessionType = peerEntity.getType(); + if (sessionType == DBConstant.SESSION_TYPE_SINGLE) { + int loginId = imService.getLoginManager().getLoginId(); + logger.d("tempgroup#loginId:%d", loginId); + checkListSet.add(loginId); + checkListSet.add(peerEntity.getPeerId()); + logger.d("tempgroup#memberList size:%d", checkListSet.size()); + ShowDialogForTempGroupname(groupMgr, checkListSet); + } else if (sessionType == DBConstant.SESSION_TYPE_GROUP) { + showProgressBar(); + imService.getGroupManager().reqAddGroupMember(peerEntity.getPeerId(),checkListSet); + } + } + + + private void ShowDialogForTempGroupname(final IMGroupManager groupMgr,final Set memberList) { + AlertDialog.Builder builder = new AlertDialog.Builder(new ContextThemeWrapper(getActivity(), + android.R.style.Theme_Holo_Light_Dialog)); + + LayoutInflater inflater = (LayoutInflater)getActivity().getSystemService(Context.LAYOUT_INFLATER_SERVICE); + View dialog_view = inflater.inflate(R.layout.tt_custom_dialog, null); + final EditText editText = (EditText)dialog_view.findViewById(R.id.dialog_edit_content); + TextView textText = (TextView)dialog_view.findViewById(R.id.dialog_title); + textText.setText(R.string.create_temp_group_dialog_title); + builder.setView(dialog_view); + + builder.setPositiveButton(getString(R.string.tt_ok), new DialogInterface.OnClickListener() { + + @Override + public void onClick(DialogInterface dialog, int which) { + String tempGroupName = editText.getText().toString(); + tempGroupName = tempGroupName.trim(); + showProgressBar(); + groupMgr.reqCreateTempGroup(tempGroupName,memberList); + } + }); + builder.setNegativeButton(getString(R.string.tt_cancel), new DialogInterface.OnClickListener() { + @Override + public void onClick(DialogInterface dialogInterface, int i) { + InputMethodManager inputManager = + (InputMethodManager)editText.getContext().getSystemService(Context.INPUT_METHOD_SERVICE); + inputManager.hideSoftInputFromWindow(editText.getWindowToken(),0); + } + }); + final AlertDialog alertDialog = builder.create(); + + /**只有输入框中有值的时候,确定按钮才可以按下*/ + editText.addTextChangedListener(new TextWatcher() { + @Override + public void beforeTextChanged(CharSequence s, int start, int count, int after) {} + @Override + public void onTextChanged(CharSequence s, int start, int before, int count) {} + + @Override + public void afterTextChanged(Editable s) { + if(TextUtils.isEmpty(s.toString().trim())){ + alertDialog.getButton(AlertDialog.BUTTON_POSITIVE).setEnabled(false); + }else{ + alertDialog.getButton(AlertDialog.BUTTON_POSITIVE).setEnabled(true); + } + } + }); + + alertDialog.show(); + alertDialog.getButton(AlertDialog.BUTTON_POSITIVE).setEnabled(false); + + /**对话框弹出的时候,下面的键盘也要跟上来*/ + Timer timer = new Timer(); + timer.schedule(new TimerTask(){ + @Override + public void run() { + InputMethodManager inputManager = + (InputMethodManager)editText.getContext().getSystemService(Context.INPUT_METHOD_SERVICE); + + inputManager.toggleSoftInput(0, InputMethodManager.HIDE_NOT_ALWAYS); + } + }, 100); + } + }); + + sortSideBar = (SortSideBar) curView.findViewById(R.id.sidrbar); + sortSideBar.setOnTouchingLetterChangedListener(this); + + dialog = (TextView) curView.findViewById(R.id.dialog); + sortSideBar.setTextView(dialog); + + contactListView = (ListView) curView.findViewById(R.id.all_contact_list); + contactListView.setOnScrollListener(new AbsListView.OnScrollListener() { + @Override + public void onScrollStateChanged(AbsListView view, int scrollState) { + //如果存在软键盘,关闭掉 + InputMethodManager imm = (InputMethodManager)getActivity().getSystemService( + Context.INPUT_METHOD_SERVICE); + //txtName is a reference of an EditText Field + imm.hideSoftInputFromWindow(searchEditText.getWindowToken(), 0); + } + + @Override + public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) { + } + }); + + searchEditText = (SearchEditText) curView.findViewById(R.id.filter_edit); + searchEditText.addTextChangedListener(new TextWatcher() { + + @Override + public void onTextChanged(CharSequence s, int start, int before, + int count) { + + String key = s.toString(); + if(TextUtils.isEmpty(key)){ + adapter.recover(); + sortSideBar.setVisibility(View.VISIBLE); + }else{ + sortSideBar.setVisibility(View.INVISIBLE); + adapter.onSearch(key); + } + } + + @Override + public void beforeTextChanged(CharSequence s, int start, int count, + int after) { + } + + @Override + public void afterTextChanged(Editable s) { + } + }); + } + + + public void onEventMainThread(GroupEvent event){ + switch (event.getEvent()){ + case CHANGE_GROUP_MEMBER_SUCCESS: + handleGroupMemChangeSuccess(event); + break; + case CHANGE_GROUP_MEMBER_FAIL: + case CHANGE_GROUP_MEMBER_TIMEOUT: + handleChangeGroupMemFail(); + break; + case CREATE_GROUP_OK: + handleCreateGroupSuccess(event); + break; + case CREATE_GROUP_FAIL: + case CREATE_GROUP_TIMEOUT: + handleCreateGroupFail(); + break; + + } + } + + /** + * 处理群创建成功、失败事件 + * @param event + */ + private void handleCreateGroupSuccess(GroupEvent event) { + logger.d("groupmgr#on CREATE_GROUP_OK"); + String groupSessionKey = event.getGroupEntity().getSessionKey(); + IMUIHelper.openChatActivity(getActivity(),groupSessionKey); + getActivity().finish(); + } + + private void handleCreateGroupFail() { + logger.d("groupmgr#on CREATE_GROUP_FAIL"); + hideProgressBar(); + Toast.makeText(getActivity(), getString(R.string.create_temp_group_failed), Toast.LENGTH_SHORT).show(); + } + + /** + * 处理 群成员增加删除成功、失败事件 + * 直接返回群详情管理页面 + * @param event + */ + private void handleGroupMemChangeSuccess(GroupEvent event) { + logger.d("groupmgr#on handleGroupMemChangeSuccess"); + getActivity().finish(); + } + + + private void handleChangeGroupMemFail() { + logger.d("groupmgr#on handleChangeGroupMemFail"); + hideProgressBar(); + Toast.makeText(getActivity(), getString(R.string.change_temp_group_failed), Toast.LENGTH_SHORT).show(); + } + + + @Override + protected void initHandler() { + // TODO Auto-generated method stub + } + + @Override + public void onTouchingLetterChanged(String s) { + // TODO Auto-generated method stub + int position = adapter.getPositionForSection(s.charAt(0)); + if (position != -1) { + contactListView.setSelection(position); + } + } + +} diff --git a/android/app/src/main/java/com/mogujie/tt/ui/fragment/InternalFragment.java b/android/app/src/main/java/com/mogujie/tt/ui/fragment/InternalFragment.java new file mode 100644 index 000000000..eccaa1ea1 --- /dev/null +++ b/android/app/src/main/java/com/mogujie/tt/ui/fragment/InternalFragment.java @@ -0,0 +1,63 @@ +package com.mogujie.tt.ui.fragment; + +import android.content.Intent; +import android.os.Bundle; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.AdapterView; +import android.widget.ListView; + +import com.mogujie.tt.R; +import com.mogujie.tt.config.IntentConstant; +import com.mogujie.tt.ui.activity.WebViewFragmentActivity; +import com.mogujie.tt.ui.adapter.InternalAdapter; +import com.mogujie.tt.ui.base.TTBaseFragment; + +public class InternalFragment extends TTBaseFragment { + private View curView = null; + private ListView internalListView; + private InternalAdapter mAdapter; + + @Override + public View onCreateView(LayoutInflater inflater, ViewGroup container, + Bundle savedInstanceState) { + if (null != curView) { + ((ViewGroup) curView.getParent()).removeView(curView); + return curView; + } + curView = inflater.inflate(R.layout.tt_fragment_internal, + topContentView); + + initRes(); + mAdapter = new InternalAdapter(this.getActivity()); + internalListView.setAdapter(mAdapter); + mAdapter.update(); + return curView; + } + + private void initRes() { + // 设置顶部标题栏 + setTopTitle(getActivity().getString(R.string.main_innernet)); + internalListView = (ListView)curView.findViewById(R.id.internalListView); + internalListView.setOnItemClickListener(new AdapterView.OnItemClickListener() { + @Override + public void onItemClick(AdapterView adapterView, View view, int i, long l) { + String url = mAdapter.getItem(i).getItemUrl(); + Intent intent=new Intent(InternalFragment.this.getActivity(),WebViewFragmentActivity.class); + intent.putExtra(IntentConstant.WEBVIEW_URL, url); + startActivity(intent); + } + }); + } + + @Override + public void onDestroy() { + super.onDestroy(); + } + + @Override + protected void initHandler() { + } + +} diff --git a/android/app/src/main/java/com/mogujie/tt/ui/fragment/MainFragment.java b/android/app/src/main/java/com/mogujie/tt/ui/fragment/MainFragment.java new file mode 100644 index 000000000..6038eaf96 --- /dev/null +++ b/android/app/src/main/java/com/mogujie/tt/ui/fragment/MainFragment.java @@ -0,0 +1,24 @@ +package com.mogujie.tt.ui.fragment; + +import android.view.View; +import android.widget.ProgressBar; + +import com.mogujie.tt.R; +import com.mogujie.tt.ui.base.TTBaseFragment; + +public abstract class MainFragment extends TTBaseFragment { + private ProgressBar progressbar; + + public void init(View curView) { + progressbar = (ProgressBar) curView.findViewById(R.id.progress_bar); + } + + public void showProgressBar() { + progressbar.setVisibility(View.VISIBLE); + } + + public void hideProgressBar() { + progressbar.setVisibility(View.GONE); + } + +} diff --git a/android/app/src/main/java/com/mogujie/tt/ui/fragment/MessageImageFragment.java b/android/app/src/main/java/com/mogujie/tt/ui/fragment/MessageImageFragment.java new file mode 100644 index 000000000..944fd10ec --- /dev/null +++ b/android/app/src/main/java/com/mogujie/tt/ui/fragment/MessageImageFragment.java @@ -0,0 +1,173 @@ +package com.mogujie.tt.ui.fragment; + + +import android.app.Activity; +import android.graphics.Bitmap; +import android.os.Bundle; +import android.text.TextUtils; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.FrameLayout; +import android.widget.ProgressBar; + +import com.mogujie.tt.R; +import com.mogujie.tt.imservice.entity.ImageMessage; +import com.mogujie.tt.imservice.service.IMService; +import com.mogujie.tt.utils.FileUtil; +import com.mogujie.tt.utils.ImageLoaderUtil; +import com.nostra13.universalimageloader.core.DisplayImageOptions; +import com.nostra13.universalimageloader.core.assist.FailReason; +import com.nostra13.universalimageloader.core.assist.ImageScaleType; +import com.nostra13.universalimageloader.core.listener.SimpleImageLoadingListener; +import com.polites.android.GestureImageView; + + +public class MessageImageFragment extends android.support.v4.app.Fragment { + private View curView = null; + protected GestureImageView view; + protected GestureImageView newView; + private ImageMessage messageInfo = null; + private ProgressBar mProgressbar = null; + private FrameLayout parentLayout = null; + private IMService imService; + + public void setImService(IMService service) { + this.imService = service; + } + + public void setImageInfo(ImageMessage imageInfo) { + messageInfo = imageInfo; + } + + @Override + public void onAttach(Activity activity) { + super.onAttach(activity); + } + + @Override + public void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + } + + @Override + public void onResume() { + super.onResume(); + } + + @Override + public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle bundle) { + try { + if (null != curView) { + if (null != curView.getParent()) { + ((ViewGroup) curView.getParent()).removeView(curView); + } + } + curView = inflater.inflate(R.layout.fragment_message_image, null); + initRes(curView); + initData(); + return curView; + } catch (Exception e) { + return null; + } + } + + private void initRes(View curView) { + try { + view = (GestureImageView) curView.findViewById(R.id.image); + newView = (GestureImageView) curView.findViewById(R.id.new_image); + parentLayout = (FrameLayout) curView.findViewById(R.id.layout); + mProgressbar = (ProgressBar) curView.findViewById(R.id.progress_bar); + mProgressbar.setVisibility(View.VISIBLE); + view.setVisibility(View.VISIBLE); + newView.setVisibility(View.GONE); + view.setClickable(true); + view.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + parentLayout.performClick(); + } + }); + parentLayout.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View arg0) { + if (isAdded()) { + getActivity().finish(); + getActivity().overridePendingTransition( + R.anim.tt_stay, R.anim.tt_image_exit); + } + } + }); + } catch (Exception e) { + } + } + + private void initData() { + try { + + //@ZJ 破图的展示 + String imageUrl = messageInfo.getUrl(); + if (!TextUtils.isEmpty(messageInfo.getPath()) && FileUtil.isFileExist(messageInfo.getPath())) { + imageUrl = "file://" + messageInfo.getPath(); + } + + ImageLoaderUtil.getImageLoaderInstance().displayImage(imageUrl, view, new DisplayImageOptions.Builder() + .cacheInMemory(false) + .cacheOnDisk(true) + .showImageOnLoading(R.drawable.tt_message_image_default) + .showImageOnFail(R.drawable.tt_message_image_error) + .imageScaleType(ImageScaleType.IN_SAMPLE_INT) + .bitmapConfig(Bitmap.Config.RGB_565) + .showImageOnFail(R.drawable.tt_message_image_error) + .resetViewBeforeLoading(true) + .build(), new SimpleImageLoadingListener() { + @Override + public void onLoadingComplete(String imageUri, View view, Bitmap loadedImage) { + closeProgressDialog(loadedImage, true); + } + + @Override + public void onLoadingStarted(String imageUri, View view) { + + } + + @Override + public void onLoadingCancelled(String imageUri, View view) { + + } + + @Override + public void onLoadingFailed(String imageUri, View view, FailReason failReason) { + closeProgressDialog(null, true); + } + }); + } catch (Exception e) { + } + } + + private void closeProgressDialog(Bitmap bitmap, boolean hideProgress) { + try { + if (isAdded()) { + if (hideProgress) { + mProgressbar.setVisibility(View.GONE); + } + if (null == bitmap) { + return; + } + view.setVisibility(View.GONE); + newView.setVisibility(View.VISIBLE); + newView.setImageBitmap(bitmap); + newView.setClickable(true); + newView.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + parentLayout.performClick(); + } + }); + } + } catch (Exception e) { + } + } + + +} \ No newline at end of file diff --git a/android/app/src/main/java/com/mogujie/tt/ui/fragment/MyFragment.java b/android/app/src/main/java/com/mogujie/tt/ui/fragment/MyFragment.java new file mode 100644 index 000000000..7b2d96562 --- /dev/null +++ b/android/app/src/main/java/com/mogujie/tt/ui/fragment/MyFragment.java @@ -0,0 +1,273 @@ +package com.mogujie.tt.ui.fragment; + +import android.app.AlertDialog; +import android.content.Context; +import android.content.DialogInterface; +import android.content.Intent; +import android.os.Bundle; +import android.os.Environment; +import android.os.Handler; +import android.view.ContextThemeWrapper; +import android.view.Gravity; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.EditText; +import android.widget.RelativeLayout; +import android.widget.TextView; +import android.widget.Toast; + +import com.mogujie.tt.DB.entity.UserEntity; +import com.mogujie.tt.R; +import com.mogujie.tt.config.SysConstant; +import com.mogujie.tt.utils.IMUIHelper; +import com.mogujie.tt.imservice.event.UserInfoEvent; +import com.mogujie.tt.imservice.manager.IMLoginManager; +import com.mogujie.tt.imservice.service.IMService; +import com.mogujie.tt.ui.activity.SettingActivity; +import com.mogujie.tt.imservice.support.IMServiceConnector; +import com.mogujie.tt.utils.FileUtil; +import com.mogujie.tt.ui.widget.IMBaseImageView; +import com.nostra13.universalimageloader.core.ImageLoader; + +import java.io.File; + +import de.greenrobot.event.EventBus; + +public class MyFragment extends MainFragment { + private View curView = null; + private View contentView; + private View exitView; + private View clearView; + private View settingView; + + private IMServiceConnector imServiceConnector = new IMServiceConnector(){ + @Override + public void onServiceDisconnected() {} + + @Override + public void onIMServiceConnected() { + if (curView == null) { + return; + } + IMService imService = imServiceConnector.getIMService(); + if (imService == null) { + return; + } + if (!imService.getContactManager().isUserDataReady()) { + logger.i("detail#contact data are not ready"); + } else { + init(imService); + } + } + }; + + @Override + public View onCreateView(LayoutInflater inflater, ViewGroup container, + Bundle savedInstanceState) { + + + imServiceConnector.connect(getActivity()); + EventBus.getDefault().register(this); + + if (null != curView) { + ((ViewGroup) curView.getParent()).removeView(curView); + return curView; + } + curView = inflater.inflate(R.layout.tt_fragment_my, topContentView); + + initRes(); + + return curView; + } + + /** + * @Description 初始化资源 + */ + private void initRes() { + super.init(curView); + + contentView = curView.findViewById(R.id.content); + exitView = curView.findViewById(R.id.exitPage); + clearView = curView.findViewById(R.id.clearPage); + settingView = curView.findViewById(R.id.settingPage); + + clearView.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View view) { + AlertDialog.Builder builder = new AlertDialog.Builder(new ContextThemeWrapper(getActivity(), android.R.style.Theme_Holo_Light_Dialog)); + LayoutInflater inflater = (LayoutInflater)getActivity().getSystemService(Context.LAYOUT_INFLATER_SERVICE); + View dialog_view = inflater.inflate(R.layout.tt_custom_dialog, null); + final EditText editText = (EditText)dialog_view.findViewById(R.id.dialog_edit_content); + editText.setVisibility(View.GONE); + TextView textText = (TextView)dialog_view.findViewById(R.id.dialog_title); + textText.setText(R.string.clear_cache_tip); + builder.setView(dialog_view); + + builder.setPositiveButton(getString(R.string.tt_ok), new DialogInterface.OnClickListener() { + + @Override + public void onClick(DialogInterface dialog, int which) { + ImageLoader.getInstance().clearMemoryCache(); + ImageLoader.getInstance().clearDiskCache(); + new Handler().postDelayed(new Runnable() { + @Override + public void run() { + FileUtil.deleteHistoryFiles(new File(Environment.getExternalStorageDirectory().toString() + + File.separator + "MGJ-IM"+File.separator),System.currentTimeMillis()); + Toast toast = Toast.makeText(getActivity(),R.string.thumb_remove_finish,Toast.LENGTH_LONG); + toast.setGravity(Gravity.CENTER,0,0); + toast.show(); + } + },500); + + dialog.dismiss(); + } + }); + + builder.setNegativeButton(getString(R.string.tt_cancel), new DialogInterface.OnClickListener() { + @Override + public void onClick(DialogInterface dialogInterface, int i) { + dialogInterface.dismiss(); + } + }); + builder.show(); + } + }); + exitView.setOnClickListener(new View.OnClickListener() { + + @Override + public void onClick(View v) { + + AlertDialog.Builder builder = new AlertDialog.Builder(new ContextThemeWrapper(getActivity(), android.R.style.Theme_Holo_Light_Dialog)); + LayoutInflater inflater = (LayoutInflater)getActivity().getSystemService(Context.LAYOUT_INFLATER_SERVICE); + View dialog_view = inflater.inflate(R.layout.tt_custom_dialog, null); + final EditText editText = (EditText)dialog_view.findViewById(R.id.dialog_edit_content); + editText.setVisibility(View.GONE); + TextView textText = (TextView)dialog_view.findViewById(R.id.dialog_title); + textText.setText(R.string.exit_teamtalk_tip); + builder.setView(dialog_view); + builder.setPositiveButton(getString(R.string.tt_ok), new DialogInterface.OnClickListener() { + + @Override + public void onClick(DialogInterface dialog, int which) { + IMLoginManager.instance().setKickout(false); + IMLoginManager.instance().logOut(); + getActivity().finish(); + dialog.dismiss(); + } + }); + + builder.setNegativeButton(getString(R.string.tt_cancel), new DialogInterface.OnClickListener() { + @Override + public void onClick(DialogInterface dialogInterface, int i) { + dialogInterface.dismiss(); + } + }); + builder.show(); + + } + }); + + settingView.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + // 跳转到配置页面 + startActivity(new Intent(MyFragment.this.getActivity(), SettingActivity.class)); + } + }); + hideContent(); + + // 设置顶部标题栏 + setTopTitle(getActivity().getString(R.string.page_me)); + // 设置页面其它控件 + + } + + private void hideContent() { + if (contentView != null) { + contentView.setVisibility(View.GONE); + } + } + + private void showContent() { + if (contentView != null) { + contentView.setVisibility(View.VISIBLE); + } + } + @Override + public void onActivityCreated(Bundle savedInstanceState) { + super.onActivityCreated(savedInstanceState); + } + + @Override + public void onHiddenChanged(boolean hidden) { + super.onHiddenChanged(hidden); + } + + @Override + public void onDestroy() { + super.onDestroy(); + // 应该放在这里嘛?? + imServiceConnector.disconnect(getActivity()); + EventBus.getDefault().unregister(this); + } + + @Override + protected void initHandler() { + } + + public void onEventMainThread(UserInfoEvent event){ + switch (event){ + case USER_INFO_OK: + init(imServiceConnector.getIMService()); + } + } + + + private void init(IMService imService) { + showContent(); + hideProgressBar(); + + if (imService == null) { + return; + } + + final UserEntity loginContact = imService.getLoginManager().getLoginInfo(); + if (loginContact == null) { + return; + } + TextView nickNameView = (TextView) curView.findViewById(R.id.nickName); + TextView userNameView = (TextView) curView.findViewById(R.id.userName); + IMBaseImageView portraitImageView = (IMBaseImageView) curView.findViewById(R.id.user_portrait); + + nickNameView.setText(loginContact.getMainName()); + userNameView.setText(loginContact.getRealName()); + + //头像设置 + portraitImageView.setDefaultImageRes(R.drawable.tt_default_user_portrait_corner); + portraitImageView.setCorner(15); + portraitImageView.setAvatarAppend(SysConstant.AVATAR_APPEND_200); + portraitImageView.setImageResource(R.drawable.tt_default_user_portrait_corner); + portraitImageView.setImageUrl(loginContact.getAvatar()); + + RelativeLayout userContainer = (RelativeLayout) curView.findViewById(R.id.user_container); + userContainer.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View arg0) { + IMUIHelper.openUserProfileActivity(getActivity(), loginContact.getPeerId()); + } + }); + } + + private void deleteFilesByDirectory(File directory) { + if (directory != null && directory.exists() && directory.isDirectory()) { + for (File item : directory.listFiles()) { + item.delete(); + } + } + else { + logger.e("fragment#deleteFilesByDirectory, failed"); + } + } +} diff --git a/android/app/src/main/java/com/mogujie/tt/ui/fragment/SearchFragment.java b/android/app/src/main/java/com/mogujie/tt/ui/fragment/SearchFragment.java new file mode 100644 index 000000000..3e1a8de27 --- /dev/null +++ b/android/app/src/main/java/com/mogujie/tt/ui/fragment/SearchFragment.java @@ -0,0 +1,148 @@ +package com.mogujie.tt.ui.fragment; + +import android.os.Bundle; +import android.text.Editable; +import android.text.TextWatcher; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.ListView; + +import com.mogujie.tools.ScreenTools; +import com.mogujie.tt.DB.entity.DepartmentEntity; +import com.mogujie.tt.DB.entity.GroupEntity; +import com.mogujie.tt.DB.entity.UserEntity; +import com.mogujie.tt.R; +import com.mogujie.tt.imservice.support.IMServiceConnector; +import com.mogujie.tt.imservice.service.IMService; +import com.mogujie.tt.ui.adapter.SearchAdapter; +import com.mogujie.tt.ui.base.TTBaseFragment; +import com.mogujie.tt.utils.Logger; + +import java.util.List; + +/** + * @yingmu modify + */ +public class SearchFragment extends TTBaseFragment { + + private Logger logger = Logger.getLogger(SearchFragment.class); + private View curView = null; + private ListView listView; + private View noSearchResultView; + private SearchAdapter adapter; + IMService imService; + + private IMServiceConnector imServiceConnector = new IMServiceConnector(){ + @Override + public void onIMServiceConnected() { + logger.d("config#onIMServiceConnected"); + imService = imServiceConnector.getIMService(); + //init set adapter service + initAdapter(); + } + @Override + public void onServiceDisconnected() { + } + }; + + @Override + public View onCreateView(LayoutInflater inflater, ViewGroup container, + Bundle savedInstanceState) { + + imServiceConnector.connect(this.getActivity()); + if (null != curView) { + ((ViewGroup) curView.getParent()).removeView(curView); + return curView; + } + curView = inflater.inflate(R.layout.tt_fragment_search, topContentView); + noSearchResultView = curView.findViewById(R.id.layout_no_search_result); + initTopBar(); + listView = (ListView) curView.findViewById(R.id.search); + return curView; + } + + @Override + public void onResume() { + super.onResume(); + } + + private void initTopBar() { + setTopBar(R.drawable.tt_top_default_bk); + showTopSearchBar(); + setTopLeftButton(R.drawable.tt_top_back); + hideTopRightButton(); + + topLeftBtn.setPadding(0, 0, ScreenTools.instance(getActivity()).dip2px(30), 0); + topLeftBtn.setOnClickListener(new View.OnClickListener() { + + @Override + public void onClick(View arg0) { + getActivity().finish(); + } + }); + + topSearchEdt.addTextChangedListener(new TextWatcher() { + @Override + public void onTextChanged(CharSequence s, int start, int before, + int count) { + String key = s.toString(); + adapter.setSearchKey(key); + if(key.isEmpty()) + { + adapter.clear(); + noSearchResultView.setVisibility(View.GONE); + }else{ + searchEntityLists(key); + } + } + + @Override + public void beforeTextChanged(CharSequence s, int start, int count, + int after) {} + @Override + public void afterTextChanged(Editable s) { + } + }); + } + + private void initAdapter(){ + adapter = new SearchAdapter(getActivity(),imService); + listView.setAdapter(adapter); + listView.setOnItemClickListener(adapter); + listView.setOnItemLongClickListener(adapter); + } + + // 文字高亮search 模块 + private void searchEntityLists(String key) { + List contactList = imService.getContactManager().getSearchContactList(key); + int contactSize = contactList.size(); + adapter.putUserList(contactList); + + List groupList = imService.getGroupManager().getSearchAllGroupList(key); + int groupSize = groupList.size(); + adapter.putGroupList(groupList); + + List departmentList = imService.getContactManager().getSearchDepartList(key); + int deptSize = departmentList.size(); + adapter.putDeptList(departmentList); + + int sum = contactSize + groupSize +deptSize; + adapter.notifyDataSetChanged(); + if(sum <= 0){ + noSearchResultView.setVisibility(View.VISIBLE); + }else{ + noSearchResultView.setVisibility(View.GONE); + } + } + + @Override + protected void initHandler() { + } + + @Override + public void onDestroy() { + imServiceConnector.disconnect(getActivity()); + super.onDestroy(); + } +} diff --git a/android/app/src/main/java/com/mogujie/tt/ui/fragment/SettingFragment.java b/android/app/src/main/java/com/mogujie/tt/ui/fragment/SettingFragment.java new file mode 100644 index 000000000..8aab483e2 --- /dev/null +++ b/android/app/src/main/java/com/mogujie/tt/ui/fragment/SettingFragment.java @@ -0,0 +1,107 @@ +package com.mogujie.tt.ui.fragment; + +import android.os.Bundle; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.CheckBox; + +import com.mogujie.tt.DB.sp.ConfigurationSp; +import com.mogujie.tt.R; +import com.mogujie.tt.config.SysConstant; +import com.mogujie.tt.imservice.service.IMService; +import com.mogujie.tt.ui.helper.CheckboxConfigHelper; +import com.mogujie.tt.ui.base.TTBaseFragment; +import com.mogujie.tt.imservice.support.IMServiceConnector; +import com.mogujie.tt.utils.Logger; + +/** + * 设置页面 + */ +public class SettingFragment extends TTBaseFragment{ + private View curView = null; + private CheckBox notificationNoDisturbCheckBox; + private CheckBox notificationGotSoundCheckBox; + private CheckBox notificationGotVibrationCheckBox; + CheckboxConfigHelper checkBoxConfiger = new CheckboxConfigHelper(); + + + private IMServiceConnector imServiceConnector = new IMServiceConnector(){ + @Override + public void onIMServiceConnected() { + logger.d("config#onIMServiceConnected"); + IMService imService = imServiceConnector.getIMService(); + if (imService != null) { + checkBoxConfiger.init(imService.getConfigSp()); + initOptions(); + } + } + + @Override + public void onServiceDisconnected() { + } + }; + + @Override + public View onCreateView(LayoutInflater inflater, ViewGroup container, + Bundle savedInstanceState) { + imServiceConnector.connect(this.getActivity()); + if (null != curView) { + ((ViewGroup) curView.getParent()).removeView(curView); + return curView; + } + curView = inflater.inflate(R.layout.tt_fragment_setting, topContentView); + initRes(); + return curView; + } + + /** + * Called when the fragment is no longer in use. This is called + * after {@link #onStop()} and before {@link #onDetach()}. + */ + @Override + public void onDestroy() { + super.onDestroy(); + imServiceConnector.disconnect(getActivity()); + } + + private void initOptions() { + notificationNoDisturbCheckBox = (CheckBox) curView.findViewById(R.id.NotificationNoDisturbCheckbox); + notificationGotSoundCheckBox = (CheckBox) curView.findViewById(R.id.notifyGotSoundCheckBox); + notificationGotVibrationCheckBox = (CheckBox) curView.findViewById(R.id.notifyGotVibrationCheckBox); +// saveTrafficModeCheckBox = (CheckBox) curView.findViewById(R.id.saveTrafficCheckBox); + + checkBoxConfiger.initCheckBox(notificationNoDisturbCheckBox, SysConstant.SETTING_GLOBAL, ConfigurationSp.CfgDimension.NOTIFICATION ); + checkBoxConfiger.initCheckBox(notificationGotSoundCheckBox, SysConstant.SETTING_GLOBAL , ConfigurationSp.CfgDimension.SOUND); + checkBoxConfiger.initCheckBox(notificationGotVibrationCheckBox, SysConstant.SETTING_GLOBAL,ConfigurationSp.CfgDimension.VIBRATION ); +// checkBoxConfiger.initCheckBox(saveTrafficModeCheckBox, ConfigDefs.SETTING_GLOBAL, ConfigDefs.KEY_SAVE_TRAFFIC_MODE, ConfigDefs.DEF_VALUE_SAVE_TRAFFIC_MODE); + } + + @Override + public void onResume() { + + super.onResume(); + } + + /** + * @Description 初始化资源 + */ + private void initRes() { + // 设置标题栏 + setTopTitle(getActivity().getString(R.string.setting_page_name)); + setTopLeftButton(R.drawable.tt_top_back); + topLeftContainerLayout.setOnClickListener(new View.OnClickListener() { + + @Override + public void onClick(View arg0) { + getActivity().finish(); + } + }); + setTopLeftText(getResources().getString(R.string.top_left_back)); + } + + @Override + protected void initHandler() { + } + +} diff --git a/android/app/src/main/java/com/mogujie/tt/ui/fragment/UserInfoFragment.java b/android/app/src/main/java/com/mogujie/tt/ui/fragment/UserInfoFragment.java new file mode 100644 index 000000000..3b6c8aa6b --- /dev/null +++ b/android/app/src/main/java/com/mogujie/tt/ui/fragment/UserInfoFragment.java @@ -0,0 +1,261 @@ +package com.mogujie.tt.ui.fragment; + +import android.content.Intent; +import android.graphics.Color; +import android.net.Uri; +import android.os.Bundle; +import android.os.Handler; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.Button; +import android.widget.TextView; + +import com.mogujie.tt.DB.entity.DepartmentEntity; +import com.mogujie.tt.DB.entity.UserEntity; +import com.mogujie.tt.R; +import com.mogujie.tt.config.DBConstant; +import com.mogujie.tt.config.IntentConstant; +import com.mogujie.tt.config.SysConstant; +import com.mogujie.tt.utils.IMUIHelper; +import com.mogujie.tt.imservice.event.UserInfoEvent; +import com.mogujie.tt.imservice.manager.IMLoginManager; +import com.mogujie.tt.imservice.service.IMService; +import com.mogujie.tt.ui.activity.DetailPortraitActivity; +import com.mogujie.tt.imservice.support.IMServiceConnector; +import com.mogujie.tt.ui.widget.IMBaseImageView; + +import java.util.ArrayList; + +/** + * 1.18 添加currentUser变量 + */ +public class UserInfoFragment extends MainFragment { + + private View curView = null; + private IMService imService; + private UserEntity currentUser; + private int currentUserId; + private IMServiceConnector imServiceConnector = new IMServiceConnector(){ + @Override + public void onIMServiceConnected() { + logger.d("detail#onIMServiceConnected"); + + imService = imServiceConnector.getIMService(); + if (imService == null) { + logger.e("detail#imService is null"); + return; + } + + currentUserId = getActivity().getIntent().getIntExtra(IntentConstant.KEY_PEERID,0); + if(currentUserId == 0){ + logger.e("detail#intent params error!!"); + return; + } + currentUser = imService.getContactManager().findContact(currentUserId); + if(currentUser != null) { + initBaseProfile(); + initDetailProfile(); + } + ArrayList userIds = new ArrayList<>(1); + //just single type + userIds.add(currentUserId); + imService.getContactManager().reqGetDetaillUsers(userIds); + } + @Override + public void onServiceDisconnected() {} + }; + + @Override + public void onDestroyView() { + super.onDestroyView(); + imServiceConnector.disconnect(getActivity()); + } + + @Override + public View onCreateView(LayoutInflater inflater, ViewGroup container, + Bundle savedInstanceState) { + + imServiceConnector.connect(getActivity()); + if (null != curView) { + ((ViewGroup) curView.getParent()).removeView(curView); + return curView; + } + curView = inflater.inflate(R.layout.tt_fragment_user_detail, topContentView); + super.init(curView); + showProgressBar(); + initRes(); + return curView; + } + + @Override + public void onResume() { + Intent intent = getActivity().getIntent(); + if (null != intent) { + String fromPage = intent.getStringExtra(IntentConstant.USER_DETAIL_PARAM); + setTopLeftText(fromPage); + } + super.onResume(); + } + + /** + * @Description 初始化资源 + */ + private void initRes() { + // 设置标题栏 + setTopTitle(getActivity().getString(R.string.page_user_detail)); + setTopLeftButton(R.drawable.tt_top_back); + topLeftContainerLayout.setOnClickListener(new View.OnClickListener() { + + @Override + public void onClick(View arg0) { + getActivity().finish(); + } + }); + setTopLeftText(getResources().getString(R.string.top_left_back)); + } + + @Override + protected void initHandler() { + } + + public void onEventMainThread(UserInfoEvent event){ + switch (event){ + case USER_INFO_UPDATE: + UserEntity entity = imService.getContactManager().findContact(currentUserId); + if(entity !=null && currentUser.equals(entity)){ + initBaseProfile(); + initDetailProfile(); + } + break; + } + } + + + private void initBaseProfile() { + logger.d("detail#initBaseProfile"); + IMBaseImageView portraitImageView = (IMBaseImageView) curView.findViewById(R.id.user_portrait); + + setTextViewContent(R.id.nickName, currentUser.getMainName()); + setTextViewContent(R.id.userName, currentUser.getRealName()); + //头像设置 + portraitImageView.setDefaultImageRes(R.drawable.tt_default_user_portrait_corner); + portraitImageView.setCorner(8); + portraitImageView.setAvatarAppend(SysConstant.AVATAR_APPEND_200); + portraitImageView.setImageResource(R.drawable.tt_default_user_portrait_corner); + portraitImageView.setImageUrl(currentUser.getAvatar()); + + portraitImageView.setOnClickListener(new View.OnClickListener() { + + @Override + public void onClick(View v) { + Intent intent = new Intent(getActivity(), DetailPortraitActivity.class); + intent.putExtra(IntentConstant.KEY_AVATAR_URL, currentUser.getAvatar()); + intent.putExtra(IntentConstant.KEY_IS_IMAGE_CONTACT_AVATAR, true); + + startActivity(intent); + } + }); + + // 设置界面信息 + Button chatBtn = (Button) curView.findViewById(R.id.chat_btn); + if (currentUserId == imService.getLoginManager().getLoginId()) { + chatBtn.setVisibility(View.GONE); + }else{ + chatBtn.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View arg0) { + IMUIHelper.openChatActivity(getActivity(),currentUser.getSessionKey()); + getActivity().finish(); + } + }); + + } + } + + private void initDetailProfile() { + logger.d("detail#initDetailProfile"); + hideProgressBar(); + DepartmentEntity deptEntity = imService.getContactManager().findDepartment(currentUser.getDepartmentId()); + setTextViewContent(R.id.department,deptEntity.getDepartName()); + setTextViewContent(R.id.telno, currentUser.getPhone()); + setTextViewContent(R.id.email, currentUser.getEmail()); + + View phoneView = curView.findViewById(R.id.phoneArea); + View emailView = curView.findViewById(R.id.emailArea); + IMUIHelper.setViewTouchHightlighted(phoneView); + IMUIHelper.setViewTouchHightlighted(emailView); + + emailView.setOnClickListener(new View.OnClickListener(){ + @Override + public void onClick(View view) { + if (currentUserId == IMLoginManager.instance().getLoginId()) + return; + IMUIHelper.showCustomDialog(getActivity(),View.GONE,String.format(getString(R.string.confirm_send_email),currentUser.getEmail()),new IMUIHelper.dialogCallback() { + @Override + public void callback() { + Intent data=new Intent(Intent.ACTION_SENDTO); + data.setData(Uri.parse("mailto:" + currentUser.getEmail())); + data.putExtra(Intent.EXTRA_SUBJECT, ""); + data.putExtra(Intent.EXTRA_TEXT, ""); + startActivity(data); + } + }); + } + }); + + phoneView.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + if (currentUserId == IMLoginManager.instance().getLoginId()) + return; + IMUIHelper.showCustomDialog(getActivity(),View.GONE,String.format(getString(R.string.confirm_dial),currentUser.getPhone()),new IMUIHelper.dialogCallback() { + @Override + public void callback() { + new Handler().postDelayed(new Runnable() { + @Override + public void run() { + IMUIHelper.callPhone(getActivity(), currentUser.getPhone()); + } + },0); + } + }); + } + }); + + setSex(currentUser.getGender()); + } + + private void setTextViewContent(int id, String content) { + TextView textView = (TextView) curView.findViewById(id); + if (textView == null) { + return; + } + + textView.setText(content); + } + + private void setSex(int sex) { + if (curView == null) { + return; + } + + TextView sexTextView = (TextView) curView.findViewById(R.id.sex); + if (sexTextView == null) { + return; + } + + int textColor = Color.rgb(255, 138, 168); //xiaoxian + String text = getString(R.string.sex_female_name); + + if (sex == DBConstant.SEX_MAILE) { + textColor = Color.rgb(144, 203, 1); + text = getString(R.string.sex_male_name); + } + + sexTextView.setVisibility(View.VISIBLE); + sexTextView.setText(text); + sexTextView.setTextColor(textColor); + } + +} diff --git a/android/app/src/main/java/com/mogujie/tt/ui/fragment/WebviewFragment.java b/android/app/src/main/java/com/mogujie/tt/ui/fragment/WebviewFragment.java new file mode 100644 index 000000000..00a5c0703 --- /dev/null +++ b/android/app/src/main/java/com/mogujie/tt/ui/fragment/WebviewFragment.java @@ -0,0 +1,103 @@ +package com.mogujie.tt.ui.fragment; + +import android.annotation.SuppressLint; +import android.net.Uri; +import android.os.Bundle; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.webkit.WebView; +import android.webkit.WebViewClient; + +import com.mogujie.tt.R; + +@SuppressLint("SetJavaScriptEnabled") +public class WebviewFragment extends MainFragment { + private View curView = null; + private static String url; + + @Override + public View onCreateView(LayoutInflater inflater, ViewGroup container, + Bundle savedInstanceState) { + extractUidFromUri(); + if (null != curView) { + ((ViewGroup) curView.getParent()).removeView(curView); + return curView; + } + curView = inflater.inflate(R.layout.tt_fragment_webview, topContentView); + super.init(curView); + showProgressBar(); + initRes(); + + return curView; + } + + private void initRes() { + // 设置顶部标题栏 + setTopTitleBold(getActivity().getString(R.string.main_innernet)); + setTopLeftButton(R.drawable.tt_top_back); + topLeftContainerLayout.setOnClickListener(new View.OnClickListener() { + + @Override + public void onClick(View arg0) { + getActivity().finish(); + } + }); + setTopLeftText(getResources().getString(R.string.top_left_back)); + + WebView webView = (WebView) curView.findViewById(R.id.webView1); + webView.getSettings().setJavaScriptEnabled(true); + webView.loadUrl(url); + webView.setVerticalScrollBarEnabled(false); + webView.setHorizontalScrollBarEnabled(false); + webView.setWebViewClient(new WebViewClient() { + + @Override + public void onPageFinished(WebView view, String url) { + setTopTitle(view.getTitle()); + hideProgressBar(); + } + + @Override + public void onReceivedError(WebView view, int errorCode, + String description, String failingUrl) { + // TODO Auto-generated method stub + super.onReceivedError(view, errorCode, description, failingUrl); + hideProgressBar(); + } + + }); + } + + @Override + public void onDestroy() { + super.onDestroy(); + } + + @Override + protected void initHandler() { + } + + /** + * @param str + */ + public static void setUrl(String str) { + url = str; + } + + private static final String SCHEMA ="com.mogujie.tt://message_private_url"; + private static final String PARAM_UID ="uid"; + private static final Uri PROFILE_URI = Uri.parse(SCHEMA); + private void extractUidFromUri() { + Uri uri = getActivity().getIntent().getData(); + if (uri !=null && PROFILE_URI.getScheme().equals(uri.getScheme())) { + url = uri.getQueryParameter(PARAM_UID); + } + if(url.indexOf("www") == 0){ + url = "http://"+url; + }else if(url.indexOf("https") == 0){ + String bUid = url.substring(5, url.length()); + url = "http"+bUid; + } + } +} diff --git a/android/app/src/main/java/com/mogujie/tt/ui/helper/AudioPlayerHandler.java b/android/app/src/main/java/com/mogujie/tt/ui/helper/AudioPlayerHandler.java new file mode 100644 index 000000000..1f8a9cd39 --- /dev/null +++ b/android/app/src/main/java/com/mogujie/tt/ui/helper/AudioPlayerHandler.java @@ -0,0 +1,142 @@ + +package com.mogujie.tt.ui.helper; + +import android.content.Context; +import android.media.AudioManager; + +import com.mogujie.tt.imservice.event.AudioEvent; +import com.mogujie.tt.imservice.support.audio.SpeexDecoder; +import com.mogujie.tt.utils.Logger; + +import java.io.File; + +import de.greenrobot.event.EventBus; + +public class AudioPlayerHandler{ + private String currentPlayPath = null; + private SpeexDecoder speexdec = null; + private Thread th = null; + + private static AudioPlayerHandler instance = null; + private Logger logger = Logger.getLogger(AudioPlayerHandler.class); + + public static AudioPlayerHandler getInstance() { + if (null == instance) { + synchronized(AudioPlayerHandler.class){ + instance = new AudioPlayerHandler(); + EventBus.getDefault().register(instance); + } + } + return instance; + } + + + //语音播放的模式 + public void setAudioMode(int mode,Context ctx) { + if (mode != AudioManager.MODE_NORMAL && mode != AudioManager.MODE_IN_CALL) { + return; + } + AudioManager audioManager = (AudioManager) ctx.getSystemService(Context.AUDIO_SERVICE); + audioManager.setMode(mode); + } + + /**messagePop调用*/ + public int getAudioMode(Context ctx) { + AudioManager audioManager = (AudioManager) ctx.getSystemService(Context.AUDIO_SERVICE); + return audioManager.getMode(); + } + + public void clear(){ + if (isPlaying()){ + stopPlayer(); + } + EventBus.getDefault().unregister(instance); + instance = null; + } + + + private AudioPlayerHandler() { + } + + /** + * yingmu modify + * speexdec 由于线程模型 + * */ + public interface AudioListener{ + public void onStop(); + } + + private AudioListener audioListener; + + public void setAudioListener(AudioListener audioListener) { + this.audioListener = audioListener; + } + + private void stopAnimation(){ + if(audioListener!=null){ + audioListener.onStop(); + } + } + + public void onEventMainThread(AudioEvent audioEvent){ + switch (audioEvent){ + case AUDIO_STOP_PLAY:{ + currentPlayPath = null; + stopPlayer(); + }break; + } + } + + public void stopPlayer() { + try { + if (null != th) { + th.interrupt(); + th = null; + Thread.currentThread().interrupt(); + } else { + } + } catch (Exception e) { + logger.e(e.getMessage()); + }finally { + stopAnimation(); + } + } + + public boolean isPlaying() { + return null != th; + } + + public void startPlay(String filePath) { + this.currentPlayPath = filePath; + try { + speexdec = new SpeexDecoder(new File(this.currentPlayPath)); + RecordPlayThread rpt = new RecordPlayThread(); + if (null == th) + th = new Thread(rpt); + th.start(); + } catch (Exception e) { + // 关闭动画很多地方需要写,是不是需要重新考虑一下@yingmu + logger.e(e.getMessage()); + stopAnimation(); + } + } + + + + class RecordPlayThread extends Thread { + public void run() { + try { + if (null != speexdec) + speexdec.decode(); + + } catch (Exception e) { + logger.e(e.getMessage()); + stopAnimation(); + } + } + }; + + public String getCurrentPlayPath() { + return currentPlayPath; + } +} diff --git a/android/app/src/main/java/com/mogujie/tt/ui/helper/AudioRecordHandler.java b/android/app/src/main/java/com/mogujie/tt/ui/helper/AudioRecordHandler.java new file mode 100644 index 000000000..6f38d95ab --- /dev/null +++ b/android/app/src/main/java/com/mogujie/tt/ui/helper/AudioRecordHandler.java @@ -0,0 +1,156 @@ + +package com.mogujie.tt.ui.helper; + +import android.media.AudioFormat; +import android.media.AudioRecord; +import android.media.MediaRecorder; +import android.os.Message; + +import com.mogujie.tt.config.HandlerConstant; +import com.mogujie.tt.config.SysConstant; +import com.mogujie.tt.imservice.support.audio.SpeexEncoder; +import com.mogujie.tt.ui.activity.MessageActivity; +import com.mogujie.tt.utils.Logger; + +public class AudioRecordHandler implements Runnable { + + private Logger logger = Logger.getLogger(AudioRecordHandler.class); + private volatile boolean isRecording; + private final Object mutex = new Object(); + private static final int frequency = 8000; + private static final int audioEncoding = AudioFormat.ENCODING_PCM_16BIT; + public static int packagesize = 160;// 320 + private String fileName = null; + private float recordTime = 0; + private long startTime = 0; + private long endTime = 0; + private long maxVolumeStart = 0; + private long maxVolumeEnd = 0; + private static AudioRecord recordInstance = null; + + public AudioRecordHandler(String fileName) { + super(); + this.fileName = fileName; + } + + public void run() { + try { + logger.d("chat#audio#in audio thread"); + SpeexEncoder encoder = new SpeexEncoder(this.fileName); + Thread encodeThread = new Thread(encoder); + encoder.setRecording(true); + logger.d("chat#audio#encoder thread starts"); + encodeThread.start(); + + synchronized (mutex) { + while (!this.isRecording) { + try { + mutex.wait(); + } catch (InterruptedException e) { + throw new IllegalStateException("Wait() interrupted!", e); + } + } + } + android.os.Process + .setThreadPriority(android.os.Process.THREAD_PRIORITY_URGENT_AUDIO); + + int bufferRead = 0; + int bufferSize = AudioRecord.getMinBufferSize(frequency, + AudioFormat.CHANNEL_IN_MONO, audioEncoding); + + short[] tempBuffer = new short[packagesize]; + try { + if (null == recordInstance) { + recordInstance = new AudioRecord(MediaRecorder.AudioSource.MIC, + frequency, AudioFormat.CHANNEL_IN_MONO, audioEncoding, + bufferSize); + } + + recordInstance.startRecording(); + recordTime = 0; + startTime = System.currentTimeMillis(); + maxVolumeStart = System.currentTimeMillis(); + while (this.isRecording) { + endTime = System.currentTimeMillis(); + recordTime = (float) ((endTime - startTime) / 1000.0f); + if (recordTime >= SysConstant.MAX_SOUND_RECORD_TIME) { + MessageActivity.getUiHandler().sendEmptyMessage( + HandlerConstant.RECORD_AUDIO_TOO_LONG); + break; + } + + bufferRead = recordInstance.read(tempBuffer, 0, packagesize); + if (bufferRead == AudioRecord.ERROR_INVALID_OPERATION) { + throw new IllegalStateException( + "read() returned AudioRecord.ERROR_INVALID_OPERATION"); + } else if (bufferRead == AudioRecord.ERROR_BAD_VALUE) { + throw new IllegalStateException( + "read() returned AudioRecord.ERROR_BAD_VALUE"); + } else if (bufferRead == AudioRecord.ERROR_INVALID_OPERATION) { + throw new IllegalStateException( + "read() returned AudioRecord.ERROR_INVALID_OPERATION"); + } + encoder.putData(tempBuffer, bufferRead); + maxVolumeEnd = System.currentTimeMillis(); + setMaxVolume(tempBuffer, bufferRead); + } + } catch (Exception e) { + logger.e(e.getMessage()); + } finally { + encoder.setRecording(false); + if (recordInstance != null) { + recordInstance.stop(); + recordInstance.release(); + recordInstance = null; + } else { + } + } + } catch (Exception e) { + logger.e(e.getMessage()); + } + } + + private void setMaxVolume(short[] buffer, int readLen) { + try { + if (maxVolumeEnd - maxVolumeStart < 100) { + return; + } + maxVolumeStart = maxVolumeEnd; + int max = 0; + for (int i = 0; i < readLen; i++) { + if (Math.abs(buffer[i]) > max) { + max = Math.abs(buffer[i]); + } + } + Message Msg = new Message(); + Msg.what = HandlerConstant.RECEIVE_MAX_VOLUME; + Msg.obj = max; + MessageActivity.getUiHandler().sendMessage(Msg); + } catch (Exception e) { + logger.e(e.getMessage()); + } + } + + public float getRecordTime() { + return recordTime; + } + + public void setRecordTime(float len) { + recordTime = len; + } + + public void setRecording(boolean isRec) { + synchronized (mutex) { + this.isRecording = isRec; + if (this.isRecording) { + mutex.notify(); + } + } + } + + public boolean isRecording() { + synchronized (mutex) { + return isRecording; + } + } +} diff --git a/android/app/src/main/java/com/mogujie/tt/ui/helper/BubbleImageHelper.java b/android/app/src/main/java/com/mogujie/tt/ui/helper/BubbleImageHelper.java new file mode 100644 index 000000000..dd906b378 --- /dev/null +++ b/android/app/src/main/java/com/mogujie/tt/ui/helper/BubbleImageHelper.java @@ -0,0 +1,131 @@ + +package com.mogujie.tt.ui.helper; + + +import android.content.Context; +import android.graphics.Bitmap; +import android.graphics.Bitmap.Config; +import android.graphics.BitmapFactory; +import android.graphics.Canvas; +import android.graphics.Matrix; +import android.graphics.Paint; +import android.graphics.PorterDuff; +import android.graphics.PorterDuffXfermode; +import android.graphics.Rect; + +//not use now +public class BubbleImageHelper { + private final static int MIN_WIDTH =120; + private final static int MAX_HEIGHT =300; + private final static int MAX_WIDTH =290; + private final static int MIN_HEIGHT =130; + + private Context context = null; + private static BubbleImageHelper instance = null; + + public static synchronized BubbleImageHelper getInstance(Context c) { + if (null == instance) { + instance = new BubbleImageHelper(c); + } + return instance; + } + + private BubbleImageHelper(Context c) { + context = c; + } + + private Bitmap getScaleImage(Bitmap bitmap, float width, float height) { + if (null == bitmap || width < 0.0f || height < 0.0f) { + return null; + } + Matrix matrix = new Matrix(); + float scaleWidth = width / bitmap.getWidth(); + float scaleHeight = height / bitmap.getHeight(); + matrix.postScale(scaleWidth, scaleHeight); + Bitmap resizeBmp = Bitmap.createBitmap(bitmap, 0, 0, bitmap.getWidth(), + bitmap.getHeight(), matrix, true); + return resizeBmp; + } + + public Bitmap getBubbleImageBitmap(Bitmap srcBitmap, int backgroundResourceID) { + if (null == srcBitmap) { + return null; + } + Bitmap background = null; + background = BitmapFactory.decodeResource(context.getResources(), + backgroundResourceID); + if (null == background) { + return null; + } + + Bitmap mask = null; + Bitmap newBitmap = null; + mask = srcBitmap; + resetSrcImgSize(srcBitmap); + + Bitmap tmp = getScaleImage(background, srcBitmap.getWidth(), srcBitmap.getHeight()); + if (null != tmp) { + background = tmp; + } else { + tmp = getScaleImage(srcBitmap, srcBitmap.getWidth(),srcBitmap.getHeight()); + if (null != tmp) { + mask = tmp; + } + } + + Config config = background.getConfig(); + if (null == config) { + config = Bitmap.Config.ARGB_8888; + } + + newBitmap = Bitmap.createBitmap(background.getWidth(), + background.getHeight(), config); + Canvas newCanvas = new Canvas(newBitmap); + + newCanvas.drawBitmap(background, 0, 0, null); + + Paint paint = new Paint(); + + paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC_ATOP)); + newCanvas.drawBitmap(mask, new Rect(0, 0, mask.getWidth(),mask.getHeight()), + new Rect(0, 0, background.getWidth(), background.getHeight()), + paint); + + return newBitmap; + } + + private void resetSrcImgSize(Bitmap srcBitmap){ + int srcWidth = srcBitmap.getWidth(); + int srcHeight = srcBitmap.getHeight(); + + if(srcWidth>srcHeight) { + srcWidth= MAX_WIDTH; + if (srcHeight < MIN_HEIGHT) { + srcHeight = MIN_HEIGHT; + } + if (srcHeight > MAX_HEIGHT) { + srcHeight = MAX_HEIGHT; + } + }else if(srcWidth MAX_WIDTH){ + srcWidth= MAX_WIDTH; + } + }else{ + if(srcWidth< MIN_WIDTH){ + srcWidth= MIN_WIDTH; + srcHeight = MIN_WIDTH; + } + if (srcHeight> MAX_HEIGHT){ + srcWidth= MAX_HEIGHT; + srcHeight = MAX_HEIGHT; + } + } + + srcBitmap = getScaleImage(srcBitmap, srcWidth, srcHeight); + } + +} diff --git a/android/app/src/main/java/com/mogujie/tt/ui/helper/CheckboxConfigHelper.java b/android/app/src/main/java/com/mogujie/tt/ui/helper/CheckboxConfigHelper.java new file mode 100644 index 000000000..c819e09b2 --- /dev/null +++ b/android/app/src/main/java/com/mogujie/tt/ui/helper/CheckboxConfigHelper.java @@ -0,0 +1,71 @@ +package com.mogujie.tt.ui.helper; + +import android.view.View; +import android.widget.CheckBox; + +import com.mogujie.tt.DB.sp.ConfigurationSp; +import com.mogujie.tt.utils.Logger; + +import java.util.HashSet; +import java.util.TreeSet; + +// 配置滑动按钮的简单封装 +public class CheckboxConfigHelper { + private Logger logger = Logger.getLogger(CheckboxConfigHelper.class); + private ConfigurationSp configMgr; + public CheckboxConfigHelper() { + } + public void init(ConfigurationSp configMgr){ + this.configMgr = configMgr; + } + + public void initTopCheckBox(final CheckBox checkBox, final String sessionKey){ + if (configMgr == null || checkBox == null) { + logger.e("config#configMgr is null"); + return; + } + boolean shouldCheck = false; + HashSet topList = configMgr.getSessionTopList(); + if(topList != null && topList.size() >0){ + shouldCheck = topList.contains(sessionKey); + } + checkBox.setChecked(shouldCheck); + + checkBox.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + configMgr.setSessionTop(sessionKey, checkBox.isChecked()); + } + }); + } + + public void initCheckBox(CheckBox checkBox,String key,ConfigurationSp.CfgDimension dimension) { + handleCheckBoxChanged(checkBox,key,dimension); + configCheckBox(checkBox,key,dimension); + } + + private void configCheckBox(CheckBox checkBox,String key,ConfigurationSp.CfgDimension dimension) { + + if (configMgr == null) { + logger.e("config#configMgr is null"); + return; + } + + boolean shouldCheck = configMgr.getCfg(key,dimension); + logger.d("config#%s is set %s", dimension, shouldCheck); + checkBox.setChecked(shouldCheck); + } + + private void handleCheckBoxChanged(final CheckBox checkBox,final String key,final ConfigurationSp.CfgDimension dimension) { + if (checkBox == null || configMgr == null) { + return; + } + + checkBox.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + configMgr.setCfg(key,dimension,checkBox.isChecked()); + } + }); + } +} diff --git a/android/app/src/main/java/com/mogujie/tt/ui/helper/CircleBitmapDisplayer.java b/android/app/src/main/java/com/mogujie/tt/ui/helper/CircleBitmapDisplayer.java new file mode 100644 index 000000000..db8745ae9 --- /dev/null +++ b/android/app/src/main/java/com/mogujie/tt/ui/helper/CircleBitmapDisplayer.java @@ -0,0 +1,63 @@ +package com.mogujie.tt.ui.helper; + +import android.graphics.Bitmap; +import android.graphics.Canvas; +import android.graphics.Paint; +import android.graphics.PorterDuff; +import android.graphics.PorterDuffXfermode; +import android.graphics.Rect; + +import com.nostra13.universalimageloader.core.assist.LoadedFrom; +import com.nostra13.universalimageloader.core.display.BitmapDisplayer; +import com.nostra13.universalimageloader.core.imageaware.ImageAware; + +/** + * Created by zhujian on 15/1/14. + */ +public class CircleBitmapDisplayer implements BitmapDisplayer { + + private float borderWidth = 0; + private int borderColor; + + public CircleBitmapDisplayer() { + super(); + } + + public CircleBitmapDisplayer(int borderColor, int borderWidth){ + super(); + this.borderColor = borderColor; + this.borderWidth = borderWidth; + } + + @Override + public void display(Bitmap bitmap, ImageAware imageAware, LoadedFrom loadedFrom) { + Bitmap output = Bitmap.createBitmap(bitmap.getWidth(), bitmap.getHeight(), Bitmap.Config.ARGB_4444); + + Canvas canvas = new Canvas(output); + + final int color = 0xff424242; + final Paint paint = new Paint(); + final Rect rect = new Rect(0, 0, bitmap.getWidth(), bitmap.getHeight()); + + paint.setAntiAlias(true); + canvas.drawARGB(0, 0, 0, 0); + paint.setColor(color); + + //--CROP THE IMAGE + canvas.drawCircle(bitmap.getWidth() / 2, bitmap.getHeight() / 2, bitmap.getWidth() / 2 - 1, paint); + paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC_IN)); + canvas.drawBitmap(bitmap, rect, rect, paint); + + //--ADD BORDER IF NEEDED + if(this.borderWidth > 0){ + final Paint paint2 = new Paint(); + paint2.setAntiAlias(true); + paint2.setColor(this.borderColor); + paint2.setStrokeWidth(this.borderWidth); + paint2.setStyle(Paint.Style.STROKE); + canvas.drawCircle(bitmap.getWidth() / 2, bitmap.getHeight() / 2, (float) (bitmap.getWidth() / 2 - Math.ceil(this.borderWidth / 2)), paint2); + } + imageAware.setImageBitmap(output); + } + +} diff --git a/android/app/src/main/java/com/mogujie/tt/ui/helper/Emoparser.java b/android/app/src/main/java/com/mogujie/tt/ui/helper/Emoparser.java new file mode 100644 index 000000000..cf0041d55 --- /dev/null +++ b/android/app/src/main/java/com/mogujie/tt/ui/helper/Emoparser.java @@ -0,0 +1,207 @@ + +package com.mogujie.tt.ui.helper; + +import android.annotation.SuppressLint; +import android.content.Context; +import android.graphics.drawable.Drawable; +import android.os.Handler; +import android.os.HandlerThread; +import android.os.Looper; +import android.text.SpannableStringBuilder; +import android.text.Spanned; +import android.text.style.ImageSpan; + +import com.mogujie.tt.R; +import com.mogujie.tt.utils.CommonUtil; +import com.mogujie.tt.utils.Logger; + +import java.io.IOException; +import java.util.HashMap; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +/** + * @Description 表情解析 + * @author Nana + * @date 2014-4-16 + */ +@SuppressLint("UseSparseArrays") +public class Emoparser { + private static Logger logger = Logger.getLogger(Emoparser.class); + + private Context context; + private String[] emoList; + private String[] yayaEmoList; + private Pattern mPattern; + private Pattern mYayaPattern; + private static HashMap phraseIdMap; + private static HashMap idPhraseMap; + private static HashMap yayaPhraseIdMap; + private static HashMap yayaIdPhraseMap; + private static Emoparser instance = null; + + public static boolean isGifEmo = false; + private final int DEFAULT_SMILEY_TEXTS = R.array.default_emo_phrase; + private final int YAYA_EMO_TEXTS = R.array.yaya_emo_phrase; + private final int[] DEFAULT_EMO_RES_IDS = { + R.drawable.tt_e0, R.drawable.tt_e1, + R.drawable.tt_e2, R.drawable.tt_e3, R.drawable.tt_e4, R.drawable.tt_e5, + R.drawable.tt_e6, R.drawable.tt_e7, R.drawable.tt_e8, R.drawable.tt_e9, + R.drawable.tt_e10, R.drawable.tt_e11, R.drawable.tt_e12, R.drawable.tt_e13, + R.drawable.tt_e14, R.drawable.tt_e15, R.drawable.tt_e16, R.drawable.tt_e17, + R.drawable.tt_e18, R.drawable.tt_e19, R.drawable.tt_e20, R.drawable.tt_e21, + R.drawable.tt_e22, R.drawable.tt_e23, R.drawable.tt_e24, R.drawable.tt_e25, + R.drawable.tt_e26, R.drawable.tt_e27, R.drawable.tt_e28, R.drawable.tt_e29, + R.drawable.tt_e30, R.drawable.tt_e31, R.drawable.tt_e32, R.drawable.tt_e33, + R.drawable.tt_e34, R.drawable.tt_e35, R.drawable.tt_e36, R.drawable.tt_e37, + R.drawable.tt_e38, R.drawable.tt_e39, R.drawable.tt_e40, R.drawable.tt_e41, + R.drawable.tt_e42, R.drawable.tt_e43, R.drawable.tt_e44, R.drawable.tt_e45 + }; + + private final int[] YAYA_EMO_RES_IDS = { + R.drawable.tt_yaya_e1, R.drawable.tt_yaya_e2, R.drawable.tt_yaya_e3, R.drawable.tt_yaya_e4, + R.drawable.tt_yaya_e5, R.drawable.tt_yaya_e6, R.drawable.tt_yaya_e7, R.drawable.tt_yaya_e8, + R.drawable.tt_yaya_e9, R.drawable.tt_yaya_e10, R.drawable.tt_yaya_e11, R.drawable.tt_yaya_e12, + R.drawable.tt_yaya_e13, R.drawable.tt_yaya_e14, R.drawable.tt_yaya_e15, R.drawable.tt_yaya_e16, + R.drawable.tt_yaya_e17, R.drawable.tt_yaya_e18, R.drawable.tt_yaya_e19 + }; + + public int[] getResIdList() { + return DEFAULT_EMO_RES_IDS; + } + + public int[] getYayaResIdList() { + return YAYA_EMO_RES_IDS; + } + + public static synchronized Emoparser getInstance(Context cxt) { + if (null == instance && null != cxt) { + instance = new Emoparser(cxt); + } + return instance; + } + + private Emoparser(Context cxt) { + context = cxt; + emoList = context.getResources().getStringArray(DEFAULT_SMILEY_TEXTS); + yayaEmoList = context.getResources().getStringArray(YAYA_EMO_TEXTS); + buildMap(); + buildYayaEmoMap(); + mPattern = buildPattern(); + mYayaPattern = buildYayaEmoPattern(); + } + + private void buildMap() { + if (DEFAULT_EMO_RES_IDS.length != emoList.length) { + throw new IllegalStateException("Smiley resource ID/text mismatch"); + } + phraseIdMap = new HashMap(emoList.length); + idPhraseMap = new HashMap(emoList.length); + for (int i = 0; i < emoList.length; i++) { + phraseIdMap.put(emoList[i], DEFAULT_EMO_RES_IDS[i]); + idPhraseMap.put(DEFAULT_EMO_RES_IDS[i], emoList[i]); + } + } + + private void buildYayaEmoMap(){ + if (YAYA_EMO_RES_IDS.length != yayaEmoList.length) { + throw new IllegalStateException("Yaya emo resource ID/text mismatch"); + } + yayaPhraseIdMap = new HashMap<>(yayaEmoList.length); + yayaIdPhraseMap = new HashMap<>(yayaEmoList.length); + for (int i = 0; i < yayaEmoList.length; i++) { + yayaPhraseIdMap.put(yayaEmoList[i], YAYA_EMO_RES_IDS[i]); + yayaIdPhraseMap.put(YAYA_EMO_RES_IDS[i], yayaEmoList[i]); + } + } + + public HashMap getPhraseIdMap() { + return phraseIdMap; + } + + public HashMap getIdPhraseMap() { + return idPhraseMap; + } + + public HashMap getYayaPhraseIdMap() { + return yayaPhraseIdMap; + } + + public HashMap getYayaIdPhraseMap() { + return yayaIdPhraseMap; + } + + private Pattern buildPattern() { + StringBuilder patternString = new StringBuilder(emoList.length * 3); + patternString.append('('); + for (String s : emoList) { + patternString.append(Pattern.quote(s)); + patternString.append('|'); + } + patternString.replace(patternString.length() - 1, + patternString.length(), ")"); + + return Pattern.compile(patternString.toString()); + } + + private Pattern buildYayaEmoPattern() { + StringBuilder patternString = new StringBuilder(yayaEmoList.length * 3); + patternString.append('('); + for (String s : yayaEmoList) { + patternString.append(Pattern.quote(s)); + patternString.append('|'); + } + patternString.replace(patternString.length() - 1, + patternString.length(), ")"); + + return Pattern.compile(patternString.toString()); + } + + public CharSequence emoCharsequence(CharSequence text) { + SpannableStringBuilder builder = new SpannableStringBuilder(text); + Matcher matcher = mPattern.matcher(text); + while (matcher.find()) { + int resId = phraseIdMap.get(matcher.group()); + Drawable drawable = context.getResources().getDrawable(resId); + int size = (int) (CommonUtil.getElementSzie(context) * 0.8); + drawable.setBounds(0, 0, size, size); + ImageSpan imageSpan = new ImageSpan(drawable, + ImageSpan.ALIGN_BOTTOM); + builder.setSpan(imageSpan, matcher.start(), matcher.end(), + Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); + } + + matcher = mYayaPattern.matcher(text); + while (matcher.find()) { + isGifEmo = true; + int resId = yayaPhraseIdMap.get(matcher.group()); + Drawable drawable = context.getResources().getDrawable(resId); + drawable.setBounds(0, 0, 105, 115); + ImageSpan imageSpan = new ImageSpan(drawable, + ImageSpan.ALIGN_BOTTOM); + builder.setSpan(imageSpan, matcher.start(), matcher.end(), + Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); + } + return builder; + } + + public int getResIdByCharSequence(CharSequence text) { + + Matcher matcher = mYayaPattern.matcher(text); + while (matcher.find()) { + int resId = yayaPhraseIdMap.get(matcher.group()); + return resId; + } + return 0; + } + + public boolean isMessageGif(CharSequence text){ + + Matcher matcher = mYayaPattern.matcher(text); + while (matcher.find()) { + return true; + } + return false; + } + +} diff --git a/android/app/src/main/java/com/mogujie/tt/ui/helper/GifAnimationDrawable.java b/android/app/src/main/java/com/mogujie/tt/ui/helper/GifAnimationDrawable.java new file mode 100644 index 000000000..5d27526ae --- /dev/null +++ b/android/app/src/main/java/com/mogujie/tt/ui/helper/GifAnimationDrawable.java @@ -0,0 +1,89 @@ +package com.mogujie.tt.ui.helper; + +import android.graphics.Bitmap; +import android.graphics.drawable.AnimationDrawable; +import android.graphics.drawable.BitmapDrawable; +import android.os.Handler; +import android.os.HandlerThread; + +import java.io.BufferedInputStream; +import java.io.IOException; +import java.io.InputStream; + +/** + * @author : fengzi on 15-1-25. + * @email : fengzi@mogujie.com. + * + * Creates an AnimationDrawable from a GIF image. + */ +public class GifAnimationDrawable extends AnimationDrawable +{ + private GifDecoder mGifDecoder; + private Bitmap mTmpBitmap; + private int height, width; + public Handler uiHandler; + + public GifAnimationDrawable(InputStream is,HandlerThread handlerThread,Handler workHandler,Handler uiHandler) throws IOException { + this(is, false,handlerThread,workHandler,uiHandler); + } + + public GifAnimationDrawable(InputStream is) throws IOException + { + this(is, false,null,null,null); + } + + public GifAnimationDrawable(InputStream is, boolean inline,HandlerThread handlerThread,Handler workHandler,Handler uiHandler) throws IOException + { + super(); + InputStream bis = is; + if(!BufferedInputStream.class.isInstance(bis)) bis = new BufferedInputStream(is, 32768); + mGifDecoder = new GifDecoder(); + mGifDecoder.read(bis); + mTmpBitmap = mGifDecoder.getFrame(0); + height = mTmpBitmap.getHeight(); + width = mTmpBitmap.getWidth(); + addFrame(new BitmapDrawable(mTmpBitmap), mGifDecoder.getDelay(0)); +// setOneShot(mGifDecoder.getLoopCount() != 0); +// setVisible(true, true); + this.uiHandler = uiHandler; + //TODO 临时解决方案 因为卡顿,所以暂时关闭播放 + if(inline){ + loader.run(); + }else{ + if(handlerThread!=null) + { + workHandler.postDelayed(loader, 0); + } + } + } + + private Runnable loader = new Runnable(){ + public void run() + { + mGifDecoder.complete(); + int i, n = mGifDecoder.getFrameCount(), t; + for(i=1;i frames; // frames read from current file + protected int frameCount; + + private boolean readComplete; + + public GifDecoder() + { + readComplete = false; + } + + private static class GifFrame { + public GifFrame(Bitmap im, int del) { + image = im; + delay = del; + } + + public Bitmap image; + public int delay; + } + + /** + * Gets display duration for specified frame. + * + * @param n + * int index of frame + * @return delay in milliseconds + */ + public int getDelay(int n) { + delay = -1; + if ((n >= 0) && (n < frameCount)) { + delay = frames.elementAt(n).delay; + //meets browser compatibility standards + if (delay < MIN_DELAY_ENFORCE_THRESHOLD) delay = MIN_DELAY; + } + return delay; + } + + /** + * Gets the number of frames read from file. + * + * @return frame count + */ + public int getFrameCount() { + return frameCount; + } + + /** + * Gets the first (or only) image read. + * + * @return BufferedBitmap containing first frame, or null if none. + */ + public Bitmap getBitmap() { + return getFrame(0); + } + + /** + * Gets the "Netscape" iteration count, if any. A count of 0 means repeat indefinitiely. + * + * @return iteration count if one was specified, else 1. + */ + public int getLoopCount() { + return loopCount; + } + + /** + * Creates new frame image from current data (and previous frames as specified by their disposition codes). + */ + protected void setPixels() { + // expose destination image's pixels as int array + int[] dest = new int[width * height]; + // fill in starting image contents based on last image's dispose code + if (lastDispose > 0) { + if (lastDispose == 3) { + // use image before last + int n = frameCount - 2; + if (n > 0) { + lastBitmap = getFrame(n - 1); + } else { + lastBitmap = null; + } + } + if (lastBitmap != null) { + lastBitmap.getPixels(dest, 0, width, 0, 0, width, height); + // copy pixels + if (lastDispose == 2) { + // fill last image rect area with background color + int c = 0; + if (!transparency) { + c = lastBgColor; + } + for (int i = 0; i < lrh; i++) { + int n1 = (lry + i) * width + lrx; + int n2 = n1 + lrw; + for (int k = n1; k < n2; k++) { + dest[k] = c; + } + } + } + } + } + // copy each source line to the appropriate place in the destination + int pass = 1; + int inc = 8; + int iline = 0; + for (int i = 0; i < ih; i++) { + int line = i; + if (interlace) { + if (iline >= ih) { + pass++; + switch (pass) { + case 2: + iline = 4; + break; + case 3: + iline = 2; + inc = 4; + break; + case 4: + iline = 1; + inc = 2; + break; + default: + break; + } + } + line = iline; + iline += inc; + } + line += iy; + if (line < height) { + int k = line * width; + int dx = k + ix; // start of line in dest + int dlim = dx + iw; // end of dest line + if ((k + width) < dlim) { + dlim = k + width; // past dest edge + } + int sx = i * iw; // start of line in source + while (dx < dlim) { + // map color and insert in destination + int index = ((int) pixels[sx++]) & 0xff; + int c = act[index]; + if (c != 0) { + dest[dx] = c; + } + dx++; + } + } + } + image = Bitmap.createBitmap(dest, width, height, Config.ARGB_4444); + } + + /** + * Gets the image contents of frame n. + * + * @return BufferedBitmap representation of frame, or null if n is invalid. + */ + public Bitmap getFrame(int n) { + if (frameCount <= 0) + return null; + n = n % frameCount; + return ((GifFrame) frames.elementAt(n)).image; + } + + /** + * Reads GIF image from stream + * + * @param is + * containing GIF file. + * @return read status code (0 = no errors) + */ + public int read(InputStream is) + { + init(); + if (is != null) { + in = is; + readHeader(); + if (!err()) { + readContents(); + if (frameCount < 0) { + status = STATUS_FORMAT_ERROR; + } + } + } else { + status = STATUS_OPEN_ERROR; + } + readComplete = true; + return status; + } + + public void complete() + { + readContents(); + try { + in.close(); + } catch (Exception e) { + } + } + + /** + * Decodes LZW image data into pixel array. Adapted from John Cristy's BitmapMagick. + */ + protected void decodeBitmapData() { + int nullCode = -1; + int npix = iw * ih; + int available, clear, code_mask, code_size, end_of_information, in_code, old_code, bits, code, count, i, datum, data_size, first, top, bi, pi; + if ((pixels == null) || (pixels.length < npix)) { + pixels = new byte[npix]; // allocate new pixel array + } + if (prefix == null) { + prefix = new short[MAX_STACK_SIZE]; + } + if (suffix == null) { + suffix = new byte[MAX_STACK_SIZE]; + } + if (pixelStack == null) { + pixelStack = new byte[MAX_STACK_SIZE + 1]; + } + // Initialize GIF data stream decoder. + data_size = read(); + clear = 1 << data_size; + end_of_information = clear + 1; + available = clear + 2; + old_code = nullCode; + code_size = data_size + 1; + code_mask = (1 << code_size) - 1; + for (code = 0; code < clear; code++) { + prefix[code] = 0; // XXX ArrayIndexOutOfBoundsException + suffix[code] = (byte) code; + } + // Decode GIF pixel stream. + datum = bits = count = first = top = pi = bi = 0; + for (i = 0; i < npix;) { + if (top == 0) { + if (bits < code_size) { + // Load bytes until there are enough bits for a code. + if (count == 0) { + // Read a new data block. + count = readBlock(); + if (count <= 0) { + break; + } + bi = 0; + } + datum += (((int) block[bi]) & 0xff) << bits; + bits += 8; + bi++; + count--; + continue; + } + // Get the next code. + code = datum & code_mask; + datum >>= code_size; + bits -= code_size; + // Interpret the code + if ((code > available) || (code == end_of_information)) { + break; + } + if (code == clear) { + // Reset decoder. + code_size = data_size + 1; + code_mask = (1 << code_size) - 1; + available = clear + 2; + old_code = nullCode; + continue; + } + if (old_code == nullCode) { + pixelStack[top++] = suffix[code]; + old_code = code; + first = code; + continue; + } + in_code = code; + if (code == available) { + pixelStack[top++] = (byte) first; + code = old_code; + } + while (code > clear) { + pixelStack[top++] = suffix[code]; + code = prefix[code]; + } + first = ((int) suffix[code]) & 0xff; + // Add a new string to the string table, + if (available >= MAX_STACK_SIZE) { + break; + } + pixelStack[top++] = (byte) first; + prefix[available] = (short) old_code; + suffix[available] = (byte) first; + available++; + if (((available & code_mask) == 0) && (available < MAX_STACK_SIZE)) { + code_size++; + code_mask += available; + } + old_code = in_code; + } + // Pop a pixel off the pixel stack. + top--; + pixels[pi++] = pixelStack[top]; + i++; + } + for (i = pi; i < npix; i++) { + pixels[i] = 0; // clear missing pixels + } + } + + /** + * Returns true if an error was encountered during reading/decoding + */ + protected boolean err() { + return status != STATUS_OK; + } + + /** + * Initializes or re-initializes reader + */ + protected void init() { + status = STATUS_OK; + frameCount = 0; + frames = new Vector(); + gct = null; + lct = null; + } + + /** + * Reads a single byte from the input stream. + */ + protected int read() { + int curByte = 0; + try { + curByte = in.read(); + } catch (Exception e) { + status = STATUS_FORMAT_ERROR; + } + return curByte; + } + + /** + * Reads next variable length block from input. + * + * @return number of bytes stored in "buffer" + */ + protected int readBlock() { + blockSize = read(); + int n = 0; + if (blockSize > 0) { + try { + int count = 0; + while (n < blockSize) { + count = in.read(block, n, blockSize - n); + if (count == -1) { + break; + } + n += count; + } + } catch (Exception e) { + e.printStackTrace(); + } + if (n < blockSize) { + status = STATUS_FORMAT_ERROR; + } + } + return n; + } + + /** + * Reads color table as 256 RGB integer values + * + * @param ncolors + * int number of colors to read + * @return int array containing 256 colors (packed ARGB with full alpha) + */ + protected int[] readColorTable(int ncolors) { + int nbytes = 3 * ncolors; + int[] tab = null; + byte[] c = new byte[nbytes]; + int n = 0; + try { + n = in.read(c); + } catch (Exception e) { + e.printStackTrace(); + } + if (n < nbytes) { + status = STATUS_FORMAT_ERROR; + } else { + tab = new int[256]; // max size to avoid bounds checks + int i = 0; + int j = 0; + while (i < ncolors) { + int r = ((int) c[j++]) & 0xff; + int g = ((int) c[j++]) & 0xff; + int b = ((int) c[j++]) & 0xff; + tab[i++] = 0xff000000 | (r << 16) | (g << 8) | b; + } + } + return tab; + } + + /** + * Main file parser. Reads GIF content blocks. + */ + protected void readContents() { + // read GIF file content blocks + boolean done = false; + while (!(done || err())) { + int code = read(); + switch (code) { + case 0x2C: // image separator + readBitmap(); + if(!readComplete) return; + break; + case 0x21: // extension + code = read(); + switch (code) { + case 0xf9: // graphics control extension + readGraphicControlExt(); + break; + case 0xff: // application extension + readBlock(); + String app = ""; + for (int i = 0; i < 11; i++) { + app += (char) block[i]; + } + if (app.equals("NETSCAPE2.0")) { + readNetscapeExt(); + } else { + skip(); // don't care + } + break; + case 0xfe:// comment extension + skip(); + break; + case 0x01:// plain text extension + skip(); + break; + default: // uninteresting extension + skip(); + } + break; + case 0x3b: // terminator + done = true; + break; + case 0x00: // bad byte, but keep going and see what happens break; + default: + status = STATUS_FORMAT_ERROR; + } + } + } + + /** + * Reads Graphics Control Extension values + */ + protected void readGraphicControlExt() { + read(); // block size + int packed = read(); // packed fields + dispose = (packed & 0x1c) >> 2; // disposal method + if (dispose == 0) { + dispose = 1; // elect to keep old image if discretionary + } + transparency = (packed & 1) != 0; + delay = readShort() * 10; // delay in milliseconds + transIndex = read(); // transparent color index + read(); // block terminator + } + + /** + * Reads GIF file header information. + */ + protected void readHeader() { + String id = ""; + for (int i = 0; i < 6; i++) { + id += (char) read(); + } + if (!id.startsWith("GIF")) { + status = STATUS_FORMAT_ERROR; + return; + } + readLSD(); + if (gctFlag && !err()) { + gct = readColorTable(gctSize); + bgColor = gct[bgIndex]; + } + } + + /** + * Reads next frame image + */ + protected void readBitmap() { + ix = readShort(); // (sub)image position & size + iy = readShort(); + iw = readShort(); + ih = readShort(); + int packed = read(); + lctFlag = (packed & 0x80) != 0; // 1 - local color table flag interlace + lctSize = (int) Math.pow(2, (packed & 0x07) + 1); + // 3 - sort flag + // 4-5 - reserved lctSize = 2 << (packed & 7); // 6-8 - local color + // table size + interlace = (packed & 0x40) != 0; + if (lctFlag) { + lct = readColorTable(lctSize); // read table + act = lct; // make local table active + } else { + act = gct; // make global table active + if (bgIndex == transIndex) { + bgColor = 0; + } + } + int save = 0; + if (transparency) { + save = act[transIndex]; + act[transIndex] = 0; // set transparent color if specified + } + if (act == null) { + status = STATUS_FORMAT_ERROR; // no color table defined + } + if (err()) { + return; + } + decodeBitmapData(); // decode pixel data + skip(); + if (err()) { + return; + } + frameCount++; + // create new image to receive frame data + image = Bitmap.createBitmap(width, height, Config.ARGB_4444); + setPixels(); // transfer pixel data to image + frames.addElement(new GifFrame(image, delay)); // add image to frame + // list + if (transparency) { + act[transIndex] = save; + } + resetFrame(); + } + + /** + * Reads Logical Screen Descriptor + */ + protected void readLSD() { + // logical screen size + width = readShort(); + height = readShort(); + // packed fields + int packed = read(); + gctFlag = (packed & 0x80) != 0; // 1 : global color table flag + // 2-4 : color resolution + // 5 : gct sort flag + gctSize = 2 << (packed & 7); // 6-8 : gct size + bgIndex = read(); // background color index + pixelAspect = read(); // pixel aspect ratio + } + + /** + * Reads Netscape extenstion to obtain iteration count + */ + protected void readNetscapeExt() { + do { + readBlock(); + if (block[0] == 1) { + // loop count sub-block + int b1 = ((int) block[1]) & 0xff; + int b2 = ((int) block[2]) & 0xff; + loopCount = (b2 << 8) | b1; + } + } while ((blockSize > 0) && !err()); + } + + /** + * Reads next 16-bit value, LSB first + */ + protected int readShort() { + // read 16-bit value, LSB first + return read() | (read() << 8); + } + + /** + * Resets frame state for reading next image. + */ + protected void resetFrame() { + lastDispose = dispose; + lrx = ix; + lry = iy; + lrw = iw; + lrh = ih; + lastBitmap = image; + lastBgColor = bgColor; + dispose = 0; + transparency = false; + delay = 0; + lct = null; + } + + /** + * Skips variable length blocks up to and including next zero length block. + */ + protected void skip() { + do { + readBlock(); + } while ((blockSize > 0) && !err()); + } +} + diff --git a/android/app/src/main/java/com/mogujie/tt/ui/helper/PhotoHelper.java b/android/app/src/main/java/com/mogujie/tt/ui/helper/PhotoHelper.java new file mode 100644 index 000000000..119974bb4 --- /dev/null +++ b/android/app/src/main/java/com/mogujie/tt/ui/helper/PhotoHelper.java @@ -0,0 +1,228 @@ + +package com.mogujie.tt.ui.helper; + +import android.content.Context; +import android.content.Intent; +import android.database.Cursor; +import android.graphics.Bitmap; +import android.graphics.BitmapFactory; +import android.graphics.Matrix; +import android.media.ExifInterface; +import android.net.Uri; +import android.provider.MediaStore; +import android.text.TextUtils; +import android.widget.Toast; + +import com.mogujie.tt.R; +import com.mogujie.tt.config.SysConstant; +import com.mogujie.tt.ui.activity.MessageActivity; +import com.mogujie.tt.utils.CommonUtil; +import com.mogujie.tt.utils.Logger; + +import java.io.BufferedInputStream; +import java.io.ByteArrayOutputStream; +import java.io.File; +import java.io.FileInputStream; +import java.io.IOException; + +// todo 这个类还是有用的,但是结构不清晰 +// 应该是处理图像的 辅助类 和imageTool 配合使用 + +public class PhotoHelper { + private Context context; + private String takePhotoSavePath = null; + private static PhotoHelper instance = null; + + public static synchronized PhotoHelper getInstance(Context c) { + if (null == instance) { + instance = new PhotoHelper(c); + } + return instance; + } + + private PhotoHelper(Context c) { + context = c; + } + + public String getTakePhotoSavePath() { + return takePhotoSavePath; + } + + public void setTakePhotoSavePath(String takePhotoSavePath) { + this.takePhotoSavePath = takePhotoSavePath; + } + + public Intent getPhotoPickIntent() { + Intent intent = new Intent(Intent.ACTION_GET_CONTENT, null); + intent.addCategory(Intent.CATEGORY_OPENABLE); + intent.setType("image/*"); + return intent; + } + + public void takePhoto() { + if (CommonUtil.checkSDCard()) { + doTakePhoto(context); + } else { + Toast.makeText(context, + context.getResources().getString(R.string.no_sdcard), + Toast.LENGTH_LONG).show(); + } + } + + public static byte[] getBytes(Bitmap bitmap) { + ByteArrayOutputStream baos = null; + try { + baos = new ByteArrayOutputStream(); + bitmap.compress(Bitmap.CompressFormat.PNG, 0, baos);// 压缩位图 + byte[] bytes = baos.toByteArray();// 创建分配字节数组 + return bytes; + } catch (Exception e) { + Logger.getLogger(PhotoHelper.class).e(e.getMessage()); + return null; + } finally { + if (null != baos) { + try { + baos.flush(); + baos.close(); + } catch (IOException e) { + Logger.getLogger(PhotoHelper.class).e(e.getMessage()); + } + } + } + } + + /** + * @Description 上传服务器前调用该方法进行压缩 + * @param path + * @return + * @throws IOException + */ + public static int calculateInSampleSize(BitmapFactory.Options options, + int reqWidth, int reqHeight) { + // 源图片的高度和宽度 + final int height = options.outHeight; + final int width = options.outWidth; + int inSampleSize = 1; + if (height > reqHeight || width > reqWidth) { + // 计算出实际宽高和目标宽高的比率 + final int heightRatio = Math.round((float) height / (float) reqHeight); + final int widthRatio = Math.round((float) width / (float) reqWidth); + // 选择宽和高中最小的比率作为inSampleSize的值,这样可以保证最终图片的宽和高 + // 一定都会大于等于目标的宽和高。 + inSampleSize = heightRatio < widthRatio ? heightRatio : widthRatio; + } + return inSampleSize; + } + + public static Bitmap revitionImage(String path) throws IOException { + if (null == path || TextUtils.isEmpty(path) || !new File(path).exists()) + return null; + BufferedInputStream in = null; + try { + int degree = readPictureDegree(path); + in = new BufferedInputStream(new FileInputStream(new File(path))); + BitmapFactory.Options options = new BitmapFactory.Options(); + options.inJustDecodeBounds = true; + BitmapFactory.decodeStream(in, null, options); + options.inSampleSize = calculateInSampleSize(options, 400, 600); + + in.close(); + in = new BufferedInputStream(new FileInputStream(new File(path))); + options.inJustDecodeBounds = false; + Bitmap bitmap = BitmapFactory.decodeStream(in, null, options); + Bitmap newbitmap = rotaingImageView(degree, bitmap); + return newbitmap; + } catch (Exception e) { + Logger.getLogger(PhotoHelper.class).e(e.getMessage()); + return null; + } finally { + if (null != in) { + in.close(); + in = null; + } + } + } + + public String getImagePathFromUri(Uri uri) { + // 如果是file,直接拿 + if (uri.getScheme().equalsIgnoreCase("file")) { + return uri.getPath(); + } + + String[] projection = { + MediaStore.Images.Media.DATA + }; + Cursor cursor = context.getContentResolver().query(uri, projection, + null, null, null); + int column_index = cursor.getColumnIndex(projection[0]); + cursor.moveToFirst(); + String path = cursor.getString(column_index); + cursor.close(); + + return path; + } + + /** + * 可以在返回之前把信息发掉 + * @param context + */ + public void doTakePhoto(Context context) { + Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE); + takePhotoSavePath = CommonUtil.getImageSavePath(String.valueOf(System + .currentTimeMillis()) + ".jpg"); + intent.putExtra(MediaStore.EXTRA_OUTPUT, + Uri.fromFile(new File(takePhotoSavePath))); + // intent.putExtra(MediaStore.EXTRA_VIDEO_QUALITY, 1); + ((MessageActivity) context).startActivityForResult(intent, + SysConstant.CAMERA_WITH_DATA); + } + + /** + * 读取图片属性:旋转的角度 + * + * @param path 图片绝对路径 + * @return degree旋转的角度 + */ + public static int readPictureDegree(String path) { + int degree = 0; + try { + ExifInterface exifInterface = new ExifInterface(path); + int orientation = exifInterface.getAttributeInt( + ExifInterface.TAG_ORIENTATION, + ExifInterface.ORIENTATION_NORMAL); + switch (orientation) { + case ExifInterface.ORIENTATION_ROTATE_90: + degree = 90; + break; + case ExifInterface.ORIENTATION_ROTATE_180: + degree = 180; + break; + case ExifInterface.ORIENTATION_ROTATE_270: + degree = 270; + break; + } + } catch (IOException e) { + Logger.getLogger(PhotoHelper.class).e(e.getMessage()); + } + return degree; + } + + /* + * 旋转图片 + * @param angle + * @param bitmap + * @return Bitmap + */ + public static Bitmap rotaingImageView(int angle, Bitmap bitmap) { + if (null == bitmap) { + return null; + } + // 旋转图片 动作 + Matrix matrix = new Matrix(); + matrix.postRotate(angle); + // 创建新的图片 + Bitmap resizedBitmap = Bitmap.createBitmap(bitmap, 0, 0, + bitmap.getWidth(), bitmap.getHeight(), matrix, true); + return resizedBitmap; + } +} diff --git a/android/app/src/main/java/com/mogujie/tt/ui/helper/listener/OnDoubleClickListener.java b/android/app/src/main/java/com/mogujie/tt/ui/helper/listener/OnDoubleClickListener.java new file mode 100644 index 000000000..bdfb5cf6a --- /dev/null +++ b/android/app/src/main/java/com/mogujie/tt/ui/helper/listener/OnDoubleClickListener.java @@ -0,0 +1,64 @@ +package com.mogujie.tt.ui.helper.listener; + +import android.os.Handler; +import android.os.Message; +import android.view.MotionEvent; +import android.view.View; + +/** + * @author : yingmu on 15-1-10. + * @email : yingmu@mogujie.com. + * + */ +public abstract class OnDoubleClickListener implements View.OnTouchListener { + private volatile int count = 0; + private final int HANDLER_ON_CLICK = 1; + + /** + * Called when a touch event is dispatched to a view. This allows listeners to + * get a chance to respond before the target view. + * + * @param v The view the touch event has been dispatched to. + * @param event The MotionEvent object containing full information about + * the event. + * @return True if the listener has consumed the event, false otherwise. + */ + @Override + public boolean onTouch(final View v, MotionEvent event) { + if (MotionEvent.ACTION_DOWN == event.getAction()) { + count++; + if (count == 1) { + Handler handler = new Handler(){ + @Override + public void handleMessage(Message msg) { + super.handleMessage(msg); + switch (msg.what){ + case HANDLER_ON_CLICK:{ + if(count == 1){ + count = 0; + onClick(v); + } + + }break; + } + } + }; + + Message m = Message.obtain(handler); + m.what = HANDLER_ON_CLICK; + handler.sendMessageDelayed(m, 200); + /**事件没有被消费完*/ + return false; + } else if (count == 2) { + count = 0; + onDoubleClick(v); + /**事件不再往下面传递*/ + return true; + } + } + return false; + } + + public abstract void onDoubleClick(View view); + public abstract void onClick(View view); +} diff --git a/android/app/src/main/java/com/mogujie/tt/ui/widget/BubbleImageView.java b/android/app/src/main/java/com/mogujie/tt/ui/widget/BubbleImageView.java new file mode 100644 index 000000000..d8ec17f8c --- /dev/null +++ b/android/app/src/main/java/com/mogujie/tt/ui/widget/BubbleImageView.java @@ -0,0 +1,150 @@ +package com.mogujie.tt.ui.widget; + +import android.content.Context; +import android.graphics.Bitmap; +import android.os.AsyncTask; +import android.text.TextUtils; +import android.util.AttributeSet; +import android.view.View; +import android.widget.FrameLayout; +import android.widget.ImageView; + +import com.mogujie.tt.R; +import com.mogujie.tt.utils.CommonUtil; +import com.mogujie.tt.utils.FileUtil; +import com.mogujie.tt.utils.ImageLoaderUtil; +import com.nostra13.universalimageloader.core.DisplayImageOptions; +import com.nostra13.universalimageloader.core.assist.FailReason; +import com.nostra13.universalimageloader.core.assist.ImageScaleType; +import com.nostra13.universalimageloader.core.imageaware.ImageAware; +import com.nostra13.universalimageloader.core.imageaware.ImageViewAware; +import com.nostra13.universalimageloader.core.listener.SimpleImageLoadingListener; +import com.squareup.okhttp.Cache; +import com.squareup.okhttp.OkHttpClient; +import com.squareup.okhttp.Request; +import com.squareup.okhttp.Response; +import com.squareup.okhttp.internal.DiskLruCache; +import com.squareup.okhttp.internal.Util; + +import org.apache.commons.io.IOUtils; + +import java.io.FilterInputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.UnsupportedEncodingException; +import java.net.MalformedURLException; +import java.net.URL; +import java.net.URLDecoder; + +/** + * Created by zhujian on 15/2/13. + */ +public class BubbleImageView extends ImageView { + /** + * 图片设置相关 + */ + protected String imageUrl = null; + protected boolean isAttachedOnWindow = false; + protected int defaultImageRes = R.drawable.tt_message_image_default; + + protected ImageLoaddingCallback imageLoaddingCallback; + + + public BubbleImageView(Context context) { + super(context); + } + + public BubbleImageView(Context context, AttributeSet attrs, int defStyle) { + super(context, attrs, defStyle); + } + + public BubbleImageView(Context context, AttributeSet attrs) { + super(context, attrs); + } + + /* 图片设置相关 */ + + public void setImageLoaddingCallback(ImageLoaddingCallback callback) { + this.imageLoaddingCallback = callback; + } + + public void setImageUrl(final String url) { + this.imageUrl = url; + if (isAttachedOnWindow) { + final BubbleImageView view = this; + if (!TextUtils.isEmpty(this.imageUrl)) { + ImageAware imageAware = new ImageViewAware(this, false); + ImageLoaderUtil.getImageLoaderInstance().displayImage(this.imageUrl, imageAware, new DisplayImageOptions.Builder() + .cacheInMemory(true) + .cacheOnDisk(true) + .showImageOnLoading(R.drawable.tt_message_image_default) + .showImageOnFail(R.drawable.tt_message_image_error) + .imageScaleType(ImageScaleType.IN_SAMPLE_INT) + .bitmapConfig(Bitmap.Config.RGB_565) + .delayBeforeLoading(100) + .build(), new SimpleImageLoadingListener() { + @Override + public void onLoadingComplete(String imageUri, View view, Bitmap loadedImage) { + super.onLoadingComplete(imageUri, view, loadedImage); + if (imageLoaddingCallback != null) { + + String cachePath = ImageLoaderUtil.getImageLoaderInstance().getDiskCache().get(imageUri).getPath();//这个路径其实已不再更新 + imageLoaddingCallback.onLoadingComplete(cachePath, view, loadedImage); + } + } + + @Override + public void onLoadingStarted(String imageUri, View view) { + super.onLoadingStarted(imageUri, view); + if (imageLoaddingCallback != null) { + imageLoaddingCallback.onLoadingStarted(imageUri, view); + } + } + + @Override + public void onLoadingCancelled(String imageUri, View view) { + super.onLoadingCancelled(imageUri, view); + if (imageLoaddingCallback != null) { + imageLoaddingCallback.onLoadingCanceled(imageUri, view); + } + } + + @Override + public void onLoadingFailed(String imageUri, View view, FailReason failReason) { + super.onLoadingFailed(imageUri, view, failReason); + if (imageLoaddingCallback != null) { + imageLoaddingCallback.onLoadingFailed(imageUri, view); + } + } + }); + } + } else { + this.setImageResource(R.drawable.tt_message_image_default); + } + } + + @Override + protected void onAttachedToWindow() { + super.onAttachedToWindow(); + isAttachedOnWindow = true; + setImageUrl(this.imageUrl); + } + + protected void onDetachedFromWindow() { + super.onDetachedFromWindow(); + this.isAttachedOnWindow = false; + ImageLoaderUtil.getImageLoaderInstance().cancelDisplayTask(this); + } + + public interface ImageLoaddingCallback { + public void onLoadingComplete(String imageUri, View view, Bitmap loadedImage); + + public void onLoadingStarted(String imageUri, View view); + + public void onLoadingCanceled(String imageUri, View view); + + public void onLoadingFailed(String imageUri, View view); + } + + +} diff --git a/android/app/src/main/java/com/mogujie/tt/ui/widget/CustomEditView.java b/android/app/src/main/java/com/mogujie/tt/ui/widget/CustomEditView.java new file mode 100644 index 000000000..ed636de91 --- /dev/null +++ b/android/app/src/main/java/com/mogujie/tt/ui/widget/CustomEditView.java @@ -0,0 +1,47 @@ +package com.mogujie.tt.ui.widget; + +import android.content.Context; +import android.text.Editable; +import android.util.AttributeSet; +import android.widget.EditText; + +import com.mogujie.tt.ui.helper.Emoparser; + +/** + * Created by nana on 14-9-18. + */ +public class CustomEditView extends EditText { + private static final int ID_PASTE = android.R.id.paste; + + public CustomEditView(Context context, AttributeSet attrs) { + super(context, attrs); + } + + @Override + public boolean onTextContextMenuItem(int id) { + if(id == ID_PASTE){ + try { + int currentapiVersion = android.os.Build.VERSION.SDK_INT; + if (currentapiVersion >= android.os.Build.VERSION_CODES.HONEYCOMB) { + android.content.ClipboardManager clipboard = + (android.content.ClipboardManager) getContext().getSystemService(Context.CLIPBOARD_SERVICE); + String value = clipboard.getText().toString(); + Editable edit = getEditableText(); + edit.clear(); + edit.append(Emoparser.getInstance(getContext()).emoCharsequence(value)); + } else { + android.text.ClipboardManager clipboard = + (android.text.ClipboardManager) getContext().getSystemService(Context.CLIPBOARD_SERVICE); + String value = clipboard.getText().toString(); + Editable edit = getEditableText(); + edit.clear(); + edit.append(Emoparser.getInstance(getContext()).emoCharsequence(value)); + } + return true; + } catch (Exception e) { + e.printStackTrace(); + } + } + return super.onTextContextMenuItem(id); + } +} \ No newline at end of file diff --git a/android/app/src/main/java/com/mogujie/tt/ui/widget/CustomViewPager.java b/android/app/src/main/java/com/mogujie/tt/ui/widget/CustomViewPager.java new file mode 100644 index 000000000..9ebee3e68 --- /dev/null +++ b/android/app/src/main/java/com/mogujie/tt/ui/widget/CustomViewPager.java @@ -0,0 +1,56 @@ + +package com.mogujie.tt.ui.widget; + +import android.content.Context; +import android.support.v4.view.ViewPager; +import android.util.AttributeSet; +import android.view.MotionEvent; + +public class CustomViewPager extends ViewPager { + private boolean isCanScroll = true; + + public CustomViewPager(Context context) { + super(context); + } + + public CustomViewPager(Context context, AttributeSet attrs) { + super(context, attrs); + } + + public void setScanScroll(boolean isCanScroll) { + this.isCanScroll = isCanScroll; + } + + @Override + public void scrollTo(int x, int y) { + super.scrollTo(x, y); + } + + @Override + public boolean onTouchEvent(MotionEvent arg0) { + if (!this.isCanScroll) { + return false; + } + super.onTouchEvent(arg0); + return true; + } + + @Override + public boolean onInterceptTouchEvent(MotionEvent arg0) { + if (!this.isCanScroll) { + return false; + } + super.onInterceptTouchEvent(arg0); + return true; + } + + @Override + public void setCurrentItem(int item, boolean smoothScroll) { + super.setCurrentItem(item, smoothScroll); + } + + @Override + public void setCurrentItem(int item) { + super.setCurrentItem(item); + } +} diff --git a/android/app/src/main/java/com/mogujie/tt/ui/widget/DrawableCenterEditText.java b/android/app/src/main/java/com/mogujie/tt/ui/widget/DrawableCenterEditText.java new file mode 100644 index 000000000..945c9a4da --- /dev/null +++ b/android/app/src/main/java/com/mogujie/tt/ui/widget/DrawableCenterEditText.java @@ -0,0 +1,40 @@ +package com.mogujie.tt.ui.widget; + +import android.content.Context; +import android.graphics.Canvas; +import android.graphics.drawable.Drawable; +import android.util.AttributeSet; +import android.widget.TextView; + +public class DrawableCenterEditText extends TextView { + + public DrawableCenterEditText(Context context, AttributeSet attrs, + int defStyle) { + super(context, attrs, defStyle); + } + + public DrawableCenterEditText(Context context, AttributeSet attrs) { + super(context, attrs); + } + + public DrawableCenterEditText(Context context) { + super(context); + } + + @Override + protected void onDraw(Canvas canvas) { + Drawable[] drawables = getCompoundDrawables(); + if (drawables != null) { + Drawable drawableLeft = drawables[0]; + if (drawableLeft != null) { + float textWidth = getPaint().measureText(getText().toString()); + int drawablePadding = getCompoundDrawablePadding(); + int drawableWidth = 0; + drawableWidth = drawableLeft.getIntrinsicWidth(); + float bodyWidth = textWidth + drawableWidth + drawablePadding; + canvas.translate((getWidth() - bodyWidth) / 2 -20, 0); + } + } + super.onDraw(canvas); + } +} \ No newline at end of file diff --git a/android/app/src/main/java/com/mogujie/tt/ui/widget/EmoGridView.java b/android/app/src/main/java/com/mogujie/tt/ui/widget/EmoGridView.java new file mode 100644 index 000000000..76a499101 --- /dev/null +++ b/android/app/src/main/java/com/mogujie/tt/ui/widget/EmoGridView.java @@ -0,0 +1,215 @@ + +package com.mogujie.tt.ui.widget; + +import android.content.Context; +import android.graphics.Color; +import android.support.v4.view.ViewPager; +import android.util.AttributeSet; +import android.view.Gravity; +import android.view.View; +import android.view.ViewGroup; +import android.widget.AdapterView; +import android.widget.AdapterView.OnItemClickListener; +import android.widget.GridView; +import android.widget.ImageView; +import android.widget.LinearLayout; + +import com.mogujie.tt.R; +import com.mogujie.tt.ui.adapter.EmoGridViewAdapter; +import com.mogujie.tt.ui.adapter.ViewPageAdapter; +import com.mogujie.tt.config.SysConstant; +import com.mogujie.tt.ui.helper.Emoparser; +import com.mogujie.tt.utils.CommonUtil; + +import java.util.ArrayList; +import java.util.List; + +public class EmoGridView extends LinearLayout { + private Context _context; + private ViewPager _viewPager; + private LinearLayout _llDot; + + private OnEmoGridViewItemClick onEmoGridViewItemClick; + + private ImageView[] dots; + /** ViewPager当前页 */ + private int currentIndex; + /** ViewPager页数 */ + private int viewPager_size; + /** 默认一页20个item */ + private double pageItemCount = 20d; + + /** 保存每个页面的GridView视图 */ + private List list_Views; + + /** viewpage高度 */ + + public EmoGridView(Context cxt) { + super(cxt); + _context = cxt; + initViewPage(); + initFootDots(); + } + + public EmoGridView(Context cxt, AttributeSet attrs) { + super(cxt, attrs); + _context = cxt; + initViewPage(); + initFootDots(); + } + + private void initViewPage() { + setOrientation(VERTICAL); + _viewPager = new ViewPager(_context); + _llDot = new LinearLayout(_context); + LayoutParams params = new LayoutParams(LayoutParams.MATCH_PARENT, + CommonUtil.getDefaultPannelHeight(_context)); + params.gravity=Gravity.BOTTOM; + _viewPager.setLayoutParams(params); + _llDot.setLayoutParams(new LayoutParams(LayoutParams.MATCH_PARENT, + LayoutParams.WRAP_CONTENT)); + _llDot.setGravity(Gravity.CENTER); + _llDot.setOrientation(HORIZONTAL); + addView(_viewPager); + addView(_llDot); + } + // 底部的三点 + private void initFootDots() { + viewPager_size = (int) Math.ceil(Emoparser.getInstance(_context) + .getResIdList().length / pageItemCount); + int mod = Emoparser.getInstance(_context).getResIdList().length + % (SysConstant.pageSize - 1); + if (mod == 1) + --viewPager_size; + if (0 < viewPager_size) { + if (viewPager_size == 1) { + _llDot.setVisibility(View.GONE); + } else { + _llDot.setVisibility(View.VISIBLE); + for (int i = 0; i < viewPager_size; i++) { + ImageView image = new ImageView(_context); + image.setTag(i); + // LinearLayout.LayoutParams params = new + // LinearLayout.LayoutParams( + // 20, 20); + LinearLayout.LayoutParams params = new LinearLayout.LayoutParams( + LayoutParams.WRAP_CONTENT, + LayoutParams.WRAP_CONTENT); + params.setMargins(5, + CommonUtil.getElementSzie(_context) / 2, 5, + CommonUtil.getElementSzie(_context) / 2); + image.setBackgroundResource(R.drawable.tt_default_emo_dots); + image.setEnabled(false); + _llDot.addView(image, params); + } + } + } + if (1 != viewPager_size) { + dots = new ImageView[viewPager_size]; + for (int i = 0; i < viewPager_size; i++) { + dots[i] = (ImageView) _llDot.getChildAt(i); + dots[i].setEnabled(true); + dots[i].setTag(i); + } + currentIndex = 0; + dots[currentIndex].setEnabled(false); + _viewPager + .setOnPageChangeListener(new ViewPager.OnPageChangeListener() { + + @Override + public void onPageSelected(int arg0) { + setCurDot(arg0); + } + + @Override + public void onPageScrolled(int arg0, float arg1, + int arg2) { + + } + + @Override + public void onPageScrollStateChanged(int arg0) { + } + }); + } + } + + private void setCurDot(int position) { + if (position < 0 || position > viewPager_size - 1 + || currentIndex == position) { + return; + } + dots[position].setEnabled(false); + dots[currentIndex].setEnabled(true); + currentIndex = position; + } + + public void setAdapter() { + if (onEmoGridViewItemClick == null) { + return; + } + list_Views = new ArrayList(); + for (int i = 0; i < viewPager_size; i++) { + list_Views.add(getViewPagerItem(i)); + } + _viewPager.setAdapter(new ViewPageAdapter(list_Views)); + + } + + /** 生成gridView数据 */ + private int[] getGridViewData(int index) { + ++index; + int startPos = (index - 1) * (SysConstant.pageSize - 1); + int endPos = index * (SysConstant.pageSize - 1); + int length = 0; + + if (endPos > Emoparser.getInstance(_context).getResIdList().length) { + endPos = Emoparser.getInstance(_context).getResIdList().length; + } + length = endPos - startPos + 1; + int[] tmps = new int[length]; + + int num = 0; + for (int i = startPos; i < endPos; i++) { + tmps[num] = Emoparser.getInstance(_context).getResIdList()[i]; + num++; + } + if (length > 1) + tmps[length - 1] = R.drawable.tt_default_emo_back_normal; + return tmps; + } + + private GridView getViewPagerItem(final int index) { + GridView gridView = new GridView(_context); + gridView.setLayoutParams(new LayoutParams(LayoutParams.MATCH_PARENT, + LayoutParams.WRAP_CONTENT)); + gridView.setNumColumns(7); + gridView.setVerticalScrollBarEnabled(false); + gridView.setHorizontalScrollBarEnabled(false); + gridView.setPadding(8, 8, 8, 0); + gridView.setVerticalSpacing(CommonUtil.getElementSzie(_context) / 2 + + CommonUtil.getElementSzie(_context) / 3); + // gridView.setVerticalSpacing(30); + gridView.setBackgroundColor(Color.TRANSPARENT); + gridView.setAdapter(new EmoGridViewAdapter(_context, + getGridViewData(index))); + gridView.setOnItemClickListener(new OnItemClickListener() { + @Override + public void onItemClick(AdapterView parent, View view, + int position, long id) { + int start = index * (SysConstant.pageSize - 1); + onEmoGridViewItemClick.onItemClick(position + start, index); + } + }); + return gridView; + } + + public void setOnEmoGridViewItemClick( + OnEmoGridViewItemClick onFaceGridViewItemClick) { + this.onEmoGridViewItemClick = onFaceGridViewItemClick; + } + + public interface OnEmoGridViewItemClick { + public void onItemClick(int facesPos, int viewIndex); + } +} diff --git a/android/app/src/main/java/com/mogujie/tt/ui/widget/GifDecoder.java b/android/app/src/main/java/com/mogujie/tt/ui/widget/GifDecoder.java new file mode 100644 index 000000000..5268b248b --- /dev/null +++ b/android/app/src/main/java/com/mogujie/tt/ui/widget/GifDecoder.java @@ -0,0 +1,810 @@ +package com.mogujie.tt.ui.widget; + +/** + * Created by zhujian on 15/3/9. + */ + +import android.graphics.Bitmap; +import android.util.Log; + +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.nio.BufferUnderflowException; +import java.nio.ByteBuffer; +import java.nio.ByteOrder; +import java.util.ArrayList; + +/** + * Reads frame data from a GIF image source and decodes it into individual frames + * for animation purposes. Image data can be read from either and InputStream source + * or a byte[]. + * + * This class is optimized for running animations with the frames, there + * are no methods to get individual frame images, only to decode the next frame in the + * animation sequence. Instead, it lowers its memory footprint by only housing the minimum + * data necessary to decode the next frame in the animation sequence. + * + * The animation must be manually moved forward using {@link #advance()} before requesting the next + * frame. This method must also be called before you request the first frame or an error will + * occur. + * + * Implementation adapted from sample code published in Lyons. (2004). Java for Programmers, + * republished under the MIT Open Source License + */ +public class GifDecoder { + private static final String TAG = GifDecoder.class.getSimpleName(); + + /** + * File read status: No errors. + */ + public static final int STATUS_OK = 0; + /** + * File read status: Error decoding file (may be partially decoded) + */ + public static final int STATUS_FORMAT_ERROR = 1; + /** + * File read status: Unable to open source. + */ + public static final int STATUS_OPEN_ERROR = 2; + /** + * max decoder pixel stack size + */ + protected static final int MAX_STACK_SIZE = 4096; + + /** + * GIF Disposal Method meaning take no action + */ + private static final int DISPOSAL_UNSPECIFIED = 0; + /** + * GIF Disposal Method meaning leave canvas from previous frame + */ + private static final int DISPOSAL_NONE = 1; + /** + * GIF Disposal Method meaning clear canvas to background color + */ + private static final int DISPOSAL_BACKGROUND = 2; + /** + * GIF Disposal Method meaning clear canvas to frame before last + */ + private static final int DISPOSAL_PREVIOUS = 3; + + /** + * Global status code of GIF data parsing + */ + protected int status; + + // Global File Header values and parsing flags + protected int width; // full image width + protected int height; // full image height + protected boolean gctFlag; // global color table used + protected int gctSize; // size of global color table + protected int loopCount = 1; // iterations; 0 = repeat forever + protected int[] gct; // global color table + protected int[] act; // active color table + protected int bgIndex; // background color index + protected int bgColor; // background color + protected int pixelAspect; // pixel aspect ratio + protected boolean lctFlag; // local color table flag + protected int lctSize; // local color table size + + // Raw GIF data from input source + protected ByteBuffer rawData; + + // Raw data read working array + protected byte[] block = new byte[256]; // current data block + protected int blockSize = 0; // block size last graphic control extension info + + // LZW decoder working arrays + protected short[] prefix; + protected byte[] suffix; + protected byte[] pixelStack; + protected byte[] mainPixels; + protected int[] mainScratch, copyScratch; + + protected ArrayList frames; // frames read from current file + protected GifFrame currentFrame; + protected Bitmap previousImage, currentImage, renderImage; + + protected int framePointer; + protected int frameCount; + + /** + * Inner model class housing metadata for each frame + */ + private static class GifFrame { + public int ix, iy, iw, ih; + /* Control Flags */ + public boolean interlace; + public boolean transparency; + /* Disposal Method */ + public int dispose; + /* Transparency Index */ + public int transIndex; + /* Delay, in ms, to next frame */ + public int delay; + /* Index in the raw buffer where we need to start reading to decode */ + public int bufferFrameStart; + /* Local Color Table */ + public int[] lct; + } + + /** + * Move the animation frame counter forward + */ + public void advance() { + if (frameCount > 0) + framePointer = (framePointer + 1) % frameCount; + } + + /** + * Gets display duration for specified frame. + * + * @param n int index of frame + * @return delay in milliseconds + */ + public int getDelay(final int n) { + int delay = 0; + if ((n >= 0) && (n < frameCount)) { + delay = frames.get(n).delay; + } + return delay; + } + + /** + * Gets display duration for the upcoming frame + */ + public int getNextDelay() { + if (frameCount <= 0 || framePointer < 0) { + return 0; + } + + return getDelay(framePointer); + } + + /** + * Gets the number of frames read from file. + * + * @return frame count + */ + public int getFrameCount() { + return frameCount; + } + + /** + * Gets the current index of the animation frame, or -1 if animation hasn't not yet started + * + * @return frame index + */ + public int getCurrentFrameIndex() { + return framePointer; + } + + /** + * Gets the "Netscape" iteration count, if any. A count of 0 means repeat indefinitiely. + * + * @return iteration count if one was specified, else 1. + */ + public int getLoopCount() { + return loopCount; + } + + /** + * Get the next frame in the animation sequence. + * + * @return Bitmap representation of frame + */ + public Bitmap getNextFrame() { + if (frameCount <= 0 || framePointer < 0 || currentImage == null) { + return null; + } + + final GifFrame frame = frames.get(framePointer); + + // Set the appropriate color table + if (frame.lct == null) { + act = gct; + } else { + act = frame.lct; + if (bgIndex == frame.transIndex) { + bgColor = 0; + } + } + + int save = 0; + if (frame.transparency) { + save = act[frame.transIndex]; + act[frame.transIndex] = 0; // set transparent color if specified + } + if (act == null) { + Log.w(TAG, "No Valid Color Table"); + status = STATUS_FORMAT_ERROR; // no color table defined + return null; + } + + setPixels(framePointer); // transfer pixel data to image + + // Reset the transparent pixel in the color table + if (frame.transparency) { + act[frame.transIndex] = save; + } + + return currentImage; + } + + /** + * Reads GIF image from stream + * + * @param is containing GIF file. + * @return read status code (0 = no errors) + */ + public int read(final InputStream is, final int contentLength) { + if (is != null) { + try { + final int capacity = (contentLength > 0) ? (contentLength + 4096) : 4096; + final ByteArrayOutputStream buffer = new ByteArrayOutputStream(capacity); + int nRead; + final byte[] data = new byte[16384]; + while ((nRead = is.read(data, 0, data.length)) != -1) { + buffer.write(data, 0, nRead); + } + buffer.flush(); + + read(buffer.toByteArray()); + } catch (final IOException e) { + Log.w(TAG, "Error reading data from stream", e); + } + } else { + status = STATUS_OPEN_ERROR; + } + + try { + is.close(); + } catch (final Exception e) { + Log.w(TAG, "Error closing stream", e); + } + + return status; + } + + /** + * Reads GIF image from byte array + * + * @param data containing GIF file. + * @return read status code (0 = no errors) + */ + public int read(final byte[] data) { + init(); + if (data != null) { + // Initialiaze the raw data buffer + rawData = ByteBuffer.wrap(data); + rawData.rewind(); + rawData.order(ByteOrder.LITTLE_ENDIAN); + + readHeader(); + if (!err()) { + readContents(); + if (frameCount < 0) { + status = STATUS_FORMAT_ERROR; + } + } + } else { + status = STATUS_OPEN_ERROR; + } + + return status; + } + + /** + * Creates new frame image from current data (and previous frames as specified by their disposition codes). + */ + protected void setPixels(final int frameIndex) { + final GifFrame currentFrame = frames.get(frameIndex); + GifFrame previousFrame = null; + final int previousIndex = frameIndex - 1; + if (previousIndex >= 0) { + previousFrame = frames.get(previousIndex); + } + + // final location of blended pixels + final int[] dest = mainScratch; + + // fill in starting image contents based on last image's dispose code + if (previousFrame != null && previousFrame.dispose > DISPOSAL_UNSPECIFIED) { + if (previousFrame.dispose == DISPOSAL_NONE && currentImage != null) { + // Start with the current image + currentImage.getPixels(dest, 0, width, 0, 0, width, height); + } + if (previousFrame.dispose == DISPOSAL_BACKGROUND) { + // Start with a canvas filled with the background color + int c = 0; + if (!currentFrame.transparency) { + c = bgColor; + } + for (int i = 0; i < previousFrame.ih; i++) { + final int n1 = (previousFrame.iy + i) * width + previousFrame.ix; + final int n2 = n1 + previousFrame.iw; + for (int k = n1; k < n2; k++) { + dest[k] = c; + } + } + } + if (previousFrame.dispose == DISPOSAL_PREVIOUS && previousImage != null) { + // Start with the previous frame + previousImage.getPixels(dest, 0, width, 0, 0, width, height); + } + } + + // Decode pixels for this frame into the global pixels[] scratch + decodeBitmapData(currentFrame, mainPixels); // decode pixel data + + // copy each source line to the appropriate place in the destination + int pass = 1; + int inc = 8; + int iline = 0; + for (int i = 0; i < currentFrame.ih; i++) { + int line = i; + if (currentFrame.interlace) { + if (iline >= currentFrame.ih) { + pass++; + switch (pass) { + case 2: + iline = 4; + break; + case 3: + iline = 2; + inc = 4; + break; + case 4: + iline = 1; + inc = 2; + break; + default: + break; + } + } + line = iline; + iline += inc; + } + line += currentFrame.iy; + if (line < height) { + final int k = line * width; + int dx = k + currentFrame.ix; // start of line in dest + int dlim = dx + currentFrame.iw; // end of dest line + if ((k + width) < dlim) { + dlim = k + width; // past dest edge + } + int sx = i * currentFrame.iw; // start of line in source + while (dx < dlim) { + // map color and insert in destination + final int index = (mainPixels[sx++]) & 0xff; + final int c = act[index]; + if (c != 0) { + dest[dx] = c; + } + dx++; + } + } + } + + // Copy pixels into previous image + if(currentImage!=null) + { + currentImage.getPixels(copyScratch, 0, width, 0, 0, width, height); + } + if(previousImage!=null) + { + previousImage.setPixels(copyScratch, 0, width, 0, 0, width, height); + } + if(currentImage!=null) + { + // Set pixels for current image + currentImage.setPixels(dest, 0, width, 0, 0, width, height); + } + + } + + /** + * Decodes LZW image data into pixel array. Adapted from John Cristy's BitmapMagick. + */ + protected void decodeBitmapData(final GifFrame frame, byte[] dstPixels) { + if (frame != null) { + // Jump to the frame start position + rawData.position(frame.bufferFrameStart); + } + + final int nullCode = -1; + final int npix = (frame == null) ? width * height : frame.iw * frame.ih; + int available, clear, code_mask, code_size, end_of_information, in_code, old_code, bits, code, count, i, datum, data_size, first, top, bi, pi; + + if (dstPixels == null || dstPixels.length < npix) { + dstPixels = new byte[npix]; // allocate new pixel array + } + if (prefix == null) { + prefix = new short[MAX_STACK_SIZE]; + } + if (suffix == null) { + suffix = new byte[MAX_STACK_SIZE]; + } + if (pixelStack == null) { + pixelStack = new byte[MAX_STACK_SIZE + 1]; + } + + // Initialize GIF data stream decoder. + data_size = read(); + clear = 1 << data_size; + end_of_information = clear + 1; + available = clear + 2; + old_code = nullCode; + code_size = data_size + 1; + code_mask = (1 << code_size) - 1; + for (code = 0; code < clear; code++) { + prefix[code] = 0; // XXX ArrayIndexOutOfBoundsException + suffix[code] = (byte)code; + } + + // Decode GIF pixel stream. + datum = bits = count = first = top = pi = bi = 0; + for (i = 0; i < npix;) { + if (top == 0) { + if (bits < code_size) { + // Load bytes until there are enough bits for a code. + if (count == 0) { + // Read a new data block. + count = readBlock(); + if (count <= 0) { + break; + } + bi = 0; + } + datum += ((block[bi]) & 0xff) << bits; + bits += 8; + bi++; + count--; + continue; + } + // Get the next code. + code = datum & code_mask; + datum >>= code_size; + bits -= code_size; + // Interpret the code + if ((code > available) || (code == end_of_information)) { + break; + } + if (code == clear) { + // Reset decoder. + code_size = data_size + 1; + code_mask = (1 << code_size) - 1; + available = clear + 2; + old_code = nullCode; + continue; + } + if (old_code == nullCode) { + pixelStack[top++] = suffix[code]; + old_code = code; + first = code; + continue; + } + in_code = code; + if (code == available) { + pixelStack[top++] = (byte)first; + code = old_code; + } + while (code > clear) { + pixelStack[top++] = suffix[code]; + code = prefix[code]; + } + first = (suffix[code]) & 0xff; + // Add a new string to the string table, + if (available >= MAX_STACK_SIZE) { + break; + } + pixelStack[top++] = (byte)first; + prefix[available] = (short)old_code; + suffix[available] = (byte)first; + available++; + if (((available & code_mask) == 0) && (available < MAX_STACK_SIZE)) { + code_size++; + code_mask += available; + } + old_code = in_code; + } + // Pop a pixel off the pixel stack. + top--; + dstPixels[pi++] = pixelStack[top]; + i++; + } + + for (i = pi; i < npix; i++) { + dstPixels[i] = 0; // clear missing pixels + } + } + + /** + * Returns true if an error was encountered during reading/decoding + */ + protected boolean err() { + return status != STATUS_OK; + } + + /** + * Initializes or re-initializes reader + */ + protected void init() { + status = STATUS_OK; + frameCount = 0; + framePointer = -1; + frames = new ArrayList(); + gct = null; + } + + /** + * Reads a single byte from the input stream. + */ + protected int read() { + int curByte = 0; + try { + curByte = (rawData.get() & 0xFF); + } catch (final Exception e) { + status = STATUS_FORMAT_ERROR; + } + return curByte; + } + + /** + * Reads next variable length block from input. + * + * @return number of bytes stored in "buffer" + */ + protected int readBlock() { + blockSize = read(); + int n = 0; + if (blockSize > 0) { + try { + int count; + while (n < blockSize) { + count = blockSize - n; + rawData.get(block, n, count); + + n += count; + } + } catch (final Exception e) { + Log.w(TAG, "Error Reading Block", e); + status = STATUS_FORMAT_ERROR; + } + } + return n; + } + + /** + * Reads color table as 256 RGB integer values + * + * @param ncolors int number of colors to read + * @return int array containing 256 colors (packed ARGB with full alpha) + */ + protected int[] readColorTable(final int ncolors) { + final int nbytes = 3 * ncolors; + int[] tab = null; + final byte[] c = new byte[nbytes]; + + try { + rawData.get(c); + + tab = new int[256]; // max size to avoid bounds checks + int i = 0; + int j = 0; + while (i < ncolors) { + final int r = (c[j++]) & 0xff; + final int g = (c[j++]) & 0xff; + final int b = (c[j++]) & 0xff; + tab[i++] = 0xff000000 | (r << 16) | (g << 8) | b; + } + } catch (final BufferUnderflowException e) { + Log.w(TAG, "Format Error Reading Color Table", e); + status = STATUS_FORMAT_ERROR; + } + + return tab; + } + + /** + * Main file parser. Reads GIF content blocks. + */ + protected void readContents() { + // read GIF file content blocks + boolean done = false; + while (!(done || err())) { + int code = read(); + switch (code) { + case 0x2C: // image separator + readBitmap(); + break; + case 0x21: // extension + code = read(); + switch (code) { + case 0xf9: // graphics control extension + // Start a new frame + currentFrame = new GifFrame(); + readGraphicControlExt(); + break; + case 0xff: // application extension + readBlock(); + String app = ""; + for (int i = 0; i < 11; i++) { + app += (char)block[i]; + } + if (app.equals("NETSCAPE2.0")) { + readNetscapeExt(); + } else { + skip(); // don't care + } + break; + case 0xfe:// comment extension + skip(); + break; + case 0x01:// plain text extension + skip(); + break; + default: // uninteresting extension + skip(); + } + break; + case 0x3b: // terminator + done = true; + break; + case 0x00: // bad byte, but keep going and see what happens break; + default: + status = STATUS_FORMAT_ERROR; + } + } + } + + /** + * Reads GIF file header information. + */ + protected void readHeader() { + String id = ""; + for (int i = 0; i < 6; i++) { + id += (char)read(); + } + if (!id.startsWith("GIF")) { + status = STATUS_FORMAT_ERROR; + return; + } + readLSD(); + if (gctFlag && !err()) { + gct = readColorTable(gctSize); + bgColor = gct[bgIndex]; + } + } + + /** + * Reads Graphics Control Extension values + */ + protected void readGraphicControlExt() { + read(); // block size + final int packed = read(); // packed fields + currentFrame.dispose = (packed & 0x1c) >> 2; // disposal method + if (currentFrame.dispose == 0) { + currentFrame.dispose = 1; // elect to keep old image if discretionary + } + currentFrame.transparency = (packed & 1) != 0; + currentFrame.delay = readShort() * 10; // delay in milliseconds + currentFrame.transIndex = read(); // transparent color index + read(); // block terminator + } + + /** + * Reads next frame image + */ + protected void readBitmap() { + currentFrame.ix = readShort(); // (sub)image position & size + currentFrame.iy = readShort(); + currentFrame.iw = readShort(); + currentFrame.ih = readShort(); + + final int packed = read(); + lctFlag = (packed & 0x80) != 0; // 1 - local color table flag interlace + lctSize = (int)Math.pow(2, (packed & 0x07) + 1); + // 3 - sort flag + // 4-5 - reserved lctSize = 2 << (packed & 7); // 6-8 - local color + // table size + currentFrame.interlace = (packed & 0x40) != 0; + if (lctFlag) { + currentFrame.lct = readColorTable(lctSize); // read table + } else { + currentFrame.lct = null; // No local color table + } + + currentFrame.bufferFrameStart = rawData.position(); // Save this as the decoding position pointer + + skipBitmapData(); + if (err()) { + return; + } + + frameCount++; + frames.add(currentFrame); // add image to frame + } + + private void skipBitmapData() { + read(); // code size + skip(); + } + + /** + * Reads Logical Screen Descriptor + */ + protected void readLSD() { + // logical screen size + width = readShort(); + height = readShort(); + // packed fields + final int packed = read(); + gctFlag = (packed & 0x80) != 0; // 1 : global color table flag + // 2-4 : color resolution + // 5 : gct sort flag + gctSize = 2 << (packed & 7); // 6-8 : gct size + bgIndex = read(); // background color index + pixelAspect = read(); // pixel aspect ratio + + // Now that we know the size, init scratch arrays + try { + mainPixels = new byte[width * height]; + mainScratch = new int[width * height]; + copyScratch = new int[width * height]; + + previousImage = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888); + currentImage = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888); + } catch (final OutOfMemoryError e) { + // Try with halving down the bitmap size + final int dimension = (width * height) / 2; + mainPixels = new byte[dimension]; + mainScratch = new int[dimension]; + copyScratch = new int[dimension]; + + previousImage = Bitmap.createBitmap(width / 2, height / 2, Bitmap.Config.RGB_565); + currentImage = Bitmap.createBitmap(width / 2, height / 2, Bitmap.Config.RGB_565); + } + } + + /** + * Reads Netscape extenstion to obtain iteration count + */ + protected void readNetscapeExt() { + do { + readBlock(); + if (block[0] == 1) { + // loop count sub-block + final int b1 = (block[1]) & 0xff; + final int b2 = (block[2]) & 0xff; + loopCount = (b2 << 8) | b1; + } + } while ((blockSize > 0) && !err()); + } + + /** + * Reads next 16-bit value, LSB first + */ + protected int readShort() { + // read 16-bit value + return rawData.getShort(); + } + + /** + * Skips variable length blocks up to and including next zero length block. + */ + protected void skip() { + do { + readBlock(); + } while ((blockSize > 0) && !err()); + } + + public int getWidth() { + return width; + } + + public int getHeight() { + return height; + } +} \ No newline at end of file diff --git a/android/app/src/main/java/com/mogujie/tt/ui/widget/GifLoadTask.java b/android/app/src/main/java/com/mogujie/tt/ui/widget/GifLoadTask.java new file mode 100644 index 000000000..a1598d370 --- /dev/null +++ b/android/app/src/main/java/com/mogujie/tt/ui/widget/GifLoadTask.java @@ -0,0 +1,112 @@ +package com.mogujie.tt.ui.widget; + +import android.os.AsyncTask; + +import com.mogujie.tt.utils.CommonUtil; +import com.squareup.okhttp.Cache; +import com.squareup.okhttp.OkHttpClient; +import com.squareup.okhttp.Request; +import com.squareup.okhttp.Response; +import com.squareup.okhttp.internal.DiskLruCache; +import com.squareup.okhttp.internal.Util; + +import org.apache.commons.io.IOUtils; + +import java.io.FilterInputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.UnsupportedEncodingException; +import java.net.MalformedURLException; +import java.net.URL; +import java.net.URLDecoder; + +/** + * Created by zhujian on 15/3/26. + */ +public class GifLoadTask extends AsyncTask { + + public GifLoadTask() { + } + + @Override + protected void onPreExecute() { + super.onPreExecute(); + } + + @Override + protected byte[] doInBackground(final String... params) { + final String gifUrl = params[0]; + if (gifUrl == null) + return null; + byte[] gif = null; + try { + gif = byteArrayHttpClient(gifUrl); + } catch (OutOfMemoryError e) { + } catch (IOException e) { + e.printStackTrace(); + } catch (Exception e) { + e.printStackTrace(); + } + return gif; + } + + private FilterInputStream getFromCache(String url) throws Exception { + DiskLruCache cache = DiskLruCache.open(CommonUtil.getImageSavePath(), 1, 2, 2*1024*1024); + cache.flush(); + String key = Util.hash(url); + final DiskLruCache.Snapshot snapshot; + try { + snapshot = cache.get(key); + if (snapshot == null) { + return null; + } + } catch (IOException e) { + return null; + } + FilterInputStream bodyIn = new FilterInputStream(snapshot.getInputStream(1)) { + @Override + public void close() throws IOException { + snapshot.close(); + super.close(); + } + }; + return bodyIn; + } + + public byte[] byteArrayHttpClient(final String urlString) throws Exception { + OkHttpClient client = null; + if (client == null) { + client = new OkHttpClient(); + Cache responseCache = new Cache(CommonUtil.getImageSavePath(), 2*1024*1024); + client.setCache(responseCache); + client.setReadTimeout(30, java.util.concurrent.TimeUnit.SECONDS); + client.setConnectTimeout(30, java.util.concurrent.TimeUnit.SECONDS); + } + FilterInputStream inputStream = getFromCache(urlString); + if (inputStream != null) { + return IOUtils.toByteArray(inputStream); + } + InputStream in = null; + try { + final String decodedUrl = URLDecoder.decode(urlString, "UTF-8"); + final URL url = new URL(decodedUrl); + final Request request = new Request.Builder().url(url).build(); + final Response response = client.newCall(request).execute(); + in = response.body().byteStream(); + return IOUtils.toByteArray(in); + } catch (final MalformedURLException e) { + } catch (final OutOfMemoryError e) { + } catch (final UnsupportedEncodingException e) { + } catch (final IOException e) { + } finally { + if (in != null) { + try { + in.close(); + } catch (final IOException ignored) { + } + } + } + return null; + } +} + diff --git a/android/app/src/main/java/com/mogujie/tt/ui/widget/GifView.java b/android/app/src/main/java/com/mogujie/tt/ui/widget/GifView.java new file mode 100644 index 000000000..8f86d3ae1 --- /dev/null +++ b/android/app/src/main/java/com/mogujie/tt/ui/widget/GifView.java @@ -0,0 +1,172 @@ +package com.mogujie.tt.ui.widget; + +/** + * Created by zhujian on 15/3/9. + */ +import android.content.Context; +import android.graphics.Bitmap; +import android.os.Handler; +import android.os.Looper; +import android.util.AttributeSet; +import android.util.Log; +import android.widget.ImageView; + +import com.mogujie.tt.app.IMApplication; + +public class GifView extends ImageView implements Runnable { + + private static final String TAG = "GifDecoderView"; + private GifDecoder gifDecoder; + private Bitmap tmpBitmap; + private final Handler handler = new Handler(Looper.getMainLooper()); + private boolean animating; + private boolean shouldClear; + private Thread animationThread; + private OnFrameAvailable frameCallback = null; + + private final Runnable updateResults = new Runnable() { + @Override + public void run() { + if (tmpBitmap != null && !tmpBitmap.isRecycled()) + setImageBitmap(tmpBitmap); + } + }; + + private final Runnable cleanupRunnable = new Runnable() { + @Override + public void run() { + if (tmpBitmap != null && !tmpBitmap.isRecycled()) + tmpBitmap.recycle(); + tmpBitmap = null; + gifDecoder = null; + animationThread = null; + shouldClear = false; + } + }; + + public GifView(final Context context, final AttributeSet attrs,int defStyle) { + super(context, attrs,defStyle); + } + + public GifView(final Context context, final AttributeSet attrs) { + super(context, attrs); + } + + public GifView(final Context context) { + super(context); + } + + public void setBytes(final byte[] bytes) { + gifDecoder = new GifDecoder(); + try { + gifDecoder.read(bytes); + } catch (final OutOfMemoryError e) { + gifDecoder = null; + Log.e(TAG, e.getMessage(), e); + return; + } + + if (canStart()) { + animationThread = new Thread(this); + animationThread.start(); + } + } + + public void startAnimation() { + animating = true; + + if (canStart()) { + animationThread = new Thread(this); + animationThread.start(); + } + } + + public boolean isAnimating() { + return animating; + } + + public void stopAnimation() { + animating = false; + + if (animationThread != null) { + animationThread.interrupt(); + animationThread = null; + } + } + + public void clear() { + animating = false; + shouldClear = true; + stopAnimation(); + } + + private boolean canStart() { + return animating && gifDecoder != null && animationThread == null; + } + + public int getGifWidth() { + return gifDecoder.getWidth(); + } + + public int getGifHeight() { + return gifDecoder.getHeight(); + } + + @Override + public void run() { + if (shouldClear) { + handler.post(cleanupRunnable); + return; + } + int n = 0; + if(gifDecoder!=null) + { + n = gifDecoder.getFrameCount(); + } + + do { + + for (int i = 0; i < n; i++) { + + if (!animating) + break; + try { + tmpBitmap = gifDecoder.getNextFrame(); + if (frameCallback != null) + tmpBitmap = frameCallback.onFrameAvailable(tmpBitmap); + + if (!animating) + break; + handler.post(updateResults); + } catch (final ArrayIndexOutOfBoundsException | IllegalArgumentException e) { + Log.w(TAG, e); + } + if (!animating) + break; + gifDecoder.advance(); + try { + Thread.sleep(150); + } catch (final Exception e) { + // suppress any exception + // it can be InterruptedException or IllegalArgumentException + } + } + if (!IMApplication.gifRunning) { + this.clear(); + return; + } + } while (animating); + } + + public OnFrameAvailable getOnFrameAvailable() { + return frameCallback; + } + + public void setOnFrameAvailable(OnFrameAvailable frameProcessor) { + this.frameCallback = frameProcessor; + } + + public interface OnFrameAvailable { + public Bitmap onFrameAvailable(Bitmap bitmap); + } +} diff --git a/android/app/src/main/java/com/mogujie/tt/ui/widget/GroupManagerGridView.java b/android/app/src/main/java/com/mogujie/tt/ui/widget/GroupManagerGridView.java new file mode 100644 index 000000000..66077797b --- /dev/null +++ b/android/app/src/main/java/com/mogujie/tt/ui/widget/GroupManagerGridView.java @@ -0,0 +1,39 @@ +package com.mogujie.tt.ui.widget; + +import android.content.Context; +import android.util.AttributeSet; +import android.util.DisplayMetrics; +import android.view.WindowManager; +import android.widget.GridView; + +import com.mogujie.tt.utils.ScreenUtil; + +/** + * Created by zhujian on 15/1/19. + */ +public class GroupManagerGridView extends GridView { + private Context ctx; + public GroupManagerGridView(Context context, AttributeSet attrs) { + super(context, attrs); + this.ctx = context; + } + public GroupManagerGridView(Context context) { + super(context); + this.ctx = context; + } + public GroupManagerGridView(Context context, AttributeSet attrs, int defStyle) { + super(context, attrs, defStyle); + this.ctx = context; + } + @Override + public void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { + DisplayMetrics metric = new DisplayMetrics(); + WindowManager windowManager = (WindowManager) ctx.getSystemService(Context.WINDOW_SERVICE); + windowManager.getDefaultDisplay().getMetrics(metric); + int height =metric.heightPixels; + int expandSpec = MeasureSpec.makeMeasureSpec( + height-ScreenUtil.instance(ctx).dip2px(250), MeasureSpec.AT_MOST); + super.onMeasure(widthMeasureSpec, expandSpec); + } + +} diff --git a/android/app/src/main/java/com/mogujie/tt/ui/widget/IMBaseImageView.java b/android/app/src/main/java/com/mogujie/tt/ui/widget/IMBaseImageView.java new file mode 100644 index 000000000..6242dd368 --- /dev/null +++ b/android/app/src/main/java/com/mogujie/tt/ui/widget/IMBaseImageView.java @@ -0,0 +1,124 @@ +package com.mogujie.tt.ui.widget; + +import android.content.Context; +import android.graphics.Bitmap; +import android.text.TextUtils; +import android.util.AttributeSet; +import android.view.View; +import android.widget.ImageView; + +import com.mogujie.tt.R; +import com.mogujie.tt.utils.CommonUtil; +import com.mogujie.tt.utils.ImageLoaderUtil; +import com.nostra13.universalimageloader.core.assist.ImageSize; +import com.nostra13.universalimageloader.core.listener.SimpleImageLoadingListener; + +/** + * Created by zhujian on 15/1/14. + */ +public class IMBaseImageView extends ImageView { + + protected String imageUrl=null; + protected int imageId; + protected boolean isAttachedOnWindow=false; + protected String avatarAppend= null; + protected int defaultImageRes = R.drawable.tt_default_user_portrait_corner; + protected int corner=0; + + public IMBaseImageView(Context context) { + super(context); + } + + public IMBaseImageView(Context context, AttributeSet attrs) { + super(context, attrs); + } + + public IMBaseImageView(Context context, AttributeSet attrs, int defStyleAttr) { + super(context, attrs, defStyleAttr); + } + + public void setAvatarAppend(String appendStr){ + this.avatarAppend=appendStr; + } + + public void setImageUrl(String url) { + this.imageUrl = url; + if (isAttachedOnWindow){ + if (!TextUtils.isEmpty(this.imageUrl)&&this.imageUrl.equals(CommonUtil.matchUrl(this.imageUrl))) { + if (!TextUtils.isEmpty(avatarAppend)){ + if(! this.imageUrl.contains(avatarAppend)) { + this.imageUrl += avatarAppend; + } + } + ImageLoaderUtil.getImageLoaderInstance().displayImage(this.imageUrl, this, ImageLoaderUtil.getAvatarOptions(corner, defaultImageRes)); + }else{ + String defaultUri="drawable://" + defaultImageRes; + if(imageId!=0) + { + defaultUri="drawable://" + imageId; + } + ImageLoaderUtil.getImageLoaderInstance().displayImage(defaultUri, this, ImageLoaderUtil.getAvatarOptions(corner, defaultImageRes)); + } + } + } + + public void setImageId(int id) { + this.imageId=id; + } + + public void setDefaultImageRes(int defaultImageRes) { + this.defaultImageRes = defaultImageRes; + + } + + public void setCorner(int corner) { + this.corner = corner; + } + + @Deprecated + public void loadImage(String imageUrl,ImageSize imageSize,ImageLoaddingCallback imageLoaddingCallback){ + ImageLoaderUtil.getImageLoaderInstance().loadImage(imageUrl,imageSize,new ImageLoaddingListener(imageLoaddingCallback)); + } + + public int getCorner() { + return corner; + } + + public int getDefaultImageRes() { + return defaultImageRes; + } + + public String getImageUrl() { + return imageUrl; + } + + @Override + protected void onAttachedToWindow() { + super.onAttachedToWindow(); + isAttachedOnWindow = true; + setImageUrl(this.imageUrl); + } + + protected void onDetachedFromWindow() { + super.onDetachedFromWindow(); + this.isAttachedOnWindow=false; + ImageLoaderUtil.getImageLoaderInstance().cancelDisplayTask(this); + } + + private static class ImageLoaddingListener extends SimpleImageLoadingListener { + private ImageLoaddingCallback imageLoaddingCallback; + + public ImageLoaddingListener(ImageLoaddingCallback callback) { + this.imageLoaddingCallback=callback; + } + @Override + public void onLoadingComplete(String imageUri, View view, Bitmap loadedImage){ + imageLoaddingCallback.onLoadingComplete(imageUri,view,loadedImage); + } + + } + + public interface ImageLoaddingCallback { + public void onLoadingComplete(String imageUri, View view, Bitmap loadedImage); + } +} diff --git a/android/app/src/main/java/com/mogujie/tt/ui/widget/IMGroupAvatar.java b/android/app/src/main/java/com/mogujie/tt/ui/widget/IMGroupAvatar.java new file mode 100644 index 000000000..831426812 --- /dev/null +++ b/android/app/src/main/java/com/mogujie/tt/ui/widget/IMGroupAvatar.java @@ -0,0 +1,205 @@ +package com.mogujie.tt.ui.widget; + +import android.content.Context; +import android.util.AttributeSet; +import android.view.Gravity; +import android.view.ViewGroup; +import android.widget.ImageView; +import android.widget.LinearLayout; + +import com.mogujie.tt.R; +import com.mogujie.tt.utils.ScreenUtil; + +import java.util.ArrayList; + +/** + * Created by zhujian on 15/1/14. + */ +public class IMGroupAvatar extends LinearLayout { + private String avatarUrlAppend=null; + private int parentAvatarSize = 0; + private int childAvatarSize = 0; + private int childMargin = 0; + private int avatarCount = 0; + private int maxColumnSize = 0; + private int rowCnt = 0; + private int parentPadding = 0; + private int childCorner =0; + private int defaultChildAvatarRes = R.drawable.group_default; + private int defaultParentAvatarBk = R.drawable.group_avatar_bk; + private ArrayList mAvatarImages = new ArrayList<>(); + private ArrayList mImageUrls = new ArrayList(); + + private static int DEFAULT_MAX_COLUMN_SIZE = 3; + private static final int DEFAULT_PADDING_DIP = 3; + private static final int DEFAULT_MARGIN_DIP = 2; + private static final int DEFAULT_VIEW_SIZE_DIP = 53; + private static int currentIndex; + + + public IMGroupAvatar(Context ctx){ + this(ctx, null); + } + + public IMGroupAvatar(Context context, AttributeSet attrs) { + super(context, attrs); + setBackgroundResource(defaultParentAvatarBk); + setOrientation(VERTICAL); + setGravity(Gravity.CENTER); + parentPadding = ScreenUtil.instance(getContext()).dip2px(DEFAULT_PADDING_DIP); + childMargin = ScreenUtil.instance(getContext()).dip2px(DEFAULT_MARGIN_DIP); + parentAvatarSize = ScreenUtil.instance(getContext()).dip2px(DEFAULT_VIEW_SIZE_DIP); + setPadding(parentPadding, parentPadding, parentPadding, parentPadding); + } + + public void setParentPadding(int padding){ + if (padding >= 0) { + parentPadding = ScreenUtil.instance(getContext()).dip2px(padding); + setPadding(parentPadding, parentPadding, parentPadding, parentPadding); + } + } + + public void setAvatarUrlAppend(String appendStr){ + this.avatarUrlAppend=appendStr; + } + + public void setAvatarUrls(ArrayList avatarUrls){ + try { + if (null != avatarUrls && avatarUrls.size() >= 1) { + if (null != this.mImageUrls && this.mImageUrls.size() > 0 && this.mImageUrls.size() == avatarUrls.size()) { + ArrayList urls = new ArrayList(this.mImageUrls); + for (String url : avatarUrls) { + if (urls.contains(url)) { + urls.remove(url); + } + } + if (null != urls && urls.size() == 0) { + return; + } + } + + removeAllViews(); + mAvatarImages.clear(); + mImageUrls.clear(); + mImageUrls.addAll(avatarUrls); + calcParams(avatarUrls.size()); + initAvatarsLayout(); + } + }catch (Exception e){ + } + } + + private void calcParams(int avatarCount){ + this.avatarCount = avatarCount; + maxColumnSize = getColumnMaxSize(avatarCount); + if (maxColumnSize > 0){ + rowCnt = (this.avatarCount + maxColumnSize - 1 ) / maxColumnSize; + } + + int totalWidth = getMeasuredWidth() > 0 ? getMeasuredWidth() : parentAvatarSize; + if (maxColumnSize > 0) { + childAvatarSize = (totalWidth - 2 * parentPadding - (maxColumnSize - 1) * childMargin) / maxColumnSize; + } + } + + private void initAvatarsLayout(){ + int columnSizeOfFirstRow = 0; + columnSizeOfFirstRow = avatarCount - (rowCnt - 1) * maxColumnSize; + currentIndex=0; + for (int i = 0; i < rowCnt; i++){ + initOneRow(i,i == 0, i == 0 ? columnSizeOfFirstRow : maxColumnSize); + } + } + + private void initOneRow(int curRow,boolean isFirst, int columnSize){ + try { + LinearLayout rowLayout = new LinearLayout(getContext()); + rowLayout.setOrientation(HORIZONTAL); + LayoutParams params = new LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, childAvatarSize); + if (!isFirst) { + params.topMargin = childMargin; + } + addView(rowLayout, params); + + for (int i = 0; i < columnSize; i++) { + IMBaseImageView avatar = new IMBaseImageView(getContext()); + avatar.setScaleType(ImageView.ScaleType.CENTER_CROP); + LayoutParams avatarParams = new LayoutParams(childAvatarSize, childAvatarSize); + avatarParams.leftMargin = i == 0 ? 0 : childMargin; + + int avatarIndex = curRow * columnSize + i; + String avatarUrl = null; +// if (avatarIndex >= 0 && avatarIndex < mImageUrls.size()) { +// avatarUrl = mImageUrls.get(avatarIndex); +// } + avatarUrl = mImageUrls.get(currentIndex); + avatar.setAvatarAppend(avatarUrlAppend); +// avatar.setBackgroundResource(defaultChildAvatarRes); + avatar.setImageResource(R.drawable.tt_default_user_portrait_corner); + avatar.setCorner(ScreenUtil.instance(getContext()).dip2px(childCorner)); + avatar.setDefaultImageRes(defaultChildAvatarRes); + avatar.setImageUrl(avatarUrl); + + rowLayout.addView(avatar, avatarParams); + mAvatarImages.add(avatar); + currentIndex+=1; + } + }catch (Exception e){ + + } + } + + private int getColumnMaxSize(int avatarCount){ + int columnSize = DEFAULT_MAX_COLUMN_SIZE; + for (columnSize = DEFAULT_MAX_COLUMN_SIZE; columnSize > 1; columnSize--){ + int rowSize = (avatarCount + columnSize - 1) / columnSize; + int minColumn = avatarCount - (rowSize - 1) * columnSize; + if (columnSize == rowSize || (Math.abs(columnSize - rowSize) == 1 && Math.abs(columnSize - minColumn) <= 1)){ + return columnSize; + } + } + return columnSize; + } + + public void setChildCorner(int childCorner) { + this.childCorner = childCorner; + } + + public int getDefaultParentAvatarBk() { + return defaultParentAvatarBk; + } + + public int getChildCorner() { + return childCorner; + } + + public ArrayList getAvatarUrls(){ + return this.mImageUrls; + } + + public void setChildMarginDip(int marginDip){ + childMargin =marginDip; + } + + public void setViewSize(int viewSize){ + if (viewSize > 0) { + parentAvatarSize = viewSize; + } + } + + public void setDefaultParentAvatarBk(int defaultParentAvatarBk) { + this.defaultParentAvatarBk = defaultParentAvatarBk; + } + + public int getDefaultChildAvatarRes() { + return defaultChildAvatarRes; + } + + public void setDefaultChildAvatarRes(int defaultChildAvatarRes) { + this.defaultChildAvatarRes = defaultChildAvatarRes; + } + + public void setMaxColumnSize(int maxColumnSize){ + DEFAULT_MAX_COLUMN_SIZE = maxColumnSize; + } +} \ No newline at end of file diff --git a/android/app/src/main/java/com/mogujie/tt/ui/widget/MGDialog.java b/android/app/src/main/java/com/mogujie/tt/ui/widget/MGDialog.java new file mode 100644 index 000000000..7454a79ac --- /dev/null +++ b/android/app/src/main/java/com/mogujie/tt/ui/widget/MGDialog.java @@ -0,0 +1,223 @@ + +package com.mogujie.tt.ui.widget; + +import android.app.Dialog; +import android.content.Context; +import android.text.TextUtils; +import android.view.Gravity; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup.MarginLayoutParams; +import android.widget.Button; +import android.widget.TextView; + +import com.mogujie.tools.ScreenTools; +import com.mogujie.tt.R; + +/** + * Dialog基类,提供基本的“确定”,“取消”按钮和title与message的显示。子类可以继承Builder,在content + * layout中添加其他控件进行自定义。tips:cancel的回调不需要调用dialog.dismiss(),控件会自动调用 + * + * @author dolphinWang + */ + +public class MGDialog extends Dialog implements View.OnClickListener { + + private OnButtonClickListener mOnButtonClickListener; + + protected View mDialogContentView; + + private boolean mButtonInverse; + + public MGDialog(Context context) { + super(context); + } + + public MGDialog(Context context, int Theme) { + super(context, Theme); + } + + @Override + public void onClick(View v) { + int id = v.getId(); + if (R.id.imPositiveButton == id) + { + if (mOnButtonClickListener != null) { + if (mButtonInverse) { + mOnButtonClickListener.onCancelButtonClick(this); + dismiss(); + } else { + mOnButtonClickListener.onOKButtonClick(this); + } + } + } + else if (R.id.imNegativeButton == id) { + if (mOnButtonClickListener != null) { + if (mButtonInverse) { + mOnButtonClickListener.onOKButtonClick(this); + } else { + mOnButtonClickListener.onCancelButtonClick(this); + dismiss(); + } + } + } + } + + public void setOnButtonClickListener(OnButtonClickListener l) { + mOnButtonClickListener = l; + } + + public void setTitleText(String text) { + if (TextUtils.isEmpty(text)) { + return; + } + + ((TextView) mDialogContentView.findViewById(R.id.imTitle)).setText(text); + } + + public void setSubTitleText(String text) { + if (TextUtils.isEmpty(text)) { + return; + } + + ((TextView) mDialogContentView.findViewById(R.id.imSubTitle)) + .setText(text); + } + + @Override + public void show() { + super.show(); + setContentView(mDialogContentView); + } + + public interface OnButtonClickListener { + public void onOKButtonClick(MGDialog dialog); + + public void onCancelButtonClick(MGDialog dialog); + } + + public static class DialogBuilder { + protected String positiveButtonText; + protected String negativeButtonText; + protected String titleText; + protected String subTitleText; + protected boolean buttonInverse; + + protected int subTitleTextGravity = Integer.MIN_VALUE; + + protected MGDialog dialog; + + protected Context context; + + protected View dialogLayout; + + protected LayoutInflater mInflater; + + public DialogBuilder(Context context) { + this.context = context; + + mInflater = LayoutInflater.from(context); + } + + public DialogBuilder setPositiveButtonText(String positiveButtonText) { + this.positiveButtonText = positiveButtonText; + + return this; + } + + public DialogBuilder setNegativeButtonText(String negativeButtonText) { + this.negativeButtonText = negativeButtonText; + + return this; + } + + public DialogBuilder setTitleText(String titleText) { + this.titleText = titleText; + + return this; + } + + public DialogBuilder setSubTitleText(String subTitleText) { + this.subTitleText = subTitleText; + + return this; + } + + public DialogBuilder setSubTitleTextGravity(int gravity) { + this.subTitleTextGravity = gravity; + + return this; + } + + public DialogBuilder inverseButton() { + buttonInverse = true; + + return this; + } + + protected void setupViews() { + + dialog.getWindow().getAttributes().gravity = Gravity.CENTER; + // dialog.getWindow().setWindowAnimations(R.style.PopupAnimation); + + dialogLayout = mInflater.inflate(R.layout.tt_view_dialog_base, null); + + Button okBtn = (Button) dialogLayout + .findViewById(R.id.imPositiveButton); + if (!TextUtils.isEmpty(positiveButtonText)) { + okBtn.setOnClickListener(dialog); + okBtn.setText(positiveButtonText); + } else { + okBtn.setVisibility(View.GONE); + } + + Button cancelBtn = (Button) dialogLayout + .findViewById(R.id.imNegativeButton); + if (!TextUtils.isEmpty(negativeButtonText)) { + cancelBtn.setOnClickListener(dialog); + cancelBtn.setText(negativeButtonText); + } else { + cancelBtn.setVisibility(View.GONE); + + MarginLayoutParams mlp = (MarginLayoutParams) okBtn.getLayoutParams(); + mlp.leftMargin = 0; + } + + TextView titleView = (TextView) dialogLayout + .findViewById(R.id.imTitle); + if (!TextUtils.isEmpty(titleText)) { + titleView.setVisibility(View.VISIBLE); + titleView.setText(titleText); + } + + if (!TextUtils.isEmpty(subTitleText)) { + TextView subTitleView = (TextView) dialogLayout + .findViewById(R.id.imSubTitle); + subTitleView.setVisibility(View.VISIBLE); + subTitleView.setText(subTitleText); + + if (subTitleTextGravity != Integer.MIN_VALUE) { + subTitleView.setGravity(subTitleTextGravity); + } + } else { + // title 需要设置一下bottom margin + MarginLayoutParams mlp = (MarginLayoutParams) titleView + .getLayoutParams(); + mlp.bottomMargin = ScreenTools.instance(context).dip2px(30); + } + + dialog.mDialogContentView = dialogLayout; + dialog.mButtonInverse = buttonInverse; + } + + /** + * @return + */ + public MGDialog build() { + dialog = new MGDialog(context, R.style.imDialog); + + setupViews(); + return dialog; + } + } +} diff --git a/android/app/src/main/java/com/mogujie/tt/ui/widget/MGProgressbar.java b/android/app/src/main/java/com/mogujie/tt/ui/widget/MGProgressbar.java new file mode 100644 index 000000000..c0524feb6 --- /dev/null +++ b/android/app/src/main/java/com/mogujie/tt/ui/widget/MGProgressbar.java @@ -0,0 +1,81 @@ + +package com.mogujie.tt.ui.widget; + +import android.content.Context; +import android.util.AttributeSet; +import android.view.LayoutInflater; +import android.view.View; +import android.widget.Button; +import android.widget.LinearLayout; +import android.widget.ProgressBar; +import android.widget.TextView; + +import com.mogujie.tt.R; + +public class MGProgressbar extends LinearLayout { + + private ProgressBar mProgressBar; + private TextView mLoadingText; + private Button mRefreshButton; + private boolean mbTextShow = true; + + public interface OnRefreshBtnListener { + void onRefresh(); + } + + public MGProgressbar(Context context) { + this(context, null); + } + + public MGProgressbar(Context context, AttributeSet attrs) { + super(context, attrs); + setOrientation(LinearLayout.VERTICAL); + LayoutInflater inflater = (LayoutInflater) context.getSystemService + (Context.LAYOUT_INFLATER_SERVICE); + + inflater.inflate(R.layout.tt_progress, this, true); + mProgressBar = (ProgressBar) findViewById(R.id.progress_bar); + mLoadingText = (TextView) findViewById(R.id.loading_text); + mRefreshButton = (Button) findViewById(R.id.refresh_button); + + hideProgress(); + } + + public void showProgress() { + mProgressBar.setVisibility(View.VISIBLE); + if (mbTextShow) { + mLoadingText.setVisibility(View.VISIBLE); + } + mRefreshButton.setVisibility(View.GONE); + } + + public void hideProgress() { + mProgressBar.setVisibility(View.GONE); + mLoadingText.setVisibility(View.GONE); + mRefreshButton.setVisibility(View.GONE); + } + + public void showRefreshBtn() { + mRefreshButton.setVisibility(View.VISIBLE); + mProgressBar.setVisibility(View.GONE); + mLoadingText.setVisibility(View.GONE); + } + + public void setRefreshBtnListener(final OnRefreshBtnListener listener) { + mRefreshButton.setOnClickListener(new OnClickListener() { + @Override + public void onClick(View v) { + showProgress(); + listener.onRefresh(); + } + }); + } + + public void setShowText(boolean bShow) { + mbTextShow = bShow; + } + + public void setText(String text) { + mLoadingText.setText(text); + } +} diff --git a/android/app/src/main/java/com/mogujie/tt/ui/widget/NaviTabButton.java b/android/app/src/main/java/com/mogujie/tt/ui/widget/NaviTabButton.java new file mode 100644 index 000000000..8e821bdce --- /dev/null +++ b/android/app/src/main/java/com/mogujie/tt/ui/widget/NaviTabButton.java @@ -0,0 +1,133 @@ +package com.mogujie.tt.ui.widget; + +import android.content.Context; +import android.graphics.drawable.Drawable; +import android.util.AttributeSet; +import android.view.LayoutInflater; +import android.view.View; +import android.widget.FrameLayout; +import android.widget.ImageView; +import android.widget.RelativeLayout; +import android.widget.TextView; + +import com.mogujie.tt.R; +import com.mogujie.tt.ui.activity.MainActivity; +import com.mogujie.tt.utils.Logger; +import com.mogujie.tt.ui.helper.listener.OnDoubleClickListener; + +public class NaviTabButton extends FrameLayout { + private int mIndex; + + private ImageView mImage; + private TextView mTitle; + private TextView mNotify; + + private Drawable mSelectedImg; + private Drawable mUnselectedImg; + + private Context mContext; + + private Logger logger = Logger.getLogger(NaviTabButton.class); + + public NaviTabButton(Context context) { + this(context, null); + } + + public NaviTabButton(Context context, AttributeSet attrs) { + this(context, attrs, 0); + } + + public NaviTabButton(Context context, AttributeSet attrs, int defStyle) { + super(context, attrs, defStyle); + + this.mContext = context; + LayoutInflater inflater = (LayoutInflater) context + .getSystemService(Context.LAYOUT_INFLATER_SERVICE); + inflater.inflate(R.layout.tt_navi_tab_button, this, true); + RelativeLayout container = (RelativeLayout) findViewById(R.id.tab_btn_container); + + mImage = (ImageView) findViewById(R.id.tab_btn_default); + mTitle = (TextView) findViewById(R.id.tab_btn_title); + mNotify = (TextView) findViewById(R.id.tab_unread_notify); + + /**双击的判断是有延迟的,为了其他三个按钮click的点击速度,所以区别对待*/ + if (mIndex == 0) { + OnDoubleClickListener touchListener = new OnDoubleClickListener() { + @Override + public void onDoubleClick(View view) { + if (mIndex == 0) { + ((MainActivity) mContext).chatDoubleListener(); + } + } + + @Override + public void onClick(View view) { + } + }; + container.setOnTouchListener(touchListener); + } + + View.OnClickListener clickListener = new View.OnClickListener() { + @Override + public void onClick(View v) { + ((MainActivity) mContext).setFragmentIndicator(mIndex); + } + }; + container.setOnClickListener(clickListener); + + } + + public void setIndex(int index) { + this.mIndex = index; + } + + public void setUnselectedImage(Drawable img) { + this.mUnselectedImg = img; + } + + public void setSelectedImage(Drawable img) { + this.mSelectedImg = img; + } + + private void setSelectedColor(Boolean selected) { + if (selected) { + mTitle.setTextColor(getResources().getColor( + R.color.default_blue_color)); + } else { + mTitle.setTextColor(getResources().getColor( + R.color.default_light_grey_color)); + } + } + + public void setSelectedButton(Boolean selected) { + setSelectedColor(selected); + if (selected) { + mImage.setImageDrawable(mSelectedImg); + } else { + mImage.setImageDrawable(mUnselectedImg); + } + } + + public void setTitle(String title) { + mTitle.setText(title); + } + + public void setUnreadNotify(int unreadNum) { + logger.d("unread#setUreadNotify -> unreadNum:%d", unreadNum); + if (0 == unreadNum) { + mNotify.setVisibility(View.INVISIBLE); + return; + } + + String notify; + if (unreadNum > 99) { + notify = "99+"; + } else { + notify = Integer.toString(unreadNum); + } + + mNotify.setText(notify); + mNotify.setVisibility(View.VISIBLE); + } + +} diff --git a/android/app/src/main/java/com/mogujie/tt/ui/widget/PinkToast.java b/android/app/src/main/java/com/mogujie/tt/ui/widget/PinkToast.java new file mode 100644 index 000000000..88953ea19 --- /dev/null +++ b/android/app/src/main/java/com/mogujie/tt/ui/widget/PinkToast.java @@ -0,0 +1,67 @@ +/** + * @author zhouzhengnan + * @date 20 Oct 2013 + */ + +package com.mogujie.tt.ui.widget; + +import android.content.Context; +import android.graphics.Color; +import android.view.Gravity; +import android.view.ViewGroup; +import android.widget.TextView; +import android.widget.Toast; + +import com.mogujie.tools.ScreenTools; +import com.mogujie.tt.R; + +/** + * @author zhouzhengnan + * @date 20 Oct 2013 + */ +public class PinkToast extends Toast { + + /** + * @param context + */ + public PinkToast(Context context) { + super(context); + } + + public static Toast makeText(Context context, CharSequence text, int duration) { + Toast result = Toast.makeText(context, text, duration); + result.getView().setBackgroundResource(R.drawable.tt_waterfall_refresh_bg); + result.setGravity(Gravity.CENTER, 0, 0); + TextView tv = (TextView) ((ViewGroup) result.getView()).getChildAt(0); + ScreenTools tools = ScreenTools.instance(context); + + tv.setPadding(tools.dip2px(5), tools.dip2px(8), tools.dip2px(5), + tools.dip2px(8)); + tv.setShadowLayer(0, 0, 0, Color.TRANSPARENT); + tv.setMinWidth(tools.dip2px(180)); + tv.setGravity(Gravity.CENTER); + tv.setTextColor(context.getResources().getColor(android.R.color.white)); + return result; + } + + public static Toast makeText(Context context, int id, int duration) { + Toast result = Toast.makeText(context, id, duration); + result.getView().setBackgroundResource(R.drawable.tt_waterfall_refresh_bg); + result.setGravity(Gravity.CENTER, 0, 0); + TextView tv = (TextView) ((ViewGroup) result.getView()).getChildAt(0); + ScreenTools tools = ScreenTools.instance(context); + + tv.setPadding(tools.dip2px(5), tools.dip2px(8), tools.dip2px(5), + tools.dip2px(8)); + tv.setShadowLayer(0, 0, 0, Color.TRANSPARENT); + tv.setMinWidth(tools.dip2px(180)); + tv.setGravity(Gravity.CENTER); + tv.setTextColor(context.getResources().getColor(android.R.color.white)); + return result; + } + + public void show() { + super.show(); + } + +} diff --git a/android/app/src/main/java/com/mogujie/tt/ui/widget/SearchEditText.java b/android/app/src/main/java/com/mogujie/tt/ui/widget/SearchEditText.java new file mode 100644 index 000000000..523b84b02 --- /dev/null +++ b/android/app/src/main/java/com/mogujie/tt/ui/widget/SearchEditText.java @@ -0,0 +1,138 @@ +package com.mogujie.tt.ui.widget; + +import android.content.Context; +import android.graphics.drawable.Drawable; +import android.text.Editable; +import android.text.TextWatcher; +import android.util.AttributeSet; +import android.view.MotionEvent; +import android.view.View; +import android.view.View.OnFocusChangeListener; +import android.view.animation.Animation; +import android.view.animation.CycleInterpolator; +import android.view.animation.TranslateAnimation; +import android.widget.EditText; + +import com.mogujie.tt.R; + +public class SearchEditText extends EditText implements + OnFocusChangeListener, TextWatcher { + private Drawable clearWordsImage; + + public SearchEditText(Context context) { + this(context, null); + } + + public SearchEditText(Context context, AttributeSet attrs) { + this(context, attrs, android.R.attr.editTextStyle); + } + + public SearchEditText(Context context, AttributeSet attrs, int defStyle) { + super(context, attrs, defStyle); + init(); + } + + + private void init() { + //获取EditText的DrawableRight,假如没有设置我们就使用默认的图片 + clearWordsImage = getCompoundDrawables()[2]; + if (clearWordsImage == null) { + clearWordsImage = getResources() + .getDrawable(R.drawable.tt_delete_bar); + } + clearWordsImage.setBounds(0, 0, clearWordsImage.getIntrinsicWidth(), clearWordsImage.getIntrinsicHeight()); + setClearIconVisible(false); + setOnFocusChangeListener(this); + addTextChangedListener(this); + } + + + /** + * 因为我们不能直接给EditText设置点击事件,所以我们用记住我们按下的位置来模拟点击事件 + * 当我们按下的位置 在 EditText的宽度 - 图标到控件右边的间距 - 图标的宽度 和 + * EditText的宽度 - 图标到控件右边的间距之间我们就算点击了图标,竖直方向没有考虑 + */ + @Override + public boolean onTouchEvent(MotionEvent event) { + if (getCompoundDrawables()[2] != null) { + if (event.getAction() == MotionEvent.ACTION_UP) { + boolean touchable = event.getX() > (getWidth() + - getPaddingRight() - clearWordsImage.getIntrinsicWidth()) + && (event.getX() < ((getWidth() - getPaddingRight()))); + if (touchable) { + this.setText(""); + } + } + } + + return super.onTouchEvent(event); + } + + /** + * 当ClearEditText焦点发生变化的时候,判断里面字符串长度设置清除图标的显示与隐藏 + */ + @Override + public void onFocusChange(View v, boolean hasFocus) { + if (hasFocus) { + setClearIconVisible(getText().length() > 0); + } else { + setClearIconVisible(false); + } + } + + + /** + * 设置清除图标的显示与隐藏,调用setCompoundDrawables为EditText绘制上去 + * @param visible + */ + protected void setClearIconVisible(boolean visible) { + Drawable right = visible ? clearWordsImage : null; + setCompoundDrawables(getCompoundDrawables()[0], + getCompoundDrawables()[1], right, getCompoundDrawables()[3]); + } + + + /** + * 当输入框里面内容发生变化的时候回调的方法 + */ + @Override + public void onTextChanged(CharSequence s, int start, int count, + int after) { + setClearIconVisible(s.length() > 0); + } + + @Override + public void beforeTextChanged(CharSequence s, int start, int count, + int after) { + + } + + @Override + public void afterTextChanged(Editable s) { + + } + + + /** + * 设置晃动动画 + */ + public void setShakeAnimation(){ + this.setAnimation(shakeAnimation(5)); + } + + + /** + * 晃动动画 + * @param counts 1秒钟晃动多少下 + * @return + */ + public static Animation shakeAnimation(int counts){ + Animation translateAnimation = new TranslateAnimation(0, 10, 0, 0); + translateAnimation.setInterpolator(new CycleInterpolator(counts)); + translateAnimation.setDuration(1000); + return translateAnimation; + } + + +} + diff --git a/android/app/src/main/java/com/mogujie/tt/ui/widget/SortSideBar.java b/android/app/src/main/java/com/mogujie/tt/ui/widget/SortSideBar.java new file mode 100644 index 000000000..d9d879a0e --- /dev/null +++ b/android/app/src/main/java/com/mogujie/tt/ui/widget/SortSideBar.java @@ -0,0 +1,133 @@ + +package com.mogujie.tt.ui.widget; + +import android.content.Context; +import android.graphics.Bitmap; +import android.graphics.Canvas; +import android.graphics.Color; +import android.graphics.Paint; +import android.graphics.drawable.BitmapDrawable; +import android.graphics.drawable.ColorDrawable; +import android.util.AttributeSet; +import android.view.MotionEvent; +import android.view.View; +import android.widget.TextView; + +import com.mogujie.tt.R; +import com.mogujie.tt.utils.Logger; + +public class SortSideBar extends View { + private OnTouchingLetterChangedListener onTouchingLetterChangedListener; + + public static String[] b = { + "A", "B", "C", "D", "E", "F", "G", "H", "I", + "J", "K", "L", "M", "N", "O", "P", "Q", "R", "S", "T", "U", "V", + "W", "X", "Y", "Z", "#" + }; + private int sel = -1; + private Paint paint = new Paint(); + + private TextView textDialog; + + public void setTextView(TextView textview) { + this.textDialog = textview; + } + + public SortSideBar(Context context, AttributeSet attrs, int defStyle) { + super(context, attrs, defStyle); + } + + public SortSideBar(Context context, AttributeSet attrs) { + super(context, attrs); + } + + public SortSideBar(Context context) { + super(context); + } + + protected void onDraw(Canvas canvas) { + super.onDraw(canvas); + // 获取焦点改变背景颜色. + int height = getHeight();// 获取对应高度 + int width = getWidth(); // 获取对应宽度 + int singleHeight = height / (b.length + 1);// 获取每一个字母的高度 + + if (b.length > 0) { + BitmapDrawable bmpDraw = (BitmapDrawable) getResources().getDrawable( + R.drawable.tt_contact_side_search); + Bitmap bmp = bmpDraw.getBitmap(); + float left = width / 2 - paint.measureText(b[0]) / 2 - 4; + canvas.drawBitmap(bmp, left, 0, paint); + } + + for (int i = 0; i < b.length; i++) { + paint.setColor(Color.parseColor("#666666")); + //paint.setTypeface(Typeface.DEFAULT_BOLD); + paint.setAntiAlias(true); + + paint.setTextSize(21); + // 选中的状态 + if (i == sel) { + paint.setColor(Color.WHITE); + paint.setFakeBoldText(true); + } + // x坐标等于中间-字符串宽度的一半. + float xPos = width / 2 - paint.measureText(b[i]) / 2; + float yPos = singleHeight * i + singleHeight+singleHeight/2; + + canvas.drawText(b[i], xPos, yPos, paint); + paint.reset(); + } + } + + @SuppressWarnings("deprecation") + @Override + public boolean dispatchTouchEvent(MotionEvent event) { + final int action = event.getAction(); + final float y = event.getY();// 点击y坐标 + final int oldChoose = sel; + final OnTouchingLetterChangedListener listener = onTouchingLetterChangedListener; + final int c = (int) (y / getHeight() * b.length);// 点击y坐标所占总高度的比例*b数组的长度就等于点击b中的个数. + + switch (action) { + case MotionEvent.ACTION_UP: + setBackgroundDrawable(new ColorDrawable(0x00000000)); + sel = -1;// + invalidate(); + if (textDialog != null) { + textDialog.setVisibility(View.INVISIBLE); + } + break; + + default: + // setBackgroundResource(R.drawable.sidebar_background); + if (oldChoose != c) { + if (c >= 0 && c < b.length) { + if (listener != null) { + listener.onTouchingLetterChanged(b[c]); + } + if (textDialog != null) { + textDialog.setText(b[c]); + textDialog.setVisibility(View.VISIBLE); + } + + sel = c; + invalidate(); + } + } + + break; + } + return true; + } + + public void setOnTouchingLetterChangedListener( + OnTouchingLetterChangedListener onTouchingLetterChangedListener) { + this.onTouchingLetterChangedListener = onTouchingLetterChangedListener; + } + + public interface OnTouchingLetterChangedListener { + public void onTouchingLetterChanged(String s); + } + +} diff --git a/android/app/src/main/java/com/mogujie/tt/ui/widget/SpeekerToast.java b/android/app/src/main/java/com/mogujie/tt/ui/widget/SpeekerToast.java new file mode 100644 index 000000000..90b397f97 --- /dev/null +++ b/android/app/src/main/java/com/mogujie/tt/ui/widget/SpeekerToast.java @@ -0,0 +1,31 @@ + +package com.mogujie.tt.ui.widget; + +import android.app.Activity; +import android.content.Context; +import android.view.Gravity; +import android.view.LayoutInflater; +import android.view.View; +import android.widget.TextView; +import android.widget.Toast; + +import com.mogujie.tt.R; + +public class SpeekerToast { + public static void show(Context context, CharSequence text, int duration) { + LayoutInflater inflater = ((Activity) context).getLayoutInflater(); + View view = inflater.inflate(R.layout.tt_speeker_layout, null); + TextView title = (TextView) view.findViewById(R.id.top_tip); + title.setText(text); + Toast toast = new Toast(context.getApplicationContext()); + toast.setGravity( + Gravity.FILL_HORIZONTAL | Gravity.TOP, + 0, + (int) context.getResources().getDimension( + R.dimen.top_bar_default_height)); + toast.setDuration(duration); + toast.setView(view); + toast.show(); + } + +} diff --git a/android/app/src/main/java/com/mogujie/tt/ui/widget/TopTabButton.java b/android/app/src/main/java/com/mogujie/tt/ui/widget/TopTabButton.java new file mode 100644 index 000000000..951dc2c4a --- /dev/null +++ b/android/app/src/main/java/com/mogujie/tt/ui/widget/TopTabButton.java @@ -0,0 +1,99 @@ + +package com.mogujie.tt.ui.widget; + +import android.content.Context; +import android.os.Handler; +import android.os.Message; +import android.util.AttributeSet; +import android.view.LayoutInflater; +import android.view.View; +import android.widget.Button; +import android.widget.FrameLayout; + +import com.mogujie.tt.R; +import com.mogujie.tt.config.HandlerConstant; +import com.mogujie.tt.ui.fragment.ContactFragment; + +public class TopTabButton extends FrameLayout { + private Context context = null; + private Button tabALLBtn = null; + private Button tabDepartmentBtn = null; + + public Button getTabDepartmentBtn() { + return tabDepartmentBtn; + } + + public TopTabButton(Context cxt) { + super(cxt); + this.context = cxt; + initView(); + } + + public TopTabButton(Context cxt, AttributeSet attrs) { + super(cxt,attrs); + this.context = cxt; + initView(); + } + + public TopTabButton(Context cxt, AttributeSet attrs, int defStyle) { + super(cxt, attrs, defStyle); + this.context = cxt; + initView(); + } + + private void initView() { + // 加载布局 + LayoutInflater inflater = (LayoutInflater) context + .getSystemService(Context.LAYOUT_INFLATER_SERVICE); + inflater.inflate(R.layout.tt_top_tab_button, this); + + tabALLBtn = (Button) findViewById(R.id.all_btn); + tabDepartmentBtn = (Button) findViewById(R.id.department_btn); + + // tabDepartmentBtn.setText(context.getString(R.string.contact_department)); + // tabDepartmentBtn.setBackgroundResource(R.drawable.contact_top_right_nor); + tabDepartmentBtn.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + Handler handler = ContactFragment.getHandler(); + Message message = handler.obtainMessage(); + message.what=HandlerConstant.HANDLER_CHANGE_CONTACT_TAB; + message.obj = 1; + handler.sendMessage(message); + + setSelTextColor(1); + tabDepartmentBtn.setBackgroundResource(R.drawable.tt_contact_top_right_sel); + tabALLBtn.setBackgroundResource(R.drawable.tt_contact_top_left_nor); + } + }); + + // tabALLBtn.setText(context.getString(R.string.contact_all)); + // tabALLBtn.setBackgroundResource(R.drawable.contact_top_left_sel); + tabALLBtn.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + Handler handler = ContactFragment.getHandler(); + Message message = handler.obtainMessage(); + message.what=HandlerConstant.HANDLER_CHANGE_CONTACT_TAB; + message.obj = 0; + handler.sendMessage(message); + + setSelTextColor(0); + tabALLBtn.setBackgroundResource(R.drawable.tt_contact_top_left_sel); + tabDepartmentBtn.setBackgroundResource(R.drawable.tt_contact_top_right_nor); + } + }); + + } + + private void setSelTextColor(int index) { + if (0 == index) { + tabALLBtn.setTextColor(getResources().getColor(android.R.color.white)); + tabDepartmentBtn.setTextColor(getResources().getColor(R.color.default_blue_color)); + } else { + tabDepartmentBtn.setTextColor(getResources().getColor(android.R.color.white)); + tabALLBtn.setTextColor(getResources().getColor(R.color.default_blue_color)); + } + + } +} diff --git a/android/app/src/main/java/com/mogujie/tt/ui/widget/YayaEmoGridView.java b/android/app/src/main/java/com/mogujie/tt/ui/widget/YayaEmoGridView.java new file mode 100644 index 000000000..58253786f --- /dev/null +++ b/android/app/src/main/java/com/mogujie/tt/ui/widget/YayaEmoGridView.java @@ -0,0 +1,211 @@ + +package com.mogujie.tt.ui.widget; + +import android.content.Context; +import android.graphics.Color; +import android.graphics.drawable.ColorDrawable; +import android.support.v4.view.ViewPager; +import android.util.AttributeSet; +import android.view.Gravity; +import android.view.View; +import android.widget.AdapterView; +import android.widget.AdapterView.OnItemClickListener; +import android.widget.GridView; +import android.widget.ImageView; +import android.widget.LinearLayout; + +import com.mogujie.tt.R; +import com.mogujie.tt.ui.adapter.ViewPageAdapter; +import com.mogujie.tt.ui.adapter.YayaEmoGridViewAdapter; +import com.mogujie.tt.config.SysConstant; +import com.mogujie.tt.ui.helper.Emoparser; +import com.mogujie.tt.utils.CommonUtil; + +import java.util.ArrayList; +import java.util.List; + +public class YayaEmoGridView extends LinearLayout { + private Context _context; + private ViewPager _viewPager; + private LinearLayout _llDot; + + private OnEmoGridViewItemClick onEmoGridViewItemClick; + + private ImageView[] dots; + /** ViewPager当前页 */ + private int currentIndex; + /** ViewPager页数 */ + private int viewPager_size; + /** 默认一页20个item */ + private double pageItemCount = 8d; + + /** 保存每个页面的GridView视图 */ + private List list_Views; + + /** viewpage高度 */ + + public YayaEmoGridView(Context cxt) { + super(cxt); + _context = cxt; + initViewPage(); + initFootDots(); + } + + public YayaEmoGridView(Context cxt, AttributeSet attrs) { + super(cxt, attrs); + _context = cxt; + initViewPage(); + initFootDots(); + } + + private void initViewPage() { + setOrientation(VERTICAL); + _viewPager = new ViewPager(_context); + _llDot = new LinearLayout(_context); + + LayoutParams params = new LayoutParams(LayoutParams.MATCH_PARENT, + CommonUtil.getDefaultPannelHeight(_context)); + params.gravity=Gravity.BOTTOM; + _viewPager.setLayoutParams(params); + _llDot.setLayoutParams(new LayoutParams(LayoutParams.MATCH_PARENT, + LayoutParams.WRAP_CONTENT)); + _llDot.setGravity(Gravity.CENTER); + _llDot.setOrientation(HORIZONTAL); + addView(_viewPager); + addView(_llDot); + } + // 底部的三点 + private void initFootDots() { + viewPager_size = (int) Math.ceil(Emoparser.getInstance(_context) + .getYayaResIdList().length / pageItemCount); + int mod = Emoparser.getInstance(_context).getResIdList().length + % (SysConstant.pageSize - 1); + if (mod == 1) + --viewPager_size; + if (0 < viewPager_size) { + if (viewPager_size == 1) { + _llDot.setVisibility(View.GONE); + } else { + _llDot.setVisibility(View.VISIBLE); + for (int i = 0; i < viewPager_size; i++) { + ImageView image = new ImageView(_context); + image.setTag(i); + // LinearLayout.LayoutParams params = new + // LinearLayout.LayoutParams( + // 20, 20); + LayoutParams params = new LayoutParams( + LayoutParams.WRAP_CONTENT, + LayoutParams.WRAP_CONTENT); + params.setMargins(5, + CommonUtil.getElementSzie(_context) / 2, 5, + CommonUtil.getElementSzie(_context) / 2); + image.setBackgroundResource(R.drawable.tt_default_emo_dots); + image.setEnabled(false); + _llDot.addView(image, params); + } + } + } + if (1 != viewPager_size) { + dots = new ImageView[viewPager_size]; + for (int i = 0; i < viewPager_size; i++) { + dots[i] = (ImageView) _llDot.getChildAt(i); + dots[i].setEnabled(true); + dots[i].setTag(i); + } + currentIndex = 0; + dots[currentIndex].setEnabled(false); + _viewPager + .setOnPageChangeListener(new ViewPager.OnPageChangeListener() { + + @Override + public void onPageSelected(int arg0) { + setCurDot(arg0); + } + + @Override + public void onPageScrolled(int arg0, float arg1, + int arg2) { + + } + + @Override + public void onPageScrollStateChanged(int arg0) { + } + }); + } + } + + private void setCurDot(int position) { + if (position < 0 || position > viewPager_size - 1 + || currentIndex == position) { + return; + } + dots[position].setEnabled(false); + dots[currentIndex].setEnabled(true); + currentIndex = position; + } + + public void setAdapter() { + if (onEmoGridViewItemClick == null) { + return; + } + list_Views = new ArrayList(); + for (int i = 0; i < viewPager_size; i++) { + list_Views.add(getViewPagerItem(i)); + } + _viewPager.setAdapter(new ViewPageAdapter(list_Views)); + + } + + /** 生成gridView数据 */ + private int[] getGridViewData(int index) { + ++index; + int startPos = (index - 1) * SysConstant.yayaPageSize; + int endPos = index * SysConstant.yayaPageSize - 1; + + if (endPos > Emoparser.getInstance(_context).getYayaResIdList().length) { + endPos = Emoparser.getInstance(_context).getYayaResIdList().length-1; + } + int[] tmps = new int[endPos - startPos + 1]; + + int num = 0; + for (int i = startPos; i <= endPos; i++) { + tmps[num] = Emoparser.getInstance(_context).getYayaResIdList()[i]; + num++; + } + return tmps; + } + + private GridView getViewPagerItem(final int index) { + GridView gridView = new GridView(_context); + gridView.setLayoutParams(new LayoutParams(LayoutParams.MATCH_PARENT, + LayoutParams.WRAP_CONTENT)); + gridView.setNumColumns(4); + gridView.setVerticalScrollBarEnabled(false); + gridView.setHorizontalScrollBarEnabled(false); + gridView.setPadding(8, 8, 8, 0); + gridView.setVerticalSpacing(20); + gridView.setSelector(new ColorDrawable(Color.TRANSPARENT)); + + gridView.setAdapter(new YayaEmoGridViewAdapter(_context, + getGridViewData(index))); + gridView.setOnItemClickListener(new OnItemClickListener() { + @Override + public void onItemClick(AdapterView parent, View view, + int position, long id) { + int start = index * SysConstant.yayaPageSize; + onEmoGridViewItemClick.onItemClick(position + start, index); + } + }); + return gridView; + } + + public void setOnEmoGridViewItemClick( + OnEmoGridViewItemClick onFaceGridViewItemClick) { + this.onEmoGridViewItemClick = onFaceGridViewItemClick; + } + + public interface OnEmoGridViewItemClick { + public void onItemClick(int facesPos, int viewIndex); + } +} diff --git a/android/app/src/main/java/com/mogujie/tt/ui/widget/ZoomableImageView.java b/android/app/src/main/java/com/mogujie/tt/ui/widget/ZoomableImageView.java new file mode 100644 index 000000000..460de7d5b --- /dev/null +++ b/android/app/src/main/java/com/mogujie/tt/ui/widget/ZoomableImageView.java @@ -0,0 +1,428 @@ +package com.mogujie.tt.ui.widget; + +import android.app.Dialog; +import android.content.Context; +import android.graphics.Matrix; +import android.graphics.PointF; +import android.util.AttributeSet; +import android.view.GestureDetector; +import android.view.LayoutInflater; +import android.view.MotionEvent; +import android.view.ScaleGestureDetector; +import android.view.View; +import android.widget.Button; +import android.widget.ImageView; +import android.widget.Toast; + +import com.mogujie.tt.R; +import com.mogujie.tt.ui.activity.DetailPortraitActivity; +import com.mogujie.tt.utils.Logger; + +/** + * Created by zhujian on 15/1/19. + */ +public class ZoomableImageView extends ImageView{ + + private static Logger logger = Logger.getLogger(ZoomableImageView.class); + private float maxScale = 3f; + private float minScale = 1f; + + private enum State { + INIT, DRAG, ZOOM + } + + private State state; + + private Matrix matrix; + private float[] finalTransformation = new float[9]; + private PointF last = new PointF(); + private float currentScale = 1f; + + private int viewWidth; + private int viewHeight; + private float afterScaleDrawableWidth; + private float afterScaleDrawableHeight; + private DetailPortraitActivity.finishActivity finishActivity; + + private ScaleGestureDetector scaleDetector; + + private GestureDetector doubleTapDetecture; + + public ZoomableImageView(Context context) { + super(context); + setUp(context); + } + + public ZoomableImageView(Context context, AttributeSet attrs) { + super(context, attrs); + setUp(context); + } + + public ZoomableImageView(Context context, AttributeSet attrs, int defStyle) { + super(context, attrs, defStyle); + setUp(context); + } + + public void setFinishActivity(DetailPortraitActivity.finishActivity finishInterface) + { + this.finishActivity = finishInterface; + } + + @Override + protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { + super.onMeasure(widthMeasureSpec, heightMeasureSpec); + viewWidth = MeasureSpec.getSize(widthMeasureSpec); + viewHeight = MeasureSpec.getSize(heightMeasureSpec); + + // Set up drawable at first load + if (hasDrawable()) { + resetImage(); + } + } + + + @Override + public boolean onTouchEvent(MotionEvent event) { + scaleDetector.onTouchEvent(event); + doubleTapDetecture.onTouchEvent(event); + + PointF current = new PointF(event.getX(), event.getY()); + + switch (event.getAction()) { + case MotionEvent.ACTION_DOWN: + last.set(current); + state = State.DRAG; + stopInterceptEvent(); + break; + + case MotionEvent.ACTION_MOVE: + if (state == State.DRAG) { + + //Edit by boris ����߽� + if (drag(current)) { + stopInterceptEvent(); + last.set(current); + } else { + startInterceptEvent(); + return false; + } + + } + break; + + case MotionEvent.ACTION_UP: + state = State.INIT; + startInterceptEvent(); + break; + + case MotionEvent.ACTION_POINTER_UP: + state = State.INIT; + break; + } + + setImageMatrix(matrix); + invalidate(); + return true; + } + + /** ���������Լ����� */ + private void stopInterceptEvent() { + getParent().requestDisallowInterceptTouchEvent(true); + } + + /** ����������view���� */ + private void startInterceptEvent() { + getParent().requestDisallowInterceptTouchEvent(false); + } + + /** + * Set up the class. Method called by constructors. + * + * @param context + */ + private void setUp(Context context) { + super.setClickable(false); + matrix = new Matrix(); + state = State.INIT; + scaleDetector = new ScaleGestureDetector(context, new ScaleListener()); + doubleTapDetecture = new GestureDetector(context, new GestureListener()); + setScaleType(ScaleType.MATRIX); + } + + public void resetImage() { + + // Scale Image + float scale = getScaleForDrawable(); + matrix.setScale(scale, scale); + + // Center Image + float marginY = ((float) viewHeight - (scale * getDrawable() + .getIntrinsicHeight())) / 2; + float marginX = ((float) viewWidth - (scale * getDrawable() + .getIntrinsicWidth())) / 2; + matrix.postTranslate(marginX, marginY); + + afterScaleDrawableWidth = (float) viewWidth - 2 * marginX; + afterScaleDrawableHeight = (float) viewHeight - 2 * marginY; + + setImageMatrix(matrix); + + + //Edit by boris + currentScale = 1f; + state = State.INIT; + } + + /** + * Getter and setter for max/min scale. Default are min=1 and max=3 + */ + + public float getMaxScale() { + return maxScale; + } + + public void setMaxScale(float maxScale) { + this.maxScale = maxScale; + } + + public float getMinScale() { + return minScale; + } + + public void setMinScale(float minScale) { + this.minScale = minScale; + } + + /** + * Drag method + * //Edit by boris,����϶����˱߽��򷵻�false + * + * @param current + * Current point to drag to. + */ + private boolean drag(PointF current) { + if (isXSide(current)) { + return false; + } + + float deltaX = getMoveDraggingDelta(current.x - last.x, viewWidth, + afterScaleDrawableWidth * currentScale); + float deltaY = getMoveDraggingDelta(current.y - last.y, viewHeight, + afterScaleDrawableHeight * currentScale); + + beforLimitDragX = deltaX; + + matrix.postTranslate(deltaX, deltaY); + + limitDrag(); + + return true; + } + + /** + * @param current + * @return + */ + private boolean isXSide(PointF current) { + Matrix retainMatrix = new Matrix(); + retainMatrix.set(matrix); + + float deltaX = getMoveDraggingDelta(current.x - last.x, viewWidth, + afterScaleDrawableWidth * currentScale); + float deltaY = getMoveDraggingDelta(current.y - last.y, viewHeight, + afterScaleDrawableHeight * currentScale); + retainMatrix.postTranslate(deltaX, deltaY); + + retainMatrix.getValues(finalTransformation); + float finalXTransformation = finalTransformation[Matrix.MTRANS_X]; + + float deltaX1 = getScaleDraggingDelta(finalXTransformation, viewWidth, + afterScaleDrawableWidth * currentScale); + + return deltaX + deltaX1 == 0; + } + + /** + * Scale method for zooming + * + * @param focusX + * X of center of scale + * @param focusY + * Y of center of scale + * @param scaleFactor + * scale factor to zoom in/out + */ + private void scale(float focusX, float focusY, float scaleFactor) { + float lastScale = currentScale; + float newScale = lastScale * scaleFactor; + + // Calculate next scale with resetting to max or min if required + if (newScale > maxScale) { + currentScale = maxScale; + scaleFactor = maxScale / lastScale; + } else if (newScale < minScale) { + currentScale = minScale; + scaleFactor = minScale / lastScale; + } else { + currentScale = newScale; + } + + // Do scale + if (requireCentering()) { + matrix.postScale(scaleFactor, scaleFactor, (float) viewWidth / 2, + (float) viewHeight / 2); + } else + matrix.postScale(scaleFactor, scaleFactor, focusX, focusY); + + limitDrag(); + } + + private float beforLimitDragX; + + /** + * This method permits to keep drag and zoom inside the drawable. It makes + * sure the drag is staying in bound. + */ + private void limitDrag() { + matrix.getValues(finalTransformation); + float finalXTransformation = finalTransformation[Matrix.MTRANS_X]; + float finalYTransformation = finalTransformation[Matrix.MTRANS_Y]; + + float deltaX = getScaleDraggingDelta(finalXTransformation, viewWidth, + afterScaleDrawableWidth * currentScale); + float deltaY = getScaleDraggingDelta(finalYTransformation, viewHeight, + afterScaleDrawableHeight * currentScale); + + // Edit bu shao + if (beforLimitDragX + deltaX == 0) { + startInterceptEvent(); + } else { + stopInterceptEvent(); + } + + matrix.postTranslate(deltaX, deltaY); + } + + private float getScaleDraggingDelta(float delta, float viewSize, + float contentSize) { + float minTrans = 0; + float maxTrans = 0; + + if (contentSize <= viewSize) { + maxTrans = viewSize - contentSize; + } else { + minTrans = viewSize - contentSize; + } + + if (delta < minTrans) + return minTrans - delta; + else if (delta > maxTrans) + return maxTrans - delta; + else + return 0; + } + + // Check if dragging is still possible if so return delta otherwise return 0 + // (do nothing) + private float getMoveDraggingDelta(float delta, float viewSize, + float contentSize) { + if (contentSize <= viewSize) { + return 0; + } + return delta; + } + + private float getScaleForDrawable() { + float scaleX = (float) viewWidth + / (float) getDrawable().getIntrinsicWidth(); + float scaleY = (float) viewHeight + / (float) getDrawable().getIntrinsicHeight(); + return Math.min(scaleX, scaleY); + } + + private boolean hasDrawable() { + return getDrawable() != null && getDrawable().getIntrinsicWidth() != 0 + && getDrawable().getIntrinsicHeight() != 0; + } + + private boolean requireCentering() { + return afterScaleDrawableWidth * currentScale <= (float) viewWidth + || afterScaleDrawableHeight * currentScale <= (float) viewHeight; + } + + private boolean isZoom() { + return currentScale != 1f; + } + + /** + * Listener for detecting scale. + * + * @author jmartinez + */ + private class ScaleListener extends + ScaleGestureDetector.SimpleOnScaleGestureListener { + @Override + public boolean onScaleBegin(ScaleGestureDetector detector) { + state = State.ZOOM; + return true; + } + + @Override + public boolean onScale(ScaleGestureDetector detector) { + scale(detector.getFocusX(), detector.getFocusY(), + detector.getScaleFactor()); + return true; + } + } + + /** + * Listener for double tap detection + * + * @author jmartinez + */ + private class GestureListener extends + GestureDetector.SimpleOnGestureListener { + + @Override + public boolean onDoubleTap(MotionEvent e) { + if (isZoom()) { + resetImage(); + } else { + scale(e.getX(), e.getY(), maxScale); + } + return true; + } + + @Override + public boolean onSingleTapConfirmed(MotionEvent e) { + if(finishActivity!=null) + { + finishActivity.finish(); + } + return true; + } + + @Override + public void onLongPress(MotionEvent e) { + final Dialog dialog = new Dialog(getContext() , R.style.phoneNumDialog); + setupDialogViews(dialog); + dialog.show(); + } + + public void setupDialogViews(final Dialog dialog){ + View dialogLyout = LayoutInflater.from(getContext()).inflate(R.layout.tt_dialog_call, null); + + Button callButton = (Button)dialogLyout.findViewById(R.id.call); + callButton.setText(getContext().getText(R.string.save_image)); + callButton.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View view) { + dialog.dismiss(); + Toast.makeText(getContext(), "图片已经保存到"+DetailPortraitActivity.imageUri.substring(8), Toast.LENGTH_LONG).show(); + } + }); + dialog.setContentView(dialogLyout); + } + } + +} diff --git a/android/app/src/main/java/com/mogujie/tt/ui/widget/message/AudioRenderView.java b/android/app/src/main/java/com/mogujie/tt/ui/widget/message/AudioRenderView.java new file mode 100644 index 000000000..32c525d2a --- /dev/null +++ b/android/app/src/main/java/com/mogujie/tt/ui/widget/message/AudioRenderView.java @@ -0,0 +1,237 @@ +package com.mogujie.tt.ui.widget.message; + +import android.content.Context; +import android.graphics.drawable.AnimationDrawable; +import android.util.AttributeSet; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.RelativeLayout; +import android.widget.TextView; +import android.widget.Toast; + +import com.mogujie.tt.DB.entity.MessageEntity; +import com.mogujie.tt.DB.entity.UserEntity; +import com.mogujie.tt.R; +import com.mogujie.tt.config.MessageConstant; +import com.mogujie.tt.ui.helper.AudioPlayerHandler; +import com.mogujie.tt.imservice.entity.AudioMessage; +import com.mogujie.tt.utils.CommonUtil; +import com.mogujie.tt.utils.ScreenUtil; + +import java.io.File; + +/** + * @author : yingmu on 15-1-9. + * @email : yingmu@mogujie.com. + */ +public class AudioRenderView extends BaseMsgRenderView { + + /**可点击的消息体*/ + private View messageLayout; + /** 播放动画的view*/ + private View audioAnttView; + /** 指示语音是否被播放*/ + private View audioUnreadNotify; + /** 语音时长*/ + private TextView audioDuration; + + /**对外暴露的监听器,点击*/ + private BtnImageListener btnImageListener; + public interface BtnImageListener{ + public void onClickUnread(); + public void onClickReaded(); + } + + public void setBtnImageListener(BtnImageListener btnImageListener){ + this.btnImageListener = btnImageListener; + } + + public AudioRenderView(Context context, AttributeSet attrs) { + super(context, attrs); + } + + public static AudioRenderView inflater(Context ctx,ViewGroup viewGroup,boolean isMine){ + + int resoure = isMine?R.layout.tt_mine_audio_message_item:R.layout.tt_other_audio_message_item; + //tt_other_audio_message_item + AudioRenderView audioRenderView = (AudioRenderView) LayoutInflater.from(ctx).inflate(resoure,viewGroup,false); + audioRenderView.setMine(isMine); + audioRenderView.setParentView(viewGroup); + return audioRenderView; + } + + @Override + protected void onFinishInflate() { + super.onFinishInflate(); + messageLayout= findViewById(R.id.message_layout); + audioAnttView = findViewById(R.id.audio_antt_view); + audioDuration = (TextView) findViewById(R.id.audio_duration); + audioUnreadNotify = findViewById(R.id.audio_unread_notify); + } + + + /** + * 控件赋值 + * 是不是采用callback的形式 + * + * @param messageEntity + * @param userEntity + */ + @Override + public void render(final MessageEntity messageEntity,final UserEntity userEntity,final Context ctx) { + super.render(messageEntity, userEntity,ctx); + final AudioMessage audioMessage = (AudioMessage)messageEntity; + + final String audioPath = audioMessage.getAudioPath(); + final int audioReadStatus = audioMessage.getReadStatus(); + + messageLayout.setOnClickListener(new OnClickListener() { + @Override + public void onClick(View v) { + // 上层回调事件 + if (!new File(audioPath).exists()) { + Toast.makeText(ctx, ctx.getResources().getString(R.string.notfound_audio_file), Toast.LENGTH_LONG).show(); + return; + } + switch (audioReadStatus){ + case MessageConstant.AUDIO_UNREAD: + if(btnImageListener != null){ + btnImageListener.onClickUnread(); + audioUnreadNotify.setVisibility(View.GONE); + } + break; + case MessageConstant.AUDIO_READED: + if(btnImageListener != null){ + btnImageListener.onClickReaded(); + } + break; + } + + + // 获取播放路径,播放语音 + String currentPlayPath = AudioPlayerHandler.getInstance().getCurrentPlayPath(); + if (currentPlayPath !=null && AudioPlayerHandler.getInstance().isPlaying()) { + AudioPlayerHandler.getInstance().stopPlayer(); + if (currentPlayPath.equals(audioPath)) { + // 关闭当前的 + return; + } + } + + final AnimationDrawable animationDrawable = (AnimationDrawable) audioAnttView.getBackground(); + AudioPlayerHandler.getInstance().setAudioListener(new AudioPlayerHandler.AudioListener() { + @Override + public void onStop() { + if(animationDrawable!=null && animationDrawable.isRunning()){ + animationDrawable.stop(); + animationDrawable.selectDrawable(0); + } + } + }); + + // 延迟播放 + Thread myThread = new Thread() { + public void run() { + try { + Thread.sleep(200); + AudioPlayerHandler.getInstance().startPlay(audioPath); + animationDrawable.start(); + } catch (Exception e) { + e.printStackTrace(); + } + } + }; + myThread.start(); + } + }); + + //针对path 的设定 + if (null != audioPath) { + int resource = isMine?R.anim.tt_voice_play_mine:R.anim.tt_voice_play_other; + audioAnttView.setBackgroundResource(resource); + AnimationDrawable animationDrawable = (AnimationDrawable) audioAnttView.getBackground(); + + if (null != AudioPlayerHandler.getInstance().getCurrentPlayPath() + && AudioPlayerHandler.getInstance().getCurrentPlayPath().equals(audioPath)) { + animationDrawable.start(); + } else { + if (animationDrawable.isRunning()) { + animationDrawable.stop(); + animationDrawable.selectDrawable(0); + } + } + + switch (audioReadStatus){ + case MessageConstant.AUDIO_READED: + audioAlreadyRead(); + break; + case MessageConstant.AUDIO_UNREAD: + audioUnread(); + break; + } + + int audioLength = audioMessage.getAudiolength(); + audioDuration.setText(String.valueOf(audioLength) + '"'); + // messageLayout 的长按事件绑定 在上层做掉,有时间了再迁移 + + //getAudioBkSize ,在看一下 + int width = CommonUtil.getAudioBkSize(audioLength, ctx); + if(width< ScreenUtil.instance(ctx).dip2px(45)) + { + width = ScreenUtil.instance(ctx).dip2px(45); + } + RelativeLayout.LayoutParams layoutParam = new RelativeLayout.LayoutParams(width, LayoutParams.WRAP_CONTENT); + messageLayout.setLayoutParams(layoutParam); + if (isMine) { + layoutParam.addRule(RelativeLayout.RIGHT_OF, R.id.audio_duration); + RelativeLayout.LayoutParams param = (android.widget.RelativeLayout.LayoutParams) audioDuration.getLayoutParams(); + param.addRule(RelativeLayout.RIGHT_OF, R.id.message_state_failed); + param.addRule(RelativeLayout.RIGHT_OF, R.id.progressBar1); + } + } + } + + // 是否开启播放动画 + public void startAnimation(){ + AnimationDrawable animationDrawable = (AnimationDrawable) audioAnttView.getBackground(); + animationDrawable.start(); + } + + + public void stopAnimation(){ + AnimationDrawable animationDrawable = (AnimationDrawable) audioAnttView.getBackground(); + if (animationDrawable.isRunning()) { + animationDrawable.stop(); + animationDrawable.selectDrawable(0); + } + } + + + // unread 与 alreadRead的区别是什么 + private void audioUnread(){ + if(isMine){ + audioUnreadNotify.setVisibility(View.GONE); + }else{ + audioUnreadNotify.setVisibility(View.VISIBLE); + } + } + + private void audioAlreadyRead(){ + audioUnreadNotify.setVisibility(View.GONE); + } + + + /**------------------------set/get--------------*/ + public View getMessageLayout() { + return messageLayout; + } + + public void setMine(boolean isMine) { + this.isMine = isMine; + } + + public void setParentView(ViewGroup parentView) { + this.parentView = parentView; + } +} diff --git a/android/app/src/main/java/com/mogujie/tt/ui/widget/message/BaseMsgRenderView.java b/android/app/src/main/java/com/mogujie/tt/ui/widget/message/BaseMsgRenderView.java new file mode 100644 index 000000000..500a5066f --- /dev/null +++ b/android/app/src/main/java/com/mogujie/tt/ui/widget/message/BaseMsgRenderView.java @@ -0,0 +1,152 @@ +package com.mogujie.tt.ui.widget.message; + +import android.content.Context; +import android.util.AttributeSet; +import android.view.View; +import android.view.ViewGroup; +import android.widget.ImageView; +import android.widget.ProgressBar; +import android.widget.RelativeLayout; +import android.widget.TextView; + +import com.mogujie.tt.DB.entity.MessageEntity; +import com.mogujie.tt.DB.entity.UserEntity; +import com.mogujie.tt.R; +import com.mogujie.tt.config.MessageConstant; +import com.mogujie.tt.config.SysConstant; +import com.mogujie.tt.utils.IMUIHelper; +import com.mogujie.tt.ui.widget.IMBaseImageView; + +/** + * @author : yingmu on 15-1-9. + * @email : yingmu@mogujie.com. + */ +public abstract class BaseMsgRenderView extends RelativeLayout{ + /** 头像*/ + protected IMBaseImageView portrait; + /** 消息状态*/ + protected ImageView messageFailed; + protected ProgressBar loadingProgressBar; + protected TextView name; + + /**渲染的消息实体*/ + protected MessageEntity messageEntity; + protected ViewGroup parentView; + protected boolean isMine; + + protected BaseMsgRenderView(Context context, AttributeSet attrs) { + super(context, attrs); + } + + // 渲染之后做的事情 子类会调用到这个地方嘛? + @Override + protected void onFinishInflate() { + super.onFinishInflate(); + portrait = (IMBaseImageView) findViewById(R.id.user_portrait); + messageFailed = (ImageView) findViewById(R.id.message_state_failed); + loadingProgressBar = (ProgressBar) findViewById(R.id.progressBar1); + name = (TextView) findViewById(R.id.name); + } + + + + // 消息失败绑定事件 三种不同的弹窗 + // image的load状态就是 sending状态的一个子状态 + public void msgSendinging(final MessageEntity messageEntity){ + messageFailed.setVisibility(View.GONE); + loadingProgressBar.setVisibility(View.VISIBLE); + } + + public void msgFailure(final MessageEntity messageEntity){ + messageFailed.setVisibility(View.VISIBLE); + loadingProgressBar.setVisibility(View.GONE); + } + + public void msgSuccess(final MessageEntity messageEntity){ + messageFailed.setVisibility(View.GONE); + loadingProgressBar.setVisibility(View.GONE); + } + + public void msgStatusError(final MessageEntity messageEntity){ + messageFailed.setVisibility(View.GONE); + loadingProgressBar.setVisibility(View.GONE); + } + + /**控件赋值*/ + public void render(final MessageEntity entity, UserEntity userEntity,final Context ctx){ + this.messageEntity = entity; + if(userEntity == null){ + // 没有找到对应的用户信息 todo + // 请求用户信息 设定默认头像、默认姓名、 + userEntity=new UserEntity(); + userEntity.setMainName("未知"); + userEntity.setRealName("未知"); + } + + String avatar = userEntity.getAvatar(); + int msgStatus = messageEntity.getStatus(); + + //头像设置 + portrait.setDefaultImageRes(R.drawable.tt_default_user_portrait_corner); + portrait.setCorner(5); + portrait.setAvatarAppend(SysConstant.AVATAR_APPEND_100); + portrait.setImageUrl(avatar); + // 设定姓名 应该消息都是有的 + if(!isMine){ + name.setText(userEntity.getMainName()); + name.setVisibility(View.VISIBLE); + } + + + /**头像的跳转事件暂时放在这里, todo 业务结合紧密,但是应该不会改了*/ + final int userId = userEntity.getPeerId(); + portrait.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + IMUIHelper.openUserProfileActivity(getContext(),userId); + } + }); + /**头像事件 end*/ + + // 设定三种信息的弹窗类型 + // 判定消息的状态 成功还是失败 todo 具体实现放在子类中 + switch (msgStatus){ + case MessageConstant.MSG_FAILURE: + msgFailure(messageEntity); + break; + case MessageConstant.MSG_SUCCESS: + msgSuccess(messageEntity); + break; + case MessageConstant.MSG_SENDING: + msgSendinging(messageEntity); + break; + default: + msgStatusError(messageEntity); + } + + // 如果消息还是处于loading 状态 + // 判断是否是image类型 image类型的才有 loading,其他的都GONE + // todo 上面这些由子类做 + // 消息总体的类型有两种 + // 展示类型有四种(图片、文字、语音、混排) + } + + /**-------------------------set/get--------------------------*/ + public ImageView getPortrait() { + return portrait; + } + + public ImageView getMessageFailed() { + return messageFailed; + } + + + public ProgressBar getLoadingProgressBar() { + return loadingProgressBar; + } + + public TextView getName() { + return name; + } + +} diff --git a/android/app/src/main/java/com/mogujie/tt/ui/widget/message/EmojiRenderView.java b/android/app/src/main/java/com/mogujie/tt/ui/widget/message/EmojiRenderView.java new file mode 100644 index 000000000..a318d877b --- /dev/null +++ b/android/app/src/main/java/com/mogujie/tt/ui/widget/message/EmojiRenderView.java @@ -0,0 +1,109 @@ +package com.mogujie.tt.ui.widget.message; + +import android.content.Context; +import android.graphics.Bitmap; +import android.util.AttributeSet; +import android.view.LayoutInflater; +import android.view.ViewGroup; +import android.widget.ImageView; + +import com.mogujie.tt.DB.entity.MessageEntity; +import com.mogujie.tt.DB.entity.UserEntity; +import com.mogujie.tt.R; +import com.mogujie.tt.imservice.entity.TextMessage; +import com.mogujie.tt.ui.helper.Emoparser; +import com.mogujie.tt.ui.widget.GifView; + +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.nio.ByteBuffer; + +/** + * @author : fengzi on 15-1-25. + * @email : fengzi@mogujie.com. + * + * 虽然gif与text在服务端是同一种消息类型,但是在客户端应该区分开来 + */ +public class EmojiRenderView extends BaseMsgRenderView { + private GifView messageContent; + + public static EmojiRenderView inflater(Context context,ViewGroup viewGroup,boolean isMine){ + int resource = isMine?R.layout.tt_mine_emoji_message_item :R.layout.tt_other_emoji_message_item; + EmojiRenderView gifRenderView = (EmojiRenderView) LayoutInflater.from(context).inflate(resource, viewGroup, false); + gifRenderView.setMine(isMine); + gifRenderView.setParentView(viewGroup); + return gifRenderView; + } + + public EmojiRenderView(Context context, AttributeSet attrs) { + super(context, attrs); + } + + protected void onFinishInflate() { + super.onFinishInflate(); + messageContent = (GifView) findViewById(R.id.message_content); + } + + /** + * 控件赋值 + * @param messageEntity + * @param userEntity + */ + @Override + public void render(MessageEntity messageEntity, UserEntity userEntity,Context context) { + super.render(messageEntity, userEntity,context); + TextMessage textMessage = (TextMessage) messageEntity; + String content = textMessage.getContent(); + + InputStream is = getResources().openRawResource(Emoparser.getInstance(getContext()).getResIdByCharSequence(content)); + int lenght = 0; + try { + lenght = is.available(); + byte[] buffer = ByteBuffer.allocate(lenght).array(); + is.read(buffer); + messageContent.setBytes(buffer); + messageContent.startAnimation(); + } catch (IOException e) { + e.printStackTrace(); + } + } + + @Override + public void msgFailure(MessageEntity messageEntity) { + super.msgFailure(messageEntity); + } + + + /**----------------set/get---------------------------------*/ + public ImageView getMessageContent() { + return messageContent; + } + + public void setMessageContent(GifView messageContent) { + this.messageContent = messageContent; + } + + public boolean isMine() { + return isMine; + } + + public void setMine(boolean isMine) { + this.isMine = isMine; + } + + public ViewGroup getParentView() { + return parentView; + } + + public void setParentView(ViewGroup parentView) { + this.parentView = parentView; + } + + private byte[] Bitmap2Bytes(Bitmap bm){ + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + bm.compress(Bitmap.CompressFormat.PNG, 100, baos); + return baos.toByteArray(); + } +} + diff --git a/android/app/src/main/java/com/mogujie/tt/ui/widget/message/GifImageRenderView.java b/android/app/src/main/java/com/mogujie/tt/ui/widget/message/GifImageRenderView.java new file mode 100644 index 000000000..e1d87515b --- /dev/null +++ b/android/app/src/main/java/com/mogujie/tt/ui/widget/message/GifImageRenderView.java @@ -0,0 +1,82 @@ +package com.mogujie.tt.ui.widget.message; + +import android.content.Context; +import android.util.AttributeSet; +import android.view.LayoutInflater; +import android.view.ViewGroup; +import android.widget.FrameLayout; + +import com.mogujie.tt.DB.entity.MessageEntity; +import com.mogujie.tt.DB.entity.UserEntity; +import com.mogujie.tt.R; +import com.mogujie.tt.imservice.entity.ImageMessage; +import com.mogujie.tt.ui.widget.GifLoadTask; +import com.mogujie.tt.ui.widget.GifView; + +/** + * Created by zhujian on 15/3/26. + */ +public class GifImageRenderView extends BaseMsgRenderView { + private GifView messageContent; + + public GifView getMessageContent() + { + return messageContent; + } + public static GifImageRenderView inflater(Context context,ViewGroup viewGroup,boolean isMine){ + int resource = isMine? R.layout.tt_mine_gifimage_message_item :R.layout.tt_other_gifimage_message_item; + GifImageRenderView gifRenderView = (GifImageRenderView) LayoutInflater.from(context).inflate(resource, viewGroup, false); + gifRenderView.setMine(isMine); + return gifRenderView; + } + + public GifImageRenderView(Context context, AttributeSet attrs) { + super(context, attrs); + } + + protected void onFinishInflate() { + super.onFinishInflate(); + messageContent = (GifView) findViewById(R.id.message_image); + } + + /** + * 控件赋值 + * @param messageEntity + * @param userEntity + */ + @Override + public void render(MessageEntity messageEntity, UserEntity userEntity,Context context) { + super.render(messageEntity, userEntity,context); + ImageMessage imageMessage = (ImageMessage) messageEntity; + String url = imageMessage.getUrl(); + new GifLoadTask() { + @Override + protected void onPostExecute(byte[] bytes) { + messageContent.setBytes(bytes); + messageContent.startAnimation(); + } + @Override + protected void onPreExecute() { + super.onPreExecute(); + } + }.execute(url); + } + + @Override + public void msgFailure(MessageEntity messageEntity) { + super.msgFailure(messageEntity); + } + + /**----------------set/get---------------------------------*/ + + public void setMine(boolean isMine) { + this.isMine = isMine; + } + + + public void setParentView(ViewGroup parentView) { + this.parentView = parentView; + } + + +} diff --git a/android/app/src/main/java/com/mogujie/tt/ui/widget/message/ImageRenderView.java b/android/app/src/main/java/com/mogujie/tt/ui/widget/message/ImageRenderView.java new file mode 100644 index 000000000..e1edc2476 --- /dev/null +++ b/android/app/src/main/java/com/mogujie/tt/ui/widget/message/ImageRenderView.java @@ -0,0 +1,371 @@ +package com.mogujie.tt.ui.widget.message; + +import android.content.Context; +import android.graphics.Bitmap; +import android.text.TextUtils; +import android.util.AttributeSet; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.ImageView; + +import com.mogujie.tt.DB.entity.MessageEntity; +import com.mogujie.tt.DB.entity.UserEntity; +import com.mogujie.tt.R; +import com.mogujie.tt.config.MessageConstant; +import com.mogujie.tt.imservice.entity.ImageMessage; +import com.mogujie.tt.ui.widget.BubbleImageView; +import com.mogujie.tt.ui.widget.MGProgressbar; +import com.mogujie.tt.utils.FileUtil; +import com.mogujie.tt.utils.Logger; + +/** + * @author : yingmu on 15-1-9. + * @email : yingmu@mogujie.com. + * + */ +public class ImageRenderView extends BaseMsgRenderView { + private Logger logger = Logger.getLogger(ImageRenderView.class); + + // 上层必须实现的接口 + private ImageLoadListener imageLoadListener; + private BtnImageListener btnImageListener; + + /** 可点击的view*/ + private View messageLayout; + /**图片消息体*/ + private BubbleImageView messageImage; + /** 图片状态指示*/ + private MGProgressbar imageProgress; + + public ImageRenderView(Context context, AttributeSet attrs) { + super(context, attrs); + } + + public static ImageRenderView inflater(Context context,ViewGroup viewGroup,boolean isMine){ + int resource = isMine?R.layout.tt_mine_image_message_item:R.layout.tt_other_image_message_item; + ImageRenderView imageRenderView = (ImageRenderView) LayoutInflater.from(context).inflate(resource, viewGroup, false); + imageRenderView.setMine(isMine); + imageRenderView.setParentView(viewGroup); + return imageRenderView; + } + + @Override + protected void onFinishInflate() { + super.onFinishInflate(); + messageLayout = findViewById(R.id.message_layout); + messageImage = (BubbleImageView) findViewById(R.id.message_image); + imageProgress = (MGProgressbar) findViewById(R.id.tt_image_progress); + imageProgress.setShowText(false); + } + + /** + * + * */ + + /** + * 控件赋值 + * @param messageEntity + * @param userEntity + * + * 对于mine。 图片send_success 就是成功了直接取地址 + * 对于sending 就是正在上传 + * + * 对于other,消息一定是success,接受成功额 + * 2. 然后分析loadStatus 判断消息的展示状态 + */ + @Override + public void render(final MessageEntity messageEntity,final UserEntity userEntity,Context ctx) { + super.render(messageEntity, userEntity,ctx); + } + + + + /** + * 多端同步也不会拉到本地失败的数据 + * 只有isMine才有的状态,消息发送失败 + * 1. 图片上传失败。点击图片重新上传??[也是重新发送] + * 2. 图片上传成功,但是发送失败。 点击重新发送?? + * 3. 比较悲剧的是 图片上传失败和消息发送失败都是这个状态 不过可以通过另外一个状态来区别 图片load状态 + * @param entity + */ + @Override + public void msgFailure(final MessageEntity entity) { + super.msgFailure(entity); + messageImage.setOnClickListener(new OnClickListener(){ + @Override + public void onClick(View v) { + /**判断状态,重新发送resend*/ + btnImageListener.onMsgFailure(); + } + }); + if(FileUtil.isFileExist(((ImageMessage)entity).getPath())) + { + messageImage.setImageUrl("file://"+((ImageMessage)entity).getPath()); + } + else{ + messageImage.setImageUrl(((ImageMessage)entity).getUrl()); + } + imageProgress.hideProgress(); + } + + + @Override + public void msgStatusError(final MessageEntity entity) { + super.msgStatusError(entity); + imageProgress.hideProgress(); + } + + + /** + * 图片信息正在发送的过程中 + * 1. 上传图片 + * 2. 发送信息 + */ + @Override + public void msgSendinging(final MessageEntity entity) { + if(isMine()) + { + if(FileUtil.isFileExist(((ImageMessage)entity).getPath())) + { + + messageImage.setImageLoaddingCallback(new BubbleImageView.ImageLoaddingCallback() { + @Override + public void onLoadingComplete(String imageUri, View view, Bitmap loadedImage) { +// imageProgress.hideProgress(); + } + + @Override + public void onLoadingStarted(String imageUri, View view) { + imageProgress.showProgress(); + } + + @Override + public void onLoadingCanceled(String imageUri, View view) { + + } + + @Override + public void onLoadingFailed(String imageUri, View view) { + imageProgress.hideProgress(); + } + }); + messageImage.setImageUrl("file://"+((ImageMessage)entity).getPath()); + } + else + { + //todo 文件不存在 + } + } + + } + + + /** + * 消息成功 + * 1. 对方图片消息 + * 2. 自己多端同步的消息 + * 说明imageUrl不会为空的 + */ + @Override + public void msgSuccess(final MessageEntity entity) { + super.msgSuccess(entity); + ImageMessage imageMessage = (ImageMessage)entity; + final String imagePath = imageMessage.getPath(); + final String url = imageMessage.getUrl(); + int loadStatus = imageMessage.getLoadStatus(); + if(TextUtils.isEmpty(url)){ + /**消息状态异常*/ + msgStatusError(entity); + return; + } + + switch (loadStatus) { + case MessageConstant.IMAGE_UNLOAD:{ + messageImage.setImageLoaddingCallback(new BubbleImageView.ImageLoaddingCallback() { + @Override + public void onLoadingComplete(String imageUri, View view, Bitmap bitmap) { + if(imageLoadListener!=null) + { + imageLoadListener.onLoadComplete(imageUri); + } + getImageProgress().hideProgress(); + } + + @Override + public void onLoadingStarted(String imageUri, View view) { + getImageProgress().showProgress(); + } + + @Override + public void onLoadingCanceled(String imageUri, View view) { + getImageProgress().hideProgress(); + } + + @Override + public void onLoadingFailed(String imageUri, View view) { + getImageProgress().hideProgress(); + imageLoadListener.onLoadFailed(); + } + }); + + if(isMine()) + { + if(FileUtil.isFileExist(imagePath)) + { + messageImage.setImageUrl("file://"+imagePath); + } + else + { + messageImage.setImageUrl(url); + } + } + else { + messageImage.setImageUrl(url); + } + }break; + + case MessageConstant.IMAGE_LOADING:{ + + }break; + + case MessageConstant.IMAGE_LOADED_SUCCESS:{ + messageImage.setImageLoaddingCallback(new BubbleImageView.ImageLoaddingCallback() { + @Override + public void onLoadingComplete(String imageUri, View view, Bitmap loadedImage) { + imageProgress.hideProgress(); + } + + @Override + public void onLoadingStarted(String imageUri, View view) { + imageProgress.showProgress(); + } + + @Override + public void onLoadingCanceled(String imageUri, View view) { + + } + + @Override + public void onLoadingFailed(String imageUri, View view) { + imageProgress.showProgress(); + } + }); + + if(isMine()) + { + if(FileUtil.isFileExist(imagePath)) + { + messageImage.setImageUrl("file://"+imagePath); + } + else + { + messageImage.setImageUrl(url); + } + } + else { + messageImage.setImageUrl(url); + } + messageImage.setOnClickListener(new OnClickListener() { + @Override + public void onClick(View view) { + if(btnImageListener!=null) + { + btnImageListener.onMsgSuccess(); + } + } + }); + + }break; + + //todo 图像失败了,允许点击之后重新下载 + case MessageConstant.IMAGE_LOADED_FAILURE:{ +// msgStatusError(imageMessage); +// getImageProgress().hideProgress(); + messageImage.setImageLoaddingCallback(new BubbleImageView.ImageLoaddingCallback() { + @Override + public void onLoadingComplete(String imageUri, View view, Bitmap loadedImage) { + getImageProgress().hideProgress(); + imageLoadListener.onLoadComplete(imageUri); + } + + @Override + public void onLoadingStarted(String imageUri, View view) { + getImageProgress().showProgress(); + } + + @Override + public void onLoadingCanceled(String imageUri, View view) { + + } + + @Override + public void onLoadingFailed(String imageUri, View view) { + } + }); + messageImage.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View view) { + messageImage.setImageUrl(url); + } + }); + }break; + + } + } + + /**---------------------图片下载相关、点击、以及事件回调start-----------------------------------*/ + public interface BtnImageListener{ + public void onMsgSuccess(); + public void onMsgFailure(); + } + + public void setBtnImageListener(BtnImageListener btnImageListener){ + this.btnImageListener = btnImageListener; + } + + + public interface ImageLoadListener{ + public void onLoadComplete(String path); + // 应该把exception 返回结构放进去 + public void onLoadFailed(); + + } + + public void setImageLoadListener(ImageLoadListener imageLoadListener){ + this.imageLoadListener = imageLoadListener; + } + + /**---------------------图片下载相关、以及事件回调 end-----------------------------------*/ + + + /**----------------------set/get------------------------------------*/ + public View getMessageLayout() { + return messageLayout; + } + + public ImageView getMessageImage() { + return messageImage; + } + + public MGProgressbar getImageProgress() { + return imageProgress; + } + + public boolean isMine() { + return isMine; + } + + public void setMine(boolean isMine) { + this.isMine = isMine; + } + + public ViewGroup getParentView() { + return parentView; + } + + public void setParentView(ViewGroup parentView) { + this.parentView = parentView; + } + +} diff --git a/android/app/src/main/java/com/mogujie/tt/ui/widget/message/MessageOperatePopup.java b/android/app/src/main/java/com/mogujie/tt/ui/widget/message/MessageOperatePopup.java new file mode 100644 index 000000000..c01d0262f --- /dev/null +++ b/android/app/src/main/java/com/mogujie/tt/ui/widget/message/MessageOperatePopup.java @@ -0,0 +1,410 @@ + +package com.mogujie.tt.ui.widget.message; + +import android.annotation.SuppressLint; +import android.content.Context; +import android.content.res.Resources; +import android.graphics.drawable.BitmapDrawable; +import android.graphics.drawable.Drawable; +import android.media.AudioManager; +import android.view.Gravity; +import android.view.LayoutInflater; +import android.view.MotionEvent; +import android.view.View; +import android.widget.PopupWindow; +import android.widget.TextView; + +import com.mogujie.tt.config.DBConstant; +import com.mogujie.tt.R; +import com.mogujie.tt.ui.helper.AudioPlayerHandler; + +/** + * A popup window that can be used to display an arbitrary view + * OnItemClickListener + */ +public class MessageOperatePopup implements View.OnClickListener, View.OnTouchListener { + + private PopupWindow mPopup; + private static MessageOperatePopup messageOperatePopup; + private OnItemClickListener mListener; + + private int mWidth; + private int mHeight; + + private int mParentTop; + private TextView copyBtn, resendBtn, speakerBtn; + private boolean bcopyShow, bresendShow, bspeakerShow; + + private Context context = null; + + public static MessageOperatePopup instance(Context ctx,View parent){ + if(null == messageOperatePopup ){ + synchronized (MessageOperatePopup.class){ + messageOperatePopup = new MessageOperatePopup(ctx,parent); + } + } + return messageOperatePopup; + } + + public void hidePopup() { + if (messageOperatePopup != null) { + messageOperatePopup.dismiss(); + } + } + + + @SuppressWarnings("deprecation") + private MessageOperatePopup(Context ctx, View parent) { + View view = LayoutInflater.from(ctx).inflate(R.layout.tt_popup_list, + null); + this.context = ctx; + + // popView = (LinearLayout) view.findViewById(R.id.popup_list); + + copyBtn = (TextView) view.findViewById(R.id.copy_btn); + copyBtn.setOnClickListener(this); + copyBtn.setOnTouchListener(this); + copyBtn.setPadding(0, 13, 0, 8); + + resendBtn = (TextView) view.findViewById(R.id.resend_btn); + resendBtn.setOnClickListener(this); + resendBtn.setOnTouchListener(this); + resendBtn.setPadding(0, 13, 0, 8); + + speakerBtn = (TextView) view.findViewById(R.id.speaker_btn); + speakerBtn.setOnClickListener(this); + speakerBtn.setOnTouchListener(this); + speakerBtn.setPadding(0, 13, 0, 8); + + mWidth = (int) context.getResources().getDimension( + R.dimen.message_item_popup_width_single_short); + mHeight = (int) context.getResources().getDimension( + R.dimen.message_item_popup_height); + + int[] location = new int[2]; + parent.getLocationOnScreen(location); + mParentTop = location[1]; + mPopup = new PopupWindow(view, mWidth, mHeight); + // mPopup.setFocusable(true); + // 设置允许在外点击消失 + mPopup.setOutsideTouchable(true); + // 这个是为了点击“返回Back”也能使其消失,并且并不会影响你的背景 + mPopup.setBackgroundDrawable(new BitmapDrawable()); + } + + public void setOnItemClickListener(OnItemClickListener l) { + mListener = l; + } + + @SuppressWarnings("deprecation") + @SuppressLint("NewApi") + public void show(View item, int type, boolean bResend, boolean bSelf) { + if (mPopup == null || mPopup.isShowing()) { + return; + } + + boolean showTop = true; + + int[] location = new int[2]; + item.getLocationOnScreen(location); + // 默认在item上面弹出 + if (location[1] - mParentTop/* - mHeight */<= 0) { + // showTop = false; + } + else { + // 如果不是在最顶部,显示的距离要上移10 + location[1] = location[1] - 10; + } + + //下面全用回调 todo + + // 语音类型 + if (type == DBConstant.SHOW_AUDIO_TYPE) { + speakerBtn.setVisibility(View.VISIBLE); + if (AudioPlayerHandler.getInstance().getAudioMode(context) == AudioManager.MODE_NORMAL) { + speakerBtn.setText(R.string.call_mode); + } else { + speakerBtn.setText(R.string.speaker_mode); + } + bspeakerShow = true; + } else { + speakerBtn.setVisibility(View.GONE); + bspeakerShow = false; + } + + // 自己消息重发 + // 自己的消息 + // 非自己的消息 + // 图片语音 + // 文本 + if (bResend && bSelf) { + resendBtn.setVisibility(View.VISIBLE); + bresendShow = true; + if (type == DBConstant.SHOW_ORIGIN_TEXT_TYPE) { + copyBtn.setVisibility(View.VISIBLE); + bcopyShow = true; + } else { + copyBtn.setVisibility(View.GONE); + bcopyShow = false; + } + } else if (!bResend && bSelf) { + resendBtn.setVisibility(View.GONE); + bresendShow = false; + if (type != DBConstant.SHOW_IMAGE_TYPE && type != DBConstant.SHOW_AUDIO_TYPE && type != DBConstant.SHOW_GIF_TYPE) { + copyBtn.setVisibility(View.VISIBLE); + bcopyShow = true; + } else { + copyBtn.setVisibility(View.GONE); + bcopyShow = false; + } + } else { + if (type != DBConstant.SHOW_IMAGE_TYPE && type != DBConstant.SHOW_AUDIO_TYPE && type != DBConstant.SHOW_GIF_TYPE) { + copyBtn.setVisibility(View.VISIBLE); + bcopyShow = true; + }else { + copyBtn.setVisibility(View.GONE); + bcopyShow = false; + } + } + Resources resource = context.getResources(); + if (bcopyShow && bresendShow) { + // int nWidth = (int) resource + // .getDimension(R.dimen.message_item_popup_width_double_short); + mWidth = (int) resource + .getDimension(R.dimen.message_item_popup_width_double_short); + mPopup.setWidth(mWidth); + Drawable bgLeft = resource + .getDrawable(R.drawable.tt_bg_popup_left_nomal); + copyBtn.setBackgroundDrawable(bgLeft); + copyBtn.setPadding(0, 13, 0, 8); + Drawable bgRight = resource + .getDrawable(R.drawable.tt_bg_popup_right_nomal); + resendBtn.setBackgroundDrawable(bgRight); + resendBtn.setPadding(0, 13, 0, 8); + } else if (bcopyShow || bresendShow) { + if (bspeakerShow) { + // int nWidth = (int) resource + // .getDimension(R.dimen.message_item_popup_width_double_long); + mWidth = (int) resource + .getDimension(R.dimen.message_item_popup_width_double_long); + mPopup.setWidth(mWidth); + Drawable bgLeft = resource + .getDrawable(R.drawable.tt_bg_popup_left_nomal); + speakerBtn.setBackgroundDrawable(bgLeft); + Drawable bgRight = resource + .getDrawable(R.drawable.tt_bg_popup_right_nomal); + speakerBtn.setPadding(0, 13, 0, 8); + resendBtn.setBackgroundDrawable(bgRight); + resendBtn.setPadding(0, 13, 0, 8); + } else { + // int nWidth = (int) resource + // .getDimension(R.dimen.message_item_popup_width_single_short); + mWidth = (int) resource + .getDimension(R.dimen.message_item_popup_width_single_short); + mPopup.setWidth(mWidth); + Drawable bgNormal = resource + .getDrawable(R.drawable.tt_bg_popup_normal); + copyBtn.setBackgroundDrawable(bgNormal); + resendBtn.setBackgroundDrawable(bgNormal); + copyBtn.setPadding(0, 13, 0, 8); + resendBtn.setPadding(0, 13, 0, 8); + } + } else if (bspeakerShow) { + // int nWidth = (int) resource + // .getDimension(R.dimen.message_item_popup_width_single_long); + mWidth = (int) resource + .getDimension(R.dimen.message_item_popup_width_single_long); + mPopup.setWidth(mWidth); + Drawable bgNormal = resource + .getDrawable(R.drawable.tt_bg_popup_normal); + speakerBtn.setBackgroundDrawable(bgNormal); + speakerBtn.setPadding(0, 13, 0, 8); + } else { + return; + } + if (showTop) { + if (location[1] - mParentTop/* - mHeight */> 0) { + mPopup.showAtLocation(item, Gravity.NO_GRAVITY, location[0] + + (item.getWidth() / 2 - mWidth / 2), location[1] + - mHeight); + } else { + mPopup.showAtLocation(item, Gravity.NO_GRAVITY, location[0] + + (item.getWidth() / 2 - mWidth / 2), 0 + mHeight / 2); + } + } else { + // TODO: 在下面弹出的时候需要翻转背景 + mPopup.showAtLocation(item, Gravity.NO_GRAVITY, + location[0] + (item.getWidth() / 2 - mWidth / 2), + location[1] + item.getHeight()); + } + } + + public void dismiss() { + if (mPopup == null || !mPopup.isShowing()) { + return; + } + + mPopup.dismiss(); + } + + public interface OnItemClickListener { + void onCopyClick(); + + void onResendClick(); + + void onSpeakerClick(); + } + + @Override + public void onClick(View v) { + final int id = v.getId(); + + if (R.id.copy_btn == id) { + dismiss(); + if (mListener != null) { + mListener.onCopyClick(); + } + } else if (R.id.resend_btn == id) { + dismiss(); + if (mListener != null) { + mListener.onResendClick(); + } + } else if (R.id.speaker_btn == id) { + dismiss(); + if (mListener != null) { + mListener.onSpeakerClick(); + } + } + } + + @SuppressWarnings("deprecation") + @SuppressLint("NewApi") + @Override + public boolean onTouch(View v, MotionEvent event) { + // TODO Auto-generated method stub + Resources resource = context.getResources(); + if (event.getAction() == MotionEvent.ACTION_UP) { + if (R.id.copy_btn == v.getId()) { + Drawable drawable = null; + if (bcopyShow && bresendShow) { + drawable = resource + .getDrawable(R.drawable.tt_bg_popup_left_nomal); + } else if (bcopyShow || bresendShow) { + drawable = resource + .getDrawable(R.drawable.tt_bg_popup_normal); + } + if (drawable != null) { + copyBtn.setBackgroundDrawable(drawable); + copyBtn.setPadding(0, 13, 0, 8); + } + } else if (R.id.resend_btn == v.getId()) { + Drawable drawable = null; + if (bcopyShow && bresendShow) { + drawable = resource + .getDrawable(R.drawable.tt_bg_popup_right_nomal); + } else if (bcopyShow || bresendShow) { + if (bspeakerShow) { + drawable = resource + .getDrawable(R.drawable.tt_bg_popup_right_nomal); + } else { + drawable = resource + .getDrawable(R.drawable.tt_bg_popup_normal); + } + } + if (drawable != null) { + resendBtn.setBackgroundDrawable(drawable); + resendBtn.setPadding(0, 13, 0, 8); + } + } else if (R.id.speaker_btn == v.getId()) { + Drawable drawable = null; + if (bresendShow) { + drawable = resource + .getDrawable(R.drawable.tt_bg_popup_left_nomal); + } else if (bspeakerShow) { + drawable = resource + .getDrawable(R.drawable.tt_bg_popup_normal); + } + if (drawable != null) { + speakerBtn.setBackgroundDrawable(drawable); + speakerBtn.setPadding(0, 13, 0, 8); + } + } + } else { + if (R.id.copy_btn == v.getId()) { + Drawable drawableResend = null; + Drawable drawableCopy = null; + if (bcopyShow && bresendShow) { + drawableCopy = resource + .getDrawable(R.drawable.tt_bg_popup_left_pressed); + drawableResend = resource + .getDrawable(R.drawable.tt_bg_popup_right_nomal); + } else if (bcopyShow || bresendShow) { + drawableCopy = resource + .getDrawable(R.drawable.tt_bg_popup_pressed); + } + if (drawableCopy != null) { + copyBtn.setBackgroundDrawable(drawableCopy); + copyBtn.setPadding(0, 13, 0, 8); + } + if (drawableResend != null) { + resendBtn.setBackgroundDrawable(drawableResend); + resendBtn.setPadding(0, 13, 0, 8); + } + } else if (R.id.resend_btn == v.getId()) { + Drawable drawableCopy = null; + Drawable drawableResend = null; + Drawable drawableSpeaker = null; + if (bcopyShow && bresendShow) { + drawableCopy = resource + .getDrawable(R.drawable.tt_bg_popup_left_nomal); + drawableResend = resource + .getDrawable(R.drawable.tt_bg_popup_right_pressed); + } else if (bcopyShow || bresendShow) { + if (bspeakerShow) { + drawableSpeaker = resource + .getDrawable(R.drawable.tt_bg_popup_left_nomal); + drawableResend = resource + .getDrawable(R.drawable.tt_bg_popup_right_pressed); + } else { + drawableResend = resource + .getDrawable(R.drawable.tt_bg_popup_pressed); + } + } + if (drawableResend != null) { + resendBtn.setBackgroundDrawable(drawableResend); + resendBtn.setPadding(0, 13, 0, 8); + } + if (drawableCopy != null) { + copyBtn.setBackgroundDrawable(drawableCopy); + copyBtn.setPadding(0, 13, 0, 8); + } + if (drawableSpeaker != null) { + speakerBtn.setBackgroundDrawable(drawableSpeaker); + speakerBtn.setPadding(0, 13, 0, 8); + } + } else if (R.id.speaker_btn == v.getId()) { + // Drawable drawableCopy = null; + Drawable drawableResend = null; + Drawable drawableSpeaker = null; + if (bresendShow && bspeakerShow) { + drawableSpeaker = resource + .getDrawable(R.drawable.tt_bg_popup_left_pressed); + drawableResend = resource + .getDrawable(R.drawable.tt_bg_popup_right_nomal); + } else if (bspeakerShow) { + drawableSpeaker = resource + .getDrawable(R.drawable.tt_bg_popup_pressed); + } + if (drawableResend != null) { + resendBtn.setBackgroundDrawable(drawableResend); + resendBtn.setPadding(0, 13, 0, 8); + } + if (drawableSpeaker != null) { + speakerBtn.setBackgroundDrawable(drawableSpeaker); + speakerBtn.setPadding(0, 13, 0, 8); + } + } + } + return false; + } +} diff --git a/android/app/src/main/java/com/mogujie/tt/ui/widget/message/RenderType.java b/android/app/src/main/java/com/mogujie/tt/ui/widget/message/RenderType.java new file mode 100644 index 000000000..936b4b7fe --- /dev/null +++ b/android/app/src/main/java/com/mogujie/tt/ui/widget/message/RenderType.java @@ -0,0 +1,20 @@ +package com.mogujie.tt.ui.widget.message; + +/** + * @author : yingmu on 15-1-8. + * @email : yingmu@mogujie.com. + */ +public enum RenderType { + MESSAGE_TYPE_INVALID, + MESSAGE_TYPE_MINE_TETX , + MESSAGE_TYPE_MINE_GIF , + MESSAGE_TYPE_MINE_IMAGE, + MESSAGE_TYPE_MINE_GIF_IMAGE, + MESSAGE_TYPE_MINE_AUDIO, + MESSAGE_TYPE_OTHER_TEXT, + MESSAGE_TYPE_OTHER_GIF, + MESSAGE_TYPE_OTHER_IMAGE, + MESSAGE_TYPE_OTHER_GIF_IMAGE, + MESSAGE_TYPE_OTHER_AUDIO, + MESSAGE_TYPE_TIME_TITLE +} diff --git a/android/app/src/main/java/com/mogujie/tt/ui/widget/message/TextRenderView.java b/android/app/src/main/java/com/mogujie/tt/ui/widget/message/TextRenderView.java new file mode 100644 index 000000000..603825ea3 --- /dev/null +++ b/android/app/src/main/java/com/mogujie/tt/ui/widget/message/TextRenderView.java @@ -0,0 +1,100 @@ +package com.mogujie.tt.ui.widget.message; + +import android.content.Context; +import android.text.util.Linkify; +import android.util.AttributeSet; +import android.view.LayoutInflater; +import android.view.ViewGroup; +import android.widget.TextView; + +import com.mogujie.tt.DB.entity.MessageEntity; +import com.mogujie.tt.DB.entity.UserEntity; +import com.mogujie.tt.R; +import com.mogujie.tt.imservice.entity.TextMessage; +import com.mogujie.tt.ui.helper.Emoparser; + +/** + * @author : yingmu on 15-1-9. + * @email : yingmu@mogujie.com. + * + * 样式根据mine 与other不同可以分成两个 + */ +public class TextRenderView extends BaseMsgRenderView { + /** 文字消息体 */ + private TextView messageContent; + + public static TextRenderView inflater(Context context,ViewGroup viewGroup,boolean isMine){ + int resource = isMine?R.layout.tt_mine_text_message_item:R.layout.tt_other_text_message_item; + + TextRenderView textRenderView = (TextRenderView) LayoutInflater.from(context).inflate(resource, viewGroup, false); + textRenderView.setMine(isMine); + textRenderView.setParentView(viewGroup); + return textRenderView; + } + + public TextRenderView(Context context, AttributeSet attrs) { + super(context, attrs); + } + + protected void onFinishInflate() { + super.onFinishInflate(); + messageContent = (TextView) findViewById(R.id.message_content); + } + + + /** + * 控件赋值 + * @param messageEntity + * @param userEntity + */ + @Override + public void render(MessageEntity messageEntity, UserEntity userEntity,Context context) { + super.render(messageEntity, userEntity,context); + TextMessage textMessage = (TextMessage) messageEntity; + // 按钮的长按也是上层设定的 + // url 路径可以设定 跳转哦哦 + String content = textMessage.getContent(); + messageContent.setText(Emoparser.getInstance(getContext()).emoCharsequence(content)); // 所以上层还是处理好之后再给我 Emoparser 处理之后的 + extractUrl2Link(messageContent); + + } + private static final String SCHEMA ="com.mogujie.tt://message_private_url"; + private static final String PARAM_UID ="uid"; + private String urlRegex = "((?:(http|https|Http|Https|rtsp|Rtsp):\\/\\/(?:(?:[a-zA-Z0-9\\$\\-\\_\\.\\+\\!\\*\\'\\(\\)\\,\\;\\?\\&\\=]|(?:\\%[a-fA-F0-9]{2})){1,64}(?:\\:(?:[a-zA-Z0-9\\$\\-\\_\\.\\+\\!\\*\\'\\(\\)\\,\\;\\?\\&\\=]|(?:\\%[a-fA-F0-9]{2})){1,25})?\\@)?)?((?:(?:[a-zA-Z0-9][a-zA-Z0-9\\-]{0,64}\\.)+(?:(?:aero|arpa|asia|a[cdefgilmnoqrstuwxz])|(?:biz|b[abdefghijmnorstvwyz])|(?:cat|com|coop|c[acdfghiklmnoruvxyz])|d[ejkmoz]|(?:edu|e[cegrstu])|f[ijkmor]|(?:gov|g[abdefghilmnpqrstuwy])|h[kmnrtu]|(?:info|int|i[delmnoqrst])|(?:jobs|j[emop])|k[eghimnrwyz]|l[abcikrstuvy]|(?:mil|mobi|museum|m[acdghklmnopqrstuvwxyz])|(?:name|net|n[acefgilopruz])|(?:org|om)|(?:pro|p[aefghklmnrstwy])|qa|r[eouw]|s[abcdeghijklmnortuvyz]|(?:tel|travel|t[cdfghjklmnoprtvwz])|u[agkmsyz]|v[aceginu]|w[fs]|y[etu]|z[amw]))|(?:(?:25[0-5]|2[0-4][0-9]|[0-1][0-9]{2}|[1-9][0-9]|[1-9])\\.(?:25[0-5]|2[0-4][0-9]|[0-1][0-9]{2}|[1-9][0-9]|[1-9]|0)\\.(?:25[0-5]|2[0-4][0-9]|[0-1][0-9]{2}|[1-9][0-9]|[1-9]|0)\\.(?:25[0-5]|2[0-4][0-9]|[0-1][0-9]{2}|[1-9][0-9]|[0-9])))(?:\\:\\d{1,5})?)(\\/(?:(?:[a-zA-Z0-9\\;\\/\\?\\:\\@\\&\\=\\#\\~\\-\\.\\+\\!\\*\\'\\(\\)\\,\\_])|(?:\\%[a-fA-F0-9]{2}))*)?(?:\\b|$)"; + + private void extractUrl2Link(TextView v) { + java.util.regex.Pattern wikiWordMatcher = java.util.regex.Pattern.compile(urlRegex); + String mentionsScheme = String.format("%s/?%s=",SCHEMA, PARAM_UID); + Linkify.addLinks(v, wikiWordMatcher, mentionsScheme); + } + + @Override + public void msgFailure(MessageEntity messageEntity) { + super.msgFailure(messageEntity); + } + + /**----------------set/get---------------------------------*/ + public TextView getMessageContent() { + return messageContent; + } + + public void setMessageContent(TextView messageContent) { + this.messageContent = messageContent; + } + + public boolean isMine() { + return isMine; + } + + public void setMine(boolean isMine) { + this.isMine = isMine; + } + + public ViewGroup getParentView() { + return parentView; + } + + public void setParentView(ViewGroup parentView) { + this.parentView = parentView; + } +} diff --git a/android/app/src/main/java/com/mogujie/tt/ui/widget/message/TimeRenderView.java b/android/app/src/main/java/com/mogujie/tt/ui/widget/message/TimeRenderView.java new file mode 100644 index 000000000..99831d24c --- /dev/null +++ b/android/app/src/main/java/com/mogujie/tt/ui/widget/message/TimeRenderView.java @@ -0,0 +1,48 @@ +package com.mogujie.tt.ui.widget.message; + +import android.content.Context; +import android.util.AttributeSet; +import android.view.LayoutInflater; +import android.view.ViewGroup; +import android.widget.LinearLayout; +import android.widget.TextView; + +import com.mogujie.tt.R; +import com.mogujie.tt.utils.DateUtil; + +import java.util.Date; + +/** + * @author : yingmu on 15-1-9. + * @email : yingmu@mogujie.com. + * + * 消息列表中的时间气泡 + * [备注] 插入条件是前后两条消息发送的时间diff 超过某个范围 + * + */ +public class TimeRenderView extends LinearLayout { + private TextView time_title; + + public TimeRenderView(Context context, AttributeSet attrs) { + super(context, attrs); + } + + public static TimeRenderView inflater(Context context,ViewGroup viewGroup){ + TimeRenderView timeRenderView = (TimeRenderView) LayoutInflater.from(context).inflate(R.layout.tt_message_title_time, viewGroup, false); + return timeRenderView; + } + + @Override + protected void onFinishInflate() { + super.onFinishInflate(); + time_title = (TextView) findViewById(R.id.time_title); + } + + /**与数据绑定*/ + public void setTime(Integer msgTime){ + long timeStamp = (long) msgTime; + Date msgTimeDate = new Date(timeStamp * 1000); + time_title.setText(DateUtil.getTimeDiffDesc(msgTimeDate)); + } + +} diff --git a/android/app/src/main/java/com/mogujie/tt/utils/CharacterParser.java b/android/app/src/main/java/com/mogujie/tt/utils/CharacterParser.java new file mode 100644 index 000000000..29f393c89 --- /dev/null +++ b/android/app/src/main/java/com/mogujie/tt/utils/CharacterParser.java @@ -0,0 +1,132 @@ +package com.mogujie.tt.utils; + +import com.mogujie.tt.imservice.entity.MsgAnalyzeEngine; + +/** + * + * @Description 汉字转换为拼音 + * todo 使用方,以及使用的场景? + */ +public class CharacterParser { + private static int[] pyvalue = new int[] {-20319, -20317, -20304, -20295, -20292, -20283, -20265, -20257, -20242, -20230, -20051, -20036, -20032, + -20026, -20002, -19990, -19986, -19982, -19976, -19805, -19784, -19775, -19774, -19763, -19756, -19751, -19746, -19741, -19739, -19728, + -19725, -19715, -19540, -19531, -19525, -19515, -19500, -19484, -19479, -19467, -19289, -19288, -19281, -19275, -19270, -19263, -19261, + -19249, -19243, -19242, -19238, -19235, -19227, -19224, -19218, -19212, -19038, -19023, -19018, -19006, -19003, -18996, -18977, -18961, + -18952, -18783, -18774, -18773, -18763, -18756, -18741, -18735, -18731, -18722, -18710, -18697, -18696, -18526, -18518, -18501, -18490, + -18478, -18463, -18448, -18447, -18446, -18239, -18237, -18231, -18220, -18211, -18201, -18184, -18183, -18181, -18012, -17997, -17988, + -17970, -17964, -17961, -17950, -17947, -17931, -17928, -17922, -17759, -17752, -17733, -17730, -17721, -17703, -17701, -17697, -17692, + -17683, -17676, -17496, -17487, -17482, -17468, -17454, -17433, -17427, -17417, -17202, -17185, -16983, -16970, -16942, -16915, -16733, + -16708, -16706, -16689, -16664, -16657, -16647, -16474, -16470, -16465, -16459, -16452, -16448, -16433, -16429, -16427, -16423, -16419, + -16412, -16407, -16403, -16401, -16393, -16220, -16216, -16212, -16205, -16202, -16187, -16180, -16171, -16169, -16158, -16155, -15959, + -15958, -15944, -15933, -15920, -15915, -15903, -15889, -15878, -15707, -15701, -15681, -15667, -15661, -15659, -15652, -15640, -15631, + -15625, -15454, -15448, -15436, -15435, -15419, -15416, -15408, -15394, -15385, -15377, -15375, -15369, -15363, -15362, -15183, -15180, + -15165, -15158, -15153, -15150, -15149, -15144, -15143, -15141, -15140, -15139, -15128, -15121, -15119, -15117, -15110, -15109, -14941, + -14937, -14933, -14930, -14929, -14928, -14926, -14922, -14921, -14914, -14908, -14902, -14894, -14889, -14882, -14873, -14871, -14857, + -14678, -14674, -14670, -14668, -14663, -14654, -14645, -14630, -14594, -14429, -14407, -14399, -14384, -14379, -14368, -14355, -14353, + -14345, -14170, -14159, -14151, -14149, -14145, -14140, -14137, -14135, -14125, -14123, -14122, -14112, -14109, -14099, -14097, -14094, + -14092, -14090, -14087, -14083, -13917, -13914, -13910, -13907, -13906, -13905, -13896, -13894, -13878, -13870, -13859, -13847, -13831, + -13658, -13611, -13601, -13406, -13404, -13400, -13398, -13395, -13391, -13387, -13383, -13367, -13359, -13356, -13343, -13340, -13329, + -13326, -13318, -13147, -13138, -13120, -13107, -13096, -13095, -13091, -13076, -13068, -13063, -13060, -12888, -12875, -12871, -12860, + -12858, -12852, -12849, -12838, -12831, -12829, -12812, -12802, -12607, -12597, -12594, -12585, -12556, -12359, -12346, -12320, -12300, + -12120, -12099, -12089, -12074, -12067, -12058, -12039, -11867, -11861, -11847, -11831, -11798, -11781, -11604, -11589, -11536, -11358, + -11340, -11339, -11324, -11303, -11097, -11077, -11067, -11055, -11052, -11045, -11041, -11038, -11024, -11020, -11019, -11018, -11014, + -10838, -10832, -10815, -10800, -10790, -10780, -10764, -10587, -10544, -10533, -10519, -10331, -10329, -10328, -10322, -10315, -10309, + -10307, -10296, -10281, -10274, -10270, -10262, -10260, -10256, -10254}; + public static String[] pystr = new String[] {"a", "ai", "an", "ang", "ao", "ba", "bai", "ban", "bang", "bao", "bei", "ben", "beng", "bi", "bian", + "biao", "bie", "bin", "bing", "bo", "bu", "ca", "cai", "can", "cang", "cao", "ce", "ceng", "cha", "chai", "chan", "chang", "chao", "che", + "chen", "cheng", "chi", "chong", "chou", "chu", "chuai", "chuan", "chuang", "chui", "chun", "chuo", "ci", "cong", "cou", "cu", "cuan", + "cui", "cun", "cuo", "da", "dai", "dan", "dang", "dao", "de", "deng", "di", "dian", "diao", "die", "ding", "diu", "dong", "dou", "du", + "duan", "dui", "dun", "duo", "e", "en", "er", "fa", "fan", "fang", "fei", "fen", "feng", "fo", "fou", "fu", "ga", "gai", "gan", "gang", + "gao", "ge", "gei", "gen", "geng", "gong", "gou", "gu", "gua", "guai", "guan", "guang", "gui", "gun", "guo", "ha", "hai", "han", "hang", + "hao", "he", "hei", "hen", "heng", "hong", "hou", "hu", "hua", "huai", "huan", "huang", "hui", "hun", "huo", "ji", "jia", "jian", + "jiang", "jiao", "jie", "jin", "jing", "jiong", "jiu", "ju", "juan", "jue", "jun", "ka", "kai", "kan", "kang", "kao", "ke", "ken", + "keng", "kong", "kou", "ku", "kua", "kuai", "kuan", "kuang", "kui", "kun", "kuo", "la", "lai", "lan", "lang", "lao", "le", "lei", "leng", + "li", "lia", "lian", "liang", "liao", "lie", "lin", "ling", "liu", "long", "lou", "lu", "lv", "luan", "lue", "lun", "luo", "ma", "mai", + "man", "mang", "mao", "me", "mei", "men", "meng", "mi", "mian", "miao", "mie", "min", "ming", "miu", "mo", "mou", "mu", "na", "nai", + "nan", "nang", "nao", "ne", "nei", "nen", "neng", "ni", "nian", "niang", "niao", "nie", "nin", "ning", "niu", "nong", "nu", "nv", "nuan", + "nue", "nuo", "o", "ou", "pa", "pai", "pan", "pang", "pao", "pei", "pen", "peng", "pi", "pian", "piao", "pie", "pin", "ping", "po", "pu", + "qi", "qia", "qian", "qiang", "qiao", "qie", "qin", "qing", "qiong", "qiu", "qu", "quan", "que", "qun", "ran", "rang", "rao", "re", + "ren", "reng", "ri", "rong", "rou", "ru", "ruan", "rui", "run", "ruo", "sa", "sai", "san", "sang", "sao", "se", "sen", "seng", "sha", + "shai", "shan", "shang", "shao", "she", "shen", "sheng", "shi", "shou", "shu", "shua", "shuai", "shuan", "shuang", "shui", "shun", + "shuo", "si", "song", "sou", "su", "suan", "sui", "sun", "suo", "ta", "tai", "tan", "tang", "tao", "te", "teng", "ti", "tian", "tiao", + "tie", "ting", "tong", "tou", "tu", "tuan", "tui", "tun", "tuo", "wa", "wai", "wan", "wang", "wei", "wen", "weng", "wo", "wu", "xi", + "xia", "xian", "xiang", "xiao", "xie", "xin", "xing", "xiong", "xiu", "xu", "xuan", "xue", "xun", "ya", "yan", "yang", "yao", "ye", "yi", + "yin", "ying", "yo", "yong", "you", "yu", "yuan", "yue", "yun", "za", "zai", "zan", "zang", "zao", "ze", "zei", "zen", "zeng", "zha", + "zhai", "zhan", "zhang", "zhao", "zhe", "zhen", "zheng", "zhi", "zhong", "zhou", "zhu", "zhua", "zhuai", "zhuan", "zhuang", "zhui", + "zhun", "zhuo", "zi", "zong", "zou", "zu", "zuan", "zui", "zun", "zuo"}; + private StringBuilder buffer; + private String resource; + private static CharacterParser characterParser = new CharacterParser(); + + public static CharacterParser getInstance() { + return characterParser; + } + + public String getResource() { + return resource; + } + + public void setResource(String resource) { + this.resource = resource; + } + + private int getChsToAscii(String chs) { + int asc = 0; + try { + byte[] bytes = chs.getBytes("gb2312"); + if (bytes == null || bytes.length > 2 || bytes.length <= 0) { + throw new RuntimeException("illegal resource string"); + } + if (bytes.length == 1) { + asc = bytes[0]; + } + if (bytes.length == 2) { + int hightByte = 256 + bytes[0]; + int lowByte = 256 + bytes[1]; + asc = (256 * hightByte + lowByte) - 256 * 256; + } + } catch (Exception e) { + Logger.getLogger(MsgAnalyzeEngine.class).e(e.getMessage()); + } + return asc; + } + + public String convertChs(String str) { + String result = null; + int ascii = getChsToAscii(str); + if (ascii > 0 && ascii < 160) { + result = String.valueOf((char) ascii); + } else { + for (int i = (pyvalue.length - 1); i >= 0; i--) { + if (pyvalue[i] <= ascii) { + result = pystr[i]; + break; + } + } + } + return result; + } + + public String getSelling(String chs) { + String key, value; + buffer = new StringBuilder(); + for (int i = 0; i < chs.length(); i++) { + key = chs.substring(i, i + 1); + if (key.getBytes().length >= 2) { + value = (String) convertChs(key); + if (value == null) { + value = "unknown"; + } + } else { + value = key; + } + buffer.append(value); + } + return buffer.toString(); + } + + public String getSpelling() { + return this.getSelling(this.getResource()); + } + +} diff --git a/android/app/src/main/java/com/mogujie/tt/utils/CommonUtil.java b/android/app/src/main/java/com/mogujie/tt/utils/CommonUtil.java new file mode 100644 index 000000000..6d9a5606f --- /dev/null +++ b/android/app/src/main/java/com/mogujie/tt/utils/CommonUtil.java @@ -0,0 +1,412 @@ + +package com.mogujie.tt.utils; + +import android.app.Activity; +import android.app.ActivityManager; +import android.content.ComponentName; +import android.content.Context; +import android.content.Intent; +import android.database.Cursor; +import android.net.Uri; +import android.os.Environment; +import android.os.StatFs; +import android.text.TextUtils; +import android.util.DisplayMetrics; +import android.view.View; +import android.view.inputmethod.InputMethodManager; +import android.widget.Toast; + +import com.mogujie.tt.R; +import com.mogujie.tt.config.SysConstant; + +import java.io.BufferedReader; +import java.io.File; +import java.io.FileNotFoundException; +import java.io.FileReader; +import java.io.IOException; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +public class CommonUtil { + private static Logger logger = Logger.getLogger(CommonUtil.class); + /** + * @Description 判断是否是顶部activity + * @param context + * @param activityName + * @return + */ + public static boolean isTopActivy(Context context, String activityName) { + ActivityManager am = (ActivityManager) context + .getSystemService(Context.ACTIVITY_SERVICE); + ComponentName cName = am.getRunningTasks(1).size() > 0 ? am + .getRunningTasks(1).get(0).topActivity : null; + + if (null == cName) + return false; + return cName.getClassName().equals(activityName); + } + + /** + * @Description 判断存储卡是否存在 + * @return + */ + public static boolean checkSDCard() { + if (android.os.Environment.getExternalStorageState().equals( + android.os.Environment.MEDIA_MOUNTED)) { + return true; + } + + return false; + } + + /** + * @Description 获取sdcard可用空间的大小 + * @return + */ + @SuppressWarnings("deprecation") + public static long getSDFreeSize() { + File path = Environment.getExternalStorageDirectory(); + StatFs sf = new StatFs(path.getPath()); + long blockSize = sf.getBlockSize(); + long freeBlocks = sf.getAvailableBlocks(); + // return freeBlocks * blockSize; //单位Byte + // return (freeBlocks * blockSize)/1024; //单位KB + return (freeBlocks * blockSize) / 1024 / 1024; // 单位MB + } + + /** + * @Description 获取sdcard容量 + * @return + */ + @SuppressWarnings({ + "deprecation", "unused" + }) + private static long getSDAllSize() { + File path = Environment.getExternalStorageDirectory(); + StatFs sf = new StatFs(path.getPath()); + long blockSize = sf.getBlockSize(); + long allBlocks = sf.getBlockCount(); + // 返回SD卡大小 + // return allBlocks * blockSize; //单位Byte + // return (allBlocks * blockSize)/1024; //单位KB + return (allBlocks * blockSize) / 1024 / 1024; // 单位MB + } + + public static byte[] intToBytes(int n) { + byte[] b = new byte[4]; + for (int i = 0; i < 4; i++) { + b[i] = (byte) (n >> (24 - i * 8)); + } + return b; + } + + public static byte[] float2byte(float f) { + + // 把float转换为byte[] + int fbit = Float.floatToIntBits(f); + + byte[] b = new byte[4]; + for (int i = 0; i < 4; i++) { + b[i] = (byte) (fbit >> (24 - i * 8)); + } + + // 翻转数组 + int len = b.length; + // 建立一个与源数组元素类型相同的数组 + byte[] dest = new byte[len]; + // 为了防止修改源数组,将源数组拷贝一份副本 + System.arraycopy(b, 0, dest, 0, len); + byte temp; + // 将顺位第i个与倒数第i个交换 + for (int i = 0; i < len / 2; ++i) { + temp = dest[i]; + dest[i] = dest[len - i - 1]; + dest[len - i - 1] = temp; + } + + return dest; + + } + + /** + * 将byte数组转换为int数据 + * + * @param b 字节数组 + * @return 生成的int数据 + */ + public static int byteArray2int(byte[] b) { + return (((int) b[0]) << 24) + (((int) b[1]) << 16) + + (((int) b[2]) << 8) + b[3]; + } + + /** + * @Description 判断是否是url + * @param text + * @return + */ + public static String matchUrl(String text) { + if (TextUtils.isEmpty(text)) { + return null; + } + Pattern p = Pattern.compile( + "[http]+[://]+[0-9A-Za-z:/[-]_#[?][=][.][&]]*", + Pattern.CASE_INSENSITIVE); + Matcher matcher = p.matcher(text); + if (matcher.find()) { + return matcher.group(); + } else { + return null; + } + } + + + public static String getImageSavePath(String fileName) { + + if (TextUtils.isEmpty(fileName)) { + return null; + } + + final File folder = new File(Environment.getExternalStorageDirectory() + .getAbsolutePath() + + File.separator + + "MGJ-IM" + + File.separator + + "images"); + if (!folder.exists()) { + folder.mkdirs(); + } + + return folder.getAbsolutePath() + File.separator + fileName; + } + + public static File getImageSavePath() { + final File folder = new File(Environment.getExternalStorageDirectory() + .getAbsolutePath() + + File.separator + + "MGJ-IM" + + File.separator + + "images"); + if (!folder.exists()) { + folder.mkdirs(); + } + return folder; + } + + /** + * @param uri The Uri to check. + * @return Whether the Uri authority is ExternalStorageProvider. + */ + public static boolean isExternalStorageDocument(Uri uri) { + return "com.android.externalstorage.documents".equals(uri + .getAuthority()); + } + + /** + * @param uri The Uri to check. + * @return Whether the Uri authority is DownloadsProvider. + */ + public static boolean isDownloadsDocument(Uri uri) { + return "com.android.providers.downloads.documents".equals(uri + .getAuthority()); + } + + /** + * @param uri The Uri to check. + * @return Whether the Uri authority is MediaProvider. + */ + public static boolean isMediaDocument(Uri uri) { + return "com.android.providers.media.documents".equals(uri + .getAuthority()); + } + + /** + * @param uri The Uri to check. + * @return Whether the Uri authority is Google Photos. + */ + public static boolean isGooglePhotosUri(Uri uri) { + return "com.google.android.apps.photos.content".equals(uri + .getAuthority()); + } + + /** + * Get the value of the data column for this Uri. This is useful for + * MediaStore Uris, and other file-based ContentProviders. + * + * @param context The context. + * @param uri The Uri to query. + * @param selection (Optional) Filter used in the query. + * @param selectionArgs (Optional) Selection arguments used in the query. + * @return The value of the _data column, which is typically a file path. + */ + public static String getDataColumn(Context context, Uri uri, + String selection, String[] selectionArgs) { + + Cursor cursor = null; + final String column = "_data"; + final String[] projection = { + column + }; + + try { + cursor = context.getContentResolver().query(uri, projection, + selection, selectionArgs, null); + if (cursor != null && cursor.moveToFirst()) { + final int index = cursor.getColumnIndexOrThrow(column); + return cursor.getString(index); + } + } finally { + if (cursor != null) + cursor.close(); + } + return null; + } + + + public static int getDefaultPannelHeight(Context context) { + if (context != null) { + int size = (int) (getElementSzie(context) * 5.5); + return size; + } else { + return 300; + } + } + + // check again + public static int getAudioBkSize(int sec, Context context) { + int size = getElementSzie(context) * 2; + if (sec <= 0) { + return -1; + } else if (sec <= 2) { + return size; + } else if (sec <= 8) { + return (int) (size + ((float) ((sec - 2) / 6.0)) * size); + } else if (sec <= 60) { + return (int) (2 * size + ((float) ((sec - 8) / 52.0)) * size); + } else { + return -1; + } + } + + public static int getElementSzie(Context context) { + if (context != null) { + DisplayMetrics dm = context.getResources().getDisplayMetrics(); + int screenHeight = px2dip(dm.heightPixels, context); + int screenWidth = px2dip(dm.widthPixels, context); + int size = screenWidth / 6; + if (screenWidth >= 800) { + size = 60; + } else if (screenWidth >= 650) { + size = 55; + } else if (screenWidth >= 600) { + size = 50; + } else if (screenHeight <= 400) { + size = 20; + } else if (screenHeight <= 480) { + size = 25; + } else if (screenHeight <= 520) { + size = 30; + } else if (screenHeight <= 570) { + size = 35; + } else if (screenHeight <= 640) { + if (dm.heightPixels <= 960) { + size = 50; + } else if (dm.heightPixels <= 1000) { + size = 45; + } + } + return size; + } + return 40; + } + + private static int px2dip(float pxValue, Context context) { + final float scale = context.getResources().getDisplayMetrics().density; + return (int) (pxValue / scale + 0.5f); + } + + public static String getAudioSavePath(int userId) { + String path = getSavePath(SysConstant.FILE_SAVE_TYPE_AUDIO) + userId + + "_" + String.valueOf(System.currentTimeMillis()) + + ".spx"; + File file = new File(path); + File parent = file.getParentFile(); + if (parent != null && !parent.exists()) { + parent.mkdirs(); + } + return path; + } + + public static String getSavePath(int type) { + String path; + String floder = (type == SysConstant.FILE_SAVE_TYPE_IMAGE) ? "images" + : "audio"; + if (CommonUtil.checkSDCard()) { + path = Environment.getExternalStorageDirectory().toString() + + File.separator + "MGJ-IM" + File.separator + floder + + File.separator; + + } else { + path = Environment.getDataDirectory().toString() + File.separator + + "MGJ-IM" + File.separator + floder + File.separator; + } + return path; + } + + /** + * @Description 隐藏软键盘 + * @param activity + */ + public static void hideInput(Activity activity) { + View view = activity.getWindow().peekDecorView(); + if (view != null) { + InputMethodManager inputmanger = (InputMethodManager) activity + .getSystemService(Context.INPUT_METHOD_SERVICE); + inputmanger.hideSoftInputFromWindow(view.getWindowToken(), 0); + } + } + + + + public static long getmem_TOLAL() { + long mTotal; + // /proc/meminfo读出的内核信息进行解释 + String path = "/proc/meminfo"; + String content = null; + BufferedReader br = null; + try { + br = new BufferedReader(new FileReader(path), 8); + String line; + if ((line = br.readLine()) != null) { + content = line; + } + } catch (FileNotFoundException e) { + e.printStackTrace(); + } catch (IOException e) { + e.printStackTrace(); + } finally { + if (br != null) { + try { + br.close(); + } catch (IOException e) { + e.printStackTrace(); + } + } + } + // beginIndex + int begin = content.indexOf(':'); + // endIndex + int end = content.indexOf('k'); + // 截取字符串信息 + + content = content.substring(begin + 1, end).trim(); + mTotal = Integer.parseInt(content); + return mTotal; + } + + public static boolean gifCheck(String url) + { + boolean isGif = !TextUtils.isEmpty(url) && url.equals(CommonUtil.matchUrl(url)) && url.toLowerCase().substring(url.length() - 4, url.length()).equals(".gif"); + return isGif; + } + +} diff --git a/android/app/src/main/java/com/mogujie/tt/utils/DateUtil.java b/android/app/src/main/java/com/mogujie/tt/utils/DateUtil.java new file mode 100644 index 000000000..310e2fb7a --- /dev/null +++ b/android/app/src/main/java/com/mogujie/tt/utils/DateUtil.java @@ -0,0 +1,228 @@ + +package com.mogujie.tt.utils; + +import java.text.SimpleDateFormat; +import java.util.Calendar; +import java.util.Date; + +/** + * 主要终于页面时间的转化 + * 日期工具类 + * @yingmu + * + */ +public class DateUtil { + /** + * 新版时间展示 聊天页面 + * @param mTimeStamp + * @return + * 【备注】注意时间单位是毫秒 + */ + public static String getSessionTime(int mTimeStamp) { + if (mTimeStamp <= 0) { + return null; + } + String[] weekDays = { + "星期日", "星期一", "星期二", "星期三", "星期四", "星期五", "星期六" + }; + String strDesc = null; + SimpleDateFormat formatYear = new SimpleDateFormat("yy/MM/dd"); + SimpleDateFormat formatToday = new SimpleDateFormat("HH:mm"); + /**消息时间戳*/ + long changeTime = (long) mTimeStamp; + long messageTimeStamp = changeTime * 1000; + /**当前的时间戳*/ + long currentTimeStamp =System.currentTimeMillis(); + /**获取今天的 0 点时间戳*/ + long todayTimeStamp = getTimesmorning(); + /**获取 上一周 0点时间戳*/ + long rangeWeekStamp = todayTimeStamp - 86400000*6; + + /**今天的显示 hh:mm (今天星期三) + * 昨天 + * 星期一 + * 星期日 、 星期六、 星期五、星期四 + * yy-hh-mm + * */ + do{ + long diff = currentTimeStamp - messageTimeStamp; + long diffToday = currentTimeStamp - todayTimeStamp; + /**今天之内的*/ + if(diff < diffToday){ + strDesc = formatToday.format(messageTimeStamp); + break; + } + + long diffWeek = currentTimeStamp - rangeWeekStamp; + /**最近一周的判断*/ + if(diff < diffWeek){ + /**昨天零点的时间*/ + long yesterday = todayTimeStamp - 86400000; + long diffYesterday = currentTimeStamp - yesterday; + if(diff < diffYesterday){ + strDesc = "昨天"; + }else{ + Calendar weekCal = Calendar.getInstance(); + weekCal.setTimeInMillis(messageTimeStamp); + int w = weekCal.get(Calendar.DAY_OF_WEEK) -1; + w = w<0?0:w; + strDesc = weekDays[w]; + } + break; + } + /**年月日显示*/ + strDesc = formatYear.format(messageTimeStamp); + }while(false); + return strDesc; + } + + /** + * 获取当天 零点的时间戳【linux】 + * @return + */ + public static long getTimesmorning() { + Calendar cal = Calendar.getInstance(); + cal.set(Calendar.HOUR_OF_DAY, 0); + cal.set(Calendar.SECOND, 0); + cal.set(Calendar.MINUTE, 0); + cal.set(Calendar.MILLISECOND, 0); + return cal.getTimeInMillis(); + } + + public static boolean needDisplayTime(int predateTime, int curdateTime) { + long timediff = (curdateTime - predateTime); + return (timediff >= 5 * 60 ); + } + + public static String getTimeDiffDesc(Date date) { + + if (date == null) { + return null; + } + + String strDesc = null; + Calendar curCalendar = Calendar.getInstance(); + Date curDate = new Date(); + curCalendar.setTime(curDate); + Calendar thenCalendar = Calendar.getInstance(); + thenCalendar.setTime(date); + + String[] weekDays = { + "星期日", "星期一", "星期二", "星期三", "星期四", "星期五", "星期六" + }; + int w = thenCalendar.get(Calendar.DAY_OF_WEEK) - 1; + if (w < 0) + w = 0; + // SimpleDateFormat format = new + // SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); + Calendar current = Calendar.getInstance(); + Calendar today = Calendar.getInstance(); // 今天 + today.set(Calendar.YEAR, current.get(Calendar.YEAR)); + today.set(Calendar.MONTH, current.get(Calendar.MONTH)); + today.set(Calendar.DAY_OF_MONTH, current.get(Calendar.DAY_OF_MONTH)); + today.set(Calendar.HOUR_OF_DAY, 0); + today.set(Calendar.MINUTE, 0); + today.set(Calendar.SECOND, 0); + // Date datetoday = today.getTime(); + // System.out.println(format.format(datetoday)); + + Calendar yesterday = Calendar.getInstance(); // 昨天 + yesterday.setTime(curDate); + yesterday.add(Calendar.DATE, -1); + yesterday.set(Calendar.HOUR_OF_DAY, 0); + yesterday.set(Calendar.MINUTE, 0); + yesterday.set(Calendar.SECOND, 0); + // Date dateyestoday = yesterday.getTime(); + // System.out.println(format.format(dateyestoday)); + + Calendar sevendaysago = Calendar.getInstance(); // 7天 + sevendaysago.setTime(curDate); + sevendaysago.add(Calendar.DATE, -7); + sevendaysago.set(Calendar.HOUR_OF_DAY, 0); + sevendaysago.set(Calendar.MINUTE, 0); + sevendaysago.set(Calendar.SECOND, 0); + // Date datesevenago = sevendaysago.getTime(); + // System.out.println(format.format(datesevenago)); + /* + * Date tasktime = yesterday.getTime(); SimpleDateFormat df=new + * SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); + * System.out.println(df.format(tasktime)); + */ + + int thenMonth = thenCalendar.get(Calendar.MONTH); + int thenDay = thenCalendar.get(Calendar.DAY_OF_MONTH); + int h = thenCalendar.get(Calendar.HOUR_OF_DAY); + int m = thenCalendar.get(Calendar.MINUTE); + String sh = "", sm = ""; + if (h < 10) + sh = "0"; + + if (m < 10) + sm = "0"; + if (thenCalendar.after(today))// today + { + if (h < 6) { + strDesc = "凌晨 " + sh + h + ":" + sm + m; + } else if (h < 12) { + strDesc = "上午 " + sh + h + ":" + sm + m; + } else if (h < 13) { + strDesc = "下午 " + h + ":" + sm + m; + } else if (h < 19) { + strDesc = "下午 " + (h - 12) + ":" + sm + m; + } else { + strDesc = "晚上 " + (h - 12) + ":" + sm + m; + } + } else if (thenCalendar.before(today) && thenCalendar.after(yesterday)) {// yestoday + // System.out.println("yestoday"); + if (h < 6) { + strDesc = "昨天凌晨 " + sh + h + ":" + sm + m; + } else if (h < 12) { + strDesc = "昨天上午 " + sh + h + ":" + sm + m; + } else if (h < 13) { + strDesc = "昨天下午 " + h + ":" + sm + m; + } else if (h < 19) { + strDesc = "昨天下午 " + (h - 12) + ":" + sm + m; + } else { + strDesc = "昨天晚上 " + (h - 12) + ":" + sm + m; + } + } else if (thenCalendar.before(yesterday) + && thenCalendar.after(sevendaysago)) {// 2 ~ 7days ago + // System.out.println("2~7"); + if (h < 6) { + strDesc = weekDays[w] + "凌晨 " + sh + h + ":" + sm + m; + } else if (h < 12) { + strDesc = weekDays[w] + "上午 " + sh + h + ":" + sm + m; + } else if (h < 13) { + strDesc = weekDays[w] + "下午 " + h + ":" + sm + m; + } else if (h < 19) { + strDesc = weekDays[w] + "下午 " + (h - 12) + ":" + sm + m; + } else { + strDesc = weekDays[w] + "晚上 " + (h - 12) + ":" + sm + m; + } + } else { + // System.out.println("7~"); + if (h < 6) { + strDesc = (thenMonth + 1) + "月" + thenDay + "日" + "凌晨 " + sh + + h + ":" + sm + m; + } else if (h < 12) { + strDesc = (thenMonth + 1) + "月" + thenDay + "日" + "上午 " + sh + + h + ":" + sm + m; + } else if (h < 13) { + strDesc = (thenMonth + 1) + "月" + thenDay + "日" + "下午 " + h + + ":" + sm + m; + } else if (h < 19) { + strDesc = (thenMonth + 1) + "月" + thenDay + "日" + "下午 " + + (h - 12) + ":" + sm + m; + } else { + strDesc = (thenMonth + 1) + "月" + thenDay + "日" + "晚上 " + + (h - 12) + ":" + sm + m; + } + } + // System.out.println(strDesc); + return strDesc; + } + + + + +} diff --git a/android/app/src/main/java/com/mogujie/tt/utils/DumpUtils.java b/android/app/src/main/java/com/mogujie/tt/utils/DumpUtils.java new file mode 100644 index 000000000..9544672df --- /dev/null +++ b/android/app/src/main/java/com/mogujie/tt/utils/DumpUtils.java @@ -0,0 +1,39 @@ +package com.mogujie.tt.utils; + +import android.util.Log; + +import java.util.List; + +public class DumpUtils { + public static void dumpStringList(Logger logger, String desc, + List memberList) { + String log = String.format("%s, members:", desc); + for (String memberId : memberList) { + log += memberId + ","; + } + + logger.d("%s", log); + } + + public static void dumpIntegerList(Logger logger, String desc, + List memberList) { + String log = String.format("%s, members:", desc); + for (int memberId : memberList) { + log += memberId + ","; + } + + logger.d("%s", log); + } + + //oneLine for purpose of "tail -f", so you can track them at one line + public static void dumpStacktrace(Logger logger, String desc, + boolean oneLine) { + String stackTraceString = Log.getStackTraceString(new Throwable()); + + if (oneLine) { + stackTraceString = stackTraceString.replace("\n", "####"); + } + + logger.d("%s:%s", desc, stackTraceString); + } +} diff --git a/android/app/src/main/java/com/mogujie/tt/utils/FileUtil.java b/android/app/src/main/java/com/mogujie/tt/utils/FileUtil.java new file mode 100644 index 000000000..f233a3064 --- /dev/null +++ b/android/app/src/main/java/com/mogujie/tt/utils/FileUtil.java @@ -0,0 +1,501 @@ + +package com.mogujie.tt.utils; + +import android.graphics.Bitmap; +import android.graphics.BitmapFactory; +import android.os.Environment; + +import com.mogujie.tt.config.SysConstant; +import com.squareup.okhttp.Cache; +import com.squareup.okhttp.OkHttpClient; +import com.squareup.okhttp.Request; +import com.squareup.okhttp.Response; +import com.squareup.okhttp.internal.DiskLruCache; +import com.squareup.okhttp.internal.Util; + +import org.apache.commons.io.IOUtils; + +import java.io.BufferedReader; +import java.io.ByteArrayOutputStream; +import java.io.DataOutputStream; +import java.io.File; +import java.io.FileInputStream; +import java.io.FileNotFoundException; +import java.io.FileOutputStream; +import java.io.FilterInputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.io.OutputStream; +import java.io.OutputStreamWriter; +import java.io.UnsupportedEncodingException; +import java.net.HttpURLConnection; +import java.net.MalformedURLException; +import java.net.URL; +import java.net.URLDecoder; + +public class FileUtil +{ + public static String SDCardRoot; + public static File updateFile; + static + { + // 获取SD卡路径 + SDCardRoot = Environment.getExternalStorageDirectory().getAbsolutePath() + File.separator; + } + + /** + * 创建文件夹 + * + * @throws IOException + */ + public static File createFileInSDCard(String fileName, String dir) + { + File file = new File(SDCardRoot + dir + File.separator + fileName); + try + { + file.createNewFile(); + } catch (IOException e) + { + e.printStackTrace(); + } + updateFile = file; + return file; + } + + /** + * 创建目录 + * + * @param dir + * @return + */ + public static File creatSDDir(String dir) + { + File dirFile = new File(SDCardRoot + dir + File.separator); + dirFile.mkdirs(); + return dirFile; + } + + /** + * 检测文件是否存在 + */ + public static boolean isFileExist(String fileName, String path) + { + File file = new File(SDCardRoot + path + File.separator + fileName); + return file.exists(); + } + public static boolean isFileExist(String filePath) + { + File file = new File(filePath); + return file.exists(); + } + + /** + * 通过流往文件里写东西 + */ + public static File writeToSDFromInput(String path, String fileName, InputStream input) + { + + File file = null; + OutputStream output = null; + try + { + file = createFileInSDCard(fileName, path); + output = new FileOutputStream(file, false); + byte buffer[] = new byte[4 * 1024]; + int temp; + while ((temp = input.read(buffer)) != -1) + { + output.write(buffer, 0, temp); + } + output.flush(); + } catch (Exception e) + { + e.printStackTrace(); + } finally + { + try + { + output.close(); + } catch (Exception e) + { + e.printStackTrace(); + } + } + return file; + } + + /** + * 把字符串写入文件 + */ + public static File writeToSDFromInput(String path, String fileName, String data) + { + + File file = null; + OutputStreamWriter outputWriter = null; + OutputStream outputStream = null; + try + { + creatSDDir(path); + file = createFileInSDCard(fileName, path); + outputStream = new FileOutputStream(file, false); + outputWriter = new OutputStreamWriter(outputStream); + outputWriter.write(data); + outputWriter.flush(); + } catch (Exception e) + { + e.printStackTrace(); + } finally + { + try + { + outputWriter.close(); + } catch (Exception e) + { + e.printStackTrace(); + } + } + return file; + } + + public static String getFromCipherConnection(String actionUrl, String content, String path) + { + + try + { + File[] files = new File[1]; + files[0] = new File(path); + // content = CipherUtil.getCipherString(content); + String BOUNDARY = java.util.UUID.randomUUID().toString(); + String PREFIX = "--", LINEND = "\r\n"; + String MULTIPART_FROM_DATA = "multipart/form-data"; + String CHARSET = "UTF-8"; + URL uri = new URL(actionUrl); + HttpURLConnection conn = (HttpURLConnection) uri.openConnection(); + conn.setReadTimeout(5 * 1000); // 缓存的最长时间 + conn.setDoInput(true);// 允许输入 + conn.setDoOutput(true);// 允许输出 + conn.setUseCaches(false); // 不允许使用缓存 + conn.setRequestMethod("POST"); + conn.setRequestProperty("connection", "keep-alive"); + conn.setRequestProperty("Charsert", "UTF-8"); + conn.setRequestProperty("Content-Type", MULTIPART_FROM_DATA + ";boundary=" + BOUNDARY); + // 首先组拼文本类型的参数 + StringBuilder sb = new StringBuilder(); + sb.append(PREFIX); + sb.append(BOUNDARY); + sb.append(LINEND); + sb.append("Content-Disposition: form-data; name=\"userName\"" + LINEND);// \"userName\" + sb.append("Content-Type: text/plain; charset=" + CHARSET + LINEND); + sb.append("Content-Transfer-Encoding: 8bit" + LINEND); + sb.append(LINEND); + sb.append(content); + sb.append(LINEND); + + DataOutputStream outStream = new DataOutputStream(conn.getOutputStream()); + outStream.write(sb.toString().getBytes()); + // 发送文件数据 + if (files != null) + { + for (File file : files) + { + StringBuilder sb1 = new StringBuilder(); + sb1.append(PREFIX); + sb1.append(BOUNDARY); + sb1.append(LINEND); + sb1.append("Content-Disposition: form-data; name=\"" + file.getName() + + "\"; filename=\"" + file.getName() + "\"" + LINEND); + sb1.append("Content-Type: application/octet-stream; charset=" + CHARSET + + LINEND); + sb1.append(LINEND); + outStream.write(sb1.toString().getBytes()); + try + { + InputStream is = new FileInputStream(file); + byte[] buffer = new byte[1024]; + int len = 0; + while ((len = is.read(buffer)) != -1) + { + + outStream.write(buffer, 0, len); + } + is.close(); + outStream.write(LINEND.getBytes()); + } catch (IOException e) + { + e.printStackTrace(); + } + } + } + // 请求结束标志 + byte[] end_data = (PREFIX + BOUNDARY + PREFIX + LINEND).getBytes(); + outStream.write(end_data); + outStream.flush(); + outStream.close(); + // 得到响应码 + int res = conn.getResponseCode(); + if (res == 200) + { + BufferedReader in = new BufferedReader(new InputStreamReader( + (InputStream) conn.getInputStream())); + String line = null; + StringBuilder result = new StringBuilder(); + while ((line = in.readLine()) != null) + { + result.append(line); + } + in.close(); + conn.disconnect();// 断开连接 + return "true"; + } + else + { + return ""; + } + + } catch (Exception e) + { + e.printStackTrace(); + return ""; + } + + } + + public static byte[] getFileContent(String fileName) { + FileInputStream fin = null; + try { + fin = new FileInputStream(fileName); + int length = fin.available(); + byte[] bytes = new byte[length]; + fin.read(bytes); + return bytes; + } catch (Exception e) { + e.printStackTrace(); + return null; + } finally { + try { + if (fin != null) { + fin.close(); + } + } catch (IOException e) { + e.printStackTrace(); + } + } + } + + /** + * @Description 删除文件或文件夹 + * @param file + */ + public static void delete(File file) { + if (!file.exists()) { + return; // 不存在直接返回 + } + + if (file.isFile()) { + file.delete(); // 若是文件则删除后返回 + return; + } + + // 若是目录递归删除后,并最后删除目录后返回 + if (file.isDirectory()) { + File[] childFiles = file.listFiles(); + if (childFiles == null || childFiles.length == 0) { + file.delete(); // 如果是空目录,直接删除 + return; + } + + for (int i = 0; i < childFiles.length; i++) { + delete(childFiles[i]); // 递归删除子文件或子文件夹 + } + file.delete(); // 删除最后的空目录 + } + return; + } + + /** + * @Description 删除目录下过旧的文件 + * @param dirFile 目录文件 + * @param timeLine 时间分隔线 + */ + public static void deleteHistoryFiles(File dirFile, long timeLine) { + // 不存在或是文件直接返回 + if (!dirFile.exists() || dirFile.isFile()) { + return; + } + + try { + // 如果是目录则删除过旧的文件 + if (dirFile.isDirectory()) { + File[] childFiles = dirFile.listFiles(); + if (childFiles == null || childFiles.length == 0) { + return; // 如果是空目录就直接返回 + } + // 遍历文件,删除过旧的文件 + Long fileTime; + for (int i = 0; i < childFiles.length; i++) { + fileTime = childFiles[i].lastModified(); + if (fileTime < timeLine) { + delete(childFiles[i]); + } + } + } + } catch (Exception e) { + e.printStackTrace(); + } + + } + + public static File save2File(String savePath, String saveName, + String crashReport) { + try { + File dir = new File(savePath); + if (!dir.exists()) + dir.mkdir(); + File file = new File(dir, saveName); + FileOutputStream fos = new FileOutputStream(file); + fos.write(crashReport.toString().getBytes()); + fos.close(); + return file; + } catch (FileNotFoundException e) { + e.printStackTrace(); + } catch (IOException e) { + e.printStackTrace(); + } + return null; + } + + + public static String saveAudioResourceToFile(byte[] content,int userId) { + try { + String audioSavePath = CommonUtil.getAudioSavePath(userId); + File file = new File(audioSavePath); + FileOutputStream fops = new FileOutputStream(file); + fops.write(content); + fops.flush(); + fops.close(); + return audioSavePath; + } catch (Exception e) { + e.printStackTrace(); + return null; + } + } + + public static String saveGifResourceToFile(byte[] content) { + try { + String gifSavePath = CommonUtil.getSavePath(SysConstant.FILE_SAVE_TYPE_IMAGE); + File file = new File(gifSavePath); + FileOutputStream fops = new FileOutputStream(file); + fops.write(content); + fops.flush(); + fops.close(); + return gifSavePath; + } catch (Exception e) { + e.printStackTrace(); + return null; + } + } + + + + @SuppressWarnings("unused") + private static Bitmap getBitmap(InputStream fs) { + BitmapFactory.Options opts = new BitmapFactory.Options(); + opts.inSampleSize = 1; + Bitmap imgBitmap = BitmapFactory.decodeStream(fs, null, opts); + if (imgBitmap != null) { + int width = imgBitmap.getWidth(); + int height = imgBitmap.getHeight(); + imgBitmap = Bitmap.createScaledBitmap(imgBitmap, width, height, + true); + } + return imgBitmap; + } + + public static long getFileLen(File file) { + long total = 0; + try { + InputStream is = new FileInputStream(file); + byte[] bytes = new byte[1024]; + int len = 0; + while ((len = is.read(bytes)) != -1) { + total += len; + } + is.close(); + } catch (Exception e) { + + } + return total; + } + + public static boolean isSdCardAvailuable() { + + boolean bRet = false; + do { + if (!Environment.getExternalStorageState().equals( + Environment.MEDIA_MOUNTED)) { + break; + } + + if (CommonUtil.getSDFreeSize() < 5) { + break; + } + + bRet = true; + } while (false); + + return bRet; + } + + public static byte[] InputStreamToByte(InputStream is) throws IOException { + ByteArrayOutputStream bytestream = new ByteArrayOutputStream(); + int ch; + while ((ch = is.read()) != -1) { + bytestream.write(ch); + } + byte imgdata[] = bytestream.toByteArray(); + bytestream.close(); + + + return imgdata; + } + + public static byte[] File2byte(String filePath) + { + byte[] buffer = null; + try + { + File file = new File(filePath); + FileInputStream fis = new FileInputStream(file); + ByteArrayOutputStream bos = new ByteArrayOutputStream(); + byte[] b = new byte[1024]; + int n; + while ((n = fis.read(b)) != -1) + { + bos.write(b, 0, n); + } + fis.close(); + bos.close(); + buffer = bos.toByteArray(); + } + catch (FileNotFoundException e) + { + e.printStackTrace(); + } + catch (IOException e) + { + e.printStackTrace(); + } + return buffer; + } + + public static String getExtensionName(String filename) { + if ((filename != null) && (filename.length() > 0)) { + int dot = filename.lastIndexOf('.'); + if ((dot >-1) && (dot < (filename.length() - 1))) { + return filename.substring(dot + 1); + } + } + return filename; + } +} diff --git a/android/app/src/main/java/com/mogujie/tt/utils/IMUIHelper.java b/android/app/src/main/java/com/mogujie/tt/utils/IMUIHelper.java new file mode 100644 index 000000000..b27341929 --- /dev/null +++ b/android/app/src/main/java/com/mogujie/tt/utils/IMUIHelper.java @@ -0,0 +1,471 @@ +package com.mogujie.tt.utils; + +import android.app.AlertDialog; +import android.content.Context; +import android.content.DialogInterface; +import android.content.Intent; +import android.graphics.Bitmap; +import android.graphics.Color; +import android.net.Uri; +import android.text.Spannable; +import android.text.TextUtils; +import android.text.style.ForegroundColorSpan; +import android.view.ContextThemeWrapper; +import android.view.LayoutInflater; +import android.view.MotionEvent; +import android.view.View; +import android.widget.EditText; +import android.widget.ImageView; +import android.widget.TextView; +import android.widget.TextView.BufferType; + +import com.mogujie.tt.config.DBConstant; +import com.mogujie.tt.DB.entity.DepartmentEntity; +import com.mogujie.tt.DB.entity.GroupEntity; +import com.mogujie.tt.DB.entity.UserEntity; +import com.mogujie.tt.R; +import com.mogujie.tt.config.IntentConstant; +import com.mogujie.tt.config.UrlConstant; +import com.mogujie.tt.imservice.entity.SearchElement; +import com.mogujie.tt.imservice.event.LoginEvent; +import com.mogujie.tt.imservice.event.SocketEvent; +import com.mogujie.tt.ui.activity.GroupMemberSelectActivity; +import com.mogujie.tt.ui.activity.MessageActivity; +import com.mogujie.tt.ui.activity.UserInfoActivity; +import com.mogujie.tt.utils.pinyin.PinYin.PinYinElement; +import com.nostra13.universalimageloader.core.DisplayImageOptions; +import com.nostra13.universalimageloader.core.ImageLoader; +import com.nostra13.universalimageloader.core.assist.ImageScaleType; +import com.nostra13.universalimageloader.core.display.RoundedBitmapDisplayer; + +public class IMUIHelper { + + // 在视图中,长按用户信息条目弹出的对话框 + public static void handleContactItemLongClick(final UserEntity contact, final Context ctx){ + if(contact == null || ctx == null){ + return; + } + AlertDialog.Builder builder = new AlertDialog.Builder(new ContextThemeWrapper(ctx, android.R.style.Theme_Holo_Light_Dialog)); + builder.setTitle(contact.getMainName()); + String[] items = new String[]{ctx.getString(R.string.check_profile), + ctx.getString(R.string.start_session)}; + + final int userId = contact.getPeerId(); + builder.setItems(items, new DialogInterface.OnClickListener() { + + @Override + public void onClick(DialogInterface dialog, int which) { + switch (which) { + case 0 : + IMUIHelper.openUserProfileActivity(ctx, userId); + break; + case 1 : + IMUIHelper.openChatActivity(ctx,contact.getSessionKey()); + break; + } + } + }); + AlertDialog alertDialog = builder.create(); + alertDialog.setCanceledOnTouchOutside(true); + alertDialog.show(); + } + + + // 根据event 展示提醒文案 + public static int getLoginErrorTip(LoginEvent event) { + switch (event) { + case LOGIN_AUTH_FAILED: + return R.string.login_error_general_failed; + case LOGIN_INNER_FAILED: + return R.string.login_error_unexpected; + default : + return R.string.login_error_unexpected; + } + } + + public static int getSocketErrorTip(SocketEvent event) { + switch (event) { + case CONNECT_MSG_SERVER_FAILED : + return R.string.connect_msg_server_failed; + case REQ_MSG_SERVER_ADDRS_FAILED : + return R.string.req_msg_server_addrs_failed; + default : + return R.string.login_error_unexpected; + } + } + + // 跳转到聊天页面 + public static void openChatActivity(Context ctx, String sessionKey) { + Intent intent = new Intent(ctx, MessageActivity.class); + intent.putExtra(IntentConstant.KEY_SESSION_KEY, sessionKey); + ctx.startActivity(intent); + } + + + //跳转到用户信息页面 + public static void openUserProfileActivity(Context ctx, int contactId) { + Intent intent = new Intent(ctx, UserInfoActivity.class); + intent.putExtra(IntentConstant.KEY_PEERID, contactId); + ctx.startActivity(intent); + } + + public static void openGroupMemberSelectActivity(Context ctx, String sessionKey) { + Intent intent = new Intent(ctx, GroupMemberSelectActivity.class); + intent.putExtra(IntentConstant.KEY_SESSION_KEY, sessionKey); + ctx.startActivity(intent); + } + + + // 对话框回调函数 + public interface dialogCallback{ + public void callback(); + } + + public static void showCustomDialog(Context context,int visibale,String title, final dialogCallback callback) + { + AlertDialog.Builder builder = new AlertDialog.Builder(new ContextThemeWrapper(context, android.R.style.Theme_Holo_Light_Dialog)); + LayoutInflater inflater = (LayoutInflater)context.getSystemService(Context.LAYOUT_INFLATER_SERVICE); + View dialog_view = inflater.inflate(R.layout.tt_custom_dialog, null); + final EditText editText = (EditText)dialog_view.findViewById(R.id.dialog_edit_content); + editText.setVisibility(visibale); + TextView textText = (TextView)dialog_view.findViewById(R.id.dialog_title); + textText.setText(title); + builder.setView(dialog_view); + + builder.setPositiveButton(context.getString(R.string.tt_ok), new DialogInterface.OnClickListener() { + + @Override + public void onClick(DialogInterface dialog, int which) { + callback.callback(); + dialog.dismiss(); + } + }); + + builder.setNegativeButton(context.getString(R.string.tt_cancel), new DialogInterface.OnClickListener() { + @Override + public void onClick(DialogInterface dialogInterface, int i) { + dialogInterface.dismiss(); + } + }); + builder.show(); + } + + public static void callPhone(Context ctx, String phoneNumber) { + if (ctx == null) { + return; + } + if (phoneNumber == null || phoneNumber.isEmpty()) { + return; + } + Intent intent = new Intent(Intent.ACTION_CALL, Uri.parse("tel:" + + phoneNumber)); + + ctx.startActivity(intent); + } + + + + + // 文字高亮显示 + public static void setTextHilighted(TextView textView, String text,SearchElement searchElement) { + textView.setText(text); + if (textView == null + || TextUtils.isEmpty(text) + || searchElement ==null) { + return; + } + + int startIndex = searchElement.startIndex; + int endIndex = searchElement.endIndex; + if (startIndex < 0 || endIndex > text.length()) { + return; + } + // 开始高亮处理 + int color = Color.rgb(69, 192, 26); + textView.setText(text, BufferType.SPANNABLE); + Spannable span = (Spannable) textView.getText(); + span.setSpan(new ForegroundColorSpan(color), startIndex, endIndex, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE); + } + + + /** + * 如果图片路径是以 http开头,直接返回 + * 如果不是, 需要集合自己的图像路径生成规律 + * @param avatarUrl + * @return + */ + public static String getRealAvatarUrl(String avatarUrl) { + if (avatarUrl.toLowerCase().contains("http")) { + return avatarUrl; + } else if (avatarUrl.trim().isEmpty()) { + return ""; + } else { + return UrlConstant.AVATAR_URL_PREFIX + avatarUrl; + } + } + + + + // search helper start + public static boolean handleDepartmentSearch(String key, DepartmentEntity department) { + if (TextUtils.isEmpty(key) || department == null) { + return false; + } + department.getSearchElement().reset(); + + return handleTokenFirstCharsSearch(key, department.getPinyinElement(), department.getSearchElement()) + || handleTokenPinyinFullSearch(key, department.getPinyinElement(), department.getSearchElement()) + || handleNameSearch(department.getDepartName(), key, department.getSearchElement()); + } + + + public static boolean handleGroupSearch(String key, GroupEntity group) { + if (TextUtils.isEmpty(key) || group == null) { + return false; + } + group.getSearchElement().reset(); + + return handleTokenFirstCharsSearch(key, group.getPinyinElement(), group.getSearchElement()) + || handleTokenPinyinFullSearch(key, group.getPinyinElement(), group.getSearchElement()) + || handleNameSearch(group.getMainName(), key, group.getSearchElement()); + } + + public static boolean handleContactSearch(String key, UserEntity contact) { + if (TextUtils.isEmpty(key) || contact == null) { + return false; + } + + contact.getSearchElement().reset(); + + return handleTokenFirstCharsSearch(key, contact.getPinyinElement(), contact.getSearchElement()) + || handleTokenPinyinFullSearch(key, contact.getPinyinElement(), contact.getSearchElement()) + || handleNameSearch(contact.getMainName(), key, contact.getSearchElement()); + // 原先是 contact.name 代表花名的意思嘛?? + } + + public static boolean handleNameSearch(String name, String key, + SearchElement searchElement) { + int index = name.indexOf(key); + if (index == -1) { + return false; + } + + searchElement.startIndex = index; + searchElement.endIndex = index + key.length(); + + return true; + } + + public static boolean handleTokenFirstCharsSearch(String key, PinYinElement pinYinElement, SearchElement searchElement) { + return handleNameSearch(pinYinElement.tokenFirstChars, key.toUpperCase(), searchElement); + } + + public static boolean handleTokenPinyinFullSearch(String key, PinYinElement pinYinElement, SearchElement searchElement) { + if (TextUtils.isEmpty(key)) { + return false; + } + + String searchKey = key.toUpperCase(); + + //onLoginOut the old search result + searchElement.reset(); + + int tokenCnt = pinYinElement.tokenPinyinList.size(); + int startIndex = -1; + int endIndex = -1; + + for (int i = 0; i < tokenCnt; ++i) { + String tokenPinyin = pinYinElement.tokenPinyinList.get(i); + + int tokenPinyinSize = tokenPinyin.length(); + int searchKeySize = searchKey.length(); + + int keyCnt = Math.min(searchKeySize, tokenPinyinSize); + String keyPart = searchKey.substring(0, keyCnt); + + if (tokenPinyin.startsWith(keyPart)) { + + if (startIndex == -1) { + startIndex = i; + } + + endIndex = i + 1; + } else { + continue; + } + + if (searchKeySize <= tokenPinyinSize) { + searchKey = ""; + break; + } + + searchKey = searchKey.substring(keyCnt, searchKeySize); + } + + if (!searchKey.isEmpty()) { + return false; + } + + if (startIndex >= 0 && endIndex > 0) { + searchElement.startIndex = startIndex; + searchElement.endIndex = endIndex; + + return true; + } + + return false; + } + + // search helper end + + + + public static void setViewTouchHightlighted(final View view) { + if (view == null) { + return; + } + + view.setOnTouchListener(new View.OnTouchListener() { + + @Override + public boolean onTouch(View v, MotionEvent event) { + if (event.getAction() == MotionEvent.ACTION_DOWN) { + view.setBackgroundColor(Color.rgb(1, 175, 244)); + } else if (event.getAction() == MotionEvent.ACTION_UP) { + view.setBackgroundColor(Color.rgb(255, 255, 255)); + } + return false; + } + }); + } + + + + + + // 这个还是蛮有用的,方便以后的替换 + public static int getDefaultAvatarResId(int sessionType) { + if (sessionType == DBConstant.SESSION_TYPE_SINGLE) { + return R.drawable.tt_default_user_portrait_corner; + } else if (sessionType == DBConstant.SESSION_TYPE_GROUP) { + return R.drawable.group_default; + } else if (sessionType == DBConstant.SESSION_TYPE_GROUP) { + return R.drawable.discussion_group_default; + } + + return R.drawable.tt_default_user_portrait_corner; + } + + + public static void setEntityImageViewAvatarNoDefaultPortrait(ImageView imageView, + String avatarUrl, int sessionType, int roundPixel) { + setEntityImageViewAvatarImpl(imageView, avatarUrl, sessionType, false, roundPixel); + } + + public static void setEntityImageViewAvatarImpl(ImageView imageView, + String avatarUrl, int sessionType, boolean showDefaultPortrait, int roundPixel) { + if (avatarUrl == null) { + avatarUrl = ""; + } + + String fullAvatar = getRealAvatarUrl(avatarUrl); + int defaultResId = -1; + + if (showDefaultPortrait) { + defaultResId = getDefaultAvatarResId(sessionType); + } + + displayImage(imageView, fullAvatar, defaultResId, roundPixel); + } + + public static void displayImage(ImageView imageView, + String resourceUri, int defaultResId, int roundPixel) { + + Logger logger = Logger.getLogger(IMUIHelper.class); + + logger.d("displayimage#displayImage resourceUri:%s, defeaultResourceId:%d", resourceUri, defaultResId); + + if (resourceUri == null) { + resourceUri = ""; + } + + boolean showDefaultImage = !(defaultResId <= 0); + + if (TextUtils.isEmpty(resourceUri) && !showDefaultImage) { + logger.e("displayimage#, unable to display image"); + return; + } + + + DisplayImageOptions options; + if (showDefaultImage) { + options = new DisplayImageOptions.Builder(). + showImageOnLoading(defaultResId). + showImageForEmptyUri(defaultResId). + showImageOnFail(defaultResId). + cacheInMemory(true). + cacheOnDisk(true). + considerExifParams(true). + displayer(new RoundedBitmapDisplayer(roundPixel)). + imageScaleType(ImageScaleType.EXACTLY).// 改善OOM + bitmapConfig(Bitmap.Config.RGB_565).// 改善OOM + build(); + } else { + options = new DisplayImageOptions.Builder(). + cacheInMemory(true). + cacheOnDisk(true). +// considerExifParams(true). +// displayer(new RoundedBitmapDisplayer(roundPixel)). +// imageScaleType(ImageScaleType.EXACTLY).// 改善OOM +// bitmapConfig(Bitmap.Config.RGB_565).// 改善OOM + build(); + } + + ImageLoader.getInstance().displayImage(resourceUri, imageView, options, null); + } + + + + public static void displayImageNoOptions(ImageView imageView, + String resourceUri, int defaultResId, int roundPixel) { + + Logger logger = Logger.getLogger(IMUIHelper.class); + + logger.d("displayimage#displayImage resourceUri:%s, defeaultResourceId:%d", resourceUri, defaultResId); + + if (resourceUri == null) { + resourceUri = ""; + } + + boolean showDefaultImage = !(defaultResId <= 0); + + if (TextUtils.isEmpty(resourceUri) && !showDefaultImage) { + logger.e("displayimage#, unable to display image"); + return; + } + + DisplayImageOptions options; + if (showDefaultImage) { + options = new DisplayImageOptions.Builder(). + showImageOnLoading(defaultResId). + showImageForEmptyUri(defaultResId). + showImageOnFail(defaultResId). + cacheInMemory(true). + cacheOnDisk(true). + considerExifParams(true). + displayer(new RoundedBitmapDisplayer(roundPixel)). + imageScaleType(ImageScaleType.EXACTLY).// 改善OOM + bitmapConfig(Bitmap.Config.RGB_565).// 改善OOM + build(); + } else { + options = new DisplayImageOptions.Builder(). +// cacheInMemory(true). +// cacheOnDisk(true). + imageScaleType(ImageScaleType.EXACTLY).// 改善OOM + bitmapConfig(Bitmap.Config.RGB_565).// 改善OOM + build(); + } + ImageLoader.getInstance().displayImage(resourceUri, imageView, options, null); + } + +} diff --git a/android/app/src/main/java/com/mogujie/tt/utils/ImageLoaderUtil.java b/android/app/src/main/java/com/mogujie/tt/utils/ImageLoaderUtil.java new file mode 100644 index 000000000..dc05487ed --- /dev/null +++ b/android/app/src/main/java/com/mogujie/tt/utils/ImageLoaderUtil.java @@ -0,0 +1,175 @@ +package com.mogujie.tt.utils; + +import android.content.Context; +import android.graphics.Bitmap; +import android.util.DisplayMetrics; +import android.view.WindowManager; + +import com.mogujie.tt.R; +import com.mogujie.tt.config.SysConstant; +import com.mogujie.tt.ui.helper.CircleBitmapDisplayer; +import com.nostra13.universalimageloader.cache.disc.impl.UnlimitedDiscCache; +import com.nostra13.universalimageloader.cache.disc.naming.Md5FileNameGenerator; +import com.nostra13.universalimageloader.cache.memory.impl.UsingFreqLimitedMemoryCache; +import com.nostra13.universalimageloader.core.DisplayImageOptions; +import com.nostra13.universalimageloader.core.ImageLoader; +import com.nostra13.universalimageloader.core.ImageLoaderConfiguration; +import com.nostra13.universalimageloader.core.assist.ImageScaleType; +import com.nostra13.universalimageloader.core.assist.QueueProcessingType; +import com.nostra13.universalimageloader.core.display.RoundedBitmapDisplayer; +import com.nostra13.universalimageloader.utils.StorageUtils; + +import java.io.File; +import java.util.HashMap; +import java.util.Map; + +/** + * Created by zhujian on 15/1/14. + */ +public class ImageLoaderUtil { + private static Logger logger = Logger.getLogger(ImageLoaderUtil.class); + private static ImageLoaderConfiguration IMImageLoaderConfig; + private static ImageLoader IMImageLoadInstance; + private static Map> avatarOptionsMaps=new HashMap>(); + public final static int CIRCLE_CORNER = -10; + + public static void initImageLoaderConfig(Context context) { + try { + File cacheDir = StorageUtils.getOwnCacheDirectory(context, CommonUtil.getSavePath(SysConstant.FILE_SAVE_TYPE_IMAGE)); + File reserveCacheDir = StorageUtils.getCacheDirectory(context); + + int maxMemory = (int) (Runtime.getRuntime().maxMemory() ); + // 使用最大可用内存值的1/8作为缓存的大小。 + int cacheSize = maxMemory/8; + DisplayMetrics metrics=new DisplayMetrics(); + WindowManager mWm = (WindowManager)context.getSystemService(Context.WINDOW_SERVICE); + mWm.getDefaultDisplay().getMetrics(metrics); + + IMImageLoaderConfig = new ImageLoaderConfiguration.Builder(context) + .memoryCacheExtraOptions(metrics.widthPixels, metrics.heightPixels) + .threadPriority(Thread.NORM_PRIORITY-2) +// .denyCacheImageMultipleSizesInMemory() + .memoryCache(new UsingFreqLimitedMemoryCache(cacheSize)) + .diskCacheFileNameGenerator(new Md5FileNameGenerator()) + .tasksProcessingOrder(QueueProcessingType.LIFO) + .diskCacheExtraOptions(metrics.widthPixels, metrics.heightPixels, null) + .diskCache(new UnlimitedDiscCache(cacheDir,reserveCacheDir,new Md5FileNameGenerator())) + .diskCacheSize(1024 * 1024 * 1024) + .diskCacheFileCount(1000) + .build(); + + IMImageLoadInstance = ImageLoader.getInstance(); + IMImageLoadInstance.init(IMImageLoaderConfig); + }catch (Exception e){ + logger.e(e.toString()); + } + } + + public static ImageLoader getImageLoaderInstance() { + return IMImageLoadInstance; + } + + public static DisplayImageOptions getAvatarOptions(int corner,int defaultRes){ + try { + if (defaultRes <= 0) { + defaultRes = R.drawable.tt_default_user_portrait_corner; + } + if (avatarOptionsMaps.containsKey(defaultRes)) { + Map displayOption = avatarOptionsMaps.get(defaultRes); + if (displayOption.containsKey(corner)) { + return displayOption.get(corner); + } + } + DisplayImageOptions newDisplayOption = null; + if (corner==CIRCLE_CORNER) { + newDisplayOption = new DisplayImageOptions.Builder() + .showImageOnFail(defaultRes) + .showImageForEmptyUri(defaultRes) + .cacheInMemory(true) + .resetViewBeforeLoading(true) + .displayer(new CircleBitmapDisplayer()) + .build(); + } else { + if (corner < 0) { + corner = 0; + } + newDisplayOption = new DisplayImageOptions.Builder() + .showImageOnLoading(defaultRes) + .showImageForEmptyUri(defaultRes) + .showImageOnFail(defaultRes) + .cacheInMemory(true) + .cacheOnDisk(true) + .considerExifParams(true) + .imageScaleType(ImageScaleType.EXACTLY) + .bitmapConfig(Bitmap.Config.RGB_565) + .resetViewBeforeLoading(false) +// .displayer(new FadeInBitmapDisplayer(200)) + .displayer(new RoundedBitmapDisplayer(corner)) + .build(); + } + + Map cornerDisplayOptMap = new HashMap(); + cornerDisplayOptMap.put(corner, newDisplayOption); + avatarOptionsMaps.put(defaultRes, cornerDisplayOptMap); + return newDisplayOption; + }catch (Exception e){ + logger.e(e.toString()); + return null; + } + } + + public static DisplayImageOptions getAvatarOptions2(int corner,int defaultRes){ + try { + if (defaultRes <= 0) { + defaultRes = R.drawable.tt_default_user_portrait_corner; + } + if (avatarOptionsMaps.containsKey(defaultRes)) { + Map displayOption = avatarOptionsMaps.get(defaultRes); + if (displayOption.containsKey(corner)) { + return displayOption.get(corner); + } + } + DisplayImageOptions newDisplayOption = null; + if (corner==CIRCLE_CORNER) { + newDisplayOption = new DisplayImageOptions.Builder() + .showImageOnFail(defaultRes) + .cacheInMemory(true) + .build(); + } else { + if (corner < 0) { + corner = 0; + } + newDisplayOption = new DisplayImageOptions.Builder() + .cacheInMemory(true) + .cacheOnDisk(true) + .build(); + } + + Map cornerDisplayOptMap = new HashMap(); + cornerDisplayOptMap.put(corner, newDisplayOption); + avatarOptionsMaps.put(defaultRes, cornerDisplayOptMap); + return newDisplayOption; + }catch (Exception e){ + logger.e(e.toString()); + return null; + } + } + + /** + * 清除缓存 + */ + public static void clearCache() { + try { + if (IMImageLoadInstance != null) { + IMImageLoadInstance.clearMemoryCache(); + IMImageLoadInstance.clearDiskCache(); + } + if(null!=avatarOptionsMaps) + { + avatarOptionsMaps.clear(); + } + } catch (Exception e) { + logger.e(e.toString()); + } + } +} diff --git a/android/app/src/main/java/com/mogujie/tt/utils/ImageUtil.java b/android/app/src/main/java/com/mogujie/tt/utils/ImageUtil.java new file mode 100644 index 000000000..c34165b66 --- /dev/null +++ b/android/app/src/main/java/com/mogujie/tt/utils/ImageUtil.java @@ -0,0 +1,69 @@ +package com.mogujie.tt.utils; + +import android.app.Activity; +import android.content.Context; +import android.graphics.Bitmap; +import android.graphics.BitmapFactory; +import android.graphics.Matrix; +import android.util.DisplayMetrics; + +import com.mogujie.tt.ui.helper.PhotoHelper; + +import java.io.File; + +/** + * @Description 图片处理 + * @author Nana + * @date 2014-8-4 + * + */ +public class ImageUtil { + private static Logger logger = Logger.getLogger(ImageUtil.class); + + public static Bitmap getBigBitmapForDisplay(String imagePath, + Context context) { + if (null == imagePath || !new File(imagePath).exists()) + return null; + try { + int degeree = PhotoHelper.readPictureDegree(imagePath); + Bitmap bitmap = BitmapFactory.decodeFile(imagePath); + if (bitmap == null) + return null; + DisplayMetrics dm = new DisplayMetrics(); + ((Activity) context).getWindowManager().getDefaultDisplay().getMetrics(dm); + float scale = bitmap.getWidth() / (float) dm.widthPixels; + Bitmap newBitMap = null; + if (scale > 1) { + newBitMap = zoomBitmap(bitmap, (int) (bitmap.getWidth() / scale), (int) (bitmap.getHeight() / scale)); + bitmap.recycle(); + Bitmap resultBitmap = PhotoHelper.rotaingImageView(degeree, newBitMap); + return resultBitmap; + } + Bitmap resultBitmap = PhotoHelper.rotaingImageView(degeree, bitmap); + return resultBitmap; + } catch (Exception e) { + logger.e(e.getMessage()); + return null; + } + } + + private static Bitmap zoomBitmap(Bitmap bitmap, int width, int height) { + if (null == bitmap) { + return null; + } + try { + int w = bitmap.getWidth(); + int h = bitmap.getHeight(); + Matrix matrix = new Matrix(); + float scaleWidth = ((float) width / w); + float scaleHeight = ((float) height / h); + matrix.postScale(scaleWidth, scaleHeight); + Bitmap newbmp = Bitmap.createBitmap(bitmap, 0, 0, w, h, matrix, true); + return newbmp; + } catch (Exception e) { + logger.e(e.getMessage()); + return null; + } + } + +} diff --git a/android/app/src/main/java/com/mogujie/tt/utils/Logger.java b/android/app/src/main/java/com/mogujie/tt/utils/Logger.java new file mode 100644 index 000000000..e093601d7 --- /dev/null +++ b/android/app/src/main/java/com/mogujie/tt/utils/Logger.java @@ -0,0 +1,194 @@ +package com.mogujie.tt.utils; + +import android.util.Log; + +import java.text.SimpleDateFormat; +import java.util.Date; +import java.util.concurrent.locks.Lock; +import java.util.concurrent.locks.ReentrantLock; + +public class Logger { + /** + * log tag + */ + private String tagName = "MoGuLogger";// tag name + private static int logLevel = Log.ERROR; + //private static int logLevel = Log.DEBUG; + + private static Logger inst; + private Lock lock; + + private Logger() { + lock = new ReentrantLock(); + } + + public static synchronized Logger getLogger(Class key) { + if (inst == null) { + inst = new Logger(); + } + return inst; + } + + private String getFunctionName() { + StackTraceElement[] sts = Thread.currentThread().getStackTrace(); + + if (sts == null) { + return null; + } + + for (StackTraceElement st : sts) { + if (st.isNativeMethod()) { + continue; + } + + if (st.getClassName().equals(Thread.class.getName())) { + continue; + } + + if (st.getClassName().equals(this.getClass().getName())) { + continue; + } + + return "[" + st.getFileName() + ":" + st.getLineNumber() + "]"; + } + + return null; + } + + private String createMessage(String msg) { + String functionName = getFunctionName(); + long threadId = Thread.currentThread().getId(); + String currentTime = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss:SSS").format(new Date()); + String message = (functionName == null ? msg : (functionName + " - " + + String.valueOf(threadId) + " - " + msg)); + String finalRes = currentTime + " - " + message; + return finalRes; + } + + /** + * log.i + */ + public void i(String format, Object... args) { + if (logLevel <= Log.INFO) { + lock.lock(); + try { + String message = createMessage(getInputString(format, args)); + Log.i(tagName, message); + } finally { + lock.unlock(); + } + } + } + + /** + * log.v + */ + public void v(String format, Object... args) { + if (logLevel <= Log.VERBOSE) { + lock.lock(); + try { + String message = createMessage(getInputString(format, args)); + Log.v(tagName, message); + } finally { + lock.unlock(); + } + } + } + + /** + * log.d + */ + public void d(String format, Object... args) { + if (logLevel <= Log.DEBUG) { + lock.lock(); + try { + String message = createMessage(getInputString(format, args)); + Log.d(tagName, message); + } finally { + lock.unlock(); + } + } + } + + /** + * log.e + */ + public void e(String format, Object... args) { + if (logLevel <= Log.ERROR) { + lock.lock(); + try { + String message = createMessage(getInputString(format, args)); + Log.e(tagName, message); + } finally { + lock.unlock(); + } + } + } + + private String getInputString(String format, Object... args) { + if (format == null) { + return "null log format"; + } + + return String.format(format, args); + } + + /** + * log.error + */ + public void error(Exception e) { + if (logLevel <= Log.ERROR) { + StringBuffer sb = new StringBuffer(); + lock.lock(); + try { + String name = getFunctionName(); + StackTraceElement[] sts = e.getStackTrace(); + + if (name != null) { + sb.append(name + " - " + e + "\r\n"); + } else { + sb.append(e + "\r\n"); + } + if (sts != null && sts.length > 0) { + for (StackTraceElement st : sts) { + if (st != null) { + sb.append("[ " + st.getFileName() + ":" + + st.getLineNumber() + " ]\r\n"); + } + } + } + Log.e(tagName, sb.toString()); + } finally { + lock.unlock(); + } + } + } + /** + * log.d + */ + public void w(String format, Object... args) { + if (logLevel <= Log.WARN) { + lock.lock(); + try { + String message = createMessage(getInputString(format, args)); + Log.w(tagName, message); + } finally { + lock.unlock(); + } + } + } + + /** + * set log level + */ + + public void setLevel(int l) { + lock.lock(); + try { + logLevel = l; + } finally { + lock.unlock(); + } + } + +} diff --git a/android/app/src/main/java/com/mogujie/tt/utils/MoGuHttpClient.java b/android/app/src/main/java/com/mogujie/tt/utils/MoGuHttpClient.java new file mode 100644 index 000000000..164ba4dbe --- /dev/null +++ b/android/app/src/main/java/com/mogujie/tt/utils/MoGuHttpClient.java @@ -0,0 +1,88 @@ +package com.mogujie.tt.utils; + +import org.json.JSONObject; + +import java.io.BufferedReader; +import java.io.DataOutputStream; +import java.io.File; +import java.io.InputStreamReader; +import java.io.OutputStream; +import java.net.HttpURLConnection; +import java.net.URL; +import java.util.ArrayList; +import java.util.List; + +public class MoGuHttpClient { + + private static Logger logger = Logger.getLogger(MoGuHttpClient.class); + + public String uploadImage3(String strUrl, byte[] bytes, String fileName) { + logger.d("pic#uploadImage3 strUlr:%s", strUrl); + List list = new ArrayList(); // 要上传的文件名,如:d:\haha.doc.你要实现自己的业务。我这里就是一个空list. + list.add(fileName); + try { + String BOUNDARY = "---------7d4a6d158c9"; // 定义数据分隔线 + URL url = new URL(strUrl); + HttpURLConnection conn = (HttpURLConnection) url.openConnection(); + // 发送POST请求必须设置如下两行 + conn.setDoOutput(true); + conn.setDoInput(true); + conn.setUseCaches(false); + conn.setRequestMethod("POST"); + conn.setRequestProperty("connection", "Keep-Alive"); + conn.setRequestProperty("user-agent", + "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1)"); + conn.setRequestProperty("Charsert", "UTF-8"); + conn.setRequestProperty("Content-Type", + "multipart/form-data; boundary=" + BOUNDARY); + + OutputStream out = new DataOutputStream(conn.getOutputStream()); + byte[] end_data = ("\r\n--" + BOUNDARY + "--\r\n").getBytes();// 定义最后数据分隔线 + int leng = list.size(); + for (int i = 0; i < leng; i++) { + String fname = list.get(i); + File file = new File(fname); + StringBuilder sb = new StringBuilder(); + sb.append("--"); + sb.append(BOUNDARY); + sb.append("\r\n"); + sb.append("Content-Disposition: form-data;name=\"file" + i + + "\";filename=\"" + file.getName() + "\"\r\n"); + sb.append("Content-Type:application/octet-stream\r\n\r\n"); + + byte[] data = sb.toString().getBytes(); + out.write(data); + out.write(bytes); + out.write("\r\n".getBytes()); // 多个文件时,二个文件之间加入这个 + } + out.write(end_data); + out.flush(); + out.close(); + + // 定义BufferedReader输入流来读取URL的响应 + BufferedReader reader = new BufferedReader(new InputStreamReader( + conn.getInputStream())); + String line = null; + while ((line = reader.readLine()) != null) { + logger.d("pic#line:%s", line); + + // todo eric + /* + * {"error_code":0,"error_msg": + * "成功","path":"g0/000/000/1410706133246550_140184328214.jpg" + * ,"url": + * "http://122.225.68.125:8001/g0/000/000/1410706133246550_140184328214.jpg" + * } + */ + JSONObject root = new JSONObject(line); + return root.getString("url"); + } + + } catch (Exception e) { + System.out.println("pic#发送POST请求出现异常!" + e); + e.printStackTrace(); + } + + return ""; + } +} diff --git a/android/app/src/main/java/com/mogujie/tt/utils/NetworkUtil.java b/android/app/src/main/java/com/mogujie/tt/utils/NetworkUtil.java new file mode 100644 index 000000000..77a8fb7bd --- /dev/null +++ b/android/app/src/main/java/com/mogujie/tt/utils/NetworkUtil.java @@ -0,0 +1,43 @@ + +package com.mogujie.tt.utils; + +import android.content.Context; +import android.net.ConnectivityManager; +import android.net.NetworkInfo; + +public class NetworkUtil { + + /** 网络不可用 */ + public static final int NONETWORK = 0; + /** 是wifi连接 */ + public static final int WIFI = 1; + /** 不是wifi连接 */ + public static final int NOWIFI = 2; + + public static int getNetWorkType(Context context) { + if (!isNetWorkAvalible(context)) { + return NetworkUtil.NONETWORK; + } + ConnectivityManager cm = (ConnectivityManager) context + .getSystemService(Context.CONNECTIVITY_SERVICE); + // cm.getNetworkInfo(ConnectivityManager.TYPE_MOBILE); + if (cm.getNetworkInfo(ConnectivityManager.TYPE_WIFI).isConnectedOrConnecting()) + return NetworkUtil.WIFI; + else + return NetworkUtil.NOWIFI; + } + + public static boolean isNetWorkAvalible(Context context) { + ConnectivityManager cm = (ConnectivityManager) context + .getSystemService(Context.CONNECTIVITY_SERVICE); + if (cm == null) { + return false; + } + NetworkInfo ni = cm.getActiveNetworkInfo(); + if (ni == null || !ni.isAvailable()) { + return false; + } + return true; + } + +} diff --git a/android/app/src/main/java/com/mogujie/tt/utils/ScreenUtil.java b/android/app/src/main/java/com/mogujie/tt/utils/ScreenUtil.java new file mode 100644 index 000000000..028db7618 --- /dev/null +++ b/android/app/src/main/java/com/mogujie/tt/utils/ScreenUtil.java @@ -0,0 +1,89 @@ +package com.mogujie.tt.utils; + +/** + * Created by zhujian on 15/1/14. + */ + +import android.content.Context; + +import java.lang.reflect.Field; + +/** + * 获取屏幕,分辨率相关 + */ +public class ScreenUtil { + private Context mCtx; + private static ScreenUtil mScreenTools; + + public static ScreenUtil instance(Context ctx){ + if(null == mScreenTools){ + mScreenTools = new ScreenUtil(ctx); + } + return mScreenTools; + } + + private ScreenUtil(Context ctx){ + mCtx = ctx.getApplicationContext(); + } + + public int getScreenWidth(){ + return mCtx.getResources().getDisplayMetrics().widthPixels; + } + + public int dip2px(int dip){ + float density = getDensity(mCtx); + return (int)(dip * density + 0.5); + } + + public int px2dip(int px){ + float density = getDensity(mCtx); + return (int)((px - 0.5) / density); + } + + private float getDensity(Context ctx){ + return ctx.getResources().getDisplayMetrics().density; + } + + /** + * 540 的分辨率上是85 ( + * @return + */ + public int getScal(){ + return (int)(getScreenWidth() * 100 / 480); + } + + /** + * 宽全屏, 根据当前分辨率 动态获取高度 + * height 在800*480情况下 的高度 + * @return + */ + public int get480Height(int height480){ + int width = getScreenWidth(); + return (height480 * width / 480); + } + + /** + * 获取状态栏高度 + * @return + */ + public int getStatusBarHeight(){ + Class c = null; + Object obj = null; + Field field = null; + int x = 0, sbar = 0; + try { + c = Class.forName("com.android.internal.R$dimen"); + obj = c.newInstance(); + field = c.getField("status_bar_height"); + x = Integer.parseInt(field.get(obj).toString()); + sbar = mCtx.getResources().getDimensionPixelSize(x); + } catch (Exception e1) { + e1.printStackTrace(); + } + return sbar; + } + + public int getScreenHeight(){ + return mCtx.getResources().getDisplayMetrics().heightPixels; + } +} \ No newline at end of file diff --git a/android/app/src/main/java/com/mogujie/tt/utils/packageInfo b/android/app/src/main/java/com/mogujie/tt/utils/packageInfo new file mode 100644 index 000000000..0bea6f113 --- /dev/null +++ b/android/app/src/main/java/com/mogujie/tt/utils/packageInfo @@ -0,0 +1,5 @@ +* 项目的工具类 +1. 不依赖具体的业务代码,较为独立 +2. 注意和helper区分。helper 业务联系紧密。脱离具体业务代码意义不大。 +3. mgimlibs也包含这么多的工具类 todo 转移到mgimlibs中,合并已知的 +4 有些代码的通用部分可以抽离出来,例如reconnect 中的isNetWorkAvalible \ No newline at end of file diff --git a/android/app/src/main/java/com/mogujie/tt/utils/pinyin/HanziToPinyin3.java b/android/app/src/main/java/com/mogujie/tt/utils/pinyin/HanziToPinyin3.java new file mode 100644 index 000000000..2ad0c8ea5 --- /dev/null +++ b/android/app/src/main/java/com/mogujie/tt/utils/pinyin/HanziToPinyin3.java @@ -0,0 +1,558 @@ +/* + * Copyright (C) 2011 The Android Open Source Project + * + * 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 com.mogujie.tt.utils.pinyin; + +import android.text.TextUtils; +import android.util.Log; + +import java.text.Collator; +import java.util.ArrayList; +import java.util.Locale; + +/** + * An object to convert Chinese character to its corresponding pinyin string. For characters with + * multiple possible pinyin string, only one is selected according to collator. Polyphone is not + * supported in this implementation. This class is implemented to achieve the best runtime + * performance and minimum runtime resources with tolerable sacrifice of accuracy. This + * implementation highly depends on zh_CN ICU collation data and must be always synchronized with + * ICU. + * + * Currently this file is aligned to zh.txt in ICU 4.6 + * 来自android4.2源码 + */ +public class HanziToPinyin3 { + private static final String TAG = "HanziToPinyin"; + + // Turn on this flag when we want to check internal data structure. + private static final boolean DEBUG = false; + + /** + * Unihans array. + * + * Each unihans is the first one within same pinyin when collator is zh_CN. + */ + public static final char[] UNIHANS = { + '\u963f', '\u54ce', '\u5b89', '\u80ae', '\u51f9', '\u516b', + '\u6300', '\u6273', '\u90a6', '\u52f9', '\u9642', '\u5954', + '\u4f3b', '\u5c44', '\u8fb9', '\u706c', '\u618b', '\u6c43', + '\u51ab', '\u7676', '\u5cec', '\u5693', '\u5072', '\u53c2', + '\u4ed3', '\u64a1', '\u518a', '\u5d7e', '\u66fd', '\u66fe', + '\u5c64', '\u53c9', '\u8286', '\u8fbf', '\u4f25', '\u6284', + '\u8f66', '\u62bb', '\u6c88', '\u6c89', '\u9637', '\u5403', + '\u5145', '\u62bd', '\u51fa', '\u6b3b', '\u63e3', '\u5ddb', + '\u5205', '\u5439', '\u65fe', '\u9034', '\u5472', '\u5306', + '\u51d1', '\u7c97', '\u6c46', '\u5d14', '\u90a8', '\u6413', + '\u5491', '\u5446', '\u4e39', '\u5f53', '\u5200', '\u561a', + '\u6265', '\u706f', '\u6c10', '\u55f2', '\u7538', '\u5201', + '\u7239', '\u4e01', '\u4e1f', '\u4e1c', '\u543a', '\u53be', + '\u8011', '\u8968', '\u5428', '\u591a', '\u59b8', '\u8bf6', + '\u5940', '\u97a5', '\u513f', '\u53d1', '\u5e06', '\u531a', + '\u98de', '\u5206', '\u4e30', '\u8985', '\u4ecf', '\u7d11', + '\u4f15', '\u65ee', '\u4f85', '\u7518', '\u5188', '\u768b', + '\u6208', '\u7ed9', '\u6839', '\u522f', '\u5de5', '\u52fe', + '\u4f30', '\u74dc', '\u4e56', '\u5173', '\u5149', '\u5f52', + '\u4e28', '\u5459', '\u54c8', '\u548d', '\u4f44', '\u592f', + '\u8320', '\u8bc3', '\u9ed2', '\u62eb', '\u4ea8', '\u5677', + '\u53ff', '\u9f41', '\u4e6f', '\u82b1', '\u6000', '\u72bf', + '\u5ddf', '\u7070', '\u660f', '\u5419', '\u4e0c', '\u52a0', + '\u620b', '\u6c5f', '\u827d', '\u9636', '\u5dfe', '\u5755', + '\u5182', '\u4e29', '\u51e5', '\u59e2', '\u5658', '\u519b', + '\u5494', '\u5f00', '\u520a', '\u5ffc', '\u5c3b', '\u533c', + '\u808e', '\u52a5', '\u7a7a', '\u62a0', '\u625d', '\u5938', + '\u84af', '\u5bbd', '\u5321', '\u4e8f', '\u5764', '\u6269', + '\u5783', '\u6765', '\u5170', '\u5577', '\u635e', '\u808b', + '\u52d2', '\u5d1a', '\u5215', '\u4fe9', '\u5941', '\u826f', + '\u64a9', '\u5217', '\u62ce', '\u5222', '\u6e9c', '\u56d6', + '\u9f99', '\u779c', '\u565c', '\u5a08', '\u7567', '\u62a1', + '\u7f57', '\u5463', '\u5988', '\u57cb', '\u5ada', '\u7264', + '\u732b', '\u4e48', '\u5445', '\u95e8', '\u753f', '\u54aa', + '\u5b80', '\u55b5', '\u4e5c', '\u6c11', '\u540d', '\u8c2c', + '\u6478', '\u54de', '\u6bea', '\u55ef', '\u62cf', '\u8149', + '\u56e1', '\u56d4', '\u5b6c', '\u7592', '\u5a1e', '\u6041', + '\u80fd', '\u59ae', '\u62c8', '\u5b22', '\u9e1f', '\u634f', + '\u56dc', '\u5b81', '\u599e', '\u519c', '\u7fba', '\u5974', + '\u597b', '\u759f', '\u9ec1', '\u90cd', '\u5594', '\u8bb4', + '\u5991', '\u62cd', '\u7705', '\u4e53', '\u629b', '\u5478', + '\u55b7', '\u5309', '\u4e15', '\u56e8', '\u527d', '\u6c15', + '\u59d8', '\u4e52', '\u948b', '\u5256', '\u4ec6', '\u4e03', + '\u6390', '\u5343', '\u545b', '\u6084', '\u767f', '\u4eb2', + '\u72c5', '\u828e', '\u4e18', '\u533a', '\u5cd1', '\u7f3a', + '\u590b', '\u5465', '\u7a63', '\u5a06', '\u60f9', '\u4eba', + '\u6254', '\u65e5', '\u8338', '\u53b9', '\u909a', '\u633c', + '\u5827', '\u5a51', '\u77a4', '\u637c', '\u4ee8', '\u6be2', + '\u4e09', '\u6852', '\u63bb', '\u95aa', '\u68ee', '\u50e7', + '\u6740', '\u7b5b', '\u5c71', '\u4f24', '\u5f30', '\u5962', + '\u7533', '\u8398', '\u6552', '\u5347', '\u5c38', '\u53ce', + '\u4e66', '\u5237', '\u8870', '\u95e9', '\u53cc', '\u8c01', + '\u542e', '\u8bf4', '\u53b6', '\u5fea', '\u635c', '\u82cf', + '\u72fb', '\u590a', '\u5b59', '\u5506', '\u4ed6', '\u56fc', + '\u574d', '\u6c64', '\u5932', '\u5fd1', '\u71a5', '\u5254', + '\u5929', '\u65eb', '\u5e16', '\u5385', '\u56f2', '\u5077', + '\u51f8', '\u6e4d', '\u63a8', '\u541e', '\u4e47', '\u7a75', + '\u6b6a', '\u5f2f', '\u5c23', '\u5371', '\u6637', '\u7fc1', + '\u631d', '\u4e4c', '\u5915', '\u8672', '\u4eda', '\u4e61', + '\u7071', '\u4e9b', '\u5fc3', '\u661f', '\u51f6', '\u4f11', + '\u5401', '\u5405', '\u524a', '\u5743', '\u4e2b', '\u6079', + '\u592e', '\u5e7a', '\u503b', '\u4e00', '\u56d9', '\u5e94', + '\u54df', '\u4f63', '\u4f18', '\u625c', '\u56e6', '\u66f0', + '\u6655', '\u7b60', '\u7b7c', '\u5e00', '\u707d', '\u5142', + '\u5328', '\u50ae', '\u5219', '\u8d3c', '\u600e', '\u5897', + '\u624e', '\u635a', '\u6cbe', '\u5f20', '\u957f', '\u9577', + '\u4f4b', '\u8707', '\u8d1e', '\u4e89', '\u4e4b', '\u5cd9', + '\u5ea2', '\u4e2d', '\u5dde', '\u6731', '\u6293', '\u62fd', + '\u4e13', '\u5986', '\u96b9', '\u5b92', '\u5353', '\u4e72', + '\u5b97', '\u90b9', '\u79df', '\u94bb', '\u539c', '\u5c0a', + '\u6628', '\u5159', '\u9fc3', '\u9fc4', }; + + /** + * Pinyin array. + * + * Each pinyin is corresponding to unihans of same + * offset in the unihans array. + */ + public static final byte[][] PINYINS = { + { 65, 0, 0, 0, 0, 0}, { 65, 73, 0, 0, 0, 0}, + { 65, 78, 0, 0, 0, 0}, { 65, 78, 71, 0, 0, 0}, + { 65, 79, 0, 0, 0, 0}, { 66, 65, 0, 0, 0, 0}, + { 66, 65, 73, 0, 0, 0}, { 66, 65, 78, 0, 0, 0}, + { 66, 65, 78, 71, 0, 0}, { 66, 65, 79, 0, 0, 0}, + { 66, 69, 73, 0, 0, 0}, { 66, 69, 78, 0, 0, 0}, + { 66, 69, 78, 71, 0, 0}, { 66, 73, 0, 0, 0, 0}, + { 66, 73, 65, 78, 0, 0}, { 66, 73, 65, 79, 0, 0}, + { 66, 73, 69, 0, 0, 0}, { 66, 73, 78, 0, 0, 0}, + { 66, 73, 78, 71, 0, 0}, { 66, 79, 0, 0, 0, 0}, + { 66, 85, 0, 0, 0, 0}, { 67, 65, 0, 0, 0, 0}, + { 67, 65, 73, 0, 0, 0}, { 67, 65, 78, 0, 0, 0}, + { 67, 65, 78, 71, 0, 0}, { 67, 65, 79, 0, 0, 0}, + { 67, 69, 0, 0, 0, 0}, { 67, 69, 78, 0, 0, 0}, + { 67, 69, 78, 71, 0, 0}, { 90, 69, 78, 71, 0, 0}, + { 67, 69, 78, 71, 0, 0}, { 67, 72, 65, 0, 0, 0}, + { 67, 72, 65, 73, 0, 0}, { 67, 72, 65, 78, 0, 0}, + { 67, 72, 65, 78, 71, 0}, { 67, 72, 65, 79, 0, 0}, + { 67, 72, 69, 0, 0, 0}, { 67, 72, 69, 78, 0, 0}, + { 83, 72, 69, 78, 0, 0}, { 67, 72, 69, 78, 0, 0}, + { 67, 72, 69, 78, 71, 0}, { 67, 72, 73, 0, 0, 0}, + { 67, 72, 79, 78, 71, 0}, { 67, 72, 79, 85, 0, 0}, + { 67, 72, 85, 0, 0, 0}, { 67, 72, 85, 65, 0, 0}, + { 67, 72, 85, 65, 73, 0}, { 67, 72, 85, 65, 78, 0}, + { 67, 72, 85, 65, 78, 71}, { 67, 72, 85, 73, 0, 0}, + { 67, 72, 85, 78, 0, 0}, { 67, 72, 85, 79, 0, 0}, + { 67, 73, 0, 0, 0, 0}, { 67, 79, 78, 71, 0, 0}, + { 67, 79, 85, 0, 0, 0}, { 67, 85, 0, 0, 0, 0}, + { 67, 85, 65, 78, 0, 0}, { 67, 85, 73, 0, 0, 0}, + { 67, 85, 78, 0, 0, 0}, { 67, 85, 79, 0, 0, 0}, + { 68, 65, 0, 0, 0, 0}, { 68, 65, 73, 0, 0, 0}, + { 68, 65, 78, 0, 0, 0}, { 68, 65, 78, 71, 0, 0}, + { 68, 65, 79, 0, 0, 0}, { 68, 69, 0, 0, 0, 0}, + { 68, 69, 78, 0, 0, 0}, { 68, 69, 78, 71, 0, 0}, + { 68, 73, 0, 0, 0, 0}, { 68, 73, 65, 0, 0, 0}, + { 68, 73, 65, 78, 0, 0}, { 68, 73, 65, 79, 0, 0}, + { 68, 73, 69, 0, 0, 0}, { 68, 73, 78, 71, 0, 0}, + { 68, 73, 85, 0, 0, 0}, { 68, 79, 78, 71, 0, 0}, + { 68, 79, 85, 0, 0, 0}, { 68, 85, 0, 0, 0, 0}, + { 68, 85, 65, 78, 0, 0}, { 68, 85, 73, 0, 0, 0}, + { 68, 85, 78, 0, 0, 0}, { 68, 85, 79, 0, 0, 0}, + { 69, 0, 0, 0, 0, 0}, { 69, 73, 0, 0, 0, 0}, + { 69, 78, 0, 0, 0, 0}, { 69, 78, 71, 0, 0, 0}, + { 69, 82, 0, 0, 0, 0}, { 70, 65, 0, 0, 0, 0}, + { 70, 65, 78, 0, 0, 0}, { 70, 65, 78, 71, 0, 0}, + { 70, 69, 73, 0, 0, 0}, { 70, 69, 78, 0, 0, 0}, + { 70, 69, 78, 71, 0, 0}, { 70, 73, 65, 79, 0, 0}, + { 70, 79, 0, 0, 0, 0}, { 70, 79, 85, 0, 0, 0}, + { 70, 85, 0, 0, 0, 0}, { 71, 65, 0, 0, 0, 0}, + { 71, 65, 73, 0, 0, 0}, { 71, 65, 78, 0, 0, 0}, + { 71, 65, 78, 71, 0, 0}, { 71, 65, 79, 0, 0, 0}, + { 71, 69, 0, 0, 0, 0}, { 71, 69, 73, 0, 0, 0}, + { 71, 69, 78, 0, 0, 0}, { 71, 69, 78, 71, 0, 0}, + { 71, 79, 78, 71, 0, 0}, { 71, 79, 85, 0, 0, 0}, + { 71, 85, 0, 0, 0, 0}, { 71, 85, 65, 0, 0, 0}, + { 71, 85, 65, 73, 0, 0}, { 71, 85, 65, 78, 0, 0}, + { 71, 85, 65, 78, 71, 0}, { 71, 85, 73, 0, 0, 0}, + { 71, 85, 78, 0, 0, 0}, { 71, 85, 79, 0, 0, 0}, + { 72, 65, 0, 0, 0, 0}, { 72, 65, 73, 0, 0, 0}, + { 72, 65, 78, 0, 0, 0}, { 72, 65, 78, 71, 0, 0}, + { 72, 65, 79, 0, 0, 0}, { 72, 69, 0, 0, 0, 0}, + { 72, 69, 73, 0, 0, 0}, { 72, 69, 78, 0, 0, 0}, + { 72, 69, 78, 71, 0, 0}, { 72, 77, 0, 0, 0, 0}, + { 72, 79, 78, 71, 0, 0}, { 72, 79, 85, 0, 0, 0}, + { 72, 85, 0, 0, 0, 0}, { 72, 85, 65, 0, 0, 0}, + { 72, 85, 65, 73, 0, 0}, { 72, 85, 65, 78, 0, 0}, + { 72, 85, 65, 78, 71, 0}, { 72, 85, 73, 0, 0, 0}, + { 72, 85, 78, 0, 0, 0}, { 72, 85, 79, 0, 0, 0}, + { 74, 73, 0, 0, 0, 0}, { 74, 73, 65, 0, 0, 0}, + { 74, 73, 65, 78, 0, 0}, { 74, 73, 65, 78, 71, 0}, + { 74, 73, 65, 79, 0, 0}, { 74, 73, 69, 0, 0, 0}, + { 74, 73, 78, 0, 0, 0}, { 74, 73, 78, 71, 0, 0}, + { 74, 73, 79, 78, 71, 0}, { 74, 73, 85, 0, 0, 0}, + { 74, 85, 0, 0, 0, 0}, { 74, 85, 65, 78, 0, 0}, + { 74, 85, 69, 0, 0, 0}, { 74, 85, 78, 0, 0, 0}, + { 75, 65, 0, 0, 0, 0}, { 75, 65, 73, 0, 0, 0}, + { 75, 65, 78, 0, 0, 0}, { 75, 65, 78, 71, 0, 0}, + { 75, 65, 79, 0, 0, 0}, { 75, 69, 0, 0, 0, 0}, + { 75, 69, 78, 0, 0, 0}, { 75, 69, 78, 71, 0, 0}, + { 75, 79, 78, 71, 0, 0}, { 75, 79, 85, 0, 0, 0}, + { 75, 85, 0, 0, 0, 0}, { 75, 85, 65, 0, 0, 0}, + { 75, 85, 65, 73, 0, 0}, { 75, 85, 65, 78, 0, 0}, + { 75, 85, 65, 78, 71, 0}, { 75, 85, 73, 0, 0, 0}, + { 75, 85, 78, 0, 0, 0}, { 75, 85, 79, 0, 0, 0}, + { 76, 65, 0, 0, 0, 0}, { 76, 65, 73, 0, 0, 0}, + { 76, 65, 78, 0, 0, 0}, { 76, 65, 78, 71, 0, 0}, + { 76, 65, 79, 0, 0, 0}, { 76, 69, 0, 0, 0, 0}, + { 76, 69, 73, 0, 0, 0}, { 76, 69, 78, 71, 0, 0}, + { 76, 73, 0, 0, 0, 0}, { 76, 73, 65, 0, 0, 0}, + { 76, 73, 65, 78, 0, 0}, { 76, 73, 65, 78, 71, 0}, + { 76, 73, 65, 79, 0, 0}, { 76, 73, 69, 0, 0, 0}, + { 76, 73, 78, 0, 0, 0}, { 76, 73, 78, 71, 0, 0}, + { 76, 73, 85, 0, 0, 0}, { 76, 79, 0, 0, 0, 0}, + { 76, 79, 78, 71, 0, 0}, { 76, 79, 85, 0, 0, 0}, + { 76, 85, 0, 0, 0, 0}, { 76, 85, 65, 78, 0, 0}, + { 76, 85, 69, 0, 0, 0}, { 76, 85, 78, 0, 0, 0}, + { 76, 85, 79, 0, 0, 0}, { 77, 0, 0, 0, 0, 0}, + { 77, 65, 0, 0, 0, 0}, { 77, 65, 73, 0, 0, 0}, + { 77, 65, 78, 0, 0, 0}, { 77, 65, 78, 71, 0, 0}, + { 77, 65, 79, 0, 0, 0}, { 77, 69, 0, 0, 0, 0}, + { 77, 69, 73, 0, 0, 0}, { 77, 69, 78, 0, 0, 0}, + { 77, 69, 78, 71, 0, 0}, { 77, 73, 0, 0, 0, 0}, + { 77, 73, 65, 78, 0, 0}, { 77, 73, 65, 79, 0, 0}, + { 77, 73, 69, 0, 0, 0}, { 77, 73, 78, 0, 0, 0}, + { 77, 73, 78, 71, 0, 0}, { 77, 73, 85, 0, 0, 0}, + { 77, 79, 0, 0, 0, 0}, { 77, 79, 85, 0, 0, 0}, + { 77, 85, 0, 0, 0, 0}, { 78, 0, 0, 0, 0, 0}, + { 78, 65, 0, 0, 0, 0}, { 78, 65, 73, 0, 0, 0}, + { 78, 65, 78, 0, 0, 0}, { 78, 65, 78, 71, 0, 0}, + { 78, 65, 79, 0, 0, 0}, { 78, 69, 0, 0, 0, 0}, + { 78, 69, 73, 0, 0, 0}, { 78, 69, 78, 0, 0, 0}, + { 78, 69, 78, 71, 0, 0}, { 78, 73, 0, 0, 0, 0}, + { 78, 73, 65, 78, 0, 0}, { 78, 73, 65, 78, 71, 0}, + { 78, 73, 65, 79, 0, 0}, { 78, 73, 69, 0, 0, 0}, + { 78, 73, 78, 0, 0, 0}, { 78, 73, 78, 71, 0, 0}, + { 78, 73, 85, 0, 0, 0}, { 78, 79, 78, 71, 0, 0}, + { 78, 79, 85, 0, 0, 0}, { 78, 85, 0, 0, 0, 0}, + { 78, 85, 65, 78, 0, 0}, { 78, 85, 69, 0, 0, 0}, + { 78, 85, 78, 0, 0, 0}, { 78, 85, 79, 0, 0, 0}, + { 79, 0, 0, 0, 0, 0}, { 79, 85, 0, 0, 0, 0}, + { 80, 65, 0, 0, 0, 0}, { 80, 65, 73, 0, 0, 0}, + { 80, 65, 78, 0, 0, 0}, { 80, 65, 78, 71, 0, 0}, + { 80, 65, 79, 0, 0, 0}, { 80, 69, 73, 0, 0, 0}, + { 80, 69, 78, 0, 0, 0}, { 80, 69, 78, 71, 0, 0}, + { 80, 73, 0, 0, 0, 0}, { 80, 73, 65, 78, 0, 0}, + { 80, 73, 65, 79, 0, 0}, { 80, 73, 69, 0, 0, 0}, + { 80, 73, 78, 0, 0, 0}, { 80, 73, 78, 71, 0, 0}, + { 80, 79, 0, 0, 0, 0}, { 80, 79, 85, 0, 0, 0}, + { 80, 85, 0, 0, 0, 0}, { 81, 73, 0, 0, 0, 0}, + { 81, 73, 65, 0, 0, 0}, { 81, 73, 65, 78, 0, 0}, + { 81, 73, 65, 78, 71, 0}, { 81, 73, 65, 79, 0, 0}, + { 81, 73, 69, 0, 0, 0}, { 81, 73, 78, 0, 0, 0}, + { 81, 73, 78, 71, 0, 0}, { 81, 73, 79, 78, 71, 0}, + { 81, 73, 85, 0, 0, 0}, { 81, 85, 0, 0, 0, 0}, + { 81, 85, 65, 78, 0, 0}, { 81, 85, 69, 0, 0, 0}, + { 81, 85, 78, 0, 0, 0}, { 82, 65, 78, 0, 0, 0}, + { 82, 65, 78, 71, 0, 0}, { 82, 65, 79, 0, 0, 0}, + { 82, 69, 0, 0, 0, 0}, { 82, 69, 78, 0, 0, 0}, + { 82, 69, 78, 71, 0, 0}, { 82, 73, 0, 0, 0, 0}, + { 82, 79, 78, 71, 0, 0}, { 82, 79, 85, 0, 0, 0}, + { 82, 85, 0, 0, 0, 0}, { 82, 85, 65, 0, 0, 0}, + { 82, 85, 65, 78, 0, 0}, { 82, 85, 73, 0, 0, 0}, + { 82, 85, 78, 0, 0, 0}, { 82, 85, 79, 0, 0, 0}, + { 83, 65, 0, 0, 0, 0}, { 83, 65, 73, 0, 0, 0}, + { 83, 65, 78, 0, 0, 0}, { 83, 65, 78, 71, 0, 0}, + { 83, 65, 79, 0, 0, 0}, { 83, 69, 0, 0, 0, 0}, + { 83, 69, 78, 0, 0, 0}, { 83, 69, 78, 71, 0, 0}, + { 83, 72, 65, 0, 0, 0}, { 83, 72, 65, 73, 0, 0}, + { 83, 72, 65, 78, 0, 0}, { 83, 72, 65, 78, 71, 0}, + { 83, 72, 65, 79, 0, 0}, { 83, 72, 69, 0, 0, 0}, + { 83, 72, 69, 78, 0, 0}, { 88, 73, 78, 0, 0, 0}, + { 83, 72, 69, 78, 0, 0}, { 83, 72, 69, 78, 71, 0}, + { 83, 72, 73, 0, 0, 0}, { 83, 72, 79, 85, 0, 0}, + { 83, 72, 85, 0, 0, 0}, { 83, 72, 85, 65, 0, 0}, + { 83, 72, 85, 65, 73, 0}, { 83, 72, 85, 65, 78, 0}, + { 83, 72, 85, 65, 78, 71}, { 83, 72, 85, 73, 0, 0}, + { 83, 72, 85, 78, 0, 0}, { 83, 72, 85, 79, 0, 0}, + { 83, 73, 0, 0, 0, 0}, { 83, 79, 78, 71, 0, 0}, + { 83, 79, 85, 0, 0, 0}, { 83, 85, 0, 0, 0, 0}, + { 83, 85, 65, 78, 0, 0}, { 83, 85, 73, 0, 0, 0}, + { 83, 85, 78, 0, 0, 0}, { 83, 85, 79, 0, 0, 0}, + { 84, 65, 0, 0, 0, 0}, { 84, 65, 73, 0, 0, 0}, + { 84, 65, 78, 0, 0, 0}, { 84, 65, 78, 71, 0, 0}, + { 84, 65, 79, 0, 0, 0}, { 84, 69, 0, 0, 0, 0}, + { 84, 69, 78, 71, 0, 0}, { 84, 73, 0, 0, 0, 0}, + { 84, 73, 65, 78, 0, 0}, { 84, 73, 65, 79, 0, 0}, + { 84, 73, 69, 0, 0, 0}, { 84, 73, 78, 71, 0, 0}, + { 84, 79, 78, 71, 0, 0}, { 84, 79, 85, 0, 0, 0}, + { 84, 85, 0, 0, 0, 0}, { 84, 85, 65, 78, 0, 0}, + { 84, 85, 73, 0, 0, 0}, { 84, 85, 78, 0, 0, 0}, + { 84, 85, 79, 0, 0, 0}, { 87, 65, 0, 0, 0, 0}, + { 87, 65, 73, 0, 0, 0}, { 87, 65, 78, 0, 0, 0}, + { 87, 65, 78, 71, 0, 0}, { 87, 69, 73, 0, 0, 0}, + { 87, 69, 78, 0, 0, 0}, { 87, 69, 78, 71, 0, 0}, + { 87, 79, 0, 0, 0, 0}, { 87, 85, 0, 0, 0, 0}, + { 88, 73, 0, 0, 0, 0}, { 88, 73, 65, 0, 0, 0}, + { 88, 73, 65, 78, 0, 0}, { 88, 73, 65, 78, 71, 0}, + { 88, 73, 65, 79, 0, 0}, { 88, 73, 69, 0, 0, 0}, + { 88, 73, 78, 0, 0, 0}, { 88, 73, 78, 71, 0, 0}, + { 88, 73, 79, 78, 71, 0}, { 88, 73, 85, 0, 0, 0}, + { 88, 85, 0, 0, 0, 0}, { 88, 85, 65, 78, 0, 0}, + { 88, 85, 69, 0, 0, 0}, { 88, 85, 78, 0, 0, 0}, + { 89, 65, 0, 0, 0, 0}, { 89, 65, 78, 0, 0, 0}, + { 89, 65, 78, 71, 0, 0}, { 89, 65, 79, 0, 0, 0}, + { 89, 69, 0, 0, 0, 0}, { 89, 73, 0, 0, 0, 0}, + { 89, 73, 78, 0, 0, 0}, { 89, 73, 78, 71, 0, 0}, + { 89, 79, 0, 0, 0, 0}, { 89, 79, 78, 71, 0, 0}, + { 89, 79, 85, 0, 0, 0}, { 89, 85, 0, 0, 0, 0}, + { 89, 85, 65, 78, 0, 0}, { 89, 85, 69, 0, 0, 0}, + { 89, 85, 78, 0, 0, 0}, { 74, 85, 78, 0, 0, 0}, + { 89, 85, 78, 0, 0, 0}, { 90, 65, 0, 0, 0, 0}, + { 90, 65, 73, 0, 0, 0}, { 90, 65, 78, 0, 0, 0}, + { 90, 65, 78, 71, 0, 0}, { 90, 65, 79, 0, 0, 0}, + { 90, 69, 0, 0, 0, 0}, { 90, 69, 73, 0, 0, 0}, + { 90, 69, 78, 0, 0, 0}, { 90, 69, 78, 71, 0, 0}, + { 90, 72, 65, 0, 0, 0}, { 90, 72, 65, 73, 0, 0}, + { 90, 72, 65, 78, 0, 0}, { 90, 72, 65, 78, 71, 0}, + { 67, 72, 65, 78, 71, 0}, { 90, 72, 65, 78, 71, 0}, + { 90, 72, 65, 79, 0, 0}, { 90, 72, 69, 0, 0, 0}, + { 90, 72, 69, 78, 0, 0}, { 90, 72, 69, 78, 71, 0}, + { 90, 72, 73, 0, 0, 0}, { 83, 72, 73, 0, 0, 0}, + { 90, 72, 73, 0, 0, 0}, { 90, 72, 79, 78, 71, 0}, + { 90, 72, 79, 85, 0, 0}, { 90, 72, 85, 0, 0, 0}, + { 90, 72, 85, 65, 0, 0}, { 90, 72, 85, 65, 73, 0}, + { 90, 72, 85, 65, 78, 0}, { 90, 72, 85, 65, 78, 71}, + { 90, 72, 85, 73, 0, 0}, { 90, 72, 85, 78, 0, 0}, + { 90, 72, 85, 79, 0, 0}, { 90, 73, 0, 0, 0, 0}, + { 90, 79, 78, 71, 0, 0}, { 90, 79, 85, 0, 0, 0}, + { 90, 85, 0, 0, 0, 0}, { 90, 85, 65, 78, 0, 0}, + { 90, 85, 73, 0, 0, 0}, { 90, 85, 78, 0, 0, 0}, + { 90, 85, 79, 0, 0, 0}, { 0, 0, 0, 0, 0, 0}, + { 83, 72, 65, 78, 0, 0}, { 0, 0, 0, 0, 0, 0}, }; + + /** First and last Chinese character with known Pinyin according to zh collation */ + private static final String FIRST_PINYIN_UNIHAN = "\u963F"; + private static final String LAST_PINYIN_UNIHAN = "\u9FFF"; + +// private static final Collator COLLATOR = Collator.getInstance(Locale.CHINA); + private static final Collator COLLATOR = Collator.getInstance(Locale.CHINESE); + + private static HanziToPinyin3 sInstance; + private final boolean mHasChinaCollator; + + public static class Token { + /** + * Separator between target string for each source char + */ + public static final String SEPARATOR = " "; + + public static final int LATIN = 1; + public static final int PINYIN = 2; + public static final int UNKNOWN = 3; + + public Token() { + } + + public Token(int type, String source, String target) { + this.type = type; + this.source = source; + this.target = target; + } + + /** + * Type of this token, ASCII, PINYIN or UNKNOWN. + */ + public int type; + /** + * Original string before translation. + */ + public String source; + /** + * Translated string of source. For Han, target is corresponding Pinyin. Otherwise target is + * original string in source. + */ + public String target; + } + + protected HanziToPinyin3(boolean hasChinaCollator) { + mHasChinaCollator = hasChinaCollator; + } + + public static HanziToPinyin3 getInstance() { + synchronized (HanziToPinyin3.class) { + if (sInstance != null) { + return sInstance; + } + // Check if zh_CN collation data is available + final Locale locale[] = Collator.getAvailableLocales(); + for (int i = 0; i < locale.length; i++) { + if (locale[i].equals(Locale.CHINESE)) { + // Do self validation just once. + if (DEBUG) { + Log.d(TAG, "Self validation. Result: " + doSelfValidation()); + } + sInstance = new HanziToPinyin3(true); + return sInstance; + } + } + Log.w(TAG, "There is no Chinese collator, HanziToPinyin is disabled"); + sInstance = new HanziToPinyin3(false); + return sInstance; + } + } + + /** + * Validate if our internal table has some wrong value. + * + * @return true when the table looks correct. + */ + private static boolean doSelfValidation() { + char lastChar = UNIHANS[0]; + String lastString = Character.toString(lastChar); + for (char c : UNIHANS) { + if (lastChar == c) { + continue; + } + final String curString = Character.toString(c); + int cmp = COLLATOR.compare(lastString, curString); + if (cmp >= 0) { + Log.e(TAG, "Internal error in Unihan table. " + "The last string \"" + lastString + + "\" is greater than current string \"" + curString + "\"."); + return false; + } + lastString = curString; + } + return true; + } + + private Token getToken(char character) { + Token token = new Token(); + final String letter = Character.toString(character); + token.source = letter; + int offset = -1; + int cmp; + if (character < 256) { + token.type = Token.LATIN; + token.target = letter; + return token; + } else { + cmp = COLLATOR.compare(letter, FIRST_PINYIN_UNIHAN); + if (cmp < 0) { + token.type = Token.UNKNOWN; + token.target = letter; + return token; + } else if (cmp == 0) { + token.type = Token.PINYIN; + offset = 0; + } else { + cmp = COLLATOR.compare(letter, LAST_PINYIN_UNIHAN); + if (cmp > 0) { + token.type = Token.UNKNOWN; + token.target = letter; + return token; + } else if (cmp == 0) { + token.type = Token.PINYIN; + offset = UNIHANS.length - 1; + } + } + } + + token.type = Token.PINYIN; + if (offset < 0) { + int begin = 0; + int end = UNIHANS.length - 1; + while (begin <= end) { + offset = (begin + end) / 2; + final String unihan = Character.toString(UNIHANS[offset]); + cmp = COLLATOR.compare(letter, unihan); + if (cmp == 0) { + break; + } else if (cmp > 0) { + begin = offset + 1; + } else { + end = offset - 1; + } + } + } + if (cmp < 0) { + offset--; + } + StringBuilder pinyin = new StringBuilder(); + for (int j = 0; j < PINYINS[offset].length && PINYINS[offset][j] != 0; j++) { + pinyin.append((char) PINYINS[offset][j]); + } + token.target = pinyin.toString(); + if (TextUtils.isEmpty(token.target)) { + token.type = Token.UNKNOWN; + token.target = token.source; + } + return token; + } + + /** + * Convert the input to a array of tokens. The sequence of ASCII or Unknown characters without + * space will be put into a Token, One Hanzi character which has pinyin will be treated as a + * Token. If these is no China collator, the empty token array is returned. + */ + public ArrayList get(final String input) { + ArrayList tokens = new ArrayList(); + if (!mHasChinaCollator || TextUtils.isEmpty(input)) { + // return empty tokens. + return tokens; + } + final int inputLength = input.length(); + final StringBuilder sb = new StringBuilder(); + int tokenType = Token.LATIN; + //Users/ericxu1983/Downloads/ChineseToPinyin-master/two/ChineseToPinyin/src/com/liucanwen/chinesetopinyin/pinyin/PinYin.java/ Go through the input, create a new token when + // a. Token type changed + // b. Get the Pinyin of current charater. + // c. current character is space. + for (int i = 0; i < inputLength; i++) { + final char character = input.charAt(i); + if (character == ' ') { + if (sb.length() > 0) { + addToken(sb, tokens, tokenType); + } + } else if (character < 256) { + if (tokenType != Token.LATIN && sb.length() > 0) { + addToken(sb, tokens, tokenType); + } + tokenType = Token.LATIN; + sb.append(character); + } else { + Token t = getToken(character); + if (t.type == Token.PINYIN) { + if (sb.length() > 0) { + addToken(sb, tokens, tokenType); + } + tokens.add(t); + tokenType = Token.PINYIN; + } else { + if (tokenType != t.type && sb.length() > 0) { + addToken(sb, tokens, tokenType); + } + tokenType = t.type; + sb.append(character); + } + } + } + if (sb.length() > 0) { + addToken(sb, tokens, tokenType); + } + return tokens; + } + + private void addToken( + final StringBuilder sb, final ArrayList tokens, final int tokenType) { + String str = sb.toString(); + tokens.add(new Token(tokenType, str, str)); + sb.setLength(0); + } +} diff --git a/android/app/src/main/java/com/mogujie/tt/utils/pinyin/PinYin.java b/android/app/src/main/java/com/mogujie/tt/utils/pinyin/PinYin.java new file mode 100644 index 000000000..b504171f4 --- /dev/null +++ b/android/app/src/main/java/com/mogujie/tt/utils/pinyin/PinYin.java @@ -0,0 +1,77 @@ +package com.mogujie.tt.utils.pinyin; + +import com.mogujie.tt.utils.pinyin.HanziToPinyin3.Token; + +import java.util.ArrayList; +import java.util.List; + +public class PinYin { + public static class PinYinElement { + + // 开源TT ==> kaiyuantt + public String pinyin; + + //every token's pinyin, so "你xx好" -> ["NI", "X", "Y", "HAO"] + public List tokenPinyinList = new ArrayList(); + + //every first char bonds together for all token's pinyin list + public String tokenFirstChars = ""; + + + @Override + public String toString() { + StringBuilder part1 = new StringBuilder("PinYinElement [pinyin=" + pinyin + ", firstChars=" + tokenFirstChars + "]"); + StringBuilder part2 = new StringBuilder("tokenPinyinList:"); + for (String tokenPinyin : tokenPinyinList) { + part2.append(tokenPinyin).append(","); + } + + return part1.append(part2).toString(); + } + + //@YM getPinYin 调用的入口太多,暂时临时解决 + public void clear(){ + tokenFirstChars = ""; + tokenPinyinList.clear(); + pinyin = null; + } + } + + // 汉字返回拼音,字母原样返回,都转换为小写 + // 函数的名称也是存在问题 + + public static void getPinYin(String input,PinYinElement pinyinElement) { + ArrayList tokens = HanziToPinyin3.getInstance().get(input); + + StringBuilder sb = new StringBuilder(); + pinyinElement.clear(); + if (tokens != null && tokens.size() > 0) { + for (Token token : tokens) { + + if (Token.PINYIN == token.type) { + sb.append(token.target); + pinyinElement.tokenPinyinList.add(token.target); + pinyinElement.tokenFirstChars += token.target.substring(0, 1); + } else { + //你xyz好 -> token.source = xyz, so we should separate every original character here + sb.append(token.source); + for (int i = 0; i < token.source.length(); ++i) { + String childString = token.source.substring(i, i + 1).toUpperCase(); + pinyinElement.tokenPinyinList.add(childString); + pinyinElement.tokenFirstChars += childString; + } + } + } + } + + String ret = sb.toString().toUpperCase(); + if (!ret.isEmpty()) { + int firstChar = ret.charAt(0); + if (!(firstChar >= 'A' && firstChar <= 'Z')) { + ret = "#" + ret; + } + } + + pinyinElement.pinyin = ret; + } +} diff --git a/android/app/src/main/jni/Android.mk b/android/app/src/main/jni/Android.mk new file mode 100644 index 000000000..42287cae4 --- /dev/null +++ b/android/app/src/main/jni/Android.mk @@ -0,0 +1,53 @@ +LOCAL_PATH := $(call my-dir) + +include $(CLEAR_VARS) + +LOCAL_MODULE := libspeex +LOCAL_CFLAGS = -DFIXED_POINT -DUSE_KISS_FFT -DEXPORT="" -UHAVE_CONFIG_H +LOCAL_C_INCLUDES := $(LOCAL_PATH)/include + +LOCAL_SRC_FILES := speex_jni.cpp \ +./libspeex/bits.c \ +./libspeex/buffer.c \ +./libspeex/cb_search.c \ +./libspeex/exc_10_16_table.c \ +./libspeex/exc_10_32_table.c \ +./libspeex/exc_20_32_table.c \ +./libspeex/exc_5_256_table.c \ +./libspeex/exc_5_64_table.c \ +./libspeex/exc_8_128_table.c \ +./libspeex/fftwrap.c \ +./libspeex/filterbank.c \ +./libspeex/filters.c \ +./libspeex/gain_table.c \ +./libspeex/gain_table_lbr.c \ +./libspeex/hexc_10_32_table.c \ +./libspeex/hexc_table.c \ +./libspeex/high_lsp_tables.c \ +./libspeex/jitter.c \ +./libspeex/kiss_fft.c \ +./libspeex/kiss_fftr.c \ +./libspeex/lpc.c \ +./libspeex/lsp.c \ +./libspeex/lsp_tables_nb.c \ +./libspeex/ltp.c \ +./libspeex/mdf.c \ +./libspeex/modes.c \ +./libspeex/modes_wb.c \ +./libspeex/nb_celp.c \ +./libspeex/preprocess.c \ +./libspeex/quant_lsp.c \ +./libspeex/resample.c \ +./libspeex/sb_celp.c \ +./libspeex/scal.c \ +./libspeex/smallft.c \ +./libspeex/speex.c \ +./libspeex/speex_callbacks.c \ +./libspeex/speex_header.c \ +./libspeex/stereo.c \ +./libspeex/vbr.c \ +./libspeex/vq.c \ +./libspeex/window.c + +include $(BUILD_SHARED_LIBRARY) + diff --git a/android/app/src/main/jni/Application.mk b/android/app/src/main/jni/Application.mk new file mode 100644 index 000000000..fd148b149 --- /dev/null +++ b/android/app/src/main/jni/Application.mk @@ -0,0 +1,2 @@ +APP_ABI := armeabi armeabi-v7a +APP_PLATFORM := android-7 \ No newline at end of file diff --git a/android/app/src/main/jni/include/Makefile.am b/android/app/src/main/jni/include/Makefile.am new file mode 100644 index 000000000..09613b63a --- /dev/null +++ b/android/app/src/main/jni/include/Makefile.am @@ -0,0 +1,2 @@ + +SUBDIRS = speex diff --git a/android/app/src/main/jni/include/Makefile.in b/android/app/src/main/jni/include/Makefile.in new file mode 100644 index 000000000..3663878ae --- /dev/null +++ b/android/app/src/main/jni/include/Makefile.in @@ -0,0 +1,481 @@ +# Makefile.in generated by automake 1.8.5 from Makefile.am. +# @configure_input@ + +# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, +# 2003, 2004 Free Software Foundation, Inc. +# This Makefile.in is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY, to the extent permitted by law; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. + +@SET_MAKE@ +srcdir = @srcdir@ +top_srcdir = @top_srcdir@ +VPATH = @srcdir@ +pkgdatadir = $(datadir)/@PACKAGE@ +pkglibdir = $(libdir)/@PACKAGE@ +pkgincludedir = $(includedir)/@PACKAGE@ +top_builddir = .. +am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd +INSTALL = @INSTALL@ +install_sh_DATA = $(install_sh) -c -m 644 +install_sh_PROGRAM = $(install_sh) -c +install_sh_SCRIPT = $(install_sh) -c +INSTALL_HEADER = $(INSTALL_DATA) +transform = $(program_transform_name) +NORMAL_INSTALL = : +PRE_INSTALL = : +POST_INSTALL = : +NORMAL_UNINSTALL = : +PRE_UNINSTALL = : +POST_UNINSTALL = : +host_triplet = @host@ +subdir = include +DIST_COMMON = $(srcdir)/Makefile.am $(srcdir)/Makefile.in +ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 +am__aclocal_m4_deps = $(top_srcdir)/acinclude.m4 \ + $(top_srcdir)/configure.ac +am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ + $(ACLOCAL_M4) +mkinstalldirs = $(mkdir_p) +CONFIG_HEADER = $(top_builddir)/config.h +CONFIG_CLEAN_FILES = +SOURCES = +DIST_SOURCES = +RECURSIVE_TARGETS = all-recursive check-recursive dvi-recursive \ + html-recursive info-recursive install-data-recursive \ + install-exec-recursive install-info-recursive \ + install-recursive installcheck-recursive installdirs-recursive \ + pdf-recursive ps-recursive uninstall-info-recursive \ + uninstall-recursive +ETAGS = etags +CTAGS = ctags +DIST_SUBDIRS = $(SUBDIRS) +DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) +ACLOCAL = @ACLOCAL@ +AMDEP_FALSE = @AMDEP_FALSE@ +AMDEP_TRUE = @AMDEP_TRUE@ +AMTAR = @AMTAR@ +AR = @AR@ +AS = @AS@ +AUTOCONF = @AUTOCONF@ +AUTOHEADER = @AUTOHEADER@ +AUTOMAKE = @AUTOMAKE@ +AWK = @AWK@ +BUILD_KISS_FFT_FALSE = @BUILD_KISS_FFT_FALSE@ +BUILD_KISS_FFT_TRUE = @BUILD_KISS_FFT_TRUE@ +BUILD_SMALLFT_FALSE = @BUILD_SMALLFT_FALSE@ +BUILD_SMALLFT_TRUE = @BUILD_SMALLFT_TRUE@ +CC = @CC@ +CCDEPMODE = @CCDEPMODE@ +CFLAGS = @CFLAGS@ +CPP = @CPP@ +CPPFLAGS = @CPPFLAGS@ +CXX = @CXX@ +CXXCPP = @CXXCPP@ +CXXDEPMODE = @CXXDEPMODE@ +CXXFLAGS = @CXXFLAGS@ +CYGPATH_W = @CYGPATH_W@ +DEFS = @DEFS@ +DEPDIR = @DEPDIR@ +DLLTOOL = @DLLTOOL@ +DSYMUTIL = @DSYMUTIL@ +ECHO = @ECHO@ +ECHO_C = @ECHO_C@ +ECHO_N = @ECHO_N@ +ECHO_T = @ECHO_T@ +EGREP = @EGREP@ +EXEEXT = @EXEEXT@ +F77 = @F77@ +FFLAGS = @FFLAGS@ +FFT_CFLAGS = @FFT_CFLAGS@ +FFT_LIBS = @FFT_LIBS@ +FFT_PKGCONFIG = @FFT_PKGCONFIG@ +GREP = @GREP@ +INSTALL_DATA = @INSTALL_DATA@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ +INSTALL_SCRIPT = @INSTALL_SCRIPT@ +INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ +LDFLAGS = @LDFLAGS@ +LIBOBJS = @LIBOBJS@ +LIBS = @LIBS@ +LIBTOOL = @LIBTOOL@ +LN_S = @LN_S@ +LTLIBOBJS = @LTLIBOBJS@ +MAINT = @MAINT@ +MAINTAINER_MODE_FALSE = @MAINTAINER_MODE_FALSE@ +MAINTAINER_MODE_TRUE = @MAINTAINER_MODE_TRUE@ +MAKEINFO = @MAKEINFO@ +NMEDIT = @NMEDIT@ +OBJDUMP = @OBJDUMP@ +OBJEXT = @OBJEXT@ +OGG_CFLAGS = @OGG_CFLAGS@ +OGG_LIBS = @OGG_LIBS@ +PACKAGE = @PACKAGE@ +PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ +PACKAGE_NAME = @PACKAGE_NAME@ +PACKAGE_STRING = @PACKAGE_STRING@ +PACKAGE_TARNAME = @PACKAGE_TARNAME@ +PACKAGE_VERSION = @PACKAGE_VERSION@ +PATH_SEPARATOR = @PATH_SEPARATOR@ +PKG_CONFIG = @PKG_CONFIG@ +RANLIB = @RANLIB@ +SED = @SED@ +SET_MAKE = @SET_MAKE@ +SHELL = @SHELL@ +SIZE16 = @SIZE16@ +SIZE32 = @SIZE32@ +SPEEX_LT_AGE = @SPEEX_LT_AGE@ +SPEEX_LT_CURRENT = @SPEEX_LT_CURRENT@ +SPEEX_LT_REVISION = @SPEEX_LT_REVISION@ +SPEEX_VERSION = @SPEEX_VERSION@ +STRIP = @STRIP@ +VERSION = @VERSION@ +ac_ct_CC = @ac_ct_CC@ +ac_ct_CXX = @ac_ct_CXX@ +ac_ct_F77 = @ac_ct_F77@ +am__fastdepCC_FALSE = @am__fastdepCC_FALSE@ +am__fastdepCC_TRUE = @am__fastdepCC_TRUE@ +am__fastdepCXX_FALSE = @am__fastdepCXX_FALSE@ +am__fastdepCXX_TRUE = @am__fastdepCXX_TRUE@ +am__include = @am__include@ +am__leading_dot = @am__leading_dot@ +am__quote = @am__quote@ +bindir = @bindir@ +build = @build@ +build_alias = @build_alias@ +build_cpu = @build_cpu@ +build_os = @build_os@ +build_vendor = @build_vendor@ +datadir = @datadir@ +datarootdir = @datarootdir@ +docdir = @docdir@ +dvidir = @dvidir@ +exec_prefix = @exec_prefix@ +host = @host@ +host_alias = @host_alias@ +host_cpu = @host_cpu@ +host_os = @host_os@ +host_vendor = @host_vendor@ +htmldir = @htmldir@ +includedir = @includedir@ +infodir = @infodir@ +install_sh = @install_sh@ +libdir = @libdir@ +libexecdir = @libexecdir@ +localedir = @localedir@ +localstatedir = @localstatedir@ +mandir = @mandir@ +mkdir_p = @mkdir_p@ +oldincludedir = @oldincludedir@ +pdfdir = @pdfdir@ +prefix = @prefix@ +program_transform_name = @program_transform_name@ +psdir = @psdir@ +sbindir = @sbindir@ +sharedstatedir = @sharedstatedir@ +src = @src@ +sysconfdir = @sysconfdir@ +target_alias = @target_alias@ +SUBDIRS = speex +all: all-recursive + +.SUFFIXES: +$(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(am__configure_deps) + @for dep in $?; do \ + case '$(am__configure_deps)' in \ + *$$dep*) \ + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh \ + && exit 0; \ + exit 1;; \ + esac; \ + done; \ + echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu include/Makefile'; \ + cd $(top_srcdir) && \ + $(AUTOMAKE) --gnu include/Makefile +.PRECIOUS: Makefile +Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status + @case '$?' in \ + *config.status*) \ + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ + *) \ + echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ + cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ + esac; + +$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh + +$(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh + +mostlyclean-libtool: + -rm -f *.lo + +clean-libtool: + -rm -rf .libs _libs + +distclean-libtool: + -rm -f libtool +uninstall-info-am: + +# This directory's subdirectories are mostly independent; you can cd +# into them and run `make' without going through this Makefile. +# To change the values of `make' variables: instead of editing Makefiles, +# (1) if the variable is set in `config.status', edit `config.status' +# (which will cause the Makefiles to be regenerated when you run `make'); +# (2) otherwise, pass the desired values on the `make' command line. +$(RECURSIVE_TARGETS): + @set fnord $$MAKEFLAGS; amf=$$2; \ + dot_seen=no; \ + target=`echo $@ | sed s/-recursive//`; \ + list='$(SUBDIRS)'; for subdir in $$list; do \ + echo "Making $$target in $$subdir"; \ + if test "$$subdir" = "."; then \ + dot_seen=yes; \ + local_target="$$target-am"; \ + else \ + local_target="$$target"; \ + fi; \ + (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) $$local_target) \ + || case "$$amf" in *=*) exit 1;; *k*) fail=yes;; *) exit 1;; esac; \ + done; \ + if test "$$dot_seen" = "no"; then \ + $(MAKE) $(AM_MAKEFLAGS) "$$target-am" || exit 1; \ + fi; test -z "$$fail" + +mostlyclean-recursive clean-recursive distclean-recursive \ +maintainer-clean-recursive: + @set fnord $$MAKEFLAGS; amf=$$2; \ + dot_seen=no; \ + case "$@" in \ + distclean-* | maintainer-clean-*) list='$(DIST_SUBDIRS)' ;; \ + *) list='$(SUBDIRS)' ;; \ + esac; \ + rev=''; for subdir in $$list; do \ + if test "$$subdir" = "."; then :; else \ + rev="$$subdir $$rev"; \ + fi; \ + done; \ + rev="$$rev ."; \ + target=`echo $@ | sed s/-recursive//`; \ + for subdir in $$rev; do \ + echo "Making $$target in $$subdir"; \ + if test "$$subdir" = "."; then \ + local_target="$$target-am"; \ + else \ + local_target="$$target"; \ + fi; \ + (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) $$local_target) \ + || case "$$amf" in *=*) exit 1;; *k*) fail=yes;; *) exit 1;; esac; \ + done && test -z "$$fail" +tags-recursive: + list='$(SUBDIRS)'; for subdir in $$list; do \ + test "$$subdir" = . || (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) tags); \ + done +ctags-recursive: + list='$(SUBDIRS)'; for subdir in $$list; do \ + test "$$subdir" = . || (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) ctags); \ + done + +ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES) + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) ' { files[$$0] = 1; } \ + END { for (i in files) print i; }'`; \ + mkid -fID $$unique +tags: TAGS + +TAGS: tags-recursive $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + tags=; \ + here=`pwd`; \ + if ($(ETAGS) --etags-include --version) >/dev/null 2>&1; then \ + include_option=--etags-include; \ + empty_fix=.; \ + else \ + include_option=--include; \ + empty_fix=; \ + fi; \ + list='$(SUBDIRS)'; for subdir in $$list; do \ + if test "$$subdir" = .; then :; else \ + test ! -f $$subdir/TAGS || \ + tags="$$tags $$include_option=$$here/$$subdir/TAGS"; \ + fi; \ + done; \ + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) ' { files[$$0] = 1; } \ + END { for (i in files) print i; }'`; \ + if test -z "$(ETAGS_ARGS)$$tags$$unique"; then :; else \ + test -n "$$unique" || unique=$$empty_fix; \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + $$tags $$unique; \ + fi +ctags: CTAGS +CTAGS: ctags-recursive $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + tags=; \ + here=`pwd`; \ + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) ' { files[$$0] = 1; } \ + END { for (i in files) print i; }'`; \ + test -z "$(CTAGS_ARGS)$$tags$$unique" \ + || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ + $$tags $$unique + +GTAGS: + here=`$(am__cd) $(top_builddir) && pwd` \ + && cd $(top_srcdir) \ + && gtags -i $(GTAGS_ARGS) $$here + +distclean-tags: + -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags + +distdir: $(DISTFILES) + @srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; \ + topsrcdirstrip=`echo "$(top_srcdir)" | sed 's|.|.|g'`; \ + list='$(DISTFILES)'; for file in $$list; do \ + case $$file in \ + $(srcdir)/*) file=`echo "$$file" | sed "s|^$$srcdirstrip/||"`;; \ + $(top_srcdir)/*) file=`echo "$$file" | sed "s|^$$topsrcdirstrip/|$(top_builddir)/|"`;; \ + esac; \ + if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ + dir=`echo "$$file" | sed -e 's,/[^/]*$$,,'`; \ + if test "$$dir" != "$$file" && test "$$dir" != "."; then \ + dir="/$$dir"; \ + $(mkdir_p) "$(distdir)$$dir"; \ + else \ + dir=''; \ + fi; \ + if test -d $$d/$$file; then \ + if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ + cp -pR $(srcdir)/$$file $(distdir)$$dir || exit 1; \ + fi; \ + cp -pR $$d/$$file $(distdir)$$dir || exit 1; \ + else \ + test -f $(distdir)/$$file \ + || cp -p $$d/$$file $(distdir)/$$file \ + || exit 1; \ + fi; \ + done + list='$(SUBDIRS)'; for subdir in $$list; do \ + if test "$$subdir" = .; then :; else \ + test -d "$(distdir)/$$subdir" \ + || mkdir "$(distdir)/$$subdir" \ + || exit 1; \ + (cd $$subdir && \ + $(MAKE) $(AM_MAKEFLAGS) \ + top_distdir="../$(top_distdir)" \ + distdir="../$(distdir)/$$subdir" \ + distdir) \ + || exit 1; \ + fi; \ + done +check-am: all-am +check: check-recursive +all-am: Makefile +installdirs: installdirs-recursive +installdirs-am: +install: install-recursive +install-exec: install-exec-recursive +install-data: install-data-recursive +uninstall: uninstall-recursive + +install-am: all-am + @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am + +installcheck: installcheck-recursive +install-strip: + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + `test -z '$(STRIP)' || \ + echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install +mostlyclean-generic: + +clean-generic: + +distclean-generic: + -rm -f $(CONFIG_CLEAN_FILES) + +maintainer-clean-generic: + @echo "This command is intended for maintainers to use" + @echo "it deletes files that may require special tools to rebuild." +clean: clean-recursive + +clean-am: clean-generic clean-libtool mostlyclean-am + +distclean: distclean-recursive + -rm -f Makefile +distclean-am: clean-am distclean-generic distclean-libtool \ + distclean-tags + +dvi: dvi-recursive + +dvi-am: + +html: html-recursive + +info: info-recursive + +info-am: + +install-data-am: + +install-exec-am: + +install-info: install-info-recursive + +install-man: + +installcheck-am: + +maintainer-clean: maintainer-clean-recursive + -rm -f Makefile +maintainer-clean-am: distclean-am maintainer-clean-generic + +mostlyclean: mostlyclean-recursive + +mostlyclean-am: mostlyclean-generic mostlyclean-libtool + +pdf: pdf-recursive + +pdf-am: + +ps: ps-recursive + +ps-am: + +uninstall-am: uninstall-info-am + +uninstall-info: uninstall-info-recursive + +.PHONY: $(RECURSIVE_TARGETS) CTAGS GTAGS all all-am check check-am \ + clean clean-generic clean-libtool clean-recursive ctags \ + ctags-recursive distclean distclean-generic distclean-libtool \ + distclean-recursive distclean-tags distdir dvi dvi-am html \ + html-am info info-am install install-am install-data \ + install-data-am install-exec install-exec-am install-info \ + install-info-am install-man install-strip installcheck \ + installcheck-am installdirs installdirs-am maintainer-clean \ + maintainer-clean-generic maintainer-clean-recursive \ + mostlyclean mostlyclean-generic mostlyclean-libtool \ + mostlyclean-recursive pdf pdf-am ps ps-am tags tags-recursive \ + uninstall uninstall-am uninstall-info-am + +# Tell versions [3.59,3.63) of GNU make to not export all variables. +# Otherwise a system limit (for SysV at least) may be exceeded. +.NOEXPORT: diff --git a/android/app/src/main/jni/include/speex/Makefile.am b/android/app/src/main/jni/include/speex/Makefile.am new file mode 100644 index 000000000..2ae34f9f8 --- /dev/null +++ b/android/app/src/main/jni/include/speex/Makefile.am @@ -0,0 +1,9 @@ +# Disable automatic dependency tracking if using other tools than gcc and gmake +#AUTOMAKE_OPTIONS = no-dependencies + +nodist_pkginclude_HEADERS = speex_config_types.h + +pkginclude_HEADERS = speex.h speex_bits.h speex_buffer.h speex_callbacks.h \ + speex_echo.h speex_header.h speex_jitter.h speex_preprocess.h speex_resampler.h \ + speex_stereo.h speex_types.h + diff --git a/android/app/src/main/jni/include/speex/Makefile.in b/android/app/src/main/jni/include/speex/Makefile.in new file mode 100644 index 000000000..9c0a33d08 --- /dev/null +++ b/android/app/src/main/jni/include/speex/Makefile.in @@ -0,0 +1,440 @@ +# Makefile.in generated by automake 1.8.5 from Makefile.am. +# @configure_input@ + +# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, +# 2003, 2004 Free Software Foundation, Inc. +# This Makefile.in is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY, to the extent permitted by law; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. + +@SET_MAKE@ + +# Disable automatic dependency tracking if using other tools than gcc and gmake +#AUTOMAKE_OPTIONS = no-dependencies + +srcdir = @srcdir@ +top_srcdir = @top_srcdir@ +VPATH = @srcdir@ +pkgdatadir = $(datadir)/@PACKAGE@ +pkglibdir = $(libdir)/@PACKAGE@ +pkgincludedir = $(includedir)/@PACKAGE@ +top_builddir = ../.. +am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd +INSTALL = @INSTALL@ +install_sh_DATA = $(install_sh) -c -m 644 +install_sh_PROGRAM = $(install_sh) -c +install_sh_SCRIPT = $(install_sh) -c +INSTALL_HEADER = $(INSTALL_DATA) +transform = $(program_transform_name) +NORMAL_INSTALL = : +PRE_INSTALL = : +POST_INSTALL = : +NORMAL_UNINSTALL = : +PRE_UNINSTALL = : +POST_UNINSTALL = : +host_triplet = @host@ +subdir = include/speex +DIST_COMMON = $(pkginclude_HEADERS) $(srcdir)/Makefile.am \ + $(srcdir)/Makefile.in $(srcdir)/speex_config_types.h.in +ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 +am__aclocal_m4_deps = $(top_srcdir)/acinclude.m4 \ + $(top_srcdir)/configure.ac +am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ + $(ACLOCAL_M4) +mkinstalldirs = $(mkdir_p) +CONFIG_HEADER = $(top_builddir)/config.h +CONFIG_CLEAN_FILES = speex_config_types.h +SOURCES = +DIST_SOURCES = +am__installdirs = "$(DESTDIR)$(pkgincludedir)" "$(DESTDIR)$(pkgincludedir)" +nodist_pkgincludeHEADERS_INSTALL = $(INSTALL_HEADER) +pkgincludeHEADERS_INSTALL = $(INSTALL_HEADER) +HEADERS = $(nodist_pkginclude_HEADERS) $(pkginclude_HEADERS) +ETAGS = etags +CTAGS = ctags +DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) +ACLOCAL = @ACLOCAL@ +AMDEP_FALSE = @AMDEP_FALSE@ +AMDEP_TRUE = @AMDEP_TRUE@ +AMTAR = @AMTAR@ +AR = @AR@ +AS = @AS@ +AUTOCONF = @AUTOCONF@ +AUTOHEADER = @AUTOHEADER@ +AUTOMAKE = @AUTOMAKE@ +AWK = @AWK@ +BUILD_KISS_FFT_FALSE = @BUILD_KISS_FFT_FALSE@ +BUILD_KISS_FFT_TRUE = @BUILD_KISS_FFT_TRUE@ +BUILD_SMALLFT_FALSE = @BUILD_SMALLFT_FALSE@ +BUILD_SMALLFT_TRUE = @BUILD_SMALLFT_TRUE@ +CC = @CC@ +CCDEPMODE = @CCDEPMODE@ +CFLAGS = @CFLAGS@ +CPP = @CPP@ +CPPFLAGS = @CPPFLAGS@ +CXX = @CXX@ +CXXCPP = @CXXCPP@ +CXXDEPMODE = @CXXDEPMODE@ +CXXFLAGS = @CXXFLAGS@ +CYGPATH_W = @CYGPATH_W@ +DEFS = @DEFS@ +DEPDIR = @DEPDIR@ +DLLTOOL = @DLLTOOL@ +DSYMUTIL = @DSYMUTIL@ +ECHO = @ECHO@ +ECHO_C = @ECHO_C@ +ECHO_N = @ECHO_N@ +ECHO_T = @ECHO_T@ +EGREP = @EGREP@ +EXEEXT = @EXEEXT@ +F77 = @F77@ +FFLAGS = @FFLAGS@ +FFT_CFLAGS = @FFT_CFLAGS@ +FFT_LIBS = @FFT_LIBS@ +FFT_PKGCONFIG = @FFT_PKGCONFIG@ +GREP = @GREP@ +INSTALL_DATA = @INSTALL_DATA@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ +INSTALL_SCRIPT = @INSTALL_SCRIPT@ +INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ +LDFLAGS = @LDFLAGS@ +LIBOBJS = @LIBOBJS@ +LIBS = @LIBS@ +LIBTOOL = @LIBTOOL@ +LN_S = @LN_S@ +LTLIBOBJS = @LTLIBOBJS@ +MAINT = @MAINT@ +MAINTAINER_MODE_FALSE = @MAINTAINER_MODE_FALSE@ +MAINTAINER_MODE_TRUE = @MAINTAINER_MODE_TRUE@ +MAKEINFO = @MAKEINFO@ +NMEDIT = @NMEDIT@ +OBJDUMP = @OBJDUMP@ +OBJEXT = @OBJEXT@ +OGG_CFLAGS = @OGG_CFLAGS@ +OGG_LIBS = @OGG_LIBS@ +PACKAGE = @PACKAGE@ +PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ +PACKAGE_NAME = @PACKAGE_NAME@ +PACKAGE_STRING = @PACKAGE_STRING@ +PACKAGE_TARNAME = @PACKAGE_TARNAME@ +PACKAGE_VERSION = @PACKAGE_VERSION@ +PATH_SEPARATOR = @PATH_SEPARATOR@ +PKG_CONFIG = @PKG_CONFIG@ +RANLIB = @RANLIB@ +SED = @SED@ +SET_MAKE = @SET_MAKE@ +SHELL = @SHELL@ +SIZE16 = @SIZE16@ +SIZE32 = @SIZE32@ +SPEEX_LT_AGE = @SPEEX_LT_AGE@ +SPEEX_LT_CURRENT = @SPEEX_LT_CURRENT@ +SPEEX_LT_REVISION = @SPEEX_LT_REVISION@ +SPEEX_VERSION = @SPEEX_VERSION@ +STRIP = @STRIP@ +VERSION = @VERSION@ +ac_ct_CC = @ac_ct_CC@ +ac_ct_CXX = @ac_ct_CXX@ +ac_ct_F77 = @ac_ct_F77@ +am__fastdepCC_FALSE = @am__fastdepCC_FALSE@ +am__fastdepCC_TRUE = @am__fastdepCC_TRUE@ +am__fastdepCXX_FALSE = @am__fastdepCXX_FALSE@ +am__fastdepCXX_TRUE = @am__fastdepCXX_TRUE@ +am__include = @am__include@ +am__leading_dot = @am__leading_dot@ +am__quote = @am__quote@ +bindir = @bindir@ +build = @build@ +build_alias = @build_alias@ +build_cpu = @build_cpu@ +build_os = @build_os@ +build_vendor = @build_vendor@ +datadir = @datadir@ +datarootdir = @datarootdir@ +docdir = @docdir@ +dvidir = @dvidir@ +exec_prefix = @exec_prefix@ +host = @host@ +host_alias = @host_alias@ +host_cpu = @host_cpu@ +host_os = @host_os@ +host_vendor = @host_vendor@ +htmldir = @htmldir@ +includedir = @includedir@ +infodir = @infodir@ +install_sh = @install_sh@ +libdir = @libdir@ +libexecdir = @libexecdir@ +localedir = @localedir@ +localstatedir = @localstatedir@ +mandir = @mandir@ +mkdir_p = @mkdir_p@ +oldincludedir = @oldincludedir@ +pdfdir = @pdfdir@ +prefix = @prefix@ +program_transform_name = @program_transform_name@ +psdir = @psdir@ +sbindir = @sbindir@ +sharedstatedir = @sharedstatedir@ +src = @src@ +sysconfdir = @sysconfdir@ +target_alias = @target_alias@ +nodist_pkginclude_HEADERS = speex_config_types.h +pkginclude_HEADERS = speex.h speex_bits.h speex_buffer.h speex_callbacks.h \ + speex_echo.h speex_header.h speex_jitter.h speex_preprocess.h speex_resampler.h \ + speex_stereo.h speex_types.h + +all: all-am + +.SUFFIXES: +$(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(am__configure_deps) + @for dep in $?; do \ + case '$(am__configure_deps)' in \ + *$$dep*) \ + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh \ + && exit 0; \ + exit 1;; \ + esac; \ + done; \ + echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu include/speex/Makefile'; \ + cd $(top_srcdir) && \ + $(AUTOMAKE) --gnu include/speex/Makefile +.PRECIOUS: Makefile +Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status + @case '$?' in \ + *config.status*) \ + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ + *) \ + echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ + cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ + esac; + +$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh + +$(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +speex_config_types.h: $(top_builddir)/config.status $(srcdir)/speex_config_types.h.in + cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ + +mostlyclean-libtool: + -rm -f *.lo + +clean-libtool: + -rm -rf .libs _libs + +distclean-libtool: + -rm -f libtool +uninstall-info-am: +install-nodist_pkgincludeHEADERS: $(nodist_pkginclude_HEADERS) + @$(NORMAL_INSTALL) + test -z "$(pkgincludedir)" || $(mkdir_p) "$(DESTDIR)$(pkgincludedir)" + @list='$(nodist_pkginclude_HEADERS)'; for p in $$list; do \ + if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \ + f="`echo $$p | sed -e 's|^.*/||'`"; \ + echo " $(nodist_pkgincludeHEADERS_INSTALL) '$$d$$p' '$(DESTDIR)$(pkgincludedir)/$$f'"; \ + $(nodist_pkgincludeHEADERS_INSTALL) "$$d$$p" "$(DESTDIR)$(pkgincludedir)/$$f"; \ + done + +uninstall-nodist_pkgincludeHEADERS: + @$(NORMAL_UNINSTALL) + @list='$(nodist_pkginclude_HEADERS)'; for p in $$list; do \ + f="`echo $$p | sed -e 's|^.*/||'`"; \ + echo " rm -f '$(DESTDIR)$(pkgincludedir)/$$f'"; \ + rm -f "$(DESTDIR)$(pkgincludedir)/$$f"; \ + done +install-pkgincludeHEADERS: $(pkginclude_HEADERS) + @$(NORMAL_INSTALL) + test -z "$(pkgincludedir)" || $(mkdir_p) "$(DESTDIR)$(pkgincludedir)" + @list='$(pkginclude_HEADERS)'; for p in $$list; do \ + if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \ + f="`echo $$p | sed -e 's|^.*/||'`"; \ + echo " $(pkgincludeHEADERS_INSTALL) '$$d$$p' '$(DESTDIR)$(pkgincludedir)/$$f'"; \ + $(pkgincludeHEADERS_INSTALL) "$$d$$p" "$(DESTDIR)$(pkgincludedir)/$$f"; \ + done + +uninstall-pkgincludeHEADERS: + @$(NORMAL_UNINSTALL) + @list='$(pkginclude_HEADERS)'; for p in $$list; do \ + f="`echo $$p | sed -e 's|^.*/||'`"; \ + echo " rm -f '$(DESTDIR)$(pkgincludedir)/$$f'"; \ + rm -f "$(DESTDIR)$(pkgincludedir)/$$f"; \ + done + +ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES) + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) ' { files[$$0] = 1; } \ + END { for (i in files) print i; }'`; \ + mkid -fID $$unique +tags: TAGS + +TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + tags=; \ + here=`pwd`; \ + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) ' { files[$$0] = 1; } \ + END { for (i in files) print i; }'`; \ + if test -z "$(ETAGS_ARGS)$$tags$$unique"; then :; else \ + test -n "$$unique" || unique=$$empty_fix; \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + $$tags $$unique; \ + fi +ctags: CTAGS +CTAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + tags=; \ + here=`pwd`; \ + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) ' { files[$$0] = 1; } \ + END { for (i in files) print i; }'`; \ + test -z "$(CTAGS_ARGS)$$tags$$unique" \ + || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ + $$tags $$unique + +GTAGS: + here=`$(am__cd) $(top_builddir) && pwd` \ + && cd $(top_srcdir) \ + && gtags -i $(GTAGS_ARGS) $$here + +distclean-tags: + -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags + +distdir: $(DISTFILES) + @srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; \ + topsrcdirstrip=`echo "$(top_srcdir)" | sed 's|.|.|g'`; \ + list='$(DISTFILES)'; for file in $$list; do \ + case $$file in \ + $(srcdir)/*) file=`echo "$$file" | sed "s|^$$srcdirstrip/||"`;; \ + $(top_srcdir)/*) file=`echo "$$file" | sed "s|^$$topsrcdirstrip/|$(top_builddir)/|"`;; \ + esac; \ + if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ + dir=`echo "$$file" | sed -e 's,/[^/]*$$,,'`; \ + if test "$$dir" != "$$file" && test "$$dir" != "."; then \ + dir="/$$dir"; \ + $(mkdir_p) "$(distdir)$$dir"; \ + else \ + dir=''; \ + fi; \ + if test -d $$d/$$file; then \ + if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ + cp -pR $(srcdir)/$$file $(distdir)$$dir || exit 1; \ + fi; \ + cp -pR $$d/$$file $(distdir)$$dir || exit 1; \ + else \ + test -f $(distdir)/$$file \ + || cp -p $$d/$$file $(distdir)/$$file \ + || exit 1; \ + fi; \ + done +check-am: all-am +check: check-am +all-am: Makefile $(HEADERS) +installdirs: + for dir in "$(DESTDIR)$(pkgincludedir)" "$(DESTDIR)$(pkgincludedir)"; do \ + test -z "$$dir" || $(mkdir_p) "$$dir"; \ + done +install: install-am +install-exec: install-exec-am +install-data: install-data-am +uninstall: uninstall-am + +install-am: all-am + @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am + +installcheck: installcheck-am +install-strip: + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + `test -z '$(STRIP)' || \ + echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install +mostlyclean-generic: + +clean-generic: + +distclean-generic: + -rm -f $(CONFIG_CLEAN_FILES) + +maintainer-clean-generic: + @echo "This command is intended for maintainers to use" + @echo "it deletes files that may require special tools to rebuild." +clean: clean-am + +clean-am: clean-generic clean-libtool mostlyclean-am + +distclean: distclean-am + -rm -f Makefile +distclean-am: clean-am distclean-generic distclean-libtool \ + distclean-tags + +dvi: dvi-am + +dvi-am: + +html: html-am + +info: info-am + +info-am: + +install-data-am: install-nodist_pkgincludeHEADERS \ + install-pkgincludeHEADERS + +install-exec-am: + +install-info: install-info-am + +install-man: + +installcheck-am: + +maintainer-clean: maintainer-clean-am + -rm -f Makefile +maintainer-clean-am: distclean-am maintainer-clean-generic + +mostlyclean: mostlyclean-am + +mostlyclean-am: mostlyclean-generic mostlyclean-libtool + +pdf: pdf-am + +pdf-am: + +ps: ps-am + +ps-am: + +uninstall-am: uninstall-info-am uninstall-nodist_pkgincludeHEADERS \ + uninstall-pkgincludeHEADERS + +.PHONY: CTAGS GTAGS all all-am check check-am clean clean-generic \ + clean-libtool ctags distclean distclean-generic \ + distclean-libtool distclean-tags distdir dvi dvi-am html \ + html-am info info-am install install-am install-data \ + install-data-am install-exec install-exec-am install-info \ + install-info-am install-man install-nodist_pkgincludeHEADERS \ + install-pkgincludeHEADERS install-strip installcheck \ + installcheck-am installdirs maintainer-clean \ + maintainer-clean-generic mostlyclean mostlyclean-generic \ + mostlyclean-libtool pdf pdf-am ps ps-am tags uninstall \ + uninstall-am uninstall-info-am \ + uninstall-nodist_pkgincludeHEADERS uninstall-pkgincludeHEADERS + +# Tell versions [3.59,3.63) of GNU make to not export all variables. +# Otherwise a system limit (for SysV at least) may be exceeded. +.NOEXPORT: diff --git a/android/app/src/main/jni/include/speex/speex.h b/android/app/src/main/jni/include/speex/speex.h new file mode 100644 index 000000000..82ba01623 --- /dev/null +++ b/android/app/src/main/jni/include/speex/speex.h @@ -0,0 +1,424 @@ +/* Copyright (C) 2002-2006 Jean-Marc Valin*/ +/** + @file speex.h + @brief Describes the different modes of the codec +*/ +/* + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + - Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + - Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + - Neither the name of the Xiph.org Foundation nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR + CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +*/ + +#ifndef SPEEX_H +#define SPEEX_H +/** @defgroup Codec Speex encoder and decoder + * This is the Speex codec itself. + * @{ + */ + +#include "speex/speex_bits.h" +#include "speex/speex_types.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/* Values allowed for *ctl() requests */ + +/** Set enhancement on/off (decoder only) */ +#define SPEEX_SET_ENH 0 +/** Get enhancement state (decoder only) */ +#define SPEEX_GET_ENH 1 + +/*Would be SPEEX_SET_FRAME_SIZE, but it's (currently) invalid*/ +/** Obtain frame size used by encoder/decoder */ +#define SPEEX_GET_FRAME_SIZE 3 + +/** Set quality value */ +#define SPEEX_SET_QUALITY 4 +/** Get current quality setting */ +/* #define SPEEX_GET_QUALITY 5 -- Doesn't make much sense, does it? */ + +/** Set sub-mode to use */ +#define SPEEX_SET_MODE 6 +/** Get current sub-mode in use */ +#define SPEEX_GET_MODE 7 + +/** Set low-band sub-mode to use (wideband only)*/ +#define SPEEX_SET_LOW_MODE 8 +/** Get current low-band mode in use (wideband only)*/ +#define SPEEX_GET_LOW_MODE 9 + +/** Set high-band sub-mode to use (wideband only)*/ +#define SPEEX_SET_HIGH_MODE 10 +/** Get current high-band mode in use (wideband only)*/ +#define SPEEX_GET_HIGH_MODE 11 + +/** Set VBR on (1) or off (0) */ +#define SPEEX_SET_VBR 12 +/** Get VBR status (1 for on, 0 for off) */ +#define SPEEX_GET_VBR 13 + +/** Set quality value for VBR encoding (0-10) */ +#define SPEEX_SET_VBR_QUALITY 14 +/** Get current quality value for VBR encoding (0-10) */ +#define SPEEX_GET_VBR_QUALITY 15 + +/** Set complexity of the encoder (0-10) */ +#define SPEEX_SET_COMPLEXITY 16 +/** Get current complexity of the encoder (0-10) */ +#define SPEEX_GET_COMPLEXITY 17 + +/** Set bit-rate used by the encoder (or lower) */ +#define SPEEX_SET_BITRATE 18 +/** Get current bit-rate used by the encoder or decoder */ +#define SPEEX_GET_BITRATE 19 + +/** Define a handler function for in-band Speex request*/ +#define SPEEX_SET_HANDLER 20 + +/** Define a handler function for in-band user-defined request*/ +#define SPEEX_SET_USER_HANDLER 22 + +/** Set sampling rate used in bit-rate computation */ +#define SPEEX_SET_SAMPLING_RATE 24 +/** Get sampling rate used in bit-rate computation */ +#define SPEEX_GET_SAMPLING_RATE 25 + +/** Reset the encoder/decoder memories to zero*/ +#define SPEEX_RESET_STATE 26 + +/** Get VBR info (mostly used internally) */ +#define SPEEX_GET_RELATIVE_QUALITY 29 + +/** Set VAD status (1 for on, 0 for off) */ +#define SPEEX_SET_VAD 30 + +/** Get VAD status (1 for on, 0 for off) */ +#define SPEEX_GET_VAD 31 + +/** Set Average Bit-Rate (ABR) to n bits per seconds */ +#define SPEEX_SET_ABR 32 +/** Get Average Bit-Rate (ABR) setting (in bps) */ +#define SPEEX_GET_ABR 33 + +/** Set DTX status (1 for on, 0 for off) */ +#define SPEEX_SET_DTX 34 +/** Get DTX status (1 for on, 0 for off) */ +#define SPEEX_GET_DTX 35 + +/** Set submode encoding in each frame (1 for yes, 0 for no, setting to no breaks the standard) */ +#define SPEEX_SET_SUBMODE_ENCODING 36 +/** Get submode encoding in each frame */ +#define SPEEX_GET_SUBMODE_ENCODING 37 + +/*#define SPEEX_SET_LOOKAHEAD 38*/ +/** Returns the lookahead used by Speex */ +#define SPEEX_GET_LOOKAHEAD 39 + +/** Sets tuning for packet-loss concealment (expected loss rate) */ +#define SPEEX_SET_PLC_TUNING 40 +/** Gets tuning for PLC */ +#define SPEEX_GET_PLC_TUNING 41 + +/** Sets the max bit-rate allowed in VBR mode */ +#define SPEEX_SET_VBR_MAX_BITRATE 42 +/** Gets the max bit-rate allowed in VBR mode */ +#define SPEEX_GET_VBR_MAX_BITRATE 43 + +/** Turn on/off input/output high-pass filtering */ +#define SPEEX_SET_HIGHPASS 44 +/** Get status of input/output high-pass filtering */ +#define SPEEX_GET_HIGHPASS 45 + +/** Get "activity level" of the last decoded frame, i.e. + how much damage we cause if we remove the frame */ +#define SPEEX_GET_ACTIVITY 47 + + +/* Preserving compatibility:*/ +/** Equivalent to SPEEX_SET_ENH */ +#define SPEEX_SET_PF 0 +/** Equivalent to SPEEX_GET_ENH */ +#define SPEEX_GET_PF 1 + + + + +/* Values allowed for mode queries */ +/** Query the frame size of a mode */ +#define SPEEX_MODE_FRAME_SIZE 0 + +/** Query the size of an encoded frame for a particular sub-mode */ +#define SPEEX_SUBMODE_BITS_PER_FRAME 1 + + + +/** Get major Speex version */ +#define SPEEX_LIB_GET_MAJOR_VERSION 1 +/** Get minor Speex version */ +#define SPEEX_LIB_GET_MINOR_VERSION 3 +/** Get micro Speex version */ +#define SPEEX_LIB_GET_MICRO_VERSION 5 +/** Get extra Speex version */ +#define SPEEX_LIB_GET_EXTRA_VERSION 7 +/** Get Speex version string */ +#define SPEEX_LIB_GET_VERSION_STRING 9 + +/*#define SPEEX_LIB_SET_ALLOC_FUNC 10 +#define SPEEX_LIB_GET_ALLOC_FUNC 11 +#define SPEEX_LIB_SET_FREE_FUNC 12 +#define SPEEX_LIB_GET_FREE_FUNC 13 + +#define SPEEX_LIB_SET_WARNING_FUNC 14 +#define SPEEX_LIB_GET_WARNING_FUNC 15 +#define SPEEX_LIB_SET_ERROR_FUNC 16 +#define SPEEX_LIB_GET_ERROR_FUNC 17 +*/ + +/** Number of defined modes in Speex */ +#define SPEEX_NB_MODES 3 + +/** modeID for the defined narrowband mode */ +#define SPEEX_MODEID_NB 0 + +/** modeID for the defined wideband mode */ +#define SPEEX_MODEID_WB 1 + +/** modeID for the defined ultra-wideband mode */ +#define SPEEX_MODEID_UWB 2 + +struct SpeexMode; + + +/* Prototypes for mode function pointers */ + +/** Encoder state initialization function */ +typedef void *(*encoder_init_func)(const struct SpeexMode *mode); + +/** Encoder state destruction function */ +typedef void (*encoder_destroy_func)(void *st); + +/** Main encoding function */ +typedef int (*encode_func)(void *state, void *in, SpeexBits *bits); + +/** Function for controlling the encoder options */ +typedef int (*encoder_ctl_func)(void *state, int request, void *ptr); + +/** Decoder state initialization function */ +typedef void *(*decoder_init_func)(const struct SpeexMode *mode); + +/** Decoder state destruction function */ +typedef void (*decoder_destroy_func)(void *st); + +/** Main decoding function */ +typedef int (*decode_func)(void *state, SpeexBits *bits, void *out); + +/** Function for controlling the decoder options */ +typedef int (*decoder_ctl_func)(void *state, int request, void *ptr); + + +/** Query function for a mode */ +typedef int (*mode_query_func)(const void *mode, int request, void *ptr); + +/** Struct defining a Speex mode */ +typedef struct SpeexMode { + /** Pointer to the low-level mode data */ + const void *mode; + + /** Pointer to the mode query function */ + mode_query_func query; + + /** The name of the mode (you should not rely on this to identify the mode)*/ + const char *modeName; + + /**ID of the mode*/ + int modeID; + + /**Version number of the bitstream (incremented every time we break + bitstream compatibility*/ + int bitstream_version; + + /** Pointer to encoder initialization function */ + encoder_init_func enc_init; + + /** Pointer to encoder destruction function */ + encoder_destroy_func enc_destroy; + + /** Pointer to frame encoding function */ + encode_func enc; + + /** Pointer to decoder initialization function */ + decoder_init_func dec_init; + + /** Pointer to decoder destruction function */ + decoder_destroy_func dec_destroy; + + /** Pointer to frame decoding function */ + decode_func dec; + + /** ioctl-like requests for encoder */ + encoder_ctl_func enc_ctl; + + /** ioctl-like requests for decoder */ + decoder_ctl_func dec_ctl; + +} SpeexMode; + +/** + * Returns a handle to a newly created Speex encoder state structure. For now, + * the "mode" argument can be &nb_mode or &wb_mode . In the future, more modes + * may be added. Note that for now if you have more than one channels to + * encode, you need one state per channel. + * + * @param mode The mode to use (either speex_nb_mode or speex_wb.mode) + * @return A newly created encoder state or NULL if state allocation fails + */ +void *speex_encoder_init(const SpeexMode *mode); + +/** Frees all resources associated to an existing Speex encoder state. + * @param state Encoder state to be destroyed */ +void speex_encoder_destroy(void *state); + +/** Uses an existing encoder state to encode one frame of speech pointed to by + "in". The encoded bit-stream is saved in "bits". + @param state Encoder state + @param in Frame that will be encoded with a +-2^15 range. This data MAY be + overwritten by the encoder and should be considered uninitialised + after the call. + @param bits Bit-stream where the data will be written + @return 0 if frame needs not be transmitted (DTX only), 1 otherwise + */ +int speex_encode(void *state, float *in, SpeexBits *bits); + +/** Uses an existing encoder state to encode one frame of speech pointed to by + "in". The encoded bit-stream is saved in "bits". + @param state Encoder state + @param in Frame that will be encoded with a +-2^15 range + @param bits Bit-stream where the data will be written + @return 0 if frame needs not be transmitted (DTX only), 1 otherwise + */ +int speex_encode_int(void *state, spx_int16_t *in, SpeexBits *bits); + +/** Used like the ioctl function to control the encoder parameters + * + * @param state Encoder state + * @param request ioctl-type request (one of the SPEEX_* macros) + * @param ptr Data exchanged to-from function + * @return 0 if no error, -1 if request in unknown, -2 for invalid parameter + */ +int speex_encoder_ctl(void *state, int request, void *ptr); + + +/** Returns a handle to a newly created decoder state structure. For now, + * the mode argument can be &nb_mode or &wb_mode . In the future, more modes + * may be added. Note that for now if you have more than one channels to + * decode, you need one state per channel. + * + * @param mode Speex mode (one of speex_nb_mode or speex_wb_mode) + * @return A newly created decoder state or NULL if state allocation fails + */ +void *speex_decoder_init(const SpeexMode *mode); + +/** Frees all resources associated to an existing decoder state. + * + * @param state State to be destroyed + */ +void speex_decoder_destroy(void *state); + +/** Uses an existing decoder state to decode one frame of speech from + * bit-stream bits. The output speech is saved written to out. + * + * @param state Decoder state + * @param bits Bit-stream from which to decode the frame (NULL if the packet was lost) + * @param out Where to write the decoded frame + * @return return status (0 for no error, -1 for end of stream, -2 corrupt stream) + */ +int speex_decode(void *state, SpeexBits *bits, float *out); + +/** Uses an existing decoder state to decode one frame of speech from + * bit-stream bits. The output speech is saved written to out. + * + * @param state Decoder state + * @param bits Bit-stream from which to decode the frame (NULL if the packet was lost) + * @param out Where to write the decoded frame + * @return return status (0 for no error, -1 for end of stream, -2 corrupt stream) + */ +int speex_decode_int(void *state, SpeexBits *bits, spx_int16_t *out); + +/** Used like the ioctl function to control the encoder parameters + * + * @param state Decoder state + * @param request ioctl-type request (one of the SPEEX_* macros) + * @param ptr Data exchanged to-from function + * @return 0 if no error, -1 if request in unknown, -2 for invalid parameter + */ +int speex_decoder_ctl(void *state, int request, void *ptr); + + +/** Query function for mode information + * + * @param mode Speex mode + * @param request ioctl-type request (one of the SPEEX_* macros) + * @param ptr Data exchanged to-from function + * @return 0 if no error, -1 if request in unknown, -2 for invalid parameter + */ +int speex_mode_query(const SpeexMode *mode, int request, void *ptr); + +/** Functions for controlling the behavior of libspeex + * @param request ioctl-type request (one of the SPEEX_LIB_* macros) + * @param ptr Data exchanged to-from function + * @return 0 if no error, -1 if request in unknown, -2 for invalid parameter + */ +int speex_lib_ctl(int request, void *ptr); + +/** Default narrowband mode */ +extern const SpeexMode speex_nb_mode; + +/** Default wideband mode */ +extern const SpeexMode speex_wb_mode; + +/** Default "ultra-wideband" mode */ +extern const SpeexMode speex_uwb_mode; + +/** List of all modes available */ +extern const SpeexMode * const speex_mode_list[SPEEX_NB_MODES]; + +/** Obtain one of the modes available */ +const SpeexMode * speex_lib_get_mode (int mode); + +#ifndef WIN32 +/* We actually override the function in the narrowband case so that we can avoid linking in the wideband stuff */ +#define speex_lib_get_mode(mode) ((mode)==SPEEX_MODEID_NB ? &speex_nb_mode : speex_lib_get_mode (mode)) +#endif + +#ifdef __cplusplus +} +#endif + +/** @}*/ +#endif diff --git a/android/app/src/main/jni/include/speex/speex_bits.h b/android/app/src/main/jni/include/speex/speex_bits.h new file mode 100644 index 000000000..a26fb4ce0 --- /dev/null +++ b/android/app/src/main/jni/include/speex/speex_bits.h @@ -0,0 +1,174 @@ +/* Copyright (C) 2002 Jean-Marc Valin */ +/** + @file speex_bits.h + @brief Handles bit packing/unpacking +*/ +/* + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + - Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + - Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + - Neither the name of the Xiph.org Foundation nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR + CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +*/ + +#ifndef BITS_H +#define BITS_H +/** @defgroup SpeexBits SpeexBits: Bit-stream manipulations + * This is the structure that holds the bit-stream when encoding or decoding + * with Speex. It allows some manipulations as well. + * @{ + */ + +#ifdef __cplusplus +extern "C" { +#endif + +/** Bit-packing data structure representing (part of) a bit-stream. */ +typedef struct SpeexBits { + char *chars; /**< "raw" data */ + int nbBits; /**< Total number of bits stored in the stream*/ + int charPtr; /**< Position of the byte "cursor" */ + int bitPtr; /**< Position of the bit "cursor" within the current char */ + int owner; /**< Does the struct "own" the "raw" buffer (member "chars") */ + int overflow;/**< Set to one if we try to read past the valid data */ + int buf_size;/**< Allocated size for buffer */ + int reserved1; /**< Reserved for future use */ + void *reserved2; /**< Reserved for future use */ +} SpeexBits; + +/** Initializes and allocates resources for a SpeexBits struct */ +void speex_bits_init(SpeexBits *bits); + +/** Initializes SpeexBits struct using a pre-allocated buffer*/ +void speex_bits_init_buffer(SpeexBits *bits, void *buff, int buf_size); + +/** Sets the bits in a SpeexBits struct to use data from an existing buffer (for decoding without copying data) */ +void speex_bits_set_bit_buffer(SpeexBits *bits, void *buff, int buf_size); + +/** Frees all resources associated to a SpeexBits struct. Right now this does nothing since no resources are allocated, but this could change in the future.*/ +void speex_bits_destroy(SpeexBits *bits); + +/** Resets bits to initial value (just after initialization, erasing content)*/ +void speex_bits_reset(SpeexBits *bits); + +/** Rewind the bit-stream to the beginning (ready for read) without erasing the content */ +void speex_bits_rewind(SpeexBits *bits); + +/** Initializes the bit-stream from the data in an area of memory */ +void speex_bits_read_from(SpeexBits *bits, char *bytes, int len); + +/** Append bytes to the bit-stream + * + * @param bits Bit-stream to operate on + * @param bytes pointer to the bytes what will be appended + * @param len Number of bytes of append + */ +void speex_bits_read_whole_bytes(SpeexBits *bits, char *bytes, int len); + +/** Write the content of a bit-stream to an area of memory + * + * @param bits Bit-stream to operate on + * @param bytes Memory location where to write the bits + * @param max_len Maximum number of bytes to write (i.e. size of the "bytes" buffer) + * @return Number of bytes written to the "bytes" buffer +*/ +int speex_bits_write(SpeexBits *bits, char *bytes, int max_len); + +/** Like speex_bits_write, but writes only the complete bytes in the stream. Also removes the written bytes from the stream */ +int speex_bits_write_whole_bytes(SpeexBits *bits, char *bytes, int max_len); + +/** Append bits to the bit-stream + * @param bits Bit-stream to operate on + * @param data Value to append as integer + * @param nbBits number of bits to consider in "data" + */ +void speex_bits_pack(SpeexBits *bits, int data, int nbBits); + +/** Interpret the next bits in the bit-stream as a signed integer + * + * @param bits Bit-stream to operate on + * @param nbBits Number of bits to interpret + * @return A signed integer represented by the bits read + */ +int speex_bits_unpack_signed(SpeexBits *bits, int nbBits); + +/** Interpret the next bits in the bit-stream as an unsigned integer + * + * @param bits Bit-stream to operate on + * @param nbBits Number of bits to interpret + * @return An unsigned integer represented by the bits read + */ +unsigned int speex_bits_unpack_unsigned(SpeexBits *bits, int nbBits); + +/** Returns the number of bytes in the bit-stream, including the last one even if it is not "full" + * + * @param bits Bit-stream to operate on + * @return Number of bytes in the stream + */ +int speex_bits_nbytes(SpeexBits *bits); + +/** Same as speex_bits_unpack_unsigned, but without modifying the cursor position + * + * @param bits Bit-stream to operate on + * @param nbBits Number of bits to look for + * @return Value of the bits peeked, interpreted as unsigned + */ +unsigned int speex_bits_peek_unsigned(SpeexBits *bits, int nbBits); + +/** Get the value of the next bit in the stream, without modifying the + * "cursor" position + * + * @param bits Bit-stream to operate on + * @return Value of the bit peeked (one bit only) + */ +int speex_bits_peek(SpeexBits *bits); + +/** Advances the position of the "bit cursor" in the stream + * + * @param bits Bit-stream to operate on + * @param n Number of bits to advance + */ +void speex_bits_advance(SpeexBits *bits, int n); + +/** Returns the number of bits remaining to be read in a stream + * + * @param bits Bit-stream to operate on + * @return Number of bits that can still be read from the stream + */ +int speex_bits_remaining(SpeexBits *bits); + +/** Insert a terminator so that the data can be sent as a packet while auto-detecting + * the number of frames in each packet + * + * @param bits Bit-stream to operate on + */ +void speex_bits_insert_terminator(SpeexBits *bits); + +#ifdef __cplusplus +} +#endif + +/* @} */ +#endif diff --git a/android/app/src/main/jni/include/speex/speex_buffer.h b/android/app/src/main/jni/include/speex/speex_buffer.h new file mode 100644 index 000000000..df56f5f18 --- /dev/null +++ b/android/app/src/main/jni/include/speex/speex_buffer.h @@ -0,0 +1,68 @@ +/* Copyright (C) 2007 Jean-Marc Valin + + File: speex_buffer.h + This is a very simple ring buffer implementation. It is not thread-safe + so you need to do your own locking. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are + met: + + 1. Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + 3. The name of the author may not be used to endorse or promote products + derived from this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, + INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + POSSIBILITY OF SUCH DAMAGE. +*/ + +#ifndef SPEEX_BUFFER_H +#define SPEEX_BUFFER_H + +#include "speex/speex_types.h" + +#ifdef __cplusplus +extern "C" { +#endif + +struct SpeexBuffer_; +typedef struct SpeexBuffer_ SpeexBuffer; + +SpeexBuffer *speex_buffer_init(int size); + +void speex_buffer_destroy(SpeexBuffer *st); + +int speex_buffer_write(SpeexBuffer *st, void *data, int len); + +int speex_buffer_writezeros(SpeexBuffer *st, int len); + +int speex_buffer_read(SpeexBuffer *st, void *data, int len); + +int speex_buffer_get_available(SpeexBuffer *st); + +int speex_buffer_resize(SpeexBuffer *st, int len); + +#ifdef __cplusplus +} +#endif + +#endif + + + + diff --git a/android/app/src/main/jni/include/speex/speex_callbacks.h b/android/app/src/main/jni/include/speex/speex_callbacks.h new file mode 100644 index 000000000..6f450b3a3 --- /dev/null +++ b/android/app/src/main/jni/include/speex/speex_callbacks.h @@ -0,0 +1,134 @@ +/* Copyright (C) 2002 Jean-Marc Valin*/ +/** + @file speex_callbacks.h + @brief Describes callback handling and in-band signalling +*/ +/* + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + - Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + - Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + - Neither the name of the Xiph.org Foundation nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR + CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +*/ + +#ifndef SPEEX_CALLBACKS_H +#define SPEEX_CALLBACKS_H +/** @defgroup SpeexCallbacks Various definitions for Speex callbacks supported by the decoder. + * @{ + */ + +#include "speex.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** Total number of callbacks */ +#define SPEEX_MAX_CALLBACKS 16 + +/* Describes all the in-band requests */ + +/*These are 1-bit requests*/ +/** Request for perceptual enhancement (1 for on, 0 for off) */ +#define SPEEX_INBAND_ENH_REQUEST 0 +/** Reserved */ +#define SPEEX_INBAND_RESERVED1 1 + +/*These are 4-bit requests*/ +/** Request for a mode change */ +#define SPEEX_INBAND_MODE_REQUEST 2 +/** Request for a low mode change */ +#define SPEEX_INBAND_LOW_MODE_REQUEST 3 +/** Request for a high mode change */ +#define SPEEX_INBAND_HIGH_MODE_REQUEST 4 +/** Request for VBR (1 on, 0 off) */ +#define SPEEX_INBAND_VBR_QUALITY_REQUEST 5 +/** Request to be sent acknowledge */ +#define SPEEX_INBAND_ACKNOWLEDGE_REQUEST 6 +/** Request for VBR (1 for on, 0 for off) */ +#define SPEEX_INBAND_VBR_REQUEST 7 + +/*These are 8-bit requests*/ +/** Send a character in-band */ +#define SPEEX_INBAND_CHAR 8 +/** Intensity stereo information */ +#define SPEEX_INBAND_STEREO 9 + +/*These are 16-bit requests*/ +/** Transmit max bit-rate allowed */ +#define SPEEX_INBAND_MAX_BITRATE 10 + +/*These are 32-bit requests*/ +/** Acknowledge packet reception */ +#define SPEEX_INBAND_ACKNOWLEDGE 12 + +/** Callback function type */ +typedef int (*speex_callback_func)(SpeexBits *bits, void *state, void *data); + +/** Callback information */ +typedef struct SpeexCallback { + int callback_id; /**< ID associated to the callback */ + speex_callback_func func; /**< Callback handler function */ + void *data; /**< Data that will be sent to the handler */ + void *reserved1; /**< Reserved for future use */ + int reserved2; /**< Reserved for future use */ +} SpeexCallback; + +/** Handle in-band request */ +int speex_inband_handler(SpeexBits *bits, SpeexCallback *callback_list, void *state); + +/** Standard handler for mode request (change mode, no questions asked) */ +int speex_std_mode_request_handler(SpeexBits *bits, void *state, void *data); + +/** Standard handler for high mode request (change high mode, no questions asked) */ +int speex_std_high_mode_request_handler(SpeexBits *bits, void *state, void *data); + +/** Standard handler for in-band characters (write to stderr) */ +int speex_std_char_handler(SpeexBits *bits, void *state, void *data); + +/** Default handler for user-defined requests: in this case, just ignore */ +int speex_default_user_handler(SpeexBits *bits, void *state, void *data); + + + +/** Standard handler for low mode request (change low mode, no questions asked) */ +int speex_std_low_mode_request_handler(SpeexBits *bits, void *state, void *data); + +/** Standard handler for VBR request (Set VBR, no questions asked) */ +int speex_std_vbr_request_handler(SpeexBits *bits, void *state, void *data); + +/** Standard handler for enhancer request (Turn enhancer on/off, no questions asked) */ +int speex_std_enh_request_handler(SpeexBits *bits, void *state, void *data); + +/** Standard handler for VBR quality request (Set VBR quality, no questions asked) */ +int speex_std_vbr_quality_request_handler(SpeexBits *bits, void *state, void *data); + + +#ifdef __cplusplus +} +#endif + +/** @} */ +#endif diff --git a/android/app/src/main/jni/include/speex/speex_config_types.h b/android/app/src/main/jni/include/speex/speex_config_types.h new file mode 100644 index 000000000..bd548546b --- /dev/null +++ b/android/app/src/main/jni/include/speex/speex_config_types.h @@ -0,0 +1,11 @@ +#ifndef __SPEEX_TYPES_H__ +#define __SPEEX_TYPES_H__ + +/* these are filled in by configure */ +typedef short spx_int16_t; +typedef unsigned short spx_uint16_t; +typedef int spx_int32_t; +typedef unsigned int spx_uint32_t; + +#endif + diff --git a/android/app/src/main/jni/include/speex/speex_config_types.h.in b/android/app/src/main/jni/include/speex/speex_config_types.h.in new file mode 100644 index 000000000..3fab2ae44 --- /dev/null +++ b/android/app/src/main/jni/include/speex/speex_config_types.h.in @@ -0,0 +1,11 @@ +#ifndef __SPEEX_TYPES_H__ +#define __SPEEX_TYPES_H__ + +/* these are filled in by configure */ +typedef @SIZE16@ spx_int16_t; +typedef unsigned @SIZE16@ spx_uint16_t; +typedef @SIZE32@ spx_int32_t; +typedef unsigned @SIZE32@ spx_uint32_t; + +#endif + diff --git a/android/app/src/main/jni/include/speex/speex_echo.h b/android/app/src/main/jni/include/speex/speex_echo.h new file mode 100644 index 000000000..53bcd28a1 --- /dev/null +++ b/android/app/src/main/jni/include/speex/speex_echo.h @@ -0,0 +1,170 @@ +/* Copyright (C) Jean-Marc Valin */ +/** + @file speex_echo.h + @brief Echo cancellation +*/ +/* + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are + met: + + 1. Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + 3. The name of the author may not be used to endorse or promote products + derived from this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, + INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + POSSIBILITY OF SUCH DAMAGE. +*/ + +#ifndef SPEEX_ECHO_H +#define SPEEX_ECHO_H +/** @defgroup SpeexEchoState SpeexEchoState: Acoustic echo canceller + * This is the acoustic echo canceller module. + * @{ + */ +#include "speex/speex_types.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** Obtain frame size used by the AEC */ +#define SPEEX_ECHO_GET_FRAME_SIZE 3 + +/** Set sampling rate */ +#define SPEEX_ECHO_SET_SAMPLING_RATE 24 +/** Get sampling rate */ +#define SPEEX_ECHO_GET_SAMPLING_RATE 25 + +/* Can't set window sizes */ +/** Get size of impulse response (int32) */ +#define SPEEX_ECHO_GET_IMPULSE_RESPONSE_SIZE 27 + +/* Can't set window content */ +/** Get impulse response (int32[]) */ +#define SPEEX_ECHO_GET_IMPULSE_RESPONSE 29 + +/** Internal echo canceller state. Should never be accessed directly. */ +struct SpeexEchoState_; + +/** @class SpeexEchoState + * This holds the state of the echo canceller. You need one per channel. +*/ + +/** Internal echo canceller state. Should never be accessed directly. */ +typedef struct SpeexEchoState_ SpeexEchoState; + +/** Creates a new echo canceller state + * @param frame_size Number of samples to process at one time (should correspond to 10-20 ms) + * @param filter_length Number of samples of echo to cancel (should generally correspond to 100-500 ms) + * @return Newly-created echo canceller state + */ +SpeexEchoState *speex_echo_state_init(int frame_size, int filter_length); + +/** Creates a new multi-channel echo canceller state + * @param frame_size Number of samples to process at one time (should correspond to 10-20 ms) + * @param filter_length Number of samples of echo to cancel (should generally correspond to 100-500 ms) + * @param nb_mic Number of microphone channels + * @param nb_speakers Number of speaker channels + * @return Newly-created echo canceller state + */ +SpeexEchoState *speex_echo_state_init_mc(int frame_size, int filter_length, int nb_mic, int nb_speakers); + +/** Destroys an echo canceller state + * @param st Echo canceller state +*/ +void speex_echo_state_destroy(SpeexEchoState *st); + +/** Performs echo cancellation a frame, based on the audio sent to the speaker (no delay is added + * to playback in this form) + * + * @param st Echo canceller state + * @param rec Signal from the microphone (near end + far end echo) + * @param play Signal played to the speaker (received from far end) + * @param out Returns near-end signal with echo removed + */ +void speex_echo_cancellation(SpeexEchoState *st, const spx_int16_t *rec, const spx_int16_t *play, spx_int16_t *out); + +/** Performs echo cancellation a frame (deprecated) */ +void speex_echo_cancel(SpeexEchoState *st, const spx_int16_t *rec, const spx_int16_t *play, spx_int16_t *out, spx_int32_t *Yout); + +/** Perform echo cancellation using internal playback buffer, which is delayed by two frames + * to account for the delay introduced by most soundcards (but it could be off!) + * @param st Echo canceller state + * @param rec Signal from the microphone (near end + far end echo) + * @param out Returns near-end signal with echo removed +*/ +void speex_echo_capture(SpeexEchoState *st, const spx_int16_t *rec, spx_int16_t *out); + +/** Let the echo canceller know that a frame was just queued to the soundcard + * @param st Echo canceller state + * @param play Signal played to the speaker (received from far end) +*/ +void speex_echo_playback(SpeexEchoState *st, const spx_int16_t *play); + +/** Reset the echo canceller to its original state + * @param st Echo canceller state + */ +void speex_echo_state_reset(SpeexEchoState *st); + +/** Used like the ioctl function to control the echo canceller parameters + * + * @param st Echo canceller state + * @param request ioctl-type request (one of the SPEEX_ECHO_* macros) + * @param ptr Data exchanged to-from function + * @return 0 if no error, -1 if request in unknown + */ +int speex_echo_ctl(SpeexEchoState *st, int request, void *ptr); + + + +struct SpeexDecorrState_; + +typedef struct SpeexDecorrState_ SpeexDecorrState; + + +/** Create a state for the channel decorrelation algorithm + This is useful for multi-channel echo cancellation only + * @param rate Sampling rate + * @param channels Number of channels (it's a bit pointless if you don't have at least 2) + * @param frame_size Size of the frame to process at ones (counting samples *per* channel) +*/ +SpeexDecorrState *speex_decorrelate_new(int rate, int channels, int frame_size); + +/** Remove correlation between the channels by modifying the phase and possibly + adding noise in a way that is not (or little) perceptible. + * @param st Decorrelator state + * @param in Input audio in interleaved format + * @param out Result of the decorrelation (out *may* alias in) + * @param strength How much alteration of the audio to apply from 0 to 100. +*/ +void speex_decorrelate(SpeexDecorrState *st, const spx_int16_t *in, spx_int16_t *out, int strength); + +/** Destroy a Decorrelation state + * @param st State to destroy +*/ +void speex_decorrelate_destroy(SpeexDecorrState *st); + + +#ifdef __cplusplus +} +#endif + + +/** @}*/ +#endif diff --git a/android/app/src/main/jni/include/speex/speex_header.h b/android/app/src/main/jni/include/speex/speex_header.h new file mode 100644 index 000000000..f85b2496a --- /dev/null +++ b/android/app/src/main/jni/include/speex/speex_header.h @@ -0,0 +1,94 @@ +/* Copyright (C) 2002 Jean-Marc Valin */ +/** + @file speex_header.h + @brief Describes the Speex header +*/ +/* + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + - Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + - Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + - Neither the name of the Xiph.org Foundation nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR + CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +*/ + + +#ifndef SPEEX_HEADER_H +#define SPEEX_HEADER_H +/** @defgroup SpeexHeader SpeexHeader: Makes it easy to write/parse an Ogg/Speex header + * This is the Speex header for the Ogg encapsulation. You don't need that if you just use RTP. + * @{ + */ + +#include "speex/speex_types.h" + +#ifdef __cplusplus +extern "C" { +#endif + +struct SpeexMode; + +/** Length of the Speex header identifier */ +#define SPEEX_HEADER_STRING_LENGTH 8 + +/** Maximum number of characters for encoding the Speex version number in the header */ +#define SPEEX_HEADER_VERSION_LENGTH 20 + +/** Speex header info for file-based formats */ +typedef struct SpeexHeader { + char speex_string[SPEEX_HEADER_STRING_LENGTH]; /**< Identifies a Speex bit-stream, always set to "Speex " */ + char speex_version[SPEEX_HEADER_VERSION_LENGTH]; /**< Speex version */ + spx_int32_t speex_version_id; /**< Version for Speex (for checking compatibility) */ + spx_int32_t header_size; /**< Total size of the header ( sizeof(SpeexHeader) ) */ + spx_int32_t rate; /**< Sampling rate used */ + spx_int32_t mode; /**< Mode used (0 for narrowband, 1 for wideband) */ + spx_int32_t mode_bitstream_version; /**< Version ID of the bit-stream */ + spx_int32_t nb_channels; /**< Number of channels encoded */ + spx_int32_t bitrate; /**< Bit-rate used */ + spx_int32_t frame_size; /**< Size of frames */ + spx_int32_t vbr; /**< 1 for a VBR encoding, 0 otherwise */ + spx_int32_t frames_per_packet; /**< Number of frames stored per Ogg packet */ + spx_int32_t extra_headers; /**< Number of additional headers after the comments */ + spx_int32_t reserved1; /**< Reserved for future use, must be zero */ + spx_int32_t reserved2; /**< Reserved for future use, must be zero */ +} SpeexHeader; + +/** Initializes a SpeexHeader using basic information */ +void speex_init_header(SpeexHeader *header, int rate, int nb_channels, const struct SpeexMode *m); + +/** Creates the header packet from the header itself (mostly involves endianness conversion) */ +char *speex_header_to_packet(SpeexHeader *header, int *size); + +/** Creates a SpeexHeader from a packet */ +SpeexHeader *speex_packet_to_header(char *packet, int size); + +/** Frees the memory allocated by either speex_header_to_packet() or speex_packet_to_header() */ +void speex_header_free(void *ptr); + +#ifdef __cplusplus +} +#endif + +/** @} */ +#endif diff --git a/android/app/src/main/jni/include/speex/speex_jitter.h b/android/app/src/main/jni/include/speex/speex_jitter.h new file mode 100644 index 000000000..d68674b13 --- /dev/null +++ b/android/app/src/main/jni/include/speex/speex_jitter.h @@ -0,0 +1,197 @@ +/* Copyright (C) 2002 Jean-Marc Valin */ +/** + @file speex_jitter.h + @brief Adaptive jitter buffer for Speex +*/ +/* + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + - Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + - Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + - Neither the name of the Xiph.org Foundation nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR + CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +*/ + +#ifndef SPEEX_JITTER_H +#define SPEEX_JITTER_H +/** @defgroup JitterBuffer JitterBuffer: Adaptive jitter buffer + * This is the jitter buffer that reorders UDP/RTP packets and adjusts the buffer size + * to maintain good quality and low latency. + * @{ + */ + +#include "speex/speex_types.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** Generic adaptive jitter buffer state */ +struct JitterBuffer_; + +/** Generic adaptive jitter buffer state */ +typedef struct JitterBuffer_ JitterBuffer; + +/** Definition of an incoming packet */ +typedef struct _JitterBufferPacket JitterBufferPacket; + +/** Definition of an incoming packet */ +struct _JitterBufferPacket { + char *data; /**< Data bytes contained in the packet */ + spx_uint32_t len; /**< Length of the packet in bytes */ + spx_uint32_t timestamp; /**< Timestamp for the packet */ + spx_uint32_t span; /**< Time covered by the packet (same units as timestamp) */ + spx_uint16_t sequence; /**< RTP Sequence number if available (0 otherwise) */ + spx_uint32_t user_data; /**< Put whatever data you like here (it's ignored by the jitter buffer) */ +}; + +/** Packet has been retrieved */ +#define JITTER_BUFFER_OK 0 +/** Packet is lost or is late */ +#define JITTER_BUFFER_MISSING 1 +/** A "fake" packet is meant to be inserted here to increase buffering */ +#define JITTER_BUFFER_INSERTION 2 +/** There was an error in the jitter buffer */ +#define JITTER_BUFFER_INTERNAL_ERROR -1 +/** Invalid argument */ +#define JITTER_BUFFER_BAD_ARGUMENT -2 + + +/** Set minimum amount of extra buffering required (margin) */ +#define JITTER_BUFFER_SET_MARGIN 0 +/** Get minimum amount of extra buffering required (margin) */ +#define JITTER_BUFFER_GET_MARGIN 1 +/* JITTER_BUFFER_SET_AVAILABLE_COUNT wouldn't make sense */ + +/** Get the amount of available packets currently buffered */ +#define JITTER_BUFFER_GET_AVAILABLE_COUNT 3 +/** Included because of an early misspelling (will remove in next release) */ +#define JITTER_BUFFER_GET_AVALIABLE_COUNT 3 + +/** Assign a function to destroy unused packet. When setting that, the jitter + buffer no longer copies packet data. */ +#define JITTER_BUFFER_SET_DESTROY_CALLBACK 4 +/** */ +#define JITTER_BUFFER_GET_DESTROY_CALLBACK 5 + +/** Tell the jitter buffer to only adjust the delay in multiples of the step parameter provided */ +#define JITTER_BUFFER_SET_DELAY_STEP 6 +/** */ +#define JITTER_BUFFER_GET_DELAY_STEP 7 + +/** Tell the jitter buffer to only do concealment in multiples of the size parameter provided */ +#define JITTER_BUFFER_SET_CONCEALMENT_SIZE 8 +#define JITTER_BUFFER_GET_CONCEALMENT_SIZE 9 + +/** Absolute max amount of loss that can be tolerated regardless of the delay. Typical loss + should be half of that or less. */ +#define JITTER_BUFFER_SET_MAX_LATE_RATE 10 +#define JITTER_BUFFER_GET_MAX_LATE_RATE 11 + +/** Equivalent cost of one percent late packet in timestamp units */ +#define JITTER_BUFFER_SET_LATE_COST 12 +#define JITTER_BUFFER_GET_LATE_COST 13 + + +/** Initialises jitter buffer + * + * @param step_size Starting value for the size of concleanment packets and delay + adjustment steps. Can be changed at any time using JITTER_BUFFER_SET_DELAY_STEP + and JITTER_BUFFER_GET_CONCEALMENT_SIZE. + * @return Newly created jitter buffer state + */ +JitterBuffer *jitter_buffer_init(int step_size); + +/** Restores jitter buffer to its original state + * + * @param jitter Jitter buffer state + */ +void jitter_buffer_reset(JitterBuffer *jitter); + +/** Destroys jitter buffer + * + * @param jitter Jitter buffer state + */ +void jitter_buffer_destroy(JitterBuffer *jitter); + +/** Put one packet into the jitter buffer + * + * @param jitter Jitter buffer state + * @param packet Incoming packet +*/ +void jitter_buffer_put(JitterBuffer *jitter, const JitterBufferPacket *packet); + +/** Get one packet from the jitter buffer + * + * @param jitter Jitter buffer state + * @param packet Returned packet + * @param desired_span Number of samples (or units) we wish to get from the buffer (no guarantee) + * @param current_timestamp Timestamp for the returned packet +*/ +int jitter_buffer_get(JitterBuffer *jitter, JitterBufferPacket *packet, spx_int32_t desired_span, spx_int32_t *start_offset); + +/** Used right after jitter_buffer_get() to obtain another packet that would have the same timestamp. + * This is mainly useful for media where a single "frame" can be split into several packets. + * + * @param jitter Jitter buffer state + * @param packet Returned packet + */ +int jitter_buffer_get_another(JitterBuffer *jitter, JitterBufferPacket *packet); + +/** Get pointer timestamp of jitter buffer + * + * @param jitter Jitter buffer state +*/ +int jitter_buffer_get_pointer_timestamp(JitterBuffer *jitter); + +/** Advance by one tick + * + * @param jitter Jitter buffer state +*/ +void jitter_buffer_tick(JitterBuffer *jitter); + +/** Telling the jitter buffer about the remaining data in the application buffer + * @param jitter Jitter buffer state + * @param rem Amount of data buffered by the application (timestamp units) + */ +void jitter_buffer_remaining_span(JitterBuffer *jitter, spx_uint32_t rem); + +/** Used like the ioctl function to control the jitter buffer parameters + * + * @param jitter Jitter buffer state + * @param request ioctl-type request (one of the JITTER_BUFFER_* macros) + * @param ptr Data exchanged to-from function + * @return 0 if no error, -1 if request in unknown +*/ +int jitter_buffer_ctl(JitterBuffer *jitter, int request, void *ptr); + +int jitter_buffer_update_delay(JitterBuffer *jitter, JitterBufferPacket *packet, spx_int32_t *start_offset); + +/* @} */ + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/android/app/src/main/jni/include/speex/speex_preprocess.h b/android/app/src/main/jni/include/speex/speex_preprocess.h new file mode 100644 index 000000000..f8eef2cd9 --- /dev/null +++ b/android/app/src/main/jni/include/speex/speex_preprocess.h @@ -0,0 +1,219 @@ +/* Copyright (C) 2003 Epic Games + Written by Jean-Marc Valin */ +/** + * @file speex_preprocess.h + * @brief Speex preprocessor. The preprocess can do noise suppression, + * residual echo suppression (after using the echo canceller), automatic + * gain control (AGC) and voice activity detection (VAD). +*/ +/* + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are + met: + + 1. Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + 3. The name of the author may not be used to endorse or promote products + derived from this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, + INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + POSSIBILITY OF SUCH DAMAGE. +*/ + +#ifndef SPEEX_PREPROCESS_H +#define SPEEX_PREPROCESS_H +/** @defgroup SpeexPreprocessState SpeexPreprocessState: The Speex preprocessor + * This is the Speex preprocessor. The preprocess can do noise suppression, + * residual echo suppression (after using the echo canceller), automatic + * gain control (AGC) and voice activity detection (VAD). + * @{ + */ + +#include "speex/speex_types.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** State of the preprocessor (one per channel). Should never be accessed directly. */ +struct SpeexPreprocessState_; + +/** State of the preprocessor (one per channel). Should never be accessed directly. */ +typedef struct SpeexPreprocessState_ SpeexPreprocessState; + + +/** Creates a new preprocessing state. You MUST create one state per channel processed. + * @param frame_size Number of samples to process at one time (should correspond to 10-20 ms). Must be + * the same value as that used for the echo canceller for residual echo cancellation to work. + * @param sampling_rate Sampling rate used for the input. + * @return Newly created preprocessor state +*/ +SpeexPreprocessState *speex_preprocess_state_init(int frame_size, int sampling_rate); + +/** Destroys a preprocessor state + * @param st Preprocessor state to destroy +*/ +void speex_preprocess_state_destroy(SpeexPreprocessState *st); + +/** Preprocess a frame + * @param st Preprocessor state + * @param x Audio sample vector (in and out). Must be same size as specified in speex_preprocess_state_init(). + * @return Bool value for voice activity (1 for speech, 0 for noise/silence), ONLY if VAD turned on. +*/ +int speex_preprocess_run(SpeexPreprocessState *st, spx_int16_t *x); + +/** Preprocess a frame (deprecated, use speex_preprocess_run() instead)*/ +int speex_preprocess(SpeexPreprocessState *st, spx_int16_t *x, spx_int32_t *echo); + +/** Update preprocessor state, but do not compute the output + * @param st Preprocessor state + * @param x Audio sample vector (in only). Must be same size as specified in speex_preprocess_state_init(). +*/ +void speex_preprocess_estimate_update(SpeexPreprocessState *st, spx_int16_t *x); + +/** Used like the ioctl function to control the preprocessor parameters + * @param st Preprocessor state + * @param request ioctl-type request (one of the SPEEX_PREPROCESS_* macros) + * @param ptr Data exchanged to-from function + * @return 0 if no error, -1 if request in unknown +*/ +int speex_preprocess_ctl(SpeexPreprocessState *st, int request, void *ptr); + + + +/** Set preprocessor denoiser state */ +#define SPEEX_PREPROCESS_SET_DENOISE 0 +/** Get preprocessor denoiser state */ +#define SPEEX_PREPROCESS_GET_DENOISE 1 + +/** Set preprocessor Automatic Gain Control state */ +#define SPEEX_PREPROCESS_SET_AGC 2 +/** Get preprocessor Automatic Gain Control state */ +#define SPEEX_PREPROCESS_GET_AGC 3 + +/** Set preprocessor Voice Activity Detection state */ +#define SPEEX_PREPROCESS_SET_VAD 4 +/** Get preprocessor Voice Activity Detection state */ +#define SPEEX_PREPROCESS_GET_VAD 5 + +/** Set preprocessor Automatic Gain Control level (float) */ +#define SPEEX_PREPROCESS_SET_AGC_LEVEL 6 +/** Get preprocessor Automatic Gain Control level (float) */ +#define SPEEX_PREPROCESS_GET_AGC_LEVEL 7 + +/** Set preprocessor dereverb state */ +#define SPEEX_PREPROCESS_SET_DEREVERB 8 +/** Get preprocessor dereverb state */ +#define SPEEX_PREPROCESS_GET_DEREVERB 9 + +/** Set preprocessor dereverb level */ +#define SPEEX_PREPROCESS_SET_DEREVERB_LEVEL 10 +/** Get preprocessor dereverb level */ +#define SPEEX_PREPROCESS_GET_DEREVERB_LEVEL 11 + +/** Set preprocessor dereverb decay */ +#define SPEEX_PREPROCESS_SET_DEREVERB_DECAY 12 +/** Get preprocessor dereverb decay */ +#define SPEEX_PREPROCESS_GET_DEREVERB_DECAY 13 + +/** Set probability required for the VAD to go from silence to voice */ +#define SPEEX_PREPROCESS_SET_PROB_START 14 +/** Get probability required for the VAD to go from silence to voice */ +#define SPEEX_PREPROCESS_GET_PROB_START 15 + +/** Set probability required for the VAD to stay in the voice state (integer percent) */ +#define SPEEX_PREPROCESS_SET_PROB_CONTINUE 16 +/** Get probability required for the VAD to stay in the voice state (integer percent) */ +#define SPEEX_PREPROCESS_GET_PROB_CONTINUE 17 + +/** Set maximum attenuation of the noise in dB (negative number) */ +#define SPEEX_PREPROCESS_SET_NOISE_SUPPRESS 18 +/** Get maximum attenuation of the noise in dB (negative number) */ +#define SPEEX_PREPROCESS_GET_NOISE_SUPPRESS 19 + +/** Set maximum attenuation of the residual echo in dB (negative number) */ +#define SPEEX_PREPROCESS_SET_ECHO_SUPPRESS 20 +/** Get maximum attenuation of the residual echo in dB (negative number) */ +#define SPEEX_PREPROCESS_GET_ECHO_SUPPRESS 21 + +/** Set maximum attenuation of the residual echo in dB when near end is active (negative number) */ +#define SPEEX_PREPROCESS_SET_ECHO_SUPPRESS_ACTIVE 22 +/** Get maximum attenuation of the residual echo in dB when near end is active (negative number) */ +#define SPEEX_PREPROCESS_GET_ECHO_SUPPRESS_ACTIVE 23 + +/** Set the corresponding echo canceller state so that residual echo suppression can be performed (NULL for no residual echo suppression) */ +#define SPEEX_PREPROCESS_SET_ECHO_STATE 24 +/** Get the corresponding echo canceller state */ +#define SPEEX_PREPROCESS_GET_ECHO_STATE 25 + +/** Set maximal gain increase in dB/second (int32) */ +#define SPEEX_PREPROCESS_SET_AGC_INCREMENT 26 + +/** Get maximal gain increase in dB/second (int32) */ +#define SPEEX_PREPROCESS_GET_AGC_INCREMENT 27 + +/** Set maximal gain decrease in dB/second (int32) */ +#define SPEEX_PREPROCESS_SET_AGC_DECREMENT 28 + +/** Get maximal gain decrease in dB/second (int32) */ +#define SPEEX_PREPROCESS_GET_AGC_DECREMENT 29 + +/** Set maximal gain in dB (int32) */ +#define SPEEX_PREPROCESS_SET_AGC_MAX_GAIN 30 + +/** Get maximal gain in dB (int32) */ +#define SPEEX_PREPROCESS_GET_AGC_MAX_GAIN 31 + +/* Can't set loudness */ +/** Get loudness */ +#define SPEEX_PREPROCESS_GET_AGC_LOUDNESS 33 + +/* Can't set gain */ +/** Get current gain (int32 percent) */ +#define SPEEX_PREPROCESS_GET_AGC_GAIN 35 + +/* Can't set spectrum size */ +/** Get spectrum size for power spectrum (int32) */ +#define SPEEX_PREPROCESS_GET_PSD_SIZE 37 + +/* Can't set power spectrum */ +/** Get power spectrum (int32[] of squared values) */ +#define SPEEX_PREPROCESS_GET_PSD 39 + +/* Can't set noise size */ +/** Get spectrum size for noise estimate (int32) */ +#define SPEEX_PREPROCESS_GET_NOISE_PSD_SIZE 41 + +/* Can't set noise estimate */ +/** Get noise estimate (int32[] of squared values) */ +#define SPEEX_PREPROCESS_GET_NOISE_PSD 43 + +/* Can't set speech probability */ +/** Get speech probability in last frame (int32). */ +#define SPEEX_PREPROCESS_GET_PROB 45 + +/** Set preprocessor Automatic Gain Control level (int32) */ +#define SPEEX_PREPROCESS_SET_AGC_TARGET 46 +/** Get preprocessor Automatic Gain Control level (int32) */ +#define SPEEX_PREPROCESS_GET_AGC_TARGET 47 + +#ifdef __cplusplus +} +#endif + +/** @}*/ +#endif diff --git a/android/app/src/main/jni/include/speex/speex_resampler.h b/android/app/src/main/jni/include/speex/speex_resampler.h new file mode 100644 index 000000000..54eef8d7b --- /dev/null +++ b/android/app/src/main/jni/include/speex/speex_resampler.h @@ -0,0 +1,340 @@ +/* Copyright (C) 2007 Jean-Marc Valin + + File: speex_resampler.h + Resampling code + + The design goals of this code are: + - Very fast algorithm + - Low memory requirement + - Good *perceptual* quality (and not best SNR) + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are + met: + + 1. Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + 3. The name of the author may not be used to endorse or promote products + derived from this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, + INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + POSSIBILITY OF SUCH DAMAGE. +*/ + + +#ifndef SPEEX_RESAMPLER_H +#define SPEEX_RESAMPLER_H + +#ifdef OUTSIDE_SPEEX + +/********* WARNING: MENTAL SANITY ENDS HERE *************/ + +/* If the resampler is defined outside of Speex, we change the symbol names so that + there won't be any clash if linking with Speex later on. */ + +/* #define RANDOM_PREFIX your software name here */ +#ifndef RANDOM_PREFIX +#error "Please define RANDOM_PREFIX (above) to something specific to your project to prevent symbol name clashes" +#endif + +#define CAT_PREFIX2(a,b) a ## b +#define CAT_PREFIX(a,b) CAT_PREFIX2(a, b) + +#define speex_resampler_init CAT_PREFIX(RANDOM_PREFIX,_resampler_init) +#define speex_resampler_init_frac CAT_PREFIX(RANDOM_PREFIX,_resampler_init_frac) +#define speex_resampler_destroy CAT_PREFIX(RANDOM_PREFIX,_resampler_destroy) +#define speex_resampler_process_float CAT_PREFIX(RANDOM_PREFIX,_resampler_process_float) +#define speex_resampler_process_int CAT_PREFIX(RANDOM_PREFIX,_resampler_process_int) +#define speex_resampler_process_interleaved_float CAT_PREFIX(RANDOM_PREFIX,_resampler_process_interleaved_float) +#define speex_resampler_process_interleaved_int CAT_PREFIX(RANDOM_PREFIX,_resampler_process_interleaved_int) +#define speex_resampler_set_rate CAT_PREFIX(RANDOM_PREFIX,_resampler_set_rate) +#define speex_resampler_get_rate CAT_PREFIX(RANDOM_PREFIX,_resampler_get_rate) +#define speex_resampler_set_rate_frac CAT_PREFIX(RANDOM_PREFIX,_resampler_set_rate_frac) +#define speex_resampler_get_ratio CAT_PREFIX(RANDOM_PREFIX,_resampler_get_ratio) +#define speex_resampler_set_quality CAT_PREFIX(RANDOM_PREFIX,_resampler_set_quality) +#define speex_resampler_get_quality CAT_PREFIX(RANDOM_PREFIX,_resampler_get_quality) +#define speex_resampler_set_input_stride CAT_PREFIX(RANDOM_PREFIX,_resampler_set_input_stride) +#define speex_resampler_get_input_stride CAT_PREFIX(RANDOM_PREFIX,_resampler_get_input_stride) +#define speex_resampler_set_output_stride CAT_PREFIX(RANDOM_PREFIX,_resampler_set_output_stride) +#define speex_resampler_get_output_stride CAT_PREFIX(RANDOM_PREFIX,_resampler_get_output_stride) +#define speex_resampler_get_input_latency CAT_PREFIX(RANDOM_PREFIX,_resampler_get_input_latency) +#define speex_resampler_get_output_latency CAT_PREFIX(RANDOM_PREFIX,_resampler_get_output_latency) +#define speex_resampler_skip_zeros CAT_PREFIX(RANDOM_PREFIX,_resampler_skip_zeros) +#define speex_resampler_reset_mem CAT_PREFIX(RANDOM_PREFIX,_resampler_reset_mem) +#define speex_resampler_strerror CAT_PREFIX(RANDOM_PREFIX,_resampler_strerror) + +#define spx_int16_t short +#define spx_int32_t int +#define spx_uint16_t unsigned short +#define spx_uint32_t unsigned int + +#else /* OUTSIDE_SPEEX */ + +#include "speex/speex_types.h" + +#endif /* OUTSIDE_SPEEX */ + +#ifdef __cplusplus +extern "C" { +#endif + +#define SPEEX_RESAMPLER_QUALITY_MAX 10 +#define SPEEX_RESAMPLER_QUALITY_MIN 0 +#define SPEEX_RESAMPLER_QUALITY_DEFAULT 4 +#define SPEEX_RESAMPLER_QUALITY_VOIP 3 +#define SPEEX_RESAMPLER_QUALITY_DESKTOP 5 + +enum { + RESAMPLER_ERR_SUCCESS = 0, + RESAMPLER_ERR_ALLOC_FAILED = 1, + RESAMPLER_ERR_BAD_STATE = 2, + RESAMPLER_ERR_INVALID_ARG = 3, + RESAMPLER_ERR_PTR_OVERLAP = 4, + + RESAMPLER_ERR_MAX_ERROR +}; + +struct SpeexResamplerState_; +typedef struct SpeexResamplerState_ SpeexResamplerState; + +/** Create a new resampler with integer input and output rates. + * @param nb_channels Number of channels to be processed + * @param in_rate Input sampling rate (integer number of Hz). + * @param out_rate Output sampling rate (integer number of Hz). + * @param quality Resampling quality between 0 and 10, where 0 has poor quality + * and 10 has very high quality. + * @return Newly created resampler state + * @retval NULL Error: not enough memory + */ +SpeexResamplerState *speex_resampler_init(spx_uint32_t nb_channels, + spx_uint32_t in_rate, + spx_uint32_t out_rate, + int quality, + int *err); + +/** Create a new resampler with fractional input/output rates. The sampling + * rate ratio is an arbitrary rational number with both the numerator and + * denominator being 32-bit integers. + * @param nb_channels Number of channels to be processed + * @param ratio_num Numerator of the sampling rate ratio + * @param ratio_den Denominator of the sampling rate ratio + * @param in_rate Input sampling rate rounded to the nearest integer (in Hz). + * @param out_rate Output sampling rate rounded to the nearest integer (in Hz). + * @param quality Resampling quality between 0 and 10, where 0 has poor quality + * and 10 has very high quality. + * @return Newly created resampler state + * @retval NULL Error: not enough memory + */ +SpeexResamplerState *speex_resampler_init_frac(spx_uint32_t nb_channels, + spx_uint32_t ratio_num, + spx_uint32_t ratio_den, + spx_uint32_t in_rate, + spx_uint32_t out_rate, + int quality, + int *err); + +/** Destroy a resampler state. + * @param st Resampler state + */ +void speex_resampler_destroy(SpeexResamplerState *st); + +/** Resample a float array. The input and output buffers must *not* overlap. + * @param st Resampler state + * @param channel_index Index of the channel to process for the multi-channel + * base (0 otherwise) + * @param in Input buffer + * @param in_len Number of input samples in the input buffer. Returns the + * number of samples processed + * @param out Output buffer + * @param out_len Size of the output buffer. Returns the number of samples written + */ +int speex_resampler_process_float(SpeexResamplerState *st, + spx_uint32_t channel_index, + const float *in, + spx_uint32_t *in_len, + float *out, + spx_uint32_t *out_len); + +/** Resample an int array. The input and output buffers must *not* overlap. + * @param st Resampler state + * @param channel_index Index of the channel to process for the multi-channel + * base (0 otherwise) + * @param in Input buffer + * @param in_len Number of input samples in the input buffer. Returns the number + * of samples processed + * @param out Output buffer + * @param out_len Size of the output buffer. Returns the number of samples written + */ +int speex_resampler_process_int(SpeexResamplerState *st, + spx_uint32_t channel_index, + const spx_int16_t *in, + spx_uint32_t *in_len, + spx_int16_t *out, + spx_uint32_t *out_len); + +/** Resample an interleaved float array. The input and output buffers must *not* overlap. + * @param st Resampler state + * @param in Input buffer + * @param in_len Number of input samples in the input buffer. Returns the number + * of samples processed. This is all per-channel. + * @param out Output buffer + * @param out_len Size of the output buffer. Returns the number of samples written. + * This is all per-channel. + */ +int speex_resampler_process_interleaved_float(SpeexResamplerState *st, + const float *in, + spx_uint32_t *in_len, + float *out, + spx_uint32_t *out_len); + +/** Resample an interleaved int array. The input and output buffers must *not* overlap. + * @param st Resampler state + * @param in Input buffer + * @param in_len Number of input samples in the input buffer. Returns the number + * of samples processed. This is all per-channel. + * @param out Output buffer + * @param out_len Size of the output buffer. Returns the number of samples written. + * This is all per-channel. + */ +int speex_resampler_process_interleaved_int(SpeexResamplerState *st, + const spx_int16_t *in, + spx_uint32_t *in_len, + spx_int16_t *out, + spx_uint32_t *out_len); + +/** Set (change) the input/output sampling rates (integer value). + * @param st Resampler state + * @param in_rate Input sampling rate (integer number of Hz). + * @param out_rate Output sampling rate (integer number of Hz). + */ +int speex_resampler_set_rate(SpeexResamplerState *st, + spx_uint32_t in_rate, + spx_uint32_t out_rate); + +/** Get the current input/output sampling rates (integer value). + * @param st Resampler state + * @param in_rate Input sampling rate (integer number of Hz) copied. + * @param out_rate Output sampling rate (integer number of Hz) copied. + */ +void speex_resampler_get_rate(SpeexResamplerState *st, + spx_uint32_t *in_rate, + spx_uint32_t *out_rate); + +/** Set (change) the input/output sampling rates and resampling ratio + * (fractional values in Hz supported). + * @param st Resampler state + * @param ratio_num Numerator of the sampling rate ratio + * @param ratio_den Denominator of the sampling rate ratio + * @param in_rate Input sampling rate rounded to the nearest integer (in Hz). + * @param out_rate Output sampling rate rounded to the nearest integer (in Hz). + */ +int speex_resampler_set_rate_frac(SpeexResamplerState *st, + spx_uint32_t ratio_num, + spx_uint32_t ratio_den, + spx_uint32_t in_rate, + spx_uint32_t out_rate); + +/** Get the current resampling ratio. This will be reduced to the least + * common denominator. + * @param st Resampler state + * @param ratio_num Numerator of the sampling rate ratio copied + * @param ratio_den Denominator of the sampling rate ratio copied + */ +void speex_resampler_get_ratio(SpeexResamplerState *st, + spx_uint32_t *ratio_num, + spx_uint32_t *ratio_den); + +/** Set (change) the conversion quality. + * @param st Resampler state + * @param quality Resampling quality between 0 and 10, where 0 has poor + * quality and 10 has very high quality. + */ +int speex_resampler_set_quality(SpeexResamplerState *st, + int quality); + +/** Get the conversion quality. + * @param st Resampler state + * @param quality Resampling quality between 0 and 10, where 0 has poor + * quality and 10 has very high quality. + */ +void speex_resampler_get_quality(SpeexResamplerState *st, + int *quality); + +/** Set (change) the input stride. + * @param st Resampler state + * @param stride Input stride + */ +void speex_resampler_set_input_stride(SpeexResamplerState *st, + spx_uint32_t stride); + +/** Get the input stride. + * @param st Resampler state + * @param stride Input stride copied + */ +void speex_resampler_get_input_stride(SpeexResamplerState *st, + spx_uint32_t *stride); + +/** Set (change) the output stride. + * @param st Resampler state + * @param stride Output stride + */ +void speex_resampler_set_output_stride(SpeexResamplerState *st, + spx_uint32_t stride); + +/** Get the output stride. + * @param st Resampler state copied + * @param stride Output stride + */ +void speex_resampler_get_output_stride(SpeexResamplerState *st, + spx_uint32_t *stride); + +/** Get the latency in input samples introduced by the resampler. + * @param st Resampler state + */ +int speex_resampler_get_input_latency(SpeexResamplerState *st); + +/** Get the latency in output samples introduced by the resampler. + * @param st Resampler state + */ +int speex_resampler_get_output_latency(SpeexResamplerState *st); + +/** Make sure that the first samples to go out of the resamplers don't have + * leading zeros. This is only useful before starting to use a newly created + * resampler. It is recommended to use that when resampling an audio file, as + * it will generate a file with the same length. For real-time processing, + * it is probably easier not to use this call (so that the output duration + * is the same for the first frame). + * @param st Resampler state + */ +int speex_resampler_skip_zeros(SpeexResamplerState *st); + +/** Reset a resampler so a new (unrelated) stream can be processed. + * @param st Resampler state + */ +int speex_resampler_reset_mem(SpeexResamplerState *st); + +/** Returns the English meaning for an error code + * @param err Error code + * @return English string + */ +const char *speex_resampler_strerror(int err); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/android/app/src/main/jni/include/speex/speex_stereo.h b/android/app/src/main/jni/include/speex/speex_stereo.h new file mode 100644 index 000000000..a259713b8 --- /dev/null +++ b/android/app/src/main/jni/include/speex/speex_stereo.h @@ -0,0 +1,91 @@ +/* Copyright (C) 2002 Jean-Marc Valin*/ +/** + @file speex_stereo.h + @brief Describes the handling for intensity stereo +*/ +/* + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + - Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + - Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + - Neither the name of the Xiph.org Foundation nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR + CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#ifndef STEREO_H +#define STEREO_H +/** @defgroup SpeexStereoState SpeexStereoState: Handling Speex stereo files + * This describes the Speex intensity stereo encoding/decoding + * @{ + */ + +#include "speex/speex_types.h" +#include "speex/speex_bits.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** If you access any of these fields directly, I'll personally come and bite you */ +typedef struct SpeexStereoState { + float balance; /**< Left/right balance info */ + float e_ratio; /**< Ratio of energies: E(left+right)/[E(left)+E(right)] */ + float smooth_left; /**< Smoothed left channel gain */ + float smooth_right; /**< Smoothed right channel gain */ + float reserved1; /**< Reserved for future use */ + float reserved2; /**< Reserved for future use */ +} SpeexStereoState; + +/** Deprecated. Use speex_stereo_state_init() instead. */ +#define SPEEX_STEREO_STATE_INIT {1,.5,1,1,0,0} + +/** Initialise/create a stereo stereo state */ +SpeexStereoState *speex_stereo_state_init(); + +/** Reset/re-initialise an already allocated stereo state */ +void speex_stereo_state_reset(SpeexStereoState *stereo); + +/** Destroy a stereo stereo state */ +void speex_stereo_state_destroy(SpeexStereoState *stereo); + +/** Transforms a stereo frame into a mono frame and stores intensity stereo info in 'bits' */ +void speex_encode_stereo(float *data, int frame_size, SpeexBits *bits); + +/** Transforms a stereo frame into a mono frame and stores intensity stereo info in 'bits' */ +void speex_encode_stereo_int(spx_int16_t *data, int frame_size, SpeexBits *bits); + +/** Transforms a mono frame into a stereo frame using intensity stereo info */ +void speex_decode_stereo(float *data, int frame_size, SpeexStereoState *stereo); + +/** Transforms a mono frame into a stereo frame using intensity stereo info */ +void speex_decode_stereo_int(spx_int16_t *data, int frame_size, SpeexStereoState *stereo); + +/** Callback handler for intensity stereo info */ +int speex_std_stereo_request_handler(SpeexBits *bits, void *state, void *data); + +#ifdef __cplusplus +} +#endif + +/** @} */ +#endif diff --git a/android/app/src/main/jni/include/speex/speex_types.h b/android/app/src/main/jni/include/speex/speex_types.h new file mode 100644 index 000000000..e90b1131a --- /dev/null +++ b/android/app/src/main/jni/include/speex/speex_types.h @@ -0,0 +1,126 @@ +/* speex_types.h taken from libogg */ +/******************************************************************** + * * + * THIS FILE IS PART OF THE OggVorbis SOFTWARE CODEC SOURCE CODE. * + * USE, DISTRIBUTION AND REPRODUCTION OF THIS LIBRARY SOURCE IS * + * GOVERNED BY A BSD-STYLE SOURCE LICENSE INCLUDED WITH THIS SOURCE * + * IN 'COPYING'. PLEASE READ THESE TERMS BEFORE DISTRIBUTING. * + * * + * THE OggVorbis SOURCE CODE IS (C) COPYRIGHT 1994-2002 * + * by the Xiph.Org Foundation http://www.xiph.org/ * + * * + ******************************************************************** + + function: #ifdef jail to whip a few platforms into the UNIX ideal. + last mod: $Id: os_types.h 7524 2004-08-11 04:20:36Z conrad $ + + ********************************************************************/ +/** + @file speex_types.h + @brief Speex types +*/ +#ifndef _SPEEX_TYPES_H +#define _SPEEX_TYPES_H + +#if defined(_WIN32) + +# if defined(__CYGWIN__) +# include <_G_config.h> + typedef _G_int32_t spx_int32_t; + typedef _G_uint32_t spx_uint32_t; + typedef _G_int16_t spx_int16_t; + typedef _G_uint16_t spx_uint16_t; +# elif defined(__MINGW32__) + typedef short spx_int16_t; + typedef unsigned short spx_uint16_t; + typedef int spx_int32_t; + typedef unsigned int spx_uint32_t; +# elif defined(__MWERKS__) + typedef int spx_int32_t; + typedef unsigned int spx_uint32_t; + typedef short spx_int16_t; + typedef unsigned short spx_uint16_t; +# else + /* MSVC/Borland */ + typedef __int32 spx_int32_t; + typedef unsigned __int32 spx_uint32_t; + typedef __int16 spx_int16_t; + typedef unsigned __int16 spx_uint16_t; +# endif + +#elif defined(__MACOS__) + +# include + typedef SInt16 spx_int16_t; + typedef UInt16 spx_uint16_t; + typedef SInt32 spx_int32_t; + typedef UInt32 spx_uint32_t; + +#elif (defined(__APPLE__) && defined(__MACH__)) /* MacOS X Framework build */ + +# include + typedef int16_t spx_int16_t; + typedef u_int16_t spx_uint16_t; + typedef int32_t spx_int32_t; + typedef u_int32_t spx_uint32_t; + +#elif defined(__BEOS__) + + /* Be */ +# include + typedef int16_t spx_int16_t; + typedef u_int16_t spx_uint16_t; + typedef int32_t spx_int32_t; + typedef u_int32_t spx_uint32_t; + +#elif defined (__EMX__) + + /* OS/2 GCC */ + typedef short spx_int16_t; + typedef unsigned short spx_uint16_t; + typedef int spx_int32_t; + typedef unsigned int spx_uint32_t; + +#elif defined (DJGPP) + + /* DJGPP */ + typedef short spx_int16_t; + typedef int spx_int32_t; + typedef unsigned int spx_uint32_t; + +#elif defined(R5900) + + /* PS2 EE */ + typedef int spx_int32_t; + typedef unsigned spx_uint32_t; + typedef short spx_int16_t; + +#elif defined(__SYMBIAN32__) + + /* Symbian GCC */ + typedef signed short spx_int16_t; + typedef unsigned short spx_uint16_t; + typedef signed int spx_int32_t; + typedef unsigned int spx_uint32_t; + +#elif defined(CONFIG_TI_C54X) || defined (CONFIG_TI_C55X) + + typedef short spx_int16_t; + typedef unsigned short spx_uint16_t; + typedef long spx_int32_t; + typedef unsigned long spx_uint32_t; + +#elif defined(CONFIG_TI_C6X) + + typedef short spx_int16_t; + typedef unsigned short spx_uint16_t; + typedef int spx_int32_t; + typedef unsigned int spx_uint32_t; + +#else + +# include "speex/speex_config_types.h" + +#endif + +#endif /* _SPEEX_TYPES_H */ diff --git a/android/app/src/main/jni/libspeex/Makefile.am b/android/app/src/main/jni/libspeex/Makefile.am new file mode 100644 index 000000000..3d4e03f9a --- /dev/null +++ b/android/app/src/main/jni/libspeex/Makefile.am @@ -0,0 +1,55 @@ +# Disable automatic dependency tracking if using other tools than gcc and gmake +#AUTOMAKE_OPTIONS = no-dependencies + + +EXTRA_DIST=echo_diagnostic.m + +INCLUDES = -I$(top_srcdir)/include -I$(top_builddir)/include -I$(top_builddir) @OGG_CFLAGS@ @FFT_CFLAGS@ + +lib_LTLIBRARIES = libspeex.la libspeexdsp.la + +# Sources for compilation in the library +libspeex_la_SOURCES = cb_search.c exc_10_32_table.c exc_8_128_table.c \ + filters.c gain_table.c hexc_table.c high_lsp_tables.c lsp.c \ + ltp.c speex.c stereo.c vbr.c vq.c bits.c exc_10_16_table.c \ + exc_20_32_table.c exc_5_256_table.c exc_5_64_table.c gain_table_lbr.c hexc_10_32_table.c \ + lpc.c lsp_tables_nb.c modes.c modes_wb.c nb_celp.c quant_lsp.c sb_celp.c \ + speex_callbacks.c speex_header.c window.c + +if BUILD_KISS_FFT + FFTSRC=kiss_fft.c _kiss_fft_guts.h kiss_fft.h kiss_fftr.c kiss_fftr.h +else +if BUILD_SMALLFT + FFTSRC=smallft.c +else + FFTSRC= +endif +endif + +libspeexdsp_la_SOURCES = preprocess.c jitter.c mdf.c fftwrap.c filterbank.c resample.c buffer.c scal.c $(FFTSRC) + +noinst_HEADERS = arch.h cb_search_arm4.h cb_search_bfin.h cb_search_sse.h \ + filters.h filters_arm4.h filters_bfin.h filters_sse.h fixed_arm4.h \ + fixed_arm5e.h fixed_bfin.h fixed_debug.h lpc.h lpc_bfin.h ltp.h ltp_arm4.h \ + ltp_sse.h math_approx.h misc_bfin.h nb_celp.h quant_lsp.h sb_celp.h \ + stack_alloc.h vbr.h vq.h vq_arm4.h vq_bfin.h vq_sse.h cb_search.h fftwrap.h \ + filterbank.h fixed_generic.h lsp.h lsp_bfin.h ltp_bfin.h modes.h os_support.h \ + pseudofloat.h quant_lsp_bfin.h smallft.h vorbis_psy.h resample_sse.h + + +libspeex_la_LDFLAGS = -no-undefined -version-info @SPEEX_LT_CURRENT@:@SPEEX_LT_REVISION@:@SPEEX_LT_AGE@ +libspeexdsp_la_LDFLAGS = -no-undefined -version-info @SPEEX_LT_CURRENT@:@SPEEX_LT_REVISION@:@SPEEX_LT_AGE@ + +noinst_PROGRAMS = testenc testenc_wb testenc_uwb testdenoise testecho testjitter +testenc_SOURCES = testenc.c +testenc_LDADD = libspeex.la +testenc_wb_SOURCES = testenc_wb.c +testenc_wb_LDADD = libspeex.la +testenc_uwb_SOURCES = testenc_uwb.c +testenc_uwb_LDADD = libspeex.la +testdenoise_SOURCES = testdenoise.c +testdenoise_LDADD = libspeexdsp.la @FFT_LIBS@ +testecho_SOURCES = testecho.c +testecho_LDADD = libspeexdsp.la @FFT_LIBS@ +testjitter_SOURCES = testjitter.c +testjitter_LDADD = libspeexdsp.la @FFT_LIBS@ diff --git a/android/app/src/main/jni/libspeex/Makefile.in b/android/app/src/main/jni/libspeex/Makefile.in new file mode 100644 index 000000000..a1044a58d --- /dev/null +++ b/android/app/src/main/jni/libspeex/Makefile.in @@ -0,0 +1,667 @@ +# Makefile.in generated by automake 1.8.5 from Makefile.am. +# @configure_input@ + +# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, +# 2003, 2004 Free Software Foundation, Inc. +# This Makefile.in is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY, to the extent permitted by law; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. + +@SET_MAKE@ + +# Disable automatic dependency tracking if using other tools than gcc and gmake +#AUTOMAKE_OPTIONS = no-dependencies + + + +SOURCES = $(libspeex_la_SOURCES) $(libspeexdsp_la_SOURCES) $(testdenoise_SOURCES) $(testecho_SOURCES) $(testenc_SOURCES) $(testenc_uwb_SOURCES) $(testenc_wb_SOURCES) $(testjitter_SOURCES) + +srcdir = @srcdir@ +top_srcdir = @top_srcdir@ +VPATH = @srcdir@ +pkgdatadir = $(datadir)/@PACKAGE@ +pkglibdir = $(libdir)/@PACKAGE@ +pkgincludedir = $(includedir)/@PACKAGE@ +top_builddir = .. +am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd +INSTALL = @INSTALL@ +install_sh_DATA = $(install_sh) -c -m 644 +install_sh_PROGRAM = $(install_sh) -c +install_sh_SCRIPT = $(install_sh) -c +INSTALL_HEADER = $(INSTALL_DATA) +transform = $(program_transform_name) +NORMAL_INSTALL = : +PRE_INSTALL = : +POST_INSTALL = : +NORMAL_UNINSTALL = : +PRE_UNINSTALL = : +POST_UNINSTALL = : +host_triplet = @host@ +noinst_PROGRAMS = testenc$(EXEEXT) testenc_wb$(EXEEXT) \ + testenc_uwb$(EXEEXT) testdenoise$(EXEEXT) testecho$(EXEEXT) \ + testjitter$(EXEEXT) +subdir = libspeex +DIST_COMMON = $(noinst_HEADERS) $(srcdir)/Makefile.am \ + $(srcdir)/Makefile.in +ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 +am__aclocal_m4_deps = $(top_srcdir)/acinclude.m4 \ + $(top_srcdir)/configure.ac +am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ + $(ACLOCAL_M4) +mkinstalldirs = $(mkdir_p) +CONFIG_HEADER = $(top_builddir)/config.h +CONFIG_CLEAN_FILES = +am__installdirs = "$(DESTDIR)$(libdir)" +libLTLIBRARIES_INSTALL = $(INSTALL) +LTLIBRARIES = $(lib_LTLIBRARIES) +libspeex_la_LIBADD = +am_libspeex_la_OBJECTS = cb_search.lo exc_10_32_table.lo \ + exc_8_128_table.lo filters.lo gain_table.lo hexc_table.lo \ + high_lsp_tables.lo lsp.lo ltp.lo speex.lo stereo.lo vbr.lo \ + vq.lo bits.lo exc_10_16_table.lo exc_20_32_table.lo \ + exc_5_256_table.lo exc_5_64_table.lo gain_table_lbr.lo \ + hexc_10_32_table.lo lpc.lo lsp_tables_nb.lo modes.lo \ + modes_wb.lo nb_celp.lo quant_lsp.lo sb_celp.lo \ + speex_callbacks.lo speex_header.lo window.lo +libspeex_la_OBJECTS = $(am_libspeex_la_OBJECTS) +libspeexdsp_la_LIBADD = +am__libspeexdsp_la_SOURCES_DIST = preprocess.c jitter.c mdf.c \ + fftwrap.c filterbank.c resample.c buffer.c scal.c smallft.c \ + kiss_fft.c _kiss_fft_guts.h kiss_fft.h kiss_fftr.c kiss_fftr.h +@BUILD_KISS_FFT_FALSE@@BUILD_SMALLFT_TRUE@am__objects_1 = smallft.lo +@BUILD_KISS_FFT_TRUE@am__objects_1 = kiss_fft.lo kiss_fftr.lo +am_libspeexdsp_la_OBJECTS = preprocess.lo jitter.lo mdf.lo fftwrap.lo \ + filterbank.lo resample.lo buffer.lo scal.lo $(am__objects_1) +libspeexdsp_la_OBJECTS = $(am_libspeexdsp_la_OBJECTS) +PROGRAMS = $(noinst_PROGRAMS) +am_testdenoise_OBJECTS = testdenoise.$(OBJEXT) +testdenoise_OBJECTS = $(am_testdenoise_OBJECTS) +testdenoise_DEPENDENCIES = libspeexdsp.la +am_testecho_OBJECTS = testecho.$(OBJEXT) +testecho_OBJECTS = $(am_testecho_OBJECTS) +testecho_DEPENDENCIES = libspeexdsp.la +am_testenc_OBJECTS = testenc.$(OBJEXT) +testenc_OBJECTS = $(am_testenc_OBJECTS) +testenc_DEPENDENCIES = libspeex.la +am_testenc_uwb_OBJECTS = testenc_uwb.$(OBJEXT) +testenc_uwb_OBJECTS = $(am_testenc_uwb_OBJECTS) +testenc_uwb_DEPENDENCIES = libspeex.la +am_testenc_wb_OBJECTS = testenc_wb.$(OBJEXT) +testenc_wb_OBJECTS = $(am_testenc_wb_OBJECTS) +testenc_wb_DEPENDENCIES = libspeex.la +am_testjitter_OBJECTS = testjitter.$(OBJEXT) +testjitter_OBJECTS = $(am_testjitter_OBJECTS) +testjitter_DEPENDENCIES = libspeexdsp.la +DEFAULT_INCLUDES = -I. -I$(srcdir) -I$(top_builddir) +depcomp = $(SHELL) $(top_srcdir)/depcomp +am__depfiles_maybe = depfiles +@AMDEP_TRUE@DEP_FILES = ./$(DEPDIR)/bits.Plo ./$(DEPDIR)/buffer.Plo \ +@AMDEP_TRUE@ ./$(DEPDIR)/cb_search.Plo \ +@AMDEP_TRUE@ ./$(DEPDIR)/exc_10_16_table.Plo \ +@AMDEP_TRUE@ ./$(DEPDIR)/exc_10_32_table.Plo \ +@AMDEP_TRUE@ ./$(DEPDIR)/exc_20_32_table.Plo \ +@AMDEP_TRUE@ ./$(DEPDIR)/exc_5_256_table.Plo \ +@AMDEP_TRUE@ ./$(DEPDIR)/exc_5_64_table.Plo \ +@AMDEP_TRUE@ ./$(DEPDIR)/exc_8_128_table.Plo \ +@AMDEP_TRUE@ ./$(DEPDIR)/fftwrap.Plo ./$(DEPDIR)/filterbank.Plo \ +@AMDEP_TRUE@ ./$(DEPDIR)/filters.Plo ./$(DEPDIR)/gain_table.Plo \ +@AMDEP_TRUE@ ./$(DEPDIR)/gain_table_lbr.Plo \ +@AMDEP_TRUE@ ./$(DEPDIR)/hexc_10_32_table.Plo \ +@AMDEP_TRUE@ ./$(DEPDIR)/hexc_table.Plo \ +@AMDEP_TRUE@ ./$(DEPDIR)/high_lsp_tables.Plo \ +@AMDEP_TRUE@ ./$(DEPDIR)/jitter.Plo ./$(DEPDIR)/kiss_fft.Plo \ +@AMDEP_TRUE@ ./$(DEPDIR)/kiss_fftr.Plo ./$(DEPDIR)/lpc.Plo \ +@AMDEP_TRUE@ ./$(DEPDIR)/lsp.Plo ./$(DEPDIR)/lsp_tables_nb.Plo \ +@AMDEP_TRUE@ ./$(DEPDIR)/ltp.Plo ./$(DEPDIR)/mdf.Plo \ +@AMDEP_TRUE@ ./$(DEPDIR)/modes.Plo ./$(DEPDIR)/modes_wb.Plo \ +@AMDEP_TRUE@ ./$(DEPDIR)/nb_celp.Plo ./$(DEPDIR)/preprocess.Plo \ +@AMDEP_TRUE@ ./$(DEPDIR)/quant_lsp.Plo ./$(DEPDIR)/resample.Plo \ +@AMDEP_TRUE@ ./$(DEPDIR)/sb_celp.Plo ./$(DEPDIR)/scal.Plo \ +@AMDEP_TRUE@ ./$(DEPDIR)/smallft.Plo ./$(DEPDIR)/speex.Plo \ +@AMDEP_TRUE@ ./$(DEPDIR)/speex_callbacks.Plo \ +@AMDEP_TRUE@ ./$(DEPDIR)/speex_header.Plo \ +@AMDEP_TRUE@ ./$(DEPDIR)/stereo.Plo ./$(DEPDIR)/testdenoise.Po \ +@AMDEP_TRUE@ ./$(DEPDIR)/testecho.Po ./$(DEPDIR)/testenc.Po \ +@AMDEP_TRUE@ ./$(DEPDIR)/testenc_uwb.Po \ +@AMDEP_TRUE@ ./$(DEPDIR)/testenc_wb.Po \ +@AMDEP_TRUE@ ./$(DEPDIR)/testjitter.Po ./$(DEPDIR)/vbr.Plo \ +@AMDEP_TRUE@ ./$(DEPDIR)/vq.Plo ./$(DEPDIR)/window.Plo +COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ + $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) +LTCOMPILE = $(LIBTOOL) --mode=compile $(CC) $(DEFS) \ + $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \ + $(AM_CFLAGS) $(CFLAGS) +CCLD = $(CC) +LINK = $(LIBTOOL) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \ + $(AM_LDFLAGS) $(LDFLAGS) -o $@ +SOURCES = $(libspeex_la_SOURCES) $(libspeexdsp_la_SOURCES) \ + $(testdenoise_SOURCES) $(testecho_SOURCES) $(testenc_SOURCES) \ + $(testenc_uwb_SOURCES) $(testenc_wb_SOURCES) \ + $(testjitter_SOURCES) +DIST_SOURCES = $(libspeex_la_SOURCES) \ + $(am__libspeexdsp_la_SOURCES_DIST) $(testdenoise_SOURCES) \ + $(testecho_SOURCES) $(testenc_SOURCES) $(testenc_uwb_SOURCES) \ + $(testenc_wb_SOURCES) $(testjitter_SOURCES) +HEADERS = $(noinst_HEADERS) +ETAGS = etags +CTAGS = ctags +DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) +ACLOCAL = @ACLOCAL@ +AMDEP_FALSE = @AMDEP_FALSE@ +AMDEP_TRUE = @AMDEP_TRUE@ +AMTAR = @AMTAR@ +AR = @AR@ +AS = @AS@ +AUTOCONF = @AUTOCONF@ +AUTOHEADER = @AUTOHEADER@ +AUTOMAKE = @AUTOMAKE@ +AWK = @AWK@ +BUILD_KISS_FFT_FALSE = @BUILD_KISS_FFT_FALSE@ +BUILD_KISS_FFT_TRUE = @BUILD_KISS_FFT_TRUE@ +BUILD_SMALLFT_FALSE = @BUILD_SMALLFT_FALSE@ +BUILD_SMALLFT_TRUE = @BUILD_SMALLFT_TRUE@ +CC = @CC@ +CCDEPMODE = @CCDEPMODE@ +CFLAGS = @CFLAGS@ +CPP = @CPP@ +CPPFLAGS = @CPPFLAGS@ +CXX = @CXX@ +CXXCPP = @CXXCPP@ +CXXDEPMODE = @CXXDEPMODE@ +CXXFLAGS = @CXXFLAGS@ +CYGPATH_W = @CYGPATH_W@ +DEFS = @DEFS@ +DEPDIR = @DEPDIR@ +DLLTOOL = @DLLTOOL@ +DSYMUTIL = @DSYMUTIL@ +ECHO = @ECHO@ +ECHO_C = @ECHO_C@ +ECHO_N = @ECHO_N@ +ECHO_T = @ECHO_T@ +EGREP = @EGREP@ +EXEEXT = @EXEEXT@ +F77 = @F77@ +FFLAGS = @FFLAGS@ +FFT_CFLAGS = @FFT_CFLAGS@ +FFT_LIBS = @FFT_LIBS@ +FFT_PKGCONFIG = @FFT_PKGCONFIG@ +GREP = @GREP@ +INSTALL_DATA = @INSTALL_DATA@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ +INSTALL_SCRIPT = @INSTALL_SCRIPT@ +INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ +LDFLAGS = @LDFLAGS@ +LIBOBJS = @LIBOBJS@ +LIBS = @LIBS@ +LIBTOOL = @LIBTOOL@ +LN_S = @LN_S@ +LTLIBOBJS = @LTLIBOBJS@ +MAINT = @MAINT@ +MAINTAINER_MODE_FALSE = @MAINTAINER_MODE_FALSE@ +MAINTAINER_MODE_TRUE = @MAINTAINER_MODE_TRUE@ +MAKEINFO = @MAKEINFO@ +NMEDIT = @NMEDIT@ +OBJDUMP = @OBJDUMP@ +OBJEXT = @OBJEXT@ +OGG_CFLAGS = @OGG_CFLAGS@ +OGG_LIBS = @OGG_LIBS@ +PACKAGE = @PACKAGE@ +PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ +PACKAGE_NAME = @PACKAGE_NAME@ +PACKAGE_STRING = @PACKAGE_STRING@ +PACKAGE_TARNAME = @PACKAGE_TARNAME@ +PACKAGE_VERSION = @PACKAGE_VERSION@ +PATH_SEPARATOR = @PATH_SEPARATOR@ +PKG_CONFIG = @PKG_CONFIG@ +RANLIB = @RANLIB@ +SED = @SED@ +SET_MAKE = @SET_MAKE@ +SHELL = @SHELL@ +SIZE16 = @SIZE16@ +SIZE32 = @SIZE32@ +SPEEX_LT_AGE = @SPEEX_LT_AGE@ +SPEEX_LT_CURRENT = @SPEEX_LT_CURRENT@ +SPEEX_LT_REVISION = @SPEEX_LT_REVISION@ +SPEEX_VERSION = @SPEEX_VERSION@ +STRIP = @STRIP@ +VERSION = @VERSION@ +ac_ct_CC = @ac_ct_CC@ +ac_ct_CXX = @ac_ct_CXX@ +ac_ct_F77 = @ac_ct_F77@ +am__fastdepCC_FALSE = @am__fastdepCC_FALSE@ +am__fastdepCC_TRUE = @am__fastdepCC_TRUE@ +am__fastdepCXX_FALSE = @am__fastdepCXX_FALSE@ +am__fastdepCXX_TRUE = @am__fastdepCXX_TRUE@ +am__include = @am__include@ +am__leading_dot = @am__leading_dot@ +am__quote = @am__quote@ +bindir = @bindir@ +build = @build@ +build_alias = @build_alias@ +build_cpu = @build_cpu@ +build_os = @build_os@ +build_vendor = @build_vendor@ +datadir = @datadir@ +datarootdir = @datarootdir@ +docdir = @docdir@ +dvidir = @dvidir@ +exec_prefix = @exec_prefix@ +host = @host@ +host_alias = @host_alias@ +host_cpu = @host_cpu@ +host_os = @host_os@ +host_vendor = @host_vendor@ +htmldir = @htmldir@ +includedir = @includedir@ +infodir = @infodir@ +install_sh = @install_sh@ +libdir = @libdir@ +libexecdir = @libexecdir@ +localedir = @localedir@ +localstatedir = @localstatedir@ +mandir = @mandir@ +mkdir_p = @mkdir_p@ +oldincludedir = @oldincludedir@ +pdfdir = @pdfdir@ +prefix = @prefix@ +program_transform_name = @program_transform_name@ +psdir = @psdir@ +sbindir = @sbindir@ +sharedstatedir = @sharedstatedir@ +src = @src@ +sysconfdir = @sysconfdir@ +target_alias = @target_alias@ +EXTRA_DIST = echo_diagnostic.m +INCLUDES = -I$(top_srcdir)/include -I$(top_builddir)/include -I$(top_builddir) @OGG_CFLAGS@ @FFT_CFLAGS@ +lib_LTLIBRARIES = libspeex.la libspeexdsp.la + +# Sources for compilation in the library +libspeex_la_SOURCES = cb_search.c exc_10_32_table.c exc_8_128_table.c \ + filters.c gain_table.c hexc_table.c high_lsp_tables.c lsp.c \ + ltp.c speex.c stereo.c vbr.c vq.c bits.c exc_10_16_table.c \ + exc_20_32_table.c exc_5_256_table.c exc_5_64_table.c gain_table_lbr.c hexc_10_32_table.c \ + lpc.c lsp_tables_nb.c modes.c modes_wb.c nb_celp.c quant_lsp.c sb_celp.c \ + speex_callbacks.c speex_header.c window.c + +@BUILD_KISS_FFT_FALSE@@BUILD_SMALLFT_FALSE@FFTSRC = +@BUILD_KISS_FFT_FALSE@@BUILD_SMALLFT_TRUE@FFTSRC = smallft.c +@BUILD_KISS_FFT_TRUE@FFTSRC = kiss_fft.c _kiss_fft_guts.h kiss_fft.h kiss_fftr.c kiss_fftr.h +libspeexdsp_la_SOURCES = preprocess.c jitter.c mdf.c fftwrap.c filterbank.c resample.c buffer.c scal.c $(FFTSRC) +noinst_HEADERS = arch.h cb_search_arm4.h cb_search_bfin.h cb_search_sse.h \ + filters.h filters_arm4.h filters_bfin.h filters_sse.h fixed_arm4.h \ + fixed_arm5e.h fixed_bfin.h fixed_debug.h lpc.h lpc_bfin.h ltp.h ltp_arm4.h \ + ltp_sse.h math_approx.h misc_bfin.h nb_celp.h quant_lsp.h sb_celp.h \ + stack_alloc.h vbr.h vq.h vq_arm4.h vq_bfin.h vq_sse.h cb_search.h fftwrap.h \ + filterbank.h fixed_generic.h lsp.h lsp_bfin.h ltp_bfin.h modes.h os_support.h \ + pseudofloat.h quant_lsp_bfin.h smallft.h vorbis_psy.h resample_sse.h + +libspeex_la_LDFLAGS = -no-undefined -version-info @SPEEX_LT_CURRENT@:@SPEEX_LT_REVISION@:@SPEEX_LT_AGE@ +libspeexdsp_la_LDFLAGS = -no-undefined -version-info @SPEEX_LT_CURRENT@:@SPEEX_LT_REVISION@:@SPEEX_LT_AGE@ +testenc_SOURCES = testenc.c +testenc_LDADD = libspeex.la +testenc_wb_SOURCES = testenc_wb.c +testenc_wb_LDADD = libspeex.la +testenc_uwb_SOURCES = testenc_uwb.c +testenc_uwb_LDADD = libspeex.la +testdenoise_SOURCES = testdenoise.c +testdenoise_LDADD = libspeexdsp.la @FFT_LIBS@ +testecho_SOURCES = testecho.c +testecho_LDADD = libspeexdsp.la @FFT_LIBS@ +testjitter_SOURCES = testjitter.c +testjitter_LDADD = libspeexdsp.la @FFT_LIBS@ +all: all-am + +.SUFFIXES: +.SUFFIXES: .c .lo .o .obj +$(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(am__configure_deps) + @for dep in $?; do \ + case '$(am__configure_deps)' in \ + *$$dep*) \ + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh \ + && exit 0; \ + exit 1;; \ + esac; \ + done; \ + echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu libspeex/Makefile'; \ + cd $(top_srcdir) && \ + $(AUTOMAKE) --gnu libspeex/Makefile +.PRECIOUS: Makefile +Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status + @case '$?' in \ + *config.status*) \ + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ + *) \ + echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ + cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ + esac; + +$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh + +$(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +install-libLTLIBRARIES: $(lib_LTLIBRARIES) + @$(NORMAL_INSTALL) + test -z "$(libdir)" || $(mkdir_p) "$(DESTDIR)$(libdir)" + @list='$(lib_LTLIBRARIES)'; for p in $$list; do \ + if test -f $$p; then \ + f="`echo $$p | sed -e 's|^.*/||'`"; \ + echo " $(LIBTOOL) --mode=install $(libLTLIBRARIES_INSTALL) $(INSTALL_STRIP_FLAG) '$$p' '$(DESTDIR)$(libdir)/$$f'"; \ + $(LIBTOOL) --mode=install $(libLTLIBRARIES_INSTALL) $(INSTALL_STRIP_FLAG) "$$p" "$(DESTDIR)$(libdir)/$$f"; \ + else :; fi; \ + done + +uninstall-libLTLIBRARIES: + @$(NORMAL_UNINSTALL) + @list='$(lib_LTLIBRARIES)'; for p in $$list; do \ + p="`echo $$p | sed -e 's|^.*/||'`"; \ + echo " $(LIBTOOL) --mode=uninstall rm -f '$(DESTDIR)$(libdir)/$$p'"; \ + $(LIBTOOL) --mode=uninstall rm -f "$(DESTDIR)$(libdir)/$$p"; \ + done + +clean-libLTLIBRARIES: + -test -z "$(lib_LTLIBRARIES)" || rm -f $(lib_LTLIBRARIES) + @list='$(lib_LTLIBRARIES)'; for p in $$list; do \ + dir="`echo $$p | sed -e 's|/[^/]*$$||'`"; \ + test "$$dir" != "$$p" || dir=.; \ + echo "rm -f \"$${dir}/so_locations\""; \ + rm -f "$${dir}/so_locations"; \ + done +libspeex.la: $(libspeex_la_OBJECTS) $(libspeex_la_DEPENDENCIES) + $(LINK) -rpath $(libdir) $(libspeex_la_LDFLAGS) $(libspeex_la_OBJECTS) $(libspeex_la_LIBADD) $(LIBS) +libspeexdsp.la: $(libspeexdsp_la_OBJECTS) $(libspeexdsp_la_DEPENDENCIES) + $(LINK) -rpath $(libdir) $(libspeexdsp_la_LDFLAGS) $(libspeexdsp_la_OBJECTS) $(libspeexdsp_la_LIBADD) $(LIBS) + +clean-noinstPROGRAMS: + @list='$(noinst_PROGRAMS)'; for p in $$list; do \ + f=`echo $$p|sed 's/$(EXEEXT)$$//'`; \ + echo " rm -f $$p $$f"; \ + rm -f $$p $$f ; \ + done +testdenoise$(EXEEXT): $(testdenoise_OBJECTS) $(testdenoise_DEPENDENCIES) + @rm -f testdenoise$(EXEEXT) + $(LINK) $(testdenoise_LDFLAGS) $(testdenoise_OBJECTS) $(testdenoise_LDADD) $(LIBS) +testecho$(EXEEXT): $(testecho_OBJECTS) $(testecho_DEPENDENCIES) + @rm -f testecho$(EXEEXT) + $(LINK) $(testecho_LDFLAGS) $(testecho_OBJECTS) $(testecho_LDADD) $(LIBS) +testenc$(EXEEXT): $(testenc_OBJECTS) $(testenc_DEPENDENCIES) + @rm -f testenc$(EXEEXT) + $(LINK) $(testenc_LDFLAGS) $(testenc_OBJECTS) $(testenc_LDADD) $(LIBS) +testenc_uwb$(EXEEXT): $(testenc_uwb_OBJECTS) $(testenc_uwb_DEPENDENCIES) + @rm -f testenc_uwb$(EXEEXT) + $(LINK) $(testenc_uwb_LDFLAGS) $(testenc_uwb_OBJECTS) $(testenc_uwb_LDADD) $(LIBS) +testenc_wb$(EXEEXT): $(testenc_wb_OBJECTS) $(testenc_wb_DEPENDENCIES) + @rm -f testenc_wb$(EXEEXT) + $(LINK) $(testenc_wb_LDFLAGS) $(testenc_wb_OBJECTS) $(testenc_wb_LDADD) $(LIBS) +testjitter$(EXEEXT): $(testjitter_OBJECTS) $(testjitter_DEPENDENCIES) + @rm -f testjitter$(EXEEXT) + $(LINK) $(testjitter_LDFLAGS) $(testjitter_OBJECTS) $(testjitter_LDADD) $(LIBS) + +mostlyclean-compile: + -rm -f *.$(OBJEXT) + +distclean-compile: + -rm -f *.tab.c + +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/bits.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/buffer.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/cb_search.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/exc_10_16_table.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/exc_10_32_table.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/exc_20_32_table.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/exc_5_256_table.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/exc_5_64_table.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/exc_8_128_table.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/fftwrap.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/filterbank.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/filters.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gain_table.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gain_table_lbr.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/hexc_10_32_table.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/hexc_table.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/high_lsp_tables.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/jitter.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/kiss_fft.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/kiss_fftr.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/lpc.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/lsp.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/lsp_tables_nb.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ltp.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/mdf.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/modes.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/modes_wb.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/nb_celp.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/preprocess.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/quant_lsp.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/resample.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sb_celp.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/scal.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/smallft.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/speex.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/speex_callbacks.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/speex_header.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/stereo.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/testdenoise.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/testecho.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/testenc.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/testenc_uwb.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/testenc_wb.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/testjitter.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/vbr.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/vq.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/window.Plo@am__quote@ + +.c.o: +@am__fastdepCC_TRUE@ if $(COMPILE) -MT $@ -MD -MP -MF "$(DEPDIR)/$*.Tpo" -c -o $@ $<; \ +@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/$*.Tpo" "$(DEPDIR)/$*.Po"; else rm -f "$(DEPDIR)/$*.Tpo"; exit 1; fi +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ depfile='$(DEPDIR)/$*.Po' tmpdepfile='$(DEPDIR)/$*.TPo' @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(COMPILE) -c $< + +.c.obj: +@am__fastdepCC_TRUE@ if $(COMPILE) -MT $@ -MD -MP -MF "$(DEPDIR)/$*.Tpo" -c -o $@ `$(CYGPATH_W) '$<'`; \ +@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/$*.Tpo" "$(DEPDIR)/$*.Po"; else rm -f "$(DEPDIR)/$*.Tpo"; exit 1; fi +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ depfile='$(DEPDIR)/$*.Po' tmpdepfile='$(DEPDIR)/$*.TPo' @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(COMPILE) -c `$(CYGPATH_W) '$<'` + +.c.lo: +@am__fastdepCC_TRUE@ if $(LTCOMPILE) -MT $@ -MD -MP -MF "$(DEPDIR)/$*.Tpo" -c -o $@ $<; \ +@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/$*.Tpo" "$(DEPDIR)/$*.Plo"; else rm -f "$(DEPDIR)/$*.Tpo"; exit 1; fi +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ depfile='$(DEPDIR)/$*.Plo' tmpdepfile='$(DEPDIR)/$*.TPlo' @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LTCOMPILE) -c -o $@ $< + +mostlyclean-libtool: + -rm -f *.lo + +clean-libtool: + -rm -rf .libs _libs + +distclean-libtool: + -rm -f libtool +uninstall-info-am: + +ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES) + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) ' { files[$$0] = 1; } \ + END { for (i in files) print i; }'`; \ + mkid -fID $$unique +tags: TAGS + +TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + tags=; \ + here=`pwd`; \ + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) ' { files[$$0] = 1; } \ + END { for (i in files) print i; }'`; \ + if test -z "$(ETAGS_ARGS)$$tags$$unique"; then :; else \ + test -n "$$unique" || unique=$$empty_fix; \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + $$tags $$unique; \ + fi +ctags: CTAGS +CTAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + tags=; \ + here=`pwd`; \ + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) ' { files[$$0] = 1; } \ + END { for (i in files) print i; }'`; \ + test -z "$(CTAGS_ARGS)$$tags$$unique" \ + || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ + $$tags $$unique + +GTAGS: + here=`$(am__cd) $(top_builddir) && pwd` \ + && cd $(top_srcdir) \ + && gtags -i $(GTAGS_ARGS) $$here + +distclean-tags: + -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags + +distdir: $(DISTFILES) + @srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; \ + topsrcdirstrip=`echo "$(top_srcdir)" | sed 's|.|.|g'`; \ + list='$(DISTFILES)'; for file in $$list; do \ + case $$file in \ + $(srcdir)/*) file=`echo "$$file" | sed "s|^$$srcdirstrip/||"`;; \ + $(top_srcdir)/*) file=`echo "$$file" | sed "s|^$$topsrcdirstrip/|$(top_builddir)/|"`;; \ + esac; \ + if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ + dir=`echo "$$file" | sed -e 's,/[^/]*$$,,'`; \ + if test "$$dir" != "$$file" && test "$$dir" != "."; then \ + dir="/$$dir"; \ + $(mkdir_p) "$(distdir)$$dir"; \ + else \ + dir=''; \ + fi; \ + if test -d $$d/$$file; then \ + if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ + cp -pR $(srcdir)/$$file $(distdir)$$dir || exit 1; \ + fi; \ + cp -pR $$d/$$file $(distdir)$$dir || exit 1; \ + else \ + test -f $(distdir)/$$file \ + || cp -p $$d/$$file $(distdir)/$$file \ + || exit 1; \ + fi; \ + done +check-am: all-am +check: check-am +all-am: Makefile $(LTLIBRARIES) $(PROGRAMS) $(HEADERS) +installdirs: + for dir in "$(DESTDIR)$(libdir)"; do \ + test -z "$$dir" || $(mkdir_p) "$$dir"; \ + done +install: install-am +install-exec: install-exec-am +install-data: install-data-am +uninstall: uninstall-am + +install-am: all-am + @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am + +installcheck: installcheck-am +install-strip: + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + `test -z '$(STRIP)' || \ + echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install +mostlyclean-generic: + +clean-generic: + +distclean-generic: + -rm -f $(CONFIG_CLEAN_FILES) + +maintainer-clean-generic: + @echo "This command is intended for maintainers to use" + @echo "it deletes files that may require special tools to rebuild." +clean: clean-am + +clean-am: clean-generic clean-libLTLIBRARIES clean-libtool \ + clean-noinstPROGRAMS mostlyclean-am + +distclean: distclean-am + -rm -rf ./$(DEPDIR) + -rm -f Makefile +distclean-am: clean-am distclean-compile distclean-generic \ + distclean-libtool distclean-tags + +dvi: dvi-am + +dvi-am: + +html: html-am + +info: info-am + +info-am: + +install-data-am: + +install-exec-am: install-libLTLIBRARIES + +install-info: install-info-am + +install-man: + +installcheck-am: + +maintainer-clean: maintainer-clean-am + -rm -rf ./$(DEPDIR) + -rm -f Makefile +maintainer-clean-am: distclean-am maintainer-clean-generic + +mostlyclean: mostlyclean-am + +mostlyclean-am: mostlyclean-compile mostlyclean-generic \ + mostlyclean-libtool + +pdf: pdf-am + +pdf-am: + +ps: ps-am + +ps-am: + +uninstall-am: uninstall-info-am uninstall-libLTLIBRARIES + +.PHONY: CTAGS GTAGS all all-am check check-am clean clean-generic \ + clean-libLTLIBRARIES clean-libtool clean-noinstPROGRAMS ctags \ + distclean distclean-compile distclean-generic \ + distclean-libtool distclean-tags distdir dvi dvi-am html \ + html-am info info-am install install-am install-data \ + install-data-am install-exec install-exec-am install-info \ + install-info-am install-libLTLIBRARIES install-man \ + install-strip installcheck installcheck-am installdirs \ + maintainer-clean maintainer-clean-generic mostlyclean \ + mostlyclean-compile mostlyclean-generic mostlyclean-libtool \ + pdf pdf-am ps ps-am tags uninstall uninstall-am \ + uninstall-info-am uninstall-libLTLIBRARIES + +# Tell versions [3.59,3.63) of GNU make to not export all variables. +# Otherwise a system limit (for SysV at least) may be exceeded. +.NOEXPORT: diff --git a/android/app/src/main/jni/libspeex/_kiss_fft_guts.h b/android/app/src/main/jni/libspeex/_kiss_fft_guts.h new file mode 100644 index 000000000..6571e79c0 --- /dev/null +++ b/android/app/src/main/jni/libspeex/_kiss_fft_guts.h @@ -0,0 +1,160 @@ +/* +Copyright (c) 2003-2004, Mark Borgerding + +All rights reserved. + +Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. + * Neither the author nor the names of any contributors may be used to endorse or promote products derived from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#define MIN(a,b) ((a)<(b) ? (a):(b)) +#define MAX(a,b) ((a)>(b) ? (a):(b)) + +/* kiss_fft.h + defines kiss_fft_scalar as either short or a float type + and defines + typedef struct { kiss_fft_scalar r; kiss_fft_scalar i; }kiss_fft_cpx; */ +#include "kiss_fft.h" +#include "math_approx.h" + +#define MAXFACTORS 32 +/* e.g. an fft of length 128 has 4 factors + as far as kissfft is concerned + 4*4*4*2 + */ + +struct kiss_fft_state{ + int nfft; + int inverse; + int factors[2*MAXFACTORS]; + kiss_fft_cpx twiddles[1]; +}; + +/* + Explanation of macros dealing with complex math: + + C_MUL(m,a,b) : m = a*b + C_FIXDIV( c , div ) : if a fixed point impl., c /= div. noop otherwise + C_SUB( res, a,b) : res = a - b + C_SUBFROM( res , a) : res -= a + C_ADDTO( res , a) : res += a + * */ +#ifdef FIXED_POINT +#include "arch.h" +# define FRACBITS 15 +# define SAMPPROD spx_int32_t +#define SAMP_MAX 32767 + +#define SAMP_MIN -SAMP_MAX + +#if defined(CHECK_OVERFLOW) +# define CHECK_OVERFLOW_OP(a,op,b) \ + if ( (SAMPPROD)(a) op (SAMPPROD)(b) > SAMP_MAX || (SAMPPROD)(a) op (SAMPPROD)(b) < SAMP_MIN ) { \ + fprintf(stderr,"WARNING:overflow @ " __FILE__ "(%d): (%d " #op" %d) = %ld\n",__LINE__,(a),(b),(SAMPPROD)(a) op (SAMPPROD)(b) ); } +#endif + + +# define smul(a,b) ( (SAMPPROD)(a)*(b) ) +# define sround( x ) (kiss_fft_scalar)( ( (x) + (1<<(FRACBITS-1)) ) >> FRACBITS ) + +# define S_MUL(a,b) sround( smul(a,b) ) + +# define C_MUL(m,a,b) \ + do{ (m).r = sround( smul((a).r,(b).r) - smul((a).i,(b).i) ); \ + (m).i = sround( smul((a).r,(b).i) + smul((a).i,(b).r) ); }while(0) + +# define C_MUL4(m,a,b) \ + do{ (m).r = PSHR32( smul((a).r,(b).r) - smul((a).i,(b).i),17 ); \ + (m).i = PSHR32( smul((a).r,(b).i) + smul((a).i,(b).r),17 ); }while(0) + +# define DIVSCALAR(x,k) \ + (x) = sround( smul( x, SAMP_MAX/k ) ) + +# define C_FIXDIV(c,div) \ + do { DIVSCALAR( (c).r , div); \ + DIVSCALAR( (c).i , div); }while (0) + +# define C_MULBYSCALAR( c, s ) \ + do{ (c).r = sround( smul( (c).r , s ) ) ;\ + (c).i = sround( smul( (c).i , s ) ) ; }while(0) + +#else /* not FIXED_POINT*/ + +# define S_MUL(a,b) ( (a)*(b) ) +#define C_MUL(m,a,b) \ + do{ (m).r = (a).r*(b).r - (a).i*(b).i;\ + (m).i = (a).r*(b).i + (a).i*(b).r; }while(0) + +#define C_MUL4(m,a,b) C_MUL(m,a,b) + +# define C_FIXDIV(c,div) /* NOOP */ +# define C_MULBYSCALAR( c, s ) \ + do{ (c).r *= (s);\ + (c).i *= (s); }while(0) +#endif + +#ifndef CHECK_OVERFLOW_OP +# define CHECK_OVERFLOW_OP(a,op,b) /* noop */ +#endif + +#define C_ADD( res, a,b)\ + do { \ + CHECK_OVERFLOW_OP((a).r,+,(b).r)\ + CHECK_OVERFLOW_OP((a).i,+,(b).i)\ + (res).r=(a).r+(b).r; (res).i=(a).i+(b).i; \ + }while(0) +#define C_SUB( res, a,b)\ + do { \ + CHECK_OVERFLOW_OP((a).r,-,(b).r)\ + CHECK_OVERFLOW_OP((a).i,-,(b).i)\ + (res).r=(a).r-(b).r; (res).i=(a).i-(b).i; \ + }while(0) +#define C_ADDTO( res , a)\ + do { \ + CHECK_OVERFLOW_OP((res).r,+,(a).r)\ + CHECK_OVERFLOW_OP((res).i,+,(a).i)\ + (res).r += (a).r; (res).i += (a).i;\ + }while(0) + +#define C_SUBFROM( res , a)\ + do {\ + CHECK_OVERFLOW_OP((res).r,-,(a).r)\ + CHECK_OVERFLOW_OP((res).i,-,(a).i)\ + (res).r -= (a).r; (res).i -= (a).i; \ + }while(0) + + +#ifdef FIXED_POINT +# define KISS_FFT_COS(phase) floor(MIN(32767,MAX(-32767,.5+32768 * cos (phase)))) +# define KISS_FFT_SIN(phase) floor(MIN(32767,MAX(-32767,.5+32768 * sin (phase)))) +# define HALF_OF(x) ((x)>>1) +#elif defined(USE_SIMD) +# define KISS_FFT_COS(phase) _mm_set1_ps( cos(phase) ) +# define KISS_FFT_SIN(phase) _mm_set1_ps( sin(phase) ) +# define HALF_OF(x) ((x)*_mm_set1_ps(.5)) +#else +# define KISS_FFT_COS(phase) (kiss_fft_scalar) cos(phase) +# define KISS_FFT_SIN(phase) (kiss_fft_scalar) sin(phase) +# define HALF_OF(x) ((x)*.5) +#endif + +#define kf_cexp(x,phase) \ + do{ \ + (x)->r = KISS_FFT_COS(phase);\ + (x)->i = KISS_FFT_SIN(phase);\ + }while(0) +#define kf_cexp2(x,phase) \ + do{ \ + (x)->r = spx_cos_norm((phase));\ + (x)->i = spx_cos_norm((phase)-32768);\ +}while(0) + + +/* a debugging function */ +#define pcpx(c)\ + fprintf(stderr,"%g + %gi\n",(double)((c)->r),(double)((c)->i) ) diff --git a/android/app/src/main/jni/libspeex/arch.h b/android/app/src/main/jni/libspeex/arch.h new file mode 100644 index 000000000..d38c36ce7 --- /dev/null +++ b/android/app/src/main/jni/libspeex/arch.h @@ -0,0 +1,239 @@ +/* Copyright (C) 2003 Jean-Marc Valin */ +/** + @file arch.h + @brief Various architecture definitions Speex +*/ +/* + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + - Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + - Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + - Neither the name of the Xiph.org Foundation nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR + CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#ifndef ARCH_H +#define ARCH_H + +#ifndef SPEEX_VERSION +#define SPEEX_MAJOR_VERSION 1 /**< Major Speex version. */ +#define SPEEX_MINOR_VERSION 1 /**< Minor Speex version. */ +#define SPEEX_MICRO_VERSION 15 /**< Micro Speex version. */ +#define SPEEX_EXTRA_VERSION "" /**< Extra Speex version. */ +#define SPEEX_VERSION "speex-1.2beta3" /**< Speex version string. */ +#endif + +/* A couple test to catch stupid option combinations */ +#ifdef FIXED_POINT + +#ifdef FLOATING_POINT +#error You cannot compile as floating point and fixed point at the same time +#endif +#ifdef _USE_SSE +#error SSE is only for floating-point +#endif +#if ((defined (ARM4_ASM)||defined (ARM4_ASM)) && defined(BFIN_ASM)) || (defined (ARM4_ASM)&&defined(ARM5E_ASM)) +#error Make up your mind. What CPU do you have? +#endif +#ifdef VORBIS_PSYCHO +#error Vorbis-psy model currently not implemented in fixed-point +#endif + +#else + +#ifndef FLOATING_POINT +#error You now need to define either FIXED_POINT or FLOATING_POINT +#endif +#if defined (ARM4_ASM) || defined(ARM5E_ASM) || defined(BFIN_ASM) +#error I suppose you can have a [ARM4/ARM5E/Blackfin] that has float instructions? +#endif +#ifdef FIXED_POINT_DEBUG +#error "Don't you think enabling fixed-point is a good thing to do if you want to debug that?" +#endif + + +#endif + +#ifndef OUTSIDE_SPEEX +#include "speex/speex_types.h" +#endif + +#define ABS(x) ((x) < 0 ? (-(x)) : (x)) /**< Absolute integer value. */ +#define ABS16(x) ((x) < 0 ? (-(x)) : (x)) /**< Absolute 16-bit value. */ +#define MIN16(a,b) ((a) < (b) ? (a) : (b)) /**< Maximum 16-bit value. */ +#define MAX16(a,b) ((a) > (b) ? (a) : (b)) /**< Maximum 16-bit value. */ +#define ABS32(x) ((x) < 0 ? (-(x)) : (x)) /**< Absolute 32-bit value. */ +#define MIN32(a,b) ((a) < (b) ? (a) : (b)) /**< Maximum 32-bit value. */ +#define MAX32(a,b) ((a) > (b) ? (a) : (b)) /**< Maximum 32-bit value. */ + +#ifdef FIXED_POINT + +typedef spx_int16_t spx_word16_t; +typedef spx_int32_t spx_word32_t; +typedef spx_word32_t spx_mem_t; +typedef spx_word16_t spx_coef_t; +typedef spx_word16_t spx_lsp_t; +typedef spx_word32_t spx_sig_t; + +#define Q15ONE 32767 + +#define LPC_SCALING 8192 +#define SIG_SCALING 16384 +#define LSP_SCALING 8192. +#define GAMMA_SCALING 32768. +#define GAIN_SCALING 64 +#define GAIN_SCALING_1 0.015625 + +#define LPC_SHIFT 13 +#define LSP_SHIFT 13 +#define SIG_SHIFT 14 +#define GAIN_SHIFT 6 + +#define VERY_SMALL 0 +#define VERY_LARGE32 ((spx_word32_t)2147483647) +#define VERY_LARGE16 ((spx_word16_t)32767) +#define Q15_ONE ((spx_word16_t)32767) + + +#ifdef FIXED_DEBUG +#include "fixed_debug.h" +#else + +#include "fixed_generic.h" + +#ifdef ARM5E_ASM +#include "fixed_arm5e.h" +#elif defined (ARM4_ASM) +#include "fixed_arm4.h" +#elif defined (BFIN_ASM) +#include "fixed_bfin.h" +#endif + +#endif + + +#else + +typedef float spx_mem_t; +typedef float spx_coef_t; +typedef float spx_lsp_t; +typedef float spx_sig_t; +typedef float spx_word16_t; +typedef float spx_word32_t; + +#define Q15ONE 1.0f +#define LPC_SCALING 1.f +#define SIG_SCALING 1.f +#define LSP_SCALING 1.f +#define GAMMA_SCALING 1.f +#define GAIN_SCALING 1.f +#define GAIN_SCALING_1 1.f + + +#define VERY_SMALL 1e-15f +#define VERY_LARGE32 1e15f +#define VERY_LARGE16 1e15f +#define Q15_ONE ((spx_word16_t)1.f) + +#define QCONST16(x,bits) (x) +#define QCONST32(x,bits) (x) + +#define NEG16(x) (-(x)) +#define NEG32(x) (-(x)) +#define EXTRACT16(x) (x) +#define EXTEND32(x) (x) +#define SHR16(a,shift) (a) +#define SHL16(a,shift) (a) +#define SHR32(a,shift) (a) +#define SHL32(a,shift) (a) +#define PSHR16(a,shift) (a) +#define PSHR32(a,shift) (a) +#define VSHR32(a,shift) (a) +#define SATURATE16(x,a) (x) +#define SATURATE32(x,a) (x) + +#define PSHR(a,shift) (a) +#define SHR(a,shift) (a) +#define SHL(a,shift) (a) +#define SATURATE(x,a) (x) + +#define ADD16(a,b) ((a)+(b)) +#define SUB16(a,b) ((a)-(b)) +#define ADD32(a,b) ((a)+(b)) +#define SUB32(a,b) ((a)-(b)) +#define MULT16_16_16(a,b) ((a)*(b)) +#define MULT16_16(a,b) ((spx_word32_t)(a)*(spx_word32_t)(b)) +#define MAC16_16(c,a,b) ((c)+(spx_word32_t)(a)*(spx_word32_t)(b)) + +#define MULT16_32_Q11(a,b) ((a)*(b)) +#define MULT16_32_Q13(a,b) ((a)*(b)) +#define MULT16_32_Q14(a,b) ((a)*(b)) +#define MULT16_32_Q15(a,b) ((a)*(b)) +#define MULT16_32_P15(a,b) ((a)*(b)) + +#define MAC16_32_Q11(c,a,b) ((c)+(a)*(b)) +#define MAC16_32_Q15(c,a,b) ((c)+(a)*(b)) + +#define MAC16_16_Q11(c,a,b) ((c)+(a)*(b)) +#define MAC16_16_Q13(c,a,b) ((c)+(a)*(b)) +#define MAC16_16_P13(c,a,b) ((c)+(a)*(b)) +#define MULT16_16_Q11_32(a,b) ((a)*(b)) +#define MULT16_16_Q13(a,b) ((a)*(b)) +#define MULT16_16_Q14(a,b) ((a)*(b)) +#define MULT16_16_Q15(a,b) ((a)*(b)) +#define MULT16_16_P15(a,b) ((a)*(b)) +#define MULT16_16_P13(a,b) ((a)*(b)) +#define MULT16_16_P14(a,b) ((a)*(b)) + +#define DIV32_16(a,b) (((spx_word32_t)(a))/(spx_word16_t)(b)) +#define PDIV32_16(a,b) (((spx_word32_t)(a))/(spx_word16_t)(b)) +#define DIV32(a,b) (((spx_word32_t)(a))/(spx_word32_t)(b)) +#define PDIV32(a,b) (((spx_word32_t)(a))/(spx_word32_t)(b)) + + +#endif + + +#if defined (CONFIG_TI_C54X) || defined (CONFIG_TI_C55X) + +/* 2 on TI C5x DSP */ +#define BYTES_PER_CHAR 2 +#define BITS_PER_CHAR 16 +#define LOG2_BITS_PER_CHAR 4 + +#else + +#define BYTES_PER_CHAR 1 +#define BITS_PER_CHAR 8 +#define LOG2_BITS_PER_CHAR 3 + +#endif + + + +#ifdef FIXED_DEBUG +extern long long spx_mips; +#endif + + +#endif diff --git a/android/app/src/main/jni/libspeex/bits.c b/android/app/src/main/jni/libspeex/bits.c new file mode 100644 index 000000000..3ef7c6c1b --- /dev/null +++ b/android/app/src/main/jni/libspeex/bits.c @@ -0,0 +1,372 @@ +/* Copyright (C) 2002 Jean-Marc Valin + File: speex_bits.c + + Handles bit packing/unpacking + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + - Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + - Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + - Neither the name of the Xiph.org Foundation nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR + CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +*/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include +#include "arch.h" +#include "os_support.h" + +/* Maximum size of the bit-stream (for fixed-size allocation) */ +#ifndef MAX_CHARS_PER_FRAME +#define MAX_CHARS_PER_FRAME (2000/BYTES_PER_CHAR) +#endif + +EXPORT void speex_bits_init(SpeexBits *bits) +{ + bits->chars = (char*)speex_alloc(MAX_CHARS_PER_FRAME); + if (!bits->chars) + return; + + bits->buf_size = MAX_CHARS_PER_FRAME; + + bits->owner=1; + + speex_bits_reset(bits); +} + +EXPORT void speex_bits_init_buffer(SpeexBits *bits, void *buff, int buf_size) +{ + bits->chars = (char*)buff; + bits->buf_size = buf_size; + + bits->owner=0; + + speex_bits_reset(bits); +} + +EXPORT void speex_bits_set_bit_buffer(SpeexBits *bits, void *buff, int buf_size) +{ + bits->chars = (char*)buff; + bits->buf_size = buf_size; + + bits->owner=0; + + bits->nbBits=buf_size<charPtr=0; + bits->bitPtr=0; + bits->overflow=0; + +} + +EXPORT void speex_bits_destroy(SpeexBits *bits) +{ + if (bits->owner) + speex_free(bits->chars); + /* Will do something once the allocation is dynamic */ +} + +EXPORT void speex_bits_reset(SpeexBits *bits) +{ + /* We only need to clear the first byte now */ + bits->chars[0]=0; + bits->nbBits=0; + bits->charPtr=0; + bits->bitPtr=0; + bits->overflow=0; +} + +EXPORT void speex_bits_rewind(SpeexBits *bits) +{ + bits->charPtr=0; + bits->bitPtr=0; + bits->overflow=0; +} + +EXPORT void speex_bits_read_from(SpeexBits *bits, char *chars, int len) +{ + int i; + int nchars = len / BYTES_PER_CHAR; + if (nchars > bits->buf_size) + { + speex_notify("Packet is larger than allocated buffer"); + if (bits->owner) + { + char *tmp = (char*)speex_realloc(bits->chars, nchars); + if (tmp) + { + bits->buf_size=nchars; + bits->chars=tmp; + } else { + nchars=bits->buf_size; + speex_warning("Could not resize input buffer: truncating input"); + } + } else { + speex_warning("Do not own input buffer: truncating oversize input"); + nchars=bits->buf_size; + } + } +#if (BYTES_PER_CHAR==2) +/* Swap bytes to proper endian order (could be done externally) */ +#define HTOLS(A) ((((A) >> 8)&0xff)|(((A) & 0xff)<<8)) +#else +#define HTOLS(A) (A) +#endif + for (i=0;ichars[i]=HTOLS(chars[i]); + + bits->nbBits=nchars<charPtr=0; + bits->bitPtr=0; + bits->overflow=0; +} + +static void speex_bits_flush(SpeexBits *bits) +{ + int nchars = ((bits->nbBits+BITS_PER_CHAR-1)>>LOG2_BITS_PER_CHAR); + if (bits->charPtr>0) + SPEEX_MOVE(bits->chars, &bits->chars[bits->charPtr], nchars-bits->charPtr); + bits->nbBits -= bits->charPtr<charPtr=0; +} + +EXPORT void speex_bits_read_whole_bytes(SpeexBits *bits, char *chars, int nbytes) +{ + int i,pos; + int nchars = nbytes/BYTES_PER_CHAR; + + if (((bits->nbBits+BITS_PER_CHAR-1)>>LOG2_BITS_PER_CHAR)+nchars > bits->buf_size) + { + /* Packet is larger than allocated buffer */ + if (bits->owner) + { + char *tmp = (char*)speex_realloc(bits->chars, (bits->nbBits>>LOG2_BITS_PER_CHAR)+nchars+1); + if (tmp) + { + bits->buf_size=(bits->nbBits>>LOG2_BITS_PER_CHAR)+nchars+1; + bits->chars=tmp; + } else { + nchars=bits->buf_size-(bits->nbBits>>LOG2_BITS_PER_CHAR)-1; + speex_warning("Could not resize input buffer: truncating oversize input"); + } + } else { + speex_warning("Do not own input buffer: truncating oversize input"); + nchars=bits->buf_size; + } + } + + speex_bits_flush(bits); + pos=bits->nbBits>>LOG2_BITS_PER_CHAR; + for (i=0;ichars[pos+i]=HTOLS(chars[i]); + bits->nbBits+=nchars<bitPtr; + charPtr=bits->charPtr; + nbBits=bits->nbBits; + speex_bits_insert_terminator(bits); + bits->bitPtr=bitPtr; + bits->charPtr=charPtr; + bits->nbBits=nbBits; + + if (max_nchars > ((bits->nbBits+BITS_PER_CHAR-1)>>LOG2_BITS_PER_CHAR)) + max_nchars = ((bits->nbBits+BITS_PER_CHAR-1)>>LOG2_BITS_PER_CHAR); + + for (i=0;ichars[i]); + return max_nchars*BYTES_PER_CHAR; +} + +EXPORT int speex_bits_write_whole_bytes(SpeexBits *bits, char *chars, int max_nbytes) +{ + int max_nchars = max_nbytes/BYTES_PER_CHAR; + int i; + if (max_nchars > ((bits->nbBits)>>LOG2_BITS_PER_CHAR)) + max_nchars = ((bits->nbBits)>>LOG2_BITS_PER_CHAR); + for (i=0;ichars[i]); + + if (bits->bitPtr>0) + bits->chars[0]=bits->chars[max_nchars]; + else + bits->chars[0]=0; + bits->charPtr=0; + bits->nbBits &= (BITS_PER_CHAR-1); + return max_nchars*BYTES_PER_CHAR; +} + +EXPORT void speex_bits_pack(SpeexBits *bits, int data, int nbBits) +{ + unsigned int d=data; + + if (bits->charPtr+((nbBits+bits->bitPtr)>>LOG2_BITS_PER_CHAR) >= bits->buf_size) + { + speex_notify("Buffer too small to pack bits"); + if (bits->owner) + { + int new_nchars = ((bits->buf_size+5)*3)>>1; + char *tmp = (char*)speex_realloc(bits->chars, new_nchars); + if (tmp) + { + bits->buf_size=new_nchars; + bits->chars=tmp; + } else { + speex_warning("Could not resize input buffer: not packing"); + return; + } + } else { + speex_warning("Do not own input buffer: not packing"); + return; + } + } + + while(nbBits) + { + int bit; + bit = (d>>(nbBits-1))&1; + bits->chars[bits->charPtr] |= bit<<(BITS_PER_CHAR-1-bits->bitPtr); + bits->bitPtr++; + + if (bits->bitPtr==BITS_PER_CHAR) + { + bits->bitPtr=0; + bits->charPtr++; + bits->chars[bits->charPtr] = 0; + } + bits->nbBits++; + nbBits--; + } +} + +EXPORT int speex_bits_unpack_signed(SpeexBits *bits, int nbBits) +{ + unsigned int d=speex_bits_unpack_unsigned(bits,nbBits); + /* If number is negative */ + if (d>>(nbBits-1)) + { + d |= (-1)<charPtr<bitPtr+nbBits>bits->nbBits) + bits->overflow=1; + if (bits->overflow) + return 0; + while(nbBits) + { + d<<=1; + d |= (bits->chars[bits->charPtr]>>(BITS_PER_CHAR-1 - bits->bitPtr))&1; + bits->bitPtr++; + if (bits->bitPtr==BITS_PER_CHAR) + { + bits->bitPtr=0; + bits->charPtr++; + } + nbBits--; + } + return d; +} + +EXPORT unsigned int speex_bits_peek_unsigned(SpeexBits *bits, int nbBits) +{ + unsigned int d=0; + int bitPtr, charPtr; + char *chars; + + if ((bits->charPtr<bitPtr+nbBits>bits->nbBits) + bits->overflow=1; + if (bits->overflow) + return 0; + + bitPtr=bits->bitPtr; + charPtr=bits->charPtr; + chars = bits->chars; + while(nbBits) + { + d<<=1; + d |= (chars[charPtr]>>(BITS_PER_CHAR-1 - bitPtr))&1; + bitPtr++; + if (bitPtr==BITS_PER_CHAR) + { + bitPtr=0; + charPtr++; + } + nbBits--; + } + return d; +} + +EXPORT int speex_bits_peek(SpeexBits *bits) +{ + if ((bits->charPtr<bitPtr+1>bits->nbBits) + bits->overflow=1; + if (bits->overflow) + return 0; + return (bits->chars[bits->charPtr]>>(BITS_PER_CHAR-1 - bits->bitPtr))&1; +} + +EXPORT void speex_bits_advance(SpeexBits *bits, int n) +{ + if (((bits->charPtr<bitPtr+n>bits->nbBits) || bits->overflow){ + bits->overflow=1; + return; + } + bits->charPtr += (bits->bitPtr+n) >> LOG2_BITS_PER_CHAR; /* divide by BITS_PER_CHAR */ + bits->bitPtr = (bits->bitPtr+n) & (BITS_PER_CHAR-1); /* modulo by BITS_PER_CHAR */ +} + +EXPORT int speex_bits_remaining(SpeexBits *bits) +{ + if (bits->overflow) + return -1; + else + return bits->nbBits-((bits->charPtr<bitPtr); +} + +EXPORT int speex_bits_nbytes(SpeexBits *bits) +{ + return ((bits->nbBits+BITS_PER_CHAR-1)>>LOG2_BITS_PER_CHAR); +} + +EXPORT void speex_bits_insert_terminator(SpeexBits *bits) +{ + if (bits->bitPtr) + speex_bits_pack(bits, 0, 1); + while (bits->bitPtr) + speex_bits_pack(bits, 1, 1); +} diff --git a/android/app/src/main/jni/libspeex/buffer.c b/android/app/src/main/jni/libspeex/buffer.c new file mode 100644 index 000000000..6cfd5a341 --- /dev/null +++ b/android/app/src/main/jni/libspeex/buffer.c @@ -0,0 +1,176 @@ +/* Copyright (C) 2007 Jean-Marc Valin + + File: buffer.c + This is a very simple ring buffer implementation. It is not thread-safe + so you need to do your own locking. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are + met: + + 1. Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + 3. The name of the author may not be used to endorse or promote products + derived from this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, + INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + POSSIBILITY OF SUCH DAMAGE. +*/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + + +#include "os_support.h" +#include "arch.h" +#include + +struct SpeexBuffer_ { + char *data; + int size; + int read_ptr; + int write_ptr; + int available; +}; + +EXPORT SpeexBuffer *speex_buffer_init(int size) +{ + SpeexBuffer *st = speex_alloc(sizeof(SpeexBuffer)); + st->data = speex_alloc(size); + st->size = size; + st->read_ptr = 0; + st->write_ptr = 0; + st->available = 0; + return st; +} + +EXPORT void speex_buffer_destroy(SpeexBuffer *st) +{ + speex_free(st->data); + speex_free(st); +} + +EXPORT int speex_buffer_write(SpeexBuffer *st, void *_data, int len) +{ + int end; + int end1; + char *data = _data; + if (len > st->size) + { + data += len-st->size; + len = st->size; + } + end = st->write_ptr + len; + end1 = end; + if (end1 > st->size) + end1 = st->size; + SPEEX_COPY(st->data + st->write_ptr, data, end1 - st->write_ptr); + if (end > st->size) + { + end -= st->size; + SPEEX_COPY(st->data, data+end1 - st->write_ptr, end); + } + st->available += len; + if (st->available > st->size) + { + st->available = st->size; + st->read_ptr = st->write_ptr; + } + st->write_ptr += len; + if (st->write_ptr > st->size) + st->write_ptr -= st->size; + return len; +} + +EXPORT int speex_buffer_writezeros(SpeexBuffer *st, int len) +{ + /* This is almost the same as for speex_buffer_write() but using + SPEEX_MEMSET() instead of SPEEX_COPY(). Update accordingly. */ + int end; + int end1; + if (len > st->size) + { + len = st->size; + } + end = st->write_ptr + len; + end1 = end; + if (end1 > st->size) + end1 = st->size; + SPEEX_MEMSET(st->data + st->write_ptr, 0, end1 - st->write_ptr); + if (end > st->size) + { + end -= st->size; + SPEEX_MEMSET(st->data, 0, end); + } + st->available += len; + if (st->available > st->size) + { + st->available = st->size; + st->read_ptr = st->write_ptr; + } + st->write_ptr += len; + if (st->write_ptr > st->size) + st->write_ptr -= st->size; + return len; +} + +EXPORT int speex_buffer_read(SpeexBuffer *st, void *_data, int len) +{ + int end, end1; + char *data = _data; + if (len > st->available) + { + SPEEX_MEMSET(data+st->available, 0, st->size-st->available); + len = st->available; + } + end = st->read_ptr + len; + end1 = end; + if (end1 > st->size) + end1 = st->size; + SPEEX_COPY(data, st->data + st->read_ptr, end1 - st->read_ptr); + + if (end > st->size) + { + end -= st->size; + SPEEX_COPY(data+end1 - st->read_ptr, st->data, end); + } + st->available -= len; + st->read_ptr += len; + if (st->read_ptr > st->size) + st->read_ptr -= st->size; + return len; +} + +EXPORT int speex_buffer_get_available(SpeexBuffer *st) +{ + return st->available; +} + +EXPORT int speex_buffer_resize(SpeexBuffer *st, int len) +{ + int old_len = st->size; + if (len > old_len) + { + st->data = speex_realloc(st->data, len); + /* FIXME: move data/pointers properly for growing the buffer */ + } else { + /* FIXME: move data/pointers properly for shrinking the buffer */ + st->data = speex_realloc(st->data, len); + } + return len; +} diff --git a/android/app/src/main/jni/libspeex/cb_search.c b/android/app/src/main/jni/libspeex/cb_search.c new file mode 100644 index 000000000..63f4c6a4b --- /dev/null +++ b/android/app/src/main/jni/libspeex/cb_search.c @@ -0,0 +1,612 @@ +/* Copyright (C) 2002-2006 Jean-Marc Valin + File: cb_search.c + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + - Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + - Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + - Neither the name of the Xiph.org Foundation nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR + CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "cb_search.h" +#include "filters.h" +#include "stack_alloc.h" +#include "vq.h" +#include "arch.h" +#include "math_approx.h" +#include "os_support.h" + +#ifdef _USE_SSE +#include "cb_search_sse.h" +#elif defined(ARM4_ASM) || defined(ARM5E_ASM) +#include "cb_search_arm4.h" +#elif defined(BFIN_ASM) +#include "cb_search_bfin.h" +#endif + +#ifndef OVERRIDE_COMPUTE_WEIGHTED_CODEBOOK +static void compute_weighted_codebook(const signed char *shape_cb, const spx_word16_t *r, spx_word16_t *resp, spx_word16_t *resp2, spx_word32_t *E, int shape_cb_size, int subvect_size, char *stack) +{ + int i, j, k; + VARDECL(spx_word16_t *shape); + ALLOC(shape, subvect_size, spx_word16_t); + for (i=0;isubvect_size; + nb_subvect = params->nb_subvect; + shape_cb_size = 1<shape_bits; + shape_cb = params->shape_cb; + have_sign = params->have_sign; + ALLOC(resp, shape_cb_size*subvect_size, spx_word16_t); +#ifdef _USE_SSE + ALLOC(resp2, (shape_cb_size*subvect_size)>>2, __m128); + ALLOC(E, shape_cb_size>>2, __m128); +#else + resp2 = resp; + ALLOC(E, shape_cb_size, spx_word32_t); +#endif + ALLOC(t, nsf, spx_word16_t); + ALLOC(e, nsf, spx_sig_t); + + /* FIXME: Do we still need to copy the target? */ + SPEEX_COPY(t, target, nsf); + + compute_weighted_codebook(shape_cb, r, resp, resp2, E, shape_cb_size, subvect_size, stack); + + for (i=0;ishape_bits+have_sign); + + { + int rind; + spx_word16_t *res; + spx_word16_t sign=1; + rind = best_index; + if (rind>=shape_cb_size) + { + sign=-1; + rind-=shape_cb_size; + } + res = resp+rind*subvect_size; + if (sign>0) + for (m=0;m=shape_cb_size) + { + sign=-1; + rind-=shape_cb_size; + } + + q=subvect_size-m; +#ifdef FIXED_POINT + g=sign*shape_cb[rind*subvect_size+m]; +#else + g=sign*0.03125*shape_cb[rind*subvect_size+m]; +#endif + target_update(t+subvect_size*(i+1), g, r+q, nsf-subvect_size*(i+1)); + } + } + + /* Update excitation */ + /* FIXME: We could update the excitation directly above */ + for (j=0;j10) + N=10; + /* Complexity isn't as important for the codebooks as it is for the pitch */ + N=(2*N)/3; + if (N<1) + N=1; + if (N==1) + { + split_cb_search_shape_sign_N1(target,ak,awk1,awk2,par,p,nsf,exc,r,bits,stack,update_target); + return; + } + ALLOC(ot2, N, spx_word16_t*); + ALLOC(nt2, N, spx_word16_t*); + ALLOC(oind, N, int*); + ALLOC(nind, N, int*); + + params = (const split_cb_params *) par; + subvect_size = params->subvect_size; + nb_subvect = params->nb_subvect; + shape_cb_size = 1<shape_bits; + shape_cb = params->shape_cb; + have_sign = params->have_sign; + ALLOC(resp, shape_cb_size*subvect_size, spx_word16_t); +#ifdef _USE_SSE + ALLOC(resp2, (shape_cb_size*subvect_size)>>2, __m128); + ALLOC(E, shape_cb_size>>2, __m128); +#else + resp2 = resp; + ALLOC(E, shape_cb_size, spx_word32_t); +#endif + ALLOC(t, nsf, spx_word16_t); + ALLOC(e, nsf, spx_sig_t); + ALLOC(ind, nb_subvect, int); + + ALLOC(tmp, 2*N*nsf, spx_word16_t); + for (i=0;im;n--) + { + ndist[n] = ndist[n-1]; + best_nind[n] = best_nind[n-1]; + best_ntarget[n] = best_ntarget[n-1]; + } + /* n is equal to m here, so they're interchangeable */ + ndist[m] = err; + best_nind[n] = best_index[k]; + best_ntarget[n] = j; + break; + } + } + } + } + if (i==0) + break; + } + for (j=0;j=shape_cb_size) + { + sign=-1; + rind-=shape_cb_size; + } + + q=subvect_size-m; +#ifdef FIXED_POINT + g=sign*shape_cb[rind*subvect_size+m]; +#else + g=sign*0.03125*shape_cb[rind*subvect_size+m]; +#endif + target_update(nt[j]+subvect_size*(i+1), g, r+q, nsf-subvect_size*(i+1)); + } + + for (q=0;qshape_bits+have_sign); + } + + /* Put everything back together */ + for (i=0;i=shape_cb_size) + { + sign=-1; + rind-=shape_cb_size; + } +#ifdef FIXED_POINT + if (sign==1) + { + for (j=0;jsubvect_size; + nb_subvect = params->nb_subvect; + shape_cb_size = 1<shape_bits; + shape_cb = params->shape_cb; + have_sign = params->have_sign; + + ALLOC(ind, nb_subvect, int); + ALLOC(signs, nb_subvect, int); + + /* Decode codewords and gains */ + for (i=0;ishape_bits); + } + /* Compute decoded excitation */ + for (i=0;i +#include "arch.h" + +/** Split codebook parameters. */ +typedef struct split_cb_params { + int subvect_size; + int nb_subvect; + const signed char *shape_cb; + int shape_bits; + int have_sign; +} split_cb_params; + + +void split_cb_search_shape_sign( +spx_word16_t target[], /* target vector */ +spx_coef_t ak[], /* LPCs for this subframe */ +spx_coef_t awk1[], /* Weighted LPCs for this subframe */ +spx_coef_t awk2[], /* Weighted LPCs for this subframe */ +const void *par, /* Codebook/search parameters */ +int p, /* number of LPC coeffs */ +int nsf, /* number of samples in subframe */ +spx_sig_t *exc, +spx_word16_t *r, +SpeexBits *bits, +char *stack, +int complexity, +int update_target +); + +void split_cb_shape_sign_unquant( +spx_sig_t *exc, +const void *par, /* non-overlapping codebook */ +int nsf, /* number of samples in subframe */ +SpeexBits *bits, +char *stack, +spx_int32_t *seed +); + + +void noise_codebook_quant( +spx_word16_t target[], /* target vector */ +spx_coef_t ak[], /* LPCs for this subframe */ +spx_coef_t awk1[], /* Weighted LPCs for this subframe */ +spx_coef_t awk2[], /* Weighted LPCs for this subframe */ +const void *par, /* Codebook/search parameters */ +int p, /* number of LPC coeffs */ +int nsf, /* number of samples in subframe */ +spx_sig_t *exc, +spx_word16_t *r, +SpeexBits *bits, +char *stack, +int complexity, +int update_target +); + + +void noise_codebook_unquant( +spx_sig_t *exc, +const void *par, /* non-overlapping codebook */ +int nsf, /* number of samples in subframe */ +SpeexBits *bits, +char *stack, +spx_int32_t *seed +); + +#endif diff --git a/android/app/src/main/jni/libspeex/cb_search_arm4.h b/android/app/src/main/jni/libspeex/cb_search_arm4.h new file mode 100644 index 000000000..19b752a4b --- /dev/null +++ b/android/app/src/main/jni/libspeex/cb_search_arm4.h @@ -0,0 +1,137 @@ +/* Copyright (C) 2004 Jean-Marc Valin */ +/** + @file cb_search_arm4.h + @brief Fixed codebook functions (ARM4 version) +*/ +/* + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + - Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + - Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + - Neither the name of the Xiph.org Foundation nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR + CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +/* This optimization is temporaly disabled until it is fixed to account for the fact + that "r" is now a 16-bit array */ +#if 0 +#define OVERRIDE_COMPUTE_WEIGHTED_CODEBOOK +static void compute_weighted_codebook(const signed char *shape_cb, const spx_word16_t *r, spx_word16_t *resp, spx_word16_t *resp2, spx_word32_t *E, int shape_cb_size, int subvect_size, char *stack) +{ + int i, j, k; + //const signed char *shape; + for (i=0;i>>= 13;\n\t" + "A1 += R0.L*R0.L (IS);\n\t" + "W[P3++] = R0;\n\t" + "P0 += 1;\n\t" + "P2 += 2;\n\t" + "LOOP_END outter%=;\n\t" + "P4 = %4;\n\t" + "R1 = A1;\n\t" + "[P4] = R1;\n\t" + : + : "m" (subvect_size), "m" (shape_cb), "m" (r), "m" (resp), "m" (E) + : "A0", "P0", "P1", "P2", "P3", "P4", "R0", "R1", "R2", "I0", "I1", "L0", + "L1", "A0", "A1", "memory" +#if !(__GNUC__ == 3) + , "LC0", "LC1" /* gcc 3.4 doesn't know about LC registers */ +#endif + ); + shape_cb += subvect_size; + resp += subvect_size; + E++; + } +} + +#define OVERRIDE_TARGET_UPDATE +static inline void target_update(spx_word16_t *t, spx_word16_t g, spx_word16_t *r, int len) +{ + if (!len) + return; + __asm__ __volatile__ + ( + "I0 = %0;\n\t" + "I1 = %1;\n\t" + "L0 = 0;\n\t" + "L1 = 0;\n\t" + "R2 = 4096;\n\t" + "LOOP tupdate%= LC0 = %3;\n\t" + "LOOP_BEGIN tupdate%=;\n\t" + "R0.L = W[I0] || R1.L = W[I1++];\n\t" + "R1 = (A1 = R1.L*%2.L) (IS);\n\t" + "R1 = R1 + R2;\n\t" + "R1 >>>= 13;\n\t" + "R0.L = R0.L - R1.L;\n\t" + "W[I0++] = R0.L;\n\t" + "LOOP_END tupdate%=;\n\t" + : + : "a" (t), "a" (r), "d" (g), "a" (len) + : "R0", "R1", "R2", "A1", "I0", "I1", "L0", "L1" + ); +} diff --git a/android/app/src/main/jni/libspeex/cb_search_sse.h b/android/app/src/main/jni/libspeex/cb_search_sse.h new file mode 100644 index 000000000..8b039686f --- /dev/null +++ b/android/app/src/main/jni/libspeex/cb_search_sse.h @@ -0,0 +1,84 @@ +/* Copyright (C) 2004 Jean-Marc Valin */ +/** + @file cb_search_sse.h + @brief Fixed codebook functions (SSE version) +*/ +/* + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + - Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + - Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + - Neither the name of the Xiph.org Foundation nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR + CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#include + +static inline void _spx_mm_getr_ps (__m128 U, float *__Z, float *__Y, float *__X, float *__W) +{ + union { + float __a[4]; + __m128 __v; + } __u; + + __u.__v = U; + + *__Z = __u.__a[0]; + *__Y = __u.__a[1]; + *__X = __u.__a[2]; + *__W = __u.__a[3]; + +} + +#define OVERRIDE_COMPUTE_WEIGHTED_CODEBOOK +static void compute_weighted_codebook(const signed char *shape_cb, const spx_sig_t *_r, float *resp, __m128 *resp2, __m128 *E, int shape_cb_size, int subvect_size, char *stack) +{ + int i, j, k; + __m128 resj, EE; + VARDECL(__m128 *r); + VARDECL(__m128 *shape); + ALLOC(r, subvect_size, __m128); + ALLOC(shape, subvect_size, __m128); + for(j=0;j>2] = EE; + } +} diff --git a/android/app/src/main/jni/libspeex/echo_diagnostic.m b/android/app/src/main/jni/libspeex/echo_diagnostic.m new file mode 100644 index 000000000..aebf39067 --- /dev/null +++ b/android/app/src/main/jni/libspeex/echo_diagnostic.m @@ -0,0 +1,72 @@ +% Attempts to diagnose AEC problems from recorded samples +% +% out = echo_diagnostic(rec_file, play_file, out_file, tail_length) +% +% Computes the full matrix inversion to cancel echo from the +% recording 'rec_file' using the far end signal 'play_file' using +% a filter length of 'tail_length'. The output is saved to 'out_file'. +function out = echo_diagnostic(rec_file, play_file, out_file, tail_length) + +F=fopen(rec_file,'rb'); +rec=fread(F,Inf,'short'); +fclose (F); +F=fopen(play_file,'rb'); +play=fread(F,Inf,'short'); +fclose (F); + +rec = [rec; zeros(1024,1)]; +play = [play; zeros(1024,1)]; + +N = length(rec); +corr = real(ifft(fft(rec).*conj(fft(play)))); +acorr = real(ifft(fft(play).*conj(fft(play)))); + +[a,b] = max(corr); + +if b > N/2 + b = b-N; +end +printf ("Far end to near end delay is %d samples\n", b); +if (b > .3*tail_length) + printf ('This is too much delay, try delaying the far-end signal a bit\n'); +else if (b < 0) + printf ('You have a negative delay, the echo canceller has no chance to cancel anything!\n'); + else + printf ('Delay looks OK.\n'); + end + end +end +N2 = round(N/2); +corr1 = real(ifft(fft(rec(1:N2)).*conj(fft(play(1:N2))))); +corr2 = real(ifft(fft(rec(N2+1:end)).*conj(fft(play(N2+1:end))))); + +[a,b1] = max(corr1); +if b1 > N2/2 + b1 = b1-N2; +end +[a,b2] = max(corr2); +if b2 > N2/2 + b2 = b2-N2; +end +drift = (b1-b2)/N2; +printf ('Drift estimate is %f%% (%d samples)\n', 100*drift, b1-b2); +if abs(b1-b2) < 10 + printf ('A drift of a few (+-10) samples is normal.\n'); +else + if abs(b1-b2) < 30 + printf ('There may be (not sure) excessive clock drift. Is the capture and playback done on the same soundcard?\n'); + else + printf ('Your clock is drifting! No way the AEC will be able to do anything with that. Most likely, you''re doing capture and playback from two different cards.\n'); + end + end +end +acorr(1) = .001+1.00001*acorr(1); +AtA = toeplitz(acorr(1:tail_length)); +bb = corr(1:tail_length); +h = AtA\bb; + +out = (rec - filter(h, 1, play)); + +F=fopen(out_file,'w'); +fwrite(F,out,'short'); +fclose (F); diff --git a/android/app/src/main/jni/libspeex/exc_10_16_table.c b/android/app/src/main/jni/libspeex/exc_10_16_table.c new file mode 100644 index 000000000..98ae357d8 --- /dev/null +++ b/android/app/src/main/jni/libspeex/exc_10_16_table.c @@ -0,0 +1,50 @@ +/* Copyright (C) 2002 Jean-Marc Valin + File: exc_10_16_table.c + Codebook for excitation in narrowband CELP mode (3200 bps) + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + - Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + - Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + - Neither the name of the Xiph.org Foundation nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR + CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + + +const signed char exc_10_16_table[160] = { +22,39,14,44,11,35,-2,23,-4,6, +46,-28,13,-27,-23,12,4,20,-5,9, +37,-18,-23,23,0,9,-6,-20,4,-1, +-17,-5,-4,17,0,1,9,-2,1,2, +2,-12,8,-25,39,15,9,16,-55,-11, +9,11,5,10,-2,-60,8,13,-6,11, +-16,27,-47,-12,11,1,16,-7,9,-3, +-29,9,-14,25,-19,34,36,12,40,-10, +-3,-24,-14,-37,-21,-35,-2,-36,3,-6, +67,28,6,-17,-3,-12,-16,-15,-17,-7, +-59,-36,-13,1,7,1,2,10,2,11, +13,10,8,-2,7,3,5,4,2,2, +-3,-8,4,-5,6,7,-42,15,35,-2, +-46,38,28,-20,-9,1,7,-3,0,-2, +0,0,0,0,0,0,0,0,0,0, +-15,-28,52,32,5,-5,-17,-20,-10,-1}; diff --git a/android/app/src/main/jni/libspeex/exc_10_32_table.c b/android/app/src/main/jni/libspeex/exc_10_32_table.c new file mode 100644 index 000000000..1ee56a259 --- /dev/null +++ b/android/app/src/main/jni/libspeex/exc_10_32_table.c @@ -0,0 +1,66 @@ +/* Copyright (C) 2002 Jean-Marc Valin + File: exc_10_32_table.c + Codebook for excitation in narrowband CELP mode (4000 bps) + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + - Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + - Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + - Neither the name of the Xiph.org Foundation nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR + CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + + +const signed char exc_10_32_table[320] = { +7,17,17,27,25,22,12,4,-3,0, +28,-36,39,-24,-15,3,-9,15,-5,10, +31,-28,11,31,-21,9,-11,-11,-2,-7, +-25,14,-22,31,4,-14,19,-12,14,-5, +4,-7,4,-5,9,0,-2,42,-47,-16, +1,8,0,9,23,-57,0,28,-11,6, +-31,55,-45,3,-5,4,2,-2,4,-7, +-3,6,-2,7,-3,12,5,8,54,-10, +8,-7,-8,-24,-25,-27,-14,-5,8,5, +44,23,5,-9,-11,-11,-13,-9,-12,-8, +-29,-8,-22,6,-15,3,-12,-1,-5,-3, +34,-1,29,-16,17,-4,12,2,1,4, +-2,-4,2,-1,11,-3,-52,28,30,-9, +-32,25,44,-20,-24,4,6,-1,0,0, +0,0,0,0,0,0,0,0,0,0, +-25,-10,22,29,13,-13,-22,-13,-4,0, +-4,-16,10,15,-36,-24,28,25,-1,-3, +66,-33,-11,-15,6,0,3,4,-2,5, +24,-20,-47,29,19,-2,-4,-1,0,-1, +-2,3,1,8,-11,5,5,-57,28,28, +0,-16,4,-4,12,-6,-1,2,-20,61, +-9,24,-22,-42,29,6,17,8,4,2, +-65,15,8,10,5,6,5,3,2,-2, +-3,5,-9,4,-5,23,13,23,-3,-63, +3,-5,-4,-6,0,-3,23,-36,-46,9, +5,5,8,4,9,-5,1,-3,10,1, +-6,10,-11,24,-47,31,22,-12,14,-10, +6,11,-7,-7,7,-31,51,-12,-6,7, +6,-17,9,-11,-20,52,-19,3,-6,-6, +-8,-5,23,-41,37,1,-21,10,-14,8, +7,5,-15,-15,23,39,-26,-33,7,2, +-32,-30,-21,-8,4,12,17,15,14,11}; diff --git a/android/app/src/main/jni/libspeex/exc_20_32_table.c b/android/app/src/main/jni/libspeex/exc_20_32_table.c new file mode 100644 index 000000000..e4098b8d1 --- /dev/null +++ b/android/app/src/main/jni/libspeex/exc_20_32_table.c @@ -0,0 +1,66 @@ +/* Copyright (C) 2002 Jean-Marc Valin + File: exc_20_32_table.c + Codebook for excitation in narrowband CELP mode (2000 bps) + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + - Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + - Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + - Neither the name of the Xiph.org Foundation nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR + CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + + +const signed char exc_20_32_table[640] = { +12,32,25,46,36,33,9,14,-3,6,1,-8,0,-10,-5,-7,-7,-7,-5,-5, +31,-27,24,-32,-4,10,-11,21,-3,19,23,-9,22,24,-10,-1,-10,-13,-7,-11, +42,-33,31,19,-8,0,-10,-16,1,-21,-17,10,-8,14,8,4,11,-2,5,-2, +-33,11,-16,33,11,-4,9,-4,11,2,6,-5,8,-5,11,-4,-6,26,-36,-16, +0,4,-2,-8,12,6,-1,34,-46,-22,9,9,21,9,5,-66,-5,26,2,10, +13,2,19,9,12,-81,3,13,13,0,-14,22,-35,6,-7,-4,6,-6,10,-6, +-31,38,-33,0,-10,-11,5,-12,12,-17,5,0,-6,13,-9,10,8,25,33,2, +-12,8,-6,10,-2,21,7,17,43,5,11,-7,-9,-20,-36,-20,-23,-4,-4,-3, +27,-9,-9,-49,-39,-38,-11,-9,6,5,23,25,5,3,3,4,1,2,-3,-1, +87,39,17,-21,-9,-19,-9,-15,-13,-14,-17,-11,-10,-11,-8,-6,-1,-3,-3,-1, +-54,-34,-27,-8,-11,-4,-5,0,0,4,8,6,9,7,9,7,6,5,5,5, +48,10,19,-10,12,-1,9,-3,2,5,-3,2,-2,-2,0,-2,-26,6,9,-7, +-16,-9,2,7,7,-5,-43,11,22,-11,-9,34,37,-15,-13,-6,1,-1,1,1, +-64,56,52,-11,-27,5,4,3,1,2,1,3,-1,-4,-4,-10,-7,-4,-4,2, +-1,-7,-7,-12,-10,-15,-9,-5,-5,-11,-16,-13,6,16,4,-13,-16,-10,-4,2, +-47,-13,25,47,19,-14,-20,-8,-17,0,-3,-13,1,6,-17,-14,15,1,10,6, +-24,0,-10,19,-69,-8,14,49,17,-5,33,-29,3,-4,0,2,-8,5,-6,2, +120,-56,-12,-47,23,-9,6,-5,1,2,-5,1,-10,4,-1,-1,4,-1,0,-3, +30,-52,-67,30,22,11,-1,-4,3,0,7,2,0,1,-10,-4,-8,-13,5,1, +1,-1,5,13,-9,-3,-10,-62,22,48,-4,-6,2,3,5,1,1,4,1,13, +3,-20,10,-9,13,-2,-4,9,-20,44,-1,20,-32,-67,19,0,28,11,8,2, +-11,15,-19,-53,31,2,34,10,6,-4,-58,8,10,13,14,1,12,2,0,0, +-128,37,-8,44,-9,26,-3,18,2,6,11,-1,9,1,5,3,0,1,1,2, +12,3,-2,-3,7,25,9,18,-6,-37,3,-8,-16,3,-10,-7,17,-34,-44,11, +17,-15,-3,-16,-1,-13,11,-46,-65,-2,8,13,2,4,4,5,15,5,9,6, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +-9,19,-12,12,-28,38,29,-1,12,2,5,23,-10,3,4,-15,21,-4,3,3, +6,17,-9,-4,-8,-20,26,5,-10,6,1,-19,18,-15,-12,47,-6,-2,-7,-9, +-1,-17,-2,-2,-14,30,-14,2,-7,-4,-1,-12,11,-25,16,-3,-12,11,-7,7, +-17,1,19,-28,31,-7,-10,7,-10,3,12,5,-16,6,24,41,-29,-54,0,1, +7,-1,5,-6,13,10,-4,-8,8,-9,-27,-53,-38,-1,10,19,17,16,12,12, +0,3,-7,-4,13,12,-31,-14,6,-5,3,5,17,43,50,25,10,1,-6,-2}; diff --git a/android/app/src/main/jni/libspeex/exc_5_256_table.c b/android/app/src/main/jni/libspeex/exc_5_256_table.c new file mode 100644 index 000000000..4137996d4 --- /dev/null +++ b/android/app/src/main/jni/libspeex/exc_5_256_table.c @@ -0,0 +1,290 @@ +/* Copyright (C) 2002 Jean-Marc Valin + File: exc_5_256_table.c + Codebook for excitation in narrowband CELP mode (12800 bps) + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + - Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + - Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + - Neither the name of the Xiph.org Foundation nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR + CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + + +const signed char exc_5_256_table[1280] = { +-8,-37,5,-43,5, +73,61,39,12,-3, +-61,-32,2,42,30, +-3,17,-27,9,34, +20,-1,-5,2,23, +-7,-46,26,53,-47, +20,-2,-33,-89,-51, +-64,27,11,15,-34, +-5,-56,25,-9,-1, +-29,1,40,67,-23, +-16,16,33,19,7, +14,85,22,-10,-10, +-12,-7,-1,52,89, +29,11,-20,-37,-46, +-15,17,-24,-28,24, +2,1,0,23,-101, +23,14,-1,-23,-18, +9,5,-13,38,1, +-28,-28,4,27,51, +-26,34,-40,35,47, +54,38,-54,-26,-6, +42,-25,13,-30,-36, +18,41,-4,-33,23, +-32,-7,-4,51,-3, +17,-52,56,-47,36, +-2,-21,36,10,8, +-33,31,19,9,-5, +-40,10,-9,-21,19, +18,-78,-18,-5,0, +-26,-36,-47,-51,-44, +18,40,27,-2,29, +49,-26,2,32,-54, +30,-73,54,3,-5, +36,22,53,10,-1, +-84,-53,-29,-5,3, +-44,53,-51,4,22, +71,-35,-1,33,-5, +-27,-7,36,17,-23, +-39,16,-9,-55,-15, +-20,39,-35,6,-39, +-14,18,48,-64,-17, +-15,9,39,81,37, +-68,37,47,-21,-6, +-104,13,6,9,-2, +35,8,-23,18,42, +45,21,33,-5,-49, +9,-6,-43,-56,39, +2,-16,-25,87,1, +-3,-9,17,-25,-11, +-9,-1,10,2,-14, +-14,4,-1,-10,28, +-23,40,-32,26,-9, +26,4,-27,-23,3, +42,-60,1,49,-3, +27,10,-52,-40,-2, +18,45,-23,17,-44, +3,-3,17,-46,52, +-40,-47,25,75,31, +-49,53,30,-30,-32, +-36,38,-6,-15,-16, +54,-27,-48,3,38, +-29,-32,-22,-14,-4, +-23,-13,32,-39,9, +8,-45,-13,34,-16, +49,40,32,31,28, +23,23,32,47,59, +-68,8,62,44,25, +-14,-24,-65,-16,36, +67,-25,-38,-21,4, +-33,-2,42,5,-63, +40,11,26,-42,-23, +-61,79,-31,23,-20, +10,-32,53,-25,-36, +10,-26,-5,3,0, +-71,5,-10,-37,1, +-24,21,-54,-17,1, +-29,-25,-15,-27,32, +68,45,-16,-37,-18, +-5,1,0,-77,71, +-6,3,-20,71,-67, +29,-35,10,-30,19, +4,16,17,5,0, +-14,19,2,28,26, +59,3,2,24,39, +55,-50,-45,-18,-17, +33,-35,14,-1,1, +8,87,-35,-29,0, +-27,13,-7,23,-13, +37,-40,50,-35,14, +19,-7,-14,49,54, +-5,22,-2,-29,-8, +-27,38,13,27,48, +12,-41,-21,-15,28, +7,-16,-24,-19,-20, +11,-20,9,2,13, +23,-20,11,27,-27, +71,-69,8,2,-6, +22,12,16,16,9, +-16,-8,-17,1,25, +1,40,-37,-33,66, +94,53,4,-22,-25, +-41,-42,25,35,-16, +-15,57,31,-29,-32, +21,16,-60,45,15, +-1,7,57,-26,-47, +-29,11,8,15,19, +-105,-8,54,27,10, +-17,6,-12,-1,-10, +4,0,23,-10,31, +13,11,10,12,-64, +23,-3,-8,-19,16, +52,24,-40,16,10, +40,5,9,0,-13, +-7,-21,-8,-6,-7, +-21,59,16,-53,18, +-60,11,-47,14,-18, +25,-13,-24,4,-39, +16,-28,54,26,-67, +30,27,-20,-52,20, +-12,55,12,18,-16, +39,-14,-6,-26,56, +-88,-55,12,25,26, +-37,6,75,0,-34, +-81,54,-30,1,-7, +49,-23,-14,21,10, +-62,-58,-57,-47,-34, +15,-4,34,-78,31, +25,-11,7,50,-10, +42,-63,14,-36,-4, +57,55,57,53,42, +-42,-1,15,40,37, +15,25,-11,6,1, +31,-2,-6,-1,-7, +-64,34,28,30,-1, +3,21,0,-88,-12, +-56,25,-28,40,8, +-28,-14,9,12,2, +-6,-17,22,49,-6, +-26,14,28,-20,4, +-12,50,35,40,13, +-38,-58,-29,17,30, +22,60,26,-54,-39, +-12,58,-28,-63,10, +-21,-8,-12,26,-62, +6,-10,-11,-22,-6, +-7,4,1,18,2, +-70,11,14,4,13, +19,-24,-34,24,67, +17,51,-21,13,23, +54,-30,48,1,-13, +80,26,-16,-2,13, +-4,6,-30,29,-24, +73,-58,30,-27,20, +-2,-21,41,45,30, +-27,-3,-5,-18,-20, +-49,-3,-35,10,42, +-19,-67,-53,-11,9, +13,-15,-33,-51,-30, +15,7,25,-30,4, +28,-22,-34,54,-29, +39,-46,20,16,34, +-4,47,75,1,-44, +-55,-24,7,-1,9, +-42,50,-8,-36,41, +68,0,-4,-10,-23, +-15,-50,64,36,-9, +-27,12,25,-38,-47, +-37,32,-49,51,-36, +2,-4,69,-26,19, +7,45,67,46,13, +-63,46,15,-47,4, +-41,13,-6,5,-21, +37,26,-55,-7,33, +-1,-28,10,-17,-64, +-14,0,-36,-17,93, +-3,-9,-66,44,-21, +3,-12,38,-6,-13, +-12,19,13,43,-43, +-10,-12,6,-5,9, +-49,32,-5,2,4, +5,15,-16,10,-21, +8,-62,-8,64,8, +79,-1,-66,-49,-18, +5,40,-5,-30,-45, +1,-6,21,-32,93, +-18,-30,-21,32,21, +-18,22,8,5,-41, +-54,80,22,-10,-7, +-8,-23,-64,66,56, +-14,-30,-41,-46,-14, +-29,-37,27,-14,42, +-2,-9,-29,34,14, +33,-14,22,4,10, +26,26,28,32,23, +-72,-32,3,0,-14, +35,-42,-78,-32,6, +29,-18,-45,-5,7, +-33,-45,-3,-22,-34, +8,-8,4,-51,-25, +-9,59,-78,21,-5, +-25,-48,66,-15,-17, +-24,-49,-13,25,-23, +-64,-6,40,-24,-19, +-11,57,-33,-8,1, +10,-52,-54,28,39, +49,34,-11,-61,-41, +-43,10,15,-15,51, +30,15,-51,32,-34, +-2,-34,14,18,16, +1,1,-3,-3,1, +1,-18,6,16,48, +12,-5,-42,7,36, +48,7,-20,-10,7, +12,2,54,39,-38, +37,54,4,-11,-8, +-46,-10,5,-10,-34, +46,-12,29,-37,39, +36,-11,24,56,17, +14,20,25,0,-25, +-28,55,-7,-5,27, +3,9,-26,-8,6, +-24,-10,-30,-31,-34, +18,4,22,21,40, +-1,-29,-37,-8,-21, +92,-29,11,-3,11, +73,23,22,7,4, +-44,-9,-11,21,-13, +11,9,-78,-1,47, +114,-12,-37,-19,-5, +-11,-22,19,12,-30, +7,38,45,-21,-8, +-9,55,-45,56,-21, +7,17,46,-57,-87, +-6,27,31,31,7, +-56,-12,46,21,-5, +-12,36,3,3,-21, +43,19,12,-7,9, +-14,0,-9,-33,-91, +7,26,3,-11,64, +83,-31,-46,25,2, +9,5,2,2,-1, +20,-17,10,-5,-27, +-8,20,8,-19,16, +-21,-13,-31,5,5, +42,24,9,34,-20, +28,-61,22,11,-39, +64,-20,-1,-30,-9, +-20,24,-25,-24,-29, +22,-60,6,-5,41, +-9,-87,14,34,15, +-57,52,69,15,-3, +-102,58,16,3,6, +60,-75,-32,26,7, +-57,-27,-32,-24,-21, +-29,-16,62,-46,31, +30,-27,-15,7,15}; diff --git a/android/app/src/main/jni/libspeex/exc_5_64_table.c b/android/app/src/main/jni/libspeex/exc_5_64_table.c new file mode 100644 index 000000000..2c66d5189 --- /dev/null +++ b/android/app/src/main/jni/libspeex/exc_5_64_table.c @@ -0,0 +1,98 @@ +/* Copyright (C) 2002 Jean-Marc Valin + File: exc_5_64_table.c + Codebook for excitation in narrowband CELP mode (9600 bps) + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + - Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + - Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + - Neither the name of the Xiph.org Foundation nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR + CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + + +const signed char exc_5_64_table[320]={ +1,5,-15,49,-66, +-48,-4,50,-44,7, +37,16,-18,25,-26, +-26,-15,19,19,-27, +-47,28,57,5,-17, +-32,-41,68,21,-2, +64,56,8,-16,-13, +-26,-9,-16,11,6, +-39,25,-19,22,-31, +20,-45,55,-43,10, +-16,47,-40,40,-20, +-51,3,-17,-14,-15, +-24,53,-20,-46,46, +27,-68,32,3,-18, +-5,9,-31,16,-9, +-10,-1,-23,48,95, +47,25,-41,-32,-3, +15,-25,-55,36,41, +-27,20,5,13,14, +-22,5,2,-23,18, +46,-15,17,-18,-34, +-5,-8,27,-55,73, +16,2,-1,-17,40, +-78,33,0,2,19, +4,53,-16,-15,-16, +-28,-3,-13,49,8, +-7,-29,27,-13,32, +20,32,-61,16,14, +41,44,40,24,20, +7,4,48,-60,-77, +17,-6,-48,65,-15, +32,-30,-71,-10,-3, +-6,10,-2,-7,-29, +-56,67,-30,7,-5, +86,-6,-10,0,5, +-31,60,34,-38,-3, +24,10,-2,30,23, +24,-41,12,70,-43, +15,-17,6,13,16, +-13,8,30,-15,-8, +5,23,-34,-98,-4, +-13,13,-48,-31,70, +12,31,25,24,-24, +26,-7,33,-16,8, +5,-11,-14,-8,-65, +13,10,-2,-9,0, +-3,-68,5,35,7, +0,-31,-1,-17,-9, +-9,16,-37,-18,-1, +69,-48,-28,22,-21, +-11,5,49,55,23, +-86,-36,16,2,13, +63,-51,30,-11,13, +24,-18,-6,14,-19, +1,41,9,-5,27, +-36,-44,-34,-37,-21, +-26,31,-39,15,43, +5,-8,29,20,-8, +-20,-52,-28,-1,13, +26,-34,-10,-9,27, +-8,8,27,-66,4, +12,-22,49,10,-77, +32,-18,3,-38,12, +-3,-1,2,2,0}; diff --git a/android/app/src/main/jni/libspeex/exc_8_128_table.c b/android/app/src/main/jni/libspeex/exc_8_128_table.c new file mode 100644 index 000000000..17ee64b92 --- /dev/null +++ b/android/app/src/main/jni/libspeex/exc_8_128_table.c @@ -0,0 +1,162 @@ +/* Copyright (C) 2002 Jean-Marc Valin + File: exc_8_128_table.c + Codebook for excitation in narrowband CELP mode (7000 bps) + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + - Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + - Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + - Neither the name of the Xiph.org Foundation nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR + CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + + +const signed char exc_8_128_table[1024] = { +-14,9,13,-32,2,-10,31,-10, +-8,-8,6,-4,-1,10,-64,23, +6,20,13,6,8,-22,16,34, +7,42,-49,-28,5,26,4,-15, +41,34,41,32,33,24,23,14, +8,40,34,4,-24,-41,-19,-15, +13,-13,33,-54,24,27,-44,33, +27,-15,-15,24,-19,14,-36,14, +-9,24,-12,-4,37,-5,16,-34, +5,10,33,-15,-54,-16,12,25, +12,1,2,0,3,-1,-4,-4, +11,2,-56,54,27,-20,13,-6, +-46,-41,-33,-11,-5,7,12,14, +-14,-5,8,20,6,3,4,-8, +-5,-42,11,8,-14,25,-2,2, +13,11,-22,39,-9,9,5,-45, +-9,7,-9,12,-7,34,-17,-102, +7,2,-42,18,35,-9,-34,11, +-5,-2,3,22,46,-52,-25,-9, +-94,8,11,-5,-5,-5,4,-7, +-35,-7,54,5,-32,3,24,-9, +-22,8,65,37,-1,-12,-23,-6, +-9,-28,55,-33,14,-3,2,18, +-60,41,-17,8,-16,17,-11,0, +-11,29,-28,37,9,-53,33,-14, +-9,7,-25,-7,-11,26,-32,-8, +24,-21,22,-19,19,-10,29,-14, +0,0,0,0,0,0,0,0, +-5,-52,10,41,6,-30,-4,16, +32,22,-27,-22,32,-3,-28,-3, +3,-35,6,17,23,21,8,2, +4,-45,-17,14,23,-4,-31,-11, +-3,14,1,19,-11,2,61,-8, +9,-12,7,-10,12,-3,-24,99, +-48,23,50,-37,-5,-23,0,8, +-14,35,-64,-5,46,-25,13,-1, +-49,-19,-15,9,34,50,25,11, +-6,-9,-16,-20,-32,-33,-32,-27, +10,-8,12,-15,56,-14,-32,33, +3,-9,1,65,-9,-9,-10,-2, +-6,-23,9,17,3,-28,13,-32, +4,-2,-10,4,-16,76,12,-52, +6,13,33,-6,4,-14,-9,-3, +1,-15,-16,28,1,-15,11,16, +9,4,-21,-37,-40,-6,22,12, +-15,-23,-14,-17,-16,-9,-10,-9, +13,-39,41,5,-9,16,-38,25, +46,-47,4,49,-14,17,-2,6, +18,5,-6,-33,-22,44,50,-2, +1,3,-6,7,7,-3,-21,38, +-18,34,-14,-41,60,-13,6,16, +-24,35,19,-13,-36,24,3,-17, +-14,-10,36,44,-44,-29,-3,3, +-54,-8,12,55,26,4,-2,-5, +2,-11,22,-23,2,22,1,-25, +-39,66,-49,21,-8,-2,10,-14, +-60,25,6,10,27,-25,16,5, +-2,-9,26,-13,-20,58,-2,7, +52,-9,2,5,-4,-15,23,-1, +-38,23,8,27,-6,0,-27,-7, +39,-10,-14,26,11,-45,-12,9, +-5,34,4,-35,10,43,-22,-11, +56,-7,20,1,10,1,-26,9, +94,11,-27,-14,-13,1,-11,0, +14,-5,-6,-10,-4,-15,-8,-41, +21,-5,1,-28,-8,22,-9,33, +-23,-4,-4,-12,39,4,-7,3, +-60,80,8,-17,2,-6,12,-5, +1,9,15,27,31,30,27,23, +61,47,26,10,-5,-8,-12,-13, +5,-18,25,-15,-4,-15,-11,12, +-2,-2,-16,-2,-6,24,12,11, +-4,9,1,-9,14,-45,57,12, +20,-35,26,11,-64,32,-10,-10, +42,-4,-9,-16,32,24,7,10, +52,-11,-57,29,0,8,0,-6, +17,-17,-56,-40,7,20,18,12, +-6,16,5,7,-1,9,1,10, +29,12,16,13,-2,23,7,9, +-3,-4,-5,18,-64,13,55,-25, +9,-9,24,14,-25,15,-11,-40, +-30,37,1,-19,22,-5,-31,13, +-2,0,7,-4,16,-67,12,66, +-36,24,-8,18,-15,-23,19,0, +-45,-7,4,3,-13,13,35,5, +13,33,10,27,23,0,-7,-11, +43,-74,36,-12,2,5,-8,6, +-33,11,-16,-14,-5,-7,-3,17, +-34,27,-16,11,-9,15,33,-31, +8,-16,7,-6,-7,63,-55,-17, +11,-1,20,-46,34,-30,6,9, +19,28,-9,5,-24,-8,-23,-2, +31,-19,-16,-5,-15,-18,0,26, +18,37,-5,-15,-2,17,5,-27, +21,-33,44,12,-27,-9,17,11, +25,-21,-31,-7,13,33,-8,-25, +-7,7,-10,4,-6,-9,48,-82, +-23,-8,6,11,-23,3,-3,49, +-29,25,31,4,14,16,9,-4, +-18,10,-26,3,5,-44,-9,9, +-47,-55,15,9,28,1,4,-3, +46,6,-6,-38,-29,-31,-15,-6, +3,0,14,-6,8,-54,-50,33, +-5,1,-14,33,-48,26,-4,-5, +-3,-5,-3,-5,-28,-22,77,55, +-1,2,10,10,-9,-14,-66,-49, +11,-36,-6,-20,10,-10,16,12, +4,-1,-16,45,-44,-50,31,-2, +25,42,23,-32,-22,0,11,20, +-40,-35,-40,-36,-32,-26,-21,-13, +52,-22,6,-24,-20,17,-5,-8, +36,-25,-11,21,-26,6,34,-8, +7,20,-3,5,-25,-8,18,-5, +-9,-4,1,-9,20,20,39,48, +-24,9,5,-65,22,29,4,3, +-43,-11,32,-6,9,19,-27,-10, +-47,-14,24,10,-7,-36,-7,-1, +-4,-5,-5,16,53,25,-26,-29, +-4,-12,45,-58,-34,33,-5,2, +-1,27,-48,31,-15,22,-5,4, +7,7,-25,-3,11,-22,16,-12, +8,-3,7,-11,45,14,-73,-19, +56,-46,24,-20,28,-12,-2,-1, +-36,-3,-33,19,-6,7,2,-15, +5,-31,-45,8,35,13,20,0, +-9,48,-13,-43,-3,-13,2,-5, +72,-68,-27,2,1,-2,-7,5, +36,33,-40,-12,-4,-5,23,19}; diff --git a/android/app/src/main/jni/libspeex/fftwrap.c b/android/app/src/main/jni/libspeex/fftwrap.c new file mode 100644 index 000000000..4f37e1b3f --- /dev/null +++ b/android/app/src/main/jni/libspeex/fftwrap.c @@ -0,0 +1,397 @@ +/* Copyright (C) 2005-2006 Jean-Marc Valin + File: fftwrap.c + + Wrapper for various FFTs + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + - Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + - Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + - Neither the name of the Xiph.org Foundation nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR + CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +*/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "arch.h" +#include "os_support.h" + +#define MAX_FFT_SIZE 2048 + +#ifdef FIXED_POINT +static int maximize_range(spx_word16_t *in, spx_word16_t *out, spx_word16_t bound, int len) +{ + int i, shift; + spx_word16_t max_val = 0; + for (i=0;imax_val) + max_val = in[i]; + if (-in[i]>max_val) + max_val = -in[i]; + } + shift=0; + while (max_val <= (bound>>1) && max_val != 0) + { + max_val <<= 1; + shift++; + } + for (i=0;i + +void *spx_fft_init(int size) +{ + struct drft_lookup *table; + table = speex_alloc(sizeof(struct drft_lookup)); + spx_drft_init((struct drft_lookup *)table, size); + return (void*)table; +} + +void spx_fft_destroy(void *table) +{ + spx_drft_clear(table); + speex_free(table); +} + +void spx_fft(void *table, float *in, float *out) +{ + if (in==out) + { + int i; + float scale = 1./((struct drft_lookup *)table)->n; + speex_warning("FFT should not be done in-place"); + for (i=0;i<((struct drft_lookup *)table)->n;i++) + out[i] = scale*in[i]; + } else { + int i; + float scale = 1./((struct drft_lookup *)table)->n; + for (i=0;i<((struct drft_lookup *)table)->n;i++) + out[i] = scale*in[i]; + } + spx_drft_forward((struct drft_lookup *)table, out); +} + +void spx_ifft(void *table, float *in, float *out) +{ + if (in==out) + { + speex_warning("FFT should not be done in-place"); + } else { + int i; + for (i=0;i<((struct drft_lookup *)table)->n;i++) + out[i] = in[i]; + } + spx_drft_backward((struct drft_lookup *)table, out); +} + +#elif defined(USE_INTEL_MKL) +#include + +struct mkl_config { + DFTI_DESCRIPTOR_HANDLE desc; + int N; +}; + +void *spx_fft_init(int size) +{ + struct mkl_config *table = (struct mkl_config *) speex_alloc(sizeof(struct mkl_config)); + table->N = size; + DftiCreateDescriptor(&table->desc, DFTI_SINGLE, DFTI_REAL, 1, size); + DftiSetValue(table->desc, DFTI_PACKED_FORMAT, DFTI_PACK_FORMAT); + DftiSetValue(table->desc, DFTI_PLACEMENT, DFTI_NOT_INPLACE); + DftiSetValue(table->desc, DFTI_FORWARD_SCALE, 1.0f / size); + DftiCommitDescriptor(table->desc); + return table; +} + +void spx_fft_destroy(void *table) +{ + struct mkl_config *t = (struct mkl_config *) table; + DftiFreeDescriptor(t->desc); + speex_free(table); +} + +void spx_fft(void *table, spx_word16_t *in, spx_word16_t *out) +{ + struct mkl_config *t = (struct mkl_config *) table; + DftiComputeForward(t->desc, in, out); +} + +void spx_ifft(void *table, spx_word16_t *in, spx_word16_t *out) +{ + struct mkl_config *t = (struct mkl_config *) table; + DftiComputeBackward(t->desc, in, out); +} + +#elif defined(USE_GPL_FFTW3) + +#include + +struct fftw_config { + float *in; + float *out; + fftwf_plan fft; + fftwf_plan ifft; + int N; +}; + +void *spx_fft_init(int size) +{ + struct fftw_config *table = (struct fftw_config *) speex_alloc(sizeof(struct fftw_config)); + table->in = fftwf_malloc(sizeof(float) * (size+2)); + table->out = fftwf_malloc(sizeof(float) * (size+2)); + + table->fft = fftwf_plan_dft_r2c_1d(size, table->in, (fftwf_complex *) table->out, FFTW_PATIENT); + table->ifft = fftwf_plan_dft_c2r_1d(size, (fftwf_complex *) table->in, table->out, FFTW_PATIENT); + + table->N = size; + return table; +} + +void spx_fft_destroy(void *table) +{ + struct fftw_config *t = (struct fftw_config *) table; + fftwf_destroy_plan(t->fft); + fftwf_destroy_plan(t->ifft); + fftwf_free(t->in); + fftwf_free(t->out); + speex_free(table); +} + + +void spx_fft(void *table, spx_word16_t *in, spx_word16_t *out) +{ + int i; + struct fftw_config *t = (struct fftw_config *) table; + const int N = t->N; + float *iptr = t->in; + float *optr = t->out; + const float m = 1.0 / N; + for(i=0;ifft); + + out[0] = optr[0]; + for(i=1;iN; + float *iptr = t->in; + float *optr = t->out; + + iptr[0] = in[0]; + iptr[1] = 0.0f; + for(i=1;iifft); + + for(i=0;iforward = kiss_fftr_alloc(size,0,NULL,NULL); + table->backward = kiss_fftr_alloc(size,1,NULL,NULL); + table->N = size; + return table; +} + +void spx_fft_destroy(void *table) +{ + struct kiss_config *t = (struct kiss_config *)table; + kiss_fftr_free(t->forward); + kiss_fftr_free(t->backward); + speex_free(table); +} + +#ifdef FIXED_POINT + +void spx_fft(void *table, spx_word16_t *in, spx_word16_t *out) +{ + int shift; + struct kiss_config *t = (struct kiss_config *)table; + shift = maximize_range(in, in, 32000, t->N); + kiss_fftr2(t->forward, in, out); + renorm_range(in, in, shift, t->N); + renorm_range(out, out, shift, t->N); +} + +#else + +void spx_fft(void *table, spx_word16_t *in, spx_word16_t *out) +{ + int i; + float scale; + struct kiss_config *t = (struct kiss_config *)table; + scale = 1./t->N; + kiss_fftr2(t->forward, in, out); + for (i=0;iN;i++) + out[i] *= scale; +} +#endif + +void spx_ifft(void *table, spx_word16_t *in, spx_word16_t *out) +{ + struct kiss_config *t = (struct kiss_config *)table; + kiss_fftri2(t->backward, in, out); +} + + +#else + +#error No other FFT implemented + +#endif + + +#ifdef FIXED_POINT +/*#include "smallft.h"*/ + + +void spx_fft_float(void *table, float *in, float *out) +{ + int i; +#ifdef USE_SMALLFT + int N = ((struct drft_lookup *)table)->n; +#elif defined(USE_KISS_FFT) + int N = ((struct kiss_config *)table)->N; +#else +#endif +#ifdef VAR_ARRAYS + spx_word16_t _in[N]; + spx_word16_t _out[N]; +#else + spx_word16_t _in[MAX_FFT_SIZE]; + spx_word16_t _out[MAX_FFT_SIZE]; +#endif + for (i=0;iN); + scale = 1./((struct kiss_config *)table)->N; + for (i=0;i<((struct kiss_config *)table)->N;i++) + out[i] = scale*in[i]; + spx_drft_forward(&t, out); + spx_drft_clear(&t); + } +#endif +} + +void spx_ifft_float(void *table, float *in, float *out) +{ + int i; +#ifdef USE_SMALLFT + int N = ((struct drft_lookup *)table)->n; +#elif defined(USE_KISS_FFT) + int N = ((struct kiss_config *)table)->N; +#else +#endif +#ifdef VAR_ARRAYS + spx_word16_t _in[N]; + spx_word16_t _out[N]; +#else + spx_word16_t _in[MAX_FFT_SIZE]; + spx_word16_t _out[MAX_FFT_SIZE]; +#endif + for (i=0;iN); + for (i=0;i<((struct kiss_config *)table)->N;i++) + out[i] = in[i]; + spx_drft_backward(&t, out); + spx_drft_clear(&t); + } +#endif +} + +#else + +void spx_fft_float(void *table, float *in, float *out) +{ + spx_fft(table, in, out); +} +void spx_ifft_float(void *table, float *in, float *out) +{ + spx_ifft(table, in, out); +} + +#endif diff --git a/android/app/src/main/jni/libspeex/fftwrap.h b/android/app/src/main/jni/libspeex/fftwrap.h new file mode 100644 index 000000000..dfaf48944 --- /dev/null +++ b/android/app/src/main/jni/libspeex/fftwrap.h @@ -0,0 +1,58 @@ +/* Copyright (C) 2005 Jean-Marc Valin + File: fftwrap.h + + Wrapper for various FFTs + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + - Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + - Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + - Neither the name of the Xiph.org Foundation nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR + CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +*/ + +#ifndef FFTWRAP_H +#define FFTWRAP_H + +#include "arch.h" + +/** Compute tables for an FFT */ +void *spx_fft_init(int size); + +/** Destroy tables for an FFT */ +void spx_fft_destroy(void *table); + +/** Forward (real to half-complex) transform */ +void spx_fft(void *table, spx_word16_t *in, spx_word16_t *out); + +/** Backward (half-complex to real) transform */ +void spx_ifft(void *table, spx_word16_t *in, spx_word16_t *out); + +/** Forward (real to half-complex) transform of float data */ +void spx_fft_float(void *table, float *in, float *out); + +/** Backward (half-complex to real) transform of float data */ +void spx_ifft_float(void *table, float *in, float *out); + +#endif diff --git a/android/app/src/main/jni/libspeex/filterbank.c b/android/app/src/main/jni/libspeex/filterbank.c new file mode 100644 index 000000000..e2fb71d4b --- /dev/null +++ b/android/app/src/main/jni/libspeex/filterbank.c @@ -0,0 +1,227 @@ +/* Copyright (C) 2006 Jean-Marc Valin */ +/** + @file filterbank.c + @brief Converting between psd and filterbank + */ +/* + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are + met: + + 1. Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + 3. The name of the author may not be used to endorse or promote products + derived from this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, + INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + POSSIBILITY OF SUCH DAMAGE. +*/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "filterbank.h" +#include "arch.h" +#include +#include "math_approx.h" +#include "os_support.h" + +#ifdef FIXED_POINT + +#define toBARK(n) (MULT16_16(26829,spx_atan(SHR32(MULT16_16(97,n),2))) + MULT16_16(4588,spx_atan(MULT16_32_Q15(20,MULT16_16(n,n)))) + MULT16_16(3355,n)) + +#else +#define toBARK(n) (13.1f*atan(.00074f*(n))+2.24f*atan((n)*(n)*1.85e-8f)+1e-4f*(n)) +#endif + +#define toMEL(n) (2595.f*log10(1.f+(n)/700.f)) + +FilterBank *filterbank_new(int banks, spx_word32_t sampling, int len, int type) +{ + FilterBank *bank; + spx_word32_t df; + spx_word32_t max_mel, mel_interval; + int i; + int id1; + int id2; + df = DIV32(SHL32(sampling,15),MULT16_16(2,len)); + max_mel = toBARK(EXTRACT16(sampling/2)); + mel_interval = PDIV32(max_mel,banks-1); + + bank = (FilterBank*)speex_alloc(sizeof(FilterBank)); + bank->nb_banks = banks; + bank->len = len; + bank->bank_left = (int*)speex_alloc(len*sizeof(int)); + bank->bank_right = (int*)speex_alloc(len*sizeof(int)); + bank->filter_left = (spx_word16_t*)speex_alloc(len*sizeof(spx_word16_t)); + bank->filter_right = (spx_word16_t*)speex_alloc(len*sizeof(spx_word16_t)); + /* Think I can safely disable normalisation that for fixed-point (and probably float as well) */ +#ifndef FIXED_POINT + bank->scaling = (float*)speex_alloc(banks*sizeof(float)); +#endif + for (i=0;i max_mel) + break; +#ifdef FIXED_POINT + id1 = DIV32(mel,mel_interval); +#else + id1 = (int)(floor(mel/mel_interval)); +#endif + if (id1>banks-2) + { + id1 = banks-2; + val = Q15_ONE; + } else { + val = DIV32_16(mel - id1*mel_interval,EXTRACT16(PSHR32(mel_interval,15))); + } + id2 = id1+1; + bank->bank_left[i] = id1; + bank->filter_left[i] = SUB16(Q15_ONE,val); + bank->bank_right[i] = id2; + bank->filter_right[i] = val; + } + + /* Think I can safely disable normalisation for fixed-point (and probably float as well) */ +#ifndef FIXED_POINT + for (i=0;inb_banks;i++) + bank->scaling[i] = 0; + for (i=0;ilen;i++) + { + int id = bank->bank_left[i]; + bank->scaling[id] += bank->filter_left[i]; + id = bank->bank_right[i]; + bank->scaling[id] += bank->filter_right[i]; + } + for (i=0;inb_banks;i++) + bank->scaling[i] = Q15_ONE/(bank->scaling[i]); +#endif + return bank; +} + +void filterbank_destroy(FilterBank *bank) +{ + speex_free(bank->bank_left); + speex_free(bank->bank_right); + speex_free(bank->filter_left); + speex_free(bank->filter_right); +#ifndef FIXED_POINT + speex_free(bank->scaling); +#endif + speex_free(bank); +} + +void filterbank_compute_bank32(FilterBank *bank, spx_word32_t *ps, spx_word32_t *mel) +{ + int i; + for (i=0;inb_banks;i++) + mel[i] = 0; + + for (i=0;ilen;i++) + { + int id; + id = bank->bank_left[i]; + mel[id] += MULT16_32_P15(bank->filter_left[i],ps[i]); + id = bank->bank_right[i]; + mel[id] += MULT16_32_P15(bank->filter_right[i],ps[i]); + } + /* Think I can safely disable normalisation that for fixed-point (and probably float as well) */ +#ifndef FIXED_POINT + /*for (i=0;inb_banks;i++) + mel[i] = MULT16_32_P15(Q15(bank->scaling[i]),mel[i]); + */ +#endif +} + +void filterbank_compute_psd16(FilterBank *bank, spx_word16_t *mel, spx_word16_t *ps) +{ + int i; + for (i=0;ilen;i++) + { + spx_word32_t tmp; + int id1, id2; + id1 = bank->bank_left[i]; + id2 = bank->bank_right[i]; + tmp = MULT16_16(mel[id1],bank->filter_left[i]); + tmp += MULT16_16(mel[id2],bank->filter_right[i]); + ps[i] = EXTRACT16(PSHR32(tmp,15)); + } +} + + +#ifndef FIXED_POINT +void filterbank_compute_bank(FilterBank *bank, float *ps, float *mel) +{ + int i; + for (i=0;inb_banks;i++) + mel[i] = 0; + + for (i=0;ilen;i++) + { + int id = bank->bank_left[i]; + mel[id] += bank->filter_left[i]*ps[i]; + id = bank->bank_right[i]; + mel[id] += bank->filter_right[i]*ps[i]; + } + for (i=0;inb_banks;i++) + mel[i] *= bank->scaling[i]; +} + +void filterbank_compute_psd(FilterBank *bank, float *mel, float *ps) +{ + int i; + for (i=0;ilen;i++) + { + int id = bank->bank_left[i]; + ps[i] = mel[id]*bank->filter_left[i]; + id = bank->bank_right[i]; + ps[i] += mel[id]*bank->filter_right[i]; + } +} + +void filterbank_psy_smooth(FilterBank *bank, float *ps, float *mask) +{ + /* Low freq slope: 14 dB/Bark*/ + /* High freq slope: 9 dB/Bark*/ + /* Noise vs tone: 5 dB difference */ + /* FIXME: Temporary kludge */ + float bark[100]; + int i; + /* Assumes 1/3 Bark resolution */ + float decay_low = 0.34145f; + float decay_high = 0.50119f; + filterbank_compute_bank(bank, ps, bark); + for (i=1;inb_banks;i++) + { + /*float decay_high = 13-1.6*log10(bark[i-1]); + decay_high = pow(10,(-decay_high/30.f));*/ + bark[i] = bark[i] + decay_high*bark[i-1]; + } + for (i=bank->nb_banks-2;i>=0;i--) + { + bark[i] = bark[i] + decay_low*bark[i+1]; + } + filterbank_compute_psd(bank, bark, mask); +} + +#endif diff --git a/android/app/src/main/jni/libspeex/filterbank.h b/android/app/src/main/jni/libspeex/filterbank.h new file mode 100644 index 000000000..3e889a22f --- /dev/null +++ b/android/app/src/main/jni/libspeex/filterbank.h @@ -0,0 +1,66 @@ +/* Copyright (C) 2006 Jean-Marc Valin */ +/** + @file filterbank.h + @brief Converting between psd and filterbank + */ +/* + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are + met: + + 1. Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + 3. The name of the author may not be used to endorse or promote products + derived from this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, + INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + POSSIBILITY OF SUCH DAMAGE. +*/ + +#ifndef FILTERBANK_H +#define FILTERBANK_H + +#include "arch.h" + +typedef struct { + int *bank_left; + int *bank_right; + spx_word16_t *filter_left; + spx_word16_t *filter_right; +#ifndef FIXED_POINT + float *scaling; +#endif + int nb_banks; + int len; +} FilterBank; + + +FilterBank *filterbank_new(int banks, spx_word32_t sampling, int len, int type); + +void filterbank_destroy(FilterBank *bank); + +void filterbank_compute_bank32(FilterBank *bank, spx_word32_t *ps, spx_word32_t *mel); + +void filterbank_compute_psd16(FilterBank *bank, spx_word16_t *mel, spx_word16_t *psd); + +#ifndef FIXED_POINT +void filterbank_compute_bank(FilterBank *bank, float *psd, float *mel); +void filterbank_compute_psd(FilterBank *bank, float *mel, float *psd); +#endif + + +#endif diff --git a/android/app/src/main/jni/libspeex/filters.c b/android/app/src/main/jni/libspeex/filters.c new file mode 100644 index 000000000..36ef4f697 --- /dev/null +++ b/android/app/src/main/jni/libspeex/filters.c @@ -0,0 +1,821 @@ +/* Copyright (C) 2002-2006 Jean-Marc Valin + File: filters.c + Various analysis/synthesis filters + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + - Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + - Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + - Neither the name of the Xiph.org Foundation nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR + CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "filters.h" +#include "stack_alloc.h" +#include "arch.h" +#include "math_approx.h" +#include "ltp.h" +#include + +#ifdef _USE_SSE +#include "filters_sse.h" +#elif defined (ARM4_ASM) || defined(ARM5E_ASM) +#include "filters_arm4.h" +#elif defined (BFIN_ASM) +#include "filters_bfin.h" +#endif + + + +void bw_lpc(spx_word16_t gamma, const spx_coef_t *lpc_in, spx_coef_t *lpc_out, int order) +{ + int i; + spx_word16_t tmp=gamma; + for (i=0;i=min_val && vec[i] <= max_val)) + { + if (vec[i] < min_val) + vec[i] = min_val; + else if (vec[i] > max_val) + vec[i] = max_val; + else /* Has to be NaN */ + vec[i] = 0; + } + } +} + +void highpass(const spx_word16_t *x, spx_word16_t *y, int len, int filtID, spx_mem_t *mem) +{ + int i; +#ifdef FIXED_POINT + const spx_word16_t Pcoef[5][3] = {{16384, -31313, 14991}, {16384, -31569, 15249}, {16384, -31677, 15328}, {16384, -32313, 15947}, {16384, -22446, 6537}}; + const spx_word16_t Zcoef[5][3] = {{15672, -31344, 15672}, {15802, -31601, 15802}, {15847, -31694, 15847}, {16162, -32322, 16162}, {14418, -28836, 14418}}; +#else + const spx_word16_t Pcoef[5][3] = {{1.00000f, -1.91120f, 0.91498f}, {1.00000f, -1.92683f, 0.93071f}, {1.00000f, -1.93338f, 0.93553f}, {1.00000f, -1.97226f, 0.97332f}, {1.00000f, -1.37000f, 0.39900f}}; + const spx_word16_t Zcoef[5][3] = {{0.95654f, -1.91309f, 0.95654f}, {0.96446f, -1.92879f, 0.96446f}, {0.96723f, -1.93445f, 0.96723f}, {0.98645f, -1.97277f, 0.98645f}, {0.88000f, -1.76000f, 0.88000f}}; +#endif + const spx_word16_t *den, *num; + if (filtID>4) + filtID=4; + + den = Pcoef[filtID]; num = Zcoef[filtID]; + /*return;*/ + for (i=0;i SHL32(EXTEND32(SIG_SCALING), 8)) + { + spx_word16_t scale_1; + scale = PSHR32(scale, SIG_SHIFT); + scale_1 = EXTRACT16(PDIV32_16(SHL32(EXTEND32(SIG_SCALING),7),scale)); + for (i=0;i SHR32(EXTEND32(SIG_SCALING), 2)) { + spx_word16_t scale_1; + scale = PSHR32(scale, SIG_SHIFT-5); + scale_1 = DIV32_16(SHL32(EXTEND32(SIG_SCALING),3),scale); + for (i=0;i max_val) + max_val = tmp; + } + + sig_shift=0; + while (max_val>16383) + { + sig_shift++; + max_val >>= 1; + } + + for (i=0;i max_val) + max_val = tmp; + } + if (max_val>16383) + { + spx_word32_t sum=0; + for (i=0;i= max_val) + max_val = tmp; + } + + sig_shift=0; + while (max_val>max_scale) + { + sig_shift++; + max_val >>= 1; + } + + for (i=0;i>1; + for (i=0;i>1; + N2 = N>>1; + ALLOC(xx1, M2+N2, spx_word16_t); + ALLOC(xx2, M2+N2, spx_word16_t); + + for (i = 0; i < N2; i++) + xx1[i] = x1[N2-1-i]; + for (i = 0; i < M2; i++) + xx1[N2+i] = mem1[2*i+1]; + for (i = 0; i < N2; i++) + xx2[i] = x2[N2-1-i]; + for (i = 0; i < M2; i++) + xx2[N2+i] = mem2[2*i+1]; + + for (i = 0; i < N2; i += 2) { + spx_sig_t y0, y1, y2, y3; + spx_word16_t x10, x20; + + y0 = y1 = y2 = y3 = 0; + x10 = xx1[N2-2-i]; + x20 = xx2[N2-2-i]; + + for (j = 0; j < M2; j += 2) { + spx_word16_t x11, x21; + spx_word16_t a0, a1; + + a0 = a[2*j]; + a1 = a[2*j+1]; + x11 = xx1[N2-1+j-i]; + x21 = xx2[N2-1+j-i]; + +#ifdef FIXED_POINT + /* We multiply twice by the same coef to avoid overflows */ + y0 = MAC16_16(MAC16_16(y0, a0, x11), NEG16(a0), x21); + y1 = MAC16_16(MAC16_16(y1, a1, x11), a1, x21); + y2 = MAC16_16(MAC16_16(y2, a0, x10), NEG16(a0), x20); + y3 = MAC16_16(MAC16_16(y3, a1, x10), a1, x20); +#else + y0 = ADD32(y0,MULT16_16(a0, x11-x21)); + y1 = ADD32(y1,MULT16_16(a1, x11+x21)); + y2 = ADD32(y2,MULT16_16(a0, x10-x20)); + y3 = ADD32(y3,MULT16_16(a1, x10+x20)); +#endif + a0 = a[2*j+2]; + a1 = a[2*j+3]; + x10 = xx1[N2+j-i]; + x20 = xx2[N2+j-i]; + +#ifdef FIXED_POINT + /* We multiply twice by the same coef to avoid overflows */ + y0 = MAC16_16(MAC16_16(y0, a0, x10), NEG16(a0), x20); + y1 = MAC16_16(MAC16_16(y1, a1, x10), a1, x20); + y2 = MAC16_16(MAC16_16(y2, a0, x11), NEG16(a0), x21); + y3 = MAC16_16(MAC16_16(y3, a1, x11), a1, x21); +#else + y0 = ADD32(y0,MULT16_16(a0, x10-x20)); + y1 = ADD32(y1,MULT16_16(a1, x10+x20)); + y2 = ADD32(y2,MULT16_16(a0, x11-x21)); + y3 = ADD32(y3,MULT16_16(a1, x11+x21)); +#endif + } +#ifdef FIXED_POINT + y[2*i] = EXTRACT16(SATURATE32(PSHR32(y0,15),32767)); + y[2*i+1] = EXTRACT16(SATURATE32(PSHR32(y1,15),32767)); + y[2*i+2] = EXTRACT16(SATURATE32(PSHR32(y2,15),32767)); + y[2*i+3] = EXTRACT16(SATURATE32(PSHR32(y3,15),32767)); +#else + /* Normalize up explicitly if we're in float */ + y[2*i] = 2.f*y0; + y[2*i+1] = 2.f*y1; + y[2*i+2] = 2.f*y2; + y[2*i+3] = 2.f*y3; +#endif + } + + for (i = 0; i < M2; i++) + mem1[2*i+1] = xx1[i]; + for (i = 0; i < M2; i++) + mem2[2*i+1] = xx2[i]; +} + +#ifdef FIXED_POINT +#if 0 +const spx_word16_t shift_filt[3][7] = {{-33, 1043, -4551, 19959, 19959, -4551, 1043}, + {-98, 1133, -4425, 29179, 8895, -2328, 444}, + {444, -2328, 8895, 29179, -4425, 1133, -98}}; +#else +const spx_word16_t shift_filt[3][7] = {{-390, 1540, -4993, 20123, 20123, -4993, 1540}, + {-1064, 2817, -6694, 31589, 6837, -990, -209}, + {-209, -990, 6837, 31589, -6694, 2817, -1064}}; +#endif +#else +#if 0 +const float shift_filt[3][7] = {{-9.9369e-04, 3.1831e-02, -1.3889e-01, 6.0910e-01, 6.0910e-01, -1.3889e-01, 3.1831e-02}, + {-0.0029937, 0.0345613, -0.1350474, 0.8904793, 0.2714479, -0.0710304, 0.0135403}, + {0.0135403, -0.0710304, 0.2714479, 0.8904793, -0.1350474, 0.0345613, -0.0029937}}; +#else +const float shift_filt[3][7] = {{-0.011915f, 0.046995f, -0.152373f, 0.614108f, 0.614108f, -0.152373f, 0.046995f}, + {-0.0324855f, 0.0859768f, -0.2042986f, 0.9640297f, 0.2086420f, -0.0302054f, -0.0063646f}, + {-0.0063646f, -0.0302054f, 0.2086420f, 0.9640297f, -0.2042986f, 0.0859768f, -0.0324855f}}; +#endif +#endif + +int interp_pitch( +spx_word16_t *exc, /*decoded excitation*/ +spx_word16_t *interp, /*decoded excitation*/ +int pitch, /*pitch period*/ +int len +) +{ + int i,j,k; + spx_word32_t corr[4][7]; + spx_word32_t maxcorr; + int maxi, maxj; + for (i=0;i<7;i++) + { + corr[0][i] = inner_prod(exc, exc-pitch-3+i, len); + } + for (i=0;i<3;i++) + { + for (j=0;j<7;j++) + { + int i1, i2; + spx_word32_t tmp=0; + i1 = 3-j; + if (i1<0) + i1 = 0; + i2 = 10-j; + if (i2>7) + i2 = 7; + for (k=i1;k maxcorr) + { + maxcorr = corr[i][j]; + maxi=i; + maxj=j; + } + } + } + for (i=0;i0) + { + for (k=0;k<7;k++) + { + tmp += MULT16_16(exc[i-(pitch-maxj+3)+k-3],shift_filt[maxi-1][k]); + } + } else { + tmp = SHL32(exc[i-(pitch-maxj+3)],15); + } + interp[i] = PSHR32(tmp,15); + } + return pitch-maxj+3; +} + +void multicomb( +spx_word16_t *exc, /*decoded excitation*/ +spx_word16_t *new_exc, /*enhanced excitation*/ +spx_coef_t *ak, /*LPC filter coefs*/ +int p, /*LPC order*/ +int nsf, /*sub-frame size*/ +int pitch, /*pitch period*/ +int max_pitch, +spx_word16_t comb_gain, /*gain of comb filter*/ +char *stack +) +{ + int i; + VARDECL(spx_word16_t *iexc); + spx_word16_t old_ener, new_ener; + int corr_pitch; + + spx_word16_t iexc0_mag, iexc1_mag, exc_mag; + spx_word32_t corr0, corr1; + spx_word16_t gain0, gain1; + spx_word16_t pgain1, pgain2; + spx_word16_t c1, c2; + spx_word16_t g1, g2; + spx_word16_t ngain; + spx_word16_t gg1, gg2; +#ifdef FIXED_POINT + int scaledown=0; +#endif +#if 0 /* Set to 1 to enable full pitch search */ + int nol_pitch[6]; + spx_word16_t nol_pitch_coef[6]; + spx_word16_t ol_pitch_coef; + open_loop_nbest_pitch(exc, 20, 120, nsf, + nol_pitch, nol_pitch_coef, 6, stack); + corr_pitch=nol_pitch[0]; + ol_pitch_coef = nol_pitch_coef[0]; + /*Try to remove pitch multiples*/ + for (i=1;i<6;i++) + { +#ifdef FIXED_POINT + if ((nol_pitch_coef[i]>MULT16_16_Q15(nol_pitch_coef[0],19661)) && +#else + if ((nol_pitch_coef[i]>.6*nol_pitch_coef[0]) && +#endif + (ABS(2*nol_pitch[i]-corr_pitch)<=2 || ABS(3*nol_pitch[i]-corr_pitch)<=3 || + ABS(4*nol_pitch[i]-corr_pitch)<=4 || ABS(5*nol_pitch[i]-corr_pitch)<=5)) + { + corr_pitch = nol_pitch[i]; + } + } +#else + corr_pitch = pitch; +#endif + + ALLOC(iexc, 2*nsf, spx_word16_t); + + interp_pitch(exc, iexc, corr_pitch, 80); + if (corr_pitch>max_pitch) + interp_pitch(exc, iexc+nsf, 2*corr_pitch, 80); + else + interp_pitch(exc, iexc+nsf, -corr_pitch, 80); + +#ifdef FIXED_POINT + for (i=0;i16383) + { + scaledown = 1; + break; + } + } + if (scaledown) + { + for (i=0;i MULT16_16(iexc0_mag,exc_mag)) + pgain1 = QCONST16(1., 14); + else + pgain1 = PDIV32_16(SHL32(PDIV32(corr0, exc_mag),14),iexc0_mag); + if (corr1 > MULT16_16(iexc1_mag,exc_mag)) + pgain2 = QCONST16(1., 14); + else + pgain2 = PDIV32_16(SHL32(PDIV32(corr1, exc_mag),14),iexc1_mag); + gg1 = PDIV32_16(SHL32(EXTEND32(exc_mag),8), iexc0_mag); + gg2 = PDIV32_16(SHL32(EXTEND32(exc_mag),8), iexc1_mag); + if (comb_gain>0) + { +#ifdef FIXED_POINT + c1 = (MULT16_16_Q15(QCONST16(.4,15),comb_gain)+QCONST16(.07,15)); + c2 = QCONST16(.5,15)+MULT16_16_Q14(QCONST16(1.72,14),(c1-QCONST16(.07,15))); +#else + c1 = .4*comb_gain+.07; + c2 = .5+1.72*(c1-.07); +#endif + } else + { + c1=c2=0; + } +#ifdef FIXED_POINT + g1 = 32767 - MULT16_16_Q13(MULT16_16_Q15(c2, pgain1),pgain1); + g2 = 32767 - MULT16_16_Q13(MULT16_16_Q15(c2, pgain2),pgain2); +#else + g1 = 1-c2*pgain1*pgain1; + g2 = 1-c2*pgain2*pgain2; +#endif + if (g1max_pitch) + { + gain0 = MULT16_16_Q15(QCONST16(.7,15),MULT16_16_Q14(g1,gg1)); + gain1 = MULT16_16_Q15(QCONST16(.3,15),MULT16_16_Q14(g2,gg2)); + } else { + gain0 = MULT16_16_Q15(QCONST16(.6,15),MULT16_16_Q14(g1,gg1)); + gain1 = MULT16_16_Q15(QCONST16(.6,15),MULT16_16_Q14(g2,gg2)); + } + for (i=0;i new_ener) + old_ener = new_ener; + ngain = PDIV32_16(SHL32(EXTEND32(old_ener),14),new_ener); + + for (i=0;imax_scale) + { + sig_shift++; + max_val >>= 1; + } + + __asm__ __volatile__ ( + ".normalize16loop%=: \n" + + "\tldr %4, [%0], #4 \n" + "\tldr %5, [%0], #4 \n" + "\tmov %4, %4, asr %3 \n" + "\tstrh %4, [%1], #2 \n" + "\tldr %4, [%0], #4 \n" + "\tmov %5, %5, asr %3 \n" + "\tstrh %5, [%1], #2 \n" + "\tldr %5, [%0], #4 \n" + "\tmov %4, %4, asr %3 \n" + "\tstrh %4, [%1], #2 \n" + "\tsubs %2, %2, #1 \n" + "\tmov %5, %5, asr %3 \n" + "\tstrh %5, [%1], #2 \n" + + "\tbgt .normalize16loop%=\n" + : "=r" (dead1), "=r" (dead2), "=r" (dead3), "=r" (dead4), + "=r" (dead5), "=r" (dead6) + : "0" (x), "1" (y), "2" (len>>2), "3" (sig_shift) + : "cc", "memory"); + return sig_shift; +} + diff --git a/android/app/src/main/jni/libspeex/filters_bfin.h b/android/app/src/main/jni/libspeex/filters_bfin.h new file mode 100644 index 000000000..1e433ee16 --- /dev/null +++ b/android/app/src/main/jni/libspeex/filters_bfin.h @@ -0,0 +1,515 @@ +/* Copyright (C) 2005 Analog Devices */ +/** + @file filters_bfin.h + @brief Various analysis/synthesis filters (Blackfin version) +*/ +/* + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + - Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + - Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + - Neither the name of the Xiph.org Foundation nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR + CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#define OVERRIDE_NORMALIZE16 +int normalize16(const spx_sig_t *x, spx_word16_t *y, spx_sig_t max_scale, int len) +{ + spx_sig_t max_val=1; + int sig_shift; + __asm__ + ( + "%0 = 0;\n\t" + "I0 = %1;\n\t" + "L0 = 0;\n\t" + "R1 = [I0++];\n\t" + "LOOP norm_max%= LC0 = %2;\n\t" + "LOOP_BEGIN norm_max%=;\n\t" + "R2 = ABS R1 || R1 = [I0++];\n\t" + "%0 = MAX(%0, R2);\n\t" + "LOOP_END norm_max%=;\n\t" + : "=&d" (max_val) + : "a" (x), "a" (len) + : "R1", "R2" + ); + + sig_shift=0; + while (max_val>max_scale) + { + sig_shift++; + max_val >>= 1; + } + + __asm__ __volatile__ + ( + "I0 = %0;\n\t" + "L0 = 0;\n\t" + "P1 = %1;\n\t" + "R0 = [I0++];\n\t" + "LOOP norm_shift%= LC0 = %3;\n\t" + "LOOP_BEGIN norm_shift%=;\n\t" + "R1 = ASHIFT R0 by %2.L || R0 = [I0++];\n\t" + "W[P1++] = R1;\n\t" + "LOOP_END norm_shift%=;\n\t" + "R1 = ASHIFT R0 by %2.L;\n\t" + "W[P1++] = R1;\n\t" + : : "a" (x), "a" (y), "d" (-sig_shift), "a" (len-1) + : "I0", "L0", "P1", "R0", "R1", "memory" + ); + return sig_shift; +} + + + +#define OVERRIDE_FILTER_MEM16 +void filter_mem16(const spx_word16_t *_x, const spx_coef_t *num, const spx_coef_t *den, spx_word16_t *_y, int N, int ord, spx_mem_t *mem, char *stack) +{ + VARDECL(spx_word32_t *xy2); + VARDECL(spx_word32_t *numden_a); + spx_word32_t *xy; + spx_word16_t *numden; + int i; + + ALLOC(xy2, (N+1), spx_word32_t); + ALLOC(numden_a, (2*ord+2), spx_word32_t); + xy = xy2+1; + numden = (spx_word16_t*) numden_a; + + for (i=0;i>> 13;\n\t" + "W[%0] = R3.L;\n\t" + "R0 <<= 1;\n\t" + "R1 = R1 + R0;\n\t" + "R1 >>>= 13;\n\t" + "W[%1] = R1.L;\n\t" + "LOOP_END samples%=;\n\t" + : "=a" (ytmp2), "=a" (y) + : "a" (awk2), "a" (ak), "d" (ord), "m" (N), "0" (ytmp2), "1" (y) + : "A0", "A1", "R0", "R1", "R2", "R3", "I0", "I1", "I2", "I3", "L0", "L1", "L2", "L3", "A0", "A1" + ); +} + + + +#if 0 /* Equivalent C function for filter_mem2 and compute_impulse_response */ +#define min(a,b) ((a)<(b) ? (a):(b)) + +void compute_impulse_response(const spx_coef_t *ak, const spx_coef_t *awk1, const spx_coef_t *awk2, spx_word16_t *y, int N, int ord, char *stack) +{ + int i,j; + VARDECL(spx_word16_t *ytmp); + ALLOC(ytmp, N, spx_word16_t); + + y[0] = LPC_SCALING; + for (i=0;i + +void filter_mem16_10(const float *x, const float *_num, const float *_den, float *y, int N, int ord, float *_mem) +{ + __m128 num[3], den[3], mem[3]; + + int i; + + /* Copy numerator, denominator and memory to aligned xmm */ + for (i=0;i<2;i++) + { + mem[i] = _mm_loadu_ps(_mem+4*i); + num[i] = _mm_loadu_ps(_num+4*i); + den[i] = _mm_loadu_ps(_den+4*i); + } + mem[2] = _mm_setr_ps(_mem[8], _mem[9], 0, 0); + num[2] = _mm_setr_ps(_num[8], _num[9], 0, 0); + den[2] = _mm_setr_ps(_den[8], _den[9], 0, 0); + + for (i=0;i>1; + __asm__ ( + "P0 = 15;\n\t" + "R0 = %1;\n\t" + "R1 = %2;\n\t" + //"R0 = R0 + R1;\n\t" + "R0 <<= 1;\n\t" + "DIVS (R0, R1);\n\t" + "LOOP divide%= LC0 = P0;\n\t" + "LOOP_BEGIN divide%=;\n\t" + "DIVQ (R0, R1);\n\t" + "LOOP_END divide%=;\n\t" + "R0 = R0.L;\n\t" + "%0 = R0;\n\t" + : "=m" (res) + : "m" (a), "m" (bb) + : "P0", "R0", "R1", "cc"); + return res; +} + +#undef DIV32_16 +static inline spx_word16_t DIV32_16(spx_word32_t a, spx_word16_t b) +{ + spx_word32_t res, bb; + bb = b; + /* Make the roundinf consistent with the C version + (do we need to do that?)*/ + if (a<0) + a += (b-1); + __asm__ ( + "P0 = 15;\n\t" + "R0 = %1;\n\t" + "R1 = %2;\n\t" + "R0 <<= 1;\n\t" + "DIVS (R0, R1);\n\t" + "LOOP divide%= LC0 = P0;\n\t" + "LOOP_BEGIN divide%=;\n\t" + "DIVQ (R0, R1);\n\t" + "LOOP_END divide%=;\n\t" + "R0 = R0.L;\n\t" + "%0 = R0;\n\t" + : "=m" (res) + : "m" (a), "m" (bb) + : "P0", "R0", "R1", "cc"); + return res; +} + +#undef MAX16 +static inline spx_word16_t MAX16(spx_word16_t a, spx_word16_t b) +{ + spx_word32_t res; + __asm__ ( + "%1 = %1.L (X);\n\t" + "%2 = %2.L (X);\n\t" + "%0 = MAX(%1,%2);" + : "=d" (res) + : "%d" (a), "d" (b) + ); + return res; +} + +#undef MULT16_32_Q15 +static inline spx_word32_t MULT16_32_Q15(spx_word16_t a, spx_word32_t b) +{ + spx_word32_t res; + __asm__ + ( + "A1 = %2.L*%1.L (M);\n\t" + "A1 = A1 >>> 15;\n\t" + "%0 = (A1 += %2.L*%1.H) ;\n\t" + : "=&W" (res), "=&d" (b) + : "d" (a), "1" (b) + : "A1" + ); + return res; +} + +#undef MAC16_32_Q15 +static inline spx_word32_t MAC16_32_Q15(spx_word32_t c, spx_word16_t a, spx_word32_t b) +{ + spx_word32_t res; + __asm__ + ( + "A1 = %2.L*%1.L (M);\n\t" + "A1 = A1 >>> 15;\n\t" + "%0 = (A1 += %2.L*%1.H);\n\t" + "%0 = %0 + %4;\n\t" + : "=&W" (res), "=&d" (b) + : "d" (a), "1" (b), "d" (c) + : "A1" + ); + return res; +} + +#undef MULT16_32_Q14 +static inline spx_word32_t MULT16_32_Q14(spx_word16_t a, spx_word32_t b) +{ + spx_word32_t res; + __asm__ + ( + "%2 <<= 1;\n\t" + "A1 = %1.L*%2.L (M);\n\t" + "A1 = A1 >>> 15;\n\t" + "%0 = (A1 += %1.L*%2.H);\n\t" + : "=W" (res), "=d" (a), "=d" (b) + : "1" (a), "2" (b) + : "A1" + ); + return res; +} + +#undef MAC16_32_Q14 +static inline spx_word32_t MAC16_32_Q14(spx_word32_t c, spx_word16_t a, spx_word32_t b) +{ + spx_word32_t res; + __asm__ + ( + "%1 <<= 1;\n\t" + "A1 = %2.L*%1.L (M);\n\t" + "A1 = A1 >>> 15;\n\t" + "%0 = (A1 += %2.L*%1.H);\n\t" + "%0 = %0 + %4;\n\t" + : "=&W" (res), "=&d" (b) + : "d" (a), "1" (b), "d" (c) + : "A1" + ); + return res; +} + +#endif diff --git a/android/app/src/main/jni/libspeex/fixed_debug.h b/android/app/src/main/jni/libspeex/fixed_debug.h new file mode 100644 index 000000000..54f3866e8 --- /dev/null +++ b/android/app/src/main/jni/libspeex/fixed_debug.h @@ -0,0 +1,487 @@ +/* Copyright (C) 2003 Jean-Marc Valin */ +/** + @file fixed_debug.h + @brief Fixed-point operations with debugging +*/ +/* + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + - Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + - Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + - Neither the name of the Xiph.org Foundation nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR + CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#ifndef FIXED_DEBUG_H +#define FIXED_DEBUG_H + +#include + +extern long long spx_mips; +#define MIPS_INC spx_mips++, + +#define QCONST16(x,bits) ((spx_word16_t)(.5+(x)*(((spx_word32_t)1)<<(bits)))) +#define QCONST32(x,bits) ((spx_word32_t)(.5+(x)*(((spx_word32_t)1)<<(bits)))) + + +#define VERIFY_SHORT(x) ((x)<=32767&&(x)>=-32768) +#define VERIFY_INT(x) ((x)<=2147483647LL&&(x)>=-2147483648LL) + +static inline short NEG16(int x) +{ + int res; + if (!VERIFY_SHORT(x)) + { + fprintf (stderr, "NEG16: input is not short: %d\n", (int)x); + } + res = -x; + if (!VERIFY_SHORT(res)) + fprintf (stderr, "NEG16: output is not short: %d\n", (int)res); + spx_mips++; + return res; +} +static inline int NEG32(long long x) +{ + long long res; + if (!VERIFY_INT(x)) + { + fprintf (stderr, "NEG16: input is not int: %d\n", (int)x); + } + res = -x; + if (!VERIFY_INT(res)) + fprintf (stderr, "NEG16: output is not int: %d\n", (int)res); + spx_mips++; + return res; +} + +#define EXTRACT16(x) _EXTRACT16(x, __FILE__, __LINE__) +static inline short _EXTRACT16(int x, char *file, int line) +{ + int res; + if (!VERIFY_SHORT(x)) + { + fprintf (stderr, "EXTRACT16: input is not short: %d in %s: line %d\n", x, file, line); + } + res = x; + spx_mips++; + return res; +} + +#define EXTEND32(x) _EXTEND32(x, __FILE__, __LINE__) +static inline int _EXTEND32(int x, char *file, int line) +{ + int res; + if (!VERIFY_SHORT(x)) + { + fprintf (stderr, "EXTEND32: input is not short: %d in %s: line %d\n", x, file, line); + } + res = x; + spx_mips++; + return res; +} + +#define SHR16(a, shift) _SHR16(a, shift, __FILE__, __LINE__) +static inline short _SHR16(int a, int shift, char *file, int line) +{ + int res; + if (!VERIFY_SHORT(a) || !VERIFY_SHORT(shift)) + { + fprintf (stderr, "SHR16: inputs are not short: %d >> %d in %s: line %d\n", a, shift, file, line); + } + res = a>>shift; + if (!VERIFY_SHORT(res)) + fprintf (stderr, "SHR16: output is not short: %d in %s: line %d\n", res, file, line); + spx_mips++; + return res; +} +#define SHL16(a, shift) _SHL16(a, shift, __FILE__, __LINE__) +static inline short _SHL16(int a, int shift, char *file, int line) +{ + int res; + if (!VERIFY_SHORT(a) || !VERIFY_SHORT(shift)) + { + fprintf (stderr, "SHL16: inputs are not short: %d %d in %s: line %d\n", a, shift, file, line); + } + res = a<>shift; + if (!VERIFY_INT(res)) + { + fprintf (stderr, "SHR32: output is not int: %d\n", (int)res); + } + spx_mips++; + return res; +} +static inline int SHL32(long long a, int shift) +{ + long long res; + if (!VERIFY_INT(a) || !VERIFY_SHORT(shift)) + { + fprintf (stderr, "SHL32: inputs are not int: %d %d\n", (int)a, shift); + } + res = a<>1))),shift)) +#define PSHR32(a,shift) (SHR32(ADD32((a),((EXTEND32(1)<<((shift))>>1))),shift)) +#define VSHR32(a, shift) (((shift)>0) ? SHR32(a, shift) : SHL32(a, -(shift))) + +#define SATURATE16(x,a) (((x)>(a) ? (a) : (x)<-(a) ? -(a) : (x))) +#define SATURATE32(x,a) (((x)>(a) ? (a) : (x)<-(a) ? -(a) : (x))) + +//#define SHR(a,shift) ((a) >> (shift)) +//#define SHL(a,shift) ((a) << (shift)) + +#define ADD16(a, b) _ADD16(a, b, __FILE__, __LINE__) +static inline short _ADD16(int a, int b, char *file, int line) +{ + int res; + if (!VERIFY_SHORT(a) || !VERIFY_SHORT(b)) + { + fprintf (stderr, "ADD16: inputs are not short: %d %d in %s: line %d\n", a, b, file, line); + } + res = a+b; + if (!VERIFY_SHORT(res)) + { + fprintf (stderr, "ADD16: output is not short: %d+%d=%d in %s: line %d\n", a,b,res, file, line); + } + spx_mips++; + return res; +} + +#define SUB16(a, b) _SUB16(a, b, __FILE__, __LINE__) +static inline short _SUB16(int a, int b, char *file, int line) +{ + int res; + if (!VERIFY_SHORT(a) || !VERIFY_SHORT(b)) + { + fprintf (stderr, "SUB16: inputs are not short: %d %d in %s: line %d\n", a, b, file, line); + } + res = a-b; + if (!VERIFY_SHORT(res)) + fprintf (stderr, "SUB16: output is not short: %d in %s: line %d\n", res, file, line); + spx_mips++; + return res; +} + +#define ADD32(a, b) _ADD32(a, b, __FILE__, __LINE__) +static inline int _ADD32(long long a, long long b, char *file, int line) +{ + long long res; + if (!VERIFY_INT(a) || !VERIFY_INT(b)) + { + fprintf (stderr, "ADD32: inputs are not int: %d %d in %s: line %d\n", (int)a, (int)b, file, line); + } + res = a+b; + if (!VERIFY_INT(res)) + { + fprintf (stderr, "ADD32: output is not int: %d in %s: line %d\n", (int)res, file, line); + } + spx_mips++; + return res; +} + +static inline int SUB32(long long a, long long b) +{ + long long res; + if (!VERIFY_INT(a) || !VERIFY_INT(b)) + { + fprintf (stderr, "SUB32: inputs are not int: %d %d\n", (int)a, (int)b); + } + res = a-b; + if (!VERIFY_INT(res)) + fprintf (stderr, "SUB32: output is not int: %d\n", (int)res); + spx_mips++; + return res; +} + +#define ADD64(a,b) (MIPS_INC(a)+(b)) + +/* result fits in 16 bits */ +static inline short MULT16_16_16(int a, int b) +{ + int res; + if (!VERIFY_SHORT(a) || !VERIFY_SHORT(b)) + { + fprintf (stderr, "MULT16_16_16: inputs are not short: %d %d\n", a, b); + } + res = a*b; + if (!VERIFY_SHORT(res)) + fprintf (stderr, "MULT16_16_16: output is not short: %d\n", res); + spx_mips++; + return res; +} + +#define MULT16_16(a, b) _MULT16_16(a, b, __FILE__, __LINE__) +static inline int _MULT16_16(int a, int b, char *file, int line) +{ + long long res; + if (!VERIFY_SHORT(a) || !VERIFY_SHORT(b)) + { + fprintf (stderr, "MULT16_16: inputs are not short: %d %d in %s: line %d\n", a, b, file, line); + } + res = ((long long)a)*b; + if (!VERIFY_INT(res)) + fprintf (stderr, "MULT16_16: output is not int: %d in %s: line %d\n", (int)res, file, line); + spx_mips++; + return res; +} + +#define MAC16_16(c,a,b) (spx_mips--,ADD32((c),MULT16_16((a),(b)))) +#define MAC16_16_Q11(c,a,b) (EXTRACT16(ADD16((c),EXTRACT16(SHR32(MULT16_16((a),(b)),11))))) +#define MAC16_16_Q13(c,a,b) (EXTRACT16(ADD16((c),EXTRACT16(SHR32(MULT16_16((a),(b)),13))))) +#define MAC16_16_P13(c,a,b) (EXTRACT16(ADD32((c),SHR32(ADD32(4096,MULT16_16((a),(b))),13)))) + + +#define MULT16_32_QX(a, b, Q) _MULT16_32_QX(a, b, Q, __FILE__, __LINE__) +static inline int _MULT16_32_QX(int a, long long b, int Q, char *file, int line) +{ + long long res; + if (!VERIFY_SHORT(a) || !VERIFY_INT(b)) + { + fprintf (stderr, "MULT16_32_Q%d: inputs are not short+int: %d %d in %s: line %d\n", Q, (int)a, (int)b, file, line); + } + if (ABS32(b)>=(EXTEND32(1)<<(15+Q))) + fprintf (stderr, "MULT16_32_Q%d: second operand too large: %d %d in %s: line %d\n", Q, (int)a, (int)b, file, line); + res = (((long long)a)*(long long)b) >> Q; + if (!VERIFY_INT(res)) + fprintf (stderr, "MULT16_32_Q%d: output is not int: %d*%d=%d in %s: line %d\n", Q, (int)a, (int)b,(int)res, file, line); + spx_mips+=5; + return res; +} + +static inline int MULT16_32_PX(int a, long long b, int Q) +{ + long long res; + if (!VERIFY_SHORT(a) || !VERIFY_INT(b)) + { + fprintf (stderr, "MULT16_32_P%d: inputs are not short+int: %d %d\n", Q, (int)a, (int)b); + } + if (ABS32(b)>=(EXTEND32(1)<<(15+Q))) + fprintf (stderr, "MULT16_32_Q%d: second operand too large: %d %d\n", Q, (int)a, (int)b); + res = ((((long long)a)*(long long)b) + ((EXTEND32(1)<>1))>> Q; + if (!VERIFY_INT(res)) + fprintf (stderr, "MULT16_32_P%d: output is not int: %d*%d=%d\n", Q, (int)a, (int)b,(int)res); + spx_mips+=5; + return res; +} + + +#define MULT16_32_Q11(a,b) MULT16_32_QX(a,b,11) +#define MAC16_32_Q11(c,a,b) ADD32((c),MULT16_32_Q11((a),(b))) +#define MULT16_32_Q12(a,b) MULT16_32_QX(a,b,12) +#define MULT16_32_Q13(a,b) MULT16_32_QX(a,b,13) +#define MULT16_32_Q14(a,b) MULT16_32_QX(a,b,14) +#define MULT16_32_Q15(a,b) MULT16_32_QX(a,b,15) +#define MULT16_32_P15(a,b) MULT16_32_PX(a,b,15) +#define MAC16_32_Q15(c,a,b) ADD32((c),MULT16_32_Q15((a),(b))) + +static inline int SATURATE(int a, int b) +{ + if (a>b) + a=b; + if (a<-b) + a = -b; + return a; +} + +static inline int MULT16_16_Q11_32(int a, int b) +{ + long long res; + if (!VERIFY_SHORT(a) || !VERIFY_SHORT(b)) + { + fprintf (stderr, "MULT16_16_Q11: inputs are not short: %d %d\n", a, b); + } + res = ((long long)a)*b; + res >>= 11; + if (!VERIFY_INT(res)) + fprintf (stderr, "MULT16_16_Q11: output is not short: %d*%d=%d\n", (int)a, (int)b, (int)res); + spx_mips+=3; + return res; +} +static inline short MULT16_16_Q13(int a, int b) +{ + long long res; + if (!VERIFY_SHORT(a) || !VERIFY_SHORT(b)) + { + fprintf (stderr, "MULT16_16_Q13: inputs are not short: %d %d\n", a, b); + } + res = ((long long)a)*b; + res >>= 13; + if (!VERIFY_SHORT(res)) + fprintf (stderr, "MULT16_16_Q13: output is not short: %d*%d=%d\n", a, b, (int)res); + spx_mips+=3; + return res; +} +static inline short MULT16_16_Q14(int a, int b) +{ + long long res; + if (!VERIFY_SHORT(a) || !VERIFY_SHORT(b)) + { + fprintf (stderr, "MULT16_16_Q14: inputs are not short: %d %d\n", a, b); + } + res = ((long long)a)*b; + res >>= 14; + if (!VERIFY_SHORT(res)) + fprintf (stderr, "MULT16_16_Q14: output is not short: %d\n", (int)res); + spx_mips+=3; + return res; +} +static inline short MULT16_16_Q15(int a, int b) +{ + long long res; + if (!VERIFY_SHORT(a) || !VERIFY_SHORT(b)) + { + fprintf (stderr, "MULT16_16_Q15: inputs are not short: %d %d\n", a, b); + } + res = ((long long)a)*b; + res >>= 15; + if (!VERIFY_SHORT(res)) + { + fprintf (stderr, "MULT16_16_Q15: output is not short: %d\n", (int)res); + } + spx_mips+=3; + return res; +} + +static inline short MULT16_16_P13(int a, int b) +{ + long long res; + if (!VERIFY_SHORT(a) || !VERIFY_SHORT(b)) + { + fprintf (stderr, "MULT16_16_P13: inputs are not short: %d %d\n", a, b); + } + res = ((long long)a)*b; + res += 4096; + if (!VERIFY_INT(res)) + fprintf (stderr, "MULT16_16_P13: overflow: %d*%d=%d\n", a, b, (int)res); + res >>= 13; + if (!VERIFY_SHORT(res)) + fprintf (stderr, "MULT16_16_P13: output is not short: %d*%d=%d\n", a, b, (int)res); + spx_mips+=4; + return res; +} +static inline short MULT16_16_P14(int a, int b) +{ + long long res; + if (!VERIFY_SHORT(a) || !VERIFY_SHORT(b)) + { + fprintf (stderr, "MULT16_16_P14: inputs are not short: %d %d\n", a, b); + } + res = ((long long)a)*b; + res += 8192; + if (!VERIFY_INT(res)) + fprintf (stderr, "MULT16_16_P14: overflow: %d*%d=%d\n", a, b, (int)res); + res >>= 14; + if (!VERIFY_SHORT(res)) + fprintf (stderr, "MULT16_16_P14: output is not short: %d*%d=%d\n", a, b, (int)res); + spx_mips+=4; + return res; +} +static inline short MULT16_16_P15(int a, int b) +{ + long long res; + if (!VERIFY_SHORT(a) || !VERIFY_SHORT(b)) + { + fprintf (stderr, "MULT16_16_P15: inputs are not short: %d %d\n", a, b); + } + res = ((long long)a)*b; + res += 16384; + if (!VERIFY_INT(res)) + fprintf (stderr, "MULT16_16_P15: overflow: %d*%d=%d\n", a, b, (int)res); + res >>= 15; + if (!VERIFY_SHORT(res)) + fprintf (stderr, "MULT16_16_P15: output is not short: %d*%d=%d\n", a, b, (int)res); + spx_mips+=4; + return res; +} + +#define DIV32_16(a, b) _DIV32_16(a, b, __FILE__, __LINE__) + +static inline int _DIV32_16(long long a, long long b, char *file, int line) +{ + long long res; + if (b==0) + { + fprintf(stderr, "DIV32_16: divide by zero: %d/%d in %s: line %d\n", (int)a, (int)b, file, line); + return 0; + } + if (!VERIFY_INT(a) || !VERIFY_SHORT(b)) + { + fprintf (stderr, "DIV32_16: inputs are not int/short: %d %d in %s: line %d\n", (int)a, (int)b, file, line); + } + res = a/b; + if (!VERIFY_SHORT(res)) + { + fprintf (stderr, "DIV32_16: output is not short: %d / %d = %d in %s: line %d\n", (int)a,(int)b,(int)res, file, line); + if (res>32767) + res = 32767; + if (res<-32768) + res = -32768; + } + spx_mips+=20; + return res; +} + +#define DIV32(a, b) _DIV32(a, b, __FILE__, __LINE__) +static inline int _DIV32(long long a, long long b, char *file, int line) +{ + long long res; + if (b==0) + { + fprintf(stderr, "DIV32: divide by zero: %d/%d in %s: line %d\n", (int)a, (int)b, file, line); + return 0; + } + + if (!VERIFY_INT(a) || !VERIFY_INT(b)) + { + fprintf (stderr, "DIV32: inputs are not int/short: %d %d in %s: line %d\n", (int)a, (int)b, file, line); + } + res = a/b; + if (!VERIFY_INT(res)) + fprintf (stderr, "DIV32: output is not int: %d in %s: line %d\n", (int)res, file, line); + spx_mips+=36; + return res; +} +#define PDIV32(a,b) DIV32(ADD32((a),(b)>>1),b) +#define PDIV32_16(a,b) DIV32_16(ADD32((a),(b)>>1),b) + +#endif diff --git a/android/app/src/main/jni/libspeex/fixed_generic.h b/android/app/src/main/jni/libspeex/fixed_generic.h new file mode 100644 index 000000000..3fb096ed9 --- /dev/null +++ b/android/app/src/main/jni/libspeex/fixed_generic.h @@ -0,0 +1,106 @@ +/* Copyright (C) 2003 Jean-Marc Valin */ +/** + @file fixed_generic.h + @brief Generic fixed-point operations +*/ +/* + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + - Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + - Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + - Neither the name of the Xiph.org Foundation nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR + CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#ifndef FIXED_GENERIC_H +#define FIXED_GENERIC_H + +#define QCONST16(x,bits) ((spx_word16_t)(.5+(x)*(((spx_word32_t)1)<<(bits)))) +#define QCONST32(x,bits) ((spx_word32_t)(.5+(x)*(((spx_word32_t)1)<<(bits)))) + +#define NEG16(x) (-(x)) +#define NEG32(x) (-(x)) +#define EXTRACT16(x) ((spx_word16_t)(x)) +#define EXTEND32(x) ((spx_word32_t)(x)) +#define SHR16(a,shift) ((a) >> (shift)) +#define SHL16(a,shift) ((a) << (shift)) +#define SHR32(a,shift) ((a) >> (shift)) +#define SHL32(a,shift) ((a) << (shift)) +#define PSHR16(a,shift) (SHR16((a)+((1<<((shift))>>1)),shift)) +#define PSHR32(a,shift) (SHR32((a)+((EXTEND32(1)<<((shift))>>1)),shift)) +#define VSHR32(a, shift) (((shift)>0) ? SHR32(a, shift) : SHL32(a, -(shift))) +#define SATURATE16(x,a) (((x)>(a) ? (a) : (x)<-(a) ? -(a) : (x))) +#define SATURATE32(x,a) (((x)>(a) ? (a) : (x)<-(a) ? -(a) : (x))) + +#define SHR(a,shift) ((a) >> (shift)) +#define SHL(a,shift) ((spx_word32_t)(a) << (shift)) +#define PSHR(a,shift) (SHR((a)+((EXTEND32(1)<<((shift))>>1)),shift)) +#define SATURATE(x,a) (((x)>(a) ? (a) : (x)<-(a) ? -(a) : (x))) + + +#define ADD16(a,b) ((spx_word16_t)((spx_word16_t)(a)+(spx_word16_t)(b))) +#define SUB16(a,b) ((spx_word16_t)(a)-(spx_word16_t)(b)) +#define ADD32(a,b) ((spx_word32_t)(a)+(spx_word32_t)(b)) +#define SUB32(a,b) ((spx_word32_t)(a)-(spx_word32_t)(b)) + + +/* result fits in 16 bits */ +#define MULT16_16_16(a,b) ((((spx_word16_t)(a))*((spx_word16_t)(b)))) + +/* (spx_word32_t)(spx_word16_t) gives TI compiler a hint that it's 16x16->32 multiply */ +#define MULT16_16(a,b) (((spx_word32_t)(spx_word16_t)(a))*((spx_word32_t)(spx_word16_t)(b))) + +#define MAC16_16(c,a,b) (ADD32((c),MULT16_16((a),(b)))) +#define MULT16_32_Q12(a,b) ADD32(MULT16_16((a),SHR((b),12)), SHR(MULT16_16((a),((b)&0x00000fff)),12)) +#define MULT16_32_Q13(a,b) ADD32(MULT16_16((a),SHR((b),13)), SHR(MULT16_16((a),((b)&0x00001fff)),13)) +#define MULT16_32_Q14(a,b) ADD32(MULT16_16((a),SHR((b),14)), SHR(MULT16_16((a),((b)&0x00003fff)),14)) + +#define MULT16_32_Q11(a,b) ADD32(MULT16_16((a),SHR((b),11)), SHR(MULT16_16((a),((b)&0x000007ff)),11)) +#define MAC16_32_Q11(c,a,b) ADD32(c,ADD32(MULT16_16((a),SHR((b),11)), SHR(MULT16_16((a),((b)&0x000007ff)),11))) + +#define MULT16_32_P15(a,b) ADD32(MULT16_16((a),SHR((b),15)), PSHR(MULT16_16((a),((b)&0x00007fff)),15)) +#define MULT16_32_Q15(a,b) ADD32(MULT16_16((a),SHR((b),15)), SHR(MULT16_16((a),((b)&0x00007fff)),15)) +#define MAC16_32_Q15(c,a,b) ADD32(c,ADD32(MULT16_16((a),SHR((b),15)), SHR(MULT16_16((a),((b)&0x00007fff)),15))) + + +#define MAC16_16_Q11(c,a,b) (ADD32((c),SHR(MULT16_16((a),(b)),11))) +#define MAC16_16_Q13(c,a,b) (ADD32((c),SHR(MULT16_16((a),(b)),13))) +#define MAC16_16_P13(c,a,b) (ADD32((c),SHR(ADD32(4096,MULT16_16((a),(b))),13))) + +#define MULT16_16_Q11_32(a,b) (SHR(MULT16_16((a),(b)),11)) +#define MULT16_16_Q13(a,b) (SHR(MULT16_16((a),(b)),13)) +#define MULT16_16_Q14(a,b) (SHR(MULT16_16((a),(b)),14)) +#define MULT16_16_Q15(a,b) (SHR(MULT16_16((a),(b)),15)) + +#define MULT16_16_P13(a,b) (SHR(ADD32(4096,MULT16_16((a),(b))),13)) +#define MULT16_16_P14(a,b) (SHR(ADD32(8192,MULT16_16((a),(b))),14)) +#define MULT16_16_P15(a,b) (SHR(ADD32(16384,MULT16_16((a),(b))),15)) + +#define MUL_16_32_R15(a,bh,bl) ADD32(MULT16_16((a),(bh)), SHR(MULT16_16((a),(bl)),15)) + +#define DIV32_16(a,b) ((spx_word16_t)(((spx_word32_t)(a))/((spx_word16_t)(b)))) +#define PDIV32_16(a,b) ((spx_word16_t)(((spx_word32_t)(a)+((spx_word16_t)(b)>>1))/((spx_word16_t)(b)))) +#define DIV32(a,b) (((spx_word32_t)(a))/((spx_word32_t)(b))) +#define PDIV32(a,b) (((spx_word32_t)(a)+((spx_word16_t)(b)>>1))/((spx_word32_t)(b))) + +#endif diff --git a/android/app/src/main/jni/libspeex/gain_table.c b/android/app/src/main/jni/libspeex/gain_table.c new file mode 100644 index 000000000..00b824425 --- /dev/null +++ b/android/app/src/main/jni/libspeex/gain_table.c @@ -0,0 +1,160 @@ +/* Copyright (C) 2002 Jean-Marc Valin + File: gain_table.c + Codebook for 3-tap pitch prediction gain (128 entries) + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are + met: + + 1. Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + 3. The name of the author may not be used to endorse or promote products + derived from this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, + INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + POSSIBILITY OF SUCH DAMAGE. +*/ + +const signed char gain_cdbk_nb[512] = { +-32, -32, -32, 0, +-28, -67, -5, 33, +-42, -6, -32, 18, +-57, -10, -54, 35, +-16, 27, -41, 42, +19, -19, -40, 36, +-45, 24, -21, 40, +-8, -14, -18, 28, +1, 14, -58, 53, +-18, -88, -39, 39, +-38, 21, -18, 37, +-19, 20, -43, 38, +10, 17, -48, 54, +-52, -58, -13, 33, +-44, -1, -11, 32, +-12, -11, -34, 22, +14, 0, -46, 46, +-37, -35, -34, 5, +-25, 44, -30, 43, +6, -4, -63, 49, +-31, 43, -41, 43, +-23, 30, -43, 41, +-43, 26, -14, 44, +-33, 1, -13, 27, +-13, 18, -37, 37, +-46, -73, -45, 34, +-36, 24, -25, 34, +-36, -11, -20, 19, +-25, 12, -18, 33, +-36, -69, -59, 34, +-45, 6, 8, 46, +-22, -14, -24, 18, +-1, 13, -44, 44, +-39, -48, -26, 15, +-32, 31, -37, 34, +-33, 15, -46, 31, +-24, 30, -36, 37, +-41, 31, -23, 41, +-50, 22, -4, 50, +-22, 2, -21, 28, +-17, 30, -34, 40, +-7, -60, -28, 29, +-38, 42, -28, 42, +-44, -11, 21, 43, +-16, 8, -44, 34, +-39, -55, -43, 21, +-11, -35, 26, 41, +-9, 0, -34, 29, +-8, 121, -81, 113, +7, -16, -22, 33, +-37, 33, -31, 36, +-27, -7, -36, 17, +-34, 70, -57, 65, +-37, -11, -48, 21, +-40, 17, -1, 44, +-33, 6, -6, 33, +-9, 0, -20, 34, +-21, 69, -33, 57, +-29, 33, -31, 35, +-55, 12, -1, 49, +-33, 27, -22, 35, +-50, -33, -47, 17, +-50, 54, 51, 94, +-1, -5, -44, 35, +-4, 22, -40, 45, +-39, -66, -25, 24, +-33, 1, -26, 20, +-24, -23, -25, 12, +-11, 21, -45, 44, +-25, -45, -19, 17, +-43, 105, -16, 82, +5, -21, 1, 41, +-16, 11, -33, 30, +-13, -99, -4, 57, +-37, 33, -15, 44, +-25, 37, -63, 54, +-36, 24, -31, 31, +-53, -56, -38, 26, +-41, -4, 4, 37, +-33, 13, -30, 24, +49, 52, -94, 114, +-5, -30, -15, 23, +1, 38, -40, 56, +-23, 12, -36, 29, +-17, 40, -47, 51, +-37, -41, -39, 11, +-49, 34, 0, 58, +-18, -7, -4, 34, +-16, 17, -27, 35, +30, 5, -62, 65, +4, 48, -68, 76, +-43, 11, -11, 38, +-18, 19, -15, 41, +-23, -62, -39, 23, +-42, 10, -2, 41, +-21, -13, -13, 25, +-9, 13, -47, 42, +-23, -62, -24, 24, +-44, 60, -21, 58, +-18, -3, -52, 32, +-22, 22, -36, 34, +-75, 57, 16, 90, +-19, 3, 10, 45, +-29, 23, -38, 32, +-5, -62, -51, 38, +-51, 40, -18, 53, +-42, 13, -24, 32, +-34, 14, -20, 30, +-56, -75, -26, 37, +-26, 32, 15, 59, +-26, 17, -29, 29, +-7, 28, -52, 53, +-12, -30, 5, 30, +-5, -48, -5, 35, +2, 2, -43, 40, +21, 16, 16, 75, +-25, -45, -32, 10, +-43, 18, -10, 42, +9, 0, -1, 52, +-1, 7, -30, 36, +19, -48, -4, 48, +-28, 25, -29, 32, +-22, 0, -31, 22, +-32, 17, -10, 36, +-64, -41, -62, 36, +-52, 15, 16, 58, +-30, -22, -32, 6, +-7, 9, -38, 36}; diff --git a/android/app/src/main/jni/libspeex/gain_table_lbr.c b/android/app/src/main/jni/libspeex/gain_table_lbr.c new file mode 100644 index 000000000..3c1c3dba9 --- /dev/null +++ b/android/app/src/main/jni/libspeex/gain_table_lbr.c @@ -0,0 +1,64 @@ +/* Copyright (C) 2002 Jean-Marc Valin + File: gain_table_lbr.c + Codebook for 3-tap pitch prediction gain (32 entries) + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are + met: + + 1. Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + 3. The name of the author may not be used to endorse or promote products + derived from this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, + INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + POSSIBILITY OF SUCH DAMAGE. +*/ + +const signed char gain_cdbk_lbr[128] = { +-32, -32, -32, 0, +-31, -58, -16, 22, +-41, -24, -43, 14, +-56, -22, -55, 29, +-13, 33, -41, 47, +-4, -39, -9, 29, +-41, 15, -12, 38, +-8, -15, -12, 31, +1, 2, -44, 40, +-22, -66, -42, 27, +-38, 28, -23, 38, +-21, 14, -37, 31, +0, 21, -50, 52, +-53, -71, -27, 33, +-37, -1, -19, 25, +-19, -5, -28, 22, +6, 65, -44, 74, +-33, -48, -33, 9, +-40, 57, -14, 58, +-17, 4, -45, 32, +-31, 38, -33, 36, +-23, 28, -40, 39, +-43, 29, -12, 46, +-34, 13, -23, 28, +-16, 15, -27, 34, +-14, -82, -15, 43, +-31, 25, -32, 29, +-21, 5, -5, 38, +-47, -63, -51, 33, +-46, 12, 3, 47, +-28, -17, -29, 11, +-10, 14, -40, 38}; diff --git a/android/app/src/main/jni/libspeex/hexc_10_32_table.c b/android/app/src/main/jni/libspeex/hexc_10_32_table.c new file mode 100644 index 000000000..8dd408f2c --- /dev/null +++ b/android/app/src/main/jni/libspeex/hexc_10_32_table.c @@ -0,0 +1,66 @@ +/* Copyright (C) 2002 Jean-Marc Valin + File: hexc_10_32_table.c + Codebook for high-band excitation in SB-CELP mode (4000 bps) + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + - Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + - Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + - Neither the name of the Xiph.org Foundation nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR + CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +const signed char hexc_10_32_table[320] = { +-3, -2, -1, 0, -4, 5, 35, -40, -9, 13, +-44, 5, -27, -1, -7, 6, -11, 7, -8, 7, +19, -14, 15, -4, 9, -10, 10, -8, 10, -9, +-1, 1, 0, 0, 2, 5, -18, 22, -53, 50, +1, -23, 50, -36, 15, 3, -13, 14, -10, 6, +1, 5, -3, 4, -2, 5, -32, 25, 5, -2, +-1, -4, 1, 11, -29, 26, -6, -15, 30, -18, +0, 15, -17, 40, -41, 3, 9, -2, -2, 3, +-3, -1, -5, 2, 21, -6, -16, -21, 23, 2, +60, 15, 16, -16, -9, 14, 9, -1, 7, -9, +0, 1, 1, 0, -1, -6, 17, -28, 54, -45, +-1, 1, -1, -6, -6, 2, 11, 26, -29, -2, +46, -21, 34, 12, -23, 32, -23, 16, -10, 3, +66, 19, -20, 24, 7, 11, -3, 0, -3, -1, +-50, -46, 2, -18, -3, 4, -1, -2, 3, -3, +-19, 41, -36, 9, 11, -24, 21, -16, 9, -3, +-25, -3, 10, 18, -9, -2, -5, -1, -5, 6, +-4, -3, 2, -26, 21, -19, 35, -15, 7, -13, +17, -19, 39, -43, 48, -31, 16, -9, 7, -2, +-5, 3, -4, 9, -19, 27, -55, 63, -35, 10, +26, -44, -2, 9, 4, 1, -6, 8, -9, 5, +-8, -1, -3, -16, 45, -42, 5, 15, -16, 10, +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +-16, 24, -55, 47, -38, 27, -19, 7, -3, 1, +16, 27, 20, -19, 18, 5, -7, 1, -5, 2, +-6, 8, -22, 0, -3, -3, 8, -1, 7, -8, +1, -3, 5, 0, 17, -48, 58, -52, 29, -7, +-2, 3, -10, 6, -26, 58, -31, 1, -6, 3, +93, -29, 39, 3, 17, 5, 6, -1, -1, -1, +27, 13, 10, 19, -7, -34, 12, 10, -4, 9, +-76, 9, 8, -28, -2, -11, 2, -1, 3, 1, +-83, 38, -39, 4, -16, -6, -2, -5, 5, -2, +}; diff --git a/android/app/src/main/jni/libspeex/hexc_table.c b/android/app/src/main/jni/libspeex/hexc_table.c new file mode 100644 index 000000000..268408a8d --- /dev/null +++ b/android/app/src/main/jni/libspeex/hexc_table.c @@ -0,0 +1,162 @@ +/* Copyright (C) 2002 Jean-Marc Valin + File: hexc_table.c + Codebook for high-band excitation in SB-CELP mode (8000 bps with sign) + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + - Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + - Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + - Neither the name of the Xiph.org Foundation nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR + CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +const signed char hexc_table[1024] = { +-24, 21, -20, 5, -5, -7, 14, -10, +2, -27, 16, -20, 0, -32, 26, 19, +8, -11, -41, 31, 28, -27, -32, 34, +42, 34, -17, 22, -10, 13, -29, 18, +-12, -26, -24, 11, 22, 5, -5, -5, +54, -68, -43, 57, -25, 24, 4, 4, +26, -8, -12, -17, 54, 30, -45, 1, +10, -15, 18, -41, 11, 68, -67, 37, +-16, -24, -16, 38, -22, 6, -29, 30, +66, -27, 5, 7, -16, 13, 2, -12, +-7, -3, -20, 36, 4, -28, 9, 3, +32, 48, 26, 39, 3, 0, 7, -21, +-13, 5, -82, -7, 73, -20, 34, -9, +-5, 1, -1, 10, -5, -10, -1, 9, +1, -9, 10, 0, -14, 11, -1, -2, +-1, 11, 20, 96, -81, -22, -12, -9, +-58, 9, 24, -30, 26, -35, 27, -12, +13, -18, 56, -59, 15, -7, 23, -15, +-1, 6, -25, 14, -22, -20, 47, -11, +16, 2, 38, -23, -19, -30, -9, 40, +-11, 5, 4, -6, 8, 26, -21, -11, +127, 4, 1, 6, -9, 2, -7, -2, +-3, 7, -5, 10, -19, 7, -106, 91, +-3, 9, -4, 21, -8, 26, -80, 8, +1, -2, -10, -17, -17, -27, 32, 71, +6, -29, 11, -23, 54, -38, 29, -22, +39, 87, -31, -12, -20, 3, -2, -2, +2, 20, 0, -1, -35, 27, 9, -6, +-12, 3, -12, -6, 13, 1, 14, -22, +-59, -15, -17, -25, 13, -7, 7, 3, +0, 1, -7, 6, -3, 61, -37, -23, +-23, -29, 38, -31, 27, 1, -8, 2, +-27, 23, -26, 36, -34, 5, 24, -24, +-6, 7, 3, -59, 78, -62, 44, -16, +1, 6, 0, 17, 8, 45, 0, -110, +6, 14, -2, 32, -77, -56, 62, -3, +3, -13, 4, -16, 102, -15, -36, -1, +9, -113, 6, 23, 0, 9, 9, 5, +-8, -1, -14, 5, -12, 121, -53, -27, +-8, -9, 22, -13, 3, 2, -3, 1, +-2, -71, 95, 38, -19, 15, -16, -5, +71, 10, 2, -32, -13, -5, 15, -1, +-2, -14, -85, 30, 29, 6, 3, 2, +0, 0, 0, 0, 0, 0, 0, 0, +2, -65, -56, -9, 18, 18, 23, -14, +-2, 0, 12, -29, 26, -12, 1, 2, +-12, -64, 90, -6, 4, 1, 5, -5, +-110, -3, -31, 22, -29, 9, 0, 8, +-40, -5, 21, -5, -5, 13, 10, -18, +40, 1, 35, -20, 30, -28, 11, -6, +19, 7, 14, 18, -64, 9, -6, 16, +51, 68, 8, 16, 12, -8, 0, -9, +20, -22, 25, 7, -4, -13, 41, -35, +93, -18, -54, 11, -1, 1, -9, 4, +-66, 66, -31, 20, -22, 25, -23, 11, +10, 9, 19, 15, 11, -5, -31, -10, +-23, -28, -6, -6, -3, -4, 5, 3, +-28, 22, -11, -42, 25, -25, -16, 41, +34, 47, -6, 2, 42, -19, -22, 5, +-39, 32, 6, -35, 22, 17, -30, 8, +-26, -11, -11, 3, -12, 33, 33, -37, +21, -1, 6, -4, 3, 0, -5, 5, +12, -12, 57, 27, -61, -3, 20, -17, +2, 0, 4, 0, -2, -33, -58, 81, +-23, 39, -10, -5, 2, 6, -7, 5, +4, -3, -2, -13, -23, -72, 107, 15, +-5, 0, -7, -3, -6, 5, -4, 15, +47, 12, -31, 25, -16, 8, 22, -25, +-62, -56, -18, 14, 28, 12, 2, -11, +74, -66, 41, -20, -7, 16, -20, 16, +-8, 0, -16, 4, -19, 92, 12, -59, +-14, -39, 49, -25, -16, 23, -27, 19, +-3, -33, 19, 85, -29, 6, -7, -10, +16, -7, -12, 1, -6, 2, 4, -2, +64, 10, -25, 41, -2, -31, 15, 0, +110, 50, 69, 35, 28, 19, -10, 2, +-43, -49, -56, -15, -16, 10, 3, 12, +-1, -8, 1, 26, -12, -1, 7, -11, +-27, 41, 25, 1, -11, -18, 22, -7, +-1, -47, -8, 23, -3, -17, -7, 18, +-125, 59, -5, 3, 18, 1, 2, 3, +27, -35, 65, -53, 50, -46, 37, -21, +-28, 7, 14, -37, -5, -5, 12, 5, +-8, 78, -19, 21, -6, -16, 8, -7, +5, 2, 7, 2, 10, -6, 12, -60, +44, 11, -36, -32, 31, 0, 2, -2, +2, 1, -3, 7, -10, 17, -21, 10, +6, -2, 19, -2, 59, -38, -86, 38, +8, -41, -30, -45, -33, 7, 15, 28, +29, -7, 24, -40, 7, 7, 5, -2, +9, 24, -23, -18, 6, -29, 30, 2, +28, 49, -11, -46, 10, 43, -13, -9, +-1, -3, -7, -7, -17, -6, 97, -33, +-21, 3, 5, 1, 12, -43, -8, 28, +7, -43, -7, 17, -20, 19, -1, 2, +-13, 9, 54, 34, 9, -28, -11, -9, +-17, 110, -59, 44, -26, 0, 3, -12, +-47, 73, -34, -43, 38, -33, 16, -5, +-46, -4, -6, -2, -25, 19, -29, 28, +-13, 5, 14, 27, -40, -43, 4, 32, +-13, -2, -35, -4, 112, -42, 9, -12, +37, -28, 17, 14, -19, 35, -39, 23, +3, -14, -1, -57, -5, 94, -9, 3, +-39, 5, 30, -10, -32, 42, -13, -14, +-97, -63, 30, -9, 1, -7, 12, 5, +20, 17, -9, -36, -30, 25, 47, -9, +-15, 12, -22, 98, -8, -50, 15, -27, +21, -16, -11, 2, 12, -10, 10, -3, +33, 36, -96, 0, -17, 31, -9, 9, +3, -20, 13, -11, 8, -4, 10, -10, +9, 1, 112, -70, -27, 5, -21, 2, +-57, -3, -29, 10, 19, -21, 21, -10, +-66, -3, 91, -35, 30, -12, 0, -7, +59, -28, 26, 2, 14, -18, 1, 1, +11, 17, 20, -54, -59, 27, 4, 29, +32, 5, 19, 12, -4, 1, 7, -10, +5, -2, 10, 0, 23, -5, 28, -104, +46, 11, 16, 3, 29, 1, -8, -14, +1, 7, -50, 88, -62, 26, 8, -17, +-14, 50, 0, 32, -12, -3, -27, 18, +-8, -5, 8, 3, -20, -11, 37, -12, +9, 33, 46, -101, -1, -4, 1, 6, +-1, 28, -42, -15, 16, 5, -1, -2, +-55, 85, 38, -9, -4, 11, -2, -9, +-6, 3, -20, -10, -77, 89, 24, -3, +-104, -57, -26, -31, -20, -6, -9, 14, +20, -23, 46, -15, -31, 28, 1, -15, +-2, 6, -2, 31, 45, -76, 23, -25, +}; diff --git a/android/app/src/main/jni/libspeex/high_lsp_tables.c b/android/app/src/main/jni/libspeex/high_lsp_tables.c new file mode 100644 index 000000000..e82e87550 --- /dev/null +++ b/android/app/src/main/jni/libspeex/high_lsp_tables.c @@ -0,0 +1,163 @@ +/* Copyright (C) 2002 Jean-Marc Valin + File: high_lsp_tables.c + Codebooks for high-band LSPs in SB-CELP mode + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are + met: + + 1. Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + 3. The name of the author may not be used to endorse or promote products + derived from this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, + INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + POSSIBILITY OF SUCH DAMAGE. +*/ + +const signed char high_lsp_cdbk[512]={ +39,12,-14,-20,-29,-61,-67,-76, +-32,-71,-67,68,77,46,34,5, +-13,-48,-46,-72,-81,-84,-60,-58, +-40,-28,82,93,68,45,29,3, +-19,-47,-28,-43,-35,-30,-8,-13, +-39,-91,-91,-123,-96,10,10,-6, +-18,-55,-60,-91,-56,-36,-27,-16, +-48,-75,40,28,-10,-28,35,9, +37,19,1,-20,-31,-41,-18,-25, +-35,-68,-80,45,27,-1,47,13, +0,-29,-35,-57,-50,-79,-73,-38, +-19,5,35,14,-10,-23,16,-8, +5,-24,-40,-62,-23,-27,-22,-16, +-18,-46,-72,-77,43,21,33,1, +-80,-70,-70,-64,-56,-52,-39,-33, +-31,-38,-19,-19,-15,32,33,-2, +7,-15,-15,-24,-23,-33,-41,-56, +-24,-57,5,89,64,41,27,5, +-9,-47,-60,-97,-97,-124,-20,-9, +-44,-73,31,29,-4,64,48,7, +-35,-57,0,-3,-26,-47,-3,-6, +-40,-76,-79,-48,12,81,55,10, +9,-24,-43,-73,-57,-69,16,5, +-28,-53,18,29,20,0,-4,-11, +6,-13,23,7,-17,-35,-37,-37, +-30,-68,-63,6,24,-9,-14,3, +21,-13,-27,-57,-49,-80,-24,-41, +-5,-16,-5,1,45,25,12,-7, +3,-15,-6,-16,-15,-8,6,-13, +-42,-81,-80,-87,14,1,-10,-3, +-43,-69,-46,-24,-28,-29,36,6, +-43,-56,-12,12,54,79,43,9, +54,22,2,8,-12,-43,-46,-52, +-38,-69,-89,-5,75,38,33,5, +-13,-53,-62,-87,-89,-113,-99,-55, +-34,-37,62,55,33,16,21,-2, +-17,-46,-29,-38,-38,-48,-39,-42, +-36,-75,-72,-88,-48,-30,21,2, +-15,-57,-64,-98,-84,-76,25,1, +-46,-80,-12,18,-7,3,34,6, +38,31,23,4,-1,20,14,-15, +-43,-78,-91,-24,14,-3,54,16, +0,-27,-28,-44,-56,-83,-92,-89, +-3,34,56,41,36,22,20,-8, +-7,-35,-42,-62,-49,3,12,-10, +-50,-87,-96,-66,92,70,38,9, +-70,-71,-62,-42,-39,-43,-11,-7, +-50,-79,-58,-50,-31,32,31,-6, +-4,-25,7,-17,-38,-70,-58,-27, +-43,-83,-28,59,36,20,31,2, +-27,-71,-80,-109,-98,-75,-33,-32, +-31,-2,33,15,-6,43,33,-5, +0,-22,-10,-27,-34,-49,-11,-20, +-41,-91,-100,-121,-39,57,41,10, +-19,-50,-38,-59,-60,-70,-18,-20, +-8,-31,-8,-15,1,-14,-26,-25, +33,21,32,17,1,-19,-19,-26, +-58,-81,-35,-22,45,30,11,-11, +3,-26,-48,-87,-67,-83,-58,3, +-1,-26,-20,44,10,25,39,5, +-9,-35,-27,-38,7,10,4,-9, +-42,-85,-102,-127,52,44,28,10, +-47,-61,-40,-39,-17,-1,-10,-33, +-42,-74,-48,21,-4,70,52,10}; + + +const signed char high_lsp_cdbk2[512]={ +-36,-62,6,-9,-10,-14,-56,23, +1,-26,23,-48,-17,12,8,-7, +23,29,-36,-28,-6,-29,-17,-5, +40,23,10,10,-46,-13,36,6, +4,-30,-29,62,32,-32,-1,22, +-14,1,-4,-22,-45,2,54,4, +-30,-57,-59,-12,27,-3,-31,8, +-9,5,10,-14,32,66,19,9, +2,-25,-37,23,-15,18,-38,-31, +5,-9,-21,15,0,22,62,30, +15,-12,-14,-46,77,21,33,3, +34,29,-19,50,2,11,9,-38, +-12,-37,62,1,-15,54,32,6, +2,-24,20,35,-21,2,19,24, +-13,55,4,9,39,-19,30,-1, +-21,73,54,33,8,18,3,15, +6,-19,-47,6,-3,-48,-50,1, +26,20,8,-23,-50,65,-14,-55, +-17,-31,-37,-28,53,-1,-17,-53, +1,57,11,-8,-25,-30,-37,64, +5,-52,-45,15,23,31,15,14, +-25,24,33,-2,-44,-56,-18,6, +-21,-43,4,-12,17,-37,20,-10, +34,15,2,15,55,21,-11,-31, +-6,46,25,16,-9,-25,-8,-62, +28,17,20,-32,-29,26,30,25, +-19,2,-16,-17,26,-51,2,50, +42,19,-66,23,29,-2,3,19, +-19,-37,32,15,6,30,-34,13, +11,-5,40,31,10,-42,4,-9, +26,-9,-70,17,-2,-23,20,-22, +-55,51,-24,-31,22,-22,15,-13, +3,-10,-28,-16,56,4,-63,11, +-18,-15,-18,-38,-35,16,-7,34, +-1,-21,-49,-47,9,-37,7,8, +69,55,20,6,-33,-45,-10,-9, +6,-9,12,71,15,-3,-42,-7, +-24,32,-35,-2,-42,-17,-5,0, +-2,-33,-54,13,-12,-34,47,23, +19,55,7,-8,74,31,14,16, +-23,-26,19,12,-18,-49,-28,-31, +-20,2,-14,-20,-47,78,40,13, +-23,-11,21,-6,18,1,47,5, +38,35,32,46,22,8,13,16, +-14,18,51,19,40,39,11,-26, +-1,-17,47,2,-53,-15,31,-22, +38,21,-15,-16,5,-33,53,15, +-38,86,11,-3,-24,49,13,-4, +-11,-18,28,20,-12,-27,-26,35, +-25,-35,-3,-20,-61,30,10,-55, +-12,-22,-52,-54,-14,19,-32,-12, +45,15,-8,-48,-9,11,-32,8, +-16,-34,-13,51,18,38,-2,-32, +-17,22,-2,-18,-28,-70,59,27, +-28,-19,-10,-20,-9,-9,-8,-21, +21,-8,35,-2,45,-3,-9,12, +0,30,7,-39,43,27,-38,-91, +30,26,19,-55,-4,63,14,-17, +13,9,13,2,7,4,6,61, +72,-1,-17,29,-1,-22,-17,8, +-28,-37,63,44,41,3,2,14, +9,-6,75,-8,-7,-12,-15,-12, +13,9,-4,30,-22,-65,15,0, +-45,4,-4,1,5,22,11,23}; diff --git a/android/app/src/main/jni/libspeex/jitter.c b/android/app/src/main/jni/libspeex/jitter.c new file mode 100644 index 000000000..17bd044fc --- /dev/null +++ b/android/app/src/main/jni/libspeex/jitter.c @@ -0,0 +1,843 @@ +/* Copyright (C) 2002 Jean-Marc Valin + File: speex_jitter.h + + Adaptive jitter buffer for Speex + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + - Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + - Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + - Neither the name of the Xiph.org Foundation nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR + CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +*/ + +/* +TODO: +- Add short-term estimate +- Defensive programming + + warn when last returned < last desired (begative buffering) + + warn if update_delay not called between get() and tick() or is called twice in a row +- Linked list structure for holding the packets instead of the current fixed-size array + + return memory to a pool + + allow pre-allocation of the pool + + optional max number of elements +- Statistics + + drift + + loss + + late + + jitter + + buffering delay +*/ +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + + +#include "arch.h" +#include +#include +#include +#include "os_support.h" + +#ifndef NULL +#define NULL 0 +#endif + +#define SPEEX_JITTER_MAX_BUFFER_SIZE 200 /**< Maximum number of packets in jitter buffer */ + +#define TSUB(a,b) ((spx_int32_t)((a)-(b))) + +#define GT32(a,b) (((spx_int32_t)((a)-(b)))>0) +#define GE32(a,b) (((spx_int32_t)((a)-(b)))>=0) +#define LT32(a,b) (((spx_int32_t)((a)-(b)))<0) +#define LE32(a,b) (((spx_int32_t)((a)-(b)))<=0) + +#define ROUND_DOWN(x, step) ((x)<0 ? ((x)-(step)+1)/(step)*(step) : (x)/(step)*(step)) + +#define MAX_TIMINGS 40 +#define MAX_BUFFERS 3 +#define TOP_DELAY 40 + +/** Buffer that keeps the time of arrival of the latest packets */ +struct TimingBuffer { + int filled; /**< Number of entries occupied in "timing" and "counts"*/ + int curr_count; /**< Number of packet timings we got (including those we discarded) */ + spx_int32_t timing[MAX_TIMINGS]; /**< Sorted list of all timings ("latest" packets first) */ + spx_int16_t counts[MAX_TIMINGS]; /**< Order the packets were put in (will be used for short-term estimate) */ +}; + +static void tb_init(struct TimingBuffer *tb) +{ + tb->filled = 0; + tb->curr_count = 0; +} + +/* Add the timing of a new packet to the TimingBuffer */ +static void tb_add(struct TimingBuffer *tb, spx_int16_t timing) +{ + int pos; + /* Discard packet that won't make it into the list because they're too early */ + if (tb->filled >= MAX_TIMINGS && timing >= tb->timing[tb->filled-1]) + { + tb->curr_count++; + return; + } + + /* Find where the timing info goes in the sorted list */ + pos = 0; + /* FIXME: Do bisection instead of linear search */ + while (posfilled && timing >= tb->timing[pos]) + { + pos++; + } + + speex_assert(pos <= tb->filled && pos < MAX_TIMINGS); + + /* Shift everything so we can perform the insertion */ + if (pos < tb->filled) + { + int move_size = tb->filled-pos; + if (tb->filled == MAX_TIMINGS) + move_size -= 1; + SPEEX_MOVE(&tb->timing[pos+1], &tb->timing[pos], move_size); + SPEEX_MOVE(&tb->counts[pos+1], &tb->counts[pos], move_size); + } + /* Insert */ + tb->timing[pos] = timing; + tb->counts[pos] = tb->curr_count; + + tb->curr_count++; + if (tb->filledfilled++; +} + + + +/** Jitter buffer structure */ +struct JitterBuffer_ { + spx_uint32_t pointer_timestamp; /**< Timestamp of what we will *get* next */ + spx_uint32_t last_returned_timestamp; /**< Useful for getting the next packet with the same timestamp (for fragmented media) */ + spx_uint32_t next_stop; /**< Estimated time the next get() will be called */ + + spx_int32_t buffered; /**< Amount of data we think is still buffered by the application (timestamp units)*/ + + JitterBufferPacket packets[SPEEX_JITTER_MAX_BUFFER_SIZE]; /**< Packets stored in the buffer */ + spx_uint32_t arrival[SPEEX_JITTER_MAX_BUFFER_SIZE]; /**< Packet arrival time (0 means it was late, even though it's a valid timestamp) */ + + void (*destroy) (void *); /**< Callback for destroying a packet */ + + spx_int32_t delay_step; /**< Size of the steps when adjusting buffering (timestamp units) */ + spx_int32_t concealment_size; /**< Size of the packet loss concealment "units" */ + int reset_state; /**< True if state was just reset */ + int buffer_margin; /**< How many frames we want to keep in the buffer (lower bound) */ + int late_cutoff; /**< How late must a packet be for it not to be considered at all */ + int interp_requested; /**< An interpolation is requested by speex_jitter_update_delay() */ + int auto_adjust; /**< Whether to automatically adjust the delay at any time */ + + struct TimingBuffer _tb[MAX_BUFFERS]; /**< Don't use those directly */ + struct TimingBuffer *timeBuffers[MAX_BUFFERS]; /**< Storing arrival time of latest frames so we can compute some stats */ + int window_size; /**< Total window over which the late frames are counted */ + int subwindow_size; /**< Sub-window size for faster computation */ + int max_late_rate; /**< Absolute maximum amount of late packets tolerable (in percent) */ + int latency_tradeoff; /**< Latency equivalent of losing one percent of packets */ + int auto_tradeoff; /**< Latency equivalent of losing one percent of packets (automatic default) */ + + int lost_count; /**< Number of consecutive lost packets */ +}; + +/** Based on available data, this computes the optimal delay for the jitter buffer. + The optimised function is in timestamp units and is: + cost = delay + late_factor*[number of frames that would be late if we used that delay] + @param tb Array of buffers + @param late_factor Equivalent cost of a late frame (in timestamp units) + */ +static spx_int16_t compute_opt_delay(JitterBuffer *jitter) +{ + int i; + spx_int16_t opt=0; + spx_int32_t best_cost=0x7fffffff; + int late = 0; + int pos[MAX_BUFFERS]; + int tot_count; + float late_factor; + int penalty_taken = 0; + int best = 0; + int worst = 0; + spx_int32_t deltaT; + struct TimingBuffer *tb; + + tb = jitter->_tb; + + /* Number of packet timings we have received (including those we didn't keep) */ + tot_count = 0; + for (i=0;ilatency_tradeoff != 0) + late_factor = jitter->latency_tradeoff * 100.0f / tot_count; + else + late_factor = jitter->auto_tradeoff * jitter->window_size/tot_count; + + /*fprintf(stderr, "late_factor = %f\n", late_factor);*/ + for (i=0;idelay_step); + pos[next]++; + + /* Actual cost function that tells us how bad using this delay would be */ + cost = -latest + late_factor*late; + /*fprintf(stderr, "cost %d = %d + %f * %d\n", cost, -latest, late_factor, late);*/ + if (cost < best_cost) + { + best_cost = cost; + opt = latest; + } + } else { + break; + } + + /* For the next timing we will consider, there will be one more late packet to count */ + late++; + /* Two-frame penalty if we're going to increase the amount of late frames (hysteresis) */ + if (latest >= 0 && !penalty_taken) + { + penalty_taken = 1; + late+=4; + } + } + + deltaT = best-worst; + /* This is a default "automatic latency tradeoff" when none is provided */ + jitter->auto_tradeoff = 1 + deltaT/TOP_DELAY; + /*fprintf(stderr, "auto_tradeoff = %d (%d %d %d)\n", jitter->auto_tradeoff, best, worst, i);*/ + + /* FIXME: Compute a short-term estimate too and combine with the long-term one */ + + /* Prevents reducing the buffer size when we haven't really had much data */ + if (tot_count < TOP_DELAY && opt > 0) + return 0; + return opt; +} + + +/** Initialise jitter buffer */ +EXPORT JitterBuffer *jitter_buffer_init(int step_size) +{ + JitterBuffer *jitter = (JitterBuffer*)speex_alloc(sizeof(JitterBuffer)); + if (jitter) + { + int i; + spx_int32_t tmp; + for (i=0;ipackets[i].data=NULL; + jitter->delay_step = step_size; + jitter->concealment_size = step_size; + /*FIXME: Should this be 0 or 1?*/ + jitter->buffer_margin = 0; + jitter->late_cutoff = 50; + jitter->destroy = NULL; + jitter->latency_tradeoff = 0; + jitter->auto_adjust = 1; + tmp = 4; + jitter_buffer_ctl(jitter, JITTER_BUFFER_SET_MAX_LATE_RATE, &tmp); + jitter_buffer_reset(jitter); + } + return jitter; +} + +/** Reset jitter buffer */ +EXPORT void jitter_buffer_reset(JitterBuffer *jitter) +{ + int i; + for (i=0;ipackets[i].data) + { + if (jitter->destroy) + jitter->destroy(jitter->packets[i].data); + else + speex_free(jitter->packets[i].data); + jitter->packets[i].data = NULL; + } + } + /* Timestamp is actually undefined at this point */ + jitter->pointer_timestamp = 0; + jitter->next_stop = 0; + jitter->reset_state = 1; + jitter->lost_count = 0; + jitter->buffered = 0; + jitter->auto_tradeoff = 32000; + + for (i=0;i_tb[i]); + jitter->timeBuffers[i] = &jitter->_tb[i]; + } + /*fprintf (stderr, "reset\n");*/ +} + +/** Destroy jitter buffer */ +EXPORT void jitter_buffer_destroy(JitterBuffer *jitter) +{ + jitter_buffer_reset(jitter); + speex_free(jitter); +} + +/** Take the following timing into consideration for future calculations */ +static void update_timings(JitterBuffer *jitter, spx_int32_t timing) +{ + if (timing < -32767) + timing = -32767; + if (timing > 32767) + timing = 32767; + /* If the current sub-window is full, perform a rotation and discard oldest sub-widow */ + if (jitter->timeBuffers[0]->curr_count >= jitter->subwindow_size) + { + int i; + /*fprintf(stderr, "Rotate buffer\n");*/ + struct TimingBuffer *tmp = jitter->timeBuffers[MAX_BUFFERS-1]; + for (i=MAX_BUFFERS-1;i>=1;i--) + jitter->timeBuffers[i] = jitter->timeBuffers[i-1]; + jitter->timeBuffers[0] = tmp; + tb_init(jitter->timeBuffers[0]); + } + tb_add(jitter->timeBuffers[0], timing); +} + +/** Compensate all timings when we do an adjustment of the buffering */ +static void shift_timings(JitterBuffer *jitter, spx_int16_t amount) +{ + int i, j; + for (i=0;itimeBuffers[i]->filled;j++) + jitter->timeBuffers[i]->timing[j] += amount; + } +} + + +/** Put one packet into the jitter buffer */ +EXPORT void jitter_buffer_put(JitterBuffer *jitter, const JitterBufferPacket *packet) +{ + int i,j; + int late; + /*fprintf (stderr, "put packet %d %d\n", timestamp, span);*/ + + /* Cleanup buffer (remove old packets that weren't played) */ + if (!jitter->reset_state) + { + for (i=0;ipackets[i].data && LE32(jitter->packets[i].timestamp + jitter->packets[i].span, jitter->pointer_timestamp)) + { + /*fprintf (stderr, "cleaned (not played)\n");*/ + if (jitter->destroy) + jitter->destroy(jitter->packets[i].data); + else + speex_free(jitter->packets[i].data); + jitter->packets[i].data = NULL; + } + } + } + + /*fprintf(stderr, "arrival: %d %d %d\n", packet->timestamp, jitter->next_stop, jitter->pointer_timestamp);*/ + /* Check if packet is late (could still be useful though) */ + if (!jitter->reset_state && LT32(packet->timestamp, jitter->next_stop)) + { + update_timings(jitter, ((spx_int32_t)packet->timestamp) - ((spx_int32_t)jitter->next_stop) - jitter->buffer_margin); + late = 1; + } else { + late = 0; + } + + /* For some reason, the consumer has failed the last 20 fetches. Make sure this packet is + * used to resync. */ + if (jitter->lost_count>20) + { + jitter_buffer_reset(jitter); + } + + /* Only insert the packet if it's not hopelessly late (i.e. totally useless) */ + if (jitter->reset_state || GE32(packet->timestamp+packet->span+jitter->delay_step, jitter->pointer_timestamp)) + { + + /*Find an empty slot in the buffer*/ + for (i=0;ipackets[i].data==NULL) + break; + } + + /*No place left in the buffer, need to make room for it by discarding the oldest packet */ + if (i==SPEEX_JITTER_MAX_BUFFER_SIZE) + { + int earliest=jitter->packets[0].timestamp; + i=0; + for (j=1;jpackets[i].data || LT32(jitter->packets[j].timestamp,earliest)) + { + earliest = jitter->packets[j].timestamp; + i=j; + } + } + if (jitter->destroy) + jitter->destroy(jitter->packets[i].data); + else + speex_free(jitter->packets[i].data); + jitter->packets[i].data=NULL; + /*fprintf (stderr, "Buffer is full, discarding earliest frame %d (currently at %d)\n", timestamp, jitter->pointer_timestamp);*/ + } + + /* Copy packet in buffer */ + if (jitter->destroy) + { + jitter->packets[i].data = packet->data; + } else { + jitter->packets[i].data=(char*)speex_alloc(packet->len); + for (j=0;jlen;j++) + jitter->packets[i].data[j]=packet->data[j]; + } + jitter->packets[i].timestamp=packet->timestamp; + jitter->packets[i].span=packet->span; + jitter->packets[i].len=packet->len; + jitter->packets[i].sequence=packet->sequence; + jitter->packets[i].user_data=packet->user_data; + if (jitter->reset_state || late) + jitter->arrival[i] = 0; + else + jitter->arrival[i] = jitter->next_stop; + } + + +} + +/** Get one packet from the jitter buffer */ +EXPORT int jitter_buffer_get(JitterBuffer *jitter, JitterBufferPacket *packet, spx_int32_t desired_span, spx_int32_t *start_offset) +{ + int i; + unsigned int j; + int incomplete = 0; + spx_int16_t opt; + + if (start_offset != NULL) + *start_offset = 0; + + /* Syncing on the first call */ + if (jitter->reset_state) + { + int found = 0; + /* Find the oldest packet */ + spx_uint32_t oldest=0; + for (i=0;ipackets[i].data && (!found || LT32(jitter->packets[i].timestamp,oldest))) + { + oldest = jitter->packets[i].timestamp; + found = 1; + } + } + if (found) + { + jitter->reset_state=0; + jitter->pointer_timestamp = oldest; + jitter->next_stop = oldest; + } else { + packet->timestamp = 0; + packet->span = jitter->interp_requested; + return JITTER_BUFFER_MISSING; + } + } + + + jitter->last_returned_timestamp = jitter->pointer_timestamp; + + if (jitter->interp_requested != 0) + { + packet->timestamp = jitter->pointer_timestamp; + packet->span = jitter->interp_requested; + + /* Increment the pointer because it got decremented in the delay update */ + jitter->pointer_timestamp += jitter->interp_requested; + packet->len = 0; + /*fprintf (stderr, "Deferred interpolate\n");*/ + + jitter->interp_requested = 0; + + jitter->buffered = packet->span - desired_span; + + return JITTER_BUFFER_INSERTION; + } + + /* Searching for the packet that fits best */ + + /* Search the buffer for a packet with the right timestamp and spanning the whole current chunk */ + for (i=0;ipackets[i].data && jitter->packets[i].timestamp==jitter->pointer_timestamp && GE32(jitter->packets[i].timestamp+jitter->packets[i].span,jitter->pointer_timestamp+desired_span)) + break; + } + + /* If no match, try for an "older" packet that still spans (fully) the current chunk */ + if (i==SPEEX_JITTER_MAX_BUFFER_SIZE) + { + for (i=0;ipackets[i].data && LE32(jitter->packets[i].timestamp, jitter->pointer_timestamp) && GE32(jitter->packets[i].timestamp+jitter->packets[i].span,jitter->pointer_timestamp+desired_span)) + break; + } + } + + /* If still no match, try for an "older" packet that spans part of the current chunk */ + if (i==SPEEX_JITTER_MAX_BUFFER_SIZE) + { + for (i=0;ipackets[i].data && LE32(jitter->packets[i].timestamp, jitter->pointer_timestamp) && GT32(jitter->packets[i].timestamp+jitter->packets[i].span,jitter->pointer_timestamp)) + break; + } + } + + /* If still no match, try for earliest packet possible */ + if (i==SPEEX_JITTER_MAX_BUFFER_SIZE) + { + int found = 0; + spx_uint32_t best_time=0; + int best_span=0; + int besti=0; + for (i=0;ipackets[i].data && LT32(jitter->packets[i].timestamp,jitter->pointer_timestamp+desired_span) && GE32(jitter->packets[i].timestamp,jitter->pointer_timestamp)) + { + if (!found || LT32(jitter->packets[i].timestamp,best_time) || (jitter->packets[i].timestamp==best_time && GT32(jitter->packets[i].span,best_span))) + { + best_time = jitter->packets[i].timestamp; + best_span = jitter->packets[i].span; + besti = i; + found = 1; + } + } + } + if (found) + { + i=besti; + incomplete = 1; + /*fprintf (stderr, "incomplete: %d %d %d %d\n", jitter->packets[i].timestamp, jitter->pointer_timestamp, chunk_size, jitter->packets[i].span);*/ + } + } + + /* If we find something */ + if (i!=SPEEX_JITTER_MAX_BUFFER_SIZE) + { + spx_int32_t offset; + + /* We (obviously) haven't lost this packet */ + jitter->lost_count = 0; + + /* In this case, 0 isn't as a valid timestamp */ + if (jitter->arrival[i] != 0) + { + update_timings(jitter, ((spx_int32_t)jitter->packets[i].timestamp) - ((spx_int32_t)jitter->arrival[i]) - jitter->buffer_margin); + } + + + /* Copy packet */ + if (jitter->destroy) + { + packet->data = jitter->packets[i].data; + packet->len = jitter->packets[i].len; + } else { + if (jitter->packets[i].len > packet->len) + { + speex_warning_int("jitter_buffer_get(): packet too large to fit. Size is", jitter->packets[i].len); + } else { + packet->len = jitter->packets[i].len; + } + for (j=0;jlen;j++) + packet->data[j] = jitter->packets[i].data[j]; + /* Remove packet */ + speex_free(jitter->packets[i].data); + } + jitter->packets[i].data = NULL; + /* Set timestamp and span (if requested) */ + offset = (spx_int32_t)jitter->packets[i].timestamp-(spx_int32_t)jitter->pointer_timestamp; + if (start_offset != NULL) + *start_offset = offset; + else if (offset != 0) + speex_warning_int("jitter_buffer_get() discarding non-zero start_offset", offset); + + packet->timestamp = jitter->packets[i].timestamp; + jitter->last_returned_timestamp = packet->timestamp; + + packet->span = jitter->packets[i].span; + packet->sequence = jitter->packets[i].sequence; + packet->user_data = jitter->packets[i].user_data; + /* Point to the end of the current packet */ + jitter->pointer_timestamp = jitter->packets[i].timestamp+jitter->packets[i].span; + + jitter->buffered = packet->span - desired_span; + + if (start_offset != NULL) + jitter->buffered += *start_offset; + + return JITTER_BUFFER_OK; + } + + + /* If we haven't found anything worth returning */ + + /*fprintf (stderr, "not found\n");*/ + jitter->lost_count++; + /*fprintf (stderr, "m");*/ + /*fprintf (stderr, "lost_count = %d\n", jitter->lost_count);*/ + + opt = compute_opt_delay(jitter); + + /* Should we force an increase in the buffer or just do normal interpolation? */ + if (opt < 0) + { + /* Need to increase buffering */ + + /* Shift histogram to compensate */ + shift_timings(jitter, -opt); + + packet->timestamp = jitter->pointer_timestamp; + packet->span = -opt; + /* Don't move the pointer_timestamp forward */ + packet->len = 0; + + jitter->buffered = packet->span - desired_span; + return JITTER_BUFFER_INSERTION; + /*jitter->pointer_timestamp -= jitter->delay_step;*/ + /*fprintf (stderr, "Forced to interpolate\n");*/ + } else { + /* Normal packet loss */ + packet->timestamp = jitter->pointer_timestamp; + + desired_span = ROUND_DOWN(desired_span, jitter->concealment_size); + packet->span = desired_span; + jitter->pointer_timestamp += desired_span; + packet->len = 0; + + jitter->buffered = packet->span - desired_span; + return JITTER_BUFFER_MISSING; + /*fprintf (stderr, "Normal loss\n");*/ + } + + +} + +EXPORT int jitter_buffer_get_another(JitterBuffer *jitter, JitterBufferPacket *packet) +{ + int i, j; + for (i=0;ipackets[i].data && jitter->packets[i].timestamp==jitter->last_returned_timestamp) + break; + } + if (i!=SPEEX_JITTER_MAX_BUFFER_SIZE) + { + /* Copy packet */ + packet->len = jitter->packets[i].len; + if (jitter->destroy) + { + packet->data = jitter->packets[i].data; + } else { + for (j=0;jlen;j++) + packet->data[j] = jitter->packets[i].data[j]; + /* Remove packet */ + speex_free(jitter->packets[i].data); + } + jitter->packets[i].data = NULL; + packet->timestamp = jitter->packets[i].timestamp; + packet->span = jitter->packets[i].span; + packet->sequence = jitter->packets[i].sequence; + packet->user_data = jitter->packets[i].user_data; + return JITTER_BUFFER_OK; + } else { + packet->data = NULL; + packet->len = 0; + packet->span = 0; + return JITTER_BUFFER_MISSING; + } +} + +/* Let the jitter buffer know it's the right time to adjust the buffering delay to the network conditions */ +static int _jitter_buffer_update_delay(JitterBuffer *jitter, JitterBufferPacket *packet, spx_int32_t *start_offset) +{ + spx_int16_t opt = compute_opt_delay(jitter); + /*fprintf(stderr, "opt adjustment is %d ", opt);*/ + + if (opt < 0) + { + shift_timings(jitter, -opt); + + jitter->pointer_timestamp += opt; + jitter->interp_requested = -opt; + /*fprintf (stderr, "Decision to interpolate %d samples\n", -opt);*/ + } else if (opt > 0) + { + shift_timings(jitter, -opt); + jitter->pointer_timestamp += opt; + /*fprintf (stderr, "Decision to drop %d samples\n", opt);*/ + } + + return opt; +} + +/* Let the jitter buffer know it's the right time to adjust the buffering delay to the network conditions */ +EXPORT int jitter_buffer_update_delay(JitterBuffer *jitter, JitterBufferPacket *packet, spx_int32_t *start_offset) +{ + /* If the programmer calls jitter_buffer_update_delay() directly, + automatically disable auto-adjustment */ + jitter->auto_adjust = 0; + + return _jitter_buffer_update_delay(jitter, packet, start_offset); +} + +/** Get pointer timestamp of jitter buffer */ +EXPORT int jitter_buffer_get_pointer_timestamp(JitterBuffer *jitter) +{ + return jitter->pointer_timestamp; +} + +EXPORT void jitter_buffer_tick(JitterBuffer *jitter) +{ + /* Automatically-adjust the buffering delay if requested */ + if (jitter->auto_adjust) + _jitter_buffer_update_delay(jitter, NULL, NULL); + + if (jitter->buffered >= 0) + { + jitter->next_stop = jitter->pointer_timestamp - jitter->buffered; + } else { + jitter->next_stop = jitter->pointer_timestamp; + speex_warning_int("jitter buffer sees negative buffering, your code might be broken. Value is ", jitter->buffered); + } + jitter->buffered = 0; +} + +EXPORT void jitter_buffer_remaining_span(JitterBuffer *jitter, spx_uint32_t rem) +{ + /* Automatically-adjust the buffering delay if requested */ + if (jitter->auto_adjust) + _jitter_buffer_update_delay(jitter, NULL, NULL); + + if (jitter->buffered < 0) + speex_warning_int("jitter buffer sees negative buffering, your code might be broken. Value is ", jitter->buffered); + jitter->next_stop = jitter->pointer_timestamp - rem; +} + + +/* Used like the ioctl function to control the jitter buffer parameters */ +EXPORT int jitter_buffer_ctl(JitterBuffer *jitter, int request, void *ptr) +{ + int count, i; + switch(request) + { + case JITTER_BUFFER_SET_MARGIN: + jitter->buffer_margin = *(spx_int32_t*)ptr; + break; + case JITTER_BUFFER_GET_MARGIN: + *(spx_int32_t*)ptr = jitter->buffer_margin; + break; + case JITTER_BUFFER_GET_AVALIABLE_COUNT: + count = 0; + for (i=0;ipackets[i].data && LE32(jitter->pointer_timestamp, jitter->packets[i].timestamp)) + { + count++; + } + } + *(spx_int32_t*)ptr = count; + break; + case JITTER_BUFFER_SET_DESTROY_CALLBACK: + jitter->destroy = (void (*) (void *))ptr; + break; + case JITTER_BUFFER_GET_DESTROY_CALLBACK: + *(void (**) (void *))ptr = jitter->destroy; + break; + case JITTER_BUFFER_SET_DELAY_STEP: + jitter->delay_step = *(spx_int32_t*)ptr; + break; + case JITTER_BUFFER_GET_DELAY_STEP: + *(spx_int32_t*)ptr = jitter->delay_step; + break; + case JITTER_BUFFER_SET_CONCEALMENT_SIZE: + jitter->concealment_size = *(spx_int32_t*)ptr; + break; + case JITTER_BUFFER_GET_CONCEALMENT_SIZE: + *(spx_int32_t*)ptr = jitter->concealment_size; + break; + case JITTER_BUFFER_SET_MAX_LATE_RATE: + jitter->max_late_rate = *(spx_int32_t*)ptr; + jitter->window_size = 100*TOP_DELAY/jitter->max_late_rate; + jitter->subwindow_size = jitter->window_size/MAX_BUFFERS; + break; + case JITTER_BUFFER_GET_MAX_LATE_RATE: + *(spx_int32_t*)ptr = jitter->max_late_rate; + break; + case JITTER_BUFFER_SET_LATE_COST: + jitter->latency_tradeoff = *(spx_int32_t*)ptr; + break; + case JITTER_BUFFER_GET_LATE_COST: + *(spx_int32_t*)ptr = jitter->latency_tradeoff; + break; + default: + speex_warning_int("Unknown jitter_buffer_ctl request: ", request); + return -1; + } + return 0; +} + diff --git a/android/app/src/main/jni/libspeex/kiss_fft.c b/android/app/src/main/jni/libspeex/kiss_fft.c new file mode 100644 index 000000000..67782810f --- /dev/null +++ b/android/app/src/main/jni/libspeex/kiss_fft.c @@ -0,0 +1,523 @@ +/* +Copyright (c) 2003-2004, Mark Borgerding +Copyright (c) 2005-2007, Jean-Marc Valin + +All rights reserved. + +Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. + * Neither the author nor the names of any contributors may be used to endorse or promote products derived from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "_kiss_fft_guts.h" +#include "arch.h" +#include "os_support.h" + +/* The guts header contains all the multiplication and addition macros that are defined for + fixed or floating point complex numbers. It also delares the kf_ internal functions. + */ + +static void kf_bfly2( + kiss_fft_cpx * Fout, + const size_t fstride, + const kiss_fft_cfg st, + int m, + int N, + int mm + ) +{ + kiss_fft_cpx * Fout2; + kiss_fft_cpx * tw1; + kiss_fft_cpx t; + if (!st->inverse) { + int i,j; + kiss_fft_cpx * Fout_beg = Fout; + for (i=0;itwiddles; + for(j=0;jr , tw1->r),MULT16_16(Fout2->i , tw1->i)), 1); + ti = SHR32(ADD32(MULT16_16(Fout2->i , tw1->r),MULT16_16(Fout2->r , tw1->i)), 1); + tw1 += fstride; + Fout2->r = PSHR32(SUB32(SHL32(EXTEND32(Fout->r), 14), tr), 15); + Fout2->i = PSHR32(SUB32(SHL32(EXTEND32(Fout->i), 14), ti), 15); + Fout->r = PSHR32(ADD32(SHL32(EXTEND32(Fout->r), 14), tr), 15); + Fout->i = PSHR32(ADD32(SHL32(EXTEND32(Fout->i), 14), ti), 15); + ++Fout2; + ++Fout; + } + } + } else { + int i,j; + kiss_fft_cpx * Fout_beg = Fout; + for (i=0;itwiddles; + for(j=0;jinverse) + { + kiss_fft_cpx * Fout_beg = Fout; + for (i=0;itwiddles; + for (j=0;jtwiddles; + for (j=0;jr = PSHR16(Fout->r, 2); + Fout->i = PSHR16(Fout->i, 2); + C_SUB( scratch[5] , *Fout, scratch[1] ); + C_ADDTO(*Fout, scratch[1]); + C_ADD( scratch[3] , scratch[0] , scratch[2] ); + C_SUB( scratch[4] , scratch[0] , scratch[2] ); + Fout[m2].r = PSHR16(Fout[m2].r, 2); + Fout[m2].i = PSHR16(Fout[m2].i, 2); + C_SUB( Fout[m2], *Fout, scratch[3] ); + tw1 += fstride; + tw2 += fstride*2; + tw3 += fstride*3; + C_ADDTO( *Fout , scratch[3] ); + + Fout[m].r = scratch[5].r + scratch[4].i; + Fout[m].i = scratch[5].i - scratch[4].r; + Fout[m3].r = scratch[5].r - scratch[4].i; + Fout[m3].i = scratch[5].i + scratch[4].r; + ++Fout; + } + } + } +} + +static void kf_bfly3( + kiss_fft_cpx * Fout, + const size_t fstride, + const kiss_fft_cfg st, + size_t m + ) +{ + size_t k=m; + const size_t m2 = 2*m; + kiss_fft_cpx *tw1,*tw2; + kiss_fft_cpx scratch[5]; + kiss_fft_cpx epi3; + epi3 = st->twiddles[fstride*m]; + + tw1=tw2=st->twiddles; + + do{ + if (!st->inverse) { + C_FIXDIV(*Fout,3); C_FIXDIV(Fout[m],3); C_FIXDIV(Fout[m2],3); + } + + C_MUL(scratch[1],Fout[m] , *tw1); + C_MUL(scratch[2],Fout[m2] , *tw2); + + C_ADD(scratch[3],scratch[1],scratch[2]); + C_SUB(scratch[0],scratch[1],scratch[2]); + tw1 += fstride; + tw2 += fstride*2; + + Fout[m].r = Fout->r - HALF_OF(scratch[3].r); + Fout[m].i = Fout->i - HALF_OF(scratch[3].i); + + C_MULBYSCALAR( scratch[0] , epi3.i ); + + C_ADDTO(*Fout,scratch[3]); + + Fout[m2].r = Fout[m].r + scratch[0].i; + Fout[m2].i = Fout[m].i - scratch[0].r; + + Fout[m].r -= scratch[0].i; + Fout[m].i += scratch[0].r; + + ++Fout; + }while(--k); +} + +static void kf_bfly5( + kiss_fft_cpx * Fout, + const size_t fstride, + const kiss_fft_cfg st, + int m + ) +{ + kiss_fft_cpx *Fout0,*Fout1,*Fout2,*Fout3,*Fout4; + int u; + kiss_fft_cpx scratch[13]; + kiss_fft_cpx * twiddles = st->twiddles; + kiss_fft_cpx *tw; + kiss_fft_cpx ya,yb; + ya = twiddles[fstride*m]; + yb = twiddles[fstride*2*m]; + + Fout0=Fout; + Fout1=Fout0+m; + Fout2=Fout0+2*m; + Fout3=Fout0+3*m; + Fout4=Fout0+4*m; + + tw=st->twiddles; + for ( u=0; uinverse) { + C_FIXDIV( *Fout0,5); C_FIXDIV( *Fout1,5); C_FIXDIV( *Fout2,5); C_FIXDIV( *Fout3,5); C_FIXDIV( *Fout4,5); + } + scratch[0] = *Fout0; + + C_MUL(scratch[1] ,*Fout1, tw[u*fstride]); + C_MUL(scratch[2] ,*Fout2, tw[2*u*fstride]); + C_MUL(scratch[3] ,*Fout3, tw[3*u*fstride]); + C_MUL(scratch[4] ,*Fout4, tw[4*u*fstride]); + + C_ADD( scratch[7],scratch[1],scratch[4]); + C_SUB( scratch[10],scratch[1],scratch[4]); + C_ADD( scratch[8],scratch[2],scratch[3]); + C_SUB( scratch[9],scratch[2],scratch[3]); + + Fout0->r += scratch[7].r + scratch[8].r; + Fout0->i += scratch[7].i + scratch[8].i; + + scratch[5].r = scratch[0].r + S_MUL(scratch[7].r,ya.r) + S_MUL(scratch[8].r,yb.r); + scratch[5].i = scratch[0].i + S_MUL(scratch[7].i,ya.r) + S_MUL(scratch[8].i,yb.r); + + scratch[6].r = S_MUL(scratch[10].i,ya.i) + S_MUL(scratch[9].i,yb.i); + scratch[6].i = -S_MUL(scratch[10].r,ya.i) - S_MUL(scratch[9].r,yb.i); + + C_SUB(*Fout1,scratch[5],scratch[6]); + C_ADD(*Fout4,scratch[5],scratch[6]); + + scratch[11].r = scratch[0].r + S_MUL(scratch[7].r,yb.r) + S_MUL(scratch[8].r,ya.r); + scratch[11].i = scratch[0].i + S_MUL(scratch[7].i,yb.r) + S_MUL(scratch[8].i,ya.r); + scratch[12].r = - S_MUL(scratch[10].i,yb.i) + S_MUL(scratch[9].i,ya.i); + scratch[12].i = S_MUL(scratch[10].r,yb.i) - S_MUL(scratch[9].r,ya.i); + + C_ADD(*Fout2,scratch[11],scratch[12]); + C_SUB(*Fout3,scratch[11],scratch[12]); + + ++Fout0;++Fout1;++Fout2;++Fout3;++Fout4; + } +} + +/* perform the butterfly for one stage of a mixed radix FFT */ +static void kf_bfly_generic( + kiss_fft_cpx * Fout, + const size_t fstride, + const kiss_fft_cfg st, + int m, + int p + ) +{ + int u,k,q1,q; + kiss_fft_cpx * twiddles = st->twiddles; + kiss_fft_cpx t; + kiss_fft_cpx scratchbuf[17]; + int Norig = st->nfft; + + /*CHECKBUF(scratchbuf,nscratchbuf,p);*/ + if (p>17) + speex_fatal("KissFFT: max radix supported is 17"); + + for ( u=0; uinverse) { + C_FIXDIV(scratchbuf[q1],p); + } + k += m; + } + + k=u; + for ( q1=0 ; q1

=Norig) twidx-=Norig; + C_MUL(t,scratchbuf[q] , twiddles[twidx] ); + C_ADDTO( Fout[ k ] ,t); + } + k += m; + } + } +} + +static +void kf_shuffle( + kiss_fft_cpx * Fout, + const kiss_fft_cpx * f, + const size_t fstride, + int in_stride, + int * factors, + const kiss_fft_cfg st + ) +{ + const int p=*factors++; /* the radix */ + const int m=*factors++; /* stage's fft length/p */ + + /*printf ("fft %d %d %d %d %d %d\n", p*m, m, p, s2, fstride*in_stride, N);*/ + if (m==1) + { + int j; + for (j=0;j32000 || (spx_int32_t)p*(spx_int32_t)p > n) + p = n; /* no more factors, skip to end */ + } + n /= p; + *facbuf++ = p; + *facbuf++ = n; + } while (n > 1); +} +/* + * + * User-callable function to allocate all necessary storage space for the fft. + * + * The return value is a contiguous block of memory, allocated with malloc. As such, + * It can be freed with free(), rather than a kiss_fft-specific function. + * */ +kiss_fft_cfg kiss_fft_alloc(int nfft,int inverse_fft,void * mem,size_t * lenmem ) +{ + kiss_fft_cfg st=NULL; + size_t memneeded = sizeof(struct kiss_fft_state) + + sizeof(kiss_fft_cpx)*(nfft-1); /* twiddle factors*/ + + if ( lenmem==NULL ) { + st = ( kiss_fft_cfg)KISS_FFT_MALLOC( memneeded ); + }else{ + if (mem != NULL && *lenmem >= memneeded) + st = (kiss_fft_cfg)mem; + *lenmem = memneeded; + } + if (st) { + int i; + st->nfft=nfft; + st->inverse = inverse_fft; +#ifdef FIXED_POINT + for (i=0;iinverse) + phase = -phase; + kf_cexp2(st->twiddles+i, DIV32(SHL32(phase,17),nfft)); + } +#else + for (i=0;iinverse) + phase *= -1; + kf_cexp(st->twiddles+i, phase ); + } +#endif + kf_factor(nfft,st->factors); + } + return st; +} + + + + +void kiss_fft_stride(kiss_fft_cfg st,const kiss_fft_cpx *fin,kiss_fft_cpx *fout,int in_stride) +{ + if (fin == fout) + { + speex_fatal("In-place FFT not supported"); + /*CHECKBUF(tmpbuf,ntmpbuf,st->nfft); + kf_work(tmpbuf,fin,1,in_stride, st->factors,st); + SPEEX_MOVE(fout,tmpbuf,st->nfft);*/ + } else { + kf_shuffle( fout, fin, 1,in_stride, st->factors,st); + kf_work( fout, fin, 1,in_stride, st->factors,st, 1, in_stride, 1); + } +} + +void kiss_fft(kiss_fft_cfg cfg,const kiss_fft_cpx *fin,kiss_fft_cpx *fout) +{ + kiss_fft_stride(cfg,fin,fout,1); +} + diff --git a/android/app/src/main/jni/libspeex/kiss_fft.h b/android/app/src/main/jni/libspeex/kiss_fft.h new file mode 100644 index 000000000..fa3f2c604 --- /dev/null +++ b/android/app/src/main/jni/libspeex/kiss_fft.h @@ -0,0 +1,108 @@ +#ifndef KISS_FFT_H +#define KISS_FFT_H + +#include +#include +#include "arch.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/* + ATTENTION! + If you would like a : + -- a utility that will handle the caching of fft objects + -- real-only (no imaginary time component ) FFT + -- a multi-dimensional FFT + -- a command-line utility to perform ffts + -- a command-line utility to perform fast-convolution filtering + + Then see kfc.h kiss_fftr.h kiss_fftnd.h fftutil.c kiss_fastfir.c + in the tools/ directory. +*/ + +#ifdef USE_SIMD +# include +# define kiss_fft_scalar __m128 +#define KISS_FFT_MALLOC(nbytes) memalign(16,nbytes) +#else +#define KISS_FFT_MALLOC speex_alloc +#endif + + +#ifdef FIXED_POINT +#include "arch.h" +# define kiss_fft_scalar spx_int16_t +#else +# ifndef kiss_fft_scalar +/* default is float */ +# define kiss_fft_scalar float +# endif +#endif + +typedef struct { + kiss_fft_scalar r; + kiss_fft_scalar i; +}kiss_fft_cpx; + +typedef struct kiss_fft_state* kiss_fft_cfg; + +/* + * kiss_fft_alloc + * + * Initialize a FFT (or IFFT) algorithm's cfg/state buffer. + * + * typical usage: kiss_fft_cfg mycfg=kiss_fft_alloc(1024,0,NULL,NULL); + * + * The return value from fft_alloc is a cfg buffer used internally + * by the fft routine or NULL. + * + * If lenmem is NULL, then kiss_fft_alloc will allocate a cfg buffer using malloc. + * The returned value should be free()d when done to avoid memory leaks. + * + * The state can be placed in a user supplied buffer 'mem': + * If lenmem is not NULL and mem is not NULL and *lenmem is large enough, + * then the function places the cfg in mem and the size used in *lenmem + * and returns mem. + * + * If lenmem is not NULL and ( mem is NULL or *lenmem is not large enough), + * then the function returns NULL and places the minimum cfg + * buffer size in *lenmem. + * */ + +kiss_fft_cfg kiss_fft_alloc(int nfft,int inverse_fft,void * mem,size_t * lenmem); + +/* + * kiss_fft(cfg,in_out_buf) + * + * Perform an FFT on a complex input buffer. + * for a forward FFT, + * fin should be f[0] , f[1] , ... ,f[nfft-1] + * fout will be F[0] , F[1] , ... ,F[nfft-1] + * Note that each element is complex and can be accessed like + f[k].r and f[k].i + * */ +void kiss_fft(kiss_fft_cfg cfg,const kiss_fft_cpx *fin,kiss_fft_cpx *fout); + +/* + A more generic version of the above function. It reads its input from every Nth sample. + * */ +void kiss_fft_stride(kiss_fft_cfg cfg,const kiss_fft_cpx *fin,kiss_fft_cpx *fout,int fin_stride); + +/* If kiss_fft_alloc allocated a buffer, it is one contiguous + buffer and can be simply free()d when no longer needed*/ +#define kiss_fft_free speex_free + +/* + Cleans up some memory that gets managed internally. Not necessary to call, but it might clean up + your compiler output to call this before you exit. +*/ +void kiss_fft_cleanup(void); + + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/android/app/src/main/jni/libspeex/kiss_fftr.c b/android/app/src/main/jni/libspeex/kiss_fftr.c new file mode 100644 index 000000000..f6275b879 --- /dev/null +++ b/android/app/src/main/jni/libspeex/kiss_fftr.c @@ -0,0 +1,297 @@ +/* +Copyright (c) 2003-2004, Mark Borgerding + +All rights reserved. + +Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. + * Neither the author nor the names of any contributors may be used to endorse or promote products derived from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "os_support.h" +#include "kiss_fftr.h" +#include "_kiss_fft_guts.h" + +struct kiss_fftr_state{ + kiss_fft_cfg substate; + kiss_fft_cpx * tmpbuf; + kiss_fft_cpx * super_twiddles; +#ifdef USE_SIMD + long pad; +#endif +}; + +kiss_fftr_cfg kiss_fftr_alloc(int nfft,int inverse_fft,void * mem,size_t * lenmem) +{ + int i; + kiss_fftr_cfg st = NULL; + size_t subsize, memneeded; + + if (nfft & 1) { + speex_warning("Real FFT optimization must be even.\n"); + return NULL; + } + nfft >>= 1; + + kiss_fft_alloc (nfft, inverse_fft, NULL, &subsize); + memneeded = sizeof(struct kiss_fftr_state) + subsize + sizeof(kiss_fft_cpx) * ( nfft * 2); + + if (lenmem == NULL) { + st = (kiss_fftr_cfg) KISS_FFT_MALLOC (memneeded); + } else { + if (*lenmem >= memneeded) + st = (kiss_fftr_cfg) mem; + *lenmem = memneeded; + } + if (!st) + return NULL; + + st->substate = (kiss_fft_cfg) (st + 1); /*just beyond kiss_fftr_state struct */ + st->tmpbuf = (kiss_fft_cpx *) (((char *) st->substate) + subsize); + st->super_twiddles = st->tmpbuf + nfft; + kiss_fft_alloc(nfft, inverse_fft, st->substate, &subsize); + +#ifdef FIXED_POINT + for (i=0;i>1); + if (!inverse_fft) + phase = -phase; + kf_cexp2(st->super_twiddles+i, DIV32(SHL32(phase,16),nfft)); + } +#else + for (i=0;isuper_twiddles+i, phase ); + } +#endif + return st; +} + +void kiss_fftr(kiss_fftr_cfg st,const kiss_fft_scalar *timedata,kiss_fft_cpx *freqdata) +{ + /* input buffer timedata is stored row-wise */ + int k,ncfft; + kiss_fft_cpx fpnk,fpk,f1k,f2k,tw,tdc; + + if ( st->substate->inverse) { + speex_fatal("kiss fft usage error: improper alloc\n"); + } + + ncfft = st->substate->nfft; + + /*perform the parallel fft of two real signals packed in real,imag*/ + kiss_fft( st->substate , (const kiss_fft_cpx*)timedata, st->tmpbuf ); + /* The real part of the DC element of the frequency spectrum in st->tmpbuf + * contains the sum of the even-numbered elements of the input time sequence + * The imag part is the sum of the odd-numbered elements + * + * The sum of tdc.r and tdc.i is the sum of the input time sequence. + * yielding DC of input time sequence + * The difference of tdc.r - tdc.i is the sum of the input (dot product) [1,-1,1,-1... + * yielding Nyquist bin of input time sequence + */ + + tdc.r = st->tmpbuf[0].r; + tdc.i = st->tmpbuf[0].i; + C_FIXDIV(tdc,2); + CHECK_OVERFLOW_OP(tdc.r ,+, tdc.i); + CHECK_OVERFLOW_OP(tdc.r ,-, tdc.i); + freqdata[0].r = tdc.r + tdc.i; + freqdata[ncfft].r = tdc.r - tdc.i; +#ifdef USE_SIMD + freqdata[ncfft].i = freqdata[0].i = _mm_set1_ps(0); +#else + freqdata[ncfft].i = freqdata[0].i = 0; +#endif + + for ( k=1;k <= ncfft/2 ; ++k ) { + fpk = st->tmpbuf[k]; + fpnk.r = st->tmpbuf[ncfft-k].r; + fpnk.i = - st->tmpbuf[ncfft-k].i; + C_FIXDIV(fpk,2); + C_FIXDIV(fpnk,2); + + C_ADD( f1k, fpk , fpnk ); + C_SUB( f2k, fpk , fpnk ); + C_MUL( tw , f2k , st->super_twiddles[k]); + + freqdata[k].r = HALF_OF(f1k.r + tw.r); + freqdata[k].i = HALF_OF(f1k.i + tw.i); + freqdata[ncfft-k].r = HALF_OF(f1k.r - tw.r); + freqdata[ncfft-k].i = HALF_OF(tw.i - f1k.i); + } +} + +void kiss_fftri(kiss_fftr_cfg st,const kiss_fft_cpx *freqdata, kiss_fft_scalar *timedata) +{ + /* input buffer timedata is stored row-wise */ + int k, ncfft; + + if (st->substate->inverse == 0) { + speex_fatal("kiss fft usage error: improper alloc\n"); + } + + ncfft = st->substate->nfft; + + st->tmpbuf[0].r = freqdata[0].r + freqdata[ncfft].r; + st->tmpbuf[0].i = freqdata[0].r - freqdata[ncfft].r; + /*C_FIXDIV(st->tmpbuf[0],2);*/ + + for (k = 1; k <= ncfft / 2; ++k) { + kiss_fft_cpx fk, fnkc, fek, fok, tmp; + fk = freqdata[k]; + fnkc.r = freqdata[ncfft - k].r; + fnkc.i = -freqdata[ncfft - k].i; + /*C_FIXDIV( fk , 2 ); + C_FIXDIV( fnkc , 2 );*/ + + C_ADD (fek, fk, fnkc); + C_SUB (tmp, fk, fnkc); + C_MUL (fok, tmp, st->super_twiddles[k]); + C_ADD (st->tmpbuf[k], fek, fok); + C_SUB (st->tmpbuf[ncfft - k], fek, fok); +#ifdef USE_SIMD + st->tmpbuf[ncfft - k].i *= _mm_set1_ps(-1.0); +#else + st->tmpbuf[ncfft - k].i *= -1; +#endif + } + kiss_fft (st->substate, st->tmpbuf, (kiss_fft_cpx *) timedata); +} + +void kiss_fftr2(kiss_fftr_cfg st,const kiss_fft_scalar *timedata,kiss_fft_scalar *freqdata) +{ + /* input buffer timedata is stored row-wise */ + int k,ncfft; + kiss_fft_cpx f2k,tdc; + spx_word32_t f1kr, f1ki, twr, twi; + + if ( st->substate->inverse) { + speex_fatal("kiss fft usage error: improper alloc\n"); + } + + ncfft = st->substate->nfft; + + /*perform the parallel fft of two real signals packed in real,imag*/ + kiss_fft( st->substate , (const kiss_fft_cpx*)timedata, st->tmpbuf ); + /* The real part of the DC element of the frequency spectrum in st->tmpbuf + * contains the sum of the even-numbered elements of the input time sequence + * The imag part is the sum of the odd-numbered elements + * + * The sum of tdc.r and tdc.i is the sum of the input time sequence. + * yielding DC of input time sequence + * The difference of tdc.r - tdc.i is the sum of the input (dot product) [1,-1,1,-1... + * yielding Nyquist bin of input time sequence + */ + + tdc.r = st->tmpbuf[0].r; + tdc.i = st->tmpbuf[0].i; + C_FIXDIV(tdc,2); + CHECK_OVERFLOW_OP(tdc.r ,+, tdc.i); + CHECK_OVERFLOW_OP(tdc.r ,-, tdc.i); + freqdata[0] = tdc.r + tdc.i; + freqdata[2*ncfft-1] = tdc.r - tdc.i; + + for ( k=1;k <= ncfft/2 ; ++k ) + { + /*fpk = st->tmpbuf[k]; + fpnk.r = st->tmpbuf[ncfft-k].r; + fpnk.i = - st->tmpbuf[ncfft-k].i; + C_FIXDIV(fpk,2); + C_FIXDIV(fpnk,2); + + C_ADD( f1k, fpk , fpnk ); + C_SUB( f2k, fpk , fpnk ); + + C_MUL( tw , f2k , st->super_twiddles[k]); + + freqdata[2*k-1] = HALF_OF(f1k.r + tw.r); + freqdata[2*k] = HALF_OF(f1k.i + tw.i); + freqdata[2*(ncfft-k)-1] = HALF_OF(f1k.r - tw.r); + freqdata[2*(ncfft-k)] = HALF_OF(tw.i - f1k.i); + */ + + /*f1k.r = PSHR32(ADD32(EXTEND32(st->tmpbuf[k].r), EXTEND32(st->tmpbuf[ncfft-k].r)),1); + f1k.i = PSHR32(SUB32(EXTEND32(st->tmpbuf[k].i), EXTEND32(st->tmpbuf[ncfft-k].i)),1); + f2k.r = PSHR32(SUB32(EXTEND32(st->tmpbuf[k].r), EXTEND32(st->tmpbuf[ncfft-k].r)),1); + f2k.i = SHR32(ADD32(EXTEND32(st->tmpbuf[k].i), EXTEND32(st->tmpbuf[ncfft-k].i)),1); + + C_MUL( tw , f2k , st->super_twiddles[k]); + + freqdata[2*k-1] = HALF_OF(f1k.r + tw.r); + freqdata[2*k] = HALF_OF(f1k.i + tw.i); + freqdata[2*(ncfft-k)-1] = HALF_OF(f1k.r - tw.r); + freqdata[2*(ncfft-k)] = HALF_OF(tw.i - f1k.i); + */ + f2k.r = SHR32(SUB32(EXTEND32(st->tmpbuf[k].r), EXTEND32(st->tmpbuf[ncfft-k].r)),1); + f2k.i = PSHR32(ADD32(EXTEND32(st->tmpbuf[k].i), EXTEND32(st->tmpbuf[ncfft-k].i)),1); + + f1kr = SHL32(ADD32(EXTEND32(st->tmpbuf[k].r), EXTEND32(st->tmpbuf[ncfft-k].r)),13); + f1ki = SHL32(SUB32(EXTEND32(st->tmpbuf[k].i), EXTEND32(st->tmpbuf[ncfft-k].i)),13); + + twr = SHR32(SUB32(MULT16_16(f2k.r,st->super_twiddles[k].r),MULT16_16(f2k.i,st->super_twiddles[k].i)), 1); + twi = SHR32(ADD32(MULT16_16(f2k.i,st->super_twiddles[k].r),MULT16_16(f2k.r,st->super_twiddles[k].i)), 1); + +#ifdef FIXED_POINT + freqdata[2*k-1] = PSHR32(f1kr + twr, 15); + freqdata[2*k] = PSHR32(f1ki + twi, 15); + freqdata[2*(ncfft-k)-1] = PSHR32(f1kr - twr, 15); + freqdata[2*(ncfft-k)] = PSHR32(twi - f1ki, 15); +#else + freqdata[2*k-1] = .5f*(f1kr + twr); + freqdata[2*k] = .5f*(f1ki + twi); + freqdata[2*(ncfft-k)-1] = .5f*(f1kr - twr); + freqdata[2*(ncfft-k)] = .5f*(twi - f1ki); + +#endif + } +} + +void kiss_fftri2(kiss_fftr_cfg st,const kiss_fft_scalar *freqdata,kiss_fft_scalar *timedata) +{ + /* input buffer timedata is stored row-wise */ + int k, ncfft; + + if (st->substate->inverse == 0) { + speex_fatal ("kiss fft usage error: improper alloc\n"); + } + + ncfft = st->substate->nfft; + + st->tmpbuf[0].r = freqdata[0] + freqdata[2*ncfft-1]; + st->tmpbuf[0].i = freqdata[0] - freqdata[2*ncfft-1]; + /*C_FIXDIV(st->tmpbuf[0],2);*/ + + for (k = 1; k <= ncfft / 2; ++k) { + kiss_fft_cpx fk, fnkc, fek, fok, tmp; + fk.r = freqdata[2*k-1]; + fk.i = freqdata[2*k]; + fnkc.r = freqdata[2*(ncfft - k)-1]; + fnkc.i = -freqdata[2*(ncfft - k)]; + /*C_FIXDIV( fk , 2 ); + C_FIXDIV( fnkc , 2 );*/ + + C_ADD (fek, fk, fnkc); + C_SUB (tmp, fk, fnkc); + C_MUL (fok, tmp, st->super_twiddles[k]); + C_ADD (st->tmpbuf[k], fek, fok); + C_SUB (st->tmpbuf[ncfft - k], fek, fok); +#ifdef USE_SIMD + st->tmpbuf[ncfft - k].i *= _mm_set1_ps(-1.0); +#else + st->tmpbuf[ncfft - k].i *= -1; +#endif + } + kiss_fft (st->substate, st->tmpbuf, (kiss_fft_cpx *) timedata); +} diff --git a/android/app/src/main/jni/libspeex/kiss_fftr.h b/android/app/src/main/jni/libspeex/kiss_fftr.h new file mode 100644 index 000000000..7bfb42334 --- /dev/null +++ b/android/app/src/main/jni/libspeex/kiss_fftr.h @@ -0,0 +1,51 @@ +#ifndef KISS_FTR_H +#define KISS_FTR_H + +#include "kiss_fft.h" +#ifdef __cplusplus +extern "C" { +#endif + + +/* + + Real optimized version can save about 45% cpu time vs. complex fft of a real seq. + + + + */ + +typedef struct kiss_fftr_state *kiss_fftr_cfg; + + +kiss_fftr_cfg kiss_fftr_alloc(int nfft,int inverse_fft,void * mem, size_t * lenmem); +/* + nfft must be even + + If you don't care to allocate space, use mem = lenmem = NULL +*/ + + +void kiss_fftr(kiss_fftr_cfg cfg,const kiss_fft_scalar *timedata,kiss_fft_cpx *freqdata); +/* + input timedata has nfft scalar points + output freqdata has nfft/2+1 complex points +*/ + +void kiss_fftr2(kiss_fftr_cfg st,const kiss_fft_scalar *timedata,kiss_fft_scalar *freqdata); + +void kiss_fftri(kiss_fftr_cfg cfg,const kiss_fft_cpx *freqdata,kiss_fft_scalar *timedata); + +void kiss_fftri2(kiss_fftr_cfg st,const kiss_fft_scalar *freqdata, kiss_fft_scalar *timedata); + +/* + input freqdata has nfft/2+1 complex points + output timedata has nfft scalar points +*/ + +#define kiss_fftr_free speex_free + +#ifdef __cplusplus +} +#endif +#endif diff --git a/android/app/src/main/jni/libspeex/lpc.c b/android/app/src/main/jni/libspeex/lpc.c new file mode 100644 index 000000000..fd5d3821e --- /dev/null +++ b/android/app/src/main/jni/libspeex/lpc.c @@ -0,0 +1,201 @@ +/* + Copyright 1992, 1993, 1994 by Jutta Degener and Carsten Bormann, + Technische Universitaet Berlin + + Any use of this software is permitted provided that this notice is not + removed and that neither the authors nor the Technische Universitaet Berlin + are deemed to have made any representations as to the suitability of this + software for any purpose nor are held responsible for any defects of + this software. THERE IS ABSOLUTELY NO WARRANTY FOR THIS SOFTWARE. + + As a matter of courtesy, the authors request to be informed about uses + this software has found, about bugs in this software, and about any + improvements that may be of general interest. + + Berlin, 28.11.1994 + Jutta Degener + Carsten Bormann + + + Code modified by Jean-Marc Valin + + Speex License: + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + - Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + - Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + - Neither the name of the Xiph.org Foundation nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR + CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "lpc.h" + +#ifdef BFIN_ASM +#include "lpc_bfin.h" +#endif + +/* LPC analysis + * + * The next two functions calculate linear prediction coefficients + * and/or the related reflection coefficients from the first P_MAX+1 + * values of the autocorrelation function. + */ + +/* Invented by N. Levinson in 1947, modified by J. Durbin in 1959. + */ + +/* returns minimum mean square error */ +spx_word32_t _spx_lpc( +spx_coef_t *lpc, /* out: [0...p-1] LPC coefficients */ +const spx_word16_t *ac, /* in: [0...p] autocorrelation values */ +int p +) +{ + int i, j; + spx_word16_t r; + spx_word16_t error = ac[0]; + + if (ac[0] == 0) + { + for (i = 0; i < p; i++) + lpc[i] = 0; + return 0; + } + + for (i = 0; i < p; i++) { + + /* Sum up this iteration's reflection coefficient */ + spx_word32_t rr = NEG32(SHL32(EXTEND32(ac[i + 1]),13)); + for (j = 0; j < i; j++) + rr = SUB32(rr,MULT16_16(lpc[j],ac[i - j])); +#ifdef FIXED_POINT + r = DIV32_16(rr+PSHR32(error,1),ADD16(error,8)); +#else + r = rr/(error+.003*ac[0]); +#endif + /* Update LPC coefficients and total error */ + lpc[i] = r; + for (j = 0; j < i>>1; j++) + { + spx_word16_t tmp = lpc[j]; + lpc[j] = MAC16_16_P13(lpc[j],r,lpc[i-1-j]); + lpc[i-1-j] = MAC16_16_P13(lpc[i-1-j],r,tmp); + } + if (i & 1) + lpc[j] = MAC16_16_P13(lpc[j],lpc[j],r); + + error = SUB16(error,MULT16_16_Q13(r,MULT16_16_Q13(error,r))); + } + return error; +} + + +#ifdef FIXED_POINT + +/* Compute the autocorrelation + * ,--, + * ac(i) = > x(n) * x(n-i) for all n + * `--' + * for lags between 0 and lag-1, and x == 0 outside 0...n-1 + */ + +#ifndef OVERRIDE_SPEEX_AUTOCORR +void _spx_autocorr( +const spx_word16_t *x, /* in: [0...n-1] samples x */ +spx_word16_t *ac, /* out: [0...lag-1] ac values */ +int lag, +int n +) +{ + spx_word32_t d; + int i, j; + spx_word32_t ac0=1; + int shift, ac_shift; + + for (j=0;j x(n) * x(n-i) for all n + * `--' + * for lags between 0 and lag-1, and x == 0 outside 0...n-1 + */ +void _spx_autocorr( +const spx_word16_t *x, /* in: [0...n-1] samples x */ +float *ac, /* out: [0...lag-1] ac values */ +int lag, +int n +) +{ + float d; + int i; + while (lag--) + { + for (i = lag, d = 0; i < n; i++) + d += x[i] * x[i-lag]; + ac[lag] = d; + } + ac[0] += 10; +} + +#endif + + diff --git a/android/app/src/main/jni/libspeex/lpc.h b/android/app/src/main/jni/libspeex/lpc.h new file mode 100644 index 000000000..952ecdd93 --- /dev/null +++ b/android/app/src/main/jni/libspeex/lpc.h @@ -0,0 +1,53 @@ +/* Copyright (C) 2002 Jean-Marc Valin */ +/** + @file lpc.h + @brief Functions for LPC (Linear Prediction Coefficients) analysis +*/ +/* + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + - Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + - Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + - Neither the name of the Xiph.org Foundation nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR + CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#ifndef LPC_H +#define LPC_H + +#include "arch.h" + +void _spx_autocorr( + const spx_word16_t * x, /* in: [0...n-1] samples x */ + spx_word16_t *ac, /* out: [0...lag-1] ac values */ + int lag, int n); + +spx_word32_t /* returns minimum mean square error */ +_spx_lpc( + spx_coef_t * lpc, /* [0...p-1] LPC coefficients */ + const spx_word16_t * ac, /* in: [0...p] autocorrelation values */ + int p + ); + + +#endif diff --git a/android/app/src/main/jni/libspeex/lpc_bfin.h b/android/app/src/main/jni/libspeex/lpc_bfin.h new file mode 100644 index 000000000..7310ffba5 --- /dev/null +++ b/android/app/src/main/jni/libspeex/lpc_bfin.h @@ -0,0 +1,131 @@ +/* Copyright (C) 2005 Analog Devices */ +/** + @file lpc_bfin.h + @author Jean-Marc Valin + @brief Functions for LPC (Linear Prediction Coefficients) analysis (Blackfin version) +*/ +/* + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + - Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + - Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + - Neither the name of the Xiph.org Foundation nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR + CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#define OVERRIDE_SPEEX_AUTOCORR +void _spx_autocorr( +const spx_word16_t *x, /* in: [0...n-1] samples x */ +spx_word16_t *ac, /* out: [0...lag-1] ac values */ +int lag, +int n + ) +{ + spx_word32_t d; + const spx_word16_t *xs; + int i, j; + spx_word32_t ac0=1; + spx_word32_t ac32[11], *ac32top; + int shift, ac_shift; + ac32top = ac32+lag-1; + int lag_1, N_lag; + int nshift; + lag_1 = lag-1; + N_lag = n-lag_1; + for (j=0;j> 1;\n\t" + "LOOP_BEGIN pitch%=;\n\t" + "I1 = P0;\n\t" + "A1 = A0 = 0;\n\t" + "R1 = [I1++];\n\t" + "LOOP inner_prod%= LC1 = P3 >> 1;\n\t" + "LOOP_BEGIN inner_prod%=;\n\t" + "A1 += R0.L*R1.H, A0 += R0.L*R1.L (IS) || R1.L = W[I1++];\n\t" + "A1 += R0.H*R1.L, A0 += R0.H*R1.H (IS) || R1.H = W[I1++] || R0 = [I0++];\n\t" + "LOOP_END inner_prod%=;\n\t" + "A0 = ASHIFT A0 by R4.L;\n\t" + "A1 = ASHIFT A1 by R4.L;\n\t" + + "R2 = A0, R3 = A1;\n\t" + "[P1--] = R2;\n\t" + "[P1--] = R3;\n\t" + "P0 += 4;\n\t" + "LOOP_END pitch%=;\n\t" + : : "m" (xs), "m" (x), "m" (ac32top), "m" (N_lag), "m" (lag_1), "m" (nshift) + : "A0", "A1", "P0", "P1", "P2", "P3", "P4", "R0", "R1", "R2", "R3", "R4", "I0", "I1", "L0", "L1", "B0", "B1", "memory" + ); + d=0; + for (j=0;j +#include "lsp.h" +#include "stack_alloc.h" +#include "math_approx.h" + +#ifndef M_PI +#define M_PI 3.14159265358979323846 /* pi */ +#endif + +#ifndef NULL +#define NULL 0 +#endif + +#ifdef FIXED_POINT + +#define FREQ_SCALE 16384 + +/*#define ANGLE2X(a) (32768*cos(((a)/8192.)))*/ +#define ANGLE2X(a) (SHL16(spx_cos(a),2)) + +/*#define X2ANGLE(x) (acos(.00006103515625*(x))*LSP_SCALING)*/ +#define X2ANGLE(x) (spx_acos(x)) + +#ifdef BFIN_ASM +#include "lsp_bfin.h" +#endif + +#else + +/*#define C1 0.99940307 +#define C2 -0.49558072 +#define C3 0.03679168*/ + +#define FREQ_SCALE 1. +#define ANGLE2X(a) (spx_cos(a)) +#define X2ANGLE(x) (acos(x)) + +#endif + + +/*---------------------------------------------------------------------------*\ + + FUNCTION....: cheb_poly_eva() + + AUTHOR......: David Rowe + DATE CREATED: 24/2/93 + + This function evaluates a series of Chebyshev polynomials + +\*---------------------------------------------------------------------------*/ + +#ifdef FIXED_POINT + +#ifndef OVERRIDE_CHEB_POLY_EVA +static inline spx_word32_t cheb_poly_eva( + spx_word16_t *coef, /* P or Q coefs in Q13 format */ + spx_word16_t x, /* cos of freq (-1.0 to 1.0) in Q14 format */ + int m, /* LPC order/2 */ + char *stack +) +{ + int i; + spx_word16_t b0, b1; + spx_word32_t sum; + + /*Prevents overflows*/ + if (x>16383) + x = 16383; + if (x<-16383) + x = -16383; + + /* Initialise values */ + b1=16384; + b0=x; + + /* Evaluate Chebyshev series formulation usin g iterative approach */ + sum = ADD32(EXTEND32(coef[m]), EXTEND32(MULT16_16_P14(coef[m-1],x))); + for(i=2;i<=m;i++) + { + spx_word16_t tmp=b0; + b0 = SUB16(MULT16_16_Q13(x,b0), b1); + b1 = tmp; + sum = ADD32(sum, EXTEND32(MULT16_16_P14(coef[m-i],b0))); + } + + return sum; +} +#endif + +#else + +static float cheb_poly_eva(spx_word32_t *coef, spx_word16_t x, int m, char *stack) +{ + int k; + float b0, b1, tmp; + + /* Initial conditions */ + b0=0; /* b_(m+1) */ + b1=0; /* b_(m+2) */ + + x*=2; + + /* Calculate the b_(k) */ + for(k=m;k>0;k--) + { + tmp=b0; /* tmp holds the previous value of b0 */ + b0=x*b0-b1+coef[m-k]; /* b0 holds its new value based on b0 and b1 */ + b1=tmp; /* b1 holds the previous value of b0 */ + } + + return(-b1+.5*x*b0+coef[m]); +} +#endif + +/*---------------------------------------------------------------------------*\ + + FUNCTION....: lpc_to_lsp() + + AUTHOR......: David Rowe + DATE CREATED: 24/2/93 + + This function converts LPC coefficients to LSP + coefficients. + +\*---------------------------------------------------------------------------*/ + +#ifdef FIXED_POINT +#define SIGN_CHANGE(a,b) (((a)&0x70000000)^((b)&0x70000000)||(b==0)) +#else +#define SIGN_CHANGE(a,b) (((a)*(b))<0.0) +#endif + + +int lpc_to_lsp (spx_coef_t *a,int lpcrdr,spx_lsp_t *freq,int nb,spx_word16_t delta, char *stack) +/* float *a lpc coefficients */ +/* int lpcrdr order of LPC coefficients (10) */ +/* float *freq LSP frequencies in the x domain */ +/* int nb number of sub-intervals (4) */ +/* float delta grid spacing interval (0.02) */ + + +{ + spx_word16_t temp_xr,xl,xr,xm=0; + spx_word32_t psuml,psumr,psumm,temp_psumr/*,temp_qsumr*/; + int i,j,m,flag,k; + VARDECL(spx_word32_t *Q); /* ptrs for memory allocation */ + VARDECL(spx_word32_t *P); + VARDECL(spx_word16_t *Q16); /* ptrs for memory allocation */ + VARDECL(spx_word16_t *P16); + spx_word32_t *px; /* ptrs of respective P'(z) & Q'(z) */ + spx_word32_t *qx; + spx_word32_t *p; + spx_word32_t *q; + spx_word16_t *pt; /* ptr used for cheb_poly_eval() + whether P' or Q' */ + int roots=0; /* DR 8/2/94: number of roots found */ + flag = 1; /* program is searching for a root when, + 1 else has found one */ + m = lpcrdr/2; /* order of P'(z) & Q'(z) polynomials */ + + /* Allocate memory space for polynomials */ + ALLOC(Q, (m+1), spx_word32_t); + ALLOC(P, (m+1), spx_word32_t); + + /* determine P'(z)'s and Q'(z)'s coefficients where + P'(z) = P(z)/(1 + z^(-1)) and Q'(z) = Q(z)/(1-z^(-1)) */ + + px = P; /* initialise ptrs */ + qx = Q; + p = px; + q = qx; + +#ifdef FIXED_POINT + *px++ = LPC_SCALING; + *qx++ = LPC_SCALING; + for(i=0;i=32768) + speex_warning_int("px", *px); + if (fabs(*qx)>=32768) + speex_warning_int("qx", *qx);*/ + *px = PSHR32(*px,2); + *qx = PSHR32(*qx,2); + px++; + qx++; + } + /* The reason for this lies in the way cheb_poly_eva() is implemented for fixed-point */ + P[m] = PSHR32(P[m],3); + Q[m] = PSHR32(Q[m],3); +#else + *px++ = LPC_SCALING; + *qx++ = LPC_SCALING; + for(i=0;i= -FREQ_SCALE)){ + spx_word16_t dd; + /* Modified by JMV to provide smaller steps around x=+-1 */ +#ifdef FIXED_POINT + dd = MULT16_16_Q15(delta,SUB16(FREQ_SCALE, MULT16_16_Q14(MULT16_16_Q14(xl,xl),14000))); + if (psuml<512 && psuml>-512) + dd = PSHR16(dd,1); +#else + dd=delta*(1-.9*xl*xl); + if (fabs(psuml)<.2) + dd *= .5; +#endif + xr = SUB16(xl, dd); /* interval spacing */ + psumr = cheb_poly_eva(pt,xr,m,stack);/* poly(xl-delta_x) */ + temp_psumr = psumr; + temp_xr = xr; + + /* if no sign change increment xr and re-evaluate poly(xr). Repeat til + sign change. + if a sign change has occurred the interval is bisected and then + checked again for a sign change which determines in which + interval the zero lies in. + If there is no sign change between poly(xm) and poly(xl) set interval + between xm and xr else set interval between xl and xr and repeat till + root is located within the specified limits */ + + if(SIGN_CHANGE(psumr,psuml)) + { + roots++; + + psumm=psuml; + for(k=0;k<=nb;k++){ +#ifdef FIXED_POINT + xm = ADD16(PSHR16(xl,1),PSHR16(xr,1)); /* bisect the interval */ +#else + xm = .5*(xl+xr); /* bisect the interval */ +#endif + psumm=cheb_poly_eva(pt,xm,m,stack); + /*if(psumm*psuml>0.)*/ + if(!SIGN_CHANGE(psumm,psuml)) + { + psuml=psumm; + xl=xm; + } else { + psumr=psumm; + xr=xm; + } + } + + /* once zero is found, reset initial interval to xr */ + freq[j] = X2ANGLE(xm); + xl = xm; + flag = 0; /* reset flag for next search */ + } + else{ + psuml=temp_psumr; + xl=temp_xr; + } + } + } + return(roots); +} + +/*---------------------------------------------------------------------------*\ + + FUNCTION....: lsp_to_lpc() + + AUTHOR......: David Rowe + DATE CREATED: 24/2/93 + + Converts LSP coefficients to LPC coefficients. + +\*---------------------------------------------------------------------------*/ + +#ifdef FIXED_POINT + +void lsp_to_lpc(spx_lsp_t *freq,spx_coef_t *ak,int lpcrdr, char *stack) +/* float *freq array of LSP frequencies in the x domain */ +/* float *ak array of LPC coefficients */ +/* int lpcrdr order of LPC coefficients */ +{ + int i,j; + spx_word32_t xout1,xout2,xin; + spx_word32_t mult, a; + VARDECL(spx_word16_t *freqn); + VARDECL(spx_word32_t **xp); + VARDECL(spx_word32_t *xpmem); + VARDECL(spx_word32_t **xq); + VARDECL(spx_word32_t *xqmem); + int m = lpcrdr>>1; + + /* + + Reconstruct P(z) and Q(z) by cascading second order polynomials + in form 1 - 2cos(w)z(-1) + z(-2), where w is the LSP frequency. + In the time domain this is: + + y(n) = x(n) - 2cos(w)x(n-1) + x(n-2) + + This is what the ALLOCS below are trying to do: + + int xp[m+1][lpcrdr+1+2]; // P matrix in QIMP + int xq[m+1][lpcrdr+1+2]; // Q matrix in QIMP + + These matrices store the output of each stage on each row. The + final (m-th) row has the output of the final (m-th) cascaded + 2nd order filter. The first row is the impulse input to the + system (not written as it is known). + + The version below takes advantage of the fact that a lot of the + outputs are zero or known, for example if we put an inpulse + into the first section the "clock" it 10 times only the first 3 + outputs samples are non-zero (it's an FIR filter). + */ + + ALLOC(xp, (m+1), spx_word32_t*); + ALLOC(xpmem, (m+1)*(lpcrdr+1+2), spx_word32_t); + + ALLOC(xq, (m+1), spx_word32_t*); + ALLOC(xqmem, (m+1)*(lpcrdr+1+2), spx_word32_t); + + for(i=0; i<=m; i++) { + xp[i] = xpmem + i*(lpcrdr+1+2); + xq[i] = xqmem + i*(lpcrdr+1+2); + } + + /* work out 2cos terms in Q14 */ + + ALLOC(freqn, lpcrdr, spx_word16_t); + for (i=0;i 32767) a = 32767; + ak[j-1] = (short)a; + + } + +} + +#else + +void lsp_to_lpc(spx_lsp_t *freq,spx_coef_t *ak,int lpcrdr, char *stack) +/* float *freq array of LSP frequencies in the x domain */ +/* float *ak array of LPC coefficients */ +/* int lpcrdr order of LPC coefficients */ + + +{ + int i,j; + float xout1,xout2,xin1,xin2; + VARDECL(float *Wp); + float *pw,*n1,*n2,*n3,*n4=NULL; + VARDECL(float *x_freq); + int m = lpcrdr>>1; + + ALLOC(Wp, 4*m+2, float); + pw = Wp; + + /* initialise contents of array */ + + for(i=0;i<=4*m+1;i++){ /* set contents of buffer to 0 */ + *pw++ = 0.0; + } + + /* Set pointers up */ + + pw = Wp; + xin1 = 1.0; + xin2 = 1.0; + + ALLOC(x_freq, lpcrdr, float); + for (i=0;i0) + ak[j-1] = (xout1 + xout2)*0.5f; + *(n4+1) = xin1; + *(n4+2) = xin2; + + xin1 = 0.0; + xin2 = 0.0; + } + +} +#endif + + +#ifdef FIXED_POINT + +/*Makes sure the LSPs are stable*/ +void lsp_enforce_margin(spx_lsp_t *lsp, int len, spx_word16_t margin) +{ + int i; + spx_word16_t m = margin; + spx_word16_t m2 = 25736-margin; + + if (lsp[0]m2) + lsp[len-1]=m2; + for (i=1;ilsp[i+1]-m) + lsp[i]= SHR16(lsp[i],1) + SHR16(lsp[i+1]-m,1); + } +} + + +void lsp_interpolate(spx_lsp_t *old_lsp, spx_lsp_t *new_lsp, spx_lsp_t *interp_lsp, int len, int subframe, int nb_subframes) +{ + int i; + spx_word16_t tmp = DIV32_16(SHL32(EXTEND32(1 + subframe),14),nb_subframes); + spx_word16_t tmp2 = 16384-tmp; + for (i=0;iLSP_SCALING*(M_PI-margin)) + lsp[len-1]=LSP_SCALING*(M_PI-margin); + for (i=1;ilsp[i+1]-LSP_SCALING*margin) + lsp[i]= .5f* (lsp[i] + lsp[i+1]-LSP_SCALING*margin); + } +} + + +void lsp_interpolate(spx_lsp_t *old_lsp, spx_lsp_t *new_lsp, spx_lsp_t *interp_lsp, int len, int subframe, int nb_subframes) +{ + int i; + float tmp = (1.0f + subframe)/nb_subframes; + for (i=0;i>>= 14;\n\t" + "R3 = R3 + R5;\n\t" + + "R0 = R2;\n\t" /* R0: b0 */ + "R1 = 16384;\n\t" /* R1: b1 */ + "LOOP cpe%= LC0 = %3;\n\t" + "LOOP_BEGIN cpe%=;\n\t" + "P1 = R0;\n\t" + "R0 = R2.L * R0.L (IS) || R5 = W[P0--] (X);\n\t" + "R0 >>>= 13;\n\t" + "R0 = R0 - R1;\n\t" + "R1 = P1;\n\t" + "R5 = R5.L * R0.L (IS);\n\t" + "R5 = R5 + R4;\n\t" + "R5 >>>= 14;\n\t" + "R3 = R3 + R5;\n\t" + "LOOP_END cpe%=;\n\t" + "%0 = R3;\n\t" + : "=&d" (sum) + : "a" (x), "a" (&coef[m]), "a" (m-1) + : "R0", "R1", "R3", "R2", "R4", "R5", "P0", "P1" + ); + return sum; +} +#endif + + + diff --git a/android/app/src/main/jni/libspeex/lsp_tables_nb.c b/android/app/src/main/jni/libspeex/lsp_tables_nb.c new file mode 100644 index 000000000..16f2e1b64 --- /dev/null +++ b/android/app/src/main/jni/libspeex/lsp_tables_nb.c @@ -0,0 +1,360 @@ +/* Copyright (C) 2002 Jean-Marc Valin + File: lsp_tables_nb.c + Codebooks for LSPs in narrowband CELP mode + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are + met: + + 1. Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + 3. The name of the author may not be used to endorse or promote products + derived from this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, + INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + POSSIBILITY OF SUCH DAMAGE. +*/ + +const signed char cdbk_nb[640]={ +30,19,38,34,40,32,46,43,58,43, +5,-18,-25,-40,-33,-55,-52,20,34,28, +-20,-63,-97,-92,61,53,47,49,53,75, +-14,-53,-77,-79,0,-3,-5,19,22,26, +-9,-53,-55,66,90,72,85,68,74,52, +-4,-41,-58,-31,-18,-31,27,32,30,18, +24,3,8,5,-12,-3,26,28,74,63, +-2,-39,-67,-77,-106,-74,59,59,73,65, +44,40,71,72,82,83,98,88,89,60, +-6,-31,-47,-48,-13,-39,-9,7,2,79, +-1,-39,-60,-17,87,81,65,50,45,19, +-21,-67,-91,-87,-41,-50,7,18,39,74, +10,-31,-28,39,24,13,23,5,56,45, +29,10,-5,-13,-11,-35,-18,-8,-10,-8, +-25,-71,-77,-21,2,16,50,63,87,87, +5,-32,-40,-51,-68,0,12,6,54,34, +5,-12,32,52,68,64,69,59,65,45, +14,-16,-31,-40,-65,-67,41,49,47,37, +-11,-52,-75,-84,-4,57,48,42,42,33, +-11,-51,-68,-6,13,0,8,-8,26,32, +-23,-53,0,36,56,76,97,105,111,97, +-1,-28,-39,-40,-43,-54,-44,-40,-18,35, +16,-20,-19,-28,-42,29,47,38,74,45, +3,-29,-48,-62,-80,-104,-33,56,59,59, +10,17,46,72,84,101,117,123,123,106, +-7,-33,-49,-51,-70,-67,-27,-31,70,67, +-16,-62,-85,-20,82,71,86,80,85,74, +-19,-58,-75,-45,-29,-33,-18,-25,45,57, +-12,-42,-5,12,28,36,52,64,81,82, +13,-9,-27,-28,22,3,2,22,26,6, +-6,-44,-51,2,15,10,48,43,49,34, +-19,-62,-84,-89,-102,-24,8,17,61,68, +39,24,23,19,16,-5,12,15,27,15, +-8,-44,-49,-60,-18,-32,-28,52,54,62, +-8,-48,-77,-70,66,101,83,63,61,37, +-12,-50,-75,-64,33,17,13,25,15,77, +1,-42,-29,72,64,46,49,31,61,44, +-8,-47,-54,-46,-30,19,20,-1,-16,0, +16,-12,-18,-9,-26,-27,-10,-22,53,45, +-10,-47,-75,-82,-105,-109,8,25,49,77, +50,65,114,117,124,118,115,96,90,61, +-9,-45,-63,-60,-75,-57,8,11,20,29, +0,-35,-49,-43,40,47,35,40,55,38, +-24,-76,-103,-112,-27,3,23,34,52,75, +8,-29,-43,12,63,38,35,29,24,8, +25,11,1,-15,-18,-43,-7,37,40,21, +-20,-56,-19,-19,-4,-2,11,29,51,63, +-2,-44,-62,-75,-89,30,57,51,74,51, +50,46,68,64,65,52,63,55,65,43, +18,-9,-26,-35,-55,-69,3,6,8,17, +-15,-61,-86,-97,1,86,93,74,78,67, +-1,-38,-66,-48,48,39,29,25,17,-1, +13,13,29,39,50,51,69,82,97,98, +-2,-36,-46,-27,-16,-30,-13,-4,-7,-4, +25,-5,-11,-6,-25,-21,33,12,31,29, +-8,-38,-52,-63,-68,-89,-33,-1,10,74, +-2,-15,59,91,105,105,101,87,84,62, +-7,-33,-50,-35,-54,-47,25,17,82,81, +-13,-56,-83,21,58,31,42,25,72,65, +-24,-66,-91,-56,9,-2,21,10,69,75, +2,-24,11,22,25,28,38,34,48,33, +7,-29,-26,17,15,-1,14,0,-2,0, +-6,-41,-67,6,-2,-9,19,2,85,74, +-22,-67,-84,-71,-50,3,11,-9,2,62}; + +const signed char cdbk_nb_low1[320]={ +-34,-52,-15,45,2, +23,21,52,24,-33, +-9,-1,9,-44,-41, +-13,-17,44,22,-17, +-6,-4,-1,22,38, +26,16,2,50,27, +-35,-34,-9,-41,6, +0,-16,-34,51,8, +-14,-31,-49,15,-33, +45,49,33,-11,-37, +-62,-54,45,11,-5, +-72,11,-1,-12,-11, +24,27,-11,-43,46, +43,33,-12,-9,-1, +1,-4,-23,-57,-71, +11,8,16,17,-8, +-20,-31,-41,53,48, +-16,3,65,-24,-8, +-23,-32,-37,-32,-49, +-10,-17,6,38,5, +-9,-17,-46,8,52, +3,6,45,40,39, +-7,-6,-34,-74,31, +8,1,-16,43,68, +-11,-19,-31,4,6, +0,-6,-17,-16,-38, +-16,-30,2,9,-39, +-16,-1,43,-10,48, +3,3,-16,-31,-3, +62,68,43,13,3, +-10,8,20,-56,12, +12,-2,-18,22,-15, +-40,-36,1,7,41, +0,1,46,-6,-62, +-4,-12,-2,-11,-83, +-13,-2,91,33,-10, +0,4,-11,-16,79, +32,37,14,9,51, +-21,-28,-56,-34,0, +21,9,-26,11,28, +-42,-54,-23,-2,-15, +31,30,8,-39,-66, +-39,-36,31,-28,-40, +-46,35,40,22,24, +33,48,23,-34,14, +40,32,17,27,-3, +25,26,-13,-61,-17, +11,4,31,60,-6, +-26,-41,-64,13,16, +-26,54,31,-11,-23, +-9,-11,-34,-71,-21, +-34,-35,55,50,29, +-22,-27,-50,-38,57, +33,42,57,48,26, +11,0,-49,-31,26, +-4,-14,5,78,37, +17,0,-49,-12,-23, +26,14,2,2,-43, +-17,-12,10,-8,-4, +8,18,12,-6,20, +-12,-6,-13,-25,34, +15,40,49,7,8, +13,20,20,-19,-22, +-2,-8,2,51,-51}; + +const signed char cdbk_nb_low2[320]={ +-6,53,-21,-24,4, +26,17,-4,-37,25, +17,-36,-13,31,3, +-6,27,15,-10,31, +28,26,-10,-10,-40, +16,-7,15,13,41, +-9,0,-4,50,-6, +-7,14,38,22,0, +-48,2,1,-13,-19, +32,-3,-60,11,-17, +-1,-24,-34,-1,35, +-5,-27,28,44,13, +25,15,42,-11,15, +51,35,-36,20,8, +-4,-12,-29,19,-47, +49,-15,-4,16,-29, +-39,14,-30,4,25, +-9,-5,-51,-14,-3, +-40,-32,38,5,-9, +-8,-4,-1,-22,71, +-3,14,26,-18,-22, +24,-41,-25,-24,6, +23,19,-10,39,-26, +-27,65,45,2,-7, +-26,-8,22,-12,16, +15,16,-35,-5,33, +-21,-8,0,23,33, +34,6,21,36,6, +-7,-22,8,-37,-14, +31,38,11,-4,-3, +-39,-32,-8,32,-23, +-6,-12,16,20,-28, +-4,23,13,-52,-1, +22,6,-33,-40,-6, +4,-62,13,5,-26, +35,39,11,2,57, +-11,9,-20,-28,-33, +52,-5,-6,-2,22, +-14,-16,-48,35,1, +-58,20,13,33,-1, +-74,56,-18,-22,-31, +12,6,-14,4,-2, +-9,-47,10,-3,29, +-17,-5,61,14,47, +-12,2,72,-39,-17, +92,64,-53,-51,-15, +-30,-38,-41,-29,-28, +27,9,36,9,-35, +-42,81,-21,20,25, +-16,-5,-17,-35,21, +15,-28,48,2,-2, +9,-19,29,-40,30, +-18,-18,18,-16,-57, +15,-20,-12,-15,-37, +-15,33,-39,21,-22, +-13,35,11,13,-38, +-63,29,23,-27,32, +18,3,-26,42,33, +-64,-66,-17,16,56, +2,36,3,31,21, +-41,-39,8,-57,14, +37,-2,19,-36,-19, +-23,-29,-16,1,-3, +-8,-10,31,64,-65}; + +const signed char cdbk_nb_high1[320]={ +-26,-8,29,21,4, +19,-39,33,-7,-36, +56,54,48,40,29, +-4,-24,-42,-66,-43, +-60,19,-2,37,41, +-10,-37,-60,-64,18, +-22,77,73,40,25, +4,19,-19,-66,-2, +11,5,21,14,26, +-25,-86,-4,18,1, +26,-37,10,37,-1, +24,-12,-59,-11,20, +-6,34,-16,-16,42, +19,-28,-51,53,32, +4,10,62,21,-12, +-34,27,4,-48,-48, +-50,-49,31,-7,-21, +-42,-25,-4,-43,-22, +59,2,27,12,-9, +-6,-16,-8,-32,-58, +-16,-29,-5,41,23, +-30,-33,-46,-13,-10, +-38,52,52,1,-17, +-9,10,26,-25,-6, +33,-20,53,55,25, +-32,-5,-42,23,21, +66,5,-28,20,9, +75,29,-7,-42,-39, +15,3,-23,21,6, +11,1,-29,14,63, +10,54,26,-24,-51, +-49,7,-23,-51,15, +-66,1,60,25,10, +0,-30,-4,-15,17, +19,59,40,4,-5, +33,6,-22,-58,-70, +-5,23,-6,60,44, +-29,-16,-47,-29,52, +-19,50,28,16,35, +31,36,0,-21,6, +21,27,22,42,7, +-66,-40,-8,7,19, +46,0,-4,60,36, +45,-7,-29,-6,-32, +-39,2,6,-9,33, +20,-51,-34,18,-6, +19,6,11,5,-19, +-29,-2,42,-11,-45, +-21,-55,57,37,2, +-14,-67,-16,-27,-38, +69,48,19,2,-17, +20,-20,-16,-34,-17, +-25,-61,10,73,45, +16,-40,-64,-17,-29, +-22,56,17,-39,8, +-11,8,-25,-18,-13, +-19,8,54,57,36, +-17,-26,-4,6,-21, +40,42,-4,20,31, +53,10,-34,-53,31, +-17,35,0,15,-6, +-20,-63,-73,22,25, +29,17,8,-29,-39, +-69,18,15,-15,-5}; + +const signed char cdbk_nb_high2[320]={ +11,47,16,-9,-46, +-32,26,-64,34,-5, +38,-7,47,20,2, +-73,-99,-3,-45,20, +70,-52,15,-6,-7, +-82,31,21,47,51, +39,-3,9,0,-41, +-7,-15,-54,2,0, +27,-31,9,-45,-22, +-38,-24,-24,8,-33, +23,5,50,-36,-17, +-18,-51,-2,13,19, +43,12,-15,-12,61, +38,38,7,13,0, +6,-1,3,62,9, +27,22,-33,38,-35, +-9,30,-43,-9,-32, +-1,4,-4,1,-5, +-11,-8,38,31,11, +-10,-42,-21,-37,1, +43,15,-13,-35,-19, +-18,15,23,-26,59, +1,-21,53,8,-41, +-50,-14,-28,4,21, +25,-28,-40,5,-40, +-41,4,51,-33,-8, +-8,1,17,-60,12, +25,-41,17,34,43, +19,45,7,-37,24, +-15,56,-2,35,-10, +48,4,-47,-2,5, +-5,-54,5,-3,-33, +-10,30,-2,-44,-24, +-38,9,-9,42,4, +6,-56,44,-16,9, +-40,-26,18,-20,10, +28,-41,-21,-4,13, +-18,32,-30,-3,37, +15,22,28,50,-40, +3,-29,-64,7,51, +-19,-11,17,-27,-40, +-64,24,-12,-7,-27, +3,37,48,-1,2, +-9,-38,-34,46,1, +27,-6,19,-13,26, +10,34,20,25,40, +50,-6,-7,30,9, +-24,0,-23,71,-61, +22,58,-34,-4,2, +-49,-33,25,30,-8, +-6,-16,77,2,38, +-8,-35,-6,-30,56, +78,31,33,-20,13, +-39,20,22,4,21, +-8,4,-6,10,-83, +-41,9,-25,-43,15, +-7,-12,-34,-39,-37, +-33,19,30,16,-33, +42,-25,25,-68,44, +-15,-11,-4,23,50, +14,4,-39,-43,20, +-30,60,9,-20,7, +16,19,-33,37,29, +16,-35,7,38,-27}; diff --git a/android/app/src/main/jni/libspeex/ltp.c b/android/app/src/main/jni/libspeex/ltp.c new file mode 100644 index 000000000..0129c95f1 --- /dev/null +++ b/android/app/src/main/jni/libspeex/ltp.c @@ -0,0 +1,839 @@ +/* Copyright (C) 2002-2006 Jean-Marc Valin + File: ltp.c + Long-Term Prediction functions + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + - Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + - Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + - Neither the name of the Xiph.org Foundation nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR + CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include +#include "ltp.h" +#include "stack_alloc.h" +#include "filters.h" +#include +#include "math_approx.h" +#include "os_support.h" + +#ifndef NULL +#define NULL 0 +#endif + + +#ifdef _USE_SSE +#include "ltp_sse.h" +#elif defined (ARM4_ASM) || defined(ARM5E_ASM) +#include "ltp_arm4.h" +#elif defined (BFIN_ASM) +#include "ltp_bfin.h" +#endif + +#ifndef OVERRIDE_INNER_PROD +spx_word32_t inner_prod(const spx_word16_t *x, const spx_word16_t *y, int len) +{ + spx_word32_t sum=0; + len >>= 2; + while(len--) + { + spx_word32_t part=0; + part = MAC16_16(part,*x++,*y++); + part = MAC16_16(part,*x++,*y++); + part = MAC16_16(part,*x++,*y++); + part = MAC16_16(part,*x++,*y++); + /* HINT: If you had a 40-bit accumulator, you could shift only at the end */ + sum = ADD32(sum,SHR32(part,6)); + } + return sum; +} +#endif + +#ifndef OVERRIDE_PITCH_XCORR +#if 0 /* HINT: Enable this for machines with enough registers (i.e. not x86) */ +void pitch_xcorr(const spx_word16_t *_x, const spx_word16_t *_y, spx_word32_t *corr, int len, int nb_pitch, char *stack) +{ + int i,j; + for (i=0;i16383) + { + scaledown=1; + break; + } + } + /* If the weighted input is close to saturation, then we scale it down */ + if (scaledown) + { + for (i=-end;iMULT16_16(best_score[N-1],ADD16(1,ener16[i-start]))) + { + /* We can safely put it last and then check */ + best_score[N-1]=tmp; + best_ener[N-1]=ener16[i-start]+1; + pitch[N-1]=i; + /* Check if it comes in front of others */ + for (j=0;jMULT16_16(best_score[j],ADD16(1,ener16[i-start]))) + { + for (k=N-1;k>j;k--) + { + best_score[k]=best_score[k-1]; + best_ener[k]=best_ener[k-1]; + pitch[k]=pitch[k-1]; + } + best_score[j]=tmp; + best_ener[j]=ener16[i-start]+1; + pitch[j]=i; + break; + } + } + } + } + + /* Compute open-loop gain if necessary */ + if (gain) + { + for (j=0;jbest_sum && gain_sum<=max_gain) { + best_sum=sum; + best_cdbk=i; + } + } + + return best_cdbk; +} +#endif + +/** Finds the best quantized 3-tap pitch predictor by analysis by synthesis */ +static spx_word32_t pitch_gain_search_3tap( +const spx_word16_t target[], /* Target vector */ +const spx_coef_t ak[], /* LPCs for this subframe */ +const spx_coef_t awk1[], /* Weighted LPCs #1 for this subframe */ +const spx_coef_t awk2[], /* Weighted LPCs #2 for this subframe */ +spx_sig_t exc[], /* Excitation */ +const signed char *gain_cdbk, +int gain_cdbk_size, +int pitch, /* Pitch value */ +int p, /* Number of LPC coeffs */ +int nsf, /* Number of samples in subframe */ +SpeexBits *bits, +char *stack, +const spx_word16_t *exc2, +const spx_word16_t *r, +spx_word16_t *new_target, +int *cdbk_index, +int plc_tuning, +spx_word32_t cumul_gain, +int scaledown +) +{ + int i,j; + VARDECL(spx_word16_t *tmp1); + VARDECL(spx_word16_t *e); + spx_word16_t *x[3]; + spx_word32_t corr[3]; + spx_word32_t A[3][3]; + spx_word16_t gain[3]; + spx_word32_t err; + spx_word16_t max_gain=128; + int best_cdbk=0; + + ALLOC(tmp1, 3*nsf, spx_word16_t); + ALLOC(e, nsf, spx_word16_t); + + if (cumul_gain > 262144) + max_gain = 31; + + x[0]=tmp1; + x[1]=tmp1+nsf; + x[2]=tmp1+2*nsf; + + for (j=0;j=0;i--) + { + spx_word16_t e0=exc2[-pitch-1+i]; +#ifdef FIXED_POINT + /* Scale excitation down if needed (avoiding overflow) */ + if (scaledown) + e0 = SHR16(e0,1); +#endif + x[i][0]=MULT16_16_Q14(r[0], e0); + for (j=0;j30) + plc_tuning=30; +#ifdef FIXED_POINT + C[0] = SHL32(C[0],1); + C[1] = SHL32(C[1],1); + C[2] = SHL32(C[2],1); + C[3] = SHL32(C[3],1); + C[4] = SHL32(C[4],1); + C[5] = SHL32(C[5],1); + C[6] = MAC16_32_Q15(C[6],MULT16_16_16(plc_tuning,655),C[6]); + C[7] = MAC16_32_Q15(C[7],MULT16_16_16(plc_tuning,655),C[7]); + C[8] = MAC16_32_Q15(C[8],MULT16_16_16(plc_tuning,655),C[8]); + normalize16(C, C16, 32767, 9); +#else + C[6]*=.5*(1+.02*plc_tuning); + C[7]*=.5*(1+.02*plc_tuning); + C[8]*=.5*(1+.02*plc_tuning); +#endif + + best_cdbk = pitch_gain_search_3tap_vq(gain_cdbk, gain_cdbk_size, C16, max_gain); + +#ifdef FIXED_POINT + gain[0] = ADD16(32,(spx_word16_t)gain_cdbk[best_cdbk*4]); + gain[1] = ADD16(32,(spx_word16_t)gain_cdbk[best_cdbk*4+1]); + gain[2] = ADD16(32,(spx_word16_t)gain_cdbk[best_cdbk*4+2]); + /*printf ("%d %d %d %d\n",gain[0],gain[1],gain[2], best_cdbk);*/ +#else + gain[0] = 0.015625*gain_cdbk[best_cdbk*4] + .5; + gain[1] = 0.015625*gain_cdbk[best_cdbk*4+1]+ .5; + gain[2] = 0.015625*gain_cdbk[best_cdbk*4+2]+ .5; +#endif + *cdbk_index=best_cdbk; + } + + SPEEX_MEMSET(exc, 0, nsf); + for (i=0;i<3;i++) + { + int j; + int tmp1, tmp3; + int pp=pitch+1-i; + tmp1=nsf; + if (tmp1>pp) + tmp1=pp; + for (j=0;jpp+pitch) + tmp3=pp+pitch; + for (j=tmp1;jgain_bits; + gain_cdbk = params->gain_cdbk + 4*gain_cdbk_size*cdbk_offset; + + N=complexity; + if (N>10) + N=10; + if (N<1) + N=1; + + ALLOC(nbest, N, int); + params = (const ltp_params*) par; + + if (endpitch_bits); + speex_bits_pack(bits, 0, params->gain_bits); + SPEEX_MEMSET(exc, 0, nsf); + return start; + } + +#ifdef FIXED_POINT + /* Check if we need to scale everything down in the pitch search to avoid overflows */ + for (i=0;i16383) + { + scaledown=1; + break; + } + } + for (i=-end;i16383) + { + scaledown=1; + break; + } + } +#endif + if (N>end-start+1) + N=end-start+1; + if (end != start) + open_loop_nbest_pitch(sw, start, end, nsf, nbest, NULL, N, stack); + else + nbest[0] = start; + + ALLOC(best_exc, nsf, spx_sig_t); + ALLOC(new_target, nsf, spx_word16_t); + ALLOC(best_target, nsf, spx_word16_t); + + for (i=0;ipitch_bits); + speex_bits_pack(bits, best_gain_index, params->gain_bits); +#ifdef FIXED_POINT + *cumul_gain = MULT16_32_Q13(SHL16(params->gain_cdbk[4*best_gain_index+3],8), MAX32(1024,*cumul_gain)); +#else + *cumul_gain = 0.03125*MAX32(1024,*cumul_gain)*params->gain_cdbk[4*best_gain_index+3]; +#endif + /*printf ("%f\n", cumul_gain);*/ + /*printf ("encode pitch: %d %d\n", best_pitch, best_gain_index);*/ + SPEEX_COPY(exc, best_exc, nsf); + SPEEX_COPY(target, best_target, nsf); +#ifdef FIXED_POINT + /* Scale target back up if needed */ + if (scaledown) + { + for (i=0;igain_bits; + gain_cdbk = params->gain_cdbk + 4*gain_cdbk_size*cdbk_offset; + + pitch = speex_bits_unpack_unsigned(bits, params->pitch_bits); + pitch += start; + gain_index = speex_bits_unpack_unsigned(bits, params->gain_bits); + /*printf ("decode pitch: %d %d\n", pitch, gain_index);*/ +#ifdef FIXED_POINT + gain[0] = ADD16(32,(spx_word16_t)gain_cdbk[gain_index*4]); + gain[1] = ADD16(32,(spx_word16_t)gain_cdbk[gain_index*4+1]); + gain[2] = ADD16(32,(spx_word16_t)gain_cdbk[gain_index*4+2]); +#else + gain[0] = 0.015625*gain_cdbk[gain_index*4]+.5; + gain[1] = 0.015625*gain_cdbk[gain_index*4+1]+.5; + gain[2] = 0.015625*gain_cdbk[gain_index*4+2]+.5; +#endif + + if (count_lost && pitch > subframe_offset) + { + spx_word16_t gain_sum; + if (1) { +#ifdef FIXED_POINT + spx_word16_t tmp = count_lost < 4 ? last_pitch_gain : SHR16(last_pitch_gain,1); + if (tmp>62) + tmp=62; +#else + spx_word16_t tmp = count_lost < 4 ? last_pitch_gain : 0.5 * last_pitch_gain; + if (tmp>.95) + tmp=.95; +#endif + gain_sum = gain_3tap_to_1tap(gain); + + if (gain_sum > tmp) + { + spx_word16_t fact = DIV32_16(SHL32(EXTEND32(tmp),14),gain_sum); + for (i=0;i<3;i++) + gain[i]=MULT16_16_Q14(fact,gain[i]); + } + + } + + } + + *pitch_val = pitch; + gain_val[0]=gain[0]; + gain_val[1]=gain[1]; + gain_val[2]=gain[2]; + gain[0] = SHL16(gain[0],7); + gain[1] = SHL16(gain[1],7); + gain[2] = SHL16(gain[2],7); + SPEEX_MEMSET(exc_out, 0, nsf); + for (i=0;i<3;i++) + { + int j; + int tmp1, tmp3; + int pp=pitch+1-i; + tmp1=nsf; + if (tmp1>pp) + tmp1=pp; + for (j=0;jpp+pitch) + tmp3=pp+pitch; + for (j=tmp1;j63) + pitch_coef=63; +#else + if (pitch_coef>.99) + pitch_coef=.99; +#endif + for (i=0;i63) + pitch_coef=63; +#else + if (pitch_coef>.99) + pitch_coef=.99; +#endif + for (i=0;i +#include "arch.h" + +/** LTP parameters. */ +typedef struct { + const signed char *gain_cdbk; + int gain_bits; + int pitch_bits; +} ltp_params; + +#ifdef FIXED_POINT +#define gain_3tap_to_1tap(g) (ABS(g[1]) + (g[0]>0 ? g[0] : -SHR16(g[0],1)) + (g[2]>0 ? g[2] : -SHR16(g[2],1))) +#else +#define gain_3tap_to_1tap(g) (ABS(g[1]) + (g[0]>0 ? g[0] : -.5*g[0]) + (g[2]>0 ? g[2] : -.5*g[2])) +#endif + +spx_word32_t inner_prod(const spx_word16_t *x, const spx_word16_t *y, int len); +void pitch_xcorr(const spx_word16_t *_x, const spx_word16_t *_y, spx_word32_t *corr, int len, int nb_pitch, char *stack); + +void open_loop_nbest_pitch(spx_word16_t *sw, int start, int end, int len, int *pitch, spx_word16_t *gain, int N, char *stack); + + +/** Finds the best quantized 3-tap pitch predictor by analysis by synthesis */ +int pitch_search_3tap( +spx_word16_t target[], /* Target vector */ +spx_word16_t *sw, +spx_coef_t ak[], /* LPCs for this subframe */ +spx_coef_t awk1[], /* Weighted LPCs #1 for this subframe */ +spx_coef_t awk2[], /* Weighted LPCs #2 for this subframe */ +spx_sig_t exc[], /* Overlapping codebook */ +const void *par, +int start, /* Smallest pitch value allowed */ +int end, /* Largest pitch value allowed */ +spx_word16_t pitch_coef, /* Voicing (pitch) coefficient */ +int p, /* Number of LPC coeffs */ +int nsf, /* Number of samples in subframe */ +SpeexBits *bits, +char *stack, +spx_word16_t *exc2, +spx_word16_t *r, +int complexity, +int cdbk_offset, +int plc_tuning, +spx_word32_t *cumul_gain +); + +/*Unquantize adaptive codebook and update pitch contribution*/ +void pitch_unquant_3tap( +spx_word16_t exc[], /* Input excitation */ +spx_word32_t exc_out[], /* Output excitation */ +int start, /* Smallest pitch value allowed */ +int end, /* Largest pitch value allowed */ +spx_word16_t pitch_coef, /* Voicing (pitch) coefficient */ +const void *par, +int nsf, /* Number of samples in subframe */ +int *pitch_val, +spx_word16_t *gain_val, +SpeexBits *bits, +char *stack, +int lost, +int subframe_offset, +spx_word16_t last_pitch_gain, +int cdbk_offset +); + +/** Forced pitch delay and gain */ +int forced_pitch_quant( +spx_word16_t target[], /* Target vector */ +spx_word16_t *sw, +spx_coef_t ak[], /* LPCs for this subframe */ +spx_coef_t awk1[], /* Weighted LPCs #1 for this subframe */ +spx_coef_t awk2[], /* Weighted LPCs #2 for this subframe */ +spx_sig_t exc[], /* Excitation */ +const void *par, +int start, /* Smallest pitch value allowed */ +int end, /* Largest pitch value allowed */ +spx_word16_t pitch_coef, /* Voicing (pitch) coefficient */ +int p, /* Number of LPC coeffs */ +int nsf, /* Number of samples in subframe */ +SpeexBits *bits, +char *stack, +spx_word16_t *exc2, +spx_word16_t *r, +int complexity, +int cdbk_offset, +int plc_tuning, +spx_word32_t *cumul_gain +); + +/** Unquantize forced pitch delay and gain */ +void forced_pitch_unquant( +spx_word16_t exc[], /* Input excitation */ +spx_word32_t exc_out[], /* Output excitation */ +int start, /* Smallest pitch value allowed */ +int end, /* Largest pitch value allowed */ +spx_word16_t pitch_coef, /* Voicing (pitch) coefficient */ +const void *par, +int nsf, /* Number of samples in subframe */ +int *pitch_val, +spx_word16_t *gain_val, +SpeexBits *bits, +char *stack, +int lost, +int subframe_offset, +spx_word16_t last_pitch_gain, +int cdbk_offset +); diff --git a/android/app/src/main/jni/libspeex/ltp_arm4.h b/android/app/src/main/jni/libspeex/ltp_arm4.h new file mode 100644 index 000000000..cdb94e603 --- /dev/null +++ b/android/app/src/main/jni/libspeex/ltp_arm4.h @@ -0,0 +1,187 @@ +/* Copyright (C) 2004 Jean-Marc Valin */ +/** + @file ltp_arm4.h + @brief Long-Term Prediction functions (ARM4 version) +*/ +/* + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + - Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + - Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + - Neither the name of the Xiph.org Foundation nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR + CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#define OVERRIDE_INNER_PROD +spx_word32_t inner_prod(const spx_word16_t *x, const spx_word16_t *y, int len) +{ + spx_word32_t sum1=0,sum2=0; + spx_word16_t *deadx, *deady; + int deadlen, dead1, dead2, dead3, dead4, dead5, dead6; + __asm__ __volatile__ ( + "\tldrsh %5, [%0], #2 \n" + "\tldrsh %6, [%1], #2 \n" + ".inner_prod_loop%=:\n" + "\tsub %7, %7, %7\n" + "\tsub %10, %10, %10\n" + + "\tldrsh %8, [%0], #2 \n" + "\tldrsh %9, [%1], #2 \n" + "\tmla %7, %5, %6, %7\n" + "\tldrsh %5, [%0], #2 \n" + "\tldrsh %6, [%1], #2 \n" + "\tmla %10, %8, %9, %10\n" + "\tldrsh %8, [%0], #2 \n" + "\tldrsh %9, [%1], #2 \n" + "\tmla %7, %5, %6, %7\n" + "\tldrsh %5, [%0], #2 \n" + "\tldrsh %6, [%1], #2 \n" + "\tmla %10, %8, %9, %10\n" + + "\tldrsh %8, [%0], #2 \n" + "\tldrsh %9, [%1], #2 \n" + "\tmla %7, %5, %6, %7\n" + "\tldrsh %5, [%0], #2 \n" + "\tldrsh %6, [%1], #2 \n" + "\tmla %10, %8, %9, %10\n" + "\tldrsh %8, [%0], #2 \n" + "\tldrsh %9, [%1], #2 \n" + "\tmla %7, %5, %6, %7\n" + "\tldrsh %5, [%0], #2 \n" + "\tldrsh %6, [%1], #2 \n" + "\tmla %10, %8, %9, %10\n" + + "\tsubs %4, %4, #1\n" + "\tadd %2, %2, %7, asr #5\n" + "\tadd %3, %3, %10, asr #5\n" + "\tbne .inner_prod_loop%=\n" + : "=r" (deadx), "=r" (deady), "+r" (sum1), "+r" (sum2), + "=r" (deadlen), "=r" (dead1), "=r" (dead2), "=r" (dead3), + "=r" (dead4), "=r" (dead5), "=r" (dead6) + : "0" (x), "1" (y), "4" (len>>3) + : "cc" + ); + return (sum1+sum2)>>1; +} + +#define OVERRIDE_PITCH_XCORR +void pitch_xcorr(const spx_word16_t *_x, const spx_word16_t *_y, spx_word32_t *corr, int len, int nb_pitch, char *stack) +{ + int i,j; + for (i=0;i>> 6;\n\t" + "R0 = A0;\n\t" + "%0 = R0;\n\t" + : "=m" (sum) + : "m" (x), "m" (y), "d" (len-1) + : "P0", "P1", "P2", "R0", "R1", "A0", "I0", "I1", "L0", "L1", "R3" + ); + return sum; +} + +#define OVERRIDE_PITCH_XCORR +void pitch_xcorr(const spx_word16_t *_x, const spx_word16_t *_y, spx_word32_t *corr, int len, int nb_pitch, char *stack) +{ + corr += nb_pitch - 1; + __asm__ __volatile__ ( + "P2 = %0;\n\t" + "I0 = P2;\n\t" /* x in I0 */ + "B0 = P2;\n\t" /* x in B0 */ + "R0 = %3;\n\t" /* len in R0 */ + "P3 = %3;\n\t" + "P3 += -2;\n\t" /* len in R0 */ + "P4 = %4;\n\t" /* nb_pitch in R0 */ + "R1 = R0 << 1;\n\t" /* number of bytes in x */ + "L0 = R1;\n\t" + "P0 = %1;\n\t" + + "P1 = %2;\n\t" + "B1 = P1;\n\t" + "L1 = 0;\n\t" /*Disable looping on I1*/ + + "r0 = [I0++];\n\t" + "LOOP pitch%= LC0 = P4 >> 1;\n\t" + "LOOP_BEGIN pitch%=;\n\t" + "I1 = P0;\n\t" + "A1 = A0 = 0;\n\t" + "R1 = [I1++];\n\t" + "LOOP inner_prod%= LC1 = P3 >> 1;\n\t" + "LOOP_BEGIN inner_prod%=;\n\t" + "A1 += R0.L*R1.H, A0 += R0.L*R1.L (IS) || R1.L = W[I1++];\n\t" + "A1 += R0.H*R1.L, A0 += R0.H*R1.H (IS) || R1.H = W[I1++] || R0 = [I0++];\n\t" + "LOOP_END inner_prod%=;\n\t" + "A1 += R0.L*R1.H, A0 += R0.L*R1.L (IS) || R1.L = W[I1++];\n\t" + "A1 += R0.H*R1.L, A0 += R0.H*R1.H (IS) || R0 = [I0++];\n\t" + "A0 = A0 >>> 6;\n\t" + "A1 = A1 >>> 6;\n\t" + "R2 = A0, R3 = A1;\n\t" + "[P1--] = r2;\n\t" + "[P1--] = r3;\n\t" + "P0 += 4;\n\t" + "LOOP_END pitch%=;\n\t" + "L0 = 0;\n\t" + : : "m" (_x), "m" (_y), "m" (corr), "m" (len), "m" (nb_pitch) + : "A0", "A1", "P0", "P1", "P2", "P3", "P4", "R0", "R1", "R2", "R3", "I0", "I1", "L0", "L1", "B0", "B1", "memory" + ); +} + +#define OVERRIDE_COMPUTE_PITCH_ERROR +static inline spx_word32_t compute_pitch_error(spx_word16_t *C, spx_word16_t *g, spx_word16_t pitch_control) +{ + spx_word32_t sum; + __asm__ __volatile__ + ( + "A0 = 0;\n\t" + + "R0 = W[%1++];\n\t" + "R1.L = %2.L*%5.L (IS);\n\t" + "A0 += R1.L*R0.L (IS) || R0 = W[%1++];\n\t" + + "R1.L = %3.L*%5.L (IS);\n\t" + "A0 += R1.L*R0.L (IS) || R0 = W[%1++];\n\t" + + "R1.L = %4.L*%5.L (IS);\n\t" + "A0 += R1.L*R0.L (IS) || R0 = W[%1++];\n\t" + + "R1.L = %2.L*%3.L (IS);\n\t" + "A0 -= R1.L*R0.L (IS) || R0 = W[%1++];\n\t" + + "R1.L = %4.L*%3.L (IS);\n\t" + "A0 -= R1.L*R0.L (IS) || R0 = W[%1++];\n\t" + + "R1.L = %4.L*%2.L (IS);\n\t" + "A0 -= R1.L*R0.L (IS) || R0 = W[%1++];\n\t" + + "R1.L = %2.L*%2.L (IS);\n\t" + "A0 -= R1.L*R0.L (IS) || R0 = W[%1++];\n\t" + + "R1.L = %3.L*%3.L (IS);\n\t" + "A0 -= R1.L*R0.L (IS) || R0 = W[%1++];\n\t" + + "R1.L = %4.L*%4.L (IS);\n\t" + "A0 -= R1.L*R0.L (IS);\n\t" + + "%0 = A0;\n\t" + : "=&D" (sum), "=a" (C) + : "d" (g[0]), "d" (g[1]), "d" (g[2]), "d" (pitch_control), "1" (C) + : "R0", "R1", "R2", "A0" + ); + return sum; +} + +#define OVERRIDE_OPEN_LOOP_NBEST_PITCH +#ifdef OVERRIDE_OPEN_LOOP_NBEST_PITCH +void open_loop_nbest_pitch(spx_word16_t *sw, int start, int end, int len, int *pitch, spx_word16_t *gain, int N, char *stack) +{ + int i,j,k; + VARDECL(spx_word32_t *best_score); + VARDECL(spx_word32_t *best_ener); + spx_word32_t e0; + VARDECL(spx_word32_t *corr); + VARDECL(spx_word32_t *energy); + + ALLOC(best_score, N, spx_word32_t); + ALLOC(best_ener, N, spx_word32_t); + ALLOC(corr, end-start+1, spx_word32_t); + ALLOC(energy, end-start+2, spx_word32_t); + + for (i=0;i>>= 6;\n\t" +" R1 = R1 + R2;\n\t" +" R0 >>>= 6;\n\t" +" R1 = R1 - R0;\n\t" +" R2 = MAX(R1,R3);\n\t" +"eu2: [P0++] = R2;\n\t" + : : "d" (energy), "d" (&sw[-start-1]), "d" (&sw[-start+len-1]), + "a" (end-start) + : "P0", "I1", "I2", "R0", "R1", "R2", "R3" +#if (__GNUC__ == 4) + , "LC1" +#endif + ); + + pitch_xcorr(sw, sw-end, corr, len, end-start+1, stack); + + /* FIXME: Fixed-point and floating-point code should be merged */ + { + VARDECL(spx_word16_t *corr16); + VARDECL(spx_word16_t *ener16); + ALLOC(corr16, end-start+1, spx_word16_t); + ALLOC(ener16, end-start+1, spx_word16_t); + /* Normalize to 180 so we can square it and it still fits in 16 bits */ + normalize16(corr, corr16, 180, end-start+1); + normalize16(energy, ener16, 180, end-start+1); + + if (N == 1) { + /* optimised asm to handle N==1 case */ + __asm__ __volatile__ + ( +" I0 = %1;\n\t" /* I0: corr16[] */ +" L0 = 0;\n\t" +" I1 = %2;\n\t" /* I1: energy */ +" L1 = 0;\n\t" +" R2 = -1;\n\t" /* R2: best score */ +" R3 = 0;\n\t" /* R3: best energy */ +" P0 = %4;\n\t" /* P0: best pitch */ +" P1 = %4;\n\t" /* P1: counter */ +" LSETUP (sl1, sl2) LC1 = %3;\n\t" +"sl1: R0.L = W [I0++] || R1.L = W [I1++];\n\t" +" R0 = R0.L * R0.L (IS);\n\t" +" R1 += 1;\n\t" +" R4 = R0.L * R3.L;\n\t" +" R5 = R2.L * R1.L;\n\t" +" cc = R5 < R4;\n\t" +" if cc R2 = R0;\n\t" +" if cc R3 = R1;\n\t" +" if cc P0 = P1;\n\t" +"sl2: P1 += 1;\n\t" +" %0 = P0;\n\t" + : "=&d" (pitch[0]) + : "a" (corr16), "a" (ener16), "a" (end+1-start), "d" (start) + : "P0", "P1", "I0", "I1", "R0", "R1", "R2", "R3", "R4", "R5" +#if (__GNUC__ == 4) + , "LC1" +#endif + ); + + } + else { + for (i=start;i<=end;i++) + { + spx_word16_t tmp = MULT16_16_16(corr16[i-start],corr16[i-start]); + /* Instead of dividing the tmp by the energy, we multiply on the other side */ + if (MULT16_16(tmp,best_ener[N-1])>MULT16_16(best_score[N-1],ADD16(1,ener16[i-start]))) + { + /* We can safely put it last and then check */ + best_score[N-1]=tmp; + best_ener[N-1]=ener16[i-start]+1; + pitch[N-1]=i; + /* Check if it comes in front of others */ + for (j=0;jMULT16_16(best_score[j],ADD16(1,ener16[i-start]))) + { + for (k=N-1;k>j;k--) + { + best_score[k]=best_score[k-1]; + best_ener[k]=best_ener[k-1]; + pitch[k]=pitch[k-1]; + } + best_score[j]=tmp; + best_ener[j]=ener16[i-start]+1; + pitch[j]=i; + break; + } + } + } + } + } + } + + /* Compute open-loop gain */ + if (gain) + { + for (j=0;jbest_sum && gain_sum<=max_gain) ------ (1) + + if (sum>best_sum && !(gain_sum>max_gain)) ------ (2) + + if (max_gain<=gain_sum) { ------ (3) + sum = -VERY_LARGE32; + } + if (best_sum<=sum) + + The blackin cc instructions are all of the form: + + cc = x < y (or cc = x <= y) +*/ +" R1 = B0\n\t" +" R2 = %5\n\t" +" R3 = %6\n\t" +" cc = R2 <= R1;\n\t" +" if cc R0 = R3;\n\t" +" cc = %0 <= R0;\n\t" +" if cc %0 = R0;\n\t" +" if cc %1 = P1;\n\t" + +"pgs2: P1 += 1;\n\t" + + : "=&d" (best_sum), "=&d" (best_cdbk) + : "a" (gain_cdbk), "a" (C16), "a" (gain_cdbk_size), "a" (max_gain), + "b" (-VERY_LARGE32) + : "R0", "R1", "R2", "R3", "R4", "P0", + "P1", "I1", "L1", "A0", "B0" +#if (__GNUC__ == 4) + , "LC1" +#endif + ); + + return best_cdbk; +} +#endif + diff --git a/android/app/src/main/jni/libspeex/ltp_sse.h b/android/app/src/main/jni/libspeex/ltp_sse.h new file mode 100644 index 000000000..bed6eaac9 --- /dev/null +++ b/android/app/src/main/jni/libspeex/ltp_sse.h @@ -0,0 +1,92 @@ +/* Copyright (C) 2002 Jean-Marc Valin */ +/** + @file ltp_sse.h + @brief Long-Term Prediction functions (SSE version) +*/ +/* + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + - Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + - Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + - Neither the name of the Xiph.org Foundation nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR + CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#include + +#define OVERRIDE_INNER_PROD +float inner_prod(const float *a, const float *b, int len) +{ + int i; + float ret; + __m128 sum = _mm_setzero_ps(); + for (i=0;i<(len>>2);i+=2) + { + sum = _mm_add_ps(sum, _mm_mul_ps(_mm_loadu_ps(a+0), _mm_loadu_ps(b+0))); + sum = _mm_add_ps(sum, _mm_mul_ps(_mm_loadu_ps(a+4), _mm_loadu_ps(b+4))); + a += 8; + b += 8; + } + sum = _mm_add_ps(sum, _mm_movehl_ps(sum, sum)); + sum = _mm_add_ss(sum, _mm_shuffle_ps(sum, sum, 0x55)); + _mm_store_ss(&ret, sum); + return ret; +} + +#define OVERRIDE_PITCH_XCORR +void pitch_xcorr(const float *_x, const float *_y, float *corr, int len, int nb_pitch, char *stack) +{ + int i, offset; + VARDECL(__m128 *x); + VARDECL(__m128 *y); + int N, L; + N = len>>2; + L = nb_pitch>>2; + ALLOC(x, N, __m128); + ALLOC(y, N+L, __m128); + for (i=0;i=(spx_int32_t)65536) + { + x >>= 16; + r += 16; + } + if (x>=256) + { + x >>= 8; + r += 8; + } + if (x>=16) + { + x >>= 4; + r += 4; + } + if (x>=4) + { + x >>= 2; + r += 2; + } + if (x>=2) + { + r += 1; + } + return r; +} + +static inline spx_int16_t spx_ilog4(spx_uint32_t x) +{ + int r=0; + if (x>=(spx_int32_t)65536) + { + x >>= 16; + r += 8; + } + if (x>=256) + { + x >>= 8; + r += 4; + } + if (x>=16) + { + x >>= 4; + r += 2; + } + if (x>=4) + { + r += 1; + } + return r; +} + +#ifdef FIXED_POINT + +/** Generate a pseudo-random number */ +static inline spx_word16_t speex_rand(spx_word16_t std, spx_int32_t *seed) +{ + spx_word32_t res; + *seed = 1664525 * *seed + 1013904223; + res = MULT16_16(EXTRACT16(SHR32(*seed,16)),std); + return EXTRACT16(PSHR32(SUB32(res, SHR32(res, 3)),14)); +} + +/* sqrt(x) ~= 0.22178 + 1.29227*x - 0.77070*x^2 + 0.25723*x^3 (for .25 < x < 1) */ +/*#define C0 3634 +#define C1 21173 +#define C2 -12627 +#define C3 4215*/ + +/* sqrt(x) ~= 0.22178 + 1.29227*x - 0.77070*x^2 + 0.25659*x^3 (for .25 < x < 1) */ +#define C0 3634 +#define C1 21173 +#define C2 -12627 +#define C3 4204 + +static inline spx_word16_t spx_sqrt(spx_word32_t x) +{ + int k; + spx_word32_t rt; + k = spx_ilog4(x)-6; + x = VSHR32(x, (k<<1)); + rt = ADD16(C0, MULT16_16_Q14(x, ADD16(C1, MULT16_16_Q14(x, ADD16(C2, MULT16_16_Q14(x, (C3))))))); + rt = VSHR32(rt,7-k); + return rt; +} + +/* log(x) ~= -2.18151 + 4.20592*x - 2.88938*x^2 + 0.86535*x^3 (for .5 < x < 1) */ + + +#define A1 16469 +#define A2 2242 +#define A3 1486 + +static inline spx_word16_t spx_acos(spx_word16_t x) +{ + int s=0; + spx_word16_t ret; + spx_word16_t sq; + if (x<0) + { + s=1; + x = NEG16(x); + } + x = SUB16(16384,x); + + x = x >> 1; + sq = MULT16_16_Q13(x, ADD16(A1, MULT16_16_Q13(x, ADD16(A2, MULT16_16_Q13(x, (A3)))))); + ret = spx_sqrt(SHL32(EXTEND32(sq),13)); + + /*ret = spx_sqrt(67108864*(-1.6129e-04 + 2.0104e+00*f + 2.7373e-01*f*f + 1.8136e-01*f*f*f));*/ + if (s) + ret = SUB16(25736,ret); + return ret; +} + + +#define K1 8192 +#define K2 -4096 +#define K3 340 +#define K4 -10 + +static inline spx_word16_t spx_cos(spx_word16_t x) +{ + spx_word16_t x2; + + if (x<12868) + { + x2 = MULT16_16_P13(x,x); + return ADD32(K1, MULT16_16_P13(x2, ADD32(K2, MULT16_16_P13(x2, ADD32(K3, MULT16_16_P13(K4, x2)))))); + } else { + x = SUB16(25736,x); + x2 = MULT16_16_P13(x,x); + return SUB32(-K1, MULT16_16_P13(x2, ADD32(K2, MULT16_16_P13(x2, ADD32(K3, MULT16_16_P13(K4, x2)))))); + } +} + +#define L1 32767 +#define L2 -7651 +#define L3 8277 +#define L4 -626 + +static inline spx_word16_t _spx_cos_pi_2(spx_word16_t x) +{ + spx_word16_t x2; + + x2 = MULT16_16_P15(x,x); + return ADD16(1,MIN16(32766,ADD32(SUB16(L1,x2), MULT16_16_P15(x2, ADD32(L2, MULT16_16_P15(x2, ADD32(L3, MULT16_16_P15(L4, x2)))))))); +} + +static inline spx_word16_t spx_cos_norm(spx_word32_t x) +{ + x = x&0x0001ffff; + if (x>SHL32(EXTEND32(1), 16)) + x = SUB32(SHL32(EXTEND32(1), 17),x); + if (x&0x00007fff) + { + if (x14) + return 0x7fffffff; + else if (integer < -15) + return 0; + frac = SHL16(x-SHL16(integer,11),3); + frac = ADD16(D0, MULT16_16_Q14(frac, ADD16(D1, MULT16_16_Q14(frac, ADD16(D2 , MULT16_16_Q14(D3,frac)))))); + return VSHR32(EXTEND32(frac), -integer-2); +} + +/* Input in Q11 format, output in Q16 */ +static inline spx_word32_t spx_exp(spx_word16_t x) +{ + if (x>21290) + return 0x7fffffff; + else if (x<-21290) + return 0; + else + return spx_exp2(MULT16_16_P14(23637,x)); +} +#define M1 32767 +#define M2 -21 +#define M3 -11943 +#define M4 4936 + +static inline spx_word16_t spx_atan01(spx_word16_t x) +{ + return MULT16_16_P15(x, ADD32(M1, MULT16_16_P15(x, ADD32(M2, MULT16_16_P15(x, ADD32(M3, MULT16_16_P15(M4, x))))))); +} + +#undef M1 +#undef M2 +#undef M3 +#undef M4 + +/* Input in Q15, output in Q14 */ +static inline spx_word16_t spx_atan(spx_word32_t x) +{ + if (x <= 32767) + { + return SHR16(spx_atan01(x),1); + } else { + int e = spx_ilog2(x); + if (e>=29) + return 25736; + x = DIV32_16(SHL32(EXTEND32(32767),29-e), EXTRACT16(SHR32(x, e-14))); + return SUB16(25736, SHR16(spx_atan01(x),1)); + } +} +#else + +#ifndef M_PI +#define M_PI 3.14159265358979323846 /* pi */ +#endif + +#define C1 0.9999932946f +#define C2 -0.4999124376f +#define C3 0.0414877472f +#define C4 -0.0012712095f + + +#define SPX_PI_2 1.5707963268 +static inline spx_word16_t spx_cos(spx_word16_t x) +{ + if (x 32766 ? 32767 : (x))) +#else +#define WORD2INT(x) ((x) < -32767.5f ? -32768 : ((x) > 32766.5f ? 32767 : floor(.5+(x)))) +#endif + +/* If enabled, the AEC will use a foreground filter and a background filter to be more robust to double-talk + and difficult signals in general. The cost is an extra FFT and a matrix-vector multiply */ +#define TWO_PATH + +#ifdef FIXED_POINT +static const spx_float_t MIN_LEAK = {20972, -22}; + +/* Constants for the two-path filter */ +static const spx_float_t VAR1_SMOOTH = {23593, -16}; +static const spx_float_t VAR2_SMOOTH = {23675, -15}; +static const spx_float_t VAR1_UPDATE = {16384, -15}; +static const spx_float_t VAR2_UPDATE = {16384, -16}; +static const spx_float_t VAR_BACKTRACK = {16384, -12}; +#define TOP16(x) ((x)>>16) + +#else + +static const spx_float_t MIN_LEAK = .005f; + +/* Constants for the two-path filter */ +static const spx_float_t VAR1_SMOOTH = .36f; +static const spx_float_t VAR2_SMOOTH = .7225f; +static const spx_float_t VAR1_UPDATE = .5f; +static const spx_float_t VAR2_UPDATE = .25f; +static const spx_float_t VAR_BACKTRACK = 4.f; +#define TOP16(x) (x) +#endif + + +#define PLAYBACK_DELAY 2 + +void speex_echo_get_residual(SpeexEchoState *st, spx_word32_t *Yout, int len); + + +/** Speex echo cancellation state. */ +struct SpeexEchoState_ { + int frame_size; /**< Number of samples processed each time */ + int window_size; + int M; + int cancel_count; + int adapted; + int saturated; + int screwed_up; + int C; /** Number of input channels (microphones) */ + int K; /** Number of output channels (loudspeakers) */ + spx_int32_t sampling_rate; + spx_word16_t spec_average; + spx_word16_t beta0; + spx_word16_t beta_max; + spx_word32_t sum_adapt; + spx_word16_t leak_estimate; + + spx_word16_t *e; /* scratch */ + spx_word16_t *x; /* Far-end input buffer (2N) */ + spx_word16_t *X; /* Far-end buffer (M+1 frames) in frequency domain */ + spx_word16_t *input; /* scratch */ + spx_word16_t *y; /* scratch */ + spx_word16_t *last_y; + spx_word16_t *Y; /* scratch */ + spx_word16_t *E; + spx_word32_t *PHI; /* scratch */ + spx_word32_t *W; /* (Background) filter weights */ +#ifdef TWO_PATH + spx_word16_t *foreground; /* Foreground filter weights */ + spx_word32_t Davg1; /* 1st recursive average of the residual power difference */ + spx_word32_t Davg2; /* 2nd recursive average of the residual power difference */ + spx_float_t Dvar1; /* Estimated variance of 1st estimator */ + spx_float_t Dvar2; /* Estimated variance of 2nd estimator */ +#endif + spx_word32_t *power; /* Power of the far-end signal */ + spx_float_t *power_1;/* Inverse power of far-end */ + spx_word16_t *wtmp; /* scratch */ +#ifdef FIXED_POINT + spx_word16_t *wtmp2; /* scratch */ +#endif + spx_word32_t *Rf; /* scratch */ + spx_word32_t *Yf; /* scratch */ + spx_word32_t *Xf; /* scratch */ + spx_word32_t *Eh; + spx_word32_t *Yh; + spx_float_t Pey; + spx_float_t Pyy; + spx_word16_t *window; + spx_word16_t *prop; + void *fft_table; + spx_word16_t *memX, *memD, *memE; + spx_word16_t preemph; + spx_word16_t notch_radius; + spx_mem_t *notch_mem; + + /* NOTE: If you only use speex_echo_cancel() and want to save some memory, remove this */ + spx_int16_t *play_buf; + int play_buf_pos; + int play_buf_started; +}; + +static inline void filter_dc_notch16(const spx_int16_t *in, spx_word16_t radius, spx_word16_t *out, int len, spx_mem_t *mem, int stride) +{ + int i; + spx_word16_t den2; +#ifdef FIXED_POINT + den2 = MULT16_16_Q15(radius,radius) + MULT16_16_Q15(QCONST16(.7,15),MULT16_16_Q15(32767-radius,32767-radius)); +#else + den2 = radius*radius + .7*(1-radius)*(1-radius); +#endif + /*printf ("%d %d %d %d %d %d\n", num[0], num[1], num[2], den[0], den[1], den[2]);*/ + for (i=0;i>= 1; + while(len--) + { + spx_word32_t part=0; + part = MAC16_16(part,*x++,*y++); + part = MAC16_16(part,*x++,*y++); + /* HINT: If you had a 40-bit accumulator, you could shift only at the end */ + sum = ADD32(sum,SHR32(part,6)); + } + return sum; +} + +/** Compute power spectrum of a half-complex (packed) vector */ +static inline void power_spectrum(const spx_word16_t *X, spx_word32_t *ps, int N) +{ + int i, j; + ps[0]=MULT16_16(X[0],X[0]); + for (i=1,j=1;i max_sum) + max_sum = prop[i]; + } + for (i=0;i +static FILE *rFile=NULL, *pFile=NULL, *oFile=NULL; + +static void dump_audio(const spx_int16_t *rec, const spx_int16_t *play, const spx_int16_t *out, int len) +{ + if (!(rFile && pFile && oFile)) + { + speex_fatal("Dump files not open"); + } + fwrite(rec, sizeof(spx_int16_t), len, rFile); + fwrite(play, sizeof(spx_int16_t), len, pFile); + fwrite(out, sizeof(spx_int16_t), len, oFile); +} +#endif + +/** Creates a new echo canceller state */ +EXPORT SpeexEchoState *speex_echo_state_init(int frame_size, int filter_length) +{ + return speex_echo_state_init_mc(frame_size, filter_length, 1, 1); +} + +EXPORT SpeexEchoState *speex_echo_state_init_mc(int frame_size, int filter_length, int nb_mic, int nb_speakers) +{ + int i,N,M, C, K; + SpeexEchoState *st = (SpeexEchoState *)speex_alloc(sizeof(SpeexEchoState)); + + st->K = nb_speakers; + st->C = nb_mic; + C=st->C; + K=st->K; +#ifdef DUMP_ECHO_CANCEL_DATA + if (rFile || pFile || oFile) + speex_fatal("Opening dump files twice"); + rFile = fopen("aec_rec.sw", "wb"); + pFile = fopen("aec_play.sw", "wb"); + oFile = fopen("aec_out.sw", "wb"); +#endif + + st->frame_size = frame_size; + st->window_size = 2*frame_size; + N = st->window_size; + M = st->M = (filter_length+st->frame_size-1)/frame_size; + st->cancel_count=0; + st->sum_adapt = 0; + st->saturated = 0; + st->screwed_up = 0; + /* This is the default sampling rate */ + st->sampling_rate = 8000; + st->spec_average = DIV32_16(SHL32(EXTEND32(st->frame_size), 15), st->sampling_rate); +#ifdef FIXED_POINT + st->beta0 = DIV32_16(SHL32(EXTEND32(st->frame_size), 16), st->sampling_rate); + st->beta_max = DIV32_16(SHL32(EXTEND32(st->frame_size), 14), st->sampling_rate); +#else + st->beta0 = (2.0f*st->frame_size)/st->sampling_rate; + st->beta_max = (.5f*st->frame_size)/st->sampling_rate; +#endif + st->leak_estimate = 0; + + st->fft_table = spx_fft_init(N); + + st->e = (spx_word16_t*)speex_alloc(C*N*sizeof(spx_word16_t)); + st->x = (spx_word16_t*)speex_alloc(K*N*sizeof(spx_word16_t)); + st->input = (spx_word16_t*)speex_alloc(C*st->frame_size*sizeof(spx_word16_t)); + st->y = (spx_word16_t*)speex_alloc(C*N*sizeof(spx_word16_t)); + st->last_y = (spx_word16_t*)speex_alloc(C*N*sizeof(spx_word16_t)); + st->Yf = (spx_word32_t*)speex_alloc((st->frame_size+1)*sizeof(spx_word32_t)); + st->Rf = (spx_word32_t*)speex_alloc((st->frame_size+1)*sizeof(spx_word32_t)); + st->Xf = (spx_word32_t*)speex_alloc((st->frame_size+1)*sizeof(spx_word32_t)); + st->Yh = (spx_word32_t*)speex_alloc((st->frame_size+1)*sizeof(spx_word32_t)); + st->Eh = (spx_word32_t*)speex_alloc((st->frame_size+1)*sizeof(spx_word32_t)); + + st->X = (spx_word16_t*)speex_alloc(K*(M+1)*N*sizeof(spx_word16_t)); + st->Y = (spx_word16_t*)speex_alloc(C*N*sizeof(spx_word16_t)); + st->E = (spx_word16_t*)speex_alloc(C*N*sizeof(spx_word16_t)); + st->W = (spx_word32_t*)speex_alloc(C*K*M*N*sizeof(spx_word32_t)); +#ifdef TWO_PATH + st->foreground = (spx_word16_t*)speex_alloc(M*N*C*K*sizeof(spx_word16_t)); +#endif + st->PHI = (spx_word32_t*)speex_alloc(N*sizeof(spx_word32_t)); + st->power = (spx_word32_t*)speex_alloc((frame_size+1)*sizeof(spx_word32_t)); + st->power_1 = (spx_float_t*)speex_alloc((frame_size+1)*sizeof(spx_float_t)); + st->window = (spx_word16_t*)speex_alloc(N*sizeof(spx_word16_t)); + st->prop = (spx_word16_t*)speex_alloc(M*sizeof(spx_word16_t)); + st->wtmp = (spx_word16_t*)speex_alloc(N*sizeof(spx_word16_t)); +#ifdef FIXED_POINT + st->wtmp2 = (spx_word16_t*)speex_alloc(N*sizeof(spx_word16_t)); + for (i=0;i>1;i++) + { + st->window[i] = (16383-SHL16(spx_cos(DIV32_16(MULT16_16(25736,i<<1),N)),1)); + st->window[N-i-1] = st->window[i]; + } +#else + for (i=0;iwindow[i] = .5-.5*cos(2*M_PI*i/N); +#endif + for (i=0;i<=st->frame_size;i++) + st->power_1[i] = FLOAT_ONE; + for (i=0;iW[i] = 0; + { + spx_word32_t sum = 0; + /* Ratio of ~10 between adaptation rate of first and last block */ + spx_word16_t decay = SHR32(spx_exp(NEG16(DIV32_16(QCONST16(2.4,11),M))),1); + st->prop[0] = QCONST16(.7, 15); + sum = EXTEND32(st->prop[0]); + for (i=1;iprop[i] = MULT16_16_Q15(st->prop[i-1], decay); + sum = ADD32(sum, EXTEND32(st->prop[i])); + } + for (i=M-1;i>=0;i--) + { + st->prop[i] = DIV32(MULT16_16(QCONST16(.8f,15), st->prop[i]),sum); + } + } + + st->memX = (spx_word16_t*)speex_alloc(K*sizeof(spx_word16_t)); + st->memD = (spx_word16_t*)speex_alloc(C*sizeof(spx_word16_t)); + st->memE = (spx_word16_t*)speex_alloc(C*sizeof(spx_word16_t)); + st->preemph = QCONST16(.9,15); + if (st->sampling_rate<12000) + st->notch_radius = QCONST16(.9, 15); + else if (st->sampling_rate<24000) + st->notch_radius = QCONST16(.982, 15); + else + st->notch_radius = QCONST16(.992, 15); + + st->notch_mem = (spx_mem_t*)speex_alloc(2*C*sizeof(spx_mem_t)); + st->adapted = 0; + st->Pey = st->Pyy = FLOAT_ONE; + +#ifdef TWO_PATH + st->Davg1 = st->Davg2 = 0; + st->Dvar1 = st->Dvar2 = FLOAT_ZERO; +#endif + + st->play_buf = (spx_int16_t*)speex_alloc(K*(PLAYBACK_DELAY+1)*st->frame_size*sizeof(spx_int16_t)); + st->play_buf_pos = PLAYBACK_DELAY*st->frame_size; + st->play_buf_started = 0; + + return st; +} + +/** Resets echo canceller state */ +EXPORT void speex_echo_state_reset(SpeexEchoState *st) +{ + int i, M, N, C, K; + st->cancel_count=0; + st->screwed_up = 0; + N = st->window_size; + M = st->M; + C=st->C; + K=st->K; + for (i=0;iW[i] = 0; +#ifdef TWO_PATH + for (i=0;iforeground[i] = 0; +#endif + for (i=0;iX[i] = 0; + for (i=0;i<=st->frame_size;i++) + { + st->power[i] = 0; + st->power_1[i] = FLOAT_ONE; + st->Eh[i] = 0; + st->Yh[i] = 0; + } + for (i=0;iframe_size;i++) + { + st->last_y[i] = 0; + } + for (i=0;iE[i] = 0; + } + for (i=0;ix[i] = 0; + } + for (i=0;i<2*C;i++) + st->notch_mem[i] = 0; + for (i=0;imemD[i]=st->memE[i]=0; + for (i=0;imemX[i]=0; + + st->saturated = 0; + st->adapted = 0; + st->sum_adapt = 0; + st->Pey = st->Pyy = FLOAT_ONE; +#ifdef TWO_PATH + st->Davg1 = st->Davg2 = 0; + st->Dvar1 = st->Dvar2 = FLOAT_ZERO; +#endif + for (i=0;i<3*st->frame_size;i++) + st->play_buf[i] = 0; + st->play_buf_pos = PLAYBACK_DELAY*st->frame_size; + st->play_buf_started = 0; + +} + +/** Destroys an echo canceller state */ +EXPORT void speex_echo_state_destroy(SpeexEchoState *st) +{ + spx_fft_destroy(st->fft_table); + + speex_free(st->e); + speex_free(st->x); + speex_free(st->input); + speex_free(st->y); + speex_free(st->last_y); + speex_free(st->Yf); + speex_free(st->Rf); + speex_free(st->Xf); + speex_free(st->Yh); + speex_free(st->Eh); + + speex_free(st->X); + speex_free(st->Y); + speex_free(st->E); + speex_free(st->W); +#ifdef TWO_PATH + speex_free(st->foreground); +#endif + speex_free(st->PHI); + speex_free(st->power); + speex_free(st->power_1); + speex_free(st->window); + speex_free(st->prop); + speex_free(st->wtmp); +#ifdef FIXED_POINT + speex_free(st->wtmp2); +#endif + speex_free(st->memX); + speex_free(st->memD); + speex_free(st->memE); + speex_free(st->notch_mem); + + speex_free(st->play_buf); + speex_free(st); + +#ifdef DUMP_ECHO_CANCEL_DATA + fclose(rFile); + fclose(pFile); + fclose(oFile); + rFile = pFile = oFile = NULL; +#endif +} + +EXPORT void speex_echo_capture(SpeexEchoState *st, const spx_int16_t *rec, spx_int16_t *out) +{ + int i; + /*speex_warning_int("capture with fill level ", st->play_buf_pos/st->frame_size);*/ + st->play_buf_started = 1; + if (st->play_buf_pos>=st->frame_size) + { + speex_echo_cancellation(st, rec, st->play_buf, out); + st->play_buf_pos -= st->frame_size; + for (i=0;iplay_buf_pos;i++) + st->play_buf[i] = st->play_buf[i+st->frame_size]; + } else { + speex_warning("No playback frame available (your application is buggy and/or got xruns)"); + if (st->play_buf_pos!=0) + { + speex_warning("internal playback buffer corruption?"); + st->play_buf_pos = 0; + } + for (i=0;iframe_size;i++) + out[i] = rec[i]; + } +} + +EXPORT void speex_echo_playback(SpeexEchoState *st, const spx_int16_t *play) +{ + /*speex_warning_int("playback with fill level ", st->play_buf_pos/st->frame_size);*/ + if (!st->play_buf_started) + { + speex_warning("discarded first playback frame"); + return; + } + if (st->play_buf_pos<=PLAYBACK_DELAY*st->frame_size) + { + int i; + for (i=0;iframe_size;i++) + st->play_buf[st->play_buf_pos+i] = play[i]; + st->play_buf_pos += st->frame_size; + if (st->play_buf_pos <= (PLAYBACK_DELAY-1)*st->frame_size) + { + speex_warning("Auto-filling the buffer (your application is buggy and/or got xruns)"); + for (i=0;iframe_size;i++) + st->play_buf[st->play_buf_pos+i] = play[i]; + st->play_buf_pos += st->frame_size; + } + } else { + speex_warning("Had to discard a playback frame (your application is buggy and/or got xruns)"); + } +} + +/** Performs echo cancellation on a frame (deprecated, last arg now ignored) */ +EXPORT void speex_echo_cancel(SpeexEchoState *st, const spx_int16_t *in, const spx_int16_t *far_end, spx_int16_t *out, spx_int32_t *Yout) +{ + speex_echo_cancellation(st, in, far_end, out); +} + +/** Performs echo cancellation on a frame */ +EXPORT void speex_echo_cancellation(SpeexEchoState *st, const spx_int16_t *in, const spx_int16_t *far_end, spx_int16_t *out) +{ + int i,j, chan, speak; + int N,M, C, K; + spx_word32_t Syy,See,Sxx,Sdd, Sff; +#ifdef TWO_PATH + spx_word32_t Dbf; + int update_foreground; +#endif + spx_word32_t Sey; + spx_word16_t ss, ss_1; + spx_float_t Pey = FLOAT_ONE, Pyy=FLOAT_ONE; + spx_float_t alpha, alpha_1; + spx_word16_t RER; + spx_word32_t tmp32; + + N = st->window_size; + M = st->M; + C = st->C; + K = st->K; + + st->cancel_count++; +#ifdef FIXED_POINT + ss=DIV32_16(11469,M); + ss_1 = SUB16(32767,ss); +#else + ss=.35/M; + ss_1 = 1-ss; +#endif + + for (chan = 0; chan < C; chan++) + { + /* Apply a notch filter to make sure DC doesn't end up causing problems */ + filter_dc_notch16(in+chan, st->notch_radius, st->input+chan*st->frame_size, st->frame_size, st->notch_mem+2*chan, C); + /* Copy input data to buffer and apply pre-emphasis */ + /* Copy input data to buffer */ + for (i=0;iframe_size;i++) + { + spx_word32_t tmp32; + /* FIXME: This core has changed a bit, need to merge properly */ + tmp32 = SUB32(EXTEND32(st->input[chan*st->frame_size+i]), EXTEND32(MULT16_16_P15(st->preemph, st->memD[chan]))); +#ifdef FIXED_POINT + if (tmp32 > 32767) + { + tmp32 = 32767; + if (st->saturated == 0) + st->saturated = 1; + } + if (tmp32 < -32767) + { + tmp32 = -32767; + if (st->saturated == 0) + st->saturated = 1; + } +#endif + st->memD[chan] = st->input[chan*st->frame_size+i]; + st->input[chan*st->frame_size+i] = EXTRACT16(tmp32); + } + } + + for (speak = 0; speak < K; speak++) + { + for (i=0;iframe_size;i++) + { + spx_word32_t tmp32; + st->x[speak*N+i] = st->x[speak*N+i+st->frame_size]; + tmp32 = SUB32(EXTEND32(far_end[i*K+speak]), EXTEND32(MULT16_16_P15(st->preemph, st->memX[speak]))); +#ifdef FIXED_POINT + /*FIXME: If saturation occurs here, we need to freeze adaptation for M frames (not just one) */ + if (tmp32 > 32767) + { + tmp32 = 32767; + st->saturated = M+1; + } + if (tmp32 < -32767) + { + tmp32 = -32767; + st->saturated = M+1; + } +#endif + st->x[speak*N+i+st->frame_size] = EXTRACT16(tmp32); + st->memX[speak] = far_end[i*K+speak]; + } + } + + for (speak = 0; speak < K; speak++) + { + /* Shift memory: this could be optimized eventually*/ + for (j=M-1;j>=0;j--) + { + for (i=0;iX[(j+1)*N*K+speak*N+i] = st->X[j*N*K+speak*N+i]; + } + /* Convert x (echo input) to frequency domain */ + spx_fft(st->fft_table, st->x+speak*N, &st->X[speak*N]); + } + + Sxx = 0; + for (speak = 0; speak < K; speak++) + { + Sxx += mdf_inner_prod(st->x+speak*N+st->frame_size, st->x+speak*N+st->frame_size, st->frame_size); + power_spectrum_accum(st->X+speak*N, st->Xf, N); + } + + Sff = 0; + for (chan = 0; chan < C; chan++) + { +#ifdef TWO_PATH + /* Compute foreground filter */ + spectral_mul_accum16(st->X, st->foreground+chan*N*K*M, st->Y+chan*N, N, M*K); + spx_ifft(st->fft_table, st->Y+chan*N, st->e+chan*N); + for (i=0;iframe_size;i++) + st->e[chan*N+i] = SUB16(st->input[chan*st->frame_size+i], st->e[chan*N+i+st->frame_size]); + Sff += mdf_inner_prod(st->e+chan*N, st->e+chan*N, st->frame_size); +#endif + } + + /* Adjust proportional adaption rate */ + /* FIXME: Adjust that for C, K*/ + if (st->adapted) + mdf_adjust_prop (st->W, N, M, C*K, st->prop); + /* Compute weight gradient */ + if (st->saturated == 0) + { + for (chan = 0; chan < C; chan++) + { + for (speak = 0; speak < K; speak++) + { + for (j=M-1;j>=0;j--) + { + weighted_spectral_mul_conj(st->power_1, FLOAT_SHL(PSEUDOFLOAT(st->prop[j]),-15), &st->X[(j+1)*N*K+speak*N], st->E+chan*N, st->PHI, N); + for (i=0;iW[chan*N*K*M + j*N*K + speak*N + i] += st->PHI[i]; + } + } + } + } else { + st->saturated--; + } + + /* FIXME: MC conversion required */ + /* Update weight to prevent circular convolution (MDF / AUMDF) */ + for (chan = 0; chan < C; chan++) + { + for (speak = 0; speak < K; speak++) + { + for (j=0;jcancel_count%(M-1) == j-1) + { +#ifdef FIXED_POINT + for (i=0;iwtmp2[i] = EXTRACT16(PSHR32(st->W[chan*N*K*M + j*N*K + speak*N + i],NORMALIZE_SCALEDOWN+16)); + spx_ifft(st->fft_table, st->wtmp2, st->wtmp); + for (i=0;iframe_size;i++) + { + st->wtmp[i]=0; + } + for (i=st->frame_size;iwtmp[i]=SHL16(st->wtmp[i],NORMALIZE_SCALEUP); + } + spx_fft(st->fft_table, st->wtmp, st->wtmp2); + /* The "-1" in the shift is a sort of kludge that trades less efficient update speed for decrease noise */ + for (i=0;iW[chan*N*K*M + j*N*K + speak*N + i] -= SHL32(EXTEND32(st->wtmp2[i]),16+NORMALIZE_SCALEDOWN-NORMALIZE_SCALEUP-1); +#else + spx_ifft(st->fft_table, &st->W[chan*N*K*M + j*N*K + speak*N], st->wtmp); + for (i=st->frame_size;iwtmp[i]=0; + } + spx_fft(st->fft_table, st->wtmp, &st->W[chan*N*K*M + j*N*K + speak*N]); +#endif + } + } + } + } + + /* So we can use power_spectrum_accum */ + for (i=0;i<=st->frame_size;i++) + st->Rf[i] = st->Yf[i] = st->Xf[i] = 0; + + Dbf = 0; + See = 0; +#ifdef TWO_PATH + /* Difference in response, this is used to estimate the variance of our residual power estimate */ + for (chan = 0; chan < C; chan++) + { + spectral_mul_accum(st->X, st->W+chan*N*K*M, st->Y+chan*N, N, M*K); + spx_ifft(st->fft_table, st->Y+chan*N, st->y+chan*N); + for (i=0;iframe_size;i++) + st->e[chan*N+i] = SUB16(st->e[chan*N+i+st->frame_size], st->y[chan*N+i+st->frame_size]); + Dbf += 10+mdf_inner_prod(st->e+chan*N, st->e+chan*N, st->frame_size); + for (i=0;iframe_size;i++) + st->e[chan*N+i] = SUB16(st->input[chan*st->frame_size+i], st->y[chan*N+i+st->frame_size]); + See += mdf_inner_prod(st->e+chan*N, st->e+chan*N, st->frame_size); + } +#endif + +#ifndef TWO_PATH + Sff = See; +#endif + +#ifdef TWO_PATH + /* Logic for updating the foreground filter */ + + /* For two time windows, compute the mean of the energy difference, as well as the variance */ + st->Davg1 = ADD32(MULT16_32_Q15(QCONST16(.6f,15),st->Davg1), MULT16_32_Q15(QCONST16(.4f,15),SUB32(Sff,See))); + st->Davg2 = ADD32(MULT16_32_Q15(QCONST16(.85f,15),st->Davg2), MULT16_32_Q15(QCONST16(.15f,15),SUB32(Sff,See))); + st->Dvar1 = FLOAT_ADD(FLOAT_MULT(VAR1_SMOOTH, st->Dvar1), FLOAT_MUL32U(MULT16_32_Q15(QCONST16(.4f,15),Sff), MULT16_32_Q15(QCONST16(.4f,15),Dbf))); + st->Dvar2 = FLOAT_ADD(FLOAT_MULT(VAR2_SMOOTH, st->Dvar2), FLOAT_MUL32U(MULT16_32_Q15(QCONST16(.15f,15),Sff), MULT16_32_Q15(QCONST16(.15f,15),Dbf))); + + /* Equivalent float code: + st->Davg1 = .6*st->Davg1 + .4*(Sff-See); + st->Davg2 = .85*st->Davg2 + .15*(Sff-See); + st->Dvar1 = .36*st->Dvar1 + .16*Sff*Dbf; + st->Dvar2 = .7225*st->Dvar2 + .0225*Sff*Dbf; + */ + + update_foreground = 0; + /* Check if we have a statistically significant reduction in the residual echo */ + /* Note that this is *not* Gaussian, so we need to be careful about the longer tail */ + if (FLOAT_GT(FLOAT_MUL32U(SUB32(Sff,See),ABS32(SUB32(Sff,See))), FLOAT_MUL32U(Sff,Dbf))) + update_foreground = 1; + else if (FLOAT_GT(FLOAT_MUL32U(st->Davg1, ABS32(st->Davg1)), FLOAT_MULT(VAR1_UPDATE,(st->Dvar1)))) + update_foreground = 1; + else if (FLOAT_GT(FLOAT_MUL32U(st->Davg2, ABS32(st->Davg2)), FLOAT_MULT(VAR2_UPDATE,(st->Dvar2)))) + update_foreground = 1; + + /* Do we update? */ + if (update_foreground) + { + st->Davg1 = st->Davg2 = 0; + st->Dvar1 = st->Dvar2 = FLOAT_ZERO; + /* Copy background filter to foreground filter */ + for (i=0;iforeground[i] = EXTRACT16(PSHR32(st->W[i],16)); + /* Apply a smooth transition so as to not introduce blocking artifacts */ + for (chan = 0; chan < C; chan++) + for (i=0;iframe_size;i++) + st->e[chan*N+i+st->frame_size] = MULT16_16_Q15(st->window[i+st->frame_size],st->e[chan*N+i+st->frame_size]) + MULT16_16_Q15(st->window[i],st->y[chan*N+i+st->frame_size]); + } else { + int reset_background=0; + /* Otherwise, check if the background filter is significantly worse */ + if (FLOAT_GT(FLOAT_MUL32U(NEG32(SUB32(Sff,See)),ABS32(SUB32(Sff,See))), FLOAT_MULT(VAR_BACKTRACK,FLOAT_MUL32U(Sff,Dbf)))) + reset_background = 1; + if (FLOAT_GT(FLOAT_MUL32U(NEG32(st->Davg1), ABS32(st->Davg1)), FLOAT_MULT(VAR_BACKTRACK,st->Dvar1))) + reset_background = 1; + if (FLOAT_GT(FLOAT_MUL32U(NEG32(st->Davg2), ABS32(st->Davg2)), FLOAT_MULT(VAR_BACKTRACK,st->Dvar2))) + reset_background = 1; + if (reset_background) + { + /* Copy foreground filter to background filter */ + for (i=0;iW[i] = SHL32(EXTEND32(st->foreground[i]),16); + /* We also need to copy the output so as to get correct adaptation */ + for (chan = 0; chan < C; chan++) + { + for (i=0;iframe_size;i++) + st->y[chan*N+i+st->frame_size] = st->e[chan*N+i+st->frame_size]; + for (i=0;iframe_size;i++) + st->e[chan*N+i] = SUB16(st->input[chan*st->frame_size+i], st->y[chan*N+i+st->frame_size]); + } + See = Sff; + st->Davg1 = st->Davg2 = 0; + st->Dvar1 = st->Dvar2 = FLOAT_ZERO; + } + } +#endif + + Sey = Syy = Sdd = 0; + for (chan = 0; chan < C; chan++) + { + /* Compute error signal (for the output with de-emphasis) */ + for (i=0;iframe_size;i++) + { + spx_word32_t tmp_out; +#ifdef TWO_PATH + tmp_out = SUB32(EXTEND32(st->input[chan*st->frame_size+i]), EXTEND32(st->e[chan*N+i+st->frame_size])); +#else + tmp_out = SUB32(EXTEND32(st->input[chan*st->frame_size+i]), EXTEND32(st->y[chan*N+i+st->frame_size])); +#endif + tmp_out = ADD32(tmp_out, EXTEND32(MULT16_16_P15(st->preemph, st->memE[chan]))); + /* This is an arbitrary test for saturation in the microphone signal */ + if (in[i*C+chan] <= -32000 || in[i*C+chan] >= 32000) + { + if (st->saturated == 0) + st->saturated = 1; + } + out[i*C+chan] = WORD2INT(tmp_out); + st->memE[chan] = tmp_out; + } + +#ifdef DUMP_ECHO_CANCEL_DATA + dump_audio(in, far_end, out, st->frame_size); +#endif + + /* Compute error signal (filter update version) */ + for (i=0;iframe_size;i++) + { + st->e[chan*N+i+st->frame_size] = st->e[chan*N+i]; + st->e[chan*N+i] = 0; + } + + /* Compute a bunch of correlations */ + /* FIXME: bad merge */ + Sey += mdf_inner_prod(st->e+chan*N+st->frame_size, st->y+chan*N+st->frame_size, st->frame_size); + Syy += mdf_inner_prod(st->y+chan*N+st->frame_size, st->y+chan*N+st->frame_size, st->frame_size); + Sdd += mdf_inner_prod(st->input+chan*st->frame_size, st->input+chan*st->frame_size, st->frame_size); + + /* Convert error to frequency domain */ + spx_fft(st->fft_table, st->e+chan*N, st->E+chan*N); + for (i=0;iframe_size;i++) + st->y[i+chan*N] = 0; + spx_fft(st->fft_table, st->y+chan*N, st->Y+chan*N); + + /* Compute power spectrum of echo (X), error (E) and filter response (Y) */ + power_spectrum_accum(st->E+chan*N, st->Rf, N); + power_spectrum_accum(st->Y+chan*N, st->Yf, N); + + } + + /*printf ("%f %f %f %f\n", Sff, See, Syy, Sdd, st->update_cond);*/ + + /* Do some sanity check */ + if (!(Syy>=0 && Sxx>=0 && See >= 0) +#ifndef FIXED_POINT + || !(Sff < N*1e9 && Syy < N*1e9 && Sxx < N*1e9) +#endif + ) + { + /* Things have gone really bad */ + st->screwed_up += 50; + for (i=0;iframe_size*C;i++) + out[i] = 0; + } else if (SHR32(Sff, 2) > ADD32(Sdd, SHR32(MULT16_16(N, 10000),6))) + { + /* AEC seems to add lots of echo instead of removing it, let's see if it will improve */ + st->screwed_up++; + } else { + /* Everything's fine */ + st->screwed_up=0; + } + if (st->screwed_up>=50) + { + speex_warning("The echo canceller started acting funny and got slapped (reset). It swears it will behave now."); + speex_echo_state_reset(st); + return; + } + + /* Add a small noise floor to make sure not to have problems when dividing */ + See = MAX32(See, SHR32(MULT16_16(N, 100),6)); + + for (speak = 0; speak < K; speak++) + { + Sxx += mdf_inner_prod(st->x+speak*N+st->frame_size, st->x+speak*N+st->frame_size, st->frame_size); + power_spectrum_accum(st->X+speak*N, st->Xf, N); + } + + + /* Smooth far end energy estimate over time */ + for (j=0;j<=st->frame_size;j++) + st->power[j] = MULT16_32_Q15(ss_1,st->power[j]) + 1 + MULT16_32_Q15(ss,st->Xf[j]); + + /* Compute filtered spectra and (cross-)correlations */ + for (j=st->frame_size;j>=0;j--) + { + spx_float_t Eh, Yh; + Eh = PSEUDOFLOAT(st->Rf[j] - st->Eh[j]); + Yh = PSEUDOFLOAT(st->Yf[j] - st->Yh[j]); + Pey = FLOAT_ADD(Pey,FLOAT_MULT(Eh,Yh)); + Pyy = FLOAT_ADD(Pyy,FLOAT_MULT(Yh,Yh)); +#ifdef FIXED_POINT + st->Eh[j] = MAC16_32_Q15(MULT16_32_Q15(SUB16(32767,st->spec_average),st->Eh[j]), st->spec_average, st->Rf[j]); + st->Yh[j] = MAC16_32_Q15(MULT16_32_Q15(SUB16(32767,st->spec_average),st->Yh[j]), st->spec_average, st->Yf[j]); +#else + st->Eh[j] = (1-st->spec_average)*st->Eh[j] + st->spec_average*st->Rf[j]; + st->Yh[j] = (1-st->spec_average)*st->Yh[j] + st->spec_average*st->Yf[j]; +#endif + } + + Pyy = FLOAT_SQRT(Pyy); + Pey = FLOAT_DIVU(Pey,Pyy); + + /* Compute correlation updatete rate */ + tmp32 = MULT16_32_Q15(st->beta0,Syy); + if (tmp32 > MULT16_32_Q15(st->beta_max,See)) + tmp32 = MULT16_32_Q15(st->beta_max,See); + alpha = FLOAT_DIV32(tmp32, See); + alpha_1 = FLOAT_SUB(FLOAT_ONE, alpha); + /* Update correlations (recursive average) */ + st->Pey = FLOAT_ADD(FLOAT_MULT(alpha_1,st->Pey) , FLOAT_MULT(alpha,Pey)); + st->Pyy = FLOAT_ADD(FLOAT_MULT(alpha_1,st->Pyy) , FLOAT_MULT(alpha,Pyy)); + if (FLOAT_LT(st->Pyy, FLOAT_ONE)) + st->Pyy = FLOAT_ONE; + /* We don't really hope to get better than 33 dB (MIN_LEAK-3dB) attenuation anyway */ + if (FLOAT_LT(st->Pey, FLOAT_MULT(MIN_LEAK,st->Pyy))) + st->Pey = FLOAT_MULT(MIN_LEAK,st->Pyy); + if (FLOAT_GT(st->Pey, st->Pyy)) + st->Pey = st->Pyy; + /* leak_estimate is the linear regression result */ + st->leak_estimate = FLOAT_EXTRACT16(FLOAT_SHL(FLOAT_DIVU(st->Pey, st->Pyy),14)); + /* This looks like a stupid bug, but it's right (because we convert from Q14 to Q15) */ + if (st->leak_estimate > 16383) + st->leak_estimate = 32767; + else + st->leak_estimate = SHL16(st->leak_estimate,1); + /*printf ("%f\n", st->leak_estimate);*/ + + /* Compute Residual to Error Ratio */ +#ifdef FIXED_POINT + tmp32 = MULT16_32_Q15(st->leak_estimate,Syy); + tmp32 = ADD32(SHR32(Sxx,13), ADD32(tmp32, SHL32(tmp32,1))); + /* Check for y in e (lower bound on RER) */ + { + spx_float_t bound = PSEUDOFLOAT(Sey); + bound = FLOAT_DIVU(FLOAT_MULT(bound, bound), PSEUDOFLOAT(ADD32(1,Syy))); + if (FLOAT_GT(bound, PSEUDOFLOAT(See))) + tmp32 = See; + else if (tmp32 < FLOAT_EXTRACT32(bound)) + tmp32 = FLOAT_EXTRACT32(bound); + } + if (tmp32 > SHR32(See,1)) + tmp32 = SHR32(See,1); + RER = FLOAT_EXTRACT16(FLOAT_SHL(FLOAT_DIV32(tmp32,See),15)); +#else + RER = (.0001*Sxx + 3.*MULT16_32_Q15(st->leak_estimate,Syy)) / See; + /* Check for y in e (lower bound on RER) */ + if (RER < Sey*Sey/(1+See*Syy)) + RER = Sey*Sey/(1+See*Syy); + if (RER > .5) + RER = .5; +#endif + + /* We consider that the filter has had minimal adaptation if the following is true*/ + if (!st->adapted && st->sum_adapt > SHL32(EXTEND32(M),15) && MULT16_32_Q15(st->leak_estimate,Syy) > MULT16_32_Q15(QCONST16(.03f,15),Syy)) + { + st->adapted = 1; + } + + if (st->adapted) + { + /* Normal learning rate calculation once we're past the minimal adaptation phase */ + for (i=0;i<=st->frame_size;i++) + { + spx_word32_t r, e; + /* Compute frequency-domain adaptation mask */ + r = MULT16_32_Q15(st->leak_estimate,SHL32(st->Yf[i],3)); + e = SHL32(st->Rf[i],3)+1; +#ifdef FIXED_POINT + if (r>SHR32(e,1)) + r = SHR32(e,1); +#else + if (r>.5*e) + r = .5*e; +#endif + r = MULT16_32_Q15(QCONST16(.7,15),r) + MULT16_32_Q15(QCONST16(.3,15),(spx_word32_t)(MULT16_32_Q15(RER,e))); + /*st->power_1[i] = adapt_rate*r/(e*(1+st->power[i]));*/ + st->power_1[i] = FLOAT_SHL(FLOAT_DIV32_FLOAT(r,FLOAT_MUL32U(e,st->power[i]+10)),WEIGHT_SHIFT+16); + } + } else { + /* Temporary adaption rate if filter is not yet adapted enough */ + spx_word16_t adapt_rate=0; + + if (Sxx > SHR32(MULT16_16(N, 1000),6)) + { + tmp32 = MULT16_32_Q15(QCONST16(.25f, 15), Sxx); +#ifdef FIXED_POINT + if (tmp32 > SHR32(See,2)) + tmp32 = SHR32(See,2); +#else + if (tmp32 > .25*See) + tmp32 = .25*See; +#endif + adapt_rate = FLOAT_EXTRACT16(FLOAT_SHL(FLOAT_DIV32(tmp32, See),15)); + } + for (i=0;i<=st->frame_size;i++) + st->power_1[i] = FLOAT_SHL(FLOAT_DIV32(EXTEND32(adapt_rate),ADD32(st->power[i],10)),WEIGHT_SHIFT+1); + + + /* How much have we adapted so far? */ + st->sum_adapt = ADD32(st->sum_adapt,adapt_rate); + } + + /* FIXME: MC conversion required */ + for (i=0;iframe_size;i++) + st->last_y[i] = st->last_y[st->frame_size+i]; + if (st->adapted) + { + /* If the filter is adapted, take the filtered echo */ + for (i=0;iframe_size;i++) + st->last_y[st->frame_size+i] = in[i]-out[i]; + } else { + /* If filter isn't adapted yet, all we can do is take the far end signal directly */ + /* moved earlier: for (i=0;ilast_y[i] = st->x[i];*/ + } + +} + +/* Compute spectrum of estimated echo for use in an echo post-filter */ +void speex_echo_get_residual(SpeexEchoState *st, spx_word32_t *residual_echo, int len) +{ + int i; + spx_word16_t leak2; + int N; + + N = st->window_size; + + /* Apply hanning window (should pre-compute it)*/ + for (i=0;iy[i] = MULT16_16_Q15(st->window[i],st->last_y[i]); + + /* Compute power spectrum of the echo */ + spx_fft(st->fft_table, st->y, st->Y); + power_spectrum(st->Y, residual_echo, N); + +#ifdef FIXED_POINT + if (st->leak_estimate > 16383) + leak2 = 32767; + else + leak2 = SHL16(st->leak_estimate, 1); +#else + if (st->leak_estimate>.5) + leak2 = 1; + else + leak2 = 2*st->leak_estimate; +#endif + /* Estimate residual echo */ + for (i=0;i<=st->frame_size;i++) + residual_echo[i] = (spx_int32_t)MULT16_32_Q15(leak2,residual_echo[i]); + +} + +EXPORT int speex_echo_ctl(SpeexEchoState *st, int request, void *ptr) +{ + switch(request) + { + + case SPEEX_ECHO_GET_FRAME_SIZE: + (*(int*)ptr) = st->frame_size; + break; + case SPEEX_ECHO_SET_SAMPLING_RATE: + st->sampling_rate = (*(int*)ptr); + st->spec_average = DIV32_16(SHL32(EXTEND32(st->frame_size), 15), st->sampling_rate); +#ifdef FIXED_POINT + st->beta0 = DIV32_16(SHL32(EXTEND32(st->frame_size), 16), st->sampling_rate); + st->beta_max = DIV32_16(SHL32(EXTEND32(st->frame_size), 14), st->sampling_rate); +#else + st->beta0 = (2.0f*st->frame_size)/st->sampling_rate; + st->beta_max = (.5f*st->frame_size)/st->sampling_rate; +#endif + if (st->sampling_rate<12000) + st->notch_radius = QCONST16(.9, 15); + else if (st->sampling_rate<24000) + st->notch_radius = QCONST16(.982, 15); + else + st->notch_radius = QCONST16(.992, 15); + break; + case SPEEX_ECHO_GET_SAMPLING_RATE: + (*(int*)ptr) = st->sampling_rate; + break; + case SPEEX_ECHO_GET_IMPULSE_RESPONSE_SIZE: + /*FIXME: Implement this for multiple channels */ + *((spx_int32_t *)ptr) = st->M * st->frame_size; + break; + case SPEEX_ECHO_GET_IMPULSE_RESPONSE: + { + int M = st->M, N = st->window_size, n = st->frame_size, i, j; + spx_int32_t *filt = (spx_int32_t *) ptr; + for(j=0;jwtmp2[i] = EXTRACT16(PSHR32(st->W[j*N+i],16+NORMALIZE_SCALEDOWN)); + spx_ifft(st->fft_table, st->wtmp2, st->wtmp); +#else + spx_ifft(st->fft_table, &st->W[j*N], st->wtmp); +#endif + for(i=0;iwtmp[i]), WEIGHT_SHIFT-NORMALIZE_SCALEDOWN); + } + } + break; + default: + speex_warning_int("Unknown speex_echo_ctl request: ", request); + return -1; + } + return 0; +} diff --git a/android/app/src/main/jni/libspeex/misc_bfin.h b/android/app/src/main/jni/libspeex/misc_bfin.h new file mode 100644 index 000000000..77b082c05 --- /dev/null +++ b/android/app/src/main/jni/libspeex/misc_bfin.h @@ -0,0 +1,54 @@ +/* Copyright (C) 2005 Analog Devices */ +/** + @file misc_bfin.h + @author Jean-Marc Valin + @brief Various compatibility routines for Speex (Blackfin version) +*/ +/* + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + - Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + - Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + - Neither the name of the Xiph.org Foundation nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR + CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#define OVERRIDE_SPEEX_MOVE +void *speex_move (void *dest, void *src, int n) +{ + __asm__ __volatile__ + ( + "L0 = 0;\n\t" + "I0 = %0;\n\t" + "R0 = [I0++];\n\t" + "LOOP move%= LC0 = %2;\n\t" + "LOOP_BEGIN move%=;\n\t" + "[%1++] = R0 || R0 = [I0++];\n\t" + "LOOP_END move%=;\n\t" + "[%1++] = R0;\n\t" + : "=a" (src), "=a" (dest) + : "a" ((n>>2)-1), "0" (src), "1" (dest) + : "R0", "I0", "L0", "memory" + ); + return dest; +} diff --git a/android/app/src/main/jni/libspeex/modes.c b/android/app/src/main/jni/libspeex/modes.c new file mode 100644 index 000000000..e10a32e8e --- /dev/null +++ b/android/app/src/main/jni/libspeex/modes.c @@ -0,0 +1,366 @@ +/* Copyright (C) 2002-2006 Jean-Marc Valin + File: modes.c + + Describes the different modes of the codec + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + - Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + - Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + - Neither the name of the Xiph.org Foundation nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR + CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +*/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "modes.h" +#include "ltp.h" +#include "quant_lsp.h" +#include "cb_search.h" +#include "sb_celp.h" +#include "nb_celp.h" +#include "vbr.h" +#include "arch.h" +#include + +#ifndef NULL +#define NULL 0 +#endif + + +/* Extern declarations for all codebooks we use here */ +extern const signed char gain_cdbk_nb[]; +extern const signed char gain_cdbk_lbr[]; +extern const signed char exc_5_256_table[]; +extern const signed char exc_5_64_table[]; +extern const signed char exc_8_128_table[]; +extern const signed char exc_10_32_table[]; +extern const signed char exc_10_16_table[]; +extern const signed char exc_20_32_table[]; + + +/* Parameters for Long-Term Prediction (LTP)*/ +static const ltp_params ltp_params_nb = { + gain_cdbk_nb, + 7, + 7 +}; + +/* Parameters for Long-Term Prediction (LTP)*/ +static const ltp_params ltp_params_vlbr = { + gain_cdbk_lbr, + 5, + 0 +}; + +/* Parameters for Long-Term Prediction (LTP)*/ +static const ltp_params ltp_params_lbr = { + gain_cdbk_lbr, + 5, + 7 +}; + +/* Parameters for Long-Term Prediction (LTP)*/ +static const ltp_params ltp_params_med = { + gain_cdbk_lbr, + 5, + 7 +}; + +/* Split-VQ innovation parameters for very low bit-rate narrowband */ +static const split_cb_params split_cb_nb_vlbr = { + 10, /*subvect_size*/ + 4, /*nb_subvect*/ + exc_10_16_table, /*shape_cb*/ + 4, /*shape_bits*/ + 0, +}; + +/* Split-VQ innovation parameters for very low bit-rate narrowband */ +static const split_cb_params split_cb_nb_ulbr = { + 20, /*subvect_size*/ + 2, /*nb_subvect*/ + exc_20_32_table, /*shape_cb*/ + 5, /*shape_bits*/ + 0, +}; + +/* Split-VQ innovation parameters for low bit-rate narrowband */ +static const split_cb_params split_cb_nb_lbr = { + 10, /*subvect_size*/ + 4, /*nb_subvect*/ + exc_10_32_table, /*shape_cb*/ + 5, /*shape_bits*/ + 0, +}; + + +/* Split-VQ innovation parameters narrowband */ +static const split_cb_params split_cb_nb = { + 5, /*subvect_size*/ + 8, /*nb_subvect*/ + exc_5_64_table, /*shape_cb*/ + 6, /*shape_bits*/ + 0, +}; + +/* Split-VQ innovation parameters narrowband */ +static const split_cb_params split_cb_nb_med = { + 8, /*subvect_size*/ + 5, /*nb_subvect*/ + exc_8_128_table, /*shape_cb*/ + 7, /*shape_bits*/ + 0, +}; + +/* Split-VQ innovation for low-band wideband */ +static const split_cb_params split_cb_sb = { + 5, /*subvect_size*/ + 8, /*nb_subvect*/ + exc_5_256_table, /*shape_cb*/ + 8, /*shape_bits*/ + 0, +}; + + + +/* 2150 bps "vocoder-like" mode for comfort noise */ +static const SpeexSubmode nb_submode1 = { + 0, + 1, + 0, + 0, + /* LSP quantization */ + lsp_quant_lbr, + lsp_unquant_lbr, + /* No pitch quantization */ + forced_pitch_quant, + forced_pitch_unquant, + NULL, + /* No innovation quantization (noise only) */ + noise_codebook_quant, + noise_codebook_unquant, + NULL, + -1, + 43 +}; + +/* 3.95 kbps very low bit-rate mode */ +static const SpeexSubmode nb_submode8 = { + 0, + 1, + 0, + 0, + /*LSP quantization*/ + lsp_quant_lbr, + lsp_unquant_lbr, + /*No pitch quantization*/ + forced_pitch_quant, + forced_pitch_unquant, + NULL, + /*Innovation quantization*/ + split_cb_search_shape_sign, + split_cb_shape_sign_unquant, + &split_cb_nb_ulbr, + QCONST16(.5,15), + 79 +}; + +/* 5.95 kbps very low bit-rate mode */ +static const SpeexSubmode nb_submode2 = { + 0, + 0, + 0, + 0, + /*LSP quantization*/ + lsp_quant_lbr, + lsp_unquant_lbr, + /*No pitch quantization*/ + pitch_search_3tap, + pitch_unquant_3tap, + <p_params_vlbr, + /*Innovation quantization*/ + split_cb_search_shape_sign, + split_cb_shape_sign_unquant, + &split_cb_nb_vlbr, + QCONST16(.6,15), + 119 +}; + +/* 8 kbps low bit-rate mode */ +static const SpeexSubmode nb_submode3 = { + -1, + 0, + 1, + 0, + /*LSP quantization*/ + lsp_quant_lbr, + lsp_unquant_lbr, + /*Pitch quantization*/ + pitch_search_3tap, + pitch_unquant_3tap, + <p_params_lbr, + /*Innovation quantization*/ + split_cb_search_shape_sign, + split_cb_shape_sign_unquant, + &split_cb_nb_lbr, + QCONST16(.55,15), + 160 +}; + +/* 11 kbps medium bit-rate mode */ +static const SpeexSubmode nb_submode4 = { + -1, + 0, + 1, + 0, + /*LSP quantization*/ + lsp_quant_lbr, + lsp_unquant_lbr, + /*Pitch quantization*/ + pitch_search_3tap, + pitch_unquant_3tap, + <p_params_med, + /*Innovation quantization*/ + split_cb_search_shape_sign, + split_cb_shape_sign_unquant, + &split_cb_nb_med, + QCONST16(.45,15), + 220 +}; + +/* 15 kbps high bit-rate mode */ +static const SpeexSubmode nb_submode5 = { + -1, + 0, + 3, + 0, + /*LSP quantization*/ + lsp_quant_nb, + lsp_unquant_nb, + /*Pitch quantization*/ + pitch_search_3tap, + pitch_unquant_3tap, + <p_params_nb, + /*Innovation quantization*/ + split_cb_search_shape_sign, + split_cb_shape_sign_unquant, + &split_cb_nb, + QCONST16(.3,15), + 300 +}; + +/* 18.2 high bit-rate mode */ +static const SpeexSubmode nb_submode6 = { + -1, + 0, + 3, + 0, + /*LSP quantization*/ + lsp_quant_nb, + lsp_unquant_nb, + /*Pitch quantization*/ + pitch_search_3tap, + pitch_unquant_3tap, + <p_params_nb, + /*Innovation quantization*/ + split_cb_search_shape_sign, + split_cb_shape_sign_unquant, + &split_cb_sb, + QCONST16(.2,15), + 364 +}; + +/* 24.6 kbps high bit-rate mode */ +static const SpeexSubmode nb_submode7 = { + -1, + 0, + 3, + 1, + /*LSP quantization*/ + lsp_quant_nb, + lsp_unquant_nb, + /*Pitch quantization*/ + pitch_search_3tap, + pitch_unquant_3tap, + <p_params_nb, + /*Innovation quantization*/ + split_cb_search_shape_sign, + split_cb_shape_sign_unquant, + &split_cb_nb, + QCONST16(.1,15), + 492 +}; + + +/* Default mode for narrowband */ +static const SpeexNBMode nb_mode = { + 160, /*frameSize*/ + 40, /*subframeSize*/ + 10, /*lpcSize*/ + 17, /*pitchStart*/ + 144, /*pitchEnd*/ +#ifdef FIXED_POINT + 29491, 19661, /* gamma1, gamma2 */ +#else + 0.9, 0.6, /* gamma1, gamma2 */ +#endif + QCONST16(.0002,15), /*lpc_floor*/ + {NULL, &nb_submode1, &nb_submode2, &nb_submode3, &nb_submode4, &nb_submode5, &nb_submode6, &nb_submode7, + &nb_submode8, NULL, NULL, NULL, NULL, NULL, NULL, NULL}, + 5, + {1, 8, 2, 3, 3, 4, 4, 5, 5, 6, 7} +}; + + +/* Default mode for narrowband */ +EXPORT const SpeexMode speex_nb_mode = { + &nb_mode, + nb_mode_query, + "narrowband", + 0, + 4, + &nb_encoder_init, + &nb_encoder_destroy, + &nb_encode, + &nb_decoder_init, + &nb_decoder_destroy, + &nb_decode, + &nb_encoder_ctl, + &nb_decoder_ctl, +}; + + + +EXPORT int speex_mode_query(const SpeexMode *mode, int request, void *ptr) +{ + return mode->query(mode->mode, request, ptr); +} + +#ifdef FIXED_DEBUG +long long spx_mips=0; +#endif + diff --git a/android/app/src/main/jni/libspeex/modes.h b/android/app/src/main/jni/libspeex/modes.h new file mode 100644 index 000000000..26e2d8618 --- /dev/null +++ b/android/app/src/main/jni/libspeex/modes.h @@ -0,0 +1,161 @@ +/* Copyright (C) 2002-2006 Jean-Marc Valin */ +/** + @file modes.h + @brief Describes the different modes of the codec +*/ +/* + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + - Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + - Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + - Neither the name of the Xiph.org Foundation nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR + CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +*/ + +#ifndef MODES_H +#define MODES_H + +#include +#include +#include "arch.h" + +#define NB_SUBMODES 16 +#define NB_SUBMODE_BITS 4 + +#define SB_SUBMODES 8 +#define SB_SUBMODE_BITS 3 + +/* Used internally, NOT TO BE USED in applications */ +/** Used internally*/ +#define SPEEX_GET_PI_GAIN 100 +/** Used internally*/ +#define SPEEX_GET_EXC 101 +/** Used internally*/ +#define SPEEX_GET_INNOV 102 +/** Used internally*/ +#define SPEEX_GET_DTX_STATUS 103 +/** Used internally*/ +#define SPEEX_SET_INNOVATION_SAVE 104 +/** Used internally*/ +#define SPEEX_SET_WIDEBAND 105 + +/** Used internally*/ +#define SPEEX_GET_STACK 106 + + +/** Quantizes LSPs */ +typedef void (*lsp_quant_func)(spx_lsp_t *, spx_lsp_t *, int, SpeexBits *); + +/** Decodes quantized LSPs */ +typedef void (*lsp_unquant_func)(spx_lsp_t *, int, SpeexBits *); + + +/** Long-term predictor quantization */ +typedef int (*ltp_quant_func)(spx_word16_t *, spx_word16_t *, spx_coef_t *, spx_coef_t *, + spx_coef_t *, spx_sig_t *, const void *, int, int, spx_word16_t, + int, int, SpeexBits*, char *, spx_word16_t *, spx_word16_t *, int, int, int, spx_word32_t *); + +/** Long-term un-quantize */ +typedef void (*ltp_unquant_func)(spx_word16_t *, spx_word32_t *, int, int, spx_word16_t, const void *, int, int *, + spx_word16_t *, SpeexBits*, char*, int, int, spx_word16_t, int); + + +/** Innovation quantization function */ +typedef void (*innovation_quant_func)(spx_word16_t *, spx_coef_t *, spx_coef_t *, spx_coef_t *, const void *, int, int, + spx_sig_t *, spx_word16_t *, SpeexBits *, char *, int, int); + +/** Innovation unquantization function */ +typedef void (*innovation_unquant_func)(spx_sig_t *, const void *, int, SpeexBits*, char *, spx_int32_t *); + +/** Description of a Speex sub-mode (wither narrowband or wideband */ +typedef struct SpeexSubmode { + int lbr_pitch; /**< Set to -1 for "normal" modes, otherwise encode pitch using a global pitch and allowing a +- lbr_pitch variation (for low not-rates)*/ + int forced_pitch_gain; /**< Use the same (forced) pitch gain for all sub-frames */ + int have_subframe_gain; /**< Number of bits to use as sub-frame innovation gain */ + int double_codebook; /**< Apply innovation quantization twice for higher quality (and higher bit-rate)*/ + /*LSP functions*/ + lsp_quant_func lsp_quant; /**< LSP quantization function */ + lsp_unquant_func lsp_unquant; /**< LSP unquantization function */ + + /*Long-term predictor functions*/ + ltp_quant_func ltp_quant; /**< Long-term predictor (pitch) quantizer */ + ltp_unquant_func ltp_unquant; /**< Long-term predictor (pitch) un-quantizer */ + const void *ltp_params; /**< Pitch parameters (options) */ + + /*Quantization of innovation*/ + innovation_quant_func innovation_quant; /**< Innovation quantization */ + innovation_unquant_func innovation_unquant; /**< Innovation un-quantization */ + const void *innovation_params; /**< Innovation quantization parameters*/ + + spx_word16_t comb_gain; /**< Gain of enhancer comb filter */ + + int bits_per_frame; /**< Number of bits per frame after encoding*/ +} SpeexSubmode; + +/** Struct defining the encoding/decoding mode*/ +typedef struct SpeexNBMode { + int frameSize; /**< Size of frames used for encoding */ + int subframeSize; /**< Size of sub-frames used for encoding */ + int lpcSize; /**< Order of LPC filter */ + int pitchStart; /**< Smallest pitch value allowed */ + int pitchEnd; /**< Largest pitch value allowed */ + + spx_word16_t gamma1; /**< Perceptual filter parameter #1 */ + spx_word16_t gamma2; /**< Perceptual filter parameter #2 */ + spx_word16_t lpc_floor; /**< Noise floor for LPC analysis */ + + const SpeexSubmode *submodes[NB_SUBMODES]; /**< Sub-mode data for the mode */ + int defaultSubmode; /**< Default sub-mode to use when encoding */ + int quality_map[11]; /**< Mode corresponding to each quality setting */ +} SpeexNBMode; + + +/** Struct defining the encoding/decoding mode for SB-CELP (wideband) */ +typedef struct SpeexSBMode { + const SpeexMode *nb_mode; /**< Embedded narrowband mode */ + int frameSize; /**< Size of frames used for encoding */ + int subframeSize; /**< Size of sub-frames used for encoding */ + int lpcSize; /**< Order of LPC filter */ + spx_word16_t gamma1; /**< Perceptual filter parameter #1 */ + spx_word16_t gamma2; /**< Perceptual filter parameter #1 */ + spx_word16_t lpc_floor; /**< Noise floor for LPC analysis */ + spx_word16_t folding_gain; + + const SpeexSubmode *submodes[SB_SUBMODES]; /**< Sub-mode data for the mode */ + int defaultSubmode; /**< Default sub-mode to use when encoding */ + int low_quality_map[11]; /**< Mode corresponding to each quality setting */ + int quality_map[11]; /**< Mode corresponding to each quality setting */ +#ifndef DISABLE_VBR + const float (*vbr_thresh)[11]; +#endif + int nb_modes; +} SpeexSBMode; + +int speex_encode_native(void *state, spx_word16_t *in, SpeexBits *bits); +int speex_decode_native(void *state, SpeexBits *bits, spx_word16_t *out); + +int nb_mode_query(const void *mode, int request, void *ptr); +int wb_mode_query(const void *mode, int request, void *ptr); + +#endif diff --git a/android/app/src/main/jni/libspeex/modes_wb.c b/android/app/src/main/jni/libspeex/modes_wb.c new file mode 100644 index 000000000..e3b484223 --- /dev/null +++ b/android/app/src/main/jni/libspeex/modes_wb.c @@ -0,0 +1,300 @@ +/* Copyright (C) 2002-2007 Jean-Marc Valin + File: modes.c + + Describes the wideband modes of the codec + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + - Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + - Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + - Neither the name of the Xiph.org Foundation nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR + CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +*/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "modes.h" +#include "ltp.h" +#include "quant_lsp.h" +#include "cb_search.h" +#include "sb_celp.h" +#include "nb_celp.h" +#include "vbr.h" +#include "arch.h" +#include +#include "os_support.h" + + +#ifndef NULL +#define NULL 0 +#endif + +EXPORT const SpeexMode * const speex_mode_list[SPEEX_NB_MODES] = {&speex_nb_mode, &speex_wb_mode, &speex_uwb_mode}; + +extern const signed char hexc_table[]; +extern const signed char hexc_10_32_table[]; + +#ifndef DISABLE_WIDEBAND + +/* Split-VQ innovation for high-band wideband */ +static const split_cb_params split_cb_high = { + 8, /*subvect_size*/ + 5, /*nb_subvect*/ + hexc_table, /*shape_cb*/ + 7, /*shape_bits*/ + 1, +}; + + +/* Split-VQ innovation for high-band wideband */ +static const split_cb_params split_cb_high_lbr = { + 10, /*subvect_size*/ + 4, /*nb_subvect*/ + hexc_10_32_table, /*shape_cb*/ + 5, /*shape_bits*/ + 0, +}; + +#endif + + +static const SpeexSubmode wb_submode1 = { + 0, + 0, + 1, + 0, + /*LSP quantization*/ + lsp_quant_high, + lsp_unquant_high, + /*Pitch quantization*/ + NULL, + NULL, + NULL, + /*No innovation quantization*/ + NULL, + NULL, + NULL, + -1, + 36 +}; + + +static const SpeexSubmode wb_submode2 = { + 0, + 0, + 1, + 0, + /*LSP quantization*/ + lsp_quant_high, + lsp_unquant_high, + /*Pitch quantization*/ + NULL, + NULL, + NULL, + /*Innovation quantization*/ + split_cb_search_shape_sign, + split_cb_shape_sign_unquant, +#ifdef DISABLE_WIDEBAND + NULL, +#else + &split_cb_high_lbr, +#endif + -1, + 112 +}; + + +static const SpeexSubmode wb_submode3 = { + 0, + 0, + 1, + 0, + /*LSP quantization*/ + lsp_quant_high, + lsp_unquant_high, + /*Pitch quantization*/ + NULL, + NULL, + NULL, + /*Innovation quantization*/ + split_cb_search_shape_sign, + split_cb_shape_sign_unquant, +#ifdef DISABLE_WIDEBAND + NULL, +#else + &split_cb_high, +#endif + -1, + 192 +}; + +static const SpeexSubmode wb_submode4 = { + 0, + 0, + 1, + 1, + /*LSP quantization*/ + lsp_quant_high, + lsp_unquant_high, + /*Pitch quantization*/ + NULL, + NULL, + NULL, + /*Innovation quantization*/ + split_cb_search_shape_sign, + split_cb_shape_sign_unquant, +#ifdef DISABLE_WIDEBAND + NULL, +#else + &split_cb_high, +#endif + -1, + 352 +}; + + +/* Split-band wideband CELP mode*/ +static const SpeexSBMode sb_wb_mode = { + &speex_nb_mode, + 160, /*frameSize*/ + 40, /*subframeSize*/ + 8, /*lpcSize*/ +#ifdef FIXED_POINT + 29491, 19661, /* gamma1, gamma2 */ +#else + 0.9, 0.6, /* gamma1, gamma2 */ +#endif + QCONST16(.0002,15), /*lpc_floor*/ + QCONST16(0.9f,15), + {NULL, &wb_submode1, &wb_submode2, &wb_submode3, &wb_submode4, NULL, NULL, NULL}, + 3, + {1, 8, 2, 3, 4, 5, 5, 6, 6, 7, 7}, + {1, 1, 1, 1, 1, 1, 2, 2, 3, 3, 4}, +#ifndef DISABLE_VBR + vbr_hb_thresh, +#endif + 5 +}; + + +EXPORT const SpeexMode speex_wb_mode = { + &sb_wb_mode, + wb_mode_query, + "wideband (sub-band CELP)", + 1, + 4, + &sb_encoder_init, + &sb_encoder_destroy, + &sb_encode, + &sb_decoder_init, + &sb_decoder_destroy, + &sb_decode, + &sb_encoder_ctl, + &sb_decoder_ctl, +}; + + + +/* "Ultra-wideband" mode stuff */ + + + +/* Split-band "ultra-wideband" (32 kbps) CELP mode*/ +static const SpeexSBMode sb_uwb_mode = { + &speex_wb_mode, + 320, /*frameSize*/ + 80, /*subframeSize*/ + 8, /*lpcSize*/ +#ifdef FIXED_POINT + 29491, 19661, /* gamma1, gamma2 */ +#else + 0.9, 0.6, /* gamma1, gamma2 */ +#endif + QCONST16(.0002,15), /*lpc_floor*/ + QCONST16(0.7f,15), + {NULL, &wb_submode1, NULL, NULL, NULL, NULL, NULL, NULL}, + 1, + {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10}, + {0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}, +#ifndef DISABLE_VBR + vbr_uhb_thresh, +#endif + 2 +}; + +int wb_mode_query(const void *mode, int request, void *ptr) +{ + const SpeexSBMode *m = (const SpeexSBMode*)mode; + + switch (request) + { + case SPEEX_MODE_FRAME_SIZE: + *((int*)ptr)=2*m->frameSize; + break; + case SPEEX_SUBMODE_BITS_PER_FRAME: + if (*((int*)ptr)==0) + *((int*)ptr) = SB_SUBMODE_BITS+1; + else if (m->submodes[*((int*)ptr)]==NULL) + *((int*)ptr) = -1; + else + *((int*)ptr) = m->submodes[*((int*)ptr)]->bits_per_frame; + break; + default: + speex_warning_int("Unknown wb_mode_query request: ", request); + return -1; + } + return 0; +} + + +EXPORT const SpeexMode speex_uwb_mode = { + &sb_uwb_mode, + wb_mode_query, + "ultra-wideband (sub-band CELP)", + 2, + 4, + &sb_encoder_init, + &sb_encoder_destroy, + &sb_encode, + &sb_decoder_init, + &sb_decoder_destroy, + &sb_decode, + &sb_encoder_ctl, + &sb_decoder_ctl, +}; + +/* We have defined speex_lib_get_mode() as a macro in speex.h */ +#undef speex_lib_get_mode + +EXPORT const SpeexMode * speex_lib_get_mode (int mode) +{ + if (mode < 0 || mode >= SPEEX_NB_MODES) return NULL; + + return speex_mode_list[mode]; +} + + + diff --git a/android/app/src/main/jni/libspeex/nb_celp.c b/android/app/src/main/jni/libspeex/nb_celp.c new file mode 100644 index 000000000..9dd726a0c --- /dev/null +++ b/android/app/src/main/jni/libspeex/nb_celp.c @@ -0,0 +1,1903 @@ +/* Copyright (C) 2002-2006 Jean-Marc Valin + File: nb_celp.c + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + - Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + - Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + - Neither the name of the Xiph.org Foundation nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR + CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include +#include "nb_celp.h" +#include "lpc.h" +#include "lsp.h" +#include "ltp.h" +#include "quant_lsp.h" +#include "cb_search.h" +#include "filters.h" +#include "stack_alloc.h" +#include "vq.h" +#include +#include "vbr.h" +#include "arch.h" +#include "math_approx.h" +#include "os_support.h" +#include + +#ifdef VORBIS_PSYCHO +#include "vorbis_psy.h" +#endif + +#ifndef M_PI +#define M_PI 3.14159265358979323846 /* pi */ +#endif + +#ifndef NULL +#define NULL 0 +#endif + +#define SUBMODE(x) st->submodes[st->submodeID]->x + +/* Default size for the encoder and decoder stack (can be changed at compile time). + This does not apply when using variable-size arrays or alloca. */ +#ifndef NB_ENC_STACK +#define NB_ENC_STACK (8000*sizeof(spx_sig_t)) +#endif + +#ifndef NB_DEC_STACK +#define NB_DEC_STACK (4000*sizeof(spx_sig_t)) +#endif + + +#ifdef FIXED_POINT +const spx_word32_t ol_gain_table[32]={18900, 25150, 33468, 44536, 59265, 78865, 104946, 139653, 185838, 247297, 329081, 437913, 582736, 775454, 1031906, 1373169, 1827293, 2431601, 3235761, 4305867, 5729870, 7624808, 10146425, 13501971, 17967238, 23909222, 31816294, 42338330, 56340132, 74972501, 99766822, 132760927}; +const spx_word16_t exc_gain_quant_scal3_bound[7]={1841, 3883, 6051, 8062, 10444, 13580, 18560}; +const spx_word16_t exc_gain_quant_scal3[8]={1002, 2680, 5086, 7016, 9108, 11781, 15380, 21740}; +const spx_word16_t exc_gain_quant_scal1_bound[1]={14385}; +const spx_word16_t exc_gain_quant_scal1[2]={11546, 17224}; + +#define LSP_MARGIN 16 +#define LSP_DELTA1 6553 +#define LSP_DELTA2 1638 + +#else + +const float exc_gain_quant_scal3_bound[7]={0.112338f, 0.236980f, 0.369316f, 0.492054f, 0.637471f, 0.828874f, 1.132784f}; +const float exc_gain_quant_scal3[8]={0.061130f, 0.163546f, 0.310413f, 0.428220f, 0.555887f, 0.719055f, 0.938694f, 1.326874f}; +const float exc_gain_quant_scal1_bound[1]={0.87798f}; +const float exc_gain_quant_scal1[2]={0.70469f, 1.05127f}; + +#define LSP_MARGIN .002f +#define LSP_DELTA1 .2f +#define LSP_DELTA2 .05f + +#endif + +#ifdef VORBIS_PSYCHO +#define EXTRA_BUFFER 100 +#else +#define EXTRA_BUFFER 0 +#endif + + +#define sqr(x) ((x)*(x)) + +extern const spx_word16_t lag_window[]; +extern const spx_word16_t lpc_window[]; + +void *nb_encoder_init(const SpeexMode *m) +{ + EncState *st; + const SpeexNBMode *mode; + int i; + + mode=(const SpeexNBMode *)m->mode; + st = (EncState*)speex_alloc(sizeof(EncState)); + if (!st) + return NULL; +#if defined(VAR_ARRAYS) || defined (USE_ALLOCA) + st->stack = NULL; +#else + st->stack = (char*)speex_alloc_scratch(NB_ENC_STACK); +#endif + + st->mode=m; + + st->frameSize = mode->frameSize; + st->nbSubframes=mode->frameSize/mode->subframeSize; + st->subframeSize=mode->subframeSize; + st->windowSize = st->frameSize+st->subframeSize; + st->lpcSize = mode->lpcSize; + st->gamma1=mode->gamma1; + st->gamma2=mode->gamma2; + st->min_pitch=mode->pitchStart; + st->max_pitch=mode->pitchEnd; + st->lpc_floor = mode->lpc_floor; + + st->submodes=mode->submodes; + st->submodeID=st->submodeSelect=mode->defaultSubmode; + st->bounded_pitch = 1; + + st->encode_submode = 1; + +#ifdef VORBIS_PSYCHO + st->psy = vorbis_psy_init(8000, 256); + st->curve = (float*)speex_alloc(128*sizeof(float)); + st->old_curve = (float*)speex_alloc(128*sizeof(float)); + st->psy_window = (float*)speex_alloc(256*sizeof(float)); +#endif + + st->cumul_gain = 1024; + + /* Allocating input buffer */ + st->winBuf = (spx_word16_t*)speex_alloc((st->windowSize-st->frameSize)*sizeof(spx_word16_t)); + /* Allocating excitation buffer */ + st->excBuf = (spx_word16_t*)speex_alloc((mode->frameSize+mode->pitchEnd+2)*sizeof(spx_word16_t)); + st->exc = st->excBuf + mode->pitchEnd + 2; + st->swBuf = (spx_word16_t*)speex_alloc((mode->frameSize+mode->pitchEnd+2)*sizeof(spx_word16_t)); + st->sw = st->swBuf + mode->pitchEnd + 2; + + st->window= lpc_window; + + /* Create the window for autocorrelation (lag-windowing) */ + st->lagWindow = lag_window; + + st->old_lsp = (spx_lsp_t*)speex_alloc((st->lpcSize)*sizeof(spx_lsp_t)); + st->old_qlsp = (spx_lsp_t*)speex_alloc((st->lpcSize)*sizeof(spx_lsp_t)); + st->first = 1; + for (i=0;ilpcSize;i++) + st->old_lsp[i]= DIV32(MULT16_16(QCONST16(3.1415927f, LSP_SHIFT), i+1), st->lpcSize+1); + + st->mem_sp = (spx_mem_t*)speex_alloc((st->lpcSize)*sizeof(spx_mem_t)); + st->mem_sw = (spx_mem_t*)speex_alloc((st->lpcSize)*sizeof(spx_mem_t)); + st->mem_sw_whole = (spx_mem_t*)speex_alloc((st->lpcSize)*sizeof(spx_mem_t)); + st->mem_exc = (spx_mem_t*)speex_alloc((st->lpcSize)*sizeof(spx_mem_t)); + st->mem_exc2 = (spx_mem_t*)speex_alloc((st->lpcSize)*sizeof(spx_mem_t)); + + st->pi_gain = (spx_word32_t*)speex_alloc((st->nbSubframes)*sizeof(spx_word32_t)); + st->innov_rms_save = NULL; + + st->pitch = (int*)speex_alloc((st->nbSubframes)*sizeof(int)); + +#ifndef DISABLE_VBR + st->vbr = (VBRState*)speex_alloc(sizeof(VBRState)); + vbr_init(st->vbr); + st->vbr_quality = 8; + st->vbr_enabled = 0; + st->vbr_max = 0; + st->vad_enabled = 0; + st->dtx_enabled = 0; + st->dtx_count=0; + st->abr_enabled = 0; + st->abr_drift = 0; + st->abr_drift2 = 0; +#endif /* #ifndef DISABLE_VBR */ + + st->plc_tuning = 2; + st->complexity=2; + st->sampling_rate=8000; + st->isWideband = 0; + st->highpass_enabled = 1; + +#ifdef ENABLE_VALGRIND + VALGRIND_MAKE_READABLE(st, NB_ENC_STACK); +#endif + return st; +} + +void nb_encoder_destroy(void *state) +{ + EncState *st=(EncState *)state; + /* Free all allocated memory */ +#if !(defined(VAR_ARRAYS) || defined (USE_ALLOCA)) + speex_free_scratch(st->stack); +#endif + + speex_free (st->winBuf); + speex_free (st->excBuf); + speex_free (st->old_qlsp); + speex_free (st->swBuf); + + speex_free (st->old_lsp); + speex_free (st->mem_sp); + speex_free (st->mem_sw); + speex_free (st->mem_sw_whole); + speex_free (st->mem_exc); + speex_free (st->mem_exc2); + speex_free (st->pi_gain); + speex_free (st->pitch); + +#ifndef DISABLE_VBR + vbr_destroy(st->vbr); + speex_free (st->vbr); +#endif /* #ifndef DISABLE_VBR */ + +#ifdef VORBIS_PSYCHO + vorbis_psy_destroy(st->psy); + speex_free (st->curve); + speex_free (st->old_curve); + speex_free (st->psy_window); +#endif + + /*Free state memory... should be last*/ + speex_free(st); +} + +int nb_encode(void *state, void *vin, SpeexBits *bits) +{ + EncState *st; + int i, sub, roots; + int ol_pitch; + spx_word16_t ol_pitch_coef; + spx_word32_t ol_gain; + VARDECL(spx_word16_t *ringing); + VARDECL(spx_word16_t *target); + VARDECL(spx_sig_t *innov); + VARDECL(spx_word32_t *exc32); + VARDECL(spx_mem_t *mem); + VARDECL(spx_coef_t *bw_lpc1); + VARDECL(spx_coef_t *bw_lpc2); + VARDECL(spx_coef_t *lpc); + VARDECL(spx_lsp_t *lsp); + VARDECL(spx_lsp_t *qlsp); + VARDECL(spx_lsp_t *interp_lsp); + VARDECL(spx_lsp_t *interp_qlsp); + VARDECL(spx_coef_t *interp_lpc); + VARDECL(spx_coef_t *interp_qlpc); + char *stack; + VARDECL(spx_word16_t *syn_resp); + VARDECL(spx_word16_t *real_exc); + + spx_word32_t ener=0; + spx_word16_t fine_gain; + spx_word16_t *in = (spx_word16_t*)vin; + + st=(EncState *)state; + stack=st->stack; + + ALLOC(lpc, st->lpcSize, spx_coef_t); + ALLOC(bw_lpc1, st->lpcSize, spx_coef_t); + ALLOC(bw_lpc2, st->lpcSize, spx_coef_t); + ALLOC(lsp, st->lpcSize, spx_lsp_t); + ALLOC(qlsp, st->lpcSize, spx_lsp_t); + ALLOC(interp_lsp, st->lpcSize, spx_lsp_t); + ALLOC(interp_qlsp, st->lpcSize, spx_lsp_t); + ALLOC(interp_lpc, st->lpcSize, spx_coef_t); + ALLOC(interp_qlpc, st->lpcSize, spx_coef_t); + + /* Move signals 1 frame towards the past */ + SPEEX_MOVE(st->excBuf, st->excBuf+st->frameSize, st->max_pitch+2); + SPEEX_MOVE(st->swBuf, st->swBuf+st->frameSize, st->max_pitch+2); + + if (st->highpass_enabled) + highpass(in, in, st->frameSize, (st->isWideband?HIGHPASS_WIDEBAND:HIGHPASS_NARROWBAND)|HIGHPASS_INPUT, st->mem_hp); + + { + VARDECL(spx_word16_t *w_sig); + VARDECL(spx_word16_t *autocorr); + ALLOC(w_sig, st->windowSize, spx_word16_t); + ALLOC(autocorr, st->lpcSize+1, spx_word16_t); + /* Window for analysis */ + for (i=0;iwindowSize-st->frameSize;i++) + w_sig[i] = EXTRACT16(SHR32(MULT16_16(st->winBuf[i],st->window[i]),SIG_SHIFT)); + for (;iwindowSize;i++) + w_sig[i] = EXTRACT16(SHR32(MULT16_16(in[i-st->windowSize+st->frameSize],st->window[i]),SIG_SHIFT)); + /* Compute auto-correlation */ + _spx_autocorr(w_sig, autocorr, st->lpcSize+1, st->windowSize); + autocorr[0] = ADD16(autocorr[0],MULT16_16_Q15(autocorr[0],st->lpc_floor)); /* Noise floor in auto-correlation domain */ + + /* Lag windowing: equivalent to filtering in the power-spectrum domain */ + for (i=0;ilpcSize+1;i++) + autocorr[i] = MULT16_16_Q14(autocorr[i],st->lagWindow[i]); + + /* Levinson-Durbin */ + _spx_lpc(lpc, autocorr, st->lpcSize); + /* LPC to LSPs (x-domain) transform */ + roots=lpc_to_lsp (lpc, st->lpcSize, lsp, 10, LSP_DELTA1, stack); + /* Check if we found all the roots */ + if (roots!=st->lpcSize) + { + /*If we can't find all LSP's, do some damage control and use previous filter*/ + for (i=0;ilpcSize;i++) + { + lsp[i]=st->old_lsp[i]; + } + } + } + + + + + /* Whole frame analysis (open-loop estimation of pitch and excitation gain) */ + { + int diff = st->windowSize-st->frameSize; + if (st->first) + for (i=0;ilpcSize;i++) + interp_lsp[i] = lsp[i]; + else + lsp_interpolate(st->old_lsp, lsp, interp_lsp, st->lpcSize, st->nbSubframes, st->nbSubframes<<1); + + lsp_enforce_margin(interp_lsp, st->lpcSize, LSP_MARGIN); + + /* Compute interpolated LPCs (unquantized) for whole frame*/ + lsp_to_lpc(interp_lsp, interp_lpc, st->lpcSize,stack); + + + /*Open-loop pitch*/ + if (!st->submodes[st->submodeID] || (st->complexity>2 && SUBMODE(have_subframe_gain)<3) || SUBMODE(forced_pitch_gain) || SUBMODE(lbr_pitch) != -1 +#ifndef DISABLE_VBR + || st->vbr_enabled || st->vad_enabled +#endif + ) + { + int nol_pitch[6]; + spx_word16_t nol_pitch_coef[6]; + + bw_lpc(st->gamma1, interp_lpc, bw_lpc1, st->lpcSize); + bw_lpc(st->gamma2, interp_lpc, bw_lpc2, st->lpcSize); + + SPEEX_COPY(st->sw, st->winBuf, diff); + SPEEX_COPY(st->sw+diff, in, st->frameSize-diff); + filter_mem16(st->sw, bw_lpc1, bw_lpc2, st->sw, st->frameSize, st->lpcSize, st->mem_sw_whole, stack); + + open_loop_nbest_pitch(st->sw, st->min_pitch, st->max_pitch, st->frameSize, + nol_pitch, nol_pitch_coef, 6, stack); + ol_pitch=nol_pitch[0]; + ol_pitch_coef = nol_pitch_coef[0]; + /*Try to remove pitch multiples*/ + for (i=1;i<6;i++) + { +#ifdef FIXED_POINT + if ((nol_pitch_coef[i]>MULT16_16_Q15(nol_pitch_coef[0],27853)) && +#else + if ((nol_pitch_coef[i]>.85*nol_pitch_coef[0]) && +#endif + (ABS(2*nol_pitch[i]-ol_pitch)<=2 || ABS(3*nol_pitch[i]-ol_pitch)<=3 || + ABS(4*nol_pitch[i]-ol_pitch)<=4 || ABS(5*nol_pitch[i]-ol_pitch)<=5)) + { + /*ol_pitch_coef=nol_pitch_coef[i];*/ + ol_pitch = nol_pitch[i]; + } + } + /*if (ol_pitch>50) + ol_pitch/=2;*/ + /*ol_pitch_coef = sqrt(ol_pitch_coef);*/ + + } else { + ol_pitch=0; + ol_pitch_coef=0; + } + + /*Compute "real" excitation*/ + SPEEX_COPY(st->exc, st->winBuf, diff); + SPEEX_COPY(st->exc+diff, in, st->frameSize-diff); + fir_mem16(st->exc, interp_lpc, st->exc, st->frameSize, st->lpcSize, st->mem_exc, stack); + + /* Compute open-loop excitation gain */ + { + spx_word16_t g = compute_rms16(st->exc, st->frameSize); + if (st->submodeID!=1 && ol_pitch>0) + ol_gain = MULT16_16(g, MULT16_16_Q14(QCONST16(1.1,14), + spx_sqrt(QCONST32(1.,28)-MULT16_32_Q15(QCONST16(.8,15),SHL32(MULT16_16(ol_pitch_coef,ol_pitch_coef),16))))); + else + ol_gain = SHL32(EXTEND32(g),SIG_SHIFT); + } + } + +#ifdef VORBIS_PSYCHO + SPEEX_MOVE(st->psy_window, st->psy_window+st->frameSize, 256-st->frameSize); + SPEEX_COPY(&st->psy_window[256-st->frameSize], in, st->frameSize); + compute_curve(st->psy, st->psy_window, st->curve); + /*print_vec(st->curve, 128, "curve");*/ + if (st->first) + SPEEX_COPY(st->old_curve, st->curve, 128); +#endif + + /*VBR stuff*/ +#ifndef DISABLE_VBR + if (st->vbr && (st->vbr_enabled||st->vad_enabled)) + { + float lsp_dist=0; + for (i=0;ilpcSize;i++) + lsp_dist += (st->old_lsp[i] - lsp[i])*(st->old_lsp[i] - lsp[i]); + lsp_dist /= LSP_SCALING*LSP_SCALING; + + if (st->abr_enabled) + { + float qual_change=0; + if (st->abr_drift2 * st->abr_drift > 0) + { + /* Only adapt if long-term and short-term drift are the same sign */ + qual_change = -.00001*st->abr_drift/(1+st->abr_count); + if (qual_change>.05) + qual_change=.05; + if (qual_change<-.05) + qual_change=-.05; + } + st->vbr_quality += qual_change; + if (st->vbr_quality>10) + st->vbr_quality=10; + if (st->vbr_quality<0) + st->vbr_quality=0; + } + + st->relative_quality = vbr_analysis(st->vbr, in, st->frameSize, ol_pitch, GAIN_SCALING_1*ol_pitch_coef); + /*if (delta_qual<0)*/ + /* delta_qual*=.1*(3+st->vbr_quality);*/ + if (st->vbr_enabled) + { + spx_int32_t mode; + int choice=0; + float min_diff=100; + mode = 8; + while (mode) + { + int v1; + float thresh; + v1=(int)floor(st->vbr_quality); + if (v1==10) + thresh = vbr_nb_thresh[mode][v1]; + else + thresh = (st->vbr_quality-v1)*vbr_nb_thresh[mode][v1+1] + (1+v1-st->vbr_quality)*vbr_nb_thresh[mode][v1]; + if (st->relative_quality > thresh && + st->relative_quality-threshrelative_quality-thresh; + } + mode--; + } + mode=choice; + if (mode==0) + { + if (st->dtx_count==0 || lsp_dist>.05 || !st->dtx_enabled || st->dtx_count>20) + { + mode=1; + st->dtx_count=1; + } else { + mode=0; + st->dtx_count++; + } + } else { + st->dtx_count=0; + } + + speex_encoder_ctl(state, SPEEX_SET_MODE, &mode); + if (st->vbr_max>0) + { + spx_int32_t rate; + speex_encoder_ctl(state, SPEEX_GET_BITRATE, &rate); + if (rate > st->vbr_max) + { + rate = st->vbr_max; + speex_encoder_ctl(state, SPEEX_SET_BITRATE, &rate); + } + } + + if (st->abr_enabled) + { + spx_int32_t bitrate; + speex_encoder_ctl(state, SPEEX_GET_BITRATE, &bitrate); + st->abr_drift+=(bitrate-st->abr_enabled); + st->abr_drift2 = .95*st->abr_drift2 + .05*(bitrate-st->abr_enabled); + st->abr_count += 1.0; + } + + } else { + /*VAD only case*/ + int mode; + if (st->relative_quality<2) + { + if (st->dtx_count==0 || lsp_dist>.05 || !st->dtx_enabled || st->dtx_count>20) + { + st->dtx_count=1; + mode=1; + } else { + mode=0; + st->dtx_count++; + } + } else { + st->dtx_count = 0; + mode=st->submodeSelect; + } + /*speex_encoder_ctl(state, SPEEX_SET_MODE, &mode);*/ + st->submodeID=mode; + } + } else { + st->relative_quality = -1; + } +#endif /* #ifndef DISABLE_VBR */ + + if (st->encode_submode) + { + /* First, transmit a zero for narrowband */ + speex_bits_pack(bits, 0, 1); + + /* Transmit the sub-mode we use for this frame */ + speex_bits_pack(bits, st->submodeID, NB_SUBMODE_BITS); + + } + + /* If null mode (no transmission), just set a couple things to zero*/ + if (st->submodes[st->submodeID] == NULL) + { + for (i=0;iframeSize;i++) + st->exc[i]=st->sw[i]=VERY_SMALL; + + for (i=0;ilpcSize;i++) + st->mem_sw[i]=0; + st->first=1; + st->bounded_pitch = 1; + + SPEEX_COPY(st->winBuf, in+2*st->frameSize-st->windowSize, st->windowSize-st->frameSize); + + /* Clear memory (no need to really compute it) */ + for (i=0;ilpcSize;i++) + st->mem_sp[i] = 0; + return 0; + + } + + /* LSP Quantization */ + if (st->first) + { + for (i=0;ilpcSize;i++) + st->old_lsp[i] = lsp[i]; + } + + + /*Quantize LSPs*/ +#if 1 /*0 for unquantized*/ + SUBMODE(lsp_quant)(lsp, qlsp, st->lpcSize, bits); +#else + for (i=0;ilpcSize;i++) + qlsp[i]=lsp[i]; +#endif + + /*If we use low bit-rate pitch mode, transmit open-loop pitch*/ + if (SUBMODE(lbr_pitch)!=-1) + { + speex_bits_pack(bits, ol_pitch-st->min_pitch, 7); + } + + if (SUBMODE(forced_pitch_gain)) + { + int quant; + /* This just damps the pitch a bit, because it tends to be too aggressive when forced */ + ol_pitch_coef = MULT16_16_Q15(QCONST16(.9,15), ol_pitch_coef); +#ifdef FIXED_POINT + quant = PSHR16(MULT16_16_16(15, ol_pitch_coef),GAIN_SHIFT); +#else + quant = (int)floor(.5+15*ol_pitch_coef*GAIN_SCALING_1); +#endif + if (quant>15) + quant=15; + if (quant<0) + quant=0; + speex_bits_pack(bits, quant, 4); + ol_pitch_coef=MULT16_16_P15(QCONST16(0.066667,15),SHL16(quant,GAIN_SHIFT)); + } + + + /*Quantize and transmit open-loop excitation gain*/ +#ifdef FIXED_POINT + { + int qe = scal_quant32(ol_gain, ol_gain_table, 32); + /*ol_gain = exp(qe/3.5)*SIG_SCALING;*/ + ol_gain = MULT16_32_Q15(28406,ol_gain_table[qe]); + speex_bits_pack(bits, qe, 5); + } +#else + { + int qe = (int)(floor(.5+3.5*log(ol_gain*1.0/SIG_SCALING))); + if (qe<0) + qe=0; + if (qe>31) + qe=31; + ol_gain = exp(qe/3.5)*SIG_SCALING; + speex_bits_pack(bits, qe, 5); + } +#endif + + + + /* Special case for first frame */ + if (st->first) + { + for (i=0;ilpcSize;i++) + st->old_qlsp[i] = qlsp[i]; + } + + /* Target signal */ + ALLOC(target, st->subframeSize, spx_word16_t); + ALLOC(innov, st->subframeSize, spx_sig_t); + ALLOC(exc32, st->subframeSize, spx_word32_t); + ALLOC(ringing, st->subframeSize, spx_word16_t); + ALLOC(syn_resp, st->subframeSize, spx_word16_t); + ALLOC(real_exc, st->subframeSize, spx_word16_t); + ALLOC(mem, st->lpcSize, spx_mem_t); + + /* Loop on sub-frames */ + for (sub=0;subnbSubframes;sub++) + { + int offset; + spx_word16_t *sw; + spx_word16_t *exc; + int pitch; + int response_bound = st->subframeSize; + + /* Offset relative to start of frame */ + offset = st->subframeSize*sub; + /* Excitation */ + exc=st->exc+offset; + /* Weighted signal */ + sw=st->sw+offset; + + /* LSP interpolation (quantized and unquantized) */ + lsp_interpolate(st->old_lsp, lsp, interp_lsp, st->lpcSize, sub, st->nbSubframes); + lsp_interpolate(st->old_qlsp, qlsp, interp_qlsp, st->lpcSize, sub, st->nbSubframes); + + /* Make sure the filters are stable */ + lsp_enforce_margin(interp_lsp, st->lpcSize, LSP_MARGIN); + lsp_enforce_margin(interp_qlsp, st->lpcSize, LSP_MARGIN); + + /* Compute interpolated LPCs (quantized and unquantized) */ + lsp_to_lpc(interp_lsp, interp_lpc, st->lpcSize,stack); + + lsp_to_lpc(interp_qlsp, interp_qlpc, st->lpcSize, stack); + + /* Compute analysis filter gain at w=pi (for use in SB-CELP) */ + { + spx_word32_t pi_g=LPC_SCALING; + for (i=0;ilpcSize;i+=2) + { + /*pi_g += -st->interp_qlpc[i] + st->interp_qlpc[i+1];*/ + pi_g = ADD32(pi_g, SUB32(EXTEND32(interp_qlpc[i+1]),EXTEND32(interp_qlpc[i]))); + } + st->pi_gain[sub] = pi_g; + } + +#ifdef VORBIS_PSYCHO + { + float curr_curve[128]; + float fact = ((float)sub+1.0f)/st->nbSubframes; + for (i=0;i<128;i++) + curr_curve[i] = (1.0f-fact)*st->old_curve[i] + fact*st->curve[i]; + curve_to_lpc(st->psy, curr_curve, bw_lpc1, bw_lpc2, 10); + } +#else + /* Compute bandwidth-expanded (unquantized) LPCs for perceptual weighting */ + bw_lpc(st->gamma1, interp_lpc, bw_lpc1, st->lpcSize); + if (st->gamma2>=0) + bw_lpc(st->gamma2, interp_lpc, bw_lpc2, st->lpcSize); + else + { + for (i=0;ilpcSize;i++) + bw_lpc2[i]=0; + } + /*print_vec(st->bw_lpc1, 10, "bw_lpc");*/ +#endif + + /*FIXME: This will break if we change the window size */ + speex_assert(st->windowSize-st->frameSize == st->subframeSize); + if (sub==0) + { + for (i=0;isubframeSize;i++) + real_exc[i] = sw[i] = st->winBuf[i]; + } else { + for (i=0;isubframeSize;i++) + real_exc[i] = sw[i] = in[i+((sub-1)*st->subframeSize)]; + } + fir_mem16(real_exc, interp_qlpc, real_exc, st->subframeSize, st->lpcSize, st->mem_exc2, stack); + + if (st->complexity==0) + response_bound >>= 1; + compute_impulse_response(interp_qlpc, bw_lpc1, bw_lpc2, syn_resp, response_bound, st->lpcSize, stack); + for (i=response_bound;isubframeSize;i++) + syn_resp[i]=VERY_SMALL; + + /* Compute zero response of A(z/g1) / ( A(z/g2) * A(z) ) */ + for (i=0;ilpcSize;i++) + mem[i]=SHL32(st->mem_sp[i],1); + for (i=0;isubframeSize;i++) + ringing[i] = VERY_SMALL; +#ifdef SHORTCUTS2 + iir_mem16(ringing, interp_qlpc, ringing, response_bound, st->lpcSize, mem, stack); + for (i=0;ilpcSize;i++) + mem[i]=SHL32(st->mem_sw[i],1); + filter_mem16(ringing, st->bw_lpc1, st->bw_lpc2, ringing, response_bound, st->lpcSize, mem, stack); + SPEEX_MEMSET(&ringing[response_bound], 0, st->subframeSize-response_bound); +#else + iir_mem16(ringing, interp_qlpc, ringing, st->subframeSize, st->lpcSize, mem, stack); + for (i=0;ilpcSize;i++) + mem[i]=SHL32(st->mem_sw[i],1); + filter_mem16(ringing, bw_lpc1, bw_lpc2, ringing, st->subframeSize, st->lpcSize, mem, stack); +#endif + + /* Compute weighted signal */ + for (i=0;ilpcSize;i++) + mem[i]=st->mem_sw[i]; + filter_mem16(sw, bw_lpc1, bw_lpc2, sw, st->subframeSize, st->lpcSize, mem, stack); + + if (st->complexity==0) + for (i=0;ilpcSize;i++) + st->mem_sw[i]=mem[i]; + + /* Compute target signal (saturation prevents overflows on clipped input speech) */ + for (i=0;isubframeSize;i++) + target[i]=EXTRACT16(SATURATE(SUB32(sw[i],PSHR32(ringing[i],1)),32767)); + + /* Reset excitation */ + SPEEX_MEMSET(exc, 0, st->subframeSize); + + /* If we have a long-term predictor (otherwise, something's wrong) */ + speex_assert (SUBMODE(ltp_quant)); + { + int pit_min, pit_max; + /* Long-term prediction */ + if (SUBMODE(lbr_pitch) != -1) + { + /* Low bit-rate pitch handling */ + int margin; + margin = SUBMODE(lbr_pitch); + if (margin) + { + if (ol_pitch < st->min_pitch+margin-1) + ol_pitch=st->min_pitch+margin-1; + if (ol_pitch > st->max_pitch-margin) + ol_pitch=st->max_pitch-margin; + pit_min = ol_pitch-margin+1; + pit_max = ol_pitch+margin; + } else { + pit_min=pit_max=ol_pitch; + } + } else { + pit_min = st->min_pitch; + pit_max = st->max_pitch; + } + + /* Force pitch to use only the current frame if needed */ + if (st->bounded_pitch && pit_max>offset) + pit_max=offset; + + /* Perform pitch search */ + pitch = SUBMODE(ltp_quant)(target, sw, interp_qlpc, bw_lpc1, bw_lpc2, + exc32, SUBMODE(ltp_params), pit_min, pit_max, ol_pitch_coef, + st->lpcSize, st->subframeSize, bits, stack, + exc, syn_resp, st->complexity, 0, st->plc_tuning, &st->cumul_gain); + + st->pitch[sub]=pitch; + } + /* Quantization of innovation */ + SPEEX_MEMSET(innov, 0, st->subframeSize); + + /* FIXME: Make sure this is save from overflows (so far so good) */ + for (i=0;isubframeSize;i++) + real_exc[i] = EXTRACT16(SUB32(EXTEND32(real_exc[i]), PSHR32(exc32[i],SIG_SHIFT-1))); + + ener = SHL32(EXTEND32(compute_rms16(real_exc, st->subframeSize)),SIG_SHIFT); + + /*FIXME: Should use DIV32_16 and make sure result fits in 16 bits */ +#ifdef FIXED_POINT + { + spx_word32_t f = PDIV32(ener,PSHR32(ol_gain,SIG_SHIFT)); + if (f<=32767) + fine_gain = f; + else + fine_gain = 32767; + } +#else + fine_gain = PDIV32_16(ener,PSHR32(ol_gain,SIG_SHIFT)); +#endif + /* Calculate gain correction for the sub-frame (if any) */ + if (SUBMODE(have_subframe_gain)) + { + int qe; + if (SUBMODE(have_subframe_gain)==3) + { + qe = scal_quant(fine_gain, exc_gain_quant_scal3_bound, 8); + speex_bits_pack(bits, qe, 3); + ener=MULT16_32_Q14(exc_gain_quant_scal3[qe],ol_gain); + } else { + qe = scal_quant(fine_gain, exc_gain_quant_scal1_bound, 2); + speex_bits_pack(bits, qe, 1); + ener=MULT16_32_Q14(exc_gain_quant_scal1[qe],ol_gain); + } + } else { + ener=ol_gain; + } + + /*printf ("%f %f\n", ener, ol_gain);*/ + + /* Normalize innovation */ + signal_div(target, target, ener, st->subframeSize); + + /* Quantize innovation */ + speex_assert (SUBMODE(innovation_quant)); + { + /* Codebook search */ + SUBMODE(innovation_quant)(target, interp_qlpc, bw_lpc1, bw_lpc2, + SUBMODE(innovation_params), st->lpcSize, st->subframeSize, + innov, syn_resp, bits, stack, st->complexity, SUBMODE(double_codebook)); + + /* De-normalize innovation and update excitation */ + signal_mul(innov, innov, ener, st->subframeSize); + + for (i=0;isubframeSize;i++) + exc[i] = EXTRACT16(SATURATE32(PSHR32(ADD32(SHL32(exc32[i],1),innov[i]),SIG_SHIFT),32767)); + + /* In some (rare) modes, we do a second search (more bits) to reduce noise even more */ + if (SUBMODE(double_codebook)) { + char *tmp_stack=stack; + VARDECL(spx_sig_t *innov2); + ALLOC(innov2, st->subframeSize, spx_sig_t); + SPEEX_MEMSET(innov2, 0, st->subframeSize); + for (i=0;isubframeSize;i++) + target[i]=MULT16_16_P13(QCONST16(2.2f,13), target[i]); + SUBMODE(innovation_quant)(target, interp_qlpc, bw_lpc1, bw_lpc2, + SUBMODE(innovation_params), st->lpcSize, st->subframeSize, + innov2, syn_resp, bits, stack, st->complexity, 0); + signal_mul(innov2, innov2, MULT16_32_Q15(QCONST16(0.454545f,15),ener), st->subframeSize); + for (i=0;isubframeSize;i++) + innov[i] = ADD32(innov[i],innov2[i]); + stack = tmp_stack; + } + for (i=0;isubframeSize;i++) + exc[i] = EXTRACT16(SATURATE32(PSHR32(ADD32(SHL32(exc32[i],1),innov[i]),SIG_SHIFT),32767)); + if (st->innov_rms_save) + { + st->innov_rms_save[sub] = compute_rms(innov, st->subframeSize); + } + } + + /* Final signal synthesis from excitation */ + iir_mem16(exc, interp_qlpc, sw, st->subframeSize, st->lpcSize, st->mem_sp, stack); + + /* Compute weighted signal again, from synthesized speech (not sure it's the right thing) */ + if (st->complexity!=0) + filter_mem16(sw, bw_lpc1, bw_lpc2, sw, st->subframeSize, st->lpcSize, st->mem_sw, stack); + + } + + /* Store the LSPs for interpolation in the next frame */ + if (st->submodeID>=1) + { + for (i=0;ilpcSize;i++) + st->old_lsp[i] = lsp[i]; + for (i=0;ilpcSize;i++) + st->old_qlsp[i] = qlsp[i]; + } + +#ifdef VORBIS_PSYCHO + if (st->submodeID>=1) + SPEEX_COPY(st->old_curve, st->curve, 128); +#endif + + if (st->submodeID==1) + { +#ifndef DISABLE_VBR + if (st->dtx_count) + speex_bits_pack(bits, 15, 4); + else +#endif + speex_bits_pack(bits, 0, 4); + } + + /* The next frame will not be the first (Duh!) */ + st->first = 0; + SPEEX_COPY(st->winBuf, in+2*st->frameSize-st->windowSize, st->windowSize-st->frameSize); + + if (SUBMODE(innovation_quant) == noise_codebook_quant || st->submodeID==0) + st->bounded_pitch = 1; + else + st->bounded_pitch = 0; + + return 1; +} + +void *nb_decoder_init(const SpeexMode *m) +{ + DecState *st; + const SpeexNBMode *mode; + int i; + + mode=(const SpeexNBMode*)m->mode; + st = (DecState *)speex_alloc(sizeof(DecState)); + if (!st) + return NULL; +#if defined(VAR_ARRAYS) || defined (USE_ALLOCA) + st->stack = NULL; +#else + st->stack = (char*)speex_alloc_scratch(NB_DEC_STACK); +#endif + + st->mode=m; + + + st->encode_submode = 1; + + st->first=1; + /* Codec parameters, should eventually have several "modes"*/ + st->frameSize = mode->frameSize; + st->nbSubframes=mode->frameSize/mode->subframeSize; + st->subframeSize=mode->subframeSize; + st->lpcSize = mode->lpcSize; + st->min_pitch=mode->pitchStart; + st->max_pitch=mode->pitchEnd; + + st->submodes=mode->submodes; + st->submodeID=mode->defaultSubmode; + + st->lpc_enh_enabled=1; + + st->excBuf = (spx_word16_t*)speex_alloc((st->frameSize + 2*st->max_pitch + st->subframeSize + 12)*sizeof(spx_word16_t)); + st->exc = st->excBuf + 2*st->max_pitch + st->subframeSize + 6; + SPEEX_MEMSET(st->excBuf, 0, st->frameSize + st->max_pitch); + + st->interp_qlpc = (spx_coef_t*)speex_alloc(st->lpcSize*sizeof(spx_coef_t)); + st->old_qlsp = (spx_lsp_t*)speex_alloc(st->lpcSize*sizeof(spx_lsp_t)); + st->mem_sp = (spx_mem_t*)speex_alloc(st->lpcSize*sizeof(spx_mem_t)); + st->pi_gain = (spx_word32_t*)speex_alloc((st->nbSubframes)*sizeof(spx_word32_t)); + st->last_pitch = 40; + st->count_lost=0; + st->pitch_gain_buf[0] = st->pitch_gain_buf[1] = st->pitch_gain_buf[2] = 0; + st->pitch_gain_buf_idx = 0; + st->seed = 1000; + + st->sampling_rate=8000; + st->last_ol_gain = 0; + + st->user_callback.func = &speex_default_user_handler; + st->user_callback.data = NULL; + for (i=0;i<16;i++) + st->speex_callbacks[i].func = NULL; + + st->voc_m1=st->voc_m2=st->voc_mean=0; + st->voc_offset=0; + st->dtx_enabled=0; + st->isWideband = 0; + st->highpass_enabled = 1; + +#ifdef ENABLE_VALGRIND + VALGRIND_MAKE_READABLE(st, NB_DEC_STACK); +#endif + return st; +} + +void nb_decoder_destroy(void *state) +{ + DecState *st; + st=(DecState*)state; + +#if !(defined(VAR_ARRAYS) || defined (USE_ALLOCA)) + speex_free_scratch(st->stack); +#endif + + speex_free (st->excBuf); + speex_free (st->interp_qlpc); + speex_free (st->old_qlsp); + speex_free (st->mem_sp); + speex_free (st->pi_gain); + + speex_free(state); +} + +#define median3(a, b, c) ((a) < (b) ? ((b) < (c) ? (b) : ((a) < (c) ? (c) : (a))) : ((c) < (b) ? (b) : ((c) < (a) ? (c) : (a)))) + +#ifdef FIXED_POINT +const spx_word16_t attenuation[10] = {32767, 31483, 27923, 22861, 17278, 12055, 7764, 4616, 2533, 1283}; +#else +const spx_word16_t attenuation[10] = {1., 0.961, 0.852, 0.698, 0.527, 0.368, 0.237, 0.141, 0.077, 0.039}; + +#endif + +static void nb_decode_lost(DecState *st, spx_word16_t *out, char *stack) +{ + int i; + int pitch_val; + spx_word16_t pitch_gain; + spx_word16_t fact; + spx_word16_t gain_med; + spx_word16_t innov_gain; + spx_word16_t noise_gain; + + if (st->count_lost<10) + fact = attenuation[st->count_lost]; + else + fact = 0; + + gain_med = median3(st->pitch_gain_buf[0], st->pitch_gain_buf[1], st->pitch_gain_buf[2]); + if (gain_med < st->last_pitch_gain) + st->last_pitch_gain = gain_med; + +#ifdef FIXED_POINT + pitch_gain = st->last_pitch_gain; + if (pitch_gain>54) + pitch_gain = 54; + pitch_gain = SHL16(pitch_gain, 9); +#else + pitch_gain = GAIN_SCALING_1*st->last_pitch_gain; + if (pitch_gain>.85) + pitch_gain=.85; +#endif + pitch_gain = MULT16_16_Q15(fact,pitch_gain) + VERY_SMALL; + /* FIXME: This was rms of innovation (not exc) */ + innov_gain = compute_rms16(st->exc, st->frameSize); + noise_gain = MULT16_16_Q15(innov_gain, MULT16_16_Q15(fact, SUB16(Q15ONE,MULT16_16_Q15(pitch_gain,pitch_gain)))); + /* Shift all buffers by one frame */ + SPEEX_MOVE(st->excBuf, st->excBuf+st->frameSize, 2*st->max_pitch + st->subframeSize + 12); + + + pitch_val = st->last_pitch + SHR32((spx_int32_t)speex_rand(1+st->count_lost, &st->seed),SIG_SHIFT); + if (pitch_val > st->max_pitch) + pitch_val = st->max_pitch; + if (pitch_val < st->min_pitch) + pitch_val = st->min_pitch; + for (i=0;iframeSize;i++) + { + st->exc[i]= MULT16_16_Q15(pitch_gain, (st->exc[i-pitch_val]+VERY_SMALL)) + + speex_rand(noise_gain, &st->seed); + } + + bw_lpc(QCONST16(.98,15), st->interp_qlpc, st->interp_qlpc, st->lpcSize); + iir_mem16(&st->exc[-st->subframeSize], st->interp_qlpc, out, st->frameSize, + st->lpcSize, st->mem_sp, stack); + highpass(out, out, st->frameSize, HIGHPASS_NARROWBAND|HIGHPASS_OUTPUT, st->mem_hp); + + st->first = 0; + st->count_lost++; + st->pitch_gain_buf[st->pitch_gain_buf_idx++] = PSHR16(pitch_gain,9); + if (st->pitch_gain_buf_idx > 2) /* rollover */ + st->pitch_gain_buf_idx = 0; +} + +/* Just so we don't need to carry the complete wideband mode information */ +static const int wb_skip_table[8] = {0, 36, 112, 192, 352, 0, 0, 0}; + +int nb_decode(void *state, SpeexBits *bits, void *vout) +{ + DecState *st; + int i, sub; + int pitch; + spx_word16_t pitch_gain[3]; + spx_word32_t ol_gain=0; + int ol_pitch=0; + spx_word16_t ol_pitch_coef=0; + int best_pitch=40; + spx_word16_t best_pitch_gain=0; + int wideband; + int m; + char *stack; + VARDECL(spx_sig_t *innov); + VARDECL(spx_word32_t *exc32); + VARDECL(spx_coef_t *ak); + VARDECL(spx_lsp_t *qlsp); + spx_word16_t pitch_average=0; + + spx_word16_t *out = (spx_word16_t*)vout; + VARDECL(spx_lsp_t *interp_qlsp); + + st=(DecState*)state; + stack=st->stack; + + /* Check if we're in DTX mode*/ + if (!bits && st->dtx_enabled) + { + st->submodeID=0; + } else + { + /* If bits is NULL, consider the packet to be lost (what could we do anyway) */ + if (!bits) + { + nb_decode_lost(st, out, stack); + return 0; + } + + if (st->encode_submode) + { + + /* Search for next narrowband block (handle requests, skip wideband blocks) */ + do { + if (speex_bits_remaining(bits)<5) + return -1; + wideband = speex_bits_unpack_unsigned(bits, 1); + if (wideband) /* Skip wideband block (for compatibility) */ + { + int submode; + int advance; + advance = submode = speex_bits_unpack_unsigned(bits, SB_SUBMODE_BITS); + /*speex_mode_query(&speex_wb_mode, SPEEX_SUBMODE_BITS_PER_FRAME, &advance);*/ + advance = wb_skip_table[submode]; + if (advance < 0) + { + speex_notify("Invalid mode encountered. The stream is corrupted."); + return -2; + } + advance -= (SB_SUBMODE_BITS+1); + speex_bits_advance(bits, advance); + + if (speex_bits_remaining(bits)<5) + return -1; + wideband = speex_bits_unpack_unsigned(bits, 1); + if (wideband) + { + advance = submode = speex_bits_unpack_unsigned(bits, SB_SUBMODE_BITS); + /*speex_mode_query(&speex_wb_mode, SPEEX_SUBMODE_BITS_PER_FRAME, &advance);*/ + advance = wb_skip_table[submode]; + if (advance < 0) + { + speex_notify("Invalid mode encountered. The stream is corrupted."); + return -2; + } + advance -= (SB_SUBMODE_BITS+1); + speex_bits_advance(bits, advance); + wideband = speex_bits_unpack_unsigned(bits, 1); + if (wideband) + { + speex_notify("More than two wideband layers found. The stream is corrupted."); + return -2; + } + + } + } + if (speex_bits_remaining(bits)<4) + return -1; + /* FIXME: Check for overflow */ + m = speex_bits_unpack_unsigned(bits, 4); + if (m==15) /* We found a terminator */ + { + return -1; + } else if (m==14) /* Speex in-band request */ + { + int ret = speex_inband_handler(bits, st->speex_callbacks, state); + if (ret) + return ret; + } else if (m==13) /* User in-band request */ + { + int ret = st->user_callback.func(bits, state, st->user_callback.data); + if (ret) + return ret; + } else if (m>8) /* Invalid mode */ + { + speex_notify("Invalid mode encountered. The stream is corrupted."); + return -2; + } + + } while (m>8); + + /* Get the sub-mode that was used */ + st->submodeID = m; + } + + } + + /* Shift all buffers by one frame */ + SPEEX_MOVE(st->excBuf, st->excBuf+st->frameSize, 2*st->max_pitch + st->subframeSize + 12); + + /* If null mode (no transmission), just set a couple things to zero*/ + if (st->submodes[st->submodeID] == NULL) + { + VARDECL(spx_coef_t *lpc); + ALLOC(lpc, st->lpcSize, spx_coef_t); + bw_lpc(QCONST16(0.93f,15), st->interp_qlpc, lpc, st->lpcSize); + { + spx_word16_t innov_gain=0; + /* FIXME: This was innov, not exc */ + innov_gain = compute_rms16(st->exc, st->frameSize); + for (i=0;iframeSize;i++) + st->exc[i]=speex_rand(innov_gain, &st->seed); + } + + + st->first=1; + + /* Final signal synthesis from excitation */ + iir_mem16(st->exc, lpc, out, st->frameSize, st->lpcSize, st->mem_sp, stack); + + st->count_lost=0; + return 0; + } + + ALLOC(qlsp, st->lpcSize, spx_lsp_t); + + /* Unquantize LSPs */ + SUBMODE(lsp_unquant)(qlsp, st->lpcSize, bits); + + /*Damp memory if a frame was lost and the LSP changed too much*/ + if (st->count_lost) + { + spx_word16_t fact; + spx_word32_t lsp_dist=0; + for (i=0;ilpcSize;i++) + lsp_dist = ADD32(lsp_dist, EXTEND32(ABS(st->old_qlsp[i] - qlsp[i]))); +#ifdef FIXED_POINT + fact = SHR16(19661,SHR32(lsp_dist,LSP_SHIFT+2)); +#else + fact = .6*exp(-.2*lsp_dist); +#endif + for (i=0;ilpcSize;i++) + st->mem_sp[i] = MULT16_32_Q15(fact,st->mem_sp[i]); + } + + + /* Handle first frame and lost-packet case */ + if (st->first || st->count_lost) + { + for (i=0;ilpcSize;i++) + st->old_qlsp[i] = qlsp[i]; + } + + /* Get open-loop pitch estimation for low bit-rate pitch coding */ + if (SUBMODE(lbr_pitch)!=-1) + { + ol_pitch = st->min_pitch+speex_bits_unpack_unsigned(bits, 7); + } + + if (SUBMODE(forced_pitch_gain)) + { + int quant; + quant = speex_bits_unpack_unsigned(bits, 4); + ol_pitch_coef=MULT16_16_P15(QCONST16(0.066667,15),SHL16(quant,GAIN_SHIFT)); + } + + /* Get global excitation gain */ + { + int qe; + qe = speex_bits_unpack_unsigned(bits, 5); +#ifdef FIXED_POINT + /* FIXME: Perhaps we could slightly lower the gain here when the output is going to saturate? */ + ol_gain = MULT16_32_Q15(28406,ol_gain_table[qe]); +#else + ol_gain = SIG_SCALING*exp(qe/3.5); +#endif + } + + ALLOC(ak, st->lpcSize, spx_coef_t); + ALLOC(innov, st->subframeSize, spx_sig_t); + ALLOC(exc32, st->subframeSize, spx_word32_t); + + if (st->submodeID==1) + { + int extra; + extra = speex_bits_unpack_unsigned(bits, 4); + + if (extra==15) + st->dtx_enabled=1; + else + st->dtx_enabled=0; + } + if (st->submodeID>1) + st->dtx_enabled=0; + + /*Loop on subframes */ + for (sub=0;subnbSubframes;sub++) + { + int offset; + spx_word16_t *exc; + spx_word16_t *sp; + spx_word16_t *innov_save = NULL; + spx_word16_t tmp; + + /* Offset relative to start of frame */ + offset = st->subframeSize*sub; + /* Excitation */ + exc=st->exc+offset; + /* Original signal */ + sp=out+offset; + if (st->innov_save) + innov_save = st->innov_save+offset; + + + /* Reset excitation */ + SPEEX_MEMSET(exc, 0, st->subframeSize); + + /*Adaptive codebook contribution*/ + speex_assert (SUBMODE(ltp_unquant)); + { + int pit_min, pit_max; + /* Handle pitch constraints if any */ + if (SUBMODE(lbr_pitch) != -1) + { + int margin; + margin = SUBMODE(lbr_pitch); + if (margin) + { +/* GT - need optimization? + if (ol_pitch < st->min_pitch+margin-1) + ol_pitch=st->min_pitch+margin-1; + if (ol_pitch > st->max_pitch-margin) + ol_pitch=st->max_pitch-margin; + pit_min = ol_pitch-margin+1; + pit_max = ol_pitch+margin; +*/ + pit_min = ol_pitch-margin+1; + if (pit_min < st->min_pitch) + pit_min = st->min_pitch; + pit_max = ol_pitch+margin; + if (pit_max > st->max_pitch) + pit_max = st->max_pitch; + } else { + pit_min = pit_max = ol_pitch; + } + } else { + pit_min = st->min_pitch; + pit_max = st->max_pitch; + } + + + + SUBMODE(ltp_unquant)(exc, exc32, pit_min, pit_max, ol_pitch_coef, SUBMODE(ltp_params), + st->subframeSize, &pitch, &pitch_gain[0], bits, stack, + st->count_lost, offset, st->last_pitch_gain, 0); + + /* Ensuring that things aren't blowing up as would happen if e.g. an encoder is + crafting packets to make us produce NaNs and slow down the decoder (vague DoS threat). + We can probably be even more aggressive and limit to 15000 or so. */ + sanitize_values32(exc32, NEG32(QCONST32(32000,SIG_SHIFT-1)), QCONST32(32000,SIG_SHIFT-1), st->subframeSize); + + tmp = gain_3tap_to_1tap(pitch_gain); + + pitch_average += tmp; + if ((tmp>best_pitch_gain&&ABS(2*best_pitch-pitch)>=3&&ABS(3*best_pitch-pitch)>=4&&ABS(4*best_pitch-pitch)>=5) + || (tmp>MULT16_16_Q15(QCONST16(.6,15),best_pitch_gain)&&(ABS(best_pitch-2*pitch)<3||ABS(best_pitch-3*pitch)<4||ABS(best_pitch-4*pitch)<5)) + || (MULT16_16_Q15(QCONST16(.67,15),tmp)>best_pitch_gain&&(ABS(2*best_pitch-pitch)<3||ABS(3*best_pitch-pitch)<4||ABS(4*best_pitch-pitch)<5)) ) + { + best_pitch = pitch; + if (tmp > best_pitch_gain) + best_pitch_gain = tmp; + } + } + + /* Unquantize the innovation */ + { + int q_energy; + spx_word32_t ener; + + SPEEX_MEMSET(innov, 0, st->subframeSize); + + /* Decode sub-frame gain correction */ + if (SUBMODE(have_subframe_gain)==3) + { + q_energy = speex_bits_unpack_unsigned(bits, 3); + ener = MULT16_32_Q14(exc_gain_quant_scal3[q_energy],ol_gain); + } else if (SUBMODE(have_subframe_gain)==1) + { + q_energy = speex_bits_unpack_unsigned(bits, 1); + ener = MULT16_32_Q14(exc_gain_quant_scal1[q_energy],ol_gain); + } else { + ener = ol_gain; + } + + speex_assert (SUBMODE(innovation_unquant)); + { + /*Fixed codebook contribution*/ + SUBMODE(innovation_unquant)(innov, SUBMODE(innovation_params), st->subframeSize, bits, stack, &st->seed); + /* De-normalize innovation and update excitation */ + + signal_mul(innov, innov, ener, st->subframeSize); + + /* Decode second codebook (only for some modes) */ + if (SUBMODE(double_codebook)) + { + char *tmp_stack=stack; + VARDECL(spx_sig_t *innov2); + ALLOC(innov2, st->subframeSize, spx_sig_t); + SPEEX_MEMSET(innov2, 0, st->subframeSize); + SUBMODE(innovation_unquant)(innov2, SUBMODE(innovation_params), st->subframeSize, bits, stack, &st->seed); + signal_mul(innov2, innov2, MULT16_32_Q15(QCONST16(0.454545f,15),ener), st->subframeSize); + for (i=0;isubframeSize;i++) + innov[i] = ADD32(innov[i], innov2[i]); + stack = tmp_stack; + } + for (i=0;isubframeSize;i++) + exc[i]=EXTRACT16(SATURATE32(PSHR32(ADD32(SHL32(exc32[i],1),innov[i]),SIG_SHIFT),32767)); + /*print_vec(exc, 40, "innov");*/ + if (innov_save) + { + for (i=0;isubframeSize;i++) + innov_save[i] = EXTRACT16(PSHR32(innov[i], SIG_SHIFT)); + } + } + + /*Vocoder mode*/ + if (st->submodeID==1) + { + spx_word16_t g=ol_pitch_coef; + g=MULT16_16_P14(QCONST16(1.5f,14),(g-QCONST16(.2f,6))); + if (g<0) + g=0; + if (g>GAIN_SCALING) + g=GAIN_SCALING; + + SPEEX_MEMSET(exc, 0, st->subframeSize); + while (st->voc_offsetsubframeSize) + { + /* exc[st->voc_offset]= g*sqrt(2*ol_pitch)*ol_gain; + Not quite sure why we need the factor of two in the sqrt */ + if (st->voc_offset>=0) + exc[st->voc_offset]=MULT16_16(spx_sqrt(MULT16_16_16(2,ol_pitch)),EXTRACT16(PSHR32(MULT16_16(g,PSHR32(ol_gain,SIG_SHIFT)),6))); + st->voc_offset+=ol_pitch; + } + st->voc_offset -= st->subframeSize; + + for (i=0;isubframeSize;i++) + { + spx_word16_t exci=exc[i]; + exc[i]= ADD16(ADD16(MULT16_16_Q15(QCONST16(.7f,15),exc[i]) , MULT16_16_Q15(QCONST16(.3f,15),st->voc_m1)), + SUB16(MULT16_16_Q15(Q15_ONE-MULT16_16_16(QCONST16(.85f,9),g),EXTRACT16(PSHR32(innov[i],SIG_SHIFT))), + MULT16_16_Q15(MULT16_16_16(QCONST16(.15f,9),g),EXTRACT16(PSHR32(st->voc_m2,SIG_SHIFT))) + )); + st->voc_m1 = exci; + st->voc_m2=innov[i]; + st->voc_mean = EXTRACT16(PSHR32(ADD32(MULT16_16(QCONST16(.8f,15),st->voc_mean), MULT16_16(QCONST16(.2f,15),exc[i])), 15)); + exc[i]-=st->voc_mean; + } + } + + } + } + + ALLOC(interp_qlsp, st->lpcSize, spx_lsp_t); + + if (st->lpc_enh_enabled && SUBMODE(comb_gain)>0 && !st->count_lost) + { + multicomb(st->exc-st->subframeSize, out, st->interp_qlpc, st->lpcSize, 2*st->subframeSize, best_pitch, 40, SUBMODE(comb_gain), stack); + multicomb(st->exc+st->subframeSize, out+2*st->subframeSize, st->interp_qlpc, st->lpcSize, 2*st->subframeSize, best_pitch, 40, SUBMODE(comb_gain), stack); + } else { + SPEEX_COPY(out, &st->exc[-st->subframeSize], st->frameSize); + } + + /* If the last packet was lost, re-scale the excitation to obtain the same energy as encoded in ol_gain */ + if (st->count_lost) + { + spx_word16_t exc_ener; + spx_word32_t gain32; + spx_word16_t gain; + exc_ener = compute_rms16 (st->exc, st->frameSize); + gain32 = PDIV32(ol_gain, ADD16(exc_ener,1)); +#ifdef FIXED_POINT + if (gain32 > 32767) + gain32 = 32767; + gain = EXTRACT16(gain32); +#else + if (gain32 > 2) + gain32=2; + gain = gain32; +#endif + for (i=0;iframeSize;i++) + { + st->exc[i] = MULT16_16_Q14(gain, st->exc[i]); + out[i]=st->exc[i-st->subframeSize]; + } + } + + /*Loop on subframes */ + for (sub=0;subnbSubframes;sub++) + { + int offset; + spx_word16_t *sp; + spx_word16_t *exc; + /* Offset relative to start of frame */ + offset = st->subframeSize*sub; + /* Original signal */ + sp=out+offset; + /* Excitation */ + exc=st->exc+offset; + + /* LSP interpolation (quantized and unquantized) */ + lsp_interpolate(st->old_qlsp, qlsp, interp_qlsp, st->lpcSize, sub, st->nbSubframes); + + /* Make sure the LSP's are stable */ + lsp_enforce_margin(interp_qlsp, st->lpcSize, LSP_MARGIN); + + /* Compute interpolated LPCs (unquantized) */ + lsp_to_lpc(interp_qlsp, ak, st->lpcSize, stack); + + /* Compute analysis filter at w=pi */ + { + spx_word32_t pi_g=LPC_SCALING; + for (i=0;ilpcSize;i+=2) + { + /*pi_g += -st->interp_qlpc[i] + st->interp_qlpc[i+1];*/ + pi_g = ADD32(pi_g, SUB32(EXTEND32(ak[i+1]),EXTEND32(ak[i]))); + } + st->pi_gain[sub] = pi_g; + } + + iir_mem16(sp, st->interp_qlpc, sp, st->subframeSize, st->lpcSize, + st->mem_sp, stack); + + for (i=0;ilpcSize;i++) + st->interp_qlpc[i] = ak[i]; + + } + + if (st->highpass_enabled) + highpass(out, out, st->frameSize, (st->isWideband?HIGHPASS_WIDEBAND:HIGHPASS_NARROWBAND)|HIGHPASS_OUTPUT, st->mem_hp); + /*for (i=0;iframeSize;i++) + printf ("%d\n", (int)st->frame[i]);*/ + + /* Tracking output level */ + st->level = 1+PSHR32(ol_gain,SIG_SHIFT); + st->max_level = MAX16(MULT16_16_Q15(QCONST16(.99f,15), st->max_level), st->level); + st->min_level = MIN16(ADD16(1,MULT16_16_Q14(QCONST16(1.01f,14), st->min_level)), st->level); + if (st->max_level < st->min_level+1) + st->max_level = st->min_level+1; + /*printf ("%f %f %f %d\n", og, st->min_level, st->max_level, update);*/ + + /* Store the LSPs for interpolation in the next frame */ + for (i=0;ilpcSize;i++) + st->old_qlsp[i] = qlsp[i]; + + /* The next frame will not be the first (Duh!) */ + st->first = 0; + st->count_lost=0; + st->last_pitch = best_pitch; +#ifdef FIXED_POINT + st->last_pitch_gain = PSHR16(pitch_average,2); +#else + st->last_pitch_gain = .25*pitch_average; +#endif + st->pitch_gain_buf[st->pitch_gain_buf_idx++] = st->last_pitch_gain; + if (st->pitch_gain_buf_idx > 2) /* rollover */ + st->pitch_gain_buf_idx = 0; + + st->last_ol_gain = ol_gain; + + return 0; +} + +int nb_encoder_ctl(void *state, int request, void *ptr) +{ + EncState *st; + st=(EncState*)state; + switch(request) + { + case SPEEX_GET_FRAME_SIZE: + (*(spx_int32_t*)ptr) = st->frameSize; + break; + case SPEEX_SET_LOW_MODE: + case SPEEX_SET_MODE: + st->submodeSelect = st->submodeID = (*(spx_int32_t*)ptr); + break; + case SPEEX_GET_LOW_MODE: + case SPEEX_GET_MODE: + (*(spx_int32_t*)ptr) = st->submodeID; + break; +#ifndef DISABLE_VBR + case SPEEX_SET_VBR: + st->vbr_enabled = (*(spx_int32_t*)ptr); + break; + case SPEEX_GET_VBR: + (*(spx_int32_t*)ptr) = st->vbr_enabled; + break; + case SPEEX_SET_VAD: + st->vad_enabled = (*(spx_int32_t*)ptr); + break; + case SPEEX_GET_VAD: + (*(spx_int32_t*)ptr) = st->vad_enabled; + break; + case SPEEX_SET_DTX: + st->dtx_enabled = (*(spx_int32_t*)ptr); + break; + case SPEEX_GET_DTX: + (*(spx_int32_t*)ptr) = st->dtx_enabled; + break; + case SPEEX_SET_ABR: + st->abr_enabled = (*(spx_int32_t*)ptr); + st->vbr_enabled = st->abr_enabled!=0; + if (st->vbr_enabled) + { + spx_int32_t i=10; + spx_int32_t rate, target; + float vbr_qual; + target = (*(spx_int32_t*)ptr); + while (i>=0) + { + speex_encoder_ctl(st, SPEEX_SET_QUALITY, &i); + speex_encoder_ctl(st, SPEEX_GET_BITRATE, &rate); + if (rate <= target) + break; + i--; + } + vbr_qual=i; + if (vbr_qual<0) + vbr_qual=0; + speex_encoder_ctl(st, SPEEX_SET_VBR_QUALITY, &vbr_qual); + st->abr_count=0; + st->abr_drift=0; + st->abr_drift2=0; + } + + break; + case SPEEX_GET_ABR: + (*(spx_int32_t*)ptr) = st->abr_enabled; + break; +#endif /* #ifndef DISABLE_VBR */ +#if !defined(DISABLE_VBR) && !defined(DISABLE_FLOAT_API) + case SPEEX_SET_VBR_QUALITY: + st->vbr_quality = (*(float*)ptr); + break; + case SPEEX_GET_VBR_QUALITY: + (*(float*)ptr) = st->vbr_quality; + break; +#endif /* !defined(DISABLE_VBR) && !defined(DISABLE_FLOAT_API) */ + case SPEEX_SET_QUALITY: + { + int quality = (*(spx_int32_t*)ptr); + if (quality < 0) + quality = 0; + if (quality > 10) + quality = 10; + st->submodeSelect = st->submodeID = ((const SpeexNBMode*)(st->mode->mode))->quality_map[quality]; + } + break; + case SPEEX_SET_COMPLEXITY: + st->complexity = (*(spx_int32_t*)ptr); + if (st->complexity<0) + st->complexity=0; + break; + case SPEEX_GET_COMPLEXITY: + (*(spx_int32_t*)ptr) = st->complexity; + break; + case SPEEX_SET_BITRATE: + { + spx_int32_t i=10; + spx_int32_t rate, target; + target = (*(spx_int32_t*)ptr); + while (i>=0) + { + speex_encoder_ctl(st, SPEEX_SET_QUALITY, &i); + speex_encoder_ctl(st, SPEEX_GET_BITRATE, &rate); + if (rate <= target) + break; + i--; + } + } + break; + case SPEEX_GET_BITRATE: + if (st->submodes[st->submodeID]) + (*(spx_int32_t*)ptr) = st->sampling_rate*SUBMODE(bits_per_frame)/st->frameSize; + else + (*(spx_int32_t*)ptr) = st->sampling_rate*(NB_SUBMODE_BITS+1)/st->frameSize; + break; + case SPEEX_SET_SAMPLING_RATE: + st->sampling_rate = (*(spx_int32_t*)ptr); + break; + case SPEEX_GET_SAMPLING_RATE: + (*(spx_int32_t*)ptr)=st->sampling_rate; + break; + case SPEEX_RESET_STATE: + { + int i; + st->bounded_pitch = 1; + st->first = 1; + for (i=0;ilpcSize;i++) + st->old_lsp[i]= DIV32(MULT16_16(QCONST16(3.1415927f, LSP_SHIFT), i+1), st->lpcSize+1); + for (i=0;ilpcSize;i++) + st->mem_sw[i]=st->mem_sw_whole[i]=st->mem_sp[i]=st->mem_exc[i]=0; + for (i=0;iframeSize+st->max_pitch+1;i++) + st->excBuf[i]=st->swBuf[i]=0; + for (i=0;iwindowSize-st->frameSize;i++) + st->winBuf[i]=0; + } + break; + case SPEEX_SET_SUBMODE_ENCODING: + st->encode_submode = (*(spx_int32_t*)ptr); + break; + case SPEEX_GET_SUBMODE_ENCODING: + (*(spx_int32_t*)ptr) = st->encode_submode; + break; + case SPEEX_GET_LOOKAHEAD: + (*(spx_int32_t*)ptr)=(st->windowSize-st->frameSize); + break; + case SPEEX_SET_PLC_TUNING: + st->plc_tuning = (*(spx_int32_t*)ptr); + if (st->plc_tuning>100) + st->plc_tuning=100; + break; + case SPEEX_GET_PLC_TUNING: + (*(spx_int32_t*)ptr)=(st->plc_tuning); + break; +#ifndef DISABLE_VBR + case SPEEX_SET_VBR_MAX_BITRATE: + st->vbr_max = (*(spx_int32_t*)ptr); + break; + case SPEEX_GET_VBR_MAX_BITRATE: + (*(spx_int32_t*)ptr) = st->vbr_max; + break; +#endif /* #ifndef DISABLE_VBR */ + case SPEEX_SET_HIGHPASS: + st->highpass_enabled = (*(spx_int32_t*)ptr); + break; + case SPEEX_GET_HIGHPASS: + (*(spx_int32_t*)ptr) = st->highpass_enabled; + break; + + /* This is all internal stuff past this point */ + case SPEEX_GET_PI_GAIN: + { + int i; + spx_word32_t *g = (spx_word32_t*)ptr; + for (i=0;inbSubframes;i++) + g[i]=st->pi_gain[i]; + } + break; + case SPEEX_GET_EXC: + { + int i; + for (i=0;inbSubframes;i++) + ((spx_word16_t*)ptr)[i] = compute_rms16(st->exc+i*st->subframeSize, st->subframeSize); + } + break; +#ifndef DISABLE_VBR + case SPEEX_GET_RELATIVE_QUALITY: + (*(float*)ptr)=st->relative_quality; + break; +#endif /* #ifndef DISABLE_VBR */ + case SPEEX_SET_INNOVATION_SAVE: + st->innov_rms_save = (spx_word16_t*)ptr; + break; + case SPEEX_SET_WIDEBAND: + st->isWideband = *((spx_int32_t*)ptr); + break; + case SPEEX_GET_STACK: + *((char**)ptr) = st->stack; + break; + default: + speex_warning_int("Unknown nb_ctl request: ", request); + return -1; + } + return 0; +} + +int nb_decoder_ctl(void *state, int request, void *ptr) +{ + DecState *st; + st=(DecState*)state; + switch(request) + { + case SPEEX_SET_LOW_MODE: + case SPEEX_SET_MODE: + st->submodeID = (*(spx_int32_t*)ptr); + break; + case SPEEX_GET_LOW_MODE: + case SPEEX_GET_MODE: + (*(spx_int32_t*)ptr) = st->submodeID; + break; + case SPEEX_SET_ENH: + st->lpc_enh_enabled = *((spx_int32_t*)ptr); + break; + case SPEEX_GET_ENH: + *((spx_int32_t*)ptr) = st->lpc_enh_enabled; + break; + case SPEEX_GET_FRAME_SIZE: + (*(spx_int32_t*)ptr) = st->frameSize; + break; + case SPEEX_GET_BITRATE: + if (st->submodes[st->submodeID]) + (*(spx_int32_t*)ptr) = st->sampling_rate*SUBMODE(bits_per_frame)/st->frameSize; + else + (*(spx_int32_t*)ptr) = st->sampling_rate*(NB_SUBMODE_BITS+1)/st->frameSize; + break; + case SPEEX_SET_SAMPLING_RATE: + st->sampling_rate = (*(spx_int32_t*)ptr); + break; + case SPEEX_GET_SAMPLING_RATE: + (*(spx_int32_t*)ptr)=st->sampling_rate; + break; + case SPEEX_SET_HANDLER: + { + SpeexCallback *c = (SpeexCallback*)ptr; + st->speex_callbacks[c->callback_id].func=c->func; + st->speex_callbacks[c->callback_id].data=c->data; + st->speex_callbacks[c->callback_id].callback_id=c->callback_id; + } + break; + case SPEEX_SET_USER_HANDLER: + { + SpeexCallback *c = (SpeexCallback*)ptr; + st->user_callback.func=c->func; + st->user_callback.data=c->data; + st->user_callback.callback_id=c->callback_id; + } + break; + case SPEEX_RESET_STATE: + { + int i; + for (i=0;ilpcSize;i++) + st->mem_sp[i]=0; + for (i=0;iframeSize + st->max_pitch + 1;i++) + st->excBuf[i]=0; + } + break; + case SPEEX_SET_SUBMODE_ENCODING: + st->encode_submode = (*(spx_int32_t*)ptr); + break; + case SPEEX_GET_SUBMODE_ENCODING: + (*(spx_int32_t*)ptr) = st->encode_submode; + break; + case SPEEX_GET_LOOKAHEAD: + (*(spx_int32_t*)ptr)=st->subframeSize; + break; + case SPEEX_SET_HIGHPASS: + st->highpass_enabled = (*(spx_int32_t*)ptr); + break; + case SPEEX_GET_HIGHPASS: + (*(spx_int32_t*)ptr) = st->highpass_enabled; + break; + /* FIXME: Convert to fixed-point and re-enable even when float API is disabled */ +#ifndef DISABLE_FLOAT_API + case SPEEX_GET_ACTIVITY: + { + float ret; + ret = log(st->level/st->min_level)/log(st->max_level/st->min_level); + if (ret>1) + ret = 1; + /* Done in a strange way to catch NaNs as well */ + if (!(ret > 0)) + ret = 0; + /*printf ("%f %f %f %f\n", st->level, st->min_level, st->max_level, ret);*/ + (*(spx_int32_t*)ptr) = (int)(100*ret); + } + break; +#endif + case SPEEX_GET_PI_GAIN: + { + int i; + spx_word32_t *g = (spx_word32_t*)ptr; + for (i=0;inbSubframes;i++) + g[i]=st->pi_gain[i]; + } + break; + case SPEEX_GET_EXC: + { + int i; + for (i=0;inbSubframes;i++) + ((spx_word16_t*)ptr)[i] = compute_rms16(st->exc+i*st->subframeSize, st->subframeSize); + } + break; + case SPEEX_GET_DTX_STATUS: + *((spx_int32_t*)ptr) = st->dtx_enabled; + break; + case SPEEX_SET_INNOVATION_SAVE: + st->innov_save = (spx_word16_t*)ptr; + break; + case SPEEX_SET_WIDEBAND: + st->isWideband = *((spx_int32_t*)ptr); + break; + case SPEEX_GET_STACK: + *((char**)ptr) = st->stack; + break; + default: + speex_warning_int("Unknown nb_ctl request: ", request); + return -1; + } + return 0; +} diff --git a/android/app/src/main/jni/libspeex/nb_celp.h b/android/app/src/main/jni/libspeex/nb_celp.h new file mode 100644 index 000000000..14c776ff3 --- /dev/null +++ b/android/app/src/main/jni/libspeex/nb_celp.h @@ -0,0 +1,203 @@ +/* Copyright (C) 2002-2006 Jean-Marc Valin */ +/** + @file nb_celp.h + @brief Narrowband CELP encoder/decoder +*/ +/* + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + - Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + - Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + - Neither the name of the Xiph.org Foundation nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR + CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +*/ + +#ifndef NB_CELP_H +#define NB_CELP_H + +#include "modes.h" +#include +#include +#include "vbr.h" +#include "filters.h" + +#ifdef VORBIS_PSYCHO +#include "vorbis_psy.h" +#endif + +/**Structure representing the full state of the narrowband encoder*/ +typedef struct EncState { + const SpeexMode *mode; /**< Mode corresponding to the state */ + int first; /**< Is this the first frame? */ + int frameSize; /**< Size of frames */ + int subframeSize; /**< Size of sub-frames */ + int nbSubframes; /**< Number of sub-frames */ + int windowSize; /**< Analysis (LPC) window length */ + int lpcSize; /**< LPC order */ + int min_pitch; /**< Minimum pitch value allowed */ + int max_pitch; /**< Maximum pitch value allowed */ + + spx_word32_t cumul_gain; /**< Product of previously used pitch gains (Q10) */ + int bounded_pitch; /**< Next frame should not rely on previous frames for pitch */ + int ol_pitch; /**< Open-loop pitch */ + int ol_voiced; /**< Open-loop voiced/non-voiced decision */ + int *pitch; + +#ifdef VORBIS_PSYCHO + VorbisPsy *psy; + float *psy_window; + float *curve; + float *old_curve; +#endif + + spx_word16_t gamma1; /**< Perceptual filter: A(z/gamma1) */ + spx_word16_t gamma2; /**< Perceptual filter: A(z/gamma2) */ + spx_word16_t lpc_floor; /**< Noise floor multiplier for A[0] in LPC analysis*/ + char *stack; /**< Pseudo-stack allocation for temporary memory */ + spx_word16_t *winBuf; /**< Input buffer (original signal) */ + spx_word16_t *excBuf; /**< Excitation buffer */ + spx_word16_t *exc; /**< Start of excitation frame */ + spx_word16_t *swBuf; /**< Weighted signal buffer */ + spx_word16_t *sw; /**< Start of weighted signal frame */ + const spx_word16_t *window; /**< Temporary (Hanning) window */ + const spx_word16_t *lagWindow; /**< Window applied to auto-correlation */ + spx_lsp_t *old_lsp; /**< LSPs for previous frame */ + spx_lsp_t *old_qlsp; /**< Quantized LSPs for previous frame */ + spx_mem_t *mem_sp; /**< Filter memory for signal synthesis */ + spx_mem_t *mem_sw; /**< Filter memory for perceptually-weighted signal */ + spx_mem_t *mem_sw_whole; /**< Filter memory for perceptually-weighted signal (whole frame)*/ + spx_mem_t *mem_exc; /**< Filter memory for excitation (whole frame) */ + spx_mem_t *mem_exc2; /**< Filter memory for excitation (whole frame) */ + spx_mem_t mem_hp[2]; /**< High-pass filter memory */ + spx_word32_t *pi_gain; /**< Gain of LPC filter at theta=pi (fe/2) */ + spx_word16_t *innov_rms_save; /**< If non-NULL, innovation RMS is copied here */ + +#ifndef DISABLE_VBR + VBRState *vbr; /**< State of the VBR data */ + float vbr_quality; /**< Quality setting for VBR encoding */ + float relative_quality; /**< Relative quality that will be needed by VBR */ + spx_int32_t vbr_enabled; /**< 1 for enabling VBR, 0 otherwise */ + spx_int32_t vbr_max; /**< Max bit-rate allowed in VBR mode */ + int vad_enabled; /**< 1 for enabling VAD, 0 otherwise */ + int dtx_enabled; /**< 1 for enabling DTX, 0 otherwise */ + int dtx_count; /**< Number of consecutive DTX frames */ + spx_int32_t abr_enabled; /**< ABR setting (in bps), 0 if off */ + float abr_drift; + float abr_drift2; + float abr_count; +#endif /* #ifndef DISABLE_VBR */ + + int complexity; /**< Complexity setting (0-10 from least complex to most complex) */ + spx_int32_t sampling_rate; + int plc_tuning; + int encode_submode; + const SpeexSubmode * const *submodes; /**< Sub-mode data */ + int submodeID; /**< Activated sub-mode */ + int submodeSelect; /**< Mode chosen by the user (may differ from submodeID if VAD is on) */ + int isWideband; /**< Is this used as part of the embedded wideband codec */ + int highpass_enabled; /**< Is the input filter enabled */ +} EncState; + +/**Structure representing the full state of the narrowband decoder*/ +typedef struct DecState { + const SpeexMode *mode; /**< Mode corresponding to the state */ + int first; /**< Is this the first frame? */ + int count_lost; /**< Was the last frame lost? */ + int frameSize; /**< Size of frames */ + int subframeSize; /**< Size of sub-frames */ + int nbSubframes; /**< Number of sub-frames */ + int lpcSize; /**< LPC order */ + int min_pitch; /**< Minimum pitch value allowed */ + int max_pitch; /**< Maximum pitch value allowed */ + spx_int32_t sampling_rate; + + spx_word16_t last_ol_gain; /**< Open-loop gain for previous frame */ + + char *stack; /**< Pseudo-stack allocation for temporary memory */ + spx_word16_t *excBuf; /**< Excitation buffer */ + spx_word16_t *exc; /**< Start of excitation frame */ + spx_lsp_t *old_qlsp; /**< Quantized LSPs for previous frame */ + spx_coef_t *interp_qlpc; /**< Interpolated quantized LPCs */ + spx_mem_t *mem_sp; /**< Filter memory for synthesis signal */ + spx_mem_t mem_hp[2]; /**< High-pass filter memory */ + spx_word32_t *pi_gain; /**< Gain of LPC filter at theta=pi (fe/2) */ + spx_word16_t *innov_save; /** If non-NULL, innovation is copied here */ + + spx_word16_t level; + spx_word16_t max_level; + spx_word16_t min_level; + + /* This is used in packet loss concealment */ + int last_pitch; /**< Pitch of last correctly decoded frame */ + spx_word16_t last_pitch_gain; /**< Pitch gain of last correctly decoded frame */ + spx_word16_t pitch_gain_buf[3]; /**< Pitch gain of last decoded frames */ + int pitch_gain_buf_idx; /**< Tail of the buffer */ + spx_int32_t seed; /** Seed used for random number generation */ + + int encode_submode; + const SpeexSubmode * const *submodes; /**< Sub-mode data */ + int submodeID; /**< Activated sub-mode */ + int lpc_enh_enabled; /**< 1 when LPC enhancer is on, 0 otherwise */ + SpeexCallback speex_callbacks[SPEEX_MAX_CALLBACKS]; + + SpeexCallback user_callback; + + /*Vocoder data*/ + spx_word16_t voc_m1; + spx_word32_t voc_m2; + spx_word16_t voc_mean; + int voc_offset; + + int dtx_enabled; + int isWideband; /**< Is this used as part of the embedded wideband codec */ + int highpass_enabled; /**< Is the input filter enabled */ +} DecState; + +/** Initializes encoder state*/ +void *nb_encoder_init(const SpeexMode *m); + +/** De-allocates encoder state resources*/ +void nb_encoder_destroy(void *state); + +/** Encodes one frame*/ +int nb_encode(void *state, void *in, SpeexBits *bits); + + +/** Initializes decoder state*/ +void *nb_decoder_init(const SpeexMode *m); + +/** De-allocates decoder state resources*/ +void nb_decoder_destroy(void *state); + +/** Decodes one frame*/ +int nb_decode(void *state, SpeexBits *bits, void *out); + +/** ioctl-like function for controlling a narrowband encoder */ +int nb_encoder_ctl(void *state, int request, void *ptr); + +/** ioctl-like function for controlling a narrowband decoder */ +int nb_decoder_ctl(void *state, int request, void *ptr); + + +#endif diff --git a/android/app/src/main/jni/libspeex/os_support.h b/android/app/src/main/jni/libspeex/os_support.h new file mode 100644 index 000000000..6b74b0c22 --- /dev/null +++ b/android/app/src/main/jni/libspeex/os_support.h @@ -0,0 +1,169 @@ +/* Copyright (C) 2007 Jean-Marc Valin + + File: os_support.h + This is the (tiny) OS abstraction layer. Aside from math.h, this is the + only place where system headers are allowed. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are + met: + + 1. Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + 3. The name of the author may not be used to endorse or promote products + derived from this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, + INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + POSSIBILITY OF SUCH DAMAGE. +*/ + +#ifndef OS_SUPPORT_H +#define OS_SUPPORT_H + +#include +#include +#include + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif +#ifdef OS_SUPPORT_CUSTOM +#include "os_support_custom.h" +#endif + +/** Speex wrapper for calloc. To do your own dynamic allocation, all you need to do is replace this function, speex_realloc and speex_free + NOTE: speex_alloc needs to CLEAR THE MEMORY */ +#ifndef OVERRIDE_SPEEX_ALLOC +static inline void *speex_alloc (int size) +{ + /* WARNING: this is not equivalent to malloc(). If you want to use malloc() + or your own allocator, YOU NEED TO CLEAR THE MEMORY ALLOCATED. Otherwise + you will experience strange bugs */ + return calloc(size,1); +} +#endif + +/** Same as speex_alloc, except that the area is only needed inside a Speex call (might cause problem with wideband though) */ +#ifndef OVERRIDE_SPEEX_ALLOC_SCRATCH +static inline void *speex_alloc_scratch (int size) +{ + /* Scratch space doesn't need to be cleared */ + return calloc(size,1); +} +#endif + +/** Speex wrapper for realloc. To do your own dynamic allocation, all you need to do is replace this function, speex_alloc and speex_free */ +#ifndef OVERRIDE_SPEEX_REALLOC +static inline void *speex_realloc (void *ptr, int size) +{ + return realloc(ptr, size); +} +#endif + +/** Speex wrapper for calloc. To do your own dynamic allocation, all you need to do is replace this function, speex_realloc and speex_alloc */ +#ifndef OVERRIDE_SPEEX_FREE +static inline void speex_free (void *ptr) +{ + free(ptr); +} +#endif + +/** Same as speex_free, except that the area is only needed inside a Speex call (might cause problem with wideband though) */ +#ifndef OVERRIDE_SPEEX_FREE_SCRATCH +static inline void speex_free_scratch (void *ptr) +{ + free(ptr); +} +#endif + +/** Copy n bytes of memory from src to dst. The 0* term provides compile-time type checking */ +#ifndef OVERRIDE_SPEEX_COPY +#define SPEEX_COPY(dst, src, n) (memcpy((dst), (src), (n)*sizeof(*(dst)) + 0*((dst)-(src)) )) +#endif + +/** Copy n bytes of memory from src to dst, allowing overlapping regions. The 0* term + provides compile-time type checking */ +#ifndef OVERRIDE_SPEEX_MOVE +#define SPEEX_MOVE(dst, src, n) (memmove((dst), (src), (n)*sizeof(*(dst)) + 0*((dst)-(src)) )) +#endif + +/** Set n bytes of memory to value of c, starting at address s */ +#ifndef OVERRIDE_SPEEX_MEMSET +#define SPEEX_MEMSET(dst, c, n) (memset((dst), (c), (n)*sizeof(*(dst)))) +#endif + + +#ifndef OVERRIDE_SPEEX_FATAL +static inline void _speex_fatal(const char *str, const char *file, int line) +{ + fprintf (stderr, "Fatal (internal) error in %s, line %d: %s\n", file, line, str); + exit(1); +} +#endif + +#ifndef OVERRIDE_SPEEX_WARNING +static inline void speex_warning(const char *str) +{ +#ifndef DISABLE_WARNINGS + fprintf (stderr, "warning: %s\n", str); +#endif +} +#endif + +#ifndef OVERRIDE_SPEEX_WARNING_INT +static inline void speex_warning_int(const char *str, int val) +{ +#ifndef DISABLE_WARNINGS + fprintf (stderr, "warning: %s %d\n", str, val); +#endif +} +#endif + +#ifndef OVERRIDE_SPEEX_NOTIFY +static inline void speex_notify(const char *str) +{ +#ifndef DISABLE_NOTIFICATIONS + fprintf (stderr, "notification: %s\n", str); +#endif +} +#endif + +#ifndef OVERRIDE_SPEEX_PUTC +/** Speex wrapper for putc */ +static inline void _speex_putc(int ch, void *file) +{ + FILE *f = (FILE *)file; + fprintf(f, "%c", ch); +} +#endif + +#define speex_fatal(str) _speex_fatal(str, __FILE__, __LINE__); +#define speex_assert(cond) {if (!(cond)) {speex_fatal("assertion failed: " #cond);}} + +#ifndef RELEASE +static inline void print_vec(float *vec, int len, char *name) +{ + int i; + printf ("%s ", name); + for (i=0;i +#include "speex/speex_preprocess.h" +#include "speex/speex_echo.h" +#include "arch.h" +#include "fftwrap.h" +#include "filterbank.h" +#include "math_approx.h" +#include "os_support.h" + +#ifndef M_PI +#define M_PI 3.14159263 +#endif + +#define LOUDNESS_EXP 5.f +#define AMP_SCALE .001f +#define AMP_SCALE_1 1000.f + +#define NB_BANDS 24 + +#define SPEECH_PROB_START_DEFAULT QCONST16(0.35f,15) +#define SPEECH_PROB_CONTINUE_DEFAULT QCONST16(0.20f,15) +#define NOISE_SUPPRESS_DEFAULT -15 +#define ECHO_SUPPRESS_DEFAULT -40 +#define ECHO_SUPPRESS_ACTIVE_DEFAULT -15 + +#ifndef NULL +#define NULL 0 +#endif + +#define SQR(x) ((x)*(x)) +#define SQR16(x) (MULT16_16((x),(x))) +#define SQR16_Q15(x) (MULT16_16_Q15((x),(x))) + +#ifdef FIXED_POINT +static inline spx_word16_t DIV32_16_Q8(spx_word32_t a, spx_word32_t b) +{ + if (SHR32(a,7) >= b) + { + return 32767; + } else { + if (b>=QCONST32(1,23)) + { + a = SHR32(a,8); + b = SHR32(b,8); + } + if (b>=QCONST32(1,19)) + { + a = SHR32(a,4); + b = SHR32(b,4); + } + if (b>=QCONST32(1,15)) + { + a = SHR32(a,4); + b = SHR32(b,4); + } + a = SHL32(a,8); + return PDIV32_16(a,b); + } + +} +static inline spx_word16_t DIV32_16_Q15(spx_word32_t a, spx_word32_t b) +{ + if (SHR32(a,15) >= b) + { + return 32767; + } else { + if (b>=QCONST32(1,23)) + { + a = SHR32(a,8); + b = SHR32(b,8); + } + if (b>=QCONST32(1,19)) + { + a = SHR32(a,4); + b = SHR32(b,4); + } + if (b>=QCONST32(1,15)) + { + a = SHR32(a,4); + b = SHR32(b,4); + } + a = SHL32(a,15)-a; + return DIV32_16(a,b); + } +} +#define SNR_SCALING 256.f +#define SNR_SCALING_1 0.0039062f +#define SNR_SHIFT 8 + +#define FRAC_SCALING 32767.f +#define FRAC_SCALING_1 3.0518e-05 +#define FRAC_SHIFT 1 + +#define EXPIN_SCALING 2048.f +#define EXPIN_SCALING_1 0.00048828f +#define EXPIN_SHIFT 11 +#define EXPOUT_SCALING_1 1.5259e-05 + +#define NOISE_SHIFT 7 + +#else + +#define DIV32_16_Q8(a,b) ((a)/(b)) +#define DIV32_16_Q15(a,b) ((a)/(b)) +#define SNR_SCALING 1.f +#define SNR_SCALING_1 1.f +#define SNR_SHIFT 0 +#define FRAC_SCALING 1.f +#define FRAC_SCALING_1 1.f +#define FRAC_SHIFT 0 +#define NOISE_SHIFT 0 + +#define EXPIN_SCALING 1.f +#define EXPIN_SCALING_1 1.f +#define EXPOUT_SCALING_1 1.f + +#endif + +/** Speex pre-processor state. */ +struct SpeexPreprocessState_ { + /* Basic info */ + int frame_size; /**< Number of samples processed each time */ + int ps_size; /**< Number of points in the power spectrum */ + int sampling_rate; /**< Sampling rate of the input/output */ + int nbands; + FilterBank *bank; + + /* Parameters */ + int denoise_enabled; + int vad_enabled; + int dereverb_enabled; + spx_word16_t reverb_decay; + spx_word16_t reverb_level; + spx_word16_t speech_prob_start; + spx_word16_t speech_prob_continue; + int noise_suppress; + int echo_suppress; + int echo_suppress_active; + SpeexEchoState *echo_state; + + spx_word16_t speech_prob; /**< Probability last frame was speech */ + + /* DSP-related arrays */ + spx_word16_t *frame; /**< Processing frame (2*ps_size) */ + spx_word16_t *ft; /**< Processing frame in freq domain (2*ps_size) */ + spx_word32_t *ps; /**< Current power spectrum */ + spx_word16_t *gain2; /**< Adjusted gains */ + spx_word16_t *gain_floor; /**< Minimum gain allowed */ + spx_word16_t *window; /**< Analysis/Synthesis window */ + spx_word32_t *noise; /**< Noise estimate */ + spx_word32_t *reverb_estimate; /**< Estimate of reverb energy */ + spx_word32_t *old_ps; /**< Power spectrum for last frame */ + spx_word16_t *gain; /**< Ephraim Malah gain */ + spx_word16_t *prior; /**< A-priori SNR */ + spx_word16_t *post; /**< A-posteriori SNR */ + + spx_word32_t *S; /**< Smoothed power spectrum */ + spx_word32_t *Smin; /**< See Cohen paper */ + spx_word32_t *Stmp; /**< See Cohen paper */ + int *update_prob; /**< Probability of speech presence for noise update */ + + spx_word16_t *zeta; /**< Smoothed a priori SNR */ + spx_word32_t *echo_noise; + spx_word32_t *residual_echo; + + /* Misc */ + spx_word16_t *inbuf; /**< Input buffer (overlapped analysis) */ + spx_word16_t *outbuf; /**< Output buffer (for overlap and add) */ + + /* AGC stuff, only for floating point for now */ +#ifndef FIXED_POINT + int agc_enabled; + float agc_level; + float loudness_accum; + float *loudness_weight; /**< Perceptual loudness curve */ + float loudness; /**< Loudness estimate */ + float agc_gain; /**< Current AGC gain */ + float max_gain; /**< Maximum gain allowed */ + float max_increase_step; /**< Maximum increase in gain from one frame to another */ + float max_decrease_step; /**< Maximum decrease in gain from one frame to another */ + float prev_loudness; /**< Loudness of previous frame */ + float init_max; /**< Current gain limit during initialisation */ +#endif + int nb_adapt; /**< Number of frames used for adaptation so far */ + int was_speech; + int min_count; /**< Number of frames processed so far */ + void *fft_lookup; /**< Lookup table for the FFT */ +#ifdef FIXED_POINT + int frame_shift; +#endif +}; + + +static void conj_window(spx_word16_t *w, int len) +{ + int i; + for (i=0;i19) + return ADD32(EXTEND32(Q15_ONE),EXTEND32(DIV32_16(QCONST32(.1296,23), SHR32(xx,EXPIN_SHIFT-SNR_SHIFT)))); + frac = SHL32(xx-SHL32(ind,10),5); + return SHL32(DIV32_16(PSHR32(MULT16_16(Q15_ONE-frac,table[ind]) + MULT16_16(frac,table[ind+1]),7),(spx_sqrt(SHL32(xx,15)+6711))),7); +} + +static inline spx_word16_t qcurve(spx_word16_t x) +{ + x = MAX16(x, 1); + return DIV32_16(SHL32(EXTEND32(32767),9),ADD16(512,MULT16_16_Q15(QCONST16(.60f,15),DIV32_16(32767,x)))); +} + +/* Compute the gain floor based on different floors for the background noise and residual echo */ +static void compute_gain_floor(int noise_suppress, int effective_echo_suppress, spx_word32_t *noise, spx_word32_t *echo, spx_word16_t *gain_floor, int len) +{ + int i; + + if (noise_suppress > effective_echo_suppress) + { + spx_word16_t noise_gain, gain_ratio; + noise_gain = EXTRACT16(MIN32(Q15_ONE,SHR32(spx_exp(MULT16_16(QCONST16(0.11513,11),noise_suppress)),1))); + gain_ratio = EXTRACT16(MIN32(Q15_ONE,SHR32(spx_exp(MULT16_16(QCONST16(.2302585f,11),effective_echo_suppress-noise_suppress)),1))); + + /* gain_floor = sqrt [ (noise*noise_floor + echo*echo_floor) / (noise+echo) ] */ + for (i=0;i19) + return FRAC_SCALING*(1+.1296/x); + frac = 2*x-integer; + return FRAC_SCALING*((1-frac)*table[ind] + frac*table[ind+1])/sqrt(x+.0001f); +} + +static inline spx_word16_t qcurve(spx_word16_t x) +{ + return 1.f/(1.f+.15f/(SNR_SCALING_1*x)); +} + +static void compute_gain_floor(int noise_suppress, int effective_echo_suppress, spx_word32_t *noise, spx_word32_t *echo, spx_word16_t *gain_floor, int len) +{ + int i; + float echo_floor; + float noise_floor; + + noise_floor = exp(.2302585f*noise_suppress); + echo_floor = exp(.2302585f*effective_echo_suppress); + + /* Compute the gain floor based on different floors for the background noise and residual echo */ + for (i=0;iframe_size = frame_size; + + /* Round ps_size down to the nearest power of two */ +#if 0 + i=1; + st->ps_size = st->frame_size; + while(1) + { + if (st->ps_size & ~i) + { + st->ps_size &= ~i; + i<<=1; + } else { + break; + } + } + + + if (st->ps_size < 3*st->frame_size/4) + st->ps_size = st->ps_size * 3 / 2; +#else + st->ps_size = st->frame_size; +#endif + + N = st->ps_size; + N3 = 2*N - st->frame_size; + N4 = st->frame_size - N3; + + st->sampling_rate = sampling_rate; + st->denoise_enabled = 1; + st->vad_enabled = 0; + st->dereverb_enabled = 0; + st->reverb_decay = 0; + st->reverb_level = 0; + st->noise_suppress = NOISE_SUPPRESS_DEFAULT; + st->echo_suppress = ECHO_SUPPRESS_DEFAULT; + st->echo_suppress_active = ECHO_SUPPRESS_ACTIVE_DEFAULT; + + st->speech_prob_start = SPEECH_PROB_START_DEFAULT; + st->speech_prob_continue = SPEECH_PROB_CONTINUE_DEFAULT; + + st->echo_state = NULL; + + st->nbands = NB_BANDS; + M = st->nbands; + st->bank = filterbank_new(M, sampling_rate, N, 1); + + st->frame = (spx_word16_t*)speex_alloc(2*N*sizeof(spx_word16_t)); + st->window = (spx_word16_t*)speex_alloc(2*N*sizeof(spx_word16_t)); + st->ft = (spx_word16_t*)speex_alloc(2*N*sizeof(spx_word16_t)); + + st->ps = (spx_word32_t*)speex_alloc((N+M)*sizeof(spx_word32_t)); + st->noise = (spx_word32_t*)speex_alloc((N+M)*sizeof(spx_word32_t)); + st->echo_noise = (spx_word32_t*)speex_alloc((N+M)*sizeof(spx_word32_t)); + st->residual_echo = (spx_word32_t*)speex_alloc((N+M)*sizeof(spx_word32_t)); + st->reverb_estimate = (spx_word32_t*)speex_alloc((N+M)*sizeof(spx_word32_t)); + st->old_ps = (spx_word32_t*)speex_alloc((N+M)*sizeof(spx_word32_t)); + st->prior = (spx_word16_t*)speex_alloc((N+M)*sizeof(spx_word16_t)); + st->post = (spx_word16_t*)speex_alloc((N+M)*sizeof(spx_word16_t)); + st->gain = (spx_word16_t*)speex_alloc((N+M)*sizeof(spx_word16_t)); + st->gain2 = (spx_word16_t*)speex_alloc((N+M)*sizeof(spx_word16_t)); + st->gain_floor = (spx_word16_t*)speex_alloc((N+M)*sizeof(spx_word16_t)); + st->zeta = (spx_word16_t*)speex_alloc((N+M)*sizeof(spx_word16_t)); + + st->S = (spx_word32_t*)speex_alloc(N*sizeof(spx_word32_t)); + st->Smin = (spx_word32_t*)speex_alloc(N*sizeof(spx_word32_t)); + st->Stmp = (spx_word32_t*)speex_alloc(N*sizeof(spx_word32_t)); + st->update_prob = (int*)speex_alloc(N*sizeof(int)); + + st->inbuf = (spx_word16_t*)speex_alloc(N3*sizeof(spx_word16_t)); + st->outbuf = (spx_word16_t*)speex_alloc(N3*sizeof(spx_word16_t)); + + conj_window(st->window, 2*N3); + for (i=2*N3;i<2*st->ps_size;i++) + st->window[i]=Q15_ONE; + + if (N4>0) + { + for (i=N3-1;i>=0;i--) + { + st->window[i+N3+N4]=st->window[i+N3]; + st->window[i+N3]=1; + } + } + for (i=0;inoise[i]=QCONST32(1.f,NOISE_SHIFT); + st->reverb_estimate[i]=0; + st->old_ps[i]=1; + st->gain[i]=Q15_ONE; + st->post[i]=SHL16(1, SNR_SHIFT); + st->prior[i]=SHL16(1, SNR_SHIFT); + } + + for (i=0;iupdate_prob[i] = 1; + for (i=0;iinbuf[i]=0; + st->outbuf[i]=0; + } +#ifndef FIXED_POINT + st->agc_enabled = 0; + st->agc_level = 8000; + st->loudness_weight = (float*)speex_alloc(N*sizeof(float)); + for (i=0;iloudness_weight[i] = .5f*(1.f/(1.f+ff/8000.f))+1.f*exp(-.5f*(ff-3800.f)*(ff-3800.f)/9e5f);*/ + st->loudness_weight[i] = .35f-.35f*ff/16000.f+.73f*exp(-.5f*(ff-3800)*(ff-3800)/9e5f); + if (st->loudness_weight[i]<.01f) + st->loudness_weight[i]=.01f; + st->loudness_weight[i] *= st->loudness_weight[i]; + } + /*st->loudness = pow(AMP_SCALE*st->agc_level,LOUDNESS_EXP);*/ + st->loudness = 1e-15; + st->agc_gain = 1; + st->max_gain = 30; + st->max_increase_step = exp(0.11513f * 12.*st->frame_size / st->sampling_rate); + st->max_decrease_step = exp(-0.11513f * 40.*st->frame_size / st->sampling_rate); + st->prev_loudness = 1; + st->init_max = 1; +#endif + st->was_speech = 0; + + st->fft_lookup = spx_fft_init(2*N); + + st->nb_adapt=0; + st->min_count=0; + return st; +} + +EXPORT void speex_preprocess_state_destroy(SpeexPreprocessState *st) +{ + speex_free(st->frame); + speex_free(st->ft); + speex_free(st->ps); + speex_free(st->gain2); + speex_free(st->gain_floor); + speex_free(st->window); + speex_free(st->noise); + speex_free(st->reverb_estimate); + speex_free(st->old_ps); + speex_free(st->gain); + speex_free(st->prior); + speex_free(st->post); +#ifndef FIXED_POINT + speex_free(st->loudness_weight); +#endif + speex_free(st->echo_noise); + speex_free(st->residual_echo); + + speex_free(st->S); + speex_free(st->Smin); + speex_free(st->Stmp); + speex_free(st->update_prob); + speex_free(st->zeta); + + speex_free(st->inbuf); + speex_free(st->outbuf); + + spx_fft_destroy(st->fft_lookup); + filterbank_destroy(st->bank); + speex_free(st); +} + +/* FIXME: The AGC doesn't work yet with fixed-point*/ +#ifndef FIXED_POINT +static void speex_compute_agc(SpeexPreprocessState *st, spx_word16_t Pframe, spx_word16_t *ft) +{ + int i; + int N = st->ps_size; + float target_gain; + float loudness=1.f; + float rate; + + for (i=2;ips[i]* st->loudness_weight[i]; + } + loudness=sqrt(loudness); + /*if (loudness < 2*pow(st->loudness, 1.0/LOUDNESS_EXP) && + loudness*2 > pow(st->loudness, 1.0/LOUDNESS_EXP))*/ + if (Pframe>.3f) + { + /*rate=2.0f*Pframe*Pframe/(1+st->nb_loudness_adapt);*/ + rate = .03*Pframe*Pframe; + st->loudness = (1-rate)*st->loudness + (rate)*pow(AMP_SCALE*loudness, LOUDNESS_EXP); + st->loudness_accum = (1-rate)*st->loudness_accum + rate; + if (st->init_max < st->max_gain && st->nb_adapt > 20) + st->init_max *= 1.f + .1f*Pframe*Pframe; + } + /*printf ("%f %f %f %f\n", Pframe, loudness, pow(st->loudness, 1.0f/LOUDNESS_EXP), st->loudness2);*/ + + target_gain = AMP_SCALE*st->agc_level*pow(st->loudness/(1e-4+st->loudness_accum), -1.0f/LOUDNESS_EXP); + + if ((Pframe>.5 && st->nb_adapt > 20) || target_gain < st->agc_gain) + { + if (target_gain > st->max_increase_step*st->agc_gain) + target_gain = st->max_increase_step*st->agc_gain; + if (target_gain < st->max_decrease_step*st->agc_gain && loudness < 10*st->prev_loudness) + target_gain = st->max_decrease_step*st->agc_gain; + if (target_gain > st->max_gain) + target_gain = st->max_gain; + if (target_gain > st->init_max) + target_gain = st->init_max; + + st->agc_gain = target_gain; + } + /*fprintf (stderr, "%f %f %f\n", loudness, (float)AMP_SCALE_1*pow(st->loudness, 1.0f/LOUDNESS_EXP), st->agc_gain);*/ + + for (i=0;i<2*N;i++) + ft[i] *= st->agc_gain; + st->prev_loudness = loudness; +} +#endif + +static void preprocess_analysis(SpeexPreprocessState *st, spx_int16_t *x) +{ + int i; + int N = st->ps_size; + int N3 = 2*N - st->frame_size; + int N4 = st->frame_size - N3; + spx_word32_t *ps=st->ps; + + /* 'Build' input frame */ + for (i=0;iframe[i]=st->inbuf[i]; + for (i=0;iframe_size;i++) + st->frame[N3+i]=x[i]; + + /* Update inbuf */ + for (i=0;iinbuf[i]=x[N4+i]; + + /* Windowing */ + for (i=0;i<2*N;i++) + st->frame[i] = MULT16_16_Q15(st->frame[i], st->window[i]); + +#ifdef FIXED_POINT + { + spx_word16_t max_val=0; + for (i=0;i<2*N;i++) + max_val = MAX16(max_val, ABS16(st->frame[i])); + st->frame_shift = 14-spx_ilog2(EXTEND32(max_val)); + for (i=0;i<2*N;i++) + st->frame[i] = SHL16(st->frame[i], st->frame_shift); + } +#endif + + /* Perform FFT */ + spx_fft(st->fft_lookup, st->frame, st->ft); + + /* Power spectrum */ + ps[0]=MULT16_16(st->ft[0],st->ft[0]); + for (i=1;ift[2*i-1],st->ft[2*i-1]) + MULT16_16(st->ft[2*i],st->ft[2*i]); + for (i=0;ips[i] = PSHR32(st->ps[i], 2*st->frame_shift); + + filterbank_compute_bank32(st->bank, ps, ps+N); +} + +static void update_noise_prob(SpeexPreprocessState *st) +{ + int i; + int min_range; + int N = st->ps_size; + + for (i=1;iS[i] = MULT16_32_Q15(QCONST16(.8f,15),st->S[i]) + MULT16_32_Q15(QCONST16(.05f,15),st->ps[i-1]) + + MULT16_32_Q15(QCONST16(.1f,15),st->ps[i]) + MULT16_32_Q15(QCONST16(.05f,15),st->ps[i+1]); + st->S[0] = MULT16_32_Q15(QCONST16(.8f,15),st->S[0]) + MULT16_32_Q15(QCONST16(.2f,15),st->ps[0]); + st->S[N-1] = MULT16_32_Q15(QCONST16(.8f,15),st->S[N-1]) + MULT16_32_Q15(QCONST16(.2f,15),st->ps[N-1]); + + if (st->nb_adapt==1) + { + for (i=0;iSmin[i] = st->Stmp[i] = 0; + } + + if (st->nb_adapt < 100) + min_range = 15; + else if (st->nb_adapt < 1000) + min_range = 50; + else if (st->nb_adapt < 10000) + min_range = 150; + else + min_range = 300; + if (st->min_count > min_range) + { + st->min_count = 0; + for (i=0;iSmin[i] = MIN32(st->Stmp[i], st->S[i]); + st->Stmp[i] = st->S[i]; + } + } else { + for (i=0;iSmin[i] = MIN32(st->Smin[i], st->S[i]); + st->Stmp[i] = MIN32(st->Stmp[i], st->S[i]); + } + } + for (i=0;iS[i]) > st->Smin[i]) + st->update_prob[i] = 1; + else + st->update_prob[i] = 0; + /*fprintf (stderr, "%f ", st->S[i]/st->Smin[i]);*/ + /*fprintf (stderr, "%f ", st->update_prob[i]);*/ + } + +} + +#define NOISE_OVERCOMPENS 1. + +void speex_echo_get_residual(SpeexEchoState *st, spx_word32_t *Yout, int len); + +EXPORT int speex_preprocess(SpeexPreprocessState *st, spx_int16_t *x, spx_int32_t *echo) +{ + return speex_preprocess_run(st, x); +} + +EXPORT int speex_preprocess_run(SpeexPreprocessState *st, spx_int16_t *x) +{ + int i; + int M; + int N = st->ps_size; + int N3 = 2*N - st->frame_size; + int N4 = st->frame_size - N3; + spx_word32_t *ps=st->ps; + spx_word32_t Zframe; + spx_word16_t Pframe; + spx_word16_t beta, beta_1; + spx_word16_t effective_echo_suppress; + + st->nb_adapt++; + if (st->nb_adapt>20000) + st->nb_adapt = 20000; + st->min_count++; + + beta = MAX16(QCONST16(.03,15),DIV32_16(Q15_ONE,st->nb_adapt)); + beta_1 = Q15_ONE-beta; + M = st->nbands; + /* Deal with residual echo if provided */ + if (st->echo_state) + { + speex_echo_get_residual(st->echo_state, st->residual_echo, N); +#ifndef FIXED_POINT + /* If there are NaNs or ridiculous values, it'll show up in the DC and we just reset everything to zero */ + if (!(st->residual_echo[0] >=0 && st->residual_echo[0]residual_echo[i] = 0; + } +#endif + for (i=0;iecho_noise[i] = MAX32(MULT16_32_Q15(QCONST16(.6f,15),st->echo_noise[i]), st->residual_echo[i]); + filterbank_compute_bank32(st->bank, st->echo_noise, st->echo_noise+N); + } else { + for (i=0;iecho_noise[i] = 0; + } + preprocess_analysis(st, x); + + update_noise_prob(st); + + /* Noise estimation always updated for the 10 first frames */ + /*if (st->nb_adapt<10) + { + for (i=1;iupdate_prob[i] = 0; + } + */ + + /* Update the noise estimate for the frequencies where it can be */ + for (i=0;iupdate_prob[i] || st->ps[i] < PSHR32(st->noise[i], NOISE_SHIFT)) + st->noise[i] = MAX32(EXTEND32(0),MULT16_32_Q15(beta_1,st->noise[i]) + MULT16_32_Q15(beta,SHL32(st->ps[i],NOISE_SHIFT))); + } + filterbank_compute_bank32(st->bank, st->noise, st->noise+N); + + /* Special case for first frame */ + if (st->nb_adapt==1) + for (i=0;iold_ps[i] = ps[i]; + + /* Compute a posteriori SNR */ + for (i=0;inoise[i],NOISE_SHIFT)) , st->echo_noise[i]) , st->reverb_estimate[i]); + + /* A posteriori SNR = ps/noise - 1*/ + st->post[i] = SUB16(DIV32_16_Q8(ps[i],tot_noise), QCONST16(1.f,SNR_SHIFT)); + st->post[i]=MIN16(st->post[i], QCONST16(100.f,SNR_SHIFT)); + + /* Computing update gamma = .1 + .9*(old/(old+noise))^2 */ + gamma = QCONST16(.1f,15)+MULT16_16_Q15(QCONST16(.89f,15),SQR16_Q15(DIV32_16_Q15(st->old_ps[i],ADD32(st->old_ps[i],tot_noise)))); + + /* A priori SNR update = gamma*max(0,post) + (1-gamma)*old/noise */ + st->prior[i] = EXTRACT16(PSHR32(ADD32(MULT16_16(gamma,MAX16(0,st->post[i])), MULT16_16(Q15_ONE-gamma,DIV32_16_Q8(st->old_ps[i],tot_noise))), 15)); + st->prior[i]=MIN16(st->prior[i], QCONST16(100.f,SNR_SHIFT)); + } + + /*print_vec(st->post, N+M, "");*/ + + /* Recursive average of the a priori SNR. A bit smoothed for the psd components */ + st->zeta[0] = PSHR32(ADD32(MULT16_16(QCONST16(.7f,15),st->zeta[0]), MULT16_16(QCONST16(.3f,15),st->prior[0])),15); + for (i=1;izeta[i] = PSHR32(ADD32(ADD32(ADD32(MULT16_16(QCONST16(.7f,15),st->zeta[i]), MULT16_16(QCONST16(.15f,15),st->prior[i])), + MULT16_16(QCONST16(.075f,15),st->prior[i-1])), MULT16_16(QCONST16(.075f,15),st->prior[i+1])),15); + for (i=N-1;izeta[i] = PSHR32(ADD32(MULT16_16(QCONST16(.7f,15),st->zeta[i]), MULT16_16(QCONST16(.3f,15),st->prior[i])),15); + + /* Speech probability of presence for the entire frame is based on the average filterbank a priori SNR */ + Zframe = 0; + for (i=N;izeta[i])); + Pframe = QCONST16(.1f,15)+MULT16_16_Q15(QCONST16(.899f,15),qcurve(DIV32_16(Zframe,st->nbands))); + + effective_echo_suppress = EXTRACT16(PSHR32(ADD32(MULT16_16(SUB16(Q15_ONE,Pframe), st->echo_suppress), MULT16_16(Pframe, st->echo_suppress_active)),15)); + + compute_gain_floor(st->noise_suppress, effective_echo_suppress, st->noise+N, st->echo_noise+N, st->gain_floor+N, M); + + /* Compute Ephraim & Malah gain speech probability of presence for each critical band (Bark scale) + Technically this is actually wrong because the EM gaim assumes a slightly different probability + distribution */ + for (i=N;iprior[i]), 15), ADD16(st->prior[i], SHL32(1,SNR_SHIFT))); + theta = MULT16_32_P15(prior_ratio, QCONST32(1.f,EXPIN_SHIFT)+SHL32(EXTEND32(st->post[i]),EXPIN_SHIFT-SNR_SHIFT)); + + MM = hypergeom_gain(theta); + /* Gain with bound */ + st->gain[i] = EXTRACT16(MIN32(Q15_ONE, MULT16_32_Q15(prior_ratio, MM))); + /* Save old Bark power spectrum */ + st->old_ps[i] = MULT16_32_P15(QCONST16(.2f,15),st->old_ps[i]) + MULT16_32_P15(MULT16_16_P15(QCONST16(.8f,15),SQR16_Q15(st->gain[i])),ps[i]); + + P1 = QCONST16(.199f,15)+MULT16_16_Q15(QCONST16(.8f,15),qcurve (st->zeta[i])); + q = Q15_ONE-MULT16_16_Q15(Pframe,P1); +#ifdef FIXED_POINT + theta = MIN32(theta, EXTEND32(32767)); +/*Q8*/tmp = MULT16_16_Q15((SHL32(1,SNR_SHIFT)+st->prior[i]),EXTRACT16(MIN32(Q15ONE,SHR32(spx_exp(-EXTRACT16(theta)),1)))); + tmp = MIN16(QCONST16(3.,SNR_SHIFT), tmp); /* Prevent overflows in the next line*/ +/*Q8*/tmp = EXTRACT16(PSHR32(MULT16_16(PDIV32_16(SHL32(EXTEND32(q),8),(Q15_ONE-q)),tmp),8)); + st->gain2[i]=DIV32_16(SHL32(EXTEND32(32767),SNR_SHIFT), ADD16(256,tmp)); +#else + st->gain2[i]=1/(1.f + (q/(1.f-q))*(1+st->prior[i])*exp(-theta)); +#endif + } + /* Convert the EM gains and speech prob to linear frequency */ + filterbank_compute_psd16(st->bank,st->gain2+N, st->gain2); + filterbank_compute_psd16(st->bank,st->gain+N, st->gain); + + /* Use 1 for linear gain resolution (best) or 0 for Bark gain resolution (faster) */ + if (1) + { + filterbank_compute_psd16(st->bank,st->gain_floor+N, st->gain_floor); + + /* Compute gain according to the Ephraim-Malah algorithm -- linear frequency */ + for (i=0;iprior[i]), 15), ADD16(st->prior[i], SHL32(1,SNR_SHIFT))); + theta = MULT16_32_P15(prior_ratio, QCONST32(1.f,EXPIN_SHIFT)+SHL32(EXTEND32(st->post[i]),EXPIN_SHIFT-SNR_SHIFT)); + + /* Optimal estimator for loudness domain */ + MM = hypergeom_gain(theta); + /* EM gain with bound */ + g = EXTRACT16(MIN32(Q15_ONE, MULT16_32_Q15(prior_ratio, MM))); + /* Interpolated speech probability of presence */ + p = st->gain2[i]; + + /* Constrain the gain to be close to the Bark scale gain */ + if (MULT16_16_Q15(QCONST16(.333f,15),g) > st->gain[i]) + g = MULT16_16(3,st->gain[i]); + st->gain[i] = g; + + /* Save old power spectrum */ + st->old_ps[i] = MULT16_32_P15(QCONST16(.2f,15),st->old_ps[i]) + MULT16_32_P15(MULT16_16_P15(QCONST16(.8f,15),SQR16_Q15(st->gain[i])),ps[i]); + + /* Apply gain floor */ + if (st->gain[i] < st->gain_floor[i]) + st->gain[i] = st->gain_floor[i]; + + /* Exponential decay model for reverberation (unused) */ + /*st->reverb_estimate[i] = st->reverb_decay*st->reverb_estimate[i] + st->reverb_decay*st->reverb_level*st->gain[i]*st->gain[i]*st->ps[i];*/ + + /* Take into account speech probability of presence (loudness domain MMSE estimator) */ + /* gain2 = [p*sqrt(gain)+(1-p)*sqrt(gain _floor) ]^2 */ + tmp = MULT16_16_P15(p,spx_sqrt(SHL32(EXTEND32(st->gain[i]),15))) + MULT16_16_P15(SUB16(Q15_ONE,p),spx_sqrt(SHL32(EXTEND32(st->gain_floor[i]),15))); + st->gain2[i]=SQR16_Q15(tmp); + + /* Use this if you want a log-domain MMSE estimator instead */ + /*st->gain2[i] = pow(st->gain[i], p) * pow(st->gain_floor[i],1.f-p);*/ + } + } else { + for (i=N;igain2[i]; + st->gain[i] = MAX16(st->gain[i], st->gain_floor[i]); + tmp = MULT16_16_P15(p,spx_sqrt(SHL32(EXTEND32(st->gain[i]),15))) + MULT16_16_P15(SUB16(Q15_ONE,p),spx_sqrt(SHL32(EXTEND32(st->gain_floor[i]),15))); + st->gain2[i]=SQR16_Q15(tmp); + } + filterbank_compute_psd16(st->bank,st->gain2+N, st->gain2); + } + + /* If noise suppression is off, don't apply the gain (but then why call this in the first place!) */ + if (!st->denoise_enabled) + { + for (i=0;igain2[i]=Q15_ONE; + } + + /* Apply computed gain */ + for (i=1;ift[2*i-1] = MULT16_16_P15(st->gain2[i],st->ft[2*i-1]); + st->ft[2*i] = MULT16_16_P15(st->gain2[i],st->ft[2*i]); + } + st->ft[0] = MULT16_16_P15(st->gain2[0],st->ft[0]); + st->ft[2*N-1] = MULT16_16_P15(st->gain2[N-1],st->ft[2*N-1]); + + /*FIXME: This *will* not work for fixed-point */ +#ifndef FIXED_POINT + if (st->agc_enabled) + speex_compute_agc(st, Pframe, st->ft); +#endif + + /* Inverse FFT with 1/N scaling */ + spx_ifft(st->fft_lookup, st->ft, st->frame); + /* Scale back to original (lower) amplitude */ + for (i=0;i<2*N;i++) + st->frame[i] = PSHR16(st->frame[i], st->frame_shift); + + /*FIXME: This *will* not work for fixed-point */ +#ifndef FIXED_POINT + if (st->agc_enabled) + { + float max_sample=0; + for (i=0;i<2*N;i++) + if (fabs(st->frame[i])>max_sample) + max_sample = fabs(st->frame[i]); + if (max_sample>28000.f) + { + float damp = 28000.f/max_sample; + for (i=0;i<2*N;i++) + st->frame[i] *= damp; + } + } +#endif + + /* Synthesis window (for WOLA) */ + for (i=0;i<2*N;i++) + st->frame[i] = MULT16_16_Q15(st->frame[i], st->window[i]); + + /* Perform overlap and add */ + for (i=0;ioutbuf[i] + st->frame[i]; + for (i=0;iframe[N3+i]; + + /* Update outbuf */ + for (i=0;ioutbuf[i] = st->frame[st->frame_size+i]; + + /* FIXME: This VAD is a kludge */ + st->speech_prob = Pframe; + if (st->vad_enabled) + { + if (st->speech_prob > st->speech_prob_start || (st->was_speech && st->speech_prob > st->speech_prob_continue)) + { + st->was_speech=1; + return 1; + } else + { + st->was_speech=0; + return 0; + } + } else { + return 1; + } +} + +EXPORT void speex_preprocess_estimate_update(SpeexPreprocessState *st, spx_int16_t *x) +{ + int i; + int N = st->ps_size; + int N3 = 2*N - st->frame_size; + int M; + spx_word32_t *ps=st->ps; + + M = st->nbands; + st->min_count++; + + preprocess_analysis(st, x); + + update_noise_prob(st); + + for (i=1;iupdate_prob[i] || st->ps[i] < PSHR32(st->noise[i],NOISE_SHIFT)) + { + st->noise[i] = MULT16_32_Q15(QCONST16(.95f,15),st->noise[i]) + MULT16_32_Q15(QCONST16(.05f,15),SHL32(st->ps[i],NOISE_SHIFT)); + } + } + + for (i=0;ioutbuf[i] = MULT16_16_Q15(x[st->frame_size-N3+i],st->window[st->frame_size+i]); + + /* Save old power spectrum */ + for (i=0;iold_ps[i] = ps[i]; + + for (i=0;ireverb_estimate[i] = MULT16_32_Q15(st->reverb_decay, st->reverb_estimate[i]); +} + + +EXPORT int speex_preprocess_ctl(SpeexPreprocessState *state, int request, void *ptr) +{ + int i; + SpeexPreprocessState *st; + st=(SpeexPreprocessState*)state; + switch(request) + { + case SPEEX_PREPROCESS_SET_DENOISE: + st->denoise_enabled = (*(spx_int32_t*)ptr); + break; + case SPEEX_PREPROCESS_GET_DENOISE: + (*(spx_int32_t*)ptr) = st->denoise_enabled; + break; +#ifndef FIXED_POINT + case SPEEX_PREPROCESS_SET_AGC: + st->agc_enabled = (*(spx_int32_t*)ptr); + break; + case SPEEX_PREPROCESS_GET_AGC: + (*(spx_int32_t*)ptr) = st->agc_enabled; + break; +#ifndef DISABLE_FLOAT_API + case SPEEX_PREPROCESS_SET_AGC_LEVEL: + st->agc_level = (*(float*)ptr); + if (st->agc_level<1) + st->agc_level=1; + if (st->agc_level>32768) + st->agc_level=32768; + break; + case SPEEX_PREPROCESS_GET_AGC_LEVEL: + (*(float*)ptr) = st->agc_level; + break; +#endif /* #ifndef DISABLE_FLOAT_API */ + case SPEEX_PREPROCESS_SET_AGC_INCREMENT: + st->max_increase_step = exp(0.11513f * (*(spx_int32_t*)ptr)*st->frame_size / st->sampling_rate); + break; + case SPEEX_PREPROCESS_GET_AGC_INCREMENT: + (*(spx_int32_t*)ptr) = floor(.5+8.6858*log(st->max_increase_step)*st->sampling_rate/st->frame_size); + break; + case SPEEX_PREPROCESS_SET_AGC_DECREMENT: + st->max_decrease_step = exp(0.11513f * (*(spx_int32_t*)ptr)*st->frame_size / st->sampling_rate); + break; + case SPEEX_PREPROCESS_GET_AGC_DECREMENT: + (*(spx_int32_t*)ptr) = floor(.5+8.6858*log(st->max_decrease_step)*st->sampling_rate/st->frame_size); + break; + case SPEEX_PREPROCESS_SET_AGC_MAX_GAIN: + st->max_gain = exp(0.11513f * (*(spx_int32_t*)ptr)); + break; + case SPEEX_PREPROCESS_GET_AGC_MAX_GAIN: + (*(spx_int32_t*)ptr) = floor(.5+8.6858*log(st->max_gain)); + break; +#endif + case SPEEX_PREPROCESS_SET_VAD: + speex_warning("The VAD has been replaced by a hack pending a complete rewrite"); + st->vad_enabled = (*(spx_int32_t*)ptr); + break; + case SPEEX_PREPROCESS_GET_VAD: + (*(spx_int32_t*)ptr) = st->vad_enabled; + break; + + case SPEEX_PREPROCESS_SET_DEREVERB: + st->dereverb_enabled = (*(spx_int32_t*)ptr); + for (i=0;ips_size;i++) + st->reverb_estimate[i]=0; + break; + case SPEEX_PREPROCESS_GET_DEREVERB: + (*(spx_int32_t*)ptr) = st->dereverb_enabled; + break; + + case SPEEX_PREPROCESS_SET_DEREVERB_LEVEL: + /* FIXME: Re-enable when de-reverberation is actually enabled again */ + /*st->reverb_level = (*(float*)ptr);*/ + break; + case SPEEX_PREPROCESS_GET_DEREVERB_LEVEL: + /* FIXME: Re-enable when de-reverberation is actually enabled again */ + /*(*(float*)ptr) = st->reverb_level;*/ + break; + + case SPEEX_PREPROCESS_SET_DEREVERB_DECAY: + /* FIXME: Re-enable when de-reverberation is actually enabled again */ + /*st->reverb_decay = (*(float*)ptr);*/ + break; + case SPEEX_PREPROCESS_GET_DEREVERB_DECAY: + /* FIXME: Re-enable when de-reverberation is actually enabled again */ + /*(*(float*)ptr) = st->reverb_decay;*/ + break; + + case SPEEX_PREPROCESS_SET_PROB_START: + *(spx_int32_t*)ptr = MIN32(100,MAX32(0, *(spx_int32_t*)ptr)); + st->speech_prob_start = DIV32_16(MULT16_16(Q15ONE,*(spx_int32_t*)ptr), 100); + break; + case SPEEX_PREPROCESS_GET_PROB_START: + (*(spx_int32_t*)ptr) = MULT16_16_Q15(st->speech_prob_start, 100); + break; + + case SPEEX_PREPROCESS_SET_PROB_CONTINUE: + *(spx_int32_t*)ptr = MIN32(100,MAX32(0, *(spx_int32_t*)ptr)); + st->speech_prob_continue = DIV32_16(MULT16_16(Q15ONE,*(spx_int32_t*)ptr), 100); + break; + case SPEEX_PREPROCESS_GET_PROB_CONTINUE: + (*(spx_int32_t*)ptr) = MULT16_16_Q15(st->speech_prob_continue, 100); + break; + + case SPEEX_PREPROCESS_SET_NOISE_SUPPRESS: + st->noise_suppress = -ABS(*(spx_int32_t*)ptr); + break; + case SPEEX_PREPROCESS_GET_NOISE_SUPPRESS: + (*(spx_int32_t*)ptr) = st->noise_suppress; + break; + case SPEEX_PREPROCESS_SET_ECHO_SUPPRESS: + st->echo_suppress = -ABS(*(spx_int32_t*)ptr); + break; + case SPEEX_PREPROCESS_GET_ECHO_SUPPRESS: + (*(spx_int32_t*)ptr) = st->echo_suppress; + break; + case SPEEX_PREPROCESS_SET_ECHO_SUPPRESS_ACTIVE: + st->echo_suppress_active = -ABS(*(spx_int32_t*)ptr); + break; + case SPEEX_PREPROCESS_GET_ECHO_SUPPRESS_ACTIVE: + (*(spx_int32_t*)ptr) = st->echo_suppress_active; + break; + case SPEEX_PREPROCESS_SET_ECHO_STATE: + st->echo_state = (SpeexEchoState*)ptr; + break; + case SPEEX_PREPROCESS_GET_ECHO_STATE: + (*(SpeexEchoState**)ptr) = (SpeexEchoState*)st->echo_state; + break; +#ifndef FIXED_POINT + case SPEEX_PREPROCESS_GET_AGC_LOUDNESS: + (*(spx_int32_t*)ptr) = pow(st->loudness, 1.0/LOUDNESS_EXP); + break; + case SPEEX_PREPROCESS_GET_AGC_GAIN: + (*(spx_int32_t*)ptr) = floor(.5+8.6858*log(st->agc_gain)); + break; +#endif + case SPEEX_PREPROCESS_GET_PSD_SIZE: + case SPEEX_PREPROCESS_GET_NOISE_PSD_SIZE: + (*(spx_int32_t*)ptr) = st->ps_size; + break; + case SPEEX_PREPROCESS_GET_PSD: + for(i=0;ips_size;i++) + ((spx_int32_t *)ptr)[i] = (spx_int32_t) st->ps[i]; + break; + case SPEEX_PREPROCESS_GET_NOISE_PSD: + for(i=0;ips_size;i++) + ((spx_int32_t *)ptr)[i] = (spx_int32_t) PSHR32(st->noise[i], NOISE_SHIFT); + break; + case SPEEX_PREPROCESS_GET_PROB: + (*(spx_int32_t*)ptr) = MULT16_16_Q15(st->speech_prob, 100); + break; +#ifndef FIXED_POINT + case SPEEX_PREPROCESS_SET_AGC_TARGET: + st->agc_level = (*(spx_int32_t*)ptr); + if (st->agc_level<1) + st->agc_level=1; + if (st->agc_level>32768) + st->agc_level=32768; + break; + case SPEEX_PREPROCESS_GET_AGC_TARGET: + (*(spx_int32_t*)ptr) = st->agc_level; + break; +#endif + default: + speex_warning_int("Unknown speex_preprocess_ctl request: ", request); + return -1; + } + return 0; +} + +#ifdef FIXED_DEBUG +long long spx_mips=0; +#endif + diff --git a/android/app/src/main/jni/libspeex/pseudofloat.h b/android/app/src/main/jni/libspeex/pseudofloat.h new file mode 100644 index 000000000..fa841a010 --- /dev/null +++ b/android/app/src/main/jni/libspeex/pseudofloat.h @@ -0,0 +1,379 @@ +/* Copyright (C) 2005 Jean-Marc Valin */ +/** + @file pseudofloat.h + @brief Pseudo-floating point + * This header file provides a lightweight floating point type for + * use on fixed-point platforms when a large dynamic range is + * required. The new type is not compatible with the 32-bit IEEE format, + * it is not even remotely as accurate as 32-bit floats, and is not + * even guaranteed to produce even remotely correct results for code + * other than Speex. It makes all kinds of shortcuts that are acceptable + * for Speex, but may not be acceptable for your application. You're + * quite welcome to reuse this code and improve it, but don't assume + * it works out of the box. Most likely, it doesn't. + */ +/* + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + - Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + - Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + - Neither the name of the Xiph.org Foundation nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR + CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#ifndef PSEUDOFLOAT_H +#define PSEUDOFLOAT_H + +#include "arch.h" +#include "os_support.h" +#include "math_approx.h" +#include + +#ifdef FIXED_POINT + +typedef struct { + spx_int16_t m; + spx_int16_t e; +} spx_float_t; + +static const spx_float_t FLOAT_ZERO = {0,0}; +static const spx_float_t FLOAT_ONE = {16384,-14}; +static const spx_float_t FLOAT_HALF = {16384,-15}; + +#define MIN(a,b) ((a)<(b)?(a):(b)) +static inline spx_float_t PSEUDOFLOAT(spx_int32_t x) +{ + int e=0; + int sign=0; + if (x<0) + { + sign = 1; + x = -x; + } + if (x==0) + { + spx_float_t r = {0,0}; + return r; + } + e = spx_ilog2(ABS32(x))-14; + x = VSHR32(x, e); + if (sign) + { + spx_float_t r; + r.m = -x; + r.e = e; + return r; + } + else + { + spx_float_t r; + r.m = x; + r.e = e; + return r; + } +} + + +static inline spx_float_t FLOAT_ADD(spx_float_t a, spx_float_t b) +{ + spx_float_t r; + if (a.m==0) + return b; + else if (b.m==0) + return a; + if ((a).e > (b).e) + { + r.m = ((a).m>>1) + ((b).m>>MIN(15,(a).e-(b).e+1)); + r.e = (a).e+1; + } + else + { + r.m = ((b).m>>1) + ((a).m>>MIN(15,(b).e-(a).e+1)); + r.e = (b).e+1; + } + if (r.m>0) + { + if (r.m<16384) + { + r.m<<=1; + r.e-=1; + } + } else { + if (r.m>-16384) + { + r.m<<=1; + r.e-=1; + } + } + /*printf ("%f + %f = %f\n", REALFLOAT(a), REALFLOAT(b), REALFLOAT(r));*/ + return r; +} + +static inline spx_float_t FLOAT_SUB(spx_float_t a, spx_float_t b) +{ + spx_float_t r; + if (a.m==0) + return b; + else if (b.m==0) + return a; + if ((a).e > (b).e) + { + r.m = ((a).m>>1) - ((b).m>>MIN(15,(a).e-(b).e+1)); + r.e = (a).e+1; + } + else + { + r.m = ((a).m>>MIN(15,(b).e-(a).e+1)) - ((b).m>>1); + r.e = (b).e+1; + } + if (r.m>0) + { + if (r.m<16384) + { + r.m<<=1; + r.e-=1; + } + } else { + if (r.m>-16384) + { + r.m<<=1; + r.e-=1; + } + } + /*printf ("%f + %f = %f\n", REALFLOAT(a), REALFLOAT(b), REALFLOAT(r));*/ + return r; +} + +static inline int FLOAT_LT(spx_float_t a, spx_float_t b) +{ + if (a.m==0) + return b.m>0; + else if (b.m==0) + return a.m<0; + if ((a).e > (b).e) + return ((a).m>>1) < ((b).m>>MIN(15,(a).e-(b).e+1)); + else + return ((b).m>>1) > ((a).m>>MIN(15,(b).e-(a).e+1)); + +} + +static inline int FLOAT_GT(spx_float_t a, spx_float_t b) +{ + return FLOAT_LT(b,a); +} + +static inline spx_float_t FLOAT_MULT(spx_float_t a, spx_float_t b) +{ + spx_float_t r; + r.m = (spx_int16_t)((spx_int32_t)(a).m*(b).m>>15); + r.e = (a).e+(b).e+15; + if (r.m>0) + { + if (r.m<16384) + { + r.m<<=1; + r.e-=1; + } + } else { + if (r.m>-16384) + { + r.m<<=1; + r.e-=1; + } + } + /*printf ("%f * %f = %f\n", REALFLOAT(a), REALFLOAT(b), REALFLOAT(r));*/ + return r; +} + +static inline spx_float_t FLOAT_AMULT(spx_float_t a, spx_float_t b) +{ + spx_float_t r; + r.m = (spx_int16_t)((spx_int32_t)(a).m*(b).m>>15); + r.e = (a).e+(b).e+15; + return r; +} + + +static inline spx_float_t FLOAT_SHL(spx_float_t a, int b) +{ + spx_float_t r; + r.m = a.m; + r.e = a.e+b; + return r; +} + +static inline spx_int16_t FLOAT_EXTRACT16(spx_float_t a) +{ + if (a.e<0) + return EXTRACT16((EXTEND32(a.m)+(EXTEND32(1)<<(-a.e-1)))>>-a.e); + else + return a.m<>-a.e; + else + return EXTEND32(a.m)<=SHL32(EXTEND32(b.m-1),15)) + { + a >>= 1; + e++; + } + r.m = DIV32_16(a,b.m); + r.e = e-b.e; + return r; +} + + +/* Do NOT attempt to divide by a negative number */ +static inline spx_float_t FLOAT_DIV32(spx_word32_t a, spx_word32_t b) +{ + int e0=0,e=0; + spx_float_t r; + if (a==0) + { + return FLOAT_ZERO; + } + if (b>32767) + { + e0 = spx_ilog2(b)-14; + b = VSHR32(b, e0); + e0 = -e0; + } + e = spx_ilog2(ABS32(a))-spx_ilog2(b-1)-15; + a = VSHR32(a, e); + if (ABS32(a)>=SHL32(EXTEND32(b-1),15)) + { + a >>= 1; + e++; + } + e += e0; + r.m = DIV32_16(a,b); + r.e = e; + return r; +} + +/* Do NOT attempt to divide by a negative number */ +static inline spx_float_t FLOAT_DIVU(spx_float_t a, spx_float_t b) +{ + int e=0; + spx_int32_t num; + spx_float_t r; + if (b.m<=0) + { + speex_warning_int("Attempted to divide by", b.m); + return FLOAT_ONE; + } + num = a.m; + a.m = ABS16(a.m); + while (a.m >= b.m) + { + e++; + a.m >>= 1; + } + num = num << (15-e); + r.m = DIV32_16(num,b.m); + r.e = a.e-b.e-15+e; + return r; +} + +static inline spx_float_t FLOAT_SQRT(spx_float_t a) +{ + spx_float_t r; + spx_int32_t m; + m = SHL32(EXTEND32(a.m), 14); + r.e = a.e - 14; + if (r.e & 1) + { + r.e -= 1; + m <<= 1; + } + r.e >>= 1; + r.m = spx_sqrt(m); + return r; +} + +#else + +#define spx_float_t float +#define FLOAT_ZERO 0.f +#define FLOAT_ONE 1.f +#define FLOAT_HALF 0.5f +#define PSEUDOFLOAT(x) (x) +#define FLOAT_MULT(a,b) ((a)*(b)) +#define FLOAT_AMULT(a,b) ((a)*(b)) +#define FLOAT_MUL32(a,b) ((a)*(b)) +#define FLOAT_DIV32(a,b) ((a)/(b)) +#define FLOAT_EXTRACT16(a) (a) +#define FLOAT_EXTRACT32(a) (a) +#define FLOAT_ADD(a,b) ((a)+(b)) +#define FLOAT_SUB(a,b) ((a)-(b)) +#define REALFLOAT(x) (x) +#define FLOAT_DIV32_FLOAT(a,b) ((a)/(b)) +#define FLOAT_MUL32U(a,b) ((a)*(b)) +#define FLOAT_SHL(a,b) (a) +#define FLOAT_LT(a,b) ((a)<(b)) +#define FLOAT_GT(a,b) ((a)>(b)) +#define FLOAT_DIVU(a,b) ((a)/(b)) +#define FLOAT_SQRT(a) (spx_sqrt(a)) + +#endif + +#endif diff --git a/android/app/src/main/jni/libspeex/quant_lsp.c b/android/app/src/main/jni/libspeex/quant_lsp.c new file mode 100644 index 000000000..e624d1a28 --- /dev/null +++ b/android/app/src/main/jni/libspeex/quant_lsp.c @@ -0,0 +1,385 @@ +/* Copyright (C) 2002 Jean-Marc Valin + File: quant_lsp.c + LSP vector quantization + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + - Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + - Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + - Neither the name of the Xiph.org Foundation nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR + CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "quant_lsp.h" +#include "os_support.h" +#include +#ifndef M_PI +#define M_PI 3.14159265358979323846 +#endif + +#include "arch.h" + +#ifdef BFIN_ASM +#include "quant_lsp_bfin.h" +#endif + +#ifdef FIXED_POINT + +#define LSP_LINEAR(i) (SHL16(i+1,11)) +#define LSP_LINEAR_HIGH(i) (ADD16(MULT16_16_16(i,2560),6144)) +#define LSP_DIV_256(x) (SHL16((spx_word16_t)x, 5)) +#define LSP_DIV_512(x) (SHL16((spx_word16_t)x, 4)) +#define LSP_DIV_1024(x) (SHL16((spx_word16_t)x, 3)) +#define LSP_PI 25736 + +#else + +#define LSP_LINEAR(i) (.25*(i)+.25) +#define LSP_LINEAR_HIGH(i) (.3125*(i)+.75) +#define LSP_SCALE 256. +#define LSP_DIV_256(x) (0.0039062*(x)) +#define LSP_DIV_512(x) (0.0019531*(x)) +#define LSP_DIV_1024(x) (0.00097656*(x)) +#define LSP_PI M_PI + +#endif + +static void compute_quant_weights(spx_lsp_t *qlsp, spx_word16_t *quant_weight, int order) +{ + int i; + spx_word16_t tmp1, tmp2; + for (i=0;i tmp2 ? tmp1 : tmp2; + }*/ + + for (i=0;i +#include "arch.h" + +#define MAX_LSP_SIZE 20 + +#define NB_CDBK_SIZE 64 +#define NB_CDBK_SIZE_LOW1 64 +#define NB_CDBK_SIZE_LOW2 64 +#define NB_CDBK_SIZE_HIGH1 64 +#define NB_CDBK_SIZE_HIGH2 64 + +/*Narrowband codebooks*/ +extern const signed char cdbk_nb[]; +extern const signed char cdbk_nb_low1[]; +extern const signed char cdbk_nb_low2[]; +extern const signed char cdbk_nb_high1[]; +extern const signed char cdbk_nb_high2[]; + +/* Quantizes narrowband LSPs with 30 bits */ +void lsp_quant_nb(spx_lsp_t *lsp, spx_lsp_t *qlsp, int order, SpeexBits *bits); + +/* Decodes quantized narrowband LSPs */ +void lsp_unquant_nb(spx_lsp_t *lsp, int order, SpeexBits *bits); + +/* Quantizes low bit-rate narrowband LSPs with 18 bits */ +void lsp_quant_lbr(spx_lsp_t *lsp, spx_lsp_t *qlsp, int order, SpeexBits *bits); + +/* Decodes quantized low bit-rate narrowband LSPs */ +void lsp_unquant_lbr(spx_lsp_t *lsp, int order, SpeexBits *bits); + +/* Quantizes high-band LSPs with 12 bits */ +void lsp_quant_high(spx_lsp_t *lsp, spx_lsp_t *qlsp, int order, SpeexBits *bits); + +/* Decodes high-band LSPs */ +void lsp_unquant_high(spx_lsp_t *lsp, int order, SpeexBits *bits); + +#endif diff --git a/android/app/src/main/jni/libspeex/quant_lsp_bfin.h b/android/app/src/main/jni/libspeex/quant_lsp_bfin.h new file mode 100644 index 000000000..087b466b7 --- /dev/null +++ b/android/app/src/main/jni/libspeex/quant_lsp_bfin.h @@ -0,0 +1,165 @@ +/* Copyright (C) 2006 David Rowe */ +/** + @file quant_lsp_bfin.h + @author David Rowe + @brief Various compatibility routines for Speex (Blackfin version) +*/ +/* + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + - Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + - Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + - Neither the name of the Xiph.org Foundation nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR + CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#define OVERRIDE_LSP_QUANT +#ifdef OVERRIDE_LSP_QUANT + +/* + Note http://gcc.gnu.org/onlinedocs/gcc/Machine-Constraints.html + well tell you all the magic resgister constraints used below + for gcc in-line asm. +*/ + +static int lsp_quant( + spx_word16_t *x, + const signed char *cdbk, + int nbVec, + int nbDim +) +{ + int j; + spx_word32_t best_dist=1<<30; + int best_id=0; + + __asm__ __volatile__ + ( +" %0 = 1 (X);\n\t" /* %0: best_dist */ +" %0 <<= 30;\n\t" +" %1 = 0 (X);\n\t" /* %1: best_i */ +" P2 = %3\n\t" /* P2: ptr to cdbk */ +" R5 = 0;\n\t" /* R5: best cb entry */ + +" R0 = %5;\n\t" /* set up circ addr */ +" R0 <<= 1;\n\t" +" L0 = R0;\n\t" +" I0 = %2;\n\t" /* %2: &x[0] */ +" B0 = %2;\n\t" + +" R2.L = W [I0++];\n\t" +" LSETUP (1f, 2f) LC0 = %4;\n\t" +"1: R3 = 0;\n\t" /* R3: dist */ +" LSETUP (3f, 4f) LC1 = %5;\n\t" +"3: R1 = B [P2++] (X);\n\t" +" R1 <<= 5;\n\t" +" R0.L = R2.L - R1.L || R2.L = W [I0++];\n\t" +" R0 = R0.L*R0.L;\n\t" +"4: R3 = R3 + R0;\n\t" + +" cc =R3<%0;\n\t" +" if cc %0=R3;\n\t" +" if cc %1=R5;\n\t" +"2: R5 += 1;\n\t" +" L0 = 0;\n\t" + : "=&d" (best_dist), "=&d" (best_id) + : "a" (x), "b" (cdbk), "a" (nbVec), "a" (nbDim) + : "I0", "P2", "R0", "R1", "R2", "R3", "R5", "L0", "B0", "A0" + ); + + for (j=0;j>> 16;\n\t" +" R1 = (A1 += R2.L*R0.H) (IS);\n\t" +"4: R3 = R3 + R1;\n\t" + +" cc =R3<%0;\n\t" +" if cc %0=R3;\n\t" +" if cc %1=R5;\n\t" +"2: R5 += 1;\n\t" +" L0 = 0;\n\t" +" L1 = 0;\n\t" + : "=&d" (best_dist), "=&d" (best_id) + : "a" (x), "a" (weight), "b" (cdbk), "a" (nbVec), "a" (nbDim) + : "I0", "I1", "P2", "R0", "R1", "R2", "R3", "R5", "A1", + "L0", "L1", "B0", "B1" + ); + + for (j=0;j +static void *speex_alloc (int size) {return calloc(size,1);} +static void *speex_realloc (void *ptr, int size) {return realloc(ptr, size);} +static void speex_free (void *ptr) {free(ptr);} +#include "speex_resampler.h" +#include "arch.h" +#else /* OUTSIDE_SPEEX */ + +#include "speex/speex_resampler.h" +#include "arch.h" +#include "os_support.h" +#endif /* OUTSIDE_SPEEX */ + +#include "stack_alloc.h" +#include + +#ifndef M_PI +#define M_PI 3.14159263 +#endif + +#ifdef FIXED_POINT +#define WORD2INT(x) ((x) < -32767 ? -32768 : ((x) > 32766 ? 32767 : (x))) +#else +#define WORD2INT(x) ((x) < -32767.5f ? -32768 : ((x) > 32766.5f ? 32767 : floor(.5+(x)))) +#endif + +#define IMAX(a,b) ((a) > (b) ? (a) : (b)) +#define IMIN(a,b) ((a) < (b) ? (a) : (b)) + +#ifndef NULL +#define NULL 0 +#endif + +#ifdef _USE_SSE +#include "resample_sse.h" +#endif + +/* Numer of elements to allocate on the stack */ +#ifdef VAR_ARRAYS +#define FIXED_STACK_ALLOC 8192 +#else +#define FIXED_STACK_ALLOC 1024 +#endif + +typedef int (*resampler_basic_func)(SpeexResamplerState *, spx_uint32_t , const spx_word16_t *, spx_uint32_t *, spx_word16_t *, spx_uint32_t *); + +struct SpeexResamplerState_ { + spx_uint32_t in_rate; + spx_uint32_t out_rate; + spx_uint32_t num_rate; + spx_uint32_t den_rate; + + int quality; + spx_uint32_t nb_channels; + spx_uint32_t filt_len; + spx_uint32_t mem_alloc_size; + spx_uint32_t buffer_size; + int int_advance; + int frac_advance; + float cutoff; + spx_uint32_t oversample; + int initialised; + int started; + + /* These are per-channel */ + spx_int32_t *last_sample; + spx_uint32_t *samp_frac_num; + spx_uint32_t *magic_samples; + + spx_word16_t *mem; + spx_word16_t *sinc_table; + spx_uint32_t sinc_table_length; + resampler_basic_func resampler_ptr; + + int in_stride; + int out_stride; +} ; + +static double kaiser12_table[68] = { + 0.99859849, 1.00000000, 0.99859849, 0.99440475, 0.98745105, 0.97779076, + 0.96549770, 0.95066529, 0.93340547, 0.91384741, 0.89213598, 0.86843014, + 0.84290116, 0.81573067, 0.78710866, 0.75723148, 0.72629970, 0.69451601, + 0.66208321, 0.62920216, 0.59606986, 0.56287762, 0.52980938, 0.49704014, + 0.46473455, 0.43304576, 0.40211431, 0.37206735, 0.34301800, 0.31506490, + 0.28829195, 0.26276832, 0.23854851, 0.21567274, 0.19416736, 0.17404546, + 0.15530766, 0.13794294, 0.12192957, 0.10723616, 0.09382272, 0.08164178, + 0.07063950, 0.06075685, 0.05193064, 0.04409466, 0.03718069, 0.03111947, + 0.02584161, 0.02127838, 0.01736250, 0.01402878, 0.01121463, 0.00886058, + 0.00691064, 0.00531256, 0.00401805, 0.00298291, 0.00216702, 0.00153438, + 0.00105297, 0.00069463, 0.00043489, 0.00025272, 0.00013031, 0.0000527734, + 0.00001000, 0.00000000}; +/* +static double kaiser12_table[36] = { + 0.99440475, 1.00000000, 0.99440475, 0.97779076, 0.95066529, 0.91384741, + 0.86843014, 0.81573067, 0.75723148, 0.69451601, 0.62920216, 0.56287762, + 0.49704014, 0.43304576, 0.37206735, 0.31506490, 0.26276832, 0.21567274, + 0.17404546, 0.13794294, 0.10723616, 0.08164178, 0.06075685, 0.04409466, + 0.03111947, 0.02127838, 0.01402878, 0.00886058, 0.00531256, 0.00298291, + 0.00153438, 0.00069463, 0.00025272, 0.0000527734, 0.00000500, 0.00000000}; +*/ +static double kaiser10_table[36] = { + 0.99537781, 1.00000000, 0.99537781, 0.98162644, 0.95908712, 0.92831446, + 0.89005583, 0.84522401, 0.79486424, 0.74011713, 0.68217934, 0.62226347, + 0.56155915, 0.50119680, 0.44221549, 0.38553619, 0.33194107, 0.28205962, + 0.23636152, 0.19515633, 0.15859932, 0.12670280, 0.09935205, 0.07632451, + 0.05731132, 0.04193980, 0.02979584, 0.02044510, 0.01345224, 0.00839739, + 0.00488951, 0.00257636, 0.00115101, 0.00035515, 0.00000000, 0.00000000}; + +static double kaiser8_table[36] = { + 0.99635258, 1.00000000, 0.99635258, 0.98548012, 0.96759014, 0.94302200, + 0.91223751, 0.87580811, 0.83439927, 0.78875245, 0.73966538, 0.68797126, + 0.63451750, 0.58014482, 0.52566725, 0.47185369, 0.41941150, 0.36897272, + 0.32108304, 0.27619388, 0.23465776, 0.19672670, 0.16255380, 0.13219758, + 0.10562887, 0.08273982, 0.06335451, 0.04724088, 0.03412321, 0.02369490, + 0.01563093, 0.00959968, 0.00527363, 0.00233883, 0.00050000, 0.00000000}; + +static double kaiser6_table[36] = { + 0.99733006, 1.00000000, 0.99733006, 0.98935595, 0.97618418, 0.95799003, + 0.93501423, 0.90755855, 0.87598009, 0.84068475, 0.80211977, 0.76076565, + 0.71712752, 0.67172623, 0.62508937, 0.57774224, 0.53019925, 0.48295561, + 0.43647969, 0.39120616, 0.34752997, 0.30580127, 0.26632152, 0.22934058, + 0.19505503, 0.16360756, 0.13508755, 0.10953262, 0.08693120, 0.06722600, + 0.05031820, 0.03607231, 0.02432151, 0.01487334, 0.00752000, 0.00000000}; + +struct FuncDef { + double *table; + int oversample; +}; + +static struct FuncDef _KAISER12 = {kaiser12_table, 64}; +#define KAISER12 (&_KAISER12) +/*static struct FuncDef _KAISER12 = {kaiser12_table, 32}; +#define KAISER12 (&_KAISER12)*/ +static struct FuncDef _KAISER10 = {kaiser10_table, 32}; +#define KAISER10 (&_KAISER10) +static struct FuncDef _KAISER8 = {kaiser8_table, 32}; +#define KAISER8 (&_KAISER8) +static struct FuncDef _KAISER6 = {kaiser6_table, 32}; +#define KAISER6 (&_KAISER6) + +struct QualityMapping { + int base_length; + int oversample; + float downsample_bandwidth; + float upsample_bandwidth; + struct FuncDef *window_func; +}; + + +/* This table maps conversion quality to internal parameters. There are two + reasons that explain why the up-sampling bandwidth is larger than the + down-sampling bandwidth: + 1) When up-sampling, we can assume that the spectrum is already attenuated + close to the Nyquist rate (from an A/D or a previous resampling filter) + 2) Any aliasing that occurs very close to the Nyquist rate will be masked + by the sinusoids/noise just below the Nyquist rate (guaranteed only for + up-sampling). +*/ +static const struct QualityMapping quality_map[11] = { + { 8, 4, 0.830f, 0.860f, KAISER6 }, /* Q0 */ + { 16, 4, 0.850f, 0.880f, KAISER6 }, /* Q1 */ + { 32, 4, 0.882f, 0.910f, KAISER6 }, /* Q2 */ /* 82.3% cutoff ( ~60 dB stop) 6 */ + { 48, 8, 0.895f, 0.917f, KAISER8 }, /* Q3 */ /* 84.9% cutoff ( ~80 dB stop) 8 */ + { 64, 8, 0.921f, 0.940f, KAISER8 }, /* Q4 */ /* 88.7% cutoff ( ~80 dB stop) 8 */ + { 80, 16, 0.922f, 0.940f, KAISER10}, /* Q5 */ /* 89.1% cutoff (~100 dB stop) 10 */ + { 96, 16, 0.940f, 0.945f, KAISER10}, /* Q6 */ /* 91.5% cutoff (~100 dB stop) 10 */ + {128, 16, 0.950f, 0.950f, KAISER10}, /* Q7 */ /* 93.1% cutoff (~100 dB stop) 10 */ + {160, 16, 0.960f, 0.960f, KAISER10}, /* Q8 */ /* 94.5% cutoff (~100 dB stop) 10 */ + {192, 32, 0.968f, 0.968f, KAISER12}, /* Q9 */ /* 95.5% cutoff (~100 dB stop) 10 */ + {256, 32, 0.975f, 0.975f, KAISER12}, /* Q10 */ /* 96.6% cutoff (~100 dB stop) 10 */ +}; +/*8,24,40,56,80,104,128,160,200,256,320*/ +static double compute_func(float x, struct FuncDef *func) +{ + float y, frac; + double interp[4]; + int ind; + y = x*func->oversample; + ind = (int)floor(y); + frac = (y-ind); + /* CSE with handle the repeated powers */ + interp[3] = -0.1666666667*frac + 0.1666666667*(frac*frac*frac); + interp[2] = frac + 0.5*(frac*frac) - 0.5*(frac*frac*frac); + /*interp[2] = 1.f - 0.5f*frac - frac*frac + 0.5f*frac*frac*frac;*/ + interp[0] = -0.3333333333*frac + 0.5*(frac*frac) - 0.1666666667*(frac*frac*frac); + /* Just to make sure we don't have rounding problems */ + interp[1] = 1.f-interp[3]-interp[2]-interp[0]; + + /*sum = frac*accum[1] + (1-frac)*accum[2];*/ + return interp[0]*func->table[ind] + interp[1]*func->table[ind+1] + interp[2]*func->table[ind+2] + interp[3]*func->table[ind+3]; +} + +#if 0 +#include +int main(int argc, char **argv) +{ + int i; + for (i=0;i<256;i++) + { + printf ("%f\n", compute_func(i/256., KAISER12)); + } + return 0; +} +#endif + +#ifdef FIXED_POINT +/* The slow way of computing a sinc for the table. Should improve that some day */ +static spx_word16_t sinc(float cutoff, float x, int N, struct FuncDef *window_func) +{ + /*fprintf (stderr, "%f ", x);*/ + float xx = x * cutoff; + if (fabs(x)<1e-6f) + return WORD2INT(32768.*cutoff); + else if (fabs(x) > .5f*N) + return 0; + /*FIXME: Can it really be any slower than this? */ + return WORD2INT(32768.*cutoff*sin(M_PI*xx)/(M_PI*xx) * compute_func(fabs(2.*x/N), window_func)); +} +#else +/* The slow way of computing a sinc for the table. Should improve that some day */ +static spx_word16_t sinc(float cutoff, float x, int N, struct FuncDef *window_func) +{ + /*fprintf (stderr, "%f ", x);*/ + float xx = x * cutoff; + if (fabs(x)<1e-6) + return cutoff; + else if (fabs(x) > .5*N) + return 0; + /*FIXME: Can it really be any slower than this? */ + return cutoff*sin(M_PI*xx)/(M_PI*xx) * compute_func(fabs(2.*x/N), window_func); +} +#endif + +#ifdef FIXED_POINT +static void cubic_coef(spx_word16_t x, spx_word16_t interp[4]) +{ + /* Compute interpolation coefficients. I'm not sure whether this corresponds to cubic interpolation + but I know it's MMSE-optimal on a sinc */ + spx_word16_t x2, x3; + x2 = MULT16_16_P15(x, x); + x3 = MULT16_16_P15(x, x2); + interp[0] = PSHR32(MULT16_16(QCONST16(-0.16667f, 15),x) + MULT16_16(QCONST16(0.16667f, 15),x3),15); + interp[1] = EXTRACT16(EXTEND32(x) + SHR32(SUB32(EXTEND32(x2),EXTEND32(x3)),1)); + interp[3] = PSHR32(MULT16_16(QCONST16(-0.33333f, 15),x) + MULT16_16(QCONST16(.5f,15),x2) - MULT16_16(QCONST16(0.16667f, 15),x3),15); + /* Just to make sure we don't have rounding problems */ + interp[2] = Q15_ONE-interp[0]-interp[1]-interp[3]; + if (interp[2]<32767) + interp[2]+=1; +} +#else +static void cubic_coef(spx_word16_t frac, spx_word16_t interp[4]) +{ + /* Compute interpolation coefficients. I'm not sure whether this corresponds to cubic interpolation + but I know it's MMSE-optimal on a sinc */ + interp[0] = -0.16667f*frac + 0.16667f*frac*frac*frac; + interp[1] = frac + 0.5f*frac*frac - 0.5f*frac*frac*frac; + /*interp[2] = 1.f - 0.5f*frac - frac*frac + 0.5f*frac*frac*frac;*/ + interp[3] = -0.33333f*frac + 0.5f*frac*frac - 0.16667f*frac*frac*frac; + /* Just to make sure we don't have rounding problems */ + interp[2] = 1.-interp[0]-interp[1]-interp[3]; +} +#endif + +static int resampler_basic_direct_single(SpeexResamplerState *st, spx_uint32_t channel_index, const spx_word16_t *in, spx_uint32_t *in_len, spx_word16_t *out, spx_uint32_t *out_len) +{ + const int N = st->filt_len; + int out_sample = 0; + int last_sample = st->last_sample[channel_index]; + spx_uint32_t samp_frac_num = st->samp_frac_num[channel_index]; + const spx_word16_t *sinc_table = st->sinc_table; + const int out_stride = st->out_stride; + const int int_advance = st->int_advance; + const int frac_advance = st->frac_advance; + const spx_uint32_t den_rate = st->den_rate; + spx_word32_t sum; + int j; + + while (!(last_sample >= (spx_int32_t)*in_len || out_sample >= (spx_int32_t)*out_len)) + { + const spx_word16_t *sinc = & sinc_table[samp_frac_num*N]; + const spx_word16_t *iptr = & in[last_sample]; + +#ifndef OVERRIDE_INNER_PRODUCT_SINGLE + float accum[4] = {0,0,0,0}; + + for(j=0;j= den_rate) + { + samp_frac_num -= den_rate; + last_sample++; + } + } + + st->last_sample[channel_index] = last_sample; + st->samp_frac_num[channel_index] = samp_frac_num; + return out_sample; +} + +#ifdef FIXED_POINT +#else +/* This is the same as the previous function, except with a double-precision accumulator */ +static int resampler_basic_direct_double(SpeexResamplerState *st, spx_uint32_t channel_index, const spx_word16_t *in, spx_uint32_t *in_len, spx_word16_t *out, spx_uint32_t *out_len) +{ + const int N = st->filt_len; + int out_sample = 0; + int last_sample = st->last_sample[channel_index]; + spx_uint32_t samp_frac_num = st->samp_frac_num[channel_index]; + const spx_word16_t *sinc_table = st->sinc_table; + const int out_stride = st->out_stride; + const int int_advance = st->int_advance; + const int frac_advance = st->frac_advance; + const spx_uint32_t den_rate = st->den_rate; + double sum; + int j; + + while (!(last_sample >= (spx_int32_t)*in_len || out_sample >= (spx_int32_t)*out_len)) + { + const spx_word16_t *sinc = & sinc_table[samp_frac_num*N]; + const spx_word16_t *iptr = & in[last_sample]; + +#ifndef OVERRIDE_INNER_PRODUCT_DOUBLE + double accum[4] = {0,0,0,0}; + + for(j=0;j= den_rate) + { + samp_frac_num -= den_rate; + last_sample++; + } + } + + st->last_sample[channel_index] = last_sample; + st->samp_frac_num[channel_index] = samp_frac_num; + return out_sample; +} +#endif + +static int resampler_basic_interpolate_single(SpeexResamplerState *st, spx_uint32_t channel_index, const spx_word16_t *in, spx_uint32_t *in_len, spx_word16_t *out, spx_uint32_t *out_len) +{ + const int N = st->filt_len; + int out_sample = 0; + int last_sample = st->last_sample[channel_index]; + spx_uint32_t samp_frac_num = st->samp_frac_num[channel_index]; + const int out_stride = st->out_stride; + const int int_advance = st->int_advance; + const int frac_advance = st->frac_advance; + const spx_uint32_t den_rate = st->den_rate; + int j; + spx_word32_t sum; + + while (!(last_sample >= (spx_int32_t)*in_len || out_sample >= (spx_int32_t)*out_len)) + { + const spx_word16_t *iptr = & in[last_sample]; + + const int offset = samp_frac_num*st->oversample/st->den_rate; +#ifdef FIXED_POINT + const spx_word16_t frac = PDIV32(SHL32((samp_frac_num*st->oversample) % st->den_rate,15),st->den_rate); +#else + const spx_word16_t frac = ((float)((samp_frac_num*st->oversample) % st->den_rate))/st->den_rate; +#endif + spx_word16_t interp[4]; + + +#ifndef OVERRIDE_INTERPOLATE_PRODUCT_SINGLE + spx_word32_t accum[4] = {0,0,0,0}; + + for(j=0;jsinc_table[4+(j+1)*st->oversample-offset-2]); + accum[1] += MULT16_16(curr_in,st->sinc_table[4+(j+1)*st->oversample-offset-1]); + accum[2] += MULT16_16(curr_in,st->sinc_table[4+(j+1)*st->oversample-offset]); + accum[3] += MULT16_16(curr_in,st->sinc_table[4+(j+1)*st->oversample-offset+1]); + } + + cubic_coef(frac, interp); + sum = MULT16_32_Q15(interp[0],accum[0]) + MULT16_32_Q15(interp[1],accum[1]) + MULT16_32_Q15(interp[2],accum[2]) + MULT16_32_Q15(interp[3],accum[3]); +#else + cubic_coef(frac, interp); + sum = interpolate_product_single(iptr, st->sinc_table + st->oversample + 4 - offset - 2, N, st->oversample, interp); +#endif + + out[out_stride * out_sample++] = PSHR32(sum,15); + last_sample += int_advance; + samp_frac_num += frac_advance; + if (samp_frac_num >= den_rate) + { + samp_frac_num -= den_rate; + last_sample++; + } + } + + st->last_sample[channel_index] = last_sample; + st->samp_frac_num[channel_index] = samp_frac_num; + return out_sample; +} + +#ifdef FIXED_POINT +#else +/* This is the same as the previous function, except with a double-precision accumulator */ +static int resampler_basic_interpolate_double(SpeexResamplerState *st, spx_uint32_t channel_index, const spx_word16_t *in, spx_uint32_t *in_len, spx_word16_t *out, spx_uint32_t *out_len) +{ + const int N = st->filt_len; + int out_sample = 0; + int last_sample = st->last_sample[channel_index]; + spx_uint32_t samp_frac_num = st->samp_frac_num[channel_index]; + const int out_stride = st->out_stride; + const int int_advance = st->int_advance; + const int frac_advance = st->frac_advance; + const spx_uint32_t den_rate = st->den_rate; + int j; + spx_word32_t sum; + + while (!(last_sample >= (spx_int32_t)*in_len || out_sample >= (spx_int32_t)*out_len)) + { + const spx_word16_t *iptr = & in[last_sample]; + + const int offset = samp_frac_num*st->oversample/st->den_rate; +#ifdef FIXED_POINT + const spx_word16_t frac = PDIV32(SHL32((samp_frac_num*st->oversample) % st->den_rate,15),st->den_rate); +#else + const spx_word16_t frac = ((float)((samp_frac_num*st->oversample) % st->den_rate))/st->den_rate; +#endif + spx_word16_t interp[4]; + + +#ifndef OVERRIDE_INTERPOLATE_PRODUCT_DOUBLE + double accum[4] = {0,0,0,0}; + + for(j=0;jsinc_table[4+(j+1)*st->oversample-offset-2]); + accum[1] += MULT16_16(curr_in,st->sinc_table[4+(j+1)*st->oversample-offset-1]); + accum[2] += MULT16_16(curr_in,st->sinc_table[4+(j+1)*st->oversample-offset]); + accum[3] += MULT16_16(curr_in,st->sinc_table[4+(j+1)*st->oversample-offset+1]); + } + + cubic_coef(frac, interp); + sum = MULT16_32_Q15(interp[0],accum[0]) + MULT16_32_Q15(interp[1],accum[1]) + MULT16_32_Q15(interp[2],accum[2]) + MULT16_32_Q15(interp[3],accum[3]); +#else + cubic_coef(frac, interp); + sum = interpolate_product_double(iptr, st->sinc_table + st->oversample + 4 - offset - 2, N, st->oversample, interp); +#endif + + out[out_stride * out_sample++] = PSHR32(sum,15); + last_sample += int_advance; + samp_frac_num += frac_advance; + if (samp_frac_num >= den_rate) + { + samp_frac_num -= den_rate; + last_sample++; + } + } + + st->last_sample[channel_index] = last_sample; + st->samp_frac_num[channel_index] = samp_frac_num; + return out_sample; +} +#endif + +static void update_filter(SpeexResamplerState *st) +{ + spx_uint32_t old_length; + + old_length = st->filt_len; + st->oversample = quality_map[st->quality].oversample; + st->filt_len = quality_map[st->quality].base_length; + + if (st->num_rate > st->den_rate) + { + /* down-sampling */ + st->cutoff = quality_map[st->quality].downsample_bandwidth * st->den_rate / st->num_rate; + /* FIXME: divide the numerator and denominator by a certain amount if they're too large */ + st->filt_len = st->filt_len*st->num_rate / st->den_rate; + /* Round down to make sure we have a multiple of 4 */ + st->filt_len &= (~0x3); + if (2*st->den_rate < st->num_rate) + st->oversample >>= 1; + if (4*st->den_rate < st->num_rate) + st->oversample >>= 1; + if (8*st->den_rate < st->num_rate) + st->oversample >>= 1; + if (16*st->den_rate < st->num_rate) + st->oversample >>= 1; + if (st->oversample < 1) + st->oversample = 1; + } else { + /* up-sampling */ + st->cutoff = quality_map[st->quality].upsample_bandwidth; + } + + /* Choose the resampling type that requires the least amount of memory */ + if (st->den_rate <= st->oversample) + { + spx_uint32_t i; + if (!st->sinc_table) + st->sinc_table = (spx_word16_t *)speex_alloc(st->filt_len*st->den_rate*sizeof(spx_word16_t)); + else if (st->sinc_table_length < st->filt_len*st->den_rate) + { + st->sinc_table = (spx_word16_t *)speex_realloc(st->sinc_table,st->filt_len*st->den_rate*sizeof(spx_word16_t)); + st->sinc_table_length = st->filt_len*st->den_rate; + } + for (i=0;iden_rate;i++) + { + spx_int32_t j; + for (j=0;jfilt_len;j++) + { + st->sinc_table[i*st->filt_len+j] = sinc(st->cutoff,((j-(spx_int32_t)st->filt_len/2+1)-((float)i)/st->den_rate), st->filt_len, quality_map[st->quality].window_func); + } + } +#ifdef FIXED_POINT + st->resampler_ptr = resampler_basic_direct_single; +#else + if (st->quality>8) + st->resampler_ptr = resampler_basic_direct_double; + else + st->resampler_ptr = resampler_basic_direct_single; +#endif + /*fprintf (stderr, "resampler uses direct sinc table and normalised cutoff %f\n", cutoff);*/ + } else { + spx_int32_t i; + if (!st->sinc_table) + st->sinc_table = (spx_word16_t *)speex_alloc((st->filt_len*st->oversample+8)*sizeof(spx_word16_t)); + else if (st->sinc_table_length < st->filt_len*st->oversample+8) + { + st->sinc_table = (spx_word16_t *)speex_realloc(st->sinc_table,(st->filt_len*st->oversample+8)*sizeof(spx_word16_t)); + st->sinc_table_length = st->filt_len*st->oversample+8; + } + for (i=-4;i<(spx_int32_t)(st->oversample*st->filt_len+4);i++) + st->sinc_table[i+4] = sinc(st->cutoff,(i/(float)st->oversample - st->filt_len/2), st->filt_len, quality_map[st->quality].window_func); +#ifdef FIXED_POINT + st->resampler_ptr = resampler_basic_interpolate_single; +#else + if (st->quality>8) + st->resampler_ptr = resampler_basic_interpolate_double; + else + st->resampler_ptr = resampler_basic_interpolate_single; +#endif + /*fprintf (stderr, "resampler uses interpolated sinc table and normalised cutoff %f\n", cutoff);*/ + } + st->int_advance = st->num_rate/st->den_rate; + st->frac_advance = st->num_rate%st->den_rate; + + + /* Here's the place where we update the filter memory to take into account + the change in filter length. It's probably the messiest part of the code + due to handling of lots of corner cases. */ + if (!st->mem) + { + spx_uint32_t i; + st->mem_alloc_size = st->filt_len-1 + st->buffer_size; + st->mem = (spx_word16_t*)speex_alloc(st->nb_channels*st->mem_alloc_size * sizeof(spx_word16_t)); + for (i=0;inb_channels*st->mem_alloc_size;i++) + st->mem[i] = 0; + /*speex_warning("init filter");*/ + } else if (!st->started) + { + spx_uint32_t i; + st->mem_alloc_size = st->filt_len-1 + st->buffer_size; + st->mem = (spx_word16_t*)speex_realloc(st->mem, st->nb_channels*st->mem_alloc_size * sizeof(spx_word16_t)); + for (i=0;inb_channels*st->mem_alloc_size;i++) + st->mem[i] = 0; + /*speex_warning("reinit filter");*/ + } else if (st->filt_len > old_length) + { + spx_int32_t i; + /* Increase the filter length */ + /*speex_warning("increase filter size");*/ + int old_alloc_size = st->mem_alloc_size; + if ((st->filt_len-1 + st->buffer_size) > st->mem_alloc_size) + { + st->mem_alloc_size = st->filt_len-1 + st->buffer_size; + st->mem = (spx_word16_t*)speex_realloc(st->mem, st->nb_channels*st->mem_alloc_size * sizeof(spx_word16_t)); + } + for (i=st->nb_channels-1;i>=0;i--) + { + spx_int32_t j; + spx_uint32_t olen = old_length; + /*if (st->magic_samples[i])*/ + { + /* Try and remove the magic samples as if nothing had happened */ + + /* FIXME: This is wrong but for now we need it to avoid going over the array bounds */ + olen = old_length + 2*st->magic_samples[i]; + for (j=old_length-2+st->magic_samples[i];j>=0;j--) + st->mem[i*st->mem_alloc_size+j+st->magic_samples[i]] = st->mem[i*old_alloc_size+j]; + for (j=0;jmagic_samples[i];j++) + st->mem[i*st->mem_alloc_size+j] = 0; + st->magic_samples[i] = 0; + } + if (st->filt_len > olen) + { + /* If the new filter length is still bigger than the "augmented" length */ + /* Copy data going backward */ + for (j=0;jmem[i*st->mem_alloc_size+(st->filt_len-2-j)] = st->mem[i*st->mem_alloc_size+(olen-2-j)]; + /* Then put zeros for lack of anything better */ + for (;jfilt_len-1;j++) + st->mem[i*st->mem_alloc_size+(st->filt_len-2-j)] = 0; + /* Adjust last_sample */ + st->last_sample[i] += (st->filt_len - olen)/2; + } else { + /* Put back some of the magic! */ + st->magic_samples[i] = (olen - st->filt_len)/2; + for (j=0;jfilt_len-1+st->magic_samples[i];j++) + st->mem[i*st->mem_alloc_size+j] = st->mem[i*st->mem_alloc_size+j+st->magic_samples[i]]; + } + } + } else if (st->filt_len < old_length) + { + spx_uint32_t i; + /* Reduce filter length, this a bit tricky. We need to store some of the memory as "magic" + samples so they can be used directly as input the next time(s) */ + for (i=0;inb_channels;i++) + { + spx_uint32_t j; + spx_uint32_t old_magic = st->magic_samples[i]; + st->magic_samples[i] = (old_length - st->filt_len)/2; + /* We must copy some of the memory that's no longer used */ + /* Copy data going backward */ + for (j=0;jfilt_len-1+st->magic_samples[i]+old_magic;j++) + st->mem[i*st->mem_alloc_size+j] = st->mem[i*st->mem_alloc_size+j+st->magic_samples[i]]; + st->magic_samples[i] += old_magic; + } + } + +} + +EXPORT SpeexResamplerState *speex_resampler_init(spx_uint32_t nb_channels, spx_uint32_t in_rate, spx_uint32_t out_rate, int quality, int *err) +{ + return speex_resampler_init_frac(nb_channels, in_rate, out_rate, in_rate, out_rate, quality, err); +} + +EXPORT SpeexResamplerState *speex_resampler_init_frac(spx_uint32_t nb_channels, spx_uint32_t ratio_num, spx_uint32_t ratio_den, spx_uint32_t in_rate, spx_uint32_t out_rate, int quality, int *err) +{ + spx_uint32_t i; + SpeexResamplerState *st; + if (quality > 10 || quality < 0) + { + if (err) + *err = RESAMPLER_ERR_INVALID_ARG; + return NULL; + } + st = (SpeexResamplerState *)speex_alloc(sizeof(SpeexResamplerState)); + st->initialised = 0; + st->started = 0; + st->in_rate = 0; + st->out_rate = 0; + st->num_rate = 0; + st->den_rate = 0; + st->quality = -1; + st->sinc_table_length = 0; + st->mem_alloc_size = 0; + st->filt_len = 0; + st->mem = 0; + st->resampler_ptr = 0; + + st->cutoff = 1.f; + st->nb_channels = nb_channels; + st->in_stride = 1; + st->out_stride = 1; + +#ifdef FIXED_POINT + st->buffer_size = 160; +#else + st->buffer_size = 160; +#endif + + /* Per channel data */ + st->last_sample = (spx_int32_t*)speex_alloc(nb_channels*sizeof(int)); + st->magic_samples = (spx_uint32_t*)speex_alloc(nb_channels*sizeof(int)); + st->samp_frac_num = (spx_uint32_t*)speex_alloc(nb_channels*sizeof(int)); + for (i=0;ilast_sample[i] = 0; + st->magic_samples[i] = 0; + st->samp_frac_num[i] = 0; + } + + speex_resampler_set_quality(st, quality); + speex_resampler_set_rate_frac(st, ratio_num, ratio_den, in_rate, out_rate); + + + update_filter(st); + + st->initialised = 1; + if (err) + *err = RESAMPLER_ERR_SUCCESS; + + return st; +} + +EXPORT void speex_resampler_destroy(SpeexResamplerState *st) +{ + speex_free(st->mem); + speex_free(st->sinc_table); + speex_free(st->last_sample); + speex_free(st->magic_samples); + speex_free(st->samp_frac_num); + speex_free(st); +} + +static int speex_resampler_process_native(SpeexResamplerState *st, spx_uint32_t channel_index, spx_uint32_t *in_len, spx_word16_t *out, spx_uint32_t *out_len) +{ + int j=0; + const int N = st->filt_len; + int out_sample = 0; + spx_word16_t *mem = st->mem + channel_index * st->mem_alloc_size; + spx_uint32_t ilen; + + st->started = 1; + + /* Call the right resampler through the function ptr */ + out_sample = st->resampler_ptr(st, channel_index, mem, in_len, out, out_len); + + if (st->last_sample[channel_index] < (spx_int32_t)*in_len) + *in_len = st->last_sample[channel_index]; + *out_len = out_sample; + st->last_sample[channel_index] -= *in_len; + + ilen = *in_len; + + for(j=0;jmagic_samples[channel_index]; + spx_word16_t *mem = st->mem + channel_index * st->mem_alloc_size; + const int N = st->filt_len; + + speex_resampler_process_native(st, channel_index, &tmp_in_len, *out, &out_len); + + st->magic_samples[channel_index] -= tmp_in_len; + + /* If we couldn't process all "magic" input samples, save the rest for next time */ + if (st->magic_samples[channel_index]) + { + spx_uint32_t i; + for (i=0;imagic_samples[channel_index];i++) + mem[N-1+i]=mem[N-1+i+tmp_in_len]; + } + *out += out_len*st->out_stride; + return out_len; +} + +#ifdef FIXED_POINT +EXPORT int speex_resampler_process_int(SpeexResamplerState *st, spx_uint32_t channel_index, const spx_int16_t *in, spx_uint32_t *in_len, spx_int16_t *out, spx_uint32_t *out_len) +#else +EXPORT int speex_resampler_process_float(SpeexResamplerState *st, spx_uint32_t channel_index, const float *in, spx_uint32_t *in_len, float *out, spx_uint32_t *out_len) +#endif +{ + int j; + spx_uint32_t ilen = *in_len; + spx_uint32_t olen = *out_len; + spx_word16_t *x = st->mem + channel_index * st->mem_alloc_size; + const int filt_offs = st->filt_len - 1; + const spx_uint32_t xlen = st->mem_alloc_size - filt_offs; + const int istride = st->in_stride; + + if (st->magic_samples[channel_index]) + olen -= speex_resampler_magic(st, channel_index, &out, olen); + if (! st->magic_samples[channel_index]) { + while (ilen && olen) { + spx_uint32_t ichunk = (ilen > xlen) ? xlen : ilen; + spx_uint32_t ochunk = olen; + + if (in) { + for(j=0;jout_stride; + if (in) + in += ichunk * istride; + } + } + *in_len -= ilen; + *out_len -= olen; + return RESAMPLER_ERR_SUCCESS; +} + +#ifdef FIXED_POINT +EXPORT int speex_resampler_process_float(SpeexResamplerState *st, spx_uint32_t channel_index, const float *in, spx_uint32_t *in_len, float *out, spx_uint32_t *out_len) +#else +EXPORT int speex_resampler_process_int(SpeexResamplerState *st, spx_uint32_t channel_index, const spx_int16_t *in, spx_uint32_t *in_len, spx_int16_t *out, spx_uint32_t *out_len) +#endif +{ + int j; + const int istride_save = st->in_stride; + const int ostride_save = st->out_stride; + spx_uint32_t ilen = *in_len; + spx_uint32_t olen = *out_len; + spx_word16_t *x = st->mem + channel_index * st->mem_alloc_size; + const spx_uint32_t xlen = st->mem_alloc_size - (st->filt_len - 1); +#ifdef VAR_ARRAYS + const unsigned int ylen = (olen < FIXED_STACK_ALLOC) ? olen : FIXED_STACK_ALLOC; + VARDECL(spx_word16_t *ystack); + ALLOC(ystack, ylen, spx_word16_t); +#else + const unsigned int ylen = FIXED_STACK_ALLOC; + spx_word16_t ystack[FIXED_STACK_ALLOC]; +#endif + + st->out_stride = 1; + + while (ilen && olen) { + spx_word16_t *y = ystack; + spx_uint32_t ichunk = (ilen > xlen) ? xlen : ilen; + spx_uint32_t ochunk = (olen > ylen) ? ylen : olen; + spx_uint32_t omagic = 0; + + if (st->magic_samples[channel_index]) { + omagic = speex_resampler_magic(st, channel_index, &y, ochunk); + ochunk -= omagic; + olen -= omagic; + } + if (! st->magic_samples[channel_index]) { + if (in) { + for(j=0;jfilt_len-1]=WORD2INT(in[j*istride_save]); +#else + x[j+st->filt_len-1]=in[j*istride_save]; +#endif + } else { + for(j=0;jfilt_len-1]=0; + } + + speex_resampler_process_native(st, channel_index, &ichunk, y, &ochunk); + } else { + ichunk = 0; + ochunk = 0; + } + + for (j=0;jout_stride = ostride_save; + *in_len -= ilen; + *out_len -= olen; + + return RESAMPLER_ERR_SUCCESS; +} + +EXPORT int speex_resampler_process_interleaved_float(SpeexResamplerState *st, const float *in, spx_uint32_t *in_len, float *out, spx_uint32_t *out_len) +{ + spx_uint32_t i; + int istride_save, ostride_save; + spx_uint32_t bak_len = *out_len; + istride_save = st->in_stride; + ostride_save = st->out_stride; + st->in_stride = st->out_stride = st->nb_channels; + for (i=0;inb_channels;i++) + { + *out_len = bak_len; + if (in != NULL) + speex_resampler_process_float(st, i, in+i, in_len, out+i, out_len); + else + speex_resampler_process_float(st, i, NULL, in_len, out+i, out_len); + } + st->in_stride = istride_save; + st->out_stride = ostride_save; + return RESAMPLER_ERR_SUCCESS; +} + +EXPORT int speex_resampler_process_interleaved_int(SpeexResamplerState *st, const spx_int16_t *in, spx_uint32_t *in_len, spx_int16_t *out, spx_uint32_t *out_len) +{ + spx_uint32_t i; + int istride_save, ostride_save; + spx_uint32_t bak_len = *out_len; + istride_save = st->in_stride; + ostride_save = st->out_stride; + st->in_stride = st->out_stride = st->nb_channels; + for (i=0;inb_channels;i++) + { + *out_len = bak_len; + if (in != NULL) + speex_resampler_process_int(st, i, in+i, in_len, out+i, out_len); + else + speex_resampler_process_int(st, i, NULL, in_len, out+i, out_len); + } + st->in_stride = istride_save; + st->out_stride = ostride_save; + return RESAMPLER_ERR_SUCCESS; +} + +EXPORT int speex_resampler_set_rate(SpeexResamplerState *st, spx_uint32_t in_rate, spx_uint32_t out_rate) +{ + return speex_resampler_set_rate_frac(st, in_rate, out_rate, in_rate, out_rate); +} + +EXPORT void speex_resampler_get_rate(SpeexResamplerState *st, spx_uint32_t *in_rate, spx_uint32_t *out_rate) +{ + *in_rate = st->in_rate; + *out_rate = st->out_rate; +} + +EXPORT int speex_resampler_set_rate_frac(SpeexResamplerState *st, spx_uint32_t ratio_num, spx_uint32_t ratio_den, spx_uint32_t in_rate, spx_uint32_t out_rate) +{ + spx_uint32_t fact; + spx_uint32_t old_den; + spx_uint32_t i; + if (st->in_rate == in_rate && st->out_rate == out_rate && st->num_rate == ratio_num && st->den_rate == ratio_den) + return RESAMPLER_ERR_SUCCESS; + + old_den = st->den_rate; + st->in_rate = in_rate; + st->out_rate = out_rate; + st->num_rate = ratio_num; + st->den_rate = ratio_den; + /* FIXME: This is terribly inefficient, but who cares (at least for now)? */ + for (fact=2;fact<=IMIN(st->num_rate, st->den_rate);fact++) + { + while ((st->num_rate % fact == 0) && (st->den_rate % fact == 0)) + { + st->num_rate /= fact; + st->den_rate /= fact; + } + } + + if (old_den > 0) + { + for (i=0;inb_channels;i++) + { + st->samp_frac_num[i]=st->samp_frac_num[i]*st->den_rate/old_den; + /* Safety net */ + if (st->samp_frac_num[i] >= st->den_rate) + st->samp_frac_num[i] = st->den_rate-1; + } + } + + if (st->initialised) + update_filter(st); + return RESAMPLER_ERR_SUCCESS; +} + +EXPORT void speex_resampler_get_ratio(SpeexResamplerState *st, spx_uint32_t *ratio_num, spx_uint32_t *ratio_den) +{ + *ratio_num = st->num_rate; + *ratio_den = st->den_rate; +} + +EXPORT int speex_resampler_set_quality(SpeexResamplerState *st, int quality) +{ + if (quality > 10 || quality < 0) + return RESAMPLER_ERR_INVALID_ARG; + if (st->quality == quality) + return RESAMPLER_ERR_SUCCESS; + st->quality = quality; + if (st->initialised) + update_filter(st); + return RESAMPLER_ERR_SUCCESS; +} + +EXPORT void speex_resampler_get_quality(SpeexResamplerState *st, int *quality) +{ + *quality = st->quality; +} + +EXPORT void speex_resampler_set_input_stride(SpeexResamplerState *st, spx_uint32_t stride) +{ + st->in_stride = stride; +} + +EXPORT void speex_resampler_get_input_stride(SpeexResamplerState *st, spx_uint32_t *stride) +{ + *stride = st->in_stride; +} + +EXPORT void speex_resampler_set_output_stride(SpeexResamplerState *st, spx_uint32_t stride) +{ + st->out_stride = stride; +} + +EXPORT void speex_resampler_get_output_stride(SpeexResamplerState *st, spx_uint32_t *stride) +{ + *stride = st->out_stride; +} + +EXPORT int speex_resampler_get_input_latency(SpeexResamplerState *st) +{ + return st->filt_len / 2; +} + +EXPORT int speex_resampler_get_output_latency(SpeexResamplerState *st) +{ + return ((st->filt_len / 2) * st->den_rate + (st->num_rate >> 1)) / st->num_rate; +} + +EXPORT int speex_resampler_skip_zeros(SpeexResamplerState *st) +{ + spx_uint32_t i; + for (i=0;inb_channels;i++) + st->last_sample[i] = st->filt_len/2; + return RESAMPLER_ERR_SUCCESS; +} + +EXPORT int speex_resampler_reset_mem(SpeexResamplerState *st) +{ + spx_uint32_t i; + for (i=0;inb_channels*(st->filt_len-1);i++) + st->mem[i] = 0; + return RESAMPLER_ERR_SUCCESS; +} + +EXPORT const char *speex_resampler_strerror(int err) +{ + switch (err) + { + case RESAMPLER_ERR_SUCCESS: + return "Success."; + case RESAMPLER_ERR_ALLOC_FAILED: + return "Memory allocation failed."; + case RESAMPLER_ERR_BAD_STATE: + return "Bad resampler state."; + case RESAMPLER_ERR_INVALID_ARG: + return "Invalid argument."; + case RESAMPLER_ERR_PTR_OVERLAP: + return "Input and output buffers overlap."; + default: + return "Unknown error. Bad error code or strange version mismatch."; + } +} diff --git a/android/app/src/main/jni/libspeex/resample_sse.h b/android/app/src/main/jni/libspeex/resample_sse.h new file mode 100644 index 000000000..4bd35a2d0 --- /dev/null +++ b/android/app/src/main/jni/libspeex/resample_sse.h @@ -0,0 +1,128 @@ +/* Copyright (C) 2007-2008 Jean-Marc Valin + * Copyright (C) 2008 Thorvald Natvig + */ +/** + @file resample_sse.h + @brief Resampler functions (SSE version) +*/ +/* + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + - Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + - Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + - Neither the name of the Xiph.org Foundation nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR + CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#include + +#define OVERRIDE_INNER_PRODUCT_SINGLE +static inline float inner_product_single(const float *a, const float *b, unsigned int len) +{ + int i; + float ret; + __m128 sum = _mm_setzero_ps(); + for (i=0;i +#define OVERRIDE_INNER_PRODUCT_DOUBLE + +static inline double inner_product_double(const float *a, const float *b, unsigned int len) +{ + int i; + double ret; + __m128d sum = _mm_setzero_pd(); + __m128 t; + for (i=0;i +#include "sb_celp.h" +#include "filters.h" +#include "lpc.h" +#include "lsp.h" +#include "stack_alloc.h" +#include "cb_search.h" +#include "quant_lsp.h" +#include "vq.h" +#include "ltp.h" +#include "arch.h" +#include "math_approx.h" +#include "os_support.h" + +#ifndef NULL +#define NULL 0 +#endif + +/* Default size for the encoder and decoder stack (can be changed at compile time). + This does not apply when using variable-size arrays or alloca. */ +#ifndef SB_ENC_STACK +#define SB_ENC_STACK (10000*sizeof(spx_sig_t)) +#endif + +#ifndef SB_DEC_STACK +#define SB_DEC_STACK (6000*sizeof(spx_sig_t)) +#endif + + +#ifdef DISABLE_WIDEBAND +void *sb_encoder_init(const SpeexMode *m) +{ + speex_fatal("Wideband and Ultra-wideband are disabled"); + return NULL; +} +void sb_encoder_destroy(void *state) +{ + speex_fatal("Wideband and Ultra-wideband are disabled"); +} +int sb_encode(void *state, void *vin, SpeexBits *bits) +{ + speex_fatal("Wideband and Ultra-wideband are disabled"); + return -2; +} +void *sb_decoder_init(const SpeexMode *m) +{ + speex_fatal("Wideband and Ultra-wideband are disabled"); + return NULL; +} +void sb_decoder_destroy(void *state) +{ + speex_fatal("Wideband and Ultra-wideband are disabled"); +} +int sb_decode(void *state, SpeexBits *bits, void *vout) +{ + speex_fatal("Wideband and Ultra-wideband are disabled"); + return -2; +} +int sb_encoder_ctl(void *state, int request, void *ptr) +{ + speex_fatal("Wideband and Ultra-wideband are disabled"); + return -2; +} +int sb_decoder_ctl(void *state, int request, void *ptr) +{ + speex_fatal("Wideband and Ultra-wideband are disabled"); + return -2; +} +#else + + +#ifndef M_PI +#define M_PI 3.14159265358979323846 /* pi */ +#endif + +#define sqr(x) ((x)*(x)) + +#define SUBMODE(x) st->submodes[st->submodeID]->x + +#ifdef FIXED_POINT +static const spx_word16_t gc_quant_bound[16] = {125, 164, 215, 282, 370, 484, 635, 832, 1090, 1428, 1871, 2452, 3213, 4210, 5516, 7228}; +static const spx_word16_t fold_quant_bound[32] = { + 39, 44, 50, 57, 64, 73, 83, 94, + 106, 120, 136, 154, 175, 198, 225, 255, + 288, 327, 370, 420, 476, 539, 611, 692, + 784, 889, 1007, 1141, 1293, 1465, 1660, 1881}; +#define LSP_MARGIN 410 +#define LSP_DELTA1 6553 +#define LSP_DELTA2 1638 + +#else + +static const spx_word16_t gc_quant_bound[16] = { + 0.97979, 1.28384, 1.68223, 2.20426, 2.88829, 3.78458, 4.95900, 6.49787, + 8.51428, 11.15642, 14.61846, 19.15484, 25.09895, 32.88761, 43.09325, 56.46588}; +static const spx_word16_t fold_quant_bound[32] = { + 0.30498, 0.34559, 0.39161, 0.44375, 0.50283, 0.56979, 0.64565, 0.73162, + 0.82903, 0.93942, 1.06450, 1.20624, 1.36685, 1.54884, 1.75506, 1.98875, + 2.25355, 2.55360, 2.89361, 3.27889, 3.71547, 4.21018, 4.77076, 5.40598, + 6.12577, 6.94141, 7.86565, 8.91295, 10.09969, 11.44445, 12.96826, 14.69497}; + +#define LSP_MARGIN .05 +#define LSP_DELTA1 .2 +#define LSP_DELTA2 .05 + +#endif + +#define QMF_ORDER 64 + +#ifdef FIXED_POINT +static const spx_word16_t h0[64] = {2, -7, -7, 18, 15, -39, -25, 75, 35, -130, -41, 212, 38, -327, -17, 483, -32, -689, 124, 956, -283, -1307, 543, 1780, -973, -2467, 1733, 3633, -3339, -6409, 9059, 30153, 30153, 9059, -6409, -3339, 3633, 1733, -2467, -973, 1780, 543, -1307, -283, 956, 124, -689, -32, 483, -17, -327, 38, 212, -41, -130, 35, 75, -25, -39, 15, 18, -7, -7, 2}; + +#else +static const float h0[64] = { + 3.596189e-05f, -0.0001123515f, + -0.0001104587f, 0.0002790277f, + 0.0002298438f, -0.0005953563f, + -0.0003823631f, 0.00113826f, + 0.0005308539f, -0.001986177f, + -0.0006243724f, 0.003235877f, + 0.0005743159f, -0.004989147f, + -0.0002584767f, 0.007367171f, + -0.0004857935f, -0.01050689f, + 0.001894714f, 0.01459396f, + -0.004313674f, -0.01994365f, + 0.00828756f, 0.02716055f, + -0.01485397f, -0.03764973f, + 0.026447f, 0.05543245f, + -0.05095487f, -0.09779096f, + 0.1382363f, 0.4600981f, + 0.4600981f, 0.1382363f, + -0.09779096f, -0.05095487f, + 0.05543245f, 0.026447f, + -0.03764973f, -0.01485397f, + 0.02716055f, 0.00828756f, + -0.01994365f, -0.004313674f, + 0.01459396f, 0.001894714f, + -0.01050689f, -0.0004857935f, + 0.007367171f, -0.0002584767f, + -0.004989147f, 0.0005743159f, + 0.003235877f, -0.0006243724f, + -0.001986177f, 0.0005308539f, + 0.00113826f, -0.0003823631f, + -0.0005953563f, 0.0002298438f, + 0.0002790277f, -0.0001104587f, + -0.0001123515f, 3.596189e-05f +}; + +#endif + +extern const spx_word16_t lag_window[]; +extern const spx_word16_t lpc_window[]; + + +void *sb_encoder_init(const SpeexMode *m) +{ + int i; + spx_int32_t tmp; + SBEncState *st; + const SpeexSBMode *mode; + + st = (SBEncState*)speex_alloc(sizeof(SBEncState)); + if (!st) + return NULL; + st->mode = m; + mode = (const SpeexSBMode*)m->mode; + + + st->st_low = speex_encoder_init(mode->nb_mode); +#if defined(VAR_ARRAYS) || defined (USE_ALLOCA) + st->stack = NULL; +#else + /*st->stack = (char*)speex_alloc_scratch(SB_ENC_STACK);*/ + speex_encoder_ctl(st->st_low, SPEEX_GET_STACK, &st->stack); +#endif + + st->full_frame_size = 2*mode->frameSize; + st->frame_size = mode->frameSize; + st->subframeSize = mode->subframeSize; + st->nbSubframes = mode->frameSize/mode->subframeSize; + st->windowSize = st->frame_size+st->subframeSize; + st->lpcSize=mode->lpcSize; + + st->encode_submode = 1; + st->submodes=mode->submodes; + st->submodeSelect = st->submodeID=mode->defaultSubmode; + + tmp=9; + speex_encoder_ctl(st->st_low, SPEEX_SET_QUALITY, &tmp); + tmp=1; + speex_encoder_ctl(st->st_low, SPEEX_SET_WIDEBAND, &tmp); + + st->lpc_floor = mode->lpc_floor; + st->gamma1=mode->gamma1; + st->gamma2=mode->gamma2; + st->first=1; + + st->high=(spx_word16_t*)speex_alloc((st->windowSize-st->frame_size)*sizeof(spx_word16_t)); + + st->h0_mem=(spx_word16_t*)speex_alloc((QMF_ORDER)*sizeof(spx_word16_t)); + st->h1_mem=(spx_word16_t*)speex_alloc((QMF_ORDER)*sizeof(spx_word16_t)); + + st->window= lpc_window; + + st->lagWindow = lag_window; + + st->old_lsp = (spx_lsp_t*)speex_alloc(st->lpcSize*sizeof(spx_lsp_t)); + st->old_qlsp = (spx_lsp_t*)speex_alloc(st->lpcSize*sizeof(spx_lsp_t)); + st->interp_qlpc = (spx_coef_t*)speex_alloc(st->lpcSize*sizeof(spx_coef_t)); + st->pi_gain = (spx_word32_t*)speex_alloc((st->nbSubframes)*sizeof(spx_word32_t)); + st->exc_rms = (spx_word16_t*)speex_alloc((st->nbSubframes)*sizeof(spx_word16_t)); + st->innov_rms_save = NULL; + + st->mem_sp = (spx_mem_t*)speex_alloc((st->lpcSize)*sizeof(spx_mem_t)); + st->mem_sp2 = (spx_mem_t*)speex_alloc((st->lpcSize)*sizeof(spx_mem_t)); + st->mem_sw = (spx_mem_t*)speex_alloc((st->lpcSize)*sizeof(spx_mem_t)); + + for (i=0;ilpcSize;i++) + st->old_lsp[i]= DIV32(MULT16_16(QCONST16(3.1415927f, LSP_SHIFT), i+1), st->lpcSize+1); + +#ifndef DISABLE_VBR + st->vbr_quality = 8; + st->vbr_enabled = 0; + st->vbr_max = 0; + st->vbr_max_high = 20000; /* We just need a big value here */ + st->vad_enabled = 0; + st->abr_enabled = 0; + st->relative_quality=0; +#endif /* #ifndef DISABLE_VBR */ + + st->complexity=2; + speex_encoder_ctl(st->st_low, SPEEX_GET_SAMPLING_RATE, &st->sampling_rate); + st->sampling_rate*=2; +#ifdef ENABLE_VALGRIND + VALGRIND_MAKE_READABLE(st, (st->stack-(char*)st)); +#endif + return st; +} + +void sb_encoder_destroy(void *state) +{ + SBEncState *st=(SBEncState*)state; + + speex_encoder_destroy(st->st_low); +#if !(defined(VAR_ARRAYS) || defined (USE_ALLOCA)) + /*speex_free_scratch(st->stack);*/ +#endif + + speex_free(st->high); + + speex_free(st->h0_mem); + speex_free(st->h1_mem); + + speex_free(st->old_lsp); + speex_free(st->old_qlsp); + speex_free(st->interp_qlpc); + speex_free(st->pi_gain); + speex_free(st->exc_rms); + + speex_free(st->mem_sp); + speex_free(st->mem_sp2); + speex_free(st->mem_sw); + + + speex_free(st); +} + + +int sb_encode(void *state, void *vin, SpeexBits *bits) +{ + SBEncState *st; + int i, roots, sub; + char *stack; + VARDECL(spx_mem_t *mem); + VARDECL(spx_sig_t *innov); + VARDECL(spx_word16_t *target); + VARDECL(spx_word16_t *syn_resp); + VARDECL(spx_word32_t *low_pi_gain); + spx_word16_t *low; + spx_word16_t *high; + VARDECL(spx_word16_t *low_exc_rms); + VARDECL(spx_word16_t *low_innov_rms); + const SpeexSBMode *mode; + spx_int32_t dtx; + spx_word16_t *in = (spx_word16_t*)vin; + spx_word16_t e_low=0, e_high=0; + VARDECL(spx_coef_t *lpc); + VARDECL(spx_coef_t *interp_lpc); + VARDECL(spx_coef_t *bw_lpc1); + VARDECL(spx_coef_t *bw_lpc2); + VARDECL(spx_lsp_t *lsp); + VARDECL(spx_lsp_t *qlsp); + VARDECL(spx_lsp_t *interp_lsp); + VARDECL(spx_lsp_t *interp_qlsp); + + st = (SBEncState*)state; + stack=st->stack; + mode = (const SpeexSBMode*)(st->mode->mode); + low = in; + high = in+st->frame_size; + + /* High-band buffering / sync with low band */ + /* Compute the two sub-bands by filtering with QMF h0*/ + qmf_decomp(in, h0, low, high, st->full_frame_size, QMF_ORDER, st->h0_mem, stack); + +#ifndef DISABLE_VBR + if (st->vbr_enabled || st->vad_enabled) + { + /* Need to compute things here before the signal is trashed by the encoder */ + /*FIXME: Are the two signals (low, high) in sync? */ + e_low = compute_rms16(low, st->frame_size); + e_high = compute_rms16(high, st->frame_size); + } +#endif /* #ifndef DISABLE_VBR */ + + ALLOC(low_innov_rms, st->nbSubframes, spx_word16_t); + speex_encoder_ctl(st->st_low, SPEEX_SET_INNOVATION_SAVE, low_innov_rms); + /* Encode the narrowband part*/ + speex_encode_native(st->st_low, low, bits); + + high = high - (st->windowSize-st->frame_size); + SPEEX_COPY(high, st->high, st->windowSize-st->frame_size); + SPEEX_COPY(st->high, &high[st->frame_size], st->windowSize-st->frame_size); + + + ALLOC(low_pi_gain, st->nbSubframes, spx_word32_t); + ALLOC(low_exc_rms, st->nbSubframes, spx_word16_t); + speex_encoder_ctl(st->st_low, SPEEX_GET_PI_GAIN, low_pi_gain); + speex_encoder_ctl(st->st_low, SPEEX_GET_EXC, low_exc_rms); + + speex_encoder_ctl(st->st_low, SPEEX_GET_LOW_MODE, &dtx); + + if (dtx==0) + dtx=1; + else + dtx=0; + + ALLOC(lpc, st->lpcSize, spx_coef_t); + ALLOC(interp_lpc, st->lpcSize, spx_coef_t); + ALLOC(bw_lpc1, st->lpcSize, spx_coef_t); + ALLOC(bw_lpc2, st->lpcSize, spx_coef_t); + + ALLOC(lsp, st->lpcSize, spx_lsp_t); + ALLOC(qlsp, st->lpcSize, spx_lsp_t); + ALLOC(interp_lsp, st->lpcSize, spx_lsp_t); + ALLOC(interp_qlsp, st->lpcSize, spx_lsp_t); + + { + VARDECL(spx_word16_t *autocorr); + VARDECL(spx_word16_t *w_sig); + ALLOC(autocorr, st->lpcSize+1, spx_word16_t); + ALLOC(w_sig, st->windowSize, spx_word16_t); + /* Window for analysis */ + /* FIXME: This is a kludge */ + if (st->subframeSize==80) + { + for (i=0;iwindowSize;i++) + w_sig[i] = EXTRACT16(SHR32(MULT16_16(high[i],st->window[i>>1]),SIG_SHIFT)); + } else { + for (i=0;iwindowSize;i++) + w_sig[i] = EXTRACT16(SHR32(MULT16_16(high[i],st->window[i]),SIG_SHIFT)); + } + /* Compute auto-correlation */ + _spx_autocorr(w_sig, autocorr, st->lpcSize+1, st->windowSize); + autocorr[0] = ADD16(autocorr[0],MULT16_16_Q15(autocorr[0],st->lpc_floor)); /* Noise floor in auto-correlation domain */ + + /* Lag windowing: equivalent to filtering in the power-spectrum domain */ + for (i=0;ilpcSize+1;i++) + autocorr[i] = MULT16_16_Q14(autocorr[i],st->lagWindow[i]); + + /* Levinson-Durbin */ + _spx_lpc(lpc, autocorr, st->lpcSize); + } + + /* LPC to LSPs (x-domain) transform */ + roots=lpc_to_lsp (lpc, st->lpcSize, lsp, 10, LSP_DELTA1, stack); + if (roots!=st->lpcSize) + { + roots = lpc_to_lsp (lpc, st->lpcSize, lsp, 10, LSP_DELTA2, stack); + if (roots!=st->lpcSize) { + /*If we can't find all LSP's, do some damage control and use a flat filter*/ + for (i=0;ilpcSize;i++) + { + lsp[i]=st->old_lsp[i]; + } + } + } + +#ifndef DISABLE_VBR + /* VBR code */ + if ((st->vbr_enabled || st->vad_enabled) && !dtx) + { + float ratio; + if (st->abr_enabled) + { + float qual_change=0; + if (st->abr_drift2 * st->abr_drift > 0) + { + /* Only adapt if long-term and short-term drift are the same sign */ + qual_change = -.00001*st->abr_drift/(1+st->abr_count); + if (qual_change>.1) + qual_change=.1; + if (qual_change<-.1) + qual_change=-.1; + } + st->vbr_quality += qual_change; + if (st->vbr_quality>10) + st->vbr_quality=10; + if (st->vbr_quality<0) + st->vbr_quality=0; + } + + + ratio = 2*log((1.f+e_high)/(1.f+e_low)); + + speex_encoder_ctl(st->st_low, SPEEX_GET_RELATIVE_QUALITY, &st->relative_quality); + if (ratio<-4) + ratio=-4; + if (ratio>2) + ratio=2; + /*if (ratio>-2)*/ + if (st->vbr_enabled) + { + spx_int32_t modeid; + modeid = mode->nb_modes-1; + st->relative_quality+=1.0*(ratio+2); + if (st->relative_quality<-1) + st->relative_quality=-1; + while (modeid) + { + int v1; + float thresh; + v1=(int)floor(st->vbr_quality); + if (v1==10) + thresh = mode->vbr_thresh[modeid][v1]; + else + thresh = (st->vbr_quality-v1) * mode->vbr_thresh[modeid][v1+1] + + (1+v1-st->vbr_quality) * mode->vbr_thresh[modeid][v1]; + if (st->relative_quality >= thresh && st->sampling_rate*st->submodes[modeid]->bits_per_frame/st->full_frame_size <= st->vbr_max_high) + break; + modeid--; + } + speex_encoder_ctl(state, SPEEX_SET_HIGH_MODE, &modeid); + if (st->abr_enabled) + { + spx_int32_t bitrate; + speex_encoder_ctl(state, SPEEX_GET_BITRATE, &bitrate); + st->abr_drift+=(bitrate-st->abr_enabled); + st->abr_drift2 = .95*st->abr_drift2 + .05*(bitrate-st->abr_enabled); + st->abr_count += 1.0; + } + + } else { + /* VAD only */ + int modeid; + if (st->relative_quality<2.0) + modeid=1; + else + modeid=st->submodeSelect; + /*speex_encoder_ctl(state, SPEEX_SET_MODE, &mode);*/ + st->submodeID=modeid; + + } + /*fprintf (stderr, "%f %f\n", ratio, low_qual);*/ + } +#endif /* #ifndef DISABLE_VBR */ + + if (st->encode_submode) + { + speex_bits_pack(bits, 1, 1); + if (dtx) + speex_bits_pack(bits, 0, SB_SUBMODE_BITS); + else + speex_bits_pack(bits, st->submodeID, SB_SUBMODE_BITS); + } + + /* If null mode (no transmission), just set a couple things to zero*/ + if (dtx || st->submodes[st->submodeID] == NULL) + { + for (i=0;iframe_size;i++) + high[i]=VERY_SMALL; + + for (i=0;ilpcSize;i++) + st->mem_sw[i]=0; + st->first=1; + + /* Final signal synthesis from excitation */ + iir_mem16(high, st->interp_qlpc, high, st->frame_size, st->lpcSize, st->mem_sp, stack); + + if (dtx) + return 0; + else + return 1; + } + + + /* LSP quantization */ + SUBMODE(lsp_quant)(lsp, qlsp, st->lpcSize, bits); + + if (st->first) + { + for (i=0;ilpcSize;i++) + st->old_lsp[i] = lsp[i]; + for (i=0;ilpcSize;i++) + st->old_qlsp[i] = qlsp[i]; + } + + ALLOC(mem, st->lpcSize, spx_mem_t); + ALLOC(syn_resp, st->subframeSize, spx_word16_t); + ALLOC(innov, st->subframeSize, spx_sig_t); + ALLOC(target, st->subframeSize, spx_word16_t); + + for (sub=0;subnbSubframes;sub++) + { + VARDECL(spx_word16_t *exc); + VARDECL(spx_word16_t *res); + VARDECL(spx_word16_t *sw); + spx_word16_t *sp; + spx_word16_t filter_ratio; /*Q7*/ + int offset; + spx_word32_t rl, rh; /*Q13*/ + spx_word16_t eh=0; + + offset = st->subframeSize*sub; + sp=high+offset; + ALLOC(exc, st->subframeSize, spx_word16_t); + ALLOC(res, st->subframeSize, spx_word16_t); + ALLOC(sw, st->subframeSize, spx_word16_t); + + /* LSP interpolation (quantized and unquantized) */ + lsp_interpolate(st->old_lsp, lsp, interp_lsp, st->lpcSize, sub, st->nbSubframes); + lsp_interpolate(st->old_qlsp, qlsp, interp_qlsp, st->lpcSize, sub, st->nbSubframes); + + lsp_enforce_margin(interp_lsp, st->lpcSize, LSP_MARGIN); + lsp_enforce_margin(interp_qlsp, st->lpcSize, LSP_MARGIN); + + lsp_to_lpc(interp_lsp, interp_lpc, st->lpcSize,stack); + lsp_to_lpc(interp_qlsp, st->interp_qlpc, st->lpcSize, stack); + + bw_lpc(st->gamma1, interp_lpc, bw_lpc1, st->lpcSize); + bw_lpc(st->gamma2, interp_lpc, bw_lpc2, st->lpcSize); + + /* Compute mid-band (4000 Hz for wideband) response of low-band and high-band + filters */ + st->pi_gain[sub]=LPC_SCALING; + rh = LPC_SCALING; + for (i=0;ilpcSize;i+=2) + { + rh += st->interp_qlpc[i+1] - st->interp_qlpc[i]; + st->pi_gain[sub] += st->interp_qlpc[i] + st->interp_qlpc[i+1]; + } + + rl = low_pi_gain[sub]; +#ifdef FIXED_POINT + filter_ratio=EXTRACT16(SATURATE(PDIV32(SHL32(ADD32(rl,82),7),ADD32(82,rh)),32767)); +#else + filter_ratio=(rl+.01)/(rh+.01); +#endif + + /* Compute "real excitation" */ + fir_mem16(sp, st->interp_qlpc, exc, st->subframeSize, st->lpcSize, st->mem_sp2, stack); + /* Compute energy of low-band and high-band excitation */ + + eh = compute_rms16(exc, st->subframeSize); + + if (!SUBMODE(innovation_quant)) {/* 1 for spectral folding excitation, 0 for stochastic */ + spx_word32_t g; /*Q7*/ + spx_word16_t el; /*Q0*/ + el = low_innov_rms[sub]; + + /* Gain to use if we want to use the low-band excitation for high-band */ + g=PDIV32(MULT16_16(filter_ratio,eh),EXTEND32(ADD16(1,el))); + +#if 0 + { + char *tmp_stack=stack; + float *tmp_sig; + float g2; + ALLOC(tmp_sig, st->subframeSize, spx_sig_t); + for (i=0;ilpcSize;i++) + mem[i]=st->mem_sp[i]; + iir_mem2(st->low_innov+offset, st->interp_qlpc, tmp_sig, st->subframeSize, st->lpcSize, mem); + g2 = compute_rms(sp, st->subframeSize)/(.01+compute_rms(tmp_sig, st->subframeSize)); + /*fprintf (stderr, "gains: %f %f\n", g, g2);*/ + g = g2; + stack = tmp_stack; + } +#endif + + /*print_vec(&g, 1, "gain factor");*/ + /* Gain quantization */ + { + int quant = scal_quant(g, fold_quant_bound, 32); + /*speex_warning_int("tata", quant);*/ + if (quant<0) + quant=0; + if (quant>31) + quant=31; + speex_bits_pack(bits, quant, 5); + } + if (st->innov_rms_save) + { + st->innov_rms_save[sub] = eh; + } + st->exc_rms[sub] = eh; + } else { + spx_word16_t gc; /*Q7*/ + spx_word32_t scale; /*Q14*/ + spx_word16_t el; /*Q0*/ + el = low_exc_rms[sub]; /*Q0*/ + + gc = PDIV32_16(MULT16_16(filter_ratio,1+eh),1+el); + + /* This is a kludge that cleans up a historical bug */ + if (st->subframeSize==80) + gc = MULT16_16_P15(QCONST16(0.70711f,15),gc); + /*printf ("%f %f %f %f\n", el, eh, filter_ratio, gc);*/ + { + int qgc = scal_quant(gc, gc_quant_bound, 16); + speex_bits_pack(bits, qgc, 4); + gc = MULT16_16_Q15(QCONST16(0.87360,15),gc_quant_bound[qgc]); + } + if (st->subframeSize==80) + gc = MULT16_16_P14(QCONST16(1.4142f,14), gc); + + scale = SHL32(MULT16_16(PDIV32_16(SHL32(EXTEND32(gc),SIG_SHIFT-6),filter_ratio),(1+el)),6); + + compute_impulse_response(st->interp_qlpc, bw_lpc1, bw_lpc2, syn_resp, st->subframeSize, st->lpcSize, stack); + + + /* Reset excitation */ + for (i=0;isubframeSize;i++) + res[i]=VERY_SMALL; + + /* Compute zero response (ringing) of A(z/g1) / ( A(z/g2) * Aq(z) ) */ + for (i=0;ilpcSize;i++) + mem[i]=st->mem_sp[i]; + iir_mem16(res, st->interp_qlpc, res, st->subframeSize, st->lpcSize, mem, stack); + + for (i=0;ilpcSize;i++) + mem[i]=st->mem_sw[i]; + filter_mem16(res, bw_lpc1, bw_lpc2, res, st->subframeSize, st->lpcSize, mem, stack); + + /* Compute weighted signal */ + for (i=0;ilpcSize;i++) + mem[i]=st->mem_sw[i]; + filter_mem16(sp, bw_lpc1, bw_lpc2, sw, st->subframeSize, st->lpcSize, mem, stack); + + /* Compute target signal */ + for (i=0;isubframeSize;i++) + target[i]=SUB16(sw[i],res[i]); + + signal_div(target, target, scale, st->subframeSize); + + /* Reset excitation */ + SPEEX_MEMSET(innov, 0, st->subframeSize); + + /*print_vec(target, st->subframeSize, "\ntarget");*/ + SUBMODE(innovation_quant)(target, st->interp_qlpc, bw_lpc1, bw_lpc2, + SUBMODE(innovation_params), st->lpcSize, st->subframeSize, + innov, syn_resp, bits, stack, st->complexity, SUBMODE(double_codebook)); + /*print_vec(target, st->subframeSize, "after");*/ + + signal_mul(innov, innov, scale, st->subframeSize); + + if (SUBMODE(double_codebook)) { + char *tmp_stack=stack; + VARDECL(spx_sig_t *innov2); + ALLOC(innov2, st->subframeSize, spx_sig_t); + SPEEX_MEMSET(innov2, 0, st->subframeSize); + for (i=0;isubframeSize;i++) + target[i]=MULT16_16_P13(QCONST16(2.5f,13), target[i]); + + SUBMODE(innovation_quant)(target, st->interp_qlpc, bw_lpc1, bw_lpc2, + SUBMODE(innovation_params), st->lpcSize, st->subframeSize, + innov2, syn_resp, bits, stack, st->complexity, 0); + signal_mul(innov2, innov2, MULT16_32_P15(QCONST16(0.4f,15),scale), st->subframeSize); + + for (i=0;isubframeSize;i++) + innov[i] = ADD32(innov[i],innov2[i]); + stack = tmp_stack; + } + for (i=0;isubframeSize;i++) + exc[i] = PSHR32(innov[i],SIG_SHIFT); + + if (st->innov_rms_save) + { + st->innov_rms_save[sub] = MULT16_16_Q15(QCONST16(.70711f, 15), compute_rms(innov, st->subframeSize)); + } + st->exc_rms[sub] = compute_rms16(exc, st->subframeSize); + + + } + + + /*Keep the previous memory*/ + for (i=0;ilpcSize;i++) + mem[i]=st->mem_sp[i]; + /* Final signal synthesis from excitation */ + iir_mem16(exc, st->interp_qlpc, sp, st->subframeSize, st->lpcSize, st->mem_sp, stack); + + /* Compute weighted signal again, from synthesized speech (not sure it's the right thing) */ + filter_mem16(sp, bw_lpc1, bw_lpc2, sw, st->subframeSize, st->lpcSize, st->mem_sw, stack); + } + + for (i=0;ilpcSize;i++) + st->old_lsp[i] = lsp[i]; + for (i=0;ilpcSize;i++) + st->old_qlsp[i] = qlsp[i]; + + st->first=0; + + return 1; +} + + + + + +void *sb_decoder_init(const SpeexMode *m) +{ + spx_int32_t tmp; + SBDecState *st; + const SpeexSBMode *mode; + st = (SBDecState*)speex_alloc(sizeof(SBDecState)); + if (!st) + return NULL; + st->mode = m; + mode=(const SpeexSBMode*)m->mode; + st->encode_submode = 1; + + st->st_low = speex_decoder_init(mode->nb_mode); +#if defined(VAR_ARRAYS) || defined (USE_ALLOCA) + st->stack = NULL; +#else + /*st->stack = (char*)speex_alloc_scratch(SB_DEC_STACK);*/ + speex_decoder_ctl(st->st_low, SPEEX_GET_STACK, &st->stack); +#endif + + st->full_frame_size = 2*mode->frameSize; + st->frame_size = mode->frameSize; + st->subframeSize = mode->subframeSize; + st->nbSubframes = mode->frameSize/mode->subframeSize; + st->lpcSize=mode->lpcSize; + speex_decoder_ctl(st->st_low, SPEEX_GET_SAMPLING_RATE, &st->sampling_rate); + st->sampling_rate*=2; + tmp=1; + speex_decoder_ctl(st->st_low, SPEEX_SET_WIDEBAND, &tmp); + + st->submodes=mode->submodes; + st->submodeID=mode->defaultSubmode; + + st->first=1; + + st->g0_mem = (spx_word16_t*)speex_alloc((QMF_ORDER)*sizeof(spx_word16_t)); + st->g1_mem = (spx_word16_t*)speex_alloc((QMF_ORDER)*sizeof(spx_word16_t)); + + st->excBuf = (spx_word16_t*)speex_alloc((st->subframeSize)*sizeof(spx_word16_t)); + + st->old_qlsp = (spx_lsp_t*)speex_alloc((st->lpcSize)*sizeof(spx_lsp_t)); + st->interp_qlpc = (spx_coef_t*)speex_alloc(st->lpcSize*sizeof(spx_coef_t)); + + st->pi_gain = (spx_word32_t*)speex_alloc((st->nbSubframes)*sizeof(spx_word32_t)); + st->exc_rms = (spx_word16_t*)speex_alloc((st->nbSubframes)*sizeof(spx_word16_t)); + st->mem_sp = (spx_mem_t*)speex_alloc((2*st->lpcSize)*sizeof(spx_mem_t)); + + st->innov_save = NULL; + + + st->lpc_enh_enabled=0; + st->seed = 1000; + +#ifdef ENABLE_VALGRIND + VALGRIND_MAKE_READABLE(st, (st->stack-(char*)st)); +#endif + return st; +} + +void sb_decoder_destroy(void *state) +{ + SBDecState *st; + st = (SBDecState*)state; + speex_decoder_destroy(st->st_low); +#if !(defined(VAR_ARRAYS) || defined (USE_ALLOCA)) + /*speex_free_scratch(st->stack);*/ +#endif + + speex_free(st->g0_mem); + speex_free(st->g1_mem); + speex_free(st->excBuf); + speex_free(st->old_qlsp); + speex_free(st->interp_qlpc); + speex_free(st->pi_gain); + speex_free(st->exc_rms); + speex_free(st->mem_sp); + + speex_free(state); +} + +static void sb_decode_lost(SBDecState *st, spx_word16_t *out, int dtx, char *stack) +{ + int i; + int saved_modeid=0; + + if (dtx) + { + saved_modeid=st->submodeID; + st->submodeID=1; + } else { + bw_lpc(QCONST16(0.99f,15), st->interp_qlpc, st->interp_qlpc, st->lpcSize); + } + + st->first=1; + + + /* Final signal synthesis from excitation */ + if (!dtx) + { + st->last_ener = MULT16_16_Q15(QCONST16(.9f,15),st->last_ener); + } + for (i=0;iframe_size;i++) + out[i+st->frame_size] = speex_rand(st->last_ener, &st->seed); + + iir_mem16(out+st->frame_size, st->interp_qlpc, out+st->frame_size, st->frame_size, st->lpcSize, + st->mem_sp, stack); + + + /* Reconstruct the original */ + qmf_synth(out, out+st->frame_size, h0, out, st->full_frame_size, QMF_ORDER, st->g0_mem, st->g1_mem, stack); + if (dtx) + { + st->submodeID=saved_modeid; + } + + return; +} + +int sb_decode(void *state, SpeexBits *bits, void *vout) +{ + int i, sub; + SBDecState *st; + int wideband; + int ret; + char *stack; + VARDECL(spx_word32_t *low_pi_gain); + VARDECL(spx_word16_t *low_exc_rms); + VARDECL(spx_coef_t *ak); + VARDECL(spx_lsp_t *qlsp); + VARDECL(spx_lsp_t *interp_qlsp); + spx_int32_t dtx; + const SpeexSBMode *mode; + spx_word16_t *out = (spx_word16_t*)vout; + spx_word16_t *low_innov_alias; + spx_word32_t exc_ener_sum = 0; + + st = (SBDecState*)state; + stack=st->stack; + mode = (const SpeexSBMode*)(st->mode->mode); + + low_innov_alias = out+st->frame_size; + speex_decoder_ctl(st->st_low, SPEEX_SET_INNOVATION_SAVE, low_innov_alias); + /* Decode the low-band */ + ret = speex_decode_native(st->st_low, bits, out); + + speex_decoder_ctl(st->st_low, SPEEX_GET_DTX_STATUS, &dtx); + + /* If error decoding the narrowband part, propagate error */ + if (ret!=0) + { + return ret; + } + + if (!bits) + { + sb_decode_lost(st, out, dtx, stack); + return 0; + } + + if (st->encode_submode) + { + + /*Check "wideband bit"*/ + if (speex_bits_remaining(bits)>0) + wideband = speex_bits_peek(bits); + else + wideband = 0; + if (wideband) + { + /*Regular wideband frame, read the submode*/ + wideband = speex_bits_unpack_unsigned(bits, 1); + st->submodeID = speex_bits_unpack_unsigned(bits, SB_SUBMODE_BITS); + } else + { + /*Was a narrowband frame, set "null submode"*/ + st->submodeID = 0; + } + if (st->submodeID != 0 && st->submodes[st->submodeID] == NULL) + { + speex_notify("Invalid mode encountered. The stream is corrupted."); + return -2; + } + } + + /* If null mode (no transmission), just set a couple things to zero*/ + if (st->submodes[st->submodeID] == NULL) + { + if (dtx) + { + sb_decode_lost(st, out, 1, stack); + return 0; + } + + for (i=0;iframe_size;i++) + out[st->frame_size+i]=VERY_SMALL; + + st->first=1; + + /* Final signal synthesis from excitation */ + iir_mem16(out+st->frame_size, st->interp_qlpc, out+st->frame_size, st->frame_size, st->lpcSize, st->mem_sp, stack); + + qmf_synth(out, out+st->frame_size, h0, out, st->full_frame_size, QMF_ORDER, st->g0_mem, st->g1_mem, stack); + + return 0; + + } + + ALLOC(low_pi_gain, st->nbSubframes, spx_word32_t); + ALLOC(low_exc_rms, st->nbSubframes, spx_word16_t); + speex_decoder_ctl(st->st_low, SPEEX_GET_PI_GAIN, low_pi_gain); + speex_decoder_ctl(st->st_low, SPEEX_GET_EXC, low_exc_rms); + + ALLOC(qlsp, st->lpcSize, spx_lsp_t); + ALLOC(interp_qlsp, st->lpcSize, spx_lsp_t); + SUBMODE(lsp_unquant)(qlsp, st->lpcSize, bits); + + if (st->first) + { + for (i=0;ilpcSize;i++) + st->old_qlsp[i] = qlsp[i]; + } + + ALLOC(ak, st->lpcSize, spx_coef_t); + + for (sub=0;subnbSubframes;sub++) + { + VARDECL(spx_word32_t *exc); + spx_word16_t *innov_save=NULL; + spx_word16_t *sp; + spx_word16_t filter_ratio; + spx_word16_t el=0; + int offset; + spx_word32_t rl=0,rh=0; + + offset = st->subframeSize*sub; + sp=out+st->frame_size+offset; + ALLOC(exc, st->subframeSize, spx_word32_t); + /* Pointer for saving innovation */ + if (st->innov_save) + { + innov_save = st->innov_save+2*offset; + SPEEX_MEMSET(innov_save, 0, 2*st->subframeSize); + } + + /* LSP interpolation */ + lsp_interpolate(st->old_qlsp, qlsp, interp_qlsp, st->lpcSize, sub, st->nbSubframes); + + lsp_enforce_margin(interp_qlsp, st->lpcSize, LSP_MARGIN); + + /* LSP to LPC */ + lsp_to_lpc(interp_qlsp, ak, st->lpcSize, stack); + + /* Calculate reponse ratio between the low and high filter in the middle + of the band (4000 Hz) */ + + st->pi_gain[sub]=LPC_SCALING; + rh = LPC_SCALING; + for (i=0;ilpcSize;i+=2) + { + rh += ak[i+1] - ak[i]; + st->pi_gain[sub] += ak[i] + ak[i+1]; + } + + rl = low_pi_gain[sub]; +#ifdef FIXED_POINT + filter_ratio=EXTRACT16(SATURATE(PDIV32(SHL32(ADD32(rl,82),7),ADD32(82,rh)),32767)); +#else + filter_ratio=(rl+.01)/(rh+.01); +#endif + + SPEEX_MEMSET(exc, 0, st->subframeSize); + if (!SUBMODE(innovation_unquant)) + { + spx_word32_t g; + int quant; + + quant = speex_bits_unpack_unsigned(bits, 5); + g= spx_exp(MULT16_16(QCONST16(.125f,11),(quant-10))); + + g = PDIV32(g, filter_ratio); + + for (i=0;isubframeSize;i+=2) + { + exc[i]=SHL32(MULT16_32_P15(MULT16_16_Q15(mode->folding_gain,low_innov_alias[offset+i]),SHL32(g,6)),SIG_SHIFT); + exc[i+1]=NEG32(SHL32(MULT16_32_P15(MULT16_16_Q15(mode->folding_gain,low_innov_alias[offset+i+1]),SHL32(g,6)),SIG_SHIFT)); + } + + } else { + spx_word16_t gc; + spx_word32_t scale; + int qgc = speex_bits_unpack_unsigned(bits, 4); + + el = low_exc_rms[sub]; + gc = MULT16_16_Q15(QCONST16(0.87360,15),gc_quant_bound[qgc]); + + if (st->subframeSize==80) + gc = MULT16_16_P14(QCONST16(1.4142f,14),gc); + + scale = SHL32(PDIV32(SHL32(MULT16_16(gc, el),3), filter_ratio),SIG_SHIFT-3); + SUBMODE(innovation_unquant)(exc, SUBMODE(innovation_params), st->subframeSize, + bits, stack, &st->seed); + + signal_mul(exc,exc,scale,st->subframeSize); + + if (SUBMODE(double_codebook)) { + char *tmp_stack=stack; + VARDECL(spx_sig_t *innov2); + ALLOC(innov2, st->subframeSize, spx_sig_t); + SPEEX_MEMSET(innov2, 0, st->subframeSize); + SUBMODE(innovation_unquant)(innov2, SUBMODE(innovation_params), st->subframeSize, + bits, stack, &st->seed); + signal_mul(innov2, innov2, MULT16_32_P15(QCONST16(0.4f,15),scale), st->subframeSize); + for (i=0;isubframeSize;i++) + exc[i] = ADD32(exc[i],innov2[i]); + stack = tmp_stack; + } + + } + + if (st->innov_save) + { + for (i=0;isubframeSize;i++) + innov_save[2*i]=EXTRACT16(PSHR32(exc[i],SIG_SHIFT)); + } + + iir_mem16(st->excBuf, st->interp_qlpc, sp, st->subframeSize, st->lpcSize, + st->mem_sp, stack); + for (i=0;isubframeSize;i++) + st->excBuf[i]=EXTRACT16(PSHR32(exc[i],SIG_SHIFT)); + for (i=0;ilpcSize;i++) + st->interp_qlpc[i] = ak[i]; + st->exc_rms[sub] = compute_rms16(st->excBuf, st->subframeSize); + exc_ener_sum = ADD32(exc_ener_sum, DIV32(MULT16_16(st->exc_rms[sub],st->exc_rms[sub]), st->nbSubframes)); + } + st->last_ener = spx_sqrt(exc_ener_sum); + + qmf_synth(out, out+st->frame_size, h0, out, st->full_frame_size, QMF_ORDER, st->g0_mem, st->g1_mem, stack); + for (i=0;ilpcSize;i++) + st->old_qlsp[i] = qlsp[i]; + + st->first=0; + + return 0; +} + + +int sb_encoder_ctl(void *state, int request, void *ptr) +{ + SBEncState *st; + st=(SBEncState*)state; + switch(request) + { + case SPEEX_GET_FRAME_SIZE: + (*(spx_int32_t*)ptr) = st->full_frame_size; + break; + case SPEEX_SET_HIGH_MODE: + st->submodeSelect = st->submodeID = (*(spx_int32_t*)ptr); + break; + case SPEEX_SET_LOW_MODE: + speex_encoder_ctl(st->st_low, SPEEX_SET_LOW_MODE, ptr); + break; + case SPEEX_SET_DTX: + speex_encoder_ctl(st->st_low, SPEEX_SET_DTX, ptr); + break; + case SPEEX_GET_DTX: + speex_encoder_ctl(st->st_low, SPEEX_GET_DTX, ptr); + break; + case SPEEX_GET_LOW_MODE: + speex_encoder_ctl(st->st_low, SPEEX_GET_LOW_MODE, ptr); + break; + case SPEEX_SET_MODE: + speex_encoder_ctl(st, SPEEX_SET_QUALITY, ptr); + break; +#ifndef DISABLE_VBR + case SPEEX_SET_VBR: + st->vbr_enabled = (*(spx_int32_t*)ptr); + speex_encoder_ctl(st->st_low, SPEEX_SET_VBR, ptr); + break; + case SPEEX_GET_VBR: + (*(spx_int32_t*)ptr) = st->vbr_enabled; + break; + case SPEEX_SET_VAD: + st->vad_enabled = (*(spx_int32_t*)ptr); + speex_encoder_ctl(st->st_low, SPEEX_SET_VAD, ptr); + break; + case SPEEX_GET_VAD: + (*(spx_int32_t*)ptr) = st->vad_enabled; + break; +#endif /* #ifndef DISABLE_VBR */ +#if !defined(DISABLE_VBR) && !defined(DISABLE_FLOAT_API) + case SPEEX_SET_VBR_QUALITY: + { + spx_int32_t q; + float qual = (*(float*)ptr)+.6; + st->vbr_quality = (*(float*)ptr); + if (qual>10) + qual=10; + q=(int)floor(.5+*(float*)ptr); + if (q>10) + q=10; + speex_encoder_ctl(st->st_low, SPEEX_SET_VBR_QUALITY, &qual); + speex_encoder_ctl(state, SPEEX_SET_QUALITY, &q); + break; + } + case SPEEX_GET_VBR_QUALITY: + (*(float*)ptr) = st->vbr_quality; + break; +#endif /* #if !defined(DISABLE_VBR) && !defined(DISABLE_FLOAT_API) */ +#ifndef DISABLE_VBR + case SPEEX_SET_ABR: + st->abr_enabled = (*(spx_int32_t*)ptr); + st->vbr_enabled = st->abr_enabled!=0; + speex_encoder_ctl(st->st_low, SPEEX_SET_VBR, &st->vbr_enabled); + if (st->vbr_enabled) + { + spx_int32_t i=10, rate, target; + float vbr_qual; + target = (*(spx_int32_t*)ptr); + while (i>=0) + { + speex_encoder_ctl(st, SPEEX_SET_QUALITY, &i); + speex_encoder_ctl(st, SPEEX_GET_BITRATE, &rate); + if (rate <= target) + break; + i--; + } + vbr_qual=i; + if (vbr_qual<0) + vbr_qual=0; + speex_encoder_ctl(st, SPEEX_SET_VBR_QUALITY, &vbr_qual); + st->abr_count=0; + st->abr_drift=0; + st->abr_drift2=0; + } + + break; + case SPEEX_GET_ABR: + (*(spx_int32_t*)ptr) = st->abr_enabled; + break; +#endif /* #ifndef DISABLE_VBR */ + + case SPEEX_SET_QUALITY: + { + spx_int32_t nb_qual; + int quality = (*(spx_int32_t*)ptr); + if (quality < 0) + quality = 0; + if (quality > 10) + quality = 10; + st->submodeSelect = st->submodeID = ((const SpeexSBMode*)(st->mode->mode))->quality_map[quality]; + nb_qual = ((const SpeexSBMode*)(st->mode->mode))->low_quality_map[quality]; + speex_encoder_ctl(st->st_low, SPEEX_SET_MODE, &nb_qual); + } + break; + case SPEEX_SET_COMPLEXITY: + speex_encoder_ctl(st->st_low, SPEEX_SET_COMPLEXITY, ptr); + st->complexity = (*(spx_int32_t*)ptr); + if (st->complexity<1) + st->complexity=1; + break; + case SPEEX_GET_COMPLEXITY: + (*(spx_int32_t*)ptr) = st->complexity; + break; + case SPEEX_SET_BITRATE: + { + spx_int32_t i=10; + spx_int32_t rate, target; + target = (*(spx_int32_t*)ptr); + while (i>=0) + { + speex_encoder_ctl(st, SPEEX_SET_QUALITY, &i); + speex_encoder_ctl(st, SPEEX_GET_BITRATE, &rate); + if (rate <= target) + break; + i--; + } + } + break; + case SPEEX_GET_BITRATE: + speex_encoder_ctl(st->st_low, request, ptr); + /*fprintf (stderr, "before: %d\n", (*(int*)ptr));*/ + if (st->submodes[st->submodeID]) + (*(spx_int32_t*)ptr) += st->sampling_rate*SUBMODE(bits_per_frame)/st->full_frame_size; + else + (*(spx_int32_t*)ptr) += st->sampling_rate*(SB_SUBMODE_BITS+1)/st->full_frame_size; + /*fprintf (stderr, "after: %d\n", (*(int*)ptr));*/ + break; + case SPEEX_SET_SAMPLING_RATE: + { + spx_int32_t tmp=(*(spx_int32_t*)ptr); + st->sampling_rate = tmp; + tmp>>=1; + speex_encoder_ctl(st->st_low, SPEEX_SET_SAMPLING_RATE, &tmp); + } + break; + case SPEEX_GET_SAMPLING_RATE: + (*(spx_int32_t*)ptr)=st->sampling_rate; + break; + case SPEEX_RESET_STATE: + { + int i; + st->first = 1; + for (i=0;ilpcSize;i++) + st->old_lsp[i]= DIV32(MULT16_16(QCONST16(3.1415927f, LSP_SHIFT), i+1), st->lpcSize+1); + for (i=0;ilpcSize;i++) + st->mem_sw[i]=st->mem_sp[i]=st->mem_sp2[i]=0; + for (i=0;ih0_mem[i]=st->h1_mem[i]=0; + } + break; + case SPEEX_SET_SUBMODE_ENCODING: + st->encode_submode = (*(spx_int32_t*)ptr); + speex_encoder_ctl(st->st_low, SPEEX_SET_SUBMODE_ENCODING, ptr); + break; + case SPEEX_GET_SUBMODE_ENCODING: + (*(spx_int32_t*)ptr) = st->encode_submode; + break; + case SPEEX_GET_LOOKAHEAD: + speex_encoder_ctl(st->st_low, SPEEX_GET_LOOKAHEAD, ptr); + (*(spx_int32_t*)ptr) = 2*(*(spx_int32_t*)ptr) + QMF_ORDER - 1; + break; + case SPEEX_SET_PLC_TUNING: + speex_encoder_ctl(st->st_low, SPEEX_SET_PLC_TUNING, ptr); + break; + case SPEEX_GET_PLC_TUNING: + speex_encoder_ctl(st->st_low, SPEEX_GET_PLC_TUNING, ptr); + break; +#ifndef DISABLE_VBR + case SPEEX_SET_VBR_MAX_BITRATE: + { + st->vbr_max = (*(spx_int32_t*)ptr); + if (SPEEX_SET_VBR_MAX_BITRATE<1) + { + speex_encoder_ctl(st->st_low, SPEEX_SET_VBR_MAX_BITRATE, &st->vbr_max); + st->vbr_max_high = 17600; + } else { + spx_int32_t low_rate; + if (st->vbr_max >= 42200) + { + st->vbr_max_high = 17600; + } else if (st->vbr_max >= 27800) + { + st->vbr_max_high = 9600; + } else if (st->vbr_max > 20600) + { + st->vbr_max_high = 5600; + } else { + st->vbr_max_high = 1800; + } + if (st->subframeSize==80) + st->vbr_max_high = 1800; + low_rate = st->vbr_max - st->vbr_max_high; + speex_encoder_ctl(st->st_low, SPEEX_SET_VBR_MAX_BITRATE, &low_rate); + } + } + break; + case SPEEX_GET_VBR_MAX_BITRATE: + (*(spx_int32_t*)ptr) = st->vbr_max; + break; +#endif /* #ifndef DISABLE_VBR */ + case SPEEX_SET_HIGHPASS: + speex_encoder_ctl(st->st_low, SPEEX_SET_HIGHPASS, ptr); + break; + case SPEEX_GET_HIGHPASS: + speex_encoder_ctl(st->st_low, SPEEX_GET_HIGHPASS, ptr); + break; + + + /* This is all internal stuff past this point */ + case SPEEX_GET_PI_GAIN: + { + int i; + spx_word32_t *g = (spx_word32_t*)ptr; + for (i=0;inbSubframes;i++) + g[i]=st->pi_gain[i]; + } + break; + case SPEEX_GET_EXC: + { + int i; + for (i=0;inbSubframes;i++) + ((spx_word16_t*)ptr)[i] = st->exc_rms[i]; + } + break; +#ifndef DISABLE_VBR + case SPEEX_GET_RELATIVE_QUALITY: + (*(float*)ptr)=st->relative_quality; + break; +#endif /* #ifndef DISABLE_VBR */ + case SPEEX_SET_INNOVATION_SAVE: + st->innov_rms_save = (spx_word16_t*)ptr; + break; + case SPEEX_SET_WIDEBAND: + speex_encoder_ctl(st->st_low, SPEEX_SET_WIDEBAND, ptr); + break; + case SPEEX_GET_STACK: + *((char**)ptr) = st->stack; + break; + default: + speex_warning_int("Unknown nb_ctl request: ", request); + return -1; + } + return 0; +} + +int sb_decoder_ctl(void *state, int request, void *ptr) +{ + SBDecState *st; + st=(SBDecState*)state; + switch(request) + { + case SPEEX_SET_HIGH_MODE: + st->submodeID = (*(spx_int32_t*)ptr); + break; + case SPEEX_SET_LOW_MODE: + speex_decoder_ctl(st->st_low, SPEEX_SET_LOW_MODE, ptr); + break; + case SPEEX_GET_LOW_MODE: + speex_decoder_ctl(st->st_low, SPEEX_GET_LOW_MODE, ptr); + break; + case SPEEX_GET_FRAME_SIZE: + (*(spx_int32_t*)ptr) = st->full_frame_size; + break; + case SPEEX_SET_ENH: + speex_decoder_ctl(st->st_low, request, ptr); + st->lpc_enh_enabled = *((spx_int32_t*)ptr); + break; + case SPEEX_GET_ENH: + *((spx_int32_t*)ptr) = st->lpc_enh_enabled; + break; + case SPEEX_SET_MODE: + case SPEEX_SET_QUALITY: + { + spx_int32_t nb_qual; + int quality = (*(spx_int32_t*)ptr); + if (quality < 0) + quality = 0; + if (quality > 10) + quality = 10; + st->submodeID = ((const SpeexSBMode*)(st->mode->mode))->quality_map[quality]; + nb_qual = ((const SpeexSBMode*)(st->mode->mode))->low_quality_map[quality]; + speex_decoder_ctl(st->st_low, SPEEX_SET_MODE, &nb_qual); + } + break; + case SPEEX_GET_BITRATE: + speex_decoder_ctl(st->st_low, request, ptr); + if (st->submodes[st->submodeID]) + (*(spx_int32_t*)ptr) += st->sampling_rate*SUBMODE(bits_per_frame)/st->full_frame_size; + else + (*(spx_int32_t*)ptr) += st->sampling_rate*(SB_SUBMODE_BITS+1)/st->full_frame_size; + break; + case SPEEX_SET_SAMPLING_RATE: + { + spx_int32_t tmp=(*(spx_int32_t*)ptr); + st->sampling_rate = tmp; + tmp>>=1; + speex_decoder_ctl(st->st_low, SPEEX_SET_SAMPLING_RATE, &tmp); + } + break; + case SPEEX_GET_SAMPLING_RATE: + (*(spx_int32_t*)ptr)=st->sampling_rate; + break; + case SPEEX_SET_HANDLER: + speex_decoder_ctl(st->st_low, SPEEX_SET_HANDLER, ptr); + break; + case SPEEX_SET_USER_HANDLER: + speex_decoder_ctl(st->st_low, SPEEX_SET_USER_HANDLER, ptr); + break; + case SPEEX_RESET_STATE: + { + int i; + for (i=0;i<2*st->lpcSize;i++) + st->mem_sp[i]=0; + for (i=0;ig0_mem[i]=st->g1_mem[i]=0; + st->last_ener=0; + } + break; + case SPEEX_SET_SUBMODE_ENCODING: + st->encode_submode = (*(spx_int32_t*)ptr); + speex_decoder_ctl(st->st_low, SPEEX_SET_SUBMODE_ENCODING, ptr); + break; + case SPEEX_GET_SUBMODE_ENCODING: + (*(spx_int32_t*)ptr) = st->encode_submode; + break; + case SPEEX_GET_LOOKAHEAD: + speex_decoder_ctl(st->st_low, SPEEX_GET_LOOKAHEAD, ptr); + (*(spx_int32_t*)ptr) = 2*(*(spx_int32_t*)ptr); + break; + case SPEEX_SET_HIGHPASS: + speex_decoder_ctl(st->st_low, SPEEX_SET_HIGHPASS, ptr); + break; + case SPEEX_GET_HIGHPASS: + speex_decoder_ctl(st->st_low, SPEEX_GET_HIGHPASS, ptr); + break; + case SPEEX_GET_ACTIVITY: + speex_decoder_ctl(st->st_low, SPEEX_GET_ACTIVITY, ptr); + break; + case SPEEX_GET_PI_GAIN: + { + int i; + spx_word32_t *g = (spx_word32_t*)ptr; + for (i=0;inbSubframes;i++) + g[i]=st->pi_gain[i]; + } + break; + case SPEEX_GET_EXC: + { + int i; + for (i=0;inbSubframes;i++) + ((spx_word16_t*)ptr)[i] = st->exc_rms[i]; + } + break; + case SPEEX_GET_DTX_STATUS: + speex_decoder_ctl(st->st_low, SPEEX_GET_DTX_STATUS, ptr); + break; + case SPEEX_SET_INNOVATION_SAVE: + st->innov_save = (spx_word16_t*)ptr; + break; + case SPEEX_SET_WIDEBAND: + speex_decoder_ctl(st->st_low, SPEEX_SET_WIDEBAND, ptr); + break; + case SPEEX_GET_STACK: + *((char**)ptr) = st->stack; + break; + default: + speex_warning_int("Unknown nb_ctl request: ", request); + return -1; + } + return 0; +} + +#endif + diff --git a/android/app/src/main/jni/libspeex/sb_celp.h b/android/app/src/main/jni/libspeex/sb_celp.h new file mode 100644 index 000000000..e8c376123 --- /dev/null +++ b/android/app/src/main/jni/libspeex/sb_celp.h @@ -0,0 +1,155 @@ +/* Copyright (C) 2002-2006 Jean-Marc Valin */ +/** + @file sb_celp.h + @brief Sub-band CELP mode used for wideband encoding +*/ +/* + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + - Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + - Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + - Neither the name of the Xiph.org Foundation nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR + CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +*/ + +#ifndef SB_CELP_H +#define SB_CELP_H + +#include "modes.h" +#include +#include "nb_celp.h" + +/**Structure representing the full state of the sub-band encoder*/ +typedef struct SBEncState { + const SpeexMode *mode; /**< Pointer to the mode (containing for vtable info) */ + void *st_low; /**< State of the low-band (narrowband) encoder */ + int full_frame_size; /**< Length of full-band frames*/ + int frame_size; /**< Length of high-band frames*/ + int subframeSize; /**< Length of high-band sub-frames*/ + int nbSubframes; /**< Number of high-band sub-frames*/ + int windowSize; /**< Length of high-band LPC window*/ + int lpcSize; /**< Order of high-band LPC analysis */ + int first; /**< First frame? */ + spx_word16_t lpc_floor; /**< Controls LPC analysis noise floor */ + spx_word16_t gamma1; /**< Perceptual weighting coef 1 */ + spx_word16_t gamma2; /**< Perceptual weighting coef 2 */ + + char *stack; /**< Temporary allocation stack */ + spx_word16_t *high; /**< High-band signal (buffer) */ + spx_word16_t *h0_mem, *h1_mem; + + const spx_word16_t *window; /**< LPC analysis window */ + const spx_word16_t *lagWindow; /**< Auto-correlation window */ + spx_lsp_t *old_lsp; /**< LSPs of previous frame */ + spx_lsp_t *old_qlsp; /**< Quantized LSPs of previous frame */ + spx_coef_t *interp_qlpc; /**< Interpolated quantized LPCs for current sub-frame */ + + spx_mem_t *mem_sp; /**< Synthesis signal memory */ + spx_mem_t *mem_sp2; + spx_mem_t *mem_sw; /**< Perceptual signal memory */ + spx_word32_t *pi_gain; + spx_word16_t *exc_rms; + spx_word16_t *innov_rms_save; /**< If non-NULL, innovation is copied here */ + +#ifndef DISABLE_VBR + float vbr_quality; /**< Quality setting for VBR encoding */ + int vbr_enabled; /**< 1 for enabling VBR, 0 otherwise */ + spx_int32_t vbr_max; /**< Max bit-rate allowed in VBR mode (total) */ + spx_int32_t vbr_max_high; /**< Max bit-rate allowed in VBR mode for the high-band */ + spx_int32_t abr_enabled; /**< ABR setting (in bps), 0 if off */ + float abr_drift; + float abr_drift2; + float abr_count; + int vad_enabled; /**< 1 for enabling VAD, 0 otherwise */ + float relative_quality; +#endif /* #ifndef DISABLE_VBR */ + + int encode_submode; + const SpeexSubmode * const *submodes; + int submodeID; + int submodeSelect; + int complexity; + spx_int32_t sampling_rate; + +} SBEncState; + + +/**Structure representing the full state of the sub-band decoder*/ +typedef struct SBDecState { + const SpeexMode *mode; /**< Pointer to the mode (containing for vtable info) */ + void *st_low; /**< State of the low-band (narrowband) encoder */ + int full_frame_size; + int frame_size; + int subframeSize; + int nbSubframes; + int lpcSize; + int first; + spx_int32_t sampling_rate; + int lpc_enh_enabled; + + char *stack; + spx_word16_t *g0_mem, *g1_mem; + + spx_word16_t *excBuf; + spx_lsp_t *old_qlsp; + spx_coef_t *interp_qlpc; + + spx_mem_t *mem_sp; + spx_word32_t *pi_gain; + spx_word16_t *exc_rms; + spx_word16_t *innov_save; /** If non-NULL, innovation is copied here */ + + spx_word16_t last_ener; + spx_int32_t seed; + + int encode_submode; + const SpeexSubmode * const *submodes; + int submodeID; +} SBDecState; + + +/**Initializes encoder state*/ +void *sb_encoder_init(const SpeexMode *m); + +/**De-allocates encoder state resources*/ +void sb_encoder_destroy(void *state); + +/**Encodes one frame*/ +int sb_encode(void *state, void *in, SpeexBits *bits); + + +/**Initializes decoder state*/ +void *sb_decoder_init(const SpeexMode *m); + +/**De-allocates decoder state resources*/ +void sb_decoder_destroy(void *state); + +/**Decodes one frame*/ +int sb_decode(void *state, SpeexBits *bits, void *out); + +int sb_encoder_ctl(void *state, int request, void *ptr); + +int sb_decoder_ctl(void *state, int request, void *ptr); + +#endif diff --git a/android/app/src/main/jni/libspeex/scal.c b/android/app/src/main/jni/libspeex/scal.c new file mode 100644 index 000000000..c6abfd22d --- /dev/null +++ b/android/app/src/main/jni/libspeex/scal.c @@ -0,0 +1,289 @@ +/* Copyright (C) 2006-2008 CSIRO, Jean-Marc Valin, Xiph.Org Foundation + + File: scal.c + Shaped comb-allpass filter for channel decorrelation + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are + met: + + 1. Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + 3. The name of the author may not be used to endorse or promote products + derived from this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, + INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + POSSIBILITY OF SUCH DAMAGE. +*/ + +/* +The algorithm implemented here is described in: + +* J.-M. Valin, Perceptually-Motivated Nonlinear Channel Decorrelation For + Stereo Acoustic Echo Cancellation, Accepted for Joint Workshop on + Hands­free Speech Communication and Microphone Arrays (HSCMA), 2008. + http://people.xiph.org/~jm/papers/valin_hscma2008.pdf + +*/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "speex/speex_echo.h" +#include "vorbis_psy.h" +#include "arch.h" +#include "os_support.h" +#include "smallft.h" +#include +#include + +#define ALLPASS_ORDER 20 + +struct SpeexDecorrState_ { + int rate; + int channels; + int frame_size; +#ifdef VORBIS_PSYCHO + VorbisPsy *psy; + struct drft_lookup lookup; + float *wola_mem; + float *curve; +#endif + float *vorbis_win; + int seed; + float *y; + + /* Per-channel stuff */ + float *buff; + float (*ring)[ALLPASS_ORDER]; + int *ringID; + int *order; + float *alpha; +}; + + + +EXPORT SpeexDecorrState *speex_decorrelate_new(int rate, int channels, int frame_size) +{ + int i, ch; + SpeexDecorrState *st = speex_alloc(sizeof(SpeexDecorrState)); + st->rate = rate; + st->channels = channels; + st->frame_size = frame_size; +#ifdef VORBIS_PSYCHO + st->psy = vorbis_psy_init(rate, 2*frame_size); + spx_drft_init(&st->lookup, 2*frame_size); + st->wola_mem = speex_alloc(frame_size*sizeof(float)); + st->curve = speex_alloc(frame_size*sizeof(float)); +#endif + st->y = speex_alloc(frame_size*sizeof(float)); + + st->buff = speex_alloc(channels*2*frame_size*sizeof(float)); + st->ringID = speex_alloc(channels*sizeof(int)); + st->order = speex_alloc(channels*sizeof(int)); + st->alpha = speex_alloc(channels*sizeof(float)); + st->ring = speex_alloc(channels*ALLPASS_ORDER*sizeof(float)); + + /*FIXME: The +20 is there only as a kludge for ALL_PASS_OLA*/ + st->vorbis_win = speex_alloc((2*frame_size+20)*sizeof(float)); + for (i=0;i<2*frame_size;i++) + st->vorbis_win[i] = sin(.5*M_PI* sin(M_PI*i/(2*frame_size))*sin(M_PI*i/(2*frame_size)) ); + st->seed = rand(); + + for (ch=0;chring[ch][i] = 0; + st->ringID[ch] = 0; + st->alpha[ch] = 0; + st->order[ch] = 10; + } + return st; +} + +static float uni_rand(int *seed) +{ + const unsigned int jflone = 0x3f800000; + const unsigned int jflmsk = 0x007fffff; + union {int i; float f;} ran; + *seed = 1664525 * *seed + 1013904223; + ran.i = jflone | (jflmsk & *seed); + ran.f -= 1.5; + return 2*ran.f; +} + +static unsigned int irand(int *seed) +{ + *seed = 1664525 * *seed + 1013904223; + return ((unsigned int)*seed)>>16; +} + + +EXPORT void speex_decorrelate(SpeexDecorrState *st, const spx_int16_t *in, spx_int16_t *out, int strength) +{ + int ch; + float amount; + + if (strength<0) + strength = 0; + if (strength>100) + strength = 100; + + amount = .01*strength; + for (ch=0;chchannels;ch++) + { + int i; + int N=2*st->frame_size; + float beta, beta2; + float *x; + float max_alpha = 0; + + float *buff; + float *ring; + int ringID; + int order; + float alpha; + + buff = st->buff+ch*2*st->frame_size; + ring = st->ring[ch]; + ringID = st->ringID[ch]; + order = st->order[ch]; + alpha = st->alpha[ch]; + + for (i=0;iframe_size;i++) + buff[i] = buff[i+st->frame_size]; + for (i=0;iframe_size;i++) + buff[i+st->frame_size] = in[i*st->channels+ch]; + + x = buff+st->frame_size; + beta = 1.-.3*amount*amount; + if (amount>1) + beta = 1-sqrt(.4*amount); + else + beta = 1-0.63246*amount; + if (beta<0) + beta = 0; + + beta2 = beta; + for (i=0;iframe_size;i++) + { + st->y[i] = alpha*(x[i-ALLPASS_ORDER+order]-beta*x[i-ALLPASS_ORDER+order-1])*st->vorbis_win[st->frame_size+i+order] + + x[i-ALLPASS_ORDER]*st->vorbis_win[st->frame_size+i] + - alpha*(ring[ringID] + - beta*ring[ringID+1>=order?0:ringID+1]); + ring[ringID++]=st->y[i]; + st->y[i] *= st->vorbis_win[st->frame_size+i]; + if (ringID>=order) + ringID=0; + } + order = order+(irand(&st->seed)%3)-1; + if (order < 5) + order = 5; + if (order > 10) + order = 10; + /*order = 5+(irand(&st->seed)%6);*/ + max_alpha = pow(.96+.04*(amount-1),order); + if (max_alpha > .98/(1.+beta2)) + max_alpha = .98/(1.+beta2); + + alpha = alpha + .4*uni_rand(&st->seed); + if (alpha > max_alpha) + alpha = max_alpha; + if (alpha < -max_alpha) + alpha = -max_alpha; + for (i=0;iframe_size;i++) + { + float tmp = alpha*(x[i-ALLPASS_ORDER+order]-beta*x[i-ALLPASS_ORDER+order-1])*st->vorbis_win[i+order] + + x[i-ALLPASS_ORDER]*st->vorbis_win[i] + - alpha*(ring[ringID] + - beta*ring[ringID+1>=order?0:ringID+1]); + ring[ringID++]=tmp; + tmp *= st->vorbis_win[i]; + if (ringID>=order) + ringID=0; + st->y[i] += tmp; + } + +#ifdef VORBIS_PSYCHO + float frame[N]; + float scale = 1./N; + for (i=0;i<2*st->frame_size;i++) + frame[i] = buff[i]; + //float coef = .5*0.78130; + float coef = M_PI*0.075063 * 0.93763 * amount * .8 * 0.707; + compute_curve(st->psy, buff, st->curve); + for (i=1;iframe_size;i++) + { + float x1,x2; + float gain; + do { + x1 = uni_rand(&st->seed); + x2 = uni_rand(&st->seed); + } while (x1*x1+x2*x2 > 1.); + gain = coef*sqrt(.1+st->curve[i]); + frame[2*i-1] = gain*x1; + frame[2*i] = gain*x2; + } + frame[0] = coef*uni_rand(&st->seed)*sqrt(.1+st->curve[0]); + frame[2*st->frame_size-1] = coef*uni_rand(&st->seed)*sqrt(.1+st->curve[st->frame_size-1]); + spx_drft_backward(&st->lookup,frame); + for (i=0;i<2*st->frame_size;i++) + frame[i] *= st->vorbis_win[i]; +#endif + + for (i=0;iframe_size;i++) + { +#ifdef VORBIS_PSYCHO + float tmp = st->y[i] + frame[i] + st->wola_mem[i]; + st->wola_mem[i] = frame[i+st->frame_size]; +#else + float tmp = st->y[i]; +#endif + if (tmp>32767) + tmp = 32767; + if (tmp < -32767) + tmp = -32767; + out[i*st->channels+ch] = tmp; + } + + st->ringID[ch] = ringID; + st->order[ch] = order; + st->alpha[ch] = alpha; + + } +} + +EXPORT void speex_decorrelate_destroy(SpeexDecorrState *st) +{ +#ifdef VORBIS_PSYCHO + vorbis_psy_destroy(st->psy); + speex_free(st->wola_mem); + speex_free(st->curve); +#endif + speex_free(st->buff); + speex_free(st->ring); + speex_free(st->ringID); + speex_free(st->alpha); + speex_free(st->vorbis_win); + speex_free(st->order); + speex_free(st->y); + speex_free(st); +} diff --git a/android/app/src/main/jni/libspeex/smallft.c b/android/app/src/main/jni/libspeex/smallft.c new file mode 100644 index 000000000..5c26d016f --- /dev/null +++ b/android/app/src/main/jni/libspeex/smallft.c @@ -0,0 +1,1261 @@ +/******************************************************************** + * * + * THIS FILE IS PART OF THE OggVorbis SOFTWARE CODEC SOURCE CODE. * + * USE, DISTRIBUTION AND REPRODUCTION OF THIS LIBRARY SOURCE IS * + * GOVERNED BY A BSD-STYLE SOURCE LICENSE INCLUDED WITH THIS SOURCE * + * IN 'COPYING'. PLEASE READ THESE TERMS BEFORE DISTRIBUTING. * + * * + * THE OggVorbis SOURCE CODE IS (C) COPYRIGHT 1994-2001 * + * by the XIPHOPHORUS Company http://www.xiph.org/ * + * * + ******************************************************************** + + function: *unnormalized* fft transform + last mod: $Id: smallft.c,v 1.19 2003/10/08 05:12:37 jm Exp $ + + ********************************************************************/ + +/* FFT implementation from OggSquish, minus cosine transforms, + * minus all but radix 2/4 case. In Vorbis we only need this + * cut-down version. + * + * To do more than just power-of-two sized vectors, see the full + * version I wrote for NetLib. + * + * Note that the packing is a little strange; rather than the FFT r/i + * packing following R_0, I_n, R_1, I_1, R_2, I_2 ... R_n-1, I_n-1, + * it follows R_0, R_1, I_1, R_2, I_2 ... R_n-1, I_n-1, I_n like the + * FORTRAN version + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include +#include "smallft.h" +#include "arch.h" +#include "os_support.h" + +static void drfti1(int n, float *wa, int *ifac){ + static int ntryh[4] = { 4,2,3,5 }; + static float tpi = 6.28318530717958648f; + float arg,argh,argld,fi; + int ntry=0,i,j=-1; + int k1, l1, l2, ib; + int ld, ii, ip, is, nq, nr; + int ido, ipm, nfm1; + int nl=n; + int nf=0; + + L101: + j++; + if (j < 4) + ntry=ntryh[j]; + else + ntry+=2; + + L104: + nq=nl/ntry; + nr=nl-ntry*nq; + if (nr!=0) goto L101; + + nf++; + ifac[nf+1]=ntry; + nl=nq; + if(ntry!=2)goto L107; + if(nf==1)goto L107; + + for (i=1;i>1; + ipp2=ip; + idp2=ido; + nbd=(ido-1)>>1; + t0=l1*ido; + t10=ip*ido; + + if(ido==1)goto L119; + for(ik=0;ikl1){ + for(j=1;j>1; + ipp2=ip; + ipph=(ip+1)>>1; + if(idol1)goto L139; + + is= -ido-1; + t1=0; + for(j=1;jn==1)return; + drftf1(l->n,data,l->trigcache,l->trigcache+l->n,l->splitcache); +} + +void spx_drft_backward(struct drft_lookup *l,float *data){ + if (l->n==1)return; + drftb1(l->n,data,l->trigcache,l->trigcache+l->n,l->splitcache); +} + +void spx_drft_init(struct drft_lookup *l,int n) +{ + l->n=n; + l->trigcache=(float*)speex_alloc(3*n*sizeof(*l->trigcache)); + l->splitcache=(int*)speex_alloc(32*sizeof(*l->splitcache)); + fdrffti(n, l->trigcache, l->splitcache); +} + +void spx_drft_clear(struct drft_lookup *l) +{ + if(l) + { + if(l->trigcache) + speex_free(l->trigcache); + if(l->splitcache) + speex_free(l->splitcache); + } +} diff --git a/android/app/src/main/jni/libspeex/smallft.h b/android/app/src/main/jni/libspeex/smallft.h new file mode 100644 index 000000000..446e2f65b --- /dev/null +++ b/android/app/src/main/jni/libspeex/smallft.h @@ -0,0 +1,46 @@ +/******************************************************************** + * * + * THIS FILE IS PART OF THE OggVorbis SOFTWARE CODEC SOURCE CODE. * + * USE, DISTRIBUTION AND REPRODUCTION OF THIS LIBRARY SOURCE IS * + * GOVERNED BY A BSD-STYLE SOURCE LICENSE INCLUDED WITH THIS SOURCE * + * IN 'COPYING'. PLEASE READ THESE TERMS BEFORE DISTRIBUTING. * + * * + * THE OggVorbis SOURCE CODE IS (C) COPYRIGHT 1994-2001 * + * by the XIPHOPHORUS Company http://www.xiph.org/ * + * * + ******************************************************************** + + function: fft transform + last mod: $Id: smallft.h,v 1.3 2003/09/16 18:35:45 jm Exp $ + + ********************************************************************/ +/** + @file smallft.h + @brief Discrete Rotational Fourier Transform (DRFT) +*/ + +#ifndef _V_SMFT_H_ +#define _V_SMFT_H_ + + +#ifdef __cplusplus +extern "C" { +#endif + +/** Discrete Rotational Fourier Transform lookup */ +struct drft_lookup{ + int n; + float *trigcache; + int *splitcache; +}; + +extern void spx_drft_forward(struct drft_lookup *l,float *data); +extern void spx_drft_backward(struct drft_lookup *l,float *data); +extern void spx_drft_init(struct drft_lookup *l,int n); +extern void spx_drft_clear(struct drft_lookup *l); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/android/app/src/main/jni/libspeex/speex.c b/android/app/src/main/jni/libspeex/speex.c new file mode 100644 index 000000000..b425155c2 --- /dev/null +++ b/android/app/src/main/jni/libspeex/speex.c @@ -0,0 +1,250 @@ +/* Copyright (C) 2002 Jean-Marc Valin + File: speex.c + + Basic Speex functions + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + - Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + - Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + - Neither the name of the Xiph.org Foundation nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR + CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +*/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "modes.h" +#include +#include "os_support.h" + +#ifndef NULL +#define NULL 0 +#endif + +#define MAX_IN_SAMPLES 640 + + + +EXPORT void *speex_encoder_init(const SpeexMode *mode) +{ + return mode->enc_init(mode); +} + +EXPORT void *speex_decoder_init(const SpeexMode *mode) +{ + return mode->dec_init(mode); +} + +EXPORT void speex_encoder_destroy(void *state) +{ + (*((SpeexMode**)state))->enc_destroy(state); +} + +EXPORT void speex_decoder_destroy(void *state) +{ + (*((SpeexMode**)state))->dec_destroy(state); +} + + + +int speex_encode_native(void *state, spx_word16_t *in, SpeexBits *bits) +{ + return (*((SpeexMode**)state))->enc(state, in, bits); +} + +int speex_decode_native(void *state, SpeexBits *bits, spx_word16_t *out) +{ + return (*((SpeexMode**)state))->dec(state, bits, out); +} + + + +#ifdef FIXED_POINT + +#ifndef DISABLE_FLOAT_API +EXPORT int speex_encode(void *state, float *in, SpeexBits *bits) +{ + int i; + spx_int32_t N; + spx_int16_t short_in[MAX_IN_SAMPLES]; + speex_encoder_ctl(state, SPEEX_GET_FRAME_SIZE, &N); + for (i=0;i32767.f) + short_in[i] = 32767; + else if (in[i]<-32768.f) + short_in[i] = -32768; + else + short_in[i] = (spx_int16_t)floor(.5+in[i]); + } + return (*((SpeexMode**)state))->enc(state, short_in, bits); +} +#endif /* #ifndef DISABLE_FLOAT_API */ + +EXPORT int speex_encode_int(void *state, spx_int16_t *in, SpeexBits *bits) +{ + SpeexMode *mode; + mode = *(SpeexMode**)state; + return (mode)->enc(state, in, bits); +} + +#ifndef DISABLE_FLOAT_API +EXPORT int speex_decode(void *state, SpeexBits *bits, float *out) +{ + int i, ret; + spx_int32_t N; + spx_int16_t short_out[MAX_IN_SAMPLES]; + speex_decoder_ctl(state, SPEEX_GET_FRAME_SIZE, &N); + ret = (*((SpeexMode**)state))->dec(state, bits, short_out); + for (i=0;idec(state, bits, out); +} + +#else + +EXPORT int speex_encode(void *state, float *in, SpeexBits *bits) +{ + return (*((SpeexMode**)state))->enc(state, in, bits); +} + +EXPORT int speex_encode_int(void *state, spx_int16_t *in, SpeexBits *bits) +{ + int i; + spx_int32_t N; + float float_in[MAX_IN_SAMPLES]; + speex_encoder_ctl(state, SPEEX_GET_FRAME_SIZE, &N); + for (i=0;ienc(state, float_in, bits); +} + +EXPORT int speex_decode(void *state, SpeexBits *bits, float *out) +{ + return (*((SpeexMode**)state))->dec(state, bits, out); +} + +EXPORT int speex_decode_int(void *state, SpeexBits *bits, spx_int16_t *out) +{ + int i; + spx_int32_t N; + float float_out[MAX_IN_SAMPLES]; + int ret; + speex_decoder_ctl(state, SPEEX_GET_FRAME_SIZE, &N); + ret = (*((SpeexMode**)state))->dec(state, bits, float_out); + for (i=0;i32767.f) + out[i] = 32767; + else if (float_out[i]<-32768.f) + out[i] = -32768; + else + out[i] = (spx_int16_t)floor(.5+float_out[i]); + } + return ret; +} +#endif + + + +EXPORT int speex_encoder_ctl(void *state, int request, void *ptr) +{ + return (*((SpeexMode**)state))->enc_ctl(state, request, ptr); +} + +EXPORT int speex_decoder_ctl(void *state, int request, void *ptr) +{ + return (*((SpeexMode**)state))->dec_ctl(state, request, ptr); +} + + + +int nb_mode_query(const void *mode, int request, void *ptr) +{ + const SpeexNBMode *m = (const SpeexNBMode*)mode; + + switch (request) + { + case SPEEX_MODE_FRAME_SIZE: + *((int*)ptr)=m->frameSize; + break; + case SPEEX_SUBMODE_BITS_PER_FRAME: + if (*((int*)ptr)==0) + *((int*)ptr) = NB_SUBMODE_BITS+1; + else if (m->submodes[*((int*)ptr)]==NULL) + *((int*)ptr) = -1; + else + *((int*)ptr) = m->submodes[*((int*)ptr)]->bits_per_frame; + break; + default: + speex_warning_int("Unknown nb_mode_query request: ", request); + return -1; + } + return 0; +} + + + +EXPORT int speex_lib_ctl(int request, void *ptr) +{ + switch (request) + { + case SPEEX_LIB_GET_MAJOR_VERSION: + *((int*)ptr) = SPEEX_MAJOR_VERSION; + break; + case SPEEX_LIB_GET_MINOR_VERSION: + *((int*)ptr) = SPEEX_MINOR_VERSION; + break; + case SPEEX_LIB_GET_MICRO_VERSION: + *((int*)ptr) = SPEEX_MICRO_VERSION; + break; + case SPEEX_LIB_GET_EXTRA_VERSION: + *((const char**)ptr) = SPEEX_EXTRA_VERSION; + break; + case SPEEX_LIB_GET_VERSION_STRING: + *((const char**)ptr) = SPEEX_VERSION; + break; + /*case SPEEX_LIB_SET_ALLOC_FUNC: + break; + case SPEEX_LIB_GET_ALLOC_FUNC: + break; + case SPEEX_LIB_SET_FREE_FUNC: + break; + case SPEEX_LIB_GET_FREE_FUNC: + break;*/ + default: + speex_warning_int("Unknown wb_mode_query request: ", request); + return -1; + } + return 0; +} diff --git a/android/app/src/main/jni/libspeex/speex_callbacks.c b/android/app/src/main/jni/libspeex/speex_callbacks.c new file mode 100644 index 000000000..0e077c380 --- /dev/null +++ b/android/app/src/main/jni/libspeex/speex_callbacks.c @@ -0,0 +1,144 @@ +/* Copyright (C) 2002 Jean-Marc Valin + File speex_callbacks.c + Callback handling and in-band signalling + + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + - Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + - Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + - Neither the name of the Xiph.org Foundation nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR + CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +*/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include +#include "arch.h" +#include "os_support.h" + +EXPORT int speex_inband_handler(SpeexBits *bits, SpeexCallback *callback_list, void *state) +{ + int id; + SpeexCallback *callback; + /*speex_bits_advance(bits, 5);*/ + id=speex_bits_unpack_unsigned(bits, 4); + callback = callback_list+id; + + if (callback->func) + { + return callback->func(bits, state, callback->data); + } else + /*If callback is not registered, skip the right number of bits*/ + { + int adv; + if (id<2) + adv = 1; + else if (id<8) + adv = 4; + else if (id<10) + adv = 8; + else if (id<12) + adv = 16; + else if (id<14) + adv = 32; + else + adv = 64; + speex_bits_advance(bits, adv); + } + return 0; +} + +EXPORT int speex_std_mode_request_handler(SpeexBits *bits, void *state, void *data) +{ + spx_int32_t m; + m = speex_bits_unpack_unsigned(bits, 4); + speex_encoder_ctl(data, SPEEX_SET_MODE, &m); + return 0; +} + +EXPORT int speex_std_low_mode_request_handler(SpeexBits *bits, void *state, void *data) +{ + spx_int32_t m; + m = speex_bits_unpack_unsigned(bits, 4); + speex_encoder_ctl(data, SPEEX_SET_LOW_MODE, &m); + return 0; +} + +EXPORT int speex_std_high_mode_request_handler(SpeexBits *bits, void *state, void *data) +{ + spx_int32_t m; + m = speex_bits_unpack_unsigned(bits, 4); + speex_encoder_ctl(data, SPEEX_SET_HIGH_MODE, &m); + return 0; +} + +#ifndef DISABLE_VBR +EXPORT int speex_std_vbr_request_handler(SpeexBits *bits, void *state, void *data) +{ + spx_int32_t vbr; + vbr = speex_bits_unpack_unsigned(bits, 1); + speex_encoder_ctl(data, SPEEX_SET_VBR, &vbr); + return 0; +} +#endif /* #ifndef DISABLE_VBR */ + +EXPORT int speex_std_enh_request_handler(SpeexBits *bits, void *state, void *data) +{ + spx_int32_t enh; + enh = speex_bits_unpack_unsigned(bits, 1); + speex_decoder_ctl(data, SPEEX_SET_ENH, &enh); + return 0; +} + +#ifndef DISABLE_VBR +EXPORT int speex_std_vbr_quality_request_handler(SpeexBits *bits, void *state, void *data) +{ + float qual; + qual = speex_bits_unpack_unsigned(bits, 4); + speex_encoder_ctl(data, SPEEX_SET_VBR_QUALITY, &qual); + return 0; +} +#endif /* #ifndef DISABLE_VBR */ + +EXPORT int speex_std_char_handler(SpeexBits *bits, void *state, void *data) +{ + unsigned char ch; + ch = speex_bits_unpack_unsigned(bits, 8); + _speex_putc(ch, data); + /*printf("speex_std_char_handler ch=%x\n", ch);*/ + return 0; +} + + + +/* Default handler for user callbacks: skip it */ +EXPORT int speex_default_user_handler(SpeexBits *bits, void *state, void *data) +{ + int req_size = speex_bits_unpack_unsigned(bits, 4); + speex_bits_advance(bits, 5+8*req_size); + return 0; +} diff --git a/android/app/src/main/jni/libspeex/speex_header.c b/android/app/src/main/jni/libspeex/speex_header.c new file mode 100644 index 000000000..b7430595f --- /dev/null +++ b/android/app/src/main/jni/libspeex/speex_header.c @@ -0,0 +1,200 @@ +/* Copyright (C) 2002 Jean-Marc Valin + File: speex_header.c + Describes the Speex header + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + - Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + - Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + - Neither the name of the Xiph.org Foundation nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR + CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +*/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "arch.h" +#include +#include +#include "os_support.h" + +#ifndef NULL +#define NULL 0 +#endif + +/** Convert little endian */ +static inline spx_int32_t le_int(spx_int32_t i) +{ +#if !defined(__LITTLE_ENDIAN__) && ( defined(WORDS_BIGENDIAN) || defined(__BIG_ENDIAN__) ) + spx_uint32_t ui, ret; + ui = i; + ret = ui>>24; + ret |= (ui>>8)&0x0000ff00; + ret |= (ui<<8)&0x00ff0000; + ret |= (ui<<24); + return ret; +#else + return i; +#endif +} + +#define ENDIAN_SWITCH(x) {x=le_int(x);} + + +/* +typedef struct SpeexHeader { + char speex_string[8]; + char speex_version[SPEEX_HEADER_VERSION_LENGTH]; + int speex_version_id; + int header_size; + int rate; + int mode; + int mode_bitstream_version; + int nb_channels; + int bitrate; + int frame_size; + int vbr; + int frames_per_packet; + int extra_headers; + int reserved1; + int reserved2; +} SpeexHeader; +*/ + +EXPORT void speex_init_header(SpeexHeader *header, int rate, int nb_channels, const SpeexMode *m) +{ + int i; + const char *h="Speex "; + /* + strncpy(header->speex_string, "Speex ", 8); + strncpy(header->speex_version, SPEEX_VERSION, SPEEX_HEADER_VERSION_LENGTH-1); + header->speex_version[SPEEX_HEADER_VERSION_LENGTH-1]=0; + */ + for (i=0;i<8;i++) + header->speex_string[i]=h[i]; + for (i=0;ispeex_version[i]=SPEEX_VERSION[i]; + for (;ispeex_version[i]=0; + + header->speex_version_id = 1; + header->header_size = sizeof(SpeexHeader); + + header->rate = rate; + header->mode = m->modeID; + header->mode_bitstream_version = m->bitstream_version; + if (m->modeID<0) + speex_warning("This mode is meant to be used alone"); + header->nb_channels = nb_channels; + header->bitrate = -1; + speex_mode_query(m, SPEEX_MODE_FRAME_SIZE, &header->frame_size); + header->vbr = 0; + + header->frames_per_packet = 0; + header->extra_headers = 0; + header->reserved1 = 0; + header->reserved2 = 0; +} + +EXPORT char *speex_header_to_packet(SpeexHeader *header, int *size) +{ + SpeexHeader *le_header; + le_header = (SpeexHeader*)speex_alloc(sizeof(SpeexHeader)); + + SPEEX_COPY(le_header, header, 1); + + /*Make sure everything is now little-endian*/ + ENDIAN_SWITCH(le_header->speex_version_id); + ENDIAN_SWITCH(le_header->header_size); + ENDIAN_SWITCH(le_header->rate); + ENDIAN_SWITCH(le_header->mode); + ENDIAN_SWITCH(le_header->mode_bitstream_version); + ENDIAN_SWITCH(le_header->nb_channels); + ENDIAN_SWITCH(le_header->bitrate); + ENDIAN_SWITCH(le_header->frame_size); + ENDIAN_SWITCH(le_header->vbr); + ENDIAN_SWITCH(le_header->frames_per_packet); + ENDIAN_SWITCH(le_header->extra_headers); + + *size = sizeof(SpeexHeader); + return (char *)le_header; +} + +EXPORT SpeexHeader *speex_packet_to_header(char *packet, int size) +{ + int i; + SpeexHeader *le_header; + const char *h = "Speex "; + for (i=0;i<8;i++) + if (packet[i]!=h[i]) + { + speex_notify("This doesn't look like a Speex file"); + return NULL; + } + + /*FIXME: Do we allow larger headers?*/ + if (size < (int)sizeof(SpeexHeader)) + { + speex_notify("Speex header too small"); + return NULL; + } + + le_header = (SpeexHeader*)speex_alloc(sizeof(SpeexHeader)); + + SPEEX_COPY(le_header, (SpeexHeader*)packet, 1); + + /*Make sure everything is converted correctly from little-endian*/ + ENDIAN_SWITCH(le_header->speex_version_id); + ENDIAN_SWITCH(le_header->header_size); + ENDIAN_SWITCH(le_header->rate); + ENDIAN_SWITCH(le_header->mode); + ENDIAN_SWITCH(le_header->mode_bitstream_version); + ENDIAN_SWITCH(le_header->nb_channels); + ENDIAN_SWITCH(le_header->bitrate); + ENDIAN_SWITCH(le_header->frame_size); + ENDIAN_SWITCH(le_header->vbr); + ENDIAN_SWITCH(le_header->frames_per_packet); + ENDIAN_SWITCH(le_header->extra_headers); + + if (le_header->mode >= SPEEX_NB_MODES || le_header->mode < 0) + { + speex_notify("Invalid mode specified in Speex header"); + speex_free (le_header); + return NULL; + } + + if (le_header->nb_channels>2) + le_header->nb_channels = 2; + if (le_header->nb_channels<1) + le_header->nb_channels = 1; + + return le_header; + +} + +EXPORT void speex_header_free(void *ptr) +{ + speex_free(ptr); +} diff --git a/android/app/src/main/jni/libspeex/stack_alloc.h b/android/app/src/main/jni/libspeex/stack_alloc.h new file mode 100644 index 000000000..5264e666b --- /dev/null +++ b/android/app/src/main/jni/libspeex/stack_alloc.h @@ -0,0 +1,115 @@ +/* Copyright (C) 2002 Jean-Marc Valin */ +/** + @file stack_alloc.h + @brief Temporary memory allocation on stack +*/ +/* + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + - Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + - Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + - Neither the name of the Xiph.org Foundation nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR + CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#ifndef STACK_ALLOC_H +#define STACK_ALLOC_H + +#ifdef USE_ALLOCA +# ifdef WIN32 +# include +# else +# ifdef HAVE_ALLOCA_H +# include +# else +# include +# endif +# endif +#endif + +/** + * @def ALIGN(stack, size) + * + * Aligns the stack to a 'size' boundary + * + * @param stack Stack + * @param size New size boundary + */ + +/** + * @def PUSH(stack, size, type) + * + * Allocates 'size' elements of type 'type' on the stack + * + * @param stack Stack + * @param size Number of elements + * @param type Type of element + */ + +/** + * @def VARDECL(var) + * + * Declare variable on stack + * + * @param var Variable to declare + */ + +/** + * @def ALLOC(var, size, type) + * + * Allocate 'size' elements of 'type' on stack + * + * @param var Name of variable to allocate + * @param size Number of elements + * @param type Type of element + */ + +#ifdef ENABLE_VALGRIND + +#include + +#define ALIGN(stack, size) ((stack) += ((size) - (long)(stack)) & ((size) - 1)) + +#define PUSH(stack, size, type) (VALGRIND_MAKE_NOACCESS(stack, 1000),ALIGN((stack),sizeof(type)),VALGRIND_MAKE_WRITABLE(stack, ((size)*sizeof(type))),(stack)+=((size)*sizeof(type)),(type*)((stack)-((size)*sizeof(type)))) + +#else + +#define ALIGN(stack, size) ((stack) += ((size) - (long)(stack)) & ((size) - 1)) + +#define PUSH(stack, size, type) (ALIGN((stack),sizeof(type)),(stack)+=((size)*sizeof(type)),(type*)((stack)-((size)*sizeof(type)))) + +#endif + +#if defined(VAR_ARRAYS) +#define VARDECL(var) +#define ALLOC(var, size, type) type var[size] +#elif defined(USE_ALLOCA) +#define VARDECL(var) var +#define ALLOC(var, size, type) var = alloca(sizeof(type)*(size)) +#else +#define VARDECL(var) var +#define ALLOC(var, size, type) var = PUSH(stack, size, type) +#endif + + +#endif diff --git a/android/app/src/main/jni/libspeex/stereo.c b/android/app/src/main/jni/libspeex/stereo.c new file mode 100644 index 000000000..db5ea4a85 --- /dev/null +++ b/android/app/src/main/jni/libspeex/stereo.c @@ -0,0 +1,296 @@ +/* Copyright (C) 2002 Jean-Marc Valin + File: stereo.c + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + - Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + - Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + - Neither the name of the Xiph.org Foundation nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR + CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include +#include +#include "math_approx.h" +#include "vq.h" +#include +#include "os_support.h" + +typedef struct RealSpeexStereoState { + spx_word32_t balance; /**< Left/right balance info */ + spx_word32_t e_ratio; /**< Ratio of energies: E(left+right)/[E(left)+E(right)] */ + spx_word32_t smooth_left; /**< Smoothed left channel gain */ + spx_word32_t smooth_right; /**< Smoothed right channel gain */ + spx_uint32_t reserved1; /**< Reserved for future use */ + spx_int32_t reserved2; /**< Reserved for future use */ +} RealSpeexStereoState; + + +/*float e_ratio_quant[4] = {1, 1.26, 1.587, 2};*/ +#ifndef FIXED_POINT +static const float e_ratio_quant[4] = {.25f, .315f, .397f, .5f}; +static const float e_ratio_quant_bounds[3] = {0.2825f, 0.356f, 0.4485f}; +#else +static const spx_word16_t e_ratio_quant[4] = {8192, 10332, 13009, 16384}; +static const spx_word16_t e_ratio_quant_bounds[3] = {9257, 11665, 14696}; +static const spx_word16_t balance_bounds[31] = {18, 23, 30, 38, 49, 63, 81, 104, + 134, 172, 221, 284, 364, 468, 600, 771, + 990, 1271, 1632, 2096, 2691, 3455, 4436, 5696, + 7314, 9392, 12059, 15484, 19882, 25529, 32766}; +#endif + +/* This is an ugly compatibility hack that properly resets the stereo state + In case it it compiled in fixed-point, but initialised with the deprecated + floating point static initialiser */ +#ifdef FIXED_POINT +#define COMPATIBILITY_HACK(s) do {if ((s)->reserved1 != 0xdeadbeef) speex_stereo_state_reset((SpeexStereoState*)s); } while (0); +#else +#define COMPATIBILITY_HACK(s) +#endif + +EXPORT SpeexStereoState *speex_stereo_state_init() +{ + SpeexStereoState *stereo = speex_alloc(sizeof(SpeexStereoState)); + speex_stereo_state_reset(stereo); + return stereo; +} + +EXPORT void speex_stereo_state_reset(SpeexStereoState *_stereo) +{ + RealSpeexStereoState *stereo = (RealSpeexStereoState*)_stereo; +#ifdef FIXED_POINT + stereo->balance = 65536; + stereo->e_ratio = 16384; + stereo->smooth_left = 16384; + stereo->smooth_right = 16384; + stereo->reserved1 = 0xdeadbeef; + stereo->reserved2 = 0; +#else + stereo->balance = 1.0f; + stereo->e_ratio = .5f; + stereo->smooth_left = 1.f; + stereo->smooth_right = 1.f; + stereo->reserved1 = 0; + stereo->reserved2 = 0; +#endif +} + +EXPORT void speex_stereo_state_destroy(SpeexStereoState *stereo) +{ + speex_free(stereo); +} + +#ifndef DISABLE_FLOAT_API +EXPORT void speex_encode_stereo(float *data, int frame_size, SpeexBits *bits) +{ + int i, tmp; + float e_left=0, e_right=0, e_tot=0; + float balance, e_ratio; + for (i=0;i0) + speex_bits_pack(bits, 0, 1); + else + speex_bits_pack(bits, 1, 1); + balance=floor(.5+fabs(balance)); + if (balance>30) + balance=31; + + speex_bits_pack(bits, (int)balance, 5); + + /* FIXME: this is a hack */ + tmp=scal_quant(e_ratio*Q15_ONE, e_ratio_quant_bounds, 4); + speex_bits_pack(bits, tmp, 2); +} +#endif /* #ifndef DISABLE_FLOAT_API */ + +EXPORT void speex_encode_stereo_int(spx_int16_t *data, int frame_size, SpeexBits *bits) +{ + int i, tmp; + spx_word32_t e_left=0, e_right=0, e_tot=0; + spx_word32_t balance, e_ratio; + spx_word32_t largest, smallest; + int balance_id; +#ifdef FIXED_POINT + int shift; +#endif + + /* In band marker */ + speex_bits_pack(bits, 14, 5); + /* Stereo marker */ + speex_bits_pack(bits, SPEEX_INBAND_STEREO, 4); + + for (i=0;i e_right) + { + speex_bits_pack(bits, 0, 1); + largest = e_left; + smallest = e_right; + } else { + speex_bits_pack(bits, 1, 1); + largest = e_right; + smallest = e_left; + } + + /* Balance quantization */ +#ifdef FIXED_POINT + shift = spx_ilog2(largest)-15; + largest = VSHR32(largest, shift-4); + smallest = VSHR32(smallest, shift); + balance = DIV32(largest, ADD32(smallest, 1)); + if (balance > 32767) + balance = 32767; + balance_id = scal_quant(EXTRACT16(balance), balance_bounds, 32); +#else + balance=(largest+1.)/(smallest+1.); + balance=4*log(balance); + balance_id=floor(.5+fabs(balance)); + if (balance_id>30) + balance_id=31; +#endif + + speex_bits_pack(bits, balance_id, 5); + + /* "coherence" quantisation */ +#ifdef FIXED_POINT + shift = spx_ilog2(e_tot); + e_tot = VSHR32(e_tot, shift-25); + e_left = VSHR32(e_left, shift-10); + e_right = VSHR32(e_right, shift-10); + e_ratio = DIV32(e_tot, e_left+e_right+1); +#else + e_ratio = e_tot/(1.+e_left+e_right); +#endif + + tmp=scal_quant(EXTRACT16(e_ratio), e_ratio_quant_bounds, 4); + /*fprintf (stderr, "%d %d %d %d\n", largest, smallest, balance_id, e_ratio);*/ + speex_bits_pack(bits, tmp, 2); +} + +#ifndef DISABLE_FLOAT_API +EXPORT void speex_decode_stereo(float *data, int frame_size, SpeexStereoState *_stereo) +{ + int i; + spx_word32_t balance; + spx_word16_t e_left, e_right, e_ratio; + RealSpeexStereoState *stereo = (RealSpeexStereoState*)_stereo; + + COMPATIBILITY_HACK(stereo); + + balance=stereo->balance; + e_ratio=stereo->e_ratio; + + /* These two are Q14, with max value just below 2. */ + e_right = DIV32(QCONST32(1., 22), spx_sqrt(MULT16_32_Q15(e_ratio, ADD32(QCONST32(1., 16), balance)))); + e_left = SHR32(MULT16_16(spx_sqrt(balance), e_right), 8); + + for (i=frame_size-1;i>=0;i--) + { + spx_word16_t tmp=data[i]; + stereo->smooth_left = EXTRACT16(PSHR32(MAC16_16(MULT16_16(stereo->smooth_left, QCONST16(0.98, 15)), e_left, QCONST16(0.02, 15)), 15)); + stereo->smooth_right = EXTRACT16(PSHR32(MAC16_16(MULT16_16(stereo->smooth_right, QCONST16(0.98, 15)), e_right, QCONST16(0.02, 15)), 15)); + data[2*i] = (float)MULT16_16_P14(stereo->smooth_left, tmp); + data[2*i+1] = (float)MULT16_16_P14(stereo->smooth_right, tmp); + } +} +#endif /* #ifndef DISABLE_FLOAT_API */ + +EXPORT void speex_decode_stereo_int(spx_int16_t *data, int frame_size, SpeexStereoState *_stereo) +{ + int i; + spx_word32_t balance; + spx_word16_t e_left, e_right, e_ratio; + RealSpeexStereoState *stereo = (RealSpeexStereoState*)_stereo; + + COMPATIBILITY_HACK(stereo); + + balance=stereo->balance; + e_ratio=stereo->e_ratio; + + /* These two are Q14, with max value just below 2. */ + e_right = DIV32(QCONST32(1., 22), spx_sqrt(MULT16_32_Q15(e_ratio, ADD32(QCONST32(1., 16), balance)))); + e_left = SHR32(MULT16_16(spx_sqrt(balance), e_right), 8); + + for (i=frame_size-1;i>=0;i--) + { + spx_int16_t tmp=data[i]; + stereo->smooth_left = EXTRACT16(PSHR32(MAC16_16(MULT16_16(stereo->smooth_left, QCONST16(0.98, 15)), e_left, QCONST16(0.02, 15)), 15)); + stereo->smooth_right = EXTRACT16(PSHR32(MAC16_16(MULT16_16(stereo->smooth_right, QCONST16(0.98, 15)), e_right, QCONST16(0.02, 15)), 15)); + data[2*i] = (spx_int16_t)MULT16_16_P14(stereo->smooth_left, tmp); + data[2*i+1] = (spx_int16_t)MULT16_16_P14(stereo->smooth_right, tmp); + } +} + +EXPORT int speex_std_stereo_request_handler(SpeexBits *bits, void *state, void *data) +{ + RealSpeexStereoState *stereo; + spx_word16_t sign=1, dexp; + int tmp; + + stereo = (RealSpeexStereoState*)data; + + COMPATIBILITY_HACK(stereo); + + if (speex_bits_unpack_unsigned(bits, 1)) + sign=-1; + dexp = speex_bits_unpack_unsigned(bits, 5); +#ifndef FIXED_POINT + stereo->balance = exp(sign*.25*dexp); +#else + stereo->balance = spx_exp(MULT16_16(sign, SHL16(dexp, 9))); +#endif + tmp = speex_bits_unpack_unsigned(bits, 2); + stereo->e_ratio = e_ratio_quant[tmp]; + + return 0; +} diff --git a/android/app/src/main/jni/libspeex/testdenoise.c b/android/app/src/main/jni/libspeex/testdenoise.c new file mode 100644 index 000000000..49f512023 --- /dev/null +++ b/android/app/src/main/jni/libspeex/testdenoise.c @@ -0,0 +1,44 @@ +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include +#include + +#define NN 160 + +int main() +{ + short in[NN]; + int i; + SpeexPreprocessState *st; + int count=0; + float f; + + st = speex_preprocess_state_init(NN, 8000); + i=1; + speex_preprocess_ctl(st, SPEEX_PREPROCESS_SET_DENOISE, &i); + i=0; + speex_preprocess_ctl(st, SPEEX_PREPROCESS_SET_AGC, &i); + i=8000; + speex_preprocess_ctl(st, SPEEX_PREPROCESS_SET_AGC_LEVEL, &i); + i=0; + speex_preprocess_ctl(st, SPEEX_PREPROCESS_SET_DEREVERB, &i); + f=.0; + speex_preprocess_ctl(st, SPEEX_PREPROCESS_SET_DEREVERB_DECAY, &f); + f=.0; + speex_preprocess_ctl(st, SPEEX_PREPROCESS_SET_DEREVERB_LEVEL, &f); + while (1) + { + int vad; + fread(in, sizeof(short), NN, stdin); + if (feof(stdin)) + break; + vad = speex_preprocess_run(st, in); + /*fprintf (stderr, "%d\n", vad);*/ + fwrite(in, sizeof(short), NN, stdout); + count++; + } + speex_preprocess_state_destroy(st); + return 0; +} diff --git a/android/app/src/main/jni/libspeex/testecho.c b/android/app/src/main/jni/libspeex/testecho.c new file mode 100644 index 000000000..5ae855f08 --- /dev/null +++ b/android/app/src/main/jni/libspeex/testecho.c @@ -0,0 +1,53 @@ +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include +#include +#include +#include +#include +#include "speex/speex_echo.h" +#include "speex/speex_preprocess.h" + + +#define NN 128 +#define TAIL 1024 + +int main(int argc, char **argv) +{ + FILE *echo_fd, *ref_fd, *e_fd; + short echo_buf[NN], ref_buf[NN], e_buf[NN]; + SpeexEchoState *st; + SpeexPreprocessState *den; + int sampleRate = 8000; + + if (argc != 4) + { + fprintf(stderr, "testecho mic_signal.sw speaker_signal.sw output.sw\n"); + exit(1); + } + echo_fd = fopen(argv[2], "rb"); + ref_fd = fopen(argv[1], "rb"); + e_fd = fopen(argv[3], "wb"); + + st = speex_echo_state_init(NN, TAIL); + den = speex_preprocess_state_init(NN, sampleRate); + speex_echo_ctl(st, SPEEX_ECHO_SET_SAMPLING_RATE, &sampleRate); + speex_preprocess_ctl(den, SPEEX_PREPROCESS_SET_ECHO_STATE, st); + + while (!feof(ref_fd) && !feof(echo_fd)) + { + fread(ref_buf, sizeof(short), NN, ref_fd); + fread(echo_buf, sizeof(short), NN, echo_fd); + speex_echo_cancellation(st, ref_buf, echo_buf, e_buf); + speex_preprocess_run(den, e_buf); + fwrite(e_buf, sizeof(short), NN, e_fd); + } + speex_echo_state_destroy(st); + speex_preprocess_state_destroy(den); + fclose(e_fd); + fclose(echo_fd); + fclose(ref_fd); + return 0; +} diff --git a/android/app/src/main/jni/libspeex/testenc.c b/android/app/src/main/jni/libspeex/testenc.c new file mode 100644 index 000000000..44c132f1c --- /dev/null +++ b/android/app/src/main/jni/libspeex/testenc.c @@ -0,0 +1,146 @@ +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include +#include +#include +#include + +#ifdef FIXED_DEBUG +extern long long spx_mips; +#endif + +#define FRAME_SIZE 160 +#include +int main(int argc, char **argv) +{ + char *inFile, *outFile, *bitsFile; + FILE *fin, *fout, *fbits=NULL; + short in_short[FRAME_SIZE]; + short out_short[FRAME_SIZE]; + int snr_frames = 0; + char cbits[200]; + int nbBits; + int i; + void *st; + void *dec; + SpeexBits bits; + spx_int32_t tmp; + int bitCount=0; + spx_int32_t skip_group_delay; + SpeexCallback callback; + + st = speex_encoder_init(speex_lib_get_mode(SPEEX_MODEID_NB)); + dec = speex_decoder_init(speex_lib_get_mode(SPEEX_MODEID_NB)); + + /* BEGIN: You probably don't need the following in a real application */ + callback.callback_id = SPEEX_INBAND_CHAR; + callback.func = speex_std_char_handler; + callback.data = stderr; + speex_decoder_ctl(dec, SPEEX_SET_HANDLER, &callback); + + callback.callback_id = SPEEX_INBAND_MODE_REQUEST; + callback.func = speex_std_mode_request_handler; + callback.data = st; + speex_decoder_ctl(dec, SPEEX_SET_HANDLER, &callback); + /* END of unnecessary stuff */ + + tmp=1; + speex_decoder_ctl(dec, SPEEX_SET_ENH, &tmp); + tmp=0; + speex_encoder_ctl(st, SPEEX_SET_VBR, &tmp); + tmp=8; + speex_encoder_ctl(st, SPEEX_SET_QUALITY, &tmp); + tmp=1; + speex_encoder_ctl(st, SPEEX_SET_COMPLEXITY, &tmp); + + /* Turn this off if you want to measure SNR (on by default) */ + tmp=1; + speex_encoder_ctl(st, SPEEX_SET_HIGHPASS, &tmp); + speex_decoder_ctl(dec, SPEEX_SET_HIGHPASS, &tmp); + + speex_encoder_ctl(st, SPEEX_GET_LOOKAHEAD, &skip_group_delay); + speex_decoder_ctl(dec, SPEEX_GET_LOOKAHEAD, &tmp); + skip_group_delay += tmp; + + if (argc != 4 && argc != 3) + { + fprintf (stderr, "Usage: encode [in file] [out file] [bits file]\nargc = %d", argc); + exit(1); + } + inFile = argv[1]; + fin = fopen(inFile, "rb"); + outFile = argv[2]; + fout = fopen(outFile, "wb+"); + if (argc==4) + { + bitsFile = argv[3]; + fbits = fopen(bitsFile, "wb"); + } + speex_bits_init(&bits); + while (!feof(fin)) + { + fread(in_short, sizeof(short), FRAME_SIZE, fin); + if (feof(fin)) + break; + speex_bits_reset(&bits); + + speex_encode_int(st, in_short, &bits); + nbBits = speex_bits_write(&bits, cbits, 200); + bitCount+=bits.nbBits; + + if (argc==4) + fwrite(cbits, 1, nbBits, fbits); + speex_bits_rewind(&bits); + + speex_decode_int(dec, &bits, out_short); + speex_bits_reset(&bits); + + fwrite(&out_short[skip_group_delay], sizeof(short), FRAME_SIZE-skip_group_delay, fout); + skip_group_delay = 0; + } + fprintf (stderr, "Total encoded size: %d bits\n", bitCount); + speex_encoder_destroy(st); + speex_decoder_destroy(dec); + speex_bits_destroy(&bits); + +#ifndef DISABLE_FLOAT_API + { + float sigpow,errpow,snr, seg_snr=0; + sigpow = 0; + errpow = 0; + + /* This code just computes SNR, so you don't need it either */ + rewind(fin); + rewind(fout); + + while ( FRAME_SIZE == fread(in_short, sizeof(short), FRAME_SIZE, fin) + && + FRAME_SIZE == fread(out_short, sizeof(short), FRAME_SIZE,fout) ) + { + float s=0, e=0; + for (i=0;i +#include +#include +#include + +#ifdef FIXED_DEBUG +extern long long spx_mips; +#endif + +#define FRAME_SIZE 640 +#include +int main(int argc, char **argv) +{ + char *inFile, *outFile, *bitsFile; + FILE *fin, *fout, *fbits=NULL; + short in_short[FRAME_SIZE]; + short out_short[FRAME_SIZE]; + float in_float[FRAME_SIZE]; + float sigpow,errpow,snr, seg_snr=0; + int snr_frames = 0; + char cbits[200]; + int nbBits; + int i; + void *st; + void *dec; + SpeexBits bits; + spx_int32_t tmp; + int bitCount=0; + spx_int32_t skip_group_delay; + SpeexCallback callback; + + sigpow = 0; + errpow = 0; + + st = speex_encoder_init(speex_lib_get_mode(SPEEX_MODEID_UWB)); + dec = speex_decoder_init(speex_lib_get_mode(SPEEX_MODEID_UWB)); + + callback.callback_id = SPEEX_INBAND_CHAR; + callback.func = speex_std_char_handler; + callback.data = stderr; + speex_decoder_ctl(dec, SPEEX_SET_HANDLER, &callback); + + callback.callback_id = SPEEX_INBAND_MODE_REQUEST; + callback.func = speex_std_mode_request_handler; + callback.data = st; + speex_decoder_ctl(dec, SPEEX_SET_HANDLER, &callback); + + tmp=0; + speex_decoder_ctl(dec, SPEEX_SET_ENH, &tmp); + tmp=0; + speex_encoder_ctl(st, SPEEX_SET_VBR, &tmp); + tmp=7; + speex_encoder_ctl(st, SPEEX_SET_QUALITY, &tmp); + tmp=1; + speex_encoder_ctl(st, SPEEX_SET_COMPLEXITY, &tmp); + + speex_encoder_ctl(st, SPEEX_GET_LOOKAHEAD, &skip_group_delay); + speex_decoder_ctl(dec, SPEEX_GET_LOOKAHEAD, &tmp); + skip_group_delay += tmp; + + + if (argc != 4 && argc != 3) + { + fprintf (stderr, "Usage: encode [in file] [out file] [bits file]\nargc = %d", argc); + exit(1); + } + inFile = argv[1]; + fin = fopen(inFile, "rb"); + outFile = argv[2]; + fout = fopen(outFile, "wb+"); + if (argc==4) + { + bitsFile = argv[3]; + fbits = fopen(bitsFile, "wb"); + } + speex_bits_init(&bits); + while (!feof(fin)) + { + fread(in_short, sizeof(short), FRAME_SIZE, fin); + if (feof(fin)) + break; + for (i=0;i +#include +#include +#include + +#ifdef FIXED_DEBUG +extern long long spx_mips; +#endif + +#define FRAME_SIZE 320 +#include +int main(int argc, char **argv) +{ + char *inFile, *outFile, *bitsFile; + FILE *fin, *fout, *fbits=NULL; + short in_short[FRAME_SIZE]; + short out_short[FRAME_SIZE]; + float sigpow,errpow,snr, seg_snr=0; + int snr_frames = 0; + char cbits[200]; + int nbBits; + int i; + void *st; + void *dec; + SpeexBits bits; + spx_int32_t tmp; + int bitCount=0; + spx_int32_t skip_group_delay; + SpeexCallback callback; + + sigpow = 0; + errpow = 0; + + st = speex_encoder_init(speex_lib_get_mode(SPEEX_MODEID_WB)); + dec = speex_decoder_init(speex_lib_get_mode(SPEEX_MODEID_WB)); + + callback.callback_id = SPEEX_INBAND_CHAR; + callback.func = speex_std_char_handler; + callback.data = stderr; + speex_decoder_ctl(dec, SPEEX_SET_HANDLER, &callback); + + callback.callback_id = SPEEX_INBAND_MODE_REQUEST; + callback.func = speex_std_mode_request_handler; + callback.data = st; + speex_decoder_ctl(dec, SPEEX_SET_HANDLER, &callback); + + tmp=1; + speex_decoder_ctl(dec, SPEEX_SET_ENH, &tmp); + tmp=0; + speex_encoder_ctl(st, SPEEX_SET_VBR, &tmp); + tmp=8; + speex_encoder_ctl(st, SPEEX_SET_QUALITY, &tmp); + tmp=3; + speex_encoder_ctl(st, SPEEX_SET_COMPLEXITY, &tmp); + /*tmp=3; + speex_encoder_ctl(st, SPEEX_SET_HIGH_MODE, &tmp); + tmp=6; + speex_encoder_ctl(st, SPEEX_SET_LOW_MODE, &tmp); +*/ + + speex_encoder_ctl(st, SPEEX_GET_LOOKAHEAD, &skip_group_delay); + speex_decoder_ctl(dec, SPEEX_GET_LOOKAHEAD, &tmp); + skip_group_delay += tmp; + + + if (argc != 4 && argc != 3) + { + fprintf (stderr, "Usage: encode [in file] [out file] [bits file]\nargc = %d", argc); + exit(1); + } + inFile = argv[1]; + fin = fopen(inFile, "rb"); + outFile = argv[2]; + fout = fopen(outFile, "wb+"); + if (argc==4) + { + bitsFile = argv[3]; + fbits = fopen(bitsFile, "wb"); + } + speex_bits_init(&bits); + while (!feof(fin)) + { + fread(in_short, sizeof(short), FRAME_SIZE, fin); + if (feof(fin)) + break; + speex_bits_reset(&bits); + + speex_encode_int(st, in_short, &bits); + nbBits = speex_bits_write(&bits, cbits, 200); + bitCount+=bits.nbBits; + + if (argc==4) + fwrite(cbits, 1, nbBits, fbits); + speex_bits_rewind(&bits); + + speex_decode_int(dec, &bits, out_short); + speex_bits_reset(&bits); + + fwrite(&out_short[skip_group_delay], sizeof(short), FRAME_SIZE-skip_group_delay, fout); + skip_group_delay = 0; + } + fprintf (stderr, "Total encoded size: %d bits\n", bitCount); + speex_encoder_destroy(st); + speex_decoder_destroy(dec); + speex_bits_destroy(&bits); + + rewind(fin); + rewind(fout); + + while ( FRAME_SIZE == fread(in_short, sizeof(short), FRAME_SIZE, fin) + && + FRAME_SIZE == fread(out_short, sizeof(short), FRAME_SIZE,fout) ) + { + float s=0, e=0; + for (i=0;i +#include + +union jbpdata { + unsigned int idx; + unsigned char data[4]; +}; + +void synthIn(JitterBufferPacket *in, int idx, int span) { + union jbpdata d; + d.idx = idx; + + in->data = d.data; + in->len = sizeof(d); + in->timestamp = idx * 10; + in->span = span * 10; + in->sequence = idx; + in->user_data = 0; +} + +void jitterFill(JitterBuffer *jb) { + char buffer[65536]; + JitterBufferPacket in, out; + int i; + + out.data = buffer; + + jitter_buffer_reset(jb); + + for(i=0;i<100;++i) { + synthIn(&in, i, 1); + jitter_buffer_put(jb, &in); + + out.len = 65536; + if (jitter_buffer_get(jb, &out, 10, NULL) != JITTER_BUFFER_OK) { + printf("Fill test failed iteration %d\n", i); + } + if (out.timestamp != i * 10) { + printf("Fill test expected %d got %d\n", i*10, out.timestamp); + } + jitter_buffer_tick(jb); + } +} + +int main() +{ + char buffer[65536]; + JitterBufferPacket in, out; + int i; + + JitterBuffer *jb = jitter_buffer_init(10); + + out.data = buffer; + + /* Frozen sender case */ + jitterFill(jb); + for(i=0;i<100;++i) { + out.len = 65536; + jitter_buffer_get(jb, &out, 10, NULL); + jitter_buffer_tick(jb); + } + synthIn(&in, 100, 1); + jitter_buffer_put(jb, &in); + out.len = 65536; + if (jitter_buffer_get(jb, &out, 10, NULL) != JITTER_BUFFER_OK) { + printf("Failed frozen sender resynchronize\n"); + } else { + printf("Frozen sender: Jitter %d\n", out.timestamp - 100*10); + } + return 0; +} diff --git a/android/app/src/main/jni/libspeex/vbr.c b/android/app/src/main/jni/libspeex/vbr.c new file mode 100644 index 000000000..5b7dd9bfa --- /dev/null +++ b/android/app/src/main/jni/libspeex/vbr.c @@ -0,0 +1,275 @@ +/* Copyright (C) 2002 Jean-Marc Valin + File: vbr.c + + VBR-related routines + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + - Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + - Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + - Neither the name of the Xiph.org Foundation nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR + CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +*/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "vbr.h" +#include + + +#define sqr(x) ((x)*(x)) + +#define MIN_ENERGY 6000 +#define NOISE_POW .3 + +#ifndef DISABLE_VBR + +const float vbr_nb_thresh[9][11]={ + {-1.0f, -1.0f, -1.0f, -1.0f, -1.0f, -1.0f, -1.0f, -1.0f, -1.0f, -1.0f, -1.0f}, /* CNG */ + { 4.0f, 2.5f, 2.0f, 1.2f, 0.5f, 0.0f, -0.5f, -0.7f, -0.8f, -0.9f, -1.0f}, /* 2 kbps */ + {10.0f, 6.5f, 5.2f, 4.5f, 3.9f, 3.5f, 3.0f, 2.5f, 2.3f, 1.8f, 1.0f}, /* 6 kbps */ + {11.0f, 8.8f, 7.5f, 6.5f, 5.0f, 3.9f, 3.9f, 3.9f, 3.5f, 3.0f, 1.0f}, /* 8 kbps */ + {11.0f, 11.0f, 9.9f, 8.5f, 7.0f, 6.0f, 4.5f, 4.0f, 4.0f, 4.0f, 2.0f}, /* 11 kbps */ + {11.0f, 11.0f, 11.0f, 11.0f, 9.5f, 8.5f, 8.0f, 7.0f, 6.0f, 5.0f, 3.0f}, /* 15 kbps */ + {11.0f, 11.0f, 11.0f, 11.0f, 11.0f, 11.0f, 9.5f, 8.5f, 7.0f, 6.0f, 5.0f}, /* 18 kbps */ + {11.0f, 11.0f, 11.0f, 11.0f, 11.0f, 11.0f, 11.0f, 11.0f, 9.8f, 9.5f, 7.5f}, /* 24 kbps */ + { 7.0f, 4.5f, 3.7f, 3.0f, 2.5f, 2.0f, 1.8f, 1.5f, 1.0f, 0.0f, 0.0f} /* 4 kbps */ +}; + + +const float vbr_hb_thresh[5][11]={ + {-1.0f, -1.0f, -1.0f, -1.0f, -1.0f, -1.0f, -1.0f, -1.0f, -1.0f, -1.0f, -1.0f}, /* silence */ + {-1.0f, -1.0f, -1.0f, -1.0f, -1.0f, -1.0f, -1.0f, -1.0f, -1.0f, -1.0f, -1.0f}, /* 2 kbps */ + {11.0f, 11.0f, 9.5f, 8.5f, 7.5f, 6.0f, 5.0f, 3.9f, 3.0f, 2.0f, 1.0f}, /* 6 kbps */ + {11.0f, 11.0f, 11.0f, 11.0f, 11.0f, 9.5f, 8.7f, 7.8f, 7.0f, 6.5f, 4.0f}, /* 10 kbps */ + {11.0f, 11.0f, 11.0f, 11.0f, 11.0f, 11.0f, 11.0f, 11.0f, 9.8f, 7.5f, 5.5f} /* 18 kbps */ +}; + +const float vbr_uhb_thresh[2][11]={ + {-1.0f, -1.0f, -1.0f, -1.0f, -1.0f, -1.0f, -1.0f, -1.0f, -1.0f, -1.0f, -1.0f}, /* silence */ + { 3.9f, 2.5f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, -1.0f} /* 2 kbps */ +}; + +void vbr_init(VBRState *vbr) +{ + int i; + + vbr->average_energy=0; + vbr->last_energy=1; + vbr->accum_sum=0; + vbr->energy_alpha=.1; + vbr->soft_pitch=0; + vbr->last_pitch_coef=0; + vbr->last_quality=0; + + vbr->noise_accum = .05*pow(MIN_ENERGY, NOISE_POW); + vbr->noise_accum_count=.05; + vbr->noise_level=vbr->noise_accum/vbr->noise_accum_count; + vbr->consec_noise=0; + + + for (i=0;ilast_log_energy[i] = log(MIN_ENERGY); +} + + +/* + This function should analyse the signal and decide how critical the + coding error will be perceptually. The following factors should be + taken into account: + + -Attacks (positive energy derivative) should be coded with more bits + + -Stationary voiced segments should receive more bits + + -Segments with (very) low absolute energy should receive less bits (maybe + only shaped noise?) + + -DTX for near-zero energy? + + -Stationary fricative segments should have less bits + + -Temporal masking: when energy slope is decreasing, decrease the bit-rate + + -Decrease bit-rate for males (low pitch)? + + -(wideband only) less bits in the high-band when signal is very + non-stationary (harder to notice high-frequency noise)??? + +*/ + +float vbr_analysis(VBRState *vbr, spx_word16_t *sig, int len, int pitch, float pitch_coef) +{ + int i; + float ener=0, ener1=0, ener2=0; + float qual=7; + int va; + float log_energy; + float non_st=0; + float voicing; + float pow_ener; + + for (i=0;i>1;i++) + ener1 += ((float)sig[i])*sig[i]; + + for (i=len>>1;ilast_log_energy[i]); + non_st = non_st/(30*VBR_MEMORY_SIZE); + if (non_st>1) + non_st=1; + + voicing = 3*(pitch_coef-.4)*fabs(pitch_coef-.4); + vbr->average_energy = (1-vbr->energy_alpha)*vbr->average_energy + vbr->energy_alpha*ener; + vbr->noise_level=vbr->noise_accum/vbr->noise_accum_count; + pow_ener = pow(ener,NOISE_POW); + if (vbr->noise_accum_count<.06 && ener>MIN_ENERGY) + vbr->noise_accum = .05*pow_ener; + + if ((voicing<.3 && non_st < .2 && pow_ener < 1.2*vbr->noise_level) + || (voicing<.3 && non_st < .05 && pow_ener < 1.5*vbr->noise_level) + || (voicing<.4 && non_st < .05 && pow_ener < 1.2*vbr->noise_level) + || (voicing<0 && non_st < .05)) + { + float tmp; + va = 0; + vbr->consec_noise++; + if (pow_ener > 3*vbr->noise_level) + tmp = 3*vbr->noise_level; + else + tmp = pow_ener; + if (vbr->consec_noise>=4) + { + vbr->noise_accum = .95*vbr->noise_accum + .05*tmp; + vbr->noise_accum_count = .95*vbr->noise_accum_count + .05; + } + } else { + va = 1; + vbr->consec_noise=0; + } + + if (pow_ener < vbr->noise_level && ener>MIN_ENERGY) + { + vbr->noise_accum = .95*vbr->noise_accum + .05*pow_ener; + vbr->noise_accum_count = .95*vbr->noise_accum_count + .05; + } + + /* Checking for very low absolute energy */ + if (ener < 30000) + { + qual -= .7; + if (ener < 10000) + qual-=.7; + if (ener < 3000) + qual-=.7; + } else { + float short_diff, long_diff; + short_diff = log((ener+1)/(1+vbr->last_energy)); + long_diff = log((ener+1)/(1+vbr->average_energy)); + /*fprintf (stderr, "%f %f\n", short_diff, long_diff);*/ + + if (long_diff<-5) + long_diff=-5; + if (long_diff>2) + long_diff=2; + + if (long_diff>0) + qual += .6*long_diff; + if (long_diff<0) + qual += .5*long_diff; + if (short_diff>0) + { + if (short_diff>5) + short_diff=5; + qual += .5*short_diff; + } + /* Checking for energy increases */ + if (ener2 > 1.6*ener1) + qual += .5; + } + vbr->last_energy = ener; + vbr->soft_pitch = .6*vbr->soft_pitch + .4*pitch_coef; + qual += 2.2*((pitch_coef-.4) + (vbr->soft_pitch-.4)); + + if (qual < vbr->last_quality) + qual = .5*qual + .5*vbr->last_quality; + if (qual<4) + qual=4; + if (qual>10) + qual=10; + + /* + if (vbr->consec_noise>=2) + qual-=1.3; + if (vbr->consec_noise>=5) + qual-=1.3; + if (vbr->consec_noise>=12) + qual-=1.3; + */ + if (vbr->consec_noise>=3) + qual=4; + + if (vbr->consec_noise) + qual -= 1.0 * (log(3.0 + vbr->consec_noise)-log(3)); + if (qual<0) + qual=0; + + if (ener<60000) + { + if (vbr->consec_noise>2) + qual-=0.5*(log(3.0 + vbr->consec_noise)-log(3)); + if (ener<10000&&vbr->consec_noise>2) + qual-=0.5*(log(3.0 + vbr->consec_noise)-log(3)); + if (qual<0) + qual=0; + qual += .3*log(.0001+ener/60000.0); + } + if (qual<-1) + qual=-1; + + /*printf ("%f %f %f %f %d\n", qual, voicing, non_st, pow_ener/(.01+vbr->noise_level), va);*/ + + vbr->last_pitch_coef = pitch_coef; + vbr->last_quality = qual; + + for (i=VBR_MEMORY_SIZE-1;i>0;i--) + vbr->last_log_energy[i] = vbr->last_log_energy[i-1]; + vbr->last_log_energy[0] = log_energy; + + /*printf ("VBR: %f %f %f %d %f\n", (float)(log_energy-log(vbr->average_energy+MIN_ENERGY)), non_st, voicing, va, vbr->noise_level);*/ + + return qual; +} + +void vbr_destroy(VBRState *vbr) +{ +} + +#endif /* #ifndef DISABLE_VBR */ diff --git a/android/app/src/main/jni/libspeex/vbr.h b/android/app/src/main/jni/libspeex/vbr.h new file mode 100644 index 000000000..ff1e3e46f --- /dev/null +++ b/android/app/src/main/jni/libspeex/vbr.h @@ -0,0 +1,70 @@ +/* Copyright (C) 2002 Jean-Marc Valin */ +/** + @file vbr.h + @brief Variable Bit-Rate (VBR) related routines +*/ +/* + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + - Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + - Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + - Neither the name of the Xiph.org Foundation nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR + CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +*/ + + +#ifndef VBR_H +#define VBR_H + +#include "arch.h" + +#define VBR_MEMORY_SIZE 5 + +extern const float vbr_nb_thresh[9][11]; +extern const float vbr_hb_thresh[5][11]; +extern const float vbr_uhb_thresh[2][11]; + +/** VBR state. */ +typedef struct VBRState { + float energy_alpha; + float average_energy; + float last_energy; + float last_log_energy[VBR_MEMORY_SIZE]; + float accum_sum; + float last_pitch_coef; + float soft_pitch; + float last_quality; + float noise_level; + float noise_accum; + float noise_accum_count; + int consec_noise; +} VBRState; + +void vbr_init(VBRState *vbr); + +float vbr_analysis(VBRState *vbr, spx_word16_t *sig, int len, int pitch, float pitch_coef); + +void vbr_destroy(VBRState *vbr); + +#endif diff --git a/android/app/src/main/jni/libspeex/vorbis_psy.h b/android/app/src/main/jni/libspeex/vorbis_psy.h new file mode 100644 index 000000000..687105775 --- /dev/null +++ b/android/app/src/main/jni/libspeex/vorbis_psy.h @@ -0,0 +1,97 @@ +/* Copyright (C) 2005 Jean-Marc Valin, CSIRO, Christopher Montgomery + File: vorbis_psy.h + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + - Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + - Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + - Neither the name of the Xiph.org Foundation nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR + CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#ifndef VORBIS_PSY_H +#define VORBIS_PSY_H + +#ifdef VORBIS_PSYCHO + +#include "smallft.h" +#define P_BANDS 17 /* 62Hz to 16kHz */ +#define NOISE_COMPAND_LEVELS 40 + + +#define todB(x) ((x)>1e-13?log((x)*(x))*4.34294480f:-30) +#define fromdB(x) (exp((x)*.11512925f)) + +/* The bark scale equations are approximations, since the original + table was somewhat hand rolled. The below are chosen to have the + best possible fit to the rolled tables, thus their somewhat odd + appearance (these are more accurate and over a longer range than + the oft-quoted bark equations found in the texts I have). The + approximations are valid from 0 - 30kHz (nyquist) or so. + + all f in Hz, z in Bark */ + +#define toBARK(n) (13.1f*atan(.00074f*(n))+2.24f*atan((n)*(n)*1.85e-8f)+1e-4f*(n)) +#define fromBARK(z) (102.f*(z)-2.f*pow(z,2.f)+.4f*pow(z,3.f)+pow(1.46f,z)-1.f) + +/* Frequency to octave. We arbitrarily declare 63.5 Hz to be octave + 0.0 */ + +#define toOC(n) (log(n)*1.442695f-5.965784f) +#define fromOC(o) (exp(((o)+5.965784f)*.693147f)) + + +typedef struct { + + float noisewindowlo; + float noisewindowhi; + int noisewindowlomin; + int noisewindowhimin; + int noisewindowfixed; + float noiseoff[P_BANDS]; + float noisecompand[NOISE_COMPAND_LEVELS]; + +} VorbisPsyInfo; + + + +typedef struct { + int n; + int rate; + struct drft_lookup lookup; + VorbisPsyInfo *vi; + + float *window; + float *noiseoffset; + long *bark; + +} VorbisPsy; + + +VorbisPsy *vorbis_psy_init(int rate, int size); +void vorbis_psy_destroy(VorbisPsy *psy); +void compute_curve(VorbisPsy *psy, float *audio, float *curve); +void curve_to_lpc(VorbisPsy *psy, float *curve, float *awk1, float *awk2, int ord); + +#endif +#endif diff --git a/android/app/src/main/jni/libspeex/vq.c b/android/app/src/main/jni/libspeex/vq.c new file mode 100644 index 000000000..609f124e7 --- /dev/null +++ b/android/app/src/main/jni/libspeex/vq.c @@ -0,0 +1,147 @@ +/* Copyright (C) 2002 Jean-Marc Valin + File: vq.c + Vector quantization + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + - Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + - Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + - Neither the name of the Xiph.org Foundation nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR + CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "vq.h" +#include "stack_alloc.h" +#include "arch.h" + +#ifdef _USE_SSE +#include +#include "vq_sse.h" +#elif defined(SHORTCUTS) && (defined(ARM4_ASM) || defined(ARM5E_ASM)) +#include "vq_arm4.h" +#elif defined(BFIN_ASM) +#include "vq_bfin.h" +#endif + + +int scal_quant(spx_word16_t in, const spx_word16_t *boundary, int entries) +{ + int i=0; + while (iboundary[0]) + { + boundary++; + i++; + } + return i; +} + +int scal_quant32(spx_word32_t in, const spx_word32_t *boundary, int entries) +{ + int i=0; + while (iboundary[0]) + { + boundary++; + i++; + } + return i; +} + + +#ifndef OVERRIDE_VQ_NBEST +/*Finds the indices of the n-best entries in a codebook*/ +void vq_nbest(spx_word16_t *in, const spx_word16_t *codebook, int len, int entries, spx_word32_t *E, int N, int *nbest, spx_word32_t *best_dist, char *stack) +{ + int i,j,k,used; + used = 0; + for (i=0;i= 1) && (k > used || dist < best_dist[k-1]); k--) + { + best_dist[k]=best_dist[k-1]; + nbest[k] = nbest[k-1]; + } + best_dist[k]=dist; + nbest[k]=i; + used++; + } + } +} +#endif + + + + +#ifndef OVERRIDE_VQ_NBEST_SIGN +/*Finds the indices of the n-best entries in a codebook with sign*/ +void vq_nbest_sign(spx_word16_t *in, const spx_word16_t *codebook, int len, int entries, spx_word32_t *E, int N, int *nbest, spx_word32_t *best_dist, char *stack) +{ + int i,j,k, sign, used; + used=0; + for (i=0;i0) + { + sign=0; + dist=-dist; + } else + { + sign=1; + } +#ifdef FIXED_POINT + dist = ADD32(dist,SHR32(E[i],1)); +#else + dist = ADD32(dist,.5f*E[i]); +#endif + if (i= 1) && (k > used || dist < best_dist[k-1]); k--) + { + best_dist[k]=best_dist[k-1]; + nbest[k] = nbest[k-1]; + } + best_dist[k]=dist; + nbest[k]=i; + used++; + if (sign) + nbest[k]+=entries; + } + } +} +#endif diff --git a/android/app/src/main/jni/libspeex/vq.h b/android/app/src/main/jni/libspeex/vq.h new file mode 100644 index 000000000..5a4ced249 --- /dev/null +++ b/android/app/src/main/jni/libspeex/vq.h @@ -0,0 +1,54 @@ +/* Copyright (C) 2002 Jean-Marc Valin */ +/** + @file vq.h + @brief Vector quantization +*/ +/* + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + - Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + - Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + - Neither the name of the Xiph.org Foundation nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR + CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#ifndef VQ_H +#define VQ_H + +#include "arch.h" + +int scal_quant(spx_word16_t in, const spx_word16_t *boundary, int entries); +int scal_quant32(spx_word32_t in, const spx_word32_t *boundary, int entries); + +#ifdef _USE_SSE +#include +void vq_nbest(spx_word16_t *in, const __m128 *codebook, int len, int entries, __m128 *E, int N, int *nbest, spx_word32_t *best_dist, char *stack); + +void vq_nbest_sign(spx_word16_t *in, const __m128 *codebook, int len, int entries, __m128 *E, int N, int *nbest, spx_word32_t *best_dist, char *stack); +#else +void vq_nbest(spx_word16_t *in, const spx_word16_t *codebook, int len, int entries, spx_word32_t *E, int N, int *nbest, spx_word32_t *best_dist, char *stack); + +void vq_nbest_sign(spx_word16_t *in, const spx_word16_t *codebook, int len, int entries, spx_word32_t *E, int N, int *nbest, spx_word32_t *best_dist, char *stack); +#endif + +#endif diff --git a/android/app/src/main/jni/libspeex/vq_arm4.h b/android/app/src/main/jni/libspeex/vq_arm4.h new file mode 100644 index 000000000..585b8613c --- /dev/null +++ b/android/app/src/main/jni/libspeex/vq_arm4.h @@ -0,0 +1,115 @@ +/* Copyright (C) 2004 Jean-Marc Valin */ +/** + @file vq_arm4.h + @brief ARM4-optimized vq routine +*/ +/* + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + - Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + - Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + - Neither the name of the Xiph.org Foundation nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR + CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#define OVERRIDE_VQ_NBEST +void vq_nbest(spx_word16_t *in, const spx_word16_t *codebook, int len, int entries, spx_word32_t *E, int N, int *nbest, spx_word32_t *best_dist, char *stack) +{ + int i,j; + for (i=0;i>= 1;\n\t" + "A0 = %0;\n\t" + "R0.L = W[%1++%7] || R1.L = W[I0++];\n\t" + "LOOP vq_loop%= LC1 = %5;\n\t" + "LOOP_BEGIN vq_loop%=;\n\t" + "%0 = (A0 -= R0.L*R1.L) (IS) || R0.L = W[%1++%7] || R1.L = W[I0++];\n\t" + "LOOP_END vq_loop%=;\n\t" + "%0 = (A0 -= R0.L*R1.L) (IS);\n\t" + "cc = %0 < %2;\n\t" + "if cc %2 = %0;\n\t" + "if cc %3 = R2;\n\t" + "R2 += 1;\n\t" + "LOOP_END entries_loop%=;\n\t" + : "=&D" (dist), "=&a" (codebook), "=&d" (best_dist[0]), "=&d" (nbest[0]), "=&a" (E) + : "a" (len-1), "a" (in), "a" (2), "d" (entries), "d" (len<<1), "1" (codebook), "4" (E), "2" (best_dist[0]), "3" (nbest[0]) + : "R0", "R1", "R2", "I0", "L0", "B0", "A0", "cc", "memory" + ); + } + } else { + int i,k,used; + used = 0; + for (i=0;i>= 1;\n\t" + "A0 = %0;\n\t" + "I0 = %3;\n\t" + "L0 = 0;\n\t" + "R0.L = W[%1++%4] || R1.L = W[I0++];\n\t" + "LOOP vq_loop%= LC0 = %2;\n\t" + "LOOP_BEGIN vq_loop%=;\n\t" + "%0 = (A0 -= R0.L*R1.L) (IS) || R0.L = W[%1++%4] || R1.L = W[I0++];\n\t" + "LOOP_END vq_loop%=;\n\t" + "%0 = (A0 -= R0.L*R1.L) (IS);\n\t" + : "=D" (dist), "=a" (codebook) + : "a" (len-1), "a" (in), "a" (2), "1" (codebook), "0" (E[i]) + : "R0", "R1", "I0", "L0", "A0" + ); + if (i= 1) && (k > used || dist < best_dist[k-1]); k--) + { + best_dist[k]=best_dist[k-1]; + nbest[k] = nbest[k-1]; + } + best_dist[k]=dist; + nbest[k]=i; + used++; + } + } + } +} diff --git a/android/app/src/main/jni/libspeex/vq_sse.h b/android/app/src/main/jni/libspeex/vq_sse.h new file mode 100644 index 000000000..00a42ce35 --- /dev/null +++ b/android/app/src/main/jni/libspeex/vq_sse.h @@ -0,0 +1,120 @@ +/* Copyright (C) 2004 Jean-Marc Valin */ +/** + @file vq_sse.h + @brief SSE-optimized vq routine +*/ +/* + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + - Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + - Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + - Neither the name of the Xiph.org Foundation nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR + CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#define OVERRIDE_VQ_NBEST +void vq_nbest(spx_word16_t *_in, const __m128 *codebook, int len, int entries, __m128 *E, int N, int *nbest, spx_word32_t *best_dist, char *stack) +{ + int i,j,k,used; + VARDECL(float *dist); + VARDECL(__m128 *in); + __m128 half; + used = 0; + ALLOC(dist, entries, float); + half = _mm_set_ps1(.5f); + ALLOC(in, len, __m128); + for (i=0;i>2;i++) + { + __m128 d = _mm_mul_ps(E[i], half); + for (j=0;j= 1) && (k > used || dist[i] < best_dist[k-1]); k--) + { + best_dist[k]=best_dist[k-1]; + nbest[k] = nbest[k-1]; + } + best_dist[k]=dist[i]; + nbest[k]=i; + used++; + } + } +} + + + + +#define OVERRIDE_VQ_NBEST_SIGN +void vq_nbest_sign(spx_word16_t *_in, const __m128 *codebook, int len, int entries, __m128 *E, int N, int *nbest, spx_word32_t *best_dist, char *stack) +{ + int i,j,k,used; + VARDECL(float *dist); + VARDECL(__m128 *in); + __m128 half; + used = 0; + ALLOC(dist, entries, float); + half = _mm_set_ps1(.5f); + ALLOC(in, len, __m128); + for (i=0;i>2;i++) + { + __m128 d = _mm_setzero_ps(); + for (j=0;j0) + { + sign=0; + dist[i]=-dist[i]; + } else + { + sign=1; + } + dist[i] += .5f*((float*)E)[i]; + if (i= 1) && (k > used || dist[i] < best_dist[k-1]); k--) + { + best_dist[k]=best_dist[k-1]; + nbest[k] = nbest[k-1]; + } + best_dist[k]=dist[i]; + nbest[k]=i; + used++; + if (sign) + nbest[k]+=entries; + } + } +} diff --git a/android/app/src/main/jni/libspeex/window.c b/android/app/src/main/jni/libspeex/window.c new file mode 100644 index 000000000..ac042d45f --- /dev/null +++ b/android/app/src/main/jni/libspeex/window.c @@ -0,0 +1,102 @@ +/* Copyright (C) 2006 Jean-Marc Valin + File: window.c + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + - Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + - Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + - Neither the name of the Xiph.org Foundation nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR + CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "arch.h" + +#ifdef FIXED_POINT +const spx_word16_t lag_window[11] = { + 16384, 16337, 16199, 15970, 15656, 15260, 14790, 14254, 13659, 13015, 12330 +}; + +const spx_word16_t lpc_window[200] = { +1310, 1313, 1321, 1333, 1352, 1375, 1403, 1436, +1475, 1518, 1567, 1621, 1679, 1743, 1811, 1884, +1962, 2044, 2132, 2224, 2320, 2421, 2526, 2636, +2750, 2868, 2990, 3116, 3246, 3380, 3518, 3659, +3804, 3952, 4104, 4259, 4417, 4578, 4742, 4909, +5079, 5251, 5425, 5602, 5781, 5963, 6146, 6331, +6518, 6706, 6896, 7087, 7280, 7473, 7668, 7863, +8059, 8256, 8452, 8650, 8847, 9044, 9241, 9438, +9635, 9831, 10026, 10220, 10414, 10606, 10797, 10987, +11176, 11363, 11548, 11731, 11912, 12091, 12268, 12443, +12615, 12785, 12952, 13116, 13277, 13435, 13590, 13742, +13890, 14035, 14176, 14314, 14448, 14578, 14704, 14826, +14944, 15058, 15168, 15273, 15374, 15470, 15562, 15649, +15732, 15810, 15883, 15951, 16015, 16073, 16127, 16175, +16219, 16257, 16291, 16319, 16342, 16360, 16373, 16381, +16384, 16384, 16384, 16384, 16384, 16384, 16384, 16384, +16384, 16384, 16384, 16384, 16384, 16384, 16384, 16384, +16384, 16384, 16384, 16384, 16384, 16384, 16384, 16384, +16384, 16384, 16384, 16384, 16384, 16384, 16384, 16384, +16384, 16384, 16384, 16384, 16384, 16384, 16384, 16384, +16384, 16384, 16384, 16384, 16384, 16384, 16384, 16384, +16384, 16384, 16384, 16361, 16294, 16183, 16028, 15830, +15588, 15304, 14979, 14613, 14207, 13763, 13282, 12766, +12215, 11631, 11016, 10373, 9702, 9007, 8289, 7551, +6797, 6028, 5251, 4470, 3695, 2943, 2248, 1696 +}; +#else +const spx_word16_t lag_window[11] = { + 1.00000, 0.99716, 0.98869, 0.97474, 0.95554, 0.93140, 0.90273, 0.86998, 0.83367, 0.79434, 0.75258 +}; + +const spx_word16_t lpc_window[200] = { + 0.080000f, 0.080158f, 0.080630f, 0.081418f, 0.082520f, 0.083935f, 0.085663f, 0.087703f, + 0.090052f, 0.092710f, 0.095674f, 0.098943f, 0.102514f, 0.106385f, 0.110553f, 0.115015f, + 0.119769f, 0.124811f, 0.130137f, 0.135744f, 0.141628f, 0.147786f, 0.154212f, 0.160902f, + 0.167852f, 0.175057f, 0.182513f, 0.190213f, 0.198153f, 0.206328f, 0.214731f, 0.223357f, + 0.232200f, 0.241254f, 0.250513f, 0.259970f, 0.269619f, 0.279453f, 0.289466f, 0.299651f, + 0.310000f, 0.320507f, 0.331164f, 0.341965f, 0.352901f, 0.363966f, 0.375151f, 0.386449f, + 0.397852f, 0.409353f, 0.420943f, 0.432615f, 0.444361f, 0.456172f, 0.468040f, 0.479958f, + 0.491917f, 0.503909f, 0.515925f, 0.527959f, 0.540000f, 0.552041f, 0.564075f, 0.576091f, + 0.588083f, 0.600042f, 0.611960f, 0.623828f, 0.635639f, 0.647385f, 0.659057f, 0.670647f, + 0.682148f, 0.693551f, 0.704849f, 0.716034f, 0.727099f, 0.738035f, 0.748836f, 0.759493f, + 0.770000f, 0.780349f, 0.790534f, 0.800547f, 0.810381f, 0.820030f, 0.829487f, 0.838746f, + 0.847800f, 0.856643f, 0.865269f, 0.873672f, 0.881847f, 0.889787f, 0.897487f, 0.904943f, + 0.912148f, 0.919098f, 0.925788f, 0.932214f, 0.938372f, 0.944256f, 0.949863f, 0.955189f, + 0.960231f, 0.964985f, 0.969447f, 0.973615f, 0.977486f, 0.981057f, 0.984326f, 0.987290f, + 0.989948f, 0.992297f, 0.994337f, 0.996065f, 0.997480f, 0.998582f, 0.999370f, 0.999842f, + 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, + 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, + 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, + 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, + 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, + 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, + 1.000000f, 1.000000f, 1.000000f, 0.998640f, 0.994566f, 0.987787f, 0.978324f, 0.966203f, + 0.951458f, 0.934131f, 0.914270f, 0.891931f, 0.867179f, 0.840084f, 0.810723f, 0.779182f, + 0.745551f, 0.709930f, 0.672424f, 0.633148f, 0.592223f, 0.549781f, 0.505964f, 0.460932f, + 0.414863f, 0.367968f, 0.320511f, 0.272858f, 0.225569f, 0.179655f, 0.137254f, 0.103524f +}; +#endif diff --git a/android/app/src/main/jni/speex_jni.cpp b/android/app/src/main/jni/speex_jni.cpp new file mode 100644 index 000000000..68d620d46 --- /dev/null +++ b/android/app/src/main/jni/speex_jni.cpp @@ -0,0 +1,217 @@ +#include + +#include +#include +//#include +//#include + +/*start*/ +#include +#include +#include +#include +#include +#include +#include +#include + +// the header length of the RTP frame (must skip when en/decoding) +static const int rtp_header = 0; + +int codec_status = 0; + +const int CODEC_OPENED = 1; +const int CODEC_CLOSED = 0; + +int aec_status = 0; + +const int AEC_OPENED = 1; +const int AEC_CLOSED = 0; + +SpeexEchoState *echoState; +SpeexPreprocessState *den; +int sampleRate = 16000; +/*end*/ + +static int codec_open = 0; + +static int dec_frame_size; +static int enc_frame_size; + +static SpeexBits ebits, dbits; +void *enc_state; +void *dec_state; + +static JavaVM *gJavaVM; + +extern "C" JNIEXPORT jint JNICALL Java_com_mogujie_tt_imservice_support_audio_Speex_open( + JNIEnv *env, jobject obj, jint compression) { + int tmp = 0; + if (codec_open++ != 0) + return (jint) 0; + + speex_bits_init(&ebits); + speex_bits_init(&dbits); + + enc_state = speex_encoder_init(&speex_nb_mode); + dec_state = speex_decoder_init(&speex_nb_mode); + + tmp = compression; + speex_encoder_ctl(enc_state, SPEEX_SET_QUALITY, &tmp); + speex_encoder_ctl(enc_state, SPEEX_GET_FRAME_SIZE, &enc_frame_size); + speex_decoder_ctl(dec_state, SPEEX_GET_FRAME_SIZE, &dec_frame_size); + + SpeexPreprocessState * m_st; + m_st = speex_preprocess_state_init(enc_frame_size, 8000); + int denoise = 1; + int noiseSuppress = -25; + speex_preprocess_ctl(m_st, SPEEX_PREPROCESS_SET_DENOISE, &denoise); + speex_preprocess_ctl(m_st, SPEEX_PREPROCESS_SET_NOISE_SUPPRESS, + &noiseSuppress); + + return (jint) 0; +} + +extern "C" JNIEXPORT jint JNICALL Java_com_mogujie_tt_imservice_support_audio_Speex_encode( + JNIEnv *env, jobject obj, jshortArray lin, jint offset, + jbyteArray encoded, jint size) { + + jshort buffer[enc_frame_size]; + jbyte output_buffer[enc_frame_size]; + int nsamples = (size - 1) / enc_frame_size + 1; + int i, tot_bytes = 0; + + if (!codec_open) + return 0; + + speex_bits_reset(&ebits); + + for (i = 0; i < nsamples; i++) { + env->GetShortArrayRegion(lin, offset + i * enc_frame_size, + enc_frame_size, buffer); + speex_encode_int(enc_state, buffer, &ebits); + } + //env->GetShortArrayRegion(lin, offset, enc_frame_size, buffer); + //speex_encode_int(enc_state, buffer, &ebits); + + tot_bytes = speex_bits_write(&ebits, (char *) output_buffer, + enc_frame_size); + env->SetByteArrayRegion(encoded, 0, tot_bytes, output_buffer); + + return (jint) tot_bytes; +} + +extern "C" JNIEXPORT jint Java_com_mogujie_tt_imservice_support_audio_Speex_decode( + JNIEnv *env, jobject obj, jbyteArray encoded, jshortArray lin, + jint size) { + + jbyte buffer[dec_frame_size]; + jshort output_buffer[dec_frame_size]; + jsize encoded_length = size; + + if (!codec_open) + return 0; + + env->GetByteArrayRegion(encoded, 0, encoded_length, buffer); + speex_bits_read_from(&dbits, (char *) buffer, encoded_length); + speex_decode_int(dec_state, &dbits, output_buffer); + env->SetShortArrayRegion(lin, 0, dec_frame_size, output_buffer); + + return (jint) dec_frame_size; +} + +extern "C" JNIEXPORT jint JNICALL Java_com_mogujie_tt_imservice_support_audio_Speex_getFrameSize( + JNIEnv *env, jobject obj) { + + if (!codec_open) + return 0; + return (jint) enc_frame_size; + +} + +extern "C" JNIEXPORT void JNICALL Java_com_mogujie_tt_imservice_support_audio_Speex_close( + JNIEnv *env, jobject obj) { + + if (--codec_open != 0) + return; + + speex_bits_destroy(&ebits); + speex_bits_destroy(&dbits); + speex_decoder_destroy(dec_state); + speex_encoder_destroy(enc_state); +} + +extern "C" JNIEXPORT void Java_com_mogujie_tt_imservice_support_audio_Speex_initEcho( + JNIEnv *env, jobject jobj, jint frame_size, jint filter_length) { + if (aec_status == AEC_OPENED) + return; + aec_status = AEC_OPENED; + + int frm_size; + int f_length; + + frm_size = frame_size; + f_length = filter_length; + + echoState = speex_echo_state_init(frame_size, filter_length); + den = speex_preprocess_state_init(frame_size, sampleRate); + speex_echo_ctl(echoState, SPEEX_ECHO_SET_SAMPLING_RATE, &sampleRate); + speex_preprocess_ctl(den, SPEEX_PREPROCESS_SET_ECHO_STATE, echoState); +} + +extern "C" JNIEXPORT void Java_com_mogujie_tt_imservice_support_audio_Speex_echoCancellation( + JNIEnv *env, jshortArray rec, jshortArray play, jshortArray out) { + + jshort echo_buf[enc_frame_size]; + jshort ref_buf[enc_frame_size]; + jshort e_buf[enc_frame_size]; + + env->GetShortArrayRegion(rec, 0, enc_frame_size, echo_buf); + env->GetShortArrayRegion(play, 0, enc_frame_size, ref_buf); + + speex_echo_cancellation(echoState, echo_buf, ref_buf, e_buf); +// speex_preprocess_run(den, e_buf); + + env->SetShortArrayRegion(out, 0, enc_frame_size, e_buf); + +} + +extern "C" JNIEXPORT int Java_com_mogujie_tt_imservice_support_audio_Speex_echoCancellationEncode( + JNIEnv *env, jshortArray rec, jshortArray play, jbyteArray encoded) { + + jshort echo_buf[enc_frame_size]; + jshort ref_buf[enc_frame_size]; + jshort e_buf[enc_frame_size]; + jbyte output_buffer[enc_frame_size]; + + env->GetShortArrayRegion(rec, 0, enc_frame_size, echo_buf); + env->GetShortArrayRegion(play, 0, enc_frame_size, ref_buf); + + speex_echo_cancellation(echoState, echo_buf, ref_buf, e_buf); + speex_preprocess_run(den, e_buf); + + speex_bits_reset(&ebits); + + speex_encode_int(enc_state, e_buf, &ebits); + + jint tot_bytes = speex_bits_write(&ebits, (char *) output_buffer, + enc_frame_size); + env->SetByteArrayRegion(encoded, 0, tot_bytes, output_buffer); + + return (jint) tot_bytes; +} + +extern "C" JNIEXPORT jint JNICALL Java_com_mogujie_tt_imservice_support_audio_Speex_getAecStatus() { + return (jint) aec_status; +} + +extern "C" JNIEXPORT void Java_com_mogujie_tt_imservice_support_audio_Speex_destroyEcho( + JNIEnv * env, jobject jobj) { + if (aec_status == AEC_CLOSED) + return; + aec_status = AEC_CLOSED; + + speex_echo_state_destroy(echoState); + speex_preprocess_state_destroy(den); +} + diff --git a/android/app/src/main/jniLibs/armeabi-v7a/libsecurity.so b/android/app/src/main/jniLibs/armeabi-v7a/libsecurity.so new file mode 100755 index 000000000..c67014500 Binary files /dev/null and b/android/app/src/main/jniLibs/armeabi-v7a/libsecurity.so differ diff --git a/android/app/src/main/jniLibs/armeabi-v7a/libspeex.so b/android/app/src/main/jniLibs/armeabi-v7a/libspeex.so new file mode 100755 index 000000000..a03acc90e Binary files /dev/null and b/android/app/src/main/jniLibs/armeabi-v7a/libspeex.so differ diff --git a/android/app/src/main/jniLibs/armeabi/libsecurity.so b/android/app/src/main/jniLibs/armeabi/libsecurity.so new file mode 100755 index 000000000..698d2186d Binary files /dev/null and b/android/app/src/main/jniLibs/armeabi/libsecurity.so differ diff --git a/android/app/src/main/jniLibs/armeabi/libspeex.so b/android/app/src/main/jniLibs/armeabi/libspeex.so new file mode 100755 index 000000000..509203236 Binary files /dev/null and b/android/app/src/main/jniLibs/armeabi/libspeex.so differ diff --git a/android/app/src/main/res/anim/login_splash.xml b/android/app/src/main/res/anim/login_splash.xml new file mode 100644 index 000000000..104fb59de --- /dev/null +++ b/android/app/src/main/res/anim/login_splash.xml @@ -0,0 +1,8 @@ + + + + + \ No newline at end of file diff --git a/android/app/src/main/res/anim/tt_album_enter.xml b/android/app/src/main/res/anim/tt_album_enter.xml new file mode 100644 index 000000000..178adc8f6 --- /dev/null +++ b/android/app/src/main/res/anim/tt_album_enter.xml @@ -0,0 +1,34 @@ + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/android/app/src/main/res/anim/tt_album_exit.xml b/android/app/src/main/res/anim/tt_album_exit.xml new file mode 100644 index 000000000..253a37685 --- /dev/null +++ b/android/app/src/main/res/anim/tt_album_exit.xml @@ -0,0 +1,27 @@ + + + + + + + + + + + \ No newline at end of file diff --git a/android/app/src/main/res/anim/tt_image_enter.xml b/android/app/src/main/res/anim/tt_image_enter.xml new file mode 100644 index 000000000..6165a90ec --- /dev/null +++ b/android/app/src/main/res/anim/tt_image_enter.xml @@ -0,0 +1,14 @@ + + + + + + + + \ No newline at end of file diff --git a/android/app/src/main/res/anim/tt_image_exit.xml b/android/app/src/main/res/anim/tt_image_exit.xml new file mode 100644 index 000000000..cb6a4b639 --- /dev/null +++ b/android/app/src/main/res/anim/tt_image_exit.xml @@ -0,0 +1,9 @@ + + + + + + \ No newline at end of file diff --git a/android/app/src/main/res/anim/tt_image_left_enter.xml b/android/app/src/main/res/anim/tt_image_left_enter.xml new file mode 100644 index 000000000..f837a0ac1 --- /dev/null +++ b/android/app/src/main/res/anim/tt_image_left_enter.xml @@ -0,0 +1,30 @@ + + + + diff --git a/android/app/src/main/res/anim/tt_image_left_exit.xml b/android/app/src/main/res/anim/tt_image_left_exit.xml new file mode 100644 index 000000000..2c3ca6f09 --- /dev/null +++ b/android/app/src/main/res/anim/tt_image_left_exit.xml @@ -0,0 +1,24 @@ + + + + + \ No newline at end of file diff --git a/android/app/src/main/res/anim/tt_speeker_in.xml b/android/app/src/main/res/anim/tt_speeker_in.xml new file mode 100644 index 000000000..8d1fdb4bd --- /dev/null +++ b/android/app/src/main/res/anim/tt_speeker_in.xml @@ -0,0 +1,8 @@ + + + + + diff --git a/android/app/src/main/res/anim/tt_speeker_out.xml b/android/app/src/main/res/anim/tt_speeker_out.xml new file mode 100644 index 000000000..fd7f7188c --- /dev/null +++ b/android/app/src/main/res/anim/tt_speeker_out.xml @@ -0,0 +1,8 @@ + + + + + diff --git a/android/app/src/main/res/anim/tt_stay.xml b/android/app/src/main/res/anim/tt_stay.xml new file mode 100644 index 000000000..0f9dfd02d --- /dev/null +++ b/android/app/src/main/res/anim/tt_stay.xml @@ -0,0 +1,5 @@ + + \ No newline at end of file diff --git a/android/app/src/main/res/anim/tt_stay_x.xml b/android/app/src/main/res/anim/tt_stay_x.xml new file mode 100644 index 000000000..3e3309fdd --- /dev/null +++ b/android/app/src/main/res/anim/tt_stay_x.xml @@ -0,0 +1,5 @@ + + \ No newline at end of file diff --git a/android/app/src/main/res/anim/tt_voice_play_mine.xml b/android/app/src/main/res/anim/tt_voice_play_mine.xml new file mode 100644 index 000000000..0d520b974 --- /dev/null +++ b/android/app/src/main/res/anim/tt_voice_play_mine.xml @@ -0,0 +1,18 @@ + + + + + + + + + \ No newline at end of file diff --git a/android/app/src/main/res/anim/tt_voice_play_other.xml b/android/app/src/main/res/anim/tt_voice_play_other.xml new file mode 100644 index 000000000..0b5bc4958 --- /dev/null +++ b/android/app/src/main/res/anim/tt_voice_play_other.xml @@ -0,0 +1,19 @@ + + + + + + + + + + \ No newline at end of file diff --git a/android/app/src/main/res/color/checkbox_background.xml b/android/app/src/main/res/color/checkbox_background.xml new file mode 100644 index 000000000..7a565a06a --- /dev/null +++ b/android/app/src/main/res/color/checkbox_background.xml @@ -0,0 +1,9 @@ + + + + + + + + + \ No newline at end of file diff --git a/android/app/src/main/res/color/toggle_checkbox_background.xml b/android/app/src/main/res/color/toggle_checkbox_background.xml new file mode 100644 index 000000000..cf2e2b65d --- /dev/null +++ b/android/app/src/main/res/color/toggle_checkbox_background.xml @@ -0,0 +1,7 @@ + + + + + + + \ No newline at end of file diff --git a/android/app/src/main/res/color/tt_dialog_negative_text_color.xml b/android/app/src/main/res/color/tt_dialog_negative_text_color.xml new file mode 100644 index 000000000..3fd3330ba --- /dev/null +++ b/android/app/src/main/res/color/tt_dialog_negative_text_color.xml @@ -0,0 +1,7 @@ + + + + + + + \ No newline at end of file diff --git a/android/app/src/main/res/color/tt_positive_text_color.xml b/android/app/src/main/res/color/tt_positive_text_color.xml new file mode 100644 index 000000000..fb2f7f2e7 --- /dev/null +++ b/android/app/src/main/res/color/tt_positive_text_color.xml @@ -0,0 +1,6 @@ + + + + + \ No newline at end of file diff --git a/android/app/src/main/res/drawable-hdpi/tt_loading_circle.png b/android/app/src/main/res/drawable-hdpi/tt_loading_circle.png new file mode 100644 index 000000000..b97a43006 Binary files /dev/null and b/android/app/src/main/res/drawable-hdpi/tt_loading_circle.png differ diff --git a/android/app/src/main/res/drawable-xhdpi/check.png b/android/app/src/main/res/drawable-xhdpi/check.png new file mode 100644 index 000000000..2d7484522 Binary files /dev/null and b/android/app/src/main/res/drawable-xhdpi/check.png differ diff --git a/android/app/src/main/res/drawable-xhdpi/check_box.png b/android/app/src/main/res/drawable-xhdpi/check_box.png new file mode 100644 index 000000000..e917e117d Binary files /dev/null and b/android/app/src/main/res/drawable-xhdpi/check_box.png differ diff --git a/android/app/src/main/res/drawable-xhdpi/discussion_group_default.png b/android/app/src/main/res/drawable-xhdpi/discussion_group_default.png new file mode 100644 index 000000000..a2d3e93af Binary files /dev/null and b/android/app/src/main/res/drawable-xhdpi/discussion_group_default.png differ diff --git a/android/app/src/main/res/drawable-xhdpi/group_avatar_bk.png b/android/app/src/main/res/drawable-xhdpi/group_avatar_bk.png new file mode 100644 index 000000000..3a59b062a Binary files /dev/null and b/android/app/src/main/res/drawable-xhdpi/group_avatar_bk.png differ diff --git a/android/app/src/main/res/drawable-xhdpi/group_default.png b/android/app/src/main/res/drawable-xhdpi/group_default.png new file mode 100644 index 000000000..1315d0aa3 Binary files /dev/null and b/android/app/src/main/res/drawable-xhdpi/group_default.png differ diff --git a/android/app/src/main/res/drawable-xhdpi/pc_notify.png b/android/app/src/main/res/drawable-xhdpi/pc_notify.png new file mode 100644 index 000000000..1821cd398 Binary files /dev/null and b/android/app/src/main/res/drawable-xhdpi/pc_notify.png differ diff --git a/android/app/src/main/res/drawable-xhdpi/seleted.png b/android/app/src/main/res/drawable-xhdpi/seleted.png new file mode 100644 index 000000000..4f796e4c0 Binary files /dev/null and b/android/app/src/main/res/drawable-xhdpi/seleted.png differ diff --git a/android/app/src/main/res/drawable-xhdpi/tele.png b/android/app/src/main/res/drawable-xhdpi/tele.png new file mode 100644 index 000000000..29b9b5d06 Binary files /dev/null and b/android/app/src/main/res/drawable-xhdpi/tele.png differ diff --git a/android/app/src/main/res/drawable-xhdpi/tt_album_arrow.png b/android/app/src/main/res/drawable-xhdpi/tt_album_arrow.png new file mode 100644 index 000000000..50363590c Binary files /dev/null and b/android/app/src/main/res/drawable-xhdpi/tt_album_arrow.png differ diff --git a/android/app/src/main/res/drawable-xhdpi/tt_album_arrow_sel.png b/android/app/src/main/res/drawable-xhdpi/tt_album_arrow_sel.png new file mode 100644 index 000000000..7f72eb7bd Binary files /dev/null and b/android/app/src/main/res/drawable-xhdpi/tt_album_arrow_sel.png differ diff --git a/android/app/src/main/res/drawable-xhdpi/tt_album_bottom_bar.png b/android/app/src/main/res/drawable-xhdpi/tt_album_bottom_bar.png new file mode 100644 index 000000000..a19307f21 Binary files /dev/null and b/android/app/src/main/res/drawable-xhdpi/tt_album_bottom_bar.png differ diff --git a/android/app/src/main/res/drawable-xhdpi/tt_album_img_select_nor.png b/android/app/src/main/res/drawable-xhdpi/tt_album_img_select_nor.png new file mode 100644 index 000000000..82fc50121 Binary files /dev/null and b/android/app/src/main/res/drawable-xhdpi/tt_album_img_select_nor.png differ diff --git a/android/app/src/main/res/drawable-xhdpi/tt_album_img_selected.png b/android/app/src/main/res/drawable-xhdpi/tt_album_img_selected.png new file mode 100644 index 000000000..5c008ef18 Binary files /dev/null and b/android/app/src/main/res/drawable-xhdpi/tt_album_img_selected.png differ diff --git a/android/app/src/main/res/drawable-xhdpi/tt_album_item_sel_bk.png b/android/app/src/main/res/drawable-xhdpi/tt_album_item_sel_bk.png new file mode 100644 index 000000000..b74a70513 Binary files /dev/null and b/android/app/src/main/res/drawable-xhdpi/tt_album_item_sel_bk.png differ diff --git a/android/app/src/main/res/drawable-xhdpi/tt_back_btn.png b/android/app/src/main/res/drawable-xhdpi/tt_back_btn.png new file mode 100644 index 000000000..3562539ad Binary files /dev/null and b/android/app/src/main/res/drawable-xhdpi/tt_back_btn.png differ diff --git a/android/app/src/main/res/drawable-xhdpi/tt_bg_popup_left_nomal.png b/android/app/src/main/res/drawable-xhdpi/tt_bg_popup_left_nomal.png new file mode 100644 index 000000000..f63292e33 Binary files /dev/null and b/android/app/src/main/res/drawable-xhdpi/tt_bg_popup_left_nomal.png differ diff --git a/android/app/src/main/res/drawable-xhdpi/tt_bg_popup_left_pressed.png b/android/app/src/main/res/drawable-xhdpi/tt_bg_popup_left_pressed.png new file mode 100644 index 000000000..f6311b2c0 Binary files /dev/null and b/android/app/src/main/res/drawable-xhdpi/tt_bg_popup_left_pressed.png differ diff --git a/android/app/src/main/res/drawable-xhdpi/tt_bg_popup_normal.9.png b/android/app/src/main/res/drawable-xhdpi/tt_bg_popup_normal.9.png new file mode 100644 index 000000000..515e68276 Binary files /dev/null and b/android/app/src/main/res/drawable-xhdpi/tt_bg_popup_normal.9.png differ diff --git a/android/app/src/main/res/drawable-xhdpi/tt_bg_popup_pressed.9.png b/android/app/src/main/res/drawable-xhdpi/tt_bg_popup_pressed.9.png new file mode 100644 index 000000000..ee9dc47b6 Binary files /dev/null and b/android/app/src/main/res/drawable-xhdpi/tt_bg_popup_pressed.9.png differ diff --git a/android/app/src/main/res/drawable-xhdpi/tt_bg_popup_right_nomal.png b/android/app/src/main/res/drawable-xhdpi/tt_bg_popup_right_nomal.png new file mode 100644 index 000000000..a4b75a3cf Binary files /dev/null and b/android/app/src/main/res/drawable-xhdpi/tt_bg_popup_right_nomal.png differ diff --git a/android/app/src/main/res/drawable-xhdpi/tt_bg_popup_right_pressed.png b/android/app/src/main/res/drawable-xhdpi/tt_bg_popup_right_pressed.png new file mode 100644 index 000000000..0ba165f7a Binary files /dev/null and b/android/app/src/main/res/drawable-xhdpi/tt_bg_popup_right_pressed.png differ diff --git a/android/app/src/main/res/drawable-xhdpi/tt_chatting_biaoqing_btn_normal.png b/android/app/src/main/res/drawable-xhdpi/tt_chatting_biaoqing_btn_normal.png new file mode 100644 index 000000000..3eb6ad704 Binary files /dev/null and b/android/app/src/main/res/drawable-xhdpi/tt_chatting_biaoqing_btn_normal.png differ diff --git a/android/app/src/main/res/drawable-xhdpi/tt_clear_bar.png b/android/app/src/main/res/drawable-xhdpi/tt_clear_bar.png new file mode 100644 index 000000000..6eac89cb5 Binary files /dev/null and b/android/app/src/main/res/drawable-xhdpi/tt_clear_bar.png differ diff --git a/android/app/src/main/res/drawable-xhdpi/tt_clock_icon.png b/android/app/src/main/res/drawable-xhdpi/tt_clock_icon.png new file mode 100644 index 000000000..a81e15d34 Binary files /dev/null and b/android/app/src/main/res/drawable-xhdpi/tt_clock_icon.png differ diff --git a/android/app/src/main/res/drawable-xhdpi/tt_contact_side_search.png b/android/app/src/main/res/drawable-xhdpi/tt_contact_side_search.png new file mode 100644 index 000000000..15acf0448 Binary files /dev/null and b/android/app/src/main/res/drawable-xhdpi/tt_contact_side_search.png differ diff --git a/android/app/src/main/res/drawable-xhdpi/tt_contact_top_left_nor.png b/android/app/src/main/res/drawable-xhdpi/tt_contact_top_left_nor.png new file mode 100644 index 000000000..2ad5fead1 Binary files /dev/null and b/android/app/src/main/res/drawable-xhdpi/tt_contact_top_left_nor.png differ diff --git a/android/app/src/main/res/drawable-xhdpi/tt_contact_top_left_sel.png b/android/app/src/main/res/drawable-xhdpi/tt_contact_top_left_sel.png new file mode 100644 index 000000000..8fedbf329 Binary files /dev/null and b/android/app/src/main/res/drawable-xhdpi/tt_contact_top_left_sel.png differ diff --git a/android/app/src/main/res/drawable-xhdpi/tt_contact_top_right_nor.png b/android/app/src/main/res/drawable-xhdpi/tt_contact_top_right_nor.png new file mode 100644 index 000000000..0cfd1c3c2 Binary files /dev/null and b/android/app/src/main/res/drawable-xhdpi/tt_contact_top_right_nor.png differ diff --git a/android/app/src/main/res/drawable-xhdpi/tt_contact_top_right_sel.png b/android/app/src/main/res/drawable-xhdpi/tt_contact_top_right_sel.png new file mode 100644 index 000000000..d1c39f36c Binary files /dev/null and b/android/app/src/main/res/drawable-xhdpi/tt_contact_top_right_sel.png differ diff --git a/android/app/src/main/res/drawable-xhdpi/tt_default_album_grid_image.png b/android/app/src/main/res/drawable-xhdpi/tt_default_album_grid_image.png new file mode 100644 index 000000000..c720f85fc Binary files /dev/null and b/android/app/src/main/res/drawable-xhdpi/tt_default_album_grid_image.png differ diff --git a/android/app/src/main/res/drawable-xhdpi/tt_default_arrow.png b/android/app/src/main/res/drawable-xhdpi/tt_default_arrow.png new file mode 100644 index 000000000..ec89c92c6 Binary files /dev/null and b/android/app/src/main/res/drawable-xhdpi/tt_default_arrow.png differ diff --git a/android/app/src/main/res/drawable-xhdpi/tt_default_btn_bk.png b/android/app/src/main/res/drawable-xhdpi/tt_default_btn_bk.png new file mode 100644 index 000000000..7cc08182b Binary files /dev/null and b/android/app/src/main/res/drawable-xhdpi/tt_default_btn_bk.png differ diff --git a/android/app/src/main/res/drawable-xhdpi/tt_default_dot_down.png b/android/app/src/main/res/drawable-xhdpi/tt_default_dot_down.png new file mode 100644 index 000000000..de1f1d4de Binary files /dev/null and b/android/app/src/main/res/drawable-xhdpi/tt_default_dot_down.png differ diff --git a/android/app/src/main/res/drawable-xhdpi/tt_default_dot_up.png b/android/app/src/main/res/drawable-xhdpi/tt_default_dot_up.png new file mode 100644 index 000000000..92d3e7e13 Binary files /dev/null and b/android/app/src/main/res/drawable-xhdpi/tt_default_dot_up.png differ diff --git a/android/app/src/main/res/drawable-xhdpi/tt_default_emo_back_normal.png b/android/app/src/main/res/drawable-xhdpi/tt_default_emo_back_normal.png new file mode 100644 index 000000000..c9ee95588 Binary files /dev/null and b/android/app/src/main/res/drawable-xhdpi/tt_default_emo_back_normal.png differ diff --git a/android/app/src/main/res/drawable-xhdpi/tt_default_image.png b/android/app/src/main/res/drawable-xhdpi/tt_default_image.png new file mode 100644 index 000000000..df221b6c2 Binary files /dev/null and b/android/app/src/main/res/drawable-xhdpi/tt_default_image.png differ diff --git a/android/app/src/main/res/drawable-xhdpi/tt_default_image_error.png b/android/app/src/main/res/drawable-xhdpi/tt_default_image_error.png new file mode 100644 index 000000000..217b41ed3 Binary files /dev/null and b/android/app/src/main/res/drawable-xhdpi/tt_default_image_error.png differ diff --git a/android/app/src/main/res/drawable-xhdpi/tt_default_message_error_image.png b/android/app/src/main/res/drawable-xhdpi/tt_default_message_error_image.png new file mode 100644 index 000000000..394e5328b Binary files /dev/null and b/android/app/src/main/res/drawable-xhdpi/tt_default_message_error_image.png differ diff --git a/android/app/src/main/res/drawable-xhdpi/tt_default_message_image.png b/android/app/src/main/res/drawable-xhdpi/tt_default_message_image.png new file mode 100644 index 000000000..9cfcceba0 Binary files /dev/null and b/android/app/src/main/res/drawable-xhdpi/tt_default_message_image.png differ diff --git a/android/app/src/main/res/drawable-xhdpi/tt_default_user_portrait_corner.png b/android/app/src/main/res/drawable-xhdpi/tt_default_user_portrait_corner.png new file mode 100644 index 000000000..dfb757afd Binary files /dev/null and b/android/app/src/main/res/drawable-xhdpi/tt_default_user_portrait_corner.png differ diff --git a/android/app/src/main/res/drawable-xhdpi/tt_delete_bar.png b/android/app/src/main/res/drawable-xhdpi/tt_delete_bar.png new file mode 100644 index 000000000..03c12a10d Binary files /dev/null and b/android/app/src/main/res/drawable-xhdpi/tt_delete_bar.png differ diff --git a/android/app/src/main/res/drawable-xhdpi/tt_dialog_navigative_btn_bg_normal.9.png b/android/app/src/main/res/drawable-xhdpi/tt_dialog_navigative_btn_bg_normal.9.png new file mode 100644 index 000000000..67a2206e7 Binary files /dev/null and b/android/app/src/main/res/drawable-xhdpi/tt_dialog_navigative_btn_bg_normal.9.png differ diff --git a/android/app/src/main/res/drawable-xhdpi/tt_dialog_navigative_btn_bg_pressed.9.png b/android/app/src/main/res/drawable-xhdpi/tt_dialog_navigative_btn_bg_pressed.9.png new file mode 100644 index 000000000..26c61681b Binary files /dev/null and b/android/app/src/main/res/drawable-xhdpi/tt_dialog_navigative_btn_bg_pressed.9.png differ diff --git a/android/app/src/main/res/drawable-xhdpi/tt_dialog_positive_btn_bg_normal.9.png b/android/app/src/main/res/drawable-xhdpi/tt_dialog_positive_btn_bg_normal.9.png new file mode 100644 index 000000000..daeb5aa20 Binary files /dev/null and b/android/app/src/main/res/drawable-xhdpi/tt_dialog_positive_btn_bg_normal.9.png differ diff --git a/android/app/src/main/res/drawable-xhdpi/tt_dialog_positive_btn_bg_pressed.9.png b/android/app/src/main/res/drawable-xhdpi/tt_dialog_positive_btn_bg_pressed.9.png new file mode 100644 index 000000000..b99909c43 Binary files /dev/null and b/android/app/src/main/res/drawable-xhdpi/tt_dialog_positive_btn_bg_pressed.9.png differ diff --git a/android/app/src/main/res/drawable-xhdpi/tt_divide_line.png b/android/app/src/main/res/drawable-xhdpi/tt_divide_line.png new file mode 100644 index 000000000..02ed8b265 Binary files /dev/null and b/android/app/src/main/res/drawable-xhdpi/tt_divide_line.png differ diff --git a/android/app/src/main/res/drawable-xhdpi/tt_e0.png b/android/app/src/main/res/drawable-xhdpi/tt_e0.png new file mode 100644 index 000000000..383ddaa98 Binary files /dev/null and b/android/app/src/main/res/drawable-xhdpi/tt_e0.png differ diff --git a/android/app/src/main/res/drawable-xhdpi/tt_e1.png b/android/app/src/main/res/drawable-xhdpi/tt_e1.png new file mode 100644 index 000000000..820372c2e Binary files /dev/null and b/android/app/src/main/res/drawable-xhdpi/tt_e1.png differ diff --git a/android/app/src/main/res/drawable-xhdpi/tt_e10.png b/android/app/src/main/res/drawable-xhdpi/tt_e10.png new file mode 100644 index 000000000..7453423d3 Binary files /dev/null and b/android/app/src/main/res/drawable-xhdpi/tt_e10.png differ diff --git a/android/app/src/main/res/drawable-xhdpi/tt_e11.png b/android/app/src/main/res/drawable-xhdpi/tt_e11.png new file mode 100644 index 000000000..7d20cb154 Binary files /dev/null and b/android/app/src/main/res/drawable-xhdpi/tt_e11.png differ diff --git a/android/app/src/main/res/drawable-xhdpi/tt_e12.png b/android/app/src/main/res/drawable-xhdpi/tt_e12.png new file mode 100644 index 000000000..11d6f05be Binary files /dev/null and b/android/app/src/main/res/drawable-xhdpi/tt_e12.png differ diff --git a/android/app/src/main/res/drawable-xhdpi/tt_e13.png b/android/app/src/main/res/drawable-xhdpi/tt_e13.png new file mode 100644 index 000000000..34817cf7b Binary files /dev/null and b/android/app/src/main/res/drawable-xhdpi/tt_e13.png differ diff --git a/android/app/src/main/res/drawable-xhdpi/tt_e14.png b/android/app/src/main/res/drawable-xhdpi/tt_e14.png new file mode 100644 index 000000000..67157d0df Binary files /dev/null and b/android/app/src/main/res/drawable-xhdpi/tt_e14.png differ diff --git a/android/app/src/main/res/drawable-xhdpi/tt_e15.png b/android/app/src/main/res/drawable-xhdpi/tt_e15.png new file mode 100644 index 000000000..4a218ed31 Binary files /dev/null and b/android/app/src/main/res/drawable-xhdpi/tt_e15.png differ diff --git a/android/app/src/main/res/drawable-xhdpi/tt_e16.png b/android/app/src/main/res/drawable-xhdpi/tt_e16.png new file mode 100644 index 000000000..934aeb951 Binary files /dev/null and b/android/app/src/main/res/drawable-xhdpi/tt_e16.png differ diff --git a/android/app/src/main/res/drawable-xhdpi/tt_e17.png b/android/app/src/main/res/drawable-xhdpi/tt_e17.png new file mode 100644 index 000000000..3fd9102c5 Binary files /dev/null and b/android/app/src/main/res/drawable-xhdpi/tt_e17.png differ diff --git a/android/app/src/main/res/drawable-xhdpi/tt_e18.png b/android/app/src/main/res/drawable-xhdpi/tt_e18.png new file mode 100644 index 000000000..af8dfcd1f Binary files /dev/null and b/android/app/src/main/res/drawable-xhdpi/tt_e18.png differ diff --git a/android/app/src/main/res/drawable-xhdpi/tt_e19.png b/android/app/src/main/res/drawable-xhdpi/tt_e19.png new file mode 100644 index 000000000..1c9382870 Binary files /dev/null and b/android/app/src/main/res/drawable-xhdpi/tt_e19.png differ diff --git a/android/app/src/main/res/drawable-xhdpi/tt_e2.png b/android/app/src/main/res/drawable-xhdpi/tt_e2.png new file mode 100644 index 000000000..737984740 Binary files /dev/null and b/android/app/src/main/res/drawable-xhdpi/tt_e2.png differ diff --git a/android/app/src/main/res/drawable-xhdpi/tt_e20.png b/android/app/src/main/res/drawable-xhdpi/tt_e20.png new file mode 100644 index 000000000..dca652479 Binary files /dev/null and b/android/app/src/main/res/drawable-xhdpi/tt_e20.png differ diff --git a/android/app/src/main/res/drawable-xhdpi/tt_e21.png b/android/app/src/main/res/drawable-xhdpi/tt_e21.png new file mode 100644 index 000000000..d5a7406f5 Binary files /dev/null and b/android/app/src/main/res/drawable-xhdpi/tt_e21.png differ diff --git a/android/app/src/main/res/drawable-xhdpi/tt_e22.png b/android/app/src/main/res/drawable-xhdpi/tt_e22.png new file mode 100644 index 000000000..54956426d Binary files /dev/null and b/android/app/src/main/res/drawable-xhdpi/tt_e22.png differ diff --git a/android/app/src/main/res/drawable-xhdpi/tt_e23.png b/android/app/src/main/res/drawable-xhdpi/tt_e23.png new file mode 100644 index 000000000..bd46e8d9e Binary files /dev/null and b/android/app/src/main/res/drawable-xhdpi/tt_e23.png differ diff --git a/android/app/src/main/res/drawable-xhdpi/tt_e24.png b/android/app/src/main/res/drawable-xhdpi/tt_e24.png new file mode 100644 index 000000000..67157d0df Binary files /dev/null and b/android/app/src/main/res/drawable-xhdpi/tt_e24.png differ diff --git a/android/app/src/main/res/drawable-xhdpi/tt_e25.png b/android/app/src/main/res/drawable-xhdpi/tt_e25.png new file mode 100644 index 000000000..8a0d283e1 Binary files /dev/null and b/android/app/src/main/res/drawable-xhdpi/tt_e25.png differ diff --git a/android/app/src/main/res/drawable-xhdpi/tt_e26.png b/android/app/src/main/res/drawable-xhdpi/tt_e26.png new file mode 100644 index 000000000..939251450 Binary files /dev/null and b/android/app/src/main/res/drawable-xhdpi/tt_e26.png differ diff --git a/android/app/src/main/res/drawable-xhdpi/tt_e27.png b/android/app/src/main/res/drawable-xhdpi/tt_e27.png new file mode 100644 index 000000000..4cbad25bc Binary files /dev/null and b/android/app/src/main/res/drawable-xhdpi/tt_e27.png differ diff --git a/android/app/src/main/res/drawable-xhdpi/tt_e28.png b/android/app/src/main/res/drawable-xhdpi/tt_e28.png new file mode 100644 index 000000000..6098a9c77 Binary files /dev/null and b/android/app/src/main/res/drawable-xhdpi/tt_e28.png differ diff --git a/android/app/src/main/res/drawable-xhdpi/tt_e29.png b/android/app/src/main/res/drawable-xhdpi/tt_e29.png new file mode 100644 index 000000000..cbcf82d7c Binary files /dev/null and b/android/app/src/main/res/drawable-xhdpi/tt_e29.png differ diff --git a/android/app/src/main/res/drawable-xhdpi/tt_e3.png b/android/app/src/main/res/drawable-xhdpi/tt_e3.png new file mode 100644 index 000000000..ce249e5bc Binary files /dev/null and b/android/app/src/main/res/drawable-xhdpi/tt_e3.png differ diff --git a/android/app/src/main/res/drawable-xhdpi/tt_e30.png b/android/app/src/main/res/drawable-xhdpi/tt_e30.png new file mode 100644 index 000000000..9d405a7c3 Binary files /dev/null and b/android/app/src/main/res/drawable-xhdpi/tt_e30.png differ diff --git a/android/app/src/main/res/drawable-xhdpi/tt_e31.png b/android/app/src/main/res/drawable-xhdpi/tt_e31.png new file mode 100644 index 000000000..3b3b726c0 Binary files /dev/null and b/android/app/src/main/res/drawable-xhdpi/tt_e31.png differ diff --git a/android/app/src/main/res/drawable-xhdpi/tt_e32.png b/android/app/src/main/res/drawable-xhdpi/tt_e32.png new file mode 100644 index 000000000..b53d1b852 Binary files /dev/null and b/android/app/src/main/res/drawable-xhdpi/tt_e32.png differ diff --git a/android/app/src/main/res/drawable-xhdpi/tt_e33.png b/android/app/src/main/res/drawable-xhdpi/tt_e33.png new file mode 100644 index 000000000..a6a8c98b7 Binary files /dev/null and b/android/app/src/main/res/drawable-xhdpi/tt_e33.png differ diff --git a/android/app/src/main/res/drawable-xhdpi/tt_e34.png b/android/app/src/main/res/drawable-xhdpi/tt_e34.png new file mode 100644 index 000000000..10a3f786e Binary files /dev/null and b/android/app/src/main/res/drawable-xhdpi/tt_e34.png differ diff --git a/android/app/src/main/res/drawable-xhdpi/tt_e35.png b/android/app/src/main/res/drawable-xhdpi/tt_e35.png new file mode 100644 index 000000000..a3fec61d8 Binary files /dev/null and b/android/app/src/main/res/drawable-xhdpi/tt_e35.png differ diff --git a/android/app/src/main/res/drawable-xhdpi/tt_e36.png b/android/app/src/main/res/drawable-xhdpi/tt_e36.png new file mode 100644 index 000000000..5184cb460 Binary files /dev/null and b/android/app/src/main/res/drawable-xhdpi/tt_e36.png differ diff --git a/android/app/src/main/res/drawable-xhdpi/tt_e37.png b/android/app/src/main/res/drawable-xhdpi/tt_e37.png new file mode 100644 index 000000000..787501104 Binary files /dev/null and b/android/app/src/main/res/drawable-xhdpi/tt_e37.png differ diff --git a/android/app/src/main/res/drawable-xhdpi/tt_e38.png b/android/app/src/main/res/drawable-xhdpi/tt_e38.png new file mode 100644 index 000000000..c33eea72c Binary files /dev/null and b/android/app/src/main/res/drawable-xhdpi/tt_e38.png differ diff --git a/android/app/src/main/res/drawable-xhdpi/tt_e39.png b/android/app/src/main/res/drawable-xhdpi/tt_e39.png new file mode 100644 index 000000000..005634d8d Binary files /dev/null and b/android/app/src/main/res/drawable-xhdpi/tt_e39.png differ diff --git a/android/app/src/main/res/drawable-xhdpi/tt_e4.png b/android/app/src/main/res/drawable-xhdpi/tt_e4.png new file mode 100644 index 000000000..0a03af728 Binary files /dev/null and b/android/app/src/main/res/drawable-xhdpi/tt_e4.png differ diff --git a/android/app/src/main/res/drawable-xhdpi/tt_e40.png b/android/app/src/main/res/drawable-xhdpi/tt_e40.png new file mode 100644 index 000000000..9e80b1b17 Binary files /dev/null and b/android/app/src/main/res/drawable-xhdpi/tt_e40.png differ diff --git a/android/app/src/main/res/drawable-xhdpi/tt_e41.png b/android/app/src/main/res/drawable-xhdpi/tt_e41.png new file mode 100644 index 000000000..599ae59a6 Binary files /dev/null and b/android/app/src/main/res/drawable-xhdpi/tt_e41.png differ diff --git a/android/app/src/main/res/drawable-xhdpi/tt_e42.png b/android/app/src/main/res/drawable-xhdpi/tt_e42.png new file mode 100644 index 000000000..4fa349454 Binary files /dev/null and b/android/app/src/main/res/drawable-xhdpi/tt_e42.png differ diff --git a/android/app/src/main/res/drawable-xhdpi/tt_e43.png b/android/app/src/main/res/drawable-xhdpi/tt_e43.png new file mode 100644 index 000000000..abe8adcee Binary files /dev/null and b/android/app/src/main/res/drawable-xhdpi/tt_e43.png differ diff --git a/android/app/src/main/res/drawable-xhdpi/tt_e44.png b/android/app/src/main/res/drawable-xhdpi/tt_e44.png new file mode 100644 index 000000000..256318047 Binary files /dev/null and b/android/app/src/main/res/drawable-xhdpi/tt_e44.png differ diff --git a/android/app/src/main/res/drawable-xhdpi/tt_e45.png b/android/app/src/main/res/drawable-xhdpi/tt_e45.png new file mode 100644 index 000000000..75c92468e Binary files /dev/null and b/android/app/src/main/res/drawable-xhdpi/tt_e45.png differ diff --git a/android/app/src/main/res/drawable-xhdpi/tt_e5.png b/android/app/src/main/res/drawable-xhdpi/tt_e5.png new file mode 100644 index 000000000..ba22141e2 Binary files /dev/null and b/android/app/src/main/res/drawable-xhdpi/tt_e5.png differ diff --git a/android/app/src/main/res/drawable-xhdpi/tt_e6.png b/android/app/src/main/res/drawable-xhdpi/tt_e6.png new file mode 100644 index 000000000..a7ba403ee Binary files /dev/null and b/android/app/src/main/res/drawable-xhdpi/tt_e6.png differ diff --git a/android/app/src/main/res/drawable-xhdpi/tt_e7.png b/android/app/src/main/res/drawable-xhdpi/tt_e7.png new file mode 100644 index 000000000..0ffa230aa Binary files /dev/null and b/android/app/src/main/res/drawable-xhdpi/tt_e7.png differ diff --git a/android/app/src/main/res/drawable-xhdpi/tt_e8.png b/android/app/src/main/res/drawable-xhdpi/tt_e8.png new file mode 100644 index 000000000..bd46e8d9e Binary files /dev/null and b/android/app/src/main/res/drawable-xhdpi/tt_e8.png differ diff --git a/android/app/src/main/res/drawable-xhdpi/tt_e9.png b/android/app/src/main/res/drawable-xhdpi/tt_e9.png new file mode 100644 index 000000000..9657bdb8c Binary files /dev/null and b/android/app/src/main/res/drawable-xhdpi/tt_e9.png differ diff --git a/android/app/src/main/res/drawable-xhdpi/tt_empty_default_icon.png b/android/app/src/main/res/drawable-xhdpi/tt_empty_default_icon.png new file mode 100644 index 000000000..024a591e1 Binary files /dev/null and b/android/app/src/main/res/drawable-xhdpi/tt_empty_default_icon.png differ diff --git a/android/app/src/main/res/drawable-xhdpi/tt_empty_no_contact_icon.png b/android/app/src/main/res/drawable-xhdpi/tt_empty_no_contact_icon.png new file mode 100644 index 000000000..4b87490e4 Binary files /dev/null and b/android/app/src/main/res/drawable-xhdpi/tt_empty_no_contact_icon.png differ diff --git a/android/app/src/main/res/drawable-xhdpi/tt_group_manager_add_user.png b/android/app/src/main/res/drawable-xhdpi/tt_group_manager_add_user.png new file mode 100644 index 000000000..24fe0266e Binary files /dev/null and b/android/app/src/main/res/drawable-xhdpi/tt_group_manager_add_user.png differ diff --git a/android/app/src/main/res/drawable-xhdpi/tt_group_manager_delete_user.png b/android/app/src/main/res/drawable-xhdpi/tt_group_manager_delete_user.png new file mode 100644 index 000000000..2331b5897 Binary files /dev/null and b/android/app/src/main/res/drawable-xhdpi/tt_group_manager_delete_user.png differ diff --git a/android/app/src/main/res/drawable-xhdpi/tt_group_tag_admin.png b/android/app/src/main/res/drawable-xhdpi/tt_group_tag_admin.png new file mode 100644 index 000000000..85fc324e1 Binary files /dev/null and b/android/app/src/main/res/drawable-xhdpi/tt_group_tag_admin.png differ diff --git a/android/app/src/main/res/drawable-xhdpi/tt_ic_launcher.png b/android/app/src/main/res/drawable-xhdpi/tt_ic_launcher.png new file mode 100644 index 000000000..d4fb7cd9d Binary files /dev/null and b/android/app/src/main/res/drawable-xhdpi/tt_ic_launcher.png differ diff --git a/android/app/src/main/res/drawable-xhdpi/tt_internal_page_logo.png b/android/app/src/main/res/drawable-xhdpi/tt_internal_page_logo.png new file mode 100644 index 000000000..cff86226d Binary files /dev/null and b/android/app/src/main/res/drawable-xhdpi/tt_internal_page_logo.png differ diff --git a/android/app/src/main/res/drawable-xhdpi/tt_login_logo.png b/android/app/src/main/res/drawable-xhdpi/tt_login_logo.png new file mode 100644 index 000000000..82fa62e9e Binary files /dev/null and b/android/app/src/main/res/drawable-xhdpi/tt_login_logo.png differ diff --git a/android/app/src/main/res/drawable-xhdpi/tt_login_logo2.png b/android/app/src/main/res/drawable-xhdpi/tt_login_logo2.png new file mode 100644 index 000000000..7e6e70346 Binary files /dev/null and b/android/app/src/main/res/drawable-xhdpi/tt_login_logo2.png differ diff --git a/android/app/src/main/res/drawable-xhdpi/tt_login_pwd.png b/android/app/src/main/res/drawable-xhdpi/tt_login_pwd.png new file mode 100644 index 000000000..750f12c6c Binary files /dev/null and b/android/app/src/main/res/drawable-xhdpi/tt_login_pwd.png differ diff --git a/android/app/src/main/res/drawable-xhdpi/tt_login_user.png b/android/app/src/main/res/drawable-xhdpi/tt_login_user.png new file mode 100644 index 000000000..41743ca34 Binary files /dev/null and b/android/app/src/main/res/drawable-xhdpi/tt_login_user.png differ diff --git a/android/app/src/main/res/drawable-xhdpi/tt_logo.png b/android/app/src/main/res/drawable-xhdpi/tt_logo.png new file mode 100644 index 000000000..920dd5d3f Binary files /dev/null and b/android/app/src/main/res/drawable-xhdpi/tt_logo.png differ diff --git a/android/app/src/main/res/drawable-xhdpi/tt_logo2.png b/android/app/src/main/res/drawable-xhdpi/tt_logo2.png new file mode 100644 index 000000000..263f23012 Binary files /dev/null and b/android/app/src/main/res/drawable-xhdpi/tt_logo2.png differ diff --git a/android/app/src/main/res/drawable-xhdpi/tt_message_botify_no_disturb.png b/android/app/src/main/res/drawable-xhdpi/tt_message_botify_no_disturb.png new file mode 100644 index 000000000..0ab1ba120 Binary files /dev/null and b/android/app/src/main/res/drawable-xhdpi/tt_message_botify_no_disturb.png differ diff --git a/android/app/src/main/res/drawable-xhdpi/tt_message_image_default.png b/android/app/src/main/res/drawable-xhdpi/tt_message_image_default.png new file mode 100644 index 000000000..f9a539ea4 Binary files /dev/null and b/android/app/src/main/res/drawable-xhdpi/tt_message_image_default.png differ diff --git a/android/app/src/main/res/drawable-xhdpi/tt_message_image_error.png b/android/app/src/main/res/drawable-xhdpi/tt_message_image_error.png new file mode 100644 index 000000000..03a1dfef1 Binary files /dev/null and b/android/app/src/main/res/drawable-xhdpi/tt_message_image_error.png differ diff --git a/android/app/src/main/res/drawable-xhdpi/tt_message_notify.9.png b/android/app/src/main/res/drawable-xhdpi/tt_message_notify.9.png new file mode 100644 index 000000000..aaf05e489 Binary files /dev/null and b/android/app/src/main/res/drawable-xhdpi/tt_message_notify.9.png differ diff --git a/android/app/src/main/res/drawable-xhdpi/tt_message_notify_single.png b/android/app/src/main/res/drawable-xhdpi/tt_message_notify_single.png new file mode 100644 index 000000000..488fb70db Binary files /dev/null and b/android/app/src/main/res/drawable-xhdpi/tt_message_notify_single.png differ diff --git a/android/app/src/main/res/drawable-xhdpi/tt_message_text_bg.9.png b/android/app/src/main/res/drawable-xhdpi/tt_message_text_bg.9.png new file mode 100644 index 000000000..a313e7f60 Binary files /dev/null and b/android/app/src/main/res/drawable-xhdpi/tt_message_text_bg.9.png differ diff --git a/android/app/src/main/res/drawable-xhdpi/tt_message_title_time_bg.9.png b/android/app/src/main/res/drawable-xhdpi/tt_message_title_time_bg.9.png new file mode 100644 index 000000000..d2b6b8d12 Binary files /dev/null and b/android/app/src/main/res/drawable-xhdpi/tt_message_title_time_bg.9.png differ diff --git a/android/app/src/main/res/drawable-xhdpi/tt_mine_image_bk.png b/android/app/src/main/res/drawable-xhdpi/tt_mine_image_bk.png new file mode 100644 index 000000000..dbb197958 Binary files /dev/null and b/android/app/src/main/res/drawable-xhdpi/tt_mine_image_bk.png differ diff --git a/android/app/src/main/res/drawable-xhdpi/tt_mine_image_default_bk.png b/android/app/src/main/res/drawable-xhdpi/tt_mine_image_default_bk.png new file mode 100644 index 000000000..d852f57d6 Binary files /dev/null and b/android/app/src/main/res/drawable-xhdpi/tt_mine_image_default_bk.png differ diff --git a/android/app/src/main/res/drawable-xhdpi/tt_mine_image_horizontal_bk.png b/android/app/src/main/res/drawable-xhdpi/tt_mine_image_horizontal_bk.png new file mode 100644 index 000000000..db229f2e5 Binary files /dev/null and b/android/app/src/main/res/drawable-xhdpi/tt_mine_image_horizontal_bk.png differ diff --git a/android/app/src/main/res/drawable-xhdpi/tt_mine_image_vertical_bk.9.png b/android/app/src/main/res/drawable-xhdpi/tt_mine_image_vertical_bk.9.png new file mode 100644 index 000000000..023a86994 Binary files /dev/null and b/android/app/src/main/res/drawable-xhdpi/tt_mine_image_vertical_bk.9.png differ diff --git a/android/app/src/main/res/drawable-xhdpi/tt_mine_item_bg_normal.9.png b/android/app/src/main/res/drawable-xhdpi/tt_mine_item_bg_normal.9.png new file mode 100644 index 000000000..5b93f06a1 Binary files /dev/null and b/android/app/src/main/res/drawable-xhdpi/tt_mine_item_bg_normal.9.png differ diff --git a/android/app/src/main/res/drawable-xhdpi/tt_mine_item_bg_pressed.9.png b/android/app/src/main/res/drawable-xhdpi/tt_mine_item_bg_pressed.9.png new file mode 100644 index 000000000..836cdbbbe Binary files /dev/null and b/android/app/src/main/res/drawable-xhdpi/tt_mine_item_bg_pressed.9.png differ diff --git a/android/app/src/main/res/drawable-xhdpi/tt_msg_tip.png b/android/app/src/main/res/drawable-xhdpi/tt_msg_tip.png new file mode 100644 index 000000000..5de885b9b Binary files /dev/null and b/android/app/src/main/res/drawable-xhdpi/tt_msg_tip.png differ diff --git a/android/app/src/main/res/drawable-xhdpi/tt_my_message_bkgnd.9.png b/android/app/src/main/res/drawable-xhdpi/tt_my_message_bkgnd.9.png new file mode 100644 index 000000000..c3c35e172 Binary files /dev/null and b/android/app/src/main/res/drawable-xhdpi/tt_my_message_bkgnd.9.png differ diff --git a/android/app/src/main/res/drawable-xhdpi/tt_new_msg_bk.png b/android/app/src/main/res/drawable-xhdpi/tt_new_msg_bk.png new file mode 100644 index 000000000..44704abe6 Binary files /dev/null and b/android/app/src/main/res/drawable-xhdpi/tt_new_msg_bk.png differ diff --git a/android/app/src/main/res/drawable-xhdpi/tt_no_disturb_image.png b/android/app/src/main/res/drawable-xhdpi/tt_no_disturb_image.png new file mode 100644 index 000000000..1e73385e1 Binary files /dev/null and b/android/app/src/main/res/drawable-xhdpi/tt_no_disturb_image.png differ diff --git a/android/app/src/main/res/drawable-xhdpi/tt_other_default_image_bk.9.png b/android/app/src/main/res/drawable-xhdpi/tt_other_default_image_bk.9.png new file mode 100644 index 000000000..118e8f8ef Binary files /dev/null and b/android/app/src/main/res/drawable-xhdpi/tt_other_default_image_bk.9.png differ diff --git a/android/app/src/main/res/drawable-xhdpi/tt_other_image_bk.png b/android/app/src/main/res/drawable-xhdpi/tt_other_image_bk.png new file mode 100644 index 000000000..762b15889 Binary files /dev/null and b/android/app/src/main/res/drawable-xhdpi/tt_other_image_bk.png differ diff --git a/android/app/src/main/res/drawable-xhdpi/tt_other_image_default_bk.png b/android/app/src/main/res/drawable-xhdpi/tt_other_image_default_bk.png new file mode 100644 index 000000000..4a6243d0d Binary files /dev/null and b/android/app/src/main/res/drawable-xhdpi/tt_other_image_default_bk.png differ diff --git a/android/app/src/main/res/drawable-xhdpi/tt_other_image_horizontal_bk.png b/android/app/src/main/res/drawable-xhdpi/tt_other_image_horizontal_bk.png new file mode 100644 index 000000000..5e0c21896 Binary files /dev/null and b/android/app/src/main/res/drawable-xhdpi/tt_other_image_horizontal_bk.png differ diff --git a/android/app/src/main/res/drawable-xhdpi/tt_other_image_vertical_bk.9.png b/android/app/src/main/res/drawable-xhdpi/tt_other_image_vertical_bk.9.png new file mode 100644 index 000000000..66ffca393 Binary files /dev/null and b/android/app/src/main/res/drawable-xhdpi/tt_other_image_vertical_bk.9.png differ diff --git a/android/app/src/main/res/drawable-xhdpi/tt_other_item_bg_normal.9.png b/android/app/src/main/res/drawable-xhdpi/tt_other_item_bg_normal.9.png new file mode 100644 index 000000000..0f2236ddd Binary files /dev/null and b/android/app/src/main/res/drawable-xhdpi/tt_other_item_bg_normal.9.png differ diff --git a/android/app/src/main/res/drawable-xhdpi/tt_other_item_bg_pressed.9.png b/android/app/src/main/res/drawable-xhdpi/tt_other_item_bg_pressed.9.png new file mode 100644 index 000000000..6b64cf286 Binary files /dev/null and b/android/app/src/main/res/drawable-xhdpi/tt_other_item_bg_pressed.9.png differ diff --git a/android/app/src/main/res/drawable-xhdpi/tt_other_text_background.png b/android/app/src/main/res/drawable-xhdpi/tt_other_text_background.png new file mode 100644 index 000000000..e1ef23023 Binary files /dev/null and b/android/app/src/main/res/drawable-xhdpi/tt_other_text_background.png differ diff --git a/android/app/src/main/res/drawable-xhdpi/tt_page_item_bk.9.png b/android/app/src/main/res/drawable-xhdpi/tt_page_item_bk.9.png new file mode 100644 index 000000000..a19cacafb Binary files /dev/null and b/android/app/src/main/res/drawable-xhdpi/tt_page_item_bk.9.png differ diff --git a/android/app/src/main/res/drawable-xhdpi/tt_page_my_setting.png b/android/app/src/main/res/drawable-xhdpi/tt_page_my_setting.png new file mode 100644 index 000000000..c3dca8247 Binary files /dev/null and b/android/app/src/main/res/drawable-xhdpi/tt_page_my_setting.png differ diff --git a/android/app/src/main/res/drawable-xhdpi/tt_pannel_bk.9.png b/android/app/src/main/res/drawable-xhdpi/tt_pannel_bk.9.png new file mode 100644 index 000000000..961fb5c44 Binary files /dev/null and b/android/app/src/main/res/drawable-xhdpi/tt_pannel_bk.9.png differ diff --git a/android/app/src/main/res/drawable-xhdpi/tt_pannel_btn_voiceforward_normal.9.png b/android/app/src/main/res/drawable-xhdpi/tt_pannel_btn_voiceforward_normal.9.png new file mode 100644 index 000000000..78aba2cfd Binary files /dev/null and b/android/app/src/main/res/drawable-xhdpi/tt_pannel_btn_voiceforward_normal.9.png differ diff --git a/android/app/src/main/res/drawable-xhdpi/tt_pannel_btn_voiceforward_pressed.9.png b/android/app/src/main/res/drawable-xhdpi/tt_pannel_btn_voiceforward_pressed.9.png new file mode 100644 index 000000000..3a39eec9e Binary files /dev/null and b/android/app/src/main/res/drawable-xhdpi/tt_pannel_btn_voiceforward_pressed.9.png differ diff --git a/android/app/src/main/res/drawable-xhdpi/tt_preview_dot_down.png b/android/app/src/main/res/drawable-xhdpi/tt_preview_dot_down.png new file mode 100644 index 000000000..217b68464 Binary files /dev/null and b/android/app/src/main/res/drawable-xhdpi/tt_preview_dot_down.png differ diff --git a/android/app/src/main/res/drawable-xhdpi/tt_preview_dot_up.png b/android/app/src/main/res/drawable-xhdpi/tt_preview_dot_up.png new file mode 100644 index 000000000..bab7be597 Binary files /dev/null and b/android/app/src/main/res/drawable-xhdpi/tt_preview_dot_up.png differ diff --git a/android/app/src/main/res/drawable-xhdpi/tt_search.png b/android/app/src/main/res/drawable-xhdpi/tt_search.png new file mode 100644 index 000000000..e24643e21 Binary files /dev/null and b/android/app/src/main/res/drawable-xhdpi/tt_search.png differ diff --git a/android/app/src/main/res/drawable-xhdpi/tt_send_btn_bg.9.png b/android/app/src/main/res/drawable-xhdpi/tt_send_btn_bg.9.png new file mode 100644 index 000000000..ab42a0cd5 Binary files /dev/null and b/android/app/src/main/res/drawable-xhdpi/tt_send_btn_bg.9.png differ diff --git a/android/app/src/main/res/drawable-xhdpi/tt_send_message_btn_bg.9.png b/android/app/src/main/res/drawable-xhdpi/tt_send_message_btn_bg.9.png new file mode 100644 index 000000000..5014ac7f0 Binary files /dev/null and b/android/app/src/main/res/drawable-xhdpi/tt_send_message_btn_bg.9.png differ diff --git a/android/app/src/main/res/drawable-xhdpi/tt_send_voice_btn_bg.9.png b/android/app/src/main/res/drawable-xhdpi/tt_send_voice_btn_bg.9.png new file mode 100644 index 000000000..7bf06d40a Binary files /dev/null and b/android/app/src/main/res/drawable-xhdpi/tt_send_voice_btn_bg.9.png differ diff --git a/android/app/src/main/res/drawable-xhdpi/tt_send_voice_btn_bg_normal.9.png b/android/app/src/main/res/drawable-xhdpi/tt_send_voice_btn_bg_normal.9.png new file mode 100644 index 000000000..7bf06d40a Binary files /dev/null and b/android/app/src/main/res/drawable-xhdpi/tt_send_voice_btn_bg_normal.9.png differ diff --git a/android/app/src/main/res/drawable-xhdpi/tt_send_voice_btn_btn_pressed.9.png b/android/app/src/main/res/drawable-xhdpi/tt_send_voice_btn_btn_pressed.9.png new file mode 100644 index 000000000..53d72cfb4 Binary files /dev/null and b/android/app/src/main/res/drawable-xhdpi/tt_send_voice_btn_btn_pressed.9.png differ diff --git a/android/app/src/main/res/drawable-xhdpi/tt_show_add_photo_btn.png b/android/app/src/main/res/drawable-xhdpi/tt_show_add_photo_btn.png new file mode 100644 index 000000000..22a396da8 Binary files /dev/null and b/android/app/src/main/res/drawable-xhdpi/tt_show_add_photo_btn.png differ diff --git a/android/app/src/main/res/drawable-xhdpi/tt_show_head_toast_bg.9.png b/android/app/src/main/res/drawable-xhdpi/tt_show_head_toast_bg.9.png new file mode 100644 index 000000000..18e7a1267 Binary files /dev/null and b/android/app/src/main/res/drawable-xhdpi/tt_show_head_toast_bg.9.png differ diff --git a/android/app/src/main/res/drawable-xhdpi/tt_small_icon.png b/android/app/src/main/res/drawable-xhdpi/tt_small_icon.png new file mode 100644 index 000000000..3da55b784 Binary files /dev/null and b/android/app/src/main/res/drawable-xhdpi/tt_small_icon.png differ diff --git a/android/app/src/main/res/drawable-xhdpi/tt_sound_volume_01.png b/android/app/src/main/res/drawable-xhdpi/tt_sound_volume_01.png new file mode 100644 index 000000000..e0c25f746 Binary files /dev/null and b/android/app/src/main/res/drawable-xhdpi/tt_sound_volume_01.png differ diff --git a/android/app/src/main/res/drawable-xhdpi/tt_sound_volume_02.png b/android/app/src/main/res/drawable-xhdpi/tt_sound_volume_02.png new file mode 100644 index 000000000..922e59e2a Binary files /dev/null and b/android/app/src/main/res/drawable-xhdpi/tt_sound_volume_02.png differ diff --git a/android/app/src/main/res/drawable-xhdpi/tt_sound_volume_03.png b/android/app/src/main/res/drawable-xhdpi/tt_sound_volume_03.png new file mode 100644 index 000000000..ba133036d Binary files /dev/null and b/android/app/src/main/res/drawable-xhdpi/tt_sound_volume_03.png differ diff --git a/android/app/src/main/res/drawable-xhdpi/tt_sound_volume_04.png b/android/app/src/main/res/drawable-xhdpi/tt_sound_volume_04.png new file mode 100644 index 000000000..ffa7dfa64 Binary files /dev/null and b/android/app/src/main/res/drawable-xhdpi/tt_sound_volume_04.png differ diff --git a/android/app/src/main/res/drawable-xhdpi/tt_sound_volume_05.png b/android/app/src/main/res/drawable-xhdpi/tt_sound_volume_05.png new file mode 100644 index 000000000..50b76aa45 Binary files /dev/null and b/android/app/src/main/res/drawable-xhdpi/tt_sound_volume_05.png differ diff --git a/android/app/src/main/res/drawable-xhdpi/tt_sound_volume_06.png b/android/app/src/main/res/drawable-xhdpi/tt_sound_volume_06.png new file mode 100644 index 000000000..284fb08a0 Binary files /dev/null and b/android/app/src/main/res/drawable-xhdpi/tt_sound_volume_06.png differ diff --git a/android/app/src/main/res/drawable-xhdpi/tt_sound_volume_07.png b/android/app/src/main/res/drawable-xhdpi/tt_sound_volume_07.png new file mode 100644 index 000000000..da34816cb Binary files /dev/null and b/android/app/src/main/res/drawable-xhdpi/tt_sound_volume_07.png differ diff --git a/android/app/src/main/res/drawable-xhdpi/tt_sound_volume_cancel_bk.png b/android/app/src/main/res/drawable-xhdpi/tt_sound_volume_cancel_bk.png new file mode 100644 index 000000000..a333f958f Binary files /dev/null and b/android/app/src/main/res/drawable-xhdpi/tt_sound_volume_cancel_bk.png differ diff --git a/android/app/src/main/res/drawable-xhdpi/tt_sound_volume_default_bk.png b/android/app/src/main/res/drawable-xhdpi/tt_sound_volume_default_bk.png new file mode 100644 index 000000000..cb95d57bd Binary files /dev/null and b/android/app/src/main/res/drawable-xhdpi/tt_sound_volume_default_bk.png differ diff --git a/android/app/src/main/res/drawable-xhdpi/tt_sound_volume_short_tip_bk.png b/android/app/src/main/res/drawable-xhdpi/tt_sound_volume_short_tip_bk.png new file mode 100644 index 000000000..95391d79a Binary files /dev/null and b/android/app/src/main/res/drawable-xhdpi/tt_sound_volume_short_tip_bk.png differ diff --git a/android/app/src/main/res/drawable-xhdpi/tt_speeker_tip_bg.png b/android/app/src/main/res/drawable-xhdpi/tt_speeker_tip_bg.png new file mode 100644 index 000000000..f04968708 Binary files /dev/null and b/android/app/src/main/res/drawable-xhdpi/tt_speeker_tip_bg.png differ diff --git a/android/app/src/main/res/drawable-xhdpi/tt_splash.jpg b/android/app/src/main/res/drawable-xhdpi/tt_splash.jpg new file mode 100644 index 000000000..994e37d77 Binary files /dev/null and b/android/app/src/main/res/drawable-xhdpi/tt_splash.jpg differ diff --git a/android/app/src/main/res/drawable-xhdpi/tt_switch_to_keyboard_btn.png b/android/app/src/main/res/drawable-xhdpi/tt_switch_to_keyboard_btn.png new file mode 100644 index 000000000..4188f367f Binary files /dev/null and b/android/app/src/main/res/drawable-xhdpi/tt_switch_to_keyboard_btn.png differ diff --git a/android/app/src/main/res/drawable-xhdpi/tt_tab_bk.png b/android/app/src/main/res/drawable-xhdpi/tt_tab_bk.png new file mode 100644 index 000000000..638e9f6f6 Binary files /dev/null and b/android/app/src/main/res/drawable-xhdpi/tt_tab_bk.png differ diff --git a/android/app/src/main/res/drawable-xhdpi/tt_tab_chat_nor.png b/android/app/src/main/res/drawable-xhdpi/tt_tab_chat_nor.png new file mode 100644 index 000000000..cde77cd81 Binary files /dev/null and b/android/app/src/main/res/drawable-xhdpi/tt_tab_chat_nor.png differ diff --git a/android/app/src/main/res/drawable-xhdpi/tt_tab_chat_sel.png b/android/app/src/main/res/drawable-xhdpi/tt_tab_chat_sel.png new file mode 100644 index 000000000..da00e7c8d Binary files /dev/null and b/android/app/src/main/res/drawable-xhdpi/tt_tab_chat_sel.png differ diff --git a/android/app/src/main/res/drawable-xhdpi/tt_tab_contact_nor.png b/android/app/src/main/res/drawable-xhdpi/tt_tab_contact_nor.png new file mode 100644 index 000000000..1e38ddb7d Binary files /dev/null and b/android/app/src/main/res/drawable-xhdpi/tt_tab_contact_nor.png differ diff --git a/android/app/src/main/res/drawable-xhdpi/tt_tab_contact_sel.png b/android/app/src/main/res/drawable-xhdpi/tt_tab_contact_sel.png new file mode 100644 index 000000000..bc79e36a4 Binary files /dev/null and b/android/app/src/main/res/drawable-xhdpi/tt_tab_contact_sel.png differ diff --git a/android/app/src/main/res/drawable-xhdpi/tt_tab_internal_nor.png b/android/app/src/main/res/drawable-xhdpi/tt_tab_internal_nor.png new file mode 100644 index 000000000..16f43e708 Binary files /dev/null and b/android/app/src/main/res/drawable-xhdpi/tt_tab_internal_nor.png differ diff --git a/android/app/src/main/res/drawable-xhdpi/tt_tab_internal_select.png b/android/app/src/main/res/drawable-xhdpi/tt_tab_internal_select.png new file mode 100644 index 000000000..be6505d2e Binary files /dev/null and b/android/app/src/main/res/drawable-xhdpi/tt_tab_internal_select.png differ diff --git a/android/app/src/main/res/drawable-xhdpi/tt_tab_me_nor.png b/android/app/src/main/res/drawable-xhdpi/tt_tab_me_nor.png new file mode 100644 index 000000000..c8c975ab1 Binary files /dev/null and b/android/app/src/main/res/drawable-xhdpi/tt_tab_me_nor.png differ diff --git a/android/app/src/main/res/drawable-xhdpi/tt_tab_me_sel.png b/android/app/src/main/res/drawable-xhdpi/tt_tab_me_sel.png new file mode 100644 index 000000000..d6f0dff28 Binary files /dev/null and b/android/app/src/main/res/drawable-xhdpi/tt_tab_me_sel.png differ diff --git a/android/app/src/main/res/drawable-xhdpi/tt_take_camera_btn_bg.png b/android/app/src/main/res/drawable-xhdpi/tt_take_camera_btn_bg.png new file mode 100644 index 000000000..c5b3d708e Binary files /dev/null and b/android/app/src/main/res/drawable-xhdpi/tt_take_camera_btn_bg.png differ diff --git a/android/app/src/main/res/drawable-xhdpi/tt_take_photo_btn_bg.png b/android/app/src/main/res/drawable-xhdpi/tt_take_photo_btn_bg.png new file mode 100644 index 000000000..b6ffac269 Binary files /dev/null and b/android/app/src/main/res/drawable-xhdpi/tt_take_photo_btn_bg.png differ diff --git a/android/app/src/main/res/drawable-xhdpi/tt_top_back.png b/android/app/src/main/res/drawable-xhdpi/tt_top_back.png new file mode 100644 index 000000000..c7b6d7c09 Binary files /dev/null and b/android/app/src/main/res/drawable-xhdpi/tt_top_back.png differ diff --git a/android/app/src/main/res/drawable-xhdpi/tt_top_default_bk.png b/android/app/src/main/res/drawable-xhdpi/tt_top_default_bk.png new file mode 100644 index 000000000..e549b0d1a Binary files /dev/null and b/android/app/src/main/res/drawable-xhdpi/tt_top_default_bk.png differ diff --git a/android/app/src/main/res/drawable-xhdpi/tt_top_right_group_manager.png b/android/app/src/main/res/drawable-xhdpi/tt_top_right_group_manager.png new file mode 100644 index 000000000..27647e308 Binary files /dev/null and b/android/app/src/main/res/drawable-xhdpi/tt_top_right_group_manager.png differ diff --git a/android/app/src/main/res/drawable-xhdpi/tt_top_search.png b/android/app/src/main/res/drawable-xhdpi/tt_top_search.png new file mode 100644 index 000000000..dfca7bfeb Binary files /dev/null and b/android/app/src/main/res/drawable-xhdpi/tt_top_search.png differ diff --git a/android/app/src/main/res/drawable-xhdpi/tt_top_search_bg.9.png b/android/app/src/main/res/drawable-xhdpi/tt_top_search_bg.9.png new file mode 100644 index 000000000..a7e877a70 Binary files /dev/null and b/android/app/src/main/res/drawable-xhdpi/tt_top_search_bg.9.png differ diff --git a/android/app/src/main/res/drawable-xhdpi/tt_unread_message_notify_bg.png b/android/app/src/main/res/drawable-xhdpi/tt_unread_message_notify_bg.png new file mode 100644 index 000000000..2fe180c85 Binary files /dev/null and b/android/app/src/main/res/drawable-xhdpi/tt_unread_message_notify_bg.png differ diff --git a/android/app/src/main/res/drawable-xhdpi/tt_voice_btn_btn.png b/android/app/src/main/res/drawable-xhdpi/tt_voice_btn_btn.png new file mode 100644 index 000000000..232b1b30f Binary files /dev/null and b/android/app/src/main/res/drawable-xhdpi/tt_voice_btn_btn.png differ diff --git a/android/app/src/main/res/drawable-xhdpi/tt_voice_node_mine.png b/android/app/src/main/res/drawable-xhdpi/tt_voice_node_mine.png new file mode 100644 index 000000000..fd09abf9a Binary files /dev/null and b/android/app/src/main/res/drawable-xhdpi/tt_voice_node_mine.png differ diff --git a/android/app/src/main/res/drawable-xhdpi/tt_voice_node_mine_playing001.png b/android/app/src/main/res/drawable-xhdpi/tt_voice_node_mine_playing001.png new file mode 100644 index 000000000..be3b1c0ce Binary files /dev/null and b/android/app/src/main/res/drawable-xhdpi/tt_voice_node_mine_playing001.png differ diff --git a/android/app/src/main/res/drawable-xhdpi/tt_voice_node_mine_playing002.png b/android/app/src/main/res/drawable-xhdpi/tt_voice_node_mine_playing002.png new file mode 100644 index 000000000..dbd6c888a Binary files /dev/null and b/android/app/src/main/res/drawable-xhdpi/tt_voice_node_mine_playing002.png differ diff --git a/android/app/src/main/res/drawable-xhdpi/tt_voice_node_mine_playing003.png b/android/app/src/main/res/drawable-xhdpi/tt_voice_node_mine_playing003.png new file mode 100644 index 000000000..e59417127 Binary files /dev/null and b/android/app/src/main/res/drawable-xhdpi/tt_voice_node_mine_playing003.png differ diff --git a/android/app/src/main/res/drawable-xhdpi/tt_voice_node_other.png b/android/app/src/main/res/drawable-xhdpi/tt_voice_node_other.png new file mode 100644 index 000000000..8c9bc3fd7 Binary files /dev/null and b/android/app/src/main/res/drawable-xhdpi/tt_voice_node_other.png differ diff --git a/android/app/src/main/res/drawable-xhdpi/tt_voice_node_other_playing001.png b/android/app/src/main/res/drawable-xhdpi/tt_voice_node_other_playing001.png new file mode 100644 index 000000000..58265e7bc Binary files /dev/null and b/android/app/src/main/res/drawable-xhdpi/tt_voice_node_other_playing001.png differ diff --git a/android/app/src/main/res/drawable-xhdpi/tt_voice_node_other_playing002.png b/android/app/src/main/res/drawable-xhdpi/tt_voice_node_other_playing002.png new file mode 100644 index 000000000..36440660d Binary files /dev/null and b/android/app/src/main/res/drawable-xhdpi/tt_voice_node_other_playing002.png differ diff --git a/android/app/src/main/res/drawable-xhdpi/tt_voice_node_other_playing003.png b/android/app/src/main/res/drawable-xhdpi/tt_voice_node_other_playing003.png new file mode 100644 index 000000000..b414e2d48 Binary files /dev/null and b/android/app/src/main/res/drawable-xhdpi/tt_voice_node_other_playing003.png differ diff --git a/android/app/src/main/res/drawable-xhdpi/tt_waterfall_refresh_bg.9.png b/android/app/src/main/res/drawable-xhdpi/tt_waterfall_refresh_bg.9.png new file mode 100644 index 000000000..bb276d496 Binary files /dev/null and b/android/app/src/main/res/drawable-xhdpi/tt_waterfall_refresh_bg.9.png differ diff --git a/android/app/src/main/res/drawable-xhdpi/tt_yaya_e1.gif b/android/app/src/main/res/drawable-xhdpi/tt_yaya_e1.gif new file mode 100755 index 000000000..d75703ebf Binary files /dev/null and b/android/app/src/main/res/drawable-xhdpi/tt_yaya_e1.gif differ diff --git a/android/app/src/main/res/drawable-xhdpi/tt_yaya_e10.gif b/android/app/src/main/res/drawable-xhdpi/tt_yaya_e10.gif new file mode 100755 index 000000000..7064b50d9 Binary files /dev/null and b/android/app/src/main/res/drawable-xhdpi/tt_yaya_e10.gif differ diff --git a/android/app/src/main/res/drawable-xhdpi/tt_yaya_e11.gif b/android/app/src/main/res/drawable-xhdpi/tt_yaya_e11.gif new file mode 100755 index 000000000..276161541 Binary files /dev/null and b/android/app/src/main/res/drawable-xhdpi/tt_yaya_e11.gif differ diff --git a/android/app/src/main/res/drawable-xhdpi/tt_yaya_e12.gif b/android/app/src/main/res/drawable-xhdpi/tt_yaya_e12.gif new file mode 100755 index 000000000..f913f56e5 Binary files /dev/null and b/android/app/src/main/res/drawable-xhdpi/tt_yaya_e12.gif differ diff --git a/android/app/src/main/res/drawable-xhdpi/tt_yaya_e13.gif b/android/app/src/main/res/drawable-xhdpi/tt_yaya_e13.gif new file mode 100755 index 000000000..656eb7904 Binary files /dev/null and b/android/app/src/main/res/drawable-xhdpi/tt_yaya_e13.gif differ diff --git a/android/app/src/main/res/drawable-xhdpi/tt_yaya_e14.gif b/android/app/src/main/res/drawable-xhdpi/tt_yaya_e14.gif new file mode 100755 index 000000000..b46680c23 Binary files /dev/null and b/android/app/src/main/res/drawable-xhdpi/tt_yaya_e14.gif differ diff --git a/android/app/src/main/res/drawable-xhdpi/tt_yaya_e15.gif b/android/app/src/main/res/drawable-xhdpi/tt_yaya_e15.gif new file mode 100755 index 000000000..f129cf3d4 Binary files /dev/null and b/android/app/src/main/res/drawable-xhdpi/tt_yaya_e15.gif differ diff --git a/android/app/src/main/res/drawable-xhdpi/tt_yaya_e16.gif b/android/app/src/main/res/drawable-xhdpi/tt_yaya_e16.gif new file mode 100755 index 000000000..35cc1148d Binary files /dev/null and b/android/app/src/main/res/drawable-xhdpi/tt_yaya_e16.gif differ diff --git a/android/app/src/main/res/drawable-xhdpi/tt_yaya_e17.gif b/android/app/src/main/res/drawable-xhdpi/tt_yaya_e17.gif new file mode 100755 index 000000000..0bfa22f79 Binary files /dev/null and b/android/app/src/main/res/drawable-xhdpi/tt_yaya_e17.gif differ diff --git a/android/app/src/main/res/drawable-xhdpi/tt_yaya_e18.gif b/android/app/src/main/res/drawable-xhdpi/tt_yaya_e18.gif new file mode 100755 index 000000000..9edcf90af Binary files /dev/null and b/android/app/src/main/res/drawable-xhdpi/tt_yaya_e18.gif differ diff --git a/android/app/src/main/res/drawable-xhdpi/tt_yaya_e19.gif b/android/app/src/main/res/drawable-xhdpi/tt_yaya_e19.gif new file mode 100755 index 000000000..6ca6e0d7e Binary files /dev/null and b/android/app/src/main/res/drawable-xhdpi/tt_yaya_e19.gif differ diff --git a/android/app/src/main/res/drawable-xhdpi/tt_yaya_e2.gif b/android/app/src/main/res/drawable-xhdpi/tt_yaya_e2.gif new file mode 100755 index 000000000..52883dd44 Binary files /dev/null and b/android/app/src/main/res/drawable-xhdpi/tt_yaya_e2.gif differ diff --git a/android/app/src/main/res/drawable-xhdpi/tt_yaya_e3.gif b/android/app/src/main/res/drawable-xhdpi/tt_yaya_e3.gif new file mode 100755 index 000000000..54636150d Binary files /dev/null and b/android/app/src/main/res/drawable-xhdpi/tt_yaya_e3.gif differ diff --git a/android/app/src/main/res/drawable-xhdpi/tt_yaya_e4.gif b/android/app/src/main/res/drawable-xhdpi/tt_yaya_e4.gif new file mode 100755 index 000000000..f7f9be2ae Binary files /dev/null and b/android/app/src/main/res/drawable-xhdpi/tt_yaya_e4.gif differ diff --git a/android/app/src/main/res/drawable-xhdpi/tt_yaya_e5.gif b/android/app/src/main/res/drawable-xhdpi/tt_yaya_e5.gif new file mode 100755 index 000000000..5ea900f8c Binary files /dev/null and b/android/app/src/main/res/drawable-xhdpi/tt_yaya_e5.gif differ diff --git a/android/app/src/main/res/drawable-xhdpi/tt_yaya_e6.gif b/android/app/src/main/res/drawable-xhdpi/tt_yaya_e6.gif new file mode 100755 index 000000000..724fe54cf Binary files /dev/null and b/android/app/src/main/res/drawable-xhdpi/tt_yaya_e6.gif differ diff --git a/android/app/src/main/res/drawable-xhdpi/tt_yaya_e7.gif b/android/app/src/main/res/drawable-xhdpi/tt_yaya_e7.gif new file mode 100755 index 000000000..a93f49f8d Binary files /dev/null and b/android/app/src/main/res/drawable-xhdpi/tt_yaya_e7.gif differ diff --git a/android/app/src/main/res/drawable-xhdpi/tt_yaya_e8.gif b/android/app/src/main/res/drawable-xhdpi/tt_yaya_e8.gif new file mode 100755 index 000000000..5ce7c7b09 Binary files /dev/null and b/android/app/src/main/res/drawable-xhdpi/tt_yaya_e8.gif differ diff --git a/android/app/src/main/res/drawable-xhdpi/tt_yaya_e9.gif b/android/app/src/main/res/drawable-xhdpi/tt_yaya_e9.gif new file mode 100755 index 000000000..86512d3c1 Binary files /dev/null and b/android/app/src/main/res/drawable-xhdpi/tt_yaya_e9.gif differ diff --git a/android/app/src/main/res/drawable-xhdpi/uncheck.png b/android/app/src/main/res/drawable-xhdpi/uncheck.png new file mode 100644 index 000000000..f0e16e5b1 Binary files /dev/null and b/android/app/src/main/res/drawable-xhdpi/uncheck.png differ diff --git a/android/app/src/main/res/drawable-xhdpi/uncheck_box.png b/android/app/src/main/res/drawable-xhdpi/uncheck_box.png new file mode 100644 index 000000000..f79f67fef Binary files /dev/null and b/android/app/src/main/res/drawable-xhdpi/uncheck_box.png differ diff --git a/android/app/src/main/res/drawable-xhdpi/warning.png b/android/app/src/main/res/drawable-xhdpi/warning.png new file mode 100644 index 000000000..5598e44e7 Binary files /dev/null and b/android/app/src/main/res/drawable-xhdpi/warning.png differ diff --git a/android/app/src/main/res/drawable-xhdpi/wifi.png b/android/app/src/main/res/drawable-xhdpi/wifi.png new file mode 100644 index 000000000..20e246036 Binary files /dev/null and b/android/app/src/main/res/drawable-xhdpi/wifi.png differ diff --git a/android/app/src/main/res/drawable-xhdpi/xiaoxia.9.png b/android/app/src/main/res/drawable-xhdpi/xiaoxia.9.png new file mode 100644 index 000000000..d3b3b349a Binary files /dev/null and b/android/app/src/main/res/drawable-xhdpi/xiaoxia.9.png differ diff --git a/android/app/src/main/res/drawable-xhdpi/xiaoxian.9.png b/android/app/src/main/res/drawable-xhdpi/xiaoxian.9.png new file mode 100644 index 000000000..6f4d5e59a Binary files /dev/null and b/android/app/src/main/res/drawable-xhdpi/xiaoxian.9.png differ diff --git a/android/app/src/main/res/drawable-xxhdpi/ic_launcher.png b/android/app/src/main/res/drawable-xxhdpi/ic_launcher.png new file mode 100644 index 000000000..85a608158 Binary files /dev/null and b/android/app/src/main/res/drawable-xxhdpi/ic_launcher.png differ diff --git a/android/app/src/main/res/drawable/tab_bg_selector.xml b/android/app/src/main/res/drawable/tab_bg_selector.xml new file mode 100644 index 000000000..30703b77a --- /dev/null +++ b/android/app/src/main/res/drawable/tab_bg_selector.xml @@ -0,0 +1,15 @@ + + + + + + + + \ No newline at end of file diff --git a/android/app/src/main/res/drawable/tt_bgd_relatly_line.xml b/android/app/src/main/res/drawable/tt_bgd_relatly_line.xml new file mode 100644 index 000000000..d9c028d41 --- /dev/null +++ b/android/app/src/main/res/drawable/tt_bgd_relatly_line.xml @@ -0,0 +1,20 @@ + + + + + + + + + + + + diff --git a/android/app/src/main/res/drawable/tt_bt_nobgd.xml b/android/app/src/main/res/drawable/tt_bt_nobgd.xml new file mode 100644 index 000000000..d960ed5f6 --- /dev/null +++ b/android/app/src/main/res/drawable/tt_bt_nobgd.xml @@ -0,0 +1,38 @@ + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/android/app/src/main/res/drawable/tt_default_emo_dots.xml b/android/app/src/main/res/drawable/tt_default_emo_dots.xml new file mode 100644 index 000000000..36771bffd --- /dev/null +++ b/android/app/src/main/res/drawable/tt_default_emo_dots.xml @@ -0,0 +1,7 @@ + + + + + + + \ No newline at end of file diff --git a/android/app/src/main/res/drawable/tt_dialog_bg.xml b/android/app/src/main/res/drawable/tt_dialog_bg.xml new file mode 100644 index 000000000..fbfeb4689 --- /dev/null +++ b/android/app/src/main/res/drawable/tt_dialog_bg.xml @@ -0,0 +1,8 @@ + + + + + + + + \ No newline at end of file diff --git a/android/app/src/main/res/drawable/tt_dialog_negative_btn_bg.xml b/android/app/src/main/res/drawable/tt_dialog_negative_btn_bg.xml new file mode 100644 index 000000000..3db37ff8e --- /dev/null +++ b/android/app/src/main/res/drawable/tt_dialog_negative_btn_bg.xml @@ -0,0 +1,7 @@ + + + + + + + \ No newline at end of file diff --git a/android/app/src/main/res/drawable/tt_dialog_positive_btn_bg.xml b/android/app/src/main/res/drawable/tt_dialog_positive_btn_bg.xml new file mode 100644 index 000000000..c6b53a7e8 --- /dev/null +++ b/android/app/src/main/res/drawable/tt_dialog_positive_btn_bg.xml @@ -0,0 +1,7 @@ + + + + + + + \ No newline at end of file diff --git a/android/app/src/main/res/drawable/tt_list_item_bk.xml b/android/app/src/main/res/drawable/tt_list_item_bk.xml new file mode 100644 index 000000000..f858e1748 --- /dev/null +++ b/android/app/src/main/res/drawable/tt_list_item_bk.xml @@ -0,0 +1,7 @@ + + + + + + + \ No newline at end of file diff --git a/android/app/src/main/res/drawable/tt_message_cursor.xml b/android/app/src/main/res/drawable/tt_message_cursor.xml new file mode 100644 index 000000000..058d335a7 --- /dev/null +++ b/android/app/src/main/res/drawable/tt_message_cursor.xml @@ -0,0 +1,5 @@ + + + + + diff --git a/android/app/src/main/res/drawable/tt_message_image_border.xml b/android/app/src/main/res/drawable/tt_message_image_border.xml new file mode 100644 index 000000000..c2174b2a6 --- /dev/null +++ b/android/app/src/main/res/drawable/tt_message_image_border.xml @@ -0,0 +1,8 @@ + + + + + + + \ No newline at end of file diff --git a/android/app/src/main/res/drawable/tt_mine_item_bg.xml b/android/app/src/main/res/drawable/tt_mine_item_bg.xml new file mode 100644 index 000000000..765b5a4c5 --- /dev/null +++ b/android/app/src/main/res/drawable/tt_mine_item_bg.xml @@ -0,0 +1,7 @@ + + + + + + + \ No newline at end of file diff --git a/android/app/src/main/res/drawable/tt_other_item_bg.xml b/android/app/src/main/res/drawable/tt_other_item_bg.xml new file mode 100644 index 000000000..585c46a44 --- /dev/null +++ b/android/app/src/main/res/drawable/tt_other_item_bg.xml @@ -0,0 +1,7 @@ + + + + + + + \ No newline at end of file diff --git a/android/app/src/main/res/drawable/tt_panel_circle.xml b/android/app/src/main/res/drawable/tt_panel_circle.xml new file mode 100644 index 000000000..6b63f4c43 --- /dev/null +++ b/android/app/src/main/res/drawable/tt_panel_circle.xml @@ -0,0 +1,7 @@ + + + + + + diff --git a/android/app/src/main/res/drawable/tt_panel_edt_focused.xml b/android/app/src/main/res/drawable/tt_panel_edt_focused.xml new file mode 100644 index 000000000..7d5d4d58f --- /dev/null +++ b/android/app/src/main/res/drawable/tt_panel_edt_focused.xml @@ -0,0 +1,12 @@ + + + + + + + + + + \ No newline at end of file diff --git a/android/app/src/main/res/drawable/tt_panel_edt_msg_bk.xml b/android/app/src/main/res/drawable/tt_panel_edt_msg_bk.xml new file mode 100644 index 000000000..ac2d24101 --- /dev/null +++ b/android/app/src/main/res/drawable/tt_panel_edt_msg_bk.xml @@ -0,0 +1,16 @@ + + + + + + + + \ No newline at end of file diff --git a/android/app/src/main/res/drawable/tt_panel_voice_forward.xml b/android/app/src/main/res/drawable/tt_panel_voice_forward.xml new file mode 100644 index 000000000..890d3403d --- /dev/null +++ b/android/app/src/main/res/drawable/tt_panel_voice_forward.xml @@ -0,0 +1,9 @@ + + + + + + + + + \ No newline at end of file diff --git a/android/app/src/main/res/drawable/tt_pannel_edt_normal.xml b/android/app/src/main/res/drawable/tt_pannel_edt_normal.xml new file mode 100644 index 000000000..d53f0a0d4 --- /dev/null +++ b/android/app/src/main/res/drawable/tt_pannel_edt_normal.xml @@ -0,0 +1,12 @@ + + + + + + + + + + \ No newline at end of file diff --git a/android/app/src/main/res/drawable/tt_pickimage_item_bg.xml b/android/app/src/main/res/drawable/tt_pickimage_item_bg.xml new file mode 100644 index 000000000..98fdfe87e --- /dev/null +++ b/android/app/src/main/res/drawable/tt_pickimage_item_bg.xml @@ -0,0 +1,12 @@ + + + + + + + \ No newline at end of file diff --git a/android/app/src/main/res/drawable/tt_popup_background.xml b/android/app/src/main/res/drawable/tt_popup_background.xml new file mode 100644 index 000000000..b3ea51a83 --- /dev/null +++ b/android/app/src/main/res/drawable/tt_popup_background.xml @@ -0,0 +1,13 @@ + + + + + + + + + + + + \ No newline at end of file diff --git a/android/app/src/main/res/drawable/tt_progressbar.xml b/android/app/src/main/res/drawable/tt_progressbar.xml new file mode 100644 index 000000000..594892767 --- /dev/null +++ b/android/app/src/main/res/drawable/tt_progressbar.xml @@ -0,0 +1,17 @@ + + + + + + + + + + \ No newline at end of file diff --git a/android/app/src/main/res/drawable/tt_search_edt_bk.xml b/android/app/src/main/res/drawable/tt_search_edt_bk.xml new file mode 100644 index 000000000..359ed0f38 --- /dev/null +++ b/android/app/src/main/res/drawable/tt_search_edt_bk.xml @@ -0,0 +1,12 @@ + + + + + + + + + + \ No newline at end of file diff --git a/android/app/src/main/res/drawable/tt_send_voice_btn_bg.xml b/android/app/src/main/res/drawable/tt_send_voice_btn_bg.xml new file mode 100644 index 000000000..b83e04466 --- /dev/null +++ b/android/app/src/main/res/drawable/tt_send_voice_btn_bg.xml @@ -0,0 +1,7 @@ + + + + + + + \ No newline at end of file diff --git a/android/app/src/main/res/drawable/tt_show_emo_btn.xml b/android/app/src/main/res/drawable/tt_show_emo_btn.xml new file mode 100644 index 000000000..31989470e --- /dev/null +++ b/android/app/src/main/res/drawable/tt_show_emo_btn.xml @@ -0,0 +1,7 @@ + + + + + + + \ No newline at end of file diff --git a/android/app/src/main/res/drawable/tt_text_while.xml b/android/app/src/main/res/drawable/tt_text_while.xml new file mode 100644 index 000000000..17d5ed509 --- /dev/null +++ b/android/app/src/main/res/drawable/tt_text_while.xml @@ -0,0 +1,8 @@ + + + + + + + + \ No newline at end of file diff --git a/android/app/src/main/res/layout/activity_preview_message_images.xml b/android/app/src/main/res/layout/activity_preview_message_images.xml new file mode 100644 index 000000000..1e72665ff --- /dev/null +++ b/android/app/src/main/res/layout/activity_preview_message_images.xml @@ -0,0 +1,47 @@ + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/android/app/src/main/res/layout/fragment_message_image.xml b/android/app/src/main/res/layout/fragment_message_image.xml new file mode 100644 index 000000000..45c404e16 --- /dev/null +++ b/android/app/src/main/res/layout/fragment_message_image.xml @@ -0,0 +1,34 @@ + + + + + + + + + + + + + \ No newline at end of file diff --git a/android/app/src/main/res/layout/fragment_preview_message_images.xml b/android/app/src/main/res/layout/fragment_preview_message_images.xml new file mode 100644 index 000000000..1e72665ff --- /dev/null +++ b/android/app/src/main/res/layout/fragment_preview_message_images.xml @@ -0,0 +1,47 @@ + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/android/app/src/main/res/layout/mogujie_notification.xml b/android/app/src/main/res/layout/mogujie_notification.xml new file mode 100644 index 000000000..32c9a13fd --- /dev/null +++ b/android/app/src/main/res/layout/mogujie_notification.xml @@ -0,0 +1,156 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/android/app/src/main/res/layout/tt_activity_base.xml b/android/app/src/main/res/layout/tt_activity_base.xml new file mode 100644 index 000000000..345462d42 --- /dev/null +++ b/android/app/src/main/res/layout/tt_activity_base.xml @@ -0,0 +1,60 @@ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/android/app/src/main/res/layout/tt_activity_detail_portrait.xml b/android/app/src/main/res/layout/tt_activity_detail_portrait.xml new file mode 100644 index 000000000..52f517efb --- /dev/null +++ b/android/app/src/main/res/layout/tt_activity_detail_portrait.xml @@ -0,0 +1,16 @@ + + + + + + \ No newline at end of file diff --git a/android/app/src/main/res/layout/tt_activity_group_member_select.xml b/android/app/src/main/res/layout/tt_activity_group_member_select.xml new file mode 100644 index 000000000..8b42f51a9 --- /dev/null +++ b/android/app/src/main/res/layout/tt_activity_group_member_select.xml @@ -0,0 +1,13 @@ + + + + + + + \ No newline at end of file diff --git a/android/app/src/main/res/layout/tt_activity_groupmanage.xml b/android/app/src/main/res/layout/tt_activity_groupmanage.xml new file mode 100644 index 000000000..cff26c7c4 --- /dev/null +++ b/android/app/src/main/res/layout/tt_activity_groupmanage.xml @@ -0,0 +1,14 @@ + + + + + + + \ No newline at end of file diff --git a/android/app/src/main/res/layout/tt_activity_image_grid.xml b/android/app/src/main/res/layout/tt_activity_image_grid.xml new file mode 100644 index 000000000..9ba4eb1d0 --- /dev/null +++ b/android/app/src/main/res/layout/tt_activity_image_grid.xml @@ -0,0 +1,111 @@ + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/android/app/src/main/res/layout/tt_activity_login.xml b/android/app/src/main/res/layout/tt_activity_login.xml new file mode 100644 index 000000000..f87251680 --- /dev/null +++ b/android/app/src/main/res/layout/tt_activity_login.xml @@ -0,0 +1,156 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/ios/IOSDuoduo/VC/MainViewControll.h b/ios/IOSDuoduo/VC/MainViewControll.h new file mode 100644 index 000000000..8becd9973 --- /dev/null +++ b/ios/IOSDuoduo/VC/MainViewControll.h @@ -0,0 +1,15 @@ +// +// MainViewControll.h +// IOSDuoduo +// +// Created by Michael Scofield on 2014-07-15. +// Copyright (c) 2014 dujia. All rights reserved. +// + +#import +#import "ContactsViewController.h" +@interface MainViewControll : UITabBarController +@property(strong)UINavigationController *nv1; +@property(strong)ContactsViewController *contacts; +-(void)setselectIndex:(int)index; +@end diff --git a/ios/IOSDuoduo/VC/MainViewControll.m b/ios/IOSDuoduo/VC/MainViewControll.m new file mode 100644 index 000000000..55b2455c9 --- /dev/null +++ b/ios/IOSDuoduo/VC/MainViewControll.m @@ -0,0 +1,119 @@ +// +// MainViewControll.m +// IOSDuoduo +// +// Created by Michael Scofield on 2014-07-15. +// Copyright (c) 2014 dujia. All rights reserved. +// + +#import "MainViewControll.h" +#import "RecentUsersViewController.h" +#import "ContactsViewController.h" +#import "MyProfileViewControll.h" +#import "DDClientStateMaintenanceManager.h" +#import "DDGroupModule.h" +#import "FinderViewController.h" +#import "LoginViewController.h" +#import "std.h" +#import "SessionEntity.h" +//#import "UIFont+SytemFontOverride.h" +@interface MainViewControll () +@property(strong) UINavigationController *nv2; +@property(assign) NSUInteger clickCount; +@end + +@implementation MainViewControll + +- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil +{ + self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil]; + if (self) { + // Custom initialization + } + return self; +} + +- (void)viewDidLoad +{ + [super viewDidLoad]; + + self.nv1= [[UINavigationController alloc] initWithRootViewController:[RecentUsersViewController shareInstance]]; + + + UIImage* conversationSelected = [[UIImage imageNamed:@"conversation_selected"] imageWithRenderingMode:UIImageRenderingModeAlwaysOriginal]; + + self.nv1.tabBarItem = [[UITabBarItem alloc]initWithTitle:@"消息" image:[UIImage imageNamed:@"conversation"] selectedImage:conversationSelected]; + self.nv1.tabBarItem.tag=0;//26 140 242 + [self.nv1.tabBarItem setTitleTextAttributes:[NSDictionary dictionaryWithObject:RGB(26, 140, 242) forKey:UITextAttributeTextColor] forState:UIControlStateSelected]; + + UIImage* contactSelected = [[UIImage imageNamed:@"contact_selected"] imageWithRenderingMode:UIImageRenderingModeAlwaysOriginal]; + + UINavigationController *nv2= [[UINavigationController alloc] initWithRootViewController:[ContactsViewController new]]; + nv2.tabBarItem = [[UITabBarItem alloc]initWithTitle:@"通讯录" image:[UIImage imageNamed:@"contact"] selectedImage:contactSelected]; + nv2.tabBarItem.tag=1; + [nv2.tabBarItem setTitleTextAttributes:[NSDictionary dictionaryWithObject:RGB(26, 140, 242) forKey:UITextAttributeTextColor] forState:UIControlStateSelected]; + + UIImage* findSelected = [[UIImage imageNamed:@"tab_nav_selected"] imageWithRenderingMode:UIImageRenderingModeAlwaysOriginal]; + + UINavigationController* nv3 = [[UINavigationController alloc] initWithRootViewController:[[FinderViewController alloc] init]]; + nv3.tabBarItem = [[UITabBarItem alloc] initWithTitle:@"发现" image:[UIImage imageNamed:@"tab_nav"] selectedImage:findSelected]; + nv3.tabBarItem.tag = 2; + [nv3.tabBarItem setTitleTextAttributes:[NSDictionary dictionaryWithObject:RGB(26, 140, 242) forKey:UITextAttributeTextColor] forState:UIControlStateSelected]; + + + UIImage* myProfileSelected = [[UIImage imageNamed:@"myprofile_selected"] imageWithRenderingMode:UIImageRenderingModeAlwaysOriginal]; + UINavigationController *nv4= [[UINavigationController alloc] initWithRootViewController:[MyProfileViewControll new]]; + nv4.tabBarItem = [[UITabBarItem alloc]initWithTitle:@"我的" image:[UIImage imageNamed:@"myprofile"] selectedImage:myProfileSelected]; + nv4.tabBarItem.tag=3; + + [nv4.tabBarItem setTitleTextAttributes:[NSDictionary dictionaryWithObject:RGB(26, 140, 242) forKey:UITextAttributeTextColor] forState:UIControlStateSelected]; + + self.viewControllers=@[self.nv1,nv2,nv3,nv4]; + self.delegate=self; + self.title=@"TeamTalk"; + self.tabBar.translucent = YES; + // [[UIApplication sharedApplication] setStatusBarStyle:UIStatusBarStyleDefault]; + +// [[UINavigationBar appearance] setBarTintColor:[UIColor yellowColor]]; + + // Do any additional setup after loading the view from its nib. + + // 设置字体 Hiragino Mincho ProN Hiragino Kaku Gothic ProN HiraKakuProN-W3 +// [[UILabel appearance] setFont:[UIFont fontWithName:@"FZLanTingHei-L-GBK" size:10.0]]; +// [self setFontFamily:@"FZLanTingHei-L-GBK" forView:self.view andSubViews:YES]; + +// +} + + +- (void)didReceiveMemoryWarning +{ + [super didReceiveMemoryWarning]; + // Dispose of any resources that can be recreated. +} + +- (void)tabBar:(UITabBar *)tabBar didSelectItem:(UITabBarItem *)item +{ + if ([self.nv1.tabBarItem isEqual:item]) + { + self.clickCount=self.clickCount+1; + if (self.clickCount==2) { + if ([[[RecentUsersViewController shareInstance].tableView visibleCells] count] > 0) + { + [[RecentUsersViewController shareInstance].items enumerateObjectsUsingBlock:^(SessionEntity *obj, NSUInteger idx, BOOL *stop) { + if (obj.unReadMsgCount) { + [[RecentUsersViewController shareInstance].tableView scrollToRowAtIndexPath:[NSIndexPath indexPathForRow:idx inSection:0] atScrollPosition:UITableViewScrollPositionTop animated:YES]; + return ; + } + }]; + + } + self.clickCount=0; + } + + }else{ + self.clickCount=0; + } +} + +@end diff --git a/ios/IOSDuoduo/VC/MainViewControll.xib b/ios/IOSDuoduo/VC/MainViewControll.xib new file mode 100644 index 000000000..4bb7a068a --- /dev/null +++ b/ios/IOSDuoduo/VC/MainViewControll.xib @@ -0,0 +1,24 @@ + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/ios/IOSDuoduo/VC/MyProfileViewControll.h b/ios/IOSDuoduo/VC/MyProfileViewControll.h new file mode 100644 index 000000000..b07dd20e3 --- /dev/null +++ b/ios/IOSDuoduo/VC/MyProfileViewControll.h @@ -0,0 +1,24 @@ +// +// MyProfileViewControll.h +// IOSDuoduo +// +// Created by Michael Scofield on 2014-07-15. +// Copyright (c) 2014 dujia. All rights reserved. +// + +#import +@class DDUserEntity; +@interface MyProfileViewControll : UIViewController + @property(strong)IBOutlet UIView *profileView; +@property(weak)IBOutlet UILabel *nickName; +@property(weak)IBOutlet UILabel *realName; +@property(weak)IBOutlet UIImageView *avatar; +@property(weak)IBOutlet UIView *view1; +@property(weak)IBOutlet UIView *view2; +@property(weak)IBOutlet UITableView *tableView; +@property(weak)IBOutlet UILabel *versionLabel; +@property(weak)DDUserEntity *user; +-(IBAction)goPersonalProfile; +-(IBAction)clearCache:(id)sender; +-(IBAction)logout:(id)sender; +@end diff --git a/ios/IOSDuoduo/VC/MyProfileViewControll.m b/ios/IOSDuoduo/VC/MyProfileViewControll.m new file mode 100644 index 000000000..88fbf3b12 --- /dev/null +++ b/ios/IOSDuoduo/VC/MyProfileViewControll.m @@ -0,0 +1,165 @@ +// +// MyProfileViewControll.m +// IOSDuoduo +// +// Created by Michael Scofield on 2014-07-15. +// Copyright (c) 2014 dujia. All rights reserved. +// + +#import "MyProfileViewControll.h" +#import "PublicProfileViewControll.h" +#import "RuntimeStatus.h" +#import "UIImageView+WebCache.h" +#import "DDUserDetailInfoAPI.h" +#import "PhotosCache.h" +#import "LogoutAPI.h" +#import "LoginViewController.h" +#import "DDClientState.h" +#import "DDUserModule.h" +#import "DDDatabaseUtil.h" +#import "NSString+Additions.h" +@interface MyProfileViewControll () + +@end + +@implementation MyProfileViewControll + +- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil +{ + self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil]; + if (self) { + // Custom initialization + } + return self; +} + +- (void)viewDidLoad +{ + [super viewDidLoad]; + self.title=@"我"; + self.profileView.userInteractionEnabled=true; + UITapGestureRecognizer *singleTap = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(goPersonalProfile)]; + [self.profileView addGestureRecognizer:singleTap]; + UIImage* placeholder = [UIImage imageNamed:@"user_placeholder"]; + [self.avatar sd_setImageWithURL:[NSURL URLWithString:[[RuntimeStatus instance].user getAvatarUrl]] placeholderImage:placeholder]; + [[DDUserModule shareInstance] getUserForUserID:[RuntimeStatus instance].user.objID Block:^(DDUserEntity *user) { + self.user=user; + self.realName.text=user.name; + self.nickName.text=user.nick; + }]; + + // 头像圆角 + [_avatar.layer setMasksToBounds:YES]; + [_avatar.layer setCornerRadius:4]; + [self.view1 setBackgroundColor:RGB(236, 236, 236)]; + [self.view setBackgroundColor:[UIColor whiteColor]]; + + [self.versionLabel setText:[NSString formatCurDayForVersion]]; + // Do any additional setup after loading the view from its nib. +} +- (void)viewWillAppear:(BOOL)animated +{ + [super viewWillAppear:animated]; + [self.tabBarController.tabBar setHidden:NO]; + +} + +- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section{ + return 2; +} + +// Row display. Implementers should *always* try to reuse cells by setting each cell's reuseIdentifier and querying for available reusable cells with dequeueReusableCellWithIdentifier: +// Cell gets various attributes set automatically based on table (separators) and data source (accessory views, editing controls) + +- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath +{ + static NSString* identifier = @"MyProfileCellIdentifier"; + UITableViewCell* cell = [tableView dequeueReusableCellWithIdentifier:identifier]; + if (!cell) + { + cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleValue1 reuseIdentifier:identifier]; + } + cell.selectedBackgroundView = [[UIView alloc] initWithFrame:cell.frame]; + cell.selectedBackgroundView.backgroundColor = RGB(244, 245, 246); + NSInteger row = [indexPath row]; + if (row == 0) + { + [cell.textLabel setText:@"清理缓存图片"]; + + } + else if (row == 1) + { + [cell.textLabel setText:@"退出"]; + + } + [cell setAccessoryType:UITableViewCellAccessoryDisclosureIndicator]; + return cell; +} +-(void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath +{ + [tableView deselectRowAtIndexPath:indexPath animated:YES]; + if (indexPath.row==0) { + [self clearCache:nil]; + }else{ + [self logout:nil]; + } +} +-(IBAction)clearCache:(id)sender +{ + __block SCLAlertView *alert = [SCLAlertView new]; + [alert addButton:@"确定" actionBlock:^{ + SCLAlertView *cleaning = [SCLAlertView new]; + [cleaning showWaiting:self title:nil subTitle:@"正在清理" closeButtonTitle:nil duration:0]; + [[PhotosCache sharedPhotoCache] clearAllCache:^(bool isfinish) { + if (isfinish) { + [cleaning hideView]; + SCLAlertView *notice = [SCLAlertView new]; + [notice showSuccess:self title:nil subTitle:@"清理完成" closeButtonTitle:nil duration:2.0]; + } + }]; + + + }]; + [alert showNotice:self title:@"提示" subTitle:@"是否清理图片缓存" closeButtonTitle:@"取消" duration:0]; + +} + + +-(IBAction)logout:(id)sender +{ + + SCLAlertView *alert = [SCLAlertView new]; + [alert addButton:@"确定" actionBlock:^{ + LogoutAPI *logout = [LogoutAPI new]; + [logout requestWithObject:nil Completion:^(id response, NSError *error) { + + }]; + [DDNotificationHelp postNotification:DDNotificationLogout userInfo:nil object:nil]; + LoginViewController *login = [LoginViewController new]; + login.isRelogin=YES; + [self presentViewController:login animated:YES completion:^{ + TheRuntime.user =nil; + TheRuntime.userID =nil; + [DDClientState shareInstance].userState = DDUserOffLineInitiative; + [[DDTcpClientManager instance] disconnect]; + [[NSUserDefaults standardUserDefaults] setBool:NO forKey:@"autologin"]; + }]; + + }]; + [alert showNotice:self title:@"提示" subTitle:@"是否确认退出?" closeButtonTitle:@"取消" duration:0]; +} + +- (void)didReceiveMemoryWarning +{ + [super didReceiveMemoryWarning]; + // Dispose of any resources that can be recreated. +} + +-(IBAction)goPersonalProfile +{ + PublicProfileViewControll *public = [PublicProfileViewControll new] ; + public.user = self.user; + [self.navigationController pushViewController:public animated:YES]; +} + +@end diff --git a/ios/IOSDuoduo/VC/MyProfileViewControll.xib b/ios/IOSDuoduo/VC/MyProfileViewControll.xib new file mode 100644 index 000000000..d58e64913 --- /dev/null +++ b/ios/IOSDuoduo/VC/MyProfileViewControll.xib @@ -0,0 +1,75 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/ios/IOSDuoduo/VC/NetwrokStatusNotifyUI.h b/ios/IOSDuoduo/VC/NetwrokStatusNotifyUI.h new file mode 100644 index 000000000..d5f6541cc --- /dev/null +++ b/ios/IOSDuoduo/VC/NetwrokStatusNotifyUI.h @@ -0,0 +1,13 @@ +// +// NetwrokStatusNotifyUI.h +// TeamTalk +// +// Created by Michael Scofield on 2014-10-13. +// Copyright (c) 2014 dujia. All rights reserved. +// + +#import +@interface NetwrokStatusNotifyUI : UIView ++ (void)showErrorWithStatus:(NSString*)status; ++ (void)dismiss; +@end diff --git a/ios/IOSDuoduo/VC/NetwrokStatusNotifyUI.m b/ios/IOSDuoduo/VC/NetwrokStatusNotifyUI.m new file mode 100644 index 000000000..918aa2523 --- /dev/null +++ b/ios/IOSDuoduo/VC/NetwrokStatusNotifyUI.m @@ -0,0 +1,126 @@ +// +// NetwrokStatusNotifyUI.m +// TeamTalk +// +// Created by Michael Scofield on 2014-10-13. +// Copyright (c) 2014 dujia. All rights reserved. +// + +#import "NetwrokStatusNotifyUI.h" +#import "std.h" +@interface NetwrokStatusNotifyUI() +@property (nonatomic, strong,readonly) UIWindow *overlayWindow; +@property (nonatomic, strong,readonly) UIView *topBar; +@property (nonatomic, strong) UILabel *stringLabel; +@end +@implementation NetwrokStatusNotifyUI +@synthesize topBar, overlayWindow, stringLabel; + ++ (NetwrokStatusNotifyUI*)sharedView { + static dispatch_once_t once; + static NetwrokStatusNotifyUI *sharedView; + dispatch_once(&once, ^ { sharedView = [[NetwrokStatusNotifyUI alloc] initWithFrame:[[UIScreen mainScreen] bounds]]; }); + return sharedView; +} + ++ (void)showErrorWithStatus:(NSString*)status { + [[NetwrokStatusNotifyUI sharedView] showWithStatus:status barColor:[UIColor blackColor] textColor:[UIColor whiteColor]]; + [NetwrokStatusNotifyUI performSelector:@selector(dismiss) withObject:self afterDelay:2.0 ]; +} + ++ (void)dismiss { + [[NetwrokStatusNotifyUI sharedView] dismiss]; +} + +- (id)initWithFrame:(CGRect)frame { + + if ((self = [super initWithFrame:frame])) { + self.userInteractionEnabled = NO; + self.backgroundColor = [UIColor clearColor]; + self.alpha = 0; + self.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight; + } + return self; +} + +- (void)showWithStatus:(NSString *)status barColor:(UIColor*)barColor textColor:(UIColor*)textColor{ + if(!self.superview) + [self.overlayWindow addSubview:self]; + [self.overlayWindow setHidden:NO]; + [self.topBar setHidden:NO]; + self.topBar.backgroundColor = barColor; + NSString *labelText = status; + CGRect labelRect = CGRectZero; + CGFloat stringWidth = 0; + CGFloat stringHeight = 0; + if(labelText) { + CGSize stringSize = [labelText sizeWithFont:self.stringLabel.font constrainedToSize:CGSizeMake(self.topBar.frame.size.width, self.topBar.frame.size.height)]; + stringWidth = stringSize.width; + stringHeight = stringSize.height; + labelRect = CGRectMake((self.topBar.frame.size.width / 2) - (stringWidth / 2), 0, stringWidth, stringHeight); + } + self.stringLabel.frame = labelRect; + self.stringLabel.alpha = 0.0; + self.stringLabel.hidden = NO; + self.stringLabel.text = labelText; + self.stringLabel.textColor = textColor; + [UIView animateWithDuration:0.4 animations:^{ + self.stringLabel.alpha = 1.0; + }]; + [self setNeedsDisplay]; +} + +- (void) dismiss +{ + [UIView animateWithDuration:0.4 animations:^{ + self.stringLabel.alpha = 0.0; + } completion:^(BOOL finished) { + [topBar removeFromSuperview]; + topBar = nil; + + [overlayWindow removeFromSuperview]; + overlayWindow = nil; + }]; +} + +- (UIWindow *)overlayWindow { + if(!overlayWindow) { + overlayWindow = [[UIWindow alloc] initWithFrame:[UIScreen mainScreen].bounds]; + overlayWindow.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight; + overlayWindow.backgroundColor = [UIColor clearColor]; + overlayWindow.userInteractionEnabled = NO; + overlayWindow.windowLevel = UIWindowLevelStatusBar; + } + return overlayWindow; +} + +- (UIView *)topBar { + if(!topBar) { + topBar = [[UIView alloc] initWithFrame:CGRectMake(0, 20, overlayWindow.frame.size.width, 20.0)]; + [overlayWindow addSubview:topBar]; + } + return topBar; +} + +- (UILabel *)stringLabel { + if (stringLabel == nil) { + stringLabel = [[UILabel alloc] initWithFrame:CGRectZero]; + stringLabel.textColor = [UIColor colorWithRed:191.0/255.0 green:191.0/255.0 blue:191.0/255.0 alpha:1.0]; + stringLabel.backgroundColor = [UIColor clearColor]; + stringLabel.adjustsFontSizeToFitWidth = YES; + stringLabel.textAlignment = NSTextAlignmentCenter; + stringLabel.baselineAdjustment = UIBaselineAdjustmentAlignCenters; + stringLabel.font = [UIFont boldSystemFontOfSize:14.0]; + stringLabel.shadowColor = [UIColor blackColor]; + stringLabel.shadowOffset = CGSizeMake(0, -1); + stringLabel.numberOfLines = 0; + } + + // if(!stringLabel.superview) + [self.topBar addSubview:stringLabel]; + + return stringLabel; +} + +@end + diff --git a/ios/IOSDuoduo/VC/OpenSourcePRViewController.h b/ios/IOSDuoduo/VC/OpenSourcePRViewController.h new file mode 100644 index 000000000..f7af138b8 --- /dev/null +++ b/ios/IOSDuoduo/VC/OpenSourcePRViewController.h @@ -0,0 +1,13 @@ +// +// OpenSourcePRViewController.h +// TeamTalk +// +// Created by 独嘉 on 14-10-22. +// Copyright (c) 2014年 dujia. All rights reserved. +// + +#import + +@interface OpenSourcePRViewController : UIViewController +@property(copy)NSString *urlString; +@end diff --git a/ios/IOSDuoduo/VC/OpenSourcePRViewController.m b/ios/IOSDuoduo/VC/OpenSourcePRViewController.m new file mode 100644 index 000000000..5e97bb2d3 --- /dev/null +++ b/ios/IOSDuoduo/VC/OpenSourcePRViewController.m @@ -0,0 +1,63 @@ +// +// OpenSourcePRViewController.m +// TeamTalk +// +// Created by 独嘉 on 14-10-22. +// Copyright (c) 2014年 dujia. All rights reserved. +// + +#import "OpenSourcePRViewController.h" + +@interface OpenSourcePRViewController () + +@end + +@implementation OpenSourcePRViewController +{ + UIWebView* _webView; + UIActivityIndicatorView* _activityIndicatorView; +} +- (void)viewDidLoad { + [super viewDidLoad]; + _webView = [[UIWebView alloc] initWithFrame:self.view.frame]; + + [_webView setClipsToBounds:YES]; + [self.view addSubview:_webView]; + NSURL* url = [NSURL URLWithString:self.urlString]; + NSURLRequest* urlRequest = [NSURLRequest requestWithURL:url]; + [_webView loadRequest:urlRequest]; + [_webView setDelegate:self]; + _activityIndicatorView = [[UIActivityIndicatorView alloc] initWithActivityIndicatorStyle:UIActivityIndicatorViewStyleGray]; + [_activityIndicatorView setCenter:_webView.center]; + [_activityIndicatorView setHidesWhenStopped:YES]; + [_activityIndicatorView startAnimating]; + [self.view addSubview:_activityIndicatorView]; + _webView.backgroundColor=[UIColor clearColor]; + for (UIView *_aView in [_webView subviews]) + { + if ([_aView isKindOfClass:[UIScrollView class]]) + { + [(UIScrollView *)_aView setShowsHorizontalScrollIndicator:NO]; //右侧的滚动条 + } + } +} +-(void)viewWillAppear:(BOOL)animated +{ + [super viewWillAppear:animated]; + [self.tabBarController.tabBar setHidden:YES]; +} +-(void)viewWillDisappear:(BOOL)animated +{ + [super viewWillDisappear:animated]; + [self.tabBarController.tabBar setHidden:NO]; +} +- (void)didReceiveMemoryWarning { + [super didReceiveMemoryWarning]; + // Dispose of any resources that can be recreated. +} + +- (void)webViewDidFinishLoad:(UIWebView *)webView +{ + [_activityIndicatorView stopAnimating]; +} +@end diff --git a/ios/IOSDuoduo/VC/Photo.h b/ios/IOSDuoduo/VC/Photo.h new file mode 100644 index 000000000..fdda92e69 --- /dev/null +++ b/ios/IOSDuoduo/VC/Photo.h @@ -0,0 +1,16 @@ +// +// DDPhoto.h +// IOSDuoduo +// +// Created by 东邪 on 14-6-6. +// Copyright (c) 2014年 dujia. All rights reserved. +// + +#import + +@interface Photo : NSObject +@property(nonatomic,strong)NSString *localPath; +@property(nonatomic,strong)NSString *resultUrl; +@property(nonatomic,assign)CGImageRef imageRef; +@property(nonatomic,strong)UIImage* image; +@end diff --git a/ios/IOSDuoduo/VC/Photo.m b/ios/IOSDuoduo/VC/Photo.m new file mode 100644 index 000000000..6afc3e9e9 --- /dev/null +++ b/ios/IOSDuoduo/VC/Photo.m @@ -0,0 +1,30 @@ +// +// DDPhoto.m +// IOSDuoduo +// +// Created by 东邪 on 14-6-6. +// Copyright (c) 2014年 dujia. All rights reserved. +// + +#import "Photo.h" + +@implementation Photo +- (instancetype)init +{ + self = [super init]; + if (self) { + self.localPath=nil; + self.resultUrl=nil; + self.imageRef = nil; + self.image= nil; + } + return self; +} +- (void)dealloc +{ + self.localPath=nil; + self.resultUrl=nil; + CGImageRelease(self.imageRef); + self.image= nil; +} +@end diff --git a/ios/IOSDuoduo/VC/PhotosCache.h b/ios/IOSDuoduo/VC/PhotosCache.h new file mode 100644 index 000000000..4067a563d --- /dev/null +++ b/ios/IOSDuoduo/VC/PhotosCache.h @@ -0,0 +1,25 @@ +// +// DDPhotosCache.h +// IOSDuoduo +// +// Created by 东邪 on 14-5-29. +// Copyright (c) 2014年 dujia. All rights reserved. +// + +#import +typedef void(^cacheblock)(BOOL isFinished); +@interface PhotosCache : NSObject ++(void)calculatePhotoSizeWithCompletionBlock:(void (^)(NSUInteger fileCount, NSUInteger totalSize))completionBlock; ++ (PhotosCache *)sharedPhotoCache; +- (void)storePhoto:(NSData *)photos forKey:(NSString *)key toDisk:(BOOL)toDisk ; +- (NSData *)photoFromDiskCacheForKey:(NSString *)key; +- (void)removePhotoForKey:(NSString *)key; +- (NSString *)defaultCachePathForKey:(NSString *)key; +- (NSUInteger)getSize; +- (int)getDiskCount; +- (void)removePhotoFromNSCacheForKey:(NSString *)key; +- (NSOperation *)queryDiskCacheForKey:(NSString *)key done:(void (^)(NSData *voice))doneBlock; +-(NSString *)getKeyName; +-(void)clearAllCache:(void(^)(bool isfinish))block;; +-(NSMutableArray *)getAllImageCache; +@end diff --git a/ios/IOSDuoduo/VC/PhotosCache.m b/ios/IOSDuoduo/VC/PhotosCache.m new file mode 100644 index 000000000..6e7ae1b7e --- /dev/null +++ b/ios/IOSDuoduo/VC/PhotosCache.m @@ -0,0 +1,261 @@ +// +// DDCacheManager.m +// IOSDuoduo +// +// Created by 东邪 on 14-5-29. +// Copyright (c) 2014年 dujia. All rights reserved. +// + +#import "PhotosCache.h" +#import "SDImageCache.h" +#import "std.h" +#import "NSString+Additions.h" +#import +#import "DDSundriesCenter.h" + +@interface PhotosCache() +@property (readonly, nonatomic) dispatch_queue_t ioQueue; +@property(nonatomic,retain) NSFileManager *fileManager; +@property (retain, nonatomic) NSCache *memCache; +@end +@implementation PhotosCache + + ++(void)calculatePhotoSizeWithCompletionBlock:(void (^)(NSUInteger fileCount, NSUInteger totalSize))completionBlock +{ + NSURL *diskCacheURL = [NSURL fileURLWithPath:PhotosMessageDir isDirectory:YES]; + [ [DDSundriesCenter instance] pushTaskToSerialQueue:^{ + NSUInteger fileCount = 0; + NSUInteger totalSize = 0; + NSFileManager *fileManager = [[NSFileManager alloc] init]; + NSDirectoryEnumerator *fileEnumerator = [fileManager enumeratorAtURL:diskCacheURL + includingPropertiesForKeys:@[NSFileSize] + options:NSDirectoryEnumerationSkipsHiddenFiles + errorHandler:NULL]; + + for (NSURL *fileURL in fileEnumerator) { + NSNumber *fileSize; + [fileURL getResourceValue:&fileSize forKey:NSURLFileSizeKey error:NULL]; + totalSize += [fileSize unsignedIntegerValue]; + fileCount += 1; + } + + if (completionBlock) { + dispatch_async(dispatch_get_main_queue(), ^{ + completionBlock(fileCount, totalSize); + }); + } + }]; + +} +-(NSData *)photoFromDiskCacheForKey:(NSString *)key +{ + NSData *photoData = [self photoFromMemoryCacheForKey:key]; + if (photoData) { + return photoData; + } + // Second check the disk cache... + NSData *diskphotoData = [self diskPhotoForKey:key]; + if (diskphotoData) { + [self.memCache setObject:diskphotoData forKey:key ]; + } + return diskphotoData; +} ++ (PhotosCache *)sharedPhotoCache +{ + static dispatch_once_t once; + static id instance; + dispatch_once(&once, ^{ + instance = [self new]; + + }); + return instance; +} +- (instancetype)init +{ + self = [super init]; + if (self) { + _ioQueue = dispatch_queue_create("com.mogujie.DDPhotosCache", DISPATCH_QUEUE_SERIAL); + _memCache = [NSCache new]; + + dispatch_sync(_ioQueue, ^{ + _fileManager = [NSFileManager new]; + }); + + } + return self; +} +- (void)storePhoto:(NSData *)data forKey:(NSString *)key +{ + [self storePhoto:data forKey:key toDisk:YES]; +} + +- (void)removePhotoForKey:(NSString *)key +{ + [self.memCache removeObjectForKey:key]; + + dispatch_async(self.ioQueue, ^{ + [_fileManager removeItemAtPath:[self defaultCachePathForKey:key] error:nil]; + }); + + +} +- (void)removePhotoFromNSCacheForKey:(NSString *)key +{ + [self.memCache removeObjectForKey:key]; + +} +- (NSUInteger)getSize { + __block NSUInteger size = 0; + dispatch_sync(self.ioQueue, ^{ + NSDirectoryEnumerator *fileEnumerator = [_fileManager enumeratorAtPath:PhotosMessageDir]; + for (NSString *fileName in fileEnumerator) { + NSString *filePath = [PhotosMessageDir stringByAppendingPathComponent:fileName]; + NSDictionary *attrs = [[NSFileManager defaultManager] attributesOfItemAtPath:filePath error:nil]; + size += [attrs fileSize]; + } + }); + return size; +} +- (int)getDiskCount { + __block int count = 0; + dispatch_sync(self.ioQueue, ^{ + NSDirectoryEnumerator *fileEnumerator = [_fileManager enumeratorAtPath:PhotosMessageDir]; + for (__unused NSString *fileName in fileEnumerator) { + count += 1; + } + }); + return count; +} +- (void)storePhoto:(NSData *)photo forKey:(NSString *)key toDisk:(BOOL)toDisk { + if (!photo || !key) { + return; + } + [self.memCache setObject:photo forKey:key ]; + + if (toDisk) { + dispatch_async(self.ioQueue, ^{ + if (photo) { + if (![_fileManager fileExistsAtPath:PhotosMessageDir]) { + [_fileManager createDirectoryAtPath:PhotosMessageDir withIntermediateDirectories:YES attributes:nil error:NULL]; + } + + [_fileManager createFileAtPath:[self defaultCachePathForKey:key] contents:photo attributes:nil]; + } + }); + } +} +- (NSString *)cachePathForKey:(NSString *)key inPath:(NSString *)path { + NSString *filename = [self cachedFileNameForKey:key]; + return [path stringByAppendingPathComponent:filename]; +} + +- (NSString *)defaultCachePathForKey:(NSString *)key { + return [self cachePathForKey:key inPath:PhotosMessageDir]; +} + +- (NSString *)cachedFileNameForKey:(NSString *)key { + const char *str = [key UTF8String]; + if (str == NULL) { + str = ""; + } + unsigned char r[CC_MD5_DIGEST_LENGTH]; + CC_MD5(str, (CC_LONG)strlen(str), r); + NSString *filename = [NSString stringWithFormat:@"%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x", + r[0], r[1], r[2], r[3], r[4], r[5], r[6], r[7], r[8], r[9], r[10], r[11], r[12], r[13], r[14], r[15]]; + + return filename; +} +- (NSOperation *)queryDiskCacheForKey:(NSString *)key done:(void (^)(NSData *photo))doneBlock { + NSOperation *operation = [NSOperation new]; + + if (!doneBlock) return nil; + + if (!key) { + doneBlock(nil); + return nil; + } + + // First check the in-memory cache... + NSData *photo = [self photoFromMemoryCacheForKey:key]; + if (photo) { + doneBlock(photo); + return nil; + } + + dispatch_async(self.ioQueue, ^{ + if (operation.isCancelled) { + return; + } + + @autoreleasepool { + NSData *diskPhotos = [self diskPhotoForKey:key]; + if (diskPhotos) { + + [self.memCache setObject:diskPhotos forKey:key]; + } + + dispatch_async(dispatch_get_main_queue(), ^{ + doneBlock(diskPhotos); + }); + } + }); + + return operation; +} +- (NSData *)photoFromMemoryCacheForKey:(NSString *)key { + return [self.memCache objectForKey:key]; +} +- (NSData *)diskPhotoForKey:(NSString *)key { + NSData *data = [self diskPhotosDataBySearchingAllPathsForKey:key]; + if (data) { + return data; + } + else { + return nil; + } +} +- (NSData *)diskPhotosDataBySearchingAllPathsForKey:(NSString *)key { + NSString *defaultPath = [self defaultCachePathForKey:key]; + NSData *data = [NSData dataWithContentsOfFile:defaultPath]; + if (data) { + return data; + } + return nil; +} +-(NSString *)getKeyName +{ + NSDateFormatter * formatter = [[NSDateFormatter alloc ] init]; + [formatter setDateFormat:@"YYYYMMddhhmmssSSS"]; + NSString *date = [formatter stringFromDate:[NSDate date]]; + NSString *timeLocal = [[NSString alloc] initWithFormat:@"%@", date]; + return [NSString stringWithFormat:@"%@_send",timeLocal]; +} +-(NSMutableArray *)getAllImageCache +{ + __block NSMutableArray *array = [NSMutableArray new]; + dispatch_sync(self.ioQueue, ^{ + NSDirectoryEnumerator *fileEnumerator = [_fileManager enumeratorAtPath:PhotosMessageDir]; + for (__unused NSString *fileName in fileEnumerator) { + + [array addObject:[NSString stringWithFormat:@"%@/%@",PhotosMessageDir,fileName]]; + + } + }); + return array; +} +-(void)clearAllCache:(void(^)(bool isfinish))block; +{ + [self.memCache removeAllObjects]; + NSArray *allimage = [self getAllImageCache]; + if( [allimage count] == 0 ) + block(YES); + [allimage enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) { + NSString *path = (NSString *)obj; + [_fileManager removeItemAtPath:path error:nil]; + if (idx == [allimage count]-1 ) { + block(YES); + } + }]; +} +@end diff --git a/ios/IOSDuoduo/VC/PublicProfileCell.h b/ios/IOSDuoduo/VC/PublicProfileCell.h new file mode 100644 index 000000000..97dc6c053 --- /dev/null +++ b/ios/IOSDuoduo/VC/PublicProfileCell.h @@ -0,0 +1,20 @@ +// +// PublicProfileCell.h +// TeamTalk +// +// Created by scorpio on 14/12/18. +// Copyright (c) 2014年 dujia. All rights reserved. +// + +#import + +@interface PublicProfileCell : UITableViewCell + +@property (nonatomic,retain)UILabel* descLabel; +@property (nonatomic,retain)UILabel* detailLabel; +@property (nonatomic,retain)UIImageView* phone; + +- (void)setDesc:(NSString *)desc detail:(NSString *)detail; +- (void)hidePhone:(BOOL)hide; + +@end diff --git a/ios/IOSDuoduo/VC/PublicProfileCell.m b/ios/IOSDuoduo/VC/PublicProfileCell.m new file mode 100644 index 000000000..185aace2c --- /dev/null +++ b/ios/IOSDuoduo/VC/PublicProfileCell.m @@ -0,0 +1,55 @@ +// +// PublicProfileCell.m +// TeamTalk +// +// Created by scorpio on 14/12/18. +// Copyright (c) 2014年 dujia. All rights reserved. +// + +#import "PublicProfileCell.h" +#import "std.h" + +@implementation PublicProfileCell + +-(instancetype)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier +{ + self = [super initWithStyle:style reuseIdentifier:reuseIdentifier]; + if (self) { + _descLabel = [[UILabel alloc]initWithFrame:CGRectMake(20, 15, 30, 15)]; + [_descLabel setFont:systemFont(15)]; + [_descLabel setTextColor:RGB(164, 165, 169)]; + [self.contentView addSubview:_descLabel]; + + _detailLabel = [[UILabel alloc]initWithFrame:CGRectMake(70, 12, 250, 20)]; + [_descLabel setFont:systemFont(15)]; + [self.contentView addSubview:_detailLabel]; + + _phone = [[UIImageView alloc]initWithFrame:CGRectMake(SCREEN_WIDTH-15-12, 16, 12, 13)]; + [_phone setImage:[UIImage imageNamed:@"phone"]]; + [_phone setHidden:YES]; + [self.contentView addSubview:_phone]; + + } + return self; +} + +- (void)setDesc:(NSString *)desc detail:(NSString *)detail{ + [_descLabel setText:desc]; + [_detailLabel setText:detail]; +} + +- (void)hidePhone:(BOOL)hide{ + [_phone setHidden:hide]; +} + +- (void)awakeFromNib { + // Initialization code +} + +- (void)setSelected:(BOOL)selected animated:(BOOL)animated { + [super setSelected:selected animated:animated]; + + // Configure the view for the selected state +} + +@end diff --git a/ios/IOSDuoduo/VC/PublicProfileViewControll.h b/ios/IOSDuoduo/VC/PublicProfileViewControll.h new file mode 100644 index 000000000..03c48c70c --- /dev/null +++ b/ios/IOSDuoduo/VC/PublicProfileViewControll.h @@ -0,0 +1,13 @@ +// +// PublieProfileViewControll.h +// IOSDuoduo +// +// Created by Michael Scofield on 2014-07-16. +// Copyright (c) 2014 dujia. All rights reserved. +// + +#import +@class DDUserEntity; +@interface PublicProfileViewControll : RootViewController +@property(strong)DDUserEntity *user; +@end diff --git a/ios/IOSDuoduo/VC/PublicProfileViewControll.m b/ios/IOSDuoduo/VC/PublicProfileViewControll.m new file mode 100644 index 000000000..98337f055 --- /dev/null +++ b/ios/IOSDuoduo/VC/PublicProfileViewControll.m @@ -0,0 +1,221 @@ +// +// PublieProfileViewControll.m +// IOSDuoduo +// +// Created by Michael Scofield on 2014-07-16. +// Copyright (c) 2014 dujia. All rights reserved. +// + +#import "PublicProfileViewControll.h" +#import "DDUserEntity.h" +#import "SessionEntity.h" +#import "UIImageView+WebCache.h" +#import "ContactsModule.h" +#import "UIImageView+WebCache.h" +#import "ChattingMainViewController.h" +#import "RuntimeStatus.h" +#import "DDUserDetailInfoAPI.h" +#import "DDDatabaseUtil.h" +#import "DDAppDelegate.h" +#import "DDUserModule.h" +#import "PublicProfileCell.h" +@interface PublicProfileViewControll () +@property(weak)IBOutlet UILabel *nickName; +@property(weak)IBOutlet UILabel *realName; +@property(weak)IBOutlet UIImageView *avatar; +@property(weak)IBOutlet UITableView *tableView; +@property(weak)IBOutlet UIButton *conversationBtn; +-(IBAction)startConversation:(id)sender; +@end + +@implementation PublicProfileViewControll + +- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil +{ + self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil]; + if (self) { + // Custom initialization + } + return self; +} + +- (void)viewDidLoad +{ + [super viewDidLoad]; + self.nickName.text = self.user.nick; + self.realName.text = self.user.name; + self.realName.text = self.user.name; + if([self.user.objID isEqualToString:TheRuntime.user.objID]) + { + [self.conversationBtn setHidden:YES]; + }else + { + [self.conversationBtn setHidden:NO]; + } + [self setTitle:@"详细资料"]; + [self initData]; + + + // Do any additional setup after loading the view from its nib. +} + +-(void)initData +{ + UIImage* placeholder = [UIImage imageNamed:@"user_placeholder"]; + [self.avatar sd_setImageWithURL:[NSURL URLWithString:[self.user getAvatarUrl]] placeholderImage:placeholder]; + [self.avatar setClipsToBounds:YES]; + [self.avatar.layer setCornerRadius:7.5]; + [self.avatar setUserInteractionEnabled:YES]; + [self.tableView setContentInset:UIEdgeInsetsMake(-63, 0, 0, 0)]; + + self.conversationBtn.layer.masksToBounds = YES; + self.conversationBtn.layer.cornerRadius = 4; +// UIView *view = [UIView new]; +// view.backgroundColor = [UIColor clearColor]; +// [self.tableView setTableFooterView:view]; +// [self.tableView setTableHeaderView:view]; +} +-(void)viewWillAppear:(BOOL)animated +{ + [super viewWillAppear:animated]; + [self.tabBarController.tabBar setHidden:YES]; +} +-(void)viewWillDisappear:(BOOL)animated +{ + [super viewWillDisappear:animated]; + [self.tabBarController.tabBar setHidden:NO]; +} +-(void)favThisContact +{ + [ContactsModule favContact:self.user]; +} +- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section +{ + return 3; +} +-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath +{ + static NSString *cellIdentifier = @"PublicProfileCell"; + PublicProfileCell *cell = [tableView dequeueReusableCellWithIdentifier:cellIdentifier ]; + if (cell == nil) { + cell = [[PublicProfileCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:cellIdentifier]; + } + switch (indexPath.row) { + case 0: + { + [[DDDatabaseUtil instance] getDepartmentTitleById:self.user.departId Block:^(NSString *title) { + [cell setDesc:@"部门" detail:title]; + }]; + cell.userInteractionEnabled = NO; + [cell hidePhone:YES]; + } + break; + case 1: + { + [cell setDesc:@"手机" detail:self.user.telphone]; + [cell hidePhone:NO]; + } + break; + case 2: + { + [cell setDesc:@"邮箱" detail:self.user.email]; + [cell hidePhone:YES]; + } + break; + default: + break; + } + + return cell; +} +-(void)alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex +{ + if (alertView.tag == 100) { + if (buttonIndex == 1) { + [self callPhoneNum:self.user.telphone]; + } + }else + { + if (buttonIndex == 1) { + [self sendEmail:self.user.email]; + } + } +} + +-(void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath +{ + [tableView deselectRowAtIndexPath:indexPath animated:YES]; + switch (indexPath.row) { + case 1:{ + NSString *alertMsg; + alertMsg = [NSString stringWithFormat:@"呼叫%@?",self.user.telphone]; + UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"提示" message:alertMsg delegate:self cancelButtonTitle:@"取消" otherButtonTitles:@"确定", nil]; + alert.tag=100; + [alert show]; + } + break; + case 2:{ + NSString *alertMsg; + alertMsg = [NSString stringWithFormat:@"发送邮件%@?",self.user.email]; + UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"提示" message:alertMsg delegate:self cancelButtonTitle:@"取消" otherButtonTitles:@"确定", nil]; + alert.tag=101; + [alert show]; + } + break; + + default: + break; + } +} +-(void)callPhoneNum:(NSString *)phoneNum +{ + if (!phoneNum) { + return; + } + NSString *stringURL =[NSString stringWithFormat:@"tel:%@",phoneNum]; + NSURL *url = [NSURL URLWithString:stringURL]; + [[UIApplication sharedApplication] openURL:url]; +} +-(void)sendEmail:(NSString *)address +{ + if (!address.length) { + return; + } + NSString *stringURL =[NSString stringWithFormat:@"mailto:%@",address]; + NSURL *url = [NSURL URLWithString:stringURL]; + [[UIApplication sharedApplication] openURL:url]; +} +-(IBAction)startConversation:(id)sender +{ + SessionEntity* session = [[SessionEntity alloc] initWithSessionID:self.user.objID type:SessionTypeSessionTypeSingle]; + [[ChattingMainViewController shareInstance] showChattingContentForSession:session]; + NSLog(@"%@...",TheAppDel.nv); + if ([[self.navigationController viewControllers] containsObject:[ChattingMainViewController shareInstance]]) { + [self.navigationController popToViewController:[ChattingMainViewController shareInstance] animated:YES]; + }else + { + [self.navigationController pushViewController:[ChattingMainViewController shareInstance] animated:YES]; + + } + + +} + +/*设置标题头的宽度*/ +-(CGFloat)tableView:(UITableView *)tableView heightForHeaderInSection:(NSInteger)section +{ + return 0; +} +/*设置标题尾的宽度*/ +-(CGFloat)tableView:(UITableView *)tableView heightForFooterInSection:(NSInteger)section +{ + return 0; +} + +- (void)didReceiveMemoryWarning +{ + [super didReceiveMemoryWarning]; + // Dispose of any resources that can be recreated. +} + +@end diff --git a/ios/IOSDuoduo/VC/PublicProfileViewControll.xib b/ios/IOSDuoduo/VC/PublicProfileViewControll.xib new file mode 100644 index 000000000..8fa386c72 --- /dev/null +++ b/ios/IOSDuoduo/VC/PublicProfileViewControll.xib @@ -0,0 +1,156 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/ios/IOSDuoduo/VC/RecentContacts/RecentUserCell.h b/ios/IOSDuoduo/VC/RecentContacts/RecentUserCell.h new file mode 100644 index 000000000..d0c693d3f --- /dev/null +++ b/ios/IOSDuoduo/VC/RecentContacts/RecentUserCell.h @@ -0,0 +1,29 @@ +// +// DDRecentUserCell.h +// IOSDuoduo +// +// Created by 独嘉 on 14-5-26. +// Copyright (c) 2014年 dujia. All rights reserved. +// + +#import +#import "GroupEntity.h" +#import "DDUserEntity.h" +@class SessionEntity; +@interface RecentUserCell : UITableViewCell +@property (weak)IBOutlet UIImageView* avatarImageView; +@property (weak)IBOutlet UILabel* nameLabel; +@property (weak)IBOutlet UILabel* dateLabel; +@property (weak)IBOutlet UILabel* lastmessageLabel; +@property (weak)IBOutlet UILabel* unreadMessageCountLabel; +//@property (weak)IBOutlet UIImageView *onTopImage; +@property (assign)NSInteger time_sort; +- (void)setName:(NSString*)name; +- (void)setTimeStamp:(NSUInteger)timeStamp; +- (void)setLastMessage:(NSString*)message; +- (void)setAvatar:(NSString*)avatar; +- (void)setUnreadMessageCount:(NSUInteger)messageCount; +//-(void)setShowGroup:(GroupEntity *)group; +//-(void)setShowUser:(DDUserEntity *)user; +-(void)setShowSession:(SessionEntity *)session; +@end diff --git a/ios/IOSDuoduo/VC/RecentContacts/RecentUserCell.m b/ios/IOSDuoduo/VC/RecentContacts/RecentUserCell.m new file mode 100644 index 000000000..99a7bc3c4 --- /dev/null +++ b/ios/IOSDuoduo/VC/RecentContacts/RecentUserCell.m @@ -0,0 +1,349 @@ +// +// DDRecentUserCell.m +// IOSDuoduo +// +// Created by 独嘉 on 14-5-26. +// Copyright (c) 2014年 dujia. All rights reserved. +// + +#import "RecentUserCell.h" +#import +#import "NSDate+DDAddition.h" +#import "UIView+DDAddition.h" +#import "std.h" +#import "RuntimeStatus.h" +#import "DDUserEntity.h" +#import "DDMessageModule.h" +#import "GroupAvatarImage.h" +#import "DDUserModule.h" +#import "SessionEntity.h" +#import "DDGroupModule.h" +#import +#import "PhotosCache.h" +#import "DDDatabaseUtil.h" +@implementation RecentUserCell + +- (id)initWithCoder:(NSCoder *)aDecoder +{ + self = [super initWithCoder:aDecoder]; + if(self){ + // 重新设置位置 + _avatarImageView.frame = CGRectMake(10, 10, 50, 50); + _nameLabel.frame = CGRectMake(10+50+10, 14, SCREEN_WIDTH-70-10-60, 20); + _dateLabel.frame = CGRectMake(FULL_WIDTH-10-60, 14, 60, 15); + _lastmessageLabel.frame = CGRectMake(10+50+10, 40, SCREEN_WIDTH-10-10-50, 16); + + // 设置字体 + [_nameLabel setFont:systemFont(17)]; + // [_lastmessageLabel setFont:systemFont(8)]; + [_dateLabel setFont:systemFont(12)]; + + } + return self; +} + +- (id)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier +{ + self = [super initWithStyle:style reuseIdentifier:reuseIdentifier]; + if (self) { + } + return self; +} + +- (void)setSelected:(BOOL)selected animated:(BOOL)animated +{ + [super setSelected:selected animated:animated]; + if (selected) + { + [_nameLabel setTextColor:[UIColor whiteColor]]; + [_lastmessageLabel setTextColor:[UIColor whiteColor]]; + [_dateLabel setTextColor:[UIColor whiteColor]]; + } + else + { + [_nameLabel setTextColor:[UIColor blackColor]]; + [_lastmessageLabel setTextColor:RGB(135, 135, 135)]; + [_dateLabel setTextColor:RGB(135, 135, 135)]; + } + // Configure the view for the selected state +} + +- (void)setHighlighted:(BOOL)highlighted animated:(BOOL)animated // animate between regular and highlighted state +{ + if (highlighted && self.selected) + { + [_nameLabel setTextColor:[UIColor whiteColor]]; + [_lastmessageLabel setTextColor:[UIColor whiteColor]]; + [_dateLabel setTextColor:[UIColor whiteColor]]; + } + else + { + [_nameLabel setTextColor:[UIColor blackColor]]; + [_lastmessageLabel setTextColor:RGB(135, 135, 135)]; + [_dateLabel setTextColor:RGB(135, 135, 135)]; + } +} + +#pragma mark - public +- (void)setName:(NSString*)name +{ + if (!name) + { + [_nameLabel setText:@""]; + } + else + { + [_nameLabel setText:name]; + } +} + +- (void)setTimeStamp:(NSUInteger)timeStamp +{ + NSDate* date = [NSDate dateWithTimeIntervalSince1970:timeStamp]; + NSString* dateString = [date transformToFuzzyDate]; + [_dateLabel setText:dateString]; +} + +- (void)setLastMessage:(NSString*)message +{ + if (!message) + { + [_lastmessageLabel setText:@"."]; + } + else + { + [_lastmessageLabel setText:message]; + } +} + +- (void)setAvatar:(NSString*)avatar +{ + + [[_avatarImageView subviews] enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) { + [(UIView*)obj removeFromSuperview]; + }]; + + NSURL* avatarURL = [NSURL URLWithString:avatar]; + [_avatarImageView setClipsToBounds:YES]; + [_avatarImageView.layer setCornerRadius:4.0]; + UIImage* placeholder = [UIImage imageNamed:@"user_placeholder"]; + [_avatarImageView sd_setImageWithURL:avatarURL placeholderImage:placeholder]; +} + +- (void)setUnreadMessageCount:(NSUInteger)messageCount +{ + if (messageCount == 0) + { + [self.unreadMessageCountLabel setHidden:YES]; + } + else if (messageCount < 10) + { + [self.unreadMessageCountLabel setHidden:NO]; + CGPoint center = self.unreadMessageCountLabel.center; + NSString* title = [NSString stringWithFormat:@"%li",messageCount]; + [self.unreadMessageCountLabel setText:title]; + [self.unreadMessageCountLabel setWidth:16]; + [self.unreadMessageCountLabel setCenter:center]; + [self.unreadMessageCountLabel.layer setCornerRadius:8]; + } + else if (messageCount < 99) + { + [self.unreadMessageCountLabel setHidden:NO]; + CGPoint center = self.unreadMessageCountLabel.center; + NSString* title = [NSString stringWithFormat:@"%li",messageCount]; + [self.unreadMessageCountLabel setText:title]; + [self.unreadMessageCountLabel setWidth:25]; + [self.unreadMessageCountLabel setCenter:center]; + [self.unreadMessageCountLabel.layer setCornerRadius:8]; + } + else + { + [self.unreadMessageCountLabel setHidden:NO]; + CGPoint center = self.unreadMessageCountLabel.center; + NSString* title = @"99+"; + [self.unreadMessageCountLabel setText:title]; + [self.unreadMessageCountLabel setWidth:34]; + [self.unreadMessageCountLabel setCenter:center]; + [self.unreadMessageCountLabel.layer setCornerRadius:8]; + } +} + + +-(void)setShowSession:(SessionEntity *)session +{ + [self setName:session.name]; + [self setUnreadMessageCount:session.unReadMsgCount]; + if ([session.lastMsg isKindOfClass:[NSString class]]) { + if ([session.lastMsg rangeOfString:DD_MESSAGE_IMAGE_PREFIX].location != NSNotFound) { + NSArray *array = [session.lastMsg componentsSeparatedByString:DD_MESSAGE_IMAGE_PREFIX]; + NSString *string = [array lastObject]; + if ([string rangeOfString:DD_MESSAGE_IMAGE_SUFFIX].location != NSNotFound) { + [self setLastMessage:@"[图片]"]; + }else{ + [self setLastMessage:string]; + } + + }else if ([session.lastMsg hasSuffix:@".spx"]) + { + [self setLastMessage:@"[语音]"]; + } + else{ + [self setLastMessage:session.lastMsg]; + + } + } + + + if (session.sessionType == SessionTypeSessionTypeSingle) { + + [[DDUserModule shareInstance] getUserForUserID:session.sessionID Block:^(DDUserEntity *user) { + + + [[_avatarImageView subviews] enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) { + [(UIView*)obj removeFromSuperview]; + }]; + [_avatarImageView setImage:nil]; + [self setAvatar:[user getAvatarUrl]]; + }]; + }else{ + [_avatarImageView setImage:nil]; + [[_avatarImageView subviews] enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) { + [(UIView*)obj removeFromSuperview]; + }]; + + if (session.avatar) + { + NSData* data = [[PhotosCache sharedPhotoCache] photoFromDiskCacheForKey:session.avatar]; + UIImage *image = [[UIImage alloc] initWithData:data]; + if (image) { + [_avatarImageView setImage:image]; + }else{ + [self loadGroupIcon:session key:session.avatar]; + } + }else{ + [self loadGroupIcon:session key:session.avatar]; + + } + + } + + [self setTimeStamp:session.timeInterval]; + if(session.unReadMsgCount) + { + //实时获取未读消息从接口 + } +} + +-(void)loadGroupIcon:(SessionEntity *)session key:(NSString*)key +{ + NSString* keyName = [[NSString alloc] init]; + if (key) { + keyName = key; + }else{ + keyName = [[PhotosCache sharedPhotoCache] getKeyName]; + session.avatar=keyName; +// [[DDDatabaseUtil instance] updateRecentSession:session completion:^(NSError *error) { +// +// }]; + } + [[DDGroupModule instance] getGroupInfogroupID:session.sessionID completion:^(GroupEntity *group) { + [self setName:group.name]; + [_avatarImageView setBackgroundColor:RGB(222, 224, 224)]; + NSMutableArray* avatars = [[NSMutableArray alloc] init]; + __block NSUInteger usedImageNumber = 0; + __block NSUInteger groupUserCnt = [group.groupUserIds count]; + [group.groupUserIds enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) { + + UIImageView* imageView = [[UIImageView alloc] initWithFrame:CGRectMake(0, 0, 21, 21)]; + [imageView.layer setCornerRadius:2.0]; + [imageView setContentMode:UIViewContentModeScaleAspectFill]; + [imageView setClipsToBounds:YES]; + + NSString* userID = (NSString*)obj; + [[DDUserModule shareInstance] getUserForUserID:userID Block:^(DDUserEntity *user) { + if (user) + { + usedImageNumber++; + NSString* avatar = [user getAvatarUrl]; + NSURL* avatarURL = [[NSURL alloc] initWithString:avatar]; + [[SDWebImageManager sharedManager] downloadImageWithURL:avatarURL options:SDWebImageLowPriority progress:^(NSInteger receivedSize, NSInteger expectedSize) { + + } completed:^(UIImage *image, NSError *error, SDImageCacheType cacheType, BOOL finished, NSURL *imageURL) { + if (!image) + { + image = [UIImage imageNamed:@"user_placeholder"]; + } + [imageView setImage:image]; + [avatars addObject:imageView]; + if (usedImageNumber >= 4 || usedImageNumber == groupUserCnt) + { + if ([avatars count] == 1) + { + UIImageView* imageView1 = avatars[0]; + [imageView1 setCenter:CGPointMake(_avatarImageView.width / 2, _avatarImageView.height / 2)]; + } + else if ([avatars count] == 2) + { + UIImageView* imageView1 = avatars[0]; + [imageView1 setCenter:CGPointMake(_avatarImageView.width / 4 + 1, _avatarImageView.height / 2)]; + + UIImageView* imageView2 = avatars[1]; + [imageView2 setCenter:CGPointMake(_avatarImageView.width / 4 * 3, _avatarImageView.height / 2)]; + } + else if ([avatars count] == 3) + { + UIImageView* imageView1 = avatars[0]; + [imageView1 setCenter:CGPointMake(_avatarImageView.width / 2, _avatarImageView.height / 4 + 1)]; + + UIImageView* imageView2 = avatars[1]; + [imageView2 setCenter:CGPointMake(_avatarImageView.width / 4 + 1, _avatarImageView.height / 4 * 3)]; + + UIImageView* imageView3 = avatars[2]; + [imageView3 setCenter:CGPointMake(_avatarImageView.width / 4 * 3, _avatarImageView.height / 4 * 3)]; + + } + else if ([avatars count] == 4) + { + UIImageView* imageView1 = avatars[0]; + [imageView1 setCenter:CGPointMake(_avatarImageView.width / 4 + 1, _avatarImageView.height / 4 + 1)]; + + UIImageView* imageView2 = avatars[1]; + [imageView2 setCenter:CGPointMake(_avatarImageView.width / 4 * 3, _avatarImageView.height / 4 + 1)]; + + UIImageView* imageView3 = avatars[2]; + [imageView3 setCenter:CGPointMake(_avatarImageView.width / 4 + 1, _avatarImageView.height / 4 * 3)]; + + UIImageView* imageView4 = avatars[3]; + [imageView4 setCenter:CGPointMake(_avatarImageView.width / 4 * 3, _avatarImageView.height / 4 * 3)]; + } + + [avatars enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) { + [_avatarImageView addSubview:obj]; + }]; + [_avatarImageView setClipsToBounds:YES]; + [_avatarImageView.layer setCornerRadius:3.0]; + UIImage *image = [self getImageFromView:_avatarImageView]; + NSData *photoData = UIImagePNGRepresentation(image); + [[PhotosCache sharedPhotoCache] storePhoto:photoData forKey:keyName toDisk:YES]; + } + }]; + } + if (usedImageNumber >= 4 || usedImageNumber == groupUserCnt) { + *stop = YES; + } + }]; + + }]; + }]; + + +} +-(UIImage *)getImageFromView:(UIView *)orgView{ + CGSize s = orgView.bounds.size; + UIGraphicsBeginImageContextWithOptions(s, NO, [UIScreen mainScreen].scale); + [orgView.layer renderInContext:UIGraphicsGetCurrentContext()]; + UIImage*image = UIGraphicsGetImageFromCurrentImageContext(); + UIGraphicsEndImageContext(); + return image; +} +@end \ No newline at end of file diff --git a/ios/IOSDuoduo/VC/RecentContacts/RecentUserCell.xib b/ios/IOSDuoduo/VC/RecentContacts/RecentUserCell.xib new file mode 100644 index 000000000..1f3846e48 --- /dev/null +++ b/ios/IOSDuoduo/VC/RecentContacts/RecentUserCell.xib @@ -0,0 +1,75 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/ios/IOSDuoduo/VC/RecentContacts/RecentUsersViewController.h b/ios/IOSDuoduo/VC/RecentContacts/RecentUsersViewController.h new file mode 100644 index 000000000..e7e5b099e --- /dev/null +++ b/ios/IOSDuoduo/VC/RecentContacts/RecentUsersViewController.h @@ -0,0 +1,19 @@ +// +// DDRecentUsersViewController.h +// IOSDuoduo +// +// Created by 独嘉 on 14-5-26. +// Copyright (c) 2014年 dujia. All rights reserved. +// + +#import +#import "SessionModule.h" +@class RecentUserVCModule; +@interface RecentUsersViewController : UIViewController +@property(nonatomic,weak)IBOutlet UITableView* tableView; +@property(nonatomic,strong)RecentUserVCModule* module; +@property(strong)NSMutableArray *items; ++ (instancetype)shareInstance; +-(void)moveSessionToTop:(NSString *)sesstionID; +- (void)showLinking; +@end diff --git a/ios/IOSDuoduo/VC/RecentContacts/RecentUsersViewController.m b/ios/IOSDuoduo/VC/RecentContacts/RecentUsersViewController.m new file mode 100644 index 000000000..68919c751 --- /dev/null +++ b/ios/IOSDuoduo/VC/RecentContacts/RecentUsersViewController.m @@ -0,0 +1,427 @@ +// +// DDRecentUsersViewController.m +// IOSDuoduo +// +// Created by 独嘉 on 14-5-26. +// Copyright (c) 2014年 dujia. All rights reserved. +// + +#import "RecentUsersViewController.h" +#import "RecentUserCell.h" +#import "DDUserModule.h" +#import "DDMessageModule.h" +#import "ChattingMainViewController.h" +#import "SessionEntity.h" +#import "std.h" +#import "DDDatabaseUtil.h" +#import "LoginModule.h" +#import "DDClientState.h" +#import "RuntimeStatus.h" +#import "DDUserModule.h" +#import "DDGroupModule.h" +#import "DDFixedGroupAPI.h" +#import "SearchContentViewController.h" +#import "MBProgressHUD.h" +#import "SessionModule.h" +#import "BlurView.h" +#import "LoginViewController.h" +@interface RecentUsersViewController () +@property(strong)UISearchDisplayController * searchController; +@property(strong)MBProgressHUD *hud; +@property(strong)NSMutableDictionary *lastMsgs; +@property(weak)IBOutlet UISearchBar *bar; +@property(strong)SearchContentViewController *searchContent; +@property(assign)NSInteger fixedCount; +- (void)n_receiveStartLoginNotification:(NSNotification*)notification; +- (void)n_receiveLoginFailureNotification:(NSNotification*)notification; +- (void)n_receiveRecentContactsUpdateNotification:(NSNotification*)notification; +@end + +@implementation RecentUsersViewController + ++ (instancetype)shareInstance +{ + static RecentUsersViewController* g_recentUsersViewController; + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^{ + g_recentUsersViewController = [RecentUsersViewController new]; + }); + return g_recentUsersViewController; +} + +- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil +{ + self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil]; + if (self) { + // Custom initialization + [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(n_receiveLoginFailureNotification:) name:DDNotificationUserLoginFailure object:nil]; + } + [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(n_receiveLoginNotification:) name:DDNotificationUserLoginSuccess object:nil]; + [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(kickOffUser:) name:@"KickOffUser" object:nil]; + [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(logout) name:DDNotificationLogout object:nil]; + return self; +} + +- (void)viewDidLoad +{ + [super viewDidLoad]; + + self.title=@"消息"; + self.navigationItem.title=@"TeamTalk"; + [self.navigationController.navigationBar setBarStyle:UIBarStyleDefault]; + self.wantsFullScreenLayout=YES; + self.items=[NSMutableArray new]; + [_tableView setFrame:self.view.frame]; + self.tableView.contentOffset = CGPointMake(0, CGRectGetHeight(self.bar.bounds)); + [self.tableView setContentInset:UIEdgeInsetsMake(0, 0, 0, 0)]; + [self.tableView setBackgroundColor:RGB(239,239,244)]; + [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(refreshData) name:@"RefreshRecentData" object:nil]; + [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(n_receiveReLoginSuccessNotification) name:@"ReloginSuccess" object:nil]; + self.lastMsgs = [NSMutableDictionary new]; + [[SessionModule sharedInstance] loadLocalSession:^(bool isok) { + if (isok) { + [self.items addObjectsFromArray:[[SessionModule sharedInstance] getAllSessions]]; + [self.tableView reloadData]; + + dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ + [[SessionModule sharedInstance] getRecentSession:^(NSUInteger count) { + + [self.items removeAllObjects]; + [self.items addObjectsFromArray:[[SessionModule sharedInstance] getAllSessions]]; + [self sortItems]; + NSUInteger unreadcount = [[self.items valueForKeyPath:@"@sum.unReadMsgCount"] integerValue]; + [self setToolbarBadge:unreadcount]; + + }]; + }); + + } + }]; + [SessionModule sharedInstance].delegate=self; + [self addCustomSearchControll]; + + +} + + +-(void)addCustomSearchControll +{ + + self.searchContent = [SearchContentViewController new]; + self.searchContent.viewController=self; + self.searchController = [[UISearchDisplayController alloc] initWithSearchBar:self.bar contentsController:self]; + self.searchController.delegate=self; + + self.searchController.searchResultsDataSource=self.searchContent.dataSource; + self.searchController.searchResultsDelegate=self.searchContent.delegate; + +} + +-(void)sortItems +{ + [self.items removeAllObjects]; + [self.items addObjectsFromArray:[[SessionModule sharedInstance] getAllSessions]]; + NSSortDescriptor *sortDescriptor = [[NSSortDescriptor alloc] initWithKey:@"timeInterval" ascending:NO]; + [self.items sortUsingDescriptors:[NSArray arrayWithObject:sortDescriptor]]; + [self.tableView reloadData]; + +} + +-(void)refreshData +{ + [self.tableView reloadData]; + [self setToolbarBadge:0]; + [self sortItems]; +} + +-(void)setToolbarBadge:(NSUInteger)count +{ + + if (count !=0) { + if (count > 99) + { + [self.parentViewController.tabBarItem setBadgeValue:@"99+"]; + } + else + { + [self.parentViewController.tabBarItem setBadgeValue:[NSString stringWithFormat:@"%ld",count]]; + } + }else + { + [[UIApplication sharedApplication] setApplicationIconBadgeNumber:0]; + [self.parentViewController.tabBarItem setBadgeValue:nil]; + } + +} + + +-(void)searchContact +{ + +} +- (void)viewWillAppear:(BOOL)animated +{ + [super viewWillAppear:animated]; + + NSUInteger count = [[self.items valueForKeyPath:@"@sum.unReadMsgCount"] integerValue]; + [self setToolbarBadge:count]; + [self.tableView reloadData]; + self.fixedCount = [TheRuntime getFixedTopCount]; + +} + + +- (void)viewDidAppear:(BOOL)animated +{ + [super viewDidAppear:animated]; + [self.tabBarController.tabBar setHidden:NO]; + [ChattingMainViewController shareInstance].module.sessionEntity=nil; + + if (!self.items) { + self.items=[NSMutableArray new]; + [_tableView setFrame:self.view.frame]; + self.lastMsgs = [NSMutableDictionary new]; + [[SessionModule sharedInstance] loadLocalSession:^(bool isok) { + if (isok) { + [self.items addObjectsFromArray:[[SessionModule sharedInstance] getAllSessions]]; + [self.tableView reloadData]; + + dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ + [[SessionModule sharedInstance] getRecentSession:^(NSUInteger count) { + + [self.items removeAllObjects]; + [self.items addObjectsFromArray:[[SessionModule sharedInstance] getAllSessions]]; + [self sortItems]; + NSUInteger unreadcount = [[self.items valueForKeyPath:@"@sum.unReadMsgCount"] integerValue]; + [self setToolbarBadge:unreadcount]; + + }]; + }); + + } + }]; + + } +} + +- (void)didReceiveMemoryWarning +{ + [super didReceiveMemoryWarning]; + // Dispose of any resources that can be recreated. +} + +- (void)dealloc +{ + [[NSNotificationCenter defaultCenter] removeObserver:self]; +} + + + +#pragma mark public +- (void)showLinking +{ + self.title = @"正在连接..."; +// UIView* titleView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 200, 44)]; +// +// UIActivityIndicatorView* activity = [[UIActivityIndicatorView alloc] initWithActivityIndicatorStyle:UIActivityIndicatorViewStyleGray]; +// [activity setFrame:CGRectMake(30, 0, 44, 44)]; +// +// UILabel* linkLabel = [[UILabel alloc] initWithFrame:CGRectMake(0, 0, 200, 44)]; +// [linkLabel setTextAlignment:NSTextAlignmentCenter]; +// [linkLabel setText:@"正在连接"]; +// +// [activity startAnimating]; +// [titleView addSubview:activity]; +// [titleView addSubview:linkLabel]; +// +// [self.navigationItem setTitleView:titleView]; +} + + +#pragma mark - UITableView DataSource +- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView +{ + return 1; +} + +- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section +{ + return [self.items count]; +} + +- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath +{ + return 72; +} + +- (UITableViewCell*)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath +{ + NSString* cellIdentifier = [NSString stringWithFormat:@"DDRecentUserCellIdentifier_%ld",indexPath.row]; + RecentUserCell* cell = (RecentUserCell*)[tableView dequeueReusableCellWithIdentifier:cellIdentifier]; + if (!cell) + { + NSArray *topLevelObjects = [[NSBundle mainBundle] loadNibNamed:@"RecentUserCell" owner:self options:nil]; + cell = [topLevelObjects objectAtIndex:0]; + } + + UIView *view = [[UIView alloc] initWithFrame:cell.bounds]; + view.backgroundColor=RGB(229, 229, 229); + cell.selectedBackgroundView=view; + NSInteger row = [indexPath row]; + [cell setShowSession:self.items[row]]; + [self preLoadMessage:self.items[row]]; + + return cell; +} +-(void)sessionUpdate:(SessionEntity *)session Action:(SessionAction)action +{ + if ([self.items containsObject:session]) { + if ([self.items indexOfObject:session] == 0) { + [self.items removeObjectAtIndex:0]; + [self.items insertObject:session atIndex:0]; + [self.tableView reloadData]; + + }else{ + NSUInteger index = [self.items indexOfObject:session]; + [self.items removeObjectAtIndex:index]; + [self.items insertObject:session atIndex:0]; + [self.tableView reloadData]; + } + }else{ + [self.items insertObject:session atIndex:0]; + @try { + [self.tableView reloadData]; + } + @catch (NSException *exception) { + DDLog(@"插入cell 动画失败"); + } + } + + NSUInteger count = [[self.items valueForKeyPath:@"@sum.unReadMsgCount"] integerValue]; + [self setToolbarBadge:count]; +} +#pragma mark - UITableView Delegate +- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath +{ + [tableView deselectRowAtIndexPath:indexPath animated:YES]; + NSInteger row = [indexPath row]; + SessionEntity *session = self.items[row]; + [ChattingMainViewController shareInstance].title=session.name; + [[ChattingMainViewController shareInstance] showChattingContentForSession:session]; + [self.navigationController pushViewController:[ChattingMainViewController shareInstance] animated:YES]; + + +} + + +-(void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath +{ + NSUInteger row = [indexPath row]; + SessionEntity *session = self.items[row]; + [[SessionModule sharedInstance] removeSessionByServer:session]; + [self.items removeObjectAtIndex:row]; + [self setToolbarBadge:[[self.items valueForKeyPath:@"@sum.unReadMsgCount"] integerValue]]; + [tableView deleteRowsAtIndexPaths:@[indexPath] withRowAnimation:UITableViewRowAnimationRight]; +} +- (BOOL)tableView:(UITableView *)tableView canEditRowAtIndexPath:(NSIndexPath *)indexPath{ + return YES; +} + +- (NSString *)tableView:(UITableView *)tableView titleForDeleteConfirmationButtonForRowAtIndexPath:(NSIndexPath *)indexPath{ + + return @"删除"; +} +- (BOOL)searchBarShouldBeginEditing:(UISearchBar *)searchBar +{ + + [self.searchController setActive:YES animated:YES]; + return YES; +} + +- (void)searchBar:(UISearchBar *)searchBar textDidChange:(NSString *)searchText +{ + [self.searchContent searchTextDidChanged:searchText Block:^(bool done) { + [self.searchDisplayController.searchResultsTableView reloadData]; + }]; +} +- (void)n_receiveLoginFailureNotification:(NSNotification*)notification +{ + self.title = @"未连接"; +} +- (void)n_receiveStartLoginNotification:(NSNotification*)notification +{ + self.title = @"TeamTalk"; +} +- (void)n_receiveLoginNotification:(NSNotification*)notification +{ + self.title = @"TeamTalk"; + +} +-(void)logout +{ + self.items=nil; +} + +-(void)kickOffUser:(NSNotification*)notification +{ + int type = [[notification object] intValue]; + [[NSUserDefaults standardUserDefaults] setObject:@(false) forKey:@"autologin"]; + LoginViewController *login = [LoginViewController new]; + login.isRelogin=YES; + + [self presentViewController:login animated:YES completion:^{ + TheRuntime.user =nil; + TheRuntime.userID =nil; + [[DDTcpClientManager instance] disconnect]; + [DDClientState shareInstance].userState = DDUserOffLineInitiative; + SCLAlertView *alert = [SCLAlertView new]; + [alert showInfo:self title:@"注意" subTitle:@"你的账号在其他设备登陆了" closeButtonTitle:@"确定" duration:0]; + + }]; +} +-(void)n_receiveReLoginSuccessNotification +{ + self.title = @"TeamTalk"; + dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ + [[SessionModule sharedInstance] getRecentSession:^(NSUInteger count) { + + [self.items removeAllObjects]; + [self.items addObjectsFromArray:[[SessionModule sharedInstance] getAllSessions]]; + [self sortItems]; + [self setToolbarBadge:count]; + + }]; + }); +} +-(void)preLoadMessage:(SessionEntity *)session +{ + + [[DDDatabaseUtil instance] getLastestMessageForSessionID:session.sessionID completion:^(DDMessageEntity *message, NSError *error) { + if (message) { + if (message.msgID != session.lastMsgID ) { + [[DDMessageModule shareInstance] getMessageFromServer:session.lastMsgID currentSession:session count:20 Block:^(NSMutableArray *array, NSError *error) { + [[DDDatabaseUtil instance] insertMessages:array success:^{ + + } failure:^(NSString *errorDescripe) { + + }]; + }]; + } + }else{ + if (session.lastMsgID !=0) { + [[DDMessageModule shareInstance] getMessageFromServer:session.lastMsgID currentSession:session count:20 Block:^(NSMutableArray *array, NSError *error) { + [[DDDatabaseUtil instance] insertMessages:array success:^{ + + } failure:^(NSString *errorDescripe) { + + }]; + }]; + } + + } + + }]; + +} + +@end diff --git a/ios/IOSDuoduo/VC/RecentContacts/RecentUsersViewController.xib b/ios/IOSDuoduo/VC/RecentContacts/RecentUsersViewController.xib new file mode 100644 index 000000000..d27c784ad --- /dev/null +++ b/ios/IOSDuoduo/VC/RecentContacts/RecentUsersViewController.xib @@ -0,0 +1,52 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/ios/IOSDuoduo/VC/RootViewController.h b/ios/IOSDuoduo/VC/RootViewController.h new file mode 100644 index 000000000..5dd4c86cd --- /dev/null +++ b/ios/IOSDuoduo/VC/RootViewController.h @@ -0,0 +1,12 @@ +// +// RootViewController.h +// TeamTalk +// +// Created by Michael Scofield on 2015-01-28. +// Copyright (c) 2015 Michael Hu. All rights reserved. +// + +#import + +@interface RootViewController : UIViewController +@end diff --git a/ios/IOSDuoduo/VC/RootViewController.m b/ios/IOSDuoduo/VC/RootViewController.m new file mode 100644 index 000000000..bbe3b9f00 --- /dev/null +++ b/ios/IOSDuoduo/VC/RootViewController.m @@ -0,0 +1,51 @@ +// +// RootViewController.m +// TeamTalk +// +// Created by Michael Scofield on 2015-01-28. +// Copyright (c) 2015 Michael Hu. All rights reserved. +// + +#import "RootViewController.h" + +@interface RootViewController () + +@end + +@implementation RootViewController + +- (void)viewDidLoad { + [super viewDidLoad]; + UIButton *back = [UIButton buttonWithType:UIButtonTypeCustom]; + back.frame=CGRectMake(0, 0, 60, 40); + UIImage* image = [UIImage imageNamed:@"top_back"]; + [back setImage:image forState:UIControlStateNormal]; + [back setImageEdgeInsets:UIEdgeInsetsMake(0, 0, 0, 10)]; + [back setTitle:@"返回" forState:UIControlStateNormal]; + [back setTitleColor:[UIColor blackColor] forState:UIControlStateNormal]; + [back addTarget:self action:@selector(p_popViewController) forControlEvents:UIControlEventTouchUpInside]; + UIBarButtonItem *backButton = [[UIBarButtonItem alloc] initWithCustomView:back]; + self.navigationItem.backBarButtonItem = backButton; + // Do any additional setup after loading the view. +} +-(void)p_popViewController +{ + [self.navigationController popViewControllerAnimated:YES]; + +} +- (void)didReceiveMemoryWarning { + [super didReceiveMemoryWarning]; + // Dispose of any resources that can be recreated. +} + +/* +#pragma mark - Navigation + +// In a storyboard-based application, you will often want to do a little preparation before navigation +- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender { + // Get the new view controller using [segue destinationViewController]. + // Pass the selected object to the new view controller. +} +*/ + +@end diff --git a/ios/IOSDuoduo/VC/ScanQRCodePage.h b/ios/IOSDuoduo/VC/ScanQRCodePage.h new file mode 100644 index 000000000..0f4310f71 --- /dev/null +++ b/ios/IOSDuoduo/VC/ScanQRCodePage.h @@ -0,0 +1,26 @@ +// +// ViewController.h +// CashBank +// +// Created by Michael Scofield on 2014-10-23. +// Copyright (c) 2014 Michael. All rights reserved. +// + +#import +#import +@interface ScanQRCodePage : UIViewController +{ + int num; + BOOL upOrdown; + NSTimer * timer; +} +@property (strong,nonatomic)AVCaptureDevice * device; +@property (strong,nonatomic)AVCaptureDeviceInput * input; +@property (strong,nonatomic)AVCaptureMetadataOutput * output; +@property (strong,nonatomic)AVCaptureSession * session; +@property (strong,nonatomic)AVCaptureVideoPreviewLayer * preview; +@property (nonatomic, retain) UIImageView * line; +@property (weak) IBOutlet UIView *scanView; +-(IBAction)scanAgain:(id)sender; +@end + diff --git a/ios/IOSDuoduo/VC/ScanQRCodePage.m b/ios/IOSDuoduo/VC/ScanQRCodePage.m new file mode 100644 index 000000000..579825652 --- /dev/null +++ b/ios/IOSDuoduo/VC/ScanQRCodePage.m @@ -0,0 +1,148 @@ +// +// ViewController.m +// CashBank +// +// Created by Michael Scofield on 2014-10-23. +// Copyright (c) 2014 Michael. All rights reserved. +// + +#import "ScanQRCodePage.h" + +@interface ScanQRCodePage () + +@end + +@implementation ScanQRCodePage + +- (void)viewDidLoad { + [super viewDidLoad]; + self.title=@"扫一扫"; + UIImageView * imageView = [[UIImageView alloc]initWithFrame:CGRectMake(10, 100, 300, 300)]; + imageView.image = [UIImage imageNamed:@"pick_bg"]; + [self.view addSubview:imageView]; + + upOrdown = NO; + num =0; + _line = [[UIImageView alloc] initWithFrame:CGRectMake(50, 110, 220, 2)]; + _line.image = [UIImage imageNamed:@"line.png"]; + [self.view addSubview:_line]; + + timer = [NSTimer scheduledTimerWithTimeInterval:.02 target:self selector:@selector(animation1) userInfo:nil repeats:YES]; + [self setupCamera]; + // Do any additional setup after loading the view, typically from a nib. +} +-(void)animation1 +{ + if (upOrdown == NO) { + num ++; + _line.frame = CGRectMake(50, 110+2*num, 220, 2); + if (2*num == 280) { + upOrdown = YES; + } + } + else { + num --; + _line.frame = CGRectMake(50, 110+2*num, 220, 2); + if (num == 0) { + upOrdown = NO; + } + } + +} +-(void)viewWillDisappear:(BOOL)animated +{ + [super viewWillDisappear:animated]; + [timer invalidate]; + [self.tabBarController.tabBar setHidden:NO]; +} +-(void)viewWillAppear:(BOOL)animated +{ + [_session startRunning]; + [self.tabBarController.tabBar setHidden:YES]; + +} +- (void)setupCamera +{ + // Device + _device = [AVCaptureDevice defaultDeviceWithMediaType:AVMediaTypeVideo]; + + // Input + _input = [AVCaptureDeviceInput deviceInputWithDevice:self.device error:nil]; + + // Output + _output = [[AVCaptureMetadataOutput alloc]init]; + [_output setMetadataObjectsDelegate:self queue:dispatch_get_main_queue()]; + + // Session + _session = [[AVCaptureSession alloc]init]; + [_session setSessionPreset:AVCaptureSessionPresetHigh]; + if ([_session canAddInput:self.input]) + { + [_session addInput:self.input]; + } + + if ([_session canAddOutput:self.output]) + { + [_session addOutput:self.output]; + } + + // 条码类型 AVMetadataObjectTypeQRCode + _output.metadataObjectTypes =@[AVMetadataObjectTypeQRCode]; + _preview =[AVCaptureVideoPreviewLayer layerWithSession:self.session]; + _preview.videoGravity = AVLayerVideoGravityResizeAspectFill; + _preview.frame =CGRectMake(0, 0, FULL_WIDTH, FULL_HEIGHT); + [self.view.layer insertSublayer:_preview atIndex:0]; + // Start + [_session startRunning]; +} +#pragma mark AVCaptureMetadataOutputObjectsDelegate +- (void)captureOutput:(AVCaptureOutput *)captureOutput didOutputMetadataObjects:(NSArray *)metadataObjects fromConnection:(AVCaptureConnection *)connection +{ + + NSString *stringValue; + + if ([metadataObjects count] >0) + { + AVMetadataMachineReadableCodeObject * metadataObject = [metadataObjects objectAtIndex:0]; + stringValue = metadataObject.stringValue; + } + + [_session stopRunning]; + + [timer invalidate]; + [self showResult:stringValue]; + +} +-(void)showScanResult:(NSString *)scanResult +{ + SCLAlertView *alert = [SCLAlertView new]; + [alert addButton:@"复制" actionBlock:^{ + UIPasteboard *pboard = [UIPasteboard generalPasteboard]; + pboard.string = scanResult; + [_session startRunning]; + }]; + [alert addButton:@"打开" actionBlock:^{ + [[UIApplication sharedApplication] openURL:[NSURL URLWithString:scanResult]]; + [_session startRunning]; + }]; + [alert addButton:@"再来" actionBlock:^{ + [_session startRunning]; + }]; + + [alert showInfo:self title:@"扫描结果" subTitle:scanResult closeButtonTitle:nil duration:0]; +} +-(NSString *)showResult:(NSString *)codeSources +{ + [self showScanResult:codeSources]; + return nil; + +} +- (void)didReceiveMemoryWarning { + [super didReceiveMemoryWarning]; + // Dispose of any resources that can be recreated. +} +-(IBAction)scanAgain:(id)sender +{ + [_session startRunning]; +} +@end diff --git a/ios/IOSDuoduo/VC/ScanQRCodePage.xib b/ios/IOSDuoduo/VC/ScanQRCodePage.xib new file mode 100644 index 000000000..3d526fda2 --- /dev/null +++ b/ios/IOSDuoduo/VC/ScanQRCodePage.xib @@ -0,0 +1,83 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/ios/IOSDuoduo/VC/SearchContentViewController.h b/ios/IOSDuoduo/VC/SearchContentViewController.h new file mode 100644 index 000000000..5b5bf13f1 --- /dev/null +++ b/ios/IOSDuoduo/VC/SearchContentViewController.h @@ -0,0 +1,14 @@ +// +// SearchContentViewController.h +// TeamTalk +// +// Created by Michael Scofield on 2014-10-20. +// Copyright (c) 2014 dujia. All rights reserved. +// + +#import + +@interface SearchContentViewController : UITableView +-(void)searchTextDidChanged:(NSString *)searchText Block:(void(^)(bool done)) block; +@property(strong)UIViewController *viewController; +@end diff --git a/ios/IOSDuoduo/VC/SearchContentViewController.m b/ios/IOSDuoduo/VC/SearchContentViewController.m new file mode 100644 index 000000000..b938ec8b4 --- /dev/null +++ b/ios/IOSDuoduo/VC/SearchContentViewController.m @@ -0,0 +1,230 @@ +// +// SearchContentViewController.m +// TeamTalk +// +// Created by Michael Scofield on 2014-10-20. +// Copyright (c) 2014 dujia. All rights reserved. +// + +#import "SearchContentViewController.h" +#import "std.h" +#import "DDSearch.h" +#import "DDContactsCell.h" +#import "DDUserEntity.h" +#import "PublicProfileViewControll.h" +#import "SessionEntity.h" +#import "ContactsViewController.h" +#import "DDAppDelegate.h" +#import "MBProgressHUD.h" +#import "ContactsModule.h" +#import "DDDatabaseUtil.h" +#import "SpellLibrary.h" +#import "DDGroupModule.h" +#import "DDUserModule.h" +#import "SessionModule.h" +#import "ChattingMainViewController.h" +@interface SearchContentViewController () +@property(strong)NSMutableArray *groups; +@property(strong)NSString *keyString; +@property(strong) ContactsViewController *contact; +@property(strong)NSMutableArray *searchResult; +@property(strong)NSMutableArray *department; +@end + +@implementation SearchContentViewController +- (instancetype)init +{ + self = [super init]; + if (self) { + self.groups = [NSMutableArray new]; + + self.searchResult = [NSMutableArray new]; + self.department = [NSMutableArray new]; + self.keyString=@""; + self.dataSource=self; + self.delegate=self; + DDLog(@"come to"); + if ([[SpellLibrary instance] isEmpty]) { + DDLog(@"spelllibrary is empty"); + dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ + [[[DDUserModule shareInstance] getAllMaintanceUser] enumerateObjectsUsingBlock:^(DDUserEntity *obj, NSUInteger idx, BOOL *stop) { + [[SpellLibrary instance] addSpellForObject:obj]; + [[SpellLibrary instance] addDeparmentSpellForObject:obj]; + + }]; + NSArray *array = [[DDGroupModule instance] getAllGroups]; + [array enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) { + [[SpellLibrary instance] addSpellForObject:obj]; + }]; + + }); + } + } + return self; +} + + +-(void)searchTextDidChanged:(NSString *)searchText Block:(void(^)(bool done)) block +{ + if ([searchText isEqualToString:@""]) { + return ; + } + + MBProgressHUD *HUD = [[MBProgressHUD alloc] initWithView:self]; + [self addSubview:HUD]; + [HUD show:YES]; + HUD.dimBackground = YES; + HUD.labelText = @"正在搜索"; + [[DDSearch instance] searchDepartment:searchText completion:^(NSArray *result, NSError *error) { + if ([result count] >0) { + [self.department removeAllObjects]; + [result enumerateObjectsUsingBlock:^(DDUserEntity *obj, NSUInteger idx, BOOL *stop) { + if (![self.department containsObject:obj.department]) { + [self.department addObject:obj.department]; + } + }]; + + block(YES); + } + [HUD removeFromSuperview]; + } + ]; + [[DDSearch instance] searchContent:searchText completion:^(NSArray *result, NSError *error) { + self.keyString=searchText; + if ([result count] >0) { + [self.searchResult removeAllObjects]; + [self.groups removeAllObjects]; + [result enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) { + if ([obj isKindOfClass:[DDUserEntity class]]) { + [self.searchResult addObject:obj]; + }else if ([obj isKindOfClass:[GroupEntity class]]) + { + [self.groups addObject:obj]; + } + + }]; + block(YES); + } + [HUD removeFromSuperview]; + }]; + +} + +- (void)searchBarCancelButtonClicked:(UISearchBar *)searchBar +{ + + [self.searchResult removeAllObjects]; + [self.groups removeAllObjects]; + [self.department removeAllObjects]; + [self reloadData]; +} +- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section +{ + if (section == 0) { + return [self.searchResult count]; + }else if(section == 1) + { + return [self.groups count]; + }else + { + return [self.department count]; + } + +} +- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView +{ + return 3; +} +- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath +{ + static NSString *cellIdentifier = @"contactsCell"; + DDContactsCell *cell = [tableView dequeueReusableCellWithIdentifier:cellIdentifier ]; + if (cell == nil) { + cell = [[DDContactsCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:cellIdentifier]; + } + DDUserEntity *user=nil; + if (indexPath.section == 0) { + user = [self.searchResult objectAtIndex:indexPath.row]; + [cell setCellContent:[user getAvatarUrl] Name:user.nick Cname:@""]; + }else if(indexPath.section == 1) + { + GroupEntity *group = [self.groups objectAtIndex:indexPath.row]; + [cell setCellContent:group.avatar Name:group.name Cname:@""]; + }else + { + NSString *string = [self.department objectAtIndex:indexPath.row]; + [cell setCellContent:[user getAvatarUrl] Name:string Cname:@""]; + } + + + + return cell; +} + +- (NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section { + if (section == 0) { + return [self.searchResult count]?@"联系人":@""; + } else if(section == 1){ + return [self.groups count]?@"群组":@""; + }else{ + return [self.department count ]?@"部门":@""; + } + +} +-(void)scrollViewDidScroll:(UIScrollView *)scrollView +{ + +} +-(CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath{ + return 55; +} + +-(void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath +{ + if (indexPath.section == 0) { + DDUserEntity *user; + user = self.searchResult[indexPath.row]; + PublicProfileViewControll *public = [PublicProfileViewControll new]; + public.user=user; + [self.viewController.navigationController pushViewController:public animated:YES]; + + return; + + }else if(indexPath.section == 1) + { + GroupEntity *group = [self.groups objectAtIndex:indexPath.row]; + SessionEntity *session; + if (![[SessionModule sharedInstance] getSessionById:group.objID]) { + session = [[SessionEntity alloc] initWithSessionID:group.objID SessionName:group.name type:SessionTypeSessionTypeGroup]; + }else{ + session = [[SessionModule sharedInstance] getSessionById:group.objID]; + } + + [[ChattingMainViewController shareInstance] showChattingContentForSession:session]; + [self.viewController.navigationController pushViewController:[ChattingMainViewController shareInstance] animated:YES]; + }else + { + NSString *string = [self.department objectAtIndex:indexPath.row]; + ContactsViewController *contact = [ContactsViewController new]; + contact.sectionTitle=string; + contact.isSearchResult=YES; + [self.viewController.navigationController pushViewController:contact animated:YES]; + + } +} + +-(void)searchBarSearchButtonClicked:(UISearchBar *)searchBar +{ + +} +/* +#pragma mark - Navigation + + In a storyboard-based application, you will often want to do a little preparation before navigation +- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender { + Get the new view controller using [segue destinationViewController]. + Pass the selected object to the new view controller. +} +*/ + +@end diff --git a/ios/IOSDuoduo/VC/WifiViewController.h b/ios/IOSDuoduo/VC/WifiViewController.h new file mode 100644 index 000000000..b3c4bbc26 --- /dev/null +++ b/ios/IOSDuoduo/VC/WifiViewController.h @@ -0,0 +1,13 @@ +// +// WifiViewController.h +// TeamTalk +// +// Created by 独嘉 on 14-10-22. +// Copyright (c) 2014年 dujia. All rights reserved. +// + +#import + +@interface WifiViewController : UIViewController + +@end diff --git a/ios/IOSDuoduo/VC/WifiViewController.m b/ios/IOSDuoduo/VC/WifiViewController.m new file mode 100644 index 000000000..a93b1db96 --- /dev/null +++ b/ios/IOSDuoduo/VC/WifiViewController.m @@ -0,0 +1,44 @@ +// +// WifiViewController.m +// TeamTalk +// +// Created by 独嘉 on 14-10-22. +// Copyright (c) 2014年 dujia. All rights reserved. +// + +#import "WifiViewController.h" + +@interface WifiViewController () + +@end + +@implementation WifiViewController + +{ + UIWebView* _webView; + UIActivityIndicatorView* _activityIndicatorView; +} +- (void)viewDidLoad { + [super viewDidLoad]; + self.title=@"街利贷"; + _webView = [[UIWebView alloc] initWithFrame:self.view.bounds]; + [self.view addSubview:_webView]; + NSURL* url = [NSURL URLWithString:@"https://f.mogujie.com/p2p/home/investment"]; + NSURLRequest* urlRequest = [NSURLRequest requestWithURL:url]; + [_webView loadRequest:urlRequest]; + [_webView setDelegate:self]; + // Do any additional setup after loading the view. +} + +- (void)didReceiveMemoryWarning { + [super didReceiveMemoryWarning]; + // Dispose of any resources that can be recreated. +} + +- (void)webViewDidFinishLoad:(UIWebView *)webView +{ + [_activityIndicatorView stopAnimating]; +} + + +@end diff --git a/ios/IOSDuoduo/VC/minus-sign.png b/ios/IOSDuoduo/VC/minus-sign.png new file mode 100644 index 000000000..33d66041c Binary files /dev/null and b/ios/IOSDuoduo/VC/minus-sign.png differ diff --git a/ios/IOSDuoduo/Voice/Code/Libs/config.h b/ios/IOSDuoduo/Voice/Code/Libs/config.h new file mode 100755 index 000000000..687efc3c1 --- /dev/null +++ b/ios/IOSDuoduo/Voice/Code/Libs/config.h @@ -0,0 +1,168 @@ +/* config.h. Generated from config.h.in by configure. */ +/* config.h.in. Generated from configure.ac by autoheader. */ + +/* Make use of ARM4 assembly optimizations */ +/* #undef ARM4_ASM */ + +/* Make use of ARM5E assembly optimizations */ +/* #undef ARM5E_ASM */ + +/* Make use of Blackfin assembly optimizations */ +/* #undef BFIN_ASM */ + +/* Disable all parts of the API that are using floats */ +/* #undef DISABLE_FLOAT_API */ + +/* Disable VBR and VAD from the codec */ +/* #undef DISABLE_VBR */ + +/* Enable valgrind extra checks */ +/* #undef ENABLE_VALGRIND */ + +/* Symbol visibility prefix */ +#define EXPORT __attribute__((visibility("default"))) + +/* Debug fixed-point implementation */ +/* #undef FIXED_DEBUG */ + +/* Compile as fixed-point */ +#define FIXED_POINT + +/* Compile as floating-point */ +/*#define FLOATING_POINT */ + +/* Define to 1 if you have the header file. */ +#define HAVE_ALLOCA_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_DLFCN_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_GETOPT_H 1 + +/* Define to 1 if you have the `getopt_long' function. */ +#define HAVE_GETOPT_LONG 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_INTTYPES_H 1 + +/* Define to 1 if you have the `m' library (-lm). */ +#define HAVE_LIBM 1 + +/* Define to 1 if you have the `winmm' library (-lwinmm). */ +/* #undef HAVE_LIBWINMM */ + +/* Define to 1 if you have the header file. */ +#define HAVE_MEMORY_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_STDINT_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_STDLIB_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_STRINGS_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_STRING_H 1 + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_SYS_AUDIOIO_H */ + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_SYS_SOUNDCARD_H */ + +/* Define to 1 if you have the header file. */ +#define HAVE_SYS_STAT_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_SYS_TYPES_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_UNISTD_H 1 + +/* Define to the address where bug reports for this package should be sent. */ +#define PACKAGE_BUGREPORT "" + +/* Define to the full name of this package. */ +#define PACKAGE_NAME "" + +/* Define to the full name and version of this package. */ +#define PACKAGE_STRING "" + +/* Define to the one symbol short name of this package. */ +#define PACKAGE_TARNAME "" + +/* Define to the version of this package. */ +#define PACKAGE_VERSION "" + +/* The size of `int', as computed by sizeof. */ +#define SIZEOF_INT 4 + +/* The size of `long', as computed by sizeof. */ +#define SIZEOF_LONG 8 + +/* The size of `short', as computed by sizeof. */ +#define SIZEOF_SHORT 2 + + +/* Version extra */ +#define SPEEX_EXTRA_VERSION "" + +/* Version major */ +#define SPEEX_MAJOR_VERSION 1 + +/* Version micro */ +/* #define SPEEX_MICRO_VERSION 16 */ + +/* Version minor */ +#define SPEEX_MINOR_VERSION 1 + +/* Complete version string */ +/* #define SPEEX_VERSION "1.2rc1" */ + + +/* Define to 1 if you have the ANSI C header files. */ +#define STDC_HEADERS 1 + +/* Enable support for TI C55X DSP */ +/* #undef TI_C55X */ + +/* Make use of alloca */ +/* #undef USE_ALLOCA */ + +/* Use FFTW3 for FFT */ +/* #undef USE_GPL_FFTW3 */ + +/* Use Intel Math Kernel Library for FFT */ +/* #undef USE_INTEL_MKL */ + +/* Use KISS Fast Fourier Transform */ +/* #undef USE_KISS_FFT */ + +/* Use FFT from OggVorbis */ +#define USE_SMALLFT + +/* Use C99 variable-size arrays */ +#define VAR_ARRAYS + +/* Define to 1 if your processor stores words with the most significant byte + first (like Motorola and SPARC, unlike Intel and VAX). */ +/* #undef WORDS_BIGENDIAN */ + +/* Enable SSE support */ +/*#define _USE_SSE */ + +/* Define to empty if `const' does not conform to ANSI C. */ +/* #undef const */ + +/* Define to `__inline__' or `__inline' if that's what the C compiler + calls it, or to nothing if 'inline' is not supported under any name. */ +#ifndef __cplusplus +/* #undef inline */ +#endif + +/* Define to equivalent of C99 restrict keyword, or to nothing if this is not + supported. Do not define if restrict is supported directly. */ +#define restrict __restrict diff --git a/ios/IOSDuoduo/Voice/Code/Libs/libogg/bitwise.c b/ios/IOSDuoduo/Voice/Code/Libs/libogg/bitwise.c new file mode 100755 index 000000000..b1ffbd16c --- /dev/null +++ b/ios/IOSDuoduo/Voice/Code/Libs/libogg/bitwise.c @@ -0,0 +1,857 @@ +/******************************************************************** + * * + * THIS FILE IS PART OF THE Ogg CONTAINER SOURCE CODE. * + * USE, DISTRIBUTION AND REPRODUCTION OF THIS LIBRARY SOURCE IS * + * GOVERNED BY A BSD-STYLE SOURCE LICENSE INCLUDED WITH THIS SOURCE * + * IN 'COPYING'. PLEASE READ THESE TERMS BEFORE DISTRIBUTING. * + * * + * THE OggVorbis SOURCE CODE IS (C) COPYRIGHT 1994-2010 * + * by the Xiph.Org Foundation http://www.xiph.org/ * + * * + ******************************************************************** + + function: packing variable sized words into an octet stream + last mod: $Id: bitwise.c 18051 2011-08-04 17:56:39Z giles $ + + ********************************************************************/ + +/* We're 'LSb' endian; if we write a word but read individual bits, + then we'll read the lsb first */ + +#include +#include +#include +#include "ogg.h" + +#define BUFFER_INCREMENT 256 + +static const unsigned long mask[]= +{0x00000000,0x00000001,0x00000003,0x00000007,0x0000000f, + 0x0000001f,0x0000003f,0x0000007f,0x000000ff,0x000001ff, + 0x000003ff,0x000007ff,0x00000fff,0x00001fff,0x00003fff, + 0x00007fff,0x0000ffff,0x0001ffff,0x0003ffff,0x0007ffff, + 0x000fffff,0x001fffff,0x003fffff,0x007fffff,0x00ffffff, + 0x01ffffff,0x03ffffff,0x07ffffff,0x0fffffff,0x1fffffff, + 0x3fffffff,0x7fffffff,0xffffffff }; + +static const unsigned int mask8B[]= +{0x00,0x80,0xc0,0xe0,0xf0,0xf8,0xfc,0xfe,0xff}; + +void oggpack_writeinit(oggpack_buffer *b){ + memset(b,0,sizeof(*b)); + b->ptr=b->buffer=_ogg_malloc(BUFFER_INCREMENT); + b->buffer[0]='\0'; + b->storage=BUFFER_INCREMENT; +} + +void oggpackB_writeinit(oggpack_buffer *b){ + oggpack_writeinit(b); +} + +int oggpack_writecheck(oggpack_buffer *b){ + if(!b->ptr || !b->storage)return -1; + return 0; +} + +int oggpackB_writecheck(oggpack_buffer *b){ + return oggpack_writecheck(b); +} + +void oggpack_writetrunc(oggpack_buffer *b,long bits){ + long bytes=bits>>3; + if(b->ptr){ + bits-=bytes*8; + b->ptr=b->buffer+bytes; + b->endbit=bits; + b->endbyte=bytes; + *b->ptr&=mask[bits]; + } +} + +void oggpackB_writetrunc(oggpack_buffer *b,long bits){ + long bytes=bits>>3; + if(b->ptr){ + bits-=bytes*8; + b->ptr=b->buffer+bytes; + b->endbit=bits; + b->endbyte=bytes; + *b->ptr&=mask8B[bits]; + } +} + +/* Takes only up to 32 bits. */ +void oggpack_write(oggpack_buffer *b,unsigned long value,int bits){ + if(bits<0 || bits>32) goto err; + if(b->endbyte>=b->storage-4){ + void *ret; + if(!b->ptr)return; + if(b->storage>LONG_MAX-BUFFER_INCREMENT) goto err; + ret=_ogg_realloc(b->buffer,b->storage+BUFFER_INCREMENT); + if(!ret) goto err; + b->buffer=ret; + b->storage+=BUFFER_INCREMENT; + b->ptr=b->buffer+b->endbyte; + } + + value&=mask[bits]; + bits+=b->endbit; + + b->ptr[0]|=value<endbit; + + if(bits>=8){ + b->ptr[1]=(unsigned char)(value>>(8-b->endbit)); + if(bits>=16){ + b->ptr[2]=(unsigned char)(value>>(16-b->endbit)); + if(bits>=24){ + b->ptr[3]=(unsigned char)(value>>(24-b->endbit)); + if(bits>=32){ + if(b->endbit) + b->ptr[4]=(unsigned char)(value>>(32-b->endbit)); + else + b->ptr[4]=0; + } + } + } + } + + b->endbyte+=bits/8; + b->ptr+=bits/8; + b->endbit=bits&7; + return; + err: + oggpack_writeclear(b); +} + +/* Takes only up to 32 bits. */ +void oggpackB_write(oggpack_buffer *b,unsigned long value,int bits){ + if(bits<0 || bits>32) goto err; + if(b->endbyte>=b->storage-4){ + void *ret; + if(!b->ptr)return; + if(b->storage>LONG_MAX-BUFFER_INCREMENT) goto err; + ret=_ogg_realloc(b->buffer,b->storage+BUFFER_INCREMENT); + if(!ret) goto err; + b->buffer=ret; + b->storage+=BUFFER_INCREMENT; + b->ptr=b->buffer+b->endbyte; + } + + value=(value&mask[bits])<<(32-bits); + bits+=b->endbit; + + b->ptr[0]|=value>>(24+b->endbit); + + if(bits>=8){ + b->ptr[1]=(unsigned char)(value>>(16+b->endbit)); + if(bits>=16){ + b->ptr[2]=(unsigned char)(value>>(8+b->endbit)); + if(bits>=24){ + b->ptr[3]=(unsigned char)(value>>(b->endbit)); + if(bits>=32){ + if(b->endbit) + b->ptr[4]=(unsigned char)(value<<(8-b->endbit)); + else + b->ptr[4]=0; + } + } + } + } + + b->endbyte+=bits/8; + b->ptr+=bits/8; + b->endbit=bits&7; + return; + err: + oggpack_writeclear(b); +} + +void oggpack_writealign(oggpack_buffer *b){ + int bits=8-b->endbit; + if(bits<8) + oggpack_write(b,0,bits); +} + +void oggpackB_writealign(oggpack_buffer *b){ + int bits=8-b->endbit; + if(bits<8) + oggpackB_write(b,0,bits); +} + +static void oggpack_writecopy_helper(oggpack_buffer *b, + void *source, + long bits, + void (*w)(oggpack_buffer *, + unsigned long, + int), + int msb){ + unsigned char *ptr=(unsigned char *)source; + + long bytes=bits/8; + bits-=bytes*8; + + if(b->endbit){ + int i; + /* unaligned copy. Do it the hard way. */ + for(i=0;iendbyte+bytes+1>=b->storage){ + void *ret; + if(!b->ptr) goto err; + if(b->endbyte+bytes+BUFFER_INCREMENT>b->storage) goto err; + b->storage=b->endbyte+bytes+BUFFER_INCREMENT; + ret=_ogg_realloc(b->buffer,b->storage); + if(!ret) goto err; + b->buffer=ret; + b->ptr=b->buffer+b->endbyte; + } + + memmove(b->ptr,source,bytes); + b->ptr+=bytes; + b->endbyte+=bytes; + *b->ptr=0; + + } + if(bits){ + if(msb) + w(b,(unsigned long)(ptr[bytes]>>(8-bits)),bits); + else + w(b,(unsigned long)(ptr[bytes]),bits); + } + return; + err: + oggpack_writeclear(b); +} + +void oggpack_writecopy(oggpack_buffer *b,void *source,long bits){ + oggpack_writecopy_helper(b,source,bits,oggpack_write,0); +} + +void oggpackB_writecopy(oggpack_buffer *b,void *source,long bits){ + oggpack_writecopy_helper(b,source,bits,oggpackB_write,1); +} + +void oggpack_reset(oggpack_buffer *b){ + if(!b->ptr)return; + b->ptr=b->buffer; + b->buffer[0]=0; + b->endbit=b->endbyte=0; +} + +void oggpackB_reset(oggpack_buffer *b){ + oggpack_reset(b); +} + +void oggpack_writeclear(oggpack_buffer *b){ + if(b->buffer)_ogg_free(b->buffer); + memset(b,0,sizeof(*b)); +} + +void oggpackB_writeclear(oggpack_buffer *b){ + oggpack_writeclear(b); +} + +void oggpack_readinit(oggpack_buffer *b,unsigned char *buf,int bytes){ + memset(b,0,sizeof(*b)); + b->buffer=b->ptr=buf; + b->storage=bytes; +} + +void oggpackB_readinit(oggpack_buffer *b,unsigned char *buf,int bytes){ + oggpack_readinit(b,buf,bytes); +} + +/* Read in bits without advancing the bitptr; bits <= 32 */ +long oggpack_look(oggpack_buffer *b,int bits){ + unsigned long ret; + unsigned long m; + + if(bits<0 || bits>32) return -1; + m=mask[bits]; + bits+=b->endbit; + + if(b->endbyte >= b->storage-4){ + /* not the main path */ + if(b->endbyte > b->storage-((bits+7)>>3)) return -1; + /* special case to avoid reading b->ptr[0], which might be past the end of + the buffer; also skips some useless accounting */ + else if(!bits)return(0L); + } + + ret=b->ptr[0]>>b->endbit; + if(bits>8){ + ret|=b->ptr[1]<<(8-b->endbit); + if(bits>16){ + ret|=b->ptr[2]<<(16-b->endbit); + if(bits>24){ + ret|=b->ptr[3]<<(24-b->endbit); + if(bits>32 && b->endbit) + ret|=b->ptr[4]<<(32-b->endbit); + } + } + } + return(m&ret); +} + +/* Read in bits without advancing the bitptr; bits <= 32 */ +long oggpackB_look(oggpack_buffer *b,int bits){ + unsigned long ret; + int m=32-bits; + + if(m<0 || m>32) return -1; + bits+=b->endbit; + + if(b->endbyte >= b->storage-4){ + /* not the main path */ + if(b->endbyte > b->storage-((bits+7)>>3)) return -1; + /* special case to avoid reading b->ptr[0], which might be past the end of + the buffer; also skips some useless accounting */ + else if(!bits)return(0L); + } + + ret=b->ptr[0]<<(24+b->endbit); + if(bits>8){ + ret|=b->ptr[1]<<(16+b->endbit); + if(bits>16){ + ret|=b->ptr[2]<<(8+b->endbit); + if(bits>24){ + ret|=b->ptr[3]<<(b->endbit); + if(bits>32 && b->endbit) + ret|=b->ptr[4]>>(8-b->endbit); + } + } + } + return ((ret&0xffffffff)>>(m>>1))>>((m+1)>>1); +} + +long oggpack_look1(oggpack_buffer *b){ + if(b->endbyte>=b->storage)return(-1); + return((b->ptr[0]>>b->endbit)&1); +} + +long oggpackB_look1(oggpack_buffer *b){ + if(b->endbyte>=b->storage)return(-1); + return((b->ptr[0]>>(7-b->endbit))&1); +} + +void oggpack_adv(oggpack_buffer *b,int bits){ + bits+=b->endbit; + + if(b->endbyte > b->storage-((bits+7)>>3)) goto overflow; + + b->ptr+=bits/8; + b->endbyte+=bits/8; + b->endbit=bits&7; + return; + + overflow: + b->ptr=NULL; + b->endbyte=b->storage; + b->endbit=1; +} + +void oggpackB_adv(oggpack_buffer *b,int bits){ + oggpack_adv(b,bits); +} + +void oggpack_adv1(oggpack_buffer *b){ + if(++(b->endbit)>7){ + b->endbit=0; + b->ptr++; + b->endbyte++; + } +} + +void oggpackB_adv1(oggpack_buffer *b){ + oggpack_adv1(b); +} + +/* bits <= 32 */ +long oggpack_read(oggpack_buffer *b,int bits){ + long ret; + unsigned long m; + + if(bits<0 || bits>32) goto err; + m=mask[bits]; + bits+=b->endbit; + + if(b->endbyte >= b->storage-4){ + /* not the main path */ + if(b->endbyte > b->storage-((bits+7)>>3)) goto overflow; + /* special case to avoid reading b->ptr[0], which might be past the end of + the buffer; also skips some useless accounting */ + else if(!bits)return(0L); + } + + ret=b->ptr[0]>>b->endbit; + if(bits>8){ + ret|=b->ptr[1]<<(8-b->endbit); + if(bits>16){ + ret|=b->ptr[2]<<(16-b->endbit); + if(bits>24){ + ret|=b->ptr[3]<<(24-b->endbit); + if(bits>32 && b->endbit){ + ret|=b->ptr[4]<<(32-b->endbit); + } + } + } + } + ret&=m; + b->ptr+=bits/8; + b->endbyte+=bits/8; + b->endbit=bits&7; + return ret; + + overflow: + err: + b->ptr=NULL; + b->endbyte=b->storage; + b->endbit=1; + return -1L; +} + +/* bits <= 32 */ +long oggpackB_read(oggpack_buffer *b,int bits){ + long ret; + long m=32-bits; + + if(m<0 || m>32) goto err; + bits+=b->endbit; + + if(b->endbyte+4>=b->storage){ + /* not the main path */ + if(b->endbyte > b->storage-((bits+7)>>3)) goto overflow; + /* special case to avoid reading b->ptr[0], which might be past the end of + the buffer; also skips some useless accounting */ + else if(!bits)return(0L); + } + + ret=b->ptr[0]<<(24+b->endbit); + if(bits>8){ + ret|=b->ptr[1]<<(16+b->endbit); + if(bits>16){ + ret|=b->ptr[2]<<(8+b->endbit); + if(bits>24){ + ret|=b->ptr[3]<<(b->endbit); + if(bits>32 && b->endbit) + ret|=b->ptr[4]>>(8-b->endbit); + } + } + } + ret=((ret&0xffffffffUL)>>(m>>1))>>((m+1)>>1); + + b->ptr+=bits/8; + b->endbyte+=bits/8; + b->endbit=bits&7; + return ret; + + overflow: + err: + b->ptr=NULL; + b->endbyte=b->storage; + b->endbit=1; + return -1L; +} + +long oggpack_read1(oggpack_buffer *b){ + long ret; + + if(b->endbyte >= b->storage) goto overflow; + ret=(b->ptr[0]>>b->endbit)&1; + + b->endbit++; + if(b->endbit>7){ + b->endbit=0; + b->ptr++; + b->endbyte++; + } + return ret; + + overflow: + b->ptr=NULL; + b->endbyte=b->storage; + b->endbit=1; + return -1L; +} + +long oggpackB_read1(oggpack_buffer *b){ + long ret; + + if(b->endbyte >= b->storage) goto overflow; + ret=(b->ptr[0]>>(7-b->endbit))&1; + + b->endbit++; + if(b->endbit>7){ + b->endbit=0; + b->ptr++; + b->endbyte++; + } + return ret; + + overflow: + b->ptr=NULL; + b->endbyte=b->storage; + b->endbit=1; + return -1L; +} + +long oggpack_bytes(oggpack_buffer *b){ + return(b->endbyte+(b->endbit+7)/8); +} + +long oggpack_bits(oggpack_buffer *b){ + return(b->endbyte*8+b->endbit); +} + +long oggpackB_bytes(oggpack_buffer *b){ + return oggpack_bytes(b); +} + +long oggpackB_bits(oggpack_buffer *b){ + return oggpack_bits(b); +} + +unsigned char *oggpack_get_buffer(oggpack_buffer *b){ + return(b->buffer); +} + +unsigned char *oggpackB_get_buffer(oggpack_buffer *b){ + return oggpack_get_buffer(b); +} + +/* Self test of the bitwise routines; everything else is based on + them, so they damned well better be solid. */ + +#ifdef _V_SELFTEST +#include + +static int ilog(unsigned int v){ + int ret=0; + while(v){ + ret++; + v>>=1; + } + return(ret); +} + +oggpack_buffer o; +oggpack_buffer r; + +void report(char *in){ + fprintf(stderr,"%s",in); + exit(1); +} + +void cliptest(unsigned long *b,int vals,int bits,int *comp,int compsize){ + long bytes,i; + unsigned char *buffer; + + oggpack_reset(&o); + for(i=0;i +#include +#include "ogg.h" + +/* A complete description of Ogg framing exists in docs/framing.html */ + +int ogg_page_version(const ogg_page *og){ + return((int)(og->header[4])); +} + +int ogg_page_continued(const ogg_page *og){ + return((int)(og->header[5]&0x01)); +} + +int ogg_page_bos(const ogg_page *og){ + return((int)(og->header[5]&0x02)); +} + +int ogg_page_eos(const ogg_page *og){ + return((int)(og->header[5]&0x04)); +} + +ogg_int64_t ogg_page_granulepos(const ogg_page *og){ + unsigned char *page=og->header; + ogg_int64_t granulepos=page[13]&(0xff); + granulepos= (granulepos<<8)|(page[12]&0xff); + granulepos= (granulepos<<8)|(page[11]&0xff); + granulepos= (granulepos<<8)|(page[10]&0xff); + granulepos= (granulepos<<8)|(page[9]&0xff); + granulepos= (granulepos<<8)|(page[8]&0xff); + granulepos= (granulepos<<8)|(page[7]&0xff); + granulepos= (granulepos<<8)|(page[6]&0xff); + return(granulepos); +} + +int ogg_page_serialno(const ogg_page *og){ + return(og->header[14] | + (og->header[15]<<8) | + (og->header[16]<<16) | + (og->header[17]<<24)); +} + +long ogg_page_pageno(const ogg_page *og){ + return(og->header[18] | + (og->header[19]<<8) | + (og->header[20]<<16) | + (og->header[21]<<24)); +} + + + +/* returns the number of packets that are completed on this page (if + the leading packet is begun on a previous page, but ends on this + page, it's counted */ + +/* NOTE: + If a page consists of a packet begun on a previous page, and a new + packet begun (but not completed) on this page, the return will be: + ogg_page_packets(page) ==1, + ogg_page_continued(page) !=0 + + If a page happens to be a single packet that was begun on a + previous page, and spans to the next page (in the case of a three or + more page packet), the return will be: + ogg_page_packets(page) ==0, + ogg_page_continued(page) !=0 +*/ + +int ogg_page_packets(const ogg_page *og){ + int i,n=og->header[26],count=0; + for(i=0;iheader[27+i]<255)count++; + return(count); +} + + +#if 0 +/* helper to initialize lookup for direct-table CRC (illustrative; we + use the static init below) */ + +static ogg_uint32_t _ogg_crc_entry(unsigned long index){ + int i; + unsigned long r; + + r = index << 24; + for (i=0; i<8; i++) + if (r & 0x80000000UL) + r = (r << 1) ^ 0x04c11db7; /* The same as the ethernet generator + polynomial, although we use an + unreflected alg and an init/final + of 0, not 0xffffffff */ + else + r<<=1; + return (r & 0xffffffffUL); +} +#endif + +static const ogg_uint32_t crc_lookup[256]={ + 0x00000000,0x04c11db7,0x09823b6e,0x0d4326d9, + 0x130476dc,0x17c56b6b,0x1a864db2,0x1e475005, + 0x2608edb8,0x22c9f00f,0x2f8ad6d6,0x2b4bcb61, + 0x350c9b64,0x31cd86d3,0x3c8ea00a,0x384fbdbd, + 0x4c11db70,0x48d0c6c7,0x4593e01e,0x4152fda9, + 0x5f15adac,0x5bd4b01b,0x569796c2,0x52568b75, + 0x6a1936c8,0x6ed82b7f,0x639b0da6,0x675a1011, + 0x791d4014,0x7ddc5da3,0x709f7b7a,0x745e66cd, + 0x9823b6e0,0x9ce2ab57,0x91a18d8e,0x95609039, + 0x8b27c03c,0x8fe6dd8b,0x82a5fb52,0x8664e6e5, + 0xbe2b5b58,0xbaea46ef,0xb7a96036,0xb3687d81, + 0xad2f2d84,0xa9ee3033,0xa4ad16ea,0xa06c0b5d, + 0xd4326d90,0xd0f37027,0xddb056fe,0xd9714b49, + 0xc7361b4c,0xc3f706fb,0xceb42022,0xca753d95, + 0xf23a8028,0xf6fb9d9f,0xfbb8bb46,0xff79a6f1, + 0xe13ef6f4,0xe5ffeb43,0xe8bccd9a,0xec7dd02d, + 0x34867077,0x30476dc0,0x3d044b19,0x39c556ae, + 0x278206ab,0x23431b1c,0x2e003dc5,0x2ac12072, + 0x128e9dcf,0x164f8078,0x1b0ca6a1,0x1fcdbb16, + 0x018aeb13,0x054bf6a4,0x0808d07d,0x0cc9cdca, + 0x7897ab07,0x7c56b6b0,0x71159069,0x75d48dde, + 0x6b93dddb,0x6f52c06c,0x6211e6b5,0x66d0fb02, + 0x5e9f46bf,0x5a5e5b08,0x571d7dd1,0x53dc6066, + 0x4d9b3063,0x495a2dd4,0x44190b0d,0x40d816ba, + 0xaca5c697,0xa864db20,0xa527fdf9,0xa1e6e04e, + 0xbfa1b04b,0xbb60adfc,0xb6238b25,0xb2e29692, + 0x8aad2b2f,0x8e6c3698,0x832f1041,0x87ee0df6, + 0x99a95df3,0x9d684044,0x902b669d,0x94ea7b2a, + 0xe0b41de7,0xe4750050,0xe9362689,0xedf73b3e, + 0xf3b06b3b,0xf771768c,0xfa325055,0xfef34de2, + 0xc6bcf05f,0xc27dede8,0xcf3ecb31,0xcbffd686, + 0xd5b88683,0xd1799b34,0xdc3abded,0xd8fba05a, + 0x690ce0ee,0x6dcdfd59,0x608edb80,0x644fc637, + 0x7a089632,0x7ec98b85,0x738aad5c,0x774bb0eb, + 0x4f040d56,0x4bc510e1,0x46863638,0x42472b8f, + 0x5c007b8a,0x58c1663d,0x558240e4,0x51435d53, + 0x251d3b9e,0x21dc2629,0x2c9f00f0,0x285e1d47, + 0x36194d42,0x32d850f5,0x3f9b762c,0x3b5a6b9b, + 0x0315d626,0x07d4cb91,0x0a97ed48,0x0e56f0ff, + 0x1011a0fa,0x14d0bd4d,0x19939b94,0x1d528623, + 0xf12f560e,0xf5ee4bb9,0xf8ad6d60,0xfc6c70d7, + 0xe22b20d2,0xe6ea3d65,0xeba91bbc,0xef68060b, + 0xd727bbb6,0xd3e6a601,0xdea580d8,0xda649d6f, + 0xc423cd6a,0xc0e2d0dd,0xcda1f604,0xc960ebb3, + 0xbd3e8d7e,0xb9ff90c9,0xb4bcb610,0xb07daba7, + 0xae3afba2,0xaafbe615,0xa7b8c0cc,0xa379dd7b, + 0x9b3660c6,0x9ff77d71,0x92b45ba8,0x9675461f, + 0x8832161a,0x8cf30bad,0x81b02d74,0x857130c3, + 0x5d8a9099,0x594b8d2e,0x5408abf7,0x50c9b640, + 0x4e8ee645,0x4a4ffbf2,0x470cdd2b,0x43cdc09c, + 0x7b827d21,0x7f436096,0x7200464f,0x76c15bf8, + 0x68860bfd,0x6c47164a,0x61043093,0x65c52d24, + 0x119b4be9,0x155a565e,0x18197087,0x1cd86d30, + 0x029f3d35,0x065e2082,0x0b1d065b,0x0fdc1bec, + 0x3793a651,0x3352bbe6,0x3e119d3f,0x3ad08088, + 0x2497d08d,0x2056cd3a,0x2d15ebe3,0x29d4f654, + 0xc5a92679,0xc1683bce,0xcc2b1d17,0xc8ea00a0, + 0xd6ad50a5,0xd26c4d12,0xdf2f6bcb,0xdbee767c, + 0xe3a1cbc1,0xe760d676,0xea23f0af,0xeee2ed18, + 0xf0a5bd1d,0xf464a0aa,0xf9278673,0xfde69bc4, + 0x89b8fd09,0x8d79e0be,0x803ac667,0x84fbdbd0, + 0x9abc8bd5,0x9e7d9662,0x933eb0bb,0x97ffad0c, + 0xafb010b1,0xab710d06,0xa6322bdf,0xa2f33668, + 0xbcb4666d,0xb8757bda,0xb5365d03,0xb1f740b4}; + +/* init the encode/decode logical stream state */ + +int ogg_stream_init(ogg_stream_state *os,int serialno){ + if(os){ + memset(os,0,sizeof(*os)); + os->body_storage=16*1024; + os->lacing_storage=1024; + + os->body_data=_ogg_malloc(os->body_storage*sizeof(*os->body_data)); + os->lacing_vals=_ogg_malloc(os->lacing_storage*sizeof(*os->lacing_vals)); + os->granule_vals=_ogg_malloc(os->lacing_storage*sizeof(*os->granule_vals)); + + if(!os->body_data || !os->lacing_vals || !os->granule_vals){ + ogg_stream_clear(os); + return -1; + } + + os->serialno=serialno; + + return(0); + } + return(-1); +} + +/* async/delayed error detection for the ogg_stream_state */ +int ogg_stream_check(ogg_stream_state *os){ + if(!os || !os->body_data) return -1; + return 0; +} + +/* _clear does not free os, only the non-flat storage within */ +int ogg_stream_clear(ogg_stream_state *os){ + if(os){ + if(os->body_data)_ogg_free(os->body_data); + if(os->lacing_vals)_ogg_free(os->lacing_vals); + if(os->granule_vals)_ogg_free(os->granule_vals); + + memset(os,0,sizeof(*os)); + } + return(0); +} + +int ogg_stream_destroy(ogg_stream_state *os){ + if(os){ + ogg_stream_clear(os); + _ogg_free(os); + } + return(0); +} + +/* Helpers for ogg_stream_encode; this keeps the structure and + what's happening fairly clear */ + +static int _os_body_expand(ogg_stream_state *os,int needed){ + if(os->body_storage<=os->body_fill+needed){ + void *ret; + ret=_ogg_realloc(os->body_data,(os->body_storage+needed+1024)* + sizeof(*os->body_data)); + if(!ret){ + ogg_stream_clear(os); + return -1; + } + os->body_storage+=(needed+1024); + os->body_data=ret; + } + return 0; +} + +static int _os_lacing_expand(ogg_stream_state *os,int needed){ + if(os->lacing_storage<=os->lacing_fill+needed){ + void *ret; + ret=_ogg_realloc(os->lacing_vals,(os->lacing_storage+needed+32)* + sizeof(*os->lacing_vals)); + if(!ret){ + ogg_stream_clear(os); + return -1; + } + os->lacing_vals=ret; + ret=_ogg_realloc(os->granule_vals,(os->lacing_storage+needed+32)* + sizeof(*os->granule_vals)); + if(!ret){ + ogg_stream_clear(os); + return -1; + } + os->granule_vals=ret; + os->lacing_storage+=(needed+32); + } + return 0; +} + +/* checksum the page */ +/* Direct table CRC; note that this will be faster in the future if we + perform the checksum simultaneously with other copies */ + +void ogg_page_checksum_set(ogg_page *og){ + if(og){ + ogg_uint32_t crc_reg=0; + int i; + + /* safety; needed for API behavior, but not framing code */ + og->header[22]=0; + og->header[23]=0; + og->header[24]=0; + og->header[25]=0; + + for(i=0;iheader_len;i++) + crc_reg=(crc_reg<<8)^crc_lookup[((crc_reg >> 24)&0xff)^og->header[i]]; + for(i=0;ibody_len;i++) + crc_reg=(crc_reg<<8)^crc_lookup[((crc_reg >> 24)&0xff)^og->body[i]]; + + og->header[22]=(unsigned char)(crc_reg&0xff); + og->header[23]=(unsigned char)((crc_reg>>8)&0xff); + og->header[24]=(unsigned char)((crc_reg>>16)&0xff); + og->header[25]=(unsigned char)((crc_reg>>24)&0xff); + } +} + +/* submit data to the internal buffer of the framing engine */ +int ogg_stream_iovecin(ogg_stream_state *os, ogg_iovec_t *iov, int count, + long e_o_s, ogg_int64_t granulepos){ + + int bytes = 0, lacing_vals, i; + + if(ogg_stream_check(os)) return -1; + if(!iov) return 0; + + for (i = 0; i < count; ++i) bytes += (int)iov[i].iov_len; + lacing_vals=bytes/255+1; + + if(os->body_returned){ + /* advance packet data according to the body_returned pointer. We + had to keep it around to return a pointer into the buffer last + call */ + + os->body_fill-=os->body_returned; + if(os->body_fill) + memmove(os->body_data,os->body_data+os->body_returned, + os->body_fill); + os->body_returned=0; + } + + /* make sure we have the buffer storage */ + if(_os_body_expand(os,bytes) || _os_lacing_expand(os,lacing_vals)) + return -1; + + /* Copy in the submitted packet. Yes, the copy is a waste; this is + the liability of overly clean abstraction for the time being. It + will actually be fairly easy to eliminate the extra copy in the + future */ + + for (i = 0; i < count; ++i) { + memcpy(os->body_data+os->body_fill, iov[i].iov_base, iov[i].iov_len); + os->body_fill += (int)iov[i].iov_len; + } + + /* Store lacing vals for this packet */ + for(i=0;ilacing_vals[os->lacing_fill+i]=255; + os->granule_vals[os->lacing_fill+i]=os->granulepos; + } + os->lacing_vals[os->lacing_fill+i]=bytes%255; + os->granulepos=os->granule_vals[os->lacing_fill+i]=granulepos; + + /* flag the first segment as the beginning of the packet */ + os->lacing_vals[os->lacing_fill]|= 0x100; + + os->lacing_fill+=lacing_vals; + + /* for the sake of completeness */ + os->packetno++; + + if(e_o_s)os->e_o_s=1; + + return(0); +} + +int ogg_stream_packetin(ogg_stream_state *os,ogg_packet *op){ + ogg_iovec_t iov; + iov.iov_base = op->packet; + iov.iov_len = op->bytes; + return ogg_stream_iovecin(os, &iov, 1, op->e_o_s, op->granulepos); +} + +/* Conditionally flush a page; force==0 will only flush nominal-size + pages, force==1 forces us to flush a page regardless of page size + so long as there's any data available at all. */ +static int ogg_stream_flush_i(ogg_stream_state *os,ogg_page *og, int force, int nfill){ + int i; + int vals=0; + int maxvals=(os->lacing_fill>255?255:os->lacing_fill); + int bytes=0; + long acc=0; + ogg_int64_t granule_pos=-1; + + if(ogg_stream_check(os)) return(0); + if(maxvals==0) return(0); + + /* construct a page */ + /* decide how many segments to include */ + + /* If this is the initial header case, the first page must only include + the initial header packet */ + if(os->b_o_s==0){ /* 'initial header page' case */ + granule_pos=0; + for(vals=0;valslacing_vals[vals]&0x0ff)<255){ + vals++; + break; + } + } + }else{ + + /* The extra packets_done, packet_just_done logic here attempts to do two things: + 1) Don't unneccessarily span pages. + 2) Unless necessary, don't flush pages if there are less than four packets on + them; this expands page size to reduce unneccessary overhead if incoming packets + are large. + These are not necessary behaviors, just 'always better than naive flushing' + without requiring an application to explicitly request a specific optimized + behavior. We'll want an explicit behavior setup pathway eventually as well. */ + + int packets_done=0; + int packet_just_done=0; + for(vals=0;valsnfill && packet_just_done>=4){ + force=1; + break; + } + acc+=os->lacing_vals[vals]&0x0ff; + if((os->lacing_vals[vals]&0xff)<255){ + granule_pos=os->granule_vals[vals]; + packet_just_done=++packets_done; + }else + packet_just_done=0; + } + if(vals==255)force=1; + } + + if(!force) return(0); + + /* construct the header in temp storage */ + memcpy(os->header,"OggS",4); + + /* stream structure version */ + os->header[4]=0x00; + + /* continued packet flag? */ + os->header[5]=0x00; + if((os->lacing_vals[0]&0x100)==0)os->header[5]|=0x01; + /* first page flag? */ + if(os->b_o_s==0)os->header[5]|=0x02; + /* last page flag? */ + if(os->e_o_s && os->lacing_fill==vals)os->header[5]|=0x04; + os->b_o_s=1; + + /* 64 bits of PCM position */ + for(i=6;i<14;i++){ + os->header[i]=(unsigned char)(granule_pos&0xff); + granule_pos>>=8; + } + + /* 32 bits of stream serial number */ + { + long serialno=os->serialno; + for(i=14;i<18;i++){ + os->header[i]=(unsigned char)(serialno&0xff); + serialno>>=8; + } + } + + /* 32 bits of page counter (we have both counter and page header + because this val can roll over) */ + if(os->pageno==-1)os->pageno=0; /* because someone called + stream_reset; this would be a + strange thing to do in an + encode stream, but it has + plausible uses */ + { + long pageno=os->pageno++; + for(i=18;i<22;i++){ + os->header[i]=(unsigned char)(pageno&0xff); + pageno>>=8; + } + } + + /* zero for computation; filled in later */ + os->header[22]=0; + os->header[23]=0; + os->header[24]=0; + os->header[25]=0; + + /* segment table */ + os->header[26]=(unsigned char)(vals&0xff); + for(i=0;iheader[i+27]=(unsigned char)(os->lacing_vals[i]&0xff); + + /* set pointers in the ogg_page struct */ + og->header=os->header; + og->header_len=os->header_fill=vals+27; + og->body=os->body_data+os->body_returned; + og->body_len=bytes; + + /* advance the lacing data and set the body_returned pointer */ + + os->lacing_fill-=vals; + memmove(os->lacing_vals,os->lacing_vals+vals,os->lacing_fill*sizeof(*os->lacing_vals)); + memmove(os->granule_vals,os->granule_vals+vals,os->lacing_fill*sizeof(*os->granule_vals)); + os->body_returned+=bytes; + + /* calculate the checksum */ + + ogg_page_checksum_set(og); + + /* done */ + return(1); +} + +/* This will flush remaining packets into a page (returning nonzero), + even if there is not enough data to trigger a flush normally + (undersized page). If there are no packets or partial packets to + flush, ogg_stream_flush returns 0. Note that ogg_stream_flush will + try to flush a normal sized page like ogg_stream_pageout; a call to + ogg_stream_flush does not guarantee that all packets have flushed. + Only a return value of 0 from ogg_stream_flush indicates all packet + data is flushed into pages. + + since ogg_stream_flush will flush the last page in a stream even if + it's undersized, you almost certainly want to use ogg_stream_pageout + (and *not* ogg_stream_flush) unless you specifically need to flush + a page regardless of size in the middle of a stream. */ + +int ogg_stream_flush(ogg_stream_state *os,ogg_page *og){ + return ogg_stream_flush_i(os,og,1,4096); +} + +/* Like the above, but an argument is provided to adjust the nominal + page size for applications which are smart enough to provide their + own delay based flushing */ + +int ogg_stream_flush_fill(ogg_stream_state *os,ogg_page *og, int nfill){ + return ogg_stream_flush_i(os,og,1,nfill); +} + +/* This constructs pages from buffered packet segments. The pointers +returned are to static buffers; do not free. The returned buffers are +good only until the next call (using the same ogg_stream_state) */ + +int ogg_stream_pageout(ogg_stream_state *os, ogg_page *og){ + int force=0; + if(ogg_stream_check(os)) return 0; + + if((os->e_o_s&&os->lacing_fill) || /* 'were done, now flush' case */ + (os->lacing_fill&&!os->b_o_s)) /* 'initial header page' case */ + force=1; + + return(ogg_stream_flush_i(os,og,force,4096)); +} + +/* Like the above, but an argument is provided to adjust the nominal +page size for applications which are smart enough to provide their +own delay based flushing */ + +int ogg_stream_pageout_fill(ogg_stream_state *os, ogg_page *og, int nfill){ + int force=0; + if(ogg_stream_check(os)) return 0; + + if((os->e_o_s&&os->lacing_fill) || /* 'were done, now flush' case */ + (os->lacing_fill&&!os->b_o_s)) /* 'initial header page' case */ + force=1; + + return(ogg_stream_flush_i(os,og,force,nfill)); +} + +int ogg_stream_eos(ogg_stream_state *os){ + if(ogg_stream_check(os)) return 1; + return os->e_o_s; +} + +/* DECODING PRIMITIVES: packet streaming layer **********************/ + +/* This has two layers to place more of the multi-serialno and paging + control in the application's hands. First, we expose a data buffer + using ogg_sync_buffer(). The app either copies into the + buffer, or passes it directly to read(), etc. We then call + ogg_sync_wrote() to tell how many bytes we just added. + + Pages are returned (pointers into the buffer in ogg_sync_state) + by ogg_sync_pageout(). The page is then submitted to + ogg_stream_pagein() along with the appropriate + ogg_stream_state* (ie, matching serialno). We then get raw + packets out calling ogg_stream_packetout() with a + ogg_stream_state. */ + +/* initialize the struct to a known state */ +int ogg_sync_init(ogg_sync_state *oy){ + if(oy){ + oy->storage = -1; /* used as a readiness flag */ + memset(oy,0,sizeof(*oy)); + } + return(0); +} + +/* clear non-flat storage within */ +int ogg_sync_clear(ogg_sync_state *oy){ + if(oy){ + if(oy->data)_ogg_free(oy->data); + memset(oy,0,sizeof(*oy)); + } + return(0); +} + +int ogg_sync_destroy(ogg_sync_state *oy){ + if(oy){ + ogg_sync_clear(oy); + _ogg_free(oy); + } + return(0); +} + +int ogg_sync_check(ogg_sync_state *oy){ + if(oy->storage<0) return -1; + return 0; +} + +char *ogg_sync_buffer(ogg_sync_state *oy, long size){ + if(ogg_sync_check(oy)) return NULL; + + /* first, clear out any space that has been previously returned */ + if(oy->returned){ + oy->fill-=oy->returned; + if(oy->fill>0) + memmove(oy->data,oy->data+oy->returned,oy->fill); + oy->returned=0; + } + + if(size>oy->storage-oy->fill){ + /* We need to extend the internal buffer */ + long newsize=size+oy->fill+4096; /* an extra page to be nice */ + void *ret; + + if(oy->data) + ret=_ogg_realloc(oy->data,newsize); + else + ret=_ogg_malloc(newsize); + if(!ret){ + ogg_sync_clear(oy); + return NULL; + } + oy->data=ret; + oy->storage=newsize; + } + + /* expose a segment at least as large as requested at the fill mark */ + return((char *)oy->data+oy->fill); +} + +int ogg_sync_wrote(ogg_sync_state *oy, long bytes){ + if(ogg_sync_check(oy))return -1; + if(oy->fill+bytes>oy->storage)return -1; + oy->fill+=bytes; + return(0); +} + +/* sync the stream. This is meant to be useful for finding page + boundaries. + + return values for this: + -n) skipped n bytes + 0) page not ready; more data (no bytes skipped) + n) page synced at current location; page length n bytes + +*/ + +long ogg_sync_pageseek(ogg_sync_state *oy,ogg_page *og){ + unsigned char *page=oy->data+oy->returned; + unsigned char *next; + long bytes=oy->fill-oy->returned; + + if(ogg_sync_check(oy))return 0; + + if(oy->headerbytes==0){ + int headerbytes,i; + if(bytes<27)return(0); /* not enough for a header */ + + /* verify capture pattern */ + if(memcmp(page,"OggS",4))goto sync_fail; + + headerbytes=page[26]+27; + if(bytesbodybytes+=page[27+i]; + oy->headerbytes=headerbytes; + } + + if(oy->bodybytes+oy->headerbytes>bytes)return(0); + + /* The whole test page is buffered. Verify the checksum */ + { + /* Grab the checksum bytes, set the header field to zero */ + char chksum[4]; + ogg_page log; + + memcpy(chksum,page+22,4); + memset(page+22,0,4); + + /* set up a temp page struct and recompute the checksum */ + log.header=page; + log.header_len=oy->headerbytes; + log.body=page+oy->headerbytes; + log.body_len=oy->bodybytes; + ogg_page_checksum_set(&log); + + /* Compare */ + if(memcmp(chksum,page+22,4)){ + /* D'oh. Mismatch! Corrupt page (or miscapture and not a page + at all) */ + /* replace the computed checksum with the one actually read in */ + memcpy(page+22,chksum,4); + + /* Bad checksum. Lose sync */ + goto sync_fail; + } + } + + /* yes, have a whole page all ready to go */ + { + unsigned char *page=oy->data+oy->returned; + long bytes; + + if(og){ + og->header=page; + og->header_len=oy->headerbytes; + og->body=page+oy->headerbytes; + og->body_len=oy->bodybytes; + } + + oy->unsynced=0; + oy->returned+=(bytes=oy->headerbytes+oy->bodybytes); + oy->headerbytes=0; + oy->bodybytes=0; + return(bytes); + } + + sync_fail: + + oy->headerbytes=0; + oy->bodybytes=0; + + /* search for possible capture */ + next=memchr(page+1,'O',bytes-1); + if(!next) + next=oy->data+oy->fill; + + oy->returned=(int)(next-oy->data); + return((long)-(next-page)); +} + +/* sync the stream and get a page. Keep trying until we find a page. + Suppress 'sync errors' after reporting the first. + + return values: + -1) recapture (hole in data) + 0) need more data + 1) page returned + + Returns pointers into buffered data; invalidated by next call to + _stream, _clear, _init, or _buffer */ + +int ogg_sync_pageout(ogg_sync_state *oy, ogg_page *og){ + + if(ogg_sync_check(oy))return 0; + + /* all we need to do is verify a page at the head of the stream + buffer. If it doesn't verify, we look for the next potential + frame */ + + for(;;){ + long ret=ogg_sync_pageseek(oy,og); + if(ret>0){ + /* have a page */ + return(1); + } + if(ret==0){ + /* need more data */ + return(0); + } + + /* head did not start a synced page... skipped some bytes */ + if(!oy->unsynced){ + oy->unsynced=1; + return(-1); + } + + /* loop. keep looking */ + + } +} + +/* add the incoming page to the stream state; we decompose the page + into packet segments here as well. */ + +int ogg_stream_pagein(ogg_stream_state *os, ogg_page *og){ + unsigned char *header=og->header; + unsigned char *body=og->body; + long bodysize=og->body_len; + int segptr=0; + + int version=ogg_page_version(og); + int continued=ogg_page_continued(og); + int bos=ogg_page_bos(og); + int eos=ogg_page_eos(og); + ogg_int64_t granulepos=ogg_page_granulepos(og); + int serialno=ogg_page_serialno(og); + long pageno=ogg_page_pageno(og); + int segments=header[26]; + + if(ogg_stream_check(os)) return -1; + + /* clean up 'returned data' */ + { + long lr=os->lacing_returned; + long br=os->body_returned; + + /* body data */ + if(br){ + os->body_fill-=br; + if(os->body_fill) + memmove(os->body_data,os->body_data+br,os->body_fill); + os->body_returned=0; + } + + if(lr){ + /* segment table */ + if(os->lacing_fill-lr){ + memmove(os->lacing_vals,os->lacing_vals+lr, + (os->lacing_fill-lr)*sizeof(*os->lacing_vals)); + memmove(os->granule_vals,os->granule_vals+lr, + (os->lacing_fill-lr)*sizeof(*os->granule_vals)); + } + os->lacing_fill-=lr; + os->lacing_packet-=lr; + os->lacing_returned=0; + } + } + + /* check the serial number */ + if(serialno!=os->serialno)return(-1); + if(version>0)return(-1); + + if(_os_lacing_expand(os,segments+1)) return -1; + + /* are we in sequence? */ + if(pageno!=os->pageno){ + int i; + + /* unroll previous partial packet (if any) */ + for(i=os->lacing_packet;ilacing_fill;i++) + os->body_fill-=os->lacing_vals[i]&0xff; + os->lacing_fill=os->lacing_packet; + + /* make a note of dropped data in segment table */ + if(os->pageno!=-1){ + os->lacing_vals[os->lacing_fill++]=0x400; + os->lacing_packet++; + } + } + + /* are we a 'continued packet' page? If so, we may need to skip + some segments */ + if(continued){ + if(os->lacing_fill<1 || + os->lacing_vals[os->lacing_fill-1]==0x400){ + bos=0; + for(;segptrbody_data+os->body_fill,body,bodysize); + os->body_fill+=bodysize; + } + + { + int saved=-1; + while(segptrlacing_vals[os->lacing_fill]=val; + os->granule_vals[os->lacing_fill]=-1; + + if(bos){ + os->lacing_vals[os->lacing_fill]|=0x100; + bos=0; + } + + if(val<255)saved=os->lacing_fill; + + os->lacing_fill++; + segptr++; + + if(val<255)os->lacing_packet=os->lacing_fill; + } + + /* set the granulepos on the last granuleval of the last full packet */ + if(saved!=-1){ + os->granule_vals[saved]=granulepos; + } + + } + + if(eos){ + os->e_o_s=1; + if(os->lacing_fill>0) + os->lacing_vals[os->lacing_fill-1]|=0x200; + } + + os->pageno=pageno+1; + + return(0); +} + +/* clear things to an initial state. Good to call, eg, before seeking */ +int ogg_sync_reset(ogg_sync_state *oy){ + if(ogg_sync_check(oy))return -1; + + oy->fill=0; + oy->returned=0; + oy->unsynced=0; + oy->headerbytes=0; + oy->bodybytes=0; + return(0); +} + +int ogg_stream_reset(ogg_stream_state *os){ + if(ogg_stream_check(os)) return -1; + + os->body_fill=0; + os->body_returned=0; + + os->lacing_fill=0; + os->lacing_packet=0; + os->lacing_returned=0; + + os->header_fill=0; + + os->e_o_s=0; + os->b_o_s=0; + os->pageno=-1; + os->packetno=0; + os->granulepos=0; + + return(0); +} + +int ogg_stream_reset_serialno(ogg_stream_state *os,int serialno){ + if(ogg_stream_check(os)) return -1; + ogg_stream_reset(os); + os->serialno=serialno; + return(0); +} + +static int _packetout(ogg_stream_state *os,ogg_packet *op,int adv){ + + /* The last part of decode. We have the stream broken into packet + segments. Now we need to group them into packets (or return the + out of sync markers) */ + + int ptr=os->lacing_returned; + + if(os->lacing_packet<=ptr)return(0); + + if(os->lacing_vals[ptr]&0x400){ + /* we need to tell the codec there's a gap; it might need to + handle previous packet dependencies. */ + os->lacing_returned++; + os->packetno++; + return(-1); + } + + if(!op && !adv)return(1); /* just using peek as an inexpensive way + to ask if there's a whole packet + waiting */ + + /* Gather the whole packet. We'll have no holes or a partial packet */ + { + int size=os->lacing_vals[ptr]&0xff; + long bytes=size; + int eos=os->lacing_vals[ptr]&0x200; /* last packet of the stream? */ + int bos=os->lacing_vals[ptr]&0x100; /* first packet of the stream? */ + + while(size==255){ + int val=os->lacing_vals[++ptr]; + size=val&0xff; + if(val&0x200)eos=0x200; + bytes+=size; + } + + if(op){ + op->e_o_s=eos; + op->b_o_s=bos; + op->packet=os->body_data+os->body_returned; + op->packetno=os->packetno; + op->granulepos=os->granule_vals[ptr]; + op->bytes=bytes; + } + + if(adv){ + os->body_returned+=bytes; + os->lacing_returned=ptr+1; + os->packetno++; + } + } + return(1); +} + +int ogg_stream_packetout(ogg_stream_state *os,ogg_packet *op){ + if(ogg_stream_check(os)) return 0; + return _packetout(os,op,1); +} + +int ogg_stream_packetpeek(ogg_stream_state *os,ogg_packet *op){ + if(ogg_stream_check(os)) return 0; + return _packetout(os,op,0); +} + +void ogg_packet_clear(ogg_packet *op) { + _ogg_free(op->packet); + memset(op, 0, sizeof(*op)); +} + +#ifdef _V_SELFTEST +#include + +ogg_stream_state os_en, os_de; +ogg_sync_state oy; + +void checkpacket(ogg_packet *op,long len, int no, long pos){ + long j; + static int sequence=0; + static int lastno=0; + + if(op->bytes!=len){ + fprintf(stderr,"incorrect packet length (%ld != %ld)!\n",op->bytes,len); + exit(1); + } + if(op->granulepos!=pos){ + fprintf(stderr,"incorrect packet granpos (%ld != %ld)!\n",(long)op->granulepos,pos); + exit(1); + } + + /* packet number just follows sequence/gap; adjust the input number + for that */ + if(no==0){ + sequence=0; + }else{ + sequence++; + if(no>lastno+1) + sequence++; + } + lastno=no; + if(op->packetno!=sequence){ + fprintf(stderr,"incorrect packet sequence %ld != %d\n", + (long)(op->packetno),sequence); + exit(1); + } + + /* Test data */ + for(j=0;jbytes;j++) + if(op->packet[j]!=((j+no)&0xff)){ + fprintf(stderr,"body data mismatch (1) at pos %ld: %x!=%lx!\n\n", + j,op->packet[j],(j+no)&0xff); + exit(1); + } +} + +void check_page(unsigned char *data,const int *header,ogg_page *og){ + long j; + /* Test data */ + for(j=0;jbody_len;j++) + if(og->body[j]!=data[j]){ + fprintf(stderr,"body data mismatch (2) at pos %ld: %x!=%x!\n\n", + j,data[j],og->body[j]); + exit(1); + } + + /* Test header */ + for(j=0;jheader_len;j++){ + if(og->header[j]!=header[j]){ + fprintf(stderr,"header content mismatch at pos %ld:\n",j); + for(j=0;jheader[j]); + fprintf(stderr,"\n"); + exit(1); + } + } + if(og->header_len!=header[26]+27){ + fprintf(stderr,"header length incorrect! (%ld!=%d)\n", + og->header_len,header[26]+27); + exit(1); + } +} + +void print_header(ogg_page *og){ + int j; + fprintf(stderr,"\nHEADER:\n"); + fprintf(stderr," capture: %c %c %c %c version: %d flags: %x\n", + og->header[0],og->header[1],og->header[2],og->header[3], + (int)og->header[4],(int)og->header[5]); + + fprintf(stderr," granulepos: %d serialno: %d pageno: %ld\n", + (og->header[9]<<24)|(og->header[8]<<16)| + (og->header[7]<<8)|og->header[6], + (og->header[17]<<24)|(og->header[16]<<16)| + (og->header[15]<<8)|og->header[14], + ((long)(og->header[21])<<24)|(og->header[20]<<16)| + (og->header[19]<<8)|og->header[18]); + + fprintf(stderr," checksum: %02x:%02x:%02x:%02x\n segments: %d (", + (int)og->header[22],(int)og->header[23], + (int)og->header[24],(int)og->header[25], + (int)og->header[26]); + + for(j=27;jheader_len;j++) + fprintf(stderr,"%d ",(int)og->header[j]); + fprintf(stderr,")\n\n"); +} + +void copy_page(ogg_page *og){ + unsigned char *temp=_ogg_malloc(og->header_len); + memcpy(temp,og->header,og->header_len); + og->header=temp; + + temp=_ogg_malloc(og->body_len); + memcpy(temp,og->body,og->body_len); + og->body=temp; +} + +void free_page(ogg_page *og){ + _ogg_free (og->header); + _ogg_free (og->body); +} + +void error(void){ + fprintf(stderr,"error!\n"); + exit(1); +} + +/* 17 only */ +const int head1_0[] = {0x4f,0x67,0x67,0x53,0,0x06, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x01,0x02,0x03,0x04,0,0,0,0, + 0x15,0xed,0xec,0x91, + 1, + 17}; + +/* 17, 254, 255, 256, 500, 510, 600 byte, pad */ +const int head1_1[] = {0x4f,0x67,0x67,0x53,0,0x02, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x01,0x02,0x03,0x04,0,0,0,0, + 0x59,0x10,0x6c,0x2c, + 1, + 17}; +const int head2_1[] = {0x4f,0x67,0x67,0x53,0,0x04, + 0x07,0x18,0x00,0x00,0x00,0x00,0x00,0x00, + 0x01,0x02,0x03,0x04,1,0,0,0, + 0x89,0x33,0x85,0xce, + 13, + 254,255,0,255,1,255,245,255,255,0, + 255,255,90}; + +/* nil packets; beginning,middle,end */ +const int head1_2[] = {0x4f,0x67,0x67,0x53,0,0x02, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x01,0x02,0x03,0x04,0,0,0,0, + 0xff,0x7b,0x23,0x17, + 1, + 0}; +const int head2_2[] = {0x4f,0x67,0x67,0x53,0,0x04, + 0x07,0x28,0x00,0x00,0x00,0x00,0x00,0x00, + 0x01,0x02,0x03,0x04,1,0,0,0, + 0x5c,0x3f,0x66,0xcb, + 17, + 17,254,255,0,0,255,1,0,255,245,255,255,0, + 255,255,90,0}; + +/* large initial packet */ +const int head1_3[] = {0x4f,0x67,0x67,0x53,0,0x02, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x01,0x02,0x03,0x04,0,0,0,0, + 0x01,0x27,0x31,0xaa, + 18, + 255,255,255,255,255,255,255,255, + 255,255,255,255,255,255,255,255,255,10}; + +const int head2_3[] = {0x4f,0x67,0x67,0x53,0,0x04, + 0x07,0x08,0x00,0x00,0x00,0x00,0x00,0x00, + 0x01,0x02,0x03,0x04,1,0,0,0, + 0x7f,0x4e,0x8a,0xd2, + 4, + 255,4,255,0}; + + +/* continuing packet test */ +const int head1_4[] = {0x4f,0x67,0x67,0x53,0,0x02, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x01,0x02,0x03,0x04,0,0,0,0, + 0xff,0x7b,0x23,0x17, + 1, + 0}; + +const int head2_4[] = {0x4f,0x67,0x67,0x53,0,0x00, + 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, + 0x01,0x02,0x03,0x04,1,0,0,0, + 0xf8,0x3c,0x19,0x79, + 255, + 255,255,255,255,255,255,255,255, + 255,255,255,255,255,255,255,255, + 255,255,255,255,255,255,255,255, + 255,255,255,255,255,255,255,255, + 255,255,255,255,255,255,255,255, + 255,255,255,255,255,255,255,255, + 255,255,255,255,255,255,255,255, + 255,255,255,255,255,255,255,255, + 255,255,255,255,255,255,255,255, + 255,255,255,255,255,255,255,255, + 255,255,255,255,255,255,255,255, + 255,255,255,255,255,255,255,255, + 255,255,255,255,255,255,255,255, + 255,255,255,255,255,255,255,255, + 255,255,255,255,255,255,255,255, + 255,255,255,255,255,255,255,255, + 255,255,255,255,255,255,255,255, + 255,255,255,255,255,255,255,255, + 255,255,255,255,255,255,255,255, + 255,255,255,255,255,255,255,255, + 255,255,255,255,255,255,255,255, + 255,255,255,255,255,255,255,255, + 255,255,255,255,255,255,255,255, + 255,255,255,255,255,255,255,255, + 255,255,255,255,255,255,255,255, + 255,255,255,255,255,255,255,255, + 255,255,255,255,255,255,255,255, + 255,255,255,255,255,255,255,255, + 255,255,255,255,255,255,255,255, + 255,255,255,255,255,255,255,255, + 255,255,255,255,255,255,255,255, + 255,255,255,255,255,255,255}; + +const int head3_4[] = {0x4f,0x67,0x67,0x53,0,0x05, + 0x07,0x0c,0x00,0x00,0x00,0x00,0x00,0x00, + 0x01,0x02,0x03,0x04,2,0,0,0, + 0x38,0xe6,0xb6,0x28, + 6, + 255,220,255,4,255,0}; + + +/* spill expansion test */ +const int head1_4b[] = {0x4f,0x67,0x67,0x53,0,0x02, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x01,0x02,0x03,0x04,0,0,0,0, + 0xff,0x7b,0x23,0x17, + 1, + 0}; + +const int head2_4b[] = {0x4f,0x67,0x67,0x53,0,0x00, + 0x07,0x10,0x00,0x00,0x00,0x00,0x00,0x00, + 0x01,0x02,0x03,0x04,1,0,0,0, + 0xce,0x8f,0x17,0x1a, + 23, + 255,255,255,255,255,255,255,255, + 255,255,255,255,255,255,255,255,255,10,255,4,255,0,0}; + + +const int head3_4b[] = {0x4f,0x67,0x67,0x53,0,0x04, + 0x07,0x14,0x00,0x00,0x00,0x00,0x00,0x00, + 0x01,0x02,0x03,0x04,2,0,0,0, + 0x9b,0xb2,0x50,0xa1, + 1, + 0}; + +/* page with the 255 segment limit */ +const int head1_5[] = {0x4f,0x67,0x67,0x53,0,0x02, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x01,0x02,0x03,0x04,0,0,0,0, + 0xff,0x7b,0x23,0x17, + 1, + 0}; + +const int head2_5[] = {0x4f,0x67,0x67,0x53,0,0x00, + 0x07,0xfc,0x03,0x00,0x00,0x00,0x00,0x00, + 0x01,0x02,0x03,0x04,1,0,0,0, + 0xed,0x2a,0x2e,0xa7, + 255, + 10,10,10,10,10,10,10,10, + 10,10,10,10,10,10,10,10, + 10,10,10,10,10,10,10,10, + 10,10,10,10,10,10,10,10, + 10,10,10,10,10,10,10,10, + 10,10,10,10,10,10,10,10, + 10,10,10,10,10,10,10,10, + 10,10,10,10,10,10,10,10, + 10,10,10,10,10,10,10,10, + 10,10,10,10,10,10,10,10, + 10,10,10,10,10,10,10,10, + 10,10,10,10,10,10,10,10, + 10,10,10,10,10,10,10,10, + 10,10,10,10,10,10,10,10, + 10,10,10,10,10,10,10,10, + 10,10,10,10,10,10,10,10, + 10,10,10,10,10,10,10,10, + 10,10,10,10,10,10,10,10, + 10,10,10,10,10,10,10,10, + 10,10,10,10,10,10,10,10, + 10,10,10,10,10,10,10,10, + 10,10,10,10,10,10,10,10, + 10,10,10,10,10,10,10,10, + 10,10,10,10,10,10,10,10, + 10,10,10,10,10,10,10,10, + 10,10,10,10,10,10,10,10, + 10,10,10,10,10,10,10,10, + 10,10,10,10,10,10,10,10, + 10,10,10,10,10,10,10,10, + 10,10,10,10,10,10,10,10, + 10,10,10,10,10,10,10,10, + 10,10,10,10,10,10,10}; + +const int head3_5[] = {0x4f,0x67,0x67,0x53,0,0x04, + 0x07,0x00,0x04,0x00,0x00,0x00,0x00,0x00, + 0x01,0x02,0x03,0x04,2,0,0,0, + 0x6c,0x3b,0x82,0x3d, + 1, + 50}; + + +/* packet that overspans over an entire page */ +const int head1_6[] = {0x4f,0x67,0x67,0x53,0,0x02, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x01,0x02,0x03,0x04,0,0,0,0, + 0xff,0x7b,0x23,0x17, + 1, + 0}; + +const int head2_6[] = {0x4f,0x67,0x67,0x53,0,0x00, + 0x07,0x04,0x00,0x00,0x00,0x00,0x00,0x00, + 0x01,0x02,0x03,0x04,1,0,0,0, + 0x68,0x22,0x7c,0x3d, + 255, + 100, + 255,255,255,255,255,255,255,255, + 255,255,255,255,255,255,255,255, + 255,255,255,255,255,255,255,255, + 255,255,255,255,255,255,255,255, + 255,255,255,255,255,255,255,255, + 255,255,255,255,255,255,255,255, + 255,255,255,255,255,255,255,255, + 255,255,255,255,255,255,255,255, + 255,255,255,255,255,255,255,255, + 255,255,255,255,255,255,255,255, + 255,255,255,255,255,255,255,255, + 255,255,255,255,255,255,255,255, + 255,255,255,255,255,255,255,255, + 255,255,255,255,255,255,255,255, + 255,255,255,255,255,255,255,255, + 255,255,255,255,255,255,255,255, + 255,255,255,255,255,255,255,255, + 255,255,255,255,255,255,255,255, + 255,255,255,255,255,255,255,255, + 255,255,255,255,255,255,255,255, + 255,255,255,255,255,255,255,255, + 255,255,255,255,255,255,255,255, + 255,255,255,255,255,255,255,255, + 255,255,255,255,255,255,255,255, + 255,255,255,255,255,255,255,255, + 255,255,255,255,255,255,255,255, + 255,255,255,255,255,255,255,255, + 255,255,255,255,255,255,255,255, + 255,255,255,255,255,255,255,255, + 255,255,255,255,255,255,255,255, + 255,255,255,255,255,255,255,255, + 255,255,255,255,255,255}; + +const int head3_6[] = {0x4f,0x67,0x67,0x53,0,0x01, + 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, + 0x01,0x02,0x03,0x04,2,0,0,0, + 0xf4,0x87,0xba,0xf3, + 255, + 255,255,255,255,255,255,255,255, + 255,255,255,255,255,255,255,255, + 255,255,255,255,255,255,255,255, + 255,255,255,255,255,255,255,255, + 255,255,255,255,255,255,255,255, + 255,255,255,255,255,255,255,255, + 255,255,255,255,255,255,255,255, + 255,255,255,255,255,255,255,255, + 255,255,255,255,255,255,255,255, + 255,255,255,255,255,255,255,255, + 255,255,255,255,255,255,255,255, + 255,255,255,255,255,255,255,255, + 255,255,255,255,255,255,255,255, + 255,255,255,255,255,255,255,255, + 255,255,255,255,255,255,255,255, + 255,255,255,255,255,255,255,255, + 255,255,255,255,255,255,255,255, + 255,255,255,255,255,255,255,255, + 255,255,255,255,255,255,255,255, + 255,255,255,255,255,255,255,255, + 255,255,255,255,255,255,255,255, + 255,255,255,255,255,255,255,255, + 255,255,255,255,255,255,255,255, + 255,255,255,255,255,255,255,255, + 255,255,255,255,255,255,255,255, + 255,255,255,255,255,255,255,255, + 255,255,255,255,255,255,255,255, + 255,255,255,255,255,255,255,255, + 255,255,255,255,255,255,255,255, + 255,255,255,255,255,255,255,255, + 255,255,255,255,255,255,255,255, + 255,255,255,255,255,255,255}; + +const int head4_6[] = {0x4f,0x67,0x67,0x53,0,0x05, + 0x07,0x10,0x00,0x00,0x00,0x00,0x00,0x00, + 0x01,0x02,0x03,0x04,3,0,0,0, + 0xf7,0x2f,0x6c,0x60, + 5, + 254,255,4,255,0}; + +/* packet that overspans over an entire page */ +const int head1_7[] = {0x4f,0x67,0x67,0x53,0,0x02, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x01,0x02,0x03,0x04,0,0,0,0, + 0xff,0x7b,0x23,0x17, + 1, + 0}; + +const int head2_7[] = {0x4f,0x67,0x67,0x53,0,0x00, + 0x07,0x04,0x00,0x00,0x00,0x00,0x00,0x00, + 0x01,0x02,0x03,0x04,1,0,0,0, + 0x68,0x22,0x7c,0x3d, + 255, + 100, + 255,255,255,255,255,255,255,255, + 255,255,255,255,255,255,255,255, + 255,255,255,255,255,255,255,255, + 255,255,255,255,255,255,255,255, + 255,255,255,255,255,255,255,255, + 255,255,255,255,255,255,255,255, + 255,255,255,255,255,255,255,255, + 255,255,255,255,255,255,255,255, + 255,255,255,255,255,255,255,255, + 255,255,255,255,255,255,255,255, + 255,255,255,255,255,255,255,255, + 255,255,255,255,255,255,255,255, + 255,255,255,255,255,255,255,255, + 255,255,255,255,255,255,255,255, + 255,255,255,255,255,255,255,255, + 255,255,255,255,255,255,255,255, + 255,255,255,255,255,255,255,255, + 255,255,255,255,255,255,255,255, + 255,255,255,255,255,255,255,255, + 255,255,255,255,255,255,255,255, + 255,255,255,255,255,255,255,255, + 255,255,255,255,255,255,255,255, + 255,255,255,255,255,255,255,255, + 255,255,255,255,255,255,255,255, + 255,255,255,255,255,255,255,255, + 255,255,255,255,255,255,255,255, + 255,255,255,255,255,255,255,255, + 255,255,255,255,255,255,255,255, + 255,255,255,255,255,255,255,255, + 255,255,255,255,255,255,255,255, + 255,255,255,255,255,255,255,255, + 255,255,255,255,255,255}; + +const int head3_7[] = {0x4f,0x67,0x67,0x53,0,0x05, + 0x07,0x08,0x00,0x00,0x00,0x00,0x00,0x00, + 0x01,0x02,0x03,0x04,2,0,0,0, + 0xd4,0xe0,0x60,0xe5, + 1, + 0}; + +void test_pack(const int *pl, const int **headers, int byteskip, + int pageskip, int packetskip){ + unsigned char *data=_ogg_malloc(1024*1024); /* for scripted test cases only */ + long inptr=0; + long outptr=0; + long deptr=0; + long depacket=0; + long granule_pos=7,pageno=0; + int i,j,packets,pageout=pageskip; + int eosflag=0; + int bosflag=0; + + int byteskipcount=0; + + ogg_stream_reset(&os_en); + ogg_stream_reset(&os_de); + ogg_sync_reset(&oy); + + for(packets=0;packetsbyteskip){ + memcpy(next,og.header,byteskipcount-byteskip); + next+=byteskipcount-byteskip; + byteskipcount=byteskip; + } + + byteskipcount+=og.body_len; + if(byteskipcount>byteskip){ + memcpy(next,og.body,byteskipcount-byteskip); + next+=byteskipcount-byteskip; + byteskipcount=byteskip; + } + + ogg_sync_wrote(&oy,next-buf); + + while(1){ + int ret=ogg_sync_pageout(&oy,&og_de); + if(ret==0)break; + if(ret<0)continue; + /* got a page. Happy happy. Verify that it's good. */ + + fprintf(stderr,"(%d), ",pageout); + + check_page(data+deptr,headers[pageout],&og_de); + deptr+=og_de.body_len; + pageout++; + + /* submit it to deconstitution */ + ogg_stream_pagein(&os_de,&og_de); + + /* packets out? */ + while(ogg_stream_packetpeek(&os_de,&op_de2)>0){ + ogg_stream_packetpeek(&os_de,NULL); + ogg_stream_packetout(&os_de,&op_de); /* just catching them all */ + + /* verify peek and out match */ + if(memcmp(&op_de,&op_de2,sizeof(op_de))){ + fprintf(stderr,"packetout != packetpeek! pos=%ld\n", + depacket); + exit(1); + } + + /* verify the packet! */ + /* check data */ + if(memcmp(data+depacket,op_de.packet,op_de.bytes)){ + fprintf(stderr,"packet data mismatch in decode! pos=%ld\n", + depacket); + exit(1); + } + /* check bos flag */ + if(bosflag==0 && op_de.b_o_s==0){ + fprintf(stderr,"b_o_s flag not set on packet!\n"); + exit(1); + } + if(bosflag && op_de.b_o_s){ + fprintf(stderr,"b_o_s flag incorrectly set on packet!\n"); + exit(1); + } + bosflag=1; + depacket+=op_de.bytes; + + /* check eos flag */ + if(eosflag){ + fprintf(stderr,"Multiple decoded packets with eos flag!\n"); + exit(1); + } + + if(op_de.e_o_s)eosflag=1; + + /* check granulepos flag */ + if(op_de.granulepos!=-1){ + fprintf(stderr," granule:%ld ",(long)op_de.granulepos); + } + } + } + } + } + } + } + _ogg_free(data); + if(headers[pageno]!=NULL){ + fprintf(stderr,"did not write last page!\n"); + exit(1); + } + if(headers[pageout]!=NULL){ + fprintf(stderr,"did not decode last page!\n"); + exit(1); + } + if(inptr!=outptr){ + fprintf(stderr,"encoded page data incomplete!\n"); + exit(1); + } + if(inptr!=deptr){ + fprintf(stderr,"decoded page data incomplete!\n"); + exit(1); + } + if(inptr!=depacket){ + fprintf(stderr,"decoded packet data incomplete!\n"); + exit(1); + } + if(!eosflag){ + fprintf(stderr,"Never got a packet with EOS set!\n"); + exit(1); + } + fprintf(stderr,"ok.\n"); +} + +int main(void){ + + ogg_stream_init(&os_en,0x04030201); + ogg_stream_init(&os_de,0x04030201); + ogg_sync_init(&oy); + + /* Exercise each code path in the framing code. Also verify that + the checksums are working. */ + + { + /* 17 only */ + const int packets[]={17, -1}; + const int *headret[]={head1_0,NULL}; + + fprintf(stderr,"testing single page encoding... "); + test_pack(packets,headret,0,0,0); + } + + { + /* 17, 254, 255, 256, 500, 510, 600 byte, pad */ + const int packets[]={17, 254, 255, 256, 500, 510, 600, -1}; + const int *headret[]={head1_1,head2_1,NULL}; + + fprintf(stderr,"testing basic page encoding... "); + test_pack(packets,headret,0,0,0); + } + + { + /* nil packets; beginning,middle,end */ + const int packets[]={0,17, 254, 255, 0, 256, 0, 500, 510, 600, 0, -1}; + const int *headret[]={head1_2,head2_2,NULL}; + + fprintf(stderr,"testing basic nil packets... "); + test_pack(packets,headret,0,0,0); + } + + { + /* large initial packet */ + const int packets[]={4345,259,255,-1}; + const int *headret[]={head1_3,head2_3,NULL}; + + fprintf(stderr,"testing initial-packet lacing > 4k... "); + test_pack(packets,headret,0,0,0); + } + + { + /* continuing packet test; with page spill expansion, we have to + overflow the lacing table. */ + const int packets[]={0,65500,259,255,-1}; + const int *headret[]={head1_4,head2_4,head3_4,NULL}; + + fprintf(stderr,"testing single packet page span... "); + test_pack(packets,headret,0,0,0); + } + + { + /* spill expand packet test */ + const int packets[]={0,4345,259,255,0,0,-1}; + const int *headret[]={head1_4b,head2_4b,head3_4b,NULL}; + + fprintf(stderr,"testing page spill expansion... "); + test_pack(packets,headret,0,0,0); + } + + /* page with the 255 segment limit */ + { + + const int packets[]={0,10,10,10,10,10,10,10,10, + 10,10,10,10,10,10,10,10, + 10,10,10,10,10,10,10,10, + 10,10,10,10,10,10,10,10, + 10,10,10,10,10,10,10,10, + 10,10,10,10,10,10,10,10, + 10,10,10,10,10,10,10,10, + 10,10,10,10,10,10,10,10, + 10,10,10,10,10,10,10,10, + 10,10,10,10,10,10,10,10, + 10,10,10,10,10,10,10,10, + 10,10,10,10,10,10,10,10, + 10,10,10,10,10,10,10,10, + 10,10,10,10,10,10,10,10, + 10,10,10,10,10,10,10,10, + 10,10,10,10,10,10,10,10, + 10,10,10,10,10,10,10,10, + 10,10,10,10,10,10,10,10, + 10,10,10,10,10,10,10,10, + 10,10,10,10,10,10,10,10, + 10,10,10,10,10,10,10,10, + 10,10,10,10,10,10,10,10, + 10,10,10,10,10,10,10,10, + 10,10,10,10,10,10,10,10, + 10,10,10,10,10,10,10,10, + 10,10,10,10,10,10,10,10, + 10,10,10,10,10,10,10,10, + 10,10,10,10,10,10,10,10, + 10,10,10,10,10,10,10,10, + 10,10,10,10,10,10,10,10, + 10,10,10,10,10,10,10,10, + 10,10,10,10,10,10,10,50,-1}; + const int *headret[]={head1_5,head2_5,head3_5,NULL}; + + fprintf(stderr,"testing max packet segments... "); + test_pack(packets,headret,0,0,0); + } + + { + /* packet that overspans over an entire page */ + const int packets[]={0,100,130049,259,255,-1}; + const int *headret[]={head1_6,head2_6,head3_6,head4_6,NULL}; + + fprintf(stderr,"testing very large packets... "); + test_pack(packets,headret,0,0,0); + } + + { + /* test for the libogg 1.1.1 resync in large continuation bug + found by Josh Coalson) */ + const int packets[]={0,100,130049,259,255,-1}; + const int *headret[]={head1_6,head2_6,head3_6,head4_6,NULL}; + + fprintf(stderr,"testing continuation resync in very large packets... "); + test_pack(packets,headret,100,2,3); + } + + { + /* term only page. why not? */ + const int packets[]={0,100,64770,-1}; + const int *headret[]={head1_7,head2_7,head3_7,NULL}; + + fprintf(stderr,"testing zero data page (1 nil packet)... "); + test_pack(packets,headret,0,0,0); + } + + + + { + /* build a bunch of pages for testing */ + unsigned char *data=_ogg_malloc(1024*1024); + int pl[]={0, 1,1,98,4079, 1,1,2954,2057, 76,34,912,0,234,1000,1000, 1000,300,-1}; + int inptr=0,i,j; + ogg_page og[5]; + + ogg_stream_reset(&os_en); + + for(i=0;pl[i]!=-1;i++){ + ogg_packet op; + int len=pl[i]; + + op.packet=data+inptr; + op.bytes=len; + op.e_o_s=(pl[i+1]<0?1:0); + op.granulepos=(i+1)*1000; + + for(j=0;j0)error(); + + /* Test fractional page inputs: incomplete fixed header */ + memcpy(ogg_sync_buffer(&oy,og[1].header_len),og[1].header+3, + 20); + ogg_sync_wrote(&oy,20); + if(ogg_sync_pageout(&oy,&og_de)>0)error(); + + /* Test fractional page inputs: incomplete header */ + memcpy(ogg_sync_buffer(&oy,og[1].header_len),og[1].header+23, + 5); + ogg_sync_wrote(&oy,5); + if(ogg_sync_pageout(&oy,&og_de)>0)error(); + + /* Test fractional page inputs: incomplete body */ + + memcpy(ogg_sync_buffer(&oy,og[1].header_len),og[1].header+28, + og[1].header_len-28); + ogg_sync_wrote(&oy,og[1].header_len-28); + if(ogg_sync_pageout(&oy,&og_de)>0)error(); + + memcpy(ogg_sync_buffer(&oy,og[1].body_len),og[1].body,1000); + ogg_sync_wrote(&oy,1000); + if(ogg_sync_pageout(&oy,&og_de)>0)error(); + + memcpy(ogg_sync_buffer(&oy,og[1].body_len),og[1].body+1000, + og[1].body_len-1000); + ogg_sync_wrote(&oy,og[1].body_len-1000); + if(ogg_sync_pageout(&oy,&og_de)<=0)error(); + + fprintf(stderr,"ok.\n"); + } + + /* Test fractional page inputs: page + incomplete capture */ + { + ogg_page og_de; + fprintf(stderr,"Testing sync on 1+partial inputs... "); + ogg_sync_reset(&oy); + + memcpy(ogg_sync_buffer(&oy,og[1].header_len),og[1].header, + og[1].header_len); + ogg_sync_wrote(&oy,og[1].header_len); + + memcpy(ogg_sync_buffer(&oy,og[1].body_len),og[1].body, + og[1].body_len); + ogg_sync_wrote(&oy,og[1].body_len); + + memcpy(ogg_sync_buffer(&oy,og[1].header_len),og[1].header, + 20); + ogg_sync_wrote(&oy,20); + if(ogg_sync_pageout(&oy,&og_de)<=0)error(); + if(ogg_sync_pageout(&oy,&og_de)>0)error(); + + memcpy(ogg_sync_buffer(&oy,og[1].header_len),og[1].header+20, + og[1].header_len-20); + ogg_sync_wrote(&oy,og[1].header_len-20); + memcpy(ogg_sync_buffer(&oy,og[1].body_len),og[1].body, + og[1].body_len); + ogg_sync_wrote(&oy,og[1].body_len); + if(ogg_sync_pageout(&oy,&og_de)<=0)error(); + + fprintf(stderr,"ok.\n"); + } + + /* Test recapture: garbage + page */ + { + ogg_page og_de; + fprintf(stderr,"Testing search for capture... "); + ogg_sync_reset(&oy); + + /* 'garbage' */ + memcpy(ogg_sync_buffer(&oy,og[1].body_len),og[1].body, + og[1].body_len); + ogg_sync_wrote(&oy,og[1].body_len); + + memcpy(ogg_sync_buffer(&oy,og[1].header_len),og[1].header, + og[1].header_len); + ogg_sync_wrote(&oy,og[1].header_len); + + memcpy(ogg_sync_buffer(&oy,og[1].body_len),og[1].body, + og[1].body_len); + ogg_sync_wrote(&oy,og[1].body_len); + + memcpy(ogg_sync_buffer(&oy,og[2].header_len),og[2].header, + 20); + ogg_sync_wrote(&oy,20); + if(ogg_sync_pageout(&oy,&og_de)>0)error(); + if(ogg_sync_pageout(&oy,&og_de)<=0)error(); + if(ogg_sync_pageout(&oy,&og_de)>0)error(); + + memcpy(ogg_sync_buffer(&oy,og[2].header_len),og[2].header+20, + og[2].header_len-20); + ogg_sync_wrote(&oy,og[2].header_len-20); + memcpy(ogg_sync_buffer(&oy,og[2].body_len),og[2].body, + og[2].body_len); + ogg_sync_wrote(&oy,og[2].body_len); + if(ogg_sync_pageout(&oy,&og_de)<=0)error(); + + fprintf(stderr,"ok.\n"); + } + + /* Test recapture: page + garbage + page */ + { + ogg_page og_de; + fprintf(stderr,"Testing recapture... "); + ogg_sync_reset(&oy); + + memcpy(ogg_sync_buffer(&oy,og[1].header_len),og[1].header, + og[1].header_len); + ogg_sync_wrote(&oy,og[1].header_len); + + memcpy(ogg_sync_buffer(&oy,og[1].body_len),og[1].body, + og[1].body_len); + ogg_sync_wrote(&oy,og[1].body_len); + + memcpy(ogg_sync_buffer(&oy,og[2].header_len),og[2].header, + og[2].header_len); + ogg_sync_wrote(&oy,og[2].header_len); + + memcpy(ogg_sync_buffer(&oy,og[2].header_len),og[2].header, + og[2].header_len); + ogg_sync_wrote(&oy,og[2].header_len); + + if(ogg_sync_pageout(&oy,&og_de)<=0)error(); + + memcpy(ogg_sync_buffer(&oy,og[2].body_len),og[2].body, + og[2].body_len-5); + ogg_sync_wrote(&oy,og[2].body_len-5); + + memcpy(ogg_sync_buffer(&oy,og[3].header_len),og[3].header, + og[3].header_len); + ogg_sync_wrote(&oy,og[3].header_len); + + memcpy(ogg_sync_buffer(&oy,og[3].body_len),og[3].body, + og[3].body_len); + ogg_sync_wrote(&oy,og[3].body_len); + + if(ogg_sync_pageout(&oy,&og_de)>0)error(); + if(ogg_sync_pageout(&oy,&og_de)<=0)error(); + + fprintf(stderr,"ok.\n"); + } + + /* Free page data that was previously copied */ + { + for(i=0;i<5;i++){ + free_page(&og[i]); + } + } + } + + return(0); +} + +#endif diff --git a/ios/IOSDuoduo/Voice/Code/Libs/libogg/ogg/ogg.h b/ios/IOSDuoduo/Voice/Code/Libs/libogg/ogg/ogg.h new file mode 100755 index 000000000..00975ca35 --- /dev/null +++ b/ios/IOSDuoduo/Voice/Code/Libs/libogg/ogg/ogg.h @@ -0,0 +1,210 @@ +/******************************************************************** + * * + * THIS FILE IS PART OF THE OggVorbis SOFTWARE CODEC SOURCE CODE. * + * USE, DISTRIBUTION AND REPRODUCTION OF THIS LIBRARY SOURCE IS * + * GOVERNED BY A BSD-STYLE SOURCE LICENSE INCLUDED WITH THIS SOURCE * + * IN 'COPYING'. PLEASE READ THESE TERMS BEFORE DISTRIBUTING. * + * * + * THE OggVorbis SOURCE CODE IS (C) COPYRIGHT 1994-2007 * + * by the Xiph.Org Foundation http://www.xiph.org/ * + * * + ******************************************************************** + + function: toplevel libogg include + last mod: $Id: ogg.h 18044 2011-08-01 17:55:20Z gmaxwell $ + + ********************************************************************/ +#ifndef _OGG_H +#define _OGG_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include +#include "os_types.h" + +typedef struct { + void *iov_base; + size_t iov_len; +} ogg_iovec_t; + +typedef struct { + long endbyte; + int endbit; + + unsigned char *buffer; + unsigned char *ptr; + long storage; +} oggpack_buffer; + +/* ogg_page is used to encapsulate the data in one Ogg bitstream page *****/ + +typedef struct { + unsigned char *header; + long header_len; + unsigned char *body; + long body_len; +} ogg_page; + +/* ogg_stream_state contains the current encode/decode state of a logical + Ogg bitstream **********************************************************/ + +typedef struct { + unsigned char *body_data; /* bytes from packet bodies */ + long body_storage; /* storage elements allocated */ + long body_fill; /* elements stored; fill mark */ + long body_returned; /* elements of fill returned */ + + + int *lacing_vals; /* The values that will go to the segment table */ + ogg_int64_t *granule_vals; /* granulepos values for headers. Not compact + this way, but it is simple coupled to the + lacing fifo */ + long lacing_storage; + long lacing_fill; + long lacing_packet; + long lacing_returned; + + unsigned char header[282]; /* working space for header encode */ + int header_fill; + + int e_o_s; /* set when we have buffered the last packet in the + logical bitstream */ + int b_o_s; /* set after we've written the initial page + of a logical bitstream */ + long serialno; + long pageno; + ogg_int64_t packetno; /* sequence number for decode; the framing + knows where there's a hole in the data, + but we need coupling so that the codec + (which is in a separate abstraction + layer) also knows about the gap */ + ogg_int64_t granulepos; + +} ogg_stream_state; + +/* ogg_packet is used to encapsulate the data and metadata belonging + to a single raw Ogg/Vorbis packet *************************************/ + +typedef struct { + unsigned char *packet; + long bytes; + long b_o_s; + long e_o_s; + + ogg_int64_t granulepos; + + ogg_int64_t packetno; /* sequence number for decode; the framing + knows where there's a hole in the data, + but we need coupling so that the codec + (which is in a separate abstraction + layer) also knows about the gap */ +} ogg_packet; + +typedef struct { + unsigned char *data; + int storage; + int fill; + int returned; + + int unsynced; + int headerbytes; + int bodybytes; +} ogg_sync_state; + +/* Ogg BITSTREAM PRIMITIVES: bitstream ************************/ + +extern void oggpack_writeinit(oggpack_buffer *b); +extern int oggpack_writecheck(oggpack_buffer *b); +extern void oggpack_writetrunc(oggpack_buffer *b,long bits); +extern void oggpack_writealign(oggpack_buffer *b); +extern void oggpack_writecopy(oggpack_buffer *b,void *source,long bits); +extern void oggpack_reset(oggpack_buffer *b); +extern void oggpack_writeclear(oggpack_buffer *b); +extern void oggpack_readinit(oggpack_buffer *b,unsigned char *buf,int bytes); +extern void oggpack_write(oggpack_buffer *b,unsigned long value,int bits); +extern long oggpack_look(oggpack_buffer *b,int bits); +extern long oggpack_look1(oggpack_buffer *b); +extern void oggpack_adv(oggpack_buffer *b,int bits); +extern void oggpack_adv1(oggpack_buffer *b); +extern long oggpack_read(oggpack_buffer *b,int bits); +extern long oggpack_read1(oggpack_buffer *b); +extern long oggpack_bytes(oggpack_buffer *b); +extern long oggpack_bits(oggpack_buffer *b); +extern unsigned char *oggpack_get_buffer(oggpack_buffer *b); + +extern void oggpackB_writeinit(oggpack_buffer *b); +extern int oggpackB_writecheck(oggpack_buffer *b); +extern void oggpackB_writetrunc(oggpack_buffer *b,long bits); +extern void oggpackB_writealign(oggpack_buffer *b); +extern void oggpackB_writecopy(oggpack_buffer *b,void *source,long bits); +extern void oggpackB_reset(oggpack_buffer *b); +extern void oggpackB_writeclear(oggpack_buffer *b); +extern void oggpackB_readinit(oggpack_buffer *b,unsigned char *buf,int bytes); +extern void oggpackB_write(oggpack_buffer *b,unsigned long value,int bits); +extern long oggpackB_look(oggpack_buffer *b,int bits); +extern long oggpackB_look1(oggpack_buffer *b); +extern void oggpackB_adv(oggpack_buffer *b,int bits); +extern void oggpackB_adv1(oggpack_buffer *b); +extern long oggpackB_read(oggpack_buffer *b,int bits); +extern long oggpackB_read1(oggpack_buffer *b); +extern long oggpackB_bytes(oggpack_buffer *b); +extern long oggpackB_bits(oggpack_buffer *b); +extern unsigned char *oggpackB_get_buffer(oggpack_buffer *b); + +/* Ogg BITSTREAM PRIMITIVES: encoding **************************/ + +extern int ogg_stream_packetin(ogg_stream_state *os, ogg_packet *op); +extern int ogg_stream_iovecin(ogg_stream_state *os, ogg_iovec_t *iov, + int count, long e_o_s, ogg_int64_t granulepos); +extern int ogg_stream_pageout(ogg_stream_state *os, ogg_page *og); +extern int ogg_stream_pageout_fill(ogg_stream_state *os, ogg_page *og, int nfill); +extern int ogg_stream_flush(ogg_stream_state *os, ogg_page *og); +extern int ogg_stream_flush_fill(ogg_stream_state *os, ogg_page *og, int nfill); + +/* Ogg BITSTREAM PRIMITIVES: decoding **************************/ + +extern int ogg_sync_init(ogg_sync_state *oy); +extern int ogg_sync_clear(ogg_sync_state *oy); +extern int ogg_sync_reset(ogg_sync_state *oy); +extern int ogg_sync_destroy(ogg_sync_state *oy); +extern int ogg_sync_check(ogg_sync_state *oy); + +extern char *ogg_sync_buffer(ogg_sync_state *oy, long size); +extern int ogg_sync_wrote(ogg_sync_state *oy, long bytes); +extern long ogg_sync_pageseek(ogg_sync_state *oy,ogg_page *og); +extern int ogg_sync_pageout(ogg_sync_state *oy, ogg_page *og); +extern int ogg_stream_pagein(ogg_stream_state *os, ogg_page *og); +extern int ogg_stream_packetout(ogg_stream_state *os,ogg_packet *op); +extern int ogg_stream_packetpeek(ogg_stream_state *os,ogg_packet *op); + +/* Ogg BITSTREAM PRIMITIVES: general ***************************/ + +extern int ogg_stream_init(ogg_stream_state *os,int serialno); +extern int ogg_stream_clear(ogg_stream_state *os); +extern int ogg_stream_reset(ogg_stream_state *os); +extern int ogg_stream_reset_serialno(ogg_stream_state *os,int serialno); +extern int ogg_stream_destroy(ogg_stream_state *os); +extern int ogg_stream_check(ogg_stream_state *os); +extern int ogg_stream_eos(ogg_stream_state *os); + +extern void ogg_page_checksum_set(ogg_page *og); + +extern int ogg_page_version(const ogg_page *og); +extern int ogg_page_continued(const ogg_page *og); +extern int ogg_page_bos(const ogg_page *og); +extern int ogg_page_eos(const ogg_page *og); +extern ogg_int64_t ogg_page_granulepos(const ogg_page *og); +extern int ogg_page_serialno(const ogg_page *og); +extern long ogg_page_pageno(const ogg_page *og); +extern int ogg_page_packets(const ogg_page *og); + +extern void ogg_packet_clear(ogg_packet *op); + + +#ifdef __cplusplus +} +#endif + +#endif /* _OGG_H */ diff --git a/ios/IOSDuoduo/Voice/Code/Libs/libogg/ogg/os_types.h b/ios/IOSDuoduo/Voice/Code/Libs/libogg/ogg/os_types.h new file mode 100755 index 000000000..d6691b703 --- /dev/null +++ b/ios/IOSDuoduo/Voice/Code/Libs/libogg/ogg/os_types.h @@ -0,0 +1,147 @@ +/******************************************************************** + * * + * THIS FILE IS PART OF THE OggVorbis SOFTWARE CODEC SOURCE CODE. * + * USE, DISTRIBUTION AND REPRODUCTION OF THIS LIBRARY SOURCE IS * + * GOVERNED BY A BSD-STYLE SOURCE LICENSE INCLUDED WITH THIS SOURCE * + * IN 'COPYING'. PLEASE READ THESE TERMS BEFORE DISTRIBUTING. * + * * + * THE OggVorbis SOURCE CODE IS (C) COPYRIGHT 1994-2002 * + * by the Xiph.Org Foundation http://www.xiph.org/ * + * * + ******************************************************************** + + function: #ifdef jail to whip a few platforms into the UNIX ideal. + last mod: $Id: os_types.h 17712 2010-12-03 17:10:02Z xiphmont $ + + ********************************************************************/ +#ifndef _OS_TYPES_H +#define _OS_TYPES_H + +/* make it easy on the folks that want to compile the libs with a + different malloc than stdlib */ +#define _ogg_malloc malloc +#define _ogg_calloc calloc +#define _ogg_realloc realloc +#define _ogg_free free + +#if defined(_WIN32) + +# if defined(__CYGWIN__) +# include + typedef int16_t ogg_int16_t; + typedef uint16_t ogg_uint16_t; + typedef int32_t ogg_int32_t; + typedef uint32_t ogg_uint32_t; + typedef int64_t ogg_int64_t; + typedef uint64_t ogg_uint64_t; +# elif defined(__MINGW32__) +# include + typedef short ogg_int16_t; + typedef unsigned short ogg_uint16_t; + typedef int ogg_int32_t; + typedef unsigned int ogg_uint32_t; + typedef long long ogg_int64_t; + typedef unsigned long long ogg_uint64_t; +# elif defined(__MWERKS__) + typedef long long ogg_int64_t; + typedef int ogg_int32_t; + typedef unsigned int ogg_uint32_t; + typedef short ogg_int16_t; + typedef unsigned short ogg_uint16_t; +# else + /* MSVC/Borland */ + typedef __int64 ogg_int64_t; + typedef __int32 ogg_int32_t; + typedef unsigned __int32 ogg_uint32_t; + typedef __int16 ogg_int16_t; + typedef unsigned __int16 ogg_uint16_t; +# endif + +#elif defined(__MACOS__) + +# include + typedef SInt16 ogg_int16_t; + typedef UInt16 ogg_uint16_t; + typedef SInt32 ogg_int32_t; + typedef UInt32 ogg_uint32_t; + typedef SInt64 ogg_int64_t; + +#elif (defined(__APPLE__) && defined(__MACH__)) /* MacOS X Framework build */ + +# include + typedef int16_t ogg_int16_t; + typedef uint16_t ogg_uint16_t; + typedef int32_t ogg_int32_t; + typedef uint32_t ogg_uint32_t; + typedef int64_t ogg_int64_t; + +#elif defined(__HAIKU__) + + /* Haiku */ +# include + typedef short ogg_int16_t; + typedef unsigned short ogg_uint16_t; + typedef int ogg_int32_t; + typedef unsigned int ogg_uint32_t; + typedef long long ogg_int64_t; + +#elif defined(__BEOS__) + + /* Be */ +# include + typedef int16_t ogg_int16_t; + typedef uint16_t ogg_uint16_t; + typedef int32_t ogg_int32_t; + typedef uint32_t ogg_uint32_t; + typedef int64_t ogg_int64_t; + +#elif defined (__EMX__) + + /* OS/2 GCC */ + typedef short ogg_int16_t; + typedef unsigned short ogg_uint16_t; + typedef int ogg_int32_t; + typedef unsigned int ogg_uint32_t; + typedef long long ogg_int64_t; + +#elif defined (DJGPP) + + /* DJGPP */ + typedef short ogg_int16_t; + typedef int ogg_int32_t; + typedef unsigned int ogg_uint32_t; + typedef long long ogg_int64_t; + +#elif defined(R5900) + + /* PS2 EE */ + typedef long ogg_int64_t; + typedef int ogg_int32_t; + typedef unsigned ogg_uint32_t; + typedef short ogg_int16_t; + +#elif defined(__SYMBIAN32__) + + /* Symbian GCC */ + typedef signed short ogg_int16_t; + typedef unsigned short ogg_uint16_t; + typedef signed int ogg_int32_t; + typedef unsigned int ogg_uint32_t; + typedef long long int ogg_int64_t; + +#elif defined(__TMS320C6X__) + + /* TI C64x compiler */ + typedef signed short ogg_int16_t; + typedef unsigned short ogg_uint16_t; + typedef signed int ogg_int32_t; + typedef unsigned int ogg_uint32_t; + typedef long long int ogg_int64_t; + +#else + +# include + +#endif + +#endif /* _OS_TYPES_H */ diff --git a/ios/IOSDuoduo/Voice/Code/Libs/libspeex/_kiss_fft_guts.h b/ios/IOSDuoduo/Voice/Code/Libs/libspeex/_kiss_fft_guts.h new file mode 100755 index 000000000..6571e79c0 --- /dev/null +++ b/ios/IOSDuoduo/Voice/Code/Libs/libspeex/_kiss_fft_guts.h @@ -0,0 +1,160 @@ +/* +Copyright (c) 2003-2004, Mark Borgerding + +All rights reserved. + +Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. + * Neither the author nor the names of any contributors may be used to endorse or promote products derived from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#define MIN(a,b) ((a)<(b) ? (a):(b)) +#define MAX(a,b) ((a)>(b) ? (a):(b)) + +/* kiss_fft.h + defines kiss_fft_scalar as either short or a float type + and defines + typedef struct { kiss_fft_scalar r; kiss_fft_scalar i; }kiss_fft_cpx; */ +#include "kiss_fft.h" +#include "math_approx.h" + +#define MAXFACTORS 32 +/* e.g. an fft of length 128 has 4 factors + as far as kissfft is concerned + 4*4*4*2 + */ + +struct kiss_fft_state{ + int nfft; + int inverse; + int factors[2*MAXFACTORS]; + kiss_fft_cpx twiddles[1]; +}; + +/* + Explanation of macros dealing with complex math: + + C_MUL(m,a,b) : m = a*b + C_FIXDIV( c , div ) : if a fixed point impl., c /= div. noop otherwise + C_SUB( res, a,b) : res = a - b + C_SUBFROM( res , a) : res -= a + C_ADDTO( res , a) : res += a + * */ +#ifdef FIXED_POINT +#include "arch.h" +# define FRACBITS 15 +# define SAMPPROD spx_int32_t +#define SAMP_MAX 32767 + +#define SAMP_MIN -SAMP_MAX + +#if defined(CHECK_OVERFLOW) +# define CHECK_OVERFLOW_OP(a,op,b) \ + if ( (SAMPPROD)(a) op (SAMPPROD)(b) > SAMP_MAX || (SAMPPROD)(a) op (SAMPPROD)(b) < SAMP_MIN ) { \ + fprintf(stderr,"WARNING:overflow @ " __FILE__ "(%d): (%d " #op" %d) = %ld\n",__LINE__,(a),(b),(SAMPPROD)(a) op (SAMPPROD)(b) ); } +#endif + + +# define smul(a,b) ( (SAMPPROD)(a)*(b) ) +# define sround( x ) (kiss_fft_scalar)( ( (x) + (1<<(FRACBITS-1)) ) >> FRACBITS ) + +# define S_MUL(a,b) sround( smul(a,b) ) + +# define C_MUL(m,a,b) \ + do{ (m).r = sround( smul((a).r,(b).r) - smul((a).i,(b).i) ); \ + (m).i = sround( smul((a).r,(b).i) + smul((a).i,(b).r) ); }while(0) + +# define C_MUL4(m,a,b) \ + do{ (m).r = PSHR32( smul((a).r,(b).r) - smul((a).i,(b).i),17 ); \ + (m).i = PSHR32( smul((a).r,(b).i) + smul((a).i,(b).r),17 ); }while(0) + +# define DIVSCALAR(x,k) \ + (x) = sround( smul( x, SAMP_MAX/k ) ) + +# define C_FIXDIV(c,div) \ + do { DIVSCALAR( (c).r , div); \ + DIVSCALAR( (c).i , div); }while (0) + +# define C_MULBYSCALAR( c, s ) \ + do{ (c).r = sround( smul( (c).r , s ) ) ;\ + (c).i = sround( smul( (c).i , s ) ) ; }while(0) + +#else /* not FIXED_POINT*/ + +# define S_MUL(a,b) ( (a)*(b) ) +#define C_MUL(m,a,b) \ + do{ (m).r = (a).r*(b).r - (a).i*(b).i;\ + (m).i = (a).r*(b).i + (a).i*(b).r; }while(0) + +#define C_MUL4(m,a,b) C_MUL(m,a,b) + +# define C_FIXDIV(c,div) /* NOOP */ +# define C_MULBYSCALAR( c, s ) \ + do{ (c).r *= (s);\ + (c).i *= (s); }while(0) +#endif + +#ifndef CHECK_OVERFLOW_OP +# define CHECK_OVERFLOW_OP(a,op,b) /* noop */ +#endif + +#define C_ADD( res, a,b)\ + do { \ + CHECK_OVERFLOW_OP((a).r,+,(b).r)\ + CHECK_OVERFLOW_OP((a).i,+,(b).i)\ + (res).r=(a).r+(b).r; (res).i=(a).i+(b).i; \ + }while(0) +#define C_SUB( res, a,b)\ + do { \ + CHECK_OVERFLOW_OP((a).r,-,(b).r)\ + CHECK_OVERFLOW_OP((a).i,-,(b).i)\ + (res).r=(a).r-(b).r; (res).i=(a).i-(b).i; \ + }while(0) +#define C_ADDTO( res , a)\ + do { \ + CHECK_OVERFLOW_OP((res).r,+,(a).r)\ + CHECK_OVERFLOW_OP((res).i,+,(a).i)\ + (res).r += (a).r; (res).i += (a).i;\ + }while(0) + +#define C_SUBFROM( res , a)\ + do {\ + CHECK_OVERFLOW_OP((res).r,-,(a).r)\ + CHECK_OVERFLOW_OP((res).i,-,(a).i)\ + (res).r -= (a).r; (res).i -= (a).i; \ + }while(0) + + +#ifdef FIXED_POINT +# define KISS_FFT_COS(phase) floor(MIN(32767,MAX(-32767,.5+32768 * cos (phase)))) +# define KISS_FFT_SIN(phase) floor(MIN(32767,MAX(-32767,.5+32768 * sin (phase)))) +# define HALF_OF(x) ((x)>>1) +#elif defined(USE_SIMD) +# define KISS_FFT_COS(phase) _mm_set1_ps( cos(phase) ) +# define KISS_FFT_SIN(phase) _mm_set1_ps( sin(phase) ) +# define HALF_OF(x) ((x)*_mm_set1_ps(.5)) +#else +# define KISS_FFT_COS(phase) (kiss_fft_scalar) cos(phase) +# define KISS_FFT_SIN(phase) (kiss_fft_scalar) sin(phase) +# define HALF_OF(x) ((x)*.5) +#endif + +#define kf_cexp(x,phase) \ + do{ \ + (x)->r = KISS_FFT_COS(phase);\ + (x)->i = KISS_FFT_SIN(phase);\ + }while(0) +#define kf_cexp2(x,phase) \ + do{ \ + (x)->r = spx_cos_norm((phase));\ + (x)->i = spx_cos_norm((phase)-32768);\ +}while(0) + + +/* a debugging function */ +#define pcpx(c)\ + fprintf(stderr,"%g + %gi\n",(double)((c)->r),(double)((c)->i) ) diff --git a/ios/IOSDuoduo/Voice/Code/Libs/libspeex/arch.h b/ios/IOSDuoduo/Voice/Code/Libs/libspeex/arch.h new file mode 100755 index 000000000..08520bdd7 --- /dev/null +++ b/ios/IOSDuoduo/Voice/Code/Libs/libspeex/arch.h @@ -0,0 +1,241 @@ +/* Copyright (C) 2003 Jean-Marc Valin */ +/** + @file arch.h + @brief Various architecture definitions Speex +*/ +/* + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + - Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + - Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + - Neither the name of the Xiph.org Foundation nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR + CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#ifndef ARCH_H +#define ARCH_H + +#ifndef SPEEX_VERSION +#define SPEEX_MAJOR_VERSION 1 /**< Major Speex version. */ +#define SPEEX_MINOR_VERSION 1 /**< Minor Speex version. */ +#define SPEEX_MICRO_VERSION 15 /**< Micro Speex version. */ +#define SPEEX_EXTRA_VERSION "" /**< Extra Speex version. */ +#define SPEEX_VERSION "speex-1.2beta3" /**< Speex version string. */ +#endif + +/* A couple test to catch stupid option combinations */ +#ifdef FIXED_POINT + +#ifdef FLOATING_POINT +#error You cannot compile as floating point and fixed point at the same time +#endif +#ifdef _USE_SSE +#error SSE is only for floating-point +#endif +#if ((defined (ARM4_ASM)||defined (ARM4_ASM)) && defined(BFIN_ASM)) || (defined (ARM4_ASM)&&defined(ARM5E_ASM)) +#error Make up your mind. What CPU do you have? +#endif +#ifdef VORBIS_PSYCHO +#error Vorbis-psy model currently not implemented in fixed-point +#endif + +#else + +/*#ifndef FLOATING_POINT +#error You now need to define either FIXED_POINT or FLOATING_POINT +#endif*/ +#if defined (ARM4_ASM) || defined(ARM5E_ASM) || defined(BFIN_ASM) +#error I suppose you can have a [ARM4/ARM5E/Blackfin] that has float instructions? +#endif +#ifdef FIXED_POINT_DEBUG +#error "Don't you think enabling fixed-point is a good thing to do if you want to debug that?" +#endif + + +#endif + +#ifndef OUTSIDE_SPEEX +#include "speex/speex_types.h" +#endif + +#include "../config.h" + +#define ABS(x) ((x) < 0 ? (-(x)) : (x)) /**< Absolute integer value. */ +#define ABS16(x) ((x) < 0 ? (-(x)) : (x)) /**< Absolute 16-bit value. */ +#define MIN16(a,b) ((a) < (b) ? (a) : (b)) /**< Maximum 16-bit value. */ +#define MAX16(a,b) ((a) > (b) ? (a) : (b)) /**< Maximum 16-bit value. */ +#define ABS32(x) ((x) < 0 ? (-(x)) : (x)) /**< Absolute 32-bit value. */ +#define MIN32(a,b) ((a) < (b) ? (a) : (b)) /**< Maximum 32-bit value. */ +#define MAX32(a,b) ((a) > (b) ? (a) : (b)) /**< Maximum 32-bit value. */ + +#ifdef FIXED_POINT + +typedef spx_int16_t spx_word16_t; +typedef spx_int32_t spx_word32_t; +typedef spx_word32_t spx_mem_t; +typedef spx_word16_t spx_coef_t; +typedef spx_word16_t spx_lsp_t; +typedef spx_word32_t spx_sig_t; + +#define Q15ONE 32767 + +#define LPC_SCALING 8192 +#define SIG_SCALING 16384 +#define LSP_SCALING 8192. +#define GAMMA_SCALING 32768. +#define GAIN_SCALING 64 +#define GAIN_SCALING_1 0.015625 + +#define LPC_SHIFT 13 +#define LSP_SHIFT 13 +#define SIG_SHIFT 14 +#define GAIN_SHIFT 6 + +#define VERY_SMALL 0 +#define VERY_LARGE32 ((spx_word32_t)2147483647) +#define VERY_LARGE16 ((spx_word16_t)32767) +#define Q15_ONE ((spx_word16_t)32767) + + +#ifdef FIXED_DEBUG +#include "fixed_debug.h" +#else + +#include "fixed_generic.h" + +#ifdef ARM5E_ASM +#include "fixed_arm5e.h" +#elif defined (ARM4_ASM) +#include "fixed_arm4.h" +#elif defined (BFIN_ASM) +#include "fixed_bfin.h" +#endif + +#endif + + +#else + +typedef float spx_mem_t; +typedef float spx_coef_t; +typedef float spx_lsp_t; +typedef float spx_sig_t; +typedef float spx_word16_t; +typedef float spx_word32_t; + +#define Q15ONE 1.0f +#define LPC_SCALING 1.f +#define SIG_SCALING 1.f +#define LSP_SCALING 1.f +#define GAMMA_SCALING 1.f +#define GAIN_SCALING 1.f +#define GAIN_SCALING_1 1.f + + +#define VERY_SMALL 1e-15f +#define VERY_LARGE32 1e15f +#define VERY_LARGE16 1e15f +#define Q15_ONE ((spx_word16_t)1.f) + +#define QCONST16(x,bits) (x) +#define QCONST32(x,bits) (x) + +#define NEG16(x) (-(x)) +#define NEG32(x) (-(x)) +#define EXTRACT16(x) (x) +#define EXTEND32(x) (x) +#define SHR16(a,shift) (a) +#define SHL16(a,shift) (a) +#define SHR32(a,shift) (a) +#define SHL32(a,shift) (a) +#define PSHR16(a,shift) (a) +#define PSHR32(a,shift) (a) +#define VSHR32(a,shift) (a) +#define SATURATE16(x,a) (x) +#define SATURATE32(x,a) (x) + +#define PSHR(a,shift) (a) +#define SHR(a,shift) (a) +#define SHL(a,shift) (a) +#define SATURATE(x,a) (x) + +#define ADD16(a,b) ((a)+(b)) +#define SUB16(a,b) ((a)-(b)) +#define ADD32(a,b) ((a)+(b)) +#define SUB32(a,b) ((a)-(b)) +#define MULT16_16_16(a,b) ((a)*(b)) +#define MULT16_16(a,b) ((spx_word32_t)(a)*(spx_word32_t)(b)) +#define MAC16_16(c,a,b) ((c)+(spx_word32_t)(a)*(spx_word32_t)(b)) + +#define MULT16_32_Q11(a,b) ((a)*(b)) +#define MULT16_32_Q13(a,b) ((a)*(b)) +#define MULT16_32_Q14(a,b) ((a)*(b)) +#define MULT16_32_Q15(a,b) ((a)*(b)) +#define MULT16_32_P15(a,b) ((a)*(b)) + +#define MAC16_32_Q11(c,a,b) ((c)+(a)*(b)) +#define MAC16_32_Q15(c,a,b) ((c)+(a)*(b)) + +#define MAC16_16_Q11(c,a,b) ((c)+(a)*(b)) +#define MAC16_16_Q13(c,a,b) ((c)+(a)*(b)) +#define MAC16_16_P13(c,a,b) ((c)+(a)*(b)) +#define MULT16_16_Q11_32(a,b) ((a)*(b)) +#define MULT16_16_Q13(a,b) ((a)*(b)) +#define MULT16_16_Q14(a,b) ((a)*(b)) +#define MULT16_16_Q15(a,b) ((a)*(b)) +#define MULT16_16_P15(a,b) ((a)*(b)) +#define MULT16_16_P13(a,b) ((a)*(b)) +#define MULT16_16_P14(a,b) ((a)*(b)) + +#define DIV32_16(a,b) (((spx_word32_t)(a))/(spx_word16_t)(b)) +#define PDIV32_16(a,b) (((spx_word32_t)(a))/(spx_word16_t)(b)) +#define DIV32(a,b) (((spx_word32_t)(a))/(spx_word32_t)(b)) +#define PDIV32(a,b) (((spx_word32_t)(a))/(spx_word32_t)(b)) + + +#endif + + +#if defined (CONFIG_TI_C54X) || defined (CONFIG_TI_C55X) + +/* 2 on TI C5x DSP */ +#define BYTES_PER_CHAR 2 +#define BITS_PER_CHAR 16 +#define LOG2_BITS_PER_CHAR 4 + +#else + +#define BYTES_PER_CHAR 1 +#define BITS_PER_CHAR 8 +#define LOG2_BITS_PER_CHAR 3 + +#endif + + + +#ifdef FIXED_DEBUG +extern long long spx_mips; +#endif + + +#endif diff --git a/ios/IOSDuoduo/Voice/Code/Libs/libspeex/bits.c b/ios/IOSDuoduo/Voice/Code/Libs/libspeex/bits.c new file mode 100755 index 000000000..96b4efe57 --- /dev/null +++ b/ios/IOSDuoduo/Voice/Code/Libs/libspeex/bits.c @@ -0,0 +1,372 @@ +/* Copyright (C) 2002 Jean-Marc Valin + File: speex_bits.c + + Handles bit packing/unpacking + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + - Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + - Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + - Neither the name of the Xiph.org Foundation nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR + CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +*/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "speex/speex_bits.h" +#include "arch.h" +#include "os_support.h" + +/* Maximum size of the bit-stream (for fixed-size allocation) */ +#ifndef MAX_CHARS_PER_FRAME +#define MAX_CHARS_PER_FRAME (2000/BYTES_PER_CHAR) +#endif + +EXPORT void speex_bits_init(SpeexBits *bits) +{ + bits->chars = (char*)speex_alloc(MAX_CHARS_PER_FRAME); + if (!bits->chars) + return; + + bits->buf_size = MAX_CHARS_PER_FRAME; + + bits->owner=1; + + speex_bits_reset(bits); +} + +EXPORT void speex_bits_init_buffer(SpeexBits *bits, void *buff, int buf_size) +{ + bits->chars = (char*)buff; + bits->buf_size = buf_size; + + bits->owner=0; + + speex_bits_reset(bits); +} + +EXPORT void speex_bits_set_bit_buffer(SpeexBits *bits, void *buff, int buf_size) +{ + bits->chars = (char*)buff; + bits->buf_size = buf_size; + + bits->owner=0; + + bits->nbBits=buf_size<charPtr=0; + bits->bitPtr=0; + bits->overflow=0; + +} + +EXPORT void speex_bits_destroy(SpeexBits *bits) +{ + if (bits->owner) + speex_free(bits->chars); + /* Will do something once the allocation is dynamic */ +} + +EXPORT void speex_bits_reset(SpeexBits *bits) +{ + /* We only need to clear the first byte now */ + bits->chars[0]=0; + bits->nbBits=0; + bits->charPtr=0; + bits->bitPtr=0; + bits->overflow=0; +} + +EXPORT void speex_bits_rewind(SpeexBits *bits) +{ + bits->charPtr=0; + bits->bitPtr=0; + bits->overflow=0; +} + +EXPORT void speex_bits_read_from(SpeexBits *bits, char *chars, int len) +{ + int i; + int nchars = len / BYTES_PER_CHAR; + if (nchars > bits->buf_size) + { + speex_notify("Packet is larger than allocated buffer"); + if (bits->owner) + { + char *tmp = (char*)speex_realloc(bits->chars, nchars); + if (tmp) + { + bits->buf_size=nchars; + bits->chars=tmp; + } else { + nchars=bits->buf_size; + speex_warning("Could not resize input buffer: truncating input"); + } + } else { + speex_warning("Do not own input buffer: truncating oversize input"); + nchars=bits->buf_size; + } + } +#if (BYTES_PER_CHAR==2) +/* Swap bytes to proper endian order (could be done externally) */ +#define HTOLS(A) ((((A) >> 8)&0xff)|(((A) & 0xff)<<8)) +#else +#define HTOLS(A) (A) +#endif + for (i=0;ichars[i]=HTOLS(chars[i]); + + bits->nbBits=nchars<charPtr=0; + bits->bitPtr=0; + bits->overflow=0; +} + +static void speex_bits_flush(SpeexBits *bits) +{ + int nchars = ((bits->nbBits+BITS_PER_CHAR-1)>>LOG2_BITS_PER_CHAR); + if (bits->charPtr>0) + SPEEX_MOVE(bits->chars, &bits->chars[bits->charPtr], nchars-bits->charPtr); + bits->nbBits -= bits->charPtr<charPtr=0; +} + +EXPORT void speex_bits_read_whole_bytes(SpeexBits *bits, char *chars, int nbytes) +{ + int i,pos; + int nchars = nbytes/BYTES_PER_CHAR; + + if (((bits->nbBits+BITS_PER_CHAR-1)>>LOG2_BITS_PER_CHAR)+nchars > bits->buf_size) + { + /* Packet is larger than allocated buffer */ + if (bits->owner) + { + char *tmp = (char*)speex_realloc(bits->chars, (bits->nbBits>>LOG2_BITS_PER_CHAR)+nchars+1); + if (tmp) + { + bits->buf_size=(bits->nbBits>>LOG2_BITS_PER_CHAR)+nchars+1; + bits->chars=tmp; + } else { + nchars=bits->buf_size-(bits->nbBits>>LOG2_BITS_PER_CHAR)-1; + speex_warning("Could not resize input buffer: truncating oversize input"); + } + } else { + speex_warning("Do not own input buffer: truncating oversize input"); + nchars=bits->buf_size; + } + } + + speex_bits_flush(bits); + pos=bits->nbBits>>LOG2_BITS_PER_CHAR; + for (i=0;ichars[pos+i]=HTOLS(chars[i]); + bits->nbBits+=nchars<bitPtr; + charPtr=bits->charPtr; + nbBits=bits->nbBits; + speex_bits_insert_terminator(bits); + bits->bitPtr=bitPtr; + bits->charPtr=charPtr; + bits->nbBits=nbBits; + + if (max_nchars > ((bits->nbBits+BITS_PER_CHAR-1)>>LOG2_BITS_PER_CHAR)) + max_nchars = ((bits->nbBits+BITS_PER_CHAR-1)>>LOG2_BITS_PER_CHAR); + + for (i=0;ichars[i]); + return max_nchars*BYTES_PER_CHAR; +} + +EXPORT int speex_bits_write_whole_bytes(SpeexBits *bits, char *chars, int max_nbytes) +{ + int max_nchars = max_nbytes/BYTES_PER_CHAR; + int i; + if (max_nchars > ((bits->nbBits)>>LOG2_BITS_PER_CHAR)) + max_nchars = ((bits->nbBits)>>LOG2_BITS_PER_CHAR); + for (i=0;ichars[i]); + + if (bits->bitPtr>0) + bits->chars[0]=bits->chars[max_nchars]; + else + bits->chars[0]=0; + bits->charPtr=0; + bits->nbBits &= (BITS_PER_CHAR-1); + return max_nchars*BYTES_PER_CHAR; +} + +EXPORT void speex_bits_pack(SpeexBits *bits, int data, int nbBits) +{ + unsigned int d=data; + + if (bits->charPtr+((nbBits+bits->bitPtr)>>LOG2_BITS_PER_CHAR) >= bits->buf_size) + { + speex_notify("Buffer too small to pack bits"); + if (bits->owner) + { + int new_nchars = ((bits->buf_size+5)*3)>>1; + char *tmp = (char*)speex_realloc(bits->chars, new_nchars); + if (tmp) + { + bits->buf_size=new_nchars; + bits->chars=tmp; + } else { + speex_warning("Could not resize input buffer: not packing"); + return; + } + } else { + speex_warning("Do not own input buffer: not packing"); + return; + } + } + + while(nbBits) + { + int bit; + bit = (d>>(nbBits-1))&1; + bits->chars[bits->charPtr] |= bit<<(BITS_PER_CHAR-1-bits->bitPtr); + bits->bitPtr++; + + if (bits->bitPtr==BITS_PER_CHAR) + { + bits->bitPtr=0; + bits->charPtr++; + bits->chars[bits->charPtr] = 0; + } + bits->nbBits++; + nbBits--; + } +} + +EXPORT int speex_bits_unpack_signed(SpeexBits *bits, int nbBits) +{ + unsigned int d=speex_bits_unpack_unsigned(bits,nbBits); + /* If number is negative */ + if (d>>(nbBits-1)) + { + d |= (-1)<charPtr<bitPtr+nbBits>bits->nbBits) + bits->overflow=1; + if (bits->overflow) + return 0; + while(nbBits) + { + d<<=1; + d |= (bits->chars[bits->charPtr]>>(BITS_PER_CHAR-1 - bits->bitPtr))&1; + bits->bitPtr++; + if (bits->bitPtr==BITS_PER_CHAR) + { + bits->bitPtr=0; + bits->charPtr++; + } + nbBits--; + } + return d; +} + +EXPORT unsigned int speex_bits_peek_unsigned(SpeexBits *bits, int nbBits) +{ + unsigned int d=0; + int bitPtr, charPtr; + char *chars; + + if ((bits->charPtr<bitPtr+nbBits>bits->nbBits) + bits->overflow=1; + if (bits->overflow) + return 0; + + bitPtr=bits->bitPtr; + charPtr=bits->charPtr; + chars = bits->chars; + while(nbBits) + { + d<<=1; + d |= (chars[charPtr]>>(BITS_PER_CHAR-1 - bitPtr))&1; + bitPtr++; + if (bitPtr==BITS_PER_CHAR) + { + bitPtr=0; + charPtr++; + } + nbBits--; + } + return d; +} + +EXPORT int speex_bits_peek(SpeexBits *bits) +{ + if ((bits->charPtr<bitPtr+1>bits->nbBits) + bits->overflow=1; + if (bits->overflow) + return 0; + return (bits->chars[bits->charPtr]>>(BITS_PER_CHAR-1 - bits->bitPtr))&1; +} + +EXPORT void speex_bits_advance(SpeexBits *bits, int n) +{ + if (((bits->charPtr<bitPtr+n>bits->nbBits) || bits->overflow){ + bits->overflow=1; + return; + } + bits->charPtr += (bits->bitPtr+n) >> LOG2_BITS_PER_CHAR; /* divide by BITS_PER_CHAR */ + bits->bitPtr = (bits->bitPtr+n) & (BITS_PER_CHAR-1); /* modulo by BITS_PER_CHAR */ +} + +EXPORT int speex_bits_remaining(SpeexBits *bits) +{ + if (bits->overflow) + return -1; + else + return bits->nbBits-((bits->charPtr<bitPtr); +} + +EXPORT int speex_bits_nbytes(SpeexBits *bits) +{ + return ((bits->nbBits+BITS_PER_CHAR-1)>>LOG2_BITS_PER_CHAR); +} + +EXPORT void speex_bits_insert_terminator(SpeexBits *bits) +{ + if (bits->bitPtr) + speex_bits_pack(bits, 0, 1); + while (bits->bitPtr) + speex_bits_pack(bits, 1, 1); +} diff --git a/ios/IOSDuoduo/Voice/Code/Libs/libspeex/buffer.c b/ios/IOSDuoduo/Voice/Code/Libs/libspeex/buffer.c new file mode 100755 index 000000000..c82cab5bc --- /dev/null +++ b/ios/IOSDuoduo/Voice/Code/Libs/libspeex/buffer.c @@ -0,0 +1,176 @@ +/* Copyright (C) 2007 Jean-Marc Valin + + File: buffer.c + This is a very simple ring buffer implementation. It is not thread-safe + so you need to do your own locking. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are + met: + + 1. Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + 3. The name of the author may not be used to endorse or promote products + derived from this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, + INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + POSSIBILITY OF SUCH DAMAGE. +*/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + + +#include "os_support.h" +#include "arch.h" +#include "speex/speex_buffer.h" + +struct SpeexBuffer_ { + char *data; + int size; + int read_ptr; + int write_ptr; + int available; +}; + +EXPORT SpeexBuffer *speex_buffer_init(int size) +{ + SpeexBuffer *st = speex_alloc(sizeof(SpeexBuffer)); + st->data = speex_alloc(size); + st->size = size; + st->read_ptr = 0; + st->write_ptr = 0; + st->available = 0; + return st; +} + +EXPORT void speex_buffer_destroy(SpeexBuffer *st) +{ + speex_free(st->data); + speex_free(st); +} + +EXPORT int speex_buffer_write(SpeexBuffer *st, void *_data, int len) +{ + int end; + int end1; + char *data = _data; + if (len > st->size) + { + data += len-st->size; + len = st->size; + } + end = st->write_ptr + len; + end1 = end; + if (end1 > st->size) + end1 = st->size; + SPEEX_COPY(st->data + st->write_ptr, data, end1 - st->write_ptr); + if (end > st->size) + { + end -= st->size; + SPEEX_COPY(st->data, data+end1 - st->write_ptr, end); + } + st->available += len; + if (st->available > st->size) + { + st->available = st->size; + st->read_ptr = st->write_ptr; + } + st->write_ptr += len; + if (st->write_ptr > st->size) + st->write_ptr -= st->size; + return len; +} + +EXPORT int speex_buffer_writezeros(SpeexBuffer *st, int len) +{ + /* This is almost the same as for speex_buffer_write() but using + SPEEX_MEMSET() instead of SPEEX_COPY(). Update accordingly. */ + int end; + int end1; + if (len > st->size) + { + len = st->size; + } + end = st->write_ptr + len; + end1 = end; + if (end1 > st->size) + end1 = st->size; + SPEEX_MEMSET(st->data + st->write_ptr, 0, end1 - st->write_ptr); + if (end > st->size) + { + end -= st->size; + SPEEX_MEMSET(st->data, 0, end); + } + st->available += len; + if (st->available > st->size) + { + st->available = st->size; + st->read_ptr = st->write_ptr; + } + st->write_ptr += len; + if (st->write_ptr > st->size) + st->write_ptr -= st->size; + return len; +} + +EXPORT int speex_buffer_read(SpeexBuffer *st, void *_data, int len) +{ + int end, end1; + char *data = _data; + if (len > st->available) + { + SPEEX_MEMSET(data+st->available, 0, st->size-st->available); + len = st->available; + } + end = st->read_ptr + len; + end1 = end; + if (end1 > st->size) + end1 = st->size; + SPEEX_COPY(data, st->data + st->read_ptr, end1 - st->read_ptr); + + if (end > st->size) + { + end -= st->size; + SPEEX_COPY(data+end1 - st->read_ptr, st->data, end); + } + st->available -= len; + st->read_ptr += len; + if (st->read_ptr > st->size) + st->read_ptr -= st->size; + return len; +} + +EXPORT int speex_buffer_get_available(SpeexBuffer *st) +{ + return st->available; +} + +EXPORT int speex_buffer_resize(SpeexBuffer *st, int len) +{ + int old_len = st->size; + if (len > old_len) + { + st->data = speex_realloc(st->data, len); + /* FIXME: move data/pointers properly for growing the buffer */ + } else { + /* FIXME: move data/pointers properly for shrinking the buffer */ + st->data = speex_realloc(st->data, len); + } + return len; +} diff --git a/ios/IOSDuoduo/Voice/Code/Libs/libspeex/cb_search.c b/ios/IOSDuoduo/Voice/Code/Libs/libspeex/cb_search.c new file mode 100755 index 000000000..63f4c6a4b --- /dev/null +++ b/ios/IOSDuoduo/Voice/Code/Libs/libspeex/cb_search.c @@ -0,0 +1,612 @@ +/* Copyright (C) 2002-2006 Jean-Marc Valin + File: cb_search.c + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + - Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + - Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + - Neither the name of the Xiph.org Foundation nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR + CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "cb_search.h" +#include "filters.h" +#include "stack_alloc.h" +#include "vq.h" +#include "arch.h" +#include "math_approx.h" +#include "os_support.h" + +#ifdef _USE_SSE +#include "cb_search_sse.h" +#elif defined(ARM4_ASM) || defined(ARM5E_ASM) +#include "cb_search_arm4.h" +#elif defined(BFIN_ASM) +#include "cb_search_bfin.h" +#endif + +#ifndef OVERRIDE_COMPUTE_WEIGHTED_CODEBOOK +static void compute_weighted_codebook(const signed char *shape_cb, const spx_word16_t *r, spx_word16_t *resp, spx_word16_t *resp2, spx_word32_t *E, int shape_cb_size, int subvect_size, char *stack) +{ + int i, j, k; + VARDECL(spx_word16_t *shape); + ALLOC(shape, subvect_size, spx_word16_t); + for (i=0;isubvect_size; + nb_subvect = params->nb_subvect; + shape_cb_size = 1<shape_bits; + shape_cb = params->shape_cb; + have_sign = params->have_sign; + ALLOC(resp, shape_cb_size*subvect_size, spx_word16_t); +#ifdef _USE_SSE + ALLOC(resp2, (shape_cb_size*subvect_size)>>2, __m128); + ALLOC(E, shape_cb_size>>2, __m128); +#else + resp2 = resp; + ALLOC(E, shape_cb_size, spx_word32_t); +#endif + ALLOC(t, nsf, spx_word16_t); + ALLOC(e, nsf, spx_sig_t); + + /* FIXME: Do we still need to copy the target? */ + SPEEX_COPY(t, target, nsf); + + compute_weighted_codebook(shape_cb, r, resp, resp2, E, shape_cb_size, subvect_size, stack); + + for (i=0;ishape_bits+have_sign); + + { + int rind; + spx_word16_t *res; + spx_word16_t sign=1; + rind = best_index; + if (rind>=shape_cb_size) + { + sign=-1; + rind-=shape_cb_size; + } + res = resp+rind*subvect_size; + if (sign>0) + for (m=0;m=shape_cb_size) + { + sign=-1; + rind-=shape_cb_size; + } + + q=subvect_size-m; +#ifdef FIXED_POINT + g=sign*shape_cb[rind*subvect_size+m]; +#else + g=sign*0.03125*shape_cb[rind*subvect_size+m]; +#endif + target_update(t+subvect_size*(i+1), g, r+q, nsf-subvect_size*(i+1)); + } + } + + /* Update excitation */ + /* FIXME: We could update the excitation directly above */ + for (j=0;j10) + N=10; + /* Complexity isn't as important for the codebooks as it is for the pitch */ + N=(2*N)/3; + if (N<1) + N=1; + if (N==1) + { + split_cb_search_shape_sign_N1(target,ak,awk1,awk2,par,p,nsf,exc,r,bits,stack,update_target); + return; + } + ALLOC(ot2, N, spx_word16_t*); + ALLOC(nt2, N, spx_word16_t*); + ALLOC(oind, N, int*); + ALLOC(nind, N, int*); + + params = (const split_cb_params *) par; + subvect_size = params->subvect_size; + nb_subvect = params->nb_subvect; + shape_cb_size = 1<shape_bits; + shape_cb = params->shape_cb; + have_sign = params->have_sign; + ALLOC(resp, shape_cb_size*subvect_size, spx_word16_t); +#ifdef _USE_SSE + ALLOC(resp2, (shape_cb_size*subvect_size)>>2, __m128); + ALLOC(E, shape_cb_size>>2, __m128); +#else + resp2 = resp; + ALLOC(E, shape_cb_size, spx_word32_t); +#endif + ALLOC(t, nsf, spx_word16_t); + ALLOC(e, nsf, spx_sig_t); + ALLOC(ind, nb_subvect, int); + + ALLOC(tmp, 2*N*nsf, spx_word16_t); + for (i=0;im;n--) + { + ndist[n] = ndist[n-1]; + best_nind[n] = best_nind[n-1]; + best_ntarget[n] = best_ntarget[n-1]; + } + /* n is equal to m here, so they're interchangeable */ + ndist[m] = err; + best_nind[n] = best_index[k]; + best_ntarget[n] = j; + break; + } + } + } + } + if (i==0) + break; + } + for (j=0;j=shape_cb_size) + { + sign=-1; + rind-=shape_cb_size; + } + + q=subvect_size-m; +#ifdef FIXED_POINT + g=sign*shape_cb[rind*subvect_size+m]; +#else + g=sign*0.03125*shape_cb[rind*subvect_size+m]; +#endif + target_update(nt[j]+subvect_size*(i+1), g, r+q, nsf-subvect_size*(i+1)); + } + + for (q=0;qshape_bits+have_sign); + } + + /* Put everything back together */ + for (i=0;i=shape_cb_size) + { + sign=-1; + rind-=shape_cb_size; + } +#ifdef FIXED_POINT + if (sign==1) + { + for (j=0;jsubvect_size; + nb_subvect = params->nb_subvect; + shape_cb_size = 1<shape_bits; + shape_cb = params->shape_cb; + have_sign = params->have_sign; + + ALLOC(ind, nb_subvect, int); + ALLOC(signs, nb_subvect, int); + + /* Decode codewords and gains */ + for (i=0;ishape_bits); + } + /* Compute decoded excitation */ + for (i=0;i>>= 13;\n\t" + "A1 += R0.L*R0.L (IS);\n\t" + "W[P3++] = R0;\n\t" + "P0 += 1;\n\t" + "P2 += 2;\n\t" + "LOOP_END outter%=;\n\t" + "P4 = %4;\n\t" + "R1 = A1;\n\t" + "[P4] = R1;\n\t" + : + : "m" (subvect_size), "m" (shape_cb), "m" (r), "m" (resp), "m" (E) + : "A0", "P0", "P1", "P2", "P3", "P4", "R0", "R1", "R2", "I0", "I1", "L0", + "L1", "A0", "A1", "memory" +#if !(__GNUC__ == 3) + , "LC0", "LC1" /* gcc 3.4 doesn't know about LC registers */ +#endif + ); + shape_cb += subvect_size; + resp += subvect_size; + E++; + } +} + +#define OVERRIDE_TARGET_UPDATE +static inline void target_update(spx_word16_t *t, spx_word16_t g, spx_word16_t *r, int len) +{ + if (!len) + return; + __asm__ __volatile__ + ( + "I0 = %0;\n\t" + "I1 = %1;\n\t" + "L0 = 0;\n\t" + "L1 = 0;\n\t" + "R2 = 4096;\n\t" + "LOOP tupdate%= LC0 = %3;\n\t" + "LOOP_BEGIN tupdate%=;\n\t" + "R0.L = W[I0] || R1.L = W[I1++];\n\t" + "R1 = (A1 = R1.L*%2.L) (IS);\n\t" + "R1 = R1 + R2;\n\t" + "R1 >>>= 13;\n\t" + "R0.L = R0.L - R1.L;\n\t" + "W[I0++] = R0.L;\n\t" + "LOOP_END tupdate%=;\n\t" + : + : "a" (t), "a" (r), "d" (g), "a" (len) + : "R0", "R1", "R2", "A1", "I0", "I1", "L0", "L1" + ); +} diff --git a/ios/IOSDuoduo/Voice/Code/Libs/libspeex/cb_search_sse.h b/ios/IOSDuoduo/Voice/Code/Libs/libspeex/cb_search_sse.h new file mode 100755 index 000000000..8b039686f --- /dev/null +++ b/ios/IOSDuoduo/Voice/Code/Libs/libspeex/cb_search_sse.h @@ -0,0 +1,84 @@ +/* Copyright (C) 2004 Jean-Marc Valin */ +/** + @file cb_search_sse.h + @brief Fixed codebook functions (SSE version) +*/ +/* + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + - Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + - Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + - Neither the name of the Xiph.org Foundation nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR + CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#include + +static inline void _spx_mm_getr_ps (__m128 U, float *__Z, float *__Y, float *__X, float *__W) +{ + union { + float __a[4]; + __m128 __v; + } __u; + + __u.__v = U; + + *__Z = __u.__a[0]; + *__Y = __u.__a[1]; + *__X = __u.__a[2]; + *__W = __u.__a[3]; + +} + +#define OVERRIDE_COMPUTE_WEIGHTED_CODEBOOK +static void compute_weighted_codebook(const signed char *shape_cb, const spx_sig_t *_r, float *resp, __m128 *resp2, __m128 *E, int shape_cb_size, int subvect_size, char *stack) +{ + int i, j, k; + __m128 resj, EE; + VARDECL(__m128 *r); + VARDECL(__m128 *shape); + ALLOC(r, subvect_size, __m128); + ALLOC(shape, subvect_size, __m128); + for(j=0;j>2] = EE; + } +} diff --git a/ios/IOSDuoduo/Voice/Code/Libs/libspeex/exc_10_16_table.c b/ios/IOSDuoduo/Voice/Code/Libs/libspeex/exc_10_16_table.c new file mode 100755 index 000000000..98ae357d8 --- /dev/null +++ b/ios/IOSDuoduo/Voice/Code/Libs/libspeex/exc_10_16_table.c @@ -0,0 +1,50 @@ +/* Copyright (C) 2002 Jean-Marc Valin + File: exc_10_16_table.c + Codebook for excitation in narrowband CELP mode (3200 bps) + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + - Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + - Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + - Neither the name of the Xiph.org Foundation nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR + CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + + +const signed char exc_10_16_table[160] = { +22,39,14,44,11,35,-2,23,-4,6, +46,-28,13,-27,-23,12,4,20,-5,9, +37,-18,-23,23,0,9,-6,-20,4,-1, +-17,-5,-4,17,0,1,9,-2,1,2, +2,-12,8,-25,39,15,9,16,-55,-11, +9,11,5,10,-2,-60,8,13,-6,11, +-16,27,-47,-12,11,1,16,-7,9,-3, +-29,9,-14,25,-19,34,36,12,40,-10, +-3,-24,-14,-37,-21,-35,-2,-36,3,-6, +67,28,6,-17,-3,-12,-16,-15,-17,-7, +-59,-36,-13,1,7,1,2,10,2,11, +13,10,8,-2,7,3,5,4,2,2, +-3,-8,4,-5,6,7,-42,15,35,-2, +-46,38,28,-20,-9,1,7,-3,0,-2, +0,0,0,0,0,0,0,0,0,0, +-15,-28,52,32,5,-5,-17,-20,-10,-1}; diff --git a/ios/IOSDuoduo/Voice/Code/Libs/libspeex/exc_10_32_table.c b/ios/IOSDuoduo/Voice/Code/Libs/libspeex/exc_10_32_table.c new file mode 100755 index 000000000..1ee56a259 --- /dev/null +++ b/ios/IOSDuoduo/Voice/Code/Libs/libspeex/exc_10_32_table.c @@ -0,0 +1,66 @@ +/* Copyright (C) 2002 Jean-Marc Valin + File: exc_10_32_table.c + Codebook for excitation in narrowband CELP mode (4000 bps) + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + - Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + - Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + - Neither the name of the Xiph.org Foundation nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR + CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + + +const signed char exc_10_32_table[320] = { +7,17,17,27,25,22,12,4,-3,0, +28,-36,39,-24,-15,3,-9,15,-5,10, +31,-28,11,31,-21,9,-11,-11,-2,-7, +-25,14,-22,31,4,-14,19,-12,14,-5, +4,-7,4,-5,9,0,-2,42,-47,-16, +1,8,0,9,23,-57,0,28,-11,6, +-31,55,-45,3,-5,4,2,-2,4,-7, +-3,6,-2,7,-3,12,5,8,54,-10, +8,-7,-8,-24,-25,-27,-14,-5,8,5, +44,23,5,-9,-11,-11,-13,-9,-12,-8, +-29,-8,-22,6,-15,3,-12,-1,-5,-3, +34,-1,29,-16,17,-4,12,2,1,4, +-2,-4,2,-1,11,-3,-52,28,30,-9, +-32,25,44,-20,-24,4,6,-1,0,0, +0,0,0,0,0,0,0,0,0,0, +-25,-10,22,29,13,-13,-22,-13,-4,0, +-4,-16,10,15,-36,-24,28,25,-1,-3, +66,-33,-11,-15,6,0,3,4,-2,5, +24,-20,-47,29,19,-2,-4,-1,0,-1, +-2,3,1,8,-11,5,5,-57,28,28, +0,-16,4,-4,12,-6,-1,2,-20,61, +-9,24,-22,-42,29,6,17,8,4,2, +-65,15,8,10,5,6,5,3,2,-2, +-3,5,-9,4,-5,23,13,23,-3,-63, +3,-5,-4,-6,0,-3,23,-36,-46,9, +5,5,8,4,9,-5,1,-3,10,1, +-6,10,-11,24,-47,31,22,-12,14,-10, +6,11,-7,-7,7,-31,51,-12,-6,7, +6,-17,9,-11,-20,52,-19,3,-6,-6, +-8,-5,23,-41,37,1,-21,10,-14,8, +7,5,-15,-15,23,39,-26,-33,7,2, +-32,-30,-21,-8,4,12,17,15,14,11}; diff --git a/ios/IOSDuoduo/Voice/Code/Libs/libspeex/exc_20_32_table.c b/ios/IOSDuoduo/Voice/Code/Libs/libspeex/exc_20_32_table.c new file mode 100755 index 000000000..e4098b8d1 --- /dev/null +++ b/ios/IOSDuoduo/Voice/Code/Libs/libspeex/exc_20_32_table.c @@ -0,0 +1,66 @@ +/* Copyright (C) 2002 Jean-Marc Valin + File: exc_20_32_table.c + Codebook for excitation in narrowband CELP mode (2000 bps) + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + - Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + - Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + - Neither the name of the Xiph.org Foundation nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR + CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + + +const signed char exc_20_32_table[640] = { +12,32,25,46,36,33,9,14,-3,6,1,-8,0,-10,-5,-7,-7,-7,-5,-5, +31,-27,24,-32,-4,10,-11,21,-3,19,23,-9,22,24,-10,-1,-10,-13,-7,-11, +42,-33,31,19,-8,0,-10,-16,1,-21,-17,10,-8,14,8,4,11,-2,5,-2, +-33,11,-16,33,11,-4,9,-4,11,2,6,-5,8,-5,11,-4,-6,26,-36,-16, +0,4,-2,-8,12,6,-1,34,-46,-22,9,9,21,9,5,-66,-5,26,2,10, +13,2,19,9,12,-81,3,13,13,0,-14,22,-35,6,-7,-4,6,-6,10,-6, +-31,38,-33,0,-10,-11,5,-12,12,-17,5,0,-6,13,-9,10,8,25,33,2, +-12,8,-6,10,-2,21,7,17,43,5,11,-7,-9,-20,-36,-20,-23,-4,-4,-3, +27,-9,-9,-49,-39,-38,-11,-9,6,5,23,25,5,3,3,4,1,2,-3,-1, +87,39,17,-21,-9,-19,-9,-15,-13,-14,-17,-11,-10,-11,-8,-6,-1,-3,-3,-1, +-54,-34,-27,-8,-11,-4,-5,0,0,4,8,6,9,7,9,7,6,5,5,5, +48,10,19,-10,12,-1,9,-3,2,5,-3,2,-2,-2,0,-2,-26,6,9,-7, +-16,-9,2,7,7,-5,-43,11,22,-11,-9,34,37,-15,-13,-6,1,-1,1,1, +-64,56,52,-11,-27,5,4,3,1,2,1,3,-1,-4,-4,-10,-7,-4,-4,2, +-1,-7,-7,-12,-10,-15,-9,-5,-5,-11,-16,-13,6,16,4,-13,-16,-10,-4,2, +-47,-13,25,47,19,-14,-20,-8,-17,0,-3,-13,1,6,-17,-14,15,1,10,6, +-24,0,-10,19,-69,-8,14,49,17,-5,33,-29,3,-4,0,2,-8,5,-6,2, +120,-56,-12,-47,23,-9,6,-5,1,2,-5,1,-10,4,-1,-1,4,-1,0,-3, +30,-52,-67,30,22,11,-1,-4,3,0,7,2,0,1,-10,-4,-8,-13,5,1, +1,-1,5,13,-9,-3,-10,-62,22,48,-4,-6,2,3,5,1,1,4,1,13, +3,-20,10,-9,13,-2,-4,9,-20,44,-1,20,-32,-67,19,0,28,11,8,2, +-11,15,-19,-53,31,2,34,10,6,-4,-58,8,10,13,14,1,12,2,0,0, +-128,37,-8,44,-9,26,-3,18,2,6,11,-1,9,1,5,3,0,1,1,2, +12,3,-2,-3,7,25,9,18,-6,-37,3,-8,-16,3,-10,-7,17,-34,-44,11, +17,-15,-3,-16,-1,-13,11,-46,-65,-2,8,13,2,4,4,5,15,5,9,6, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +-9,19,-12,12,-28,38,29,-1,12,2,5,23,-10,3,4,-15,21,-4,3,3, +6,17,-9,-4,-8,-20,26,5,-10,6,1,-19,18,-15,-12,47,-6,-2,-7,-9, +-1,-17,-2,-2,-14,30,-14,2,-7,-4,-1,-12,11,-25,16,-3,-12,11,-7,7, +-17,1,19,-28,31,-7,-10,7,-10,3,12,5,-16,6,24,41,-29,-54,0,1, +7,-1,5,-6,13,10,-4,-8,8,-9,-27,-53,-38,-1,10,19,17,16,12,12, +0,3,-7,-4,13,12,-31,-14,6,-5,3,5,17,43,50,25,10,1,-6,-2}; diff --git a/ios/IOSDuoduo/Voice/Code/Libs/libspeex/exc_5_256_table.c b/ios/IOSDuoduo/Voice/Code/Libs/libspeex/exc_5_256_table.c new file mode 100755 index 000000000..4137996d4 --- /dev/null +++ b/ios/IOSDuoduo/Voice/Code/Libs/libspeex/exc_5_256_table.c @@ -0,0 +1,290 @@ +/* Copyright (C) 2002 Jean-Marc Valin + File: exc_5_256_table.c + Codebook for excitation in narrowband CELP mode (12800 bps) + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + - Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + - Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + - Neither the name of the Xiph.org Foundation nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR + CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + + +const signed char exc_5_256_table[1280] = { +-8,-37,5,-43,5, +73,61,39,12,-3, +-61,-32,2,42,30, +-3,17,-27,9,34, +20,-1,-5,2,23, +-7,-46,26,53,-47, +20,-2,-33,-89,-51, +-64,27,11,15,-34, +-5,-56,25,-9,-1, +-29,1,40,67,-23, +-16,16,33,19,7, +14,85,22,-10,-10, +-12,-7,-1,52,89, +29,11,-20,-37,-46, +-15,17,-24,-28,24, +2,1,0,23,-101, +23,14,-1,-23,-18, +9,5,-13,38,1, +-28,-28,4,27,51, +-26,34,-40,35,47, +54,38,-54,-26,-6, +42,-25,13,-30,-36, +18,41,-4,-33,23, +-32,-7,-4,51,-3, +17,-52,56,-47,36, +-2,-21,36,10,8, +-33,31,19,9,-5, +-40,10,-9,-21,19, +18,-78,-18,-5,0, +-26,-36,-47,-51,-44, +18,40,27,-2,29, +49,-26,2,32,-54, +30,-73,54,3,-5, +36,22,53,10,-1, +-84,-53,-29,-5,3, +-44,53,-51,4,22, +71,-35,-1,33,-5, +-27,-7,36,17,-23, +-39,16,-9,-55,-15, +-20,39,-35,6,-39, +-14,18,48,-64,-17, +-15,9,39,81,37, +-68,37,47,-21,-6, +-104,13,6,9,-2, +35,8,-23,18,42, +45,21,33,-5,-49, +9,-6,-43,-56,39, +2,-16,-25,87,1, +-3,-9,17,-25,-11, +-9,-1,10,2,-14, +-14,4,-1,-10,28, +-23,40,-32,26,-9, +26,4,-27,-23,3, +42,-60,1,49,-3, +27,10,-52,-40,-2, +18,45,-23,17,-44, +3,-3,17,-46,52, +-40,-47,25,75,31, +-49,53,30,-30,-32, +-36,38,-6,-15,-16, +54,-27,-48,3,38, +-29,-32,-22,-14,-4, +-23,-13,32,-39,9, +8,-45,-13,34,-16, +49,40,32,31,28, +23,23,32,47,59, +-68,8,62,44,25, +-14,-24,-65,-16,36, +67,-25,-38,-21,4, +-33,-2,42,5,-63, +40,11,26,-42,-23, +-61,79,-31,23,-20, +10,-32,53,-25,-36, +10,-26,-5,3,0, +-71,5,-10,-37,1, +-24,21,-54,-17,1, +-29,-25,-15,-27,32, +68,45,-16,-37,-18, +-5,1,0,-77,71, +-6,3,-20,71,-67, +29,-35,10,-30,19, +4,16,17,5,0, +-14,19,2,28,26, +59,3,2,24,39, +55,-50,-45,-18,-17, +33,-35,14,-1,1, +8,87,-35,-29,0, +-27,13,-7,23,-13, +37,-40,50,-35,14, +19,-7,-14,49,54, +-5,22,-2,-29,-8, +-27,38,13,27,48, +12,-41,-21,-15,28, +7,-16,-24,-19,-20, +11,-20,9,2,13, +23,-20,11,27,-27, +71,-69,8,2,-6, +22,12,16,16,9, +-16,-8,-17,1,25, +1,40,-37,-33,66, +94,53,4,-22,-25, +-41,-42,25,35,-16, +-15,57,31,-29,-32, +21,16,-60,45,15, +-1,7,57,-26,-47, +-29,11,8,15,19, +-105,-8,54,27,10, +-17,6,-12,-1,-10, +4,0,23,-10,31, +13,11,10,12,-64, +23,-3,-8,-19,16, +52,24,-40,16,10, +40,5,9,0,-13, +-7,-21,-8,-6,-7, +-21,59,16,-53,18, +-60,11,-47,14,-18, +25,-13,-24,4,-39, +16,-28,54,26,-67, +30,27,-20,-52,20, +-12,55,12,18,-16, +39,-14,-6,-26,56, +-88,-55,12,25,26, +-37,6,75,0,-34, +-81,54,-30,1,-7, +49,-23,-14,21,10, +-62,-58,-57,-47,-34, +15,-4,34,-78,31, +25,-11,7,50,-10, +42,-63,14,-36,-4, +57,55,57,53,42, +-42,-1,15,40,37, +15,25,-11,6,1, +31,-2,-6,-1,-7, +-64,34,28,30,-1, +3,21,0,-88,-12, +-56,25,-28,40,8, +-28,-14,9,12,2, +-6,-17,22,49,-6, +-26,14,28,-20,4, +-12,50,35,40,13, +-38,-58,-29,17,30, +22,60,26,-54,-39, +-12,58,-28,-63,10, +-21,-8,-12,26,-62, +6,-10,-11,-22,-6, +-7,4,1,18,2, +-70,11,14,4,13, +19,-24,-34,24,67, +17,51,-21,13,23, +54,-30,48,1,-13, +80,26,-16,-2,13, +-4,6,-30,29,-24, +73,-58,30,-27,20, +-2,-21,41,45,30, +-27,-3,-5,-18,-20, +-49,-3,-35,10,42, +-19,-67,-53,-11,9, +13,-15,-33,-51,-30, +15,7,25,-30,4, +28,-22,-34,54,-29, +39,-46,20,16,34, +-4,47,75,1,-44, +-55,-24,7,-1,9, +-42,50,-8,-36,41, +68,0,-4,-10,-23, +-15,-50,64,36,-9, +-27,12,25,-38,-47, +-37,32,-49,51,-36, +2,-4,69,-26,19, +7,45,67,46,13, +-63,46,15,-47,4, +-41,13,-6,5,-21, +37,26,-55,-7,33, +-1,-28,10,-17,-64, +-14,0,-36,-17,93, +-3,-9,-66,44,-21, +3,-12,38,-6,-13, +-12,19,13,43,-43, +-10,-12,6,-5,9, +-49,32,-5,2,4, +5,15,-16,10,-21, +8,-62,-8,64,8, +79,-1,-66,-49,-18, +5,40,-5,-30,-45, +1,-6,21,-32,93, +-18,-30,-21,32,21, +-18,22,8,5,-41, +-54,80,22,-10,-7, +-8,-23,-64,66,56, +-14,-30,-41,-46,-14, +-29,-37,27,-14,42, +-2,-9,-29,34,14, +33,-14,22,4,10, +26,26,28,32,23, +-72,-32,3,0,-14, +35,-42,-78,-32,6, +29,-18,-45,-5,7, +-33,-45,-3,-22,-34, +8,-8,4,-51,-25, +-9,59,-78,21,-5, +-25,-48,66,-15,-17, +-24,-49,-13,25,-23, +-64,-6,40,-24,-19, +-11,57,-33,-8,1, +10,-52,-54,28,39, +49,34,-11,-61,-41, +-43,10,15,-15,51, +30,15,-51,32,-34, +-2,-34,14,18,16, +1,1,-3,-3,1, +1,-18,6,16,48, +12,-5,-42,7,36, +48,7,-20,-10,7, +12,2,54,39,-38, +37,54,4,-11,-8, +-46,-10,5,-10,-34, +46,-12,29,-37,39, +36,-11,24,56,17, +14,20,25,0,-25, +-28,55,-7,-5,27, +3,9,-26,-8,6, +-24,-10,-30,-31,-34, +18,4,22,21,40, +-1,-29,-37,-8,-21, +92,-29,11,-3,11, +73,23,22,7,4, +-44,-9,-11,21,-13, +11,9,-78,-1,47, +114,-12,-37,-19,-5, +-11,-22,19,12,-30, +7,38,45,-21,-8, +-9,55,-45,56,-21, +7,17,46,-57,-87, +-6,27,31,31,7, +-56,-12,46,21,-5, +-12,36,3,3,-21, +43,19,12,-7,9, +-14,0,-9,-33,-91, +7,26,3,-11,64, +83,-31,-46,25,2, +9,5,2,2,-1, +20,-17,10,-5,-27, +-8,20,8,-19,16, +-21,-13,-31,5,5, +42,24,9,34,-20, +28,-61,22,11,-39, +64,-20,-1,-30,-9, +-20,24,-25,-24,-29, +22,-60,6,-5,41, +-9,-87,14,34,15, +-57,52,69,15,-3, +-102,58,16,3,6, +60,-75,-32,26,7, +-57,-27,-32,-24,-21, +-29,-16,62,-46,31, +30,-27,-15,7,15}; diff --git a/ios/IOSDuoduo/Voice/Code/Libs/libspeex/exc_5_64_table.c b/ios/IOSDuoduo/Voice/Code/Libs/libspeex/exc_5_64_table.c new file mode 100755 index 000000000..2c66d5189 --- /dev/null +++ b/ios/IOSDuoduo/Voice/Code/Libs/libspeex/exc_5_64_table.c @@ -0,0 +1,98 @@ +/* Copyright (C) 2002 Jean-Marc Valin + File: exc_5_64_table.c + Codebook for excitation in narrowband CELP mode (9600 bps) + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + - Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + - Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + - Neither the name of the Xiph.org Foundation nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR + CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + + +const signed char exc_5_64_table[320]={ +1,5,-15,49,-66, +-48,-4,50,-44,7, +37,16,-18,25,-26, +-26,-15,19,19,-27, +-47,28,57,5,-17, +-32,-41,68,21,-2, +64,56,8,-16,-13, +-26,-9,-16,11,6, +-39,25,-19,22,-31, +20,-45,55,-43,10, +-16,47,-40,40,-20, +-51,3,-17,-14,-15, +-24,53,-20,-46,46, +27,-68,32,3,-18, +-5,9,-31,16,-9, +-10,-1,-23,48,95, +47,25,-41,-32,-3, +15,-25,-55,36,41, +-27,20,5,13,14, +-22,5,2,-23,18, +46,-15,17,-18,-34, +-5,-8,27,-55,73, +16,2,-1,-17,40, +-78,33,0,2,19, +4,53,-16,-15,-16, +-28,-3,-13,49,8, +-7,-29,27,-13,32, +20,32,-61,16,14, +41,44,40,24,20, +7,4,48,-60,-77, +17,-6,-48,65,-15, +32,-30,-71,-10,-3, +-6,10,-2,-7,-29, +-56,67,-30,7,-5, +86,-6,-10,0,5, +-31,60,34,-38,-3, +24,10,-2,30,23, +24,-41,12,70,-43, +15,-17,6,13,16, +-13,8,30,-15,-8, +5,23,-34,-98,-4, +-13,13,-48,-31,70, +12,31,25,24,-24, +26,-7,33,-16,8, +5,-11,-14,-8,-65, +13,10,-2,-9,0, +-3,-68,5,35,7, +0,-31,-1,-17,-9, +-9,16,-37,-18,-1, +69,-48,-28,22,-21, +-11,5,49,55,23, +-86,-36,16,2,13, +63,-51,30,-11,13, +24,-18,-6,14,-19, +1,41,9,-5,27, +-36,-44,-34,-37,-21, +-26,31,-39,15,43, +5,-8,29,20,-8, +-20,-52,-28,-1,13, +26,-34,-10,-9,27, +-8,8,27,-66,4, +12,-22,49,10,-77, +32,-18,3,-38,12, +-3,-1,2,2,0}; diff --git a/ios/IOSDuoduo/Voice/Code/Libs/libspeex/exc_8_128_table.c b/ios/IOSDuoduo/Voice/Code/Libs/libspeex/exc_8_128_table.c new file mode 100755 index 000000000..17ee64b92 --- /dev/null +++ b/ios/IOSDuoduo/Voice/Code/Libs/libspeex/exc_8_128_table.c @@ -0,0 +1,162 @@ +/* Copyright (C) 2002 Jean-Marc Valin + File: exc_8_128_table.c + Codebook for excitation in narrowband CELP mode (7000 bps) + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + - Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + - Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + - Neither the name of the Xiph.org Foundation nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR + CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + + +const signed char exc_8_128_table[1024] = { +-14,9,13,-32,2,-10,31,-10, +-8,-8,6,-4,-1,10,-64,23, +6,20,13,6,8,-22,16,34, +7,42,-49,-28,5,26,4,-15, +41,34,41,32,33,24,23,14, +8,40,34,4,-24,-41,-19,-15, +13,-13,33,-54,24,27,-44,33, +27,-15,-15,24,-19,14,-36,14, +-9,24,-12,-4,37,-5,16,-34, +5,10,33,-15,-54,-16,12,25, +12,1,2,0,3,-1,-4,-4, +11,2,-56,54,27,-20,13,-6, +-46,-41,-33,-11,-5,7,12,14, +-14,-5,8,20,6,3,4,-8, +-5,-42,11,8,-14,25,-2,2, +13,11,-22,39,-9,9,5,-45, +-9,7,-9,12,-7,34,-17,-102, +7,2,-42,18,35,-9,-34,11, +-5,-2,3,22,46,-52,-25,-9, +-94,8,11,-5,-5,-5,4,-7, +-35,-7,54,5,-32,3,24,-9, +-22,8,65,37,-1,-12,-23,-6, +-9,-28,55,-33,14,-3,2,18, +-60,41,-17,8,-16,17,-11,0, +-11,29,-28,37,9,-53,33,-14, +-9,7,-25,-7,-11,26,-32,-8, +24,-21,22,-19,19,-10,29,-14, +0,0,0,0,0,0,0,0, +-5,-52,10,41,6,-30,-4,16, +32,22,-27,-22,32,-3,-28,-3, +3,-35,6,17,23,21,8,2, +4,-45,-17,14,23,-4,-31,-11, +-3,14,1,19,-11,2,61,-8, +9,-12,7,-10,12,-3,-24,99, +-48,23,50,-37,-5,-23,0,8, +-14,35,-64,-5,46,-25,13,-1, +-49,-19,-15,9,34,50,25,11, +-6,-9,-16,-20,-32,-33,-32,-27, +10,-8,12,-15,56,-14,-32,33, +3,-9,1,65,-9,-9,-10,-2, +-6,-23,9,17,3,-28,13,-32, +4,-2,-10,4,-16,76,12,-52, +6,13,33,-6,4,-14,-9,-3, +1,-15,-16,28,1,-15,11,16, +9,4,-21,-37,-40,-6,22,12, +-15,-23,-14,-17,-16,-9,-10,-9, +13,-39,41,5,-9,16,-38,25, +46,-47,4,49,-14,17,-2,6, +18,5,-6,-33,-22,44,50,-2, +1,3,-6,7,7,-3,-21,38, +-18,34,-14,-41,60,-13,6,16, +-24,35,19,-13,-36,24,3,-17, +-14,-10,36,44,-44,-29,-3,3, +-54,-8,12,55,26,4,-2,-5, +2,-11,22,-23,2,22,1,-25, +-39,66,-49,21,-8,-2,10,-14, +-60,25,6,10,27,-25,16,5, +-2,-9,26,-13,-20,58,-2,7, +52,-9,2,5,-4,-15,23,-1, +-38,23,8,27,-6,0,-27,-7, +39,-10,-14,26,11,-45,-12,9, +-5,34,4,-35,10,43,-22,-11, +56,-7,20,1,10,1,-26,9, +94,11,-27,-14,-13,1,-11,0, +14,-5,-6,-10,-4,-15,-8,-41, +21,-5,1,-28,-8,22,-9,33, +-23,-4,-4,-12,39,4,-7,3, +-60,80,8,-17,2,-6,12,-5, +1,9,15,27,31,30,27,23, +61,47,26,10,-5,-8,-12,-13, +5,-18,25,-15,-4,-15,-11,12, +-2,-2,-16,-2,-6,24,12,11, +-4,9,1,-9,14,-45,57,12, +20,-35,26,11,-64,32,-10,-10, +42,-4,-9,-16,32,24,7,10, +52,-11,-57,29,0,8,0,-6, +17,-17,-56,-40,7,20,18,12, +-6,16,5,7,-1,9,1,10, +29,12,16,13,-2,23,7,9, +-3,-4,-5,18,-64,13,55,-25, +9,-9,24,14,-25,15,-11,-40, +-30,37,1,-19,22,-5,-31,13, +-2,0,7,-4,16,-67,12,66, +-36,24,-8,18,-15,-23,19,0, +-45,-7,4,3,-13,13,35,5, +13,33,10,27,23,0,-7,-11, +43,-74,36,-12,2,5,-8,6, +-33,11,-16,-14,-5,-7,-3,17, +-34,27,-16,11,-9,15,33,-31, +8,-16,7,-6,-7,63,-55,-17, +11,-1,20,-46,34,-30,6,9, +19,28,-9,5,-24,-8,-23,-2, +31,-19,-16,-5,-15,-18,0,26, +18,37,-5,-15,-2,17,5,-27, +21,-33,44,12,-27,-9,17,11, +25,-21,-31,-7,13,33,-8,-25, +-7,7,-10,4,-6,-9,48,-82, +-23,-8,6,11,-23,3,-3,49, +-29,25,31,4,14,16,9,-4, +-18,10,-26,3,5,-44,-9,9, +-47,-55,15,9,28,1,4,-3, +46,6,-6,-38,-29,-31,-15,-6, +3,0,14,-6,8,-54,-50,33, +-5,1,-14,33,-48,26,-4,-5, +-3,-5,-3,-5,-28,-22,77,55, +-1,2,10,10,-9,-14,-66,-49, +11,-36,-6,-20,10,-10,16,12, +4,-1,-16,45,-44,-50,31,-2, +25,42,23,-32,-22,0,11,20, +-40,-35,-40,-36,-32,-26,-21,-13, +52,-22,6,-24,-20,17,-5,-8, +36,-25,-11,21,-26,6,34,-8, +7,20,-3,5,-25,-8,18,-5, +-9,-4,1,-9,20,20,39,48, +-24,9,5,-65,22,29,4,3, +-43,-11,32,-6,9,19,-27,-10, +-47,-14,24,10,-7,-36,-7,-1, +-4,-5,-5,16,53,25,-26,-29, +-4,-12,45,-58,-34,33,-5,2, +-1,27,-48,31,-15,22,-5,4, +7,7,-25,-3,11,-22,16,-12, +8,-3,7,-11,45,14,-73,-19, +56,-46,24,-20,28,-12,-2,-1, +-36,-3,-33,19,-6,7,2,-15, +5,-31,-45,8,35,13,20,0, +-9,48,-13,-43,-3,-13,2,-5, +72,-68,-27,2,1,-2,-7,5, +36,33,-40,-12,-4,-5,23,19}; diff --git a/ios/IOSDuoduo/Voice/Code/Libs/libspeex/fftwrap.c b/ios/IOSDuoduo/Voice/Code/Libs/libspeex/fftwrap.c new file mode 100755 index 000000000..4f37e1b3f --- /dev/null +++ b/ios/IOSDuoduo/Voice/Code/Libs/libspeex/fftwrap.c @@ -0,0 +1,397 @@ +/* Copyright (C) 2005-2006 Jean-Marc Valin + File: fftwrap.c + + Wrapper for various FFTs + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + - Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + - Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + - Neither the name of the Xiph.org Foundation nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR + CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +*/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "arch.h" +#include "os_support.h" + +#define MAX_FFT_SIZE 2048 + +#ifdef FIXED_POINT +static int maximize_range(spx_word16_t *in, spx_word16_t *out, spx_word16_t bound, int len) +{ + int i, shift; + spx_word16_t max_val = 0; + for (i=0;imax_val) + max_val = in[i]; + if (-in[i]>max_val) + max_val = -in[i]; + } + shift=0; + while (max_val <= (bound>>1) && max_val != 0) + { + max_val <<= 1; + shift++; + } + for (i=0;i + +void *spx_fft_init(int size) +{ + struct drft_lookup *table; + table = speex_alloc(sizeof(struct drft_lookup)); + spx_drft_init((struct drft_lookup *)table, size); + return (void*)table; +} + +void spx_fft_destroy(void *table) +{ + spx_drft_clear(table); + speex_free(table); +} + +void spx_fft(void *table, float *in, float *out) +{ + if (in==out) + { + int i; + float scale = 1./((struct drft_lookup *)table)->n; + speex_warning("FFT should not be done in-place"); + for (i=0;i<((struct drft_lookup *)table)->n;i++) + out[i] = scale*in[i]; + } else { + int i; + float scale = 1./((struct drft_lookup *)table)->n; + for (i=0;i<((struct drft_lookup *)table)->n;i++) + out[i] = scale*in[i]; + } + spx_drft_forward((struct drft_lookup *)table, out); +} + +void spx_ifft(void *table, float *in, float *out) +{ + if (in==out) + { + speex_warning("FFT should not be done in-place"); + } else { + int i; + for (i=0;i<((struct drft_lookup *)table)->n;i++) + out[i] = in[i]; + } + spx_drft_backward((struct drft_lookup *)table, out); +} + +#elif defined(USE_INTEL_MKL) +#include + +struct mkl_config { + DFTI_DESCRIPTOR_HANDLE desc; + int N; +}; + +void *spx_fft_init(int size) +{ + struct mkl_config *table = (struct mkl_config *) speex_alloc(sizeof(struct mkl_config)); + table->N = size; + DftiCreateDescriptor(&table->desc, DFTI_SINGLE, DFTI_REAL, 1, size); + DftiSetValue(table->desc, DFTI_PACKED_FORMAT, DFTI_PACK_FORMAT); + DftiSetValue(table->desc, DFTI_PLACEMENT, DFTI_NOT_INPLACE); + DftiSetValue(table->desc, DFTI_FORWARD_SCALE, 1.0f / size); + DftiCommitDescriptor(table->desc); + return table; +} + +void spx_fft_destroy(void *table) +{ + struct mkl_config *t = (struct mkl_config *) table; + DftiFreeDescriptor(t->desc); + speex_free(table); +} + +void spx_fft(void *table, spx_word16_t *in, spx_word16_t *out) +{ + struct mkl_config *t = (struct mkl_config *) table; + DftiComputeForward(t->desc, in, out); +} + +void spx_ifft(void *table, spx_word16_t *in, spx_word16_t *out) +{ + struct mkl_config *t = (struct mkl_config *) table; + DftiComputeBackward(t->desc, in, out); +} + +#elif defined(USE_GPL_FFTW3) + +#include + +struct fftw_config { + float *in; + float *out; + fftwf_plan fft; + fftwf_plan ifft; + int N; +}; + +void *spx_fft_init(int size) +{ + struct fftw_config *table = (struct fftw_config *) speex_alloc(sizeof(struct fftw_config)); + table->in = fftwf_malloc(sizeof(float) * (size+2)); + table->out = fftwf_malloc(sizeof(float) * (size+2)); + + table->fft = fftwf_plan_dft_r2c_1d(size, table->in, (fftwf_complex *) table->out, FFTW_PATIENT); + table->ifft = fftwf_plan_dft_c2r_1d(size, (fftwf_complex *) table->in, table->out, FFTW_PATIENT); + + table->N = size; + return table; +} + +void spx_fft_destroy(void *table) +{ + struct fftw_config *t = (struct fftw_config *) table; + fftwf_destroy_plan(t->fft); + fftwf_destroy_plan(t->ifft); + fftwf_free(t->in); + fftwf_free(t->out); + speex_free(table); +} + + +void spx_fft(void *table, spx_word16_t *in, spx_word16_t *out) +{ + int i; + struct fftw_config *t = (struct fftw_config *) table; + const int N = t->N; + float *iptr = t->in; + float *optr = t->out; + const float m = 1.0 / N; + for(i=0;ifft); + + out[0] = optr[0]; + for(i=1;iN; + float *iptr = t->in; + float *optr = t->out; + + iptr[0] = in[0]; + iptr[1] = 0.0f; + for(i=1;iifft); + + for(i=0;iforward = kiss_fftr_alloc(size,0,NULL,NULL); + table->backward = kiss_fftr_alloc(size,1,NULL,NULL); + table->N = size; + return table; +} + +void spx_fft_destroy(void *table) +{ + struct kiss_config *t = (struct kiss_config *)table; + kiss_fftr_free(t->forward); + kiss_fftr_free(t->backward); + speex_free(table); +} + +#ifdef FIXED_POINT + +void spx_fft(void *table, spx_word16_t *in, spx_word16_t *out) +{ + int shift; + struct kiss_config *t = (struct kiss_config *)table; + shift = maximize_range(in, in, 32000, t->N); + kiss_fftr2(t->forward, in, out); + renorm_range(in, in, shift, t->N); + renorm_range(out, out, shift, t->N); +} + +#else + +void spx_fft(void *table, spx_word16_t *in, spx_word16_t *out) +{ + int i; + float scale; + struct kiss_config *t = (struct kiss_config *)table; + scale = 1./t->N; + kiss_fftr2(t->forward, in, out); + for (i=0;iN;i++) + out[i] *= scale; +} +#endif + +void spx_ifft(void *table, spx_word16_t *in, spx_word16_t *out) +{ + struct kiss_config *t = (struct kiss_config *)table; + kiss_fftri2(t->backward, in, out); +} + + +#else + +#error No other FFT implemented + +#endif + + +#ifdef FIXED_POINT +/*#include "smallft.h"*/ + + +void spx_fft_float(void *table, float *in, float *out) +{ + int i; +#ifdef USE_SMALLFT + int N = ((struct drft_lookup *)table)->n; +#elif defined(USE_KISS_FFT) + int N = ((struct kiss_config *)table)->N; +#else +#endif +#ifdef VAR_ARRAYS + spx_word16_t _in[N]; + spx_word16_t _out[N]; +#else + spx_word16_t _in[MAX_FFT_SIZE]; + spx_word16_t _out[MAX_FFT_SIZE]; +#endif + for (i=0;iN); + scale = 1./((struct kiss_config *)table)->N; + for (i=0;i<((struct kiss_config *)table)->N;i++) + out[i] = scale*in[i]; + spx_drft_forward(&t, out); + spx_drft_clear(&t); + } +#endif +} + +void spx_ifft_float(void *table, float *in, float *out) +{ + int i; +#ifdef USE_SMALLFT + int N = ((struct drft_lookup *)table)->n; +#elif defined(USE_KISS_FFT) + int N = ((struct kiss_config *)table)->N; +#else +#endif +#ifdef VAR_ARRAYS + spx_word16_t _in[N]; + spx_word16_t _out[N]; +#else + spx_word16_t _in[MAX_FFT_SIZE]; + spx_word16_t _out[MAX_FFT_SIZE]; +#endif + for (i=0;iN); + for (i=0;i<((struct kiss_config *)table)->N;i++) + out[i] = in[i]; + spx_drft_backward(&t, out); + spx_drft_clear(&t); + } +#endif +} + +#else + +void spx_fft_float(void *table, float *in, float *out) +{ + spx_fft(table, in, out); +} +void spx_ifft_float(void *table, float *in, float *out) +{ + spx_ifft(table, in, out); +} + +#endif diff --git a/ios/IOSDuoduo/Voice/Code/Libs/libspeex/fftwrap.h b/ios/IOSDuoduo/Voice/Code/Libs/libspeex/fftwrap.h new file mode 100755 index 000000000..dfaf48944 --- /dev/null +++ b/ios/IOSDuoduo/Voice/Code/Libs/libspeex/fftwrap.h @@ -0,0 +1,58 @@ +/* Copyright (C) 2005 Jean-Marc Valin + File: fftwrap.h + + Wrapper for various FFTs + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + - Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + - Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + - Neither the name of the Xiph.org Foundation nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR + CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +*/ + +#ifndef FFTWRAP_H +#define FFTWRAP_H + +#include "arch.h" + +/** Compute tables for an FFT */ +void *spx_fft_init(int size); + +/** Destroy tables for an FFT */ +void spx_fft_destroy(void *table); + +/** Forward (real to half-complex) transform */ +void spx_fft(void *table, spx_word16_t *in, spx_word16_t *out); + +/** Backward (half-complex to real) transform */ +void spx_ifft(void *table, spx_word16_t *in, spx_word16_t *out); + +/** Forward (real to half-complex) transform of float data */ +void spx_fft_float(void *table, float *in, float *out); + +/** Backward (half-complex to real) transform of float data */ +void spx_ifft_float(void *table, float *in, float *out); + +#endif diff --git a/ios/IOSDuoduo/Voice/Code/Libs/libspeex/filterbank.c b/ios/IOSDuoduo/Voice/Code/Libs/libspeex/filterbank.c new file mode 100755 index 000000000..e2fb71d4b --- /dev/null +++ b/ios/IOSDuoduo/Voice/Code/Libs/libspeex/filterbank.c @@ -0,0 +1,227 @@ +/* Copyright (C) 2006 Jean-Marc Valin */ +/** + @file filterbank.c + @brief Converting between psd and filterbank + */ +/* + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are + met: + + 1. Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + 3. The name of the author may not be used to endorse or promote products + derived from this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, + INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + POSSIBILITY OF SUCH DAMAGE. +*/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "filterbank.h" +#include "arch.h" +#include +#include "math_approx.h" +#include "os_support.h" + +#ifdef FIXED_POINT + +#define toBARK(n) (MULT16_16(26829,spx_atan(SHR32(MULT16_16(97,n),2))) + MULT16_16(4588,spx_atan(MULT16_32_Q15(20,MULT16_16(n,n)))) + MULT16_16(3355,n)) + +#else +#define toBARK(n) (13.1f*atan(.00074f*(n))+2.24f*atan((n)*(n)*1.85e-8f)+1e-4f*(n)) +#endif + +#define toMEL(n) (2595.f*log10(1.f+(n)/700.f)) + +FilterBank *filterbank_new(int banks, spx_word32_t sampling, int len, int type) +{ + FilterBank *bank; + spx_word32_t df; + spx_word32_t max_mel, mel_interval; + int i; + int id1; + int id2; + df = DIV32(SHL32(sampling,15),MULT16_16(2,len)); + max_mel = toBARK(EXTRACT16(sampling/2)); + mel_interval = PDIV32(max_mel,banks-1); + + bank = (FilterBank*)speex_alloc(sizeof(FilterBank)); + bank->nb_banks = banks; + bank->len = len; + bank->bank_left = (int*)speex_alloc(len*sizeof(int)); + bank->bank_right = (int*)speex_alloc(len*sizeof(int)); + bank->filter_left = (spx_word16_t*)speex_alloc(len*sizeof(spx_word16_t)); + bank->filter_right = (spx_word16_t*)speex_alloc(len*sizeof(spx_word16_t)); + /* Think I can safely disable normalisation that for fixed-point (and probably float as well) */ +#ifndef FIXED_POINT + bank->scaling = (float*)speex_alloc(banks*sizeof(float)); +#endif + for (i=0;i max_mel) + break; +#ifdef FIXED_POINT + id1 = DIV32(mel,mel_interval); +#else + id1 = (int)(floor(mel/mel_interval)); +#endif + if (id1>banks-2) + { + id1 = banks-2; + val = Q15_ONE; + } else { + val = DIV32_16(mel - id1*mel_interval,EXTRACT16(PSHR32(mel_interval,15))); + } + id2 = id1+1; + bank->bank_left[i] = id1; + bank->filter_left[i] = SUB16(Q15_ONE,val); + bank->bank_right[i] = id2; + bank->filter_right[i] = val; + } + + /* Think I can safely disable normalisation for fixed-point (and probably float as well) */ +#ifndef FIXED_POINT + for (i=0;inb_banks;i++) + bank->scaling[i] = 0; + for (i=0;ilen;i++) + { + int id = bank->bank_left[i]; + bank->scaling[id] += bank->filter_left[i]; + id = bank->bank_right[i]; + bank->scaling[id] += bank->filter_right[i]; + } + for (i=0;inb_banks;i++) + bank->scaling[i] = Q15_ONE/(bank->scaling[i]); +#endif + return bank; +} + +void filterbank_destroy(FilterBank *bank) +{ + speex_free(bank->bank_left); + speex_free(bank->bank_right); + speex_free(bank->filter_left); + speex_free(bank->filter_right); +#ifndef FIXED_POINT + speex_free(bank->scaling); +#endif + speex_free(bank); +} + +void filterbank_compute_bank32(FilterBank *bank, spx_word32_t *ps, spx_word32_t *mel) +{ + int i; + for (i=0;inb_banks;i++) + mel[i] = 0; + + for (i=0;ilen;i++) + { + int id; + id = bank->bank_left[i]; + mel[id] += MULT16_32_P15(bank->filter_left[i],ps[i]); + id = bank->bank_right[i]; + mel[id] += MULT16_32_P15(bank->filter_right[i],ps[i]); + } + /* Think I can safely disable normalisation that for fixed-point (and probably float as well) */ +#ifndef FIXED_POINT + /*for (i=0;inb_banks;i++) + mel[i] = MULT16_32_P15(Q15(bank->scaling[i]),mel[i]); + */ +#endif +} + +void filterbank_compute_psd16(FilterBank *bank, spx_word16_t *mel, spx_word16_t *ps) +{ + int i; + for (i=0;ilen;i++) + { + spx_word32_t tmp; + int id1, id2; + id1 = bank->bank_left[i]; + id2 = bank->bank_right[i]; + tmp = MULT16_16(mel[id1],bank->filter_left[i]); + tmp += MULT16_16(mel[id2],bank->filter_right[i]); + ps[i] = EXTRACT16(PSHR32(tmp,15)); + } +} + + +#ifndef FIXED_POINT +void filterbank_compute_bank(FilterBank *bank, float *ps, float *mel) +{ + int i; + for (i=0;inb_banks;i++) + mel[i] = 0; + + for (i=0;ilen;i++) + { + int id = bank->bank_left[i]; + mel[id] += bank->filter_left[i]*ps[i]; + id = bank->bank_right[i]; + mel[id] += bank->filter_right[i]*ps[i]; + } + for (i=0;inb_banks;i++) + mel[i] *= bank->scaling[i]; +} + +void filterbank_compute_psd(FilterBank *bank, float *mel, float *ps) +{ + int i; + for (i=0;ilen;i++) + { + int id = bank->bank_left[i]; + ps[i] = mel[id]*bank->filter_left[i]; + id = bank->bank_right[i]; + ps[i] += mel[id]*bank->filter_right[i]; + } +} + +void filterbank_psy_smooth(FilterBank *bank, float *ps, float *mask) +{ + /* Low freq slope: 14 dB/Bark*/ + /* High freq slope: 9 dB/Bark*/ + /* Noise vs tone: 5 dB difference */ + /* FIXME: Temporary kludge */ + float bark[100]; + int i; + /* Assumes 1/3 Bark resolution */ + float decay_low = 0.34145f; + float decay_high = 0.50119f; + filterbank_compute_bank(bank, ps, bark); + for (i=1;inb_banks;i++) + { + /*float decay_high = 13-1.6*log10(bark[i-1]); + decay_high = pow(10,(-decay_high/30.f));*/ + bark[i] = bark[i] + decay_high*bark[i-1]; + } + for (i=bank->nb_banks-2;i>=0;i--) + { + bark[i] = bark[i] + decay_low*bark[i+1]; + } + filterbank_compute_psd(bank, bark, mask); +} + +#endif diff --git a/ios/IOSDuoduo/Voice/Code/Libs/libspeex/filterbank.h b/ios/IOSDuoduo/Voice/Code/Libs/libspeex/filterbank.h new file mode 100755 index 000000000..3e889a22f --- /dev/null +++ b/ios/IOSDuoduo/Voice/Code/Libs/libspeex/filterbank.h @@ -0,0 +1,66 @@ +/* Copyright (C) 2006 Jean-Marc Valin */ +/** + @file filterbank.h + @brief Converting between psd and filterbank + */ +/* + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are + met: + + 1. Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + 3. The name of the author may not be used to endorse or promote products + derived from this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, + INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + POSSIBILITY OF SUCH DAMAGE. +*/ + +#ifndef FILTERBANK_H +#define FILTERBANK_H + +#include "arch.h" + +typedef struct { + int *bank_left; + int *bank_right; + spx_word16_t *filter_left; + spx_word16_t *filter_right; +#ifndef FIXED_POINT + float *scaling; +#endif + int nb_banks; + int len; +} FilterBank; + + +FilterBank *filterbank_new(int banks, spx_word32_t sampling, int len, int type); + +void filterbank_destroy(FilterBank *bank); + +void filterbank_compute_bank32(FilterBank *bank, spx_word32_t *ps, spx_word32_t *mel); + +void filterbank_compute_psd16(FilterBank *bank, spx_word16_t *mel, spx_word16_t *psd); + +#ifndef FIXED_POINT +void filterbank_compute_bank(FilterBank *bank, float *psd, float *mel); +void filterbank_compute_psd(FilterBank *bank, float *mel, float *psd); +#endif + + +#endif diff --git a/ios/IOSDuoduo/Voice/Code/Libs/libspeex/filters.c b/ios/IOSDuoduo/Voice/Code/Libs/libspeex/filters.c new file mode 100755 index 000000000..36ef4f697 --- /dev/null +++ b/ios/IOSDuoduo/Voice/Code/Libs/libspeex/filters.c @@ -0,0 +1,821 @@ +/* Copyright (C) 2002-2006 Jean-Marc Valin + File: filters.c + Various analysis/synthesis filters + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + - Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + - Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + - Neither the name of the Xiph.org Foundation nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR + CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "filters.h" +#include "stack_alloc.h" +#include "arch.h" +#include "math_approx.h" +#include "ltp.h" +#include + +#ifdef _USE_SSE +#include "filters_sse.h" +#elif defined (ARM4_ASM) || defined(ARM5E_ASM) +#include "filters_arm4.h" +#elif defined (BFIN_ASM) +#include "filters_bfin.h" +#endif + + + +void bw_lpc(spx_word16_t gamma, const spx_coef_t *lpc_in, spx_coef_t *lpc_out, int order) +{ + int i; + spx_word16_t tmp=gamma; + for (i=0;i=min_val && vec[i] <= max_val)) + { + if (vec[i] < min_val) + vec[i] = min_val; + else if (vec[i] > max_val) + vec[i] = max_val; + else /* Has to be NaN */ + vec[i] = 0; + } + } +} + +void highpass(const spx_word16_t *x, spx_word16_t *y, int len, int filtID, spx_mem_t *mem) +{ + int i; +#ifdef FIXED_POINT + const spx_word16_t Pcoef[5][3] = {{16384, -31313, 14991}, {16384, -31569, 15249}, {16384, -31677, 15328}, {16384, -32313, 15947}, {16384, -22446, 6537}}; + const spx_word16_t Zcoef[5][3] = {{15672, -31344, 15672}, {15802, -31601, 15802}, {15847, -31694, 15847}, {16162, -32322, 16162}, {14418, -28836, 14418}}; +#else + const spx_word16_t Pcoef[5][3] = {{1.00000f, -1.91120f, 0.91498f}, {1.00000f, -1.92683f, 0.93071f}, {1.00000f, -1.93338f, 0.93553f}, {1.00000f, -1.97226f, 0.97332f}, {1.00000f, -1.37000f, 0.39900f}}; + const spx_word16_t Zcoef[5][3] = {{0.95654f, -1.91309f, 0.95654f}, {0.96446f, -1.92879f, 0.96446f}, {0.96723f, -1.93445f, 0.96723f}, {0.98645f, -1.97277f, 0.98645f}, {0.88000f, -1.76000f, 0.88000f}}; +#endif + const spx_word16_t *den, *num; + if (filtID>4) + filtID=4; + + den = Pcoef[filtID]; num = Zcoef[filtID]; + /*return;*/ + for (i=0;i SHL32(EXTEND32(SIG_SCALING), 8)) + { + spx_word16_t scale_1; + scale = PSHR32(scale, SIG_SHIFT); + scale_1 = EXTRACT16(PDIV32_16(SHL32(EXTEND32(SIG_SCALING),7),scale)); + for (i=0;i SHR32(EXTEND32(SIG_SCALING), 2)) { + spx_word16_t scale_1; + scale = PSHR32(scale, SIG_SHIFT-5); + scale_1 = DIV32_16(SHL32(EXTEND32(SIG_SCALING),3),scale); + for (i=0;i max_val) + max_val = tmp; + } + + sig_shift=0; + while (max_val>16383) + { + sig_shift++; + max_val >>= 1; + } + + for (i=0;i max_val) + max_val = tmp; + } + if (max_val>16383) + { + spx_word32_t sum=0; + for (i=0;i= max_val) + max_val = tmp; + } + + sig_shift=0; + while (max_val>max_scale) + { + sig_shift++; + max_val >>= 1; + } + + for (i=0;i>1; + for (i=0;i>1; + N2 = N>>1; + ALLOC(xx1, M2+N2, spx_word16_t); + ALLOC(xx2, M2+N2, spx_word16_t); + + for (i = 0; i < N2; i++) + xx1[i] = x1[N2-1-i]; + for (i = 0; i < M2; i++) + xx1[N2+i] = mem1[2*i+1]; + for (i = 0; i < N2; i++) + xx2[i] = x2[N2-1-i]; + for (i = 0; i < M2; i++) + xx2[N2+i] = mem2[2*i+1]; + + for (i = 0; i < N2; i += 2) { + spx_sig_t y0, y1, y2, y3; + spx_word16_t x10, x20; + + y0 = y1 = y2 = y3 = 0; + x10 = xx1[N2-2-i]; + x20 = xx2[N2-2-i]; + + for (j = 0; j < M2; j += 2) { + spx_word16_t x11, x21; + spx_word16_t a0, a1; + + a0 = a[2*j]; + a1 = a[2*j+1]; + x11 = xx1[N2-1+j-i]; + x21 = xx2[N2-1+j-i]; + +#ifdef FIXED_POINT + /* We multiply twice by the same coef to avoid overflows */ + y0 = MAC16_16(MAC16_16(y0, a0, x11), NEG16(a0), x21); + y1 = MAC16_16(MAC16_16(y1, a1, x11), a1, x21); + y2 = MAC16_16(MAC16_16(y2, a0, x10), NEG16(a0), x20); + y3 = MAC16_16(MAC16_16(y3, a1, x10), a1, x20); +#else + y0 = ADD32(y0,MULT16_16(a0, x11-x21)); + y1 = ADD32(y1,MULT16_16(a1, x11+x21)); + y2 = ADD32(y2,MULT16_16(a0, x10-x20)); + y3 = ADD32(y3,MULT16_16(a1, x10+x20)); +#endif + a0 = a[2*j+2]; + a1 = a[2*j+3]; + x10 = xx1[N2+j-i]; + x20 = xx2[N2+j-i]; + +#ifdef FIXED_POINT + /* We multiply twice by the same coef to avoid overflows */ + y0 = MAC16_16(MAC16_16(y0, a0, x10), NEG16(a0), x20); + y1 = MAC16_16(MAC16_16(y1, a1, x10), a1, x20); + y2 = MAC16_16(MAC16_16(y2, a0, x11), NEG16(a0), x21); + y3 = MAC16_16(MAC16_16(y3, a1, x11), a1, x21); +#else + y0 = ADD32(y0,MULT16_16(a0, x10-x20)); + y1 = ADD32(y1,MULT16_16(a1, x10+x20)); + y2 = ADD32(y2,MULT16_16(a0, x11-x21)); + y3 = ADD32(y3,MULT16_16(a1, x11+x21)); +#endif + } +#ifdef FIXED_POINT + y[2*i] = EXTRACT16(SATURATE32(PSHR32(y0,15),32767)); + y[2*i+1] = EXTRACT16(SATURATE32(PSHR32(y1,15),32767)); + y[2*i+2] = EXTRACT16(SATURATE32(PSHR32(y2,15),32767)); + y[2*i+3] = EXTRACT16(SATURATE32(PSHR32(y3,15),32767)); +#else + /* Normalize up explicitly if we're in float */ + y[2*i] = 2.f*y0; + y[2*i+1] = 2.f*y1; + y[2*i+2] = 2.f*y2; + y[2*i+3] = 2.f*y3; +#endif + } + + for (i = 0; i < M2; i++) + mem1[2*i+1] = xx1[i]; + for (i = 0; i < M2; i++) + mem2[2*i+1] = xx2[i]; +} + +#ifdef FIXED_POINT +#if 0 +const spx_word16_t shift_filt[3][7] = {{-33, 1043, -4551, 19959, 19959, -4551, 1043}, + {-98, 1133, -4425, 29179, 8895, -2328, 444}, + {444, -2328, 8895, 29179, -4425, 1133, -98}}; +#else +const spx_word16_t shift_filt[3][7] = {{-390, 1540, -4993, 20123, 20123, -4993, 1540}, + {-1064, 2817, -6694, 31589, 6837, -990, -209}, + {-209, -990, 6837, 31589, -6694, 2817, -1064}}; +#endif +#else +#if 0 +const float shift_filt[3][7] = {{-9.9369e-04, 3.1831e-02, -1.3889e-01, 6.0910e-01, 6.0910e-01, -1.3889e-01, 3.1831e-02}, + {-0.0029937, 0.0345613, -0.1350474, 0.8904793, 0.2714479, -0.0710304, 0.0135403}, + {0.0135403, -0.0710304, 0.2714479, 0.8904793, -0.1350474, 0.0345613, -0.0029937}}; +#else +const float shift_filt[3][7] = {{-0.011915f, 0.046995f, -0.152373f, 0.614108f, 0.614108f, -0.152373f, 0.046995f}, + {-0.0324855f, 0.0859768f, -0.2042986f, 0.9640297f, 0.2086420f, -0.0302054f, -0.0063646f}, + {-0.0063646f, -0.0302054f, 0.2086420f, 0.9640297f, -0.2042986f, 0.0859768f, -0.0324855f}}; +#endif +#endif + +int interp_pitch( +spx_word16_t *exc, /*decoded excitation*/ +spx_word16_t *interp, /*decoded excitation*/ +int pitch, /*pitch period*/ +int len +) +{ + int i,j,k; + spx_word32_t corr[4][7]; + spx_word32_t maxcorr; + int maxi, maxj; + for (i=0;i<7;i++) + { + corr[0][i] = inner_prod(exc, exc-pitch-3+i, len); + } + for (i=0;i<3;i++) + { + for (j=0;j<7;j++) + { + int i1, i2; + spx_word32_t tmp=0; + i1 = 3-j; + if (i1<0) + i1 = 0; + i2 = 10-j; + if (i2>7) + i2 = 7; + for (k=i1;k maxcorr) + { + maxcorr = corr[i][j]; + maxi=i; + maxj=j; + } + } + } + for (i=0;i0) + { + for (k=0;k<7;k++) + { + tmp += MULT16_16(exc[i-(pitch-maxj+3)+k-3],shift_filt[maxi-1][k]); + } + } else { + tmp = SHL32(exc[i-(pitch-maxj+3)],15); + } + interp[i] = PSHR32(tmp,15); + } + return pitch-maxj+3; +} + +void multicomb( +spx_word16_t *exc, /*decoded excitation*/ +spx_word16_t *new_exc, /*enhanced excitation*/ +spx_coef_t *ak, /*LPC filter coefs*/ +int p, /*LPC order*/ +int nsf, /*sub-frame size*/ +int pitch, /*pitch period*/ +int max_pitch, +spx_word16_t comb_gain, /*gain of comb filter*/ +char *stack +) +{ + int i; + VARDECL(spx_word16_t *iexc); + spx_word16_t old_ener, new_ener; + int corr_pitch; + + spx_word16_t iexc0_mag, iexc1_mag, exc_mag; + spx_word32_t corr0, corr1; + spx_word16_t gain0, gain1; + spx_word16_t pgain1, pgain2; + spx_word16_t c1, c2; + spx_word16_t g1, g2; + spx_word16_t ngain; + spx_word16_t gg1, gg2; +#ifdef FIXED_POINT + int scaledown=0; +#endif +#if 0 /* Set to 1 to enable full pitch search */ + int nol_pitch[6]; + spx_word16_t nol_pitch_coef[6]; + spx_word16_t ol_pitch_coef; + open_loop_nbest_pitch(exc, 20, 120, nsf, + nol_pitch, nol_pitch_coef, 6, stack); + corr_pitch=nol_pitch[0]; + ol_pitch_coef = nol_pitch_coef[0]; + /*Try to remove pitch multiples*/ + for (i=1;i<6;i++) + { +#ifdef FIXED_POINT + if ((nol_pitch_coef[i]>MULT16_16_Q15(nol_pitch_coef[0],19661)) && +#else + if ((nol_pitch_coef[i]>.6*nol_pitch_coef[0]) && +#endif + (ABS(2*nol_pitch[i]-corr_pitch)<=2 || ABS(3*nol_pitch[i]-corr_pitch)<=3 || + ABS(4*nol_pitch[i]-corr_pitch)<=4 || ABS(5*nol_pitch[i]-corr_pitch)<=5)) + { + corr_pitch = nol_pitch[i]; + } + } +#else + corr_pitch = pitch; +#endif + + ALLOC(iexc, 2*nsf, spx_word16_t); + + interp_pitch(exc, iexc, corr_pitch, 80); + if (corr_pitch>max_pitch) + interp_pitch(exc, iexc+nsf, 2*corr_pitch, 80); + else + interp_pitch(exc, iexc+nsf, -corr_pitch, 80); + +#ifdef FIXED_POINT + for (i=0;i16383) + { + scaledown = 1; + break; + } + } + if (scaledown) + { + for (i=0;i MULT16_16(iexc0_mag,exc_mag)) + pgain1 = QCONST16(1., 14); + else + pgain1 = PDIV32_16(SHL32(PDIV32(corr0, exc_mag),14),iexc0_mag); + if (corr1 > MULT16_16(iexc1_mag,exc_mag)) + pgain2 = QCONST16(1., 14); + else + pgain2 = PDIV32_16(SHL32(PDIV32(corr1, exc_mag),14),iexc1_mag); + gg1 = PDIV32_16(SHL32(EXTEND32(exc_mag),8), iexc0_mag); + gg2 = PDIV32_16(SHL32(EXTEND32(exc_mag),8), iexc1_mag); + if (comb_gain>0) + { +#ifdef FIXED_POINT + c1 = (MULT16_16_Q15(QCONST16(.4,15),comb_gain)+QCONST16(.07,15)); + c2 = QCONST16(.5,15)+MULT16_16_Q14(QCONST16(1.72,14),(c1-QCONST16(.07,15))); +#else + c1 = .4*comb_gain+.07; + c2 = .5+1.72*(c1-.07); +#endif + } else + { + c1=c2=0; + } +#ifdef FIXED_POINT + g1 = 32767 - MULT16_16_Q13(MULT16_16_Q15(c2, pgain1),pgain1); + g2 = 32767 - MULT16_16_Q13(MULT16_16_Q15(c2, pgain2),pgain2); +#else + g1 = 1-c2*pgain1*pgain1; + g2 = 1-c2*pgain2*pgain2; +#endif + if (g1max_pitch) + { + gain0 = MULT16_16_Q15(QCONST16(.7,15),MULT16_16_Q14(g1,gg1)); + gain1 = MULT16_16_Q15(QCONST16(.3,15),MULT16_16_Q14(g2,gg2)); + } else { + gain0 = MULT16_16_Q15(QCONST16(.6,15),MULT16_16_Q14(g1,gg1)); + gain1 = MULT16_16_Q15(QCONST16(.6,15),MULT16_16_Q14(g2,gg2)); + } + for (i=0;i new_ener) + old_ener = new_ener; + ngain = PDIV32_16(SHL32(EXTEND32(old_ener),14),new_ener); + + for (i=0;imax_scale) + { + sig_shift++; + max_val >>= 1; + } + + __asm__ __volatile__ ( + ".normalize16loop%=: \n" + + "\tldr %4, [%0], #4 \n" + "\tldr %5, [%0], #4 \n" + "\tmov %4, %4, asr %3 \n" + "\tstrh %4, [%1], #2 \n" + "\tldr %4, [%0], #4 \n" + "\tmov %5, %5, asr %3 \n" + "\tstrh %5, [%1], #2 \n" + "\tldr %5, [%0], #4 \n" + "\tmov %4, %4, asr %3 \n" + "\tstrh %4, [%1], #2 \n" + "\tsubs %2, %2, #1 \n" + "\tmov %5, %5, asr %3 \n" + "\tstrh %5, [%1], #2 \n" + + "\tbgt .normalize16loop%=\n" + : "=r" (dead1), "=r" (dead2), "=r" (dead3), "=r" (dead4), + "=r" (dead5), "=r" (dead6) + : "0" (x), "1" (y), "2" (len>>2), "3" (sig_shift) + : "cc", "memory"); + return sig_shift; +} + diff --git a/ios/IOSDuoduo/Voice/Code/Libs/libspeex/filters_bfin.h b/ios/IOSDuoduo/Voice/Code/Libs/libspeex/filters_bfin.h new file mode 100755 index 000000000..1e433ee16 --- /dev/null +++ b/ios/IOSDuoduo/Voice/Code/Libs/libspeex/filters_bfin.h @@ -0,0 +1,515 @@ +/* Copyright (C) 2005 Analog Devices */ +/** + @file filters_bfin.h + @brief Various analysis/synthesis filters (Blackfin version) +*/ +/* + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + - Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + - Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + - Neither the name of the Xiph.org Foundation nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR + CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#define OVERRIDE_NORMALIZE16 +int normalize16(const spx_sig_t *x, spx_word16_t *y, spx_sig_t max_scale, int len) +{ + spx_sig_t max_val=1; + int sig_shift; + __asm__ + ( + "%0 = 0;\n\t" + "I0 = %1;\n\t" + "L0 = 0;\n\t" + "R1 = [I0++];\n\t" + "LOOP norm_max%= LC0 = %2;\n\t" + "LOOP_BEGIN norm_max%=;\n\t" + "R2 = ABS R1 || R1 = [I0++];\n\t" + "%0 = MAX(%0, R2);\n\t" + "LOOP_END norm_max%=;\n\t" + : "=&d" (max_val) + : "a" (x), "a" (len) + : "R1", "R2" + ); + + sig_shift=0; + while (max_val>max_scale) + { + sig_shift++; + max_val >>= 1; + } + + __asm__ __volatile__ + ( + "I0 = %0;\n\t" + "L0 = 0;\n\t" + "P1 = %1;\n\t" + "R0 = [I0++];\n\t" + "LOOP norm_shift%= LC0 = %3;\n\t" + "LOOP_BEGIN norm_shift%=;\n\t" + "R1 = ASHIFT R0 by %2.L || R0 = [I0++];\n\t" + "W[P1++] = R1;\n\t" + "LOOP_END norm_shift%=;\n\t" + "R1 = ASHIFT R0 by %2.L;\n\t" + "W[P1++] = R1;\n\t" + : : "a" (x), "a" (y), "d" (-sig_shift), "a" (len-1) + : "I0", "L0", "P1", "R0", "R1", "memory" + ); + return sig_shift; +} + + + +#define OVERRIDE_FILTER_MEM16 +void filter_mem16(const spx_word16_t *_x, const spx_coef_t *num, const spx_coef_t *den, spx_word16_t *_y, int N, int ord, spx_mem_t *mem, char *stack) +{ + VARDECL(spx_word32_t *xy2); + VARDECL(spx_word32_t *numden_a); + spx_word32_t *xy; + spx_word16_t *numden; + int i; + + ALLOC(xy2, (N+1), spx_word32_t); + ALLOC(numden_a, (2*ord+2), spx_word32_t); + xy = xy2+1; + numden = (spx_word16_t*) numden_a; + + for (i=0;i>> 13;\n\t" + "W[%0] = R3.L;\n\t" + "R0 <<= 1;\n\t" + "R1 = R1 + R0;\n\t" + "R1 >>>= 13;\n\t" + "W[%1] = R1.L;\n\t" + "LOOP_END samples%=;\n\t" + : "=a" (ytmp2), "=a" (y) + : "a" (awk2), "a" (ak), "d" (ord), "m" (N), "0" (ytmp2), "1" (y) + : "A0", "A1", "R0", "R1", "R2", "R3", "I0", "I1", "I2", "I3", "L0", "L1", "L2", "L3", "A0", "A1" + ); +} + + + +#if 0 /* Equivalent C function for filter_mem2 and compute_impulse_response */ +#define min(a,b) ((a)<(b) ? (a):(b)) + +void compute_impulse_response(const spx_coef_t *ak, const spx_coef_t *awk1, const spx_coef_t *awk2, spx_word16_t *y, int N, int ord, char *stack) +{ + int i,j; + VARDECL(spx_word16_t *ytmp); + ALLOC(ytmp, N, spx_word16_t); + + y[0] = LPC_SCALING; + for (i=0;i + +void filter_mem16_10(const float *x, const float *_num, const float *_den, float *y, int N, int ord, float *_mem) +{ + __m128 num[3], den[3], mem[3]; + + int i; + + /* Copy numerator, denominator and memory to aligned xmm */ + for (i=0;i<2;i++) + { + mem[i] = _mm_loadu_ps(_mem+4*i); + num[i] = _mm_loadu_ps(_num+4*i); + den[i] = _mm_loadu_ps(_den+4*i); + } + mem[2] = _mm_setr_ps(_mem[8], _mem[9], 0, 0); + num[2] = _mm_setr_ps(_num[8], _num[9], 0, 0); + den[2] = _mm_setr_ps(_den[8], _den[9], 0, 0); + + for (i=0;i>1; + __asm__ ( + "P0 = 15;\n\t" + "R0 = %1;\n\t" + "R1 = %2;\n\t" + //"R0 = R0 + R1;\n\t" + "R0 <<= 1;\n\t" + "DIVS (R0, R1);\n\t" + "LOOP divide%= LC0 = P0;\n\t" + "LOOP_BEGIN divide%=;\n\t" + "DIVQ (R0, R1);\n\t" + "LOOP_END divide%=;\n\t" + "R0 = R0.L;\n\t" + "%0 = R0;\n\t" + : "=m" (res) + : "m" (a), "m" (bb) + : "P0", "R0", "R1", "cc"); + return res; +} + +#undef DIV32_16 +static inline spx_word16_t DIV32_16(spx_word32_t a, spx_word16_t b) +{ + spx_word32_t res, bb; + bb = b; + /* Make the roundinf consistent with the C version + (do we need to do that?)*/ + if (a<0) + a += (b-1); + __asm__ ( + "P0 = 15;\n\t" + "R0 = %1;\n\t" + "R1 = %2;\n\t" + "R0 <<= 1;\n\t" + "DIVS (R0, R1);\n\t" + "LOOP divide%= LC0 = P0;\n\t" + "LOOP_BEGIN divide%=;\n\t" + "DIVQ (R0, R1);\n\t" + "LOOP_END divide%=;\n\t" + "R0 = R0.L;\n\t" + "%0 = R0;\n\t" + : "=m" (res) + : "m" (a), "m" (bb) + : "P0", "R0", "R1", "cc"); + return res; +} + +#undef MAX16 +static inline spx_word16_t MAX16(spx_word16_t a, spx_word16_t b) +{ + spx_word32_t res; + __asm__ ( + "%1 = %1.L (X);\n\t" + "%2 = %2.L (X);\n\t" + "%0 = MAX(%1,%2);" + : "=d" (res) + : "%d" (a), "d" (b) + ); + return res; +} + +#undef MULT16_32_Q15 +static inline spx_word32_t MULT16_32_Q15(spx_word16_t a, spx_word32_t b) +{ + spx_word32_t res; + __asm__ + ( + "A1 = %2.L*%1.L (M);\n\t" + "A1 = A1 >>> 15;\n\t" + "%0 = (A1 += %2.L*%1.H) ;\n\t" + : "=&W" (res), "=&d" (b) + : "d" (a), "1" (b) + : "A1" + ); + return res; +} + +#undef MAC16_32_Q15 +static inline spx_word32_t MAC16_32_Q15(spx_word32_t c, spx_word16_t a, spx_word32_t b) +{ + spx_word32_t res; + __asm__ + ( + "A1 = %2.L*%1.L (M);\n\t" + "A1 = A1 >>> 15;\n\t" + "%0 = (A1 += %2.L*%1.H);\n\t" + "%0 = %0 + %4;\n\t" + : "=&W" (res), "=&d" (b) + : "d" (a), "1" (b), "d" (c) + : "A1" + ); + return res; +} + +#undef MULT16_32_Q14 +static inline spx_word32_t MULT16_32_Q14(spx_word16_t a, spx_word32_t b) +{ + spx_word32_t res; + __asm__ + ( + "%2 <<= 1;\n\t" + "A1 = %1.L*%2.L (M);\n\t" + "A1 = A1 >>> 15;\n\t" + "%0 = (A1 += %1.L*%2.H);\n\t" + : "=W" (res), "=d" (a), "=d" (b) + : "1" (a), "2" (b) + : "A1" + ); + return res; +} + +#undef MAC16_32_Q14 +static inline spx_word32_t MAC16_32_Q14(spx_word32_t c, spx_word16_t a, spx_word32_t b) +{ + spx_word32_t res; + __asm__ + ( + "%1 <<= 1;\n\t" + "A1 = %2.L*%1.L (M);\n\t" + "A1 = A1 >>> 15;\n\t" + "%0 = (A1 += %2.L*%1.H);\n\t" + "%0 = %0 + %4;\n\t" + : "=&W" (res), "=&d" (b) + : "d" (a), "1" (b), "d" (c) + : "A1" + ); + return res; +} + +#endif diff --git a/ios/IOSDuoduo/Voice/Code/Libs/libspeex/fixed_debug.h b/ios/IOSDuoduo/Voice/Code/Libs/libspeex/fixed_debug.h new file mode 100755 index 000000000..54f3866e8 --- /dev/null +++ b/ios/IOSDuoduo/Voice/Code/Libs/libspeex/fixed_debug.h @@ -0,0 +1,487 @@ +/* Copyright (C) 2003 Jean-Marc Valin */ +/** + @file fixed_debug.h + @brief Fixed-point operations with debugging +*/ +/* + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + - Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + - Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + - Neither the name of the Xiph.org Foundation nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR + CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#ifndef FIXED_DEBUG_H +#define FIXED_DEBUG_H + +#include + +extern long long spx_mips; +#define MIPS_INC spx_mips++, + +#define QCONST16(x,bits) ((spx_word16_t)(.5+(x)*(((spx_word32_t)1)<<(bits)))) +#define QCONST32(x,bits) ((spx_word32_t)(.5+(x)*(((spx_word32_t)1)<<(bits)))) + + +#define VERIFY_SHORT(x) ((x)<=32767&&(x)>=-32768) +#define VERIFY_INT(x) ((x)<=2147483647LL&&(x)>=-2147483648LL) + +static inline short NEG16(int x) +{ + int res; + if (!VERIFY_SHORT(x)) + { + fprintf (stderr, "NEG16: input is not short: %d\n", (int)x); + } + res = -x; + if (!VERIFY_SHORT(res)) + fprintf (stderr, "NEG16: output is not short: %d\n", (int)res); + spx_mips++; + return res; +} +static inline int NEG32(long long x) +{ + long long res; + if (!VERIFY_INT(x)) + { + fprintf (stderr, "NEG16: input is not int: %d\n", (int)x); + } + res = -x; + if (!VERIFY_INT(res)) + fprintf (stderr, "NEG16: output is not int: %d\n", (int)res); + spx_mips++; + return res; +} + +#define EXTRACT16(x) _EXTRACT16(x, __FILE__, __LINE__) +static inline short _EXTRACT16(int x, char *file, int line) +{ + int res; + if (!VERIFY_SHORT(x)) + { + fprintf (stderr, "EXTRACT16: input is not short: %d in %s: line %d\n", x, file, line); + } + res = x; + spx_mips++; + return res; +} + +#define EXTEND32(x) _EXTEND32(x, __FILE__, __LINE__) +static inline int _EXTEND32(int x, char *file, int line) +{ + int res; + if (!VERIFY_SHORT(x)) + { + fprintf (stderr, "EXTEND32: input is not short: %d in %s: line %d\n", x, file, line); + } + res = x; + spx_mips++; + return res; +} + +#define SHR16(a, shift) _SHR16(a, shift, __FILE__, __LINE__) +static inline short _SHR16(int a, int shift, char *file, int line) +{ + int res; + if (!VERIFY_SHORT(a) || !VERIFY_SHORT(shift)) + { + fprintf (stderr, "SHR16: inputs are not short: %d >> %d in %s: line %d\n", a, shift, file, line); + } + res = a>>shift; + if (!VERIFY_SHORT(res)) + fprintf (stderr, "SHR16: output is not short: %d in %s: line %d\n", res, file, line); + spx_mips++; + return res; +} +#define SHL16(a, shift) _SHL16(a, shift, __FILE__, __LINE__) +static inline short _SHL16(int a, int shift, char *file, int line) +{ + int res; + if (!VERIFY_SHORT(a) || !VERIFY_SHORT(shift)) + { + fprintf (stderr, "SHL16: inputs are not short: %d %d in %s: line %d\n", a, shift, file, line); + } + res = a<>shift; + if (!VERIFY_INT(res)) + { + fprintf (stderr, "SHR32: output is not int: %d\n", (int)res); + } + spx_mips++; + return res; +} +static inline int SHL32(long long a, int shift) +{ + long long res; + if (!VERIFY_INT(a) || !VERIFY_SHORT(shift)) + { + fprintf (stderr, "SHL32: inputs are not int: %d %d\n", (int)a, shift); + } + res = a<>1))),shift)) +#define PSHR32(a,shift) (SHR32(ADD32((a),((EXTEND32(1)<<((shift))>>1))),shift)) +#define VSHR32(a, shift) (((shift)>0) ? SHR32(a, shift) : SHL32(a, -(shift))) + +#define SATURATE16(x,a) (((x)>(a) ? (a) : (x)<-(a) ? -(a) : (x))) +#define SATURATE32(x,a) (((x)>(a) ? (a) : (x)<-(a) ? -(a) : (x))) + +//#define SHR(a,shift) ((a) >> (shift)) +//#define SHL(a,shift) ((a) << (shift)) + +#define ADD16(a, b) _ADD16(a, b, __FILE__, __LINE__) +static inline short _ADD16(int a, int b, char *file, int line) +{ + int res; + if (!VERIFY_SHORT(a) || !VERIFY_SHORT(b)) + { + fprintf (stderr, "ADD16: inputs are not short: %d %d in %s: line %d\n", a, b, file, line); + } + res = a+b; + if (!VERIFY_SHORT(res)) + { + fprintf (stderr, "ADD16: output is not short: %d+%d=%d in %s: line %d\n", a,b,res, file, line); + } + spx_mips++; + return res; +} + +#define SUB16(a, b) _SUB16(a, b, __FILE__, __LINE__) +static inline short _SUB16(int a, int b, char *file, int line) +{ + int res; + if (!VERIFY_SHORT(a) || !VERIFY_SHORT(b)) + { + fprintf (stderr, "SUB16: inputs are not short: %d %d in %s: line %d\n", a, b, file, line); + } + res = a-b; + if (!VERIFY_SHORT(res)) + fprintf (stderr, "SUB16: output is not short: %d in %s: line %d\n", res, file, line); + spx_mips++; + return res; +} + +#define ADD32(a, b) _ADD32(a, b, __FILE__, __LINE__) +static inline int _ADD32(long long a, long long b, char *file, int line) +{ + long long res; + if (!VERIFY_INT(a) || !VERIFY_INT(b)) + { + fprintf (stderr, "ADD32: inputs are not int: %d %d in %s: line %d\n", (int)a, (int)b, file, line); + } + res = a+b; + if (!VERIFY_INT(res)) + { + fprintf (stderr, "ADD32: output is not int: %d in %s: line %d\n", (int)res, file, line); + } + spx_mips++; + return res; +} + +static inline int SUB32(long long a, long long b) +{ + long long res; + if (!VERIFY_INT(a) || !VERIFY_INT(b)) + { + fprintf (stderr, "SUB32: inputs are not int: %d %d\n", (int)a, (int)b); + } + res = a-b; + if (!VERIFY_INT(res)) + fprintf (stderr, "SUB32: output is not int: %d\n", (int)res); + spx_mips++; + return res; +} + +#define ADD64(a,b) (MIPS_INC(a)+(b)) + +/* result fits in 16 bits */ +static inline short MULT16_16_16(int a, int b) +{ + int res; + if (!VERIFY_SHORT(a) || !VERIFY_SHORT(b)) + { + fprintf (stderr, "MULT16_16_16: inputs are not short: %d %d\n", a, b); + } + res = a*b; + if (!VERIFY_SHORT(res)) + fprintf (stderr, "MULT16_16_16: output is not short: %d\n", res); + spx_mips++; + return res; +} + +#define MULT16_16(a, b) _MULT16_16(a, b, __FILE__, __LINE__) +static inline int _MULT16_16(int a, int b, char *file, int line) +{ + long long res; + if (!VERIFY_SHORT(a) || !VERIFY_SHORT(b)) + { + fprintf (stderr, "MULT16_16: inputs are not short: %d %d in %s: line %d\n", a, b, file, line); + } + res = ((long long)a)*b; + if (!VERIFY_INT(res)) + fprintf (stderr, "MULT16_16: output is not int: %d in %s: line %d\n", (int)res, file, line); + spx_mips++; + return res; +} + +#define MAC16_16(c,a,b) (spx_mips--,ADD32((c),MULT16_16((a),(b)))) +#define MAC16_16_Q11(c,a,b) (EXTRACT16(ADD16((c),EXTRACT16(SHR32(MULT16_16((a),(b)),11))))) +#define MAC16_16_Q13(c,a,b) (EXTRACT16(ADD16((c),EXTRACT16(SHR32(MULT16_16((a),(b)),13))))) +#define MAC16_16_P13(c,a,b) (EXTRACT16(ADD32((c),SHR32(ADD32(4096,MULT16_16((a),(b))),13)))) + + +#define MULT16_32_QX(a, b, Q) _MULT16_32_QX(a, b, Q, __FILE__, __LINE__) +static inline int _MULT16_32_QX(int a, long long b, int Q, char *file, int line) +{ + long long res; + if (!VERIFY_SHORT(a) || !VERIFY_INT(b)) + { + fprintf (stderr, "MULT16_32_Q%d: inputs are not short+int: %d %d in %s: line %d\n", Q, (int)a, (int)b, file, line); + } + if (ABS32(b)>=(EXTEND32(1)<<(15+Q))) + fprintf (stderr, "MULT16_32_Q%d: second operand too large: %d %d in %s: line %d\n", Q, (int)a, (int)b, file, line); + res = (((long long)a)*(long long)b) >> Q; + if (!VERIFY_INT(res)) + fprintf (stderr, "MULT16_32_Q%d: output is not int: %d*%d=%d in %s: line %d\n", Q, (int)a, (int)b,(int)res, file, line); + spx_mips+=5; + return res; +} + +static inline int MULT16_32_PX(int a, long long b, int Q) +{ + long long res; + if (!VERIFY_SHORT(a) || !VERIFY_INT(b)) + { + fprintf (stderr, "MULT16_32_P%d: inputs are not short+int: %d %d\n", Q, (int)a, (int)b); + } + if (ABS32(b)>=(EXTEND32(1)<<(15+Q))) + fprintf (stderr, "MULT16_32_Q%d: second operand too large: %d %d\n", Q, (int)a, (int)b); + res = ((((long long)a)*(long long)b) + ((EXTEND32(1)<>1))>> Q; + if (!VERIFY_INT(res)) + fprintf (stderr, "MULT16_32_P%d: output is not int: %d*%d=%d\n", Q, (int)a, (int)b,(int)res); + spx_mips+=5; + return res; +} + + +#define MULT16_32_Q11(a,b) MULT16_32_QX(a,b,11) +#define MAC16_32_Q11(c,a,b) ADD32((c),MULT16_32_Q11((a),(b))) +#define MULT16_32_Q12(a,b) MULT16_32_QX(a,b,12) +#define MULT16_32_Q13(a,b) MULT16_32_QX(a,b,13) +#define MULT16_32_Q14(a,b) MULT16_32_QX(a,b,14) +#define MULT16_32_Q15(a,b) MULT16_32_QX(a,b,15) +#define MULT16_32_P15(a,b) MULT16_32_PX(a,b,15) +#define MAC16_32_Q15(c,a,b) ADD32((c),MULT16_32_Q15((a),(b))) + +static inline int SATURATE(int a, int b) +{ + if (a>b) + a=b; + if (a<-b) + a = -b; + return a; +} + +static inline int MULT16_16_Q11_32(int a, int b) +{ + long long res; + if (!VERIFY_SHORT(a) || !VERIFY_SHORT(b)) + { + fprintf (stderr, "MULT16_16_Q11: inputs are not short: %d %d\n", a, b); + } + res = ((long long)a)*b; + res >>= 11; + if (!VERIFY_INT(res)) + fprintf (stderr, "MULT16_16_Q11: output is not short: %d*%d=%d\n", (int)a, (int)b, (int)res); + spx_mips+=3; + return res; +} +static inline short MULT16_16_Q13(int a, int b) +{ + long long res; + if (!VERIFY_SHORT(a) || !VERIFY_SHORT(b)) + { + fprintf (stderr, "MULT16_16_Q13: inputs are not short: %d %d\n", a, b); + } + res = ((long long)a)*b; + res >>= 13; + if (!VERIFY_SHORT(res)) + fprintf (stderr, "MULT16_16_Q13: output is not short: %d*%d=%d\n", a, b, (int)res); + spx_mips+=3; + return res; +} +static inline short MULT16_16_Q14(int a, int b) +{ + long long res; + if (!VERIFY_SHORT(a) || !VERIFY_SHORT(b)) + { + fprintf (stderr, "MULT16_16_Q14: inputs are not short: %d %d\n", a, b); + } + res = ((long long)a)*b; + res >>= 14; + if (!VERIFY_SHORT(res)) + fprintf (stderr, "MULT16_16_Q14: output is not short: %d\n", (int)res); + spx_mips+=3; + return res; +} +static inline short MULT16_16_Q15(int a, int b) +{ + long long res; + if (!VERIFY_SHORT(a) || !VERIFY_SHORT(b)) + { + fprintf (stderr, "MULT16_16_Q15: inputs are not short: %d %d\n", a, b); + } + res = ((long long)a)*b; + res >>= 15; + if (!VERIFY_SHORT(res)) + { + fprintf (stderr, "MULT16_16_Q15: output is not short: %d\n", (int)res); + } + spx_mips+=3; + return res; +} + +static inline short MULT16_16_P13(int a, int b) +{ + long long res; + if (!VERIFY_SHORT(a) || !VERIFY_SHORT(b)) + { + fprintf (stderr, "MULT16_16_P13: inputs are not short: %d %d\n", a, b); + } + res = ((long long)a)*b; + res += 4096; + if (!VERIFY_INT(res)) + fprintf (stderr, "MULT16_16_P13: overflow: %d*%d=%d\n", a, b, (int)res); + res >>= 13; + if (!VERIFY_SHORT(res)) + fprintf (stderr, "MULT16_16_P13: output is not short: %d*%d=%d\n", a, b, (int)res); + spx_mips+=4; + return res; +} +static inline short MULT16_16_P14(int a, int b) +{ + long long res; + if (!VERIFY_SHORT(a) || !VERIFY_SHORT(b)) + { + fprintf (stderr, "MULT16_16_P14: inputs are not short: %d %d\n", a, b); + } + res = ((long long)a)*b; + res += 8192; + if (!VERIFY_INT(res)) + fprintf (stderr, "MULT16_16_P14: overflow: %d*%d=%d\n", a, b, (int)res); + res >>= 14; + if (!VERIFY_SHORT(res)) + fprintf (stderr, "MULT16_16_P14: output is not short: %d*%d=%d\n", a, b, (int)res); + spx_mips+=4; + return res; +} +static inline short MULT16_16_P15(int a, int b) +{ + long long res; + if (!VERIFY_SHORT(a) || !VERIFY_SHORT(b)) + { + fprintf (stderr, "MULT16_16_P15: inputs are not short: %d %d\n", a, b); + } + res = ((long long)a)*b; + res += 16384; + if (!VERIFY_INT(res)) + fprintf (stderr, "MULT16_16_P15: overflow: %d*%d=%d\n", a, b, (int)res); + res >>= 15; + if (!VERIFY_SHORT(res)) + fprintf (stderr, "MULT16_16_P15: output is not short: %d*%d=%d\n", a, b, (int)res); + spx_mips+=4; + return res; +} + +#define DIV32_16(a, b) _DIV32_16(a, b, __FILE__, __LINE__) + +static inline int _DIV32_16(long long a, long long b, char *file, int line) +{ + long long res; + if (b==0) + { + fprintf(stderr, "DIV32_16: divide by zero: %d/%d in %s: line %d\n", (int)a, (int)b, file, line); + return 0; + } + if (!VERIFY_INT(a) || !VERIFY_SHORT(b)) + { + fprintf (stderr, "DIV32_16: inputs are not int/short: %d %d in %s: line %d\n", (int)a, (int)b, file, line); + } + res = a/b; + if (!VERIFY_SHORT(res)) + { + fprintf (stderr, "DIV32_16: output is not short: %d / %d = %d in %s: line %d\n", (int)a,(int)b,(int)res, file, line); + if (res>32767) + res = 32767; + if (res<-32768) + res = -32768; + } + spx_mips+=20; + return res; +} + +#define DIV32(a, b) _DIV32(a, b, __FILE__, __LINE__) +static inline int _DIV32(long long a, long long b, char *file, int line) +{ + long long res; + if (b==0) + { + fprintf(stderr, "DIV32: divide by zero: %d/%d in %s: line %d\n", (int)a, (int)b, file, line); + return 0; + } + + if (!VERIFY_INT(a) || !VERIFY_INT(b)) + { + fprintf (stderr, "DIV32: inputs are not int/short: %d %d in %s: line %d\n", (int)a, (int)b, file, line); + } + res = a/b; + if (!VERIFY_INT(res)) + fprintf (stderr, "DIV32: output is not int: %d in %s: line %d\n", (int)res, file, line); + spx_mips+=36; + return res; +} +#define PDIV32(a,b) DIV32(ADD32((a),(b)>>1),b) +#define PDIV32_16(a,b) DIV32_16(ADD32((a),(b)>>1),b) + +#endif diff --git a/ios/IOSDuoduo/Voice/Code/Libs/libspeex/fixed_generic.h b/ios/IOSDuoduo/Voice/Code/Libs/libspeex/fixed_generic.h new file mode 100755 index 000000000..3fb096ed9 --- /dev/null +++ b/ios/IOSDuoduo/Voice/Code/Libs/libspeex/fixed_generic.h @@ -0,0 +1,106 @@ +/* Copyright (C) 2003 Jean-Marc Valin */ +/** + @file fixed_generic.h + @brief Generic fixed-point operations +*/ +/* + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + - Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + - Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + - Neither the name of the Xiph.org Foundation nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR + CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#ifndef FIXED_GENERIC_H +#define FIXED_GENERIC_H + +#define QCONST16(x,bits) ((spx_word16_t)(.5+(x)*(((spx_word32_t)1)<<(bits)))) +#define QCONST32(x,bits) ((spx_word32_t)(.5+(x)*(((spx_word32_t)1)<<(bits)))) + +#define NEG16(x) (-(x)) +#define NEG32(x) (-(x)) +#define EXTRACT16(x) ((spx_word16_t)(x)) +#define EXTEND32(x) ((spx_word32_t)(x)) +#define SHR16(a,shift) ((a) >> (shift)) +#define SHL16(a,shift) ((a) << (shift)) +#define SHR32(a,shift) ((a) >> (shift)) +#define SHL32(a,shift) ((a) << (shift)) +#define PSHR16(a,shift) (SHR16((a)+((1<<((shift))>>1)),shift)) +#define PSHR32(a,shift) (SHR32((a)+((EXTEND32(1)<<((shift))>>1)),shift)) +#define VSHR32(a, shift) (((shift)>0) ? SHR32(a, shift) : SHL32(a, -(shift))) +#define SATURATE16(x,a) (((x)>(a) ? (a) : (x)<-(a) ? -(a) : (x))) +#define SATURATE32(x,a) (((x)>(a) ? (a) : (x)<-(a) ? -(a) : (x))) + +#define SHR(a,shift) ((a) >> (shift)) +#define SHL(a,shift) ((spx_word32_t)(a) << (shift)) +#define PSHR(a,shift) (SHR((a)+((EXTEND32(1)<<((shift))>>1)),shift)) +#define SATURATE(x,a) (((x)>(a) ? (a) : (x)<-(a) ? -(a) : (x))) + + +#define ADD16(a,b) ((spx_word16_t)((spx_word16_t)(a)+(spx_word16_t)(b))) +#define SUB16(a,b) ((spx_word16_t)(a)-(spx_word16_t)(b)) +#define ADD32(a,b) ((spx_word32_t)(a)+(spx_word32_t)(b)) +#define SUB32(a,b) ((spx_word32_t)(a)-(spx_word32_t)(b)) + + +/* result fits in 16 bits */ +#define MULT16_16_16(a,b) ((((spx_word16_t)(a))*((spx_word16_t)(b)))) + +/* (spx_word32_t)(spx_word16_t) gives TI compiler a hint that it's 16x16->32 multiply */ +#define MULT16_16(a,b) (((spx_word32_t)(spx_word16_t)(a))*((spx_word32_t)(spx_word16_t)(b))) + +#define MAC16_16(c,a,b) (ADD32((c),MULT16_16((a),(b)))) +#define MULT16_32_Q12(a,b) ADD32(MULT16_16((a),SHR((b),12)), SHR(MULT16_16((a),((b)&0x00000fff)),12)) +#define MULT16_32_Q13(a,b) ADD32(MULT16_16((a),SHR((b),13)), SHR(MULT16_16((a),((b)&0x00001fff)),13)) +#define MULT16_32_Q14(a,b) ADD32(MULT16_16((a),SHR((b),14)), SHR(MULT16_16((a),((b)&0x00003fff)),14)) + +#define MULT16_32_Q11(a,b) ADD32(MULT16_16((a),SHR((b),11)), SHR(MULT16_16((a),((b)&0x000007ff)),11)) +#define MAC16_32_Q11(c,a,b) ADD32(c,ADD32(MULT16_16((a),SHR((b),11)), SHR(MULT16_16((a),((b)&0x000007ff)),11))) + +#define MULT16_32_P15(a,b) ADD32(MULT16_16((a),SHR((b),15)), PSHR(MULT16_16((a),((b)&0x00007fff)),15)) +#define MULT16_32_Q15(a,b) ADD32(MULT16_16((a),SHR((b),15)), SHR(MULT16_16((a),((b)&0x00007fff)),15)) +#define MAC16_32_Q15(c,a,b) ADD32(c,ADD32(MULT16_16((a),SHR((b),15)), SHR(MULT16_16((a),((b)&0x00007fff)),15))) + + +#define MAC16_16_Q11(c,a,b) (ADD32((c),SHR(MULT16_16((a),(b)),11))) +#define MAC16_16_Q13(c,a,b) (ADD32((c),SHR(MULT16_16((a),(b)),13))) +#define MAC16_16_P13(c,a,b) (ADD32((c),SHR(ADD32(4096,MULT16_16((a),(b))),13))) + +#define MULT16_16_Q11_32(a,b) (SHR(MULT16_16((a),(b)),11)) +#define MULT16_16_Q13(a,b) (SHR(MULT16_16((a),(b)),13)) +#define MULT16_16_Q14(a,b) (SHR(MULT16_16((a),(b)),14)) +#define MULT16_16_Q15(a,b) (SHR(MULT16_16((a),(b)),15)) + +#define MULT16_16_P13(a,b) (SHR(ADD32(4096,MULT16_16((a),(b))),13)) +#define MULT16_16_P14(a,b) (SHR(ADD32(8192,MULT16_16((a),(b))),14)) +#define MULT16_16_P15(a,b) (SHR(ADD32(16384,MULT16_16((a),(b))),15)) + +#define MUL_16_32_R15(a,bh,bl) ADD32(MULT16_16((a),(bh)), SHR(MULT16_16((a),(bl)),15)) + +#define DIV32_16(a,b) ((spx_word16_t)(((spx_word32_t)(a))/((spx_word16_t)(b)))) +#define PDIV32_16(a,b) ((spx_word16_t)(((spx_word32_t)(a)+((spx_word16_t)(b)>>1))/((spx_word16_t)(b)))) +#define DIV32(a,b) (((spx_word32_t)(a))/((spx_word32_t)(b))) +#define PDIV32(a,b) (((spx_word32_t)(a)+((spx_word16_t)(b)>>1))/((spx_word32_t)(b))) + +#endif diff --git a/ios/IOSDuoduo/Voice/Code/Libs/libspeex/gain_table.c b/ios/IOSDuoduo/Voice/Code/Libs/libspeex/gain_table.c new file mode 100755 index 000000000..00b824425 --- /dev/null +++ b/ios/IOSDuoduo/Voice/Code/Libs/libspeex/gain_table.c @@ -0,0 +1,160 @@ +/* Copyright (C) 2002 Jean-Marc Valin + File: gain_table.c + Codebook for 3-tap pitch prediction gain (128 entries) + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are + met: + + 1. Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + 3. The name of the author may not be used to endorse or promote products + derived from this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, + INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + POSSIBILITY OF SUCH DAMAGE. +*/ + +const signed char gain_cdbk_nb[512] = { +-32, -32, -32, 0, +-28, -67, -5, 33, +-42, -6, -32, 18, +-57, -10, -54, 35, +-16, 27, -41, 42, +19, -19, -40, 36, +-45, 24, -21, 40, +-8, -14, -18, 28, +1, 14, -58, 53, +-18, -88, -39, 39, +-38, 21, -18, 37, +-19, 20, -43, 38, +10, 17, -48, 54, +-52, -58, -13, 33, +-44, -1, -11, 32, +-12, -11, -34, 22, +14, 0, -46, 46, +-37, -35, -34, 5, +-25, 44, -30, 43, +6, -4, -63, 49, +-31, 43, -41, 43, +-23, 30, -43, 41, +-43, 26, -14, 44, +-33, 1, -13, 27, +-13, 18, -37, 37, +-46, -73, -45, 34, +-36, 24, -25, 34, +-36, -11, -20, 19, +-25, 12, -18, 33, +-36, -69, -59, 34, +-45, 6, 8, 46, +-22, -14, -24, 18, +-1, 13, -44, 44, +-39, -48, -26, 15, +-32, 31, -37, 34, +-33, 15, -46, 31, +-24, 30, -36, 37, +-41, 31, -23, 41, +-50, 22, -4, 50, +-22, 2, -21, 28, +-17, 30, -34, 40, +-7, -60, -28, 29, +-38, 42, -28, 42, +-44, -11, 21, 43, +-16, 8, -44, 34, +-39, -55, -43, 21, +-11, -35, 26, 41, +-9, 0, -34, 29, +-8, 121, -81, 113, +7, -16, -22, 33, +-37, 33, -31, 36, +-27, -7, -36, 17, +-34, 70, -57, 65, +-37, -11, -48, 21, +-40, 17, -1, 44, +-33, 6, -6, 33, +-9, 0, -20, 34, +-21, 69, -33, 57, +-29, 33, -31, 35, +-55, 12, -1, 49, +-33, 27, -22, 35, +-50, -33, -47, 17, +-50, 54, 51, 94, +-1, -5, -44, 35, +-4, 22, -40, 45, +-39, -66, -25, 24, +-33, 1, -26, 20, +-24, -23, -25, 12, +-11, 21, -45, 44, +-25, -45, -19, 17, +-43, 105, -16, 82, +5, -21, 1, 41, +-16, 11, -33, 30, +-13, -99, -4, 57, +-37, 33, -15, 44, +-25, 37, -63, 54, +-36, 24, -31, 31, +-53, -56, -38, 26, +-41, -4, 4, 37, +-33, 13, -30, 24, +49, 52, -94, 114, +-5, -30, -15, 23, +1, 38, -40, 56, +-23, 12, -36, 29, +-17, 40, -47, 51, +-37, -41, -39, 11, +-49, 34, 0, 58, +-18, -7, -4, 34, +-16, 17, -27, 35, +30, 5, -62, 65, +4, 48, -68, 76, +-43, 11, -11, 38, +-18, 19, -15, 41, +-23, -62, -39, 23, +-42, 10, -2, 41, +-21, -13, -13, 25, +-9, 13, -47, 42, +-23, -62, -24, 24, +-44, 60, -21, 58, +-18, -3, -52, 32, +-22, 22, -36, 34, +-75, 57, 16, 90, +-19, 3, 10, 45, +-29, 23, -38, 32, +-5, -62, -51, 38, +-51, 40, -18, 53, +-42, 13, -24, 32, +-34, 14, -20, 30, +-56, -75, -26, 37, +-26, 32, 15, 59, +-26, 17, -29, 29, +-7, 28, -52, 53, +-12, -30, 5, 30, +-5, -48, -5, 35, +2, 2, -43, 40, +21, 16, 16, 75, +-25, -45, -32, 10, +-43, 18, -10, 42, +9, 0, -1, 52, +-1, 7, -30, 36, +19, -48, -4, 48, +-28, 25, -29, 32, +-22, 0, -31, 22, +-32, 17, -10, 36, +-64, -41, -62, 36, +-52, 15, 16, 58, +-30, -22, -32, 6, +-7, 9, -38, 36}; diff --git a/ios/IOSDuoduo/Voice/Code/Libs/libspeex/gain_table_lbr.c b/ios/IOSDuoduo/Voice/Code/Libs/libspeex/gain_table_lbr.c new file mode 100755 index 000000000..3c1c3dba9 --- /dev/null +++ b/ios/IOSDuoduo/Voice/Code/Libs/libspeex/gain_table_lbr.c @@ -0,0 +1,64 @@ +/* Copyright (C) 2002 Jean-Marc Valin + File: gain_table_lbr.c + Codebook for 3-tap pitch prediction gain (32 entries) + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are + met: + + 1. Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + 3. The name of the author may not be used to endorse or promote products + derived from this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, + INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + POSSIBILITY OF SUCH DAMAGE. +*/ + +const signed char gain_cdbk_lbr[128] = { +-32, -32, -32, 0, +-31, -58, -16, 22, +-41, -24, -43, 14, +-56, -22, -55, 29, +-13, 33, -41, 47, +-4, -39, -9, 29, +-41, 15, -12, 38, +-8, -15, -12, 31, +1, 2, -44, 40, +-22, -66, -42, 27, +-38, 28, -23, 38, +-21, 14, -37, 31, +0, 21, -50, 52, +-53, -71, -27, 33, +-37, -1, -19, 25, +-19, -5, -28, 22, +6, 65, -44, 74, +-33, -48, -33, 9, +-40, 57, -14, 58, +-17, 4, -45, 32, +-31, 38, -33, 36, +-23, 28, -40, 39, +-43, 29, -12, 46, +-34, 13, -23, 28, +-16, 15, -27, 34, +-14, -82, -15, 43, +-31, 25, -32, 29, +-21, 5, -5, 38, +-47, -63, -51, 33, +-46, 12, 3, 47, +-28, -17, -29, 11, +-10, 14, -40, 38}; diff --git a/ios/IOSDuoduo/Voice/Code/Libs/libspeex/hexc_10_32_table.c b/ios/IOSDuoduo/Voice/Code/Libs/libspeex/hexc_10_32_table.c new file mode 100755 index 000000000..8dd408f2c --- /dev/null +++ b/ios/IOSDuoduo/Voice/Code/Libs/libspeex/hexc_10_32_table.c @@ -0,0 +1,66 @@ +/* Copyright (C) 2002 Jean-Marc Valin + File: hexc_10_32_table.c + Codebook for high-band excitation in SB-CELP mode (4000 bps) + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + - Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + - Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + - Neither the name of the Xiph.org Foundation nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR + CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +const signed char hexc_10_32_table[320] = { +-3, -2, -1, 0, -4, 5, 35, -40, -9, 13, +-44, 5, -27, -1, -7, 6, -11, 7, -8, 7, +19, -14, 15, -4, 9, -10, 10, -8, 10, -9, +-1, 1, 0, 0, 2, 5, -18, 22, -53, 50, +1, -23, 50, -36, 15, 3, -13, 14, -10, 6, +1, 5, -3, 4, -2, 5, -32, 25, 5, -2, +-1, -4, 1, 11, -29, 26, -6, -15, 30, -18, +0, 15, -17, 40, -41, 3, 9, -2, -2, 3, +-3, -1, -5, 2, 21, -6, -16, -21, 23, 2, +60, 15, 16, -16, -9, 14, 9, -1, 7, -9, +0, 1, 1, 0, -1, -6, 17, -28, 54, -45, +-1, 1, -1, -6, -6, 2, 11, 26, -29, -2, +46, -21, 34, 12, -23, 32, -23, 16, -10, 3, +66, 19, -20, 24, 7, 11, -3, 0, -3, -1, +-50, -46, 2, -18, -3, 4, -1, -2, 3, -3, +-19, 41, -36, 9, 11, -24, 21, -16, 9, -3, +-25, -3, 10, 18, -9, -2, -5, -1, -5, 6, +-4, -3, 2, -26, 21, -19, 35, -15, 7, -13, +17, -19, 39, -43, 48, -31, 16, -9, 7, -2, +-5, 3, -4, 9, -19, 27, -55, 63, -35, 10, +26, -44, -2, 9, 4, 1, -6, 8, -9, 5, +-8, -1, -3, -16, 45, -42, 5, 15, -16, 10, +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +-16, 24, -55, 47, -38, 27, -19, 7, -3, 1, +16, 27, 20, -19, 18, 5, -7, 1, -5, 2, +-6, 8, -22, 0, -3, -3, 8, -1, 7, -8, +1, -3, 5, 0, 17, -48, 58, -52, 29, -7, +-2, 3, -10, 6, -26, 58, -31, 1, -6, 3, +93, -29, 39, 3, 17, 5, 6, -1, -1, -1, +27, 13, 10, 19, -7, -34, 12, 10, -4, 9, +-76, 9, 8, -28, -2, -11, 2, -1, 3, 1, +-83, 38, -39, 4, -16, -6, -2, -5, 5, -2, +}; diff --git a/ios/IOSDuoduo/Voice/Code/Libs/libspeex/hexc_table.c b/ios/IOSDuoduo/Voice/Code/Libs/libspeex/hexc_table.c new file mode 100755 index 000000000..268408a8d --- /dev/null +++ b/ios/IOSDuoduo/Voice/Code/Libs/libspeex/hexc_table.c @@ -0,0 +1,162 @@ +/* Copyright (C) 2002 Jean-Marc Valin + File: hexc_table.c + Codebook for high-band excitation in SB-CELP mode (8000 bps with sign) + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + - Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + - Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + - Neither the name of the Xiph.org Foundation nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR + CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +const signed char hexc_table[1024] = { +-24, 21, -20, 5, -5, -7, 14, -10, +2, -27, 16, -20, 0, -32, 26, 19, +8, -11, -41, 31, 28, -27, -32, 34, +42, 34, -17, 22, -10, 13, -29, 18, +-12, -26, -24, 11, 22, 5, -5, -5, +54, -68, -43, 57, -25, 24, 4, 4, +26, -8, -12, -17, 54, 30, -45, 1, +10, -15, 18, -41, 11, 68, -67, 37, +-16, -24, -16, 38, -22, 6, -29, 30, +66, -27, 5, 7, -16, 13, 2, -12, +-7, -3, -20, 36, 4, -28, 9, 3, +32, 48, 26, 39, 3, 0, 7, -21, +-13, 5, -82, -7, 73, -20, 34, -9, +-5, 1, -1, 10, -5, -10, -1, 9, +1, -9, 10, 0, -14, 11, -1, -2, +-1, 11, 20, 96, -81, -22, -12, -9, +-58, 9, 24, -30, 26, -35, 27, -12, +13, -18, 56, -59, 15, -7, 23, -15, +-1, 6, -25, 14, -22, -20, 47, -11, +16, 2, 38, -23, -19, -30, -9, 40, +-11, 5, 4, -6, 8, 26, -21, -11, +127, 4, 1, 6, -9, 2, -7, -2, +-3, 7, -5, 10, -19, 7, -106, 91, +-3, 9, -4, 21, -8, 26, -80, 8, +1, -2, -10, -17, -17, -27, 32, 71, +6, -29, 11, -23, 54, -38, 29, -22, +39, 87, -31, -12, -20, 3, -2, -2, +2, 20, 0, -1, -35, 27, 9, -6, +-12, 3, -12, -6, 13, 1, 14, -22, +-59, -15, -17, -25, 13, -7, 7, 3, +0, 1, -7, 6, -3, 61, -37, -23, +-23, -29, 38, -31, 27, 1, -8, 2, +-27, 23, -26, 36, -34, 5, 24, -24, +-6, 7, 3, -59, 78, -62, 44, -16, +1, 6, 0, 17, 8, 45, 0, -110, +6, 14, -2, 32, -77, -56, 62, -3, +3, -13, 4, -16, 102, -15, -36, -1, +9, -113, 6, 23, 0, 9, 9, 5, +-8, -1, -14, 5, -12, 121, -53, -27, +-8, -9, 22, -13, 3, 2, -3, 1, +-2, -71, 95, 38, -19, 15, -16, -5, +71, 10, 2, -32, -13, -5, 15, -1, +-2, -14, -85, 30, 29, 6, 3, 2, +0, 0, 0, 0, 0, 0, 0, 0, +2, -65, -56, -9, 18, 18, 23, -14, +-2, 0, 12, -29, 26, -12, 1, 2, +-12, -64, 90, -6, 4, 1, 5, -5, +-110, -3, -31, 22, -29, 9, 0, 8, +-40, -5, 21, -5, -5, 13, 10, -18, +40, 1, 35, -20, 30, -28, 11, -6, +19, 7, 14, 18, -64, 9, -6, 16, +51, 68, 8, 16, 12, -8, 0, -9, +20, -22, 25, 7, -4, -13, 41, -35, +93, -18, -54, 11, -1, 1, -9, 4, +-66, 66, -31, 20, -22, 25, -23, 11, +10, 9, 19, 15, 11, -5, -31, -10, +-23, -28, -6, -6, -3, -4, 5, 3, +-28, 22, -11, -42, 25, -25, -16, 41, +34, 47, -6, 2, 42, -19, -22, 5, +-39, 32, 6, -35, 22, 17, -30, 8, +-26, -11, -11, 3, -12, 33, 33, -37, +21, -1, 6, -4, 3, 0, -5, 5, +12, -12, 57, 27, -61, -3, 20, -17, +2, 0, 4, 0, -2, -33, -58, 81, +-23, 39, -10, -5, 2, 6, -7, 5, +4, -3, -2, -13, -23, -72, 107, 15, +-5, 0, -7, -3, -6, 5, -4, 15, +47, 12, -31, 25, -16, 8, 22, -25, +-62, -56, -18, 14, 28, 12, 2, -11, +74, -66, 41, -20, -7, 16, -20, 16, +-8, 0, -16, 4, -19, 92, 12, -59, +-14, -39, 49, -25, -16, 23, -27, 19, +-3, -33, 19, 85, -29, 6, -7, -10, +16, -7, -12, 1, -6, 2, 4, -2, +64, 10, -25, 41, -2, -31, 15, 0, +110, 50, 69, 35, 28, 19, -10, 2, +-43, -49, -56, -15, -16, 10, 3, 12, +-1, -8, 1, 26, -12, -1, 7, -11, +-27, 41, 25, 1, -11, -18, 22, -7, +-1, -47, -8, 23, -3, -17, -7, 18, +-125, 59, -5, 3, 18, 1, 2, 3, +27, -35, 65, -53, 50, -46, 37, -21, +-28, 7, 14, -37, -5, -5, 12, 5, +-8, 78, -19, 21, -6, -16, 8, -7, +5, 2, 7, 2, 10, -6, 12, -60, +44, 11, -36, -32, 31, 0, 2, -2, +2, 1, -3, 7, -10, 17, -21, 10, +6, -2, 19, -2, 59, -38, -86, 38, +8, -41, -30, -45, -33, 7, 15, 28, +29, -7, 24, -40, 7, 7, 5, -2, +9, 24, -23, -18, 6, -29, 30, 2, +28, 49, -11, -46, 10, 43, -13, -9, +-1, -3, -7, -7, -17, -6, 97, -33, +-21, 3, 5, 1, 12, -43, -8, 28, +7, -43, -7, 17, -20, 19, -1, 2, +-13, 9, 54, 34, 9, -28, -11, -9, +-17, 110, -59, 44, -26, 0, 3, -12, +-47, 73, -34, -43, 38, -33, 16, -5, +-46, -4, -6, -2, -25, 19, -29, 28, +-13, 5, 14, 27, -40, -43, 4, 32, +-13, -2, -35, -4, 112, -42, 9, -12, +37, -28, 17, 14, -19, 35, -39, 23, +3, -14, -1, -57, -5, 94, -9, 3, +-39, 5, 30, -10, -32, 42, -13, -14, +-97, -63, 30, -9, 1, -7, 12, 5, +20, 17, -9, -36, -30, 25, 47, -9, +-15, 12, -22, 98, -8, -50, 15, -27, +21, -16, -11, 2, 12, -10, 10, -3, +33, 36, -96, 0, -17, 31, -9, 9, +3, -20, 13, -11, 8, -4, 10, -10, +9, 1, 112, -70, -27, 5, -21, 2, +-57, -3, -29, 10, 19, -21, 21, -10, +-66, -3, 91, -35, 30, -12, 0, -7, +59, -28, 26, 2, 14, -18, 1, 1, +11, 17, 20, -54, -59, 27, 4, 29, +32, 5, 19, 12, -4, 1, 7, -10, +5, -2, 10, 0, 23, -5, 28, -104, +46, 11, 16, 3, 29, 1, -8, -14, +1, 7, -50, 88, -62, 26, 8, -17, +-14, 50, 0, 32, -12, -3, -27, 18, +-8, -5, 8, 3, -20, -11, 37, -12, +9, 33, 46, -101, -1, -4, 1, 6, +-1, 28, -42, -15, 16, 5, -1, -2, +-55, 85, 38, -9, -4, 11, -2, -9, +-6, 3, -20, -10, -77, 89, 24, -3, +-104, -57, -26, -31, -20, -6, -9, 14, +20, -23, 46, -15, -31, 28, 1, -15, +-2, 6, -2, 31, 45, -76, 23, -25, +}; diff --git a/ios/IOSDuoduo/Voice/Code/Libs/libspeex/high_lsp_tables.c b/ios/IOSDuoduo/Voice/Code/Libs/libspeex/high_lsp_tables.c new file mode 100755 index 000000000..e82e87550 --- /dev/null +++ b/ios/IOSDuoduo/Voice/Code/Libs/libspeex/high_lsp_tables.c @@ -0,0 +1,163 @@ +/* Copyright (C) 2002 Jean-Marc Valin + File: high_lsp_tables.c + Codebooks for high-band LSPs in SB-CELP mode + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are + met: + + 1. Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + 3. The name of the author may not be used to endorse or promote products + derived from this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, + INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + POSSIBILITY OF SUCH DAMAGE. +*/ + +const signed char high_lsp_cdbk[512]={ +39,12,-14,-20,-29,-61,-67,-76, +-32,-71,-67,68,77,46,34,5, +-13,-48,-46,-72,-81,-84,-60,-58, +-40,-28,82,93,68,45,29,3, +-19,-47,-28,-43,-35,-30,-8,-13, +-39,-91,-91,-123,-96,10,10,-6, +-18,-55,-60,-91,-56,-36,-27,-16, +-48,-75,40,28,-10,-28,35,9, +37,19,1,-20,-31,-41,-18,-25, +-35,-68,-80,45,27,-1,47,13, +0,-29,-35,-57,-50,-79,-73,-38, +-19,5,35,14,-10,-23,16,-8, +5,-24,-40,-62,-23,-27,-22,-16, +-18,-46,-72,-77,43,21,33,1, +-80,-70,-70,-64,-56,-52,-39,-33, +-31,-38,-19,-19,-15,32,33,-2, +7,-15,-15,-24,-23,-33,-41,-56, +-24,-57,5,89,64,41,27,5, +-9,-47,-60,-97,-97,-124,-20,-9, +-44,-73,31,29,-4,64,48,7, +-35,-57,0,-3,-26,-47,-3,-6, +-40,-76,-79,-48,12,81,55,10, +9,-24,-43,-73,-57,-69,16,5, +-28,-53,18,29,20,0,-4,-11, +6,-13,23,7,-17,-35,-37,-37, +-30,-68,-63,6,24,-9,-14,3, +21,-13,-27,-57,-49,-80,-24,-41, +-5,-16,-5,1,45,25,12,-7, +3,-15,-6,-16,-15,-8,6,-13, +-42,-81,-80,-87,14,1,-10,-3, +-43,-69,-46,-24,-28,-29,36,6, +-43,-56,-12,12,54,79,43,9, +54,22,2,8,-12,-43,-46,-52, +-38,-69,-89,-5,75,38,33,5, +-13,-53,-62,-87,-89,-113,-99,-55, +-34,-37,62,55,33,16,21,-2, +-17,-46,-29,-38,-38,-48,-39,-42, +-36,-75,-72,-88,-48,-30,21,2, +-15,-57,-64,-98,-84,-76,25,1, +-46,-80,-12,18,-7,3,34,6, +38,31,23,4,-1,20,14,-15, +-43,-78,-91,-24,14,-3,54,16, +0,-27,-28,-44,-56,-83,-92,-89, +-3,34,56,41,36,22,20,-8, +-7,-35,-42,-62,-49,3,12,-10, +-50,-87,-96,-66,92,70,38,9, +-70,-71,-62,-42,-39,-43,-11,-7, +-50,-79,-58,-50,-31,32,31,-6, +-4,-25,7,-17,-38,-70,-58,-27, +-43,-83,-28,59,36,20,31,2, +-27,-71,-80,-109,-98,-75,-33,-32, +-31,-2,33,15,-6,43,33,-5, +0,-22,-10,-27,-34,-49,-11,-20, +-41,-91,-100,-121,-39,57,41,10, +-19,-50,-38,-59,-60,-70,-18,-20, +-8,-31,-8,-15,1,-14,-26,-25, +33,21,32,17,1,-19,-19,-26, +-58,-81,-35,-22,45,30,11,-11, +3,-26,-48,-87,-67,-83,-58,3, +-1,-26,-20,44,10,25,39,5, +-9,-35,-27,-38,7,10,4,-9, +-42,-85,-102,-127,52,44,28,10, +-47,-61,-40,-39,-17,-1,-10,-33, +-42,-74,-48,21,-4,70,52,10}; + + +const signed char high_lsp_cdbk2[512]={ +-36,-62,6,-9,-10,-14,-56,23, +1,-26,23,-48,-17,12,8,-7, +23,29,-36,-28,-6,-29,-17,-5, +40,23,10,10,-46,-13,36,6, +4,-30,-29,62,32,-32,-1,22, +-14,1,-4,-22,-45,2,54,4, +-30,-57,-59,-12,27,-3,-31,8, +-9,5,10,-14,32,66,19,9, +2,-25,-37,23,-15,18,-38,-31, +5,-9,-21,15,0,22,62,30, +15,-12,-14,-46,77,21,33,3, +34,29,-19,50,2,11,9,-38, +-12,-37,62,1,-15,54,32,6, +2,-24,20,35,-21,2,19,24, +-13,55,4,9,39,-19,30,-1, +-21,73,54,33,8,18,3,15, +6,-19,-47,6,-3,-48,-50,1, +26,20,8,-23,-50,65,-14,-55, +-17,-31,-37,-28,53,-1,-17,-53, +1,57,11,-8,-25,-30,-37,64, +5,-52,-45,15,23,31,15,14, +-25,24,33,-2,-44,-56,-18,6, +-21,-43,4,-12,17,-37,20,-10, +34,15,2,15,55,21,-11,-31, +-6,46,25,16,-9,-25,-8,-62, +28,17,20,-32,-29,26,30,25, +-19,2,-16,-17,26,-51,2,50, +42,19,-66,23,29,-2,3,19, +-19,-37,32,15,6,30,-34,13, +11,-5,40,31,10,-42,4,-9, +26,-9,-70,17,-2,-23,20,-22, +-55,51,-24,-31,22,-22,15,-13, +3,-10,-28,-16,56,4,-63,11, +-18,-15,-18,-38,-35,16,-7,34, +-1,-21,-49,-47,9,-37,7,8, +69,55,20,6,-33,-45,-10,-9, +6,-9,12,71,15,-3,-42,-7, +-24,32,-35,-2,-42,-17,-5,0, +-2,-33,-54,13,-12,-34,47,23, +19,55,7,-8,74,31,14,16, +-23,-26,19,12,-18,-49,-28,-31, +-20,2,-14,-20,-47,78,40,13, +-23,-11,21,-6,18,1,47,5, +38,35,32,46,22,8,13,16, +-14,18,51,19,40,39,11,-26, +-1,-17,47,2,-53,-15,31,-22, +38,21,-15,-16,5,-33,53,15, +-38,86,11,-3,-24,49,13,-4, +-11,-18,28,20,-12,-27,-26,35, +-25,-35,-3,-20,-61,30,10,-55, +-12,-22,-52,-54,-14,19,-32,-12, +45,15,-8,-48,-9,11,-32,8, +-16,-34,-13,51,18,38,-2,-32, +-17,22,-2,-18,-28,-70,59,27, +-28,-19,-10,-20,-9,-9,-8,-21, +21,-8,35,-2,45,-3,-9,12, +0,30,7,-39,43,27,-38,-91, +30,26,19,-55,-4,63,14,-17, +13,9,13,2,7,4,6,61, +72,-1,-17,29,-1,-22,-17,8, +-28,-37,63,44,41,3,2,14, +9,-6,75,-8,-7,-12,-15,-12, +13,9,-4,30,-22,-65,15,0, +-45,4,-4,1,5,22,11,23}; diff --git a/ios/IOSDuoduo/Voice/Code/Libs/libspeex/jitter.c b/ios/IOSDuoduo/Voice/Code/Libs/libspeex/jitter.c new file mode 100755 index 000000000..84e4afce4 --- /dev/null +++ b/ios/IOSDuoduo/Voice/Code/Libs/libspeex/jitter.c @@ -0,0 +1,843 @@ +/* Copyright (C) 2002 Jean-Marc Valin + File: speex_jitter.h + + Adaptive jitter buffer for Speex + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + - Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + - Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + - Neither the name of the Xiph.org Foundation nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR + CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +*/ + +/* +TODO: +- Add short-term estimate +- Defensive programming + + warn when last returned < last desired (begative buffering) + + warn if update_delay not called between get() and tick() or is called twice in a row +- Linked list structure for holding the packets instead of the current fixed-size array + + return memory to a pool + + allow pre-allocation of the pool + + optional max number of elements +- Statistics + + drift + + loss + + late + + jitter + + buffering delay +*/ +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + + +#include "arch.h" +#include "speex/speex.h" +#include "speex/speex_bits.h" +#include "speex/speex_jitter.h" +#include "os_support.h" + +#ifndef NULL +#define NULL 0 +#endif + +#define SPEEX_JITTER_MAX_BUFFER_SIZE 200 /**< Maximum number of packets in jitter buffer */ + +#define TSUB(a,b) ((spx_int32_t)((a)-(b))) + +#define GT32(a,b) (((spx_int32_t)((a)-(b)))>0) +#define GE32(a,b) (((spx_int32_t)((a)-(b)))>=0) +#define LT32(a,b) (((spx_int32_t)((a)-(b)))<0) +#define LE32(a,b) (((spx_int32_t)((a)-(b)))<=0) + +#define ROUND_DOWN(x, step) ((x)<0 ? ((x)-(step)+1)/(step)*(step) : (x)/(step)*(step)) + +#define MAX_TIMINGS 40 +#define MAX_BUFFERS 3 +#define TOP_DELAY 40 + +/** Buffer that keeps the time of arrival of the latest packets */ +struct TimingBuffer { + int filled; /**< Number of entries occupied in "timing" and "counts"*/ + int curr_count; /**< Number of packet timings we got (including those we discarded) */ + spx_int32_t timing[MAX_TIMINGS]; /**< Sorted list of all timings ("latest" packets first) */ + spx_int16_t counts[MAX_TIMINGS]; /**< Order the packets were put in (will be used for short-term estimate) */ +}; + +static void tb_init(struct TimingBuffer *tb) +{ + tb->filled = 0; + tb->curr_count = 0; +} + +/* Add the timing of a new packet to the TimingBuffer */ +static void tb_add(struct TimingBuffer *tb, spx_int16_t timing) +{ + int pos; + /* Discard packet that won't make it into the list because they're too early */ + if (tb->filled >= MAX_TIMINGS && timing >= tb->timing[tb->filled-1]) + { + tb->curr_count++; + return; + } + + /* Find where the timing info goes in the sorted list */ + pos = 0; + /* FIXME: Do bisection instead of linear search */ + while (posfilled && timing >= tb->timing[pos]) + { + pos++; + } + + speex_assert(pos <= tb->filled && pos < MAX_TIMINGS); + + /* Shift everything so we can perform the insertion */ + if (pos < tb->filled) + { + int move_size = tb->filled-pos; + if (tb->filled == MAX_TIMINGS) + move_size -= 1; + SPEEX_MOVE(&tb->timing[pos+1], &tb->timing[pos], move_size); + SPEEX_MOVE(&tb->counts[pos+1], &tb->counts[pos], move_size); + } + /* Insert */ + tb->timing[pos] = timing; + tb->counts[pos] = tb->curr_count; + + tb->curr_count++; + if (tb->filledfilled++; +} + + + +/** Jitter buffer structure */ +struct JitterBuffer_ { + spx_uint32_t pointer_timestamp; /**< Timestamp of what we will *get* next */ + spx_uint32_t last_returned_timestamp; /**< Useful for getting the next packet with the same timestamp (for fragmented media) */ + spx_uint32_t next_stop; /**< Estimated time the next get() will be called */ + + spx_int32_t buffered; /**< Amount of data we think is still buffered by the application (timestamp units)*/ + + JitterBufferPacket packets[SPEEX_JITTER_MAX_BUFFER_SIZE]; /**< Packets stored in the buffer */ + spx_uint32_t arrival[SPEEX_JITTER_MAX_BUFFER_SIZE]; /**< Packet arrival time (0 means it was late, even though it's a valid timestamp) */ + + void (*destroy) (void *); /**< Callback for destroying a packet */ + + spx_int32_t delay_step; /**< Size of the steps when adjusting buffering (timestamp units) */ + spx_int32_t concealment_size; /**< Size of the packet loss concealment "units" */ + int reset_state; /**< True if state was just reset */ + int buffer_margin; /**< How many frames we want to keep in the buffer (lower bound) */ + int late_cutoff; /**< How late must a packet be for it not to be considered at all */ + int interp_requested; /**< An interpolation is requested by speex_jitter_update_delay() */ + int auto_adjust; /**< Whether to automatically adjust the delay at any time */ + + struct TimingBuffer _tb[MAX_BUFFERS]; /**< Don't use those directly */ + struct TimingBuffer *timeBuffers[MAX_BUFFERS]; /**< Storing arrival time of latest frames so we can compute some stats */ + int window_size; /**< Total window over which the late frames are counted */ + int subwindow_size; /**< Sub-window size for faster computation */ + int max_late_rate; /**< Absolute maximum amount of late packets tolerable (in percent) */ + int latency_tradeoff; /**< Latency equivalent of losing one percent of packets */ + int auto_tradeoff; /**< Latency equivalent of losing one percent of packets (automatic default) */ + + int lost_count; /**< Number of consecutive lost packets */ +}; + +/** Based on available data, this computes the optimal delay for the jitter buffer. + The optimised function is in timestamp units and is: + cost = delay + late_factor*[number of frames that would be late if we used that delay] + @param tb Array of buffers + @param late_factor Equivalent cost of a late frame (in timestamp units) + */ +static spx_int16_t compute_opt_delay(JitterBuffer *jitter) +{ + int i; + spx_int16_t opt=0; + spx_int32_t best_cost=0x7fffffff; + int late = 0; + int pos[MAX_BUFFERS]; + int tot_count; + float late_factor; + int penalty_taken = 0; + int best = 0; + int worst = 0; + spx_int32_t deltaT; + struct TimingBuffer *tb; + + tb = jitter->_tb; + + /* Number of packet timings we have received (including those we didn't keep) */ + tot_count = 0; + for (i=0;ilatency_tradeoff != 0) + late_factor = jitter->latency_tradeoff * 100.0f / tot_count; + else + late_factor = jitter->auto_tradeoff * jitter->window_size/tot_count; + + /*fprintf(stderr, "late_factor = %f\n", late_factor);*/ + for (i=0;idelay_step); + pos[next]++; + + /* Actual cost function that tells us how bad using this delay would be */ + cost = -latest + late_factor*late; + /*fprintf(stderr, "cost %d = %d + %f * %d\n", cost, -latest, late_factor, late);*/ + if (cost < best_cost) + { + best_cost = cost; + opt = latest; + } + } else { + break; + } + + /* For the next timing we will consider, there will be one more late packet to count */ + late++; + /* Two-frame penalty if we're going to increase the amount of late frames (hysteresis) */ + if (latest >= 0 && !penalty_taken) + { + penalty_taken = 1; + late+=4; + } + } + + deltaT = best-worst; + /* This is a default "automatic latency tradeoff" when none is provided */ + jitter->auto_tradeoff = 1 + deltaT/TOP_DELAY; + /*fprintf(stderr, "auto_tradeoff = %d (%d %d %d)\n", jitter->auto_tradeoff, best, worst, i);*/ + + /* FIXME: Compute a short-term estimate too and combine with the long-term one */ + + /* Prevents reducing the buffer size when we haven't really had much data */ + if (tot_count < TOP_DELAY && opt > 0) + return 0; + return opt; +} + + +/** Initialise jitter buffer */ +EXPORT JitterBuffer *jitter_buffer_init(int step_size) +{ + JitterBuffer *jitter = (JitterBuffer*)speex_alloc(sizeof(JitterBuffer)); + if (jitter) + { + int i; + spx_int32_t tmp; + for (i=0;ipackets[i].data=NULL; + jitter->delay_step = step_size; + jitter->concealment_size = step_size; + /*FIXME: Should this be 0 or 1?*/ + jitter->buffer_margin = 0; + jitter->late_cutoff = 50; + jitter->destroy = NULL; + jitter->latency_tradeoff = 0; + jitter->auto_adjust = 1; + tmp = 4; + jitter_buffer_ctl(jitter, JITTER_BUFFER_SET_MAX_LATE_RATE, &tmp); + jitter_buffer_reset(jitter); + } + return jitter; +} + +/** Reset jitter buffer */ +EXPORT void jitter_buffer_reset(JitterBuffer *jitter) +{ + int i; + for (i=0;ipackets[i].data) + { + if (jitter->destroy) + jitter->destroy(jitter->packets[i].data); + else + speex_free(jitter->packets[i].data); + jitter->packets[i].data = NULL; + } + } + /* Timestamp is actually undefined at this point */ + jitter->pointer_timestamp = 0; + jitter->next_stop = 0; + jitter->reset_state = 1; + jitter->lost_count = 0; + jitter->buffered = 0; + jitter->auto_tradeoff = 32000; + + for (i=0;i_tb[i]); + jitter->timeBuffers[i] = &jitter->_tb[i]; + } + /*fprintf (stderr, "reset\n");*/ +} + +/** Destroy jitter buffer */ +EXPORT void jitter_buffer_destroy(JitterBuffer *jitter) +{ + jitter_buffer_reset(jitter); + speex_free(jitter); +} + +/** Take the following timing into consideration for future calculations */ +static void update_timings(JitterBuffer *jitter, spx_int32_t timing) +{ + if (timing < -32767) + timing = -32767; + if (timing > 32767) + timing = 32767; + /* If the current sub-window is full, perform a rotation and discard oldest sub-widow */ + if (jitter->timeBuffers[0]->curr_count >= jitter->subwindow_size) + { + int i; + /*fprintf(stderr, "Rotate buffer\n");*/ + struct TimingBuffer *tmp = jitter->timeBuffers[MAX_BUFFERS-1]; + for (i=MAX_BUFFERS-1;i>=1;i--) + jitter->timeBuffers[i] = jitter->timeBuffers[i-1]; + jitter->timeBuffers[0] = tmp; + tb_init(jitter->timeBuffers[0]); + } + tb_add(jitter->timeBuffers[0], timing); +} + +/** Compensate all timings when we do an adjustment of the buffering */ +static void shift_timings(JitterBuffer *jitter, spx_int16_t amount) +{ + int i, j; + for (i=0;itimeBuffers[i]->filled;j++) + jitter->timeBuffers[i]->timing[j] += amount; + } +} + + +/** Put one packet into the jitter buffer */ +EXPORT void jitter_buffer_put(JitterBuffer *jitter, const JitterBufferPacket *packet) +{ + int i,j; + int late; + /*fprintf (stderr, "put packet %d %d\n", timestamp, span);*/ + + /* Cleanup buffer (remove old packets that weren't played) */ + if (!jitter->reset_state) + { + for (i=0;ipackets[i].data && LE32(jitter->packets[i].timestamp + jitter->packets[i].span, jitter->pointer_timestamp)) + { + /*fprintf (stderr, "cleaned (not played)\n");*/ + if (jitter->destroy) + jitter->destroy(jitter->packets[i].data); + else + speex_free(jitter->packets[i].data); + jitter->packets[i].data = NULL; + } + } + } + + /*fprintf(stderr, "arrival: %d %d %d\n", packet->timestamp, jitter->next_stop, jitter->pointer_timestamp);*/ + /* Check if packet is late (could still be useful though) */ + if (!jitter->reset_state && LT32(packet->timestamp, jitter->next_stop)) + { + update_timings(jitter, ((spx_int32_t)packet->timestamp) - ((spx_int32_t)jitter->next_stop) - jitter->buffer_margin); + late = 1; + } else { + late = 0; + } + + /* For some reason, the consumer has failed the last 20 fetches. Make sure this packet is + * used to resync. */ + if (jitter->lost_count>20) + { + jitter_buffer_reset(jitter); + } + + /* Only insert the packet if it's not hopelessly late (i.e. totally useless) */ + if (jitter->reset_state || GE32(packet->timestamp+packet->span+jitter->delay_step, jitter->pointer_timestamp)) + { + + /*Find an empty slot in the buffer*/ + for (i=0;ipackets[i].data==NULL) + break; + } + + /*No place left in the buffer, need to make room for it by discarding the oldest packet */ + if (i==SPEEX_JITTER_MAX_BUFFER_SIZE) + { + int earliest=jitter->packets[0].timestamp; + i=0; + for (j=1;jpackets[i].data || LT32(jitter->packets[j].timestamp,earliest)) + { + earliest = jitter->packets[j].timestamp; + i=j; + } + } + if (jitter->destroy) + jitter->destroy(jitter->packets[i].data); + else + speex_free(jitter->packets[i].data); + jitter->packets[i].data=NULL; + /*fprintf (stderr, "Buffer is full, discarding earliest frame %d (currently at %d)\n", timestamp, jitter->pointer_timestamp);*/ + } + + /* Copy packet in buffer */ + if (jitter->destroy) + { + jitter->packets[i].data = packet->data; + } else { + jitter->packets[i].data=(char*)speex_alloc(packet->len); + for (j=0;jlen;j++) + jitter->packets[i].data[j]=packet->data[j]; + } + jitter->packets[i].timestamp=packet->timestamp; + jitter->packets[i].span=packet->span; + jitter->packets[i].len=packet->len; + jitter->packets[i].sequence=packet->sequence; + jitter->packets[i].user_data=packet->user_data; + if (jitter->reset_state || late) + jitter->arrival[i] = 0; + else + jitter->arrival[i] = jitter->next_stop; + } + + +} + +/** Get one packet from the jitter buffer */ +EXPORT int jitter_buffer_get(JitterBuffer *jitter, JitterBufferPacket *packet, spx_int32_t desired_span, spx_int32_t *start_offset) +{ + int i; + unsigned int j; + int incomplete = 0; + spx_int16_t opt; + + if (start_offset != NULL) + *start_offset = 0; + + /* Syncing on the first call */ + if (jitter->reset_state) + { + int found = 0; + /* Find the oldest packet */ + spx_uint32_t oldest=0; + for (i=0;ipackets[i].data && (!found || LT32(jitter->packets[i].timestamp,oldest))) + { + oldest = jitter->packets[i].timestamp; + found = 1; + } + } + if (found) + { + jitter->reset_state=0; + jitter->pointer_timestamp = oldest; + jitter->next_stop = oldest; + } else { + packet->timestamp = 0; + packet->span = jitter->interp_requested; + return JITTER_BUFFER_MISSING; + } + } + + + jitter->last_returned_timestamp = jitter->pointer_timestamp; + + if (jitter->interp_requested != 0) + { + packet->timestamp = jitter->pointer_timestamp; + packet->span = jitter->interp_requested; + + /* Increment the pointer because it got decremented in the delay update */ + jitter->pointer_timestamp += jitter->interp_requested; + packet->len = 0; + /*fprintf (stderr, "Deferred interpolate\n");*/ + + jitter->interp_requested = 0; + + jitter->buffered = packet->span - desired_span; + + return JITTER_BUFFER_INSERTION; + } + + /* Searching for the packet that fits best */ + + /* Search the buffer for a packet with the right timestamp and spanning the whole current chunk */ + for (i=0;ipackets[i].data && jitter->packets[i].timestamp==jitter->pointer_timestamp && GE32(jitter->packets[i].timestamp+jitter->packets[i].span,jitter->pointer_timestamp+desired_span)) + break; + } + + /* If no match, try for an "older" packet that still spans (fully) the current chunk */ + if (i==SPEEX_JITTER_MAX_BUFFER_SIZE) + { + for (i=0;ipackets[i].data && LE32(jitter->packets[i].timestamp, jitter->pointer_timestamp) && GE32(jitter->packets[i].timestamp+jitter->packets[i].span,jitter->pointer_timestamp+desired_span)) + break; + } + } + + /* If still no match, try for an "older" packet that spans part of the current chunk */ + if (i==SPEEX_JITTER_MAX_BUFFER_SIZE) + { + for (i=0;ipackets[i].data && LE32(jitter->packets[i].timestamp, jitter->pointer_timestamp) && GT32(jitter->packets[i].timestamp+jitter->packets[i].span,jitter->pointer_timestamp)) + break; + } + } + + /* If still no match, try for earliest packet possible */ + if (i==SPEEX_JITTER_MAX_BUFFER_SIZE) + { + int found = 0; + spx_uint32_t best_time=0; + int best_span=0; + int besti=0; + for (i=0;ipackets[i].data && LT32(jitter->packets[i].timestamp,jitter->pointer_timestamp+desired_span) && GE32(jitter->packets[i].timestamp,jitter->pointer_timestamp)) + { + if (!found || LT32(jitter->packets[i].timestamp,best_time) || (jitter->packets[i].timestamp==best_time && GT32(jitter->packets[i].span,best_span))) + { + best_time = jitter->packets[i].timestamp; + best_span = jitter->packets[i].span; + besti = i; + found = 1; + } + } + } + if (found) + { + i=besti; + incomplete = 1; + /*fprintf (stderr, "incomplete: %d %d %d %d\n", jitter->packets[i].timestamp, jitter->pointer_timestamp, chunk_size, jitter->packets[i].span);*/ + } + } + + /* If we find something */ + if (i!=SPEEX_JITTER_MAX_BUFFER_SIZE) + { + spx_int32_t offset; + + /* We (obviously) haven't lost this packet */ + jitter->lost_count = 0; + + /* In this case, 0 isn't as a valid timestamp */ + if (jitter->arrival[i] != 0) + { + update_timings(jitter, ((spx_int32_t)jitter->packets[i].timestamp) - ((spx_int32_t)jitter->arrival[i]) - jitter->buffer_margin); + } + + + /* Copy packet */ + if (jitter->destroy) + { + packet->data = jitter->packets[i].data; + packet->len = jitter->packets[i].len; + } else { + if (jitter->packets[i].len > packet->len) + { + speex_warning_int("jitter_buffer_get(): packet too large to fit. Size is", jitter->packets[i].len); + } else { + packet->len = jitter->packets[i].len; + } + for (j=0;jlen;j++) + packet->data[j] = jitter->packets[i].data[j]; + /* Remove packet */ + speex_free(jitter->packets[i].data); + } + jitter->packets[i].data = NULL; + /* Set timestamp and span (if requested) */ + offset = (spx_int32_t)jitter->packets[i].timestamp-(spx_int32_t)jitter->pointer_timestamp; + if (start_offset != NULL) + *start_offset = offset; + else if (offset != 0) + speex_warning_int("jitter_buffer_get() discarding non-zero start_offset", offset); + + packet->timestamp = jitter->packets[i].timestamp; + jitter->last_returned_timestamp = packet->timestamp; + + packet->span = jitter->packets[i].span; + packet->sequence = jitter->packets[i].sequence; + packet->user_data = jitter->packets[i].user_data; + /* Point to the end of the current packet */ + jitter->pointer_timestamp = jitter->packets[i].timestamp+jitter->packets[i].span; + + jitter->buffered = packet->span - desired_span; + + if (start_offset != NULL) + jitter->buffered += *start_offset; + + return JITTER_BUFFER_OK; + } + + + /* If we haven't found anything worth returning */ + + /*fprintf (stderr, "not found\n");*/ + jitter->lost_count++; + /*fprintf (stderr, "m");*/ + /*fprintf (stderr, "lost_count = %d\n", jitter->lost_count);*/ + + opt = compute_opt_delay(jitter); + + /* Should we force an increase in the buffer or just do normal interpolation? */ + if (opt < 0) + { + /* Need to increase buffering */ + + /* Shift histogram to compensate */ + shift_timings(jitter, -opt); + + packet->timestamp = jitter->pointer_timestamp; + packet->span = -opt; + /* Don't move the pointer_timestamp forward */ + packet->len = 0; + + jitter->buffered = packet->span - desired_span; + return JITTER_BUFFER_INSERTION; + /*jitter->pointer_timestamp -= jitter->delay_step;*/ + /*fprintf (stderr, "Forced to interpolate\n");*/ + } else { + /* Normal packet loss */ + packet->timestamp = jitter->pointer_timestamp; + + desired_span = ROUND_DOWN(desired_span, jitter->concealment_size); + packet->span = desired_span; + jitter->pointer_timestamp += desired_span; + packet->len = 0; + + jitter->buffered = packet->span - desired_span; + return JITTER_BUFFER_MISSING; + /*fprintf (stderr, "Normal loss\n");*/ + } + + +} + +EXPORT int jitter_buffer_get_another(JitterBuffer *jitter, JitterBufferPacket *packet) +{ + int i, j; + for (i=0;ipackets[i].data && jitter->packets[i].timestamp==jitter->last_returned_timestamp) + break; + } + if (i!=SPEEX_JITTER_MAX_BUFFER_SIZE) + { + /* Copy packet */ + packet->len = jitter->packets[i].len; + if (jitter->destroy) + { + packet->data = jitter->packets[i].data; + } else { + for (j=0;jlen;j++) + packet->data[j] = jitter->packets[i].data[j]; + /* Remove packet */ + speex_free(jitter->packets[i].data); + } + jitter->packets[i].data = NULL; + packet->timestamp = jitter->packets[i].timestamp; + packet->span = jitter->packets[i].span; + packet->sequence = jitter->packets[i].sequence; + packet->user_data = jitter->packets[i].user_data; + return JITTER_BUFFER_OK; + } else { + packet->data = NULL; + packet->len = 0; + packet->span = 0; + return JITTER_BUFFER_MISSING; + } +} + +/* Let the jitter buffer know it's the right time to adjust the buffering delay to the network conditions */ +static int _jitter_buffer_update_delay(JitterBuffer *jitter, JitterBufferPacket *packet, spx_int32_t *start_offset) +{ + spx_int16_t opt = compute_opt_delay(jitter); + /*fprintf(stderr, "opt adjustment is %d ", opt);*/ + + if (opt < 0) + { + shift_timings(jitter, -opt); + + jitter->pointer_timestamp += opt; + jitter->interp_requested = -opt; + /*fprintf (stderr, "Decision to interpolate %d samples\n", -opt);*/ + } else if (opt > 0) + { + shift_timings(jitter, -opt); + jitter->pointer_timestamp += opt; + /*fprintf (stderr, "Decision to drop %d samples\n", opt);*/ + } + + return opt; +} + +/* Let the jitter buffer know it's the right time to adjust the buffering delay to the network conditions */ +EXPORT int jitter_buffer_update_delay(JitterBuffer *jitter, JitterBufferPacket *packet, spx_int32_t *start_offset) +{ + /* If the programmer calls jitter_buffer_update_delay() directly, + automatically disable auto-adjustment */ + jitter->auto_adjust = 0; + + return _jitter_buffer_update_delay(jitter, packet, start_offset); +} + +/** Get pointer timestamp of jitter buffer */ +EXPORT int jitter_buffer_get_pointer_timestamp(JitterBuffer *jitter) +{ + return jitter->pointer_timestamp; +} + +EXPORT void jitter_buffer_tick(JitterBuffer *jitter) +{ + /* Automatically-adjust the buffering delay if requested */ + if (jitter->auto_adjust) + _jitter_buffer_update_delay(jitter, NULL, NULL); + + if (jitter->buffered >= 0) + { + jitter->next_stop = jitter->pointer_timestamp - jitter->buffered; + } else { + jitter->next_stop = jitter->pointer_timestamp; + speex_warning_int("jitter buffer sees negative buffering, your code might be broken. Value is ", jitter->buffered); + } + jitter->buffered = 0; +} + +EXPORT void jitter_buffer_remaining_span(JitterBuffer *jitter, spx_uint32_t rem) +{ + /* Automatically-adjust the buffering delay if requested */ + if (jitter->auto_adjust) + _jitter_buffer_update_delay(jitter, NULL, NULL); + + if (jitter->buffered < 0) + speex_warning_int("jitter buffer sees negative buffering, your code might be broken. Value is ", jitter->buffered); + jitter->next_stop = jitter->pointer_timestamp - rem; +} + + +/* Used like the ioctl function to control the jitter buffer parameters */ +EXPORT int jitter_buffer_ctl(JitterBuffer *jitter, int request, void *ptr) +{ + int count, i; + switch(request) + { + case JITTER_BUFFER_SET_MARGIN: + jitter->buffer_margin = *(spx_int32_t*)ptr; + break; + case JITTER_BUFFER_GET_MARGIN: + *(spx_int32_t*)ptr = jitter->buffer_margin; + break; + case JITTER_BUFFER_GET_AVALIABLE_COUNT: + count = 0; + for (i=0;ipackets[i].data && LE32(jitter->pointer_timestamp, jitter->packets[i].timestamp)) + { + count++; + } + } + *(spx_int32_t*)ptr = count; + break; + case JITTER_BUFFER_SET_DESTROY_CALLBACK: + jitter->destroy = (void (*) (void *))ptr; + break; + case JITTER_BUFFER_GET_DESTROY_CALLBACK: + *(void (**) (void *))ptr = jitter->destroy; + break; + case JITTER_BUFFER_SET_DELAY_STEP: + jitter->delay_step = *(spx_int32_t*)ptr; + break; + case JITTER_BUFFER_GET_DELAY_STEP: + *(spx_int32_t*)ptr = jitter->delay_step; + break; + case JITTER_BUFFER_SET_CONCEALMENT_SIZE: + jitter->concealment_size = *(spx_int32_t*)ptr; + break; + case JITTER_BUFFER_GET_CONCEALMENT_SIZE: + *(spx_int32_t*)ptr = jitter->concealment_size; + break; + case JITTER_BUFFER_SET_MAX_LATE_RATE: + jitter->max_late_rate = *(spx_int32_t*)ptr; + jitter->window_size = 100*TOP_DELAY/jitter->max_late_rate; + jitter->subwindow_size = jitter->window_size/MAX_BUFFERS; + break; + case JITTER_BUFFER_GET_MAX_LATE_RATE: + *(spx_int32_t*)ptr = jitter->max_late_rate; + break; + case JITTER_BUFFER_SET_LATE_COST: + jitter->latency_tradeoff = *(spx_int32_t*)ptr; + break; + case JITTER_BUFFER_GET_LATE_COST: + *(spx_int32_t*)ptr = jitter->latency_tradeoff; + break; + default: + speex_warning_int("Unknown jitter_buffer_ctl request: ", request); + return -1; + } + return 0; +} + diff --git a/ios/IOSDuoduo/Voice/Code/Libs/libspeex/kiss_fft.c b/ios/IOSDuoduo/Voice/Code/Libs/libspeex/kiss_fft.c new file mode 100755 index 000000000..67782810f --- /dev/null +++ b/ios/IOSDuoduo/Voice/Code/Libs/libspeex/kiss_fft.c @@ -0,0 +1,523 @@ +/* +Copyright (c) 2003-2004, Mark Borgerding +Copyright (c) 2005-2007, Jean-Marc Valin + +All rights reserved. + +Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. + * Neither the author nor the names of any contributors may be used to endorse or promote products derived from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "_kiss_fft_guts.h" +#include "arch.h" +#include "os_support.h" + +/* The guts header contains all the multiplication and addition macros that are defined for + fixed or floating point complex numbers. It also delares the kf_ internal functions. + */ + +static void kf_bfly2( + kiss_fft_cpx * Fout, + const size_t fstride, + const kiss_fft_cfg st, + int m, + int N, + int mm + ) +{ + kiss_fft_cpx * Fout2; + kiss_fft_cpx * tw1; + kiss_fft_cpx t; + if (!st->inverse) { + int i,j; + kiss_fft_cpx * Fout_beg = Fout; + for (i=0;itwiddles; + for(j=0;jr , tw1->r),MULT16_16(Fout2->i , tw1->i)), 1); + ti = SHR32(ADD32(MULT16_16(Fout2->i , tw1->r),MULT16_16(Fout2->r , tw1->i)), 1); + tw1 += fstride; + Fout2->r = PSHR32(SUB32(SHL32(EXTEND32(Fout->r), 14), tr), 15); + Fout2->i = PSHR32(SUB32(SHL32(EXTEND32(Fout->i), 14), ti), 15); + Fout->r = PSHR32(ADD32(SHL32(EXTEND32(Fout->r), 14), tr), 15); + Fout->i = PSHR32(ADD32(SHL32(EXTEND32(Fout->i), 14), ti), 15); + ++Fout2; + ++Fout; + } + } + } else { + int i,j; + kiss_fft_cpx * Fout_beg = Fout; + for (i=0;itwiddles; + for(j=0;jinverse) + { + kiss_fft_cpx * Fout_beg = Fout; + for (i=0;itwiddles; + for (j=0;jtwiddles; + for (j=0;jr = PSHR16(Fout->r, 2); + Fout->i = PSHR16(Fout->i, 2); + C_SUB( scratch[5] , *Fout, scratch[1] ); + C_ADDTO(*Fout, scratch[1]); + C_ADD( scratch[3] , scratch[0] , scratch[2] ); + C_SUB( scratch[4] , scratch[0] , scratch[2] ); + Fout[m2].r = PSHR16(Fout[m2].r, 2); + Fout[m2].i = PSHR16(Fout[m2].i, 2); + C_SUB( Fout[m2], *Fout, scratch[3] ); + tw1 += fstride; + tw2 += fstride*2; + tw3 += fstride*3; + C_ADDTO( *Fout , scratch[3] ); + + Fout[m].r = scratch[5].r + scratch[4].i; + Fout[m].i = scratch[5].i - scratch[4].r; + Fout[m3].r = scratch[5].r - scratch[4].i; + Fout[m3].i = scratch[5].i + scratch[4].r; + ++Fout; + } + } + } +} + +static void kf_bfly3( + kiss_fft_cpx * Fout, + const size_t fstride, + const kiss_fft_cfg st, + size_t m + ) +{ + size_t k=m; + const size_t m2 = 2*m; + kiss_fft_cpx *tw1,*tw2; + kiss_fft_cpx scratch[5]; + kiss_fft_cpx epi3; + epi3 = st->twiddles[fstride*m]; + + tw1=tw2=st->twiddles; + + do{ + if (!st->inverse) { + C_FIXDIV(*Fout,3); C_FIXDIV(Fout[m],3); C_FIXDIV(Fout[m2],3); + } + + C_MUL(scratch[1],Fout[m] , *tw1); + C_MUL(scratch[2],Fout[m2] , *tw2); + + C_ADD(scratch[3],scratch[1],scratch[2]); + C_SUB(scratch[0],scratch[1],scratch[2]); + tw1 += fstride; + tw2 += fstride*2; + + Fout[m].r = Fout->r - HALF_OF(scratch[3].r); + Fout[m].i = Fout->i - HALF_OF(scratch[3].i); + + C_MULBYSCALAR( scratch[0] , epi3.i ); + + C_ADDTO(*Fout,scratch[3]); + + Fout[m2].r = Fout[m].r + scratch[0].i; + Fout[m2].i = Fout[m].i - scratch[0].r; + + Fout[m].r -= scratch[0].i; + Fout[m].i += scratch[0].r; + + ++Fout; + }while(--k); +} + +static void kf_bfly5( + kiss_fft_cpx * Fout, + const size_t fstride, + const kiss_fft_cfg st, + int m + ) +{ + kiss_fft_cpx *Fout0,*Fout1,*Fout2,*Fout3,*Fout4; + int u; + kiss_fft_cpx scratch[13]; + kiss_fft_cpx * twiddles = st->twiddles; + kiss_fft_cpx *tw; + kiss_fft_cpx ya,yb; + ya = twiddles[fstride*m]; + yb = twiddles[fstride*2*m]; + + Fout0=Fout; + Fout1=Fout0+m; + Fout2=Fout0+2*m; + Fout3=Fout0+3*m; + Fout4=Fout0+4*m; + + tw=st->twiddles; + for ( u=0; uinverse) { + C_FIXDIV( *Fout0,5); C_FIXDIV( *Fout1,5); C_FIXDIV( *Fout2,5); C_FIXDIV( *Fout3,5); C_FIXDIV( *Fout4,5); + } + scratch[0] = *Fout0; + + C_MUL(scratch[1] ,*Fout1, tw[u*fstride]); + C_MUL(scratch[2] ,*Fout2, tw[2*u*fstride]); + C_MUL(scratch[3] ,*Fout3, tw[3*u*fstride]); + C_MUL(scratch[4] ,*Fout4, tw[4*u*fstride]); + + C_ADD( scratch[7],scratch[1],scratch[4]); + C_SUB( scratch[10],scratch[1],scratch[4]); + C_ADD( scratch[8],scratch[2],scratch[3]); + C_SUB( scratch[9],scratch[2],scratch[3]); + + Fout0->r += scratch[7].r + scratch[8].r; + Fout0->i += scratch[7].i + scratch[8].i; + + scratch[5].r = scratch[0].r + S_MUL(scratch[7].r,ya.r) + S_MUL(scratch[8].r,yb.r); + scratch[5].i = scratch[0].i + S_MUL(scratch[7].i,ya.r) + S_MUL(scratch[8].i,yb.r); + + scratch[6].r = S_MUL(scratch[10].i,ya.i) + S_MUL(scratch[9].i,yb.i); + scratch[6].i = -S_MUL(scratch[10].r,ya.i) - S_MUL(scratch[9].r,yb.i); + + C_SUB(*Fout1,scratch[5],scratch[6]); + C_ADD(*Fout4,scratch[5],scratch[6]); + + scratch[11].r = scratch[0].r + S_MUL(scratch[7].r,yb.r) + S_MUL(scratch[8].r,ya.r); + scratch[11].i = scratch[0].i + S_MUL(scratch[7].i,yb.r) + S_MUL(scratch[8].i,ya.r); + scratch[12].r = - S_MUL(scratch[10].i,yb.i) + S_MUL(scratch[9].i,ya.i); + scratch[12].i = S_MUL(scratch[10].r,yb.i) - S_MUL(scratch[9].r,ya.i); + + C_ADD(*Fout2,scratch[11],scratch[12]); + C_SUB(*Fout3,scratch[11],scratch[12]); + + ++Fout0;++Fout1;++Fout2;++Fout3;++Fout4; + } +} + +/* perform the butterfly for one stage of a mixed radix FFT */ +static void kf_bfly_generic( + kiss_fft_cpx * Fout, + const size_t fstride, + const kiss_fft_cfg st, + int m, + int p + ) +{ + int u,k,q1,q; + kiss_fft_cpx * twiddles = st->twiddles; + kiss_fft_cpx t; + kiss_fft_cpx scratchbuf[17]; + int Norig = st->nfft; + + /*CHECKBUF(scratchbuf,nscratchbuf,p);*/ + if (p>17) + speex_fatal("KissFFT: max radix supported is 17"); + + for ( u=0; uinverse) { + C_FIXDIV(scratchbuf[q1],p); + } + k += m; + } + + k=u; + for ( q1=0 ; q1

=Norig) twidx-=Norig; + C_MUL(t,scratchbuf[q] , twiddles[twidx] ); + C_ADDTO( Fout[ k ] ,t); + } + k += m; + } + } +} + +static +void kf_shuffle( + kiss_fft_cpx * Fout, + const kiss_fft_cpx * f, + const size_t fstride, + int in_stride, + int * factors, + const kiss_fft_cfg st + ) +{ + const int p=*factors++; /* the radix */ + const int m=*factors++; /* stage's fft length/p */ + + /*printf ("fft %d %d %d %d %d %d\n", p*m, m, p, s2, fstride*in_stride, N);*/ + if (m==1) + { + int j; + for (j=0;j32000 || (spx_int32_t)p*(spx_int32_t)p > n) + p = n; /* no more factors, skip to end */ + } + n /= p; + *facbuf++ = p; + *facbuf++ = n; + } while (n > 1); +} +/* + * + * User-callable function to allocate all necessary storage space for the fft. + * + * The return value is a contiguous block of memory, allocated with malloc. As such, + * It can be freed with free(), rather than a kiss_fft-specific function. + * */ +kiss_fft_cfg kiss_fft_alloc(int nfft,int inverse_fft,void * mem,size_t * lenmem ) +{ + kiss_fft_cfg st=NULL; + size_t memneeded = sizeof(struct kiss_fft_state) + + sizeof(kiss_fft_cpx)*(nfft-1); /* twiddle factors*/ + + if ( lenmem==NULL ) { + st = ( kiss_fft_cfg)KISS_FFT_MALLOC( memneeded ); + }else{ + if (mem != NULL && *lenmem >= memneeded) + st = (kiss_fft_cfg)mem; + *lenmem = memneeded; + } + if (st) { + int i; + st->nfft=nfft; + st->inverse = inverse_fft; +#ifdef FIXED_POINT + for (i=0;iinverse) + phase = -phase; + kf_cexp2(st->twiddles+i, DIV32(SHL32(phase,17),nfft)); + } +#else + for (i=0;iinverse) + phase *= -1; + kf_cexp(st->twiddles+i, phase ); + } +#endif + kf_factor(nfft,st->factors); + } + return st; +} + + + + +void kiss_fft_stride(kiss_fft_cfg st,const kiss_fft_cpx *fin,kiss_fft_cpx *fout,int in_stride) +{ + if (fin == fout) + { + speex_fatal("In-place FFT not supported"); + /*CHECKBUF(tmpbuf,ntmpbuf,st->nfft); + kf_work(tmpbuf,fin,1,in_stride, st->factors,st); + SPEEX_MOVE(fout,tmpbuf,st->nfft);*/ + } else { + kf_shuffle( fout, fin, 1,in_stride, st->factors,st); + kf_work( fout, fin, 1,in_stride, st->factors,st, 1, in_stride, 1); + } +} + +void kiss_fft(kiss_fft_cfg cfg,const kiss_fft_cpx *fin,kiss_fft_cpx *fout) +{ + kiss_fft_stride(cfg,fin,fout,1); +} + diff --git a/ios/IOSDuoduo/Voice/Code/Libs/libspeex/kiss_fft.h b/ios/IOSDuoduo/Voice/Code/Libs/libspeex/kiss_fft.h new file mode 100755 index 000000000..fa3f2c604 --- /dev/null +++ b/ios/IOSDuoduo/Voice/Code/Libs/libspeex/kiss_fft.h @@ -0,0 +1,108 @@ +#ifndef KISS_FFT_H +#define KISS_FFT_H + +#include +#include +#include "arch.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/* + ATTENTION! + If you would like a : + -- a utility that will handle the caching of fft objects + -- real-only (no imaginary time component ) FFT + -- a multi-dimensional FFT + -- a command-line utility to perform ffts + -- a command-line utility to perform fast-convolution filtering + + Then see kfc.h kiss_fftr.h kiss_fftnd.h fftutil.c kiss_fastfir.c + in the tools/ directory. +*/ + +#ifdef USE_SIMD +# include +# define kiss_fft_scalar __m128 +#define KISS_FFT_MALLOC(nbytes) memalign(16,nbytes) +#else +#define KISS_FFT_MALLOC speex_alloc +#endif + + +#ifdef FIXED_POINT +#include "arch.h" +# define kiss_fft_scalar spx_int16_t +#else +# ifndef kiss_fft_scalar +/* default is float */ +# define kiss_fft_scalar float +# endif +#endif + +typedef struct { + kiss_fft_scalar r; + kiss_fft_scalar i; +}kiss_fft_cpx; + +typedef struct kiss_fft_state* kiss_fft_cfg; + +/* + * kiss_fft_alloc + * + * Initialize a FFT (or IFFT) algorithm's cfg/state buffer. + * + * typical usage: kiss_fft_cfg mycfg=kiss_fft_alloc(1024,0,NULL,NULL); + * + * The return value from fft_alloc is a cfg buffer used internally + * by the fft routine or NULL. + * + * If lenmem is NULL, then kiss_fft_alloc will allocate a cfg buffer using malloc. + * The returned value should be free()d when done to avoid memory leaks. + * + * The state can be placed in a user supplied buffer 'mem': + * If lenmem is not NULL and mem is not NULL and *lenmem is large enough, + * then the function places the cfg in mem and the size used in *lenmem + * and returns mem. + * + * If lenmem is not NULL and ( mem is NULL or *lenmem is not large enough), + * then the function returns NULL and places the minimum cfg + * buffer size in *lenmem. + * */ + +kiss_fft_cfg kiss_fft_alloc(int nfft,int inverse_fft,void * mem,size_t * lenmem); + +/* + * kiss_fft(cfg,in_out_buf) + * + * Perform an FFT on a complex input buffer. + * for a forward FFT, + * fin should be f[0] , f[1] , ... ,f[nfft-1] + * fout will be F[0] , F[1] , ... ,F[nfft-1] + * Note that each element is complex and can be accessed like + f[k].r and f[k].i + * */ +void kiss_fft(kiss_fft_cfg cfg,const kiss_fft_cpx *fin,kiss_fft_cpx *fout); + +/* + A more generic version of the above function. It reads its input from every Nth sample. + * */ +void kiss_fft_stride(kiss_fft_cfg cfg,const kiss_fft_cpx *fin,kiss_fft_cpx *fout,int fin_stride); + +/* If kiss_fft_alloc allocated a buffer, it is one contiguous + buffer and can be simply free()d when no longer needed*/ +#define kiss_fft_free speex_free + +/* + Cleans up some memory that gets managed internally. Not necessary to call, but it might clean up + your compiler output to call this before you exit. +*/ +void kiss_fft_cleanup(void); + + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/ios/IOSDuoduo/Voice/Code/Libs/libspeex/kiss_fftr.c b/ios/IOSDuoduo/Voice/Code/Libs/libspeex/kiss_fftr.c new file mode 100755 index 000000000..f6275b879 --- /dev/null +++ b/ios/IOSDuoduo/Voice/Code/Libs/libspeex/kiss_fftr.c @@ -0,0 +1,297 @@ +/* +Copyright (c) 2003-2004, Mark Borgerding + +All rights reserved. + +Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. + * Neither the author nor the names of any contributors may be used to endorse or promote products derived from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "os_support.h" +#include "kiss_fftr.h" +#include "_kiss_fft_guts.h" + +struct kiss_fftr_state{ + kiss_fft_cfg substate; + kiss_fft_cpx * tmpbuf; + kiss_fft_cpx * super_twiddles; +#ifdef USE_SIMD + long pad; +#endif +}; + +kiss_fftr_cfg kiss_fftr_alloc(int nfft,int inverse_fft,void * mem,size_t * lenmem) +{ + int i; + kiss_fftr_cfg st = NULL; + size_t subsize, memneeded; + + if (nfft & 1) { + speex_warning("Real FFT optimization must be even.\n"); + return NULL; + } + nfft >>= 1; + + kiss_fft_alloc (nfft, inverse_fft, NULL, &subsize); + memneeded = sizeof(struct kiss_fftr_state) + subsize + sizeof(kiss_fft_cpx) * ( nfft * 2); + + if (lenmem == NULL) { + st = (kiss_fftr_cfg) KISS_FFT_MALLOC (memneeded); + } else { + if (*lenmem >= memneeded) + st = (kiss_fftr_cfg) mem; + *lenmem = memneeded; + } + if (!st) + return NULL; + + st->substate = (kiss_fft_cfg) (st + 1); /*just beyond kiss_fftr_state struct */ + st->tmpbuf = (kiss_fft_cpx *) (((char *) st->substate) + subsize); + st->super_twiddles = st->tmpbuf + nfft; + kiss_fft_alloc(nfft, inverse_fft, st->substate, &subsize); + +#ifdef FIXED_POINT + for (i=0;i>1); + if (!inverse_fft) + phase = -phase; + kf_cexp2(st->super_twiddles+i, DIV32(SHL32(phase,16),nfft)); + } +#else + for (i=0;isuper_twiddles+i, phase ); + } +#endif + return st; +} + +void kiss_fftr(kiss_fftr_cfg st,const kiss_fft_scalar *timedata,kiss_fft_cpx *freqdata) +{ + /* input buffer timedata is stored row-wise */ + int k,ncfft; + kiss_fft_cpx fpnk,fpk,f1k,f2k,tw,tdc; + + if ( st->substate->inverse) { + speex_fatal("kiss fft usage error: improper alloc\n"); + } + + ncfft = st->substate->nfft; + + /*perform the parallel fft of two real signals packed in real,imag*/ + kiss_fft( st->substate , (const kiss_fft_cpx*)timedata, st->tmpbuf ); + /* The real part of the DC element of the frequency spectrum in st->tmpbuf + * contains the sum of the even-numbered elements of the input time sequence + * The imag part is the sum of the odd-numbered elements + * + * The sum of tdc.r and tdc.i is the sum of the input time sequence. + * yielding DC of input time sequence + * The difference of tdc.r - tdc.i is the sum of the input (dot product) [1,-1,1,-1... + * yielding Nyquist bin of input time sequence + */ + + tdc.r = st->tmpbuf[0].r; + tdc.i = st->tmpbuf[0].i; + C_FIXDIV(tdc,2); + CHECK_OVERFLOW_OP(tdc.r ,+, tdc.i); + CHECK_OVERFLOW_OP(tdc.r ,-, tdc.i); + freqdata[0].r = tdc.r + tdc.i; + freqdata[ncfft].r = tdc.r - tdc.i; +#ifdef USE_SIMD + freqdata[ncfft].i = freqdata[0].i = _mm_set1_ps(0); +#else + freqdata[ncfft].i = freqdata[0].i = 0; +#endif + + for ( k=1;k <= ncfft/2 ; ++k ) { + fpk = st->tmpbuf[k]; + fpnk.r = st->tmpbuf[ncfft-k].r; + fpnk.i = - st->tmpbuf[ncfft-k].i; + C_FIXDIV(fpk,2); + C_FIXDIV(fpnk,2); + + C_ADD( f1k, fpk , fpnk ); + C_SUB( f2k, fpk , fpnk ); + C_MUL( tw , f2k , st->super_twiddles[k]); + + freqdata[k].r = HALF_OF(f1k.r + tw.r); + freqdata[k].i = HALF_OF(f1k.i + tw.i); + freqdata[ncfft-k].r = HALF_OF(f1k.r - tw.r); + freqdata[ncfft-k].i = HALF_OF(tw.i - f1k.i); + } +} + +void kiss_fftri(kiss_fftr_cfg st,const kiss_fft_cpx *freqdata, kiss_fft_scalar *timedata) +{ + /* input buffer timedata is stored row-wise */ + int k, ncfft; + + if (st->substate->inverse == 0) { + speex_fatal("kiss fft usage error: improper alloc\n"); + } + + ncfft = st->substate->nfft; + + st->tmpbuf[0].r = freqdata[0].r + freqdata[ncfft].r; + st->tmpbuf[0].i = freqdata[0].r - freqdata[ncfft].r; + /*C_FIXDIV(st->tmpbuf[0],2);*/ + + for (k = 1; k <= ncfft / 2; ++k) { + kiss_fft_cpx fk, fnkc, fek, fok, tmp; + fk = freqdata[k]; + fnkc.r = freqdata[ncfft - k].r; + fnkc.i = -freqdata[ncfft - k].i; + /*C_FIXDIV( fk , 2 ); + C_FIXDIV( fnkc , 2 );*/ + + C_ADD (fek, fk, fnkc); + C_SUB (tmp, fk, fnkc); + C_MUL (fok, tmp, st->super_twiddles[k]); + C_ADD (st->tmpbuf[k], fek, fok); + C_SUB (st->tmpbuf[ncfft - k], fek, fok); +#ifdef USE_SIMD + st->tmpbuf[ncfft - k].i *= _mm_set1_ps(-1.0); +#else + st->tmpbuf[ncfft - k].i *= -1; +#endif + } + kiss_fft (st->substate, st->tmpbuf, (kiss_fft_cpx *) timedata); +} + +void kiss_fftr2(kiss_fftr_cfg st,const kiss_fft_scalar *timedata,kiss_fft_scalar *freqdata) +{ + /* input buffer timedata is stored row-wise */ + int k,ncfft; + kiss_fft_cpx f2k,tdc; + spx_word32_t f1kr, f1ki, twr, twi; + + if ( st->substate->inverse) { + speex_fatal("kiss fft usage error: improper alloc\n"); + } + + ncfft = st->substate->nfft; + + /*perform the parallel fft of two real signals packed in real,imag*/ + kiss_fft( st->substate , (const kiss_fft_cpx*)timedata, st->tmpbuf ); + /* The real part of the DC element of the frequency spectrum in st->tmpbuf + * contains the sum of the even-numbered elements of the input time sequence + * The imag part is the sum of the odd-numbered elements + * + * The sum of tdc.r and tdc.i is the sum of the input time sequence. + * yielding DC of input time sequence + * The difference of tdc.r - tdc.i is the sum of the input (dot product) [1,-1,1,-1... + * yielding Nyquist bin of input time sequence + */ + + tdc.r = st->tmpbuf[0].r; + tdc.i = st->tmpbuf[0].i; + C_FIXDIV(tdc,2); + CHECK_OVERFLOW_OP(tdc.r ,+, tdc.i); + CHECK_OVERFLOW_OP(tdc.r ,-, tdc.i); + freqdata[0] = tdc.r + tdc.i; + freqdata[2*ncfft-1] = tdc.r - tdc.i; + + for ( k=1;k <= ncfft/2 ; ++k ) + { + /*fpk = st->tmpbuf[k]; + fpnk.r = st->tmpbuf[ncfft-k].r; + fpnk.i = - st->tmpbuf[ncfft-k].i; + C_FIXDIV(fpk,2); + C_FIXDIV(fpnk,2); + + C_ADD( f1k, fpk , fpnk ); + C_SUB( f2k, fpk , fpnk ); + + C_MUL( tw , f2k , st->super_twiddles[k]); + + freqdata[2*k-1] = HALF_OF(f1k.r + tw.r); + freqdata[2*k] = HALF_OF(f1k.i + tw.i); + freqdata[2*(ncfft-k)-1] = HALF_OF(f1k.r - tw.r); + freqdata[2*(ncfft-k)] = HALF_OF(tw.i - f1k.i); + */ + + /*f1k.r = PSHR32(ADD32(EXTEND32(st->tmpbuf[k].r), EXTEND32(st->tmpbuf[ncfft-k].r)),1); + f1k.i = PSHR32(SUB32(EXTEND32(st->tmpbuf[k].i), EXTEND32(st->tmpbuf[ncfft-k].i)),1); + f2k.r = PSHR32(SUB32(EXTEND32(st->tmpbuf[k].r), EXTEND32(st->tmpbuf[ncfft-k].r)),1); + f2k.i = SHR32(ADD32(EXTEND32(st->tmpbuf[k].i), EXTEND32(st->tmpbuf[ncfft-k].i)),1); + + C_MUL( tw , f2k , st->super_twiddles[k]); + + freqdata[2*k-1] = HALF_OF(f1k.r + tw.r); + freqdata[2*k] = HALF_OF(f1k.i + tw.i); + freqdata[2*(ncfft-k)-1] = HALF_OF(f1k.r - tw.r); + freqdata[2*(ncfft-k)] = HALF_OF(tw.i - f1k.i); + */ + f2k.r = SHR32(SUB32(EXTEND32(st->tmpbuf[k].r), EXTEND32(st->tmpbuf[ncfft-k].r)),1); + f2k.i = PSHR32(ADD32(EXTEND32(st->tmpbuf[k].i), EXTEND32(st->tmpbuf[ncfft-k].i)),1); + + f1kr = SHL32(ADD32(EXTEND32(st->tmpbuf[k].r), EXTEND32(st->tmpbuf[ncfft-k].r)),13); + f1ki = SHL32(SUB32(EXTEND32(st->tmpbuf[k].i), EXTEND32(st->tmpbuf[ncfft-k].i)),13); + + twr = SHR32(SUB32(MULT16_16(f2k.r,st->super_twiddles[k].r),MULT16_16(f2k.i,st->super_twiddles[k].i)), 1); + twi = SHR32(ADD32(MULT16_16(f2k.i,st->super_twiddles[k].r),MULT16_16(f2k.r,st->super_twiddles[k].i)), 1); + +#ifdef FIXED_POINT + freqdata[2*k-1] = PSHR32(f1kr + twr, 15); + freqdata[2*k] = PSHR32(f1ki + twi, 15); + freqdata[2*(ncfft-k)-1] = PSHR32(f1kr - twr, 15); + freqdata[2*(ncfft-k)] = PSHR32(twi - f1ki, 15); +#else + freqdata[2*k-1] = .5f*(f1kr + twr); + freqdata[2*k] = .5f*(f1ki + twi); + freqdata[2*(ncfft-k)-1] = .5f*(f1kr - twr); + freqdata[2*(ncfft-k)] = .5f*(twi - f1ki); + +#endif + } +} + +void kiss_fftri2(kiss_fftr_cfg st,const kiss_fft_scalar *freqdata,kiss_fft_scalar *timedata) +{ + /* input buffer timedata is stored row-wise */ + int k, ncfft; + + if (st->substate->inverse == 0) { + speex_fatal ("kiss fft usage error: improper alloc\n"); + } + + ncfft = st->substate->nfft; + + st->tmpbuf[0].r = freqdata[0] + freqdata[2*ncfft-1]; + st->tmpbuf[0].i = freqdata[0] - freqdata[2*ncfft-1]; + /*C_FIXDIV(st->tmpbuf[0],2);*/ + + for (k = 1; k <= ncfft / 2; ++k) { + kiss_fft_cpx fk, fnkc, fek, fok, tmp; + fk.r = freqdata[2*k-1]; + fk.i = freqdata[2*k]; + fnkc.r = freqdata[2*(ncfft - k)-1]; + fnkc.i = -freqdata[2*(ncfft - k)]; + /*C_FIXDIV( fk , 2 ); + C_FIXDIV( fnkc , 2 );*/ + + C_ADD (fek, fk, fnkc); + C_SUB (tmp, fk, fnkc); + C_MUL (fok, tmp, st->super_twiddles[k]); + C_ADD (st->tmpbuf[k], fek, fok); + C_SUB (st->tmpbuf[ncfft - k], fek, fok); +#ifdef USE_SIMD + st->tmpbuf[ncfft - k].i *= _mm_set1_ps(-1.0); +#else + st->tmpbuf[ncfft - k].i *= -1; +#endif + } + kiss_fft (st->substate, st->tmpbuf, (kiss_fft_cpx *) timedata); +} diff --git a/ios/IOSDuoduo/Voice/Code/Libs/libspeex/kiss_fftr.h b/ios/IOSDuoduo/Voice/Code/Libs/libspeex/kiss_fftr.h new file mode 100755 index 000000000..7bfb42334 --- /dev/null +++ b/ios/IOSDuoduo/Voice/Code/Libs/libspeex/kiss_fftr.h @@ -0,0 +1,51 @@ +#ifndef KISS_FTR_H +#define KISS_FTR_H + +#include "kiss_fft.h" +#ifdef __cplusplus +extern "C" { +#endif + + +/* + + Real optimized version can save about 45% cpu time vs. complex fft of a real seq. + + + + */ + +typedef struct kiss_fftr_state *kiss_fftr_cfg; + + +kiss_fftr_cfg kiss_fftr_alloc(int nfft,int inverse_fft,void * mem, size_t * lenmem); +/* + nfft must be even + + If you don't care to allocate space, use mem = lenmem = NULL +*/ + + +void kiss_fftr(kiss_fftr_cfg cfg,const kiss_fft_scalar *timedata,kiss_fft_cpx *freqdata); +/* + input timedata has nfft scalar points + output freqdata has nfft/2+1 complex points +*/ + +void kiss_fftr2(kiss_fftr_cfg st,const kiss_fft_scalar *timedata,kiss_fft_scalar *freqdata); + +void kiss_fftri(kiss_fftr_cfg cfg,const kiss_fft_cpx *freqdata,kiss_fft_scalar *timedata); + +void kiss_fftri2(kiss_fftr_cfg st,const kiss_fft_scalar *freqdata, kiss_fft_scalar *timedata); + +/* + input freqdata has nfft/2+1 complex points + output timedata has nfft scalar points +*/ + +#define kiss_fftr_free speex_free + +#ifdef __cplusplus +} +#endif +#endif diff --git a/ios/IOSDuoduo/Voice/Code/Libs/libspeex/lpc.c b/ios/IOSDuoduo/Voice/Code/Libs/libspeex/lpc.c new file mode 100755 index 000000000..fd5d3821e --- /dev/null +++ b/ios/IOSDuoduo/Voice/Code/Libs/libspeex/lpc.c @@ -0,0 +1,201 @@ +/* + Copyright 1992, 1993, 1994 by Jutta Degener and Carsten Bormann, + Technische Universitaet Berlin + + Any use of this software is permitted provided that this notice is not + removed and that neither the authors nor the Technische Universitaet Berlin + are deemed to have made any representations as to the suitability of this + software for any purpose nor are held responsible for any defects of + this software. THERE IS ABSOLUTELY NO WARRANTY FOR THIS SOFTWARE. + + As a matter of courtesy, the authors request to be informed about uses + this software has found, about bugs in this software, and about any + improvements that may be of general interest. + + Berlin, 28.11.1994 + Jutta Degener + Carsten Bormann + + + Code modified by Jean-Marc Valin + + Speex License: + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + - Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + - Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + - Neither the name of the Xiph.org Foundation nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR + CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "lpc.h" + +#ifdef BFIN_ASM +#include "lpc_bfin.h" +#endif + +/* LPC analysis + * + * The next two functions calculate linear prediction coefficients + * and/or the related reflection coefficients from the first P_MAX+1 + * values of the autocorrelation function. + */ + +/* Invented by N. Levinson in 1947, modified by J. Durbin in 1959. + */ + +/* returns minimum mean square error */ +spx_word32_t _spx_lpc( +spx_coef_t *lpc, /* out: [0...p-1] LPC coefficients */ +const spx_word16_t *ac, /* in: [0...p] autocorrelation values */ +int p +) +{ + int i, j; + spx_word16_t r; + spx_word16_t error = ac[0]; + + if (ac[0] == 0) + { + for (i = 0; i < p; i++) + lpc[i] = 0; + return 0; + } + + for (i = 0; i < p; i++) { + + /* Sum up this iteration's reflection coefficient */ + spx_word32_t rr = NEG32(SHL32(EXTEND32(ac[i + 1]),13)); + for (j = 0; j < i; j++) + rr = SUB32(rr,MULT16_16(lpc[j],ac[i - j])); +#ifdef FIXED_POINT + r = DIV32_16(rr+PSHR32(error,1),ADD16(error,8)); +#else + r = rr/(error+.003*ac[0]); +#endif + /* Update LPC coefficients and total error */ + lpc[i] = r; + for (j = 0; j < i>>1; j++) + { + spx_word16_t tmp = lpc[j]; + lpc[j] = MAC16_16_P13(lpc[j],r,lpc[i-1-j]); + lpc[i-1-j] = MAC16_16_P13(lpc[i-1-j],r,tmp); + } + if (i & 1) + lpc[j] = MAC16_16_P13(lpc[j],lpc[j],r); + + error = SUB16(error,MULT16_16_Q13(r,MULT16_16_Q13(error,r))); + } + return error; +} + + +#ifdef FIXED_POINT + +/* Compute the autocorrelation + * ,--, + * ac(i) = > x(n) * x(n-i) for all n + * `--' + * for lags between 0 and lag-1, and x == 0 outside 0...n-1 + */ + +#ifndef OVERRIDE_SPEEX_AUTOCORR +void _spx_autocorr( +const spx_word16_t *x, /* in: [0...n-1] samples x */ +spx_word16_t *ac, /* out: [0...lag-1] ac values */ +int lag, +int n +) +{ + spx_word32_t d; + int i, j; + spx_word32_t ac0=1; + int shift, ac_shift; + + for (j=0;j x(n) * x(n-i) for all n + * `--' + * for lags between 0 and lag-1, and x == 0 outside 0...n-1 + */ +void _spx_autocorr( +const spx_word16_t *x, /* in: [0...n-1] samples x */ +float *ac, /* out: [0...lag-1] ac values */ +int lag, +int n +) +{ + float d; + int i; + while (lag--) + { + for (i = lag, d = 0; i < n; i++) + d += x[i] * x[i-lag]; + ac[lag] = d; + } + ac[0] += 10; +} + +#endif + + diff --git a/ios/IOSDuoduo/Voice/Code/Libs/libspeex/lpc.h b/ios/IOSDuoduo/Voice/Code/Libs/libspeex/lpc.h new file mode 100755 index 000000000..952ecdd93 --- /dev/null +++ b/ios/IOSDuoduo/Voice/Code/Libs/libspeex/lpc.h @@ -0,0 +1,53 @@ +/* Copyright (C) 2002 Jean-Marc Valin */ +/** + @file lpc.h + @brief Functions for LPC (Linear Prediction Coefficients) analysis +*/ +/* + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + - Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + - Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + - Neither the name of the Xiph.org Foundation nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR + CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#ifndef LPC_H +#define LPC_H + +#include "arch.h" + +void _spx_autocorr( + const spx_word16_t * x, /* in: [0...n-1] samples x */ + spx_word16_t *ac, /* out: [0...lag-1] ac values */ + int lag, int n); + +spx_word32_t /* returns minimum mean square error */ +_spx_lpc( + spx_coef_t * lpc, /* [0...p-1] LPC coefficients */ + const spx_word16_t * ac, /* in: [0...p] autocorrelation values */ + int p + ); + + +#endif diff --git a/ios/IOSDuoduo/Voice/Code/Libs/libspeex/lpc_bfin.h b/ios/IOSDuoduo/Voice/Code/Libs/libspeex/lpc_bfin.h new file mode 100755 index 000000000..7310ffba5 --- /dev/null +++ b/ios/IOSDuoduo/Voice/Code/Libs/libspeex/lpc_bfin.h @@ -0,0 +1,131 @@ +/* Copyright (C) 2005 Analog Devices */ +/** + @file lpc_bfin.h + @author Jean-Marc Valin + @brief Functions for LPC (Linear Prediction Coefficients) analysis (Blackfin version) +*/ +/* + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + - Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + - Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + - Neither the name of the Xiph.org Foundation nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR + CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#define OVERRIDE_SPEEX_AUTOCORR +void _spx_autocorr( +const spx_word16_t *x, /* in: [0...n-1] samples x */ +spx_word16_t *ac, /* out: [0...lag-1] ac values */ +int lag, +int n + ) +{ + spx_word32_t d; + const spx_word16_t *xs; + int i, j; + spx_word32_t ac0=1; + spx_word32_t ac32[11], *ac32top; + int shift, ac_shift; + ac32top = ac32+lag-1; + int lag_1, N_lag; + int nshift; + lag_1 = lag-1; + N_lag = n-lag_1; + for (j=0;j> 1;\n\t" + "LOOP_BEGIN pitch%=;\n\t" + "I1 = P0;\n\t" + "A1 = A0 = 0;\n\t" + "R1 = [I1++];\n\t" + "LOOP inner_prod%= LC1 = P3 >> 1;\n\t" + "LOOP_BEGIN inner_prod%=;\n\t" + "A1 += R0.L*R1.H, A0 += R0.L*R1.L (IS) || R1.L = W[I1++];\n\t" + "A1 += R0.H*R1.L, A0 += R0.H*R1.H (IS) || R1.H = W[I1++] || R0 = [I0++];\n\t" + "LOOP_END inner_prod%=;\n\t" + "A0 = ASHIFT A0 by R4.L;\n\t" + "A1 = ASHIFT A1 by R4.L;\n\t" + + "R2 = A0, R3 = A1;\n\t" + "[P1--] = R2;\n\t" + "[P1--] = R3;\n\t" + "P0 += 4;\n\t" + "LOOP_END pitch%=;\n\t" + : : "m" (xs), "m" (x), "m" (ac32top), "m" (N_lag), "m" (lag_1), "m" (nshift) + : "A0", "A1", "P0", "P1", "P2", "P3", "P4", "R0", "R1", "R2", "R3", "R4", "I0", "I1", "L0", "L1", "B0", "B1", "memory" + ); + d=0; + for (j=0;j +#include "lsp.h" +#include "stack_alloc.h" +#include "math_approx.h" + +#ifndef M_PI +#define M_PI 3.14159265358979323846 /* pi */ +#endif + +#ifndef NULL +#define NULL 0 +#endif + +#ifdef FIXED_POINT + +#define FREQ_SCALE 16384 + +/*#define ANGLE2X(a) (32768*cos(((a)/8192.)))*/ +#define ANGLE2X(a) (SHL16(spx_cos(a),2)) + +/*#define X2ANGLE(x) (acos(.00006103515625*(x))*LSP_SCALING)*/ +#define X2ANGLE(x) (spx_acos(x)) + +#ifdef BFIN_ASM +#include "lsp_bfin.h" +#endif + +#else + +/*#define C1 0.99940307 +#define C2 -0.49558072 +#define C3 0.03679168*/ + +#define FREQ_SCALE 1. +#define ANGLE2X(a) (spx_cos(a)) +#define X2ANGLE(x) (acos(x)) + +#endif + + +/*---------------------------------------------------------------------------*\ + + FUNCTION....: cheb_poly_eva() + + AUTHOR......: David Rowe + DATE CREATED: 24/2/93 + + This function evaluates a series of Chebyshev polynomials + +\*---------------------------------------------------------------------------*/ + +#ifdef FIXED_POINT + +#ifndef OVERRIDE_CHEB_POLY_EVA +static inline spx_word32_t cheb_poly_eva( + spx_word16_t *coef, /* P or Q coefs in Q13 format */ + spx_word16_t x, /* cos of freq (-1.0 to 1.0) in Q14 format */ + int m, /* LPC order/2 */ + char *stack +) +{ + int i; + spx_word16_t b0, b1; + spx_word32_t sum; + + /*Prevents overflows*/ + if (x>16383) + x = 16383; + if (x<-16383) + x = -16383; + + /* Initialise values */ + b1=16384; + b0=x; + + /* Evaluate Chebyshev series formulation usin g iterative approach */ + sum = ADD32(EXTEND32(coef[m]), EXTEND32(MULT16_16_P14(coef[m-1],x))); + for(i=2;i<=m;i++) + { + spx_word16_t tmp=b0; + b0 = SUB16(MULT16_16_Q13(x,b0), b1); + b1 = tmp; + sum = ADD32(sum, EXTEND32(MULT16_16_P14(coef[m-i],b0))); + } + + return sum; +} +#endif + +#else + +static float cheb_poly_eva(spx_word32_t *coef, spx_word16_t x, int m, char *stack) +{ + int k; + float b0, b1, tmp; + + /* Initial conditions */ + b0=0; /* b_(m+1) */ + b1=0; /* b_(m+2) */ + + x*=2; + + /* Calculate the b_(k) */ + for(k=m;k>0;k--) + { + tmp=b0; /* tmp holds the previous value of b0 */ + b0=x*b0-b1+coef[m-k]; /* b0 holds its new value based on b0 and b1 */ + b1=tmp; /* b1 holds the previous value of b0 */ + } + + return(-b1+.5*x*b0+coef[m]); +} +#endif + +/*---------------------------------------------------------------------------*\ + + FUNCTION....: lpc_to_lsp() + + AUTHOR......: David Rowe + DATE CREATED: 24/2/93 + + This function converts LPC coefficients to LSP + coefficients. + +\*---------------------------------------------------------------------------*/ + +#ifdef FIXED_POINT +#define SIGN_CHANGE(a,b) (((a)&0x70000000)^((b)&0x70000000)||(b==0)) +#else +#define SIGN_CHANGE(a,b) (((a)*(b))<0.0) +#endif + + +int lpc_to_lsp (spx_coef_t *a,int lpcrdr,spx_lsp_t *freq,int nb,spx_word16_t delta, char *stack) +/* float *a lpc coefficients */ +/* int lpcrdr order of LPC coefficients (10) */ +/* float *freq LSP frequencies in the x domain */ +/* int nb number of sub-intervals (4) */ +/* float delta grid spacing interval (0.02) */ + + +{ + spx_word16_t temp_xr,xl,xr,xm=0; + spx_word32_t psuml,psumr,psumm,temp_psumr/*,temp_qsumr*/; + int i,j,m,flag,k; + VARDECL(spx_word32_t *Q); /* ptrs for memory allocation */ + VARDECL(spx_word32_t *P); + VARDECL(spx_word16_t *Q16); /* ptrs for memory allocation */ + VARDECL(spx_word16_t *P16); + spx_word32_t *px; /* ptrs of respective P'(z) & Q'(z) */ + spx_word32_t *qx; + spx_word32_t *p; + spx_word32_t *q; + spx_word16_t *pt; /* ptr used for cheb_poly_eval() + whether P' or Q' */ + int roots=0; /* DR 8/2/94: number of roots found */ + flag = 1; /* program is searching for a root when, + 1 else has found one */ + m = lpcrdr/2; /* order of P'(z) & Q'(z) polynomials */ + + /* Allocate memory space for polynomials */ + ALLOC(Q, (m+1), spx_word32_t); + ALLOC(P, (m+1), spx_word32_t); + + /* determine P'(z)'s and Q'(z)'s coefficients where + P'(z) = P(z)/(1 + z^(-1)) and Q'(z) = Q(z)/(1-z^(-1)) */ + + px = P; /* initialise ptrs */ + qx = Q; + p = px; + q = qx; + +#ifdef FIXED_POINT + *px++ = LPC_SCALING; + *qx++ = LPC_SCALING; + for(i=0;i=32768) + speex_warning_int("px", *px); + if (fabs(*qx)>=32768) + speex_warning_int("qx", *qx);*/ + *px = PSHR32(*px,2); + *qx = PSHR32(*qx,2); + px++; + qx++; + } + /* The reason for this lies in the way cheb_poly_eva() is implemented for fixed-point */ + P[m] = PSHR32(P[m],3); + Q[m] = PSHR32(Q[m],3); +#else + *px++ = LPC_SCALING; + *qx++ = LPC_SCALING; + for(i=0;i= -FREQ_SCALE)){ + spx_word16_t dd; + /* Modified by JMV to provide smaller steps around x=+-1 */ +#ifdef FIXED_POINT + dd = MULT16_16_Q15(delta,SUB16(FREQ_SCALE, MULT16_16_Q14(MULT16_16_Q14(xl,xl),14000))); + if (psuml<512 && psuml>-512) + dd = PSHR16(dd,1); +#else + dd=delta*(1-.9*xl*xl); + if (fabs(psuml)<.2) + dd *= .5; +#endif + xr = SUB16(xl, dd); /* interval spacing */ + psumr = cheb_poly_eva(pt,xr,m,stack);/* poly(xl-delta_x) */ + temp_psumr = psumr; + temp_xr = xr; + + /* if no sign change increment xr and re-evaluate poly(xr). Repeat til + sign change. + if a sign change has occurred the interval is bisected and then + checked again for a sign change which determines in which + interval the zero lies in. + If there is no sign change between poly(xm) and poly(xl) set interval + between xm and xr else set interval between xl and xr and repeat till + root is located within the specified limits */ + + if(SIGN_CHANGE(psumr,psuml)) + { + roots++; + + psumm=psuml; + for(k=0;k<=nb;k++){ +#ifdef FIXED_POINT + xm = ADD16(PSHR16(xl,1),PSHR16(xr,1)); /* bisect the interval */ +#else + xm = .5*(xl+xr); /* bisect the interval */ +#endif + psumm=cheb_poly_eva(pt,xm,m,stack); + /*if(psumm*psuml>0.)*/ + if(!SIGN_CHANGE(psumm,psuml)) + { + psuml=psumm; + xl=xm; + } else { + psumr=psumm; + xr=xm; + } + } + + /* once zero is found, reset initial interval to xr */ + freq[j] = X2ANGLE(xm); + xl = xm; + flag = 0; /* reset flag for next search */ + } + else{ + psuml=temp_psumr; + xl=temp_xr; + } + } + } + return(roots); +} + +/*---------------------------------------------------------------------------*\ + + FUNCTION....: lsp_to_lpc() + + AUTHOR......: David Rowe + DATE CREATED: 24/2/93 + + Converts LSP coefficients to LPC coefficients. + +\*---------------------------------------------------------------------------*/ + +#ifdef FIXED_POINT + +void lsp_to_lpc(spx_lsp_t *freq,spx_coef_t *ak,int lpcrdr, char *stack) +/* float *freq array of LSP frequencies in the x domain */ +/* float *ak array of LPC coefficients */ +/* int lpcrdr order of LPC coefficients */ +{ + int i,j; + spx_word32_t xout1,xout2,xin; + spx_word32_t mult, a; + VARDECL(spx_word16_t *freqn); + VARDECL(spx_word32_t **xp); + VARDECL(spx_word32_t *xpmem); + VARDECL(spx_word32_t **xq); + VARDECL(spx_word32_t *xqmem); + int m = lpcrdr>>1; + + /* + + Reconstruct P(z) and Q(z) by cascading second order polynomials + in form 1 - 2cos(w)z(-1) + z(-2), where w is the LSP frequency. + In the time domain this is: + + y(n) = x(n) - 2cos(w)x(n-1) + x(n-2) + + This is what the ALLOCS below are trying to do: + + int xp[m+1][lpcrdr+1+2]; // P matrix in QIMP + int xq[m+1][lpcrdr+1+2]; // Q matrix in QIMP + + These matrices store the output of each stage on each row. The + final (m-th) row has the output of the final (m-th) cascaded + 2nd order filter. The first row is the impulse input to the + system (not written as it is known). + + The version below takes advantage of the fact that a lot of the + outputs are zero or known, for example if we put an inpulse + into the first section the "clock" it 10 times only the first 3 + outputs samples are non-zero (it's an FIR filter). + */ + + ALLOC(xp, (m+1), spx_word32_t*); + ALLOC(xpmem, (m+1)*(lpcrdr+1+2), spx_word32_t); + + ALLOC(xq, (m+1), spx_word32_t*); + ALLOC(xqmem, (m+1)*(lpcrdr+1+2), spx_word32_t); + + for(i=0; i<=m; i++) { + xp[i] = xpmem + i*(lpcrdr+1+2); + xq[i] = xqmem + i*(lpcrdr+1+2); + } + + /* work out 2cos terms in Q14 */ + + ALLOC(freqn, lpcrdr, spx_word16_t); + for (i=0;i 32767) a = 32767; + ak[j-1] = (short)a; + + } + +} + +#else + +void lsp_to_lpc(spx_lsp_t *freq,spx_coef_t *ak,int lpcrdr, char *stack) +/* float *freq array of LSP frequencies in the x domain */ +/* float *ak array of LPC coefficients */ +/* int lpcrdr order of LPC coefficients */ + + +{ + int i,j; + float xout1,xout2,xin1,xin2; + VARDECL(float *Wp); + float *pw,*n1,*n2,*n3,*n4=NULL; + VARDECL(float *x_freq); + int m = lpcrdr>>1; + + ALLOC(Wp, 4*m+2, float); + pw = Wp; + + /* initialise contents of array */ + + for(i=0;i<=4*m+1;i++){ /* set contents of buffer to 0 */ + *pw++ = 0.0; + } + + /* Set pointers up */ + + pw = Wp; + xin1 = 1.0; + xin2 = 1.0; + + ALLOC(x_freq, lpcrdr, float); + for (i=0;i0) + ak[j-1] = (xout1 + xout2)*0.5f; + *(n4+1) = xin1; + *(n4+2) = xin2; + + xin1 = 0.0; + xin2 = 0.0; + } + +} +#endif + + +#ifdef FIXED_POINT + +/*Makes sure the LSPs are stable*/ +void lsp_enforce_margin(spx_lsp_t *lsp, int len, spx_word16_t margin) +{ + int i; + spx_word16_t m = margin; + spx_word16_t m2 = 25736-margin; + + if (lsp[0]m2) + lsp[len-1]=m2; + for (i=1;ilsp[i+1]-m) + lsp[i]= SHR16(lsp[i],1) + SHR16(lsp[i+1]-m,1); + } +} + + +void lsp_interpolate(spx_lsp_t *old_lsp, spx_lsp_t *new_lsp, spx_lsp_t *interp_lsp, int len, int subframe, int nb_subframes) +{ + int i; + spx_word16_t tmp = DIV32_16(SHL32(EXTEND32(1 + subframe),14),nb_subframes); + spx_word16_t tmp2 = 16384-tmp; + for (i=0;iLSP_SCALING*(M_PI-margin)) + lsp[len-1]=LSP_SCALING*(M_PI-margin); + for (i=1;ilsp[i+1]-LSP_SCALING*margin) + lsp[i]= .5f* (lsp[i] + lsp[i+1]-LSP_SCALING*margin); + } +} + + +void lsp_interpolate(spx_lsp_t *old_lsp, spx_lsp_t *new_lsp, spx_lsp_t *interp_lsp, int len, int subframe, int nb_subframes) +{ + int i; + float tmp = (1.0f + subframe)/nb_subframes; + for (i=0;i>>= 14;\n\t" + "R3 = R3 + R5;\n\t" + + "R0 = R2;\n\t" /* R0: b0 */ + "R1 = 16384;\n\t" /* R1: b1 */ + "LOOP cpe%= LC0 = %3;\n\t" + "LOOP_BEGIN cpe%=;\n\t" + "P1 = R0;\n\t" + "R0 = R2.L * R0.L (IS) || R5 = W[P0--] (X);\n\t" + "R0 >>>= 13;\n\t" + "R0 = R0 - R1;\n\t" + "R1 = P1;\n\t" + "R5 = R5.L * R0.L (IS);\n\t" + "R5 = R5 + R4;\n\t" + "R5 >>>= 14;\n\t" + "R3 = R3 + R5;\n\t" + "LOOP_END cpe%=;\n\t" + "%0 = R3;\n\t" + : "=&d" (sum) + : "a" (x), "a" (&coef[m]), "a" (m-1) + : "R0", "R1", "R3", "R2", "R4", "R5", "P0", "P1" + ); + return sum; +} +#endif + + + diff --git a/ios/IOSDuoduo/Voice/Code/Libs/libspeex/lsp_tables_nb.c b/ios/IOSDuoduo/Voice/Code/Libs/libspeex/lsp_tables_nb.c new file mode 100755 index 000000000..16f2e1b64 --- /dev/null +++ b/ios/IOSDuoduo/Voice/Code/Libs/libspeex/lsp_tables_nb.c @@ -0,0 +1,360 @@ +/* Copyright (C) 2002 Jean-Marc Valin + File: lsp_tables_nb.c + Codebooks for LSPs in narrowband CELP mode + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are + met: + + 1. Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + 3. The name of the author may not be used to endorse or promote products + derived from this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, + INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + POSSIBILITY OF SUCH DAMAGE. +*/ + +const signed char cdbk_nb[640]={ +30,19,38,34,40,32,46,43,58,43, +5,-18,-25,-40,-33,-55,-52,20,34,28, +-20,-63,-97,-92,61,53,47,49,53,75, +-14,-53,-77,-79,0,-3,-5,19,22,26, +-9,-53,-55,66,90,72,85,68,74,52, +-4,-41,-58,-31,-18,-31,27,32,30,18, +24,3,8,5,-12,-3,26,28,74,63, +-2,-39,-67,-77,-106,-74,59,59,73,65, +44,40,71,72,82,83,98,88,89,60, +-6,-31,-47,-48,-13,-39,-9,7,2,79, +-1,-39,-60,-17,87,81,65,50,45,19, +-21,-67,-91,-87,-41,-50,7,18,39,74, +10,-31,-28,39,24,13,23,5,56,45, +29,10,-5,-13,-11,-35,-18,-8,-10,-8, +-25,-71,-77,-21,2,16,50,63,87,87, +5,-32,-40,-51,-68,0,12,6,54,34, +5,-12,32,52,68,64,69,59,65,45, +14,-16,-31,-40,-65,-67,41,49,47,37, +-11,-52,-75,-84,-4,57,48,42,42,33, +-11,-51,-68,-6,13,0,8,-8,26,32, +-23,-53,0,36,56,76,97,105,111,97, +-1,-28,-39,-40,-43,-54,-44,-40,-18,35, +16,-20,-19,-28,-42,29,47,38,74,45, +3,-29,-48,-62,-80,-104,-33,56,59,59, +10,17,46,72,84,101,117,123,123,106, +-7,-33,-49,-51,-70,-67,-27,-31,70,67, +-16,-62,-85,-20,82,71,86,80,85,74, +-19,-58,-75,-45,-29,-33,-18,-25,45,57, +-12,-42,-5,12,28,36,52,64,81,82, +13,-9,-27,-28,22,3,2,22,26,6, +-6,-44,-51,2,15,10,48,43,49,34, +-19,-62,-84,-89,-102,-24,8,17,61,68, +39,24,23,19,16,-5,12,15,27,15, +-8,-44,-49,-60,-18,-32,-28,52,54,62, +-8,-48,-77,-70,66,101,83,63,61,37, +-12,-50,-75,-64,33,17,13,25,15,77, +1,-42,-29,72,64,46,49,31,61,44, +-8,-47,-54,-46,-30,19,20,-1,-16,0, +16,-12,-18,-9,-26,-27,-10,-22,53,45, +-10,-47,-75,-82,-105,-109,8,25,49,77, +50,65,114,117,124,118,115,96,90,61, +-9,-45,-63,-60,-75,-57,8,11,20,29, +0,-35,-49,-43,40,47,35,40,55,38, +-24,-76,-103,-112,-27,3,23,34,52,75, +8,-29,-43,12,63,38,35,29,24,8, +25,11,1,-15,-18,-43,-7,37,40,21, +-20,-56,-19,-19,-4,-2,11,29,51,63, +-2,-44,-62,-75,-89,30,57,51,74,51, +50,46,68,64,65,52,63,55,65,43, +18,-9,-26,-35,-55,-69,3,6,8,17, +-15,-61,-86,-97,1,86,93,74,78,67, +-1,-38,-66,-48,48,39,29,25,17,-1, +13,13,29,39,50,51,69,82,97,98, +-2,-36,-46,-27,-16,-30,-13,-4,-7,-4, +25,-5,-11,-6,-25,-21,33,12,31,29, +-8,-38,-52,-63,-68,-89,-33,-1,10,74, +-2,-15,59,91,105,105,101,87,84,62, +-7,-33,-50,-35,-54,-47,25,17,82,81, +-13,-56,-83,21,58,31,42,25,72,65, +-24,-66,-91,-56,9,-2,21,10,69,75, +2,-24,11,22,25,28,38,34,48,33, +7,-29,-26,17,15,-1,14,0,-2,0, +-6,-41,-67,6,-2,-9,19,2,85,74, +-22,-67,-84,-71,-50,3,11,-9,2,62}; + +const signed char cdbk_nb_low1[320]={ +-34,-52,-15,45,2, +23,21,52,24,-33, +-9,-1,9,-44,-41, +-13,-17,44,22,-17, +-6,-4,-1,22,38, +26,16,2,50,27, +-35,-34,-9,-41,6, +0,-16,-34,51,8, +-14,-31,-49,15,-33, +45,49,33,-11,-37, +-62,-54,45,11,-5, +-72,11,-1,-12,-11, +24,27,-11,-43,46, +43,33,-12,-9,-1, +1,-4,-23,-57,-71, +11,8,16,17,-8, +-20,-31,-41,53,48, +-16,3,65,-24,-8, +-23,-32,-37,-32,-49, +-10,-17,6,38,5, +-9,-17,-46,8,52, +3,6,45,40,39, +-7,-6,-34,-74,31, +8,1,-16,43,68, +-11,-19,-31,4,6, +0,-6,-17,-16,-38, +-16,-30,2,9,-39, +-16,-1,43,-10,48, +3,3,-16,-31,-3, +62,68,43,13,3, +-10,8,20,-56,12, +12,-2,-18,22,-15, +-40,-36,1,7,41, +0,1,46,-6,-62, +-4,-12,-2,-11,-83, +-13,-2,91,33,-10, +0,4,-11,-16,79, +32,37,14,9,51, +-21,-28,-56,-34,0, +21,9,-26,11,28, +-42,-54,-23,-2,-15, +31,30,8,-39,-66, +-39,-36,31,-28,-40, +-46,35,40,22,24, +33,48,23,-34,14, +40,32,17,27,-3, +25,26,-13,-61,-17, +11,4,31,60,-6, +-26,-41,-64,13,16, +-26,54,31,-11,-23, +-9,-11,-34,-71,-21, +-34,-35,55,50,29, +-22,-27,-50,-38,57, +33,42,57,48,26, +11,0,-49,-31,26, +-4,-14,5,78,37, +17,0,-49,-12,-23, +26,14,2,2,-43, +-17,-12,10,-8,-4, +8,18,12,-6,20, +-12,-6,-13,-25,34, +15,40,49,7,8, +13,20,20,-19,-22, +-2,-8,2,51,-51}; + +const signed char cdbk_nb_low2[320]={ +-6,53,-21,-24,4, +26,17,-4,-37,25, +17,-36,-13,31,3, +-6,27,15,-10,31, +28,26,-10,-10,-40, +16,-7,15,13,41, +-9,0,-4,50,-6, +-7,14,38,22,0, +-48,2,1,-13,-19, +32,-3,-60,11,-17, +-1,-24,-34,-1,35, +-5,-27,28,44,13, +25,15,42,-11,15, +51,35,-36,20,8, +-4,-12,-29,19,-47, +49,-15,-4,16,-29, +-39,14,-30,4,25, +-9,-5,-51,-14,-3, +-40,-32,38,5,-9, +-8,-4,-1,-22,71, +-3,14,26,-18,-22, +24,-41,-25,-24,6, +23,19,-10,39,-26, +-27,65,45,2,-7, +-26,-8,22,-12,16, +15,16,-35,-5,33, +-21,-8,0,23,33, +34,6,21,36,6, +-7,-22,8,-37,-14, +31,38,11,-4,-3, +-39,-32,-8,32,-23, +-6,-12,16,20,-28, +-4,23,13,-52,-1, +22,6,-33,-40,-6, +4,-62,13,5,-26, +35,39,11,2,57, +-11,9,-20,-28,-33, +52,-5,-6,-2,22, +-14,-16,-48,35,1, +-58,20,13,33,-1, +-74,56,-18,-22,-31, +12,6,-14,4,-2, +-9,-47,10,-3,29, +-17,-5,61,14,47, +-12,2,72,-39,-17, +92,64,-53,-51,-15, +-30,-38,-41,-29,-28, +27,9,36,9,-35, +-42,81,-21,20,25, +-16,-5,-17,-35,21, +15,-28,48,2,-2, +9,-19,29,-40,30, +-18,-18,18,-16,-57, +15,-20,-12,-15,-37, +-15,33,-39,21,-22, +-13,35,11,13,-38, +-63,29,23,-27,32, +18,3,-26,42,33, +-64,-66,-17,16,56, +2,36,3,31,21, +-41,-39,8,-57,14, +37,-2,19,-36,-19, +-23,-29,-16,1,-3, +-8,-10,31,64,-65}; + +const signed char cdbk_nb_high1[320]={ +-26,-8,29,21,4, +19,-39,33,-7,-36, +56,54,48,40,29, +-4,-24,-42,-66,-43, +-60,19,-2,37,41, +-10,-37,-60,-64,18, +-22,77,73,40,25, +4,19,-19,-66,-2, +11,5,21,14,26, +-25,-86,-4,18,1, +26,-37,10,37,-1, +24,-12,-59,-11,20, +-6,34,-16,-16,42, +19,-28,-51,53,32, +4,10,62,21,-12, +-34,27,4,-48,-48, +-50,-49,31,-7,-21, +-42,-25,-4,-43,-22, +59,2,27,12,-9, +-6,-16,-8,-32,-58, +-16,-29,-5,41,23, +-30,-33,-46,-13,-10, +-38,52,52,1,-17, +-9,10,26,-25,-6, +33,-20,53,55,25, +-32,-5,-42,23,21, +66,5,-28,20,9, +75,29,-7,-42,-39, +15,3,-23,21,6, +11,1,-29,14,63, +10,54,26,-24,-51, +-49,7,-23,-51,15, +-66,1,60,25,10, +0,-30,-4,-15,17, +19,59,40,4,-5, +33,6,-22,-58,-70, +-5,23,-6,60,44, +-29,-16,-47,-29,52, +-19,50,28,16,35, +31,36,0,-21,6, +21,27,22,42,7, +-66,-40,-8,7,19, +46,0,-4,60,36, +45,-7,-29,-6,-32, +-39,2,6,-9,33, +20,-51,-34,18,-6, +19,6,11,5,-19, +-29,-2,42,-11,-45, +-21,-55,57,37,2, +-14,-67,-16,-27,-38, +69,48,19,2,-17, +20,-20,-16,-34,-17, +-25,-61,10,73,45, +16,-40,-64,-17,-29, +-22,56,17,-39,8, +-11,8,-25,-18,-13, +-19,8,54,57,36, +-17,-26,-4,6,-21, +40,42,-4,20,31, +53,10,-34,-53,31, +-17,35,0,15,-6, +-20,-63,-73,22,25, +29,17,8,-29,-39, +-69,18,15,-15,-5}; + +const signed char cdbk_nb_high2[320]={ +11,47,16,-9,-46, +-32,26,-64,34,-5, +38,-7,47,20,2, +-73,-99,-3,-45,20, +70,-52,15,-6,-7, +-82,31,21,47,51, +39,-3,9,0,-41, +-7,-15,-54,2,0, +27,-31,9,-45,-22, +-38,-24,-24,8,-33, +23,5,50,-36,-17, +-18,-51,-2,13,19, +43,12,-15,-12,61, +38,38,7,13,0, +6,-1,3,62,9, +27,22,-33,38,-35, +-9,30,-43,-9,-32, +-1,4,-4,1,-5, +-11,-8,38,31,11, +-10,-42,-21,-37,1, +43,15,-13,-35,-19, +-18,15,23,-26,59, +1,-21,53,8,-41, +-50,-14,-28,4,21, +25,-28,-40,5,-40, +-41,4,51,-33,-8, +-8,1,17,-60,12, +25,-41,17,34,43, +19,45,7,-37,24, +-15,56,-2,35,-10, +48,4,-47,-2,5, +-5,-54,5,-3,-33, +-10,30,-2,-44,-24, +-38,9,-9,42,4, +6,-56,44,-16,9, +-40,-26,18,-20,10, +28,-41,-21,-4,13, +-18,32,-30,-3,37, +15,22,28,50,-40, +3,-29,-64,7,51, +-19,-11,17,-27,-40, +-64,24,-12,-7,-27, +3,37,48,-1,2, +-9,-38,-34,46,1, +27,-6,19,-13,26, +10,34,20,25,40, +50,-6,-7,30,9, +-24,0,-23,71,-61, +22,58,-34,-4,2, +-49,-33,25,30,-8, +-6,-16,77,2,38, +-8,-35,-6,-30,56, +78,31,33,-20,13, +-39,20,22,4,21, +-8,4,-6,10,-83, +-41,9,-25,-43,15, +-7,-12,-34,-39,-37, +-33,19,30,16,-33, +42,-25,25,-68,44, +-15,-11,-4,23,50, +14,4,-39,-43,20, +-30,60,9,-20,7, +16,19,-33,37,29, +16,-35,7,38,-27}; diff --git a/ios/IOSDuoduo/Voice/Code/Libs/libspeex/ltp.c b/ios/IOSDuoduo/Voice/Code/Libs/libspeex/ltp.c new file mode 100755 index 000000000..a8c051c1c --- /dev/null +++ b/ios/IOSDuoduo/Voice/Code/Libs/libspeex/ltp.c @@ -0,0 +1,839 @@ +/* Copyright (C) 2002-2006 Jean-Marc Valin + File: ltp.c + Long-Term Prediction functions + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + - Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + - Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + - Neither the name of the Xiph.org Foundation nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR + CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include +#include "ltp.h" +#include "stack_alloc.h" +#include "filters.h" +#include "speex/speex_bits.h" +#include "math_approx.h" +#include "os_support.h" + +#ifndef NULL +#define NULL 0 +#endif + + +#ifdef _USE_SSE +#include "ltp_sse.h" +#elif defined (ARM4_ASM) || defined(ARM5E_ASM) +#include "ltp_arm4.h" +#elif defined (BFIN_ASM) +#include "ltp_bfin.h" +#endif + +#ifndef OVERRIDE_INNER_PROD +spx_word32_t inner_prod(const spx_word16_t *x, const spx_word16_t *y, int len) +{ + spx_word32_t sum=0; + len >>= 2; + while(len--) + { + spx_word32_t part=0; + part = MAC16_16(part,*x++,*y++); + part = MAC16_16(part,*x++,*y++); + part = MAC16_16(part,*x++,*y++); + part = MAC16_16(part,*x++,*y++); + /* HINT: If you had a 40-bit accumulator, you could shift only at the end */ + sum = ADD32(sum,SHR32(part,6)); + } + return sum; +} +#endif + +#ifndef OVERRIDE_PITCH_XCORR +#if 0 /* HINT: Enable this for machines with enough registers (i.e. not x86) */ +void pitch_xcorr(const spx_word16_t *_x, const spx_word16_t *_y, spx_word32_t *corr, int len, int nb_pitch, char *stack) +{ + int i,j; + for (i=0;i16383) + { + scaledown=1; + break; + } + } + /* If the weighted input is close to saturation, then we scale it down */ + if (scaledown) + { + for (i=-end;iMULT16_16(best_score[N-1],ADD16(1,ener16[i-start]))) + { + /* We can safely put it last and then check */ + best_score[N-1]=tmp; + best_ener[N-1]=ener16[i-start]+1; + pitch[N-1]=i; + /* Check if it comes in front of others */ + for (j=0;jMULT16_16(best_score[j],ADD16(1,ener16[i-start]))) + { + for (k=N-1;k>j;k--) + { + best_score[k]=best_score[k-1]; + best_ener[k]=best_ener[k-1]; + pitch[k]=pitch[k-1]; + } + best_score[j]=tmp; + best_ener[j]=ener16[i-start]+1; + pitch[j]=i; + break; + } + } + } + } + + /* Compute open-loop gain if necessary */ + if (gain) + { + for (j=0;jbest_sum && gain_sum<=max_gain) { + best_sum=sum; + best_cdbk=i; + } + } + + return best_cdbk; +} +#endif + +/** Finds the best quantized 3-tap pitch predictor by analysis by synthesis */ +static spx_word32_t pitch_gain_search_3tap( +const spx_word16_t target[], /* Target vector */ +const spx_coef_t ak[], /* LPCs for this subframe */ +const spx_coef_t awk1[], /* Weighted LPCs #1 for this subframe */ +const spx_coef_t awk2[], /* Weighted LPCs #2 for this subframe */ +spx_sig_t exc[], /* Excitation */ +const signed char *gain_cdbk, +int gain_cdbk_size, +int pitch, /* Pitch value */ +int p, /* Number of LPC coeffs */ +int nsf, /* Number of samples in subframe */ +SpeexBits *bits, +char *stack, +const spx_word16_t *exc2, +const spx_word16_t *r, +spx_word16_t *new_target, +int *cdbk_index, +int plc_tuning, +spx_word32_t cumul_gain, +int scaledown +) +{ + int i,j; + VARDECL(spx_word16_t *tmp1); + VARDECL(spx_word16_t *e); + spx_word16_t *x[3]; + spx_word32_t corr[3]; + spx_word32_t A[3][3]; + spx_word16_t gain[3]; + spx_word32_t err; + spx_word16_t max_gain=128; + int best_cdbk=0; + + ALLOC(tmp1, 3*nsf, spx_word16_t); + ALLOC(e, nsf, spx_word16_t); + + if (cumul_gain > 262144) + max_gain = 31; + + x[0]=tmp1; + x[1]=tmp1+nsf; + x[2]=tmp1+2*nsf; + + for (j=0;j=0;i--) + { + spx_word16_t e0=exc2[-pitch-1+i]; +#ifdef FIXED_POINT + /* Scale excitation down if needed (avoiding overflow) */ + if (scaledown) + e0 = SHR16(e0,1); +#endif + x[i][0]=MULT16_16_Q14(r[0], e0); + for (j=0;j30) + plc_tuning=30; +#ifdef FIXED_POINT + C[0] = SHL32(C[0],1); + C[1] = SHL32(C[1],1); + C[2] = SHL32(C[2],1); + C[3] = SHL32(C[3],1); + C[4] = SHL32(C[4],1); + C[5] = SHL32(C[5],1); + C[6] = MAC16_32_Q15(C[6],MULT16_16_16(plc_tuning,655),C[6]); + C[7] = MAC16_32_Q15(C[7],MULT16_16_16(plc_tuning,655),C[7]); + C[8] = MAC16_32_Q15(C[8],MULT16_16_16(plc_tuning,655),C[8]); + normalize16(C, C16, 32767, 9); +#else + C[6]*=.5*(1+.02*plc_tuning); + C[7]*=.5*(1+.02*plc_tuning); + C[8]*=.5*(1+.02*plc_tuning); +#endif + + best_cdbk = pitch_gain_search_3tap_vq(gain_cdbk, gain_cdbk_size, C16, max_gain); + +#ifdef FIXED_POINT + gain[0] = ADD16(32,(spx_word16_t)gain_cdbk[best_cdbk*4]); + gain[1] = ADD16(32,(spx_word16_t)gain_cdbk[best_cdbk*4+1]); + gain[2] = ADD16(32,(spx_word16_t)gain_cdbk[best_cdbk*4+2]); + /*printf ("%d %d %d %d\n",gain[0],gain[1],gain[2], best_cdbk);*/ +#else + gain[0] = 0.015625*gain_cdbk[best_cdbk*4] + .5; + gain[1] = 0.015625*gain_cdbk[best_cdbk*4+1]+ .5; + gain[2] = 0.015625*gain_cdbk[best_cdbk*4+2]+ .5; +#endif + *cdbk_index=best_cdbk; + } + + SPEEX_MEMSET(exc, 0, nsf); + for (i=0;i<3;i++) + { + int j; + int tmp1, tmp3; + int pp=pitch+1-i; + tmp1=nsf; + if (tmp1>pp) + tmp1=pp; + for (j=0;jpp+pitch) + tmp3=pp+pitch; + for (j=tmp1;jgain_bits; + gain_cdbk = params->gain_cdbk + 4*gain_cdbk_size*cdbk_offset; + + N=complexity; + if (N>10) + N=10; + if (N<1) + N=1; + + ALLOC(nbest, N, int); + params = (const ltp_params*) par; + + if (endpitch_bits); + speex_bits_pack(bits, 0, params->gain_bits); + SPEEX_MEMSET(exc, 0, nsf); + return start; + } + +#ifdef FIXED_POINT + /* Check if we need to scale everything down in the pitch search to avoid overflows */ + for (i=0;i16383) + { + scaledown=1; + break; + } + } + for (i=-end;i16383) + { + scaledown=1; + break; + } + } +#endif + if (N>end-start+1) + N=end-start+1; + if (end != start) + open_loop_nbest_pitch(sw, start, end, nsf, nbest, NULL, N, stack); + else + nbest[0] = start; + + ALLOC(best_exc, nsf, spx_sig_t); + ALLOC(new_target, nsf, spx_word16_t); + ALLOC(best_target, nsf, spx_word16_t); + + for (i=0;ipitch_bits); + speex_bits_pack(bits, best_gain_index, params->gain_bits); +#ifdef FIXED_POINT + *cumul_gain = MULT16_32_Q13(SHL16(params->gain_cdbk[4*best_gain_index+3],8), MAX32(1024,*cumul_gain)); +#else + *cumul_gain = 0.03125*MAX32(1024,*cumul_gain)*params->gain_cdbk[4*best_gain_index+3]; +#endif + /*printf ("%f\n", cumul_gain);*/ + /*printf ("encode pitch: %d %d\n", best_pitch, best_gain_index);*/ + SPEEX_COPY(exc, best_exc, nsf); + SPEEX_COPY(target, best_target, nsf); +#ifdef FIXED_POINT + /* Scale target back up if needed */ + if (scaledown) + { + for (i=0;igain_bits; + gain_cdbk = params->gain_cdbk + 4*gain_cdbk_size*cdbk_offset; + + pitch = speex_bits_unpack_unsigned(bits, params->pitch_bits); + pitch += start; + gain_index = speex_bits_unpack_unsigned(bits, params->gain_bits); + /*printf ("decode pitch: %d %d\n", pitch, gain_index);*/ +#ifdef FIXED_POINT + gain[0] = ADD16(32,(spx_word16_t)gain_cdbk[gain_index*4]); + gain[1] = ADD16(32,(spx_word16_t)gain_cdbk[gain_index*4+1]); + gain[2] = ADD16(32,(spx_word16_t)gain_cdbk[gain_index*4+2]); +#else + gain[0] = 0.015625*gain_cdbk[gain_index*4]+.5; + gain[1] = 0.015625*gain_cdbk[gain_index*4+1]+.5; + gain[2] = 0.015625*gain_cdbk[gain_index*4+2]+.5; +#endif + + if (count_lost && pitch > subframe_offset) + { + spx_word16_t gain_sum; + if (1) { +#ifdef FIXED_POINT + spx_word16_t tmp = count_lost < 4 ? last_pitch_gain : SHR16(last_pitch_gain,1); + if (tmp>62) + tmp=62; +#else + spx_word16_t tmp = count_lost < 4 ? last_pitch_gain : 0.5 * last_pitch_gain; + if (tmp>.95) + tmp=.95; +#endif + gain_sum = gain_3tap_to_1tap(gain); + + if (gain_sum > tmp) + { + spx_word16_t fact = DIV32_16(SHL32(EXTEND32(tmp),14),gain_sum); + for (i=0;i<3;i++) + gain[i]=MULT16_16_Q14(fact,gain[i]); + } + + } + + } + + *pitch_val = pitch; + gain_val[0]=gain[0]; + gain_val[1]=gain[1]; + gain_val[2]=gain[2]; + gain[0] = SHL16(gain[0],7); + gain[1] = SHL16(gain[1],7); + gain[2] = SHL16(gain[2],7); + SPEEX_MEMSET(exc_out, 0, nsf); + for (i=0;i<3;i++) + { + int j; + int tmp1, tmp3; + int pp=pitch+1-i; + tmp1=nsf; + if (tmp1>pp) + tmp1=pp; + for (j=0;jpp+pitch) + tmp3=pp+pitch; + for (j=tmp1;j63) + pitch_coef=63; +#else + if (pitch_coef>.99) + pitch_coef=.99; +#endif + for (i=0;i63) + pitch_coef=63; +#else + if (pitch_coef>.99) + pitch_coef=.99; +#endif + for (i=0;i0 ? g[0] : -SHR16(g[0],1)) + (g[2]>0 ? g[2] : -SHR16(g[2],1))) +#else +#define gain_3tap_to_1tap(g) (ABS(g[1]) + (g[0]>0 ? g[0] : -.5*g[0]) + (g[2]>0 ? g[2] : -.5*g[2])) +#endif + +spx_word32_t inner_prod(const spx_word16_t *x, const spx_word16_t *y, int len); +void pitch_xcorr(const spx_word16_t *_x, const spx_word16_t *_y, spx_word32_t *corr, int len, int nb_pitch, char *stack); + +void open_loop_nbest_pitch(spx_word16_t *sw, int start, int end, int len, int *pitch, spx_word16_t *gain, int N, char *stack); + + +/** Finds the best quantized 3-tap pitch predictor by analysis by synthesis */ +int pitch_search_3tap( +spx_word16_t target[], /* Target vector */ +spx_word16_t *sw, +spx_coef_t ak[], /* LPCs for this subframe */ +spx_coef_t awk1[], /* Weighted LPCs #1 for this subframe */ +spx_coef_t awk2[], /* Weighted LPCs #2 for this subframe */ +spx_sig_t exc[], /* Overlapping codebook */ +const void *par, +int start, /* Smallest pitch value allowed */ +int end, /* Largest pitch value allowed */ +spx_word16_t pitch_coef, /* Voicing (pitch) coefficient */ +int p, /* Number of LPC coeffs */ +int nsf, /* Number of samples in subframe */ +SpeexBits *bits, +char *stack, +spx_word16_t *exc2, +spx_word16_t *r, +int complexity, +int cdbk_offset, +int plc_tuning, +spx_word32_t *cumul_gain +); + +/*Unquantize adaptive codebook and update pitch contribution*/ +void pitch_unquant_3tap( +spx_word16_t exc[], /* Input excitation */ +spx_word32_t exc_out[], /* Output excitation */ +int start, /* Smallest pitch value allowed */ +int end, /* Largest pitch value allowed */ +spx_word16_t pitch_coef, /* Voicing (pitch) coefficient */ +const void *par, +int nsf, /* Number of samples in subframe */ +int *pitch_val, +spx_word16_t *gain_val, +SpeexBits *bits, +char *stack, +int lost, +int subframe_offset, +spx_word16_t last_pitch_gain, +int cdbk_offset +); + +/** Forced pitch delay and gain */ +int forced_pitch_quant( +spx_word16_t target[], /* Target vector */ +spx_word16_t *sw, +spx_coef_t ak[], /* LPCs for this subframe */ +spx_coef_t awk1[], /* Weighted LPCs #1 for this subframe */ +spx_coef_t awk2[], /* Weighted LPCs #2 for this subframe */ +spx_sig_t exc[], /* Excitation */ +const void *par, +int start, /* Smallest pitch value allowed */ +int end, /* Largest pitch value allowed */ +spx_word16_t pitch_coef, /* Voicing (pitch) coefficient */ +int p, /* Number of LPC coeffs */ +int nsf, /* Number of samples in subframe */ +SpeexBits *bits, +char *stack, +spx_word16_t *exc2, +spx_word16_t *r, +int complexity, +int cdbk_offset, +int plc_tuning, +spx_word32_t *cumul_gain +); + +/** Unquantize forced pitch delay and gain */ +void forced_pitch_unquant( +spx_word16_t exc[], /* Input excitation */ +spx_word32_t exc_out[], /* Output excitation */ +int start, /* Smallest pitch value allowed */ +int end, /* Largest pitch value allowed */ +spx_word16_t pitch_coef, /* Voicing (pitch) coefficient */ +const void *par, +int nsf, /* Number of samples in subframe */ +int *pitch_val, +spx_word16_t *gain_val, +SpeexBits *bits, +char *stack, +int lost, +int subframe_offset, +spx_word16_t last_pitch_gain, +int cdbk_offset +); diff --git a/ios/IOSDuoduo/Voice/Code/Libs/libspeex/ltp_arm4.h b/ios/IOSDuoduo/Voice/Code/Libs/libspeex/ltp_arm4.h new file mode 100755 index 000000000..cdb94e603 --- /dev/null +++ b/ios/IOSDuoduo/Voice/Code/Libs/libspeex/ltp_arm4.h @@ -0,0 +1,187 @@ +/* Copyright (C) 2004 Jean-Marc Valin */ +/** + @file ltp_arm4.h + @brief Long-Term Prediction functions (ARM4 version) +*/ +/* + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + - Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + - Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + - Neither the name of the Xiph.org Foundation nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR + CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#define OVERRIDE_INNER_PROD +spx_word32_t inner_prod(const spx_word16_t *x, const spx_word16_t *y, int len) +{ + spx_word32_t sum1=0,sum2=0; + spx_word16_t *deadx, *deady; + int deadlen, dead1, dead2, dead3, dead4, dead5, dead6; + __asm__ __volatile__ ( + "\tldrsh %5, [%0], #2 \n" + "\tldrsh %6, [%1], #2 \n" + ".inner_prod_loop%=:\n" + "\tsub %7, %7, %7\n" + "\tsub %10, %10, %10\n" + + "\tldrsh %8, [%0], #2 \n" + "\tldrsh %9, [%1], #2 \n" + "\tmla %7, %5, %6, %7\n" + "\tldrsh %5, [%0], #2 \n" + "\tldrsh %6, [%1], #2 \n" + "\tmla %10, %8, %9, %10\n" + "\tldrsh %8, [%0], #2 \n" + "\tldrsh %9, [%1], #2 \n" + "\tmla %7, %5, %6, %7\n" + "\tldrsh %5, [%0], #2 \n" + "\tldrsh %6, [%1], #2 \n" + "\tmla %10, %8, %9, %10\n" + + "\tldrsh %8, [%0], #2 \n" + "\tldrsh %9, [%1], #2 \n" + "\tmla %7, %5, %6, %7\n" + "\tldrsh %5, [%0], #2 \n" + "\tldrsh %6, [%1], #2 \n" + "\tmla %10, %8, %9, %10\n" + "\tldrsh %8, [%0], #2 \n" + "\tldrsh %9, [%1], #2 \n" + "\tmla %7, %5, %6, %7\n" + "\tldrsh %5, [%0], #2 \n" + "\tldrsh %6, [%1], #2 \n" + "\tmla %10, %8, %9, %10\n" + + "\tsubs %4, %4, #1\n" + "\tadd %2, %2, %7, asr #5\n" + "\tadd %3, %3, %10, asr #5\n" + "\tbne .inner_prod_loop%=\n" + : "=r" (deadx), "=r" (deady), "+r" (sum1), "+r" (sum2), + "=r" (deadlen), "=r" (dead1), "=r" (dead2), "=r" (dead3), + "=r" (dead4), "=r" (dead5), "=r" (dead6) + : "0" (x), "1" (y), "4" (len>>3) + : "cc" + ); + return (sum1+sum2)>>1; +} + +#define OVERRIDE_PITCH_XCORR +void pitch_xcorr(const spx_word16_t *_x, const spx_word16_t *_y, spx_word32_t *corr, int len, int nb_pitch, char *stack) +{ + int i,j; + for (i=0;i>> 6;\n\t" + "R0 = A0;\n\t" + "%0 = R0;\n\t" + : "=m" (sum) + : "m" (x), "m" (y), "d" (len-1) + : "P0", "P1", "P2", "R0", "R1", "A0", "I0", "I1", "L0", "L1", "R3" + ); + return sum; +} + +#define OVERRIDE_PITCH_XCORR +void pitch_xcorr(const spx_word16_t *_x, const spx_word16_t *_y, spx_word32_t *corr, int len, int nb_pitch, char *stack) +{ + corr += nb_pitch - 1; + __asm__ __volatile__ ( + "P2 = %0;\n\t" + "I0 = P2;\n\t" /* x in I0 */ + "B0 = P2;\n\t" /* x in B0 */ + "R0 = %3;\n\t" /* len in R0 */ + "P3 = %3;\n\t" + "P3 += -2;\n\t" /* len in R0 */ + "P4 = %4;\n\t" /* nb_pitch in R0 */ + "R1 = R0 << 1;\n\t" /* number of bytes in x */ + "L0 = R1;\n\t" + "P0 = %1;\n\t" + + "P1 = %2;\n\t" + "B1 = P1;\n\t" + "L1 = 0;\n\t" /*Disable looping on I1*/ + + "r0 = [I0++];\n\t" + "LOOP pitch%= LC0 = P4 >> 1;\n\t" + "LOOP_BEGIN pitch%=;\n\t" + "I1 = P0;\n\t" + "A1 = A0 = 0;\n\t" + "R1 = [I1++];\n\t" + "LOOP inner_prod%= LC1 = P3 >> 1;\n\t" + "LOOP_BEGIN inner_prod%=;\n\t" + "A1 += R0.L*R1.H, A0 += R0.L*R1.L (IS) || R1.L = W[I1++];\n\t" + "A1 += R0.H*R1.L, A0 += R0.H*R1.H (IS) || R1.H = W[I1++] || R0 = [I0++];\n\t" + "LOOP_END inner_prod%=;\n\t" + "A1 += R0.L*R1.H, A0 += R0.L*R1.L (IS) || R1.L = W[I1++];\n\t" + "A1 += R0.H*R1.L, A0 += R0.H*R1.H (IS) || R0 = [I0++];\n\t" + "A0 = A0 >>> 6;\n\t" + "A1 = A1 >>> 6;\n\t" + "R2 = A0, R3 = A1;\n\t" + "[P1--] = r2;\n\t" + "[P1--] = r3;\n\t" + "P0 += 4;\n\t" + "LOOP_END pitch%=;\n\t" + "L0 = 0;\n\t" + : : "m" (_x), "m" (_y), "m" (corr), "m" (len), "m" (nb_pitch) + : "A0", "A1", "P0", "P1", "P2", "P3", "P4", "R0", "R1", "R2", "R3", "I0", "I1", "L0", "L1", "B0", "B1", "memory" + ); +} + +#define OVERRIDE_COMPUTE_PITCH_ERROR +static inline spx_word32_t compute_pitch_error(spx_word16_t *C, spx_word16_t *g, spx_word16_t pitch_control) +{ + spx_word32_t sum; + __asm__ __volatile__ + ( + "A0 = 0;\n\t" + + "R0 = W[%1++];\n\t" + "R1.L = %2.L*%5.L (IS);\n\t" + "A0 += R1.L*R0.L (IS) || R0 = W[%1++];\n\t" + + "R1.L = %3.L*%5.L (IS);\n\t" + "A0 += R1.L*R0.L (IS) || R0 = W[%1++];\n\t" + + "R1.L = %4.L*%5.L (IS);\n\t" + "A0 += R1.L*R0.L (IS) || R0 = W[%1++];\n\t" + + "R1.L = %2.L*%3.L (IS);\n\t" + "A0 -= R1.L*R0.L (IS) || R0 = W[%1++];\n\t" + + "R1.L = %4.L*%3.L (IS);\n\t" + "A0 -= R1.L*R0.L (IS) || R0 = W[%1++];\n\t" + + "R1.L = %4.L*%2.L (IS);\n\t" + "A0 -= R1.L*R0.L (IS) || R0 = W[%1++];\n\t" + + "R1.L = %2.L*%2.L (IS);\n\t" + "A0 -= R1.L*R0.L (IS) || R0 = W[%1++];\n\t" + + "R1.L = %3.L*%3.L (IS);\n\t" + "A0 -= R1.L*R0.L (IS) || R0 = W[%1++];\n\t" + + "R1.L = %4.L*%4.L (IS);\n\t" + "A0 -= R1.L*R0.L (IS);\n\t" + + "%0 = A0;\n\t" + : "=&D" (sum), "=a" (C) + : "d" (g[0]), "d" (g[1]), "d" (g[2]), "d" (pitch_control), "1" (C) + : "R0", "R1", "R2", "A0" + ); + return sum; +} + +#define OVERRIDE_OPEN_LOOP_NBEST_PITCH +#ifdef OVERRIDE_OPEN_LOOP_NBEST_PITCH +void open_loop_nbest_pitch(spx_word16_t *sw, int start, int end, int len, int *pitch, spx_word16_t *gain, int N, char *stack) +{ + int i,j,k; + VARDECL(spx_word32_t *best_score); + VARDECL(spx_word32_t *best_ener); + spx_word32_t e0; + VARDECL(spx_word32_t *corr); + VARDECL(spx_word32_t *energy); + + ALLOC(best_score, N, spx_word32_t); + ALLOC(best_ener, N, spx_word32_t); + ALLOC(corr, end-start+1, spx_word32_t); + ALLOC(energy, end-start+2, spx_word32_t); + + for (i=0;i>>= 6;\n\t" +" R1 = R1 + R2;\n\t" +" R0 >>>= 6;\n\t" +" R1 = R1 - R0;\n\t" +" R2 = MAX(R1,R3);\n\t" +"eu2: [P0++] = R2;\n\t" + : : "d" (energy), "d" (&sw[-start-1]), "d" (&sw[-start+len-1]), + "a" (end-start) + : "P0", "I1", "I2", "R0", "R1", "R2", "R3" +#if (__GNUC__ == 4) + , "LC1" +#endif + ); + + pitch_xcorr(sw, sw-end, corr, len, end-start+1, stack); + + /* FIXME: Fixed-point and floating-point code should be merged */ + { + VARDECL(spx_word16_t *corr16); + VARDECL(spx_word16_t *ener16); + ALLOC(corr16, end-start+1, spx_word16_t); + ALLOC(ener16, end-start+1, spx_word16_t); + /* Normalize to 180 so we can square it and it still fits in 16 bits */ + normalize16(corr, corr16, 180, end-start+1); + normalize16(energy, ener16, 180, end-start+1); + + if (N == 1) { + /* optimised asm to handle N==1 case */ + __asm__ __volatile__ + ( +" I0 = %1;\n\t" /* I0: corr16[] */ +" L0 = 0;\n\t" +" I1 = %2;\n\t" /* I1: energy */ +" L1 = 0;\n\t" +" R2 = -1;\n\t" /* R2: best score */ +" R3 = 0;\n\t" /* R3: best energy */ +" P0 = %4;\n\t" /* P0: best pitch */ +" P1 = %4;\n\t" /* P1: counter */ +" LSETUP (sl1, sl2) LC1 = %3;\n\t" +"sl1: R0.L = W [I0++] || R1.L = W [I1++];\n\t" +" R0 = R0.L * R0.L (IS);\n\t" +" R1 += 1;\n\t" +" R4 = R0.L * R3.L;\n\t" +" R5 = R2.L * R1.L;\n\t" +" cc = R5 < R4;\n\t" +" if cc R2 = R0;\n\t" +" if cc R3 = R1;\n\t" +" if cc P0 = P1;\n\t" +"sl2: P1 += 1;\n\t" +" %0 = P0;\n\t" + : "=&d" (pitch[0]) + : "a" (corr16), "a" (ener16), "a" (end+1-start), "d" (start) + : "P0", "P1", "I0", "I1", "R0", "R1", "R2", "R3", "R4", "R5" +#if (__GNUC__ == 4) + , "LC1" +#endif + ); + + } + else { + for (i=start;i<=end;i++) + { + spx_word16_t tmp = MULT16_16_16(corr16[i-start],corr16[i-start]); + /* Instead of dividing the tmp by the energy, we multiply on the other side */ + if (MULT16_16(tmp,best_ener[N-1])>MULT16_16(best_score[N-1],ADD16(1,ener16[i-start]))) + { + /* We can safely put it last and then check */ + best_score[N-1]=tmp; + best_ener[N-1]=ener16[i-start]+1; + pitch[N-1]=i; + /* Check if it comes in front of others */ + for (j=0;jMULT16_16(best_score[j],ADD16(1,ener16[i-start]))) + { + for (k=N-1;k>j;k--) + { + best_score[k]=best_score[k-1]; + best_ener[k]=best_ener[k-1]; + pitch[k]=pitch[k-1]; + } + best_score[j]=tmp; + best_ener[j]=ener16[i-start]+1; + pitch[j]=i; + break; + } + } + } + } + } + } + + /* Compute open-loop gain */ + if (gain) + { + for (j=0;jbest_sum && gain_sum<=max_gain) ------ (1) + + if (sum>best_sum && !(gain_sum>max_gain)) ------ (2) + + if (max_gain<=gain_sum) { ------ (3) + sum = -VERY_LARGE32; + } + if (best_sum<=sum) + + The blackin cc instructions are all of the form: + + cc = x < y (or cc = x <= y) +*/ +" R1 = B0\n\t" +" R2 = %5\n\t" +" R3 = %6\n\t" +" cc = R2 <= R1;\n\t" +" if cc R0 = R3;\n\t" +" cc = %0 <= R0;\n\t" +" if cc %0 = R0;\n\t" +" if cc %1 = P1;\n\t" + +"pgs2: P1 += 1;\n\t" + + : "=&d" (best_sum), "=&d" (best_cdbk) + : "a" (gain_cdbk), "a" (C16), "a" (gain_cdbk_size), "a" (max_gain), + "b" (-VERY_LARGE32) + : "R0", "R1", "R2", "R3", "R4", "P0", + "P1", "I1", "L1", "A0", "B0" +#if (__GNUC__ == 4) + , "LC1" +#endif + ); + + return best_cdbk; +} +#endif + diff --git a/ios/IOSDuoduo/Voice/Code/Libs/libspeex/ltp_sse.h b/ios/IOSDuoduo/Voice/Code/Libs/libspeex/ltp_sse.h new file mode 100755 index 000000000..bed6eaac9 --- /dev/null +++ b/ios/IOSDuoduo/Voice/Code/Libs/libspeex/ltp_sse.h @@ -0,0 +1,92 @@ +/* Copyright (C) 2002 Jean-Marc Valin */ +/** + @file ltp_sse.h + @brief Long-Term Prediction functions (SSE version) +*/ +/* + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + - Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + - Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + - Neither the name of the Xiph.org Foundation nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR + CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#include + +#define OVERRIDE_INNER_PROD +float inner_prod(const float *a, const float *b, int len) +{ + int i; + float ret; + __m128 sum = _mm_setzero_ps(); + for (i=0;i<(len>>2);i+=2) + { + sum = _mm_add_ps(sum, _mm_mul_ps(_mm_loadu_ps(a+0), _mm_loadu_ps(b+0))); + sum = _mm_add_ps(sum, _mm_mul_ps(_mm_loadu_ps(a+4), _mm_loadu_ps(b+4))); + a += 8; + b += 8; + } + sum = _mm_add_ps(sum, _mm_movehl_ps(sum, sum)); + sum = _mm_add_ss(sum, _mm_shuffle_ps(sum, sum, 0x55)); + _mm_store_ss(&ret, sum); + return ret; +} + +#define OVERRIDE_PITCH_XCORR +void pitch_xcorr(const float *_x, const float *_y, float *corr, int len, int nb_pitch, char *stack) +{ + int i, offset; + VARDECL(__m128 *x); + VARDECL(__m128 *y); + int N, L; + N = len>>2; + L = nb_pitch>>2; + ALLOC(x, N, __m128); + ALLOC(y, N+L, __m128); + for (i=0;i=(spx_int32_t)65536) + { + x >>= 16; + r += 16; + } + if (x>=256) + { + x >>= 8; + r += 8; + } + if (x>=16) + { + x >>= 4; + r += 4; + } + if (x>=4) + { + x >>= 2; + r += 2; + } + if (x>=2) + { + r += 1; + } + return r; +} + +static inline spx_int16_t spx_ilog4(spx_uint32_t x) +{ + int r=0; + if (x>=(spx_int32_t)65536) + { + x >>= 16; + r += 8; + } + if (x>=256) + { + x >>= 8; + r += 4; + } + if (x>=16) + { + x >>= 4; + r += 2; + } + if (x>=4) + { + r += 1; + } + return r; +} + +#ifdef FIXED_POINT + +/** Generate a pseudo-random number */ +static inline spx_word16_t speex_rand(spx_word16_t std, spx_int32_t *seed) +{ + spx_word32_t res; + *seed = 1664525 * *seed + 1013904223; + res = MULT16_16(EXTRACT16(SHR32(*seed,16)),std); + return EXTRACT16(PSHR32(SUB32(res, SHR32(res, 3)),14)); +} + +/* sqrt(x) ~= 0.22178 + 1.29227*x - 0.77070*x^2 + 0.25723*x^3 (for .25 < x < 1) */ +/*#define C0 3634 +#define C1 21173 +#define C2 -12627 +#define C3 4215*/ + +/* sqrt(x) ~= 0.22178 + 1.29227*x - 0.77070*x^2 + 0.25659*x^3 (for .25 < x < 1) */ +#define C0 3634 +#define C1 21173 +#define C2 -12627 +#define C3 4204 + +static inline spx_word16_t spx_sqrt(spx_word32_t x) +{ + int k; + spx_word32_t rt; + k = spx_ilog4(x)-6; + x = VSHR32(x, (k<<1)); + rt = ADD16(C0, MULT16_16_Q14(x, ADD16(C1, MULT16_16_Q14(x, ADD16(C2, MULT16_16_Q14(x, (C3))))))); + rt = VSHR32(rt,7-k); + return rt; +} + +/* log(x) ~= -2.18151 + 4.20592*x - 2.88938*x^2 + 0.86535*x^3 (for .5 < x < 1) */ + + +#define A1 16469 +#define A2 2242 +#define A3 1486 + +static inline spx_word16_t spx_acos(spx_word16_t x) +{ + int s=0; + spx_word16_t ret; + spx_word16_t sq; + if (x<0) + { + s=1; + x = NEG16(x); + } + x = SUB16(16384,x); + + x = x >> 1; + sq = MULT16_16_Q13(x, ADD16(A1, MULT16_16_Q13(x, ADD16(A2, MULT16_16_Q13(x, (A3)))))); + ret = spx_sqrt(SHL32(EXTEND32(sq),13)); + + /*ret = spx_sqrt(67108864*(-1.6129e-04 + 2.0104e+00*f + 2.7373e-01*f*f + 1.8136e-01*f*f*f));*/ + if (s) + ret = SUB16(25736,ret); + return ret; +} + + +#define K1 8192 +#define K2 -4096 +#define K3 340 +#define K4 -10 + +static inline spx_word16_t spx_cos(spx_word16_t x) +{ + spx_word16_t x2; + + if (x<12868) + { + x2 = MULT16_16_P13(x,x); + return ADD32(K1, MULT16_16_P13(x2, ADD32(K2, MULT16_16_P13(x2, ADD32(K3, MULT16_16_P13(K4, x2)))))); + } else { + x = SUB16(25736,x); + x2 = MULT16_16_P13(x,x); + return SUB32(-K1, MULT16_16_P13(x2, ADD32(K2, MULT16_16_P13(x2, ADD32(K3, MULT16_16_P13(K4, x2)))))); + } +} + +#define L1 32767 +#define L2 -7651 +#define L3 8277 +#define L4 -626 + +static inline spx_word16_t _spx_cos_pi_2(spx_word16_t x) +{ + spx_word16_t x2; + + x2 = MULT16_16_P15(x,x); + return ADD16(1,MIN16(32766,ADD32(SUB16(L1,x2), MULT16_16_P15(x2, ADD32(L2, MULT16_16_P15(x2, ADD32(L3, MULT16_16_P15(L4, x2)))))))); +} + +static inline spx_word16_t spx_cos_norm(spx_word32_t x) +{ + x = x&0x0001ffff; + if (x>SHL32(EXTEND32(1), 16)) + x = SUB32(SHL32(EXTEND32(1), 17),x); + if (x&0x00007fff) + { + if (x14) + return 0x7fffffff; + else if (integer < -15) + return 0; + frac = SHL16(x-SHL16(integer,11),3); + frac = ADD16(D0, MULT16_16_Q14(frac, ADD16(D1, MULT16_16_Q14(frac, ADD16(D2 , MULT16_16_Q14(D3,frac)))))); + return VSHR32(EXTEND32(frac), -integer-2); +} + +/* Input in Q11 format, output in Q16 */ +static inline spx_word32_t spx_exp(spx_word16_t x) +{ + if (x>21290) + return 0x7fffffff; + else if (x<-21290) + return 0; + else + return spx_exp2(MULT16_16_P14(23637,x)); +} +#define M1 32767 +#define M2 -21 +#define M3 -11943 +#define M4 4936 + +static inline spx_word16_t spx_atan01(spx_word16_t x) +{ + return MULT16_16_P15(x, ADD32(M1, MULT16_16_P15(x, ADD32(M2, MULT16_16_P15(x, ADD32(M3, MULT16_16_P15(M4, x))))))); +} + +#undef M1 +#undef M2 +#undef M3 +#undef M4 + +/* Input in Q15, output in Q14 */ +static inline spx_word16_t spx_atan(spx_word32_t x) +{ + if (x <= 32767) + { + return SHR16(spx_atan01(x),1); + } else { + int e = spx_ilog2(x); + if (e>=29) + return 25736; + x = DIV32_16(SHL32(EXTEND32(32767),29-e), EXTRACT16(SHR32(x, e-14))); + return SUB16(25736, SHR16(spx_atan01(x),1)); + } +} +#else + +#ifndef M_PI +#define M_PI 3.14159265358979323846 /* pi */ +#endif + +#define C1 0.9999932946f +#define C2 -0.4999124376f +#define C3 0.0414877472f +#define C4 -0.0012712095f + + +#define SPX_PI_2 1.5707963268 +static inline spx_word16_t spx_cos(spx_word16_t x) +{ + if (x 32766 ? 32767 : (x))) +#else +#define WORD2INT(x) ((x) < -32767.5f ? -32768 : ((x) > 32766.5f ? 32767 : floor(.5+(x)))) +#endif + +/* If enabled, the AEC will use a foreground filter and a background filter to be more robust to double-talk + and difficult signals in general. The cost is an extra FFT and a matrix-vector multiply */ +#define TWO_PATH + +#ifdef FIXED_POINT +static const spx_float_t MIN_LEAK = {20972, -22}; + +/* Constants for the two-path filter */ +static const spx_float_t VAR1_SMOOTH = {23593, -16}; +static const spx_float_t VAR2_SMOOTH = {23675, -15}; +static const spx_float_t VAR1_UPDATE = {16384, -15}; +static const spx_float_t VAR2_UPDATE = {16384, -16}; +static const spx_float_t VAR_BACKTRACK = {16384, -12}; +#define TOP16(x) ((x)>>16) + +#else + +static const spx_float_t MIN_LEAK = .005f; + +/* Constants for the two-path filter */ +static const spx_float_t VAR1_SMOOTH = .36f; +static const spx_float_t VAR2_SMOOTH = .7225f; +static const spx_float_t VAR1_UPDATE = .5f; +static const spx_float_t VAR2_UPDATE = .25f; +static const spx_float_t VAR_BACKTRACK = 4.f; +#define TOP16(x) (x) +#endif + + +#define PLAYBACK_DELAY 2 + +void speex_echo_get_residual(SpeexEchoState *st, spx_word32_t *Yout, int len); + + +/** Speex echo cancellation state. */ +struct SpeexEchoState_ { + int frame_size; /**< Number of samples processed each time */ + int window_size; + int M; + int cancel_count; + int adapted; + int saturated; + int screwed_up; + int C; /** Number of input channels (microphones) */ + int K; /** Number of output channels (loudspeakers) */ + spx_int32_t sampling_rate; + spx_word16_t spec_average; + spx_word16_t beta0; + spx_word16_t beta_max; + spx_word32_t sum_adapt; + spx_word16_t leak_estimate; + + spx_word16_t *e; /* scratch */ + spx_word16_t *x; /* Far-end input buffer (2N) */ + spx_word16_t *X; /* Far-end buffer (M+1 frames) in frequency domain */ + spx_word16_t *input; /* scratch */ + spx_word16_t *y; /* scratch */ + spx_word16_t *last_y; + spx_word16_t *Y; /* scratch */ + spx_word16_t *E; + spx_word32_t *PHI; /* scratch */ + spx_word32_t *W; /* (Background) filter weights */ +#ifdef TWO_PATH + spx_word16_t *foreground; /* Foreground filter weights */ + spx_word32_t Davg1; /* 1st recursive average of the residual power difference */ + spx_word32_t Davg2; /* 2nd recursive average of the residual power difference */ + spx_float_t Dvar1; /* Estimated variance of 1st estimator */ + spx_float_t Dvar2; /* Estimated variance of 2nd estimator */ +#endif + spx_word32_t *power; /* Power of the far-end signal */ + spx_float_t *power_1;/* Inverse power of far-end */ + spx_word16_t *wtmp; /* scratch */ +#ifdef FIXED_POINT + spx_word16_t *wtmp2; /* scratch */ +#endif + spx_word32_t *Rf; /* scratch */ + spx_word32_t *Yf; /* scratch */ + spx_word32_t *Xf; /* scratch */ + spx_word32_t *Eh; + spx_word32_t *Yh; + spx_float_t Pey; + spx_float_t Pyy; + spx_word16_t *window; + spx_word16_t *prop; + void *fft_table; + spx_word16_t *memX, *memD, *memE; + spx_word16_t preemph; + spx_word16_t notch_radius; + spx_mem_t *notch_mem; + + /* NOTE: If you only use speex_echo_cancel() and want to save some memory, remove this */ + spx_int16_t *play_buf; + int play_buf_pos; + int play_buf_started; +}; + +static inline void filter_dc_notch16(const spx_int16_t *in, spx_word16_t radius, spx_word16_t *out, int len, spx_mem_t *mem, int stride) +{ + int i; + spx_word16_t den2; +#ifdef FIXED_POINT + den2 = MULT16_16_Q15(radius,radius) + MULT16_16_Q15(QCONST16(.7,15),MULT16_16_Q15(32767-radius,32767-radius)); +#else + den2 = radius*radius + .7*(1-radius)*(1-radius); +#endif + /*printf ("%d %d %d %d %d %d\n", num[0], num[1], num[2], den[0], den[1], den[2]);*/ + for (i=0;i>= 1; + while(len--) + { + spx_word32_t part=0; + part = MAC16_16(part,*x++,*y++); + part = MAC16_16(part,*x++,*y++); + /* HINT: If you had a 40-bit accumulator, you could shift only at the end */ + sum = ADD32(sum,SHR32(part,6)); + } + return sum; +} + +/** Compute power spectrum of a half-complex (packed) vector */ +static inline void power_spectrum(const spx_word16_t *X, spx_word32_t *ps, int N) +{ + int i, j; + ps[0]=MULT16_16(X[0],X[0]); + for (i=1,j=1;i max_sum) + max_sum = prop[i]; + } + for (i=0;i +static FILE *rFile=NULL, *pFile=NULL, *oFile=NULL; + +static void dump_audio(const spx_int16_t *rec, const spx_int16_t *play, const spx_int16_t *out, int len) +{ + if (!(rFile && pFile && oFile)) + { + speex_fatal("Dump files not open"); + } + fwrite(rec, sizeof(spx_int16_t), len, rFile); + fwrite(play, sizeof(spx_int16_t), len, pFile); + fwrite(out, sizeof(spx_int16_t), len, oFile); +} +#endif + +/** Creates a new echo canceller state */ +EXPORT SpeexEchoState *speex_echo_state_init(int frame_size, int filter_length) +{ + return speex_echo_state_init_mc(frame_size, filter_length, 1, 1); +} + +EXPORT SpeexEchoState *speex_echo_state_init_mc(int frame_size, int filter_length, int nb_mic, int nb_speakers) +{ + int i,N,M, C, K; + SpeexEchoState *st = (SpeexEchoState *)speex_alloc(sizeof(SpeexEchoState)); + + st->K = nb_speakers; + st->C = nb_mic; + C=st->C; + K=st->K; +#ifdef DUMP_ECHO_CANCEL_DATA + if (rFile || pFile || oFile) + speex_fatal("Opening dump files twice"); + rFile = fopen("aec_rec.sw", "wb"); + pFile = fopen("aec_play.sw", "wb"); + oFile = fopen("aec_out.sw", "wb"); +#endif + + st->frame_size = frame_size; + st->window_size = 2*frame_size; + N = st->window_size; + M = st->M = (filter_length+st->frame_size-1)/frame_size; + st->cancel_count=0; + st->sum_adapt = 0; + st->saturated = 0; + st->screwed_up = 0; + /* This is the default sampling rate */ + st->sampling_rate = 8000; + st->spec_average = DIV32_16(SHL32(EXTEND32(st->frame_size), 15), st->sampling_rate); +#ifdef FIXED_POINT + st->beta0 = DIV32_16(SHL32(EXTEND32(st->frame_size), 16), st->sampling_rate); + st->beta_max = DIV32_16(SHL32(EXTEND32(st->frame_size), 14), st->sampling_rate); +#else + st->beta0 = (2.0f*st->frame_size)/st->sampling_rate; + st->beta_max = (.5f*st->frame_size)/st->sampling_rate; +#endif + st->leak_estimate = 0; + + st->fft_table = spx_fft_init(N); + + st->e = (spx_word16_t*)speex_alloc(C*N*sizeof(spx_word16_t)); + st->x = (spx_word16_t*)speex_alloc(K*N*sizeof(spx_word16_t)); + st->input = (spx_word16_t*)speex_alloc(C*st->frame_size*sizeof(spx_word16_t)); + st->y = (spx_word16_t*)speex_alloc(C*N*sizeof(spx_word16_t)); + st->last_y = (spx_word16_t*)speex_alloc(C*N*sizeof(spx_word16_t)); + st->Yf = (spx_word32_t*)speex_alloc((st->frame_size+1)*sizeof(spx_word32_t)); + st->Rf = (spx_word32_t*)speex_alloc((st->frame_size+1)*sizeof(spx_word32_t)); + st->Xf = (spx_word32_t*)speex_alloc((st->frame_size+1)*sizeof(spx_word32_t)); + st->Yh = (spx_word32_t*)speex_alloc((st->frame_size+1)*sizeof(spx_word32_t)); + st->Eh = (spx_word32_t*)speex_alloc((st->frame_size+1)*sizeof(spx_word32_t)); + + st->X = (spx_word16_t*)speex_alloc(K*(M+1)*N*sizeof(spx_word16_t)); + st->Y = (spx_word16_t*)speex_alloc(C*N*sizeof(spx_word16_t)); + st->E = (spx_word16_t*)speex_alloc(C*N*sizeof(spx_word16_t)); + st->W = (spx_word32_t*)speex_alloc(C*K*M*N*sizeof(spx_word32_t)); +#ifdef TWO_PATH + st->foreground = (spx_word16_t*)speex_alloc(M*N*C*K*sizeof(spx_word16_t)); +#endif + st->PHI = (spx_word32_t*)speex_alloc(N*sizeof(spx_word32_t)); + st->power = (spx_word32_t*)speex_alloc((frame_size+1)*sizeof(spx_word32_t)); + st->power_1 = (spx_float_t*)speex_alloc((frame_size+1)*sizeof(spx_float_t)); + st->window = (spx_word16_t*)speex_alloc(N*sizeof(spx_word16_t)); + st->prop = (spx_word16_t*)speex_alloc(M*sizeof(spx_word16_t)); + st->wtmp = (spx_word16_t*)speex_alloc(N*sizeof(spx_word16_t)); +#ifdef FIXED_POINT + st->wtmp2 = (spx_word16_t*)speex_alloc(N*sizeof(spx_word16_t)); + for (i=0;i>1;i++) + { + st->window[i] = (16383-SHL16(spx_cos(DIV32_16(MULT16_16(25736,i<<1),N)),1)); + st->window[N-i-1] = st->window[i]; + } +#else + for (i=0;iwindow[i] = .5-.5*cos(2*M_PI*i/N); +#endif + for (i=0;i<=st->frame_size;i++) + st->power_1[i] = FLOAT_ONE; + for (i=0;iW[i] = 0; + { + spx_word32_t sum = 0; + /* Ratio of ~10 between adaptation rate of first and last block */ + spx_word16_t decay = SHR32(spx_exp(NEG16(DIV32_16(QCONST16(2.4,11),M))),1); + st->prop[0] = QCONST16(.7, 15); + sum = EXTEND32(st->prop[0]); + for (i=1;iprop[i] = MULT16_16_Q15(st->prop[i-1], decay); + sum = ADD32(sum, EXTEND32(st->prop[i])); + } + for (i=M-1;i>=0;i--) + { + st->prop[i] = DIV32(MULT16_16(QCONST16(.8f,15), st->prop[i]),sum); + } + } + + st->memX = (spx_word16_t*)speex_alloc(K*sizeof(spx_word16_t)); + st->memD = (spx_word16_t*)speex_alloc(C*sizeof(spx_word16_t)); + st->memE = (spx_word16_t*)speex_alloc(C*sizeof(spx_word16_t)); + st->preemph = QCONST16(.9,15); + if (st->sampling_rate<12000) + st->notch_radius = QCONST16(.9, 15); + else if (st->sampling_rate<24000) + st->notch_radius = QCONST16(.982, 15); + else + st->notch_radius = QCONST16(.992, 15); + + st->notch_mem = (spx_mem_t*)speex_alloc(2*C*sizeof(spx_mem_t)); + st->adapted = 0; + st->Pey = st->Pyy = FLOAT_ONE; + +#ifdef TWO_PATH + st->Davg1 = st->Davg2 = 0; + st->Dvar1 = st->Dvar2 = FLOAT_ZERO; +#endif + + st->play_buf = (spx_int16_t*)speex_alloc(K*(PLAYBACK_DELAY+1)*st->frame_size*sizeof(spx_int16_t)); + st->play_buf_pos = PLAYBACK_DELAY*st->frame_size; + st->play_buf_started = 0; + + return st; +} + +/** Resets echo canceller state */ +EXPORT void speex_echo_state_reset(SpeexEchoState *st) +{ + int i, M, N, C, K; + st->cancel_count=0; + st->screwed_up = 0; + N = st->window_size; + M = st->M; + C=st->C; + K=st->K; + for (i=0;iW[i] = 0; +#ifdef TWO_PATH + for (i=0;iforeground[i] = 0; +#endif + for (i=0;iX[i] = 0; + for (i=0;i<=st->frame_size;i++) + { + st->power[i] = 0; + st->power_1[i] = FLOAT_ONE; + st->Eh[i] = 0; + st->Yh[i] = 0; + } + for (i=0;iframe_size;i++) + { + st->last_y[i] = 0; + } + for (i=0;iE[i] = 0; + } + for (i=0;ix[i] = 0; + } + for (i=0;i<2*C;i++) + st->notch_mem[i] = 0; + for (i=0;imemD[i]=st->memE[i]=0; + for (i=0;imemX[i]=0; + + st->saturated = 0; + st->adapted = 0; + st->sum_adapt = 0; + st->Pey = st->Pyy = FLOAT_ONE; +#ifdef TWO_PATH + st->Davg1 = st->Davg2 = 0; + st->Dvar1 = st->Dvar2 = FLOAT_ZERO; +#endif + for (i=0;i<3*st->frame_size;i++) + st->play_buf[i] = 0; + st->play_buf_pos = PLAYBACK_DELAY*st->frame_size; + st->play_buf_started = 0; + +} + +/** Destroys an echo canceller state */ +EXPORT void speex_echo_state_destroy(SpeexEchoState *st) +{ + spx_fft_destroy(st->fft_table); + + speex_free(st->e); + speex_free(st->x); + speex_free(st->input); + speex_free(st->y); + speex_free(st->last_y); + speex_free(st->Yf); + speex_free(st->Rf); + speex_free(st->Xf); + speex_free(st->Yh); + speex_free(st->Eh); + + speex_free(st->X); + speex_free(st->Y); + speex_free(st->E); + speex_free(st->W); +#ifdef TWO_PATH + speex_free(st->foreground); +#endif + speex_free(st->PHI); + speex_free(st->power); + speex_free(st->power_1); + speex_free(st->window); + speex_free(st->prop); + speex_free(st->wtmp); +#ifdef FIXED_POINT + speex_free(st->wtmp2); +#endif + speex_free(st->memX); + speex_free(st->memD); + speex_free(st->memE); + speex_free(st->notch_mem); + + speex_free(st->play_buf); + speex_free(st); + +#ifdef DUMP_ECHO_CANCEL_DATA + fclose(rFile); + fclose(pFile); + fclose(oFile); + rFile = pFile = oFile = NULL; +#endif +} + +EXPORT void speex_echo_capture(SpeexEchoState *st, const spx_int16_t *rec, spx_int16_t *out) +{ + int i; + /*speex_warning_int("capture with fill level ", st->play_buf_pos/st->frame_size);*/ + st->play_buf_started = 1; + if (st->play_buf_pos>=st->frame_size) + { + speex_echo_cancellation(st, rec, st->play_buf, out); + st->play_buf_pos -= st->frame_size; + for (i=0;iplay_buf_pos;i++) + st->play_buf[i] = st->play_buf[i+st->frame_size]; + } else { + speex_warning("No playback frame available (your application is buggy and/or got xruns)"); + if (st->play_buf_pos!=0) + { + speex_warning("internal playback buffer corruption?"); + st->play_buf_pos = 0; + } + for (i=0;iframe_size;i++) + out[i] = rec[i]; + } +} + +EXPORT void speex_echo_playback(SpeexEchoState *st, const spx_int16_t *play) +{ + /*speex_warning_int("playback with fill level ", st->play_buf_pos/st->frame_size);*/ + if (!st->play_buf_started) + { + speex_warning("discarded first playback frame"); + return; + } + if (st->play_buf_pos<=PLAYBACK_DELAY*st->frame_size) + { + int i; + for (i=0;iframe_size;i++) + st->play_buf[st->play_buf_pos+i] = play[i]; + st->play_buf_pos += st->frame_size; + if (st->play_buf_pos <= (PLAYBACK_DELAY-1)*st->frame_size) + { + speex_warning("Auto-filling the buffer (your application is buggy and/or got xruns)"); + for (i=0;iframe_size;i++) + st->play_buf[st->play_buf_pos+i] = play[i]; + st->play_buf_pos += st->frame_size; + } + } else { + speex_warning("Had to discard a playback frame (your application is buggy and/or got xruns)"); + } +} + +/** Performs echo cancellation on a frame (deprecated, last arg now ignored) */ +EXPORT void speex_echo_cancel(SpeexEchoState *st, const spx_int16_t *in, const spx_int16_t *far_end, spx_int16_t *out, spx_int32_t *Yout) +{ + speex_echo_cancellation(st, in, far_end, out); +} + +/** Performs echo cancellation on a frame */ +EXPORT void speex_echo_cancellation(SpeexEchoState *st, const spx_int16_t *in, const spx_int16_t *far_end, spx_int16_t *out) +{ + int i,j, chan, speak; + int N,M, C, K; + spx_word32_t Syy,See,Sxx,Sdd, Sff; +#ifdef TWO_PATH + spx_word32_t Dbf; + int update_foreground; +#endif + spx_word32_t Sey; + spx_word16_t ss, ss_1; + spx_float_t Pey = FLOAT_ONE, Pyy=FLOAT_ONE; + spx_float_t alpha, alpha_1; + spx_word16_t RER; + spx_word32_t tmp32; + + N = st->window_size; + M = st->M; + C = st->C; + K = st->K; + + st->cancel_count++; +#ifdef FIXED_POINT + ss=DIV32_16(11469,M); + ss_1 = SUB16(32767,ss); +#else + ss=.35/M; + ss_1 = 1-ss; +#endif + + for (chan = 0; chan < C; chan++) + { + /* Apply a notch filter to make sure DC doesn't end up causing problems */ + filter_dc_notch16(in+chan, st->notch_radius, st->input+chan*st->frame_size, st->frame_size, st->notch_mem+2*chan, C); + /* Copy input data to buffer and apply pre-emphasis */ + /* Copy input data to buffer */ + for (i=0;iframe_size;i++) + { + spx_word32_t tmp32; + /* FIXME: This core has changed a bit, need to merge properly */ + tmp32 = SUB32(EXTEND32(st->input[chan*st->frame_size+i]), EXTEND32(MULT16_16_P15(st->preemph, st->memD[chan]))); +#ifdef FIXED_POINT + if (tmp32 > 32767) + { + tmp32 = 32767; + if (st->saturated == 0) + st->saturated = 1; + } + if (tmp32 < -32767) + { + tmp32 = -32767; + if (st->saturated == 0) + st->saturated = 1; + } +#endif + st->memD[chan] = st->input[chan*st->frame_size+i]; + st->input[chan*st->frame_size+i] = EXTRACT16(tmp32); + } + } + + for (speak = 0; speak < K; speak++) + { + for (i=0;iframe_size;i++) + { + spx_word32_t tmp32; + st->x[speak*N+i] = st->x[speak*N+i+st->frame_size]; + tmp32 = SUB32(EXTEND32(far_end[i*K+speak]), EXTEND32(MULT16_16_P15(st->preemph, st->memX[speak]))); +#ifdef FIXED_POINT + /*FIXME: If saturation occurs here, we need to freeze adaptation for M frames (not just one) */ + if (tmp32 > 32767) + { + tmp32 = 32767; + st->saturated = M+1; + } + if (tmp32 < -32767) + { + tmp32 = -32767; + st->saturated = M+1; + } +#endif + st->x[speak*N+i+st->frame_size] = EXTRACT16(tmp32); + st->memX[speak] = far_end[i*K+speak]; + } + } + + for (speak = 0; speak < K; speak++) + { + /* Shift memory: this could be optimized eventually*/ + for (j=M-1;j>=0;j--) + { + for (i=0;iX[(j+1)*N*K+speak*N+i] = st->X[j*N*K+speak*N+i]; + } + /* Convert x (echo input) to frequency domain */ + spx_fft(st->fft_table, st->x+speak*N, &st->X[speak*N]); + } + + Sxx = 0; + for (speak = 0; speak < K; speak++) + { + Sxx += mdf_inner_prod(st->x+speak*N+st->frame_size, st->x+speak*N+st->frame_size, st->frame_size); + power_spectrum_accum(st->X+speak*N, st->Xf, N); + } + + Sff = 0; + for (chan = 0; chan < C; chan++) + { +#ifdef TWO_PATH + /* Compute foreground filter */ + spectral_mul_accum16(st->X, st->foreground+chan*N*K*M, st->Y+chan*N, N, M*K); + spx_ifft(st->fft_table, st->Y+chan*N, st->e+chan*N); + for (i=0;iframe_size;i++) + st->e[chan*N+i] = SUB16(st->input[chan*st->frame_size+i], st->e[chan*N+i+st->frame_size]); + Sff += mdf_inner_prod(st->e+chan*N, st->e+chan*N, st->frame_size); +#endif + } + + /* Adjust proportional adaption rate */ + /* FIXME: Adjust that for C, K*/ + if (st->adapted) + mdf_adjust_prop (st->W, N, M, C*K, st->prop); + /* Compute weight gradient */ + if (st->saturated == 0) + { + for (chan = 0; chan < C; chan++) + { + for (speak = 0; speak < K; speak++) + { + for (j=M-1;j>=0;j--) + { + weighted_spectral_mul_conj(st->power_1, FLOAT_SHL(PSEUDOFLOAT(st->prop[j]),-15), &st->X[(j+1)*N*K+speak*N], st->E+chan*N, st->PHI, N); + for (i=0;iW[chan*N*K*M + j*N*K + speak*N + i] += st->PHI[i]; + } + } + } + } else { + st->saturated--; + } + + /* FIXME: MC conversion required */ + /* Update weight to prevent circular convolution (MDF / AUMDF) */ + for (chan = 0; chan < C; chan++) + { + for (speak = 0; speak < K; speak++) + { + for (j=0;jcancel_count%(M-1) == j-1) + { +#ifdef FIXED_POINT + for (i=0;iwtmp2[i] = EXTRACT16(PSHR32(st->W[chan*N*K*M + j*N*K + speak*N + i],NORMALIZE_SCALEDOWN+16)); + spx_ifft(st->fft_table, st->wtmp2, st->wtmp); + for (i=0;iframe_size;i++) + { + st->wtmp[i]=0; + } + for (i=st->frame_size;iwtmp[i]=SHL16(st->wtmp[i],NORMALIZE_SCALEUP); + } + spx_fft(st->fft_table, st->wtmp, st->wtmp2); + /* The "-1" in the shift is a sort of kludge that trades less efficient update speed for decrease noise */ + for (i=0;iW[chan*N*K*M + j*N*K + speak*N + i] -= SHL32(EXTEND32(st->wtmp2[i]),16+NORMALIZE_SCALEDOWN-NORMALIZE_SCALEUP-1); +#else + spx_ifft(st->fft_table, &st->W[chan*N*K*M + j*N*K + speak*N], st->wtmp); + for (i=st->frame_size;iwtmp[i]=0; + } + spx_fft(st->fft_table, st->wtmp, &st->W[chan*N*K*M + j*N*K + speak*N]); +#endif + } + } + } + } + + /* So we can use power_spectrum_accum */ + for (i=0;i<=st->frame_size;i++) + st->Rf[i] = st->Yf[i] = st->Xf[i] = 0; + + Dbf = 0; + See = 0; +#ifdef TWO_PATH + /* Difference in response, this is used to estimate the variance of our residual power estimate */ + for (chan = 0; chan < C; chan++) + { + spectral_mul_accum(st->X, st->W+chan*N*K*M, st->Y+chan*N, N, M*K); + spx_ifft(st->fft_table, st->Y+chan*N, st->y+chan*N); + for (i=0;iframe_size;i++) + st->e[chan*N+i] = SUB16(st->e[chan*N+i+st->frame_size], st->y[chan*N+i+st->frame_size]); + Dbf += 10+mdf_inner_prod(st->e+chan*N, st->e+chan*N, st->frame_size); + for (i=0;iframe_size;i++) + st->e[chan*N+i] = SUB16(st->input[chan*st->frame_size+i], st->y[chan*N+i+st->frame_size]); + See += mdf_inner_prod(st->e+chan*N, st->e+chan*N, st->frame_size); + } +#endif + +#ifndef TWO_PATH + Sff = See; +#endif + +#ifdef TWO_PATH + /* Logic for updating the foreground filter */ + + /* For two time windows, compute the mean of the energy difference, as well as the variance */ + st->Davg1 = ADD32(MULT16_32_Q15(QCONST16(.6f,15),st->Davg1), MULT16_32_Q15(QCONST16(.4f,15),SUB32(Sff,See))); + st->Davg2 = ADD32(MULT16_32_Q15(QCONST16(.85f,15),st->Davg2), MULT16_32_Q15(QCONST16(.15f,15),SUB32(Sff,See))); + st->Dvar1 = FLOAT_ADD(FLOAT_MULT(VAR1_SMOOTH, st->Dvar1), FLOAT_MUL32U(MULT16_32_Q15(QCONST16(.4f,15),Sff), MULT16_32_Q15(QCONST16(.4f,15),Dbf))); + st->Dvar2 = FLOAT_ADD(FLOAT_MULT(VAR2_SMOOTH, st->Dvar2), FLOAT_MUL32U(MULT16_32_Q15(QCONST16(.15f,15),Sff), MULT16_32_Q15(QCONST16(.15f,15),Dbf))); + + /* Equivalent float code: + st->Davg1 = .6*st->Davg1 + .4*(Sff-See); + st->Davg2 = .85*st->Davg2 + .15*(Sff-See); + st->Dvar1 = .36*st->Dvar1 + .16*Sff*Dbf; + st->Dvar2 = .7225*st->Dvar2 + .0225*Sff*Dbf; + */ + + update_foreground = 0; + /* Check if we have a statistically significant reduction in the residual echo */ + /* Note that this is *not* Gaussian, so we need to be careful about the longer tail */ + if (FLOAT_GT(FLOAT_MUL32U(SUB32(Sff,See),ABS32(SUB32(Sff,See))), FLOAT_MUL32U(Sff,Dbf))) + update_foreground = 1; + else if (FLOAT_GT(FLOAT_MUL32U(st->Davg1, ABS32(st->Davg1)), FLOAT_MULT(VAR1_UPDATE,(st->Dvar1)))) + update_foreground = 1; + else if (FLOAT_GT(FLOAT_MUL32U(st->Davg2, ABS32(st->Davg2)), FLOAT_MULT(VAR2_UPDATE,(st->Dvar2)))) + update_foreground = 1; + + /* Do we update? */ + if (update_foreground) + { + st->Davg1 = st->Davg2 = 0; + st->Dvar1 = st->Dvar2 = FLOAT_ZERO; + /* Copy background filter to foreground filter */ + for (i=0;iforeground[i] = EXTRACT16(PSHR32(st->W[i],16)); + /* Apply a smooth transition so as to not introduce blocking artifacts */ + for (chan = 0; chan < C; chan++) + for (i=0;iframe_size;i++) + st->e[chan*N+i+st->frame_size] = MULT16_16_Q15(st->window[i+st->frame_size],st->e[chan*N+i+st->frame_size]) + MULT16_16_Q15(st->window[i],st->y[chan*N+i+st->frame_size]); + } else { + int reset_background=0; + /* Otherwise, check if the background filter is significantly worse */ + if (FLOAT_GT(FLOAT_MUL32U(NEG32(SUB32(Sff,See)),ABS32(SUB32(Sff,See))), FLOAT_MULT(VAR_BACKTRACK,FLOAT_MUL32U(Sff,Dbf)))) + reset_background = 1; + if (FLOAT_GT(FLOAT_MUL32U(NEG32(st->Davg1), ABS32(st->Davg1)), FLOAT_MULT(VAR_BACKTRACK,st->Dvar1))) + reset_background = 1; + if (FLOAT_GT(FLOAT_MUL32U(NEG32(st->Davg2), ABS32(st->Davg2)), FLOAT_MULT(VAR_BACKTRACK,st->Dvar2))) + reset_background = 1; + if (reset_background) + { + /* Copy foreground filter to background filter */ + for (i=0;iW[i] = SHL32(EXTEND32(st->foreground[i]),16); + /* We also need to copy the output so as to get correct adaptation */ + for (chan = 0; chan < C; chan++) + { + for (i=0;iframe_size;i++) + st->y[chan*N+i+st->frame_size] = st->e[chan*N+i+st->frame_size]; + for (i=0;iframe_size;i++) + st->e[chan*N+i] = SUB16(st->input[chan*st->frame_size+i], st->y[chan*N+i+st->frame_size]); + } + See = Sff; + st->Davg1 = st->Davg2 = 0; + st->Dvar1 = st->Dvar2 = FLOAT_ZERO; + } + } +#endif + + Sey = Syy = Sdd = 0; + for (chan = 0; chan < C; chan++) + { + /* Compute error signal (for the output with de-emphasis) */ + for (i=0;iframe_size;i++) + { + spx_word32_t tmp_out; +#ifdef TWO_PATH + tmp_out = SUB32(EXTEND32(st->input[chan*st->frame_size+i]), EXTEND32(st->e[chan*N+i+st->frame_size])); +#else + tmp_out = SUB32(EXTEND32(st->input[chan*st->frame_size+i]), EXTEND32(st->y[chan*N+i+st->frame_size])); +#endif + tmp_out = ADD32(tmp_out, EXTEND32(MULT16_16_P15(st->preemph, st->memE[chan]))); + /* This is an arbitrary test for saturation in the microphone signal */ + if (in[i*C+chan] <= -32000 || in[i*C+chan] >= 32000) + { + if (st->saturated == 0) + st->saturated = 1; + } + out[i*C+chan] = WORD2INT(tmp_out); + st->memE[chan] = tmp_out; + } + +#ifdef DUMP_ECHO_CANCEL_DATA + dump_audio(in, far_end, out, st->frame_size); +#endif + + /* Compute error signal (filter update version) */ + for (i=0;iframe_size;i++) + { + st->e[chan*N+i+st->frame_size] = st->e[chan*N+i]; + st->e[chan*N+i] = 0; + } + + /* Compute a bunch of correlations */ + /* FIXME: bad merge */ + Sey += mdf_inner_prod(st->e+chan*N+st->frame_size, st->y+chan*N+st->frame_size, st->frame_size); + Syy += mdf_inner_prod(st->y+chan*N+st->frame_size, st->y+chan*N+st->frame_size, st->frame_size); + Sdd += mdf_inner_prod(st->input+chan*st->frame_size, st->input+chan*st->frame_size, st->frame_size); + + /* Convert error to frequency domain */ + spx_fft(st->fft_table, st->e+chan*N, st->E+chan*N); + for (i=0;iframe_size;i++) + st->y[i+chan*N] = 0; + spx_fft(st->fft_table, st->y+chan*N, st->Y+chan*N); + + /* Compute power spectrum of echo (X), error (E) and filter response (Y) */ + power_spectrum_accum(st->E+chan*N, st->Rf, N); + power_spectrum_accum(st->Y+chan*N, st->Yf, N); + + } + + /*printf ("%f %f %f %f\n", Sff, See, Syy, Sdd, st->update_cond);*/ + + /* Do some sanity check */ + if (!(Syy>=0 && Sxx>=0 && See >= 0) +#ifndef FIXED_POINT + || !(Sff < N*1e9 && Syy < N*1e9 && Sxx < N*1e9) +#endif + ) + { + /* Things have gone really bad */ + st->screwed_up += 50; + for (i=0;iframe_size*C;i++) + out[i] = 0; + } else if (SHR32(Sff, 2) > ADD32(Sdd, SHR32(MULT16_16(N, 10000),6))) + { + /* AEC seems to add lots of echo instead of removing it, let's see if it will improve */ + st->screwed_up++; + } else { + /* Everything's fine */ + st->screwed_up=0; + } + if (st->screwed_up>=50) + { + speex_warning("The echo canceller started acting funny and got slapped (reset). It swears it will behave now."); + speex_echo_state_reset(st); + return; + } + + /* Add a small noise floor to make sure not to have problems when dividing */ + See = MAX32(See, SHR32(MULT16_16(N, 100),6)); + + for (speak = 0; speak < K; speak++) + { + Sxx += mdf_inner_prod(st->x+speak*N+st->frame_size, st->x+speak*N+st->frame_size, st->frame_size); + power_spectrum_accum(st->X+speak*N, st->Xf, N); + } + + + /* Smooth far end energy estimate over time */ + for (j=0;j<=st->frame_size;j++) + st->power[j] = MULT16_32_Q15(ss_1,st->power[j]) + 1 + MULT16_32_Q15(ss,st->Xf[j]); + + /* Compute filtered spectra and (cross-)correlations */ + for (j=st->frame_size;j>=0;j--) + { + spx_float_t Eh, Yh; + Eh = PSEUDOFLOAT(st->Rf[j] - st->Eh[j]); + Yh = PSEUDOFLOAT(st->Yf[j] - st->Yh[j]); + Pey = FLOAT_ADD(Pey,FLOAT_MULT(Eh,Yh)); + Pyy = FLOAT_ADD(Pyy,FLOAT_MULT(Yh,Yh)); +#ifdef FIXED_POINT + st->Eh[j] = MAC16_32_Q15(MULT16_32_Q15(SUB16(32767,st->spec_average),st->Eh[j]), st->spec_average, st->Rf[j]); + st->Yh[j] = MAC16_32_Q15(MULT16_32_Q15(SUB16(32767,st->spec_average),st->Yh[j]), st->spec_average, st->Yf[j]); +#else + st->Eh[j] = (1-st->spec_average)*st->Eh[j] + st->spec_average*st->Rf[j]; + st->Yh[j] = (1-st->spec_average)*st->Yh[j] + st->spec_average*st->Yf[j]; +#endif + } + + Pyy = FLOAT_SQRT(Pyy); + Pey = FLOAT_DIVU(Pey,Pyy); + + /* Compute correlation updatete rate */ + tmp32 = MULT16_32_Q15(st->beta0,Syy); + if (tmp32 > MULT16_32_Q15(st->beta_max,See)) + tmp32 = MULT16_32_Q15(st->beta_max,See); + alpha = FLOAT_DIV32(tmp32, See); + alpha_1 = FLOAT_SUB(FLOAT_ONE, alpha); + /* Update correlations (recursive average) */ + st->Pey = FLOAT_ADD(FLOAT_MULT(alpha_1,st->Pey) , FLOAT_MULT(alpha,Pey)); + st->Pyy = FLOAT_ADD(FLOAT_MULT(alpha_1,st->Pyy) , FLOAT_MULT(alpha,Pyy)); + if (FLOAT_LT(st->Pyy, FLOAT_ONE)) + st->Pyy = FLOAT_ONE; + /* We don't really hope to get better than 33 dB (MIN_LEAK-3dB) attenuation anyway */ + if (FLOAT_LT(st->Pey, FLOAT_MULT(MIN_LEAK,st->Pyy))) + st->Pey = FLOAT_MULT(MIN_LEAK,st->Pyy); + if (FLOAT_GT(st->Pey, st->Pyy)) + st->Pey = st->Pyy; + /* leak_estimate is the linear regression result */ + st->leak_estimate = FLOAT_EXTRACT16(FLOAT_SHL(FLOAT_DIVU(st->Pey, st->Pyy),14)); + /* This looks like a stupid bug, but it's right (because we convert from Q14 to Q15) */ + if (st->leak_estimate > 16383) + st->leak_estimate = 32767; + else + st->leak_estimate = SHL16(st->leak_estimate,1); + /*printf ("%f\n", st->leak_estimate);*/ + + /* Compute Residual to Error Ratio */ +#ifdef FIXED_POINT + tmp32 = MULT16_32_Q15(st->leak_estimate,Syy); + tmp32 = ADD32(SHR32(Sxx,13), ADD32(tmp32, SHL32(tmp32,1))); + /* Check for y in e (lower bound on RER) */ + { + spx_float_t bound = PSEUDOFLOAT(Sey); + bound = FLOAT_DIVU(FLOAT_MULT(bound, bound), PSEUDOFLOAT(ADD32(1,Syy))); + if (FLOAT_GT(bound, PSEUDOFLOAT(See))) + tmp32 = See; + else if (tmp32 < FLOAT_EXTRACT32(bound)) + tmp32 = FLOAT_EXTRACT32(bound); + } + if (tmp32 > SHR32(See,1)) + tmp32 = SHR32(See,1); + RER = FLOAT_EXTRACT16(FLOAT_SHL(FLOAT_DIV32(tmp32,See),15)); +#else + RER = (.0001*Sxx + 3.*MULT16_32_Q15(st->leak_estimate,Syy)) / See; + /* Check for y in e (lower bound on RER) */ + if (RER < Sey*Sey/(1+See*Syy)) + RER = Sey*Sey/(1+See*Syy); + if (RER > .5) + RER = .5; +#endif + + /* We consider that the filter has had minimal adaptation if the following is true*/ + if (!st->adapted && st->sum_adapt > SHL32(EXTEND32(M),15) && MULT16_32_Q15(st->leak_estimate,Syy) > MULT16_32_Q15(QCONST16(.03f,15),Syy)) + { + st->adapted = 1; + } + + if (st->adapted) + { + /* Normal learning rate calculation once we're past the minimal adaptation phase */ + for (i=0;i<=st->frame_size;i++) + { + spx_word32_t r, e; + /* Compute frequency-domain adaptation mask */ + r = MULT16_32_Q15(st->leak_estimate,SHL32(st->Yf[i],3)); + e = SHL32(st->Rf[i],3)+1; +#ifdef FIXED_POINT + if (r>SHR32(e,1)) + r = SHR32(e,1); +#else + if (r>.5*e) + r = .5*e; +#endif + r = MULT16_32_Q15(QCONST16(.7,15),r) + MULT16_32_Q15(QCONST16(.3,15),(spx_word32_t)(MULT16_32_Q15(RER,e))); + /*st->power_1[i] = adapt_rate*r/(e*(1+st->power[i]));*/ + st->power_1[i] = FLOAT_SHL(FLOAT_DIV32_FLOAT(r,FLOAT_MUL32U(e,st->power[i]+10)),WEIGHT_SHIFT+16); + } + } else { + /* Temporary adaption rate if filter is not yet adapted enough */ + spx_word16_t adapt_rate=0; + + if (Sxx > SHR32(MULT16_16(N, 1000),6)) + { + tmp32 = MULT16_32_Q15(QCONST16(.25f, 15), Sxx); +#ifdef FIXED_POINT + if (tmp32 > SHR32(See,2)) + tmp32 = SHR32(See,2); +#else + if (tmp32 > .25*See) + tmp32 = .25*See; +#endif + adapt_rate = FLOAT_EXTRACT16(FLOAT_SHL(FLOAT_DIV32(tmp32, See),15)); + } + for (i=0;i<=st->frame_size;i++) + st->power_1[i] = FLOAT_SHL(FLOAT_DIV32(EXTEND32(adapt_rate),ADD32(st->power[i],10)),WEIGHT_SHIFT+1); + + + /* How much have we adapted so far? */ + st->sum_adapt = ADD32(st->sum_adapt,adapt_rate); + } + + /* FIXME: MC conversion required */ + for (i=0;iframe_size;i++) + st->last_y[i] = st->last_y[st->frame_size+i]; + if (st->adapted) + { + /* If the filter is adapted, take the filtered echo */ + for (i=0;iframe_size;i++) + st->last_y[st->frame_size+i] = in[i]-out[i]; + } else { + /* If filter isn't adapted yet, all we can do is take the far end signal directly */ + /* moved earlier: for (i=0;ilast_y[i] = st->x[i];*/ + } + +} + +/* Compute spectrum of estimated echo for use in an echo post-filter */ +void speex_echo_get_residual(SpeexEchoState *st, spx_word32_t *residual_echo, int len) +{ + int i; + spx_word16_t leak2; + int N; + + N = st->window_size; + + /* Apply hanning window (should pre-compute it)*/ + for (i=0;iy[i] = MULT16_16_Q15(st->window[i],st->last_y[i]); + + /* Compute power spectrum of the echo */ + spx_fft(st->fft_table, st->y, st->Y); + power_spectrum(st->Y, residual_echo, N); + +#ifdef FIXED_POINT + if (st->leak_estimate > 16383) + leak2 = 32767; + else + leak2 = SHL16(st->leak_estimate, 1); +#else + if (st->leak_estimate>.5) + leak2 = 1; + else + leak2 = 2*st->leak_estimate; +#endif + /* Estimate residual echo */ + for (i=0;i<=st->frame_size;i++) + residual_echo[i] = (spx_int32_t)MULT16_32_Q15(leak2,residual_echo[i]); + +} + +EXPORT int speex_echo_ctl(SpeexEchoState *st, int request, void *ptr) +{ + switch(request) + { + + case SPEEX_ECHO_GET_FRAME_SIZE: + (*(int*)ptr) = st->frame_size; + break; + case SPEEX_ECHO_SET_SAMPLING_RATE: + st->sampling_rate = (*(int*)ptr); + st->spec_average = DIV32_16(SHL32(EXTEND32(st->frame_size), 15), st->sampling_rate); +#ifdef FIXED_POINT + st->beta0 = DIV32_16(SHL32(EXTEND32(st->frame_size), 16), st->sampling_rate); + st->beta_max = DIV32_16(SHL32(EXTEND32(st->frame_size), 14), st->sampling_rate); +#else + st->beta0 = (2.0f*st->frame_size)/st->sampling_rate; + st->beta_max = (.5f*st->frame_size)/st->sampling_rate; +#endif + if (st->sampling_rate<12000) + st->notch_radius = QCONST16(.9, 15); + else if (st->sampling_rate<24000) + st->notch_radius = QCONST16(.982, 15); + else + st->notch_radius = QCONST16(.992, 15); + break; + case SPEEX_ECHO_GET_SAMPLING_RATE: + (*(int*)ptr) = st->sampling_rate; + break; + case SPEEX_ECHO_GET_IMPULSE_RESPONSE_SIZE: + /*FIXME: Implement this for multiple channels */ + *((spx_int32_t *)ptr) = st->M * st->frame_size; + break; + case SPEEX_ECHO_GET_IMPULSE_RESPONSE: + { + int M = st->M, N = st->window_size, n = st->frame_size, i, j; + spx_int32_t *filt = (spx_int32_t *) ptr; + for(j=0;jwtmp2[i] = EXTRACT16(PSHR32(st->W[j*N+i],16+NORMALIZE_SCALEDOWN)); + spx_ifft(st->fft_table, st->wtmp2, st->wtmp); +#else + spx_ifft(st->fft_table, &st->W[j*N], st->wtmp); +#endif + for(i=0;iwtmp[i]), WEIGHT_SHIFT-NORMALIZE_SCALEDOWN); + } + } + break; + default: + speex_warning_int("Unknown speex_echo_ctl request: ", request); + return -1; + } + return 0; +} diff --git a/ios/IOSDuoduo/Voice/Code/Libs/libspeex/misc_bfin.h b/ios/IOSDuoduo/Voice/Code/Libs/libspeex/misc_bfin.h new file mode 100755 index 000000000..77b082c05 --- /dev/null +++ b/ios/IOSDuoduo/Voice/Code/Libs/libspeex/misc_bfin.h @@ -0,0 +1,54 @@ +/* Copyright (C) 2005 Analog Devices */ +/** + @file misc_bfin.h + @author Jean-Marc Valin + @brief Various compatibility routines for Speex (Blackfin version) +*/ +/* + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + - Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + - Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + - Neither the name of the Xiph.org Foundation nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR + CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#define OVERRIDE_SPEEX_MOVE +void *speex_move (void *dest, void *src, int n) +{ + __asm__ __volatile__ + ( + "L0 = 0;\n\t" + "I0 = %0;\n\t" + "R0 = [I0++];\n\t" + "LOOP move%= LC0 = %2;\n\t" + "LOOP_BEGIN move%=;\n\t" + "[%1++] = R0 || R0 = [I0++];\n\t" + "LOOP_END move%=;\n\t" + "[%1++] = R0;\n\t" + : "=a" (src), "=a" (dest) + : "a" ((n>>2)-1), "0" (src), "1" (dest) + : "R0", "I0", "L0", "memory" + ); + return dest; +} diff --git a/ios/IOSDuoduo/Voice/Code/Libs/libspeex/modes.c b/ios/IOSDuoduo/Voice/Code/Libs/libspeex/modes.c new file mode 100755 index 000000000..e10a32e8e --- /dev/null +++ b/ios/IOSDuoduo/Voice/Code/Libs/libspeex/modes.c @@ -0,0 +1,366 @@ +/* Copyright (C) 2002-2006 Jean-Marc Valin + File: modes.c + + Describes the different modes of the codec + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + - Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + - Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + - Neither the name of the Xiph.org Foundation nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR + CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +*/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "modes.h" +#include "ltp.h" +#include "quant_lsp.h" +#include "cb_search.h" +#include "sb_celp.h" +#include "nb_celp.h" +#include "vbr.h" +#include "arch.h" +#include + +#ifndef NULL +#define NULL 0 +#endif + + +/* Extern declarations for all codebooks we use here */ +extern const signed char gain_cdbk_nb[]; +extern const signed char gain_cdbk_lbr[]; +extern const signed char exc_5_256_table[]; +extern const signed char exc_5_64_table[]; +extern const signed char exc_8_128_table[]; +extern const signed char exc_10_32_table[]; +extern const signed char exc_10_16_table[]; +extern const signed char exc_20_32_table[]; + + +/* Parameters for Long-Term Prediction (LTP)*/ +static const ltp_params ltp_params_nb = { + gain_cdbk_nb, + 7, + 7 +}; + +/* Parameters for Long-Term Prediction (LTP)*/ +static const ltp_params ltp_params_vlbr = { + gain_cdbk_lbr, + 5, + 0 +}; + +/* Parameters for Long-Term Prediction (LTP)*/ +static const ltp_params ltp_params_lbr = { + gain_cdbk_lbr, + 5, + 7 +}; + +/* Parameters for Long-Term Prediction (LTP)*/ +static const ltp_params ltp_params_med = { + gain_cdbk_lbr, + 5, + 7 +}; + +/* Split-VQ innovation parameters for very low bit-rate narrowband */ +static const split_cb_params split_cb_nb_vlbr = { + 10, /*subvect_size*/ + 4, /*nb_subvect*/ + exc_10_16_table, /*shape_cb*/ + 4, /*shape_bits*/ + 0, +}; + +/* Split-VQ innovation parameters for very low bit-rate narrowband */ +static const split_cb_params split_cb_nb_ulbr = { + 20, /*subvect_size*/ + 2, /*nb_subvect*/ + exc_20_32_table, /*shape_cb*/ + 5, /*shape_bits*/ + 0, +}; + +/* Split-VQ innovation parameters for low bit-rate narrowband */ +static const split_cb_params split_cb_nb_lbr = { + 10, /*subvect_size*/ + 4, /*nb_subvect*/ + exc_10_32_table, /*shape_cb*/ + 5, /*shape_bits*/ + 0, +}; + + +/* Split-VQ innovation parameters narrowband */ +static const split_cb_params split_cb_nb = { + 5, /*subvect_size*/ + 8, /*nb_subvect*/ + exc_5_64_table, /*shape_cb*/ + 6, /*shape_bits*/ + 0, +}; + +/* Split-VQ innovation parameters narrowband */ +static const split_cb_params split_cb_nb_med = { + 8, /*subvect_size*/ + 5, /*nb_subvect*/ + exc_8_128_table, /*shape_cb*/ + 7, /*shape_bits*/ + 0, +}; + +/* Split-VQ innovation for low-band wideband */ +static const split_cb_params split_cb_sb = { + 5, /*subvect_size*/ + 8, /*nb_subvect*/ + exc_5_256_table, /*shape_cb*/ + 8, /*shape_bits*/ + 0, +}; + + + +/* 2150 bps "vocoder-like" mode for comfort noise */ +static const SpeexSubmode nb_submode1 = { + 0, + 1, + 0, + 0, + /* LSP quantization */ + lsp_quant_lbr, + lsp_unquant_lbr, + /* No pitch quantization */ + forced_pitch_quant, + forced_pitch_unquant, + NULL, + /* No innovation quantization (noise only) */ + noise_codebook_quant, + noise_codebook_unquant, + NULL, + -1, + 43 +}; + +/* 3.95 kbps very low bit-rate mode */ +static const SpeexSubmode nb_submode8 = { + 0, + 1, + 0, + 0, + /*LSP quantization*/ + lsp_quant_lbr, + lsp_unquant_lbr, + /*No pitch quantization*/ + forced_pitch_quant, + forced_pitch_unquant, + NULL, + /*Innovation quantization*/ + split_cb_search_shape_sign, + split_cb_shape_sign_unquant, + &split_cb_nb_ulbr, + QCONST16(.5,15), + 79 +}; + +/* 5.95 kbps very low bit-rate mode */ +static const SpeexSubmode nb_submode2 = { + 0, + 0, + 0, + 0, + /*LSP quantization*/ + lsp_quant_lbr, + lsp_unquant_lbr, + /*No pitch quantization*/ + pitch_search_3tap, + pitch_unquant_3tap, + <p_params_vlbr, + /*Innovation quantization*/ + split_cb_search_shape_sign, + split_cb_shape_sign_unquant, + &split_cb_nb_vlbr, + QCONST16(.6,15), + 119 +}; + +/* 8 kbps low bit-rate mode */ +static const SpeexSubmode nb_submode3 = { + -1, + 0, + 1, + 0, + /*LSP quantization*/ + lsp_quant_lbr, + lsp_unquant_lbr, + /*Pitch quantization*/ + pitch_search_3tap, + pitch_unquant_3tap, + <p_params_lbr, + /*Innovation quantization*/ + split_cb_search_shape_sign, + split_cb_shape_sign_unquant, + &split_cb_nb_lbr, + QCONST16(.55,15), + 160 +}; + +/* 11 kbps medium bit-rate mode */ +static const SpeexSubmode nb_submode4 = { + -1, + 0, + 1, + 0, + /*LSP quantization*/ + lsp_quant_lbr, + lsp_unquant_lbr, + /*Pitch quantization*/ + pitch_search_3tap, + pitch_unquant_3tap, + <p_params_med, + /*Innovation quantization*/ + split_cb_search_shape_sign, + split_cb_shape_sign_unquant, + &split_cb_nb_med, + QCONST16(.45,15), + 220 +}; + +/* 15 kbps high bit-rate mode */ +static const SpeexSubmode nb_submode5 = { + -1, + 0, + 3, + 0, + /*LSP quantization*/ + lsp_quant_nb, + lsp_unquant_nb, + /*Pitch quantization*/ + pitch_search_3tap, + pitch_unquant_3tap, + <p_params_nb, + /*Innovation quantization*/ + split_cb_search_shape_sign, + split_cb_shape_sign_unquant, + &split_cb_nb, + QCONST16(.3,15), + 300 +}; + +/* 18.2 high bit-rate mode */ +static const SpeexSubmode nb_submode6 = { + -1, + 0, + 3, + 0, + /*LSP quantization*/ + lsp_quant_nb, + lsp_unquant_nb, + /*Pitch quantization*/ + pitch_search_3tap, + pitch_unquant_3tap, + <p_params_nb, + /*Innovation quantization*/ + split_cb_search_shape_sign, + split_cb_shape_sign_unquant, + &split_cb_sb, + QCONST16(.2,15), + 364 +}; + +/* 24.6 kbps high bit-rate mode */ +static const SpeexSubmode nb_submode7 = { + -1, + 0, + 3, + 1, + /*LSP quantization*/ + lsp_quant_nb, + lsp_unquant_nb, + /*Pitch quantization*/ + pitch_search_3tap, + pitch_unquant_3tap, + <p_params_nb, + /*Innovation quantization*/ + split_cb_search_shape_sign, + split_cb_shape_sign_unquant, + &split_cb_nb, + QCONST16(.1,15), + 492 +}; + + +/* Default mode for narrowband */ +static const SpeexNBMode nb_mode = { + 160, /*frameSize*/ + 40, /*subframeSize*/ + 10, /*lpcSize*/ + 17, /*pitchStart*/ + 144, /*pitchEnd*/ +#ifdef FIXED_POINT + 29491, 19661, /* gamma1, gamma2 */ +#else + 0.9, 0.6, /* gamma1, gamma2 */ +#endif + QCONST16(.0002,15), /*lpc_floor*/ + {NULL, &nb_submode1, &nb_submode2, &nb_submode3, &nb_submode4, &nb_submode5, &nb_submode6, &nb_submode7, + &nb_submode8, NULL, NULL, NULL, NULL, NULL, NULL, NULL}, + 5, + {1, 8, 2, 3, 3, 4, 4, 5, 5, 6, 7} +}; + + +/* Default mode for narrowband */ +EXPORT const SpeexMode speex_nb_mode = { + &nb_mode, + nb_mode_query, + "narrowband", + 0, + 4, + &nb_encoder_init, + &nb_encoder_destroy, + &nb_encode, + &nb_decoder_init, + &nb_decoder_destroy, + &nb_decode, + &nb_encoder_ctl, + &nb_decoder_ctl, +}; + + + +EXPORT int speex_mode_query(const SpeexMode *mode, int request, void *ptr) +{ + return mode->query(mode->mode, request, ptr); +} + +#ifdef FIXED_DEBUG +long long spx_mips=0; +#endif + diff --git a/ios/IOSDuoduo/Voice/Code/Libs/libspeex/modes.h b/ios/IOSDuoduo/Voice/Code/Libs/libspeex/modes.h new file mode 100755 index 000000000..0fa1c3460 --- /dev/null +++ b/ios/IOSDuoduo/Voice/Code/Libs/libspeex/modes.h @@ -0,0 +1,161 @@ +/* Copyright (C) 2002-2006 Jean-Marc Valin */ +/** + @file modes.h + @brief Describes the different modes of the codec +*/ +/* + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + - Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + - Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + - Neither the name of the Xiph.org Foundation nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR + CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +*/ + +#ifndef MODES_H +#define MODES_H + +#include "speex/speex.h" +#include "speex/speex_bits.h" +#include "arch.h" + +#define NB_SUBMODES 16 +#define NB_SUBMODE_BITS 4 + +#define SB_SUBMODES 8 +#define SB_SUBMODE_BITS 3 + +/* Used internally, NOT TO BE USED in applications */ +/** Used internally*/ +#define SPEEX_GET_PI_GAIN 100 +/** Used internally*/ +#define SPEEX_GET_EXC 101 +/** Used internally*/ +#define SPEEX_GET_INNOV 102 +/** Used internally*/ +#define SPEEX_GET_DTX_STATUS 103 +/** Used internally*/ +#define SPEEX_SET_INNOVATION_SAVE 104 +/** Used internally*/ +#define SPEEX_SET_WIDEBAND 105 + +/** Used internally*/ +#define SPEEX_GET_STACK 106 + + +/** Quantizes LSPs */ +typedef void (*lsp_quant_func)(spx_lsp_t *, spx_lsp_t *, int, SpeexBits *); + +/** Decodes quantized LSPs */ +typedef void (*lsp_unquant_func)(spx_lsp_t *, int, SpeexBits *); + + +/** Long-term predictor quantization */ +typedef int (*ltp_quant_func)(spx_word16_t *, spx_word16_t *, spx_coef_t *, spx_coef_t *, + spx_coef_t *, spx_sig_t *, const void *, int, int, spx_word16_t, + int, int, SpeexBits*, char *, spx_word16_t *, spx_word16_t *, int, int, int, spx_word32_t *); + +/** Long-term un-quantize */ +typedef void (*ltp_unquant_func)(spx_word16_t *, spx_word32_t *, int, int, spx_word16_t, const void *, int, int *, + spx_word16_t *, SpeexBits*, char*, int, int, spx_word16_t, int); + + +/** Innovation quantization function */ +typedef void (*innovation_quant_func)(spx_word16_t *, spx_coef_t *, spx_coef_t *, spx_coef_t *, const void *, int, int, + spx_sig_t *, spx_word16_t *, SpeexBits *, char *, int, int); + +/** Innovation unquantization function */ +typedef void (*innovation_unquant_func)(spx_sig_t *, const void *, int, SpeexBits*, char *, spx_int32_t *); + +/** Description of a Speex sub-mode (wither narrowband or wideband */ +typedef struct SpeexSubmode { + int lbr_pitch; /**< Set to -1 for "normal" modes, otherwise encode pitch using a global pitch and allowing a +- lbr_pitch variation (for low not-rates)*/ + int forced_pitch_gain; /**< Use the same (forced) pitch gain for all sub-frames */ + int have_subframe_gain; /**< Number of bits to use as sub-frame innovation gain */ + int double_codebook; /**< Apply innovation quantization twice for higher quality (and higher bit-rate)*/ + /*LSP functions*/ + lsp_quant_func lsp_quant; /**< LSP quantization function */ + lsp_unquant_func lsp_unquant; /**< LSP unquantization function */ + + /*Long-term predictor functions*/ + ltp_quant_func ltp_quant; /**< Long-term predictor (pitch) quantizer */ + ltp_unquant_func ltp_unquant; /**< Long-term predictor (pitch) un-quantizer */ + const void *ltp_params; /**< Pitch parameters (options) */ + + /*Quantization of innovation*/ + innovation_quant_func innovation_quant; /**< Innovation quantization */ + innovation_unquant_func innovation_unquant; /**< Innovation un-quantization */ + const void *innovation_params; /**< Innovation quantization parameters*/ + + spx_word16_t comb_gain; /**< Gain of enhancer comb filter */ + + int bits_per_frame; /**< Number of bits per frame after encoding*/ +} SpeexSubmode; + +/** Struct defining the encoding/decoding mode*/ +typedef struct SpeexNBMode { + int frameSize; /**< Size of frames used for encoding */ + int subframeSize; /**< Size of sub-frames used for encoding */ + int lpcSize; /**< Order of LPC filter */ + int pitchStart; /**< Smallest pitch value allowed */ + int pitchEnd; /**< Largest pitch value allowed */ + + spx_word16_t gamma1; /**< Perceptual filter parameter #1 */ + spx_word16_t gamma2; /**< Perceptual filter parameter #2 */ + spx_word16_t lpc_floor; /**< Noise floor for LPC analysis */ + + const SpeexSubmode *submodes[NB_SUBMODES]; /**< Sub-mode data for the mode */ + int defaultSubmode; /**< Default sub-mode to use when encoding */ + int quality_map[11]; /**< Mode corresponding to each quality setting */ +} SpeexNBMode; + + +/** Struct defining the encoding/decoding mode for SB-CELP (wideband) */ +typedef struct SpeexSBMode { + const SpeexMode *nb_mode; /**< Embedded narrowband mode */ + int frameSize; /**< Size of frames used for encoding */ + int subframeSize; /**< Size of sub-frames used for encoding */ + int lpcSize; /**< Order of LPC filter */ + spx_word16_t gamma1; /**< Perceptual filter parameter #1 */ + spx_word16_t gamma2; /**< Perceptual filter parameter #1 */ + spx_word16_t lpc_floor; /**< Noise floor for LPC analysis */ + spx_word16_t folding_gain; + + const SpeexSubmode *submodes[SB_SUBMODES]; /**< Sub-mode data for the mode */ + int defaultSubmode; /**< Default sub-mode to use when encoding */ + int low_quality_map[11]; /**< Mode corresponding to each quality setting */ + int quality_map[11]; /**< Mode corresponding to each quality setting */ +#ifndef DISABLE_VBR + const float (*vbr_thresh)[11]; +#endif + int nb_modes; +} SpeexSBMode; + +int speex_encode_native(void *state, spx_word16_t *in, SpeexBits *bits); +int speex_decode_native(void *state, SpeexBits *bits, spx_word16_t *out); + +int nb_mode_query(const void *mode, int request, void *ptr); +int wb_mode_query(const void *mode, int request, void *ptr); + +#endif diff --git a/ios/IOSDuoduo/Voice/Code/Libs/libspeex/modes_wb.c b/ios/IOSDuoduo/Voice/Code/Libs/libspeex/modes_wb.c new file mode 100755 index 000000000..e3b484223 --- /dev/null +++ b/ios/IOSDuoduo/Voice/Code/Libs/libspeex/modes_wb.c @@ -0,0 +1,300 @@ +/* Copyright (C) 2002-2007 Jean-Marc Valin + File: modes.c + + Describes the wideband modes of the codec + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + - Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + - Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + - Neither the name of the Xiph.org Foundation nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR + CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +*/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "modes.h" +#include "ltp.h" +#include "quant_lsp.h" +#include "cb_search.h" +#include "sb_celp.h" +#include "nb_celp.h" +#include "vbr.h" +#include "arch.h" +#include +#include "os_support.h" + + +#ifndef NULL +#define NULL 0 +#endif + +EXPORT const SpeexMode * const speex_mode_list[SPEEX_NB_MODES] = {&speex_nb_mode, &speex_wb_mode, &speex_uwb_mode}; + +extern const signed char hexc_table[]; +extern const signed char hexc_10_32_table[]; + +#ifndef DISABLE_WIDEBAND + +/* Split-VQ innovation for high-band wideband */ +static const split_cb_params split_cb_high = { + 8, /*subvect_size*/ + 5, /*nb_subvect*/ + hexc_table, /*shape_cb*/ + 7, /*shape_bits*/ + 1, +}; + + +/* Split-VQ innovation for high-band wideband */ +static const split_cb_params split_cb_high_lbr = { + 10, /*subvect_size*/ + 4, /*nb_subvect*/ + hexc_10_32_table, /*shape_cb*/ + 5, /*shape_bits*/ + 0, +}; + +#endif + + +static const SpeexSubmode wb_submode1 = { + 0, + 0, + 1, + 0, + /*LSP quantization*/ + lsp_quant_high, + lsp_unquant_high, + /*Pitch quantization*/ + NULL, + NULL, + NULL, + /*No innovation quantization*/ + NULL, + NULL, + NULL, + -1, + 36 +}; + + +static const SpeexSubmode wb_submode2 = { + 0, + 0, + 1, + 0, + /*LSP quantization*/ + lsp_quant_high, + lsp_unquant_high, + /*Pitch quantization*/ + NULL, + NULL, + NULL, + /*Innovation quantization*/ + split_cb_search_shape_sign, + split_cb_shape_sign_unquant, +#ifdef DISABLE_WIDEBAND + NULL, +#else + &split_cb_high_lbr, +#endif + -1, + 112 +}; + + +static const SpeexSubmode wb_submode3 = { + 0, + 0, + 1, + 0, + /*LSP quantization*/ + lsp_quant_high, + lsp_unquant_high, + /*Pitch quantization*/ + NULL, + NULL, + NULL, + /*Innovation quantization*/ + split_cb_search_shape_sign, + split_cb_shape_sign_unquant, +#ifdef DISABLE_WIDEBAND + NULL, +#else + &split_cb_high, +#endif + -1, + 192 +}; + +static const SpeexSubmode wb_submode4 = { + 0, + 0, + 1, + 1, + /*LSP quantization*/ + lsp_quant_high, + lsp_unquant_high, + /*Pitch quantization*/ + NULL, + NULL, + NULL, + /*Innovation quantization*/ + split_cb_search_shape_sign, + split_cb_shape_sign_unquant, +#ifdef DISABLE_WIDEBAND + NULL, +#else + &split_cb_high, +#endif + -1, + 352 +}; + + +/* Split-band wideband CELP mode*/ +static const SpeexSBMode sb_wb_mode = { + &speex_nb_mode, + 160, /*frameSize*/ + 40, /*subframeSize*/ + 8, /*lpcSize*/ +#ifdef FIXED_POINT + 29491, 19661, /* gamma1, gamma2 */ +#else + 0.9, 0.6, /* gamma1, gamma2 */ +#endif + QCONST16(.0002,15), /*lpc_floor*/ + QCONST16(0.9f,15), + {NULL, &wb_submode1, &wb_submode2, &wb_submode3, &wb_submode4, NULL, NULL, NULL}, + 3, + {1, 8, 2, 3, 4, 5, 5, 6, 6, 7, 7}, + {1, 1, 1, 1, 1, 1, 2, 2, 3, 3, 4}, +#ifndef DISABLE_VBR + vbr_hb_thresh, +#endif + 5 +}; + + +EXPORT const SpeexMode speex_wb_mode = { + &sb_wb_mode, + wb_mode_query, + "wideband (sub-band CELP)", + 1, + 4, + &sb_encoder_init, + &sb_encoder_destroy, + &sb_encode, + &sb_decoder_init, + &sb_decoder_destroy, + &sb_decode, + &sb_encoder_ctl, + &sb_decoder_ctl, +}; + + + +/* "Ultra-wideband" mode stuff */ + + + +/* Split-band "ultra-wideband" (32 kbps) CELP mode*/ +static const SpeexSBMode sb_uwb_mode = { + &speex_wb_mode, + 320, /*frameSize*/ + 80, /*subframeSize*/ + 8, /*lpcSize*/ +#ifdef FIXED_POINT + 29491, 19661, /* gamma1, gamma2 */ +#else + 0.9, 0.6, /* gamma1, gamma2 */ +#endif + QCONST16(.0002,15), /*lpc_floor*/ + QCONST16(0.7f,15), + {NULL, &wb_submode1, NULL, NULL, NULL, NULL, NULL, NULL}, + 1, + {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10}, + {0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}, +#ifndef DISABLE_VBR + vbr_uhb_thresh, +#endif + 2 +}; + +int wb_mode_query(const void *mode, int request, void *ptr) +{ + const SpeexSBMode *m = (const SpeexSBMode*)mode; + + switch (request) + { + case SPEEX_MODE_FRAME_SIZE: + *((int*)ptr)=2*m->frameSize; + break; + case SPEEX_SUBMODE_BITS_PER_FRAME: + if (*((int*)ptr)==0) + *((int*)ptr) = SB_SUBMODE_BITS+1; + else if (m->submodes[*((int*)ptr)]==NULL) + *((int*)ptr) = -1; + else + *((int*)ptr) = m->submodes[*((int*)ptr)]->bits_per_frame; + break; + default: + speex_warning_int("Unknown wb_mode_query request: ", request); + return -1; + } + return 0; +} + + +EXPORT const SpeexMode speex_uwb_mode = { + &sb_uwb_mode, + wb_mode_query, + "ultra-wideband (sub-band CELP)", + 2, + 4, + &sb_encoder_init, + &sb_encoder_destroy, + &sb_encode, + &sb_decoder_init, + &sb_decoder_destroy, + &sb_decode, + &sb_encoder_ctl, + &sb_decoder_ctl, +}; + +/* We have defined speex_lib_get_mode() as a macro in speex.h */ +#undef speex_lib_get_mode + +EXPORT const SpeexMode * speex_lib_get_mode (int mode) +{ + if (mode < 0 || mode >= SPEEX_NB_MODES) return NULL; + + return speex_mode_list[mode]; +} + + + diff --git a/ios/IOSDuoduo/Voice/Code/Libs/libspeex/nb_celp.c b/ios/IOSDuoduo/Voice/Code/Libs/libspeex/nb_celp.c new file mode 100755 index 000000000..14d06f183 --- /dev/null +++ b/ios/IOSDuoduo/Voice/Code/Libs/libspeex/nb_celp.c @@ -0,0 +1,1903 @@ +/* Copyright (C) 2002-2006 Jean-Marc Valin + File: nb_celp.c + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + - Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + - Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + - Neither the name of the Xiph.org Foundation nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR + CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include +#include "nb_celp.h" +#include "lpc.h" +#include "lsp.h" +#include "ltp.h" +#include "quant_lsp.h" +#include "cb_search.h" +#include "filters.h" +#include "stack_alloc.h" +#include "vq.h" +#include "speex/speex_bits.h" +#include "vbr.h" +#include "arch.h" +#include "math_approx.h" +#include "os_support.h" +#include "speex/speex_callbacks.h" + +#ifdef VORBIS_PSYCHO +#include "vorbis_psy.h" +#endif + +#ifndef M_PI +#define M_PI 3.14159265358979323846 /* pi */ +#endif + +#ifndef NULL +#define NULL 0 +#endif + +#define SUBMODE(x) st->submodes[st->submodeID]->x + +/* Default size for the encoder and decoder stack (can be changed at compile time). + This does not apply when using variable-size arrays or alloca. */ +#ifndef NB_ENC_STACK +#define NB_ENC_STACK (8000*sizeof(spx_sig_t)) +#endif + +#ifndef NB_DEC_STACK +#define NB_DEC_STACK (4000*sizeof(spx_sig_t)) +#endif + + +#ifdef FIXED_POINT +const spx_word32_t ol_gain_table[32]={18900, 25150, 33468, 44536, 59265, 78865, 104946, 139653, 185838, 247297, 329081, 437913, 582736, 775454, 1031906, 1373169, 1827293, 2431601, 3235761, 4305867, 5729870, 7624808, 10146425, 13501971, 17967238, 23909222, 31816294, 42338330, 56340132, 74972501, 99766822, 132760927}; +const spx_word16_t exc_gain_quant_scal3_bound[7]={1841, 3883, 6051, 8062, 10444, 13580, 18560}; +const spx_word16_t exc_gain_quant_scal3[8]={1002, 2680, 5086, 7016, 9108, 11781, 15380, 21740}; +const spx_word16_t exc_gain_quant_scal1_bound[1]={14385}; +const spx_word16_t exc_gain_quant_scal1[2]={11546, 17224}; + +#define LSP_MARGIN 16 +#define LSP_DELTA1 6553 +#define LSP_DELTA2 1638 + +#else + +const float exc_gain_quant_scal3_bound[7]={0.112338f, 0.236980f, 0.369316f, 0.492054f, 0.637471f, 0.828874f, 1.132784f}; +const float exc_gain_quant_scal3[8]={0.061130f, 0.163546f, 0.310413f, 0.428220f, 0.555887f, 0.719055f, 0.938694f, 1.326874f}; +const float exc_gain_quant_scal1_bound[1]={0.87798f}; +const float exc_gain_quant_scal1[2]={0.70469f, 1.05127f}; + +#define LSP_MARGIN .002f +#define LSP_DELTA1 .2f +#define LSP_DELTA2 .05f + +#endif + +#ifdef VORBIS_PSYCHO +#define EXTRA_BUFFER 100 +#else +#define EXTRA_BUFFER 0 +#endif + + +#define sqr(x) ((x)*(x)) + +extern const spx_word16_t lag_window[]; +extern const spx_word16_t lpc_window[]; + +void *nb_encoder_init(const SpeexMode *m) +{ + EncState *st; + const SpeexNBMode *mode; + int i; + + mode=(const SpeexNBMode *)m->mode; + st = (EncState*)speex_alloc(sizeof(EncState)); + if (!st) + return NULL; +#if defined(VAR_ARRAYS) || defined (USE_ALLOCA) + st->stack = NULL; +#else + st->stack = (char*)speex_alloc_scratch(NB_ENC_STACK); +#endif + + st->mode=m; + + st->frameSize = mode->frameSize; + st->nbSubframes=mode->frameSize/mode->subframeSize; + st->subframeSize=mode->subframeSize; + st->windowSize = st->frameSize+st->subframeSize; + st->lpcSize = mode->lpcSize; + st->gamma1=mode->gamma1; + st->gamma2=mode->gamma2; + st->min_pitch=mode->pitchStart; + st->max_pitch=mode->pitchEnd; + st->lpc_floor = mode->lpc_floor; + + st->submodes=mode->submodes; + st->submodeID=st->submodeSelect=mode->defaultSubmode; + st->bounded_pitch = 1; + + st->encode_submode = 1; + +#ifdef VORBIS_PSYCHO + st->psy = vorbis_psy_init(8000, 256); + st->curve = (float*)speex_alloc(128*sizeof(float)); + st->old_curve = (float*)speex_alloc(128*sizeof(float)); + st->psy_window = (float*)speex_alloc(256*sizeof(float)); +#endif + + st->cumul_gain = 1024; + + /* Allocating input buffer */ + st->winBuf = (spx_word16_t*)speex_alloc((st->windowSize-st->frameSize)*sizeof(spx_word16_t)); + /* Allocating excitation buffer */ + st->excBuf = (spx_word16_t*)speex_alloc((mode->frameSize+mode->pitchEnd+2)*sizeof(spx_word16_t)); + st->exc = st->excBuf + mode->pitchEnd + 2; + st->swBuf = (spx_word16_t*)speex_alloc((mode->frameSize+mode->pitchEnd+2)*sizeof(spx_word16_t)); + st->sw = st->swBuf + mode->pitchEnd + 2; + + st->window= lpc_window; + + /* Create the window for autocorrelation (lag-windowing) */ + st->lagWindow = lag_window; + + st->old_lsp = (spx_lsp_t*)speex_alloc((st->lpcSize)*sizeof(spx_lsp_t)); + st->old_qlsp = (spx_lsp_t*)speex_alloc((st->lpcSize)*sizeof(spx_lsp_t)); + st->first = 1; + for (i=0;ilpcSize;i++) + st->old_lsp[i]= DIV32(MULT16_16(QCONST16(3.1415927f, LSP_SHIFT), i+1), st->lpcSize+1); + + st->mem_sp = (spx_mem_t*)speex_alloc((st->lpcSize)*sizeof(spx_mem_t)); + st->mem_sw = (spx_mem_t*)speex_alloc((st->lpcSize)*sizeof(spx_mem_t)); + st->mem_sw_whole = (spx_mem_t*)speex_alloc((st->lpcSize)*sizeof(spx_mem_t)); + st->mem_exc = (spx_mem_t*)speex_alloc((st->lpcSize)*sizeof(spx_mem_t)); + st->mem_exc2 = (spx_mem_t*)speex_alloc((st->lpcSize)*sizeof(spx_mem_t)); + + st->pi_gain = (spx_word32_t*)speex_alloc((st->nbSubframes)*sizeof(spx_word32_t)); + st->innov_rms_save = NULL; + + st->pitch = (int*)speex_alloc((st->nbSubframes)*sizeof(int)); + +#ifndef DISABLE_VBR + st->vbr = (VBRState*)speex_alloc(sizeof(VBRState)); + vbr_init(st->vbr); + st->vbr_quality = 8; + st->vbr_enabled = 0; + st->vbr_max = 0; + st->vad_enabled = 0; + st->dtx_enabled = 0; + st->dtx_count=0; + st->abr_enabled = 0; + st->abr_drift = 0; + st->abr_drift2 = 0; +#endif /* #ifndef DISABLE_VBR */ + + st->plc_tuning = 2; + st->complexity=2; + st->sampling_rate=8000; + st->isWideband = 0; + st->highpass_enabled = 1; + +#ifdef ENABLE_VALGRIND + VALGRIND_MAKE_READABLE(st, NB_ENC_STACK); +#endif + return st; +} + +void nb_encoder_destroy(void *state) +{ + EncState *st=(EncState *)state; + /* Free all allocated memory */ +#if !(defined(VAR_ARRAYS) || defined (USE_ALLOCA)) + speex_free_scratch(st->stack); +#endif + + speex_free (st->winBuf); + speex_free (st->excBuf); + speex_free (st->old_qlsp); + speex_free (st->swBuf); + + speex_free (st->old_lsp); + speex_free (st->mem_sp); + speex_free (st->mem_sw); + speex_free (st->mem_sw_whole); + speex_free (st->mem_exc); + speex_free (st->mem_exc2); + speex_free (st->pi_gain); + speex_free (st->pitch); + +#ifndef DISABLE_VBR + vbr_destroy(st->vbr); + speex_free (st->vbr); +#endif /* #ifndef DISABLE_VBR */ + +#ifdef VORBIS_PSYCHO + vorbis_psy_destroy(st->psy); + speex_free (st->curve); + speex_free (st->old_curve); + speex_free (st->psy_window); +#endif + + /*Free state memory... should be last*/ + speex_free(st); +} + +int nb_encode(void *state, void *vin, SpeexBits *bits) +{ + EncState *st; + int i, sub, roots; + int ol_pitch; + spx_word16_t ol_pitch_coef; + spx_word32_t ol_gain; + VARDECL(spx_word16_t *ringing); + VARDECL(spx_word16_t *target); + VARDECL(spx_sig_t *innov); + VARDECL(spx_word32_t *exc32); + VARDECL(spx_mem_t *mem); + VARDECL(spx_coef_t *bw_lpc1); + VARDECL(spx_coef_t *bw_lpc2); + VARDECL(spx_coef_t *lpc); + VARDECL(spx_lsp_t *lsp); + VARDECL(spx_lsp_t *qlsp); + VARDECL(spx_lsp_t *interp_lsp); + VARDECL(spx_lsp_t *interp_qlsp); + VARDECL(spx_coef_t *interp_lpc); + VARDECL(spx_coef_t *interp_qlpc); + char *stack; + VARDECL(spx_word16_t *syn_resp); + VARDECL(spx_word16_t *real_exc); + + spx_word32_t ener=0; + spx_word16_t fine_gain; + spx_word16_t *in = (spx_word16_t*)vin; + + st=(EncState *)state; + stack=st->stack; + + ALLOC(lpc, st->lpcSize, spx_coef_t); + ALLOC(bw_lpc1, st->lpcSize, spx_coef_t); + ALLOC(bw_lpc2, st->lpcSize, spx_coef_t); + ALLOC(lsp, st->lpcSize, spx_lsp_t); + ALLOC(qlsp, st->lpcSize, spx_lsp_t); + ALLOC(interp_lsp, st->lpcSize, spx_lsp_t); + ALLOC(interp_qlsp, st->lpcSize, spx_lsp_t); + ALLOC(interp_lpc, st->lpcSize, spx_coef_t); + ALLOC(interp_qlpc, st->lpcSize, spx_coef_t); + + /* Move signals 1 frame towards the past */ + SPEEX_MOVE(st->excBuf, st->excBuf+st->frameSize, st->max_pitch+2); + SPEEX_MOVE(st->swBuf, st->swBuf+st->frameSize, st->max_pitch+2); + + if (st->highpass_enabled) + highpass(in, in, st->frameSize, (st->isWideband?HIGHPASS_WIDEBAND:HIGHPASS_NARROWBAND)|HIGHPASS_INPUT, st->mem_hp); + + { + VARDECL(spx_word16_t *w_sig); + VARDECL(spx_word16_t *autocorr); + ALLOC(w_sig, st->windowSize, spx_word16_t); + ALLOC(autocorr, st->lpcSize+1, spx_word16_t); + /* Window for analysis */ + for (i=0;iwindowSize-st->frameSize;i++) + w_sig[i] = EXTRACT16(SHR32(MULT16_16(st->winBuf[i],st->window[i]),SIG_SHIFT)); + for (;iwindowSize;i++) + w_sig[i] = EXTRACT16(SHR32(MULT16_16(in[i-st->windowSize+st->frameSize],st->window[i]),SIG_SHIFT)); + /* Compute auto-correlation */ + _spx_autocorr(w_sig, autocorr, st->lpcSize+1, st->windowSize); + autocorr[0] = ADD16(autocorr[0],MULT16_16_Q15(autocorr[0],st->lpc_floor)); /* Noise floor in auto-correlation domain */ + + /* Lag windowing: equivalent to filtering in the power-spectrum domain */ + for (i=0;ilpcSize+1;i++) + autocorr[i] = MULT16_16_Q14(autocorr[i],st->lagWindow[i]); + + /* Levinson-Durbin */ + _spx_lpc(lpc, autocorr, st->lpcSize); + /* LPC to LSPs (x-domain) transform */ + roots=lpc_to_lsp (lpc, st->lpcSize, lsp, 10, LSP_DELTA1, stack); + /* Check if we found all the roots */ + if (roots!=st->lpcSize) + { + /*If we can't find all LSP's, do some damage control and use previous filter*/ + for (i=0;ilpcSize;i++) + { + lsp[i]=st->old_lsp[i]; + } + } + } + + + + + /* Whole frame analysis (open-loop estimation of pitch and excitation gain) */ + { + int diff = st->windowSize-st->frameSize; + if (st->first) + for (i=0;ilpcSize;i++) + interp_lsp[i] = lsp[i]; + else + lsp_interpolate(st->old_lsp, lsp, interp_lsp, st->lpcSize, st->nbSubframes, st->nbSubframes<<1); + + lsp_enforce_margin(interp_lsp, st->lpcSize, LSP_MARGIN); + + /* Compute interpolated LPCs (unquantized) for whole frame*/ + lsp_to_lpc(interp_lsp, interp_lpc, st->lpcSize,stack); + + + /*Open-loop pitch*/ + if (!st->submodes[st->submodeID] || (st->complexity>2 && SUBMODE(have_subframe_gain)<3) || SUBMODE(forced_pitch_gain) || SUBMODE(lbr_pitch) != -1 +#ifndef DISABLE_VBR + || st->vbr_enabled || st->vad_enabled +#endif + ) + { + int nol_pitch[6]; + spx_word16_t nol_pitch_coef[6]; + + bw_lpc(st->gamma1, interp_lpc, bw_lpc1, st->lpcSize); + bw_lpc(st->gamma2, interp_lpc, bw_lpc2, st->lpcSize); + + SPEEX_COPY(st->sw, st->winBuf, diff); + SPEEX_COPY(st->sw+diff, in, st->frameSize-diff); + filter_mem16(st->sw, bw_lpc1, bw_lpc2, st->sw, st->frameSize, st->lpcSize, st->mem_sw_whole, stack); + + open_loop_nbest_pitch(st->sw, st->min_pitch, st->max_pitch, st->frameSize, + nol_pitch, nol_pitch_coef, 6, stack); + ol_pitch=nol_pitch[0]; + ol_pitch_coef = nol_pitch_coef[0]; + /*Try to remove pitch multiples*/ + for (i=1;i<6;i++) + { +#ifdef FIXED_POINT + if ((nol_pitch_coef[i]>MULT16_16_Q15(nol_pitch_coef[0],27853)) && +#else + if ((nol_pitch_coef[i]>.85*nol_pitch_coef[0]) && +#endif + (ABS(2*nol_pitch[i]-ol_pitch)<=2 || ABS(3*nol_pitch[i]-ol_pitch)<=3 || + ABS(4*nol_pitch[i]-ol_pitch)<=4 || ABS(5*nol_pitch[i]-ol_pitch)<=5)) + { + /*ol_pitch_coef=nol_pitch_coef[i];*/ + ol_pitch = nol_pitch[i]; + } + } + /*if (ol_pitch>50) + ol_pitch/=2;*/ + /*ol_pitch_coef = sqrt(ol_pitch_coef);*/ + + } else { + ol_pitch=0; + ol_pitch_coef=0; + } + + /*Compute "real" excitation*/ + SPEEX_COPY(st->exc, st->winBuf, diff); + SPEEX_COPY(st->exc+diff, in, st->frameSize-diff); + fir_mem16(st->exc, interp_lpc, st->exc, st->frameSize, st->lpcSize, st->mem_exc, stack); + + /* Compute open-loop excitation gain */ + { + spx_word16_t g = compute_rms16(st->exc, st->frameSize); + if (st->submodeID!=1 && ol_pitch>0) + ol_gain = MULT16_16(g, MULT16_16_Q14(QCONST16(1.1,14), + spx_sqrt(QCONST32(1.,28)-MULT16_32_Q15(QCONST16(.8,15),SHL32(MULT16_16(ol_pitch_coef,ol_pitch_coef),16))))); + else + ol_gain = SHL32(EXTEND32(g),SIG_SHIFT); + } + } + +#ifdef VORBIS_PSYCHO + SPEEX_MOVE(st->psy_window, st->psy_window+st->frameSize, 256-st->frameSize); + SPEEX_COPY(&st->psy_window[256-st->frameSize], in, st->frameSize); + compute_curve(st->psy, st->psy_window, st->curve); + /*print_vec(st->curve, 128, "curve");*/ + if (st->first) + SPEEX_COPY(st->old_curve, st->curve, 128); +#endif + + /*VBR stuff*/ +#ifndef DISABLE_VBR + if (st->vbr && (st->vbr_enabled||st->vad_enabled)) + { + float lsp_dist=0; + for (i=0;ilpcSize;i++) + lsp_dist += (st->old_lsp[i] - lsp[i])*(st->old_lsp[i] - lsp[i]); + lsp_dist /= LSP_SCALING*LSP_SCALING; + + if (st->abr_enabled) + { + float qual_change=0; + if (st->abr_drift2 * st->abr_drift > 0) + { + /* Only adapt if long-term and short-term drift are the same sign */ + qual_change = -.00001*st->abr_drift/(1+st->abr_count); + if (qual_change>.05) + qual_change=.05; + if (qual_change<-.05) + qual_change=-.05; + } + st->vbr_quality += qual_change; + if (st->vbr_quality>10) + st->vbr_quality=10; + if (st->vbr_quality<0) + st->vbr_quality=0; + } + + st->relative_quality = vbr_analysis(st->vbr, in, st->frameSize, ol_pitch, GAIN_SCALING_1*ol_pitch_coef); + /*if (delta_qual<0)*/ + /* delta_qual*=.1*(3+st->vbr_quality);*/ + if (st->vbr_enabled) + { + spx_int32_t mode; + int choice=0; + float min_diff=100; + mode = 8; + while (mode) + { + int v1; + float thresh; + v1=(int)floor(st->vbr_quality); + if (v1==10) + thresh = vbr_nb_thresh[mode][v1]; + else + thresh = (st->vbr_quality-v1)*vbr_nb_thresh[mode][v1+1] + (1+v1-st->vbr_quality)*vbr_nb_thresh[mode][v1]; + if (st->relative_quality > thresh && + st->relative_quality-threshrelative_quality-thresh; + } + mode--; + } + mode=choice; + if (mode==0) + { + if (st->dtx_count==0 || lsp_dist>.05 || !st->dtx_enabled || st->dtx_count>20) + { + mode=1; + st->dtx_count=1; + } else { + mode=0; + st->dtx_count++; + } + } else { + st->dtx_count=0; + } + + speex_encoder_ctl(state, SPEEX_SET_MODE, &mode); + if (st->vbr_max>0) + { + spx_int32_t rate; + speex_encoder_ctl(state, SPEEX_GET_BITRATE, &rate); + if (rate > st->vbr_max) + { + rate = st->vbr_max; + speex_encoder_ctl(state, SPEEX_SET_BITRATE, &rate); + } + } + + if (st->abr_enabled) + { + spx_int32_t bitrate; + speex_encoder_ctl(state, SPEEX_GET_BITRATE, &bitrate); + st->abr_drift+=(bitrate-st->abr_enabled); + st->abr_drift2 = .95*st->abr_drift2 + .05*(bitrate-st->abr_enabled); + st->abr_count += 1.0; + } + + } else { + /*VAD only case*/ + int mode; + if (st->relative_quality<2) + { + if (st->dtx_count==0 || lsp_dist>.05 || !st->dtx_enabled || st->dtx_count>20) + { + st->dtx_count=1; + mode=1; + } else { + mode=0; + st->dtx_count++; + } + } else { + st->dtx_count = 0; + mode=st->submodeSelect; + } + /*speex_encoder_ctl(state, SPEEX_SET_MODE, &mode);*/ + st->submodeID=mode; + } + } else { + st->relative_quality = -1; + } +#endif /* #ifndef DISABLE_VBR */ + + if (st->encode_submode) + { + /* First, transmit a zero for narrowband */ + speex_bits_pack(bits, 0, 1); + + /* Transmit the sub-mode we use for this frame */ + speex_bits_pack(bits, st->submodeID, NB_SUBMODE_BITS); + + } + + /* If null mode (no transmission), just set a couple things to zero*/ + if (st->submodes[st->submodeID] == NULL) + { + for (i=0;iframeSize;i++) + st->exc[i]=st->sw[i]=VERY_SMALL; + + for (i=0;ilpcSize;i++) + st->mem_sw[i]=0; + st->first=1; + st->bounded_pitch = 1; + + SPEEX_COPY(st->winBuf, in+2*st->frameSize-st->windowSize, st->windowSize-st->frameSize); + + /* Clear memory (no need to really compute it) */ + for (i=0;ilpcSize;i++) + st->mem_sp[i] = 0; + return 0; + + } + + /* LSP Quantization */ + if (st->first) + { + for (i=0;ilpcSize;i++) + st->old_lsp[i] = lsp[i]; + } + + + /*Quantize LSPs*/ +#if 1 /*0 for unquantized*/ + SUBMODE(lsp_quant)(lsp, qlsp, st->lpcSize, bits); +#else + for (i=0;ilpcSize;i++) + qlsp[i]=lsp[i]; +#endif + + /*If we use low bit-rate pitch mode, transmit open-loop pitch*/ + if (SUBMODE(lbr_pitch)!=-1) + { + speex_bits_pack(bits, ol_pitch-st->min_pitch, 7); + } + + if (SUBMODE(forced_pitch_gain)) + { + int quant; + /* This just damps the pitch a bit, because it tends to be too aggressive when forced */ + ol_pitch_coef = MULT16_16_Q15(QCONST16(.9,15), ol_pitch_coef); +#ifdef FIXED_POINT + quant = PSHR16(MULT16_16_16(15, ol_pitch_coef),GAIN_SHIFT); +#else + quant = (int)floor(.5+15*ol_pitch_coef*GAIN_SCALING_1); +#endif + if (quant>15) + quant=15; + if (quant<0) + quant=0; + speex_bits_pack(bits, quant, 4); + ol_pitch_coef=MULT16_16_P15(QCONST16(0.066667,15),SHL16(quant,GAIN_SHIFT)); + } + + + /*Quantize and transmit open-loop excitation gain*/ +#ifdef FIXED_POINT + { + int qe = scal_quant32(ol_gain, ol_gain_table, 32); + /*ol_gain = exp(qe/3.5)*SIG_SCALING;*/ + ol_gain = MULT16_32_Q15(28406,ol_gain_table[qe]); + speex_bits_pack(bits, qe, 5); + } +#else + { + int qe = (int)(floor(.5+3.5*log(ol_gain*1.0/SIG_SCALING))); + if (qe<0) + qe=0; + if (qe>31) + qe=31; + ol_gain = exp(qe/3.5)*SIG_SCALING; + speex_bits_pack(bits, qe, 5); + } +#endif + + + + /* Special case for first frame */ + if (st->first) + { + for (i=0;ilpcSize;i++) + st->old_qlsp[i] = qlsp[i]; + } + + /* Target signal */ + ALLOC(target, st->subframeSize, spx_word16_t); + ALLOC(innov, st->subframeSize, spx_sig_t); + ALLOC(exc32, st->subframeSize, spx_word32_t); + ALLOC(ringing, st->subframeSize, spx_word16_t); + ALLOC(syn_resp, st->subframeSize, spx_word16_t); + ALLOC(real_exc, st->subframeSize, spx_word16_t); + ALLOC(mem, st->lpcSize, spx_mem_t); + + /* Loop on sub-frames */ + for (sub=0;subnbSubframes;sub++) + { + int offset; + spx_word16_t *sw; + spx_word16_t *exc; + int pitch; + int response_bound = st->subframeSize; + + /* Offset relative to start of frame */ + offset = st->subframeSize*sub; + /* Excitation */ + exc=st->exc+offset; + /* Weighted signal */ + sw=st->sw+offset; + + /* LSP interpolation (quantized and unquantized) */ + lsp_interpolate(st->old_lsp, lsp, interp_lsp, st->lpcSize, sub, st->nbSubframes); + lsp_interpolate(st->old_qlsp, qlsp, interp_qlsp, st->lpcSize, sub, st->nbSubframes); + + /* Make sure the filters are stable */ + lsp_enforce_margin(interp_lsp, st->lpcSize, LSP_MARGIN); + lsp_enforce_margin(interp_qlsp, st->lpcSize, LSP_MARGIN); + + /* Compute interpolated LPCs (quantized and unquantized) */ + lsp_to_lpc(interp_lsp, interp_lpc, st->lpcSize,stack); + + lsp_to_lpc(interp_qlsp, interp_qlpc, st->lpcSize, stack); + + /* Compute analysis filter gain at w=pi (for use in SB-CELP) */ + { + spx_word32_t pi_g=LPC_SCALING; + for (i=0;ilpcSize;i+=2) + { + /*pi_g += -st->interp_qlpc[i] + st->interp_qlpc[i+1];*/ + pi_g = ADD32(pi_g, SUB32(EXTEND32(interp_qlpc[i+1]),EXTEND32(interp_qlpc[i]))); + } + st->pi_gain[sub] = pi_g; + } + +#ifdef VORBIS_PSYCHO + { + float curr_curve[128]; + float fact = ((float)sub+1.0f)/st->nbSubframes; + for (i=0;i<128;i++) + curr_curve[i] = (1.0f-fact)*st->old_curve[i] + fact*st->curve[i]; + curve_to_lpc(st->psy, curr_curve, bw_lpc1, bw_lpc2, 10); + } +#else + /* Compute bandwidth-expanded (unquantized) LPCs for perceptual weighting */ + bw_lpc(st->gamma1, interp_lpc, bw_lpc1, st->lpcSize); + if (st->gamma2>=0) + bw_lpc(st->gamma2, interp_lpc, bw_lpc2, st->lpcSize); + else + { + for (i=0;ilpcSize;i++) + bw_lpc2[i]=0; + } + /*print_vec(st->bw_lpc1, 10, "bw_lpc");*/ +#endif + + /*FIXME: This will break if we change the window size */ + speex_assert(st->windowSize-st->frameSize == st->subframeSize); + if (sub==0) + { + for (i=0;isubframeSize;i++) + real_exc[i] = sw[i] = st->winBuf[i]; + } else { + for (i=0;isubframeSize;i++) + real_exc[i] = sw[i] = in[i+((sub-1)*st->subframeSize)]; + } + fir_mem16(real_exc, interp_qlpc, real_exc, st->subframeSize, st->lpcSize, st->mem_exc2, stack); + + if (st->complexity==0) + response_bound >>= 1; + compute_impulse_response(interp_qlpc, bw_lpc1, bw_lpc2, syn_resp, response_bound, st->lpcSize, stack); + for (i=response_bound;isubframeSize;i++) + syn_resp[i]=VERY_SMALL; + + /* Compute zero response of A(z/g1) / ( A(z/g2) * A(z) ) */ + for (i=0;ilpcSize;i++) + mem[i]=SHL32(st->mem_sp[i],1); + for (i=0;isubframeSize;i++) + ringing[i] = VERY_SMALL; +#ifdef SHORTCUTS2 + iir_mem16(ringing, interp_qlpc, ringing, response_bound, st->lpcSize, mem, stack); + for (i=0;ilpcSize;i++) + mem[i]=SHL32(st->mem_sw[i],1); + filter_mem16(ringing, st->bw_lpc1, st->bw_lpc2, ringing, response_bound, st->lpcSize, mem, stack); + SPEEX_MEMSET(&ringing[response_bound], 0, st->subframeSize-response_bound); +#else + iir_mem16(ringing, interp_qlpc, ringing, st->subframeSize, st->lpcSize, mem, stack); + for (i=0;ilpcSize;i++) + mem[i]=SHL32(st->mem_sw[i],1); + filter_mem16(ringing, bw_lpc1, bw_lpc2, ringing, st->subframeSize, st->lpcSize, mem, stack); +#endif + + /* Compute weighted signal */ + for (i=0;ilpcSize;i++) + mem[i]=st->mem_sw[i]; + filter_mem16(sw, bw_lpc1, bw_lpc2, sw, st->subframeSize, st->lpcSize, mem, stack); + + if (st->complexity==0) + for (i=0;ilpcSize;i++) + st->mem_sw[i]=mem[i]; + + /* Compute target signal (saturation prevents overflows on clipped input speech) */ + for (i=0;isubframeSize;i++) + target[i]=EXTRACT16(SATURATE(SUB32(sw[i],PSHR32(ringing[i],1)),32767)); + + /* Reset excitation */ + SPEEX_MEMSET(exc, 0, st->subframeSize); + + /* If we have a long-term predictor (otherwise, something's wrong) */ + speex_assert (SUBMODE(ltp_quant)); + { + int pit_min, pit_max; + /* Long-term prediction */ + if (SUBMODE(lbr_pitch) != -1) + { + /* Low bit-rate pitch handling */ + int margin; + margin = SUBMODE(lbr_pitch); + if (margin) + { + if (ol_pitch < st->min_pitch+margin-1) + ol_pitch=st->min_pitch+margin-1; + if (ol_pitch > st->max_pitch-margin) + ol_pitch=st->max_pitch-margin; + pit_min = ol_pitch-margin+1; + pit_max = ol_pitch+margin; + } else { + pit_min=pit_max=ol_pitch; + } + } else { + pit_min = st->min_pitch; + pit_max = st->max_pitch; + } + + /* Force pitch to use only the current frame if needed */ + if (st->bounded_pitch && pit_max>offset) + pit_max=offset; + + /* Perform pitch search */ + pitch = SUBMODE(ltp_quant)(target, sw, interp_qlpc, bw_lpc1, bw_lpc2, + exc32, SUBMODE(ltp_params), pit_min, pit_max, ol_pitch_coef, + st->lpcSize, st->subframeSize, bits, stack, + exc, syn_resp, st->complexity, 0, st->plc_tuning, &st->cumul_gain); + + st->pitch[sub]=pitch; + } + /* Quantization of innovation */ + SPEEX_MEMSET(innov, 0, st->subframeSize); + + /* FIXME: Make sure this is save from overflows (so far so good) */ + for (i=0;isubframeSize;i++) + real_exc[i] = EXTRACT16(SUB32(EXTEND32(real_exc[i]), PSHR32(exc32[i],SIG_SHIFT-1))); + + ener = SHL32(EXTEND32(compute_rms16(real_exc, st->subframeSize)),SIG_SHIFT); + + /*FIXME: Should use DIV32_16 and make sure result fits in 16 bits */ +#ifdef FIXED_POINT + { + spx_word32_t f = PDIV32(ener,PSHR32(ol_gain,SIG_SHIFT)); + if (f<=32767) + fine_gain = f; + else + fine_gain = 32767; + } +#else + fine_gain = PDIV32_16(ener,PSHR32(ol_gain,SIG_SHIFT)); +#endif + /* Calculate gain correction for the sub-frame (if any) */ + if (SUBMODE(have_subframe_gain)) + { + int qe; + if (SUBMODE(have_subframe_gain)==3) + { + qe = scal_quant(fine_gain, exc_gain_quant_scal3_bound, 8); + speex_bits_pack(bits, qe, 3); + ener=MULT16_32_Q14(exc_gain_quant_scal3[qe],ol_gain); + } else { + qe = scal_quant(fine_gain, exc_gain_quant_scal1_bound, 2); + speex_bits_pack(bits, qe, 1); + ener=MULT16_32_Q14(exc_gain_quant_scal1[qe],ol_gain); + } + } else { + ener=ol_gain; + } + + /*printf ("%f %f\n", ener, ol_gain);*/ + + /* Normalize innovation */ + signal_div(target, target, ener, st->subframeSize); + + /* Quantize innovation */ + speex_assert (SUBMODE(innovation_quant)); + { + /* Codebook search */ + SUBMODE(innovation_quant)(target, interp_qlpc, bw_lpc1, bw_lpc2, + SUBMODE(innovation_params), st->lpcSize, st->subframeSize, + innov, syn_resp, bits, stack, st->complexity, SUBMODE(double_codebook)); + + /* De-normalize innovation and update excitation */ + signal_mul(innov, innov, ener, st->subframeSize); + + for (i=0;isubframeSize;i++) + exc[i] = EXTRACT16(SATURATE32(PSHR32(ADD32(SHL32(exc32[i],1),innov[i]),SIG_SHIFT),32767)); + + /* In some (rare) modes, we do a second search (more bits) to reduce noise even more */ + if (SUBMODE(double_codebook)) { + char *tmp_stack=stack; + VARDECL(spx_sig_t *innov2); + ALLOC(innov2, st->subframeSize, spx_sig_t); + SPEEX_MEMSET(innov2, 0, st->subframeSize); + for (i=0;isubframeSize;i++) + target[i]=MULT16_16_P13(QCONST16(2.2f,13), target[i]); + SUBMODE(innovation_quant)(target, interp_qlpc, bw_lpc1, bw_lpc2, + SUBMODE(innovation_params), st->lpcSize, st->subframeSize, + innov2, syn_resp, bits, stack, st->complexity, 0); + signal_mul(innov2, innov2, MULT16_32_Q15(QCONST16(0.454545f,15),ener), st->subframeSize); + for (i=0;isubframeSize;i++) + innov[i] = ADD32(innov[i],innov2[i]); + stack = tmp_stack; + } + for (i=0;isubframeSize;i++) + exc[i] = EXTRACT16(SATURATE32(PSHR32(ADD32(SHL32(exc32[i],1),innov[i]),SIG_SHIFT),32767)); + if (st->innov_rms_save) + { + st->innov_rms_save[sub] = compute_rms(innov, st->subframeSize); + } + } + + /* Final signal synthesis from excitation */ + iir_mem16(exc, interp_qlpc, sw, st->subframeSize, st->lpcSize, st->mem_sp, stack); + + /* Compute weighted signal again, from synthesized speech (not sure it's the right thing) */ + if (st->complexity!=0) + filter_mem16(sw, bw_lpc1, bw_lpc2, sw, st->subframeSize, st->lpcSize, st->mem_sw, stack); + + } + + /* Store the LSPs for interpolation in the next frame */ + if (st->submodeID>=1) + { + for (i=0;ilpcSize;i++) + st->old_lsp[i] = lsp[i]; + for (i=0;ilpcSize;i++) + st->old_qlsp[i] = qlsp[i]; + } + +#ifdef VORBIS_PSYCHO + if (st->submodeID>=1) + SPEEX_COPY(st->old_curve, st->curve, 128); +#endif + + if (st->submodeID==1) + { +#ifndef DISABLE_VBR + if (st->dtx_count) + speex_bits_pack(bits, 15, 4); + else +#endif + speex_bits_pack(bits, 0, 4); + } + + /* The next frame will not be the first (Duh!) */ + st->first = 0; + SPEEX_COPY(st->winBuf, in+2*st->frameSize-st->windowSize, st->windowSize-st->frameSize); + + if (SUBMODE(innovation_quant) == noise_codebook_quant || st->submodeID==0) + st->bounded_pitch = 1; + else + st->bounded_pitch = 0; + + return 1; +} + +void *nb_decoder_init(const SpeexMode *m) +{ + DecState *st; + const SpeexNBMode *mode; + int i; + + mode=(const SpeexNBMode*)m->mode; + st = (DecState *)speex_alloc(sizeof(DecState)); + if (!st) + return NULL; +#if defined(VAR_ARRAYS) || defined (USE_ALLOCA) + st->stack = NULL; +#else + st->stack = (char*)speex_alloc_scratch(NB_DEC_STACK); +#endif + + st->mode=m; + + + st->encode_submode = 1; + + st->first=1; + /* Codec parameters, should eventually have several "modes"*/ + st->frameSize = mode->frameSize; + st->nbSubframes=mode->frameSize/mode->subframeSize; + st->subframeSize=mode->subframeSize; + st->lpcSize = mode->lpcSize; + st->min_pitch=mode->pitchStart; + st->max_pitch=mode->pitchEnd; + + st->submodes=mode->submodes; + st->submodeID=mode->defaultSubmode; + + st->lpc_enh_enabled=1; + + st->excBuf = (spx_word16_t*)speex_alloc((st->frameSize + 2*st->max_pitch + st->subframeSize + 12)*sizeof(spx_word16_t)); + st->exc = st->excBuf + 2*st->max_pitch + st->subframeSize + 6; + SPEEX_MEMSET(st->excBuf, 0, st->frameSize + st->max_pitch); + + st->interp_qlpc = (spx_coef_t*)speex_alloc(st->lpcSize*sizeof(spx_coef_t)); + st->old_qlsp = (spx_lsp_t*)speex_alloc(st->lpcSize*sizeof(spx_lsp_t)); + st->mem_sp = (spx_mem_t*)speex_alloc(st->lpcSize*sizeof(spx_mem_t)); + st->pi_gain = (spx_word32_t*)speex_alloc((st->nbSubframes)*sizeof(spx_word32_t)); + st->last_pitch = 40; + st->count_lost=0; + st->pitch_gain_buf[0] = st->pitch_gain_buf[1] = st->pitch_gain_buf[2] = 0; + st->pitch_gain_buf_idx = 0; + st->seed = 1000; + + st->sampling_rate=8000; + st->last_ol_gain = 0; + + st->user_callback.func = &speex_default_user_handler; + st->user_callback.data = NULL; + for (i=0;i<16;i++) + st->speex_callbacks[i].func = NULL; + + st->voc_m1=st->voc_m2=st->voc_mean=0; + st->voc_offset=0; + st->dtx_enabled=0; + st->isWideband = 0; + st->highpass_enabled = 1; + +#ifdef ENABLE_VALGRIND + VALGRIND_MAKE_READABLE(st, NB_DEC_STACK); +#endif + return st; +} + +void nb_decoder_destroy(void *state) +{ + DecState *st; + st=(DecState*)state; + +#if !(defined(VAR_ARRAYS) || defined (USE_ALLOCA)) + speex_free_scratch(st->stack); +#endif + + speex_free (st->excBuf); + speex_free (st->interp_qlpc); + speex_free (st->old_qlsp); + speex_free (st->mem_sp); + speex_free (st->pi_gain); + + speex_free(state); +} + +#define median3(a, b, c) ((a) < (b) ? ((b) < (c) ? (b) : ((a) < (c) ? (c) : (a))) : ((c) < (b) ? (b) : ((c) < (a) ? (c) : (a)))) + +#ifdef FIXED_POINT +const spx_word16_t attenuation[10] = {32767, 31483, 27923, 22861, 17278, 12055, 7764, 4616, 2533, 1283}; +#else +const spx_word16_t attenuation[10] = {1., 0.961, 0.852, 0.698, 0.527, 0.368, 0.237, 0.141, 0.077, 0.039}; + +#endif + +static void nb_decode_lost(DecState *st, spx_word16_t *out, char *stack) +{ + int i; + int pitch_val; + spx_word16_t pitch_gain; + spx_word16_t fact; + spx_word16_t gain_med; + spx_word16_t innov_gain; + spx_word16_t noise_gain; + + if (st->count_lost<10) + fact = attenuation[st->count_lost]; + else + fact = 0; + + gain_med = median3(st->pitch_gain_buf[0], st->pitch_gain_buf[1], st->pitch_gain_buf[2]); + if (gain_med < st->last_pitch_gain) + st->last_pitch_gain = gain_med; + +#ifdef FIXED_POINT + pitch_gain = st->last_pitch_gain; + if (pitch_gain>54) + pitch_gain = 54; + pitch_gain = SHL16(pitch_gain, 9); +#else + pitch_gain = GAIN_SCALING_1*st->last_pitch_gain; + if (pitch_gain>.85) + pitch_gain=.85; +#endif + pitch_gain = MULT16_16_Q15(fact,pitch_gain) + VERY_SMALL; + /* FIXME: This was rms of innovation (not exc) */ + innov_gain = compute_rms16(st->exc, st->frameSize); + noise_gain = MULT16_16_Q15(innov_gain, MULT16_16_Q15(fact, SUB16(Q15ONE,MULT16_16_Q15(pitch_gain,pitch_gain)))); + /* Shift all buffers by one frame */ + SPEEX_MOVE(st->excBuf, st->excBuf+st->frameSize, 2*st->max_pitch + st->subframeSize + 12); + + + pitch_val = st->last_pitch + SHR32((spx_int32_t)speex_rand(1+st->count_lost, &st->seed),SIG_SHIFT); + if (pitch_val > st->max_pitch) + pitch_val = st->max_pitch; + if (pitch_val < st->min_pitch) + pitch_val = st->min_pitch; + for (i=0;iframeSize;i++) + { + st->exc[i]= MULT16_16_Q15(pitch_gain, (st->exc[i-pitch_val]+VERY_SMALL)) + + speex_rand(noise_gain, &st->seed); + } + + bw_lpc(QCONST16(.98,15), st->interp_qlpc, st->interp_qlpc, st->lpcSize); + iir_mem16(&st->exc[-st->subframeSize], st->interp_qlpc, out, st->frameSize, + st->lpcSize, st->mem_sp, stack); + highpass(out, out, st->frameSize, HIGHPASS_NARROWBAND|HIGHPASS_OUTPUT, st->mem_hp); + + st->first = 0; + st->count_lost++; + st->pitch_gain_buf[st->pitch_gain_buf_idx++] = PSHR16(pitch_gain,9); + if (st->pitch_gain_buf_idx > 2) /* rollover */ + st->pitch_gain_buf_idx = 0; +} + +/* Just so we don't need to carry the complete wideband mode information */ +static const int wb_skip_table[8] = {0, 36, 112, 192, 352, 0, 0, 0}; + +int nb_decode(void *state, SpeexBits *bits, void *vout) +{ + DecState *st; + int i, sub; + int pitch; + spx_word16_t pitch_gain[3]; + spx_word32_t ol_gain=0; + int ol_pitch=0; + spx_word16_t ol_pitch_coef=0; + int best_pitch=40; + spx_word16_t best_pitch_gain=0; + int wideband; + int m; + char *stack; + VARDECL(spx_sig_t *innov); + VARDECL(spx_word32_t *exc32); + VARDECL(spx_coef_t *ak); + VARDECL(spx_lsp_t *qlsp); + spx_word16_t pitch_average=0; + + spx_word16_t *out = (spx_word16_t*)vout; + VARDECL(spx_lsp_t *interp_qlsp); + + st=(DecState*)state; + stack=st->stack; + + /* Check if we're in DTX mode*/ + if (!bits && st->dtx_enabled) + { + st->submodeID=0; + } else + { + /* If bits is NULL, consider the packet to be lost (what could we do anyway) */ + if (!bits) + { + nb_decode_lost(st, out, stack); + return 0; + } + + if (st->encode_submode) + { + + /* Search for next narrowband block (handle requests, skip wideband blocks) */ + do { + if (speex_bits_remaining(bits)<5) + return -1; + wideband = speex_bits_unpack_unsigned(bits, 1); + if (wideband) /* Skip wideband block (for compatibility) */ + { + int submode; + int advance; + advance = submode = speex_bits_unpack_unsigned(bits, SB_SUBMODE_BITS); + /*speex_mode_query(&speex_wb_mode, SPEEX_SUBMODE_BITS_PER_FRAME, &advance);*/ + advance = wb_skip_table[submode]; + if (advance < 0) + { + speex_notify("Invalid mode encountered. The stream is corrupted."); + return -2; + } + advance -= (SB_SUBMODE_BITS+1); + speex_bits_advance(bits, advance); + + if (speex_bits_remaining(bits)<5) + return -1; + wideband = speex_bits_unpack_unsigned(bits, 1); + if (wideband) + { + advance = submode = speex_bits_unpack_unsigned(bits, SB_SUBMODE_BITS); + /*speex_mode_query(&speex_wb_mode, SPEEX_SUBMODE_BITS_PER_FRAME, &advance);*/ + advance = wb_skip_table[submode]; + if (advance < 0) + { + speex_notify("Invalid mode encountered. The stream is corrupted."); + return -2; + } + advance -= (SB_SUBMODE_BITS+1); + speex_bits_advance(bits, advance); + wideband = speex_bits_unpack_unsigned(bits, 1); + if (wideband) + { + speex_notify("More than two wideband layers found. The stream is corrupted."); + return -2; + } + + } + } + if (speex_bits_remaining(bits)<4) + return -1; + /* FIXME: Check for overflow */ + m = speex_bits_unpack_unsigned(bits, 4); + if (m==15) /* We found a terminator */ + { + return -1; + } else if (m==14) /* Speex in-band request */ + { + int ret = speex_inband_handler(bits, st->speex_callbacks, state); + if (ret) + return ret; + } else if (m==13) /* User in-band request */ + { + int ret = st->user_callback.func(bits, state, st->user_callback.data); + if (ret) + return ret; + } else if (m>8) /* Invalid mode */ + { + speex_notify("Invalid mode encountered. The stream is corrupted."); + return -2; + } + + } while (m>8); + + /* Get the sub-mode that was used */ + st->submodeID = m; + } + + } + + /* Shift all buffers by one frame */ + SPEEX_MOVE(st->excBuf, st->excBuf+st->frameSize, 2*st->max_pitch + st->subframeSize + 12); + + /* If null mode (no transmission), just set a couple things to zero*/ + if (st->submodes[st->submodeID] == NULL) + { + VARDECL(spx_coef_t *lpc); + ALLOC(lpc, st->lpcSize, spx_coef_t); + bw_lpc(QCONST16(0.93f,15), st->interp_qlpc, lpc, st->lpcSize); + { + spx_word16_t innov_gain=0; + /* FIXME: This was innov, not exc */ + innov_gain = compute_rms16(st->exc, st->frameSize); + for (i=0;iframeSize;i++) + st->exc[i]=speex_rand(innov_gain, &st->seed); + } + + + st->first=1; + + /* Final signal synthesis from excitation */ + iir_mem16(st->exc, lpc, out, st->frameSize, st->lpcSize, st->mem_sp, stack); + + st->count_lost=0; + return 0; + } + + ALLOC(qlsp, st->lpcSize, spx_lsp_t); + + /* Unquantize LSPs */ + SUBMODE(lsp_unquant)(qlsp, st->lpcSize, bits); + + /*Damp memory if a frame was lost and the LSP changed too much*/ + if (st->count_lost) + { + spx_word16_t fact; + spx_word32_t lsp_dist=0; + for (i=0;ilpcSize;i++) + lsp_dist = ADD32(lsp_dist, EXTEND32(ABS(st->old_qlsp[i] - qlsp[i]))); +#ifdef FIXED_POINT + fact = SHR16(19661,SHR32(lsp_dist,LSP_SHIFT+2)); +#else + fact = .6*exp(-.2*lsp_dist); +#endif + for (i=0;ilpcSize;i++) + st->mem_sp[i] = MULT16_32_Q15(fact,st->mem_sp[i]); + } + + + /* Handle first frame and lost-packet case */ + if (st->first || st->count_lost) + { + for (i=0;ilpcSize;i++) + st->old_qlsp[i] = qlsp[i]; + } + + /* Get open-loop pitch estimation for low bit-rate pitch coding */ + if (SUBMODE(lbr_pitch)!=-1) + { + ol_pitch = st->min_pitch+speex_bits_unpack_unsigned(bits, 7); + } + + if (SUBMODE(forced_pitch_gain)) + { + int quant; + quant = speex_bits_unpack_unsigned(bits, 4); + ol_pitch_coef=MULT16_16_P15(QCONST16(0.066667,15),SHL16(quant,GAIN_SHIFT)); + } + + /* Get global excitation gain */ + { + int qe; + qe = speex_bits_unpack_unsigned(bits, 5); +#ifdef FIXED_POINT + /* FIXME: Perhaps we could slightly lower the gain here when the output is going to saturate? */ + ol_gain = MULT16_32_Q15(28406,ol_gain_table[qe]); +#else + ol_gain = SIG_SCALING*exp(qe/3.5); +#endif + } + + ALLOC(ak, st->lpcSize, spx_coef_t); + ALLOC(innov, st->subframeSize, spx_sig_t); + ALLOC(exc32, st->subframeSize, spx_word32_t); + + if (st->submodeID==1) + { + int extra; + extra = speex_bits_unpack_unsigned(bits, 4); + + if (extra==15) + st->dtx_enabled=1; + else + st->dtx_enabled=0; + } + if (st->submodeID>1) + st->dtx_enabled=0; + + /*Loop on subframes */ + for (sub=0;subnbSubframes;sub++) + { + int offset; + spx_word16_t *exc; + spx_word16_t *sp; + spx_word16_t *innov_save = NULL; + spx_word16_t tmp; + + /* Offset relative to start of frame */ + offset = st->subframeSize*sub; + /* Excitation */ + exc=st->exc+offset; + /* Original signal */ + sp=out+offset; + if (st->innov_save) + innov_save = st->innov_save+offset; + + + /* Reset excitation */ + SPEEX_MEMSET(exc, 0, st->subframeSize); + + /*Adaptive codebook contribution*/ + speex_assert (SUBMODE(ltp_unquant)); + { + int pit_min, pit_max; + /* Handle pitch constraints if any */ + if (SUBMODE(lbr_pitch) != -1) + { + int margin; + margin = SUBMODE(lbr_pitch); + if (margin) + { +/* GT - need optimization? + if (ol_pitch < st->min_pitch+margin-1) + ol_pitch=st->min_pitch+margin-1; + if (ol_pitch > st->max_pitch-margin) + ol_pitch=st->max_pitch-margin; + pit_min = ol_pitch-margin+1; + pit_max = ol_pitch+margin; +*/ + pit_min = ol_pitch-margin+1; + if (pit_min < st->min_pitch) + pit_min = st->min_pitch; + pit_max = ol_pitch+margin; + if (pit_max > st->max_pitch) + pit_max = st->max_pitch; + } else { + pit_min = pit_max = ol_pitch; + } + } else { + pit_min = st->min_pitch; + pit_max = st->max_pitch; + } + + + + SUBMODE(ltp_unquant)(exc, exc32, pit_min, pit_max, ol_pitch_coef, SUBMODE(ltp_params), + st->subframeSize, &pitch, &pitch_gain[0], bits, stack, + st->count_lost, offset, st->last_pitch_gain, 0); + + /* Ensuring that things aren't blowing up as would happen if e.g. an encoder is + crafting packets to make us produce NaNs and slow down the decoder (vague DoS threat). + We can probably be even more aggressive and limit to 15000 or so. */ + sanitize_values32(exc32, NEG32(QCONST32(32000,SIG_SHIFT-1)), QCONST32(32000,SIG_SHIFT-1), st->subframeSize); + + tmp = gain_3tap_to_1tap(pitch_gain); + + pitch_average += tmp; + if ((tmp>best_pitch_gain&&ABS(2*best_pitch-pitch)>=3&&ABS(3*best_pitch-pitch)>=4&&ABS(4*best_pitch-pitch)>=5) + || (tmp>MULT16_16_Q15(QCONST16(.6,15),best_pitch_gain)&&(ABS(best_pitch-2*pitch)<3||ABS(best_pitch-3*pitch)<4||ABS(best_pitch-4*pitch)<5)) + || (MULT16_16_Q15(QCONST16(.67,15),tmp)>best_pitch_gain&&(ABS(2*best_pitch-pitch)<3||ABS(3*best_pitch-pitch)<4||ABS(4*best_pitch-pitch)<5)) ) + { + best_pitch = pitch; + if (tmp > best_pitch_gain) + best_pitch_gain = tmp; + } + } + + /* Unquantize the innovation */ + { + int q_energy; + spx_word32_t ener; + + SPEEX_MEMSET(innov, 0, st->subframeSize); + + /* Decode sub-frame gain correction */ + if (SUBMODE(have_subframe_gain)==3) + { + q_energy = speex_bits_unpack_unsigned(bits, 3); + ener = MULT16_32_Q14(exc_gain_quant_scal3[q_energy],ol_gain); + } else if (SUBMODE(have_subframe_gain)==1) + { + q_energy = speex_bits_unpack_unsigned(bits, 1); + ener = MULT16_32_Q14(exc_gain_quant_scal1[q_energy],ol_gain); + } else { + ener = ol_gain; + } + + speex_assert (SUBMODE(innovation_unquant)); + { + /*Fixed codebook contribution*/ + SUBMODE(innovation_unquant)(innov, SUBMODE(innovation_params), st->subframeSize, bits, stack, &st->seed); + /* De-normalize innovation and update excitation */ + + signal_mul(innov, innov, ener, st->subframeSize); + + /* Decode second codebook (only for some modes) */ + if (SUBMODE(double_codebook)) + { + char *tmp_stack=stack; + VARDECL(spx_sig_t *innov2); + ALLOC(innov2, st->subframeSize, spx_sig_t); + SPEEX_MEMSET(innov2, 0, st->subframeSize); + SUBMODE(innovation_unquant)(innov2, SUBMODE(innovation_params), st->subframeSize, bits, stack, &st->seed); + signal_mul(innov2, innov2, MULT16_32_Q15(QCONST16(0.454545f,15),ener), st->subframeSize); + for (i=0;isubframeSize;i++) + innov[i] = ADD32(innov[i], innov2[i]); + stack = tmp_stack; + } + for (i=0;isubframeSize;i++) + exc[i]=EXTRACT16(SATURATE32(PSHR32(ADD32(SHL32(exc32[i],1),innov[i]),SIG_SHIFT),32767)); + /*print_vec(exc, 40, "innov");*/ + if (innov_save) + { + for (i=0;isubframeSize;i++) + innov_save[i] = EXTRACT16(PSHR32(innov[i], SIG_SHIFT)); + } + } + + /*Vocoder mode*/ + if (st->submodeID==1) + { + spx_word16_t g=ol_pitch_coef; + g=MULT16_16_P14(QCONST16(1.5f,14),(g-QCONST16(.2f,6))); + if (g<0) + g=0; + if (g>GAIN_SCALING) + g=GAIN_SCALING; + + SPEEX_MEMSET(exc, 0, st->subframeSize); + while (st->voc_offsetsubframeSize) + { + /* exc[st->voc_offset]= g*sqrt(2*ol_pitch)*ol_gain; + Not quite sure why we need the factor of two in the sqrt */ + if (st->voc_offset>=0) + exc[st->voc_offset]=MULT16_16(spx_sqrt(MULT16_16_16(2,ol_pitch)),EXTRACT16(PSHR32(MULT16_16(g,PSHR32(ol_gain,SIG_SHIFT)),6))); + st->voc_offset+=ol_pitch; + } + st->voc_offset -= st->subframeSize; + + for (i=0;isubframeSize;i++) + { + spx_word16_t exci=exc[i]; + exc[i]= ADD16(ADD16(MULT16_16_Q15(QCONST16(.7f,15),exc[i]) , MULT16_16_Q15(QCONST16(.3f,15),st->voc_m1)), + SUB16(MULT16_16_Q15(Q15_ONE-MULT16_16_16(QCONST16(.85f,9),g),EXTRACT16(PSHR32(innov[i],SIG_SHIFT))), + MULT16_16_Q15(MULT16_16_16(QCONST16(.15f,9),g),EXTRACT16(PSHR32(st->voc_m2,SIG_SHIFT))) + )); + st->voc_m1 = exci; + st->voc_m2=innov[i]; + st->voc_mean = EXTRACT16(PSHR32(ADD32(MULT16_16(QCONST16(.8f,15),st->voc_mean), MULT16_16(QCONST16(.2f,15),exc[i])), 15)); + exc[i]-=st->voc_mean; + } + } + + } + } + + ALLOC(interp_qlsp, st->lpcSize, spx_lsp_t); + + if (st->lpc_enh_enabled && SUBMODE(comb_gain)>0 && !st->count_lost) + { + multicomb(st->exc-st->subframeSize, out, st->interp_qlpc, st->lpcSize, 2*st->subframeSize, best_pitch, 40, SUBMODE(comb_gain), stack); + multicomb(st->exc+st->subframeSize, out+2*st->subframeSize, st->interp_qlpc, st->lpcSize, 2*st->subframeSize, best_pitch, 40, SUBMODE(comb_gain), stack); + } else { + SPEEX_COPY(out, &st->exc[-st->subframeSize], st->frameSize); + } + + /* If the last packet was lost, re-scale the excitation to obtain the same energy as encoded in ol_gain */ + if (st->count_lost) + { + spx_word16_t exc_ener; + spx_word32_t gain32; + spx_word16_t gain; + exc_ener = compute_rms16 (st->exc, st->frameSize); + gain32 = PDIV32(ol_gain, ADD16(exc_ener,1)); +#ifdef FIXED_POINT + if (gain32 > 32767) + gain32 = 32767; + gain = EXTRACT16(gain32); +#else + if (gain32 > 2) + gain32=2; + gain = gain32; +#endif + for (i=0;iframeSize;i++) + { + st->exc[i] = MULT16_16_Q14(gain, st->exc[i]); + out[i]=st->exc[i-st->subframeSize]; + } + } + + /*Loop on subframes */ + for (sub=0;subnbSubframes;sub++) + { + int offset; + spx_word16_t *sp; + spx_word16_t *exc; + /* Offset relative to start of frame */ + offset = st->subframeSize*sub; + /* Original signal */ + sp=out+offset; + /* Excitation */ + exc=st->exc+offset; + + /* LSP interpolation (quantized and unquantized) */ + lsp_interpolate(st->old_qlsp, qlsp, interp_qlsp, st->lpcSize, sub, st->nbSubframes); + + /* Make sure the LSP's are stable */ + lsp_enforce_margin(interp_qlsp, st->lpcSize, LSP_MARGIN); + + /* Compute interpolated LPCs (unquantized) */ + lsp_to_lpc(interp_qlsp, ak, st->lpcSize, stack); + + /* Compute analysis filter at w=pi */ + { + spx_word32_t pi_g=LPC_SCALING; + for (i=0;ilpcSize;i+=2) + { + /*pi_g += -st->interp_qlpc[i] + st->interp_qlpc[i+1];*/ + pi_g = ADD32(pi_g, SUB32(EXTEND32(ak[i+1]),EXTEND32(ak[i]))); + } + st->pi_gain[sub] = pi_g; + } + + iir_mem16(sp, st->interp_qlpc, sp, st->subframeSize, st->lpcSize, + st->mem_sp, stack); + + for (i=0;ilpcSize;i++) + st->interp_qlpc[i] = ak[i]; + + } + + if (st->highpass_enabled) + highpass(out, out, st->frameSize, (st->isWideband?HIGHPASS_WIDEBAND:HIGHPASS_NARROWBAND)|HIGHPASS_OUTPUT, st->mem_hp); + /*for (i=0;iframeSize;i++) + printf ("%d\n", (int)st->frame[i]);*/ + + /* Tracking output level */ + st->level = 1+PSHR32(ol_gain,SIG_SHIFT); + st->max_level = MAX16(MULT16_16_Q15(QCONST16(.99f,15), st->max_level), st->level); + st->min_level = MIN16(ADD16(1,MULT16_16_Q14(QCONST16(1.01f,14), st->min_level)), st->level); + if (st->max_level < st->min_level+1) + st->max_level = st->min_level+1; + /*printf ("%f %f %f %d\n", og, st->min_level, st->max_level, update);*/ + + /* Store the LSPs for interpolation in the next frame */ + for (i=0;ilpcSize;i++) + st->old_qlsp[i] = qlsp[i]; + + /* The next frame will not be the first (Duh!) */ + st->first = 0; + st->count_lost=0; + st->last_pitch = best_pitch; +#ifdef FIXED_POINT + st->last_pitch_gain = PSHR16(pitch_average,2); +#else + st->last_pitch_gain = .25*pitch_average; +#endif + st->pitch_gain_buf[st->pitch_gain_buf_idx++] = st->last_pitch_gain; + if (st->pitch_gain_buf_idx > 2) /* rollover */ + st->pitch_gain_buf_idx = 0; + + st->last_ol_gain = ol_gain; + + return 0; +} + +int nb_encoder_ctl(void *state, int request, void *ptr) +{ + EncState *st; + st=(EncState*)state; + switch(request) + { + case SPEEX_GET_FRAME_SIZE: + (*(spx_int32_t*)ptr) = st->frameSize; + break; + case SPEEX_SET_LOW_MODE: + case SPEEX_SET_MODE: + st->submodeSelect = st->submodeID = (*(spx_int32_t*)ptr); + break; + case SPEEX_GET_LOW_MODE: + case SPEEX_GET_MODE: + (*(spx_int32_t*)ptr) = st->submodeID; + break; +#ifndef DISABLE_VBR + case SPEEX_SET_VBR: + st->vbr_enabled = (*(spx_int32_t*)ptr); + break; + case SPEEX_GET_VBR: + (*(spx_int32_t*)ptr) = st->vbr_enabled; + break; + case SPEEX_SET_VAD: + st->vad_enabled = (*(spx_int32_t*)ptr); + break; + case SPEEX_GET_VAD: + (*(spx_int32_t*)ptr) = st->vad_enabled; + break; + case SPEEX_SET_DTX: + st->dtx_enabled = (*(spx_int32_t*)ptr); + break; + case SPEEX_GET_DTX: + (*(spx_int32_t*)ptr) = st->dtx_enabled; + break; + case SPEEX_SET_ABR: + st->abr_enabled = (*(spx_int32_t*)ptr); + st->vbr_enabled = st->abr_enabled!=0; + if (st->vbr_enabled) + { + spx_int32_t i=10; + spx_int32_t rate, target; + float vbr_qual; + target = (*(spx_int32_t*)ptr); + while (i>=0) + { + speex_encoder_ctl(st, SPEEX_SET_QUALITY, &i); + speex_encoder_ctl(st, SPEEX_GET_BITRATE, &rate); + if (rate <= target) + break; + i--; + } + vbr_qual=i; + if (vbr_qual<0) + vbr_qual=0; + speex_encoder_ctl(st, SPEEX_SET_VBR_QUALITY, &vbr_qual); + st->abr_count=0; + st->abr_drift=0; + st->abr_drift2=0; + } + + break; + case SPEEX_GET_ABR: + (*(spx_int32_t*)ptr) = st->abr_enabled; + break; +#endif /* #ifndef DISABLE_VBR */ +#if !defined(DISABLE_VBR) && !defined(DISABLE_FLOAT_API) + case SPEEX_SET_VBR_QUALITY: + st->vbr_quality = (*(float*)ptr); + break; + case SPEEX_GET_VBR_QUALITY: + (*(float*)ptr) = st->vbr_quality; + break; +#endif /* !defined(DISABLE_VBR) && !defined(DISABLE_FLOAT_API) */ + case SPEEX_SET_QUALITY: + { + int quality = (*(spx_int32_t*)ptr); + if (quality < 0) + quality = 0; + if (quality > 10) + quality = 10; + st->submodeSelect = st->submodeID = ((const SpeexNBMode*)(st->mode->mode))->quality_map[quality]; + } + break; + case SPEEX_SET_COMPLEXITY: + st->complexity = (*(spx_int32_t*)ptr); + if (st->complexity<0) + st->complexity=0; + break; + case SPEEX_GET_COMPLEXITY: + (*(spx_int32_t*)ptr) = st->complexity; + break; + case SPEEX_SET_BITRATE: + { + spx_int32_t i=10; + spx_int32_t rate, target; + target = (*(spx_int32_t*)ptr); + while (i>=0) + { + speex_encoder_ctl(st, SPEEX_SET_QUALITY, &i); + speex_encoder_ctl(st, SPEEX_GET_BITRATE, &rate); + if (rate <= target) + break; + i--; + } + } + break; + case SPEEX_GET_BITRATE: + if (st->submodes[st->submodeID]) + (*(spx_int32_t*)ptr) = st->sampling_rate*SUBMODE(bits_per_frame)/st->frameSize; + else + (*(spx_int32_t*)ptr) = st->sampling_rate*(NB_SUBMODE_BITS+1)/st->frameSize; + break; + case SPEEX_SET_SAMPLING_RATE: + st->sampling_rate = (*(spx_int32_t*)ptr); + break; + case SPEEX_GET_SAMPLING_RATE: + (*(spx_int32_t*)ptr)=st->sampling_rate; + break; + case SPEEX_RESET_STATE: + { + int i; + st->bounded_pitch = 1; + st->first = 1; + for (i=0;ilpcSize;i++) + st->old_lsp[i]= DIV32(MULT16_16(QCONST16(3.1415927f, LSP_SHIFT), i+1), st->lpcSize+1); + for (i=0;ilpcSize;i++) + st->mem_sw[i]=st->mem_sw_whole[i]=st->mem_sp[i]=st->mem_exc[i]=0; + for (i=0;iframeSize+st->max_pitch+1;i++) + st->excBuf[i]=st->swBuf[i]=0; + for (i=0;iwindowSize-st->frameSize;i++) + st->winBuf[i]=0; + } + break; + case SPEEX_SET_SUBMODE_ENCODING: + st->encode_submode = (*(spx_int32_t*)ptr); + break; + case SPEEX_GET_SUBMODE_ENCODING: + (*(spx_int32_t*)ptr) = st->encode_submode; + break; + case SPEEX_GET_LOOKAHEAD: + (*(spx_int32_t*)ptr)=(st->windowSize-st->frameSize); + break; + case SPEEX_SET_PLC_TUNING: + st->plc_tuning = (*(spx_int32_t*)ptr); + if (st->plc_tuning>100) + st->plc_tuning=100; + break; + case SPEEX_GET_PLC_TUNING: + (*(spx_int32_t*)ptr)=(st->plc_tuning); + break; +#ifndef DISABLE_VBR + case SPEEX_SET_VBR_MAX_BITRATE: + st->vbr_max = (*(spx_int32_t*)ptr); + break; + case SPEEX_GET_VBR_MAX_BITRATE: + (*(spx_int32_t*)ptr) = st->vbr_max; + break; +#endif /* #ifndef DISABLE_VBR */ + case SPEEX_SET_HIGHPASS: + st->highpass_enabled = (*(spx_int32_t*)ptr); + break; + case SPEEX_GET_HIGHPASS: + (*(spx_int32_t*)ptr) = st->highpass_enabled; + break; + + /* This is all internal stuff past this point */ + case SPEEX_GET_PI_GAIN: + { + int i; + spx_word32_t *g = (spx_word32_t*)ptr; + for (i=0;inbSubframes;i++) + g[i]=st->pi_gain[i]; + } + break; + case SPEEX_GET_EXC: + { + int i; + for (i=0;inbSubframes;i++) + ((spx_word16_t*)ptr)[i] = compute_rms16(st->exc+i*st->subframeSize, st->subframeSize); + } + break; +#ifndef DISABLE_VBR + case SPEEX_GET_RELATIVE_QUALITY: + (*(float*)ptr)=st->relative_quality; + break; +#endif /* #ifndef DISABLE_VBR */ + case SPEEX_SET_INNOVATION_SAVE: + st->innov_rms_save = (spx_word16_t*)ptr; + break; + case SPEEX_SET_WIDEBAND: + st->isWideband = *((spx_int32_t*)ptr); + break; + case SPEEX_GET_STACK: + *((char**)ptr) = st->stack; + break; + default: + speex_warning_int("Unknown nb_ctl request: ", request); + return -1; + } + return 0; +} + +int nb_decoder_ctl(void *state, int request, void *ptr) +{ + DecState *st; + st=(DecState*)state; + switch(request) + { + case SPEEX_SET_LOW_MODE: + case SPEEX_SET_MODE: + st->submodeID = (*(spx_int32_t*)ptr); + break; + case SPEEX_GET_LOW_MODE: + case SPEEX_GET_MODE: + (*(spx_int32_t*)ptr) = st->submodeID; + break; + case SPEEX_SET_ENH: + st->lpc_enh_enabled = *((spx_int32_t*)ptr); + break; + case SPEEX_GET_ENH: + *((spx_int32_t*)ptr) = st->lpc_enh_enabled; + break; + case SPEEX_GET_FRAME_SIZE: + (*(spx_int32_t*)ptr) = st->frameSize; + break; + case SPEEX_GET_BITRATE: + if (st->submodes[st->submodeID]) + (*(spx_int32_t*)ptr) = st->sampling_rate*SUBMODE(bits_per_frame)/st->frameSize; + else + (*(spx_int32_t*)ptr) = st->sampling_rate*(NB_SUBMODE_BITS+1)/st->frameSize; + break; + case SPEEX_SET_SAMPLING_RATE: + st->sampling_rate = (*(spx_int32_t*)ptr); + break; + case SPEEX_GET_SAMPLING_RATE: + (*(spx_int32_t*)ptr)=st->sampling_rate; + break; + case SPEEX_SET_HANDLER: + { + SpeexCallback *c = (SpeexCallback*)ptr; + st->speex_callbacks[c->callback_id].func=c->func; + st->speex_callbacks[c->callback_id].data=c->data; + st->speex_callbacks[c->callback_id].callback_id=c->callback_id; + } + break; + case SPEEX_SET_USER_HANDLER: + { + SpeexCallback *c = (SpeexCallback*)ptr; + st->user_callback.func=c->func; + st->user_callback.data=c->data; + st->user_callback.callback_id=c->callback_id; + } + break; + case SPEEX_RESET_STATE: + { + int i; + for (i=0;ilpcSize;i++) + st->mem_sp[i]=0; + for (i=0;iframeSize + st->max_pitch + 1;i++) + st->excBuf[i]=0; + } + break; + case SPEEX_SET_SUBMODE_ENCODING: + st->encode_submode = (*(spx_int32_t*)ptr); + break; + case SPEEX_GET_SUBMODE_ENCODING: + (*(spx_int32_t*)ptr) = st->encode_submode; + break; + case SPEEX_GET_LOOKAHEAD: + (*(spx_int32_t*)ptr)=st->subframeSize; + break; + case SPEEX_SET_HIGHPASS: + st->highpass_enabled = (*(spx_int32_t*)ptr); + break; + case SPEEX_GET_HIGHPASS: + (*(spx_int32_t*)ptr) = st->highpass_enabled; + break; + /* FIXME: Convert to fixed-point and re-enable even when float API is disabled */ +#ifndef DISABLE_FLOAT_API + case SPEEX_GET_ACTIVITY: + { + float ret; + ret = log(st->level/st->min_level)/log(st->max_level/st->min_level); + if (ret>1) + ret = 1; + /* Done in a strange way to catch NaNs as well */ + if (!(ret > 0)) + ret = 0; + /*printf ("%f %f %f %f\n", st->level, st->min_level, st->max_level, ret);*/ + (*(spx_int32_t*)ptr) = (int)(100*ret); + } + break; +#endif + case SPEEX_GET_PI_GAIN: + { + int i; + spx_word32_t *g = (spx_word32_t*)ptr; + for (i=0;inbSubframes;i++) + g[i]=st->pi_gain[i]; + } + break; + case SPEEX_GET_EXC: + { + int i; + for (i=0;inbSubframes;i++) + ((spx_word16_t*)ptr)[i] = compute_rms16(st->exc+i*st->subframeSize, st->subframeSize); + } + break; + case SPEEX_GET_DTX_STATUS: + *((spx_int32_t*)ptr) = st->dtx_enabled; + break; + case SPEEX_SET_INNOVATION_SAVE: + st->innov_save = (spx_word16_t*)ptr; + break; + case SPEEX_SET_WIDEBAND: + st->isWideband = *((spx_int32_t*)ptr); + break; + case SPEEX_GET_STACK: + *((char**)ptr) = st->stack; + break; + default: + speex_warning_int("Unknown nb_ctl request: ", request); + return -1; + } + return 0; +} diff --git a/ios/IOSDuoduo/Voice/Code/Libs/libspeex/nb_celp.h b/ios/IOSDuoduo/Voice/Code/Libs/libspeex/nb_celp.h new file mode 100755 index 000000000..a18b86918 --- /dev/null +++ b/ios/IOSDuoduo/Voice/Code/Libs/libspeex/nb_celp.h @@ -0,0 +1,203 @@ +/* Copyright (C) 2002-2006 Jean-Marc Valin */ +/** + @file nb_celp.h + @brief Narrowband CELP encoder/decoder +*/ +/* + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + - Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + - Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + - Neither the name of the Xiph.org Foundation nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR + CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +*/ + +#ifndef NB_CELP_H +#define NB_CELP_H + +#include "modes.h" +#include "speex/speex_bits.h" +#include "speex/speex_callbacks.h" +#include "vbr.h" +#include "filters.h" + +#ifdef VORBIS_PSYCHO +#include "vorbis_psy.h" +#endif + +/**Structure representing the full state of the narrowband encoder*/ +typedef struct EncState { + const SpeexMode *mode; /**< Mode corresponding to the state */ + int first; /**< Is this the first frame? */ + int frameSize; /**< Size of frames */ + int subframeSize; /**< Size of sub-frames */ + int nbSubframes; /**< Number of sub-frames */ + int windowSize; /**< Analysis (LPC) window length */ + int lpcSize; /**< LPC order */ + int min_pitch; /**< Minimum pitch value allowed */ + int max_pitch; /**< Maximum pitch value allowed */ + + spx_word32_t cumul_gain; /**< Product of previously used pitch gains (Q10) */ + int bounded_pitch; /**< Next frame should not rely on previous frames for pitch */ + int ol_pitch; /**< Open-loop pitch */ + int ol_voiced; /**< Open-loop voiced/non-voiced decision */ + int *pitch; + +#ifdef VORBIS_PSYCHO + VorbisPsy *psy; + float *psy_window; + float *curve; + float *old_curve; +#endif + + spx_word16_t gamma1; /**< Perceptual filter: A(z/gamma1) */ + spx_word16_t gamma2; /**< Perceptual filter: A(z/gamma2) */ + spx_word16_t lpc_floor; /**< Noise floor multiplier for A[0] in LPC analysis*/ + char *stack; /**< Pseudo-stack allocation for temporary memory */ + spx_word16_t *winBuf; /**< Input buffer (original signal) */ + spx_word16_t *excBuf; /**< Excitation buffer */ + spx_word16_t *exc; /**< Start of excitation frame */ + spx_word16_t *swBuf; /**< Weighted signal buffer */ + spx_word16_t *sw; /**< Start of weighted signal frame */ + const spx_word16_t *window; /**< Temporary (Hanning) window */ + const spx_word16_t *lagWindow; /**< Window applied to auto-correlation */ + spx_lsp_t *old_lsp; /**< LSPs for previous frame */ + spx_lsp_t *old_qlsp; /**< Quantized LSPs for previous frame */ + spx_mem_t *mem_sp; /**< Filter memory for signal synthesis */ + spx_mem_t *mem_sw; /**< Filter memory for perceptually-weighted signal */ + spx_mem_t *mem_sw_whole; /**< Filter memory for perceptually-weighted signal (whole frame)*/ + spx_mem_t *mem_exc; /**< Filter memory for excitation (whole frame) */ + spx_mem_t *mem_exc2; /**< Filter memory for excitation (whole frame) */ + spx_mem_t mem_hp[2]; /**< High-pass filter memory */ + spx_word32_t *pi_gain; /**< Gain of LPC filter at theta=pi (fe/2) */ + spx_word16_t *innov_rms_save; /**< If non-NULL, innovation RMS is copied here */ + +#ifndef DISABLE_VBR + VBRState *vbr; /**< State of the VBR data */ + float vbr_quality; /**< Quality setting for VBR encoding */ + float relative_quality; /**< Relative quality that will be needed by VBR */ + spx_int32_t vbr_enabled; /**< 1 for enabling VBR, 0 otherwise */ + spx_int32_t vbr_max; /**< Max bit-rate allowed in VBR mode */ + int vad_enabled; /**< 1 for enabling VAD, 0 otherwise */ + int dtx_enabled; /**< 1 for enabling DTX, 0 otherwise */ + int dtx_count; /**< Number of consecutive DTX frames */ + spx_int32_t abr_enabled; /**< ABR setting (in bps), 0 if off */ + float abr_drift; + float abr_drift2; + float abr_count; +#endif /* #ifndef DISABLE_VBR */ + + int complexity; /**< Complexity setting (0-10 from least complex to most complex) */ + spx_int32_t sampling_rate; + int plc_tuning; + int encode_submode; + const SpeexSubmode * const *submodes; /**< Sub-mode data */ + int submodeID; /**< Activated sub-mode */ + int submodeSelect; /**< Mode chosen by the user (may differ from submodeID if VAD is on) */ + int isWideband; /**< Is this used as part of the embedded wideband codec */ + int highpass_enabled; /**< Is the input filter enabled */ +} EncState; + +/**Structure representing the full state of the narrowband decoder*/ +typedef struct DecState { + const SpeexMode *mode; /**< Mode corresponding to the state */ + int first; /**< Is this the first frame? */ + int count_lost; /**< Was the last frame lost? */ + int frameSize; /**< Size of frames */ + int subframeSize; /**< Size of sub-frames */ + int nbSubframes; /**< Number of sub-frames */ + int lpcSize; /**< LPC order */ + int min_pitch; /**< Minimum pitch value allowed */ + int max_pitch; /**< Maximum pitch value allowed */ + spx_int32_t sampling_rate; + + spx_word16_t last_ol_gain; /**< Open-loop gain for previous frame */ + + char *stack; /**< Pseudo-stack allocation for temporary memory */ + spx_word16_t *excBuf; /**< Excitation buffer */ + spx_word16_t *exc; /**< Start of excitation frame */ + spx_lsp_t *old_qlsp; /**< Quantized LSPs for previous frame */ + spx_coef_t *interp_qlpc; /**< Interpolated quantized LPCs */ + spx_mem_t *mem_sp; /**< Filter memory for synthesis signal */ + spx_mem_t mem_hp[2]; /**< High-pass filter memory */ + spx_word32_t *pi_gain; /**< Gain of LPC filter at theta=pi (fe/2) */ + spx_word16_t *innov_save; /** If non-NULL, innovation is copied here */ + + spx_word16_t level; + spx_word16_t max_level; + spx_word16_t min_level; + + /* This is used in packet loss concealment */ + int last_pitch; /**< Pitch of last correctly decoded frame */ + spx_word16_t last_pitch_gain; /**< Pitch gain of last correctly decoded frame */ + spx_word16_t pitch_gain_buf[3]; /**< Pitch gain of last decoded frames */ + int pitch_gain_buf_idx; /**< Tail of the buffer */ + spx_int32_t seed; /** Seed used for random number generation */ + + int encode_submode; + const SpeexSubmode * const *submodes; /**< Sub-mode data */ + int submodeID; /**< Activated sub-mode */ + int lpc_enh_enabled; /**< 1 when LPC enhancer is on, 0 otherwise */ + SpeexCallback speex_callbacks[SPEEX_MAX_CALLBACKS]; + + SpeexCallback user_callback; + + /*Vocoder data*/ + spx_word16_t voc_m1; + spx_word32_t voc_m2; + spx_word16_t voc_mean; + int voc_offset; + + int dtx_enabled; + int isWideband; /**< Is this used as part of the embedded wideband codec */ + int highpass_enabled; /**< Is the input filter enabled */ +} DecState; + +/** Initializes encoder state*/ +void *nb_encoder_init(const SpeexMode *m); + +/** De-allocates encoder state resources*/ +void nb_encoder_destroy(void *state); + +/** Encodes one frame*/ +int nb_encode(void *state, void *in, SpeexBits *bits); + + +/** Initializes decoder state*/ +void *nb_decoder_init(const SpeexMode *m); + +/** De-allocates decoder state resources*/ +void nb_decoder_destroy(void *state); + +/** Decodes one frame*/ +int nb_decode(void *state, SpeexBits *bits, void *out); + +/** ioctl-like function for controlling a narrowband encoder */ +int nb_encoder_ctl(void *state, int request, void *ptr); + +/** ioctl-like function for controlling a narrowband decoder */ +int nb_decoder_ctl(void *state, int request, void *ptr); + + +#endif diff --git a/ios/IOSDuoduo/Voice/Code/Libs/libspeex/os_support.h b/ios/IOSDuoduo/Voice/Code/Libs/libspeex/os_support.h new file mode 100755 index 000000000..6b74b0c22 --- /dev/null +++ b/ios/IOSDuoduo/Voice/Code/Libs/libspeex/os_support.h @@ -0,0 +1,169 @@ +/* Copyright (C) 2007 Jean-Marc Valin + + File: os_support.h + This is the (tiny) OS abstraction layer. Aside from math.h, this is the + only place where system headers are allowed. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are + met: + + 1. Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + 3. The name of the author may not be used to endorse or promote products + derived from this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, + INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + POSSIBILITY OF SUCH DAMAGE. +*/ + +#ifndef OS_SUPPORT_H +#define OS_SUPPORT_H + +#include +#include +#include + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif +#ifdef OS_SUPPORT_CUSTOM +#include "os_support_custom.h" +#endif + +/** Speex wrapper for calloc. To do your own dynamic allocation, all you need to do is replace this function, speex_realloc and speex_free + NOTE: speex_alloc needs to CLEAR THE MEMORY */ +#ifndef OVERRIDE_SPEEX_ALLOC +static inline void *speex_alloc (int size) +{ + /* WARNING: this is not equivalent to malloc(). If you want to use malloc() + or your own allocator, YOU NEED TO CLEAR THE MEMORY ALLOCATED. Otherwise + you will experience strange bugs */ + return calloc(size,1); +} +#endif + +/** Same as speex_alloc, except that the area is only needed inside a Speex call (might cause problem with wideband though) */ +#ifndef OVERRIDE_SPEEX_ALLOC_SCRATCH +static inline void *speex_alloc_scratch (int size) +{ + /* Scratch space doesn't need to be cleared */ + return calloc(size,1); +} +#endif + +/** Speex wrapper for realloc. To do your own dynamic allocation, all you need to do is replace this function, speex_alloc and speex_free */ +#ifndef OVERRIDE_SPEEX_REALLOC +static inline void *speex_realloc (void *ptr, int size) +{ + return realloc(ptr, size); +} +#endif + +/** Speex wrapper for calloc. To do your own dynamic allocation, all you need to do is replace this function, speex_realloc and speex_alloc */ +#ifndef OVERRIDE_SPEEX_FREE +static inline void speex_free (void *ptr) +{ + free(ptr); +} +#endif + +/** Same as speex_free, except that the area is only needed inside a Speex call (might cause problem with wideband though) */ +#ifndef OVERRIDE_SPEEX_FREE_SCRATCH +static inline void speex_free_scratch (void *ptr) +{ + free(ptr); +} +#endif + +/** Copy n bytes of memory from src to dst. The 0* term provides compile-time type checking */ +#ifndef OVERRIDE_SPEEX_COPY +#define SPEEX_COPY(dst, src, n) (memcpy((dst), (src), (n)*sizeof(*(dst)) + 0*((dst)-(src)) )) +#endif + +/** Copy n bytes of memory from src to dst, allowing overlapping regions. The 0* term + provides compile-time type checking */ +#ifndef OVERRIDE_SPEEX_MOVE +#define SPEEX_MOVE(dst, src, n) (memmove((dst), (src), (n)*sizeof(*(dst)) + 0*((dst)-(src)) )) +#endif + +/** Set n bytes of memory to value of c, starting at address s */ +#ifndef OVERRIDE_SPEEX_MEMSET +#define SPEEX_MEMSET(dst, c, n) (memset((dst), (c), (n)*sizeof(*(dst)))) +#endif + + +#ifndef OVERRIDE_SPEEX_FATAL +static inline void _speex_fatal(const char *str, const char *file, int line) +{ + fprintf (stderr, "Fatal (internal) error in %s, line %d: %s\n", file, line, str); + exit(1); +} +#endif + +#ifndef OVERRIDE_SPEEX_WARNING +static inline void speex_warning(const char *str) +{ +#ifndef DISABLE_WARNINGS + fprintf (stderr, "warning: %s\n", str); +#endif +} +#endif + +#ifndef OVERRIDE_SPEEX_WARNING_INT +static inline void speex_warning_int(const char *str, int val) +{ +#ifndef DISABLE_WARNINGS + fprintf (stderr, "warning: %s %d\n", str, val); +#endif +} +#endif + +#ifndef OVERRIDE_SPEEX_NOTIFY +static inline void speex_notify(const char *str) +{ +#ifndef DISABLE_NOTIFICATIONS + fprintf (stderr, "notification: %s\n", str); +#endif +} +#endif + +#ifndef OVERRIDE_SPEEX_PUTC +/** Speex wrapper for putc */ +static inline void _speex_putc(int ch, void *file) +{ + FILE *f = (FILE *)file; + fprintf(f, "%c", ch); +} +#endif + +#define speex_fatal(str) _speex_fatal(str, __FILE__, __LINE__); +#define speex_assert(cond) {if (!(cond)) {speex_fatal("assertion failed: " #cond);}} + +#ifndef RELEASE +static inline void print_vec(float *vec, int len, char *name) +{ + int i; + printf ("%s ", name); + for (i=0;i +#include "speex/speex_preprocess.h" +#include "speex/speex_echo.h" +#include "arch.h" +#include "fftwrap.h" +#include "filterbank.h" +#include "math_approx.h" +#include "os_support.h" + +#ifndef M_PI +#define M_PI 3.14159263 +#endif + +#define LOUDNESS_EXP 5.f +#define AMP_SCALE .001f +#define AMP_SCALE_1 1000.f + +#define NB_BANDS 24 + +#define SPEECH_PROB_START_DEFAULT QCONST16(0.35f,15) +#define SPEECH_PROB_CONTINUE_DEFAULT QCONST16(0.20f,15) +#define NOISE_SUPPRESS_DEFAULT -15 +#define ECHO_SUPPRESS_DEFAULT -40 +#define ECHO_SUPPRESS_ACTIVE_DEFAULT -15 + +#ifndef NULL +#define NULL 0 +#endif + +#define SQR(x) ((x)*(x)) +#define SQR16(x) (MULT16_16((x),(x))) +#define SQR16_Q15(x) (MULT16_16_Q15((x),(x))) + +#ifdef FIXED_POINT +static inline spx_word16_t DIV32_16_Q8(spx_word32_t a, spx_word32_t b) +{ + if (SHR32(a,7) >= b) + { + return 32767; + } else { + if (b>=QCONST32(1,23)) + { + a = SHR32(a,8); + b = SHR32(b,8); + } + if (b>=QCONST32(1,19)) + { + a = SHR32(a,4); + b = SHR32(b,4); + } + if (b>=QCONST32(1,15)) + { + a = SHR32(a,4); + b = SHR32(b,4); + } + a = SHL32(a,8); + return PDIV32_16(a,b); + } + +} +static inline spx_word16_t DIV32_16_Q15(spx_word32_t a, spx_word32_t b) +{ + if (SHR32(a,15) >= b) + { + return 32767; + } else { + if (b>=QCONST32(1,23)) + { + a = SHR32(a,8); + b = SHR32(b,8); + } + if (b>=QCONST32(1,19)) + { + a = SHR32(a,4); + b = SHR32(b,4); + } + if (b>=QCONST32(1,15)) + { + a = SHR32(a,4); + b = SHR32(b,4); + } + a = SHL32(a,15)-a; + return DIV32_16(a,b); + } +} +#define SNR_SCALING 256.f +#define SNR_SCALING_1 0.0039062f +#define SNR_SHIFT 8 + +#define FRAC_SCALING 32767.f +#define FRAC_SCALING_1 3.0518e-05 +#define FRAC_SHIFT 1 + +#define EXPIN_SCALING 2048.f +#define EXPIN_SCALING_1 0.00048828f +#define EXPIN_SHIFT 11 +#define EXPOUT_SCALING_1 1.5259e-05 + +#define NOISE_SHIFT 7 + +#else + +#define DIV32_16_Q8(a,b) ((a)/(b)) +#define DIV32_16_Q15(a,b) ((a)/(b)) +#define SNR_SCALING 1.f +#define SNR_SCALING_1 1.f +#define SNR_SHIFT 0 +#define FRAC_SCALING 1.f +#define FRAC_SCALING_1 1.f +#define FRAC_SHIFT 0 +#define NOISE_SHIFT 0 + +#define EXPIN_SCALING 1.f +#define EXPIN_SCALING_1 1.f +#define EXPOUT_SCALING_1 1.f + +#endif + +/** Speex pre-processor state. */ +struct SpeexPreprocessState_ { + /* Basic info */ + int frame_size; /**< Number of samples processed each time */ + int ps_size; /**< Number of points in the power spectrum */ + int sampling_rate; /**< Sampling rate of the input/output */ + int nbands; + FilterBank *bank; + + /* Parameters */ + int denoise_enabled; + int vad_enabled; + int dereverb_enabled; + spx_word16_t reverb_decay; + spx_word16_t reverb_level; + spx_word16_t speech_prob_start; + spx_word16_t speech_prob_continue; + int noise_suppress; + int echo_suppress; + int echo_suppress_active; + SpeexEchoState *echo_state; + + spx_word16_t speech_prob; /**< Probability last frame was speech */ + + /* DSP-related arrays */ + spx_word16_t *frame; /**< Processing frame (2*ps_size) */ + spx_word16_t *ft; /**< Processing frame in freq domain (2*ps_size) */ + spx_word32_t *ps; /**< Current power spectrum */ + spx_word16_t *gain2; /**< Adjusted gains */ + spx_word16_t *gain_floor; /**< Minimum gain allowed */ + spx_word16_t *window; /**< Analysis/Synthesis window */ + spx_word32_t *noise; /**< Noise estimate */ + spx_word32_t *reverb_estimate; /**< Estimate of reverb energy */ + spx_word32_t *old_ps; /**< Power spectrum for last frame */ + spx_word16_t *gain; /**< Ephraim Malah gain */ + spx_word16_t *prior; /**< A-priori SNR */ + spx_word16_t *post; /**< A-posteriori SNR */ + + spx_word32_t *S; /**< Smoothed power spectrum */ + spx_word32_t *Smin; /**< See Cohen paper */ + spx_word32_t *Stmp; /**< See Cohen paper */ + int *update_prob; /**< Probability of speech presence for noise update */ + + spx_word16_t *zeta; /**< Smoothed a priori SNR */ + spx_word32_t *echo_noise; + spx_word32_t *residual_echo; + + /* Misc */ + spx_word16_t *inbuf; /**< Input buffer (overlapped analysis) */ + spx_word16_t *outbuf; /**< Output buffer (for overlap and add) */ + + /* AGC stuff, only for floating point for now */ +#ifndef FIXED_POINT + int agc_enabled; + float agc_level; + float loudness_accum; + float *loudness_weight; /**< Perceptual loudness curve */ + float loudness; /**< Loudness estimate */ + float agc_gain; /**< Current AGC gain */ + float max_gain; /**< Maximum gain allowed */ + float max_increase_step; /**< Maximum increase in gain from one frame to another */ + float max_decrease_step; /**< Maximum decrease in gain from one frame to another */ + float prev_loudness; /**< Loudness of previous frame */ + float init_max; /**< Current gain limit during initialisation */ +#endif + int nb_adapt; /**< Number of frames used for adaptation so far */ + int was_speech; + int min_count; /**< Number of frames processed so far */ + void *fft_lookup; /**< Lookup table for the FFT */ +#ifdef FIXED_POINT + int frame_shift; +#endif +}; + + +static void conj_window(spx_word16_t *w, int len) +{ + int i; + for (i=0;i19) + return ADD32(EXTEND32(Q15_ONE),EXTEND32(DIV32_16(QCONST32(.1296,23), SHR32(xx,EXPIN_SHIFT-SNR_SHIFT)))); + frac = SHL32(xx-SHL32(ind,10),5); + return SHL32(DIV32_16(PSHR32(MULT16_16(Q15_ONE-frac,table[ind]) + MULT16_16(frac,table[ind+1]),7),(spx_sqrt(SHL32(xx,15)+6711))),7); +} + +static inline spx_word16_t qcurve(spx_word16_t x) +{ + x = MAX16(x, 1); + return DIV32_16(SHL32(EXTEND32(32767),9),ADD16(512,MULT16_16_Q15(QCONST16(.60f,15),DIV32_16(32767,x)))); +} + +/* Compute the gain floor based on different floors for the background noise and residual echo */ +static void compute_gain_floor(int noise_suppress, int effective_echo_suppress, spx_word32_t *noise, spx_word32_t *echo, spx_word16_t *gain_floor, int len) +{ + int i; + + if (noise_suppress > effective_echo_suppress) + { + spx_word16_t noise_gain, gain_ratio; + noise_gain = EXTRACT16(MIN32(Q15_ONE,SHR32(spx_exp(MULT16_16(QCONST16(0.11513,11),noise_suppress)),1))); + gain_ratio = EXTRACT16(MIN32(Q15_ONE,SHR32(spx_exp(MULT16_16(QCONST16(.2302585f,11),effective_echo_suppress-noise_suppress)),1))); + + /* gain_floor = sqrt [ (noise*noise_floor + echo*echo_floor) / (noise+echo) ] */ + for (i=0;i19) + return FRAC_SCALING*(1+.1296/x); + frac = 2*x-integer; + return FRAC_SCALING*((1-frac)*table[ind] + frac*table[ind+1])/sqrt(x+.0001f); +} + +static inline spx_word16_t qcurve(spx_word16_t x) +{ + return 1.f/(1.f+.15f/(SNR_SCALING_1*x)); +} + +static void compute_gain_floor(int noise_suppress, int effective_echo_suppress, spx_word32_t *noise, spx_word32_t *echo, spx_word16_t *gain_floor, int len) +{ + int i; + float echo_floor; + float noise_floor; + + noise_floor = exp(.2302585f*noise_suppress); + echo_floor = exp(.2302585f*effective_echo_suppress); + + /* Compute the gain floor based on different floors for the background noise and residual echo */ + for (i=0;iframe_size = frame_size; + + /* Round ps_size down to the nearest power of two */ +#if 0 + i=1; + st->ps_size = st->frame_size; + while(1) + { + if (st->ps_size & ~i) + { + st->ps_size &= ~i; + i<<=1; + } else { + break; + } + } + + + if (st->ps_size < 3*st->frame_size/4) + st->ps_size = st->ps_size * 3 / 2; +#else + st->ps_size = st->frame_size; +#endif + + N = st->ps_size; + N3 = 2*N - st->frame_size; + N4 = st->frame_size - N3; + + st->sampling_rate = sampling_rate; + st->denoise_enabled = 1; + st->vad_enabled = 0; + st->dereverb_enabled = 0; + st->reverb_decay = 0; + st->reverb_level = 0; + st->noise_suppress = NOISE_SUPPRESS_DEFAULT; + st->echo_suppress = ECHO_SUPPRESS_DEFAULT; + st->echo_suppress_active = ECHO_SUPPRESS_ACTIVE_DEFAULT; + + st->speech_prob_start = SPEECH_PROB_START_DEFAULT; + st->speech_prob_continue = SPEECH_PROB_CONTINUE_DEFAULT; + + st->echo_state = NULL; + + st->nbands = NB_BANDS; + M = st->nbands; + st->bank = filterbank_new(M, sampling_rate, N, 1); + + st->frame = (spx_word16_t*)speex_alloc(2*N*sizeof(spx_word16_t)); + st->window = (spx_word16_t*)speex_alloc(2*N*sizeof(spx_word16_t)); + st->ft = (spx_word16_t*)speex_alloc(2*N*sizeof(spx_word16_t)); + + st->ps = (spx_word32_t*)speex_alloc((N+M)*sizeof(spx_word32_t)); + st->noise = (spx_word32_t*)speex_alloc((N+M)*sizeof(spx_word32_t)); + st->echo_noise = (spx_word32_t*)speex_alloc((N+M)*sizeof(spx_word32_t)); + st->residual_echo = (spx_word32_t*)speex_alloc((N+M)*sizeof(spx_word32_t)); + st->reverb_estimate = (spx_word32_t*)speex_alloc((N+M)*sizeof(spx_word32_t)); + st->old_ps = (spx_word32_t*)speex_alloc((N+M)*sizeof(spx_word32_t)); + st->prior = (spx_word16_t*)speex_alloc((N+M)*sizeof(spx_word16_t)); + st->post = (spx_word16_t*)speex_alloc((N+M)*sizeof(spx_word16_t)); + st->gain = (spx_word16_t*)speex_alloc((N+M)*sizeof(spx_word16_t)); + st->gain2 = (spx_word16_t*)speex_alloc((N+M)*sizeof(spx_word16_t)); + st->gain_floor = (spx_word16_t*)speex_alloc((N+M)*sizeof(spx_word16_t)); + st->zeta = (spx_word16_t*)speex_alloc((N+M)*sizeof(spx_word16_t)); + + st->S = (spx_word32_t*)speex_alloc(N*sizeof(spx_word32_t)); + st->Smin = (spx_word32_t*)speex_alloc(N*sizeof(spx_word32_t)); + st->Stmp = (spx_word32_t*)speex_alloc(N*sizeof(spx_word32_t)); + st->update_prob = (int*)speex_alloc(N*sizeof(int)); + + st->inbuf = (spx_word16_t*)speex_alloc(N3*sizeof(spx_word16_t)); + st->outbuf = (spx_word16_t*)speex_alloc(N3*sizeof(spx_word16_t)); + + conj_window(st->window, 2*N3); + for (i=2*N3;i<2*st->ps_size;i++) + st->window[i]=Q15_ONE; + + if (N4>0) + { + for (i=N3-1;i>=0;i--) + { + st->window[i+N3+N4]=st->window[i+N3]; + st->window[i+N3]=1; + } + } + for (i=0;inoise[i]=QCONST32(1.f,NOISE_SHIFT); + st->reverb_estimate[i]=0; + st->old_ps[i]=1; + st->gain[i]=Q15_ONE; + st->post[i]=SHL16(1, SNR_SHIFT); + st->prior[i]=SHL16(1, SNR_SHIFT); + } + + for (i=0;iupdate_prob[i] = 1; + for (i=0;iinbuf[i]=0; + st->outbuf[i]=0; + } +#ifndef FIXED_POINT + st->agc_enabled = 0; + st->agc_level = 8000; + st->loudness_weight = (float*)speex_alloc(N*sizeof(float)); + for (i=0;iloudness_weight[i] = .5f*(1.f/(1.f+ff/8000.f))+1.f*exp(-.5f*(ff-3800.f)*(ff-3800.f)/9e5f);*/ + st->loudness_weight[i] = .35f-.35f*ff/16000.f+.73f*exp(-.5f*(ff-3800)*(ff-3800)/9e5f); + if (st->loudness_weight[i]<.01f) + st->loudness_weight[i]=.01f; + st->loudness_weight[i] *= st->loudness_weight[i]; + } + /*st->loudness = pow(AMP_SCALE*st->agc_level,LOUDNESS_EXP);*/ + st->loudness = 1e-15; + st->agc_gain = 1; + st->max_gain = 30; + st->max_increase_step = exp(0.11513f * 12.*st->frame_size / st->sampling_rate); + st->max_decrease_step = exp(-0.11513f * 40.*st->frame_size / st->sampling_rate); + st->prev_loudness = 1; + st->init_max = 1; +#endif + st->was_speech = 0; + + st->fft_lookup = spx_fft_init(2*N); + + st->nb_adapt=0; + st->min_count=0; + return st; +} + +EXPORT void speex_preprocess_state_destroy(SpeexPreprocessState *st) +{ + speex_free(st->frame); + speex_free(st->ft); + speex_free(st->ps); + speex_free(st->gain2); + speex_free(st->gain_floor); + speex_free(st->window); + speex_free(st->noise); + speex_free(st->reverb_estimate); + speex_free(st->old_ps); + speex_free(st->gain); + speex_free(st->prior); + speex_free(st->post); +#ifndef FIXED_POINT + speex_free(st->loudness_weight); +#endif + speex_free(st->echo_noise); + speex_free(st->residual_echo); + + speex_free(st->S); + speex_free(st->Smin); + speex_free(st->Stmp); + speex_free(st->update_prob); + speex_free(st->zeta); + + speex_free(st->inbuf); + speex_free(st->outbuf); + + spx_fft_destroy(st->fft_lookup); + filterbank_destroy(st->bank); + speex_free(st); +} + +/* FIXME: The AGC doesn't work yet with fixed-point*/ +#ifndef FIXED_POINT +static void speex_compute_agc(SpeexPreprocessState *st, spx_word16_t Pframe, spx_word16_t *ft) +{ + int i; + int N = st->ps_size; + float target_gain; + float loudness=1.f; + float rate; + + for (i=2;ips[i]* st->loudness_weight[i]; + } + loudness=sqrt(loudness); + /*if (loudness < 2*pow(st->loudness, 1.0/LOUDNESS_EXP) && + loudness*2 > pow(st->loudness, 1.0/LOUDNESS_EXP))*/ + if (Pframe>.3f) + { + /*rate=2.0f*Pframe*Pframe/(1+st->nb_loudness_adapt);*/ + rate = .03*Pframe*Pframe; + st->loudness = (1-rate)*st->loudness + (rate)*pow(AMP_SCALE*loudness, LOUDNESS_EXP); + st->loudness_accum = (1-rate)*st->loudness_accum + rate; + if (st->init_max < st->max_gain && st->nb_adapt > 20) + st->init_max *= 1.f + .1f*Pframe*Pframe; + } + /*printf ("%f %f %f %f\n", Pframe, loudness, pow(st->loudness, 1.0f/LOUDNESS_EXP), st->loudness2);*/ + + target_gain = AMP_SCALE*st->agc_level*pow(st->loudness/(1e-4+st->loudness_accum), -1.0f/LOUDNESS_EXP); + + if ((Pframe>.5 && st->nb_adapt > 20) || target_gain < st->agc_gain) + { + if (target_gain > st->max_increase_step*st->agc_gain) + target_gain = st->max_increase_step*st->agc_gain; + if (target_gain < st->max_decrease_step*st->agc_gain && loudness < 10*st->prev_loudness) + target_gain = st->max_decrease_step*st->agc_gain; + if (target_gain > st->max_gain) + target_gain = st->max_gain; + if (target_gain > st->init_max) + target_gain = st->init_max; + + st->agc_gain = target_gain; + } + /*fprintf (stderr, "%f %f %f\n", loudness, (float)AMP_SCALE_1*pow(st->loudness, 1.0f/LOUDNESS_EXP), st->agc_gain);*/ + + for (i=0;i<2*N;i++) + ft[i] *= st->agc_gain; + st->prev_loudness = loudness; +} +#endif + +static void preprocess_analysis(SpeexPreprocessState *st, spx_int16_t *x) +{ + int i; + int N = st->ps_size; + int N3 = 2*N - st->frame_size; + int N4 = st->frame_size - N3; + spx_word32_t *ps=st->ps; + + /* 'Build' input frame */ + for (i=0;iframe[i]=st->inbuf[i]; + for (i=0;iframe_size;i++) + st->frame[N3+i]=x[i]; + + /* Update inbuf */ + for (i=0;iinbuf[i]=x[N4+i]; + + /* Windowing */ + for (i=0;i<2*N;i++) + st->frame[i] = MULT16_16_Q15(st->frame[i], st->window[i]); + +#ifdef FIXED_POINT + { + spx_word16_t max_val=0; + for (i=0;i<2*N;i++) + max_val = MAX16(max_val, ABS16(st->frame[i])); + st->frame_shift = 14-spx_ilog2(EXTEND32(max_val)); + for (i=0;i<2*N;i++) + st->frame[i] = SHL16(st->frame[i], st->frame_shift); + } +#endif + + /* Perform FFT */ + spx_fft(st->fft_lookup, st->frame, st->ft); + + /* Power spectrum */ + ps[0]=MULT16_16(st->ft[0],st->ft[0]); + for (i=1;ift[2*i-1],st->ft[2*i-1]) + MULT16_16(st->ft[2*i],st->ft[2*i]); + for (i=0;ips[i] = PSHR32(st->ps[i], 2*st->frame_shift); + + filterbank_compute_bank32(st->bank, ps, ps+N); +} + +static void update_noise_prob(SpeexPreprocessState *st) +{ + int i; + int min_range; + int N = st->ps_size; + + for (i=1;iS[i] = MULT16_32_Q15(QCONST16(.8f,15),st->S[i]) + MULT16_32_Q15(QCONST16(.05f,15),st->ps[i-1]) + + MULT16_32_Q15(QCONST16(.1f,15),st->ps[i]) + MULT16_32_Q15(QCONST16(.05f,15),st->ps[i+1]); + st->S[0] = MULT16_32_Q15(QCONST16(.8f,15),st->S[0]) + MULT16_32_Q15(QCONST16(.2f,15),st->ps[0]); + st->S[N-1] = MULT16_32_Q15(QCONST16(.8f,15),st->S[N-1]) + MULT16_32_Q15(QCONST16(.2f,15),st->ps[N-1]); + + if (st->nb_adapt==1) + { + for (i=0;iSmin[i] = st->Stmp[i] = 0; + } + + if (st->nb_adapt < 100) + min_range = 15; + else if (st->nb_adapt < 1000) + min_range = 50; + else if (st->nb_adapt < 10000) + min_range = 150; + else + min_range = 300; + if (st->min_count > min_range) + { + st->min_count = 0; + for (i=0;iSmin[i] = MIN32(st->Stmp[i], st->S[i]); + st->Stmp[i] = st->S[i]; + } + } else { + for (i=0;iSmin[i] = MIN32(st->Smin[i], st->S[i]); + st->Stmp[i] = MIN32(st->Stmp[i], st->S[i]); + } + } + for (i=0;iS[i]) > st->Smin[i]) + st->update_prob[i] = 1; + else + st->update_prob[i] = 0; + /*fprintf (stderr, "%f ", st->S[i]/st->Smin[i]);*/ + /*fprintf (stderr, "%f ", st->update_prob[i]);*/ + } + +} + +#define NOISE_OVERCOMPENS 1. + +void speex_echo_get_residual(SpeexEchoState *st, spx_word32_t *Yout, int len); + +EXPORT int speex_preprocess(SpeexPreprocessState *st, spx_int16_t *x, spx_int32_t *echo) +{ + return speex_preprocess_run(st, x); +} + +EXPORT int speex_preprocess_run(SpeexPreprocessState *st, spx_int16_t *x) +{ + int i; + int M; + int N = st->ps_size; + int N3 = 2*N - st->frame_size; + int N4 = st->frame_size - N3; + spx_word32_t *ps=st->ps; + spx_word32_t Zframe; + spx_word16_t Pframe; + spx_word16_t beta, beta_1; + spx_word16_t effective_echo_suppress; + + st->nb_adapt++; + if (st->nb_adapt>20000) + st->nb_adapt = 20000; + st->min_count++; + + beta = MAX16(QCONST16(.03,15),DIV32_16(Q15_ONE,st->nb_adapt)); + beta_1 = Q15_ONE-beta; + M = st->nbands; + /* Deal with residual echo if provided */ + if (st->echo_state) + { + speex_echo_get_residual(st->echo_state, st->residual_echo, N); +#ifndef FIXED_POINT + /* If there are NaNs or ridiculous values, it'll show up in the DC and we just reset everything to zero */ + if (!(st->residual_echo[0] >=0 && st->residual_echo[0]residual_echo[i] = 0; + } +#endif + for (i=0;iecho_noise[i] = MAX32(MULT16_32_Q15(QCONST16(.6f,15),st->echo_noise[i]), st->residual_echo[i]); + filterbank_compute_bank32(st->bank, st->echo_noise, st->echo_noise+N); + } else { + for (i=0;iecho_noise[i] = 0; + } + preprocess_analysis(st, x); + + update_noise_prob(st); + + /* Noise estimation always updated for the 10 first frames */ + /*if (st->nb_adapt<10) + { + for (i=1;iupdate_prob[i] = 0; + } + */ + + /* Update the noise estimate for the frequencies where it can be */ + for (i=0;iupdate_prob[i] || st->ps[i] < PSHR32(st->noise[i], NOISE_SHIFT)) + st->noise[i] = MAX32(EXTEND32(0),MULT16_32_Q15(beta_1,st->noise[i]) + MULT16_32_Q15(beta,SHL32(st->ps[i],NOISE_SHIFT))); + } + filterbank_compute_bank32(st->bank, st->noise, st->noise+N); + + /* Special case for first frame */ + if (st->nb_adapt==1) + for (i=0;iold_ps[i] = ps[i]; + + /* Compute a posteriori SNR */ + for (i=0;inoise[i],NOISE_SHIFT)) , st->echo_noise[i]) , st->reverb_estimate[i]); + + /* A posteriori SNR = ps/noise - 1*/ + st->post[i] = SUB16(DIV32_16_Q8(ps[i],tot_noise), QCONST16(1.f,SNR_SHIFT)); + st->post[i]=MIN16(st->post[i], QCONST16(100.f,SNR_SHIFT)); + + /* Computing update gamma = .1 + .9*(old/(old+noise))^2 */ + gamma = QCONST16(.1f,15)+MULT16_16_Q15(QCONST16(.89f,15),SQR16_Q15(DIV32_16_Q15(st->old_ps[i],ADD32(st->old_ps[i],tot_noise)))); + + /* A priori SNR update = gamma*max(0,post) + (1-gamma)*old/noise */ + st->prior[i] = EXTRACT16(PSHR32(ADD32(MULT16_16(gamma,MAX16(0,st->post[i])), MULT16_16(Q15_ONE-gamma,DIV32_16_Q8(st->old_ps[i],tot_noise))), 15)); + st->prior[i]=MIN16(st->prior[i], QCONST16(100.f,SNR_SHIFT)); + } + + /*print_vec(st->post, N+M, "");*/ + + /* Recursive average of the a priori SNR. A bit smoothed for the psd components */ + st->zeta[0] = PSHR32(ADD32(MULT16_16(QCONST16(.7f,15),st->zeta[0]), MULT16_16(QCONST16(.3f,15),st->prior[0])),15); + for (i=1;izeta[i] = PSHR32(ADD32(ADD32(ADD32(MULT16_16(QCONST16(.7f,15),st->zeta[i]), MULT16_16(QCONST16(.15f,15),st->prior[i])), + MULT16_16(QCONST16(.075f,15),st->prior[i-1])), MULT16_16(QCONST16(.075f,15),st->prior[i+1])),15); + for (i=N-1;izeta[i] = PSHR32(ADD32(MULT16_16(QCONST16(.7f,15),st->zeta[i]), MULT16_16(QCONST16(.3f,15),st->prior[i])),15); + + /* Speech probability of presence for the entire frame is based on the average filterbank a priori SNR */ + Zframe = 0; + for (i=N;izeta[i])); + Pframe = QCONST16(.1f,15)+MULT16_16_Q15(QCONST16(.899f,15),qcurve(DIV32_16(Zframe,st->nbands))); + + effective_echo_suppress = EXTRACT16(PSHR32(ADD32(MULT16_16(SUB16(Q15_ONE,Pframe), st->echo_suppress), MULT16_16(Pframe, st->echo_suppress_active)),15)); + + compute_gain_floor(st->noise_suppress, effective_echo_suppress, st->noise+N, st->echo_noise+N, st->gain_floor+N, M); + + /* Compute Ephraim & Malah gain speech probability of presence for each critical band (Bark scale) + Technically this is actually wrong because the EM gaim assumes a slightly different probability + distribution */ + for (i=N;iprior[i]), 15), ADD16(st->prior[i], SHL32(1,SNR_SHIFT))); + theta = MULT16_32_P15(prior_ratio, QCONST32(1.f,EXPIN_SHIFT)+SHL32(EXTEND32(st->post[i]),EXPIN_SHIFT-SNR_SHIFT)); + + MM = hypergeom_gain(theta); + /* Gain with bound */ + st->gain[i] = EXTRACT16(MIN32(Q15_ONE, MULT16_32_Q15(prior_ratio, MM))); + /* Save old Bark power spectrum */ + st->old_ps[i] = MULT16_32_P15(QCONST16(.2f,15),st->old_ps[i]) + MULT16_32_P15(MULT16_16_P15(QCONST16(.8f,15),SQR16_Q15(st->gain[i])),ps[i]); + + P1 = QCONST16(.199f,15)+MULT16_16_Q15(QCONST16(.8f,15),qcurve (st->zeta[i])); + q = Q15_ONE-MULT16_16_Q15(Pframe,P1); +#ifdef FIXED_POINT + theta = MIN32(theta, EXTEND32(32767)); +/*Q8*/tmp = MULT16_16_Q15((SHL32(1,SNR_SHIFT)+st->prior[i]),EXTRACT16(MIN32(Q15ONE,SHR32(spx_exp(-EXTRACT16(theta)),1)))); + tmp = MIN16(QCONST16(3.,SNR_SHIFT), tmp); /* Prevent overflows in the next line*/ +/*Q8*/tmp = EXTRACT16(PSHR32(MULT16_16(PDIV32_16(SHL32(EXTEND32(q),8),(Q15_ONE-q)),tmp),8)); + st->gain2[i]=DIV32_16(SHL32(EXTEND32(32767),SNR_SHIFT), ADD16(256,tmp)); +#else + st->gain2[i]=1/(1.f + (q/(1.f-q))*(1+st->prior[i])*exp(-theta)); +#endif + } + /* Convert the EM gains and speech prob to linear frequency */ + filterbank_compute_psd16(st->bank,st->gain2+N, st->gain2); + filterbank_compute_psd16(st->bank,st->gain+N, st->gain); + + /* Use 1 for linear gain resolution (best) or 0 for Bark gain resolution (faster) */ + if (1) + { + filterbank_compute_psd16(st->bank,st->gain_floor+N, st->gain_floor); + + /* Compute gain according to the Ephraim-Malah algorithm -- linear frequency */ + for (i=0;iprior[i]), 15), ADD16(st->prior[i], SHL32(1,SNR_SHIFT))); + theta = MULT16_32_P15(prior_ratio, QCONST32(1.f,EXPIN_SHIFT)+SHL32(EXTEND32(st->post[i]),EXPIN_SHIFT-SNR_SHIFT)); + + /* Optimal estimator for loudness domain */ + MM = hypergeom_gain(theta); + /* EM gain with bound */ + g = EXTRACT16(MIN32(Q15_ONE, MULT16_32_Q15(prior_ratio, MM))); + /* Interpolated speech probability of presence */ + p = st->gain2[i]; + + /* Constrain the gain to be close to the Bark scale gain */ + if (MULT16_16_Q15(QCONST16(.333f,15),g) > st->gain[i]) + g = MULT16_16(3,st->gain[i]); + st->gain[i] = g; + + /* Save old power spectrum */ + st->old_ps[i] = MULT16_32_P15(QCONST16(.2f,15),st->old_ps[i]) + MULT16_32_P15(MULT16_16_P15(QCONST16(.8f,15),SQR16_Q15(st->gain[i])),ps[i]); + + /* Apply gain floor */ + if (st->gain[i] < st->gain_floor[i]) + st->gain[i] = st->gain_floor[i]; + + /* Exponential decay model for reverberation (unused) */ + /*st->reverb_estimate[i] = st->reverb_decay*st->reverb_estimate[i] + st->reverb_decay*st->reverb_level*st->gain[i]*st->gain[i]*st->ps[i];*/ + + /* Take into account speech probability of presence (loudness domain MMSE estimator) */ + /* gain2 = [p*sqrt(gain)+(1-p)*sqrt(gain _floor) ]^2 */ + tmp = MULT16_16_P15(p,spx_sqrt(SHL32(EXTEND32(st->gain[i]),15))) + MULT16_16_P15(SUB16(Q15_ONE,p),spx_sqrt(SHL32(EXTEND32(st->gain_floor[i]),15))); + st->gain2[i]=SQR16_Q15(tmp); + + /* Use this if you want a log-domain MMSE estimator instead */ + /*st->gain2[i] = pow(st->gain[i], p) * pow(st->gain_floor[i],1.f-p);*/ + } + } else { + for (i=N;igain2[i]; + st->gain[i] = MAX16(st->gain[i], st->gain_floor[i]); + tmp = MULT16_16_P15(p,spx_sqrt(SHL32(EXTEND32(st->gain[i]),15))) + MULT16_16_P15(SUB16(Q15_ONE,p),spx_sqrt(SHL32(EXTEND32(st->gain_floor[i]),15))); + st->gain2[i]=SQR16_Q15(tmp); + } + filterbank_compute_psd16(st->bank,st->gain2+N, st->gain2); + } + + /* If noise suppression is off, don't apply the gain (but then why call this in the first place!) */ + if (!st->denoise_enabled) + { + for (i=0;igain2[i]=Q15_ONE; + } + + /* Apply computed gain */ + for (i=1;ift[2*i-1] = MULT16_16_P15(st->gain2[i],st->ft[2*i-1]); + st->ft[2*i] = MULT16_16_P15(st->gain2[i],st->ft[2*i]); + } + st->ft[0] = MULT16_16_P15(st->gain2[0],st->ft[0]); + st->ft[2*N-1] = MULT16_16_P15(st->gain2[N-1],st->ft[2*N-1]); + + /*FIXME: This *will* not work for fixed-point */ +#ifndef FIXED_POINT + if (st->agc_enabled) + speex_compute_agc(st, Pframe, st->ft); +#endif + + /* Inverse FFT with 1/N scaling */ + spx_ifft(st->fft_lookup, st->ft, st->frame); + /* Scale back to original (lower) amplitude */ + for (i=0;i<2*N;i++) + st->frame[i] = PSHR16(st->frame[i], st->frame_shift); + + /*FIXME: This *will* not work for fixed-point */ +#ifndef FIXED_POINT + if (st->agc_enabled) + { + float max_sample=0; + for (i=0;i<2*N;i++) + if (fabs(st->frame[i])>max_sample) + max_sample = fabs(st->frame[i]); + if (max_sample>28000.f) + { + float damp = 28000.f/max_sample; + for (i=0;i<2*N;i++) + st->frame[i] *= damp; + } + } +#endif + + /* Synthesis window (for WOLA) */ + for (i=0;i<2*N;i++) + st->frame[i] = MULT16_16_Q15(st->frame[i], st->window[i]); + + /* Perform overlap and add */ + for (i=0;ioutbuf[i] + st->frame[i]; + for (i=0;iframe[N3+i]; + + /* Update outbuf */ + for (i=0;ioutbuf[i] = st->frame[st->frame_size+i]; + + /* FIXME: This VAD is a kludge */ + st->speech_prob = Pframe; + if (st->vad_enabled) + { + if (st->speech_prob > st->speech_prob_start || (st->was_speech && st->speech_prob > st->speech_prob_continue)) + { + st->was_speech=1; + return 1; + } else + { + st->was_speech=0; + return 0; + } + } else { + return 1; + } +} + +EXPORT void speex_preprocess_estimate_update(SpeexPreprocessState *st, spx_int16_t *x) +{ + int i; + int N = st->ps_size; + int N3 = 2*N - st->frame_size; + int M; + spx_word32_t *ps=st->ps; + + M = st->nbands; + st->min_count++; + + preprocess_analysis(st, x); + + update_noise_prob(st); + + for (i=1;iupdate_prob[i] || st->ps[i] < PSHR32(st->noise[i],NOISE_SHIFT)) + { + st->noise[i] = MULT16_32_Q15(QCONST16(.95f,15),st->noise[i]) + MULT16_32_Q15(QCONST16(.05f,15),SHL32(st->ps[i],NOISE_SHIFT)); + } + } + + for (i=0;ioutbuf[i] = MULT16_16_Q15(x[st->frame_size-N3+i],st->window[st->frame_size+i]); + + /* Save old power spectrum */ + for (i=0;iold_ps[i] = ps[i]; + + for (i=0;ireverb_estimate[i] = MULT16_32_Q15(st->reverb_decay, st->reverb_estimate[i]); +} + + +EXPORT int speex_preprocess_ctl(SpeexPreprocessState *state, int request, void *ptr) +{ + int i; + SpeexPreprocessState *st; + st=(SpeexPreprocessState*)state; + switch(request) + { + case SPEEX_PREPROCESS_SET_DENOISE: + st->denoise_enabled = (*(spx_int32_t*)ptr); + break; + case SPEEX_PREPROCESS_GET_DENOISE: + (*(spx_int32_t*)ptr) = st->denoise_enabled; + break; +#ifndef FIXED_POINT + case SPEEX_PREPROCESS_SET_AGC: + st->agc_enabled = (*(spx_int32_t*)ptr); + break; + case SPEEX_PREPROCESS_GET_AGC: + (*(spx_int32_t*)ptr) = st->agc_enabled; + break; +#ifndef DISABLE_FLOAT_API + case SPEEX_PREPROCESS_SET_AGC_LEVEL: + st->agc_level = (*(float*)ptr); + if (st->agc_level<1) + st->agc_level=1; + if (st->agc_level>32768) + st->agc_level=32768; + break; + case SPEEX_PREPROCESS_GET_AGC_LEVEL: + (*(float*)ptr) = st->agc_level; + break; +#endif /* #ifndef DISABLE_FLOAT_API */ + case SPEEX_PREPROCESS_SET_AGC_INCREMENT: + st->max_increase_step = exp(0.11513f * (*(spx_int32_t*)ptr)*st->frame_size / st->sampling_rate); + break; + case SPEEX_PREPROCESS_GET_AGC_INCREMENT: + (*(spx_int32_t*)ptr) = floor(.5+8.6858*log(st->max_increase_step)*st->sampling_rate/st->frame_size); + break; + case SPEEX_PREPROCESS_SET_AGC_DECREMENT: + st->max_decrease_step = exp(0.11513f * (*(spx_int32_t*)ptr)*st->frame_size / st->sampling_rate); + break; + case SPEEX_PREPROCESS_GET_AGC_DECREMENT: + (*(spx_int32_t*)ptr) = floor(.5+8.6858*log(st->max_decrease_step)*st->sampling_rate/st->frame_size); + break; + case SPEEX_PREPROCESS_SET_AGC_MAX_GAIN: + st->max_gain = exp(0.11513f * (*(spx_int32_t*)ptr)); + break; + case SPEEX_PREPROCESS_GET_AGC_MAX_GAIN: + (*(spx_int32_t*)ptr) = floor(.5+8.6858*log(st->max_gain)); + break; +#endif + case SPEEX_PREPROCESS_SET_VAD: + speex_warning("The VAD has been replaced by a hack pending a complete rewrite"); + st->vad_enabled = (*(spx_int32_t*)ptr); + break; + case SPEEX_PREPROCESS_GET_VAD: + (*(spx_int32_t*)ptr) = st->vad_enabled; + break; + + case SPEEX_PREPROCESS_SET_DEREVERB: + st->dereverb_enabled = (*(spx_int32_t*)ptr); + for (i=0;ips_size;i++) + st->reverb_estimate[i]=0; + break; + case SPEEX_PREPROCESS_GET_DEREVERB: + (*(spx_int32_t*)ptr) = st->dereverb_enabled; + break; + + case SPEEX_PREPROCESS_SET_DEREVERB_LEVEL: + /* FIXME: Re-enable when de-reverberation is actually enabled again */ + /*st->reverb_level = (*(float*)ptr);*/ + break; + case SPEEX_PREPROCESS_GET_DEREVERB_LEVEL: + /* FIXME: Re-enable when de-reverberation is actually enabled again */ + /*(*(float*)ptr) = st->reverb_level;*/ + break; + + case SPEEX_PREPROCESS_SET_DEREVERB_DECAY: + /* FIXME: Re-enable when de-reverberation is actually enabled again */ + /*st->reverb_decay = (*(float*)ptr);*/ + break; + case SPEEX_PREPROCESS_GET_DEREVERB_DECAY: + /* FIXME: Re-enable when de-reverberation is actually enabled again */ + /*(*(float*)ptr) = st->reverb_decay;*/ + break; + + case SPEEX_PREPROCESS_SET_PROB_START: + *(spx_int32_t*)ptr = MIN32(100,MAX32(0, *(spx_int32_t*)ptr)); + st->speech_prob_start = DIV32_16(MULT16_16(Q15ONE,*(spx_int32_t*)ptr), 100); + break; + case SPEEX_PREPROCESS_GET_PROB_START: + (*(spx_int32_t*)ptr) = MULT16_16_Q15(st->speech_prob_start, 100); + break; + + case SPEEX_PREPROCESS_SET_PROB_CONTINUE: + *(spx_int32_t*)ptr = MIN32(100,MAX32(0, *(spx_int32_t*)ptr)); + st->speech_prob_continue = DIV32_16(MULT16_16(Q15ONE,*(spx_int32_t*)ptr), 100); + break; + case SPEEX_PREPROCESS_GET_PROB_CONTINUE: + (*(spx_int32_t*)ptr) = MULT16_16_Q15(st->speech_prob_continue, 100); + break; + + case SPEEX_PREPROCESS_SET_NOISE_SUPPRESS: + st->noise_suppress = -ABS(*(spx_int32_t*)ptr); + break; + case SPEEX_PREPROCESS_GET_NOISE_SUPPRESS: + (*(spx_int32_t*)ptr) = st->noise_suppress; + break; + case SPEEX_PREPROCESS_SET_ECHO_SUPPRESS: + st->echo_suppress = -ABS(*(spx_int32_t*)ptr); + break; + case SPEEX_PREPROCESS_GET_ECHO_SUPPRESS: + (*(spx_int32_t*)ptr) = st->echo_suppress; + break; + case SPEEX_PREPROCESS_SET_ECHO_SUPPRESS_ACTIVE: + st->echo_suppress_active = -ABS(*(spx_int32_t*)ptr); + break; + case SPEEX_PREPROCESS_GET_ECHO_SUPPRESS_ACTIVE: + (*(spx_int32_t*)ptr) = st->echo_suppress_active; + break; + case SPEEX_PREPROCESS_SET_ECHO_STATE: + st->echo_state = (SpeexEchoState*)ptr; + break; + case SPEEX_PREPROCESS_GET_ECHO_STATE: + (*(SpeexEchoState**)ptr) = (SpeexEchoState*)st->echo_state; + break; +#ifndef FIXED_POINT + case SPEEX_PREPROCESS_GET_AGC_LOUDNESS: + (*(spx_int32_t*)ptr) = pow(st->loudness, 1.0/LOUDNESS_EXP); + break; + case SPEEX_PREPROCESS_GET_AGC_GAIN: + (*(spx_int32_t*)ptr) = floor(.5+8.6858*log(st->agc_gain)); + break; +#endif + case SPEEX_PREPROCESS_GET_PSD_SIZE: + case SPEEX_PREPROCESS_GET_NOISE_PSD_SIZE: + (*(spx_int32_t*)ptr) = st->ps_size; + break; + case SPEEX_PREPROCESS_GET_PSD: + for(i=0;ips_size;i++) + ((spx_int32_t *)ptr)[i] = (spx_int32_t) st->ps[i]; + break; + case SPEEX_PREPROCESS_GET_NOISE_PSD: + for(i=0;ips_size;i++) + ((spx_int32_t *)ptr)[i] = (spx_int32_t) PSHR32(st->noise[i], NOISE_SHIFT); + break; + case SPEEX_PREPROCESS_GET_PROB: + (*(spx_int32_t*)ptr) = MULT16_16_Q15(st->speech_prob, 100); + break; +#ifndef FIXED_POINT + case SPEEX_PREPROCESS_SET_AGC_TARGET: + st->agc_level = (*(spx_int32_t*)ptr); + if (st->agc_level<1) + st->agc_level=1; + if (st->agc_level>32768) + st->agc_level=32768; + break; + case SPEEX_PREPROCESS_GET_AGC_TARGET: + (*(spx_int32_t*)ptr) = st->agc_level; + break; +#endif + default: + speex_warning_int("Unknown speex_preprocess_ctl request: ", request); + return -1; + } + return 0; +} + +#ifdef FIXED_DEBUG +long long spx_mips=0; +#endif + diff --git a/ios/IOSDuoduo/Voice/Code/Libs/libspeex/pseudofloat.h b/ios/IOSDuoduo/Voice/Code/Libs/libspeex/pseudofloat.h new file mode 100755 index 000000000..fa841a010 --- /dev/null +++ b/ios/IOSDuoduo/Voice/Code/Libs/libspeex/pseudofloat.h @@ -0,0 +1,379 @@ +/* Copyright (C) 2005 Jean-Marc Valin */ +/** + @file pseudofloat.h + @brief Pseudo-floating point + * This header file provides a lightweight floating point type for + * use on fixed-point platforms when a large dynamic range is + * required. The new type is not compatible with the 32-bit IEEE format, + * it is not even remotely as accurate as 32-bit floats, and is not + * even guaranteed to produce even remotely correct results for code + * other than Speex. It makes all kinds of shortcuts that are acceptable + * for Speex, but may not be acceptable for your application. You're + * quite welcome to reuse this code and improve it, but don't assume + * it works out of the box. Most likely, it doesn't. + */ +/* + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + - Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + - Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + - Neither the name of the Xiph.org Foundation nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR + CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#ifndef PSEUDOFLOAT_H +#define PSEUDOFLOAT_H + +#include "arch.h" +#include "os_support.h" +#include "math_approx.h" +#include + +#ifdef FIXED_POINT + +typedef struct { + spx_int16_t m; + spx_int16_t e; +} spx_float_t; + +static const spx_float_t FLOAT_ZERO = {0,0}; +static const spx_float_t FLOAT_ONE = {16384,-14}; +static const spx_float_t FLOAT_HALF = {16384,-15}; + +#define MIN(a,b) ((a)<(b)?(a):(b)) +static inline spx_float_t PSEUDOFLOAT(spx_int32_t x) +{ + int e=0; + int sign=0; + if (x<0) + { + sign = 1; + x = -x; + } + if (x==0) + { + spx_float_t r = {0,0}; + return r; + } + e = spx_ilog2(ABS32(x))-14; + x = VSHR32(x, e); + if (sign) + { + spx_float_t r; + r.m = -x; + r.e = e; + return r; + } + else + { + spx_float_t r; + r.m = x; + r.e = e; + return r; + } +} + + +static inline spx_float_t FLOAT_ADD(spx_float_t a, spx_float_t b) +{ + spx_float_t r; + if (a.m==0) + return b; + else if (b.m==0) + return a; + if ((a).e > (b).e) + { + r.m = ((a).m>>1) + ((b).m>>MIN(15,(a).e-(b).e+1)); + r.e = (a).e+1; + } + else + { + r.m = ((b).m>>1) + ((a).m>>MIN(15,(b).e-(a).e+1)); + r.e = (b).e+1; + } + if (r.m>0) + { + if (r.m<16384) + { + r.m<<=1; + r.e-=1; + } + } else { + if (r.m>-16384) + { + r.m<<=1; + r.e-=1; + } + } + /*printf ("%f + %f = %f\n", REALFLOAT(a), REALFLOAT(b), REALFLOAT(r));*/ + return r; +} + +static inline spx_float_t FLOAT_SUB(spx_float_t a, spx_float_t b) +{ + spx_float_t r; + if (a.m==0) + return b; + else if (b.m==0) + return a; + if ((a).e > (b).e) + { + r.m = ((a).m>>1) - ((b).m>>MIN(15,(a).e-(b).e+1)); + r.e = (a).e+1; + } + else + { + r.m = ((a).m>>MIN(15,(b).e-(a).e+1)) - ((b).m>>1); + r.e = (b).e+1; + } + if (r.m>0) + { + if (r.m<16384) + { + r.m<<=1; + r.e-=1; + } + } else { + if (r.m>-16384) + { + r.m<<=1; + r.e-=1; + } + } + /*printf ("%f + %f = %f\n", REALFLOAT(a), REALFLOAT(b), REALFLOAT(r));*/ + return r; +} + +static inline int FLOAT_LT(spx_float_t a, spx_float_t b) +{ + if (a.m==0) + return b.m>0; + else if (b.m==0) + return a.m<0; + if ((a).e > (b).e) + return ((a).m>>1) < ((b).m>>MIN(15,(a).e-(b).e+1)); + else + return ((b).m>>1) > ((a).m>>MIN(15,(b).e-(a).e+1)); + +} + +static inline int FLOAT_GT(spx_float_t a, spx_float_t b) +{ + return FLOAT_LT(b,a); +} + +static inline spx_float_t FLOAT_MULT(spx_float_t a, spx_float_t b) +{ + spx_float_t r; + r.m = (spx_int16_t)((spx_int32_t)(a).m*(b).m>>15); + r.e = (a).e+(b).e+15; + if (r.m>0) + { + if (r.m<16384) + { + r.m<<=1; + r.e-=1; + } + } else { + if (r.m>-16384) + { + r.m<<=1; + r.e-=1; + } + } + /*printf ("%f * %f = %f\n", REALFLOAT(a), REALFLOAT(b), REALFLOAT(r));*/ + return r; +} + +static inline spx_float_t FLOAT_AMULT(spx_float_t a, spx_float_t b) +{ + spx_float_t r; + r.m = (spx_int16_t)((spx_int32_t)(a).m*(b).m>>15); + r.e = (a).e+(b).e+15; + return r; +} + + +static inline spx_float_t FLOAT_SHL(spx_float_t a, int b) +{ + spx_float_t r; + r.m = a.m; + r.e = a.e+b; + return r; +} + +static inline spx_int16_t FLOAT_EXTRACT16(spx_float_t a) +{ + if (a.e<0) + return EXTRACT16((EXTEND32(a.m)+(EXTEND32(1)<<(-a.e-1)))>>-a.e); + else + return a.m<>-a.e; + else + return EXTEND32(a.m)<=SHL32(EXTEND32(b.m-1),15)) + { + a >>= 1; + e++; + } + r.m = DIV32_16(a,b.m); + r.e = e-b.e; + return r; +} + + +/* Do NOT attempt to divide by a negative number */ +static inline spx_float_t FLOAT_DIV32(spx_word32_t a, spx_word32_t b) +{ + int e0=0,e=0; + spx_float_t r; + if (a==0) + { + return FLOAT_ZERO; + } + if (b>32767) + { + e0 = spx_ilog2(b)-14; + b = VSHR32(b, e0); + e0 = -e0; + } + e = spx_ilog2(ABS32(a))-spx_ilog2(b-1)-15; + a = VSHR32(a, e); + if (ABS32(a)>=SHL32(EXTEND32(b-1),15)) + { + a >>= 1; + e++; + } + e += e0; + r.m = DIV32_16(a,b); + r.e = e; + return r; +} + +/* Do NOT attempt to divide by a negative number */ +static inline spx_float_t FLOAT_DIVU(spx_float_t a, spx_float_t b) +{ + int e=0; + spx_int32_t num; + spx_float_t r; + if (b.m<=0) + { + speex_warning_int("Attempted to divide by", b.m); + return FLOAT_ONE; + } + num = a.m; + a.m = ABS16(a.m); + while (a.m >= b.m) + { + e++; + a.m >>= 1; + } + num = num << (15-e); + r.m = DIV32_16(num,b.m); + r.e = a.e-b.e-15+e; + return r; +} + +static inline spx_float_t FLOAT_SQRT(spx_float_t a) +{ + spx_float_t r; + spx_int32_t m; + m = SHL32(EXTEND32(a.m), 14); + r.e = a.e - 14; + if (r.e & 1) + { + r.e -= 1; + m <<= 1; + } + r.e >>= 1; + r.m = spx_sqrt(m); + return r; +} + +#else + +#define spx_float_t float +#define FLOAT_ZERO 0.f +#define FLOAT_ONE 1.f +#define FLOAT_HALF 0.5f +#define PSEUDOFLOAT(x) (x) +#define FLOAT_MULT(a,b) ((a)*(b)) +#define FLOAT_AMULT(a,b) ((a)*(b)) +#define FLOAT_MUL32(a,b) ((a)*(b)) +#define FLOAT_DIV32(a,b) ((a)/(b)) +#define FLOAT_EXTRACT16(a) (a) +#define FLOAT_EXTRACT32(a) (a) +#define FLOAT_ADD(a,b) ((a)+(b)) +#define FLOAT_SUB(a,b) ((a)-(b)) +#define REALFLOAT(x) (x) +#define FLOAT_DIV32_FLOAT(a,b) ((a)/(b)) +#define FLOAT_MUL32U(a,b) ((a)*(b)) +#define FLOAT_SHL(a,b) (a) +#define FLOAT_LT(a,b) ((a)<(b)) +#define FLOAT_GT(a,b) ((a)>(b)) +#define FLOAT_DIVU(a,b) ((a)/(b)) +#define FLOAT_SQRT(a) (spx_sqrt(a)) + +#endif + +#endif diff --git a/ios/IOSDuoduo/Voice/Code/Libs/libspeex/quant_lsp.c b/ios/IOSDuoduo/Voice/Code/Libs/libspeex/quant_lsp.c new file mode 100755 index 000000000..e624d1a28 --- /dev/null +++ b/ios/IOSDuoduo/Voice/Code/Libs/libspeex/quant_lsp.c @@ -0,0 +1,385 @@ +/* Copyright (C) 2002 Jean-Marc Valin + File: quant_lsp.c + LSP vector quantization + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + - Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + - Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + - Neither the name of the Xiph.org Foundation nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR + CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "quant_lsp.h" +#include "os_support.h" +#include +#ifndef M_PI +#define M_PI 3.14159265358979323846 +#endif + +#include "arch.h" + +#ifdef BFIN_ASM +#include "quant_lsp_bfin.h" +#endif + +#ifdef FIXED_POINT + +#define LSP_LINEAR(i) (SHL16(i+1,11)) +#define LSP_LINEAR_HIGH(i) (ADD16(MULT16_16_16(i,2560),6144)) +#define LSP_DIV_256(x) (SHL16((spx_word16_t)x, 5)) +#define LSP_DIV_512(x) (SHL16((spx_word16_t)x, 4)) +#define LSP_DIV_1024(x) (SHL16((spx_word16_t)x, 3)) +#define LSP_PI 25736 + +#else + +#define LSP_LINEAR(i) (.25*(i)+.25) +#define LSP_LINEAR_HIGH(i) (.3125*(i)+.75) +#define LSP_SCALE 256. +#define LSP_DIV_256(x) (0.0039062*(x)) +#define LSP_DIV_512(x) (0.0019531*(x)) +#define LSP_DIV_1024(x) (0.00097656*(x)) +#define LSP_PI M_PI + +#endif + +static void compute_quant_weights(spx_lsp_t *qlsp, spx_word16_t *quant_weight, int order) +{ + int i; + spx_word16_t tmp1, tmp2; + for (i=0;i tmp2 ? tmp1 : tmp2; + }*/ + + for (i=0;i>> 16;\n\t" +" R1 = (A1 += R2.L*R0.H) (IS);\n\t" +"4: R3 = R3 + R1;\n\t" + +" cc =R3<%0;\n\t" +" if cc %0=R3;\n\t" +" if cc %1=R5;\n\t" +"2: R5 += 1;\n\t" +" L0 = 0;\n\t" +" L1 = 0;\n\t" + : "=&d" (best_dist), "=&d" (best_id) + : "a" (x), "a" (weight), "b" (cdbk), "a" (nbVec), "a" (nbDim) + : "I0", "I1", "P2", "R0", "R1", "R2", "R3", "R5", "A1", + "L0", "L1", "B0", "B1" + ); + + for (j=0;j +static void *speex_alloc (int size) {return calloc(size,1);} +static void *speex_realloc (void *ptr, int size) {return realloc(ptr, size);} +static void speex_free (void *ptr) {free(ptr);} +#include "speex_resampler.h" +#include "arch.h" +#else /* OUTSIDE_SPEEX */ + +#include "speex/speex_resampler.h" +#include "arch.h" +#include "os_support.h" +#endif /* OUTSIDE_SPEEX */ + +#include "stack_alloc.h" +#include + +#ifndef M_PI +#define M_PI 3.14159263 +#endif + +#ifdef FIXED_POINT +#define WORD2INT(x) ((x) < -32767 ? -32768 : ((x) > 32766 ? 32767 : (x))) +#else +#define WORD2INT(x) ((x) < -32767.5f ? -32768 : ((x) > 32766.5f ? 32767 : floor(.5+(x)))) +#endif + +#define IMAX(a,b) ((a) > (b) ? (a) : (b)) +#define IMIN(a,b) ((a) < (b) ? (a) : (b)) + +#ifndef NULL +#define NULL 0 +#endif + +#ifdef _USE_SSE +#include "resample_sse.h" +#endif + +/* Numer of elements to allocate on the stack */ +#ifdef VAR_ARRAYS +#define FIXED_STACK_ALLOC 8192 +#else +#define FIXED_STACK_ALLOC 1024 +#endif + +typedef int (*resampler_basic_func)(SpeexResamplerState *, spx_uint32_t , const spx_word16_t *, spx_uint32_t *, spx_word16_t *, spx_uint32_t *); + +struct SpeexResamplerState_ { + spx_uint32_t in_rate; + spx_uint32_t out_rate; + spx_uint32_t num_rate; + spx_uint32_t den_rate; + + int quality; + spx_uint32_t nb_channels; + spx_uint32_t filt_len; + spx_uint32_t mem_alloc_size; + spx_uint32_t buffer_size; + int int_advance; + int frac_advance; + float cutoff; + spx_uint32_t oversample; + int initialised; + int started; + + /* These are per-channel */ + spx_int32_t *last_sample; + spx_uint32_t *samp_frac_num; + spx_uint32_t *magic_samples; + + spx_word16_t *mem; + spx_word16_t *sinc_table; + spx_uint32_t sinc_table_length; + resampler_basic_func resampler_ptr; + + int in_stride; + int out_stride; +} ; + +static double kaiser12_table[68] = { + 0.99859849, 1.00000000, 0.99859849, 0.99440475, 0.98745105, 0.97779076, + 0.96549770, 0.95066529, 0.93340547, 0.91384741, 0.89213598, 0.86843014, + 0.84290116, 0.81573067, 0.78710866, 0.75723148, 0.72629970, 0.69451601, + 0.66208321, 0.62920216, 0.59606986, 0.56287762, 0.52980938, 0.49704014, + 0.46473455, 0.43304576, 0.40211431, 0.37206735, 0.34301800, 0.31506490, + 0.28829195, 0.26276832, 0.23854851, 0.21567274, 0.19416736, 0.17404546, + 0.15530766, 0.13794294, 0.12192957, 0.10723616, 0.09382272, 0.08164178, + 0.07063950, 0.06075685, 0.05193064, 0.04409466, 0.03718069, 0.03111947, + 0.02584161, 0.02127838, 0.01736250, 0.01402878, 0.01121463, 0.00886058, + 0.00691064, 0.00531256, 0.00401805, 0.00298291, 0.00216702, 0.00153438, + 0.00105297, 0.00069463, 0.00043489, 0.00025272, 0.00013031, 0.0000527734, + 0.00001000, 0.00000000}; +/* +static double kaiser12_table[36] = { + 0.99440475, 1.00000000, 0.99440475, 0.97779076, 0.95066529, 0.91384741, + 0.86843014, 0.81573067, 0.75723148, 0.69451601, 0.62920216, 0.56287762, + 0.49704014, 0.43304576, 0.37206735, 0.31506490, 0.26276832, 0.21567274, + 0.17404546, 0.13794294, 0.10723616, 0.08164178, 0.06075685, 0.04409466, + 0.03111947, 0.02127838, 0.01402878, 0.00886058, 0.00531256, 0.00298291, + 0.00153438, 0.00069463, 0.00025272, 0.0000527734, 0.00000500, 0.00000000}; +*/ +static double kaiser10_table[36] = { + 0.99537781, 1.00000000, 0.99537781, 0.98162644, 0.95908712, 0.92831446, + 0.89005583, 0.84522401, 0.79486424, 0.74011713, 0.68217934, 0.62226347, + 0.56155915, 0.50119680, 0.44221549, 0.38553619, 0.33194107, 0.28205962, + 0.23636152, 0.19515633, 0.15859932, 0.12670280, 0.09935205, 0.07632451, + 0.05731132, 0.04193980, 0.02979584, 0.02044510, 0.01345224, 0.00839739, + 0.00488951, 0.00257636, 0.00115101, 0.00035515, 0.00000000, 0.00000000}; + +static double kaiser8_table[36] = { + 0.99635258, 1.00000000, 0.99635258, 0.98548012, 0.96759014, 0.94302200, + 0.91223751, 0.87580811, 0.83439927, 0.78875245, 0.73966538, 0.68797126, + 0.63451750, 0.58014482, 0.52566725, 0.47185369, 0.41941150, 0.36897272, + 0.32108304, 0.27619388, 0.23465776, 0.19672670, 0.16255380, 0.13219758, + 0.10562887, 0.08273982, 0.06335451, 0.04724088, 0.03412321, 0.02369490, + 0.01563093, 0.00959968, 0.00527363, 0.00233883, 0.00050000, 0.00000000}; + +static double kaiser6_table[36] = { + 0.99733006, 1.00000000, 0.99733006, 0.98935595, 0.97618418, 0.95799003, + 0.93501423, 0.90755855, 0.87598009, 0.84068475, 0.80211977, 0.76076565, + 0.71712752, 0.67172623, 0.62508937, 0.57774224, 0.53019925, 0.48295561, + 0.43647969, 0.39120616, 0.34752997, 0.30580127, 0.26632152, 0.22934058, + 0.19505503, 0.16360756, 0.13508755, 0.10953262, 0.08693120, 0.06722600, + 0.05031820, 0.03607231, 0.02432151, 0.01487334, 0.00752000, 0.00000000}; + +struct FuncDef { + double *table; + int oversample; +}; + +static struct FuncDef _KAISER12 = {kaiser12_table, 64}; +#define KAISER12 (&_KAISER12) +/*static struct FuncDef _KAISER12 = {kaiser12_table, 32}; +#define KAISER12 (&_KAISER12)*/ +static struct FuncDef _KAISER10 = {kaiser10_table, 32}; +#define KAISER10 (&_KAISER10) +static struct FuncDef _KAISER8 = {kaiser8_table, 32}; +#define KAISER8 (&_KAISER8) +static struct FuncDef _KAISER6 = {kaiser6_table, 32}; +#define KAISER6 (&_KAISER6) + +struct QualityMapping { + int base_length; + int oversample; + float downsample_bandwidth; + float upsample_bandwidth; + struct FuncDef *window_func; +}; + + +/* This table maps conversion quality to internal parameters. There are two + reasons that explain why the up-sampling bandwidth is larger than the + down-sampling bandwidth: + 1) When up-sampling, we can assume that the spectrum is already attenuated + close to the Nyquist rate (from an A/D or a previous resampling filter) + 2) Any aliasing that occurs very close to the Nyquist rate will be masked + by the sinusoids/noise just below the Nyquist rate (guaranteed only for + up-sampling). +*/ +static const struct QualityMapping quality_map[11] = { + { 8, 4, 0.830f, 0.860f, KAISER6 }, /* Q0 */ + { 16, 4, 0.850f, 0.880f, KAISER6 }, /* Q1 */ + { 32, 4, 0.882f, 0.910f, KAISER6 }, /* Q2 */ /* 82.3% cutoff ( ~60 dB stop) 6 */ + { 48, 8, 0.895f, 0.917f, KAISER8 }, /* Q3 */ /* 84.9% cutoff ( ~80 dB stop) 8 */ + { 64, 8, 0.921f, 0.940f, KAISER8 }, /* Q4 */ /* 88.7% cutoff ( ~80 dB stop) 8 */ + { 80, 16, 0.922f, 0.940f, KAISER10}, /* Q5 */ /* 89.1% cutoff (~100 dB stop) 10 */ + { 96, 16, 0.940f, 0.945f, KAISER10}, /* Q6 */ /* 91.5% cutoff (~100 dB stop) 10 */ + {128, 16, 0.950f, 0.950f, KAISER10}, /* Q7 */ /* 93.1% cutoff (~100 dB stop) 10 */ + {160, 16, 0.960f, 0.960f, KAISER10}, /* Q8 */ /* 94.5% cutoff (~100 dB stop) 10 */ + {192, 32, 0.968f, 0.968f, KAISER12}, /* Q9 */ /* 95.5% cutoff (~100 dB stop) 10 */ + {256, 32, 0.975f, 0.975f, KAISER12}, /* Q10 */ /* 96.6% cutoff (~100 dB stop) 10 */ +}; +/*8,24,40,56,80,104,128,160,200,256,320*/ +static double compute_func(float x, struct FuncDef *func) +{ + float y, frac; + double interp[4]; + int ind; + y = x*func->oversample; + ind = (int)floor(y); + frac = (y-ind); + /* CSE with handle the repeated powers */ + interp[3] = -0.1666666667*frac + 0.1666666667*(frac*frac*frac); + interp[2] = frac + 0.5*(frac*frac) - 0.5*(frac*frac*frac); + /*interp[2] = 1.f - 0.5f*frac - frac*frac + 0.5f*frac*frac*frac;*/ + interp[0] = -0.3333333333*frac + 0.5*(frac*frac) - 0.1666666667*(frac*frac*frac); + /* Just to make sure we don't have rounding problems */ + interp[1] = 1.f-interp[3]-interp[2]-interp[0]; + + /*sum = frac*accum[1] + (1-frac)*accum[2];*/ + return interp[0]*func->table[ind] + interp[1]*func->table[ind+1] + interp[2]*func->table[ind+2] + interp[3]*func->table[ind+3]; +} + +#if 0 +#include +int main(int argc, char **argv) +{ + int i; + for (i=0;i<256;i++) + { + printf ("%f\n", compute_func(i/256., KAISER12)); + } + return 0; +} +#endif + +#ifdef FIXED_POINT +/* The slow way of computing a sinc for the table. Should improve that some day */ +static spx_word16_t sinc(float cutoff, float x, int N, struct FuncDef *window_func) +{ + /*fprintf (stderr, "%f ", x);*/ + float xx = x * cutoff; + if (fabs(x)<1e-6f) + return WORD2INT(32768.*cutoff); + else if (fabs(x) > .5f*N) + return 0; + /*FIXME: Can it really be any slower than this? */ + return WORD2INT(32768.*cutoff*sin(M_PI*xx)/(M_PI*xx) * compute_func(fabs(2.*x/N), window_func)); +} +#else +/* The slow way of computing a sinc for the table. Should improve that some day */ +static spx_word16_t sinc(float cutoff, float x, int N, struct FuncDef *window_func) +{ + /*fprintf (stderr, "%f ", x);*/ + float xx = x * cutoff; + if (fabs(x)<1e-6) + return cutoff; + else if (fabs(x) > .5*N) + return 0; + /*FIXME: Can it really be any slower than this? */ + return cutoff*sin(M_PI*xx)/(M_PI*xx) * compute_func(fabs(2.*x/N), window_func); +} +#endif + +#ifdef FIXED_POINT +static void cubic_coef(spx_word16_t x, spx_word16_t interp[4]) +{ + /* Compute interpolation coefficients. I'm not sure whether this corresponds to cubic interpolation + but I know it's MMSE-optimal on a sinc */ + spx_word16_t x2, x3; + x2 = MULT16_16_P15(x, x); + x3 = MULT16_16_P15(x, x2); + interp[0] = PSHR32(MULT16_16(QCONST16(-0.16667f, 15),x) + MULT16_16(QCONST16(0.16667f, 15),x3),15); + interp[1] = EXTRACT16(EXTEND32(x) + SHR32(SUB32(EXTEND32(x2),EXTEND32(x3)),1)); + interp[3] = PSHR32(MULT16_16(QCONST16(-0.33333f, 15),x) + MULT16_16(QCONST16(.5f,15),x2) - MULT16_16(QCONST16(0.16667f, 15),x3),15); + /* Just to make sure we don't have rounding problems */ + interp[2] = Q15_ONE-interp[0]-interp[1]-interp[3]; + if (interp[2]<32767) + interp[2]+=1; +} +#else +static void cubic_coef(spx_word16_t frac, spx_word16_t interp[4]) +{ + /* Compute interpolation coefficients. I'm not sure whether this corresponds to cubic interpolation + but I know it's MMSE-optimal on a sinc */ + interp[0] = -0.16667f*frac + 0.16667f*frac*frac*frac; + interp[1] = frac + 0.5f*frac*frac - 0.5f*frac*frac*frac; + /*interp[2] = 1.f - 0.5f*frac - frac*frac + 0.5f*frac*frac*frac;*/ + interp[3] = -0.33333f*frac + 0.5f*frac*frac - 0.16667f*frac*frac*frac; + /* Just to make sure we don't have rounding problems */ + interp[2] = 1.-interp[0]-interp[1]-interp[3]; +} +#endif + +static int resampler_basic_direct_single(SpeexResamplerState *st, spx_uint32_t channel_index, const spx_word16_t *in, spx_uint32_t *in_len, spx_word16_t *out, spx_uint32_t *out_len) +{ + const int N = st->filt_len; + int out_sample = 0; + int last_sample = st->last_sample[channel_index]; + spx_uint32_t samp_frac_num = st->samp_frac_num[channel_index]; + const spx_word16_t *sinc_table = st->sinc_table; + const int out_stride = st->out_stride; + const int int_advance = st->int_advance; + const int frac_advance = st->frac_advance; + const spx_uint32_t den_rate = st->den_rate; + spx_word32_t sum; + int j; + + while (!(last_sample >= (spx_int32_t)*in_len || out_sample >= (spx_int32_t)*out_len)) + { + const spx_word16_t *sinc = & sinc_table[samp_frac_num*N]; + const spx_word16_t *iptr = & in[last_sample]; + +#ifndef OVERRIDE_INNER_PRODUCT_SINGLE + float accum[4] = {0,0,0,0}; + + for(j=0;j= den_rate) + { + samp_frac_num -= den_rate; + last_sample++; + } + } + + st->last_sample[channel_index] = last_sample; + st->samp_frac_num[channel_index] = samp_frac_num; + return out_sample; +} + +#ifdef FIXED_POINT +#else +/* This is the same as the previous function, except with a double-precision accumulator */ +static int resampler_basic_direct_double(SpeexResamplerState *st, spx_uint32_t channel_index, const spx_word16_t *in, spx_uint32_t *in_len, spx_word16_t *out, spx_uint32_t *out_len) +{ + const int N = st->filt_len; + int out_sample = 0; + int last_sample = st->last_sample[channel_index]; + spx_uint32_t samp_frac_num = st->samp_frac_num[channel_index]; + const spx_word16_t *sinc_table = st->sinc_table; + const int out_stride = st->out_stride; + const int int_advance = st->int_advance; + const int frac_advance = st->frac_advance; + const spx_uint32_t den_rate = st->den_rate; + double sum; + int j; + + while (!(last_sample >= (spx_int32_t)*in_len || out_sample >= (spx_int32_t)*out_len)) + { + const spx_word16_t *sinc = & sinc_table[samp_frac_num*N]; + const spx_word16_t *iptr = & in[last_sample]; + +#ifndef OVERRIDE_INNER_PRODUCT_DOUBLE + double accum[4] = {0,0,0,0}; + + for(j=0;j= den_rate) + { + samp_frac_num -= den_rate; + last_sample++; + } + } + + st->last_sample[channel_index] = last_sample; + st->samp_frac_num[channel_index] = samp_frac_num; + return out_sample; +} +#endif + +static int resampler_basic_interpolate_single(SpeexResamplerState *st, spx_uint32_t channel_index, const spx_word16_t *in, spx_uint32_t *in_len, spx_word16_t *out, spx_uint32_t *out_len) +{ + const int N = st->filt_len; + int out_sample = 0; + int last_sample = st->last_sample[channel_index]; + spx_uint32_t samp_frac_num = st->samp_frac_num[channel_index]; + const int out_stride = st->out_stride; + const int int_advance = st->int_advance; + const int frac_advance = st->frac_advance; + const spx_uint32_t den_rate = st->den_rate; + int j; + spx_word32_t sum; + + while (!(last_sample >= (spx_int32_t)*in_len || out_sample >= (spx_int32_t)*out_len)) + { + const spx_word16_t *iptr = & in[last_sample]; + + const int offset = samp_frac_num*st->oversample/st->den_rate; +#ifdef FIXED_POINT + const spx_word16_t frac = PDIV32(SHL32((samp_frac_num*st->oversample) % st->den_rate,15),st->den_rate); +#else + const spx_word16_t frac = ((float)((samp_frac_num*st->oversample) % st->den_rate))/st->den_rate; +#endif + spx_word16_t interp[4]; + + +#ifndef OVERRIDE_INTERPOLATE_PRODUCT_SINGLE + spx_word32_t accum[4] = {0,0,0,0}; + + for(j=0;jsinc_table[4+(j+1)*st->oversample-offset-2]); + accum[1] += MULT16_16(curr_in,st->sinc_table[4+(j+1)*st->oversample-offset-1]); + accum[2] += MULT16_16(curr_in,st->sinc_table[4+(j+1)*st->oversample-offset]); + accum[3] += MULT16_16(curr_in,st->sinc_table[4+(j+1)*st->oversample-offset+1]); + } + + cubic_coef(frac, interp); + sum = MULT16_32_Q15(interp[0],accum[0]) + MULT16_32_Q15(interp[1],accum[1]) + MULT16_32_Q15(interp[2],accum[2]) + MULT16_32_Q15(interp[3],accum[3]); +#else + cubic_coef(frac, interp); + sum = interpolate_product_single(iptr, st->sinc_table + st->oversample + 4 - offset - 2, N, st->oversample, interp); +#endif + + out[out_stride * out_sample++] = PSHR32(sum,15); + last_sample += int_advance; + samp_frac_num += frac_advance; + if (samp_frac_num >= den_rate) + { + samp_frac_num -= den_rate; + last_sample++; + } + } + + st->last_sample[channel_index] = last_sample; + st->samp_frac_num[channel_index] = samp_frac_num; + return out_sample; +} + +#ifdef FIXED_POINT +#else +/* This is the same as the previous function, except with a double-precision accumulator */ +static int resampler_basic_interpolate_double(SpeexResamplerState *st, spx_uint32_t channel_index, const spx_word16_t *in, spx_uint32_t *in_len, spx_word16_t *out, spx_uint32_t *out_len) +{ + const int N = st->filt_len; + int out_sample = 0; + int last_sample = st->last_sample[channel_index]; + spx_uint32_t samp_frac_num = st->samp_frac_num[channel_index]; + const int out_stride = st->out_stride; + const int int_advance = st->int_advance; + const int frac_advance = st->frac_advance; + const spx_uint32_t den_rate = st->den_rate; + int j; + spx_word32_t sum; + + while (!(last_sample >= (spx_int32_t)*in_len || out_sample >= (spx_int32_t)*out_len)) + { + const spx_word16_t *iptr = & in[last_sample]; + + const int offset = samp_frac_num*st->oversample/st->den_rate; +#ifdef FIXED_POINT + const spx_word16_t frac = PDIV32(SHL32((samp_frac_num*st->oversample) % st->den_rate,15),st->den_rate); +#else + const spx_word16_t frac = ((float)((samp_frac_num*st->oversample) % st->den_rate))/st->den_rate; +#endif + spx_word16_t interp[4]; + + +#ifndef OVERRIDE_INTERPOLATE_PRODUCT_DOUBLE + double accum[4] = {0,0,0,0}; + + for(j=0;jsinc_table[4+(j+1)*st->oversample-offset-2]); + accum[1] += MULT16_16(curr_in,st->sinc_table[4+(j+1)*st->oversample-offset-1]); + accum[2] += MULT16_16(curr_in,st->sinc_table[4+(j+1)*st->oversample-offset]); + accum[3] += MULT16_16(curr_in,st->sinc_table[4+(j+1)*st->oversample-offset+1]); + } + + cubic_coef(frac, interp); + sum = MULT16_32_Q15(interp[0],accum[0]) + MULT16_32_Q15(interp[1],accum[1]) + MULT16_32_Q15(interp[2],accum[2]) + MULT16_32_Q15(interp[3],accum[3]); +#else + cubic_coef(frac, interp); + sum = interpolate_product_double(iptr, st->sinc_table + st->oversample + 4 - offset - 2, N, st->oversample, interp); +#endif + + out[out_stride * out_sample++] = PSHR32(sum,15); + last_sample += int_advance; + samp_frac_num += frac_advance; + if (samp_frac_num >= den_rate) + { + samp_frac_num -= den_rate; + last_sample++; + } + } + + st->last_sample[channel_index] = last_sample; + st->samp_frac_num[channel_index] = samp_frac_num; + return out_sample; +} +#endif + +static void update_filter(SpeexResamplerState *st) +{ + spx_uint32_t old_length; + + old_length = st->filt_len; + st->oversample = quality_map[st->quality].oversample; + st->filt_len = quality_map[st->quality].base_length; + + if (st->num_rate > st->den_rate) + { + /* down-sampling */ + st->cutoff = quality_map[st->quality].downsample_bandwidth * st->den_rate / st->num_rate; + /* FIXME: divide the numerator and denominator by a certain amount if they're too large */ + st->filt_len = st->filt_len*st->num_rate / st->den_rate; + /* Round down to make sure we have a multiple of 4 */ + st->filt_len &= (~0x3); + if (2*st->den_rate < st->num_rate) + st->oversample >>= 1; + if (4*st->den_rate < st->num_rate) + st->oversample >>= 1; + if (8*st->den_rate < st->num_rate) + st->oversample >>= 1; + if (16*st->den_rate < st->num_rate) + st->oversample >>= 1; + if (st->oversample < 1) + st->oversample = 1; + } else { + /* up-sampling */ + st->cutoff = quality_map[st->quality].upsample_bandwidth; + } + + /* Choose the resampling type that requires the least amount of memory */ + if (st->den_rate <= st->oversample) + { + spx_uint32_t i; + if (!st->sinc_table) + st->sinc_table = (spx_word16_t *)speex_alloc(st->filt_len*st->den_rate*sizeof(spx_word16_t)); + else if (st->sinc_table_length < st->filt_len*st->den_rate) + { + st->sinc_table = (spx_word16_t *)speex_realloc(st->sinc_table,st->filt_len*st->den_rate*sizeof(spx_word16_t)); + st->sinc_table_length = st->filt_len*st->den_rate; + } + for (i=0;iden_rate;i++) + { + spx_int32_t j; + for (j=0;jfilt_len;j++) + { + st->sinc_table[i*st->filt_len+j] = sinc(st->cutoff,((j-(spx_int32_t)st->filt_len/2+1)-((float)i)/st->den_rate), st->filt_len, quality_map[st->quality].window_func); + } + } +#ifdef FIXED_POINT + st->resampler_ptr = resampler_basic_direct_single; +#else + if (st->quality>8) + st->resampler_ptr = resampler_basic_direct_double; + else + st->resampler_ptr = resampler_basic_direct_single; +#endif + /*fprintf (stderr, "resampler uses direct sinc table and normalised cutoff %f\n", cutoff);*/ + } else { + spx_int32_t i; + if (!st->sinc_table) + st->sinc_table = (spx_word16_t *)speex_alloc((st->filt_len*st->oversample+8)*sizeof(spx_word16_t)); + else if (st->sinc_table_length < st->filt_len*st->oversample+8) + { + st->sinc_table = (spx_word16_t *)speex_realloc(st->sinc_table,(st->filt_len*st->oversample+8)*sizeof(spx_word16_t)); + st->sinc_table_length = st->filt_len*st->oversample+8; + } + for (i=-4;i<(spx_int32_t)(st->oversample*st->filt_len+4);i++) + st->sinc_table[i+4] = sinc(st->cutoff,(i/(float)st->oversample - st->filt_len/2), st->filt_len, quality_map[st->quality].window_func); +#ifdef FIXED_POINT + st->resampler_ptr = resampler_basic_interpolate_single; +#else + if (st->quality>8) + st->resampler_ptr = resampler_basic_interpolate_double; + else + st->resampler_ptr = resampler_basic_interpolate_single; +#endif + /*fprintf (stderr, "resampler uses interpolated sinc table and normalised cutoff %f\n", cutoff);*/ + } + st->int_advance = st->num_rate/st->den_rate; + st->frac_advance = st->num_rate%st->den_rate; + + + /* Here's the place where we update the filter memory to take into account + the change in filter length. It's probably the messiest part of the code + due to handling of lots of corner cases. */ + if (!st->mem) + { + spx_uint32_t i; + st->mem_alloc_size = st->filt_len-1 + st->buffer_size; + st->mem = (spx_word16_t*)speex_alloc(st->nb_channels*st->mem_alloc_size * sizeof(spx_word16_t)); + for (i=0;inb_channels*st->mem_alloc_size;i++) + st->mem[i] = 0; + /*speex_warning("init filter");*/ + } else if (!st->started) + { + spx_uint32_t i; + st->mem_alloc_size = st->filt_len-1 + st->buffer_size; + st->mem = (spx_word16_t*)speex_realloc(st->mem, st->nb_channels*st->mem_alloc_size * sizeof(spx_word16_t)); + for (i=0;inb_channels*st->mem_alloc_size;i++) + st->mem[i] = 0; + /*speex_warning("reinit filter");*/ + } else if (st->filt_len > old_length) + { + spx_int32_t i; + /* Increase the filter length */ + /*speex_warning("increase filter size");*/ + int old_alloc_size = st->mem_alloc_size; + if ((st->filt_len-1 + st->buffer_size) > st->mem_alloc_size) + { + st->mem_alloc_size = st->filt_len-1 + st->buffer_size; + st->mem = (spx_word16_t*)speex_realloc(st->mem, st->nb_channels*st->mem_alloc_size * sizeof(spx_word16_t)); + } + for (i=st->nb_channels-1;i>=0;i--) + { + spx_int32_t j; + spx_uint32_t olen = old_length; + /*if (st->magic_samples[i])*/ + { + /* Try and remove the magic samples as if nothing had happened */ + + /* FIXME: This is wrong but for now we need it to avoid going over the array bounds */ + olen = old_length + 2*st->magic_samples[i]; + for (j=old_length-2+st->magic_samples[i];j>=0;j--) + st->mem[i*st->mem_alloc_size+j+st->magic_samples[i]] = st->mem[i*old_alloc_size+j]; + for (j=0;jmagic_samples[i];j++) + st->mem[i*st->mem_alloc_size+j] = 0; + st->magic_samples[i] = 0; + } + if (st->filt_len > olen) + { + /* If the new filter length is still bigger than the "augmented" length */ + /* Copy data going backward */ + for (j=0;jmem[i*st->mem_alloc_size+(st->filt_len-2-j)] = st->mem[i*st->mem_alloc_size+(olen-2-j)]; + /* Then put zeros for lack of anything better */ + for (;jfilt_len-1;j++) + st->mem[i*st->mem_alloc_size+(st->filt_len-2-j)] = 0; + /* Adjust last_sample */ + st->last_sample[i] += (st->filt_len - olen)/2; + } else { + /* Put back some of the magic! */ + st->magic_samples[i] = (olen - st->filt_len)/2; + for (j=0;jfilt_len-1+st->magic_samples[i];j++) + st->mem[i*st->mem_alloc_size+j] = st->mem[i*st->mem_alloc_size+j+st->magic_samples[i]]; + } + } + } else if (st->filt_len < old_length) + { + spx_uint32_t i; + /* Reduce filter length, this a bit tricky. We need to store some of the memory as "magic" + samples so they can be used directly as input the next time(s) */ + for (i=0;inb_channels;i++) + { + spx_uint32_t j; + spx_uint32_t old_magic = st->magic_samples[i]; + st->magic_samples[i] = (old_length - st->filt_len)/2; + /* We must copy some of the memory that's no longer used */ + /* Copy data going backward */ + for (j=0;jfilt_len-1+st->magic_samples[i]+old_magic;j++) + st->mem[i*st->mem_alloc_size+j] = st->mem[i*st->mem_alloc_size+j+st->magic_samples[i]]; + st->magic_samples[i] += old_magic; + } + } + +} + +EXPORT SpeexResamplerState *speex_resampler_init(spx_uint32_t nb_channels, spx_uint32_t in_rate, spx_uint32_t out_rate, int quality, int *err) +{ + return speex_resampler_init_frac(nb_channels, in_rate, out_rate, in_rate, out_rate, quality, err); +} + +EXPORT SpeexResamplerState *speex_resampler_init_frac(spx_uint32_t nb_channels, spx_uint32_t ratio_num, spx_uint32_t ratio_den, spx_uint32_t in_rate, spx_uint32_t out_rate, int quality, int *err) +{ + spx_uint32_t i; + SpeexResamplerState *st; + if (quality > 10 || quality < 0) + { + if (err) + *err = RESAMPLER_ERR_INVALID_ARG; + return NULL; + } + st = (SpeexResamplerState *)speex_alloc(sizeof(SpeexResamplerState)); + st->initialised = 0; + st->started = 0; + st->in_rate = 0; + st->out_rate = 0; + st->num_rate = 0; + st->den_rate = 0; + st->quality = -1; + st->sinc_table_length = 0; + st->mem_alloc_size = 0; + st->filt_len = 0; + st->mem = 0; + st->resampler_ptr = 0; + + st->cutoff = 1.f; + st->nb_channels = nb_channels; + st->in_stride = 1; + st->out_stride = 1; + +#ifdef FIXED_POINT + st->buffer_size = 160; +#else + st->buffer_size = 160; +#endif + + /* Per channel data */ + st->last_sample = (spx_int32_t*)speex_alloc(nb_channels*sizeof(int)); + st->magic_samples = (spx_uint32_t*)speex_alloc(nb_channels*sizeof(int)); + st->samp_frac_num = (spx_uint32_t*)speex_alloc(nb_channels*sizeof(int)); + for (i=0;ilast_sample[i] = 0; + st->magic_samples[i] = 0; + st->samp_frac_num[i] = 0; + } + + speex_resampler_set_quality(st, quality); + speex_resampler_set_rate_frac(st, ratio_num, ratio_den, in_rate, out_rate); + + + update_filter(st); + + st->initialised = 1; + if (err) + *err = RESAMPLER_ERR_SUCCESS; + + return st; +} + +EXPORT void speex_resampler_destroy(SpeexResamplerState *st) +{ + speex_free(st->mem); + speex_free(st->sinc_table); + speex_free(st->last_sample); + speex_free(st->magic_samples); + speex_free(st->samp_frac_num); + speex_free(st); +} + +static int speex_resampler_process_native(SpeexResamplerState *st, spx_uint32_t channel_index, spx_uint32_t *in_len, spx_word16_t *out, spx_uint32_t *out_len) +{ + int j=0; + const int N = st->filt_len; + int out_sample = 0; + spx_word16_t *mem = st->mem + channel_index * st->mem_alloc_size; + spx_uint32_t ilen; + + st->started = 1; + + /* Call the right resampler through the function ptr */ + out_sample = st->resampler_ptr(st, channel_index, mem, in_len, out, out_len); + + if (st->last_sample[channel_index] < (spx_int32_t)*in_len) + *in_len = st->last_sample[channel_index]; + *out_len = out_sample; + st->last_sample[channel_index] -= *in_len; + + ilen = *in_len; + + for(j=0;jmagic_samples[channel_index]; + spx_word16_t *mem = st->mem + channel_index * st->mem_alloc_size; + const int N = st->filt_len; + + speex_resampler_process_native(st, channel_index, &tmp_in_len, *out, &out_len); + + st->magic_samples[channel_index] -= tmp_in_len; + + /* If we couldn't process all "magic" input samples, save the rest for next time */ + if (st->magic_samples[channel_index]) + { + spx_uint32_t i; + for (i=0;imagic_samples[channel_index];i++) + mem[N-1+i]=mem[N-1+i+tmp_in_len]; + } + *out += out_len*st->out_stride; + return out_len; +} + +#ifdef FIXED_POINT +EXPORT int speex_resampler_process_int(SpeexResamplerState *st, spx_uint32_t channel_index, const spx_int16_t *in, spx_uint32_t *in_len, spx_int16_t *out, spx_uint32_t *out_len) +#else +EXPORT int speex_resampler_process_float(SpeexResamplerState *st, spx_uint32_t channel_index, const float *in, spx_uint32_t *in_len, float *out, spx_uint32_t *out_len) +#endif +{ + int j; + spx_uint32_t ilen = *in_len; + spx_uint32_t olen = *out_len; + spx_word16_t *x = st->mem + channel_index * st->mem_alloc_size; + const int filt_offs = st->filt_len - 1; + const spx_uint32_t xlen = st->mem_alloc_size - filt_offs; + const int istride = st->in_stride; + + if (st->magic_samples[channel_index]) + olen -= speex_resampler_magic(st, channel_index, &out, olen); + if (! st->magic_samples[channel_index]) { + while (ilen && olen) { + spx_uint32_t ichunk = (ilen > xlen) ? xlen : ilen; + spx_uint32_t ochunk = olen; + + if (in) { + for(j=0;jout_stride; + if (in) + in += ichunk * istride; + } + } + *in_len -= ilen; + *out_len -= olen; + return RESAMPLER_ERR_SUCCESS; +} + +#ifdef FIXED_POINT +EXPORT int speex_resampler_process_float(SpeexResamplerState *st, spx_uint32_t channel_index, const float *in, spx_uint32_t *in_len, float *out, spx_uint32_t *out_len) +#else +EXPORT int speex_resampler_process_int(SpeexResamplerState *st, spx_uint32_t channel_index, const spx_int16_t *in, spx_uint32_t *in_len, spx_int16_t *out, spx_uint32_t *out_len) +#endif +{ + int j; + const int istride_save = st->in_stride; + const int ostride_save = st->out_stride; + spx_uint32_t ilen = *in_len; + spx_uint32_t olen = *out_len; + spx_word16_t *x = st->mem + channel_index * st->mem_alloc_size; + const spx_uint32_t xlen = st->mem_alloc_size - (st->filt_len - 1); +#ifdef VAR_ARRAYS + const unsigned int ylen = (olen < FIXED_STACK_ALLOC) ? olen : FIXED_STACK_ALLOC; + VARDECL(spx_word16_t *ystack); + ALLOC(ystack, ylen, spx_word16_t); +#else + const unsigned int ylen = FIXED_STACK_ALLOC; + spx_word16_t ystack[FIXED_STACK_ALLOC]; +#endif + + st->out_stride = 1; + + while (ilen && olen) { + spx_word16_t *y = ystack; + spx_uint32_t ichunk = (ilen > xlen) ? xlen : ilen; + spx_uint32_t ochunk = (olen > ylen) ? ylen : olen; + spx_uint32_t omagic = 0; + + if (st->magic_samples[channel_index]) { + omagic = speex_resampler_magic(st, channel_index, &y, ochunk); + ochunk -= omagic; + olen -= omagic; + } + if (! st->magic_samples[channel_index]) { + if (in) { + for(j=0;jfilt_len-1]=WORD2INT(in[j*istride_save]); +#else + x[j+st->filt_len-1]=in[j*istride_save]; +#endif + } else { + for(j=0;jfilt_len-1]=0; + } + + speex_resampler_process_native(st, channel_index, &ichunk, y, &ochunk); + } else { + ichunk = 0; + ochunk = 0; + } + + for (j=0;jout_stride = ostride_save; + *in_len -= ilen; + *out_len -= olen; + + return RESAMPLER_ERR_SUCCESS; +} + +EXPORT int speex_resampler_process_interleaved_float(SpeexResamplerState *st, const float *in, spx_uint32_t *in_len, float *out, spx_uint32_t *out_len) +{ + spx_uint32_t i; + int istride_save, ostride_save; + spx_uint32_t bak_len = *out_len; + istride_save = st->in_stride; + ostride_save = st->out_stride; + st->in_stride = st->out_stride = st->nb_channels; + for (i=0;inb_channels;i++) + { + *out_len = bak_len; + if (in != NULL) + speex_resampler_process_float(st, i, in+i, in_len, out+i, out_len); + else + speex_resampler_process_float(st, i, NULL, in_len, out+i, out_len); + } + st->in_stride = istride_save; + st->out_stride = ostride_save; + return RESAMPLER_ERR_SUCCESS; +} + +EXPORT int speex_resampler_process_interleaved_int(SpeexResamplerState *st, const spx_int16_t *in, spx_uint32_t *in_len, spx_int16_t *out, spx_uint32_t *out_len) +{ + spx_uint32_t i; + int istride_save, ostride_save; + spx_uint32_t bak_len = *out_len; + istride_save = st->in_stride; + ostride_save = st->out_stride; + st->in_stride = st->out_stride = st->nb_channels; + for (i=0;inb_channels;i++) + { + *out_len = bak_len; + if (in != NULL) + speex_resampler_process_int(st, i, in+i, in_len, out+i, out_len); + else + speex_resampler_process_int(st, i, NULL, in_len, out+i, out_len); + } + st->in_stride = istride_save; + st->out_stride = ostride_save; + return RESAMPLER_ERR_SUCCESS; +} + +EXPORT int speex_resampler_set_rate(SpeexResamplerState *st, spx_uint32_t in_rate, spx_uint32_t out_rate) +{ + return speex_resampler_set_rate_frac(st, in_rate, out_rate, in_rate, out_rate); +} + +EXPORT void speex_resampler_get_rate(SpeexResamplerState *st, spx_uint32_t *in_rate, spx_uint32_t *out_rate) +{ + *in_rate = st->in_rate; + *out_rate = st->out_rate; +} + +EXPORT int speex_resampler_set_rate_frac(SpeexResamplerState *st, spx_uint32_t ratio_num, spx_uint32_t ratio_den, spx_uint32_t in_rate, spx_uint32_t out_rate) +{ + spx_uint32_t fact; + spx_uint32_t old_den; + spx_uint32_t i; + if (st->in_rate == in_rate && st->out_rate == out_rate && st->num_rate == ratio_num && st->den_rate == ratio_den) + return RESAMPLER_ERR_SUCCESS; + + old_den = st->den_rate; + st->in_rate = in_rate; + st->out_rate = out_rate; + st->num_rate = ratio_num; + st->den_rate = ratio_den; + /* FIXME: This is terribly inefficient, but who cares (at least for now)? */ + for (fact=2;fact<=IMIN(st->num_rate, st->den_rate);fact++) + { + while ((st->num_rate % fact == 0) && (st->den_rate % fact == 0)) + { + st->num_rate /= fact; + st->den_rate /= fact; + } + } + + if (old_den > 0) + { + for (i=0;inb_channels;i++) + { + st->samp_frac_num[i]=st->samp_frac_num[i]*st->den_rate/old_den; + /* Safety net */ + if (st->samp_frac_num[i] >= st->den_rate) + st->samp_frac_num[i] = st->den_rate-1; + } + } + + if (st->initialised) + update_filter(st); + return RESAMPLER_ERR_SUCCESS; +} + +EXPORT void speex_resampler_get_ratio(SpeexResamplerState *st, spx_uint32_t *ratio_num, spx_uint32_t *ratio_den) +{ + *ratio_num = st->num_rate; + *ratio_den = st->den_rate; +} + +EXPORT int speex_resampler_set_quality(SpeexResamplerState *st, int quality) +{ + if (quality > 10 || quality < 0) + return RESAMPLER_ERR_INVALID_ARG; + if (st->quality == quality) + return RESAMPLER_ERR_SUCCESS; + st->quality = quality; + if (st->initialised) + update_filter(st); + return RESAMPLER_ERR_SUCCESS; +} + +EXPORT void speex_resampler_get_quality(SpeexResamplerState *st, int *quality) +{ + *quality = st->quality; +} + +EXPORT void speex_resampler_set_input_stride(SpeexResamplerState *st, spx_uint32_t stride) +{ + st->in_stride = stride; +} + +EXPORT void speex_resampler_get_input_stride(SpeexResamplerState *st, spx_uint32_t *stride) +{ + *stride = st->in_stride; +} + +EXPORT void speex_resampler_set_output_stride(SpeexResamplerState *st, spx_uint32_t stride) +{ + st->out_stride = stride; +} + +EXPORT void speex_resampler_get_output_stride(SpeexResamplerState *st, spx_uint32_t *stride) +{ + *stride = st->out_stride; +} + +EXPORT int speex_resampler_get_input_latency(SpeexResamplerState *st) +{ + return st->filt_len / 2; +} + +EXPORT int speex_resampler_get_output_latency(SpeexResamplerState *st) +{ + return ((st->filt_len / 2) * st->den_rate + (st->num_rate >> 1)) / st->num_rate; +} + +EXPORT int speex_resampler_skip_zeros(SpeexResamplerState *st) +{ + spx_uint32_t i; + for (i=0;inb_channels;i++) + st->last_sample[i] = st->filt_len/2; + return RESAMPLER_ERR_SUCCESS; +} + +EXPORT int speex_resampler_reset_mem(SpeexResamplerState *st) +{ + spx_uint32_t i; + for (i=0;inb_channels*(st->filt_len-1);i++) + st->mem[i] = 0; + return RESAMPLER_ERR_SUCCESS; +} + +EXPORT const char *speex_resampler_strerror(int err) +{ + switch (err) + { + case RESAMPLER_ERR_SUCCESS: + return "Success."; + case RESAMPLER_ERR_ALLOC_FAILED: + return "Memory allocation failed."; + case RESAMPLER_ERR_BAD_STATE: + return "Bad resampler state."; + case RESAMPLER_ERR_INVALID_ARG: + return "Invalid argument."; + case RESAMPLER_ERR_PTR_OVERLAP: + return "Input and output buffers overlap."; + default: + return "Unknown error. Bad error code or strange version mismatch."; + } +} diff --git a/ios/IOSDuoduo/Voice/Code/Libs/libspeex/resample_sse.h b/ios/IOSDuoduo/Voice/Code/Libs/libspeex/resample_sse.h new file mode 100755 index 000000000..4bd35a2d0 --- /dev/null +++ b/ios/IOSDuoduo/Voice/Code/Libs/libspeex/resample_sse.h @@ -0,0 +1,128 @@ +/* Copyright (C) 2007-2008 Jean-Marc Valin + * Copyright (C) 2008 Thorvald Natvig + */ +/** + @file resample_sse.h + @brief Resampler functions (SSE version) +*/ +/* + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + - Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + - Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + - Neither the name of the Xiph.org Foundation nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR + CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#include + +#define OVERRIDE_INNER_PRODUCT_SINGLE +static inline float inner_product_single(const float *a, const float *b, unsigned int len) +{ + int i; + float ret; + __m128 sum = _mm_setzero_ps(); + for (i=0;i +#define OVERRIDE_INNER_PRODUCT_DOUBLE + +static inline double inner_product_double(const float *a, const float *b, unsigned int len) +{ + int i; + double ret; + __m128d sum = _mm_setzero_pd(); + __m128 t; + for (i=0;i +#include "sb_celp.h" +#include "filters.h" +#include "lpc.h" +#include "lsp.h" +#include "stack_alloc.h" +#include "cb_search.h" +#include "quant_lsp.h" +#include "vq.h" +#include "ltp.h" +#include "arch.h" +#include "math_approx.h" +#include "os_support.h" + +#ifndef NULL +#define NULL 0 +#endif + +/* Default size for the encoder and decoder stack (can be changed at compile time). + This does not apply when using variable-size arrays or alloca. */ +#ifndef SB_ENC_STACK +#define SB_ENC_STACK (10000*sizeof(spx_sig_t)) +#endif + +#ifndef SB_DEC_STACK +#define SB_DEC_STACK (6000*sizeof(spx_sig_t)) +#endif + + +#ifdef DISABLE_WIDEBAND +void *sb_encoder_init(const SpeexMode *m) +{ + speex_fatal("Wideband and Ultra-wideband are disabled"); + return NULL; +} +void sb_encoder_destroy(void *state) +{ + speex_fatal("Wideband and Ultra-wideband are disabled"); +} +int sb_encode(void *state, void *vin, SpeexBits *bits) +{ + speex_fatal("Wideband and Ultra-wideband are disabled"); + return -2; +} +void *sb_decoder_init(const SpeexMode *m) +{ + speex_fatal("Wideband and Ultra-wideband are disabled"); + return NULL; +} +void sb_decoder_destroy(void *state) +{ + speex_fatal("Wideband and Ultra-wideband are disabled"); +} +int sb_decode(void *state, SpeexBits *bits, void *vout) +{ + speex_fatal("Wideband and Ultra-wideband are disabled"); + return -2; +} +int sb_encoder_ctl(void *state, int request, void *ptr) +{ + speex_fatal("Wideband and Ultra-wideband are disabled"); + return -2; +} +int sb_decoder_ctl(void *state, int request, void *ptr) +{ + speex_fatal("Wideband and Ultra-wideband are disabled"); + return -2; +} +#else + + +#ifndef M_PI +#define M_PI 3.14159265358979323846 /* pi */ +#endif + +#define sqr(x) ((x)*(x)) + +#define SUBMODE(x) st->submodes[st->submodeID]->x + +#ifdef FIXED_POINT +static const spx_word16_t gc_quant_bound[16] = {125, 164, 215, 282, 370, 484, 635, 832, 1090, 1428, 1871, 2452, 3213, 4210, 5516, 7228}; +static const spx_word16_t fold_quant_bound[32] = { + 39, 44, 50, 57, 64, 73, 83, 94, + 106, 120, 136, 154, 175, 198, 225, 255, + 288, 327, 370, 420, 476, 539, 611, 692, + 784, 889, 1007, 1141, 1293, 1465, 1660, 1881}; +#define LSP_MARGIN 410 +#define LSP_DELTA1 6553 +#define LSP_DELTA2 1638 + +#else + +static const spx_word16_t gc_quant_bound[16] = { + 0.97979, 1.28384, 1.68223, 2.20426, 2.88829, 3.78458, 4.95900, 6.49787, + 8.51428, 11.15642, 14.61846, 19.15484, 25.09895, 32.88761, 43.09325, 56.46588}; +static const spx_word16_t fold_quant_bound[32] = { + 0.30498, 0.34559, 0.39161, 0.44375, 0.50283, 0.56979, 0.64565, 0.73162, + 0.82903, 0.93942, 1.06450, 1.20624, 1.36685, 1.54884, 1.75506, 1.98875, + 2.25355, 2.55360, 2.89361, 3.27889, 3.71547, 4.21018, 4.77076, 5.40598, + 6.12577, 6.94141, 7.86565, 8.91295, 10.09969, 11.44445, 12.96826, 14.69497}; + +#define LSP_MARGIN .05 +#define LSP_DELTA1 .2 +#define LSP_DELTA2 .05 + +#endif + +#define QMF_ORDER 64 + +#ifdef FIXED_POINT +static const spx_word16_t h0[64] = {2, -7, -7, 18, 15, -39, -25, 75, 35, -130, -41, 212, 38, -327, -17, 483, -32, -689, 124, 956, -283, -1307, 543, 1780, -973, -2467, 1733, 3633, -3339, -6409, 9059, 30153, 30153, 9059, -6409, -3339, 3633, 1733, -2467, -973, 1780, 543, -1307, -283, 956, 124, -689, -32, 483, -17, -327, 38, 212, -41, -130, 35, 75, -25, -39, 15, 18, -7, -7, 2}; + +#else +static const float h0[64] = { + 3.596189e-05f, -0.0001123515f, + -0.0001104587f, 0.0002790277f, + 0.0002298438f, -0.0005953563f, + -0.0003823631f, 0.00113826f, + 0.0005308539f, -0.001986177f, + -0.0006243724f, 0.003235877f, + 0.0005743159f, -0.004989147f, + -0.0002584767f, 0.007367171f, + -0.0004857935f, -0.01050689f, + 0.001894714f, 0.01459396f, + -0.004313674f, -0.01994365f, + 0.00828756f, 0.02716055f, + -0.01485397f, -0.03764973f, + 0.026447f, 0.05543245f, + -0.05095487f, -0.09779096f, + 0.1382363f, 0.4600981f, + 0.4600981f, 0.1382363f, + -0.09779096f, -0.05095487f, + 0.05543245f, 0.026447f, + -0.03764973f, -0.01485397f, + 0.02716055f, 0.00828756f, + -0.01994365f, -0.004313674f, + 0.01459396f, 0.001894714f, + -0.01050689f, -0.0004857935f, + 0.007367171f, -0.0002584767f, + -0.004989147f, 0.0005743159f, + 0.003235877f, -0.0006243724f, + -0.001986177f, 0.0005308539f, + 0.00113826f, -0.0003823631f, + -0.0005953563f, 0.0002298438f, + 0.0002790277f, -0.0001104587f, + -0.0001123515f, 3.596189e-05f +}; + +#endif + +extern const spx_word16_t lag_window[]; +extern const spx_word16_t lpc_window[]; + + +void *sb_encoder_init(const SpeexMode *m) +{ + int i; + spx_int32_t tmp; + SBEncState *st; + const SpeexSBMode *mode; + + st = (SBEncState*)speex_alloc(sizeof(SBEncState)); + if (!st) + return NULL; + st->mode = m; + mode = (const SpeexSBMode*)m->mode; + + + st->st_low = speex_encoder_init(mode->nb_mode); +#if defined(VAR_ARRAYS) || defined (USE_ALLOCA) + st->stack = NULL; +#else + /*st->stack = (char*)speex_alloc_scratch(SB_ENC_STACK);*/ + speex_encoder_ctl(st->st_low, SPEEX_GET_STACK, &st->stack); +#endif + + st->full_frame_size = 2*mode->frameSize; + st->frame_size = mode->frameSize; + st->subframeSize = mode->subframeSize; + st->nbSubframes = mode->frameSize/mode->subframeSize; + st->windowSize = st->frame_size+st->subframeSize; + st->lpcSize=mode->lpcSize; + + st->encode_submode = 1; + st->submodes=mode->submodes; + st->submodeSelect = st->submodeID=mode->defaultSubmode; + + tmp=9; + speex_encoder_ctl(st->st_low, SPEEX_SET_QUALITY, &tmp); + tmp=1; + speex_encoder_ctl(st->st_low, SPEEX_SET_WIDEBAND, &tmp); + + st->lpc_floor = mode->lpc_floor; + st->gamma1=mode->gamma1; + st->gamma2=mode->gamma2; + st->first=1; + + st->high=(spx_word16_t*)speex_alloc((st->windowSize-st->frame_size)*sizeof(spx_word16_t)); + + st->h0_mem=(spx_word16_t*)speex_alloc((QMF_ORDER)*sizeof(spx_word16_t)); + st->h1_mem=(spx_word16_t*)speex_alloc((QMF_ORDER)*sizeof(spx_word16_t)); + + st->window= lpc_window; + + st->lagWindow = lag_window; + + st->old_lsp = (spx_lsp_t*)speex_alloc(st->lpcSize*sizeof(spx_lsp_t)); + st->old_qlsp = (spx_lsp_t*)speex_alloc(st->lpcSize*sizeof(spx_lsp_t)); + st->interp_qlpc = (spx_coef_t*)speex_alloc(st->lpcSize*sizeof(spx_coef_t)); + st->pi_gain = (spx_word32_t*)speex_alloc((st->nbSubframes)*sizeof(spx_word32_t)); + st->exc_rms = (spx_word16_t*)speex_alloc((st->nbSubframes)*sizeof(spx_word16_t)); + st->innov_rms_save = NULL; + + st->mem_sp = (spx_mem_t*)speex_alloc((st->lpcSize)*sizeof(spx_mem_t)); + st->mem_sp2 = (spx_mem_t*)speex_alloc((st->lpcSize)*sizeof(spx_mem_t)); + st->mem_sw = (spx_mem_t*)speex_alloc((st->lpcSize)*sizeof(spx_mem_t)); + + for (i=0;ilpcSize;i++) + st->old_lsp[i]= DIV32(MULT16_16(QCONST16(3.1415927f, LSP_SHIFT), i+1), st->lpcSize+1); + +#ifndef DISABLE_VBR + st->vbr_quality = 8; + st->vbr_enabled = 0; + st->vbr_max = 0; + st->vbr_max_high = 20000; /* We just need a big value here */ + st->vad_enabled = 0; + st->abr_enabled = 0; + st->relative_quality=0; +#endif /* #ifndef DISABLE_VBR */ + + st->complexity=2; + speex_encoder_ctl(st->st_low, SPEEX_GET_SAMPLING_RATE, &st->sampling_rate); + st->sampling_rate*=2; +#ifdef ENABLE_VALGRIND + VALGRIND_MAKE_READABLE(st, (st->stack-(char*)st)); +#endif + return st; +} + +void sb_encoder_destroy(void *state) +{ + SBEncState *st=(SBEncState*)state; + + speex_encoder_destroy(st->st_low); +#if !(defined(VAR_ARRAYS) || defined (USE_ALLOCA)) + /*speex_free_scratch(st->stack);*/ +#endif + + speex_free(st->high); + + speex_free(st->h0_mem); + speex_free(st->h1_mem); + + speex_free(st->old_lsp); + speex_free(st->old_qlsp); + speex_free(st->interp_qlpc); + speex_free(st->pi_gain); + speex_free(st->exc_rms); + + speex_free(st->mem_sp); + speex_free(st->mem_sp2); + speex_free(st->mem_sw); + + + speex_free(st); +} + + +int sb_encode(void *state, void *vin, SpeexBits *bits) +{ + SBEncState *st; + int i, roots, sub; + char *stack; + VARDECL(spx_mem_t *mem); + VARDECL(spx_sig_t *innov); + VARDECL(spx_word16_t *target); + VARDECL(spx_word16_t *syn_resp); + VARDECL(spx_word32_t *low_pi_gain); + spx_word16_t *low; + spx_word16_t *high; + VARDECL(spx_word16_t *low_exc_rms); + VARDECL(spx_word16_t *low_innov_rms); + const SpeexSBMode *mode; + spx_int32_t dtx; + spx_word16_t *in = (spx_word16_t*)vin; + spx_word16_t e_low=0, e_high=0; + VARDECL(spx_coef_t *lpc); + VARDECL(spx_coef_t *interp_lpc); + VARDECL(spx_coef_t *bw_lpc1); + VARDECL(spx_coef_t *bw_lpc2); + VARDECL(spx_lsp_t *lsp); + VARDECL(spx_lsp_t *qlsp); + VARDECL(spx_lsp_t *interp_lsp); + VARDECL(spx_lsp_t *interp_qlsp); + + st = (SBEncState*)state; + stack=st->stack; + mode = (const SpeexSBMode*)(st->mode->mode); + low = in; + high = in+st->frame_size; + + /* High-band buffering / sync with low band */ + /* Compute the two sub-bands by filtering with QMF h0*/ + qmf_decomp(in, h0, low, high, st->full_frame_size, QMF_ORDER, st->h0_mem, stack); + +#ifndef DISABLE_VBR + if (st->vbr_enabled || st->vad_enabled) + { + /* Need to compute things here before the signal is trashed by the encoder */ + /*FIXME: Are the two signals (low, high) in sync? */ + e_low = compute_rms16(low, st->frame_size); + e_high = compute_rms16(high, st->frame_size); + } +#endif /* #ifndef DISABLE_VBR */ + + ALLOC(low_innov_rms, st->nbSubframes, spx_word16_t); + speex_encoder_ctl(st->st_low, SPEEX_SET_INNOVATION_SAVE, low_innov_rms); + /* Encode the narrowband part*/ + speex_encode_native(st->st_low, low, bits); + + high = high - (st->windowSize-st->frame_size); + SPEEX_COPY(high, st->high, st->windowSize-st->frame_size); + SPEEX_COPY(st->high, &high[st->frame_size], st->windowSize-st->frame_size); + + + ALLOC(low_pi_gain, st->nbSubframes, spx_word32_t); + ALLOC(low_exc_rms, st->nbSubframes, spx_word16_t); + speex_encoder_ctl(st->st_low, SPEEX_GET_PI_GAIN, low_pi_gain); + speex_encoder_ctl(st->st_low, SPEEX_GET_EXC, low_exc_rms); + + speex_encoder_ctl(st->st_low, SPEEX_GET_LOW_MODE, &dtx); + + if (dtx==0) + dtx=1; + else + dtx=0; + + ALLOC(lpc, st->lpcSize, spx_coef_t); + ALLOC(interp_lpc, st->lpcSize, spx_coef_t); + ALLOC(bw_lpc1, st->lpcSize, spx_coef_t); + ALLOC(bw_lpc2, st->lpcSize, spx_coef_t); + + ALLOC(lsp, st->lpcSize, spx_lsp_t); + ALLOC(qlsp, st->lpcSize, spx_lsp_t); + ALLOC(interp_lsp, st->lpcSize, spx_lsp_t); + ALLOC(interp_qlsp, st->lpcSize, spx_lsp_t); + + { + VARDECL(spx_word16_t *autocorr); + VARDECL(spx_word16_t *w_sig); + ALLOC(autocorr, st->lpcSize+1, spx_word16_t); + ALLOC(w_sig, st->windowSize, spx_word16_t); + /* Window for analysis */ + /* FIXME: This is a kludge */ + if (st->subframeSize==80) + { + for (i=0;iwindowSize;i++) + w_sig[i] = EXTRACT16(SHR32(MULT16_16(high[i],st->window[i>>1]),SIG_SHIFT)); + } else { + for (i=0;iwindowSize;i++) + w_sig[i] = EXTRACT16(SHR32(MULT16_16(high[i],st->window[i]),SIG_SHIFT)); + } + /* Compute auto-correlation */ + _spx_autocorr(w_sig, autocorr, st->lpcSize+1, st->windowSize); + autocorr[0] = ADD16(autocorr[0],MULT16_16_Q15(autocorr[0],st->lpc_floor)); /* Noise floor in auto-correlation domain */ + + /* Lag windowing: equivalent to filtering in the power-spectrum domain */ + for (i=0;ilpcSize+1;i++) + autocorr[i] = MULT16_16_Q14(autocorr[i],st->lagWindow[i]); + + /* Levinson-Durbin */ + _spx_lpc(lpc, autocorr, st->lpcSize); + } + + /* LPC to LSPs (x-domain) transform */ + roots=lpc_to_lsp (lpc, st->lpcSize, lsp, 10, LSP_DELTA1, stack); + if (roots!=st->lpcSize) + { + roots = lpc_to_lsp (lpc, st->lpcSize, lsp, 10, LSP_DELTA2, stack); + if (roots!=st->lpcSize) { + /*If we can't find all LSP's, do some damage control and use a flat filter*/ + for (i=0;ilpcSize;i++) + { + lsp[i]=st->old_lsp[i]; + } + } + } + +#ifndef DISABLE_VBR + /* VBR code */ + if ((st->vbr_enabled || st->vad_enabled) && !dtx) + { + float ratio; + if (st->abr_enabled) + { + float qual_change=0; + if (st->abr_drift2 * st->abr_drift > 0) + { + /* Only adapt if long-term and short-term drift are the same sign */ + qual_change = -.00001*st->abr_drift/(1+st->abr_count); + if (qual_change>.1) + qual_change=.1; + if (qual_change<-.1) + qual_change=-.1; + } + st->vbr_quality += qual_change; + if (st->vbr_quality>10) + st->vbr_quality=10; + if (st->vbr_quality<0) + st->vbr_quality=0; + } + + + ratio = 2*log((1.f+e_high)/(1.f+e_low)); + + speex_encoder_ctl(st->st_low, SPEEX_GET_RELATIVE_QUALITY, &st->relative_quality); + if (ratio<-4) + ratio=-4; + if (ratio>2) + ratio=2; + /*if (ratio>-2)*/ + if (st->vbr_enabled) + { + spx_int32_t modeid; + modeid = mode->nb_modes-1; + st->relative_quality+=1.0*(ratio+2); + if (st->relative_quality<-1) + st->relative_quality=-1; + while (modeid) + { + int v1; + float thresh; + v1=(int)floor(st->vbr_quality); + if (v1==10) + thresh = mode->vbr_thresh[modeid][v1]; + else + thresh = (st->vbr_quality-v1) * mode->vbr_thresh[modeid][v1+1] + + (1+v1-st->vbr_quality) * mode->vbr_thresh[modeid][v1]; + if (st->relative_quality >= thresh && st->sampling_rate*st->submodes[modeid]->bits_per_frame/st->full_frame_size <= st->vbr_max_high) + break; + modeid--; + } + speex_encoder_ctl(state, SPEEX_SET_HIGH_MODE, &modeid); + if (st->abr_enabled) + { + spx_int32_t bitrate; + speex_encoder_ctl(state, SPEEX_GET_BITRATE, &bitrate); + st->abr_drift+=(bitrate-st->abr_enabled); + st->abr_drift2 = .95*st->abr_drift2 + .05*(bitrate-st->abr_enabled); + st->abr_count += 1.0; + } + + } else { + /* VAD only */ + int modeid; + if (st->relative_quality<2.0) + modeid=1; + else + modeid=st->submodeSelect; + /*speex_encoder_ctl(state, SPEEX_SET_MODE, &mode);*/ + st->submodeID=modeid; + + } + /*fprintf (stderr, "%f %f\n", ratio, low_qual);*/ + } +#endif /* #ifndef DISABLE_VBR */ + + if (st->encode_submode) + { + speex_bits_pack(bits, 1, 1); + if (dtx) + speex_bits_pack(bits, 0, SB_SUBMODE_BITS); + else + speex_bits_pack(bits, st->submodeID, SB_SUBMODE_BITS); + } + + /* If null mode (no transmission), just set a couple things to zero*/ + if (dtx || st->submodes[st->submodeID] == NULL) + { + for (i=0;iframe_size;i++) + high[i]=VERY_SMALL; + + for (i=0;ilpcSize;i++) + st->mem_sw[i]=0; + st->first=1; + + /* Final signal synthesis from excitation */ + iir_mem16(high, st->interp_qlpc, high, st->frame_size, st->lpcSize, st->mem_sp, stack); + + if (dtx) + return 0; + else + return 1; + } + + + /* LSP quantization */ + SUBMODE(lsp_quant)(lsp, qlsp, st->lpcSize, bits); + + if (st->first) + { + for (i=0;ilpcSize;i++) + st->old_lsp[i] = lsp[i]; + for (i=0;ilpcSize;i++) + st->old_qlsp[i] = qlsp[i]; + } + + ALLOC(mem, st->lpcSize, spx_mem_t); + ALLOC(syn_resp, st->subframeSize, spx_word16_t); + ALLOC(innov, st->subframeSize, spx_sig_t); + ALLOC(target, st->subframeSize, spx_word16_t); + + for (sub=0;subnbSubframes;sub++) + { + VARDECL(spx_word16_t *exc); + VARDECL(spx_word16_t *res); + VARDECL(spx_word16_t *sw); + spx_word16_t *sp; + spx_word16_t filter_ratio; /*Q7*/ + int offset; + spx_word32_t rl, rh; /*Q13*/ + spx_word16_t eh=0; + + offset = st->subframeSize*sub; + sp=high+offset; + ALLOC(exc, st->subframeSize, spx_word16_t); + ALLOC(res, st->subframeSize, spx_word16_t); + ALLOC(sw, st->subframeSize, spx_word16_t); + + /* LSP interpolation (quantized and unquantized) */ + lsp_interpolate(st->old_lsp, lsp, interp_lsp, st->lpcSize, sub, st->nbSubframes); + lsp_interpolate(st->old_qlsp, qlsp, interp_qlsp, st->lpcSize, sub, st->nbSubframes); + + lsp_enforce_margin(interp_lsp, st->lpcSize, LSP_MARGIN); + lsp_enforce_margin(interp_qlsp, st->lpcSize, LSP_MARGIN); + + lsp_to_lpc(interp_lsp, interp_lpc, st->lpcSize,stack); + lsp_to_lpc(interp_qlsp, st->interp_qlpc, st->lpcSize, stack); + + bw_lpc(st->gamma1, interp_lpc, bw_lpc1, st->lpcSize); + bw_lpc(st->gamma2, interp_lpc, bw_lpc2, st->lpcSize); + + /* Compute mid-band (4000 Hz for wideband) response of low-band and high-band + filters */ + st->pi_gain[sub]=LPC_SCALING; + rh = LPC_SCALING; + for (i=0;ilpcSize;i+=2) + { + rh += st->interp_qlpc[i+1] - st->interp_qlpc[i]; + st->pi_gain[sub] += st->interp_qlpc[i] + st->interp_qlpc[i+1]; + } + + rl = low_pi_gain[sub]; +#ifdef FIXED_POINT + filter_ratio=EXTRACT16(SATURATE(PDIV32(SHL32(ADD32(rl,82),7),ADD32(82,rh)),32767)); +#else + filter_ratio=(rl+.01)/(rh+.01); +#endif + + /* Compute "real excitation" */ + fir_mem16(sp, st->interp_qlpc, exc, st->subframeSize, st->lpcSize, st->mem_sp2, stack); + /* Compute energy of low-band and high-band excitation */ + + eh = compute_rms16(exc, st->subframeSize); + + if (!SUBMODE(innovation_quant)) {/* 1 for spectral folding excitation, 0 for stochastic */ + spx_word32_t g; /*Q7*/ + spx_word16_t el; /*Q0*/ + el = low_innov_rms[sub]; + + /* Gain to use if we want to use the low-band excitation for high-band */ + g=PDIV32(MULT16_16(filter_ratio,eh),EXTEND32(ADD16(1,el))); + +#if 0 + { + char *tmp_stack=stack; + float *tmp_sig; + float g2; + ALLOC(tmp_sig, st->subframeSize, spx_sig_t); + for (i=0;ilpcSize;i++) + mem[i]=st->mem_sp[i]; + iir_mem2(st->low_innov+offset, st->interp_qlpc, tmp_sig, st->subframeSize, st->lpcSize, mem); + g2 = compute_rms(sp, st->subframeSize)/(.01+compute_rms(tmp_sig, st->subframeSize)); + /*fprintf (stderr, "gains: %f %f\n", g, g2);*/ + g = g2; + stack = tmp_stack; + } +#endif + + /*print_vec(&g, 1, "gain factor");*/ + /* Gain quantization */ + { + int quant = scal_quant(g, fold_quant_bound, 32); + /*speex_warning_int("tata", quant);*/ + if (quant<0) + quant=0; + if (quant>31) + quant=31; + speex_bits_pack(bits, quant, 5); + } + if (st->innov_rms_save) + { + st->innov_rms_save[sub] = eh; + } + st->exc_rms[sub] = eh; + } else { + spx_word16_t gc; /*Q7*/ + spx_word32_t scale; /*Q14*/ + spx_word16_t el; /*Q0*/ + el = low_exc_rms[sub]; /*Q0*/ + + gc = PDIV32_16(MULT16_16(filter_ratio,1+eh),1+el); + + /* This is a kludge that cleans up a historical bug */ + if (st->subframeSize==80) + gc = MULT16_16_P15(QCONST16(0.70711f,15),gc); + /*printf ("%f %f %f %f\n", el, eh, filter_ratio, gc);*/ + { + int qgc = scal_quant(gc, gc_quant_bound, 16); + speex_bits_pack(bits, qgc, 4); + gc = MULT16_16_Q15(QCONST16(0.87360,15),gc_quant_bound[qgc]); + } + if (st->subframeSize==80) + gc = MULT16_16_P14(QCONST16(1.4142f,14), gc); + + scale = SHL32(MULT16_16(PDIV32_16(SHL32(EXTEND32(gc),SIG_SHIFT-6),filter_ratio),(1+el)),6); + + compute_impulse_response(st->interp_qlpc, bw_lpc1, bw_lpc2, syn_resp, st->subframeSize, st->lpcSize, stack); + + + /* Reset excitation */ + for (i=0;isubframeSize;i++) + res[i]=VERY_SMALL; + + /* Compute zero response (ringing) of A(z/g1) / ( A(z/g2) * Aq(z) ) */ + for (i=0;ilpcSize;i++) + mem[i]=st->mem_sp[i]; + iir_mem16(res, st->interp_qlpc, res, st->subframeSize, st->lpcSize, mem, stack); + + for (i=0;ilpcSize;i++) + mem[i]=st->mem_sw[i]; + filter_mem16(res, bw_lpc1, bw_lpc2, res, st->subframeSize, st->lpcSize, mem, stack); + + /* Compute weighted signal */ + for (i=0;ilpcSize;i++) + mem[i]=st->mem_sw[i]; + filter_mem16(sp, bw_lpc1, bw_lpc2, sw, st->subframeSize, st->lpcSize, mem, stack); + + /* Compute target signal */ + for (i=0;isubframeSize;i++) + target[i]=SUB16(sw[i],res[i]); + + signal_div(target, target, scale, st->subframeSize); + + /* Reset excitation */ + SPEEX_MEMSET(innov, 0, st->subframeSize); + + /*print_vec(target, st->subframeSize, "\ntarget");*/ + SUBMODE(innovation_quant)(target, st->interp_qlpc, bw_lpc1, bw_lpc2, + SUBMODE(innovation_params), st->lpcSize, st->subframeSize, + innov, syn_resp, bits, stack, st->complexity, SUBMODE(double_codebook)); + /*print_vec(target, st->subframeSize, "after");*/ + + signal_mul(innov, innov, scale, st->subframeSize); + + if (SUBMODE(double_codebook)) { + char *tmp_stack=stack; + VARDECL(spx_sig_t *innov2); + ALLOC(innov2, st->subframeSize, spx_sig_t); + SPEEX_MEMSET(innov2, 0, st->subframeSize); + for (i=0;isubframeSize;i++) + target[i]=MULT16_16_P13(QCONST16(2.5f,13), target[i]); + + SUBMODE(innovation_quant)(target, st->interp_qlpc, bw_lpc1, bw_lpc2, + SUBMODE(innovation_params), st->lpcSize, st->subframeSize, + innov2, syn_resp, bits, stack, st->complexity, 0); + signal_mul(innov2, innov2, MULT16_32_P15(QCONST16(0.4f,15),scale), st->subframeSize); + + for (i=0;isubframeSize;i++) + innov[i] = ADD32(innov[i],innov2[i]); + stack = tmp_stack; + } + for (i=0;isubframeSize;i++) + exc[i] = PSHR32(innov[i],SIG_SHIFT); + + if (st->innov_rms_save) + { + st->innov_rms_save[sub] = MULT16_16_Q15(QCONST16(.70711f, 15), compute_rms(innov, st->subframeSize)); + } + st->exc_rms[sub] = compute_rms16(exc, st->subframeSize); + + + } + + + /*Keep the previous memory*/ + for (i=0;ilpcSize;i++) + mem[i]=st->mem_sp[i]; + /* Final signal synthesis from excitation */ + iir_mem16(exc, st->interp_qlpc, sp, st->subframeSize, st->lpcSize, st->mem_sp, stack); + + /* Compute weighted signal again, from synthesized speech (not sure it's the right thing) */ + filter_mem16(sp, bw_lpc1, bw_lpc2, sw, st->subframeSize, st->lpcSize, st->mem_sw, stack); + } + + for (i=0;ilpcSize;i++) + st->old_lsp[i] = lsp[i]; + for (i=0;ilpcSize;i++) + st->old_qlsp[i] = qlsp[i]; + + st->first=0; + + return 1; +} + + + + + +void *sb_decoder_init(const SpeexMode *m) +{ + spx_int32_t tmp; + SBDecState *st; + const SpeexSBMode *mode; + st = (SBDecState*)speex_alloc(sizeof(SBDecState)); + if (!st) + return NULL; + st->mode = m; + mode=(const SpeexSBMode*)m->mode; + st->encode_submode = 1; + + st->st_low = speex_decoder_init(mode->nb_mode); +#if defined(VAR_ARRAYS) || defined (USE_ALLOCA) + st->stack = NULL; +#else + /*st->stack = (char*)speex_alloc_scratch(SB_DEC_STACK);*/ + speex_decoder_ctl(st->st_low, SPEEX_GET_STACK, &st->stack); +#endif + + st->full_frame_size = 2*mode->frameSize; + st->frame_size = mode->frameSize; + st->subframeSize = mode->subframeSize; + st->nbSubframes = mode->frameSize/mode->subframeSize; + st->lpcSize=mode->lpcSize; + speex_decoder_ctl(st->st_low, SPEEX_GET_SAMPLING_RATE, &st->sampling_rate); + st->sampling_rate*=2; + tmp=1; + speex_decoder_ctl(st->st_low, SPEEX_SET_WIDEBAND, &tmp); + + st->submodes=mode->submodes; + st->submodeID=mode->defaultSubmode; + + st->first=1; + + st->g0_mem = (spx_word16_t*)speex_alloc((QMF_ORDER)*sizeof(spx_word16_t)); + st->g1_mem = (spx_word16_t*)speex_alloc((QMF_ORDER)*sizeof(spx_word16_t)); + + st->excBuf = (spx_word16_t*)speex_alloc((st->subframeSize)*sizeof(spx_word16_t)); + + st->old_qlsp = (spx_lsp_t*)speex_alloc((st->lpcSize)*sizeof(spx_lsp_t)); + st->interp_qlpc = (spx_coef_t*)speex_alloc(st->lpcSize*sizeof(spx_coef_t)); + + st->pi_gain = (spx_word32_t*)speex_alloc((st->nbSubframes)*sizeof(spx_word32_t)); + st->exc_rms = (spx_word16_t*)speex_alloc((st->nbSubframes)*sizeof(spx_word16_t)); + st->mem_sp = (spx_mem_t*)speex_alloc((2*st->lpcSize)*sizeof(spx_mem_t)); + + st->innov_save = NULL; + + + st->lpc_enh_enabled=0; + st->seed = 1000; + +#ifdef ENABLE_VALGRIND + VALGRIND_MAKE_READABLE(st, (st->stack-(char*)st)); +#endif + return st; +} + +void sb_decoder_destroy(void *state) +{ + SBDecState *st; + st = (SBDecState*)state; + speex_decoder_destroy(st->st_low); +#if !(defined(VAR_ARRAYS) || defined (USE_ALLOCA)) + /*speex_free_scratch(st->stack);*/ +#endif + + speex_free(st->g0_mem); + speex_free(st->g1_mem); + speex_free(st->excBuf); + speex_free(st->old_qlsp); + speex_free(st->interp_qlpc); + speex_free(st->pi_gain); + speex_free(st->exc_rms); + speex_free(st->mem_sp); + + speex_free(state); +} + +static void sb_decode_lost(SBDecState *st, spx_word16_t *out, int dtx, char *stack) +{ + int i; + int saved_modeid=0; + + if (dtx) + { + saved_modeid=st->submodeID; + st->submodeID=1; + } else { + bw_lpc(QCONST16(0.99f,15), st->interp_qlpc, st->interp_qlpc, st->lpcSize); + } + + st->first=1; + + + /* Final signal synthesis from excitation */ + if (!dtx) + { + st->last_ener = MULT16_16_Q15(QCONST16(.9f,15),st->last_ener); + } + for (i=0;iframe_size;i++) + out[i+st->frame_size] = speex_rand(st->last_ener, &st->seed); + + iir_mem16(out+st->frame_size, st->interp_qlpc, out+st->frame_size, st->frame_size, st->lpcSize, + st->mem_sp, stack); + + + /* Reconstruct the original */ + qmf_synth(out, out+st->frame_size, h0, out, st->full_frame_size, QMF_ORDER, st->g0_mem, st->g1_mem, stack); + if (dtx) + { + st->submodeID=saved_modeid; + } + + return; +} + +int sb_decode(void *state, SpeexBits *bits, void *vout) +{ + int i, sub; + SBDecState *st; + int wideband; + int ret; + char *stack; + VARDECL(spx_word32_t *low_pi_gain); + VARDECL(spx_word16_t *low_exc_rms); + VARDECL(spx_coef_t *ak); + VARDECL(spx_lsp_t *qlsp); + VARDECL(spx_lsp_t *interp_qlsp); + spx_int32_t dtx; + const SpeexSBMode *mode; + spx_word16_t *out = (spx_word16_t*)vout; + spx_word16_t *low_innov_alias; + spx_word32_t exc_ener_sum = 0; + + st = (SBDecState*)state; + stack=st->stack; + mode = (const SpeexSBMode*)(st->mode->mode); + + low_innov_alias = out+st->frame_size; + speex_decoder_ctl(st->st_low, SPEEX_SET_INNOVATION_SAVE, low_innov_alias); + /* Decode the low-band */ + ret = speex_decode_native(st->st_low, bits, out); + + speex_decoder_ctl(st->st_low, SPEEX_GET_DTX_STATUS, &dtx); + + /* If error decoding the narrowband part, propagate error */ + if (ret!=0) + { + return ret; + } + + if (!bits) + { + sb_decode_lost(st, out, dtx, stack); + return 0; + } + + if (st->encode_submode) + { + + /*Check "wideband bit"*/ + if (speex_bits_remaining(bits)>0) + wideband = speex_bits_peek(bits); + else + wideband = 0; + if (wideband) + { + /*Regular wideband frame, read the submode*/ + wideband = speex_bits_unpack_unsigned(bits, 1); + st->submodeID = speex_bits_unpack_unsigned(bits, SB_SUBMODE_BITS); + } else + { + /*Was a narrowband frame, set "null submode"*/ + st->submodeID = 0; + } + if (st->submodeID != 0 && st->submodes[st->submodeID] == NULL) + { + speex_notify("Invalid mode encountered. The stream is corrupted."); + return -2; + } + } + + /* If null mode (no transmission), just set a couple things to zero*/ + if (st->submodes[st->submodeID] == NULL) + { + if (dtx) + { + sb_decode_lost(st, out, 1, stack); + return 0; + } + + for (i=0;iframe_size;i++) + out[st->frame_size+i]=VERY_SMALL; + + st->first=1; + + /* Final signal synthesis from excitation */ + iir_mem16(out+st->frame_size, st->interp_qlpc, out+st->frame_size, st->frame_size, st->lpcSize, st->mem_sp, stack); + + qmf_synth(out, out+st->frame_size, h0, out, st->full_frame_size, QMF_ORDER, st->g0_mem, st->g1_mem, stack); + + return 0; + + } + + ALLOC(low_pi_gain, st->nbSubframes, spx_word32_t); + ALLOC(low_exc_rms, st->nbSubframes, spx_word16_t); + speex_decoder_ctl(st->st_low, SPEEX_GET_PI_GAIN, low_pi_gain); + speex_decoder_ctl(st->st_low, SPEEX_GET_EXC, low_exc_rms); + + ALLOC(qlsp, st->lpcSize, spx_lsp_t); + ALLOC(interp_qlsp, st->lpcSize, spx_lsp_t); + SUBMODE(lsp_unquant)(qlsp, st->lpcSize, bits); + + if (st->first) + { + for (i=0;ilpcSize;i++) + st->old_qlsp[i] = qlsp[i]; + } + + ALLOC(ak, st->lpcSize, spx_coef_t); + + for (sub=0;subnbSubframes;sub++) + { + VARDECL(spx_word32_t *exc); + spx_word16_t *innov_save=NULL; + spx_word16_t *sp; + spx_word16_t filter_ratio; + spx_word16_t el=0; + int offset; + spx_word32_t rl=0,rh=0; + + offset = st->subframeSize*sub; + sp=out+st->frame_size+offset; + ALLOC(exc, st->subframeSize, spx_word32_t); + /* Pointer for saving innovation */ + if (st->innov_save) + { + innov_save = st->innov_save+2*offset; + SPEEX_MEMSET(innov_save, 0, 2*st->subframeSize); + } + + /* LSP interpolation */ + lsp_interpolate(st->old_qlsp, qlsp, interp_qlsp, st->lpcSize, sub, st->nbSubframes); + + lsp_enforce_margin(interp_qlsp, st->lpcSize, LSP_MARGIN); + + /* LSP to LPC */ + lsp_to_lpc(interp_qlsp, ak, st->lpcSize, stack); + + /* Calculate reponse ratio between the low and high filter in the middle + of the band (4000 Hz) */ + + st->pi_gain[sub]=LPC_SCALING; + rh = LPC_SCALING; + for (i=0;ilpcSize;i+=2) + { + rh += ak[i+1] - ak[i]; + st->pi_gain[sub] += ak[i] + ak[i+1]; + } + + rl = low_pi_gain[sub]; +#ifdef FIXED_POINT + filter_ratio=EXTRACT16(SATURATE(PDIV32(SHL32(ADD32(rl,82),7),ADD32(82,rh)),32767)); +#else + filter_ratio=(rl+.01)/(rh+.01); +#endif + + SPEEX_MEMSET(exc, 0, st->subframeSize); + if (!SUBMODE(innovation_unquant)) + { + spx_word32_t g; + int quant; + + quant = speex_bits_unpack_unsigned(bits, 5); + g= spx_exp(MULT16_16(QCONST16(.125f,11),(quant-10))); + + g = PDIV32(g, filter_ratio); + + for (i=0;isubframeSize;i+=2) + { + exc[i]=SHL32(MULT16_32_P15(MULT16_16_Q15(mode->folding_gain,low_innov_alias[offset+i]),SHL32(g,6)),SIG_SHIFT); + exc[i+1]=NEG32(SHL32(MULT16_32_P15(MULT16_16_Q15(mode->folding_gain,low_innov_alias[offset+i+1]),SHL32(g,6)),SIG_SHIFT)); + } + + } else { + spx_word16_t gc; + spx_word32_t scale; + int qgc = speex_bits_unpack_unsigned(bits, 4); + + el = low_exc_rms[sub]; + gc = MULT16_16_Q15(QCONST16(0.87360,15),gc_quant_bound[qgc]); + + if (st->subframeSize==80) + gc = MULT16_16_P14(QCONST16(1.4142f,14),gc); + + scale = SHL32(PDIV32(SHL32(MULT16_16(gc, el),3), filter_ratio),SIG_SHIFT-3); + SUBMODE(innovation_unquant)(exc, SUBMODE(innovation_params), st->subframeSize, + bits, stack, &st->seed); + + signal_mul(exc,exc,scale,st->subframeSize); + + if (SUBMODE(double_codebook)) { + char *tmp_stack=stack; + VARDECL(spx_sig_t *innov2); + ALLOC(innov2, st->subframeSize, spx_sig_t); + SPEEX_MEMSET(innov2, 0, st->subframeSize); + SUBMODE(innovation_unquant)(innov2, SUBMODE(innovation_params), st->subframeSize, + bits, stack, &st->seed); + signal_mul(innov2, innov2, MULT16_32_P15(QCONST16(0.4f,15),scale), st->subframeSize); + for (i=0;isubframeSize;i++) + exc[i] = ADD32(exc[i],innov2[i]); + stack = tmp_stack; + } + + } + + if (st->innov_save) + { + for (i=0;isubframeSize;i++) + innov_save[2*i]=EXTRACT16(PSHR32(exc[i],SIG_SHIFT)); + } + + iir_mem16(st->excBuf, st->interp_qlpc, sp, st->subframeSize, st->lpcSize, + st->mem_sp, stack); + for (i=0;isubframeSize;i++) + st->excBuf[i]=EXTRACT16(PSHR32(exc[i],SIG_SHIFT)); + for (i=0;ilpcSize;i++) + st->interp_qlpc[i] = ak[i]; + st->exc_rms[sub] = compute_rms16(st->excBuf, st->subframeSize); + exc_ener_sum = ADD32(exc_ener_sum, DIV32(MULT16_16(st->exc_rms[sub],st->exc_rms[sub]), st->nbSubframes)); + } + st->last_ener = spx_sqrt(exc_ener_sum); + + qmf_synth(out, out+st->frame_size, h0, out, st->full_frame_size, QMF_ORDER, st->g0_mem, st->g1_mem, stack); + for (i=0;ilpcSize;i++) + st->old_qlsp[i] = qlsp[i]; + + st->first=0; + + return 0; +} + + +int sb_encoder_ctl(void *state, int request, void *ptr) +{ + SBEncState *st; + st=(SBEncState*)state; + switch(request) + { + case SPEEX_GET_FRAME_SIZE: + (*(spx_int32_t*)ptr) = st->full_frame_size; + break; + case SPEEX_SET_HIGH_MODE: + st->submodeSelect = st->submodeID = (*(spx_int32_t*)ptr); + break; + case SPEEX_SET_LOW_MODE: + speex_encoder_ctl(st->st_low, SPEEX_SET_LOW_MODE, ptr); + break; + case SPEEX_SET_DTX: + speex_encoder_ctl(st->st_low, SPEEX_SET_DTX, ptr); + break; + case SPEEX_GET_DTX: + speex_encoder_ctl(st->st_low, SPEEX_GET_DTX, ptr); + break; + case SPEEX_GET_LOW_MODE: + speex_encoder_ctl(st->st_low, SPEEX_GET_LOW_MODE, ptr); + break; + case SPEEX_SET_MODE: + speex_encoder_ctl(st, SPEEX_SET_QUALITY, ptr); + break; +#ifndef DISABLE_VBR + case SPEEX_SET_VBR: + st->vbr_enabled = (*(spx_int32_t*)ptr); + speex_encoder_ctl(st->st_low, SPEEX_SET_VBR, ptr); + break; + case SPEEX_GET_VBR: + (*(spx_int32_t*)ptr) = st->vbr_enabled; + break; + case SPEEX_SET_VAD: + st->vad_enabled = (*(spx_int32_t*)ptr); + speex_encoder_ctl(st->st_low, SPEEX_SET_VAD, ptr); + break; + case SPEEX_GET_VAD: + (*(spx_int32_t*)ptr) = st->vad_enabled; + break; +#endif /* #ifndef DISABLE_VBR */ +#if !defined(DISABLE_VBR) && !defined(DISABLE_FLOAT_API) + case SPEEX_SET_VBR_QUALITY: + { + spx_int32_t q; + float qual = (*(float*)ptr)+.6; + st->vbr_quality = (*(float*)ptr); + if (qual>10) + qual=10; + q=(int)floor(.5+*(float*)ptr); + if (q>10) + q=10; + speex_encoder_ctl(st->st_low, SPEEX_SET_VBR_QUALITY, &qual); + speex_encoder_ctl(state, SPEEX_SET_QUALITY, &q); + break; + } + case SPEEX_GET_VBR_QUALITY: + (*(float*)ptr) = st->vbr_quality; + break; +#endif /* #if !defined(DISABLE_VBR) && !defined(DISABLE_FLOAT_API) */ +#ifndef DISABLE_VBR + case SPEEX_SET_ABR: + st->abr_enabled = (*(spx_int32_t*)ptr); + st->vbr_enabled = st->abr_enabled!=0; + speex_encoder_ctl(st->st_low, SPEEX_SET_VBR, &st->vbr_enabled); + if (st->vbr_enabled) + { + spx_int32_t i=10, rate, target; + float vbr_qual; + target = (*(spx_int32_t*)ptr); + while (i>=0) + { + speex_encoder_ctl(st, SPEEX_SET_QUALITY, &i); + speex_encoder_ctl(st, SPEEX_GET_BITRATE, &rate); + if (rate <= target) + break; + i--; + } + vbr_qual=i; + if (vbr_qual<0) + vbr_qual=0; + speex_encoder_ctl(st, SPEEX_SET_VBR_QUALITY, &vbr_qual); + st->abr_count=0; + st->abr_drift=0; + st->abr_drift2=0; + } + + break; + case SPEEX_GET_ABR: + (*(spx_int32_t*)ptr) = st->abr_enabled; + break; +#endif /* #ifndef DISABLE_VBR */ + + case SPEEX_SET_QUALITY: + { + spx_int32_t nb_qual; + int quality = (*(spx_int32_t*)ptr); + if (quality < 0) + quality = 0; + if (quality > 10) + quality = 10; + st->submodeSelect = st->submodeID = ((const SpeexSBMode*)(st->mode->mode))->quality_map[quality]; + nb_qual = ((const SpeexSBMode*)(st->mode->mode))->low_quality_map[quality]; + speex_encoder_ctl(st->st_low, SPEEX_SET_MODE, &nb_qual); + } + break; + case SPEEX_SET_COMPLEXITY: + speex_encoder_ctl(st->st_low, SPEEX_SET_COMPLEXITY, ptr); + st->complexity = (*(spx_int32_t*)ptr); + if (st->complexity<1) + st->complexity=1; + break; + case SPEEX_GET_COMPLEXITY: + (*(spx_int32_t*)ptr) = st->complexity; + break; + case SPEEX_SET_BITRATE: + { + spx_int32_t i=10; + spx_int32_t rate, target; + target = (*(spx_int32_t*)ptr); + while (i>=0) + { + speex_encoder_ctl(st, SPEEX_SET_QUALITY, &i); + speex_encoder_ctl(st, SPEEX_GET_BITRATE, &rate); + if (rate <= target) + break; + i--; + } + } + break; + case SPEEX_GET_BITRATE: + speex_encoder_ctl(st->st_low, request, ptr); + /*fprintf (stderr, "before: %d\n", (*(int*)ptr));*/ + if (st->submodes[st->submodeID]) + (*(spx_int32_t*)ptr) += st->sampling_rate*SUBMODE(bits_per_frame)/st->full_frame_size; + else + (*(spx_int32_t*)ptr) += st->sampling_rate*(SB_SUBMODE_BITS+1)/st->full_frame_size; + /*fprintf (stderr, "after: %d\n", (*(int*)ptr));*/ + break; + case SPEEX_SET_SAMPLING_RATE: + { + spx_int32_t tmp=(*(spx_int32_t*)ptr); + st->sampling_rate = tmp; + tmp>>=1; + speex_encoder_ctl(st->st_low, SPEEX_SET_SAMPLING_RATE, &tmp); + } + break; + case SPEEX_GET_SAMPLING_RATE: + (*(spx_int32_t*)ptr)=st->sampling_rate; + break; + case SPEEX_RESET_STATE: + { + int i; + st->first = 1; + for (i=0;ilpcSize;i++) + st->old_lsp[i]= DIV32(MULT16_16(QCONST16(3.1415927f, LSP_SHIFT), i+1), st->lpcSize+1); + for (i=0;ilpcSize;i++) + st->mem_sw[i]=st->mem_sp[i]=st->mem_sp2[i]=0; + for (i=0;ih0_mem[i]=st->h1_mem[i]=0; + } + break; + case SPEEX_SET_SUBMODE_ENCODING: + st->encode_submode = (*(spx_int32_t*)ptr); + speex_encoder_ctl(st->st_low, SPEEX_SET_SUBMODE_ENCODING, ptr); + break; + case SPEEX_GET_SUBMODE_ENCODING: + (*(spx_int32_t*)ptr) = st->encode_submode; + break; + case SPEEX_GET_LOOKAHEAD: + speex_encoder_ctl(st->st_low, SPEEX_GET_LOOKAHEAD, ptr); + (*(spx_int32_t*)ptr) = 2*(*(spx_int32_t*)ptr) + QMF_ORDER - 1; + break; + case SPEEX_SET_PLC_TUNING: + speex_encoder_ctl(st->st_low, SPEEX_SET_PLC_TUNING, ptr); + break; + case SPEEX_GET_PLC_TUNING: + speex_encoder_ctl(st->st_low, SPEEX_GET_PLC_TUNING, ptr); + break; +#ifndef DISABLE_VBR + case SPEEX_SET_VBR_MAX_BITRATE: + { + st->vbr_max = (*(spx_int32_t*)ptr); + if (SPEEX_SET_VBR_MAX_BITRATE<1) + { + speex_encoder_ctl(st->st_low, SPEEX_SET_VBR_MAX_BITRATE, &st->vbr_max); + st->vbr_max_high = 17600; + } else { + spx_int32_t low_rate; + if (st->vbr_max >= 42200) + { + st->vbr_max_high = 17600; + } else if (st->vbr_max >= 27800) + { + st->vbr_max_high = 9600; + } else if (st->vbr_max > 20600) + { + st->vbr_max_high = 5600; + } else { + st->vbr_max_high = 1800; + } + if (st->subframeSize==80) + st->vbr_max_high = 1800; + low_rate = st->vbr_max - st->vbr_max_high; + speex_encoder_ctl(st->st_low, SPEEX_SET_VBR_MAX_BITRATE, &low_rate); + } + } + break; + case SPEEX_GET_VBR_MAX_BITRATE: + (*(spx_int32_t*)ptr) = st->vbr_max; + break; +#endif /* #ifndef DISABLE_VBR */ + case SPEEX_SET_HIGHPASS: + speex_encoder_ctl(st->st_low, SPEEX_SET_HIGHPASS, ptr); + break; + case SPEEX_GET_HIGHPASS: + speex_encoder_ctl(st->st_low, SPEEX_GET_HIGHPASS, ptr); + break; + + + /* This is all internal stuff past this point */ + case SPEEX_GET_PI_GAIN: + { + int i; + spx_word32_t *g = (spx_word32_t*)ptr; + for (i=0;inbSubframes;i++) + g[i]=st->pi_gain[i]; + } + break; + case SPEEX_GET_EXC: + { + int i; + for (i=0;inbSubframes;i++) + ((spx_word16_t*)ptr)[i] = st->exc_rms[i]; + } + break; +#ifndef DISABLE_VBR + case SPEEX_GET_RELATIVE_QUALITY: + (*(float*)ptr)=st->relative_quality; + break; +#endif /* #ifndef DISABLE_VBR */ + case SPEEX_SET_INNOVATION_SAVE: + st->innov_rms_save = (spx_word16_t*)ptr; + break; + case SPEEX_SET_WIDEBAND: + speex_encoder_ctl(st->st_low, SPEEX_SET_WIDEBAND, ptr); + break; + case SPEEX_GET_STACK: + *((char**)ptr) = st->stack; + break; + default: + speex_warning_int("Unknown nb_ctl request: ", request); + return -1; + } + return 0; +} + +int sb_decoder_ctl(void *state, int request, void *ptr) +{ + SBDecState *st; + st=(SBDecState*)state; + switch(request) + { + case SPEEX_SET_HIGH_MODE: + st->submodeID = (*(spx_int32_t*)ptr); + break; + case SPEEX_SET_LOW_MODE: + speex_decoder_ctl(st->st_low, SPEEX_SET_LOW_MODE, ptr); + break; + case SPEEX_GET_LOW_MODE: + speex_decoder_ctl(st->st_low, SPEEX_GET_LOW_MODE, ptr); + break; + case SPEEX_GET_FRAME_SIZE: + (*(spx_int32_t*)ptr) = st->full_frame_size; + break; + case SPEEX_SET_ENH: + speex_decoder_ctl(st->st_low, request, ptr); + st->lpc_enh_enabled = *((spx_int32_t*)ptr); + break; + case SPEEX_GET_ENH: + *((spx_int32_t*)ptr) = st->lpc_enh_enabled; + break; + case SPEEX_SET_MODE: + case SPEEX_SET_QUALITY: + { + spx_int32_t nb_qual; + int quality = (*(spx_int32_t*)ptr); + if (quality < 0) + quality = 0; + if (quality > 10) + quality = 10; + st->submodeID = ((const SpeexSBMode*)(st->mode->mode))->quality_map[quality]; + nb_qual = ((const SpeexSBMode*)(st->mode->mode))->low_quality_map[quality]; + speex_decoder_ctl(st->st_low, SPEEX_SET_MODE, &nb_qual); + } + break; + case SPEEX_GET_BITRATE: + speex_decoder_ctl(st->st_low, request, ptr); + if (st->submodes[st->submodeID]) + (*(spx_int32_t*)ptr) += st->sampling_rate*SUBMODE(bits_per_frame)/st->full_frame_size; + else + (*(spx_int32_t*)ptr) += st->sampling_rate*(SB_SUBMODE_BITS+1)/st->full_frame_size; + break; + case SPEEX_SET_SAMPLING_RATE: + { + spx_int32_t tmp=(*(spx_int32_t*)ptr); + st->sampling_rate = tmp; + tmp>>=1; + speex_decoder_ctl(st->st_low, SPEEX_SET_SAMPLING_RATE, &tmp); + } + break; + case SPEEX_GET_SAMPLING_RATE: + (*(spx_int32_t*)ptr)=st->sampling_rate; + break; + case SPEEX_SET_HANDLER: + speex_decoder_ctl(st->st_low, SPEEX_SET_HANDLER, ptr); + break; + case SPEEX_SET_USER_HANDLER: + speex_decoder_ctl(st->st_low, SPEEX_SET_USER_HANDLER, ptr); + break; + case SPEEX_RESET_STATE: + { + int i; + for (i=0;i<2*st->lpcSize;i++) + st->mem_sp[i]=0; + for (i=0;ig0_mem[i]=st->g1_mem[i]=0; + st->last_ener=0; + } + break; + case SPEEX_SET_SUBMODE_ENCODING: + st->encode_submode = (*(spx_int32_t*)ptr); + speex_decoder_ctl(st->st_low, SPEEX_SET_SUBMODE_ENCODING, ptr); + break; + case SPEEX_GET_SUBMODE_ENCODING: + (*(spx_int32_t*)ptr) = st->encode_submode; + break; + case SPEEX_GET_LOOKAHEAD: + speex_decoder_ctl(st->st_low, SPEEX_GET_LOOKAHEAD, ptr); + (*(spx_int32_t*)ptr) = 2*(*(spx_int32_t*)ptr); + break; + case SPEEX_SET_HIGHPASS: + speex_decoder_ctl(st->st_low, SPEEX_SET_HIGHPASS, ptr); + break; + case SPEEX_GET_HIGHPASS: + speex_decoder_ctl(st->st_low, SPEEX_GET_HIGHPASS, ptr); + break; + case SPEEX_GET_ACTIVITY: + speex_decoder_ctl(st->st_low, SPEEX_GET_ACTIVITY, ptr); + break; + case SPEEX_GET_PI_GAIN: + { + int i; + spx_word32_t *g = (spx_word32_t*)ptr; + for (i=0;inbSubframes;i++) + g[i]=st->pi_gain[i]; + } + break; + case SPEEX_GET_EXC: + { + int i; + for (i=0;inbSubframes;i++) + ((spx_word16_t*)ptr)[i] = st->exc_rms[i]; + } + break; + case SPEEX_GET_DTX_STATUS: + speex_decoder_ctl(st->st_low, SPEEX_GET_DTX_STATUS, ptr); + break; + case SPEEX_SET_INNOVATION_SAVE: + st->innov_save = (spx_word16_t*)ptr; + break; + case SPEEX_SET_WIDEBAND: + speex_decoder_ctl(st->st_low, SPEEX_SET_WIDEBAND, ptr); + break; + case SPEEX_GET_STACK: + *((char**)ptr) = st->stack; + break; + default: + speex_warning_int("Unknown nb_ctl request: ", request); + return -1; + } + return 0; +} + +#endif + diff --git a/ios/IOSDuoduo/Voice/Code/Libs/libspeex/sb_celp.h b/ios/IOSDuoduo/Voice/Code/Libs/libspeex/sb_celp.h new file mode 100755 index 000000000..cb98e26ec --- /dev/null +++ b/ios/IOSDuoduo/Voice/Code/Libs/libspeex/sb_celp.h @@ -0,0 +1,155 @@ +/* Copyright (C) 2002-2006 Jean-Marc Valin */ +/** + @file sb_celp.h + @brief Sub-band CELP mode used for wideband encoding +*/ +/* + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + - Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + - Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + - Neither the name of the Xiph.org Foundation nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR + CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +*/ + +#ifndef SB_CELP_H +#define SB_CELP_H + +#include "modes.h" +#include "speex/speex_bits.h" +#include "nb_celp.h" + +/**Structure representing the full state of the sub-band encoder*/ +typedef struct SBEncState { + const SpeexMode *mode; /**< Pointer to the mode (containing for vtable info) */ + void *st_low; /**< State of the low-band (narrowband) encoder */ + int full_frame_size; /**< Length of full-band frames*/ + int frame_size; /**< Length of high-band frames*/ + int subframeSize; /**< Length of high-band sub-frames*/ + int nbSubframes; /**< Number of high-band sub-frames*/ + int windowSize; /**< Length of high-band LPC window*/ + int lpcSize; /**< Order of high-band LPC analysis */ + int first; /**< First frame? */ + spx_word16_t lpc_floor; /**< Controls LPC analysis noise floor */ + spx_word16_t gamma1; /**< Perceptual weighting coef 1 */ + spx_word16_t gamma2; /**< Perceptual weighting coef 2 */ + + char *stack; /**< Temporary allocation stack */ + spx_word16_t *high; /**< High-band signal (buffer) */ + spx_word16_t *h0_mem, *h1_mem; + + const spx_word16_t *window; /**< LPC analysis window */ + const spx_word16_t *lagWindow; /**< Auto-correlation window */ + spx_lsp_t *old_lsp; /**< LSPs of previous frame */ + spx_lsp_t *old_qlsp; /**< Quantized LSPs of previous frame */ + spx_coef_t *interp_qlpc; /**< Interpolated quantized LPCs for current sub-frame */ + + spx_mem_t *mem_sp; /**< Synthesis signal memory */ + spx_mem_t *mem_sp2; + spx_mem_t *mem_sw; /**< Perceptual signal memory */ + spx_word32_t *pi_gain; + spx_word16_t *exc_rms; + spx_word16_t *innov_rms_save; /**< If non-NULL, innovation is copied here */ + +#ifndef DISABLE_VBR + float vbr_quality; /**< Quality setting for VBR encoding */ + int vbr_enabled; /**< 1 for enabling VBR, 0 otherwise */ + spx_int32_t vbr_max; /**< Max bit-rate allowed in VBR mode (total) */ + spx_int32_t vbr_max_high; /**< Max bit-rate allowed in VBR mode for the high-band */ + spx_int32_t abr_enabled; /**< ABR setting (in bps), 0 if off */ + float abr_drift; + float abr_drift2; + float abr_count; + int vad_enabled; /**< 1 for enabling VAD, 0 otherwise */ + float relative_quality; +#endif /* #ifndef DISABLE_VBR */ + + int encode_submode; + const SpeexSubmode * const *submodes; + int submodeID; + int submodeSelect; + int complexity; + spx_int32_t sampling_rate; + +} SBEncState; + + +/**Structure representing the full state of the sub-band decoder*/ +typedef struct SBDecState { + const SpeexMode *mode; /**< Pointer to the mode (containing for vtable info) */ + void *st_low; /**< State of the low-band (narrowband) encoder */ + int full_frame_size; + int frame_size; + int subframeSize; + int nbSubframes; + int lpcSize; + int first; + spx_int32_t sampling_rate; + int lpc_enh_enabled; + + char *stack; + spx_word16_t *g0_mem, *g1_mem; + + spx_word16_t *excBuf; + spx_lsp_t *old_qlsp; + spx_coef_t *interp_qlpc; + + spx_mem_t *mem_sp; + spx_word32_t *pi_gain; + spx_word16_t *exc_rms; + spx_word16_t *innov_save; /** If non-NULL, innovation is copied here */ + + spx_word16_t last_ener; + spx_int32_t seed; + + int encode_submode; + const SpeexSubmode * const *submodes; + int submodeID; +} SBDecState; + + +/**Initializes encoder state*/ +void *sb_encoder_init(const SpeexMode *m); + +/**De-allocates encoder state resources*/ +void sb_encoder_destroy(void *state); + +/**Encodes one frame*/ +int sb_encode(void *state, void *in, SpeexBits *bits); + + +/**Initializes decoder state*/ +void *sb_decoder_init(const SpeexMode *m); + +/**De-allocates decoder state resources*/ +void sb_decoder_destroy(void *state); + +/**Decodes one frame*/ +int sb_decode(void *state, SpeexBits *bits, void *out); + +int sb_encoder_ctl(void *state, int request, void *ptr); + +int sb_decoder_ctl(void *state, int request, void *ptr); + +#endif diff --git a/ios/IOSDuoduo/Voice/Code/Libs/libspeex/scal.c b/ios/IOSDuoduo/Voice/Code/Libs/libspeex/scal.c new file mode 100755 index 000000000..23b83e7a8 --- /dev/null +++ b/ios/IOSDuoduo/Voice/Code/Libs/libspeex/scal.c @@ -0,0 +1,288 @@ +/* Copyright (C) 2006-2008 CSIRO, Jean-Marc Valin, Xiph.Org Foundation + + File: scal.c + Shaped comb-allpass filter for channel decorrelation + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are + met: + + 1. Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + 3. The name of the author may not be used to endorse or promote products + derived from this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, + INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + POSSIBILITY OF SUCH DAMAGE. +*/ + +/* +The algorithm implemented here is described in: + +* J.-M. Valin, Perceptually-Motivated Nonlinear Channel Decorrelation For + Stereo Acoustic Echo Cancellation, Accepted for Joint Workshop on + Hands­free Speech Communication and Microphone Arrays (HSCMA), 2008. + http://people.xiph.org/~jm/papers/valin_hscma2008.pdf + +*/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "speex/speex_echo.h" +#include "vorbis_psy.h" +#include "arch.h" +#include "os_support.h" +#include "smallft.h" +#include +#include + +#define ALLPASS_ORDER 20 + +struct SpeexDecorrState_ { + int rate; + int channels; + int frame_size; +#ifdef VORBIS_PSYCHO + VorbisPsy *psy; + struct drft_lookup lookup; + float *wola_mem; + float *curve; +#endif + float *vorbis_win; + int seed; + float *y; + + /* Per-channel stuff */ + float *buff; + float (*ring)[ALLPASS_ORDER]; + int *ringID; + int *order; + float *alpha; +}; + + + +EXPORT SpeexDecorrState *speex_decorrelate_new(int rate, int channels, int frame_size) +{ + int i, ch; + SpeexDecorrState *st = speex_alloc(sizeof(SpeexDecorrState)); + st->rate = rate; + st->channels = channels; + st->frame_size = frame_size; +#ifdef VORBIS_PSYCHO + st->psy = vorbis_psy_init(rate, 2*frame_size); + spx_drft_init(&st->lookup, 2*frame_size); + st->wola_mem = speex_alloc(frame_size*sizeof(float)); + st->curve = speex_alloc(frame_size*sizeof(float)); +#endif + st->y = speex_alloc(frame_size*sizeof(float)); + + st->buff = speex_alloc(channels*2*frame_size*sizeof(float)); + st->ringID = speex_alloc(channels*sizeof(int)); + st->order = speex_alloc(channels*sizeof(int)); + st->alpha = speex_alloc(channels*sizeof(float)); + st->ring = speex_alloc(channels*ALLPASS_ORDER*sizeof(float)); + + /*FIXME: The +20 is there only as a kludge for ALL_PASS_OLA*/ + st->vorbis_win = speex_alloc((2*frame_size+20)*sizeof(float)); + for (i=0;i<2*frame_size;i++) + st->vorbis_win[i] = sin(.5*M_PI* sin(M_PI*i/(2*frame_size))*sin(M_PI*i/(2*frame_size)) ); + st->seed = rand(); + + for (ch=0;chring[ch][i] = 0; + st->ringID[ch] = 0; + st->alpha[ch] = 0; + st->order[ch] = 10; + } + return st; +} + +static float uni_rand(int *seed) +{ + const unsigned int jflone = 0x3f800000; + const unsigned int jflmsk = 0x007fffff; + union {int i; float f;} ran; + *seed = 1664525 * *seed + 1013904223; + ran.i = jflone | (jflmsk & *seed); + ran.f -= 1.5; + return 2*ran.f; +} + +static unsigned int irand(int *seed) +{ + *seed = 1664525 * *seed + 1013904223; + return ((unsigned int)*seed)>>16; +} + + +EXPORT void speex_decorrelate(SpeexDecorrState *st, const spx_int16_t *in, spx_int16_t *out, int strength) +{ + int ch; + float amount; + + if (strength<0) + strength = 0; + if (strength>100) + strength = 100; + + amount = .01*strength; + for (ch=0;chchannels;ch++) + { + int i; + float beta, beta2; + float *x; + float max_alpha = 0; + + float *buff; + float *ring; + int ringID; + int order; + float alpha; + + buff = st->buff+ch*2*st->frame_size; + ring = st->ring[ch]; + ringID = st->ringID[ch]; + order = st->order[ch]; + alpha = st->alpha[ch]; + + for (i=0;iframe_size;i++) + buff[i] = buff[i+st->frame_size]; + for (i=0;iframe_size;i++) + buff[i+st->frame_size] = in[i*st->channels+ch]; + + x = buff+st->frame_size; + beta = 1.-.3*amount*amount; + if (amount>1) + beta = 1-sqrt(.4*amount); + else + beta = 1-0.63246*amount; + if (beta<0) + beta = 0; + + beta2 = beta; + for (i=0;iframe_size;i++) + { + st->y[i] = alpha*(x[i-ALLPASS_ORDER+order]-beta*x[i-ALLPASS_ORDER+order-1])*st->vorbis_win[st->frame_size+i+order] + + x[i-ALLPASS_ORDER]*st->vorbis_win[st->frame_size+i] + - alpha*(ring[ringID] + - beta*ring[ringID+1>=order?0:ringID+1]); + ring[ringID++]=st->y[i]; + st->y[i] *= st->vorbis_win[st->frame_size+i]; + if (ringID>=order) + ringID=0; + } + order = order+(irand(&st->seed)%3)-1; + if (order < 5) + order = 5; + if (order > 10) + order = 10; + /*order = 5+(irand(&st->seed)%6);*/ + max_alpha = pow(.96+.04*(amount-1),order); + if (max_alpha > .98/(1.+beta2)) + max_alpha = .98/(1.+beta2); + + alpha = alpha + .4*uni_rand(&st->seed); + if (alpha > max_alpha) + alpha = max_alpha; + if (alpha < -max_alpha) + alpha = -max_alpha; + for (i=0;iframe_size;i++) + { + float tmp = alpha*(x[i-ALLPASS_ORDER+order]-beta*x[i-ALLPASS_ORDER+order-1])*st->vorbis_win[i+order] + + x[i-ALLPASS_ORDER]*st->vorbis_win[i] + - alpha*(ring[ringID] + - beta*ring[ringID+1>=order?0:ringID+1]); + ring[ringID++]=tmp; + tmp *= st->vorbis_win[i]; + if (ringID>=order) + ringID=0; + st->y[i] += tmp; + } + +#ifdef VORBIS_PSYCHO + float frame[N]; + float scale = 1./N; + for (i=0;i<2*st->frame_size;i++) + frame[i] = buff[i]; + //float coef = .5*0.78130; + float coef = M_PI*0.075063 * 0.93763 * amount * .8 * 0.707; + compute_curve(st->psy, buff, st->curve); + for (i=1;iframe_size;i++) + { + float x1,x2; + float gain; + do { + x1 = uni_rand(&st->seed); + x2 = uni_rand(&st->seed); + } while (x1*x1+x2*x2 > 1.); + gain = coef*sqrt(.1+st->curve[i]); + frame[2*i-1] = gain*x1; + frame[2*i] = gain*x2; + } + frame[0] = coef*uni_rand(&st->seed)*sqrt(.1+st->curve[0]); + frame[2*st->frame_size-1] = coef*uni_rand(&st->seed)*sqrt(.1+st->curve[st->frame_size-1]); + spx_drft_backward(&st->lookup,frame); + for (i=0;i<2*st->frame_size;i++) + frame[i] *= st->vorbis_win[i]; +#endif + + for (i=0;iframe_size;i++) + { +#ifdef VORBIS_PSYCHO + float tmp = st->y[i] + frame[i] + st->wola_mem[i]; + st->wola_mem[i] = frame[i+st->frame_size]; +#else + float tmp = st->y[i]; +#endif + if (tmp>32767) + tmp = 32767; + if (tmp < -32767) + tmp = -32767; + out[i*st->channels+ch] = tmp; + } + + st->ringID[ch] = ringID; + st->order[ch] = order; + st->alpha[ch] = alpha; + + } +} + +EXPORT void speex_decorrelate_destroy(SpeexDecorrState *st) +{ +#ifdef VORBIS_PSYCHO + vorbis_psy_destroy(st->psy); + speex_free(st->wola_mem); + speex_free(st->curve); +#endif + speex_free(st->buff); + speex_free(st->ring); + speex_free(st->ringID); + speex_free(st->alpha); + speex_free(st->vorbis_win); + speex_free(st->order); + speex_free(st->y); + speex_free(st); +} diff --git a/ios/IOSDuoduo/Voice/Code/Libs/libspeex/smallft.c b/ios/IOSDuoduo/Voice/Code/Libs/libspeex/smallft.c new file mode 100755 index 000000000..5c26d016f --- /dev/null +++ b/ios/IOSDuoduo/Voice/Code/Libs/libspeex/smallft.c @@ -0,0 +1,1261 @@ +/******************************************************************** + * * + * THIS FILE IS PART OF THE OggVorbis SOFTWARE CODEC SOURCE CODE. * + * USE, DISTRIBUTION AND REPRODUCTION OF THIS LIBRARY SOURCE IS * + * GOVERNED BY A BSD-STYLE SOURCE LICENSE INCLUDED WITH THIS SOURCE * + * IN 'COPYING'. PLEASE READ THESE TERMS BEFORE DISTRIBUTING. * + * * + * THE OggVorbis SOURCE CODE IS (C) COPYRIGHT 1994-2001 * + * by the XIPHOPHORUS Company http://www.xiph.org/ * + * * + ******************************************************************** + + function: *unnormalized* fft transform + last mod: $Id: smallft.c,v 1.19 2003/10/08 05:12:37 jm Exp $ + + ********************************************************************/ + +/* FFT implementation from OggSquish, minus cosine transforms, + * minus all but radix 2/4 case. In Vorbis we only need this + * cut-down version. + * + * To do more than just power-of-two sized vectors, see the full + * version I wrote for NetLib. + * + * Note that the packing is a little strange; rather than the FFT r/i + * packing following R_0, I_n, R_1, I_1, R_2, I_2 ... R_n-1, I_n-1, + * it follows R_0, R_1, I_1, R_2, I_2 ... R_n-1, I_n-1, I_n like the + * FORTRAN version + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include +#include "smallft.h" +#include "arch.h" +#include "os_support.h" + +static void drfti1(int n, float *wa, int *ifac){ + static int ntryh[4] = { 4,2,3,5 }; + static float tpi = 6.28318530717958648f; + float arg,argh,argld,fi; + int ntry=0,i,j=-1; + int k1, l1, l2, ib; + int ld, ii, ip, is, nq, nr; + int ido, ipm, nfm1; + int nl=n; + int nf=0; + + L101: + j++; + if (j < 4) + ntry=ntryh[j]; + else + ntry+=2; + + L104: + nq=nl/ntry; + nr=nl-ntry*nq; + if (nr!=0) goto L101; + + nf++; + ifac[nf+1]=ntry; + nl=nq; + if(ntry!=2)goto L107; + if(nf==1)goto L107; + + for (i=1;i>1; + ipp2=ip; + idp2=ido; + nbd=(ido-1)>>1; + t0=l1*ido; + t10=ip*ido; + + if(ido==1)goto L119; + for(ik=0;ikl1){ + for(j=1;j>1; + ipp2=ip; + ipph=(ip+1)>>1; + if(idol1)goto L139; + + is= -ido-1; + t1=0; + for(j=1;jn==1)return; + drftf1(l->n,data,l->trigcache,l->trigcache+l->n,l->splitcache); +} + +void spx_drft_backward(struct drft_lookup *l,float *data){ + if (l->n==1)return; + drftb1(l->n,data,l->trigcache,l->trigcache+l->n,l->splitcache); +} + +void spx_drft_init(struct drft_lookup *l,int n) +{ + l->n=n; + l->trigcache=(float*)speex_alloc(3*n*sizeof(*l->trigcache)); + l->splitcache=(int*)speex_alloc(32*sizeof(*l->splitcache)); + fdrffti(n, l->trigcache, l->splitcache); +} + +void spx_drft_clear(struct drft_lookup *l) +{ + if(l) + { + if(l->trigcache) + speex_free(l->trigcache); + if(l->splitcache) + speex_free(l->splitcache); + } +} diff --git a/ios/IOSDuoduo/Voice/Code/Libs/libspeex/smallft.h b/ios/IOSDuoduo/Voice/Code/Libs/libspeex/smallft.h new file mode 100755 index 000000000..446e2f65b --- /dev/null +++ b/ios/IOSDuoduo/Voice/Code/Libs/libspeex/smallft.h @@ -0,0 +1,46 @@ +/******************************************************************** + * * + * THIS FILE IS PART OF THE OggVorbis SOFTWARE CODEC SOURCE CODE. * + * USE, DISTRIBUTION AND REPRODUCTION OF THIS LIBRARY SOURCE IS * + * GOVERNED BY A BSD-STYLE SOURCE LICENSE INCLUDED WITH THIS SOURCE * + * IN 'COPYING'. PLEASE READ THESE TERMS BEFORE DISTRIBUTING. * + * * + * THE OggVorbis SOURCE CODE IS (C) COPYRIGHT 1994-2001 * + * by the XIPHOPHORUS Company http://www.xiph.org/ * + * * + ******************************************************************** + + function: fft transform + last mod: $Id: smallft.h,v 1.3 2003/09/16 18:35:45 jm Exp $ + + ********************************************************************/ +/** + @file smallft.h + @brief Discrete Rotational Fourier Transform (DRFT) +*/ + +#ifndef _V_SMFT_H_ +#define _V_SMFT_H_ + + +#ifdef __cplusplus +extern "C" { +#endif + +/** Discrete Rotational Fourier Transform lookup */ +struct drft_lookup{ + int n; + float *trigcache; + int *splitcache; +}; + +extern void spx_drft_forward(struct drft_lookup *l,float *data); +extern void spx_drft_backward(struct drft_lookup *l,float *data); +extern void spx_drft_init(struct drft_lookup *l,int n); +extern void spx_drft_clear(struct drft_lookup *l); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/ios/IOSDuoduo/Voice/Code/Libs/libspeex/speex.c b/ios/IOSDuoduo/Voice/Code/Libs/libspeex/speex.c new file mode 100755 index 000000000..b425155c2 --- /dev/null +++ b/ios/IOSDuoduo/Voice/Code/Libs/libspeex/speex.c @@ -0,0 +1,250 @@ +/* Copyright (C) 2002 Jean-Marc Valin + File: speex.c + + Basic Speex functions + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + - Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + - Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + - Neither the name of the Xiph.org Foundation nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR + CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +*/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "modes.h" +#include +#include "os_support.h" + +#ifndef NULL +#define NULL 0 +#endif + +#define MAX_IN_SAMPLES 640 + + + +EXPORT void *speex_encoder_init(const SpeexMode *mode) +{ + return mode->enc_init(mode); +} + +EXPORT void *speex_decoder_init(const SpeexMode *mode) +{ + return mode->dec_init(mode); +} + +EXPORT void speex_encoder_destroy(void *state) +{ + (*((SpeexMode**)state))->enc_destroy(state); +} + +EXPORT void speex_decoder_destroy(void *state) +{ + (*((SpeexMode**)state))->dec_destroy(state); +} + + + +int speex_encode_native(void *state, spx_word16_t *in, SpeexBits *bits) +{ + return (*((SpeexMode**)state))->enc(state, in, bits); +} + +int speex_decode_native(void *state, SpeexBits *bits, spx_word16_t *out) +{ + return (*((SpeexMode**)state))->dec(state, bits, out); +} + + + +#ifdef FIXED_POINT + +#ifndef DISABLE_FLOAT_API +EXPORT int speex_encode(void *state, float *in, SpeexBits *bits) +{ + int i; + spx_int32_t N; + spx_int16_t short_in[MAX_IN_SAMPLES]; + speex_encoder_ctl(state, SPEEX_GET_FRAME_SIZE, &N); + for (i=0;i32767.f) + short_in[i] = 32767; + else if (in[i]<-32768.f) + short_in[i] = -32768; + else + short_in[i] = (spx_int16_t)floor(.5+in[i]); + } + return (*((SpeexMode**)state))->enc(state, short_in, bits); +} +#endif /* #ifndef DISABLE_FLOAT_API */ + +EXPORT int speex_encode_int(void *state, spx_int16_t *in, SpeexBits *bits) +{ + SpeexMode *mode; + mode = *(SpeexMode**)state; + return (mode)->enc(state, in, bits); +} + +#ifndef DISABLE_FLOAT_API +EXPORT int speex_decode(void *state, SpeexBits *bits, float *out) +{ + int i, ret; + spx_int32_t N; + spx_int16_t short_out[MAX_IN_SAMPLES]; + speex_decoder_ctl(state, SPEEX_GET_FRAME_SIZE, &N); + ret = (*((SpeexMode**)state))->dec(state, bits, short_out); + for (i=0;idec(state, bits, out); +} + +#else + +EXPORT int speex_encode(void *state, float *in, SpeexBits *bits) +{ + return (*((SpeexMode**)state))->enc(state, in, bits); +} + +EXPORT int speex_encode_int(void *state, spx_int16_t *in, SpeexBits *bits) +{ + int i; + spx_int32_t N; + float float_in[MAX_IN_SAMPLES]; + speex_encoder_ctl(state, SPEEX_GET_FRAME_SIZE, &N); + for (i=0;ienc(state, float_in, bits); +} + +EXPORT int speex_decode(void *state, SpeexBits *bits, float *out) +{ + return (*((SpeexMode**)state))->dec(state, bits, out); +} + +EXPORT int speex_decode_int(void *state, SpeexBits *bits, spx_int16_t *out) +{ + int i; + spx_int32_t N; + float float_out[MAX_IN_SAMPLES]; + int ret; + speex_decoder_ctl(state, SPEEX_GET_FRAME_SIZE, &N); + ret = (*((SpeexMode**)state))->dec(state, bits, float_out); + for (i=0;i32767.f) + out[i] = 32767; + else if (float_out[i]<-32768.f) + out[i] = -32768; + else + out[i] = (spx_int16_t)floor(.5+float_out[i]); + } + return ret; +} +#endif + + + +EXPORT int speex_encoder_ctl(void *state, int request, void *ptr) +{ + return (*((SpeexMode**)state))->enc_ctl(state, request, ptr); +} + +EXPORT int speex_decoder_ctl(void *state, int request, void *ptr) +{ + return (*((SpeexMode**)state))->dec_ctl(state, request, ptr); +} + + + +int nb_mode_query(const void *mode, int request, void *ptr) +{ + const SpeexNBMode *m = (const SpeexNBMode*)mode; + + switch (request) + { + case SPEEX_MODE_FRAME_SIZE: + *((int*)ptr)=m->frameSize; + break; + case SPEEX_SUBMODE_BITS_PER_FRAME: + if (*((int*)ptr)==0) + *((int*)ptr) = NB_SUBMODE_BITS+1; + else if (m->submodes[*((int*)ptr)]==NULL) + *((int*)ptr) = -1; + else + *((int*)ptr) = m->submodes[*((int*)ptr)]->bits_per_frame; + break; + default: + speex_warning_int("Unknown nb_mode_query request: ", request); + return -1; + } + return 0; +} + + + +EXPORT int speex_lib_ctl(int request, void *ptr) +{ + switch (request) + { + case SPEEX_LIB_GET_MAJOR_VERSION: + *((int*)ptr) = SPEEX_MAJOR_VERSION; + break; + case SPEEX_LIB_GET_MINOR_VERSION: + *((int*)ptr) = SPEEX_MINOR_VERSION; + break; + case SPEEX_LIB_GET_MICRO_VERSION: + *((int*)ptr) = SPEEX_MICRO_VERSION; + break; + case SPEEX_LIB_GET_EXTRA_VERSION: + *((const char**)ptr) = SPEEX_EXTRA_VERSION; + break; + case SPEEX_LIB_GET_VERSION_STRING: + *((const char**)ptr) = SPEEX_VERSION; + break; + /*case SPEEX_LIB_SET_ALLOC_FUNC: + break; + case SPEEX_LIB_GET_ALLOC_FUNC: + break; + case SPEEX_LIB_SET_FREE_FUNC: + break; + case SPEEX_LIB_GET_FREE_FUNC: + break;*/ + default: + speex_warning_int("Unknown wb_mode_query request: ", request); + return -1; + } + return 0; +} diff --git a/ios/IOSDuoduo/Voice/Code/Libs/libspeex/speex/speex.h b/ios/IOSDuoduo/Voice/Code/Libs/libspeex/speex/speex.h new file mode 100755 index 000000000..ffb0714f1 --- /dev/null +++ b/ios/IOSDuoduo/Voice/Code/Libs/libspeex/speex/speex.h @@ -0,0 +1,424 @@ +/* Copyright (C) 2002-2006 Jean-Marc Valin*/ +/** + @file speex.h + @brief Describes the different modes of the codec +*/ +/* + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + - Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + - Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + - Neither the name of the Xiph.org Foundation nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR + CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +*/ + +#ifndef SPEEX_H +#define SPEEX_H +/** @defgroup Codec Speex encoder and decoder + * This is the Speex codec itself. + * @{ + */ + +#include "speex_bits.h" +#include "speex_types.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/* Values allowed for *ctl() requests */ + +/** Set enhancement on/off (decoder only) */ +#define SPEEX_SET_ENH 0 +/** Get enhancement state (decoder only) */ +#define SPEEX_GET_ENH 1 + +/*Would be SPEEX_SET_FRAME_SIZE, but it's (currently) invalid*/ +/** Obtain frame size used by encoder/decoder */ +#define SPEEX_GET_FRAME_SIZE 3 + +/** Set quality value */ +#define SPEEX_SET_QUALITY 4 +/** Get current quality setting */ +/* #define SPEEX_GET_QUALITY 5 -- Doesn't make much sense, does it? */ + +/** Set sub-mode to use */ +#define SPEEX_SET_MODE 6 +/** Get current sub-mode in use */ +#define SPEEX_GET_MODE 7 + +/** Set low-band sub-mode to use (wideband only)*/ +#define SPEEX_SET_LOW_MODE 8 +/** Get current low-band mode in use (wideband only)*/ +#define SPEEX_GET_LOW_MODE 9 + +/** Set high-band sub-mode to use (wideband only)*/ +#define SPEEX_SET_HIGH_MODE 10 +/** Get current high-band mode in use (wideband only)*/ +#define SPEEX_GET_HIGH_MODE 11 + +/** Set VBR on (1) or off (0) */ +#define SPEEX_SET_VBR 12 +/** Get VBR status (1 for on, 0 for off) */ +#define SPEEX_GET_VBR 13 + +/** Set quality value for VBR encoding (0-10) */ +#define SPEEX_SET_VBR_QUALITY 14 +/** Get current quality value for VBR encoding (0-10) */ +#define SPEEX_GET_VBR_QUALITY 15 + +/** Set complexity of the encoder (0-10) */ +#define SPEEX_SET_COMPLEXITY 16 +/** Get current complexity of the encoder (0-10) */ +#define SPEEX_GET_COMPLEXITY 17 + +/** Set bit-rate used by the encoder (or lower) */ +#define SPEEX_SET_BITRATE 18 +/** Get current bit-rate used by the encoder or decoder */ +#define SPEEX_GET_BITRATE 19 + +/** Define a handler function for in-band Speex request*/ +#define SPEEX_SET_HANDLER 20 + +/** Define a handler function for in-band user-defined request*/ +#define SPEEX_SET_USER_HANDLER 22 + +/** Set sampling rate used in bit-rate computation */ +#define SPEEX_SET_SAMPLING_RATE 24 +/** Get sampling rate used in bit-rate computation */ +#define SPEEX_GET_SAMPLING_RATE 25 + +/** Reset the encoder/decoder memories to zero*/ +#define SPEEX_RESET_STATE 26 + +/** Get VBR info (mostly used internally) */ +#define SPEEX_GET_RELATIVE_QUALITY 29 + +/** Set VAD status (1 for on, 0 for off) */ +#define SPEEX_SET_VAD 30 + +/** Get VAD status (1 for on, 0 for off) */ +#define SPEEX_GET_VAD 31 + +/** Set Average Bit-Rate (ABR) to n bits per seconds */ +#define SPEEX_SET_ABR 32 +/** Get Average Bit-Rate (ABR) setting (in bps) */ +#define SPEEX_GET_ABR 33 + +/** Set DTX status (1 for on, 0 for off) */ +#define SPEEX_SET_DTX 34 +/** Get DTX status (1 for on, 0 for off) */ +#define SPEEX_GET_DTX 35 + +/** Set submode encoding in each frame (1 for yes, 0 for no, setting to no breaks the standard) */ +#define SPEEX_SET_SUBMODE_ENCODING 36 +/** Get submode encoding in each frame */ +#define SPEEX_GET_SUBMODE_ENCODING 37 + +/*#define SPEEX_SET_LOOKAHEAD 38*/ +/** Returns the lookahead used by Speex */ +#define SPEEX_GET_LOOKAHEAD 39 + +/** Sets tuning for packet-loss concealment (expected loss rate) */ +#define SPEEX_SET_PLC_TUNING 40 +/** Gets tuning for PLC */ +#define SPEEX_GET_PLC_TUNING 41 + +/** Sets the max bit-rate allowed in VBR mode */ +#define SPEEX_SET_VBR_MAX_BITRATE 42 +/** Gets the max bit-rate allowed in VBR mode */ +#define SPEEX_GET_VBR_MAX_BITRATE 43 + +/** Turn on/off input/output high-pass filtering */ +#define SPEEX_SET_HIGHPASS 44 +/** Get status of input/output high-pass filtering */ +#define SPEEX_GET_HIGHPASS 45 + +/** Get "activity level" of the last decoded frame, i.e. + how much damage we cause if we remove the frame */ +#define SPEEX_GET_ACTIVITY 47 + + +/* Preserving compatibility:*/ +/** Equivalent to SPEEX_SET_ENH */ +#define SPEEX_SET_PF 0 +/** Equivalent to SPEEX_GET_ENH */ +#define SPEEX_GET_PF 1 + + + + +/* Values allowed for mode queries */ +/** Query the frame size of a mode */ +#define SPEEX_MODE_FRAME_SIZE 0 + +/** Query the size of an encoded frame for a particular sub-mode */ +#define SPEEX_SUBMODE_BITS_PER_FRAME 1 + + + +/** Get major Speex version */ +#define SPEEX_LIB_GET_MAJOR_VERSION 1 +/** Get minor Speex version */ +#define SPEEX_LIB_GET_MINOR_VERSION 3 +/** Get micro Speex version */ +#define SPEEX_LIB_GET_MICRO_VERSION 5 +/** Get extra Speex version */ +#define SPEEX_LIB_GET_EXTRA_VERSION 7 +/** Get Speex version string */ +#define SPEEX_LIB_GET_VERSION_STRING 9 + +/*#define SPEEX_LIB_SET_ALLOC_FUNC 10 +#define SPEEX_LIB_GET_ALLOC_FUNC 11 +#define SPEEX_LIB_SET_FREE_FUNC 12 +#define SPEEX_LIB_GET_FREE_FUNC 13 + +#define SPEEX_LIB_SET_WARNING_FUNC 14 +#define SPEEX_LIB_GET_WARNING_FUNC 15 +#define SPEEX_LIB_SET_ERROR_FUNC 16 +#define SPEEX_LIB_GET_ERROR_FUNC 17 +*/ + +/** Number of defined modes in Speex */ +#define SPEEX_NB_MODES 3 + +/** modeID for the defined narrowband mode */ +#define SPEEX_MODEID_NB 0 + +/** modeID for the defined wideband mode */ +#define SPEEX_MODEID_WB 1 + +/** modeID for the defined ultra-wideband mode */ +#define SPEEX_MODEID_UWB 2 + +struct SpeexMode; + + +/* Prototypes for mode function pointers */ + +/** Encoder state initialization function */ +typedef void *(*encoder_init_func)(const struct SpeexMode *mode); + +/** Encoder state destruction function */ +typedef void (*encoder_destroy_func)(void *st); + +/** Main encoding function */ +typedef int (*encode_func)(void *state, void *in, SpeexBits *bits); + +/** Function for controlling the encoder options */ +typedef int (*encoder_ctl_func)(void *state, int request, void *ptr); + +/** Decoder state initialization function */ +typedef void *(*decoder_init_func)(const struct SpeexMode *mode); + +/** Decoder state destruction function */ +typedef void (*decoder_destroy_func)(void *st); + +/** Main decoding function */ +typedef int (*decode_func)(void *state, SpeexBits *bits, void *out); + +/** Function for controlling the decoder options */ +typedef int (*decoder_ctl_func)(void *state, int request, void *ptr); + + +/** Query function for a mode */ +typedef int (*mode_query_func)(const void *mode, int request, void *ptr); + +/** Struct defining a Speex mode */ +typedef struct SpeexMode { + /** Pointer to the low-level mode data */ + const void *mode; + + /** Pointer to the mode query function */ + mode_query_func query; + + /** The name of the mode (you should not rely on this to identify the mode)*/ + const char *modeName; + + /**ID of the mode*/ + int modeID; + + /**Version number of the bitstream (incremented every time we break + bitstream compatibility*/ + int bitstream_version; + + /** Pointer to encoder initialization function */ + encoder_init_func enc_init; + + /** Pointer to encoder destruction function */ + encoder_destroy_func enc_destroy; + + /** Pointer to frame encoding function */ + encode_func enc; + + /** Pointer to decoder initialization function */ + decoder_init_func dec_init; + + /** Pointer to decoder destruction function */ + decoder_destroy_func dec_destroy; + + /** Pointer to frame decoding function */ + decode_func dec; + + /** ioctl-like requests for encoder */ + encoder_ctl_func enc_ctl; + + /** ioctl-like requests for decoder */ + decoder_ctl_func dec_ctl; + +} SpeexMode; + +/** + * Returns a handle to a newly created Speex encoder state structure. For now, + * the "mode" argument can be &nb_mode or &wb_mode . In the future, more modes + * may be added. Note that for now if you have more than one channels to + * encode, you need one state per channel. + * + * @param mode The mode to use (either speex_nb_mode or speex_wb.mode) + * @return A newly created encoder state or NULL if state allocation fails + */ +void *speex_encoder_init(const SpeexMode *mode); + +/** Frees all resources associated to an existing Speex encoder state. + * @param state Encoder state to be destroyed */ +void speex_encoder_destroy(void *state); + +/** Uses an existing encoder state to encode one frame of speech pointed to by + "in". The encoded bit-stream is saved in "bits". + @param state Encoder state + @param in Frame that will be encoded with a +-2^15 range. This data MAY be + overwritten by the encoder and should be considered uninitialised + after the call. + @param bits Bit-stream where the data will be written + @return 0 if frame needs not be transmitted (DTX only), 1 otherwise + */ +int speex_encode(void *state, float *in, SpeexBits *bits); + +/** Uses an existing encoder state to encode one frame of speech pointed to by + "in". The encoded bit-stream is saved in "bits". + @param state Encoder state + @param in Frame that will be encoded with a +-2^15 range + @param bits Bit-stream where the data will be written + @return 0 if frame needs not be transmitted (DTX only), 1 otherwise + */ +int speex_encode_int(void *state, spx_int16_t *in, SpeexBits *bits); + +/** Used like the ioctl function to control the encoder parameters + * + * @param state Encoder state + * @param request ioctl-type request (one of the SPEEX_* macros) + * @param ptr Data exchanged to-from function + * @return 0 if no error, -1 if request in unknown, -2 for invalid parameter + */ +int speex_encoder_ctl(void *state, int request, void *ptr); + + +/** Returns a handle to a newly created decoder state structure. For now, + * the mode argument can be &nb_mode or &wb_mode . In the future, more modes + * may be added. Note that for now if you have more than one channels to + * decode, you need one state per channel. + * + * @param mode Speex mode (one of speex_nb_mode or speex_wb_mode) + * @return A newly created decoder state or NULL if state allocation fails + */ +void *speex_decoder_init(const SpeexMode *mode); + +/** Frees all resources associated to an existing decoder state. + * + * @param state State to be destroyed + */ +void speex_decoder_destroy(void *state); + +/** Uses an existing decoder state to decode one frame of speech from + * bit-stream bits. The output speech is saved written to out. + * + * @param state Decoder state + * @param bits Bit-stream from which to decode the frame (NULL if the packet was lost) + * @param out Where to write the decoded frame + * @return return status (0 for no error, -1 for end of stream, -2 corrupt stream) + */ +int speex_decode(void *state, SpeexBits *bits, float *out); + +/** Uses an existing decoder state to decode one frame of speech from + * bit-stream bits. The output speech is saved written to out. + * + * @param state Decoder state + * @param bits Bit-stream from which to decode the frame (NULL if the packet was lost) + * @param out Where to write the decoded frame + * @return return status (0 for no error, -1 for end of stream, -2 corrupt stream) + */ +int speex_decode_int(void *state, SpeexBits *bits, spx_int16_t *out); + +/** Used like the ioctl function to control the encoder parameters + * + * @param state Decoder state + * @param request ioctl-type request (one of the SPEEX_* macros) + * @param ptr Data exchanged to-from function + * @return 0 if no error, -1 if request in unknown, -2 for invalid parameter + */ +int speex_decoder_ctl(void *state, int request, void *ptr); + + +/** Query function for mode information + * + * @param mode Speex mode + * @param request ioctl-type request (one of the SPEEX_* macros) + * @param ptr Data exchanged to-from function + * @return 0 if no error, -1 if request in unknown, -2 for invalid parameter + */ +int speex_mode_query(const SpeexMode *mode, int request, void *ptr); + +/** Functions for controlling the behavior of libspeex + * @param request ioctl-type request (one of the SPEEX_LIB_* macros) + * @param ptr Data exchanged to-from function + * @return 0 if no error, -1 if request in unknown, -2 for invalid parameter + */ +int speex_lib_ctl(int request, void *ptr); + +/** Default narrowband mode */ +extern const SpeexMode speex_nb_mode; + +/** Default wideband mode */ +extern const SpeexMode speex_wb_mode; + +/** Default "ultra-wideband" mode */ +extern const SpeexMode speex_uwb_mode; + +/** List of all modes available */ +extern const SpeexMode * const speex_mode_list[SPEEX_NB_MODES]; + +/** Obtain one of the modes available */ +const SpeexMode * speex_lib_get_mode (int mode); + +#ifndef WIN32 +/* We actually override the function in the narrowband case so that we can avoid linking in the wideband stuff */ +#define speex_lib_get_mode(mode) ((mode)==SPEEX_MODEID_NB ? &speex_nb_mode : speex_lib_get_mode (mode)) +#endif + +#ifdef __cplusplus +} +#endif + +/** @}*/ +#endif diff --git a/ios/IOSDuoduo/Voice/Code/Libs/libspeex/speex/speex_bits.h b/ios/IOSDuoduo/Voice/Code/Libs/libspeex/speex/speex_bits.h new file mode 100755 index 000000000..a26fb4ce0 --- /dev/null +++ b/ios/IOSDuoduo/Voice/Code/Libs/libspeex/speex/speex_bits.h @@ -0,0 +1,174 @@ +/* Copyright (C) 2002 Jean-Marc Valin */ +/** + @file speex_bits.h + @brief Handles bit packing/unpacking +*/ +/* + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + - Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + - Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + - Neither the name of the Xiph.org Foundation nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR + CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +*/ + +#ifndef BITS_H +#define BITS_H +/** @defgroup SpeexBits SpeexBits: Bit-stream manipulations + * This is the structure that holds the bit-stream when encoding or decoding + * with Speex. It allows some manipulations as well. + * @{ + */ + +#ifdef __cplusplus +extern "C" { +#endif + +/** Bit-packing data structure representing (part of) a bit-stream. */ +typedef struct SpeexBits { + char *chars; /**< "raw" data */ + int nbBits; /**< Total number of bits stored in the stream*/ + int charPtr; /**< Position of the byte "cursor" */ + int bitPtr; /**< Position of the bit "cursor" within the current char */ + int owner; /**< Does the struct "own" the "raw" buffer (member "chars") */ + int overflow;/**< Set to one if we try to read past the valid data */ + int buf_size;/**< Allocated size for buffer */ + int reserved1; /**< Reserved for future use */ + void *reserved2; /**< Reserved for future use */ +} SpeexBits; + +/** Initializes and allocates resources for a SpeexBits struct */ +void speex_bits_init(SpeexBits *bits); + +/** Initializes SpeexBits struct using a pre-allocated buffer*/ +void speex_bits_init_buffer(SpeexBits *bits, void *buff, int buf_size); + +/** Sets the bits in a SpeexBits struct to use data from an existing buffer (for decoding without copying data) */ +void speex_bits_set_bit_buffer(SpeexBits *bits, void *buff, int buf_size); + +/** Frees all resources associated to a SpeexBits struct. Right now this does nothing since no resources are allocated, but this could change in the future.*/ +void speex_bits_destroy(SpeexBits *bits); + +/** Resets bits to initial value (just after initialization, erasing content)*/ +void speex_bits_reset(SpeexBits *bits); + +/** Rewind the bit-stream to the beginning (ready for read) without erasing the content */ +void speex_bits_rewind(SpeexBits *bits); + +/** Initializes the bit-stream from the data in an area of memory */ +void speex_bits_read_from(SpeexBits *bits, char *bytes, int len); + +/** Append bytes to the bit-stream + * + * @param bits Bit-stream to operate on + * @param bytes pointer to the bytes what will be appended + * @param len Number of bytes of append + */ +void speex_bits_read_whole_bytes(SpeexBits *bits, char *bytes, int len); + +/** Write the content of a bit-stream to an area of memory + * + * @param bits Bit-stream to operate on + * @param bytes Memory location where to write the bits + * @param max_len Maximum number of bytes to write (i.e. size of the "bytes" buffer) + * @return Number of bytes written to the "bytes" buffer +*/ +int speex_bits_write(SpeexBits *bits, char *bytes, int max_len); + +/** Like speex_bits_write, but writes only the complete bytes in the stream. Also removes the written bytes from the stream */ +int speex_bits_write_whole_bytes(SpeexBits *bits, char *bytes, int max_len); + +/** Append bits to the bit-stream + * @param bits Bit-stream to operate on + * @param data Value to append as integer + * @param nbBits number of bits to consider in "data" + */ +void speex_bits_pack(SpeexBits *bits, int data, int nbBits); + +/** Interpret the next bits in the bit-stream as a signed integer + * + * @param bits Bit-stream to operate on + * @param nbBits Number of bits to interpret + * @return A signed integer represented by the bits read + */ +int speex_bits_unpack_signed(SpeexBits *bits, int nbBits); + +/** Interpret the next bits in the bit-stream as an unsigned integer + * + * @param bits Bit-stream to operate on + * @param nbBits Number of bits to interpret + * @return An unsigned integer represented by the bits read + */ +unsigned int speex_bits_unpack_unsigned(SpeexBits *bits, int nbBits); + +/** Returns the number of bytes in the bit-stream, including the last one even if it is not "full" + * + * @param bits Bit-stream to operate on + * @return Number of bytes in the stream + */ +int speex_bits_nbytes(SpeexBits *bits); + +/** Same as speex_bits_unpack_unsigned, but without modifying the cursor position + * + * @param bits Bit-stream to operate on + * @param nbBits Number of bits to look for + * @return Value of the bits peeked, interpreted as unsigned + */ +unsigned int speex_bits_peek_unsigned(SpeexBits *bits, int nbBits); + +/** Get the value of the next bit in the stream, without modifying the + * "cursor" position + * + * @param bits Bit-stream to operate on + * @return Value of the bit peeked (one bit only) + */ +int speex_bits_peek(SpeexBits *bits); + +/** Advances the position of the "bit cursor" in the stream + * + * @param bits Bit-stream to operate on + * @param n Number of bits to advance + */ +void speex_bits_advance(SpeexBits *bits, int n); + +/** Returns the number of bits remaining to be read in a stream + * + * @param bits Bit-stream to operate on + * @return Number of bits that can still be read from the stream + */ +int speex_bits_remaining(SpeexBits *bits); + +/** Insert a terminator so that the data can be sent as a packet while auto-detecting + * the number of frames in each packet + * + * @param bits Bit-stream to operate on + */ +void speex_bits_insert_terminator(SpeexBits *bits); + +#ifdef __cplusplus +} +#endif + +/* @} */ +#endif diff --git a/ios/IOSDuoduo/Voice/Code/Libs/libspeex/speex/speex_buffer.h b/ios/IOSDuoduo/Voice/Code/Libs/libspeex/speex/speex_buffer.h new file mode 100755 index 000000000..bceae3f65 --- /dev/null +++ b/ios/IOSDuoduo/Voice/Code/Libs/libspeex/speex/speex_buffer.h @@ -0,0 +1,68 @@ +/* Copyright (C) 2007 Jean-Marc Valin + + File: speex_buffer.h + This is a very simple ring buffer implementation. It is not thread-safe + so you need to do your own locking. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are + met: + + 1. Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + 3. The name of the author may not be used to endorse or promote products + derived from this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, + INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + POSSIBILITY OF SUCH DAMAGE. +*/ + +#ifndef SPEEX_BUFFER_H +#define SPEEX_BUFFER_H + +#include "speex_types.h" + +#ifdef __cplusplus +extern "C" { +#endif + +struct SpeexBuffer_; +typedef struct SpeexBuffer_ SpeexBuffer; + +SpeexBuffer *speex_buffer_init(int size); + +void speex_buffer_destroy(SpeexBuffer *st); + +int speex_buffer_write(SpeexBuffer *st, void *data, int len); + +int speex_buffer_writezeros(SpeexBuffer *st, int len); + +int speex_buffer_read(SpeexBuffer *st, void *data, int len); + +int speex_buffer_get_available(SpeexBuffer *st); + +int speex_buffer_resize(SpeexBuffer *st, int len); + +#ifdef __cplusplus +} +#endif + +#endif + + + + diff --git a/ios/IOSDuoduo/Voice/Code/Libs/libspeex/speex/speex_callbacks.h b/ios/IOSDuoduo/Voice/Code/Libs/libspeex/speex/speex_callbacks.h new file mode 100755 index 000000000..6f450b3a3 --- /dev/null +++ b/ios/IOSDuoduo/Voice/Code/Libs/libspeex/speex/speex_callbacks.h @@ -0,0 +1,134 @@ +/* Copyright (C) 2002 Jean-Marc Valin*/ +/** + @file speex_callbacks.h + @brief Describes callback handling and in-band signalling +*/ +/* + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + - Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + - Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + - Neither the name of the Xiph.org Foundation nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR + CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +*/ + +#ifndef SPEEX_CALLBACKS_H +#define SPEEX_CALLBACKS_H +/** @defgroup SpeexCallbacks Various definitions for Speex callbacks supported by the decoder. + * @{ + */ + +#include "speex.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** Total number of callbacks */ +#define SPEEX_MAX_CALLBACKS 16 + +/* Describes all the in-band requests */ + +/*These are 1-bit requests*/ +/** Request for perceptual enhancement (1 for on, 0 for off) */ +#define SPEEX_INBAND_ENH_REQUEST 0 +/** Reserved */ +#define SPEEX_INBAND_RESERVED1 1 + +/*These are 4-bit requests*/ +/** Request for a mode change */ +#define SPEEX_INBAND_MODE_REQUEST 2 +/** Request for a low mode change */ +#define SPEEX_INBAND_LOW_MODE_REQUEST 3 +/** Request for a high mode change */ +#define SPEEX_INBAND_HIGH_MODE_REQUEST 4 +/** Request for VBR (1 on, 0 off) */ +#define SPEEX_INBAND_VBR_QUALITY_REQUEST 5 +/** Request to be sent acknowledge */ +#define SPEEX_INBAND_ACKNOWLEDGE_REQUEST 6 +/** Request for VBR (1 for on, 0 for off) */ +#define SPEEX_INBAND_VBR_REQUEST 7 + +/*These are 8-bit requests*/ +/** Send a character in-band */ +#define SPEEX_INBAND_CHAR 8 +/** Intensity stereo information */ +#define SPEEX_INBAND_STEREO 9 + +/*These are 16-bit requests*/ +/** Transmit max bit-rate allowed */ +#define SPEEX_INBAND_MAX_BITRATE 10 + +/*These are 32-bit requests*/ +/** Acknowledge packet reception */ +#define SPEEX_INBAND_ACKNOWLEDGE 12 + +/** Callback function type */ +typedef int (*speex_callback_func)(SpeexBits *bits, void *state, void *data); + +/** Callback information */ +typedef struct SpeexCallback { + int callback_id; /**< ID associated to the callback */ + speex_callback_func func; /**< Callback handler function */ + void *data; /**< Data that will be sent to the handler */ + void *reserved1; /**< Reserved for future use */ + int reserved2; /**< Reserved for future use */ +} SpeexCallback; + +/** Handle in-band request */ +int speex_inband_handler(SpeexBits *bits, SpeexCallback *callback_list, void *state); + +/** Standard handler for mode request (change mode, no questions asked) */ +int speex_std_mode_request_handler(SpeexBits *bits, void *state, void *data); + +/** Standard handler for high mode request (change high mode, no questions asked) */ +int speex_std_high_mode_request_handler(SpeexBits *bits, void *state, void *data); + +/** Standard handler for in-band characters (write to stderr) */ +int speex_std_char_handler(SpeexBits *bits, void *state, void *data); + +/** Default handler for user-defined requests: in this case, just ignore */ +int speex_default_user_handler(SpeexBits *bits, void *state, void *data); + + + +/** Standard handler for low mode request (change low mode, no questions asked) */ +int speex_std_low_mode_request_handler(SpeexBits *bits, void *state, void *data); + +/** Standard handler for VBR request (Set VBR, no questions asked) */ +int speex_std_vbr_request_handler(SpeexBits *bits, void *state, void *data); + +/** Standard handler for enhancer request (Turn enhancer on/off, no questions asked) */ +int speex_std_enh_request_handler(SpeexBits *bits, void *state, void *data); + +/** Standard handler for VBR quality request (Set VBR quality, no questions asked) */ +int speex_std_vbr_quality_request_handler(SpeexBits *bits, void *state, void *data); + + +#ifdef __cplusplus +} +#endif + +/** @} */ +#endif diff --git a/ios/IOSDuoduo/Voice/Code/Libs/libspeex/speex/speex_config_types.h b/ios/IOSDuoduo/Voice/Code/Libs/libspeex/speex/speex_config_types.h new file mode 100755 index 000000000..bd548546b --- /dev/null +++ b/ios/IOSDuoduo/Voice/Code/Libs/libspeex/speex/speex_config_types.h @@ -0,0 +1,11 @@ +#ifndef __SPEEX_TYPES_H__ +#define __SPEEX_TYPES_H__ + +/* these are filled in by configure */ +typedef short spx_int16_t; +typedef unsigned short spx_uint16_t; +typedef int spx_int32_t; +typedef unsigned int spx_uint32_t; + +#endif + diff --git a/ios/IOSDuoduo/Voice/Code/Libs/libspeex/speex/speex_config_types.h.in b/ios/IOSDuoduo/Voice/Code/Libs/libspeex/speex/speex_config_types.h.in new file mode 100755 index 000000000..3fab2ae44 --- /dev/null +++ b/ios/IOSDuoduo/Voice/Code/Libs/libspeex/speex/speex_config_types.h.in @@ -0,0 +1,11 @@ +#ifndef __SPEEX_TYPES_H__ +#define __SPEEX_TYPES_H__ + +/* these are filled in by configure */ +typedef @SIZE16@ spx_int16_t; +typedef unsigned @SIZE16@ spx_uint16_t; +typedef @SIZE32@ spx_int32_t; +typedef unsigned @SIZE32@ spx_uint32_t; + +#endif + diff --git a/ios/IOSDuoduo/Voice/Code/Libs/libspeex/speex/speex_echo.h b/ios/IOSDuoduo/Voice/Code/Libs/libspeex/speex/speex_echo.h new file mode 100755 index 000000000..d85292853 --- /dev/null +++ b/ios/IOSDuoduo/Voice/Code/Libs/libspeex/speex/speex_echo.h @@ -0,0 +1,170 @@ +/* Copyright (C) Jean-Marc Valin */ +/** + @file speex_echo.h + @brief Echo cancellation +*/ +/* + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are + met: + + 1. Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + 3. The name of the author may not be used to endorse or promote products + derived from this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, + INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + POSSIBILITY OF SUCH DAMAGE. +*/ + +#ifndef SPEEX_ECHO_H +#define SPEEX_ECHO_H +/** @defgroup SpeexEchoState SpeexEchoState: Acoustic echo canceller + * This is the acoustic echo canceller module. + * @{ + */ +#include "speex_types.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** Obtain frame size used by the AEC */ +#define SPEEX_ECHO_GET_FRAME_SIZE 3 + +/** Set sampling rate */ +#define SPEEX_ECHO_SET_SAMPLING_RATE 24 +/** Get sampling rate */ +#define SPEEX_ECHO_GET_SAMPLING_RATE 25 + +/* Can't set window sizes */ +/** Get size of impulse response (int32) */ +#define SPEEX_ECHO_GET_IMPULSE_RESPONSE_SIZE 27 + +/* Can't set window content */ +/** Get impulse response (int32[]) */ +#define SPEEX_ECHO_GET_IMPULSE_RESPONSE 29 + +/** Internal echo canceller state. Should never be accessed directly. */ +struct SpeexEchoState_; + +/** @class SpeexEchoState + * This holds the state of the echo canceller. You need one per channel. +*/ + +/** Internal echo canceller state. Should never be accessed directly. */ +typedef struct SpeexEchoState_ SpeexEchoState; + +/** Creates a new echo canceller state + * @param frame_size Number of samples to process at one time (should correspond to 10-20 ms) + * @param filter_length Number of samples of echo to cancel (should generally correspond to 100-500 ms) + * @return Newly-created echo canceller state + */ +SpeexEchoState *speex_echo_state_init(int frame_size, int filter_length); + +/** Creates a new multi-channel echo canceller state + * @param frame_size Number of samples to process at one time (should correspond to 10-20 ms) + * @param filter_length Number of samples of echo to cancel (should generally correspond to 100-500 ms) + * @param nb_mic Number of microphone channels + * @param nb_speakers Number of speaker channels + * @return Newly-created echo canceller state + */ +SpeexEchoState *speex_echo_state_init_mc(int frame_size, int filter_length, int nb_mic, int nb_speakers); + +/** Destroys an echo canceller state + * @param st Echo canceller state +*/ +void speex_echo_state_destroy(SpeexEchoState *st); + +/** Performs echo cancellation a frame, based on the audio sent to the speaker (no delay is added + * to playback in this form) + * + * @param st Echo canceller state + * @param rec Signal from the microphone (near end + far end echo) + * @param play Signal played to the speaker (received from far end) + * @param out Returns near-end signal with echo removed + */ +void speex_echo_cancellation(SpeexEchoState *st, const spx_int16_t *rec, const spx_int16_t *play, spx_int16_t *out); + +/** Performs echo cancellation a frame (deprecated) */ +void speex_echo_cancel(SpeexEchoState *st, const spx_int16_t *rec, const spx_int16_t *play, spx_int16_t *out, spx_int32_t *Yout); + +/** Perform echo cancellation using internal playback buffer, which is delayed by two frames + * to account for the delay introduced by most soundcards (but it could be off!) + * @param st Echo canceller state + * @param rec Signal from the microphone (near end + far end echo) + * @param out Returns near-end signal with echo removed +*/ +void speex_echo_capture(SpeexEchoState *st, const spx_int16_t *rec, spx_int16_t *out); + +/** Let the echo canceller know that a frame was just queued to the soundcard + * @param st Echo canceller state + * @param play Signal played to the speaker (received from far end) +*/ +void speex_echo_playback(SpeexEchoState *st, const spx_int16_t *play); + +/** Reset the echo canceller to its original state + * @param st Echo canceller state + */ +void speex_echo_state_reset(SpeexEchoState *st); + +/** Used like the ioctl function to control the echo canceller parameters + * + * @param st Echo canceller state + * @param request ioctl-type request (one of the SPEEX_ECHO_* macros) + * @param ptr Data exchanged to-from function + * @return 0 if no error, -1 if request in unknown + */ +int speex_echo_ctl(SpeexEchoState *st, int request, void *ptr); + + + +struct SpeexDecorrState_; + +typedef struct SpeexDecorrState_ SpeexDecorrState; + + +/** Create a state for the channel decorrelation algorithm + This is useful for multi-channel echo cancellation only + * @param rate Sampling rate + * @param channels Number of channels (it's a bit pointless if you don't have at least 2) + * @param frame_size Size of the frame to process at ones (counting samples *per* channel) +*/ +SpeexDecorrState *speex_decorrelate_new(int rate, int channels, int frame_size); + +/** Remove correlation between the channels by modifying the phase and possibly + adding noise in a way that is not (or little) perceptible. + * @param st Decorrelator state + * @param in Input audio in interleaved format + * @param out Result of the decorrelation (out *may* alias in) + * @param strength How much alteration of the audio to apply from 0 to 100. +*/ +void speex_decorrelate(SpeexDecorrState *st, const spx_int16_t *in, spx_int16_t *out, int strength); + +/** Destroy a Decorrelation state + * @param st State to destroy +*/ +void speex_decorrelate_destroy(SpeexDecorrState *st); + + +#ifdef __cplusplus +} +#endif + + +/** @}*/ +#endif diff --git a/ios/IOSDuoduo/Voice/Code/Libs/libspeex/speex/speex_header.h b/ios/IOSDuoduo/Voice/Code/Libs/libspeex/speex/speex_header.h new file mode 100755 index 000000000..f8e36db48 --- /dev/null +++ b/ios/IOSDuoduo/Voice/Code/Libs/libspeex/speex/speex_header.h @@ -0,0 +1,94 @@ +/* Copyright (C) 2002 Jean-Marc Valin */ +/** + @file speex_header.h + @brief Describes the Speex header +*/ +/* + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + - Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + - Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + - Neither the name of the Xiph.org Foundation nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR + CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +*/ + + +#ifndef SPEEX_HEADER_H +#define SPEEX_HEADER_H +/** @defgroup SpeexHeader SpeexHeader: Makes it easy to write/parse an Ogg/Speex header + * This is the Speex header for the Ogg encapsulation. You don't need that if you just use RTP. + * @{ + */ + +#include "speex_types.h" + +#ifdef __cplusplus +extern "C" { +#endif + +struct SpeexMode; + +/** Length of the Speex header identifier */ +#define SPEEX_HEADER_STRING_LENGTH 8 + +/** Maximum number of characters for encoding the Speex version number in the header */ +#define SPEEX_HEADER_VERSION_LENGTH 20 + +/** Speex header info for file-based formats */ +typedef struct SpeexHeader { + char speex_string[SPEEX_HEADER_STRING_LENGTH]; /**< Identifies a Speex bit-stream, always set to "Speex " */ + char speex_version[SPEEX_HEADER_VERSION_LENGTH]; /**< Speex version */ + spx_int32_t speex_version_id; /**< Version for Speex (for checking compatibility) */ + spx_int32_t header_size; /**< Total size of the header ( sizeof(SpeexHeader) ) */ + spx_int32_t rate; /**< Sampling rate used */ + spx_int32_t mode; /**< Mode used (0 for narrowband, 1 for wideband) */ + spx_int32_t mode_bitstream_version; /**< Version ID of the bit-stream */ + spx_int32_t nb_channels; /**< Number of channels encoded */ + spx_int32_t bitrate; /**< Bit-rate used */ + spx_int32_t frame_size; /**< Size of frames */ + spx_int32_t vbr; /**< 1 for a VBR encoding, 0 otherwise */ + spx_int32_t frames_per_packet; /**< Number of frames stored per Ogg packet */ + spx_int32_t extra_headers; /**< Number of additional headers after the comments */ + spx_int32_t reserved1; /**< Reserved for future use, must be zero */ + spx_int32_t reserved2; /**< Reserved for future use, must be zero */ +} SpeexHeader; + +/** Initializes a SpeexHeader using basic information */ +void speex_init_header(SpeexHeader *header, int rate, int nb_channels, const struct SpeexMode *m); + +/** Creates the header packet from the header itself (mostly involves endianness conversion) */ +char *speex_header_to_packet(SpeexHeader *header, int *size); + +/** Creates a SpeexHeader from a packet */ +SpeexHeader *speex_packet_to_header(char *packet, int size); + +/** Frees the memory allocated by either speex_header_to_packet() or speex_packet_to_header() */ +void speex_header_free(void *ptr); + +#ifdef __cplusplus +} +#endif + +/** @} */ +#endif diff --git a/ios/IOSDuoduo/Voice/Code/Libs/libspeex/speex/speex_jitter.h b/ios/IOSDuoduo/Voice/Code/Libs/libspeex/speex/speex_jitter.h new file mode 100755 index 000000000..03bac1563 --- /dev/null +++ b/ios/IOSDuoduo/Voice/Code/Libs/libspeex/speex/speex_jitter.h @@ -0,0 +1,197 @@ +/* Copyright (C) 2002 Jean-Marc Valin */ +/** + @file speex_jitter.h + @brief Adaptive jitter buffer for Speex +*/ +/* + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + - Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + - Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + - Neither the name of the Xiph.org Foundation nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR + CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +*/ + +#ifndef SPEEX_JITTER_H +#define SPEEX_JITTER_H +/** @defgroup JitterBuffer JitterBuffer: Adaptive jitter buffer + * This is the jitter buffer that reorders UDP/RTP packets and adjusts the buffer size + * to maintain good quality and low latency. + * @{ + */ + +#include "speex_types.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** Generic adaptive jitter buffer state */ +struct JitterBuffer_; + +/** Generic adaptive jitter buffer state */ +typedef struct JitterBuffer_ JitterBuffer; + +/** Definition of an incoming packet */ +typedef struct _JitterBufferPacket JitterBufferPacket; + +/** Definition of an incoming packet */ +struct _JitterBufferPacket { + char *data; /**< Data bytes contained in the packet */ + spx_uint32_t len; /**< Length of the packet in bytes */ + spx_uint32_t timestamp; /**< Timestamp for the packet */ + spx_uint32_t span; /**< Time covered by the packet (same units as timestamp) */ + spx_uint16_t sequence; /**< RTP Sequence number if available (0 otherwise) */ + spx_uint32_t user_data; /**< Put whatever data you like here (it's ignored by the jitter buffer) */ +}; + +/** Packet has been retrieved */ +#define JITTER_BUFFER_OK 0 +/** Packet is lost or is late */ +#define JITTER_BUFFER_MISSING 1 +/** A "fake" packet is meant to be inserted here to increase buffering */ +#define JITTER_BUFFER_INSERTION 2 +/** There was an error in the jitter buffer */ +#define JITTER_BUFFER_INTERNAL_ERROR -1 +/** Invalid argument */ +#define JITTER_BUFFER_BAD_ARGUMENT -2 + + +/** Set minimum amount of extra buffering required (margin) */ +#define JITTER_BUFFER_SET_MARGIN 0 +/** Get minimum amount of extra buffering required (margin) */ +#define JITTER_BUFFER_GET_MARGIN 1 +/* JITTER_BUFFER_SET_AVAILABLE_COUNT wouldn't make sense */ + +/** Get the amount of available packets currently buffered */ +#define JITTER_BUFFER_GET_AVAILABLE_COUNT 3 +/** Included because of an early misspelling (will remove in next release) */ +#define JITTER_BUFFER_GET_AVALIABLE_COUNT 3 + +/** Assign a function to destroy unused packet. When setting that, the jitter + buffer no longer copies packet data. */ +#define JITTER_BUFFER_SET_DESTROY_CALLBACK 4 +/** */ +#define JITTER_BUFFER_GET_DESTROY_CALLBACK 5 + +/** Tell the jitter buffer to only adjust the delay in multiples of the step parameter provided */ +#define JITTER_BUFFER_SET_DELAY_STEP 6 +/** */ +#define JITTER_BUFFER_GET_DELAY_STEP 7 + +/** Tell the jitter buffer to only do concealment in multiples of the size parameter provided */ +#define JITTER_BUFFER_SET_CONCEALMENT_SIZE 8 +#define JITTER_BUFFER_GET_CONCEALMENT_SIZE 9 + +/** Absolute max amount of loss that can be tolerated regardless of the delay. Typical loss + should be half of that or less. */ +#define JITTER_BUFFER_SET_MAX_LATE_RATE 10 +#define JITTER_BUFFER_GET_MAX_LATE_RATE 11 + +/** Equivalent cost of one percent late packet in timestamp units */ +#define JITTER_BUFFER_SET_LATE_COST 12 +#define JITTER_BUFFER_GET_LATE_COST 13 + + +/** Initialises jitter buffer + * + * @param step_size Starting value for the size of concleanment packets and delay + adjustment steps. Can be changed at any time using JITTER_BUFFER_SET_DELAY_STEP + and JITTER_BUFFER_GET_CONCEALMENT_SIZE. + * @return Newly created jitter buffer state + */ +JitterBuffer *jitter_buffer_init(int step_size); + +/** Restores jitter buffer to its original state + * + * @param jitter Jitter buffer state + */ +void jitter_buffer_reset(JitterBuffer *jitter); + +/** Destroys jitter buffer + * + * @param jitter Jitter buffer state + */ +void jitter_buffer_destroy(JitterBuffer *jitter); + +/** Put one packet into the jitter buffer + * + * @param jitter Jitter buffer state + * @param packet Incoming packet +*/ +void jitter_buffer_put(JitterBuffer *jitter, const JitterBufferPacket *packet); + +/** Get one packet from the jitter buffer + * + * @param jitter Jitter buffer state + * @param packet Returned packet + * @param desired_span Number of samples (or units) we wish to get from the buffer (no guarantee) + * @param current_timestamp Timestamp for the returned packet +*/ +int jitter_buffer_get(JitterBuffer *jitter, JitterBufferPacket *packet, spx_int32_t desired_span, spx_int32_t *start_offset); + +/** Used right after jitter_buffer_get() to obtain another packet that would have the same timestamp. + * This is mainly useful for media where a single "frame" can be split into several packets. + * + * @param jitter Jitter buffer state + * @param packet Returned packet + */ +int jitter_buffer_get_another(JitterBuffer *jitter, JitterBufferPacket *packet); + +/** Get pointer timestamp of jitter buffer + * + * @param jitter Jitter buffer state +*/ +int jitter_buffer_get_pointer_timestamp(JitterBuffer *jitter); + +/** Advance by one tick + * + * @param jitter Jitter buffer state +*/ +void jitter_buffer_tick(JitterBuffer *jitter); + +/** Telling the jitter buffer about the remaining data in the application buffer + * @param jitter Jitter buffer state + * @param rem Amount of data buffered by the application (timestamp units) + */ +void jitter_buffer_remaining_span(JitterBuffer *jitter, spx_uint32_t rem); + +/** Used like the ioctl function to control the jitter buffer parameters + * + * @param jitter Jitter buffer state + * @param request ioctl-type request (one of the JITTER_BUFFER_* macros) + * @param ptr Data exchanged to-from function + * @return 0 if no error, -1 if request in unknown +*/ +int jitter_buffer_ctl(JitterBuffer *jitter, int request, void *ptr); + +int jitter_buffer_update_delay(JitterBuffer *jitter, JitterBufferPacket *packet, spx_int32_t *start_offset); + +/* @} */ + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/ios/IOSDuoduo/Voice/Code/Libs/libspeex/speex/speex_preprocess.h b/ios/IOSDuoduo/Voice/Code/Libs/libspeex/speex/speex_preprocess.h new file mode 100755 index 000000000..2762d10e5 --- /dev/null +++ b/ios/IOSDuoduo/Voice/Code/Libs/libspeex/speex/speex_preprocess.h @@ -0,0 +1,219 @@ +/* Copyright (C) 2003 Epic Games + Written by Jean-Marc Valin */ +/** + * @file speex_preprocess.h + * @brief Speex preprocessor. The preprocess can do noise suppression, + * residual echo suppression (after using the echo canceller), automatic + * gain control (AGC) and voice activity detection (VAD). +*/ +/* + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are + met: + + 1. Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + 3. The name of the author may not be used to endorse or promote products + derived from this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, + INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + POSSIBILITY OF SUCH DAMAGE. +*/ + +#ifndef SPEEX_PREPROCESS_H +#define SPEEX_PREPROCESS_H +/** @defgroup SpeexPreprocessState SpeexPreprocessState: The Speex preprocessor + * This is the Speex preprocessor. The preprocess can do noise suppression, + * residual echo suppression (after using the echo canceller), automatic + * gain control (AGC) and voice activity detection (VAD). + * @{ + */ + +#include "speex_types.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** State of the preprocessor (one per channel). Should never be accessed directly. */ +struct SpeexPreprocessState_; + +/** State of the preprocessor (one per channel). Should never be accessed directly. */ +typedef struct SpeexPreprocessState_ SpeexPreprocessState; + + +/** Creates a new preprocessing state. You MUST create one state per channel processed. + * @param frame_size Number of samples to process at one time (should correspond to 10-20 ms). Must be + * the same value as that used for the echo canceller for residual echo cancellation to work. + * @param sampling_rate Sampling rate used for the input. + * @return Newly created preprocessor state +*/ +SpeexPreprocessState *speex_preprocess_state_init(int frame_size, int sampling_rate); + +/** Destroys a preprocessor state + * @param st Preprocessor state to destroy +*/ +void speex_preprocess_state_destroy(SpeexPreprocessState *st); + +/** Preprocess a frame + * @param st Preprocessor state + * @param x Audio sample vector (in and out). Must be same size as specified in speex_preprocess_state_init(). + * @return Bool value for voice activity (1 for speech, 0 for noise/silence), ONLY if VAD turned on. +*/ +int speex_preprocess_run(SpeexPreprocessState *st, spx_int16_t *x); + +/** Preprocess a frame (deprecated, use speex_preprocess_run() instead)*/ +int speex_preprocess(SpeexPreprocessState *st, spx_int16_t *x, spx_int32_t *echo); + +/** Update preprocessor state, but do not compute the output + * @param st Preprocessor state + * @param x Audio sample vector (in only). Must be same size as specified in speex_preprocess_state_init(). +*/ +void speex_preprocess_estimate_update(SpeexPreprocessState *st, spx_int16_t *x); + +/** Used like the ioctl function to control the preprocessor parameters + * @param st Preprocessor state + * @param request ioctl-type request (one of the SPEEX_PREPROCESS_* macros) + * @param ptr Data exchanged to-from function + * @return 0 if no error, -1 if request in unknown +*/ +int speex_preprocess_ctl(SpeexPreprocessState *st, int request, void *ptr); + + + +/** Set preprocessor denoiser state */ +#define SPEEX_PREPROCESS_SET_DENOISE 0 +/** Get preprocessor denoiser state */ +#define SPEEX_PREPROCESS_GET_DENOISE 1 + +/** Set preprocessor Automatic Gain Control state */ +#define SPEEX_PREPROCESS_SET_AGC 2 +/** Get preprocessor Automatic Gain Control state */ +#define SPEEX_PREPROCESS_GET_AGC 3 + +/** Set preprocessor Voice Activity Detection state */ +#define SPEEX_PREPROCESS_SET_VAD 4 +/** Get preprocessor Voice Activity Detection state */ +#define SPEEX_PREPROCESS_GET_VAD 5 + +/** Set preprocessor Automatic Gain Control level (float) */ +#define SPEEX_PREPROCESS_SET_AGC_LEVEL 6 +/** Get preprocessor Automatic Gain Control level (float) */ +#define SPEEX_PREPROCESS_GET_AGC_LEVEL 7 + +/** Set preprocessor dereverb state */ +#define SPEEX_PREPROCESS_SET_DEREVERB 8 +/** Get preprocessor dereverb state */ +#define SPEEX_PREPROCESS_GET_DEREVERB 9 + +/** Set preprocessor dereverb level */ +#define SPEEX_PREPROCESS_SET_DEREVERB_LEVEL 10 +/** Get preprocessor dereverb level */ +#define SPEEX_PREPROCESS_GET_DEREVERB_LEVEL 11 + +/** Set preprocessor dereverb decay */ +#define SPEEX_PREPROCESS_SET_DEREVERB_DECAY 12 +/** Get preprocessor dereverb decay */ +#define SPEEX_PREPROCESS_GET_DEREVERB_DECAY 13 + +/** Set probability required for the VAD to go from silence to voice */ +#define SPEEX_PREPROCESS_SET_PROB_START 14 +/** Get probability required for the VAD to go from silence to voice */ +#define SPEEX_PREPROCESS_GET_PROB_START 15 + +/** Set probability required for the VAD to stay in the voice state (integer percent) */ +#define SPEEX_PREPROCESS_SET_PROB_CONTINUE 16 +/** Get probability required for the VAD to stay in the voice state (integer percent) */ +#define SPEEX_PREPROCESS_GET_PROB_CONTINUE 17 + +/** Set maximum attenuation of the noise in dB (negative number) */ +#define SPEEX_PREPROCESS_SET_NOISE_SUPPRESS 18 +/** Get maximum attenuation of the noise in dB (negative number) */ +#define SPEEX_PREPROCESS_GET_NOISE_SUPPRESS 19 + +/** Set maximum attenuation of the residual echo in dB (negative number) */ +#define SPEEX_PREPROCESS_SET_ECHO_SUPPRESS 20 +/** Get maximum attenuation of the residual echo in dB (negative number) */ +#define SPEEX_PREPROCESS_GET_ECHO_SUPPRESS 21 + +/** Set maximum attenuation of the residual echo in dB when near end is active (negative number) */ +#define SPEEX_PREPROCESS_SET_ECHO_SUPPRESS_ACTIVE 22 +/** Get maximum attenuation of the residual echo in dB when near end is active (negative number) */ +#define SPEEX_PREPROCESS_GET_ECHO_SUPPRESS_ACTIVE 23 + +/** Set the corresponding echo canceller state so that residual echo suppression can be performed (NULL for no residual echo suppression) */ +#define SPEEX_PREPROCESS_SET_ECHO_STATE 24 +/** Get the corresponding echo canceller state */ +#define SPEEX_PREPROCESS_GET_ECHO_STATE 25 + +/** Set maximal gain increase in dB/second (int32) */ +#define SPEEX_PREPROCESS_SET_AGC_INCREMENT 26 + +/** Get maximal gain increase in dB/second (int32) */ +#define SPEEX_PREPROCESS_GET_AGC_INCREMENT 27 + +/** Set maximal gain decrease in dB/second (int32) */ +#define SPEEX_PREPROCESS_SET_AGC_DECREMENT 28 + +/** Get maximal gain decrease in dB/second (int32) */ +#define SPEEX_PREPROCESS_GET_AGC_DECREMENT 29 + +/** Set maximal gain in dB (int32) */ +#define SPEEX_PREPROCESS_SET_AGC_MAX_GAIN 30 + +/** Get maximal gain in dB (int32) */ +#define SPEEX_PREPROCESS_GET_AGC_MAX_GAIN 31 + +/* Can't set loudness */ +/** Get loudness */ +#define SPEEX_PREPROCESS_GET_AGC_LOUDNESS 33 + +/* Can't set gain */ +/** Get current gain (int32 percent) */ +#define SPEEX_PREPROCESS_GET_AGC_GAIN 35 + +/* Can't set spectrum size */ +/** Get spectrum size for power spectrum (int32) */ +#define SPEEX_PREPROCESS_GET_PSD_SIZE 37 + +/* Can't set power spectrum */ +/** Get power spectrum (int32[] of squared values) */ +#define SPEEX_PREPROCESS_GET_PSD 39 + +/* Can't set noise size */ +/** Get spectrum size for noise estimate (int32) */ +#define SPEEX_PREPROCESS_GET_NOISE_PSD_SIZE 41 + +/* Can't set noise estimate */ +/** Get noise estimate (int32[] of squared values) */ +#define SPEEX_PREPROCESS_GET_NOISE_PSD 43 + +/* Can't set speech probability */ +/** Get speech probability in last frame (int32). */ +#define SPEEX_PREPROCESS_GET_PROB 45 + +/** Set preprocessor Automatic Gain Control level (int32) */ +#define SPEEX_PREPROCESS_SET_AGC_TARGET 46 +/** Get preprocessor Automatic Gain Control level (int32) */ +#define SPEEX_PREPROCESS_GET_AGC_TARGET 47 + +#ifdef __cplusplus +} +#endif + +/** @}*/ +#endif diff --git a/ios/IOSDuoduo/Voice/Code/Libs/libspeex/speex/speex_resampler.h b/ios/IOSDuoduo/Voice/Code/Libs/libspeex/speex/speex_resampler.h new file mode 100755 index 000000000..6bb9a2e18 --- /dev/null +++ b/ios/IOSDuoduo/Voice/Code/Libs/libspeex/speex/speex_resampler.h @@ -0,0 +1,340 @@ +/* Copyright (C) 2007 Jean-Marc Valin + + File: speex_resampler.h + Resampling code + + The design goals of this code are: + - Very fast algorithm + - Low memory requirement + - Good *perceptual* quality (and not best SNR) + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are + met: + + 1. Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + 3. The name of the author may not be used to endorse or promote products + derived from this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, + INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + POSSIBILITY OF SUCH DAMAGE. +*/ + + +#ifndef SPEEX_RESAMPLER_H +#define SPEEX_RESAMPLER_H + +#ifdef OUTSIDE_SPEEX + +/********* WARNING: MENTAL SANITY ENDS HERE *************/ + +/* If the resampler is defined outside of Speex, we change the symbol names so that + there won't be any clash if linking with Speex later on. */ + +/* #define RANDOM_PREFIX your software name here */ +#ifndef RANDOM_PREFIX +#error "Please define RANDOM_PREFIX (above) to something specific to your project to prevent symbol name clashes" +#endif + +#define CAT_PREFIX2(a,b) a ## b +#define CAT_PREFIX(a,b) CAT_PREFIX2(a, b) + +#define speex_resampler_init CAT_PREFIX(RANDOM_PREFIX,_resampler_init) +#define speex_resampler_init_frac CAT_PREFIX(RANDOM_PREFIX,_resampler_init_frac) +#define speex_resampler_destroy CAT_PREFIX(RANDOM_PREFIX,_resampler_destroy) +#define speex_resampler_process_float CAT_PREFIX(RANDOM_PREFIX,_resampler_process_float) +#define speex_resampler_process_int CAT_PREFIX(RANDOM_PREFIX,_resampler_process_int) +#define speex_resampler_process_interleaved_float CAT_PREFIX(RANDOM_PREFIX,_resampler_process_interleaved_float) +#define speex_resampler_process_interleaved_int CAT_PREFIX(RANDOM_PREFIX,_resampler_process_interleaved_int) +#define speex_resampler_set_rate CAT_PREFIX(RANDOM_PREFIX,_resampler_set_rate) +#define speex_resampler_get_rate CAT_PREFIX(RANDOM_PREFIX,_resampler_get_rate) +#define speex_resampler_set_rate_frac CAT_PREFIX(RANDOM_PREFIX,_resampler_set_rate_frac) +#define speex_resampler_get_ratio CAT_PREFIX(RANDOM_PREFIX,_resampler_get_ratio) +#define speex_resampler_set_quality CAT_PREFIX(RANDOM_PREFIX,_resampler_set_quality) +#define speex_resampler_get_quality CAT_PREFIX(RANDOM_PREFIX,_resampler_get_quality) +#define speex_resampler_set_input_stride CAT_PREFIX(RANDOM_PREFIX,_resampler_set_input_stride) +#define speex_resampler_get_input_stride CAT_PREFIX(RANDOM_PREFIX,_resampler_get_input_stride) +#define speex_resampler_set_output_stride CAT_PREFIX(RANDOM_PREFIX,_resampler_set_output_stride) +#define speex_resampler_get_output_stride CAT_PREFIX(RANDOM_PREFIX,_resampler_get_output_stride) +#define speex_resampler_get_input_latency CAT_PREFIX(RANDOM_PREFIX,_resampler_get_input_latency) +#define speex_resampler_get_output_latency CAT_PREFIX(RANDOM_PREFIX,_resampler_get_output_latency) +#define speex_resampler_skip_zeros CAT_PREFIX(RANDOM_PREFIX,_resampler_skip_zeros) +#define speex_resampler_reset_mem CAT_PREFIX(RANDOM_PREFIX,_resampler_reset_mem) +#define speex_resampler_strerror CAT_PREFIX(RANDOM_PREFIX,_resampler_strerror) + +#define spx_int16_t short +#define spx_int32_t int +#define spx_uint16_t unsigned short +#define spx_uint32_t unsigned int + +#else /* OUTSIDE_SPEEX */ + +#include "speex_types.h" + +#endif /* OUTSIDE_SPEEX */ + +#ifdef __cplusplus +extern "C" { +#endif + +#define SPEEX_RESAMPLER_QUALITY_MAX 10 +#define SPEEX_RESAMPLER_QUALITY_MIN 0 +#define SPEEX_RESAMPLER_QUALITY_DEFAULT 4 +#define SPEEX_RESAMPLER_QUALITY_VOIP 3 +#define SPEEX_RESAMPLER_QUALITY_DESKTOP 5 + +enum { + RESAMPLER_ERR_SUCCESS = 0, + RESAMPLER_ERR_ALLOC_FAILED = 1, + RESAMPLER_ERR_BAD_STATE = 2, + RESAMPLER_ERR_INVALID_ARG = 3, + RESAMPLER_ERR_PTR_OVERLAP = 4, + + RESAMPLER_ERR_MAX_ERROR +}; + +struct SpeexResamplerState_; +typedef struct SpeexResamplerState_ SpeexResamplerState; + +/** Create a new resampler with integer input and output rates. + * @param nb_channels Number of channels to be processed + * @param in_rate Input sampling rate (integer number of Hz). + * @param out_rate Output sampling rate (integer number of Hz). + * @param quality Resampling quality between 0 and 10, where 0 has poor quality + * and 10 has very high quality. + * @return Newly created resampler state + * @retval NULL Error: not enough memory + */ +SpeexResamplerState *speex_resampler_init(spx_uint32_t nb_channels, + spx_uint32_t in_rate, + spx_uint32_t out_rate, + int quality, + int *err); + +/** Create a new resampler with fractional input/output rates. The sampling + * rate ratio is an arbitrary rational number with both the numerator and + * denominator being 32-bit integers. + * @param nb_channels Number of channels to be processed + * @param ratio_num Numerator of the sampling rate ratio + * @param ratio_den Denominator of the sampling rate ratio + * @param in_rate Input sampling rate rounded to the nearest integer (in Hz). + * @param out_rate Output sampling rate rounded to the nearest integer (in Hz). + * @param quality Resampling quality between 0 and 10, where 0 has poor quality + * and 10 has very high quality. + * @return Newly created resampler state + * @retval NULL Error: not enough memory + */ +SpeexResamplerState *speex_resampler_init_frac(spx_uint32_t nb_channels, + spx_uint32_t ratio_num, + spx_uint32_t ratio_den, + spx_uint32_t in_rate, + spx_uint32_t out_rate, + int quality, + int *err); + +/** Destroy a resampler state. + * @param st Resampler state + */ +void speex_resampler_destroy(SpeexResamplerState *st); + +/** Resample a float array. The input and output buffers must *not* overlap. + * @param st Resampler state + * @param channel_index Index of the channel to process for the multi-channel + * base (0 otherwise) + * @param in Input buffer + * @param in_len Number of input samples in the input buffer. Returns the + * number of samples processed + * @param out Output buffer + * @param out_len Size of the output buffer. Returns the number of samples written + */ +int speex_resampler_process_float(SpeexResamplerState *st, + spx_uint32_t channel_index, + const float *in, + spx_uint32_t *in_len, + float *out, + spx_uint32_t *out_len); + +/** Resample an int array. The input and output buffers must *not* overlap. + * @param st Resampler state + * @param channel_index Index of the channel to process for the multi-channel + * base (0 otherwise) + * @param in Input buffer + * @param in_len Number of input samples in the input buffer. Returns the number + * of samples processed + * @param out Output buffer + * @param out_len Size of the output buffer. Returns the number of samples written + */ +int speex_resampler_process_int(SpeexResamplerState *st, + spx_uint32_t channel_index, + const spx_int16_t *in, + spx_uint32_t *in_len, + spx_int16_t *out, + spx_uint32_t *out_len); + +/** Resample an interleaved float array. The input and output buffers must *not* overlap. + * @param st Resampler state + * @param in Input buffer + * @param in_len Number of input samples in the input buffer. Returns the number + * of samples processed. This is all per-channel. + * @param out Output buffer + * @param out_len Size of the output buffer. Returns the number of samples written. + * This is all per-channel. + */ +int speex_resampler_process_interleaved_float(SpeexResamplerState *st, + const float *in, + spx_uint32_t *in_len, + float *out, + spx_uint32_t *out_len); + +/** Resample an interleaved int array. The input and output buffers must *not* overlap. + * @param st Resampler state + * @param in Input buffer + * @param in_len Number of input samples in the input buffer. Returns the number + * of samples processed. This is all per-channel. + * @param out Output buffer + * @param out_len Size of the output buffer. Returns the number of samples written. + * This is all per-channel. + */ +int speex_resampler_process_interleaved_int(SpeexResamplerState *st, + const spx_int16_t *in, + spx_uint32_t *in_len, + spx_int16_t *out, + spx_uint32_t *out_len); + +/** Set (change) the input/output sampling rates (integer value). + * @param st Resampler state + * @param in_rate Input sampling rate (integer number of Hz). + * @param out_rate Output sampling rate (integer number of Hz). + */ +int speex_resampler_set_rate(SpeexResamplerState *st, + spx_uint32_t in_rate, + spx_uint32_t out_rate); + +/** Get the current input/output sampling rates (integer value). + * @param st Resampler state + * @param in_rate Input sampling rate (integer number of Hz) copied. + * @param out_rate Output sampling rate (integer number of Hz) copied. + */ +void speex_resampler_get_rate(SpeexResamplerState *st, + spx_uint32_t *in_rate, + spx_uint32_t *out_rate); + +/** Set (change) the input/output sampling rates and resampling ratio + * (fractional values in Hz supported). + * @param st Resampler state + * @param ratio_num Numerator of the sampling rate ratio + * @param ratio_den Denominator of the sampling rate ratio + * @param in_rate Input sampling rate rounded to the nearest integer (in Hz). + * @param out_rate Output sampling rate rounded to the nearest integer (in Hz). + */ +int speex_resampler_set_rate_frac(SpeexResamplerState *st, + spx_uint32_t ratio_num, + spx_uint32_t ratio_den, + spx_uint32_t in_rate, + spx_uint32_t out_rate); + +/** Get the current resampling ratio. This will be reduced to the least + * common denominator. + * @param st Resampler state + * @param ratio_num Numerator of the sampling rate ratio copied + * @param ratio_den Denominator of the sampling rate ratio copied + */ +void speex_resampler_get_ratio(SpeexResamplerState *st, + spx_uint32_t *ratio_num, + spx_uint32_t *ratio_den); + +/** Set (change) the conversion quality. + * @param st Resampler state + * @param quality Resampling quality between 0 and 10, where 0 has poor + * quality and 10 has very high quality. + */ +int speex_resampler_set_quality(SpeexResamplerState *st, + int quality); + +/** Get the conversion quality. + * @param st Resampler state + * @param quality Resampling quality between 0 and 10, where 0 has poor + * quality and 10 has very high quality. + */ +void speex_resampler_get_quality(SpeexResamplerState *st, + int *quality); + +/** Set (change) the input stride. + * @param st Resampler state + * @param stride Input stride + */ +void speex_resampler_set_input_stride(SpeexResamplerState *st, + spx_uint32_t stride); + +/** Get the input stride. + * @param st Resampler state + * @param stride Input stride copied + */ +void speex_resampler_get_input_stride(SpeexResamplerState *st, + spx_uint32_t *stride); + +/** Set (change) the output stride. + * @param st Resampler state + * @param stride Output stride + */ +void speex_resampler_set_output_stride(SpeexResamplerState *st, + spx_uint32_t stride); + +/** Get the output stride. + * @param st Resampler state copied + * @param stride Output stride + */ +void speex_resampler_get_output_stride(SpeexResamplerState *st, + spx_uint32_t *stride); + +/** Get the latency in input samples introduced by the resampler. + * @param st Resampler state + */ +int speex_resampler_get_input_latency(SpeexResamplerState *st); + +/** Get the latency in output samples introduced by the resampler. + * @param st Resampler state + */ +int speex_resampler_get_output_latency(SpeexResamplerState *st); + +/** Make sure that the first samples to go out of the resamplers don't have + * leading zeros. This is only useful before starting to use a newly created + * resampler. It is recommended to use that when resampling an audio file, as + * it will generate a file with the same length. For real-time processing, + * it is probably easier not to use this call (so that the output duration + * is the same for the first frame). + * @param st Resampler state + */ +int speex_resampler_skip_zeros(SpeexResamplerState *st); + +/** Reset a resampler so a new (unrelated) stream can be processed. + * @param st Resampler state + */ +int speex_resampler_reset_mem(SpeexResamplerState *st); + +/** Returns the English meaning for an error code + * @param err Error code + * @return English string + */ +const char *speex_resampler_strerror(int err); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/ios/IOSDuoduo/Voice/Code/Libs/libspeex/speex/speex_stereo.h b/ios/IOSDuoduo/Voice/Code/Libs/libspeex/speex/speex_stereo.h new file mode 100755 index 000000000..b817a5535 --- /dev/null +++ b/ios/IOSDuoduo/Voice/Code/Libs/libspeex/speex/speex_stereo.h @@ -0,0 +1,91 @@ +/* Copyright (C) 2002 Jean-Marc Valin*/ +/** + @file speex_stereo.h + @brief Describes the handling for intensity stereo +*/ +/* + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + - Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + - Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + - Neither the name of the Xiph.org Foundation nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR + CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#ifndef STEREO_H +#define STEREO_H +/** @defgroup SpeexStereoState SpeexStereoState: Handling Speex stereo files + * This describes the Speex intensity stereo encoding/decoding + * @{ + */ + +#include "speex_types.h" +#include "speex_bits.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** If you access any of these fields directly, I'll personally come and bite you */ +typedef struct SpeexStereoState { + float balance; /**< Left/right balance info */ + float e_ratio; /**< Ratio of energies: E(left+right)/[E(left)+E(right)] */ + float smooth_left; /**< Smoothed left channel gain */ + float smooth_right; /**< Smoothed right channel gain */ + float reserved1; /**< Reserved for future use */ + float reserved2; /**< Reserved for future use */ +} SpeexStereoState; + +/** Deprecated. Use speex_stereo_state_init() instead. */ +#define SPEEX_STEREO_STATE_INIT {1,.5,1,1,0,0} + +/** Initialise/create a stereo stereo state */ +SpeexStereoState *speex_stereo_state_init(); + +/** Reset/re-initialise an already allocated stereo state */ +void speex_stereo_state_reset(SpeexStereoState *stereo); + +/** Destroy a stereo stereo state */ +void speex_stereo_state_destroy(SpeexStereoState *stereo); + +/** Transforms a stereo frame into a mono frame and stores intensity stereo info in 'bits' */ +void speex_encode_stereo(float *data, int frame_size, SpeexBits *bits); + +/** Transforms a stereo frame into a mono frame and stores intensity stereo info in 'bits' */ +void speex_encode_stereo_int(spx_int16_t *data, int frame_size, SpeexBits *bits); + +/** Transforms a mono frame into a stereo frame using intensity stereo info */ +void speex_decode_stereo(float *data, int frame_size, SpeexStereoState *stereo); + +/** Transforms a mono frame into a stereo frame using intensity stereo info */ +void speex_decode_stereo_int(spx_int16_t *data, int frame_size, SpeexStereoState *stereo); + +/** Callback handler for intensity stereo info */ +int speex_std_stereo_request_handler(SpeexBits *bits, void *state, void *data); + +#ifdef __cplusplus +} +#endif + +/** @} */ +#endif diff --git a/ios/IOSDuoduo/Voice/Code/Libs/libspeex/speex/speex_types.h b/ios/IOSDuoduo/Voice/Code/Libs/libspeex/speex/speex_types.h new file mode 100755 index 000000000..852fed801 --- /dev/null +++ b/ios/IOSDuoduo/Voice/Code/Libs/libspeex/speex/speex_types.h @@ -0,0 +1,126 @@ +/* speex_types.h taken from libogg */ +/******************************************************************** + * * + * THIS FILE IS PART OF THE OggVorbis SOFTWARE CODEC SOURCE CODE. * + * USE, DISTRIBUTION AND REPRODUCTION OF THIS LIBRARY SOURCE IS * + * GOVERNED BY A BSD-STYLE SOURCE LICENSE INCLUDED WITH THIS SOURCE * + * IN 'COPYING'. PLEASE READ THESE TERMS BEFORE DISTRIBUTING. * + * * + * THE OggVorbis SOURCE CODE IS (C) COPYRIGHT 1994-2002 * + * by the Xiph.Org Foundation http://www.xiph.org/ * + * * + ******************************************************************** + + function: #ifdef jail to whip a few platforms into the UNIX ideal. + last mod: $Id: os_types.h 7524 2004-08-11 04:20:36Z conrad $ + + ********************************************************************/ +/** + @file speex_types.h + @brief Speex types +*/ +#ifndef _SPEEX_TYPES_H +#define _SPEEX_TYPES_H + +#if defined(_WIN32) + +# if defined(__CYGWIN__) +# include <_G_config.h> + typedef _G_int32_t spx_int32_t; + typedef _G_uint32_t spx_uint32_t; + typedef _G_int16_t spx_int16_t; + typedef _G_uint16_t spx_uint16_t; +# elif defined(__MINGW32__) + typedef short spx_int16_t; + typedef unsigned short spx_uint16_t; + typedef int spx_int32_t; + typedef unsigned int spx_uint32_t; +# elif defined(__MWERKS__) + typedef int spx_int32_t; + typedef unsigned int spx_uint32_t; + typedef short spx_int16_t; + typedef unsigned short spx_uint16_t; +# else + /* MSVC/Borland */ + typedef __int32 spx_int32_t; + typedef unsigned __int32 spx_uint32_t; + typedef __int16 spx_int16_t; + typedef unsigned __int16 spx_uint16_t; +# endif + +#elif defined(__MACOS__) + +# include + typedef SInt16 spx_int16_t; + typedef UInt16 spx_uint16_t; + typedef SInt32 spx_int32_t; + typedef UInt32 spx_uint32_t; + +#elif (defined(__APPLE__) && defined(__MACH__)) /* MacOS X Framework build */ + +# include + typedef int16_t spx_int16_t; + typedef u_int16_t spx_uint16_t; + typedef int32_t spx_int32_t; + typedef u_int32_t spx_uint32_t; + +#elif defined(__BEOS__) + + /* Be */ +# include + typedef int16_t spx_int16_t; + typedef u_int16_t spx_uint16_t; + typedef int32_t spx_int32_t; + typedef u_int32_t spx_uint32_t; + +#elif defined (__EMX__) + + /* OS/2 GCC */ + typedef short spx_int16_t; + typedef unsigned short spx_uint16_t; + typedef int spx_int32_t; + typedef unsigned int spx_uint32_t; + +#elif defined (DJGPP) + + /* DJGPP */ + typedef short spx_int16_t; + typedef int spx_int32_t; + typedef unsigned int spx_uint32_t; + +#elif defined(R5900) + + /* PS2 EE */ + typedef int spx_int32_t; + typedef unsigned spx_uint32_t; + typedef short spx_int16_t; + +#elif defined(__SYMBIAN32__) + + /* Symbian GCC */ + typedef signed short spx_int16_t; + typedef unsigned short spx_uint16_t; + typedef signed int spx_int32_t; + typedef unsigned int spx_uint32_t; + +#elif defined(CONFIG_TI_C54X) || defined (CONFIG_TI_C55X) + + typedef short spx_int16_t; + typedef unsigned short spx_uint16_t; + typedef long spx_int32_t; + typedef unsigned long spx_uint32_t; + +#elif defined(CONFIG_TI_C6X) + + typedef short spx_int16_t; + typedef unsigned short spx_uint16_t; + typedef int spx_int32_t; + typedef unsigned int spx_uint32_t; + +#else + +# include + +#endif + +#endif /* _SPEEX_TYPES_H */ diff --git a/ios/IOSDuoduo/Voice/Code/Libs/libspeex/speex_callbacks.c b/ios/IOSDuoduo/Voice/Code/Libs/libspeex/speex_callbacks.c new file mode 100755 index 000000000..09f037c19 --- /dev/null +++ b/ios/IOSDuoduo/Voice/Code/Libs/libspeex/speex_callbacks.c @@ -0,0 +1,144 @@ +/* Copyright (C) 2002 Jean-Marc Valin + File speex_callbacks.c + Callback handling and in-band signalling + + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + - Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + - Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + - Neither the name of the Xiph.org Foundation nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR + CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +*/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "speex/speex_callbacks.h" +#include "arch.h" +#include "os_support.h" + +EXPORT int speex_inband_handler(SpeexBits *bits, SpeexCallback *callback_list, void *state) +{ + int id; + SpeexCallback *callback; + /*speex_bits_advance(bits, 5);*/ + id=speex_bits_unpack_unsigned(bits, 4); + callback = callback_list+id; + + if (callback->func) + { + return callback->func(bits, state, callback->data); + } else + /*If callback is not registered, skip the right number of bits*/ + { + int adv; + if (id<2) + adv = 1; + else if (id<8) + adv = 4; + else if (id<10) + adv = 8; + else if (id<12) + adv = 16; + else if (id<14) + adv = 32; + else + adv = 64; + speex_bits_advance(bits, adv); + } + return 0; +} + +EXPORT int speex_std_mode_request_handler(SpeexBits *bits, void *state, void *data) +{ + spx_int32_t m; + m = speex_bits_unpack_unsigned(bits, 4); + speex_encoder_ctl(data, SPEEX_SET_MODE, &m); + return 0; +} + +EXPORT int speex_std_low_mode_request_handler(SpeexBits *bits, void *state, void *data) +{ + spx_int32_t m; + m = speex_bits_unpack_unsigned(bits, 4); + speex_encoder_ctl(data, SPEEX_SET_LOW_MODE, &m); + return 0; +} + +EXPORT int speex_std_high_mode_request_handler(SpeexBits *bits, void *state, void *data) +{ + spx_int32_t m; + m = speex_bits_unpack_unsigned(bits, 4); + speex_encoder_ctl(data, SPEEX_SET_HIGH_MODE, &m); + return 0; +} + +#ifndef DISABLE_VBR +EXPORT int speex_std_vbr_request_handler(SpeexBits *bits, void *state, void *data) +{ + spx_int32_t vbr; + vbr = speex_bits_unpack_unsigned(bits, 1); + speex_encoder_ctl(data, SPEEX_SET_VBR, &vbr); + return 0; +} +#endif /* #ifndef DISABLE_VBR */ + +EXPORT int speex_std_enh_request_handler(SpeexBits *bits, void *state, void *data) +{ + spx_int32_t enh; + enh = speex_bits_unpack_unsigned(bits, 1); + speex_decoder_ctl(data, SPEEX_SET_ENH, &enh); + return 0; +} + +#ifndef DISABLE_VBR +EXPORT int speex_std_vbr_quality_request_handler(SpeexBits *bits, void *state, void *data) +{ + float qual; + qual = speex_bits_unpack_unsigned(bits, 4); + speex_encoder_ctl(data, SPEEX_SET_VBR_QUALITY, &qual); + return 0; +} +#endif /* #ifndef DISABLE_VBR */ + +EXPORT int speex_std_char_handler(SpeexBits *bits, void *state, void *data) +{ + unsigned char ch; + ch = speex_bits_unpack_unsigned(bits, 8); + _speex_putc(ch, data); + /*printf("speex_std_char_handler ch=%x\n", ch);*/ + return 0; +} + + + +/* Default handler for user callbacks: skip it */ +EXPORT int speex_default_user_handler(SpeexBits *bits, void *state, void *data) +{ + int req_size = speex_bits_unpack_unsigned(bits, 4); + speex_bits_advance(bits, 5+8*req_size); + return 0; +} diff --git a/ios/IOSDuoduo/Voice/Code/Libs/libspeex/speex_header.c b/ios/IOSDuoduo/Voice/Code/Libs/libspeex/speex_header.c new file mode 100755 index 000000000..82751488e --- /dev/null +++ b/ios/IOSDuoduo/Voice/Code/Libs/libspeex/speex_header.c @@ -0,0 +1,200 @@ +/* Copyright (C) 2002 Jean-Marc Valin + File: speex_header.c + Describes the Speex header + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + - Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + - Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + - Neither the name of the Xiph.org Foundation nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR + CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +*/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "arch.h" +#include "speex/speex_header.h" +#include "speex/speex.h" +#include "os_support.h" + +#ifndef NULL +#define NULL 0 +#endif + +/** Convert little endian */ +static inline spx_int32_t le_int(spx_int32_t i) +{ +#if !defined(__LITTLE_ENDIAN__) && ( defined(WORDS_BIGENDIAN) || defined(__BIG_ENDIAN__) ) + spx_uint32_t ui, ret; + ui = i; + ret = ui>>24; + ret |= (ui>>8)&0x0000ff00; + ret |= (ui<<8)&0x00ff0000; + ret |= (ui<<24); + return ret; +#else + return i; +#endif +} + +#define ENDIAN_SWITCH(x) {x=le_int(x);} + + +/* +typedef struct SpeexHeader { + char speex_string[8]; + char speex_version[SPEEX_HEADER_VERSION_LENGTH]; + int speex_version_id; + int header_size; + int rate; + int mode; + int mode_bitstream_version; + int nb_channels; + int bitrate; + int frame_size; + int vbr; + int frames_per_packet; + int extra_headers; + int reserved1; + int reserved2; +} SpeexHeader; +*/ + +EXPORT void speex_init_header(SpeexHeader *header, int rate, int nb_channels, const SpeexMode *m) +{ + int i; + const char *h="Speex "; + /* + strncpy(header->speex_string, "Speex ", 8); + strncpy(header->speex_version, SPEEX_VERSION, SPEEX_HEADER_VERSION_LENGTH-1); + header->speex_version[SPEEX_HEADER_VERSION_LENGTH-1]=0; + */ + for (i=0;i<8;i++) + header->speex_string[i]=h[i]; + for (i=0;ispeex_version[i]=SPEEX_VERSION[i]; + for (;ispeex_version[i]=0; + + header->speex_version_id = 1; + header->header_size = sizeof(SpeexHeader); + + header->rate = rate; + header->mode = m->modeID; + header->mode_bitstream_version = m->bitstream_version; + if (m->modeID<0) + speex_warning("This mode is meant to be used alone"); + header->nb_channels = nb_channels; + header->bitrate = -1; + speex_mode_query(m, SPEEX_MODE_FRAME_SIZE, &header->frame_size); + header->vbr = 0; + + header->frames_per_packet = 0; + header->extra_headers = 0; + header->reserved1 = 0; + header->reserved2 = 0; +} + +EXPORT char *speex_header_to_packet(SpeexHeader *header, int *size) +{ + SpeexHeader *le_header; + le_header = (SpeexHeader*)speex_alloc(sizeof(SpeexHeader)); + + SPEEX_COPY(le_header, header, 1); + + /*Make sure everything is now little-endian*/ + ENDIAN_SWITCH(le_header->speex_version_id); + ENDIAN_SWITCH(le_header->header_size); + ENDIAN_SWITCH(le_header->rate); + ENDIAN_SWITCH(le_header->mode); + ENDIAN_SWITCH(le_header->mode_bitstream_version); + ENDIAN_SWITCH(le_header->nb_channels); + ENDIAN_SWITCH(le_header->bitrate); + ENDIAN_SWITCH(le_header->frame_size); + ENDIAN_SWITCH(le_header->vbr); + ENDIAN_SWITCH(le_header->frames_per_packet); + ENDIAN_SWITCH(le_header->extra_headers); + + *size = sizeof(SpeexHeader); + return (char *)le_header; +} + +EXPORT SpeexHeader *speex_packet_to_header(char *packet, int size) +{ + int i; + SpeexHeader *le_header; + const char *h = "Speex "; + for (i=0;i<8;i++) + if (packet[i]!=h[i]) + { + speex_notify("This doesn't look like a Speex file"); + return NULL; + } + + /*FIXME: Do we allow larger headers?*/ + if (size < (int)sizeof(SpeexHeader)) + { + speex_notify("Speex header too small"); + return NULL; + } + + le_header = (SpeexHeader*)speex_alloc(sizeof(SpeexHeader)); + + SPEEX_COPY(le_header, (SpeexHeader*)packet, 1); + + /*Make sure everything is converted correctly from little-endian*/ + ENDIAN_SWITCH(le_header->speex_version_id); + ENDIAN_SWITCH(le_header->header_size); + ENDIAN_SWITCH(le_header->rate); + ENDIAN_SWITCH(le_header->mode); + ENDIAN_SWITCH(le_header->mode_bitstream_version); + ENDIAN_SWITCH(le_header->nb_channels); + ENDIAN_SWITCH(le_header->bitrate); + ENDIAN_SWITCH(le_header->frame_size); + ENDIAN_SWITCH(le_header->vbr); + ENDIAN_SWITCH(le_header->frames_per_packet); + ENDIAN_SWITCH(le_header->extra_headers); + + if (le_header->mode >= SPEEX_NB_MODES || le_header->mode < 0) + { + speex_notify("Invalid mode specified in Speex header"); + speex_free (le_header); + return NULL; + } + + if (le_header->nb_channels>2) + le_header->nb_channels = 2; + if (le_header->nb_channels<1) + le_header->nb_channels = 1; + + return le_header; + +} + +EXPORT void speex_header_free(void *ptr) +{ + speex_free(ptr); +} diff --git a/ios/IOSDuoduo/Voice/Code/Libs/libspeex/stack_alloc.h b/ios/IOSDuoduo/Voice/Code/Libs/libspeex/stack_alloc.h new file mode 100755 index 000000000..5264e666b --- /dev/null +++ b/ios/IOSDuoduo/Voice/Code/Libs/libspeex/stack_alloc.h @@ -0,0 +1,115 @@ +/* Copyright (C) 2002 Jean-Marc Valin */ +/** + @file stack_alloc.h + @brief Temporary memory allocation on stack +*/ +/* + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + - Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + - Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + - Neither the name of the Xiph.org Foundation nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR + CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#ifndef STACK_ALLOC_H +#define STACK_ALLOC_H + +#ifdef USE_ALLOCA +# ifdef WIN32 +# include +# else +# ifdef HAVE_ALLOCA_H +# include +# else +# include +# endif +# endif +#endif + +/** + * @def ALIGN(stack, size) + * + * Aligns the stack to a 'size' boundary + * + * @param stack Stack + * @param size New size boundary + */ + +/** + * @def PUSH(stack, size, type) + * + * Allocates 'size' elements of type 'type' on the stack + * + * @param stack Stack + * @param size Number of elements + * @param type Type of element + */ + +/** + * @def VARDECL(var) + * + * Declare variable on stack + * + * @param var Variable to declare + */ + +/** + * @def ALLOC(var, size, type) + * + * Allocate 'size' elements of 'type' on stack + * + * @param var Name of variable to allocate + * @param size Number of elements + * @param type Type of element + */ + +#ifdef ENABLE_VALGRIND + +#include + +#define ALIGN(stack, size) ((stack) += ((size) - (long)(stack)) & ((size) - 1)) + +#define PUSH(stack, size, type) (VALGRIND_MAKE_NOACCESS(stack, 1000),ALIGN((stack),sizeof(type)),VALGRIND_MAKE_WRITABLE(stack, ((size)*sizeof(type))),(stack)+=((size)*sizeof(type)),(type*)((stack)-((size)*sizeof(type)))) + +#else + +#define ALIGN(stack, size) ((stack) += ((size) - (long)(stack)) & ((size) - 1)) + +#define PUSH(stack, size, type) (ALIGN((stack),sizeof(type)),(stack)+=((size)*sizeof(type)),(type*)((stack)-((size)*sizeof(type)))) + +#endif + +#if defined(VAR_ARRAYS) +#define VARDECL(var) +#define ALLOC(var, size, type) type var[size] +#elif defined(USE_ALLOCA) +#define VARDECL(var) var +#define ALLOC(var, size, type) var = alloca(sizeof(type)*(size)) +#else +#define VARDECL(var) var +#define ALLOC(var, size, type) var = PUSH(stack, size, type) +#endif + + +#endif diff --git a/ios/IOSDuoduo/Voice/Code/Libs/libspeex/stereo.c b/ios/IOSDuoduo/Voice/Code/Libs/libspeex/stereo.c new file mode 100755 index 000000000..3655e4c4b --- /dev/null +++ b/ios/IOSDuoduo/Voice/Code/Libs/libspeex/stereo.c @@ -0,0 +1,296 @@ +/* Copyright (C) 2002 Jean-Marc Valin + File: stereo.c + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + - Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + - Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + - Neither the name of the Xiph.org Foundation nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR + CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "speex/speex_stereo.h" +#include "speex/speex_callbacks.h" +#include "math_approx.h" +#include "vq.h" +#include +#include "os_support.h" + +typedef struct RealSpeexStereoState { + spx_word32_t balance; /**< Left/right balance info */ + spx_word32_t e_ratio; /**< Ratio of energies: E(left+right)/[E(left)+E(right)] */ + spx_word32_t smooth_left; /**< Smoothed left channel gain */ + spx_word32_t smooth_right; /**< Smoothed right channel gain */ + spx_uint32_t reserved1; /**< Reserved for future use */ + spx_int32_t reserved2; /**< Reserved for future use */ +} RealSpeexStereoState; + + +/*float e_ratio_quant[4] = {1, 1.26, 1.587, 2};*/ +#ifndef FIXED_POINT +static const float e_ratio_quant[4] = {.25f, .315f, .397f, .5f}; +static const float e_ratio_quant_bounds[3] = {0.2825f, 0.356f, 0.4485f}; +#else +static const spx_word16_t e_ratio_quant[4] = {8192, 10332, 13009, 16384}; +static const spx_word16_t e_ratio_quant_bounds[3] = {9257, 11665, 14696}; +static const spx_word16_t balance_bounds[31] = {18, 23, 30, 38, 49, 63, 81, 104, + 134, 172, 221, 284, 364, 468, 600, 771, + 990, 1271, 1632, 2096, 2691, 3455, 4436, 5696, + 7314, 9392, 12059, 15484, 19882, 25529, 32766}; +#endif + +/* This is an ugly compatibility hack that properly resets the stereo state + In case it it compiled in fixed-point, but initialised with the deprecated + floating point static initialiser */ +#ifdef FIXED_POINT +#define COMPATIBILITY_HACK(s) do {if ((s)->reserved1 != 0xdeadbeef) speex_stereo_state_reset((SpeexStereoState*)s); } while (0); +#else +#define COMPATIBILITY_HACK(s) +#endif + +EXPORT SpeexStereoState *speex_stereo_state_init() +{ + SpeexStereoState *stereo = speex_alloc(sizeof(SpeexStereoState)); + speex_stereo_state_reset(stereo); + return stereo; +} + +EXPORT void speex_stereo_state_reset(SpeexStereoState *_stereo) +{ + RealSpeexStereoState *stereo = (RealSpeexStereoState*)_stereo; +#ifdef FIXED_POINT + stereo->balance = 65536; + stereo->e_ratio = 16384; + stereo->smooth_left = 16384; + stereo->smooth_right = 16384; + stereo->reserved1 = 0xdeadbeef; + stereo->reserved2 = 0; +#else + stereo->balance = 1.0f; + stereo->e_ratio = .5f; + stereo->smooth_left = 1.f; + stereo->smooth_right = 1.f; + stereo->reserved1 = 0; + stereo->reserved2 = 0; +#endif +} + +EXPORT void speex_stereo_state_destroy(SpeexStereoState *stereo) +{ + speex_free(stereo); +} + +#ifndef DISABLE_FLOAT_API +EXPORT void speex_encode_stereo(float *data, int frame_size, SpeexBits *bits) +{ + int i, tmp; + float e_left=0, e_right=0, e_tot=0; + float balance, e_ratio; + for (i=0;i0) + speex_bits_pack(bits, 0, 1); + else + speex_bits_pack(bits, 1, 1); + balance=floor(.5+fabs(balance)); + if (balance>30) + balance=31; + + speex_bits_pack(bits, (int)balance, 5); + + /* FIXME: this is a hack */ + tmp=scal_quant(e_ratio*Q15_ONE, e_ratio_quant_bounds, 4); + speex_bits_pack(bits, tmp, 2); +} +#endif /* #ifndef DISABLE_FLOAT_API */ + +EXPORT void speex_encode_stereo_int(spx_int16_t *data, int frame_size, SpeexBits *bits) +{ + int i, tmp; + spx_word32_t e_left=0, e_right=0, e_tot=0; + spx_word32_t balance, e_ratio; + spx_word32_t largest, smallest; + int balance_id; +#ifdef FIXED_POINT + int shift; +#endif + + /* In band marker */ + speex_bits_pack(bits, 14, 5); + /* Stereo marker */ + speex_bits_pack(bits, SPEEX_INBAND_STEREO, 4); + + for (i=0;i e_right) + { + speex_bits_pack(bits, 0, 1); + largest = e_left; + smallest = e_right; + } else { + speex_bits_pack(bits, 1, 1); + largest = e_right; + smallest = e_left; + } + + /* Balance quantization */ +#ifdef FIXED_POINT + shift = spx_ilog2(largest)-15; + largest = VSHR32(largest, shift-4); + smallest = VSHR32(smallest, shift); + balance = DIV32(largest, ADD32(smallest, 1)); + if (balance > 32767) + balance = 32767; + balance_id = scal_quant(EXTRACT16(balance), balance_bounds, 32); +#else + balance=(largest+1.)/(smallest+1.); + balance=4*log(balance); + balance_id=floor(.5+fabs(balance)); + if (balance_id>30) + balance_id=31; +#endif + + speex_bits_pack(bits, balance_id, 5); + + /* "coherence" quantisation */ +#ifdef FIXED_POINT + shift = spx_ilog2(e_tot); + e_tot = VSHR32(e_tot, shift-25); + e_left = VSHR32(e_left, shift-10); + e_right = VSHR32(e_right, shift-10); + e_ratio = DIV32(e_tot, e_left+e_right+1); +#else + e_ratio = e_tot/(1.+e_left+e_right); +#endif + + tmp=scal_quant(EXTRACT16(e_ratio), e_ratio_quant_bounds, 4); + /*fprintf (stderr, "%d %d %d %d\n", largest, smallest, balance_id, e_ratio);*/ + speex_bits_pack(bits, tmp, 2); +} + +#ifndef DISABLE_FLOAT_API +EXPORT void speex_decode_stereo(float *data, int frame_size, SpeexStereoState *_stereo) +{ + int i; + spx_word32_t balance; + spx_word16_t e_left, e_right, e_ratio; + RealSpeexStereoState *stereo = (RealSpeexStereoState*)_stereo; + + COMPATIBILITY_HACK(stereo); + + balance=stereo->balance; + e_ratio=stereo->e_ratio; + + /* These two are Q14, with max value just below 2. */ + e_right = DIV32(QCONST32(1., 22), spx_sqrt(MULT16_32_Q15(e_ratio, ADD32(QCONST32(1., 16), balance)))); + e_left = SHR32(MULT16_16(spx_sqrt(balance), e_right), 8); + + for (i=frame_size-1;i>=0;i--) + { + spx_word16_t tmp=data[i]; + stereo->smooth_left = EXTRACT16(PSHR32(MAC16_16(MULT16_16(stereo->smooth_left, QCONST16(0.98, 15)), e_left, QCONST16(0.02, 15)), 15)); + stereo->smooth_right = EXTRACT16(PSHR32(MAC16_16(MULT16_16(stereo->smooth_right, QCONST16(0.98, 15)), e_right, QCONST16(0.02, 15)), 15)); + data[2*i] = (float)MULT16_16_P14(stereo->smooth_left, tmp); + data[2*i+1] = (float)MULT16_16_P14(stereo->smooth_right, tmp); + } +} +#endif /* #ifndef DISABLE_FLOAT_API */ + +EXPORT void speex_decode_stereo_int(spx_int16_t *data, int frame_size, SpeexStereoState *_stereo) +{ + int i; + spx_word32_t balance; + spx_word16_t e_left, e_right, e_ratio; + RealSpeexStereoState *stereo = (RealSpeexStereoState*)_stereo; + + COMPATIBILITY_HACK(stereo); + + balance=stereo->balance; + e_ratio=stereo->e_ratio; + + /* These two are Q14, with max value just below 2. */ + e_right = DIV32(QCONST32(1., 22), spx_sqrt(MULT16_32_Q15(e_ratio, ADD32(QCONST32(1., 16), balance)))); + e_left = SHR32(MULT16_16(spx_sqrt(balance), e_right), 8); + + for (i=frame_size-1;i>=0;i--) + { + spx_int16_t tmp=data[i]; + stereo->smooth_left = EXTRACT16(PSHR32(MAC16_16(MULT16_16(stereo->smooth_left, QCONST16(0.98, 15)), e_left, QCONST16(0.02, 15)), 15)); + stereo->smooth_right = EXTRACT16(PSHR32(MAC16_16(MULT16_16(stereo->smooth_right, QCONST16(0.98, 15)), e_right, QCONST16(0.02, 15)), 15)); + data[2*i] = (spx_int16_t)MULT16_16_P14(stereo->smooth_left, tmp); + data[2*i+1] = (spx_int16_t)MULT16_16_P14(stereo->smooth_right, tmp); + } +} + +EXPORT int speex_std_stereo_request_handler(SpeexBits *bits, void *state, void *data) +{ + RealSpeexStereoState *stereo; + spx_word16_t sign=1, dexp; + int tmp; + + stereo = (RealSpeexStereoState*)data; + + COMPATIBILITY_HACK(stereo); + + if (speex_bits_unpack_unsigned(bits, 1)) + sign=-1; + dexp = speex_bits_unpack_unsigned(bits, 5); +#ifndef FIXED_POINT + stereo->balance = exp(sign*.25*dexp); +#else + stereo->balance = spx_exp(MULT16_16(sign, SHL16(dexp, 9))); +#endif + tmp = speex_bits_unpack_unsigned(bits, 2); + stereo->e_ratio = e_ratio_quant[tmp]; + + return 0; +} diff --git a/ios/IOSDuoduo/Voice/Code/Libs/libspeex/vbr.c b/ios/IOSDuoduo/Voice/Code/Libs/libspeex/vbr.c new file mode 100755 index 000000000..5b7dd9bfa --- /dev/null +++ b/ios/IOSDuoduo/Voice/Code/Libs/libspeex/vbr.c @@ -0,0 +1,275 @@ +/* Copyright (C) 2002 Jean-Marc Valin + File: vbr.c + + VBR-related routines + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + - Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + - Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + - Neither the name of the Xiph.org Foundation nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR + CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +*/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "vbr.h" +#include + + +#define sqr(x) ((x)*(x)) + +#define MIN_ENERGY 6000 +#define NOISE_POW .3 + +#ifndef DISABLE_VBR + +const float vbr_nb_thresh[9][11]={ + {-1.0f, -1.0f, -1.0f, -1.0f, -1.0f, -1.0f, -1.0f, -1.0f, -1.0f, -1.0f, -1.0f}, /* CNG */ + { 4.0f, 2.5f, 2.0f, 1.2f, 0.5f, 0.0f, -0.5f, -0.7f, -0.8f, -0.9f, -1.0f}, /* 2 kbps */ + {10.0f, 6.5f, 5.2f, 4.5f, 3.9f, 3.5f, 3.0f, 2.5f, 2.3f, 1.8f, 1.0f}, /* 6 kbps */ + {11.0f, 8.8f, 7.5f, 6.5f, 5.0f, 3.9f, 3.9f, 3.9f, 3.5f, 3.0f, 1.0f}, /* 8 kbps */ + {11.0f, 11.0f, 9.9f, 8.5f, 7.0f, 6.0f, 4.5f, 4.0f, 4.0f, 4.0f, 2.0f}, /* 11 kbps */ + {11.0f, 11.0f, 11.0f, 11.0f, 9.5f, 8.5f, 8.0f, 7.0f, 6.0f, 5.0f, 3.0f}, /* 15 kbps */ + {11.0f, 11.0f, 11.0f, 11.0f, 11.0f, 11.0f, 9.5f, 8.5f, 7.0f, 6.0f, 5.0f}, /* 18 kbps */ + {11.0f, 11.0f, 11.0f, 11.0f, 11.0f, 11.0f, 11.0f, 11.0f, 9.8f, 9.5f, 7.5f}, /* 24 kbps */ + { 7.0f, 4.5f, 3.7f, 3.0f, 2.5f, 2.0f, 1.8f, 1.5f, 1.0f, 0.0f, 0.0f} /* 4 kbps */ +}; + + +const float vbr_hb_thresh[5][11]={ + {-1.0f, -1.0f, -1.0f, -1.0f, -1.0f, -1.0f, -1.0f, -1.0f, -1.0f, -1.0f, -1.0f}, /* silence */ + {-1.0f, -1.0f, -1.0f, -1.0f, -1.0f, -1.0f, -1.0f, -1.0f, -1.0f, -1.0f, -1.0f}, /* 2 kbps */ + {11.0f, 11.0f, 9.5f, 8.5f, 7.5f, 6.0f, 5.0f, 3.9f, 3.0f, 2.0f, 1.0f}, /* 6 kbps */ + {11.0f, 11.0f, 11.0f, 11.0f, 11.0f, 9.5f, 8.7f, 7.8f, 7.0f, 6.5f, 4.0f}, /* 10 kbps */ + {11.0f, 11.0f, 11.0f, 11.0f, 11.0f, 11.0f, 11.0f, 11.0f, 9.8f, 7.5f, 5.5f} /* 18 kbps */ +}; + +const float vbr_uhb_thresh[2][11]={ + {-1.0f, -1.0f, -1.0f, -1.0f, -1.0f, -1.0f, -1.0f, -1.0f, -1.0f, -1.0f, -1.0f}, /* silence */ + { 3.9f, 2.5f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, -1.0f} /* 2 kbps */ +}; + +void vbr_init(VBRState *vbr) +{ + int i; + + vbr->average_energy=0; + vbr->last_energy=1; + vbr->accum_sum=0; + vbr->energy_alpha=.1; + vbr->soft_pitch=0; + vbr->last_pitch_coef=0; + vbr->last_quality=0; + + vbr->noise_accum = .05*pow(MIN_ENERGY, NOISE_POW); + vbr->noise_accum_count=.05; + vbr->noise_level=vbr->noise_accum/vbr->noise_accum_count; + vbr->consec_noise=0; + + + for (i=0;ilast_log_energy[i] = log(MIN_ENERGY); +} + + +/* + This function should analyse the signal and decide how critical the + coding error will be perceptually. The following factors should be + taken into account: + + -Attacks (positive energy derivative) should be coded with more bits + + -Stationary voiced segments should receive more bits + + -Segments with (very) low absolute energy should receive less bits (maybe + only shaped noise?) + + -DTX for near-zero energy? + + -Stationary fricative segments should have less bits + + -Temporal masking: when energy slope is decreasing, decrease the bit-rate + + -Decrease bit-rate for males (low pitch)? + + -(wideband only) less bits in the high-band when signal is very + non-stationary (harder to notice high-frequency noise)??? + +*/ + +float vbr_analysis(VBRState *vbr, spx_word16_t *sig, int len, int pitch, float pitch_coef) +{ + int i; + float ener=0, ener1=0, ener2=0; + float qual=7; + int va; + float log_energy; + float non_st=0; + float voicing; + float pow_ener; + + for (i=0;i>1;i++) + ener1 += ((float)sig[i])*sig[i]; + + for (i=len>>1;ilast_log_energy[i]); + non_st = non_st/(30*VBR_MEMORY_SIZE); + if (non_st>1) + non_st=1; + + voicing = 3*(pitch_coef-.4)*fabs(pitch_coef-.4); + vbr->average_energy = (1-vbr->energy_alpha)*vbr->average_energy + vbr->energy_alpha*ener; + vbr->noise_level=vbr->noise_accum/vbr->noise_accum_count; + pow_ener = pow(ener,NOISE_POW); + if (vbr->noise_accum_count<.06 && ener>MIN_ENERGY) + vbr->noise_accum = .05*pow_ener; + + if ((voicing<.3 && non_st < .2 && pow_ener < 1.2*vbr->noise_level) + || (voicing<.3 && non_st < .05 && pow_ener < 1.5*vbr->noise_level) + || (voicing<.4 && non_st < .05 && pow_ener < 1.2*vbr->noise_level) + || (voicing<0 && non_st < .05)) + { + float tmp; + va = 0; + vbr->consec_noise++; + if (pow_ener > 3*vbr->noise_level) + tmp = 3*vbr->noise_level; + else + tmp = pow_ener; + if (vbr->consec_noise>=4) + { + vbr->noise_accum = .95*vbr->noise_accum + .05*tmp; + vbr->noise_accum_count = .95*vbr->noise_accum_count + .05; + } + } else { + va = 1; + vbr->consec_noise=0; + } + + if (pow_ener < vbr->noise_level && ener>MIN_ENERGY) + { + vbr->noise_accum = .95*vbr->noise_accum + .05*pow_ener; + vbr->noise_accum_count = .95*vbr->noise_accum_count + .05; + } + + /* Checking for very low absolute energy */ + if (ener < 30000) + { + qual -= .7; + if (ener < 10000) + qual-=.7; + if (ener < 3000) + qual-=.7; + } else { + float short_diff, long_diff; + short_diff = log((ener+1)/(1+vbr->last_energy)); + long_diff = log((ener+1)/(1+vbr->average_energy)); + /*fprintf (stderr, "%f %f\n", short_diff, long_diff);*/ + + if (long_diff<-5) + long_diff=-5; + if (long_diff>2) + long_diff=2; + + if (long_diff>0) + qual += .6*long_diff; + if (long_diff<0) + qual += .5*long_diff; + if (short_diff>0) + { + if (short_diff>5) + short_diff=5; + qual += .5*short_diff; + } + /* Checking for energy increases */ + if (ener2 > 1.6*ener1) + qual += .5; + } + vbr->last_energy = ener; + vbr->soft_pitch = .6*vbr->soft_pitch + .4*pitch_coef; + qual += 2.2*((pitch_coef-.4) + (vbr->soft_pitch-.4)); + + if (qual < vbr->last_quality) + qual = .5*qual + .5*vbr->last_quality; + if (qual<4) + qual=4; + if (qual>10) + qual=10; + + /* + if (vbr->consec_noise>=2) + qual-=1.3; + if (vbr->consec_noise>=5) + qual-=1.3; + if (vbr->consec_noise>=12) + qual-=1.3; + */ + if (vbr->consec_noise>=3) + qual=4; + + if (vbr->consec_noise) + qual -= 1.0 * (log(3.0 + vbr->consec_noise)-log(3)); + if (qual<0) + qual=0; + + if (ener<60000) + { + if (vbr->consec_noise>2) + qual-=0.5*(log(3.0 + vbr->consec_noise)-log(3)); + if (ener<10000&&vbr->consec_noise>2) + qual-=0.5*(log(3.0 + vbr->consec_noise)-log(3)); + if (qual<0) + qual=0; + qual += .3*log(.0001+ener/60000.0); + } + if (qual<-1) + qual=-1; + + /*printf ("%f %f %f %f %d\n", qual, voicing, non_st, pow_ener/(.01+vbr->noise_level), va);*/ + + vbr->last_pitch_coef = pitch_coef; + vbr->last_quality = qual; + + for (i=VBR_MEMORY_SIZE-1;i>0;i--) + vbr->last_log_energy[i] = vbr->last_log_energy[i-1]; + vbr->last_log_energy[0] = log_energy; + + /*printf ("VBR: %f %f %f %d %f\n", (float)(log_energy-log(vbr->average_energy+MIN_ENERGY)), non_st, voicing, va, vbr->noise_level);*/ + + return qual; +} + +void vbr_destroy(VBRState *vbr) +{ +} + +#endif /* #ifndef DISABLE_VBR */ diff --git a/ios/IOSDuoduo/Voice/Code/Libs/libspeex/vbr.h b/ios/IOSDuoduo/Voice/Code/Libs/libspeex/vbr.h new file mode 100755 index 000000000..ff1e3e46f --- /dev/null +++ b/ios/IOSDuoduo/Voice/Code/Libs/libspeex/vbr.h @@ -0,0 +1,70 @@ +/* Copyright (C) 2002 Jean-Marc Valin */ +/** + @file vbr.h + @brief Variable Bit-Rate (VBR) related routines +*/ +/* + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + - Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + - Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + - Neither the name of the Xiph.org Foundation nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR + CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +*/ + + +#ifndef VBR_H +#define VBR_H + +#include "arch.h" + +#define VBR_MEMORY_SIZE 5 + +extern const float vbr_nb_thresh[9][11]; +extern const float vbr_hb_thresh[5][11]; +extern const float vbr_uhb_thresh[2][11]; + +/** VBR state. */ +typedef struct VBRState { + float energy_alpha; + float average_energy; + float last_energy; + float last_log_energy[VBR_MEMORY_SIZE]; + float accum_sum; + float last_pitch_coef; + float soft_pitch; + float last_quality; + float noise_level; + float noise_accum; + float noise_accum_count; + int consec_noise; +} VBRState; + +void vbr_init(VBRState *vbr); + +float vbr_analysis(VBRState *vbr, spx_word16_t *sig, int len, int pitch, float pitch_coef); + +void vbr_destroy(VBRState *vbr); + +#endif diff --git a/ios/IOSDuoduo/Voice/Code/Libs/libspeex/vorbis_psy.h b/ios/IOSDuoduo/Voice/Code/Libs/libspeex/vorbis_psy.h new file mode 100755 index 000000000..687105775 --- /dev/null +++ b/ios/IOSDuoduo/Voice/Code/Libs/libspeex/vorbis_psy.h @@ -0,0 +1,97 @@ +/* Copyright (C) 2005 Jean-Marc Valin, CSIRO, Christopher Montgomery + File: vorbis_psy.h + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + - Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + - Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + - Neither the name of the Xiph.org Foundation nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR + CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#ifndef VORBIS_PSY_H +#define VORBIS_PSY_H + +#ifdef VORBIS_PSYCHO + +#include "smallft.h" +#define P_BANDS 17 /* 62Hz to 16kHz */ +#define NOISE_COMPAND_LEVELS 40 + + +#define todB(x) ((x)>1e-13?log((x)*(x))*4.34294480f:-30) +#define fromdB(x) (exp((x)*.11512925f)) + +/* The bark scale equations are approximations, since the original + table was somewhat hand rolled. The below are chosen to have the + best possible fit to the rolled tables, thus their somewhat odd + appearance (these are more accurate and over a longer range than + the oft-quoted bark equations found in the texts I have). The + approximations are valid from 0 - 30kHz (nyquist) or so. + + all f in Hz, z in Bark */ + +#define toBARK(n) (13.1f*atan(.00074f*(n))+2.24f*atan((n)*(n)*1.85e-8f)+1e-4f*(n)) +#define fromBARK(z) (102.f*(z)-2.f*pow(z,2.f)+.4f*pow(z,3.f)+pow(1.46f,z)-1.f) + +/* Frequency to octave. We arbitrarily declare 63.5 Hz to be octave + 0.0 */ + +#define toOC(n) (log(n)*1.442695f-5.965784f) +#define fromOC(o) (exp(((o)+5.965784f)*.693147f)) + + +typedef struct { + + float noisewindowlo; + float noisewindowhi; + int noisewindowlomin; + int noisewindowhimin; + int noisewindowfixed; + float noiseoff[P_BANDS]; + float noisecompand[NOISE_COMPAND_LEVELS]; + +} VorbisPsyInfo; + + + +typedef struct { + int n; + int rate; + struct drft_lookup lookup; + VorbisPsyInfo *vi; + + float *window; + float *noiseoffset; + long *bark; + +} VorbisPsy; + + +VorbisPsy *vorbis_psy_init(int rate, int size); +void vorbis_psy_destroy(VorbisPsy *psy); +void compute_curve(VorbisPsy *psy, float *audio, float *curve); +void curve_to_lpc(VorbisPsy *psy, float *curve, float *awk1, float *awk2, int ord); + +#endif +#endif diff --git a/ios/IOSDuoduo/Voice/Code/Libs/libspeex/vq.c b/ios/IOSDuoduo/Voice/Code/Libs/libspeex/vq.c new file mode 100755 index 000000000..609f124e7 --- /dev/null +++ b/ios/IOSDuoduo/Voice/Code/Libs/libspeex/vq.c @@ -0,0 +1,147 @@ +/* Copyright (C) 2002 Jean-Marc Valin + File: vq.c + Vector quantization + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + - Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + - Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + - Neither the name of the Xiph.org Foundation nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR + CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "vq.h" +#include "stack_alloc.h" +#include "arch.h" + +#ifdef _USE_SSE +#include +#include "vq_sse.h" +#elif defined(SHORTCUTS) && (defined(ARM4_ASM) || defined(ARM5E_ASM)) +#include "vq_arm4.h" +#elif defined(BFIN_ASM) +#include "vq_bfin.h" +#endif + + +int scal_quant(spx_word16_t in, const spx_word16_t *boundary, int entries) +{ + int i=0; + while (iboundary[0]) + { + boundary++; + i++; + } + return i; +} + +int scal_quant32(spx_word32_t in, const spx_word32_t *boundary, int entries) +{ + int i=0; + while (iboundary[0]) + { + boundary++; + i++; + } + return i; +} + + +#ifndef OVERRIDE_VQ_NBEST +/*Finds the indices of the n-best entries in a codebook*/ +void vq_nbest(spx_word16_t *in, const spx_word16_t *codebook, int len, int entries, spx_word32_t *E, int N, int *nbest, spx_word32_t *best_dist, char *stack) +{ + int i,j,k,used; + used = 0; + for (i=0;i= 1) && (k > used || dist < best_dist[k-1]); k--) + { + best_dist[k]=best_dist[k-1]; + nbest[k] = nbest[k-1]; + } + best_dist[k]=dist; + nbest[k]=i; + used++; + } + } +} +#endif + + + + +#ifndef OVERRIDE_VQ_NBEST_SIGN +/*Finds the indices of the n-best entries in a codebook with sign*/ +void vq_nbest_sign(spx_word16_t *in, const spx_word16_t *codebook, int len, int entries, spx_word32_t *E, int N, int *nbest, spx_word32_t *best_dist, char *stack) +{ + int i,j,k, sign, used; + used=0; + for (i=0;i0) + { + sign=0; + dist=-dist; + } else + { + sign=1; + } +#ifdef FIXED_POINT + dist = ADD32(dist,SHR32(E[i],1)); +#else + dist = ADD32(dist,.5f*E[i]); +#endif + if (i= 1) && (k > used || dist < best_dist[k-1]); k--) + { + best_dist[k]=best_dist[k-1]; + nbest[k] = nbest[k-1]; + } + best_dist[k]=dist; + nbest[k]=i; + used++; + if (sign) + nbest[k]+=entries; + } + } +} +#endif diff --git a/ios/IOSDuoduo/Voice/Code/Libs/libspeex/vq.h b/ios/IOSDuoduo/Voice/Code/Libs/libspeex/vq.h new file mode 100755 index 000000000..5a4ced249 --- /dev/null +++ b/ios/IOSDuoduo/Voice/Code/Libs/libspeex/vq.h @@ -0,0 +1,54 @@ +/* Copyright (C) 2002 Jean-Marc Valin */ +/** + @file vq.h + @brief Vector quantization +*/ +/* + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + - Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + - Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + - Neither the name of the Xiph.org Foundation nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR + CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#ifndef VQ_H +#define VQ_H + +#include "arch.h" + +int scal_quant(spx_word16_t in, const spx_word16_t *boundary, int entries); +int scal_quant32(spx_word32_t in, const spx_word32_t *boundary, int entries); + +#ifdef _USE_SSE +#include +void vq_nbest(spx_word16_t *in, const __m128 *codebook, int len, int entries, __m128 *E, int N, int *nbest, spx_word32_t *best_dist, char *stack); + +void vq_nbest_sign(spx_word16_t *in, const __m128 *codebook, int len, int entries, __m128 *E, int N, int *nbest, spx_word32_t *best_dist, char *stack); +#else +void vq_nbest(spx_word16_t *in, const spx_word16_t *codebook, int len, int entries, spx_word32_t *E, int N, int *nbest, spx_word32_t *best_dist, char *stack); + +void vq_nbest_sign(spx_word16_t *in, const spx_word16_t *codebook, int len, int entries, spx_word32_t *E, int N, int *nbest, spx_word32_t *best_dist, char *stack); +#endif + +#endif diff --git a/ios/IOSDuoduo/Voice/Code/Libs/libspeex/vq_arm4.h b/ios/IOSDuoduo/Voice/Code/Libs/libspeex/vq_arm4.h new file mode 100755 index 000000000..585b8613c --- /dev/null +++ b/ios/IOSDuoduo/Voice/Code/Libs/libspeex/vq_arm4.h @@ -0,0 +1,115 @@ +/* Copyright (C) 2004 Jean-Marc Valin */ +/** + @file vq_arm4.h + @brief ARM4-optimized vq routine +*/ +/* + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + - Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + - Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + - Neither the name of the Xiph.org Foundation nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR + CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#define OVERRIDE_VQ_NBEST +void vq_nbest(spx_word16_t *in, const spx_word16_t *codebook, int len, int entries, spx_word32_t *E, int N, int *nbest, spx_word32_t *best_dist, char *stack) +{ + int i,j; + for (i=0;i>= 1;\n\t" + "A0 = %0;\n\t" + "R0.L = W[%1++%7] || R1.L = W[I0++];\n\t" + "LOOP vq_loop%= LC1 = %5;\n\t" + "LOOP_BEGIN vq_loop%=;\n\t" + "%0 = (A0 -= R0.L*R1.L) (IS) || R0.L = W[%1++%7] || R1.L = W[I0++];\n\t" + "LOOP_END vq_loop%=;\n\t" + "%0 = (A0 -= R0.L*R1.L) (IS);\n\t" + "cc = %0 < %2;\n\t" + "if cc %2 = %0;\n\t" + "if cc %3 = R2;\n\t" + "R2 += 1;\n\t" + "LOOP_END entries_loop%=;\n\t" + : "=&D" (dist), "=&a" (codebook), "=&d" (best_dist[0]), "=&d" (nbest[0]), "=&a" (E) + : "a" (len-1), "a" (in), "a" (2), "d" (entries), "d" (len<<1), "1" (codebook), "4" (E), "2" (best_dist[0]), "3" (nbest[0]) + : "R0", "R1", "R2", "I0", "L0", "B0", "A0", "cc", "memory" + ); + } + } else { + int i,k,used; + used = 0; + for (i=0;i>= 1;\n\t" + "A0 = %0;\n\t" + "I0 = %3;\n\t" + "L0 = 0;\n\t" + "R0.L = W[%1++%4] || R1.L = W[I0++];\n\t" + "LOOP vq_loop%= LC0 = %2;\n\t" + "LOOP_BEGIN vq_loop%=;\n\t" + "%0 = (A0 -= R0.L*R1.L) (IS) || R0.L = W[%1++%4] || R1.L = W[I0++];\n\t" + "LOOP_END vq_loop%=;\n\t" + "%0 = (A0 -= R0.L*R1.L) (IS);\n\t" + : "=D" (dist), "=a" (codebook) + : "a" (len-1), "a" (in), "a" (2), "1" (codebook), "0" (E[i]) + : "R0", "R1", "I0", "L0", "A0" + ); + if (i= 1) && (k > used || dist < best_dist[k-1]); k--) + { + best_dist[k]=best_dist[k-1]; + nbest[k] = nbest[k-1]; + } + best_dist[k]=dist; + nbest[k]=i; + used++; + } + } + } +} diff --git a/ios/IOSDuoduo/Voice/Code/Libs/libspeex/vq_sse.h b/ios/IOSDuoduo/Voice/Code/Libs/libspeex/vq_sse.h new file mode 100755 index 000000000..00a42ce35 --- /dev/null +++ b/ios/IOSDuoduo/Voice/Code/Libs/libspeex/vq_sse.h @@ -0,0 +1,120 @@ +/* Copyright (C) 2004 Jean-Marc Valin */ +/** + @file vq_sse.h + @brief SSE-optimized vq routine +*/ +/* + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + - Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + - Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + - Neither the name of the Xiph.org Foundation nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR + CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#define OVERRIDE_VQ_NBEST +void vq_nbest(spx_word16_t *_in, const __m128 *codebook, int len, int entries, __m128 *E, int N, int *nbest, spx_word32_t *best_dist, char *stack) +{ + int i,j,k,used; + VARDECL(float *dist); + VARDECL(__m128 *in); + __m128 half; + used = 0; + ALLOC(dist, entries, float); + half = _mm_set_ps1(.5f); + ALLOC(in, len, __m128); + for (i=0;i>2;i++) + { + __m128 d = _mm_mul_ps(E[i], half); + for (j=0;j= 1) && (k > used || dist[i] < best_dist[k-1]); k--) + { + best_dist[k]=best_dist[k-1]; + nbest[k] = nbest[k-1]; + } + best_dist[k]=dist[i]; + nbest[k]=i; + used++; + } + } +} + + + + +#define OVERRIDE_VQ_NBEST_SIGN +void vq_nbest_sign(spx_word16_t *_in, const __m128 *codebook, int len, int entries, __m128 *E, int N, int *nbest, spx_word32_t *best_dist, char *stack) +{ + int i,j,k,used; + VARDECL(float *dist); + VARDECL(__m128 *in); + __m128 half; + used = 0; + ALLOC(dist, entries, float); + half = _mm_set_ps1(.5f); + ALLOC(in, len, __m128); + for (i=0;i>2;i++) + { + __m128 d = _mm_setzero_ps(); + for (j=0;j0) + { + sign=0; + dist[i]=-dist[i]; + } else + { + sign=1; + } + dist[i] += .5f*((float*)E)[i]; + if (i= 1) && (k > used || dist[i] < best_dist[k-1]); k--) + { + best_dist[k]=best_dist[k-1]; + nbest[k] = nbest[k-1]; + } + best_dist[k]=dist[i]; + nbest[k]=i; + used++; + if (sign) + nbest[k]+=entries; + } + } +} diff --git a/ios/IOSDuoduo/Voice/Code/Libs/libspeex/window.c b/ios/IOSDuoduo/Voice/Code/Libs/libspeex/window.c new file mode 100755 index 000000000..ac042d45f --- /dev/null +++ b/ios/IOSDuoduo/Voice/Code/Libs/libspeex/window.c @@ -0,0 +1,102 @@ +/* Copyright (C) 2006 Jean-Marc Valin + File: window.c + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + - Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + - Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + - Neither the name of the Xiph.org Foundation nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR + CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "arch.h" + +#ifdef FIXED_POINT +const spx_word16_t lag_window[11] = { + 16384, 16337, 16199, 15970, 15656, 15260, 14790, 14254, 13659, 13015, 12330 +}; + +const spx_word16_t lpc_window[200] = { +1310, 1313, 1321, 1333, 1352, 1375, 1403, 1436, +1475, 1518, 1567, 1621, 1679, 1743, 1811, 1884, +1962, 2044, 2132, 2224, 2320, 2421, 2526, 2636, +2750, 2868, 2990, 3116, 3246, 3380, 3518, 3659, +3804, 3952, 4104, 4259, 4417, 4578, 4742, 4909, +5079, 5251, 5425, 5602, 5781, 5963, 6146, 6331, +6518, 6706, 6896, 7087, 7280, 7473, 7668, 7863, +8059, 8256, 8452, 8650, 8847, 9044, 9241, 9438, +9635, 9831, 10026, 10220, 10414, 10606, 10797, 10987, +11176, 11363, 11548, 11731, 11912, 12091, 12268, 12443, +12615, 12785, 12952, 13116, 13277, 13435, 13590, 13742, +13890, 14035, 14176, 14314, 14448, 14578, 14704, 14826, +14944, 15058, 15168, 15273, 15374, 15470, 15562, 15649, +15732, 15810, 15883, 15951, 16015, 16073, 16127, 16175, +16219, 16257, 16291, 16319, 16342, 16360, 16373, 16381, +16384, 16384, 16384, 16384, 16384, 16384, 16384, 16384, +16384, 16384, 16384, 16384, 16384, 16384, 16384, 16384, +16384, 16384, 16384, 16384, 16384, 16384, 16384, 16384, +16384, 16384, 16384, 16384, 16384, 16384, 16384, 16384, +16384, 16384, 16384, 16384, 16384, 16384, 16384, 16384, +16384, 16384, 16384, 16384, 16384, 16384, 16384, 16384, +16384, 16384, 16384, 16361, 16294, 16183, 16028, 15830, +15588, 15304, 14979, 14613, 14207, 13763, 13282, 12766, +12215, 11631, 11016, 10373, 9702, 9007, 8289, 7551, +6797, 6028, 5251, 4470, 3695, 2943, 2248, 1696 +}; +#else +const spx_word16_t lag_window[11] = { + 1.00000, 0.99716, 0.98869, 0.97474, 0.95554, 0.93140, 0.90273, 0.86998, 0.83367, 0.79434, 0.75258 +}; + +const spx_word16_t lpc_window[200] = { + 0.080000f, 0.080158f, 0.080630f, 0.081418f, 0.082520f, 0.083935f, 0.085663f, 0.087703f, + 0.090052f, 0.092710f, 0.095674f, 0.098943f, 0.102514f, 0.106385f, 0.110553f, 0.115015f, + 0.119769f, 0.124811f, 0.130137f, 0.135744f, 0.141628f, 0.147786f, 0.154212f, 0.160902f, + 0.167852f, 0.175057f, 0.182513f, 0.190213f, 0.198153f, 0.206328f, 0.214731f, 0.223357f, + 0.232200f, 0.241254f, 0.250513f, 0.259970f, 0.269619f, 0.279453f, 0.289466f, 0.299651f, + 0.310000f, 0.320507f, 0.331164f, 0.341965f, 0.352901f, 0.363966f, 0.375151f, 0.386449f, + 0.397852f, 0.409353f, 0.420943f, 0.432615f, 0.444361f, 0.456172f, 0.468040f, 0.479958f, + 0.491917f, 0.503909f, 0.515925f, 0.527959f, 0.540000f, 0.552041f, 0.564075f, 0.576091f, + 0.588083f, 0.600042f, 0.611960f, 0.623828f, 0.635639f, 0.647385f, 0.659057f, 0.670647f, + 0.682148f, 0.693551f, 0.704849f, 0.716034f, 0.727099f, 0.738035f, 0.748836f, 0.759493f, + 0.770000f, 0.780349f, 0.790534f, 0.800547f, 0.810381f, 0.820030f, 0.829487f, 0.838746f, + 0.847800f, 0.856643f, 0.865269f, 0.873672f, 0.881847f, 0.889787f, 0.897487f, 0.904943f, + 0.912148f, 0.919098f, 0.925788f, 0.932214f, 0.938372f, 0.944256f, 0.949863f, 0.955189f, + 0.960231f, 0.964985f, 0.969447f, 0.973615f, 0.977486f, 0.981057f, 0.984326f, 0.987290f, + 0.989948f, 0.992297f, 0.994337f, 0.996065f, 0.997480f, 0.998582f, 0.999370f, 0.999842f, + 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, + 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, + 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, + 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, + 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, + 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, + 1.000000f, 1.000000f, 1.000000f, 0.998640f, 0.994566f, 0.987787f, 0.978324f, 0.966203f, + 0.951458f, 0.934131f, 0.914270f, 0.891931f, 0.867179f, 0.840084f, 0.810723f, 0.779182f, + 0.745551f, 0.709930f, 0.672424f, 0.633148f, 0.592223f, 0.549781f, 0.505964f, 0.460932f, + 0.414863f, 0.367968f, 0.320511f, 0.272858f, 0.225569f, 0.179655f, 0.137254f, 0.103524f +}; +#endif diff --git a/ios/IOSDuoduo/Voice/SpeexAllHeaders.h b/ios/IOSDuoduo/Voice/SpeexAllHeaders.h new file mode 100755 index 000000000..4c3d888a4 --- /dev/null +++ b/ios/IOSDuoduo/Voice/SpeexAllHeaders.h @@ -0,0 +1,26 @@ +// +// SpeexAllHeaders.h +// OggSpeex +// +// Created by Jiang Chuncheng on 11/26/12. +// Copyright (c) 2012 Sense Force. All rights reserved. +// + +#ifndef OggSpeex_SpeexAllHeaders_h +#define OggSpeex_SpeexAllHeaders_h + +#import "ogg.h" +#import "os_types.h" +#import "speex.h" +#import "speex_bits.h" +#import "speex_buffer.h" +#import "speex_callbacks.h" +#import "speex_config_types.h" +#import "speex_echo.h" +#import "speex_header.h" +#import "speex_jitter.h" +#import "speex_preprocess.h" +#import "speex_stereo.h" +#import "speex_types.h" + +#endif diff --git a/ios/IOSDuoduo/Voice/manager/AQRecorder.h b/ios/IOSDuoduo/Voice/manager/AQRecorder.h new file mode 100755 index 000000000..bf768a3f3 --- /dev/null +++ b/ios/IOSDuoduo/Voice/manager/AQRecorder.h @@ -0,0 +1,96 @@ +/* + + File: AQRecorder.h +Abstract: Helper class for recording audio files via the AudioQueue + Version: 2.5 + +Disclaimer: IMPORTANT: This Apple software is supplied to you by Apple +Inc. ("Apple") in consideration of your agreement to the following +terms, and your use, installation, modification or redistribution of +this Apple software constitutes acceptance of these terms. If you do +not agree with these terms, please do not use, install, modify or +redistribute this Apple software. + +In consideration of your agreement to abide by the following terms, and +subject to these terms, Apple grants you a personal, non-exclusive +license, under Apple's copyrights in this original Apple software (the +"Apple Software"), to use, reproduce, modify and redistribute the Apple +Software, with or without modifications, in source and/or binary forms; +provided that if you redistribute the Apple Software in its entirety and +without modifications, you must retain this notice and the following +text and disclaimers in all such redistributions of the Apple Software. +Neither the name, trademarks, service marks or logos of Apple Inc. may +be used to endorse or promote products derived from the Apple Software +without specific prior written permission from Apple. Except as +expressly stated in this notice, no other rights or licenses, express or +implied, are granted by Apple herein, including but not limited to any +patent rights that may be infringed by your derivative works or by other +works in which the Apple Software may be incorporated. + +The Apple Software is provided by Apple on an "AS IS" basis. APPLE +MAKES NO WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION +THE IMPLIED WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS +FOR A PARTICULAR PURPOSE, REGARDING THE APPLE SOFTWARE OR ITS USE AND +OPERATION ALONE OR IN COMBINATION WITH YOUR PRODUCTS. + +IN NO EVENT SHALL APPLE BE LIABLE FOR ANY SPECIAL, INDIRECT, INCIDENTAL +OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) ARISING IN ANY WAY OUT OF THE USE, REPRODUCTION, +MODIFICATION AND/OR DISTRIBUTION OF THE APPLE SOFTWARE, HOWEVER CAUSED +AND WHETHER UNDER THEORY OF CONTRACT, TORT (INCLUDING NEGLIGENCE), +STRICT LIABILITY OR OTHERWISE, EVEN IF APPLE HAS BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. + +Copyright (C) 2012 Apple Inc. All Rights Reserved. + + +*/ + +#include +#include +#include + +#include "CAStreamBasicDescription.h" +#include "CAXException.h" +#include "Encapsulator.h" + +#define kNumberRecordBuffers 3 +#define kBufferDurationSeconds .5 + +class AQRecorder + { + public: + AQRecorder(); + ~AQRecorder(); + + UInt32 GetNumberChannels() const { return mRecordFormat.NumberChannels(); } + AudioQueueRef Queue() const { return mQueue; } + CAStreamBasicDescription DataFormat() const { return mRecordFormat; } + + Boolean StartRecord(Encapsulator *encapsulator); + void StopRecord(); + Boolean IsRunning() const { return mIsRunning; } + + UInt64 startTime; + + private: + AudioQueueRef mQueue; + AudioQueueBufferRef mBuffers[kNumberRecordBuffers]; + SInt64 mRecordPacket; // current packet number in record file + CAStreamBasicDescription mRecordFormat; + Boolean mIsRunning; + + OSStatus errorStatus; + Encapsulator *mEncapsulator; + + void SetupAudioFormat(UInt32 inFormatID); + int ComputeRecordBufferSize(const AudioStreamBasicDescription *format, float seconds); + + static void MyInputBufferHandler( void * inUserData, + AudioQueueRef inAQ, + AudioQueueBufferRef inBuffer, + const AudioTimeStamp * inStartTime, + UInt32 inNumPackets, + const AudioStreamPacketDescription* inPacketDesc); + }; \ No newline at end of file diff --git a/ios/IOSDuoduo/Voice/manager/AQRecorder.mm b/ios/IOSDuoduo/Voice/manager/AQRecorder.mm new file mode 100755 index 000000000..87080e2d9 --- /dev/null +++ b/ios/IOSDuoduo/Voice/manager/AQRecorder.mm @@ -0,0 +1,224 @@ +/* + + File: AQRecorder.mm +Abstract: n/a + Version: 2.5 + +Disclaimer: IMPORTANT: This Apple software is supplied to you by Apple +Inc. ("Apple") in consideration of your agreement to the following +terms, and your use, installation, modification or redistribution of +this Apple software constitutes acceptance of these terms. If you do +not agree with these terms, please do not use, install, modify or +redistribute this Apple software. + +In consideration of your agreement to abide by the following terms, and +subject to these terms, Apple grants you a personal, non-exclusive +license, under Apple's copyrights in this original Apple software (the +"Apple Software"), to use, reproduce, modify and redistribute the Apple +Software, with or without modifications, in source and/or binary forms; +provided that if you redistribute the Apple Software in its entirety and +without modifications, you must retain this notice and the following +text and disclaimers in all such redistributions of the Apple Software. +Neither the name, trademarks, service marks or logos of Apple Inc. may +be used to endorse or promote products derived from the Apple Software +without specific prior written permission from Apple. Except as +expressly stated in this notice, no other rights or licenses, express or +implied, are granted by Apple herein, including but not limited to any +patent rights that may be infringed by your derivative works or by other +works in which the Apple Software may be incorporated. + +The Apple Software is provided by Apple on an "AS IS" basis. APPLE +MAKES NO WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION +THE IMPLIED WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS +FOR A PARTICULAR PURPOSE, REGARDING THE APPLE SOFTWARE OR ITS USE AND +OPERATION ALONE OR IN COMBINATION WITH YOUR PRODUCTS. + +IN NO EVENT SHALL APPLE BE LIABLE FOR ANY SPECIAL, INDIRECT, INCIDENTAL +OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) ARISING IN ANY WAY OUT OF THE USE, REPRODUCTION, +MODIFICATION AND/OR DISTRIBUTION OF THE APPLE SOFTWARE, HOWEVER CAUSED +AND WHETHER UNDER THEORY OF CONTRACT, TORT (INCLUDING NEGLIGENCE), +STRICT LIABILITY OR OTHERWISE, EVEN IF APPLE HAS BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. + +Copyright (C) 2012 Apple Inc. All Rights Reserved. + + +*/ + +#include "AQRecorder.h" +#include "CAStreamBasicDescription.h" +#include "CAXException.h" + +// ____________________________________________________________________________________ +// Determine the size, in bytes, of a buffer necessary to represent the supplied number +// of seconds of audio data. +int AQRecorder::ComputeRecordBufferSize(const AudioStreamBasicDescription *format, float seconds) +{ + int packets, frames, bytes = 0; + frames = (int)ceil(seconds * format->mSampleRate); + + if (format->mBytesPerFrame > 0) + bytes = frames * format->mBytesPerFrame; + else { + UInt32 maxPacketSize; + if (format->mBytesPerPacket > 0) + maxPacketSize = format->mBytesPerPacket; // constant packet size + else { + UInt32 propertySize = sizeof(maxPacketSize); + errorStatus = AudioQueueGetProperty(mQueue, kAudioQueueProperty_MaximumOutputPacketSize, &maxPacketSize, + &propertySize); + if (errorStatus) { + NSLog(@"ComputeRecordBufferSize error:%ld", errorStatus); + return 0; + } + } + if (format->mFramesPerPacket > 0) + packets = frames / format->mFramesPerPacket; + else + packets = frames; // worst-case scenario: 1 frame in a packet + if (packets == 0) // sanity check + packets = 1; + bytes = packets * maxPacketSize; + } + return bytes; +} + +// ____________________________________________________________________________________ +// AudioQueue callback function, called when an input buffers has been filled. +void AQRecorder::MyInputBufferHandler( void * inUserData, + AudioQueueRef inAQ, + AudioQueueBufferRef inBuffer, + const AudioTimeStamp * inStartTime, + UInt32 inNumPackets, + const AudioStreamPacketDescription* inPacketDesc) +{ + AQRecorder *aqr = (AQRecorder *)inUserData; + + if (inNumPackets > 0) { + + if (aqr->mEncapsulator) { + [aqr->mEncapsulator inputPCMDataFromBuffer:(unsigned char *)inBuffer->mAudioData size:inBuffer->mAudioDataByteSize]; + } + + aqr->mRecordPacket += inNumPackets; + } + + // if we're not stopping, re-enqueue the buffe so that it gets filled again + if (aqr->IsRunning()) { + OSStatus errorStatus = AudioQueueEnqueueBuffer(inAQ, inBuffer, 0, NULL); + if (errorStatus) { + NSLog(@"MyInputBufferHandler error:%ld", errorStatus); + return; + } + } +} + +AQRecorder::AQRecorder() +{ + mIsRunning = false; + mRecordPacket = 0; +} + +AQRecorder::~AQRecorder() +{ + AudioQueueDispose(mQueue, TRUE); +// AudioFileClose(mRecordFile); +// if (mFileName) CFRelease(mFileName); + mEncapsulator = nil; +} + +void AQRecorder::SetupAudioFormat(UInt32 inFormatID) +{ + memset(&mRecordFormat, 0, sizeof(mRecordFormat)); + + mRecordFormat.mFormatID = inFormatID; + if (inFormatID == kAudioFormatLinearPCM) + { + // if we want pcm, default to signed 16-bit little-endian + mRecordFormat.mFormatFlags = kLinearPCMFormatFlagIsSignedInteger | kLinearPCMFormatFlagIsPacked; + mRecordFormat.mBitsPerChannel = 16; + mRecordFormat.mChannelsPerFrame = 1; + mRecordFormat.mBytesPerFrame = (mRecordFormat.mBitsPerChannel / 8) * mRecordFormat.mChannelsPerFrame; + mRecordFormat.mFramesPerPacket = 1; + mRecordFormat.mBytesPerPacket = mRecordFormat.mBytesPerFrame * mRecordFormat.mFramesPerPacket; + + mRecordFormat.mSampleRate = 8000; //8k frames per second + } +} + +Boolean AQRecorder::StartRecord(Encapsulator *encapsulator) { + int i, bufferByteSize; + UInt32 size; + + mEncapsulator = encapsulator; + [mEncapsulator prepareForEncapsulating]; + + // specify the recording format + SetupAudioFormat(kAudioFormatLinearPCM); + + // create the queue + errorStatus = AudioQueueNewInput( + &mRecordFormat, + MyInputBufferHandler, + this /* userData */, + NULL /* run loop */, NULL /* run loop mode */, + 0 /* flags */, &mQueue); + if (errorStatus) { + NSLog(@"StartRecord error:%ld when AudioQueueNewInput ", errorStatus); + return false; + } + + // get the record format back from the queue's audio converter -- + // the file may require a more specific stream description than was necessary to create the encoder. + mRecordPacket = 0; + + size = sizeof(mRecordFormat); + errorStatus = AudioQueueGetProperty(mQueue, kAudioQueueProperty_StreamDescription, + &mRecordFormat, &size); + if (errorStatus) { + NSLog(@"StartRecord error:%ld when AudioQueueGetProperty StreamDescription", errorStatus); + } + + UInt32 val = 1; + errorStatus = AudioQueueSetProperty(mQueue, kAudioQueueProperty_EnableLevelMetering, &val, sizeof(UInt32)); + if (errorStatus) { + NSLog(@"StartRecord error:%ld when AudioQueueGetProperty LevelMetering", errorStatus); + } + + // allocate and enqueue buffers + bufferByteSize = ComputeRecordBufferSize(&mRecordFormat, kBufferDurationSeconds); // enough bytes for half a second + for (i = 0; i < kNumberRecordBuffers; ++i) { + errorStatus = AudioQueueAllocateBuffer(mQueue, bufferByteSize, &mBuffers[i]); + errorStatus = AudioQueueEnqueueBuffer(mQueue, mBuffers[i], 0, NULL); + if (errorStatus) { + NSLog(@"StartRecord error:%ld alloc and enqueue buffer", errorStatus); + } + } + // start the queue + mIsRunning = true; + errorStatus = AudioQueueStart(mQueue, NULL); + if (errorStatus) { + NSLog(@"StartRecord error:%ld", errorStatus); + return false; + } + return true; +} + +void AQRecorder::StopRecord() +{ + // end recording + mIsRunning = false; + errorStatus = AudioQueueStop(mQueue, true); + if (errorStatus) { + NSLog(@"StopRecord error:%ld", errorStatus); + } + AudioQueueDispose(mQueue, true); + + if (mEncapsulator) { + [mEncapsulator stopEncapsulating:NO]; + } + mEncapsulator = nil; + +} diff --git a/ios/IOSDuoduo/Voice/manager/Codec/SpeexAllHeaders.h b/ios/IOSDuoduo/Voice/manager/Codec/SpeexAllHeaders.h new file mode 100755 index 000000000..4c3d888a4 --- /dev/null +++ b/ios/IOSDuoduo/Voice/manager/Codec/SpeexAllHeaders.h @@ -0,0 +1,26 @@ +// +// SpeexAllHeaders.h +// OggSpeex +// +// Created by Jiang Chuncheng on 11/26/12. +// Copyright (c) 2012 Sense Force. All rights reserved. +// + +#ifndef OggSpeex_SpeexAllHeaders_h +#define OggSpeex_SpeexAllHeaders_h + +#import "ogg.h" +#import "os_types.h" +#import "speex.h" +#import "speex_bits.h" +#import "speex_buffer.h" +#import "speex_callbacks.h" +#import "speex_config_types.h" +#import "speex_echo.h" +#import "speex_header.h" +#import "speex_jitter.h" +#import "speex_preprocess.h" +#import "speex_stereo.h" +#import "speex_types.h" + +#endif diff --git a/ios/IOSDuoduo/Voice/manager/Codec/SpeexCodec.h b/ios/IOSDuoduo/Voice/manager/Codec/SpeexCodec.h new file mode 100755 index 000000000..15a8799ea --- /dev/null +++ b/ios/IOSDuoduo/Voice/manager/Codec/SpeexCodec.h @@ -0,0 +1,33 @@ +// +// SpeexCodec.h +// OggSpeex +// +// Created by Jiang Chuncheng on 11/26/12. +// Copyright (c) 2012 Sense Force. All rights reserved. +// + +/**----Guide---- + * Encode: open -> encode:length -> close + * Decode: open -> encode:length:output -> close + */ + +#import +#import "SpeexAllHeaders.h" + +@interface SpeexCodec : NSObject { + int codecOpenedTimes; //the times the codec is opened + + int encodeFrameSize; + int decodeFrameSize; + SpeexBits encodeSpeexBits; + SpeexBits decodeSpeexBits; + void *encodeState; + void *decodeState; +} + +- (void)open:(int)quality; +- (NSData *)encode:(short *)pcmBuffer length:(int)lengthOfShorts; +- (int)decode:(Byte *)encodedBytes length:(int)lengthOfBytes output:(short *)decoded; +- (void)close; + +@end diff --git a/ios/IOSDuoduo/Voice/manager/Codec/SpeexCodec.m b/ios/IOSDuoduo/Voice/manager/Codec/SpeexCodec.m new file mode 100755 index 000000000..274f67263 --- /dev/null +++ b/ios/IOSDuoduo/Voice/manager/Codec/SpeexCodec.m @@ -0,0 +1,101 @@ +// +// SpeexCodec.m +// OggSpeex +// +// Created by Jiang Chuncheng on 11/26/12. +// Copyright (c) 2012 Sense Force. All rights reserved. +// + +#import "SpeexCodec.h" + +@implementation SpeexCodec +- (id)init { + if (self = [super init]) { + codecOpenedTimes = 0; + } + return self; +} + +/* + quality value 1 ~ 10 + */ +- (void)open:(int)quality { + if ((quality < 1) || (quality > 10)) { + return; + } + if (codecOpenedTimes++ != 0) { + return; + } + else { + speex_bits_init(&encodeSpeexBits); + speex_bits_init(&decodeSpeexBits); + + encodeState = speex_encoder_init(&speex_nb_mode); + decodeState = speex_decoder_init(&speex_nb_mode); + + int tmp = quality; + speex_encoder_ctl(encodeState, SPEEX_SET_QUALITY, &tmp); + speex_encoder_ctl(encodeState, SPEEX_GET_FRAME_SIZE, &encodeFrameSize); + speex_decoder_ctl(decodeState, SPEEX_GET_FRAME_SIZE, &decodeFrameSize); + } +} + +- (NSData *)encode:(short *)pcmBuffer length:(int)lengthOfShorts { + if (codecOpenedTimes == 0) { + return nil; + } + + NSMutableData *decodedData = [NSMutableData dataWithCapacity:20]; + + short input_frame[encodeFrameSize]; + char cbits[200]; + int nbBytes; + + speex_bits_reset(&encodeSpeexBits); + + int nSamples = (int)ceil(lengthOfShorts / (float)encodeFrameSize); + + for (int sampleIndex = 0; sampleIndex < nSamples; sampleIndex++) { + memcpy(input_frame, pcmBuffer + (sampleIndex * encodeFrameSize * sizeof(short)), encodeFrameSize * sizeof(short)); + speex_encode_int(encodeState, input_frame, &encodeSpeexBits); + nbBytes = speex_bits_write(&encodeSpeexBits, cbits, encodeFrameSize); + + [decodedData appendBytes:cbits length:nbBytes]; + } + + return decodedData; +} + +- (int)decode:(unsigned char *)encodedBytes length:(int)lengthOfBytes output:(short *)decoded { + if ( ! codecOpenedTimes) + return 0; + + char cbits[200]; + memcpy(cbits, encodedBytes, lengthOfBytes); + + speex_bits_read_from(&decodeSpeexBits, cbits, lengthOfBytes); + + speex_decode_int(decodeState, &decodeSpeexBits, decoded); + + return decodeFrameSize; +} + +- (void)close { + if (--codecOpenedTimes != 0) { + return; + } + + speex_bits_destroy(&encodeSpeexBits); + speex_bits_destroy(&decodeSpeexBits); + speex_encoder_destroy(encodeState); + speex_decoder_destroy(decodeState); +} + +- (void)dealloc { + [self close]; +#if !__has_feature(objc_arc) + [super dealloc]; +#endif +} + +@end \ No newline at end of file diff --git a/ios/IOSDuoduo/Voice/manager/Decapsulator.h b/ios/IOSDuoduo/Voice/manager/Decapsulator.h new file mode 100755 index 000000000..6bf8ca44c --- /dev/null +++ b/ios/IOSDuoduo/Voice/manager/Decapsulator.h @@ -0,0 +1,43 @@ +// +// Decapsulator.h +// OggSpeex +// +// Created by Jiang Chuncheng on 6/25/13. +// Copyright (c) 2013 Sense Force. All rights reserved. +// + +#import +#import +#import "SpeexCodec.h" + +@class RawAudioDataPlayer; + +@protocol DecapsulatingDelegate + +- (void)decapsulatingAndPlayingOver; + +@end + +@interface Decapsulator : NSObject { + NSString *mFileName; + + BOOL isPlaying; + + NSOperationQueue *operationQueue; + + ogg_stream_state oggStreamState; + ogg_sync_state oggSyncState; + int packetNo; +} + +@property (atomic, strong) RawAudioDataPlayer *player; +@property (nonatomic, weak) id delegate; + +//生成对象 +- (id)initWithFileName:(NSString *)filename; + +- (void)play; + +- (void)stopPlaying; + +@end diff --git a/ios/IOSDuoduo/Voice/manager/Decapsulator.m b/ios/IOSDuoduo/Voice/manager/Decapsulator.m new file mode 100755 index 000000000..617e5e5a3 --- /dev/null +++ b/ios/IOSDuoduo/Voice/manager/Decapsulator.m @@ -0,0 +1,209 @@ +// +// Decapsulator.m +// OggSpeex +// +// Created by Jiang Chuncheng on 6/25/13. +// Copyright (c) 2013 Sense Force. All rights reserved. +// + +#import "Decapsulator.h" +#import "RawAudioDataPlayer.h" + +#define DESIRED_BUFFER_SIZE 4096 + +@interface Decapsulator() + +//将ogg格式数据转换为pcm数据 +- (void)convertOggToPCMWithData:(NSData *)oggData; + +//packet转换完成 +- (void)packetDecoded:(Byte *)decodedData size:(int)dataSize; + +- (void)error:(NSString *)errorDesription; + + +@end + +@implementation Decapsulator + + +- (id)initWithFileName:(NSString *)filename { + if (self = [super init]) { + mFileName = [NSString stringWithString:filename]; + NSFileManager *fileManager = [NSFileManager defaultManager]; + if ( ! [fileManager fileExistsAtPath:filename]) { + NSLog(@"要播放的文件不存在:%@", filename); + } + operationQueue = [[NSOperationQueue alloc] init]; + } + return self; +} + +- (void)play { + isPlaying = YES; + + if ( ! self.player) { + self.player = [[RawAudioDataPlayer alloc] init]; + [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(playingingOver:) name:NOTIFICATION_PLAY_OVER object:nil]; + } + [self.player startPlay]; + + NSInvocationOperation *operation = [[NSInvocationOperation alloc] initWithTarget:self selector:@selector(convertOggToPCMWithData:) object:[NSData dataWithContentsOfFile:mFileName]]; + [[[NSOperationQueue alloc] init] addOperation:operation]; + +} + +- (void)stopPlaying { + isPlaying = NO; + if (self.player) { + [self.player stopPlay]; + } +// [self playingingOver:nil]; +} + +#pragma mark - + +//packet转换完成 +- (void)packetDecoded:(Byte *)decodedData size:(int)dataSize { + [self.player inputNewDataFromBuffer:decodedData size:dataSize]; +} + +//将ogg格式数据转换为pcm数据 +- (void )convertOggToPCMWithData:(NSData *)oggData { + const Byte *oggBytes = [oggData bytes]; + int oggByteSize = [oggData length]; + int readedBytes = 0; + NSUInteger decodedByteLength = 0; + + packetNo = 0; + int pageNo = 0; + + ogg_sync_init(&oggSyncState); + ogg_stream_init(&oggStreamState, 0); + + while (isPlaying) { + + int byteSizeToRead = oggByteSize - readedBytes; + if (byteSizeToRead > DESIRED_BUFFER_SIZE) { + byteSizeToRead = DESIRED_BUFFER_SIZE; + } + char *buffer = ogg_sync_buffer(&oggSyncState, DESIRED_BUFFER_SIZE); + memcpy(buffer, oggBytes, byteSizeToRead); //!!! + oggBytes += byteSizeToRead; + readedBytes += byteSizeToRead; + NSLog(@"byteSizeToRead = %d, oggByteSize = %d, readedBytes = %d", byteSizeToRead, oggByteSize, readedBytes); +// oggSyncState.bodybytes = byteSizeToRead; + + int resultSyncWrote = ogg_sync_wrote(&oggSyncState, byteSizeToRead); + if (resultSyncWrote == -1) { + [self error:@"error:the number of bytes written overflows the internal storage of the ogg_sync_state struct or an internal error occurred."]; + return; + } + + while (YES) { + ogg_page oggPage; + int resultSyncPageout= ogg_sync_pageout(&oggSyncState, &oggPage); + if (resultSyncPageout == 1) { + NSLog(@"to decode a page which was synced and returned"); + + //检查header和comment + if(packetNo == 0) { + NSLog(@"it's the header page, check the header later"); + if ([self readOggHeaderToStreamState:&oggStreamState fromOggPage:&oggPage]) { + oggStreamState.packetno = packetNo ++; + pageNo ++; + } + else { + packetNo = 0; + } + continue; + } + else if(packetNo == 1) { + NSLog(@"it's the comment"); + oggStreamState.packetno = packetNo ++; + pageNo ++; + continue; + } + else { + oggStreamState.pageno = pageNo ++; + } + + int resultStreamPagein = ogg_stream_pagein(&oggStreamState, &oggPage); + if (resultStreamPagein == -1) { + [self error:@"ogg_stream_pagein failure"]; + return; + } + + SpeexCodec *codec = [[SpeexCodec alloc] init]; + [codec open:4]; + short decodedBuffer[1024]; + + while (YES) { + ogg_packet oggPacket; + int packetResult = ogg_stream_packetout(&oggStreamState, &oggPacket); + if (packetResult == 1) { + //decode speex +// NSLog(@"to decode a packet"); + packetNo ++; + int nDecodedByte = sizeof(short) * [codec decode:oggPacket.packet length:oggPacket.bytes output:decodedBuffer]; + decodedByteLength += nDecodedByte; + [self packetDecoded:(Byte *)decodedBuffer size:nDecodedByte]; + } + else if (packetResult == 0) { + //need more + break; + } + else { + break; + } + } + + [codec close]; + codec = nil; + } + else if (resultSyncPageout == 0) { + NSLog(@"not enough to decode a page or error"); + break; + } + else { + [self error:@"stream has not yet captured sync"]; + } + } + + if (byteSizeToRead < DESIRED_BUFFER_SIZE) { + break; + } + } + self.player.isDataInputOver = YES; + + NSLog(@"decode ogg to pcm: %d -> %d", [oggData length], decodedByteLength); +} + +- (BOOL)readOggHeaderToStreamState:(ogg_stream_state *)os fromOggPage:(ogg_page *)op { + if (op->body_len != 80) { + return NO; + } +// if ( ! [[NSString stringWithCharacters:(unichar *)op->header length:4] isEqualToString:@"OggS"]) { +// return NO; +// } + os->serialno = ogg_page_serialno(op); + return YES; +} + +- (void)error:(NSString *)errorDesription { + NSLog(@"error:%@", errorDesription); +} + +- (void)dealloc { + [[NSNotificationCenter defaultCenter] removeObserver:self]; +} + +#pragma mark - DecapsulatingDelegate + +- (void)playingingOver:(NSNotification *)notification { + if (self.delegate) { + [self.delegate decapsulatingAndPlayingOver]; + } +} + +@end diff --git a/ios/IOSDuoduo/Voice/manager/Encapsulator.h b/ios/IOSDuoduo/Voice/manager/Encapsulator.h new file mode 100755 index 000000000..fcfffb883 --- /dev/null +++ b/ios/IOSDuoduo/Voice/manager/Encapsulator.h @@ -0,0 +1,132 @@ +// +// Encapsulator.h +// OggSpeex +// +// Created by Jiang Chuncheng on 6/25/13. +// Copyright (c) 2013 Sense Force. All rights reserved. +// + +#import +#import "SpeexCodec.h" + +#define FRAME_SIZE 160 // PCM音频8khz*20ms -> 8000*0.02=160 + +@class EncapsulatingOperation; + +@protocol EncapsulatingDelegate + +- (void)encapsulatingOver; + +@end + +@interface Encapsulator : NSObject { + + NSMutableData *bufferData; //用于ogg文件输出 + NSMutableData *tempData; //用于输入的pcm切割剩余 + + NSMutableArray *pcmDatas; + + NSOperationQueue *operationQueue; + EncapsulatingOperation *encapsulationOperation; + NSString *mFileName; + + int mode; + int sampleRate; + int channels; + int nframes; + BOOL vbr; + int streamSeraialNmber; + + BOOL moreDataInputing, isCanceled; //moreDataInputing是否继续封装;isCanceled,是否强制停止封装 + + SpeexHeader speexHeader; + + id delegate; + + + // + +} +//@property (atomic, retain) NSMutableData *bufferData; +@property (assign) BOOL moreDataInputing, isCanceled; +@property (readonly) SpeexHeader speexHeader; +@property (readonly, retain) NSString *mFileName; + +@property (nonatomic, weak) id delegete; + +@property int mode; +@property int sampleRate; +@property int channels; +@property int nframes; +@property BOOL vbr; + +@property int streamSeraialNmber; + +void writeInt(unsigned char *dest, int offset, int value); + +void writeString(unsigned char *dest, int offset, unsigned char *value, int length); + ++ (NSString *)defaultFileName; + +//生成对象 +- (id)initWithFileName:(NSString *)filename; + +- (void)resetWithFileName:(NSString *)filename; + +- (NSMutableData *)getBufferData; + +- (NSMutableArray *)getPCMDatas; + +//设置参数 +- (void)setMode:(int)_mode sampleRate:(int)_sampleRate channels:(int)_channels frames:(int)_nframes vbr:(BOOL)_vbr; + +//输入新PCM数据。注意数据同步 +- (void)inputPCMDataFromBuffer:(Byte *)buffer size:(UInt32)dataSize; + +//停止封装。是否强制结束未完成的封装 +- (void)stopEncapsulating:(BOOL)forceCancel; + +//为即将开始的封装做准备,包括写入ogg的头 +- (void)prepareForEncapsulating; + +@end + +@interface EncapsulatingOperation : NSOperation { + + Encapsulator *mParent; + + NSMutableArray *oggPeckets; + + ogg_stream_state oggStreamState; + ogg_page oggPage; + + int isFirstInput; + ogg_int64_t mPacketCount; + ogg_int16_t mGranulepos; + + // + NSMutableData* _data; + +} + +@property (nonatomic, retain) Encapsulator *mParent; + +//初始化NSOperation +- (id)initWithParent:(Encapsulator *)parent; + +//写入ogg的头以及comment +- (void)writeHeaderWithComment:(NSString *)comment; + +//从编码好的数据中输出ogg packet +- (void)inputOggPacketFromSpeexData:(NSData *)data; + +//检查packet是否足够生成一个page +- (void)checkPageSufficient; + +//将页保存至文件并重置一些计数器。是否关闭文件。 +- (void)outputAPage:(BOOL)isHeaderOrComment endOfSteam:(BOOL)endOfStream; + +//将新的数据添加到音频文件末尾 +- (void)writeDataToFile:(NSData *)newData; + +@end diff --git a/ios/IOSDuoduo/Voice/manager/Encapsulator.m b/ios/IOSDuoduo/Voice/manager/Encapsulator.m new file mode 100755 index 000000000..9f672c010 --- /dev/null +++ b/ios/IOSDuoduo/Voice/manager/Encapsulator.m @@ -0,0 +1,338 @@ +// +// Encapsulator.m +// OggSpeex +// +// Created by Jiang Chuncheng on 6/25/13. +// Copyright (c) 2013 Sense Force. All rights reserved. +// + +#import "Encapsulator.h" + +#define NOTIFICATION_ENCAPSULTING_OVER @"EncapsulatingOver" + +@implementation Encapsulator + +@synthesize moreDataInputing,isCanceled; +@synthesize speexHeader; +@synthesize mode, sampleRate, channels, nframes, vbr, streamSeraialNmber; +@synthesize mFileName; +@synthesize delegete; + +void writeInt(unsigned char *dest, int offset, int value) { + for(int i = 0;i < 4;i++) { + dest[offset + i]=(unsigned char)(0xff & ((unsigned int)value)>>(i*8)); + } +} + +void writeString(unsigned char *dest, int offset, unsigned char *value, int length) { + unsigned char *tempPointr = dest + offset; + memcpy(tempPointr, value, length); +} + ++ (NSString *)defaultFileName { + NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES); + NSString *documentsDirectory = [paths objectAtIndex:0]; + NSString *voiceDirectory = [documentsDirectory stringByAppendingPathComponent:@"voice"]; + if ( ! [[NSFileManager defaultManager] fileExistsAtPath:voiceDirectory]) { + [[NSFileManager defaultManager] createDirectoryAtPath:voiceDirectory withIntermediateDirectories:YES attributes:nil error:NULL]; + } + return [voiceDirectory stringByAppendingPathComponent:[NSString stringWithFormat:@"%f.spx", [[NSDate date] timeIntervalSince1970]]]; + +} + +- (id)initWithFileName:(NSString *)filename { + if (self = [super init]) { + mFileName = [NSString stringWithString:filename]; + NSFileManager *fileManager = [NSFileManager defaultManager]; + if ([fileManager fileExistsAtPath:filename]) { + [fileManager removeItemAtPath:filename error:nil]; + } + bufferData = [NSMutableData data]; + tempData = [NSMutableData data]; + pcmDatas = [NSMutableArray array]; + + [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(encapsulatingOver:) name:NOTIFICATION_ENCAPSULTING_OVER object:nil]; + + [self setMode:0 sampleRate:8000 channels:1 frames:1 vbr:YES]; + + NSLog(@"size of version(%s)",speexHeader.speex_version); + speex_init_header(&speexHeader, sampleRate, channels, &speex_nb_mode); + + NSLog(@"size of version(%s)",speexHeader.speex_version); + + operationQueue = [[NSOperationQueue alloc] init]; + } + return self; +} + +- (void)resetWithFileName:(NSString *)filename { + for(NSOperation *operation in [operationQueue operations]) { + [operation cancel]; + } + mFileName = [NSString stringWithString:filename]; + NSFileManager *fileManager = [NSFileManager defaultManager]; + if ([fileManager fileExistsAtPath:filename]) { + [fileManager removeItemAtPath:filename error:nil]; + } + + [bufferData setLength:0]; + [tempData setLength:0]; + [pcmDatas removeAllObjects]; +} + +- (NSMutableData *)getBufferData { + return bufferData; +} + +- (NSMutableArray *)getPCMDatas { + @synchronized(pcmDatas) { + return pcmDatas; + } +} + + +- (void)setMode:(int)_mode sampleRate:(int)_sampleRate channels:(int)_channels frames:(int)_nframes vbr:(BOOL)_vbr { + self.mode = _mode; + self.sampleRate = _sampleRate; + self.channels = _channels; + self.nframes = _nframes; + self.vbr = _vbr; + +} + +- (void)prepareForEncapsulating { + + self.moreDataInputing = YES; + self.isCanceled = NO; + encapsulationOperation = [[EncapsulatingOperation alloc] initWithParent:self]; + if (operationQueue) { + [operationQueue addOperation:encapsulationOperation]; + } + + //写入一些数据之前的头 + [encapsulationOperation writeHeaderWithComment:@"Encoded with:test by jcccn "]; + +} + +- (void)inputPCMDataFromBuffer:(Byte *)buffer size:(UInt32)dataSize { + + if ( ! self.moreDataInputing) { + return; + } + int packetSize = FRAME_SIZE * 2; + @synchronized(pcmDatas) { + [tempData appendBytes:buffer length:dataSize]; + while ([tempData length] >= packetSize) { + @autoreleasepool { + NSData *pcmData = [NSData dataWithBytes:[tempData bytes] length:packetSize]; + [pcmDatas addObject:pcmData]; + + Byte *dataPtr = (Byte *)[tempData bytes]; + dataPtr += packetSize; + tempData = [NSMutableData dataWithBytesNoCopy:dataPtr length:[tempData length] - packetSize freeWhenDone:NO]; + + } + } + } +} + +- (void)stopEncapsulating:(BOOL)forceCancel { + self.moreDataInputing = NO; + if ( ! self.isCanceled) { + self.isCanceled = forceCancel; + } +} + +- (void)encapsulatingOver:(NSNotification *)notification { + NSLog(@"encapsulatingOver by %@", [self description]); + if (self.delegete) { + [self.delegete encapsulatingOver]; + } +} + +- (void)dealloc { + [[NSNotificationCenter defaultCenter] removeObserver:self]; +} + +@end + +@implementation EncapsulatingOperation + +@synthesize mParent; + +//不停从bufferData中获取数据构建paket并且修改相关计数器 +- (void)main { + SpeexCodec *codec = [[SpeexCodec alloc] init]; + [codec open:4]; //压缩率为4 + while ( ! self.mParent.isCanceled) { + if ([[self.mParent getPCMDatas] count] > 0) { + NSData *pcmData = [[self.mParent getPCMDatas] objectAtIndex:0]; + + NSData *speexData = [codec encode:(short *)[pcmData bytes] length:[pcmData length]/sizeof(short)]; + + [self inputOggPacketFromSpeexData:speexData]; + + if ([[self.mParent getPCMDatas] count] > 0) + { + [[self.mParent getPCMDatas] removeObjectAtIndex:0]; + } + } + else { + [NSThread sleepForTimeInterval:0.02]; + + if ( ! [self.mParent moreDataInputing]) { + break; + } + } + + } + [codec close]; + codec = nil; + if ( ! [self.mParent isCanceled]) { + [self outputAPage:NO endOfSteam:YES]; + [[NSNotificationCenter defaultCenter] postNotificationName:NOTIFICATION_ENCAPSULTING_OVER object:self userInfo:nil]; + } +} + +//初始化NSOperation +- (id)initWithParent:(Encapsulator *)parent { + if (self = [super init]) { + self.mParent = parent; + + isFirstInput = 1; + mPacketCount = 0; + mGranulepos = 0; + + oggPeckets = [NSMutableArray array]; + + ogg_stream_init(&oggStreamState, arc4random()%8888); + } + return self; +} + + +//写入ogg的头以及comment +- (void)writeHeaderWithComment:(NSString *)comment { + + mPacketCount = 0; + mGranulepos = 0; + + //first, write the ogg header page + unsigned char speexHeader[80]; + + int offset = 0; + writeString(speexHeader, offset+0, (unsigned char *)"Speex ", 8); // 0 - 7: speex_string + int versionSize = sizeof(self.mParent.speexHeader.speex_version); + NSLog(@"size of version(%s) chars array:%d",self.mParent.speexHeader.speex_version, versionSize); + writeString(speexHeader, offset+8, (unsigned char *)self.mParent.speexHeader.speex_version, versionSize); //8 - 27: speex_version + writeInt(speexHeader, offset+28, 1); // 28 - 31: speex_version_id + writeInt(speexHeader, offset+32, 80); // 32 - 35: header_size + writeInt(speexHeader, offset+36, 8000); // 36 - 39: rate + writeInt(speexHeader, offset+40, 0); // 40 - 43: mode (0=NB, 1=WB, 2=UWB) + writeInt(speexHeader, offset+44, 4); // 44 - 47: mode_bitstream_version + writeInt(speexHeader, offset+48, 1); // 48 - 51: nb_channels + writeInt(speexHeader, offset+52, -1); // 52 - 55: bitrate + writeInt(speexHeader, offset+56, 160 << 0); // 56 - 59: frame_size (NB=160, WB=320, UWB=640) + writeInt(speexHeader, offset+60, 1); // 60 - 63: vbr + writeInt(speexHeader, offset+64, 1); // 64 - 67: frames_per_packet + writeInt(speexHeader, offset+68, 0); // 68 - 71: extra_headers + writeInt(speexHeader, offset+72, 0); // 72 - 75: reserved1 + writeInt(speexHeader, offset+76, 0); // 76 - 79: reserved2 + + ogg_packet speexHeaderPacket; + speexHeaderPacket.packet = (unsigned char *)speexHeader; + speexHeaderPacket.bytes = 80; + speexHeaderPacket.b_o_s = 1; + speexHeaderPacket.e_o_s = 0; + speexHeaderPacket.granulepos = 0; + speexHeaderPacket.packetno = mPacketCount++; + + ogg_stream_packetin(&oggStreamState, &speexHeaderPacket); + [self outputAPage:YES endOfSteam:NO]; + NSLog(@"ogg header writed\n"); + + + + //second. write the ogg comment page + offset = 0; + const char *commentChars = [comment cStringUsingEncoding:NSUTF8StringEncoding]; + int length = [comment lengthOfBytesUsingEncoding:NSUTF8StringEncoding]; + unsigned char speexCommentHeader[length + 8]; + writeInt(speexCommentHeader, offset, length); // vendor comment size + writeString(speexCommentHeader, offset+4, (unsigned char *)commentChars, length); // vendor comment + writeInt(speexCommentHeader, offset+length+4, 0); // user comment list length + + ogg_packet speexCommentPacket; + speexCommentPacket.packet = (unsigned char *)speexCommentHeader; + speexCommentPacket.bytes = length + 8; + speexCommentPacket.b_o_s = 0; + speexCommentPacket.e_o_s = 0; + speexCommentPacket.granulepos = 0; + speexCommentPacket.packetno = mPacketCount++; + + ogg_stream_packetin(&oggStreamState, &speexCommentPacket); + [self outputAPage:YES endOfSteam:NO]; + NSLog(@"ogg comment writed\n"); +} + +- (void)inputOggPacketFromSpeexData:(NSData *)data { + ogg_packet packet; + packet.packet = (unsigned char *)[data bytes]; + packet.bytes = (long)([data length]); + packet.b_o_s = 0; + packet.e_o_s = 0; + mGranulepos += FRAME_SIZE; + packet.granulepos = mGranulepos; + packet.packetno = mPacketCount++; + ogg_stream_packetin(&oggStreamState, &packet); + + [self checkPageSufficient]; +} + +//检查packet是否足够生成一个page +- (void)checkPageSufficient { + [self outputAPage:NO endOfSteam:NO]; +} + +//将页保存至文件并重置一些计数器。是否关闭文件。 +- (void)outputAPage:(BOOL)isHeaderOrComment endOfSteam:(BOOL)endOfStream { + if (isHeaderOrComment || endOfStream) { + ogg_stream_flush(&oggStreamState, &oggPage); + [[self.mParent getBufferData] appendBytes:oggPage.header length:oggPage.header_len]; + [[self.mParent getBufferData] appendBytes:oggPage.body length:oggPage.body_len]; + [self writeDataToFile:[self.mParent getBufferData]]; + [[self.mParent getBufferData] setLength:0]; + + if (endOfStream) { + NSLog(@"end of stream"); +// self.mParent.moreDataInputing = NO; + } + } + else { + if (ogg_stream_pageout(&oggStreamState, &oggPage)) { + NSLog(@"page out"); + [[self.mParent getBufferData] appendBytes:oggPage.header length:oggPage.header_len]; + [[self.mParent getBufferData] appendBytes:oggPage.body length:oggPage.body_len]; + [self writeDataToFile:[self.mParent getBufferData]]; + + [[self.mParent getBufferData] setLength:0]; + } + } + +} + +- (void)writeDataToFile:(NSData *)newData { + NSString *filename = (NSString *)self.mParent.mFileName; + NSFileManager *fileManager = [NSFileManager defaultManager]; + if ( ! [fileManager fileExistsAtPath:filename]) { + [fileManager createFileAtPath:filename contents:nil attributes:nil]; + } +// NSLog(@"write data of %d bytes to file %@", [newData length], filename); + NSFileHandle *file = [NSFileHandle fileHandleForUpdatingAtPath:filename]; + [file seekToEndOfFile]; + [file writeData:newData]; + [file closeFile]; +} + + +@end \ No newline at end of file diff --git a/ios/IOSDuoduo/Voice/manager/PlayerManager.h b/ios/IOSDuoduo/Voice/manager/PlayerManager.h new file mode 100755 index 000000000..76df96cf4 --- /dev/null +++ b/ios/IOSDuoduo/Voice/manager/PlayerManager.h @@ -0,0 +1,41 @@ +// +// PlayerManager.h +// OggSpeex +// +// Created by Jiang Chuncheng on 6/25/13. +// Copyright (c) 2013 Sense Force. All rights reserved. +// + +#import +#import +#import "Decapsulator.h" + +typedef NS_ENUM(NSUInteger, PlayerType) +{ + DDEarPhone, + DDSpeaker +}; + +@protocol PlayingDelegate + +- (void)playingStoped; + +@end + +@interface PlayerManager : NSObject { + Decapsulator *decapsulator; + AVAudioPlayer *avAudioPlayer; + +} +@property (nonatomic, strong) Decapsulator *decapsulator; +@property (nonatomic, strong) AVAudioPlayer *avAudioPlayer; +@property (nonatomic, weak) id delegate; + ++ (PlayerManager *)sharedManager; + +- (void)playAudioWithFileName:(NSString *)filename delegate:(id)newDelegate; +- (void)stopPlaying; + +- (void)playAudioWithFileName:(NSString *)filename playerType:(PlayerType)type delegate:(id)newDelegate; +- (BOOL)playingFileName:(NSString*)fileName; +@end diff --git a/ios/IOSDuoduo/Voice/manager/PlayerManager.m b/ios/IOSDuoduo/Voice/manager/PlayerManager.m new file mode 100755 index 000000000..485a8a5a4 --- /dev/null +++ b/ios/IOSDuoduo/Voice/manager/PlayerManager.m @@ -0,0 +1,280 @@ +// +// PlayerManager.m +// OggSpeex +// +// Created by Jiang Chuncheng on 6/25/13. +// Copyright (c) 2013 Sense Force. All rights reserved. +// + +#import "PlayerManager.h" + +@interface PlayerManager () + +- (void)startProximityMonitering; //开启距离感应器监听(开始播放时) +- (void)stopProximityMonitering; //关闭距离感应器监听(播放完成时) + +@end + +@implementation PlayerManager +{ + NSString* _playingFileName; +} +@synthesize decapsulator; +@synthesize avAudioPlayer; + +static PlayerManager *mPlayerManager = nil; + ++ (PlayerManager *)sharedManager { + static PlayerManager *g_playerManager; + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^{ + g_playerManager = [[PlayerManager alloc] init]; + }); + return g_playerManager; +// @synchronized(self) { +// if (mPlayerManager == nil) +// { +// mPlayerManager = [[PlayerManager alloc] init]; +// +// [[NSNotificationCenter defaultCenter] addObserver:mPlayerManager +// selector:@selector(sensorStateChange:) +// name:@"UIDeviceProximityStateDidChangeNotification" +// object:nil]; +// } +// } +// return mPlayerManager; +} + ++ (id)allocWithZone:(NSZone *)zone +{ + @synchronized(self) + { + if(mPlayerManager == nil) + { + mPlayerManager = [super allocWithZone:zone]; + return mPlayerManager; + } + } + + return nil; +} + +- (id)init { + if (self = [super init]) { + + [[NSNotificationCenter defaultCenter] addObserver:mPlayerManager + selector:@selector(sensorStateChange:) + name:@"UIDeviceProximityStateDidChangeNotification" + object:nil]; + + //初始化播放器的时候如下设置 + UInt32 sessionCategory = kAudioSessionCategory_MediaPlayback; + AudioSessionSetProperty(kAudioSessionProperty_AudioCategory, sizeof(sessionCategory), &sessionCategory); + UInt32 audioRouteOverride = kAudioSessionOverrideAudioRoute_Speaker; + AudioSessionSetProperty(kAudioSessionProperty_OverrideAudioRoute, sizeof(audioRouteOverride), &audioRouteOverride); + + AVAudioSession *audioSession = [AVAudioSession sharedInstance]; + //默认情况下扬声器播放 + [audioSession setCategory:AVAudioSessionCategoryPlayback error:nil]; + [audioSession setActive:YES error:nil]; + } + return self; +} + +- (void)playAudioWithFileName:(NSString *)filename delegate:(id)newDelegate { + if ( ! filename) { + return; + } + if ([filename rangeOfString:@".spx"].location != NSNotFound) { + [[AVAudioSession sharedInstance] setActive:YES error:nil]; + + [self stopPlaying]; + + self.delegate = newDelegate; + + self.decapsulator = [[Decapsulator alloc] initWithFileName:filename]; + self.decapsulator.delegate = self; + [[AVAudioSession sharedInstance] setCategory:AVAudioSessionCategoryPlayback error:nil]; + [self startProximityMonitering]; + _playingFileName = [filename copy]; + [self.decapsulator play]; + + } + else if ([filename rangeOfString:@".mp3"].location != NSNotFound) { + if ( ! [[NSFileManager defaultManager] fileExistsAtPath:filename]) { + NSLog(@"要播放的文件不存在:%@", filename); + _playingFileName = nil; + [self.delegate playingStoped]; + [newDelegate playingStoped]; + return; + } + [self.delegate playingStoped]; + self.delegate = newDelegate; + + NSError *error; + self.avAudioPlayer = [[AVAudioPlayer alloc] initWithContentsOfURL:[NSURL URLWithString:filename] error:&error]; + if (self.avAudioPlayer) { + [[AVAudioSession sharedInstance] setCategory:AVAudioSessionCategoryPlayback error:nil]; + [[AVAudioSession sharedInstance] setActive:YES error:nil]; + self.avAudioPlayer.delegate = self; + _playingFileName = [filename copy]; + [self.avAudioPlayer play]; + [self startProximityMonitering]; + } + else { + [self.delegate playingStoped]; + } + } + else { + [self.delegate playingStoped]; + } +} + +- (void)playAudioWithFileName:(NSString *)filename playerType:(PlayerType)type delegate:(id)newDelegate +{ + [[AVAudioSession sharedInstance] setActive:YES error:nil]; + if ([filename rangeOfString:@".spx"].location != NSNotFound) { + [self stopPlaying]; + self.delegate = newDelegate; + + self.decapsulator = [[Decapsulator alloc] initWithFileName:filename]; + self.decapsulator.delegate = self; + [self.decapsulator play]; + + } + else if ([filename rangeOfString:@".mp3"].location != NSNotFound) { + if ( ! [[NSFileManager defaultManager] fileExistsAtPath:filename]) { + NSLog(@"要播放的文件不存在:%@", filename); + _playingFileName = nil; + [self.delegate playingStoped]; + [newDelegate playingStoped]; + return; + } + _playingFileName = nil; + [self.delegate playingStoped]; + self.delegate = newDelegate; + + NSError *error; + self.avAudioPlayer = [[AVAudioPlayer alloc] initWithContentsOfURL:[NSURL URLWithString:filename] error:&error]; + if (self.avAudioPlayer) { + self.avAudioPlayer.delegate = self; + [self.avAudioPlayer play]; + } + else { + _playingFileName = nil; + [self.delegate playingStoped]; + } + }else if([filename rangeOfString:@".caf"].location != NSNotFound) + { + // if ( ! [[NSFileManager defaultManager] fileExistsAtPath:filename]) { + // NSLog(@"要播放的文件不存在:%@", filename); + // [self.delegate playingStoped]; + // [newDelegate playingStoped]; + // return; + // } + _playingFileName = nil; + [self.delegate playingStoped]; + self.delegate = newDelegate; + + NSError *error; + NSArray *array =[filename componentsSeparatedByString:@"."]; + NSString *bundlePath=[[NSBundle mainBundle]pathForResource:@"Resource" ofType:@"bundle"]; + NSBundle *bundle=[NSBundle bundleWithPath:bundlePath]; + NSString *soundPath=[bundle pathForResource:array[0] ofType:@"caf"inDirectory:nil]; + if (soundPath ==nil) { + NSLog(@"要播放的文件不存在:%@", filename); + [self.delegate playingStoped]; + [newDelegate playingStoped]; + return; + } + NSURL *soundUrl=[[NSURL alloc] initFileURLWithPath:soundPath]; + self.avAudioPlayer = [[AVAudioPlayer alloc] initWithContentsOfURL:soundUrl error:&error]; + if (self.avAudioPlayer) { + self.avAudioPlayer.delegate = self; + [self.avAudioPlayer play]; + } + else { + _playingFileName = nil; + [self.delegate playingStoped]; + } + } + else { + _playingFileName = nil; + [self.delegate playingStoped]; + } + + switch (type) + { + case DDEarPhone: + //听筒 + [[AVAudioSession sharedInstance] setCategory:AVAudioSessionCategoryPlayAndRecord error:nil]; + break; + case DDSpeaker: + //扬声器 + [[AVAudioSession sharedInstance] setCategory:AVAudioSessionCategoryPlayback error:nil]; + break; + default: + break; + } +} + +- (void)stopPlaying { + _playingFileName = nil; + [self stopProximityMonitering]; + + if (self.decapsulator) { + [self.decapsulator stopPlaying]; +// self.decapsulator.delegate = nil; //此行如果放在上一行之前会导致回调问题 + self.decapsulator = nil; + } + if (self.avAudioPlayer) { + [self.avAudioPlayer stop]; + self.avAudioPlayer = nil; + +// [self.delegate playingStoped]; + } + + [self.delegate playingStoped]; +} + +- (BOOL)playingFileName:(NSString *)fileName +{ + return [_playingFileName isEqualToString:fileName]; +} + +- (void)decapsulatingAndPlayingOver { + _playingFileName = nil; + [self.delegate playingStoped]; + [self stopProximityMonitering]; +} + +- (void)sensorStateChange:(NSNotification *)notification { + //如果此时手机靠近面部放在耳朵旁,那么声音将通过听筒输出,并将屏幕变暗 + if ([[UIDevice currentDevice] proximityState] == YES) { + NSLog(@"Device is close to user"); + [[AVAudioSession sharedInstance] setCategory:AVAudioSessionCategoryPlayAndRecord error:nil]; + } + else { + NSLog(@"Device is not close to user"); + [[AVAudioSession sharedInstance] setCategory:AVAudioSessionCategoryPlayback error:nil]; + } +} + +- (void)startProximityMonitering { + [[UIDevice currentDevice] setProximityMonitoringEnabled:YES]; + NSLog(@"开启距离监听"); +} + +- (void)stopProximityMonitering { +// dispatch_async(dispatch_get_main_queue(), ^{ + [[AVAudioSession sharedInstance] setCategory:AVAudioSessionCategoryPlayback error:nil]; + [[UIDevice currentDevice] setProximityMonitoringEnabled:NO]; + NSLog(@"关闭距离监听"); +// }); +} + +- (void)dealloc { + [[NSNotificationCenter defaultCenter] removeObserver:self]; +} + +@end diff --git a/ios/IOSDuoduo/Voice/manager/PublicUtility/CADebugMacros.cpp b/ios/IOSDuoduo/Voice/manager/PublicUtility/CADebugMacros.cpp new file mode 100755 index 000000000..d5a4806fc --- /dev/null +++ b/ios/IOSDuoduo/Voice/manager/PublicUtility/CADebugMacros.cpp @@ -0,0 +1,88 @@ +/* + File: CADebugMacros.cpp + Abstract: CADebugMacros.h + Version: 2.5 + + Disclaimer: IMPORTANT: This Apple software is supplied to you by Apple + Inc. ("Apple") in consideration of your agreement to the following + terms, and your use, installation, modification or redistribution of + this Apple software constitutes acceptance of these terms. If you do + not agree with these terms, please do not use, install, modify or + redistribute this Apple software. + + In consideration of your agreement to abide by the following terms, and + subject to these terms, Apple grants you a personal, non-exclusive + license, under Apple's copyrights in this original Apple software (the + "Apple Software"), to use, reproduce, modify and redistribute the Apple + Software, with or without modifications, in source and/or binary forms; + provided that if you redistribute the Apple Software in its entirety and + without modifications, you must retain this notice and the following + text and disclaimers in all such redistributions of the Apple Software. + Neither the name, trademarks, service marks or logos of Apple Inc. may + be used to endorse or promote products derived from the Apple Software + without specific prior written permission from Apple. Except as + expressly stated in this notice, no other rights or licenses, express or + implied, are granted by Apple herein, including but not limited to any + patent rights that may be infringed by your derivative works or by other + works in which the Apple Software may be incorporated. + + The Apple Software is provided by Apple on an "AS IS" basis. APPLE + MAKES NO WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION + THE IMPLIED WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS + FOR A PARTICULAR PURPOSE, REGARDING THE APPLE SOFTWARE OR ITS USE AND + OPERATION ALONE OR IN COMBINATION WITH YOUR PRODUCTS. + + IN NO EVENT SHALL APPLE BE LIABLE FOR ANY SPECIAL, INDIRECT, INCIDENTAL + OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + INTERRUPTION) ARISING IN ANY WAY OUT OF THE USE, REPRODUCTION, + MODIFICATION AND/OR DISTRIBUTION OF THE APPLE SOFTWARE, HOWEVER CAUSED + AND WHETHER UNDER THEORY OF CONTRACT, TORT (INCLUDING NEGLIGENCE), + STRICT LIABILITY OR OTHERWISE, EVEN IF APPLE HAS BEEN ADVISED OF THE + POSSIBILITY OF SUCH DAMAGE. + + Copyright (C) 2012 Apple Inc. All Rights Reserved. + +*/ +#include "CADebugMacros.h" +#include +#include +#if TARGET_API_MAC_OSX + #include +#endif + +#if DEBUG +#include + +void DebugPrint(const char *fmt, ...) +{ + va_list args; + va_start(args, fmt); + vprintf(fmt, args); + va_end(args); +} +#endif // DEBUG + +#if TARGET_API_MAC_OSX +void LogError(const char *fmt, ...) +{ + va_list args; + va_start(args, fmt); +#if DEBUG + vprintf(fmt, args); +#endif + vsyslog(LOG_ERR, fmt, args); + va_end(args); +} + +void LogWarning(const char *fmt, ...) +{ + va_list args; + va_start(args, fmt); +#if DEBUG + vprintf(fmt, args); +#endif + vsyslog(LOG_WARNING, fmt, args); + va_end(args); +} +#endif diff --git a/ios/IOSDuoduo/Voice/manager/PublicUtility/CADebugMacros.h b/ios/IOSDuoduo/Voice/manager/PublicUtility/CADebugMacros.h new file mode 100755 index 000000000..bf8c3cf8c --- /dev/null +++ b/ios/IOSDuoduo/Voice/manager/PublicUtility/CADebugMacros.h @@ -0,0 +1,604 @@ +/* + File: CADebugMacros.h + Abstract: Part of CoreAudio Utility Classes + Version: 2.5 + + Disclaimer: IMPORTANT: This Apple software is supplied to you by Apple + Inc. ("Apple") in consideration of your agreement to the following + terms, and your use, installation, modification or redistribution of + this Apple software constitutes acceptance of these terms. If you do + not agree with these terms, please do not use, install, modify or + redistribute this Apple software. + + In consideration of your agreement to abide by the following terms, and + subject to these terms, Apple grants you a personal, non-exclusive + license, under Apple's copyrights in this original Apple software (the + "Apple Software"), to use, reproduce, modify and redistribute the Apple + Software, with or without modifications, in source and/or binary forms; + provided that if you redistribute the Apple Software in its entirety and + without modifications, you must retain this notice and the following + text and disclaimers in all such redistributions of the Apple Software. + Neither the name, trademarks, service marks or logos of Apple Inc. may + be used to endorse or promote products derived from the Apple Software + without specific prior written permission from Apple. Except as + expressly stated in this notice, no other rights or licenses, express or + implied, are granted by Apple herein, including but not limited to any + patent rights that may be infringed by your derivative works or by other + works in which the Apple Software may be incorporated. + + The Apple Software is provided by Apple on an "AS IS" basis. APPLE + MAKES NO WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION + THE IMPLIED WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS + FOR A PARTICULAR PURPOSE, REGARDING THE APPLE SOFTWARE OR ITS USE AND + OPERATION ALONE OR IN COMBINATION WITH YOUR PRODUCTS. + + IN NO EVENT SHALL APPLE BE LIABLE FOR ANY SPECIAL, INDIRECT, INCIDENTAL + OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + INTERRUPTION) ARISING IN ANY WAY OUT OF THE USE, REPRODUCTION, + MODIFICATION AND/OR DISTRIBUTION OF THE APPLE SOFTWARE, HOWEVER CAUSED + AND WHETHER UNDER THEORY OF CONTRACT, TORT (INCLUDING NEGLIGENCE), + STRICT LIABILITY OR OTHERWISE, EVEN IF APPLE HAS BEEN ADVISED OF THE + POSSIBILITY OF SUCH DAMAGE. + + Copyright (C) 2012 Apple Inc. All Rights Reserved. + +*/ +#if !defined(__CADebugMacros_h__) +#define __CADebugMacros_h__ + +//============================================================================= +// Includes +//============================================================================= + +#if !defined(__COREAUDIO_USE_FLAT_INCLUDES__) + #include +#else + #include "CoreAudioTypes.h" +#endif + +//============================================================================= +// CADebugMacros +//============================================================================= + +//#define CoreAudio_StopOnFailure 1 +//#define CoreAudio_TimeStampMessages 1 +//#define CoreAudio_ThreadStampMessages 1 +//#define CoreAudio_FlushDebugMessages 1 + +#if TARGET_RT_BIG_ENDIAN + #define CA4CCToCString(the4CC) { ((char*)&the4CC)[0], ((char*)&the4CC)[1], ((char*)&the4CC)[2], ((char*)&the4CC)[3], 0 } + #define CACopy4CCToCString(theCString, the4CC) { theCString[0] = ((char*)&the4CC)[0]; theCString[1] = ((char*)&the4CC)[1]; theCString[2] = ((char*)&the4CC)[2]; theCString[3] = ((char*)&the4CC)[3]; theCString[4] = 0; } +#else + #define CA4CCToCString(the4CC) { ((char*)&the4CC)[3], ((char*)&the4CC)[2], ((char*)&the4CC)[1], ((char*)&the4CC)[0], 0 } + #define CACopy4CCToCString(theCString, the4CC) { theCString[0] = ((char*)&the4CC)[3]; theCString[1] = ((char*)&the4CC)[2]; theCString[2] = ((char*)&the4CC)[1]; theCString[3] = ((char*)&the4CC)[0]; theCString[4] = 0; } +#endif + +// This is a macro that does a sizeof and casts the result to a UInt32. This is useful for all the +// places where -wshorten64-32 catches assigning a sizeof expression to a UInt32. +// For want of a better place to park this, we'll park it here. +#define SizeOf32(X) ((UInt32)sizeof(X)) + +// This is a macro that does a offsetof and casts the result to a UInt32. This is useful for all the +// places where -wshorten64-32 catches assigning an offsetof expression to a UInt32. +// For want of a better place to park this, we'll park it here. +#define OffsetOf32(X, Y) ((UInt32)offsetof(X, Y)) + +// This macro casts the expression to a UInt32. It is called out specially to allow us to track casts +// that have been added purely to avert -wshorten64-32 warnings on 64 bit platforms. +// For want of a better place to park this, we'll park it here. +#define ToUInt32(X) ((UInt32)(X)) + +#pragma mark Basic Definitions + +#if DEBUG || CoreAudio_Debug + // can be used to break into debugger immediately, also see CADebugger + #define BusError() (*(long *)0 = 0) + + // basic debugging print routines + #if TARGET_OS_MAC && !TARGET_API_MAC_CARBON + extern void DebugStr(const unsigned char* debuggerMsg); + #define DebugMessage(msg) DebugStr("\p"msg) + #define DebugMessageN1(msg, N1) + #define DebugMessageN2(msg, N1, N2) + #define DebugMessageN3(msg, N1, N2, N3) + #else +// #include "CADebugPrintf.h" + + #if (CoreAudio_FlushDebugMessages && !CoreAudio_UseSysLog) || defined(CoreAudio_UseSideFile) + #define FlushRtn ,fflush(DebugPrintfFile) + #else + #define FlushRtn + #endif + + #if CoreAudio_ThreadStampMessages + #include + #include "CAHostTimeBase.h" + #if TARGET_RT_64_BIT + #define DebugPrintfThreadIDFormat "%16p" + #else + #define DebugPrintfThreadIDFormat "%8p" + #endif + #define DebugMessage(msg) DebugPrintfRtn(DebugPrintfFileComma "%17qd: " DebugPrintfThreadIDFormat " %s"DebugPrintfLineEnding, CAHostTimeBase::GetCurrentTimeInNanos(), pthread_self(), msg) FlushRtn + #define DebugMessageN1(msg, N1) DebugPrintfRtn(DebugPrintfFileComma "%17qd: " DebugPrintfThreadIDFormat " "msg"\n", CAHostTimeBase::GetCurrentTimeInNanos(), pthread_self(), N1) FlushRtn + #define DebugMessageN2(msg, N1, N2) DebugPrintfRtn(DebugPrintfFileComma "%17qd: " DebugPrintfThreadIDFormat " "msg"\n", CAHostTimeBase::GetCurrentTimeInNanos(), pthread_self(), N1, N2) FlushRtn + #define DebugMessageN3(msg, N1, N2, N3) DebugPrintfRtn(DebugPrintfFileComma "%17qd: " DebugPrintfThreadIDFormat " "msg"\n", CAHostTimeBase::GetCurrentTimeInNanos(), pthread_self(), N1, N2, N3) FlushRtn + #define DebugMessageN4(msg, N1, N2, N3, N4) DebugPrintfRtn(DebugPrintfFileComma "%17qd: " DebugPrintfThreadIDFormat " "msg"\n", CAHostTimeBase::GetCurrentTimeInNanos(), pthread_self(), N1, N2, N3, N4) FlushRtn + #define DebugMessageN5(msg, N1, N2, N3, N4, N5) DebugPrintfRtn(DebugPrintfFileComma "%17qd: " DebugPrintfThreadIDFormat " "msg"\n", CAHostTimeBase::GetCurrentTimeInNanos(), pthread_self(), N1, N2, N3, N4, N5) FlushRtn + #define DebugMessageN6(msg, N1, N2, N3, N4, N5, N6) DebugPrintfRtn(DebugPrintfFileComma "%17qd: " DebugPrintfThreadIDFormat " "msg"\n", CAHostTimeBase::GetCurrentTimeInNanos(), pthread_self(), N1, N2, N3, N4, N5, N6) FlushRtn + #define DebugMessageN7(msg, N1, N2, N3, N4, N5, N6, N7) DebugPrintfRtn(DebugPrintfFileComma "%17qd: " DebugPrintfThreadIDFormat " "msg"\n", CAHostTimeBase::GetCurrentTimeInNanos(), pthread_self(), N1, N2, N3, N4, N5, N6, N7) FlushRtn + #define DebugMessageN8(msg, N1, N2, N3, N4, N5, N6, N7, N8) DebugPrintfRtn(DebugPrintfFileComma "%17qd: " DebugPrintfThreadIDFormat " "msg"\n", CAHostTimeBase::GetCurrentTimeInNanos(), pthread_self(), N1, N2, N3, N4, N5, N6, N7, N8) FlushRtn + #define DebugMessageN9(msg, N1, N2, N3, N4, N5, N6, N7, N8, N9) DebugPrintfRtn(DebugPrintfFileComma "%17qd: " DebugPrintfThreadIDFormat " "msg"\n", CAHostTimeBase::GetCurrentTimeInNanos(), pthread_self(), N1, N2, N3, N4, N5, N6, N7, N8, N9) FlushRtn + #elif CoreAudio_TimeStampMessages + #include "CAHostTimeBase.h" + #define DebugMessage(msg) DebugPrintfRtn(DebugPrintfFileComma "%17qd: %s"DebugPrintfLineEnding, CAHostTimeBase::GetCurrentTimeInNanos(), msg) FlushRtn + #define DebugMessageN1(msg, N1) DebugPrintfRtn(DebugPrintfFileComma "%17qd: "msg DebugPrintfLineEnding, CAHostTimeBase::GetCurrentTimeInNanos(), N1) FlushRtn + #define DebugMessageN2(msg, N1, N2) DebugPrintfRtn(DebugPrintfFileComma "%17qd: "msg DebugPrintfLineEnding, CAHostTimeBase::GetCurrentTimeInNanos(), N1, N2) FlushRtn + #define DebugMessageN3(msg, N1, N2, N3) DebugPrintfRtn(DebugPrintfFileComma "%17qd: "msg DebugPrintfLineEnding, CAHostTimeBase::GetCurrentTimeInNanos(), N1, N2, N3) FlushRtn + #define DebugMessageN4(msg, N1, N2, N3, N4) DebugPrintfRtn(DebugPrintfFileComma "%17qd: "msg DebugPrintfLineEnding, CAHostTimeBase::GetCurrentTimeInNanos(), N1, N2, N3, N4) FlushRtn + #define DebugMessageN5(msg, N1, N2, N3, N4, N5) DebugPrintfRtn(DebugPrintfFileComma "%17qd: "msg DebugPrintfLineEnding, CAHostTimeBase::GetCurrentTimeInNanos(), N1, N2, N3, N4, N5) FlushRtn + #define DebugMessageN6(msg, N1, N2, N3, N4, N5, N6) DebugPrintfRtn(DebugPrintfFileComma "%17qd: "msg DebugPrintfLineEnding, CAHostTimeBase::GetCurrentTimeInNanos(), N1, N2, N3, N4, N5, N6) FlushRtn + #define DebugMessageN7(msg, N1, N2, N3, N4, N5, N6, N7) DebugPrintfRtn(DebugPrintfFileComma "%17qd: "msg DebugPrintfLineEnding, CAHostTimeBase::GetCurrentTimeInNanos(), N1, N2, N3, N4, N5, N6, N7) FlushRtn + #define DebugMessageN8(msg, N1, N2, N3, N4, N5, N6, N7, N8) DebugPrintfRtn(DebugPrintfFileComma "%17qd: "msg DebugPrintfLineEnding, CAHostTimeBase::GetCurrentTimeInNanos(), N1, N2, N3, N4, N5, N6, N7, N8) FlushRtn + #define DebugMessageN9(msg, N1, N2, N3, N4, N5, N6, N7, N8, N9) DebugPrintfRtn(DebugPrintfFileComma "%17qd: "msg DebugPrintfLineEnding, CAHostTimeBase::GetCurrentTimeInNanos(), N1, N2, N3, N4, N5, N6, N7, N8, N9) FlushRtn + #else +// #define DebugMessage(msg) DebugPrintfRtn(DebugPrintfFileComma "%s"DebugPrintfLineEnding, msg) FlushRtn + #define DebugMessageN1(msg, N1) DebugPrintfRtn(DebugPrintfFileComma msg DebugPrintfLineEnding, N1) FlushRtn + #define DebugMessageN2(msg, N1, N2) DebugPrintfRtn(DebugPrintfFileComma msg DebugPrintfLineEnding, N1, N2) FlushRtn + #define DebugMessageN3(msg, N1, N2, N3) DebugPrintfRtn(DebugPrintfFileComma msg DebugPrintfLineEnding, N1, N2, N3) FlushRtn + #define DebugMessageN4(msg, N1, N2, N3, N4) DebugPrintfRtn(DebugPrintfFileComma msg DebugPrintfLineEnding, N1, N2, N3, N4) FlushRtn + #define DebugMessageN5(msg, N1, N2, N3, N4, N5) DebugPrintfRtn(DebugPrintfFileComma msg DebugPrintfLineEnding, N1, N2, N3, N4, N5) FlushRtn + #define DebugMessageN6(msg, N1, N2, N3, N4, N5, N6) DebugPrintfRtn(DebugPrintfFileComma msg DebugPrintfLineEnding, N1, N2, N3, N4, N5, N6) FlushRtn + #define DebugMessageN7(msg, N1, N2, N3, N4, N5, N6, N7) DebugPrintfRtn(DebugPrintfFileComma msg DebugPrintfLineEnding, N1, N2, N3, N4, N5, N6, N7) FlushRtn + #define DebugMessageN8(msg, N1, N2, N3, N4, N5, N6, N7, N8) DebugPrintfRtn(DebugPrintfFileComma msg DebugPrintfLineEnding, N1, N2, N3, N4, N5, N6, N7, N8) FlushRtn + #define DebugMessageN9(msg, N1, N2, N3, N4, N5, N6, N7, N8, N9) DebugPrintfRtn(DebugPrintfFileComma msg DebugPrintfLineEnding, N1, N2, N3, N4, N5, N6, N7, N8, N9) FlushRtn + #endif + #endif + void DebugPrint(const char *fmt, ...); // can be used like printf + #ifndef DEBUGPRINT + #define DEBUGPRINT(msg) DebugPrint msg // have to double-parenthesize arglist (see Debugging.h) + #endif + #if VERBOSE + #define vprint(msg) DEBUGPRINT(msg) + #else + #define vprint(msg) + #endif + + // Original macro keeps its function of turning on and off use of CADebuggerStop() for both asserts and throws. + // For backwards compat, it overrides any setting of the two sub-macros. + #if CoreAudio_StopOnFailure + #include "CADebugger.h" + #undef CoreAudio_StopOnAssert + #define CoreAudio_StopOnAssert 1 + #undef CoreAudio_StopOnThrow + #define CoreAudio_StopOnThrow 1 + #define STOP CADebuggerStop() + #else + #define STOP + #endif + + #if CoreAudio_StopOnAssert + #if !CoreAudio_StopOnFailure + #include "CADebugger.h" + #define STOP + #endif + #define __ASSERT_STOP CADebuggerStop() + #else + #define __ASSERT_STOP + #endif + + #if CoreAudio_StopOnThrow + #if !CoreAudio_StopOnFailure + #include "CADebugger.h" + #define STOP + #endif + #define __THROW_STOP CADebuggerStop() + #else + #define __THROW_STOP + #endif + +#else + #define DebugMessage(msg) + #define DebugMessageN1(msg, N1) + #define DebugMessageN2(msg, N1, N2) + #define DebugMessageN3(msg, N1, N2, N3) + #define DebugMessageN4(msg, N1, N2, N3, N4) + #define DebugMessageN5(msg, N1, N2, N3, N4, N5) + #define DebugMessageN6(msg, N1, N2, N3, N4, N5, N6) + #define DebugMessageN7(msg, N1, N2, N3, N4, N5, N6, N7) + #define DebugMessageN8(msg, N1, N2, N3, N4, N5, N6, N7, N8) + #define DebugMessageN9(msg, N1, N2, N3, N4, N5, N6, N7, N8, N9) + #ifndef DEBUGPRINT + #define DEBUGPRINT(msg) + #endif + #define vprint(msg) + #define STOP + #define __ASSERT_STOP + #define __THROW_STOP +#endif + +//void LogError(const char *fmt, ...); // writes to syslog (and stderr if debugging) +void LogWarning(const char *fmt, ...); // writes to syslog (and stderr if debugging) + +#define NO_ACTION (void)0 + +#if DEBUG || CoreAudio_Debug + +#pragma mark Debug Macros + +#define Assert(inCondition, inMessage) \ + if(!(inCondition)) \ + { \ + DebugMessage(inMessage); \ + __ASSERT_STOP; \ + } + +#define AssertFileLine(inCondition, inMessage) \ + if(!(inCondition)) \ + { \ + DebugMessageN3("%s, line %d: %s", __FILE__, __LINE__, inMessage); \ + __ASSERT_STOP; \ + } + +#define AssertNoError(inError, inMessage) \ + { \ + SInt32 __Err = (inError); \ + if(__Err != 0) \ + { \ + char __4CC[5] = CA4CCToCString(__Err); \ + DebugMessageN2(inMessage ", Error: %d (%s)", (int)__Err, __4CC); \ + __ASSERT_STOP; \ + } \ + } + +#define AssertNoKernelError(inError, inMessage) \ + { \ + unsigned int __Err = (unsigned int)(inError); \ + if(__Err != 0) \ + { \ + DebugMessageN1(inMessage ", Error: 0x%X", __Err); \ + __ASSERT_STOP; \ + } \ + } + +#define AssertNotNULL(inPtr, inMessage) \ + { \ + if((inPtr) == NULL) \ + { \ + DebugMessage(inMessage); \ + __ASSERT_STOP; \ + } \ + } + +#define FailIf(inCondition, inHandler, inMessage) \ + if(inCondition) \ + { \ + DebugMessage(inMessage); \ + STOP; \ + goto inHandler; \ + } + +#define FailWithAction(inCondition, inAction, inHandler, inMessage) \ + if(inCondition) \ + { \ + DebugMessage(inMessage); \ + STOP; \ + { inAction; } \ + goto inHandler; \ + } + +#define FailIfNULL(inPointer, inAction, inHandler, inMessage) \ + if((inPointer) == NULL) \ + { \ + DebugMessage(inMessage); \ + STOP; \ + { inAction; } \ + goto inHandler; \ + } + +#define FailIfKernelError(inKernelError, inAction, inHandler, inMessage) \ + { \ + unsigned int __Err = (inKernelError); \ + if(__Err != 0) \ + { \ + DebugMessageN1(inMessage ", Error: 0x%X", __Err); \ + STOP; \ + { inAction; } \ + goto inHandler; \ + } \ + } + +#define FailIfError(inError, inAction, inHandler, inMessage) \ + { \ + SInt32 __Err = (inError); \ + if(__Err != 0) \ + { \ + char __4CC[5] = CA4CCToCString(__Err); \ + DebugMessageN2(inMessage ", Error: %ld (%s)", __Err, __4CC); \ + STOP; \ + { inAction; } \ + goto inHandler; \ + } \ + } + +#define FailIfNoMessage(inCondition, inHandler, inMessage) \ + if(inCondition) \ + { \ + STOP; \ + goto inHandler; \ + } + +#define FailWithActionNoMessage(inCondition, inAction, inHandler, inMessage) \ + if(inCondition) \ + { \ + STOP; \ + { inAction; } \ + goto inHandler; \ + } + +#define FailIfNULLNoMessage(inPointer, inAction, inHandler, inMessage) \ + if((inPointer) == NULL) \ + { \ + STOP; \ + { inAction; } \ + goto inHandler; \ + } + +#define FailIfKernelErrorNoMessage(inKernelError, inAction, inHandler, inMessage) \ + { \ + unsigned int __Err = (inKernelError); \ + if(__Err != 0) \ + { \ + STOP; \ + { inAction; } \ + goto inHandler; \ + } \ + } + +#define FailIfErrorNoMessage(inError, inAction, inHandler, inMessage) \ + { \ + SInt32 __Err = (inError); \ + if(__Err != 0) \ + { \ + STOP; \ + { inAction; } \ + goto inHandler; \ + } \ + } + +#if defined(__cplusplus) + +#define Throw(inException) __THROW_STOP; throw (inException) + +#define ThrowIf(inCondition, inException, inMessage) \ + if(inCondition) \ + { \ + DebugMessage(inMessage); \ + Throw(inException); \ + } + +#define ThrowIfNULL(inPointer, inException, inMessage) \ + if((inPointer) == NULL) \ + { \ + DebugMessage(inMessage); \ + Throw(inException); \ + } + +#define ThrowIfKernelError(inKernelError, inException, inMessage) \ + { \ + unsigned int __Err = (inKernelError); \ + if(__Err != 0) \ + { \ + DebugMessageN1(inMessage ", Error: 0x%X", __Err); \ + Throw(inException); \ + } \ + } + +#define ThrowIfError(inError, inException, inMessage) \ + { \ + SInt32 __Err = (inError); \ + if(__Err != 0) \ + { \ + char __4CC[5] = CA4CCToCString(__Err); \ + DebugMessageN2(inMessage ", Error: %d (%s)", (int)__Err, __4CC); \ + Throw(inException); \ + } \ + } + +#if TARGET_OS_WIN32 +#define ThrowIfWinError(inError, inException, inMessage) \ + { \ + HRESULT __Err = (inError); \ + if(FAILED(__Err)) \ + { \ + DebugMessageN2(inMessage ", Code: %d, Facility: 0x%X", HRESULT_CODE(__Err), HRESULT_FACILITY(__Err)); \ + Throw(inException); \ + } \ + } +#endif + +#define SubclassResponsibility(inMethodName, inException) \ + { \ + DebugMessage(inMethodName": Subclasses must implement this method"); \ + Throw(inException); \ + } + +#endif // defined(__cplusplus) + +#else + +#pragma mark Release Macros + +#define Assert(inCondition, inMessage) \ + if(!(inCondition)) \ + { \ + __ASSERT_STOP; \ + } + +#define AssertFileLine(inCondition, inMessage) Assert(inCondition, inMessage) + +#define AssertNoError(inError, inMessage) \ + { \ + SInt32 __Err = (inError); \ + if(__Err != 0) \ + { \ + __ASSERT_STOP; \ + } \ + } + +#define AssertNoKernelError(inError, inMessage) \ + { \ + unsigned int __Err = (unsigned int)(inError); \ + if(__Err != 0) \ + { \ + __ASSERT_STOP; \ + } \ + } + +#define AssertNotNULL(inPtr, inMessage) \ + { \ + if((inPtr) == NULL) \ + { \ + __ASSERT_STOP; \ + } \ + } + +#define FailIf(inCondition, inHandler, inMessage) \ + if(inCondition) \ + { \ + STOP; \ + goto inHandler; \ + } + +#define FailWithAction(inCondition, inAction, inHandler, inMessage) \ + if(inCondition) \ + { \ + STOP; \ + { inAction; } \ + goto inHandler; \ + } + +#define FailIfNULL(inPointer, inAction, inHandler, inMessage) \ + if((inPointer) == NULL) \ + { \ + STOP; \ + { inAction; } \ + goto inHandler; \ + } + +#define FailIfKernelError(inKernelError, inAction, inHandler, inMessage) \ + if((inKernelError) != 0) \ + { \ + STOP; \ + { inAction; } \ + goto inHandler; \ + } + +#define FailIfError(inError, inAction, inHandler, inMessage) \ + if((inError) != 0) \ + { \ + STOP; \ + { inAction; } \ + goto inHandler; \ + } + +#define FailIfNoMessage(inCondition, inHandler, inMessage) \ + if(inCondition) \ + { \ + STOP; \ + goto inHandler; \ + } + +#define FailWithActionNoMessage(inCondition, inAction, inHandler, inMessage) \ + if(inCondition) \ + { \ + STOP; \ + { inAction; } \ + goto inHandler; \ + } + +#define FailIfNULLNoMessage(inPointer, inAction, inHandler, inMessage) \ + if((inPointer) == NULL) \ + { \ + STOP; \ + { inAction; } \ + goto inHandler; \ + } + +#define FailIfKernelErrorNoMessage(inKernelError, inAction, inHandler, inMessage) \ + { \ + unsigned int __Err = (inKernelError); \ + if(__Err != 0) \ + { \ + STOP; \ + { inAction; } \ + goto inHandler; \ + } \ + } + +#define FailIfErrorNoMessage(inError, inAction, inHandler, inMessage) \ + { \ + SInt32 __Err = (inError); \ + if(__Err != 0) \ + { \ + STOP; \ + { inAction; } \ + goto inHandler; \ + } \ + } + +#if defined(__cplusplus) + +#define Throw(inException) __THROW_STOP; throw (inException) + +#define ThrowIf(inCondition, inException, inMessage) \ + if(inCondition) \ + { \ + Throw(inException); \ + } + +#define ThrowIfNULL(inPointer, inException, inMessage) \ + if((inPointer) == NULL) \ + { \ + Throw(inException); \ + } + +#define ThrowIfKernelError(inKernelError, inException, inMessage) \ + { \ + unsigned int __Err = (inKernelError); \ + if(__Err != 0) \ + { \ + Throw(inException); \ + } \ + } + +#define ThrowIfError(inError, inException, inMessage) \ + { \ + SInt32 __Err = (inError); \ + if(__Err != 0) \ + { \ + Throw(inException); \ + } \ + } + +#if TARGET_OS_WIN32 +#define ThrowIfWinError(inError, inException, inMessage) \ + { \ + HRESULT __Err = (inError); \ + if(FAILED(__Err)) \ + { \ + Throw(inException); \ + } \ + } +#endif + +#define SubclassResponsibility(inMethodName, inException) \ + { \ + Throw(inException); \ + } + +#endif // defined(__cplusplus) + +#endif // DEBUG || CoreAudio_Debug + +#endif diff --git a/ios/IOSDuoduo/Voice/manager/PublicUtility/CAMath.h b/ios/IOSDuoduo/Voice/manager/PublicUtility/CAMath.h new file mode 100755 index 000000000..f666704f9 --- /dev/null +++ b/ios/IOSDuoduo/Voice/manager/PublicUtility/CAMath.h @@ -0,0 +1,68 @@ +/* + File: CAMath.h + Abstract: Part of CoreAudio Utility Classes + Version: 2.5 + + Disclaimer: IMPORTANT: This Apple software is supplied to you by Apple + Inc. ("Apple") in consideration of your agreement to the following + terms, and your use, installation, modification or redistribution of + this Apple software constitutes acceptance of these terms. If you do + not agree with these terms, please do not use, install, modify or + redistribute this Apple software. + + In consideration of your agreement to abide by the following terms, and + subject to these terms, Apple grants you a personal, non-exclusive + license, under Apple's copyrights in this original Apple software (the + "Apple Software"), to use, reproduce, modify and redistribute the Apple + Software, with or without modifications, in source and/or binary forms; + provided that if you redistribute the Apple Software in its entirety and + without modifications, you must retain this notice and the following + text and disclaimers in all such redistributions of the Apple Software. + Neither the name, trademarks, service marks or logos of Apple Inc. may + be used to endorse or promote products derived from the Apple Software + without specific prior written permission from Apple. Except as + expressly stated in this notice, no other rights or licenses, express or + implied, are granted by Apple herein, including but not limited to any + patent rights that may be infringed by your derivative works or by other + works in which the Apple Software may be incorporated. + + The Apple Software is provided by Apple on an "AS IS" basis. APPLE + MAKES NO WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION + THE IMPLIED WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS + FOR A PARTICULAR PURPOSE, REGARDING THE APPLE SOFTWARE OR ITS USE AND + OPERATION ALONE OR IN COMBINATION WITH YOUR PRODUCTS. + + IN NO EVENT SHALL APPLE BE LIABLE FOR ANY SPECIAL, INDIRECT, INCIDENTAL + OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + INTERRUPTION) ARISING IN ANY WAY OUT OF THE USE, REPRODUCTION, + MODIFICATION AND/OR DISTRIBUTION OF THE APPLE SOFTWARE, HOWEVER CAUSED + AND WHETHER UNDER THEORY OF CONTRACT, TORT (INCLUDING NEGLIGENCE), + STRICT LIABILITY OR OTHERWISE, EVEN IF APPLE HAS BEEN ADVISED OF THE + POSSIBILITY OF SUCH DAMAGE. + + Copyright (C) 2012 Apple Inc. All Rights Reserved. + +*/ +#ifndef __CAMath_h__ +#define __CAMath_h__ + +#if !defined(__COREAUDIO_USE_FLAT_INCLUDES__) + #include +#else + #include +#endif + +inline bool fiszero(Float64 f) { return (f == 0.); } +inline bool fiszero(Float32 f) { return (f == 0.f); } + +inline bool fnonzero(Float64 f) { return !fiszero(f); } +inline bool fnonzero(Float32 f) { return !fiszero(f); } + +inline bool fequal(const Float64 &a, const Float64 &b) { return a == b; } +inline bool fequal(const Float32 &a, const Float32 &b) { return a == b; } + +inline bool fnotequal(const Float64 &a, const Float64 &b) { return !fequal(a, b); } +inline bool fnotequal(const Float32 &a, const Float32 &b) { return !fequal(a, b); } + +#endif // __CAMath_h__ diff --git a/ios/IOSDuoduo/Voice/manager/PublicUtility/CAStreamBasicDescription.cpp b/ios/IOSDuoduo/Voice/manager/PublicUtility/CAStreamBasicDescription.cpp new file mode 100755 index 000000000..87a259b31 --- /dev/null +++ b/ios/IOSDuoduo/Voice/manager/PublicUtility/CAStreamBasicDescription.cpp @@ -0,0 +1,795 @@ +/* + File: CAStreamBasicDescription.cpp + Abstract: CAStreamBasicDescription.h + Version: 2.5 + + Disclaimer: IMPORTANT: This Apple software is supplied to you by Apple + Inc. ("Apple") in consideration of your agreement to the following + terms, and your use, installation, modification or redistribution of + this Apple software constitutes acceptance of these terms. If you do + not agree with these terms, please do not use, install, modify or + redistribute this Apple software. + + In consideration of your agreement to abide by the following terms, and + subject to these terms, Apple grants you a personal, non-exclusive + license, under Apple's copyrights in this original Apple software (the + "Apple Software"), to use, reproduce, modify and redistribute the Apple + Software, with or without modifications, in source and/or binary forms; + provided that if you redistribute the Apple Software in its entirety and + without modifications, you must retain this notice and the following + text and disclaimers in all such redistributions of the Apple Software. + Neither the name, trademarks, service marks or logos of Apple Inc. may + be used to endorse or promote products derived from the Apple Software + without specific prior written permission from Apple. Except as + expressly stated in this notice, no other rights or licenses, express or + implied, are granted by Apple herein, including but not limited to any + patent rights that may be infringed by your derivative works or by other + works in which the Apple Software may be incorporated. + + The Apple Software is provided by Apple on an "AS IS" basis. APPLE + MAKES NO WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION + THE IMPLIED WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS + FOR A PARTICULAR PURPOSE, REGARDING THE APPLE SOFTWARE OR ITS USE AND + OPERATION ALONE OR IN COMBINATION WITH YOUR PRODUCTS. + + IN NO EVENT SHALL APPLE BE LIABLE FOR ANY SPECIAL, INDIRECT, INCIDENTAL + OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + INTERRUPTION) ARISING IN ANY WAY OUT OF THE USE, REPRODUCTION, + MODIFICATION AND/OR DISTRIBUTION OF THE APPLE SOFTWARE, HOWEVER CAUSED + AND WHETHER UNDER THEORY OF CONTRACT, TORT (INCLUDING NEGLIGENCE), + STRICT LIABILITY OR OTHERWISE, EVEN IF APPLE HAS BEEN ADVISED OF THE + POSSIBILITY OF SUCH DAMAGE. + + Copyright (C) 2012 Apple Inc. All Rights Reserved. + +*/ +#include "CAStreamBasicDescription.h" +#include "CAMath.h" + +#if !defined(__COREAUDIO_USE_FLAT_INCLUDES__) + #include +#else + #include +#endif + +#pragma mark This file needs to compile on earlier versions of the OS, so please keep that in mind when editing it + +char *CAStringForOSType (OSType t, char *writeLocation) +{ + char *p = writeLocation; + unsigned char str[4] = {0}, *q = str; + *(UInt32 *)str = CFSwapInt32HostToBig(t); + + bool hasNonPrint = false; + for (int i = 0; i < 4; ++i) { + if (!(isprint(*q) && *q != '\\')) { + hasNonPrint = true; + break; + } + q++; + } + q = str; + + if (hasNonPrint) + p += sprintf (p, "0x"); + else + *p++ = '\''; + + for (int i = 0; i < 4; ++i) { + if (hasNonPrint) { + p += sprintf(p, "%02X", *q++); + } else { + *p++ = *q++; + } + } + if (!hasNonPrint) + *p++ = '\''; + *p = '\0'; + return writeLocation; +} + + +const AudioStreamBasicDescription CAStreamBasicDescription::sEmpty = { 0.0, 0, 0, 0, 0, 0, 0, 0, 0 }; + +CAStreamBasicDescription::CAStreamBasicDescription() +{ + memset (this, 0, sizeof(AudioStreamBasicDescription)); +} + +CAStreamBasicDescription::CAStreamBasicDescription(const AudioStreamBasicDescription &desc) +{ + SetFrom(desc); +} + + +CAStreamBasicDescription::CAStreamBasicDescription(double inSampleRate, UInt32 inFormatID, + UInt32 inBytesPerPacket, UInt32 inFramesPerPacket, + UInt32 inBytesPerFrame, UInt32 inChannelsPerFrame, + UInt32 inBitsPerChannel, UInt32 inFormatFlags) +{ + mSampleRate = inSampleRate; + mFormatID = inFormatID; + mBytesPerPacket = inBytesPerPacket; + mFramesPerPacket = inFramesPerPacket; + mBytesPerFrame = inBytesPerFrame; + mChannelsPerFrame = inChannelsPerFrame; + mBitsPerChannel = inBitsPerChannel; + mFormatFlags = inFormatFlags; + mReserved = 0; +} + +char *CAStreamBasicDescription::AsString(char *buf, size_t _bufsize) const +{ + int bufsize = (int)_bufsize; // must be signed to protect against overflow + char *theBuffer = buf; + int nc; + char formatID[24]; + CAStringForOSType (mFormatID, formatID); + nc = snprintf(buf, bufsize, "%2d ch, %6.0f Hz, %s (0x%08X) ", (int)NumberChannels(), mSampleRate, formatID, (int)mFormatFlags); + buf += nc; if ((bufsize -= nc) <= 0) goto exit; + if (mFormatID == kAudioFormatLinearPCM) { + bool isInt = !(mFormatFlags & kLinearPCMFormatFlagIsFloat); + int wordSize = SampleWordSize(); + const char *endian = (wordSize > 1) ? + ((mFormatFlags & kLinearPCMFormatFlagIsBigEndian) ? " big-endian" : " little-endian" ) : ""; + const char *sign = isInt ? + ((mFormatFlags & kLinearPCMFormatFlagIsSignedInteger) ? " signed" : " unsigned") : ""; + const char *floatInt = isInt ? "integer" : "float"; + char packed[32]; + if (wordSize > 0 && PackednessIsSignificant()) { + if (mFormatFlags & kLinearPCMFormatFlagIsPacked) + snprintf(packed, sizeof(packed), "packed in %d bytes", wordSize); + else + snprintf(packed, sizeof(packed), "unpacked in %d bytes", wordSize); + } else + packed[0] = '\0'; + const char *align = (wordSize > 0 && AlignmentIsSignificant()) ? + ((mFormatFlags & kLinearPCMFormatFlagIsAlignedHigh) ? " high-aligned" : " low-aligned") : ""; + const char *deinter = (mFormatFlags & kAudioFormatFlagIsNonInterleaved) ? ", deinterleaved" : ""; + const char *commaSpace = (packed[0]!='\0') || (align[0]!='\0') ? ", " : ""; + char bitdepth[20]; + + int fracbits = (mFormatFlags & kLinearPCMFormatFlagsSampleFractionMask) >> kLinearPCMFormatFlagsSampleFractionShift; + if (fracbits > 0) + snprintf(bitdepth, sizeof(bitdepth), "%d.%d", (int)mBitsPerChannel - fracbits, fracbits); + else + snprintf(bitdepth, sizeof(bitdepth), "%d", (int)mBitsPerChannel); + + /* nc =*/ snprintf(buf, bufsize, "%s-bit%s%s %s%s%s%s%s", + bitdepth, endian, sign, floatInt, + commaSpace, packed, align, deinter); + // buf += nc; if ((bufsize -= nc) <= 0) goto exit; + } else if (mFormatID == 'alac') { // kAudioFormatAppleLossless + int sourceBits = 0; + switch (mFormatFlags) + { + case 1: // kAppleLosslessFormatFlag_16BitSourceData + sourceBits = 16; + break; + case 2: // kAppleLosslessFormatFlag_20BitSourceData + sourceBits = 20; + break; + case 3: // kAppleLosslessFormatFlag_24BitSourceData + sourceBits = 24; + break; + case 4: // kAppleLosslessFormatFlag_32BitSourceData + sourceBits = 32; + break; + } + if (sourceBits) + nc = snprintf(buf, bufsize, "from %d-bit source, ", sourceBits); + else + nc = snprintf(buf, bufsize, "from UNKNOWN source bit depth, "); + buf += nc; if ((bufsize -= nc) <= 0) goto exit; + /* nc =*/ snprintf(buf, bufsize, "%d frames/packet", (int)mFramesPerPacket); + // buf += nc; if ((bufsize -= nc) <= 0) goto exit; + } + else + /* nc =*/ snprintf(buf, bufsize, "%d bits/channel, %d bytes/packet, %d frames/packet, %d bytes/frame", + (int)mBitsPerChannel, (int)mBytesPerPacket, (int)mFramesPerPacket, (int)mBytesPerFrame); +exit: + return theBuffer; +} + +void CAStreamBasicDescription::NormalizeLinearPCMFormat(AudioStreamBasicDescription& ioDescription) +{ + // the only thing that changes is to make mixable linear PCM into the canonical linear PCM format + if((ioDescription.mFormatID == kAudioFormatLinearPCM) && ((ioDescription.mFormatFlags & kIsNonMixableFlag) == 0)) + { + // the canonical linear PCM format + ioDescription.mFormatFlags = kAudioFormatFlagsCanonical; + ioDescription.mBytesPerPacket = SizeOf32(AudioSampleType) * ioDescription.mChannelsPerFrame; + ioDescription.mFramesPerPacket = 1; + ioDescription.mBytesPerFrame = SizeOf32(AudioSampleType) * ioDescription.mChannelsPerFrame; + ioDescription.mBitsPerChannel = 8 * SizeOf32(AudioSampleType); + } +} + +void CAStreamBasicDescription::NormalizeLinearPCMFormat(bool inNativeEndian, AudioStreamBasicDescription& ioDescription) +{ + // the only thing that changes is to make mixable linear PCM into the canonical linear PCM format + if((ioDescription.mFormatID == kAudioFormatLinearPCM) && ((ioDescription.mFormatFlags & kIsNonMixableFlag) == 0)) + { + // the canonical linear PCM format + ioDescription.mFormatFlags = kAudioFormatFlagIsFloat | kAudioFormatFlagIsPacked; + if(inNativeEndian) + { +#if TARGET_RT_BIG_ENDIAN + ioDescription.mFormatFlags |= kAudioFormatFlagIsBigEndian; +#endif + } + else + { +#if TARGET_RT_LITTLE_ENDIAN + ioDescription.mFormatFlags |= kAudioFormatFlagIsBigEndian; +#endif + } + ioDescription.mBytesPerPacket = SizeOf32(AudioSampleType) * ioDescription.mChannelsPerFrame; + ioDescription.mFramesPerPacket = 1; + ioDescription.mBytesPerFrame = SizeOf32(AudioSampleType) * ioDescription.mChannelsPerFrame; + ioDescription.mBitsPerChannel = 8 * SizeOf32(AudioSampleType); + } +} + +void CAStreamBasicDescription::ResetFormat(AudioStreamBasicDescription& ioDescription) +{ + ioDescription.mSampleRate = 0; + ioDescription.mFormatID = 0; + ioDescription.mBytesPerPacket = 0; + ioDescription.mFramesPerPacket = 0; + ioDescription.mBytesPerFrame = 0; + ioDescription.mChannelsPerFrame = 0; + ioDescription.mBitsPerChannel = 0; + ioDescription.mFormatFlags = 0; +} + +void CAStreamBasicDescription::FillOutFormat(AudioStreamBasicDescription& ioDescription, const AudioStreamBasicDescription& inTemplateDescription) +{ + if(fiszero(ioDescription.mSampleRate)) + { + ioDescription.mSampleRate = inTemplateDescription.mSampleRate; + } + if(ioDescription.mFormatID == 0) + { + ioDescription.mFormatID = inTemplateDescription.mFormatID; + } + if(ioDescription.mFormatFlags == 0) + { + ioDescription.mFormatFlags = inTemplateDescription.mFormatFlags; + } + if(ioDescription.mBytesPerPacket == 0) + { + ioDescription.mBytesPerPacket = inTemplateDescription.mBytesPerPacket; + } + if(ioDescription.mFramesPerPacket == 0) + { + ioDescription.mFramesPerPacket = inTemplateDescription.mFramesPerPacket; + } + if(ioDescription.mBytesPerFrame == 0) + { + ioDescription.mBytesPerFrame = inTemplateDescription.mBytesPerFrame; + } + if(ioDescription.mChannelsPerFrame == 0) + { + ioDescription.mChannelsPerFrame = inTemplateDescription.mChannelsPerFrame; + } + if(ioDescription.mBitsPerChannel == 0) + { + ioDescription.mBitsPerChannel = inTemplateDescription.mBitsPerChannel; + } +} + +void CAStreamBasicDescription::GetSimpleName(const AudioStreamBasicDescription& inDescription, char* outName, UInt32 inMaxNameLength, bool inAbbreviate, bool inIncludeSampleRate) +{ + if(inIncludeSampleRate) + { + int theCharactersWritten = snprintf(outName, inMaxNameLength, "%.0f ", inDescription.mSampleRate); + outName += theCharactersWritten; + inMaxNameLength -= theCharactersWritten; + } + + switch(inDescription.mFormatID) + { + case kAudioFormatLinearPCM: + { + const char* theEndianString = NULL; + if((inDescription.mFormatFlags & kAudioFormatFlagIsBigEndian) != 0) + { + #if TARGET_RT_LITTLE_ENDIAN + theEndianString = "Big Endian"; + #endif + } + else + { + #if TARGET_RT_BIG_ENDIAN + theEndianString = "Little Endian"; + #endif + } + + const char* theKindString = NULL; + if((inDescription.mFormatFlags & kAudioFormatFlagIsFloat) != 0) + { + theKindString = (inAbbreviate ? "Float" : "Floating Point"); + } + else if((inDescription.mFormatFlags & kAudioFormatFlagIsSignedInteger) != 0) + { + theKindString = (inAbbreviate ? "SInt" : "Signed Integer"); + } + else + { + theKindString = (inAbbreviate ? "UInt" : "Unsigned Integer"); + } + + const char* thePackingString = NULL; + if((inDescription.mFormatFlags & kAudioFormatFlagIsPacked) == 0) + { + if((inDescription.mFormatFlags & kAudioFormatFlagIsAlignedHigh) != 0) + { + thePackingString = "High"; + } + else + { + thePackingString = "Low"; + } + } + + const char* theMixabilityString = NULL; + if((inDescription.mFormatFlags & kIsNonMixableFlag) == 0) + { + theMixabilityString = "Mixable"; + } + else + { + theMixabilityString = "Unmixable"; + } + + if(inAbbreviate) + { + if(theEndianString != NULL) + { + if(thePackingString != NULL) + { + snprintf(outName, inMaxNameLength, "%s %d Ch %s %s %s%d/%s%d", theMixabilityString, (int)inDescription.mChannelsPerFrame, theEndianString, thePackingString, theKindString, (int)inDescription.mBitsPerChannel, theKindString, (int)(inDescription.mBytesPerFrame / inDescription.mChannelsPerFrame) * 8); + } + else + { + snprintf(outName, inMaxNameLength, "%s %d Ch %s %s%d", theMixabilityString, (int)inDescription.mChannelsPerFrame, theEndianString, theKindString, (int)inDescription.mBitsPerChannel); + } + } + else + { + if(thePackingString != NULL) + { + snprintf(outName, inMaxNameLength, "%s %d Ch %s %s%d/%s%d", theMixabilityString, (int)inDescription.mChannelsPerFrame, thePackingString, theKindString, (int)inDescription.mBitsPerChannel, theKindString, (int)((inDescription.mBytesPerFrame / inDescription.mChannelsPerFrame) * 8)); + } + else + { + snprintf(outName, inMaxNameLength, "%s %d Ch %s%d", theMixabilityString, (int)inDescription.mChannelsPerFrame, theKindString, (int)inDescription.mBitsPerChannel); + } + } + } + else + { + if(theEndianString != NULL) + { + if(thePackingString != NULL) + { + snprintf(outName, inMaxNameLength, "%s %d Channel %d Bit %s %s Aligned %s in %d Bits", theMixabilityString, (int)inDescription.mChannelsPerFrame, (int)inDescription.mBitsPerChannel, theEndianString, theKindString, thePackingString, (int)(inDescription.mBytesPerFrame / inDescription.mChannelsPerFrame) * 8); + } + else + { + snprintf(outName, inMaxNameLength, "%s %d Channel %d Bit %s %s", theMixabilityString, (int)inDescription.mChannelsPerFrame, (int)inDescription.mBitsPerChannel, theEndianString, theKindString); + } + } + else + { + if(thePackingString != NULL) + { + snprintf(outName, inMaxNameLength, "%s %d Channel %d Bit %s Aligned %s in %d Bits", theMixabilityString, (int)inDescription.mChannelsPerFrame, (int)inDescription.mBitsPerChannel, theKindString, thePackingString, (int)(inDescription.mBytesPerFrame / inDescription.mChannelsPerFrame) * 8); + } + else + { + snprintf(outName, inMaxNameLength, "%s %d Channel %d Bit %s", theMixabilityString, (int)inDescription.mChannelsPerFrame, (int)inDescription.mBitsPerChannel, theKindString); + } + } + } + } + break; + + case kAudioFormatAC3: + strlcpy(outName, "AC-3", sizeof(outName)); + break; + + case kAudioFormat60958AC3: + strlcpy(outName, "AC-3 for SPDIF", sizeof(outName)); + break; + + default: + CACopy4CCToCString(outName, inDescription.mFormatID); + break; + }; +} + +#if CoreAudio_Debug +#include "CALogMacros.h" + +void CAStreamBasicDescription::PrintToLog(const AudioStreamBasicDescription& inDesc) +{ + PrintFloat (" Sample Rate: ", inDesc.mSampleRate); + Print4CharCode (" Format ID: ", inDesc.mFormatID); + PrintHex (" Format Flags: ", inDesc.mFormatFlags); + PrintInt (" Bytes per Packet: ", inDesc.mBytesPerPacket); + PrintInt (" Frames per Packet: ", inDesc.mFramesPerPacket); + PrintInt (" Bytes per Frame: ", inDesc.mBytesPerFrame); + PrintInt (" Channels per Frame: ", inDesc.mChannelsPerFrame); + PrintInt (" Bits per Channel: ", inDesc.mBitsPerChannel); +} +#endif + +bool operator<(const AudioStreamBasicDescription& x, const AudioStreamBasicDescription& y) +{ + bool theAnswer = false; + bool isDone = false; + + // note that if either side is 0, that field is skipped + + // format ID is the first order sort + if((!isDone) && ((x.mFormatID != 0) && (y.mFormatID != 0))) + { + if(x.mFormatID != y.mFormatID) + { + // formats are sorted numerically except that linear + // PCM is always first + if(x.mFormatID == kAudioFormatLinearPCM) + { + theAnswer = true; + } + else if(y.mFormatID == kAudioFormatLinearPCM) + { + theAnswer = false; + } + else + { + theAnswer = x.mFormatID < y.mFormatID; + } + isDone = true; + } + } + + + // mixable is always better than non-mixable for linear PCM and should be the second order sort item + if((!isDone) && ((x.mFormatID == kAudioFormatLinearPCM) && (y.mFormatID == kAudioFormatLinearPCM))) + { + if(((x.mFormatFlags & kIsNonMixableFlag) == 0) && ((y.mFormatFlags & kIsNonMixableFlag) != 0)) + { + theAnswer = true; + isDone = true; + } + else if(((x.mFormatFlags & kIsNonMixableFlag) != 0) && ((y.mFormatFlags & kIsNonMixableFlag) == 0)) + { + theAnswer = false; + isDone = true; + } + } + + // floating point vs integer for linear PCM only + if((!isDone) && ((x.mFormatID == kAudioFormatLinearPCM) && (y.mFormatID == kAudioFormatLinearPCM))) + { + if((x.mFormatFlags & kAudioFormatFlagIsFloat) != (y.mFormatFlags & kAudioFormatFlagIsFloat)) + { + // floating point is better than integer + theAnswer = y.mFormatFlags & kAudioFormatFlagIsFloat; + isDone = true; + } + } + + // bit depth + if((!isDone) && ((x.mBitsPerChannel != 0) && (y.mBitsPerChannel != 0))) + { + if(x.mBitsPerChannel != y.mBitsPerChannel) + { + // deeper bit depths are higher quality + theAnswer = x.mBitsPerChannel < y.mBitsPerChannel; + isDone = true; + } + } + + // sample rate + if((!isDone) && fnonzero(x.mSampleRate) && fnonzero(y.mSampleRate)) + { + if(fnotequal(x.mSampleRate, y.mSampleRate)) + { + // higher sample rates are higher quality + theAnswer = x.mSampleRate < y.mSampleRate; + isDone = true; + } + } + + // number of channels + if((!isDone) && ((x.mChannelsPerFrame != 0) && (y.mChannelsPerFrame != 0))) + { + if(x.mChannelsPerFrame != y.mChannelsPerFrame) + { + // more channels is higher quality + theAnswer = x.mChannelsPerFrame < y.mChannelsPerFrame; + //isDone = true; + } + } + + return theAnswer; +} + +static bool MatchFormatFlags(const AudioStreamBasicDescription& x, const AudioStreamBasicDescription& y) +{ + UInt32 xFlags = x.mFormatFlags; + UInt32 yFlags = y.mFormatFlags; + + // match wildcards + if (x.mFormatID == 0 || y.mFormatID == 0 || xFlags == 0 || yFlags == 0) + return true; + + if (x.mFormatID == kAudioFormatLinearPCM) + { + // knock off the all clear flag + xFlags = xFlags & ~kAudioFormatFlagsAreAllClear; + yFlags = yFlags & ~kAudioFormatFlagsAreAllClear; + + // if both kAudioFormatFlagIsPacked bits are set, then we don't care about the kAudioFormatFlagIsAlignedHigh bit. + if (xFlags & yFlags & kAudioFormatFlagIsPacked) { + xFlags = xFlags & ~kAudioFormatFlagIsAlignedHigh; + yFlags = yFlags & ~kAudioFormatFlagIsAlignedHigh; + } + + // if both kAudioFormatFlagIsFloat bits are set, then we don't care about the kAudioFormatFlagIsSignedInteger bit. + if (xFlags & yFlags & kAudioFormatFlagIsFloat) { + xFlags = xFlags & ~kAudioFormatFlagIsSignedInteger; + yFlags = yFlags & ~kAudioFormatFlagIsSignedInteger; + } + + // if the bit depth is 8 bits or less and the format is packed, we don't care about endianness + if((x.mBitsPerChannel <= 8) && ((xFlags & kAudioFormatFlagIsPacked) == kAudioFormatFlagIsPacked)) + { + xFlags = xFlags & ~kAudioFormatFlagIsBigEndian; + } + if((y.mBitsPerChannel <= 8) && ((yFlags & kAudioFormatFlagIsPacked) == kAudioFormatFlagIsPacked)) + { + yFlags = yFlags & ~kAudioFormatFlagIsBigEndian; + } + + // if the number of channels is 1, we don't care about non-interleavedness + if (x.mChannelsPerFrame == 1 && y.mChannelsPerFrame == 1) { + xFlags &= ~kLinearPCMFormatFlagIsNonInterleaved; + yFlags &= ~kLinearPCMFormatFlagIsNonInterleaved; + } + } + return xFlags == yFlags; +} + +bool operator==(const AudioStreamBasicDescription& x, const AudioStreamBasicDescription& y) +{ + // the semantics for equality are: + // 1) Values must match exactly -- except for PCM format flags, see above. + // 2) wildcard's are ignored in the comparison + +#define MATCH(name) ((x.name) == 0 || (y.name) == 0 || (x.name) == (y.name)) + + return + // check the sample rate + (fiszero(x.mSampleRate) || fiszero(y.mSampleRate) || fequal(x.mSampleRate, y.mSampleRate)) + + // check the format ids + && MATCH(mFormatID) + + // check the format flags + && MatchFormatFlags(x, y) + + // check the bytes per packet + && MATCH(mBytesPerPacket) + + // check the frames per packet + && MATCH(mFramesPerPacket) + + // check the bytes per frame + && MATCH(mBytesPerFrame) + + // check the channels per frame + && MATCH(mChannelsPerFrame) + + // check the channels per frame + && MATCH(mBitsPerChannel) ; +} + +bool CAStreamBasicDescription::IsEqual(const AudioStreamBasicDescription &other, bool interpretingWildcards) const +{ + if (interpretingWildcards) + return *this == other; + return memcmp(this, &other, offsetof(AudioStreamBasicDescription, mReserved)) == 0; +} + +bool SanityCheck(const AudioStreamBasicDescription& x) +{ + // This function returns false if there are sufficiently insane values in any field. + // It is very conservative so even some very unlikely values will pass. + // This is just meant to catch the case where the data from a file is corrupted. + + return + (x.mSampleRate >= 0.) + && (x.mSampleRate < 3e6) // SACD sample rate is 2.8224 MHz + && (x.mBytesPerPacket < 1000000) + && (x.mFramesPerPacket < 1000000) + && (x.mBytesPerFrame < 1000000) + && (x.mChannelsPerFrame <= 1024) + && (x.mBitsPerChannel <= 1024) + && (x.mFormatID != 0) + && !(x.mFormatID == kAudioFormatLinearPCM && (x.mFramesPerPacket != 1 || x.mBytesPerPacket != x.mBytesPerFrame)); +} + +bool CAStreamBasicDescription::FromText(const char *inTextDesc, AudioStreamBasicDescription &fmt) +{ + const char *p = inTextDesc; + + memset(&fmt, 0, sizeof(fmt)); + + bool isPCM = true; // until proven otherwise + UInt32 pcmFlags = kAudioFormatFlagIsPacked | kAudioFormatFlagIsSignedInteger; + + if (p[0] == '-') // previously we required a leading dash on PCM formats + ++p; + + if (p[0] == 'B' && p[1] == 'E') { + pcmFlags |= kLinearPCMFormatFlagIsBigEndian; + p += 2; + } else if (p[0] == 'L' && p[1] == 'E') { + p += 2; + } else { + // default is native-endian +#if TARGET_RT_BIG_ENDIAN + pcmFlags |= kLinearPCMFormatFlagIsBigEndian; +#endif + } + if (p[0] == 'F') { + pcmFlags = (pcmFlags & ~kAudioFormatFlagIsSignedInteger) | kAudioFormatFlagIsFloat; + ++p; + } else { + if (p[0] == 'U') { + pcmFlags &= ~kAudioFormatFlagIsSignedInteger; + ++p; + } + if (p[0] == 'I') + ++p; + else { + // it's not PCM; presumably some other format (NOT VALIDATED; use AudioFormat for that) + isPCM = false; + p = inTextDesc; // go back to the beginning + char buf[4] = { ' ',' ',' ',' ' }; + for (int i = 0; i < 4; ++i) { + if (*p != '\\') { + if ((buf[i] = *p++) == '\0') { + // special-case for 'aac' + if (i != 3) return false; + --p; // keep pointing at the terminating null + buf[i] = ' '; + break; + } + } else { + // "\xNN" is a hex byte + if (*++p != 'x') return false; + int x; + if (sscanf(++p, "%02X", &x) != 1) return false; + buf[i] = x; + p += 2; + } + } + + if (strchr("-@/#", buf[3])) { + // further special-casing for 'aac' + buf[3] = ' '; + --p; + } + + fmt.mFormatID = CFSwapInt32BigToHost(*(UInt32 *)buf); + } + } + + if (isPCM) { + fmt.mFormatID = kAudioFormatLinearPCM; + fmt.mFormatFlags = pcmFlags; + fmt.mFramesPerPacket = 1; + fmt.mChannelsPerFrame = 1; + int bitdepth = 0, fracbits = 0; + while (isdigit(*p)) + bitdepth = 10 * bitdepth + *p++ - '0'; + if (*p == '.') { + ++p; + if (!isdigit(*p)) { + fprintf(stderr, "Expected fractional bits following '.'\n"); + goto Bail; + } + while (isdigit(*p)) + fracbits = 10 * fracbits + *p++ - '0'; + bitdepth += fracbits; + fmt.mFormatFlags |= (fracbits << kLinearPCMFormatFlagsSampleFractionShift); + } + fmt.mBitsPerChannel = bitdepth; + fmt.mBytesPerPacket = fmt.mBytesPerFrame = (bitdepth + 7) / 8; + if (bitdepth & 7) { + // assume unpacked. (packed odd bit depths are describable but not supported in AudioConverter.) + fmt.mFormatFlags &= ~kLinearPCMFormatFlagIsPacked; + // alignment matters; default to high-aligned. use ':L_' for low. + fmt.mFormatFlags |= kLinearPCMFormatFlagIsAlignedHigh; + } + } + if (*p == '@') { + ++p; + while (isdigit(*p)) + fmt.mSampleRate = 10 * fmt.mSampleRate + (*p++ - '0'); + } + if (*p == '/') { + UInt32 flags = 0; + while (true) { + char c = *++p; + if (c >= '0' && c <= '9') + flags = (flags << 4) | (c - '0'); + else if (c >= 'A' && c <= 'F') + flags = (flags << 4) | (c - 'A' + 10); + else if (c >= 'a' && c <= 'f') + flags = (flags << 4) | (c - 'a' + 10); + else break; + } + fmt.mFormatFlags = flags; + } + if (*p == '#') { + ++p; + while (isdigit(*p)) + fmt.mFramesPerPacket = 10 * fmt.mFramesPerPacket + (*p++ - '0'); + } + if (*p == ':') { + ++p; + fmt.mFormatFlags &= ~kLinearPCMFormatFlagIsPacked; + if (*p == 'L') + fmt.mFormatFlags &= ~kLinearPCMFormatFlagIsAlignedHigh; + else if (*p == 'H') + fmt.mFormatFlags |= kLinearPCMFormatFlagIsAlignedHigh; + else + goto Bail; + ++p; + int bytesPerFrame = 0; + while (isdigit(*p)) + bytesPerFrame = 10 * bytesPerFrame + (*p++ - '0'); + fmt.mBytesPerFrame = fmt.mBytesPerPacket = bytesPerFrame; + } + if (*p == ',') { + ++p; + int ch = 0; + while (isdigit(*p)) + ch = 10 * ch + (*p++ - '0'); + fmt.mChannelsPerFrame = ch; + if (*p == 'D') { + ++p; + if (fmt.mFormatID != kAudioFormatLinearPCM) { + fprintf(stderr, "non-interleaved flag invalid for non-PCM formats\n"); + goto Bail; + } + fmt.mFormatFlags |= kAudioFormatFlagIsNonInterleaved; + } else { + if (*p == 'I') ++p; // default + if (fmt.mFormatID == kAudioFormatLinearPCM) + fmt.mBytesPerPacket = fmt.mBytesPerFrame *= ch; + } + } + if (*p != '\0') { + fprintf(stderr, "extra characters at end of format string: %s\n", p); + goto Bail; + } + return true; + +Bail: + fprintf(stderr, "Invalid format string: %s\n", inTextDesc); + fprintf(stderr, "Syntax of format strings is: \n"); + return false; +} + +const char *CAStreamBasicDescription::sTextParsingUsageString = + "format[@sample_rate_hz][/format_flags][#frames_per_packet][:LHbytesPerFrame][,channelsDI].\n" + "Format for PCM is [-][BE|LE]{F|I|UI}{bitdepth}; else a 4-char format code (e.g. aac, alac).\n"; diff --git a/ios/IOSDuoduo/Voice/manager/PublicUtility/CAStreamBasicDescription.h b/ios/IOSDuoduo/Voice/manager/PublicUtility/CAStreamBasicDescription.h new file mode 100755 index 000000000..97a267515 --- /dev/null +++ b/ios/IOSDuoduo/Voice/manager/PublicUtility/CAStreamBasicDescription.h @@ -0,0 +1,409 @@ +/* + File: CAStreamBasicDescription.h + Abstract: Part of CoreAudio Utility Classes + Version: 2.5 + + Disclaimer: IMPORTANT: This Apple software is supplied to you by Apple + Inc. ("Apple") in consideration of your agreement to the following + terms, and your use, installation, modification or redistribution of + this Apple software constitutes acceptance of these terms. If you do + not agree with these terms, please do not use, install, modify or + redistribute this Apple software. + + In consideration of your agreement to abide by the following terms, and + subject to these terms, Apple grants you a personal, non-exclusive + license, under Apple's copyrights in this original Apple software (the + "Apple Software"), to use, reproduce, modify and redistribute the Apple + Software, with or without modifications, in source and/or binary forms; + provided that if you redistribute the Apple Software in its entirety and + without modifications, you must retain this notice and the following + text and disclaimers in all such redistributions of the Apple Software. + Neither the name, trademarks, service marks or logos of Apple Inc. may + be used to endorse or promote products derived from the Apple Software + without specific prior written permission from Apple. Except as + expressly stated in this notice, no other rights or licenses, express or + implied, are granted by Apple herein, including but not limited to any + patent rights that may be infringed by your derivative works or by other + works in which the Apple Software may be incorporated. + + The Apple Software is provided by Apple on an "AS IS" basis. APPLE + MAKES NO WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION + THE IMPLIED WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS + FOR A PARTICULAR PURPOSE, REGARDING THE APPLE SOFTWARE OR ITS USE AND + OPERATION ALONE OR IN COMBINATION WITH YOUR PRODUCTS. + + IN NO EVENT SHALL APPLE BE LIABLE FOR ANY SPECIAL, INDIRECT, INCIDENTAL + OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + INTERRUPTION) ARISING IN ANY WAY OUT OF THE USE, REPRODUCTION, + MODIFICATION AND/OR DISTRIBUTION OF THE APPLE SOFTWARE, HOWEVER CAUSED + AND WHETHER UNDER THEORY OF CONTRACT, TORT (INCLUDING NEGLIGENCE), + STRICT LIABILITY OR OTHERWISE, EVEN IF APPLE HAS BEEN ADVISED OF THE + POSSIBILITY OF SUCH DAMAGE. + + Copyright (C) 2012 Apple Inc. All Rights Reserved. + +*/ +#ifndef __CAStreamBasicDescription_h__ +#define __CAStreamBasicDescription_h__ + +#if !defined(__COREAUDIO_USE_FLAT_INCLUDES__) + #include + #include +#else + #include "CoreAudioTypes.h" + #include "CoreFoundation.h" +#endif + +#include "CADebugMacros.h" +#include // for memset, memcpy +#include // for FILE * + +#pragma mark This file needs to compile on more earlier versions of the OS, so please keep that in mind when editing it + +extern char *CAStringForOSType (OSType t, char *writeLocation); + +// define Leopard specific symbols for backward compatibility if applicable +#if COREAUDIOTYPES_VERSION < 1050 +typedef Float32 AudioSampleType; +enum { kAudioFormatFlagsCanonical = kAudioFormatFlagIsFloat | kAudioFormatFlagsNativeEndian | kAudioFormatFlagIsPacked }; +#endif +#if COREAUDIOTYPES_VERSION < 1051 +typedef Float32 AudioUnitSampleType; +enum { + kLinearPCMFormatFlagsSampleFractionShift = 7, + kLinearPCMFormatFlagsSampleFractionMask = (0x3F << kLinearPCMFormatFlagsSampleFractionShift), +}; +#endif + +// define the IsMixable format flag for all versions of the system +#if (MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_3) + enum { kIsNonMixableFlag = kAudioFormatFlagIsNonMixable }; +#else + enum { kIsNonMixableFlag = (1L << 6) }; +#endif + +//============================================================================= +// CAStreamBasicDescription +// +// This is a wrapper class for the AudioStreamBasicDescription struct. +// It adds a number of convenience routines, but otherwise adds nothing +// to the footprint of the original struct. +//============================================================================= +class CAStreamBasicDescription : + public AudioStreamBasicDescription +{ + +// Constants +public: + static const AudioStreamBasicDescription sEmpty; + + enum CommonPCMFormat { + kPCMFormatOther = 0, + kPCMFormatFloat32 = 1, + kPCMFormatInt16 = 2, + kPCMFormatFixed824 = 3 + }; + +// Construction/Destruction +public: + CAStreamBasicDescription(); + + CAStreamBasicDescription(const AudioStreamBasicDescription &desc); + + CAStreamBasicDescription( double inSampleRate, UInt32 inFormatID, + UInt32 inBytesPerPacket, UInt32 inFramesPerPacket, + UInt32 inBytesPerFrame, UInt32 inChannelsPerFrame, + UInt32 inBitsPerChannel, UInt32 inFormatFlags); + + CAStreamBasicDescription( double inSampleRate, UInt32 inNumChannels, CommonPCMFormat pcmf, bool inIsInterleaved) { + unsigned wordsize; + + mSampleRate = inSampleRate; + mFormatID = kAudioFormatLinearPCM; + mFormatFlags = kAudioFormatFlagsNativeEndian | kAudioFormatFlagIsPacked; + mFramesPerPacket = 1; + mChannelsPerFrame = inNumChannels; + mBytesPerFrame = mBytesPerPacket = 0; + mReserved = 0; + + switch (pcmf) { + default: + return; + case kPCMFormatFloat32: + wordsize = 4; + mFormatFlags |= kAudioFormatFlagIsFloat; + break; + case kPCMFormatInt16: + wordsize = 2; + mFormatFlags |= kAudioFormatFlagIsSignedInteger; + break; + case kPCMFormatFixed824: + wordsize = 4; + mFormatFlags |= kAudioFormatFlagIsSignedInteger | (24 << kLinearPCMFormatFlagsSampleFractionShift); + break; + } + mBitsPerChannel = wordsize * 8; + if (inIsInterleaved) + mBytesPerFrame = mBytesPerPacket = wordsize * inNumChannels; + else { + mFormatFlags |= kAudioFormatFlagIsNonInterleaved; + mBytesPerFrame = mBytesPerPacket = wordsize; + } + } + +// Assignment + CAStreamBasicDescription& operator=(const AudioStreamBasicDescription& v) { SetFrom(v); return *this; } + + void SetFrom(const AudioStreamBasicDescription &desc) + { + memcpy(this, &desc, sizeof(AudioStreamBasicDescription)); + } + + bool FromText(const char *inTextDesc) { return FromText(inTextDesc, *this); } + static bool FromText(const char *inTextDesc, AudioStreamBasicDescription &outDesc); + // return true if parsing was successful + + static const char *sTextParsingUsageString; + + // _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ + // + // interrogation + + bool IsPCM() const { return mFormatID == kAudioFormatLinearPCM; } + + bool PackednessIsSignificant() const + { +// Assert(IsPCM(), "PackednessIsSignificant only applies for PCM"); + return (SampleWordSize() << 3) != mBitsPerChannel; + } + + bool AlignmentIsSignificant() const + { + return PackednessIsSignificant() || (mBitsPerChannel & 7) != 0; + } + + bool IsInterleaved() const + { + return !IsPCM() || !(mFormatFlags & kAudioFormatFlagIsNonInterleaved); + } + + bool IsSignedInteger() const + { + return IsPCM() && (mFormatFlags & kAudioFormatFlagIsSignedInteger); + } + + bool IsFloat() const + { + return IsPCM() && (mFormatFlags & kAudioFormatFlagIsFloat); + } + + bool IsNativeEndian() const + { + return (mFormatFlags & kAudioFormatFlagIsBigEndian) == kAudioFormatFlagsNativeEndian; + } + + // for sanity with interleaved/deinterleaved possibilities, never access mChannelsPerFrame, use these: + UInt32 NumberInterleavedChannels() const { return IsInterleaved() ? mChannelsPerFrame : 1; } + UInt32 NumberChannelStreams() const { return IsInterleaved() ? 1 : mChannelsPerFrame; } + UInt32 NumberChannels() const { return mChannelsPerFrame; } + UInt32 SampleWordSize() const { + return (mBytesPerFrame > 0 && NumberInterleavedChannels()) ? mBytesPerFrame / NumberInterleavedChannels() : 0; + } + + UInt32 FramesToBytes(UInt32 nframes) const { return nframes * mBytesPerFrame; } + UInt32 BytesToFrames(UInt32 nbytes) const { +// Assert(mBytesPerFrame > 0, "bytesPerFrame must be > 0 in BytesToFrames"); + return nbytes / mBytesPerFrame; + } + + bool SameChannelsAndInterleaving(const CAStreamBasicDescription &a) const + { + return this->NumberChannels() == a.NumberChannels() && this->IsInterleaved() == a.IsInterleaved(); + } + + bool IdentifyCommonPCMFormat(CommonPCMFormat &outFormat, bool *outIsInterleaved=NULL) const + { // return true if it's a valid PCM format. + + outFormat = kPCMFormatOther; + // trap out patently invalid formats. + if (mFormatID != kAudioFormatLinearPCM || mFramesPerPacket != 1 || mBytesPerFrame != mBytesPerPacket || mBitsPerChannel/8 > mBytesPerFrame || mChannelsPerFrame == 0) + return false; + bool interleaved = (mFormatFlags & kAudioFormatFlagIsNonInterleaved) == 0; + if (outIsInterleaved != NULL) *outIsInterleaved = interleaved; + unsigned wordsize = mBytesPerFrame; + if (interleaved) { + if (wordsize % mChannelsPerFrame != 0) return false; + wordsize /= mChannelsPerFrame; + } + + if ((mFormatFlags & kAudioFormatFlagIsBigEndian) == kAudioFormatFlagsNativeEndian + && wordsize * 8 == mBitsPerChannel) { + // packed and native endian, good + if (mFormatFlags & kLinearPCMFormatFlagIsFloat) { + // float: reject nonsense bits + if (mFormatFlags & (kLinearPCMFormatFlagIsSignedInteger | kLinearPCMFormatFlagsSampleFractionMask)) + return false; + if (wordsize == 4) + outFormat = kPCMFormatFloat32; + } else if (mFormatFlags & kLinearPCMFormatFlagIsSignedInteger) { + // signed int + unsigned fracbits = (mFormatFlags & kLinearPCMFormatFlagsSampleFractionMask) >> kLinearPCMFormatFlagsSampleFractionShift; + if (wordsize == 4 && fracbits == 24) + outFormat = kPCMFormatFixed824; + else if (wordsize == 2 && fracbits == 0) + outFormat = kPCMFormatInt16; + } + } + return true; + } + + bool IsCommonFloat32(bool *outIsInterleaved=NULL) const { + CommonPCMFormat fmt; + return IdentifyCommonPCMFormat(fmt, outIsInterleaved) && fmt == kPCMFormatFloat32; + } + bool IsCommonFixed824(bool *outIsInterleaved=NULL) const { + CommonPCMFormat fmt; + return IdentifyCommonPCMFormat(fmt, outIsInterleaved) && fmt == kPCMFormatFixed824; + } + bool IsCommonInt16(bool *outIsInterleaved=NULL) const { + CommonPCMFormat fmt; + return IdentifyCommonPCMFormat(fmt, outIsInterleaved) && fmt == kPCMFormatInt16; + } + + // _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ + // + // manipulation + + void SetCanonical(UInt32 nChannels, bool interleaved) + // note: leaves sample rate untouched + { + mFormatID = kAudioFormatLinearPCM; + int sampleSize = SizeOf32(AudioSampleType); + mFormatFlags = kAudioFormatFlagsCanonical; + mBitsPerChannel = 8 * sampleSize; + mChannelsPerFrame = nChannels; + mFramesPerPacket = 1; + if (interleaved) + mBytesPerPacket = mBytesPerFrame = nChannels * sampleSize; + else { + mBytesPerPacket = mBytesPerFrame = sampleSize; + mFormatFlags |= kAudioFormatFlagIsNonInterleaved; + } + } + + bool IsCanonical() const + { + if (mFormatID != kAudioFormatLinearPCM) return false; + UInt32 reqFormatFlags; + UInt32 flagsMask = (kLinearPCMFormatFlagIsFloat | kLinearPCMFormatFlagIsBigEndian | kLinearPCMFormatFlagIsSignedInteger | kLinearPCMFormatFlagIsPacked | kLinearPCMFormatFlagsSampleFractionMask); + bool interleaved = (mFormatFlags & kAudioFormatFlagIsNonInterleaved) == 0; + unsigned sampleSize = SizeOf32(AudioSampleType); + reqFormatFlags = kAudioFormatFlagsCanonical; + UInt32 reqFrameSize = interleaved ? (mChannelsPerFrame * sampleSize) : sampleSize; + + return ((mFormatFlags & flagsMask) == reqFormatFlags + && mBitsPerChannel == 8 * sampleSize + && mFramesPerPacket == 1 + && mBytesPerFrame == reqFrameSize + && mBytesPerPacket == reqFrameSize); + } + + void SetAUCanonical(UInt32 nChannels, bool interleaved) + { + mFormatID = kAudioFormatLinearPCM; +#if CA_PREFER_FIXED_POINT + mFormatFlags = kAudioFormatFlagsCanonical | (kAudioUnitSampleFractionBits << kLinearPCMFormatFlagsSampleFractionShift); +#else + mFormatFlags = kAudioFormatFlagsCanonical; +#endif + mChannelsPerFrame = nChannels; + mFramesPerPacket = 1; + mBitsPerChannel = 8 * SizeOf32(AudioUnitSampleType); + if (interleaved) + mBytesPerPacket = mBytesPerFrame = nChannels * SizeOf32(AudioUnitSampleType); + else { + mBytesPerPacket = mBytesPerFrame = SizeOf32(AudioUnitSampleType); + mFormatFlags |= kAudioFormatFlagIsNonInterleaved; + } + } + + void ChangeNumberChannels(UInt32 nChannels, bool interleaved) + // alter an existing format + { +// Assert(IsPCM(), "ChangeNumberChannels only works for PCM formats"); + UInt32 wordSize = SampleWordSize(); // get this before changing ANYTHING + if (wordSize == 0) + wordSize = (mBitsPerChannel + 7) / 8; + mChannelsPerFrame = nChannels; + mFramesPerPacket = 1; + if (interleaved) { + mBytesPerPacket = mBytesPerFrame = nChannels * wordSize; + mFormatFlags &= ~kAudioFormatFlagIsNonInterleaved; + } else { + mBytesPerPacket = mBytesPerFrame = wordSize; + mFormatFlags |= kAudioFormatFlagIsNonInterleaved; + } + } + + // _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ + // + // other + + bool IsEqual(const AudioStreamBasicDescription &other, bool interpretingWildcards=true) const; + + void Print() const { + Print (stdout); + } + + void Print(FILE* file) const { + PrintFormat (file, "", "AudioStreamBasicDescription:"); + } + + void PrintFormat(FILE *f, const char *indent, const char *name) const { + char buf[256]; + fprintf(f, "%s%s %s\n", indent, name, AsString(buf, sizeof(buf))); + } + + void PrintFormat2(FILE *f, const char *indent, const char *name) const { // no trailing newline + char buf[256]; + fprintf(f, "%s%s %s", indent, name, AsString(buf, sizeof(buf))); + } + + char * AsString(char *buf, size_t bufsize) const; + + static void Print (const AudioStreamBasicDescription &inDesc) + { + CAStreamBasicDescription desc(inDesc); + desc.Print (); + } + + OSStatus Save(CFPropertyListRef *outData) const; + + OSStatus Restore(CFPropertyListRef &inData); + +// Operations + static bool IsMixable(const AudioStreamBasicDescription& inDescription) { return (inDescription.mFormatID == kAudioFormatLinearPCM) && ((inDescription.mFormatFlags & kIsNonMixableFlag) == 0); } + static void NormalizeLinearPCMFormat(AudioStreamBasicDescription& ioDescription); + static void NormalizeLinearPCMFormat(bool inNativeEndian, AudioStreamBasicDescription& ioDescription); + static void ResetFormat(AudioStreamBasicDescription& ioDescription); + static void FillOutFormat(AudioStreamBasicDescription& ioDescription, const AudioStreamBasicDescription& inTemplateDescription); + static void GetSimpleName(const AudioStreamBasicDescription& inDescription, char* outName, UInt32 inMaxNameLength, bool inAbbreviate, bool inIncludeSampleRate = false); +#if CoreAudio_Debug + static void PrintToLog(const AudioStreamBasicDescription& inDesc); +#endif +}; + +bool operator<(const AudioStreamBasicDescription& x, const AudioStreamBasicDescription& y); +bool operator==(const AudioStreamBasicDescription& x, const AudioStreamBasicDescription& y); +#if TARGET_OS_MAC || (TARGET_OS_WIN32 && (_MSC_VER > 600)) +inline bool operator!=(const AudioStreamBasicDescription& x, const AudioStreamBasicDescription& y) { return !(x == y); } +inline bool operator<=(const AudioStreamBasicDescription& x, const AudioStreamBasicDescription& y) { return (x < y) || (x == y); } +inline bool operator>=(const AudioStreamBasicDescription& x, const AudioStreamBasicDescription& y) { return !(x < y); } +inline bool operator>(const AudioStreamBasicDescription& x, const AudioStreamBasicDescription& y) { return !((x < y) || (x == y)); } +#endif + +bool SanityCheck(const AudioStreamBasicDescription& x); + + +#endif // __CAStreamBasicDescription_h__ diff --git a/ios/IOSDuoduo/Voice/manager/PublicUtility/CAXException.cpp b/ios/IOSDuoduo/Voice/manager/PublicUtility/CAXException.cpp new file mode 100755 index 000000000..00851286b --- /dev/null +++ b/ios/IOSDuoduo/Voice/manager/PublicUtility/CAXException.cpp @@ -0,0 +1,49 @@ +/* + File: CAXException.cpp + Abstract: CAXException.h + Version: 2.5 + + Disclaimer: IMPORTANT: This Apple software is supplied to you by Apple + Inc. ("Apple") in consideration of your agreement to the following + terms, and your use, installation, modification or redistribution of + this Apple software constitutes acceptance of these terms. If you do + not agree with these terms, please do not use, install, modify or + redistribute this Apple software. + + In consideration of your agreement to abide by the following terms, and + subject to these terms, Apple grants you a personal, non-exclusive + license, under Apple's copyrights in this original Apple software (the + "Apple Software"), to use, reproduce, modify and redistribute the Apple + Software, with or without modifications, in source and/or binary forms; + provided that if you redistribute the Apple Software in its entirety and + without modifications, you must retain this notice and the following + text and disclaimers in all such redistributions of the Apple Software. + Neither the name, trademarks, service marks or logos of Apple Inc. may + be used to endorse or promote products derived from the Apple Software + without specific prior written permission from Apple. Except as + expressly stated in this notice, no other rights or licenses, express or + implied, are granted by Apple herein, including but not limited to any + patent rights that may be infringed by your derivative works or by other + works in which the Apple Software may be incorporated. + + The Apple Software is provided by Apple on an "AS IS" basis. APPLE + MAKES NO WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION + THE IMPLIED WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS + FOR A PARTICULAR PURPOSE, REGARDING THE APPLE SOFTWARE OR ITS USE AND + OPERATION ALONE OR IN COMBINATION WITH YOUR PRODUCTS. + + IN NO EVENT SHALL APPLE BE LIABLE FOR ANY SPECIAL, INDIRECT, INCIDENTAL + OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + INTERRUPTION) ARISING IN ANY WAY OUT OF THE USE, REPRODUCTION, + MODIFICATION AND/OR DISTRIBUTION OF THE APPLE SOFTWARE, HOWEVER CAUSED + AND WHETHER UNDER THEORY OF CONTRACT, TORT (INCLUDING NEGLIGENCE), + STRICT LIABILITY OR OTHERWISE, EVEN IF APPLE HAS BEEN ADVISED OF THE + POSSIBILITY OF SUCH DAMAGE. + + Copyright (C) 2012 Apple Inc. All Rights Reserved. + +*/ +#include "CAXException.h" + +CAXException::WarningHandler CAXException::sWarningHandler = NULL; diff --git a/ios/IOSDuoduo/Voice/manager/PublicUtility/CAXException.h b/ios/IOSDuoduo/Voice/manager/PublicUtility/CAXException.h new file mode 100755 index 000000000..c5dfb6b16 --- /dev/null +++ b/ios/IOSDuoduo/Voice/manager/PublicUtility/CAXException.h @@ -0,0 +1,338 @@ +/* + File: CAXException.h + Abstract: Part of CoreAudio Utility Classes + Version: 2.5 + + Disclaimer: IMPORTANT: This Apple software is supplied to you by Apple + Inc. ("Apple") in consideration of your agreement to the following + terms, and your use, installation, modification or redistribution of + this Apple software constitutes acceptance of these terms. If you do + not agree with these terms, please do not use, install, modify or + redistribute this Apple software. + + In consideration of your agreement to abide by the following terms, and + subject to these terms, Apple grants you a personal, non-exclusive + license, under Apple's copyrights in this original Apple software (the + "Apple Software"), to use, reproduce, modify and redistribute the Apple + Software, with or without modifications, in source and/or binary forms; + provided that if you redistribute the Apple Software in its entirety and + without modifications, you must retain this notice and the following + text and disclaimers in all such redistributions of the Apple Software. + Neither the name, trademarks, service marks or logos of Apple Inc. may + be used to endorse or promote products derived from the Apple Software + without specific prior written permission from Apple. Except as + expressly stated in this notice, no other rights or licenses, express or + implied, are granted by Apple herein, including but not limited to any + patent rights that may be infringed by your derivative works or by other + works in which the Apple Software may be incorporated. + + The Apple Software is provided by Apple on an "AS IS" basis. APPLE + MAKES NO WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION + THE IMPLIED WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS + FOR A PARTICULAR PURPOSE, REGARDING THE APPLE SOFTWARE OR ITS USE AND + OPERATION ALONE OR IN COMBINATION WITH YOUR PRODUCTS. + + IN NO EVENT SHALL APPLE BE LIABLE FOR ANY SPECIAL, INDIRECT, INCIDENTAL + OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + INTERRUPTION) ARISING IN ANY WAY OUT OF THE USE, REPRODUCTION, + MODIFICATION AND/OR DISTRIBUTION OF THE APPLE SOFTWARE, HOWEVER CAUSED + AND WHETHER UNDER THEORY OF CONTRACT, TORT (INCLUDING NEGLIGENCE), + STRICT LIABILITY OR OTHERWISE, EVEN IF APPLE HAS BEEN ADVISED OF THE + POSSIBILITY OF SUCH DAMAGE. + + Copyright (C) 2012 Apple Inc. All Rights Reserved. + +*/ +#ifndef __CAXException_h__ +#define __CAXException_h__ + +#if !defined(__COREAUDIO_USE_FLAT_INCLUDES__) + #include +#else + #include + #include +#endif +#include "CADebugMacros.h" +#include +//#include +#include + + +class CAX4CCString { +public: + CAX4CCString(OSStatus error) { + // see if it appears to be a 4-char-code + char *str = mStr; + *(UInt32 *)(str + 1) = CFSwapInt32HostToBig(error); + if (isprint(str[1]) && isprint(str[2]) && isprint(str[3]) && isprint(str[4])) { + str[0] = str[5] = '\''; + str[6] = '\0'; + } else if (error > -200000 && error < 200000) + // no, format it as an integer + sprintf(str, "%d", (int)error); + else + sprintf(str, "0x%x", (int)error); + } + const char *get() const { return mStr; } + operator const char *() const { return mStr; } +private: + char mStr[16]; +}; + +// An extended exception class that includes the name of the failed operation +class CAXException { +public: + CAXException(const char *operation, OSStatus err) : + mError(err) + { + if (operation == NULL) + mOperation[0] = '\0'; + else if (strlen(operation) >= sizeof(mOperation)) { + memcpy(mOperation, operation, sizeof(mOperation) - 1); + mOperation[sizeof(mOperation) - 1] = '\0'; + } else + + strlcpy(mOperation, operation, sizeof(mOperation)); + } + + char *FormatError(char *str) const + { + return FormatError(str, mError); + } + + char mOperation[256]; + const OSStatus mError; + + // ------------------------------------------------- + + typedef void (*WarningHandler)(const char *msg, OSStatus err); + + static char *FormatError(char *str, OSStatus error) + { + strcpy(str, CAX4CCString(error)); + return str; + } + + static void Warning(const char *s, OSStatus error) + { + if (sWarningHandler) + (*sWarningHandler)(s, error); + } + + static void SetWarningHandler(WarningHandler f) { sWarningHandler = f; } +private: + static WarningHandler sWarningHandler; +}; + +#if DEBUG || CoreAudio_Debug + #define XThrowIfError(error, operation) \ + do { \ + OSStatus __err = error; \ + if (__err) { \ + DebugMessageN2("about to throw %s: %s", CAX4CCString(__err).get(), operation);\ + __THROW_STOP; \ + throw CAXException(operation, __err); \ + } \ + } while (0) + + #define XThrowIf(condition, error, operation) \ + do { \ + if (condition) { \ + OSStatus __err = error; \ + DebugMessageN2("about to throw %s: %s", CAX4CCString(__err).get(), operation);\ + __THROW_STOP; \ + throw CAXException(operation, __err); \ + } \ + } while (0) + + #define XRequireNoError(error, label) \ + do { \ + OSStatus __err = error; \ + if (__err) { \ + DebugMessageN2("about to throw %s: %s", CAX4CCString(__err).get(), #error);\ + STOP; \ + goto label; \ + } \ + } while (0) + + #define XAssert(assertion) \ + do { \ + if (!(assertion)) { \ + DebugMessageN3("[%s, %d] error: failed assertion: %s", __FILE__, __LINE__, #assertion); \ + __ASSERT_STOP; \ + } \ + } while (0) + + #define XAssertNoError(error) \ + do { \ + OSStatus __err = error; \ + if (__err) { \ + DebugMessageN2("error %s: %s", CAX4CCString(__err).get(), #error);\ + STOP; \ + } \ + } while (0) + + #define ca_require_noerr(errorCode, exceptionLabel) \ + do \ + { \ + int evalOnceErrorCode = (errorCode); \ + if ( __builtin_expect(0 != evalOnceErrorCode, 0) ) \ + { \ + DebugMessageN5("ca_require_noerr: [%s, %d] (goto %s;) %s:%d", \ + #errorCode, evalOnceErrorCode, \ + #exceptionLabel, \ + __FILE__, \ + __LINE__); \ + goto exceptionLabel; \ + } \ + } while ( 0 ) + + #define ca_verify_noerr(errorCode) \ + do \ + { \ + int evalOnceErrorCode = (errorCode); \ + if ( __builtin_expect(0 != evalOnceErrorCode, 0) ) \ + { \ + DebugMessageN4("ca_verify_noerr: [%s, %d] %s:%d", \ + #errorCode, evalOnceErrorCode, \ + __FILE__, \ + __LINE__); \ + } \ + } while ( 0 ) + + #define ca_debug_string(message) \ + do \ + { \ + DebugMessageN3("ca_debug_string: %s %s:%d", \ + message, \ + __FILE__, \ + __LINE__); \ + } while ( 0 ) + + + #define ca_verify(assertion) \ + do \ + { \ + if ( __builtin_expect(!(assertion), 0) ) \ + { \ + DebugMessageN3("ca_verify: %s %s:%d", \ + #assertion, \ + __FILE__, \ + __LINE__); \ + } \ + } while ( 0 ) + + #define ca_require(assertion, exceptionLabel) \ + do \ + { \ + if ( __builtin_expect(!(assertion), 0) ) \ + { \ + DebugMessageN4("ca_require: %s %s %s:%d", \ + #assertion, \ + #exceptionLabel, \ + __FILE__, \ + __LINE__); \ + goto exceptionLabel; \ + } \ + } while ( 0 ) + + #define ca_check(assertion) \ + do \ + { \ + if ( __builtin_expect(!(assertion), 0) ) \ + { \ + DebugMessageN3("ca_check: %s %s:%d", \ + #assertion, \ + __FILE__, \ + __LINE__); \ + } \ + } while ( 0 ) + +#else + #define XThrowIfError(error, operation) \ + do { \ + OSStatus __err = error; \ + if (__err) { \ + throw CAXException(operation, __err); \ + } \ + } while (0) + + #define XThrowIf(condition, error, operation) \ + do { \ + if (condition) { \ + OSStatus __err = error; \ + throw CAXException(operation, __err); \ + } \ + } while (0) + + #define XRequireNoError(error, label) \ + do { \ + OSStatus __err = error; \ + if (__err) { \ + goto label; \ + } \ + } while (0) + + #define XAssert(assertion) \ + do { \ + if (!(assertion)) { \ + } \ + } while (0) + + #define XAssertNoError(error) \ + do { \ + /*OSStatus __err =*/ error; \ + } while (0) + + #define ca_require_noerr(errorCode, exceptionLabel) \ + do \ + { \ + if ( __builtin_expect(0 != (errorCode), 0) ) \ + { \ + goto exceptionLabel; \ + } \ + } while ( 0 ) + + #define ca_verify_noerr(errorCode) \ + do \ + { \ + if ( 0 != (errorCode) ) \ + { \ + } \ + } while ( 0 ) + + #define ca_debug_string(message) + + #define ca_verify(assertion) \ + do \ + { \ + if ( !(assertion) ) \ + { \ + } \ + } while ( 0 ) + + #define ca_require(assertion, exceptionLabel) \ + do \ + { \ + if ( __builtin_expect(!(assertion), 0) ) \ + { \ + goto exceptionLabel; \ + } \ + } while ( 0 ) + + #define ca_check(assertion) \ + do \ + { \ + if ( !(assertion) ) \ + { \ + } \ + } while ( 0 ) + + +#endif + +#define XThrow(error, operation) XThrowIf(true, error, operation) +#define XThrowIfErr(error) XThrowIfError(error, #error) + +#endif // __CAXException_h__ diff --git a/ios/IOSDuoduo/Voice/manager/RawAudioDataPlayer.h b/ios/IOSDuoduo/Voice/manager/RawAudioDataPlayer.h new file mode 100755 index 000000000..ce317cc94 --- /dev/null +++ b/ios/IOSDuoduo/Voice/manager/RawAudioDataPlayer.h @@ -0,0 +1,40 @@ +// +// RawAudioDataPlayer.h +// OggSpeex +// +// Created by Jiang Chuncheng on 6/25/13. +// Copyright (c) 2013 Sense Force. All rights reserved. +// + +#import +#import +#import + +#define QUEUE_BUFFER_SIZE 4 //队列缓冲个数 +#define EVERY_READ_LENGTH 1000 //每次从文件读取的长度 +#define MIN_SIZE_PER_FRAME 2000 //每侦最小数据长 + +#define NOTIFICATION_PLAY_OVER @"playingOver" + +@interface RawAudioDataPlayer : NSObject { + AudioStreamBasicDescription audioDescription;///音频参数 + AudioQueueRef audioQueue;//音频播放队列 + AudioQueueBufferRef audioQueueBuffers[QUEUE_BUFFER_SIZE];//音频缓存 + NSLock *synlock ;///同步控制 + Byte *pcmDataBuffer;//pcm的读文件数据区 + + BOOL isDataInputOver; + NSMutableData *mPcmData; + NSUInteger readedBytes; + NSMutableArray *emptyAudioQueueBufferIndexs; +} + +@property (nonatomic, assign) BOOL isDataInputOver; + +//static void AudioPlayerAQInputCallback(void *input, AudioQueueRef inQ, AudioQueueBufferRef outQB); + +- (void)startPlay; +- (void)stopPlay; +- (void)inputNewDataFromBuffer:(Byte *)buffer size:(int)bufferSize; + +@end diff --git a/ios/IOSDuoduo/Voice/manager/RawAudioDataPlayer.m b/ios/IOSDuoduo/Voice/manager/RawAudioDataPlayer.m new file mode 100755 index 000000000..4908f409e --- /dev/null +++ b/ios/IOSDuoduo/Voice/manager/RawAudioDataPlayer.m @@ -0,0 +1,209 @@ +// +// RawAudioDataPlayer.m +// OggSpeex +// +// Created by Jiang Chuncheng on 6/25/13. +// Copyright (c) 2013 Sense Force. All rights reserved. +// + +#import "RawAudioDataPlayer.h" + +static void AudioPlayerAQInputCallback(void *input, AudioQueueRef inQ, AudioQueueBufferRef outQB); + +@interface RawAudioDataPlayer() + +- (void)prepare; +- (void)initAudio; +- (void)readPCMAndPlay:(AudioQueueRef)outQ buffer:(AudioQueueBufferRef)outQB; +- (int)checkUsedQueueBuffer:(AudioQueueBufferRef) qbuf; +- (void)putEmptyBuffer:(AudioQueueBufferRef)buffer; +- (void)removeEmptyBuffer:(AudioQueueBufferRef)buffer; + +@end + +@implementation RawAudioDataPlayer + +@synthesize isDataInputOver; + +- (id)init { + self = [super init]; + if (self) { + mPcmData = [NSMutableData data]; + readedBytes = 0; + pcmDataBuffer = malloc(EVERY_READ_LENGTH); + synlock = [[NSLock alloc] init]; + emptyAudioQueueBufferIndexs = [NSMutableArray arrayWithCapacity:QUEUE_BUFFER_SIZE]; + } + return self; +} + +- (void)prepare { + isDataInputOver = NO; + readedBytes = 0; + [emptyAudioQueueBufferIndexs removeAllObjects]; +} + +-(void)startPlay { + [self initAudio]; + [self prepare]; + OSStatus status = AudioQueueStart(audioQueue, NULL); + if (status) { + [[NSNotificationCenter defaultCenter] postNotificationName:NOTIFICATION_PLAY_OVER object:nil]; + return; + } + for(int i=0;i 0) { //如果有空闲的audio queue buffer就尝试填入 + [self readPCMAndPlay:audioQueue buffer:audioQueueBuffers[[[emptyAudioQueueBufferIndexs objectAtIndex:0] intValue]]]; + } + +} + +- (void)setIsDataInputOver:(BOOL)dataInputOver { + isDataInputOver = dataInputOver; + if (dataInputOver) { + if ([emptyAudioQueueBufferIndexs count] == QUEUE_BUFFER_SIZE) { + NSLog(@"audio queue play over"); + [self stopPlay]; + [[NSNotificationCenter defaultCenter] postNotificationName:NOTIFICATION_PLAY_OVER object:nil]; + } + } +} + +-(void)readPCMAndPlay:(AudioQueueRef)outQ buffer:(AudioQueueBufferRef)outQB +{ + [synlock lock]; + + NSUInteger lengthLeft = [mPcmData length] - readedBytes; //能够读取的数据长度 + if ((lengthLeft < EVERY_READ_LENGTH) && ( ! isDataInputOver)) { //数据不足以填充queue buffer + [self putEmptyBuffer:outQB]; + } + else { + if ([emptyAudioQueueBufferIndexs count] > 0) { + if (lengthLeft == 0 && isDataInputOver) { + //所有数据都输入并且读取完了 + if ([emptyAudioQueueBufferIndexs count] == QUEUE_BUFFER_SIZE) { + NSLog(@"audio queue play over"); + [[NSNotificationCenter defaultCenter] postNotificationName:NOTIFICATION_PLAY_OVER object:nil]; + } + } + else { + [self removeEmptyBuffer:outQB]; + + NSUInteger readLength = (lengthLeft > EVERY_READ_LENGTH) ? EVERY_READ_LENGTH : lengthLeft; + outQB->mAudioDataByteSize = readLength; + Byte *audioData = (Byte *)outQB->mAudioData; + memcpy(audioData, [mPcmData bytes] + readedBytes, readLength); + readedBytes += readLength; + /* + 将创建的buffer区添加到audioqueue里播放 + AudioQueueBufferRef用来缓存待播放的数据区,AudioQueueBufferRef有两个比较重要的参数,AudioQueueBufferRef->mAudioDataByteSize用来指示数据区大小,AudioQueueBufferRef->mAudioData用来保存数据区 + */ + AudioQueueEnqueueBuffer(outQ, outQB, 0, NULL); + } + + } + } + [synlock unlock]; +} + +- (void)putEmptyBuffer:(AudioQueueBufferRef)buffer { + BOOL isInArray = NO; + int indexValue = [self checkUsedQueueBuffer:buffer]; + for (NSNumber *index in emptyAudioQueueBufferIndexs) { + if ([index intValue] == indexValue) { + isInArray = YES; + } + } + if ( ! isInArray) { + [emptyAudioQueueBufferIndexs addObject:[NSNumber numberWithInt:indexValue]]; + } +} + +- (void)removeEmptyBuffer:(AudioQueueBufferRef)buffer { + int indexValue = [self checkUsedQueueBuffer:buffer]; + for (NSNumber *index in emptyAudioQueueBufferIndexs) { + if ([index intValue] == indexValue) { + [emptyAudioQueueBufferIndexs removeObject:index]; + return; + } + } +} + +-(int)checkUsedQueueBuffer:(AudioQueueBufferRef) qbuf { + int bufferIndex = 0; + if(qbuf == audioQueueBuffers[0]) { + bufferIndex = 0; + } + if(qbuf == audioQueueBuffers[1]) { + bufferIndex = 1; + } + if(qbuf == audioQueueBuffers[2]) { + bufferIndex = 2; + } + if(qbuf == audioQueueBuffers[3]) { + bufferIndex = 3; + } + return bufferIndex; +} + + +- (void)dealloc { + free(pcmDataBuffer); +} + +#pragma mark - +#pragma mark player call back +/* + 试了下其实可以不用静态函数,但是c写法的函数内是无法调用[self ***]这种格式的写法,所以还是用静态函数通过void *input来获取原类指针 + 这个回调存在的意义是为了重用缓冲buffer区,当通过AudioQueueEnqueueBuffer(outQ, outQB, 0, NULL);函数放入queue里面的音频文件播放完以后,通过这个函数通知 + 调用者,这样可以重新再使用回调传回的AudioQueueBufferRef + */ +static void AudioPlayerAQInputCallback(void *input, AudioQueueRef outQ, AudioQueueBufferRef outQB) { + @autoreleasepool { + RawAudioDataPlayer *player = (__bridge RawAudioDataPlayer *)input; + [player putEmptyBuffer:outQB]; + [player readPCMAndPlay:outQ buffer:outQB]; + } +} + +@end diff --git a/ios/IOSDuoduo/Voice/manager/RecorderManager.h b/ios/IOSDuoduo/Voice/manager/RecorderManager.h new file mode 100755 index 000000000..1e6917374 --- /dev/null +++ b/ios/IOSDuoduo/Voice/manager/RecorderManager.h @@ -0,0 +1,50 @@ +// +// RecorderManager.h +// OggSpeex +// +// Created by Jiang Chuncheng on 6/25/13. +// Copyright (c) 2013 Sense Force. All rights reserved. +// + +#import +//#import "AQRecorder.h" +#import "Encapsulator.h" + +@protocol RecordingDelegate + +@optional +- (void)levelMeterChanged:(float)levelMeter; +- (void)recordingFinishedWithFileName:(NSString *)filePath time:(NSTimeInterval)interval; +- (void)recordingTimeout; +- (void)recordingStopped; //录音机停止采集声音 +- (void)recordingFailed:(NSString *)failureInfoString; + +@end + +@interface RecorderManager : NSObject { + + Encapsulator *encapsulator; + NSString *filename; + NSDate *dateStartRecording; + NSDate *dateStopRecording; + NSTimer *timerLevelMeter; + NSTimer *timerTimeout; +} + +@property (nonatomic, weak) id delegate; +@property (nonatomic, strong) Encapsulator *encapsulator; +@property (nonatomic, strong) NSDate *dateStartRecording, *dateStopRecording; +@property (nonatomic, strong) NSTimer *timerLevelMeter; +@property (nonatomic, strong) NSTimer *timerTimeout; + ++ (RecorderManager *)sharedManager; + +- (void)startRecording; + +- (void)stopRecording; + +- (void)cancelRecording; + +- (NSTimeInterval)recordedTimeInterval; + +@end diff --git a/ios/IOSDuoduo/Voice/manager/RecorderManager.mm b/ios/IOSDuoduo/Voice/manager/RecorderManager.mm new file mode 100755 index 000000000..1f3cc49b1 --- /dev/null +++ b/ios/IOSDuoduo/Voice/manager/RecorderManager.mm @@ -0,0 +1,241 @@ +// +// RecorderManager.mm +// OggSpeex +// +// Created by Jiang Chuncheng on 6/25/13. +// Copyright (c) 2013 Sense Force. All rights reserved. +// + +#import "RecorderManager.h" +#import "AQRecorder.h" +#import +#import + +@interface RecorderManager() + +- (void)updateLevelMeter:(id)sender; +- (void)stopRecording:(BOOL)isCanceled; + +@end + +@implementation RecorderManager + +@synthesize dateStartRecording, dateStopRecording; +@synthesize encapsulator; +@synthesize timerLevelMeter; +@synthesize timerTimeout; + +static RecorderManager *mRecorderManager = nil; +AQRecorder *mAQRecorder; +AudioQueueLevelMeterState *levelMeterStates; + ++ (RecorderManager *)sharedManager { + @synchronized(self) { + if (mRecorderManager == nil) + { + mRecorderManager = [[self alloc] init]; + } + } + return mRecorderManager; +} + ++ (id)allocWithZone:(NSZone *)zone +{ + @synchronized(self) + { + if(mRecorderManager == nil) + { + mRecorderManager = [super allocWithZone:zone]; + return mRecorderManager; + } + } + + return nil; +} + +- (void)startRecording { + [[AVAudioSession sharedInstance] setCategory:AVAudioSessionCategoryPlayAndRecord error:nil]; + if ( ! mAQRecorder) { + + mAQRecorder = new AQRecorder(); + + OSStatus error = AudioSessionInitialize(NULL, NULL, interruptionListener, (__bridge void *)self); + if (error) printf("ERROR INITIALIZING AUDIO SESSION! %d\n", (int)error); + else + { + UInt32 category = kAudioSessionCategory_PlayAndRecord; + error = AudioSessionSetProperty(kAudioSessionProperty_AudioCategory, sizeof(category), &category); + if (error) printf("couldn't set audio category!"); + + error = AudioSessionAddPropertyListener(kAudioSessionProperty_AudioRouteChange, propListener, (__bridge void *)self); + if (error) printf("ERROR ADDING AUDIO SESSION PROP LISTENER! %d\n", (int)error); + UInt32 inputAvailable = 0; + UInt32 size = sizeof(inputAvailable); + + // we do not want to allow recording if input is not available + error = AudioSessionGetProperty(kAudioSessionProperty_AudioInputAvailable, &size, &inputAvailable); + if (error) printf("ERROR GETTING INPUT AVAILABILITY! %d\n", (int)error); + + // we also need to listen to see if input availability changes + error = AudioSessionAddPropertyListener(kAudioSessionProperty_AudioInputAvailable, propListener, (__bridge void *)self); + if (error) printf("ERROR ADDING AUDIO SESSION PROP LISTENER! %d\n", (int)error); + + error = AudioSessionSetActive(true); + if (error) printf("AudioSessionSetActive (true) failed"); + } + + } + + filename = [NSString stringWithString:[Encapsulator defaultFileName]]; + NSLog(@"filename:%@",filename); + +// if (self.encapsulator) { +// self.encapsulator.delegete = nil; +// [self.encapsulator release]; +// } +// self.encapsulator = [[[Encapsulator alloc] initWithFileName:filename] autorelease]; +// self.encapsulator.delegete = self; + + if ( ! self.encapsulator) { + self.encapsulator = [[Encapsulator alloc] initWithFileName:filename]; + self.encapsulator.delegete = self; + } + else { + [self.encapsulator resetWithFileName:filename]; + } + if ( ! mAQRecorder->IsRunning()) { + mAQRecorder->StartRecord(self.encapsulator); + } + if ( ! mAQRecorder->IsRunning()) { + mAQRecorder->StartRecord(self.encapsulator); + NSLog(@"audio session category : %@", [[AVAudioSession sharedInstance] category]); + Boolean recordingWillBegin = mAQRecorder->StartRecord(encapsulator); + if ( ! recordingWillBegin) { + if ([self.delegate respondsToSelector:@selector(recordingFailed:)]) { + [self.delegate recordingFailed:@"程序错误,无法继续录音,请重启程序试试"]; + } + return; + } + } + + self.dateStartRecording = [NSDate date]; + + if (!levelMeterStates) + { + levelMeterStates = (AudioQueueLevelMeterState *)malloc(sizeof(AudioQueueLevelMeterState) * 1); + } + self.timerLevelMeter = [NSTimer scheduledTimerWithTimeInterval:0.1 target:self selector:@selector(updateLevelMeter:) userInfo:nil repeats:YES]; + self.timerTimeout = [NSTimer scheduledTimerWithTimeInterval:60 target:self selector:@selector(timeoutCheck:) userInfo:nil repeats:NO]; +} + +- (void)stopRecording { + [self stopRecording:NO]; +} + +- (void)cancelRecording { + [self stopRecording:YES]; +} + +- (void)stopRecording:(BOOL)isCanceled { + self.dateStopRecording = [NSDate date]; + if (self.delegate) { + // [self.delegate recordingStopped]; + } + if (isCanceled) { + if (self.encapsulator) { + [self.encapsulator stopEncapsulating:YES]; + } + } + [self.timerLevelMeter invalidate]; + [self.timerTimeout invalidate]; + self.timerLevelMeter = nil; +// free(levelMeterStates); + if (mAQRecorder) { + mAQRecorder->StopRecord(); + } + +} + +- (void)encapsulatingOver { + if (self.delegate) { + [self.delegate recordingFinishedWithFileName:filename time:[self recordedTimeInterval]]; + } +} + +- (NSTimeInterval)recordedTimeInterval { + DDLog(@"record start time %@______ record stop time %@",dateStartRecording,dateStopRecording); + return (dateStopRecording && dateStartRecording) ? [dateStopRecording timeIntervalSinceDate:dateStartRecording] : 0; +} + +- (void)updateLevelMeter:(id)sender { + if (self.delegate) { + UInt32 dataSize = sizeof(AudioQueueLevelMeterState); + AudioQueueGetProperty(mAQRecorder->Queue(), kAudioQueueProperty_CurrentLevelMeter, levelMeterStates, &dataSize); + if ([self.delegate respondsToSelector:@selector(levelMeterChanged:)]) { + [self.delegate levelMeterChanged:levelMeterStates[0].mPeakPower]; + } + + } +} + +- (void)timeoutCheck:(id)sender { + [[self delegate] recordingTimeout]; +} + +- (void)dealloc { + if (mAQRecorder) { + delete mAQRecorder; + } + if (levelMeterStates) + { + delete levelMeterStates; + } + self.encapsulator = nil; +} + +#pragma mark AudioSession listeners +void interruptionListener( void * inClientData, + UInt32 inInterruptionState) +{ + RecorderManager *THIS = (__bridge RecorderManager*)inClientData; + if (inInterruptionState == kAudioSessionBeginInterruption) + { + if (mAQRecorder->IsRunning()) { + [THIS stopRecording]; + } + } +} + +void propListener( void * inClientData, + AudioSessionPropertyID inID, + UInt32 inDataSize, + const void * inData) +{ + RecorderManager *THIS = (__bridge RecorderManager*)inClientData; + if (inID == kAudioSessionProperty_AudioRouteChange) + { + CFDictionaryRef routeDictionary = (CFDictionaryRef)inData; + //CFShow(routeDictionary); + CFNumberRef reason = (CFNumberRef)CFDictionaryGetValue(routeDictionary, CFSTR(kAudioSession_AudioRouteChangeKey_Reason)); + SInt32 reasonVal; + CFNumberGetValue(reason, kCFNumberSInt32Type, &reasonVal); + if (reasonVal != kAudioSessionRouteChangeReason_CategoryChange) + { + // stop the queue if we had a non-policy route change + if (mAQRecorder->IsRunning()) { + [THIS stopRecording]; + } + } + } + else if (inID == kAudioSessionProperty_AudioInputAvailable) + { + if (inDataSize == sizeof(UInt32)) + { +// UInt32 isAvailable = *(UInt32*)inData; + // disable recording if input is not available +// BOOL available = (isAvailable > 0) ? YES : NO; + } + } +} + +@end diff --git a/ios/IOSDuoduo/XLog.h b/ios/IOSDuoduo/XLog.h new file mode 100644 index 000000000..5b2e845ee --- /dev/null +++ b/ios/IOSDuoduo/XLog.h @@ -0,0 +1,27 @@ +// +// XLog.h +// IOSDuoduo +// +// Created by 东邪 on 14-5-23. +// Copyright (c) 2014年 dujia. All rights reserved. +// + + +#import +#define _XLOG + +#ifdef _XLOG +#define LogOut(format,...); DLog(@"[%s][%d]" format,__func__,__LINE__,##__VA_ARGS__); +#define LogOutMethodFun DLog( @"[%@] %@", NSStringFromClass([self class]), NSStringFromSelector(_cmd) ); +#define LogError(format,...); DLog(@"[error][%s][%d]" format,__func__,__LINE__,##__VA_ARGS__); +#define LogWaring(format,...); DLog(@"[waring][%s][%d]" format,__func__,__LINE__,##__VA_ARGS__); +#define LogTeym(format,...); {} +#else +#define LogOut(format,...); {} +#define LogOutMethodFun {} +#define LogError(format,...); {} +#define LogWaring(format,...); {} +#define LogTeym(format,...); {} +#endif + + diff --git a/ios/IOSDuoduo/std.h b/ios/IOSDuoduo/std.h new file mode 100755 index 000000000..55a0cfca7 --- /dev/null +++ b/ios/IOSDuoduo/std.h @@ -0,0 +1,88 @@ +// +// std.h +// IOSDuoduo +// +// Created by 东邪 on 14-5-23. +// Copyright (c) 2014年 dujia. All rights reserved. +// + + +#import +#import "XLog.h" +#define objectOrNull(obj) ((obj) ? (obj) : [NSNull null]) +#define objectOrEmptyStr(obj) ((obj) ? (obj) : @"") + +#define isNull(x) (!x || [x isKindOfClass:[NSNull class]]) +#define toInt(x) (isNull(x) ? 0 : [x intValue]) +#define isEmptyString(x) (isNull(x) || [x isEqual:@""] || [x isEqual:@"(null)"]) + +#define sleep(s); [NSThread sleepForTimeInterval:s]; +#define Syn(x) @synthesize x = _##x + +#define RGBA(r,g,b,a) [UIColor colorWithRed:r/255.0 green:g/255.0 blue:b/255.0 alpha:a] +#define RGB(r,g,b) [UIColor colorWithRed:r/255.0 green:g/255.0 blue:b/255.0 alpha:1.0] +#define BoldSystemFont(size) [UIFont boldSystemFontOfSize:size] +#define systemFont(size) [UIFont systemFontOfSize:size] +#define beginAutoPool NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init]; { +#define endAutoPool } [pool release]; +#define skipspace(c) while (isspace(*c)) ++c +#define skipUntil(c,x) while (x != *c) ++c +#define TheWindowHeight ([UIDevice isAfterOS7] ? [UIScreen mainScreen].bounds.size.height : ([UIScreen mainScreen].bounds.size.height - 20)) +#define IntToNumber(int) ([NSNumber numberWithInt:int]) +#define isIOS7 [[UIDevice currentDevice].systemVersion doubleValue]>=7.0?YES:NO +#define SYSTEM_VERSION [[[UIDevice currentDevice] systemVersion] floatValue] +#define STATUSBAR_HEIGHT [[UIApplication sharedApplication] statusBarFrame].size.height +#define NAVBAR_HEIGHT (44.f + ((SYSTEM_VERSION >= 7) ? STATUSBAR_HEIGHT : 0)) +#define FULL_WIDTH SCREEN_WIDTH +#define FULL_HEIGHT (SCREEN_HEIGHT - ((SYSTEM_VERSION >= 7) ? 0 : STATUSBAR_HEIGHT)) +#define CONTENT_HEIGHT (FULL_HEIGHT - NAVBAR_HEIGHT) +// 屏幕高度 +#define SCREEN_HEIGHT [[UIScreen mainScreen] bounds].size.height + +// 屏幕宽度 +#define SCREEN_WIDTH [[UIScreen mainScreen] bounds].size.width +#define PhotosMessageDir ([[NSString documentPath] stringByAppendingPathComponent:@"/PhotosMessageDir/"]) +#define IPHONE4 ( [ [ UIScreen mainScreen ] bounds ].size.height == 480 ) +//字体颜色 +#define GRAYCOLOR RGB(137, 139, 144) +extern NSString * const kInvited; +extern NSString * const kUserSetting; +extern NSString * const kLastLoginUser; +extern NSString * const kHasAlertVIP; +extern NSString * const kLastPosition; +extern NSString * const kAccessToken; +extern NSString * const kRefreshToken; +extern NSString * const kTokenExpiredTime; +extern NSString * const kAppVersion; +extern NSString * const kArrowCount; + + +#define FileManager ([NSFileManager defaultManager]) +#define TheUserDefaults ([NSUserDefaults standardUserDefaults]) +#define VoiceMessageDir ([[NSString documentPath] stringByAppendingPathComponent:@"/VoiceMessageDir/"]) +#define BlacklistDir ([[NSString documentPath] stringByAppendingPathComponent:@"/BlacklistDir/"]) +#define Departmentlist ([[NSString documentPath] stringByAppendingPathComponent:@"/department.plist"]) +#define fixedlist ([[NSString documentPath] stringByAppendingPathComponent:@"/fixed.plist"]) +#define shieldinglist ([[NSString documentPath] stringByAppendingPathComponent:@"/shieldingArray.plist"]) +#define TheBundleVerison (bundleVerison()) +#undef AS_SINGLETON +#define AS_SINGLETON( __class ) \ ++ (__class *)sharedInstance; + +#undef DEF_SINGLETON +#define DEF_SINGLETON( __class ) \ ++ (__class *)sharedInstance \ +{ \ +static dispatch_once_t once; \ +static __class * __singleton__; \ +dispatch_once( &once, ^{ __singleton__ = [[__class alloc] init]; } ); \ +return __singleton__; \ +} + +@protocol DDShareObjDelegate + +- (NSString*)shareTypeName; + +@end +char pinyinFirstLetter(unsigned short hanzi); +char getFirstChar(const NSString * str); diff --git a/ios/IOSDuoduo/std.m b/ios/IOSDuoduo/std.m new file mode 100755 index 000000000..dd5c4e8af --- /dev/null +++ b/ios/IOSDuoduo/std.m @@ -0,0 +1,268 @@ +// +// std.m +// IOSDuoduo +// +// Created by 东邪 on 14-5-23. +// Copyright (c) 2014年 dujia. All rights reserved. +// + +#import "std.h" +NSString * const kInvited = @"kInvited"; +NSString * const kUserSetting = @"kUserSetting"; +NSString * const kLastLoginUser = @"kLastLoginUser"; +NSString * const kLastPosition = @"last_pos"; +NSString * const kAccessToken = @"access_token"; +NSString * const kRefreshToken = @"refresh_token"; +NSString * const kTokenExpiredTime = @"expires_in"; +NSString * const kAppVersion = @"kAppVersion"; +NSString * const kArrowCount = @"kArrowCount"; + +NSString *bundleVerison(){ + NSBundle * bundle=[NSBundle mainBundle]; + NSString * ver=[bundle.infoDictionary objectForKey:@"CFBundleShortVersionString"]; + return ver; +} + + +#define HANZI_START 19968 +#define HANZI_COUNT 20902 +static char firstLetterArray[HANZI_COUNT] = +"ydkqsxnwzssxjbymgcczqpssqbycdscdqldylybssjgyqzjjfgcclzznwdwzjljpfyynnjjtmynzwzhflzppqhgccyynmjqyxxgd" +"nnsnsjnjnsnnmlnrxyfsngnnnnqzggllyjlnyzssecykyyhqwjssggyxyqyjtwktjhychmnxjtlhjyqbyxdldwrrjnwysrldzjpc" +"bzjjbrcfslnczstzfxxchtrqggddlyccssymmrjcyqzpwwjjyfcrwfdfzqpyddwyxkyjawjffxjbcftzyhhycyswccyxsclcxxwz" +"cxnbgnnxbxlzsqsbsjpysazdhmdzbqbscwdzzyytzhbtsyyfzgntnxjywqnknphhlxgybfmjnbjhhgqtjcysxstkzglyckglysmz" +"xyalmeldccxgzyrjxjzlnjzcqkcnnjwhjczccqljststbnhbtyxceqxkkwjyflzqlyhjxspsfxlmpbysxxxytccnylllsjxfhjxp" +"jbtffyabyxbcczbzyclwlczggbtssmdtjcxpthyqtgjjxcjfzkjzjqnlzwlslhdzbwjncjzyzsqnycqynzcjjwybrtwpyftwexcs" +"kdzctbyhyzqyyjxzcfbzzmjyxxsdczottbzljwfckscsxfyrlrygmbdthjxsqjccsbxyytswfbjdztnbcnzlcyzzpsacyzzsqqcs" +"hzqydxlbpjllmqxqydzxsqjtzpxlcglqdcwzfhctdjjsfxjejjtlbgxsxjmyjjqpfzasyjnsydjxkjcdjsznbartcclnjqmwnqnc" +"lllkbdbzzsyhqcltwlccrshllzntylnewyzyxczxxgdkdmtcedejtsyyssdqdfmxdbjlkrwnqlybglxnlgtgxbqjdznyjsjyjcjm" +"rnymgrcjczgjmzmgxmmryxkjnymsgmzzymknfxmbdtgfbhcjhkylpfmdxlxjjsmsqgzsjlqdldgjycalcmzcsdjllnxdjffffjcn" +"fnnffpfkhkgdpqxktacjdhhzdddrrcfqyjkqccwjdxhwjlyllzgcfcqjsmlzpbjjblsbcjggdckkdezsqcckjgcgkdjtjllzycxk" +"lqccgjcltfpcqczgwbjdqyzjjbyjhsjddwgfsjgzkcjctllfspkjgqjhzzljplgjgjjthjjyjzccmlzlyqbgjwmljkxzdznjqsyz" +"mljlljkywxmkjlhskjhbmclyymkxjqlbmllkmdxxkwyxwslmlpsjqqjqxyqfjtjdxmxxllcrqbsyjbgwynnggbcnxpjtgpapfgdj" +"qbhbncfjyzjkjkhxqfgqckfhygkhdkllsdjqxpqyaybnqsxqnszswhbsxwhxwbzzxdmndjbsbkbbzklylxgwxjjwaqzmywsjqlsj" +"xxjqwjeqxnchetlzalyyyszzpnkyzcptlshtzcfycyxyljsdcjqagyslcllyyysslqqqnldxzsccscadycjysfsgbfrsszqsbxjp" +"sjysdrckgjlgtkzjzbdktcsyqpyhstcldjnhmymcgxyzhjdctmhltxzhylamoxyjcltyfbqqjpfbdfehthsqhzywwcncxcdwhowg" +"yjlegmdqcwgfjhcsntmydolbygnqwesqpwnmlrydzszzlyqpzgcwxhnxpyxshmdqjgztdppbfbhzhhjyfdzwkgkzbldnzsxhqeeg" +"zxylzmmzyjzgszxkhkhtxexxgylyapsthxdwhzydpxagkydxbhnhnkdnjnmyhylpmgecslnzhkxxlbzzlbmlsfbhhgsgyyggbhsc" +"yajtxglxtzmcwzydqdqmngdnllszhngjzwfyhqswscelqajynytlsxthaznkzzsdhlaxxtwwcjhqqtddwzbcchyqzflxpslzqgpz" +"sznglydqtbdlxntctajdkywnsyzljhhdzckryyzywmhychhhxhjkzwsxhdnxlyscqydpslyzwmypnkxyjlkchtyhaxqsyshxasmc" +"hkdscrsgjpwqsgzjlwwschsjhsqnhnsngndantbaalczmsstdqjcjktscjnxplggxhhgoxzcxpdmmhldgtybynjmxhmrzplxjzck" +"zxshflqxxcdhxwzpckczcdytcjyxqhlxdhypjqxnlsyydzozjnhhqezysjyayxkypdgxddnsppyzndhthrhxydpcjjhtcnnctlhb" +"ynyhmhzllnnxmylllmdcppxhmxdkycyrdltxjchhznxclcclylnzsxnjzzlnnnnwhyqsnjhxynttdkyjpychhyegkcwtwlgjrlgg" +"tgtygyhpyhylqyqgcwyqkpyyettttlhyylltyttsylnyzwgywgpydqqzzdqnnkcqnmjjzzbxtqfjkdffbtkhzkbxdjjkdjjtlbwf" +"zpptkqtztgpdwntpjyfalqmkgxbcclzfhzcllllanpnxtjklcclgyhdzfgyddgcyyfgydxkssendhykdndknnaxxhbpbyyhxccga" +"pfqyjjdmlxcsjzllpcnbsxgjyndybwjspcwjlzkzddtacsbkzdyzypjzqsjnkktknjdjgyepgtlnyqnacdntcyhblgdzhbbydmjr" +"egkzyheyybjmcdtafzjzhgcjnlghldwxjjkytcyksssmtwcttqzlpbszdtwcxgzagyktywxlnlcpbclloqmmzsslcmbjcsdzkydc" +"zjgqjdsmcytzqqlnzqzxssbpkdfqmddzzsddtdmfhtdycnaqjqkypbdjyyxtljhdrqxlmhkydhrnlklytwhllrllrcxylbnsrnzz" +"symqzzhhkyhxksmzsyzgcxfbnbsqlfzxxnnxkxwymsddyqnggqmmyhcdzttfgyyhgsbttybykjdnkyjbelhdypjqnfxfdnkzhqks" +"byjtzbxhfdsbdaswpawajldyjsfhblcnndnqjtjnchxfjsrfwhzfmdrfjyxwzpdjkzyjympcyznynxfbytfyfwygdbnzzzdnytxz" +"emmqbsqehxfznbmflzzsrsyqjgsxwzjsprytjsjgskjjgljjynzjjxhgjkymlpyyycxycgqzswhwlyrjlpxslcxmnsmwklcdnkny" +"npsjszhdzeptxmwywxyysywlxjqcqxzdclaeelmcpjpclwbxsqhfwrtfnjtnqjhjqdxhwlbyccfjlylkyynldxnhycstyywncjtx" +"ywtrmdrqnwqcmfjdxzmhmayxnwmyzqtxtlmrspwwjhanbxtgzypxyyrrclmpamgkqjszycymyjsnxtplnbappypylxmyzkynldgy" +"jzcchnlmzhhanqnbgwqtzmxxmllhgdzxnhxhrxycjmffxywcfsbssqlhnndycannmtcjcypnxnytycnnymnmsxndlylysljnlxys" +"sqmllyzlzjjjkyzzcsfbzxxmstbjgnxnchlsnmcjscyznfzlxbrnnnylmnrtgzqysatswryhyjzmgdhzgzdwybsscskxsyhytsxg" +"cqgxzzbhyxjscrhmkkbsczjyjymkqhzjfnbhmqhysnjnzybknqmcjgqhwlsnzswxkhljhyybqcbfcdsxdldspfzfskjjzwzxsddx" +"jseeegjscssygclxxnwwyllymwwwgydkzjggggggsycknjwnjpcxbjjtqtjwdsspjxcxnzxnmelptfsxtllxcljxjjljsxctnswx" +"lennlyqrwhsycsqnybyaywjejqfwqcqqcjqgxaldbzzyjgkgxbltqyfxjltpydkyqhpmatlcndnkxmtxynhklefxdllegqtymsaw" +"hzmljtkynxlyjzljeeyybqqffnlyxhdsctgjhxywlkllxqkcctnhjlqmkkzgcyygllljdcgydhzwypysjbzjdzgyzzhywyfqdtyz" +"szyezklymgjjhtsmqwyzljyywzcsrkqyqltdxwcdrjalwsqzwbdcqyncjnnszjlncdcdtlzzzacqqzzddxyblxcbqjylzllljddz" +"jgyqyjzyxnyyyexjxksdaznyrdlzyyynjlslldyxjcykywnqcclddnyyynycgczhjxcclgzqjgnwnncqqjysbzzxyjxjnxjfzbsb" +"dsfnsfpzxhdwztdmpptflzzbzdmyypqjrsdzsqzsqxbdgcpzswdwcsqzgmdhzxmwwfybpngphdmjthzsmmbgzmbzjcfzhfcbbnmq" +"dfmbcmcjxlgpnjbbxgyhyyjgptzgzmqbqdcgybjxlwnkydpdymgcftpfxyztzxdzxtgkptybbclbjaskytssqyymscxfjhhlslls" +"jpqjjqaklyldlycctsxmcwfgngbqxllllnyxtyltyxytdpjhnhgnkbyqnfjyyzbyyessessgdyhfhwtcqbsdzjtfdmxhcnjzymqw" +"srxjdzjqbdqbbsdjgnfbknbxdkqhmkwjjjgdllthzhhyyyyhhsxztyyyccbdbpypzyccztjpzywcbdlfwzcwjdxxhyhlhwczxjtc" +"nlcdpxnqczczlyxjjcjbhfxwpywxzpcdzzbdccjwjhmlxbqxxbylrddgjrrctttgqdczwmxfytmmzcwjwxyywzzkybzcccttqnhx" +"nwxxkhkfhtswoccjybcmpzzykbnnzpbthhjdlszddytyfjpxyngfxbyqxzbhxcpxxtnzdnnycnxsxlhkmzxlthdhkghxxsshqyhh" +"cjyxglhzxcxnhekdtgqxqypkdhentykcnymyyjmkqyyyjxzlthhqtbyqhxbmyhsqckwwyllhcyylnneqxqwmcfbdccmljggxdqkt" +"lxkknqcdgcjwyjjlyhhqyttnwchhxcxwherzjydjccdbqcdgdnyxzdhcqrxcbhztqcbxwgqwyybxhmbymykdyecmqkyaqyngyzsl" +"fnkkqgyssqyshngjctxkzycssbkyxhyylstycxqthysmnscpmmgcccccmnztasmgqzjhklosjylswtmqzyqkdzljqqyplzycztcq" +"qpbbcjzclpkhqcyyxxdtdddsjcxffllchqxmjlwcjcxtspycxndtjshjwhdqqqckxyamylsjhmlalygxcyydmamdqmlmcznnyybz" +"xkyflmcncmlhxrcjjhsylnmtjggzgywjxsrxcwjgjqhqzdqjdcjjskjkgdzcgjjyjylxzxxcdqhhheslmhlfsbdjsyyshfyssczq" +"lpbdrfnztzdkykhsccgkwtqzckmsynbcrxqbjyfaxpzzedzcjykbcjwhyjbqzzywnyszptdkzpfpbaztklqnhbbzptpptyzzybhn" +"ydcpzmmcycqmcjfzzdcmnlfpbplngqjtbttajzpzbbdnjkljqylnbzqhksjznggqstzkcxchpzsnbcgzkddzqanzgjkdrtlzldwj" +"njzlywtxndjzjhxnatncbgtzcsskmljpjytsnwxcfjwjjtkhtzplbhsnjssyjbhbjyzlstlsbjhdnwqpslmmfbjdwajyzccjtbnn" +"nzwxxcdslqgdsdpdzgjtqqpsqlyyjzlgyhsdlctcbjtktyczjtqkbsjlgnnzdncsgpynjzjjyyknhrpwszxmtncszzyshbyhyzax" +"ywkcjtllckjjtjhgcssxyqyczbynnlwqcglzgjgqyqcczssbcrbcskydznxjsqgxssjmecnstjtpbdlthzwxqwqczexnqczgwesg" +"ssbybstscslccgbfsdqnzlccglllzghzcthcnmjgyzazcmsksstzmmzckbjygqljyjppldxrkzyxccsnhshhdznlzhzjjcddcbcj" +"xlbfqbczztpqdnnxljcthqzjgylklszzpcjdscqjhjqkdxgpbajynnsmjtzdxlcjyryynhjbngzjkmjxltbsllrzpylssznxjhll" +"hyllqqzqlsymrcncxsljmlzltzldwdjjllnzggqxppskyggggbfzbdkmwggcxmcgdxjmcjsdycabxjdlnbcddygskydqdxdjjyxh" +"saqazdzfslqxxjnqzylblxxwxqqzbjzlfbblylwdsljhxjyzjwtdjcyfqzqzzdzsxzzqlzcdzfxhwspynpqzmlpplffxjjnzzyls" +"jnyqzfpfzgsywjjjhrdjzzxtxxglghtdxcskyswmmtcwybazbjkshfhgcxmhfqhyxxyzftsjyzbxyxpzlchmzmbxhzzssyfdmncw" +"dabazlxktcshhxkxjjzjsthygxsxyyhhhjwxkzxssbzzwhhhcwtzzzpjxsyxqqjgzyzawllcwxznxgyxyhfmkhydwsqmnjnaycys" +"pmjkgwcqhylajgmzxhmmcnzhbhxclxdjpltxyjkdyylttxfqzhyxxsjbjnayrsmxyplckdnyhlxrlnllstycyyqygzhhsccsmcct" +"zcxhyqfpyyrpbflfqnntszlljmhwtcjqyzwtlnmlmdwmbzzsnzrbpdddlqjjbxtcsnzqqygwcsxfwzlxccrszdzmcyggdyqsgtnn" +"nlsmymmsyhfbjdgyxccpshxczcsbsjyygjmpbwaffyfnxhydxzylremzgzzyndsznlljcsqfnxxkptxzgxjjgbmyyssnbtylbnlh" +"bfzdcyfbmgqrrmzszxysjtznnydzzcdgnjafjbdknzblczszpsgcycjszlmnrznbzzldlnllysxsqzqlcxzlsgkbrxbrbzcycxzj" +"zeeyfgklzlnyhgzcgzlfjhgtgwkraajyzkzqtsshjjxdzyznynnzyrzdqqhgjzxsszbtkjbbfrtjxllfqwjgclqtymblpzdxtzag" +"bdhzzrbgjhwnjtjxlkscfsmwlldcysjtxkzscfwjlbnntzlljzllqblcqmqqcgcdfpbphzczjlpyyghdtgwdxfczqyyyqysrclqz" +"fklzzzgffcqnwglhjycjjczlqzzyjbjzzbpdcsnnjgxdqnknlznnnnpsntsdyfwwdjzjysxyyczcyhzwbbyhxrylybhkjksfxtjj" +"mmchhlltnyymsxxyzpdjjycsycwmdjjkqyrhllngpngtlyycljnnnxjyzfnmlrgjjtyzbsyzmsjyjhgfzqmsyxrszcytlrtqzsst" +"kxgqkgsptgxdnjsgcqcqhmxggztqydjjznlbznxqlhyqgggthqscbyhjhhkyygkggcmjdzllcclxqsftgjslllmlcskctbljszsz" +"mmnytpzsxqhjcnnqnyexzqzcpshkzzyzxxdfgmwqrllqxrfztlystctmjcsjjthjnxtnrztzfqrhcgllgcnnnnjdnlnnytsjtlny" +"xsszxcgjzyqpylfhdjsbbdczgjjjqzjqdybssllcmyttmqnbhjqmnygjyeqyqmzgcjkpdcnmyzgqllslnclmholzgdylfzslncnz" +"lylzcjeshnyllnxnjxlyjyyyxnbcljsswcqqnnyllzldjnllzllbnylnqchxyyqoxccqkyjxxxyklksxeyqhcqkkkkcsnyxxyqxy" +"gwtjohthxpxxhsnlcykychzzcbwqbbwjqcscszsslcylgddsjzmmymcytsdsxxscjpqqsqylyfzychdjynywcbtjsydchcyddjlb" +"djjsodzyqyskkyxdhhgqjyohdyxwgmmmazdybbbppbcmnnpnjzsmtxerxjmhqdntpjdcbsnmssythjtslmltrcplzszmlqdsdmjm" +"qpnqdxcfrnnfsdqqyxhyaykqyddlqyyysszbydslntfgtzqbzmchdhczcwfdxtmqqsphqwwxsrgjcwnntzcqmgwqjrjhtqjbbgwz" +"fxjhnqfxxqywyyhyscdydhhqmrmtmwctbszppzzglmzfollcfwhmmsjzttdhlmyffytzzgzyskjjxqyjzqbhmbzclyghgfmshpcf" +"zsnclpbqsnjyzslxxfpmtyjygbxlldlxpzjyzjyhhzcywhjylsjexfszzywxkzjlnadymlymqjpwxxhxsktqjezrpxxzghmhwqpw" +"qlyjjqjjzszcnhjlchhnxjlqwzjhbmzyxbdhhypylhlhlgfwlcfyytlhjjcwmscpxstkpnhjxsntyxxtestjctlsslstdlllwwyh" +"dnrjzsfgxssyczykwhtdhwjglhtzdqdjzxxqgghltzphcsqfclnjtclzpfstpdynylgmjllycqhynspchylhqyqtmzymbywrfqyk" +"jsyslzdnjmpxyyssrhzjnyqtqdfzbwwdwwrxcwggyhxmkmyyyhmxmzhnksepmlqqmtcwctmxmxjpjjhfxyyzsjzhtybmstsyjznq" +"jnytlhynbyqclcycnzwsmylknjxlggnnpjgtysylymzskttwlgsmzsylmpwlcwxwqcssyzsyxyrhssntsrwpccpwcmhdhhxzdzyf" +"jhgzttsbjhgyglzysmyclllxbtyxhbbzjkssdmalhhycfygmqypjyjqxjllljgclzgqlycjcctotyxmtmshllwlqfxymzmklpszz" +"cxhkjyclctyjcyhxsgyxnnxlzwpyjpxhjwpjpwxqqxlxsdhmrslzzydwdtcxknstzshbsccstplwsscjchjlcgchssphylhfhhxj" +"sxallnylmzdhzxylsxlmzykcldyahlcmddyspjtqjzlngjfsjshctsdszlblmssmnyymjqbjhrzwtyydchjljapzwbgqxbkfnbjd" +"llllyylsjydwhxpsbcmljpscgbhxlqhyrljxyswxhhzlldfhlnnymjljyflyjycdrjlfsyzfsllcqyqfgqyhnszlylmdtdjcnhbz" +"llnwlqxygyyhbmgdhxxnhlzzjzxczzzcyqzfngwpylcpkpykpmclgkdgxzgxwqbdxzzkzfbddlzxjtpjpttbythzzdwslcpnhslt" +"jxxqlhyxxxywzyswttzkhlxzxzpyhgzhknfsyhntjrnxfjcpjztwhplshfcrhnslxxjxxyhzqdxqwnnhyhmjdbflkhcxcwhjfyjc" +"fpqcxqxzyyyjygrpynscsnnnnchkzdyhflxxhjjbyzwttxnncyjjymswyxqrmhxzwfqsylznggbhyxnnbwttcsybhxxwxyhhxyxn" +"knyxmlywrnnqlxbbcljsylfsytjzyhyzawlhorjmnsczjxxxyxchcyqryxqzddsjfslyltsffyxlmtyjmnnyyyxltzcsxqclhzxl" +"wyxzhnnlrxkxjcdyhlbrlmbrdlaxksnlljlyxxlynrylcjtgncmtlzllcyzlpzpzyawnjjfybdyyzsepckzzqdqpbpsjpdyttbdb" +"bbyndycncpjmtmlrmfmmrwyfbsjgygsmdqqqztxmkqwgxllpjgzbqrdjjjfpkjkcxbljmswldtsjxldlppbxcwkcqqbfqbccajzg" +"mykbhyhhzykndqzybpjnspxthlfpnsygyjdbgxnhhjhzjhstrstldxskzysybmxjlxyslbzyslzxjhfybqnbylljqkygzmcyzzym" +"ccslnlhzhwfwyxzmwyxtynxjhbyymcysbmhysmydyshnyzchmjjmzcaahcbjbbhblytylsxsnxgjdhkxxtxxnbhnmlngsltxmrhn" +"lxqqxmzllyswqgdlbjhdcgjyqyymhwfmjybbbyjyjwjmdpwhxqldyapdfxxbcgjspckrssyzjmslbzzjfljjjlgxzgyxyxlszqkx" +"bexyxhgcxbpndyhwectwwcjmbtxchxyqqllxflyxlljlssnwdbzcmyjclwswdczpchqekcqbwlcgydblqppqzqfnqdjhymmcxtxd" +"rmzwrhxcjzylqxdyynhyyhrslnrsywwjjymtltllgtqcjzyabtckzcjyccqlysqxalmzynywlwdnzxqdllqshgpjfjljnjabcqzd" +"jgthhsstnyjfbswzlxjxrhgldlzrlzqzgsllllzlymxxgdzhgbdphzpbrlwnjqbpfdwonnnhlypcnjccndmbcpbzzncyqxldomzb" +"lzwpdwyygdstthcsqsccrsssyslfybnntyjszdfndpdhtqzmbqlxlcmyffgtjjqwftmnpjwdnlbzcmmcngbdzlqlpnfhyymjylsd" +"chdcjwjcctljcldtljjcbddpndsszycndbjlggjzxsxnlycybjjxxcbylzcfzppgkcxqdzfztjjfjdjxzbnzyjqctyjwhdyczhym" +"djxttmpxsplzcdwslshxypzgtfmlcjtacbbmgdewycyzxdszjyhflystygwhkjyylsjcxgywjcbllcsnddbtzbsclyzczzssqdll" +"mjyyhfllqllxfdyhabxggnywyypllsdldllbjcyxjznlhljdxyyqytdlllbngpfdfbbqbzzmdpjhgclgmjjpgaehhbwcqxajhhhz" +"chxyphjaxhlphjpgpzjqcqzgjjzzgzdmqyybzzphyhybwhazyjhykfgdpfqsdlzmljxjpgalxzdaglmdgxmmzqwtxdxxpfdmmssy" +"mpfmdmmkxksyzyshdzkjsysmmzzzmdydyzzczxbmlstmdyemxckjmztyymzmzzmsshhdccjewxxkljsthwlsqlyjzllsjssdppmh" +"nlgjczyhmxxhgncjmdhxtkgrmxfwmckmwkdcksxqmmmszzydkmsclcmpcjmhrpxqpzdsslcxkyxtwlkjyahzjgzjwcjnxyhmmbml" +"gjxmhlmlgmxctkzmjlyscjsyszhsyjzjcdajzhbsdqjzgwtkqxfkdmsdjlfmnhkzqkjfeypzyszcdpynffmzqykttdzzefmzlbnp" +"plplpbpszalltnlkckqzkgenjlwalkxydpxnhsxqnwqnkxqclhyxxmlnccwlymqyckynnlcjnszkpyzkcqzqljbdmdjhlasqlbyd" +"wqlwdgbqcryddztjybkbwszdxdtnpjdtcnqnfxqqmgnseclstbhpwslctxxlpwydzklnqgzcqapllkqcylbqmqczqcnjslqzdjxl" +"ddhpzqdljjxzqdjyzhhzlkcjqdwjppypqakjyrmpzbnmcxkllzllfqpylllmbsglzysslrsysqtmxyxzqzbscnysyztffmzzsmzq" +"hzssccmlyxwtpzgxzjgzgsjzgkddhtqggzllbjdzlsbzhyxyzhzfywxytymsdnzzyjgtcmtnxqyxjscxhslnndlrytzlryylxqht" +"xsrtzcgyxbnqqzfhykmzjbzymkbpnlyzpblmcnqyzzzsjztjctzhhyzzjrdyzhnfxklfzslkgjtctssyllgzrzbbjzzklpkbczys" +"nnyxbjfbnjzzxcdwlzyjxzzdjjgggrsnjkmsmzjlsjywqsnyhqjsxpjztnlsnshrnynjtwchglbnrjlzxwjqxqkysjycztlqzybb" +"ybyzjqdwgyzcytjcjxckcwdkkzxsnkdnywwyyjqyytlytdjlxwkcjnklccpzcqqdzzqlcsfqchqqgssmjzzllbjjzysjhtsjdysj" +"qjpdszcdchjkjzzlpycgmzndjxbsjzzsyzyhgxcpbjydssxdzncglqmbtsfcbfdzdlznfgfjgfsmpnjqlnblgqcyyxbqgdjjqsrf" +"kztjdhczklbsdzcfytplljgjhtxzcsszzxstjygkgckgynqxjplzbbbgcgyjzgczqszlbjlsjfzgkqqjcgycjbzqtldxrjnbsxxp" +"zshszycfwdsjjhxmfczpfzhqhqmqnknlyhtycgfrzgnqxcgpdlbzcsczqlljblhbdcypscppdymzzxgyhckcpzjgslzlnscnsldl" +"xbmsdlddfjmkdqdhslzxlsznpqpgjdlybdskgqlbzlnlkyyhzttmcjnqtzzfszqktlljtyyllnllqyzqlbdzlslyyzxmdfszsnxl" +"xznczqnbbwskrfbcylctnblgjpmczzlstlxshtzcyzlzbnfmqnlxflcjlyljqcbclzjgnsstbrmhxzhjzclxfnbgxgtqncztmsfz" +"kjmssncljkbhszjntnlzdntlmmjxgzjyjczxyhyhwrwwqnztnfjscpyshzjfyrdjsfscjzbjfzqzchzlxfxsbzqlzsgyftzdcszx" +"zjbjpszkjrhxjzcgbjkhcggtxkjqglxbxfgtrtylxqxhdtsjxhjzjjcmzlcqsbtxwqgxtxxhxftsdkfjhzyjfjxnzldlllcqsqqz" +"qwqxswqtwgwbzcgcllqzbclmqjtzgzyzxljfrmyzflxnsnxxjkxrmjdzdmmyxbsqbhgzmwfwygmjlzbyytgzyccdjyzxsngnyjyz" +"nbgpzjcqsyxsxrtfyzgrhztxszzthcbfclsyxzlzqmzlmplmxzjssfsbysmzqhxxnxrxhqzzzsslyflczjrcrxhhzxqndshxsjjh" +"qcjjbcynsysxjbqjpxzqplmlxzkyxlxcnlcycxxzzlxdlllmjyhzxhyjwkjrwyhcpsgnrzlfzwfzznsxgxflzsxzzzbfcsyjdbrj" +"krdhhjxjljjtgxjxxstjtjxlyxqfcsgswmsbctlqzzwlzzkxjmltmjyhsddbxgzhdlbmyjfrzfcgclyjbpmlysmsxlszjqqhjzfx" +"gfqfqbphngyyqxgztnqwyltlgwgwwhnlfmfgzjmgmgbgtjflyzzgzyzaflsspmlbflcwbjztljjmzlpjjlymqtmyyyfbgygqzgly" +"zdxqyxrqqqhsxyyqxygjtyxfsfsllgnqcygycwfhcccfxpylypllzqxxxxxqqhhsshjzcftsczjxspzwhhhhhapylqnlpqafyhxd" +"ylnkmzqgggddesrenzltzgchyppcsqjjhclljtolnjpzljlhymhezdydsqycddhgznndzclzywllznteydgnlhslpjjbdgwxpcnn" +"tycklkclwkllcasstknzdnnjttlyyzssysszzryljqkcgdhhyrxrzydgrgcwcgzqffbppjfzynakrgywyjpqxxfkjtszzxswzddf" +"bbqtbgtzkznpzfpzxzpjszbmqhkyyxyldkljnypkyghgdzjxxeaxpnznctzcmxcxmmjxnkszqnmnlwbwwqjjyhclstmcsxnjcxxt" +"pcnfdtnnpglllzcjlspblpgjcdtnjjlyarscffjfqwdpgzdwmrzzcgodaxnssnyzrestyjwjyjdbcfxnmwttbqlwstszgybljpxg" +"lbnclgpcbjftmxzljylzxcltpnclcgxtfzjshcrxsfysgdkntlbyjcyjllstgqcbxnhzxbxklylhzlqzlnzcqwgzlgzjncjgcmnz" +"zgjdzxtzjxycyycxxjyyxjjxsssjstsstdppghtcsxwzdcsynptfbchfbblzjclzzdbxgcjlhpxnfzflsyltnwbmnjhszbmdnbcy" +"sccldnycndqlyjjhmqllcsgljjsyfpyyccyltjantjjpwycmmgqyysxdxqmzhszxbftwwzqswqrfkjlzjqqyfbrxjhhfwjgzyqac" +"myfrhcyybynwlpexcczsyyrlttdmqlrkmpbgmyyjprkznbbsqyxbhyzdjdnghpmfsgbwfzmfqmmbzmzdcgjlnnnxyqgmlrygqccy" +"xzlwdkcjcggmcjjfyzzjhycfrrcmtznzxhkqgdjxccjeascrjthpljlrzdjrbcqhjdnrhylyqjsymhzydwcdfryhbbydtssccwbx" +"glpzmlzjdqsscfjmmxjcxjytycghycjwynsxlfemwjnmkllswtxhyyyncmmcyjdqdjzglljwjnkhpzggflccsczmcbltbhbqjxqd" +"jpdjztghglfjawbzyzjltstdhjhctcbchflqmpwdshyytqwcnntjtlnnmnndyyyxsqkxwyyflxxnzwcxypmaelyhgjwzzjbrxxaq" +"jfllpfhhhytzzxsgqjmhspgdzqwbwpjhzjdyjcqwxkthxsqlzyymysdzgnqckknjlwpnsyscsyzlnmhqsyljxbcxtlhzqzpcycyk" +"pppnsxfyzjjrcemhszmnxlxglrwgcstlrsxbygbzgnxcnlnjlclynymdxwtzpalcxpqjcjwtcyyjlblxbzlqmyljbghdslssdmxm" +"bdczsxyhamlczcpjmcnhjyjnsykchskqmczqdllkablwjqsfmocdxjrrlyqchjmybyqlrhetfjzfrfksryxfjdwtsxxywsqjysly" +"xwjhsdlxyyxhbhawhwjcxlmyljcsqlkydttxbzslfdxgxsjkhsxxybssxdpwncmrptqzczenygcxqfjxkjbdmljzmqqxnoxslyxx" +"lylljdzptymhbfsttqqwlhsgynlzzalzxclhtwrrqhlstmypyxjjxmnsjnnbryxyjllyqyltwylqyfmlkljdnlltfzwkzhljmlhl" +"jnljnnlqxylmbhhlnlzxqchxcfxxlhyhjjgbyzzkbxscqdjqdsndzsygzhhmgsxcsymxfepcqwwrbpyyjqryqcyjhqqzyhmwffhg" +"zfrjfcdbxntqyzpcyhhjlfrzgpbxzdbbgrqstlgdgylcqmgchhmfywlzyxkjlypjhsywmqqggzmnzjnsqxlqsyjtcbehsxfszfxz" +"wfllbcyyjdytdthwzsfjmqqyjlmqsxlldttkghybfpwdyysqqrnqwlgwdebzwcyygcnlkjxtmxmyjsxhybrwfymwfrxyymxysctz" +"ztfykmldhqdlgyjnlcryjtlpsxxxywlsbrrjwxhqybhtydnhhxmmywytycnnmnssccdalwztcpqpyjllqzyjswjwzzmmglmxclmx" +"nzmxmzsqtzppjqblpgxjzhfljjhycjsrxwcxsncdlxsyjdcqzxslqyclzxlzzxmxqrjmhrhzjbhmfljlmlclqnldxzlllfyprgjy" +"nxcqqdcmqjzzxhnpnxzmemmsxykynlxsxtljxyhwdcwdzhqyybgybcyscfgfsjnzdrzzxqxrzrqjjymcanhrjtldbpyzbstjhxxz" +"ypbdwfgzzrpymnnkxcqbyxnbnfyckrjjcmjegrzgyclnnzdnkknsjkcljspgyyclqqjybzssqlllkjftbgtylcccdblsppfylgyd" +"tzjqjzgkntsfcxbdkdxxhybbfytyhbclnnytgdhryrnjsbtcsnyjqhklllzslydxxwbcjqsbxnpjzjzjdzfbxxbrmladhcsnclbj" +"dstblprznswsbxbcllxxlzdnzsjpynyxxyftnnfbhjjjgbygjpmmmmsszljmtlyzjxswxtyledqpjmpgqzjgdjlqjwjqllsdgjgy" +"gmscljjxdtygjqjjjcjzcjgdzdshqgzjggcjhqxsnjlzzbxhsgzxcxyljxyxyydfqqjhjfxdhctxjyrxysqtjxyefyyssyxjxncy" +"zxfxcsxszxyyschshxzzzgzzzgfjdldylnpzgsjaztyqzpbxcbdztzczyxxyhhscjshcggqhjhgxhsctmzmehyxgebtclzkkwytj" +"zrslekestdbcyhqqsayxcjxwwgsphjszsdncsjkqcxswxfctynydpccczjqtcwjqjzzzqzljzhlsbhpydxpsxshhezdxfptjqyzc" +"xhyaxncfzyyhxgnqmywntzsjbnhhgymxmxqcnssbcqsjyxxtyyhybcqlmmszmjzzllcogxzaajzyhjmchhcxzsxsdznleyjjzjbh" +"zwjzsqtzpsxzzdsqjjjlnyazphhyysrnqzthzhnyjyjhdzxzlswclybzyecwcycrylchzhzydzydyjdfrjjhtrsqtxyxjrjhojyn" +"xelxsfsfjzghpzsxzszdzcqzbyyklsgsjhczshdgqgxyzgxchxzjwyqwgyhksseqzzndzfkwyssdclzstsymcdhjxxyweyxczayd" +"mpxmdsxybsqmjmzjmtjqlpjyqzcgqhyjhhhqxhlhdldjqcfdwbsxfzzyyschtytyjbhecxhjkgqfxbhyzjfxhwhbdzfyzbchpnpg" +"dydmsxhkhhmamlnbyjtmpxejmcthqbzyfcgtyhwphftgzzezsbzegpbmdskftycmhbllhgpzjxzjgzjyxzsbbqsczzlzscstpgxm" +"jsfdcczjzdjxsybzlfcjsazfgszlwbczzzbyztzynswyjgxzbdsynxlgzbzfygczxbzhzftpbgzgejbstgkdmfhyzzjhzllzzgjq" +"zlsfdjsscbzgpdlfzfzszyzyzsygcxsnxxchczxtzzljfzgqsqqxcjqccccdjcdszzyqjccgxztdlgscxzsyjjqtcclqdqztqchq" +"qyzynzzzpbkhdjfcjfztypqyqttynlmbdktjcpqzjdzfpjsbnjlgyjdxjdcqkzgqkxclbzjtcjdqbxdjjjstcxnxbxqmslyjcxnt" +"jqwwcjjnjjlllhjcwqtbzqqczczpzzdzyddcyzdzccjgtjfzdprntctjdcxtqzdtjnplzbcllctdsxkjzqdmzlbznbtjdcxfczdb" +"czjjltqqpldckztbbzjcqdcjwynllzlzccdwllxwzlxrxntqjczxkjlsgdnqtddglnlajjtnnynkqlldzntdnycygjwyxdxfrsqs" +"tcdenqmrrqzhhqhdldazfkapbggpzrebzzykyqspeqjjglkqzzzjlysyhyzwfqznlzzlzhwcgkypqgnpgblplrrjyxcccgyhsfzf" +"wbzywtgzxyljczwhncjzplfflgskhyjdeyxhlpllllcygxdrzelrhgklzzyhzlyqszzjzqljzflnbhgwlczcfjwspyxzlzlxgccp" +"zbllcxbbbbnbbcbbcrnnzccnrbbnnldcgqyyqxygmqzwnzytyjhyfwtehznjywlccntzyjjcdedpwdztstnjhtymbjnyjzlxtsst" +"phndjxxbyxqtzqddtjtdyztgwscszqflshlnzbcjbhdlyzjyckwtydylbnydsdsycctyszyyebgexhqddwnygyclxtdcystqnygz" +"ascsszzdzlcclzrqxyywljsbymxshzdembbllyyllytdqyshymrqnkfkbfxnnsbychxbwjyhtqbpbsbwdzylkgzskyghqzjxhxjx" +"gnljkzlyycdxlfwfghljgjybxblybxqpqgntzplncybxdjyqydymrbeyjyyhkxxstmxrczzjwxyhybmcflyzhqyzfwxdbxbcwzms" +"lpdmyckfmzklzcyqycclhxfzlydqzpzygyjyzmdxtzfnnyttqtzhgsfcdmlccytzxjcytjmkslpzhysnwllytpzctzccktxdhxxt" +"qcyfksmqccyyazhtjplylzlyjbjxtfnyljyynrxcylmmnxjsmybcsysslzylljjgyldzdlqhfzzblfndsqkczfyhhgqmjdsxyctt" +"xnqnjpyybfcjtyyfbnxejdgyqbjrcnfyyqpghyjsyzngrhtknlnndzntsmgklbygbpyszbydjzsstjztsxzbhbscsbzczptqfzlq" +"flypybbjgszmnxdjmtsyskkbjtxhjcegbsmjyjzcstmljyxrczqscxxqpyzhmkyxxxjcljyrmyygadyskqlnadhrskqxzxztcggz" +"dlmlwxybwsyctbhjhcfcwzsxwwtgzlxqshnyczjxemplsrcgltnzntlzjcyjgdtclglbllqpjmzpapxyzlaktkdwczzbncctdqqz" +"qyjgmcdxltgcszlmlhbglkznnwzndxnhlnmkydlgxdtwcfrjerctzhydxykxhwfzcqshknmqqhzhhymjdjskhxzjzbzzxympajnm" +"ctbxlsxlzynwrtsqgscbptbsgzwyhtlkssswhzzlyytnxjgmjrnsnnnnlskztxgxlsammlbwldqhylakqcqctmycfjbslxclzjcl" +"xxknbnnzlhjphqplsxsckslnhpsfqcytxjjzljldtzjjzdlydjntptnndskjfsljhylzqqzlbthydgdjfdbyadxdzhzjnthqbykn" +"xjjqczmlljzkspldsclbblnnlelxjlbjycxjxgcnlcqplzlznjtsljgyzdzpltqcssfdmnycxgbtjdcznbgbqyqjwgkfhtnbyqzq" +"gbkpbbyzmtjdytblsqmbsxtbnpdxklemyycjynzdtldykzzxtdxhqshygmzsjycctayrzlpwltlkxslzcggexclfxlkjrtlqjaqz" +"ncmbqdkkcxglczjzxjhptdjjmzqykqsecqzdshhadmlzfmmzbgntjnnlhbyjbrbtmlbyjdzxlcjlpldlpcqdhlhzlycblcxccjad" +"qlmzmmsshmybhbnkkbhrsxxjmxmdznnpklbbrhgghfchgmnklltsyyycqlcskymyehywxnxqywbawykqldnntndkhqcgdqktgpkx" +"hcpdhtwnmssyhbwcrwxhjmkmzngwtmlkfghkjyldyycxwhyyclqhkqhtdqkhffldxqwytyydesbpkyrzpjfyyzjceqdzzdlattpb" +"fjllcxdlmjsdxegwgsjqxcfbssszpdyzcxznyxppzydlyjccpltxlnxyzyrscyyytylwwndsahjsygyhgywwaxtjzdaxysrltdps" +"syxfnejdxyzhlxlllzhzsjnyqyqyxyjghzgjcyjchzlycdshhsgczyjscllnxzjjyyxnfsmwfpyllyllabmddhwzxjmcxztzpmlq" +"chsfwzynctlndywlslxhymmylmbwwkyxyaddxylldjpybpwnxjmmmllhafdllaflbnhhbqqjqzjcqjjdjtffkmmmpythygdrjrdd" +"wrqjxnbysrmzdbyytbjhpymyjtjxaahggdqtmystqxkbtzbkjlxrbyqqhxmjjbdjntgtbxpgbktlgqxjjjcdhxqdwjlwrfmjgwqh" +"cnrxswgbtgygbwhswdwrfhwytjjxxxjyzyslphyypyyxhydqpxshxyxgskqhywbdddpplcjlhqeewjgsyykdpplfjthkjltcyjhh" +"jttpltzzcdlyhqkcjqysteeyhkyzyxxyysddjkllpymqyhqgxqhzrhbxpllnqydqhxsxxwgdqbshyllpjjjthyjkyphthyyktyez" +"yenmdshlzrpqfbnfxzbsftlgxsjbswyysksflxlpplbbblnsfbfyzbsjssylpbbffffsscjdstjsxtryjcyffsyzyzbjtlctsbsd" +"hrtjjbytcxyyeylycbnebjdsysyhgsjzbxbytfzwgenhhhthjhhxfwgcstbgxklstyymtmbyxjskzscdyjrcythxzfhmymcxlzns" +"djtxtxrycfyjsbsdyerxhljxbbdeynjghxgckgscymblxjmsznskgxfbnbbthfjyafxwxfbxmyfhdttcxzzpxrsywzdlybbktyqw" +"qjbzypzjznjpzjlztfysbttslmptzrtdxqsjehbnylndxljsqmlhtxtjecxalzzspktlzkqqyfsyjywpcpqfhjhytqxzkrsgtksq" +"czlptxcdyyzsslzslxlzmacpcqbzyxhbsxlzdltztjtylzjyytbzypltxjsjxhlbmytxcqrblzssfjzztnjytxmyjhlhpblcyxqj" +"qqkzzscpzkswalqsplczzjsxgwwwygyatjbbctdkhqhkgtgpbkqyslbxbbckbmllndzstbklggqkqlzbkktfxrmdkbftpzfrtppm" +"ferqnxgjpzsstlbztpszqzsjdhljqlzbpmsmmsxlqqnhknblrddnhxdkddjcyyljfqgzlgsygmjqjkhbpmxyxlytqwlwjcpbmjxc" +"yzydrjbhtdjyeqshtmgsfyplwhlzffnynnhxqhpltbqpfbjwjdbygpnxtbfzjgnnntjshxeawtzylltyqbwjpgxghnnkndjtmszs" +"qynzggnwqtfhclssgmnnnnynzqqxncjdqgzdlfnykljcjllzlmzznnnnsshthxjlzjbbhqjwwycrdhlyqqjbeyfsjhthnrnwjhwp" +"slmssgzttygrqqwrnlalhmjtqjsmxqbjjzjqzyzkxbjqxbjxshzssfglxmxnxfghkzszggslcnnarjxhnlllmzxelglxydjytlfb" +"kbpnlyzfbbhptgjkwetzhkjjxzxxglljlstgshjjyqlqzfkcgnndjsszfdbctwwseqfhqjbsaqtgypjlbxbmmywxgslzhglsgnyf" +"ljbyfdjfngsfmbyzhqffwjsyfyjjphzbyyzffwotjnlmftwlbzgyzqxcdjygzyyryzynyzwegazyhjjlzrthlrmgrjxzclnnnljj" +"yhtbwjybxxbxjjtjteekhwslnnlbsfazpqqbdlqjjtyyqlyzkdksqjnejzldqcgjqnnjsncmrfqthtejmfctyhypymhydmjncfgy" +"yxwshctxrljgjzhzcyyyjltkttntmjlzclzzayyoczlrlbszywjytsjyhbyshfjlykjxxtmzyyltxxypslqyjzyzyypnhmymdyyl" +"blhlsyygqllnjjymsoycbzgdlyxylcqyxtszegxhzglhwbljheyxtwqmakbpqcgyshhegqcmwyywljyjhyyzlljjylhzyhmgsljl" +"jxcjjyclycjbcpzjzjmmwlcjlnqljjjlxyjmlszljqlycmmgcfmmfpqqmfxlqmcffqmmmmhnznfhhjgtthxkhslnchhyqzxtmmqd" +"cydyxyqmyqylddcyaytazdcymdydlzfffmmycqcwzzmabtbyctdmndzggdftypcgqyttssffwbdttqssystwnjhjytsxxylbyyhh" +"whxgzxwznnqzjzjjqjccchykxbzszcnjtllcqxynjnckycynccqnxyewyczdcjycchyjlbtzyycqwlpgpyllgktltlgkgqbgychj" +"xy"; +char pinyinFirstLetter(unsigned short hanzi) +{ + int index = hanzi - HANZI_START; + if (index >= 0 && index <= HANZI_COUNT) + { + return firstLetterArray[index]; + } + else + { + return '#'; + } +} + +char getFirstChar(const NSString * str) { + if (nil == str || 0 == [str length]) { + return '#'; + } + const char * firstChar = [str UTF8String]; + if ( ('a'<= *firstChar && *firstChar <= 'z') + || ('A' <= *firstChar && *firstChar <= 'Z')) { + return *firstChar; + } + else { + return pinyinFirstLetter([str characterAtIndex:0]); + } +} + + + diff --git a/ios/IOSDuoduoTests/IOSDuoduoTests.m b/ios/IOSDuoduoTests/IOSDuoduoTests.m new file mode 100644 index 000000000..f4d8ddb1e --- /dev/null +++ b/ios/IOSDuoduoTests/IOSDuoduoTests.m @@ -0,0 +1,34 @@ +// +// IOSDuoduoTests.m +// IOSDuoduoTests +// +// Created by 独嘉 on 14-5-23. +// Copyright (c) 2014年 dujia. All rights reserved. +// + +#import + +@interface IOSDuoduoTests : XCTestCase + +@end + +@implementation IOSDuoduoTests + +- (void)setUp +{ + [super setUp]; + // Put setup code here. This method is called before the invocation of each test method in the class. +} + +- (void)tearDown +{ + // Put teardown code here. This method is called after the invocation of each test method in the class. + [super tearDown]; +} + +- (void)testExample +{ + XCTFail(@"No implementation for \"%s\"", __PRETTY_FUNCTION__); +} + +@end diff --git a/ios/IOSDuoduoTests/TeamTalkTests-Info.plist b/ios/IOSDuoduoTests/TeamTalkTests-Info.plist new file mode 100644 index 000000000..0b484e4f6 --- /dev/null +++ b/ios/IOSDuoduoTests/TeamTalkTests-Info.plist @@ -0,0 +1,22 @@ + + + + + CFBundleDevelopmentRegion + en + CFBundleExecutable + ${EXECUTABLE_NAME} + CFBundleIdentifier + com.mogujie.${PRODUCT_NAME:rfc1034identifier} + CFBundleInfoDictionaryVersion + 6.0 + CFBundlePackageType + BNDL + CFBundleShortVersionString + 1.0 + CFBundleSignature + ???? + CFBundleVersion + 1 + + diff --git a/ios/IOSDuoduoTests/en.lproj/InfoPlist.strings b/ios/IOSDuoduoTests/en.lproj/InfoPlist.strings new file mode 100644 index 000000000..477b28ff8 --- /dev/null +++ b/ios/IOSDuoduoTests/en.lproj/InfoPlist.strings @@ -0,0 +1,2 @@ +/* Localized versions of Info.plist keys */ + diff --git a/ios/Images.xcassets/AppIcon.appiconset/Contents.json b/ios/Images.xcassets/AppIcon.appiconset/Contents.json new file mode 100644 index 000000000..a396706db --- /dev/null +++ b/ios/Images.xcassets/AppIcon.appiconset/Contents.json @@ -0,0 +1,23 @@ +{ + "images" : [ + { + "idiom" : "iphone", + "size" : "29x29", + "scale" : "2x" + }, + { + "idiom" : "iphone", + "size" : "40x40", + "scale" : "2x" + }, + { + "idiom" : "iphone", + "size" : "60x60", + "scale" : "2x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/ios/Images.xcassets/LaunchImage.launchimage/Contents.json b/ios/Images.xcassets/LaunchImage.launchimage/Contents.json new file mode 100644 index 000000000..c79ebd3ad --- /dev/null +++ b/ios/Images.xcassets/LaunchImage.launchimage/Contents.json @@ -0,0 +1,23 @@ +{ + "images" : [ + { + "orientation" : "portrait", + "idiom" : "iphone", + "extent" : "full-screen", + "minimum-system-version" : "7.0", + "scale" : "2x" + }, + { + "orientation" : "portrait", + "idiom" : "iphone", + "subtype" : "retina4", + "extent" : "full-screen", + "minimum-system-version" : "7.0", + "scale" : "2x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/ios/Launch Screen.xib b/ios/Launch Screen.xib new file mode 100644 index 000000000..0319bda84 --- /dev/null +++ b/ios/Launch Screen.xib @@ -0,0 +1,55 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/ios/MobClick.h b/ios/MobClick.h new file mode 100644 index 000000000..13e505cc2 --- /dev/null +++ b/ios/MobClick.h @@ -0,0 +1,313 @@ +// +// MobClick.h +// MobClick +// +// Created by Aladdin on 2010-03-25. +// Updated by Minghua on 2014-05-21. +// Copyright (C) 2010-2014 Umeng.com . All rights reserved. +// Version 3.1.2 , updated_at 2014-05-21. + +#import +#import + +#define UMOnlineConfigDidFinishedNotification @"OnlineConfigDidFinishedNotification" +#define XcodeAppVersion [[[NSBundle mainBundle] infoDictionary] objectForKey:@"CFBundleShortVersionString"] + + +typedef enum { + REALTIME = 0, //实时发送 + BATCH = 1, //启动发送 + SENDDAILY = 4, //每日发送 + SENDWIFIONLY = 5, //仅在WIFI下启动时发送 + SEND_INTERVAL = 6, //按最小间隔发送 + SEND_ON_EXIT = 7 //退出或进入后台时发送 +} ReportPolicy; + +@class CLLocation; + +/** MobClick是统计的核心类,本身不需要实例化,所有方法以类方法的形式提供. + 目前发送策略有REALTIME,BATCH,SENDDAILY,SENDWIFIONLY,SEND_INTERVAL,SEND_ON_EXIT。 + 其中REALTIME,SENDWIFIONLY 只在模拟器和DEBUG模式下生效,真机release模式会自动改成BATCH。 + 关于发送策略的调整,请参见关于发送策略及发送策略变更的说明 + http://blog.umeng.com/index.php/2012/12/0601/ + SEND_INTERVAL 为按最小间隔发送,默认为10秒,取值范围为10 到 86400(一天), 如果不在这个区间的话,会按10设置。 + SEND_ON_EXIT 为退出或进入后台时发送,这种发送策略在App运行过程中不发送,对开发者和用户的影响最小。 + 不过这种发送策略只在iOS > 4.0时才会生效, iOS < 4.0 会被自动调整为BATCH。 + + */ +@interface MobClick : NSObject +#pragma mark basics + +///--------------------------------------------------------------------------------------- +/// @name 设置 +///--------------------------------------------------------------------------------------- + +/** 设置app版本号。由于历史原因需要和xcode3工程兼容,友盟提取的是Build号(CFBundleVersion),如果需要和App Store上的版本一致,需要调用此方法。 + + @param appVersion 版本号,例如设置成`XcodeAppVersion`. + @return void. +*/ ++ (void)setAppVersion:(NSString *)appVersion; + + +/** 开启CrashReport收集, 默认是开启状态. + + @param value 设置成NO,就可以关闭友盟CrashReport收集. + @return void. +*/ ++ (void)setCrashReportEnabled:(BOOL)value; + + +/** 设置是否打印sdk的log信息,默认不开启 + @param value 设置为YES,umeng SDK 会输出log信息,记得release产品时要设置回NO. + @return . + @exception . + */ + ++ (void)setLogEnabled:(BOOL)value; + + +///--------------------------------------------------------------------------------------- +/// @name 开启统计 +///--------------------------------------------------------------------------------------- + + +/** 开启友盟统计,默认以BATCH方式发送log. + + @param appKey 友盟appKey. + @param reportPolicy 发送策略. + @param channelId 渠道名称,为nil或@""时,默认会被被当作@"App Store"渠道 + @return void +*/ ++ (void)startWithAppkey:(NSString *)appKey; ++ (void)startWithAppkey:(NSString *)appKey reportPolicy:(ReportPolicy)rp channelId:(NSString *)cid; + +/** 当reportPolicy == SEND_INTERVAL 时设定log发送间隔 + + @param second 单位为秒,最小为10,最大为86400(一天). + @return void. +*/ + ++ (void)setLogSendInterval:(double)second; + + +///--------------------------------------------------------------------------------------- +/// @name 页面计时 +///--------------------------------------------------------------------------------------- + + +/** 页面时长统计,记录某个view被打开多长时间,可以自己计时也可以调用beginLogPageView,endLogPageView自动计时 + + @param pageName 需要记录时长的view名称. + @param seconds 秒数,int型. + @return void. +*/ + ++ (void)logPageView:(NSString *)pageName seconds:(int)seconds; ++ (void)beginLogPageView:(NSString *)pageName; ++ (void)endLogPageView:(NSString *)pageName; + +#pragma mark event logs + + +///--------------------------------------------------------------------------------------- +/// @name 事件统计 +///--------------------------------------------------------------------------------------- + + +/** 自定义事件,数量统计. + 使用前,请先到友盟App管理后台的设置->编辑自定义事件 中添加相应的事件ID,然后在工程中传入相应的事件ID + + @param eventId 网站上注册的事件Id. + @param label 分类标签。不同的标签会分别进行统计,方便同一事件的不同标签的对比,为nil或空字符串时后台会生成和eventId同名的标签. + @param accumulation 累加值。为减少网络交互,可以自行对某一事件ID的某一分类标签进行累加,再传入次数作为参数。 + @return void. + */ ++ (void)event:(NSString *)eventId; //等同于 event:eventId label:eventId; +/** 自定义事件,数量统计. + 使用前,请先到友盟App管理后台的设置->编辑自定义事件 中添加相应的事件ID,然后在工程中传入相应的事件ID + */ ++ (void)event:(NSString *)eventId label:(NSString *)label; // label为nil或@""时,等同于 event:eventId label:eventId; +/** 自定义事件,数量统计. + 使用前,请先到友盟App管理后台的设置->编辑自定义事件 中添加相应的事件ID,然后在工程中传入相应的事件ID + */ ++ (void)event:(NSString *)eventId acc:(NSInteger)accumulation; +/** 自定义事件,数量统计. + 使用前,请先到友盟App管理后台的设置->编辑自定义事件 中添加相应的事件ID,然后在工程中传入相应的事件ID + */ ++ (void)event:(NSString *)eventId label:(NSString *)label acc:(NSInteger)accumulation; +/** 自定义事件,数量统计. + 使用前,请先到友盟App管理后台的设置->编辑自定义事件 中添加相应的事件ID,然后在工程中传入相应的事件ID + */ ++ (void)event:(NSString *)eventId attributes:(NSDictionary *)attributes; + ++ (void)event:(NSString *)eventId attributes:(NSDictionary *)attributes counter:(int)number; + +/** 自定义事件,时长统计. + 使用前,请先到友盟App管理后台的设置->编辑自定义事件 中添加相应的事件ID,然后在工程中传入相应的事件ID. + beginEvent,endEvent要配对使用,也可以自己计时后通过durations参数传递进来 + + @param eventId 网站上注册的事件Id. + @param label 分类标签。不同的标签会分别进行统计,方便同一事件的不同标签的对比,为nil或空字符串时后台会生成和eventId同名的标签. + @param primarykey 这个参数用于和event_id一起标示一个唯一事件,并不会被统计;对于同一个事件在beginEvent和endEvent 中要传递相同的eventId 和 primarykey + @param millisecond 自己计时需要的话需要传毫秒进来 + @return void. + + + @warning 每个event的attributes不能超过10个 + eventId、attributes中key和value都不能使用空格和特殊字符,且长度不能超过255个字符(否则将截取前255个字符) + id, ts, du是保留字段,不能作为eventId及key的名称 + +*/ ++ (void)beginEvent:(NSString *)eventId; +/** 自定义事件,时长统计. + 使用前,请先到友盟App管理后台的设置->编辑自定义事件 中添加相应的事件ID,然后在工程中传入相应的事件ID. + */ ++ (void)endEvent:(NSString *)eventId; +/** 自定义事件,时长统计. + 使用前,请先到友盟App管理后台的设置->编辑自定义事件 中添加相应的事件ID,然后在工程中传入相应的事件ID. + */ + ++ (void)beginEvent:(NSString *)eventId label:(NSString *)label; +/** 自定义事件,时长统计. + 使用前,请先到友盟App管理后台的设置->编辑自定义事件 中添加相应的事件ID,然后在工程中传入相应的事件ID. + */ + ++ (void)endEvent:(NSString *)eventId label:(NSString *)label; +/** 自定义事件,时长统计. + 使用前,请先到友盟App管理后台的设置->编辑自定义事件 中添加相应的事件ID,然后在工程中传入相应的事件ID. + */ + ++ (void)beginEvent:(NSString *)eventId primarykey :(NSString *)keyName attributes:(NSDictionary *)attributes; +/** 自定义事件,时长统计. + 使用前,请先到友盟App管理后台的设置->编辑自定义事件 中添加相应的事件ID,然后在工程中传入相应的事件ID. + */ + ++ (void)endEvent:(NSString *)eventId primarykey:(NSString *)keyName; +/** 自定义事件,时长统计. + 使用前,请先到友盟App管理后台的设置->编辑自定义事件 中添加相应的事件ID,然后在工程中传入相应的事件ID. + */ + ++ (void)event:(NSString *)eventId durations:(int)millisecond; +/** 自定义事件,时长统计. + 使用前,请先到友盟App管理后台的设置->编辑自定义事件 中添加相应的事件ID,然后在工程中传入相应的事件ID. + */ + ++ (void)event:(NSString *)eventId label:(NSString *)label durations:(int)millisecond; +/** 自定义事件,时长统计. + 使用前,请先到友盟App管理后台的设置->编辑自定义事件 中添加相应的事件ID,然后在工程中传入相应的事件ID. + */ + ++ (void)event:(NSString *)eventId attributes:(NSDictionary *)attributes durations:(int)millisecond; + + +///--------------------------------------------------------------------------------------- +/// @name 按渠道自动更新 +///--------------------------------------------------------------------------------------- + + +/** 按渠道自动更新检测 + 检查当前app是否有更新,有更新弹出UIAlertView提示用户,当用户点击升级按钮时app会跳转到您预先设置的网址。 + 无更新不做任何操作。 + 您需要先在服务器端设置app版本信息,默认渠道是App Store. + 如果您想自己控制自动更新操作流程,请实现MobClickDelegate的appUpdate方法。 + + @param title 对应UIAlertView的title. + @param cancelTitle 对应UIAlertView的cancelTitle. + @param otherTitle 对应UIAlertView的otherTitle. + @param delegate 需要自定义checkUpdate的对象. + @param callBackSelectorWithDictionary 当checkUpdate事件完成时此方法会被调用,同时标记app更新信息的字典被传回. + @return void. + */ + ++ (void)checkUpdate; +/** 按渠道自动更新检测 + */ + ++ (void)checkUpdate:(NSString *)title cancelButtonTitle:(NSString *)cancelTitle otherButtonTitles:(NSString *)otherTitle; +/** 按渠道自动更新检测 + */ + ++ (void)checkUpdateWithDelegate:(id)delegate selector:(SEL)callBackSelectorWithDictionary; + + +///--------------------------------------------------------------------------------------- +/// @name 在线参数 +///--------------------------------------------------------------------------------------- + + +/** 使用在线参数功能,可以让你动态修改应用中的参数值, + 检查并更新服务器端配置的在线参数,缓存在[NSUserDefaults standardUserDefaults]里, + 调用此方法您将自动拥有在线更改SDK端发送策略的功能,您需要先在服务器端设置好在线参数. + 请在[MobClick startWithAppkey:]方法之后调用; + 如果想知道在线参数是否完成完成,请监听UMOnlineConfigDidFinishedNotification + @param 无. + @return void. + */ + ++ (void)updateOnlineConfig; + +/** 从[NSUserDefaults standardUserDefaults]获取缓存的在线参数的数值 + 带参数的方法获取某个key的值,不带参数的获取所有的在线参数. + 需要先调用updateOnlineConfig才能使用,如果想知道在线参数是否完成完成,请监听UMOnlineConfigDidFinishedNotification + + @param key + @return (NSString *) . + */ + ++ (NSString *)getConfigParams:(NSString *)key; + +/** 从[NSUserDefaults standardUserDefaults]获取缓存的在线参数 + @return (NSDictionary *). + */ + ++ (NSDictionary *)getConfigParams; + ++ (NSString *)getAdURL; + + +///--------------------------------------------------------------------------------------- +/// @name 地理位置设置 +///--------------------------------------------------------------------------------------- + + +/** 为了更精确的统计用户地理位置,可以调用此方法传入经纬度信息 + 需要链接 CoreLocation.framework 并且 #import + @param latitude 纬度. + @param longitude 经度. + @param location CLLocation *型的地理信息 + @return void + */ + ++ (void)setLatitude:(double)latitude longitude:(double)longitude; +/** 为了更精确的统计用户地理位置,可以调用此方法传入经纬度信息 + */ + ++ (void)setLocation:(CLLocation *)location; + + +///--------------------------------------------------------------------------------------- +/// @name helper方法 +///--------------------------------------------------------------------------------------- + + +/** 判断设备是否越狱,判断方法根据 apt和Cydia.app的path来判断 + */ ++ (BOOL)isJailbroken; +/** 判断你的App是否被破解 + */ ++ (BOOL)isPirated; + +#pragma mark DEPRECATED methods from version 1.7 + +/** 友盟模块启动 + [MobClick startWithAppkey:]通常在application:didFinishLaunchingWithOptions:里被调用监听 + App启动和退出事件,如果你没法在application:didFinishLaunchingWithOptions:里添加友盟的[MobClick startWithAppkey:] + 方法,App的启动事件可能会无法监听,此时你就可以手动调用[MobClick startSession:nil]来启动友盟的session。 + 通常发生在某些第三方框架生成的app里,普通app使用不到. + + */ + ++ (void)startSession:(NSNotification *)notification; + +@end \ No newline at end of file diff --git a/ios/Podfile b/ios/Podfile new file mode 100644 index 000000000..8e5b64eda --- /dev/null +++ b/ios/Podfile @@ -0,0 +1,12 @@ +platform:ios, "6.0" +pod 'FMDB', '~> 2.3' +pod 'SDWebImage', '~> 3.6' +pod "AFNetworking", "~> 2.3.0" +pod 'DACircularProgress', '~> 2.2.0' +pod 'MBProgressHUD', '~> 0.8' +pod 'PSTCollectionView', '~> 1.2.1' +pod 'HPGrowingTextView' , '~> 1.1' +pod 'ProtocolBuffers', '1.9.3' +pod 'leveldb-library', '~> 1.18.1' +pod 'SCLAlertView-Objective-C', '~> 0.3.7' +pod 'MWPhotoBrowser', '~> 1.4.1' diff --git a/ios/Podfile.lock b/ios/Podfile.lock new file mode 100644 index 000000000..fdc80e2a7 --- /dev/null +++ b/ios/Podfile.lock @@ -0,0 +1,70 @@ +PODS: + - AFNetworking (2.3.1): + - AFNetworking/NSURLConnection (= 2.3.1) + - AFNetworking/NSURLSession (= 2.3.1) + - AFNetworking/Reachability (= 2.3.1) + - AFNetworking/Security (= 2.3.1) + - AFNetworking/Serialization (= 2.3.1) + - AFNetworking/UIKit (= 2.3.1) + - AFNetworking/NSURLConnection (2.3.1): + - AFNetworking/Reachability + - AFNetworking/Security + - AFNetworking/Serialization + - AFNetworking/NSURLSession (2.3.1): + - AFNetworking/Reachability + - AFNetworking/Security + - AFNetworking/Serialization + - AFNetworking/Reachability (2.3.1) + - AFNetworking/Security (2.3.1) + - AFNetworking/Serialization (2.3.1) + - AFNetworking/UIKit (2.3.1): + - AFNetworking/NSURLConnection + - AFNetworking/NSURLSession + - DACircularProgress (2.2.0) + - FMDB (2.4): + - FMDB/standard (= 2.4) + - FMDB/common (2.4) + - FMDB/standard (2.4): + - FMDB/common + - HPGrowingTextView (1.1) + - leveldb-library (1.18.1) + - MBProgressHUD (0.9) + - MWPhotoBrowser (1.4.1): + - DACircularProgress + - MBProgressHUD (~> 0.8) + - PSTCollectionView (~> 1.2) + - SDWebImage (~> 3.7) + - ProtocolBuffers (1.9.3) + - PSTCollectionView (1.2.3) + - SCLAlertView-Objective-C (0.3.7) + - SDWebImage (3.7.1): + - SDWebImage/Core (= 3.7.1) + - SDWebImage/Core (3.7.1) + +DEPENDENCIES: + - AFNetworking (~> 2.3.0) + - DACircularProgress (~> 2.2.0) + - FMDB (~> 2.3) + - HPGrowingTextView (~> 1.1) + - leveldb-library (~> 1.18.1) + - MBProgressHUD (~> 0.8) + - MWPhotoBrowser (~> 1.4.1) + - ProtocolBuffers (= 1.9.3) + - PSTCollectionView (~> 1.2.1) + - SCLAlertView-Objective-C (~> 0.3.7) + - SDWebImage (~> 3.6) + +SPEC CHECKSUMS: + AFNetworking: 6d7b76aa5d04c8c37daad3eef4b7e3f2a7620da3 + DACircularProgress: 3b41941891a56dc6aa17971f5322a9a38a6f446e + FMDB: 0b2fa25e5264ef177973c0cb8c02c711107979aa + HPGrowingTextView: 07d5ab1f1e867acfb7a6f498b819948c9e97d07c + leveldb-library: 27d1c7bf65f324cc6f57e06fa9be32f02ac2b700 + MBProgressHUD: 2038dbcf3dce73215abed6001657043d53aa79a8 + MWPhotoBrowser: be05b3b7521e961382a4ba5579685bf5a00b93d8 + ProtocolBuffers: e80f9e4fc401aec9d3c30be70db87fcd5f1cb880 + PSTCollectionView: d9f466e4554cc83260ca9bde7beb27f308e8fd76 + SCLAlertView-Objective-C: 0f05aadaf5388ec44a06a4271e99cd871830246a + SDWebImage: 116e88633b5b416ea0ca4b334a4ac59cf72dd38d + +COCOAPODS: 0.35.0 diff --git a/ios/Pods/AFNetworking/AFNetworking/AFHTTPRequestOperation.h b/ios/Pods/AFNetworking/AFNetworking/AFHTTPRequestOperation.h new file mode 100644 index 000000000..dfa82f669 --- /dev/null +++ b/ios/Pods/AFNetworking/AFNetworking/AFHTTPRequestOperation.h @@ -0,0 +1,67 @@ +// AFHTTPRequestOperation.h +// +// Copyright (c) 2013-2014 AFNetworking (http://afnetworking.com) +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +#import +#import "AFURLConnectionOperation.h" + +/** + `AFHTTPRequestOperation` is a subclass of `AFURLConnectionOperation` for requests using the HTTP or HTTPS protocols. It encapsulates the concept of acceptable status codes and content types, which determine the success or failure of a request. + */ +@interface AFHTTPRequestOperation : AFURLConnectionOperation + +///------------------------------------------------ +/// @name Getting HTTP URL Connection Information +///------------------------------------------------ + +/** + The last HTTP response received by the operation's connection. + */ +@property (readonly, nonatomic, strong) NSHTTPURLResponse *response; + +/** + Responses sent from the server in data tasks created with `dataTaskWithRequest:success:failure:` and run using the `GET` / `POST` / et al. convenience methods are automatically validated and serialized by the response serializer. By default, this property is set to an AFHTTPResponse serializer, which uses the raw data as its response object. The serializer validates the status code to be in the `2XX` range, denoting success. If the response serializer generates an error in `-responseObjectForResponse:data:error:`, the `failure` callback of the session task or request operation will be executed; otherwise, the `success` callback will be executed. + + @warning `responseSerializer` must not be `nil`. Setting a response serializer will clear out any cached value + */ +@property (nonatomic, strong) AFHTTPResponseSerializer * responseSerializer; + +/** + An object constructed by the `responseSerializer` from the response and response data. Returns `nil` unless the operation `isFinished`, has a `response`, and has `responseData` with non-zero content length. If an error occurs during serialization, `nil` will be returned, and the `error` property will be populated with the serialization error. + */ +@property (readonly, nonatomic, strong) id responseObject; + +///----------------------------------------------------------- +/// @name Setting Completion Block Success / Failure Callbacks +///----------------------------------------------------------- + +/** + Sets the `completionBlock` property with a block that executes either the specified success or failure block, depending on the state of the request on completion. If `error` returns a value, which can be caused by an unacceptable status code or content type, then `failure` is executed. Otherwise, `success` is executed. + + This method should be overridden in subclasses in order to specify the response object passed into the success block. + + @param success The block to be executed on the completion of a successful request. This block has no return value and takes two arguments: the receiver operation and the object constructed from the response data of the request. + @param failure The block to be executed on the completion of an unsuccessful request. This block has no return value and takes two arguments: the receiver operation and the error that occurred during the request. + */ +- (void)setCompletionBlockWithSuccess:(void (^)(AFHTTPRequestOperation *operation, id responseObject))success + failure:(void (^)(AFHTTPRequestOperation *operation, NSError *error))failure; + +@end diff --git a/ios/Pods/AFNetworking/AFNetworking/AFHTTPRequestOperation.m b/ios/Pods/AFNetworking/AFNetworking/AFHTTPRequestOperation.m new file mode 100644 index 000000000..723a3b383 --- /dev/null +++ b/ios/Pods/AFNetworking/AFNetworking/AFHTTPRequestOperation.m @@ -0,0 +1,206 @@ +// AFHTTPRequestOperation.m +// +// Copyright (c) 2013-2014 AFNetworking (http://afnetworking.com) +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +#import "AFHTTPRequestOperation.h" + +static dispatch_queue_t http_request_operation_processing_queue() { + static dispatch_queue_t af_http_request_operation_processing_queue; + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^{ + af_http_request_operation_processing_queue = dispatch_queue_create("com.alamofire.networking.http-request.processing", DISPATCH_QUEUE_CONCURRENT); + }); + + return af_http_request_operation_processing_queue; +} + +static dispatch_group_t http_request_operation_completion_group() { + static dispatch_group_t af_http_request_operation_completion_group; + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^{ + af_http_request_operation_completion_group = dispatch_group_create(); + }); + + return af_http_request_operation_completion_group; +} + +#pragma mark - + +@interface AFURLConnectionOperation () +@property (readwrite, nonatomic, strong) NSURLRequest *request; +@property (readwrite, nonatomic, strong) NSURLResponse *response; +@end + +@interface AFHTTPRequestOperation () +@property (readwrite, nonatomic, strong) NSHTTPURLResponse *response; +@property (readwrite, nonatomic, strong) id responseObject; +@property (readwrite, nonatomic, strong) NSError *responseSerializationError; +@property (readwrite, nonatomic, strong) NSRecursiveLock *lock; +@end + +@implementation AFHTTPRequestOperation +@dynamic lock; + +- (instancetype)initWithRequest:(NSURLRequest *)urlRequest { + self = [super initWithRequest:urlRequest]; + if (!self) { + return nil; + } + + self.responseSerializer = [AFHTTPResponseSerializer serializer]; + + return self; +} + +- (void)setResponseSerializer:(AFHTTPResponseSerializer *)responseSerializer { + NSParameterAssert(responseSerializer); + + [self.lock lock]; + _responseSerializer = responseSerializer; + self.responseObject = nil; + self.responseSerializationError = nil; + [self.lock unlock]; +} + +- (id)responseObject { + [self.lock lock]; + if (!_responseObject && [self isFinished] && !self.error) { + NSError *error = nil; + self.responseObject = [self.responseSerializer responseObjectForResponse:self.response data:self.responseData error:&error]; + if (error) { + self.responseSerializationError = error; + } + } + [self.lock unlock]; + + return _responseObject; +} + +- (NSError *)error { + if (_responseSerializationError) { + return _responseSerializationError; + } else { + return [super error]; + } +} + +#pragma mark - AFHTTPRequestOperation + +- (void)setCompletionBlockWithSuccess:(void (^)(AFHTTPRequestOperation *operation, id responseObject))success + failure:(void (^)(AFHTTPRequestOperation *operation, NSError *error))failure +{ + // completionBlock is manually nilled out in AFURLConnectionOperation to break the retain cycle. +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Warc-retain-cycles" +#pragma clang diagnostic ignored "-Wgnu" + self.completionBlock = ^{ + if (self.completionGroup) { + dispatch_group_enter(self.completionGroup); + } + + dispatch_async(http_request_operation_processing_queue(), ^{ + if (self.error) { + if (failure) { + dispatch_group_async(self.completionGroup ?: http_request_operation_completion_group(), self.completionQueue ?: dispatch_get_main_queue(), ^{ + failure(self, self.error); + }); + } + } else { + id responseObject = self.responseObject; + if (self.error) { + if (failure) { + dispatch_group_async(self.completionGroup ?: http_request_operation_completion_group(), self.completionQueue ?: dispatch_get_main_queue(), ^{ + failure(self, self.error); + }); + } + } else { + if (success) { + dispatch_group_async(self.completionGroup ?: http_request_operation_completion_group(), self.completionQueue ?: dispatch_get_main_queue(), ^{ + success(self, responseObject); + }); + } + } + } + + if (self.completionGroup) { + dispatch_group_leave(self.completionGroup); + } + }); + }; +#pragma clang diagnostic pop +} + +#pragma mark - AFURLRequestOperation + +- (void)pause { + [super pause]; + + u_int64_t offset = 0; + if ([self.outputStream propertyForKey:NSStreamFileCurrentOffsetKey]) { + offset = [(NSNumber *)[self.outputStream propertyForKey:NSStreamFileCurrentOffsetKey] unsignedLongLongValue]; + } else { + offset = [(NSData *)[self.outputStream propertyForKey:NSStreamDataWrittenToMemoryStreamKey] length]; + } + + NSMutableURLRequest *mutableURLRequest = [self.request mutableCopy]; + if ([self.response respondsToSelector:@selector(allHeaderFields)] && [[self.response allHeaderFields] valueForKey:@"ETag"]) { + [mutableURLRequest setValue:[[self.response allHeaderFields] valueForKey:@"ETag"] forHTTPHeaderField:@"If-Range"]; + } + [mutableURLRequest setValue:[NSString stringWithFormat:@"bytes=%llu-", offset] forHTTPHeaderField:@"Range"]; + self.request = mutableURLRequest; +} + +#pragma mark - NSecureCoding + ++ (BOOL)supportsSecureCoding { + return YES; +} + +- (id)initWithCoder:(NSCoder *)decoder { + self = [super initWithCoder:decoder]; + if (!self) { + return nil; + } + + self.responseSerializer = [decoder decodeObjectOfClass:[AFHTTPResponseSerializer class] forKey:NSStringFromSelector(@selector(responseSerializer))]; + + return self; +} + +- (void)encodeWithCoder:(NSCoder *)coder { + [super encodeWithCoder:coder]; + + [coder encodeObject:self.responseSerializer forKey:NSStringFromSelector(@selector(responseSerializer))]; +} + +#pragma mark - NSCopying + +- (id)copyWithZone:(NSZone *)zone { + AFHTTPRequestOperation *operation = [[[self class] allocWithZone:zone] initWithRequest:self.request]; + + operation.responseSerializer = [self.responseSerializer copyWithZone:zone]; + operation.completionQueue = self.completionQueue; + operation.completionGroup = self.completionGroup; + + return operation; +} + +@end diff --git a/ios/Pods/AFNetworking/AFNetworking/AFHTTPRequestOperationManager.h b/ios/Pods/AFNetworking/AFNetworking/AFHTTPRequestOperationManager.h new file mode 100644 index 000000000..d7f6d4228 --- /dev/null +++ b/ios/Pods/AFNetworking/AFNetworking/AFHTTPRequestOperationManager.h @@ -0,0 +1,308 @@ +// AFHTTPRequestOperationManager.h +// +// Copyright (c) 2013-2014 AFNetworking (http://afnetworking.com) +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +#import +#import +#import + +#if __IPHONE_OS_VERSION_MIN_REQUIRED +#import +#else +#import +#endif + +#import "AFHTTPRequestOperation.h" +#import "AFURLResponseSerialization.h" +#import "AFURLRequestSerialization.h" +#import "AFSecurityPolicy.h" +#import "AFNetworkReachabilityManager.h" + +/** + `AFHTTPRequestOperationManager` encapsulates the common patterns of communicating with a web application over HTTP, including request creation, response serialization, network reachability monitoring, and security, as well as request operation management. + + ## Subclassing Notes + + Developers targeting iOS 7 or Mac OS X 10.9 or later that deal extensively with a web service are encouraged to subclass `AFHTTPSessionManager`, providing a class method that returns a shared singleton object on which authentication and other configuration can be shared across the application. + + For developers targeting iOS 6 or Mac OS X 10.8 or earlier, `AFHTTPRequestOperationManager` may be used to similar effect. + + ## Methods to Override + + To change the behavior of all request operation construction for an `AFHTTPRequestOperationManager` subclass, override `HTTPRequestOperationWithRequest:success:failure`. + + ## Serialization + + Requests created by an HTTP client will contain default headers and encode parameters according to the `requestSerializer` property, which is an object conforming to ``. + + Responses received from the server are automatically validated and serialized by the `responseSerializers` property, which is an object conforming to `` + + ## URL Construction Using Relative Paths + + For HTTP convenience methods, the request serializer constructs URLs from the path relative to the `-baseURL`, using `NSURL +URLWithString:relativeToURL:`, when provided. If `baseURL` is `nil`, `path` needs to resolve to a valid `NSURL` object using `NSURL +URLWithString:`. + + Below are a few examples of how `baseURL` and relative paths interact: + + NSURL *baseURL = [NSURL URLWithString:@"http://example.com/v1/"]; + [NSURL URLWithString:@"foo" relativeToURL:baseURL]; // http://example.com/v1/foo + [NSURL URLWithString:@"foo?bar=baz" relativeToURL:baseURL]; // http://example.com/v1/foo?bar=baz + [NSURL URLWithString:@"/foo" relativeToURL:baseURL]; // http://example.com/foo + [NSURL URLWithString:@"foo/" relativeToURL:baseURL]; // http://example.com/v1/foo + [NSURL URLWithString:@"/foo/" relativeToURL:baseURL]; // http://example.com/foo/ + [NSURL URLWithString:@"http://example2.com/" relativeToURL:baseURL]; // http://example2.com/ + + Also important to note is that a trailing slash will be added to any `baseURL` without one. This would otherwise cause unexpected behavior when constructing URLs using paths without a leading slash. + + ## Network Reachability Monitoring + + Network reachability status and change monitoring is available through the `reachabilityManager` property. Applications may choose to monitor network reachability conditions in order to prevent or suspend any outbound requests. See `AFNetworkReachabilityManager` for more details. + + ## NSecureCoding & NSCopying Caveats + + `AFHTTPRequestOperationManager` conforms to the `NSecureCoding` and `NSCopying` protocols, allowing operations to be archived to disk, and copied in memory, respectively. There are a few minor caveats to keep in mind, however: + + - Archives and copies of HTTP clients will be initialized with an empty operation queue. + - NSecureCoding cannot serialize / deserialize block properties, so an archive of an HTTP client will not include any reachability callback block that may be set. + */ +@interface AFHTTPRequestOperationManager : NSObject + +/** + The URL used to monitor reachability, and construct requests from relative paths in methods like `requestWithMethod:URLString:parameters:`, and the `GET` / `POST` / et al. convenience methods. + */ +@property (readonly, nonatomic, strong) NSURL *baseURL; + +/** + Requests created with `requestWithMethod:URLString:parameters:` & `multipartFormRequestWithMethod:URLString:parameters:constructingBodyWithBlock:` are constructed with a set of default headers using a parameter serialization specified by this property. By default, this is set to an instance of `AFHTTPRequestSerializer`, which serializes query string parameters for `GET`, `HEAD`, and `DELETE` requests, or otherwise URL-form-encodes HTTP message bodies. + + @warning `requestSerializer` must not be `nil`. + */ +@property (nonatomic, strong) AFHTTPRequestSerializer * requestSerializer; + +/** + Responses sent from the server in data tasks created with `dataTaskWithRequest:success:failure:` and run using the `GET` / `POST` / et al. convenience methods are automatically validated and serialized by the response serializer. By default, this property is set to a JSON serializer, which serializes data from responses with a `application/json` MIME type, and falls back to the raw data object. The serializer validates the status code to be in the `2XX` range, denoting success. If the response serializer generates an error in `-responseObjectForResponse:data:error:`, the `failure` callback of the session task or request operation will be executed; otherwise, the `success` callback will be executed. + + @warning `responseSerializer` must not be `nil`. + */ +@property (nonatomic, strong) AFHTTPResponseSerializer * responseSerializer; + +/** + The operation queue on which request operations are scheduled and run. + */ +@property (nonatomic, strong) NSOperationQueue *operationQueue; + +///------------------------------- +/// @name Managing URL Credentials +///------------------------------- + +/** + Whether request operations should consult the credential storage for authenticating the connection. `YES` by default. + + @see AFURLConnectionOperation -shouldUseCredentialStorage + */ +@property (nonatomic, assign) BOOL shouldUseCredentialStorage; + +/** + The credential used by request operations for authentication challenges. + + @see AFURLConnectionOperation -credential + */ +@property (nonatomic, strong) NSURLCredential *credential; + +///------------------------------- +/// @name Managing Security Policy +///------------------------------- + +/** + The security policy used by created request operations to evaluate server trust for secure connections. `AFHTTPRequestOperationManager` uses the `defaultPolicy` unless otherwise specified. + */ +@property (nonatomic, strong) AFSecurityPolicy *securityPolicy; + +///------------------------------------ +/// @name Managing Network Reachability +///------------------------------------ + +/** + The network reachability manager. `AFHTTPRequestOperationManager` uses the `sharedManager` by default. + */ +@property (readwrite, nonatomic, strong) AFNetworkReachabilityManager *reachabilityManager; + +///------------------------------- +/// @name Managing Callback Queues +///------------------------------- + +/** + The dispatch queue for the `completionBlock` of request operations. If `NULL` (default), the main queue is used. + */ +@property (nonatomic, strong) dispatch_queue_t completionQueue; + +/** + The dispatch group for the `completionBlock` of request operations. If `NULL` (default), a private dispatch group is used. + */ +@property (nonatomic, strong) dispatch_group_t completionGroup; + +///--------------------------------------------- +/// @name Creating and Initializing HTTP Clients +///--------------------------------------------- + +/** + Creates and returns an `AFHTTPRequestOperationManager` object. + */ ++ (instancetype)manager; + +/** + Initializes an `AFHTTPRequestOperationManager` object with the specified base URL. + + This is the designated initializer. + + @param url The base URL for the HTTP client. + + @return The newly-initialized HTTP client + */ +- (instancetype)initWithBaseURL:(NSURL *)url; + +///--------------------------------------- +/// @name Managing HTTP Request Operations +///--------------------------------------- + +/** + Creates an `AFHTTPRequestOperation`, and sets the response serializers to that of the HTTP client. + + @param request The request object to be loaded asynchronously during execution of the operation. + @param success A block object to be executed when the request operation finishes successfully. This block has no return value and takes two arguments: the created request operation and the object created from the response data of request. + @param failure A block object to be executed when the request operation finishes unsuccessfully, or that finishes successfully, but encountered an error while parsing the response data. This block has no return value and takes two arguments:, the created request operation and the `NSError` object describing the network or parsing error that occurred. + */ +- (AFHTTPRequestOperation *)HTTPRequestOperationWithRequest:(NSURLRequest *)request + success:(void (^)(AFHTTPRequestOperation *operation, id responseObject))success + failure:(void (^)(AFHTTPRequestOperation *operation, NSError *error))failure; + +///--------------------------- +/// @name Making HTTP Requests +///--------------------------- + +/** + Creates and runs an `AFHTTPRequestOperation` with a `GET` request. + + @param URLString The URL string used to create the request URL. + @param parameters The parameters to be encoded according to the client request serializer. + @param success A block object to be executed when the request operation finishes successfully. This block has no return value and takes two arguments: the request operation, and the response object created by the client response serializer. + @param failure A block object to be executed when the request operation finishes unsuccessfully, or that finishes successfully, but encountered an error while parsing the response data. This block has no return value and takes a two arguments: the request operation and the error describing the network or parsing error that occurred. + + @see -HTTPRequestOperationWithRequest:success:failure: + */ +- (AFHTTPRequestOperation *)GET:(NSString *)URLString + parameters:(id)parameters + success:(void (^)(AFHTTPRequestOperation *operation, id responseObject))success + failure:(void (^)(AFHTTPRequestOperation *operation, NSError *error))failure; + +/** + Creates and runs an `AFHTTPRequestOperation` with a `HEAD` request. + + @param URLString The URL string used to create the request URL. + @param parameters The parameters to be encoded according to the client request serializer. + @param success A block object to be executed when the request operation finishes successfully. This block has no return value and takes a single arguments: the request operation. + @param failure A block object to be executed when the request operation finishes unsuccessfully, or that finishes successfully, but encountered an error while parsing the response data. This block has no return value and takes a two arguments: the request operation and the error describing the network or parsing error that occurred. + + @see -HTTPRequestOperationWithRequest:success:failure: + */ +- (AFHTTPRequestOperation *)HEAD:(NSString *)URLString + parameters:(id)parameters + success:(void (^)(AFHTTPRequestOperation *operation))success + failure:(void (^)(AFHTTPRequestOperation *operation, NSError *error))failure; + +/** + Creates and runs an `AFHTTPRequestOperation` with a `POST` request. + + @param URLString The URL string used to create the request URL. + @param parameters The parameters to be encoded according to the client request serializer. + @param success A block object to be executed when the request operation finishes successfully. This block has no return value and takes two arguments: the request operation, and the response object created by the client response serializer. + @param failure A block object to be executed when the request operation finishes unsuccessfully, or that finishes successfully, but encountered an error while parsing the response data. This block has no return value and takes a two arguments: the request operation and the error describing the network or parsing error that occurred. + + @see -HTTPRequestOperationWithRequest:success:failure: + */ +- (AFHTTPRequestOperation *)POST:(NSString *)URLString + parameters:(id)parameters + success:(void (^)(AFHTTPRequestOperation *operation, id responseObject))success + failure:(void (^)(AFHTTPRequestOperation *operation, NSError *error))failure; + +/** + Creates and runs an `AFHTTPRequestOperation` with a multipart `POST` request. + + @param URLString The URL string used to create the request URL. + @param parameters The parameters to be encoded according to the client request serializer. + @param block A block that takes a single argument and appends data to the HTTP body. The block argument is an object adopting the `AFMultipartFormData` protocol. + @param success A block object to be executed when the request operation finishes successfully. This block has no return value and takes two arguments: the request operation, and the response object created by the client response serializer. + @param failure A block object to be executed when the request operation finishes unsuccessfully, or that finishes successfully, but encountered an error while parsing the response data. This block has no return value and takes a two arguments: the request operation and the error describing the network or parsing error that occurred. + + @see -HTTPRequestOperationWithRequest:success:failure: + */ +- (AFHTTPRequestOperation *)POST:(NSString *)URLString + parameters:(id)parameters + constructingBodyWithBlock:(void (^)(id formData))block + success:(void (^)(AFHTTPRequestOperation *operation, id responseObject))success + failure:(void (^)(AFHTTPRequestOperation *operation, NSError *error))failure; + +/** + Creates and runs an `AFHTTPRequestOperation` with a `PUT` request. + + @param URLString The URL string used to create the request URL. + @param parameters The parameters to be encoded according to the client request serializer. + @param success A block object to be executed when the request operation finishes successfully. This block has no return value and takes two arguments: the request operation, and the response object created by the client response serializer. + @param failure A block object to be executed when the request operation finishes unsuccessfully, or that finishes successfully, but encountered an error while parsing the response data. This block has no return value and takes a two arguments: the request operation and the error describing the network or parsing error that occurred. + + @see -HTTPRequestOperationWithRequest:success:failure: + */ +- (AFHTTPRequestOperation *)PUT:(NSString *)URLString + parameters:(id)parameters + success:(void (^)(AFHTTPRequestOperation *operation, id responseObject))success + failure:(void (^)(AFHTTPRequestOperation *operation, NSError *error))failure; + +/** + Creates and runs an `AFHTTPRequestOperation` with a `PATCH` request. + + @param URLString The URL string used to create the request URL. + @param parameters The parameters to be encoded according to the client request serializer. + @param success A block object to be executed when the request operation finishes successfully. This block has no return value and takes two arguments: the request operation, and the response object created by the client response serializer. + @param failure A block object to be executed when the request operation finishes unsuccessfully, or that finishes successfully, but encountered an error while parsing the response data. This block has no return value and takes a two arguments: the request operation and the error describing the network or parsing error that occurred. + + @see -HTTPRequestOperationWithRequest:success:failure: + */ +- (AFHTTPRequestOperation *)PATCH:(NSString *)URLString + parameters:(id)parameters + success:(void (^)(AFHTTPRequestOperation *operation, id responseObject))success + failure:(void (^)(AFHTTPRequestOperation *operation, NSError *error))failure; + +/** + Creates and runs an `AFHTTPRequestOperation` with a `DELETE` request. + + @param URLString The URL string used to create the request URL. + @param parameters The parameters to be encoded according to the client request serializer. + @param success A block object to be executed when the request operation finishes successfully. This block has no return value and takes two arguments: the request operation, and the response object created by the client response serializer. + @param failure A block object to be executed when the request operation finishes unsuccessfully, or that finishes successfully, but encountered an error while parsing the response data. This block has no return value and takes a two arguments: the request operation and the error describing the network or parsing error that occurred. + + @see -HTTPRequestOperationWithRequest:success:failure: + */ +- (AFHTTPRequestOperation *)DELETE:(NSString *)URLString + parameters:(id)parameters + success:(void (^)(AFHTTPRequestOperation *operation, id responseObject))success + failure:(void (^)(AFHTTPRequestOperation *operation, NSError *error))failure; + +@end + diff --git a/ios/Pods/AFNetworking/AFNetworking/AFHTTPRequestOperationManager.m b/ios/Pods/AFNetworking/AFNetworking/AFHTTPRequestOperationManager.m new file mode 100644 index 000000000..03116cc73 --- /dev/null +++ b/ios/Pods/AFNetworking/AFNetworking/AFHTTPRequestOperationManager.m @@ -0,0 +1,253 @@ +// AFHTTPRequestOperationManager.m +// +// Copyright (c) 2013-2014 AFNetworking (http://afnetworking.com) +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +#import + +#import "AFHTTPRequestOperationManager.h" +#import "AFHTTPRequestOperation.h" + +#import +#import + +#if defined(__IPHONE_OS_VERSION_MIN_REQUIRED) +#import +#endif + +@interface AFHTTPRequestOperationManager () +@property (readwrite, nonatomic, strong) NSURL *baseURL; +@end + +@implementation AFHTTPRequestOperationManager + ++ (instancetype)manager { + return [[self alloc] initWithBaseURL:nil]; +} + +- (instancetype)init { + return [self initWithBaseURL:nil]; +} + +- (instancetype)initWithBaseURL:(NSURL *)url { + self = [super init]; + if (!self) { + return nil; + } + + // Ensure terminal slash for baseURL path, so that NSURL +URLWithString:relativeToURL: works as expected + if ([[url path] length] > 0 && ![[url absoluteString] hasSuffix:@"/"]) { + url = [url URLByAppendingPathComponent:@""]; + } + + self.baseURL = url; + + self.requestSerializer = [AFHTTPRequestSerializer serializer]; + self.responseSerializer = [AFJSONResponseSerializer serializer]; + + self.securityPolicy = [AFSecurityPolicy defaultPolicy]; + + self.reachabilityManager = [AFNetworkReachabilityManager sharedManager]; + + self.operationQueue = [[NSOperationQueue alloc] init]; + + self.shouldUseCredentialStorage = YES; + + return self; +} + +#pragma mark - + +#ifdef _SYSTEMCONFIGURATION_H +#endif + +- (void)setRequestSerializer:(AFHTTPRequestSerializer *)requestSerializer { + NSParameterAssert(requestSerializer); + + _requestSerializer = requestSerializer; +} + +- (void)setResponseSerializer:(AFHTTPResponseSerializer *)responseSerializer { + NSParameterAssert(responseSerializer); + + _responseSerializer = responseSerializer; +} + +#pragma mark - + +- (AFHTTPRequestOperation *)HTTPRequestOperationWithRequest:(NSURLRequest *)request + success:(void (^)(AFHTTPRequestOperation *operation, id responseObject))success + failure:(void (^)(AFHTTPRequestOperation *operation, NSError *error))failure +{ + AFHTTPRequestOperation *operation = [[AFHTTPRequestOperation alloc] initWithRequest:request]; + operation.responseSerializer = self.responseSerializer; + operation.shouldUseCredentialStorage = self.shouldUseCredentialStorage; + operation.credential = self.credential; + operation.securityPolicy = self.securityPolicy; + + [operation setCompletionBlockWithSuccess:success failure:failure]; + operation.completionQueue = self.completionQueue; + operation.completionGroup = self.completionGroup; + + return operation; +} + +#pragma mark - + +- (AFHTTPRequestOperation *)GET:(NSString *)URLString + parameters:(id)parameters + success:(void (^)(AFHTTPRequestOperation *operation, id responseObject))success + failure:(void (^)(AFHTTPRequestOperation *operation, NSError *error))failure +{ + NSMutableURLRequest *request = [self.requestSerializer requestWithMethod:@"GET" URLString:[[NSURL URLWithString:URLString relativeToURL:self.baseURL] absoluteString] parameters:parameters error:nil]; + AFHTTPRequestOperation *operation = [self HTTPRequestOperationWithRequest:request success:success failure:failure]; + + [self.operationQueue addOperation:operation]; + + return operation; +} + +- (AFHTTPRequestOperation *)HEAD:(NSString *)URLString + parameters:(id)parameters + success:(void (^)(AFHTTPRequestOperation *operation))success + failure:(void (^)(AFHTTPRequestOperation *operation, NSError *error))failure +{ + NSMutableURLRequest *request = [self.requestSerializer requestWithMethod:@"HEAD" URLString:[[NSURL URLWithString:URLString relativeToURL:self.baseURL] absoluteString] parameters:parameters error:nil]; + AFHTTPRequestOperation *operation = [self HTTPRequestOperationWithRequest:request success:^(AFHTTPRequestOperation *requestOperation, __unused id responseObject) { + if (success) { + success(requestOperation); + } + } failure:failure]; + + [self.operationQueue addOperation:operation]; + + return operation; +} + +- (AFHTTPRequestOperation *)POST:(NSString *)URLString + parameters:(id)parameters + success:(void (^)(AFHTTPRequestOperation *operation, id responseObject))success + failure:(void (^)(AFHTTPRequestOperation *operation, NSError *error))failure +{ + NSMutableURLRequest *request = [self.requestSerializer requestWithMethod:@"POST" URLString:[[NSURL URLWithString:URLString relativeToURL:self.baseURL] absoluteString] parameters:parameters error:nil]; + AFHTTPRequestOperation *operation = [self HTTPRequestOperationWithRequest:request success:success failure:failure]; + + [self.operationQueue addOperation:operation]; + + return operation; +} + +- (AFHTTPRequestOperation *)POST:(NSString *)URLString + parameters:(id)parameters + constructingBodyWithBlock:(void (^)(id formData))block + success:(void (^)(AFHTTPRequestOperation *operation, id responseObject))success + failure:(void (^)(AFHTTPRequestOperation *operation, NSError *error))failure +{ + NSMutableURLRequest *request = [self.requestSerializer multipartFormRequestWithMethod:@"POST" URLString:[[NSURL URLWithString:URLString relativeToURL:self.baseURL] absoluteString] parameters:parameters constructingBodyWithBlock:block error:nil]; + AFHTTPRequestOperation *operation = [self HTTPRequestOperationWithRequest:request success:success failure:failure]; + + [self.operationQueue addOperation:operation]; + + return operation; +} + +- (AFHTTPRequestOperation *)PUT:(NSString *)URLString + parameters:(id)parameters + success:(void (^)(AFHTTPRequestOperation *operation, id responseObject))success + failure:(void (^)(AFHTTPRequestOperation *operation, NSError *error))failure +{ + NSMutableURLRequest *request = [self.requestSerializer requestWithMethod:@"PUT" URLString:[[NSURL URLWithString:URLString relativeToURL:self.baseURL] absoluteString] parameters:parameters error:nil]; + AFHTTPRequestOperation *operation = [self HTTPRequestOperationWithRequest:request success:success failure:failure]; + + [self.operationQueue addOperation:operation]; + + return operation; +} + +- (AFHTTPRequestOperation *)PATCH:(NSString *)URLString + parameters:(id)parameters + success:(void (^)(AFHTTPRequestOperation *operation, id responseObject))success + failure:(void (^)(AFHTTPRequestOperation *operation, NSError *error))failure +{ + NSMutableURLRequest *request = [self.requestSerializer requestWithMethod:@"PATCH" URLString:[[NSURL URLWithString:URLString relativeToURL:self.baseURL] absoluteString] parameters:parameters error:nil]; + AFHTTPRequestOperation *operation = [self HTTPRequestOperationWithRequest:request success:success failure:failure]; + + [self.operationQueue addOperation:operation]; + + return operation; +} + +- (AFHTTPRequestOperation *)DELETE:(NSString *)URLString + parameters:(id)parameters + success:(void (^)(AFHTTPRequestOperation *operation, id responseObject))success + failure:(void (^)(AFHTTPRequestOperation *operation, NSError *error))failure +{ + NSMutableURLRequest *request = [self.requestSerializer requestWithMethod:@"DELETE" URLString:[[NSURL URLWithString:URLString relativeToURL:self.baseURL] absoluteString] parameters:parameters error:nil]; + AFHTTPRequestOperation *operation = [self HTTPRequestOperationWithRequest:request success:success failure:failure]; + + [self.operationQueue addOperation:operation]; + + return operation; +} + +#pragma mark - NSObject + +- (NSString *)description { + return [NSString stringWithFormat:@"<%@: %p, baseURL: %@, operationQueue: %@>", NSStringFromClass([self class]), self, [self.baseURL absoluteString], self.operationQueue]; +} + +#pragma mark - NSecureCoding + ++ (BOOL)supportsSecureCoding { + return YES; +} + +- (id)initWithCoder:(NSCoder *)decoder { + NSURL *baseURL = [decoder decodeObjectForKey:NSStringFromSelector(@selector(baseURL))]; + + self = [self initWithBaseURL:baseURL]; + if (!self) { + return nil; + } + + self.requestSerializer = [decoder decodeObjectOfClass:[AFHTTPRequestSerializer class] forKey:NSStringFromSelector(@selector(requestSerializer))]; + self.responseSerializer = [decoder decodeObjectOfClass:[AFHTTPResponseSerializer class] forKey:NSStringFromSelector(@selector(responseSerializer))]; + + return self; +} + +- (void)encodeWithCoder:(NSCoder *)coder { + [coder encodeObject:self.baseURL forKey:NSStringFromSelector(@selector(baseURL))]; + [coder encodeObject:self.requestSerializer forKey:NSStringFromSelector(@selector(requestSerializer))]; + [coder encodeObject:self.responseSerializer forKey:NSStringFromSelector(@selector(responseSerializer))]; +} + +#pragma mark - NSCopying + +- (id)copyWithZone:(NSZone *)zone { + AFHTTPRequestOperationManager *HTTPClient = [[[self class] allocWithZone:zone] initWithBaseURL:self.baseURL]; + + HTTPClient.requestSerializer = [self.requestSerializer copyWithZone:zone]; + HTTPClient.responseSerializer = [self.responseSerializer copyWithZone:zone]; + + return HTTPClient; +} + +@end diff --git a/ios/Pods/AFNetworking/AFNetworking/AFHTTPSessionManager.h b/ios/Pods/AFNetworking/AFNetworking/AFHTTPSessionManager.h new file mode 100644 index 000000000..a84fcc554 --- /dev/null +++ b/ios/Pods/AFNetworking/AFNetworking/AFHTTPSessionManager.h @@ -0,0 +1,238 @@ +// AFHTTPSessionManager.h +// +// Copyright (c) 2013-2014 AFNetworking (http://afnetworking.com) +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +#import +#import +#import + +#if __IPHONE_OS_VERSION_MIN_REQUIRED +#import +#else +#import +#endif + +#import "AFURLSessionManager.h" + +/** + `AFHTTPSessionManager` is a subclass of `AFURLSessionManager` with convenience methods for making HTTP requests. When a `baseURL` is provided, requests made with the `GET` / `POST` / et al. convenience methods can be made with relative paths. + + ## Subclassing Notes + + Developers targeting iOS 7 or Mac OS X 10.9 or later that deal extensively with a web service are encouraged to subclass `AFHTTPSessionManager`, providing a class method that returns a shared singleton object on which authentication and other configuration can be shared across the application. + + For developers targeting iOS 6 or Mac OS X 10.8 or earlier, `AFHTTPRequestOperationManager` may be used to similar effect. + + ## Methods to Override + + To change the behavior of all data task operation construction, which is also used in the `GET` / `POST` / et al. convenience methods, override `dataTaskWithRequest:completionHandler:`. + + ## Serialization + + Requests created by an HTTP client will contain default headers and encode parameters according to the `requestSerializer` property, which is an object conforming to ``. + + Responses received from the server are automatically validated and serialized by the `responseSerializers` property, which is an object conforming to `` + + ## URL Construction Using Relative Paths + + For HTTP convenience methods, the request serializer constructs URLs from the path relative to the `-baseURL`, using `NSURL +URLWithString:relativeToURL:`, when provided. If `baseURL` is `nil`, `path` needs to resolve to a valid `NSURL` object using `NSURL +URLWithString:`. + + Below are a few examples of how `baseURL` and relative paths interact: + + NSURL *baseURL = [NSURL URLWithString:@"http://example.com/v1/"]; + [NSURL URLWithString:@"foo" relativeToURL:baseURL]; // http://example.com/v1/foo + [NSURL URLWithString:@"foo?bar=baz" relativeToURL:baseURL]; // http://example.com/v1/foo?bar=baz + [NSURL URLWithString:@"/foo" relativeToURL:baseURL]; // http://example.com/foo + [NSURL URLWithString:@"foo/" relativeToURL:baseURL]; // http://example.com/v1/foo + [NSURL URLWithString:@"/foo/" relativeToURL:baseURL]; // http://example.com/foo/ + [NSURL URLWithString:@"http://example2.com/" relativeToURL:baseURL]; // http://example2.com/ + + Also important to note is that a trailing slash will be added to any `baseURL` without one. This would otherwise cause unexpected behavior when constructing URLs using paths without a leading slash. + */ + +#if (defined(__IPHONE_OS_VERSION_MAX_ALLOWED) && __IPHONE_OS_VERSION_MAX_ALLOWED >= 70000) || (defined(__MAC_OS_X_VERSION_MAX_ALLOWED) && __MAC_OS_X_VERSION_MAX_ALLOWED >= 1090) + +@interface AFHTTPSessionManager : AFURLSessionManager + +/** + The URL used to monitor reachability, and construct requests from relative paths in methods like `requestWithMethod:URLString:parameters:`, and the `GET` / `POST` / et al. convenience methods. + */ +@property (readonly, nonatomic, strong) NSURL *baseURL; + +/** + Requests created with `requestWithMethod:URLString:parameters:` & `multipartFormRequestWithMethod:URLString:parameters:constructingBodyWithBlock:` are constructed with a set of default headers using a parameter serialization specified by this property. By default, this is set to an instance of `AFHTTPRequestSerializer`, which serializes query string parameters for `GET`, `HEAD`, and `DELETE` requests, or otherwise URL-form-encodes HTTP message bodies. + + @warning `requestSerializer` must not be `nil`. + */ +@property (nonatomic, strong) AFHTTPRequestSerializer * requestSerializer; + +/** + Responses sent from the server in data tasks created with `dataTaskWithRequest:success:failure:` and run using the `GET` / `POST` / et al. convenience methods are automatically validated and serialized by the response serializer. By default, this property is set to an instance of `AFJSONResponseSerializer`. + + @warning `responseSerializer` must not be `nil`. + */ +@property (nonatomic, strong) AFHTTPResponseSerializer * responseSerializer; + +///--------------------- +/// @name Initialization +///--------------------- + +/** + Creates and returns an `AFHTTPSessionManager` object. + */ ++ (instancetype)manager; + +/** + Initializes an `AFHTTPSessionManager` object with the specified base URL. + + @param url The base URL for the HTTP client. + + @return The newly-initialized HTTP client + */ +- (instancetype)initWithBaseURL:(NSURL *)url; + +/** + Initializes an `AFHTTPSessionManager` object with the specified base URL. + + This is the designated initializer. + + @param url The base URL for the HTTP client. + @param configuration The configuration used to create the managed session. + + @return The newly-initialized HTTP client + */ +- (instancetype)initWithBaseURL:(NSURL *)url + sessionConfiguration:(NSURLSessionConfiguration *)configuration; + +///--------------------------- +/// @name Making HTTP Requests +///--------------------------- + +/** + Creates and runs an `NSURLSessionDataTask` with a `GET` request. + + @param URLString The URL string used to create the request URL. + @param parameters The parameters to be encoded according to the client request serializer. + @param success A block object to be executed when the task finishes successfully. This block has no return value and takes two arguments: the data task, and the response object created by the client response serializer. + @param failure A block object to be executed when the task finishes unsuccessfully, or that finishes successfully, but encountered an error while parsing the response data. This block has no return value and takes a two arguments: the data task and the error describing the network or parsing error that occurred. + + @see -dataTaskWithRequest:completionHandler: + */ +- (NSURLSessionDataTask *)GET:(NSString *)URLString + parameters:(id)parameters + success:(void (^)(NSURLSessionDataTask *task, id responseObject))success + failure:(void (^)(NSURLSessionDataTask *task, NSError *error))failure; + +/** + Creates and runs an `NSURLSessionDataTask` with a `HEAD` request. + + @param URLString The URL string used to create the request URL. + @param parameters The parameters to be encoded according to the client request serializer. + @param success A block object to be executed when the task finishes successfully. This block has no return value and takes a single arguments: the data task. + @param failure A block object to be executed when the task finishes unsuccessfully, or that finishes successfully, but encountered an error while parsing the response data. This block has no return value and takes a two arguments: the data task and the error describing the network or parsing error that occurred. + + @see -dataTaskWithRequest:completionHandler: + */ +- (NSURLSessionDataTask *)HEAD:(NSString *)URLString + parameters:(id)parameters + success:(void (^)(NSURLSessionDataTask *task))success + failure:(void (^)(NSURLSessionDataTask *task, NSError *error))failure; + +/** + Creates and runs an `NSURLSessionDataTask` with a `POST` request. + + @param URLString The URL string used to create the request URL. + @param parameters The parameters to be encoded according to the client request serializer. + @param success A block object to be executed when the task finishes successfully. This block has no return value and takes two arguments: the data task, and the response object created by the client response serializer. + @param failure A block object to be executed when the task finishes unsuccessfully, or that finishes successfully, but encountered an error while parsing the response data. This block has no return value and takes a two arguments: the data task and the error describing the network or parsing error that occurred. + + @see -dataTaskWithRequest:completionHandler: + */ +- (NSURLSessionDataTask *)POST:(NSString *)URLString + parameters:(id)parameters + success:(void (^)(NSURLSessionDataTask *task, id responseObject))success + failure:(void (^)(NSURLSessionDataTask *task, NSError *error))failure; + +/** + Creates and runs an `NSURLSessionDataTask` with a multipart `POST` request. + + @param URLString The URL string used to create the request URL. + @param parameters The parameters to be encoded according to the client request serializer. + @param block A block that takes a single argument and appends data to the HTTP body. The block argument is an object adopting the `AFMultipartFormData` protocol. + @param success A block object to be executed when the task finishes successfully. This block has no return value and takes two arguments: the data task, and the response object created by the client response serializer. + @param failure A block object to be executed when the task finishes unsuccessfully, or that finishes successfully, but encountered an error while parsing the response data. This block has no return value and takes a two arguments: the data task and the error describing the network or parsing error that occurred. + + @see -dataTaskWithRequest:completionHandler: + */ +- (NSURLSessionDataTask *)POST:(NSString *)URLString + parameters:(id)parameters + constructingBodyWithBlock:(void (^)(id formData))block + success:(void (^)(NSURLSessionDataTask *task, id responseObject))success + failure:(void (^)(NSURLSessionDataTask *task, NSError *error))failure; + +/** + Creates and runs an `NSURLSessionDataTask` with a `PUT` request. + + @param URLString The URL string used to create the request URL. + @param parameters The parameters to be encoded according to the client request serializer. + @param success A block object to be executed when the task finishes successfully. This block has no return value and takes two arguments: the data task, and the response object created by the client response serializer. + @param failure A block object to be executed when the task finishes unsuccessfully, or that finishes successfully, but encountered an error while parsing the response data. This block has no return value and takes a two arguments: the data task and the error describing the network or parsing error that occurred. + + @see -dataTaskWithRequest:completionHandler: + */ +- (NSURLSessionDataTask *)PUT:(NSString *)URLString + parameters:(id)parameters + success:(void (^)(NSURLSessionDataTask *task, id responseObject))success + failure:(void (^)(NSURLSessionDataTask *task, NSError *error))failure; + +/** + Creates and runs an `NSURLSessionDataTask` with a `PATCH` request. + + @param URLString The URL string used to create the request URL. + @param parameters The parameters to be encoded according to the client request serializer. + @param success A block object to be executed when the task finishes successfully. This block has no return value and takes two arguments: the data task, and the response object created by the client response serializer. + @param failure A block object to be executed when the task finishes unsuccessfully, or that finishes successfully, but encountered an error while parsing the response data. This block has no return value and takes a two arguments: the data task and the error describing the network or parsing error that occurred. + + @see -dataTaskWithRequest:completionHandler: + */ +- (NSURLSessionDataTask *)PATCH:(NSString *)URLString + parameters:(id)parameters + success:(void (^)(NSURLSessionDataTask *task, id responseObject))success + failure:(void (^)(NSURLSessionDataTask *task, NSError *error))failure; + +/** + Creates and runs an `NSURLSessionDataTask` with a `DELETE` request. + + @param URLString The URL string used to create the request URL. + @param parameters The parameters to be encoded according to the client request serializer. + @param success A block object to be executed when the task finishes successfully. This block has no return value and takes two arguments: the data task, and the response object created by the client response serializer. + @param failure A block object to be executed when the task finishes unsuccessfully, or that finishes successfully, but encountered an error while parsing the response data. This block has no return value and takes a two arguments: the data task and the error describing the network or parsing error that occurred. + + @see -dataTaskWithRequest:completionHandler: + */ +- (NSURLSessionDataTask *)DELETE:(NSString *)URLString + parameters:(id)parameters + success:(void (^)(NSURLSessionDataTask *task, id responseObject))success + failure:(void (^)(NSURLSessionDataTask *task, NSError *error))failure; + +@end + +#endif diff --git a/ios/Pods/AFNetworking/AFNetworking/AFHTTPSessionManager.m b/ios/Pods/AFNetworking/AFNetworking/AFHTTPSessionManager.m new file mode 100644 index 000000000..5abfe7e31 --- /dev/null +++ b/ios/Pods/AFNetworking/AFNetworking/AFHTTPSessionManager.m @@ -0,0 +1,339 @@ +// AFHTTPSessionManager.m +// +// Copyright (c) 2013-2014 AFNetworking (http://afnetworking.com) +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +#import "AFHTTPSessionManager.h" + +#if (defined(__IPHONE_OS_VERSION_MAX_ALLOWED) && __IPHONE_OS_VERSION_MAX_ALLOWED >= 70000) || (defined(__MAC_OS_X_VERSION_MAX_ALLOWED) && __MAC_OS_X_VERSION_MAX_ALLOWED >= 1090) + +#import "AFURLRequestSerialization.h" +#import "AFURLResponseSerialization.h" + +#import +#import + +#ifdef _SYSTEMCONFIGURATION_H +#import +#import +#import +#import +#import +#endif + +#if defined(__IPHONE_OS_VERSION_MIN_REQUIRED) +#import +#endif + +@interface AFHTTPSessionManager () +@property (readwrite, nonatomic, strong) NSURL *baseURL; +@end + +@implementation AFHTTPSessionManager + ++ (instancetype)manager { + return [[[self class] alloc] initWithBaseURL:nil]; +} + +- (instancetype)init { + return [self initWithBaseURL:nil]; +} + +- (instancetype)initWithBaseURL:(NSURL *)url { + return [self initWithBaseURL:url sessionConfiguration:nil]; +} + +- (instancetype)initWithSessionConfiguration:(NSURLSessionConfiguration *)configuration { + return [self initWithBaseURL:nil sessionConfiguration:configuration]; +} + +- (instancetype)initWithBaseURL:(NSURL *)url + sessionConfiguration:(NSURLSessionConfiguration *)configuration +{ + self = [super initWithSessionConfiguration:configuration]; + if (!self) { + return nil; + } + + // Ensure terminal slash for baseURL path, so that NSURL +URLWithString:relativeToURL: works as expected + if ([[url path] length] > 0 && ![[url absoluteString] hasSuffix:@"/"]) { + url = [url URLByAppendingPathComponent:@""]; + } + + self.baseURL = url; + + self.requestSerializer = [AFHTTPRequestSerializer serializer]; + self.responseSerializer = [AFJSONResponseSerializer serializer]; + + return self; +} + +#pragma mark - + +#ifdef _SYSTEMCONFIGURATION_H +#endif + +- (void)setRequestSerializer:(AFHTTPRequestSerializer *)requestSerializer { + NSParameterAssert(requestSerializer); + + _requestSerializer = requestSerializer; +} + +- (void)setResponseSerializer:(AFHTTPResponseSerializer *)responseSerializer { + NSParameterAssert(responseSerializer); + + [super setResponseSerializer:responseSerializer]; +} + +#pragma mark - + +- (NSURLSessionDataTask *)GET:(NSString *)URLString + parameters:(id)parameters + success:(void (^)(NSURLSessionDataTask *task, id responseObject))success + failure:(void (^)(NSURLSessionDataTask *task, NSError *error))failure +{ + NSMutableURLRequest *request = [self.requestSerializer requestWithMethod:@"GET" URLString:[[NSURL URLWithString:URLString relativeToURL:self.baseURL] absoluteString] parameters:parameters error:nil]; + + __block NSURLSessionDataTask *task = [self dataTaskWithRequest:request completionHandler:^(NSURLResponse * __unused response, id responseObject, NSError *error) { + if (error) { + if (failure) { + failure(task, error); + } + } else { + if (success) { + success(task, responseObject); + } + } + }]; + + [task resume]; + + return task; +} + +- (NSURLSessionDataTask *)HEAD:(NSString *)URLString + parameters:(id)parameters + success:(void (^)(NSURLSessionDataTask *task))success + failure:(void (^)(NSURLSessionDataTask *task, NSError *error))failure +{ + NSMutableURLRequest *request = [self.requestSerializer requestWithMethod:@"HEAD" URLString:[[NSURL URLWithString:URLString relativeToURL:self.baseURL] absoluteString] parameters:parameters error:nil]; + + __block NSURLSessionDataTask *task = [self dataTaskWithRequest:request completionHandler:^(NSURLResponse * __unused response, id __unused responseObject, NSError *error) { + if (error) { + if (failure) { + failure(task, error); + } + } else { + if (success) { + success(task); + } + } + }]; + + [task resume]; + + return task; +} + +- (NSURLSessionDataTask *)POST:(NSString *)URLString + parameters:(id)parameters + success:(void (^)(NSURLSessionDataTask *task, id responseObject))success + failure:(void (^)(NSURLSessionDataTask *task, NSError *error))failure +{ + NSMutableURLRequest *request = [self.requestSerializer requestWithMethod:@"POST" URLString:[[NSURL URLWithString:URLString relativeToURL:self.baseURL] absoluteString] parameters:parameters error:nil]; + + __block NSURLSessionDataTask *task = [self dataTaskWithRequest:request completionHandler:^(NSURLResponse * __unused response, id responseObject, NSError *error) { + if (error) { + if (failure) { + failure(task, error); + } + } else { + if (success) { + success(task, responseObject); + } + } + }]; + + [task resume]; + + return task; +} + +- (NSURLSessionDataTask *)POST:(NSString *)URLString + parameters:(id)parameters + constructingBodyWithBlock:(void (^)(id formData))block + success:(void (^)(NSURLSessionDataTask *task, id responseObject))success + failure:(void (^)(NSURLSessionDataTask *task, NSError *error))failure +{ + NSMutableURLRequest *request = [self.requestSerializer multipartFormRequestWithMethod:@"POST" URLString:[[NSURL URLWithString:URLString relativeToURL:self.baseURL] absoluteString] parameters:parameters constructingBodyWithBlock:block error:nil]; + + __block NSURLSessionDataTask *task = [self uploadTaskWithStreamedRequest:request progress:nil completionHandler:^(NSURLResponse * __unused response, id responseObject, NSError *error) { + if (error) { + if (failure) { + failure(task, error); + } + } else { + if (success) { + success(task, responseObject); + } + } + }]; + + [task resume]; + + return task; +} + +- (NSURLSessionDataTask *)PUT:(NSString *)URLString + parameters:(id)parameters + success:(void (^)(NSURLSessionDataTask *task, id responseObject))success + failure:(void (^)(NSURLSessionDataTask *task, NSError *error))failure +{ + NSMutableURLRequest *request = [self.requestSerializer requestWithMethod:@"PUT" URLString:[[NSURL URLWithString:URLString relativeToURL:self.baseURL] absoluteString] parameters:parameters error:nil]; + + __block NSURLSessionDataTask *task = [self dataTaskWithRequest:request completionHandler:^(NSURLResponse * __unused response, id responseObject, NSError *error) { + if (error) { + if (failure) { + failure(task, error); + } + } else { + if (success) { + success(task, responseObject); + } + } + }]; + + [task resume]; + + return task; +} + +- (NSURLSessionDataTask *)PATCH:(NSString *)URLString + parameters:(id)parameters + success:(void (^)(NSURLSessionDataTask *task, id responseObject))success + failure:(void (^)(NSURLSessionDataTask *task, NSError *error))failure +{ + NSMutableURLRequest *request = [self.requestSerializer requestWithMethod:@"PATCH" URLString:[[NSURL URLWithString:URLString relativeToURL:self.baseURL] absoluteString] parameters:parameters error:nil]; + + __block NSURLSessionDataTask *task = [self dataTaskWithRequest:request completionHandler:^(NSURLResponse * __unused response, id responseObject, NSError *error) { + if (error) { + if (failure) { + failure(task, error); + } + } else { + if (success) { + success(task, responseObject); + } + } + }]; + + [task resume]; + + return task; +} + +- (NSURLSessionDataTask *)DELETE:(NSString *)URLString + parameters:(id)parameters + success:(void (^)(NSURLSessionDataTask *task, id responseObject))success + failure:(void (^)(NSURLSessionDataTask *task, NSError *error))failure +{ + NSMutableURLRequest *request = [self.requestSerializer requestWithMethod:@"DELETE" URLString:[[NSURL URLWithString:URLString relativeToURL:self.baseURL] absoluteString] parameters:parameters error:nil]; + + __block NSURLSessionDataTask *task = [self dataTaskWithRequest:request completionHandler:^(NSURLResponse * __unused response, id responseObject, NSError *error) { + if (error) { + if (failure) { + failure(task, error); + } + } else { + if (success) { + success(task, responseObject); + } + } + }]; + + [task resume]; + + return task; +} + +#pragma mark - NSObject + +- (NSString *)description { + return [NSString stringWithFormat:@"<%@: %p, baseURL: %@, session: %@, operationQueue: %@>", NSStringFromClass([self class]), self, [self.baseURL absoluteString], self.session, self.operationQueue]; +} + +#pragma mark - NSecureCoding + ++ (BOOL)supportsSecureCoding { + return YES; +} + +- (id)initWithCoder:(NSCoder *)decoder { + NSURL *baseURL = [decoder decodeObjectOfClass:[NSURL class] forKey:NSStringFromSelector(@selector(baseURL))]; + NSURLSessionConfiguration *configuration = [decoder decodeObjectOfClass:[NSURLSessionConfiguration class] forKey:@"sessionConfiguration"]; + if (!configuration) { + NSString *configurationIdentifier = [decoder decodeObjectOfClass:[NSString class] forKey:@"identifier"]; + if (configurationIdentifier) { +#if (defined(__IPHONE_OS_VERSION_MAX_ALLOWED) && __IPHONE_OS_VERSION_MAX_ALLOWED >= 80000) || (defined(__MAC_OS_X_VERSION_MAX_ALLOWED) && __MAC_OS_X_VERSION_MAX_ALLOWED >= 1100) + configuration = [NSURLSessionConfiguration backgroundSessionConfigurationWithIdentifier:configurationIdentifier]; +#else + configuration = [NSURLSessionConfiguration backgroundSessionConfiguration:configurationIdentifier]; +#endif + } + } + + self = [self initWithBaseURL:baseURL sessionConfiguration:configuration]; + if (!self) { + return nil; + } + + self.requestSerializer = [decoder decodeObjectOfClass:[AFHTTPRequestSerializer class] forKey:NSStringFromSelector(@selector(requestSerializer))]; + self.responseSerializer = [decoder decodeObjectOfClass:[AFHTTPResponseSerializer class] forKey:NSStringFromSelector(@selector(responseSerializer))]; + + return self; +} + +- (void)encodeWithCoder:(NSCoder *)coder { + [super encodeWithCoder:coder]; + + [coder encodeObject:self.baseURL forKey:NSStringFromSelector(@selector(baseURL))]; + if ([self.session.configuration conformsToProtocol:@protocol(NSCoding)]) { + [coder encodeObject:self.session.configuration forKey:@"sessionConfiguration"]; + } else { + [coder encodeObject:self.session.configuration.identifier forKey:@"identifier"]; + } + [coder encodeObject:self.requestSerializer forKey:NSStringFromSelector(@selector(requestSerializer))]; + [coder encodeObject:self.responseSerializer forKey:NSStringFromSelector(@selector(responseSerializer))]; +} + +#pragma mark - NSCopying + +- (id)copyWithZone:(NSZone *)zone { + AFHTTPSessionManager *HTTPClient = [[[self class] allocWithZone:zone] initWithBaseURL:self.baseURL sessionConfiguration:self.session.configuration]; + + HTTPClient.requestSerializer = [self.requestSerializer copyWithZone:zone]; + HTTPClient.responseSerializer = [self.responseSerializer copyWithZone:zone]; + + return HTTPClient; +} + +@end + +#endif diff --git a/ios/Pods/AFNetworking/AFNetworking/AFNetworkReachabilityManager.h b/ios/Pods/AFNetworking/AFNetworking/AFNetworkReachabilityManager.h new file mode 100644 index 000000000..63207835f --- /dev/null +++ b/ios/Pods/AFNetworking/AFNetworking/AFNetworkReachabilityManager.h @@ -0,0 +1,199 @@ +// AFNetworkReachabilityManager.h +// +// Copyright (c) 2013-2014 AFNetworking (http://afnetworking.com) +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +#import +#import + +#import +#import +#import +#import +#import + +typedef NS_ENUM(NSInteger, AFNetworkReachabilityStatus) { + AFNetworkReachabilityStatusUnknown = -1, + AFNetworkReachabilityStatusNotReachable = 0, + AFNetworkReachabilityStatusReachableViaWWAN = 1, + AFNetworkReachabilityStatusReachableViaWiFi = 2, +}; + +/** + `AFNetworkReachabilityManager` monitors the reachability of domains, and addresses for both WWAN and WiFi network interfaces. + + Reachability can be used to determine background information about why a network operation failed, or to trigger a network operation retrying when a connection is established. It should not be used to prevent a user from initiating a network request, as it's possible that an initial request may be required to establish reachability. + + See Apple's Reachability Sample Code (https://developer.apple.com/library/ios/samplecode/reachability/) + + @warning Instances of `AFNetworkReachabilityManager` must be started with `-startMonitoring` before reachability status can be determined. + */ +@interface AFNetworkReachabilityManager : NSObject + +/** + The current network reachability status. + */ +@property (readonly, nonatomic, assign) AFNetworkReachabilityStatus networkReachabilityStatus; + +/** + Whether or not the network is currently reachable. + */ +@property (readonly, nonatomic, assign, getter = isReachable) BOOL reachable; + +/** + Whether or not the network is currently reachable via WWAN. + */ +@property (readonly, nonatomic, assign, getter = isReachableViaWWAN) BOOL reachableViaWWAN; + +/** + Whether or not the network is currently reachable via WiFi. + */ +@property (readonly, nonatomic, assign, getter = isReachableViaWiFi) BOOL reachableViaWiFi; + +///--------------------- +/// @name Initialization +///--------------------- + +/** + Returns the shared network reachability manager. + */ ++ (instancetype)sharedManager; + +/** + Creates and returns a network reachability manager for the specified domain. + + @param domain The domain used to evaluate network reachability. + + @return An initialized network reachability manager, actively monitoring the specified domain. + */ ++ (instancetype)managerForDomain:(NSString *)domain; + +/** + Creates and returns a network reachability manager for the socket address. + + @param address The socket address used to evaluate network reachability. + + @return An initialized network reachability manager, actively monitoring the specified socket address. + */ ++ (instancetype)managerForAddress:(const struct sockaddr_in *)address; + +/** + Initializes an instance of a network reachability manager from the specified reachability object. + + @param reachability The reachability object to monitor. + + @return An initialized network reachability manager, actively monitoring the specified reachability. + */ +- (instancetype)initWithReachability:(SCNetworkReachabilityRef)reachability; + +///-------------------------------------------------- +/// @name Starting & Stopping Reachability Monitoring +///-------------------------------------------------- + +/** + Starts monitoring for changes in network reachability status. + */ +- (void)startMonitoring; + +/** + Stops monitoring for changes in network reachability status. + */ +- (void)stopMonitoring; + +///------------------------------------------------- +/// @name Getting Localized Reachability Description +///------------------------------------------------- + +/** + Returns a localized string representation of the current network reachability status. + */ +- (NSString *)localizedNetworkReachabilityStatusString; + +///--------------------------------------------------- +/// @name Setting Network Reachability Change Callback +///--------------------------------------------------- + +/** + Sets a callback to be executed when the network availability of the `baseURL` host changes. + + @param block A block object to be executed when the network availability of the `baseURL` host changes.. This block has no return value and takes a single argument which represents the various reachability states from the device to the `baseURL`. + */ +- (void)setReachabilityStatusChangeBlock:(void (^)(AFNetworkReachabilityStatus status))block; + +@end + +///---------------- +/// @name Constants +///---------------- + +/** + ## Network Reachability + + The following constants are provided by `AFNetworkReachabilityManager` as possible network reachability statuses. + + enum { + AFNetworkReachabilityStatusUnknown, + AFNetworkReachabilityStatusNotReachable, + AFNetworkReachabilityStatusReachableViaWWAN, + AFNetworkReachabilityStatusReachableViaWiFi, + } + + `AFNetworkReachabilityStatusUnknown` + The `baseURL` host reachability is not known. + + `AFNetworkReachabilityStatusNotReachable` + The `baseURL` host cannot be reached. + + `AFNetworkReachabilityStatusReachableViaWWAN` + The `baseURL` host can be reached via a cellular connection, such as EDGE or GPRS. + + `AFNetworkReachabilityStatusReachableViaWiFi` + The `baseURL` host can be reached via a Wi-Fi connection. + + ### Keys for Notification UserInfo Dictionary + + Strings that are used as keys in a `userInfo` dictionary in a network reachability status change notification. + + `AFNetworkingReachabilityNotificationStatusItem` + A key in the userInfo dictionary in a `AFNetworkingReachabilityDidChangeNotification` notification. + The corresponding value is an `NSNumber` object representing the `AFNetworkReachabilityStatus` value for the current reachability status. + */ + +///-------------------- +/// @name Notifications +///-------------------- + +/** + Posted when network reachability changes. + This notification assigns no notification object. The `userInfo` dictionary contains an `NSNumber` object under the `AFNetworkingReachabilityNotificationStatusItem` key, representing the `AFNetworkReachabilityStatus` value for the current network reachability. + + @warning In order for network reachability to be monitored, include the `SystemConfiguration` framework in the active target's "Link Binary With Library" build phase, and add `#import ` to the header prefix of the project (`Prefix.pch`). + */ +extern NSString * const AFNetworkingReachabilityDidChangeNotification; +extern NSString * const AFNetworkingReachabilityNotificationStatusItem; + +///-------------------- +/// @name Functions +///-------------------- + +/** + Returns a localized string representation of an `AFNetworkReachabilityStatus` value. + */ +extern NSString * AFStringFromNetworkReachabilityStatus(AFNetworkReachabilityStatus status); diff --git a/ios/Pods/AFNetworking/AFNetworking/AFNetworkReachabilityManager.m b/ios/Pods/AFNetworking/AFNetworking/AFNetworkReachabilityManager.m new file mode 100644 index 000000000..71adaefa9 --- /dev/null +++ b/ios/Pods/AFNetworking/AFNetworking/AFNetworkReachabilityManager.m @@ -0,0 +1,253 @@ +// AFNetworkReachabilityManager.m +// +// Copyright (c) 2013-2014 AFNetworking (http://afnetworking.com) +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +#import "AFNetworkReachabilityManager.h" + +NSString * const AFNetworkingReachabilityDidChangeNotification = @"com.alamofire.networking.reachability.change"; +NSString * const AFNetworkingReachabilityNotificationStatusItem = @"AFNetworkingReachabilityNotificationStatusItem"; + +typedef void (^AFNetworkReachabilityStatusBlock)(AFNetworkReachabilityStatus status); + +typedef NS_ENUM(NSUInteger, AFNetworkReachabilityAssociation) { + AFNetworkReachabilityForAddress = 1, + AFNetworkReachabilityForAddressPair = 2, + AFNetworkReachabilityForName = 3, +}; + +NSString * AFStringFromNetworkReachabilityStatus(AFNetworkReachabilityStatus status) { + switch (status) { + case AFNetworkReachabilityStatusNotReachable: + return NSLocalizedStringFromTable(@"Not Reachable", @"AFNetworking", nil); + case AFNetworkReachabilityStatusReachableViaWWAN: + return NSLocalizedStringFromTable(@"Reachable via WWAN", @"AFNetworking", nil); + case AFNetworkReachabilityStatusReachableViaWiFi: + return NSLocalizedStringFromTable(@"Reachable via WiFi", @"AFNetworking", nil); + case AFNetworkReachabilityStatusUnknown: + default: + return NSLocalizedStringFromTable(@"Unknown", @"AFNetworking", nil); + } +} + +static AFNetworkReachabilityStatus AFNetworkReachabilityStatusForFlags(SCNetworkReachabilityFlags flags) { + BOOL isReachable = ((flags & kSCNetworkReachabilityFlagsReachable) != 0); + BOOL needsConnection = ((flags & kSCNetworkReachabilityFlagsConnectionRequired) != 0); + BOOL canConnectionAutomatically = (((flags & kSCNetworkReachabilityFlagsConnectionOnDemand ) != 0) || ((flags & kSCNetworkReachabilityFlagsConnectionOnTraffic) != 0)); + BOOL canConnectWithoutUserInteraction = (canConnectionAutomatically && (flags & kSCNetworkReachabilityFlagsInterventionRequired) == 0); + BOOL isNetworkReachable = (isReachable && (!needsConnection || canConnectWithoutUserInteraction)); + + AFNetworkReachabilityStatus status = AFNetworkReachabilityStatusUnknown; + if (isNetworkReachable == NO) { + status = AFNetworkReachabilityStatusNotReachable; + } +#if TARGET_OS_IPHONE + else if ((flags & kSCNetworkReachabilityFlagsIsWWAN) != 0) { + status = AFNetworkReachabilityStatusReachableViaWWAN; + } +#endif + else { + status = AFNetworkReachabilityStatusReachableViaWiFi; + } + + return status; +} + +static void AFNetworkReachabilityCallback(SCNetworkReachabilityRef __unused target, SCNetworkReachabilityFlags flags, void *info) { + AFNetworkReachabilityStatus status = AFNetworkReachabilityStatusForFlags(flags); + AFNetworkReachabilityStatusBlock block = (__bridge AFNetworkReachabilityStatusBlock)info; + if (block) { + block(status); + } + + + dispatch_async(dispatch_get_main_queue(), ^{ + NSNotificationCenter *notificationCenter = [NSNotificationCenter defaultCenter]; + [notificationCenter postNotificationName:AFNetworkingReachabilityDidChangeNotification object:nil userInfo:@{ AFNetworkingReachabilityNotificationStatusItem: @(status) }]; + }); + +} + +static const void * AFNetworkReachabilityRetainCallback(const void *info) { + return Block_copy(info); +} + +static void AFNetworkReachabilityReleaseCallback(const void *info) { + if (info) { + Block_release(info); + } +} + +@interface AFNetworkReachabilityManager () +@property (readwrite, nonatomic, assign) SCNetworkReachabilityRef networkReachability; +@property (readwrite, nonatomic, assign) AFNetworkReachabilityAssociation networkReachabilityAssociation; +@property (readwrite, nonatomic, assign) AFNetworkReachabilityStatus networkReachabilityStatus; +@property (readwrite, nonatomic, copy) AFNetworkReachabilityStatusBlock networkReachabilityStatusBlock; +@end + +@implementation AFNetworkReachabilityManager + ++ (instancetype)sharedManager { + static AFNetworkReachabilityManager *_sharedManager = nil; + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^{ + struct sockaddr_in address; + bzero(&address, sizeof(address)); + address.sin_len = sizeof(address); + address.sin_family = AF_INET; + + _sharedManager = [self managerForAddress:&address]; + }); + + return _sharedManager; +} + ++ (instancetype)managerForDomain:(NSString *)domain { + SCNetworkReachabilityRef reachability = SCNetworkReachabilityCreateWithName(kCFAllocatorDefault, [domain UTF8String]); + + AFNetworkReachabilityManager *manager = [[self alloc] initWithReachability:reachability]; + manager.networkReachabilityAssociation = AFNetworkReachabilityForName; + + return manager; +} + ++ (instancetype)managerForAddress:(const struct sockaddr_in *)address { + SCNetworkReachabilityRef reachability = SCNetworkReachabilityCreateWithAddress(kCFAllocatorDefault, (const struct sockaddr *)address); + + AFNetworkReachabilityManager *manager = [[self alloc] initWithReachability:reachability]; + manager.networkReachabilityAssociation = AFNetworkReachabilityForAddress; + + return manager; +} + +- (instancetype)initWithReachability:(SCNetworkReachabilityRef)reachability { + self = [super init]; + if (!self) { + return nil; + } + + self.networkReachability = reachability; + self.networkReachabilityStatus = AFNetworkReachabilityStatusUnknown; + + return self; +} + +- (void)dealloc { + [self stopMonitoring]; + + if (_networkReachability) { + CFRelease(_networkReachability); + _networkReachability = NULL; + } +} + +#pragma mark - + +- (BOOL)isReachable { + return [self isReachableViaWWAN] || [self isReachableViaWiFi]; +} + +- (BOOL)isReachableViaWWAN { + return self.networkReachabilityStatus == AFNetworkReachabilityStatusReachableViaWWAN; +} + +- (BOOL)isReachableViaWiFi { + return self.networkReachabilityStatus == AFNetworkReachabilityStatusReachableViaWiFi; +} + +#pragma mark - + +- (void)startMonitoring { + [self stopMonitoring]; + + if (!self.networkReachability) { + return; + } + + __weak __typeof(self)weakSelf = self; + AFNetworkReachabilityStatusBlock callback = ^(AFNetworkReachabilityStatus status) { + __strong __typeof(weakSelf)strongSelf = weakSelf; + + strongSelf.networkReachabilityStatus = status; + if (strongSelf.networkReachabilityStatusBlock) { + strongSelf.networkReachabilityStatusBlock(status); + } + + }; + + SCNetworkReachabilityContext context = {0, (__bridge void *)callback, AFNetworkReachabilityRetainCallback, AFNetworkReachabilityReleaseCallback, NULL}; + SCNetworkReachabilitySetCallback(self.networkReachability, AFNetworkReachabilityCallback, &context); + SCNetworkReachabilityScheduleWithRunLoop(self.networkReachability, CFRunLoopGetMain(), kCFRunLoopCommonModes); + + switch (self.networkReachabilityAssociation) { + case AFNetworkReachabilityForName: + break; + case AFNetworkReachabilityForAddress: + case AFNetworkReachabilityForAddressPair: + default: { + dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0),^{ + SCNetworkReachabilityFlags flags; + SCNetworkReachabilityGetFlags(self.networkReachability, &flags); + AFNetworkReachabilityStatus status = AFNetworkReachabilityStatusForFlags(flags); + dispatch_async(dispatch_get_main_queue(), ^{ + callback(status); + + NSNotificationCenter *notificationCenter = [NSNotificationCenter defaultCenter]; + [notificationCenter postNotificationName:AFNetworkingReachabilityDidChangeNotification object:nil userInfo:@{ AFNetworkingReachabilityNotificationStatusItem: @(status) }]; + + + }); + }); + } + break; + } +} + +- (void)stopMonitoring { + if (!self.networkReachability) { + return; + } + + SCNetworkReachabilityUnscheduleFromRunLoop(self.networkReachability, CFRunLoopGetMain(), kCFRunLoopCommonModes); +} + +#pragma mark - + +- (NSString *)localizedNetworkReachabilityStatusString { + return AFStringFromNetworkReachabilityStatus(self.networkReachabilityStatus); +} + +#pragma mark - + +- (void)setReachabilityStatusChangeBlock:(void (^)(AFNetworkReachabilityStatus status))block { + self.networkReachabilityStatusBlock = block; +} + +#pragma mark - NSKeyValueObserving + ++ (NSSet *)keyPathsForValuesAffectingValueForKey:(NSString *)key { + if ([key isEqualToString:@"reachable"] || [key isEqualToString:@"reachableViaWWAN"] || [key isEqualToString:@"reachableViaWiFi"]) { + return [NSSet setWithObject:@"networkReachabilityStatus"]; + } + + return [super keyPathsForValuesAffectingValueForKey:key]; +} + +@end diff --git a/ios/Pods/AFNetworking/AFNetworking/AFNetworking.h b/ios/Pods/AFNetworking/AFNetworking/AFNetworking.h new file mode 100644 index 000000000..68273da58 --- /dev/null +++ b/ios/Pods/AFNetworking/AFNetworking/AFNetworking.h @@ -0,0 +1,44 @@ +// AFNetworking.h +// +// Copyright (c) 2013 AFNetworking (http://afnetworking.com/) +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +#import +#import + +#ifndef _AFNETWORKING_ + #define _AFNETWORKING_ + + #import "AFURLRequestSerialization.h" + #import "AFURLResponseSerialization.h" + #import "AFSecurityPolicy.h" + #import "AFNetworkReachabilityManager.h" + + #import "AFURLConnectionOperation.h" + #import "AFHTTPRequestOperation.h" + #import "AFHTTPRequestOperationManager.h" + +#if ( ( defined(__MAC_OS_X_VERSION_MAX_ALLOWED) && __MAC_OS_X_VERSION_MAX_ALLOWED >= 1090) || \ + ( defined(__IPHONE_OS_VERSION_MAX_ALLOWED) && __IPHONE_OS_VERSION_MAX_ALLOWED >= 70000 ) ) + #import "AFURLSessionManager.h" + #import "AFHTTPSessionManager.h" +#endif + +#endif /* _AFNETWORKING_ */ diff --git a/ios/Pods/AFNetworking/AFNetworking/AFSecurityPolicy.h b/ios/Pods/AFNetworking/AFNetworking/AFSecurityPolicy.h new file mode 100644 index 000000000..b86e76b4d --- /dev/null +++ b/ios/Pods/AFNetworking/AFNetworking/AFSecurityPolicy.h @@ -0,0 +1,143 @@ +// AFSecurity.h +// +// Copyright (c) 2013-2014 AFNetworking (http://afnetworking.com) +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +#import +#import + +typedef NS_ENUM(NSUInteger, AFSSLPinningMode) { + AFSSLPinningModeNone, + AFSSLPinningModePublicKey, + AFSSLPinningModeCertificate, +}; + +/** + `AFSecurityPolicy` evaluates server trust against pinned X.509 certificates and public keys over secure connections. + + Adding pinned SSL certificates to your app helps prevent man-in-the-middle attacks and other vulnerabilities. Applications dealing with sensitive customer data or financial information are strongly encouraged to route all communication over an HTTPS connection with SSL pinning configured and enabled. + */ +@interface AFSecurityPolicy : NSObject + +/** + The criteria by which server trust should be evaluated against the pinned SSL certificates. Defaults to `AFSSLPinningModeNone`. + */ +@property (nonatomic, assign) AFSSLPinningMode SSLPinningMode; + +/** + Whether to evaluate an entire SSL certificate chain, or just the leaf certificate. Defaults to `YES`. + */ +@property (nonatomic, assign) BOOL validatesCertificateChain; + +/** + The certificates used to evaluate server trust according to the SSL pinning mode. By default, this property is set to any (`.cer`) certificates included in the app bundle. + */ +@property (nonatomic, strong) NSArray *pinnedCertificates; + +/** + Whether or not to trust servers with an invalid or expired SSL certificates. Defaults to `NO`. + */ +@property (nonatomic, assign) BOOL allowInvalidCertificates; + +/** + Whether or not to validate the domain name in the certificates CN field. Defaults to `YES` for `AFSSLPinningModePublicKey` or `AFSSLPinningModeCertificate`, otherwise `NO`. + */ +@property (nonatomic, assign) BOOL validatesDomainName; + +///----------------------------------------- +/// @name Getting Specific Security Policies +///----------------------------------------- + +/** + Returns the shared default security policy, which does not accept invalid certificates, and does not validate against pinned certificates or public keys. + + @return The default security policy. + */ ++ (instancetype)defaultPolicy; + +///--------------------- +/// @name Initialization +///--------------------- + +/** + Creates and returns a security policy with the specified pinning mode. + + @param pinningMode The SSL pinning mode. + + @return A new security policy. + */ ++ (instancetype)policyWithPinningMode:(AFSSLPinningMode)pinningMode; + +///------------------------------ +/// @name Evaluating Server Trust +///------------------------------ + +/** + Whether or not the specified server trust should be accepted, based on the security policy. + + This method should be used when responding to an authentication challenge from a server. + + @param serverTrust The X.509 certificate trust of the server. + + @return Whether or not to trust the server. + + @warning This method has been deprecated in favor of `-evaluateServerTrust:forDomain:`. + */ +- (BOOL)evaluateServerTrust:(SecTrustRef)serverTrust DEPRECATED_ATTRIBUTE; + +/** + Whether or not the specified server trust should be accepted, based on the security policy. + + This method should be used when responding to an authentication challenge from a server. + + @param serverTrust The X.509 certificate trust of the server. + @param domain The domain of serverTrust. If `nil`, the domain will not be validated. + + @return Whether or not to trust the server. + */ +- (BOOL)evaluateServerTrust:(SecTrustRef)serverTrust + forDomain:(NSString *)domain; + +@end + +///---------------- +/// @name Constants +///---------------- + +/** + ## SSL Pinning Modes + + The following constants are provided by `AFSSLPinningMode` as possible SSL pinning modes. + + enum { + AFSSLPinningModeNone, + AFSSLPinningModePublicKey, + AFSSLPinningModeCertificate, + } + + `AFSSLPinningModeNone` + Do not used pinned certificates to validate servers. + + `AFSSLPinningModePublicKey` + Validate host certificates against public keys of pinned certificates. + + `AFSSLPinningModeCertificate` + Validate host certificates against pinned certificates. +*/ diff --git a/ios/Pods/AFNetworking/AFNetworking/AFSecurityPolicy.m b/ios/Pods/AFNetworking/AFNetworking/AFSecurityPolicy.m new file mode 100644 index 000000000..f11caaa63 --- /dev/null +++ b/ios/Pods/AFNetworking/AFNetworking/AFSecurityPolicy.m @@ -0,0 +1,320 @@ +// AFSecurity.m +// +// Copyright (c) 2013-2014 AFNetworking (http://afnetworking.com) +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +#import "AFSecurityPolicy.h" + +// Equivalent of macro in , without causing compiler warning: +// "'DebugAssert' is deprecated: first deprecated in OS X 10.8" +#ifndef AF_Require + #define AF_Require(assertion, exceptionLabel) \ + do { \ + if (__builtin_expect(!(assertion), 0)) { \ + goto exceptionLabel; \ + } \ + } while (0) +#endif + +#ifndef AF_Require_noErr + #define AF_Require_noErr(errorCode, exceptionLabel) \ + do { \ + if (__builtin_expect(0 != (errorCode), 0)) { \ + goto exceptionLabel; \ + } \ + } while (0) +#endif + +#if !defined(__IPHONE_OS_VERSION_MIN_REQUIRED) +static NSData * AFSecKeyGetData(SecKeyRef key) { + CFDataRef data = NULL; + + AF_Require_noErr(SecItemExport(key, kSecFormatUnknown, kSecItemPemArmour, NULL, &data), _out); + + return (__bridge_transfer NSData *)data; + +_out: + if (data) { + CFRelease(data); + } + + return nil; +} +#endif + +static BOOL AFSecKeyIsEqualToKey(SecKeyRef key1, SecKeyRef key2) { +#if defined(__IPHONE_OS_VERSION_MIN_REQUIRED) + return [(__bridge id)key1 isEqual:(__bridge id)key2]; +#else + return [AFSecKeyGetData(key1) isEqual:AFSecKeyGetData(key2)]; +#endif +} + +static id AFPublicKeyForCertificate(NSData *certificate) { + id allowedPublicKey = nil; + SecCertificateRef allowedCertificate; + SecCertificateRef allowedCertificates[1]; + CFArrayRef tempCertificates = nil; + SecPolicyRef policy = nil; + SecTrustRef allowedTrust = nil; + SecTrustResultType result; + + allowedCertificate = SecCertificateCreateWithData(NULL, (__bridge CFDataRef)certificate); + AF_Require(allowedCertificate != NULL, _out); + + allowedCertificates[0] = allowedCertificate; + tempCertificates = CFArrayCreate(NULL, (const void **)allowedCertificates, 1, NULL); + + policy = SecPolicyCreateBasicX509(); + AF_Require_noErr(SecTrustCreateWithCertificates(tempCertificates, policy, &allowedTrust), _out); + AF_Require_noErr(SecTrustEvaluate(allowedTrust, &result), _out); + + allowedPublicKey = (__bridge_transfer id)SecTrustCopyPublicKey(allowedTrust); + +_out: + if (allowedTrust) { + CFRelease(allowedTrust); + } + + if (policy) { + CFRelease(policy); + } + + if (tempCertificates) { + CFRelease(tempCertificates); + } + + if (allowedCertificate) { + CFRelease(allowedCertificate); + } + + return allowedPublicKey; +} + +static BOOL AFServerTrustIsValid(SecTrustRef serverTrust) { + BOOL isValid = NO; + SecTrustResultType result; + AF_Require_noErr(SecTrustEvaluate(serverTrust, &result), _out); + + isValid = (result == kSecTrustResultUnspecified || result == kSecTrustResultProceed); + +_out: + return isValid; +} + +static NSArray * AFCertificateTrustChainForServerTrust(SecTrustRef serverTrust) { + CFIndex certificateCount = SecTrustGetCertificateCount(serverTrust); + NSMutableArray *trustChain = [NSMutableArray arrayWithCapacity:(NSUInteger)certificateCount]; + + for (CFIndex i = 0; i < certificateCount; i++) { + SecCertificateRef certificate = SecTrustGetCertificateAtIndex(serverTrust, i); + [trustChain addObject:(__bridge_transfer NSData *)SecCertificateCopyData(certificate)]; + } + + return [NSArray arrayWithArray:trustChain]; +} + +static NSArray * AFPublicKeyTrustChainForServerTrust(SecTrustRef serverTrust) { + SecPolicyRef policy = SecPolicyCreateBasicX509(); + CFIndex certificateCount = SecTrustGetCertificateCount(serverTrust); + NSMutableArray *trustChain = [NSMutableArray arrayWithCapacity:(NSUInteger)certificateCount]; + for (CFIndex i = 0; i < certificateCount; i++) { + SecCertificateRef certificate = SecTrustGetCertificateAtIndex(serverTrust, i); + + SecCertificateRef someCertificates[] = {certificate}; + CFArrayRef certificates = CFArrayCreate(NULL, (const void **)someCertificates, 1, NULL); + + SecTrustRef trust; + AF_Require_noErr(SecTrustCreateWithCertificates(certificates, policy, &trust), _out); + + SecTrustResultType result; + AF_Require_noErr(SecTrustEvaluate(trust, &result), _out); + + [trustChain addObject:(__bridge_transfer id)SecTrustCopyPublicKey(trust)]; + + _out: + if (trust) { + CFRelease(trust); + } + + if (certificates) { + CFRelease(certificates); + } + + continue; + } + CFRelease(policy); + + return [NSArray arrayWithArray:trustChain]; +} + +#pragma mark - + +@interface AFSecurityPolicy() +@property (readwrite, nonatomic, strong) NSArray *pinnedPublicKeys; +@end + +@implementation AFSecurityPolicy + ++ (NSArray *)defaultPinnedCertificates { + static NSArray *_defaultPinnedCertificates = nil; + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^{ + NSBundle *bundle = [NSBundle bundleForClass:[self class]]; + NSArray *paths = [bundle pathsForResourcesOfType:@"cer" inDirectory:@"."]; + + NSMutableArray *certificates = [NSMutableArray arrayWithCapacity:[paths count]]; + for (NSString *path in paths) { + NSData *certificateData = [NSData dataWithContentsOfFile:path]; + [certificates addObject:certificateData]; + } + + _defaultPinnedCertificates = [[NSArray alloc] initWithArray:certificates]; + }); + + return _defaultPinnedCertificates; +} + ++ (instancetype)defaultPolicy { + AFSecurityPolicy *securityPolicy = [[self alloc] init]; + securityPolicy.SSLPinningMode = AFSSLPinningModeNone; + + return securityPolicy; +} + ++ (instancetype)policyWithPinningMode:(AFSSLPinningMode)pinningMode { + AFSecurityPolicy *securityPolicy = [[self alloc] init]; + securityPolicy.SSLPinningMode = pinningMode; + securityPolicy.validatesDomainName = YES; + [securityPolicy setPinnedCertificates:[self defaultPinnedCertificates]]; + + return securityPolicy; +} + +- (id)init { + self = [super init]; + if (!self) { + return nil; + } + + self.validatesCertificateChain = YES; + + return self; +} + +#pragma mark - + +- (void)setPinnedCertificates:(NSArray *)pinnedCertificates { + _pinnedCertificates = pinnedCertificates; + + if (self.pinnedCertificates) { + NSMutableArray *mutablePinnedPublicKeys = [NSMutableArray arrayWithCapacity:[self.pinnedCertificates count]]; + for (NSData *certificate in self.pinnedCertificates) { + id publicKey = AFPublicKeyForCertificate(certificate); + if (!publicKey) { + continue; + } + [mutablePinnedPublicKeys addObject:publicKey]; + } + self.pinnedPublicKeys = [NSArray arrayWithArray:mutablePinnedPublicKeys]; + } else { + self.pinnedPublicKeys = nil; + } +} + +#pragma mark - + +- (BOOL)evaluateServerTrust:(SecTrustRef)serverTrust { + return [self evaluateServerTrust:serverTrust forDomain:nil]; +} + +- (BOOL)evaluateServerTrust:(SecTrustRef)serverTrust + forDomain:(NSString *)domain +{ + NSMutableArray *policies = [NSMutableArray array]; + if (self.validatesDomainName) { + [policies addObject:(__bridge_transfer id)SecPolicyCreateSSL(true, (__bridge CFStringRef)domain)]; + } else { + [policies addObject:(__bridge_transfer id)SecPolicyCreateBasicX509()]; + } + + SecTrustSetPolicies(serverTrust, (__bridge CFArrayRef)policies); + + if (!AFServerTrustIsValid(serverTrust) && !self.allowInvalidCertificates) { + return NO; + } + + NSArray *serverCertificates = AFCertificateTrustChainForServerTrust(serverTrust); + switch (self.SSLPinningMode) { + case AFSSLPinningModeNone: + return YES; + case AFSSLPinningModeCertificate: { + NSMutableArray *pinnedCertificates = [NSMutableArray array]; + for (NSData *certificateData in self.pinnedCertificates) { + [pinnedCertificates addObject:(__bridge_transfer id)SecCertificateCreateWithData(NULL, (__bridge CFDataRef)certificateData)]; + } + SecTrustSetAnchorCertificates(serverTrust, (__bridge CFArrayRef)pinnedCertificates); + + if (!AFServerTrustIsValid(serverTrust)) { + return NO; + } + + if (!self.validatesCertificateChain) { + return YES; + } + + NSUInteger trustedCertificateCount = 0; + for (NSData *trustChainCertificate in serverCertificates) { + if ([self.pinnedCertificates containsObject:trustChainCertificate]) { + trustedCertificateCount++; + } + } + + return trustedCertificateCount == [serverCertificates count]; + } + case AFSSLPinningModePublicKey: { + NSUInteger trustedPublicKeyCount = 0; + NSArray *publicKeys = AFPublicKeyTrustChainForServerTrust(serverTrust); + if (!self.validatesCertificateChain && [publicKeys count] > 0) { + publicKeys = @[[publicKeys firstObject]]; + } + + for (id trustChainPublicKey in publicKeys) { + for (id pinnedPublicKey in self.pinnedPublicKeys) { + if (AFSecKeyIsEqualToKey((__bridge SecKeyRef)trustChainPublicKey, (__bridge SecKeyRef)pinnedPublicKey)) { + trustedPublicKeyCount += 1; + } + } + } + + return trustedPublicKeyCount > 0 && ((self.validatesCertificateChain && trustedPublicKeyCount == [serverCertificates count]) || (!self.validatesCertificateChain && trustedPublicKeyCount >= 1)); + } + } + + return NO; +} + +#pragma mark - NSKeyValueObserving + ++ (NSSet *)keyPathsForValuesAffectingPinnedPublicKeys { + return [NSSet setWithObject:@"pinnedCertificates"]; +} + +@end diff --git a/ios/Pods/AFNetworking/AFNetworking/AFURLConnectionOperation.h b/ios/Pods/AFNetworking/AFNetworking/AFURLConnectionOperation.h new file mode 100644 index 000000000..9fbc5d23b --- /dev/null +++ b/ios/Pods/AFNetworking/AFNetworking/AFURLConnectionOperation.h @@ -0,0 +1,328 @@ +// AFURLConnectionOperation.h +// +// Copyright (c) 2013-2014 AFNetworking (http://afnetworking.com) +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. +#define _AFNETWORKING_ALLOW_INVALID_SSL_CERTIFICATES_ +#import + +#import +#import "AFURLRequestSerialization.h" +#import "AFURLResponseSerialization.h" +#import "AFSecurityPolicy.h" + +/** + `AFURLConnectionOperation` is a subclass of `NSOperation` that implements `NSURLConnection` delegate methods. + + ## Subclassing Notes + + This is the base class of all network request operations. You may wish to create your own subclass in order to implement additional `NSURLConnection` delegate methods (see "`NSURLConnection` Delegate Methods" below), or to provide additional properties and/or class constructors. + + If you are creating a subclass that communicates over the HTTP or HTTPS protocols, you may want to consider subclassing `AFHTTPRequestOperation` instead, as it supports specifying acceptable content types or status codes. + + ## NSURLConnection Delegate Methods + + `AFURLConnectionOperation` implements the following `NSURLConnection` delegate methods: + + - `connection:didReceiveResponse:` + - `connection:didReceiveData:` + - `connectionDidFinishLoading:` + - `connection:didFailWithError:` + - `connection:didSendBodyData:totalBytesWritten:totalBytesExpectedToWrite:` + - `connection:willCacheResponse:` + - `connectionShouldUseCredentialStorage:` + - `connection:needNewBodyStream:` + - `connection:willSendRequestForAuthenticationChallenge:` + + If any of these methods are overridden in a subclass, they _must_ call the `super` implementation first. + + ## Callbacks and Completion Blocks + + The built-in `completionBlock` provided by `NSOperation` allows for custom behavior to be executed after the request finishes. It is a common pattern for class constructors in subclasses to take callback block parameters, and execute them conditionally in the body of its `completionBlock`. Make sure to handle cancelled operations appropriately when setting a `completionBlock` (i.e. returning early before parsing response data). See the implementation of any of the `AFHTTPRequestOperation` subclasses for an example of this. + + Subclasses are strongly discouraged from overriding `setCompletionBlock:`, as `AFURLConnectionOperation`'s implementation includes a workaround to mitigate retain cycles, and what Apple rather ominously refers to as ["The Deallocation Problem"](http://developer.apple.com/library/ios/#technotes/tn2109/). + + ## SSL Pinning + + Relying on the CA trust model to validate SSL certificates exposes your app to security vulnerabilities, such as man-in-the-middle attacks. For applications that connect to known servers, SSL certificate pinning provides an increased level of security, by checking server certificate validity against those specified in the app bundle. + + SSL with certificate pinning is strongly recommended for any application that transmits sensitive information to an external webservice. + + Connections will be validated on all matching certificates with a `.cer` extension in the bundle root. + + ## App Extensions + + When using AFNetworking in an App Extension, `#define AF_APP_EXTENSIONS` to avoid using unavailable APIs. + + ## NSCoding & NSCopying Conformance + + `AFURLConnectionOperation` conforms to the `NSCoding` and `NSCopying` protocols, allowing operations to be archived to disk, and copied in memory, respectively. However, because of the intrinsic limitations of capturing the exact state of an operation at a particular moment, there are some important caveats to keep in mind: + + ### NSCoding Caveats + + - Encoded operations do not include any block or stream properties. Be sure to set `completionBlock`, `outputStream`, and any callback blocks as necessary when using `-initWithCoder:` or `NSKeyedUnarchiver`. + - Operations are paused on `encodeWithCoder:`. If the operation was encoded while paused or still executing, its archived state will return `YES` for `isReady`. Otherwise, the state of an operation when encoding will remain unchanged. + + ### NSCopying Caveats + + - `-copy` and `-copyWithZone:` return a new operation with the `NSURLRequest` of the original. So rather than an exact copy of the operation at that particular instant, the copying mechanism returns a completely new instance, which can be useful for retrying operations. + - A copy of an operation will not include the `outputStream` of the original. + - Operation copies do not include `completionBlock`, as it often strongly captures a reference to `self`, which would otherwise have the unintuitive side-effect of pointing to the _original_ operation when copied. + */ + +@interface AFURLConnectionOperation : NSOperation + +///------------------------------- +/// @name Accessing Run Loop Modes +///------------------------------- + +/** + The run loop modes in which the operation will run on the network thread. By default, this is a single-member set containing `NSRunLoopCommonModes`. + */ +@property (nonatomic, strong) NSSet *runLoopModes; + +///----------------------------------------- +/// @name Getting URL Connection Information +///----------------------------------------- + +/** + The request used by the operation's connection. + */ +@property (readonly, nonatomic, strong) NSURLRequest *request; + +/** + The last response received by the operation's connection. + */ +@property (readonly, nonatomic, strong) NSURLResponse *response; + +/** + The error, if any, that occurred in the lifecycle of the request. + */ +@property (readonly, nonatomic, strong) NSError *error; + +///---------------------------- +/// @name Getting Response Data +///---------------------------- + +/** + The data received during the request. + */ +@property (readonly, nonatomic, strong) NSData *responseData; + +/** + The string representation of the response data. + */ +@property (readonly, nonatomic, copy) NSString *responseString; + +/** + The string encoding of the response. + + If the response does not specify a valid string encoding, `responseStringEncoding` will return `NSUTF8StringEncoding`. + */ +@property (readonly, nonatomic, assign) NSStringEncoding responseStringEncoding; + +///------------------------------- +/// @name Managing URL Credentials +///------------------------------- + +/** + Whether the URL connection should consult the credential storage for authenticating the connection. `YES` by default. + + This is the value that is returned in the `NSURLConnectionDelegate` method `-connectionShouldUseCredentialStorage:`. + */ +@property (nonatomic, assign) BOOL shouldUseCredentialStorage; + +/** + The credential used for authentication challenges in `-connection:didReceiveAuthenticationChallenge:`. + + This will be overridden by any shared credentials that exist for the username or password of the request URL, if present. + */ +@property (nonatomic, strong) NSURLCredential *credential; + +///------------------------------- +/// @name Managing Security Policy +///------------------------------- + +/** + The security policy used to evaluate server trust for secure connections. + */ +@property (nonatomic, strong) AFSecurityPolicy *securityPolicy; + +///------------------------ +/// @name Accessing Streams +///------------------------ + +/** + The input stream used to read data to be sent during the request. + + This property acts as a proxy to the `HTTPBodyStream` property of `request`. + */ +@property (nonatomic, strong) NSInputStream *inputStream; + +/** + The output stream that is used to write data received until the request is finished. + + By default, data is accumulated into a buffer that is stored into `responseData` upon completion of the request, with the intermediary `outputStream` property set to `nil`. When `outputStream` is set, the data will not be accumulated into an internal buffer, and as a result, the `responseData` property of the completed request will be `nil`. The output stream will be scheduled in the network thread runloop upon being set. + */ +@property (nonatomic, strong) NSOutputStream *outputStream; + +///--------------------------------- +/// @name Managing Callback Queues +///--------------------------------- + +/** + The dispatch queue for `completionBlock`. If `NULL` (default), the main queue is used. + */ +@property (nonatomic, strong) dispatch_queue_t completionQueue; + +/** + The dispatch group for `completionBlock`. If `NULL` (default), a private dispatch group is used. + */ +@property (nonatomic, strong) dispatch_group_t completionGroup; + +///--------------------------------------------- +/// @name Managing Request Operation Information +///--------------------------------------------- + +/** + The user info dictionary for the receiver. + */ +@property (nonatomic, strong) NSDictionary *userInfo; + +///------------------------------------------------------ +/// @name Initializing an AFURLConnectionOperation Object +///------------------------------------------------------ + +/** + Initializes and returns a newly allocated operation object with a url connection configured with the specified url request. + + This is the designated initializer. + + @param urlRequest The request object to be used by the operation connection. + */ +- (instancetype)initWithRequest:(NSURLRequest *)urlRequest; + +///---------------------------------- +/// @name Pausing / Resuming Requests +///---------------------------------- + +/** + Pauses the execution of the request operation. + + A paused operation returns `NO` for `-isReady`, `-isExecuting`, and `-isFinished`. As such, it will remain in an `NSOperationQueue` until it is either cancelled or resumed. Pausing a finished, cancelled, or paused operation has no effect. + */ +- (void)pause; + +/** + Whether the request operation is currently paused. + + @return `YES` if the operation is currently paused, otherwise `NO`. + */ +- (BOOL)isPaused; + +/** + Resumes the execution of the paused request operation. + + Pause/Resume behavior varies depending on the underlying implementation for the operation class. In its base implementation, resuming a paused requests restarts the original request. However, since HTTP defines a specification for how to request a specific content range, `AFHTTPRequestOperation` will resume downloading the request from where it left off, instead of restarting the original request. + */ +- (void)resume; + +///---------------------------------------------- +/// @name Configuring Backgrounding Task Behavior +///---------------------------------------------- + +/** + Specifies that the operation should continue execution after the app has entered the background, and the expiration handler for that background task. + + @param handler A handler to be called shortly before the application’s remaining background time reaches 0. The handler is wrapped in a block that cancels the operation, and cleans up and marks the end of execution, unlike the `handler` parameter in `UIApplication -beginBackgroundTaskWithExpirationHandler:`, which expects this to be done in the handler itself. The handler is called synchronously on the main thread, thus blocking the application’s suspension momentarily while the application is notified. + */ +#if defined(__IPHONE_OS_VERSION_MIN_REQUIRED) && !defined(AF_APP_EXTENSIONS) +- (void)setShouldExecuteAsBackgroundTaskWithExpirationHandler:(void (^)(void))handler; +#endif + +///--------------------------------- +/// @name Setting Progress Callbacks +///--------------------------------- + +/** + Sets a callback to be called when an undetermined number of bytes have been uploaded to the server. + + @param block A block object to be called when an undetermined number of bytes have been uploaded to the server. This block has no return value and takes three arguments: the number of bytes written since the last time the upload progress block was called, the total bytes written, and the total bytes expected to be written during the request, as initially determined by the length of the HTTP body. This block may be called multiple times, and will execute on the main thread. + */ +- (void)setUploadProgressBlock:(void (^)(NSUInteger bytesWritten, long long totalBytesWritten, long long totalBytesExpectedToWrite))block; + +/** + Sets a callback to be called when an undetermined number of bytes have been downloaded from the server. + + @param block A block object to be called when an undetermined number of bytes have been downloaded from the server. This block has no return value and takes three arguments: the number of bytes read since the last time the download progress block was called, the total bytes read, and the total bytes expected to be read during the request, as initially determined by the expected content size of the `NSHTTPURLResponse` object. This block may be called multiple times, and will execute on the main thread. + */ +- (void)setDownloadProgressBlock:(void (^)(NSUInteger bytesRead, long long totalBytesRead, long long totalBytesExpectedToRead))block; + +///------------------------------------------------- +/// @name Setting NSURLConnection Delegate Callbacks +///------------------------------------------------- + +/** + Sets a block to be executed when the connection will authenticate a challenge in order to download its request, as handled by the `NSURLConnectionDelegate` method `connection:willSendRequestForAuthenticationChallenge:`. + + @param block A block object to be executed when the connection will authenticate a challenge in order to download its request. The block has no return type and takes two arguments: the URL connection object, and the challenge that must be authenticated. This block must invoke one of the challenge-responder methods (NSURLAuthenticationChallengeSender protocol). + + If `allowsInvalidSSLCertificate` is set to YES, `connection:willSendRequestForAuthenticationChallenge:` will attempt to have the challenge sender use credentials with invalid SSL certificates. + */ +- (void)setWillSendRequestForAuthenticationChallengeBlock:(void (^)(NSURLConnection *connection, NSURLAuthenticationChallenge *challenge))block; + +/** + Sets a block to be executed when the server redirects the request from one URL to another URL, or when the request URL changed by the `NSURLProtocol` subclass handling the request in order to standardize its format, as handled by the `NSURLConnectionDataDelegate` method `connection:willSendRequest:redirectResponse:`. + + @param block A block object to be executed when the request URL was changed. The block returns an `NSURLRequest` object, the URL request to redirect, and takes three arguments: the URL connection object, the the proposed redirected request, and the URL response that caused the redirect. + */ +- (void)setRedirectResponseBlock:(NSURLRequest * (^)(NSURLConnection *connection, NSURLRequest *request, NSURLResponse *redirectResponse))block; + + +/** + Sets a block to be executed to modify the response a connection will cache, if any, as handled by the `NSURLConnectionDelegate` method `connection:willCacheResponse:`. + + @param block A block object to be executed to determine what response a connection will cache, if any. The block returns an `NSCachedURLResponse` object, the cached response to store in memory or `nil` to prevent the response from being cached, and takes two arguments: the URL connection object, and the cached response provided for the request. + */ +- (void)setCacheResponseBlock:(NSCachedURLResponse * (^)(NSURLConnection *connection, NSCachedURLResponse *cachedResponse))block; + +/// + +/** + + */ ++ (NSArray *)batchOfRequestOperations:(NSArray *)operations + progressBlock:(void (^)(NSUInteger numberOfFinishedOperations, NSUInteger totalNumberOfOperations))progressBlock + completionBlock:(void (^)(NSArray *operations))completionBlock; + +@end + +///-------------------- +/// @name Notifications +///-------------------- + +/** + Posted when an operation begins executing. + */ +extern NSString * const AFNetworkingOperationDidStartNotification; + +/** + Posted when an operation finishes. + */ +extern NSString * const AFNetworkingOperationDidFinishNotification; diff --git a/ios/Pods/AFNetworking/AFNetworking/AFURLConnectionOperation.m b/ios/Pods/AFNetworking/AFNetworking/AFURLConnectionOperation.m new file mode 100644 index 000000000..e5e6839a8 --- /dev/null +++ b/ios/Pods/AFNetworking/AFNetworking/AFURLConnectionOperation.m @@ -0,0 +1,789 @@ +// AFURLConnectionOperation.m +// +// Copyright (c) 2013-2014 AFNetworking (http://afnetworking.com) +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +#import "AFURLConnectionOperation.h" + +#if defined(__IPHONE_OS_VERSION_MIN_REQUIRED) +#import +#endif + +#if !__has_feature(objc_arc) +#error AFNetworking must be built with ARC. +// You can turn on ARC for only AFNetworking files by adding -fobjc-arc to the build phase for each of its files. +#endif + +typedef NS_ENUM(NSInteger, AFOperationState) { + AFOperationPausedState = -1, + AFOperationReadyState = 1, + AFOperationExecutingState = 2, + AFOperationFinishedState = 3, +}; + +#if defined(__IPHONE_OS_VERSION_MIN_REQUIRED) && !defined(AF_APP_EXTENSIONS) +typedef UIBackgroundTaskIdentifier AFBackgroundTaskIdentifier; +#else +typedef id AFBackgroundTaskIdentifier; +#endif + +static dispatch_group_t url_request_operation_completion_group() { + static dispatch_group_t af_url_request_operation_completion_group; + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^{ + af_url_request_operation_completion_group = dispatch_group_create(); + }); + + return af_url_request_operation_completion_group; +} + +static dispatch_queue_t url_request_operation_completion_queue() { + static dispatch_queue_t af_url_request_operation_completion_queue; + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^{ + af_url_request_operation_completion_queue = dispatch_queue_create("com.alamofire.networking.operation.queue", DISPATCH_QUEUE_CONCURRENT ); + }); + + return af_url_request_operation_completion_queue; +} + +static NSString * const kAFNetworkingLockName = @"com.alamofire.networking.operation.lock"; + +NSString * const AFNetworkingOperationDidStartNotification = @"com.alamofire.networking.operation.start"; +NSString * const AFNetworkingOperationDidFinishNotification = @"com.alamofire.networking.operation.finish"; + +typedef void (^AFURLConnectionOperationProgressBlock)(NSUInteger bytes, long long totalBytes, long long totalBytesExpected); +typedef void (^AFURLConnectionOperationAuthenticationChallengeBlock)(NSURLConnection *connection, NSURLAuthenticationChallenge *challenge); +typedef NSCachedURLResponse * (^AFURLConnectionOperationCacheResponseBlock)(NSURLConnection *connection, NSCachedURLResponse *cachedResponse); +typedef NSURLRequest * (^AFURLConnectionOperationRedirectResponseBlock)(NSURLConnection *connection, NSURLRequest *request, NSURLResponse *redirectResponse); + +static inline NSString * AFKeyPathFromOperationState(AFOperationState state) { + switch (state) { + case AFOperationReadyState: + return @"isReady"; + case AFOperationExecutingState: + return @"isExecuting"; + case AFOperationFinishedState: + return @"isFinished"; + case AFOperationPausedState: + return @"isPaused"; + default: { +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wunreachable-code" + return @"state"; +#pragma clang diagnostic pop + } + } +} + +static inline BOOL AFStateTransitionIsValid(AFOperationState fromState, AFOperationState toState, BOOL isCancelled) { + switch (fromState) { + case AFOperationReadyState: + switch (toState) { + case AFOperationPausedState: + case AFOperationExecutingState: + return YES; + case AFOperationFinishedState: + return isCancelled; + default: + return NO; + } + case AFOperationExecutingState: + switch (toState) { + case AFOperationPausedState: + case AFOperationFinishedState: + return YES; + default: + return NO; + } + case AFOperationFinishedState: + return NO; + case AFOperationPausedState: + return toState == AFOperationReadyState; + default: { +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wunreachable-code" + switch (toState) { + case AFOperationPausedState: + case AFOperationReadyState: + case AFOperationExecutingState: + case AFOperationFinishedState: + return YES; + default: + return NO; + } + } +#pragma clang diagnostic pop + } +} + +@interface AFURLConnectionOperation () +@property (readwrite, nonatomic, assign) AFOperationState state; +@property (readwrite, nonatomic, strong) NSRecursiveLock *lock; +@property (readwrite, nonatomic, strong) NSURLConnection *connection; +@property (readwrite, nonatomic, strong) NSURLRequest *request; +@property (readwrite, nonatomic, strong) NSURLResponse *response; +@property (readwrite, nonatomic, strong) NSError *error; +@property (readwrite, nonatomic, strong) NSData *responseData; +@property (readwrite, nonatomic, copy) NSString *responseString; +@property (readwrite, nonatomic, assign) NSStringEncoding responseStringEncoding; +@property (readwrite, nonatomic, assign) long long totalBytesRead; +@property (readwrite, nonatomic, assign) AFBackgroundTaskIdentifier backgroundTaskIdentifier; +@property (readwrite, nonatomic, copy) AFURLConnectionOperationProgressBlock uploadProgress; +@property (readwrite, nonatomic, copy) AFURLConnectionOperationProgressBlock downloadProgress; +@property (readwrite, nonatomic, copy) AFURLConnectionOperationAuthenticationChallengeBlock authenticationChallenge; +@property (readwrite, nonatomic, copy) AFURLConnectionOperationCacheResponseBlock cacheResponse; +@property (readwrite, nonatomic, copy) AFURLConnectionOperationRedirectResponseBlock redirectResponse; + +- (void)operationDidStart; +- (void)finish; +- (void)cancelConnection; +@end + +@implementation AFURLConnectionOperation +@synthesize outputStream = _outputStream; + ++ (void)networkRequestThreadEntryPoint:(id)__unused object { + @autoreleasepool { + [[NSThread currentThread] setName:@"AFNetworking"]; + + NSRunLoop *runLoop = [NSRunLoop currentRunLoop]; + [runLoop addPort:[NSMachPort port] forMode:NSDefaultRunLoopMode]; + [runLoop run]; + } +} + ++ (NSThread *)networkRequestThread { + static NSThread *_networkRequestThread = nil; + static dispatch_once_t oncePredicate; + dispatch_once(&oncePredicate, ^{ + _networkRequestThread = [[NSThread alloc] initWithTarget:self selector:@selector(networkRequestThreadEntryPoint:) object:nil]; + [_networkRequestThread start]; + }); + + return _networkRequestThread; +} + +- (instancetype)initWithRequest:(NSURLRequest *)urlRequest { + NSParameterAssert(urlRequest); + + self = [super init]; + if (!self) { + return nil; + } + + _state = AFOperationReadyState; + + self.lock = [[NSRecursiveLock alloc] init]; + self.lock.name = kAFNetworkingLockName; + + self.runLoopModes = [NSSet setWithObject:NSRunLoopCommonModes]; + + self.request = urlRequest; + + self.shouldUseCredentialStorage = YES; + + self.securityPolicy = [AFSecurityPolicy defaultPolicy]; + + return self; +} + +- (void)dealloc { + if (_outputStream) { + [_outputStream close]; + _outputStream = nil; + } + +#if defined(__IPHONE_OS_VERSION_MIN_REQUIRED) && !defined(AF_APP_EXTENSIONS) + if (_backgroundTaskIdentifier) { + [[UIApplication sharedApplication] endBackgroundTask:_backgroundTaskIdentifier]; + _backgroundTaskIdentifier = UIBackgroundTaskInvalid; + } +#endif +} + +#pragma mark - + +- (void)setResponseData:(NSData *)responseData { + [self.lock lock]; + if (!responseData) { + _responseData = nil; + } else { + _responseData = [NSData dataWithBytes:responseData.bytes length:responseData.length]; + } + [self.lock unlock]; +} + +- (NSString *)responseString { + [self.lock lock]; + if (!_responseString && self.response && self.responseData) { + self.responseString = [[NSString alloc] initWithData:self.responseData encoding:self.responseStringEncoding]; + } + [self.lock unlock]; + + return _responseString; +} + +- (NSStringEncoding)responseStringEncoding { + [self.lock lock]; + if (!_responseStringEncoding && self.response) { + NSStringEncoding stringEncoding = NSUTF8StringEncoding; + if (self.response.textEncodingName) { + CFStringEncoding IANAEncoding = CFStringConvertIANACharSetNameToEncoding((__bridge CFStringRef)self.response.textEncodingName); + if (IANAEncoding != kCFStringEncodingInvalidId) { + stringEncoding = CFStringConvertEncodingToNSStringEncoding(IANAEncoding); + } + } + + self.responseStringEncoding = stringEncoding; + } + [self.lock unlock]; + + return _responseStringEncoding; +} + +- (NSInputStream *)inputStream { + return self.request.HTTPBodyStream; +} + +- (void)setInputStream:(NSInputStream *)inputStream { + NSMutableURLRequest *mutableRequest = [self.request mutableCopy]; + mutableRequest.HTTPBodyStream = inputStream; + self.request = mutableRequest; +} + +- (NSOutputStream *)outputStream { + if (!_outputStream) { + self.outputStream = [NSOutputStream outputStreamToMemory]; + } + + return _outputStream; +} + +- (void)setOutputStream:(NSOutputStream *)outputStream { + [self.lock lock]; + if (outputStream != _outputStream) { + if (_outputStream) { + [_outputStream close]; + } + + _outputStream = outputStream; + } + [self.lock unlock]; +} + +#if defined(__IPHONE_OS_VERSION_MIN_REQUIRED) && !defined(AF_APP_EXTENSIONS) +- (void)setShouldExecuteAsBackgroundTaskWithExpirationHandler:(void (^)(void))handler { + [self.lock lock]; + if (!self.backgroundTaskIdentifier) { + UIApplication *application = [UIApplication sharedApplication]; + __weak __typeof(self)weakSelf = self; + self.backgroundTaskIdentifier = [application beginBackgroundTaskWithExpirationHandler:^{ + __strong __typeof(weakSelf)strongSelf = weakSelf; + + if (handler) { + handler(); + } + + if (strongSelf) { + [strongSelf cancel]; + + [application endBackgroundTask:strongSelf.backgroundTaskIdentifier]; + strongSelf.backgroundTaskIdentifier = UIBackgroundTaskInvalid; + } + }]; + } + [self.lock unlock]; +} +#endif + +#pragma mark - + +- (void)setState:(AFOperationState)state { + if (!AFStateTransitionIsValid(self.state, state, [self isCancelled])) { + return; + } + + [self.lock lock]; + NSString *oldStateKey = AFKeyPathFromOperationState(self.state); + NSString *newStateKey = AFKeyPathFromOperationState(state); + + [self willChangeValueForKey:newStateKey]; + [self willChangeValueForKey:oldStateKey]; + _state = state; + [self didChangeValueForKey:oldStateKey]; + [self didChangeValueForKey:newStateKey]; + [self.lock unlock]; +} + +- (void)pause { + if ([self isPaused] || [self isFinished] || [self isCancelled]) { + return; + } + + [self.lock lock]; + + if ([self isExecuting]) { + [self performSelector:@selector(operationDidPause) onThread:[[self class] networkRequestThread] withObject:nil waitUntilDone:NO modes:[self.runLoopModes allObjects]]; + + dispatch_async(dispatch_get_main_queue(), ^{ + NSNotificationCenter *notificationCenter = [NSNotificationCenter defaultCenter]; + [notificationCenter postNotificationName:AFNetworkingOperationDidFinishNotification object:self]; + }); + } + + self.state = AFOperationPausedState; + + [self.lock unlock]; +} + +- (void)operationDidPause { + [self.lock lock]; + [self.connection cancel]; + [self.lock unlock]; +} + +- (BOOL)isPaused { + return self.state == AFOperationPausedState; +} + +- (void)resume { + if (![self isPaused]) { + return; + } + + [self.lock lock]; + self.state = AFOperationReadyState; + + [self start]; + [self.lock unlock]; +} + +#pragma mark - + +- (void)setUploadProgressBlock:(void (^)(NSUInteger bytesWritten, long long totalBytesWritten, long long totalBytesExpectedToWrite))block { + self.uploadProgress = block; +} + +- (void)setDownloadProgressBlock:(void (^)(NSUInteger bytesRead, long long totalBytesRead, long long totalBytesExpectedToRead))block { + self.downloadProgress = block; +} + +- (void)setWillSendRequestForAuthenticationChallengeBlock:(void (^)(NSURLConnection *connection, NSURLAuthenticationChallenge *challenge))block { + self.authenticationChallenge = block; +} + +- (void)setCacheResponseBlock:(NSCachedURLResponse * (^)(NSURLConnection *connection, NSCachedURLResponse *cachedResponse))block { + self.cacheResponse = block; +} + +- (void)setRedirectResponseBlock:(NSURLRequest * (^)(NSURLConnection *connection, NSURLRequest *request, NSURLResponse *redirectResponse))block { + self.redirectResponse = block; +} + +#pragma mark - NSOperation + +- (void)setCompletionBlock:(void (^)(void))block { + [self.lock lock]; + if (!block) { + [super setCompletionBlock:nil]; + } else { + __weak __typeof(self)weakSelf = self; + [super setCompletionBlock:^ { + __strong __typeof(weakSelf)strongSelf = weakSelf; + +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wgnu" + dispatch_group_t group = strongSelf.completionGroup ?: url_request_operation_completion_group(); + dispatch_queue_t queue = strongSelf.completionQueue ?: dispatch_get_main_queue(); +#pragma clang diagnostic pop + + dispatch_group_async(group, queue, ^{ + block(); + }); + + dispatch_group_notify(group, url_request_operation_completion_queue(), ^{ + [strongSelf setCompletionBlock:nil]; + }); + }]; + } + [self.lock unlock]; +} + +- (BOOL)isReady { + return self.state == AFOperationReadyState && [super isReady]; +} + +- (BOOL)isExecuting { + return self.state == AFOperationExecutingState; +} + +- (BOOL)isFinished { + return self.state == AFOperationFinishedState; +} + +- (BOOL)isConcurrent { + return YES; +} + +- (void)start { + [self.lock lock]; + if ([self isCancelled]) { + [self performSelector:@selector(cancelConnection) onThread:[[self class] networkRequestThread] withObject:nil waitUntilDone:NO modes:[self.runLoopModes allObjects]]; + } else if ([self isReady]) { + self.state = AFOperationExecutingState; + + [self performSelector:@selector(operationDidStart) onThread:[[self class] networkRequestThread] withObject:nil waitUntilDone:NO modes:[self.runLoopModes allObjects]]; + } + [self.lock unlock]; +} + +- (void)operationDidStart { + [self.lock lock]; + if (![self isCancelled]) { + self.connection = [[NSURLConnection alloc] initWithRequest:self.request delegate:self startImmediately:NO]; + + NSRunLoop *runLoop = [NSRunLoop currentRunLoop]; + for (NSString *runLoopMode in self.runLoopModes) { + [self.connection scheduleInRunLoop:runLoop forMode:runLoopMode]; + [self.outputStream scheduleInRunLoop:runLoop forMode:runLoopMode]; + } + + [self.connection start]; + } + [self.lock unlock]; + + dispatch_async(dispatch_get_main_queue(), ^{ + [[NSNotificationCenter defaultCenter] postNotificationName:AFNetworkingOperationDidStartNotification object:self]; + }); +} + +- (void)finish { + [self.lock lock]; + self.state = AFOperationFinishedState; + [self.lock unlock]; + + dispatch_async(dispatch_get_main_queue(), ^{ + [[NSNotificationCenter defaultCenter] postNotificationName:AFNetworkingOperationDidFinishNotification object:self]; + }); +} + +- (void)cancel { + [self.lock lock]; + if (![self isFinished] && ![self isCancelled]) { + [super cancel]; + + if ([self isExecuting]) { + [self performSelector:@selector(cancelConnection) onThread:[[self class] networkRequestThread] withObject:nil waitUntilDone:NO modes:[self.runLoopModes allObjects]]; + } + } + [self.lock unlock]; +} + +- (void)cancelConnection { + NSDictionary *userInfo = nil; + if ([self.request URL]) { + userInfo = [NSDictionary dictionaryWithObject:[self.request URL] forKey:NSURLErrorFailingURLErrorKey]; + } + NSError *error = [NSError errorWithDomain:NSURLErrorDomain code:NSURLErrorCancelled userInfo:userInfo]; + + if (![self isFinished]) { + if (self.connection) { + [self.connection cancel]; + [self performSelector:@selector(connection:didFailWithError:) withObject:self.connection withObject:error]; + } else { + // Accomodate race condition where `self.connection` has not yet been set before cancellation + self.error = error; + [self finish]; + } + } +} + +#pragma mark - + ++ (NSArray *)batchOfRequestOperations:(NSArray *)operations + progressBlock:(void (^)(NSUInteger numberOfFinishedOperations, NSUInteger totalNumberOfOperations))progressBlock + completionBlock:(void (^)(NSArray *operations))completionBlock +{ + if (!operations || [operations count] == 0) { + return @[[NSBlockOperation blockOperationWithBlock:^{ + dispatch_async(dispatch_get_main_queue(), ^{ + if (completionBlock) { + completionBlock(@[]); + } + }); + }]]; + } + + __block dispatch_group_t group = dispatch_group_create(); + NSBlockOperation *batchedOperation = [NSBlockOperation blockOperationWithBlock:^{ + dispatch_group_notify(group, dispatch_get_main_queue(), ^{ + if (completionBlock) { + completionBlock(operations); + } + }); + }]; + + for (AFURLConnectionOperation *operation in operations) { + operation.completionGroup = group; + void (^originalCompletionBlock)(void) = [operation.completionBlock copy]; + __weak __typeof(operation)weakOperation = operation; + operation.completionBlock = ^{ + __strong __typeof(weakOperation)strongOperation = weakOperation; +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wgnu" + dispatch_queue_t queue = strongOperation.completionQueue ?: dispatch_get_main_queue(); +#pragma clang diagnostic pop + dispatch_group_async(group, queue, ^{ + if (originalCompletionBlock) { + originalCompletionBlock(); + } + + NSUInteger numberOfFinishedOperations = [[operations indexesOfObjectsPassingTest:^BOOL(id op, NSUInteger __unused idx, BOOL __unused *stop) { + return [op isFinished]; + }] count]; + + if (progressBlock) { + progressBlock(numberOfFinishedOperations, [operations count]); + } + + dispatch_group_leave(group); + }); + }; + + dispatch_group_enter(group); + [batchedOperation addDependency:operation]; + } + + return [operations arrayByAddingObject:batchedOperation]; +} + +#pragma mark - NSObject + +- (NSString *)description { + return [NSString stringWithFormat:@"<%@: %p, state: %@, cancelled: %@ request: %@, response: %@>", NSStringFromClass([self class]), self, AFKeyPathFromOperationState(self.state), ([self isCancelled] ? @"YES" : @"NO"), self.request, self.response]; +} + +#pragma mark - NSURLConnectionDelegate + +- (void)connection:(NSURLConnection *)connection +willSendRequestForAuthenticationChallenge:(NSURLAuthenticationChallenge *)challenge +{ + if (self.authenticationChallenge) { + self.authenticationChallenge(connection, challenge); + return; + } + + if ([challenge.protectionSpace.authenticationMethod isEqualToString:NSURLAuthenticationMethodServerTrust]) { + if ([self.securityPolicy evaluateServerTrust:challenge.protectionSpace.serverTrust forDomain:challenge.protectionSpace.host]) { + NSURLCredential *credential = [NSURLCredential credentialForTrust:challenge.protectionSpace.serverTrust]; + [[challenge sender] useCredential:credential forAuthenticationChallenge:challenge]; + } else { + [[challenge sender] cancelAuthenticationChallenge:challenge]; + } + } else { + if ([challenge previousFailureCount] == 0) { + if (self.credential) { + [[challenge sender] useCredential:self.credential forAuthenticationChallenge:challenge]; + } else { + [[challenge sender] continueWithoutCredentialForAuthenticationChallenge:challenge]; + } + } else { + [[challenge sender] continueWithoutCredentialForAuthenticationChallenge:challenge]; + } + } +} + +- (BOOL)connectionShouldUseCredentialStorage:(NSURLConnection __unused *)connection { + return self.shouldUseCredentialStorage; +} + +- (NSURLRequest *)connection:(NSURLConnection *)connection + willSendRequest:(NSURLRequest *)request + redirectResponse:(NSURLResponse *)redirectResponse +{ + if (self.redirectResponse) { + return self.redirectResponse(connection, request, redirectResponse); + } else { + return request; + } +} + +- (void)connection:(NSURLConnection __unused *)connection + didSendBodyData:(NSInteger)bytesWritten + totalBytesWritten:(NSInteger)totalBytesWritten +totalBytesExpectedToWrite:(NSInteger)totalBytesExpectedToWrite +{ + dispatch_async(dispatch_get_main_queue(), ^{ + if (self.uploadProgress) { + self.uploadProgress((NSUInteger)bytesWritten, totalBytesWritten, totalBytesExpectedToWrite); + } + }); +} + +- (void)connection:(NSURLConnection __unused *)connection +didReceiveResponse:(NSURLResponse *)response +{ + self.response = response; + + [self.outputStream open]; +} + +- (void)connection:(NSURLConnection __unused *)connection + didReceiveData:(NSData *)data +{ + NSUInteger length = [data length]; + while (YES) { + NSInteger totalNumberOfBytesWritten = 0; + if ([self.outputStream hasSpaceAvailable]) { + const uint8_t *dataBuffer = (uint8_t *)[data bytes]; + + NSInteger numberOfBytesWritten = 0; + while (totalNumberOfBytesWritten < (NSInteger)length) { + numberOfBytesWritten = [self.outputStream write:&dataBuffer[(NSUInteger)totalNumberOfBytesWritten] maxLength:(length - (NSUInteger)totalNumberOfBytesWritten)]; + if (numberOfBytesWritten == -1) { + break; + } + + totalNumberOfBytesWritten += numberOfBytesWritten; + } + + break; + } + + if (self.outputStream.streamError) { + [self.connection cancel]; + [self performSelector:@selector(connection:didFailWithError:) withObject:self.connection withObject:self.outputStream.streamError]; + return; + } + } + + dispatch_async(dispatch_get_main_queue(), ^{ + self.totalBytesRead += (long long)length; + + if (self.downloadProgress) { + self.downloadProgress(length, self.totalBytesRead, self.response.expectedContentLength); + } + }); +} + +- (void)connectionDidFinishLoading:(NSURLConnection __unused *)connection { + self.responseData = [self.outputStream propertyForKey:NSStreamDataWrittenToMemoryStreamKey]; + + [self.outputStream close]; + if (self.responseData) { + self.outputStream = nil; + } + + self.connection = nil; + + [self finish]; +} + +- (void)connection:(NSURLConnection __unused *)connection + didFailWithError:(NSError *)error +{ + self.error = error; + + [self.outputStream close]; + if (self.responseData) { + self.outputStream = nil; + } + + self.connection = nil; + + [self finish]; +} + +- (NSCachedURLResponse *)connection:(NSURLConnection *)connection + willCacheResponse:(NSCachedURLResponse *)cachedResponse +{ + if (self.cacheResponse) { + return self.cacheResponse(connection, cachedResponse); + } else { + if ([self isCancelled]) { + return nil; + } + + return cachedResponse; + } +} + +#pragma mark - NSecureCoding + ++ (BOOL)supportsSecureCoding { + return YES; +} + +- (id)initWithCoder:(NSCoder *)decoder { + NSURLRequest *request = [decoder decodeObjectOfClass:[NSURLRequest class] forKey:NSStringFromSelector(@selector(request))]; + + self = [self initWithRequest:request]; + if (!self) { + return nil; + } + + self.state = [[decoder decodeObjectOfClass:[NSNumber class] forKey:NSStringFromSelector(@selector(state))] integerValue]; + self.response = [decoder decodeObjectOfClass:[NSHTTPURLResponse class] forKey:NSStringFromSelector(@selector(response))]; + self.error = [decoder decodeObjectOfClass:[NSError class] forKey:NSStringFromSelector(@selector(error))]; + self.responseData = [decoder decodeObjectOfClass:[NSData class] forKey:NSStringFromSelector(@selector(responseData))]; + self.totalBytesRead = [[decoder decodeObjectOfClass:[NSNumber class] forKey:NSStringFromSelector(@selector(totalBytesRead))] longLongValue]; + + return self; +} + +- (void)encodeWithCoder:(NSCoder *)coder { + [self pause]; + + [coder encodeObject:self.request forKey:NSStringFromSelector(@selector(request))]; + + switch (self.state) { + case AFOperationExecutingState: + case AFOperationPausedState: + [coder encodeInteger:AFOperationReadyState forKey:NSStringFromSelector(@selector(state))]; + break; + default: + [coder encodeInteger:self.state forKey:NSStringFromSelector(@selector(state))]; + break; + } + + [coder encodeObject:self.response forKey:NSStringFromSelector(@selector(response))]; + [coder encodeObject:self.error forKey:NSStringFromSelector(@selector(error))]; + [coder encodeObject:self.responseData forKey:NSStringFromSelector(@selector(responseData))]; + [coder encodeInt64:self.totalBytesRead forKey:NSStringFromSelector(@selector(totalBytesRead))]; +} + +#pragma mark - NSCopying + +- (id)copyWithZone:(NSZone *)zone { + AFURLConnectionOperation *operation = [(AFURLConnectionOperation *)[[self class] allocWithZone:zone] initWithRequest:self.request]; + + operation.uploadProgress = self.uploadProgress; + operation.downloadProgress = self.downloadProgress; + operation.authenticationChallenge = self.authenticationChallenge; + operation.cacheResponse = self.cacheResponse; + operation.redirectResponse = self.redirectResponse; + operation.completionQueue = self.completionQueue; + operation.completionGroup = self.completionGroup; + + return operation; +} + +@end diff --git a/ios/Pods/AFNetworking/AFNetworking/AFURLRequestSerialization.h b/ios/Pods/AFNetworking/AFNetworking/AFURLRequestSerialization.h new file mode 100644 index 000000000..161b551d8 --- /dev/null +++ b/ios/Pods/AFNetworking/AFNetworking/AFURLRequestSerialization.h @@ -0,0 +1,444 @@ +// AFSerialization.h +// +// Copyright (c) 2013-2014 AFNetworking (http://afnetworking.com) +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +#import +#if defined(__IPHONE_OS_VERSION_MIN_REQUIRED) +#import +#endif + +/** + The `AFURLRequestSerialization` protocol is adopted by an object that encodes parameters for a specified HTTP requests. Request serializers may encode parameters as query strings, HTTP bodies, setting the appropriate HTTP header fields as necessary. + + For example, a JSON request serializer may set the HTTP body of the request to a JSON representation, and set the `Content-Type` HTTP header field value to `application/json`. + */ +@protocol AFURLRequestSerialization + +/** + Returns a request with the specified parameters encoded into a copy of the original request. + + @param request The original request. + @param parameters The parameters to be encoded. + @param error The error that occurred while attempting to encode the request parameters. + + @return A serialized request. + */ +- (NSURLRequest *)requestBySerializingRequest:(NSURLRequest *)request + withParameters:(id)parameters + error:(NSError * __autoreleasing *)error; + +@end + +#pragma mark - + +/** + + */ +typedef NS_ENUM(NSUInteger, AFHTTPRequestQueryStringSerializationStyle) { + AFHTTPRequestQueryStringDefaultStyle = 0, +}; + +@protocol AFMultipartFormData; + +/** + `AFHTTPRequestSerializer` conforms to the `AFURLRequestSerialization` & `AFURLResponseSerialization` protocols, offering a concrete base implementation of query string / URL form-encoded parameter serialization and default request headers, as well as response status code and content type validation. + + Any request or response serializer dealing with HTTP is encouraged to subclass `AFHTTPRequestSerializer` in order to ensure consistent default behavior. + */ +@interface AFHTTPRequestSerializer : NSObject + +/** + The string encoding used to serialize parameters. `NSUTF8StringEncoding` by default. + */ +@property (nonatomic, assign) NSStringEncoding stringEncoding; + +/** + Whether created requests can use the device’s cellular radio (if present). `YES` by default. + + @see NSMutableURLRequest -setAllowsCellularAccess: + */ +@property (nonatomic, assign) BOOL allowsCellularAccess; + +/** + The cache policy of created requests. `NSURLRequestUseProtocolCachePolicy` by default. + + @see NSMutableURLRequest -setCachePolicy: + */ +@property (nonatomic, assign) NSURLRequestCachePolicy cachePolicy; + +/** + Whether created requests should use the default cookie handling. `YES` by default. + + @see NSMutableURLRequest -setHTTPShouldHandleCookies: + */ +@property (nonatomic, assign) BOOL HTTPShouldHandleCookies; + +/** + Whether created requests can continue transmitting data before receiving a response from an earlier transmission. `NO` by default + + @see NSMutableURLRequest -setHTTPShouldUsePipelining: + */ +@property (nonatomic, assign) BOOL HTTPShouldUsePipelining; + +/** + The network service type for created requests. `NSURLNetworkServiceTypeDefault` by default. + + @see NSMutableURLRequest -setNetworkServiceType: + */ +@property (nonatomic, assign) NSURLRequestNetworkServiceType networkServiceType; + +/** + The timeout interval, in seconds, for created requests. The default timeout interval is 60 seconds. + + @see NSMutableURLRequest -setTimeoutInterval: + */ +@property (nonatomic, assign) NSTimeInterval timeoutInterval; + +///--------------------------------------- +/// @name Configuring HTTP Request Headers +///--------------------------------------- + +/** + Default HTTP header field values to be applied to serialized requests. + */ +@property (readonly, nonatomic, strong) NSDictionary *HTTPRequestHeaders; + +/** + Creates and returns a serializer with default configuration. + */ ++ (instancetype)serializer; + +/** + Sets the value for the HTTP headers set in request objects made by the HTTP client. If `nil`, removes the existing value for that header. + + @param field The HTTP header to set a default value for + @param value The value set as default for the specified header, or `nil` + */ +- (void)setValue:(NSString *)value +forHTTPHeaderField:(NSString *)field; + +/** + Sets the "Authorization" HTTP header set in request objects made by the HTTP client to a basic authentication value with Base64-encoded username and password. This overwrites any existing value for this header. + + @param username The HTTP basic auth username + @param password The HTTP basic auth password + */ +- (void)setAuthorizationHeaderFieldWithUsername:(NSString *)username + password:(NSString *)password; + +/** + @deprecated This method has been deprecated. Use -setValue:forHTTPHeaderField: instead. + */ +- (void)setAuthorizationHeaderFieldWithToken:(NSString *)token DEPRECATED_ATTRIBUTE; + + +/** + Clears any existing value for the "Authorization" HTTP header. + */ +- (void)clearAuthorizationHeader; + +///------------------------------------------------------- +/// @name Configuring Query String Parameter Serialization +///------------------------------------------------------- + +/** + HTTP methods for which serialized requests will encode parameters as a query string. `GET`, `HEAD`, and `DELETE` by default. + */ +@property (nonatomic, strong) NSSet *HTTPMethodsEncodingParametersInURI; + +/** + Set the method of query string serialization according to one of the pre-defined styles. + + @param style The serialization style. + + @see AFHTTPRequestQueryStringSerializationStyle + */ +- (void)setQueryStringSerializationWithStyle:(AFHTTPRequestQueryStringSerializationStyle)style; + +/** + Set the a custom method of query string serialization according to the specified block. + + @param block A block that defines a process of encoding parameters into a query string. This block returns the query string and takes three arguments: the request, the parameters to encode, and the error that occurred when attempting to encode parameters for the given request. + */ +- (void)setQueryStringSerializationWithBlock:(NSString * (^)(NSURLRequest *request, NSDictionary *parameters, NSError * __autoreleasing *error))block; + +///------------------------------- +/// @name Creating Request Objects +///------------------------------- + +/** + @deprecated This method has been deprecated. Use -requestWithMethod:URLString:parameters:error: instead. + */ +- (NSMutableURLRequest *)requestWithMethod:(NSString *)method + URLString:(NSString *)URLString + parameters:(id)parameters DEPRECATED_ATTRIBUTE; + +/** + Creates an `NSMutableURLRequest` object with the specified HTTP method and URL string. + + If the HTTP method is `GET`, `HEAD`, or `DELETE`, the parameters will be used to construct a url-encoded query string that is appended to the request's URL. Otherwise, the parameters will be encoded according to the value of the `parameterEncoding` property, and set as the request body. + + @param method The HTTP method for the request, such as `GET`, `POST`, `PUT`, or `DELETE`. This parameter must not be `nil`. + @param URLString The URL string used to create the request URL. + @param parameters The parameters to be either set as a query string for `GET` requests, or the request HTTP body. + @param error The error that occured while constructing the request. + + @return An `NSMutableURLRequest` object. + */ +- (NSMutableURLRequest *)requestWithMethod:(NSString *)method + URLString:(NSString *)URLString + parameters:(id)parameters + error:(NSError * __autoreleasing *)error; + +/** + @deprecated This method has been deprecated. Use -multipartFormRequestWithMethod:URLString:parameters:constructingBodyWithBlock:error: instead. + */ +- (NSMutableURLRequest *)multipartFormRequestWithMethod:(NSString *)method + URLString:(NSString *)URLString + parameters:(NSDictionary *)parameters + constructingBodyWithBlock:(void (^)(id formData))block DEPRECATED_ATTRIBUTE; + +/** + Creates an `NSMutableURLRequest` object with the specified HTTP method and URLString, and constructs a `multipart/form-data` HTTP body, using the specified parameters and multipart form data block. See http://www.w3.org/TR/html4/interact/forms.html#h-17.13.4.2 + + Multipart form requests are automatically streamed, reading files directly from disk along with in-memory data in a single HTTP body. The resulting `NSMutableURLRequest` object has an `HTTPBodyStream` property, so refrain from setting `HTTPBodyStream` or `HTTPBody` on this request object, as it will clear out the multipart form body stream. + + @param method The HTTP method for the request. This parameter must not be `GET` or `HEAD`, or `nil`. + @param URLString The URL string used to create the request URL. + @param parameters The parameters to be encoded and set in the request HTTP body. + @param block A block that takes a single argument and appends data to the HTTP body. The block argument is an object adopting the `AFMultipartFormData` protocol. + @param error The error that occured while constructing the request. + + @return An `NSMutableURLRequest` object + */ +- (NSMutableURLRequest *)multipartFormRequestWithMethod:(NSString *)method + URLString:(NSString *)URLString + parameters:(NSDictionary *)parameters + constructingBodyWithBlock:(void (^)(id formData))block + error:(NSError * __autoreleasing *)error; + +/** + Creates an `NSMutableURLRequest` by removing the `HTTPBodyStream` from a request, and asynchronously writing its contents into the specified file, invoking the completion handler when finished. + + @param request The multipart form request. + @param fileURL The file URL to write multipart form contents to. + @param handler A handler block to execute. + + @discussion There is a bug in `NSURLSessionTask` that causes requests to not send a `Content-Length` header when streaming contents from an HTTP body, which is notably problematic when interacting with the Amazon S3 webservice. As a workaround, this method takes a request constructed with `multipartFormRequestWithMethod:URLString:parameters:constructingBodyWithBlock:error:`, or any other request with an `HTTPBodyStream`, writes the contents to the specified file and returns a copy of the original request with the `HTTPBodyStream` property set to `nil`. From here, the file can either be passed to `AFURLSessionManager -uploadTaskWithRequest:fromFile:progress:completionHandler:`, or have its contents read into an `NSData` that's assigned to the `HTTPBody` property of the request. + + @see https://github.com/AFNetworking/AFNetworking/issues/1398 + */ +- (NSMutableURLRequest *)requestWithMultipartFormRequest:(NSURLRequest *)request + writingStreamContentsToFile:(NSURL *)fileURL + completionHandler:(void (^)(NSError *error))handler; + +@end + +#pragma mark - + +/** + The `AFMultipartFormData` protocol defines the methods supported by the parameter in the block argument of `AFHTTPRequestSerializer -multipartFormRequestWithMethod:URLString:parameters:constructingBodyWithBlock:`. + */ +@protocol AFMultipartFormData + +/** + Appends the HTTP header `Content-Disposition: file; filename=#{generated filename}; name=#{name}"` and `Content-Type: #{generated mimeType}`, followed by the encoded file data and the multipart form boundary. + + The filename and MIME type for this data in the form will be automatically generated, using the last path component of the `fileURL` and system associated MIME type for the `fileURL` extension, respectively. + + @param fileURL The URL corresponding to the file whose content will be appended to the form. This parameter must not be `nil`. + @param name The name to be associated with the specified data. This parameter must not be `nil`. + @param error If an error occurs, upon return contains an `NSError` object that describes the problem. + + @return `YES` if the file data was successfully appended, otherwise `NO`. + */ +- (BOOL)appendPartWithFileURL:(NSURL *)fileURL + name:(NSString *)name + error:(NSError * __autoreleasing *)error; + +/** + Appends the HTTP header `Content-Disposition: file; filename=#{filename}; name=#{name}"` and `Content-Type: #{mimeType}`, followed by the encoded file data and the multipart form boundary. + + @param fileURL The URL corresponding to the file whose content will be appended to the form. This parameter must not be `nil`. + @param name The name to be associated with the specified data. This parameter must not be `nil`. + @param fileName The file name to be used in the `Content-Disposition` header. This parameter must not be `nil`. + @param mimeType The declared MIME type of the file data. This parameter must not be `nil`. + @param error If an error occurs, upon return contains an `NSError` object that describes the problem. + + @return `YES` if the file data was successfully appended otherwise `NO`. + */ +- (BOOL)appendPartWithFileURL:(NSURL *)fileURL + name:(NSString *)name + fileName:(NSString *)fileName + mimeType:(NSString *)mimeType + error:(NSError * __autoreleasing *)error; + +/** + Appends the HTTP header `Content-Disposition: file; filename=#{filename}; name=#{name}"` and `Content-Type: #{mimeType}`, followed by the data from the input stream and the multipart form boundary. + + @param inputStream The input stream to be appended to the form data + @param name The name to be associated with the specified input stream. This parameter must not be `nil`. + @param fileName The filename to be associated with the specified input stream. This parameter must not be `nil`. + @param length The length of the specified input stream in bytes. + @param mimeType The MIME type of the specified data. (For example, the MIME type for a JPEG image is image/jpeg.) For a list of valid MIME types, see http://www.iana.org/assignments/media-types/. This parameter must not be `nil`. + */ +- (void)appendPartWithInputStream:(NSInputStream *)inputStream + name:(NSString *)name + fileName:(NSString *)fileName + length:(int64_t)length + mimeType:(NSString *)mimeType; + +/** + Appends the HTTP header `Content-Disposition: file; filename=#{filename}; name=#{name}"` and `Content-Type: #{mimeType}`, followed by the encoded file data and the multipart form boundary. + + @param data The data to be encoded and appended to the form data. + @param name The name to be associated with the specified data. This parameter must not be `nil`. + @param fileName The filename to be associated with the specified data. This parameter must not be `nil`. + @param mimeType The MIME type of the specified data. (For example, the MIME type for a JPEG image is image/jpeg.) For a list of valid MIME types, see http://www.iana.org/assignments/media-types/. This parameter must not be `nil`. + */ +- (void)appendPartWithFileData:(NSData *)data + name:(NSString *)name + fileName:(NSString *)fileName + mimeType:(NSString *)mimeType; + +/** + Appends the HTTP headers `Content-Disposition: form-data; name=#{name}"`, followed by the encoded data and the multipart form boundary. + + @param data The data to be encoded and appended to the form data. + @param name The name to be associated with the specified data. This parameter must not be `nil`. + */ + +- (void)appendPartWithFormData:(NSData *)data + name:(NSString *)name; + + +/** + Appends HTTP headers, followed by the encoded data and the multipart form boundary. + + @param headers The HTTP headers to be appended to the form data. + @param body The data to be encoded and appended to the form data. + */ +- (void)appendPartWithHeaders:(NSDictionary *)headers + body:(NSData *)body; + +/** + Throttles request bandwidth by limiting the packet size and adding a delay for each chunk read from the upload stream. + + When uploading over a 3G or EDGE connection, requests may fail with "request body stream exhausted". Setting a maximum packet size and delay according to the recommended values (`kAFUploadStream3GSuggestedPacketSize` and `kAFUploadStream3GSuggestedDelay`) lowers the risk of the input stream exceeding its allocated bandwidth. Unfortunately, there is no definite way to distinguish between a 3G, EDGE, or LTE connection over `NSURLConnection`. As such, it is not recommended that you throttle bandwidth based solely on network reachability. Instead, you should consider checking for the "request body stream exhausted" in a failure block, and then retrying the request with throttled bandwidth. + + @param numberOfBytes Maximum packet size, in number of bytes. The default packet size for an input stream is 16kb. + @param delay Duration of delay each time a packet is read. By default, no delay is set. + */ +- (void)throttleBandwidthWithPacketSize:(NSUInteger)numberOfBytes + delay:(NSTimeInterval)delay; + +@end + +#pragma mark - + +@interface AFJSONRequestSerializer : AFHTTPRequestSerializer + +/** + Options for writing the request JSON data from Foundation objects. For possible values, see the `NSJSONSerialization` documentation section "NSJSONWritingOptions". `0` by default. + */ +@property (nonatomic, assign) NSJSONWritingOptions writingOptions; + +/** + Creates and returns a JSON serializer with specified reading and writing options. + + @param writingOptions The specified JSON writing options. + */ ++ (instancetype)serializerWithWritingOptions:(NSJSONWritingOptions)writingOptions; + +@end + +@interface AFPropertyListRequestSerializer : AFHTTPRequestSerializer + +/** + The property list format. Possible values are described in "NSPropertyListFormat". + */ +@property (nonatomic, assign) NSPropertyListFormat format; + +/** + @warning The `writeOptions` property is currently unused. + */ +@property (nonatomic, assign) NSPropertyListWriteOptions writeOptions; + +/** + Creates and returns a property list serializer with a specified format, read options, and write options. + + @param format The property list format. + @param writeOptions The property list write options. + + @warning The `writeOptions` property is currently unused. + */ ++ (instancetype)serializerWithFormat:(NSPropertyListFormat)format + writeOptions:(NSPropertyListWriteOptions)writeOptions; + +@end + +///---------------- +/// @name Constants +///---------------- + +/** + ## Error Domains + + The following error domain is predefined. + + - `NSString * const AFURLRequestSerializationErrorDomain` + + ### Constants + + `AFURLRequestSerializationErrorDomain` + AFURLRequestSerializer errors. Error codes for `AFURLRequestSerializationErrorDomain` correspond to codes in `NSURLErrorDomain`. + */ +extern NSString * const AFURLRequestSerializationErrorDomain; + +/** + ## User info dictionary keys + + These keys may exist in the user info dictionary, in addition to those defined for NSError. + + - `NSString * const AFNetworkingOperationFailingURLResponseErrorKey` + + ### Constants + + `AFNetworkingOperationFailingURLRequestErrorKey` + The corresponding value is an `NSURLRequest` containing the request of the operation associated with an error. This key is only present in the `AFURLRequestSerializationErrorDomain`. + */ +extern NSString * const AFNetworkingOperationFailingURLRequestErrorKey; + +/** + ## Throttling Bandwidth for HTTP Request Input Streams + + @see -throttleBandwidthWithPacketSize:delay: + + ### Constants + + `kAFUploadStream3GSuggestedPacketSize` + Maximum packet size, in number of bytes. Equal to 16kb. + + `kAFUploadStream3GSuggestedDelay` + Duration of delay each time a packet is read. Equal to 0.2 seconds. + */ +extern NSUInteger const kAFUploadStream3GSuggestedPacketSize; +extern NSTimeInterval const kAFUploadStream3GSuggestedDelay; diff --git a/ios/Pods/AFNetworking/AFNetworking/AFURLRequestSerialization.m b/ios/Pods/AFNetworking/AFNetworking/AFURLRequestSerialization.m new file mode 100644 index 000000000..45df7a033 --- /dev/null +++ b/ios/Pods/AFNetworking/AFNetworking/AFURLRequestSerialization.m @@ -0,0 +1,1281 @@ +// AFSerialization.h +// +// Copyright (c) 2013-2014 AFNetworking (http://afnetworking.com) +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +#import "AFURLRequestSerialization.h" + +#if __IPHONE_OS_VERSION_MIN_REQUIRED +#import +#else +#import +#endif + +NSString * const AFURLRequestSerializationErrorDomain = @"com.alamofire.error.serialization.request"; +NSString * const AFNetworkingOperationFailingURLRequestErrorKey = @"com.alamofire.serialization.request.error.response"; + +typedef NSString * (^AFQueryStringSerializationBlock)(NSURLRequest *request, NSDictionary *parameters, NSError *__autoreleasing *error); + +static NSString * AFBase64EncodedStringFromString(NSString *string) { + NSData *data = [NSData dataWithBytes:[string UTF8String] length:[string lengthOfBytesUsingEncoding:NSUTF8StringEncoding]]; + NSUInteger length = [data length]; + NSMutableData *mutableData = [NSMutableData dataWithLength:((length + 2) / 3) * 4]; + + uint8_t *input = (uint8_t *)[data bytes]; + uint8_t *output = (uint8_t *)[mutableData mutableBytes]; + + for (NSUInteger i = 0; i < length; i += 3) { + NSUInteger value = 0; + for (NSUInteger j = i; j < (i + 3); j++) { + value <<= 8; + if (j < length) { + value |= (0xFF & input[j]); + } + } + + static uint8_t const kAFBase64EncodingTable[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; + + NSUInteger idx = (i / 3) * 4; + output[idx + 0] = kAFBase64EncodingTable[(value >> 18) & 0x3F]; + output[idx + 1] = kAFBase64EncodingTable[(value >> 12) & 0x3F]; + output[idx + 2] = (i + 1) < length ? kAFBase64EncodingTable[(value >> 6) & 0x3F] : '='; + output[idx + 3] = (i + 2) < length ? kAFBase64EncodingTable[(value >> 0) & 0x3F] : '='; + } + + return [[NSString alloc] initWithData:mutableData encoding:NSASCIIStringEncoding]; +} + +static NSString * const kAFCharactersToBeEscapedInQueryString = @":/?&=;+!@#$()',*"; + +static NSString * AFPercentEscapedQueryStringKeyFromStringWithEncoding(NSString *string, NSStringEncoding encoding) { + static NSString * const kAFCharactersToLeaveUnescapedInQueryStringPairKey = @"[]."; + + return (__bridge_transfer NSString *)CFURLCreateStringByAddingPercentEscapes(kCFAllocatorDefault, (__bridge CFStringRef)string, (__bridge CFStringRef)kAFCharactersToLeaveUnescapedInQueryStringPairKey, (__bridge CFStringRef)kAFCharactersToBeEscapedInQueryString, CFStringConvertNSStringEncodingToEncoding(encoding)); +} + +static NSString * AFPercentEscapedQueryStringValueFromStringWithEncoding(NSString *string, NSStringEncoding encoding) { + return (__bridge_transfer NSString *)CFURLCreateStringByAddingPercentEscapes(kCFAllocatorDefault, (__bridge CFStringRef)string, NULL, (__bridge CFStringRef)kAFCharactersToBeEscapedInQueryString, CFStringConvertNSStringEncodingToEncoding(encoding)); +} + +#pragma mark - + +@interface AFQueryStringPair : NSObject +@property (readwrite, nonatomic, strong) id field; +@property (readwrite, nonatomic, strong) id value; + +- (id)initWithField:(id)field value:(id)value; + +- (NSString *)URLEncodedStringValueWithEncoding:(NSStringEncoding)stringEncoding; +@end + +@implementation AFQueryStringPair + +- (id)initWithField:(id)field value:(id)value { + self = [super init]; + if (!self) { + return nil; + } + + self.field = field; + self.value = value; + + return self; +} + +- (NSString *)URLEncodedStringValueWithEncoding:(NSStringEncoding)stringEncoding { + if (!self.value || [self.value isEqual:[NSNull null]]) { + return AFPercentEscapedQueryStringKeyFromStringWithEncoding([self.field description], stringEncoding); + } else { + return [NSString stringWithFormat:@"%@=%@", AFPercentEscapedQueryStringKeyFromStringWithEncoding([self.field description], stringEncoding), AFPercentEscapedQueryStringValueFromStringWithEncoding([self.value description], stringEncoding)]; + } +} + +@end + +#pragma mark - + +extern NSArray * AFQueryStringPairsFromDictionary(NSDictionary *dictionary); +extern NSArray * AFQueryStringPairsFromKeyAndValue(NSString *key, id value); + +static NSString * AFQueryStringFromParametersWithEncoding(NSDictionary *parameters, NSStringEncoding stringEncoding) { + NSMutableArray *mutablePairs = [NSMutableArray array]; + for (AFQueryStringPair *pair in AFQueryStringPairsFromDictionary(parameters)) { + [mutablePairs addObject:[pair URLEncodedStringValueWithEncoding:stringEncoding]]; + } + + return [mutablePairs componentsJoinedByString:@"&"]; +} + +NSArray * AFQueryStringPairsFromDictionary(NSDictionary *dictionary) { + return AFQueryStringPairsFromKeyAndValue(nil, dictionary); +} + +NSArray * AFQueryStringPairsFromKeyAndValue(NSString *key, id value) { + NSMutableArray *mutableQueryStringComponents = [NSMutableArray array]; + + NSSortDescriptor *sortDescriptor = [NSSortDescriptor sortDescriptorWithKey:@"description" ascending:YES selector:@selector(compare:)]; + + if ([value isKindOfClass:[NSDictionary class]]) { + NSDictionary *dictionary = value; + // Sort dictionary keys to ensure consistent ordering in query string, which is important when deserializing potentially ambiguous sequences, such as an array of dictionaries + for (id nestedKey in [dictionary.allKeys sortedArrayUsingDescriptors:@[ sortDescriptor ]]) { + id nestedValue = [dictionary objectForKey:nestedKey]; + if (nestedValue) { + [mutableQueryStringComponents addObjectsFromArray:AFQueryStringPairsFromKeyAndValue((key ? [NSString stringWithFormat:@"%@[%@]", key, nestedKey] : nestedKey), nestedValue)]; + } + } + } else if ([value isKindOfClass:[NSArray class]]) { + NSArray *array = value; + for (id nestedValue in array) { + [mutableQueryStringComponents addObjectsFromArray:AFQueryStringPairsFromKeyAndValue([NSString stringWithFormat:@"%@[]", key], nestedValue)]; + } + } else if ([value isKindOfClass:[NSSet class]]) { + NSSet *set = value; + for (id obj in [set sortedArrayUsingDescriptors:@[ sortDescriptor ]]) { + [mutableQueryStringComponents addObjectsFromArray:AFQueryStringPairsFromKeyAndValue(key, obj)]; + } + } else { + [mutableQueryStringComponents addObject:[[AFQueryStringPair alloc] initWithField:key value:value]]; + } + + return mutableQueryStringComponents; +} + +#pragma mark - + +@interface AFStreamingMultipartFormData : NSObject +- (instancetype)initWithURLRequest:(NSMutableURLRequest *)urlRequest + stringEncoding:(NSStringEncoding)encoding; + +- (NSMutableURLRequest *)requestByFinalizingMultipartFormData; +@end + +#pragma mark - + +@interface AFHTTPRequestSerializer () +@property (readwrite, nonatomic, strong) NSMutableDictionary *mutableHTTPRequestHeaders; +@property (readwrite, nonatomic, assign) AFHTTPRequestQueryStringSerializationStyle queryStringSerializationStyle; +@property (readwrite, nonatomic, copy) AFQueryStringSerializationBlock queryStringSerialization; +@end + +@implementation AFHTTPRequestSerializer + ++ (instancetype)serializer { + return [[self alloc] init]; +} + +- (instancetype)init { + self = [super init]; + if (!self) { + return nil; + } + + self.stringEncoding = NSUTF8StringEncoding; + self.allowsCellularAccess = YES; + self.cachePolicy = NSURLRequestUseProtocolCachePolicy; + self.HTTPShouldHandleCookies = YES; + self.HTTPShouldUsePipelining = NO; + self.networkServiceType = NSURLNetworkServiceTypeDefault; + self.timeoutInterval = 60; + + self.mutableHTTPRequestHeaders = [NSMutableDictionary dictionary]; + + // Accept-Language HTTP Header; see http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.4 + NSMutableArray *acceptLanguagesComponents = [NSMutableArray array]; + [[NSLocale preferredLanguages] enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) { + float q = 1.0f - (idx * 0.1f); + [acceptLanguagesComponents addObject:[NSString stringWithFormat:@"%@;q=%0.1g", obj, q]]; + *stop = q <= 0.5f; + }]; + [self setValue:[acceptLanguagesComponents componentsJoinedByString:@", "] forHTTPHeaderField:@"Accept-Language"]; + + NSString *userAgent = nil; +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wgnu" +#if defined(__IPHONE_OS_VERSION_MIN_REQUIRED) + // User-Agent Header; see http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.43 + userAgent = [NSString stringWithFormat:@"%@/%@ (%@; iOS %@; Scale/%0.2f)", [[[NSBundle mainBundle] infoDictionary] objectForKey:(__bridge NSString *)kCFBundleExecutableKey] ?: [[[NSBundle mainBundle] infoDictionary] objectForKey:(__bridge NSString *)kCFBundleIdentifierKey], (__bridge id)CFBundleGetValueForInfoDictionaryKey(CFBundleGetMainBundle(), kCFBundleVersionKey) ?: [[[NSBundle mainBundle] infoDictionary] objectForKey:(__bridge NSString *)kCFBundleVersionKey], [[UIDevice currentDevice] model], [[UIDevice currentDevice] systemVersion], [[UIScreen mainScreen] scale]]; +#elif defined(__MAC_OS_X_VERSION_MIN_REQUIRED) + userAgent = [NSString stringWithFormat:@"%@/%@ (Mac OS X %@)", [[[NSBundle mainBundle] infoDictionary] objectForKey:(__bridge NSString *)kCFBundleExecutableKey] ?: [[[NSBundle mainBundle] infoDictionary] objectForKey:(__bridge NSString *)kCFBundleIdentifierKey], [[[NSBundle mainBundle] infoDictionary] objectForKey:@"CFBundleShortVersionString"] ?: [[[NSBundle mainBundle] infoDictionary] objectForKey:(__bridge NSString *)kCFBundleVersionKey], [[NSProcessInfo processInfo] operatingSystemVersionString]]; +#endif +#pragma clang diagnostic pop + if (userAgent) { + if (![userAgent canBeConvertedToEncoding:NSASCIIStringEncoding]) { + NSMutableString *mutableUserAgent = [userAgent mutableCopy]; + if (CFStringTransform((__bridge CFMutableStringRef)(mutableUserAgent), NULL, (__bridge CFStringRef)@"Any-Latin; Latin-ASCII; [:^ASCII:] Remove", false)) { + userAgent = mutableUserAgent; + } + } + [self setValue:userAgent forHTTPHeaderField:@"User-Agent"]; + } + + // HTTP Method Definitions; see http://www.w3.org/Protocols/rfc2616/rfc2616-sec9.html + self.HTTPMethodsEncodingParametersInURI = [NSSet setWithObjects:@"GET", @"HEAD", @"DELETE", nil]; + + return self; +} + +#pragma mark - + +- (NSDictionary *)HTTPRequestHeaders { + return [NSDictionary dictionaryWithDictionary:self.mutableHTTPRequestHeaders]; +} + +- (void)setValue:(NSString *)value forHTTPHeaderField:(NSString *)field { + [self.mutableHTTPRequestHeaders setValue:value forKey:field]; +} + +- (void)setAuthorizationHeaderFieldWithUsername:(NSString *)username password:(NSString *)password { + NSString *basicAuthCredentials = [NSString stringWithFormat:@"%@:%@", username, password]; + [self setValue:[NSString stringWithFormat:@"Basic %@", AFBase64EncodedStringFromString(basicAuthCredentials)] forHTTPHeaderField:@"Authorization"]; +} + +- (void)setAuthorizationHeaderFieldWithToken:(NSString *)token { + [self setValue:[NSString stringWithFormat:@"Token token=\"%@\"", token] forHTTPHeaderField:@"Authorization"]; +} + +- (void)clearAuthorizationHeader { + [self.mutableHTTPRequestHeaders removeObjectForKey:@"Authorization"]; +} + +#pragma mark - + +- (void)setQueryStringSerializationWithStyle:(AFHTTPRequestQueryStringSerializationStyle)style { + self.queryStringSerializationStyle = style; + self.queryStringSerialization = nil; +} + +- (void)setQueryStringSerializationWithBlock:(NSString *(^)(NSURLRequest *, NSDictionary *, NSError *__autoreleasing *))block { + self.queryStringSerialization = block; +} + +#pragma mark - + +- (NSMutableURLRequest *)requestWithMethod:(NSString *)method + URLString:(NSString *)URLString + parameters:(id)parameters +{ + return [self requestWithMethod:method URLString:URLString parameters:parameters error:nil]; +} + +- (NSMutableURLRequest *)requestWithMethod:(NSString *)method + URLString:(NSString *)URLString + parameters:(id)parameters + error:(NSError *__autoreleasing *)error +{ + NSParameterAssert(method); + NSParameterAssert(URLString); + + NSURL *url = [NSURL URLWithString:URLString]; + + NSParameterAssert(url); + + NSMutableURLRequest *mutableRequest = [[NSMutableURLRequest alloc] initWithURL:url]; + mutableRequest.HTTPMethod = method; + mutableRequest.allowsCellularAccess = self.allowsCellularAccess; + mutableRequest.cachePolicy = self.cachePolicy; + mutableRequest.HTTPShouldHandleCookies = self.HTTPShouldHandleCookies; + mutableRequest.HTTPShouldUsePipelining = self.HTTPShouldUsePipelining; + mutableRequest.networkServiceType = self.networkServiceType; + mutableRequest.timeoutInterval = self.timeoutInterval; + + mutableRequest = [[self requestBySerializingRequest:mutableRequest withParameters:parameters error:error] mutableCopy]; + + return mutableRequest; +} + +- (NSMutableURLRequest *)multipartFormRequestWithMethod:(NSString *)method + URLString:(NSString *)URLString + parameters:(NSDictionary *)parameters + constructingBodyWithBlock:(void (^)(id formData))block +{ + return [self multipartFormRequestWithMethod:method URLString:URLString parameters:parameters constructingBodyWithBlock:block error:nil]; +} + +- (NSMutableURLRequest *)multipartFormRequestWithMethod:(NSString *)method + URLString:(NSString *)URLString + parameters:(NSDictionary *)parameters + constructingBodyWithBlock:(void (^)(id formData))block + error:(NSError *__autoreleasing *)error +{ + NSParameterAssert(method); + NSParameterAssert(![method isEqualToString:@"GET"] && ![method isEqualToString:@"HEAD"]); + + NSMutableURLRequest *mutableRequest = [self requestWithMethod:method URLString:URLString parameters:nil error:error]; + + __block AFStreamingMultipartFormData *formData = [[AFStreamingMultipartFormData alloc] initWithURLRequest:mutableRequest stringEncoding:NSUTF8StringEncoding]; + + if (parameters) { + for (AFQueryStringPair *pair in AFQueryStringPairsFromDictionary(parameters)) { + NSData *data = nil; + if ([pair.value isKindOfClass:[NSData class]]) { + data = pair.value; + } else if ([pair.value isEqual:[NSNull null]]) { + data = [NSData data]; + } else { + data = [[pair.value description] dataUsingEncoding:self.stringEncoding]; + } + + if (data) { + [formData appendPartWithFormData:data name:[pair.field description]]; + } + } + } + + if (block) { + block(formData); + } + + return [formData requestByFinalizingMultipartFormData]; +} + +- (NSMutableURLRequest *)requestWithMultipartFormRequest:(NSURLRequest *)request + writingStreamContentsToFile:(NSURL *)fileURL + completionHandler:(void (^)(NSError *error))handler +{ + if (!request.HTTPBodyStream) { + return [request mutableCopy]; + } + + NSParameterAssert([fileURL isFileURL]); + + NSInputStream *inputStream = request.HTTPBodyStream; + NSOutputStream *outputStream = [[NSOutputStream alloc] initWithURL:fileURL append:NO]; + __block NSError *error = nil; + + dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ + [inputStream scheduleInRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode]; + [outputStream scheduleInRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode]; + + [inputStream open]; + [outputStream open]; + + while ([inputStream hasBytesAvailable] && [outputStream hasSpaceAvailable]) { + uint8_t buffer[1024]; + + NSInteger bytesRead = [inputStream read:buffer maxLength:1024]; + if (inputStream.streamError || bytesRead < 0) { + error = inputStream.streamError; + break; + } + + NSInteger bytesWritten = [outputStream write:buffer maxLength:(NSUInteger)bytesRead]; + if (outputStream.streamError || bytesWritten < 0) { + error = outputStream.streamError; + break; + } + + if (bytesRead == 0 && bytesWritten == 0) { + break; + } + } + + [outputStream close]; + [inputStream close]; + + if (handler) { + dispatch_async(dispatch_get_main_queue(), ^{ + handler(error); + }); + } + }); + + NSMutableURLRequest *mutableRequest = [request mutableCopy]; + mutableRequest.HTTPBodyStream = nil; + + return mutableRequest; +} + +#pragma mark - AFURLRequestSerialization + +- (NSURLRequest *)requestBySerializingRequest:(NSURLRequest *)request + withParameters:(id)parameters + error:(NSError *__autoreleasing *)error +{ + NSParameterAssert(request); + + NSMutableURLRequest *mutableRequest = [request mutableCopy]; + + [self.HTTPRequestHeaders enumerateKeysAndObjectsUsingBlock:^(id field, id value, BOOL * __unused stop) { + if (![request valueForHTTPHeaderField:field]) { + [mutableRequest setValue:value forHTTPHeaderField:field]; + } + }]; + + if (parameters) { + NSString *query = nil; + if (self.queryStringSerialization) { + query = self.queryStringSerialization(request, parameters, error); + } else { + switch (self.queryStringSerializationStyle) { + case AFHTTPRequestQueryStringDefaultStyle: + query = AFQueryStringFromParametersWithEncoding(parameters, self.stringEncoding); + break; + } + } + + if ([self.HTTPMethodsEncodingParametersInURI containsObject:[[request HTTPMethod] uppercaseString]]) { + mutableRequest.URL = [NSURL URLWithString:[[mutableRequest.URL absoluteString] stringByAppendingFormat:mutableRequest.URL.query ? @"&%@" : @"?%@", query]]; + } else { + if (![mutableRequest valueForHTTPHeaderField:@"Content-Type"]) { + NSString *charset = (__bridge NSString *)CFStringConvertEncodingToIANACharSetName(CFStringConvertNSStringEncodingToEncoding(self.stringEncoding)); + [mutableRequest setValue:[NSString stringWithFormat:@"application/x-www-form-urlencoded; charset=%@", charset] forHTTPHeaderField:@"Content-Type"]; + } + [mutableRequest setHTTPBody:[query dataUsingEncoding:self.stringEncoding]]; + } + } + + return mutableRequest; +} + +#pragma mark - NSecureCoding + ++ (BOOL)supportsSecureCoding { + return YES; +} + +- (id)initWithCoder:(NSCoder *)decoder { + self = [self init]; + if (!self) { + return nil; + } + + self.mutableHTTPRequestHeaders = [[decoder decodeObjectOfClass:[NSDictionary class] forKey:NSStringFromSelector(@selector(mutableHTTPRequestHeaders))] mutableCopy]; + self.queryStringSerializationStyle = [[decoder decodeObjectOfClass:[NSNumber class] forKey:NSStringFromSelector(@selector(queryStringSerializationStyle))] unsignedIntegerValue]; + + return self; +} + +- (void)encodeWithCoder:(NSCoder *)coder { + [coder encodeObject:self.mutableHTTPRequestHeaders forKey:NSStringFromSelector(@selector(mutableHTTPRequestHeaders))]; + [coder encodeInteger:self.queryStringSerializationStyle forKey:NSStringFromSelector(@selector(queryStringSerializationStyle))]; +} + +#pragma mark - NSCopying + +- (id)copyWithZone:(NSZone *)zone { + AFHTTPRequestSerializer *serializer = [[[self class] allocWithZone:zone] init]; + serializer.mutableHTTPRequestHeaders = [self.mutableHTTPRequestHeaders mutableCopyWithZone:zone]; + serializer.queryStringSerializationStyle = self.queryStringSerializationStyle; + serializer.queryStringSerialization = self.queryStringSerialization; + + return serializer; +} + +@end + +#pragma mark - + +static NSString * AFCreateMultipartFormBoundary() { + return [NSString stringWithFormat:@"Boundary+%08X%08X", arc4random(), arc4random()]; +} + +static NSString * const kAFMultipartFormCRLF = @"\r\n"; + +static inline NSString * AFMultipartFormInitialBoundary(NSString *boundary) { + return [NSString stringWithFormat:@"--%@%@", boundary, kAFMultipartFormCRLF]; +} + +static inline NSString * AFMultipartFormEncapsulationBoundary(NSString *boundary) { + return [NSString stringWithFormat:@"%@--%@%@", kAFMultipartFormCRLF, boundary, kAFMultipartFormCRLF]; +} + +static inline NSString * AFMultipartFormFinalBoundary(NSString *boundary) { + return [NSString stringWithFormat:@"%@--%@--%@", kAFMultipartFormCRLF, boundary, kAFMultipartFormCRLF]; +} + +static inline NSString * AFContentTypeForPathExtension(NSString *extension) { +#ifdef __UTTYPE__ + NSString *UTI = (__bridge_transfer NSString *)UTTypeCreatePreferredIdentifierForTag(kUTTagClassFilenameExtension, (__bridge CFStringRef)extension, NULL); + NSString *contentType = (__bridge_transfer NSString *)UTTypeCopyPreferredTagWithClass((__bridge CFStringRef)UTI, kUTTagClassMIMEType); + if (!contentType) { + return @"application/octet-stream"; + } else { + return contentType; + } +#else +#pragma unused (extension) + return @"application/octet-stream"; +#endif +} + +NSUInteger const kAFUploadStream3GSuggestedPacketSize = 1024 * 16; +NSTimeInterval const kAFUploadStream3GSuggestedDelay = 0.2; + +@interface AFHTTPBodyPart : NSObject +@property (nonatomic, assign) NSStringEncoding stringEncoding; +@property (nonatomic, strong) NSDictionary *headers; +@property (nonatomic, copy) NSString *boundary; +@property (nonatomic, strong) id body; +@property (nonatomic, assign) unsigned long long bodyContentLength; +@property (nonatomic, strong) NSInputStream *inputStream; + +@property (nonatomic, assign) BOOL hasInitialBoundary; +@property (nonatomic, assign) BOOL hasFinalBoundary; + +@property (readonly, nonatomic, assign, getter = hasBytesAvailable) BOOL bytesAvailable; +@property (readonly, nonatomic, assign) unsigned long long contentLength; + +- (NSInteger)read:(uint8_t *)buffer + maxLength:(NSUInteger)length; +@end + +@interface AFMultipartBodyStream : NSInputStream +@property (nonatomic, assign) NSUInteger numberOfBytesInPacket; +@property (nonatomic, assign) NSTimeInterval delay; +@property (nonatomic, strong) NSInputStream *inputStream; +@property (readonly, nonatomic, assign) unsigned long long contentLength; +@property (readonly, nonatomic, assign, getter = isEmpty) BOOL empty; + +- (id)initWithStringEncoding:(NSStringEncoding)encoding; +- (void)setInitialAndFinalBoundaries; +- (void)appendHTTPBodyPart:(AFHTTPBodyPart *)bodyPart; +@end + +#pragma mark - + +@interface AFStreamingMultipartFormData () +@property (readwrite, nonatomic, copy) NSMutableURLRequest *request; +@property (readwrite, nonatomic, assign) NSStringEncoding stringEncoding; +@property (readwrite, nonatomic, copy) NSString *boundary; +@property (readwrite, nonatomic, strong) AFMultipartBodyStream *bodyStream; +@end + +@implementation AFStreamingMultipartFormData + +- (id)initWithURLRequest:(NSMutableURLRequest *)urlRequest + stringEncoding:(NSStringEncoding)encoding +{ + self = [super init]; + if (!self) { + return nil; + } + + self.request = urlRequest; + self.stringEncoding = encoding; + self.boundary = AFCreateMultipartFormBoundary(); + self.bodyStream = [[AFMultipartBodyStream alloc] initWithStringEncoding:encoding]; + + return self; +} + +- (BOOL)appendPartWithFileURL:(NSURL *)fileURL + name:(NSString *)name + error:(NSError * __autoreleasing *)error +{ + NSParameterAssert(fileURL); + NSParameterAssert(name); + + NSString *fileName = [fileURL lastPathComponent]; + NSString *mimeType = AFContentTypeForPathExtension([fileURL pathExtension]); + + return [self appendPartWithFileURL:fileURL name:name fileName:fileName mimeType:mimeType error:error]; +} + +- (BOOL)appendPartWithFileURL:(NSURL *)fileURL + name:(NSString *)name + fileName:(NSString *)fileName + mimeType:(NSString *)mimeType + error:(NSError * __autoreleasing *)error +{ + NSParameterAssert(fileURL); + NSParameterAssert(name); + NSParameterAssert(fileName); + NSParameterAssert(mimeType); + + if (![fileURL isFileURL]) { + NSDictionary *userInfo = @{NSLocalizedFailureReasonErrorKey: NSLocalizedStringFromTable(@"Expected URL to be a file URL", @"AFNetworking", nil)}; + if (error) { + *error = [[NSError alloc] initWithDomain:AFURLRequestSerializationErrorDomain code:NSURLErrorBadURL userInfo:userInfo]; + } + + return NO; + } else if ([fileURL checkResourceIsReachableAndReturnError:error] == NO) { + NSDictionary *userInfo = @{NSLocalizedFailureReasonErrorKey: NSLocalizedStringFromTable(@"File URL not reachable.", @"AFNetworking", nil)}; + if (error) { + *error = [[NSError alloc] initWithDomain:AFURLRequestSerializationErrorDomain code:NSURLErrorBadURL userInfo:userInfo]; + } + + return NO; + } + + NSDictionary *fileAttributes = [[NSFileManager defaultManager] attributesOfItemAtPath:[fileURL path] error:error]; + if (!fileAttributes) { + return NO; + } + + NSMutableDictionary *mutableHeaders = [NSMutableDictionary dictionary]; + [mutableHeaders setValue:[NSString stringWithFormat:@"form-data; name=\"%@\"; filename=\"%@\"", name, fileName] forKey:@"Content-Disposition"]; + [mutableHeaders setValue:mimeType forKey:@"Content-Type"]; + + AFHTTPBodyPart *bodyPart = [[AFHTTPBodyPart alloc] init]; + bodyPart.stringEncoding = self.stringEncoding; + bodyPart.headers = mutableHeaders; + bodyPart.boundary = self.boundary; + bodyPart.body = fileURL; + bodyPart.bodyContentLength = [[fileAttributes objectForKey:NSFileSize] unsignedLongLongValue]; + [self.bodyStream appendHTTPBodyPart:bodyPart]; + + return YES; +} + +- (void)appendPartWithInputStream:(NSInputStream *)inputStream + name:(NSString *)name + fileName:(NSString *)fileName + length:(int64_t)length + mimeType:(NSString *)mimeType +{ + NSParameterAssert(name); + NSParameterAssert(fileName); + NSParameterAssert(mimeType); + + NSMutableDictionary *mutableHeaders = [NSMutableDictionary dictionary]; + [mutableHeaders setValue:[NSString stringWithFormat:@"form-data; name=\"%@\"; filename=\"%@\"", name, fileName] forKey:@"Content-Disposition"]; + [mutableHeaders setValue:mimeType forKey:@"Content-Type"]; + + + AFHTTPBodyPart *bodyPart = [[AFHTTPBodyPart alloc] init]; + bodyPart.stringEncoding = self.stringEncoding; + bodyPart.headers = mutableHeaders; + bodyPart.boundary = self.boundary; + bodyPart.body = inputStream; + + bodyPart.bodyContentLength = (unsigned long long)length; + + [self.bodyStream appendHTTPBodyPart:bodyPart]; +} + +- (void)appendPartWithFileData:(NSData *)data + name:(NSString *)name + fileName:(NSString *)fileName + mimeType:(NSString *)mimeType +{ + NSParameterAssert(name); + NSParameterAssert(fileName); + NSParameterAssert(mimeType); + + NSMutableDictionary *mutableHeaders = [NSMutableDictionary dictionary]; + [mutableHeaders setValue:[NSString stringWithFormat:@"form-data; name=\"%@\"; filename=\"%@\"", name, fileName] forKey:@"Content-Disposition"]; + [mutableHeaders setValue:mimeType forKey:@"Content-Type"]; + + [self appendPartWithHeaders:mutableHeaders body:data]; +} + +- (void)appendPartWithFormData:(NSData *)data + name:(NSString *)name +{ + NSParameterAssert(name); + + NSMutableDictionary *mutableHeaders = [NSMutableDictionary dictionary]; + [mutableHeaders setValue:[NSString stringWithFormat:@"form-data; name=\"%@\"", name] forKey:@"Content-Disposition"]; + + [self appendPartWithHeaders:mutableHeaders body:data]; +} + +- (void)appendPartWithHeaders:(NSDictionary *)headers + body:(NSData *)body +{ + NSParameterAssert(body); + + AFHTTPBodyPart *bodyPart = [[AFHTTPBodyPart alloc] init]; + bodyPart.stringEncoding = self.stringEncoding; + bodyPart.headers = headers; + bodyPart.boundary = self.boundary; + bodyPart.bodyContentLength = [body length]; + bodyPart.body = body; + + [self.bodyStream appendHTTPBodyPart:bodyPart]; +} + +- (void)throttleBandwidthWithPacketSize:(NSUInteger)numberOfBytes + delay:(NSTimeInterval)delay +{ + self.bodyStream.numberOfBytesInPacket = numberOfBytes; + self.bodyStream.delay = delay; +} + +- (NSMutableURLRequest *)requestByFinalizingMultipartFormData { + if ([self.bodyStream isEmpty]) { + return self.request; + } + + // Reset the initial and final boundaries to ensure correct Content-Length + [self.bodyStream setInitialAndFinalBoundaries]; + [self.request setHTTPBodyStream:self.bodyStream]; + + [self.request setValue:[NSString stringWithFormat:@"multipart/form-data; boundary=%@", self.boundary] forHTTPHeaderField:@"Content-Type"]; + [self.request setValue:[NSString stringWithFormat:@"%llu", [self.bodyStream contentLength]] forHTTPHeaderField:@"Content-Length"]; + + return self.request; +} + +@end + +#pragma mark - + +@interface NSStream () +@property (readwrite) NSStreamStatus streamStatus; +@property (readwrite, copy) NSError *streamError; +@end + +@interface AFMultipartBodyStream () +@property (readwrite, nonatomic, assign) NSStringEncoding stringEncoding; +@property (readwrite, nonatomic, strong) NSMutableArray *HTTPBodyParts; +@property (readwrite, nonatomic, strong) NSEnumerator *HTTPBodyPartEnumerator; +@property (readwrite, nonatomic, strong) AFHTTPBodyPart *currentHTTPBodyPart; +@property (readwrite, nonatomic, strong) NSOutputStream *outputStream; +@property (readwrite, nonatomic, strong) NSMutableData *buffer; +@end + +@implementation AFMultipartBodyStream +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wimplicit-atomic-properties" +@synthesize streamStatus; +@synthesize streamError; +#pragma clang diagnostic pop + +- (id)initWithStringEncoding:(NSStringEncoding)encoding { + self = [super init]; + if (!self) { + return nil; + } + + self.stringEncoding = encoding; + self.HTTPBodyParts = [NSMutableArray array]; + self.numberOfBytesInPacket = NSIntegerMax; + + return self; +} + +- (void)setInitialAndFinalBoundaries { + if ([self.HTTPBodyParts count] > 0) { + for (AFHTTPBodyPart *bodyPart in self.HTTPBodyParts) { + bodyPart.hasInitialBoundary = NO; + bodyPart.hasFinalBoundary = NO; + } + + [[self.HTTPBodyParts objectAtIndex:0] setHasInitialBoundary:YES]; + [[self.HTTPBodyParts lastObject] setHasFinalBoundary:YES]; + } +} + +- (void)appendHTTPBodyPart:(AFHTTPBodyPart *)bodyPart { + [self.HTTPBodyParts addObject:bodyPart]; +} + +- (BOOL)isEmpty { + return [self.HTTPBodyParts count] == 0; +} + +#pragma mark - NSInputStream + +- (NSInteger)read:(uint8_t *)buffer + maxLength:(NSUInteger)length +{ + if ([self streamStatus] == NSStreamStatusClosed) { + return 0; + } + + NSInteger totalNumberOfBytesRead = 0; + +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wgnu" + while ((NSUInteger)totalNumberOfBytesRead < MIN(length, self.numberOfBytesInPacket)) { + if (!self.currentHTTPBodyPart || ![self.currentHTTPBodyPart hasBytesAvailable]) { + if (!(self.currentHTTPBodyPart = [self.HTTPBodyPartEnumerator nextObject])) { + break; + } + } else { + NSUInteger maxLength = length - (NSUInteger)totalNumberOfBytesRead; + NSInteger numberOfBytesRead = [self.currentHTTPBodyPart read:&buffer[totalNumberOfBytesRead] maxLength:maxLength]; + if (numberOfBytesRead == -1) { + self.streamError = self.currentHTTPBodyPart.inputStream.streamError; + break; + } else { + totalNumberOfBytesRead += numberOfBytesRead; + + if (self.delay > 0.0f) { + [NSThread sleepForTimeInterval:self.delay]; + } + } + } + } +#pragma clang diagnostic pop + + return totalNumberOfBytesRead; +} + +- (BOOL)getBuffer:(__unused uint8_t **)buffer + length:(__unused NSUInteger *)len +{ + return NO; +} + +- (BOOL)hasBytesAvailable { + return [self streamStatus] == NSStreamStatusOpen; +} + +#pragma mark - NSStream + +- (void)open { + if (self.streamStatus == NSStreamStatusOpen) { + return; + } + + self.streamStatus = NSStreamStatusOpen; + + [self setInitialAndFinalBoundaries]; + self.HTTPBodyPartEnumerator = [self.HTTPBodyParts objectEnumerator]; +} + +- (void)close { + self.streamStatus = NSStreamStatusClosed; +} + +- (id)propertyForKey:(__unused NSString *)key { + return nil; +} + +- (BOOL)setProperty:(__unused id)property + forKey:(__unused NSString *)key +{ + return NO; +} + +- (void)scheduleInRunLoop:(__unused NSRunLoop *)aRunLoop + forMode:(__unused NSString *)mode +{} + +- (void)removeFromRunLoop:(__unused NSRunLoop *)aRunLoop + forMode:(__unused NSString *)mode +{} + +- (unsigned long long)contentLength { + unsigned long long length = 0; + for (AFHTTPBodyPart *bodyPart in self.HTTPBodyParts) { + length += [bodyPart contentLength]; + } + + return length; +} + +#pragma mark - Undocumented CFReadStream Bridged Methods + +- (void)_scheduleInCFRunLoop:(__unused CFRunLoopRef)aRunLoop + forMode:(__unused CFStringRef)aMode +{} + +- (void)_unscheduleFromCFRunLoop:(__unused CFRunLoopRef)aRunLoop + forMode:(__unused CFStringRef)aMode +{} + +- (BOOL)_setCFClientFlags:(__unused CFOptionFlags)inFlags + callback:(__unused CFReadStreamClientCallBack)inCallback + context:(__unused CFStreamClientContext *)inContext { + return NO; +} + +#pragma mark - NSCopying + +-(id)copyWithZone:(NSZone *)zone { + AFMultipartBodyStream *bodyStreamCopy = [[[self class] allocWithZone:zone] initWithStringEncoding:self.stringEncoding]; + + for (AFHTTPBodyPart *bodyPart in self.HTTPBodyParts) { + [bodyStreamCopy appendHTTPBodyPart:[bodyPart copy]]; + } + + [bodyStreamCopy setInitialAndFinalBoundaries]; + + return bodyStreamCopy; +} + +@end + +#pragma mark - + +typedef enum { + AFEncapsulationBoundaryPhase = 1, + AFHeaderPhase = 2, + AFBodyPhase = 3, + AFFinalBoundaryPhase = 4, +} AFHTTPBodyPartReadPhase; + +@interface AFHTTPBodyPart () { + AFHTTPBodyPartReadPhase _phase; + NSInputStream *_inputStream; + unsigned long long _phaseReadOffset; +} + +- (BOOL)transitionToNextPhase; +- (NSInteger)readData:(NSData *)data + intoBuffer:(uint8_t *)buffer + maxLength:(NSUInteger)length; +@end + +@implementation AFHTTPBodyPart + +- (id)init { + self = [super init]; + if (!self) { + return nil; + } + + [self transitionToNextPhase]; + + return self; +} + +- (void)dealloc { + if (_inputStream) { + [_inputStream close]; + _inputStream = nil; + } +} + +- (NSInputStream *)inputStream { + if (!_inputStream) { + if ([self.body isKindOfClass:[NSData class]]) { + _inputStream = [NSInputStream inputStreamWithData:self.body]; + } else if ([self.body isKindOfClass:[NSURL class]]) { + _inputStream = [NSInputStream inputStreamWithURL:self.body]; + } else if ([self.body isKindOfClass:[NSInputStream class]]) { + _inputStream = self.body; + } + } + + return _inputStream; +} + +- (NSString *)stringForHeaders { + NSMutableString *headerString = [NSMutableString string]; + for (NSString *field in [self.headers allKeys]) { + [headerString appendString:[NSString stringWithFormat:@"%@: %@%@", field, [self.headers valueForKey:field], kAFMultipartFormCRLF]]; + } + [headerString appendString:kAFMultipartFormCRLF]; + + return [NSString stringWithString:headerString]; +} + +- (unsigned long long)contentLength { + unsigned long long length = 0; + + NSData *encapsulationBoundaryData = [([self hasInitialBoundary] ? AFMultipartFormInitialBoundary(self.boundary) : AFMultipartFormEncapsulationBoundary(self.boundary)) dataUsingEncoding:self.stringEncoding]; + length += [encapsulationBoundaryData length]; + + NSData *headersData = [[self stringForHeaders] dataUsingEncoding:self.stringEncoding]; + length += [headersData length]; + + length += _bodyContentLength; + + NSData *closingBoundaryData = ([self hasFinalBoundary] ? [AFMultipartFormFinalBoundary(self.boundary) dataUsingEncoding:self.stringEncoding] : [NSData data]); + length += [closingBoundaryData length]; + + return length; +} + +- (BOOL)hasBytesAvailable { + // Allows `read:maxLength:` to be called again if `AFMultipartFormFinalBoundary` doesn't fit into the available buffer + if (_phase == AFFinalBoundaryPhase) { + return YES; + } + +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wcovered-switch-default" + switch (self.inputStream.streamStatus) { + case NSStreamStatusNotOpen: + case NSStreamStatusOpening: + case NSStreamStatusOpen: + case NSStreamStatusReading: + case NSStreamStatusWriting: + return YES; + case NSStreamStatusAtEnd: + case NSStreamStatusClosed: + case NSStreamStatusError: + default: + return NO; + } +#pragma clang diagnostic pop +} + +- (NSInteger)read:(uint8_t *)buffer + maxLength:(NSUInteger)length +{ + NSInteger totalNumberOfBytesRead = 0; + + if (_phase == AFEncapsulationBoundaryPhase) { + NSData *encapsulationBoundaryData = [([self hasInitialBoundary] ? AFMultipartFormInitialBoundary(self.boundary) : AFMultipartFormEncapsulationBoundary(self.boundary)) dataUsingEncoding:self.stringEncoding]; + totalNumberOfBytesRead += [self readData:encapsulationBoundaryData intoBuffer:&buffer[totalNumberOfBytesRead] maxLength:(length - (NSUInteger)totalNumberOfBytesRead)]; + } + + if (_phase == AFHeaderPhase) { + NSData *headersData = [[self stringForHeaders] dataUsingEncoding:self.stringEncoding]; + totalNumberOfBytesRead += [self readData:headersData intoBuffer:&buffer[totalNumberOfBytesRead] maxLength:(length - (NSUInteger)totalNumberOfBytesRead)]; + } + + if (_phase == AFBodyPhase) { + NSInteger numberOfBytesRead = 0; + + numberOfBytesRead = [self.inputStream read:&buffer[totalNumberOfBytesRead] maxLength:(length - (NSUInteger)totalNumberOfBytesRead)]; + if (numberOfBytesRead == -1) { + return -1; + } else { + totalNumberOfBytesRead += numberOfBytesRead; + + if ([self.inputStream streamStatus] >= NSStreamStatusAtEnd) { + [self transitionToNextPhase]; + } + } + } + + if (_phase == AFFinalBoundaryPhase) { + NSData *closingBoundaryData = ([self hasFinalBoundary] ? [AFMultipartFormFinalBoundary(self.boundary) dataUsingEncoding:self.stringEncoding] : [NSData data]); + totalNumberOfBytesRead += [self readData:closingBoundaryData intoBuffer:&buffer[totalNumberOfBytesRead] maxLength:(length - (NSUInteger)totalNumberOfBytesRead)]; + } + + return totalNumberOfBytesRead; +} + +- (NSInteger)readData:(NSData *)data + intoBuffer:(uint8_t *)buffer + maxLength:(NSUInteger)length +{ +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wgnu" + NSRange range = NSMakeRange((NSUInteger)_phaseReadOffset, MIN([data length] - ((NSUInteger)_phaseReadOffset), length)); + [data getBytes:buffer range:range]; +#pragma clang diagnostic pop + + _phaseReadOffset += range.length; + + if (((NSUInteger)_phaseReadOffset) >= [data length]) { + [self transitionToNextPhase]; + } + + return (NSInteger)range.length; +} + +- (BOOL)transitionToNextPhase { + if (![[NSThread currentThread] isMainThread]) { + [self performSelectorOnMainThread:@selector(transitionToNextPhase) withObject:nil waitUntilDone:YES]; + return YES; + } + +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wcovered-switch-default" + switch (_phase) { + case AFEncapsulationBoundaryPhase: + _phase = AFHeaderPhase; + break; + case AFHeaderPhase: + [self.inputStream scheduleInRunLoop:[NSRunLoop currentRunLoop] forMode:NSRunLoopCommonModes]; + [self.inputStream open]; + _phase = AFBodyPhase; + break; + case AFBodyPhase: + [self.inputStream close]; + _phase = AFFinalBoundaryPhase; + break; + case AFFinalBoundaryPhase: + default: + _phase = AFEncapsulationBoundaryPhase; + break; + } + _phaseReadOffset = 0; +#pragma clang diagnostic pop + + return YES; +} + +#pragma mark - NSCopying + +- (id)copyWithZone:(NSZone *)zone { + AFHTTPBodyPart *bodyPart = [[[self class] allocWithZone:zone] init]; + + bodyPart.stringEncoding = self.stringEncoding; + bodyPart.headers = self.headers; + bodyPart.bodyContentLength = self.bodyContentLength; + bodyPart.body = self.body; + bodyPart.boundary = self.boundary; + + return bodyPart; +} + +@end + +#pragma mark - + +@implementation AFJSONRequestSerializer + ++ (instancetype)serializer { + return [self serializerWithWritingOptions:0]; +} + ++ (instancetype)serializerWithWritingOptions:(NSJSONWritingOptions)writingOptions +{ + AFJSONRequestSerializer *serializer = [[self alloc] init]; + serializer.writingOptions = writingOptions; + + return serializer; +} + +#pragma mark - AFURLRequestSerialization + +- (NSURLRequest *)requestBySerializingRequest:(NSURLRequest *)request + withParameters:(id)parameters + error:(NSError *__autoreleasing *)error +{ + NSParameterAssert(request); + + if ([self.HTTPMethodsEncodingParametersInURI containsObject:[[request HTTPMethod] uppercaseString]]) { + return [super requestBySerializingRequest:request withParameters:parameters error:error]; + } + + NSMutableURLRequest *mutableRequest = [request mutableCopy]; + + [self.HTTPRequestHeaders enumerateKeysAndObjectsUsingBlock:^(id field, id value, BOOL * __unused stop) { + if (![request valueForHTTPHeaderField:field]) { + [mutableRequest setValue:value forHTTPHeaderField:field]; + } + }]; + + if (parameters) { + if (![mutableRequest valueForHTTPHeaderField:@"Content-Type"]) { + NSString *charset = (__bridge NSString *)CFStringConvertEncodingToIANACharSetName(CFStringConvertNSStringEncodingToEncoding(NSUTF8StringEncoding)); + [mutableRequest setValue:[NSString stringWithFormat:@"application/json; charset=%@", charset] forHTTPHeaderField:@"Content-Type"]; + } + + [mutableRequest setHTTPBody:[NSJSONSerialization dataWithJSONObject:parameters options:self.writingOptions error:error]]; + } + + return mutableRequest; +} + +#pragma mark - NSecureCoding + +- (id)initWithCoder:(NSCoder *)decoder { + self = [super initWithCoder:decoder]; + if (!self) { + return nil; + } + + self.writingOptions = [[decoder decodeObjectOfClass:[NSNumber class] forKey:NSStringFromSelector(@selector(writingOptions))] unsignedIntegerValue]; + + return self; +} + +- (void)encodeWithCoder:(NSCoder *)coder { + [super encodeWithCoder:coder]; + + [coder encodeInteger:self.writingOptions forKey:NSStringFromSelector(@selector(writingOptions))]; +} + +#pragma mark - NSCopying + +- (id)copyWithZone:(NSZone *)zone { + AFJSONRequestSerializer *serializer = [super copyWithZone:zone]; + serializer.writingOptions = self.writingOptions; + + return serializer; +} + +@end + +#pragma mark - + +@implementation AFPropertyListRequestSerializer + ++ (instancetype)serializer { + return [self serializerWithFormat:NSPropertyListXMLFormat_v1_0 writeOptions:0]; +} + ++ (instancetype)serializerWithFormat:(NSPropertyListFormat)format + writeOptions:(NSPropertyListWriteOptions)writeOptions +{ + AFPropertyListRequestSerializer *serializer = [[self alloc] init]; + serializer.format = format; + serializer.writeOptions = writeOptions; + + return serializer; +} + +#pragma mark - AFURLRequestSerializer + +- (NSURLRequest *)requestBySerializingRequest:(NSURLRequest *)request + withParameters:(id)parameters + error:(NSError *__autoreleasing *)error +{ + NSParameterAssert(request); + + if ([self.HTTPMethodsEncodingParametersInURI containsObject:[[request HTTPMethod] uppercaseString]]) { + return [super requestBySerializingRequest:request withParameters:parameters error:error]; + } + + NSMutableURLRequest *mutableRequest = [request mutableCopy]; + + [self.HTTPRequestHeaders enumerateKeysAndObjectsUsingBlock:^(id field, id value, BOOL * __unused stop) { + if (![request valueForHTTPHeaderField:field]) { + [mutableRequest setValue:value forHTTPHeaderField:field]; + } + }]; + + if (parameters) { + if (![mutableRequest valueForHTTPHeaderField:@"Content-Type"]) { + NSString *charset = (__bridge NSString *)CFStringConvertEncodingToIANACharSetName(CFStringConvertNSStringEncodingToEncoding(NSUTF8StringEncoding)); + [mutableRequest setValue:[NSString stringWithFormat:@"application/x-plist; charset=%@", charset] forHTTPHeaderField:@"Content-Type"]; + } + + [mutableRequest setHTTPBody:[NSPropertyListSerialization dataWithPropertyList:parameters format:self.format options:self.writeOptions error:error]]; + } + + return mutableRequest; +} + +#pragma mark - NSecureCoding + +- (id)initWithCoder:(NSCoder *)decoder { + self = [super initWithCoder:decoder]; + if (!self) { + return nil; + } + + self.format = [[decoder decodeObjectOfClass:[NSNumber class] forKey:NSStringFromSelector(@selector(format))] unsignedIntegerValue]; + self.writeOptions = [[decoder decodeObjectOfClass:[NSNumber class] forKey:NSStringFromSelector(@selector(writeOptions))] unsignedIntegerValue]; + + return self; +} + +- (void)encodeWithCoder:(NSCoder *)coder { + [super encodeWithCoder:coder]; + + [coder encodeInteger:self.format forKey:NSStringFromSelector(@selector(format))]; + [coder encodeObject:@(self.writeOptions) forKey:NSStringFromSelector(@selector(writeOptions))]; +} + +#pragma mark - NSCopying + +- (id)copyWithZone:(NSZone *)zone { + AFPropertyListRequestSerializer *serializer = [super copyWithZone:zone]; + serializer.format = self.format; + serializer.writeOptions = self.writeOptions; + + return serializer; +} + +@end diff --git a/ios/Pods/AFNetworking/AFNetworking/AFURLResponseSerialization.h b/ios/Pods/AFNetworking/AFNetworking/AFURLResponseSerialization.h new file mode 100644 index 000000000..36ed33e5a --- /dev/null +++ b/ios/Pods/AFNetworking/AFNetworking/AFURLResponseSerialization.h @@ -0,0 +1,294 @@ +// AFSerialization.h +// +// Copyright (c) 2013-2014 AFNetworking (http://afnetworking.com) +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +#import +#import + +/** + The `AFURLResponseSerialization` protocol is adopted by an object that decodes data into a more useful object representation, according to details in the server response. Response serializers may additionally perform validation on the incoming response and data. + + For example, a JSON response serializer may check for an acceptable status code (`2XX` range) and content type (`application/json`), decoding a valid JSON response into an object. + */ +@protocol AFURLResponseSerialization + +/** + The response object decoded from the data associated with a specified response. + + @param response The response to be processed. + @param data The response data to be decoded. + @param error The error that occurred while attempting to decode the response data. + + @return The object decoded from the specified response data. + */ +- (id)responseObjectForResponse:(NSURLResponse *)response + data:(NSData *)data + error:(NSError *__autoreleasing *)error; + +@end + +#pragma mark - + +/** + `AFHTTPResponseSerializer` conforms to the `AFURLRequestSerialization` & `AFURLResponseSerialization` protocols, offering a concrete base implementation of query string / URL form-encoded parameter serialization and default request headers, as well as response status code and content type validation. + + Any request or response serializer dealing with HTTP is encouraged to subclass `AFHTTPResponseSerializer` in order to ensure consistent default behavior. + */ +@interface AFHTTPResponseSerializer : NSObject + +/** + The string encoding used to serialize parameters. + */ +@property (nonatomic, assign) NSStringEncoding stringEncoding; + +/** + Creates and returns a serializer with default configuration. + */ ++ (instancetype)serializer; + +///----------------------------------------- +/// @name Configuring Response Serialization +///----------------------------------------- + +/** + The acceptable HTTP status codes for responses. When non-`nil`, responses with status codes not contained by the set will result in an error during validation. + + See http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html + */ +@property (nonatomic, copy) NSIndexSet *acceptableStatusCodes; + +/** + The acceptable MIME types for responses. When non-`nil`, responses with a `Content-Type` with MIME types that do not intersect with the set will result in an error during validation. + */ +@property (nonatomic, copy) NSSet *acceptableContentTypes; + +/** + Validates the specified response and data. + + In its base implementation, this method checks for an acceptable status code and content type. Subclasses may wish to add other domain-specific checks. + + @param response The response to be validated. + @param data The data associated with the response. + @param error The error that occurred while attempting to validate the response. + + @return `YES` if the response is valid, otherwise `NO`. + */ +- (BOOL)validateResponse:(NSHTTPURLResponse *)response + data:(NSData *)data + error:(NSError *__autoreleasing *)error; + +@end + +#pragma mark - + + +/** + `AFJSONResponseSerializer` is a subclass of `AFHTTPResponseSerializer` that validates and decodes JSON responses. + + By default, `AFJSONResponseSerializer` accepts the following MIME types, which includes the official standard, `application/json`, as well as other commonly-used types: + + - `application/json` + - `text/json` + - `text/javascript` + */ +@interface AFJSONResponseSerializer : AFHTTPResponseSerializer + +/** + Options for reading the response JSON data and creating the Foundation objects. For possible values, see the `NSJSONSerialization` documentation section "NSJSONReadingOptions". `0` by default. + */ +@property (nonatomic, assign) NSJSONReadingOptions readingOptions; + +/** + Whether to remove keys with `NSNull` values from response JSON. Defaults to `NO`. + */ +@property (nonatomic, assign) BOOL removesKeysWithNullValues; + +/** + Creates and returns a JSON serializer with specified reading and writing options. + + @param readingOptions The specified JSON reading options. + */ ++ (instancetype)serializerWithReadingOptions:(NSJSONReadingOptions)readingOptions; + +@end + +#pragma mark - + +/** + `AFXMLParserSerializer` is a subclass of `AFHTTPResponseSerializer` that validates and decodes XML responses as an `NSXMLParser` objects. + + By default, `AFXMLParserSerializer` accepts the following MIME types, which includes the official standard, `application/xml`, as well as other commonly-used types: + + - `application/xml` + - `text/xml` + */ +@interface AFXMLParserResponseSerializer : AFHTTPResponseSerializer + +@end + +#pragma mark - + +#ifdef __MAC_OS_X_VERSION_MIN_REQUIRED + +/** + `AFXMLDocumentSerializer` is a subclass of `AFHTTPResponseSerializer` that validates and decodes XML responses as an `NSXMLDocument` objects. + + By default, `AFXMLDocumentSerializer` accepts the following MIME types, which includes the official standard, `application/xml`, as well as other commonly-used types: + + - `application/xml` + - `text/xml` + */ +@interface AFXMLDocumentResponseSerializer : AFHTTPResponseSerializer + +/** + Input and output options specifically intended for `NSXMLDocument` objects. For possible values, see the `NSJSONSerialization` documentation section "NSJSONReadingOptions". `0` by default. + */ +@property (nonatomic, assign) NSUInteger options; + +/** + Creates and returns an XML document serializer with the specified options. + + @param mask The XML document options. + */ ++ (instancetype)serializerWithXMLDocumentOptions:(NSUInteger)mask; + +@end + +#endif + +#pragma mark - + +/** + `AFPropertyListSerializer` is a subclass of `AFHTTPResponseSerializer` that validates and decodes XML responses as an `NSXMLDocument` objects. + + By default, `AFPropertyListSerializer` accepts the following MIME types: + + - `application/x-plist` + */ +@interface AFPropertyListResponseSerializer : AFHTTPResponseSerializer + +/** + The property list format. Possible values are described in "NSPropertyListFormat". + */ +@property (nonatomic, assign) NSPropertyListFormat format; + +/** + The property list reading options. Possible values are described in "NSPropertyListMutabilityOptions." + */ +@property (nonatomic, assign) NSPropertyListReadOptions readOptions; + +/** + Creates and returns a property list serializer with a specified format, read options, and write options. + + @param format The property list format. + @param readOptions The property list reading options. + */ ++ (instancetype)serializerWithFormat:(NSPropertyListFormat)format + readOptions:(NSPropertyListReadOptions)readOptions; + +@end + +#pragma mark - + +/** + `AFImageSerializer` is a subclass of `AFHTTPResponseSerializer` that validates and decodes image responses. + + By default, `AFImageSerializer` accepts the following MIME types, which correspond to the image formats supported by UIImage or NSImage: + + - `image/tiff` + - `image/jpeg` + - `image/gif` + - `image/png` + - `image/ico` + - `image/x-icon` + - `image/bmp` + - `image/x-bmp` + - `image/x-xbitmap` + - `image/x-win-bitmap` + */ +@interface AFImageResponseSerializer : AFHTTPResponseSerializer + +#if defined(__IPHONE_OS_VERSION_MIN_REQUIRED) +/** + The scale factor used when interpreting the image data to construct `responseImage`. Specifying a scale factor of 1.0 results in an image whose size matches the pixel-based dimensions of the image. Applying a different scale factor changes the size of the image as reported by the size property. This is set to the value of scale of the main screen by default, which automatically scales images for retina displays, for instance. + */ +@property (nonatomic, assign) CGFloat imageScale; + +/** + Whether to automatically inflate response image data for compressed formats (such as PNG or JPEG). Enabling this can significantly improve drawing performance on iOS when used with `setCompletionBlockWithSuccess:failure:`, as it allows a bitmap representation to be constructed in the background rather than on the main thread. `YES` by default. + */ +@property (nonatomic, assign) BOOL automaticallyInflatesResponseImage; +#endif + +@end + +#pragma mark - + +/** + `AFCompoundSerializer` is a subclass of `AFHTTPResponseSerializer` that delegates the response serialization to the first `AFHTTPResponseSerializer` object that returns an object for `responseObjectForResponse:data:error:`, falling back on the default behavior of `AFHTTPResponseSerializer`. This is useful for supporting multiple potential types and structures of server responses with a single serializer. + */ +@interface AFCompoundResponseSerializer : AFHTTPResponseSerializer + +/** + The component response serializers. + */ +@property (readonly, nonatomic, copy) NSArray *responseSerializers; + +/** + Creates and returns a compound serializer comprised of the specified response serializers. + + @warning Each response serializer specified must be a subclass of `AFHTTPResponseSerializer`, and response to `-validateResponse:data:error:`. + */ ++ (instancetype)compoundSerializerWithResponseSerializers:(NSArray *)responseSerializers; + +@end + +///---------------- +/// @name Constants +///---------------- + +/** + ## Error Domains + + The following error domain is predefined. + + - `NSString * const AFURLResponseSerializationErrorDomain` + + ### Constants + + `AFURLResponseSerializationErrorDomain` + AFURLResponseSerializer errors. Error codes for `AFURLResponseSerializationErrorDomain` correspond to codes in `NSURLErrorDomain`. + */ +extern NSString * const AFURLResponseSerializationErrorDomain; + +/** + ## User info dictionary keys + + These keys may exist in the user info dictionary, in addition to those defined for NSError. + + - `NSString * const AFNetworkingOperationFailingURLResponseErrorKey` + + ### Constants + + `AFNetworkingOperationFailingURLResponseErrorKey` + The corresponding value is an `NSURLResponse` containing the response of the operation associated with an error. This key is only present in the `AFURLResponseSerializationErrorDomain`. + */ +extern NSString * const AFNetworkingOperationFailingURLResponseErrorKey; diff --git a/ios/Pods/AFNetworking/AFNetworking/AFURLResponseSerialization.m b/ios/Pods/AFNetworking/AFNetworking/AFURLResponseSerialization.m new file mode 100644 index 000000000..cc1e00b6c --- /dev/null +++ b/ios/Pods/AFNetworking/AFNetworking/AFURLResponseSerialization.m @@ -0,0 +1,779 @@ +// AFSerialization.h +// +// Copyright (c) 2013-2014 AFNetworking (http://afnetworking.com) +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +#import "AFURLResponseSerialization.h" + +#if defined(__IPHONE_OS_VERSION_MIN_REQUIRED) +#import +#elif defined(__MAC_OS_X_VERSION_MIN_REQUIRED) +#import +#endif + +NSString * const AFURLResponseSerializationErrorDomain = @"com.alamofire.error.serialization.response"; +NSString * const AFNetworkingOperationFailingURLResponseErrorKey = @"com.alamofire.serialization.response.error.response"; + +static NSError * AFErrorWithUnderlyingError(NSError *error, NSError *underlyingError) { + if (!error) { + return underlyingError; + } + + if (!underlyingError || error.userInfo[NSUnderlyingErrorKey]) { + return error; + } + + NSMutableDictionary *mutableUserInfo = [error.userInfo mutableCopy]; + mutableUserInfo[NSUnderlyingErrorKey] = underlyingError; + + return [[NSError alloc] initWithDomain:error.domain code:error.code userInfo:mutableUserInfo]; +} + +static BOOL AFErrorOrUnderlyingErrorHasCodeInDomain(NSError *error, NSInteger code, NSString *domain) { + if ([error.domain isEqualToString:domain] && error.code == code) { + return YES; + } else if (error.userInfo[NSUnderlyingErrorKey]) { + return AFErrorOrUnderlyingErrorHasCodeInDomain(error.userInfo[NSUnderlyingErrorKey], code, domain); + } + + return NO; +} + +static id AFJSONObjectByRemovingKeysWithNullValues(id JSONObject, NSJSONReadingOptions readingOptions) { + if ([JSONObject isKindOfClass:[NSArray class]]) { + NSMutableArray *mutableArray = [NSMutableArray arrayWithCapacity:[(NSArray *)JSONObject count]]; + for (id value in (NSArray *)JSONObject) { + [mutableArray addObject:AFJSONObjectByRemovingKeysWithNullValues(value, readingOptions)]; + } + + return (readingOptions & NSJSONReadingMutableContainers) ? mutableArray : [NSArray arrayWithArray:mutableArray]; + } else if ([JSONObject isKindOfClass:[NSDictionary class]]) { + NSMutableDictionary *mutableDictionary = [NSMutableDictionary dictionaryWithDictionary:JSONObject]; + for (id key in [(NSDictionary *)JSONObject allKeys]) { + id value = [(NSDictionary *)JSONObject objectForKey:key]; + if (!value || [value isEqual:[NSNull null]]) { + [mutableDictionary removeObjectForKey:key]; + } else if ([value isKindOfClass:[NSArray class]] || [value isKindOfClass:[NSDictionary class]]) { + [mutableDictionary setObject:AFJSONObjectByRemovingKeysWithNullValues(value, readingOptions) forKey:key]; + } + } + + return (readingOptions & NSJSONReadingMutableContainers) ? mutableDictionary : [NSDictionary dictionaryWithDictionary:mutableDictionary]; + } + + return JSONObject; +} + +@implementation AFHTTPResponseSerializer + ++ (instancetype)serializer { + return [[self alloc] init]; +} + +- (instancetype)init { + self = [super init]; + if (!self) { + return nil; + } + + self.stringEncoding = NSUTF8StringEncoding; + + self.acceptableStatusCodes = [NSIndexSet indexSetWithIndexesInRange:NSMakeRange(200, 100)]; + self.acceptableContentTypes = nil; + + return self; +} + +#pragma mark - + +- (BOOL)validateResponse:(NSHTTPURLResponse *)response + data:(NSData *)data + error:(NSError * __autoreleasing *)error +{ + BOOL responseIsValid = YES; + NSError *validationError = nil; + + if (response && [response isKindOfClass:[NSHTTPURLResponse class]]) { + if (self.acceptableContentTypes && ![self.acceptableContentTypes containsObject:[response MIMEType]]) { + if ([data length] > 0) { + NSDictionary *userInfo = @{ + NSLocalizedDescriptionKey: [NSString stringWithFormat:NSLocalizedStringFromTable(@"Request failed: unacceptable content-type: %@", @"AFNetworking", nil), [response MIMEType]], + NSURLErrorFailingURLErrorKey:[response URL], + AFNetworkingOperationFailingURLResponseErrorKey: response + }; + + validationError = AFErrorWithUnderlyingError([NSError errorWithDomain:AFURLResponseSerializationErrorDomain code:NSURLErrorCannotDecodeContentData userInfo:userInfo], validationError); + } + + responseIsValid = NO; + } + + if (self.acceptableStatusCodes && ![self.acceptableStatusCodes containsIndex:(NSUInteger)response.statusCode]) { + NSDictionary *userInfo = @{ + NSLocalizedDescriptionKey: [NSString stringWithFormat:NSLocalizedStringFromTable(@"Request failed: %@ (%ld)", @"AFNetworking", nil), [NSHTTPURLResponse localizedStringForStatusCode:response.statusCode], (long)response.statusCode], + NSURLErrorFailingURLErrorKey:[response URL], + AFNetworkingOperationFailingURLResponseErrorKey: response + }; + + validationError = AFErrorWithUnderlyingError([NSError errorWithDomain:AFURLResponseSerializationErrorDomain code:NSURLErrorBadServerResponse userInfo:userInfo], validationError); + + responseIsValid = NO; + } + } + + if (error && !responseIsValid) { + *error = validationError; + } + + return responseIsValid; +} + +#pragma mark - AFURLResponseSerialization + +- (id)responseObjectForResponse:(NSURLResponse *)response + data:(NSData *)data + error:(NSError *__autoreleasing *)error +{ + [self validateResponse:(NSHTTPURLResponse *)response data:data error:error]; + + return data; +} + +#pragma mark - NSecureCoding + ++ (BOOL)supportsSecureCoding { + return YES; +} + +- (id)initWithCoder:(NSCoder *)decoder { + self = [self init]; + if (!self) { + return nil; + } + + self.acceptableStatusCodes = [decoder decodeObjectOfClass:[NSIndexSet class] forKey:NSStringFromSelector(@selector(acceptableStatusCodes))]; + self.acceptableContentTypes = [decoder decodeObjectOfClass:[NSIndexSet class] forKey:NSStringFromSelector(@selector(acceptableContentTypes))]; + + return self; +} + +- (void)encodeWithCoder:(NSCoder *)coder { + [coder encodeObject:self.acceptableStatusCodes forKey:NSStringFromSelector(@selector(acceptableStatusCodes))]; + [coder encodeObject:self.acceptableContentTypes forKey:NSStringFromSelector(@selector(acceptableContentTypes))]; +} + +#pragma mark - NSCopying + +- (id)copyWithZone:(NSZone *)zone { + AFHTTPResponseSerializer *serializer = [[[self class] allocWithZone:zone] init]; + serializer.acceptableStatusCodes = [self.acceptableStatusCodes copyWithZone:zone]; + serializer.acceptableContentTypes = [self.acceptableContentTypes copyWithZone:zone]; + + return serializer; +} + +@end + +#pragma mark - + +@implementation AFJSONResponseSerializer + ++ (instancetype)serializer { + return [self serializerWithReadingOptions:0]; +} + ++ (instancetype)serializerWithReadingOptions:(NSJSONReadingOptions)readingOptions { + AFJSONResponseSerializer *serializer = [[self alloc] init]; + serializer.readingOptions = readingOptions; + + return serializer; +} + +- (instancetype)init { + self = [super init]; + if (!self) { + return nil; + } + + self.acceptableContentTypes = [NSSet setWithObjects:@"application/json", @"text/json", @"text/javascript", nil]; + + return self; +} + +#pragma mark - AFURLResponseSerialization + +- (id)responseObjectForResponse:(NSURLResponse *)response + data:(NSData *)data + error:(NSError *__autoreleasing *)error +{ + if (![self validateResponse:(NSHTTPURLResponse *)response data:data error:error]) { + if (!error || AFErrorOrUnderlyingErrorHasCodeInDomain(*error, NSURLErrorCannotDecodeContentData, AFURLResponseSerializationErrorDomain)) { + return nil; + } + } + + // Workaround for behavior of Rails to return a single space for `head :ok` (a workaround for a bug in Safari), which is not interpreted as valid input by NSJSONSerialization. + // See https://github.com/rails/rails/issues/1742 + NSStringEncoding stringEncoding = self.stringEncoding; + if (response.textEncodingName) { + CFStringEncoding encoding = CFStringConvertIANACharSetNameToEncoding((CFStringRef)response.textEncodingName); + if (encoding != kCFStringEncodingInvalidId) { + stringEncoding = CFStringConvertEncodingToNSStringEncoding(encoding); + } + } + + id responseObject = nil; + NSError *serializationError = nil; + @autoreleasepool { + NSString *responseString = [[NSString alloc] initWithData:data encoding:stringEncoding]; + if (responseString && ![responseString isEqualToString:@" "]) { + // Workaround for a bug in NSJSONSerialization when Unicode character escape codes are used instead of the actual character + // See http://stackoverflow.com/a/12843465/157142 + data = [responseString dataUsingEncoding:NSUTF8StringEncoding]; + + if (data) { + if ([data length] > 0) { + responseObject = [NSJSONSerialization JSONObjectWithData:data options:self.readingOptions error:&serializationError]; + } else { + return nil; + } + } else { + NSDictionary *userInfo = @{ + NSLocalizedDescriptionKey: NSLocalizedStringFromTable(@"Data failed decoding as a UTF-8 string", nil, @"AFNetworking"), + NSLocalizedFailureReasonErrorKey: [NSString stringWithFormat:NSLocalizedStringFromTable(@"Could not decode string: %@", nil, @"AFNetworking"), responseString] + }; + + serializationError = [NSError errorWithDomain:AFURLResponseSerializationErrorDomain code:NSURLErrorCannotDecodeContentData userInfo:userInfo]; + } + } + } + + if (self.removesKeysWithNullValues && responseObject) { + responseObject = AFJSONObjectByRemovingKeysWithNullValues(responseObject, self.readingOptions); + } + + if (error) { + *error = AFErrorWithUnderlyingError(serializationError, *error);; + } + + return responseObject; +} + +#pragma mark - NSecureCoding + +- (id)initWithCoder:(NSCoder *)decoder { + self = [super initWithCoder:decoder]; + if (!self) { + return nil; + } + + self.readingOptions = [[decoder decodeObjectOfClass:[NSNumber class] forKey:NSStringFromSelector(@selector(readingOptions))] unsignedIntegerValue]; + + return self; +} + +- (void)encodeWithCoder:(NSCoder *)coder { + [super encodeWithCoder:coder]; + + [coder encodeObject:@(self.readingOptions) forKey:NSStringFromSelector(@selector(readingOptions))]; +} + +#pragma mark - NSCopying + +- (id)copyWithZone:(NSZone *)zone { + AFJSONResponseSerializer *serializer = [[[self class] allocWithZone:zone] init]; + serializer.readingOptions = self.readingOptions; + + return serializer; +} + +@end + +#pragma mark - + +@implementation AFXMLParserResponseSerializer + ++ (instancetype)serializer { + AFXMLParserResponseSerializer *serializer = [[self alloc] init]; + + return serializer; +} + +- (instancetype)init { + self = [super init]; + if (!self) { + return nil; + } + + self.acceptableContentTypes = [[NSSet alloc] initWithObjects:@"application/xml", @"text/xml", nil]; + + return self; +} + +#pragma mark - AFURLResponseSerialization + +- (id)responseObjectForResponse:(NSHTTPURLResponse *)response + data:(NSData *)data + error:(NSError *__autoreleasing *)error +{ + if (![self validateResponse:(NSHTTPURLResponse *)response data:data error:error]) { + if (!error || AFErrorOrUnderlyingErrorHasCodeInDomain(*error, NSURLErrorCannotDecodeContentData, AFURLResponseSerializationErrorDomain)) { + return nil; + } + } + + return [[NSXMLParser alloc] initWithData:data]; +} + +@end + +#pragma mark - + +#ifdef __MAC_OS_X_VERSION_MIN_REQUIRED + +@implementation AFXMLDocumentResponseSerializer + ++ (instancetype)serializer { + return [self serializerWithXMLDocumentOptions:0]; +} + ++ (instancetype)serializerWithXMLDocumentOptions:(NSUInteger)mask { + AFXMLDocumentResponseSerializer *serializer = [[self alloc] init]; + serializer.options = mask; + + return serializer; +} + +- (instancetype)init { + self = [super init]; + if (!self) { + return nil; + } + + self.acceptableContentTypes = [[NSSet alloc] initWithObjects:@"application/xml", @"text/xml", nil]; + + return self; +} + +#pragma mark - AFURLResponseSerialization + +- (id)responseObjectForResponse:(NSURLResponse *)response + data:(NSData *)data + error:(NSError *__autoreleasing *)error +{ + if (![self validateResponse:(NSHTTPURLResponse *)response data:data error:error]) { + if (!error || AFErrorOrUnderlyingErrorHasCodeInDomain(*error, NSURLErrorCannotDecodeContentData, AFURLResponseSerializationErrorDomain)) { + return nil; + } + } + + NSError *serializationError = nil; + NSXMLDocument *document = [[NSXMLDocument alloc] initWithData:data options:self.options error:&serializationError]; + + if (error) { + *error = AFErrorWithUnderlyingError(serializationError, *error); + } + + return document; +} + +#pragma mark - NSecureCoding + +- (id)initWithCoder:(NSCoder *)decoder { + self = [super initWithCoder:decoder]; + if (!self) { + return nil; + } + + self.options = [[decoder decodeObjectOfClass:[NSNumber class] forKey:NSStringFromSelector(@selector(options))] unsignedIntegerValue]; + + return self; +} + +- (void)encodeWithCoder:(NSCoder *)coder { + [super encodeWithCoder:coder]; + + [coder encodeObject:@(self.options) forKey:NSStringFromSelector(@selector(options))]; +} + +#pragma mark - NSCopying + +- (id)copyWithZone:(NSZone *)zone { + AFXMLDocumentResponseSerializer *serializer = [[[self class] allocWithZone:zone] init]; + serializer.options = self.options; + + return serializer; +} + +@end + +#endif + +#pragma mark - + +@implementation AFPropertyListResponseSerializer + ++ (instancetype)serializer { + return [self serializerWithFormat:NSPropertyListXMLFormat_v1_0 readOptions:0]; +} + ++ (instancetype)serializerWithFormat:(NSPropertyListFormat)format + readOptions:(NSPropertyListReadOptions)readOptions +{ + AFPropertyListResponseSerializer *serializer = [[self alloc] init]; + serializer.format = format; + serializer.readOptions = readOptions; + + return serializer; +} + +- (instancetype)init { + self = [super init]; + if (!self) { + return nil; + } + + self.acceptableContentTypes = [[NSSet alloc] initWithObjects:@"application/x-plist", nil]; + + return self; +} + +#pragma mark - AFURLResponseSerialization + +- (id)responseObjectForResponse:(NSURLResponse *)response + data:(NSData *)data + error:(NSError *__autoreleasing *)error +{ + if (![self validateResponse:(NSHTTPURLResponse *)response data:data error:error]) { + if (!error || AFErrorOrUnderlyingErrorHasCodeInDomain(*error, NSURLErrorCannotDecodeContentData, AFURLResponseSerializationErrorDomain)) { + return nil; + } + } + + id responseObject; + NSError *serializationError = nil; + + if (data) { + responseObject = [NSPropertyListSerialization propertyListWithData:data options:self.readOptions format:NULL error:&serializationError]; + } + + if (error) { + *error = AFErrorWithUnderlyingError(serializationError, *error); + } + + return responseObject; +} + +#pragma mark - NSecureCoding + +- (id)initWithCoder:(NSCoder *)decoder { + self = [super initWithCoder:decoder]; + if (!self) { + return nil; + } + + self.format = [[decoder decodeObjectOfClass:[NSNumber class] forKey:NSStringFromSelector(@selector(format))] unsignedIntegerValue]; + self.readOptions = [[decoder decodeObjectOfClass:[NSNumber class] forKey:NSStringFromSelector(@selector(readOptions))] unsignedIntegerValue]; + + return self; +} + +- (void)encodeWithCoder:(NSCoder *)coder { + [super encodeWithCoder:coder]; + + [coder encodeObject:@(self.format) forKey:NSStringFromSelector(@selector(format))]; + [coder encodeObject:@(self.readOptions) forKey:NSStringFromSelector(@selector(readOptions))]; +} + +#pragma mark - NSCopying + +- (id)copyWithZone:(NSZone *)zone { + AFPropertyListResponseSerializer *serializer = [[[self class] allocWithZone:zone] init]; + serializer.format = self.format; + serializer.readOptions = self.readOptions; + + return serializer; +} + +@end + +#pragma mark - + +#if defined(__IPHONE_OS_VERSION_MIN_REQUIRED) +#import + +static UIImage * AFImageWithDataAtScale(NSData *data, CGFloat scale) { + UIImage *image = [[UIImage alloc] initWithData:data]; + + return [[UIImage alloc] initWithCGImage:[image CGImage] scale:scale orientation:image.imageOrientation]; +} + +static UIImage * AFInflatedImageFromResponseWithDataAtScale(NSHTTPURLResponse *response, NSData *data, CGFloat scale) { + if (!data || [data length] == 0) { + return nil; + } + + CGImageRef imageRef = NULL; + CGDataProviderRef dataProvider = CGDataProviderCreateWithCFData((__bridge CFDataRef)data); + + if ([response.MIMEType isEqualToString:@"image/png"]) { + imageRef = CGImageCreateWithPNGDataProvider(dataProvider, NULL, true, kCGRenderingIntentDefault); + } else if ([response.MIMEType isEqualToString:@"image/jpeg"]) { + imageRef = CGImageCreateWithJPEGDataProvider(dataProvider, NULL, true, kCGRenderingIntentDefault); + + // CGImageCreateWithJPEGDataProvider does not properly handle CMKY, so if so, fall back to AFImageWithDataAtScale + if (imageRef) { + CGColorSpaceRef imageColorSpace = CGImageGetColorSpace(imageRef); + CGColorSpaceModel imageColorSpaceModel = CGColorSpaceGetModel(imageColorSpace); + if (imageColorSpaceModel == kCGColorSpaceModelCMYK) { + CGImageRelease(imageRef); + imageRef = NULL; + } + } + } + + CGDataProviderRelease(dataProvider); + + UIImage *image = AFImageWithDataAtScale(data, scale); + if (!imageRef) { + if (image.images || !image) { + return image; + } + + imageRef = CGImageCreateCopy([image CGImage]); + if (!imageRef) { + return nil; + } + } + + size_t width = CGImageGetWidth(imageRef); + size_t height = CGImageGetHeight(imageRef); + size_t bitsPerComponent = CGImageGetBitsPerComponent(imageRef); + + if (width * height > 1024 * 1024 || bitsPerComponent > 8) { + CGImageRelease(imageRef); + + return image; + } + + size_t bytesPerRow = 0; // CGImageGetBytesPerRow() calculates incorrectly in iOS 5.0, so defer to CGBitmapContextCreate + CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB(); + CGColorSpaceModel colorSpaceModel = CGColorSpaceGetModel(colorSpace); + CGBitmapInfo bitmapInfo = CGImageGetBitmapInfo(imageRef); + + if (colorSpaceModel == kCGColorSpaceModelRGB) { + uint32_t alpha = (bitmapInfo & kCGBitmapAlphaInfoMask); + if (alpha == kCGImageAlphaNone) { + bitmapInfo &= ~kCGBitmapAlphaInfoMask; + bitmapInfo |= kCGImageAlphaNoneSkipFirst; + } else if (!(alpha == kCGImageAlphaNoneSkipFirst || alpha == kCGImageAlphaNoneSkipLast)) { + bitmapInfo &= ~kCGBitmapAlphaInfoMask; + bitmapInfo |= kCGImageAlphaPremultipliedFirst; + } + } + + CGContextRef context = CGBitmapContextCreate(NULL, width, height, bitsPerComponent, bytesPerRow, colorSpace, bitmapInfo); + + CGColorSpaceRelease(colorSpace); + + if (!context) { + CGImageRelease(imageRef); + + return image; + } + + CGContextDrawImage(context, CGRectMake(0.0f, 0.0f, width, height), imageRef); + CGImageRef inflatedImageRef = CGBitmapContextCreateImage(context); + + CGContextRelease(context); + + UIImage *inflatedImage = [[UIImage alloc] initWithCGImage:inflatedImageRef scale:scale orientation:image.imageOrientation]; + + CGImageRelease(inflatedImageRef); + CGImageRelease(imageRef); + + return inflatedImage; +} +#endif + + +@implementation AFImageResponseSerializer + +- (instancetype)init { + self = [super init]; + if (!self) { + return nil; + } + + self.acceptableContentTypes = [[NSSet alloc] initWithObjects:@"image/tiff", @"image/jpeg", @"image/gif", @"image/png", @"image/ico", @"image/x-icon", @"image/bmp", @"image/x-bmp", @"image/x-xbitmap", @"image/x-win-bitmap", nil]; + +#if defined(__IPHONE_OS_VERSION_MIN_REQUIRED) + self.imageScale = [[UIScreen mainScreen] scale]; + self.automaticallyInflatesResponseImage = YES; +#endif + + return self; +} + +#pragma mark - AFURLResponseSerializer + +- (id)responseObjectForResponse:(NSURLResponse *)response + data:(NSData *)data + error:(NSError *__autoreleasing *)error +{ + if (![self validateResponse:(NSHTTPURLResponse *)response data:data error:error]) { + if (!error || AFErrorOrUnderlyingErrorHasCodeInDomain(*error, NSURLErrorCannotDecodeContentData, AFURLResponseSerializationErrorDomain)) { + return nil; + } + } + +#if defined(__IPHONE_OS_VERSION_MIN_REQUIRED) + if (self.automaticallyInflatesResponseImage) { + return AFInflatedImageFromResponseWithDataAtScale((NSHTTPURLResponse *)response, data, self.imageScale); + } else { + return AFImageWithDataAtScale(data, self.imageScale); + } +#elif defined(__MAC_OS_X_VERSION_MIN_REQUIRED) + // Ensure that the image is set to it's correct pixel width and height + NSBitmapImageRep *bitimage = [[NSBitmapImageRep alloc] initWithData:data]; + NSImage *image = [[NSImage alloc] initWithSize:NSMakeSize([bitimage pixelsWide], [bitimage pixelsHigh])]; + [image addRepresentation:bitimage]; + + return image; +#endif + + return nil; +} + +#pragma mark - NSecureCoding + +- (id)initWithCoder:(NSCoder *)decoder { + self = [super initWithCoder:decoder]; + if (!self) { + return nil; + } + +#if defined(__IPHONE_OS_VERSION_MIN_REQUIRED) + NSNumber *imageScale = [decoder decodeObjectOfClass:[NSNumber class] forKey:NSStringFromSelector(@selector(imageScale))]; +#if CGFLOAT_IS_DOUBLE + self.imageScale = [imageScale doubleValue]; +#else + self.imageScale = [imageScale floatValue]; +#endif + + self.automaticallyInflatesResponseImage = [decoder decodeBoolForKey:NSStringFromSelector(@selector(automaticallyInflatesResponseImage))]; +#endif + + return self; +} + +- (void)encodeWithCoder:(NSCoder *)coder { + [super encodeWithCoder:coder]; + +#if defined(__IPHONE_OS_VERSION_MIN_REQUIRED) + [coder encodeObject:@(self.imageScale) forKey:NSStringFromSelector(@selector(imageScale))]; + [coder encodeBool:self.automaticallyInflatesResponseImage forKey:NSStringFromSelector(@selector(automaticallyInflatesResponseImage))]; +#endif +} + +#pragma mark - NSCopying + +- (id)copyWithZone:(NSZone *)zone { + AFImageResponseSerializer *serializer = [[[self class] allocWithZone:zone] init]; + +#if defined(__IPHONE_OS_VERSION_MIN_REQUIRED) + serializer.imageScale = self.imageScale; + serializer.automaticallyInflatesResponseImage = self.automaticallyInflatesResponseImage; +#endif + + return serializer; +} + +@end + +#pragma mark - + +@interface AFCompoundResponseSerializer () +@property (readwrite, nonatomic, copy) NSArray *responseSerializers; +@end + +@implementation AFCompoundResponseSerializer + ++ (instancetype)compoundSerializerWithResponseSerializers:(NSArray *)responseSerializers { + AFCompoundResponseSerializer *serializer = [[self alloc] init]; + serializer.responseSerializers = responseSerializers; + + return serializer; +} + +#pragma mark - AFURLResponseSerialization + +- (id)responseObjectForResponse:(NSURLResponse *)response + data:(NSData *)data + error:(NSError *__autoreleasing *)error +{ + for (id serializer in self.responseSerializers) { + if (![serializer isKindOfClass:[AFHTTPResponseSerializer class]]) { + continue; + } + + NSError *serializerError = nil; + id responseObject = [serializer responseObjectForResponse:response data:data error:&serializerError]; + if (responseObject) { + if (error) { + *error = AFErrorWithUnderlyingError(serializerError, *error); + } + + return responseObject; + } + } + + return [super responseObjectForResponse:response data:data error:error]; +} + +#pragma mark - NSecureCoding + +- (id)initWithCoder:(NSCoder *)decoder { + self = [super initWithCoder:decoder]; + if (!self) { + return nil; + } + + self.responseSerializers = [decoder decodeObjectOfClass:[NSArray class] forKey:NSStringFromSelector(@selector(responseSerializers))]; + + return self; +} + +- (void)encodeWithCoder:(NSCoder *)coder { + [super encodeWithCoder:coder]; + + [coder encodeObject:self.responseSerializers forKey:NSStringFromSelector(@selector(responseSerializers))]; +} + +#pragma mark - NSCopying + +- (id)copyWithZone:(NSZone *)zone { + AFCompoundResponseSerializer *serializer = [[[self class] allocWithZone:zone] init]; + serializer.responseSerializers = self.responseSerializers; + + return serializer; +} + +@end diff --git a/ios/Pods/AFNetworking/AFNetworking/AFURLSessionManager.h b/ios/Pods/AFNetworking/AFNetworking/AFURLSessionManager.h new file mode 100644 index 000000000..6432027b9 --- /dev/null +++ b/ios/Pods/AFNetworking/AFNetworking/AFURLSessionManager.h @@ -0,0 +1,529 @@ +// AFURLSessionManager.h +// +// Copyright (c) 2013-2014 AFNetworking (http://afnetworking.com) +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +#import + +#import "AFURLResponseSerialization.h" +#import "AFURLRequestSerialization.h" +#import "AFSecurityPolicy.h" +#import "AFNetworkReachabilityManager.h" + +/** + `AFURLSessionManager` creates and manages an `NSURLSession` object based on a specified `NSURLSessionConfiguration` object, which conforms to ``, ``, ``, and ``. + + ## Subclassing Notes + + This is the base class for `AFHTTPSessionManager`, which adds functionality specific to making HTTP requests. If you are looking to extend `AFURLSessionManager` specifically for HTTP, consider subclassing `AFHTTPSessionManager` instead. + + ## NSURLSession & NSURLSessionTask Delegate Methods + + `AFURLSessionManager` implements the following delegate methods: + + ### `NSURLSessionDelegate` + + - `URLSession:didBecomeInvalidWithError:` + - `URLSession:didReceiveChallenge:completionHandler:` + + ### `NSURLSessionTaskDelegate` + + - `URLSession:willPerformHTTPRedirection:newRequest:completionHandler:` + - `URLSession:task:didReceiveChallenge:completionHandler:` + - `URLSession:task:didSendBodyData:totalBytesSent:totalBytesExpectedToSend:` + - `URLSession:task:didCompleteWithError:` + + ### `NSURLSessionDataDelegate` + + - `URLSession:dataTask:didReceiveResponse:completionHandler:` + - `URLSession:dataTask:didBecomeDownloadTask:` + - `URLSession:dataTask:didReceiveData:` + - `URLSession:dataTask:willCacheResponse:completionHandler:` + - `URLSessionDidFinishEventsForBackgroundURLSession:` + + ### `NSURLSessionDownloadDelegate` + + - `URLSession:downloadTask:didFinishDownloadingToURL:` + - `URLSession:downloadTask:didWriteData:totalBytesWritten:totalBytesWritten:totalBytesExpectedToWrite:` + - `URLSession:downloadTask:didResumeAtOffset:expectedTotalBytes:` + + If any of these methods are overridden in a subclass, they _must_ call the `super` implementation first. + + ## Network Reachability Monitoring + + Network reachability status and change monitoring is available through the `reachabilityManager` property. Applications may choose to monitor network reachability conditions in order to prevent or suspend any outbound requests. See `AFNetworkReachabilityManager` for more details. + + ## NSCoding Caveats + + - Encoded managers do not include any block properties. Be sure to set delegate callback blocks when using `-initWithCoder:` or `NSKeyedUnarchiver`. + + ## NSCopying Caveats + + - `-copy` and `-copyWithZone:` return a new manager with a new `NSURLSession` created from the configuration of the original. + - Operation copies do not include any delegate callback blocks, as they often strongly captures a reference to `self`, which would otherwise have the unintuitive side-effect of pointing to the _original_ session manager when copied. + */ + +#if (defined(__IPHONE_OS_VERSION_MAX_ALLOWED) && __IPHONE_OS_VERSION_MAX_ALLOWED >= 70000) || (defined(__MAC_OS_X_VERSION_MAX_ALLOWED) && __MAC_OS_X_VERSION_MAX_ALLOWED >= 1090) + +@interface AFURLSessionManager : NSObject + +/** + The managed session. + */ +@property (readonly, nonatomic, strong) NSURLSession *session; + +/** + The operation queue on which delegate callbacks are run. + */ +@property (readonly, nonatomic, strong) NSOperationQueue *operationQueue; + +/** + Responses sent from the server in data tasks created with `dataTaskWithRequest:success:failure:` and run using the `GET` / `POST` / et al. convenience methods are automatically validated and serialized by the response serializer. By default, this property is set to an instance of `AFJSONResponseSerializer`. + + @warning `responseSerializer` must not be `nil`. + */ +@property (nonatomic, strong) id responseSerializer; + +///------------------------------- +/// @name Managing Security Policy +///------------------------------- + +/** + The security policy used by created request operations to evaluate server trust for secure connections. `AFURLSessionManager` uses the `defaultPolicy` unless otherwise specified. + */ +@property (nonatomic, strong) AFSecurityPolicy *securityPolicy; + +///-------------------------------------- +/// @name Monitoring Network Reachability +///-------------------------------------- + +/** + The network reachability manager. `AFURLSessionManager` uses the `sharedManager` by default. + */ +@property (readwrite, nonatomic, strong) AFNetworkReachabilityManager *reachabilityManager; + +///---------------------------- +/// @name Getting Session Tasks +///---------------------------- + +/** + The data, upload, and download tasks currently run by the managed session. + */ +@property (readonly, nonatomic, strong) NSArray *tasks; + +/** + The data tasks currently run by the managed session. + */ +@property (readonly, nonatomic, strong) NSArray *dataTasks; + +/** + The upload tasks currently run by the managed session. + */ +@property (readonly, nonatomic, strong) NSArray *uploadTasks; + +/** + The download tasks currently run by the managed session. + */ +@property (readonly, nonatomic, strong) NSArray *downloadTasks; + +///------------------------------- +/// @name Managing Callback Queues +///------------------------------- + +/** + The dispatch queue for `completionBlock`. If `NULL` (default), the main queue is used. + */ +@property (nonatomic, strong) dispatch_queue_t completionQueue; + +/** + The dispatch group for `completionBlock`. If `NULL` (default), a private dispatch group is used. + */ +@property (nonatomic, strong) dispatch_group_t completionGroup; + +///--------------------------------- +/// @name Working Around System Bugs +///--------------------------------- + +/** + Whether to attempt to retry creation of upload tasks for background sessions when initial call returns `nil`. `NO` by default. + + @bug As of iOS 7.0, there is a bug where upload tasks created for background tasks are sometimes `nil`. As a workaround, if this property is `YES`, AFNetworking will follow Apple's recommendation to try creating the task again. + + @see https://github.com/AFNetworking/AFNetworking/issues/1675 + */ +@property (nonatomic, assign) BOOL attemptsToRecreateUploadTasksForBackgroundSessions; + +///--------------------- +/// @name Initialization +///--------------------- + +/** + Creates and returns a manager for a session created with the specified configuration. This is the designated initializer. + + @param configuration The configuration used to create the managed session. + + @return A manager for a newly-created session. + */ +- (instancetype)initWithSessionConfiguration:(NSURLSessionConfiguration *)configuration; + +/** + Invalidates the managed session, optionally canceling pending tasks. + + @param cancelPendingTasks Whether or not to cancel pending tasks. + */ +- (void)invalidateSessionCancelingTasks:(BOOL)cancelPendingTasks; + +///------------------------- +/// @name Running Data Tasks +///------------------------- + +/** + Creates an `NSURLSessionDataTask` with the specified request. + + @param request The HTTP request for the request. + @param completionHandler A block object to be executed when the task finishes. This block has no return value and takes three arguments: the server response, the response object created by that serializer, and the error that occurred, if any. + */ +- (NSURLSessionDataTask *)dataTaskWithRequest:(NSURLRequest *)request + completionHandler:(void (^)(NSURLResponse *response, id responseObject, NSError *error))completionHandler; + +///--------------------------- +/// @name Running Upload Tasks +///--------------------------- + +/** + Creates an `NSURLSessionUploadTask` with the specified request for a local file. + + @param request The HTTP request for the request. + @param fileURL A URL to the local file to be uploaded. + @param progress A progress object monitoring the current upload progress. + @param completionHandler A block object to be executed when the task finishes. This block has no return value and takes three arguments: the server response, the response object created by that serializer, and the error that occurred, if any. + + @see `attemptsToRecreateUploadTasksForBackgroundSessions` + */ +- (NSURLSessionUploadTask *)uploadTaskWithRequest:(NSURLRequest *)request + fromFile:(NSURL *)fileURL + progress:(NSProgress * __autoreleasing *)progress + completionHandler:(void (^)(NSURLResponse *response, id responseObject, NSError *error))completionHandler; + +/** + Creates an `NSURLSessionUploadTask` with the specified request for an HTTP body. + + @param request The HTTP request for the request. + @param bodyData A data object containing the HTTP body to be uploaded. + @param progress A progress object monitoring the current upload progress. + @param completionHandler A block object to be executed when the task finishes. This block has no return value and takes three arguments: the server response, the response object created by that serializer, and the error that occurred, if any. + */ +- (NSURLSessionUploadTask *)uploadTaskWithRequest:(NSURLRequest *)request + fromData:(NSData *)bodyData + progress:(NSProgress * __autoreleasing *)progress + completionHandler:(void (^)(NSURLResponse *response, id responseObject, NSError *error))completionHandler; + +/** + Creates an `NSURLSessionUploadTask` with the specified streaming request. + + @param request The HTTP request for the request. + @param progress A progress object monitoring the current upload progress. + @param completionHandler A block object to be executed when the task finishes. This block has no return value and takes three arguments: the server response, the response object created by that serializer, and the error that occurred, if any. + */ +- (NSURLSessionUploadTask *)uploadTaskWithStreamedRequest:(NSURLRequest *)request + progress:(NSProgress * __autoreleasing *)progress + completionHandler:(void (^)(NSURLResponse *response, id responseObject, NSError *error))completionHandler; + +///----------------------------- +/// @name Running Download Tasks +///----------------------------- + +/** + Creates an `NSURLSessionDownloadTask` with the specified request. + + @param request The HTTP request for the request. + @param progress A progress object monitoring the current download progress. + @param destination A block object to be executed in order to determine the destination of the downloaded file. This block takes two arguments, the target path & the server response, and returns the desired file URL of the resulting download. The temporary file used during the download will be automatically deleted after being moved to the returned URL. + @param completionHandler A block to be executed when a task finishes. This block has no return value and takes three arguments: the server response, the path of the downloaded file, and the error describing the network or parsing error that occurred, if any. + + @warning If using a background `NSURLSessionConfiguration` on iOS, these blocks will be lost when the app is terminated. Background sessions may prefer to use `-setDownloadTaskDidFinishDownloadingBlock:` to specify the URL for saving the downloaded file, rather than the destination block of this method. + */ +- (NSURLSessionDownloadTask *)downloadTaskWithRequest:(NSURLRequest *)request + progress:(NSProgress * __autoreleasing *)progress + destination:(NSURL * (^)(NSURL *targetPath, NSURLResponse *response))destination + completionHandler:(void (^)(NSURLResponse *response, NSURL *filePath, NSError *error))completionHandler; + +/** + Creates an `NSURLSessionDownloadTask` with the specified resume data. + + @param resumeData The data used to resume downloading. + @param progress A progress object monitoring the current download progress. + @param destination A block object to be executed in order to determine the destination of the downloaded file. This block takes two arguments, the target path & the server response, and returns the desired file URL of the resulting download. The temporary file used during the download will be automatically deleted after being moved to the returned URL. + @param completionHandler A block to be executed when a task finishes. This block has no return value and takes three arguments: the server response, the path of the downloaded file, and the error describing the network or parsing error that occurred, if any. + */ +- (NSURLSessionDownloadTask *)downloadTaskWithResumeData:(NSData *)resumeData + progress:(NSProgress * __autoreleasing *)progress + destination:(NSURL * (^)(NSURL *targetPath, NSURLResponse *response))destination + completionHandler:(void (^)(NSURLResponse *response, NSURL *filePath, NSError *error))completionHandler; + +///--------------------------------- +/// @name Getting Progress for Tasks +///--------------------------------- + +/** + Returns the upload progress of the specified task. + + @param uploadTask The session upload task. Must not be `nil`. + + @return An `NSProgress` object reporting the upload progress of a task, or `nil` if the progress is unavailable. + */ +- (NSProgress *)uploadProgressForTask:(NSURLSessionUploadTask *)uploadTask; + +/** + Returns the download progress of the specified task. + + @param downloadTask The session download task. Must not be `nil`. + + @return An `NSProgress` object reporting the download progress of a task, or `nil` if the progress is unavailable. + */ +- (NSProgress *)downloadProgressForTask:(NSURLSessionDownloadTask *)downloadTask; + +///----------------------------------------- +/// @name Setting Session Delegate Callbacks +///----------------------------------------- + +/** + Sets a block to be executed when the managed session becomes invalid, as handled by the `NSURLSessionDelegate` method `URLSession:didBecomeInvalidWithError:`. + + @param block A block object to be executed when the managed session becomes invalid. The block has no return value, and takes two arguments: the session, and the error related to the cause of invalidation. + */ +- (void)setSessionDidBecomeInvalidBlock:(void (^)(NSURLSession *session, NSError *error))block; + +/** + Sets a block to be executed when a connection level authentication challenge has occurred, as handled by the `NSURLSessionDelegate` method `URLSession:didReceiveChallenge:completionHandler:`. + + @param block A block object to be executed when a connection level authentication challenge has occurred. The block returns the disposition of the authentication challenge, and takes three arguments: the session, the authentication challenge, and a pointer to the credential that should be used to resolve the challenge. + */ +- (void)setSessionDidReceiveAuthenticationChallengeBlock:(NSURLSessionAuthChallengeDisposition (^)(NSURLSession *session, NSURLAuthenticationChallenge *challenge, NSURLCredential * __autoreleasing *credential))block; + +///-------------------------------------- +/// @name Setting Task Delegate Callbacks +///-------------------------------------- + +/** + Sets a block to be executed when a task requires a new request body stream to send to the remote server, as handled by the `NSURLSessionTaskDelegate` method `URLSession:task:needNewBodyStream:`. + + @param block A block object to be executed when a task requires a new request body stream. + */ +- (void)setTaskNeedNewBodyStreamBlock:(NSInputStream * (^)(NSURLSession *session, NSURLSessionTask *task))block; + +/** + Sets a block to be executed when an HTTP request is attempting to perform a redirection to a different URL, as handled by the `NSURLSessionTaskDelegate` method `URLSession:willPerformHTTPRedirection:newRequest:completionHandler:`. + + @param block A block object to be executed when an HTTP request is attempting to perform a redirection to a different URL. The block returns the request to be made for the redirection, and takes four arguments: the session, the task, the redirection response, and the request corresponding to the redirection response. + */ +- (void)setTaskWillPerformHTTPRedirectionBlock:(NSURLRequest * (^)(NSURLSession *session, NSURLSessionTask *task, NSURLResponse *response, NSURLRequest *request))block; + +/** + Sets a block to be executed when a session task has received a request specific authentication challenge, as handled by the `NSURLSessionTaskDelegate` method `URLSession:task:didReceiveChallenge:completionHandler:`. + + @param block A block object to be executed when a session task has received a request specific authentication challenge. The block returns the disposition of the authentication challenge, and takes four arguments: the session, the task, the authentication challenge, and a pointer to the credential that should be used to resolve the challenge. + */ +- (void)setTaskDidReceiveAuthenticationChallengeBlock:(NSURLSessionAuthChallengeDisposition (^)(NSURLSession *session, NSURLSessionTask *task, NSURLAuthenticationChallenge *challenge, NSURLCredential * __autoreleasing *credential))block; + +/** + Sets a block to be executed periodically to track upload progress, as handled by the `NSURLSessionTaskDelegate` method `URLSession:task:didSendBodyData:totalBytesSent:totalBytesExpectedToSend:`. + + @param block A block object to be called when an undetermined number of bytes have been uploaded to the server. This block has no return value and takes five arguments: the session, the task, the number of bytes written since the last time the upload progress block was called, the total bytes written, and the total bytes expected to be written during the request, as initially determined by the length of the HTTP body. This block may be called multiple times, and will execute on the main thread. + */ +- (void)setTaskDidSendBodyDataBlock:(void (^)(NSURLSession *session, NSURLSessionTask *task, int64_t bytesSent, int64_t totalBytesSent, int64_t totalBytesExpectedToSend))block; + +/** + Sets a block to be executed as the last message related to a specific task, as handled by the `NSURLSessionTaskDelegate` method `URLSession:task:didCompleteWithError:`. + + @param block A block object to be executed when a session task is completed. The block has no return value, and takes three arguments: the session, the task, and any error that occurred in the process of executing the task. + */ +- (void)setTaskDidCompleteBlock:(void (^)(NSURLSession *session, NSURLSessionTask *task, NSError *error))block; + +///------------------------------------------- +/// @name Setting Data Task Delegate Callbacks +///------------------------------------------- + +/** + Sets a block to be executed when a data task has received a response, as handled by the `NSURLSessionDataDelegate` method `URLSession:dataTask:didReceiveResponse:completionHandler:`. + + @param block A block object to be executed when a data task has received a response. The block returns the disposition of the session response, and takes three arguments: the session, the data task, and the received response. + */ +- (void)setDataTaskDidReceiveResponseBlock:(NSURLSessionResponseDisposition (^)(NSURLSession *session, NSURLSessionDataTask *dataTask, NSURLResponse *response))block; + +/** + Sets a block to be executed when a data task has become a download task, as handled by the `NSURLSessionDataDelegate` method `URLSession:dataTask:didBecomeDownloadTask:`. + + @param block A block object to be executed when a data task has become a download task. The block has no return value, and takes three arguments: the session, the data task, and the download task it has become. + */ +- (void)setDataTaskDidBecomeDownloadTaskBlock:(void (^)(NSURLSession *session, NSURLSessionDataTask *dataTask, NSURLSessionDownloadTask *downloadTask))block; + +/** + Sets a block to be executed when a data task receives data, as handled by the `NSURLSessionDataDelegate` method `URLSession:dataTask:didReceiveData:`. + + @param block A block object to be called when an undetermined number of bytes have been downloaded from the server. This block has no return value and takes three arguments: the session, the data task, and the data received. This block may be called multiple times, and will execute on the session manager operation queue. + */ +- (void)setDataTaskDidReceiveDataBlock:(void (^)(NSURLSession *session, NSURLSessionDataTask *dataTask, NSData *data))block; + +/** + Sets a block to be executed to determine the caching behavior of a data task, as handled by the `NSURLSessionDataDelegate` method `URLSession:dataTask:willCacheResponse:completionHandler:`. + + @param block A block object to be executed to determine the caching behavior of a data task. The block returns the response to cache, and takes three arguments: the session, the data task, and the proposed cached URL response. + */ +- (void)setDataTaskWillCacheResponseBlock:(NSCachedURLResponse * (^)(NSURLSession *session, NSURLSessionDataTask *dataTask, NSCachedURLResponse *proposedResponse))block; + +/** + Sets a block to be executed once all messages enqueued for a session have been delivered, as handled by the `NSURLSessionDataDelegate` method `URLSessionDidFinishEventsForBackgroundURLSession:`. + + @param block A block object to be executed once all messages enqueued for a session have been delivered. The block has no return value and takes a single argument: the session. + */ +- (void)setDidFinishEventsForBackgroundURLSessionBlock:(void (^)(NSURLSession *session))block; + +///----------------------------------------------- +/// @name Setting Download Task Delegate Callbacks +///----------------------------------------------- + +/** + Sets a block to be executed when a download task has completed a download, as handled by the `NSURLSessionDownloadDelegate` method `URLSession:downloadTask:didFinishDownloadingToURL:`. + + @param block A block object to be executed when a download task has completed. The block returns the URL the download should be moved to, and takes three arguments: the session, the download task, and the temporary location of the downloaded file. If the file manager encounters an error while attempting to move the temporary file to the destination, an `AFURLSessionDownloadTaskDidFailToMoveFileNotification` will be posted, with the download task as its object, and the user info of the error. + */ +- (void)setDownloadTaskDidFinishDownloadingBlock:(NSURL * (^)(NSURLSession *session, NSURLSessionDownloadTask *downloadTask, NSURL *location))block; + +/** + Sets a block to be executed periodically to track download progress, as handled by the `NSURLSessionDownloadDelegate` method `URLSession:downloadTask:didWriteData:totalBytesWritten:totalBytesWritten:totalBytesExpectedToWrite:`. + + @param block A block object to be called when an undetermined number of bytes have been downloaded from the server. This block has no return value and takes five arguments: the session, the download task, the number of bytes read since the last time the download progress block was called, the total bytes read, and the total bytes expected to be read during the request, as initially determined by the expected content size of the `NSHTTPURLResponse` object. This block may be called multiple times, and will execute on the session manager operation queue. + */ +- (void)setDownloadTaskDidWriteDataBlock:(void (^)(NSURLSession *session, NSURLSessionDownloadTask *downloadTask, int64_t bytesWritten, int64_t totalBytesWritten, int64_t totalBytesExpectedToWrite))block; + +/** + Sets a block to be executed when a download task has been resumed, as handled by the `NSURLSessionDownloadDelegate` method `URLSession:downloadTask:didResumeAtOffset:expectedTotalBytes:`. + + @param block A block object to be executed when a download task has been resumed. The block has no return value and takes four arguments: the session, the download task, the file offset of the resumed download, and the total number of bytes expected to be downloaded. + */ +- (void)setDownloadTaskDidResumeBlock:(void (^)(NSURLSession *session, NSURLSessionDownloadTask *downloadTask, int64_t fileOffset, int64_t expectedTotalBytes))block; + +@end + +#endif + +///-------------------- +/// @name Notifications +///-------------------- + +/** + Posted when a task begins executing. + + @deprecated Use `AFNetworkingTaskDidResumeNotification` instead. + */ +extern NSString * const AFNetworkingTaskDidStartNotification DEPRECATED_ATTRIBUTE; + +/** + Posted when a task resumes. + */ +extern NSString * const AFNetworkingTaskDidResumeNotification; + +/** + Posted when a task finishes executing. Includes a userInfo dictionary with additional information about the task. + + @deprecated Use `AFNetworkingTaskDidCompleteNotification` instead. + */ +extern NSString * const AFNetworkingTaskDidFinishNotification DEPRECATED_ATTRIBUTE; + +/** + Posted when a task finishes executing. Includes a userInfo dictionary with additional information about the task. + */ +extern NSString * const AFNetworkingTaskDidCompleteNotification; + +/** + Posted when a task suspends its execution. + */ +extern NSString * const AFNetworkingTaskDidSuspendNotification; + +/** + Posted when a session is invalidated. + */ +extern NSString * const AFURLSessionDidInvalidateNotification; + +/** + Posted when a session download task encountered an error when moving the temporary download file to a specified destination. + */ +extern NSString * const AFURLSessionDownloadTaskDidFailToMoveFileNotification; + +/** + The raw response data of the task. Included in the userInfo dictionary of the `AFNetworkingTaskDidFinishNotification` if response data exists for the task. + + @deprecated Use `AFNetworkingTaskDidCompleteResponseDataKey` instead. + */ +extern NSString * const AFNetworkingTaskDidFinishResponseDataKey DEPRECATED_ATTRIBUTE; + +/** + The raw response data of the task. Included in the userInfo dictionary of the `AFNetworkingTaskDidFinishNotification` if response data exists for the task. + */ +extern NSString * const AFNetworkingTaskDidCompleteResponseDataKey; + +/** + The serialized response object of the task. Included in the userInfo dictionary of the `AFNetworkingTaskDidFinishNotification` if the response was serialized. + + @deprecated Use `AFNetworkingTaskDidCompleteSerializedResponseKey` instead. + */ +extern NSString * const AFNetworkingTaskDidFinishSerializedResponseKey DEPRECATED_ATTRIBUTE; + +/** + The serialized response object of the task. Included in the userInfo dictionary of the `AFNetworkingTaskDidFinishNotification` if the response was serialized. + */ +extern NSString * const AFNetworkingTaskDidCompleteSerializedResponseKey; + +/** + The response serializer used to serialize the response. Included in the userInfo dictionary of the `AFNetworkingTaskDidFinishNotification` if the task has an associated response serializer. + + @deprecated Use `AFNetworkingTaskDidCompleteResponseSerializerKey` instead. + */ +extern NSString * const AFNetworkingTaskDidFinishResponseSerializerKey DEPRECATED_ATTRIBUTE; + +/** + The response serializer used to serialize the response. Included in the userInfo dictionary of the `AFNetworkingTaskDidFinishNotification` if the task has an associated response serializer. + */ +extern NSString * const AFNetworkingTaskDidCompleteResponseSerializerKey; + +/** + The file path associated with the download task. Included in the userInfo dictionary of the `AFNetworkingTaskDidFinishNotification` if an the response data has been stored directly to disk. + + @deprecated Use `AFNetworkingTaskDidCompleteAssetPathKey` instead. + */ +extern NSString * const AFNetworkingTaskDidFinishAssetPathKey DEPRECATED_ATTRIBUTE; + +/** + The file path associated with the download task. Included in the userInfo dictionary of the `AFNetworkingTaskDidFinishNotification` if an the response data has been stored directly to disk. + */ +extern NSString * const AFNetworkingTaskDidCompleteAssetPathKey; + +/** + Any error associated with the task, or the serialization of the response. Included in the userInfo dictionary of the `AFNetworkingTaskDidFinishNotification` if an error exists. + + @deprecated Use `AFNetworkingTaskDidCompleteErrorKey` instead. + */ +extern NSString * const AFNetworkingTaskDidFinishErrorKey DEPRECATED_ATTRIBUTE; + +/** + Any error associated with the task, or the serialization of the response. Included in the userInfo dictionary of the `AFNetworkingTaskDidFinishNotification` if an error exists. + */ +extern NSString * const AFNetworkingTaskDidCompleteErrorKey; diff --git a/ios/Pods/AFNetworking/AFNetworking/AFURLSessionManager.m b/ios/Pods/AFNetworking/AFNetworking/AFURLSessionManager.m new file mode 100644 index 000000000..194cdfadb --- /dev/null +++ b/ios/Pods/AFNetworking/AFNetworking/AFURLSessionManager.m @@ -0,0 +1,1005 @@ +// AFURLSessionManager.m +// +// Copyright (c) 2013-2014 AFNetworking (http://afnetworking.com) +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +#import "AFURLSessionManager.h" + +#if (defined(__IPHONE_OS_VERSION_MAX_ALLOWED) && __IPHONE_OS_VERSION_MAX_ALLOWED >= 70000) || (defined(__MAC_OS_X_VERSION_MAX_ALLOWED) && __MAC_OS_X_VERSION_MAX_ALLOWED >= 1090) + +static dispatch_queue_t url_session_manager_processing_queue() { + static dispatch_queue_t af_url_session_manager_processing_queue; + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^{ + af_url_session_manager_processing_queue = dispatch_queue_create("com.alamofire.networking.session.manager.processing", DISPATCH_QUEUE_CONCURRENT); + }); + + return af_url_session_manager_processing_queue; +} + +static dispatch_group_t url_session_manager_completion_group() { + static dispatch_group_t af_url_session_manager_completion_group; + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^{ + af_url_session_manager_completion_group = dispatch_group_create(); + }); + + return af_url_session_manager_completion_group; +} + +NSString * const AFNetworkingTaskDidResumeNotification = @"com.alamofire.networking.task.resume"; +NSString * const AFNetworkingTaskDidCompleteNotification = @"com.alamofire.networking.task.complete"; +NSString * const AFNetworkingTaskDidSuspendNotification = @"com.alamofire.networking.task.suspend"; +NSString * const AFURLSessionDidInvalidateNotification = @"com.alamofire.networking.session.invalidate"; +NSString * const AFURLSessionDownloadTaskDidFailToMoveFileNotification = @"com.alamofire.networking.session.download.file-manager-error"; + +NSString * const AFNetworkingTaskDidStartNotification = @"com.alamofire.networking.task.resume"; // Deprecated +NSString * const AFNetworkingTaskDidFinishNotification = @"com.alamofire.networking.task.complete"; // Deprecated + +NSString * const AFNetworkingTaskDidCompleteSerializedResponseKey = @"com.alamofire.networking.task.complete.serializedresponse"; +NSString * const AFNetworkingTaskDidCompleteResponseSerializerKey = @"com.alamofire.networking.task.complete.responseserializer"; +NSString * const AFNetworkingTaskDidCompleteResponseDataKey = @"com.alamofire.networking.complete.finish.responsedata"; +NSString * const AFNetworkingTaskDidCompleteErrorKey = @"com.alamofire.networking.task.complete.error"; +NSString * const AFNetworkingTaskDidCompleteAssetPathKey = @"com.alamofire.networking.task.complete.assetpath"; + +NSString * const AFNetworkingTaskDidFinishSerializedResponseKey = @"com.alamofire.networking.task.complete.serializedresponse"; // Deprecated +NSString * const AFNetworkingTaskDidFinishResponseSerializerKey = @"com.alamofire.networking.task.complete.responseserializer"; // Deprecated +NSString * const AFNetworkingTaskDidFinishResponseDataKey = @"com.alamofire.networking.complete.finish.responsedata"; // Deprecated +NSString * const AFNetworkingTaskDidFinishErrorKey = @"com.alamofire.networking.task.complete.error"; // Deprecated +NSString * const AFNetworkingTaskDidFinishAssetPathKey = @"com.alamofire.networking.task.complete.assetpath"; // Deprecated + +static NSString * const AFURLSessionManagerLockName = @"com.alamofire.networking.session.manager.lock"; + +static NSUInteger const AFMaximumNumberOfToRecreateBackgroundSessionUploadTask = 3; + +static void * AFTaskStateChangedContext = &AFTaskStateChangedContext; + +typedef void (^AFURLSessionDidBecomeInvalidBlock)(NSURLSession *session, NSError *error); +typedef NSURLSessionAuthChallengeDisposition (^AFURLSessionDidReceiveAuthenticationChallengeBlock)(NSURLSession *session, NSURLAuthenticationChallenge *challenge, NSURLCredential * __autoreleasing *credential); + +typedef NSURLRequest * (^AFURLSessionTaskWillPerformHTTPRedirectionBlock)(NSURLSession *session, NSURLSessionTask *task, NSURLResponse *response, NSURLRequest *request); +typedef NSURLSessionAuthChallengeDisposition (^AFURLSessionTaskDidReceiveAuthenticationChallengeBlock)(NSURLSession *session, NSURLSessionTask *task, NSURLAuthenticationChallenge *challenge, NSURLCredential * __autoreleasing *credential); + +typedef NSInputStream * (^AFURLSessionTaskNeedNewBodyStreamBlock)(NSURLSession *session, NSURLSessionTask *task); +typedef void (^AFURLSessionTaskDidSendBodyDataBlock)(NSURLSession *session, NSURLSessionTask *task, int64_t bytesSent, int64_t totalBytesSent, int64_t totalBytesExpectedToSend); +typedef void (^AFURLSessionTaskDidCompleteBlock)(NSURLSession *session, NSURLSessionTask *task, NSError *error); + +typedef NSURLSessionResponseDisposition (^AFURLSessionDataTaskDidReceiveResponseBlock)(NSURLSession *session, NSURLSessionDataTask *dataTask, NSURLResponse *response); +typedef void (^AFURLSessionDataTaskDidBecomeDownloadTaskBlock)(NSURLSession *session, NSURLSessionDataTask *dataTask, NSURLSessionDownloadTask *downloadTask); +typedef void (^AFURLSessionDataTaskDidReceiveDataBlock)(NSURLSession *session, NSURLSessionDataTask *dataTask, NSData *data); +typedef NSCachedURLResponse * (^AFURLSessionDataTaskWillCacheResponseBlock)(NSURLSession *session, NSURLSessionDataTask *dataTask, NSCachedURLResponse *proposedResponse); +typedef void (^AFURLSessionDidFinishEventsForBackgroundURLSessionBlock)(NSURLSession *session); + +typedef NSURL * (^AFURLSessionDownloadTaskDidFinishDownloadingBlock)(NSURLSession *session, NSURLSessionDownloadTask *downloadTask, NSURL *location); +typedef void (^AFURLSessionDownloadTaskDidWriteDataBlock)(NSURLSession *session, NSURLSessionDownloadTask *downloadTask, int64_t bytesWritten, int64_t totalBytesWritten, int64_t totalBytesExpectedToWrite); +typedef void (^AFURLSessionDownloadTaskDidResumeBlock)(NSURLSession *session, NSURLSessionDownloadTask *downloadTask, int64_t fileOffset, int64_t expectedTotalBytes); + +typedef void (^AFURLSessionTaskCompletionHandler)(NSURLResponse *response, id responseObject, NSError *error); + +#pragma mark - + +@interface AFURLSessionManagerTaskDelegate : NSObject +@property (nonatomic, weak) AFURLSessionManager *manager; +@property (nonatomic, strong) NSMutableData *mutableData; +@property (nonatomic, strong) NSProgress *progress; +@property (nonatomic, copy) NSURL *downloadFileURL; +@property (nonatomic, copy) AFURLSessionDownloadTaskDidFinishDownloadingBlock downloadTaskDidFinishDownloading; +@property (nonatomic, copy) AFURLSessionTaskCompletionHandler completionHandler; +@end + +@implementation AFURLSessionManagerTaskDelegate + +- (instancetype)init { + self = [super init]; + if (!self) { + return nil; + } + + self.mutableData = [NSMutableData data]; + + self.progress = [NSProgress progressWithTotalUnitCount:0]; + + return self; +} + +#pragma mark - NSURLSessionTaskDelegate + +- (void)URLSession:(__unused NSURLSession *)session + task:(__unused NSURLSessionTask *)task + didSendBodyData:(__unused int64_t)bytesSent + totalBytesSent:(int64_t)totalBytesSent +totalBytesExpectedToSend:(int64_t)totalBytesExpectedToSend +{ + self.progress.totalUnitCount = totalBytesExpectedToSend; + self.progress.completedUnitCount = totalBytesSent; +} + +- (void)URLSession:(__unused NSURLSession *)session + task:(NSURLSessionTask *)task +didCompleteWithError:(NSError *)error +{ +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wgnu" + __strong AFURLSessionManager *manager = self.manager; + + __block id responseObject = nil; + + __block NSMutableDictionary *userInfo = [NSMutableDictionary dictionary]; + userInfo[AFNetworkingTaskDidCompleteResponseSerializerKey] = manager.responseSerializer; + + if (self.downloadFileURL) { + userInfo[AFNetworkingTaskDidCompleteAssetPathKey] = self.downloadFileURL; + } else if (self.mutableData) { + userInfo[AFNetworkingTaskDidCompleteResponseDataKey] = [NSData dataWithData:self.mutableData]; + } + + if (error) { + userInfo[AFNetworkingTaskDidCompleteErrorKey] = error; + + dispatch_group_async(manager.completionGroup ?: url_session_manager_completion_group(), manager.completionQueue ?: dispatch_get_main_queue(), ^{ + if (self.completionHandler) { + self.completionHandler(task.response, responseObject, error); + } + + dispatch_async(dispatch_get_main_queue(), ^{ + [[NSNotificationCenter defaultCenter] postNotificationName:AFNetworkingTaskDidCompleteNotification object:task userInfo:userInfo]; + }); + }); + } else { + dispatch_async(url_session_manager_processing_queue(), ^{ + NSError *serializationError = nil; + responseObject = [manager.responseSerializer responseObjectForResponse:task.response data:[NSData dataWithData:self.mutableData] error:&serializationError]; + + if (self.downloadFileURL) { + responseObject = self.downloadFileURL; + } + + if (responseObject) { + userInfo[AFNetworkingTaskDidCompleteSerializedResponseKey] = responseObject; + } + + if (serializationError) { + userInfo[AFNetworkingTaskDidCompleteErrorKey] = serializationError; + } + + dispatch_group_async(manager.completionGroup ?: url_session_manager_completion_group(), manager.completionQueue ?: dispatch_get_main_queue(), ^{ + if (self.completionHandler) { + self.completionHandler(task.response, responseObject, serializationError); + } + + dispatch_async(dispatch_get_main_queue(), ^{ + [[NSNotificationCenter defaultCenter] postNotificationName:AFNetworkingTaskDidCompleteNotification object:task userInfo:userInfo]; + }); + }); + }); + } +#pragma clang diagnostic pop +} + +#pragma mark - NSURLSessionDataTaskDelegate + +- (void)URLSession:(__unused NSURLSession *)session + dataTask:(__unused NSURLSessionDataTask *)dataTask + didReceiveData:(NSData *)data +{ + [self.mutableData appendData:data]; +} + +#pragma mark - NSURLSessionDownloadTaskDelegate + +- (void)URLSession:(NSURLSession *)session + downloadTask:(NSURLSessionDownloadTask *)downloadTask +didFinishDownloadingToURL:(NSURL *)location +{ + NSError *fileManagerError = nil; + self.downloadFileURL = nil; + + if (self.downloadTaskDidFinishDownloading) { + self.downloadFileURL = self.downloadTaskDidFinishDownloading(session, downloadTask, location); + if (self.downloadFileURL) { + [[NSFileManager defaultManager] moveItemAtURL:location toURL:self.downloadFileURL error:&fileManagerError]; + + if (fileManagerError) { + [[NSNotificationCenter defaultCenter] postNotificationName:AFURLSessionDownloadTaskDidFailToMoveFileNotification object:downloadTask userInfo:fileManagerError.userInfo]; + } + } + } +} + +- (void)URLSession:(__unused NSURLSession *)session + downloadTask:(__unused NSURLSessionDownloadTask *)downloadTask + didWriteData:(__unused int64_t)bytesWritten + totalBytesWritten:(int64_t)totalBytesWritten +totalBytesExpectedToWrite:(int64_t)totalBytesExpectedToWrite +{ + self.progress.totalUnitCount = totalBytesExpectedToWrite; + self.progress.completedUnitCount = totalBytesWritten; +} + +- (void)URLSession:(__unused NSURLSession *)session + downloadTask:(__unused NSURLSessionDownloadTask *)downloadTask + didResumeAtOffset:(int64_t)fileOffset +expectedTotalBytes:(int64_t)expectedTotalBytes { + self.progress.totalUnitCount = expectedTotalBytes; + self.progress.completedUnitCount = fileOffset; +} + +@end + +#pragma mark - + +@interface AFURLSessionManager () +@property (readwrite, nonatomic, strong) NSURLSessionConfiguration *sessionConfiguration; +@property (readwrite, nonatomic, strong) NSOperationQueue *operationQueue; +@property (readwrite, nonatomic, strong) NSURLSession *session; +@property (readwrite, nonatomic, strong) NSMutableDictionary *mutableTaskDelegatesKeyedByTaskIdentifier; +@property (readwrite, nonatomic, strong) NSLock *lock; +@property (readwrite, nonatomic, copy) AFURLSessionDidBecomeInvalidBlock sessionDidBecomeInvalid; +@property (readwrite, nonatomic, copy) AFURLSessionDidReceiveAuthenticationChallengeBlock sessionDidReceiveAuthenticationChallenge; +@property (readwrite, nonatomic, copy) AFURLSessionTaskWillPerformHTTPRedirectionBlock taskWillPerformHTTPRedirection; +@property (readwrite, nonatomic, copy) AFURLSessionTaskDidReceiveAuthenticationChallengeBlock taskDidReceiveAuthenticationChallenge; +@property (readwrite, nonatomic, copy) AFURLSessionTaskNeedNewBodyStreamBlock taskNeedNewBodyStream; +@property (readwrite, nonatomic, copy) AFURLSessionTaskDidSendBodyDataBlock taskDidSendBodyData; +@property (readwrite, nonatomic, copy) AFURLSessionTaskDidCompleteBlock taskDidComplete; +@property (readwrite, nonatomic, copy) AFURLSessionDataTaskDidReceiveResponseBlock dataTaskDidReceiveResponse; +@property (readwrite, nonatomic, copy) AFURLSessionDataTaskDidBecomeDownloadTaskBlock dataTaskDidBecomeDownloadTask; +@property (readwrite, nonatomic, copy) AFURLSessionDataTaskDidReceiveDataBlock dataTaskDidReceiveData; +@property (readwrite, nonatomic, copy) AFURLSessionDataTaskWillCacheResponseBlock dataTaskWillCacheResponse; +@property (readwrite, nonatomic, copy) AFURLSessionDidFinishEventsForBackgroundURLSessionBlock didFinishEventsForBackgroundURLSession; +@property (readwrite, nonatomic, copy) AFURLSessionDownloadTaskDidFinishDownloadingBlock downloadTaskDidFinishDownloading; +@property (readwrite, nonatomic, copy) AFURLSessionDownloadTaskDidWriteDataBlock downloadTaskDidWriteData; +@property (readwrite, nonatomic, copy) AFURLSessionDownloadTaskDidResumeBlock downloadTaskDidResume; +@end + +@implementation AFURLSessionManager + +- (instancetype)init { + return [self initWithSessionConfiguration:nil]; +} + +- (instancetype)initWithSessionConfiguration:(NSURLSessionConfiguration *)configuration { + self = [super init]; + if (!self) { + return nil; + } + + if (!configuration) { + configuration = [NSURLSessionConfiguration defaultSessionConfiguration]; + } + + self.operationQueue = [[NSOperationQueue alloc] init]; + self.operationQueue.maxConcurrentOperationCount = NSOperationQueueDefaultMaxConcurrentOperationCount; + + self.responseSerializer = [AFJSONResponseSerializer serializer]; + + self.sessionConfiguration = configuration; + self.session = [NSURLSession sessionWithConfiguration:self.sessionConfiguration delegate:self delegateQueue:self.operationQueue]; + + self.mutableTaskDelegatesKeyedByTaskIdentifier = [[NSMutableDictionary alloc] init]; + + self.securityPolicy = [AFSecurityPolicy defaultPolicy]; + + self.reachabilityManager = [AFNetworkReachabilityManager sharedManager]; + + self.lock = [[NSLock alloc] init]; + self.lock.name = AFURLSessionManagerLockName; + + [self.session getTasksWithCompletionHandler:^(NSArray *dataTasks, NSArray *uploadTasks, NSArray *downloadTasks) { + for (NSURLSessionDataTask *task in dataTasks) { + [self addDelegateForDataTask:task completionHandler:nil]; + } + + for (NSURLSessionUploadTask *uploadTask in uploadTasks) { + [self addDelegateForUploadTask:uploadTask progress:nil completionHandler:nil]; + } + + for (NSURLSessionDownloadTask *downloadTask in downloadTasks) { + [self addDelegateForDownloadTask:downloadTask progress:nil destination:nil completionHandler:nil]; + } + }]; + + return self; +} + +#pragma mark - + +- (AFURLSessionManagerTaskDelegate *)delegateForTask:(NSURLSessionTask *)task { + NSParameterAssert(task); + + AFURLSessionManagerTaskDelegate *delegate = nil; + [self.lock lock]; + delegate = self.mutableTaskDelegatesKeyedByTaskIdentifier[@(task.taskIdentifier)]; + [self.lock unlock]; + + return delegate; +} + +- (void)setDelegate:(AFURLSessionManagerTaskDelegate *)delegate + forTask:(NSURLSessionTask *)task +{ + NSParameterAssert(task); + NSParameterAssert(delegate); + + [self.lock lock]; + [task addObserver:self forKeyPath:NSStringFromSelector(@selector(state)) options:NSKeyValueObservingOptionOld |NSKeyValueObservingOptionNew context:AFTaskStateChangedContext]; + self.mutableTaskDelegatesKeyedByTaskIdentifier[@(task.taskIdentifier)] = delegate; + [self.lock unlock]; +} + +- (void)addDelegateForDataTask:(NSURLSessionDataTask *)dataTask + completionHandler:(void (^)(NSURLResponse *response, id responseObject, NSError *error))completionHandler +{ + AFURLSessionManagerTaskDelegate *delegate = [[AFURLSessionManagerTaskDelegate alloc] init]; + delegate.manager = self; + delegate.completionHandler = completionHandler; + + [self setDelegate:delegate forTask:dataTask]; +} + +- (void)addDelegateForUploadTask:(NSURLSessionUploadTask *)uploadTask + progress:(NSProgress * __autoreleasing *)progress + completionHandler:(void (^)(NSURLResponse *response, id responseObject, NSError *error))completionHandler +{ + AFURLSessionManagerTaskDelegate *delegate = [[AFURLSessionManagerTaskDelegate alloc] init]; + delegate.manager = self; + delegate.completionHandler = completionHandler; + + int64_t totalUnitCount = uploadTask.countOfBytesExpectedToSend; + if(totalUnitCount == NSURLSessionTransferSizeUnknown) { + NSString *contentLength = [uploadTask.originalRequest valueForHTTPHeaderField:@"Content-Length"]; + if(contentLength) { + totalUnitCount = (int64_t) [contentLength longLongValue]; + } + } + + delegate.progress = [NSProgress progressWithTotalUnitCount:totalUnitCount]; + delegate.progress.pausingHandler = ^{ + [uploadTask suspend]; + }; + delegate.progress.cancellationHandler = ^{ + [uploadTask cancel]; + }; + + if (progress) { + *progress = delegate.progress; + } + + [self setDelegate:delegate forTask:uploadTask]; +} + +- (void)addDelegateForDownloadTask:(NSURLSessionDownloadTask *)downloadTask + progress:(NSProgress * __autoreleasing *)progress + destination:(NSURL * (^)(NSURL *targetPath, NSURLResponse *response))destination + completionHandler:(void (^)(NSURLResponse *response, NSURL *filePath, NSError *error))completionHandler +{ + AFURLSessionManagerTaskDelegate *delegate = [[AFURLSessionManagerTaskDelegate alloc] init]; + delegate.manager = self; + delegate.completionHandler = completionHandler; + + delegate.downloadTaskDidFinishDownloading = ^NSURL * (NSURLSession * __unused session, NSURLSessionDownloadTask *task, NSURL *location) { + if (destination) { + return destination(location, task.response); + } + + return location; + }; + + if (progress) { + *progress = delegate.progress; + } + + [self setDelegate:delegate forTask:downloadTask]; +} + +- (void)removeDelegateForTask:(NSURLSessionTask *)task { + NSParameterAssert(task); + + [self.lock lock]; + [task removeObserver:self forKeyPath:NSStringFromSelector(@selector(state)) context:AFTaskStateChangedContext]; + [self.mutableTaskDelegatesKeyedByTaskIdentifier removeObjectForKey:@(task.taskIdentifier)]; + [self.lock unlock]; +} + +- (void)removeAllDelegates { + [self.lock lock]; + [self.mutableTaskDelegatesKeyedByTaskIdentifier removeAllObjects]; + [self.lock unlock]; +} + +#pragma mark - + +- (NSArray *)tasksForKeyPath:(NSString *)keyPath { + __block NSArray *tasks = nil; + dispatch_semaphore_t semaphore = dispatch_semaphore_create(0); + [self.session getTasksWithCompletionHandler:^(NSArray *dataTasks, NSArray *uploadTasks, NSArray *downloadTasks) { + if ([keyPath isEqualToString:NSStringFromSelector(@selector(dataTasks))]) { + tasks = dataTasks; + } else if ([keyPath isEqualToString:NSStringFromSelector(@selector(uploadTasks))]) { + tasks = uploadTasks; + } else if ([keyPath isEqualToString:NSStringFromSelector(@selector(downloadTasks))]) { + tasks = downloadTasks; + } else if ([keyPath isEqualToString:NSStringFromSelector(@selector(tasks))]) { + tasks = [@[dataTasks, uploadTasks, downloadTasks] valueForKeyPath:@"@unionOfArrays.self"]; + } + + dispatch_semaphore_signal(semaphore); + }]; + + dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER); + + return tasks; +} + +- (NSArray *)tasks { + return [self tasksForKeyPath:NSStringFromSelector(_cmd)]; +} + +- (NSArray *)dataTasks { + return [self tasksForKeyPath:NSStringFromSelector(_cmd)]; +} + +- (NSArray *)uploadTasks { + return [self tasksForKeyPath:NSStringFromSelector(_cmd)]; +} + +- (NSArray *)downloadTasks { + return [self tasksForKeyPath:NSStringFromSelector(_cmd)]; +} + +#pragma mark - + +- (void)invalidateSessionCancelingTasks:(BOOL)cancelPendingTasks { + if (cancelPendingTasks) { + [self.session invalidateAndCancel]; + } else { + [self.session finishTasksAndInvalidate]; + } +} + +#pragma mark - + +- (void)setResponseSerializer:(id )responseSerializer { + NSParameterAssert(responseSerializer); + + _responseSerializer = responseSerializer; +} + +#pragma mark - + +- (NSURLSessionDataTask *)dataTaskWithRequest:(NSURLRequest *)request + completionHandler:(void (^)(NSURLResponse *response, id responseObject, NSError *error))completionHandler +{ + NSURLSessionDataTask *dataTask = [self.session dataTaskWithRequest:request]; + + [self addDelegateForDataTask:dataTask completionHandler:completionHandler]; + + return dataTask; +} + +#pragma mark - + +- (NSURLSessionUploadTask *)uploadTaskWithRequest:(NSURLRequest *)request + fromFile:(NSURL *)fileURL + progress:(NSProgress * __autoreleasing *)progress + completionHandler:(void (^)(NSURLResponse *response, id responseObject, NSError *error))completionHandler +{ + NSURLSessionUploadTask *uploadTask = [self.session uploadTaskWithRequest:request fromFile:fileURL]; + if (!uploadTask && self.attemptsToRecreateUploadTasksForBackgroundSessions && self.session.configuration.identifier) { + for (NSUInteger attempts = 0; !uploadTask && attempts < AFMaximumNumberOfToRecreateBackgroundSessionUploadTask; attempts++) { + uploadTask = [self.session uploadTaskWithRequest:request fromFile:fileURL]; + } + } + + [self addDelegateForUploadTask:uploadTask progress:progress completionHandler:completionHandler]; + + return uploadTask; +} + +- (NSURLSessionUploadTask *)uploadTaskWithRequest:(NSURLRequest *)request + fromData:(NSData *)bodyData + progress:(NSProgress * __autoreleasing *)progress + completionHandler:(void (^)(NSURLResponse *response, id responseObject, NSError *error))completionHandler +{ + NSURLSessionUploadTask *uploadTask = [self.session uploadTaskWithRequest:request fromData:bodyData]; + + [self addDelegateForUploadTask:uploadTask progress:progress completionHandler:completionHandler]; + + return uploadTask; +} + +- (NSURLSessionUploadTask *)uploadTaskWithStreamedRequest:(NSURLRequest *)request + progress:(NSProgress * __autoreleasing *)progress + completionHandler:(void (^)(NSURLResponse *response, id responseObject, NSError *error))completionHandler +{ + NSURLSessionUploadTask *uploadTask = [self.session uploadTaskWithStreamedRequest:request]; + + [self addDelegateForUploadTask:uploadTask progress:progress completionHandler:completionHandler]; + + return uploadTask; +} + +#pragma mark - + +- (NSURLSessionDownloadTask *)downloadTaskWithRequest:(NSURLRequest *)request + progress:(NSProgress * __autoreleasing *)progress + destination:(NSURL * (^)(NSURL *targetPath, NSURLResponse *response))destination + completionHandler:(void (^)(NSURLResponse *response, NSURL *filePath, NSError *error))completionHandler +{ + NSURLSessionDownloadTask *downloadTask = [self.session downloadTaskWithRequest:request]; + + [self addDelegateForDownloadTask:downloadTask progress:progress destination:destination completionHandler:completionHandler]; + + return downloadTask; +} + +- (NSURLSessionDownloadTask *)downloadTaskWithResumeData:(NSData *)resumeData + progress:(NSProgress * __autoreleasing *)progress + destination:(NSURL * (^)(NSURL *targetPath, NSURLResponse *response))destination + completionHandler:(void (^)(NSURLResponse *response, NSURL *filePath, NSError *error))completionHandler +{ + NSURLSessionDownloadTask *downloadTask = [self.session downloadTaskWithResumeData:resumeData]; + + [self addDelegateForDownloadTask:downloadTask progress:progress destination:destination completionHandler:completionHandler]; + + return downloadTask; +} + +#pragma mark - + +- (NSProgress *)uploadProgressForTask:(NSURLSessionUploadTask *)uploadTask { + return [[self delegateForTask:uploadTask] progress]; +} + +- (NSProgress *)downloadProgressForTask:(NSURLSessionDownloadTask *)downloadTask { + return [[self delegateForTask:downloadTask] progress]; +} + +#pragma mark - + +- (void)setSessionDidBecomeInvalidBlock:(void (^)(NSURLSession *session, NSError *error))block { + self.sessionDidBecomeInvalid = block; +} + +- (void)setSessionDidReceiveAuthenticationChallengeBlock:(NSURLSessionAuthChallengeDisposition (^)(NSURLSession *session, NSURLAuthenticationChallenge *challenge, NSURLCredential * __autoreleasing *credential))block { + self.sessionDidReceiveAuthenticationChallenge = block; +} + +#pragma mark - + +- (void)setTaskNeedNewBodyStreamBlock:(NSInputStream * (^)(NSURLSession *session, NSURLSessionTask *task))block { + self.taskNeedNewBodyStream = block; +} + +- (void)setTaskWillPerformHTTPRedirectionBlock:(NSURLRequest * (^)(NSURLSession *session, NSURLSessionTask *task, NSURLResponse *response, NSURLRequest *request))block { + self.taskWillPerformHTTPRedirection = block; +} + +- (void)setTaskDidReceiveAuthenticationChallengeBlock:(NSURLSessionAuthChallengeDisposition (^)(NSURLSession *session, NSURLSessionTask *task, NSURLAuthenticationChallenge *challenge, NSURLCredential * __autoreleasing *credential))block { + self.taskDidReceiveAuthenticationChallenge = block; +} + +- (void)setTaskDidSendBodyDataBlock:(void (^)(NSURLSession *session, NSURLSessionTask *task, int64_t bytesSent, int64_t totalBytesSent, int64_t totalBytesExpectedToSend))block { + self.taskDidSendBodyData = block; +} + +- (void)setTaskDidCompleteBlock:(void (^)(NSURLSession *session, NSURLSessionTask *task, NSError *error))block { + self.taskDidComplete = block; +} + +#pragma mark - + +- (void)setDataTaskDidReceiveResponseBlock:(NSURLSessionResponseDisposition (^)(NSURLSession *session, NSURLSessionDataTask *dataTask, NSURLResponse *response))block { + self.dataTaskDidReceiveResponse = block; +} + +- (void)setDataTaskDidBecomeDownloadTaskBlock:(void (^)(NSURLSession *session, NSURLSessionDataTask *dataTask, NSURLSessionDownloadTask *downloadTask))block { + self.dataTaskDidBecomeDownloadTask = block; +} + +- (void)setDataTaskDidReceiveDataBlock:(void (^)(NSURLSession *session, NSURLSessionDataTask *dataTask, NSData *data))block { + self.dataTaskDidReceiveData = block; +} + +- (void)setDataTaskWillCacheResponseBlock:(NSCachedURLResponse * (^)(NSURLSession *session, NSURLSessionDataTask *dataTask, NSCachedURLResponse *proposedResponse))block { + self.dataTaskWillCacheResponse = block; +} + +- (void)setDidFinishEventsForBackgroundURLSessionBlock:(void (^)(NSURLSession *session))block { + self.didFinishEventsForBackgroundURLSession = block; +} + +#pragma mark - + +- (void)setDownloadTaskDidFinishDownloadingBlock:(NSURL * (^)(NSURLSession *session, NSURLSessionDownloadTask *downloadTask, NSURL *location))block { + self.downloadTaskDidFinishDownloading = block; +} + +- (void)setDownloadTaskDidWriteDataBlock:(void (^)(NSURLSession *session, NSURLSessionDownloadTask *downloadTask, int64_t bytesWritten, int64_t totalBytesWritten, int64_t totalBytesExpectedToWrite))block { + self.downloadTaskDidWriteData = block; +} + +- (void)setDownloadTaskDidResumeBlock:(void (^)(NSURLSession *session, NSURLSessionDownloadTask *downloadTask, int64_t fileOffset, int64_t expectedTotalBytes))block { + self.downloadTaskDidResume = block; +} + +#pragma mark - NSObject + +- (NSString *)description { + return [NSString stringWithFormat:@"<%@: %p, session: %@, operationQueue: %@>", NSStringFromClass([self class]), self, self.session, self.operationQueue]; +} + +- (BOOL)respondsToSelector:(SEL)selector { + if (selector == @selector(URLSession:task:willPerformHTTPRedirection:newRequest:completionHandler:)) { + return self.taskWillPerformHTTPRedirection != nil; + } else if (selector == @selector(URLSession:dataTask:didReceiveResponse:completionHandler:)) { + return self.dataTaskDidReceiveResponse != nil; + } else if (selector == @selector(URLSession:dataTask:willCacheResponse:completionHandler:)) { + return self.dataTaskWillCacheResponse != nil; + } else if (selector == @selector(URLSessionDidFinishEventsForBackgroundURLSession:)) { + return self.didFinishEventsForBackgroundURLSession != nil; + } + + return [[self class] instancesRespondToSelector:selector]; +} + +#pragma mark - NSKeyValueObserving + +- (void)observeValueForKeyPath:(NSString *)keyPath + ofObject:(id)object + change:(NSDictionary *)change + context:(void *)context +{ + if (context == AFTaskStateChangedContext && [keyPath isEqualToString:@"state"]) { + if (change[NSKeyValueChangeOldKey] && change[NSKeyValueChangeNewKey] && [change[NSKeyValueChangeNewKey] isEqual:change[NSKeyValueChangeOldKey]]) { + return; + } + + NSString *notificationName = nil; + switch ([(NSURLSessionTask *)object state]) { + case NSURLSessionTaskStateRunning: + notificationName = AFNetworkingTaskDidResumeNotification; + break; + case NSURLSessionTaskStateSuspended: + notificationName = AFNetworkingTaskDidSuspendNotification; + break; + case NSURLSessionTaskStateCompleted: + // AFNetworkingTaskDidFinishNotification posted by task completion handlers + default: + break; + } + + if (notificationName) { + dispatch_async(dispatch_get_main_queue(), ^{ + [[NSNotificationCenter defaultCenter] postNotificationName:notificationName object:object]; + }); + } + } else { + [super observeValueForKeyPath:keyPath ofObject:object change:change context:context]; + } +} + +#pragma mark - NSURLSessionDelegate + +- (void)URLSession:(NSURLSession *)session +didBecomeInvalidWithError:(NSError *)error +{ + if (self.sessionDidBecomeInvalid) { + self.sessionDidBecomeInvalid(session, error); + } + + [self.session getTasksWithCompletionHandler:^(NSArray *dataTasks, NSArray *uploadTasks, NSArray *downloadTasks) { + NSArray *tasks = [@[dataTasks, uploadTasks, downloadTasks] valueForKeyPath:@"@unionOfArrays.self"]; + for (NSURLSessionTask *task in tasks) { + [task removeObserver:self forKeyPath:NSStringFromSelector(@selector(state)) context:AFTaskStateChangedContext]; + } + + [self removeAllDelegates]; + }]; + + [[NSNotificationCenter defaultCenter] postNotificationName:AFURLSessionDidInvalidateNotification object:session]; +} + +- (void)URLSession:(NSURLSession *)session +didReceiveChallenge:(NSURLAuthenticationChallenge *)challenge + completionHandler:(void (^)(NSURLSessionAuthChallengeDisposition disposition, NSURLCredential *credential))completionHandler +{ + NSURLSessionAuthChallengeDisposition disposition = NSURLSessionAuthChallengePerformDefaultHandling; + __block NSURLCredential *credential = nil; + + if (self.sessionDidReceiveAuthenticationChallenge) { + disposition = self.sessionDidReceiveAuthenticationChallenge(session, challenge, &credential); + } else { + if ([challenge.protectionSpace.authenticationMethod isEqualToString:NSURLAuthenticationMethodServerTrust]) { + if ([self.securityPolicy evaluateServerTrust:challenge.protectionSpace.serverTrust forDomain:challenge.protectionSpace.host]) { + credential = [NSURLCredential credentialForTrust:challenge.protectionSpace.serverTrust]; + if (credential) { + disposition = NSURLSessionAuthChallengeUseCredential; + } else { + disposition = NSURLSessionAuthChallengePerformDefaultHandling; + } + } else { + disposition = NSURLSessionAuthChallengeCancelAuthenticationChallenge; + } + } else { + disposition = NSURLSessionAuthChallengePerformDefaultHandling; + } + } + + if (completionHandler) { + completionHandler(disposition, credential); + } +} + +#pragma mark - NSURLSessionTaskDelegate + +- (void)URLSession:(NSURLSession *)session + task:(NSURLSessionTask *)task +willPerformHTTPRedirection:(NSHTTPURLResponse *)response + newRequest:(NSURLRequest *)request + completionHandler:(void (^)(NSURLRequest *))completionHandler +{ + NSURLRequest *redirectRequest = request; + + if (self.taskWillPerformHTTPRedirection) { + redirectRequest = self.taskWillPerformHTTPRedirection(session, task, response, request); + } + + if (completionHandler) { + completionHandler(redirectRequest); + } +} + +- (void)URLSession:(NSURLSession *)session + task:(NSURLSessionTask *)task +didReceiveChallenge:(NSURLAuthenticationChallenge *)challenge + completionHandler:(void (^)(NSURLSessionAuthChallengeDisposition disposition, NSURLCredential *credential))completionHandler +{ + NSURLSessionAuthChallengeDisposition disposition = NSURLSessionAuthChallengePerformDefaultHandling; + __block NSURLCredential *credential = nil; + + if (self.taskDidReceiveAuthenticationChallenge) { + disposition = self.taskDidReceiveAuthenticationChallenge(session, task, challenge, &credential); + } else { + if ([challenge.protectionSpace.authenticationMethod isEqualToString:NSURLAuthenticationMethodServerTrust]) { + if ([self.securityPolicy evaluateServerTrust:challenge.protectionSpace.serverTrust forDomain:challenge.protectionSpace.host]) { + disposition = NSURLSessionAuthChallengeUseCredential; + credential = [NSURLCredential credentialForTrust:challenge.protectionSpace.serverTrust]; + } else { + disposition = NSURLSessionAuthChallengeCancelAuthenticationChallenge; + } + } else { + disposition = NSURLSessionAuthChallengePerformDefaultHandling; + } + } + + if (completionHandler) { + completionHandler(disposition, credential); + } +} + +- (void)URLSession:(NSURLSession *)session + task:(NSURLSessionTask *)task + needNewBodyStream:(void (^)(NSInputStream *bodyStream))completionHandler +{ + NSInputStream *inputStream = nil; + + if (self.taskNeedNewBodyStream) { + inputStream = self.taskNeedNewBodyStream(session, task); + } else if (task.originalRequest.HTTPBodyStream && [task.originalRequest.HTTPBodyStream conformsToProtocol:@protocol(NSCopying)]) { + inputStream = [task.originalRequest.HTTPBodyStream copy]; + } + + if (completionHandler) { + completionHandler(inputStream); + } +} + +- (void)URLSession:(NSURLSession *)session + task:(NSURLSessionTask *)task + didSendBodyData:(int64_t)bytesSent + totalBytesSent:(int64_t)totalBytesSent +totalBytesExpectedToSend:(int64_t)totalBytesExpectedToSend +{ + + int64_t totalUnitCount = totalBytesExpectedToSend; + if(totalUnitCount == NSURLSessionTransferSizeUnknown) { + NSString *contentLength = [task.originalRequest valueForHTTPHeaderField:@"Content-Length"]; + if(contentLength) { + totalUnitCount = (int64_t) [contentLength longLongValue]; + } + } + + AFURLSessionManagerTaskDelegate *delegate = [self delegateForTask:task]; + [delegate URLSession:session task:task didSendBodyData:bytesSent totalBytesSent:totalBytesSent totalBytesExpectedToSend:totalUnitCount]; + + if (self.taskDidSendBodyData) { + self.taskDidSendBodyData(session, task, bytesSent, totalBytesSent, totalUnitCount); + } +} + +- (void)URLSession:(NSURLSession *)session + task:(NSURLSessionTask *)task +didCompleteWithError:(NSError *)error +{ + AFURLSessionManagerTaskDelegate *delegate = [self delegateForTask:task]; + + // delegate may be nil when completing a task in the background + if (delegate) { + [delegate URLSession:session task:task didCompleteWithError:error]; + + [self removeDelegateForTask:task]; + } + + if (self.taskDidComplete) { + self.taskDidComplete(session, task, error); + } + +} + +#pragma mark - NSURLSessionDataDelegate + +- (void)URLSession:(NSURLSession *)session + dataTask:(NSURLSessionDataTask *)dataTask +didReceiveResponse:(NSURLResponse *)response + completionHandler:(void (^)(NSURLSessionResponseDisposition disposition))completionHandler +{ + NSURLSessionResponseDisposition disposition = NSURLSessionResponseAllow; + + if (self.dataTaskDidReceiveResponse) { + disposition = self.dataTaskDidReceiveResponse(session, dataTask, response); + } + + if (completionHandler) { + completionHandler(disposition); + } +} + +- (void)URLSession:(NSURLSession *)session + dataTask:(NSURLSessionDataTask *)dataTask +didBecomeDownloadTask:(NSURLSessionDownloadTask *)downloadTask +{ + AFURLSessionManagerTaskDelegate *delegate = [self delegateForTask:dataTask]; + if (delegate) { + [self removeDelegateForTask:dataTask]; + [self setDelegate:delegate forTask:downloadTask]; + } + + if (self.dataTaskDidBecomeDownloadTask) { + self.dataTaskDidBecomeDownloadTask(session, dataTask, downloadTask); + } +} + +- (void)URLSession:(NSURLSession *)session + dataTask:(NSURLSessionDataTask *)dataTask + didReceiveData:(NSData *)data +{ + AFURLSessionManagerTaskDelegate *delegate = [self delegateForTask:dataTask]; + [delegate URLSession:session dataTask:dataTask didReceiveData:data]; + + if (self.dataTaskDidReceiveData) { + self.dataTaskDidReceiveData(session, dataTask, data); + } +} + +- (void)URLSession:(NSURLSession *)session + dataTask:(NSURLSessionDataTask *)dataTask + willCacheResponse:(NSCachedURLResponse *)proposedResponse + completionHandler:(void (^)(NSCachedURLResponse *cachedResponse))completionHandler +{ + NSCachedURLResponse *cachedResponse = proposedResponse; + + if (self.dataTaskWillCacheResponse) { + cachedResponse = self.dataTaskWillCacheResponse(session, dataTask, proposedResponse); + } + + if (completionHandler) { + completionHandler(cachedResponse); + } +} + +- (void)URLSessionDidFinishEventsForBackgroundURLSession:(NSURLSession *)session { + if (self.didFinishEventsForBackgroundURLSession) { + dispatch_async(dispatch_get_main_queue(), ^{ + self.didFinishEventsForBackgroundURLSession(session); + }); + } +} + +#pragma mark - NSURLSessionDownloadDelegate + +- (void)URLSession:(NSURLSession *)session + downloadTask:(NSURLSessionDownloadTask *)downloadTask +didFinishDownloadingToURL:(NSURL *)location +{ + if (self.downloadTaskDidFinishDownloading) { + NSURL *fileURL = self.downloadTaskDidFinishDownloading(session, downloadTask, location); + if (fileURL) { + NSError *error = nil; + [[NSFileManager defaultManager] moveItemAtURL:location toURL:fileURL error:&error]; + if (error) { + [[NSNotificationCenter defaultCenter] postNotificationName:AFURLSessionDownloadTaskDidFailToMoveFileNotification object:downloadTask userInfo:error.userInfo]; + } + return; + } + } + + AFURLSessionManagerTaskDelegate *delegate = [self delegateForTask:downloadTask]; + if (delegate) { + [delegate URLSession:session downloadTask:downloadTask didFinishDownloadingToURL:location]; + } +} + +- (void)URLSession:(NSURLSession *)session + downloadTask:(NSURLSessionDownloadTask *)downloadTask + didWriteData:(int64_t)bytesWritten + totalBytesWritten:(int64_t)totalBytesWritten +totalBytesExpectedToWrite:(int64_t)totalBytesExpectedToWrite +{ + AFURLSessionManagerTaskDelegate *delegate = [self delegateForTask:downloadTask]; + [delegate URLSession:session downloadTask:downloadTask didWriteData:bytesWritten totalBytesWritten:totalBytesWritten totalBytesExpectedToWrite:totalBytesExpectedToWrite]; + + if (self.downloadTaskDidWriteData) { + self.downloadTaskDidWriteData(session, downloadTask, bytesWritten, totalBytesWritten, totalBytesExpectedToWrite); + } +} + +- (void)URLSession:(NSURLSession *)session + downloadTask:(NSURLSessionDownloadTask *)downloadTask + didResumeAtOffset:(int64_t)fileOffset +expectedTotalBytes:(int64_t)expectedTotalBytes +{ + AFURLSessionManagerTaskDelegate *delegate = [self delegateForTask:downloadTask]; + [delegate URLSession:session downloadTask:downloadTask didResumeAtOffset:fileOffset expectedTotalBytes:expectedTotalBytes]; + + if (self.downloadTaskDidResume) { + self.downloadTaskDidResume(session, downloadTask, fileOffset, expectedTotalBytes); + } +} + +#pragma mark - NSecureCoding + ++ (BOOL)supportsSecureCoding { + return YES; +} + +- (id)initWithCoder:(NSCoder *)decoder { + NSURLSessionConfiguration *configuration = [decoder decodeObjectOfClass:[NSURLSessionConfiguration class] forKey:@"sessionConfiguration"]; + + self = [self initWithSessionConfiguration:configuration]; + if (!self) { + return nil; + } + + return self; +} + +- (void)encodeWithCoder:(NSCoder *)coder { + [coder encodeObject:self.session.configuration forKey:@"sessionConfiguration"]; +} + +#pragma mark - NSCopying + +- (id)copyWithZone:(NSZone *)zone { + return [[[self class] allocWithZone:zone] initWithSessionConfiguration:self.session.configuration]; +} + +@end + +#endif diff --git a/ios/Pods/AFNetworking/LICENSE b/ios/Pods/AFNetworking/LICENSE new file mode 100644 index 000000000..0616192d0 --- /dev/null +++ b/ios/Pods/AFNetworking/LICENSE @@ -0,0 +1,19 @@ +Copyright (c) 2013-2014 AFNetworking (http://afnetworking.com/) + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. diff --git a/ios/Pods/AFNetworking/README.md b/ios/Pods/AFNetworking/README.md new file mode 100644 index 000000000..aac6b2b77 --- /dev/null +++ b/ios/Pods/AFNetworking/README.md @@ -0,0 +1,381 @@ +

+ AFNetworking +

+ +[![Build Status](https://travis-ci.org/AFNetworking/AFNetworking.svg)](https://travis-ci.org/AFNetworking/AFNetworking) + +AFNetworking is a delightful networking library for iOS and Mac OS X. It's built on top of the [Foundation URL Loading System](http://developer.apple.com/library/mac/#documentation/Cocoa/Conceptual/URLLoadingSystem/URLLoadingSystem.html), extending the powerful high-level networking abstractions built into Cocoa. It has a modular architecture with well-designed, feature-rich APIs that are a joy to use. + +Perhaps the most important feature of all, however, is the amazing community of developers who use and contribute to AFNetworking every day. AFNetworking powers some of the most popular and critically-acclaimed apps on the iPhone, iPad, and Mac. + +Choose AFNetworking for your next project, or migrate over your existing projects—you'll be happy you did! + +## How To Get Started + +- [Download AFNetworking](https://github.com/AFNetworking/AFNetworking/archive/master.zip) and try out the included Mac and iPhone example apps +- Read the ["Getting Started" guide](https://github.com/AFNetworking/AFNetworking/wiki/Getting-Started-with-AFNetworking), [FAQ](https://github.com/AFNetworking/AFNetworking/wiki/AFNetworking-FAQ), or [other articles on the Wiki](https://github.com/AFNetworking/AFNetworking/wiki) +- Check out the [documentation](http://cocoadocs.org/docsets/AFNetworking/2.0.0/) for a comprehensive look at all of the APIs available in AFNetworking +- Read the [AFNetworking 2.0 Migration Guide](https://github.com/AFNetworking/AFNetworking/wiki/AFNetworking-2.0-Migration-Guide) for an overview of the architectural changes from 1.0. + +## Communication + +- If you **need help**, use [Stack Overflow](http://stackoverflow.com/questions/tagged/afnetworking). (Tag 'afnetworking') +- If you'd like to **ask a general question**, use [Stack Overflow](http://stackoverflow.com/questions/tagged/afnetworking). +- If you **found a bug**, open an issue. +- If you **have a feature request**, open an issue. +- If you **want to contribute**, submit a pull request. + +### Installation with CocoaPods + +[CocoaPods](http://cocoapods.org) is a dependency manager for Objective-C, which automates and simplifies the process of using 3rd-party libraries like AFNetworking in your projects. See the ["Getting Started" guide for more information](https://github.com/AFNetworking/AFNetworking/wiki/Getting-Started-with-AFNetworking). + +#### Podfile + +```ruby +platform :ios, '7.0' +pod "AFNetworking", "~> 2.0" +``` + +## Requirements + +| AFNetworking Version | Minimum iOS Target | Minimum OS X Target | Notes | +|:--------------------:|:---------------------------:|:----------------------------:|:-------------------------------------------------------------------------:| +| 2.x | iOS 6 | OS X 10.8 | Xcode 5 is required. `AFHTTPSessionManager` requires iOS 7 or OS X 10.9. | +| [1.x](https://github.com/AFNetworking/AFNetworking/tree/1.x) | iOS 5 | Mac OS X 10.7 | | +| [0.10.x](https://github.com/AFNetworking/AFNetworking/tree/0.10.x) | iOS 4 | Mac OS X 10.6 | | + +(OS X projects must support [64-bit with modern Cocoa runtime](https://developer.apple.com/library/mac/#documentation/Cocoa/Conceptual/ObjCRuntimeGuide/Articles/ocrtVersionsPlatforms.html)). + +## Architecture + +### NSURLConnection + +- `AFURLConnectionOperation` +- `AFHTTPRequestOperation` +- `AFHTTPRequestOperationManager` + +### NSURLSession _(iOS 7 / Mac OS X 10.9)_ + +- `AFURLSessionManager` +- `AFHTTPSessionManager` + +### Serialization + +* `` + - `AFHTTPRequestSerializer` + - `AFJSONRequestSerializer` + - `AFPropertyListRequestSerializer` +* `` + - `AFHTTPResponseSerializer` + - `AFJSONResponseSerializer` + - `AFXMLParserResponseSerializer` + - `AFXMLDocumentResponseSerializer` _(Mac OS X)_ + - `AFPropertyListResponseSerializer` + - `AFImageResponseSerializer` + - `AFCompoundResponseSerializer` + +### Additional Functionality + +- `AFSecurityPolicy` +- `AFNetworkReachabilityManager` + +## Usage + +### HTTP Request Operation Manager + +`AFHTTPRequestOperationManager` encapsulates the common patterns of communicating with a web application over HTTP, including request creation, response serialization, network reachability monitoring, and security, as well as request operation management. + +#### `GET` Request + +```objective-c +AFHTTPRequestOperationManager *manager = [AFHTTPRequestOperationManager manager]; +[manager GET:@"http://example.com/resources.json" parameters:nil success:^(AFHTTPRequestOperation *operation, id responseObject) { + NSLog(@"JSON: %@", responseObject); +} failure:^(AFHTTPRequestOperation *operation, NSError *error) { + NSLog(@"Error: %@", error); +}]; +``` + +#### `POST` URL-Form-Encoded Request + +```objective-c +AFHTTPRequestOperationManager *manager = [AFHTTPRequestOperationManager manager]; +NSDictionary *parameters = @{@"foo": @"bar"}; +[manager POST:@"http://example.com/resources.json" parameters:parameters success:^(AFHTTPRequestOperation *operation, id responseObject) { + NSLog(@"JSON: %@", responseObject); +} failure:^(AFHTTPRequestOperation *operation, NSError *error) { + NSLog(@"Error: %@", error); +}]; +``` + +#### `POST` Multi-Part Request + +```objective-c +AFHTTPRequestOperationManager *manager = [AFHTTPRequestOperationManager manager]; +NSDictionary *parameters = @{@"foo": @"bar"}; +NSURL *filePath = [NSURL fileURLWithPath:@"file://path/to/image.png"]; +[manager POST:@"http://example.com/resources.json" parameters:parameters constructingBodyWithBlock:^(id formData) { + [formData appendPartWithFileURL:filePath name:@"image" error:nil]; +} success:^(AFHTTPRequestOperation *operation, id responseObject) { + NSLog(@"Success: %@", responseObject); +} failure:^(AFHTTPRequestOperation *operation, NSError *error) { + NSLog(@"Error: %@", error); +}]; +``` + +--- + +### AFURLSessionManager + +`AFURLSessionManager` creates and manages an `NSURLSession` object based on a specified `NSURLSessionConfiguration` object, which conforms to ``, ``, ``, and ``. + +#### Creating a Download Task + +```objective-c +NSURLSessionConfiguration *configuration = [NSURLSessionConfiguration defaultSessionConfiguration]; +AFURLSessionManager *manager = [[AFURLSessionManager alloc] initWithSessionConfiguration:configuration]; + +NSURL *URL = [NSURL URLWithString:@"http://example.com/download.zip"]; +NSURLRequest *request = [NSURLRequest requestWithURL:URL]; + +NSURLSessionDownloadTask *downloadTask = [manager downloadTaskWithRequest:request progress:nil destination:^NSURL *(NSURL *targetPath, NSURLResponse *response) { + NSURL *documentsDirectoryURL = [[NSFileManager defaultManager] URLForDirectory:NSDocumentDirectory inDomain:NSUserDomainMask appropriateForURL:nil create:NO error:nil]; + return [documentsDirectoryURL URLByAppendingPathComponent:[response suggestedFilename]]; +} completionHandler:^(NSURLResponse *response, NSURL *filePath, NSError *error) { + NSLog(@"File downloaded to: %@", filePath); +}]; +[downloadTask resume]; +``` + +#### Creating an Upload Task + +```objective-c +NSURLSessionConfiguration *configuration = [NSURLSessionConfiguration defaultSessionConfiguration]; +AFURLSessionManager *manager = [[AFURLSessionManager alloc] initWithSessionConfiguration:configuration]; + +NSURL *URL = [NSURL URLWithString:@"http://example.com/upload"]; +NSURLRequest *request = [NSURLRequest requestWithURL:URL]; + +NSURL *filePath = [NSURL fileURLWithPath:@"file://path/to/image.png"]; +NSURLSessionUploadTask *uploadTask = [manager uploadTaskWithRequest:request fromFile:filePath progress:nil completionHandler:^(NSURLResponse *response, id responseObject, NSError *error) { + if (error) { + NSLog(@"Error: %@", error); + } else { + NSLog(@"Success: %@ %@", response, responseObject); + } +}]; +[uploadTask resume]; +``` + +#### Creating an Upload Task for a Multi-Part Request, with Progress + +```objective-c +NSMutableURLRequest *request = [[AFHTTPRequestSerializer serializer] multipartFormRequestWithMethod:@"POST" URLString:@"http://example.com/upload" parameters:nil constructingBodyWithBlock:^(id formData) { + [formData appendPartWithFileURL:[NSURL fileURLWithPath:@"file://path/to/image.jpg"] name:@"file" fileName:@"filename.jpg" mimeType:@"image/jpeg" error:nil]; + } error:nil]; + +AFURLSessionManager *manager = [[AFURLSessionManager alloc] initWithSessionConfiguration:[NSURLSessionConfiguration defaultSessionConfiguration]]; +NSProgress *progress = nil; + +NSURLSessionUploadTask *uploadTask = [manager uploadTaskWithStreamedRequest:request progress:&progress completionHandler:^(NSURLResponse *response, id responseObject, NSError *error) { + if (error) { + NSLog(@"Error: %@", error); + } else { + NSLog(@"%@ %@", response, responseObject); + } +}]; + +[uploadTask resume]; +``` + +#### Creating a Data Task + +```objective-c +NSURLSessionConfiguration *configuration = [NSURLSessionConfiguration defaultSessionConfiguration]; +AFURLSessionManager *manager = [[AFURLSessionManager alloc] initWithSessionConfiguration:configuration]; + +NSURL *URL = [NSURL URLWithString:@"http://example.com/upload"]; +NSURLRequest *request = [NSURLRequest requestWithURL:URL]; + +NSURLSessionDataTask *dataTask = [manager dataTaskWithRequest:request completionHandler:^(NSURLResponse *response, id responseObject, NSError *error) { + if (error) { + NSLog(@"Error: %@", error); + } else { + NSLog(@"%@ %@", response, responseObject); + } +}]; +[dataTask resume]; +``` + +--- + +### Request Serialization + +Request serializers create requests from URL strings, encoding parameters as either a query string or HTTP body. + +```objective-c +NSString *URLString = @"http://example.com"; +NSDictionary *parameters = @{@"foo": @"bar", @"baz": @[@1, @2, @3]}; +``` + +#### Query String Parameter Encoding + +```objective-c +[[AFHTTPRequestSerializer serializer] requestWithMethod:@"GET" URLString:URLString parameters:parameters error:nil]; +``` + + GET http://example.com?foo=bar&baz[]=1&baz[]=2&baz[]=3 + +#### URL Form Parameter Encoding + +```objective-c +[[AFHTTPRequestSerializer serializer] requestWithMethod:@"POST" URLString:URLString parameters:parameters]; +``` + + POST http://example.com/ + Content-Type: application/x-www-form-urlencoded + + foo=bar&baz[]=1&baz[]=2&baz[]=3 + +#### JSON Parameter Encoding + +```objective-c +[[AFJSONRequestSerializer serializer] requestWithMethod:@"POST" URLString:URLString parameters:parameters]; +``` + + POST http://example.com/ + Content-Type: application/json + + {"foo": "bar", "baz": [1,2,3]} + +--- + +### Network Reachability Manager + +`AFNetworkReachabilityManager` monitors the reachability of domains, and addresses for both WWAN and WiFi network interfaces. + +#### Shared Network Reachability + +```objective-c +[[AFNetworkReachabilityManager sharedManager] setReachabilityStatusChangeBlock:^(AFNetworkReachabilityStatus status) { + NSLog(@"Reachability: %@", AFStringFromNetworkReachabilityStatus(status)); +}]; +``` + +#### HTTP Manager Reachability + +```objective-c +NSURL *baseURL = [NSURL URLWithString:@"http://example.com/"]; +AFHTTPRequestOperationManager *manager = [[AFHTTPRequestOperationManager alloc] initWithBaseURL:baseURL]; + +NSOperationQueue *operationQueue = manager.operationQueue; +[manager.reachabilityManager setReachabilityStatusChangeBlock:^(AFNetworkReachabilityStatus status) { + switch (status) { + case AFNetworkReachabilityStatusReachableViaWWAN: + case AFNetworkReachabilityStatusReachableViaWiFi: + [operationQueue setSuspended:NO]; + break; + case AFNetworkReachabilityStatusNotReachable: + default: + [operationQueue setSuspended:YES]; + break; + } +}]; +``` + +--- + +### Security Policy + +`AFSecurityPolicy` evaluates server trust against pinned X.509 certificates and public keys over secure connections. + +Adding pinned SSL certificates to your app helps prevent man-in-the-middle attacks and other vulnerabilities. Applications dealing with sensitive customer data or financial information are strongly encouraged to route all communication over an HTTPS connection with SSL pinning configured and enabled. + +#### Allowing Invalid SSL Certificates + +```objective-c +AFHTTPRequestOperationManager *manager = [AFHTTPRequestOperationManager manager]; +manager.securityPolicy.allowInvalidCertificates = YES; // not recommended for production +``` + +--- + +### AFHTTPRequestOperation + +`AFHTTPRequestOperation` is a subclass of `AFURLConnectionOperation` for requests using the HTTP or HTTPS protocols. It encapsulates the concept of acceptable status codes and content types, which determine the success or failure of a request. + +Although `AFHTTPRequestOperationManager` is usually the best way to go about making requests, `AFHTTPRequestOperation` can be used by itself. + +#### `GET` with `AFHTTPRequestOperation` + +```objective-c +NSURL *URL = [NSURL URLWithString:@"http://example.com/resources/123.json"]; +NSURLRequest *request = [NSURLRequest requestWithURL:URL]; +AFHTTPRequestOperation *op = [[AFHTTPRequestOperation alloc] initWithRequest:request]; +op.responseSerializer = [AFJSONResponseSerializer serializer]; +[op setCompletionBlockWithSuccess:^(AFHTTPRequestOperation *operation, id responseObject) { + NSLog(@"JSON: %@", responseObject); +} failure:^(AFHTTPRequestOperation *operation, NSError *error) { + NSLog(@"Error: %@", error); +}]; +[[NSOperationQueue mainQueue] addOperation:op]; +``` + +#### Batch of Operations + +```objective-c +NSMutableArray *mutableOperations = [NSMutableArray array]; +for (NSURL *fileURL in filesToUpload) { + NSURLRequest *request = [[AFHTTPRequestSerializer serializer] multipartFormRequestWithMethod:@"POST" URLString:@"http://example.com/upload" parameters:nil constructingBodyWithBlock:^(id formData) { + [formData appendPartWithFileURL:fileURL name:@"images[]" error:nil]; + }]; + + AFHTTPRequestOperation *operation = [[AFHTTPRequestOperation alloc] initWithRequest:request]; + + [mutableOperations addObject:operation]; +} + +NSArray *operations = [AFURLConnectionOperation batchOfRequestOperations:@[...] progressBlock:^(NSUInteger numberOfFinishedOperations, NSUInteger totalNumberOfOperations) { + NSLog(@"%lu of %lu complete", numberOfFinishedOperations, totalNumberOfOperations); +} completionBlock:^(NSArray *operations) { + NSLog(@"All operations in batch complete"); +}]; +[[NSOperationQueue mainQueue] addOperations:operations waitUntilFinished:NO]; +``` + +## Unit Tests + +AFNetworking includes a suite of unit tests within the Tests subdirectory. In order to run the unit tests, you must install the testing dependencies via [CocoaPods](http://cocoapods.org/): + + $ cd Tests + $ pod install + +Once testing dependencies are installed, you can execute the test suite via the 'iOS Tests' and 'OS X Tests' schemes within Xcode. + +### Running Tests from the Command Line + +Tests can also be run from the command line or within a continuous integration environment. The [`xcpretty`](https://github.com/mneorr/xcpretty) utility needs to be installed before running the tests from the command line: + + $ gem install xcpretty + +Once `xcpretty` is installed, you can execute the suite via `rake test`. + +## Credits + +AFNetworking was originally created by [Scott Raymond](https://github.com/sco/) and [Mattt Thompson](https://github.com/mattt/) in the development of [Gowalla for iPhone](http://en.wikipedia.org/wiki/Gowalla). + +AFNetworking's logo was designed by [Alan Defibaugh](http://www.alandefibaugh.com/). + +And most of all, thanks to AFNetworking's [growing list of contributors](https://github.com/AFNetworking/AFNetworking/contributors). + +## Contact + +Follow AFNetworking on Twitter ([@AFNetworking](https://twitter.com/AFNetworking)) + +### Maintainers + +- [Mattt Thompson](http://github.com/mattt) ([@mattt](https://twitter.com/mattt)) + +## License + +AFNetworking is available under the MIT license. See the LICENSE file for more info. diff --git a/ios/Pods/AFNetworking/UIKit+AFNetworking/AFNetworkActivityIndicatorManager.h b/ios/Pods/AFNetworking/UIKit+AFNetworking/AFNetworkActivityIndicatorManager.h new file mode 100644 index 000000000..312d680e0 --- /dev/null +++ b/ios/Pods/AFNetworking/UIKit+AFNetworking/AFNetworkActivityIndicatorManager.h @@ -0,0 +1,76 @@ +// AFNetworkActivityIndicatorManager.h +// +// Copyright (c) 2013-2014 AFNetworking (http://afnetworking.com) +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +#import + +#import + +#if defined(__IPHONE_OS_VERSION_MIN_REQUIRED) + +#import + +/** + `AFNetworkActivityIndicatorManager` manages the state of the network activity indicator in the status bar. When enabled, it will listen for notifications indicating that a network request operation has started or finished, and start or stop animating the indicator accordingly. The number of active requests is incremented and decremented much like a stack or a semaphore, and the activity indicator will animate so long as that number is greater than zero. + + You should enable the shared instance of `AFNetworkActivityIndicatorManager` when your application finishes launching. In `AppDelegate application:didFinishLaunchingWithOptions:` you can do so with the following code: + + [[AFNetworkActivityIndicatorManager sharedManager] setEnabled:YES]; + + By setting `isNetworkActivityIndicatorVisible` to `YES` for `sharedManager`, the network activity indicator will show and hide automatically as requests start and finish. You should not ever need to call `incrementActivityCount` or `decrementActivityCount` yourself. + + See the Apple Human Interface Guidelines section about the Network Activity Indicator for more information: + http://developer.apple.com/library/iOS/#documentation/UserExperience/Conceptual/MobileHIG/UIElementGuidelines/UIElementGuidelines.html#//apple_ref/doc/uid/TP40006556-CH13-SW44 + */ +@interface AFNetworkActivityIndicatorManager : NSObject + +/** + A Boolean value indicating whether the manager is enabled. + + If YES, the manager will change status bar network activity indicator according to network operation notifications it receives. The default value is NO. + */ +@property (nonatomic, assign, getter = isEnabled) BOOL enabled; + +/** + A Boolean value indicating whether the network activity indicator is currently displayed in the status bar. + */ +@property (readonly, nonatomic, assign) BOOL isNetworkActivityIndicatorVisible; + +/** + Returns the shared network activity indicator manager object for the system. + + @return The systemwide network activity indicator manager. + */ ++ (instancetype)sharedManager; + +/** + Increments the number of active network requests. If this number was zero before incrementing, this will start animating the status bar network activity indicator. + */ +- (void)incrementActivityCount; + +/** + Decrements the number of active network requests. If this number becomes zero after decrementing, this will stop animating the status bar network activity indicator. + */ +- (void)decrementActivityCount; + +@end + +#endif diff --git a/ios/Pods/AFNetworking/UIKit+AFNetworking/AFNetworkActivityIndicatorManager.m b/ios/Pods/AFNetworking/UIKit+AFNetworking/AFNetworkActivityIndicatorManager.m new file mode 100644 index 000000000..c2d855a59 --- /dev/null +++ b/ios/Pods/AFNetworking/UIKit+AFNetworking/AFNetworkActivityIndicatorManager.m @@ -0,0 +1,171 @@ +// AFNetworkActivityIndicatorManager.m +// +// Copyright (c) 2013-2014 AFNetworking (http://afnetworking.com) +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +#import "AFNetworkActivityIndicatorManager.h" + +#if defined(__IPHONE_OS_VERSION_MAX_ALLOWED) + +#import "AFHTTPRequestOperation.h" + +#if __IPHONE_OS_VERSION_MAX_ALLOWED >= 70000 +#import "AFURLSessionManager.h" +#endif + +static NSTimeInterval const kAFNetworkActivityIndicatorInvisibilityDelay = 0.17; + +static NSURLRequest * AFNetworkRequestFromNotification(NSNotification *notification) { + if ([[notification object] isKindOfClass:[AFURLConnectionOperation class]]) { + return [(AFURLConnectionOperation *)[notification object] request]; + } + +#if __IPHONE_OS_VERSION_MAX_ALLOWED >= 70000 + if ([[notification object] respondsToSelector:@selector(originalRequest)]) { + return [(NSURLSessionTask *)[notification object] originalRequest]; + } +#endif + + return nil; +} + +@interface AFNetworkActivityIndicatorManager () +@property (readwrite, nonatomic, assign) NSInteger activityCount; +@property (readwrite, nonatomic, strong) NSTimer *activityIndicatorVisibilityTimer; +@property (readonly, nonatomic, getter = isNetworkActivityIndicatorVisible) BOOL networkActivityIndicatorVisible; + +- (void)updateNetworkActivityIndicatorVisibility; +- (void)updateNetworkActivityIndicatorVisibilityDelayed; +@end + +@implementation AFNetworkActivityIndicatorManager +@dynamic networkActivityIndicatorVisible; + ++ (instancetype)sharedManager { + static AFNetworkActivityIndicatorManager *_sharedManager = nil; + static dispatch_once_t oncePredicate; + dispatch_once(&oncePredicate, ^{ + _sharedManager = [[self alloc] init]; + }); + + return _sharedManager; +} + ++ (NSSet *)keyPathsForValuesAffectingIsNetworkActivityIndicatorVisible { + return [NSSet setWithObject:@"activityCount"]; +} + +- (id)init { + self = [super init]; + if (!self) { + return nil; + } + + [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(networkRequestDidStart:) name:AFNetworkingOperationDidStartNotification object:nil]; + [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(networkRequestDidFinish:) name:AFNetworkingOperationDidFinishNotification object:nil]; + +#if __IPHONE_OS_VERSION_MAX_ALLOWED >= 70000 + [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(networkRequestDidStart:) name:AFNetworkingTaskDidResumeNotification object:nil]; + [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(networkRequestDidFinish:) name:AFNetworkingTaskDidSuspendNotification object:nil]; + [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(networkRequestDidFinish:) name:AFNetworkingTaskDidCompleteNotification object:nil]; +#endif + + return self; +} + +- (void)dealloc { + [[NSNotificationCenter defaultCenter] removeObserver:self]; + + [_activityIndicatorVisibilityTimer invalidate]; +} + +- (void)updateNetworkActivityIndicatorVisibilityDelayed { + if (self.enabled) { + // Delay hiding of activity indicator for a short interval, to avoid flickering + if (![self isNetworkActivityIndicatorVisible]) { + [self.activityIndicatorVisibilityTimer invalidate]; + self.activityIndicatorVisibilityTimer = [NSTimer timerWithTimeInterval:kAFNetworkActivityIndicatorInvisibilityDelay target:self selector:@selector(updateNetworkActivityIndicatorVisibility) userInfo:nil repeats:NO]; + [[NSRunLoop mainRunLoop] addTimer:self.activityIndicatorVisibilityTimer forMode:NSRunLoopCommonModes]; + } else { + [self performSelectorOnMainThread:@selector(updateNetworkActivityIndicatorVisibility) withObject:nil waitUntilDone:NO modes:@[NSRunLoopCommonModes]]; + } + } +} + +- (BOOL)isNetworkActivityIndicatorVisible { + return self.activityCount > 0; +} + +- (void)updateNetworkActivityIndicatorVisibility { + [[UIApplication sharedApplication] setNetworkActivityIndicatorVisible:[self isNetworkActivityIndicatorVisible]]; +} + +- (void)setActivityCount:(NSInteger)activityCount { + @synchronized(self) { + _activityCount = activityCount; + } + + dispatch_async(dispatch_get_main_queue(), ^{ + [self updateNetworkActivityIndicatorVisibilityDelayed]; + }); +} + +- (void)incrementActivityCount { + [self willChangeValueForKey:@"activityCount"]; + @synchronized(self) { + _activityCount++; + } + [self didChangeValueForKey:@"activityCount"]; + + dispatch_async(dispatch_get_main_queue(), ^{ + [self updateNetworkActivityIndicatorVisibilityDelayed]; + }); +} + +- (void)decrementActivityCount { + [self willChangeValueForKey:@"activityCount"]; + @synchronized(self) { +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wgnu" + _activityCount = MAX(_activityCount - 1, 0); +#pragma clang diagnostic pop + } + [self didChangeValueForKey:@"activityCount"]; + + dispatch_async(dispatch_get_main_queue(), ^{ + [self updateNetworkActivityIndicatorVisibilityDelayed]; + }); +} + +- (void)networkRequestDidStart:(NSNotification *)notification { + if ([AFNetworkRequestFromNotification(notification) URL]) { + [self incrementActivityCount]; + } +} + +- (void)networkRequestDidFinish:(NSNotification *)notification { + if ([AFNetworkRequestFromNotification(notification) URL]) { + [self decrementActivityCount]; + } +} + +@end + +#endif diff --git a/ios/Pods/AFNetworking/UIKit+AFNetworking/UIActivityIndicatorView+AFNetworking.h b/ios/Pods/AFNetworking/UIKit+AFNetworking/UIActivityIndicatorView+AFNetworking.h new file mode 100644 index 000000000..1c1f8dd6f --- /dev/null +++ b/ios/Pods/AFNetworking/UIKit+AFNetworking/UIActivityIndicatorView+AFNetworking.h @@ -0,0 +1,64 @@ +// UIActivityIndicatorView+AFNetworking.h +// +// Copyright (c) 2013-2014 AFNetworking (http://afnetworking.com) +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +#import + +#import + +#if defined(__IPHONE_OS_VERSION_MIN_REQUIRED) + +#import + +@class AFURLConnectionOperation; + +/** + This category adds methods to the UIKit framework's `UIActivityIndicatorView` class. The methods in this category provide support for automatically starting and stopping animation depending on the loading state of a request operation or session task. + */ +@interface UIActivityIndicatorView (AFNetworking) + +///---------------------------------- +/// @name Animating for Session Tasks +///---------------------------------- + +/** + Binds the animating state to the state of the specified task. + + @param task The task. If `nil`, automatic updating from any previously specified operation will be disabled. + */ +#if __IPHONE_OS_VERSION_MIN_REQUIRED >= 70000 +- (void)setAnimatingWithStateOfTask:(NSURLSessionTask *)task; +#endif + +///--------------------------------------- +/// @name Animating for Request Operations +///--------------------------------------- + +/** + Binds the animating state to the execution state of the specified operation. + + @param operation The operation. If `nil`, automatic updating from any previously specified operation will be disabled. + */ +- (void)setAnimatingWithStateOfOperation:(AFURLConnectionOperation *)operation; + +@end + +#endif diff --git a/ios/Pods/AFNetworking/UIKit+AFNetworking/UIActivityIndicatorView+AFNetworking.m b/ios/Pods/AFNetworking/UIKit+AFNetworking/UIActivityIndicatorView+AFNetworking.m new file mode 100644 index 000000000..6627dbb1b --- /dev/null +++ b/ios/Pods/AFNetworking/UIKit+AFNetworking/UIActivityIndicatorView+AFNetworking.m @@ -0,0 +1,97 @@ +// UIActivityIndicatorView+AFNetworking.m +// +// Copyright (c) 2013-2014 AFNetworking (http://afnetworking.com) +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +#import "UIActivityIndicatorView+AFNetworking.h" + +#if defined(__IPHONE_OS_VERSION_MIN_REQUIRED) + +#import "AFHTTPRequestOperation.h" + +#if __IPHONE_OS_VERSION_MIN_REQUIRED >= 70000 +#import "AFURLSessionManager.h" +#endif + +@implementation UIActivityIndicatorView (AFNetworking) + +#if __IPHONE_OS_VERSION_MIN_REQUIRED >= 70000 +- (void)setAnimatingWithStateOfTask:(NSURLSessionTask *)task { + NSNotificationCenter *notificationCenter = [NSNotificationCenter defaultCenter]; + + [notificationCenter removeObserver:self name:AFNetworkingTaskDidResumeNotification object:nil]; + [notificationCenter removeObserver:self name:AFNetworkingTaskDidSuspendNotification object:nil]; + [notificationCenter removeObserver:self name:AFNetworkingTaskDidCompleteNotification object:nil]; + + if (task) { + if (task.state != NSURLSessionTaskStateCompleted) { + if (task.state == NSURLSessionTaskStateRunning) { + [self startAnimating]; + } else { + [self stopAnimating]; + } + + [notificationCenter addObserver:self selector:@selector(af_startAnimating) name:AFNetworkingTaskDidResumeNotification object:task]; + [notificationCenter addObserver:self selector:@selector(af_stopAnimating) name:AFNetworkingTaskDidCompleteNotification object:task]; + [notificationCenter addObserver:self selector:@selector(af_stopAnimating) name:AFNetworkingTaskDidSuspendNotification object:task]; + } + } +} +#endif + +#pragma mark - + +- (void)setAnimatingWithStateOfOperation:(AFURLConnectionOperation *)operation { + NSNotificationCenter *notificationCenter = [NSNotificationCenter defaultCenter]; + + [notificationCenter removeObserver:self name:AFNetworkingOperationDidStartNotification object:nil]; + [notificationCenter removeObserver:self name:AFNetworkingOperationDidFinishNotification object:nil]; + + if (operation) { + if (![operation isFinished]) { + if ([operation isExecuting]) { + [self startAnimating]; + } else { + [self stopAnimating]; + } + + [notificationCenter addObserver:self selector:@selector(af_startAnimating) name:AFNetworkingOperationDidStartNotification object:operation]; + [notificationCenter addObserver:self selector:@selector(af_stopAnimating) name:AFNetworkingOperationDidFinishNotification object:operation]; + } + } +} + +#pragma mark - + +- (void)af_startAnimating { + dispatch_async(dispatch_get_main_queue(), ^{ + [self startAnimating]; + }); +} + +- (void)af_stopAnimating { + dispatch_async(dispatch_get_main_queue(), ^{ + [self stopAnimating]; + }); +} + +@end + +#endif diff --git a/ios/Pods/AFNetworking/UIKit+AFNetworking/UIAlertView+AFNetworking.h b/ios/Pods/AFNetworking/UIKit+AFNetworking/UIAlertView+AFNetworking.h new file mode 100644 index 000000000..b94f1cb8e --- /dev/null +++ b/ios/Pods/AFNetworking/UIKit+AFNetworking/UIAlertView+AFNetworking.h @@ -0,0 +1,96 @@ +// UIAlertView+AFNetworking.h +// +// Copyright (c) 2013-2014 AFNetworking (http://afnetworking.com) +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +#import + +#import + +#if defined(__IPHONE_OS_VERSION_MIN_REQUIRED) + +#import + +@class AFURLConnectionOperation; + +/** + This category adds methods to the UIKit framework's `UIAlertView` class. The methods in this category provide support for automatically showing an alert if a session task or request operation finishes with an error. Alert title and message are filled from the corresponding `localizedDescription` & `localizedRecoverySuggestion` or `localizedFailureReason` of the error. + */ +@interface UIAlertView (AFNetworking) + +///------------------------------------- +/// @name Showing Alert for Session Task +///------------------------------------- + +/** + Shows an alert view with the error of the specified session task, if any. + + @param task The session task. + @param delegate The alert view delegate. + */ +#if __IPHONE_OS_VERSION_MIN_REQUIRED >= 70000 ++ (void)showAlertViewForTaskWithErrorOnCompletion:(NSURLSessionTask *)task + delegate:(id)delegate; +#endif + +/** + Shows an alert view with the error of the specified session task, if any, with a custom cancel button title and other button titles. + + @param task The session task. + @param delegate The alert view delegate. + @param cancelButtonTitle The title of the cancel button or nil if there is no cancel button. Using this argument is equivalent to setting the cancel button index to the value returned by invoking addButtonWithTitle: specifying this title. + @param otherButtonTitles The title of another button. Using this argument is equivalent to invoking addButtonWithTitle: with this title to add more buttons. Too many buttons can cause the alert view to scroll. For guidelines on the best ways to use an alert in an app, see "Temporary Views". Titles of additional buttons to add to the receiver, terminated with `nil`. + */ +#if __IPHONE_OS_VERSION_MIN_REQUIRED >= 70000 ++ (void)showAlertViewForTaskWithErrorOnCompletion:(NSURLSessionTask *)task + delegate:(id)delegate + cancelButtonTitle:(NSString *)cancelButtonTitle + otherButtonTitles:(NSString *)otherButtonTitles, ... NS_REQUIRES_NIL_TERMINATION; +#endif + +///------------------------------------------ +/// @name Showing Alert for Request Operation +///------------------------------------------ + +/** + Shows an alert view with the error of the specified request operation, if any. + + @param operation The request operation. + @param delegate The alert view delegate. + */ ++ (void)showAlertViewForRequestOperationWithErrorOnCompletion:(AFURLConnectionOperation *)operation + delegate:(id)delegate; + +/** + Shows an alert view with the error of the specified request operation, if any, with a custom cancel button title and other button titles. + + @param operation The request operation. + @param delegate The alert view delegate. + @param cancelButtonTitle The title of the cancel button or nil if there is no cancel button. Using this argument is equivalent to setting the cancel button index to the value returned by invoking addButtonWithTitle: specifying this title. + @param otherButtonTitles The title of another button. Using this argument is equivalent to invoking addButtonWithTitle: with this title to add more buttons. Too many buttons can cause the alert view to scroll. For guidelines on the best ways to use an alert in an app, see "Temporary Views". Titles of additional buttons to add to the receiver, terminated with `nil`. + */ ++ (void)showAlertViewForRequestOperationWithErrorOnCompletion:(AFURLConnectionOperation *)operation + delegate:(id)delegate + cancelButtonTitle:(NSString *)cancelButtonTitle + otherButtonTitles:(NSString *)otherButtonTitles, ... NS_REQUIRES_NIL_TERMINATION; + +@end + +#endif diff --git a/ios/Pods/AFNetworking/UIKit+AFNetworking/UIAlertView+AFNetworking.m b/ios/Pods/AFNetworking/UIKit+AFNetworking/UIAlertView+AFNetworking.m new file mode 100644 index 000000000..b7e2a26cb --- /dev/null +++ b/ios/Pods/AFNetworking/UIKit+AFNetworking/UIAlertView+AFNetworking.m @@ -0,0 +1,111 @@ +// UIAlertView+AFNetworking.m +// +// Copyright (c) 2013-2014 AFNetworking (http://afnetworking.com) +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +#import "UIAlertView+AFNetworking.h" + +#if defined(__IPHONE_OS_VERSION_MIN_REQUIRED) + +#import "AFURLConnectionOperation.h" + +#if __IPHONE_OS_VERSION_MIN_REQUIRED >= 70000 +#import "AFURLSessionManager.h" +#endif + +static void AFGetAlertViewTitleAndMessageFromError(NSError *error, NSString * __autoreleasing *title, NSString * __autoreleasing *message) { + if (error.localizedDescription && (error.localizedRecoverySuggestion || error.localizedFailureReason)) { + *title = error.localizedDescription; + + if (error.localizedRecoverySuggestion) { + *message = error.localizedRecoverySuggestion; + } else { + *message = error.localizedFailureReason; + } + } else if (error.localizedDescription) { + *title = NSLocalizedStringFromTable(@"Error", @"AFNetworking", @"Fallback Error Description"); + *message = error.localizedDescription; + } else { + *title = NSLocalizedStringFromTable(@"Error", @"AFNetworking", @"Fallback Error Description"); + *message = [NSString stringWithFormat:NSLocalizedStringFromTable(@"%@ Error: %ld", @"AFNetworking", @"Fallback Error Failure Reason Format"), error.domain, (long)error.code]; + } +} + +@implementation UIAlertView (AFNetworking) + +#if __IPHONE_OS_VERSION_MIN_REQUIRED >= 70000 ++ (void)showAlertViewForTaskWithErrorOnCompletion:(NSURLSessionTask *)task + delegate:(id)delegate +{ + [self showAlertViewForTaskWithErrorOnCompletion:task delegate:delegate cancelButtonTitle:NSLocalizedStringFromTable(@"Dismiss", @"AFNetworking", @"UIAlertView Cancel Button Title") otherButtonTitles:nil, nil]; +} + ++ (void)showAlertViewForTaskWithErrorOnCompletion:(NSURLSessionTask *)task + delegate:(id)delegate + cancelButtonTitle:(NSString *)cancelButtonTitle + otherButtonTitles:(NSString *)otherButtonTitles, ... NS_REQUIRES_NIL_TERMINATION +{ + __block id observer = [[NSNotificationCenter defaultCenter] addObserverForName:AFNetworkingTaskDidCompleteNotification object:task queue:[NSOperationQueue mainQueue] usingBlock:^(NSNotification *notification) { + + NSError *error = notification.userInfo[AFNetworkingTaskDidCompleteErrorKey]; + if (error) { + NSString *title, *message; + AFGetAlertViewTitleAndMessageFromError(error, &title, &message); + + [[[UIAlertView alloc] initWithTitle:title message:message delegate:delegate cancelButtonTitle:cancelButtonTitle otherButtonTitles:otherButtonTitles, nil] show]; + } + + [[NSNotificationCenter defaultCenter] removeObserver:observer name:AFNetworkingTaskDidCompleteNotification object:notification.object]; + }]; +} +#endif + +#pragma mark - + ++ (void)showAlertViewForRequestOperationWithErrorOnCompletion:(AFURLConnectionOperation *)operation + delegate:(id)delegate +{ + [self showAlertViewForRequestOperationWithErrorOnCompletion:operation delegate:delegate cancelButtonTitle:NSLocalizedStringFromTable(@"Dismiss", @"AFNetworking", @"UIAlert View Cancel Button Title") otherButtonTitles:nil, nil]; +} + ++ (void)showAlertViewForRequestOperationWithErrorOnCompletion:(AFURLConnectionOperation *)operation + delegate:(id)delegate + cancelButtonTitle:(NSString *)cancelButtonTitle + otherButtonTitles:(NSString *)otherButtonTitles, ... NS_REQUIRES_NIL_TERMINATION +{ + __block id observer = [[NSNotificationCenter defaultCenter] addObserverForName:AFNetworkingOperationDidFinishNotification object:operation queue:[NSOperationQueue mainQueue] usingBlock:^(NSNotification *notification) { + + if (notification.object && [notification.object isKindOfClass:[AFURLConnectionOperation class]]) { + NSError *error = [(AFURLConnectionOperation *)notification.object error]; + if (error) { + NSString *title, *message; + AFGetAlertViewTitleAndMessageFromError(error, &title, &message); + + [[[UIAlertView alloc] initWithTitle:title message:message delegate:delegate cancelButtonTitle:cancelButtonTitle otherButtonTitles:otherButtonTitles, nil] show]; + } + } + + [[NSNotificationCenter defaultCenter] removeObserver:observer name:AFNetworkingOperationDidFinishNotification object:notification.object]; + }]; +} + +@end + +#endif diff --git a/ios/Pods/AFNetworking/UIKit+AFNetworking/UIButton+AFNetworking.h b/ios/Pods/AFNetworking/UIKit+AFNetworking/UIButton+AFNetworking.h new file mode 100644 index 000000000..fd89ecde8 --- /dev/null +++ b/ios/Pods/AFNetworking/UIKit+AFNetworking/UIButton+AFNetworking.h @@ -0,0 +1,146 @@ +// UIButton+AFNetworking.h +// +// Copyright (c) 2013-2014 AFNetworking (http://afnetworking.com) +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +#import + +#import + +#if defined(__IPHONE_OS_VERSION_MIN_REQUIRED) + +#import + +/** + This category adds methods to the UIKit framework's `UIButton` class. The methods in this category provide support for loading remote images and background images asynchronously from a URL. + */ +@interface UIButton (AFNetworking) + +///-------------------- +/// @name Setting Image +///-------------------- + +/** + Asynchronously downloads an image from the specified URL, and sets it as the image for the specified state once the request is finished. Any previous image request for the receiver will be cancelled. + + If the image is cached locally, the image is set immediately, otherwise the specified placeholder image will be set immediately, and then the remote image will be set once the request is finished. + + @param state The control state. + @param url The URL used for the image request. + */ +- (void)setImageForState:(UIControlState)state + withURL:(NSURL *)url; + +/** + Asynchronously downloads an image from the specified URL, and sets it as the image for the specified state once the request is finished. Any previous image request for the receiver will be cancelled. + + If the image is cached locally, the image is set immediately, otherwise the specified placeholder image will be set immediately, and then the remote image will be set once the request is finished. + + @param state The control state. + @param url The URL used for the image request. + @param placeholderImage The image to be set initially, until the image request finishes. If `nil`, the button will not change its image until the image request finishes. + */ +- (void)setImageForState:(UIControlState)state + withURL:(NSURL *)url + placeholderImage:(UIImage *)placeholderImage; + +/** + Asynchronously downloads an image from the specified URL request, and sets it as the image for the specified state once the request is finished. Any previous image request for the receiver will be cancelled. + + If the image is cached locally, the image is set immediately, otherwise the specified placeholder image will be set immediately, and then the remote image will be set once the request is finished. + + If a success block is specified, it is the responsibility of the block to set the image of the button before returning. If no success block is specified, the default behavior of setting the image with `setImage:forState:` is applied. + + @param state The control state. + @param urlRequest The URL request used for the image request. + @param placeholderImage The image to be set initially, until the image request finishes. If `nil`, the button will not change its image until the image request finishes. + @param success A block to be executed when the image request operation finishes successfully. This block has no return value and takes two arguments: the server response and the image. If the image was returned from cache, the request and response parameters will be `nil`. + @param failure A block object to be executed when the image request operation finishes unsuccessfully, or that finishes successfully. This block has no return value and takes a single argument: the error that occurred. + */ +- (void)setImageForState:(UIControlState)state + withURLRequest:(NSURLRequest *)urlRequest + placeholderImage:(UIImage *)placeholderImage + success:(void (^)(NSHTTPURLResponse *response, UIImage *image))success + failure:(void (^)(NSError *error))failure; + + +///------------------------------- +/// @name Setting Background Image +///------------------------------- + +/** + Asynchronously downloads an image from the specified URL, and sets it as the background image for the specified state once the request is finished. Any previous background image request for the receiver will be cancelled. + + If the background image is cached locally, the background image is set immediately, otherwise the specified placeholder background image will be set immediately, and then the remote background image will be set once the request is finished. + + @param state The control state. + @param url The URL used for the background image request. + */ +- (void)setBackgroundImageForState:(UIControlState)state + withURL:(NSURL *)url; + +/** + Asynchronously downloads an image from the specified URL, and sets it as the background image for the specified state once the request is finished. Any previous image request for the receiver will be cancelled. + + If the image is cached locally, the image is set immediately, otherwise the specified placeholder image will be set immediately, and then the remote image will be set once the request is finished. + + @param state The control state. + @param url The URL used for the background image request. + @param placeholderImage The background image to be set initially, until the background image request finishes. If `nil`, the button will not change its background image until the background image request finishes. + */ +- (void)setBackgroundImageForState:(UIControlState)state + withURL:(NSURL *)url + placeholderImage:(UIImage *)placeholderImage; + +/** + Asynchronously downloads an image from the specified URL request, and sets it as the image for the specified state once the request is finished. Any previous image request for the receiver will be cancelled. + + If the image is cached locally, the image is set immediately, otherwise the specified placeholder image will be set immediately, and then the remote image will be set once the request is finished. + + If a success block is specified, it is the responsibility of the block to set the image of the button before returning. If no success block is specified, the default behavior of setting the image with `setBackgroundImage:forState:` is applied. + + @param state The control state. + @param urlRequest The URL request used for the image request. + @param placeholderImage The background image to be set initially, until the background image request finishes. If `nil`, the button will not change its background image until the background image request finishes. + */ +- (void)setBackgroundImageForState:(UIControlState)state + withURLRequest:(NSURLRequest *)urlRequest + placeholderImage:(UIImage *)placeholderImage + success:(void (^)(NSHTTPURLResponse *response, UIImage *image))success + failure:(void (^)(NSError *error))failure; + + +///------------------------------ +/// @name Canceling Image Loading +///------------------------------ + +/** + Cancels any executing image operation for the receiver, if one exists. + */ +- (void)cancelImageRequestOperation; + +/** + Cancels any executing background image operation for the receiver, if one exists. + */ +- (void)cancelBackgroundImageRequestOperation; + +@end + +#endif diff --git a/ios/Pods/AFNetworking/UIKit+AFNetworking/UIButton+AFNetworking.m b/ios/Pods/AFNetworking/UIKit+AFNetworking/UIButton+AFNetworking.m new file mode 100644 index 000000000..689ae9ac5 --- /dev/null +++ b/ios/Pods/AFNetworking/UIKit+AFNetworking/UIButton+AFNetworking.m @@ -0,0 +1,185 @@ +// UIButton+AFNetworking.m +// +// Copyright (c) 2013-2014 AFNetworking (http://afnetworking.com) +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +#import "UIButton+AFNetworking.h" + +#import + +#if defined(__IPHONE_OS_VERSION_MIN_REQUIRED) + +#import "AFHTTPRequestOperation.h" + +@interface UIButton (_AFNetworking) +@property (readwrite, nonatomic, strong, setter = af_setImageRequestOperation:) AFHTTPRequestOperation *af_imageRequestOperation; +@property (readwrite, nonatomic, strong, setter = af_setBackgroundImageRequestOperation:) AFHTTPRequestOperation *af_backgroundImageRequestOperation; +@end + +@implementation UIButton (_AFNetworking) + ++ (NSOperationQueue *)af_sharedImageRequestOperationQueue { + static NSOperationQueue *_af_sharedImageRequestOperationQueue = nil; + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^{ + _af_sharedImageRequestOperationQueue = [[NSOperationQueue alloc] init]; + _af_sharedImageRequestOperationQueue.maxConcurrentOperationCount = NSOperationQueueDefaultMaxConcurrentOperationCount; + }); + + return _af_sharedImageRequestOperationQueue; +} + +- (AFHTTPRequestOperation *)af_imageRequestOperation { + return (AFHTTPRequestOperation *)objc_getAssociatedObject(self, @selector(af_imageRequestOperation)); +} + +- (void)af_setImageRequestOperation:(AFHTTPRequestOperation *)imageRequestOperation { + objc_setAssociatedObject(self, @selector(af_imageRequestOperation), imageRequestOperation, OBJC_ASSOCIATION_RETAIN_NONATOMIC); +} + +- (AFHTTPRequestOperation *)af_backgroundImageRequestOperation { + return (AFHTTPRequestOperation *)objc_getAssociatedObject(self, @selector(af_backgroundImageRequestOperation)); +} + +- (void)af_setBackgroundImageRequestOperation:(AFHTTPRequestOperation *)imageRequestOperation { + objc_setAssociatedObject(self, @selector(af_backgroundImageRequestOperation), imageRequestOperation, OBJC_ASSOCIATION_RETAIN_NONATOMIC); +} + +@end + +#pragma mark - + +@implementation UIButton (AFNetworking) + +- (void)setImageForState:(UIControlState)state + withURL:(NSURL *)url +{ + [self setImageForState:state withURL:url placeholderImage:nil]; +} + +- (void)setImageForState:(UIControlState)state + withURL:(NSURL *)url + placeholderImage:(UIImage *)placeholderImage +{ + NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url]; + [request addValue:@"image/*" forHTTPHeaderField:@"Accept"]; + + [self setImageForState:state withURLRequest:request placeholderImage:placeholderImage success:nil failure:nil]; +} + +- (void)setImageForState:(UIControlState)state + withURLRequest:(NSURLRequest *)urlRequest + placeholderImage:(UIImage *)placeholderImage + success:(void (^)(NSHTTPURLResponse *response, UIImage *image))success + failure:(void (^)(NSError *error))failure +{ + [self cancelImageRequestOperation]; + + [self setImage:placeholderImage forState:state]; + + __weak __typeof(self)weakSelf = self; + self.af_imageRequestOperation = [[AFHTTPRequestOperation alloc] initWithRequest:urlRequest]; + self.af_imageRequestOperation.responseSerializer = [AFImageResponseSerializer serializer]; + [self.af_imageRequestOperation setCompletionBlockWithSuccess:^(AFHTTPRequestOperation *operation, id responseObject) { + __strong __typeof(weakSelf)strongSelf = weakSelf; + if ([[urlRequest URL] isEqual:[operation.request URL]]) { + if (success) { + success(operation.response, responseObject); + } else if (responseObject) { + [strongSelf setImage:responseObject forState:state]; + } + } + } failure:^(AFHTTPRequestOperation *operation, NSError *error) { + if ([[urlRequest URL] isEqual:[operation.response URL]]) { + if (failure) { + failure(error); + } + } + }]; + + [[[self class] af_sharedImageRequestOperationQueue] addOperation:self.af_imageRequestOperation]; +} + +#pragma mark - + +- (void)setBackgroundImageForState:(UIControlState)state + withURL:(NSURL *)url +{ + [self setBackgroundImageForState:state withURL:url placeholderImage:nil]; +} + +- (void)setBackgroundImageForState:(UIControlState)state + withURL:(NSURL *)url + placeholderImage:(UIImage *)placeholderImage +{ + NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url]; + [request addValue:@"image/*" forHTTPHeaderField:@"Accept"]; + + [self setBackgroundImageForState:state withURLRequest:request placeholderImage:placeholderImage success:nil failure:nil]; +} + +- (void)setBackgroundImageForState:(UIControlState)state + withURLRequest:(NSURLRequest *)urlRequest + placeholderImage:(UIImage *)placeholderImage + success:(void (^)(NSHTTPURLResponse *response, UIImage *image))success + failure:(void (^)(NSError *error))failure +{ + [self cancelBackgroundImageRequestOperation]; + + [self setBackgroundImage:placeholderImage forState:state]; + + __weak __typeof(self)weakSelf = self; + self.af_backgroundImageRequestOperation = [[AFHTTPRequestOperation alloc] initWithRequest:urlRequest]; + self.af_backgroundImageRequestOperation.responseSerializer = [AFImageResponseSerializer serializer]; + [self.af_backgroundImageRequestOperation setCompletionBlockWithSuccess:^(AFHTTPRequestOperation *operation, id responseObject) { + __strong __typeof(weakSelf)strongSelf = weakSelf; + if ([[urlRequest URL] isEqual:[operation.request URL]]) { + if (success) { + success(operation.response, responseObject); + } else if (responseObject) { + [strongSelf setBackgroundImage:responseObject forState:state]; + } + } + } failure:^(AFHTTPRequestOperation *operation, NSError *error) { + if ([[urlRequest URL] isEqual:[operation.response URL]]) { + if (failure) { + failure(error); + } + } + }]; + + [[[self class] af_sharedImageRequestOperationQueue] addOperation:self.af_backgroundImageRequestOperation]; +} + +#pragma mark - + +- (void)cancelImageRequestOperation { + [self.af_imageRequestOperation cancel]; + self.af_imageRequestOperation = nil; +} + +- (void)cancelBackgroundImageRequestOperation { + [self.af_backgroundImageRequestOperation cancel]; + self.af_backgroundImageRequestOperation = nil; +} + +@end + +#endif diff --git a/ios/Pods/AFNetworking/UIKit+AFNetworking/UIImageView+AFNetworking.h b/ios/Pods/AFNetworking/UIKit+AFNetworking/UIImageView+AFNetworking.h new file mode 100644 index 000000000..a983d9829 --- /dev/null +++ b/ios/Pods/AFNetworking/UIKit+AFNetworking/UIImageView+AFNetworking.h @@ -0,0 +1,143 @@ +// UIImageView+AFNetworking.h +// +// Copyright (c) 2013-2014 AFNetworking (http://afnetworking.com) +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +#import + +#import + +#if defined(__IPHONE_OS_VERSION_MIN_REQUIRED) + +#import + +@protocol AFURLResponseSerialization, AFImageCache; + +/** + This category adds methods to the UIKit framework's `UIImageView` class. The methods in this category provide support for loading remote images asynchronously from a URL. + */ +@interface UIImageView (AFNetworking) + +///---------------------------- +/// @name Accessing Image Cache +///---------------------------- + +/** + The image cache used to improve image loadiing performance on scroll views. By default, this is an `NSCache` subclass conforming to the `AFImageCache` protocol, which listens for notification warnings and evicts objects accordingly. +*/ ++ (id )sharedImageCache; + +/** + Set the cache used for image loading. + + @param imageCache The image cache. + */ ++ (void)setSharedImageCache:(id )imageCache; + +///------------------------------------ +/// @name Accessing Response Serializer +///------------------------------------ + +/** + The response serializer used to create an image representation from the server response and response data. By default, this is an instance of `AFImageResponseSerializer`. + + @discussion Subclasses of `AFImageResponseSerializer` could be used to perform post-processing, such as color correction, face detection, or other effects. See https://github.com/AFNetworking/AFCoreImageSerializer + */ +@property (nonatomic, strong) id imageResponseSerializer; + +///-------------------- +/// @name Setting Image +///-------------------- + +/** + Asynchronously downloads an image from the specified URL, and sets it once the request is finished. Any previous image request for the receiver will be cancelled. + + If the image is cached locally, the image is set immediately, otherwise the specified placeholder image will be set immediately, and then the remote image will be set once the request is finished. + + By default, URL requests have a `Accept` header field value of "image / *", a cache policy of `NSURLCacheStorageAllowed` and a timeout interval of 30 seconds, and are set not handle cookies. To configure URL requests differently, use `setImageWithURLRequest:placeholderImage:success:failure:` + + @param url The URL used for the image request. + */ +- (void)setImageWithURL:(NSURL *)url; + +/** + Asynchronously downloads an image from the specified URL, and sets it once the request is finished. Any previous image request for the receiver will be cancelled. + + If the image is cached locally, the image is set immediately, otherwise the specified placeholder image will be set immediately, and then the remote image will be set once the request is finished. + + By default, URL requests have a `Accept` header field value of "image / *", a cache policy of `NSURLCacheStorageAllowed` and a timeout interval of 30 seconds, and are set not handle cookies. To configure URL requests differently, use `setImageWithURLRequest:placeholderImage:success:failure:` + + @param url The URL used for the image request. + @param placeholderImage The image to be set initially, until the image request finishes. If `nil`, the image view will not change its image until the image request finishes. + */ +- (void)setImageWithURL:(NSURL *)url + placeholderImage:(UIImage *)placeholderImage; + +/** + Asynchronously downloads an image from the specified URL request, and sets it once the request is finished. Any previous image request for the receiver will be cancelled. + + If the image is cached locally, the image is set immediately, otherwise the specified placeholder image will be set immediately, and then the remote image will be set once the request is finished. + + If a success block is specified, it is the responsibility of the block to set the image of the image view before returning. If no success block is specified, the default behavior of setting the image with `self.image = image` is applied. + + @param urlRequest The URL request used for the image request. + @param placeholderImage The image to be set initially, until the image request finishes. If `nil`, the image view will not change its image until the image request finishes. + @param success A block to be executed when the image request operation finishes successfully. This block has no return value and takes three arguments: the request sent from the client, the response received from the server, and the image created from the response data of request. If the image was returned from cache, the request and response parameters will be `nil`. + @param failure A block object to be executed when the image request operation finishes unsuccessfully, or that finishes successfully. This block has no return value and takes three arguments: the request sent from the client, the response received from the server, and the error object describing the network or parsing error that occurred. + */ +- (void)setImageWithURLRequest:(NSURLRequest *)urlRequest + placeholderImage:(UIImage *)placeholderImage + success:(void (^)(NSURLRequest *request, NSHTTPURLResponse *response, UIImage *image))success + failure:(void (^)(NSURLRequest *request, NSHTTPURLResponse *response, NSError *error))failure; + +/** + Cancels any executing image operation for the receiver, if one exists. + */ +- (void)cancelImageRequestOperation; + +@end + +#pragma mark - + +/** + The `AFImageCache` protocol is adopted by an object used to cache images loaded by the AFNetworking category on `UIImageView`. + */ +@protocol AFImageCache + +/** + Returns a cached image for the specififed request, if available. + + @param request The image request. + + @return The cached image. + */ +- (UIImage *)cachedImageForRequest:(NSURLRequest *)request; + +/** + Caches a particular image for the specified request. + + @param image The image to cache. + @param request The request to be used as a cache key. + */ +- (void)cacheImage:(UIImage *)image + forRequest:(NSURLRequest *)request; +@end + +#endif diff --git a/ios/Pods/AFNetworking/UIKit+AFNetworking/UIImageView+AFNetworking.m b/ios/Pods/AFNetworking/UIKit+AFNetworking/UIImageView+AFNetworking.m new file mode 100644 index 000000000..64c094323 --- /dev/null +++ b/ios/Pods/AFNetworking/UIKit+AFNetworking/UIImageView+AFNetworking.m @@ -0,0 +1,214 @@ +// UIImageView+AFNetworking.m +// +// Copyright (c) 2013-2014 AFNetworking (http://afnetworking.com) +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +#import "UIImageView+AFNetworking.h" + +#import + +#if defined(__IPHONE_OS_VERSION_MIN_REQUIRED) + +#import "AFHTTPRequestOperation.h" + +@interface AFImageCache : NSCache +@end + +#pragma mark - + +@interface UIImageView (_AFNetworking) +@property (readwrite, nonatomic, strong, setter = af_setImageRequestOperation:) AFHTTPRequestOperation *af_imageRequestOperation; +@end + +@implementation UIImageView (_AFNetworking) + ++ (NSOperationQueue *)af_sharedImageRequestOperationQueue { + static NSOperationQueue *_af_sharedImageRequestOperationQueue = nil; + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^{ + _af_sharedImageRequestOperationQueue = [[NSOperationQueue alloc] init]; + _af_sharedImageRequestOperationQueue.maxConcurrentOperationCount = NSOperationQueueDefaultMaxConcurrentOperationCount; + }); + + return _af_sharedImageRequestOperationQueue; +} + +- (AFHTTPRequestOperation *)af_imageRequestOperation { + return (AFHTTPRequestOperation *)objc_getAssociatedObject(self, @selector(af_imageRequestOperation)); +} + +- (void)af_setImageRequestOperation:(AFHTTPRequestOperation *)imageRequestOperation { + objc_setAssociatedObject(self, @selector(af_imageRequestOperation), imageRequestOperation, OBJC_ASSOCIATION_RETAIN_NONATOMIC); +} + +@end + +#pragma mark - + +@implementation UIImageView (AFNetworking) +@dynamic imageResponseSerializer; + ++ (id )sharedImageCache { + static AFImageCache *_af_defaultImageCache = nil; + static dispatch_once_t oncePredicate; + dispatch_once(&oncePredicate, ^{ + _af_defaultImageCache = [[AFImageCache alloc] init]; + + [[NSNotificationCenter defaultCenter] addObserverForName:UIApplicationDidReceiveMemoryWarningNotification object:nil queue:[NSOperationQueue mainQueue] usingBlock:^(NSNotification * __unused notification) { + [_af_defaultImageCache removeAllObjects]; + }]; + }); + +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wgnu" + return objc_getAssociatedObject(self, @selector(sharedImageCache)) ?: _af_defaultImageCache; +#pragma clang diagnostic pop +} + ++ (void)setSharedImageCache:(id)imageCache { + objc_setAssociatedObject(self, @selector(sharedImageCache), imageCache, OBJC_ASSOCIATION_RETAIN_NONATOMIC); +} + +- (id )imageResponseSerializer { + static id _af_defaultImageResponseSerializer = nil; + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^{ + _af_defaultImageResponseSerializer = [AFImageResponseSerializer serializer]; + }); + +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wgnu" + return objc_getAssociatedObject(self, @selector(imageResponseSerializer)) ?: _af_defaultImageResponseSerializer; +#pragma clang diagnostic pop +} + +- (void)setImageResponseSerializer:(id )serializer { + objc_setAssociatedObject(self, @selector(imageResponseSerializer), serializer, OBJC_ASSOCIATION_RETAIN_NONATOMIC); +} + +#pragma mark - + +- (void)setImageWithURL:(NSURL *)url { + [self setImageWithURL:url placeholderImage:nil]; +} + +- (void)setImageWithURL:(NSURL *)url + placeholderImage:(UIImage *)placeholderImage +{ + NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url]; + [request addValue:@"image/*" forHTTPHeaderField:@"Accept"]; + + [self setImageWithURLRequest:request placeholderImage:placeholderImage success:nil failure:nil]; +} + +- (void)setImageWithURLRequest:(NSURLRequest *)urlRequest + placeholderImage:(UIImage *)placeholderImage + success:(void (^)(NSURLRequest *request, NSHTTPURLResponse *response, UIImage *image))success + failure:(void (^)(NSURLRequest *request, NSHTTPURLResponse *response, NSError *error))failure +{ + [self cancelImageRequestOperation]; + + UIImage *cachedImage = [[[self class] sharedImageCache] cachedImageForRequest:urlRequest]; + if (cachedImage) { + if (success) { + success(nil, nil, cachedImage); + } else { + self.image = cachedImage; + } + + self.af_imageRequestOperation = nil; + } else { + if (placeholderImage) { + self.image = placeholderImage; + } + + __weak __typeof(self)weakSelf = self; + self.af_imageRequestOperation = [[AFHTTPRequestOperation alloc] initWithRequest:urlRequest]; + self.af_imageRequestOperation.responseSerializer = self.imageResponseSerializer; + [self.af_imageRequestOperation setCompletionBlockWithSuccess:^(AFHTTPRequestOperation *operation, id responseObject) { + __strong __typeof(weakSelf)strongSelf = weakSelf; + if ([[urlRequest URL] isEqual:[strongSelf.af_imageRequestOperation.request URL]]) { + if (success) { + success(urlRequest, operation.response, responseObject); + } else if (responseObject) { + strongSelf.image = responseObject; + } + + if (operation == strongSelf.af_imageRequestOperation){ + strongSelf.af_imageRequestOperation = nil; + } + } + + [[[strongSelf class] sharedImageCache] cacheImage:responseObject forRequest:urlRequest]; + } failure:^(AFHTTPRequestOperation *operation, NSError *error) { + __strong __typeof(weakSelf)strongSelf = weakSelf; + if ([[urlRequest URL] isEqual:[strongSelf.af_imageRequestOperation.request URL]]) { + if (failure) { + failure(urlRequest, operation.response, error); + } + + if (operation == strongSelf.af_imageRequestOperation){ + strongSelf.af_imageRequestOperation = nil; + } + } + }]; + + [[[self class] af_sharedImageRequestOperationQueue] addOperation:self.af_imageRequestOperation]; + } +} + +- (void)cancelImageRequestOperation { + [self.af_imageRequestOperation cancel]; + self.af_imageRequestOperation = nil; +} + +@end + +#pragma mark - + +static inline NSString * AFImageCacheKeyFromURLRequest(NSURLRequest *request) { + return [[request URL] absoluteString]; +} + +@implementation AFImageCache + +- (UIImage *)cachedImageForRequest:(NSURLRequest *)request { + switch ([request cachePolicy]) { + case NSURLRequestReloadIgnoringCacheData: + case NSURLRequestReloadIgnoringLocalAndRemoteCacheData: + return nil; + default: + break; + } + + return [self objectForKey:AFImageCacheKeyFromURLRequest(request)]; +} + +- (void)cacheImage:(UIImage *)image + forRequest:(NSURLRequest *)request +{ + if (image && request) { + [self setObject:image forKey:AFImageCacheKeyFromURLRequest(request)]; + } +} + +@end + +#endif diff --git a/ios/Pods/AFNetworking/UIKit+AFNetworking/UIKit+AFNetworking.h b/ios/Pods/AFNetworking/UIKit+AFNetworking/UIKit+AFNetworking.h new file mode 100644 index 000000000..94082f6cb --- /dev/null +++ b/ios/Pods/AFNetworking/UIKit+AFNetworking/UIKit+AFNetworking.h @@ -0,0 +1,38 @@ +// UIKit+AFNetworking.h +// +// Copyright (c) 2013 AFNetworking (http://afnetworking.com/) +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +#import + +#ifndef _UIKIT_AFNETWORKING_ + #define _UIKIT_AFNETWORKING_ + + #import "AFNetworkActivityIndicatorManager.h" + + #import "UIActivityIndicatorView+AFNetworking.h" + #import "UIAlertView+AFNetworking.h" + #import "UIButton+AFNetworking.h" + #import "UIImageView+AFNetworking.h" + #import "UIKit+AFNetworking.h" + #import "UIProgressView+AFNetworking.h" + #import "UIRefreshControl+AFNetworking.h" + #import "UIWebView+AFNetworking.h" +#endif /* _UIKIT_AFNETWORKING_ */ diff --git a/ios/Pods/AFNetworking/UIKit+AFNetworking/UIProgressView+AFNetworking.h b/ios/Pods/AFNetworking/UIKit+AFNetworking/UIProgressView+AFNetworking.h new file mode 100644 index 000000000..3f1bc086f --- /dev/null +++ b/ios/Pods/AFNetworking/UIKit+AFNetworking/UIProgressView+AFNetworking.h @@ -0,0 +1,88 @@ +// UIProgressView+AFNetworking.h +// +// Copyright (c) 2013-2014 AFNetworking (http://afnetworking.com) +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +#import + +#import + +#if defined(__IPHONE_OS_VERSION_MIN_REQUIRED) + +#import + +@class AFURLConnectionOperation; + +/** + This category adds methods to the UIKit framework's `UIProgressView` class. The methods in this category provide support for binding the progress to the upload and download progress of a session task or request operation. + */ +@interface UIProgressView (AFNetworking) + +///------------------------------------ +/// @name Setting Session Task Progress +///------------------------------------ + +/** + Binds the progress to the upload progress of the specified session task. + + @param task The session task. + @param animated `YES` if the change should be animated, `NO` if the change should happen immediately. + */ +#if __IPHONE_OS_VERSION_MIN_REQUIRED >= 70000 +- (void)setProgressWithUploadProgressOfTask:(NSURLSessionUploadTask *)task + animated:(BOOL)animated; +#endif + +/** + Binds the progress to the download progress of the specified session task. + + @param task The session task. + @param animated `YES` if the change should be animated, `NO` if the change should happen immediately. + */ +#if __IPHONE_OS_VERSION_MIN_REQUIRED >= 70000 +- (void)setProgressWithDownloadProgressOfTask:(NSURLSessionDownloadTask *)task + animated:(BOOL)animated; +#endif + +///------------------------------------ +/// @name Setting Session Task Progress +///------------------------------------ + +/** + Binds the progress to the upload progress of the specified request operation. + + @param operation The request operation. + @param animated `YES` if the change should be animated, `NO` if the change should happen immediately. + */ +- (void)setProgressWithUploadProgressOfOperation:(AFURLConnectionOperation *)operation + animated:(BOOL)animated; + +/** + Binds the progress to the download progress of the specified request operation. + + @param operation The request operation. + @param animated `YES` if the change should be animated, `NO` if the change should happen immediately. + */ +- (void)setProgressWithDownloadProgressOfOperation:(AFURLConnectionOperation *)operation + animated:(BOOL)animated; + +@end + +#endif diff --git a/ios/Pods/AFNetworking/UIKit+AFNetworking/UIProgressView+AFNetworking.m b/ios/Pods/AFNetworking/UIKit+AFNetworking/UIProgressView+AFNetworking.m new file mode 100644 index 000000000..7281149ec --- /dev/null +++ b/ios/Pods/AFNetworking/UIKit+AFNetworking/UIProgressView+AFNetworking.m @@ -0,0 +1,183 @@ +// UIProgressView+AFNetworking.m +// +// Copyright (c) 2013-2014 AFNetworking (http://afnetworking.com) +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +#import "UIProgressView+AFNetworking.h" + +#import + +#if defined(__IPHONE_OS_VERSION_MIN_REQUIRED) + +#import "AFURLConnectionOperation.h" + +#if __IPHONE_OS_VERSION_MIN_REQUIRED >= 70000 +#import "AFURLSessionManager.h" +#endif + +static void * AFTaskCountOfBytesSentContext = &AFTaskCountOfBytesSentContext; +static void * AFTaskCountOfBytesReceivedContext = &AFTaskCountOfBytesReceivedContext; + +@interface AFURLConnectionOperation (_UIProgressView) +@property (readwrite, nonatomic, copy) void (^uploadProgress)(NSUInteger bytes, long long totalBytes, long long totalBytesExpected); +@property (readwrite, nonatomic, assign, setter = af_setUploadProgressAnimated:) BOOL af_uploadProgressAnimated; + +@property (readwrite, nonatomic, copy) void (^downloadProgress)(NSUInteger bytes, long long totalBytes, long long totalBytesExpected); +@property (readwrite, nonatomic, assign, setter = af_setDownloadProgressAnimated:) BOOL af_downloadProgressAnimated; +@end + +@implementation AFURLConnectionOperation (_UIProgressView) +@dynamic uploadProgress; // Implemented in AFURLConnectionOperation +@dynamic af_uploadProgressAnimated; + +@dynamic downloadProgress; // Implemented in AFURLConnectionOperation +@dynamic af_downloadProgressAnimated; +@end + +#pragma mark - + +@implementation UIProgressView (AFNetworking) + +- (BOOL)af_uploadProgressAnimated { + return [(NSNumber *)objc_getAssociatedObject(self, @selector(af_uploadProgressAnimated)) boolValue]; +} + +- (void)af_setUploadProgressAnimated:(BOOL)animated { + objc_setAssociatedObject(self, @selector(af_uploadProgressAnimated), @(animated), OBJC_ASSOCIATION_RETAIN_NONATOMIC); +} + +- (BOOL)af_downloadProgressAnimated { + return [(NSNumber *)objc_getAssociatedObject(self, @selector(af_downloadProgressAnimated)) boolValue]; +} + +- (void)af_setDownloadProgressAnimated:(BOOL)animated { + objc_setAssociatedObject(self, @selector(af_downloadProgressAnimated), @(animated), OBJC_ASSOCIATION_RETAIN_NONATOMIC); +} + +#pragma mark - + +#if __IPHONE_OS_VERSION_MIN_REQUIRED >= 70000 +- (void)setProgressWithUploadProgressOfTask:(NSURLSessionUploadTask *)task + animated:(BOOL)animated +{ + [task addObserver:self forKeyPath:@"state" options:0 context:AFTaskCountOfBytesSentContext]; + [task addObserver:self forKeyPath:@"countOfBytesSent" options:0 context:AFTaskCountOfBytesSentContext]; + + [self af_setUploadProgressAnimated:animated]; +} + +- (void)setProgressWithDownloadProgressOfTask:(NSURLSessionDownloadTask *)task + animated:(BOOL)animated +{ + [task addObserver:self forKeyPath:@"state" options:0 context:AFTaskCountOfBytesReceivedContext]; + [task addObserver:self forKeyPath:@"countOfBytesReceived" options:0 context:AFTaskCountOfBytesReceivedContext]; + + [self af_setDownloadProgressAnimated:animated]; +} +#endif + +#pragma mark - + +- (void)setProgressWithUploadProgressOfOperation:(AFURLConnectionOperation *)operation + animated:(BOOL)animated +{ + __weak __typeof(self)weakSelf = self; + void (^original)(NSUInteger bytesWritten, long long totalBytesWritten, long long totalBytesExpectedToWrite) = [operation.uploadProgress copy]; + [operation setUploadProgressBlock:^(NSUInteger bytesWritten, long long totalBytesWritten, long long totalBytesExpectedToWrite) { + if (original) { + original(bytesWritten, totalBytesWritten, totalBytesExpectedToWrite); + } + + dispatch_async(dispatch_get_main_queue(), ^{ + if (totalBytesExpectedToWrite > 0) { + __strong __typeof(weakSelf)strongSelf = weakSelf; + [strongSelf setProgress:(totalBytesWritten / (totalBytesExpectedToWrite * 1.0f)) animated:animated]; + } + }); + }]; +} + +- (void)setProgressWithDownloadProgressOfOperation:(AFURLConnectionOperation *)operation + animated:(BOOL)animated +{ + __weak __typeof(self)weakSelf = self; + void (^original)(NSUInteger bytesRead, long long totalBytesRead, long long totalBytesExpectedToRead) = [operation.downloadProgress copy]; + [operation setDownloadProgressBlock:^(NSUInteger bytesRead, long long totalBytesRead, long long totalBytesExpectedToRead) { + if (original) { + original(bytesRead, totalBytesRead, totalBytesExpectedToRead); + } + + dispatch_async(dispatch_get_main_queue(), ^{ + if (totalBytesExpectedToRead > 0) { + __strong __typeof(weakSelf)strongSelf = weakSelf; + [strongSelf setProgress:(totalBytesRead / (totalBytesExpectedToRead * 1.0f)) animated:animated]; + } + }); + }]; +} + +#pragma mark - NSKeyValueObserving + +- (void)observeValueForKeyPath:(NSString *)keyPath + ofObject:(id)object + change:(__unused NSDictionary *)change + context:(void *)context +{ +#if __IPHONE_OS_VERSION_MIN_REQUIRED >= 70000 + if (context == AFTaskCountOfBytesSentContext || context == AFTaskCountOfBytesReceivedContext) { + if ([keyPath isEqualToString:NSStringFromSelector(@selector(countOfBytesSent))]) { + if ([object countOfBytesExpectedToSend] > 0) { + dispatch_async(dispatch_get_main_queue(), ^{ + [self setProgress:[object countOfBytesSent] / ([object countOfBytesExpectedToSend] * 1.0f) animated:self.af_uploadProgressAnimated]; + }); + } + } + + if ([keyPath isEqualToString:NSStringFromSelector(@selector(countOfBytesReceived))]) { + if ([object countOfBytesExpectedToReceive] > 0) { + dispatch_async(dispatch_get_main_queue(), ^{ + [self setProgress:[object countOfBytesReceived] / ([object countOfBytesExpectedToReceive] * 1.0f) animated:self.af_downloadProgressAnimated]; + }); + } + } + + if ([keyPath isEqualToString:NSStringFromSelector(@selector(state))]) { + if ([(NSURLSessionTask *)object state] == NSURLSessionTaskStateCompleted) { + @try { + [object removeObserver:self forKeyPath:NSStringFromSelector(@selector(state))]; + + if (context == AFTaskCountOfBytesSentContext) { + [object removeObserver:self forKeyPath:NSStringFromSelector(@selector(countOfBytesSent))]; + } + + if (context == AFTaskCountOfBytesReceivedContext) { + [object removeObserver:self forKeyPath:NSStringFromSelector(@selector(countOfBytesReceived))]; + } + } + @catch (NSException * __unused exception) {} + } + } + } +#endif +} + +@end + +#endif diff --git a/ios/Pods/AFNetworking/UIKit+AFNetworking/UIRefreshControl+AFNetworking.h b/ios/Pods/AFNetworking/UIKit+AFNetworking/UIRefreshControl+AFNetworking.h new file mode 100644 index 000000000..37ce772de --- /dev/null +++ b/ios/Pods/AFNetworking/UIKit+AFNetworking/UIRefreshControl+AFNetworking.h @@ -0,0 +1,64 @@ +// UIRefreshControl+AFNetworking.m +// +// Copyright (c) 2014 AFNetworking (http://afnetworking.com) +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +#import + +#import + +#if defined(__IPHONE_OS_VERSION_MIN_REQUIRED) + +#import + +@class AFURLConnectionOperation; + +/** + This category adds methods to the UIKit framework's `UIRefreshControl` class. The methods in this category provide support for automatically begining and ending refreshing depending on the loading state of a request operation or session task. + */ +@interface UIRefreshControl (AFNetworking) + +///----------------------------------- +/// @name Refreshing for Session Tasks +///----------------------------------- + +/** + Binds the refreshing state to the state of the specified task. + + @param task The task. If `nil`, automatic updating from any previously specified operation will be diabled. + */ +#if __IPHONE_OS_VERSION_MIN_REQUIRED >= 70000 +- (void)setRefreshingWithStateOfTask:(NSURLSessionTask *)task; +#endif + +///---------------------------------------- +/// @name Refreshing for Request Operations +///---------------------------------------- + +/** + Binds the refreshing state to the execution state of the specified operation. + + @param operation The operation. If `nil`, automatic updating from any previously specified operation will be disabled. + */ +- (void)setRefreshingWithStateOfOperation:(AFURLConnectionOperation *)operation; + +@end + +#endif diff --git a/ios/Pods/AFNetworking/UIKit+AFNetworking/UIRefreshControl+AFNetworking.m b/ios/Pods/AFNetworking/UIKit+AFNetworking/UIRefreshControl+AFNetworking.m new file mode 100644 index 000000000..ba2815738 --- /dev/null +++ b/ios/Pods/AFNetworking/UIKit+AFNetworking/UIRefreshControl+AFNetworking.m @@ -0,0 +1,95 @@ +// UIRefreshControl+AFNetworking.m +// +// Copyright (c) 2014 AFNetworking (http://afnetworking.com) +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +#import "UIRefreshControl+AFNetworking.h" + +#if defined(__IPHONE_OS_VERSION_MIN_REQUIRED) + +#import "AFHTTPRequestOperation.h" + +#if __IPHONE_OS_VERSION_MIN_REQUIRED >= 70000 +#import "AFURLSessionManager.h" +#endif + +@implementation UIRefreshControl (AFNetworking) + +#if __IPHONE_OS_VERSION_MIN_REQUIRED >= 70000 +- (void)setRefreshingWithStateOfTask:(NSURLSessionTask *)task { + NSNotificationCenter *notificationCenter = [NSNotificationCenter defaultCenter]; + + [notificationCenter removeObserver:self name:AFNetworkingTaskDidResumeNotification object:nil]; + [notificationCenter removeObserver:self name:AFNetworkingTaskDidSuspendNotification object:nil]; + [notificationCenter removeObserver:self name:AFNetworkingTaskDidCompleteNotification object:nil]; + + if (task) { + if (task.state != NSURLSessionTaskStateCompleted) { + if (task.state == NSURLSessionTaskStateRunning) { + [self beginRefreshing]; + } else { + [self endRefreshing]; + } + + [notificationCenter addObserver:self selector:@selector(af_beginRefreshing) name:AFNetworkingTaskDidResumeNotification object:task]; + [notificationCenter addObserver:self selector:@selector(af_endRefreshing) name:AFNetworkingTaskDidCompleteNotification object:task]; + [notificationCenter addObserver:self selector:@selector(af_endRefreshing) name:AFNetworkingTaskDidSuspendNotification object:task]; + } + } +} +#endif + +- (void)setRefreshingWithStateOfOperation:(AFURLConnectionOperation *)operation { + NSNotificationCenter *notificationCenter = [NSNotificationCenter defaultCenter]; + + [notificationCenter removeObserver:self name:AFNetworkingOperationDidStartNotification object:nil]; + [notificationCenter removeObserver:self name:AFNetworkingOperationDidFinishNotification object:nil]; + + if (operation) { + if (![operation isFinished]) { + if ([operation isExecuting]) { + [self beginRefreshing]; + } else { + [self endRefreshing]; + } + + [notificationCenter addObserver:self selector:@selector(af_beginRefreshing) name:AFNetworkingOperationDidStartNotification object:operation]; + [notificationCenter addObserver:self selector:@selector(af_endRefreshing) name:AFNetworkingOperationDidFinishNotification object:operation]; + } + } +} + +#pragma mark - + +- (void)af_beginRefreshing { + dispatch_async(dispatch_get_main_queue(), ^{ + [self beginRefreshing]; + }); +} + +- (void)af_endRefreshing { + dispatch_async(dispatch_get_main_queue(), ^{ + [self endRefreshing]; + }); +} + +@end + +#endif diff --git a/ios/Pods/AFNetworking/UIKit+AFNetworking/UIWebView+AFNetworking.h b/ios/Pods/AFNetworking/UIKit+AFNetworking/UIWebView+AFNetworking.h new file mode 100644 index 000000000..202e8f4ea --- /dev/null +++ b/ios/Pods/AFNetworking/UIKit+AFNetworking/UIWebView+AFNetworking.h @@ -0,0 +1,83 @@ +// UIWebView+AFNetworking.h +// +// Copyright (c) 2013-2014 AFNetworking (http://afnetworking.com) +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +#import + +#import + +#if defined(__IPHONE_OS_VERSION_MIN_REQUIRED) + +#import + +@class AFHTTPRequestSerializer, AFHTTPResponseSerializer; +@protocol AFURLRequestSerialization, AFURLResponseSerialization; + +/** + This category adds methods to the UIKit framework's `UIWebView` class. The methods in this category provide increased control over the request cycle, including progress monitoring and success / failure handling. + + @discussion When using these category methods, make sure to assign `delegate` for the web view, which implements `–webView:shouldStartLoadWithRequest:navigationType:` appropriately. This allows for tapped links to be loaded through AFNetworking, and can ensure that `canGoBack` & `canGoForward` update their values correctly. + */ +@interface UIWebView (AFNetworking) + +/** + The request serializer used to serialize requests made with the `-loadRequest:...` category methods. By default, this is an instance of `AFHTTPRequestSerializer`. + */ +@property (nonatomic, strong) AFHTTPRequestSerializer * requestSerializer; + +/** + The response serializer used to serialize responses made with the `-loadRequest:...` category methods. By default, this is an instance of `AFHTTPResponseSerializer`. + */ +@property (nonatomic, strong) AFHTTPResponseSerializer * responseSerializer; + +/** + Asynchronously loads the specified request. + + @param request A URL request identifying the location of the content to load. This must not be `nil`. + @param progress A block object to be called when an undetermined number of bytes have been downloaded from the server. This block has no return value and takes three arguments: the number of bytes read since the last time the download progress block was called, the total bytes read, and the total bytes expected to be read during the request, as initially determined by the expected content size of the `NSHTTPURLResponse` object. This block may be called multiple times, and will execute on the main thread. + @param success A block object to be executed when the request finishes loading successfully. This block returns the HTML string to be loaded by the web view, and takes two arguments: the response, and the response string. + @param failure A block object to be executed when the request operation finishes unsuccessfully, or that finishes successfully, but encountered an error while parsing the response data. This block has no return value and takes a single argument: the error that occurred. + */ +- (void)loadRequest:(NSURLRequest *)request + progress:(void (^)(NSUInteger bytesWritten, long long totalBytesWritten, long long totalBytesExpectedToWrite))progress + success:(NSString * (^)(NSHTTPURLResponse *response, NSString *HTML))success + failure:(void (^)(NSError *error))failure; + +/** + Asynchronously loads the data associated with a particular request with a specified MIME type and text encoding. + + @param request A URL request identifying the location of the content to load. This must not be `nil`. + @param MIMEType The MIME type of the content. Defaults to the content type of the response if not specified. + @param textEncodingName The IANA encoding name, as in `utf-8` or `utf-16`. Defaults to the response text encoding if not specified. + @param progress A block object to be called when an undetermined number of bytes have been downloaded from the server. This block has no return value and takes three arguments: the number of bytes read since the last time the download progress block was called, the total bytes read, and the total bytes expected to be read during the request, as initially determined by the expected content size of the `NSHTTPURLResponse` object. This block may be called multiple times, and will execute on the main thread. + @param success A block object to be executed when the request finishes loading successfully. This block returns the data to be loaded by the web view and takes two arguments: the response, and the downloaded data. + @param failure A block object to be executed when the request operation finishes unsuccessfully, or that finishes successfully, but encountered an error while parsing the response data. This block has no return value and takes a single argument: the error that occurred. + */ +- (void)loadRequest:(NSURLRequest *)request + MIMEType:(NSString *)MIMEType + textEncodingName:(NSString *)textEncodingName + progress:(void (^)(NSUInteger bytesWritten, long long totalBytesWritten, long long totalBytesExpectedToWrite))progress + success:(NSData * (^)(NSHTTPURLResponse *response, NSData *data))success + failure:(void (^)(NSError *error))failure; + +@end + +#endif diff --git a/ios/Pods/AFNetworking/UIKit+AFNetworking/UIWebView+AFNetworking.m b/ios/Pods/AFNetworking/UIKit+AFNetworking/UIWebView+AFNetworking.m new file mode 100644 index 000000000..525d02aea --- /dev/null +++ b/ios/Pods/AFNetworking/UIKit+AFNetworking/UIWebView+AFNetworking.m @@ -0,0 +1,151 @@ +// UIWebView+AFNetworking.m +// +// Copyright (c) 2013-2014 AFNetworking (http://afnetworking.com) +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +#import "UIWebView+AFNetworking.h" + +#import + +#if defined(__IPHONE_OS_VERSION_MIN_REQUIRED) + +#import "AFHTTPRequestOperation.h" +#import "AFURLResponseSerialization.h" +#import "AFURLRequestSerialization.h" + +@interface UIWebView (_AFNetworking) +@property (readwrite, nonatomic, strong, setter = af_setHTTPRequestOperation:) AFHTTPRequestOperation *af_HTTPRequestOperation; +@end + +@implementation UIWebView (_AFNetworking) + +- (AFHTTPRequestOperation *)af_HTTPRequestOperation { + return (AFHTTPRequestOperation *)objc_getAssociatedObject(self, @selector(af_HTTPRequestOperation)); +} + +- (void)af_setHTTPRequestOperation:(AFHTTPRequestOperation *)operation { + objc_setAssociatedObject(self, @selector(af_HTTPRequestOperation), operation, OBJC_ASSOCIATION_RETAIN_NONATOMIC); +} + +@end + +#pragma mark - + +@implementation UIWebView (AFNetworking) + +- (AFHTTPRequestSerializer *)requestSerializer { + static AFHTTPRequestSerializer *_af_defaultRequestSerializer = nil; + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^{ + _af_defaultRequestSerializer = [AFHTTPRequestSerializer serializer]; + }); + +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wgnu" + return objc_getAssociatedObject(self, @selector(requestSerializer)) ?: _af_defaultRequestSerializer; +#pragma clang diagnostic pop +} + +- (void)setRequestSerializer:(AFHTTPRequestSerializer *)requestSerializer { + objc_setAssociatedObject(self, @selector(requestSerializer), requestSerializer, OBJC_ASSOCIATION_RETAIN_NONATOMIC); +} + +- (AFHTTPResponseSerializer *)responseSerializer { + static AFHTTPResponseSerializer *_af_defaultResponseSerializer = nil; + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^{ + _af_defaultResponseSerializer = [AFHTTPResponseSerializer serializer]; + }); + +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wgnu" + return objc_getAssociatedObject(self, @selector(responseSerializer)) ?: _af_defaultResponseSerializer; +#pragma clang diagnostic pop +} + +- (void)setResponseSerializer:(AFHTTPResponseSerializer *)responseSerializer { + objc_setAssociatedObject(self, @selector(responseSerializer), responseSerializer, OBJC_ASSOCIATION_RETAIN_NONATOMIC); +} + +#pragma mark - + +- (void)loadRequest:(NSURLRequest *)request + progress:(void (^)(NSUInteger bytesWritten, long long totalBytesWritten, long long totalBytesExpectedToWrite))progress + success:(NSString * (^)(NSHTTPURLResponse *response, NSString *HTML))success + failure:(void (^)(NSError *error))failure +{ + [self loadRequest:request MIMEType:nil textEncodingName:nil progress:progress success:^NSData *(NSHTTPURLResponse *response, NSData *data) { + NSStringEncoding stringEncoding = NSUTF8StringEncoding; + if (response.textEncodingName) { + CFStringEncoding encoding = CFStringConvertIANACharSetNameToEncoding((CFStringRef)response.textEncodingName); + if (encoding != kCFStringEncodingInvalidId) { + stringEncoding = CFStringConvertEncodingToNSStringEncoding(encoding); + } + } + + NSString *string = [[NSString alloc] initWithData:data encoding:stringEncoding]; + if (success) { + string = success(response, string); + } + + return [string dataUsingEncoding:stringEncoding]; + } failure:failure]; +} + +- (void)loadRequest:(NSURLRequest *)request + MIMEType:(NSString *)MIMEType + textEncodingName:(NSString *)textEncodingName + progress:(void (^)(NSUInteger bytesWritten, long long totalBytesWritten, long long totalBytesExpectedToWrite))progress + success:(NSData * (^)(NSHTTPURLResponse *response, NSData *data))success + failure:(void (^)(NSError *error))failure +{ + NSParameterAssert(request); + + if (self.af_HTTPRequestOperation) { + [self.af_HTTPRequestOperation cancel]; + } + + request = [self.requestSerializer requestBySerializingRequest:request withParameters:nil error:nil]; + + self.af_HTTPRequestOperation = [[AFHTTPRequestOperation alloc] initWithRequest:request]; + self.af_HTTPRequestOperation.responseSerializer = self.responseSerializer; + + __weak __typeof(self)weakSelf = self; + [self.af_HTTPRequestOperation setDownloadProgressBlock:progress]; + [self.af_HTTPRequestOperation setCompletionBlockWithSuccess:^(AFHTTPRequestOperation *operation, id __unused responseObject) { + NSData *data = success ? success(operation.response, operation.responseData) : operation.responseData; + +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wgnu" + __strong __typeof(weakSelf) strongSelf = weakSelf; + [strongSelf loadData:data MIMEType:(MIMEType ?: [operation.response MIMEType]) textEncodingName:(textEncodingName ?: [operation.response textEncodingName]) baseURL:[operation.response URL]]; +#pragma clang diagnostic pop + } failure:^(AFHTTPRequestOperation * __unused operation, NSError *error) { + if (failure) { + failure(error); + } + }]; + + [self.af_HTTPRequestOperation start]; +} + +@end + +#endif diff --git a/ios/Pods/DACircularProgress/DACircularProgress/DACircularProgressView.h b/ios/Pods/DACircularProgress/DACircularProgress/DACircularProgressView.h new file mode 100644 index 000000000..78146886c --- /dev/null +++ b/ios/Pods/DACircularProgress/DACircularProgress/DACircularProgressView.h @@ -0,0 +1,25 @@ +// +// DACircularProgressView.h +// DACircularProgress +// +// Created by Daniel Amitay on 2/6/12. +// Copyright (c) 2012 Daniel Amitay. All rights reserved. +// + +#import + +@interface DACircularProgressView : UIView + +@property(nonatomic, strong) UIColor *trackTintColor UI_APPEARANCE_SELECTOR; +@property(nonatomic, strong) UIColor *progressTintColor UI_APPEARANCE_SELECTOR; +@property(nonatomic) NSInteger roundedCorners UI_APPEARANCE_SELECTOR; // Can not use BOOL with UI_APPEARANCE_SELECTOR :-( +@property(nonatomic) CGFloat thicknessRatio UI_APPEARANCE_SELECTOR; +@property(nonatomic) NSInteger clockwiseProgress UI_APPEARANCE_SELECTOR; // Can not use BOOL with UI_APPEARANCE_SELECTOR :-( +@property(nonatomic) CGFloat progress; + +@property(nonatomic) CGFloat indeterminateDuration UI_APPEARANCE_SELECTOR; +@property(nonatomic) NSInteger indeterminate UI_APPEARANCE_SELECTOR; // Can not use BOOL with UI_APPEARANCE_SELECTOR :-( + +- (void)setProgress:(CGFloat)progress animated:(BOOL)animated; + +@end diff --git a/ios/Pods/DACircularProgress/DACircularProgress/DACircularProgressView.m b/ios/Pods/DACircularProgress/DACircularProgress/DACircularProgressView.m new file mode 100644 index 000000000..928206c2a --- /dev/null +++ b/ios/Pods/DACircularProgress/DACircularProgress/DACircularProgressView.m @@ -0,0 +1,271 @@ +// +// DACircularProgressView.m +// DACircularProgress +// +// Created by Daniel Amitay on 2/6/12. +// Copyright (c) 2012 Daniel Amitay. All rights reserved. +// + +#import "DACircularProgressView.h" + +#import + +@interface DACircularProgressLayer : CALayer + +@property(nonatomic, strong) UIColor *trackTintColor; +@property(nonatomic, strong) UIColor *progressTintColor; +@property(nonatomic) NSInteger roundedCorners; +@property(nonatomic) CGFloat thicknessRatio; +@property(nonatomic) CGFloat progress; +@property(nonatomic) NSInteger clockwiseProgress; + +@end + +@implementation DACircularProgressLayer + +@dynamic trackTintColor; +@dynamic progressTintColor; +@dynamic roundedCorners; +@dynamic thicknessRatio; +@dynamic progress; +@dynamic clockwiseProgress; + ++ (BOOL)needsDisplayForKey:(NSString *)key +{ + if ([key isEqualToString:@"progress"]) { + return YES; + } else { + return [super needsDisplayForKey:key]; + } +} + +- (void)drawInContext:(CGContextRef)context +{ + CGRect rect = self.bounds; + CGPoint centerPoint = CGPointMake(rect.size.width / 2.0f, rect.size.height / 2.0f); + CGFloat radius = MIN(rect.size.height, rect.size.width) / 2.0f; + + BOOL clockwise = (self.clockwiseProgress != 0); + + CGFloat progress = MIN(self.progress, 1.0f - FLT_EPSILON); + CGFloat radians = 0; + if (clockwise) + { + radians = (float)((progress * 2.0f * M_PI) - M_PI_2); + } + else + { + radians = (float)(3 * M_PI_2 - (progress * 2.0f * M_PI)); + } + + CGContextSetFillColorWithColor(context, self.trackTintColor.CGColor); + CGMutablePathRef trackPath = CGPathCreateMutable(); + CGPathMoveToPoint(trackPath, NULL, centerPoint.x, centerPoint.y); + CGPathAddArc(trackPath, NULL, centerPoint.x, centerPoint.y, radius, (float)(2.0f * M_PI), 0.0f, TRUE); + CGPathCloseSubpath(trackPath); + CGContextAddPath(context, trackPath); + CGContextFillPath(context); + CGPathRelease(trackPath); + + if (progress > 0.0f) { + CGContextSetFillColorWithColor(context, self.progressTintColor.CGColor); + CGMutablePathRef progressPath = CGPathCreateMutable(); + CGPathMoveToPoint(progressPath, NULL, centerPoint.x, centerPoint.y); + CGPathAddArc(progressPath, NULL, centerPoint.x, centerPoint.y, radius, (float)(3.0f * M_PI_2), radians, !clockwise); + CGPathCloseSubpath(progressPath); + CGContextAddPath(context, progressPath); + CGContextFillPath(context); + CGPathRelease(progressPath); + } + + if (progress > 0.0f && self.roundedCorners) { + CGFloat pathWidth = radius * self.thicknessRatio; + CGFloat xOffset = radius * (1.0f + ((1.0f - (self.thicknessRatio / 2.0f)) * cosf(radians))); + CGFloat yOffset = radius * (1.0f + ((1.0f - (self.thicknessRatio / 2.0f)) * sinf(radians))); + CGPoint endPoint = CGPointMake(xOffset, yOffset); + + CGRect startEllipseRect = (CGRect) { + .origin.x = centerPoint.x - pathWidth / 2.0f, + .origin.y = 0.0f, + .size.width = pathWidth, + .size.height = pathWidth + }; + CGContextAddEllipseInRect(context, startEllipseRect); + CGContextFillPath(context); + + CGRect endEllipseRect = (CGRect) { + .origin.x = endPoint.x - pathWidth / 2.0f, + .origin.y = endPoint.y - pathWidth / 2.0f, + .size.width = pathWidth, + .size.height = pathWidth + }; + CGContextAddEllipseInRect(context, endEllipseRect); + CGContextFillPath(context); + } + + CGContextSetBlendMode(context, kCGBlendModeClear); + CGFloat innerRadius = radius * (1.0f - self.thicknessRatio); + CGRect clearRect = (CGRect) { + .origin.x = centerPoint.x - innerRadius, + .origin.y = centerPoint.y - innerRadius, + .size.width = innerRadius * 2.0f, + .size.height = innerRadius * 2.0f + }; + CGContextAddEllipseInRect(context, clearRect); + CGContextFillPath(context); +} + +@end + +@interface DACircularProgressView () + +@end + +@implementation DACircularProgressView + ++ (void) initialize +{ + if (self == [DACircularProgressView class]) { + DACircularProgressView *circularProgressViewAppearance = [DACircularProgressView appearance]; + [circularProgressViewAppearance setTrackTintColor:[[UIColor whiteColor] colorWithAlphaComponent:0.3f]]; + [circularProgressViewAppearance setProgressTintColor:[UIColor whiteColor]]; + [circularProgressViewAppearance setBackgroundColor:[UIColor clearColor]]; + [circularProgressViewAppearance setThicknessRatio:0.3f]; + [circularProgressViewAppearance setRoundedCorners:NO]; + [circularProgressViewAppearance setClockwiseProgress:YES]; + + [circularProgressViewAppearance setIndeterminateDuration:2.0f]; + [circularProgressViewAppearance setIndeterminate:NO]; + } +} + ++ (Class)layerClass +{ + return [DACircularProgressLayer class]; +} + +- (DACircularProgressLayer *)circularProgressLayer +{ + return (DACircularProgressLayer *)self.layer; +} + +- (id)init +{ + return [super initWithFrame:CGRectMake(0.0f, 0.0f, 40.0f, 40.0f)]; +} + +- (void)didMoveToWindow +{ + CGFloat windowContentsScale = self.window.screen.scale; + self.circularProgressLayer.contentsScale = windowContentsScale; + [self.circularProgressLayer setNeedsDisplay]; +} + +#pragma mark - Progress + +- (CGFloat)progress +{ + return self.circularProgressLayer.progress; +} + +- (void)setProgress:(CGFloat)progress +{ + [self setProgress:progress animated:NO]; +} + +- (void)setProgress:(CGFloat)progress animated:(BOOL)animated +{ + [self.layer removeAnimationForKey:@"indeterminateAnimation"]; + [self.circularProgressLayer removeAnimationForKey:@"progress"]; + + CGFloat pinnedProgress = MIN(MAX(progress, 0.0f), 1.0f); + if (animated) { + CABasicAnimation *animation = [CABasicAnimation animationWithKeyPath:@"progress"]; + animation.duration = fabsf(self.progress - pinnedProgress); // Same duration as UIProgressView animation + animation.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut]; + animation.fromValue = [NSNumber numberWithFloat:self.progress]; + animation.toValue = [NSNumber numberWithFloat:pinnedProgress]; + [self.circularProgressLayer addAnimation:animation forKey:@"progress"]; + } else { + [self.circularProgressLayer setNeedsDisplay]; + } + self.circularProgressLayer.progress = pinnedProgress; +} + +#pragma mark - UIAppearance methods + +- (UIColor *)trackTintColor +{ + return self.circularProgressLayer.trackTintColor; +} + +- (void)setTrackTintColor:(UIColor *)trackTintColor +{ + self.circularProgressLayer.trackTintColor = trackTintColor; + [self.circularProgressLayer setNeedsDisplay]; +} + +- (UIColor *)progressTintColor +{ + return self.circularProgressLayer.progressTintColor; +} + +- (void)setProgressTintColor:(UIColor *)progressTintColor +{ + self.circularProgressLayer.progressTintColor = progressTintColor; + [self.circularProgressLayer setNeedsDisplay]; +} + +- (NSInteger)roundedCorners +{ + return self.roundedCorners; +} + +- (void)setRoundedCorners:(NSInteger)roundedCorners +{ + self.circularProgressLayer.roundedCorners = roundedCorners; + [self.circularProgressLayer setNeedsDisplay]; +} + +- (CGFloat)thicknessRatio +{ + return self.circularProgressLayer.thicknessRatio; +} + +- (void)setThicknessRatio:(CGFloat)thicknessRatio +{ + self.circularProgressLayer.thicknessRatio = MIN(MAX(thicknessRatio, 0.f), 1.f); + [self.circularProgressLayer setNeedsDisplay]; +} + +- (NSInteger)indeterminate +{ + CAAnimation *spinAnimation = [self.layer animationForKey:@"indeterminateAnimation"]; + return (spinAnimation == nil ? 0 : 1); +} + +- (void)setIndeterminate:(NSInteger)indeterminate +{ + if (indeterminate && !self.indeterminate) { + CABasicAnimation *spinAnimation = [CABasicAnimation animationWithKeyPath:@"transform.rotation"]; + spinAnimation.byValue = [NSNumber numberWithFloat:indeterminate > 0 ? 2.0f*M_PI : -2.0f*M_PI]; + spinAnimation.duration = self.indeterminateDuration; + spinAnimation.repeatCount = HUGE_VALF; + [self.layer addAnimation:spinAnimation forKey:@"indeterminateAnimation"]; + } else { + [self.layer removeAnimationForKey:@"indeterminateAnimation"]; + } +} + +- (NSInteger)clockwiseProgress +{ + return self.circularProgressLayer.clockwiseProgress; +} + +- (void)setClockwiseProgress:(NSInteger)clockwiseProgres +{ + self.circularProgressLayer.clockwiseProgress = clockwiseProgres; + [self.circularProgressLayer setNeedsDisplay]; +} + +@end diff --git a/ios/Pods/DACircularProgress/LICENSE.md b/ios/Pods/DACircularProgress/LICENSE.md new file mode 100755 index 000000000..94d061018 --- /dev/null +++ b/ios/Pods/DACircularProgress/LICENSE.md @@ -0,0 +1,23 @@ +# License + +## MIT License + +Copyright (c) 2013 Daniel Amitay (http://danielamitay.com) + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. \ No newline at end of file diff --git a/ios/Pods/DACircularProgress/README.md b/ios/Pods/DACircularProgress/README.md new file mode 100755 index 000000000..3c400317b --- /dev/null +++ b/ios/Pods/DACircularProgress/README.md @@ -0,0 +1,77 @@ +## DACircularProgress + +`DACircularProgress` is a `UIView` subclass with circular `UIProgressView` properties. + +It was originally built to be an imitation of Facebook's photo progress indicator. + +View the included example project for a demonstration. + +![Screenshot](https://github.com/danielamitay/DACircularProgress/raw/master/screenshot.png) + +## Installation + +To use `DACircularProgress`: + +- Copy over the `DACircularProgress` folder to your project folder. +- Make sure that your project includes ``. +- `#import "DACircularProgressView.h"` + +### Example Code + +```objective-c + +self.progressView = [[DACircularProgressView alloc] initWithFrame:CGRectMake(140.0f, 30.0f, 40.0f, 40.0f)]; +self.progressView.roundedCorners = YES; +self.progressView.trackTintColor = [UIColor clearColor]; +[self.view addSubview:self.progressView]; +``` + +- You can also use Interface Builder by adding a `UIView` element and setting its class to `DACircularProgress` + +## Notes + +### Compatibility + +iOS5.0+ + +### Automatic Reference Counting (ARC) support + +`DACircularProgress` was made with ARC enabled by default. + +## Contact + +- [Personal website](http://danielamitay.com) +- [GitHub](http://github.com/danielamitay) +- [Twitter](http://twitter.com/danielamitay) +- [LinkedIn](http://www.linkedin.com/in/danielamitay) +- [Email](hello@danielamitay.com) + +If you use/enjoy `DACircularProgress`, let me know! + +## Credits + +`DACircularProgress` is brought to you by [Daniel Amitay](http://www.amitay.us) and [contributors to the project](https://github.com/danielamitay/DACircularProgress/contributors). A special thanks to [Cédric Luthi](https://github.com/0xced) for a significant amount of changes. If you have feature suggestions or bug reports, feel free to help out by sending pull requests or by [creating new issues](https://github.com/danielamitay/DACircularProgress/issues/new). + +## License + +### MIT License + +Copyright (c) 2013 Daniel Amitay (http://danielamitay.com) + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. diff --git a/ios/Pods/FMDB/LICENSE.txt b/ios/Pods/FMDB/LICENSE.txt new file mode 100644 index 000000000..1cf79eef4 --- /dev/null +++ b/ios/Pods/FMDB/LICENSE.txt @@ -0,0 +1,24 @@ +If you are using fmdb in your project, I'd love to hear about it. Let me +know at gus@flyingmeat.com. + +In short, this is the MIT License. + +Copyright (c) 2008 Flying Meat Inc. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. \ No newline at end of file diff --git a/ios/Pods/FMDB/README.markdown b/ios/Pods/FMDB/README.markdown new file mode 100644 index 000000000..da05a4c1b --- /dev/null +++ b/ios/Pods/FMDB/README.markdown @@ -0,0 +1,274 @@ +# FMDB v2.3 +This is an Objective-C wrapper around SQLite: http://sqlite.org/ + +## The FMDB Mailing List: +http://groups.google.com/group/fmdb + +## Read the SQLite FAQ: +http://www.sqlite.org/faq.html + +Since FMDB is built on top of SQLite, you're going to want to read this page top to bottom at least once. And while you're there, make sure to bookmark the SQLite Documentation page: http://www.sqlite.org/docs.html + +## Contributing +Do you have an awesome idea that deserves to be in FMDB? You might consider pinging ccgus first to make sure he hasn't already ruled it out for some reason. Otherwise pull requests are great, and make sure you stick to the local coding conventions. However, please be patient and if you haven't heard anything from ccgus for a week or more, you might want to send a note asking what's up. + +## CocoaPods + +[![Dependency Status](https://www.versioneye.com/objective-c/fmdb/2.3/badge.svg?style=flat)](https://www.versioneye.com/objective-c/fmdb/2.3) +[![Reference Status](https://www.versioneye.com/objective-c/fmdb/reference_badge.svg?style=flat)](https://www.versioneye.com/objective-c/fmdb/references) + +FMDB can be installed using [CocoaPods](http://cocoapods.org/). + +``` +pod 'FMDB' +# pod 'FMDB/SQLCipher' # If using FMDB with SQLCipher +``` + +**If using FMDB with [SQLCipher](http://sqlcipher.net/) you must use the FMDB/SQLCipher subspec. The FMDB/SQLCipher subspec declares SQLCipher as a dependency, allowing FMDB to be compiled with the `-DSQLITE_HAS_CODEC` flag.** + +## FMDB Class Reference: +http://ccgus.github.io/fmdb/html/index.html + +## Automatic Reference Counting (ARC) or Manual Memory Management? +You can use either style in your Cocoa project. FMDB Will figure out which you are using at compile time and do the right thing. + +## Usage +There are three main classes in FMDB: + +1. `FMDatabase` - Represents a single SQLite database. Used for executing SQL statements. +2. `FMResultSet` - Represents the results of executing a query on an `FMDatabase`. +3. `FMDatabaseQueue` - If you're wanting to perform queries and updates on multiple threads, you'll want to use this class. It's described in the "Thread Safety" section below. + +### Database Creation +An `FMDatabase` is created with a path to a SQLite database file. This path can be one of these three: + +1. A file system path. The file does not have to exist on disk. If it does not exist, it is created for you. +2. An empty string (`@""`). An empty database is created at a temporary location. This database is deleted with the `FMDatabase` connection is closed. +3. `NULL`. An in-memory database is created. This database will be destroyed with the `FMDatabase` connection is closed. + +(For more information on temporary and in-memory databases, read the sqlite documentation on the subject: http://www.sqlite.org/inmemorydb.html) + + FMDatabase *db = [FMDatabase databaseWithPath:@"/tmp/tmp.db"]; + +### Opening + +Before you can interact with the database, it must be opened. Opening fails if there are insufficient resources or permissions to open and/or create the database. + + if (![db open]) { + [db release]; + return; + } + +### Executing Updates + +Any sort of SQL statement which is not a `SELECT` statement qualifies as an update. This includes `CREATE`, `UPDATE`, `INSERT`, `ALTER`, `COMMIT`, `BEGIN`, `DETACH`, `DELETE`, `DROP`, `END`, `EXPLAIN`, `VACUUM`, and `REPLACE` statements (plus many more). Basically, if your SQL statement does not begin with `SELECT`, it is an update statement. + +Executing updates returns a single value, a `BOOL`. A return value of `YES` means the update was successfully executed, and a return value of `NO` means that some error was encountered. You may invoke the `-lastErrorMessage` and `-lastErrorCode` methods to retrieve more information. + +### Executing Queries + +A `SELECT` statement is a query and is executed via one of the `-executeQuery...` methods. + +Executing queries returns an `FMResultSet` object if successful, and `nil` upon failure. Like executing updates, there is a variant that accepts an `NSError **` parameter. Otherwise you should use the `-lastErrorMessage` and `-lastErrorCode` methods to determine why a query failed. + +In order to iterate through the results of your query, you use a `while()` loop. You also need to "step" from one record to the other. With FMDB, the easiest way to do that is like this: + + FMResultSet *s = [db executeQuery:@"SELECT * FROM myTable"]; + while ([s next]) { + //retrieve values for each record + } + +You must always invoke `-[FMResultSet next]` before attempting to access the values returned in a query, even if you're only expecting one: + + FMResultSet *s = [db executeQuery:@"SELECT COUNT(*) FROM myTable"]; + if ([s next]) { + int totalCount = [s intForColumnIndex:0]; + } + +`FMResultSet` has many methods to retrieve data in an appropriate format: + +- `intForColumn:` +- `longForColumn:` +- `longLongIntForColumn:` +- `boolForColumn:` +- `doubleForColumn:` +- `stringForColumn:` +- `dateForColumn:` +- `dataForColumn:` +- `dataNoCopyForColumn:` +- `UTF8StringForColumnName:` +- `objectForColumnName:` + +Each of these methods also has a `{type}ForColumnIndex:` variant that is used to retrieve the data based on the position of the column in the results, as opposed to the column's name. + +Typically, there's no need to `-close` an `FMResultSet` yourself, since that happens when either the result set is deallocated, or the parent database is closed. + +### Closing + +When you have finished executing queries and updates on the database, you should `-close` the `FMDatabase` connection so that SQLite will relinquish any resources it has acquired during the course of its operation. + + [db close]; + +### Transactions + +`FMDatabase` can begin and commit a transaction by invoking one of the appropriate methods or executing a begin/end transaction statement. + +### Multiple Statements and Batch Stuff + +You can use `FMDatabase`'s executeStatements:withResultBlock: to do multiple statements in a string: + +``` +NSString *sql = @"create table bulktest1 (id integer primary key autoincrement, x text);" + "create table bulktest2 (id integer primary key autoincrement, y text);" + "create table bulktest3 (id integer primary key autoincrement, z text);" + "insert into bulktest1 (x) values ('XXX');" + "insert into bulktest2 (y) values ('YYY');" + "insert into bulktest3 (z) values ('ZZZ');"; + +success = [db executeStatements:sql]; + +sql = @"select count(*) as count from bulktest1;" + "select count(*) as count from bulktest2;" + "select count(*) as count from bulktest3;"; + +success = [self.db executeStatements:sql withResultBlock:^int(NSDictionary *dictionary) { + NSInteger count = [dictionary[@"count"] integerValue]; + XCTAssertEqual(count, 1, @"expected one record for dictionary %@", dictionary); + return 0; +}]; + +``` + +### Data Sanitization + +When providing a SQL statement to FMDB, you should not attempt to "sanitize" any values before insertion. Instead, you should use the standard SQLite binding syntax: + + INSERT INTO myTable VALUES (?, ?, ?) + +The `?` character is recognized by SQLite as a placeholder for a value to be inserted. The execution methods all accept a variable number of arguments (or a representation of those arguments, such as an `NSArray`, `NSDictionary`, or a `va_list`), which are properly escaped for you. + +Alternatively, you may use named parameters syntax: + + INSERT INTO myTable VALUES (:id, :name, :value) + +The parameters *must* start with a colon. SQLite itself supports other characters, but internally the Dictionary keys are prefixed with a colon, do **not** include the colon in your dictionary keys. + + NSDictionary *argsDict = [NSDictionary dictionaryWithObjectsAndKeys:@"My Name", @"name", nil]; + [db executeUpdate:@"INSERT INTO myTable (name) VALUES (:name)" withParameterDictionary:argsDict]; + +Thus, you SHOULD NOT do this (or anything like this): + + [db executeUpdate:[NSString stringWithFormat:@"INSERT INTO myTable VALUES (%@)", @"this has \" lots of ' bizarre \" quotes '"]]; + +Instead, you SHOULD do: + + [db executeUpdate:@"INSERT INTO myTable VALUES (?)", @"this has \" lots of ' bizarre \" quotes '"]; + +All arguments provided to the `-executeUpdate:` method (or any of the variants that accept a `va_list` as a parameter) must be objects. The following will not work (and will result in a crash): + + [db executeUpdate:@"INSERT INTO myTable VALUES (?)", 42]; + +The proper way to insert a number is to box it in an `NSNumber` object: + + [db executeUpdate:@"INSERT INTO myTable VALUES (?)", [NSNumber numberWithInt:42]]; + +Alternatively, you can use the `-execute*WithFormat:` variant to use `NSString`-style substitution: + + [db executeUpdateWithFormat:@"INSERT INTO myTable VALUES (%d)", 42]; + +Internally, the `-execute*WithFormat:` methods are properly boxing things for you. The following percent modifiers are recognized: `%@`, `%c`, `%s`, `%d`, `%D`, `%i`, `%u`, `%U`, `%hi`, `%hu`, `%qi`, `%qu`, `%f`, `%g`, `%ld`, `%lu`, `%lld`, and `%llu`. Using a modifier other than those will have unpredictable results. If, for some reason, you need the `%` character to appear in your SQL statement, you should use `%%`. + + +

Using FMDatabaseQueue and Thread Safety.

+ +Using a single instance of FMDatabase from multiple threads at once is a bad idea. It has always been OK to make a FMDatabase object *per thread*. Just don't share a single instance across threads, and definitely not across multiple threads at the same time. Bad things will eventually happen and you'll eventually get something to crash, or maybe get an exception, or maybe meteorites will fall out of the sky and hit your Mac Pro. *This would suck*. + +**So don't instantiate a single FMDatabase object and use it across multiple threads.** + +Instead, use FMDatabaseQueue. It's your friend and it's here to help. Here's how to use it: + +First, make your queue. + + FMDatabaseQueue *queue = [FMDatabaseQueue databaseQueueWithPath:aPath]; + +Then use it like so: + + [queue inDatabase:^(FMDatabase *db) { + [db executeUpdate:@"INSERT INTO myTable VALUES (?)", [NSNumber numberWithInt:1]]; + [db executeUpdate:@"INSERT INTO myTable VALUES (?)", [NSNumber numberWithInt:2]]; + [db executeUpdate:@"INSERT INTO myTable VALUES (?)", [NSNumber numberWithInt:3]]; + + FMResultSet *rs = [db executeQuery:@"select * from foo"]; + while ([rs next]) { + … + } + }]; + +An easy way to wrap things up in a transaction can be done like this: + + [queue inTransaction:^(FMDatabase *db, BOOL *rollback) { + [db executeUpdate:@"INSERT INTO myTable VALUES (?)", [NSNumber numberWithInt:1]]; + [db executeUpdate:@"INSERT INTO myTable VALUES (?)", [NSNumber numberWithInt:2]]; + [db executeUpdate:@"INSERT INTO myTable VALUES (?)", [NSNumber numberWithInt:3]]; + + if (whoopsSomethingWrongHappened) { + *rollback = YES; + return; + } + // etc… + [db executeUpdate:@"INSERT INTO myTable VALUES (?)", [NSNumber numberWithInt:4]]; + }]; + + +FMDatabaseQueue will run the blocks on a serialized queue (hence the name of the class). So if you call FMDatabaseQueue's methods from multiple threads at the same time, they will be executed in the order they are received. This way queries and updates won't step on each other's toes, and every one is happy. + +**Note:** The calls to FMDatabaseQueue's methods are blocking. So even though you are passing along blocks, they will **not** be run on another thread. + +## Making custom sqlite functions, based on blocks. + +You can do this! For an example, look for "makeFunctionNamed:" in main.m + +## History + +The history and changes are availbe on its [GitHub page](https://github.com/ccgus/fmdb) and are summarized in the "CHANGES_AND_TODO_LIST.txt" file. + +## Contributors + +The contributors to FMDB are contained in the "Contributors.txt" file. + +## Additional projects using FMDB, which might be interesting to the discerning developer. + + * FMDBMigrationManager, A SQLite schema migration management system for FMDB: https://github.com/layerhq/FMDBMigrationManager + * FCModel, An alternative to Core Data for people who like having direct SQL access: https://github.com/marcoarment/FCModel + +## Quick notes on FMDB's coding style + +Spaces, not tabs. Square brackets, not dot notation. Look at what FMDB already does with curly brackets and such, and stick to that style. + +## Reporting bugs + +Reduce your bug down to the smallest amount of code possible. You want to make it super easy for the developers to see and reproduce your bug. If it helps, pretend that the person who can fix your bug is active on shipping 3 major products, works on a handful of open source projects, has a newborn baby, and is generally very very busy. + +And we've even added a template function to main.m (FMDBReportABugFunction) in the FMDB distribution to help you out: + +* Open up fmdb project in Xcode. +* Open up main.m and modify the FMDBReportABugFunction to reproduce your bug. + * Setup your table(s) in the code. + * Make your query or update(s). + * Add some assertions which demonstrate the bug. + +Then you can bring it up on the FMDB mailing list by showing your nice and compact FMDBReportABugFunction, or you can report the bug via the github FMDB bug reporter. + +**Optional:** + +Figure out where the bug is, fix it, and send a patch in or bring that up on the mailing list. Make sure all the other tests run after your modifications. + +## Support + +The support channels for FMDB are the mailing list (see above), filing a bug here, or maybe on Stack Overflow. So that is to say, support is provided by the community and on a voluntary basis. + +FMDB development is overseen by Gus Mueller of Flying Meat. If FMDB been helpful to you, consider purchasing an app from FM or telling all your friends about it. + +## License + +The license for FMDB is contained in the "License.txt" file. diff --git a/ios/Pods/FMDB/src/fmdb/FMDB.h b/ios/Pods/FMDB/src/fmdb/FMDB.h new file mode 100644 index 000000000..39e2f4312 --- /dev/null +++ b/ios/Pods/FMDB/src/fmdb/FMDB.h @@ -0,0 +1,5 @@ +#import "FMDatabase.h" +#import "FMResultSet.h" +#import "FMDatabaseAdditions.h" +#import "FMDatabaseQueue.h" +#import "FMDatabasePool.h" diff --git a/ios/Pods/FMDB/src/fmdb/FMDatabase.h b/ios/Pods/FMDB/src/fmdb/FMDatabase.h new file mode 100644 index 000000000..ab3b6966e --- /dev/null +++ b/ios/Pods/FMDB/src/fmdb/FMDatabase.h @@ -0,0 +1,1079 @@ +#import +#import "sqlite3.h" +#import "FMResultSet.h" +#import "FMDatabasePool.h" + + +#if ! __has_feature(objc_arc) + #define FMDBAutorelease(__v) ([__v autorelease]); + #define FMDBReturnAutoreleased FMDBAutorelease + + #define FMDBRetain(__v) ([__v retain]); + #define FMDBReturnRetained FMDBRetain + + #define FMDBRelease(__v) ([__v release]); + + #define FMDBDispatchQueueRelease(__v) (dispatch_release(__v)); +#else + // -fobjc-arc + #define FMDBAutorelease(__v) + #define FMDBReturnAutoreleased(__v) (__v) + + #define FMDBRetain(__v) + #define FMDBReturnRetained(__v) (__v) + + #define FMDBRelease(__v) + +// If OS_OBJECT_USE_OBJC=1, then the dispatch objects will be treated like ObjC objects +// and will participate in ARC. +// See the section on "Dispatch Queues and Automatic Reference Counting" in "Grand Central Dispatch (GCD) Reference" for details. + #if OS_OBJECT_USE_OBJC + #define FMDBDispatchQueueRelease(__v) + #else + #define FMDBDispatchQueueRelease(__v) (dispatch_release(__v)); + #endif +#endif + +#if !__has_feature(objc_instancetype) + #define instancetype id +#endif + + +typedef int(^FMDBExecuteStatementsCallbackBlock)(NSDictionary *resultsDictionary); + + +/** A SQLite ([http://sqlite.org/](http://sqlite.org/)) Objective-C wrapper. + + ### Usage + The three main classes in FMDB are: + + - `FMDatabase` - Represents a single SQLite database. Used for executing SQL statements. + - `` - Represents the results of executing a query on an `FMDatabase`. + - `` - If you want to perform queries and updates on multiple threads, you'll want to use this class. + + ### See also + + - `` - A pool of `FMDatabase` objects. + - `` - A wrapper for `sqlite_stmt`. + + ### External links + + - [FMDB on GitHub](https://github.com/ccgus/fmdb) including introductory documentation + - [SQLite web site](http://sqlite.org/) + - [FMDB mailing list](http://groups.google.com/group/fmdb) + - [SQLite FAQ](http://www.sqlite.org/faq.html) + + @warning Do not instantiate a single `FMDatabase` object and use it across multiple threads. Instead, use ``. + + */ + +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wobjc-interface-ivars" + + +@interface FMDatabase : NSObject { + + sqlite3* _db; + NSString* _databasePath; + BOOL _logsErrors; + BOOL _crashOnErrors; + BOOL _traceExecution; + BOOL _checkedOut; + BOOL _shouldCacheStatements; + BOOL _isExecutingStatement; + BOOL _inTransaction; + NSTimeInterval _maxBusyRetryTimeInterval; + NSTimeInterval _startBusyRetryTime; + + NSMutableDictionary *_cachedStatements; + NSMutableSet *_openResultSets; + NSMutableSet *_openFunctions; + + NSDateFormatter *_dateFormat; +} + +///----------------- +/// @name Properties +///----------------- + +/** Whether should trace execution */ + +@property (atomic, assign) BOOL traceExecution; + +/** Whether checked out or not */ + +@property (atomic, assign) BOOL checkedOut; + +/** Crash on errors */ + +@property (atomic, assign) BOOL crashOnErrors; + +/** Logs errors */ + +@property (atomic, assign) BOOL logsErrors; + +/** Dictionary of cached statements */ + +@property (atomic, retain) NSMutableDictionary *cachedStatements; + +///--------------------- +/// @name Initialization +///--------------------- + +/** Create a `FMDatabase` object. + + An `FMDatabase` is created with a path to a SQLite database file. This path can be one of these three: + + 1. A file system path. The file does not have to exist on disk. If it does not exist, it is created for you. + 2. An empty string (`@""`). An empty database is created at a temporary location. This database is deleted with the `FMDatabase` connection is closed. + 3. `nil`. An in-memory database is created. This database will be destroyed with the `FMDatabase` connection is closed. + + For example, to create/open a database in your Mac OS X `tmp` folder: + + FMDatabase *db = [FMDatabase databaseWithPath:@"/tmp/tmp.db"]; + + Or, in iOS, you might open a database in the app's `Documents` directory: + + NSString *docsPath = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES)[0]; + NSString *dbPath = [docsPath stringByAppendingPathComponent:@"test.db"]; + FMDatabase *db = [FMDatabase databaseWithPath:dbPath]; + + (For more information on temporary and in-memory databases, read the sqlite documentation on the subject: [http://www.sqlite.org/inmemorydb.html](http://www.sqlite.org/inmemorydb.html)) + + @param inPath Path of database file + + @return `FMDatabase` object if successful; `nil` if failure. + + */ + ++ (instancetype)databaseWithPath:(NSString*)inPath; + +/** Initialize a `FMDatabase` object. + + An `FMDatabase` is created with a path to a SQLite database file. This path can be one of these three: + + 1. A file system path. The file does not have to exist on disk. If it does not exist, it is created for you. + 2. An empty string (`@""`). An empty database is created at a temporary location. This database is deleted with the `FMDatabase` connection is closed. + 3. `nil`. An in-memory database is created. This database will be destroyed with the `FMDatabase` connection is closed. + + For example, to create/open a database in your Mac OS X `tmp` folder: + + FMDatabase *db = [FMDatabase databaseWithPath:@"/tmp/tmp.db"]; + + Or, in iOS, you might open a database in the app's `Documents` directory: + + NSString *docsPath = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES)[0]; + NSString *dbPath = [docsPath stringByAppendingPathComponent:@"test.db"]; + FMDatabase *db = [FMDatabase databaseWithPath:dbPath]; + + (For more information on temporary and in-memory databases, read the sqlite documentation on the subject: [http://www.sqlite.org/inmemorydb.html](http://www.sqlite.org/inmemorydb.html)) + + @param inPath Path of database file + + @return `FMDatabase` object if successful; `nil` if failure. + + */ + +- (instancetype)initWithPath:(NSString*)inPath; + + +///----------------------------------- +/// @name Opening and closing database +///----------------------------------- + +/** Opening a new database connection + + The database is opened for reading and writing, and is created if it does not already exist. + + @return `YES` if successful, `NO` on error. + + @see [sqlite3_open()](http://sqlite.org/c3ref/open.html) + @see openWithFlags: + @see close + */ + +- (BOOL)open; + +/** Opening a new database connection with flags + + @param flags one of the following three values, optionally combined with the `SQLITE_OPEN_NOMUTEX`, `SQLITE_OPEN_FULLMUTEX`, `SQLITE_OPEN_SHAREDCACHE`, `SQLITE_OPEN_PRIVATECACHE`, and/or `SQLITE_OPEN_URI` flags: + + `SQLITE_OPEN_READONLY` + + The database is opened in read-only mode. If the database does not already exist, an error is returned. + + `SQLITE_OPEN_READWRITE` + + The database is opened for reading and writing if possible, or reading only if the file is write protected by the operating system. In either case the database must already exist, otherwise an error is returned. + + `SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE` + + The database is opened for reading and writing, and is created if it does not already exist. This is the behavior that is always used for `open` method. + + @return `YES` if successful, `NO` on error. + + @see [sqlite3_open_v2()](http://sqlite.org/c3ref/open.html) + @see open + @see close + */ + +#if SQLITE_VERSION_NUMBER >= 3005000 +- (BOOL)openWithFlags:(int)flags; +#endif + +/** Closing a database connection + + @return `YES` if success, `NO` on error. + + @see [sqlite3_close()](http://sqlite.org/c3ref/close.html) + @see open + @see openWithFlags: + */ + +- (BOOL)close; + +/** Test to see if we have a good connection to the database. + + This will confirm whether: + + - is database open + - if open, it will try a simple SELECT statement and confirm that it succeeds. + + @return `YES` if everything succeeds, `NO` on failure. + */ + +- (BOOL)goodConnection; + + +///---------------------- +/// @name Perform updates +///---------------------- + +/** Execute single update statement + + This method executes a single SQL update statement (i.e. any SQL that does not return results, such as `UPDATE`, `INSERT`, or `DELETE`. This method employs [`sqlite3_prepare_v2`](http://sqlite.org/c3ref/prepare.html), [`sqlite3_bind`](http://sqlite.org/c3ref/bind_blob.html) to bind values to `?` placeholders in the SQL with the optional list of parameters, and [`sqlite_step`](http://sqlite.org/c3ref/step.html) to perform the update. + + The optional values provided to this method should be objects (e.g. `NSString`, `NSNumber`, `NSNull`, `NSDate`, and `NSData` objects), not fundamental data types (e.g. `int`, `long`, `NSInteger`, etc.). This method automatically handles the aforementioned object types, and all other object types will be interpreted as text values using the object's `description` method. + + @param sql The SQL to be performed, with optional `?` placeholders. + + @param outErr A reference to the `NSError` pointer to be updated with an auto released `NSError` object if an error if an error occurs. If `nil`, no `NSError` object will be returned. + + @param ... Optional parameters to bind to `?` placeholders in the SQL statement. These should be Objective-C objects (e.g. `NSString`, `NSNumber`, etc.), not fundamental C data types (e.g. `int`, `char *`, etc.). + + @return `YES` upon success; `NO` upon failure. If failed, you can call ``, ``, or `` for diagnostic information regarding the failure. + + @see lastError + @see lastErrorCode + @see lastErrorMessage + @see [`sqlite3_bind`](http://sqlite.org/c3ref/bind_blob.html) + */ + +- (BOOL)executeUpdate:(NSString*)sql withErrorAndBindings:(NSError**)outErr, ...; + +/** Execute single update statement + + @see executeUpdate:withErrorAndBindings: + + @warning **Deprecated**: Please use `` instead. + */ + +- (BOOL)update:(NSString*)sql withErrorAndBindings:(NSError**)outErr, ... __attribute__ ((deprecated)); + +/** Execute single update statement + + This method executes a single SQL update statement (i.e. any SQL that does not return results, such as `UPDATE`, `INSERT`, or `DELETE`. This method employs [`sqlite3_prepare_v2`](http://sqlite.org/c3ref/prepare.html), [`sqlite3_bind`](http://sqlite.org/c3ref/bind_blob.html) to bind values to `?` placeholders in the SQL with the optional list of parameters, and [`sqlite_step`](http://sqlite.org/c3ref/step.html) to perform the update. + + The optional values provided to this method should be objects (e.g. `NSString`, `NSNumber`, `NSNull`, `NSDate`, and `NSData` objects), not fundamental data types (e.g. `int`, `long`, `NSInteger`, etc.). This method automatically handles the aforementioned object types, and all other object types will be interpreted as text values using the object's `description` method. + + @param sql The SQL to be performed, with optional `?` placeholders. + + @param ... Optional parameters to bind to `?` placeholders in the SQL statement. These should be Objective-C objects (e.g. `NSString`, `NSNumber`, etc.), not fundamental C data types (e.g. `int`, `char *`, etc.). + + @return `YES` upon success; `NO` upon failure. If failed, you can call ``, ``, or `` for diagnostic information regarding the failure. + + @see lastError + @see lastErrorCode + @see lastErrorMessage + @see [`sqlite3_bind`](http://sqlite.org/c3ref/bind_blob.html) + + @note This technique supports the use of `?` placeholders in the SQL, automatically binding any supplied value parameters to those placeholders. This approach is more robust than techniques that entail using `stringWithFormat` to manually build SQL statements, which can be problematic if the values happened to include any characters that needed to be quoted. + */ + +- (BOOL)executeUpdate:(NSString*)sql, ...; + +/** Execute single update statement + + This method executes a single SQL update statement (i.e. any SQL that does not return results, such as `UPDATE`, `INSERT`, or `DELETE`. This method employs [`sqlite3_prepare_v2`](http://sqlite.org/c3ref/prepare.html) and [`sqlite_step`](http://sqlite.org/c3ref/step.html) to perform the update. Unlike the other `executeUpdate` methods, this uses printf-style formatters (e.g. `%s`, `%d`, etc.) to build the SQL. Do not use `?` placeholders in the SQL if you use this method. + + @param format The SQL to be performed, with `printf`-style escape sequences. + + @param ... Optional parameters to bind to use in conjunction with the `printf`-style escape sequences in the SQL statement. + + @return `YES` upon success; `NO` upon failure. If failed, you can call ``, ``, or `` for diagnostic information regarding the failure. + + @see executeUpdate: + @see lastError + @see lastErrorCode + @see lastErrorMessage + + @note This method does not technically perform a traditional printf-style replacement. What this method actually does is replace the printf-style percent sequences with a SQLite `?` placeholder, and then bind values to that placeholder. Thus the following command + + [db executeUpdateWithFormat:@"INSERT INTO test (name) VALUES (%@)", @"Gus"]; + + is actually replacing the `%@` with `?` placeholder, and then performing something equivalent to `` + + [db executeUpdate:@"INSERT INTO test (name) VALUES (?)", @"Gus"]; + + There are two reasons why this distinction is important. First, the printf-style escape sequences can only be used where it is permissible to use a SQLite `?` placeholder. You can use it only for values in SQL statements, but not for table names or column names or any other non-value context. This method also cannot be used in conjunction with `pragma` statements and the like. Second, note the lack of quotation marks in the SQL. The `VALUES` clause was _not_ `VALUES ('%@')` (like you might have to do if you built a SQL statement using `NSString` method `stringWithFormat`), but rather simply `VALUES (%@)`. + */ + +- (BOOL)executeUpdateWithFormat:(NSString *)format, ... NS_FORMAT_FUNCTION(1,2); + +/** Execute single update statement + + This method executes a single SQL update statement (i.e. any SQL that does not return results, such as `UPDATE`, `INSERT`, or `DELETE`. This method employs [`sqlite3_prepare_v2`](http://sqlite.org/c3ref/prepare.html) and [`sqlite3_bind`](http://sqlite.org/c3ref/bind_blob.html) binding any `?` placeholders in the SQL with the optional list of parameters. + + The optional values provided to this method should be objects (e.g. `NSString`, `NSNumber`, `NSNull`, `NSDate`, and `NSData` objects), not fundamental data types (e.g. `int`, `long`, `NSInteger`, etc.). This method automatically handles the aforementioned object types, and all other object types will be interpreted as text values using the object's `description` method. + + @param sql The SQL to be performed, with optional `?` placeholders. + + @param arguments A `NSArray` of objects to be used when binding values to the `?` placeholders in the SQL statement. + + @return `YES` upon success; `NO` upon failure. If failed, you can call ``, ``, or `` for diagnostic information regarding the failure. + + @see lastError + @see lastErrorCode + @see lastErrorMessage + */ + +- (BOOL)executeUpdate:(NSString*)sql withArgumentsInArray:(NSArray *)arguments; + +/** Execute single update statement + + This method executes a single SQL update statement (i.e. any SQL that does not return results, such as `UPDATE`, `INSERT`, or `DELETE`. This method employs [`sqlite3_prepare_v2`](http://sqlite.org/c3ref/prepare.html) and [`sqlite_step`](http://sqlite.org/c3ref/step.html) to perform the update. Unlike the other `executeUpdate` methods, this uses printf-style formatters (e.g. `%s`, `%d`, etc.) to build the SQL. + + The optional values provided to this method should be objects (e.g. `NSString`, `NSNumber`, `NSNull`, `NSDate`, and `NSData` objects), not fundamental data types (e.g. `int`, `long`, `NSInteger`, etc.). This method automatically handles the aforementioned object types, and all other object types will be interpreted as text values using the object's `description` method. + + @param sql The SQL to be performed, with optional `?` placeholders. + + @param arguments A `NSDictionary` of objects keyed by column names that will be used when binding values to the `?` placeholders in the SQL statement. + + @return `YES` upon success; `NO` upon failure. If failed, you can call ``, ``, or `` for diagnostic information regarding the failure. + + @see lastError + @see lastErrorCode + @see lastErrorMessage +*/ + +- (BOOL)executeUpdate:(NSString*)sql withParameterDictionary:(NSDictionary *)arguments; + + +/** Execute single update statement + + This method executes a single SQL update statement (i.e. any SQL that does not return results, such as `UPDATE`, `INSERT`, or `DELETE`. This method employs [`sqlite3_prepare_v2`](http://sqlite.org/c3ref/prepare.html) and [`sqlite_step`](http://sqlite.org/c3ref/step.html) to perform the update. Unlike the other `executeUpdate` methods, this uses printf-style formatters (e.g. `%s`, `%d`, etc.) to build the SQL. + + The optional values provided to this method should be objects (e.g. `NSString`, `NSNumber`, `NSNull`, `NSDate`, and `NSData` objects), not fundamental data types (e.g. `int`, `long`, `NSInteger`, etc.). This method automatically handles the aforementioned object types, and all other object types will be interpreted as text values using the object's `description` method. + + @param sql The SQL to be performed, with optional `?` placeholders. + + @param args A `va_list` of arguments. + + @return `YES` upon success; `NO` upon failure. If failed, you can call ``, ``, or `` for diagnostic information regarding the failure. + + @see lastError + @see lastErrorCode + @see lastErrorMessage + */ + +- (BOOL)executeUpdate:(NSString*)sql withVAList: (va_list)args; + +/** Execute multiple SQL statements + + This executes a series of SQL statements that are combined in a single string (e.g. the SQL generated by the `sqlite3` command line `.dump` command). This accepts no value parameters, but rather simply expects a single string with multiple SQL statements, each terminated with a semicolon. This uses `sqlite3_exec`. + + @param sql The SQL to be performed + + @return `YES` upon success; `NO` upon failure. If failed, you can call ``, ``, or `` for diagnostic information regarding the failure. + + @see executeStatements:withResultBlock: + @see [sqlite3_exec()](http://sqlite.org/c3ref/exec.html) + + */ + +- (BOOL)executeStatements:(NSString *)sql; + +/** Execute multiple SQL statements with callback handler + + This executes a series of SQL statements that are combined in a single string (e.g. the SQL generated by the `sqlite3` command line `.dump` command). This accepts no value parameters, but rather simply expects a single string with multiple SQL statements, each terminated with a semicolon. This uses `sqlite3_exec`. + + @param sql The SQL to be performed. + @param block A block that will be called for any result sets returned by any SQL statements. + Note, if you supply this block, it must return integer value, zero upon success (this would be a good opportunity to use SQLITE_OK), + non-zero value upon failure (which will stop the bulk execution of the SQL). If a statement returns values, the block will be called with the results from the query in NSDictionary *resultsDictionary. + This may be `nil` if you don't care to receive any results. + + @return `YES` upon success; `NO` upon failure. If failed, you can call ``, + ``, or `` for diagnostic information regarding the failure. + + @see executeStatements: + @see [sqlite3_exec()](http://sqlite.org/c3ref/exec.html) + + */ + +- (BOOL)executeStatements:(NSString *)sql withResultBlock:(FMDBExecuteStatementsCallbackBlock)block; + +/** Last insert rowid + + Each entry in an SQLite table has a unique 64-bit signed integer key called the "rowid". The rowid is always available as an undeclared column named `ROWID`, `OID`, or `_ROWID_` as long as those names are not also used by explicitly declared columns. If the table has a column of type `INTEGER PRIMARY KEY` then that column is another alias for the rowid. + + This routine returns the rowid of the most recent successful `INSERT` into the database from the database connection in the first argument. As of SQLite version 3.7.7, this routines records the last insert rowid of both ordinary tables and virtual tables. If no successful `INSERT`s have ever occurred on that database connection, zero is returned. + + @return The rowid of the last inserted row. + + @see [sqlite3_last_insert_rowid()](http://sqlite.org/c3ref/last_insert_rowid.html) + + */ + +- (sqlite_int64)lastInsertRowId; + +/** The number of rows changed by prior SQL statement. + + This function returns the number of database rows that were changed or inserted or deleted by the most recently completed SQL statement on the database connection specified by the first parameter. Only changes that are directly specified by the INSERT, UPDATE, or DELETE statement are counted. + + @return The number of rows changed by prior SQL statement. + + @see [sqlite3_changes()](http://sqlite.org/c3ref/changes.html) + + */ + +- (int)changes; + + +///------------------------- +/// @name Retrieving results +///------------------------- + +/** Execute select statement + + Executing queries returns an `` object if successful, and `nil` upon failure. Like executing updates, there is a variant that accepts an `NSError **` parameter. Otherwise you should use the `` and `` methods to determine why a query failed. + + In order to iterate through the results of your query, you use a `while()` loop. You also need to "step" (via `<[FMResultSet next]>`) from one record to the other. + + This method employs [`sqlite3_bind`](http://sqlite.org/c3ref/bind_blob.html) for any optional value parameters. This properly escapes any characters that need escape sequences (e.g. quotation marks), which eliminates simple SQL errors as well as protects against SQL injection attacks. This method natively handles `NSString`, `NSNumber`, `NSNull`, `NSDate`, and `NSData` objects. All other object types will be interpreted as text values using the object's `description` method. + + @param sql The SELECT statement to be performed, with optional `?` placeholders. + + @param ... Optional parameters to bind to `?` placeholders in the SQL statement. These should be Objective-C objects (e.g. `NSString`, `NSNumber`, etc.), not fundamental C data types (e.g. `int`, `char *`, etc.). + + @return A `` for the result set upon success; `nil` upon failure. If failed, you can call ``, ``, or `` for diagnostic information regarding the failure. + + @see FMResultSet + @see [`FMResultSet next`](<[FMResultSet next]>) + @see [`sqlite3_bind`](http://sqlite.org/c3ref/bind_blob.html) + */ + +- (FMResultSet *)executeQuery:(NSString*)sql, ...; + +/** Execute select statement + + Executing queries returns an `` object if successful, and `nil` upon failure. Like executing updates, there is a variant that accepts an `NSError **` parameter. Otherwise you should use the `` and `` methods to determine why a query failed. + + In order to iterate through the results of your query, you use a `while()` loop. You also need to "step" (via `<[FMResultSet next]>`) from one record to the other. + + @param format The SQL to be performed, with `printf`-style escape sequences. + + @param ... Optional parameters to bind to use in conjunction with the `printf`-style escape sequences in the SQL statement. + + @return A `` for the result set upon success; `nil` upon failure. If failed, you can call ``, ``, or `` for diagnostic information regarding the failure. + + @see executeQuery: + @see FMResultSet + @see [`FMResultSet next`](<[FMResultSet next]>) + + @note This method does not technically perform a traditional printf-style replacement. What this method actually does is replace the printf-style percent sequences with a SQLite `?` placeholder, and then bind values to that placeholder. Thus the following command + + [db executeQueryWithFormat:@"SELECT * FROM test WHERE name=%@", @"Gus"]; + + is actually replacing the `%@` with `?` placeholder, and then performing something equivalent to `` + + [db executeQuery:@"SELECT * FROM test WHERE name=?", @"Gus"]; + + There are two reasons why this distinction is important. First, the printf-style escape sequences can only be used where it is permissible to use a SQLite `?` placeholder. You can use it only for values in SQL statements, but not for table names or column names or any other non-value context. This method also cannot be used in conjunction with `pragma` statements and the like. Second, note the lack of quotation marks in the SQL. The `WHERE` clause was _not_ `WHERE name='%@'` (like you might have to do if you built a SQL statement using `NSString` method `stringWithFormat`), but rather simply `WHERE name=%@`. + + */ + +- (FMResultSet *)executeQueryWithFormat:(NSString*)format, ... NS_FORMAT_FUNCTION(1,2); + +/** Execute select statement + + Executing queries returns an `` object if successful, and `nil` upon failure. Like executing updates, there is a variant that accepts an `NSError **` parameter. Otherwise you should use the `` and `` methods to determine why a query failed. + + In order to iterate through the results of your query, you use a `while()` loop. You also need to "step" (via `<[FMResultSet next]>`) from one record to the other. + + @param sql The SELECT statement to be performed, with optional `?` placeholders. + + @param arguments A `NSArray` of objects to be used when binding values to the `?` placeholders in the SQL statement. + + @return A `` for the result set upon success; `nil` upon failure. If failed, you can call ``, ``, or `` for diagnostic information regarding the failure. + + @see FMResultSet + @see [`FMResultSet next`](<[FMResultSet next]>) + */ + +- (FMResultSet *)executeQuery:(NSString *)sql withArgumentsInArray:(NSArray *)arguments; + +/** Execute select statement + + Executing queries returns an `` object if successful, and `nil` upon failure. Like executing updates, there is a variant that accepts an `NSError **` parameter. Otherwise you should use the `` and `` methods to determine why a query failed. + + In order to iterate through the results of your query, you use a `while()` loop. You also need to "step" (via `<[FMResultSet next]>`) from one record to the other. + + @param sql The SELECT statement to be performed, with optional `?` placeholders. + + @param arguments A `NSDictionary` of objects keyed by column names that will be used when binding values to the `?` placeholders in the SQL statement. + + @return A `` for the result set upon success; `nil` upon failure. If failed, you can call ``, ``, or `` for diagnostic information regarding the failure. + + @see FMResultSet + @see [`FMResultSet next`](<[FMResultSet next]>) + */ + +- (FMResultSet *)executeQuery:(NSString *)sql withParameterDictionary:(NSDictionary *)arguments; + + +// Documentation forthcoming. +- (FMResultSet *)executeQuery:(NSString*)sql withVAList: (va_list)args; + +///------------------- +/// @name Transactions +///------------------- + +/** Begin a transaction + + @return `YES` on success; `NO` on failure. If failed, you can call ``, ``, or `` for diagnostic information regarding the failure. + + @see commit + @see rollback + @see beginDeferredTransaction + @see inTransaction + */ + +- (BOOL)beginTransaction; + +/** Begin a deferred transaction + + @return `YES` on success; `NO` on failure. If failed, you can call ``, ``, or `` for diagnostic information regarding the failure. + + @see commit + @see rollback + @see beginTransaction + @see inTransaction + */ + +- (BOOL)beginDeferredTransaction; + +/** Commit a transaction + + Commit a transaction that was initiated with either `` or with ``. + + @return `YES` on success; `NO` on failure. If failed, you can call ``, ``, or `` for diagnostic information regarding the failure. + + @see beginTransaction + @see beginDeferredTransaction + @see rollback + @see inTransaction + */ + +- (BOOL)commit; + +/** Rollback a transaction + + Rollback a transaction that was initiated with either `` or with ``. + + @return `YES` on success; `NO` on failure. If failed, you can call ``, ``, or `` for diagnostic information regarding the failure. + + @see beginTransaction + @see beginDeferredTransaction + @see commit + @see inTransaction + */ + +- (BOOL)rollback; + +/** Identify whether currently in a transaction or not + + @return `YES` if currently within transaction; `NO` if not. + + @see beginTransaction + @see beginDeferredTransaction + @see commit + @see rollback + */ + +- (BOOL)inTransaction; + + +///---------------------------------------- +/// @name Cached statements and result sets +///---------------------------------------- + +/** Clear cached statements */ + +- (void)clearCachedStatements; + +/** Close all open result sets */ + +- (void)closeOpenResultSets; + +/** Whether database has any open result sets + + @return `YES` if there are open result sets; `NO` if not. + */ + +- (BOOL)hasOpenResultSets; + +/** Return whether should cache statements or not + + @return `YES` if should cache statements; `NO` if not. + */ + +- (BOOL)shouldCacheStatements; + +/** Set whether should cache statements or not + + @param value `YES` if should cache statements; `NO` if not. + */ + +- (void)setShouldCacheStatements:(BOOL)value; + + +///------------------------- +/// @name Encryption methods +///------------------------- + +/** Set encryption key. + + @param key The key to be used. + + @return `YES` if success, `NO` on error. + + @see http://www.sqlite-encrypt.com/develop-guide.htm + + @warning You need to have purchased the sqlite encryption extensions for this method to work. + */ + +- (BOOL)setKey:(NSString*)key; + +/** Reset encryption key + + @param key The key to be used. + + @return `YES` if success, `NO` on error. + + @see http://www.sqlite-encrypt.com/develop-guide.htm + + @warning You need to have purchased the sqlite encryption extensions for this method to work. + */ + +- (BOOL)rekey:(NSString*)key; + +/** Set encryption key using `keyData`. + + @param keyData The `NSData` to be used. + + @return `YES` if success, `NO` on error. + + @see http://www.sqlite-encrypt.com/develop-guide.htm + + @warning You need to have purchased the sqlite encryption extensions for this method to work. + */ + +- (BOOL)setKeyWithData:(NSData *)keyData; + +/** Reset encryption key using `keyData`. + + @param keyData The `NSData` to be used. + + @return `YES` if success, `NO` on error. + + @see http://www.sqlite-encrypt.com/develop-guide.htm + + @warning You need to have purchased the sqlite encryption extensions for this method to work. + */ + +- (BOOL)rekeyWithData:(NSData *)keyData; + + +///------------------------------ +/// @name General inquiry methods +///------------------------------ + +/** The path of the database file + + @return path of database. + + */ + +- (NSString *)databasePath; + +/** The underlying SQLite handle + + @return The `sqlite3` pointer. + + */ + +- (sqlite3*)sqliteHandle; + + +///----------------------------- +/// @name Retrieving error codes +///----------------------------- + +/** Last error message + + Returns the English-language text that describes the most recent failed SQLite API call associated with a database connection. If a prior API call failed but the most recent API call succeeded, this return value is undefined. + + @return `NSString` of the last error message. + + @see [sqlite3_errmsg()](http://sqlite.org/c3ref/errcode.html) + @see lastErrorCode + @see lastError + + */ + +- (NSString*)lastErrorMessage; + +/** Last error code + + Returns the numeric result code or extended result code for the most recent failed SQLite API call associated with a database connection. If a prior API call failed but the most recent API call succeeded, this return value is undefined. + + @return Integer value of the last error code. + + @see [sqlite3_errcode()](http://sqlite.org/c3ref/errcode.html) + @see lastErrorMessage + @see lastError + + */ + +- (int)lastErrorCode; + +/** Had error + + @return `YES` if there was an error, `NO` if no error. + + @see lastError + @see lastErrorCode + @see lastErrorMessage + + */ + +- (BOOL)hadError; + +/** Last error + + @return `NSError` representing the last error. + + @see lastErrorCode + @see lastErrorMessage + + */ + +- (NSError*)lastError; + + +// description forthcoming +- (void)setMaxBusyRetryTimeInterval:(NSTimeInterval)timeoutInSeconds; +- (NSTimeInterval)maxBusyRetryTimeInterval; + + +#if SQLITE_VERSION_NUMBER >= 3007000 + +///------------------ +/// @name Save points +///------------------ + +/** Start save point + + @param name Name of save point. + + @param outErr A `NSError` object to receive any error object (if any). + + @return `YES` on success; `NO` on failure. If failed, you can call ``, ``, or `` for diagnostic information regarding the failure. + + @see releaseSavePointWithName:error: + @see rollbackToSavePointWithName:error: + */ + +- (BOOL)startSavePointWithName:(NSString*)name error:(NSError**)outErr; + +/** Release save point + + @param name Name of save point. + + @param outErr A `NSError` object to receive any error object (if any). + + @return `YES` on success; `NO` on failure. If failed, you can call ``, ``, or `` for diagnostic information regarding the failure. + + @see startSavePointWithName:error: + @see rollbackToSavePointWithName:error: + + */ + +- (BOOL)releaseSavePointWithName:(NSString*)name error:(NSError**)outErr; + +/** Roll back to save point + + @param name Name of save point. + @param outErr A `NSError` object to receive any error object (if any). + + @return `YES` on success; `NO` on failure. If failed, you can call ``, ``, or `` for diagnostic information regarding the failure. + + @see startSavePointWithName:error: + @see releaseSavePointWithName:error: + + */ + +- (BOOL)rollbackToSavePointWithName:(NSString*)name error:(NSError**)outErr; + +/** Start save point + + @param block Block of code to perform from within save point. + + @return The NSError corresponding to the error, if any. If no error, returns `nil`. + + @see startSavePointWithName:error: + @see releaseSavePointWithName:error: + @see rollbackToSavePointWithName:error: + + */ + +- (NSError*)inSavePoint:(void (^)(BOOL *rollback))block; + +#endif + +///---------------------------- +/// @name SQLite library status +///---------------------------- + +/** Test to see if the library is threadsafe + + @return `NO` if and only if SQLite was compiled with mutexing code omitted due to the SQLITE_THREADSAFE compile-time option being set to 0. + + @see [sqlite3_threadsafe()](http://sqlite.org/c3ref/threadsafe.html) + */ + ++ (BOOL)isSQLiteThreadSafe; + +/** Run-time library version numbers + + @return The sqlite library version string. + + @see [sqlite3_libversion()](http://sqlite.org/c3ref/libversion.html) + */ + ++ (NSString*)sqliteLibVersion; + + ++ (NSString*)FMDBUserVersion; + ++ (SInt32)FMDBVersion; + + +///------------------------ +/// @name Make SQL function +///------------------------ + +/** Adds SQL functions or aggregates or to redefine the behavior of existing SQL functions or aggregates. + + For example: + + [queue inDatabase:^(FMDatabase *adb) { + + [adb executeUpdate:@"create table ftest (foo text)"]; + [adb executeUpdate:@"insert into ftest values ('hello')"]; + [adb executeUpdate:@"insert into ftest values ('hi')"]; + [adb executeUpdate:@"insert into ftest values ('not h!')"]; + [adb executeUpdate:@"insert into ftest values ('definitely not h!')"]; + + [adb makeFunctionNamed:@"StringStartsWithH" maximumArguments:1 withBlock:^(sqlite3_context *context, int aargc, sqlite3_value **aargv) { + if (sqlite3_value_type(aargv[0]) == SQLITE_TEXT) { + @autoreleasepool { + const char *c = (const char *)sqlite3_value_text(aargv[0]); + NSString *s = [NSString stringWithUTF8String:c]; + sqlite3_result_int(context, [s hasPrefix:@"h"]); + } + } + else { + NSLog(@"Unknown formart for StringStartsWithH (%d) %s:%d", sqlite3_value_type(aargv[0]), __FUNCTION__, __LINE__); + sqlite3_result_null(context); + } + }]; + + int rowCount = 0; + FMResultSet *ars = [adb executeQuery:@"select * from ftest where StringStartsWithH(foo)"]; + while ([ars next]) { + rowCount++; + NSLog(@"Does %@ start with 'h'?", [rs stringForColumnIndex:0]); + } + FMDBQuickCheck(rowCount == 2); + }]; + + @param name Name of function + + @param count Maximum number of parameters + + @param block The block of code for the function + + @see [sqlite3_create_function()](http://sqlite.org/c3ref/create_function.html) + */ + +- (void)makeFunctionNamed:(NSString*)name maximumArguments:(int)count withBlock:(void (^)(sqlite3_context *context, int argc, sqlite3_value **argv))block; + + +///--------------------- +/// @name Date formatter +///--------------------- + +/** Generate an `NSDateFormatter` that won't be broken by permutations of timezones or locales. + + Use this method to generate values to set the dateFormat property. + + Example: + + myDB.dateFormat = [FMDatabase storeableDateFormat:@"yyyy-MM-dd HH:mm:ss"]; + + @param format A valid NSDateFormatter format string. + + @return A `NSDateFormatter` that can be used for converting dates to strings and vice versa. + + @see hasDateFormatter + @see setDateFormat: + @see dateFromString: + @see stringFromDate: + @see storeableDateFormat: + + @warning Note that `NSDateFormatter` is not thread-safe, so the formatter generated by this method should be assigned to only one FMDB instance and should not be used for other purposes. + + */ + ++ (NSDateFormatter *)storeableDateFormat:(NSString *)format; + +/** Test whether the database has a date formatter assigned. + + @return `YES` if there is a date formatter; `NO` if not. + + @see hasDateFormatter + @see setDateFormat: + @see dateFromString: + @see stringFromDate: + @see storeableDateFormat: + */ + +- (BOOL)hasDateFormatter; + +/** Set to a date formatter to use string dates with sqlite instead of the default UNIX timestamps. + + @param format Set to nil to use UNIX timestamps. Defaults to nil. Should be set using a formatter generated using FMDatabase::storeableDateFormat. + + @see hasDateFormatter + @see setDateFormat: + @see dateFromString: + @see stringFromDate: + @see storeableDateFormat: + + @warning Note there is no direct getter for the `NSDateFormatter`, and you should not use the formatter you pass to FMDB for other purposes, as `NSDateFormatter` is not thread-safe. + */ + +- (void)setDateFormat:(NSDateFormatter *)format; + +/** Convert the supplied NSString to NSDate, using the current database formatter. + + @param s `NSString` to convert to `NSDate`. + + @return The `NSDate` object; or `nil` if no formatter is set. + + @see hasDateFormatter + @see setDateFormat: + @see dateFromString: + @see stringFromDate: + @see storeableDateFormat: + */ + +- (NSDate *)dateFromString:(NSString *)s; + +/** Convert the supplied NSDate to NSString, using the current database formatter. + + @param date `NSDate` of date to convert to `NSString`. + + @return The `NSString` representation of the date; `nil` if no formatter is set. + + @see hasDateFormatter + @see setDateFormat: + @see dateFromString: + @see stringFromDate: + @see storeableDateFormat: + */ + +- (NSString *)stringFromDate:(NSDate *)date; + +@end + + +/** Objective-C wrapper for `sqlite3_stmt` + + This is a wrapper for a SQLite `sqlite3_stmt`. Generally when using FMDB you will not need to interact directly with `FMStatement`, but rather with `` and `` only. + + ### See also + + - `` + - `` + - [`sqlite3_stmt`](http://www.sqlite.org/c3ref/stmt.html) + */ + +@interface FMStatement : NSObject { + sqlite3_stmt *_statement; + NSString *_query; + long _useCount; + BOOL _inUse; +} + +///----------------- +/// @name Properties +///----------------- + +/** Usage count */ + +@property (atomic, assign) long useCount; + +/** SQL statement */ + +@property (atomic, retain) NSString *query; + +/** SQLite sqlite3_stmt + + @see [`sqlite3_stmt`](http://www.sqlite.org/c3ref/stmt.html) + */ + +@property (atomic, assign) sqlite3_stmt *statement; + +/** Indication of whether the statement is in use */ + +@property (atomic, assign) BOOL inUse; + +///---------------------------- +/// @name Closing and Resetting +///---------------------------- + +/** Close statement */ + +- (void)close; + +/** Reset statement */ + +- (void)reset; + +@end + +#pragma clang diagnostic pop + diff --git a/ios/Pods/FMDB/src/fmdb/FMDatabase.m b/ios/Pods/FMDB/src/fmdb/FMDatabase.m new file mode 100644 index 000000000..566f6b122 --- /dev/null +++ b/ios/Pods/FMDB/src/fmdb/FMDatabase.m @@ -0,0 +1,1420 @@ +#import "FMDatabase.h" +#import "unistd.h" +#import + +@interface FMDatabase () + +- (FMResultSet *)executeQuery:(NSString *)sql withArgumentsInArray:(NSArray*)arrayArgs orDictionary:(NSDictionary *)dictionaryArgs orVAList:(va_list)args; +- (BOOL)executeUpdate:(NSString*)sql error:(NSError**)outErr withArgumentsInArray:(NSArray*)arrayArgs orDictionary:(NSDictionary *)dictionaryArgs orVAList:(va_list)args; + +@end + +@implementation FMDatabase +@synthesize cachedStatements=_cachedStatements; +@synthesize logsErrors=_logsErrors; +@synthesize crashOnErrors=_crashOnErrors; +@synthesize checkedOut=_checkedOut; +@synthesize traceExecution=_traceExecution; + +#pragma mark FMDatabase instantiation and deallocation + ++ (instancetype)databaseWithPath:(NSString*)aPath { + return FMDBReturnAutoreleased([[self alloc] initWithPath:aPath]); +} + +- (instancetype)init { + return [self initWithPath:nil]; +} + +- (instancetype)initWithPath:(NSString*)aPath { + + assert(sqlite3_threadsafe()); // whoa there big boy- gotta make sure sqlite it happy with what we're going to do. + + self = [super init]; + + if (self) { + _databasePath = [aPath copy]; + _openResultSets = [[NSMutableSet alloc] init]; + _db = nil; + _logsErrors = YES; + _crashOnErrors = NO; + _maxBusyRetryTimeInterval = 2; + } + + return self; +} + +- (void)finalize { + [self close]; + [super finalize]; +} + +- (void)dealloc { + [self close]; + FMDBRelease(_openResultSets); + FMDBRelease(_cachedStatements); + FMDBRelease(_dateFormat); + FMDBRelease(_databasePath); + FMDBRelease(_openFunctions); + +#if ! __has_feature(objc_arc) + [super dealloc]; +#endif +} + +- (NSString *)databasePath { + return _databasePath; +} + ++ (NSString*)FMDBUserVersion { + return @"2.3"; +} + +// returns 0x0230 for version 2.3. This makes it super easy to do things like: +// /* need to make sure to do X with FMDB version 2.3 or later */ +// if ([FMDatabase FMDBVersion] >= 0x0230) { … } + ++ (SInt32)FMDBVersion { + + // we go through these hoops so that we only have to change the version number in a single spot. + static dispatch_once_t once; + static SInt32 FMDBVersionVal = 0; + + dispatch_once(&once, ^{ + NSString *prodVersion = [self FMDBUserVersion]; + + if ([[prodVersion componentsSeparatedByString:@"."] count] < 3) { + prodVersion = [prodVersion stringByAppendingString:@".0"]; + } + + NSString *junk = [prodVersion stringByReplacingOccurrencesOfString:@"." withString:@""]; + + char *e = nil; + FMDBVersionVal = (int) strtoul([junk UTF8String], &e, 16); + + }); + + + return FMDBVersionVal; +} + +#pragma mark SQLite information + ++ (NSString*)sqliteLibVersion { + return [NSString stringWithFormat:@"%s", sqlite3_libversion()]; +} + ++ (BOOL)isSQLiteThreadSafe { + // make sure to read the sqlite headers on this guy! + return sqlite3_threadsafe() != 0; +} + +- (sqlite3*)sqliteHandle { + return _db; +} + +- (const char*)sqlitePath { + + if (!_databasePath) { + return ":memory:"; + } + + if ([_databasePath length] == 0) { + return ""; // this creates a temporary database (it's an sqlite thing). + } + + return [_databasePath fileSystemRepresentation]; + +} + +#pragma mark Open and close database + +- (BOOL)open { + if (_db) { + return YES; + } + + int err = sqlite3_open([self sqlitePath], &_db ); + if(err != SQLITE_OK) { + NSLog(@"error opening!: %d", err); + return NO; + } + + if (_maxBusyRetryTimeInterval > 0.0) { + // set the handler + [self setMaxBusyRetryTimeInterval:_maxBusyRetryTimeInterval]; + } + + + return YES; +} + +#if SQLITE_VERSION_NUMBER >= 3005000 +- (BOOL)openWithFlags:(int)flags { + if (_db) { + return YES; + } + + int err = sqlite3_open_v2([self sqlitePath], &_db, flags, NULL /* Name of VFS module to use */); + if(err != SQLITE_OK) { + NSLog(@"error opening!: %d", err); + return NO; + } + + if (_maxBusyRetryTimeInterval > 0.0) { + // set the handler + [self setMaxBusyRetryTimeInterval:_maxBusyRetryTimeInterval]; + } + + return YES; +} +#endif + + +- (BOOL)close { + + [self clearCachedStatements]; + [self closeOpenResultSets]; + + if (!_db) { + return YES; + } + + int rc; + BOOL retry; + BOOL triedFinalizingOpenStatements = NO; + + do { + retry = NO; + rc = sqlite3_close(_db); + if (SQLITE_BUSY == rc || SQLITE_LOCKED == rc) { + if (!triedFinalizingOpenStatements) { + triedFinalizingOpenStatements = YES; + sqlite3_stmt *pStmt; + while ((pStmt = sqlite3_next_stmt(_db, nil)) !=0) { + NSLog(@"Closing leaked statement"); + sqlite3_finalize(pStmt); + retry = YES; + } + } + } + else if (SQLITE_OK != rc) { + NSLog(@"error closing!: %d", rc); + } + } + while (retry); + + _db = nil; + return YES; +} + +#pragma mark Busy handler routines + +// NOTE: appledoc seems to choke on this function for some reason; +// so when generating documentation, you might want to ignore the +// .m files so that it only documents the public interfaces outlined +// in the .h files. +// +// This is a known appledoc bug that it has problems with C functions +// within a class implementation, but for some reason, only this +// C function causes problems; the rest don't. Anyway, ignoring the .m +// files with appledoc will prevent this problem from occurring. + +static int FMDBDatabaseBusyHandler(void *f, int count) { + FMDatabase *self = (__bridge FMDatabase*)f; + + if (count == 0) { + self->_startBusyRetryTime = [NSDate timeIntervalSinceReferenceDate]; + return 1; + } + + NSTimeInterval delta = [NSDate timeIntervalSinceReferenceDate] - (self->_startBusyRetryTime); + + if (delta < [self maxBusyRetryTimeInterval]) { + sqlite3_sleep(50); // milliseconds + return 1; + } + + return 0; +} + +- (void)setMaxBusyRetryTimeInterval:(NSTimeInterval)timeout { + + _maxBusyRetryTimeInterval = timeout; + + if (!_db) { + return; + } + + if (timeout > 0) { + sqlite3_busy_handler(_db, &FMDBDatabaseBusyHandler, (__bridge void *)(self)); + } + else { + // turn it off otherwise + sqlite3_busy_handler(_db, nil, nil); + } +} + +- (NSTimeInterval)maxBusyRetryTimeInterval { + return _maxBusyRetryTimeInterval; +} + + +// we no longer make busyRetryTimeout public +// but for folks who don't bother noticing that the interface to FMDatabase changed, +// we'll still implement the method so they don't get suprise crashes +- (int)busyRetryTimeout { + NSLog(@"%s:%d", __FUNCTION__, __LINE__); + NSLog(@"FMDB: busyRetryTimeout no longer works, please use maxBusyRetryTimeInterval"); + return -1; +} + +- (void)setBusyRetryTimeout:(int)i { + NSLog(@"%s:%d", __FUNCTION__, __LINE__); + NSLog(@"FMDB: setBusyRetryTimeout does nothing, please use setMaxBusyRetryTimeInterval:"); +} + +#pragma mark Result set functions + +- (BOOL)hasOpenResultSets { + return [_openResultSets count] > 0; +} + +- (void)closeOpenResultSets { + + //Copy the set so we don't get mutation errors + NSSet *openSetCopy = FMDBReturnAutoreleased([_openResultSets copy]); + for (NSValue *rsInWrappedInATastyValueMeal in openSetCopy) { + FMResultSet *rs = (FMResultSet *)[rsInWrappedInATastyValueMeal pointerValue]; + + [rs setParentDB:nil]; + [rs close]; + + [_openResultSets removeObject:rsInWrappedInATastyValueMeal]; + } +} + +- (void)resultSetDidClose:(FMResultSet *)resultSet { + NSValue *setValue = [NSValue valueWithNonretainedObject:resultSet]; + + [_openResultSets removeObject:setValue]; +} + +#pragma mark Cached statements + +- (void)clearCachedStatements { + + for (NSMutableSet *statements in [_cachedStatements objectEnumerator]) { + [statements makeObjectsPerformSelector:@selector(close)]; + } + + [_cachedStatements removeAllObjects]; +} + +- (FMStatement*)cachedStatementForQuery:(NSString*)query { + + NSMutableSet* statements = [_cachedStatements objectForKey:query]; + + return [[statements objectsPassingTest:^BOOL(FMStatement* statement, BOOL *stop) { + + *stop = ![statement inUse]; + return *stop; + + }] anyObject]; +} + + +- (void)setCachedStatement:(FMStatement*)statement forQuery:(NSString*)query { + + query = [query copy]; // in case we got handed in a mutable string... + [statement setQuery:query]; + + NSMutableSet* statements = [_cachedStatements objectForKey:query]; + if (!statements) { + statements = [NSMutableSet set]; + } + + [statements addObject:statement]; + + [_cachedStatements setObject:statements forKey:query]; + + FMDBRelease(query); +} + +#pragma mark Key routines + +- (BOOL)rekey:(NSString*)key { + NSData *keyData = [NSData dataWithBytes:(void *)[key UTF8String] length:(NSUInteger)strlen([key UTF8String])]; + + return [self rekeyWithData:keyData]; +} + +- (BOOL)rekeyWithData:(NSData *)keyData { +#ifdef SQLITE_HAS_CODEC + if (!keyData) { + return NO; + } + + int rc = sqlite3_rekey(_db, [keyData bytes], (int)[keyData length]); + + if (rc != SQLITE_OK) { + NSLog(@"error on rekey: %d", rc); + NSLog(@"%@", [self lastErrorMessage]); + } + + return (rc == SQLITE_OK); +#else + return NO; +#endif +} + +- (BOOL)setKey:(NSString*)key { + NSData *keyData = [NSData dataWithBytes:[key UTF8String] length:(NSUInteger)strlen([key UTF8String])]; + + return [self setKeyWithData:keyData]; +} + +- (BOOL)setKeyWithData:(NSData *)keyData { +#ifdef SQLITE_HAS_CODEC + if (!keyData) { + return NO; + } + + int rc = sqlite3_key(_db, [keyData bytes], (int)[keyData length]); + + return (rc == SQLITE_OK); +#else + return NO; +#endif +} + +#pragma mark Date routines + ++ (NSDateFormatter *)storeableDateFormat:(NSString *)format { + + NSDateFormatter *result = FMDBReturnAutoreleased([[NSDateFormatter alloc] init]); + result.dateFormat = format; + result.timeZone = [NSTimeZone timeZoneForSecondsFromGMT:0]; + result.locale = FMDBReturnAutoreleased([[NSLocale alloc] initWithLocaleIdentifier:@"en_US"]); + return result; +} + + +- (BOOL)hasDateFormatter { + return _dateFormat != nil; +} + +- (void)setDateFormat:(NSDateFormatter *)format { + FMDBAutorelease(_dateFormat); + _dateFormat = FMDBReturnRetained(format); +} + +- (NSDate *)dateFromString:(NSString *)s { + return [_dateFormat dateFromString:s]; +} + +- (NSString *)stringFromDate:(NSDate *)date { + return [_dateFormat stringFromDate:date]; +} + +#pragma mark State of database + +- (BOOL)goodConnection { + + if (!_db) { + return NO; + } + + FMResultSet *rs = [self executeQuery:@"select name from sqlite_master where type='table'"]; + + if (rs) { + [rs close]; + return YES; + } + + return NO; +} + +- (void)warnInUse { + NSLog(@"The FMDatabase %@ is currently in use.", self); + +#ifndef NS_BLOCK_ASSERTIONS + if (_crashOnErrors) { + NSAssert(false, @"The FMDatabase %@ is currently in use.", self); + abort(); + } +#endif +} + +- (BOOL)databaseExists { + + if (!_db) { + + NSLog(@"The FMDatabase %@ is not open.", self); + + #ifndef NS_BLOCK_ASSERTIONS + if (_crashOnErrors) { + NSAssert(false, @"The FMDatabase %@ is not open.", self); + abort(); + } + #endif + + return NO; + } + + return YES; +} + +#pragma mark Error routines + +- (NSString*)lastErrorMessage { + return [NSString stringWithUTF8String:sqlite3_errmsg(_db)]; +} + +- (BOOL)hadError { + int lastErrCode = [self lastErrorCode]; + + return (lastErrCode > SQLITE_OK && lastErrCode < SQLITE_ROW); +} + +- (int)lastErrorCode { + return sqlite3_errcode(_db); +} + +- (NSError*)errorWithMessage:(NSString*)message { + NSDictionary* errorMessage = [NSDictionary dictionaryWithObject:message forKey:NSLocalizedDescriptionKey]; + + return [NSError errorWithDomain:@"FMDatabase" code:sqlite3_errcode(_db) userInfo:errorMessage]; +} + +- (NSError*)lastError { + return [self errorWithMessage:[self lastErrorMessage]]; +} + +#pragma mark Update information routines + +- (sqlite_int64)lastInsertRowId { + + if (_isExecutingStatement) { + [self warnInUse]; + return NO; + } + + _isExecutingStatement = YES; + + sqlite_int64 ret = sqlite3_last_insert_rowid(_db); + + _isExecutingStatement = NO; + + return ret; +} + +- (int)changes { + if (_isExecutingStatement) { + [self warnInUse]; + return 0; + } + + _isExecutingStatement = YES; + + int ret = sqlite3_changes(_db); + + _isExecutingStatement = NO; + + return ret; +} + +#pragma mark SQL manipulation + +- (void)bindObject:(id)obj toColumn:(int)idx inStatement:(sqlite3_stmt*)pStmt { + + if ((!obj) || ((NSNull *)obj == [NSNull null])) { + sqlite3_bind_null(pStmt, idx); + } + + // FIXME - someday check the return codes on these binds. + else if ([obj isKindOfClass:[NSData class]]) { + const void *bytes = [obj bytes]; + if (!bytes) { + // it's an empty NSData object, aka [NSData data]. + // Don't pass a NULL pointer, or sqlite will bind a SQL null instead of a blob. + bytes = ""; + } + sqlite3_bind_blob(pStmt, idx, bytes, (int)[obj length], SQLITE_STATIC); + } + else if ([obj isKindOfClass:[NSDate class]]) { + if (self.hasDateFormatter) + sqlite3_bind_text(pStmt, idx, [[self stringFromDate:obj] UTF8String], -1, SQLITE_STATIC); + else + sqlite3_bind_double(pStmt, idx, [obj timeIntervalSince1970]); + } + else if ([obj isKindOfClass:[NSNumber class]]) { + + if (strcmp([obj objCType], @encode(char)) == 0) { + sqlite3_bind_int(pStmt, idx, [obj charValue]); + } + else if (strcmp([obj objCType], @encode(unsigned char)) == 0) { + sqlite3_bind_int(pStmt, idx, [obj unsignedCharValue]); + } + else if (strcmp([obj objCType], @encode(short)) == 0) { + sqlite3_bind_int(pStmt, idx, [obj shortValue]); + } + else if (strcmp([obj objCType], @encode(unsigned short)) == 0) { + sqlite3_bind_int(pStmt, idx, [obj unsignedShortValue]); + } + else if (strcmp([obj objCType], @encode(int)) == 0) { + sqlite3_bind_int(pStmt, idx, [obj intValue]); + } + else if (strcmp([obj objCType], @encode(unsigned int)) == 0) { + sqlite3_bind_int64(pStmt, idx, (long long)[obj unsignedIntValue]); + } + else if (strcmp([obj objCType], @encode(long)) == 0) { + sqlite3_bind_int64(pStmt, idx, [obj longValue]); + } + else if (strcmp([obj objCType], @encode(unsigned long)) == 0) { + sqlite3_bind_int64(pStmt, idx, (long long)[obj unsignedLongValue]); + } + else if (strcmp([obj objCType], @encode(long long)) == 0) { + sqlite3_bind_int64(pStmt, idx, [obj longLongValue]); + } + else if (strcmp([obj objCType], @encode(unsigned long long)) == 0) { + sqlite3_bind_int64(pStmt, idx, (long long)[obj unsignedLongLongValue]); + } + else if (strcmp([obj objCType], @encode(float)) == 0) { + sqlite3_bind_double(pStmt, idx, [obj floatValue]); + } + else if (strcmp([obj objCType], @encode(double)) == 0) { + sqlite3_bind_double(pStmt, idx, [obj doubleValue]); + } + else if (strcmp([obj objCType], @encode(BOOL)) == 0) { + sqlite3_bind_int(pStmt, idx, ([obj boolValue] ? 1 : 0)); + } + else { + sqlite3_bind_text(pStmt, idx, [[obj description] UTF8String], -1, SQLITE_STATIC); + } + } + else { + sqlite3_bind_text(pStmt, idx, [[obj description] UTF8String], -1, SQLITE_STATIC); + } +} + +- (void)extractSQL:(NSString *)sql argumentsList:(va_list)args intoString:(NSMutableString *)cleanedSQL arguments:(NSMutableArray *)arguments { + + NSUInteger length = [sql length]; + unichar last = '\0'; + for (NSUInteger i = 0; i < length; ++i) { + id arg = nil; + unichar current = [sql characterAtIndex:i]; + unichar add = current; + if (last == '%') { + switch (current) { + case '@': + arg = va_arg(args, id); + break; + case 'c': + // warning: second argument to 'va_arg' is of promotable type 'char'; this va_arg has undefined behavior because arguments will be promoted to 'int' + arg = [NSString stringWithFormat:@"%c", va_arg(args, int)]; + break; + case 's': + arg = [NSString stringWithUTF8String:va_arg(args, char*)]; + break; + case 'd': + case 'D': + case 'i': + arg = [NSNumber numberWithInt:va_arg(args, int)]; + break; + case 'u': + case 'U': + arg = [NSNumber numberWithUnsignedInt:va_arg(args, unsigned int)]; + break; + case 'h': + i++; + if (i < length && [sql characterAtIndex:i] == 'i') { + // warning: second argument to 'va_arg' is of promotable type 'short'; this va_arg has undefined behavior because arguments will be promoted to 'int' + arg = [NSNumber numberWithShort:(short)(va_arg(args, int))]; + } + else if (i < length && [sql characterAtIndex:i] == 'u') { + // warning: second argument to 'va_arg' is of promotable type 'unsigned short'; this va_arg has undefined behavior because arguments will be promoted to 'int' + arg = [NSNumber numberWithUnsignedShort:(unsigned short)(va_arg(args, uint))]; + } + else { + i--; + } + break; + case 'q': + i++; + if (i < length && [sql characterAtIndex:i] == 'i') { + arg = [NSNumber numberWithLongLong:va_arg(args, long long)]; + } + else if (i < length && [sql characterAtIndex:i] == 'u') { + arg = [NSNumber numberWithUnsignedLongLong:va_arg(args, unsigned long long)]; + } + else { + i--; + } + break; + case 'f': + arg = [NSNumber numberWithDouble:va_arg(args, double)]; + break; + case 'g': + // warning: second argument to 'va_arg' is of promotable type 'float'; this va_arg has undefined behavior because arguments will be promoted to 'double' + arg = [NSNumber numberWithFloat:(float)(va_arg(args, double))]; + break; + case 'l': + i++; + if (i < length) { + unichar next = [sql characterAtIndex:i]; + if (next == 'l') { + i++; + if (i < length && [sql characterAtIndex:i] == 'd') { + //%lld + arg = [NSNumber numberWithLongLong:va_arg(args, long long)]; + } + else if (i < length && [sql characterAtIndex:i] == 'u') { + //%llu + arg = [NSNumber numberWithUnsignedLongLong:va_arg(args, unsigned long long)]; + } + else { + i--; + } + } + else if (next == 'd') { + //%ld + arg = [NSNumber numberWithLong:va_arg(args, long)]; + } + else if (next == 'u') { + //%lu + arg = [NSNumber numberWithUnsignedLong:va_arg(args, unsigned long)]; + } + else { + i--; + } + } + else { + i--; + } + break; + default: + // something else that we can't interpret. just pass it on through like normal + break; + } + } + else if (current == '%') { + // percent sign; skip this character + add = '\0'; + } + + if (arg != nil) { + [cleanedSQL appendString:@"?"]; + [arguments addObject:arg]; + } + else if (add == (unichar)'@' && last == (unichar) '%') { + [cleanedSQL appendFormat:@"NULL"]; + } + else if (add != '\0') { + [cleanedSQL appendFormat:@"%C", add]; + } + last = current; + } +} + +#pragma mark Execute queries + +- (FMResultSet *)executeQuery:(NSString *)sql withParameterDictionary:(NSDictionary *)arguments { + return [self executeQuery:sql withArgumentsInArray:nil orDictionary:arguments orVAList:nil]; +} + +- (FMResultSet *)executeQuery:(NSString *)sql withArgumentsInArray:(NSArray*)arrayArgs orDictionary:(NSDictionary *)dictionaryArgs orVAList:(va_list)args { + + if (![self databaseExists]) { + return 0x00; + } + + if (_isExecutingStatement) { + [self warnInUse]; + return 0x00; + } + + _isExecutingStatement = YES; + + int rc = 0x00; + sqlite3_stmt *pStmt = 0x00; + FMStatement *statement = 0x00; + FMResultSet *rs = 0x00; + + if (_traceExecution && sql) { + NSLog(@"%@ executeQuery: %@", self, sql); + } + + if (_shouldCacheStatements) { + statement = [self cachedStatementForQuery:sql]; + pStmt = statement ? [statement statement] : 0x00; + [statement reset]; + } + + if (!pStmt) { + + rc = sqlite3_prepare_v2(_db, [sql UTF8String], -1, &pStmt, 0); + + if (SQLITE_OK != rc) { + if (_logsErrors) { + NSLog(@"DB Error: %d \"%@\"", [self lastErrorCode], [self lastErrorMessage]); + NSLog(@"DB Query: %@", sql); + NSLog(@"DB Path: %@", _databasePath); + } + + if (_crashOnErrors) { + NSAssert(false, @"DB Error: %d \"%@\"", [self lastErrorCode], [self lastErrorMessage]); + abort(); + } + + sqlite3_finalize(pStmt); + _isExecutingStatement = NO; + return nil; + } + } + + id obj; + int idx = 0; + int queryCount = sqlite3_bind_parameter_count(pStmt); // pointed out by Dominic Yu (thanks!) + + // If dictionaryArgs is passed in, that means we are using sqlite's named parameter support + if (dictionaryArgs) { + + for (NSString *dictionaryKey in [dictionaryArgs allKeys]) { + + // Prefix the key with a colon. + NSString *parameterName = [[NSString alloc] initWithFormat:@":%@", dictionaryKey]; + + if (_traceExecution) { + NSLog(@"%@ = %@", parameterName, [dictionaryArgs objectForKey:dictionaryKey]); + } + + // Get the index for the parameter name. + int namedIdx = sqlite3_bind_parameter_index(pStmt, [parameterName UTF8String]); + + FMDBRelease(parameterName); + + if (namedIdx > 0) { + // Standard binding from here. + [self bindObject:[dictionaryArgs objectForKey:dictionaryKey] toColumn:namedIdx inStatement:pStmt]; + // increment the binding count, so our check below works out + idx++; + } + else { + NSLog(@"Could not find index for %@", dictionaryKey); + } + } + } + else { + + while (idx < queryCount) { + + if (arrayArgs && idx < (int)[arrayArgs count]) { + obj = [arrayArgs objectAtIndex:(NSUInteger)idx]; + } + else if (args) { + obj = va_arg(args, id); + } + else { + //We ran out of arguments + break; + } + + if (_traceExecution) { + if ([obj isKindOfClass:[NSData class]]) { + NSLog(@"data: %ld bytes", (unsigned long)[(NSData*)obj length]); + } + else { + NSLog(@"obj: %@", obj); + } + } + + idx++; + + [self bindObject:obj toColumn:idx inStatement:pStmt]; + } + } + + if (idx != queryCount) { + NSLog(@"Error: the bind count is not correct for the # of variables (executeQuery)"); + sqlite3_finalize(pStmt); + _isExecutingStatement = NO; + return nil; + } + + FMDBRetain(statement); // to balance the release below + + if (!statement) { + statement = [[FMStatement alloc] init]; + [statement setStatement:pStmt]; + + if (_shouldCacheStatements && sql) { + [self setCachedStatement:statement forQuery:sql]; + } + } + + // the statement gets closed in rs's dealloc or [rs close]; + rs = [FMResultSet resultSetWithStatement:statement usingParentDatabase:self]; + [rs setQuery:sql]; + + NSValue *openResultSet = [NSValue valueWithNonretainedObject:rs]; + [_openResultSets addObject:openResultSet]; + + [statement setUseCount:[statement useCount] + 1]; + + FMDBRelease(statement); + + _isExecutingStatement = NO; + + return rs; +} + +- (FMResultSet *)executeQuery:(NSString*)sql, ... { + va_list args; + va_start(args, sql); + + id result = [self executeQuery:sql withArgumentsInArray:nil orDictionary:nil orVAList:args]; + + va_end(args); + return result; +} + +- (FMResultSet *)executeQueryWithFormat:(NSString*)format, ... { + va_list args; + va_start(args, format); + + NSMutableString *sql = [NSMutableString stringWithCapacity:[format length]]; + NSMutableArray *arguments = [NSMutableArray array]; + [self extractSQL:format argumentsList:args intoString:sql arguments:arguments]; + + va_end(args); + + return [self executeQuery:sql withArgumentsInArray:arguments]; +} + +- (FMResultSet *)executeQuery:(NSString *)sql withArgumentsInArray:(NSArray *)arguments { + return [self executeQuery:sql withArgumentsInArray:arguments orDictionary:nil orVAList:nil]; +} + +- (FMResultSet *)executeQuery:(NSString*)sql withVAList:(va_list)args { + return [self executeQuery:sql withArgumentsInArray:nil orDictionary:nil orVAList:args]; +} + +#pragma mark Execute updates + +- (BOOL)executeUpdate:(NSString*)sql error:(NSError**)outErr withArgumentsInArray:(NSArray*)arrayArgs orDictionary:(NSDictionary *)dictionaryArgs orVAList:(va_list)args { + + if (![self databaseExists]) { + return NO; + } + + if (_isExecutingStatement) { + [self warnInUse]; + return NO; + } + + _isExecutingStatement = YES; + + int rc = 0x00; + sqlite3_stmt *pStmt = 0x00; + FMStatement *cachedStmt = 0x00; + + if (_traceExecution && sql) { + NSLog(@"%@ executeUpdate: %@", self, sql); + } + + if (_shouldCacheStatements) { + cachedStmt = [self cachedStatementForQuery:sql]; + pStmt = cachedStmt ? [cachedStmt statement] : 0x00; + [cachedStmt reset]; + } + + if (!pStmt) { + rc = sqlite3_prepare_v2(_db, [sql UTF8String], -1, &pStmt, 0); + + if (SQLITE_OK != rc) { + if (_logsErrors) { + NSLog(@"DB Error: %d \"%@\"", [self lastErrorCode], [self lastErrorMessage]); + NSLog(@"DB Query: %@", sql); + NSLog(@"DB Path: %@", _databasePath); + } + + if (_crashOnErrors) { + NSAssert(false, @"DB Error: %d \"%@\"", [self lastErrorCode], [self lastErrorMessage]); + abort(); + } + + sqlite3_finalize(pStmt); + + if (outErr) { + *outErr = [self errorWithMessage:[NSString stringWithUTF8String:sqlite3_errmsg(_db)]]; + } + + _isExecutingStatement = NO; + return NO; + } + } + + id obj; + int idx = 0; + int queryCount = sqlite3_bind_parameter_count(pStmt); + + // If dictionaryArgs is passed in, that means we are using sqlite's named parameter support + if (dictionaryArgs) { + + for (NSString *dictionaryKey in [dictionaryArgs allKeys]) { + + // Prefix the key with a colon. + NSString *parameterName = [[NSString alloc] initWithFormat:@":%@", dictionaryKey]; + + if (_traceExecution) { + NSLog(@"%@ = %@", parameterName, [dictionaryArgs objectForKey:dictionaryKey]); + } + // Get the index for the parameter name. + int namedIdx = sqlite3_bind_parameter_index(pStmt, [parameterName UTF8String]); + + FMDBRelease(parameterName); + + if (namedIdx > 0) { + // Standard binding from here. + [self bindObject:[dictionaryArgs objectForKey:dictionaryKey] toColumn:namedIdx inStatement:pStmt]; + + // increment the binding count, so our check below works out + idx++; + } + else { + NSLog(@"Could not find index for %@", dictionaryKey); + } + } + } + else { + + while (idx < queryCount) { + + if (arrayArgs && idx < (int)[arrayArgs count]) { + obj = [arrayArgs objectAtIndex:(NSUInteger)idx]; + } + else if (args) { + obj = va_arg(args, id); + } + else { + //We ran out of arguments + break; + } + + if (_traceExecution) { + if ([obj isKindOfClass:[NSData class]]) { + NSLog(@"data: %ld bytes", (unsigned long)[(NSData*)obj length]); + } + else { + NSLog(@"obj: %@", obj); + } + } + + idx++; + + [self bindObject:obj toColumn:idx inStatement:pStmt]; + } + } + + + if (idx != queryCount) { + NSLog(@"Error: the bind count (%d) is not correct for the # of variables in the query (%d) (%@) (executeUpdate)", idx, queryCount, sql); + sqlite3_finalize(pStmt); + _isExecutingStatement = NO; + return NO; + } + + /* Call sqlite3_step() to run the virtual machine. Since the SQL being + ** executed is not a SELECT statement, we assume no data will be returned. + */ + + rc = sqlite3_step(pStmt); + + if (SQLITE_DONE == rc) { + // all is well, let's return. + } + else if (SQLITE_ERROR == rc) { + if (_logsErrors) { + NSLog(@"Error calling sqlite3_step (%d: %s) SQLITE_ERROR", rc, sqlite3_errmsg(_db)); + NSLog(@"DB Query: %@", sql); + } + } + else if (SQLITE_MISUSE == rc) { + // uh oh. + if (_logsErrors) { + NSLog(@"Error calling sqlite3_step (%d: %s) SQLITE_MISUSE", rc, sqlite3_errmsg(_db)); + NSLog(@"DB Query: %@", sql); + } + } + else { + // wtf? + if (_logsErrors) { + NSLog(@"Unknown error calling sqlite3_step (%d: %s) eu", rc, sqlite3_errmsg(_db)); + NSLog(@"DB Query: %@", sql); + } + } + + if (rc == SQLITE_ROW) { + NSAssert(NO, @"A executeUpdate is being called with a query string '%@'", sql); + } + + if (_shouldCacheStatements && !cachedStmt) { + cachedStmt = [[FMStatement alloc] init]; + + [cachedStmt setStatement:pStmt]; + + [self setCachedStatement:cachedStmt forQuery:sql]; + + FMDBRelease(cachedStmt); + } + + int closeErrorCode; + + if (cachedStmt) { + [cachedStmt setUseCount:[cachedStmt useCount] + 1]; + closeErrorCode = sqlite3_reset(pStmt); + } + else { + /* Finalize the virtual machine. This releases all memory and other + ** resources allocated by the sqlite3_prepare() call above. + */ + closeErrorCode = sqlite3_finalize(pStmt); + } + + if (closeErrorCode != SQLITE_OK) { + if (_logsErrors) { + NSLog(@"Unknown error finalizing or resetting statement (%d: %s)", closeErrorCode, sqlite3_errmsg(_db)); + NSLog(@"DB Query: %@", sql); + } + } + + _isExecutingStatement = NO; + return (rc == SQLITE_DONE || rc == SQLITE_OK); +} + + +- (BOOL)executeUpdate:(NSString*)sql, ... { + va_list args; + va_start(args, sql); + + BOOL result = [self executeUpdate:sql error:nil withArgumentsInArray:nil orDictionary:nil orVAList:args]; + + va_end(args); + return result; +} + +- (BOOL)executeUpdate:(NSString*)sql withArgumentsInArray:(NSArray *)arguments { + return [self executeUpdate:sql error:nil withArgumentsInArray:arguments orDictionary:nil orVAList:nil]; +} + +- (BOOL)executeUpdate:(NSString*)sql withParameterDictionary:(NSDictionary *)arguments { + return [self executeUpdate:sql error:nil withArgumentsInArray:nil orDictionary:arguments orVAList:nil]; +} + +- (BOOL)executeUpdate:(NSString*)sql withVAList:(va_list)args { + return [self executeUpdate:sql error:nil withArgumentsInArray:nil orDictionary:nil orVAList:args]; +} + +- (BOOL)executeUpdateWithFormat:(NSString*)format, ... { + va_list args; + va_start(args, format); + + NSMutableString *sql = [NSMutableString stringWithCapacity:[format length]]; + NSMutableArray *arguments = [NSMutableArray array]; + + [self extractSQL:format argumentsList:args intoString:sql arguments:arguments]; + + va_end(args); + + return [self executeUpdate:sql withArgumentsInArray:arguments]; +} + + +int FMDBExecuteBulkSQLCallback(void *theBlockAsVoid, int columns, char **values, char **names); // shhh clang. +int FMDBExecuteBulkSQLCallback(void *theBlockAsVoid, int columns, char **values, char **names) { + + if (!theBlockAsVoid) { + return SQLITE_OK; + } + + int (^execCallbackBlock)(NSDictionary *resultsDictionary) = (__bridge int (^)(NSDictionary *__strong))(theBlockAsVoid); + + NSMutableDictionary *dictionary = [NSMutableDictionary dictionaryWithCapacity:(NSUInteger)columns]; + + for (NSInteger i = 0; i < columns; i++) { + NSString *key = [NSString stringWithUTF8String:names[i]]; + id value = values[i] ? [NSString stringWithUTF8String:values[i]] : [NSNull null]; + [dictionary setObject:value forKey:key]; + } + + return execCallbackBlock(dictionary); +} + +- (BOOL)executeStatements:(NSString *)sql { + return [self executeStatements:sql withResultBlock:nil]; +} + +- (BOOL)executeStatements:(NSString *)sql withResultBlock:(FMDBExecuteStatementsCallbackBlock)block { + + int rc; + char *errmsg = nil; + + rc = sqlite3_exec([self sqliteHandle], [sql UTF8String], block ? FMDBExecuteBulkSQLCallback : nil, (__bridge void *)(block), &errmsg); + + if (errmsg && [self logsErrors]) { + NSLog(@"Error inserting batch: %s", errmsg); + sqlite3_free(errmsg); + } + + return (rc == SQLITE_OK); +} + +- (BOOL)executeUpdate:(NSString*)sql withErrorAndBindings:(NSError**)outErr, ... { + + va_list args; + va_start(args, outErr); + + BOOL result = [self executeUpdate:sql error:outErr withArgumentsInArray:nil orDictionary:nil orVAList:args]; + + va_end(args); + return result; +} + + +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wdeprecated-implementations" +- (BOOL)update:(NSString*)sql withErrorAndBindings:(NSError**)outErr, ... { + va_list args; + va_start(args, outErr); + + BOOL result = [self executeUpdate:sql error:outErr withArgumentsInArray:nil orDictionary:nil orVAList:args]; + + va_end(args); + return result; +} + +#pragma clang diagnostic pop + +#pragma mark Transactions + +- (BOOL)rollback { + BOOL b = [self executeUpdate:@"rollback transaction"]; + + if (b) { + _inTransaction = NO; + } + + return b; +} + +- (BOOL)commit { + BOOL b = [self executeUpdate:@"commit transaction"]; + + if (b) { + _inTransaction = NO; + } + + return b; +} + +- (BOOL)beginDeferredTransaction { + + BOOL b = [self executeUpdate:@"begin deferred transaction"]; + if (b) { + _inTransaction = YES; + } + + return b; +} + +- (BOOL)beginTransaction { + + BOOL b = [self executeUpdate:@"begin exclusive transaction"]; + if (b) { + _inTransaction = YES; + } + + return b; +} + +- (BOOL)inTransaction { + return _inTransaction; +} + +#if SQLITE_VERSION_NUMBER >= 3007000 + +static NSString *FMDBEscapeSavePointName(NSString *savepointName) { + return [savepointName stringByReplacingOccurrencesOfString:@"'" withString:@"''"]; +} + +- (BOOL)startSavePointWithName:(NSString*)name error:(NSError**)outErr { + + NSParameterAssert(name); + + NSString *sql = [NSString stringWithFormat:@"savepoint '%@';", FMDBEscapeSavePointName(name)]; + + if (![self executeUpdate:sql]) { + + if (outErr) { + *outErr = [self lastError]; + } + + return NO; + } + + return YES; +} + +- (BOOL)releaseSavePointWithName:(NSString*)name error:(NSError**)outErr { + + NSParameterAssert(name); + + NSString *sql = [NSString stringWithFormat:@"release savepoint '%@';", FMDBEscapeSavePointName(name)]; + BOOL worked = [self executeUpdate:sql]; + + if (!worked && outErr) { + *outErr = [self lastError]; + } + + return worked; +} + +- (BOOL)rollbackToSavePointWithName:(NSString*)name error:(NSError**)outErr { + + NSParameterAssert(name); + + NSString *sql = [NSString stringWithFormat:@"rollback transaction to savepoint '%@';", FMDBEscapeSavePointName(name)]; + BOOL worked = [self executeUpdate:sql]; + + if (!worked && outErr) { + *outErr = [self lastError]; + } + + return worked; +} + +- (NSError*)inSavePoint:(void (^)(BOOL *rollback))block { + static unsigned long savePointIdx = 0; + + NSString *name = [NSString stringWithFormat:@"dbSavePoint%ld", savePointIdx++]; + + BOOL shouldRollback = NO; + + NSError *err = 0x00; + + if (![self startSavePointWithName:name error:&err]) { + return err; + } + + block(&shouldRollback); + + if (shouldRollback) { + // We need to rollback and release this savepoint to remove it + [self rollbackToSavePointWithName:name error:&err]; + } + [self releaseSavePointWithName:name error:&err]; + + return err; +} + +#endif + +#pragma mark Cache statements + +- (BOOL)shouldCacheStatements { + return _shouldCacheStatements; +} + +- (void)setShouldCacheStatements:(BOOL)value { + + _shouldCacheStatements = value; + + if (_shouldCacheStatements && !_cachedStatements) { + [self setCachedStatements:[NSMutableDictionary dictionary]]; + } + + if (!_shouldCacheStatements) { + [self setCachedStatements:nil]; + } +} + +#pragma mark Callback function + +void FMDBBlockSQLiteCallBackFunction(sqlite3_context *context, int argc, sqlite3_value **argv); // -Wmissing-prototypes +void FMDBBlockSQLiteCallBackFunction(sqlite3_context *context, int argc, sqlite3_value **argv) { +#if ! __has_feature(objc_arc) + void (^block)(sqlite3_context *context, int argc, sqlite3_value **argv) = (id)sqlite3_user_data(context); +#else + void (^block)(sqlite3_context *context, int argc, sqlite3_value **argv) = (__bridge id)sqlite3_user_data(context); +#endif + block(context, argc, argv); +} + + +- (void)makeFunctionNamed:(NSString*)name maximumArguments:(int)count withBlock:(void (^)(sqlite3_context *context, int argc, sqlite3_value **argv))block { + + if (!_openFunctions) { + _openFunctions = [NSMutableSet new]; + } + + id b = FMDBReturnAutoreleased([block copy]); + + [_openFunctions addObject:b]; + + /* I tried adding custom functions to release the block when the connection is destroyed- but they seemed to never be called, so we use _openFunctions to store the values instead. */ +#if ! __has_feature(objc_arc) + sqlite3_create_function([self sqliteHandle], [name UTF8String], count, SQLITE_UTF8, (void*)b, &FMDBBlockSQLiteCallBackFunction, 0x00, 0x00); +#else + sqlite3_create_function([self sqliteHandle], [name UTF8String], count, SQLITE_UTF8, (__bridge void*)b, &FMDBBlockSQLiteCallBackFunction, 0x00, 0x00); +#endif +} + +@end + + + +@implementation FMStatement +@synthesize statement=_statement; +@synthesize query=_query; +@synthesize useCount=_useCount; +@synthesize inUse=_inUse; + +- (void)finalize { + [self close]; + [super finalize]; +} + +- (void)dealloc { + [self close]; + FMDBRelease(_query); +#if ! __has_feature(objc_arc) + [super dealloc]; +#endif +} + +- (void)close { + if (_statement) { + sqlite3_finalize(_statement); + _statement = 0x00; + } + + _inUse = NO; +} + +- (void)reset { + if (_statement) { + sqlite3_reset(_statement); + } + + _inUse = NO; +} + +- (NSString*)description { + return [NSString stringWithFormat:@"%@ %ld hit(s) for query %@", [super description], _useCount, _query]; +} + + +@end + diff --git a/ios/Pods/FMDB/src/fmdb/FMDatabaseAdditions.h b/ios/Pods/FMDB/src/fmdb/FMDatabaseAdditions.h new file mode 100644 index 000000000..e35df93ca --- /dev/null +++ b/ios/Pods/FMDB/src/fmdb/FMDatabaseAdditions.h @@ -0,0 +1,267 @@ +// +// FMDatabaseAdditions.h +// fmdb +// +// Created by August Mueller on 10/30/05. +// Copyright 2005 Flying Meat Inc.. All rights reserved. +// + +#import +#import "FMDatabase.h" + + +/** Category of additions for `` class. + + ### See also + + - `` + */ + +@interface FMDatabase (FMDatabaseAdditions) + +///---------------------------------------- +/// @name Return results of SQL to variable +///---------------------------------------- + +/** Return `int` value for query + + @param query The SQL query to be performed. + @param ... A list of parameters that will be bound to the `?` placeholders in the SQL query. + + @return `int` value. + */ + +- (int)intForQuery:(NSString*)query, ...; + +/** Return `long` value for query + + @param query The SQL query to be performed. + @param ... A list of parameters that will be bound to the `?` placeholders in the SQL query. + + @return `long` value. + */ + +- (long)longForQuery:(NSString*)query, ...; + +/** Return `BOOL` value for query + + @param query The SQL query to be performed. + @param ... A list of parameters that will be bound to the `?` placeholders in the SQL query. + + @return `BOOL` value. + */ + +- (BOOL)boolForQuery:(NSString*)query, ...; + +/** Return `double` value for query + + @param query The SQL query to be performed. + @param ... A list of parameters that will be bound to the `?` placeholders in the SQL query. + + @return `double` value. + */ + +- (double)doubleForQuery:(NSString*)query, ...; + +/** Return `NSString` value for query + + @param query The SQL query to be performed. + @param ... A list of parameters that will be bound to the `?` placeholders in the SQL query. + + @return `NSString` value. + */ + +- (NSString*)stringForQuery:(NSString*)query, ...; + +/** Return `NSData` value for query + + @param query The SQL query to be performed. + @param ... A list of parameters that will be bound to the `?` placeholders in the SQL query. + + @return `NSData` value. + */ + +- (NSData*)dataForQuery:(NSString*)query, ...; + +/** Return `NSDate` value for query + + @param query The SQL query to be performed. + @param ... A list of parameters that will be bound to the `?` placeholders in the SQL query. + + @return `NSDate` value. + */ + +- (NSDate*)dateForQuery:(NSString*)query, ...; + + +// Notice that there's no dataNoCopyForQuery:. +// That would be a bad idea, because we close out the result set, and then what +// happens to the data that we just didn't copy? Who knows, not I. + + +///-------------------------------- +/// @name Schema related operations +///-------------------------------- + +/** Does table exist in database? + + @param tableName The name of the table being looked for. + + @return `YES` if table found; `NO` if not found. + */ + +- (BOOL)tableExists:(NSString*)tableName; + +/** The schema of the database. + + This will be the schema for the entire database. For each entity, each row of the result set will include the following fields: + + - `type` - The type of entity (e.g. table, index, view, or trigger) + - `name` - The name of the object + - `tbl_name` - The name of the table to which the object references + - `rootpage` - The page number of the root b-tree page for tables and indices + - `sql` - The SQL that created the entity + + @return `FMResultSet` of schema; `nil` on error. + + @see [SQLite File Format](http://www.sqlite.org/fileformat.html) + */ + +- (FMResultSet*)getSchema; + +/** The schema of the database. + + This will be the schema for a particular table as report by SQLite `PRAGMA`, for example: + + PRAGMA table_info('employees') + + This will report: + + - `cid` - The column ID number + - `name` - The name of the column + - `type` - The data type specified for the column + - `notnull` - whether the field is defined as NOT NULL (i.e. values required) + - `dflt_value` - The default value for the column + - `pk` - Whether the field is part of the primary key of the table + + @param tableName The name of the table for whom the schema will be returned. + + @return `FMResultSet` of schema; `nil` on error. + + @see [table_info](http://www.sqlite.org/pragma.html#pragma_table_info) + */ + +- (FMResultSet*)getTableSchema:(NSString*)tableName; + +/** Test to see if particular column exists for particular table in database + + @param columnName The name of the column. + + @param tableName The name of the table. + + @return `YES` if column exists in table in question; `NO` otherwise. + */ + +- (BOOL)columnExists:(NSString*)columnName inTableWithName:(NSString*)tableName; + +/** Test to see if particular column exists for particular table in database + + @param columnName The name of the column. + + @param tableName The name of the table. + + @return `YES` if column exists in table in question; `NO` otherwise. + + @see columnExists:inTableWithName: + + @warning Deprecated - use `` instead. + */ + +- (BOOL)columnExists:(NSString*)tableName columnName:(NSString*)columnName __attribute__ ((deprecated)); + + +/** Validate SQL statement + + This validates SQL statement by performing `sqlite3_prepare_v2`, but not returning the results, but instead immediately calling `sqlite3_finalize`. + + @param sql The SQL statement being validated. + + @param error This is a pointer to a `NSError` object that will receive the autoreleased `NSError` object if there was any error. If this is `nil`, no `NSError` result will be returned. + + @return `YES` if validation succeeded without incident; `NO` otherwise. + + */ + +- (BOOL)validateSQL:(NSString*)sql error:(NSError**)error; + + +#if SQLITE_VERSION_NUMBER >= 3007017 + +///----------------------------------- +/// @name Application identifier tasks +///----------------------------------- + +/** Retrieve application ID + + @return The `uint32_t` numeric value of the application ID. + + @see setApplicationID: + */ + +- (uint32_t)applicationID; + +/** Set the application ID + + @param appID The `uint32_t` numeric value of the application ID. + + @see applicationID + */ + +- (void)setApplicationID:(uint32_t)appID; + +#if TARGET_OS_MAC && !TARGET_OS_IPHONE +/** Retrieve application ID string + + @return The `NSString` value of the application ID. + + @see setApplicationIDString: + */ + + +- (NSString*)applicationIDString; + +/** Set the application ID string + + @param string The `NSString` value of the application ID. + + @see applicationIDString + */ + +- (void)setApplicationIDString:(NSString*)string; +#endif + +#endif + +///----------------------------------- +/// @name user version identifier tasks +///----------------------------------- + +/** Retrieve user version + + @return The `uint32_t` numeric value of the user version. + + @see setUserVersion: + */ + +- (uint32_t)userVersion; + +/** Set the user-version + + @param version The `uint32_t` numeric value of the user version. + + @see userVersion + */ + +- (void)setUserVersion:(uint32_t)version; + +@end diff --git a/ios/Pods/FMDB/src/fmdb/FMDatabaseAdditions.m b/ios/Pods/FMDB/src/fmdb/FMDatabaseAdditions.m new file mode 100644 index 000000000..4ab35fa2d --- /dev/null +++ b/ios/Pods/FMDB/src/fmdb/FMDatabaseAdditions.m @@ -0,0 +1,224 @@ +// +// FMDatabaseAdditions.m +// fmdb +// +// Created by August Mueller on 10/30/05. +// Copyright 2005 Flying Meat Inc.. All rights reserved. +// + +#import "FMDatabase.h" +#import "FMDatabaseAdditions.h" +#import "TargetConditionals.h" + +@interface FMDatabase (PrivateStuff) +- (FMResultSet *)executeQuery:(NSString *)sql withArgumentsInArray:(NSArray*)arrayArgs orDictionary:(NSDictionary *)dictionaryArgs orVAList:(va_list)args; +@end + +@implementation FMDatabase (FMDatabaseAdditions) + +#define RETURN_RESULT_FOR_QUERY_WITH_SELECTOR(type, sel) \ +va_list args; \ +va_start(args, query); \ +FMResultSet *resultSet = [self executeQuery:query withArgumentsInArray:0x00 orDictionary:0x00 orVAList:args]; \ +va_end(args); \ +if (![resultSet next]) { return (type)0; } \ +type ret = [resultSet sel:0]; \ +[resultSet close]; \ +[resultSet setParentDB:nil]; \ +return ret; + + +- (NSString*)stringForQuery:(NSString*)query, ... { + RETURN_RESULT_FOR_QUERY_WITH_SELECTOR(NSString *, stringForColumnIndex); +} + +- (int)intForQuery:(NSString*)query, ... { + RETURN_RESULT_FOR_QUERY_WITH_SELECTOR(int, intForColumnIndex); +} + +- (long)longForQuery:(NSString*)query, ... { + RETURN_RESULT_FOR_QUERY_WITH_SELECTOR(long, longForColumnIndex); +} + +- (BOOL)boolForQuery:(NSString*)query, ... { + RETURN_RESULT_FOR_QUERY_WITH_SELECTOR(BOOL, boolForColumnIndex); +} + +- (double)doubleForQuery:(NSString*)query, ... { + RETURN_RESULT_FOR_QUERY_WITH_SELECTOR(double, doubleForColumnIndex); +} + +- (NSData*)dataForQuery:(NSString*)query, ... { + RETURN_RESULT_FOR_QUERY_WITH_SELECTOR(NSData *, dataForColumnIndex); +} + +- (NSDate*)dateForQuery:(NSString*)query, ... { + RETURN_RESULT_FOR_QUERY_WITH_SELECTOR(NSDate *, dateForColumnIndex); +} + + +- (BOOL)tableExists:(NSString*)tableName { + + tableName = [tableName lowercaseString]; + + FMResultSet *rs = [self executeQuery:@"select [sql] from sqlite_master where [type] = 'table' and lower(name) = ?", tableName]; + + //if at least one next exists, table exists + BOOL returnBool = [rs next]; + + //close and free object + [rs close]; + + return returnBool; +} + +/* + get table with list of tables: result colums: type[STRING], name[STRING],tbl_name[STRING],rootpage[INTEGER],sql[STRING] + check if table exist in database (patch from OZLB) +*/ +- (FMResultSet*)getSchema { + + //result colums: type[STRING], name[STRING],tbl_name[STRING],rootpage[INTEGER],sql[STRING] + FMResultSet *rs = [self executeQuery:@"SELECT type, name, tbl_name, rootpage, sql FROM (SELECT * FROM sqlite_master UNION ALL SELECT * FROM sqlite_temp_master) WHERE type != 'meta' AND name NOT LIKE 'sqlite_%' ORDER BY tbl_name, type DESC, name"]; + + return rs; +} + +/* + get table schema: result colums: cid[INTEGER], name,type [STRING], notnull[INTEGER], dflt_value[],pk[INTEGER] +*/ +- (FMResultSet*)getTableSchema:(NSString*)tableName { + + //result colums: cid[INTEGER], name,type [STRING], notnull[INTEGER], dflt_value[],pk[INTEGER] + FMResultSet *rs = [self executeQuery:[NSString stringWithFormat: @"pragma table_info('%@')", tableName]]; + + return rs; +} + +- (BOOL)columnExists:(NSString*)columnName inTableWithName:(NSString*)tableName { + + BOOL returnBool = NO; + + tableName = [tableName lowercaseString]; + columnName = [columnName lowercaseString]; + + FMResultSet *rs = [self getTableSchema:tableName]; + + //check if column is present in table schema + while ([rs next]) { + if ([[[rs stringForColumn:@"name"] lowercaseString] isEqualToString:columnName]) { + returnBool = YES; + break; + } + } + + //If this is not done FMDatabase instance stays out of pool + [rs close]; + + return returnBool; +} + + +#if SQLITE_VERSION_NUMBER >= 3007017 + +- (uint32_t)applicationID { + + uint32_t r = 0; + + FMResultSet *rs = [self executeQuery:@"pragma application_id"]; + + if ([rs next]) { + r = (uint32_t)[rs longLongIntForColumnIndex:0]; + } + + [rs close]; + + return r; +} + +- (void)setApplicationID:(uint32_t)appID { + NSString *query = [NSString stringWithFormat:@"pragma application_id=%d", appID]; + FMResultSet *rs = [self executeQuery:query]; + [rs next]; + [rs close]; +} + + +#if TARGET_OS_MAC && !TARGET_OS_IPHONE +- (NSString*)applicationIDString { + NSString *s = NSFileTypeForHFSTypeCode([self applicationID]); + + assert([s length] == 6); + + s = [s substringWithRange:NSMakeRange(1, 4)]; + + + return s; + +} + +- (void)setApplicationIDString:(NSString*)s { + + if ([s length] != 4) { + NSLog(@"setApplicationIDString: string passed is not exactly 4 chars long. (was %ld)", [s length]); + } + + [self setApplicationID:NSHFSTypeCodeFromFileType([NSString stringWithFormat:@"'%@'", s])]; +} + + +#endif + +#endif + +- (uint32_t)userVersion { + uint32_t r = 0; + + FMResultSet *rs = [self executeQuery:@"pragma user_version"]; + + if ([rs next]) { + r = (uint32_t)[rs longLongIntForColumnIndex:0]; + } + + [rs close]; + return r; +} + +- (void)setUserVersion:(uint32_t)version { + NSString *query = [NSString stringWithFormat:@"pragma user_version = %d", version]; + FMResultSet *rs = [self executeQuery:query]; + [rs next]; + [rs close]; +} + +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wdeprecated-implementations" + +- (BOOL)columnExists:(NSString*)tableName columnName:(NSString*)columnName __attribute__ ((deprecated)) { + return [self columnExists:columnName inTableWithName:tableName]; +} + +#pragma clang diagnostic pop + + +- (BOOL)validateSQL:(NSString*)sql error:(NSError**)error { + sqlite3_stmt *pStmt = NULL; + BOOL validationSucceeded = YES; + + int rc = sqlite3_prepare_v2(_db, [sql UTF8String], -1, &pStmt, 0); + if (rc != SQLITE_OK) { + validationSucceeded = NO; + if (error) { + *error = [NSError errorWithDomain:NSCocoaErrorDomain + code:[self lastErrorCode] + userInfo:[NSDictionary dictionaryWithObject:[self lastErrorMessage] + forKey:NSLocalizedDescriptionKey]]; + } + } + + sqlite3_finalize(pStmt); + + return validationSucceeded; +} + +@end diff --git a/ios/Pods/FMDB/src/fmdb/FMDatabasePool.h b/ios/Pods/FMDB/src/fmdb/FMDatabasePool.h new file mode 100644 index 000000000..692b8ae27 --- /dev/null +++ b/ios/Pods/FMDB/src/fmdb/FMDatabasePool.h @@ -0,0 +1,204 @@ +// +// FMDatabasePool.h +// fmdb +// +// Created by August Mueller on 6/22/11. +// Copyright 2011 Flying Meat Inc. All rights reserved. +// + +#import +#import "sqlite3.h" + +@class FMDatabase; + +/** Pool of `` objects. + + ### See also + + - `` + - `` + + @warning Before using `FMDatabasePool`, please consider using `` instead. + + If you really really really know what you're doing and `FMDatabasePool` is what + you really really need (ie, you're using a read only database), OK you can use + it. But just be careful not to deadlock! + + For an example on deadlocking, search for: + `ONLY_USE_THE_POOL_IF_YOU_ARE_DOING_READS_OTHERWISE_YOULL_DEADLOCK_USE_FMDATABASEQUEUE_INSTEAD` + in the main.m file. + */ + +@interface FMDatabasePool : NSObject { + NSString *_path; + + dispatch_queue_t _lockQueue; + + NSMutableArray *_databaseInPool; + NSMutableArray *_databaseOutPool; + + __unsafe_unretained id _delegate; + + NSUInteger _maximumNumberOfDatabasesToCreate; + int _openFlags; +} + +/** Database path */ + +@property (atomic, retain) NSString *path; + +/** Delegate object */ + +@property (atomic, assign) id delegate; + +/** Maximum number of databases to create */ + +@property (atomic, assign) NSUInteger maximumNumberOfDatabasesToCreate; + +/** Open flags */ + +@property (atomic, readonly) int openFlags; + + +///--------------------- +/// @name Initialization +///--------------------- + +/** Create pool using path. + + @param aPath The file path of the database. + + @return The `FMDatabasePool` object. `nil` on error. + */ + ++ (instancetype)databasePoolWithPath:(NSString*)aPath; + +/** Create pool using path and specified flags + + @param aPath The file path of the database. + @param openFlags Flags passed to the openWithFlags method of the database + + @return The `FMDatabasePool` object. `nil` on error. + */ + ++ (instancetype)databasePoolWithPath:(NSString*)aPath flags:(int)openFlags; + +/** Create pool using path. + + @param aPath The file path of the database. + + @return The `FMDatabasePool` object. `nil` on error. + */ + +- (instancetype)initWithPath:(NSString*)aPath; + +/** Create pool using path and specified flags. + + @param aPath The file path of the database. + @param openFlags Flags passed to the openWithFlags method of the database + + @return The `FMDatabasePool` object. `nil` on error. + */ + +- (instancetype)initWithPath:(NSString*)aPath flags:(int)openFlags; + +///------------------------------------------------ +/// @name Keeping track of checked in/out databases +///------------------------------------------------ + +/** Number of checked-in databases in pool + + @returns Number of databases + */ + +- (NSUInteger)countOfCheckedInDatabases; + +/** Number of checked-out databases in pool + + @returns Number of databases + */ + +- (NSUInteger)countOfCheckedOutDatabases; + +/** Total number of databases in pool + + @returns Number of databases + */ + +- (NSUInteger)countOfOpenDatabases; + +/** Release all databases in pool */ + +- (void)releaseAllDatabases; + +///------------------------------------------ +/// @name Perform database operations in pool +///------------------------------------------ + +/** Synchronously perform database operations in pool. + + @param block The code to be run on the `FMDatabasePool` pool. + */ + +- (void)inDatabase:(void (^)(FMDatabase *db))block; + +/** Synchronously perform database operations in pool using transaction. + + @param block The code to be run on the `FMDatabasePool` pool. + */ + +- (void)inTransaction:(void (^)(FMDatabase *db, BOOL *rollback))block; + +/** Synchronously perform database operations in pool using deferred transaction. + + @param block The code to be run on the `FMDatabasePool` pool. + */ + +- (void)inDeferredTransaction:(void (^)(FMDatabase *db, BOOL *rollback))block; + +#if SQLITE_VERSION_NUMBER >= 3007000 + +/** Synchronously perform database operations in pool using save point. + + @param block The code to be run on the `FMDatabasePool` pool. + + @return `NSError` object if error; `nil` if successful. + + @warning You can not nest these, since calling it will pull another database out of the pool and you'll get a deadlock. If you need to nest, use `<[FMDatabase startSavePointWithName:error:]>` instead. +*/ + +- (NSError*)inSavePoint:(void (^)(FMDatabase *db, BOOL *rollback))block; +#endif + +@end + + +/** FMDatabasePool delegate category + + This is a category that defines the protocol for the FMDatabasePool delegate + */ + +@interface NSObject (FMDatabasePoolDelegate) + +/** Asks the delegate whether database should be added to the pool. + + @param pool The `FMDatabasePool` object. + @param database The `FMDatabase` object. + + @return `YES` if it should add database to pool; `NO` if not. + + */ + +- (BOOL)databasePool:(FMDatabasePool*)pool shouldAddDatabaseToPool:(FMDatabase*)database; + +/** Tells the delegate that database was added to the pool. + + @param pool The `FMDatabasePool` object. + @param database The `FMDatabase` object. + + */ + +- (void)databasePool:(FMDatabasePool*)pool didAddDatabase:(FMDatabase*)database; + +@end + diff --git a/ios/Pods/FMDB/src/fmdb/FMDatabasePool.m b/ios/Pods/FMDB/src/fmdb/FMDatabasePool.m new file mode 100644 index 000000000..010e2920f --- /dev/null +++ b/ios/Pods/FMDB/src/fmdb/FMDatabasePool.m @@ -0,0 +1,273 @@ +// +// FMDatabasePool.m +// fmdb +// +// Created by August Mueller on 6/22/11. +// Copyright 2011 Flying Meat Inc. All rights reserved. +// + +#import "FMDatabasePool.h" +#import "FMDatabase.h" + +@interface FMDatabasePool() + +- (void)pushDatabaseBackInPool:(FMDatabase*)db; +- (FMDatabase*)db; + +@end + + +@implementation FMDatabasePool +@synthesize path=_path; +@synthesize delegate=_delegate; +@synthesize maximumNumberOfDatabasesToCreate=_maximumNumberOfDatabasesToCreate; +@synthesize openFlags=_openFlags; + + ++ (instancetype)databasePoolWithPath:(NSString*)aPath { + return FMDBReturnAutoreleased([[self alloc] initWithPath:aPath]); +} + ++ (instancetype)databasePoolWithPath:(NSString*)aPath flags:(int)openFlags { + return FMDBReturnAutoreleased([[self alloc] initWithPath:aPath flags:openFlags]); +} + +- (instancetype)initWithPath:(NSString*)aPath flags:(int)openFlags { + + self = [super init]; + + if (self != nil) { + _path = [aPath copy]; + _lockQueue = dispatch_queue_create([[NSString stringWithFormat:@"fmdb.%@", self] UTF8String], NULL); + _databaseInPool = FMDBReturnRetained([NSMutableArray array]); + _databaseOutPool = FMDBReturnRetained([NSMutableArray array]); + _openFlags = openFlags; + } + + return self; +} + +- (instancetype)initWithPath:(NSString*)aPath +{ + // default flags for sqlite3_open + return [self initWithPath:aPath flags:SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE]; +} + +- (instancetype)init { + return [self initWithPath:nil]; +} + + +- (void)dealloc { + + _delegate = 0x00; + FMDBRelease(_path); + FMDBRelease(_databaseInPool); + FMDBRelease(_databaseOutPool); + + if (_lockQueue) { + FMDBDispatchQueueRelease(_lockQueue); + _lockQueue = 0x00; + } +#if ! __has_feature(objc_arc) + [super dealloc]; +#endif +} + + +- (void)executeLocked:(void (^)(void))aBlock { + dispatch_sync(_lockQueue, aBlock); +} + +- (void)pushDatabaseBackInPool:(FMDatabase*)db { + + if (!db) { // db can be null if we set an upper bound on the # of databases to create. + return; + } + + [self executeLocked:^() { + + if ([self->_databaseInPool containsObject:db]) { + [[NSException exceptionWithName:@"Database already in pool" reason:@"The FMDatabase being put back into the pool is already present in the pool" userInfo:nil] raise]; + } + + [self->_databaseInPool addObject:db]; + [self->_databaseOutPool removeObject:db]; + + }]; +} + +- (FMDatabase*)db { + + __block FMDatabase *db; + + + [self executeLocked:^() { + db = [self->_databaseInPool lastObject]; + + BOOL shouldNotifyDelegate = NO; + + if (db) { + [self->_databaseOutPool addObject:db]; + [self->_databaseInPool removeLastObject]; + } + else { + + if (self->_maximumNumberOfDatabasesToCreate) { + NSUInteger currentCount = [self->_databaseOutPool count] + [self->_databaseInPool count]; + + if (currentCount >= self->_maximumNumberOfDatabasesToCreate) { + NSLog(@"Maximum number of databases (%ld) has already been reached!", (long)currentCount); + return; + } + } + + db = [FMDatabase databaseWithPath:self->_path]; + shouldNotifyDelegate = YES; + } + + //This ensures that the db is opened before returning +#if SQLITE_VERSION_NUMBER >= 3005000 + BOOL success = [db openWithFlags:self->_openFlags]; +#else + BOOL success = [db open]; +#endif + if (success) { + if ([self->_delegate respondsToSelector:@selector(databasePool:shouldAddDatabaseToPool:)] && ![self->_delegate databasePool:self shouldAddDatabaseToPool:db]) { + [db close]; + db = 0x00; + } + else { + //It should not get added in the pool twice if lastObject was found + if (![self->_databaseOutPool containsObject:db]) { + [self->_databaseOutPool addObject:db]; + + if (shouldNotifyDelegate && [self->_delegate respondsToSelector:@selector(databasePool:didAddDatabase:)]) { + [self->_delegate databasePool:self didAddDatabase:db]; + } + } + } + } + else { + NSLog(@"Could not open up the database at path %@", self->_path); + db = 0x00; + } + }]; + + return db; +} + +- (NSUInteger)countOfCheckedInDatabases { + + __block NSUInteger count; + + [self executeLocked:^() { + count = [self->_databaseInPool count]; + }]; + + return count; +} + +- (NSUInteger)countOfCheckedOutDatabases { + + __block NSUInteger count; + + [self executeLocked:^() { + count = [self->_databaseOutPool count]; + }]; + + return count; +} + +- (NSUInteger)countOfOpenDatabases { + __block NSUInteger count; + + [self executeLocked:^() { + count = [self->_databaseOutPool count] + [self->_databaseInPool count]; + }]; + + return count; +} + +- (void)releaseAllDatabases { + [self executeLocked:^() { + [self->_databaseOutPool removeAllObjects]; + [self->_databaseInPool removeAllObjects]; + }]; +} + +- (void)inDatabase:(void (^)(FMDatabase *db))block { + + FMDatabase *db = [self db]; + + block(db); + + [self pushDatabaseBackInPool:db]; +} + +- (void)beginTransaction:(BOOL)useDeferred withBlock:(void (^)(FMDatabase *db, BOOL *rollback))block { + + BOOL shouldRollback = NO; + + FMDatabase *db = [self db]; + + if (useDeferred) { + [db beginDeferredTransaction]; + } + else { + [db beginTransaction]; + } + + + block(db, &shouldRollback); + + if (shouldRollback) { + [db rollback]; + } + else { + [db commit]; + } + + [self pushDatabaseBackInPool:db]; +} + +- (void)inDeferredTransaction:(void (^)(FMDatabase *db, BOOL *rollback))block { + [self beginTransaction:YES withBlock:block]; +} + +- (void)inTransaction:(void (^)(FMDatabase *db, BOOL *rollback))block { + [self beginTransaction:NO withBlock:block]; +} +#if SQLITE_VERSION_NUMBER >= 3007000 +- (NSError*)inSavePoint:(void (^)(FMDatabase *db, BOOL *rollback))block { + + static unsigned long savePointIdx = 0; + + NSString *name = [NSString stringWithFormat:@"savePoint%ld", savePointIdx++]; + + BOOL shouldRollback = NO; + + FMDatabase *db = [self db]; + + NSError *err = 0x00; + + if (![db startSavePointWithName:name error:&err]) { + [self pushDatabaseBackInPool:db]; + return err; + } + + block(db, &shouldRollback); + + if (shouldRollback) { + // We need to rollback and release this savepoint to remove it + [db rollbackToSavePointWithName:name error:&err]; + } + [db releaseSavePointWithName:name error:&err]; + + [self pushDatabaseBackInPool:db]; + + return err; +} +#endif + +@end diff --git a/ios/Pods/FMDB/src/fmdb/FMDatabaseQueue.h b/ios/Pods/FMDB/src/fmdb/FMDatabaseQueue.h new file mode 100644 index 000000000..34c0750d1 --- /dev/null +++ b/ios/Pods/FMDB/src/fmdb/FMDatabaseQueue.h @@ -0,0 +1,174 @@ +// +// FMDatabaseQueue.h +// fmdb +// +// Created by August Mueller on 6/22/11. +// Copyright 2011 Flying Meat Inc. All rights reserved. +// + +#import +#import "sqlite3.h" + +@class FMDatabase; + +/** To perform queries and updates on multiple threads, you'll want to use `FMDatabaseQueue`. + + Using a single instance of `` from multiple threads at once is a bad idea. It has always been OK to make a `` object *per thread*. Just don't share a single instance across threads, and definitely not across multiple threads at the same time. + + Instead, use `FMDatabaseQueue`. Here's how to use it: + + First, make your queue. + + FMDatabaseQueue *queue = [FMDatabaseQueue databaseQueueWithPath:aPath]; + + Then use it like so: + + [queue inDatabase:^(FMDatabase *db) { + [db executeUpdate:@"INSERT INTO myTable VALUES (?)", [NSNumber numberWithInt:1]]; + [db executeUpdate:@"INSERT INTO myTable VALUES (?)", [NSNumber numberWithInt:2]]; + [db executeUpdate:@"INSERT INTO myTable VALUES (?)", [NSNumber numberWithInt:3]]; + + FMResultSet *rs = [db executeQuery:@"select * from foo"]; + while ([rs next]) { + //… + } + }]; + + An easy way to wrap things up in a transaction can be done like this: + + [queue inTransaction:^(FMDatabase *db, BOOL *rollback) { + [db executeUpdate:@"INSERT INTO myTable VALUES (?)", [NSNumber numberWithInt:1]]; + [db executeUpdate:@"INSERT INTO myTable VALUES (?)", [NSNumber numberWithInt:2]]; + [db executeUpdate:@"INSERT INTO myTable VALUES (?)", [NSNumber numberWithInt:3]]; + + if (whoopsSomethingWrongHappened) { + *rollback = YES; + return; + } + // etc… + [db executeUpdate:@"INSERT INTO myTable VALUES (?)", [NSNumber numberWithInt:4]]; + }]; + + `FMDatabaseQueue` will run the blocks on a serialized queue (hence the name of the class). So if you call `FMDatabaseQueue`'s methods from multiple threads at the same time, they will be executed in the order they are received. This way queries and updates won't step on each other's toes, and every one is happy. + + ### See also + + - `` + + @warning Do not instantiate a single `` object and use it across multiple threads. Use `FMDatabaseQueue` instead. + + @warning The calls to `FMDatabaseQueue`'s methods are blocking. So even though you are passing along blocks, they will **not** be run on another thread. + + */ + +@interface FMDatabaseQueue : NSObject { + NSString *_path; + dispatch_queue_t _queue; + FMDatabase *_db; + int _openFlags; +} + +/** Path of database */ + +@property (atomic, retain) NSString *path; + +/** Open flags */ + +@property (atomic, readonly) int openFlags; + +///---------------------------------------------------- +/// @name Initialization, opening, and closing of queue +///---------------------------------------------------- + +/** Create queue using path. + + @param aPath The file path of the database. + + @return The `FMDatabaseQueue` object. `nil` on error. + */ + ++ (instancetype)databaseQueueWithPath:(NSString*)aPath; + +/** Create queue using path and specified flags. + + @param aPath The file path of the database. + @param openFlags Flags passed to the openWithFlags method of the database + + @return The `FMDatabaseQueue` object. `nil` on error. + */ ++ (instancetype)databaseQueueWithPath:(NSString*)aPath flags:(int)openFlags; + +/** Create queue using path. + + @param aPath The file path of the database. + + @return The `FMDatabaseQueue` object. `nil` on error. + */ + +- (instancetype)initWithPath:(NSString*)aPath; + +/** Create queue using path and specified flags. + + @param aPath The file path of the database. + @param openFlags Flags passed to the openWithFlags method of the database + + @return The `FMDatabaseQueue` object. `nil` on error. + */ + +- (instancetype)initWithPath:(NSString*)aPath flags:(int)openFlags; + +/** Returns the Class of 'FMDatabase' subclass, that will be used to instantiate database object. + + Subclasses can override this method to return specified Class of 'FMDatabase' subclass. + + @return The Class of 'FMDatabase' subclass, that will be used to instantiate database object. + */ + ++ (Class)databaseClass; + +/** Close database used by queue. */ + +- (void)close; + +///----------------------------------------------- +/// @name Dispatching database operations to queue +///----------------------------------------------- + +/** Synchronously perform database operations on queue. + + @param block The code to be run on the queue of `FMDatabaseQueue` + */ + +- (void)inDatabase:(void (^)(FMDatabase *db))block; + +/** Synchronously perform database operations on queue, using transactions. + + @param block The code to be run on the queue of `FMDatabaseQueue` + */ + +- (void)inTransaction:(void (^)(FMDatabase *db, BOOL *rollback))block; + +/** Synchronously perform database operations on queue, using deferred transactions. + + @param block The code to be run on the queue of `FMDatabaseQueue` + */ + +- (void)inDeferredTransaction:(void (^)(FMDatabase *db, BOOL *rollback))block; + +///----------------------------------------------- +/// @name Dispatching database operations to queue +///----------------------------------------------- + +/** Synchronously perform database operations using save point. + + @param block The code to be run on the queue of `FMDatabaseQueue` + */ + +#if SQLITE_VERSION_NUMBER >= 3007000 +// NOTE: you can not nest these, since calling it will pull another database out of the pool and you'll get a deadlock. +// If you need to nest, use FMDatabase's startSavePointWithName:error: instead. +- (NSError*)inSavePoint:(void (^)(FMDatabase *db, BOOL *rollback))block; +#endif + +@end + diff --git a/ios/Pods/FMDB/src/fmdb/FMDatabaseQueue.m b/ios/Pods/FMDB/src/fmdb/FMDatabaseQueue.m new file mode 100644 index 000000000..7c128735a --- /dev/null +++ b/ios/Pods/FMDB/src/fmdb/FMDatabaseQueue.m @@ -0,0 +1,232 @@ +// +// FMDatabaseQueue.m +// fmdb +// +// Created by August Mueller on 6/22/11. +// Copyright 2011 Flying Meat Inc. All rights reserved. +// + +#import "FMDatabaseQueue.h" +#import "FMDatabase.h" + +/* + + Note: we call [self retain]; before using dispatch_sync, just incase + FMDatabaseQueue is released on another thread and we're in the middle of doing + something in dispatch_sync + + */ + +/* + * A key used to associate the FMDatabaseQueue object with the dispatch_queue_t it uses. + * This in turn is used for deadlock detection by seeing if inDatabase: is called on + * the queue's dispatch queue, which should not happen and causes a deadlock. + */ +static const void * const kDispatchQueueSpecificKey = &kDispatchQueueSpecificKey; + +@implementation FMDatabaseQueue + +@synthesize path = _path; +@synthesize openFlags = _openFlags; + ++ (instancetype)databaseQueueWithPath:(NSString*)aPath { + + FMDatabaseQueue *q = [[self alloc] initWithPath:aPath]; + + FMDBAutorelease(q); + + return q; +} + ++ (instancetype)databaseQueueWithPath:(NSString*)aPath flags:(int)openFlags { + + FMDatabaseQueue *q = [[self alloc] initWithPath:aPath flags:openFlags]; + + FMDBAutorelease(q); + + return q; +} + ++ (Class)databaseClass { + return [FMDatabase class]; +} + +- (instancetype)initWithPath:(NSString*)aPath flags:(int)openFlags { + + self = [super init]; + + if (self != nil) { + + _db = [[[self class] databaseClass] databaseWithPath:aPath]; + FMDBRetain(_db); + +#if SQLITE_VERSION_NUMBER >= 3005000 + BOOL success = [_db openWithFlags:openFlags]; +#else + BOOL success = [_db open]; +#endif + if (!success) { + NSLog(@"Could not create database queue for path %@", aPath); + FMDBRelease(self); + return 0x00; + } + + _path = FMDBReturnRetained(aPath); + + _queue = dispatch_queue_create([[NSString stringWithFormat:@"fmdb.%@", self] UTF8String], NULL); + dispatch_queue_set_specific(_queue, kDispatchQueueSpecificKey, (__bridge void *)self, NULL); + _openFlags = openFlags; + } + + return self; +} + +- (instancetype)initWithPath:(NSString*)aPath { + + // default flags for sqlite3_open + return [self initWithPath:aPath flags:SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE]; +} + +- (instancetype)init { + return [self initWithPath:nil]; +} + + +- (void)dealloc { + + FMDBRelease(_db); + FMDBRelease(_path); + + if (_queue) { + FMDBDispatchQueueRelease(_queue); + _queue = 0x00; + } +#if ! __has_feature(objc_arc) + [super dealloc]; +#endif +} + +- (void)close { + FMDBRetain(self); + dispatch_sync(_queue, ^() { + [self->_db close]; + FMDBRelease(_db); + self->_db = 0x00; + }); + FMDBRelease(self); +} + +- (FMDatabase*)database { + if (!_db) { + _db = FMDBReturnRetained([FMDatabase databaseWithPath:_path]); + +#if SQLITE_VERSION_NUMBER >= 3005000 + BOOL success = [_db openWithFlags:_openFlags]; +#else + BOOL success = [db open]; +#endif + if (!success) { + NSLog(@"FMDatabaseQueue could not reopen database for path %@", _path); + FMDBRelease(_db); + _db = 0x00; + return 0x00; + } + } + + return _db; +} + +- (void)inDatabase:(void (^)(FMDatabase *db))block { + /* Get the currently executing queue (which should probably be nil, but in theory could be another DB queue + * and then check it against self to make sure we're not about to deadlock. */ + FMDatabaseQueue *currentSyncQueue = (__bridge id)dispatch_get_specific(kDispatchQueueSpecificKey); + assert(currentSyncQueue != self && "inDatabase: was called reentrantly on the same queue, which would lead to a deadlock"); + + FMDBRetain(self); + + dispatch_sync(_queue, ^() { + + FMDatabase *db = [self database]; + block(db); + + if ([db hasOpenResultSets]) { + NSLog(@"Warning: there is at least one open result set around after performing [FMDatabaseQueue inDatabase:]"); + +#if defined(DEBUG) && DEBUG + NSSet *openSetCopy = FMDBReturnAutoreleased([[db valueForKey:@"_openResultSets"] copy]); + for (NSValue *rsInWrappedInATastyValueMeal in openSetCopy) { + FMResultSet *rs = (FMResultSet *)[rsInWrappedInATastyValueMeal pointerValue]; + NSLog(@"query: '%@'", [rs query]); + } +#endif + } + }); + + FMDBRelease(self); +} + + +- (void)beginTransaction:(BOOL)useDeferred withBlock:(void (^)(FMDatabase *db, BOOL *rollback))block { + FMDBRetain(self); + dispatch_sync(_queue, ^() { + + BOOL shouldRollback = NO; + + if (useDeferred) { + [[self database] beginDeferredTransaction]; + } + else { + [[self database] beginTransaction]; + } + + block([self database], &shouldRollback); + + if (shouldRollback) { + [[self database] rollback]; + } + else { + [[self database] commit]; + } + }); + + FMDBRelease(self); +} + +- (void)inDeferredTransaction:(void (^)(FMDatabase *db, BOOL *rollback))block { + [self beginTransaction:YES withBlock:block]; +} + +- (void)inTransaction:(void (^)(FMDatabase *db, BOOL *rollback))block { + [self beginTransaction:NO withBlock:block]; +} + +#if SQLITE_VERSION_NUMBER >= 3007000 +- (NSError*)inSavePoint:(void (^)(FMDatabase *db, BOOL *rollback))block { + + static unsigned long savePointIdx = 0; + __block NSError *err = 0x00; + FMDBRetain(self); + dispatch_sync(_queue, ^() { + + NSString *name = [NSString stringWithFormat:@"savePoint%ld", savePointIdx++]; + + BOOL shouldRollback = NO; + + if ([[self database] startSavePointWithName:name error:&err]) { + + block([self database], &shouldRollback); + + if (shouldRollback) { + // We need to rollback and release this savepoint to remove it + [[self database] rollbackToSavePointWithName:name error:&err]; + } + [[self database] releaseSavePointWithName:name error:&err]; + + } + }); + FMDBRelease(self); + return err; +} +#endif + +@end diff --git a/ios/Pods/FMDB/src/fmdb/FMResultSet.h b/ios/Pods/FMDB/src/fmdb/FMResultSet.h new file mode 100644 index 000000000..8585a6984 --- /dev/null +++ b/ios/Pods/FMDB/src/fmdb/FMResultSet.h @@ -0,0 +1,456 @@ +#import +#import "sqlite3.h" + +#ifndef __has_feature // Optional. +#define __has_feature(x) 0 // Compatibility with non-clang compilers. +#endif + +#ifndef NS_RETURNS_NOT_RETAINED +#if __has_feature(attribute_ns_returns_not_retained) +#define NS_RETURNS_NOT_RETAINED __attribute__((ns_returns_not_retained)) +#else +#define NS_RETURNS_NOT_RETAINED +#endif +#endif + +@class FMDatabase; +@class FMStatement; + +/** Represents the results of executing a query on an ``. + + ### See also + + - `` + */ + +@interface FMResultSet : NSObject { + FMDatabase *_parentDB; + FMStatement *_statement; + + NSString *_query; + NSMutableDictionary *_columnNameToIndexMap; +} + +///----------------- +/// @name Properties +///----------------- + +/** Executed query */ + +@property (atomic, retain) NSString *query; + +/** `NSMutableDictionary` mapping column names to numeric index */ + +@property (readonly) NSMutableDictionary *columnNameToIndexMap; + +/** `FMStatement` used by result set. */ + +@property (atomic, retain) FMStatement *statement; + +///------------------------------------ +/// @name Creating and closing database +///------------------------------------ + +/** Create result set from `` + + @param statement A `` to be performed + + @param aDB A `` to be used + + @return A `FMResultSet` on success; `nil` on failure + */ + ++ (instancetype)resultSetWithStatement:(FMStatement *)statement usingParentDatabase:(FMDatabase*)aDB; + +/** Close result set */ + +- (void)close; + +- (void)setParentDB:(FMDatabase *)newDb; + +///--------------------------------------- +/// @name Iterating through the result set +///--------------------------------------- + +/** Retrieve next row for result set. + + You must always invoke `next` before attempting to access the values returned in a query, even if you're only expecting one. + + @return `YES` if row successfully retrieved; `NO` if end of result set reached + + @see hasAnotherRow + */ + +- (BOOL)next; + +/** Did the last call to `` succeed in retrieving another row? + + @return `YES` if the last call to `` succeeded in retrieving another record; `NO` if not. + + @see next + + @warning The `hasAnotherRow` method must follow a call to ``. If the previous database interaction was something other than a call to `next`, then this method may return `NO`, whether there is another row of data or not. + */ + +- (BOOL)hasAnotherRow; + +///--------------------------------------------- +/// @name Retrieving information from result set +///--------------------------------------------- + +/** How many columns in result set + + @return Integer value of the number of columns. + */ + +- (int)columnCount; + +/** Column index for column name + + @param columnName `NSString` value of the name of the column. + + @return Zero-based index for column. + */ + +- (int)columnIndexForName:(NSString*)columnName; + +/** Column name for column index + + @param columnIdx Zero-based index for column. + + @return columnName `NSString` value of the name of the column. + */ + +- (NSString*)columnNameForIndex:(int)columnIdx; + +/** Result set integer value for column. + + @param columnName `NSString` value of the name of the column. + + @return `int` value of the result set's column. + */ + +- (int)intForColumn:(NSString*)columnName; + +/** Result set integer value for column. + + @param columnIdx Zero-based index for column. + + @return `int` value of the result set's column. + */ + +- (int)intForColumnIndex:(int)columnIdx; + +/** Result set `long` value for column. + + @param columnName `NSString` value of the name of the column. + + @return `long` value of the result set's column. + */ + +- (long)longForColumn:(NSString*)columnName; + +/** Result set long value for column. + + @param columnIdx Zero-based index for column. + + @return `long` value of the result set's column. + */ + +- (long)longForColumnIndex:(int)columnIdx; + +/** Result set `long long int` value for column. + + @param columnName `NSString` value of the name of the column. + + @return `long long int` value of the result set's column. + */ + +- (long long int)longLongIntForColumn:(NSString*)columnName; + +/** Result set `long long int` value for column. + + @param columnIdx Zero-based index for column. + + @return `long long int` value of the result set's column. + */ + +- (long long int)longLongIntForColumnIndex:(int)columnIdx; + +/** Result set `unsigned long long int` value for column. + + @param columnName `NSString` value of the name of the column. + + @return `unsigned long long int` value of the result set's column. + */ + +- (unsigned long long int)unsignedLongLongIntForColumn:(NSString*)columnName; + +/** Result set `unsigned long long int` value for column. + + @param columnIdx Zero-based index for column. + + @return `unsigned long long int` value of the result set's column. + */ + +- (unsigned long long int)unsignedLongLongIntForColumnIndex:(int)columnIdx; + +/** Result set `BOOL` value for column. + + @param columnName `NSString` value of the name of the column. + + @return `BOOL` value of the result set's column. + */ + +- (BOOL)boolForColumn:(NSString*)columnName; + +/** Result set `BOOL` value for column. + + @param columnIdx Zero-based index for column. + + @return `BOOL` value of the result set's column. + */ + +- (BOOL)boolForColumnIndex:(int)columnIdx; + +/** Result set `double` value for column. + + @param columnName `NSString` value of the name of the column. + + @return `double` value of the result set's column. + + */ + +- (double)doubleForColumn:(NSString*)columnName; + +/** Result set `double` value for column. + + @param columnIdx Zero-based index for column. + + @return `double` value of the result set's column. + + */ + +- (double)doubleForColumnIndex:(int)columnIdx; + +/** Result set `NSString` value for column. + + @param columnName `NSString` value of the name of the column. + + @return `NSString` value of the result set's column. + + */ + +- (NSString*)stringForColumn:(NSString*)columnName; + +/** Result set `NSString` value for column. + + @param columnIdx Zero-based index for column. + + @return `NSString` value of the result set's column. + */ + +- (NSString*)stringForColumnIndex:(int)columnIdx; + +/** Result set `NSDate` value for column. + + @param columnName `NSString` value of the name of the column. + + @return `NSDate` value of the result set's column. + */ + +- (NSDate*)dateForColumn:(NSString*)columnName; + +/** Result set `NSDate` value for column. + + @param columnIdx Zero-based index for column. + + @return `NSDate` value of the result set's column. + + */ + +- (NSDate*)dateForColumnIndex:(int)columnIdx; + +/** Result set `NSData` value for column. + + This is useful when storing binary data in table (such as image or the like). + + @param columnName `NSString` value of the name of the column. + + @return `NSData` value of the result set's column. + + */ + +- (NSData*)dataForColumn:(NSString*)columnName; + +/** Result set `NSData` value for column. + + @param columnIdx Zero-based index for column. + + @return `NSData` value of the result set's column. + */ + +- (NSData*)dataForColumnIndex:(int)columnIdx; + +/** Result set `(const unsigned char *)` value for column. + + @param columnName `NSString` value of the name of the column. + + @return `(const unsigned char *)` value of the result set's column. + */ + +- (const unsigned char *)UTF8StringForColumnName:(NSString*)columnName; + +/** Result set `(const unsigned char *)` value for column. + + @param columnIdx Zero-based index for column. + + @return `(const unsigned char *)` value of the result set's column. + */ + +- (const unsigned char *)UTF8StringForColumnIndex:(int)columnIdx; + +/** Result set object for column. + + @param columnName `NSString` value of the name of the column. + + @return Either `NSNumber`, `NSString`, `NSData`, or `NSNull`. If the column was `NULL`, this returns `[NSNull null]` object. + + @see objectForKeyedSubscript: + */ + +- (id)objectForColumnName:(NSString*)columnName; + +/** Result set object for column. + + @param columnIdx Zero-based index for column. + + @return Either `NSNumber`, `NSString`, `NSData`, or `NSNull`. If the column was `NULL`, this returns `[NSNull null]` object. + + @see objectAtIndexedSubscript: + */ + +- (id)objectForColumnIndex:(int)columnIdx; + +/** Result set object for column. + + This method allows the use of the "boxed" syntax supported in Modern Objective-C. For example, by defining this method, the following syntax is now supported: + + id result = rs[@"employee_name"]; + + This simplified syntax is equivalent to calling: + + id result = [rs objectForKeyedSubscript:@"employee_name"]; + + which is, it turns out, equivalent to calling: + + id result = [rs objectForColumnName:@"employee_name"]; + + @param columnName `NSString` value of the name of the column. + + @return Either `NSNumber`, `NSString`, `NSData`, or `NSNull`. If the column was `NULL`, this returns `[NSNull null]` object. + */ + +- (id)objectForKeyedSubscript:(NSString *)columnName; + +/** Result set object for column. + + This method allows the use of the "boxed" syntax supported in Modern Objective-C. For example, by defining this method, the following syntax is now supported: + + id result = rs[0]; + + This simplified syntax is equivalent to calling: + + id result = [rs objectForKeyedSubscript:0]; + + which is, it turns out, equivalent to calling: + + id result = [rs objectForColumnName:0]; + + @param columnIdx Zero-based index for column. + + @return Either `NSNumber`, `NSString`, `NSData`, or `NSNull`. If the column was `NULL`, this returns `[NSNull null]` object. + */ + +- (id)objectAtIndexedSubscript:(int)columnIdx; + +/** Result set `NSData` value for column. + + @param columnName `NSString` value of the name of the column. + + @return `NSData` value of the result set's column. + + @warning If you are going to use this data after you iterate over the next row, or after you close the +result set, make sure to make a copy of the data first (or just use ``/``) +If you don't, you're going to be in a world of hurt when you try and use the data. + + */ + +- (NSData*)dataNoCopyForColumn:(NSString*)columnName NS_RETURNS_NOT_RETAINED; + +/** Result set `NSData` value for column. + + @param columnIdx Zero-based index for column. + + @return `NSData` value of the result set's column. + + @warning If you are going to use this data after you iterate over the next row, or after you close the + result set, make sure to make a copy of the data first (or just use ``/``) + If you don't, you're going to be in a world of hurt when you try and use the data. + + */ + +- (NSData*)dataNoCopyForColumnIndex:(int)columnIdx NS_RETURNS_NOT_RETAINED; + +/** Is the column `NULL`? + + @param columnIdx Zero-based index for column. + + @return `YES` if column is `NULL`; `NO` if not `NULL`. + */ + +- (BOOL)columnIndexIsNull:(int)columnIdx; + +/** Is the column `NULL`? + + @param columnName `NSString` value of the name of the column. + + @return `YES` if column is `NULL`; `NO` if not `NULL`. + */ + +- (BOOL)columnIsNull:(NSString*)columnName; + + +/** Returns a dictionary of the row results mapped to case sensitive keys of the column names. + + @returns `NSDictionary` of the row results. + + @warning The keys to the dictionary are case sensitive of the column names. + */ + +- (NSDictionary*)resultDictionary; + +/** Returns a dictionary of the row results + + @see resultDictionary + + @warning **Deprecated**: Please use `` instead. Also, beware that `` is case sensitive! + */ + +- (NSDictionary*)resultDict __attribute__ ((deprecated)); + +///----------------------------- +/// @name Key value coding magic +///----------------------------- + +/** Performs `setValue` to yield support for key value observing. + + @param object The object for which the values will be set. This is the key-value-coding compliant object that you might, for example, observe. + + */ + +- (void)kvcMagic:(id)object; + + +@end + diff --git a/ios/Pods/FMDB/src/fmdb/FMResultSet.m b/ios/Pods/FMDB/src/fmdb/FMResultSet.m new file mode 100644 index 000000000..9d6c6e17d --- /dev/null +++ b/ios/Pods/FMDB/src/fmdb/FMResultSet.m @@ -0,0 +1,390 @@ +#import "FMResultSet.h" +#import "FMDatabase.h" +#import "unistd.h" + +@interface FMDatabase () +- (void)resultSetDidClose:(FMResultSet *)resultSet; +@end + + +@implementation FMResultSet +@synthesize query=_query; +@synthesize statement=_statement; + ++ (instancetype)resultSetWithStatement:(FMStatement *)statement usingParentDatabase:(FMDatabase*)aDB { + + FMResultSet *rs = [[FMResultSet alloc] init]; + + [rs setStatement:statement]; + [rs setParentDB:aDB]; + + NSParameterAssert(![statement inUse]); + [statement setInUse:YES]; // weak reference + + return FMDBReturnAutoreleased(rs); +} + +- (void)finalize { + [self close]; + [super finalize]; +} + +- (void)dealloc { + [self close]; + + FMDBRelease(_query); + _query = nil; + + FMDBRelease(_columnNameToIndexMap); + _columnNameToIndexMap = nil; + +#if ! __has_feature(objc_arc) + [super dealloc]; +#endif +} + +- (void)close { + [_statement reset]; + FMDBRelease(_statement); + _statement = nil; + + // we don't need this anymore... (i think) + //[_parentDB setInUse:NO]; + [_parentDB resultSetDidClose:self]; + _parentDB = nil; +} + +- (int)columnCount { + return sqlite3_column_count([_statement statement]); +} + +- (NSMutableDictionary *)columnNameToIndexMap { + if (!_columnNameToIndexMap) { + int columnCount = sqlite3_column_count([_statement statement]); + _columnNameToIndexMap = [[NSMutableDictionary alloc] initWithCapacity:(NSUInteger)columnCount]; + int columnIdx = 0; + for (columnIdx = 0; columnIdx < columnCount; columnIdx++) { + [_columnNameToIndexMap setObject:[NSNumber numberWithInt:columnIdx] + forKey:[[NSString stringWithUTF8String:sqlite3_column_name([_statement statement], columnIdx)] lowercaseString]]; + } + } + return _columnNameToIndexMap; +} + +- (void)kvcMagic:(id)object { + + int columnCount = sqlite3_column_count([_statement statement]); + + int columnIdx = 0; + for (columnIdx = 0; columnIdx < columnCount; columnIdx++) { + + const char *c = (const char *)sqlite3_column_text([_statement statement], columnIdx); + + // check for a null row + if (c) { + NSString *s = [NSString stringWithUTF8String:c]; + + [object setValue:s forKey:[NSString stringWithUTF8String:sqlite3_column_name([_statement statement], columnIdx)]]; + } + } +} + +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wdeprecated-implementations" + +- (NSDictionary*)resultDict { + + NSUInteger num_cols = (NSUInteger)sqlite3_data_count([_statement statement]); + + if (num_cols > 0) { + NSMutableDictionary *dict = [NSMutableDictionary dictionaryWithCapacity:num_cols]; + + NSEnumerator *columnNames = [[self columnNameToIndexMap] keyEnumerator]; + NSString *columnName = nil; + while ((columnName = [columnNames nextObject])) { + id objectValue = [self objectForColumnName:columnName]; + [dict setObject:objectValue forKey:columnName]; + } + + return FMDBReturnAutoreleased([dict copy]); + } + else { + NSLog(@"Warning: There seem to be no columns in this set."); + } + + return nil; +} + +#pragma clang diagnostic pop + +- (NSDictionary*)resultDictionary { + + NSUInteger num_cols = (NSUInteger)sqlite3_data_count([_statement statement]); + + if (num_cols > 0) { + NSMutableDictionary *dict = [NSMutableDictionary dictionaryWithCapacity:num_cols]; + + int columnCount = sqlite3_column_count([_statement statement]); + + int columnIdx = 0; + for (columnIdx = 0; columnIdx < columnCount; columnIdx++) { + + NSString *columnName = [NSString stringWithUTF8String:sqlite3_column_name([_statement statement], columnIdx)]; + id objectValue = [self objectForColumnIndex:columnIdx]; + [dict setObject:objectValue forKey:columnName]; + } + + return dict; + } + else { + NSLog(@"Warning: There seem to be no columns in this set."); + } + + return nil; +} + + + + +- (BOOL)next { + + int rc = sqlite3_step([_statement statement]); + + if (SQLITE_BUSY == rc || SQLITE_LOCKED == rc) { + NSLog(@"%s:%d Database busy (%@)", __FUNCTION__, __LINE__, [_parentDB databasePath]); + NSLog(@"Database busy"); + } + else if (SQLITE_DONE == rc || SQLITE_ROW == rc) { + // all is well, let's return. + } + else if (SQLITE_ERROR == rc) { + NSLog(@"Error calling sqlite3_step (%d: %s) rs", rc, sqlite3_errmsg([_parentDB sqliteHandle])); + } + else if (SQLITE_MISUSE == rc) { + // uh oh. + NSLog(@"Error calling sqlite3_step (%d: %s) rs", rc, sqlite3_errmsg([_parentDB sqliteHandle])); + } + else { + // wtf? + NSLog(@"Unknown error calling sqlite3_step (%d: %s) rs", rc, sqlite3_errmsg([_parentDB sqliteHandle])); + } + + + if (rc != SQLITE_ROW) { + [self close]; + } + + return (rc == SQLITE_ROW); +} + +- (BOOL)hasAnotherRow { + return sqlite3_errcode([_parentDB sqliteHandle]) == SQLITE_ROW; +} + +- (int)columnIndexForName:(NSString*)columnName { + columnName = [columnName lowercaseString]; + + NSNumber *n = [[self columnNameToIndexMap] objectForKey:columnName]; + + if (n) { + return [n intValue]; + } + + NSLog(@"Warning: I could not find the column named '%@'.", columnName); + + return -1; +} + + + +- (int)intForColumn:(NSString*)columnName { + return [self intForColumnIndex:[self columnIndexForName:columnName]]; +} + +- (int)intForColumnIndex:(int)columnIdx { + return sqlite3_column_int([_statement statement], columnIdx); +} + +- (long)longForColumn:(NSString*)columnName { + return [self longForColumnIndex:[self columnIndexForName:columnName]]; +} + +- (long)longForColumnIndex:(int)columnIdx { + return (long)sqlite3_column_int64([_statement statement], columnIdx); +} + +- (long long int)longLongIntForColumn:(NSString*)columnName { + return [self longLongIntForColumnIndex:[self columnIndexForName:columnName]]; +} + +- (long long int)longLongIntForColumnIndex:(int)columnIdx { + return sqlite3_column_int64([_statement statement], columnIdx); +} + +- (unsigned long long int)unsignedLongLongIntForColumn:(NSString*)columnName { + return [self unsignedLongLongIntForColumnIndex:[self columnIndexForName:columnName]]; +} + +- (unsigned long long int)unsignedLongLongIntForColumnIndex:(int)columnIdx { + return (unsigned long long int)[self longLongIntForColumnIndex:columnIdx]; +} + +- (BOOL)boolForColumn:(NSString*)columnName { + return [self boolForColumnIndex:[self columnIndexForName:columnName]]; +} + +- (BOOL)boolForColumnIndex:(int)columnIdx { + return ([self intForColumnIndex:columnIdx] != 0); +} + +- (double)doubleForColumn:(NSString*)columnName { + return [self doubleForColumnIndex:[self columnIndexForName:columnName]]; +} + +- (double)doubleForColumnIndex:(int)columnIdx { + return sqlite3_column_double([_statement statement], columnIdx); +} + +- (NSString*)stringForColumnIndex:(int)columnIdx { + + if (sqlite3_column_type([_statement statement], columnIdx) == SQLITE_NULL || (columnIdx < 0)) { + return nil; + } + + const char *c = (const char *)sqlite3_column_text([_statement statement], columnIdx); + + if (!c) { + // null row. + return nil; + } + + return [NSString stringWithUTF8String:c]; +} + +- (NSString*)stringForColumn:(NSString*)columnName { + return [self stringForColumnIndex:[self columnIndexForName:columnName]]; +} + +- (NSDate*)dateForColumn:(NSString*)columnName { + return [self dateForColumnIndex:[self columnIndexForName:columnName]]; +} + +- (NSDate*)dateForColumnIndex:(int)columnIdx { + + if (sqlite3_column_type([_statement statement], columnIdx) == SQLITE_NULL || (columnIdx < 0)) { + return nil; + } + + return [_parentDB hasDateFormatter] ? [_parentDB dateFromString:[self stringForColumnIndex:columnIdx]] : [NSDate dateWithTimeIntervalSince1970:[self doubleForColumnIndex:columnIdx]]; +} + + +- (NSData*)dataForColumn:(NSString*)columnName { + return [self dataForColumnIndex:[self columnIndexForName:columnName]]; +} + +- (NSData*)dataForColumnIndex:(int)columnIdx { + + if (sqlite3_column_type([_statement statement], columnIdx) == SQLITE_NULL || (columnIdx < 0)) { + return nil; + } + + int dataSize = sqlite3_column_bytes([_statement statement], columnIdx); + const char *dataBuffer = sqlite3_column_blob([_statement statement], columnIdx); + + if (dataBuffer == NULL) { + return nil; + } + + return [NSData dataWithBytes:(const void *)dataBuffer length:(NSUInteger)dataSize]; +} + + +- (NSData*)dataNoCopyForColumn:(NSString*)columnName { + return [self dataNoCopyForColumnIndex:[self columnIndexForName:columnName]]; +} + +- (NSData*)dataNoCopyForColumnIndex:(int)columnIdx { + + if (sqlite3_column_type([_statement statement], columnIdx) == SQLITE_NULL || (columnIdx < 0)) { + return nil; + } + + int dataSize = sqlite3_column_bytes([_statement statement], columnIdx); + + NSData *data = [NSData dataWithBytesNoCopy:(void *)sqlite3_column_blob([_statement statement], columnIdx) length:(NSUInteger)dataSize freeWhenDone:NO]; + + return data; +} + + +- (BOOL)columnIndexIsNull:(int)columnIdx { + return sqlite3_column_type([_statement statement], columnIdx) == SQLITE_NULL; +} + +- (BOOL)columnIsNull:(NSString*)columnName { + return [self columnIndexIsNull:[self columnIndexForName:columnName]]; +} + +- (const unsigned char *)UTF8StringForColumnIndex:(int)columnIdx { + + if (sqlite3_column_type([_statement statement], columnIdx) == SQLITE_NULL || (columnIdx < 0)) { + return nil; + } + + return sqlite3_column_text([_statement statement], columnIdx); +} + +- (const unsigned char *)UTF8StringForColumnName:(NSString*)columnName { + return [self UTF8StringForColumnIndex:[self columnIndexForName:columnName]]; +} + +- (id)objectForColumnIndex:(int)columnIdx { + int columnType = sqlite3_column_type([_statement statement], columnIdx); + + id returnValue = nil; + + if (columnType == SQLITE_INTEGER) { + returnValue = [NSNumber numberWithLongLong:[self longLongIntForColumnIndex:columnIdx]]; + } + else if (columnType == SQLITE_FLOAT) { + returnValue = [NSNumber numberWithDouble:[self doubleForColumnIndex:columnIdx]]; + } + else if (columnType == SQLITE_BLOB) { + returnValue = [self dataForColumnIndex:columnIdx]; + } + else { + //default to a string for everything else + returnValue = [self stringForColumnIndex:columnIdx]; + } + + if (returnValue == nil) { + returnValue = [NSNull null]; + } + + return returnValue; +} + +- (id)objectForColumnName:(NSString*)columnName { + return [self objectForColumnIndex:[self columnIndexForName:columnName]]; +} + +// returns autoreleased NSString containing the name of the column in the result set +- (NSString*)columnNameForIndex:(int)columnIdx { + return [NSString stringWithUTF8String: sqlite3_column_name([_statement statement], columnIdx)]; +} + +- (void)setParentDB:(FMDatabase *)newDb { + _parentDB = newDb; +} + +- (id)objectAtIndexedSubscript:(int)columnIdx { + return [self objectForColumnIndex:columnIdx]; +} + +- (id)objectForKeyedSubscript:(NSString *)columnName { + return [self objectForColumnName:columnName]; +} + + +@end diff --git a/ios/Pods/HPGrowingTextView/LICENSE.txt b/ios/Pods/HPGrowingTextView/LICENSE.txt new file mode 100644 index 000000000..954f712fb --- /dev/null +++ b/ios/Pods/HPGrowingTextView/LICENSE.txt @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2011 Hans Pinckaers + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. \ No newline at end of file diff --git a/ios/Pods/HPGrowingTextView/README.md b/ios/Pods/HPGrowingTextView/README.md new file mode 100644 index 000000000..ca281caf2 --- /dev/null +++ b/ios/Pods/HPGrowingTextView/README.md @@ -0,0 +1,59 @@ +HPGrowingTextView +================= + +Multi-line/Autoresizing UITextView similar as in the SMS-app. The example project mimicks the look of Apple's SMS-app. + +![Screenshot](http://f.cl.ly/items/270f2F3q3d3q142m140A/ss.png) + +Properties +---------- + +```objective-c +int maxNumberOfLines; // Stops growing at this amount of lines. +int minNumberOfLines; // Starts growing at this amount of lines. +int maxHeight; // Specify the maximum height in points instead of lines. +int minHeight; // Specify the minimum height in points instead of lines. +BOOL animateHeightChange; // Animate the growing +NSTimeInterval animationDuration; // Adjust the duration of the growth animation. +``` + +UITextView borrowed properties +---------------- + +```objective-c +NSString *text; +UIFont *font; +UIColor *textColor; +NSTextAlignment textAlignment; +NSRange selectedRange; +BOOL editable; +UIDataDetectorTypes dataDetectorTypes; +UIReturnKeyType returnKeyType; +``` + +If you want to set other UITextView properties, use .internalTextView + +Delegate methods +--------------- + +```objective-c +-(BOOL)growingTextViewShouldBeginEditing:(HPGrowingTextView *)growingTextView; +-(BOOL)growingTextViewShouldEndEditing:(HPGrowingTextView *)growingTextView; + +-(void)growingTextViewDidBeginEditing:(HPGrowingTextView *)growingTextView; +-(void)growingTextViewDidEndEditing:(HPGrowingTextView *)growingTextView; + +-(BOOL)growingTextView:(HPGrowingTextView *)growingTextView shouldChangeTextInRange:(NSRange)range replacementText:(NSString *)text; +-(void)growingTextViewDidChange:(HPGrowingTextView *)growingTextView; + +// Called WITHIN animation block! +-(void)growingTextView:(HPGrowingTextView *)growingTextView willChangeHeight:(float)height; + +// Called after animation +-(void)growingTextView:(HPGrowingTextView *)growingTextView didChangeHeight:(float)height; + +-(void)growingTextViewDidChangeSelection:(HPGrowingTextView *)growingTextView; +-(BOOL)growingTextViewShouldReturn:(HPGrowingTextView *)growingTextView; +``` + +For more info, see blogpost: http://www.hanspinckaers.com/multi-line-uitextview-similar-to-sms diff --git a/ios/Pods/HPGrowingTextView/class/HPGrowingTextView.h b/ios/Pods/HPGrowingTextView/class/HPGrowingTextView.h new file mode 100644 index 000000000..8b343c5be --- /dev/null +++ b/ios/Pods/HPGrowingTextView/class/HPGrowingTextView.h @@ -0,0 +1,126 @@ +// +// HPTextView.h +// +// Created by Hans Pinckaers on 29-06-10. +// +// MIT License +// +// Copyright (c) 2011 Hans Pinckaers +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +#import + +#if __IPHONE_OS_VERSION_MAX_ALLOWED < 60000 + // UITextAlignment is deprecated in iOS 6.0+, use NSTextAlignment instead. + // Reference: https://developer.apple.com/library/ios/documentation/uikit/reference/NSString_UIKit_Additions/Reference/Reference.html + #define NSTextAlignment UITextAlignment +#endif + +@class HPGrowingTextView; +@class HPTextViewInternal; + +@protocol HPGrowingTextViewDelegate + +@optional +- (BOOL)growingTextViewShouldBeginEditing:(HPGrowingTextView *)growingTextView; +- (BOOL)growingTextViewShouldEndEditing:(HPGrowingTextView *)growingTextView; + +- (void)growingTextViewDidBeginEditing:(HPGrowingTextView *)growingTextView; +- (void)growingTextViewDidEndEditing:(HPGrowingTextView *)growingTextView; + +- (BOOL)growingTextView:(HPGrowingTextView *)growingTextView shouldChangeTextInRange:(NSRange)range replacementText:(NSString *)text; +- (void)growingTextViewDidChange:(HPGrowingTextView *)growingTextView; + +- (void)growingTextView:(HPGrowingTextView *)growingTextView willChangeHeight:(float)height; +- (void)growingTextView:(HPGrowingTextView *)growingTextView didChangeHeight:(float)height; + +- (void)growingTextViewDidChangeSelection:(HPGrowingTextView *)growingTextView; +- (BOOL)growingTextViewShouldReturn:(HPGrowingTextView *)growingTextView; +@end + +@interface HPGrowingTextView : UIView { + HPTextViewInternal *internalTextView; + + int minHeight; + int maxHeight; + + //class properties + int maxNumberOfLines; + int minNumberOfLines; + + BOOL animateHeightChange; + NSTimeInterval animationDuration; + + //uitextview properties + NSObject *__unsafe_unretained delegate; + NSTextAlignment textAlignment; + NSRange selectedRange; + BOOL editable; + UIDataDetectorTypes dataDetectorTypes; + UIReturnKeyType returnKeyType; + UIKeyboardType keyboardType; + + UIEdgeInsets contentInset; +} + +//real class properties +@property int maxNumberOfLines; +@property int minNumberOfLines; +@property (nonatomic) int maxHeight; +@property (nonatomic) int minHeight; +@property BOOL animateHeightChange; +@property NSTimeInterval animationDuration; +@property (nonatomic, strong) NSString *placeholder; +@property (nonatomic, strong) UIColor *placeholderColor; +@property (nonatomic, strong) UITextView *internalTextView; + + +//uitextview properties +@property(unsafe_unretained) NSObject *delegate; +@property(nonatomic,strong) NSString *text; +@property(nonatomic,strong) UIFont *font; +@property(nonatomic,strong) UIColor *textColor; +@property(nonatomic) NSTextAlignment textAlignment; // default is NSTextAlignmentLeft +@property(nonatomic) NSRange selectedRange; // only ranges of length 0 are supported +@property(nonatomic,getter=isEditable) BOOL editable; +@property(nonatomic) UIDataDetectorTypes dataDetectorTypes __OSX_AVAILABLE_STARTING(__MAC_NA, __IPHONE_3_0); +@property (nonatomic) UIReturnKeyType returnKeyType; +@property (nonatomic) UIKeyboardType keyboardType; +@property (assign) UIEdgeInsets contentInset; +@property (nonatomic) BOOL isScrollable; +@property(nonatomic) BOOL enablesReturnKeyAutomatically; + +#if __IPHONE_OS_VERSION_MIN_REQUIRED >= 70000 +- (id)initWithFrame:(CGRect)frame textContainer:(NSTextContainer *)textContainer; +#endif + +//uitextview methods +//need others? use .internalTextView +- (BOOL)becomeFirstResponder; +- (BOOL)resignFirstResponder; +- (BOOL)isFirstResponder; + +- (BOOL)hasText; +- (void)scrollRangeToVisible:(NSRange)range; + +// call to force a height change (e.g. after you change max/min lines) +- (void)refreshHeight; + +@end diff --git a/ios/Pods/HPGrowingTextView/class/HPGrowingTextView.m b/ios/Pods/HPGrowingTextView/class/HPGrowingTextView.m new file mode 100644 index 000000000..9871c6fa9 --- /dev/null +++ b/ios/Pods/HPGrowingTextView/class/HPGrowingTextView.m @@ -0,0 +1,666 @@ +// +// HPTextView.m +// +// Created by Hans Pinckaers on 29-06-10. +// +// MIT License +// +// Copyright (c) 2011 Hans Pinckaers +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +#import "HPGrowingTextView.h" +#import "HPTextViewInternal.h" + +@interface HPGrowingTextView(private) +-(void)commonInitialiser; +-(void)resizeTextView:(NSInteger)newSizeH; +-(void)growDidStop; +@end + +@implementation HPGrowingTextView +@synthesize internalTextView; +@synthesize delegate; +@synthesize maxHeight; +@synthesize minHeight; +@synthesize font; +@synthesize textColor; +@synthesize textAlignment; +@synthesize selectedRange; +@synthesize editable; +@synthesize dataDetectorTypes; +@synthesize animateHeightChange; +@synthesize animationDuration; +@synthesize returnKeyType; +@dynamic placeholder; +@dynamic placeholderColor; + +// having initwithcoder allows us to use HPGrowingTextView in a Nib. -- aob, 9/2011 +- (id)initWithCoder:(NSCoder *)aDecoder +{ + if ((self = [super initWithCoder:aDecoder])) { + [self commonInitialiser]; + } + return self; +} + +- (id)initWithFrame:(CGRect)frame { + if ((self = [super initWithFrame:frame])) { + [self commonInitialiser]; + } + return self; +} + +#if __IPHONE_OS_VERSION_MIN_REQUIRED >= 70000 +- (id)initWithFrame:(CGRect)frame textContainer:(NSTextContainer *)textContainer { + if ((self = [super initWithFrame:frame])) { + [self commonInitialiser:textContainer]; + } + return self; +} + +-(void)commonInitialiser { + [self commonInitialiser:nil]; +} + +-(void)commonInitialiser:(NSTextContainer *)textContainer +#else +-(void)commonInitialiser +#endif +{ + // Initialization code + CGRect r = self.frame; + r.origin.y = 0; + r.origin.x = 0; +#if __IPHONE_OS_VERSION_MIN_REQUIRED >= 70000 + internalTextView = [[HPTextViewInternal alloc] initWithFrame:r textContainer:textContainer]; +#else + internalTextView = [[HPTextViewInternal alloc] initWithFrame:r]; +#endif + internalTextView.delegate = self; + internalTextView.scrollEnabled = NO; + internalTextView.font = [UIFont fontWithName:@"Helvetica" size:13]; + internalTextView.contentInset = UIEdgeInsetsZero; + internalTextView.showsHorizontalScrollIndicator = NO; + internalTextView.text = @"-"; + internalTextView.contentMode = UIViewContentModeRedraw; + [self addSubview:internalTextView]; + + minHeight = internalTextView.frame.size.height; + minNumberOfLines = 1; + + animateHeightChange = YES; + animationDuration = 0.1f; + + internalTextView.text = @""; + + [self setMaxNumberOfLines:3]; + + [self setPlaceholderColor:[UIColor lightGrayColor]]; + internalTextView.displayPlaceHolder = YES; +} + +-(CGSize)sizeThatFits:(CGSize)size +{ + if (self.text.length == 0) { + size.height = minHeight; + } + return size; +} + +-(void)layoutSubviews +{ + [super layoutSubviews]; + + CGRect r = self.bounds; + r.origin.y = 0; + r.origin.x = contentInset.left; + r.size.width -= contentInset.left + contentInset.right; + + internalTextView.frame = r; +} + +-(void)setContentInset:(UIEdgeInsets)inset +{ + contentInset = inset; + + CGRect r = self.frame; + r.origin.y = inset.top - inset.bottom; + r.origin.x = inset.left; + r.size.width -= inset.left + inset.right; + + internalTextView.frame = r; + + [self setMaxNumberOfLines:maxNumberOfLines]; + [self setMinNumberOfLines:minNumberOfLines]; +} + +-(UIEdgeInsets)contentInset +{ + return contentInset; +} + +-(void)setMaxNumberOfLines:(int)n +{ + if(n == 0 && maxHeight > 0) return; // the user specified a maxHeight themselves. + + // Use internalTextView for height calculations, thanks to Gwynne + NSString *saveText = internalTextView.text, *newText = @"-"; + + internalTextView.delegate = nil; + internalTextView.hidden = YES; + + for (int i = 1; i < n; ++i) + newText = [newText stringByAppendingString:@"\n|W|"]; + + internalTextView.text = newText; + + maxHeight = [self measureHeight]; + + internalTextView.text = saveText; + internalTextView.hidden = NO; + internalTextView.delegate = self; + + [self sizeToFit]; + + maxNumberOfLines = n; +} + +-(int)maxNumberOfLines +{ + return maxNumberOfLines; +} + +- (void)setMaxHeight:(int)height +{ + maxHeight = height; + maxNumberOfLines = 0; +} + +-(void)setMinNumberOfLines:(int)m +{ + if(m == 0 && minHeight > 0) return; // the user specified a minHeight themselves. + + // Use internalTextView for height calculations, thanks to Gwynne + NSString *saveText = internalTextView.text, *newText = @"-"; + + internalTextView.delegate = nil; + internalTextView.hidden = YES; + + for (int i = 1; i < m; ++i) + newText = [newText stringByAppendingString:@"\n|W|"]; + + internalTextView.text = newText; + + minHeight = [self measureHeight]; + + internalTextView.text = saveText; + internalTextView.hidden = NO; + internalTextView.delegate = self; + + [self sizeToFit]; + + minNumberOfLines = m; +} + +-(int)minNumberOfLines +{ + return minNumberOfLines; +} + +- (void)setMinHeight:(int)height +{ + minHeight = height; + minNumberOfLines = 0; +} + +- (NSString *)placeholder +{ + return internalTextView.placeholder; +} + +- (void)setPlaceholder:(NSString *)placeholder +{ + [internalTextView setPlaceholder:placeholder]; + [internalTextView setNeedsDisplay]; +} + +- (UIColor *)placeholderColor +{ + return internalTextView.placeholderColor; +} + +- (void)setPlaceholderColor:(UIColor *)placeholderColor +{ + [internalTextView setPlaceholderColor:placeholderColor]; +} + +- (void)textViewDidChange:(UITextView *)textView +{ + [self refreshHeight]; +} + +- (void)refreshHeight +{ + //size of content, so we can set the frame of self + NSInteger newSizeH = [self measureHeight]; + if (newSizeH < minHeight || !internalTextView.hasText) { + newSizeH = minHeight; //not smalles than minHeight + } + else if (maxHeight && newSizeH > maxHeight) { + newSizeH = maxHeight; // not taller than maxHeight + } + + if (internalTextView.frame.size.height != newSizeH) + { + // if our new height is greater than the maxHeight + // sets not set the height or move things + // around and enable scrolling + if (newSizeH >= maxHeight) + { + if(!internalTextView.scrollEnabled){ + internalTextView.scrollEnabled = YES; + [internalTextView flashScrollIndicators]; + } + + } else { + internalTextView.scrollEnabled = NO; + } + + // [fixed] Pasting too much text into the view failed to fire the height change, + // thanks to Gwynne + if (newSizeH <= maxHeight) + { + if(animateHeightChange) { + + if ([UIView resolveClassMethod:@selector(animateWithDuration:animations:)]) { +#if __IPHONE_OS_VERSION_MAX_ALLOWED >= 40000 + [UIView animateWithDuration:animationDuration + delay:0 + options:(UIViewAnimationOptionAllowUserInteraction| + UIViewAnimationOptionBeginFromCurrentState) + animations:^(void) { + [self resizeTextView:newSizeH]; + } + completion:^(BOOL finished) { + if ([delegate respondsToSelector:@selector(growingTextView:didChangeHeight:)]) { + [delegate growingTextView:self didChangeHeight:newSizeH]; + } + }]; +#endif + } else { + [UIView beginAnimations:@"" context:nil]; + [UIView setAnimationDuration:animationDuration]; + [UIView setAnimationDelegate:self]; + [UIView setAnimationDidStopSelector:@selector(growDidStop)]; + [UIView setAnimationBeginsFromCurrentState:YES]; + [self resizeTextView:newSizeH]; + [UIView commitAnimations]; + } + } else { + [self resizeTextView:newSizeH]; + // [fixed] The growingTextView:didChangeHeight: delegate method was not called at all when not animating height changes. + // thanks to Gwynne + + if ([delegate respondsToSelector:@selector(growingTextView:didChangeHeight:)]) { + [delegate growingTextView:self didChangeHeight:newSizeH]; + } + } + } + } + // Display (or not) the placeholder string + + BOOL wasDisplayingPlaceholder = internalTextView.displayPlaceHolder; + internalTextView.displayPlaceHolder = self.internalTextView.text.length == 0; + + if (wasDisplayingPlaceholder != internalTextView.displayPlaceHolder) { + [internalTextView setNeedsDisplay]; + } + + + // scroll to caret (needed on iOS7) + if ([self respondsToSelector:@selector(snapshotViewAfterScreenUpdates:)]) + { + [self performSelector:@selector(resetScrollPositionForIOS7) withObject:nil afterDelay:0.1f]; + } + + // Tell the delegate that the text view changed + if ([delegate respondsToSelector:@selector(growingTextViewDidChange:)]) { + [delegate growingTextViewDidChange:self]; + } +} + +// Code from apple developer forum - @Steve Krulewitz, @Mark Marszal, @Eric Silverberg +- (CGFloat)measureHeight +{ + if ([self respondsToSelector:@selector(snapshotViewAfterScreenUpdates:)]) + { + return ceilf([self.internalTextView sizeThatFits:self.internalTextView.frame.size].height); + } + else { + return self.internalTextView.contentSize.height; + } +} + +- (void)resetScrollPositionForIOS7 +{ + CGRect r = [internalTextView caretRectForPosition:internalTextView.selectedTextRange.end]; + CGFloat caretY = MAX(r.origin.y - internalTextView.frame.size.height + r.size.height + 8, 0); + if (internalTextView.contentOffset.y < caretY && r.origin.y != INFINITY) + internalTextView.contentOffset = CGPointMake(0, caretY); +} + +-(void)resizeTextView:(NSInteger)newSizeH +{ + if ([delegate respondsToSelector:@selector(growingTextView:willChangeHeight:)]) { + [delegate growingTextView:self willChangeHeight:newSizeH]; + } + + CGRect internalTextViewFrame = self.frame; + internalTextViewFrame.size.height = newSizeH; // + padding + self.frame = internalTextViewFrame; + + internalTextViewFrame.origin.y = contentInset.top - contentInset.bottom; + internalTextViewFrame.origin.x = contentInset.left; + + if(!CGRectEqualToRect(internalTextView.frame, internalTextViewFrame)) internalTextView.frame = internalTextViewFrame; +} + +- (void)growDidStop +{ + // scroll to caret (needed on iOS7) + if ([self respondsToSelector:@selector(snapshotViewAfterScreenUpdates:)]) + { + [self resetScrollPositionForIOS7]; + } + + if ([delegate respondsToSelector:@selector(growingTextView:didChangeHeight:)]) { + [delegate growingTextView:self didChangeHeight:self.frame.size.height]; + } +} + +-(void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event +{ + [internalTextView becomeFirstResponder]; +} + +- (BOOL)becomeFirstResponder +{ + [super becomeFirstResponder]; + return [self.internalTextView becomeFirstResponder]; +} + +-(BOOL)resignFirstResponder +{ + [super resignFirstResponder]; + return [internalTextView resignFirstResponder]; +} + +-(BOOL)isFirstResponder +{ + return [self.internalTextView isFirstResponder]; +} + + + +/////////////////////////////////////////////////////////////////////////////////////////////////// +#pragma mark UITextView properties +/////////////////////////////////////////////////////////////////////////////////////////////////// + +-(void)setText:(NSString *)newText +{ + internalTextView.text = newText; + + // include this line to analyze the height of the textview. + // fix from Ankit Thakur + [self performSelector:@selector(textViewDidChange:) withObject:internalTextView]; +} + +-(NSString*) text +{ + return internalTextView.text; +} + +/////////////////////////////////////////////////////////////////////////////////////////////////// + +-(void)setFont:(UIFont *)afont +{ + internalTextView.font= afont; + + [self setMaxNumberOfLines:maxNumberOfLines]; + [self setMinNumberOfLines:minNumberOfLines]; +} + +-(UIFont *)font +{ + return internalTextView.font; +} + +/////////////////////////////////////////////////////////////////////////////////////////////////// + +-(void)setTextColor:(UIColor *)color +{ + internalTextView.textColor = color; +} + +-(UIColor*)textColor{ + return internalTextView.textColor; +} + +/////////////////////////////////////////////////////////////////////////////////////////////////// + +-(void)setBackgroundColor:(UIColor *)backgroundColor +{ + [super setBackgroundColor:backgroundColor]; + internalTextView.backgroundColor = backgroundColor; +} + +-(UIColor*)backgroundColor +{ + return internalTextView.backgroundColor; +} + +/////////////////////////////////////////////////////////////////////////////////////////////////// + +-(void)setTextAlignment:(NSTextAlignment)aligment +{ + internalTextView.textAlignment = aligment; +} + +-(NSTextAlignment)textAlignment +{ + return internalTextView.textAlignment; +} + +/////////////////////////////////////////////////////////////////////////////////////////////////// + +-(void)setSelectedRange:(NSRange)range +{ + internalTextView.selectedRange = range; +} + +-(NSRange)selectedRange +{ + return internalTextView.selectedRange; +} + +/////////////////////////////////////////////////////////////////////////////////////////////////// + +- (void)setIsScrollable:(BOOL)isScrollable +{ + internalTextView.scrollEnabled = isScrollable; +} + +- (BOOL)isScrollable +{ + return internalTextView.scrollEnabled; +} + +/////////////////////////////////////////////////////////////////////////////////////////////////// + +-(void)setEditable:(BOOL)beditable +{ + internalTextView.editable = beditable; +} + +-(BOOL)isEditable +{ + return internalTextView.editable; +} + +/////////////////////////////////////////////////////////////////////////////////////////////////// + +-(void)setReturnKeyType:(UIReturnKeyType)keyType +{ + internalTextView.returnKeyType = keyType; +} + +-(UIReturnKeyType)returnKeyType +{ + return internalTextView.returnKeyType; +} + +/////////////////////////////////////////////////////////////////////////////////////////////////// + +- (void)setKeyboardType:(UIKeyboardType)keyType +{ + internalTextView.keyboardType = keyType; +} + +- (UIKeyboardType)keyboardType +{ + return internalTextView.keyboardType; +} + +/////////////////////////////////////////////////////////////////////////////////////////////////// + +- (void)setEnablesReturnKeyAutomatically:(BOOL)enablesReturnKeyAutomatically +{ + internalTextView.enablesReturnKeyAutomatically = enablesReturnKeyAutomatically; +} + +- (BOOL)enablesReturnKeyAutomatically +{ + return internalTextView.enablesReturnKeyAutomatically; +} + +/////////////////////////////////////////////////////////////////////////////////////////////////// + +-(void)setDataDetectorTypes:(UIDataDetectorTypes)datadetector +{ + internalTextView.dataDetectorTypes = datadetector; +} + +-(UIDataDetectorTypes)dataDetectorTypes +{ + return internalTextView.dataDetectorTypes; +} + +/////////////////////////////////////////////////////////////////////////////////////////////////// + +- (BOOL)hasText{ + return [internalTextView hasText]; +} + +- (void)scrollRangeToVisible:(NSRange)range +{ + [internalTextView scrollRangeToVisible:range]; +} + +///////////////////////////////////////////////////////////////////////////////////////////////////// +///////////////////////////////////////////////////////////////////////////////////////////////////// +#pragma mark - +#pragma mark UITextViewDelegate + + +/////////////////////////////////////////////////////////////////////////////////////////////////// +- (BOOL)textViewShouldBeginEditing:(UITextView *)textView { + if ([delegate respondsToSelector:@selector(growingTextViewShouldBeginEditing:)]) { + return [delegate growingTextViewShouldBeginEditing:self]; + + } else { + return YES; + } +} + + +/////////////////////////////////////////////////////////////////////////////////////////////////// +- (BOOL)textViewShouldEndEditing:(UITextView *)textView { + if ([delegate respondsToSelector:@selector(growingTextViewShouldEndEditing:)]) { + return [delegate growingTextViewShouldEndEditing:self]; + + } else { + return YES; + } +} + + +/////////////////////////////////////////////////////////////////////////////////////////////////// +- (void)textViewDidBeginEditing:(UITextView *)textView { + if ([delegate respondsToSelector:@selector(growingTextViewDidBeginEditing:)]) { + [delegate growingTextViewDidBeginEditing:self]; + } +} + + +/////////////////////////////////////////////////////////////////////////////////////////////////// +- (void)textViewDidEndEditing:(UITextView *)textView { + if ([delegate respondsToSelector:@selector(growingTextViewDidEndEditing:)]) { + [delegate growingTextViewDidEndEditing:self]; + } +} + + +/////////////////////////////////////////////////////////////////////////////////////////////////// +- (BOOL)textView:(UITextView *)textView shouldChangeTextInRange:(NSRange)range + replacementText:(NSString *)atext { + + //weird 1 pixel bug when clicking backspace when textView is empty + if(![textView hasText] && [atext isEqualToString:@""]) return NO; + + //Added by bretdabaker: sometimes we want to handle this ourselves + if ([delegate respondsToSelector:@selector(growingTextView:shouldChangeTextInRange:replacementText:)]) + return [delegate growingTextView:self shouldChangeTextInRange:range replacementText:atext]; + + if ([atext isEqualToString:@"\n"]) { + if ([delegate respondsToSelector:@selector(growingTextViewShouldReturn:)]) { + if (![delegate performSelector:@selector(growingTextViewShouldReturn:) withObject:self]) { + return YES; + } else { + [textView resignFirstResponder]; + return NO; + } + } + } + + return YES; + + +} + +/////////////////////////////////////////////////////////////////////////////////////////////////// +- (void)textViewDidChangeSelection:(UITextView *)textView { + if ([delegate respondsToSelector:@selector(growingTextViewDidChangeSelection:)]) { + [delegate growingTextViewDidChangeSelection:self]; + } +} + + + +@end diff --git a/ios/Pods/HPGrowingTextView/class/HPTextViewInternal.h b/ios/Pods/HPGrowingTextView/class/HPTextViewInternal.h new file mode 100644 index 000000000..175f4d472 --- /dev/null +++ b/ios/Pods/HPGrowingTextView/class/HPTextViewInternal.h @@ -0,0 +1,37 @@ +// +// HPTextViewInternal.h +// +// Created by Hans Pinckaers on 29-06-10. +// +// MIT License +// +// Copyright (c) 2011 Hans Pinckaers +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +#import + + +@interface HPTextViewInternal : UITextView + +@property (nonatomic, strong) NSString *placeholder; +@property (nonatomic, strong) UIColor *placeholderColor; +@property (nonatomic) BOOL displayPlaceHolder; + +@end diff --git a/ios/Pods/HPGrowingTextView/class/HPTextViewInternal.m b/ios/Pods/HPGrowingTextView/class/HPTextViewInternal.m new file mode 100644 index 000000000..f3a6a1d60 --- /dev/null +++ b/ios/Pods/HPGrowingTextView/class/HPTextViewInternal.m @@ -0,0 +1,126 @@ +// +// HPTextViewInternal.m +// +// Created by Hans Pinckaers on 29-06-10. +// +// MIT License +// +// Copyright (c) 2011 Hans Pinckaers +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +#import "HPTextViewInternal.h" + + +@implementation HPTextViewInternal + +-(void)setText:(NSString *)text +{ + BOOL originalValue = self.scrollEnabled; + //If one of GrowingTextView's superviews is a scrollView, and self.scrollEnabled == NO, + //setting the text programatically will cause UIKit to search upwards until it finds a scrollView with scrollEnabled==yes + //then scroll it erratically. Setting scrollEnabled temporarily to YES prevents this. + [self setScrollEnabled:YES]; + [super setText:text]; + [self setScrollEnabled:originalValue]; +} + +- (void)setScrollable:(BOOL)isScrollable +{ + [super setScrollEnabled:isScrollable]; +} + +-(void)setContentOffset:(CGPoint)s +{ + if(self.tracking || self.decelerating){ + //initiated by user... + + UIEdgeInsets insets = self.contentInset; + insets.bottom = 0; + insets.top = 0; + self.contentInset = insets; + + } else { + + float bottomOffset = (self.contentSize.height - self.frame.size.height + self.contentInset.bottom); + if(s.y < bottomOffset && self.scrollEnabled){ + UIEdgeInsets insets = self.contentInset; + insets.bottom = 8; + insets.top = 0; + self.contentInset = insets; + } + } + + // Fix "overscrolling" bug + if (s.y > self.contentSize.height - self.frame.size.height && !self.decelerating && !self.tracking && !self.dragging) + s = CGPointMake(s.x, self.contentSize.height - self.frame.size.height); + + [super setContentOffset:s]; +} + +-(void)setContentInset:(UIEdgeInsets)s +{ + UIEdgeInsets insets = s; + + if(s.bottom>8) insets.bottom = 0; + insets.top = 0; + + [super setContentInset:insets]; +} + +-(void)setContentSize:(CGSize)contentSize +{ + // is this an iOS5 bug? Need testing! + if(self.contentSize.height > contentSize.height) + { + UIEdgeInsets insets = self.contentInset; + insets.bottom = 0; + insets.top = 0; + self.contentInset = insets; + } + + [super setContentSize:contentSize]; +} + +- (void)drawRect:(CGRect)rect +{ + [super drawRect:rect]; + if (self.displayPlaceHolder && self.placeholder && self.placeholderColor) + { + if ([self respondsToSelector:@selector(snapshotViewAfterScreenUpdates:)]) + { + NSMutableParagraphStyle *paragraphStyle = [[NSMutableParagraphStyle alloc] init]; + paragraphStyle.alignment = self.textAlignment; + [self.placeholder drawInRect:CGRectMake(5, 8 + self.contentInset.top, self.frame.size.width-self.contentInset.left, self.frame.size.height- self.contentInset.top) withAttributes:@{NSFontAttributeName:self.font, NSForegroundColorAttributeName:self.placeholderColor, NSParagraphStyleAttributeName:paragraphStyle}]; + } + else { + [self.placeholderColor set]; + [self.placeholder drawInRect:CGRectMake(8.0f, 8.0f, self.frame.size.width - 16.0f, self.frame.size.height - 16.0f) withFont:self.font]; + } + } +} + +-(void)setPlaceholder:(NSString *)placeholder +{ + _placeholder = placeholder; + + [self setNeedsDisplay]; +} + +@end diff --git a/ios/Pods/Headers/Build/AFNetworking/AFHTTPRequestOperation.h b/ios/Pods/Headers/Build/AFNetworking/AFHTTPRequestOperation.h new file mode 120000 index 000000000..ac762c823 --- /dev/null +++ b/ios/Pods/Headers/Build/AFNetworking/AFHTTPRequestOperation.h @@ -0,0 +1 @@ +../../../AFNetworking/AFNetworking/AFHTTPRequestOperation.h \ No newline at end of file diff --git a/ios/Pods/Headers/Build/AFNetworking/AFHTTPRequestOperationManager.h b/ios/Pods/Headers/Build/AFNetworking/AFHTTPRequestOperationManager.h new file mode 120000 index 000000000..9dcc623c6 --- /dev/null +++ b/ios/Pods/Headers/Build/AFNetworking/AFHTTPRequestOperationManager.h @@ -0,0 +1 @@ +../../../AFNetworking/AFNetworking/AFHTTPRequestOperationManager.h \ No newline at end of file diff --git a/ios/Pods/Headers/Build/AFNetworking/AFHTTPSessionManager.h b/ios/Pods/Headers/Build/AFNetworking/AFHTTPSessionManager.h new file mode 120000 index 000000000..56feb9fb8 --- /dev/null +++ b/ios/Pods/Headers/Build/AFNetworking/AFHTTPSessionManager.h @@ -0,0 +1 @@ +../../../AFNetworking/AFNetworking/AFHTTPSessionManager.h \ No newline at end of file diff --git a/ios/Pods/Headers/Build/AFNetworking/AFNetworkActivityIndicatorManager.h b/ios/Pods/Headers/Build/AFNetworking/AFNetworkActivityIndicatorManager.h new file mode 120000 index 000000000..67519d984 --- /dev/null +++ b/ios/Pods/Headers/Build/AFNetworking/AFNetworkActivityIndicatorManager.h @@ -0,0 +1 @@ +../../../AFNetworking/UIKit+AFNetworking/AFNetworkActivityIndicatorManager.h \ No newline at end of file diff --git a/ios/Pods/Headers/Build/AFNetworking/AFNetworkReachabilityManager.h b/ios/Pods/Headers/Build/AFNetworking/AFNetworkReachabilityManager.h new file mode 120000 index 000000000..68fc7744f --- /dev/null +++ b/ios/Pods/Headers/Build/AFNetworking/AFNetworkReachabilityManager.h @@ -0,0 +1 @@ +../../../AFNetworking/AFNetworking/AFNetworkReachabilityManager.h \ No newline at end of file diff --git a/ios/Pods/Headers/Build/AFNetworking/AFNetworking.h b/ios/Pods/Headers/Build/AFNetworking/AFNetworking.h new file mode 120000 index 000000000..a5a38da7d --- /dev/null +++ b/ios/Pods/Headers/Build/AFNetworking/AFNetworking.h @@ -0,0 +1 @@ +../../../AFNetworking/AFNetworking/AFNetworking.h \ No newline at end of file diff --git a/ios/Pods/Headers/Build/AFNetworking/AFSecurityPolicy.h b/ios/Pods/Headers/Build/AFNetworking/AFSecurityPolicy.h new file mode 120000 index 000000000..fd1322db9 --- /dev/null +++ b/ios/Pods/Headers/Build/AFNetworking/AFSecurityPolicy.h @@ -0,0 +1 @@ +../../../AFNetworking/AFNetworking/AFSecurityPolicy.h \ No newline at end of file diff --git a/ios/Pods/Headers/Build/AFNetworking/AFURLConnectionOperation.h b/ios/Pods/Headers/Build/AFNetworking/AFURLConnectionOperation.h new file mode 120000 index 000000000..d9b35fb75 --- /dev/null +++ b/ios/Pods/Headers/Build/AFNetworking/AFURLConnectionOperation.h @@ -0,0 +1 @@ +../../../AFNetworking/AFNetworking/AFURLConnectionOperation.h \ No newline at end of file diff --git a/ios/Pods/Headers/Build/AFNetworking/AFURLRequestSerialization.h b/ios/Pods/Headers/Build/AFNetworking/AFURLRequestSerialization.h new file mode 120000 index 000000000..ca8209b81 --- /dev/null +++ b/ios/Pods/Headers/Build/AFNetworking/AFURLRequestSerialization.h @@ -0,0 +1 @@ +../../../AFNetworking/AFNetworking/AFURLRequestSerialization.h \ No newline at end of file diff --git a/ios/Pods/Headers/Build/AFNetworking/AFURLResponseSerialization.h b/ios/Pods/Headers/Build/AFNetworking/AFURLResponseSerialization.h new file mode 120000 index 000000000..e36a765d8 --- /dev/null +++ b/ios/Pods/Headers/Build/AFNetworking/AFURLResponseSerialization.h @@ -0,0 +1 @@ +../../../AFNetworking/AFNetworking/AFURLResponseSerialization.h \ No newline at end of file diff --git a/ios/Pods/Headers/Build/AFNetworking/AFURLSessionManager.h b/ios/Pods/Headers/Build/AFNetworking/AFURLSessionManager.h new file mode 120000 index 000000000..835101de7 --- /dev/null +++ b/ios/Pods/Headers/Build/AFNetworking/AFURLSessionManager.h @@ -0,0 +1 @@ +../../../AFNetworking/AFNetworking/AFURLSessionManager.h \ No newline at end of file diff --git a/ios/Pods/Headers/Build/AFNetworking/UIActivityIndicatorView+AFNetworking.h b/ios/Pods/Headers/Build/AFNetworking/UIActivityIndicatorView+AFNetworking.h new file mode 120000 index 000000000..c534ebfb0 --- /dev/null +++ b/ios/Pods/Headers/Build/AFNetworking/UIActivityIndicatorView+AFNetworking.h @@ -0,0 +1 @@ +../../../AFNetworking/UIKit+AFNetworking/UIActivityIndicatorView+AFNetworking.h \ No newline at end of file diff --git a/ios/Pods/Headers/Build/AFNetworking/UIAlertView+AFNetworking.h b/ios/Pods/Headers/Build/AFNetworking/UIAlertView+AFNetworking.h new file mode 120000 index 000000000..f99281338 --- /dev/null +++ b/ios/Pods/Headers/Build/AFNetworking/UIAlertView+AFNetworking.h @@ -0,0 +1 @@ +../../../AFNetworking/UIKit+AFNetworking/UIAlertView+AFNetworking.h \ No newline at end of file diff --git a/ios/Pods/Headers/Build/AFNetworking/UIButton+AFNetworking.h b/ios/Pods/Headers/Build/AFNetworking/UIButton+AFNetworking.h new file mode 120000 index 000000000..8f2e22193 --- /dev/null +++ b/ios/Pods/Headers/Build/AFNetworking/UIButton+AFNetworking.h @@ -0,0 +1 @@ +../../../AFNetworking/UIKit+AFNetworking/UIButton+AFNetworking.h \ No newline at end of file diff --git a/ios/Pods/Headers/Build/AFNetworking/UIImageView+AFNetworking.h b/ios/Pods/Headers/Build/AFNetworking/UIImageView+AFNetworking.h new file mode 120000 index 000000000..a95d67380 --- /dev/null +++ b/ios/Pods/Headers/Build/AFNetworking/UIImageView+AFNetworking.h @@ -0,0 +1 @@ +../../../AFNetworking/UIKit+AFNetworking/UIImageView+AFNetworking.h \ No newline at end of file diff --git a/ios/Pods/Headers/Build/AFNetworking/UIKit+AFNetworking.h b/ios/Pods/Headers/Build/AFNetworking/UIKit+AFNetworking.h new file mode 120000 index 000000000..95017cce5 --- /dev/null +++ b/ios/Pods/Headers/Build/AFNetworking/UIKit+AFNetworking.h @@ -0,0 +1 @@ +../../../AFNetworking/UIKit+AFNetworking/UIKit+AFNetworking.h \ No newline at end of file diff --git a/ios/Pods/Headers/Build/AFNetworking/UIProgressView+AFNetworking.h b/ios/Pods/Headers/Build/AFNetworking/UIProgressView+AFNetworking.h new file mode 120000 index 000000000..730b167dc --- /dev/null +++ b/ios/Pods/Headers/Build/AFNetworking/UIProgressView+AFNetworking.h @@ -0,0 +1 @@ +../../../AFNetworking/UIKit+AFNetworking/UIProgressView+AFNetworking.h \ No newline at end of file diff --git a/ios/Pods/Headers/Build/AFNetworking/UIRefreshControl+AFNetworking.h b/ios/Pods/Headers/Build/AFNetworking/UIRefreshControl+AFNetworking.h new file mode 120000 index 000000000..8efd82620 --- /dev/null +++ b/ios/Pods/Headers/Build/AFNetworking/UIRefreshControl+AFNetworking.h @@ -0,0 +1 @@ +../../../AFNetworking/UIKit+AFNetworking/UIRefreshControl+AFNetworking.h \ No newline at end of file diff --git a/ios/Pods/Headers/Build/AFNetworking/UIWebView+AFNetworking.h b/ios/Pods/Headers/Build/AFNetworking/UIWebView+AFNetworking.h new file mode 120000 index 000000000..c8df6ef17 --- /dev/null +++ b/ios/Pods/Headers/Build/AFNetworking/UIWebView+AFNetworking.h @@ -0,0 +1 @@ +../../../AFNetworking/UIKit+AFNetworking/UIWebView+AFNetworking.h \ No newline at end of file diff --git a/ios/Pods/Headers/Build/DACircularProgress/DACircularProgressView.h b/ios/Pods/Headers/Build/DACircularProgress/DACircularProgressView.h new file mode 120000 index 000000000..b67e984a6 --- /dev/null +++ b/ios/Pods/Headers/Build/DACircularProgress/DACircularProgressView.h @@ -0,0 +1 @@ +../../../DACircularProgress/DACircularProgress/DACircularProgressView.h \ No newline at end of file diff --git a/ios/Pods/Headers/Build/FMDB/FMDB.h b/ios/Pods/Headers/Build/FMDB/FMDB.h new file mode 120000 index 000000000..bcd6e0a12 --- /dev/null +++ b/ios/Pods/Headers/Build/FMDB/FMDB.h @@ -0,0 +1 @@ +../../../FMDB/src/fmdb/FMDB.h \ No newline at end of file diff --git a/ios/Pods/Headers/Build/FMDB/FMDatabase.h b/ios/Pods/Headers/Build/FMDB/FMDatabase.h new file mode 120000 index 000000000..e69b333e8 --- /dev/null +++ b/ios/Pods/Headers/Build/FMDB/FMDatabase.h @@ -0,0 +1 @@ +../../../FMDB/src/fmdb/FMDatabase.h \ No newline at end of file diff --git a/ios/Pods/Headers/Build/FMDB/FMDatabaseAdditions.h b/ios/Pods/Headers/Build/FMDB/FMDatabaseAdditions.h new file mode 120000 index 000000000..b48a6a351 --- /dev/null +++ b/ios/Pods/Headers/Build/FMDB/FMDatabaseAdditions.h @@ -0,0 +1 @@ +../../../FMDB/src/fmdb/FMDatabaseAdditions.h \ No newline at end of file diff --git a/ios/Pods/Headers/Build/FMDB/FMDatabasePool.h b/ios/Pods/Headers/Build/FMDB/FMDatabasePool.h new file mode 120000 index 000000000..1d78001fc --- /dev/null +++ b/ios/Pods/Headers/Build/FMDB/FMDatabasePool.h @@ -0,0 +1 @@ +../../../FMDB/src/fmdb/FMDatabasePool.h \ No newline at end of file diff --git a/ios/Pods/Headers/Build/FMDB/FMDatabaseQueue.h b/ios/Pods/Headers/Build/FMDB/FMDatabaseQueue.h new file mode 120000 index 000000000..9adde8736 --- /dev/null +++ b/ios/Pods/Headers/Build/FMDB/FMDatabaseQueue.h @@ -0,0 +1 @@ +../../../FMDB/src/fmdb/FMDatabaseQueue.h \ No newline at end of file diff --git a/ios/Pods/Headers/Build/FMDB/FMResultSet.h b/ios/Pods/Headers/Build/FMDB/FMResultSet.h new file mode 120000 index 000000000..fd761d84a --- /dev/null +++ b/ios/Pods/Headers/Build/FMDB/FMResultSet.h @@ -0,0 +1 @@ +../../../FMDB/src/fmdb/FMResultSet.h \ No newline at end of file diff --git a/ios/Pods/Headers/Build/HPGrowingTextView/HPGrowingTextView.h b/ios/Pods/Headers/Build/HPGrowingTextView/HPGrowingTextView.h new file mode 120000 index 000000000..d22eb7155 --- /dev/null +++ b/ios/Pods/Headers/Build/HPGrowingTextView/HPGrowingTextView.h @@ -0,0 +1 @@ +../../../HPGrowingTextView/class/HPGrowingTextView.h \ No newline at end of file diff --git a/ios/Pods/Headers/Build/HPGrowingTextView/HPTextViewInternal.h b/ios/Pods/Headers/Build/HPGrowingTextView/HPTextViewInternal.h new file mode 120000 index 000000000..6e9773259 --- /dev/null +++ b/ios/Pods/Headers/Build/HPGrowingTextView/HPTextViewInternal.h @@ -0,0 +1 @@ +../../../HPGrowingTextView/class/HPTextViewInternal.h \ No newline at end of file diff --git a/ios/Pods/Headers/Build/MBProgressHUD/MBProgressHUD.h b/ios/Pods/Headers/Build/MBProgressHUD/MBProgressHUD.h new file mode 120000 index 000000000..19ed4db7d --- /dev/null +++ b/ios/Pods/Headers/Build/MBProgressHUD/MBProgressHUD.h @@ -0,0 +1 @@ +../../../MBProgressHUD/MBProgressHUD.h \ No newline at end of file diff --git a/ios/Pods/Headers/Build/MWPhotoBrowser/MWCaptionView.h b/ios/Pods/Headers/Build/MWPhotoBrowser/MWCaptionView.h new file mode 120000 index 000000000..aab1c09aa --- /dev/null +++ b/ios/Pods/Headers/Build/MWPhotoBrowser/MWCaptionView.h @@ -0,0 +1 @@ +../../../MWPhotoBrowser/MWPhotoBrowser/Classes/MWCaptionView.h \ No newline at end of file diff --git a/ios/Pods/Headers/Build/MWPhotoBrowser/MWCommon.h b/ios/Pods/Headers/Build/MWPhotoBrowser/MWCommon.h new file mode 120000 index 000000000..945d66b82 --- /dev/null +++ b/ios/Pods/Headers/Build/MWPhotoBrowser/MWCommon.h @@ -0,0 +1 @@ +../../../MWPhotoBrowser/MWPhotoBrowser/Classes/MWCommon.h \ No newline at end of file diff --git a/ios/Pods/Headers/Build/MWPhotoBrowser/MWGridCell.h b/ios/Pods/Headers/Build/MWPhotoBrowser/MWGridCell.h new file mode 120000 index 000000000..c2be288ac --- /dev/null +++ b/ios/Pods/Headers/Build/MWPhotoBrowser/MWGridCell.h @@ -0,0 +1 @@ +../../../MWPhotoBrowser/MWPhotoBrowser/Classes/MWGridCell.h \ No newline at end of file diff --git a/ios/Pods/Headers/Build/MWPhotoBrowser/MWGridViewController.h b/ios/Pods/Headers/Build/MWPhotoBrowser/MWGridViewController.h new file mode 120000 index 000000000..bf9f72849 --- /dev/null +++ b/ios/Pods/Headers/Build/MWPhotoBrowser/MWGridViewController.h @@ -0,0 +1 @@ +../../../MWPhotoBrowser/MWPhotoBrowser/Classes/MWGridViewController.h \ No newline at end of file diff --git a/ios/Pods/Headers/Build/MWPhotoBrowser/MWPhoto.h b/ios/Pods/Headers/Build/MWPhotoBrowser/MWPhoto.h new file mode 120000 index 000000000..2770f05fd --- /dev/null +++ b/ios/Pods/Headers/Build/MWPhotoBrowser/MWPhoto.h @@ -0,0 +1 @@ +../../../MWPhotoBrowser/MWPhotoBrowser/Classes/MWPhoto.h \ No newline at end of file diff --git a/ios/Pods/Headers/Build/MWPhotoBrowser/MWPhotoBrowser.h b/ios/Pods/Headers/Build/MWPhotoBrowser/MWPhotoBrowser.h new file mode 120000 index 000000000..cafd1fa0f --- /dev/null +++ b/ios/Pods/Headers/Build/MWPhotoBrowser/MWPhotoBrowser.h @@ -0,0 +1 @@ +../../../MWPhotoBrowser/MWPhotoBrowser/Classes/MWPhotoBrowser.h \ No newline at end of file diff --git a/ios/Pods/Headers/Build/MWPhotoBrowser/MWPhotoBrowserPrivate.h b/ios/Pods/Headers/Build/MWPhotoBrowser/MWPhotoBrowserPrivate.h new file mode 120000 index 000000000..cf26f18e1 --- /dev/null +++ b/ios/Pods/Headers/Build/MWPhotoBrowser/MWPhotoBrowserPrivate.h @@ -0,0 +1 @@ +../../../MWPhotoBrowser/MWPhotoBrowser/Classes/MWPhotoBrowserPrivate.h \ No newline at end of file diff --git a/ios/Pods/Headers/Build/MWPhotoBrowser/MWPhotoProtocol.h b/ios/Pods/Headers/Build/MWPhotoBrowser/MWPhotoProtocol.h new file mode 120000 index 000000000..d7c83b8d1 --- /dev/null +++ b/ios/Pods/Headers/Build/MWPhotoBrowser/MWPhotoProtocol.h @@ -0,0 +1 @@ +../../../MWPhotoBrowser/MWPhotoBrowser/Classes/MWPhotoProtocol.h \ No newline at end of file diff --git a/ios/Pods/Headers/Build/MWPhotoBrowser/MWTapDetectingImageView.h b/ios/Pods/Headers/Build/MWPhotoBrowser/MWTapDetectingImageView.h new file mode 120000 index 000000000..6b79a7027 --- /dev/null +++ b/ios/Pods/Headers/Build/MWPhotoBrowser/MWTapDetectingImageView.h @@ -0,0 +1 @@ +../../../MWPhotoBrowser/MWPhotoBrowser/Classes/MWTapDetectingImageView.h \ No newline at end of file diff --git a/ios/Pods/Headers/Build/MWPhotoBrowser/MWTapDetectingView.h b/ios/Pods/Headers/Build/MWPhotoBrowser/MWTapDetectingView.h new file mode 120000 index 000000000..48e9abbb7 --- /dev/null +++ b/ios/Pods/Headers/Build/MWPhotoBrowser/MWTapDetectingView.h @@ -0,0 +1 @@ +../../../MWPhotoBrowser/MWPhotoBrowser/Classes/MWTapDetectingView.h \ No newline at end of file diff --git a/ios/Pods/Headers/Build/MWPhotoBrowser/MWZoomingScrollView.h b/ios/Pods/Headers/Build/MWPhotoBrowser/MWZoomingScrollView.h new file mode 120000 index 000000000..69e4f5620 --- /dev/null +++ b/ios/Pods/Headers/Build/MWPhotoBrowser/MWZoomingScrollView.h @@ -0,0 +1 @@ +../../../MWPhotoBrowser/MWPhotoBrowser/Classes/MWZoomingScrollView.h \ No newline at end of file diff --git a/ios/Pods/Headers/Build/PSTCollectionView/NSIndexPath+PSTCollectionViewAdditions.h b/ios/Pods/Headers/Build/PSTCollectionView/NSIndexPath+PSTCollectionViewAdditions.h new file mode 120000 index 000000000..4c7f8b365 --- /dev/null +++ b/ios/Pods/Headers/Build/PSTCollectionView/NSIndexPath+PSTCollectionViewAdditions.h @@ -0,0 +1 @@ +../../../PSTCollectionView/PSTCollectionView/NSIndexPath+PSTCollectionViewAdditions.h \ No newline at end of file diff --git a/ios/Pods/Headers/Build/PSTCollectionView/PSTCollectionView.h b/ios/Pods/Headers/Build/PSTCollectionView/PSTCollectionView.h new file mode 120000 index 000000000..7c79db062 --- /dev/null +++ b/ios/Pods/Headers/Build/PSTCollectionView/PSTCollectionView.h @@ -0,0 +1 @@ +../../../PSTCollectionView/PSTCollectionView/PSTCollectionView.h \ No newline at end of file diff --git a/ios/Pods/Headers/Build/PSTCollectionView/PSTCollectionViewCell.h b/ios/Pods/Headers/Build/PSTCollectionView/PSTCollectionViewCell.h new file mode 120000 index 000000000..de5e37a81 --- /dev/null +++ b/ios/Pods/Headers/Build/PSTCollectionView/PSTCollectionViewCell.h @@ -0,0 +1 @@ +../../../PSTCollectionView/PSTCollectionView/PSTCollectionViewCell.h \ No newline at end of file diff --git a/ios/Pods/Headers/Build/PSTCollectionView/PSTCollectionViewCommon.h b/ios/Pods/Headers/Build/PSTCollectionView/PSTCollectionViewCommon.h new file mode 120000 index 000000000..d2d5c4d55 --- /dev/null +++ b/ios/Pods/Headers/Build/PSTCollectionView/PSTCollectionViewCommon.h @@ -0,0 +1 @@ +../../../PSTCollectionView/PSTCollectionView/PSTCollectionViewCommon.h \ No newline at end of file diff --git a/ios/Pods/Headers/Build/PSTCollectionView/PSTCollectionViewController.h b/ios/Pods/Headers/Build/PSTCollectionView/PSTCollectionViewController.h new file mode 120000 index 000000000..e99bef7b7 --- /dev/null +++ b/ios/Pods/Headers/Build/PSTCollectionView/PSTCollectionViewController.h @@ -0,0 +1 @@ +../../../PSTCollectionView/PSTCollectionView/PSTCollectionViewController.h \ No newline at end of file diff --git a/ios/Pods/Headers/Build/PSTCollectionView/PSTCollectionViewData.h b/ios/Pods/Headers/Build/PSTCollectionView/PSTCollectionViewData.h new file mode 120000 index 000000000..c1ae1bd70 --- /dev/null +++ b/ios/Pods/Headers/Build/PSTCollectionView/PSTCollectionViewData.h @@ -0,0 +1 @@ +../../../PSTCollectionView/PSTCollectionView/PSTCollectionViewData.h \ No newline at end of file diff --git a/ios/Pods/Headers/Build/PSTCollectionView/PSTCollectionViewFlowLayout.h b/ios/Pods/Headers/Build/PSTCollectionView/PSTCollectionViewFlowLayout.h new file mode 120000 index 000000000..0865bdaab --- /dev/null +++ b/ios/Pods/Headers/Build/PSTCollectionView/PSTCollectionViewFlowLayout.h @@ -0,0 +1 @@ +../../../PSTCollectionView/PSTCollectionView/PSTCollectionViewFlowLayout.h \ No newline at end of file diff --git a/ios/Pods/Headers/Build/PSTCollectionView/PSTCollectionViewItemKey.h b/ios/Pods/Headers/Build/PSTCollectionView/PSTCollectionViewItemKey.h new file mode 120000 index 000000000..1879bfbd6 --- /dev/null +++ b/ios/Pods/Headers/Build/PSTCollectionView/PSTCollectionViewItemKey.h @@ -0,0 +1 @@ +../../../PSTCollectionView/PSTCollectionView/PSTCollectionViewItemKey.h \ No newline at end of file diff --git a/ios/Pods/Headers/Build/PSTCollectionView/PSTCollectionViewLayout+Internals.h b/ios/Pods/Headers/Build/PSTCollectionView/PSTCollectionViewLayout+Internals.h new file mode 120000 index 000000000..35ac25343 --- /dev/null +++ b/ios/Pods/Headers/Build/PSTCollectionView/PSTCollectionViewLayout+Internals.h @@ -0,0 +1 @@ +../../../PSTCollectionView/PSTCollectionView/PSTCollectionViewLayout+Internals.h \ No newline at end of file diff --git a/ios/Pods/Headers/Build/PSTCollectionView/PSTCollectionViewLayout.h b/ios/Pods/Headers/Build/PSTCollectionView/PSTCollectionViewLayout.h new file mode 120000 index 000000000..3c668a242 --- /dev/null +++ b/ios/Pods/Headers/Build/PSTCollectionView/PSTCollectionViewLayout.h @@ -0,0 +1 @@ +../../../PSTCollectionView/PSTCollectionView/PSTCollectionViewLayout.h \ No newline at end of file diff --git a/ios/Pods/Headers/Build/PSTCollectionView/PSTCollectionViewUpdateItem.h b/ios/Pods/Headers/Build/PSTCollectionView/PSTCollectionViewUpdateItem.h new file mode 120000 index 000000000..8c2f4f58c --- /dev/null +++ b/ios/Pods/Headers/Build/PSTCollectionView/PSTCollectionViewUpdateItem.h @@ -0,0 +1 @@ +../../../PSTCollectionView/PSTCollectionView/PSTCollectionViewUpdateItem.h \ No newline at end of file diff --git a/ios/Pods/Headers/Build/PSTCollectionView/PSTGridLayoutInfo.h b/ios/Pods/Headers/Build/PSTCollectionView/PSTGridLayoutInfo.h new file mode 120000 index 000000000..5b81070b5 --- /dev/null +++ b/ios/Pods/Headers/Build/PSTCollectionView/PSTGridLayoutInfo.h @@ -0,0 +1 @@ +../../../PSTCollectionView/PSTCollectionView/PSTGridLayoutInfo.h \ No newline at end of file diff --git a/ios/Pods/Headers/Build/PSTCollectionView/PSTGridLayoutItem.h b/ios/Pods/Headers/Build/PSTCollectionView/PSTGridLayoutItem.h new file mode 120000 index 000000000..8beec7e6d --- /dev/null +++ b/ios/Pods/Headers/Build/PSTCollectionView/PSTGridLayoutItem.h @@ -0,0 +1 @@ +../../../PSTCollectionView/PSTCollectionView/PSTGridLayoutItem.h \ No newline at end of file diff --git a/ios/Pods/Headers/Build/PSTCollectionView/PSTGridLayoutRow.h b/ios/Pods/Headers/Build/PSTCollectionView/PSTGridLayoutRow.h new file mode 120000 index 000000000..f29321818 --- /dev/null +++ b/ios/Pods/Headers/Build/PSTCollectionView/PSTGridLayoutRow.h @@ -0,0 +1 @@ +../../../PSTCollectionView/PSTCollectionView/PSTGridLayoutRow.h \ No newline at end of file diff --git a/ios/Pods/Headers/Build/PSTCollectionView/PSTGridLayoutSection.h b/ios/Pods/Headers/Build/PSTCollectionView/PSTGridLayoutSection.h new file mode 120000 index 000000000..6188f30e4 --- /dev/null +++ b/ios/Pods/Headers/Build/PSTCollectionView/PSTGridLayoutSection.h @@ -0,0 +1 @@ +../../../PSTCollectionView/PSTCollectionView/PSTGridLayoutSection.h \ No newline at end of file diff --git a/ios/Pods/Headers/Build/ProtocolBuffers/ProtocolBuffers/AbstractMessage.h b/ios/Pods/Headers/Build/ProtocolBuffers/ProtocolBuffers/AbstractMessage.h new file mode 120000 index 000000000..02b035b8f --- /dev/null +++ b/ios/Pods/Headers/Build/ProtocolBuffers/ProtocolBuffers/AbstractMessage.h @@ -0,0 +1 @@ +../../../../ProtocolBuffers/src/runtime/Classes/AbstractMessage.h \ No newline at end of file diff --git a/ios/Pods/Headers/Build/ProtocolBuffers/ProtocolBuffers/AbstractMessageBuilder.h b/ios/Pods/Headers/Build/ProtocolBuffers/ProtocolBuffers/AbstractMessageBuilder.h new file mode 120000 index 000000000..a768765b4 --- /dev/null +++ b/ios/Pods/Headers/Build/ProtocolBuffers/ProtocolBuffers/AbstractMessageBuilder.h @@ -0,0 +1 @@ +../../../../ProtocolBuffers/src/runtime/Classes/AbstractMessageBuilder.h \ No newline at end of file diff --git a/ios/Pods/Headers/Build/ProtocolBuffers/ProtocolBuffers/Bootstrap.h b/ios/Pods/Headers/Build/ProtocolBuffers/ProtocolBuffers/Bootstrap.h new file mode 120000 index 000000000..f982e0635 --- /dev/null +++ b/ios/Pods/Headers/Build/ProtocolBuffers/ProtocolBuffers/Bootstrap.h @@ -0,0 +1 @@ +../../../../ProtocolBuffers/src/runtime/Classes/Bootstrap.h \ No newline at end of file diff --git a/ios/Pods/Headers/Build/ProtocolBuffers/ProtocolBuffers/CodedInputStream.h b/ios/Pods/Headers/Build/ProtocolBuffers/ProtocolBuffers/CodedInputStream.h new file mode 120000 index 000000000..88c1caf7b --- /dev/null +++ b/ios/Pods/Headers/Build/ProtocolBuffers/ProtocolBuffers/CodedInputStream.h @@ -0,0 +1 @@ +../../../../ProtocolBuffers/src/runtime/Classes/CodedInputStream.h \ No newline at end of file diff --git a/ios/Pods/Headers/Build/ProtocolBuffers/ProtocolBuffers/CodedOutputStream.h b/ios/Pods/Headers/Build/ProtocolBuffers/ProtocolBuffers/CodedOutputStream.h new file mode 120000 index 000000000..7ad312cf2 --- /dev/null +++ b/ios/Pods/Headers/Build/ProtocolBuffers/ProtocolBuffers/CodedOutputStream.h @@ -0,0 +1 @@ +../../../../ProtocolBuffers/src/runtime/Classes/CodedOutputStream.h \ No newline at end of file diff --git a/ios/Pods/Headers/Build/ProtocolBuffers/ProtocolBuffers/ConcreteExtensionField.h b/ios/Pods/Headers/Build/ProtocolBuffers/ProtocolBuffers/ConcreteExtensionField.h new file mode 120000 index 000000000..8975928cd --- /dev/null +++ b/ios/Pods/Headers/Build/ProtocolBuffers/ProtocolBuffers/ConcreteExtensionField.h @@ -0,0 +1 @@ +../../../../ProtocolBuffers/src/runtime/Classes/ConcreteExtensionField.h \ No newline at end of file diff --git a/ios/Pods/Headers/Build/ProtocolBuffers/ProtocolBuffers/Descriptor.pb.h b/ios/Pods/Headers/Build/ProtocolBuffers/ProtocolBuffers/Descriptor.pb.h new file mode 120000 index 000000000..af11c1693 --- /dev/null +++ b/ios/Pods/Headers/Build/ProtocolBuffers/ProtocolBuffers/Descriptor.pb.h @@ -0,0 +1 @@ +../../../../ProtocolBuffers/src/runtime/Classes/Descriptor.pb.h \ No newline at end of file diff --git a/ios/Pods/Headers/Build/ProtocolBuffers/ProtocolBuffers/ExtendableMessage.h b/ios/Pods/Headers/Build/ProtocolBuffers/ProtocolBuffers/ExtendableMessage.h new file mode 120000 index 000000000..68aa8b57b --- /dev/null +++ b/ios/Pods/Headers/Build/ProtocolBuffers/ProtocolBuffers/ExtendableMessage.h @@ -0,0 +1 @@ +../../../../ProtocolBuffers/src/runtime/Classes/ExtendableMessage.h \ No newline at end of file diff --git a/ios/Pods/Headers/Build/ProtocolBuffers/ProtocolBuffers/ExtendableMessageBuilder.h b/ios/Pods/Headers/Build/ProtocolBuffers/ProtocolBuffers/ExtendableMessageBuilder.h new file mode 120000 index 000000000..5efe55ab6 --- /dev/null +++ b/ios/Pods/Headers/Build/ProtocolBuffers/ProtocolBuffers/ExtendableMessageBuilder.h @@ -0,0 +1 @@ +../../../../ProtocolBuffers/src/runtime/Classes/ExtendableMessageBuilder.h \ No newline at end of file diff --git a/ios/Pods/Headers/Build/ProtocolBuffers/ProtocolBuffers/ExtensionField.h b/ios/Pods/Headers/Build/ProtocolBuffers/ProtocolBuffers/ExtensionField.h new file mode 120000 index 000000000..b6d3dc82d --- /dev/null +++ b/ios/Pods/Headers/Build/ProtocolBuffers/ProtocolBuffers/ExtensionField.h @@ -0,0 +1 @@ +../../../../ProtocolBuffers/src/runtime/Classes/ExtensionField.h \ No newline at end of file diff --git a/ios/Pods/Headers/Build/ProtocolBuffers/ProtocolBuffers/ExtensionRegistry.h b/ios/Pods/Headers/Build/ProtocolBuffers/ProtocolBuffers/ExtensionRegistry.h new file mode 120000 index 000000000..ad9fbbfbd --- /dev/null +++ b/ios/Pods/Headers/Build/ProtocolBuffers/ProtocolBuffers/ExtensionRegistry.h @@ -0,0 +1 @@ +../../../../ProtocolBuffers/src/runtime/Classes/ExtensionRegistry.h \ No newline at end of file diff --git a/ios/Pods/Headers/Build/ProtocolBuffers/ProtocolBuffers/Field.h b/ios/Pods/Headers/Build/ProtocolBuffers/ProtocolBuffers/Field.h new file mode 120000 index 000000000..11db638eb --- /dev/null +++ b/ios/Pods/Headers/Build/ProtocolBuffers/ProtocolBuffers/Field.h @@ -0,0 +1 @@ +../../../../ProtocolBuffers/src/runtime/Classes/Field.h \ No newline at end of file diff --git a/ios/Pods/Headers/Build/ProtocolBuffers/ProtocolBuffers/ForwardDeclarations.h b/ios/Pods/Headers/Build/ProtocolBuffers/ProtocolBuffers/ForwardDeclarations.h new file mode 120000 index 000000000..d6966a1b8 --- /dev/null +++ b/ios/Pods/Headers/Build/ProtocolBuffers/ProtocolBuffers/ForwardDeclarations.h @@ -0,0 +1 @@ +../../../../ProtocolBuffers/src/runtime/Classes/ForwardDeclarations.h \ No newline at end of file diff --git a/ios/Pods/Headers/Build/ProtocolBuffers/ProtocolBuffers/GeneratedMessage.h b/ios/Pods/Headers/Build/ProtocolBuffers/ProtocolBuffers/GeneratedMessage.h new file mode 120000 index 000000000..8a2005822 --- /dev/null +++ b/ios/Pods/Headers/Build/ProtocolBuffers/ProtocolBuffers/GeneratedMessage.h @@ -0,0 +1 @@ +../../../../ProtocolBuffers/src/runtime/Classes/GeneratedMessage.h \ No newline at end of file diff --git a/ios/Pods/Headers/Build/ProtocolBuffers/ProtocolBuffers/GeneratedMessageBuilder.h b/ios/Pods/Headers/Build/ProtocolBuffers/ProtocolBuffers/GeneratedMessageBuilder.h new file mode 120000 index 000000000..baa870a8e --- /dev/null +++ b/ios/Pods/Headers/Build/ProtocolBuffers/ProtocolBuffers/GeneratedMessageBuilder.h @@ -0,0 +1 @@ +../../../../ProtocolBuffers/src/runtime/Classes/GeneratedMessageBuilder.h \ No newline at end of file diff --git a/ios/Pods/Headers/Build/ProtocolBuffers/ProtocolBuffers/Message.h b/ios/Pods/Headers/Build/ProtocolBuffers/ProtocolBuffers/Message.h new file mode 120000 index 000000000..5f3b99797 --- /dev/null +++ b/ios/Pods/Headers/Build/ProtocolBuffers/ProtocolBuffers/Message.h @@ -0,0 +1 @@ +../../../../ProtocolBuffers/src/runtime/Classes/Message.h \ No newline at end of file diff --git a/ios/Pods/Headers/Build/ProtocolBuffers/ProtocolBuffers/MessageBuilder.h b/ios/Pods/Headers/Build/ProtocolBuffers/ProtocolBuffers/MessageBuilder.h new file mode 120000 index 000000000..53681abf2 --- /dev/null +++ b/ios/Pods/Headers/Build/ProtocolBuffers/ProtocolBuffers/MessageBuilder.h @@ -0,0 +1 @@ +../../../../ProtocolBuffers/src/runtime/Classes/MessageBuilder.h \ No newline at end of file diff --git a/ios/Pods/Headers/Build/ProtocolBuffers/ProtocolBuffers/MutableExtensionRegistry.h b/ios/Pods/Headers/Build/ProtocolBuffers/ProtocolBuffers/MutableExtensionRegistry.h new file mode 120000 index 000000000..5655db0ba --- /dev/null +++ b/ios/Pods/Headers/Build/ProtocolBuffers/ProtocolBuffers/MutableExtensionRegistry.h @@ -0,0 +1 @@ +../../../../ProtocolBuffers/src/runtime/Classes/MutableExtensionRegistry.h \ No newline at end of file diff --git a/ios/Pods/Headers/Build/ProtocolBuffers/ProtocolBuffers/MutableField.h b/ios/Pods/Headers/Build/ProtocolBuffers/ProtocolBuffers/MutableField.h new file mode 120000 index 000000000..421f9ef1e --- /dev/null +++ b/ios/Pods/Headers/Build/ProtocolBuffers/ProtocolBuffers/MutableField.h @@ -0,0 +1 @@ +../../../../ProtocolBuffers/src/runtime/Classes/MutableField.h \ No newline at end of file diff --git a/ios/Pods/Headers/Build/ProtocolBuffers/ProtocolBuffers/PBArray.h b/ios/Pods/Headers/Build/ProtocolBuffers/ProtocolBuffers/PBArray.h new file mode 120000 index 000000000..2bd608d19 --- /dev/null +++ b/ios/Pods/Headers/Build/ProtocolBuffers/ProtocolBuffers/PBArray.h @@ -0,0 +1 @@ +../../../../ProtocolBuffers/src/runtime/Classes/PBArray.h \ No newline at end of file diff --git a/ios/Pods/Headers/Build/ProtocolBuffers/ProtocolBuffers/ProtocolBuffers.h b/ios/Pods/Headers/Build/ProtocolBuffers/ProtocolBuffers/ProtocolBuffers.h new file mode 120000 index 000000000..29d4b82c2 --- /dev/null +++ b/ios/Pods/Headers/Build/ProtocolBuffers/ProtocolBuffers/ProtocolBuffers.h @@ -0,0 +1 @@ +../../../../ProtocolBuffers/src/runtime/Classes/ProtocolBuffers.h \ No newline at end of file diff --git a/ios/Pods/Headers/Build/ProtocolBuffers/ProtocolBuffers/RingBuffer.h b/ios/Pods/Headers/Build/ProtocolBuffers/ProtocolBuffers/RingBuffer.h new file mode 120000 index 000000000..cd4359a5c --- /dev/null +++ b/ios/Pods/Headers/Build/ProtocolBuffers/ProtocolBuffers/RingBuffer.h @@ -0,0 +1 @@ +../../../../ProtocolBuffers/src/runtime/Classes/RingBuffer.h \ No newline at end of file diff --git a/ios/Pods/Headers/Build/ProtocolBuffers/ProtocolBuffers/TextFormat.h b/ios/Pods/Headers/Build/ProtocolBuffers/ProtocolBuffers/TextFormat.h new file mode 120000 index 000000000..37e85f034 --- /dev/null +++ b/ios/Pods/Headers/Build/ProtocolBuffers/ProtocolBuffers/TextFormat.h @@ -0,0 +1 @@ +../../../../ProtocolBuffers/src/runtime/Classes/TextFormat.h \ No newline at end of file diff --git a/ios/Pods/Headers/Build/ProtocolBuffers/ProtocolBuffers/UnknownFieldSet.h b/ios/Pods/Headers/Build/ProtocolBuffers/ProtocolBuffers/UnknownFieldSet.h new file mode 120000 index 000000000..1b41c25b9 --- /dev/null +++ b/ios/Pods/Headers/Build/ProtocolBuffers/ProtocolBuffers/UnknownFieldSet.h @@ -0,0 +1 @@ +../../../../ProtocolBuffers/src/runtime/Classes/UnknownFieldSet.h \ No newline at end of file diff --git a/ios/Pods/Headers/Build/ProtocolBuffers/ProtocolBuffers/UnknownFieldSetBuilder.h b/ios/Pods/Headers/Build/ProtocolBuffers/ProtocolBuffers/UnknownFieldSetBuilder.h new file mode 120000 index 000000000..988d8cafb --- /dev/null +++ b/ios/Pods/Headers/Build/ProtocolBuffers/ProtocolBuffers/UnknownFieldSetBuilder.h @@ -0,0 +1 @@ +../../../../ProtocolBuffers/src/runtime/Classes/UnknownFieldSetBuilder.h \ No newline at end of file diff --git a/ios/Pods/Headers/Build/ProtocolBuffers/ProtocolBuffers/Utilities.h b/ios/Pods/Headers/Build/ProtocolBuffers/ProtocolBuffers/Utilities.h new file mode 120000 index 000000000..f31cff40c --- /dev/null +++ b/ios/Pods/Headers/Build/ProtocolBuffers/ProtocolBuffers/Utilities.h @@ -0,0 +1 @@ +../../../../ProtocolBuffers/src/runtime/Classes/Utilities.h \ No newline at end of file diff --git a/ios/Pods/Headers/Build/ProtocolBuffers/ProtocolBuffers/WireFormat.h b/ios/Pods/Headers/Build/ProtocolBuffers/ProtocolBuffers/WireFormat.h new file mode 120000 index 000000000..9afcf5ac3 --- /dev/null +++ b/ios/Pods/Headers/Build/ProtocolBuffers/ProtocolBuffers/WireFormat.h @@ -0,0 +1 @@ +../../../../ProtocolBuffers/src/runtime/Classes/WireFormat.h \ No newline at end of file diff --git a/ios/Pods/Headers/Build/SCLAlertView-Objective-C/SCLAlertView.h b/ios/Pods/Headers/Build/SCLAlertView-Objective-C/SCLAlertView.h new file mode 120000 index 000000000..153c3f068 --- /dev/null +++ b/ios/Pods/Headers/Build/SCLAlertView-Objective-C/SCLAlertView.h @@ -0,0 +1 @@ +../../../SCLAlertView-Objective-C/SCLAlertView/SCLAlertView.h \ No newline at end of file diff --git a/ios/Pods/Headers/Build/SCLAlertView-Objective-C/SCLAlertViewResponder.h b/ios/Pods/Headers/Build/SCLAlertView-Objective-C/SCLAlertViewResponder.h new file mode 120000 index 000000000..c5754aa4c --- /dev/null +++ b/ios/Pods/Headers/Build/SCLAlertView-Objective-C/SCLAlertViewResponder.h @@ -0,0 +1 @@ +../../../SCLAlertView-Objective-C/SCLAlertView/SCLAlertViewResponder.h \ No newline at end of file diff --git a/ios/Pods/Headers/Build/SCLAlertView-Objective-C/SCLAlertViewStyleKit.h b/ios/Pods/Headers/Build/SCLAlertView-Objective-C/SCLAlertViewStyleKit.h new file mode 120000 index 000000000..0b23a2eff --- /dev/null +++ b/ios/Pods/Headers/Build/SCLAlertView-Objective-C/SCLAlertViewStyleKit.h @@ -0,0 +1 @@ +../../../SCLAlertView-Objective-C/SCLAlertView/SCLAlertViewStyleKit.h \ No newline at end of file diff --git a/ios/Pods/Headers/Build/SCLAlertView-Objective-C/SCLButton.h b/ios/Pods/Headers/Build/SCLAlertView-Objective-C/SCLButton.h new file mode 120000 index 000000000..cbc946228 --- /dev/null +++ b/ios/Pods/Headers/Build/SCLAlertView-Objective-C/SCLButton.h @@ -0,0 +1 @@ +../../../SCLAlertView-Objective-C/SCLAlertView/SCLButton.h \ No newline at end of file diff --git a/ios/Pods/Headers/Build/SCLAlertView-Objective-C/UIImage+ImageEffects.h b/ios/Pods/Headers/Build/SCLAlertView-Objective-C/UIImage+ImageEffects.h new file mode 120000 index 000000000..8c083c13c --- /dev/null +++ b/ios/Pods/Headers/Build/SCLAlertView-Objective-C/UIImage+ImageEffects.h @@ -0,0 +1 @@ +../../../SCLAlertView-Objective-C/SCLAlertView/UIImage+ImageEffects.h \ No newline at end of file diff --git a/ios/Pods/Headers/Build/SDWebImage/NSData+ImageContentType.h b/ios/Pods/Headers/Build/SDWebImage/NSData+ImageContentType.h new file mode 120000 index 000000000..84574987a --- /dev/null +++ b/ios/Pods/Headers/Build/SDWebImage/NSData+ImageContentType.h @@ -0,0 +1 @@ +../../../SDWebImage/SDWebImage/NSData+ImageContentType.h \ No newline at end of file diff --git a/ios/Pods/Headers/Build/SDWebImage/SDImageCache.h b/ios/Pods/Headers/Build/SDWebImage/SDImageCache.h new file mode 120000 index 000000000..0040b06a1 --- /dev/null +++ b/ios/Pods/Headers/Build/SDWebImage/SDImageCache.h @@ -0,0 +1 @@ +../../../SDWebImage/SDWebImage/SDImageCache.h \ No newline at end of file diff --git a/ios/Pods/Headers/Build/SDWebImage/SDWebImageCompat.h b/ios/Pods/Headers/Build/SDWebImage/SDWebImageCompat.h new file mode 120000 index 000000000..6ca247842 --- /dev/null +++ b/ios/Pods/Headers/Build/SDWebImage/SDWebImageCompat.h @@ -0,0 +1 @@ +../../../SDWebImage/SDWebImage/SDWebImageCompat.h \ No newline at end of file diff --git a/ios/Pods/Headers/Build/SDWebImage/SDWebImageDecoder.h b/ios/Pods/Headers/Build/SDWebImage/SDWebImageDecoder.h new file mode 120000 index 000000000..a2f3a683d --- /dev/null +++ b/ios/Pods/Headers/Build/SDWebImage/SDWebImageDecoder.h @@ -0,0 +1 @@ +../../../SDWebImage/SDWebImage/SDWebImageDecoder.h \ No newline at end of file diff --git a/ios/Pods/Headers/Build/SDWebImage/SDWebImageDownloader.h b/ios/Pods/Headers/Build/SDWebImage/SDWebImageDownloader.h new file mode 120000 index 000000000..303b03b1e --- /dev/null +++ b/ios/Pods/Headers/Build/SDWebImage/SDWebImageDownloader.h @@ -0,0 +1 @@ +../../../SDWebImage/SDWebImage/SDWebImageDownloader.h \ No newline at end of file diff --git a/ios/Pods/Headers/Build/SDWebImage/SDWebImageDownloaderOperation.h b/ios/Pods/Headers/Build/SDWebImage/SDWebImageDownloaderOperation.h new file mode 120000 index 000000000..99441c485 --- /dev/null +++ b/ios/Pods/Headers/Build/SDWebImage/SDWebImageDownloaderOperation.h @@ -0,0 +1 @@ +../../../SDWebImage/SDWebImage/SDWebImageDownloaderOperation.h \ No newline at end of file diff --git a/ios/Pods/Headers/Build/SDWebImage/SDWebImageManager.h b/ios/Pods/Headers/Build/SDWebImage/SDWebImageManager.h new file mode 120000 index 000000000..1b8184856 --- /dev/null +++ b/ios/Pods/Headers/Build/SDWebImage/SDWebImageManager.h @@ -0,0 +1 @@ +../../../SDWebImage/SDWebImage/SDWebImageManager.h \ No newline at end of file diff --git a/ios/Pods/Headers/Build/SDWebImage/SDWebImageOperation.h b/ios/Pods/Headers/Build/SDWebImage/SDWebImageOperation.h new file mode 120000 index 000000000..20e5b89ef --- /dev/null +++ b/ios/Pods/Headers/Build/SDWebImage/SDWebImageOperation.h @@ -0,0 +1 @@ +../../../SDWebImage/SDWebImage/SDWebImageOperation.h \ No newline at end of file diff --git a/ios/Pods/Headers/Build/SDWebImage/SDWebImagePrefetcher.h b/ios/Pods/Headers/Build/SDWebImage/SDWebImagePrefetcher.h new file mode 120000 index 000000000..50585c6d0 --- /dev/null +++ b/ios/Pods/Headers/Build/SDWebImage/SDWebImagePrefetcher.h @@ -0,0 +1 @@ +../../../SDWebImage/SDWebImage/SDWebImagePrefetcher.h \ No newline at end of file diff --git a/ios/Pods/Headers/Build/SDWebImage/UIButton+WebCache.h b/ios/Pods/Headers/Build/SDWebImage/UIButton+WebCache.h new file mode 120000 index 000000000..19d2d8e8c --- /dev/null +++ b/ios/Pods/Headers/Build/SDWebImage/UIButton+WebCache.h @@ -0,0 +1 @@ +../../../SDWebImage/SDWebImage/UIButton+WebCache.h \ No newline at end of file diff --git a/ios/Pods/Headers/Build/SDWebImage/UIImage+GIF.h b/ios/Pods/Headers/Build/SDWebImage/UIImage+GIF.h new file mode 120000 index 000000000..14d5aadd9 --- /dev/null +++ b/ios/Pods/Headers/Build/SDWebImage/UIImage+GIF.h @@ -0,0 +1 @@ +../../../SDWebImage/SDWebImage/UIImage+GIF.h \ No newline at end of file diff --git a/ios/Pods/Headers/Build/SDWebImage/UIImage+MultiFormat.h b/ios/Pods/Headers/Build/SDWebImage/UIImage+MultiFormat.h new file mode 120000 index 000000000..1fb965010 --- /dev/null +++ b/ios/Pods/Headers/Build/SDWebImage/UIImage+MultiFormat.h @@ -0,0 +1 @@ +../../../SDWebImage/SDWebImage/UIImage+MultiFormat.h \ No newline at end of file diff --git a/ios/Pods/Headers/Build/SDWebImage/UIImageView+HighlightedWebCache.h b/ios/Pods/Headers/Build/SDWebImage/UIImageView+HighlightedWebCache.h new file mode 120000 index 000000000..fd4dea41e --- /dev/null +++ b/ios/Pods/Headers/Build/SDWebImage/UIImageView+HighlightedWebCache.h @@ -0,0 +1 @@ +../../../SDWebImage/SDWebImage/UIImageView+HighlightedWebCache.h \ No newline at end of file diff --git a/ios/Pods/Headers/Build/SDWebImage/UIImageView+WebCache.h b/ios/Pods/Headers/Build/SDWebImage/UIImageView+WebCache.h new file mode 120000 index 000000000..0c53a47b8 --- /dev/null +++ b/ios/Pods/Headers/Build/SDWebImage/UIImageView+WebCache.h @@ -0,0 +1 @@ +../../../SDWebImage/SDWebImage/UIImageView+WebCache.h \ No newline at end of file diff --git a/ios/Pods/Headers/Build/SDWebImage/UIView+WebCacheOperation.h b/ios/Pods/Headers/Build/SDWebImage/UIView+WebCacheOperation.h new file mode 120000 index 000000000..f9890c406 --- /dev/null +++ b/ios/Pods/Headers/Build/SDWebImage/UIView+WebCacheOperation.h @@ -0,0 +1 @@ +../../../SDWebImage/SDWebImage/UIView+WebCacheOperation.h \ No newline at end of file diff --git a/ios/Pods/Headers/Build/leveldb-library/leveldb/c.h b/ios/Pods/Headers/Build/leveldb-library/leveldb/c.h new file mode 120000 index 000000000..684bb4bc9 --- /dev/null +++ b/ios/Pods/Headers/Build/leveldb-library/leveldb/c.h @@ -0,0 +1 @@ +../../../../leveldb-library/include/leveldb/c.h \ No newline at end of file diff --git a/ios/Pods/Headers/Build/leveldb-library/leveldb/cache.h b/ios/Pods/Headers/Build/leveldb-library/leveldb/cache.h new file mode 120000 index 000000000..f71b37911 --- /dev/null +++ b/ios/Pods/Headers/Build/leveldb-library/leveldb/cache.h @@ -0,0 +1 @@ +../../../../leveldb-library/include/leveldb/cache.h \ No newline at end of file diff --git a/ios/Pods/Headers/Build/leveldb-library/leveldb/comparator.h b/ios/Pods/Headers/Build/leveldb-library/leveldb/comparator.h new file mode 120000 index 000000000..d092f9750 --- /dev/null +++ b/ios/Pods/Headers/Build/leveldb-library/leveldb/comparator.h @@ -0,0 +1 @@ +../../../../leveldb-library/include/leveldb/comparator.h \ No newline at end of file diff --git a/ios/Pods/Headers/Build/leveldb-library/leveldb/db.h b/ios/Pods/Headers/Build/leveldb-library/leveldb/db.h new file mode 120000 index 000000000..e68182ac1 --- /dev/null +++ b/ios/Pods/Headers/Build/leveldb-library/leveldb/db.h @@ -0,0 +1 @@ +../../../../leveldb-library/include/leveldb/db.h \ No newline at end of file diff --git a/ios/Pods/Headers/Build/leveldb-library/leveldb/dumpfile.h b/ios/Pods/Headers/Build/leveldb-library/leveldb/dumpfile.h new file mode 120000 index 000000000..53b92ee13 --- /dev/null +++ b/ios/Pods/Headers/Build/leveldb-library/leveldb/dumpfile.h @@ -0,0 +1 @@ +../../../../leveldb-library/include/leveldb/dumpfile.h \ No newline at end of file diff --git a/ios/Pods/Headers/Build/leveldb-library/leveldb/env.h b/ios/Pods/Headers/Build/leveldb-library/leveldb/env.h new file mode 120000 index 000000000..655aee312 --- /dev/null +++ b/ios/Pods/Headers/Build/leveldb-library/leveldb/env.h @@ -0,0 +1 @@ +../../../../leveldb-library/include/leveldb/env.h \ No newline at end of file diff --git a/ios/Pods/Headers/Build/leveldb-library/leveldb/filter_policy.h b/ios/Pods/Headers/Build/leveldb-library/leveldb/filter_policy.h new file mode 120000 index 000000000..24bd90c57 --- /dev/null +++ b/ios/Pods/Headers/Build/leveldb-library/leveldb/filter_policy.h @@ -0,0 +1 @@ +../../../../leveldb-library/include/leveldb/filter_policy.h \ No newline at end of file diff --git a/ios/Pods/Headers/Build/leveldb-library/leveldb/iterator.h b/ios/Pods/Headers/Build/leveldb-library/leveldb/iterator.h new file mode 120000 index 000000000..0b79d163a --- /dev/null +++ b/ios/Pods/Headers/Build/leveldb-library/leveldb/iterator.h @@ -0,0 +1 @@ +../../../../leveldb-library/include/leveldb/iterator.h \ No newline at end of file diff --git a/ios/Pods/Headers/Build/leveldb-library/leveldb/options.h b/ios/Pods/Headers/Build/leveldb-library/leveldb/options.h new file mode 120000 index 000000000..df730a3cc --- /dev/null +++ b/ios/Pods/Headers/Build/leveldb-library/leveldb/options.h @@ -0,0 +1 @@ +../../../../leveldb-library/include/leveldb/options.h \ No newline at end of file diff --git a/ios/Pods/Headers/Build/leveldb-library/leveldb/slice.h b/ios/Pods/Headers/Build/leveldb-library/leveldb/slice.h new file mode 120000 index 000000000..1198d0335 --- /dev/null +++ b/ios/Pods/Headers/Build/leveldb-library/leveldb/slice.h @@ -0,0 +1 @@ +../../../../leveldb-library/include/leveldb/slice.h \ No newline at end of file diff --git a/ios/Pods/Headers/Build/leveldb-library/leveldb/status.h b/ios/Pods/Headers/Build/leveldb-library/leveldb/status.h new file mode 120000 index 000000000..f0a87b2fe --- /dev/null +++ b/ios/Pods/Headers/Build/leveldb-library/leveldb/status.h @@ -0,0 +1 @@ +../../../../leveldb-library/include/leveldb/status.h \ No newline at end of file diff --git a/ios/Pods/Headers/Build/leveldb-library/leveldb/table.h b/ios/Pods/Headers/Build/leveldb-library/leveldb/table.h new file mode 120000 index 000000000..6951d31cd --- /dev/null +++ b/ios/Pods/Headers/Build/leveldb-library/leveldb/table.h @@ -0,0 +1 @@ +../../../../leveldb-library/include/leveldb/table.h \ No newline at end of file diff --git a/ios/Pods/Headers/Build/leveldb-library/leveldb/table_builder.h b/ios/Pods/Headers/Build/leveldb-library/leveldb/table_builder.h new file mode 120000 index 000000000..e396af91c --- /dev/null +++ b/ios/Pods/Headers/Build/leveldb-library/leveldb/table_builder.h @@ -0,0 +1 @@ +../../../../leveldb-library/include/leveldb/table_builder.h \ No newline at end of file diff --git a/ios/Pods/Headers/Build/leveldb-library/leveldb/write_batch.h b/ios/Pods/Headers/Build/leveldb-library/leveldb/write_batch.h new file mode 120000 index 000000000..fdc08d62a --- /dev/null +++ b/ios/Pods/Headers/Build/leveldb-library/leveldb/write_batch.h @@ -0,0 +1 @@ +../../../../leveldb-library/include/leveldb/write_batch.h \ No newline at end of file diff --git a/ios/Pods/Headers/Public/AFNetworking/AFHTTPRequestOperation.h b/ios/Pods/Headers/Public/AFNetworking/AFHTTPRequestOperation.h new file mode 120000 index 000000000..ac762c823 --- /dev/null +++ b/ios/Pods/Headers/Public/AFNetworking/AFHTTPRequestOperation.h @@ -0,0 +1 @@ +../../../AFNetworking/AFNetworking/AFHTTPRequestOperation.h \ No newline at end of file diff --git a/ios/Pods/Headers/Public/AFNetworking/AFHTTPRequestOperationManager.h b/ios/Pods/Headers/Public/AFNetworking/AFHTTPRequestOperationManager.h new file mode 120000 index 000000000..9dcc623c6 --- /dev/null +++ b/ios/Pods/Headers/Public/AFNetworking/AFHTTPRequestOperationManager.h @@ -0,0 +1 @@ +../../../AFNetworking/AFNetworking/AFHTTPRequestOperationManager.h \ No newline at end of file diff --git a/ios/Pods/Headers/Public/AFNetworking/AFHTTPSessionManager.h b/ios/Pods/Headers/Public/AFNetworking/AFHTTPSessionManager.h new file mode 120000 index 000000000..56feb9fb8 --- /dev/null +++ b/ios/Pods/Headers/Public/AFNetworking/AFHTTPSessionManager.h @@ -0,0 +1 @@ +../../../AFNetworking/AFNetworking/AFHTTPSessionManager.h \ No newline at end of file diff --git a/ios/Pods/Headers/Public/AFNetworking/AFNetworkActivityIndicatorManager.h b/ios/Pods/Headers/Public/AFNetworking/AFNetworkActivityIndicatorManager.h new file mode 120000 index 000000000..67519d984 --- /dev/null +++ b/ios/Pods/Headers/Public/AFNetworking/AFNetworkActivityIndicatorManager.h @@ -0,0 +1 @@ +../../../AFNetworking/UIKit+AFNetworking/AFNetworkActivityIndicatorManager.h \ No newline at end of file diff --git a/ios/Pods/Headers/Public/AFNetworking/AFNetworkReachabilityManager.h b/ios/Pods/Headers/Public/AFNetworking/AFNetworkReachabilityManager.h new file mode 120000 index 000000000..68fc7744f --- /dev/null +++ b/ios/Pods/Headers/Public/AFNetworking/AFNetworkReachabilityManager.h @@ -0,0 +1 @@ +../../../AFNetworking/AFNetworking/AFNetworkReachabilityManager.h \ No newline at end of file diff --git a/ios/Pods/Headers/Public/AFNetworking/AFNetworking.h b/ios/Pods/Headers/Public/AFNetworking/AFNetworking.h new file mode 120000 index 000000000..a5a38da7d --- /dev/null +++ b/ios/Pods/Headers/Public/AFNetworking/AFNetworking.h @@ -0,0 +1 @@ +../../../AFNetworking/AFNetworking/AFNetworking.h \ No newline at end of file diff --git a/ios/Pods/Headers/Public/AFNetworking/AFSecurityPolicy.h b/ios/Pods/Headers/Public/AFNetworking/AFSecurityPolicy.h new file mode 120000 index 000000000..fd1322db9 --- /dev/null +++ b/ios/Pods/Headers/Public/AFNetworking/AFSecurityPolicy.h @@ -0,0 +1 @@ +../../../AFNetworking/AFNetworking/AFSecurityPolicy.h \ No newline at end of file diff --git a/ios/Pods/Headers/Public/AFNetworking/AFURLConnectionOperation.h b/ios/Pods/Headers/Public/AFNetworking/AFURLConnectionOperation.h new file mode 120000 index 000000000..d9b35fb75 --- /dev/null +++ b/ios/Pods/Headers/Public/AFNetworking/AFURLConnectionOperation.h @@ -0,0 +1 @@ +../../../AFNetworking/AFNetworking/AFURLConnectionOperation.h \ No newline at end of file diff --git a/ios/Pods/Headers/Public/AFNetworking/AFURLRequestSerialization.h b/ios/Pods/Headers/Public/AFNetworking/AFURLRequestSerialization.h new file mode 120000 index 000000000..ca8209b81 --- /dev/null +++ b/ios/Pods/Headers/Public/AFNetworking/AFURLRequestSerialization.h @@ -0,0 +1 @@ +../../../AFNetworking/AFNetworking/AFURLRequestSerialization.h \ No newline at end of file diff --git a/ios/Pods/Headers/Public/AFNetworking/AFURLResponseSerialization.h b/ios/Pods/Headers/Public/AFNetworking/AFURLResponseSerialization.h new file mode 120000 index 000000000..e36a765d8 --- /dev/null +++ b/ios/Pods/Headers/Public/AFNetworking/AFURLResponseSerialization.h @@ -0,0 +1 @@ +../../../AFNetworking/AFNetworking/AFURLResponseSerialization.h \ No newline at end of file diff --git a/ios/Pods/Headers/Public/AFNetworking/AFURLSessionManager.h b/ios/Pods/Headers/Public/AFNetworking/AFURLSessionManager.h new file mode 120000 index 000000000..835101de7 --- /dev/null +++ b/ios/Pods/Headers/Public/AFNetworking/AFURLSessionManager.h @@ -0,0 +1 @@ +../../../AFNetworking/AFNetworking/AFURLSessionManager.h \ No newline at end of file diff --git a/ios/Pods/Headers/Public/AFNetworking/UIActivityIndicatorView+AFNetworking.h b/ios/Pods/Headers/Public/AFNetworking/UIActivityIndicatorView+AFNetworking.h new file mode 120000 index 000000000..c534ebfb0 --- /dev/null +++ b/ios/Pods/Headers/Public/AFNetworking/UIActivityIndicatorView+AFNetworking.h @@ -0,0 +1 @@ +../../../AFNetworking/UIKit+AFNetworking/UIActivityIndicatorView+AFNetworking.h \ No newline at end of file diff --git a/ios/Pods/Headers/Public/AFNetworking/UIAlertView+AFNetworking.h b/ios/Pods/Headers/Public/AFNetworking/UIAlertView+AFNetworking.h new file mode 120000 index 000000000..f99281338 --- /dev/null +++ b/ios/Pods/Headers/Public/AFNetworking/UIAlertView+AFNetworking.h @@ -0,0 +1 @@ +../../../AFNetworking/UIKit+AFNetworking/UIAlertView+AFNetworking.h \ No newline at end of file diff --git a/ios/Pods/Headers/Public/AFNetworking/UIButton+AFNetworking.h b/ios/Pods/Headers/Public/AFNetworking/UIButton+AFNetworking.h new file mode 120000 index 000000000..8f2e22193 --- /dev/null +++ b/ios/Pods/Headers/Public/AFNetworking/UIButton+AFNetworking.h @@ -0,0 +1 @@ +../../../AFNetworking/UIKit+AFNetworking/UIButton+AFNetworking.h \ No newline at end of file diff --git a/ios/Pods/Headers/Public/AFNetworking/UIImageView+AFNetworking.h b/ios/Pods/Headers/Public/AFNetworking/UIImageView+AFNetworking.h new file mode 120000 index 000000000..a95d67380 --- /dev/null +++ b/ios/Pods/Headers/Public/AFNetworking/UIImageView+AFNetworking.h @@ -0,0 +1 @@ +../../../AFNetworking/UIKit+AFNetworking/UIImageView+AFNetworking.h \ No newline at end of file diff --git a/ios/Pods/Headers/Public/AFNetworking/UIKit+AFNetworking.h b/ios/Pods/Headers/Public/AFNetworking/UIKit+AFNetworking.h new file mode 120000 index 000000000..95017cce5 --- /dev/null +++ b/ios/Pods/Headers/Public/AFNetworking/UIKit+AFNetworking.h @@ -0,0 +1 @@ +../../../AFNetworking/UIKit+AFNetworking/UIKit+AFNetworking.h \ No newline at end of file diff --git a/ios/Pods/Headers/Public/AFNetworking/UIProgressView+AFNetworking.h b/ios/Pods/Headers/Public/AFNetworking/UIProgressView+AFNetworking.h new file mode 120000 index 000000000..730b167dc --- /dev/null +++ b/ios/Pods/Headers/Public/AFNetworking/UIProgressView+AFNetworking.h @@ -0,0 +1 @@ +../../../AFNetworking/UIKit+AFNetworking/UIProgressView+AFNetworking.h \ No newline at end of file diff --git a/ios/Pods/Headers/Public/AFNetworking/UIRefreshControl+AFNetworking.h b/ios/Pods/Headers/Public/AFNetworking/UIRefreshControl+AFNetworking.h new file mode 120000 index 000000000..8efd82620 --- /dev/null +++ b/ios/Pods/Headers/Public/AFNetworking/UIRefreshControl+AFNetworking.h @@ -0,0 +1 @@ +../../../AFNetworking/UIKit+AFNetworking/UIRefreshControl+AFNetworking.h \ No newline at end of file diff --git a/ios/Pods/Headers/Public/AFNetworking/UIWebView+AFNetworking.h b/ios/Pods/Headers/Public/AFNetworking/UIWebView+AFNetworking.h new file mode 120000 index 000000000..c8df6ef17 --- /dev/null +++ b/ios/Pods/Headers/Public/AFNetworking/UIWebView+AFNetworking.h @@ -0,0 +1 @@ +../../../AFNetworking/UIKit+AFNetworking/UIWebView+AFNetworking.h \ No newline at end of file diff --git a/ios/Pods/Headers/Public/DACircularProgress/DACircularProgressView.h b/ios/Pods/Headers/Public/DACircularProgress/DACircularProgressView.h new file mode 120000 index 000000000..b67e984a6 --- /dev/null +++ b/ios/Pods/Headers/Public/DACircularProgress/DACircularProgressView.h @@ -0,0 +1 @@ +../../../DACircularProgress/DACircularProgress/DACircularProgressView.h \ No newline at end of file diff --git a/ios/Pods/Headers/Public/FMDB/FMDB.h b/ios/Pods/Headers/Public/FMDB/FMDB.h new file mode 120000 index 000000000..bcd6e0a12 --- /dev/null +++ b/ios/Pods/Headers/Public/FMDB/FMDB.h @@ -0,0 +1 @@ +../../../FMDB/src/fmdb/FMDB.h \ No newline at end of file diff --git a/ios/Pods/Headers/Public/FMDB/FMDatabase.h b/ios/Pods/Headers/Public/FMDB/FMDatabase.h new file mode 120000 index 000000000..e69b333e8 --- /dev/null +++ b/ios/Pods/Headers/Public/FMDB/FMDatabase.h @@ -0,0 +1 @@ +../../../FMDB/src/fmdb/FMDatabase.h \ No newline at end of file diff --git a/ios/Pods/Headers/Public/FMDB/FMDatabaseAdditions.h b/ios/Pods/Headers/Public/FMDB/FMDatabaseAdditions.h new file mode 120000 index 000000000..b48a6a351 --- /dev/null +++ b/ios/Pods/Headers/Public/FMDB/FMDatabaseAdditions.h @@ -0,0 +1 @@ +../../../FMDB/src/fmdb/FMDatabaseAdditions.h \ No newline at end of file diff --git a/ios/Pods/Headers/Public/FMDB/FMDatabasePool.h b/ios/Pods/Headers/Public/FMDB/FMDatabasePool.h new file mode 120000 index 000000000..1d78001fc --- /dev/null +++ b/ios/Pods/Headers/Public/FMDB/FMDatabasePool.h @@ -0,0 +1 @@ +../../../FMDB/src/fmdb/FMDatabasePool.h \ No newline at end of file diff --git a/ios/Pods/Headers/Public/FMDB/FMDatabaseQueue.h b/ios/Pods/Headers/Public/FMDB/FMDatabaseQueue.h new file mode 120000 index 000000000..9adde8736 --- /dev/null +++ b/ios/Pods/Headers/Public/FMDB/FMDatabaseQueue.h @@ -0,0 +1 @@ +../../../FMDB/src/fmdb/FMDatabaseQueue.h \ No newline at end of file diff --git a/ios/Pods/Headers/Public/FMDB/FMResultSet.h b/ios/Pods/Headers/Public/FMDB/FMResultSet.h new file mode 120000 index 000000000..fd761d84a --- /dev/null +++ b/ios/Pods/Headers/Public/FMDB/FMResultSet.h @@ -0,0 +1 @@ +../../../FMDB/src/fmdb/FMResultSet.h \ No newline at end of file diff --git a/ios/Pods/Headers/Public/HPGrowingTextView/HPGrowingTextView.h b/ios/Pods/Headers/Public/HPGrowingTextView/HPGrowingTextView.h new file mode 120000 index 000000000..d22eb7155 --- /dev/null +++ b/ios/Pods/Headers/Public/HPGrowingTextView/HPGrowingTextView.h @@ -0,0 +1 @@ +../../../HPGrowingTextView/class/HPGrowingTextView.h \ No newline at end of file diff --git a/ios/Pods/Headers/Public/HPGrowingTextView/HPTextViewInternal.h b/ios/Pods/Headers/Public/HPGrowingTextView/HPTextViewInternal.h new file mode 120000 index 000000000..6e9773259 --- /dev/null +++ b/ios/Pods/Headers/Public/HPGrowingTextView/HPTextViewInternal.h @@ -0,0 +1 @@ +../../../HPGrowingTextView/class/HPTextViewInternal.h \ No newline at end of file diff --git a/ios/Pods/Headers/Public/MBProgressHUD/MBProgressHUD.h b/ios/Pods/Headers/Public/MBProgressHUD/MBProgressHUD.h new file mode 120000 index 000000000..19ed4db7d --- /dev/null +++ b/ios/Pods/Headers/Public/MBProgressHUD/MBProgressHUD.h @@ -0,0 +1 @@ +../../../MBProgressHUD/MBProgressHUD.h \ No newline at end of file diff --git a/ios/Pods/Headers/Public/MWPhotoBrowser/MWCaptionView.h b/ios/Pods/Headers/Public/MWPhotoBrowser/MWCaptionView.h new file mode 120000 index 000000000..aab1c09aa --- /dev/null +++ b/ios/Pods/Headers/Public/MWPhotoBrowser/MWCaptionView.h @@ -0,0 +1 @@ +../../../MWPhotoBrowser/MWPhotoBrowser/Classes/MWCaptionView.h \ No newline at end of file diff --git a/ios/Pods/Headers/Public/MWPhotoBrowser/MWCommon.h b/ios/Pods/Headers/Public/MWPhotoBrowser/MWCommon.h new file mode 120000 index 000000000..945d66b82 --- /dev/null +++ b/ios/Pods/Headers/Public/MWPhotoBrowser/MWCommon.h @@ -0,0 +1 @@ +../../../MWPhotoBrowser/MWPhotoBrowser/Classes/MWCommon.h \ No newline at end of file diff --git a/ios/Pods/Headers/Public/MWPhotoBrowser/MWGridCell.h b/ios/Pods/Headers/Public/MWPhotoBrowser/MWGridCell.h new file mode 120000 index 000000000..c2be288ac --- /dev/null +++ b/ios/Pods/Headers/Public/MWPhotoBrowser/MWGridCell.h @@ -0,0 +1 @@ +../../../MWPhotoBrowser/MWPhotoBrowser/Classes/MWGridCell.h \ No newline at end of file diff --git a/ios/Pods/Headers/Public/MWPhotoBrowser/MWGridViewController.h b/ios/Pods/Headers/Public/MWPhotoBrowser/MWGridViewController.h new file mode 120000 index 000000000..bf9f72849 --- /dev/null +++ b/ios/Pods/Headers/Public/MWPhotoBrowser/MWGridViewController.h @@ -0,0 +1 @@ +../../../MWPhotoBrowser/MWPhotoBrowser/Classes/MWGridViewController.h \ No newline at end of file diff --git a/ios/Pods/Headers/Public/MWPhotoBrowser/MWPhoto.h b/ios/Pods/Headers/Public/MWPhotoBrowser/MWPhoto.h new file mode 120000 index 000000000..2770f05fd --- /dev/null +++ b/ios/Pods/Headers/Public/MWPhotoBrowser/MWPhoto.h @@ -0,0 +1 @@ +../../../MWPhotoBrowser/MWPhotoBrowser/Classes/MWPhoto.h \ No newline at end of file diff --git a/ios/Pods/Headers/Public/MWPhotoBrowser/MWPhotoBrowser.h b/ios/Pods/Headers/Public/MWPhotoBrowser/MWPhotoBrowser.h new file mode 120000 index 000000000..cafd1fa0f --- /dev/null +++ b/ios/Pods/Headers/Public/MWPhotoBrowser/MWPhotoBrowser.h @@ -0,0 +1 @@ +../../../MWPhotoBrowser/MWPhotoBrowser/Classes/MWPhotoBrowser.h \ No newline at end of file diff --git a/ios/Pods/Headers/Public/MWPhotoBrowser/MWPhotoBrowserPrivate.h b/ios/Pods/Headers/Public/MWPhotoBrowser/MWPhotoBrowserPrivate.h new file mode 120000 index 000000000..cf26f18e1 --- /dev/null +++ b/ios/Pods/Headers/Public/MWPhotoBrowser/MWPhotoBrowserPrivate.h @@ -0,0 +1 @@ +../../../MWPhotoBrowser/MWPhotoBrowser/Classes/MWPhotoBrowserPrivate.h \ No newline at end of file diff --git a/ios/Pods/Headers/Public/MWPhotoBrowser/MWPhotoProtocol.h b/ios/Pods/Headers/Public/MWPhotoBrowser/MWPhotoProtocol.h new file mode 120000 index 000000000..d7c83b8d1 --- /dev/null +++ b/ios/Pods/Headers/Public/MWPhotoBrowser/MWPhotoProtocol.h @@ -0,0 +1 @@ +../../../MWPhotoBrowser/MWPhotoBrowser/Classes/MWPhotoProtocol.h \ No newline at end of file diff --git a/ios/Pods/Headers/Public/MWPhotoBrowser/MWTapDetectingImageView.h b/ios/Pods/Headers/Public/MWPhotoBrowser/MWTapDetectingImageView.h new file mode 120000 index 000000000..6b79a7027 --- /dev/null +++ b/ios/Pods/Headers/Public/MWPhotoBrowser/MWTapDetectingImageView.h @@ -0,0 +1 @@ +../../../MWPhotoBrowser/MWPhotoBrowser/Classes/MWTapDetectingImageView.h \ No newline at end of file diff --git a/ios/Pods/Headers/Public/MWPhotoBrowser/MWTapDetectingView.h b/ios/Pods/Headers/Public/MWPhotoBrowser/MWTapDetectingView.h new file mode 120000 index 000000000..48e9abbb7 --- /dev/null +++ b/ios/Pods/Headers/Public/MWPhotoBrowser/MWTapDetectingView.h @@ -0,0 +1 @@ +../../../MWPhotoBrowser/MWPhotoBrowser/Classes/MWTapDetectingView.h \ No newline at end of file diff --git a/ios/Pods/Headers/Public/MWPhotoBrowser/MWZoomingScrollView.h b/ios/Pods/Headers/Public/MWPhotoBrowser/MWZoomingScrollView.h new file mode 120000 index 000000000..69e4f5620 --- /dev/null +++ b/ios/Pods/Headers/Public/MWPhotoBrowser/MWZoomingScrollView.h @@ -0,0 +1 @@ +../../../MWPhotoBrowser/MWPhotoBrowser/Classes/MWZoomingScrollView.h \ No newline at end of file diff --git a/ios/Pods/Headers/Public/PSTCollectionView/NSIndexPath+PSTCollectionViewAdditions.h b/ios/Pods/Headers/Public/PSTCollectionView/NSIndexPath+PSTCollectionViewAdditions.h new file mode 120000 index 000000000..4c7f8b365 --- /dev/null +++ b/ios/Pods/Headers/Public/PSTCollectionView/NSIndexPath+PSTCollectionViewAdditions.h @@ -0,0 +1 @@ +../../../PSTCollectionView/PSTCollectionView/NSIndexPath+PSTCollectionViewAdditions.h \ No newline at end of file diff --git a/ios/Pods/Headers/Public/PSTCollectionView/PSTCollectionView.h b/ios/Pods/Headers/Public/PSTCollectionView/PSTCollectionView.h new file mode 120000 index 000000000..7c79db062 --- /dev/null +++ b/ios/Pods/Headers/Public/PSTCollectionView/PSTCollectionView.h @@ -0,0 +1 @@ +../../../PSTCollectionView/PSTCollectionView/PSTCollectionView.h \ No newline at end of file diff --git a/ios/Pods/Headers/Public/PSTCollectionView/PSTCollectionViewCell.h b/ios/Pods/Headers/Public/PSTCollectionView/PSTCollectionViewCell.h new file mode 120000 index 000000000..de5e37a81 --- /dev/null +++ b/ios/Pods/Headers/Public/PSTCollectionView/PSTCollectionViewCell.h @@ -0,0 +1 @@ +../../../PSTCollectionView/PSTCollectionView/PSTCollectionViewCell.h \ No newline at end of file diff --git a/ios/Pods/Headers/Public/PSTCollectionView/PSTCollectionViewCommon.h b/ios/Pods/Headers/Public/PSTCollectionView/PSTCollectionViewCommon.h new file mode 120000 index 000000000..d2d5c4d55 --- /dev/null +++ b/ios/Pods/Headers/Public/PSTCollectionView/PSTCollectionViewCommon.h @@ -0,0 +1 @@ +../../../PSTCollectionView/PSTCollectionView/PSTCollectionViewCommon.h \ No newline at end of file diff --git a/ios/Pods/Headers/Public/PSTCollectionView/PSTCollectionViewController.h b/ios/Pods/Headers/Public/PSTCollectionView/PSTCollectionViewController.h new file mode 120000 index 000000000..e99bef7b7 --- /dev/null +++ b/ios/Pods/Headers/Public/PSTCollectionView/PSTCollectionViewController.h @@ -0,0 +1 @@ +../../../PSTCollectionView/PSTCollectionView/PSTCollectionViewController.h \ No newline at end of file diff --git a/ios/Pods/Headers/Public/PSTCollectionView/PSTCollectionViewData.h b/ios/Pods/Headers/Public/PSTCollectionView/PSTCollectionViewData.h new file mode 120000 index 000000000..c1ae1bd70 --- /dev/null +++ b/ios/Pods/Headers/Public/PSTCollectionView/PSTCollectionViewData.h @@ -0,0 +1 @@ +../../../PSTCollectionView/PSTCollectionView/PSTCollectionViewData.h \ No newline at end of file diff --git a/ios/Pods/Headers/Public/PSTCollectionView/PSTCollectionViewFlowLayout.h b/ios/Pods/Headers/Public/PSTCollectionView/PSTCollectionViewFlowLayout.h new file mode 120000 index 000000000..0865bdaab --- /dev/null +++ b/ios/Pods/Headers/Public/PSTCollectionView/PSTCollectionViewFlowLayout.h @@ -0,0 +1 @@ +../../../PSTCollectionView/PSTCollectionView/PSTCollectionViewFlowLayout.h \ No newline at end of file diff --git a/ios/Pods/Headers/Public/PSTCollectionView/PSTCollectionViewItemKey.h b/ios/Pods/Headers/Public/PSTCollectionView/PSTCollectionViewItemKey.h new file mode 120000 index 000000000..1879bfbd6 --- /dev/null +++ b/ios/Pods/Headers/Public/PSTCollectionView/PSTCollectionViewItemKey.h @@ -0,0 +1 @@ +../../../PSTCollectionView/PSTCollectionView/PSTCollectionViewItemKey.h \ No newline at end of file diff --git a/ios/Pods/Headers/Public/PSTCollectionView/PSTCollectionViewLayout+Internals.h b/ios/Pods/Headers/Public/PSTCollectionView/PSTCollectionViewLayout+Internals.h new file mode 120000 index 000000000..35ac25343 --- /dev/null +++ b/ios/Pods/Headers/Public/PSTCollectionView/PSTCollectionViewLayout+Internals.h @@ -0,0 +1 @@ +../../../PSTCollectionView/PSTCollectionView/PSTCollectionViewLayout+Internals.h \ No newline at end of file diff --git a/ios/Pods/Headers/Public/PSTCollectionView/PSTCollectionViewLayout.h b/ios/Pods/Headers/Public/PSTCollectionView/PSTCollectionViewLayout.h new file mode 120000 index 000000000..3c668a242 --- /dev/null +++ b/ios/Pods/Headers/Public/PSTCollectionView/PSTCollectionViewLayout.h @@ -0,0 +1 @@ +../../../PSTCollectionView/PSTCollectionView/PSTCollectionViewLayout.h \ No newline at end of file diff --git a/ios/Pods/Headers/Public/PSTCollectionView/PSTCollectionViewUpdateItem.h b/ios/Pods/Headers/Public/PSTCollectionView/PSTCollectionViewUpdateItem.h new file mode 120000 index 000000000..8c2f4f58c --- /dev/null +++ b/ios/Pods/Headers/Public/PSTCollectionView/PSTCollectionViewUpdateItem.h @@ -0,0 +1 @@ +../../../PSTCollectionView/PSTCollectionView/PSTCollectionViewUpdateItem.h \ No newline at end of file diff --git a/ios/Pods/Headers/Public/PSTCollectionView/PSTGridLayoutInfo.h b/ios/Pods/Headers/Public/PSTCollectionView/PSTGridLayoutInfo.h new file mode 120000 index 000000000..5b81070b5 --- /dev/null +++ b/ios/Pods/Headers/Public/PSTCollectionView/PSTGridLayoutInfo.h @@ -0,0 +1 @@ +../../../PSTCollectionView/PSTCollectionView/PSTGridLayoutInfo.h \ No newline at end of file diff --git a/ios/Pods/Headers/Public/PSTCollectionView/PSTGridLayoutItem.h b/ios/Pods/Headers/Public/PSTCollectionView/PSTGridLayoutItem.h new file mode 120000 index 000000000..8beec7e6d --- /dev/null +++ b/ios/Pods/Headers/Public/PSTCollectionView/PSTGridLayoutItem.h @@ -0,0 +1 @@ +../../../PSTCollectionView/PSTCollectionView/PSTGridLayoutItem.h \ No newline at end of file diff --git a/ios/Pods/Headers/Public/PSTCollectionView/PSTGridLayoutRow.h b/ios/Pods/Headers/Public/PSTCollectionView/PSTGridLayoutRow.h new file mode 120000 index 000000000..f29321818 --- /dev/null +++ b/ios/Pods/Headers/Public/PSTCollectionView/PSTGridLayoutRow.h @@ -0,0 +1 @@ +../../../PSTCollectionView/PSTCollectionView/PSTGridLayoutRow.h \ No newline at end of file diff --git a/ios/Pods/Headers/Public/PSTCollectionView/PSTGridLayoutSection.h b/ios/Pods/Headers/Public/PSTCollectionView/PSTGridLayoutSection.h new file mode 120000 index 000000000..6188f30e4 --- /dev/null +++ b/ios/Pods/Headers/Public/PSTCollectionView/PSTGridLayoutSection.h @@ -0,0 +1 @@ +../../../PSTCollectionView/PSTCollectionView/PSTGridLayoutSection.h \ No newline at end of file diff --git a/ios/Pods/Headers/Public/ProtocolBuffers/ProtocolBuffers/AbstractMessage.h b/ios/Pods/Headers/Public/ProtocolBuffers/ProtocolBuffers/AbstractMessage.h new file mode 120000 index 000000000..02b035b8f --- /dev/null +++ b/ios/Pods/Headers/Public/ProtocolBuffers/ProtocolBuffers/AbstractMessage.h @@ -0,0 +1 @@ +../../../../ProtocolBuffers/src/runtime/Classes/AbstractMessage.h \ No newline at end of file diff --git a/ios/Pods/Headers/Public/ProtocolBuffers/ProtocolBuffers/AbstractMessageBuilder.h b/ios/Pods/Headers/Public/ProtocolBuffers/ProtocolBuffers/AbstractMessageBuilder.h new file mode 120000 index 000000000..a768765b4 --- /dev/null +++ b/ios/Pods/Headers/Public/ProtocolBuffers/ProtocolBuffers/AbstractMessageBuilder.h @@ -0,0 +1 @@ +../../../../ProtocolBuffers/src/runtime/Classes/AbstractMessageBuilder.h \ No newline at end of file diff --git a/ios/Pods/Headers/Public/ProtocolBuffers/ProtocolBuffers/Bootstrap.h b/ios/Pods/Headers/Public/ProtocolBuffers/ProtocolBuffers/Bootstrap.h new file mode 120000 index 000000000..f982e0635 --- /dev/null +++ b/ios/Pods/Headers/Public/ProtocolBuffers/ProtocolBuffers/Bootstrap.h @@ -0,0 +1 @@ +../../../../ProtocolBuffers/src/runtime/Classes/Bootstrap.h \ No newline at end of file diff --git a/ios/Pods/Headers/Public/ProtocolBuffers/ProtocolBuffers/CodedInputStream.h b/ios/Pods/Headers/Public/ProtocolBuffers/ProtocolBuffers/CodedInputStream.h new file mode 120000 index 000000000..88c1caf7b --- /dev/null +++ b/ios/Pods/Headers/Public/ProtocolBuffers/ProtocolBuffers/CodedInputStream.h @@ -0,0 +1 @@ +../../../../ProtocolBuffers/src/runtime/Classes/CodedInputStream.h \ No newline at end of file diff --git a/ios/Pods/Headers/Public/ProtocolBuffers/ProtocolBuffers/CodedOutputStream.h b/ios/Pods/Headers/Public/ProtocolBuffers/ProtocolBuffers/CodedOutputStream.h new file mode 120000 index 000000000..7ad312cf2 --- /dev/null +++ b/ios/Pods/Headers/Public/ProtocolBuffers/ProtocolBuffers/CodedOutputStream.h @@ -0,0 +1 @@ +../../../../ProtocolBuffers/src/runtime/Classes/CodedOutputStream.h \ No newline at end of file diff --git a/ios/Pods/Headers/Public/ProtocolBuffers/ProtocolBuffers/ConcreteExtensionField.h b/ios/Pods/Headers/Public/ProtocolBuffers/ProtocolBuffers/ConcreteExtensionField.h new file mode 120000 index 000000000..8975928cd --- /dev/null +++ b/ios/Pods/Headers/Public/ProtocolBuffers/ProtocolBuffers/ConcreteExtensionField.h @@ -0,0 +1 @@ +../../../../ProtocolBuffers/src/runtime/Classes/ConcreteExtensionField.h \ No newline at end of file diff --git a/ios/Pods/Headers/Public/ProtocolBuffers/ProtocolBuffers/Descriptor.pb.h b/ios/Pods/Headers/Public/ProtocolBuffers/ProtocolBuffers/Descriptor.pb.h new file mode 120000 index 000000000..af11c1693 --- /dev/null +++ b/ios/Pods/Headers/Public/ProtocolBuffers/ProtocolBuffers/Descriptor.pb.h @@ -0,0 +1 @@ +../../../../ProtocolBuffers/src/runtime/Classes/Descriptor.pb.h \ No newline at end of file diff --git a/ios/Pods/Headers/Public/ProtocolBuffers/ProtocolBuffers/ExtendableMessage.h b/ios/Pods/Headers/Public/ProtocolBuffers/ProtocolBuffers/ExtendableMessage.h new file mode 120000 index 000000000..68aa8b57b --- /dev/null +++ b/ios/Pods/Headers/Public/ProtocolBuffers/ProtocolBuffers/ExtendableMessage.h @@ -0,0 +1 @@ +../../../../ProtocolBuffers/src/runtime/Classes/ExtendableMessage.h \ No newline at end of file diff --git a/ios/Pods/Headers/Public/ProtocolBuffers/ProtocolBuffers/ExtendableMessageBuilder.h b/ios/Pods/Headers/Public/ProtocolBuffers/ProtocolBuffers/ExtendableMessageBuilder.h new file mode 120000 index 000000000..5efe55ab6 --- /dev/null +++ b/ios/Pods/Headers/Public/ProtocolBuffers/ProtocolBuffers/ExtendableMessageBuilder.h @@ -0,0 +1 @@ +../../../../ProtocolBuffers/src/runtime/Classes/ExtendableMessageBuilder.h \ No newline at end of file diff --git a/ios/Pods/Headers/Public/ProtocolBuffers/ProtocolBuffers/ExtensionField.h b/ios/Pods/Headers/Public/ProtocolBuffers/ProtocolBuffers/ExtensionField.h new file mode 120000 index 000000000..b6d3dc82d --- /dev/null +++ b/ios/Pods/Headers/Public/ProtocolBuffers/ProtocolBuffers/ExtensionField.h @@ -0,0 +1 @@ +../../../../ProtocolBuffers/src/runtime/Classes/ExtensionField.h \ No newline at end of file diff --git a/ios/Pods/Headers/Public/ProtocolBuffers/ProtocolBuffers/ExtensionRegistry.h b/ios/Pods/Headers/Public/ProtocolBuffers/ProtocolBuffers/ExtensionRegistry.h new file mode 120000 index 000000000..ad9fbbfbd --- /dev/null +++ b/ios/Pods/Headers/Public/ProtocolBuffers/ProtocolBuffers/ExtensionRegistry.h @@ -0,0 +1 @@ +../../../../ProtocolBuffers/src/runtime/Classes/ExtensionRegistry.h \ No newline at end of file diff --git a/ios/Pods/Headers/Public/ProtocolBuffers/ProtocolBuffers/Field.h b/ios/Pods/Headers/Public/ProtocolBuffers/ProtocolBuffers/Field.h new file mode 120000 index 000000000..11db638eb --- /dev/null +++ b/ios/Pods/Headers/Public/ProtocolBuffers/ProtocolBuffers/Field.h @@ -0,0 +1 @@ +../../../../ProtocolBuffers/src/runtime/Classes/Field.h \ No newline at end of file diff --git a/ios/Pods/Headers/Public/ProtocolBuffers/ProtocolBuffers/ForwardDeclarations.h b/ios/Pods/Headers/Public/ProtocolBuffers/ProtocolBuffers/ForwardDeclarations.h new file mode 120000 index 000000000..d6966a1b8 --- /dev/null +++ b/ios/Pods/Headers/Public/ProtocolBuffers/ProtocolBuffers/ForwardDeclarations.h @@ -0,0 +1 @@ +../../../../ProtocolBuffers/src/runtime/Classes/ForwardDeclarations.h \ No newline at end of file diff --git a/ios/Pods/Headers/Public/ProtocolBuffers/ProtocolBuffers/GeneratedMessage.h b/ios/Pods/Headers/Public/ProtocolBuffers/ProtocolBuffers/GeneratedMessage.h new file mode 120000 index 000000000..8a2005822 --- /dev/null +++ b/ios/Pods/Headers/Public/ProtocolBuffers/ProtocolBuffers/GeneratedMessage.h @@ -0,0 +1 @@ +../../../../ProtocolBuffers/src/runtime/Classes/GeneratedMessage.h \ No newline at end of file diff --git a/ios/Pods/Headers/Public/ProtocolBuffers/ProtocolBuffers/GeneratedMessageBuilder.h b/ios/Pods/Headers/Public/ProtocolBuffers/ProtocolBuffers/GeneratedMessageBuilder.h new file mode 120000 index 000000000..baa870a8e --- /dev/null +++ b/ios/Pods/Headers/Public/ProtocolBuffers/ProtocolBuffers/GeneratedMessageBuilder.h @@ -0,0 +1 @@ +../../../../ProtocolBuffers/src/runtime/Classes/GeneratedMessageBuilder.h \ No newline at end of file diff --git a/ios/Pods/Headers/Public/ProtocolBuffers/ProtocolBuffers/Message.h b/ios/Pods/Headers/Public/ProtocolBuffers/ProtocolBuffers/Message.h new file mode 120000 index 000000000..5f3b99797 --- /dev/null +++ b/ios/Pods/Headers/Public/ProtocolBuffers/ProtocolBuffers/Message.h @@ -0,0 +1 @@ +../../../../ProtocolBuffers/src/runtime/Classes/Message.h \ No newline at end of file diff --git a/ios/Pods/Headers/Public/ProtocolBuffers/ProtocolBuffers/MessageBuilder.h b/ios/Pods/Headers/Public/ProtocolBuffers/ProtocolBuffers/MessageBuilder.h new file mode 120000 index 000000000..53681abf2 --- /dev/null +++ b/ios/Pods/Headers/Public/ProtocolBuffers/ProtocolBuffers/MessageBuilder.h @@ -0,0 +1 @@ +../../../../ProtocolBuffers/src/runtime/Classes/MessageBuilder.h \ No newline at end of file diff --git a/ios/Pods/Headers/Public/ProtocolBuffers/ProtocolBuffers/MutableExtensionRegistry.h b/ios/Pods/Headers/Public/ProtocolBuffers/ProtocolBuffers/MutableExtensionRegistry.h new file mode 120000 index 000000000..5655db0ba --- /dev/null +++ b/ios/Pods/Headers/Public/ProtocolBuffers/ProtocolBuffers/MutableExtensionRegistry.h @@ -0,0 +1 @@ +../../../../ProtocolBuffers/src/runtime/Classes/MutableExtensionRegistry.h \ No newline at end of file diff --git a/ios/Pods/Headers/Public/ProtocolBuffers/ProtocolBuffers/MutableField.h b/ios/Pods/Headers/Public/ProtocolBuffers/ProtocolBuffers/MutableField.h new file mode 120000 index 000000000..421f9ef1e --- /dev/null +++ b/ios/Pods/Headers/Public/ProtocolBuffers/ProtocolBuffers/MutableField.h @@ -0,0 +1 @@ +../../../../ProtocolBuffers/src/runtime/Classes/MutableField.h \ No newline at end of file diff --git a/ios/Pods/Headers/Public/ProtocolBuffers/ProtocolBuffers/PBArray.h b/ios/Pods/Headers/Public/ProtocolBuffers/ProtocolBuffers/PBArray.h new file mode 120000 index 000000000..2bd608d19 --- /dev/null +++ b/ios/Pods/Headers/Public/ProtocolBuffers/ProtocolBuffers/PBArray.h @@ -0,0 +1 @@ +../../../../ProtocolBuffers/src/runtime/Classes/PBArray.h \ No newline at end of file diff --git a/ios/Pods/Headers/Public/ProtocolBuffers/ProtocolBuffers/ProtocolBuffers.h b/ios/Pods/Headers/Public/ProtocolBuffers/ProtocolBuffers/ProtocolBuffers.h new file mode 120000 index 000000000..29d4b82c2 --- /dev/null +++ b/ios/Pods/Headers/Public/ProtocolBuffers/ProtocolBuffers/ProtocolBuffers.h @@ -0,0 +1 @@ +../../../../ProtocolBuffers/src/runtime/Classes/ProtocolBuffers.h \ No newline at end of file diff --git a/ios/Pods/Headers/Public/ProtocolBuffers/ProtocolBuffers/RingBuffer.h b/ios/Pods/Headers/Public/ProtocolBuffers/ProtocolBuffers/RingBuffer.h new file mode 120000 index 000000000..cd4359a5c --- /dev/null +++ b/ios/Pods/Headers/Public/ProtocolBuffers/ProtocolBuffers/RingBuffer.h @@ -0,0 +1 @@ +../../../../ProtocolBuffers/src/runtime/Classes/RingBuffer.h \ No newline at end of file diff --git a/ios/Pods/Headers/Public/ProtocolBuffers/ProtocolBuffers/TextFormat.h b/ios/Pods/Headers/Public/ProtocolBuffers/ProtocolBuffers/TextFormat.h new file mode 120000 index 000000000..37e85f034 --- /dev/null +++ b/ios/Pods/Headers/Public/ProtocolBuffers/ProtocolBuffers/TextFormat.h @@ -0,0 +1 @@ +../../../../ProtocolBuffers/src/runtime/Classes/TextFormat.h \ No newline at end of file diff --git a/ios/Pods/Headers/Public/ProtocolBuffers/ProtocolBuffers/UnknownFieldSet.h b/ios/Pods/Headers/Public/ProtocolBuffers/ProtocolBuffers/UnknownFieldSet.h new file mode 120000 index 000000000..1b41c25b9 --- /dev/null +++ b/ios/Pods/Headers/Public/ProtocolBuffers/ProtocolBuffers/UnknownFieldSet.h @@ -0,0 +1 @@ +../../../../ProtocolBuffers/src/runtime/Classes/UnknownFieldSet.h \ No newline at end of file diff --git a/ios/Pods/Headers/Public/ProtocolBuffers/ProtocolBuffers/UnknownFieldSetBuilder.h b/ios/Pods/Headers/Public/ProtocolBuffers/ProtocolBuffers/UnknownFieldSetBuilder.h new file mode 120000 index 000000000..988d8cafb --- /dev/null +++ b/ios/Pods/Headers/Public/ProtocolBuffers/ProtocolBuffers/UnknownFieldSetBuilder.h @@ -0,0 +1 @@ +../../../../ProtocolBuffers/src/runtime/Classes/UnknownFieldSetBuilder.h \ No newline at end of file diff --git a/ios/Pods/Headers/Public/ProtocolBuffers/ProtocolBuffers/Utilities.h b/ios/Pods/Headers/Public/ProtocolBuffers/ProtocolBuffers/Utilities.h new file mode 120000 index 000000000..f31cff40c --- /dev/null +++ b/ios/Pods/Headers/Public/ProtocolBuffers/ProtocolBuffers/Utilities.h @@ -0,0 +1 @@ +../../../../ProtocolBuffers/src/runtime/Classes/Utilities.h \ No newline at end of file diff --git a/ios/Pods/Headers/Public/ProtocolBuffers/ProtocolBuffers/WireFormat.h b/ios/Pods/Headers/Public/ProtocolBuffers/ProtocolBuffers/WireFormat.h new file mode 120000 index 000000000..9afcf5ac3 --- /dev/null +++ b/ios/Pods/Headers/Public/ProtocolBuffers/ProtocolBuffers/WireFormat.h @@ -0,0 +1 @@ +../../../../ProtocolBuffers/src/runtime/Classes/WireFormat.h \ No newline at end of file diff --git a/ios/Pods/Headers/Public/SCLAlertView-Objective-C/SCLAlertView.h b/ios/Pods/Headers/Public/SCLAlertView-Objective-C/SCLAlertView.h new file mode 120000 index 000000000..153c3f068 --- /dev/null +++ b/ios/Pods/Headers/Public/SCLAlertView-Objective-C/SCLAlertView.h @@ -0,0 +1 @@ +../../../SCLAlertView-Objective-C/SCLAlertView/SCLAlertView.h \ No newline at end of file diff --git a/ios/Pods/Headers/Public/SCLAlertView-Objective-C/SCLAlertViewResponder.h b/ios/Pods/Headers/Public/SCLAlertView-Objective-C/SCLAlertViewResponder.h new file mode 120000 index 000000000..c5754aa4c --- /dev/null +++ b/ios/Pods/Headers/Public/SCLAlertView-Objective-C/SCLAlertViewResponder.h @@ -0,0 +1 @@ +../../../SCLAlertView-Objective-C/SCLAlertView/SCLAlertViewResponder.h \ No newline at end of file diff --git a/ios/Pods/Headers/Public/SCLAlertView-Objective-C/SCLAlertViewStyleKit.h b/ios/Pods/Headers/Public/SCLAlertView-Objective-C/SCLAlertViewStyleKit.h new file mode 120000 index 000000000..0b23a2eff --- /dev/null +++ b/ios/Pods/Headers/Public/SCLAlertView-Objective-C/SCLAlertViewStyleKit.h @@ -0,0 +1 @@ +../../../SCLAlertView-Objective-C/SCLAlertView/SCLAlertViewStyleKit.h \ No newline at end of file diff --git a/ios/Pods/Headers/Public/SCLAlertView-Objective-C/SCLButton.h b/ios/Pods/Headers/Public/SCLAlertView-Objective-C/SCLButton.h new file mode 120000 index 000000000..cbc946228 --- /dev/null +++ b/ios/Pods/Headers/Public/SCLAlertView-Objective-C/SCLButton.h @@ -0,0 +1 @@ +../../../SCLAlertView-Objective-C/SCLAlertView/SCLButton.h \ No newline at end of file diff --git a/ios/Pods/Headers/Public/SCLAlertView-Objective-C/UIImage+ImageEffects.h b/ios/Pods/Headers/Public/SCLAlertView-Objective-C/UIImage+ImageEffects.h new file mode 120000 index 000000000..8c083c13c --- /dev/null +++ b/ios/Pods/Headers/Public/SCLAlertView-Objective-C/UIImage+ImageEffects.h @@ -0,0 +1 @@ +../../../SCLAlertView-Objective-C/SCLAlertView/UIImage+ImageEffects.h \ No newline at end of file diff --git a/ios/Pods/Headers/Public/SDWebImage/NSData+ImageContentType.h b/ios/Pods/Headers/Public/SDWebImage/NSData+ImageContentType.h new file mode 120000 index 000000000..84574987a --- /dev/null +++ b/ios/Pods/Headers/Public/SDWebImage/NSData+ImageContentType.h @@ -0,0 +1 @@ +../../../SDWebImage/SDWebImage/NSData+ImageContentType.h \ No newline at end of file diff --git a/ios/Pods/Headers/Public/SDWebImage/SDImageCache.h b/ios/Pods/Headers/Public/SDWebImage/SDImageCache.h new file mode 120000 index 000000000..0040b06a1 --- /dev/null +++ b/ios/Pods/Headers/Public/SDWebImage/SDImageCache.h @@ -0,0 +1 @@ +../../../SDWebImage/SDWebImage/SDImageCache.h \ No newline at end of file diff --git a/ios/Pods/Headers/Public/SDWebImage/SDWebImageCompat.h b/ios/Pods/Headers/Public/SDWebImage/SDWebImageCompat.h new file mode 120000 index 000000000..6ca247842 --- /dev/null +++ b/ios/Pods/Headers/Public/SDWebImage/SDWebImageCompat.h @@ -0,0 +1 @@ +../../../SDWebImage/SDWebImage/SDWebImageCompat.h \ No newline at end of file diff --git a/ios/Pods/Headers/Public/SDWebImage/SDWebImageDecoder.h b/ios/Pods/Headers/Public/SDWebImage/SDWebImageDecoder.h new file mode 120000 index 000000000..a2f3a683d --- /dev/null +++ b/ios/Pods/Headers/Public/SDWebImage/SDWebImageDecoder.h @@ -0,0 +1 @@ +../../../SDWebImage/SDWebImage/SDWebImageDecoder.h \ No newline at end of file diff --git a/ios/Pods/Headers/Public/SDWebImage/SDWebImageDownloader.h b/ios/Pods/Headers/Public/SDWebImage/SDWebImageDownloader.h new file mode 120000 index 000000000..303b03b1e --- /dev/null +++ b/ios/Pods/Headers/Public/SDWebImage/SDWebImageDownloader.h @@ -0,0 +1 @@ +../../../SDWebImage/SDWebImage/SDWebImageDownloader.h \ No newline at end of file diff --git a/ios/Pods/Headers/Public/SDWebImage/SDWebImageDownloaderOperation.h b/ios/Pods/Headers/Public/SDWebImage/SDWebImageDownloaderOperation.h new file mode 120000 index 000000000..99441c485 --- /dev/null +++ b/ios/Pods/Headers/Public/SDWebImage/SDWebImageDownloaderOperation.h @@ -0,0 +1 @@ +../../../SDWebImage/SDWebImage/SDWebImageDownloaderOperation.h \ No newline at end of file diff --git a/ios/Pods/Headers/Public/SDWebImage/SDWebImageManager.h b/ios/Pods/Headers/Public/SDWebImage/SDWebImageManager.h new file mode 120000 index 000000000..1b8184856 --- /dev/null +++ b/ios/Pods/Headers/Public/SDWebImage/SDWebImageManager.h @@ -0,0 +1 @@ +../../../SDWebImage/SDWebImage/SDWebImageManager.h \ No newline at end of file diff --git a/ios/Pods/Headers/Public/SDWebImage/SDWebImageOperation.h b/ios/Pods/Headers/Public/SDWebImage/SDWebImageOperation.h new file mode 120000 index 000000000..20e5b89ef --- /dev/null +++ b/ios/Pods/Headers/Public/SDWebImage/SDWebImageOperation.h @@ -0,0 +1 @@ +../../../SDWebImage/SDWebImage/SDWebImageOperation.h \ No newline at end of file diff --git a/ios/Pods/Headers/Public/SDWebImage/SDWebImagePrefetcher.h b/ios/Pods/Headers/Public/SDWebImage/SDWebImagePrefetcher.h new file mode 120000 index 000000000..50585c6d0 --- /dev/null +++ b/ios/Pods/Headers/Public/SDWebImage/SDWebImagePrefetcher.h @@ -0,0 +1 @@ +../../../SDWebImage/SDWebImage/SDWebImagePrefetcher.h \ No newline at end of file diff --git a/ios/Pods/Headers/Public/SDWebImage/UIButton+WebCache.h b/ios/Pods/Headers/Public/SDWebImage/UIButton+WebCache.h new file mode 120000 index 000000000..19d2d8e8c --- /dev/null +++ b/ios/Pods/Headers/Public/SDWebImage/UIButton+WebCache.h @@ -0,0 +1 @@ +../../../SDWebImage/SDWebImage/UIButton+WebCache.h \ No newline at end of file diff --git a/ios/Pods/Headers/Public/SDWebImage/UIImage+GIF.h b/ios/Pods/Headers/Public/SDWebImage/UIImage+GIF.h new file mode 120000 index 000000000..14d5aadd9 --- /dev/null +++ b/ios/Pods/Headers/Public/SDWebImage/UIImage+GIF.h @@ -0,0 +1 @@ +../../../SDWebImage/SDWebImage/UIImage+GIF.h \ No newline at end of file diff --git a/ios/Pods/Headers/Public/SDWebImage/UIImage+MultiFormat.h b/ios/Pods/Headers/Public/SDWebImage/UIImage+MultiFormat.h new file mode 120000 index 000000000..1fb965010 --- /dev/null +++ b/ios/Pods/Headers/Public/SDWebImage/UIImage+MultiFormat.h @@ -0,0 +1 @@ +../../../SDWebImage/SDWebImage/UIImage+MultiFormat.h \ No newline at end of file diff --git a/ios/Pods/Headers/Public/SDWebImage/UIImageView+HighlightedWebCache.h b/ios/Pods/Headers/Public/SDWebImage/UIImageView+HighlightedWebCache.h new file mode 120000 index 000000000..fd4dea41e --- /dev/null +++ b/ios/Pods/Headers/Public/SDWebImage/UIImageView+HighlightedWebCache.h @@ -0,0 +1 @@ +../../../SDWebImage/SDWebImage/UIImageView+HighlightedWebCache.h \ No newline at end of file diff --git a/ios/Pods/Headers/Public/SDWebImage/UIImageView+WebCache.h b/ios/Pods/Headers/Public/SDWebImage/UIImageView+WebCache.h new file mode 120000 index 000000000..0c53a47b8 --- /dev/null +++ b/ios/Pods/Headers/Public/SDWebImage/UIImageView+WebCache.h @@ -0,0 +1 @@ +../../../SDWebImage/SDWebImage/UIImageView+WebCache.h \ No newline at end of file diff --git a/ios/Pods/Headers/Public/SDWebImage/UIView+WebCacheOperation.h b/ios/Pods/Headers/Public/SDWebImage/UIView+WebCacheOperation.h new file mode 120000 index 000000000..f9890c406 --- /dev/null +++ b/ios/Pods/Headers/Public/SDWebImage/UIView+WebCacheOperation.h @@ -0,0 +1 @@ +../../../SDWebImage/SDWebImage/UIView+WebCacheOperation.h \ No newline at end of file diff --git a/ios/Pods/Headers/Public/leveldb-library/leveldb/c.h b/ios/Pods/Headers/Public/leveldb-library/leveldb/c.h new file mode 120000 index 000000000..684bb4bc9 --- /dev/null +++ b/ios/Pods/Headers/Public/leveldb-library/leveldb/c.h @@ -0,0 +1 @@ +../../../../leveldb-library/include/leveldb/c.h \ No newline at end of file diff --git a/ios/Pods/Headers/Public/leveldb-library/leveldb/cache.h b/ios/Pods/Headers/Public/leveldb-library/leveldb/cache.h new file mode 120000 index 000000000..f71b37911 --- /dev/null +++ b/ios/Pods/Headers/Public/leveldb-library/leveldb/cache.h @@ -0,0 +1 @@ +../../../../leveldb-library/include/leveldb/cache.h \ No newline at end of file diff --git a/ios/Pods/Headers/Public/leveldb-library/leveldb/comparator.h b/ios/Pods/Headers/Public/leveldb-library/leveldb/comparator.h new file mode 120000 index 000000000..d092f9750 --- /dev/null +++ b/ios/Pods/Headers/Public/leveldb-library/leveldb/comparator.h @@ -0,0 +1 @@ +../../../../leveldb-library/include/leveldb/comparator.h \ No newline at end of file diff --git a/ios/Pods/Headers/Public/leveldb-library/leveldb/db.h b/ios/Pods/Headers/Public/leveldb-library/leveldb/db.h new file mode 120000 index 000000000..e68182ac1 --- /dev/null +++ b/ios/Pods/Headers/Public/leveldb-library/leveldb/db.h @@ -0,0 +1 @@ +../../../../leveldb-library/include/leveldb/db.h \ No newline at end of file diff --git a/ios/Pods/Headers/Public/leveldb-library/leveldb/dumpfile.h b/ios/Pods/Headers/Public/leveldb-library/leveldb/dumpfile.h new file mode 120000 index 000000000..53b92ee13 --- /dev/null +++ b/ios/Pods/Headers/Public/leveldb-library/leveldb/dumpfile.h @@ -0,0 +1 @@ +../../../../leveldb-library/include/leveldb/dumpfile.h \ No newline at end of file diff --git a/ios/Pods/Headers/Public/leveldb-library/leveldb/env.h b/ios/Pods/Headers/Public/leveldb-library/leveldb/env.h new file mode 120000 index 000000000..655aee312 --- /dev/null +++ b/ios/Pods/Headers/Public/leveldb-library/leveldb/env.h @@ -0,0 +1 @@ +../../../../leveldb-library/include/leveldb/env.h \ No newline at end of file diff --git a/ios/Pods/Headers/Public/leveldb-library/leveldb/filter_policy.h b/ios/Pods/Headers/Public/leveldb-library/leveldb/filter_policy.h new file mode 120000 index 000000000..24bd90c57 --- /dev/null +++ b/ios/Pods/Headers/Public/leveldb-library/leveldb/filter_policy.h @@ -0,0 +1 @@ +../../../../leveldb-library/include/leveldb/filter_policy.h \ No newline at end of file diff --git a/ios/Pods/Headers/Public/leveldb-library/leveldb/iterator.h b/ios/Pods/Headers/Public/leveldb-library/leveldb/iterator.h new file mode 120000 index 000000000..0b79d163a --- /dev/null +++ b/ios/Pods/Headers/Public/leveldb-library/leveldb/iterator.h @@ -0,0 +1 @@ +../../../../leveldb-library/include/leveldb/iterator.h \ No newline at end of file diff --git a/ios/Pods/Headers/Public/leveldb-library/leveldb/options.h b/ios/Pods/Headers/Public/leveldb-library/leveldb/options.h new file mode 120000 index 000000000..df730a3cc --- /dev/null +++ b/ios/Pods/Headers/Public/leveldb-library/leveldb/options.h @@ -0,0 +1 @@ +../../../../leveldb-library/include/leveldb/options.h \ No newline at end of file diff --git a/ios/Pods/Headers/Public/leveldb-library/leveldb/slice.h b/ios/Pods/Headers/Public/leveldb-library/leveldb/slice.h new file mode 120000 index 000000000..1198d0335 --- /dev/null +++ b/ios/Pods/Headers/Public/leveldb-library/leveldb/slice.h @@ -0,0 +1 @@ +../../../../leveldb-library/include/leveldb/slice.h \ No newline at end of file diff --git a/ios/Pods/Headers/Public/leveldb-library/leveldb/status.h b/ios/Pods/Headers/Public/leveldb-library/leveldb/status.h new file mode 120000 index 000000000..f0a87b2fe --- /dev/null +++ b/ios/Pods/Headers/Public/leveldb-library/leveldb/status.h @@ -0,0 +1 @@ +../../../../leveldb-library/include/leveldb/status.h \ No newline at end of file diff --git a/ios/Pods/Headers/Public/leveldb-library/leveldb/table.h b/ios/Pods/Headers/Public/leveldb-library/leveldb/table.h new file mode 120000 index 000000000..6951d31cd --- /dev/null +++ b/ios/Pods/Headers/Public/leveldb-library/leveldb/table.h @@ -0,0 +1 @@ +../../../../leveldb-library/include/leveldb/table.h \ No newline at end of file diff --git a/ios/Pods/Headers/Public/leveldb-library/leveldb/table_builder.h b/ios/Pods/Headers/Public/leveldb-library/leveldb/table_builder.h new file mode 120000 index 000000000..e396af91c --- /dev/null +++ b/ios/Pods/Headers/Public/leveldb-library/leveldb/table_builder.h @@ -0,0 +1 @@ +../../../../leveldb-library/include/leveldb/table_builder.h \ No newline at end of file diff --git a/ios/Pods/Headers/Public/leveldb-library/leveldb/write_batch.h b/ios/Pods/Headers/Public/leveldb-library/leveldb/write_batch.h new file mode 120000 index 000000000..fdc08d62a --- /dev/null +++ b/ios/Pods/Headers/Public/leveldb-library/leveldb/write_batch.h @@ -0,0 +1 @@ +../../../../leveldb-library/include/leveldb/write_batch.h \ No newline at end of file diff --git a/ios/Pods/MBProgressHUD/LICENSE b/ios/Pods/MBProgressHUD/LICENSE new file mode 100644 index 000000000..c51b6b071 --- /dev/null +++ b/ios/Pods/MBProgressHUD/LICENSE @@ -0,0 +1,19 @@ +Copyright (c) 2013 Matej Bukovinski + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. \ No newline at end of file diff --git a/ios/Pods/MBProgressHUD/MBProgressHUD.h b/ios/Pods/MBProgressHUD/MBProgressHUD.h new file mode 100644 index 000000000..1caa3ca44 --- /dev/null +++ b/ios/Pods/MBProgressHUD/MBProgressHUD.h @@ -0,0 +1,515 @@ +// +// MBProgressHUD.h +// Version 0.9 +// Created by Matej Bukovinski on 2.4.09. +// + +// This code is distributed under the terms and conditions of the MIT license. + +// Copyright (c) 2013 Matej Bukovinski +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +#import +#import +#import + +@protocol MBProgressHUDDelegate; + + +typedef enum { + /** Progress is shown using an UIActivityIndicatorView. This is the default. */ + MBProgressHUDModeIndeterminate, + /** Progress is shown using a round, pie-chart like, progress view. */ + MBProgressHUDModeDeterminate, + /** Progress is shown using a horizontal progress bar */ + MBProgressHUDModeDeterminateHorizontalBar, + /** Progress is shown using a ring-shaped progress view. */ + MBProgressHUDModeAnnularDeterminate, + /** Shows a custom view */ + MBProgressHUDModeCustomView, + /** Shows only labels */ + MBProgressHUDModeText +} MBProgressHUDMode; + +typedef enum { + /** Opacity animation */ + MBProgressHUDAnimationFade, + /** Opacity + scale animation */ + MBProgressHUDAnimationZoom, + MBProgressHUDAnimationZoomOut = MBProgressHUDAnimationZoom, + MBProgressHUDAnimationZoomIn +} MBProgressHUDAnimation; + + +#ifndef MB_INSTANCETYPE +#if __has_feature(objc_instancetype) + #define MB_INSTANCETYPE instancetype +#else + #define MB_INSTANCETYPE id +#endif +#endif + +#ifndef MB_STRONG +#if __has_feature(objc_arc) + #define MB_STRONG strong +#else + #define MB_STRONG retain +#endif +#endif + +#ifndef MB_WEAK +#if __has_feature(objc_arc_weak) + #define MB_WEAK weak +#elif __has_feature(objc_arc) + #define MB_WEAK unsafe_unretained +#else + #define MB_WEAK assign +#endif +#endif + +#if NS_BLOCKS_AVAILABLE +typedef void (^MBProgressHUDCompletionBlock)(); +#endif + + +/** + * Displays a simple HUD window containing a progress indicator and two optional labels for short messages. + * + * This is a simple drop-in class for displaying a progress HUD view similar to Apple's private UIProgressHUD class. + * The MBProgressHUD window spans over the entire space given to it by the initWithFrame constructor and catches all + * user input on this region, thereby preventing the user operations on components below the view. The HUD itself is + * drawn centered as a rounded semi-transparent view which resizes depending on the user specified content. + * + * This view supports four modes of operation: + * - MBProgressHUDModeIndeterminate - shows a UIActivityIndicatorView + * - MBProgressHUDModeDeterminate - shows a custom round progress indicator + * - MBProgressHUDModeAnnularDeterminate - shows a custom annular progress indicator + * - MBProgressHUDModeCustomView - shows an arbitrary, user specified view (@see customView) + * + * All three modes can have optional labels assigned: + * - If the labelText property is set and non-empty then a label containing the provided content is placed below the + * indicator view. + * - If also the detailsLabelText property is set then another label is placed below the first label. + */ +@interface MBProgressHUD : UIView + +/** + * Creates a new HUD, adds it to provided view and shows it. The counterpart to this method is hideHUDForView:animated:. + * + * @param view The view that the HUD will be added to + * @param animated If set to YES the HUD will appear using the current animationType. If set to NO the HUD will not use + * animations while appearing. + * @return A reference to the created HUD. + * + * @see hideHUDForView:animated: + * @see animationType + */ ++ (MB_INSTANCETYPE)showHUDAddedTo:(UIView *)view animated:(BOOL)animated; + +/** + * Finds the top-most HUD subview and hides it. The counterpart to this method is showHUDAddedTo:animated:. + * + * @param view The view that is going to be searched for a HUD subview. + * @param animated If set to YES the HUD will disappear using the current animationType. If set to NO the HUD will not use + * animations while disappearing. + * @return YES if a HUD was found and removed, NO otherwise. + * + * @see showHUDAddedTo:animated: + * @see animationType + */ ++ (BOOL)hideHUDForView:(UIView *)view animated:(BOOL)animated; + +/** + * Finds all the HUD subviews and hides them. + * + * @param view The view that is going to be searched for HUD subviews. + * @param animated If set to YES the HUDs will disappear using the current animationType. If set to NO the HUDs will not use + * animations while disappearing. + * @return the number of HUDs found and removed. + * + * @see hideHUDForView:animated: + * @see animationType + */ ++ (NSUInteger)hideAllHUDsForView:(UIView *)view animated:(BOOL)animated; + +/** + * Finds the top-most HUD subview and returns it. + * + * @param view The view that is going to be searched. + * @return A reference to the last HUD subview discovered. + */ ++ (MB_INSTANCETYPE)HUDForView:(UIView *)view; + +/** + * Finds all HUD subviews and returns them. + * + * @param view The view that is going to be searched. + * @return All found HUD views (array of MBProgressHUD objects). + */ ++ (NSArray *)allHUDsForView:(UIView *)view; + +/** + * A convenience constructor that initializes the HUD with the window's bounds. Calls the designated constructor with + * window.bounds as the parameter. + * + * @param window The window instance that will provide the bounds for the HUD. Should be the same instance as + * the HUD's superview (i.e., the window that the HUD will be added to). + */ +- (id)initWithWindow:(UIWindow *)window; + +/** + * A convenience constructor that initializes the HUD with the view's bounds. Calls the designated constructor with + * view.bounds as the parameter + * + * @param view The view instance that will provide the bounds for the HUD. Should be the same instance as + * the HUD's superview (i.e., the view that the HUD will be added to). + */ +- (id)initWithView:(UIView *)view; + +/** + * Display the HUD. You need to make sure that the main thread completes its run loop soon after this method call so + * the user interface can be updated. Call this method when your task is already set-up to be executed in a new thread + * (e.g., when using something like NSOperation or calling an asynchronous call like NSURLRequest). + * + * @param animated If set to YES the HUD will appear using the current animationType. If set to NO the HUD will not use + * animations while appearing. + * + * @see animationType + */ +- (void)show:(BOOL)animated; + +/** + * Hide the HUD. This still calls the hudWasHidden: delegate. This is the counterpart of the show: method. Use it to + * hide the HUD when your task completes. + * + * @param animated If set to YES the HUD will disappear using the current animationType. If set to NO the HUD will not use + * animations while disappearing. + * + * @see animationType + */ +- (void)hide:(BOOL)animated; + +/** + * Hide the HUD after a delay. This still calls the hudWasHidden: delegate. This is the counterpart of the show: method. Use it to + * hide the HUD when your task completes. + * + * @param animated If set to YES the HUD will disappear using the current animationType. If set to NO the HUD will not use + * animations while disappearing. + * @param delay Delay in seconds until the HUD is hidden. + * + * @see animationType + */ +- (void)hide:(BOOL)animated afterDelay:(NSTimeInterval)delay; + +/** + * Shows the HUD while a background task is executing in a new thread, then hides the HUD. + * + * This method also takes care of autorelease pools so your method does not have to be concerned with setting up a + * pool. + * + * @param method The method to be executed while the HUD is shown. This method will be executed in a new thread. + * @param target The object that the target method belongs to. + * @param object An optional object to be passed to the method. + * @param animated If set to YES the HUD will (dis)appear using the current animationType. If set to NO the HUD will not use + * animations while (dis)appearing. + */ +- (void)showWhileExecuting:(SEL)method onTarget:(id)target withObject:(id)object animated:(BOOL)animated; + +#if NS_BLOCKS_AVAILABLE + +/** + * Shows the HUD while a block is executing on a background queue, then hides the HUD. + * + * @see showAnimated:whileExecutingBlock:onQueue:completionBlock: + */ +- (void)showAnimated:(BOOL)animated whileExecutingBlock:(dispatch_block_t)block; + +/** + * Shows the HUD while a block is executing on a background queue, then hides the HUD. + * + * @see showAnimated:whileExecutingBlock:onQueue:completionBlock: + */ +- (void)showAnimated:(BOOL)animated whileExecutingBlock:(dispatch_block_t)block completionBlock:(MBProgressHUDCompletionBlock)completion; + +/** + * Shows the HUD while a block is executing on the specified dispatch queue, then hides the HUD. + * + * @see showAnimated:whileExecutingBlock:onQueue:completionBlock: + */ +- (void)showAnimated:(BOOL)animated whileExecutingBlock:(dispatch_block_t)block onQueue:(dispatch_queue_t)queue; + +/** + * Shows the HUD while a block is executing on the specified dispatch queue, executes completion block on the main queue, and then hides the HUD. + * + * @param animated If set to YES the HUD will (dis)appear using the current animationType. If set to NO the HUD will + * not use animations while (dis)appearing. + * @param block The block to be executed while the HUD is shown. + * @param queue The dispatch queue on which the block should be executed. + * @param completion The block to be executed on completion. + * + * @see completionBlock + */ +- (void)showAnimated:(BOOL)animated whileExecutingBlock:(dispatch_block_t)block onQueue:(dispatch_queue_t)queue + completionBlock:(MBProgressHUDCompletionBlock)completion; + +/** + * A block that gets called after the HUD was completely hidden. + */ +@property (copy) MBProgressHUDCompletionBlock completionBlock; + +#endif + +/** + * MBProgressHUD operation mode. The default is MBProgressHUDModeIndeterminate. + * + * @see MBProgressHUDMode + */ +@property (assign) MBProgressHUDMode mode; + +/** + * The animation type that should be used when the HUD is shown and hidden. + * + * @see MBProgressHUDAnimation + */ +@property (assign) MBProgressHUDAnimation animationType; + +/** + * The UIView (e.g., a UIImageView) to be shown when the HUD is in MBProgressHUDModeCustomView. + * For best results use a 37 by 37 pixel view (so the bounds match the built in indicator bounds). + */ +@property (MB_STRONG) UIView *customView; + +/** + * The HUD delegate object. + * + * @see MBProgressHUDDelegate + */ +@property (MB_WEAK) id delegate; + +/** + * An optional short message to be displayed below the activity indicator. The HUD is automatically resized to fit + * the entire text. If the text is too long it will get clipped by displaying "..." at the end. If left unchanged or + * set to @"", then no message is displayed. + */ +@property (copy) NSString *labelText; + +/** + * An optional details message displayed below the labelText message. This message is displayed only if the labelText + * property is also set and is different from an empty string (@""). The details text can span multiple lines. + */ +@property (copy) NSString *detailsLabelText; + +/** + * The opacity of the HUD window. Defaults to 0.8 (80% opacity). + */ +@property (assign) float opacity; + +/** + * The color of the HUD window. Defaults to black. If this property is set, color is set using + * this UIColor and the opacity property is not used. using retain because performing copy on + * UIColor base colors (like [UIColor greenColor]) cause problems with the copyZone. + */ +@property (MB_STRONG) UIColor *color; + +/** + * The x-axis offset of the HUD relative to the centre of the superview. + */ +@property (assign) float xOffset; + +/** + * The y-axis offset of the HUD relative to the centre of the superview. + */ +@property (assign) float yOffset; + +/** + * The amount of space between the HUD edge and the HUD elements (labels, indicators or custom views). + * Defaults to 20.0 + */ +@property (assign) float margin; + +/** + * The corner radius for the HUD + * Defaults to 10.0 + */ +@property (assign) float cornerRadius; + +/** + * Cover the HUD background view with a radial gradient. + */ +@property (assign) BOOL dimBackground; + +/* + * Grace period is the time (in seconds) that the invoked method may be run without + * showing the HUD. If the task finishes before the grace time runs out, the HUD will + * not be shown at all. + * This may be used to prevent HUD display for very short tasks. + * Defaults to 0 (no grace time). + * Grace time functionality is only supported when the task status is known! + * @see taskInProgress + */ +@property (assign) float graceTime; + +/** + * The minimum time (in seconds) that the HUD is shown. + * This avoids the problem of the HUD being shown and than instantly hidden. + * Defaults to 0 (no minimum show time). + */ +@property (assign) float minShowTime; + +/** + * Indicates that the executed operation is in progress. Needed for correct graceTime operation. + * If you don't set a graceTime (different than 0.0) this does nothing. + * This property is automatically set when using showWhileExecuting:onTarget:withObject:animated:. + * When threading is done outside of the HUD (i.e., when the show: and hide: methods are used directly), + * you need to set this property when your task starts and completes in order to have normal graceTime + * functionality. + */ +@property (assign) BOOL taskInProgress; + +/** + * Removes the HUD from its parent view when hidden. + * Defaults to NO. + */ +@property (assign) BOOL removeFromSuperViewOnHide; + +/** + * Font to be used for the main label. Set this property if the default is not adequate. + */ +@property (MB_STRONG) UIFont* labelFont; + +/** + * Color to be used for the main label. Set this property if the default is not adequate. + */ +@property (MB_STRONG) UIColor* labelColor; + +/** + * Font to be used for the details label. Set this property if the default is not adequate. + */ +@property (MB_STRONG) UIFont* detailsLabelFont; + +/** + * Color to be used for the details label. Set this property if the default is not adequate. + */ +@property (MB_STRONG) UIColor* detailsLabelColor; + +/** + * The color of the activity indicator. Defaults to [UIColor whiteColor] + * Does nothing on pre iOS 5. + */ +@property (MB_STRONG) UIColor *activityIndicatorColor; + +/** + * The progress of the progress indicator, from 0.0 to 1.0. Defaults to 0.0. + */ +@property (assign) float progress; + +/** + * The minimum size of the HUD bezel. Defaults to CGSizeZero (no minimum size). + */ +@property (assign) CGSize minSize; + + +/** + * The actual size of the HUD bezel. + * You can use this to limit touch handling on the bezel aria only. + * @see https://github.com/jdg/MBProgressHUD/pull/200 + */ +@property (atomic, assign, readonly) CGSize size; + + +/** + * Force the HUD dimensions to be equal if possible. + */ +@property (assign, getter = isSquare) BOOL square; + +@end + + +@protocol MBProgressHUDDelegate + +@optional + +/** + * Called after the HUD was fully hidden from the screen. + */ +- (void)hudWasHidden:(MBProgressHUD *)hud; + +@end + + +/** + * A progress view for showing definite progress by filling up a circle (pie chart). + */ +@interface MBRoundProgressView : UIView + +/** + * Progress (0.0 to 1.0) + */ +@property (nonatomic, assign) float progress; + +/** + * Indicator progress color. + * Defaults to white [UIColor whiteColor] + */ +@property (nonatomic, MB_STRONG) UIColor *progressTintColor; + +/** + * Indicator background (non-progress) color. + * Defaults to translucent white (alpha 0.1) + */ +@property (nonatomic, MB_STRONG) UIColor *backgroundTintColor; + +/* + * Display mode - NO = round or YES = annular. Defaults to round. + */ +@property (nonatomic, assign, getter = isAnnular) BOOL annular; + +@end + + +/** + * A flat bar progress view. + */ +@interface MBBarProgressView : UIView + +/** + * Progress (0.0 to 1.0) + */ +@property (nonatomic, assign) float progress; + +/** + * Bar border line color. + * Defaults to white [UIColor whiteColor]. + */ +@property (nonatomic, MB_STRONG) UIColor *lineColor; + +/** + * Bar background color. + * Defaults to clear [UIColor clearColor]; + */ +@property (nonatomic, MB_STRONG) UIColor *progressRemainingColor; + +/** + * Bar progress color. + * Defaults to white [UIColor whiteColor]. + */ +@property (nonatomic, MB_STRONG) UIColor *progressColor; + +@end diff --git a/ios/Pods/MBProgressHUD/MBProgressHUD.m b/ios/Pods/MBProgressHUD/MBProgressHUD.m new file mode 100644 index 000000000..4375f35e0 --- /dev/null +++ b/ios/Pods/MBProgressHUD/MBProgressHUD.m @@ -0,0 +1,1023 @@ +// +// MBProgressHUD.m +// Version 0.9 +// Created by Matej Bukovinski on 2.4.09. +// + +#import "MBProgressHUD.h" +#import + + +#if __has_feature(objc_arc) + #define MB_AUTORELEASE(exp) exp + #define MB_RELEASE(exp) exp + #define MB_RETAIN(exp) exp +#else + #define MB_AUTORELEASE(exp) [exp autorelease] + #define MB_RELEASE(exp) [exp release] + #define MB_RETAIN(exp) [exp retain] +#endif + +#if __IPHONE_OS_VERSION_MIN_REQUIRED >= 60000 + #define MBLabelAlignmentCenter NSTextAlignmentCenter +#else + #define MBLabelAlignmentCenter UITextAlignmentCenter +#endif + +#if __IPHONE_OS_VERSION_MIN_REQUIRED >= 70000 + #define MB_TEXTSIZE(text, font) [text length] > 0 ? [text \ + sizeWithAttributes:@{NSFontAttributeName:font}] : CGSizeZero; +#else + #define MB_TEXTSIZE(text, font) [text length] > 0 ? [text sizeWithFont:font] : CGSizeZero; +#endif + +#if __IPHONE_OS_VERSION_MIN_REQUIRED >= 70000 + #define MB_MULTILINE_TEXTSIZE(text, font, maxSize, mode) [text length] > 0 ? [text \ + boundingRectWithSize:maxSize options:(NSStringDrawingUsesLineFragmentOrigin) \ + attributes:@{NSFontAttributeName:font} context:nil].size : CGSizeZero; +#else + #define MB_MULTILINE_TEXTSIZE(text, font, maxSize, mode) [text length] > 0 ? [text \ + sizeWithFont:font constrainedToSize:maxSize lineBreakMode:mode] : CGSizeZero; +#endif + +#ifndef kCFCoreFoundationVersionNumber_iOS_7_0 + #define kCFCoreFoundationVersionNumber_iOS_7_0 847.20 +#endif + +#ifndef kCFCoreFoundationVersionNumber_iOS_8_0 + #define kCFCoreFoundationVersionNumber_iOS_8_0 1129.15 +#endif + + +static const CGFloat kPadding = 4.f; +static const CGFloat kLabelFontSize = 16.f; +static const CGFloat kDetailsLabelFontSize = 12.f; + + +@interface MBProgressHUD () { + BOOL useAnimation; + SEL methodForExecution; + id targetForExecution; + id objectForExecution; + UILabel *label; + UILabel *detailsLabel; + BOOL isFinished; + CGAffineTransform rotationTransform; +} + +@property (atomic, MB_STRONG) UIView *indicator; +@property (atomic, MB_STRONG) NSTimer *graceTimer; +@property (atomic, MB_STRONG) NSTimer *minShowTimer; +@property (atomic, MB_STRONG) NSDate *showStarted; + + +@end + + +@implementation MBProgressHUD + +#pragma mark - Properties + +@synthesize animationType; +@synthesize delegate; +@synthesize opacity; +@synthesize color; +@synthesize labelFont; +@synthesize labelColor; +@synthesize detailsLabelFont; +@synthesize detailsLabelColor; +@synthesize indicator; +@synthesize xOffset; +@synthesize yOffset; +@synthesize minSize; +@synthesize square; +@synthesize margin; +@synthesize dimBackground; +@synthesize graceTime; +@synthesize minShowTime; +@synthesize graceTimer; +@synthesize minShowTimer; +@synthesize taskInProgress; +@synthesize removeFromSuperViewOnHide; +@synthesize customView; +@synthesize showStarted; +@synthesize mode; +@synthesize labelText; +@synthesize detailsLabelText; +@synthesize progress; +@synthesize size; +@synthesize activityIndicatorColor; +#if NS_BLOCKS_AVAILABLE +@synthesize completionBlock; +#endif + +#pragma mark - Class methods + ++ (MB_INSTANCETYPE)showHUDAddedTo:(UIView *)view animated:(BOOL)animated { + MBProgressHUD *hud = [[self alloc] initWithView:view]; + [view addSubview:hud]; + [hud show:animated]; + return MB_AUTORELEASE(hud); +} + ++ (BOOL)hideHUDForView:(UIView *)view animated:(BOOL)animated { + MBProgressHUD *hud = [self HUDForView:view]; + if (hud != nil) { + hud.removeFromSuperViewOnHide = YES; + [hud hide:animated]; + return YES; + } + return NO; +} + ++ (NSUInteger)hideAllHUDsForView:(UIView *)view animated:(BOOL)animated { + NSArray *huds = [MBProgressHUD allHUDsForView:view]; + for (MBProgressHUD *hud in huds) { + hud.removeFromSuperViewOnHide = YES; + [hud hide:animated]; + } + return [huds count]; +} + ++ (MB_INSTANCETYPE)HUDForView:(UIView *)view { + NSEnumerator *subviewsEnum = [view.subviews reverseObjectEnumerator]; + for (UIView *subview in subviewsEnum) { + if ([subview isKindOfClass:self]) { + return (MBProgressHUD *)subview; + } + } + return nil; +} + ++ (NSArray *)allHUDsForView:(UIView *)view { + NSMutableArray *huds = [NSMutableArray array]; + NSArray *subviews = view.subviews; + for (UIView *aView in subviews) { + if ([aView isKindOfClass:self]) { + [huds addObject:aView]; + } + } + return [NSArray arrayWithArray:huds]; +} + +#pragma mark - Lifecycle + +- (id)initWithFrame:(CGRect)frame { + self = [super initWithFrame:frame]; + if (self) { + // Set default values for properties + self.animationType = MBProgressHUDAnimationFade; + self.mode = MBProgressHUDModeIndeterminate; + self.labelText = nil; + self.detailsLabelText = nil; + self.opacity = 0.8f; + self.color = nil; + self.labelFont = [UIFont boldSystemFontOfSize:kLabelFontSize]; + self.labelColor = [UIColor whiteColor]; + self.detailsLabelFont = [UIFont boldSystemFontOfSize:kDetailsLabelFontSize]; + self.detailsLabelColor = [UIColor whiteColor]; + self.activityIndicatorColor = [UIColor whiteColor]; + self.xOffset = 0.0f; + self.yOffset = 0.0f; + self.dimBackground = NO; + self.margin = 20.0f; + self.cornerRadius = 10.0f; + self.graceTime = 0.0f; + self.minShowTime = 0.0f; + self.removeFromSuperViewOnHide = NO; + self.minSize = CGSizeZero; + self.square = NO; + self.contentMode = UIViewContentModeCenter; + self.autoresizingMask = UIViewAutoresizingFlexibleTopMargin | UIViewAutoresizingFlexibleBottomMargin + | UIViewAutoresizingFlexibleLeftMargin | UIViewAutoresizingFlexibleRightMargin; + + // Transparent background + self.opaque = NO; + self.backgroundColor = [UIColor clearColor]; + // Make it invisible for now + self.alpha = 0.0f; + + taskInProgress = NO; + rotationTransform = CGAffineTransformIdentity; + + [self setupLabels]; + [self updateIndicators]; + [self registerForKVO]; + [self registerForNotifications]; + } + return self; +} + +- (id)initWithView:(UIView *)view { + NSAssert(view, @"View must not be nil."); + return [self initWithFrame:view.bounds]; +} + +- (id)initWithWindow:(UIWindow *)window { + return [self initWithView:window]; +} + +- (void)dealloc { + [self unregisterFromNotifications]; + [self unregisterFromKVO]; +#if !__has_feature(objc_arc) + [color release]; + [indicator release]; + [label release]; + [detailsLabel release]; + [labelText release]; + [detailsLabelText release]; + [graceTimer release]; + [minShowTimer release]; + [showStarted release]; + [customView release]; + [labelFont release]; + [labelColor release]; + [detailsLabelFont release]; + [detailsLabelColor release]; +#if NS_BLOCKS_AVAILABLE + [completionBlock release]; +#endif + [super dealloc]; +#endif +} + +#pragma mark - Show & hide + +- (void)show:(BOOL)animated { + useAnimation = animated; + // If the grace time is set postpone the HUD display + if (self.graceTime > 0.0) { + self.graceTimer = [NSTimer scheduledTimerWithTimeInterval:self.graceTime target:self + selector:@selector(handleGraceTimer:) userInfo:nil repeats:NO]; + } + // ... otherwise show the HUD imediately + else { + [self setNeedsDisplay]; + [self showUsingAnimation:useAnimation]; + } +} + +- (void)hide:(BOOL)animated { + useAnimation = animated; + // If the minShow time is set, calculate how long the hud was shown, + // and pospone the hiding operation if necessary + if (self.minShowTime > 0.0 && showStarted) { + NSTimeInterval interv = [[NSDate date] timeIntervalSinceDate:showStarted]; + if (interv < self.minShowTime) { + self.minShowTimer = [NSTimer scheduledTimerWithTimeInterval:(self.minShowTime - interv) target:self + selector:@selector(handleMinShowTimer:) userInfo:nil repeats:NO]; + return; + } + } + // ... otherwise hide the HUD immediately + [self hideUsingAnimation:useAnimation]; +} + +- (void)hide:(BOOL)animated afterDelay:(NSTimeInterval)delay { + [self performSelector:@selector(hideDelayed:) withObject:[NSNumber numberWithBool:animated] afterDelay:delay]; +} + +- (void)hideDelayed:(NSNumber *)animated { + [self hide:[animated boolValue]]; +} + +#pragma mark - Timer callbacks + +- (void)handleGraceTimer:(NSTimer *)theTimer { + // Show the HUD only if the task is still running + if (taskInProgress) { + [self setNeedsDisplay]; + [self showUsingAnimation:useAnimation]; + } +} + +- (void)handleMinShowTimer:(NSTimer *)theTimer { + [self hideUsingAnimation:useAnimation]; +} + +#pragma mark - View Hierrarchy + +- (BOOL)shouldPerformOrientationTransform { + BOOL isPreiOS8 = NSFoundationVersionNumber < kCFCoreFoundationVersionNumber_iOS_8_0; + // prior to iOS8 code needs to take care of rotation if it is being added to the window + return isPreiOS8 && [self.superview isKindOfClass:[UIWindow class]]; +} + +- (void)didMoveToSuperview { + if ([self shouldPerformOrientationTransform]) { + [self setTransformForCurrentOrientation:NO]; + } +} + +#pragma mark - Internal show & hide operations + +- (void)showUsingAnimation:(BOOL)animated { + if (animated && animationType == MBProgressHUDAnimationZoomIn) { + self.transform = CGAffineTransformConcat(rotationTransform, CGAffineTransformMakeScale(0.5f, 0.5f)); + } else if (animated && animationType == MBProgressHUDAnimationZoomOut) { + self.transform = CGAffineTransformConcat(rotationTransform, CGAffineTransformMakeScale(1.5f, 1.5f)); + } + self.showStarted = [NSDate date]; + // Fade in + if (animated) { + [UIView beginAnimations:nil context:NULL]; + [UIView setAnimationDuration:0.30]; + self.alpha = 1.0f; + if (animationType == MBProgressHUDAnimationZoomIn || animationType == MBProgressHUDAnimationZoomOut) { + self.transform = rotationTransform; + } + [UIView commitAnimations]; + } + else { + self.alpha = 1.0f; + } +} + +- (void)hideUsingAnimation:(BOOL)animated { + // Fade out + if (animated && showStarted) { + [UIView beginAnimations:nil context:NULL]; + [UIView setAnimationDuration:0.30]; + [UIView setAnimationDelegate:self]; + [UIView setAnimationDidStopSelector:@selector(animationFinished:finished:context:)]; + // 0.02 prevents the hud from passing through touches during the animation the hud will get completely hidden + // in the done method + if (animationType == MBProgressHUDAnimationZoomIn) { + self.transform = CGAffineTransformConcat(rotationTransform, CGAffineTransformMakeScale(1.5f, 1.5f)); + } else if (animationType == MBProgressHUDAnimationZoomOut) { + self.transform = CGAffineTransformConcat(rotationTransform, CGAffineTransformMakeScale(0.5f, 0.5f)); + } + + self.alpha = 0.02f; + [UIView commitAnimations]; + } + else { + self.alpha = 0.0f; + [self done]; + } + self.showStarted = nil; +} + +- (void)animationFinished:(NSString *)animationID finished:(BOOL)finished context:(void*)context { + [self done]; +} + +- (void)done { + [NSObject cancelPreviousPerformRequestsWithTarget:self]; + isFinished = YES; + self.alpha = 0.0f; + if (removeFromSuperViewOnHide) { + [self removeFromSuperview]; + } +#if NS_BLOCKS_AVAILABLE + if (self.completionBlock) { + self.completionBlock(); + self.completionBlock = NULL; + } +#endif + if ([delegate respondsToSelector:@selector(hudWasHidden:)]) { + [delegate performSelector:@selector(hudWasHidden:) withObject:self]; + } +} + +#pragma mark - Threading + +- (void)showWhileExecuting:(SEL)method onTarget:(id)target withObject:(id)object animated:(BOOL)animated { + methodForExecution = method; + targetForExecution = MB_RETAIN(target); + objectForExecution = MB_RETAIN(object); + // Launch execution in new thread + self.taskInProgress = YES; + [NSThread detachNewThreadSelector:@selector(launchExecution) toTarget:self withObject:nil]; + // Show HUD view + [self show:animated]; +} + +#if NS_BLOCKS_AVAILABLE + +- (void)showAnimated:(BOOL)animated whileExecutingBlock:(dispatch_block_t)block { + dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0); + [self showAnimated:animated whileExecutingBlock:block onQueue:queue completionBlock:NULL]; +} + +- (void)showAnimated:(BOOL)animated whileExecutingBlock:(dispatch_block_t)block completionBlock:(void (^)())completion { + dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0); + [self showAnimated:animated whileExecutingBlock:block onQueue:queue completionBlock:completion]; +} + +- (void)showAnimated:(BOOL)animated whileExecutingBlock:(dispatch_block_t)block onQueue:(dispatch_queue_t)queue { + [self showAnimated:animated whileExecutingBlock:block onQueue:queue completionBlock:NULL]; +} + +- (void)showAnimated:(BOOL)animated whileExecutingBlock:(dispatch_block_t)block onQueue:(dispatch_queue_t)queue + completionBlock:(MBProgressHUDCompletionBlock)completion { + self.taskInProgress = YES; + self.completionBlock = completion; + dispatch_async(queue, ^(void) { + block(); + dispatch_async(dispatch_get_main_queue(), ^(void) { + [self cleanUp]; + }); + }); + [self show:animated]; +} + +#endif + +- (void)launchExecution { + @autoreleasepool { +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Warc-performSelector-leaks" + // Start executing the requested task + [targetForExecution performSelector:methodForExecution withObject:objectForExecution]; +#pragma clang diagnostic pop + // Task completed, update view in main thread (note: view operations should + // be done only in the main thread) + [self performSelectorOnMainThread:@selector(cleanUp) withObject:nil waitUntilDone:NO]; + } +} + +- (void)cleanUp { + taskInProgress = NO; +#if !__has_feature(objc_arc) + [targetForExecution release]; + [objectForExecution release]; +#else + targetForExecution = nil; + objectForExecution = nil; +#endif + [self hide:useAnimation]; +} + +#pragma mark - UI + +- (void)setupLabels { + label = [[UILabel alloc] initWithFrame:self.bounds]; + label.adjustsFontSizeToFitWidth = NO; + label.textAlignment = MBLabelAlignmentCenter; + label.opaque = NO; + label.backgroundColor = [UIColor clearColor]; + label.textColor = self.labelColor; + label.font = self.labelFont; + label.text = self.labelText; + [self addSubview:label]; + + detailsLabel = [[UILabel alloc] initWithFrame:self.bounds]; + detailsLabel.font = self.detailsLabelFont; + detailsLabel.adjustsFontSizeToFitWidth = NO; + detailsLabel.textAlignment = MBLabelAlignmentCenter; + detailsLabel.opaque = NO; + detailsLabel.backgroundColor = [UIColor clearColor]; + detailsLabel.textColor = self.detailsLabelColor; + detailsLabel.numberOfLines = 0; + detailsLabel.font = self.detailsLabelFont; + detailsLabel.text = self.detailsLabelText; + [self addSubview:detailsLabel]; +} + +- (void)updateIndicators { + + BOOL isActivityIndicator = [indicator isKindOfClass:[UIActivityIndicatorView class]]; + BOOL isRoundIndicator = [indicator isKindOfClass:[MBRoundProgressView class]]; + + if (mode == MBProgressHUDModeIndeterminate) { + if (!isActivityIndicator) { + // Update to indeterminate indicator + [indicator removeFromSuperview]; + self.indicator = MB_AUTORELEASE([[UIActivityIndicatorView alloc] + initWithActivityIndicatorStyle:UIActivityIndicatorViewStyleWhiteLarge]); + [(UIActivityIndicatorView *)indicator startAnimating]; + [self addSubview:indicator]; + } +#if __IPHONE_OS_VERSION_MIN_REQUIRED >= 50000 + [(UIActivityIndicatorView *)indicator setColor:self.activityIndicatorColor]; +#endif + } + else if (mode == MBProgressHUDModeDeterminateHorizontalBar) { + // Update to bar determinate indicator + [indicator removeFromSuperview]; + self.indicator = MB_AUTORELEASE([[MBBarProgressView alloc] init]); + [self addSubview:indicator]; + } + else if (mode == MBProgressHUDModeDeterminate || mode == MBProgressHUDModeAnnularDeterminate) { + if (!isRoundIndicator) { + // Update to determinante indicator + [indicator removeFromSuperview]; + self.indicator = MB_AUTORELEASE([[MBRoundProgressView alloc] init]); + [self addSubview:indicator]; + } + if (mode == MBProgressHUDModeAnnularDeterminate) { + [(MBRoundProgressView *)indicator setAnnular:YES]; + } + } + else if (mode == MBProgressHUDModeCustomView && customView != indicator) { + // Update custom view indicator + [indicator removeFromSuperview]; + self.indicator = customView; + [self addSubview:indicator]; + } else if (mode == MBProgressHUDModeText) { + [indicator removeFromSuperview]; + self.indicator = nil; + } +} + +#pragma mark - Layout + +- (void)layoutSubviews { + [super layoutSubviews]; + + // Entirely cover the parent view + UIView *parent = self.superview; + if (parent) { + self.frame = parent.bounds; + } + CGRect bounds = self.bounds; + + // Determine the total widt and height needed + CGFloat maxWidth = bounds.size.width - 4 * margin; + CGSize totalSize = CGSizeZero; + + CGRect indicatorF = indicator.bounds; + indicatorF.size.width = MIN(indicatorF.size.width, maxWidth); + totalSize.width = MAX(totalSize.width, indicatorF.size.width); + totalSize.height += indicatorF.size.height; + + CGSize labelSize = MB_TEXTSIZE(label.text, label.font); + labelSize.width = MIN(labelSize.width, maxWidth); + totalSize.width = MAX(totalSize.width, labelSize.width); + totalSize.height += labelSize.height; + if (labelSize.height > 0.f && indicatorF.size.height > 0.f) { + totalSize.height += kPadding; + } + + CGFloat remainingHeight = bounds.size.height - totalSize.height - kPadding - 4 * margin; + CGSize maxSize = CGSizeMake(maxWidth, remainingHeight); + CGSize detailsLabelSize = MB_MULTILINE_TEXTSIZE(detailsLabel.text, detailsLabel.font, maxSize, detailsLabel.lineBreakMode); + totalSize.width = MAX(totalSize.width, detailsLabelSize.width); + totalSize.height += detailsLabelSize.height; + if (detailsLabelSize.height > 0.f && (indicatorF.size.height > 0.f || labelSize.height > 0.f)) { + totalSize.height += kPadding; + } + + totalSize.width += 2 * margin; + totalSize.height += 2 * margin; + + // Position elements + CGFloat yPos = round(((bounds.size.height - totalSize.height) / 2)) + margin + yOffset; + CGFloat xPos = xOffset; + indicatorF.origin.y = yPos; + indicatorF.origin.x = round((bounds.size.width - indicatorF.size.width) / 2) + xPos; + indicator.frame = indicatorF; + yPos += indicatorF.size.height; + + if (labelSize.height > 0.f && indicatorF.size.height > 0.f) { + yPos += kPadding; + } + CGRect labelF; + labelF.origin.y = yPos; + labelF.origin.x = round((bounds.size.width - labelSize.width) / 2) + xPos; + labelF.size = labelSize; + label.frame = labelF; + yPos += labelF.size.height; + + if (detailsLabelSize.height > 0.f && (indicatorF.size.height > 0.f || labelSize.height > 0.f)) { + yPos += kPadding; + } + CGRect detailsLabelF; + detailsLabelF.origin.y = yPos; + detailsLabelF.origin.x = round((bounds.size.width - detailsLabelSize.width) / 2) + xPos; + detailsLabelF.size = detailsLabelSize; + detailsLabel.frame = detailsLabelF; + + // Enforce minsize and quare rules + if (square) { + CGFloat max = MAX(totalSize.width, totalSize.height); + if (max <= bounds.size.width - 2 * margin) { + totalSize.width = max; + } + if (max <= bounds.size.height - 2 * margin) { + totalSize.height = max; + } + } + if (totalSize.width < minSize.width) { + totalSize.width = minSize.width; + } + if (totalSize.height < minSize.height) { + totalSize.height = minSize.height; + } + + size = totalSize; +} + +#pragma mark BG Drawing + +- (void)drawRect:(CGRect)rect { + + CGContextRef context = UIGraphicsGetCurrentContext(); + UIGraphicsPushContext(context); + + if (self.dimBackground) { + //Gradient colours + size_t gradLocationsNum = 2; + CGFloat gradLocations[2] = {0.0f, 1.0f}; + CGFloat gradColors[8] = {0.0f,0.0f,0.0f,0.0f,0.0f,0.0f,0.0f,0.75f}; + CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB(); + CGGradientRef gradient = CGGradientCreateWithColorComponents(colorSpace, gradColors, gradLocations, gradLocationsNum); + CGColorSpaceRelease(colorSpace); + //Gradient center + CGPoint gradCenter= CGPointMake(self.bounds.size.width/2, self.bounds.size.height/2); + //Gradient radius + float gradRadius = MIN(self.bounds.size.width , self.bounds.size.height) ; + //Gradient draw + CGContextDrawRadialGradient (context, gradient, gradCenter, + 0, gradCenter, gradRadius, + kCGGradientDrawsAfterEndLocation); + CGGradientRelease(gradient); + } + + // Set background rect color + if (self.color) { + CGContextSetFillColorWithColor(context, self.color.CGColor); + } else { + CGContextSetGrayFillColor(context, 0.0f, self.opacity); + } + + + // Center HUD + CGRect allRect = self.bounds; + // Draw rounded HUD backgroud rect + CGRect boxRect = CGRectMake(round((allRect.size.width - size.width) / 2) + self.xOffset, + round((allRect.size.height - size.height) / 2) + self.yOffset, size.width, size.height); + float radius = self.cornerRadius; + CGContextBeginPath(context); + CGContextMoveToPoint(context, CGRectGetMinX(boxRect) + radius, CGRectGetMinY(boxRect)); + CGContextAddArc(context, CGRectGetMaxX(boxRect) - radius, CGRectGetMinY(boxRect) + radius, radius, 3 * (float)M_PI / 2, 0, 0); + CGContextAddArc(context, CGRectGetMaxX(boxRect) - radius, CGRectGetMaxY(boxRect) - radius, radius, 0, (float)M_PI / 2, 0); + CGContextAddArc(context, CGRectGetMinX(boxRect) + radius, CGRectGetMaxY(boxRect) - radius, radius, (float)M_PI / 2, (float)M_PI, 0); + CGContextAddArc(context, CGRectGetMinX(boxRect) + radius, CGRectGetMinY(boxRect) + radius, radius, (float)M_PI, 3 * (float)M_PI / 2, 0); + CGContextClosePath(context); + CGContextFillPath(context); + + UIGraphicsPopContext(); +} + +#pragma mark - KVO + +- (void)registerForKVO { + for (NSString *keyPath in [self observableKeypaths]) { + [self addObserver:self forKeyPath:keyPath options:NSKeyValueObservingOptionNew context:NULL]; + } +} + +- (void)unregisterFromKVO { + for (NSString *keyPath in [self observableKeypaths]) { + [self removeObserver:self forKeyPath:keyPath]; + } +} + +- (NSArray *)observableKeypaths { + return [NSArray arrayWithObjects:@"mode", @"customView", @"labelText", @"labelFont", @"labelColor", + @"detailsLabelText", @"detailsLabelFont", @"detailsLabelColor", @"progress", @"activityIndicatorColor", nil]; +} + +- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context { + if (![NSThread isMainThread]) { + [self performSelectorOnMainThread:@selector(updateUIForKeypath:) withObject:keyPath waitUntilDone:NO]; + } else { + [self updateUIForKeypath:keyPath]; + } +} + +- (void)updateUIForKeypath:(NSString *)keyPath { + if ([keyPath isEqualToString:@"mode"] || [keyPath isEqualToString:@"customView"] || + [keyPath isEqualToString:@"activityIndicatorColor"]) { + [self updateIndicators]; + } else if ([keyPath isEqualToString:@"labelText"]) { + label.text = self.labelText; + } else if ([keyPath isEqualToString:@"labelFont"]) { + label.font = self.labelFont; + } else if ([keyPath isEqualToString:@"labelColor"]) { + label.textColor = self.labelColor; + } else if ([keyPath isEqualToString:@"detailsLabelText"]) { + detailsLabel.text = self.detailsLabelText; + } else if ([keyPath isEqualToString:@"detailsLabelFont"]) { + detailsLabel.font = self.detailsLabelFont; + } else if ([keyPath isEqualToString:@"detailsLabelColor"]) { + detailsLabel.textColor = self.detailsLabelColor; + } else if ([keyPath isEqualToString:@"progress"]) { + if ([indicator respondsToSelector:@selector(setProgress:)]) { + [(id)indicator setValue:@(progress) forKey:@"progress"]; + } + return; + } + [self setNeedsLayout]; + [self setNeedsDisplay]; +} + +#pragma mark - Notifications + +- (void)registerForNotifications { + NSNotificationCenter *nc = [NSNotificationCenter defaultCenter]; + + [nc addObserver:self selector:@selector(statusBarOrientationDidChange:) + name:UIApplicationDidChangeStatusBarOrientationNotification object:nil]; +} + +- (void)unregisterFromNotifications { + NSNotificationCenter *nc = [NSNotificationCenter defaultCenter]; + [nc removeObserver:self name:UIApplicationDidChangeStatusBarOrientationNotification object:nil]; +} + +- (void)statusBarOrientationDidChange:(NSNotification *)notification { + UIView *superview = self.superview; + if (!superview) { + return; + } else if ([self shouldPerformOrientationTransform]) { + [self setTransformForCurrentOrientation:YES]; + } else { + self.frame = self.superview.bounds; + [self setNeedsDisplay]; + } +} + +- (void)setTransformForCurrentOrientation:(BOOL)animated { + // Stay in sync with the superview + if (self.superview) { + self.bounds = self.superview.bounds; + [self setNeedsDisplay]; + } + + UIInterfaceOrientation orientation = [UIApplication sharedApplication].statusBarOrientation; + CGFloat radians = 0; + if (UIInterfaceOrientationIsLandscape(orientation)) { + if (orientation == UIInterfaceOrientationLandscapeLeft) { radians = -(CGFloat)M_PI_2; } + else { radians = (CGFloat)M_PI_2; } + // Window coordinates differ! + self.bounds = CGRectMake(0, 0, self.bounds.size.height, self.bounds.size.width); + } else { + if (orientation == UIInterfaceOrientationPortraitUpsideDown) { radians = (CGFloat)M_PI; } + else { radians = 0; } + } + rotationTransform = CGAffineTransformMakeRotation(radians); + + if (animated) { + [UIView beginAnimations:nil context:nil]; + [UIView setAnimationDuration:0.3]; + } + [self setTransform:rotationTransform]; + if (animated) { + [UIView commitAnimations]; + } +} + +@end + + +@implementation MBRoundProgressView + +#pragma mark - Lifecycle + +- (id)init { + return [self initWithFrame:CGRectMake(0.f, 0.f, 37.f, 37.f)]; +} + +- (id)initWithFrame:(CGRect)frame { + self = [super initWithFrame:frame]; + if (self) { + self.backgroundColor = [UIColor clearColor]; + self.opaque = NO; + _progress = 0.f; + _annular = NO; + _progressTintColor = [[UIColor alloc] initWithWhite:1.f alpha:1.f]; + _backgroundTintColor = [[UIColor alloc] initWithWhite:1.f alpha:.1f]; + [self registerForKVO]; + } + return self; +} + +- (void)dealloc { + [self unregisterFromKVO]; +#if !__has_feature(objc_arc) + [_progressTintColor release]; + [_backgroundTintColor release]; + [super dealloc]; +#endif +} + +#pragma mark - Drawing + +- (void)drawRect:(CGRect)rect { + + CGRect allRect = self.bounds; + CGRect circleRect = CGRectInset(allRect, 2.0f, 2.0f); + CGContextRef context = UIGraphicsGetCurrentContext(); + + if (_annular) { + // Draw background + BOOL isPreiOS7 = NSFoundationVersionNumber < kCFCoreFoundationVersionNumber_iOS_7_0; + CGFloat lineWidth = isPreiOS7 ? 5.f : 2.f; + UIBezierPath *processBackgroundPath = [UIBezierPath bezierPath]; + processBackgroundPath.lineWidth = lineWidth; + processBackgroundPath.lineCapStyle = kCGLineCapButt; + CGPoint center = CGPointMake(self.bounds.size.width/2, self.bounds.size.height/2); + CGFloat radius = (self.bounds.size.width - lineWidth)/2; + CGFloat startAngle = - ((float)M_PI / 2); // 90 degrees + CGFloat endAngle = (2 * (float)M_PI) + startAngle; + [processBackgroundPath addArcWithCenter:center radius:radius startAngle:startAngle endAngle:endAngle clockwise:YES]; + [_backgroundTintColor set]; + [processBackgroundPath stroke]; + // Draw progress + UIBezierPath *processPath = [UIBezierPath bezierPath]; + processPath.lineCapStyle = isPreiOS7 ? kCGLineCapRound : kCGLineCapSquare; + processPath.lineWidth = lineWidth; + endAngle = (self.progress * 2 * (float)M_PI) + startAngle; + [processPath addArcWithCenter:center radius:radius startAngle:startAngle endAngle:endAngle clockwise:YES]; + [_progressTintColor set]; + [processPath stroke]; + } else { + // Draw background + [_progressTintColor setStroke]; + [_backgroundTintColor setFill]; + CGContextSetLineWidth(context, 2.0f); + CGContextFillEllipseInRect(context, circleRect); + CGContextStrokeEllipseInRect(context, circleRect); + // Draw progress + CGPoint center = CGPointMake(allRect.size.width / 2, allRect.size.height / 2); + CGFloat radius = (allRect.size.width - 4) / 2; + CGFloat startAngle = - ((float)M_PI / 2); // 90 degrees + CGFloat endAngle = (self.progress * 2 * (float)M_PI) + startAngle; + CGContextSetRGBFillColor(context, 1.0f, 1.0f, 1.0f, 1.0f); // white + CGContextMoveToPoint(context, center.x, center.y); + CGContextAddArc(context, center.x, center.y, radius, startAngle, endAngle, 0); + CGContextClosePath(context); + CGContextFillPath(context); + } +} + +#pragma mark - KVO + +- (void)registerForKVO { + for (NSString *keyPath in [self observableKeypaths]) { + [self addObserver:self forKeyPath:keyPath options:NSKeyValueObservingOptionNew context:NULL]; + } +} + +- (void)unregisterFromKVO { + for (NSString *keyPath in [self observableKeypaths]) { + [self removeObserver:self forKeyPath:keyPath]; + } +} + +- (NSArray *)observableKeypaths { + return [NSArray arrayWithObjects:@"progressTintColor", @"backgroundTintColor", @"progress", @"annular", nil]; +} + +- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context { + [self setNeedsDisplay]; +} + +@end + + +@implementation MBBarProgressView + +#pragma mark - Lifecycle + +- (id)init { + return [self initWithFrame:CGRectMake(.0f, .0f, 120.0f, 20.0f)]; +} + +- (id)initWithFrame:(CGRect)frame { + self = [super initWithFrame:frame]; + if (self) { + _progress = 0.f; + _lineColor = [UIColor whiteColor]; + _progressColor = [UIColor whiteColor]; + _progressRemainingColor = [UIColor clearColor]; + self.backgroundColor = [UIColor clearColor]; + self.opaque = NO; + [self registerForKVO]; + } + return self; +} + +- (void)dealloc { + [self unregisterFromKVO]; +#if !__has_feature(objc_arc) + [_lineColor release]; + [_progressColor release]; + [_progressRemainingColor release]; + [super dealloc]; +#endif +} + +#pragma mark - Drawing + +- (void)drawRect:(CGRect)rect { + CGContextRef context = UIGraphicsGetCurrentContext(); + + CGContextSetLineWidth(context, 2); + CGContextSetStrokeColorWithColor(context,[_lineColor CGColor]); + CGContextSetFillColorWithColor(context, [_progressRemainingColor CGColor]); + + // Draw background + float radius = (rect.size.height / 2) - 2; + CGContextMoveToPoint(context, 2, rect.size.height/2); + CGContextAddArcToPoint(context, 2, 2, radius + 2, 2, radius); + CGContextAddLineToPoint(context, rect.size.width - radius - 2, 2); + CGContextAddArcToPoint(context, rect.size.width - 2, 2, rect.size.width - 2, rect.size.height / 2, radius); + CGContextAddArcToPoint(context, rect.size.width - 2, rect.size.height - 2, rect.size.width - radius - 2, rect.size.height - 2, radius); + CGContextAddLineToPoint(context, radius + 2, rect.size.height - 2); + CGContextAddArcToPoint(context, 2, rect.size.height - 2, 2, rect.size.height/2, radius); + CGContextFillPath(context); + + // Draw border + CGContextMoveToPoint(context, 2, rect.size.height/2); + CGContextAddArcToPoint(context, 2, 2, radius + 2, 2, radius); + CGContextAddLineToPoint(context, rect.size.width - radius - 2, 2); + CGContextAddArcToPoint(context, rect.size.width - 2, 2, rect.size.width - 2, rect.size.height / 2, radius); + CGContextAddArcToPoint(context, rect.size.width - 2, rect.size.height - 2, rect.size.width - radius - 2, rect.size.height - 2, radius); + CGContextAddLineToPoint(context, radius + 2, rect.size.height - 2); + CGContextAddArcToPoint(context, 2, rect.size.height - 2, 2, rect.size.height/2, radius); + CGContextStrokePath(context); + + CGContextSetFillColorWithColor(context, [_progressColor CGColor]); + radius = radius - 2; + float amount = self.progress * rect.size.width; + + // Progress in the middle area + if (amount >= radius + 4 && amount <= (rect.size.width - radius - 4)) { + CGContextMoveToPoint(context, 4, rect.size.height/2); + CGContextAddArcToPoint(context, 4, 4, radius + 4, 4, radius); + CGContextAddLineToPoint(context, amount, 4); + CGContextAddLineToPoint(context, amount, radius + 4); + + CGContextMoveToPoint(context, 4, rect.size.height/2); + CGContextAddArcToPoint(context, 4, rect.size.height - 4, radius + 4, rect.size.height - 4, radius); + CGContextAddLineToPoint(context, amount, rect.size.height - 4); + CGContextAddLineToPoint(context, amount, radius + 4); + + CGContextFillPath(context); + } + + // Progress in the right arc + else if (amount > radius + 4) { + float x = amount - (rect.size.width - radius - 4); + + CGContextMoveToPoint(context, 4, rect.size.height/2); + CGContextAddArcToPoint(context, 4, 4, radius + 4, 4, radius); + CGContextAddLineToPoint(context, rect.size.width - radius - 4, 4); + float angle = -acos(x/radius); + if (isnan(angle)) angle = 0; + CGContextAddArc(context, rect.size.width - radius - 4, rect.size.height/2, radius, M_PI, angle, 0); + CGContextAddLineToPoint(context, amount, rect.size.height/2); + + CGContextMoveToPoint(context, 4, rect.size.height/2); + CGContextAddArcToPoint(context, 4, rect.size.height - 4, radius + 4, rect.size.height - 4, radius); + CGContextAddLineToPoint(context, rect.size.width - radius - 4, rect.size.height - 4); + angle = acos(x/radius); + if (isnan(angle)) angle = 0; + CGContextAddArc(context, rect.size.width - radius - 4, rect.size.height/2, radius, -M_PI, angle, 1); + CGContextAddLineToPoint(context, amount, rect.size.height/2); + + CGContextFillPath(context); + } + + // Progress is in the left arc + else if (amount < radius + 4 && amount > 0) { + CGContextMoveToPoint(context, 4, rect.size.height/2); + CGContextAddArcToPoint(context, 4, 4, radius + 4, 4, radius); + CGContextAddLineToPoint(context, radius + 4, rect.size.height/2); + + CGContextMoveToPoint(context, 4, rect.size.height/2); + CGContextAddArcToPoint(context, 4, rect.size.height - 4, radius + 4, rect.size.height - 4, radius); + CGContextAddLineToPoint(context, radius + 4, rect.size.height/2); + + CGContextFillPath(context); + } +} + +#pragma mark - KVO + +- (void)registerForKVO { + for (NSString *keyPath in [self observableKeypaths]) { + [self addObserver:self forKeyPath:keyPath options:NSKeyValueObservingOptionNew context:NULL]; + } +} + +- (void)unregisterFromKVO { + for (NSString *keyPath in [self observableKeypaths]) { + [self removeObserver:self forKeyPath:keyPath]; + } +} + +- (NSArray *)observableKeypaths { + return [NSArray arrayWithObjects:@"lineColor", @"progressRemainingColor", @"progressColor", @"progress", nil]; +} + +- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context { + [self setNeedsDisplay]; +} + +@end diff --git a/ios/Pods/MBProgressHUD/README.mdown b/ios/Pods/MBProgressHUD/README.mdown new file mode 100644 index 000000000..d21bc65fb --- /dev/null +++ b/ios/Pods/MBProgressHUD/README.mdown @@ -0,0 +1,101 @@ +# MBProgressHUD [![Build Status](https://travis-ci.org/matej/MBProgressHUD.png)](https://travis-ci.org/matej/MBProgressHUD) + +MBProgressHUD is an iOS drop-in class that displays a translucent HUD with an indicator and/or labels while work is being done in a background thread. The HUD is meant as a replacement for the undocumented, private UIKit UIProgressHUD with some additional features. + +[![](http://dl.dropbox.com/u/378729/MBProgressHUD/1-thumb.png)](http://dl.dropbox.com/u/378729/MBProgressHUD/1.png) +[![](http://dl.dropbox.com/u/378729/MBProgressHUD/2-thumb.png)](http://dl.dropbox.com/u/378729/MBProgressHUD/2.png) +[![](http://dl.dropbox.com/u/378729/MBProgressHUD/3-thumb.png)](http://dl.dropbox.com/u/378729/MBProgressHUD/3.png) +[![](http://dl.dropbox.com/u/378729/MBProgressHUD/4-thumb.png)](http://dl.dropbox.com/u/378729/MBProgressHUD/4.png) +[![](http://dl.dropbox.com/u/378729/MBProgressHUD/5-thumb.png)](http://dl.dropbox.com/u/378729/MBProgressHUD/5.png) +[![](http://dl.dropbox.com/u/378729/MBProgressHUD/6-thumb.png)](http://dl.dropbox.com/u/378729/MBProgressHUD/6.png) +[![](http://dl.dropbox.com/u/378729/MBProgressHUD/7-thumb.png)](http://dl.dropbox.com/u/378729/MBProgressHUD/7.png) + +## Requirements + +MBProgressHUD works on any iOS version and is compatible with both ARC and non-ARC projects. It depends on the following Apple frameworks, which should already be included with most Xcode templates: + +* Foundation.framework +* UIKit.framework +* CoreGraphics.framework + +You will need LLVM 3.0 or later in order to build MBProgressHUD. + +## Adding MBProgressHUD to your project + +### Cocoapods + +[CocoaPods](http://cocoapods.org) is the recommended way to add MBProgressHUD to your project. + +1. Add a pod entry for MBProgressHUD to your Podfile `pod 'MBProgressHUD', '~> 0.8'` +2. Install the pod(s) by running `pod install`. +3. Include MBProgressHUD wherever you need it with `#import "MBProgressHUD.h"`. + +### Source files + +Alternatively you can directly add the `MBProgressHUD.h` and `MBProgressHUD.m` source files to your project. + +1. Download the [latest code version](https://github.com/matej/MBProgressHUD/archive/master.zip) or add the repository as a git submodule to your git-tracked project. +2. Open your project in Xcode, then drag and drop `MBProgressHUD.h` and `MBProgressHUD.m` onto your project (use the "Product Navigator view"). Make sure to select Copy items when asked if you extracted the code archive outside of your project. +3. Include MBProgressHUD wherever you need it with `#import "MBProgressHUD.h"`. + +### Static library + +You can also add MBProgressHUD as a static library to your project or workspace. + +1. Download the [latest code version](https://github.com/matej/MBProgressHUD/downloads) or add the repository as a git submodule to your git-tracked project. +2. Open your project in Xcode, then drag and drop `MBProgressHUD.xcodeproj` onto your project or workspace (use the "Product Navigator view"). +3. Select your target and go to the Build phases tab. In the Link Binary With Libraries section select the add button. On the sheet find and add `libMBProgressHUD.a`. You might also need to add `MBProgressHUD` to the Target Dependencies list. +4. Include MBProgressHUD wherever you need it with `#import `. + +## Usage + +The main guideline you need to follow when dealing with MBProgressHUD while running long-running tasks is keeping the main thread work-free, so the UI can be updated promptly. The recommended way of using MBProgressHUD is therefore to set it up on the main thread and then spinning the task, that you want to perform, off onto a new thread. + +```objective-c +[MBProgressHUD showHUDAddedTo:self.view animated:YES]; +dispatch_async(dispatch_get_global_queue( DISPATCH_QUEUE_PRIORITY_LOW, 0), ^{ + // Do something... + dispatch_async(dispatch_get_main_queue(), ^{ + [MBProgressHUD hideHUDForView:self.view animated:YES]; + }); +}); +``` + +If you need to configure the HUD you can do this by using the MBProgressHUD reference that showHUDAddedTo:animated: returns. + +```objective-c +MBProgressHUD *hud = [MBProgressHUD showHUDAddedTo:self.view animated:YES]; +hud.mode = MBProgressHUDModeAnnularDeterminate; +hud.labelText = @"Loading"; +[self doSomethingInBackgroundWithProgressCallback:^(float progress) { + hud.progress = progress; +} completionCallback:^{ + [hud hide:YES]; +}]; +``` + +UI updates should always be done on the main thread. Some MBProgressHUD setters are however considered "thread safe" and can be called from background threads. Those also include `setMode:`, `setCustomView:`, `setLabelText:`, `setLabelFont:`, `setDetailsLabelText:`, `setDetailsLabelFont:` and `setProgress:`. + +If you need to run your long-running task in the main thread, you should perform it with a slight delay, so UIKit will have enough time to update the UI (i.e., draw the HUD) before you block the main thread with your task. + +```objective-c +[MBProgressHUD showHUDAddedTo:self.view animated:YES]; +dispatch_time_t popTime = dispatch_time(DISPATCH_TIME_NOW, 0.01 * NSEC_PER_SEC); +dispatch_after(popTime, dispatch_get_main_queue(), ^(void){ + // Do something... + [MBProgressHUD hideHUDForView:self.view animated:YES]; +}); +``` + +You should be aware that any HUD updates issued inside the above block won't be displayed until the block completes. + +For more examples, including how to use MBProgressHUD with asynchronous operations such as NSURLConnection, take a look at the bundled demo project. Extensive API documentation is provided in the header file (MBProgressHUD.h). + + +## License + +This code is distributed under the terms and conditions of the [MIT license](LICENSE). + +## Change-log + +A brief summary of each MBProgressHUD release can be found on the [wiki](https://github.com/matej/MBProgressHUD/wiki/Change-log). diff --git a/ios/Pods/MWPhotoBrowser/LICENCE.txt b/ios/Pods/MWPhotoBrowser/LICENCE.txt new file mode 100644 index 000000000..1231f1aab --- /dev/null +++ b/ios/Pods/MWPhotoBrowser/LICENCE.txt @@ -0,0 +1,19 @@ +Copyright (c) 2010 Michael Waterfall + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. \ No newline at end of file diff --git a/ios/Pods/MWPhotoBrowser/MWPhotoBrowser/Classes/MWCaptionView.h b/ios/Pods/MWPhotoBrowser/MWPhotoBrowser/Classes/MWCaptionView.h new file mode 100644 index 000000000..6fd2c8c95 --- /dev/null +++ b/ios/Pods/MWPhotoBrowser/MWPhotoBrowser/Classes/MWCaptionView.h @@ -0,0 +1,33 @@ +// +// MWCaptionView.h +// MWPhotoBrowser +// +// Created by Michael Waterfall on 30/12/2011. +// Copyright (c) 2011 __MyCompanyName__. All rights reserved. +// + +#import +#import "MWPhotoProtocol.h" + +@interface MWCaptionView : UIToolbar + +// Init +- (id)initWithPhoto:(id)photo; + +// To create your own custom caption view, subclass this view +// and override the following two methods (as well as any other +// UIView methods that you see fit): + +// Override -setupCaption so setup your subviews and customise the appearance +// of your custom caption +// You can access the photo's data by accessing the _photo ivar +// If you need more data per photo then simply subclass MWPhoto and return your +// subclass to the photo browsers -photoBrowser:photoAtIndex: delegate method +- (void)setupCaption; + +// Override -sizeThatFits: and return a CGSize specifying the height of your +// custom caption view. With width property is ignored and the caption is displayed +// the full width of the screen +- (CGSize)sizeThatFits:(CGSize)size; + +@end diff --git a/ios/Pods/MWPhotoBrowser/MWPhotoBrowser/Classes/MWCaptionView.m b/ios/Pods/MWPhotoBrowser/MWPhotoBrowser/Classes/MWCaptionView.m new file mode 100644 index 000000000..27ba4224f --- /dev/null +++ b/ios/Pods/MWPhotoBrowser/MWPhotoBrowser/Classes/MWCaptionView.m @@ -0,0 +1,106 @@ +// +// MWCaptionView.m +// MWPhotoBrowser +// +// Created by Michael Waterfall on 30/12/2011. +// Copyright (c) 2011 __MyCompanyName__. All rights reserved. +// + +#import "MWCommon.h" +#import "MWCaptionView.h" +#import "MWPhoto.h" + +static const CGFloat labelPadding = 10; + +// Private +@interface MWCaptionView () { + id _photo; + UILabel *_label; +} +@end + +@implementation MWCaptionView + +- (id)initWithPhoto:(id)photo { + self = [super initWithFrame:CGRectMake(0, 0, 320, 44)]; // Random initial frame + if (self) { + self.userInteractionEnabled = NO; + _photo = photo; + if (SYSTEM_VERSION_GREATER_THAN_OR_EQUAL_TO(@"7")) { + // Use iOS 7 blurry goodness + self.barStyle = UIBarStyleBlackTranslucent; + self.tintColor = nil; + self.barTintColor = nil; + self.barStyle = UIBarStyleBlackTranslucent; + [self setBackgroundImage:nil forToolbarPosition:UIBarPositionAny barMetrics:UIBarMetricsDefault]; + } else { + // Transparent black with no gloss + CGRect rect = CGRectMake(0.0f, 0.0f, 1.0f, 1.0f); + UIGraphicsBeginImageContext(rect.size); + CGContextRef context = UIGraphicsGetCurrentContext(); + CGContextSetFillColorWithColor(context, [[UIColor colorWithWhite:0 alpha:0.6] CGColor]); + CGContextFillRect(context, rect); + UIImage *image = UIGraphicsGetImageFromCurrentImageContext(); + UIGraphicsEndImageContext(); + [self setBackgroundImage:image forToolbarPosition:UIBarPositionAny barMetrics:UIBarMetricsDefault]; + } + self.autoresizingMask = UIViewAutoresizingFlexibleWidth|UIViewAutoresizingFlexibleTopMargin|UIViewAutoresizingFlexibleLeftMargin|UIViewAutoresizingFlexibleRightMargin; + [self setupCaption]; + } + return self; +} + +- (CGSize)sizeThatFits:(CGSize)size { + CGFloat maxHeight = 9999; + if (_label.numberOfLines > 0) maxHeight = _label.font.leading*_label.numberOfLines; + CGSize textSize; + if ([NSString instancesRespondToSelector:@selector(boundingRectWithSize:options:attributes:context:)]) { + textSize = [_label.text boundingRectWithSize:CGSizeMake(size.width - labelPadding*2, maxHeight) + options:NSStringDrawingUsesLineFragmentOrigin + attributes:@{NSFontAttributeName:_label.font} + context:nil].size; + } else { +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wdeprecated-declarations" + textSize = [_label.text sizeWithFont:_label.font + constrainedToSize:CGSizeMake(size.width - labelPadding*2, maxHeight) + lineBreakMode:_label.lineBreakMode]; +#pragma clang diagnostic pop + } + return CGSizeMake(size.width, textSize.height + labelPadding * 2); +} + +- (void)setupCaption { + _label = [[UILabel alloc] initWithFrame:CGRectIntegral(CGRectMake(labelPadding, 0, + self.bounds.size.width-labelPadding*2, + self.bounds.size.height))]; + _label.autoresizingMask = UIViewAutoresizingFlexibleWidth|UIViewAutoresizingFlexibleHeight; + _label.opaque = NO; + _label.backgroundColor = [UIColor clearColor]; + if (SYSTEM_VERSION_LESS_THAN(@"6")) { +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wdeprecated-declarations" + _label.textAlignment = UITextAlignmentCenter; + _label.lineBreakMode = UILineBreakModeWordWrap; +#pragma clang diagnostic pop + } else { + _label.textAlignment = NSTextAlignmentCenter; + _label.lineBreakMode = NSLineBreakByWordWrapping; + } + + _label.numberOfLines = 0; + _label.textColor = [UIColor whiteColor]; + if (SYSTEM_VERSION_LESS_THAN(@"7")) { + // Shadow on 6 and below + _label.shadowColor = [UIColor blackColor]; + _label.shadowOffset = CGSizeMake(1, 1); + } + _label.font = [UIFont systemFontOfSize:17]; + if ([_photo respondsToSelector:@selector(caption)]) { + _label.text = [_photo caption] ? [_photo caption] : @" "; + } + [self addSubview:_label]; +} + + +@end diff --git a/ios/Pods/MWPhotoBrowser/MWPhotoBrowser/Classes/MWCommon.h b/ios/Pods/MWPhotoBrowser/MWPhotoBrowser/Classes/MWCommon.h new file mode 100644 index 000000000..b15d2824f --- /dev/null +++ b/ios/Pods/MWPhotoBrowser/MWPhotoBrowser/Classes/MWCommon.h @@ -0,0 +1,12 @@ +// +// MWPreprocessor.h +// MWPhotoBrowser +// +// Created by Michael Waterfall on 01/10/2013. +// + +#define SYSTEM_VERSION_EQUAL_TO(v) ([[[UIDevice currentDevice] systemVersion] compare:v options:NSNumericSearch] == NSOrderedSame) +#define SYSTEM_VERSION_GREATER_THAN(v) ([[[UIDevice currentDevice] systemVersion] compare:v options:NSNumericSearch] == NSOrderedDescending) +#define SYSTEM_VERSION_GREATER_THAN_OR_EQUAL_TO(v) ([[[UIDevice currentDevice] systemVersion] compare:v options:NSNumericSearch] != NSOrderedAscending) +#define SYSTEM_VERSION_LESS_THAN(v) ([[[UIDevice currentDevice] systemVersion] compare:v options:NSNumericSearch] == NSOrderedAscending) +#define SYSTEM_VERSION_LESS_THAN_OR_EQUAL_TO(v) ([[[UIDevice currentDevice] systemVersion] compare:v options:NSNumericSearch] != NSOrderedDescending) diff --git a/ios/Pods/MWPhotoBrowser/MWPhotoBrowser/Classes/MWGridCell.h b/ios/Pods/MWPhotoBrowser/MWPhotoBrowser/Classes/MWGridCell.h new file mode 100644 index 000000000..59536ab7c --- /dev/null +++ b/ios/Pods/MWPhotoBrowser/MWPhotoBrowser/Classes/MWGridCell.h @@ -0,0 +1,24 @@ +// +// MWGridCell.h +// MWPhotoBrowser +// +// Created by Michael Waterfall on 08/10/2013. +// +// + +#import +#import "MWPhoto.h" +#import "MWGridViewController.h" +#import "PSTCollectionView.h" + +@interface MWGridCell : PSTCollectionViewCell {} + +@property (nonatomic, weak) MWGridViewController *gridController; +@property (nonatomic) NSUInteger index; +@property (nonatomic) id photo; +@property (nonatomic) BOOL selectionMode; +@property (nonatomic) BOOL isSelected; + +- (void)displayImage; + +@end diff --git a/ios/Pods/MWPhotoBrowser/MWPhotoBrowser/Classes/MWGridCell.m b/ios/Pods/MWPhotoBrowser/MWPhotoBrowser/Classes/MWGridCell.m new file mode 100644 index 000000000..ecc1d7c33 --- /dev/null +++ b/ios/Pods/MWPhotoBrowser/MWPhotoBrowser/Classes/MWGridCell.m @@ -0,0 +1,223 @@ +// +// MWGridCell.m +// MWPhotoBrowser +// +// Created by Michael Waterfall on 08/10/2013. +// +// + +#import "MWGridCell.h" +#import "MWCommon.h" +#import "MWPhotoBrowserPrivate.h" +#import "DACircularProgressView.h" + +@interface MWGridCell () { + + UIImageView *_imageView; + UIImageView *_loadingError; + DACircularProgressView *_loadingIndicator; + UIButton *_selectedButton; + +} + +@end + +@implementation MWGridCell + +- (id)initWithFrame:(CGRect)frame { + if ((self = [super initWithFrame:frame])) { + + // Grey background + self.backgroundColor = [UIColor colorWithWhite:0.12 alpha:1]; + + // Image + _imageView = [UIImageView new]; + _imageView.frame = self.bounds; + _imageView.contentMode = UIViewContentModeScaleAspectFill; + _imageView.clipsToBounds = YES; + _imageView.autoresizesSubviews = UIViewAutoresizingFlexibleHeight | UIViewAutoresizingFlexibleWidth; + [self addSubview:_imageView]; + + // Selection button + _selectedButton = [UIButton buttonWithType:UIButtonTypeCustom]; + _selectedButton.contentMode = UIViewContentModeTopRight; + _selectedButton.adjustsImageWhenHighlighted = NO; + [_selectedButton setImage:nil forState:UIControlStateNormal]; + [_selectedButton setImage:[UIImage imageNamed:@"MWPhotoBrowser.bundle/images/ImageSelectedSmallOff.png"] forState:UIControlStateNormal]; + [_selectedButton setImage:[UIImage imageNamed:@"MWPhotoBrowser.bundle/images/ImageSelectedSmallOn.png"] forState:UIControlStateSelected]; + [_selectedButton addTarget:self action:@selector(selectionButtonPressed) forControlEvents:UIControlEventTouchDown]; + _selectedButton.hidden = YES; + _selectedButton.frame = CGRectMake(0, 0, 44, 44); + [self addSubview:_selectedButton]; + + // Loading indicator + _loadingIndicator = [[DACircularProgressView alloc] initWithFrame:CGRectMake(0, 0, 40.0f, 40.0f)]; + _loadingIndicator.userInteractionEnabled = NO; + if (SYSTEM_VERSION_GREATER_THAN_OR_EQUAL_TO(@"7")) { + _loadingIndicator.thicknessRatio = 0.1; + _loadingIndicator.roundedCorners = NO; + } else { + _loadingIndicator.thicknessRatio = 0.2; + _loadingIndicator.roundedCorners = YES; + } + [self addSubview:_loadingIndicator]; + + // Listen for photo loading notifications + [[NSNotificationCenter defaultCenter] addObserver:self + selector:@selector(setProgressFromNotification:) + name:MWPHOTO_PROGRESS_NOTIFICATION + object:nil]; + [[NSNotificationCenter defaultCenter] addObserver:self + selector:@selector(handleMWPhotoLoadingDidEndNotification:) + name:MWPHOTO_LOADING_DID_END_NOTIFICATION + object:nil]; + + } + return self; +} + +- (void)dealloc { + [[NSNotificationCenter defaultCenter] removeObserver:self]; +} + +#pragma mark - View + +- (void)layoutSubviews { + [super layoutSubviews]; + _imageView.frame = self.bounds; + _loadingIndicator.frame = CGRectMake(floorf((self.bounds.size.width - _loadingIndicator.frame.size.width) / 2.), + floorf((self.bounds.size.height - _loadingIndicator.frame.size.height) / 2), + _loadingIndicator.frame.size.width, + _loadingIndicator.frame.size.height); + _selectedButton.frame = CGRectMake(self.bounds.size.width - _selectedButton.frame.size.width - 0, + 0, _selectedButton.frame.size.width, _selectedButton.frame.size.height); +} + +#pragma mark - Cell + +- (void)prepareForReuse { + _photo = nil; + _gridController = nil; + _imageView.image = nil; + _loadingIndicator.progress = 0; + _selectedButton.hidden = YES; + [self hideImageFailure]; + [super prepareForReuse]; +} + +#pragma mark - Image Handling + +- (void)setPhoto:(id )photo { + _photo = photo; + if (_photo) { + if (![_photo underlyingImage]) { + [self showLoadingIndicator]; + } else { + [self hideLoadingIndicator]; + } + } else { + [self showImageFailure]; + } +} + +- (void)displayImage { + _imageView.image = [_photo underlyingImage]; + _selectedButton.hidden = !_selectionMode; + [self hideImageFailure]; +} + +#pragma mark - Selection + +- (void)setSelectionMode:(BOOL)selectionMode { + _selectionMode = selectionMode; +} + +- (void)setIsSelected:(BOOL)isSelected { + _isSelected = isSelected; + _selectedButton.selected = isSelected; +} + +- (void)selectionButtonPressed { + _selectedButton.selected = !_selectedButton.selected; + [_gridController.browser setPhotoSelected:_selectedButton.selected atIndex:_index]; +} + +#pragma mark - Touches + +- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event { + _imageView.alpha = 0.6; + [super touchesBegan:touches withEvent:event]; +} + +- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event { + _imageView.alpha = 1; + [super touchesEnded:touches withEvent:event]; +} + +- (void)touchesCancelled:(NSSet *)touches withEvent:(UIEvent *)event { + _imageView.alpha = 1; + [super touchesCancelled:touches withEvent:event]; +} + +#pragma mark Indicators + +- (void)hideLoadingIndicator { + _loadingIndicator.hidden = YES; +} + +- (void)showLoadingIndicator { + _loadingIndicator.progress = 0; + _loadingIndicator.hidden = NO; + [self hideImageFailure]; +} + +- (void)showImageFailure { + if (!_loadingError) { + _loadingError = [UIImageView new]; + _loadingError.image = [UIImage imageNamed:@"MWPhotoBrowser.bundle/images/ImageError.png"]; + _loadingError.userInteractionEnabled = NO; + [_loadingError sizeToFit]; + [self addSubview:_loadingError]; + } + [self hideLoadingIndicator]; + _imageView.image = nil; + _loadingError.frame = CGRectMake(floorf((self.bounds.size.width - _loadingError.frame.size.width) / 2.), + floorf((self.bounds.size.height - _loadingError.frame.size.height) / 2), + _loadingError.frame.size.width, + _loadingError.frame.size.height); +} + +- (void)hideImageFailure { + if (_loadingError) { + [_loadingError removeFromSuperview]; + _loadingError = nil; + } +} + +#pragma mark - Notifications + +- (void)setProgressFromNotification:(NSNotification *)notification { + NSDictionary *dict = [notification object]; + id photoWithProgress = [dict objectForKey:@"photo"]; + if (photoWithProgress == _photo) { + // NSLog(@"%f", [[dict valueForKey:@"progress"] floatValue]); + float progress = [[dict valueForKey:@"progress"] floatValue]; + _loadingIndicator.progress = MAX(MIN(1, progress), 0); + } +} + +- (void)handleMWPhotoLoadingDidEndNotification:(NSNotification *)notification { + id photo = [notification object]; + if (photo == _photo) { + if ([photo underlyingImage]) { + // Successful load + [self displayImage]; + } else { + // Failed to load + [self showImageFailure]; + } + [self hideLoadingIndicator]; + } +} + +@end diff --git a/ios/Pods/MWPhotoBrowser/MWPhotoBrowser/Classes/MWGridViewController.h b/ios/Pods/MWPhotoBrowser/MWPhotoBrowser/Classes/MWGridViewController.h new file mode 100644 index 000000000..5dc238b9d --- /dev/null +++ b/ios/Pods/MWPhotoBrowser/MWPhotoBrowser/Classes/MWGridViewController.h @@ -0,0 +1,19 @@ +// +// MWGridViewController.h +// MWPhotoBrowser +// +// Created by Michael Waterfall on 08/10/2013. +// +// + +#import +#import "MWPhotoBrowser.h" +#import "PSTCollectionView.h" + +@interface MWGridViewController : PSTCollectionViewController {} + +@property (nonatomic, assign) MWPhotoBrowser *browser; +@property (nonatomic) BOOL selectionMode; +@property (nonatomic) CGPoint initialContentOffset; + +@end diff --git a/ios/Pods/MWPhotoBrowser/MWPhotoBrowser/Classes/MWGridViewController.m b/ios/Pods/MWPhotoBrowser/MWPhotoBrowser/Classes/MWGridViewController.m new file mode 100644 index 000000000..b7bae6222 --- /dev/null +++ b/ios/Pods/MWPhotoBrowser/MWPhotoBrowser/Classes/MWGridViewController.m @@ -0,0 +1,205 @@ +// +// MWGridViewController.m +// MWPhotoBrowser +// +// Created by Michael Waterfall on 08/10/2013. +// +// + +#import "MWGridViewController.h" +#import "MWGridCell.h" +#import "MWPhotoBrowserPrivate.h" +#import "MWCommon.h" + +@interface MWGridViewController () { + + // Store margins for current setup + CGFloat _margin, _gutter, _marginL, _gutterL, _columns, _columnsL; + +} + +@end + +@implementation MWGridViewController + +- (id)init { + if ((self = [super initWithCollectionViewLayout:[PSTCollectionViewFlowLayout new]])) { + + // Defaults + _columns = 3, _columnsL = 4; + _margin = 0, _gutter = 1; + _marginL = 0, _gutterL = 1; + + // For pixel perfection... + if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad) { + // iPad + _columns = 6, _columnsL = 8; + _margin = 1, _gutter = 2; + _marginL = 1, _gutterL = 2; + } else if ([UIScreen mainScreen].bounds.size.height == 480) { + // iPhone 3.5 inch + _columns = 3, _columnsL = 4; + _margin = 0, _gutter = 1; + _marginL = 1, _gutterL = 2; + } else { + // iPhone 4 inch + _columns = 3, _columnsL = 5; + _margin = 0, _gutter = 1; + _marginL = 0, _gutterL = 2; + } + + _initialContentOffset = CGPointMake(0, CGFLOAT_MAX); + + } + return self; +} + +#pragma mark - View + +- (void)viewDidLoad { + [super viewDidLoad]; + [self.collectionView registerClass:[MWGridCell class] forCellWithReuseIdentifier:@"GridCell"]; + self.collectionView.alwaysBounceVertical = YES; + self.collectionView.backgroundColor = [UIColor blackColor]; +} + +- (void)viewWillDisappear:(BOOL)animated { + // Cancel outstanding loading + NSArray *visibleCells = [self.collectionView visibleCells]; + if (visibleCells) { + for (MWGridCell *cell in visibleCells) { + [cell.photo cancelAnyLoading]; + } + } + [super viewWillDisappear:animated]; +} + +- (void)viewWillLayoutSubviews { + [super viewWillLayoutSubviews]; + [self performLayout]; +} + +- (void)viewDidLayoutSubviews { + [super viewDidLayoutSubviews]; + + // Move to previous content offset + if (_initialContentOffset.y != CGFLOAT_MAX) { + self.collectionView.contentOffset = _initialContentOffset; + } + CGPoint currentContentOffset = self.collectionView.contentOffset; + + // Get scroll position to have the current photo on screen + if (_browser.numberOfPhotos > 0) { + NSIndexPath *currentPhotoIndexPath = [NSIndexPath indexPathForItem:_browser.currentIndex inSection:0]; + [self.collectionView scrollToItemAtIndexPath:currentPhotoIndexPath atScrollPosition:PSTCollectionViewScrollPositionNone animated:NO]; + } + CGPoint offsetToShowCurrent = self.collectionView.contentOffset; + + // Only commit to using the scrolled position if it differs from the initial content offset + if (!CGPointEqualToPoint(offsetToShowCurrent, currentContentOffset)) { + // Use offset to show current + self.collectionView.contentOffset = offsetToShowCurrent; + } else { + // Stick with initial + self.collectionView.contentOffset = currentContentOffset; + } + +} + +- (void)performLayout { + UINavigationBar *navBar = self.navigationController.navigationBar; + CGFloat yAdjust = 0; +#if __IPHONE_OS_VERSION_MIN_REQUIRED < __IPHONE_7_0 + if (SYSTEM_VERSION_LESS_THAN(@"7") && !self.browser.wantsFullScreenLayout) yAdjust = -20; +#endif + self.collectionView.contentInset = UIEdgeInsetsMake(navBar.frame.origin.y + navBar.frame.size.height + [self getGutter] + yAdjust, 0, 0, 0); +} + +- (void)willAnimateRotationToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation duration:(NSTimeInterval)duration { + [self.collectionView reloadData]; + [self performLayout]; // needed for iOS 5 & 6 +} + +#pragma mark - Layout + +- (CGFloat)getColumns { + if ((UIInterfaceOrientationIsPortrait(self.interfaceOrientation))) { + return _columns; + } else { + return _columnsL; + } +} + +- (CGFloat)getMargin { + if ((UIInterfaceOrientationIsPortrait(self.interfaceOrientation))) { + return _margin; + } else { + return _marginL; + } +} + +- (CGFloat)getGutter { + if ((UIInterfaceOrientationIsPortrait(self.interfaceOrientation))) { + return _gutter; + } else { + return _gutterL; + } +} + +#pragma mark - Collection View + +- (NSInteger)collectionView:(UICollectionView *)view numberOfItemsInSection:(NSInteger)section { + return [_browser numberOfPhotos]; +} + +- (PSTCollectionViewCell *)collectionView:(PSTCollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath { + MWGridCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:@"GridCell" forIndexPath:indexPath]; + if (!cell) { + cell = [[MWGridCell alloc] init]; + } + id photo = [_browser thumbPhotoAtIndex:indexPath.row]; + cell.photo = photo; + cell.gridController = self; + cell.selectionMode = _selectionMode; + cell.isSelected = [_browser photoIsSelectedAtIndex:indexPath.row]; + cell.index = indexPath.row; + UIImage *img = [_browser imageForPhoto:photo]; + if (img) { + [cell displayImage]; + } else { + [photo loadUnderlyingImageAndNotify]; + } + return cell; +} + +- (void)collectionView:(PSTCollectionView *)collectionView didSelectItemAtIndexPath:(NSIndexPath *)indexPath { + [_browser setCurrentPhotoIndex:indexPath.row]; + [_browser hideGrid]; +} + +- (void)collectionView:(PSTCollectionView *)collectionView didEndDisplayingCell:(PSTCollectionViewCell *)cell forItemAtIndexPath:(NSIndexPath *)indexPath { + [((MWGridCell *)cell).photo cancelAnyLoading]; +} + +- (CGSize)collectionView:(PSTCollectionView *)collectionView layout:(PSTCollectionViewLayout*)collectionViewLayout sizeForItemAtIndexPath:(NSIndexPath *)indexPath { + CGFloat margin = [self getMargin]; + CGFloat gutter = [self getGutter]; + CGFloat columns = [self getColumns]; + CGFloat value = floorf(((self.view.bounds.size.width - (columns - 1) * gutter - 2 * margin) / columns)); + return CGSizeMake(value, value); +} + +- (CGFloat)collectionView:(PSTCollectionView *)collectionView layout:(PSTCollectionViewLayout*)collectionViewLayout minimumInteritemSpacingForSectionAtIndex:(NSInteger)section { + return [self getGutter]; +} + +- (CGFloat)collectionView:(PSTCollectionView *)collectionView layout:(PSTCollectionViewLayout*)collectionViewLayout minimumLineSpacingForSectionAtIndex:(NSInteger)section { + return [self getGutter]; +} + +- (UIEdgeInsets)collectionView:(PSTCollectionView *)collectionView layout:(PSTCollectionViewLayout*)collectionViewLayout insetForSectionAtIndex:(NSInteger)section { + CGFloat margin = [self getMargin]; + return UIEdgeInsetsMake(margin, margin, margin, margin); +} + +@end diff --git a/ios/Pods/MWPhotoBrowser/MWPhotoBrowser/Classes/MWPhoto.h b/ios/Pods/MWPhotoBrowser/MWPhotoBrowser/Classes/MWPhoto.h new file mode 100644 index 000000000..7bfd960aa --- /dev/null +++ b/ios/Pods/MWPhotoBrowser/MWPhotoBrowser/Classes/MWPhoto.h @@ -0,0 +1,32 @@ +// +// MWPhoto.h +// MWPhotoBrowser +// +// Created by Michael Waterfall on 17/10/2010. +// Copyright 2010 d3i. All rights reserved. +// + +#import +#import "MWPhotoProtocol.h" + +// This class models a photo/image and it's caption +// If you want to handle photos, caching, decompression +// yourself then you can simply ensure your custom data model +// conforms to MWPhotoProtocol +@interface MWPhoto : NSObject + +@property (nonatomic, strong) NSString *caption; +@property (nonatomic, readonly) UIImage *image; +@property (nonatomic, readonly) NSURL *photoURL; +@property (nonatomic, readonly) NSString *filePath __attribute__((deprecated("Use photoURL"))); // Depreciated + ++ (MWPhoto *)photoWithImage:(UIImage *)image; ++ (MWPhoto *)photoWithFilePath:(NSString *)path __attribute__((deprecated("Use photoWithURL: with a file URL"))); // Depreciated ++ (MWPhoto *)photoWithURL:(NSURL *)url; + +- (id)initWithImage:(UIImage *)image; +- (id)initWithURL:(NSURL *)url; +- (id)initWithFilePath:(NSString *)path __attribute__((deprecated("Use initWithURL: with a file URL"))); // Depreciated + +@end + diff --git a/ios/Pods/MWPhotoBrowser/MWPhotoBrowser/Classes/MWPhoto.m b/ios/Pods/MWPhotoBrowser/MWPhotoBrowser/Classes/MWPhoto.m new file mode 100644 index 000000000..de8201a26 --- /dev/null +++ b/ios/Pods/MWPhotoBrowser/MWPhotoBrowser/Classes/MWPhoto.m @@ -0,0 +1,219 @@ +// +// MWPhoto.m +// MWPhotoBrowser +// +// Created by Michael Waterfall on 17/10/2010. +// Copyright 2010 d3i. All rights reserved. +// + +#import "MWPhoto.h" +#import "MWPhotoBrowser.h" +#import "SDWebImageDecoder.h" +#import "SDWebImageManager.h" +#import "SDWebImageOperation.h" +#import + +@interface MWPhoto () { + + BOOL _loadingInProgress; + id _webImageOperation; + +} + +- (void)imageLoadingComplete; + +@end + +@implementation MWPhoto + +@synthesize underlyingImage = _underlyingImage; // synth property from protocol + +#pragma mark - Class Methods + ++ (MWPhoto *)photoWithImage:(UIImage *)image { + return [[MWPhoto alloc] initWithImage:image]; +} + +// Deprecated ++ (MWPhoto *)photoWithFilePath:(NSString *)path { + return [MWPhoto photoWithURL:[NSURL fileURLWithPath:path]]; +} + ++ (MWPhoto *)photoWithURL:(NSURL *)url { + return [[MWPhoto alloc] initWithURL:url]; +} + +#pragma mark - Init + +- (id)initWithImage:(UIImage *)image { + if ((self = [super init])) { + _image = image; + } + return self; +} + +// Deprecated +- (id)initWithFilePath:(NSString *)path { + if ((self = [super init])) { + _photoURL = [NSURL fileURLWithPath:path]; + } + return self; +} + +- (id)initWithURL:(NSURL *)url { + if ((self = [super init])) { + _photoURL = [url copy]; + } + return self; +} + +#pragma mark - MWPhoto Protocol Methods + +- (UIImage *)underlyingImage { + return _underlyingImage; +} + +- (void)loadUnderlyingImageAndNotify { + NSAssert([[NSThread currentThread] isMainThread], @"This method must be called on the main thread."); + if (_loadingInProgress) return; + _loadingInProgress = YES; + @try { + if (self.underlyingImage) { + [self imageLoadingComplete]; + } else { + [self performLoadUnderlyingImageAndNotify]; + } + } + @catch (NSException *exception) { + self.underlyingImage = nil; + _loadingInProgress = NO; + [self imageLoadingComplete]; + } + @finally { + } +} + +// Set the underlyingImage +- (void)performLoadUnderlyingImageAndNotify { + + // Get underlying image + if (_image) { + + // We have UIImage! + self.underlyingImage = _image; + [self imageLoadingComplete]; + + } else if (_photoURL) { + + // Check what type of url it is + if ([[[_photoURL scheme] lowercaseString] isEqualToString:@"assets-library"]) { + + // Load from asset library async + dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ + @autoreleasepool { + @try { + ALAssetsLibrary *assetslibrary = [[ALAssetsLibrary alloc] init]; + [assetslibrary assetForURL:_photoURL + resultBlock:^(ALAsset *asset){ + ALAssetRepresentation *rep = [asset defaultRepresentation]; + CGImageRef iref = [rep fullScreenImage]; + if (iref) { + self.underlyingImage = [UIImage imageWithCGImage:iref]; + } + [self performSelectorOnMainThread:@selector(imageLoadingComplete) withObject:nil waitUntilDone:NO]; + } + failureBlock:^(NSError *error) { + self.underlyingImage = nil; + MWLog(@"Photo from asset library error: %@",error); + [self performSelectorOnMainThread:@selector(imageLoadingComplete) withObject:nil waitUntilDone:NO]; + }]; + } @catch (NSException *e) { + MWLog(@"Photo from asset library error: %@", e); + [self performSelectorOnMainThread:@selector(imageLoadingComplete) withObject:nil waitUntilDone:NO]; + } + } + }); + + } else if ([_photoURL isFileReferenceURL]) { + + // Load from local file async + dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ + @autoreleasepool { + @try { + self.underlyingImage = [UIImage imageWithContentsOfFile:_photoURL.path]; + if (!_underlyingImage) { + MWLog(@"Error loading photo from path: %@", _photoURL.path); + } + } @finally { + [self performSelectorOnMainThread:@selector(imageLoadingComplete) withObject:nil waitUntilDone:NO]; + } + } + }); + + } else { + + // Load async from web (using SDWebImage) + @try { + SDWebImageManager *manager = [SDWebImageManager sharedManager]; + _webImageOperation = [manager downloadImageWithURL:_photoURL + options:0 + progress:^(NSInteger receivedSize, NSInteger expectedSize) { + if (expectedSize > 0) { + float progress = receivedSize / (float)expectedSize; + NSDictionary* dict = [NSDictionary dictionaryWithObjectsAndKeys: + [NSNumber numberWithFloat:progress], @"progress", + self, @"photo", nil]; + [[NSNotificationCenter defaultCenter] postNotificationName:MWPHOTO_PROGRESS_NOTIFICATION object:dict]; + } + } + completed:^(UIImage *image, NSError *error, SDImageCacheType cacheType, BOOL finished, NSURL *imageURL) { + if (error) { + MWLog(@"SDWebImage failed to download image: %@", error); + } + _webImageOperation = nil; + self.underlyingImage = image; + [self imageLoadingComplete]; + }]; + } @catch (NSException *e) { + MWLog(@"Photo from web: %@", e); + _webImageOperation = nil; + [self imageLoadingComplete]; + } + + } + + } else { + + // Failed - no source + @throw [NSException exceptionWithName:nil reason:nil userInfo:nil]; + + } +} + +// Release if we can get it again from path or url +- (void)unloadUnderlyingImage { + _loadingInProgress = NO; + self.underlyingImage = nil; +} + +- (void)imageLoadingComplete { + NSAssert([[NSThread currentThread] isMainThread], @"This method must be called on the main thread."); + // Complete so notify + _loadingInProgress = NO; + // Notify on next run loop + [self performSelector:@selector(postCompleteNotification) withObject:nil afterDelay:0]; +} + +- (void)postCompleteNotification { + [[NSNotificationCenter defaultCenter] postNotificationName:MWPHOTO_LOADING_DID_END_NOTIFICATION + object:self]; +} + +- (void)cancelAnyLoading { + if (_webImageOperation) { + [_webImageOperation cancel]; + _loadingInProgress = NO; + } +} + +@end diff --git a/ios/Pods/MWPhotoBrowser/MWPhotoBrowser/Classes/MWPhotoBrowser.h b/ios/Pods/MWPhotoBrowser/MWPhotoBrowser/Classes/MWPhotoBrowser.h new file mode 100644 index 000000000..728d5cf45 --- /dev/null +++ b/ios/Pods/MWPhotoBrowser/MWPhotoBrowser/Classes/MWPhotoBrowser.h @@ -0,0 +1,71 @@ +// +// MWPhotoBrowser.h +// MWPhotoBrowser +// +// Created by Michael Waterfall on 14/10/2010. +// Copyright 2010 d3i. All rights reserved. +// + +#import +#import +#import "MWPhoto.h" +#import "MWPhotoProtocol.h" +#import "MWCaptionView.h" + +// Debug Logging +#if 0 // Set to 1 to enable debug logging +#define MWLog(x, ...) NSLog(x, ## __VA_ARGS__); +#else +#define MWLog(x, ...) +#endif + +@class MWPhotoBrowser; + +@protocol MWPhotoBrowserDelegate + +- (NSUInteger)numberOfPhotosInPhotoBrowser:(MWPhotoBrowser *)photoBrowser; +- (id )photoBrowser:(MWPhotoBrowser *)photoBrowser photoAtIndex:(NSUInteger)index; + +@optional + +- (id )photoBrowser:(MWPhotoBrowser *)photoBrowser thumbPhotoAtIndex:(NSUInteger)index; +- (MWCaptionView *)photoBrowser:(MWPhotoBrowser *)photoBrowser captionViewForPhotoAtIndex:(NSUInteger)index; +- (NSString *)photoBrowser:(MWPhotoBrowser *)photoBrowser titleForPhotoAtIndex:(NSUInteger)index; +- (void)photoBrowser:(MWPhotoBrowser *)photoBrowser didDisplayPhotoAtIndex:(NSUInteger)index; +- (void)photoBrowser:(MWPhotoBrowser *)photoBrowser actionButtonPressedForPhotoAtIndex:(NSUInteger)index; +- (BOOL)photoBrowser:(MWPhotoBrowser *)photoBrowser isPhotoSelectedAtIndex:(NSUInteger)index; +- (void)photoBrowser:(MWPhotoBrowser *)photoBrowser photoAtIndex:(NSUInteger)index selectedChanged:(BOOL)selected; +- (void)photoBrowserDidFinishModalPresentation:(MWPhotoBrowser *)photoBrowser; + +@end + +@interface MWPhotoBrowser : UIViewController + +@property (nonatomic, weak) IBOutlet id delegate; +@property (nonatomic) BOOL zoomPhotosToFill; +@property (nonatomic) BOOL displayNavArrows; +@property (nonatomic) BOOL displayActionButton; +@property (nonatomic) BOOL displaySelectionButtons; +@property (nonatomic) BOOL alwaysShowControls; +@property (nonatomic) BOOL enableGrid; +@property (nonatomic) BOOL enableSwipeToDismiss; +@property (nonatomic) BOOL startOnGrid; +@property (nonatomic) NSUInteger delayToHideElements; +@property (nonatomic, readonly) NSUInteger currentIndex; + +// Init +- (id)initWithPhotos:(NSArray *)photosArray __attribute__((deprecated("Use initWithDelegate: instead"))); // Depreciated +- (id)initWithDelegate:(id )delegate; + +// Reloads the photo browser and refetches data +- (void)reloadData; + +// Set page that photo browser starts on +- (void)setCurrentPhotoIndex:(NSUInteger)index; +- (void)setInitialPageIndex:(NSUInteger)index __attribute__((deprecated("Use setCurrentPhotoIndex: instead"))); // Depreciated + +// Navigation +- (void)showNextPhotoAnimated:(BOOL)animated; +- (void)showPreviousPhotoAnimated:(BOOL)animated; + +@end diff --git a/ios/Pods/MWPhotoBrowser/MWPhotoBrowser/Classes/MWPhotoBrowser.m b/ios/Pods/MWPhotoBrowser/MWPhotoBrowser/Classes/MWPhotoBrowser.m new file mode 100644 index 000000000..456676e35 --- /dev/null +++ b/ios/Pods/MWPhotoBrowser/MWPhotoBrowser/Classes/MWPhotoBrowser.m @@ -0,0 +1,1665 @@ +// +// MWPhotoBrowser.m +// MWPhotoBrowser +// +// Created by Michael Waterfall on 14/10/2010. +// Copyright 2010 d3i. All rights reserved. +// + +#import +#import "MWCommon.h" +#import "MWPhotoBrowser.h" +#import "MWPhotoBrowserPrivate.h" +#import "SDImageCache.h" + +#define PADDING 10 +#define ACTION_SHEET_OLD_ACTIONS 2000 + +@implementation MWPhotoBrowser + +#pragma mark - Init + +- (id)init { + if ((self = [super init])) { + [self _initialisation]; + } + return self; +} + +- (id)initWithDelegate:(id )delegate { + if ((self = [self init])) { + _delegate = delegate; + } + return self; +} + +- (id)initWithPhotos:(NSArray *)photosArray { + if ((self = [self init])) { + _depreciatedPhotoData = photosArray; + } + return self; +} + +- (id)initWithCoder:(NSCoder *)decoder { + if ((self = [super initWithCoder:decoder])) { + [self _initialisation]; + } + return self; +} + +- (void)_initialisation { + + // Defaults + NSNumber *isVCBasedStatusBarAppearanceNum = [[NSBundle mainBundle] objectForInfoDictionaryKey:@"UIViewControllerBasedStatusBarAppearance"]; + if (isVCBasedStatusBarAppearanceNum) { + _isVCBasedStatusBarAppearance = isVCBasedStatusBarAppearanceNum.boolValue; + } else { + _isVCBasedStatusBarAppearance = YES; // default + } +#if __IPHONE_OS_VERSION_MIN_REQUIRED < __IPHONE_7_0 + if (SYSTEM_VERSION_LESS_THAN(@"7")) self.wantsFullScreenLayout = YES; +#endif + self.hidesBottomBarWhenPushed = YES; + _hasBelongedToViewController = NO; + _photoCount = NSNotFound; + _previousLayoutBounds = CGRectZero; + _currentPageIndex = 0; + _previousPageIndex = NSUIntegerMax; + _displayActionButton = YES; + _displayNavArrows = NO; + _zoomPhotosToFill = YES; + _performingLayout = NO; // Reset on view did appear + _rotating = NO; + _viewIsActive = NO; + _enableGrid = YES; + _startOnGrid = NO; + _enableSwipeToDismiss = YES; + _delayToHideElements = 5; + _visiblePages = [[NSMutableSet alloc] init]; + _recycledPages = [[NSMutableSet alloc] init]; + _photos = [[NSMutableArray alloc] init]; + _thumbPhotos = [[NSMutableArray alloc] init]; + _currentGridContentOffset = CGPointMake(0, CGFLOAT_MAX); + _didSavePreviousStateOfNavBar = NO; + if ([self respondsToSelector:@selector(automaticallyAdjustsScrollViewInsets)]){ + self.automaticallyAdjustsScrollViewInsets = NO; + } + + // Listen for MWPhoto notifications + [[NSNotificationCenter defaultCenter] addObserver:self + selector:@selector(handleMWPhotoLoadingDidEndNotification:) + name:MWPHOTO_LOADING_DID_END_NOTIFICATION + object:nil]; + +} + +- (void)dealloc { + _pagingScrollView.delegate = nil; + [[NSNotificationCenter defaultCenter] removeObserver:self]; + [self releaseAllUnderlyingPhotos:NO]; + [[SDImageCache sharedImageCache] clearMemory]; // clear memory +} + +- (void)releaseAllUnderlyingPhotos:(BOOL)preserveCurrent { + // Create a copy in case this array is modified while we are looping through + // Release photos + NSArray *copy = [_photos copy]; + for (id p in copy) { + if (p != [NSNull null]) { + if (preserveCurrent && p == [self photoAtIndex:self.currentIndex]) { + continue; // skip current + } + [p unloadUnderlyingImage]; + } + } + // Release thumbs + copy = [_thumbPhotos copy]; + for (id p in copy) { + if (p != [NSNull null]) { + [p unloadUnderlyingImage]; + } + } +} + +- (void)didReceiveMemoryWarning { + + // Release any cached data, images, etc that aren't in use. + [self releaseAllUnderlyingPhotos:YES]; + [_recycledPages removeAllObjects]; + + // Releases the view if it doesn't have a superview. + [super didReceiveMemoryWarning]; + +} + +#pragma mark - View Loading + +// Implement viewDidLoad to do additional setup after loading the view, typically from a nib. +- (void)viewDidLoad { + + // Validate grid settings + if (_startOnGrid) _enableGrid = YES; + if (_enableGrid) { + _enableGrid = [_delegate respondsToSelector:@selector(photoBrowser:thumbPhotoAtIndex:)]; + } + if (!_enableGrid) _startOnGrid = NO; + + // View + self.view.backgroundColor = [UIColor blackColor]; + self.view.clipsToBounds = YES; + + // Setup paging scrolling view + CGRect pagingScrollViewFrame = [self frameForPagingScrollView]; + _pagingScrollView = [[UIScrollView alloc] initWithFrame:pagingScrollViewFrame]; + _pagingScrollView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight; + _pagingScrollView.pagingEnabled = YES; + _pagingScrollView.delegate = self; + _pagingScrollView.showsHorizontalScrollIndicator = NO; + _pagingScrollView.showsVerticalScrollIndicator = NO; + _pagingScrollView.backgroundColor = [UIColor blackColor]; + _pagingScrollView.contentSize = [self contentSizeForPagingScrollView]; + [self.view addSubview:_pagingScrollView]; + + // Toolbar + _toolbar = [[UIToolbar alloc] initWithFrame:[self frameForToolbarAtOrientation:self.interfaceOrientation]]; + _toolbar.tintColor = SYSTEM_VERSION_GREATER_THAN_OR_EQUAL_TO(@"7") ? [UIColor whiteColor] : nil; + if ([_toolbar respondsToSelector:@selector(setBarTintColor:)]) { + _toolbar.barTintColor = nil; + } + if ([[UIToolbar class] respondsToSelector:@selector(appearance)]) { + [_toolbar setBackgroundImage:nil forToolbarPosition:UIToolbarPositionAny barMetrics:UIBarMetricsDefault]; + [_toolbar setBackgroundImage:nil forToolbarPosition:UIToolbarPositionAny barMetrics:UIBarMetricsLandscapePhone]; + } + _toolbar.barStyle = UIBarStyleBlackTranslucent; + _toolbar.autoresizingMask = UIViewAutoresizingFlexibleTopMargin | UIViewAutoresizingFlexibleWidth; + + // Toolbar Items + if (self.displayNavArrows) { + NSString *arrowPathFormat; + if (SYSTEM_VERSION_GREATER_THAN_OR_EQUAL_TO(@"7")) { + arrowPathFormat = @"MWPhotoBrowser.bundle/images/UIBarButtonItemArrowOutline%@.png"; + } else { + arrowPathFormat = @"MWPhotoBrowser.bundle/images/UIBarButtonItemArrow%@.png"; + } + _previousButton = [[UIBarButtonItem alloc] initWithImage:[UIImage imageNamed:[NSString stringWithFormat:arrowPathFormat, @"Left"]] style:UIBarButtonItemStylePlain target:self action:@selector(gotoPreviousPage)]; + _nextButton = [[UIBarButtonItem alloc] initWithImage:[UIImage imageNamed:[NSString stringWithFormat:arrowPathFormat, @"Right"]] style:UIBarButtonItemStylePlain target:self action:@selector(gotoNextPage)]; + } + if (self.displayActionButton) { + _actionButton = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemAction target:self action:@selector(actionButtonPressed:)]; + } + + // Update + [self reloadData]; + + // Swipe to dismiss + if (_enableSwipeToDismiss) { + UISwipeGestureRecognizer *swipeGesture = [[UISwipeGestureRecognizer alloc] initWithTarget:self action:@selector(doneButtonPressed:)]; + swipeGesture.direction = UISwipeGestureRecognizerDirectionDown | UISwipeGestureRecognizerDirectionUp; + [self.view addGestureRecognizer:swipeGesture]; + } + + // Super + [super viewDidLoad]; + +} + +- (void)performLayout { + + // Setup + _performingLayout = YES; + NSUInteger numberOfPhotos = [self numberOfPhotos]; + + // Setup pages + [_visiblePages removeAllObjects]; + [_recycledPages removeAllObjects]; + + // Navigation buttons + if ([self.navigationController.viewControllers objectAtIndex:0] == self) { + // We're first on stack so show done button + _doneButton = [[UIBarButtonItem alloc] initWithTitle:NSLocalizedString(@"Done", nil) style:UIBarButtonItemStylePlain target:self action:@selector(doneButtonPressed:)]; + // Set appearance + if ([UIBarButtonItem respondsToSelector:@selector(appearance)]) { + [_doneButton setBackgroundImage:nil forState:UIControlStateNormal barMetrics:UIBarMetricsDefault]; + [_doneButton setBackgroundImage:nil forState:UIControlStateNormal barMetrics:UIBarMetricsLandscapePhone]; + [_doneButton setBackgroundImage:nil forState:UIControlStateHighlighted barMetrics:UIBarMetricsDefault]; + [_doneButton setBackgroundImage:nil forState:UIControlStateHighlighted barMetrics:UIBarMetricsLandscapePhone]; + [_doneButton setTitleTextAttributes:[NSDictionary dictionary] forState:UIControlStateNormal]; + [_doneButton setTitleTextAttributes:[NSDictionary dictionary] forState:UIControlStateHighlighted]; + } + self.navigationItem.rightBarButtonItem = _doneButton; + } else { + // We're not first so show back button + UIViewController *previousViewController = [self.navigationController.viewControllers objectAtIndex:self.navigationController.viewControllers.count-2]; + NSString *backButtonTitle = previousViewController.navigationItem.backBarButtonItem ? previousViewController.navigationItem.backBarButtonItem.title : previousViewController.title; + UIBarButtonItem *newBackButton = [[UIBarButtonItem alloc] initWithTitle:backButtonTitle style:UIBarButtonItemStylePlain target:nil action:nil]; + // Appearance + if ([UIBarButtonItem respondsToSelector:@selector(appearance)]) { + [newBackButton setBackButtonBackgroundImage:nil forState:UIControlStateNormal barMetrics:UIBarMetricsDefault]; + [newBackButton setBackButtonBackgroundImage:nil forState:UIControlStateNormal barMetrics:UIBarMetricsLandscapePhone]; + [newBackButton setBackButtonBackgroundImage:nil forState:UIControlStateHighlighted barMetrics:UIBarMetricsDefault]; + [newBackButton setBackButtonBackgroundImage:nil forState:UIControlStateHighlighted barMetrics:UIBarMetricsLandscapePhone]; + [newBackButton setTitleTextAttributes:[NSDictionary dictionary] forState:UIControlStateNormal]; + [newBackButton setTitleTextAttributes:[NSDictionary dictionary] forState:UIControlStateHighlighted]; + } + _previousViewControllerBackButton = previousViewController.navigationItem.backBarButtonItem; // remember previous + previousViewController.navigationItem.backBarButtonItem = newBackButton; + } + + // Toolbar items + BOOL hasItems = NO; + UIBarButtonItem *fixedSpace = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemFixedSpace target:self action:nil]; + fixedSpace.width = 32; // To balance action button + UIBarButtonItem *flexSpace = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemFlexibleSpace target:self action:nil]; + NSMutableArray *items = [[NSMutableArray alloc] init]; + + // Left button - Grid + if (_enableGrid) { + hasItems = YES; + NSString *buttonName = @"UIBarButtonItemGrid"; + if (SYSTEM_VERSION_LESS_THAN(@"7")) buttonName = @"UIBarButtonItemGridiOS6"; + [items addObject:[[UIBarButtonItem alloc] initWithImage:[UIImage imageNamed:[NSString stringWithFormat:@"MWPhotoBrowser.bundle/images/%@.png", buttonName]] style:UIBarButtonItemStylePlain target:self action:@selector(showGridAnimated)]]; + } else { + [items addObject:fixedSpace]; + } + + // Middle - Nav + if (_previousButton && _nextButton && numberOfPhotos > 1) { + hasItems = YES; + [items addObject:flexSpace]; + [items addObject:_previousButton]; + [items addObject:flexSpace]; + [items addObject:_nextButton]; + [items addObject:flexSpace]; + } else { + [items addObject:flexSpace]; + } + + // Right - Action + if (_actionButton && !(!hasItems && !self.navigationItem.rightBarButtonItem)) { + [items addObject:_actionButton]; + } else { + // We're not showing the toolbar so try and show in top right + if (_actionButton) + self.navigationItem.rightBarButtonItem = _actionButton; + [items addObject:fixedSpace]; + } + + // Toolbar visibility + [_toolbar setItems:items]; + BOOL hideToolbar = YES; + for (UIBarButtonItem* item in _toolbar.items) { + if (item != fixedSpace && item != flexSpace) { + hideToolbar = NO; + break; + } + } + if (hideToolbar) { + [_toolbar removeFromSuperview]; + } else { + [self.view addSubview:_toolbar]; + } + + // Update nav + [self updateNavigation]; + + // Content offset + _pagingScrollView.contentOffset = [self contentOffsetForPageAtIndex:_currentPageIndex]; + [self tilePages]; + _performingLayout = NO; + +} + +// Release any retained subviews of the main view. +- (void)viewDidUnload { + _currentPageIndex = 0; + _pagingScrollView = nil; + _visiblePages = nil; + _recycledPages = nil; + _toolbar = nil; + _previousButton = nil; + _nextButton = nil; + _progressHUD = nil; + [super viewDidUnload]; +} + +- (BOOL)presentingViewControllerPrefersStatusBarHidden { + UIViewController *presenting = self.presentingViewController; + if (presenting) { + if ([presenting isKindOfClass:[UINavigationController class]]) { + presenting = [(UINavigationController *)presenting topViewController]; + } + } else { + // We're in a navigation controller so get previous one! + if (self.navigationController && self.navigationController.viewControllers.count > 1) { + presenting = [self.navigationController.viewControllers objectAtIndex:self.navigationController.viewControllers.count-2]; + } + } + if (presenting) { + return [presenting prefersStatusBarHidden]; + } else { + return NO; + } +} + +#pragma mark - Appearance + +- (void)viewWillAppear:(BOOL)animated { + + // Super + [super viewWillAppear:animated]; + + // Status bar + if ([UIViewController instancesRespondToSelector:@selector(prefersStatusBarHidden)]) { + _leaveStatusBarAlone = [self presentingViewControllerPrefersStatusBarHidden]; + } else { + _leaveStatusBarAlone = [UIApplication sharedApplication].statusBarHidden; + } + if (CGRectEqualToRect([[UIApplication sharedApplication] statusBarFrame], CGRectZero)) { + // If the frame is zero then definitely leave it alone + _leaveStatusBarAlone = YES; + } + BOOL fullScreen = YES; +#if __IPHONE_OS_VERSION_MIN_REQUIRED < __IPHONE_7_0 + if (SYSTEM_VERSION_LESS_THAN(@"7")) fullScreen = self.wantsFullScreenLayout; +#endif + if (!_leaveStatusBarAlone && fullScreen && UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPhone) { + _previousStatusBarStyle = [[UIApplication sharedApplication] statusBarStyle]; + if (SYSTEM_VERSION_LESS_THAN(@"7")) { +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wdeprecated-declarations" + [[UIApplication sharedApplication] setStatusBarStyle:UIStatusBarStyleBlackTranslucent animated:animated]; +#pragma clang diagnostic push + } else { + [[UIApplication sharedApplication] setStatusBarStyle:UIStatusBarStyleDefault animated:animated]; + } + } + + // Navigation bar appearance + if (!_viewIsActive && [self.navigationController.viewControllers objectAtIndex:0] != self) { + [self storePreviousNavBarAppearance]; + } + [self setNavBarAppearance:animated]; + + // Update UI + [self hideControlsAfterDelay]; + + // Initial appearance + if (!_viewHasAppearedInitially) { + if (_startOnGrid) { + [self showGrid:NO]; + } + _viewHasAppearedInitially = YES; + } + +} + +- (void)viewWillDisappear:(BOOL)animated { + + // Check that we're being popped for good + if ([self.navigationController.viewControllers objectAtIndex:0] != self && + ![self.navigationController.viewControllers containsObject:self]) { + + // State + _viewIsActive = NO; + + // Bar state / appearance + [self restorePreviousNavBarAppearance:animated]; + + } + + // Controls + [self.navigationController.navigationBar.layer removeAllAnimations]; // Stop all animations on nav bar + [NSObject cancelPreviousPerformRequestsWithTarget:self]; // Cancel any pending toggles from taps + [self setControlsHidden:NO animated:NO permanent:YES]; + + // Status bar + BOOL fullScreen = YES; +#if __IPHONE_OS_VERSION_MIN_REQUIRED < __IPHONE_7_0 + if (SYSTEM_VERSION_LESS_THAN(@"7")) fullScreen = self.wantsFullScreenLayout; +#endif + if (!_leaveStatusBarAlone && fullScreen && UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPhone) { + [[UIApplication sharedApplication] setStatusBarStyle:_previousStatusBarStyle animated:animated]; + } + + // Super + [super viewWillDisappear:animated]; + +} + +- (void)viewDidAppear:(BOOL)animated { + [super viewDidAppear:animated]; + _viewIsActive = YES; +} + +- (void)willMoveToParentViewController:(UIViewController *)parent { + if (parent && _hasBelongedToViewController) { + [NSException raise:@"MWPhotoBrowser Instance Reuse" format:@"MWPhotoBrowser instances cannot be reused."]; + } +} + +- (void)didMoveToParentViewController:(UIViewController *)parent { + if (!parent) _hasBelongedToViewController = YES; +} + +#pragma mark - Nav Bar Appearance + +- (void)setNavBarAppearance:(BOOL)animated { + [self.navigationController setNavigationBarHidden:NO animated:animated]; + UINavigationBar *navBar = self.navigationController.navigationBar; + navBar.tintColor = SYSTEM_VERSION_GREATER_THAN_OR_EQUAL_TO(@"7") ? [UIColor whiteColor] : nil; + if ([navBar respondsToSelector:@selector(setBarTintColor:)]) { + navBar.barTintColor = nil; + navBar.shadowImage = nil; + } + navBar.translucent = YES; + navBar.barStyle = UIBarStyleBlackTranslucent; + if ([[UINavigationBar class] respondsToSelector:@selector(appearance)]) { + [navBar setBackgroundImage:nil forBarMetrics:UIBarMetricsDefault]; + [navBar setBackgroundImage:nil forBarMetrics:UIBarMetricsLandscapePhone]; + } +} + +- (void)storePreviousNavBarAppearance { + _didSavePreviousStateOfNavBar = YES; + if ([UINavigationBar instancesRespondToSelector:@selector(barTintColor)]) { + _previousNavBarBarTintColor = self.navigationController.navigationBar.barTintColor; + } + _previousNavBarTranslucent = self.navigationController.navigationBar.translucent; + _previousNavBarTintColor = self.navigationController.navigationBar.tintColor; + _previousNavBarHidden = self.navigationController.navigationBarHidden; + _previousNavBarStyle = self.navigationController.navigationBar.barStyle; + if ([[UINavigationBar class] respondsToSelector:@selector(appearance)]) { + _previousNavigationBarBackgroundImageDefault = [self.navigationController.navigationBar backgroundImageForBarMetrics:UIBarMetricsDefault]; + _previousNavigationBarBackgroundImageLandscapePhone = [self.navigationController.navigationBar backgroundImageForBarMetrics:UIBarMetricsLandscapePhone]; + } +} + +- (void)restorePreviousNavBarAppearance:(BOOL)animated { + if (_didSavePreviousStateOfNavBar) { + [self.navigationController setNavigationBarHidden:_previousNavBarHidden animated:animated]; + UINavigationBar *navBar = self.navigationController.navigationBar; + navBar.tintColor = _previousNavBarTintColor; + navBar.translucent = _previousNavBarTranslucent; + if ([UINavigationBar instancesRespondToSelector:@selector(barTintColor)]) { + navBar.barTintColor = _previousNavBarBarTintColor; + } + navBar.barStyle = _previousNavBarStyle; + if ([[UINavigationBar class] respondsToSelector:@selector(appearance)]) { + [navBar setBackgroundImage:_previousNavigationBarBackgroundImageDefault forBarMetrics:UIBarMetricsDefault]; + [navBar setBackgroundImage:_previousNavigationBarBackgroundImageLandscapePhone forBarMetrics:UIBarMetricsLandscapePhone]; + } + // Restore back button if we need to + if (_previousViewControllerBackButton) { + UIViewController *previousViewController = [self.navigationController topViewController]; // We've disappeared so previous is now top + previousViewController.navigationItem.backBarButtonItem = _previousViewControllerBackButton; + _previousViewControllerBackButton = nil; + } + } +} + +#pragma mark - Layout + +- (void)viewWillLayoutSubviews { + [super viewWillLayoutSubviews]; + [self layoutVisiblePages]; +} + +- (void)layoutVisiblePages { + + // Flag + _performingLayout = YES; + + // Toolbar + _toolbar.frame = [self frameForToolbarAtOrientation:self.interfaceOrientation]; + + // Remember index + NSUInteger indexPriorToLayout = _currentPageIndex; + + // Get paging scroll view frame to determine if anything needs changing + CGRect pagingScrollViewFrame = [self frameForPagingScrollView]; + + // Frame needs changing + if (!_skipNextPagingScrollViewPositioning) { + _pagingScrollView.frame = pagingScrollViewFrame; + } + _skipNextPagingScrollViewPositioning = NO; + + // Recalculate contentSize based on current orientation + _pagingScrollView.contentSize = [self contentSizeForPagingScrollView]; + + // Adjust frames and configuration of each visible page + for (MWZoomingScrollView *page in _visiblePages) { + NSUInteger index = page.index; + page.frame = [self frameForPageAtIndex:index]; + if (page.captionView) { + page.captionView.frame = [self frameForCaptionView:page.captionView atIndex:index]; + } + if (page.selectedButton) { + page.selectedButton.frame = [self frameForSelectedButton:page.selectedButton atIndex:index]; + } + + // Adjust scales if bounds has changed since last time + if (!CGRectEqualToRect(_previousLayoutBounds, self.view.bounds)) { + // Update zooms for new bounds + [page setMaxMinZoomScalesForCurrentBounds]; + _previousLayoutBounds = self.view.bounds; + } + + } + + // Adjust contentOffset to preserve page location based on values collected prior to location + _pagingScrollView.contentOffset = [self contentOffsetForPageAtIndex:indexPriorToLayout]; + [self didStartViewingPageAtIndex:_currentPageIndex]; // initial + + // Reset + _currentPageIndex = indexPriorToLayout; + _performingLayout = NO; + +} + +#pragma mark - Rotation + +- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation { + return YES; +} + +- (NSUInteger)supportedInterfaceOrientations { + return UIInterfaceOrientationMaskAll; +} + +- (void)willRotateToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation duration:(NSTimeInterval)duration { + + // Remember page index before rotation + _pageIndexBeforeRotation = _currentPageIndex; + _rotating = YES; + + // In iOS 7 the nav bar gets shown after rotation, but might as well do this for everything! + if ([self areControlsHidden]) { + // Force hidden + self.navigationController.navigationBarHidden = YES; + } + +} + +- (void)willAnimateRotationToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation duration:(NSTimeInterval)duration { + + // Perform layout + _currentPageIndex = _pageIndexBeforeRotation; + + // Delay control holding + [self hideControlsAfterDelay]; + + // Layout + [self layoutVisiblePages]; + +} + +- (void)didRotateFromInterfaceOrientation:(UIInterfaceOrientation)fromInterfaceOrientation { + _rotating = NO; + // Ensure nav bar isn't re-displayed + if ([self areControlsHidden]) { + self.navigationController.navigationBarHidden = NO; + self.navigationController.navigationBar.alpha = 0; + } +} + +#pragma mark - Data + +- (NSUInteger)currentIndex { + return _currentPageIndex; +} + +- (void)reloadData { + + // Reset + _photoCount = NSNotFound; + + // Get data + NSUInteger numberOfPhotos = [self numberOfPhotos]; + [self releaseAllUnderlyingPhotos:YES]; + [_photos removeAllObjects]; + [_thumbPhotos removeAllObjects]; + for (int i = 0; i < numberOfPhotos; i++) { + [_photos addObject:[NSNull null]]; + [_thumbPhotos addObject:[NSNull null]]; + } + + // Update current page index + if (numberOfPhotos > 0) { + _currentPageIndex = MAX(0, MIN(_currentPageIndex, numberOfPhotos - 1)); + } else { + _currentPageIndex = 0; + } + + // Update layout + if ([self isViewLoaded]) { + while (_pagingScrollView.subviews.count) { + [[_pagingScrollView.subviews lastObject] removeFromSuperview]; + } + [self performLayout]; + [self.view setNeedsLayout]; + } + +} + +- (NSUInteger)numberOfPhotos { + if (_photoCount == NSNotFound) { + if ([_delegate respondsToSelector:@selector(numberOfPhotosInPhotoBrowser:)]) { + _photoCount = [_delegate numberOfPhotosInPhotoBrowser:self]; + } else if (_depreciatedPhotoData) { + _photoCount = _depreciatedPhotoData.count; + } + } + if (_photoCount == NSNotFound) _photoCount = 0; + return _photoCount; +} + +- (id)photoAtIndex:(NSUInteger)index { + id photo = nil; + if (index < _photos.count) { + if ([_photos objectAtIndex:index] == [NSNull null]) { + if ([_delegate respondsToSelector:@selector(photoBrowser:photoAtIndex:)]) { + photo = [_delegate photoBrowser:self photoAtIndex:index]; + } else if (_depreciatedPhotoData && index < _depreciatedPhotoData.count) { + photo = [_depreciatedPhotoData objectAtIndex:index]; + } + if (photo) [_photos replaceObjectAtIndex:index withObject:photo]; + } else { + photo = [_photos objectAtIndex:index]; + } + } + return photo; +} + +- (id)thumbPhotoAtIndex:(NSUInteger)index { + id photo = nil; + if (index < _thumbPhotos.count) { + if ([_thumbPhotos objectAtIndex:index] == [NSNull null]) { + if ([_delegate respondsToSelector:@selector(photoBrowser:thumbPhotoAtIndex:)]) { + photo = [_delegate photoBrowser:self thumbPhotoAtIndex:index]; + } + if (photo) [_thumbPhotos replaceObjectAtIndex:index withObject:photo]; + } else { + photo = [_thumbPhotos objectAtIndex:index]; + } + } + return photo; +} + +- (MWCaptionView *)captionViewForPhotoAtIndex:(NSUInteger)index { + MWCaptionView *captionView = nil; + if ([_delegate respondsToSelector:@selector(photoBrowser:captionViewForPhotoAtIndex:)]) { + captionView = [_delegate photoBrowser:self captionViewForPhotoAtIndex:index]; + } else { + id photo = [self photoAtIndex:index]; + if ([photo respondsToSelector:@selector(caption)]) { + if ([photo caption]) captionView = [[MWCaptionView alloc] initWithPhoto:photo]; + } + } + captionView.alpha = [self areControlsHidden] ? 0 : 1; // Initial alpha + return captionView; +} + +- (BOOL)photoIsSelectedAtIndex:(NSUInteger)index { + BOOL value = NO; + if (_displaySelectionButtons) { + if ([self.delegate respondsToSelector:@selector(photoBrowser:isPhotoSelectedAtIndex:)]) { + value = [self.delegate photoBrowser:self isPhotoSelectedAtIndex:index]; + } + } + return value; +} + +- (void)setPhotoSelected:(BOOL)selected atIndex:(NSUInteger)index { + if (_displaySelectionButtons) { + if ([self.delegate respondsToSelector:@selector(photoBrowser:photoAtIndex:selectedChanged:)]) { + [self.delegate photoBrowser:self photoAtIndex:index selectedChanged:selected]; + } + } +} + +- (UIImage *)imageForPhoto:(id)photo { + if (photo) { + // Get image or obtain in background + if ([photo underlyingImage]) { + return [photo underlyingImage]; + } else { + [photo loadUnderlyingImageAndNotify]; + } + } + return nil; +} + +- (void)loadAdjacentPhotosIfNecessary:(id)photo { + MWZoomingScrollView *page = [self pageDisplayingPhoto:photo]; + if (page) { + // If page is current page then initiate loading of previous and next pages + NSUInteger pageIndex = page.index; + if (_currentPageIndex == pageIndex) { + if (pageIndex > 0) { + // Preload index - 1 + id photo = [self photoAtIndex:pageIndex-1]; + if (![photo underlyingImage]) { + [photo loadUnderlyingImageAndNotify]; + MWLog(@"Pre-loading image at index %lu", (unsigned long)pageIndex-1); + } + } + if (pageIndex < [self numberOfPhotos] - 1) { + // Preload index + 1 + id photo = [self photoAtIndex:pageIndex+1]; + if (![photo underlyingImage]) { + [photo loadUnderlyingImageAndNotify]; + MWLog(@"Pre-loading image at index %lu", (unsigned long)pageIndex+1); + } + } + } + } +} + +#pragma mark - MWPhoto Loading Notification + +- (void)handleMWPhotoLoadingDidEndNotification:(NSNotification *)notification { + id photo = [notification object]; + MWZoomingScrollView *page = [self pageDisplayingPhoto:photo]; + if (page) { + if ([photo underlyingImage]) { + // Successful load + [page displayImage]; + [self loadAdjacentPhotosIfNecessary:photo]; + } else { + // Failed to load + [page displayImageFailure]; + } + // Update nav + [self updateNavigation]; + } +} + +#pragma mark - Paging + +- (void)tilePages { + + // Calculate which pages should be visible + // Ignore padding as paging bounces encroach on that + // and lead to false page loads + CGRect visibleBounds = _pagingScrollView.bounds; + NSInteger iFirstIndex = (NSInteger)floorf((CGRectGetMinX(visibleBounds)+PADDING*2) / CGRectGetWidth(visibleBounds)); + NSInteger iLastIndex = (NSInteger)floorf((CGRectGetMaxX(visibleBounds)-PADDING*2-1) / CGRectGetWidth(visibleBounds)); + if (iFirstIndex < 0) iFirstIndex = 0; + if (iFirstIndex > [self numberOfPhotos] - 1) iFirstIndex = [self numberOfPhotos] - 1; + if (iLastIndex < 0) iLastIndex = 0; + if (iLastIndex > [self numberOfPhotos] - 1) iLastIndex = [self numberOfPhotos] - 1; + + // Recycle no longer needed pages + NSInteger pageIndex; + for (MWZoomingScrollView *page in _visiblePages) { + pageIndex = page.index; + if (pageIndex < (NSUInteger)iFirstIndex || pageIndex > (NSUInteger)iLastIndex) { + [_recycledPages addObject:page]; + [page.captionView removeFromSuperview]; + [page.selectedButton removeFromSuperview]; + [page prepareForReuse]; + [page removeFromSuperview]; + MWLog(@"Removed page at index %lu", (unsigned long)pageIndex); + } + } + [_visiblePages minusSet:_recycledPages]; + while (_recycledPages.count > 2) // Only keep 2 recycled pages + [_recycledPages removeObject:[_recycledPages anyObject]]; + + // Add missing pages + for (NSUInteger index = (NSUInteger)iFirstIndex; index <= (NSUInteger)iLastIndex; index++) { + if (![self isDisplayingPageForIndex:index]) { + + // Add new page + MWZoomingScrollView *page = [self dequeueRecycledPage]; + if (!page) { + page = [[MWZoomingScrollView alloc] initWithPhotoBrowser:self]; + } + [_visiblePages addObject:page]; + [self configurePage:page forIndex:index]; + + [_pagingScrollView addSubview:page]; + MWLog(@"Added page at index %lu", (unsigned long)index); + + // Add caption + MWCaptionView *captionView = [self captionViewForPhotoAtIndex:index]; + if (captionView) { + captionView.frame = [self frameForCaptionView:captionView atIndex:index]; + [_pagingScrollView addSubview:captionView]; + page.captionView = captionView; + } + + // Add selected button + if (self.displaySelectionButtons) { + UIButton *selectedButton = [UIButton buttonWithType:UIButtonTypeCustom]; + [selectedButton setImage:[UIImage imageNamed:@"MWPhotoBrowser.bundle/images/ImageSelectedOff.png"] forState:UIControlStateNormal]; + [selectedButton setImage:[UIImage imageNamed:@"MWPhotoBrowser.bundle/images/ImageSelectedOn.png"] forState:UIControlStateSelected]; + [selectedButton sizeToFit]; + selectedButton.adjustsImageWhenHighlighted = NO; + [selectedButton addTarget:self action:@selector(selectedButtonTapped:) forControlEvents:UIControlEventTouchUpInside]; + selectedButton.frame = [self frameForSelectedButton:selectedButton atIndex:index]; + [_pagingScrollView addSubview:selectedButton]; + page.selectedButton = selectedButton; + selectedButton.selected = [self photoIsSelectedAtIndex:index]; + } + + } + } + +} + +- (void)updateVisiblePageStates { + NSSet *copy = [_visiblePages copy]; + for (MWZoomingScrollView *page in copy) { + + // Update selection + page.selectedButton.selected = [self photoIsSelectedAtIndex:page.index]; + + } +} + +- (BOOL)isDisplayingPageForIndex:(NSUInteger)index { + for (MWZoomingScrollView *page in _visiblePages) + if (page.index == index) return YES; + return NO; +} + +- (MWZoomingScrollView *)pageDisplayedAtIndex:(NSUInteger)index { + MWZoomingScrollView *thePage = nil; + for (MWZoomingScrollView *page in _visiblePages) { + if (page.index == index) { + thePage = page; break; + } + } + return thePage; +} + +- (MWZoomingScrollView *)pageDisplayingPhoto:(id)photo { + MWZoomingScrollView *thePage = nil; + for (MWZoomingScrollView *page in _visiblePages) { + if (page.photo == photo) { + thePage = page; break; + } + } + return thePage; +} + +- (void)configurePage:(MWZoomingScrollView *)page forIndex:(NSUInteger)index { + page.frame = [self frameForPageAtIndex:index]; + page.index = index; + page.photo = [self photoAtIndex:index]; +} + +- (MWZoomingScrollView *)dequeueRecycledPage { + MWZoomingScrollView *page = [_recycledPages anyObject]; + if (page) { + [_recycledPages removeObject:page]; + } + return page; +} + +// Handle page changes +- (void)didStartViewingPageAtIndex:(NSUInteger)index { + + if (![self numberOfPhotos]) { + // Show controls + [self setControlsHidden:NO animated:YES permanent:YES]; + return; + } + + // Release images further away than +/-1 + NSUInteger i; + if (index > 0) { + // Release anything < index - 1 + for (i = 0; i < index-1; i++) { + id photo = [_photos objectAtIndex:i]; + if (photo != [NSNull null]) { + [photo unloadUnderlyingImage]; + [_photos replaceObjectAtIndex:i withObject:[NSNull null]]; + MWLog(@"Released underlying image at index %lu", (unsigned long)i); + } + } + } + if (index < [self numberOfPhotos] - 1) { + // Release anything > index + 1 + for (i = index + 2; i < _photos.count; i++) { + id photo = [_photos objectAtIndex:i]; + if (photo != [NSNull null]) { + [photo unloadUnderlyingImage]; + [_photos replaceObjectAtIndex:i withObject:[NSNull null]]; + MWLog(@"Released underlying image at index %lu", (unsigned long)i); + } + } + } + + // Load adjacent images if needed and the photo is already + // loaded. Also called after photo has been loaded in background + id currentPhoto = [self photoAtIndex:index]; + if ([currentPhoto underlyingImage]) { + // photo loaded so load ajacent now + [self loadAdjacentPhotosIfNecessary:currentPhoto]; + } + + // Notify delegate + if (index != _previousPageIndex) { + if ([_delegate respondsToSelector:@selector(photoBrowser:didDisplayPhotoAtIndex:)]) + [_delegate photoBrowser:self didDisplayPhotoAtIndex:index]; + _previousPageIndex = index; + } + + // Update nav + [self updateNavigation]; + +} + +#pragma mark - Frame Calculations + +- (CGRect)frameForPagingScrollView { + CGRect frame = self.view.bounds;// [[UIScreen mainScreen] bounds]; + frame.origin.x -= PADDING; + frame.size.width += (2 * PADDING); + return CGRectIntegral(frame); +} + +- (CGRect)frameForPageAtIndex:(NSUInteger)index { + // We have to use our paging scroll view's bounds, not frame, to calculate the page placement. When the device is in + // landscape orientation, the frame will still be in portrait because the pagingScrollView is the root view controller's + // view, so its frame is in window coordinate space, which is never rotated. Its bounds, however, will be in landscape + // because it has a rotation transform applied. + CGRect bounds = _pagingScrollView.bounds; + CGRect pageFrame = bounds; + pageFrame.size.width -= (2 * PADDING); + pageFrame.origin.x = (bounds.size.width * index) + PADDING; + return CGRectIntegral(pageFrame); +} + +- (CGSize)contentSizeForPagingScrollView { + // We have to use the paging scroll view's bounds to calculate the contentSize, for the same reason outlined above. + CGRect bounds = _pagingScrollView.bounds; + return CGSizeMake(bounds.size.width * [self numberOfPhotos], bounds.size.height); +} + +- (CGPoint)contentOffsetForPageAtIndex:(NSUInteger)index { + CGFloat pageWidth = _pagingScrollView.bounds.size.width; + CGFloat newOffset = index * pageWidth; + return CGPointMake(newOffset, 0); +} + +- (CGRect)frameForToolbarAtOrientation:(UIInterfaceOrientation)orientation { + CGFloat height = 44; + if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPhone && + UIInterfaceOrientationIsLandscape(orientation)) height = 32; + return CGRectIntegral(CGRectMake(0, self.view.bounds.size.height - height, self.view.bounds.size.width, height)); +} + +- (CGRect)frameForCaptionView:(MWCaptionView *)captionView atIndex:(NSUInteger)index { + CGRect pageFrame = [self frameForPageAtIndex:index]; + CGSize captionSize = [captionView sizeThatFits:CGSizeMake(pageFrame.size.width, 0)]; + CGRect captionFrame = CGRectMake(pageFrame.origin.x, + pageFrame.size.height - captionSize.height - (_toolbar.superview?_toolbar.frame.size.height:0), + pageFrame.size.width, + captionSize.height); + return CGRectIntegral(captionFrame); +} + +- (CGRect)frameForSelectedButton:(UIButton *)selectedButton atIndex:(NSUInteger)index { + CGRect pageFrame = [self frameForPageAtIndex:index]; + CGFloat yOffset = 0; + if (![self areControlsHidden]) { + UINavigationBar *navBar = self.navigationController.navigationBar; + yOffset = navBar.frame.origin.y + navBar.frame.size.height; + } + CGFloat statusBarOffset = [[UIApplication sharedApplication] statusBarFrame].size.height; +#if __IPHONE_OS_VERSION_MIN_REQUIRED < __IPHONE_7_0 + if (SYSTEM_VERSION_LESS_THAN(@"7") && !self.wantsFullScreenLayout) statusBarOffset = 0; +#endif + CGRect captionFrame = CGRectMake(pageFrame.origin.x + pageFrame.size.width - 20 - selectedButton.frame.size.width, + statusBarOffset + yOffset, + selectedButton.frame.size.width, + selectedButton.frame.size.height); + return CGRectIntegral(captionFrame); +} + +#pragma mark - UIScrollView Delegate + +- (void)scrollViewDidScroll:(UIScrollView *)scrollView { + + // Checks + if (!_viewIsActive || _performingLayout || _rotating) return; + + // Tile pages + [self tilePages]; + + // Calculate current page + CGRect visibleBounds = _pagingScrollView.bounds; + NSInteger index = (NSInteger)(floorf(CGRectGetMidX(visibleBounds) / CGRectGetWidth(visibleBounds))); + if (index < 0) index = 0; + if (index > [self numberOfPhotos] - 1) index = [self numberOfPhotos] - 1; + NSUInteger previousCurrentPage = _currentPageIndex; + _currentPageIndex = index; + if (_currentPageIndex != previousCurrentPage) { + [self didStartViewingPageAtIndex:index]; + } + +} + +- (void)scrollViewWillBeginDragging:(UIScrollView *)scrollView { + // Hide controls when dragging begins + [self setControlsHidden:YES animated:YES permanent:NO]; +} + +- (void)scrollViewDidEndDecelerating:(UIScrollView *)scrollView { + // Update nav when page changes + [self updateNavigation]; +} + +#pragma mark - Navigation + +- (void)updateNavigation { + + // Title + NSUInteger numberOfPhotos = [self numberOfPhotos]; + if (_gridController) { + if (_gridController.selectionMode) { + self.title = NSLocalizedString(@"Select Photos", nil); + } else { + NSString *photosText; + if (numberOfPhotos == 1) { + photosText = NSLocalizedString(@"photo", @"Used in the context: '1 photo'"); + } else { + photosText = NSLocalizedString(@"photos", @"Used in the context: '3 photos'"); + } + self.title = [NSString stringWithFormat:@"%lu %@", (unsigned long)numberOfPhotos, photosText]; + } + } else if (numberOfPhotos > 1) { + if ([_delegate respondsToSelector:@selector(photoBrowser:titleForPhotoAtIndex:)]) { + self.title = [_delegate photoBrowser:self titleForPhotoAtIndex:_currentPageIndex]; + } else { + self.title = [NSString stringWithFormat:@"%lu %@ %lu", (unsigned long)(_currentPageIndex+1), NSLocalizedString(@"of", @"Used in the context: 'Showing 1 of 3 items'"), (unsigned long)numberOfPhotos]; + } + } else { + self.title = nil; + } + + // Buttons + _previousButton.enabled = (_currentPageIndex > 0); + _nextButton.enabled = (_currentPageIndex < numberOfPhotos - 1); + _actionButton.enabled = [[self photoAtIndex:_currentPageIndex] underlyingImage] != nil; + +} + +- (void)jumpToPageAtIndex:(NSUInteger)index animated:(BOOL)animated { + + // Change page + if (index < [self numberOfPhotos]) { + CGRect pageFrame = [self frameForPageAtIndex:index]; + [_pagingScrollView setContentOffset:CGPointMake(pageFrame.origin.x - PADDING, 0) animated:animated]; + [self updateNavigation]; + } + + // Update timer to give more time + [self hideControlsAfterDelay]; + +} + +- (void)gotoPreviousPage { + [self showPreviousPhotoAnimated:NO]; +} +- (void)gotoNextPage { + [self showNextPhotoAnimated:NO]; +} + +- (void)showPreviousPhotoAnimated:(BOOL)animated { + [self jumpToPageAtIndex:_currentPageIndex-1 animated:animated]; +} + +- (void)showNextPhotoAnimated:(BOOL)animated { + [self jumpToPageAtIndex:_currentPageIndex+1 animated:animated]; +} + +#pragma mark - Interactions + +- (void)selectedButtonTapped:(id)sender { + UIButton *selectedButton = (UIButton *)sender; + selectedButton.selected = !selectedButton.selected; + NSUInteger index = NSUIntegerMax; + for (MWZoomingScrollView *page in _visiblePages) { + if (page.selectedButton == selectedButton) { + index = page.index; + break; + } + } + if (index != NSUIntegerMax) { + [self setPhotoSelected:selectedButton.selected atIndex:index]; + } +} + +#pragma mark - Grid + +- (void)showGridAnimated { + [self showGrid:YES]; +} + +- (void)showGrid:(BOOL)animated { + + if (_gridController) return; + + // Init grid controller + _gridController = [[MWGridViewController alloc] init]; + _gridController.initialContentOffset = _currentGridContentOffset; + _gridController.browser = self; + _gridController.selectionMode = _displaySelectionButtons; + _gridController.view.frame = self.view.bounds; + _gridController.view.frame = CGRectOffset(_gridController.view.frame, 0, (self.startOnGrid ? -1 : 1) * self.view.bounds.size.height); + + // Stop specific layout being triggered + _skipNextPagingScrollViewPositioning = YES; + + // Add as a child view controller + [self addChildViewController:_gridController]; + [self.view addSubview:_gridController.view]; + + // Hide action button on nav bar if it exists + if (self.navigationItem.rightBarButtonItem == _actionButton) { + _gridPreviousRightNavItem = _actionButton; + [self.navigationItem setRightBarButtonItem:nil animated:YES]; + } else { + _gridPreviousRightNavItem = nil; + } + + // Update + [self updateNavigation]; + [self setControlsHidden:NO animated:YES permanent:YES]; + + // Animate grid in and photo scroller out + [UIView animateWithDuration:animated ? 0.3 : 0 animations:^(void) { + _gridController.view.frame = self.view.bounds; + CGRect newPagingFrame = [self frameForPagingScrollView]; + newPagingFrame = CGRectOffset(newPagingFrame, 0, (self.startOnGrid ? 1 : -1) * newPagingFrame.size.height); + _pagingScrollView.frame = newPagingFrame; + } completion:^(BOOL finished) { + [_gridController didMoveToParentViewController:self]; + }]; + +} + +- (void)hideGrid { + + if (!_gridController) return; + + // Remember previous content offset + _currentGridContentOffset = _gridController.collectionView.contentOffset; + + // Restore action button if it was removed + if (_gridPreviousRightNavItem == _actionButton && _actionButton) { + [self.navigationItem setRightBarButtonItem:_gridPreviousRightNavItem animated:YES]; + } + + // Position prior to hide animation + CGRect newPagingFrame = [self frameForPagingScrollView]; + newPagingFrame = CGRectOffset(newPagingFrame, 0, (self.startOnGrid ? 1 : -1) * newPagingFrame.size.height); + _pagingScrollView.frame = newPagingFrame; + + // Remember and remove controller now so things can detect a nil grid controller + MWGridViewController *tmpGridController = _gridController; + _gridController = nil; + + // Update + [self updateNavigation]; + [self updateVisiblePageStates]; + + // Animate, hide grid and show paging scroll view + [UIView animateWithDuration:0.3 animations:^{ + tmpGridController.view.frame = CGRectOffset(self.view.bounds, 0, (self.startOnGrid ? -1 : 1) * self.view.bounds.size.height); + _pagingScrollView.frame = [self frameForPagingScrollView]; + } completion:^(BOOL finished) { + [tmpGridController willMoveToParentViewController:nil]; + [tmpGridController.view removeFromSuperview]; + [tmpGridController removeFromParentViewController]; + [self setControlsHidden:NO animated:YES permanent:NO]; // retrigger timer + }]; + +} + +#pragma mark - Control Hiding / Showing + +// If permanent then we don't set timers to hide again +// Fades all controls on iOS 5 & 6, and iOS 7 controls slide and fade +- (void)setControlsHidden:(BOOL)hidden animated:(BOOL)animated permanent:(BOOL)permanent { + + // Force visible + if (![self numberOfPhotos] || _gridController || _alwaysShowControls) + hidden = NO; + + // Cancel any timers + [self cancelControlHiding]; + + // Animations & positions + BOOL slideAndFade = SYSTEM_VERSION_GREATER_THAN_OR_EQUAL_TO(@"7"); + CGFloat animatonOffset = 20; + CGFloat animationDuration = (animated ? 0.35 : 0); + + // Status bar + if (!_leaveStatusBarAlone) { + if ([self respondsToSelector:@selector(setNeedsStatusBarAppearanceUpdate)]) { + + // iOS 7 + // Hide status bar + if (!_isVCBasedStatusBarAppearance) { + + // Non-view controller based + [[UIApplication sharedApplication] setStatusBarHidden:hidden withAnimation:animated ? UIStatusBarAnimationSlide : UIStatusBarAnimationNone]; + + } else { + + // View controller based so animate away + _statusBarShouldBeHidden = hidden; + [UIView animateWithDuration:animationDuration animations:^(void) { + [self setNeedsStatusBarAppearanceUpdate]; + } completion:^(BOOL finished) {}]; + + } + + } else { + + // iOS < 7 + // Status bar and nav bar positioning + BOOL fullScreen = YES; +#if __IPHONE_OS_VERSION_MIN_REQUIRED < __IPHONE_7_0 + if (SYSTEM_VERSION_LESS_THAN(@"7")) fullScreen = self.wantsFullScreenLayout; +#endif + if (fullScreen) { + + // Need to get heights and set nav bar position to overcome display issues + + // Get status bar height if visible + CGFloat statusBarHeight = 0; + if (![UIApplication sharedApplication].statusBarHidden) { + CGRect statusBarFrame = [[UIApplication sharedApplication] statusBarFrame]; + statusBarHeight = MIN(statusBarFrame.size.height, statusBarFrame.size.width); + } + + // Status Bar + [[UIApplication sharedApplication] setStatusBarHidden:hidden withAnimation:animated?UIStatusBarAnimationFade:UIStatusBarAnimationNone]; + + // Get status bar height if visible + if (![UIApplication sharedApplication].statusBarHidden) { + CGRect statusBarFrame = [[UIApplication sharedApplication] statusBarFrame]; + statusBarHeight = MIN(statusBarFrame.size.height, statusBarFrame.size.width); + } + + // Set navigation bar frame + CGRect navBarFrame = self.navigationController.navigationBar.frame; + navBarFrame.origin.y = statusBarHeight; + self.navigationController.navigationBar.frame = navBarFrame; + + } + + } + } + + // Toolbar, nav bar and captions + // Pre-appear animation positions for iOS 7 sliding + if (slideAndFade && [self areControlsHidden] && !hidden && animated) { + + // Toolbar + _toolbar.frame = CGRectOffset([self frameForToolbarAtOrientation:self.interfaceOrientation], 0, animatonOffset); + + // Captions + for (MWZoomingScrollView *page in _visiblePages) { + if (page.captionView) { + MWCaptionView *v = page.captionView; + // Pass any index, all we're interested in is the Y + CGRect captionFrame = [self frameForCaptionView:v atIndex:0]; + captionFrame.origin.x = v.frame.origin.x; // Reset X + v.frame = CGRectOffset(captionFrame, 0, animatonOffset); + } + } + + } + [UIView animateWithDuration:animationDuration animations:^(void) { + + CGFloat alpha = hidden ? 0 : 1; + + // Nav bar slides up on it's own on iOS 7 + [self.navigationController.navigationBar setAlpha:alpha]; + + // Toolbar + if (slideAndFade) { + _toolbar.frame = [self frameForToolbarAtOrientation:self.interfaceOrientation]; + if (hidden) _toolbar.frame = CGRectOffset(_toolbar.frame, 0, animatonOffset); + } + _toolbar.alpha = alpha; + + // Captions + for (MWZoomingScrollView *page in _visiblePages) { + if (page.captionView) { + MWCaptionView *v = page.captionView; + if (slideAndFade) { + // Pass any index, all we're interested in is the Y + CGRect captionFrame = [self frameForCaptionView:v atIndex:0]; + captionFrame.origin.x = v.frame.origin.x; // Reset X + if (hidden) captionFrame = CGRectOffset(captionFrame, 0, animatonOffset); + v.frame = captionFrame; + } + v.alpha = alpha; + } + } + + // Selected buttons + for (MWZoomingScrollView *page in _visiblePages) { + if (page.selectedButton) { + UIButton *v = page.selectedButton; + CGRect newFrame = [self frameForSelectedButton:v atIndex:0]; + newFrame.origin.x = v.frame.origin.x; + v.frame = newFrame; + } + } + + } completion:^(BOOL finished) {}]; + + // Control hiding timer + // Will cancel existing timer but only begin hiding if + // they are visible + if (!permanent) [self hideControlsAfterDelay]; + +} + +- (BOOL)prefersStatusBarHidden { + if (!_leaveStatusBarAlone) { + return _statusBarShouldBeHidden; + } else { + return [self presentingViewControllerPrefersStatusBarHidden]; + } +} + +- (UIStatusBarAnimation)preferredStatusBarUpdateAnimation { + return UIStatusBarAnimationSlide; +} + +- (void)cancelControlHiding { + // If a timer exists then cancel and release + if (_controlVisibilityTimer) { + [_controlVisibilityTimer invalidate]; + _controlVisibilityTimer = nil; + } +} + +// Enable/disable control visiblity timer +- (void)hideControlsAfterDelay { + if (![self areControlsHidden]) { + [self cancelControlHiding]; + _controlVisibilityTimer = [NSTimer scheduledTimerWithTimeInterval:self.delayToHideElements target:self selector:@selector(hideControls) userInfo:nil repeats:NO]; + } +} + +- (BOOL)areControlsHidden { return (_toolbar.alpha == 0); } +- (void)hideControls { [self setControlsHidden:YES animated:YES permanent:NO]; } +- (void)toggleControls { [self setControlsHidden:![self areControlsHidden] animated:YES permanent:NO]; } + +#pragma mark - Properties + +// Handle depreciated method +- (void)setInitialPageIndex:(NSUInteger)index { + [self setCurrentPhotoIndex:index]; +} + +- (void)setCurrentPhotoIndex:(NSUInteger)index { + // Validate + NSUInteger photoCount = [self numberOfPhotos]; + if (photoCount == 0) { + index = 0; + } else { + if (index >= photoCount) + index = [self numberOfPhotos]-1; + } + _currentPageIndex = index; + if ([self isViewLoaded]) { + [self jumpToPageAtIndex:index animated:NO]; + if (!_viewIsActive) + [self tilePages]; // Force tiling if view is not visible + } +} + +#pragma mark - Misc + +- (void)doneButtonPressed:(id)sender { + // Only if we're modal and there's a done button + if (_doneButton) { + // See if we actually just want to show/hide grid + if (self.enableGrid) { + if (self.startOnGrid && !_gridController) { + [self showGrid:YES]; + return; + } else if (!self.startOnGrid && _gridController) { + [self hideGrid]; + return; + } + } + // Dismiss view controller + if ([_delegate respondsToSelector:@selector(photoBrowserDidFinishModalPresentation:)]) { + // Call delegate method and let them dismiss us + [_delegate photoBrowserDidFinishModalPresentation:self]; + } else { + [self dismissViewControllerAnimated:YES completion:nil]; + } + } +} + +#pragma mark - Actions + +- (void)actionButtonPressed:(id)sender { + if (_actionsSheet) { + + // Dismiss + [_actionsSheet dismissWithClickedButtonIndex:_actionsSheet.cancelButtonIndex animated:YES]; + + } else { + + // Only react when image has loaded + id photo = [self photoAtIndex:_currentPageIndex]; + if ([self numberOfPhotos] > 0 && [photo underlyingImage]) { + + // If they have defined a delegate method then just message them + if ([self.delegate respondsToSelector:@selector(photoBrowser:actionButtonPressedForPhotoAtIndex:)]) { + + // Let delegate handle things + [self.delegate photoBrowser:self actionButtonPressedForPhotoAtIndex:_currentPageIndex]; + + } else { + + // Handle default actions + if (SYSTEM_VERSION_LESS_THAN(@"6")) { + + // Old handling of activities with action sheet + if ([MFMailComposeViewController canSendMail]) { + _actionsSheet = [[UIActionSheet alloc] initWithTitle:nil delegate:self + cancelButtonTitle:NSLocalizedString(@"Cancel", nil) destructiveButtonTitle:nil + otherButtonTitles:NSLocalizedString(@"Save", nil), NSLocalizedString(@"Copy", nil), NSLocalizedString(@"Email", nil), nil]; + } else { + _actionsSheet = [[UIActionSheet alloc] initWithTitle:nil delegate:self + cancelButtonTitle:NSLocalizedString(@"Cancel", nil) destructiveButtonTitle:nil + otherButtonTitles:NSLocalizedString(@"Save", nil), NSLocalizedString(@"Copy", nil), nil]; + } + _actionsSheet.tag = ACTION_SHEET_OLD_ACTIONS; + _actionsSheet.actionSheetStyle = UIActionSheetStyleBlackTranslucent; + if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad) { + [_actionsSheet showFromBarButtonItem:sender animated:YES]; + } else { + [_actionsSheet showInView:self.view]; + } + + } else { + + // Show activity view controller + NSMutableArray *items = [NSMutableArray arrayWithObject:[photo underlyingImage]]; + if (photo.caption) { + [items addObject:photo.caption]; + } + self.activityViewController = [[UIActivityViewController alloc] initWithActivityItems:items applicationActivities:nil]; + + // Show loading spinner after a couple of seconds + double delayInSeconds = 2.0; + dispatch_time_t popTime = dispatch_time(DISPATCH_TIME_NOW, (int64_t)(delayInSeconds * NSEC_PER_SEC)); + dispatch_after(popTime, dispatch_get_main_queue(), ^(void){ + if (self.activityViewController) { + [self showProgressHUDWithMessage:nil]; + } + }); + + // Show + typeof(self) __weak weakSelf = self; + [self.activityViewController setCompletionHandler:^(NSString *activityType, BOOL completed) { + weakSelf.activityViewController = nil; + [weakSelf hideControlsAfterDelay]; + [weakSelf hideProgressHUD:YES]; + }]; + // iOS 8 - Set the Anchor Point for the popover + if (SYSTEM_VERSION_GREATER_THAN_OR_EQUAL_TO(@"8")) { + self.activityViewController.popoverPresentationController.barButtonItem = _actionButton; + } + [self presentViewController:self.activityViewController animated:YES completion:nil]; + + } + + } + + // Keep controls hidden + [self setControlsHidden:NO animated:YES permanent:YES]; + + } + } +} + +#pragma mark - Action Sheet Delegate + +- (void)actionSheet:(UIActionSheet *)actionSheet didDismissWithButtonIndex:(NSInteger)buttonIndex { + if (actionSheet.tag == ACTION_SHEET_OLD_ACTIONS) { + // Old Actions + _actionsSheet = nil; + if (buttonIndex != actionSheet.cancelButtonIndex) { + if (buttonIndex == actionSheet.firstOtherButtonIndex) { + [self savePhoto]; return; + } else if (buttonIndex == actionSheet.firstOtherButtonIndex + 1) { + [self copyPhoto]; return; + } else if (buttonIndex == actionSheet.firstOtherButtonIndex + 2) { + [self emailPhoto]; return; + } + } + } + [self hideControlsAfterDelay]; // Continue as normal... +} + +#pragma mark - Action Progress + +- (MBProgressHUD *)progressHUD { + if (!_progressHUD) { + _progressHUD = [[MBProgressHUD alloc] initWithView:self.view]; + _progressHUD.minSize = CGSizeMake(120, 120); + _progressHUD.minShowTime = 1; + // The sample image is based on the + // work by: http://www.pixelpressicons.com + // licence: http://creativecommons.org/licenses/by/2.5/ca/ + self.progressHUD.customView = [[UIImageView alloc] initWithImage:[UIImage imageNamed:@"MWPhotoBrowser.bundle/images/Checkmark.png"]]; + [self.view addSubview:_progressHUD]; + } + return _progressHUD; +} + +- (void)showProgressHUDWithMessage:(NSString *)message { + self.progressHUD.labelText = message; + self.progressHUD.mode = MBProgressHUDModeIndeterminate; + [self.progressHUD show:YES]; + self.navigationController.navigationBar.userInteractionEnabled = NO; +} + +- (void)hideProgressHUD:(BOOL)animated { + [self.progressHUD hide:animated]; + self.navigationController.navigationBar.userInteractionEnabled = YES; +} + +- (void)showProgressHUDCompleteMessage:(NSString *)message { + if (message) { + if (self.progressHUD.isHidden) [self.progressHUD show:YES]; + self.progressHUD.labelText = message; + self.progressHUD.mode = MBProgressHUDModeCustomView; + [self.progressHUD hide:YES afterDelay:1.5]; + } else { + [self.progressHUD hide:YES]; + } + self.navigationController.navigationBar.userInteractionEnabled = YES; +} + +#pragma mark - Actions + +- (void)savePhoto { + id photo = [self photoAtIndex:_currentPageIndex]; + if ([photo underlyingImage]) { + [self showProgressHUDWithMessage:[NSString stringWithFormat:@"%@\u2026" , NSLocalizedString(@"Saving", @"Displayed with ellipsis as 'Saving...' when an item is in the process of being saved")]]; + [self performSelector:@selector(actuallySavePhoto:) withObject:photo afterDelay:0]; + } +} + +- (void)actuallySavePhoto:(id)photo { + if ([photo underlyingImage]) { + UIImageWriteToSavedPhotosAlbum([photo underlyingImage], self, + @selector(image:didFinishSavingWithError:contextInfo:), nil); + } +} + +- (void)image:(UIImage *)image didFinishSavingWithError:(NSError *)error contextInfo:(void *)contextInfo { + [self showProgressHUDCompleteMessage: error ? NSLocalizedString(@"Failed", @"Informing the user a process has failed") : NSLocalizedString(@"Saved", @"Informing the user an item has been saved")]; + [self hideControlsAfterDelay]; // Continue as normal... +} + +- (void)copyPhoto { + id photo = [self photoAtIndex:_currentPageIndex]; + if ([photo underlyingImage]) { + [self showProgressHUDWithMessage:[NSString stringWithFormat:@"%@\u2026" , NSLocalizedString(@"Copying", @"Displayed with ellipsis as 'Copying...' when an item is in the process of being copied")]]; + [self performSelector:@selector(actuallyCopyPhoto:) withObject:photo afterDelay:0]; + } +} + +- (void)actuallyCopyPhoto:(id)photo { + if ([photo underlyingImage]) { + [[UIPasteboard generalPasteboard] setData:UIImagePNGRepresentation([photo underlyingImage]) + forPasteboardType:@"public.png"]; + [self showProgressHUDCompleteMessage:NSLocalizedString(@"Copied", @"Informing the user an item has finished copying")]; + [self hideControlsAfterDelay]; // Continue as normal... + } +} + +- (void)emailPhoto { + id photo = [self photoAtIndex:_currentPageIndex]; + if ([photo underlyingImage]) { + [self showProgressHUDWithMessage:[NSString stringWithFormat:@"%@\u2026" , NSLocalizedString(@"Preparing", @"Displayed with ellipsis as 'Preparing...' when an item is in the process of being prepared")]]; + [self performSelector:@selector(actuallyEmailPhoto:) withObject:photo afterDelay:0]; + } +} + +- (void)actuallyEmailPhoto:(id)photo { + if ([photo underlyingImage]) { + MFMailComposeViewController *emailer = [[MFMailComposeViewController alloc] init]; + emailer.mailComposeDelegate = self; + [emailer setSubject:NSLocalizedString(@"Photo", nil)]; + [emailer addAttachmentData:UIImagePNGRepresentation([photo underlyingImage]) mimeType:@"png" fileName:@"Photo.png"]; + if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad) { + emailer.modalPresentationStyle = UIModalPresentationPageSheet; + } + [self presentViewController:emailer animated:YES completion:nil]; + [self hideProgressHUD:NO]; + } +} + +- (void)mailComposeController:(MFMailComposeViewController*)controller didFinishWithResult:(MFMailComposeResult)result error:(NSError*)error { + if (result == MFMailComposeResultFailed) { + UIAlertView *alert = [[UIAlertView alloc] initWithTitle:NSLocalizedString(@"Email", nil) + message:NSLocalizedString(@"Email failed to send. Please try again.", nil) + delegate:nil cancelButtonTitle:NSLocalizedString(@"Dismiss", nil) otherButtonTitles:nil]; + [alert show]; + } + [self dismissViewControllerAnimated:YES completion:nil]; +} + +@end diff --git a/ios/Pods/MWPhotoBrowser/MWPhotoBrowser/Classes/MWPhotoBrowserPrivate.h b/ios/Pods/MWPhotoBrowser/MWPhotoBrowser/Classes/MWPhotoBrowserPrivate.h new file mode 100644 index 000000000..b243f4143 --- /dev/null +++ b/ios/Pods/MWPhotoBrowser/MWPhotoBrowser/Classes/MWPhotoBrowserPrivate.h @@ -0,0 +1,136 @@ +// +// MWPhotoBrowser_Private.h +// MWPhotoBrowser +// +// Created by Michael Waterfall on 08/10/2013. +// +// + +#import +#import "MBProgressHUD.h" +#import "MWGridViewController.h" +#import "MWZoomingScrollView.h" + +// Declare private methods of browser +@interface MWPhotoBrowser () { + + // Data + NSUInteger _photoCount; + NSMutableArray *_photos; + NSMutableArray *_thumbPhotos; + NSArray *_depreciatedPhotoData; // Depreciated + + // Views + UIScrollView *_pagingScrollView; + + // Paging & layout + NSMutableSet *_visiblePages, *_recycledPages; + NSUInteger _currentPageIndex; + NSUInteger _previousPageIndex; + CGRect _previousLayoutBounds; + NSUInteger _pageIndexBeforeRotation; + + // Navigation & controls + UIToolbar *_toolbar; + NSTimer *_controlVisibilityTimer; + UIBarButtonItem *_previousButton, *_nextButton, *_actionButton, *_doneButton; + MBProgressHUD *_progressHUD; + UIActionSheet *_actionsSheet; + + // Grid + MWGridViewController *_gridController; + UIBarButtonItem *_gridPreviousLeftNavItem; + UIBarButtonItem *_gridPreviousRightNavItem; + + // Appearance + BOOL _previousNavBarHidden; + BOOL _previousNavBarTranslucent; + UIBarStyle _previousNavBarStyle; + UIStatusBarStyle _previousStatusBarStyle; + UIColor *_previousNavBarTintColor; + UIColor *_previousNavBarBarTintColor; + UIBarButtonItem *_previousViewControllerBackButton; + UIImage *_previousNavigationBarBackgroundImageDefault; + UIImage *_previousNavigationBarBackgroundImageLandscapePhone; + + // Misc + BOOL _hasBelongedToViewController; + BOOL _isVCBasedStatusBarAppearance; + BOOL _statusBarShouldBeHidden; + BOOL _displayActionButton; + BOOL _leaveStatusBarAlone; + BOOL _performingLayout; + BOOL _rotating; + BOOL _viewIsActive; // active as in it's in the view heirarchy + BOOL _didSavePreviousStateOfNavBar; + BOOL _skipNextPagingScrollViewPositioning; + BOOL _viewHasAppearedInitially; + CGPoint _currentGridContentOffset; + +} + +// Properties +@property (nonatomic) UIActivityViewController *activityViewController; + +// Layout +- (void)layoutVisiblePages; +- (void)performLayout; +- (BOOL)presentingViewControllerPrefersStatusBarHidden; + +// Nav Bar Appearance +- (void)setNavBarAppearance:(BOOL)animated; +- (void)storePreviousNavBarAppearance; +- (void)restorePreviousNavBarAppearance:(BOOL)animated; + +// Paging +- (void)tilePages; +- (BOOL)isDisplayingPageForIndex:(NSUInteger)index; +- (MWZoomingScrollView *)pageDisplayedAtIndex:(NSUInteger)index; +- (MWZoomingScrollView *)pageDisplayingPhoto:(id)photo; +- (MWZoomingScrollView *)dequeueRecycledPage; +- (void)configurePage:(MWZoomingScrollView *)page forIndex:(NSUInteger)index; +- (void)didStartViewingPageAtIndex:(NSUInteger)index; + +// Frames +- (CGRect)frameForPagingScrollView; +- (CGRect)frameForPageAtIndex:(NSUInteger)index; +- (CGSize)contentSizeForPagingScrollView; +- (CGPoint)contentOffsetForPageAtIndex:(NSUInteger)index; +- (CGRect)frameForToolbarAtOrientation:(UIInterfaceOrientation)orientation; +- (CGRect)frameForCaptionView:(MWCaptionView *)captionView atIndex:(NSUInteger)index; +- (CGRect)frameForSelectedButton:(UIButton *)selectedButton atIndex:(NSUInteger)index; + +// Navigation +- (void)updateNavigation; +- (void)jumpToPageAtIndex:(NSUInteger)index animated:(BOOL)animated; +- (void)gotoPreviousPage; +- (void)gotoNextPage; + +// Grid +- (void)showGrid:(BOOL)animated; +- (void)hideGrid; + +// Controls +- (void)cancelControlHiding; +- (void)hideControlsAfterDelay; +- (void)setControlsHidden:(BOOL)hidden animated:(BOOL)animated permanent:(BOOL)permanent; +- (void)toggleControls; +- (BOOL)areControlsHidden; + +// Data +- (NSUInteger)numberOfPhotos; +- (id)photoAtIndex:(NSUInteger)index; +- (id)thumbPhotoAtIndex:(NSUInteger)index; +- (UIImage *)imageForPhoto:(id)photo; +- (BOOL)photoIsSelectedAtIndex:(NSUInteger)index; +- (void)setPhotoSelected:(BOOL)selected atIndex:(NSUInteger)index; +- (void)loadAdjacentPhotosIfNecessary:(id)photo; +- (void)releaseAllUnderlyingPhotos:(BOOL)preserveCurrent; + +// Actions +- (void)savePhoto; +- (void)copyPhoto; +- (void)emailPhoto; + +@end + diff --git a/ios/Pods/MWPhotoBrowser/MWPhotoBrowser/Classes/MWPhotoProtocol.h b/ios/Pods/MWPhotoBrowser/MWPhotoBrowser/Classes/MWPhotoProtocol.h new file mode 100644 index 000000000..4a9bccf42 --- /dev/null +++ b/ios/Pods/MWPhotoBrowser/MWPhotoBrowser/Classes/MWPhotoProtocol.h @@ -0,0 +1,64 @@ +// +// MWPhotoProtocol.h +// MWPhotoBrowser +// +// Created by Michael Waterfall on 02/01/2012. +// Copyright (c) 2012 __MyCompanyName__. All rights reserved. +// + +#import + +// Notifications +#define MWPHOTO_LOADING_DID_END_NOTIFICATION @"MWPHOTO_LOADING_DID_END_NOTIFICATION" +#define MWPHOTO_PROGRESS_NOTIFICATION @"MWPHOTO_PROGRESS_NOTIFICATION" + +// If you wish to use your own data models for photo then they must conform +// to this protocol. See instructions for details on each method. +// Otherwise you can use the MWPhoto object or subclass it yourself to +// store more information per photo. +// +// You can see the MWPhoto class for an example implementation of this protocol +// +@protocol MWPhoto + +@required + +// Return underlying UIImage to be displayed +// Return nil if the image is not immediately available (loaded into memory, preferably +// already decompressed) and needs to be loaded from a source (cache, file, web, etc) +// IMPORTANT: You should *NOT* use this method to initiate +// fetching of images from any external of source. That should be handled +// in -loadUnderlyingImageAndNotify: which may be called by the photo browser if this +// methods returns nil. +@property (nonatomic, strong) UIImage *underlyingImage; + +// Called when the browser has determined the underlying images is not +// already loaded into memory but needs it. +- (void)loadUnderlyingImageAndNotify; + +// Fetch the image data from a source and notify when complete. +// You must load the image asyncronously (and decompress it for better performance). +// It is recommended that you use SDWebImageDecoder to perform the decompression. +// See MWPhoto object for an example implementation. +// When the underlying UIImage is loaded (or failed to load) you should post the following +// notification: +// [[NSNotificationCenter defaultCenter] postNotificationName:MWPHOTO_LOADING_DID_END_NOTIFICATION +// object:self]; +- (void)performLoadUnderlyingImageAndNotify; + +// This is called when the photo browser has determined the photo data +// is no longer needed or there are low memory conditions +// You should release any underlying (possibly large and decompressed) image data +// as long as the image can be re-loaded (from cache, file, or URL) +- (void)unloadUnderlyingImage; + +@optional + +// Return a caption string to be displayed over the image +// Return nil to display no caption +- (NSString *)caption; + +// Cancel any background loading of image data +- (void)cancelAnyLoading; + +@end \ No newline at end of file diff --git a/ios/Pods/MWPhotoBrowser/MWPhotoBrowser/Classes/MWTapDetectingImageView.h b/ios/Pods/MWPhotoBrowser/MWPhotoBrowser/Classes/MWTapDetectingImageView.h new file mode 100644 index 000000000..8445b6260 --- /dev/null +++ b/ios/Pods/MWPhotoBrowser/MWPhotoBrowser/Classes/MWTapDetectingImageView.h @@ -0,0 +1,27 @@ +// +// UIImageViewTap.h +// Momento +// +// Created by Michael Waterfall on 04/11/2009. +// Copyright 2009 d3i. All rights reserved. +// + +#import + +@protocol MWTapDetectingImageViewDelegate; + +@interface MWTapDetectingImageView : UIImageView {} + +@property (nonatomic, weak) id tapDelegate; + +@end + +@protocol MWTapDetectingImageViewDelegate + +@optional + +- (void)imageView:(UIImageView *)imageView singleTapDetected:(UITouch *)touch; +- (void)imageView:(UIImageView *)imageView doubleTapDetected:(UITouch *)touch; +- (void)imageView:(UIImageView *)imageView tripleTapDetected:(UITouch *)touch; + +@end \ No newline at end of file diff --git a/ios/Pods/MWPhotoBrowser/MWPhotoBrowser/Classes/MWTapDetectingImageView.m b/ios/Pods/MWPhotoBrowser/MWPhotoBrowser/Classes/MWTapDetectingImageView.m new file mode 100644 index 000000000..b0666ba73 --- /dev/null +++ b/ios/Pods/MWPhotoBrowser/MWPhotoBrowser/Classes/MWTapDetectingImageView.m @@ -0,0 +1,68 @@ +// +// UIImageViewTap.m +// Momento +// +// Created by Michael Waterfall on 04/11/2009. +// Copyright 2009 d3i. All rights reserved. +// + +#import "MWTapDetectingImageView.h" + +@implementation MWTapDetectingImageView + +- (id)initWithFrame:(CGRect)frame { + if ((self = [super initWithFrame:frame])) { + self.userInteractionEnabled = YES; + } + return self; +} + +- (id)initWithImage:(UIImage *)image { + if ((self = [super initWithImage:image])) { + self.userInteractionEnabled = YES; + } + return self; +} + +- (id)initWithImage:(UIImage *)image highlightedImage:(UIImage *)highlightedImage { + if ((self = [super initWithImage:image highlightedImage:highlightedImage])) { + self.userInteractionEnabled = YES; + } + return self; +} + +- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event { + UITouch *touch = [touches anyObject]; + NSUInteger tapCount = touch.tapCount; + switch (tapCount) { + case 1: + [self handleSingleTap:touch]; + break; + case 2: + [self handleDoubleTap:touch]; + break; + case 3: + [self handleTripleTap:touch]; + break; + default: + break; + } + [[self nextResponder] touchesEnded:touches withEvent:event]; +} + +- (void)handleSingleTap:(UITouch *)touch { + if ([_tapDelegate respondsToSelector:@selector(imageView:singleTapDetected:)]) + [_tapDelegate imageView:self singleTapDetected:touch]; +} + +- (void)handleDoubleTap:(UITouch *)touch { + if ([_tapDelegate respondsToSelector:@selector(imageView:doubleTapDetected:)]) + [_tapDelegate imageView:self doubleTapDetected:touch]; +} + +- (void)handleTripleTap:(UITouch *)touch { + if ([_tapDelegate respondsToSelector:@selector(imageView:tripleTapDetected:)]) + [_tapDelegate imageView:self tripleTapDetected:touch]; +} + +@end diff --git a/ios/Pods/MWPhotoBrowser/MWPhotoBrowser/Classes/MWTapDetectingView.h b/ios/Pods/MWPhotoBrowser/MWPhotoBrowser/Classes/MWTapDetectingView.h new file mode 100644 index 000000000..d5309e9ed --- /dev/null +++ b/ios/Pods/MWPhotoBrowser/MWPhotoBrowser/Classes/MWTapDetectingView.h @@ -0,0 +1,27 @@ +// +// UIViewTap.h +// Momento +// +// Created by Michael Waterfall on 04/11/2009. +// Copyright 2009 d3i. All rights reserved. +// + +#import + +@protocol MWTapDetectingViewDelegate; + +@interface MWTapDetectingView : UIView {} + +@property (nonatomic, weak) id tapDelegate; + +@end + +@protocol MWTapDetectingViewDelegate + +@optional + +- (void)view:(UIView *)view singleTapDetected:(UITouch *)touch; +- (void)view:(UIView *)view doubleTapDetected:(UITouch *)touch; +- (void)view:(UIView *)view tripleTapDetected:(UITouch *)touch; + +@end \ No newline at end of file diff --git a/ios/Pods/MWPhotoBrowser/MWPhotoBrowser/Classes/MWTapDetectingView.m b/ios/Pods/MWPhotoBrowser/MWPhotoBrowser/Classes/MWTapDetectingView.m new file mode 100644 index 000000000..e1796bcc3 --- /dev/null +++ b/ios/Pods/MWPhotoBrowser/MWPhotoBrowser/Classes/MWTapDetectingView.m @@ -0,0 +1,61 @@ +// +// UIViewTap.m +// Momento +// +// Created by Michael Waterfall on 04/11/2009. +// Copyright 2009 d3i. All rights reserved. +// + +#import "MWTapDetectingView.h" + +@implementation MWTapDetectingView + +- (id)init { + if ((self = [super init])) { + self.userInteractionEnabled = YES; + } + return self; +} + +- (id)initWithFrame:(CGRect)frame { + if ((self = [super initWithFrame:frame])) { + self.userInteractionEnabled = YES; + } + return self; +} + +- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event { + UITouch *touch = [touches anyObject]; + NSUInteger tapCount = touch.tapCount; + switch (tapCount) { + case 1: + [self handleSingleTap:touch]; + break; + case 2: + [self handleDoubleTap:touch]; + break; + case 3: + [self handleTripleTap:touch]; + break; + default: + break; + } + [[self nextResponder] touchesEnded:touches withEvent:event]; +} + +- (void)handleSingleTap:(UITouch *)touch { + if ([_tapDelegate respondsToSelector:@selector(view:singleTapDetected:)]) + [_tapDelegate view:self singleTapDetected:touch]; +} + +- (void)handleDoubleTap:(UITouch *)touch { + if ([_tapDelegate respondsToSelector:@selector(view:doubleTapDetected:)]) + [_tapDelegate view:self doubleTapDetected:touch]; +} + +- (void)handleTripleTap:(UITouch *)touch { + if ([_tapDelegate respondsToSelector:@selector(view:tripleTapDetected:)]) + [_tapDelegate view:self tripleTapDetected:touch]; +} + +@end diff --git a/ios/Pods/MWPhotoBrowser/MWPhotoBrowser/Classes/MWZoomingScrollView.h b/ios/Pods/MWPhotoBrowser/MWPhotoBrowser/Classes/MWZoomingScrollView.h new file mode 100644 index 000000000..c3d8a95d1 --- /dev/null +++ b/ios/Pods/MWPhotoBrowser/MWPhotoBrowser/Classes/MWZoomingScrollView.h @@ -0,0 +1,31 @@ +// +// ZoomingScrollView.h +// MWPhotoBrowser +// +// Created by Michael Waterfall on 14/10/2010. +// Copyright 2010 d3i. All rights reserved. +// + +#import +#import "MWPhotoProtocol.h" +#import "MWTapDetectingImageView.h" +#import "MWTapDetectingView.h" + +@class MWPhotoBrowser, MWPhoto, MWCaptionView; + +@interface MWZoomingScrollView : UIScrollView { + +} + +@property () NSUInteger index; +@property (nonatomic) id photo; +@property (nonatomic, weak) MWCaptionView *captionView; +@property (nonatomic, weak) UIButton *selectedButton; + +- (id)initWithPhotoBrowser:(MWPhotoBrowser *)browser; +- (void)displayImage; +- (void)displayImageFailure; +- (void)setMaxMinZoomScalesForCurrentBounds; +- (void)prepareForReuse; + +@end diff --git a/ios/Pods/MWPhotoBrowser/MWPhotoBrowser/Classes/MWZoomingScrollView.m b/ios/Pods/MWPhotoBrowser/MWPhotoBrowser/Classes/MWZoomingScrollView.m new file mode 100644 index 000000000..6a03a4423 --- /dev/null +++ b/ios/Pods/MWPhotoBrowser/MWPhotoBrowser/Classes/MWZoomingScrollView.m @@ -0,0 +1,411 @@ +// +// ZoomingScrollView.m +// MWPhotoBrowser +// +// Created by Michael Waterfall on 14/10/2010. +// Copyright 2010 d3i. All rights reserved. +// + +#import "MWCommon.h" +#import "MWZoomingScrollView.h" +#import "MWPhotoBrowser.h" +#import "MWPhoto.h" +#import "DACircularProgressView.h" +#import "MWPhotoBrowserPrivate.h" + +// Private methods and properties +@interface MWZoomingScrollView () { + + MWPhotoBrowser __weak *_photoBrowser; + MWTapDetectingView *_tapView; // for background taps + MWTapDetectingImageView *_photoImageView; + DACircularProgressView *_loadingIndicator; + UIImageView *_loadingError; + +} + +@end + +@implementation MWZoomingScrollView + +- (id)initWithPhotoBrowser:(MWPhotoBrowser *)browser { + if ((self = [super init])) { + + // Setup + _index = NSUIntegerMax; + _photoBrowser = browser; + + // Tap view for background + _tapView = [[MWTapDetectingView alloc] initWithFrame:self.bounds]; + _tapView.tapDelegate = self; + _tapView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight; + _tapView.backgroundColor = [UIColor blackColor]; + [self addSubview:_tapView]; + + // Image view + _photoImageView = [[MWTapDetectingImageView alloc] initWithFrame:CGRectZero]; + _photoImageView.tapDelegate = self; + _photoImageView.contentMode = UIViewContentModeCenter; + _photoImageView.backgroundColor = [UIColor blackColor]; + [self addSubview:_photoImageView]; + + // Loading indicator + _loadingIndicator = [[DACircularProgressView alloc] initWithFrame:CGRectMake(140.0f, 30.0f, 40.0f, 40.0f)]; + _loadingIndicator.userInteractionEnabled = NO; + if (SYSTEM_VERSION_GREATER_THAN_OR_EQUAL_TO(@"7")) { + _loadingIndicator.thicknessRatio = 0.1; + _loadingIndicator.roundedCorners = NO; + } else { + _loadingIndicator.thicknessRatio = 0.2; + _loadingIndicator.roundedCorners = YES; + } + _loadingIndicator.autoresizingMask = UIViewAutoresizingFlexibleLeftMargin | UIViewAutoresizingFlexibleTopMargin | + UIViewAutoresizingFlexibleBottomMargin | UIViewAutoresizingFlexibleRightMargin; + [self addSubview:_loadingIndicator]; + + // Listen progress notifications + [[NSNotificationCenter defaultCenter] addObserver:self + selector:@selector(setProgressFromNotification:) + name:MWPHOTO_PROGRESS_NOTIFICATION + object:nil]; + + // Setup + self.backgroundColor = [UIColor blackColor]; + self.delegate = self; + self.showsHorizontalScrollIndicator = NO; + self.showsVerticalScrollIndicator = NO; + self.decelerationRate = UIScrollViewDecelerationRateFast; + self.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight; + + } + return self; +} + +- (void)dealloc { + [[NSNotificationCenter defaultCenter] removeObserver:self]; +} + +- (void)prepareForReuse { + [self hideImageFailure]; + self.photo = nil; + self.captionView = nil; + self.selectedButton = nil; + _photoImageView.image = nil; + _index = NSUIntegerMax; +} + +#pragma mark - Image + +- (void)setPhoto:(id)photo { + // Cancel any loading on old photo + if (_photo && photo == nil) { + if ([_photo respondsToSelector:@selector(cancelAnyLoading)]) { + [_photo cancelAnyLoading]; + } + } + _photo = photo; + UIImage *img = [_photoBrowser imageForPhoto:_photo]; + if (img) { + [self displayImage]; + } else { + // Will be loading so show loading + [self showLoadingIndicator]; + } +} + +// Get and display image +- (void)displayImage { + if (_photo && _photoImageView.image == nil) { + + // Reset + self.maximumZoomScale = 1; + self.minimumZoomScale = 1; + self.zoomScale = 1; + self.contentSize = CGSizeMake(0, 0); + + // Get image from browser as it handles ordering of fetching + UIImage *img = [_photoBrowser imageForPhoto:_photo]; + if (img) { + + // Hide indicator + [self hideLoadingIndicator]; + + // Set image + _photoImageView.image = img; + _photoImageView.hidden = NO; + + // Setup photo frame + CGRect photoImageViewFrame; + photoImageViewFrame.origin = CGPointZero; + photoImageViewFrame.size = img.size; + _photoImageView.frame = photoImageViewFrame; + self.contentSize = photoImageViewFrame.size; + + // Set zoom to minimum zoom + [self setMaxMinZoomScalesForCurrentBounds]; + + } else { + + // Failed no image + [self displayImageFailure]; + + } + [self setNeedsLayout]; + } +} + +// Image failed so just show black! +- (void)displayImageFailure { + [self hideLoadingIndicator]; + _photoImageView.image = nil; + if (!_loadingError) { + _loadingError = [UIImageView new]; + _loadingError.image = [UIImage imageNamed:@"MWPhotoBrowser.bundle/images/ImageError.png"]; + _loadingError.userInteractionEnabled = NO; + _loadingError.autoresizingMask = UIViewAutoresizingFlexibleLeftMargin | UIViewAutoresizingFlexibleTopMargin | + UIViewAutoresizingFlexibleBottomMargin | UIViewAutoresizingFlexibleRightMargin; + [_loadingError sizeToFit]; + [self addSubview:_loadingError]; + } + _loadingError.frame = CGRectMake(floorf((self.bounds.size.width - _loadingError.frame.size.width) / 2.), + floorf((self.bounds.size.height - _loadingError.frame.size.height) / 2), + _loadingError.frame.size.width, + _loadingError.frame.size.height); +} + +- (void)hideImageFailure { + if (_loadingError) { + [_loadingError removeFromSuperview]; + _loadingError = nil; + } +} + +#pragma mark - Loading Progress + +- (void)setProgressFromNotification:(NSNotification *)notification { + NSDictionary *dict = [notification object]; + id photoWithProgress = [dict objectForKey:@"photo"]; + if (photoWithProgress == self.photo) { + float progress = [[dict valueForKey:@"progress"] floatValue]; + _loadingIndicator.progress = MAX(MIN(1, progress), 0); + } +} + +- (void)hideLoadingIndicator { + _loadingIndicator.hidden = YES; +} + +- (void)showLoadingIndicator { + self.zoomScale = 0; + self.minimumZoomScale = 0; + self.maximumZoomScale = 0; + _loadingIndicator.progress = 0; + _loadingIndicator.hidden = NO; + [self hideImageFailure]; +} + +#pragma mark - Setup + +- (CGFloat)initialZoomScaleWithMinScale { + CGFloat zoomScale = self.minimumZoomScale; + if (_photoImageView && _photoBrowser.zoomPhotosToFill) { + // Zoom image to fill if the aspect ratios are fairly similar + CGSize boundsSize = self.bounds.size; + CGSize imageSize = _photoImageView.image.size; + CGFloat boundsAR = boundsSize.width / boundsSize.height; + CGFloat imageAR = imageSize.width / imageSize.height; + CGFloat xScale = boundsSize.width / imageSize.width; // the scale needed to perfectly fit the image width-wise + CGFloat yScale = boundsSize.height / imageSize.height; // the scale needed to perfectly fit the image height-wise + // Zooms standard portrait images on a 3.5in screen but not on a 4in screen. + if (ABS(boundsAR - imageAR) < 0.17) { + zoomScale = MAX(xScale, yScale); + // Ensure we don't zoom in or out too far, just in case + zoomScale = MIN(MAX(self.minimumZoomScale, zoomScale), self.maximumZoomScale); + } + } + return zoomScale; +} + +- (void)setMaxMinZoomScalesForCurrentBounds { + + // Reset + self.maximumZoomScale = 1; + self.minimumZoomScale = 1; + self.zoomScale = 1; + + // Bail if no image + if (_photoImageView.image == nil) return; + + // Reset position + _photoImageView.frame = CGRectMake(0, 0, _photoImageView.frame.size.width, _photoImageView.frame.size.height); + + // Sizes + CGSize boundsSize = self.bounds.size; + CGSize imageSize = _photoImageView.image.size; + + // Calculate Min + CGFloat xScale = boundsSize.width / imageSize.width; // the scale needed to perfectly fit the image width-wise + CGFloat yScale = boundsSize.height / imageSize.height; // the scale needed to perfectly fit the image height-wise + CGFloat minScale = MIN(xScale, yScale); // use minimum of these to allow the image to become fully visible + + // Calculate Max + CGFloat maxScale = 3; + if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad) { + // Let them go a bit bigger on a bigger screen! + maxScale = 4; + } + + // Image is smaller than screen so no zooming! + if (xScale >= 1 && yScale >= 1) { + minScale = 1.0; + } + + // Set min/max zoom + self.maximumZoomScale = maxScale; + self.minimumZoomScale = minScale; + + // Initial zoom + self.zoomScale = [self initialZoomScaleWithMinScale]; + + // If we're zooming to fill then centralise + if (self.zoomScale != minScale) { + // Centralise + self.contentOffset = CGPointMake((imageSize.width * self.zoomScale - boundsSize.width) / 2.0, + (imageSize.height * self.zoomScale - boundsSize.height) / 2.0); + // Disable scrolling initially until the first pinch to fix issues with swiping on an initally zoomed in photo + self.scrollEnabled = NO; + } + + // Layout + [self setNeedsLayout]; + +} + +#pragma mark - Layout + +- (void)layoutSubviews { + + // Update tap view frame + _tapView.frame = self.bounds; + + // Position indicators (centre does not seem to work!) + if (!_loadingIndicator.hidden) + _loadingIndicator.frame = CGRectMake(floorf((self.bounds.size.width - _loadingIndicator.frame.size.width) / 2.), + floorf((self.bounds.size.height - _loadingIndicator.frame.size.height) / 2), + _loadingIndicator.frame.size.width, + _loadingIndicator.frame.size.height); + if (_loadingError) + _loadingError.frame = CGRectMake(floorf((self.bounds.size.width - _loadingError.frame.size.width) / 2.), + floorf((self.bounds.size.height - _loadingError.frame.size.height) / 2), + _loadingError.frame.size.width, + _loadingError.frame.size.height); + + // Super + [super layoutSubviews]; + + // Center the image as it becomes smaller than the size of the screen + CGSize boundsSize = self.bounds.size; + CGRect frameToCenter = _photoImageView.frame; + + // Horizontally + if (frameToCenter.size.width < boundsSize.width) { + frameToCenter.origin.x = floorf((boundsSize.width - frameToCenter.size.width) / 2.0); + } else { + frameToCenter.origin.x = 0; + } + + // Vertically + if (frameToCenter.size.height < boundsSize.height) { + frameToCenter.origin.y = floorf((boundsSize.height - frameToCenter.size.height) / 2.0); + } else { + frameToCenter.origin.y = 0; + } + + // Center + if (!CGRectEqualToRect(_photoImageView.frame, frameToCenter)) + _photoImageView.frame = frameToCenter; + +} + +#pragma mark - UIScrollViewDelegate + +- (UIView *)viewForZoomingInScrollView:(UIScrollView *)scrollView { + return _photoImageView; +} + +- (void)scrollViewWillBeginDragging:(UIScrollView *)scrollView { + [_photoBrowser cancelControlHiding]; +} + +- (void)scrollViewWillBeginZooming:(UIScrollView *)scrollView withView:(UIView *)view { + self.scrollEnabled = YES; // reset + [_photoBrowser cancelControlHiding]; +} + +- (void)scrollViewDidEndDragging:(UIScrollView *)scrollView willDecelerate:(BOOL)decelerate { + [_photoBrowser hideControlsAfterDelay]; +} + +#pragma mark - Tap Detection + +- (void)handleSingleTap:(CGPoint)touchPoint { + [_photoBrowser performSelector:@selector(toggleControls) withObject:nil afterDelay:0.2]; +} + +- (void)handleDoubleTap:(CGPoint)touchPoint { + + // Cancel any single tap handling + [NSObject cancelPreviousPerformRequestsWithTarget:_photoBrowser]; + + // Zoom + if (self.zoomScale != self.minimumZoomScale && self.zoomScale != [self initialZoomScaleWithMinScale]) { + + // Zoom out + [self setZoomScale:self.minimumZoomScale animated:YES]; + + } else { + + // Zoom in to twice the size + CGFloat newZoomScale = ((self.maximumZoomScale + self.minimumZoomScale) / 2); + CGFloat xsize = self.bounds.size.width / newZoomScale; + CGFloat ysize = self.bounds.size.height / newZoomScale; + [self zoomToRect:CGRectMake(touchPoint.x - xsize/2, touchPoint.y - ysize/2, xsize, ysize) animated:YES]; + + } + + // Delay controls + [_photoBrowser hideControlsAfterDelay]; + +} + +// Image View +- (void)imageView:(UIImageView *)imageView singleTapDetected:(UITouch *)touch { + [self handleSingleTap:[touch locationInView:imageView]]; +} +- (void)imageView:(UIImageView *)imageView doubleTapDetected:(UITouch *)touch { + [self handleDoubleTap:[touch locationInView:imageView]]; +} + +// Background View +- (void)view:(UIView *)view singleTapDetected:(UITouch *)touch { + // Translate touch location to image view location + CGFloat touchX = [touch locationInView:view].x; + CGFloat touchY = [touch locationInView:view].y; + touchX *= 1/self.zoomScale; + touchY *= 1/self.zoomScale; + touchX += self.contentOffset.x; + touchY += self.contentOffset.y; + [self handleSingleTap:CGPointMake(touchX, touchY)]; +} +- (void)view:(UIView *)view doubleTapDetected:(UITouch *)touch { + // Translate touch location to image view location + CGFloat touchX = [touch locationInView:view].x; + CGFloat touchY = [touch locationInView:view].y; + touchX *= 1/self.zoomScale; + touchY *= 1/self.zoomScale; + touchX += self.contentOffset.x; + touchY += self.contentOffset.y; + [self handleDoubleTap:CGPointMake(touchX, touchY)]; +} + +@end diff --git a/ios/Pods/MWPhotoBrowser/MWPhotoBrowser/MWPhotoBrowser.bundle/images/Checkmark.png b/ios/Pods/MWPhotoBrowser/MWPhotoBrowser/MWPhotoBrowser.bundle/images/Checkmark.png new file mode 100755 index 000000000..89c31d3c2 Binary files /dev/null and b/ios/Pods/MWPhotoBrowser/MWPhotoBrowser/MWPhotoBrowser.bundle/images/Checkmark.png differ diff --git a/ios/Pods/MWPhotoBrowser/MWPhotoBrowser/MWPhotoBrowser.bundle/images/Checkmark@2x.png b/ios/Pods/MWPhotoBrowser/MWPhotoBrowser/MWPhotoBrowser.bundle/images/Checkmark@2x.png new file mode 100755 index 000000000..5ac8c212d Binary files /dev/null and b/ios/Pods/MWPhotoBrowser/MWPhotoBrowser/MWPhotoBrowser.bundle/images/Checkmark@2x.png differ diff --git a/ios/Pods/MWPhotoBrowser/MWPhotoBrowser/MWPhotoBrowser.bundle/images/ImageError.png b/ios/Pods/MWPhotoBrowser/MWPhotoBrowser/MWPhotoBrowser.bundle/images/ImageError.png new file mode 100644 index 000000000..eca298bc9 Binary files /dev/null and b/ios/Pods/MWPhotoBrowser/MWPhotoBrowser/MWPhotoBrowser.bundle/images/ImageError.png differ diff --git a/ios/Pods/MWPhotoBrowser/MWPhotoBrowser/MWPhotoBrowser.bundle/images/ImageError@2x.png b/ios/Pods/MWPhotoBrowser/MWPhotoBrowser/MWPhotoBrowser.bundle/images/ImageError@2x.png new file mode 100644 index 000000000..bc7ea2546 Binary files /dev/null and b/ios/Pods/MWPhotoBrowser/MWPhotoBrowser/MWPhotoBrowser.bundle/images/ImageError@2x.png differ diff --git a/ios/Pods/MWPhotoBrowser/MWPhotoBrowser/MWPhotoBrowser.bundle/images/ImageSelectedOff.png b/ios/Pods/MWPhotoBrowser/MWPhotoBrowser/MWPhotoBrowser.bundle/images/ImageSelectedOff.png new file mode 100644 index 000000000..9cc030bef Binary files /dev/null and b/ios/Pods/MWPhotoBrowser/MWPhotoBrowser/MWPhotoBrowser.bundle/images/ImageSelectedOff.png differ diff --git a/ios/Pods/MWPhotoBrowser/MWPhotoBrowser/MWPhotoBrowser.bundle/images/ImageSelectedOff@2x.png b/ios/Pods/MWPhotoBrowser/MWPhotoBrowser/MWPhotoBrowser.bundle/images/ImageSelectedOff@2x.png new file mode 100644 index 000000000..f989f6b19 Binary files /dev/null and b/ios/Pods/MWPhotoBrowser/MWPhotoBrowser/MWPhotoBrowser.bundle/images/ImageSelectedOff@2x.png differ diff --git a/ios/Pods/MWPhotoBrowser/MWPhotoBrowser/MWPhotoBrowser.bundle/images/ImageSelectedOn.png b/ios/Pods/MWPhotoBrowser/MWPhotoBrowser/MWPhotoBrowser.bundle/images/ImageSelectedOn.png new file mode 100644 index 000000000..f58548a43 Binary files /dev/null and b/ios/Pods/MWPhotoBrowser/MWPhotoBrowser/MWPhotoBrowser.bundle/images/ImageSelectedOn.png differ diff --git a/ios/Pods/MWPhotoBrowser/MWPhotoBrowser/MWPhotoBrowser.bundle/images/ImageSelectedOn@2x.png b/ios/Pods/MWPhotoBrowser/MWPhotoBrowser/MWPhotoBrowser.bundle/images/ImageSelectedOn@2x.png new file mode 100644 index 000000000..c4661bab4 Binary files /dev/null and b/ios/Pods/MWPhotoBrowser/MWPhotoBrowser/MWPhotoBrowser.bundle/images/ImageSelectedOn@2x.png differ diff --git a/ios/Pods/MWPhotoBrowser/MWPhotoBrowser/MWPhotoBrowser.bundle/images/ImageSelectedSmallOff.png b/ios/Pods/MWPhotoBrowser/MWPhotoBrowser/MWPhotoBrowser.bundle/images/ImageSelectedSmallOff.png new file mode 100644 index 000000000..1ce619b0d Binary files /dev/null and b/ios/Pods/MWPhotoBrowser/MWPhotoBrowser/MWPhotoBrowser.bundle/images/ImageSelectedSmallOff.png differ diff --git a/ios/Pods/MWPhotoBrowser/MWPhotoBrowser/MWPhotoBrowser.bundle/images/ImageSelectedSmallOff@2x.png b/ios/Pods/MWPhotoBrowser/MWPhotoBrowser/MWPhotoBrowser.bundle/images/ImageSelectedSmallOff@2x.png new file mode 100644 index 000000000..6b28c52a9 Binary files /dev/null and b/ios/Pods/MWPhotoBrowser/MWPhotoBrowser/MWPhotoBrowser.bundle/images/ImageSelectedSmallOff@2x.png differ diff --git a/ios/Pods/MWPhotoBrowser/MWPhotoBrowser/MWPhotoBrowser.bundle/images/ImageSelectedSmallOn.png b/ios/Pods/MWPhotoBrowser/MWPhotoBrowser/MWPhotoBrowser.bundle/images/ImageSelectedSmallOn.png new file mode 100644 index 000000000..b251b6cd3 Binary files /dev/null and b/ios/Pods/MWPhotoBrowser/MWPhotoBrowser/MWPhotoBrowser.bundle/images/ImageSelectedSmallOn.png differ diff --git a/ios/Pods/MWPhotoBrowser/MWPhotoBrowser/MWPhotoBrowser.bundle/images/ImageSelectedSmallOn@2x.png b/ios/Pods/MWPhotoBrowser/MWPhotoBrowser/MWPhotoBrowser.bundle/images/ImageSelectedSmallOn@2x.png new file mode 100644 index 000000000..5a8f6f8cc Binary files /dev/null and b/ios/Pods/MWPhotoBrowser/MWPhotoBrowser/MWPhotoBrowser.bundle/images/ImageSelectedSmallOn@2x.png differ diff --git a/ios/Pods/MWPhotoBrowser/MWPhotoBrowser/MWPhotoBrowser.bundle/images/UIBarButtonItemArrowLeft.png b/ios/Pods/MWPhotoBrowser/MWPhotoBrowser/MWPhotoBrowser.bundle/images/UIBarButtonItemArrowLeft.png new file mode 100644 index 000000000..4075997d9 Binary files /dev/null and b/ios/Pods/MWPhotoBrowser/MWPhotoBrowser/MWPhotoBrowser.bundle/images/UIBarButtonItemArrowLeft.png differ diff --git a/ios/Pods/MWPhotoBrowser/MWPhotoBrowser/MWPhotoBrowser.bundle/images/UIBarButtonItemArrowLeft@2x.png b/ios/Pods/MWPhotoBrowser/MWPhotoBrowser/MWPhotoBrowser.bundle/images/UIBarButtonItemArrowLeft@2x.png new file mode 100644 index 000000000..16c36ea36 Binary files /dev/null and b/ios/Pods/MWPhotoBrowser/MWPhotoBrowser/MWPhotoBrowser.bundle/images/UIBarButtonItemArrowLeft@2x.png differ diff --git a/ios/Pods/MWPhotoBrowser/MWPhotoBrowser/MWPhotoBrowser.bundle/images/UIBarButtonItemArrowOutlineLeft.png b/ios/Pods/MWPhotoBrowser/MWPhotoBrowser/MWPhotoBrowser.bundle/images/UIBarButtonItemArrowOutlineLeft.png new file mode 100644 index 000000000..412d996c9 Binary files /dev/null and b/ios/Pods/MWPhotoBrowser/MWPhotoBrowser/MWPhotoBrowser.bundle/images/UIBarButtonItemArrowOutlineLeft.png differ diff --git a/ios/Pods/MWPhotoBrowser/MWPhotoBrowser/MWPhotoBrowser.bundle/images/UIBarButtonItemArrowOutlineLeft@2x.png b/ios/Pods/MWPhotoBrowser/MWPhotoBrowser/MWPhotoBrowser.bundle/images/UIBarButtonItemArrowOutlineLeft@2x.png new file mode 100644 index 000000000..ace4d4cb8 Binary files /dev/null and b/ios/Pods/MWPhotoBrowser/MWPhotoBrowser/MWPhotoBrowser.bundle/images/UIBarButtonItemArrowOutlineLeft@2x.png differ diff --git a/ios/Pods/MWPhotoBrowser/MWPhotoBrowser/MWPhotoBrowser.bundle/images/UIBarButtonItemArrowOutlineRight.png b/ios/Pods/MWPhotoBrowser/MWPhotoBrowser/MWPhotoBrowser.bundle/images/UIBarButtonItemArrowOutlineRight.png new file mode 100644 index 000000000..4f9fe7766 Binary files /dev/null and b/ios/Pods/MWPhotoBrowser/MWPhotoBrowser/MWPhotoBrowser.bundle/images/UIBarButtonItemArrowOutlineRight.png differ diff --git a/ios/Pods/MWPhotoBrowser/MWPhotoBrowser/MWPhotoBrowser.bundle/images/UIBarButtonItemArrowOutlineRight@2x.png b/ios/Pods/MWPhotoBrowser/MWPhotoBrowser/MWPhotoBrowser.bundle/images/UIBarButtonItemArrowOutlineRight@2x.png new file mode 100644 index 000000000..d45324b10 Binary files /dev/null and b/ios/Pods/MWPhotoBrowser/MWPhotoBrowser/MWPhotoBrowser.bundle/images/UIBarButtonItemArrowOutlineRight@2x.png differ diff --git a/ios/Pods/MWPhotoBrowser/MWPhotoBrowser/MWPhotoBrowser.bundle/images/UIBarButtonItemArrowRight.png b/ios/Pods/MWPhotoBrowser/MWPhotoBrowser/MWPhotoBrowser.bundle/images/UIBarButtonItemArrowRight.png new file mode 100644 index 000000000..19109d33a Binary files /dev/null and b/ios/Pods/MWPhotoBrowser/MWPhotoBrowser/MWPhotoBrowser.bundle/images/UIBarButtonItemArrowRight.png differ diff --git a/ios/Pods/MWPhotoBrowser/MWPhotoBrowser/MWPhotoBrowser.bundle/images/UIBarButtonItemArrowRight@2x.png b/ios/Pods/MWPhotoBrowser/MWPhotoBrowser/MWPhotoBrowser.bundle/images/UIBarButtonItemArrowRight@2x.png new file mode 100644 index 000000000..55c43c730 Binary files /dev/null and b/ios/Pods/MWPhotoBrowser/MWPhotoBrowser/MWPhotoBrowser.bundle/images/UIBarButtonItemArrowRight@2x.png differ diff --git a/ios/Pods/MWPhotoBrowser/MWPhotoBrowser/MWPhotoBrowser.bundle/images/UIBarButtonItemGrid.png b/ios/Pods/MWPhotoBrowser/MWPhotoBrowser/MWPhotoBrowser.bundle/images/UIBarButtonItemGrid.png new file mode 100644 index 000000000..f3288035a Binary files /dev/null and b/ios/Pods/MWPhotoBrowser/MWPhotoBrowser/MWPhotoBrowser.bundle/images/UIBarButtonItemGrid.png differ diff --git a/ios/Pods/MWPhotoBrowser/MWPhotoBrowser/MWPhotoBrowser.bundle/images/UIBarButtonItemGrid@2x.png b/ios/Pods/MWPhotoBrowser/MWPhotoBrowser/MWPhotoBrowser.bundle/images/UIBarButtonItemGrid@2x.png new file mode 100644 index 000000000..4c4253092 Binary files /dev/null and b/ios/Pods/MWPhotoBrowser/MWPhotoBrowser/MWPhotoBrowser.bundle/images/UIBarButtonItemGrid@2x.png differ diff --git a/ios/Pods/MWPhotoBrowser/MWPhotoBrowser/MWPhotoBrowser.bundle/images/UIBarButtonItemGridiOS6.png b/ios/Pods/MWPhotoBrowser/MWPhotoBrowser/MWPhotoBrowser.bundle/images/UIBarButtonItemGridiOS6.png new file mode 100644 index 000000000..ac819d30e Binary files /dev/null and b/ios/Pods/MWPhotoBrowser/MWPhotoBrowser/MWPhotoBrowser.bundle/images/UIBarButtonItemGridiOS6.png differ diff --git a/ios/Pods/MWPhotoBrowser/MWPhotoBrowser/MWPhotoBrowser.bundle/images/UIBarButtonItemGridiOS6@2x.png b/ios/Pods/MWPhotoBrowser/MWPhotoBrowser/MWPhotoBrowser.bundle/images/UIBarButtonItemGridiOS6@2x.png new file mode 100644 index 000000000..ea4c99b57 Binary files /dev/null and b/ios/Pods/MWPhotoBrowser/MWPhotoBrowser/MWPhotoBrowser.bundle/images/UIBarButtonItemGridiOS6@2x.png differ diff --git a/ios/Pods/MWPhotoBrowser/README.md b/ios/Pods/MWPhotoBrowser/README.md new file mode 100644 index 000000000..97686ad51 --- /dev/null +++ b/ios/Pods/MWPhotoBrowser/README.md @@ -0,0 +1,223 @@ +# MWPhotoBrowser + +[![Flattr this git repo](http://api.flattr.com/button/flattr-badge-large.png)](https://flattr.com/submit/auto?user_id=mwaterfall&url=https://github.com/mwaterfall/MWPhotoBrowser&title=MWPhotoBrowser&language=&tags=github&category=software) + +## A simple iOS photo browser with optional grid view, captions and selections. + +MWPhotoBrowser can display one or more images by providing either `UIImage` objects, or URLs to files, web images or library assets. The photo browser handles the downloading and caching of photos from the web seamlessly. Photos can be zoomed and panned, and optional (customisable) captions can be displayed. + +The browser can also be used to allow the user to select one or more photos using either the grid or main image view. + +[![Alt][screenshot1_thumb]][screenshot1]    [![Alt][screenshot2_thumb]][screenshot2]    [![Alt][screenshot3_thumb]][screenshot3]    [![Alt][screenshot4_thumb]][screenshot4]    [![Alt][screenshot5_thumb]][screenshot5]    [![Alt][screenshot6_thumb]][screenshot6] + +[screenshot1_thumb]: https://raw.github.com/mwaterfall/MWPhotoBrowser/master/Preview/MWPhotoBrowser1t.png +[screenshot1]: https://raw.github.com/mwaterfall/MWPhotoBrowser/master/Preview/MWPhotoBrowser1.png +[screenshot2_thumb]: https://raw.github.com/mwaterfall/MWPhotoBrowser/master/Preview/MWPhotoBrowser2t.png +[screenshot2]: https://raw.github.com/mwaterfall/MWPhotoBrowser/master/Preview/MWPhotoBrowser2.png +[screenshot3_thumb]: https://raw.github.com/mwaterfall/MWPhotoBrowser/master/Preview/MWPhotoBrowser3t.png +[screenshot3]: https://raw.github.com/mwaterfall/MWPhotoBrowser/master/Preview/MWPhotoBrowser3.png +[screenshot4_thumb]: https://raw.github.com/mwaterfall/MWPhotoBrowser/master/Preview/MWPhotoBrowser4t.png +[screenshot4]: https://raw.github.com/mwaterfall/MWPhotoBrowser/master/Preview/MWPhotoBrowser4.png +[screenshot5_thumb]: https://raw.github.com/mwaterfall/MWPhotoBrowser/master/Preview/MWPhotoBrowser5t.png +[screenshot5]: https://raw.github.com/mwaterfall/MWPhotoBrowser/master/Preview/MWPhotoBrowser5.png +[screenshot6_thumb]: https://raw.github.com/mwaterfall/MWPhotoBrowser/master/Preview/MWPhotoBrowser6t.png +[screenshot6]: https://raw.github.com/mwaterfall/MWPhotoBrowser/master/Preview/MWPhotoBrowser6.png + +Works on iOS 5.1.1+. All strings are localisable so they can be used in apps that support multiple languages. + +## Usage + +MWPhotoBrowser is designed to be presented within a navigation controller. Simply set the delegate (which must conform to `MWPhotoBrowserDelegate`) and implement the 2 required delegate methods to provide the photo browser with the data in the form of `MWPhoto` objects. You can create an `MWPhoto` object by providing a `UIImage` object, or a URL containing the path to a file, an image online or an asset from the asset library. + +`MWPhoto` objects handle caching, file management, downloading of web images, and various optimisations for you. If however you would like to use your own data model to represent photos you can simply ensure your model conforms to the `MWPhoto` protocol. You can then handle the management of caching, downloads, etc, yourself. More information on this can be found in `MWPhotoProtocol.h`. + +See the code snippet below for an example of how to implement the photo browser. There is also a simple demo app within the project. + +```obj-c +// Create array of MWPhoto objects +self.photos = [NSMutableArray array]; +[photos addObject:[MWPhoto photoWithURL:[NSURL fileURLWithPath:[[NSBundle mainBundle] pathForResource:@"photo2l" ofType:@"jpg"]]]]; +[photos addObject:[MWPhoto photoWithURL:[NSURL URLWithString:@"http://farm4.static.flickr.com/3629/3339128908_7aecabc34b.jpg"]]]; +[photos addObject:[MWPhoto photoWithURL:[NSURL URLWithString:@"http://farm4.static.flickr.com/3590/3329114220_5fbc5bc92b.jpg"]]]; + +// Create browser (must be done each time photo browser is +// displayed. Photo browser objects cannot be re-used) +MWPhotoBrowser *browser = [[MWPhotoBrowser alloc] initWithDelegate:self]; + +// Set options +browser.displayActionButton = YES; // Show action button to allow sharing, copying, etc (defaults to YES) +browser.displayNavArrows = NO; // Whether to display left and right nav arrows on toolbar (defaults to NO) +browser.displaySelectionButtons = NO; // Whether selection buttons are shown on each image (defaults to NO) +browser.zoomPhotosToFill = YES; // Images that almost fill the screen will be initially zoomed to fill (defaults to YES) +browser.alwaysShowControls = NO; // Allows to control whether the bars and controls are always visible or whether they fade away to show the photo full (defaults to NO) +browser.enableGrid = YES; // Whether to allow the viewing of all the photo thumbnails on a grid (defaults to YES) +browser.startOnGrid = NO; // Whether to start on the grid of thumbnails instead of the first photo (defaults to NO) +browser.wantsFullScreenLayout = YES; // iOS 5 & 6 only: Decide if you want the photo browser full screen, i.e. whether the status bar is affected (defaults to YES) + +// Optionally set the current visible photo before displaying +[browser setCurrentPhotoIndex:1]; + +// Present +[self.navigationController pushViewController:browser animated:YES]; + +// Manipulate +[browser showNextPhotoAnimated:YES]; +[browser showPreviousPhotoAnimated:YES]; +[browser setCurrentPhotoIndex:10]; +``` + +Then respond to the required delegate methods: + +```obj-c +- (NSUInteger)numberOfPhotosInPhotoBrowser:(MWPhotoBrowser *)photoBrowser { + return self.photos.count; +} + +- (id )photoBrowser:(MWPhotoBrowser *)photoBrowser photoAtIndex:(NSUInteger)index { + if (index < self.photos.count) + return [self.photos objectAtIndex:index]; + return nil; +} +``` + +You can present the browser modally simply by wrapping it in a new navigation controller and presenting that. The demo app allows you to toggle between the two presentation types. + +If using iOS 5 or 6 and you don't want to view the photo browser full screen (for example if you are using view controller containment) then set the photo browser's `wantsFullScreenLayout` property to `NO`. This will mean the status bar will not be affected by the photo browser. + + +### Grid + +In order to properly show the grid of thumbnails, you must ensure the property `enableGrid` is set to `YES`, and implement the following delegate method: + +```obj-c +- (id )photoBrowser:(MWPhotoBrowser *)photoBrowser thumbPhotoAtIndex:(NSUInteger)index; +``` + +The photo browser can also start on the grid by enabling the `startOnGrid` property. + + +### Actions + +By default, if the action button is visible then the image (and caption if it exists) are sent to a UIActivityViewController. On iOS 5, a custom action sheet appears allowing them to copy or email the photo. + +You can provide a custom action by implementing the following delegate method: + +```obj-c +- (void)photoBrowser:(MWPhotoBrowser *)photoBrowser actionButtonPressedForPhotoAtIndex:(NSUInteger)index { + // Do your thing! +} +``` + + +### Photo Captions + +Photo captions can be displayed simply by setting the `caption` property on specific photos: + +```obj-c +MWPhoto *photo = [MWPhoto photoWithURL:[NSURL URLWithString:@"http://farm4.static.flickr.com/3629/3339128908_7aecabc34b.jpg"]]; +photo.caption = @"Campervan"; +``` + +No caption will be displayed if the caption property is not set. + + +#### Custom Captions + +By default, the caption is a simple black transparent view with a label displaying the photo's caption in white. If you want to implement your own caption view, follow these steps: + +1. Optionally use a subclass of `MWPhoto` for your photos so you can store more data than a simple caption string. +2. Subclass `MWCaptionView` and override `-setupCaption` and `-sizeThatFits:` (and any other UIView methods you see fit) to layout your own view and set it's size. More information on this can be found in `MWCaptionView.h` +3. Implement the `-photoBrowser:captionViewForPhotoAtIndex:` MWPhotoBrowser delegate method (shown below). + +Example delegate method for custom caption view: + +```obj-c +- (MWCaptionView *)photoBrowser:(MWPhotoBrowser *)photoBrowser captionViewForPhotoAtIndex:(NSUInteger)index { + MWPhoto *photo = [self.photos objectAtIndex:index]; + MyMWCaptionViewSubclass *captionView = [[MyMWCaptionViewSubclass alloc] initWithPhoto:photo]; + return captionView; +} +``` + + +#### Selections + +The photo browser can display check boxes allowing the user to select one or more of the photos. To use this feature, simply enable the `displaySelectionButtons` property, and implement the following delegate methods: + +```obj-c +- (BOOL)photoBrowser:(MWPhotoBrowser *)photoBrowser isPhotoSelectedAtIndex:(NSUInteger)index { + return [[_selections objectAtIndex:index] boolValue]; +} + +- (void)photoBrowser:(MWPhotoBrowser *)photoBrowser photoAtIndex:(NSUInteger)index selectedChanged:(BOOL)selected { + [_selections replaceObjectAtIndex:index withObject:[NSNumber numberWithBool:selected]]; +} +``` + + +## Adding to your project + +### Method 1: Use CocoaPods + +[CocoaPods](http://cocoapods.org) is great. If you are using CocoaPods ([and here's how to get started](http://guides.cocoapods.org/using/using-cocoapods.html)), simply add `pod 'MWPhotoBrowser'` to your podfile and run `pod install`. You're good to go! Here's an example podfile: + +``` +platform :ios, '7' + pod 'MWPhotoBrowser' +``` + + +### Method 2: Static Library + +1. Get the latest source from GitHub by either [downloading as a zip file](https://github.com/mwaterfall/MWPhotoBrowser/zipball/master) or by cloning the repository at `git://github.com/mwaterfall/MWPhotoBrowser.git` and store the code wherever you wish. +2. Right-click on the your project in the navigator, click "Add Files to 'Your Project'", and browse to and select "MWPhotoBrowser.xcodeproj" +3. In your project's target settings, go to "Build Phases" -> "Link Binary With Libraries" and add `libMWPhotoBrowser.a`. +4. Still in "Build Phases", drop down "Copy Bundle Resources" and drag the file `MWPhotoBrowser.bundle` from the MWPhotoBrowser project into that list. This ensures your project will include the required graphics for the photo browser to work correctly. +5. In the target, select the "Build Settings" tab and ensure "Always Search User Paths" is set to YES, and "User Header Search Paths" is set to the recursive absolute or relative path that points to a directory under which the MWPhotoBrowser code is stored. In the file layout of the MWPhotoBrowser project, a simple ../** works as the demo project folder and MWPhotoBrowser project folder are adjacent to one another. Please let me know if you encounter any issue with this. +6. Under "Build Phases / Link Binary With Libraries" add `MessageUI.framework`, `QuartzCore.framework`, `AssetsLibrary.framework` and `ImageIO.framework` to "Linked Frameworks and Libraries". + +You should now be able to include `MWPhotoBrowser.h` into your project and start using it. + +Setting these things up in Xcode can be a bit tricky so if you run into any problems you may wish to read through a few bits of information: + +- [Developing a Static Library and Incorporating It in Your Application](http://developer.apple.com/library/ios/#documentation/Xcode/Conceptual/ios_development_workflow/910-A-Developing_a_Static_Library_and_Incorporating_It_in_Your_Application/archiving_an_application_that_uses_a_static_library.html) +- [Using Open Source Static Libraries in Xcode 4](http://blog.carbonfive.com/2011/04/04/using-open-source-static-libraries-in-xcode-4/#using_a_static_library) +- [How to embed static library into Xcode 4 project](https://docs.google.com/document/pub?id=14XR5zcZb2Kz2s6A4AbzB00NLkrW9bWxMMprVsUao-hY) + +### Method 3: Including Source Directly Into Your Project + +Another method is to simply add the files to your Xcode project, copying them to your project's directory if required. Ensure that all the code within `MWPhotoBrowser/Classes`, `MWPhotoBrowser/Libraries` and the `MWPhotoBrowser.bundle` is included in your project. + + +## Notes and Accreditation + +MWPhotoBrowser very gratefully makes use of these other fantastic open source projects: + +- [SDWebImage](https://github.com/rs/SDWebImage) by Olivier Poitrey — Used to handle downloading and decompressing of photos from the web. +- [MBProgressHUD](https://github.com/jdg/MBProgressHUD) by Jonathan George — Used to display activity notifications. +- [DACircularProgress](https://github.com/danielamitay/DACircularProgress) by Daniel Amitay — Used to display image download progress. + +Demo photos kindly provided by Oliver Waters (). + + +## Licence + +Copyright (c) 2010 Michael Waterfall + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. \ No newline at end of file diff --git a/ios/Pods/Manifest.lock b/ios/Pods/Manifest.lock new file mode 100644 index 000000000..fdc80e2a7 --- /dev/null +++ b/ios/Pods/Manifest.lock @@ -0,0 +1,70 @@ +PODS: + - AFNetworking (2.3.1): + - AFNetworking/NSURLConnection (= 2.3.1) + - AFNetworking/NSURLSession (= 2.3.1) + - AFNetworking/Reachability (= 2.3.1) + - AFNetworking/Security (= 2.3.1) + - AFNetworking/Serialization (= 2.3.1) + - AFNetworking/UIKit (= 2.3.1) + - AFNetworking/NSURLConnection (2.3.1): + - AFNetworking/Reachability + - AFNetworking/Security + - AFNetworking/Serialization + - AFNetworking/NSURLSession (2.3.1): + - AFNetworking/Reachability + - AFNetworking/Security + - AFNetworking/Serialization + - AFNetworking/Reachability (2.3.1) + - AFNetworking/Security (2.3.1) + - AFNetworking/Serialization (2.3.1) + - AFNetworking/UIKit (2.3.1): + - AFNetworking/NSURLConnection + - AFNetworking/NSURLSession + - DACircularProgress (2.2.0) + - FMDB (2.4): + - FMDB/standard (= 2.4) + - FMDB/common (2.4) + - FMDB/standard (2.4): + - FMDB/common + - HPGrowingTextView (1.1) + - leveldb-library (1.18.1) + - MBProgressHUD (0.9) + - MWPhotoBrowser (1.4.1): + - DACircularProgress + - MBProgressHUD (~> 0.8) + - PSTCollectionView (~> 1.2) + - SDWebImage (~> 3.7) + - ProtocolBuffers (1.9.3) + - PSTCollectionView (1.2.3) + - SCLAlertView-Objective-C (0.3.7) + - SDWebImage (3.7.1): + - SDWebImage/Core (= 3.7.1) + - SDWebImage/Core (3.7.1) + +DEPENDENCIES: + - AFNetworking (~> 2.3.0) + - DACircularProgress (~> 2.2.0) + - FMDB (~> 2.3) + - HPGrowingTextView (~> 1.1) + - leveldb-library (~> 1.18.1) + - MBProgressHUD (~> 0.8) + - MWPhotoBrowser (~> 1.4.1) + - ProtocolBuffers (= 1.9.3) + - PSTCollectionView (~> 1.2.1) + - SCLAlertView-Objective-C (~> 0.3.7) + - SDWebImage (~> 3.6) + +SPEC CHECKSUMS: + AFNetworking: 6d7b76aa5d04c8c37daad3eef4b7e3f2a7620da3 + DACircularProgress: 3b41941891a56dc6aa17971f5322a9a38a6f446e + FMDB: 0b2fa25e5264ef177973c0cb8c02c711107979aa + HPGrowingTextView: 07d5ab1f1e867acfb7a6f498b819948c9e97d07c + leveldb-library: 27d1c7bf65f324cc6f57e06fa9be32f02ac2b700 + MBProgressHUD: 2038dbcf3dce73215abed6001657043d53aa79a8 + MWPhotoBrowser: be05b3b7521e961382a4ba5579685bf5a00b93d8 + ProtocolBuffers: e80f9e4fc401aec9d3c30be70db87fcd5f1cb880 + PSTCollectionView: d9f466e4554cc83260ca9bde7beb27f308e8fd76 + SCLAlertView-Objective-C: 0f05aadaf5388ec44a06a4271e99cd871830246a + SDWebImage: 116e88633b5b416ea0ca4b334a4ac59cf72dd38d + +COCOAPODS: 0.35.0 diff --git a/ios/Pods/PSTCollectionView/LICENSE b/ios/Pods/PSTCollectionView/LICENSE new file mode 100644 index 000000000..6614c6994 --- /dev/null +++ b/ios/Pods/PSTCollectionView/LICENSE @@ -0,0 +1,19 @@ +Copyright (c) 2012-2013 Peter Steinberger + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is furnished +to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. diff --git a/ios/Pods/PSTCollectionView/PSTCollectionView/NSIndexPath+PSTCollectionViewAdditions.h b/ios/Pods/PSTCollectionView/PSTCollectionView/NSIndexPath+PSTCollectionViewAdditions.h new file mode 100644 index 000000000..1fe930dbe --- /dev/null +++ b/ios/Pods/PSTCollectionView/PSTCollectionView/NSIndexPath+PSTCollectionViewAdditions.h @@ -0,0 +1,20 @@ +// +// NSIndexPath+PSTCollectionViewAdditions.h +// PSTCollectionView +// +// Copyright (c) 2013 Peter Steinberger. All rights reserved. +// + +#import + +#if __IPHONE_OS_VERSION_MIN_REQUIRED < 60000 + +@interface NSIndexPath (PSTCollectionViewAdditions) + ++ (NSIndexPath *)indexPathForItem:(NSInteger)item inSection:(NSInteger)section; + +- (NSInteger)item; + +@end + +#endif diff --git a/ios/Pods/PSTCollectionView/PSTCollectionView/NSIndexPath+PSTCollectionViewAdditions.m b/ios/Pods/PSTCollectionView/PSTCollectionView/NSIndexPath+PSTCollectionViewAdditions.m new file mode 100644 index 000000000..92b9f3939 --- /dev/null +++ b/ios/Pods/PSTCollectionView/PSTCollectionView/NSIndexPath+PSTCollectionViewAdditions.m @@ -0,0 +1,25 @@ +// +// NSIndexPath+PSTCollectionViewAdditions.m +// PSTCollectionView +// +// Copyright (c) 2013 Peter Steinberger. All rights reserved. +// + +#import "NSIndexPath+PSTCollectionViewAdditions.h" + +#if __IPHONE_OS_VERSION_MIN_REQUIRED < 60000 + +@implementation NSIndexPath (PSTCollectionViewAdditions) + +// Simple NSIndexPath addition to allow using "item" instead of "row". ++ (NSIndexPath *)indexPathForItem:(NSInteger)item inSection:(NSInteger)section { + return [NSIndexPath indexPathForRow:item inSection:section]; +} + +- (NSInteger)item { + return self.row; +} + +@end + +#endif diff --git a/ios/Pods/PSTCollectionView/PSTCollectionView/PSTCollectionView.h b/ios/Pods/PSTCollectionView/PSTCollectionView/PSTCollectionView.h new file mode 100644 index 000000000..8dd1216fc --- /dev/null +++ b/ios/Pods/PSTCollectionView/PSTCollectionView/PSTCollectionView.h @@ -0,0 +1,136 @@ +// +// PSTCollectionView.h +// PSPDFKit +// +// Copyright (c) 2012-2013 Peter Steinberger. All rights reserved. +// + +#import "PSTCollectionViewLayout.h" +#import "PSTCollectionViewFlowLayout.h" +#import "PSTCollectionViewCell.h" +#import "PSTCollectionViewController.h" +#import "PSTCollectionViewUpdateItem.h" + +@class PSTCollectionViewController; + +typedef NS_OPTIONS(NSUInteger, PSTCollectionViewScrollPosition) { + PSTCollectionViewScrollPositionNone = 0, + + // The vertical positions are mutually exclusive to each other, but are bitwise or-able with the horizontal scroll positions. + // Combining positions from the same grouping (horizontal or vertical) will result in an NSInvalidArgumentException. + PSTCollectionViewScrollPositionTop = 1 << 0, + PSTCollectionViewScrollPositionCenteredVertically = 1 << 1, + PSTCollectionViewScrollPositionBottom = 1 << 2, + + // Likewise, the horizontal positions are mutually exclusive to each other. + PSTCollectionViewScrollPositionLeft = 1 << 3, + PSTCollectionViewScrollPositionCenteredHorizontally = 1 << 4, + PSTCollectionViewScrollPositionRight = 1 << 5 +}; + +typedef NS_ENUM(NSUInteger, PSTCollectionElementCategory) { + PSTCollectionElementCategoryCell, + PSTCollectionElementCategorySupplementaryView, + PSTCollectionElementCategoryDecorationView +}; + +// Define the `PSTCollectionViewDisableForwardToUICollectionViewSentinel` to disable the automatic forwarding to UICollectionView on iOS 6+. (Copy below line into your AppDelegate.m) +//@interface PSTCollectionViewDisableForwardToUICollectionViewSentinel : NSObject @end @implementation PSTCollectionViewDisableForwardToUICollectionViewSentinel @end + +// API-compatible replacement for UICollectionView. +// Works on iOS 4.3 upwards (including iOS 6). +@interface PSTCollectionView : UIScrollView + +- (id)initWithFrame:(CGRect)frame collectionViewLayout:(PSTCollectionViewLayout *)layout; // the designated initializer + +@property (nonatomic, strong) PSTCollectionViewLayout *collectionViewLayout; +@property (nonatomic, assign) IBOutlet id delegate; +@property (nonatomic, assign) IBOutlet id dataSource; +@property (nonatomic, strong) UIView *backgroundView; // will be automatically resized to track the size of the collection view and placed behind all cells and supplementary views. + +// For each reuse identifier that the collection view will use, register either a class or a nib from which to instantiate a cell. +// If a nib is registered, it must contain exactly 1 top level object which is a PSTCollectionViewCell. +// If a class is registered, it will be instantiated via alloc/initWithFrame: +- (void)registerClass:(Class)cellClass forCellWithReuseIdentifier:(NSString *)identifier; + +- (void)registerClass:(Class)viewClass forSupplementaryViewOfKind:(NSString *)elementKind withReuseIdentifier:(NSString *)identifier; + +- (void)registerNib:(UINib *)nib forCellWithReuseIdentifier:(NSString *)identifier; + +// TODO: implement! +- (void)registerNib:(UINib *)nib forSupplementaryViewOfKind:(NSString *)kind withReuseIdentifier:(NSString *)identifier; + +- (id)dequeueReusableCellWithReuseIdentifier:(NSString *)identifier forIndexPath:(NSIndexPath *)indexPath; + +- (id)dequeueReusableSupplementaryViewOfKind:(NSString *)elementKind withReuseIdentifier:(NSString *)identifier forIndexPath:(NSIndexPath *)indexPath; + +// These properties control whether items can be selected, and if so, whether multiple items can be simultaneously selected. +@property (nonatomic) BOOL allowsSelection; // default is YES +@property (nonatomic) BOOL allowsMultipleSelection; // default is NO + +- (NSArray *)indexPathsForSelectedItems; // returns nil or an array of selected index paths +- (void)selectItemAtIndexPath:(NSIndexPath *)indexPath animated:(BOOL)animated scrollPosition:(PSTCollectionViewScrollPosition)scrollPosition; + +- (void)deselectItemAtIndexPath:(NSIndexPath *)indexPath animated:(BOOL)animated; + +- (void)reloadData; // discard the dataSource and delegate data and requery as necessary + +- (void)setCollectionViewLayout:(PSTCollectionViewLayout *)layout animated:(BOOL)animated; // transition from one layout to another + +// Information about the current state of the collection view. + +- (NSInteger)numberOfSections; + +- (NSInteger)numberOfItemsInSection:(NSInteger)section; + +- (PSTCollectionViewLayoutAttributes *)layoutAttributesForItemAtIndexPath:(NSIndexPath *)indexPath; + +- (PSTCollectionViewLayoutAttributes *)layoutAttributesForSupplementaryElementOfKind:(NSString *)kind atIndexPath:(NSIndexPath *)indexPath; + +- (NSIndexPath *)indexPathForItemAtPoint:(CGPoint)point; + +- (NSIndexPath *)indexPathForCell:(PSTCollectionViewCell *)cell; + +- (PSTCollectionViewCell *)cellForItemAtIndexPath:(NSIndexPath *)indexPath; + +- (NSArray *)visibleCells; + +- (NSArray *)indexPathsForVisibleItems; + +// Interacting with the collection view. + +- (void)scrollToItemAtIndexPath:(NSIndexPath *)indexPath atScrollPosition:(PSTCollectionViewScrollPosition)scrollPosition animated:(BOOL)animated; + +// These methods allow dynamic modification of the current set of items in the collection view +- (void)insertSections:(NSIndexSet *)sections; +- (void)deleteSections:(NSIndexSet *)sections; +- (void)reloadSections:(NSIndexSet *)sections; +- (void)moveSection:(NSInteger)section toSection:(NSInteger)newSection; +- (void)insertItemsAtIndexPaths:(NSArray *)indexPaths; +- (void)deleteItemsAtIndexPaths:(NSArray *)indexPaths; +- (void)reloadItemsAtIndexPaths:(NSArray *)indexPaths; +- (void)moveItemAtIndexPath:(NSIndexPath *)indexPath toIndexPath:(NSIndexPath *)newIndexPath; +- (void)performBatchUpdates:(void (^)(void))updates completion:(void (^)(BOOL finished))completion; // allows multiple insert/delete/reload/move calls to be animated simultaneously. Nestable. + +@end + +// To dynamically switch between PSTCollectionView and UICollectionView, use the PSUICollectionView* classes. +#define PSUICollectionView PSUICollectionView_ +#define PSUICollectionViewCell PSUICollectionViewCell_ +#define PSUICollectionReusableView PSUICollectionReusableView_ +#define PSUICollectionViewDelegate PSTCollectionViewDelegate +#define PSUICollectionViewDataSource PSTCollectionViewDataSource +#define PSUICollectionViewLayout PSUICollectionViewLayout_ +#define PSUICollectionViewFlowLayout PSUICollectionViewFlowLayout_ +#define PSUICollectionViewDelegateFlowLayout PSTCollectionViewDelegateFlowLayout +#define PSUICollectionViewLayoutAttributes PSUICollectionViewLayoutAttributes_ +#define PSUICollectionViewController PSUICollectionViewController_ + +@interface PSUICollectionView_ : PSTCollectionView @end +@interface PSUICollectionViewCell_ : PSTCollectionViewCell @end +@interface PSUICollectionReusableView_ : PSTCollectionReusableView @end +@interface PSUICollectionViewLayout_ : PSTCollectionViewLayout @end +@interface PSUICollectionViewFlowLayout_ : PSTCollectionViewFlowLayout @end +@protocol PSUICollectionViewDelegateFlowLayout_ @end +@interface PSUICollectionViewLayoutAttributes_ : PSTCollectionViewLayoutAttributes @end +@interface PSUICollectionViewController_ : PSTCollectionViewController @end diff --git a/ios/Pods/PSTCollectionView/PSTCollectionView/PSTCollectionView.m b/ios/Pods/PSTCollectionView/PSTCollectionView/PSTCollectionView.m new file mode 100644 index 000000000..bac662f36 --- /dev/null +++ b/ios/Pods/PSTCollectionView/PSTCollectionView/PSTCollectionView.m @@ -0,0 +1,2311 @@ +// +// PSTCollectionView.m +// PSPDFKit +// +// Copyright (c) 2012-2013 Peter Steinberger. All rights reserved. +// + +#import "PSTCollectionView.h" +#import "PSTCollectionViewData.h" +#import "PSTCollectionViewLayout+Internals.h" +#import "PSTCollectionViewItemKey.h" + +#import +#if TARGET_IPHONE_SIMULATOR +#import +#endif +#import + +@interface PSTCollectionViewLayout (Internal) +@property (nonatomic, unsafe_unretained) PSTCollectionView *collectionView; +@end + +@interface PSTCollectionViewData (Internal) +- (void)prepareToLoadData; +@end + +@interface PSTCollectionViewCell (Internal) +- (void)performSelectionSegue; +@end + +@interface PSTCollectionViewUpdateItem () +- (NSIndexPath *)indexPath; + +- (BOOL)isSectionOperation; +@end + +@interface PSTCollectionViewLayoutAttributes () { + char junk[128]; +} +@property (nonatomic, copy) NSString *elementKind; +@end + +CGFloat PSTSimulatorAnimationDragCoefficient(void); + +@class PSTCollectionViewExt; + +@interface PSTCollectionView () { + // ivar layout needs to EQUAL to UICollectionView. + PSTCollectionViewLayout *_layout; + __unsafe_unretained id _dataSource; + UIView *_backgroundView; + NSMutableSet *_indexPathsForSelectedItems; + NSMutableDictionary *_cellReuseQueues; + NSMutableDictionary *_supplementaryViewReuseQueues; + NSMutableDictionary *_decorationViewReuseQueues; + NSMutableSet *_indexPathsForHighlightedItems; + int _reloadingSuspendedCount; + PSTCollectionReusableView *_firstResponderView; + UIView *_newContentView; + int _firstResponderViewType; + NSString *_firstResponderViewKind; + NSIndexPath *_firstResponderIndexPath; + NSMutableDictionary *_allVisibleViewsDict; + NSIndexPath *_pendingSelectionIndexPath; + NSMutableSet *_pendingDeselectionIndexPaths; + PSTCollectionViewData *_collectionViewData; + id _update; + CGRect _visibleBoundRects; + CGRect _preRotationBounds; + CGPoint _rotationBoundsOffset; + int _rotationAnimationCount; + int _updateCount; + NSMutableArray *_insertItems; + NSMutableArray *_deleteItems; + NSMutableArray *_reloadItems; + NSMutableArray *_moveItems; + NSArray *_originalInsertItems; + NSArray *_originalDeleteItems; + UITouch *_currentTouch; + + void (^_updateCompletionHandler)(BOOL finished); + + NSMutableDictionary *_cellClassDict; + NSMutableDictionary *_cellNibDict; + NSMutableDictionary *_supplementaryViewClassDict; + NSMutableDictionary *_supplementaryViewNibDict; + NSMutableDictionary *_cellNibExternalObjectsTables; + NSMutableDictionary *_supplementaryViewNibExternalObjectsTables; + struct { + unsigned int delegateShouldHighlightItemAtIndexPath : 1; + unsigned int delegateDidHighlightItemAtIndexPath : 1; + unsigned int delegateDidUnhighlightItemAtIndexPath : 1; + unsigned int delegateShouldSelectItemAtIndexPath : 1; + unsigned int delegateShouldDeselectItemAtIndexPath : 1; + unsigned int delegateDidSelectItemAtIndexPath : 1; + unsigned int delegateDidDeselectItemAtIndexPath : 1; + unsigned int delegateSupportsMenus : 1; + unsigned int delegateDidEndDisplayingCell : 1; + unsigned int delegateDidEndDisplayingSupplementaryView : 1; + unsigned int dataSourceNumberOfSections : 1; + unsigned int dataSourceViewForSupplementaryElement : 1; + unsigned int reloadSkippedDuringSuspension : 1; + unsigned int scheduledUpdateVisibleCells : 1; + unsigned int scheduledUpdateVisibleCellLayoutAttributes : 1; + unsigned int allowsSelection : 1; + unsigned int allowsMultipleSelection : 1; + unsigned int updating : 1; + unsigned int fadeCellsForBoundsChange : 1; + unsigned int updatingLayout : 1; + unsigned int needsReload : 1; + unsigned int reloading : 1; + unsigned int skipLayoutDuringSnapshotting : 1; + unsigned int layoutInvalidatedSinceLastCellUpdate : 1; + unsigned int doneFirstLayout : 1; + }_collectionViewFlags; + CGPoint _lastLayoutOffset; + char filler[232]; // [HACK] Our class needs to be larger than Apple's class for the superclass change to work. +} +@property (nonatomic, strong) PSTCollectionViewData *collectionViewData; +@property (nonatomic, strong, readonly) PSTCollectionViewExt *extVars; +@property (nonatomic, readonly) id currentUpdate; +@property (nonatomic, readonly) NSDictionary *visibleViewsDict; +@property (nonatomic, assign) CGRect visibleBoundRects; +@end + +// Used by PSTCollectionView for external variables. +// (We need to keep the total class size equal to the UICollectionView variant) +@interface PSTCollectionViewExt : NSObject +@property (nonatomic, unsafe_unretained) id collectionViewDelegate; +@property (nonatomic, strong) PSTCollectionViewLayout *nibLayout; +@property (nonatomic, strong) NSDictionary *nibCellsExternalObjects; +@property (nonatomic, strong) NSDictionary *supplementaryViewsExternalObjects; +@property (nonatomic, strong) NSIndexPath *touchingIndexPath; +@property (nonatomic, strong) NSIndexPath *currentIndexPath; +@end + +@implementation PSTCollectionViewExt +@end + +const char kPSTColletionViewExt; + +@implementation PSTCollectionView + +@synthesize collectionViewLayout = _layout; +@synthesize currentUpdate = _update; +@synthesize visibleViewsDict = _allVisibleViewsDict; + +/////////////////////////////////////////////////////////////////////////////////////////// +#pragma mark - NSObject + +static void PSTCollectionViewCommonSetup(PSTCollectionView *_self) { + _self.allowsSelection = YES; + _self->_indexPathsForSelectedItems = [NSMutableSet new]; + _self->_indexPathsForHighlightedItems = [NSMutableSet new]; + _self->_cellReuseQueues = [NSMutableDictionary new]; + _self->_supplementaryViewReuseQueues = [NSMutableDictionary new]; + _self->_decorationViewReuseQueues = [NSMutableDictionary new]; + _self->_allVisibleViewsDict = [NSMutableDictionary new]; + _self->_cellClassDict = [NSMutableDictionary new]; + _self->_cellNibDict = [NSMutableDictionary new]; + _self->_supplementaryViewClassDict = [NSMutableDictionary new]; + _self->_supplementaryViewNibDict = [NSMutableDictionary new]; + + // add class that saves additional ivars + objc_setAssociatedObject(_self, &kPSTColletionViewExt, [PSTCollectionViewExt new], OBJC_ASSOCIATION_RETAIN_NONATOMIC); +} + +- (id)initWithFrame:(CGRect)frame { + return [self initWithFrame:frame collectionViewLayout:nil]; +} + +- (id)initWithFrame:(CGRect)frame collectionViewLayout:(PSTCollectionViewLayout *)layout { + if ((self = [super initWithFrame:frame])) { + // Set self as the UIScrollView's delegate + [super setDelegate:self]; + + PSTCollectionViewCommonSetup(self); + self.collectionViewLayout = layout; + _collectionViewData = [[PSTCollectionViewData alloc] initWithCollectionView:self layout:layout]; + } + return self; +} + +- (id)initWithCoder:(NSCoder *)inCoder { + if ((self = [super initWithCoder:inCoder])) { + // Set self as the UIScrollView's delegate + [super setDelegate:self]; + + PSTCollectionViewCommonSetup(self); + + self.extVars.nibLayout = [inCoder decodeObjectForKey:@"UICollectionLayout"]; + + NSDictionary *cellExternalObjects = [inCoder decodeObjectForKey:@"UICollectionViewCellPrototypeNibExternalObjects"]; + NSDictionary *cellNibs = [inCoder decodeObjectForKey:@"UICollectionViewCellNibDict"]; + + for (NSString *identifier in cellNibs.allKeys) { + _cellNibDict[identifier] = cellNibs[identifier]; + } + + self.extVars.nibCellsExternalObjects = cellExternalObjects; + + NSDictionary *supplementaryViewExternalObjects = [inCoder decodeObjectForKey:@"UICollectionViewSupplementaryViewPrototypeNibExternalObjects"]; + NSDictionary *supplementaryViewNibs = [inCoder decodeObjectForKey:@"UICollectionViewSupplementaryViewNibDict"]; + + for (NSString *identifier in supplementaryViewNibs.allKeys) { + _supplementaryViewNibDict[identifier] = supplementaryViewNibs[identifier]; + } + + self.extVars.supplementaryViewsExternalObjects = supplementaryViewExternalObjects; + } + return self; +} + +- (void)awakeFromNib { + [super awakeFromNib]; + + PSTCollectionViewLayout *nibLayout = self.extVars.nibLayout; + if (nibLayout) { + self.collectionViewLayout = nibLayout; + self.extVars.nibLayout = nil; + } +} + +- (NSString *)description { + return [NSString stringWithFormat:@"%@ collection view layout: %@", [super description], self.collectionViewLayout]; +} + +/////////////////////////////////////////////////////////////////////////////////////////// +#pragma mark - UIView + +- (void)layoutSubviews { + [super layoutSubviews]; + + // Adding alpha animation to make the relayouting smooth + if (_collectionViewFlags.fadeCellsForBoundsChange) { + CATransition *transition = [CATransition animation]; + transition.duration = 0.25f * PSTSimulatorAnimationDragCoefficient(); + transition.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut]; + transition.type = kCATransitionFade; + [self.layer addAnimation:transition forKey:@"rotationAnimation"]; + } + + [_collectionViewData validateLayoutInRect:self.bounds]; + + // update cells + if (_collectionViewFlags.fadeCellsForBoundsChange) { + [CATransaction begin]; + [CATransaction setDisableActions:YES]; + } + + if (!_collectionViewFlags.updatingLayout) + [self updateVisibleCellsNow:YES]; + + if (_collectionViewFlags.fadeCellsForBoundsChange) { + [CATransaction commit]; + } + + // do we need to update contentSize? + CGSize contentSize = [_collectionViewData collectionViewContentRect].size; + if (!CGSizeEqualToSize(self.contentSize, contentSize)) { + self.contentSize = contentSize; + + // if contentSize is different, we need to re-evaluate layout, bounds (contentOffset) might changed + [_collectionViewData validateLayoutInRect:self.bounds]; + [self updateVisibleCellsNow:YES]; + } + + if (_backgroundView) { + _backgroundView.frame = (CGRect){.origin=self.contentOffset, .size=self.bounds.size}; + } + + _collectionViewFlags.fadeCellsForBoundsChange = NO; + _collectionViewFlags.doneFirstLayout = YES; +} + +- (void)setFrame:(CGRect)frame { + if (!CGRectEqualToRect(frame, self.frame)) { + CGRect bounds = (CGRect){.origin=self.contentOffset, .size=frame.size}; + BOOL shouldInvalidate = [self.collectionViewLayout shouldInvalidateLayoutForBoundsChange:bounds]; + [super setFrame:frame]; + if (shouldInvalidate) { + [self invalidateLayout]; + _collectionViewFlags.fadeCellsForBoundsChange = YES; + } + } +} + +- (void)setBounds:(CGRect)bounds { + if (!CGRectEqualToRect(bounds, self.bounds)) { + BOOL shouldInvalidate = [self.collectionViewLayout shouldInvalidateLayoutForBoundsChange:bounds]; + [super setBounds:bounds]; + if (shouldInvalidate) { + [self invalidateLayout]; + _collectionViewFlags.fadeCellsForBoundsChange = YES; + } + } +} + +/////////////////////////////////////////////////////////////////////////////////////////// +#pragma mark - UIScrollViewDelegate + +- (void)scrollViewDidScroll:(UIScrollView *)scrollView { + id delegate = self.extVars.collectionViewDelegate; + if ((id)delegate != self && [delegate respondsToSelector:@selector(scrollViewDidScroll:)]) { + [delegate scrollViewDidScroll:scrollView]; + } +} + +- (void)scrollViewDidZoom:(UIScrollView *)scrollView { + id delegate = self.extVars.collectionViewDelegate; + if ((id)delegate != self && [delegate respondsToSelector:@selector(scrollViewDidZoom:)]) { + [delegate scrollViewDidZoom:scrollView]; + } +} + +- (void)scrollViewWillBeginDragging:(UIScrollView *)scrollView { + id delegate = self.extVars.collectionViewDelegate; + if ((id)delegate != self && [delegate respondsToSelector:@selector(scrollViewWillBeginDragging:)]) { + [delegate scrollViewWillBeginDragging:scrollView]; + } +} + +- (void)scrollViewWillEndDragging:(UIScrollView *)scrollView withVelocity:(CGPoint)velocity targetContentOffset:(inout CGPoint *)targetContentOffset { + // Let collectionViewLayout decide where to stop. + *targetContentOffset = [[self collectionViewLayout] targetContentOffsetForProposedContentOffset:*targetContentOffset withScrollingVelocity:velocity]; + + id delegate = self.extVars.collectionViewDelegate; + if ((id)delegate != self && [delegate respondsToSelector:@selector(scrollViewWillEndDragging:withVelocity:targetContentOffset:)]) { + //if collectionViewDelegate implements this method, it may modify targetContentOffset as well + [delegate scrollViewWillEndDragging:scrollView withVelocity:velocity targetContentOffset:targetContentOffset]; + } +} + +- (void)scrollViewDidEndDragging:(UIScrollView *)scrollView willDecelerate:(BOOL)decelerate { + id delegate = self.extVars.collectionViewDelegate; + if ((id)delegate != self && [delegate respondsToSelector:@selector(scrollViewDidEndDragging:willDecelerate:)]) { + [delegate scrollViewDidEndDragging:scrollView willDecelerate:decelerate]; + } + + // if we are in the middle of a cell touch event, perform the "touchEnded" simulation + if (self.extVars.touchingIndexPath) { + [self cellTouchCancelled]; + } +} + +- (void)scrollViewWillBeginDecelerating:(UIScrollView *)scrollView { + id delegate = self.extVars.collectionViewDelegate; + if ((id)delegate != self && [delegate respondsToSelector:@selector(scrollViewWillBeginDecelerating:)]) { + [delegate scrollViewWillBeginDecelerating:scrollView]; + } +} + +- (void)scrollViewDidEndDecelerating:(UIScrollView *)scrollView { + id delegate = self.extVars.collectionViewDelegate; + if ((id)delegate != self && [delegate respondsToSelector:@selector(scrollViewDidEndDecelerating:)]) { + [delegate scrollViewDidEndDecelerating:scrollView]; + } +} + +- (void)scrollViewDidEndScrollingAnimation:(UIScrollView *)scrollView { + id delegate = self.extVars.collectionViewDelegate; + if ((id)delegate != self && [delegate respondsToSelector:@selector(scrollViewDidEndScrollingAnimation:)]) { + [delegate scrollViewDidEndScrollingAnimation:scrollView]; + } +} + +- (UIView *)viewForZoomingInScrollView:(UIScrollView *)scrollView { + id delegate = self.extVars.collectionViewDelegate; + if ((id)delegate != self && [delegate respondsToSelector:@selector(viewForZoomingInScrollView:)]) { + return [delegate viewForZoomingInScrollView:scrollView]; + } + return nil; +} + +- (void)scrollViewWillBeginZooming:(UIScrollView *)scrollView withView:(UIView *)view { + id delegate = self.extVars.collectionViewDelegate; + if ((id)delegate != self && [delegate respondsToSelector:@selector(scrollViewWillBeginZooming:withView:)]) { + [delegate scrollViewWillBeginZooming:scrollView withView:view]; + } +} + +- (void)scrollViewDidEndZooming:(UIScrollView *)scrollView withView:(UIView *)view atScale:(CGFloat)scale { + id delegate = self.extVars.collectionViewDelegate; + if ((id)delegate != self && [delegate respondsToSelector:@selector(scrollViewDidEndZooming:withView:atScale:)]) { + [delegate scrollViewDidEndZooming:scrollView withView:view atScale:scale]; + } +} + +- (BOOL)scrollViewShouldScrollToTop:(UIScrollView *)scrollView { + id delegate = self.extVars.collectionViewDelegate; + if ((id)delegate != self && [delegate respondsToSelector:@selector(scrollViewShouldScrollToTop:)]) { + return [delegate scrollViewShouldScrollToTop:scrollView]; + } + return YES; +} + +- (void)scrollViewDidScrollToTop:(UIScrollView *)scrollView { + id delegate = self.extVars.collectionViewDelegate; + if ((id)delegate != self && [delegate respondsToSelector:@selector(scrollViewDidScrollToTop:)]) { + [delegate scrollViewDidScrollToTop:scrollView]; + } +} + +/////////////////////////////////////////////////////////////////////////////////////////// +#pragma mark - Public + +- (void)registerClass:(Class)cellClass forCellWithReuseIdentifier:(NSString *)identifier { + NSParameterAssert(cellClass); + NSParameterAssert(identifier); + _cellClassDict[identifier] = cellClass; +} + +- (void)registerClass:(Class)viewClass forSupplementaryViewOfKind:(NSString *)elementKind withReuseIdentifier:(NSString *)identifier { + NSParameterAssert(viewClass); + NSParameterAssert(elementKind); + NSParameterAssert(identifier); + NSString *kindAndIdentifier = [NSString stringWithFormat:@"%@/%@", elementKind, identifier]; + _supplementaryViewClassDict[kindAndIdentifier] = viewClass; +} + +- (void)registerNib:(UINib *)nib forCellWithReuseIdentifier:(NSString *)identifier { + NSArray *topLevelObjects = [nib instantiateWithOwner:nil options:nil]; +#pragma unused(topLevelObjects) + NSAssert(topLevelObjects.count == 1 && [topLevelObjects[0] isKindOfClass:PSTCollectionViewCell.class], @"must contain exactly 1 top level object which is a PSTCollectionViewCell"); + + _cellNibDict[identifier] = nib; +} + +- (void)registerNib:(UINib *)nib forSupplementaryViewOfKind:(NSString *)kind withReuseIdentifier:(NSString *)identifier { + NSArray *topLevelObjects = [nib instantiateWithOwner:nil options:nil]; +#pragma unused(topLevelObjects) + NSAssert(topLevelObjects.count == 1 && [topLevelObjects[0] isKindOfClass:PSTCollectionReusableView.class], @"must contain exactly 1 top level object which is a PSTCollectionReusableView"); + + NSString *kindAndIdentifier = [NSString stringWithFormat:@"%@/%@", kind, identifier]; + _supplementaryViewNibDict[kindAndIdentifier] = nib; +} + +- (id)dequeueReusableCellWithReuseIdentifier:(NSString *)identifier forIndexPath:(NSIndexPath *)indexPath { + // de-queue cell (if available) + NSMutableArray *reusableCells = _cellReuseQueues[identifier]; + PSTCollectionViewCell *cell = [reusableCells lastObject]; + PSTCollectionViewLayoutAttributes *attributes = [self.collectionViewLayout layoutAttributesForItemAtIndexPath:indexPath]; + + if (cell) { + [reusableCells removeObjectAtIndex:reusableCells.count - 1]; + }else { + if (_cellNibDict[identifier]) { + // Cell was registered via registerNib:forCellWithReuseIdentifier: + UINib *cellNib = _cellNibDict[identifier]; + NSDictionary *externalObjects = self.extVars.nibCellsExternalObjects[identifier]; + if (externalObjects) { + cell = [cellNib instantiateWithOwner:self options:@{UINibExternalObjects : externalObjects}][0]; + }else { + cell = [cellNib instantiateWithOwner:self options:nil][0]; + } + }else { + Class cellClass = _cellClassDict[identifier]; + // compatibility layer + Class collectionViewCellClass = NSClassFromString(@"UICollectionViewCell"); + if (collectionViewCellClass && [cellClass isEqual:collectionViewCellClass]) { + cellClass = PSTCollectionViewCell.class; + } + if (cellClass == nil) { + @throw [NSException exceptionWithName:NSInvalidArgumentException reason:[NSString stringWithFormat:@"Class not registered for identifier %@", identifier] userInfo:nil]; + } + if (attributes) { + cell = [[cellClass alloc] initWithFrame:attributes.frame]; + }else { + cell = [cellClass new]; + } + } + cell.collectionView = self; + cell.reuseIdentifier = identifier; + } + + [cell applyLayoutAttributes:attributes]; + + return cell; +} + +- (id)dequeueReusableSupplementaryViewOfKind:(NSString *)elementKind withReuseIdentifier:(NSString *)identifier forIndexPath:(NSIndexPath *)indexPath { + NSString *kindAndIdentifier = [NSString stringWithFormat:@"%@/%@", elementKind, identifier]; + NSMutableArray *reusableViews = _supplementaryViewReuseQueues[kindAndIdentifier]; + PSTCollectionReusableView *view = [reusableViews lastObject]; + if (view) { + [reusableViews removeObjectAtIndex:reusableViews.count - 1]; + }else { + if (_supplementaryViewNibDict[kindAndIdentifier]) { + // supplementary view was registered via registerNib:forCellWithReuseIdentifier: + UINib *supplementaryViewNib = _supplementaryViewNibDict[kindAndIdentifier]; + NSDictionary *externalObjects = self.extVars.supplementaryViewsExternalObjects[kindAndIdentifier]; + if (externalObjects) { + view = [supplementaryViewNib instantiateWithOwner:self options:@{UINibExternalObjects : externalObjects}][0]; + }else { + view = [supplementaryViewNib instantiateWithOwner:self options:nil][0]; + } + }else { + Class viewClass = _supplementaryViewClassDict[kindAndIdentifier]; + Class reusableViewClass = NSClassFromString(@"UICollectionReusableView"); + if (reusableViewClass && [viewClass isEqual:reusableViewClass]) { + viewClass = PSTCollectionReusableView.class; + } + if (viewClass == nil) { + @throw [NSException exceptionWithName:NSInvalidArgumentException reason:[NSString stringWithFormat:@"Class not registered for kind/identifier %@", kindAndIdentifier] userInfo:nil]; + } + if (self.collectionViewLayout) { + PSTCollectionViewLayoutAttributes *attributes = [self.collectionViewLayout layoutAttributesForSupplementaryViewOfKind:elementKind atIndexPath:indexPath]; + if (attributes) { + view = [[viewClass alloc] initWithFrame:attributes.frame]; + } + }else { + view = [viewClass new]; + } + } + view.collectionView = self; + view.reuseIdentifier = identifier; + } + + return view; +} + +- (id)dequeueReusableOrCreateDecorationViewOfKind:(NSString *)elementKind forIndexPath:(NSIndexPath *)indexPath { + NSMutableArray *reusableViews = _decorationViewReuseQueues[elementKind]; + PSTCollectionReusableView *view = [reusableViews lastObject]; + PSTCollectionViewLayout *collectionViewLayout = self.collectionViewLayout; + PSTCollectionViewLayoutAttributes *attributes = [collectionViewLayout layoutAttributesForDecorationViewOfKind:elementKind atIndexPath:indexPath]; + + if (view) { + [reusableViews removeObjectAtIndex:reusableViews.count - 1]; + }else { + NSDictionary *decorationViewNibDict = collectionViewLayout.decorationViewNibDict; + NSDictionary *decorationViewExternalObjects = collectionViewLayout.decorationViewExternalObjectsTables; + if (decorationViewNibDict[elementKind]) { + // supplementary view was registered via registerNib:forCellWithReuseIdentifier: + UINib *supplementaryViewNib = decorationViewNibDict[elementKind]; + NSDictionary *externalObjects = decorationViewExternalObjects[elementKind]; + if (externalObjects) { + view = [supplementaryViewNib instantiateWithOwner:self options:@{UINibExternalObjects : externalObjects}][0]; + }else { + view = [supplementaryViewNib instantiateWithOwner:self options:nil][0]; + } + }else { + NSDictionary *decorationViewClassDict = collectionViewLayout.decorationViewClassDict; + Class viewClass = decorationViewClassDict[elementKind]; + Class reusableViewClass = NSClassFromString(@"UICollectionReusableView"); + if (reusableViewClass && [viewClass isEqual:reusableViewClass]) { + viewClass = PSTCollectionReusableView.class; + } + if (viewClass == nil) { + @throw [NSException exceptionWithName:NSInvalidArgumentException reason:[NSString stringWithFormat:@"Class not registered for identifier %@", elementKind] userInfo:nil]; + } + if (attributes) { + view = [[viewClass alloc] initWithFrame:attributes.frame]; + }else { + view = [viewClass new]; + } + } + view.collectionView = self; + view.reuseIdentifier = elementKind; + } + + [view applyLayoutAttributes:attributes]; + + return view; +} + +- (NSArray *)allCells { + return [[_allVisibleViewsDict allValues] filteredArrayUsingPredicate:[NSPredicate predicateWithBlock:^BOOL(id evaluatedObject, NSDictionary *bindings) { + return [evaluatedObject isKindOfClass:PSTCollectionViewCell.class]; + }]]; +} + +- (NSArray *)visibleCells { + return [[_allVisibleViewsDict allValues] filteredArrayUsingPredicate:[NSPredicate predicateWithBlock:^BOOL(id evaluatedObject, NSDictionary *bindings) { + return [evaluatedObject isKindOfClass:PSTCollectionViewCell.class] && CGRectIntersectsRect(self.bounds, [evaluatedObject frame]); + }]]; +} + +- (void)reloadData { + if (_reloadingSuspendedCount != 0) return; + [self invalidateLayout]; + [_allVisibleViewsDict enumerateKeysAndObjectsUsingBlock:^(id key, id obj, BOOL *stop) { + if ([obj isKindOfClass:UIView.class]) { + [obj removeFromSuperview]; + } + }]; + [_allVisibleViewsDict removeAllObjects]; + + for (NSIndexPath *indexPath in _indexPathsForSelectedItems) { + PSTCollectionViewCell *selectedCell = [self cellForItemAtIndexPath:indexPath]; + selectedCell.selected = NO; + selectedCell.highlighted = NO; + } + [_indexPathsForSelectedItems removeAllObjects]; + [_indexPathsForHighlightedItems removeAllObjects]; + + [self setNeedsLayout]; +} + +/////////////////////////////////////////////////////////////////////////////////////////// +#pragma mark - Query Grid + +- (NSInteger)numberOfSections { + return [_collectionViewData numberOfSections]; +} + +- (NSInteger)numberOfItemsInSection:(NSInteger)section { + return [_collectionViewData numberOfItemsInSection:section]; +} + +- (PSTCollectionViewLayoutAttributes *)layoutAttributesForItemAtIndexPath:(NSIndexPath *)indexPath { + return [[self collectionViewLayout] layoutAttributesForItemAtIndexPath:indexPath]; +} + +- (PSTCollectionViewLayoutAttributes *)layoutAttributesForSupplementaryElementOfKind:(NSString *)kind atIndexPath:(NSIndexPath *)indexPath { + return [[self collectionViewLayout] layoutAttributesForSupplementaryViewOfKind:kind atIndexPath:indexPath]; +} + +- (NSIndexPath *)indexPathForItemAtPoint:(CGPoint)point { + PSTCollectionViewLayoutAttributes *attributes = [[self.collectionViewLayout layoutAttributesForElementsInRect:CGRectMake(point.x, point.y, 1, 1)] lastObject]; + return attributes.indexPath; +} + +- (NSIndexPath *)indexPathForCell:(PSTCollectionViewCell *)cell { + __block NSIndexPath *indexPath = nil; + [_allVisibleViewsDict enumerateKeysAndObjectsWithOptions:kNilOptions usingBlock:^(id key, id obj, BOOL *stop) { + PSTCollectionViewItemKey *itemKey = (PSTCollectionViewItemKey *)key; + if (itemKey.type == PSTCollectionViewItemTypeCell) { + PSTCollectionViewCell *currentCell = (PSTCollectionViewCell *)obj; + if (currentCell == cell) { + indexPath = itemKey.indexPath; + *stop = YES; + } + } + }]; + return indexPath; +} + +- (PSTCollectionViewCell *)cellForItemAtIndexPath:(NSIndexPath *)indexPath { + // NSInteger index = [_collectionViewData globalIndexForItemAtIndexPath:indexPath]; + // TODO Apple uses some kind of globalIndex for this. + __block PSTCollectionViewCell *cell = nil; + [_allVisibleViewsDict enumerateKeysAndObjectsWithOptions:0 usingBlock:^(id key, id obj, BOOL *stop) { + PSTCollectionViewItemKey *itemKey = (PSTCollectionViewItemKey *)key; + if (itemKey.type == PSTCollectionViewItemTypeCell) { + if ([itemKey.indexPath isEqual:indexPath]) { + cell = obj; + *stop = YES; + } + } + }]; + return cell; +} + +- (NSArray *)indexPathsForVisibleItems { + NSArray *visibleCells = self.visibleCells; + NSMutableArray *indexPaths = [NSMutableArray arrayWithCapacity:visibleCells.count]; + + [visibleCells enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) { + PSTCollectionViewCell *cell = (PSTCollectionViewCell *)obj; + [indexPaths addObject:cell.layoutAttributes.indexPath]; + }]; + + return indexPaths; +} + +// returns nil or an array of selected index paths +- (NSArray *)indexPathsForSelectedItems { + return [_indexPathsForSelectedItems allObjects]; +} + +// Interacting with the collection view. +- (void)scrollToItemAtIndexPath:(NSIndexPath *)indexPath atScrollPosition:(PSTCollectionViewScrollPosition)scrollPosition animated:(BOOL)animated { + // Ensure grid is laid out; else we can't scroll. + [self layoutSubviews]; + + PSTCollectionViewLayoutAttributes *layoutAttributes = [self.collectionViewLayout layoutAttributesForItemAtIndexPath:indexPath]; + if (layoutAttributes) { + CGRect targetRect = [self makeRect:layoutAttributes.frame toScrollPosition:scrollPosition]; + [self scrollRectToVisible:targetRect animated:animated]; + } +} + +- (CGRect)makeRect:(CGRect)targetRect toScrollPosition:(PSTCollectionViewScrollPosition)scrollPosition { + // split parameters + NSUInteger verticalPosition = scrollPosition&0x07; // 0000 0111 + NSUInteger horizontalPosition = scrollPosition&0x38; // 0011 1000 + + if (verticalPosition != PSTCollectionViewScrollPositionNone + && verticalPosition != PSTCollectionViewScrollPositionTop + && verticalPosition != PSTCollectionViewScrollPositionCenteredVertically + && verticalPosition != PSTCollectionViewScrollPositionBottom) { + @throw [NSException exceptionWithName:NSInvalidArgumentException reason:@"PSTCollectionViewScrollPosition: attempt to use a scroll position with multiple vertical positioning styles" userInfo:nil]; + } + + if (horizontalPosition != PSTCollectionViewScrollPositionNone + && horizontalPosition != PSTCollectionViewScrollPositionLeft + && horizontalPosition != PSTCollectionViewScrollPositionCenteredHorizontally + && horizontalPosition != PSTCollectionViewScrollPositionRight) { + @throw [NSException exceptionWithName:NSInvalidArgumentException reason:@"PSTCollectionViewScrollPosition: attempt to use a scroll position with multiple horizontal positioning styles" userInfo:nil]; + } + + CGRect frame = self.layer.bounds; + CGFloat calculateX; + CGFloat calculateY; + + switch (verticalPosition) { + case PSTCollectionViewScrollPositionCenteredVertically: + calculateY = fmax(targetRect.origin.y - ((frame.size.height / 2) - (targetRect.size.height / 2)), -self.contentInset.top); + targetRect = CGRectMake(targetRect.origin.x, calculateY, targetRect.size.width, frame.size.height); + break; + case PSTCollectionViewScrollPositionTop: + targetRect = CGRectMake(targetRect.origin.x, targetRect.origin.y, targetRect.size.width, frame.size.height); + break; + + case PSTCollectionViewScrollPositionBottom: + calculateY = fmax(targetRect.origin.y - (frame.size.height - targetRect.size.height), -self.contentInset.top); + targetRect = CGRectMake(targetRect.origin.x, calculateY, targetRect.size.width, frame.size.height); + break; + } + + switch (horizontalPosition) { + case PSTCollectionViewScrollPositionCenteredHorizontally: + calculateX = targetRect.origin.x - ((frame.size.width / 2) - (targetRect.size.width / 2)); + targetRect = CGRectMake(calculateX, targetRect.origin.y, frame.size.width, targetRect.size.height); + break; + + case PSTCollectionViewScrollPositionLeft: + targetRect = CGRectMake(targetRect.origin.x, targetRect.origin.y, frame.size.width, targetRect.size.height); + break; + + case PSTCollectionViewScrollPositionRight: + calculateX = targetRect.origin.x - (frame.size.width - targetRect.size.width); + targetRect = CGRectMake(calculateX, targetRect.origin.y, frame.size.width, targetRect.size.height); + break; + } + + return targetRect; +} + +/////////////////////////////////////////////////////////////////////////////////////////// +#pragma mark - Touch Handling + +- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event { + [super touchesBegan:touches withEvent:event]; + + // reset touching state vars + self.extVars.touchingIndexPath = nil; + self.extVars.currentIndexPath = nil; + + CGPoint touchPoint = [[touches anyObject] locationInView:self]; + NSIndexPath *indexPath = [self indexPathForItemAtPoint:touchPoint]; + if (indexPath && self.allowsSelection) { + if (![self highlightItemAtIndexPath:indexPath animated:YES scrollPosition:PSTCollectionViewScrollPositionNone notifyDelegate:YES]) + return; + + self.extVars.touchingIndexPath = indexPath; + self.extVars.currentIndexPath = indexPath; + + if (!self.allowsMultipleSelection) { + // temporally unhighlight background on touchesBegan (keeps selected by _indexPathsForSelectedItems) + // single-select only mode only though + NSIndexPath *tempDeselectIndexPath = _indexPathsForSelectedItems.anyObject; + if (tempDeselectIndexPath && ![tempDeselectIndexPath isEqual:self.extVars.touchingIndexPath]) { + // iOS6 UICollectionView deselects cell without notification + PSTCollectionViewCell *selectedCell = [self cellForItemAtIndexPath:tempDeselectIndexPath]; + selectedCell.selected = NO; + } + } + } +} + +- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event { + [super touchesMoved:touches withEvent:event]; + + // allows moving between highlight and unhighlight state only if setHighlighted is not overwritten + if (self.extVars.touchingIndexPath) { + CGPoint touchPoint = [[touches anyObject] locationInView:self]; + NSIndexPath *indexPath = [self indexPathForItemAtPoint:touchPoint]; + + // moving out of bounds + if ([self.extVars.currentIndexPath isEqual:self.extVars.touchingIndexPath] && + ![indexPath isEqual:self.extVars.touchingIndexPath] && + [self unhighlightItemAtIndexPath:self.extVars.touchingIndexPath animated:YES notifyDelegate:YES shouldCheckHighlight:YES]) { + self.extVars.currentIndexPath = indexPath; + // moving back into the original touching cell + }else if (![self.extVars.currentIndexPath isEqual:self.extVars.touchingIndexPath] && + [indexPath isEqual:self.extVars.touchingIndexPath]) { + [self highlightItemAtIndexPath:self.extVars.touchingIndexPath animated:YES scrollPosition:PSTCollectionViewScrollPositionNone notifyDelegate:YES]; + self.extVars.currentIndexPath = self.extVars.touchingIndexPath; + } + } +} + +- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event { + [super touchesEnded:touches withEvent:event]; + + if (self.extVars.touchingIndexPath) { + // first unhighlight the touch operation + [self unhighlightItemAtIndexPath:self.extVars.touchingIndexPath animated:YES notifyDelegate:YES]; + + CGPoint touchPoint = [[touches anyObject] locationInView:self]; + NSIndexPath *indexPath = [self indexPathForItemAtPoint:touchPoint]; + if ([indexPath isEqual:self.extVars.touchingIndexPath]) { + [self userSelectedItemAtIndexPath:indexPath]; + } + else if (!self.allowsMultipleSelection) { + NSIndexPath *tempDeselectIndexPath = _indexPathsForSelectedItems.anyObject; + if (tempDeselectIndexPath && ![tempDeselectIndexPath isEqual:self.extVars.touchingIndexPath]) { + [self cellTouchCancelled]; + } + } + + // for pedantic reasons only - always set to nil on touchesBegan + self.extVars.touchingIndexPath = nil; + self.extVars.currentIndexPath = nil; + } +} + +- (void)touchesCancelled:(NSSet *)touches withEvent:(UIEvent *)event { + [super touchesCancelled:touches withEvent:event]; + + // do not mark touchingIndexPath as nil because whoever cancelled this touch will need to signal a touch up event later + if (self.extVars.touchingIndexPath) { + // first unhighlight the touch operation + [self unhighlightItemAtIndexPath:self.extVars.touchingIndexPath animated:YES notifyDelegate:YES]; + } +} + +- (void)cellTouchCancelled { + // turn on ALL the *should be selected* cells (iOS6 UICollectionView does no state keeping or other fancy optimizations) + // there should be no notifications as this is a silent "turn everything back on" + for (NSIndexPath *tempDeselectedIndexPath in [_indexPathsForSelectedItems copy]) { + PSTCollectionViewCell *selectedCell = [self cellForItemAtIndexPath:tempDeselectedIndexPath]; + selectedCell.selected = YES; + } +} + +- (void)userSelectedItemAtIndexPath:(NSIndexPath *)indexPath { + if (self.allowsMultipleSelection && [_indexPathsForSelectedItems containsObject:indexPath]) { + [self deselectItemAtIndexPath:indexPath animated:YES notifyDelegate:YES]; + } + else if (self.allowsSelection) { + [self selectItemAtIndexPath:indexPath animated:YES scrollPosition:PSTCollectionViewScrollPositionNone notifyDelegate:YES]; + } +} + +// select item, notify delegate (internal) +- (void)selectItemAtIndexPath:(NSIndexPath *)indexPath animated:(BOOL)animated scrollPosition:(PSTCollectionViewScrollPosition)scrollPosition notifyDelegate:(BOOL)notifyDelegate { + if (self.allowsMultipleSelection && [_indexPathsForSelectedItems containsObject:indexPath]) { + BOOL shouldDeselect = YES; + if (notifyDelegate && _collectionViewFlags.delegateShouldDeselectItemAtIndexPath) { + shouldDeselect = [self.delegate collectionView:self shouldDeselectItemAtIndexPath:indexPath]; + } + + if (shouldDeselect) { + [self deselectItemAtIndexPath:indexPath animated:animated notifyDelegate:notifyDelegate]; + } + } + else { + // either single selection, or wasn't already selected in multiple selection mode + BOOL shouldSelect = YES; + if (notifyDelegate && _collectionViewFlags.delegateShouldSelectItemAtIndexPath) { + shouldSelect = [self.delegate collectionView:self shouldSelectItemAtIndexPath:indexPath]; + } + + if (!self.allowsMultipleSelection) { + // now unselect the previously selected cell for single selection + NSIndexPath *tempDeselectIndexPath = _indexPathsForSelectedItems.anyObject; + if (tempDeselectIndexPath && ![tempDeselectIndexPath isEqual:indexPath]) { + [self deselectItemAtIndexPath:tempDeselectIndexPath animated:YES notifyDelegate:YES]; + } + } + + if (shouldSelect) { + PSTCollectionViewCell *selectedCell = [self cellForItemAtIndexPath:indexPath]; + selectedCell.selected = YES; + + [_indexPathsForSelectedItems addObject:indexPath]; + + [selectedCell performSelectionSegue]; + + if (scrollPosition != PSTCollectionViewScrollPositionNone) { + [self scrollToItemAtIndexPath:indexPath atScrollPosition:scrollPosition animated:animated]; + } + + if (notifyDelegate && _collectionViewFlags.delegateDidSelectItemAtIndexPath) { + [self.delegate collectionView:self didSelectItemAtIndexPath:indexPath]; + } + } + } +} + +- (void)selectItemAtIndexPath:(NSIndexPath *)indexPath animated:(BOOL)animated scrollPosition:(PSTCollectionViewScrollPosition)scrollPosition { + [self selectItemAtIndexPath:indexPath animated:animated scrollPosition:scrollPosition notifyDelegate:NO]; +} + +- (void)deselectItemAtIndexPath:(NSIndexPath *)indexPath animated:(BOOL)animated { + [self deselectItemAtIndexPath:indexPath animated:animated notifyDelegate:NO]; +} + +- (void)deselectItemAtIndexPath:(NSIndexPath *)indexPath animated:(BOOL)animated notifyDelegate:(BOOL)notifyDelegate { + BOOL shouldDeselect = YES; + // deselect only relevant during multi mode + if (self.allowsMultipleSelection && notifyDelegate && _collectionViewFlags.delegateShouldDeselectItemAtIndexPath) { + shouldDeselect = [self.delegate collectionView:self shouldDeselectItemAtIndexPath:indexPath]; + } + + if (shouldDeselect && [_indexPathsForSelectedItems containsObject:indexPath]) { + PSTCollectionViewCell *selectedCell = [self cellForItemAtIndexPath:indexPath]; + if (selectedCell) { + if (selectedCell.selected) { + selectedCell.selected = NO; + } + } + [_indexPathsForSelectedItems removeObject:indexPath]; + + if (notifyDelegate && _collectionViewFlags.delegateDidDeselectItemAtIndexPath) { + [self.delegate collectionView:self didDeselectItemAtIndexPath:indexPath]; + } + } +} + +- (BOOL)highlightItemAtIndexPath:(NSIndexPath *)indexPath animated:(BOOL)animated scrollPosition:(PSTCollectionViewScrollPosition)scrollPosition notifyDelegate:(BOOL)notifyDelegate { + BOOL shouldHighlight = YES; + if (notifyDelegate && _collectionViewFlags.delegateShouldHighlightItemAtIndexPath) { + shouldHighlight = [self.delegate collectionView:self shouldHighlightItemAtIndexPath:indexPath]; + } + + if (shouldHighlight) { + PSTCollectionViewCell *highlightedCell = [self cellForItemAtIndexPath:indexPath]; + highlightedCell.highlighted = YES; + [_indexPathsForHighlightedItems addObject:indexPath]; + + if (scrollPosition != PSTCollectionViewScrollPositionNone) { + [self scrollToItemAtIndexPath:indexPath atScrollPosition:scrollPosition animated:animated]; + } + + if (notifyDelegate && _collectionViewFlags.delegateDidHighlightItemAtIndexPath) { + [self.delegate collectionView:self didHighlightItemAtIndexPath:indexPath]; + } + } + return shouldHighlight; +} + +- (BOOL)unhighlightItemAtIndexPath:(NSIndexPath *)indexPath animated:(BOOL)animated notifyDelegate:(BOOL)notifyDelegate { + return [self unhighlightItemAtIndexPath:indexPath animated:animated notifyDelegate:notifyDelegate shouldCheckHighlight:NO]; +} + +- (BOOL)unhighlightItemAtIndexPath:(NSIndexPath *)indexPath animated:(BOOL)animated notifyDelegate:(BOOL)notifyDelegate shouldCheckHighlight:(BOOL)check { + if ([_indexPathsForHighlightedItems containsObject:indexPath]) { + PSTCollectionViewCell *highlightedCell = [self cellForItemAtIndexPath:indexPath]; + // iOS6 does not notify any delegate if the cell was never highlighted (setHighlighted overwritten) during touchMoved + if (check && !highlightedCell.highlighted) { + return NO; + } + + // if multiple selection or not unhighlighting a selected item we don't perform any op + if (highlightedCell.highlighted && [_indexPathsForSelectedItems containsObject:indexPath]) { + highlightedCell.highlighted = YES; + }else { + highlightedCell.highlighted = NO; + } + + [_indexPathsForHighlightedItems removeObject:indexPath]; + + if (notifyDelegate && _collectionViewFlags.delegateDidUnhighlightItemAtIndexPath) { + [self.delegate collectionView:self didUnhighlightItemAtIndexPath:indexPath]; + } + + return YES; + } + return NO; +} + +/////////////////////////////////////////////////////////////////////////////////////////// +#pragma mark - Update Grid + +- (void)insertSections:(NSIndexSet *)sections { + [self updateSections:sections updateAction:PSTCollectionUpdateActionInsert]; +} + +- (void)deleteSections:(NSIndexSet *)sections { + // First delete all items + NSMutableArray *paths = [NSMutableArray new]; + [sections enumerateIndexesUsingBlock:^(NSUInteger idx, BOOL *stop) { + for (int i = 0; i < [self numberOfItemsInSection:(NSInteger)idx]; ++i) { + [paths addObject:[NSIndexPath indexPathForItem:i inSection:(NSInteger)idx]]; + } + }]; + [self deleteItemsAtIndexPaths:paths]; + // Then delete the section. + [self updateSections:sections updateAction:PSTCollectionUpdateActionDelete]; +} + +- (void)reloadSections:(NSIndexSet *)sections { + [self updateSections:sections updateAction:PSTCollectionUpdateActionReload]; +} + +- (void)moveSection:(NSInteger)section toSection:(NSInteger)newSection { + NSMutableArray *moveUpdateItems = [self arrayForUpdateAction:PSTCollectionUpdateActionMove]; + [moveUpdateItems addObject: + [[PSTCollectionViewUpdateItem alloc] initWithInitialIndexPath:[NSIndexPath indexPathForItem:NSNotFound inSection:section] + finalIndexPath:[NSIndexPath indexPathForItem:NSNotFound inSection:newSection] + updateAction:PSTCollectionUpdateActionMove]]; + if (!_collectionViewFlags.updating) { + [self setupCellAnimations]; + [self endItemAnimations]; + } +} + +- (void)insertItemsAtIndexPaths:(NSArray *)indexPaths { + [self updateRowsAtIndexPaths:indexPaths updateAction:PSTCollectionUpdateActionInsert]; +} + +- (void)deleteItemsAtIndexPaths:(NSArray *)indexPaths { + [self updateRowsAtIndexPaths:indexPaths updateAction:PSTCollectionUpdateActionDelete]; + +} + +- (void)reloadItemsAtIndexPaths:(NSArray *)indexPaths { + [self updateRowsAtIndexPaths:indexPaths updateAction:PSTCollectionUpdateActionReload]; +} + +- (void)moveItemAtIndexPath:(NSIndexPath *)indexPath toIndexPath:(NSIndexPath *)newIndexPath { + NSMutableArray *moveUpdateItems = [self arrayForUpdateAction:PSTCollectionUpdateActionMove]; + [moveUpdateItems addObject: + [[PSTCollectionViewUpdateItem alloc] initWithInitialIndexPath:indexPath + finalIndexPath:newIndexPath + updateAction:PSTCollectionUpdateActionMove]]; + if (!_collectionViewFlags.updating) { + [self setupCellAnimations]; + [self endItemAnimations]; + } + +} + +- (void)performBatchUpdates:(void (^)(void))updates completion:(void (^)(BOOL finished))completion { + [self setupCellAnimations]; + + if (updates) updates(); + if (completion) _updateCompletionHandler = completion; + + [self endItemAnimations]; +} + +/////////////////////////////////////////////////////////////////////////////////////////// +#pragma mark - Properties + +- (void)setBackgroundView:(UIView *)backgroundView { + if (backgroundView != _backgroundView) { + [_backgroundView removeFromSuperview]; + _backgroundView = backgroundView; + backgroundView.frame = (CGRect){.origin=self.contentOffset, .size=self.bounds.size}; + backgroundView.autoresizingMask = UIViewAutoresizingFlexibleHeight|UIViewAutoresizingFlexibleWidth; + [self addSubview:backgroundView]; + [self sendSubviewToBack:backgroundView]; + } +} + +- (void)setCollectionViewLayout:(PSTCollectionViewLayout *)layout animated:(BOOL)animated { + if (layout == _layout) return; + + // not sure it was it original code, but here this prevents crash + // in case we switch layout before previous one was initially loaded + if (CGRectIsEmpty(self.bounds) || !_collectionViewFlags.doneFirstLayout) { + _layout.collectionView = nil; + _collectionViewData = [[PSTCollectionViewData alloc] initWithCollectionView:self layout:layout]; + layout.collectionView = self; + _layout = layout; + + // originally the use method + // _setNeedsVisibleCellsUpdate:withLayoutAttributes: + // here with CellsUpdate set to YES and LayoutAttributes parameter set to NO + // inside this method probably some flags are set and finally + // setNeedsDisplay is called + + _collectionViewFlags.scheduledUpdateVisibleCells = YES; + _collectionViewFlags.scheduledUpdateVisibleCellLayoutAttributes = NO; + + [self setNeedsDisplay]; + } + else { + layout.collectionView = self; + + _layout.collectionView = nil; + _layout = layout; + + _collectionViewData = [[PSTCollectionViewData alloc] initWithCollectionView:self layout:layout]; + [_collectionViewData prepareToLoadData]; + + NSArray *previouslySelectedIndexPaths = [self indexPathsForSelectedItems]; + NSMutableSet *selectedCellKeys = [NSMutableSet setWithCapacity:previouslySelectedIndexPaths.count]; + + for (NSIndexPath *indexPath in previouslySelectedIndexPaths) { + [selectedCellKeys addObject:[PSTCollectionViewItemKey collectionItemKeyForCellWithIndexPath:indexPath]]; + } + + NSArray *previouslyVisibleItemsKeys = [_allVisibleViewsDict allKeys]; + NSSet *previouslyVisibleItemsKeysSet = [NSSet setWithArray:previouslyVisibleItemsKeys]; + NSMutableSet *previouslyVisibleItemsKeysSetMutable = [NSMutableSet setWithArray:previouslyVisibleItemsKeys]; + + if ([selectedCellKeys intersectsSet:selectedCellKeys]) { + [previouslyVisibleItemsKeysSetMutable intersectSet:previouslyVisibleItemsKeysSetMutable]; + } + + [self bringSubviewToFront:_allVisibleViewsDict[[previouslyVisibleItemsKeysSetMutable anyObject]]]; + + CGPoint targetOffset = self.contentOffset; + CGPoint centerPoint = CGPointMake(self.bounds.origin.x + self.bounds.size.width / 2.f, + self.bounds.origin.y + self.bounds.size.height / 2.f); + NSIndexPath *centerItemIndexPath = [self indexPathForItemAtPoint:centerPoint]; + + if (!centerItemIndexPath) { + NSArray *visibleItems = [self indexPathsForVisibleItems]; + if (visibleItems.count > 0) { + centerItemIndexPath = visibleItems[visibleItems.count / 2]; + } + } + + if (centerItemIndexPath) { + PSTCollectionViewLayoutAttributes *layoutAttributes = [layout layoutAttributesForItemAtIndexPath:centerItemIndexPath]; + if (layoutAttributes) { + PSTCollectionViewScrollPosition scrollPosition = PSTCollectionViewScrollPositionCenteredVertically|PSTCollectionViewScrollPositionCenteredHorizontally; + CGRect targetRect = [self makeRect:layoutAttributes.frame toScrollPosition:scrollPosition]; + targetOffset = CGPointMake(fmax(0.f, targetRect.origin.x), fmax(0.f, targetRect.origin.y)); + } + } + + CGRect newlyBounds = CGRectMake(targetOffset.x, targetOffset.y, self.bounds.size.width, self.bounds.size.height); + NSArray *newlyVisibleLayoutAttrs = [_collectionViewData layoutAttributesForElementsInRect:newlyBounds]; + + NSMutableDictionary *layoutInterchangeData = [NSMutableDictionary dictionaryWithCapacity: + newlyVisibleLayoutAttrs.count + previouslyVisibleItemsKeysSet.count]; + + NSMutableSet *newlyVisibleItemsKeys = [NSMutableSet set]; + for (PSTCollectionViewLayoutAttributes *attr in newlyVisibleLayoutAttrs) { + PSTCollectionViewItemKey *newKey = [PSTCollectionViewItemKey collectionItemKeyForLayoutAttributes:attr]; + [newlyVisibleItemsKeys addObject:newKey]; + + PSTCollectionViewLayoutAttributes *prevAttr = nil; + PSTCollectionViewLayoutAttributes *newAttr = nil; + + if (newKey.type == PSTCollectionViewItemTypeDecorationView) { + prevAttr = [self.collectionViewLayout layoutAttributesForDecorationViewOfKind:attr.representedElementKind + atIndexPath:newKey.indexPath]; + newAttr = [layout layoutAttributesForDecorationViewOfKind:attr.representedElementKind + atIndexPath:newKey.indexPath]; + } + else if (newKey.type == PSTCollectionViewItemTypeCell) { + prevAttr = [self.collectionViewLayout layoutAttributesForItemAtIndexPath:newKey.indexPath]; + newAttr = [layout layoutAttributesForItemAtIndexPath:newKey.indexPath]; + } + else { + prevAttr = [self.collectionViewLayout layoutAttributesForSupplementaryViewOfKind:attr.representedElementKind + atIndexPath:newKey.indexPath]; + newAttr = [layout layoutAttributesForSupplementaryViewOfKind:attr.representedElementKind + atIndexPath:newKey.indexPath]; + } + + if (prevAttr != nil && newAttr != nil) { + layoutInterchangeData[newKey] = @{@"previousLayoutInfos": prevAttr, @"newLayoutInfos": newAttr}; + } + } + + for (PSTCollectionViewItemKey *key in previouslyVisibleItemsKeysSet) { + PSTCollectionViewLayoutAttributes *prevAttr = nil; + PSTCollectionViewLayoutAttributes *newAttr = nil; + + if (key.type == PSTCollectionViewItemTypeDecorationView) { + PSTCollectionReusableView *decorView = _allVisibleViewsDict[key]; + prevAttr = [self.collectionViewLayout layoutAttributesForDecorationViewOfKind:decorView.reuseIdentifier + atIndexPath:key.indexPath]; + newAttr = [layout layoutAttributesForDecorationViewOfKind:decorView.reuseIdentifier + atIndexPath:key.indexPath]; + } + else if (key.type == PSTCollectionViewItemTypeCell) { + prevAttr = [self.collectionViewLayout layoutAttributesForItemAtIndexPath:key.indexPath]; + newAttr = [layout layoutAttributesForItemAtIndexPath:key.indexPath]; + } + else if (key.type == PSTCollectionViewItemTypeSupplementaryView) { + PSTCollectionReusableView *suuplView = _allVisibleViewsDict[key]; + prevAttr = [self.collectionViewLayout layoutAttributesForSupplementaryViewOfKind:suuplView.layoutAttributes.representedElementKind + atIndexPath:key.indexPath]; + newAttr = [layout layoutAttributesForSupplementaryViewOfKind:suuplView.layoutAttributes.representedElementKind + atIndexPath:key.indexPath]; + } + + NSMutableDictionary *layoutInterchangeDataValue = [NSMutableDictionary dictionary]; + if (prevAttr) layoutInterchangeDataValue[@"previousLayoutInfos"] = prevAttr; + if (newAttr) layoutInterchangeDataValue[@"newLayoutInfos"] = newAttr; + layoutInterchangeData[key] = layoutInterchangeDataValue; + } + + for (PSTCollectionViewItemKey *key in [layoutInterchangeData keyEnumerator]) { + if (key.type == PSTCollectionViewItemTypeCell) { + PSTCollectionViewCell *cell = _allVisibleViewsDict[key]; + + if (!cell) { + cell = [self createPreparedCellForItemAtIndexPath:key.indexPath + withLayoutAttributes:layoutInterchangeData[key][@"previousLayoutInfos"]]; + _allVisibleViewsDict[key] = cell; + [self addControlledSubview:cell]; + } + else [cell applyLayoutAttributes:layoutInterchangeData[key][@"previousLayoutInfos"]]; + } + else if (key.type == PSTCollectionViewItemTypeSupplementaryView) { + PSTCollectionReusableView *view = _allVisibleViewsDict[key]; + if (!view) { + PSTCollectionViewLayoutAttributes *attrs = layoutInterchangeData[key][@"previousLayoutInfos"]; + view = [self createPreparedSupplementaryViewForElementOfKind:attrs.representedElementKind + atIndexPath:attrs.indexPath + withLayoutAttributes:attrs]; + _allVisibleViewsDict[key] = view; + [self addControlledSubview:view]; + } + } + else if (key.type == PSTCollectionViewItemTypeDecorationView) { + PSTCollectionReusableView *view = _allVisibleViewsDict[key]; + if (!view) { + PSTCollectionViewLayoutAttributes *attrs = layoutInterchangeData[key][@"previousLayoutInfos"]; + view = [self dequeueReusableOrCreateDecorationViewOfKind:attrs.representedElementKind forIndexPath:attrs.indexPath]; + _allVisibleViewsDict[key] = view; + [self addControlledSubview:view]; + } + } + }; + + CGRect contentRect = [_collectionViewData collectionViewContentRect]; + + void (^applyNewLayoutBlock)(void) = ^{ + NSEnumerator *keys = [layoutInterchangeData keyEnumerator]; + for (PSTCollectionViewItemKey *key in keys) { + // TODO: This is most likely not 100% the same time as in UICollectionView. Needs to be investigated. + PSTCollectionViewCell *cell = (PSTCollectionViewCell *)_allVisibleViewsDict[key]; + [cell willTransitionFromLayout:_layout toLayout:layout]; + [cell applyLayoutAttributes:layoutInterchangeData[key][@"newLayoutInfos"]]; + [cell didTransitionFromLayout:_layout toLayout:layout]; + } + }; + + void (^freeUnusedViews)(void) = ^{ + NSMutableSet *toRemove = [NSMutableSet set]; + for (PSTCollectionViewItemKey *key in [_allVisibleViewsDict keyEnumerator]) { + if (![newlyVisibleItemsKeys containsObject:key]) { + if (key.type == PSTCollectionViewItemTypeCell) { + [self reuseCell:_allVisibleViewsDict[key]]; + [toRemove addObject:key]; + } + else if (key.type == PSTCollectionViewItemTypeSupplementaryView) { + [self reuseSupplementaryView:_allVisibleViewsDict[key]]; + [toRemove addObject:key]; + } + else if (key.type == PSTCollectionViewItemTypeDecorationView) { + [self reuseDecorationView:_allVisibleViewsDict[key]]; + [toRemove addObject:key]; + } + } + } + + for (id key in toRemove) + [_allVisibleViewsDict removeObjectForKey:key]; + }; + + if (animated) { + [UIView animateWithDuration:.3 animations:^{ + _collectionViewFlags.updatingLayout = YES; + self.contentOffset = targetOffset; + self.contentSize = contentRect.size; + applyNewLayoutBlock(); + } completion:^(BOOL finished) { + freeUnusedViews(); + _collectionViewFlags.updatingLayout = NO; + + // layout subviews for updating content offset or size while updating layout + if (!CGPointEqualToPoint(self.contentOffset, targetOffset) + || !CGSizeEqualToSize(self.contentSize, contentRect.size)) { + [self layoutSubviews]; + } + }]; + } + else { + self.contentOffset = targetOffset; + self.contentSize = contentRect.size; + applyNewLayoutBlock(); + freeUnusedViews(); + } + } +} + +- (void)setCollectionViewLayout:(PSTCollectionViewLayout *)layout { + [self setCollectionViewLayout:layout animated:NO]; +} + +- (id)delegate { + return self.extVars.collectionViewDelegate; +} + +- (void)setDelegate:(id)delegate { + self.extVars.collectionViewDelegate = delegate; + + // Managing the Selected Cells + _collectionViewFlags.delegateShouldSelectItemAtIndexPath = (unsigned int)[self.delegate respondsToSelector:@selector(collectionView:shouldSelectItemAtIndexPath:)]; + _collectionViewFlags.delegateDidSelectItemAtIndexPath = (unsigned int)[self.delegate respondsToSelector:@selector(collectionView:didSelectItemAtIndexPath:)]; + _collectionViewFlags.delegateShouldDeselectItemAtIndexPath = (unsigned int)[self.delegate respondsToSelector:@selector(collectionView:shouldDeselectItemAtIndexPath:)]; + _collectionViewFlags.delegateDidDeselectItemAtIndexPath = (unsigned int)[self.delegate respondsToSelector:@selector(collectionView:didDeselectItemAtIndexPath:)]; + + // Managing Cell Highlighting + _collectionViewFlags.delegateShouldHighlightItemAtIndexPath = (unsigned int)[self.delegate respondsToSelector:@selector(collectionView:shouldHighlightItemAtIndexPath:)]; + _collectionViewFlags.delegateDidHighlightItemAtIndexPath = (unsigned int)[self.delegate respondsToSelector:@selector(collectionView:didHighlightItemAtIndexPath:)]; + _collectionViewFlags.delegateDidUnhighlightItemAtIndexPath = (unsigned int)[self.delegate respondsToSelector:@selector(collectionView:didUnhighlightItemAtIndexPath:)]; + + // Tracking the Removal of Views + _collectionViewFlags.delegateDidEndDisplayingCell = (unsigned int)[self.delegate respondsToSelector:@selector(collectionView:didEndDisplayingCell:forItemAtIndexPath:)]; + _collectionViewFlags.delegateDidEndDisplayingSupplementaryView = (unsigned int)[self.delegate respondsToSelector:@selector(collectionView:didEndDisplayingSupplementaryView:forElementOfKind:atIndexPath:)]; + + // Managing Actions for Cells + _collectionViewFlags.delegateSupportsMenus = (unsigned int)[self.delegate respondsToSelector:@selector(collectionView:shouldShowMenuForItemAtIndexPath:)]; + + // These aren't present in the flags which is a little strange. Not adding them because that will mess with byte alignment which will affect cross compatibility. + // The flag names are guesses and are there for documentation purposes. + // _collectionViewFlags.delegateCanPerformActionForItemAtIndexPath = [self.delegate respondsToSelector:@selector(collectionView:canPerformAction:forItemAtIndexPath:withSender:)]; + // _collectionViewFlags.delegatePerformActionForItemAtIndexPath = [self.delegate respondsToSelector:@selector(collectionView:performAction:forItemAtIndexPath:withSender:)]; +} + +// Might be overkill since two are required and two are handled by PSTCollectionViewData leaving only one flag we actually need to check for +- (void)setDataSource:(id)dataSource { + if (dataSource != _dataSource) { + _dataSource = dataSource; + + // Getting Item and Section Metrics + _collectionViewFlags.dataSourceNumberOfSections = (unsigned int)[_dataSource respondsToSelector:@selector(numberOfSectionsInCollectionView:)]; + + // Getting Views for Items + _collectionViewFlags.dataSourceViewForSupplementaryElement = (unsigned int)[_dataSource respondsToSelector:@selector(collectionView:viewForSupplementaryElementOfKind:atIndexPath:)]; + } +} + +- (BOOL)allowsSelection { + return _collectionViewFlags.allowsSelection; +} + +- (void)setAllowsSelection:(BOOL)allowsSelection { + _collectionViewFlags.allowsSelection = (unsigned int)allowsSelection; +} + +- (BOOL)allowsMultipleSelection { + return _collectionViewFlags.allowsMultipleSelection; +} + +- (void)setAllowsMultipleSelection:(BOOL)allowsMultipleSelection { + _collectionViewFlags.allowsMultipleSelection = (unsigned int)allowsMultipleSelection; + + // Deselect all objects if allows multiple selection is false + if (!allowsMultipleSelection && _indexPathsForSelectedItems.count) { + + // Note: Apple's implementation leaves a mostly random item selected. Presumably they + // have a good reason for this, but I guess it's just skipping the last or first index. + for (NSIndexPath *selectedIndexPath in [_indexPathsForSelectedItems copy]) { + if (_indexPathsForSelectedItems.count == 1) continue; + [self deselectItemAtIndexPath:selectedIndexPath animated:YES notifyDelegate:YES]; + } + } +} + +- (CGRect)visibleBoundRects { + // in original UICollectionView implementation they + // check for _visibleBounds and can union self.bounds + // with this value. Don't know the meaning of _visibleBounds however. + return self.bounds; +} +/////////////////////////////////////////////////////////////////////////////////////////// +#pragma mark - Private + +- (PSTCollectionViewExt *)extVars { + return objc_getAssociatedObject(self, &kPSTColletionViewExt); +} + +- (void)invalidateLayout { + [self.collectionViewLayout invalidateLayout]; + [self.collectionViewData invalidate]; // invalidate layout cache +} + +// update currently visible cells, fetches new cells if needed +// TODO: use now parameter. +- (void)updateVisibleCellsNow:(BOOL)now { + NSArray *layoutAttributesArray = [_collectionViewData layoutAttributesForElementsInRect:self.bounds]; + + if (layoutAttributesArray == nil || layoutAttributesArray.count == 0) { + // If our layout source isn't providing any layout information, we should just + // stop, otherwise we'll blow away all the currently existing cells. + return; + } + + // create ItemKey/Attributes dictionary + NSMutableDictionary *itemKeysToAddDict = [NSMutableDictionary dictionary]; + + // Add new cells. + for (PSTCollectionViewLayoutAttributes *layoutAttributes in layoutAttributesArray) { + PSTCollectionViewItemKey *itemKey = [PSTCollectionViewItemKey collectionItemKeyForLayoutAttributes:layoutAttributes]; + itemKeysToAddDict[itemKey] = layoutAttributes; + + // check if cell is in visible dict; add it if not. + PSTCollectionReusableView *view = _allVisibleViewsDict[itemKey]; + if (!view) { + if (itemKey.type == PSTCollectionViewItemTypeCell) { + view = [self createPreparedCellForItemAtIndexPath:itemKey.indexPath withLayoutAttributes:layoutAttributes]; + + }else if (itemKey.type == PSTCollectionViewItemTypeSupplementaryView) { + view = [self createPreparedSupplementaryViewForElementOfKind:layoutAttributes.representedElementKind + atIndexPath:layoutAttributes.indexPath + withLayoutAttributes:layoutAttributes]; + }else if (itemKey.type == PSTCollectionViewItemTypeDecorationView) { + view = [self dequeueReusableOrCreateDecorationViewOfKind:layoutAttributes.representedElementKind forIndexPath:layoutAttributes.indexPath]; + } + + // Supplementary views are optional + if (view) { + _allVisibleViewsDict[itemKey] = view; + [self addControlledSubview:view]; + + // Always apply attributes. Fixes #203. + [view applyLayoutAttributes:layoutAttributes]; + } + }else { + // just update cell + [view applyLayoutAttributes:layoutAttributes]; + } + } + + // Detect what items should be removed and queued back. + NSMutableSet *allVisibleItemKeys = [NSMutableSet setWithArray:[_allVisibleViewsDict allKeys]]; + [allVisibleItemKeys minusSet:[NSSet setWithArray:[itemKeysToAddDict allKeys]]]; + + // Finally remove views that have not been processed and prepare them for re-use. + for (PSTCollectionViewItemKey *itemKey in allVisibleItemKeys) { + PSTCollectionReusableView *reusableView = _allVisibleViewsDict[itemKey]; + if (reusableView) { + [reusableView removeFromSuperview]; + [_allVisibleViewsDict removeObjectForKey:itemKey]; + if (itemKey.type == PSTCollectionViewItemTypeCell) { + if (_collectionViewFlags.delegateDidEndDisplayingCell) { + [self.delegate collectionView:self didEndDisplayingCell:(PSTCollectionViewCell *)reusableView forItemAtIndexPath:itemKey.indexPath]; + } + [self reuseCell:(PSTCollectionViewCell *)reusableView]; + } + else if (itemKey.type == PSTCollectionViewItemTypeSupplementaryView) { + if (_collectionViewFlags.delegateDidEndDisplayingSupplementaryView) { + [self.delegate collectionView:self didEndDisplayingSupplementaryView:reusableView forElementOfKind:itemKey.identifier atIndexPath:itemKey.indexPath]; + } + [self reuseSupplementaryView:reusableView]; + } + else if (itemKey.type == PSTCollectionViewItemTypeDecorationView) { + [self reuseDecorationView:reusableView]; + } + } + } +} + +// fetches a cell from the dataSource and sets the layoutAttributes +- (PSTCollectionViewCell *)createPreparedCellForItemAtIndexPath:(NSIndexPath *)indexPath withLayoutAttributes:(PSTCollectionViewLayoutAttributes *)layoutAttributes { + PSTCollectionViewCell *cell = [self.dataSource collectionView:self cellForItemAtIndexPath:indexPath]; + + // Apply attributes + [cell applyLayoutAttributes:layoutAttributes]; + + // reset selected/highlight state + [cell setHighlighted:[_indexPathsForHighlightedItems containsObject:indexPath]]; + [cell setSelected:[_indexPathsForSelectedItems containsObject:indexPath]]; + + // voiceover support + cell.isAccessibilityElement = YES; + + return cell; +} + +- (PSTCollectionReusableView *)createPreparedSupplementaryViewForElementOfKind:(NSString *)kind + atIndexPath:(NSIndexPath *)indexPath + withLayoutAttributes:(PSTCollectionViewLayoutAttributes *)layoutAttributes { + if (_collectionViewFlags.dataSourceViewForSupplementaryElement) { + PSTCollectionReusableView *view = [self.dataSource collectionView:self + viewForSupplementaryElementOfKind:kind + atIndexPath:indexPath]; + [view applyLayoutAttributes:layoutAttributes]; + return view; + } + return nil; +} + +// @steipete optimization +- (void)queueReusableView:(PSTCollectionReusableView *)reusableView inQueue:(NSMutableDictionary *)queue withIdentifier:(NSString *)identifier { + NSParameterAssert(identifier.length > 0); + + [reusableView removeFromSuperview]; + [reusableView prepareForReuse]; + + // enqueue cell + NSMutableArray *reuseableViews = queue[identifier]; + if (!reuseableViews) { + reuseableViews = [NSMutableArray array]; + queue[identifier] = reuseableViews; + } + [reuseableViews addObject:reusableView]; +} + +// enqueue cell for reuse +- (void)reuseCell:(PSTCollectionViewCell *)cell { + [self queueReusableView:cell inQueue:_cellReuseQueues withIdentifier:cell.reuseIdentifier]; +} + +// enqueue supplementary view for reuse +- (void)reuseSupplementaryView:(PSTCollectionReusableView *)supplementaryView { + NSString *kindAndIdentifier = [NSString stringWithFormat:@"%@/%@", supplementaryView.layoutAttributes.elementKind, supplementaryView.reuseIdentifier]; + [self queueReusableView:supplementaryView inQueue:_supplementaryViewReuseQueues withIdentifier:kindAndIdentifier]; +} + +// enqueue decoration view for reuse +- (void)reuseDecorationView:(PSTCollectionReusableView *)decorationView { + [self queueReusableView:decorationView inQueue:_decorationViewReuseQueues withIdentifier:decorationView.reuseIdentifier]; +} + +- (void)addControlledSubview:(PSTCollectionReusableView *)subview { + // avoids placing views above the scroll indicator + // If the collection view is not displaying scrollIndicators then self.subviews.count can be 0. + // We take the max to ensure we insert at a non negative index because a negative index will silently fail to insert the view + NSInteger insertionIndex = MAX((NSInteger)(self.subviews.count - (self.dragging ? 1 : 0)), 0); + [self insertSubview:subview atIndex:insertionIndex]; + UIView *scrollIndicatorView = nil; + if (self.dragging) { + scrollIndicatorView = [self.subviews lastObject]; + } + + NSMutableArray *floatingViews = [[NSMutableArray alloc] init]; + for (UIView *uiView in self.subviews) { + if ([uiView isKindOfClass:PSTCollectionReusableView.class] && [[(PSTCollectionReusableView *)uiView layoutAttributes] zIndex] > 0) { + [floatingViews addObject:uiView]; + } + } + + [floatingViews sortUsingComparator:^NSComparisonResult(PSTCollectionReusableView *obj1, PSTCollectionReusableView *obj2) { + CGFloat z1 = [[obj1 layoutAttributes] zIndex]; + CGFloat z2 = [[obj2 layoutAttributes] zIndex]; + if (z1 > z2) { + return (NSComparisonResult)NSOrderedDescending; + }else if (z1 < z2) { + return (NSComparisonResult)NSOrderedAscending; + }else { + return (NSComparisonResult)NSOrderedSame; + } + }]; + + for (PSTCollectionReusableView *uiView in floatingViews) { + [self bringSubviewToFront:uiView]; + } + + if (floatingViews.count && scrollIndicatorView) { + [self bringSubviewToFront:scrollIndicatorView]; + } +} + +/////////////////////////////////////////////////////////////////////////////////////////// +#pragma mark - Updating grid internal functionality + +- (void)suspendReloads { + _reloadingSuspendedCount++; +} + +- (void)resumeReloads { + if (0 < _reloadingSuspendedCount) _reloadingSuspendedCount--; +} + +- (NSMutableArray *)arrayForUpdateAction:(PSTCollectionUpdateAction)updateAction { + NSMutableArray *updateActions = nil; + + switch (updateAction) { + case PSTCollectionUpdateActionInsert: + if (!_insertItems) _insertItems = [NSMutableArray new]; + updateActions = _insertItems; + break; + case PSTCollectionUpdateActionDelete: + if (!_deleteItems) _deleteItems = [NSMutableArray new]; + updateActions = _deleteItems; + break; + case PSTCollectionUpdateActionMove: + if (!_moveItems) _moveItems = [NSMutableArray new]; + updateActions = _moveItems; + break; + case PSTCollectionUpdateActionReload: + if (!_reloadItems) _reloadItems = [NSMutableArray new]; + updateActions = _reloadItems; + break; + default: break; + } + return updateActions; +} + +- (void)prepareLayoutForUpdates { + NSMutableArray *array = [[NSMutableArray alloc] init]; + [array addObjectsFromArray:[_originalDeleteItems sortedArrayUsingSelector:@selector(inverseCompareIndexPaths:)]]; + [array addObjectsFromArray:[_originalInsertItems sortedArrayUsingSelector:@selector(compareIndexPaths:)]]; + [array addObjectsFromArray:[_reloadItems sortedArrayUsingSelector:@selector(compareIndexPaths:)]]; + [array addObjectsFromArray:[_moveItems sortedArrayUsingSelector:@selector(compareIndexPaths:)]]; + [_layout prepareForCollectionViewUpdates:array]; +} + +- (void)updateWithItems:(NSArray *)items { + [self prepareLayoutForUpdates]; + + NSMutableArray *animations = [[NSMutableArray alloc] init]; + NSMutableDictionary *newAllVisibleView = [[NSMutableDictionary alloc] init]; + + NSMutableDictionary *viewsToRemove = [NSMutableDictionary dictionaryWithObjectsAndKeys: + [NSMutableArray array], @(PSTCollectionViewItemTypeCell), + [NSMutableArray array], @(PSTCollectionViewItemTypeDecorationView), + [NSMutableArray array], @(PSTCollectionViewItemTypeSupplementaryView), nil]; + + for (PSTCollectionViewUpdateItem *updateItem in items) { + if (updateItem.isSectionOperation && updateItem.updateAction != PSTCollectionUpdateActionDelete) continue; + if (updateItem.isSectionOperation && updateItem.updateAction == PSTCollectionUpdateActionDelete) { + NSInteger numberOfBeforeSection = [_update[@"oldModel"] numberOfItemsInSection:updateItem.indexPathBeforeUpdate.section]; + for (NSInteger i = 0; i < numberOfBeforeSection; i++) { + NSIndexPath *indexPath = [NSIndexPath indexPathForItem:i inSection:updateItem.indexPathBeforeUpdate.section]; + + PSTCollectionViewLayoutAttributes *finalAttrs = [_layout finalLayoutAttributesForDisappearingItemAtIndexPath:indexPath]; + PSTCollectionViewItemKey *key = [PSTCollectionViewItemKey collectionItemKeyForCellWithIndexPath:indexPath]; + PSTCollectionReusableView *view = _allVisibleViewsDict[key]; + if (view) { + PSTCollectionViewLayoutAttributes *startAttrs = view.layoutAttributes; + + if (!finalAttrs) { + finalAttrs = [startAttrs copy]; + finalAttrs.alpha = 0; + } + [animations addObject:@{@"view" : view, @"previousLayoutInfos" : startAttrs, @"newLayoutInfos" : finalAttrs}]; + + [_allVisibleViewsDict removeObjectForKey:key]; + + [(NSMutableArray *)viewsToRemove[@(key.type)] addObject:view]; + + } + } + continue; + } + + if (updateItem.updateAction == PSTCollectionUpdateActionDelete) { + NSIndexPath *indexPath = updateItem.indexPathBeforeUpdate; + + PSTCollectionViewLayoutAttributes *finalAttrs = [_layout finalLayoutAttributesForDisappearingItemAtIndexPath:indexPath]; + PSTCollectionViewItemKey *key = [PSTCollectionViewItemKey collectionItemKeyForCellWithIndexPath:indexPath]; + PSTCollectionReusableView *view = _allVisibleViewsDict[key]; + if (view) { + PSTCollectionViewLayoutAttributes *startAttrs = view.layoutAttributes; + + if (!finalAttrs) { + finalAttrs = [startAttrs copy]; + finalAttrs.alpha = 0; + } + [animations addObject:@{@"view" : view, @"previousLayoutInfos" : startAttrs, @"newLayoutInfos" : finalAttrs}]; + + [_allVisibleViewsDict removeObjectForKey:key]; + + [(NSMutableArray *)viewsToRemove[@(key.type)] addObject:view]; + + } + } + else if (updateItem.updateAction == PSTCollectionUpdateActionInsert) { + NSIndexPath *indexPath = updateItem.indexPathAfterUpdate; + PSTCollectionViewItemKey *key = [PSTCollectionViewItemKey collectionItemKeyForCellWithIndexPath:indexPath]; + PSTCollectionViewLayoutAttributes *startAttrs = [_layout initialLayoutAttributesForAppearingItemAtIndexPath:indexPath]; + PSTCollectionViewLayoutAttributes *finalAttrs = [_layout layoutAttributesForItemAtIndexPath:indexPath]; + + CGRect startRect = startAttrs.frame; + CGRect finalRect = finalAttrs.frame; + + if (CGRectIntersectsRect(self.visibleBoundRects, startRect) || CGRectIntersectsRect(self.visibleBoundRects, finalRect)) { + + if (!startAttrs) { + startAttrs = [finalAttrs copy]; + startAttrs.alpha = 0; + } + + PSTCollectionReusableView *view = [self createPreparedCellForItemAtIndexPath:indexPath + withLayoutAttributes:startAttrs]; + [self addControlledSubview:view]; + + newAllVisibleView[key] = view; + [animations addObject:@{@"view" : view, @"previousLayoutInfos" : startAttrs, @"newLayoutInfos" : finalAttrs}]; + } + } + else if (updateItem.updateAction == PSTCollectionUpdateActionMove) { + NSIndexPath *indexPathBefore = updateItem.indexPathBeforeUpdate; + NSIndexPath *indexPathAfter = updateItem.indexPathAfterUpdate; + + PSTCollectionViewItemKey *keyBefore = [PSTCollectionViewItemKey collectionItemKeyForCellWithIndexPath:indexPathBefore]; + PSTCollectionViewItemKey *keyAfter = [PSTCollectionViewItemKey collectionItemKeyForCellWithIndexPath:indexPathAfter]; + PSTCollectionReusableView *view = _allVisibleViewsDict[keyBefore]; + + PSTCollectionViewLayoutAttributes *startAttrs = nil; + PSTCollectionViewLayoutAttributes *finalAttrs = [_layout layoutAttributesForItemAtIndexPath:indexPathAfter]; + + if (view) { + startAttrs = view.layoutAttributes; + [_allVisibleViewsDict removeObjectForKey:keyBefore]; + newAllVisibleView[keyAfter] = view; + } + else { + startAttrs = [finalAttrs copy]; + startAttrs.alpha = 0; + view = [self createPreparedCellForItemAtIndexPath:indexPathAfter withLayoutAttributes:startAttrs]; + [self addControlledSubview:view]; + newAllVisibleView[keyAfter] = view; + } + + [animations addObject:@{@"view" : view, @"previousLayoutInfos" : startAttrs, @"newLayoutInfos" : finalAttrs}]; + } + } + + for (PSTCollectionViewItemKey *key in [_allVisibleViewsDict keyEnumerator]) { + PSTCollectionReusableView *view = _allVisibleViewsDict[key]; + + if (key.type == PSTCollectionViewItemTypeCell) { + NSUInteger oldGlobalIndex = [_update[@"oldModel"] globalIndexForItemAtIndexPath:key.indexPath]; + NSArray *oldToNewIndexMap = _update[@"oldToNewIndexMap"]; + NSUInteger newGlobalIndex = NSNotFound; + if (NSNotFound != oldGlobalIndex && oldGlobalIndex < oldToNewIndexMap.count) { + newGlobalIndex = [oldToNewIndexMap[oldGlobalIndex] unsignedIntegerValue]; + } + NSIndexPath *newIndexPath = newGlobalIndex == NSNotFound ? nil : [_update[@"newModel"] indexPathForItemAtGlobalIndex:(int)newGlobalIndex]; + NSIndexPath *oldIndexPath = oldGlobalIndex == NSNotFound ? nil : [_update[@"oldModel"] indexPathForItemAtGlobalIndex:(int)oldGlobalIndex]; + + if (newIndexPath) { + PSTCollectionViewLayoutAttributes *startAttrs = nil; + PSTCollectionViewLayoutAttributes *finalAttrs = nil; + + startAttrs = [_layout initialLayoutAttributesForAppearingItemAtIndexPath:oldIndexPath]; + finalAttrs = [_layout layoutAttributesForItemAtIndexPath:newIndexPath]; + + NSMutableDictionary *dic = [NSMutableDictionary dictionaryWithDictionary:@{@"view" : view}]; + if (startAttrs) dic[@"previousLayoutInfos"] = startAttrs; + if (finalAttrs) dic[@"newLayoutInfos"] = finalAttrs; + + [animations addObject:dic]; + PSTCollectionViewItemKey *newKey = [key copy]; + [newKey setIndexPath:newIndexPath]; + newAllVisibleView[newKey] = view; + + } + }else if (key.type == PSTCollectionViewItemTypeSupplementaryView) { + PSTCollectionViewLayoutAttributes *startAttrs = nil; + PSTCollectionViewLayoutAttributes *finalAttrs = nil; + + startAttrs = view.layoutAttributes; + finalAttrs = [_layout layoutAttributesForSupplementaryViewOfKind:view.layoutAttributes.representedElementKind atIndexPath:key.indexPath]; + + NSMutableDictionary *dic = [NSMutableDictionary dictionaryWithDictionary:@{@"view" : view}]; + if (startAttrs) dic[@"previousLayoutInfos"] = startAttrs; + if (finalAttrs) dic[@"newLayoutInfos"] = finalAttrs; + + [animations addObject:dic]; + PSTCollectionViewItemKey *newKey = [key copy]; + newAllVisibleView[newKey] = view; + + } + } + NSArray *allNewlyVisibleItems = [_layout layoutAttributesForElementsInRect:self.visibleBoundRects]; + for (PSTCollectionViewLayoutAttributes *attrs in allNewlyVisibleItems) { + PSTCollectionViewItemKey *key = [PSTCollectionViewItemKey collectionItemKeyForLayoutAttributes:attrs]; + + if (key.type == PSTCollectionViewItemTypeCell && ![[newAllVisibleView allKeys] containsObject:key]) { + PSTCollectionViewLayoutAttributes *startAttrs = + [_layout initialLayoutAttributesForAppearingItemAtIndexPath:attrs.indexPath]; + + PSTCollectionReusableView *view = [self createPreparedCellForItemAtIndexPath:attrs.indexPath + withLayoutAttributes:startAttrs]; + [self addControlledSubview:view]; + newAllVisibleView[key] = view; + + [animations addObject:@{@"view" : view, @"previousLayoutInfos" : startAttrs ? startAttrs : attrs, @"newLayoutInfos" : attrs}]; + } + } + + //In here I think it doesn't need the animation but the transaction, it would cause some issue of display. + //I resolve the bug when user insert the new sections, the cell will display with a blink animation at the first operation. + //But I don't know why the next operation wouldn't reproduction in the pre version. + _allVisibleViewsDict = newAllVisibleView; + + for (NSDictionary *animation in animations) { + PSTCollectionReusableView *view = animation[@"view"]; + PSTCollectionViewLayoutAttributes *attr = animation[@"previousLayoutInfos"]; + [view applyLayoutAttributes:attr]; + }; + + _collectionViewFlags.updatingLayout = YES; + + [CATransaction begin]; + [CATransaction setAnimationDuration:0]; + [CATransaction setCompletionBlock:^{ + // Iterate through all the views that we are going to remove. + [viewsToRemove enumerateKeysAndObjectsUsingBlock:^(NSNumber *keyObj, NSArray *views, BOOL *stop) { + PSTCollectionViewItemType type = [keyObj unsignedIntegerValue]; + for (PSTCollectionReusableView *view in views) { + if (type == PSTCollectionViewItemTypeCell) { + [self reuseCell:(PSTCollectionViewCell *)view]; + } else if (type == PSTCollectionViewItemTypeSupplementaryView) { + [self reuseSupplementaryView:view]; + } else if (type == PSTCollectionViewItemTypeDecorationView) { + [self reuseDecorationView:view]; + } + } + }]; + + _collectionViewFlags.updatingLayout = NO; + + //In here I think when the block is called, the flag is YES. So the _updateCopletionHandler's paramer is YES. + if (_updateCompletionHandler) { + _updateCompletionHandler(YES); + _updateCompletionHandler = nil; + } + }]; + + for (NSDictionary *animation in animations) { + PSTCollectionReusableView *view = animation[@"view"]; + PSTCollectionViewLayoutAttributes *attrs = animation[@"newLayoutInfos"]; + [view applyLayoutAttributes:attrs]; + } + [CATransaction commit]; + + [_layout finalizeCollectionViewUpdates]; +} + +- (void)setupCellAnimations { + [self updateVisibleCellsNow:YES]; + [self suspendReloads]; + _collectionViewFlags.updating = YES; +} + +- (void)endItemAnimations { + _updateCount++; + PSTCollectionViewData *oldCollectionViewData = _collectionViewData; + _collectionViewData = [[PSTCollectionViewData alloc] initWithCollectionView:self layout:_layout]; + + [_layout invalidateLayout]; + [_collectionViewData prepareToLoadData]; + + NSMutableArray *someMutableArr1 = [[NSMutableArray alloc] init]; + + NSArray *removeUpdateItems = [[self arrayForUpdateAction:PSTCollectionUpdateActionDelete] + sortedArrayUsingSelector:@selector(inverseCompareIndexPaths:)]; + + NSArray *insertUpdateItems = [[self arrayForUpdateAction:PSTCollectionUpdateActionInsert] + sortedArrayUsingSelector:@selector(compareIndexPaths:)]; + + NSMutableArray *sortedMutableReloadItems = [[_reloadItems sortedArrayUsingSelector:@selector(compareIndexPaths:)] mutableCopy]; + NSMutableArray *sortedMutableMoveItems = [[_moveItems sortedArrayUsingSelector:@selector(compareIndexPaths:)] mutableCopy]; + + _originalDeleteItems = [removeUpdateItems copy]; + _originalInsertItems = [insertUpdateItems copy]; + + NSMutableArray *someMutableArr2 = [[NSMutableArray alloc] init]; + NSMutableArray *someMutableArr3 = [[NSMutableArray alloc] init]; + NSMutableDictionary *operations = [[NSMutableDictionary alloc] init]; + + for (PSTCollectionViewUpdateItem *updateItem in sortedMutableReloadItems) { + NSAssert(updateItem.indexPathBeforeUpdate.section < [oldCollectionViewData numberOfSections], + @"attempt to reload item (%@) that doesn't exist (there are only %ld sections before update)", + updateItem.indexPathBeforeUpdate, (long)[oldCollectionViewData numberOfSections]); + + if (updateItem.indexPathBeforeUpdate.item != NSNotFound) { + NSAssert(updateItem.indexPathBeforeUpdate.item < [oldCollectionViewData numberOfItemsInSection:updateItem.indexPathBeforeUpdate.section], + @"attempt to reload item (%@) that doesn't exist (there are only %ld items in section %ld before update)", + updateItem.indexPathBeforeUpdate, + (long)[oldCollectionViewData numberOfItemsInSection:updateItem.indexPathBeforeUpdate.section], + (long)updateItem.indexPathBeforeUpdate.section); + } + + [someMutableArr2 addObject:[[PSTCollectionViewUpdateItem alloc] initWithAction:PSTCollectionUpdateActionDelete + forIndexPath:updateItem.indexPathBeforeUpdate]]; + [someMutableArr3 addObject:[[PSTCollectionViewUpdateItem alloc] initWithAction:PSTCollectionUpdateActionInsert + forIndexPath:updateItem.indexPathAfterUpdate]]; + } + + NSMutableArray *sortedDeletedMutableItems = [[_deleteItems sortedArrayUsingSelector:@selector(inverseCompareIndexPaths:)] mutableCopy]; + NSMutableArray *sortedInsertMutableItems = [[_insertItems sortedArrayUsingSelector:@selector(compareIndexPaths:)] mutableCopy]; + + for (PSTCollectionViewUpdateItem *deleteItem in sortedDeletedMutableItems) { + if ([deleteItem isSectionOperation]) { + NSAssert(deleteItem.indexPathBeforeUpdate.section < [oldCollectionViewData numberOfSections], + @"attempt to delete section (%ld) that doesn't exist (there are only %ld sections before update)", + (long)deleteItem.indexPathBeforeUpdate.section, + (long)[oldCollectionViewData numberOfSections]); + + for (PSTCollectionViewUpdateItem *moveItem in sortedMutableMoveItems) { + if (moveItem.indexPathBeforeUpdate.section == deleteItem.indexPathBeforeUpdate.section) { + if (moveItem.isSectionOperation) + NSAssert(NO, @"attempt to delete and move from the same section %ld", (long)deleteItem.indexPathBeforeUpdate.section); + else + NSAssert(NO, @"attempt to delete and move from the same section (%@)", moveItem.indexPathBeforeUpdate); + } + } + }else { + NSAssert(deleteItem.indexPathBeforeUpdate.section < [oldCollectionViewData numberOfSections], + @"attempt to delete item (%@) that doesn't exist (there are only %ld sections before update)", + deleteItem.indexPathBeforeUpdate, + (long)[oldCollectionViewData numberOfSections]); + NSAssert(deleteItem.indexPathBeforeUpdate.item < [oldCollectionViewData numberOfItemsInSection:deleteItem.indexPathBeforeUpdate.section], + @"attempt to delete item (%@) that doesn't exist (there are only %ld items in section%ld before update)", + deleteItem.indexPathBeforeUpdate, + (long)[oldCollectionViewData numberOfItemsInSection:deleteItem.indexPathBeforeUpdate.section], + (long)deleteItem.indexPathBeforeUpdate.section); + + for (PSTCollectionViewUpdateItem *moveItem in sortedMutableMoveItems) { + NSAssert(![deleteItem.indexPathBeforeUpdate isEqual:moveItem.indexPathBeforeUpdate], + @"attempt to delete and move the same item (%@)", deleteItem.indexPathBeforeUpdate); + } + + if (!operations[@(deleteItem.indexPathBeforeUpdate.section)]) + operations[@(deleteItem.indexPathBeforeUpdate.section)] = [NSMutableDictionary dictionary]; + + operations[@(deleteItem.indexPathBeforeUpdate.section)][@"deleted"] = + @([operations[@(deleteItem.indexPathBeforeUpdate.section)][@"deleted"] intValue] + 1); + } + } + + for (NSUInteger i = 0; i < sortedInsertMutableItems.count; i++) { + PSTCollectionViewUpdateItem *insertItem = sortedInsertMutableItems[i]; + NSIndexPath *indexPath = insertItem.indexPathAfterUpdate; + + BOOL sectionOperation = [insertItem isSectionOperation]; + if (sectionOperation) { + NSAssert([indexPath section] < [_collectionViewData numberOfSections], + @"attempt to insert %ld but there are only %ld sections after update", + (long)[indexPath section], (long)[_collectionViewData numberOfSections]); + + for (PSTCollectionViewUpdateItem *moveItem in sortedMutableMoveItems) { + if ([moveItem.indexPathAfterUpdate isEqual:indexPath]) { + if (moveItem.isSectionOperation) + NSAssert(NO, @"attempt to perform an insert and a move to the same section (%ld)", (long)indexPath.section); + } + } + + NSUInteger j = i + 1; + while (j < sortedInsertMutableItems.count) { + PSTCollectionViewUpdateItem *nextInsertItem = sortedInsertMutableItems[j]; + + if (nextInsertItem.indexPathAfterUpdate.section == indexPath.section) { + NSAssert(nextInsertItem.indexPathAfterUpdate.item < [_collectionViewData numberOfItemsInSection:indexPath.section], + @"attempt to insert item %ld into section %ld, but there are only %ld items in section %ld after the update", + (long)nextInsertItem.indexPathAfterUpdate.item, + (long)indexPath.section, + (long)[_collectionViewData numberOfItemsInSection:indexPath.section], + (long)indexPath.section); + [sortedInsertMutableItems removeObjectAtIndex:j]; + } + else break; + } + }else { + NSAssert(indexPath.item < [_collectionViewData numberOfItemsInSection:indexPath.section], + @"attempt to insert item to (%@) but there are only %ld items in section %ld after update", + indexPath, + (long)[_collectionViewData numberOfItemsInSection:indexPath.section], + (long)indexPath.section); + + if (!operations[@(indexPath.section)]) + operations[@(indexPath.section)] = [NSMutableDictionary dictionary]; + + operations[@(indexPath.section)][@"inserted"] = + @([operations[@(indexPath.section)][@"inserted"] intValue] + 1); + } + } + + for (PSTCollectionViewUpdateItem *sortedItem in sortedMutableMoveItems) { + if (sortedItem.isSectionOperation) { + NSAssert(sortedItem.indexPathBeforeUpdate.section < [oldCollectionViewData numberOfSections], + @"attempt to move section (%ld) that doesn't exist (%ld sections before update)", + (long)sortedItem.indexPathBeforeUpdate.section, + (long)[oldCollectionViewData numberOfSections]); + NSAssert(sortedItem.indexPathAfterUpdate.section < [_collectionViewData numberOfSections], + @"attempt to move section to %ld but there are only %ld sections after update", + (long)sortedItem.indexPathAfterUpdate.section, + (long)[_collectionViewData numberOfSections]); + }else { + NSAssert(sortedItem.indexPathBeforeUpdate.section < [oldCollectionViewData numberOfSections], + @"attempt to move item (%@) that doesn't exist (%ld sections before update)", + sortedItem, (long)[oldCollectionViewData numberOfSections]); + NSAssert(sortedItem.indexPathBeforeUpdate.item < [oldCollectionViewData numberOfItemsInSection:sortedItem.indexPathBeforeUpdate.section], + @"attempt to move item (%@) that doesn't exist (%ld items in section %ld before update)", + sortedItem, + (long)[oldCollectionViewData numberOfItemsInSection:sortedItem.indexPathBeforeUpdate.section], + (long)sortedItem.indexPathBeforeUpdate.section); + + NSAssert(sortedItem.indexPathAfterUpdate.section < [_collectionViewData numberOfSections], + @"attempt to move item to (%@) but there are only %ld sections after update", + sortedItem.indexPathAfterUpdate, + (long)[_collectionViewData numberOfSections]); + NSAssert(sortedItem.indexPathAfterUpdate.item < [_collectionViewData numberOfItemsInSection:sortedItem.indexPathAfterUpdate.section], + @"attempt to move item to (%@) but there are only %ld items in section %ld after update", + sortedItem, + (long)[_collectionViewData numberOfItemsInSection:sortedItem.indexPathAfterUpdate.section], + (long)sortedItem.indexPathAfterUpdate.section); + } + + if (!operations[@(sortedItem.indexPathBeforeUpdate.section)]) + operations[@(sortedItem.indexPathBeforeUpdate.section)] = [NSMutableDictionary dictionary]; + if (!operations[@(sortedItem.indexPathAfterUpdate.section)]) + operations[@(sortedItem.indexPathAfterUpdate.section)] = [NSMutableDictionary dictionary]; + + operations[@(sortedItem.indexPathBeforeUpdate.section)][@"movedOut"] = + @([operations[@(sortedItem.indexPathBeforeUpdate.section)][@"movedOut"] intValue] + 1); + + operations[@(sortedItem.indexPathAfterUpdate.section)][@"movedIn"] = + @([operations[@(sortedItem.indexPathAfterUpdate.section)][@"movedIn"] intValue] + 1); + } + +#if !defined NS_BLOCK_ASSERTIONS + for (NSNumber *sectionKey in [operations keyEnumerator]) { + NSInteger section = [sectionKey integerValue]; + + NSInteger insertedCount = [operations[sectionKey][@"inserted"] integerValue]; + NSInteger deletedCount = [operations[sectionKey][@"deleted"] integerValue]; + NSInteger movedInCount = [operations[sectionKey][@"movedIn"] integerValue]; + NSInteger movedOutCount = [operations[sectionKey][@"movedOut"] integerValue]; + + NSAssert([oldCollectionViewData numberOfItemsInSection:section] + insertedCount - deletedCount + movedInCount - movedOutCount == + [_collectionViewData numberOfItemsInSection:section], + @"invalid update in section %ld: number of items after update (%ld) should be equal to the number of items before update (%ld) "\ + "plus count of inserted items (%ld), minus count of deleted items (%ld), plus count of items moved in (%ld), minus count of items moved out (%ld)", + (long)section, + (long)[_collectionViewData numberOfItemsInSection:section], + (long)[oldCollectionViewData numberOfItemsInSection:section], + (long)insertedCount, (long)deletedCount, (long)movedInCount, (long)movedOutCount); + } +#endif + + [someMutableArr2 addObjectsFromArray:sortedDeletedMutableItems]; + [someMutableArr3 addObjectsFromArray:sortedInsertMutableItems]; + [someMutableArr1 addObjectsFromArray:[someMutableArr2 sortedArrayUsingSelector:@selector(inverseCompareIndexPaths:)]]; + [someMutableArr1 addObjectsFromArray:sortedMutableMoveItems]; + [someMutableArr1 addObjectsFromArray:[someMutableArr3 sortedArrayUsingSelector:@selector(compareIndexPaths:)]]; + + NSMutableArray *layoutUpdateItems = [[NSMutableArray alloc] init]; + + [layoutUpdateItems addObjectsFromArray:sortedDeletedMutableItems]; + [layoutUpdateItems addObjectsFromArray:sortedMutableMoveItems]; + [layoutUpdateItems addObjectsFromArray:sortedInsertMutableItems]; + + + NSMutableArray *newModel = [NSMutableArray array]; + for (NSInteger i = 0; i < [oldCollectionViewData numberOfSections]; i++) { + NSMutableArray *sectionArr = [NSMutableArray array]; + for (NSInteger j = 0; j < [oldCollectionViewData numberOfItemsInSection:i]; j++) + [sectionArr addObject:@([oldCollectionViewData globalIndexForItemAtIndexPath:[NSIndexPath indexPathForItem:j inSection:i]])]; + [newModel addObject:sectionArr]; + } + + for (PSTCollectionViewUpdateItem *updateItem in layoutUpdateItems) { + switch (updateItem.updateAction) { + case PSTCollectionUpdateActionDelete: { + if (updateItem.isSectionOperation) { + // section updates are ignored anyway in animation code. If not commented, mixing rows and section deletion causes crash in else below + // [newModel removeObjectAtIndex:updateItem.indexPathBeforeUpdate.section]; + }else { + [(NSMutableArray *)newModel[(NSUInteger)updateItem.indexPathBeforeUpdate.section] + removeObjectAtIndex:(NSUInteger)updateItem.indexPathBeforeUpdate.item]; + } + } + break; + case PSTCollectionUpdateActionInsert: { + if (updateItem.isSectionOperation) { + [newModel insertObject:[[NSMutableArray alloc] init] + atIndex:(NSUInteger)updateItem.indexPathAfterUpdate.section]; + }else { + [(NSMutableArray *)newModel[(NSUInteger)updateItem.indexPathAfterUpdate.section] + insertObject:@(NSNotFound) + atIndex:(NSUInteger)updateItem.indexPathAfterUpdate.item]; + } + } + break; + + case PSTCollectionUpdateActionMove: { + if (updateItem.isSectionOperation) { + id section = newModel[(NSUInteger)updateItem.indexPathBeforeUpdate.section]; + [newModel insertObject:section atIndex:(NSUInteger)updateItem.indexPathAfterUpdate.section]; + } + else { + id object = @([oldCollectionViewData globalIndexForItemAtIndexPath:updateItem.indexPathBeforeUpdate]); + [newModel[(NSUInteger)updateItem.indexPathBeforeUpdate.section] removeObject:object]; + [newModel[(NSUInteger)updateItem.indexPathAfterUpdate.section] insertObject:object + atIndex:(NSUInteger)updateItem.indexPathAfterUpdate.item]; + } + } + break; + default: break; + } + } + + NSMutableArray *oldToNewMap = [NSMutableArray arrayWithCapacity:(NSUInteger)[oldCollectionViewData numberOfItems]]; + NSMutableArray *newToOldMap = [NSMutableArray arrayWithCapacity:(NSUInteger)[_collectionViewData numberOfItems]]; + + for (NSInteger i = 0; i < [oldCollectionViewData numberOfItems]; i++) + [oldToNewMap addObject:@(NSNotFound)]; + + for (NSInteger i = 0; i < [_collectionViewData numberOfItems]; i++) + [newToOldMap addObject:@(NSNotFound)]; + + for (NSUInteger i = 0; i < newModel.count; i++) { + NSMutableArray *section = newModel[i]; + for (NSUInteger j = 0; j < section.count; j++) { + NSUInteger newGlobalIndex = [_collectionViewData globalIndexForItemAtIndexPath:[NSIndexPath indexPathForItem:(NSInteger)j inSection:(NSInteger)i]]; + if ([section[j] integerValue] != NSNotFound) + oldToNewMap[[section[j] unsignedIntegerValue]] = @(newGlobalIndex); + if (newGlobalIndex != NSNotFound) + newToOldMap[newGlobalIndex] = section[j]; + } + } + + _update = @{@"oldModel" : oldCollectionViewData, @"newModel" : _collectionViewData, @"oldToNewIndexMap" : oldToNewMap, @"newToOldIndexMap" : newToOldMap}; + + [self updateWithItems:someMutableArr1]; + + _originalInsertItems = nil; + _originalDeleteItems = nil; + _insertItems = nil; + _deleteItems = nil; + _moveItems = nil; + _reloadItems = nil; + _update = nil; + _updateCount--; + _collectionViewFlags.updating = NO; + [self resumeReloads]; +} + +- (void)updateRowsAtIndexPaths:(NSArray *)indexPaths updateAction:(PSTCollectionUpdateAction)updateAction { + BOOL updating = _collectionViewFlags.updating; + if (!updating) [self setupCellAnimations]; + + NSMutableArray *array = [self arrayForUpdateAction:updateAction]; //returns appropriate empty array if not exists + + for (NSIndexPath *indexPath in indexPaths) { + PSTCollectionViewUpdateItem *updateItem = [[PSTCollectionViewUpdateItem alloc] initWithAction:updateAction forIndexPath:indexPath]; + [array addObject:updateItem]; + } + + if (!updating) [self endItemAnimations]; +} + + +- (void)updateSections:(NSIndexSet *)sections updateAction:(PSTCollectionUpdateAction)updateAction { + BOOL updating = _collectionViewFlags.updating; + if (!updating) [self setupCellAnimations]; + + NSMutableArray *updateActions = [self arrayForUpdateAction:updateAction]; + + [sections enumerateIndexesUsingBlock:^(NSUInteger section, BOOL *stop) { + PSTCollectionViewUpdateItem *updateItem = [[PSTCollectionViewUpdateItem alloc] initWithAction:updateAction forIndexPath:[NSIndexPath indexPathForItem:NSNotFound inSection:(NSInteger)section]]; + [updateActions addObject:updateItem]; + }]; + + if (!updating) [self endItemAnimations]; +} + +/////////////////////////////////////////////////////////////////////////////////////////// +#pragma mark - PSTCollection/UICollection interoperability + +#ifdef kPSUIInteroperabilityEnabled +#import +- (NSMethodSignature *)methodSignatureForSelector:(SEL)selector { + NSMethodSignature *sig = [super methodSignatureForSelector:selector]; + if(!sig) { + NSString *selString = NSStringFromSelector(selector); + if ([selString hasPrefix:@"_"]) { + SEL cleanedSelector = NSSelectorFromString([selString substringFromIndex:1]); + sig = [super methodSignatureForSelector:cleanedSelector]; + } + } + return sig; +} +- (void)forwardInvocation:(NSInvocation *)inv { + NSString *selString = NSStringFromSelector([inv selector]); + if ([selString hasPrefix:@"_"]) { + SEL cleanedSelector = NSSelectorFromString([selString substringFromIndex:1]); + if ([self respondsToSelector:cleanedSelector]) { + // dynamically add method for faster resolving + Method newMethod = class_getInstanceMethod(self.class, [inv selector]); + IMP underscoreIMP = imp_implementationWithBlock(^(id _self) { + return objc_msgSend(_self, cleanedSelector); + }); + class_addMethod(self.class, [inv selector], underscoreIMP, method_getTypeEncoding(newMethod)); + // invoke now + inv.selector = cleanedSelector; + [inv invokeWithTarget:self]; + } + }else { + [super forwardInvocation:inv]; + } +} +#endif + +@end + +/////////////////////////////////////////////////////////////////////////////////////////// +#pragma mark - Runtime Additions to create UICollectionView + +@implementation PSUICollectionView_ @end +@implementation PSUICollectionViewCell_ @end +@implementation PSUICollectionReusableView_ @end +@implementation PSUICollectionViewLayout_ @end +@implementation PSUICollectionViewFlowLayout_ @end +@implementation PSUICollectionViewLayoutAttributes_ @end +@implementation PSUICollectionViewController_ @end + +static void PSTRegisterClasses() { + NSDictionary *map = @{ + @"UICollectionView": PSUICollectionView_.class, + @"UICollectionViewCell": PSUICollectionViewCell_.class, + @"UICollectionReusableView": PSUICollectionReusableView_.class, + @"UICollectionViewLayout": PSUICollectionViewLayout_.class, + @"UICollectionViewFlowLayout": PSUICollectionViewFlowLayout_.class, + @"UICollectionViewLayoutAttributes": PSUICollectionViewLayoutAttributes_.class, + @"UICollectionViewController": PSUICollectionViewController_.class + }; + + // Ensure that superclass replacement is all-or-nothing for the PSUI*_ types. Either use exclusively + // UICollectionView*, or exclusively PSTCollectionView*. + __block BOOL canOverwrite = YES; + [map enumerateKeysAndObjectsUsingBlock:^(NSString* UIClassName, id PSTClass, BOOL *stop) { + Class UIClass = NSClassFromString(UIClassName); + if (UIClass) { + // Class size need to be the same for class_setSuperclass to work. + // If the UIKit class is smaller then our subclass, ivars won't clash, so there's no issue. + long sizeDifference = (long)class_getInstanceSize(UIClass) - class_getInstanceSize(PSTClass); + if (sizeDifference > 0) { + canOverwrite = NO; + NSLog(@"Warning! ivar size mismatch in %@ of %tu bytes - can't change the superclass.", PSTClass, sizeDifference); + } + } else { + canOverwrite = NO; + // We're most likely on iOS5, the requested UIKit class doesn't exist, so we create it dynamically. + if ((UIClass = objc_allocateClassPair(PSTClass, UIClassName.UTF8String, 0))) { + objc_registerClassPair(UIClass); + } + } + }]; + + if (canOverwrite) { + // All UICollectionView types were found and appropriately sized, so it is safe to replace the super-class. + [map enumerateKeysAndObjectsUsingBlock:^(NSString* UIClassName, id PSTClass, BOOL *stop) { + Class UIClass = NSClassFromString(UIClassName); +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wdeprecated-declarations" + // class_setSuperclass is deprecated, but still exists and works on iOS6/7. + class_setSuperclass(PSTClass, UIClass); +#pragma clang diagnostic pop + }]; + } +} + +// Create subclasses that pose as UICollectionView et al, if not available at runtime. +__attribute__((constructor)) static void PSTCreateUICollectionViewClasses(void) { + if (objc_getClass("PSTCollectionViewDisableForwardToUICollectionViewSentinel")) return; + + @autoreleasepool { + // Change superclass at runtime. This allows seamless switching from PST* to UI* at runtime. + PSTRegisterClasses(); + + // add PSUI classes at runtime to make Interface Builder sane + // (IB doesn't allow adding the PSUICollectionView_ types but doesn't complain on unknown classes) + // The class name may already be in use. This may happen if this code is running for the second time (first for an app bundle, then again for a unit test bundle). + Class c; + if ((c = objc_allocateClassPair(PSUICollectionView_.class, "PSUICollectionView", 0))) objc_registerClassPair(c); + if ((c = objc_allocateClassPair(PSUICollectionViewCell_.class, "PSUICollectionViewCell", 0))) objc_registerClassPair(c); + if ((c = objc_allocateClassPair(PSUICollectionReusableView_.class, "PSUICollectionReusableView", 0))) objc_registerClassPair(c); + if ((c = objc_allocateClassPair(PSUICollectionViewLayout_.class, "PSUICollectionViewLayout", 0))) objc_registerClassPair(c); + if ((c = objc_allocateClassPair(PSUICollectionViewFlowLayout_.class, "PSUICollectionViewFlowLayout", 0))) objc_registerClassPair(c); + if ((c = objc_allocateClassPair(PSUICollectionViewLayoutAttributes_.class, "PSUICollectionViewLayoutAttributes", 0)))objc_registerClassPair(c); + if ((c = objc_allocateClassPair(PSUICollectionViewController_.class, "PSUICollectionViewController", 0))) objc_registerClassPair(c); + } +} + +CGFloat PSTSimulatorAnimationDragCoefficient(void) { + static CGFloat (*UIAnimationDragCoefficient)(void) = NULL; +#if TARGET_IPHONE_SIMULATOR + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^{ + UIAnimationDragCoefficient = (CGFloat (*)(void))dlsym(RTLD_DEFAULT, "UIAnimationDragCoefficient"); + }); +#endif + return UIAnimationDragCoefficient ? UIAnimationDragCoefficient() : 1.f; +} + +// helper to check for ivar layout +#if 0 +static void PSTPrintIvarsForClass(Class aClass) { + unsigned int varCount; + Ivar *vars = class_copyIvarList(aClass, &varCount); + for (int i = 0; i < varCount; i++) { + NSLog(@"%s %s", ivar_getTypeEncoding(vars[i]), ivar_getName(vars[i])); + } + free(vars); +} + +__attribute__((constructor)) static void PSTCheckIfIVarLayoutIsEqualSize(void) { + @autoreleasepool { + NSLog(@"PSTCollectionView size = %zd, UICollectionView size = %zd", class_getInstanceSize(PSTCollectionView.class),class_getInstanceSize(UICollectionView.class)); + NSLog(@"PSTCollectionViewCell size = %zd, UICollectionViewCell size = %zd", class_getInstanceSize(PSTCollectionViewCell.class),class_getInstanceSize(UICollectionViewCell.class)); + NSLog(@"PSTCollectionViewController size = %zd, UICollectionViewController size = %zd", class_getInstanceSize(PSTCollectionViewController.class),class_getInstanceSize(UICollectionViewController.class)); + NSLog(@"PSTCollectionViewLayout size = %zd, UICollectionViewLayout size = %zd", class_getInstanceSize(PSTCollectionViewLayout.class),class_getInstanceSize(UICollectionViewLayout.class)); + NSLog(@"PSTCollectionViewFlowLayout size = %zd, UICollectionViewFlowLayout size = %zd", class_getInstanceSize(PSTCollectionViewFlowLayout.class),class_getInstanceSize(UICollectionViewFlowLayout.class)); + //PSTPrintIvarsForClass(PSTCollectionViewFlowLayout.class); NSLog(@"\n\n\n");PSTPrintIvarsForClass(UICollectionViewFlowLayout.class); + } +} +#endif diff --git a/ios/Pods/PSTCollectionView/PSTCollectionView/PSTCollectionViewCell.h b/ios/Pods/PSTCollectionView/PSTCollectionView/PSTCollectionViewCell.h new file mode 100644 index 000000000..ee71a7ea2 --- /dev/null +++ b/ios/Pods/PSTCollectionView/PSTCollectionView/PSTCollectionViewCell.h @@ -0,0 +1,49 @@ +// +// PSTCollectionViewCell.h +// PSPDFKit +// +// Copyright (c) 2012-2013 Peter Steinberger. All rights reserved. +// + +#import "PSTCollectionViewCommon.h" + +@class PSTCollectionViewLayout, PSTCollectionView, PSTCollectionViewLayoutAttributes; + +@interface PSTCollectionReusableView : UIView + +@property (nonatomic, readonly, copy) NSString *reuseIdentifier; + +// Override in subclasses. Called before instance is returned to the reuse queue. +- (void)prepareForReuse; + +// Apply layout attributes on cell. +- (void)applyLayoutAttributes:(PSTCollectionViewLayoutAttributes *)layoutAttributes; +- (void)willTransitionFromLayout:(PSTCollectionViewLayout *)oldLayout toLayout:(PSTCollectionViewLayout *)newLayout; +- (void)didTransitionFromLayout:(PSTCollectionViewLayout *)oldLayout toLayout:(PSTCollectionViewLayout *)newLayout; + +@end + +@interface PSTCollectionReusableView (Internal) +@property (nonatomic, unsafe_unretained) PSTCollectionView *collectionView; +@property (nonatomic, copy) NSString *reuseIdentifier; +@property (nonatomic, strong, readonly) PSTCollectionViewLayoutAttributes *layoutAttributes; +@end + + +@interface PSTCollectionViewCell : PSTCollectionReusableView + +@property (nonatomic, readonly) UIView *contentView; // add custom subviews to the cell's contentView + +// Cells become highlighted when the user touches them. +// The selected state is toggled when the user lifts up from a highlighted cell. +// Override these methods to provide custom UI for a selected or highlighted state. +// The collection view may call the setters inside an animation block. +@property (nonatomic, getter=isSelected) BOOL selected; +@property (nonatomic, getter=isHighlighted) BOOL highlighted; + +// The background view is a subview behind all other views. +// If selectedBackgroundView is different than backgroundView, it will be placed above the background view and animated in on selection. +@property (nonatomic, strong) UIView *backgroundView; +@property (nonatomic, strong) UIView *selectedBackgroundView; + +@end diff --git a/ios/Pods/PSTCollectionView/PSTCollectionView/PSTCollectionViewCell.m b/ios/Pods/PSTCollectionView/PSTCollectionView/PSTCollectionViewCell.m new file mode 100644 index 000000000..a81555e95 --- /dev/null +++ b/ios/Pods/PSTCollectionView/PSTCollectionView/PSTCollectionViewCell.m @@ -0,0 +1,264 @@ +// +// PSTCollectionViewCell.m +// PSPDFKit +// +// Copyright (c) 2012-2013 Peter Steinberger. All rights reserved. +// + +#import "PSTCollectionView.h" + +@interface PSTCollectionReusableView () { + PSTCollectionViewLayoutAttributes *_layoutAttributes; + NSString *_reuseIdentifier; + __unsafe_unretained PSTCollectionView *_collectionView; + struct { + unsigned int inUpdateAnimation : 1; + }_reusableViewFlags; + char filler[50]; // [HACK] Our class needs to be larger than Apple's class for the superclass change to work. +} +@property (nonatomic, copy) NSString *reuseIdentifier; +@property (nonatomic, unsafe_unretained) PSTCollectionView *collectionView; +@property (nonatomic, strong) PSTCollectionViewLayoutAttributes *layoutAttributes; +@end + +@implementation PSTCollectionReusableView + +/////////////////////////////////////////////////////////////////////////////////////////// +#pragma mark - NSObject + +- (id)initWithFrame:(CGRect)frame { + if ((self = [super initWithFrame:frame])) { + } + return self; +} + +- (id)initWithCoder:(NSCoder *)aDecoder { + if ((self = [super initWithCoder:aDecoder])) { + self.reuseIdentifier = [aDecoder decodeObjectForKey:@"UIReuseIdentifier"]; + } + return self; +} + +- (void)awakeFromNib { + self.reuseIdentifier = [self valueForKeyPath:@"reuseIdentifier"]; +} + +/////////////////////////////////////////////////////////////////////////////////////////// +#pragma mark - Public + +- (void)prepareForReuse { + self.layoutAttributes = nil; +} + +- (void)applyLayoutAttributes:(PSTCollectionViewLayoutAttributes *)layoutAttributes { + if (layoutAttributes != _layoutAttributes) { + _layoutAttributes = layoutAttributes; + + self.bounds = (CGRect){.origin = self.bounds.origin, .size = layoutAttributes.size}; + self.center = layoutAttributes.center; + self.hidden = layoutAttributes.hidden; + self.layer.transform = layoutAttributes.transform3D; + self.layer.zPosition = layoutAttributes.zIndex; + self.layer.opacity = layoutAttributes.alpha; + } +} + +- (void)willTransitionFromLayout:(PSTCollectionViewLayout *)oldLayout toLayout:(PSTCollectionViewLayout *)newLayout { + _reusableViewFlags.inUpdateAnimation = YES; +} + +- (void)didTransitionFromLayout:(PSTCollectionViewLayout *)oldLayout toLayout:(PSTCollectionViewLayout *)newLayout { + _reusableViewFlags.inUpdateAnimation = NO; +} + +- (BOOL)isInUpdateAnimation { + return _reusableViewFlags.inUpdateAnimation; +} + +- (void)setInUpdateAnimation:(BOOL)inUpdateAnimation { + _reusableViewFlags.inUpdateAnimation = (unsigned int)inUpdateAnimation; +} + +@end + + +@implementation PSTCollectionViewCell { + UIView *_contentView; + UIView *_backgroundView; + UIView *_selectedBackgroundView; + UILongPressGestureRecognizer *_menuGesture; + id _selectionSegueTemplate; + id _highlightingSupport; + struct { + unsigned int selected : 1; + unsigned int highlighted : 1; + unsigned int showingMenu : 1; + unsigned int clearSelectionWhenMenuDisappears : 1; + unsigned int waitingForSelectionAnimationHalfwayPoint : 1; + }_collectionCellFlags; + BOOL _selected; + BOOL _highlighted; +} + +/////////////////////////////////////////////////////////////////////////////////////////// +#pragma mark - NSObject + +- (id)initWithFrame:(CGRect)frame { + if ((self = [super initWithFrame:frame])) { + _backgroundView = [[UIView alloc] initWithFrame:self.bounds]; + _backgroundView.autoresizingMask = UIViewAutoresizingFlexibleWidth|UIViewAutoresizingFlexibleHeight; + [self addSubview:_backgroundView]; + + _contentView = [[UIView alloc] initWithFrame:self.bounds]; + _contentView.autoresizingMask = UIViewAutoresizingFlexibleWidth|UIViewAutoresizingFlexibleHeight; + [self addSubview:_contentView]; + + _menuGesture = [[UILongPressGestureRecognizer alloc] initWithTarget:self action:@selector(menuGesture:)]; + } + return self; +} + +- (id)initWithCoder:(NSCoder *)aDecoder { + if ((self = [super initWithCoder:aDecoder])) { + if (self.subviews.count > 0) { + _contentView = self.subviews[0]; + }else { + _contentView = [[UIView alloc] initWithFrame:self.bounds]; + _contentView.autoresizingMask = UIViewAutoresizingFlexibleWidth|UIViewAutoresizingFlexibleHeight; + [self addSubview:_contentView]; + } + + _backgroundView = [[UIView alloc] initWithFrame:self.bounds]; + _backgroundView.autoresizingMask = UIViewAutoresizingFlexibleWidth|UIViewAutoresizingFlexibleHeight; + [self insertSubview:_backgroundView belowSubview:_contentView]; + + _menuGesture = [[UILongPressGestureRecognizer alloc] initWithTarget:self action:@selector(menuGesture:)]; + } + return self; +} + +/////////////////////////////////////////////////////////////////////////////////////////// +#pragma mark - Public + +- (void)prepareForReuse { + self.layoutAttributes = nil; + self.selected = NO; + self.highlighted = NO; + self.accessibilityTraits = UIAccessibilityTraitNone; +} + +// Selection highlights underlying contents +- (void)setSelected:(BOOL)selected { + _collectionCellFlags.selected = (unsigned int)selected; + self.accessibilityTraits = selected ? UIAccessibilityTraitSelected : UIAccessibilityTraitNone; + [self updateBackgroundView:selected]; +} + +// Cell highlighting only highlights the cell itself +- (void)setHighlighted:(BOOL)highlighted { + _collectionCellFlags.highlighted = (unsigned int)highlighted; + [self updateBackgroundView:highlighted]; +} + +- (void)updateBackgroundView:(BOOL)highlight { + _selectedBackgroundView.alpha = highlight ? 1.0f : 0.0f; + [self setHighlighted:highlight forViews:self.contentView.subviews]; +} + +- (void)setHighlighted:(BOOL)highlighted forViews:(id)subviews { + for (id view in subviews) { + // Ignore the events if view wants to + if (!((UIView *)view).isUserInteractionEnabled && + [view respondsToSelector:@selector(setHighlighted:)] && + ![view isKindOfClass:UIControl.class]) { + [view setHighlighted:highlighted]; + + [self setHighlighted:highlighted forViews:[view subviews]]; + } + } +} + +- (void)menuGesture:(UILongPressGestureRecognizer *)recognizer { + NSLog(@"Not yet implemented: %@", NSStringFromSelector(_cmd)); +} + +- (void)setBackgroundView:(UIView *)backgroundView { + if (_backgroundView != backgroundView) { + [_backgroundView removeFromSuperview]; + _backgroundView = backgroundView; + _backgroundView.frame = self.bounds; + _backgroundView.autoresizingMask = UIViewAutoresizingFlexibleHeight|UIViewAutoresizingFlexibleWidth; + [self insertSubview:_backgroundView atIndex:0]; + } +} + +- (void)setSelectedBackgroundView:(UIView *)selectedBackgroundView { + if (_selectedBackgroundView != selectedBackgroundView) { + [_selectedBackgroundView removeFromSuperview]; + _selectedBackgroundView = selectedBackgroundView; + _selectedBackgroundView.frame = self.bounds; + _selectedBackgroundView.autoresizingMask = UIViewAutoresizingFlexibleWidth|UIViewAutoresizingFlexibleHeight; + _selectedBackgroundView.alpha = self.selected ? 1.0f : 0.0f; + if (_backgroundView) { + [self insertSubview:_selectedBackgroundView aboveSubview:_backgroundView]; + } + else { + [self insertSubview:_selectedBackgroundView atIndex:0]; + } + } +} + +- (BOOL)isSelected { + return _collectionCellFlags.selected; +} + +- (BOOL)isHighlighted { + return _collectionCellFlags.highlighted; +} + +- (void)performSelectionSegue { + /* + Currently there's no "official" way to trigger a storyboard segue + using UIStoryboardSegueTemplate, so we're doing it in a semi-legal way. + */ + SEL selector = NSSelectorFromString([NSString stringWithFormat:@"per%@", @"form:"]); + if ([self->_selectionSegueTemplate respondsToSelector:selector]) { +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Warc-performSelector-leaks" + [self->_selectionSegueTemplate performSelector:selector withObject:self]; +#pragma clang diagnostic pop + } +} + +/////////////////////////////////////////////////////////////////////////////////////////// +#pragma mark - PSTCollection/UICollection interoperability + +#ifdef kPSUIInteroperabilityEnabled +#import +- (NSMethodSignature *)methodSignatureForSelector:(SEL)selector { + NSMethodSignature *sig = [super methodSignatureForSelector:selector]; + if(!sig) { + NSString *selString = NSStringFromSelector(selector); + if ([selString hasPrefix:@"_"]) { + SEL cleanedSelector = NSSelectorFromString([selString substringFromIndex:1]); + sig = [super methodSignatureForSelector:cleanedSelector]; + } + } + return sig; +} + +- (void)forwardInvocation:(NSInvocation *)inv { + NSString *selString = NSStringFromSelector([inv selector]); + if ([selString hasPrefix:@"_"]) { + SEL cleanedSelector = NSSelectorFromString([selString substringFromIndex:1]); + if ([self respondsToSelector:cleanedSelector]) { + inv.selector = cleanedSelector; + [inv invokeWithTarget:self]; + } + }else { + [super forwardInvocation:inv]; + } +} +#endif + +@end diff --git a/ios/Pods/PSTCollectionView/PSTCollectionView/PSTCollectionViewCommon.h b/ios/Pods/PSTCollectionView/PSTCollectionView/PSTCollectionViewCommon.h new file mode 100644 index 000000000..fcb0a3d0f --- /dev/null +++ b/ios/Pods/PSTCollectionView/PSTCollectionView/PSTCollectionViewCommon.h @@ -0,0 +1,73 @@ +// +// PSTCollectionViewCommon.h +// PSPDFKit +// +// Copyright (c) 2012-2013 Peter Steinberger. All rights reserved. +// + +#import +#import + +// Mostly a debug feature, makes classes from UICollection* compatible with PSTCollection* +// (e.g. adding the "real" UICollectionViewFlowLayout to PSTCollectionView. +//#define kPSUIInteroperabilityEnabled + +@class PSTCollectionView, PSTCollectionViewCell, PSTCollectionReusableView; + +@protocol PSTCollectionViewDataSource +@required + +- (NSInteger)collectionView:(PSTCollectionView *)collectionView numberOfItemsInSection:(NSInteger)section; + +// The cell that is returned must be retrieved from a call to -dequeueReusableCellWithReuseIdentifier:forIndexPath: +- (PSTCollectionViewCell *)collectionView:(PSTCollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath; + +@optional + +- (NSInteger)numberOfSectionsInCollectionView:(PSTCollectionView *)collectionView; + +// The view that is returned must be retrieved from a call to -dequeueReusableSupplementaryViewOfKind:withReuseIdentifier:forIndexPath: +- (PSTCollectionReusableView *)collectionView:(PSTCollectionView *)collectionView viewForSupplementaryElementOfKind:(NSString *)kind atIndexPath:(NSIndexPath *)indexPath; + +@end + +@protocol PSTCollectionViewDelegate +@optional + +// Methods for notification of selection/deselection and highlight/unhighlight events. +// The sequence of calls leading to selection from a user touch is: +// +// (when the touch begins) +// 1. -collectionView:shouldHighlightItemAtIndexPath: +// 2. -collectionView:didHighlightItemAtIndexPath: +// +// (when the touch lifts) +// 3. -collectionView:shouldSelectItemAtIndexPath: or -collectionView:shouldDeselectItemAtIndexPath: +// 4. -collectionView:didSelectItemAtIndexPath: or -collectionView:didDeselectItemAtIndexPath: +// 5. -collectionView:didUnhighlightItemAtIndexPath: +- (BOOL)collectionView:(PSTCollectionView *)collectionView shouldHighlightItemAtIndexPath:(NSIndexPath *)indexPath; + +- (void)collectionView:(PSTCollectionView *)collectionView didHighlightItemAtIndexPath:(NSIndexPath *)indexPath; + +- (void)collectionView:(PSTCollectionView *)collectionView didUnhighlightItemAtIndexPath:(NSIndexPath *)indexPath; + +- (BOOL)collectionView:(PSTCollectionView *)collectionView shouldSelectItemAtIndexPath:(NSIndexPath *)indexPath; + +- (BOOL)collectionView:(PSTCollectionView *)collectionView shouldDeselectItemAtIndexPath:(NSIndexPath *)indexPath; // called when the user taps on an already-selected item in multi-select mode +- (void)collectionView:(PSTCollectionView *)collectionView didSelectItemAtIndexPath:(NSIndexPath *)indexPath; + +- (void)collectionView:(PSTCollectionView *)collectionView didDeselectItemAtIndexPath:(NSIndexPath *)indexPath; + +- (void)collectionView:(PSTCollectionView *)collectionView didEndDisplayingCell:(PSTCollectionViewCell *)cell forItemAtIndexPath:(NSIndexPath *)indexPath; + +- (void)collectionView:(PSTCollectionView *)collectionView didEndDisplayingSupplementaryView:(PSTCollectionReusableView *)view forElementOfKind:(NSString *)elementKind atIndexPath:(NSIndexPath *)indexPath; + +// These methods provide support for copy/paste actions on cells. +// All three should be implemented if any are. +- (BOOL)collectionView:(PSTCollectionView *)collectionView shouldShowMenuForItemAtIndexPath:(NSIndexPath *)indexPath; + +- (BOOL)collectionView:(PSTCollectionView *)collectionView canPerformAction:(SEL)action forItemAtIndexPath:(NSIndexPath *)indexPath withSender:(id)sender; + +- (void)collectionView:(PSTCollectionView *)collectionView performAction:(SEL)action forItemAtIndexPath:(NSIndexPath *)indexPath withSender:(id)sender; + +@end diff --git a/ios/Pods/PSTCollectionView/PSTCollectionView/PSTCollectionViewController.h b/ios/Pods/PSTCollectionView/PSTCollectionView/PSTCollectionViewController.h new file mode 100644 index 000000000..1e9ca565b --- /dev/null +++ b/ios/Pods/PSTCollectionView/PSTCollectionView/PSTCollectionViewController.h @@ -0,0 +1,24 @@ +// +// PSTCollectionViewController.h +// PSPDFKit +// +// Copyright (c) 2012-2013 Peter Steinberger. All rights reserved. +// + +#import "PSTCollectionViewCommon.h" + +@class PSTCollectionViewLayout, PSTCollectionViewController; + +// Simple controller-wrapper around PSTCollectionView. +@interface PSTCollectionViewController : UIViewController + +// Designated initializer. +- (id)initWithCollectionViewLayout:(PSTCollectionViewLayout *)layout; + +// Internally used collection view. If not set, created during loadView. +@property (nonatomic, strong) PSTCollectionView *collectionView; + +// Defaults to YES, and if YES, any selection is cleared in viewWillAppear: +@property (nonatomic, assign) BOOL clearsSelectionOnViewWillAppear; + +@end diff --git a/ios/Pods/PSTCollectionView/PSTCollectionView/PSTCollectionViewController.m b/ios/Pods/PSTCollectionView/PSTCollectionView/PSTCollectionViewController.m new file mode 100644 index 000000000..9000dc75a --- /dev/null +++ b/ios/Pods/PSTCollectionView/PSTCollectionView/PSTCollectionViewController.m @@ -0,0 +1,145 @@ +// +// PSTCollectionViewController.m +// PSPDFKit +// +// Copyright (c) 2012-2013 Peter Steinberger. All rights reserved. +// + +#import "PSTCollectionViewController.h" +#import "PSTCollectionView.h" + +@interface PSTCollectionViewController () { + PSTCollectionViewLayout *_layout; + PSTCollectionView *_collectionView; + struct { + unsigned int clearsSelectionOnViewWillAppear : 1; + unsigned int appearsFirstTime : 1; // PST extension! + }_collectionViewControllerFlags; + char filler[100]; // [HACK] Our class needs to be larger than Apple's class for the superclass change to work. +} +@property (nonatomic, strong) PSTCollectionViewLayout *layout; +@end + +@implementation PSTCollectionViewController + +/////////////////////////////////////////////////////////////////////////////////////////// +#pragma mark - NSObject + +- (id)initWithCoder:(NSCoder *)coder { + self = [super initWithCoder:coder]; + if (self) { + self.layout = [PSTCollectionViewFlowLayout new]; + self.clearsSelectionOnViewWillAppear = YES; + _collectionViewControllerFlags.appearsFirstTime = YES; + } + return self; +} + +- (id)initWithCollectionViewLayout:(PSTCollectionViewLayout *)layout { + if ((self = [super init])) { + self.layout = layout; + self.clearsSelectionOnViewWillAppear = YES; + _collectionViewControllerFlags.appearsFirstTime = YES; + } + return self; +} + +/////////////////////////////////////////////////////////////////////////////////////////// +#pragma mark - UIViewController + +- (void)loadView { + [super loadView]; + + // if this is restored from IB, we don't have plain main view. + if ([self.view isKindOfClass:PSTCollectionView.class]) { + _collectionView = (PSTCollectionView *)self.view; + self.view = [[UIView alloc] initWithFrame:self.view.bounds]; + self.collectionView.autoresizingMask = UIViewAutoresizingFlexibleWidth|UIViewAutoresizingFlexibleHeight; + } + + if (_collectionView.delegate == nil) _collectionView.delegate = self; + if (_collectionView.dataSource == nil) _collectionView.dataSource = self; + + // only create the collection view if it is not already created (by IB) + if (!_collectionView) { + self.collectionView = [[PSTCollectionView alloc] initWithFrame:self.view.bounds collectionViewLayout:self.layout]; + self.collectionView.delegate = self; + self.collectionView.dataSource = self; + } +} + +- (void)viewDidLoad { + [super viewDidLoad]; + + // This seems like a hack, but is needed for real compatibility + // There can be implementations of loadView that don't call super and don't set the view, yet it works in UICollectionViewController. + if (!self.isViewLoaded) { + self.view = [[UIView alloc] initWithFrame:CGRectZero]; + } + + // Attach the view + if (self.view != self.collectionView) { + [self.view addSubview:self.collectionView]; + self.collectionView.frame = self.view.bounds; + self.collectionView.autoresizingMask = UIViewAutoresizingFlexibleWidth|UIViewAutoresizingFlexibleHeight; + } +} + +- (void)viewWillAppear:(BOOL)animated { + [super viewWillAppear:animated]; + + if (_collectionViewControllerFlags.appearsFirstTime) { + [_collectionView reloadData]; + _collectionViewControllerFlags.appearsFirstTime = NO; + } + + if (_collectionViewControllerFlags.clearsSelectionOnViewWillAppear) { + for (NSIndexPath *aIndexPath in [[_collectionView indexPathsForSelectedItems] copy]) { + [_collectionView deselectItemAtIndexPath:aIndexPath animated:animated]; + } + } +} + +/////////////////////////////////////////////////////////////////////////////////////////// +#pragma mark - Lazy load the collection view + +- (PSTCollectionView *)collectionView { + if (!_collectionView) { + _collectionView = [[PSTCollectionView alloc] initWithFrame:UIScreen.mainScreen.bounds collectionViewLayout:self.layout]; + _collectionView.delegate = self; + _collectionView.dataSource = self; + + // If the collection view isn't the main view, add it. + if (self.isViewLoaded && self.view != self.collectionView) { + [self.view addSubview:self.collectionView]; + self.collectionView.frame = self.view.bounds; + self.collectionView.autoresizingMask = UIViewAutoresizingFlexibleWidth|UIViewAutoresizingFlexibleHeight; + } + } + return _collectionView; +} + +/////////////////////////////////////////////////////////////////////////////////////////// +#pragma mark - Properties + +- (void)setClearsSelectionOnViewWillAppear:(BOOL)clearsSelectionOnViewWillAppear { + _collectionViewControllerFlags.clearsSelectionOnViewWillAppear = (unsigned int)clearsSelectionOnViewWillAppear; +} + +- (BOOL)clearsSelectionOnViewWillAppear { + return _collectionViewControllerFlags.clearsSelectionOnViewWillAppear; +} + +/////////////////////////////////////////////////////////////////////////////////////////// +#pragma mark - PSTCollectionViewDataSource + +- (NSInteger)collectionView:(PSTCollectionView *)collectionView numberOfItemsInSection:(NSInteger)section { + return 0; +} + +- (PSTCollectionViewCell *)collectionView:(PSTCollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath { + [self doesNotRecognizeSelector:_cmd]; + return nil; +} + +@end diff --git a/ios/Pods/PSTCollectionView/PSTCollectionView/PSTCollectionViewData.h b/ios/Pods/PSTCollectionView/PSTCollectionView/PSTCollectionViewData.h new file mode 100644 index 000000000..ef05d8c91 --- /dev/null +++ b/ios/Pods/PSTCollectionView/PSTCollectionView/PSTCollectionViewData.h @@ -0,0 +1,75 @@ +// +// PSTCollectionViewData.h +// PSPDFKit +// +// Copyright (c) 2012-2013 Peter Steinberger. All rights reserved. +// + +#import "PSTCollectionViewCommon.h" + +@class PSTCollectionView, PSTCollectionViewLayout, PSTCollectionViewLayoutAttributes; + +// https://github.com/steipete/iOS6-Runtime-Headers/blob/master/UICollectionViewData.h +@interface PSTCollectionViewData : NSObject + +// Designated initializer. +- (id)initWithCollectionView:(PSTCollectionView *)collectionView layout:(PSTCollectionViewLayout *)layout; + +// Ensure data is valid. may fetches items from dataSource and layout. +- (void)validateLayoutInRect:(CGRect)rect; + +- (CGRect)rectForItemAtIndexPath:(NSIndexPath *)indexPath; + +/* + - (CGRect)rectForSupplementaryElementOfKind:(id)arg1 atIndexPath:(id)arg2; + - (CGRect)rectForDecorationElementOfKind:(id)arg1 atIndexPath:(id)arg2; + - (CGRect)rectForGlobalItemIndex:(int)arg1; +*/ + +// No fucking idea (yet) +- (NSUInteger)globalIndexForItemAtIndexPath:(NSIndexPath *)indexPath; + +- (NSIndexPath *)indexPathForItemAtGlobalIndex:(NSInteger)index; + +// Fetch layout attributes +- (NSArray *)layoutAttributesForElementsInRect:(CGRect)rect; + +/* +- (PSTCollectionViewLayoutAttributes *)layoutAttributesForItemAtIndexPath:(NSIndexPath *)indexPath; +- (PSTCollectionViewLayoutAttributes *)layoutAttributesForElementsInSection:(NSInteger)section; +- (PSTCollectionViewLayoutAttributes *)layoutAttributesForGlobalItemIndex:(NSInteger)index; +- (PSTCollectionViewLayoutAttributes *)layoutAttributesForDecorationViewOfKind:(id)arg1 atIndexPath:(NSIndexPath *)indexPath; +- (PSTCollectionViewLayoutAttributes *)layoutAttributesForSupplementaryElementOfKind:(id)arg1 atIndexPath:(NSIndexPath *)indexPath; + - (id)existingSupplementaryLayoutAttributesInSection:(int)arg1; +*/ + +// Make data to re-evaluate dataSources. +- (void)invalidate; + +// Access cached item data +- (NSInteger)numberOfItemsBeforeSection:(NSInteger)section; + +- (NSInteger)numberOfItemsInSection:(NSInteger)section; + +- (NSInteger)numberOfItems; + +- (NSInteger)numberOfSections; + +// Total size of the content. +- (CGRect)collectionViewContentRect; + +@property (readonly) BOOL layoutIsPrepared; + +/* + - (void)_setLayoutAttributes:(id)arg1 atGlobalItemIndex:(int)arg2; + - (void)_setupMutableIndexPath:(id*)arg1 forGlobalItemIndex:(int)arg2; + - (id)_screenPageForPoint:(struct CGPoint { float x1; float x2; })arg1; + - (void)_validateContentSize; + - (void)_validateItemCounts; + - (void)_updateItemCounts; + - (void)_loadEverything; + - (void)_prepareToLoadData; + - (void)invalidate:(BOOL)arg1; + */ + +@end diff --git a/ios/Pods/PSTCollectionView/PSTCollectionView/PSTCollectionViewData.m b/ios/Pods/PSTCollectionView/PSTCollectionView/PSTCollectionViewData.m new file mode 100644 index 000000000..2892e4200 --- /dev/null +++ b/ios/Pods/PSTCollectionView/PSTCollectionView/PSTCollectionViewData.m @@ -0,0 +1,235 @@ +// +// PSTCollectionViewData.m +// PSPDFKit +// +// Copyright (c) 2012-2013 Peter Steinberger. All rights reserved. +// + +#import "PSTCollectionViewData.h" +#import "PSTCollectionView.h" + +@interface PSTCollectionViewData () { + CGRect _validLayoutRect; + + NSInteger _numItems; + NSInteger _numSections; + NSInteger *_sectionItemCounts; +// id __strong* _globalItems; ///< _globalItems appears to be cached layoutAttributes. But adding that work in opens a can of worms, so deferring until later. + +/* + // At this point, I've no idea how _screenPageDict is structured. Looks like some optimization for layoutAttributesForElementsInRect. + And why UICGPointKey? Isn't that doable with NSValue? + + "" = "[number of indexes: 9 (in 1 ranges), indexes: (0-8)]"; + "" = "[number of indexes: 11 (in 2 ranges), indexes: (6-15 17)]"; + + (lldb) p (CGPoint)[[[[[collectionView valueForKey:@"_collectionViewData"] valueForKey:@"_screenPageDict"] allKeys] objectAtIndex:0] point] + (CGPoint) $11 = (x=15, y=159) + (lldb) p (CGPoint)[[[[[collectionView valueForKey:@"_collectionViewData"] valueForKey:@"_screenPageDict"] allKeys] objectAtIndex:1] point] + (CGPoint) $12 = (x=15, y=1128) + + // https://github.com/steipete/iOS6-Runtime-Headers/blob/master/UICGPointKey.h + + NSMutableDictionary *_screenPageDict; + */ + + // @steipete + + CGSize _contentSize; + struct { + unsigned int contentSizeIsValid:1; + unsigned int itemCountsAreValid:1; + unsigned int layoutIsPrepared:1; + }_collectionViewDataFlags; +} +@property (nonatomic, unsafe_unretained) PSTCollectionView *collectionView; +@property (nonatomic, unsafe_unretained) PSTCollectionViewLayout *layout; +@property (nonatomic, strong) NSArray *cachedLayoutAttributes; + +@end + +@implementation PSTCollectionViewData + +/////////////////////////////////////////////////////////////////////////////////////////// +#pragma mark - NSObject + +- (id)initWithCollectionView:(PSTCollectionView *)collectionView layout:(PSTCollectionViewLayout *)layout { + if ((self = [super init])) { + _collectionView = collectionView; + _layout = layout; + } + return self; +} + +- (void)dealloc { + free(_sectionItemCounts); +} + +- (NSString *)description { + return [NSString stringWithFormat:@"<%@: %p numItems:%ld numSections:%ld>", NSStringFromClass(self.class), self, (long)self.numberOfItems, (long)self.numberOfSections]; +} + +/////////////////////////////////////////////////////////////////////////////////////////// +#pragma mark - Public + +- (void)invalidate { + _collectionViewDataFlags.itemCountsAreValid = NO; + _collectionViewDataFlags.layoutIsPrepared = NO; + _validLayoutRect = CGRectNull; // don't set CGRectZero in case of _contentSize=CGSizeZero +} + +- (CGRect)collectionViewContentRect { + return (CGRect){.size=_contentSize}; +} + +- (void)validateLayoutInRect:(CGRect)rect { + [self validateItemCounts]; + [self prepareToLoadData]; + + // TODO: check if we need to fetch data from layout + if (!CGRectEqualToRect(_validLayoutRect, rect)) { + _validLayoutRect = rect; + // we only want cell layoutAttributes & supplementaryView layoutAttributes + self.cachedLayoutAttributes = [[self.layout layoutAttributesForElementsInRect:rect] filteredArrayUsingPredicate:[NSPredicate predicateWithBlock:^BOOL(PSTCollectionViewLayoutAttributes *evaluatedObject, NSDictionary *bindings) { + return ([evaluatedObject isKindOfClass:PSTCollectionViewLayoutAttributes.class] && + ([evaluatedObject isCell] || + [evaluatedObject isSupplementaryView] || + [evaluatedObject isDecorationView])); + }]]; + } +} + +- (NSInteger)numberOfItems { + [self validateItemCounts]; + return _numItems; +} + +- (NSInteger)numberOfItemsBeforeSection:(NSInteger)section { + [self validateItemCounts]; + + NSAssert(section < _numSections, @"request for number of items in section %ld when there are only %ld sections in the collection view", (long)section, (long)_numSections); + + NSInteger returnCount = 0; + for (int i = 0; i < section; i++) { + returnCount += _sectionItemCounts[i]; + } + + return returnCount; +} + +- (NSInteger)numberOfItemsInSection:(NSInteger)section { + [self validateItemCounts]; + if (section >= _numSections || section < 0) { + // In case of inconsistency returns the 'less harmful' amount of items. Throwing an exception here potentially + // causes exceptions when data is consistent. Deleting sections is one of the parts sensitive to this. + // All checks via assertions are done on CollectionView animation methods, specially 'endAnimations'. + return 0; + //@throw [NSException exceptionWithName:NSInvalidArgumentException reason:[NSString stringWithFormat:@"Section %d out of range: 0...%d", section, _numSections] userInfo:nil]; + } + + NSInteger numberOfItemsInSection = 0; + if (_sectionItemCounts) { + numberOfItemsInSection = _sectionItemCounts[section]; + } + return numberOfItemsInSection; +} + +- (NSInteger)numberOfSections { + [self validateItemCounts]; + return _numSections; +} + +- (CGRect)rectForItemAtIndexPath:(NSIndexPath *)indexPath { + return CGRectZero; +} + +- (NSIndexPath *)indexPathForItemAtGlobalIndex:(NSInteger)index { + [self validateItemCounts]; + + NSAssert(index < _numItems, @"request for index path for global index %ld when there are only %ld items in the collection view", (long)index, (long)_numItems); + + NSInteger section = 0; + NSInteger countItems = 0; + for (section = 0; section < _numSections; section++) { + NSInteger countIncludingThisSection = countItems + _sectionItemCounts[section]; + if (countIncludingThisSection > index) break; + countItems = countIncludingThisSection; + } + + NSInteger item = index - countItems; + + return [NSIndexPath indexPathForItem:item inSection:section]; +} + +- (NSUInteger)globalIndexForItemAtIndexPath:(NSIndexPath *)indexPath { + NSInteger offset = [self numberOfItemsBeforeSection:indexPath.section] + indexPath.item; + return (NSUInteger)offset; +} + +- (BOOL)layoutIsPrepared { + return _collectionViewDataFlags.layoutIsPrepared; +} + +- (void)setLayoutIsPrepared:(BOOL)layoutIsPrepared { + _collectionViewDataFlags.layoutIsPrepared = (unsigned int)layoutIsPrepared; +} + +/////////////////////////////////////////////////////////////////////////////////////////// +#pragma mark - Fetch Layout Attributes + +- (NSArray *)layoutAttributesForElementsInRect:(CGRect)rect { + [self validateLayoutInRect:rect]; + return self.cachedLayoutAttributes; +} + +/////////////////////////////////////////////////////////////////////////////////////////// +#pragma mark - Private + +// ensure item count is valid and loaded +- (void)validateItemCounts { + if (!_collectionViewDataFlags.itemCountsAreValid) { + [self updateItemCounts]; + } +} + +// query dataSource for new data +- (void)updateItemCounts { + // query how many sections there will be + _numSections = 1; + if ([self.collectionView.dataSource respondsToSelector:@selector(numberOfSectionsInCollectionView:)]) { + _numSections = [self.collectionView.dataSource numberOfSectionsInCollectionView:self.collectionView]; + } + if (_numSections <= 0) { // early bail-out + _numItems = 0; + free(_sectionItemCounts); + _sectionItemCounts = 0; + _collectionViewDataFlags.itemCountsAreValid = YES; + return; + } + // allocate space + if (!_sectionItemCounts) { + _sectionItemCounts = malloc((size_t)_numSections * sizeof(NSInteger)); + }else { + _sectionItemCounts = realloc(_sectionItemCounts, (size_t)_numSections * sizeof(NSInteger)); + } + + // query cells per section + _numItems = 0; + for (NSInteger i = 0; i < _numSections; i++) { + NSInteger cellCount = [self.collectionView.dataSource collectionView:self.collectionView numberOfItemsInSection:i]; + _sectionItemCounts[i] = cellCount; + _numItems += cellCount; + } + + _collectionViewDataFlags.itemCountsAreValid = YES; +} + +- (void)prepareToLoadData { + if (!self.layoutIsPrepared) { + [self.layout prepareLayout]; + _contentSize = self.layout.collectionViewContentSize; + self.layoutIsPrepared = YES; + } +} + +@end diff --git a/ios/Pods/PSTCollectionView/PSTCollectionView/PSTCollectionViewFlowLayout.h b/ios/Pods/PSTCollectionView/PSTCollectionView/PSTCollectionViewFlowLayout.h new file mode 100644 index 000000000..7dc971b54 --- /dev/null +++ b/ios/Pods/PSTCollectionView/PSTCollectionView/PSTCollectionViewFlowLayout.h @@ -0,0 +1,115 @@ +// +// PSTCollectionViewFlowLayout.h +// PSPDFKit +// +// Copyright (c) 2012-2013 Peter Steinberger. All rights reserved. +// + +#import "PSTCollectionViewLayout.h" + +extern NSString *const PSTCollectionElementKindSectionHeader; +extern NSString *const PSTCollectionElementKindSectionFooter; + +typedef NS_ENUM(NSInteger, PSTCollectionViewScrollDirection) { + PSTCollectionViewScrollDirectionVertical, + PSTCollectionViewScrollDirectionHorizontal +}; + +@protocol PSTCollectionViewDelegateFlowLayout +@optional + +- (CGSize)collectionView:(PSTCollectionView *)collectionView layout:(PSTCollectionViewLayout*)collectionViewLayout sizeForItemAtIndexPath:(NSIndexPath *)indexPath; +- (UIEdgeInsets)collectionView:(PSTCollectionView *)collectionView layout:(PSTCollectionViewLayout*)collectionViewLayout insetForSectionAtIndex:(NSInteger)section; +- (CGFloat)collectionView:(PSTCollectionView *)collectionView layout:(PSTCollectionViewLayout*)collectionViewLayout minimumLineSpacingForSectionAtIndex:(NSInteger)section; +- (CGFloat)collectionView:(PSTCollectionView *)collectionView layout:(PSTCollectionViewLayout*)collectionViewLayout minimumInteritemSpacingForSectionAtIndex:(NSInteger)section; +- (CGSize)collectionView:(PSTCollectionView *)collectionView layout:(PSTCollectionViewLayout*)collectionViewLayout referenceSizeForHeaderInSection:(NSInteger)section; +- (CGSize)collectionView:(PSTCollectionView *)collectionView layout:(PSTCollectionViewLayout*)collectionViewLayout referenceSizeForFooterInSection:(NSInteger)section; + +@end + +@class PSTGridLayoutInfo; + +@interface PSTCollectionViewFlowLayout : PSTCollectionViewLayout + +@property (nonatomic) CGFloat minimumLineSpacing; +@property (nonatomic) CGFloat minimumInteritemSpacing; +@property (nonatomic) CGSize itemSize; // for the cases the delegate method is not implemented +@property (nonatomic) PSTCollectionViewScrollDirection scrollDirection; // default is PSTCollectionViewScrollDirectionVertical +@property (nonatomic) CGSize headerReferenceSize; +@property (nonatomic) CGSize footerReferenceSize; + +@property (nonatomic) UIEdgeInsets sectionInset; + +/* + Row alignment options exits in the official UICollectionView, but hasn't been made public API. + + Here's a snippet to test this on UICollectionView: + + NSMutableDictionary *rowAlign = [[flowLayout valueForKey:@"_rowAlignmentsOptionsDictionary"] mutableCopy]; + rowAlign[@"UIFlowLayoutCommonRowHorizontalAlignmentKey"] = @(1); + rowAlign[@"UIFlowLayoutLastRowHorizontalAlignmentKey"] = @(3); + [flowLayout setValue:rowAlign forKey:@"_rowAlignmentsOptionsDictionary"]; + */ +@property (nonatomic, strong) NSDictionary *rowAlignmentOptions; + +@end + +// @steipete addition, private API in UICollectionViewFlowLayout +extern NSString *const PSTFlowLayoutCommonRowHorizontalAlignmentKey; +extern NSString *const PSTFlowLayoutLastRowHorizontalAlignmentKey; +extern NSString *const PSTFlowLayoutRowVerticalAlignmentKey; + +typedef NS_ENUM(NSInteger, PSTFlowLayoutHorizontalAlignment) { + PSTFlowLayoutHorizontalAlignmentLeft, + PSTFlowLayoutHorizontalAlignmentCentered, + PSTFlowLayoutHorizontalAlignmentRight, + PSTFlowLayoutHorizontalAlignmentJustify // 3; default except for the last row +}; +// TODO: settings for UIFlowLayoutRowVerticalAlignmentKey + + +/* +@interface PSTCollectionViewFlowLayout (Private) + +- (CGSize)synchronizeLayout; + +// For items being inserted or deleted, the collection view calls some different methods, which you should override to provide the appropriate layout information. +- (PSTCollectionViewLayoutAttributes *)initialLayoutAttributesForFooterInInsertedSection:(NSInteger)section; +- (PSTCollectionViewLayoutAttributes *)initialLayoutAttributesForHeaderInInsertedSection:(NSInteger)section; +- (PSTCollectionViewLayoutAttributes *)initialLayoutAttributesForInsertedItemAtIndexPath:(NSIndexPath *)indexPath; +- (PSTCollectionViewLayoutAttributes *)finalLayoutAttributesForFooterInDeletedSection:(NSInteger)section; +- (PSTCollectionViewLayoutAttributes *)finalLayoutAttributesForHeaderInDeletedSection:(NSInteger)section; +- (PSTCollectionViewLayoutAttributes *)finalLayoutAttributesForDeletedItemAtIndexPath:(NSIndexPath *)indexPath; + +- (void)_updateItemsLayout; +- (void)_getSizingInfos; +- (void)_updateDelegateFlags; + +- (PSTCollectionViewLayoutAttributes *)layoutAttributesForFooterInSection:(NSInteger)section; +- (PSTCollectionViewLayoutAttributes *)layoutAttributesForHeaderInSection:(NSInteger)section; +- (PSTCollectionViewLayoutAttributes *)layoutAttributesForItemAtIndexPath:(NSIndexPath *)indexPath usingData:(id)data; +- (PSTCollectionViewLayoutAttributes *)layoutAttributesForFooterInSection:(NSInteger)section usingData:(id)data; +- (PSTCollectionViewLayoutAttributes *)layoutAttributesForHeaderInSection:(NSInteger)section usingData:(id)data; + +- (id)indexesForSectionFootersInRect:(CGRect)rect; +- (id)indexesForSectionHeadersInRect:(CGRect)rect; +- (id)indexPathsForItemsInRect:(CGRect)rect usingData:(id)arg2; +- (id)indexesForSectionFootersInRect:(CGRect)rect usingData:(id)arg2; +- (id)indexesForSectionHeadersInRect:(CGRect)arg1 usingData:(id)arg2; +- (CGRect)_frameForItemAtSection:(int)arg1 andRow:(int)arg2 usingData:(id)arg3; +- (CGRect)_frameForFooterInSection:(int)arg1 usingData:(id)arg2; +- (CGRect)_frameForHeaderInSection:(int)arg1 usingData:(id)arg2; +- (void)_invalidateLayout; +- (NSIndexPath *)indexPathForItemAtPoint:(CGPoint)arg1; +- (PSTCollectionViewLayoutAttributes *)_layoutAttributesForItemsInRect:(CGRect)arg1; +- (CGSize)collectionViewContentSize; +- (void)finalizeCollectionViewUpdates; +- (void)_invalidateButKeepDelegateInfo; +- (void)_invalidateButKeepAllInfo; +- (BOOL)shouldInvalidateLayoutForBoundsChange:(CGRect)arg1; +- (id)layoutAttributesForElementsInRect:(CGRect)arg1; +- (void)invalidateLayout; +- (id)layoutAttributesForItemAtIndexPath:(id)arg1; + +@end +*/ diff --git a/ios/Pods/PSTCollectionView/PSTCollectionView/PSTCollectionViewFlowLayout.m b/ios/Pods/PSTCollectionView/PSTCollectionView/PSTCollectionViewFlowLayout.m new file mode 100644 index 000000000..e34d00271 --- /dev/null +++ b/ios/Pods/PSTCollectionView/PSTCollectionView/PSTCollectionViewFlowLayout.m @@ -0,0 +1,420 @@ +// +// PSTCollectionViewFlowLayout.m +// PSPDFKit +// +// Copyright (c) 2012-2013 Peter Steinberger. All rights reserved. +// + +#import "PSTCollectionViewFlowLayout.h" +#import "PSTCollectionView.h" +#import "PSTGridLayoutItem.h" +#import "PSTGridLayoutInfo.h" +#import "PSTGridLayoutRow.h" +#import "PSTGridLayoutSection.h" +#import + +NSString *const PSTCollectionElementKindSectionHeader = @"UICollectionElementKindSectionHeader"; +NSString *const PSTCollectionElementKindSectionFooter = @"UICollectionElementKindSectionFooter"; + +// this is not exposed in UICollectionViewFlowLayout +NSString *const PSTFlowLayoutCommonRowHorizontalAlignmentKey = @"UIFlowLayoutCommonRowHorizontalAlignmentKey"; +NSString *const PSTFlowLayoutLastRowHorizontalAlignmentKey = @"UIFlowLayoutLastRowHorizontalAlignmentKey"; +NSString *const PSTFlowLayoutRowVerticalAlignmentKey = @"UIFlowLayoutRowVerticalAlignmentKey"; + +@implementation PSTCollectionViewFlowLayout { + // class needs to have same iVar layout as UICollectionViewLayout + struct { + unsigned int delegateSizeForItem : 1; + unsigned int delegateReferenceSizeForHeader : 1; + unsigned int delegateReferenceSizeForFooter : 1; + unsigned int delegateInsetForSection : 1; + unsigned int delegateInteritemSpacingForSection : 1; + unsigned int delegateLineSpacingForSection : 1; + unsigned int delegateAlignmentOptions : 1; + unsigned int keepDelegateInfoWhileInvalidating : 1; + unsigned int keepAllDataWhileInvalidating : 1; + unsigned int layoutDataIsValid : 1; + unsigned int delegateInfoIsValid : 1; + }_gridLayoutFlags; + CGFloat _interitemSpacing; + CGFloat _lineSpacing; + CGSize _itemSize; + CGSize _headerReferenceSize; + CGSize _footerReferenceSize; + UIEdgeInsets _sectionInset; + PSTGridLayoutInfo *_data; + CGSize _currentLayoutSize; + NSMutableDictionary *_insertedItemsAttributesDict; + NSMutableDictionary *_insertedSectionHeadersAttributesDict; + NSMutableDictionary *_insertedSectionFootersAttributesDict; + NSMutableDictionary *_deletedItemsAttributesDict; + NSMutableDictionary *_deletedSectionHeadersAttributesDict; + NSMutableDictionary *_deletedSectionFootersAttributesDict; + PSTCollectionViewScrollDirection _scrollDirection; + NSDictionary *_rowAlignmentsOptionsDictionary; + CGRect _visibleBounds; + char filler[200]; // [HACK] Our class needs to be larger than Apple's class for the superclass change to work. +} + +@synthesize rowAlignmentOptions = _rowAlignmentsOptionsDictionary; +@synthesize minimumLineSpacing = _lineSpacing; +@synthesize minimumInteritemSpacing = _interitemSpacing; + +/////////////////////////////////////////////////////////////////////////////////////////// +#pragma mark - NSObject + +- (void)commonInit { + _itemSize = CGSizeMake(50.f, 50.f); + _lineSpacing = 10.f; + _interitemSpacing = 10.f; + _sectionInset = UIEdgeInsetsZero; + _scrollDirection = PSTCollectionViewScrollDirectionVertical; + _headerReferenceSize = CGSizeZero; + _footerReferenceSize = CGSizeZero; +} + +- (id)init { + if ((self = [super init])) { + [self commonInit]; + + // set default values for row alignment. + _rowAlignmentsOptionsDictionary = @{ + PSTFlowLayoutCommonRowHorizontalAlignmentKey : @(PSTFlowLayoutHorizontalAlignmentJustify), + PSTFlowLayoutLastRowHorizontalAlignmentKey : @(PSTFlowLayoutHorizontalAlignmentJustify), + // TODO: those values are some enum. find out what that is. + PSTFlowLayoutRowVerticalAlignmentKey : @(1), + }; + } + return self; +} + +- (id)initWithCoder:(NSCoder *)decoder { + if ((self = [super initWithCoder:decoder])) { + [self commonInit]; + + // Some properties are not set if they're default (like minimumInteritemSpacing == 10) + if ([decoder containsValueForKey:@"UIItemSize"]) + self.itemSize = [decoder decodeCGSizeForKey:@"UIItemSize"]; + if ([decoder containsValueForKey:@"UIInteritemSpacing"]) + self.minimumInteritemSpacing = [decoder decodeFloatForKey:@"UIInteritemSpacing"]; + if ([decoder containsValueForKey:@"UILineSpacing"]) + self.minimumLineSpacing = [decoder decodeFloatForKey:@"UILineSpacing"]; + if ([decoder containsValueForKey:@"UIFooterReferenceSize"]) + self.footerReferenceSize = [decoder decodeCGSizeForKey:@"UIFooterReferenceSize"]; + if ([decoder containsValueForKey:@"UIHeaderReferenceSize"]) + self.headerReferenceSize = [decoder decodeCGSizeForKey:@"UIHeaderReferenceSize"]; + if ([decoder containsValueForKey:@"UISectionInset"]) + self.sectionInset = [decoder decodeUIEdgeInsetsForKey:@"UISectionInset"]; + if ([decoder containsValueForKey:@"UIScrollDirection"]) + self.scrollDirection = [decoder decodeIntegerForKey:@"UIScrollDirection"]; + } + return self; +} + +- (void)encodeWithCoder:(NSCoder *)coder { + [super encodeWithCoder:coder]; + [coder encodeCGSize:self.itemSize forKey:@"UIItemSize"]; + [coder encodeFloat:(float)self.minimumInteritemSpacing forKey:@"UIInteritemSpacing"]; + [coder encodeFloat:(float)self.minimumLineSpacing forKey:@"UILineSpacing"]; + [coder encodeCGSize:self.footerReferenceSize forKey:@"UIFooterReferenceSize"]; + [coder encodeCGSize:self.headerReferenceSize forKey:@"UIHeaderReferenceSize"]; + [coder encodeUIEdgeInsets:self.sectionInset forKey:@"UISectionInset"]; + [coder encodeInteger:self.scrollDirection forKey:@"UIScrollDirection"]; +} + +/////////////////////////////////////////////////////////////////////////////////////////// +#pragma mark - PSTCollectionViewLayout + +static char kPSTCachedItemRectsKey; + +- (NSArray *)layoutAttributesForElementsInRect:(CGRect)rect { + // Apple calls _layoutAttributesForItemsInRect + if (!_data) [self prepareLayout]; + + NSMutableArray *layoutAttributesArray = [NSMutableArray array]; + for (PSTGridLayoutSection *section in _data.sections) { + if (CGRectIntersectsRect(section.frame, rect)) { + + // if we have fixed size, calculate item frames only once. + // this also uses the default PSTFlowLayoutCommonRowHorizontalAlignmentKey alignment + // for the last row. (we want this effect!) + NSMutableDictionary *rectCache = objc_getAssociatedObject(self, &kPSTCachedItemRectsKey); + NSUInteger sectionIndex = [_data.sections indexOfObjectIdenticalTo:section]; + + CGRect normalizedHeaderFrame = section.headerFrame; + normalizedHeaderFrame.origin.x += section.frame.origin.x; + normalizedHeaderFrame.origin.y += section.frame.origin.y; + if (!CGRectIsEmpty(normalizedHeaderFrame) && CGRectIntersectsRect(normalizedHeaderFrame, rect)) { + PSTCollectionViewLayoutAttributes *layoutAttributes = [[self.class layoutAttributesClass] layoutAttributesForSupplementaryViewOfKind:PSTCollectionElementKindSectionHeader withIndexPath:[NSIndexPath indexPathForItem:0 inSection:(NSInteger)sectionIndex]]; + layoutAttributes.frame = normalizedHeaderFrame; + [layoutAttributesArray addObject:layoutAttributes]; + } + + NSArray *itemRects = rectCache[@(sectionIndex)]; + if (!itemRects && section.fixedItemSize && section.rows.count) { + itemRects = [(section.rows)[0] itemRects]; + if (itemRects) rectCache[@(sectionIndex)] = itemRects; + } + + for (PSTGridLayoutRow *row in section.rows) { + CGRect normalizedRowFrame = row.rowFrame; + + normalizedRowFrame.origin.x += section.frame.origin.x; + normalizedRowFrame.origin.y += section.frame.origin.y; + + if (CGRectIntersectsRect(normalizedRowFrame, rect)) { + // TODO be more fine-grained for items + + for (NSInteger itemIndex = 0; itemIndex < row.itemCount; itemIndex++) { + PSTCollectionViewLayoutAttributes *layoutAttributes; + NSUInteger sectionItemIndex; + CGRect itemFrame; + if (row.fixedItemSize) { + itemFrame = [itemRects[(NSUInteger)itemIndex] CGRectValue]; + sectionItemIndex = (NSUInteger)(row.index * section.itemsByRowCount + itemIndex); + }else { + PSTGridLayoutItem *item = row.items[(NSUInteger)itemIndex]; + sectionItemIndex = [section.items indexOfObjectIdenticalTo:item]; + itemFrame = item.itemFrame; + } + + CGRect normalisedItemFrame = CGRectMake(normalizedRowFrame.origin.x + itemFrame.origin.x, normalizedRowFrame.origin.y + itemFrame.origin.y, itemFrame.size.width, itemFrame.size.height); + + if (CGRectIntersectsRect(normalisedItemFrame, rect)) { + layoutAttributes = [[self.class layoutAttributesClass] layoutAttributesForCellWithIndexPath:[NSIndexPath indexPathForItem:(NSInteger)sectionItemIndex inSection:(NSInteger)sectionIndex]]; + layoutAttributes.frame = normalisedItemFrame; + [layoutAttributesArray addObject:layoutAttributes]; + } + } + } + } + + CGRect normalizedFooterFrame = section.footerFrame; + normalizedFooterFrame.origin.x += section.frame.origin.x; + normalizedFooterFrame.origin.y += section.frame.origin.y; + if (!CGRectIsEmpty(normalizedFooterFrame) && CGRectIntersectsRect(normalizedFooterFrame, rect)) { + PSTCollectionViewLayoutAttributes *layoutAttributes = [[self.class layoutAttributesClass] layoutAttributesForSupplementaryViewOfKind:PSTCollectionElementKindSectionFooter withIndexPath:[NSIndexPath indexPathForItem:0 inSection:(NSInteger)sectionIndex]]; + layoutAttributes.frame = normalizedFooterFrame; + [layoutAttributesArray addObject:layoutAttributes]; + } + } + } + return layoutAttributesArray; +} + +- (PSTCollectionViewLayoutAttributes *)layoutAttributesForItemAtIndexPath:(NSIndexPath *)indexPath { + if (!_data) [self prepareLayout]; + + PSTGridLayoutSection *section = _data.sections[(NSUInteger)indexPath.section]; + PSTGridLayoutRow *row = nil; + CGRect itemFrame = CGRectZero; + + if (section.fixedItemSize && section.itemsByRowCount > 0 && indexPath.item / section.itemsByRowCount < (NSInteger)section.rows.count) { + row = section.rows[(NSUInteger)(indexPath.item / section.itemsByRowCount)]; + NSUInteger itemIndex = (NSUInteger)(indexPath.item % section.itemsByRowCount); + NSArray *itemRects = [row itemRects]; + itemFrame = [itemRects[itemIndex] CGRectValue]; + }else if (indexPath.item < (NSInteger)section.items.count) { + PSTGridLayoutItem *item = section.items[(NSUInteger)indexPath.item]; + row = item.rowObject; + itemFrame = item.itemFrame; + } + + PSTCollectionViewLayoutAttributes *layoutAttributes = [[self.class layoutAttributesClass] layoutAttributesForCellWithIndexPath:indexPath]; + + // calculate item rect + CGRect normalizedRowFrame = row.rowFrame; + normalizedRowFrame.origin.x += section.frame.origin.x; + normalizedRowFrame.origin.y += section.frame.origin.y; + layoutAttributes.frame = CGRectMake(normalizedRowFrame.origin.x + itemFrame.origin.x, normalizedRowFrame.origin.y + itemFrame.origin.y, itemFrame.size.width, itemFrame.size.height); + + return layoutAttributes; +} + +- (PSTCollectionViewLayoutAttributes *)layoutAttributesForSupplementaryViewOfKind:(NSString *)kind atIndexPath:(NSIndexPath *)indexPath { + if (!_data) [self prepareLayout]; + + NSUInteger sectionIndex = (NSUInteger)indexPath.section; + PSTCollectionViewLayoutAttributes *layoutAttributes = nil; + + if (sectionIndex < _data.sections.count) { + PSTGridLayoutSection *section = _data.sections[sectionIndex]; + + CGRect normalizedFrame = CGRectZero; + if ([kind isEqualToString:PSTCollectionElementKindSectionHeader]) { + normalizedFrame = section.headerFrame; + } + else if ([kind isEqualToString:PSTCollectionElementKindSectionFooter]) { + normalizedFrame = section.footerFrame; + } + + if (!CGRectIsEmpty(normalizedFrame)) { + normalizedFrame.origin.x += section.frame.origin.x; + normalizedFrame.origin.y += section.frame.origin.y; + + layoutAttributes = [[self.class layoutAttributesClass] layoutAttributesForSupplementaryViewOfKind:kind withIndexPath:[NSIndexPath indexPathForItem:0 inSection:(NSInteger)sectionIndex]]; + layoutAttributes.frame = normalizedFrame; + } + } + return layoutAttributes; +} + +- (PSTCollectionViewLayoutAttributes *)layoutAttributesForDecorationViewWithReuseIdentifier:(NSString *)identifier atIndexPath:(NSIndexPath *)indexPath { + return nil; +} + +- (CGSize)collectionViewContentSize { + if (!_data) [self prepareLayout]; + + return _data.contentSize; +} + +- (void)setSectionInset:(UIEdgeInsets)sectionInset { + if (!UIEdgeInsetsEqualToEdgeInsets(sectionInset, _sectionInset)) { + _sectionInset = sectionInset; + [self invalidateLayout]; + } +} + +/////////////////////////////////////////////////////////////////////////////////////////// +#pragma mark - Invalidating the Layout + +- (void)invalidateLayout { + [super invalidateLayout]; + objc_setAssociatedObject(self, &kPSTCachedItemRectsKey, nil, OBJC_ASSOCIATION_RETAIN_NONATOMIC); + _data = nil; +} + +- (BOOL)shouldInvalidateLayoutForBoundsChange:(CGRect)newBounds { + // we need to recalculate on width changes + if ((_visibleBounds.size.width != newBounds.size.width && self.scrollDirection == PSTCollectionViewScrollDirectionVertical) || (_visibleBounds.size.height != newBounds.size.height && self.scrollDirection == PSTCollectionViewScrollDirectionHorizontal)) { + _visibleBounds = self.collectionView.bounds; + return YES; + } + return NO; +} + +// return a point at which to rest after scrolling - for layouts that want snap-to-point scrolling behavior +- (CGPoint)targetContentOffsetForProposedContentOffset:(CGPoint)proposedContentOffset withScrollingVelocity:(CGPoint)velocity { + return proposedContentOffset; +} + +- (void)prepareLayout { + // custom ivars + objc_setAssociatedObject(self, &kPSTCachedItemRectsKey, [NSMutableDictionary dictionary], OBJC_ASSOCIATION_RETAIN_NONATOMIC); + + _data = [PSTGridLayoutInfo new]; // clear old layout data + _data.horizontal = self.scrollDirection == PSTCollectionViewScrollDirectionHorizontal; + _visibleBounds = self.collectionView.bounds; + CGSize collectionViewSize = _visibleBounds.size; + _data.dimension = _data.horizontal ? collectionViewSize.height : collectionViewSize.width; + _data.rowAlignmentOptions = _rowAlignmentsOptionsDictionary; + [self fetchItemsInfo]; +} + +/////////////////////////////////////////////////////////////////////////////////////////// +#pragma mark - Private + +- (void)fetchItemsInfo { + [self getSizingInfos]; + [self updateItemsLayout]; +} + +// get size of all items (if delegate is implemented) +- (void)getSizingInfos { + NSAssert(_data.sections.count == 0, @"Grid layout is already populated?"); + + id flowDataSource = (id)self.collectionView.delegate; + + BOOL implementsSizeDelegate = [flowDataSource respondsToSelector:@selector(collectionView:layout:sizeForItemAtIndexPath:)]; + BOOL implementsHeaderReferenceDelegate = [flowDataSource respondsToSelector:@selector(collectionView:layout:referenceSizeForHeaderInSection:)]; + BOOL implementsFooterReferenceDelegate = [flowDataSource respondsToSelector:@selector(collectionView:layout:referenceSizeForFooterInSection:)]; + + NSInteger numberOfSections = [self.collectionView numberOfSections]; + for (NSInteger section = 0; section < numberOfSections; section++) { + PSTGridLayoutSection *layoutSection = [_data addSection]; + layoutSection.verticalInterstice = _data.horizontal ? self.minimumInteritemSpacing : self.minimumLineSpacing; + layoutSection.horizontalInterstice = !_data.horizontal ? self.minimumInteritemSpacing : self.minimumLineSpacing; + + if ([flowDataSource respondsToSelector:@selector(collectionView:layout:insetForSectionAtIndex:)]) { + layoutSection.sectionMargins = [flowDataSource collectionView:self.collectionView layout:self insetForSectionAtIndex:section]; + }else { + layoutSection.sectionMargins = self.sectionInset; + } + + if ([flowDataSource respondsToSelector:@selector(collectionView:layout:minimumLineSpacingForSectionAtIndex:)]) { + CGFloat minimumLineSpacing = [flowDataSource collectionView:self.collectionView layout:self minimumLineSpacingForSectionAtIndex:section]; + if (_data.horizontal) { + layoutSection.horizontalInterstice = minimumLineSpacing; + }else { + layoutSection.verticalInterstice = minimumLineSpacing; + } + } + + if ([flowDataSource respondsToSelector:@selector(collectionView:layout:minimumInteritemSpacingForSectionAtIndex:)]) { + CGFloat minimumInterimSpacing = [flowDataSource collectionView:self.collectionView layout:self minimumInteritemSpacingForSectionAtIndex:section]; + if (_data.horizontal) { + layoutSection.verticalInterstice = minimumInterimSpacing; + }else { + layoutSection.horizontalInterstice = minimumInterimSpacing; + } + } + + CGSize headerReferenceSize; + if (implementsHeaderReferenceDelegate) { + headerReferenceSize = [flowDataSource collectionView:self.collectionView layout:self referenceSizeForHeaderInSection:section]; + }else { + headerReferenceSize = self.headerReferenceSize; + } + layoutSection.headerDimension = _data.horizontal ? headerReferenceSize.width : headerReferenceSize.height; + + CGSize footerReferenceSize; + if (implementsFooterReferenceDelegate) { + footerReferenceSize = [flowDataSource collectionView:self.collectionView layout:self referenceSizeForFooterInSection:section]; + }else { + footerReferenceSize = self.footerReferenceSize; + } + layoutSection.footerDimension = _data.horizontal ? footerReferenceSize.width : footerReferenceSize.height; + + NSInteger numberOfItems = [self.collectionView numberOfItemsInSection:section]; + + // if delegate implements size delegate, query it for all items + if (implementsSizeDelegate) { + for (NSInteger item = 0; item < numberOfItems; item++) { + NSIndexPath *indexPath = [NSIndexPath indexPathForItem:item inSection:(NSInteger)section]; + CGSize itemSize = implementsSizeDelegate ? [flowDataSource collectionView:self.collectionView layout:self sizeForItemAtIndexPath:indexPath] : self.itemSize; + + PSTGridLayoutItem *layoutItem = [layoutSection addItem]; + layoutItem.itemFrame = (CGRect){.size=itemSize}; + } + // if not, go the fast path + }else { + layoutSection.fixedItemSize = YES; + layoutSection.itemSize = self.itemSize; + layoutSection.itemsCount = numberOfItems; + } + } +} + +- (void)updateItemsLayout { + CGSize contentSize = CGSizeZero; + for (PSTGridLayoutSection *section in _data.sections) { + [section computeLayout]; + + // update section offset to make frame absolute (section only calculates relative) + CGRect sectionFrame = section.frame; + if (_data.horizontal) { + sectionFrame.origin.x += contentSize.width; + contentSize.width += section.frame.size.width + section.frame.origin.x; + contentSize.height = MAX(contentSize.height, sectionFrame.size.height + section.frame.origin.y + section.sectionMargins.top + section.sectionMargins.bottom); + }else { + sectionFrame.origin.y += contentSize.height; + contentSize.height += sectionFrame.size.height + section.frame.origin.y; + contentSize.width = MAX(contentSize.width, sectionFrame.size.width + section.frame.origin.x + section.sectionMargins.left + section.sectionMargins.right); + } + section.frame = sectionFrame; + } + _data.contentSize = contentSize; +} + +@end diff --git a/ios/Pods/PSTCollectionView/PSTCollectionView/PSTCollectionViewItemKey.h b/ios/Pods/PSTCollectionView/PSTCollectionView/PSTCollectionViewItemKey.h new file mode 100644 index 000000000..ddc91aace --- /dev/null +++ b/ios/Pods/PSTCollectionView/PSTCollectionView/PSTCollectionViewItemKey.h @@ -0,0 +1,28 @@ +// +// PSTCollectionViewItemKey.h +// PSPDFKit +// +// Copyright (c) 2012-2013 Peter Steinberger. All rights reserved. +// + +#import "PSTCollectionViewCommon.h" +#import "PSTCollectionViewLayout.h" + +extern NSString *const PSTCollectionElementKindCell; +extern NSString *const PSTCollectionElementKindDecorationView; +@class PSTCollectionViewLayoutAttributes; + +NSString *PSTCollectionViewItemTypeToString(PSTCollectionViewItemType type); // debug helper + +// Used in NSDictionaries +@interface PSTCollectionViewItemKey : NSObject + ++ (id)collectionItemKeyForLayoutAttributes:(PSTCollectionViewLayoutAttributes *)layoutAttributes; + ++ (id)collectionItemKeyForCellWithIndexPath:(NSIndexPath *)indexPath; + +@property (nonatomic, assign) PSTCollectionViewItemType type; +@property (nonatomic, strong) NSIndexPath *indexPath; +@property (nonatomic, strong) NSString *identifier; + +@end diff --git a/ios/Pods/PSTCollectionView/PSTCollectionView/PSTCollectionViewItemKey.m b/ios/Pods/PSTCollectionView/PSTCollectionView/PSTCollectionViewItemKey.m new file mode 100644 index 000000000..e9d69f4ba --- /dev/null +++ b/ios/Pods/PSTCollectionView/PSTCollectionView/PSTCollectionViewItemKey.m @@ -0,0 +1,77 @@ +// +// PSTCollectionViewItemKey.m +// PSPDFKit +// +// Copyright (c) 2012-2013 Peter Steinberger. All rights reserved. +// + +#import "PSTCollectionViewItemKey.h" + +NSString *const PSTCollectionElementKindCell = @"UICollectionElementKindCell"; + +@implementation PSTCollectionViewItemKey + +/////////////////////////////////////////////////////////////////////////////////////////// +#pragma mark - Static + ++ (id)collectionItemKeyForCellWithIndexPath:(NSIndexPath *)indexPath { + PSTCollectionViewItemKey *key = [self.class new]; + key.indexPath = indexPath; + key.type = PSTCollectionViewItemTypeCell; + key.identifier = PSTCollectionElementKindCell; + return key; +} + ++ (id)collectionItemKeyForLayoutAttributes:(PSTCollectionViewLayoutAttributes *)layoutAttributes { + PSTCollectionViewItemKey *key = [self.class new]; + key.indexPath = layoutAttributes.indexPath; + PSTCollectionViewItemType const itemType = layoutAttributes.representedElementCategory; + key.type = itemType; + key.identifier = layoutAttributes.representedElementKind; + return key; +} + +NSString *PSTCollectionViewItemTypeToString(PSTCollectionViewItemType type) { + switch (type) { + case PSTCollectionViewItemTypeCell: return @"Cell"; + case PSTCollectionViewItemTypeDecorationView: return @"Decoration"; + case PSTCollectionViewItemTypeSupplementaryView: return @"Supplementary"; + default: return @""; + } +} + +/////////////////////////////////////////////////////////////////////////////////////////// +#pragma mark - NSObject + +- (NSString *)description { + return [NSString stringWithFormat:@"<%@: %p Type = %@ Identifier=%@ IndexPath = %@>", NSStringFromClass(self.class), + self, PSTCollectionViewItemTypeToString(self.type), _identifier, self.indexPath]; +} + +- (NSUInteger)hash { + return (([_indexPath hash] + _type) * 31) + [_identifier hash]; +} + +- (BOOL)isEqual:(id)other { + if ([other isKindOfClass:self.class]) { + PSTCollectionViewItemKey *otherKeyItem = (PSTCollectionViewItemKey *)other; + // identifier might be nil? + if (_type == otherKeyItem.type && [_indexPath isEqual:otherKeyItem.indexPath] && ([_identifier isEqualToString:otherKeyItem.identifier] || _identifier == otherKeyItem.identifier)) { + return YES; + } + } + return NO; +} + +/////////////////////////////////////////////////////////////////////////////////////////// +#pragma mark - NSCopying + +- (id)copyWithZone:(NSZone *)zone { + PSTCollectionViewItemKey *itemKey = [self.class new]; + itemKey.indexPath = self.indexPath; + itemKey.type = self.type; + itemKey.identifier = self.identifier; + return itemKey; +} + +@end diff --git a/ios/Pods/PSTCollectionView/PSTCollectionView/PSTCollectionViewLayout+Internals.h b/ios/Pods/PSTCollectionView/PSTCollectionView/PSTCollectionViewLayout+Internals.h new file mode 100644 index 000000000..48f7746bc --- /dev/null +++ b/ios/Pods/PSTCollectionView/PSTCollectionView/PSTCollectionViewLayout+Internals.h @@ -0,0 +1,18 @@ +// +// PSTCollectionViewLayout+Internals.h +// FMPSTCollectionView +// +// Created by Scott Talbot on 27/02/13. +// Copyright (c) 2013 Scott Talbot. All rights reserved. +// + +#import "PSTCollectionViewLayout.h" + + +@interface PSTCollectionViewLayout (Internals) + +@property (nonatomic, copy, readonly) NSDictionary *decorationViewClassDict; +@property (nonatomic, copy, readonly) NSDictionary *decorationViewNibDict; +@property (nonatomic, copy, readonly) NSDictionary *decorationViewExternalObjectsTables; + +@end diff --git a/ios/Pods/PSTCollectionView/PSTCollectionView/PSTCollectionViewLayout.h b/ios/Pods/PSTCollectionView/PSTCollectionView/PSTCollectionViewLayout.h new file mode 100644 index 000000000..3f6f72900 --- /dev/null +++ b/ios/Pods/PSTCollectionView/PSTCollectionView/PSTCollectionViewLayout.h @@ -0,0 +1,128 @@ +// +// PSTCollectionViewLayout.h +// PSPDFKit +// +// Copyright (c) 2012-2013 Peter Steinberger. All rights reserved. +// + +#import "PSTCollectionViewCommon.h" +#import +#import + +typedef NS_ENUM(NSUInteger, PSTCollectionViewItemType) { + PSTCollectionViewItemTypeCell, + PSTCollectionViewItemTypeSupplementaryView, + PSTCollectionViewItemTypeDecorationView +}; + +// The PSTCollectionViewLayout class is provided as an abstract class for subclassing to define custom collection layouts. +// Defining a custom layout is an advanced operation intended for applications with complex needs. +@class PSTCollectionViewLayoutAttributes, PSTCollectionView; + +@interface PSTCollectionViewLayoutAttributes : NSObject + +@property (nonatomic) CGRect frame; +@property (nonatomic) CGPoint center; +@property (nonatomic) CGSize size; +@property (nonatomic) CATransform3D transform3D; +@property (nonatomic) CGFloat alpha; +@property (nonatomic) NSInteger zIndex; // default is 0 +@property (nonatomic, getter=isHidden) BOOL hidden; // As an optimization, PSTCollectionView might not create a view for items whose hidden attribute is YES +@property (nonatomic, strong) NSIndexPath *indexPath; + ++ (instancetype)layoutAttributesForCellWithIndexPath:(NSIndexPath *)indexPath; + ++ (instancetype)layoutAttributesForSupplementaryViewOfKind:(NSString *)elementKind withIndexPath:(NSIndexPath *)indexPath; + ++ (instancetype)layoutAttributesForDecorationViewOfKind:(NSString *)kind withIndexPath:(NSIndexPath *)indexPath; + +/* + + (id)layoutAttributesForDecorationViewOfKind:(id)arg1 withIndexPath:(id)arg2; + - (id)initialLayoutAttributesForInsertedDecorationElementOfKind:(id)arg1 atIndexPath:(id)arg2; + - (BOOL)_isEquivalentTo:(id)arg1; + */ +@end + +@interface PSTCollectionViewLayoutAttributes (Private) +@property (nonatomic, readonly) NSString *representedElementKind; +@property (nonatomic, readonly) PSTCollectionViewItemType representedElementCategory; + +- (BOOL)isDecorationView; + +- (BOOL)isSupplementaryView; + +- (BOOL)isCell; +@end + +@interface PSTCollectionViewLayout : NSObject + +// Methods in this class are meant to be overridden and will be called by its collection view to gather layout information. +// To get the truth on the current state of the collection view, call methods on PSTCollectionView rather than these. +@property (nonatomic, unsafe_unretained, readonly) PSTCollectionView *collectionView; + +// Call -invalidateLayout to indicate that the collection view needs to requery the layout information. +// Subclasses must always call super if they override. +- (void)invalidateLayout; + +/// @name Registering Decoration Views +- (void)registerClass:(Class)viewClass forDecorationViewOfKind:(NSString *)kind; + +- (void)registerNib:(UINib *)nib forDecorationViewOfKind:(NSString *)kind; + +@end + + +@interface PSTCollectionViewLayout (SubclassingHooks) + ++ (Class)layoutAttributesClass; // override this method to provide a custom class to be used when instantiating instances of PSTCollectionViewLayoutAttributes + +// The collection view calls -prepareLayout once at its first layout as the first message to the layout instance. +// The collection view calls -prepareLayout again after layout is invalidated and before requerying the layout information. +// Subclasses should always call super if they override. +- (void)prepareLayout; + +// PSTCollectionView calls these four methods to determine the layout information. +// Implement -layoutAttributesForElementsInRect: to return layout attributes for supplementary or decoration views, or to perform layout in an as-needed-on-screen fashion. +// Additionally, all layout subclasses should implement -layoutAttributesForItemAtIndexPath: to return layout attributes instances on demand for specific index paths. +// If the layout supports any supplementary or decoration view types, it should also implement the respective atIndexPath: methods for those types. +- (NSArray *)layoutAttributesForElementsInRect:(CGRect)rect; // return an array layout attributes instances for all the views in the given rect +- (PSTCollectionViewLayoutAttributes *)layoutAttributesForItemAtIndexPath:(NSIndexPath *)indexPath; + +- (PSTCollectionViewLayoutAttributes *)layoutAttributesForSupplementaryViewOfKind:(NSString *)kind atIndexPath:(NSIndexPath *)indexPath; + +- (PSTCollectionViewLayoutAttributes *)layoutAttributesForDecorationViewOfKind:(NSString *)kind atIndexPath:(NSIndexPath *)indexPath; + +- (BOOL)shouldInvalidateLayoutForBoundsChange:(CGRect)newBounds; // return YES to cause the collection view to requery the layout for geometry information +- (CGPoint)targetContentOffsetForProposedContentOffset:(CGPoint)proposedContentOffset withScrollingVelocity:(CGPoint)velocity; // return a point at which to rest after scrolling - for layouts that want snap-to-point scrolling behavior + +- (CGSize)collectionViewContentSize; // the collection view calls this to update its content size any time it queries new layout information - at least one of the width and height fields must match the respective field of the collection view's bounds + +@end + +@interface PSTCollectionViewLayout (UpdateSupportHooks) + +// This method is called when there is an update with deletes/inserts to the collection view. +// It will be called prior to calling the initial/final layout attribute methods below to give the layout an opportunity to do batch computations for the insertion and deletion layout attributes. +// The updateItems parameter is an array of PSTCollectionViewUpdateItem instances for each element that is moving to a new index path. +- (void)prepareForCollectionViewUpdates:(NSArray *)updateItems; + +// This method is called inside an animation block after all items have been laid out for a collection view update. +// Subclasses can use this opportunity to layout their 'layout-owned' decoration views in response to the update. +- (void)finalizeCollectionViewUpdates; + +// Collection view calls these methods to determine the starting layout for animating in newly inserted views, or the ending layout for animating out deleted views +- (PSTCollectionViewLayoutAttributes *)initialLayoutAttributesForAppearingItemAtIndexPath:(NSIndexPath *)itemIndexPath; + +- (PSTCollectionViewLayoutAttributes *)finalLayoutAttributesForDisappearingItemAtIndexPath:(NSIndexPath *)itemIndexPath; + +- (PSTCollectionViewLayoutAttributes *)initialLayoutAttributesForInsertedSupplementaryElementOfKind:(NSString *)elementKind atIndexPath:(NSIndexPath *)elementIndexPath; + +- (PSTCollectionViewLayoutAttributes *)finalLayoutAttributesForDeletedSupplementaryElementOfKind:(NSString *)elementKind atIndexPath:(NSIndexPath *)elementIndexPath; + +@end + +@interface PSTCollectionViewLayout (Private) +- (void)setCollectionViewBoundsSize:(CGSize)size; + +- (PSTCollectionReusableView *)decorationViewForCollectionView:(PSTCollectionView *)collectionView withReuseIdentifier:(NSString *)reuseIdentifier indexPath:(NSIndexPath *)indexPath; +@end diff --git a/ios/Pods/PSTCollectionView/PSTCollectionView/PSTCollectionViewLayout.m b/ios/Pods/PSTCollectionView/PSTCollectionView/PSTCollectionViewLayout.m new file mode 100644 index 000000000..7cb5ead29 --- /dev/null +++ b/ios/Pods/PSTCollectionView/PSTCollectionView/PSTCollectionViewLayout.m @@ -0,0 +1,481 @@ +// +// PSTCollectionViewLayout.m +// PSPDFKit +// +// Copyright (c) 2012-2013 Peter Steinberger. All rights reserved. +// + +#import "PSTCollectionView.h" +#import "PSTCollectionViewItemKey.h" +#import "PSTCollectionViewData.h" + +#import + +@interface PSTCollectionView () +- (id)currentUpdate; +- (NSDictionary *)visibleViewsDict; +- (PSTCollectionViewData *)collectionViewData; +- (CGRect)visibleBoundRects; // visibleBounds is flagged as private API (wtf) +@end + +@interface PSTCollectionReusableView () +- (void)setIndexPath:(NSIndexPath *)indexPath; +@end + +@interface PSTCollectionViewUpdateItem () +- (BOOL)isSectionOperation; +@end + +@interface PSTCollectionViewLayoutAttributes () { + struct { + unsigned int isCellKind:1; + unsigned int isDecorationView:1; + unsigned int isHidden:1; + }_layoutFlags; + char filler[20]; // [HACK] Our class needs to be larger than Apple's class for the superclass change to work. +} +@property (nonatomic) PSTCollectionViewItemType elementCategory; +@property (nonatomic, copy) NSString *elementKind; +@end + +@interface PSTCollectionViewUpdateItem () +- (NSIndexPath *)indexPath; +@end + +@implementation PSTCollectionViewLayoutAttributes + +/////////////////////////////////////////////////////////////////////////////////////////// +#pragma mark - Static + ++ (instancetype)layoutAttributesForCellWithIndexPath:(NSIndexPath *)indexPath { + PSTCollectionViewLayoutAttributes *attributes = [self new]; + attributes.elementKind = PSTCollectionElementKindCell; + attributes.elementCategory = PSTCollectionViewItemTypeCell; + attributes.indexPath = indexPath; + return attributes; +} + ++ (instancetype)layoutAttributesForSupplementaryViewOfKind:(NSString *)elementKind withIndexPath:(NSIndexPath *)indexPath { + PSTCollectionViewLayoutAttributes *attributes = [self new]; + attributes.elementCategory = PSTCollectionViewItemTypeSupplementaryView; + attributes.elementKind = elementKind; + attributes.indexPath = indexPath; + return attributes; +} + ++ (instancetype)layoutAttributesForDecorationViewOfKind:(NSString *)elementKind withIndexPath:(NSIndexPath *)indexPath { + PSTCollectionViewLayoutAttributes *attributes = [self new]; + attributes.elementCategory = PSTCollectionViewItemTypeDecorationView; + attributes.elementKind = elementKind; + attributes.indexPath = indexPath; + return attributes; +} + +/////////////////////////////////////////////////////////////////////////////////////////// +#pragma mark - NSObject + +- (id)init { + if ((self = [super init])) { + _alpha = 1.f; + _transform3D = CATransform3DIdentity; + } + return self; +} + +- (NSUInteger)hash { + return ([_elementKind hash] * 31) + [_indexPath hash]; +} + +- (BOOL)isEqual:(id)other { + if ([other isKindOfClass:self.class]) { + PSTCollectionViewLayoutAttributes *otherLayoutAttributes = (PSTCollectionViewLayoutAttributes *)other; + if (_elementCategory == otherLayoutAttributes.elementCategory && [_elementKind isEqual:otherLayoutAttributes.elementKind] && [_indexPath isEqual:otherLayoutAttributes.indexPath]) { + return YES; + } + } + return NO; +} + +- (NSString *)description { + return [NSString stringWithFormat:@"<%@: %p frame:%@ indexPath:%@ elementKind:%@>", NSStringFromClass(self.class), self, NSStringFromCGRect(self.frame), self.indexPath, self.elementKind]; +} + +/////////////////////////////////////////////////////////////////////////////////////////// +#pragma mark - Public + +- (PSTCollectionViewItemType)representedElementCategory { + return _elementCategory; +} + +/////////////////////////////////////////////////////////////////////////////////////////// +#pragma mark - Private + +- (NSString *)representedElementKind { + return self.elementKind; +} + +- (BOOL)isDecorationView { + return self.representedElementCategory == PSTCollectionViewItemTypeDecorationView; +} + +- (BOOL)isSupplementaryView { + return self.representedElementCategory == PSTCollectionViewItemTypeSupplementaryView; +} + +- (BOOL)isCell { + return self.representedElementCategory == PSTCollectionViewItemTypeCell; +} + +- (void) updateFrame { + _frame = (CGRect){{_center.x - _size.width / 2, _center.y - _size.height / 2}, _size}; +} + +- (void)setSize:(CGSize)size { + _size = size; + [self updateFrame]; +} + +- (void)setCenter:(CGPoint)center { + _center = center; + [self updateFrame]; +} + +- (void)setFrame:(CGRect)frame { + _frame = frame; + _size = _frame.size; + _center = (CGPoint){CGRectGetMidX(_frame), CGRectGetMidY(_frame)}; +} + +/////////////////////////////////////////////////////////////////////////////////////////// +#pragma mark - NSCopying + +- (id)copyWithZone:(NSZone *)zone { + PSTCollectionViewLayoutAttributes *layoutAttributes = [self.class new]; + layoutAttributes.indexPath = self.indexPath; + layoutAttributes.elementKind = self.elementKind; + layoutAttributes.elementCategory = self.elementCategory; + layoutAttributes.frame = self.frame; + layoutAttributes.center = self.center; + layoutAttributes.size = self.size; + layoutAttributes.transform3D = self.transform3D; + layoutAttributes.alpha = self.alpha; + layoutAttributes.zIndex = self.zIndex; + layoutAttributes.hidden = self.isHidden; + return layoutAttributes; +} + +/////////////////////////////////////////////////////////////////////////////////////////// +#pragma mark - PSTCollection/UICollection interoperability + +- (NSMethodSignature *)methodSignatureForSelector:(SEL)selector { + NSMethodSignature *signature = [super methodSignatureForSelector:selector]; + if (!signature) { + NSString *selString = NSStringFromSelector(selector); + if ([selString hasPrefix:@"_"]) { + SEL cleanedSelector = NSSelectorFromString([selString substringFromIndex:1]); + signature = [super methodSignatureForSelector:cleanedSelector]; + } + } + return signature; +} + +- (void)forwardInvocation:(NSInvocation *)invocation { + NSString *selString = NSStringFromSelector([invocation selector]); + if ([selString hasPrefix:@"_"]) { + SEL cleanedSelector = NSSelectorFromString([selString substringFromIndex:1]); + if ([self respondsToSelector:cleanedSelector]) { + invocation.selector = cleanedSelector; + [invocation invokeWithTarget:self]; + } + }else { + [super forwardInvocation:invocation]; + } +} + +@end + + +@interface PSTCollectionViewLayout () { + __unsafe_unretained PSTCollectionView *_collectionView; + CGSize _collectionViewBoundsSize; + NSMutableDictionary *_initialAnimationLayoutAttributesDict; + NSMutableDictionary *_finalAnimationLayoutAttributesDict; + NSMutableIndexSet *_deletedSectionsSet; + NSMutableIndexSet *_insertedSectionsSet; + NSMutableDictionary *_decorationViewClassDict; + NSMutableDictionary *_decorationViewNibDict; + NSMutableDictionary *_decorationViewExternalObjectsTables; + char filler[200]; // [HACK] Our class needs to be larger than Apple's class for the superclass change to work. +} +@property (nonatomic, unsafe_unretained) PSTCollectionView *collectionView; +@property (nonatomic, copy, readonly) NSDictionary *decorationViewClassDict; +@property (nonatomic, copy, readonly) NSDictionary *decorationViewNibDict; +@property (nonatomic, copy, readonly) NSDictionary *decorationViewExternalObjectsTables; +@end + +@implementation PSTCollectionViewLayout +/////////////////////////////////////////////////////////////////////////////////////////// +#pragma mark - NSObject + +- (id)init { + if ((self = [super init])) { + _decorationViewClassDict = [NSMutableDictionary new]; + _decorationViewNibDict = [NSMutableDictionary new]; + _decorationViewExternalObjectsTables = [NSMutableDictionary new]; + _initialAnimationLayoutAttributesDict = [NSMutableDictionary new]; + _finalAnimationLayoutAttributesDict = [NSMutableDictionary new]; + _insertedSectionsSet = [NSMutableIndexSet new]; + _deletedSectionsSet = [NSMutableIndexSet new]; + } + return self; +} + +- (void)awakeFromNib { + [super awakeFromNib]; +} + +- (void)setCollectionView:(PSTCollectionView *)collectionView { + if (collectionView != _collectionView) { + _collectionView = collectionView; + } +} + +/////////////////////////////////////////////////////////////////////////////////////////// +#pragma mark - Invalidating the Layout + +- (void)invalidateLayout { + [[_collectionView collectionViewData] invalidate]; + [_collectionView setNeedsLayout]; +} + +- (BOOL)shouldInvalidateLayoutForBoundsChange:(CGRect)newBounds { + // not sure about his.. + if ((self.collectionView.bounds.size.width != newBounds.size.width) || (self.collectionView.bounds.size.height != newBounds.size.height)) { + return YES; + } + return NO; +} + +/////////////////////////////////////////////////////////////////////////////////////////// +#pragma mark - Providing Layout Attributes + ++ (Class)layoutAttributesClass { + return PSTCollectionViewLayoutAttributes.class; +} + +- (void)prepareLayout { +} + +- (NSArray *)layoutAttributesForElementsInRect:(CGRect)rect { + return nil; +} + +- (PSTCollectionViewLayoutAttributes *)layoutAttributesForItemAtIndexPath:(NSIndexPath *)indexPath { + return nil; +} + +- (PSTCollectionViewLayoutAttributes *)layoutAttributesForSupplementaryViewOfKind:(NSString *)kind atIndexPath:(NSIndexPath *)indexPath { + return nil; +} + +- (PSTCollectionViewLayoutAttributes *)layoutAttributesForDecorationViewOfKind:(NSString *)kind atIndexPath:(NSIndexPath *)indexPath { + return nil; +} + +// return a point at which to rest after scrolling - for layouts that want snap-to-point scrolling behavior +- (CGPoint)targetContentOffsetForProposedContentOffset:(CGPoint)proposedContentOffset withScrollingVelocity:(CGPoint)velocity { + return proposedContentOffset; +} + +- (CGSize)collectionViewContentSize { + return CGSizeZero; +} + +/////////////////////////////////////////////////////////////////////////////////////////// +#pragma mark - Responding to Collection View Updates + +- (void)prepareForCollectionViewUpdates:(NSArray *)updateItems { + NSDictionary *update = [_collectionView currentUpdate]; + + for (PSTCollectionReusableView *view in [[_collectionView visibleViewsDict] objectEnumerator]) { + PSTCollectionViewLayoutAttributes *attr = [view.layoutAttributes copy]; + if (attr) { + if (attr.isCell) { + NSUInteger index = [update[@"oldModel"] globalIndexForItemAtIndexPath:[attr indexPath]]; + if (index != NSNotFound) { + [attr setIndexPath:[attr indexPath]]; + } + } + _initialAnimationLayoutAttributesDict[[PSTCollectionViewItemKey collectionItemKeyForLayoutAttributes:attr]] = attr; + } + } + + PSTCollectionViewData *collectionViewData = [_collectionView collectionViewData]; + + CGRect bounds = [_collectionView visibleBoundRects]; + + for (PSTCollectionViewLayoutAttributes *attr in [collectionViewData layoutAttributesForElementsInRect:bounds]) { + if (attr.isCell) { + NSInteger index = (NSInteger)[collectionViewData globalIndexForItemAtIndexPath:attr.indexPath]; + + index = [update[@"newToOldIndexMap"][(NSUInteger)index] integerValue]; + if (index != NSNotFound) { + PSTCollectionViewLayoutAttributes *finalAttrs = [attr copy]; + [finalAttrs setIndexPath:[update[@"oldModel"] indexPathForItemAtGlobalIndex:index]]; + [finalAttrs setAlpha:0]; + _finalAnimationLayoutAttributesDict[[PSTCollectionViewItemKey collectionItemKeyForLayoutAttributes:finalAttrs]] = finalAttrs; + } + } + } + + for (PSTCollectionViewUpdateItem *updateItem in updateItems) { + PSTCollectionUpdateAction action = updateItem.updateAction; + + if ([updateItem isSectionOperation]) { + if (action == PSTCollectionUpdateActionReload) { + [_deletedSectionsSet addIndex:(NSUInteger)[[updateItem indexPathBeforeUpdate] section]]; + [_insertedSectionsSet addIndex:(NSUInteger)[updateItem indexPathAfterUpdate].section]; + } + else { + NSMutableIndexSet *indexSet = action == PSTCollectionUpdateActionInsert ? _insertedSectionsSet : _deletedSectionsSet; + [indexSet addIndex:(NSUInteger)[updateItem indexPath].section]; + } + } + else { + if (action == PSTCollectionUpdateActionDelete) { + PSTCollectionViewItemKey *key = [PSTCollectionViewItemKey collectionItemKeyForCellWithIndexPath: + [updateItem indexPathBeforeUpdate]]; + + PSTCollectionViewLayoutAttributes *attrs = [_finalAnimationLayoutAttributesDict[key] copy]; + + if (attrs) { + [attrs setAlpha:0]; + _finalAnimationLayoutAttributesDict[key] = attrs; + } + } + else if (action == PSTCollectionUpdateActionReload || action == PSTCollectionUpdateActionInsert) { + PSTCollectionViewItemKey *key = [PSTCollectionViewItemKey collectionItemKeyForCellWithIndexPath: + [updateItem indexPathAfterUpdate]]; + PSTCollectionViewLayoutAttributes *attrs = [_initialAnimationLayoutAttributesDict[key] copy]; + + if (attrs) { + [attrs setAlpha:0]; + _initialAnimationLayoutAttributesDict[key] = attrs; + } + } + } + } +} + +- (PSTCollectionViewLayoutAttributes *)initialLayoutAttributesForAppearingItemAtIndexPath:(NSIndexPath *)itemIndexPath { + PSTCollectionViewLayoutAttributes *attrs = _initialAnimationLayoutAttributesDict[[PSTCollectionViewItemKey collectionItemKeyForCellWithIndexPath:itemIndexPath]]; + + if ([_insertedSectionsSet containsIndex:(NSUInteger)[itemIndexPath section]]) { + attrs = [attrs copy]; + [attrs setAlpha:0]; + } + return attrs; +} + +- (PSTCollectionViewLayoutAttributes *)finalLayoutAttributesForDisappearingItemAtIndexPath:(NSIndexPath *)itemIndexPath { + PSTCollectionViewLayoutAttributes *attrs = _finalAnimationLayoutAttributesDict[[PSTCollectionViewItemKey collectionItemKeyForCellWithIndexPath:itemIndexPath]]; + + if ([_deletedSectionsSet containsIndex:(NSUInteger)[itemIndexPath section]]) { + attrs = [attrs copy]; + [attrs setAlpha:0]; + } + return attrs; + +} + +- (PSTCollectionViewLayoutAttributes *)initialLayoutAttributesForInsertedSupplementaryElementOfKind:(NSString *)elementKind atIndexPath:(NSIndexPath *)elementIndexPath { + PSTCollectionViewLayoutAttributes *attrs = _initialAnimationLayoutAttributesDict[[PSTCollectionViewItemKey collectionItemKeyForCellWithIndexPath:elementIndexPath]]; + + if ([_insertedSectionsSet containsIndex:(NSUInteger)[elementIndexPath section]]) { + attrs = [attrs copy]; + [attrs setAlpha:0]; + } + return attrs; + +} + +- (PSTCollectionViewLayoutAttributes *)finalLayoutAttributesForDeletedSupplementaryElementOfKind:(NSString *)elementKind atIndexPath:(NSIndexPath *)elementIndexPath { + return nil; +} + +- (void)finalizeCollectionViewUpdates { + [_initialAnimationLayoutAttributesDict removeAllObjects]; + [_finalAnimationLayoutAttributesDict removeAllObjects]; + [_deletedSectionsSet removeAllIndexes]; + [_insertedSectionsSet removeAllIndexes]; +} + +/////////////////////////////////////////////////////////////////////////////////////////// +#pragma mark - Registering Decoration Views + +- (void)registerClass:(Class)viewClass forDecorationViewOfKind:(NSString *)kind { + _decorationViewClassDict[kind] = viewClass; +} + +- (void)registerNib:(UINib *)nib forDecorationViewOfKind:(NSString *)kind { + _decorationViewNibDict[kind] = nib; +} + +/////////////////////////////////////////////////////////////////////////////////////////// +#pragma mark - Private + +- (void)setCollectionViewBoundsSize:(CGSize)size { + _collectionViewBoundsSize = size; +} + +/////////////////////////////////////////////////////////////////////////////////////////// +#pragma mark - NSCoding + +- (id)initWithCoder:(NSCoder *)coder { + if ((self = [self init])) { + } + return self; +} + +- (void)encodeWithCoder:(NSCoder *)coder {} + +/////////////////////////////////////////////////////////////////////////////////////////// +#pragma mark - PSTCollection/UICollection interoperability + +#ifdef kPSUIInteroperabilityEnabled +#import +#import +- (NSMethodSignature *)methodSignatureForSelector:(SEL)selector { + NSMethodSignature *sig = [super methodSignatureForSelector:selector]; + if(!sig) { + NSString *selString = NSStringFromSelector(selector); + if ([selString hasPrefix:@"_"]) { + SEL cleanedSelector = NSSelectorFromString([selString substringFromIndex:1]); + sig = [super methodSignatureForSelector:cleanedSelector]; + } + } + return sig; +} + +- (void)forwardInvocation:(NSInvocation *)inv { + NSString *selString = NSStringFromSelector([inv selector]); + if ([selString hasPrefix:@"_"]) { + SEL cleanedSelector = NSSelectorFromString([selString substringFromIndex:1]); + if ([self respondsToSelector:cleanedSelector]) { + // dynamically add method for faster resolving + Method newMethod = class_getInstanceMethod(self.class, [inv selector]); + IMP underscoreIMP = imp_implementationWithBlock(^(id _self) { + return objc_msgSend(_self, cleanedSelector); + }); + class_addMethod(self.class, [inv selector], underscoreIMP, method_getTypeEncoding(newMethod)); + // invoke now + inv.selector = cleanedSelector; + [inv invokeWithTarget:self]; + } + }else { + [super forwardInvocation:inv]; + } +} +#endif + +@end diff --git a/ios/Pods/PSTCollectionView/PSTCollectionView/PSTCollectionViewUpdateItem.h b/ios/Pods/PSTCollectionView/PSTCollectionView/PSTCollectionViewUpdateItem.h new file mode 100644 index 000000000..d74c7cf86 --- /dev/null +++ b/ios/Pods/PSTCollectionView/PSTCollectionView/PSTCollectionViewUpdateItem.h @@ -0,0 +1,41 @@ +// +// PSTCollectionViewUpdateItem.h +// PSPDFKit +// +// Copyright (c) 2012-2013 Peter Steinberger. All rights reserved. +// Contributed by Sergey Gavrilyuk. +// + +#import + +typedef NS_ENUM(NSInteger, PSTCollectionUpdateAction) { + PSTCollectionUpdateActionInsert, + PSTCollectionUpdateActionDelete, + PSTCollectionUpdateActionReload, + PSTCollectionUpdateActionMove, + PSTCollectionUpdateActionNone +}; + +@interface PSTCollectionViewUpdateItem : NSObject + +@property (nonatomic, readonly, strong) NSIndexPath *indexPathBeforeUpdate; // nil for PSTCollectionUpdateActionInsert +@property (nonatomic, readonly, strong) NSIndexPath *indexPathAfterUpdate; // nil for PSTCollectionUpdateActionDelete +@property (nonatomic, readonly, assign) PSTCollectionUpdateAction updateAction; + + +- (id)initWithInitialIndexPath:(NSIndexPath *)arg1 + finalIndexPath:(NSIndexPath *)arg2 + updateAction:(PSTCollectionUpdateAction)arg3; + +- (id)initWithAction:(PSTCollectionUpdateAction)arg1 + forIndexPath:(NSIndexPath *)indexPath; + +- (id)initWithOldIndexPath:(NSIndexPath *)arg1 newIndexPath:(NSIndexPath *)arg2; + +- (PSTCollectionUpdateAction)updateAction; + +- (NSComparisonResult)compareIndexPaths:(PSTCollectionViewUpdateItem *)otherItem; + +- (NSComparisonResult)inverseCompareIndexPaths:(PSTCollectionViewUpdateItem *)otherItem; + +@end diff --git a/ios/Pods/PSTCollectionView/PSTCollectionView/PSTCollectionViewUpdateItem.m b/ios/Pods/PSTCollectionView/PSTCollectionView/PSTCollectionViewUpdateItem.m new file mode 100644 index 000000000..fe019db05 --- /dev/null +++ b/ios/Pods/PSTCollectionView/PSTCollectionView/PSTCollectionViewUpdateItem.m @@ -0,0 +1,117 @@ +// +// PSTCollectionViewUpdateItem.m +// PSPDFKit +// +// Copyright (c) 2012-2013 Peter Steinberger. All rights reserved. +// Contributed by Sergey Gavrilyuk. +// + +#import "PSTCollectionViewUpdateItem.h" +#import "NSIndexPath+PSTCollectionViewAdditions.h" + +@interface PSTCollectionViewUpdateItem () { + NSIndexPath *_initialIndexPath; + NSIndexPath *_finalIndexPath; + PSTCollectionUpdateAction _updateAction; + id _gap; +} +@end + +@implementation PSTCollectionViewUpdateItem + +@synthesize updateAction = _updateAction; +@synthesize indexPathBeforeUpdate = _initialIndexPath; +@synthesize indexPathAfterUpdate = _finalIndexPath; + +- (id)initWithInitialIndexPath:(NSIndexPath *)initialIndexPath finalIndexPath:(NSIndexPath *)finalIndexPath updateAction:(PSTCollectionUpdateAction)updateAction { + if ((self = [super init])) { + _initialIndexPath = initialIndexPath; + _finalIndexPath = finalIndexPath; + _updateAction = updateAction; + } + return self; +} + +- (id)initWithAction:(PSTCollectionUpdateAction)updateAction forIndexPath:(NSIndexPath *)indexPath { + if (updateAction == PSTCollectionUpdateActionInsert) + return [self initWithInitialIndexPath:nil finalIndexPath:indexPath updateAction:updateAction]; + else if (updateAction == PSTCollectionUpdateActionDelete) + return [self initWithInitialIndexPath:indexPath finalIndexPath:nil updateAction:updateAction]; + else if (updateAction == PSTCollectionUpdateActionReload) + return [self initWithInitialIndexPath:indexPath finalIndexPath:indexPath updateAction:updateAction]; + + return nil; +} + +- (id)initWithOldIndexPath:(NSIndexPath *)oldIndexPath newIndexPath:(NSIndexPath *)newIndexPath { + return [self initWithInitialIndexPath:oldIndexPath finalIndexPath:newIndexPath updateAction:PSTCollectionUpdateActionMove]; +} + +- (NSString *)description { + NSString *action = nil; + switch (_updateAction) { + case PSTCollectionUpdateActionInsert: action = @"insert"; break; + case PSTCollectionUpdateActionDelete: action = @"delete"; break; + case PSTCollectionUpdateActionMove: action = @"move"; break; + case PSTCollectionUpdateActionReload: action = @"reload"; break; + default: break; + } + + return [NSString stringWithFormat:@"Index path before update (%@) index path after update (%@) action (%@).", _initialIndexPath, _finalIndexPath, action]; +} + +- (void)setNewIndexPath:(NSIndexPath *)indexPath { + _finalIndexPath = indexPath; +} + +- (void)setGap:(id)gap { + _gap = gap; +} + +- (BOOL)isSectionOperation { + return (_initialIndexPath.item == NSNotFound || _finalIndexPath.item == NSNotFound); +} + +- (NSIndexPath *)newIndexPath { + return _finalIndexPath; +} + +- (id)gap { + return _gap; +} + +- (PSTCollectionUpdateAction)action { + return _updateAction; +} + +- (id)indexPath { + //TODO: check this + return _initialIndexPath; +} + +- (NSComparisonResult)compareIndexPaths:(PSTCollectionViewUpdateItem *)otherItem { + NSComparisonResult result = NSOrderedSame; + NSIndexPath *selfIndexPath = nil; + NSIndexPath *otherIndexPath = nil; + + switch (_updateAction) { + case PSTCollectionUpdateActionInsert: + selfIndexPath = _finalIndexPath; + otherIndexPath = [otherItem newIndexPath]; + break; + case PSTCollectionUpdateActionDelete: + selfIndexPath = _initialIndexPath; + otherIndexPath = [otherItem indexPath]; + default: break; + } + + if (self.isSectionOperation) result = [@(selfIndexPath.section) compare:@(otherIndexPath.section)]; + else result = [selfIndexPath compare:otherIndexPath]; + return result; +} + +- (NSComparisonResult)inverseCompareIndexPaths:(PSTCollectionViewUpdateItem *)otherItem { + return (NSComparisonResult)([self compareIndexPaths:otherItem] * -1); +} + +@end diff --git a/ios/Pods/PSTCollectionView/PSTCollectionView/PSTGridLayoutInfo.h b/ios/Pods/PSTCollectionView/PSTCollectionView/PSTGridLayoutInfo.h new file mode 100644 index 000000000..c3f215fa3 --- /dev/null +++ b/ios/Pods/PSTCollectionView/PSTCollectionView/PSTGridLayoutInfo.h @@ -0,0 +1,43 @@ +// +// PSTGridLayoutInfo.h +// PSPDFKit +// +// Copyright (c) 2012-2013 Peter Steinberger. All rights reserved. +// + +#import + +@class PSTGridLayoutSection; + +/* + Every PSTCollectionViewLayout has a PSTGridLayoutInfo attached. + Is used extensively in PSTCollectionViewFlowLayout. + */ +@interface PSTGridLayoutInfo : NSObject + +@property (nonatomic, strong, readonly) NSArray *sections; +@property (nonatomic, strong) NSDictionary *rowAlignmentOptions; +@property (nonatomic, assign) BOOL usesFloatingHeaderFooter; + +// Vertical/horizontal dimension (depending on horizontal) +// Used to create row objects +@property (nonatomic, assign) CGFloat dimension; + +@property (nonatomic, assign) BOOL horizontal; +@property (nonatomic, assign) BOOL leftToRight; +@property (nonatomic, assign) CGSize contentSize; + +// Frame for specific PSTGridLayoutItem. +- (CGRect)frameForItemAtIndexPath:(NSIndexPath *)indexPath; + +// Add new section. Invalidates layout. +- (PSTGridLayoutSection *)addSection; + +// forces the layout to recompute on next access +// TODO; what's the parameter for? +- (void)invalidate:(BOOL)arg; + +// Make a copy of the current state. +- (PSTGridLayoutInfo *)snapshot; + +@end diff --git a/ios/Pods/PSTCollectionView/PSTCollectionView/PSTGridLayoutInfo.m b/ios/Pods/PSTCollectionView/PSTCollectionView/PSTGridLayoutInfo.m new file mode 100644 index 000000000..6ab1aeb03 --- /dev/null +++ b/ios/Pods/PSTCollectionView/PSTCollectionView/PSTGridLayoutInfo.m @@ -0,0 +1,76 @@ +// +// PSTGridLayoutInfo.m +// PSPDFKit +// +// Copyright (c) 2012-2013 Peter Steinberger. All rights reserved. +// + +#import "PSTGridLayoutInfo.h" +#import "PSTGridLayoutSection.h" +#import "PSTGridLayoutItem.h" + +@interface PSTGridLayoutInfo () { + NSMutableArray *_sections; + CGRect _visibleBounds; + CGSize _layoutSize; + BOOL _isValid; +} +@property (nonatomic, strong) NSMutableArray *sections; +@end + +@implementation PSTGridLayoutInfo + +/////////////////////////////////////////////////////////////////////////////////////////// +#pragma mark - NSObject + +- (id)init { + if ((self = [super init])) { + _sections = [NSMutableArray new]; + } + return self; +} + +- (NSString *)description { + return [NSString stringWithFormat:@"<%@: %p dimension:%.1f horizontal:%d contentSize:%@ sections:%@>", NSStringFromClass(self.class), self, self.dimension, self.horizontal, NSStringFromCGSize(self.contentSize), self.sections]; +} + +/////////////////////////////////////////////////////////////////////////////////////////// +#pragma mark - Public + +- (PSTGridLayoutInfo *)snapshot { + PSTGridLayoutInfo *layoutInfo = [self.class new]; + layoutInfo.sections = self.sections; + layoutInfo.rowAlignmentOptions = self.rowAlignmentOptions; + layoutInfo.usesFloatingHeaderFooter = self.usesFloatingHeaderFooter; + layoutInfo.dimension = self.dimension; + layoutInfo.horizontal = self.horizontal; + layoutInfo.leftToRight = self.leftToRight; + layoutInfo.contentSize = self.contentSize; + return layoutInfo; +} + +- (CGRect)frameForItemAtIndexPath:(NSIndexPath *)indexPath { + PSTGridLayoutSection *section = self.sections[(NSUInteger)indexPath.section]; + CGRect itemFrame; + if (section.fixedItemSize) { + itemFrame = (CGRect){.size=section.itemSize}; + }else { + itemFrame = [section.items[(NSUInteger)indexPath.item] itemFrame]; + } + return itemFrame; +} + +- (id)addSection { + PSTGridLayoutSection *section = [PSTGridLayoutSection new]; + section.rowAlignmentOptions = self.rowAlignmentOptions; + section.layoutInfo = self; + [_sections addObject:section]; + [self invalidate:NO]; + return section; +} + +- (void)invalidate:(BOOL)arg { + _isValid = NO; +} + +@end diff --git a/ios/Pods/PSTCollectionView/PSTCollectionView/PSTGridLayoutItem.h b/ios/Pods/PSTCollectionView/PSTCollectionView/PSTGridLayoutItem.h new file mode 100644 index 000000000..380f1a994 --- /dev/null +++ b/ios/Pods/PSTCollectionView/PSTCollectionView/PSTGridLayoutItem.h @@ -0,0 +1,19 @@ +// +// PSTGridLayoutItem.h +// PSPDFKit +// +// Copyright (c) 2012-2013 Peter Steinberger. All rights reserved. +// + +#import + +@class PSTGridLayoutSection, PSTGridLayoutRow; + +// Represents a single grid item; only created for non-uniform-sized grids. +@interface PSTGridLayoutItem : NSObject + +@property (nonatomic, unsafe_unretained) PSTGridLayoutSection *section; +@property (nonatomic, unsafe_unretained) PSTGridLayoutRow *rowObject; +@property (nonatomic, assign) CGRect itemFrame; + +@end diff --git a/ios/Pods/PSTCollectionView/PSTCollectionView/PSTGridLayoutItem.m b/ios/Pods/PSTCollectionView/PSTCollectionView/PSTGridLayoutItem.m new file mode 100644 index 000000000..69cb63b36 --- /dev/null +++ b/ios/Pods/PSTCollectionView/PSTCollectionView/PSTGridLayoutItem.m @@ -0,0 +1,19 @@ +// +// PSTGridLayoutItem.m +// PSPDFKit +// +// Copyright (c) 2012-2013 Peter Steinberger. All rights reserved. +// + +#import "PSTGridLayoutItem.h" + +@implementation PSTGridLayoutItem + +/////////////////////////////////////////////////////////////////////////////////////////// +#pragma mark - NSObject + +- (NSString *)description { + return [NSString stringWithFormat:@"<%@: %p itemFrame:%@>", NSStringFromClass(self.class), self, NSStringFromCGRect(self.itemFrame)]; +} + +@end diff --git a/ios/Pods/PSTCollectionView/PSTCollectionView/PSTGridLayoutRow.h b/ios/Pods/PSTCollectionView/PSTCollectionView/PSTGridLayoutRow.h new file mode 100644 index 000000000..613db1e21 --- /dev/null +++ b/ios/Pods/PSTCollectionView/PSTCollectionView/PSTGridLayoutRow.h @@ -0,0 +1,43 @@ +// +// PSTGridLayoutRow.h +// PSPDFKit +// +// Copyright (c) 2012-2013 Peter Steinberger. All rights reserved. +// + +#import + +@class PSTGridLayoutSection, PSTGridLayoutItem; + +@interface PSTGridLayoutRow : NSObject + +@property (nonatomic, unsafe_unretained) PSTGridLayoutSection *section; +@property (nonatomic, strong, readonly) NSArray *items; +@property (nonatomic, assign) CGSize rowSize; +@property (nonatomic, assign) CGRect rowFrame; +@property (nonatomic, assign) NSInteger index; +@property (nonatomic, assign) BOOL complete; +@property (nonatomic, assign) BOOL fixedItemSize; + +// @steipete addition for row-fastPath +@property (nonatomic, assign) NSInteger itemCount; + +//- (PSTGridLayoutRow *)copyFromSection:(PSTGridLayoutSection *)section; // ??? + +// Add new item to items array. +- (void)addItem:(PSTGridLayoutItem *)item; + +// Layout current row (if invalid) +- (void)layoutRow; + +// @steipete: Helper to save code in PSTCollectionViewFlowLayout. +// Returns the item rects when fixedItemSize is enabled. +- (NSArray *)itemRects; + +// Set current row frame invalid. +- (void)invalidate; + +// Copy a snapshot of the current row data +- (PSTGridLayoutRow *)snapshot; + +@end diff --git a/ios/Pods/PSTCollectionView/PSTCollectionView/PSTGridLayoutRow.m b/ios/Pods/PSTCollectionView/PSTCollectionView/PSTGridLayoutRow.m new file mode 100644 index 000000000..3d6ef65b5 --- /dev/null +++ b/ios/Pods/PSTCollectionView/PSTCollectionView/PSTGridLayoutRow.m @@ -0,0 +1,193 @@ +// +// PSTGridLayoutRow.m +// PSPDFKit +// +// Copyright (c) 2012-2013 Peter Steinberger. All rights reserved. +// + +#import "PSTCollectionView.h" +#import "PSTGridLayoutRow.h" +#import "PSTGridLayoutSection.h" +#import "PSTGridLayoutItem.h" +#import "PSTGridLayoutInfo.h" + +@interface PSTGridLayoutRow () { + NSMutableArray *_items; + BOOL _isValid; + int _verticalAlignement; + int _horizontalAlignement; +} +@property (nonatomic, strong) NSArray *items; +@end + +@implementation PSTGridLayoutRow + +/////////////////////////////////////////////////////////////////////////////////////////// +#pragma mark - NSObject + +- (id)init { + if ((self = [super init])) { + _items = [NSMutableArray new]; + } + return self; +} + +- (NSString *)description { + return [NSString stringWithFormat:@"<%@: %p frame:%@ index:%ld items:%@>", NSStringFromClass(self.class), self, NSStringFromCGRect(self.rowFrame), (long)self.index, self.items]; +} + +/////////////////////////////////////////////////////////////////////////////////////////// +#pragma mark - Public + +- (void)invalidate { + _isValid = NO; + _rowSize = CGSizeZero; + _rowFrame = CGRectZero; +} + +- (NSArray *)itemRects { + return [self layoutRowAndGenerateRectArray:YES]; +} + +- (void)layoutRow { + [self layoutRowAndGenerateRectArray:NO]; +} + +- (NSArray *)layoutRowAndGenerateRectArray:(BOOL)generateRectArray { + NSMutableArray *rects = generateRectArray ? [NSMutableArray array] : nil; + if (!_isValid || generateRectArray) { + // properties for aligning + BOOL isHorizontal = self.section.layoutInfo.horizontal; + BOOL isLastRow = self.section.indexOfImcompleteRow == self.index; + PSTFlowLayoutHorizontalAlignment horizontalAlignment = [self.section.rowAlignmentOptions[isLastRow ? PSTFlowLayoutLastRowHorizontalAlignmentKey : PSTFlowLayoutCommonRowHorizontalAlignmentKey] integerValue]; + + // calculate space that's left over if we would align it from left to right. + CGFloat leftOverSpace = self.section.layoutInfo.dimension; + if (isHorizontal) { + leftOverSpace -= self.section.sectionMargins.top + self.section.sectionMargins.bottom; + }else { + leftOverSpace -= self.section.sectionMargins.left + self.section.sectionMargins.right; + } + + // calculate the space that we have left after counting all items. + // UICollectionView is smart and lays out items like they would have been placed on a full row + // So we need to calculate the "usedItemCount" with using the last item as a reference size. + // This allows us to correctly justify-place the items in the grid. + NSInteger usedItemCount = 0; + NSInteger itemIndex = 0; + CGFloat spacing = isHorizontal ? self.section.verticalInterstice : self.section.horizontalInterstice; + // the last row should justify as if it is filled with more (invisible) items so that the whole + // UICollectionView feels more like a grid than a random line of blocks + while (itemIndex < self.itemCount || isLastRow) { + CGFloat nextItemSize; + // first we need to find the size (width/height) of the next item to fit + if (!self.fixedItemSize) { + PSTGridLayoutItem *item = self.items[(NSUInteger)MIN(itemIndex, self.itemCount - 1)]; + nextItemSize = isHorizontal ? item.itemFrame.size.height : item.itemFrame.size.width; + }else { + nextItemSize = isHorizontal ? self.section.itemSize.height : self.section.itemSize.width; + } + + // the first item does not add a separator spacing, + // every one afterwards in the same row will need this spacing constant + if (itemIndex > 0) { + nextItemSize += spacing; + } + + // check to see if we can at least fit an item (+separator if necessary) + if (leftOverSpace < nextItemSize) { + break; + } + + // we need to maintain the leftover space after the maximum amount of items have + // occupied, so we know how to adjust equal spacing among all the items in a row + leftOverSpace -= nextItemSize; + + itemIndex++; + usedItemCount = itemIndex; + } + + // push everything to the right if right-aligning and divide in half for centered + // currently there is no public API supporting this behavior + CGPoint itemOffset = CGPointZero; + if (horizontalAlignment == PSTFlowLayoutHorizontalAlignmentRight) { + itemOffset.x += leftOverSpace; + }else if (horizontalAlignment == PSTFlowLayoutHorizontalAlignmentCentered || + (horizontalAlignment == PSTFlowLayoutHorizontalAlignmentJustify && usedItemCount == 1)) { + // Special case one item row to split leftover space in half + itemOffset.x += leftOverSpace / 2; + } + + // calculate the justified spacing among all items in a row if we are using + // the default PSTFlowLayoutHorizontalAlignmentJustify layout + CGFloat interSpacing = usedItemCount <= 1 ? 0 : leftOverSpace / (CGFloat)(usedItemCount - 1); + + // calculate row frame as union of all items + CGRect frame = CGRectZero; + CGRect itemFrame = (CGRect){.size=self.section.itemSize}; + for (itemIndex = 0; itemIndex < self.itemCount; itemIndex++) { + PSTGridLayoutItem *item = nil; + if (!self.fixedItemSize) { + item = self.items[(NSUInteger)itemIndex]; + itemFrame = [item itemFrame]; + } + // depending on horizontal/vertical for an item size (height/width), + // we add the minimum separator then an equally distributed spacing + // (since our default mode is justify) calculated from the total leftover + // space divided by the number of intervals + if (isHorizontal) { + itemFrame.origin.y = itemOffset.y; + itemOffset.y += itemFrame.size.height + self.section.verticalInterstice; + if (horizontalAlignment == PSTFlowLayoutHorizontalAlignmentJustify) { + itemOffset.y += interSpacing; + } + }else { + itemFrame.origin.x = itemOffset.x; + itemOffset.x += itemFrame.size.width + self.section.horizontalInterstice; + if (horizontalAlignment == PSTFlowLayoutHorizontalAlignmentJustify) { + itemOffset.x += interSpacing; + } + } + item.itemFrame = itemFrame; // might call nil; don't care + [rects addObject:[NSValue valueWithCGRect:itemFrame]]; + frame = CGRectUnion(frame, itemFrame); + } + _rowSize = frame.size; + // _rowFrame = frame; // set externally + _isValid = YES; + } + return rects; +} + +- (void)addItem:(PSTGridLayoutItem *)item { + [_items addObject:item]; + item.rowObject = self; + [self invalidate]; +} + +- (PSTGridLayoutRow *)snapshot { + PSTGridLayoutRow *snapshotRow = [self.class new]; + snapshotRow.section = self.section; + snapshotRow.items = self.items; + snapshotRow.rowSize = self.rowSize; + snapshotRow.rowFrame = self.rowFrame; + snapshotRow.index = self.index; + snapshotRow.complete = self.complete; + snapshotRow.fixedItemSize = self.fixedItemSize; + snapshotRow.itemCount = self.itemCount; + return snapshotRow; +} + +- (PSTGridLayoutRow *)copyFromSection:(PSTGridLayoutSection *)section { + return nil; // ??? +} + +- (NSInteger)itemCount { + if (self.fixedItemSize) { + return _itemCount; + }else { + return (NSInteger)self.items.count; + } +} + +@end diff --git a/ios/Pods/PSTCollectionView/PSTCollectionView/PSTGridLayoutSection.h b/ios/Pods/PSTCollectionView/PSTCollectionView/PSTGridLayoutSection.h new file mode 100644 index 000000000..225f37040 --- /dev/null +++ b/ios/Pods/PSTCollectionView/PSTCollectionView/PSTGridLayoutSection.h @@ -0,0 +1,64 @@ +// +// PSTGridLayoutSection.h +// PSPDFKit +// +// Copyright (c) 2012-2013 Peter Steinberger. All rights reserved. +// + +#import + +@class PSTGridLayoutInfo, PSTGridLayoutRow, PSTGridLayoutItem; + +@interface PSTGridLayoutSection : NSObject + +@property (nonatomic, strong, readonly) NSArray *items; +@property (nonatomic, strong, readonly) NSArray *rows; + +// fast path for equal-size items +@property (nonatomic, assign) BOOL fixedItemSize; +@property (nonatomic, assign) CGSize itemSize; +// depending on fixedItemSize, this either is a _ivar or queries items. +@property (nonatomic, assign) NSInteger itemsCount; + +@property (nonatomic, assign) CGFloat verticalInterstice; +@property (nonatomic, assign) CGFloat horizontalInterstice; +@property (nonatomic, assign) UIEdgeInsets sectionMargins; + +@property (nonatomic, assign) CGRect frame; +@property (nonatomic, assign) CGRect headerFrame; +@property (nonatomic, assign) CGRect footerFrame; +@property (nonatomic, assign) CGFloat headerDimension; +@property (nonatomic, assign) CGFloat footerDimension; +@property (nonatomic, unsafe_unretained) PSTGridLayoutInfo *layoutInfo; +@property (nonatomic, strong) NSDictionary *rowAlignmentOptions; + +@property (nonatomic, assign, readonly) CGFloat otherMargin; +@property (nonatomic, assign, readonly) CGFloat beginMargin; +@property (nonatomic, assign, readonly) CGFloat endMargin; +@property (nonatomic, assign, readonly) CGFloat actualGap; +@property (nonatomic, assign, readonly) CGFloat lastRowBeginMargin; +@property (nonatomic, assign, readonly) CGFloat lastRowEndMargin; +@property (nonatomic, assign, readonly) CGFloat lastRowActualGap; +@property (nonatomic, assign, readonly) BOOL lastRowIncomplete; +@property (nonatomic, assign, readonly) NSInteger itemsByRowCount; +@property (nonatomic, assign, readonly) NSInteger indexOfImcompleteRow; // typo as of iOS6B3 + +//- (PSTGridLayoutSection *)copyFromLayoutInfo:(PSTGridLayoutInfo *)layoutInfo; + +// Faster variant of invalidate/compute +- (void)recomputeFromIndex:(NSInteger)index; + +// Invalidate layout. Destroys rows. +- (void)invalidate; + +// Compute layout. Creates rows. +- (void)computeLayout; + +- (PSTGridLayoutItem *)addItem; + +- (PSTGridLayoutRow *)addRow; + +// Copy snapshot of current object +- (PSTGridLayoutSection *)snapshot; + +@end diff --git a/ios/Pods/PSTCollectionView/PSTCollectionView/PSTGridLayoutSection.m b/ios/Pods/PSTCollectionView/PSTCollectionView/PSTGridLayoutSection.m new file mode 100644 index 000000000..42bef969e --- /dev/null +++ b/ios/Pods/PSTCollectionView/PSTCollectionView/PSTGridLayoutSection.m @@ -0,0 +1,210 @@ +// +// PSTGridLayoutSection.m +// PSPDFKit +// +// Copyright (c) 2012-2013 Peter Steinberger. All rights reserved. +// + +#import "PSTGridLayoutSection.h" +#import "PSTGridLayoutItem.h" +#import "PSTGridLayoutRow.h" +#import "PSTGridLayoutInfo.h" + +@interface PSTGridLayoutSection () { + NSMutableArray *_items; + NSMutableArray *_rows; + BOOL _isValid; +} +@property (nonatomic, strong) NSArray *items; +@property (nonatomic, strong) NSArray *rows; +@property (nonatomic, assign) CGFloat otherMargin; +@property (nonatomic, assign) CGFloat beginMargin; +@property (nonatomic, assign) CGFloat endMargin; +@property (nonatomic, assign) CGFloat actualGap; +@property (nonatomic, assign) CGFloat lastRowBeginMargin; +@property (nonatomic, assign) CGFloat lastRowEndMargin; +@property (nonatomic, assign) CGFloat lastRowActualGap; +@property (nonatomic, assign) BOOL lastRowIncomplete; +@property (nonatomic, assign) NSInteger itemsByRowCount; +@property (nonatomic, assign) NSInteger indexOfImcompleteRow; +@end + +@implementation PSTGridLayoutSection + +/////////////////////////////////////////////////////////////////////////////////////////// +#pragma mark - NSObject + +- (id)init { + if ((self = [super init])) { + _items = [NSMutableArray new]; + _rows = [NSMutableArray new]; + } + return self; +} + +- (NSString *)description { + return [NSString stringWithFormat:@"<%@: %p itemCount:%ld frame:%@ rows:%@>", NSStringFromClass(self.class), self, (long)self.itemsCount, NSStringFromCGRect(self.frame), self.rows]; +} + +/////////////////////////////////////////////////////////////////////////////////////////// +#pragma mark - Public + +- (void)invalidate { + _isValid = NO; + self.rows = [NSMutableArray array]; +} + +- (void)computeLayout { + if (!_isValid) { + NSAssert(self.rows.count == 0, @"No rows shall be at this point."); + + // iterate over all items, turning them into rows. + CGSize sectionSize = CGSizeZero; + NSInteger rowIndex = 0; + NSInteger itemIndex = 0; + NSInteger itemsByRowCount = 0; + CGFloat dimensionLeft = 0; + PSTGridLayoutRow *row = nil; + // get dimension and compensate for section margin + CGFloat headerFooterDimension = self.layoutInfo.dimension; + CGFloat dimension = headerFooterDimension; + + if (self.layoutInfo.horizontal) { + dimension -= self.sectionMargins.top + self.sectionMargins.bottom; + self.headerFrame = CGRectMake(sectionSize.width, 0, self.headerDimension, headerFooterDimension); + sectionSize.width += self.headerDimension + self.sectionMargins.left; + }else { + dimension -= self.sectionMargins.left + self.sectionMargins.right; + self.headerFrame = CGRectMake(0, sectionSize.height, headerFooterDimension, self.headerDimension); + sectionSize.height += self.headerDimension + self.sectionMargins.top; + } + + CGFloat spacing = self.layoutInfo.horizontal ? self.verticalInterstice : self.horizontalInterstice; + + do { + BOOL finishCycle = itemIndex >= self.itemsCount; + // TODO: fast path could even remove row creation and just calculate on the fly + PSTGridLayoutItem *item = nil; + if (!finishCycle) item = self.fixedItemSize ? nil : self.items[(NSUInteger)itemIndex]; + + CGSize itemSize = self.fixedItemSize ? self.itemSize : item.itemFrame.size; + CGFloat itemDimension = self.layoutInfo.horizontal ? itemSize.height : itemSize.width; + // first item of each row does not add spacing + if (itemsByRowCount > 0) itemDimension += spacing; + if (dimensionLeft < itemDimension || finishCycle) { + // finish current row + if (row) { + // compensate last row + self.itemsByRowCount = fmax(itemsByRowCount, self.itemsByRowCount); + row.itemCount = itemsByRowCount; + + // if current row is done but there are still items left, increase the incomplete row counter + if (!finishCycle) self.indexOfImcompleteRow = rowIndex; + + [row layoutRow]; + + if (self.layoutInfo.horizontal) { + row.rowFrame = CGRectMake(sectionSize.width, self.sectionMargins.top, row.rowSize.width, row.rowSize.height); + sectionSize.height = MAX(row.rowSize.height, sectionSize.height); + sectionSize.width += row.rowSize.width + (finishCycle ? 0 : self.horizontalInterstice); + }else { + row.rowFrame = CGRectMake(self.sectionMargins.left, sectionSize.height, row.rowSize.width, row.rowSize.height); + sectionSize.height += row.rowSize.height + (finishCycle ? 0 : self.verticalInterstice); + sectionSize.width = MAX(row.rowSize.width, sectionSize.width); + } + } + // add new rows until the section is fully laid out + if (!finishCycle) { + // create new row + row.complete = YES; // finish up current row + row = [self addRow]; + row.fixedItemSize = self.fixedItemSize; + row.index = rowIndex; + self.indexOfImcompleteRow = rowIndex; + rowIndex++; + // convert an item from previous row to current, remove spacing for first item + if (itemsByRowCount > 0) itemDimension -= spacing; + dimensionLeft = dimension - itemDimension; + itemsByRowCount = 0; + } + }else { + dimensionLeft -= itemDimension; + } + + // add item on slow path + if (item) [row addItem:item]; + + itemIndex++; + itemsByRowCount++; + } while (itemIndex <= self.itemsCount); // cycle once more to finish last row + + if (self.layoutInfo.horizontal) { + sectionSize.width += self.sectionMargins.right; + self.footerFrame = CGRectMake(sectionSize.width, 0, self.footerDimension, headerFooterDimension); + sectionSize.width += self.footerDimension; + }else { + sectionSize.height += self.sectionMargins.bottom; + self.footerFrame = CGRectMake(0, sectionSize.height, headerFooterDimension, self.footerDimension); + sectionSize.height += self.footerDimension; + } + + _frame = CGRectMake(0, 0, sectionSize.width, sectionSize.height); + _isValid = YES; + } +} + +- (void)recomputeFromIndex:(NSInteger)index { + // TODO: use index. + [self invalidate]; + [self computeLayout]; +} + +- (PSTGridLayoutItem *)addItem { + PSTGridLayoutItem *item = [PSTGridLayoutItem new]; + item.section = self; + [_items addObject:item]; + return item; +} + +- (PSTGridLayoutRow *)addRow { + PSTGridLayoutRow *row = [PSTGridLayoutRow new]; + row.section = self; + [_rows addObject:row]; + return row; +} + +- (PSTGridLayoutSection *)snapshot { + PSTGridLayoutSection *snapshotSection = [PSTGridLayoutSection new]; + snapshotSection.items = [self.items copy]; + snapshotSection.rows = [self.items copy]; + snapshotSection.verticalInterstice = self.verticalInterstice; + snapshotSection.horizontalInterstice = self.horizontalInterstice; + snapshotSection.sectionMargins = self.sectionMargins; + snapshotSection.frame = self.frame; + snapshotSection.headerFrame = self.headerFrame; + snapshotSection.footerFrame = self.footerFrame; + snapshotSection.headerDimension = self.headerDimension; + snapshotSection.footerDimension = self.footerDimension; + snapshotSection.layoutInfo = self.layoutInfo; + snapshotSection.rowAlignmentOptions = self.rowAlignmentOptions; + snapshotSection.fixedItemSize = self.fixedItemSize; + snapshotSection.itemSize = self.itemSize; + snapshotSection.itemsCount = self.itemsCount; + snapshotSection.otherMargin = self.otherMargin; + snapshotSection.beginMargin = self.beginMargin; + snapshotSection.endMargin = self.endMargin; + snapshotSection.actualGap = self.actualGap; + snapshotSection.lastRowBeginMargin = self.lastRowBeginMargin; + snapshotSection.lastRowEndMargin = self.lastRowEndMargin; + snapshotSection.lastRowActualGap = self.lastRowActualGap; + snapshotSection.lastRowIncomplete = self.lastRowIncomplete; + snapshotSection.itemsByRowCount = self.itemsByRowCount; + snapshotSection.indexOfImcompleteRow = self.indexOfImcompleteRow; + return snapshotSection; +} + +- (NSInteger)itemsCount { + return self.fixedItemSize ? _itemsCount : (NSInteger)self.items.count; +} + +@end diff --git a/ios/Pods/PSTCollectionView/README.md b/ios/Pods/PSTCollectionView/README.md new file mode 100644 index 000000000..21a071fd5 --- /dev/null +++ b/ios/Pods/PSTCollectionView/README.md @@ -0,0 +1,57 @@ +PSTCollectionView +================= + +UPDATE: I'm no longer using PSTCollectionView in any project, but will still accept pull requests for improvements. + +Open Source, 100% API compatible replacement of UICollectionView for iOS4.3+ + +**You want to use UICollectionView, but still need to support older versions of iOS? Then you're gonna love this project.** +Originally I wrote it for [PSPDFKit](http://PSPDFKit.com), my iOS PDF framework that supports text selection and annotations, but this project seemed way too useful for others to keep it for myself :) + +**If you want to have PSTCollectionView on iOS4.3/5.x and UICollectionView on iOS6, use PSUICollectionView (basically add PS on any UICollectionView* class to get auto-support for older iOS versions)** +If you always want to use PSTCollectionView, use PSTCollectionView as class names. (replace the UI with PST) + +## Current State + +Most features work, including the flow layout with fixed or dynamic cell sizes and supplementary views. If you're not doing something fancy, it should just work. +PSTCollectionView is also internally designed very closely to UICollectionView and thus a great study if you're wondering how UICollectionView works. See [HowTo](HowTo.md) for helpful details. + +## How can I help? + +The best way is if you're already using UICollectionView somewhere. Add PSTCollectionView and try it on iOS4/5. Check if everything works, fix bugs until the result matches 1:1 with iOS6. You can also just pick an issue fron the Issue Tracker and start working there. + +Or start playing around with one of the WWDC examples and try to make them work with PSTCollectionView. Most of them already do, but just not as perfect. + +You could also write a Pinterest-style layout manager. Can't be that hard. + +## Animations + +Thanks to Sergey Gavrilyuk ([@octogavrix](https://twitter.com/octogavrix)), animations are supported. It's not perfect yet (see LineExample), but it's a great start. + +## ARC + +PSTCollectionView works with Xcode 4.5.2+ and ARC. + +## Dependencies + +PSTCollectionView needs the QuartzCore.framework. + +## Interoperability + +Another goal (at least super useful for debugging) is interoperability between UI/PST classes: + +``` objective-c +UICollectionViewFlowLayout *flowLayout = [UICollectionViewFlowLayout new]; +PSTCollectionView *collectionView = [[PSTCollectionView alloc] initWithFrame:self.view.bounds collectionViewLayout:(PSTCollectionViewFlowLayout *)flowLayout]; +``` + +(*) Note that for some methods we can't use the _ underscore variants or we risk to get a false-positive on private API use. I've added some runtime hacks to dynamcially add block forwarders for those cases (mainly for UI/PST interoperability) + +## Creator + +[Peter Steinberger](http://petersteinberger.com) ([@steipete](https://twitter.com/steipete)) +and lots of others! See [Contributors](https://github.com/steipete/PSTCollectionView/graphs/contributors) for a graph. Thanks everyone! + +## License + +PSTCollectionView is available under the MIT license. See the LICENSE file for more info. diff --git a/ios/Pods/Pods.xcodeproj/project.pbxproj b/ios/Pods/Pods.xcodeproj/project.pbxproj new file mode 100644 index 000000000..212d85091 --- /dev/null +++ b/ios/Pods/Pods.xcodeproj/project.pbxproj @@ -0,0 +1,10815 @@ + + + + + archiveVersion + 1 + classes + + objectVersion + 46 + objects + + 00A8D8FAD20BA69D8DD8ED92 + + fileRef + 8D9482B6C87566E1994EBCA2 + isa + PBXBuildFile + settings + + COMPILER_FLAGS + -DOS_MACOSX -DLEVELDB_PLATFORM_POSIX -fno-objc-arc + + + 00FA19206218DE6083F024EC + + isa + PBXTargetDependency + name + Pods-SDWebImage + target + 436B9F8EBC9F4E16A3FE4A8E + targetProxy + E84ABC7F3A9EEE8D1008FC22 + + 0126B4E3DC7E900E873706C2 + + buildConfigurations + + 5DA409F5198AB2BD27F12AC6 + 47A78CC7A9590DAD7A45E2D4 + + defaultConfigurationIsVisible + 0 + defaultConfigurationName + Release + isa + XCConfigurationList + + 020FA5C0FCF0FCD206BC1A64 + + baseConfigurationReference + CC57503D74577BEA95AD137D + buildSettings + + ALWAYS_SEARCH_USER_PATHS + NO + COPY_PHASE_STRIP + NO + DSTROOT + /tmp/xcodeproj.dst + GCC_DYNAMIC_NO_PIC + NO + GCC_OPTIMIZATION_LEVEL + 0 + GCC_PRECOMPILE_PREFIX_HEADER + YES + GCC_PREFIX_HEADER + Target Support Files/Pods-AFNetworking/Pods-AFNetworking-prefix.pch + GCC_PREPROCESSOR_DEFINITIONS + + DEBUG=1 + $(inherited) + + GCC_SYMBOLS_PRIVATE_EXTERN + NO + INSTALL_PATH + $(BUILT_PRODUCTS_DIR) + IPHONEOS_DEPLOYMENT_TARGET + 6.0 + OTHER_LDFLAGS + + OTHER_LIBTOOLFLAGS + + PRODUCT_NAME + $(TARGET_NAME) + PUBLIC_HEADERS_FOLDER_PATH + $(TARGET_NAME) + SDKROOT + iphoneos + SKIP_INSTALL + YES + + isa + XCBuildConfiguration + name + Debug + + 031A6739DE63A8B5C23C2C2A + + includeInIndex + 1 + isa + PBXFileReference + lastKnownFileType + sourcecode.c.h + name + SCLAlertViewStyleKit.h + path + SCLAlertView/SCLAlertViewStyleKit.h + sourceTree + <group> + + 035A00D1283FE86740DD4328 + + fileRef + C856BC052BAA0CD252EC9990 + isa + PBXBuildFile + + 041E19F1C2C9563727945FC2 + + isa + PBXFileReference + lastKnownFileType + wrapper.framework + name + MessageUI.framework + path + Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS7.1.sdk/System/Library/Frameworks/MessageUI.framework + sourceTree + DEVELOPER_DIR + + 0474ED89B2559A9B9503ACFA + + includeInIndex + 1 + isa + PBXFileReference + lastKnownFileType + sourcecode.c.h + name + MutableExtensionRegistry.h + path + src/runtime/Classes/MutableExtensionRegistry.h + sourceTree + <group> + + 0490DD2DD8E984B4CEC44B79 + + fileRef + 925166FE3DABD3B90304140A + isa + PBXBuildFile + + 04A48876E1246EDB856C82D7 + + fileRef + E029A3D104E6F50FE9CA4244 + isa + PBXBuildFile + settings + + COMPILER_FLAGS + -DOS_MACOSX -DLEVELDB_PLATFORM_POSIX -fno-objc-arc + + + 04A67BC2BEF06219139ED97C + + buildConfigurations + + 650B231D482769904A477885 + 1C461BD905CDB84EDE5FD9FF + + defaultConfigurationIsVisible + 0 + defaultConfigurationName + Release + isa + XCConfigurationList + + 04C2C3EE7F98B8E4F94ACA04 + + containerPortal + 32F15B3A8A99ACC37FCE0E4A + isa + PBXContainerItemProxy + proxyType + 1 + remoteGlobalIDString + 6360D6708B351012B4113963 + remoteInfo + Pods-HPGrowingTextView + + 04D48DB2E059E48F88B66E2A + + includeInIndex + 1 + isa + PBXFileReference + lastKnownFileType + sourcecode.c.h + name + PSTGridLayoutRow.h + path + PSTCollectionView/PSTGridLayoutRow.h + sourceTree + <group> + + 04D5F8B792321841AE66C196 + + includeInIndex + 1 + isa + PBXFileReference + lastKnownFileType + sourcecode.c.h + name + SDWebImageDecoder.h + path + SDWebImage/SDWebImageDecoder.h + sourceTree + <group> + + 05EB2194F0C07155D1BD9FCA + + explicitFileType + archive.ar + includeInIndex + 0 + isa + PBXFileReference + path + libPods-PSTCollectionView.a + sourceTree + BUILT_PRODUCTS_DIR + + 06CBE569D706D994B4682D20 + + includeInIndex + 1 + isa + PBXFileReference + name + db_impl.cc + path + db/db_impl.cc + sourceTree + <group> + + 06D5E5B356DDEE0016B2DF8B + + includeInIndex + 1 + isa + PBXFileReference + name + write_batch.cc + path + db/write_batch.cc + sourceTree + <group> + + 06EAABF561F969D7EDC12021 + + includeInIndex + 1 + isa + PBXFileReference + lastKnownFileType + sourcecode.c.objc + name + WireFormat.m + path + src/runtime/Classes/WireFormat.m + sourceTree + <group> + + 0709ACAA6644FD6246C29B7E + + children + + AF8CEE98DD4589CB45393A4F + 134F09CA937A8239AF65247E + + isa + PBXGroup + name + Reachability + sourceTree + <group> + + 07913D913A559DBEC47E490D + + fileRef + 98936A7C58EBE6A2962C4607 + isa + PBXBuildFile + + 083933610D4312DE9AB65E85 + + includeInIndex + 1 + isa + PBXFileReference + lastKnownFileType + text.xcconfig + path + Pods-HPGrowingTextView-Private.xcconfig + sourceTree + <group> + + 0920E0BD1922A66BE990F164 + + children + + 3EC4DCED927DA0E602EDB8F1 + E9322072BD227F89D465C3E3 + DD2B27A1FD088D6827076FC6 + 0709ACAA6644FD6246C29B7E + 2DBE80325A693315C948FC80 + A31DBF5CE8480E4CAC587BED + 56551ACFEAD4E92EB9BDEDA9 + 691AD669B45CD24586817605 + + isa + PBXGroup + name + AFNetworking + path + AFNetworking + sourceTree + <group> + + 09A20CC0DB72732970F408DF + + buildConfigurationList + 48DFB8216AF86E5ED4CF577B + buildPhases + + E9BEDCE9400DA48B9D83EA13 + C18E37B41AA810A4ACA38F0A + 7E14A75597ED49D4E36A6726 + + buildRules + + dependencies + + isa + PBXNativeTarget + name + Pods-leveldb-library + productName + Pods-leveldb-library + productReference + C7D48636C10C7744165FB31A + productType + com.apple.product-type.library.static + + 09AF0DA308729036EA8F80DF + + includeInIndex + 1 + isa + PBXFileReference + lastKnownFileType + sourcecode.c.objc + name + FMDatabasePool.m + path + src/fmdb/FMDatabasePool.m + sourceTree + <group> + + 0A12B2B6017AC4319D9A8652 + + fileRef + 06CBE569D706D994B4682D20 + isa + PBXBuildFile + settings + + COMPILER_FLAGS + -DOS_MACOSX -DLEVELDB_PLATFORM_POSIX -fno-objc-arc + + + 0A2D601202909065405557C7 + + buildActionMask + 2147483647 + files + + B663D4B8172F651C053C3449 + + isa + PBXFrameworksBuildPhase + runOnlyForDeploymentPostprocessing + 0 + + 0B2F9B6195920ACCC9915767 + + includeInIndex + 1 + isa + PBXFileReference + lastKnownFileType + sourcecode.c.h + path + Pods-AFNetworking-prefix.pch + sourceTree + <group> + + 0B75A723EBE7AEEDCD821F78 + + includeInIndex + 1 + isa + PBXFileReference + name + dbformat.cc + path + db/dbformat.cc + sourceTree + <group> + + 0C29014DB4725172127EB83B + + fileRef + F66AD7C4F4978D0D0BE1F36F + isa + PBXBuildFile + + 0C94A4F4543A58C11920B4B8 + + isa + PBXFileReference + lastKnownFileType + wrapper.framework + name + Security.framework + path + Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS7.1.sdk/System/Library/Frameworks/Security.framework + sourceTree + DEVELOPER_DIR + + 0C99167FA1FE4618CB7A1E96 + + includeInIndex + 1 + isa + PBXFileReference + lastKnownFileType + sourcecode.c.h + name + FMDatabasePool.h + path + src/fmdb/FMDatabasePool.h + sourceTree + <group> + + 0CA64C2CD908BCD291ABD244 + + buildConfigurations + + 26E94E31D25EB6E6B8D3514F + 303988E1D59A2BCC860889D7 + + defaultConfigurationIsVisible + 0 + defaultConfigurationName + Release + isa + XCConfigurationList + + 0CA8A045EE47A2291C7304E2 + + fileRef + AB66D5880E96270410AF2EA5 + isa + PBXBuildFile + settings + + COMPILER_FLAGS + -DOS_OBJECT_USE_OBJC=0 + + + 0CE348E3F868EB1254F26D08 + + baseConfigurationReference + EEC82B355AAA5C5E29EE7833 + buildSettings + + ALWAYS_SEARCH_USER_PATHS + NO + COPY_PHASE_STRIP + NO + DSTROOT + /tmp/xcodeproj.dst + GCC_DYNAMIC_NO_PIC + NO + GCC_OPTIMIZATION_LEVEL + 0 + GCC_PRECOMPILE_PREFIX_HEADER + YES + GCC_PREFIX_HEADER + Target Support Files/Pods-leveldb-library/Pods-leveldb-library-prefix.pch + GCC_PREPROCESSOR_DEFINITIONS + + DEBUG=1 + $(inherited) + + GCC_SYMBOLS_PRIVATE_EXTERN + NO + INSTALL_PATH + $(BUILT_PRODUCTS_DIR) + IPHONEOS_DEPLOYMENT_TARGET + 6.0 + OTHER_LDFLAGS + + OTHER_LIBTOOLFLAGS + + PRODUCT_NAME + $(TARGET_NAME) + PUBLIC_HEADERS_FOLDER_PATH + $(TARGET_NAME) + SDKROOT + iphoneos + SKIP_INSTALL + YES + + isa + XCBuildConfiguration + name + Debug + + 0D006504014BCFB940691563 + + fileRef + 6871CC4088D36CC9FA1A68A2 + isa + PBXBuildFile + + 0D2D1F778605EB3B977ABD85 + + fileRef + AE21AD5206DD8941D3862813 + isa + PBXBuildFile + + 0D44E9FA3B915143671C7BB7 + + includeInIndex + 1 + isa + PBXFileReference + lastKnownFileType + sourcecode.c.objc + name + AFSecurityPolicy.m + path + AFNetworking/AFSecurityPolicy.m + sourceTree + <group> + + 0DE31D4A559CEA4BAAEB43FA + + includeInIndex + 1 + isa + PBXFileReference + lastKnownFileType + sourcecode.c.h + name + AFURLConnectionOperation.h + path + AFNetworking/AFURLConnectionOperation.h + sourceTree + <group> + + 0E700B59905A929816067FBE + + includeInIndex + 1 + isa + PBXFileReference + lastKnownFileType + sourcecode.c.h + name + NSIndexPath+PSTCollectionViewAdditions.h + path + PSTCollectionView/NSIndexPath+PSTCollectionViewAdditions.h + sourceTree + <group> + + 0EC0B78B7B9E0258E437799F + + fileRef + 3752BB0CE2C29682AB862649 + isa + PBXBuildFile + + 0EDA4C917EBBC882035EC388 + + includeInIndex + 1 + isa + PBXFileReference + lastKnownFileType + text.xcconfig + path + Pods-AFNetworking.xcconfig + sourceTree + <group> + + 0F3AE90A79AA3D752538CB37 + + fileRef + 94D826954323FB898ADC26D0 + isa + PBXBuildFile + + 0F568728BB516A65EF729E07 + + fileRef + DD04C9A6E193790AB5702BC1 + isa + PBXBuildFile + + 0F8C1A3C28941B880470AD90 + + baseConfigurationReference + 6FF528D39989A2C35688A3DA + buildSettings + + ALWAYS_SEARCH_USER_PATHS + NO + COPY_PHASE_STRIP + YES + DSTROOT + /tmp/xcodeproj.dst + GCC_PRECOMPILE_PREFIX_HEADER + YES + GCC_PREFIX_HEADER + Target Support Files/Pods-PSTCollectionView/Pods-PSTCollectionView-prefix.pch + INSTALL_PATH + $(BUILT_PRODUCTS_DIR) + IPHONEOS_DEPLOYMENT_TARGET + 6.0 + OTHER_CFLAGS + + -DNS_BLOCK_ASSERTIONS=1 + $(inherited) + + OTHER_CPLUSPLUSFLAGS + + -DNS_BLOCK_ASSERTIONS=1 + $(inherited) + + OTHER_LDFLAGS + + OTHER_LIBTOOLFLAGS + + PRODUCT_NAME + $(TARGET_NAME) + PUBLIC_HEADERS_FOLDER_PATH + $(TARGET_NAME) + SDKROOT + iphoneos + SKIP_INSTALL + YES + VALIDATE_PRODUCT + YES + + isa + XCBuildConfiguration + name + Release + + 0F997A972D99D16202B345E1 + + includeInIndex + 1 + isa + PBXFileReference + lastKnownFileType + sourcecode.c.objc + name + MWTapDetectingImageView.m + path + MWPhotoBrowser/Classes/MWTapDetectingImageView.m + sourceTree + <group> + + 10184A70DD0CFEA6D44A466D + + includeInIndex + 1 + isa + PBXFileReference + lastKnownFileType + sourcecode.c.objc + name + ExtendableMessageBuilder.m + path + src/runtime/Classes/ExtendableMessageBuilder.m + sourceTree + <group> + + 117DC2290330919560CE4621 + + includeInIndex + 1 + isa + PBXFileReference + lastKnownFileType + sourcecode.c.h + name + MWTapDetectingView.h + path + MWPhotoBrowser/Classes/MWTapDetectingView.h + sourceTree + <group> + + 11ACB1BBA37F7EFFA5CD0B1C + + fileRef + 994FEDAB754303A9320036EA + isa + PBXBuildFile + settings + + COMPILER_FLAGS + -DOS_MACOSX -DLEVELDB_PLATFORM_POSIX -fno-objc-arc + + + 11D4CFF8D6847996107DE84C + + includeInIndex + 1 + isa + PBXFileReference + name + db_bench.cc + path + db/db_bench.cc + sourceTree + <group> + + 11E28228F469927B0D4BE3BB + + fileRef + E0A7964EA43A5E3E6D880E44 + isa + PBXBuildFile + + 12651ADB50AA76461BF5272A + + includeInIndex + 1 + isa + PBXFileReference + lastKnownFileType + sourcecode.c.objc + name + UIRefreshControl+AFNetworking.m + path + UIKit+AFNetworking/UIRefreshControl+AFNetworking.m + sourceTree + <group> + + 12B2407E3501674C2B74C217 + + includeInIndex + 1 + isa + PBXFileReference + lastKnownFileType + sourcecode.c.objc + name + SDWebImageManager.m + path + SDWebImage/SDWebImageManager.m + sourceTree + <group> + + 1328F74BB611C8C0974F01DF + + buildActionMask + 2147483647 + files + + EA386BB4F08F849B26C99F4E + 36948A2B0B64D5282D8D5BEF + 66A9540760E965F58EA271D9 + + isa + PBXSourcesBuildPhase + runOnlyForDeploymentPostprocessing + 0 + + 133A25A0D319725FEC1884B0 + + buildConfigurationList + 507165A17F2C83D61F165C39 + buildPhases + + 2322499EB4A5BA595F12AC47 + A95C977833BC75ACC2FBDBE4 + CD2B0C3081ECC8CAF0500549 + + buildRules + + dependencies + + AB8A384B09297D3F23928914 + DF777A3A37029DF979CD57FD + 22AD8B4BF88436E905D77EA8 + B5382AD412DDA1EF83EC3113 + + isa + PBXNativeTarget + name + Pods-MWPhotoBrowser + productName + Pods-MWPhotoBrowser + productReference + 58BAFF5AE5BD38325DEB1084 + productType + com.apple.product-type.library.static + + 134B70A7A25D73B28E189003 + + fileRef + 0B75A723EBE7AEEDCD821F78 + isa + PBXBuildFile + settings + + COMPILER_FLAGS + -DOS_MACOSX -DLEVELDB_PLATFORM_POSIX -fno-objc-arc + + + 134F09CA937A8239AF65247E + + includeInIndex + 1 + isa + PBXFileReference + lastKnownFileType + sourcecode.c.objc + name + AFNetworkReachabilityManager.m + path + AFNetworking/AFNetworkReachabilityManager.m + sourceTree + <group> + + 1452623912D26097FEBC0975 + + children + + 6B695B4DF68F0B3D11B4F5E5 + C445ADD65DE09EA6923A57DB + 355987259D3D4D8C6ED844AC + 2653ADEFD52BB567F18FE523 + + isa + PBXGroup + name + Support Files + path + ../Target Support Files/Pods-ProtocolBuffers + sourceTree + <group> + + 14595BD59DE8382D09CB3EC8 + + fileRef + 80C3C93A0CCA916B9A547AC0 + isa + PBXBuildFile + settings + + COMPILER_FLAGS + -DOS_MACOSX -DLEVELDB_PLATFORM_POSIX -fno-objc-arc + + + 14B377FB1843736348EDDEA5 + + includeInIndex + 1 + isa + PBXFileReference + lastKnownFileType + sourcecode.c.h + name + UnknownFieldSet.h + path + src/runtime/Classes/UnknownFieldSet.h + sourceTree + <group> + + 153A0E397CF589CBCA9C1700 + + containerPortal + 32F15B3A8A99ACC37FCE0E4A + isa + PBXContainerItemProxy + proxyType + 1 + remoteGlobalIDString + 45FFB846AD2C35316261CE26 + remoteInfo + Pods-MBProgressHUD + + 154045BA6367553FBB8C1A76 + + includeInIndex + 1 + isa + PBXFileReference + lastKnownFileType + sourcecode.c.h + name + UIAlertView+AFNetworking.h + path + UIKit+AFNetworking/UIAlertView+AFNetworking.h + sourceTree + <group> + + 16944116D1D304953B4BFF5A + + fileRef + 924B19B4B3E5C8F127FCFA65 + isa + PBXBuildFile + + 16AF482DD25DFC1DBE337AFB + + fileRef + 916DBA74F33694108E4C10F1 + isa + PBXBuildFile + + 16B22AE9AA5F6640B831C45A + + fileRef + 3CC6468951DC779062F5BF45 + isa + PBXBuildFile + + 16EE467E350A17008126F601 + + fileRef + 6A48B1D11FDDAF84A874CC7B + isa + PBXBuildFile + + 1733531BD18C8422A71FCB17 + + includeInIndex + 1 + isa + PBXFileReference + lastKnownFileType + sourcecode.c.objc + name + UIView+WebCacheOperation.m + path + SDWebImage/UIView+WebCacheOperation.m + sourceTree + <group> + + 17793F1AA6528675492C3B3B + + includeInIndex + 1 + isa + PBXFileReference + lastKnownFileType + sourcecode.c.h + path + Pods-FMDB-prefix.pch + sourceTree + <group> + + 17E406215ACE33340EE78A51 + + includeInIndex + 1 + isa + PBXFileReference + lastKnownFileType + sourcecode.c.h + name + ExtensionRegistry.h + path + src/runtime/Classes/ExtensionRegistry.h + sourceTree + <group> + + 1804BCFDD93BEF23F93BE360 + + includeInIndex + 1 + isa + PBXFileReference + lastKnownFileType + sourcecode.c.h + name + cache.h + path + include/leveldb/cache.h + sourceTree + <group> + + 1896F26A3AE7E0F78B862106 + + fileRef + 6D956C6D6E6AF865A3CE2D49 + isa + PBXBuildFile + + 189A7D5B9253201FCF76E504 + + includeInIndex + 1 + isa + PBXFileReference + lastKnownFileType + sourcecode.c.h + name + GeneratedMessage.h + path + src/runtime/Classes/GeneratedMessage.h + sourceTree + <group> + + 18A124FFB8D7508B0D333A73 + + containerPortal + 32F15B3A8A99ACC37FCE0E4A + isa + PBXContainerItemProxy + proxyType + 1 + remoteGlobalIDString + 81C7539C5773E295433603AB + remoteInfo + Pods-FMDB + + 1B28AAF75F073830F0B0FFEB + + includeInIndex + 1 + isa + PBXFileReference + name + comparator.cc + path + util/comparator.cc + sourceTree + <group> + + 1BAFF8B33D566F451E7265DC + + fileRef + 6605C580797700F2CB5BD172 + isa + PBXBuildFile + + 1BE238282F474E10B9E55FAA + + fileRef + 661264FDE0337383E10C08BC + isa + PBXBuildFile + settings + + COMPILER_FLAGS + -DOS_MACOSX -DLEVELDB_PLATFORM_POSIX -fno-objc-arc + + + 1BFC6BE71F25532EC7D1D612 + + includeInIndex + 1 + isa + PBXFileReference + lastKnownFileType + text.xcconfig + path + Pods-HPGrowingTextView.xcconfig + sourceTree + <group> + + 1C461BD905CDB84EDE5FD9FF + + baseConfigurationReference + 8AAB857E284C046BD52EDCBC + buildSettings + + ALWAYS_SEARCH_USER_PATHS + NO + COPY_PHASE_STRIP + YES + DSTROOT + /tmp/xcodeproj.dst + GCC_PRECOMPILE_PREFIX_HEADER + YES + GCC_PREFIX_HEADER + Target Support Files/Pods-SCLAlertView-Objective-C/Pods-SCLAlertView-Objective-C-prefix.pch + INSTALL_PATH + $(BUILT_PRODUCTS_DIR) + IPHONEOS_DEPLOYMENT_TARGET + 6.0 + OTHER_CFLAGS + + -DNS_BLOCK_ASSERTIONS=1 + $(inherited) + + OTHER_CPLUSPLUSFLAGS + + -DNS_BLOCK_ASSERTIONS=1 + $(inherited) + + OTHER_LDFLAGS + + OTHER_LIBTOOLFLAGS + + PRODUCT_NAME + $(TARGET_NAME) + PUBLIC_HEADERS_FOLDER_PATH + $(TARGET_NAME) + SDKROOT + iphoneos + SKIP_INSTALL + YES + VALIDATE_PRODUCT + YES + + isa + XCBuildConfiguration + name + Release + + 1C51BF66DDDA9E648D4FB284 + + includeInIndex + 1 + isa + PBXFileReference + lastKnownFileType + text.script.sh + path + Pods-resources.sh + sourceTree + <group> + + 1D27CE8C4A280C391AE28ED3 + + fileRef + EECD5A9A6925D5D18354177A + isa + PBXBuildFile + + 1D954353E6F68F9112161DBF + + includeInIndex + 1 + isa + PBXFileReference + lastKnownFileType + sourcecode.c.objc + name + SDWebImagePrefetcher.m + path + SDWebImage/SDWebImagePrefetcher.m + sourceTree + <group> + + 1EB5EED28F13B582578C046D + + fileRef + 433DBE8012005DACD07D65EF + isa + PBXBuildFile + + 1EBF46F409D0C38D6E0B98AA + + fileRef + B2EBBC364774B0291BF6794F + isa + PBXBuildFile + + 1EC60600D79AE4EBA2E2029C + + fileRef + 11D4CFF8D6847996107DE84C + isa + PBXBuildFile + settings + + COMPILER_FLAGS + -DOS_MACOSX -DLEVELDB_PLATFORM_POSIX -fno-objc-arc + + + 1ECDBC93F6B81E068C62FC47 + + includeInIndex + 1 + isa + PBXFileReference + lastKnownFileType + sourcecode.c.h + name + UIProgressView+AFNetworking.h + path + UIKit+AFNetworking/UIProgressView+AFNetworking.h + sourceTree + <group> + + 1EE8225012F97A9C456D1106 + + fileRef + BD9755826D5D690B487574E4 + isa + PBXBuildFile + + 1F9551963550E6B397CC9405 + + includeInIndex + 1 + isa + PBXFileReference + lastKnownFileType + sourcecode.c.objc + name + FMResultSet.m + path + src/fmdb/FMResultSet.m + sourceTree + <group> + + 203F5506F66F6388F3636144 + + includeInIndex + 1 + isa + PBXFileReference + name + arena.cc + path + util/arena.cc + sourceTree + <group> + + 207EDE5354467A76ACAA0F46 + + fileRef + 1804BCFDD93BEF23F93BE360 + isa + PBXBuildFile + + 2081D35AE4041B5506F9B8AD + + includeInIndex + 1 + isa + PBXFileReference + lastKnownFileType + sourcecode.c.h + name + WireFormat.h + path + src/runtime/Classes/WireFormat.h + sourceTree + <group> + + 20C4E0FBFE52EFAE82DAB4E0 + + children + + 2CFF4C9145609587718F8584 + F2E6DEF05A16FEF8DD6E3A10 + ADD4CBB75BD43CD983713F7F + + isa + PBXGroup + name + MBProgressHUD + path + MBProgressHUD + sourceTree + <group> + + 20EEC719BB609EF7E68B081E + + includeInIndex + 1 + isa + PBXFileReference + lastKnownFileType + sourcecode.c.objc + name + AFURLSessionManager.m + path + AFNetworking/AFURLSessionManager.m + sourceTree + <group> + + 2112856F5B4BF40635226F25 + + fileRef + 04D48DB2E059E48F88B66E2A + isa + PBXBuildFile + + 2127A5794249D556C258884E + + fileRef + EE21F90792467DB80ECA97BC + isa + PBXBuildFile + settings + + COMPILER_FLAGS + -DOS_OBJECT_USE_OBJC=0 + + + 21F53906ABFA0F22EF18210B + + includeInIndex + 1 + isa + PBXFileReference + lastKnownFileType + sourcecode.c.h + name + FMResultSet.h + path + src/fmdb/FMResultSet.h + sourceTree + <group> + + 2219374AB1AA9A28B514A4DB + + includeInIndex + 1 + isa + PBXFileReference + lastKnownFileType + sourcecode.c.h + name + SDWebImageDownloader.h + path + SDWebImage/SDWebImageDownloader.h + sourceTree + <group> + + 223837A87FA5DCB75ED915CA + + isa + PBXFileReference + lastKnownFileType + wrapper.framework + name + Foundation.framework + path + Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS7.1.sdk/System/Library/Frameworks/Foundation.framework + sourceTree + DEVELOPER_DIR + + 22669C9937AD12B16D26BBD6 + + fileRef + 12B2407E3501674C2B74C217 + isa + PBXBuildFile + settings + + COMPILER_FLAGS + -DOS_OBJECT_USE_OBJC=0 + + + 22AD8B4BF88436E905D77EA8 + + isa + PBXTargetDependency + name + Pods-PSTCollectionView + target + B2CC9370F3764EE84221A3DA + targetProxy + 22F8B0BDB70200FAC60B9872 + + 22B26915D88B0A5F805CD9C3 + + includeInIndex + 1 + isa + PBXFileReference + lastKnownFileType + sourcecode.c.h + name + MWZoomingScrollView.h + path + MWPhotoBrowser/Classes/MWZoomingScrollView.h + sourceTree + <group> + + 22B424E560CB2A89AE0EB255 + + includeInIndex + 1 + isa + PBXFileReference + lastKnownFileType + sourcecode.c.objc + name + CodedInputStream.m + path + src/runtime/Classes/CodedInputStream.m + sourceTree + <group> + + 22F8B0BDB70200FAC60B9872 + + containerPortal + 32F15B3A8A99ACC37FCE0E4A + isa + PBXContainerItemProxy + proxyType + 1 + remoteGlobalIDString + B2CC9370F3764EE84221A3DA + remoteInfo + Pods-PSTCollectionView + + 2322499EB4A5BA595F12AC47 + + buildActionMask + 2147483647 + files + + 78132618E256BD59BCFB2283 + E085885AEC926627A0118690 + 425D1AA4CA667230BD03B228 + 52FE5DBECBFB296EF121C288 + 8AE8F74A62F028021D6AB42E + C84E0A20800C38A11B9565DE + CF0C0551F1B6D22C79F97295 + 97B7F767A50D4ABB1CCC4A9F + EEC7584373E7F6F10FF13B80 + + isa + PBXSourcesBuildPhase + runOnlyForDeploymentPostprocessing + 0 + + 248D08C04B2C14981063CD8E + + includeInIndex + 1 + isa + PBXFileReference + lastKnownFileType + text.xcconfig + path + Pods-PSTCollectionView.xcconfig + sourceTree + <group> + + 24BEB24D94467F828A8EF0A9 + + children + + AE21AD5206DD8941D3862813 + BC5A1DD8838051712DD1B148 + 6672134C5065CC7C0DF1C7C7 + 608ED333FCA41508710034C1 + FB4AE529C15E6A86153C1C3D + 0C99167FA1FE4618CB7A1E96 + 09AF0DA308729036EA8F80DF + 80DB483BB0FCA8DFFF623FBC + 7EFCC14C3250B082B9F7133B + 21F53906ABFA0F22EF18210B + 1F9551963550E6B397CC9405 + + isa + PBXGroup + name + common + sourceTree + <group> + + 2500C99B3FB11290FFFD347B + + includeInIndex + 1 + isa + PBXFileReference + lastKnownFileType + sourcecode.c.h + name + AFURLResponseSerialization.h + path + AFNetworking/AFURLResponseSerialization.h + sourceTree + <group> + + 256AD2C6EA58C4053DF2AC1B + + includeInIndex + 1 + isa + PBXFileReference + lastKnownFileType + sourcecode.c.h + path + Pods-environment.h + sourceTree + <group> + + 25E731136E9378DFA707E0CA + + includeInIndex + 1 + isa + PBXFileReference + lastKnownFileType + text.xcconfig + path + Pods-MWPhotoBrowser-Private.xcconfig + sourceTree + <group> + + 25EEC171E79E6F6D138830EB + + fileRef + 0D44E9FA3B915143671C7BB7 + isa + PBXBuildFile + + 26090EAB64012ACD35014B0E + + includeInIndex + 1 + isa + PBXFileReference + lastKnownFileType + sourcecode.c.objc + name + PSTCollectionViewController.m + path + PSTCollectionView/PSTCollectionViewController.m + sourceTree + <group> + + 264F2686AC1D7A3259DE7584 + + fileRef + 6AAD773CF99897A09D77F12D + isa + PBXBuildFile + settings + + COMPILER_FLAGS + -DOS_MACOSX -DLEVELDB_PLATFORM_POSIX -fno-objc-arc + + + 2653ADEFD52BB567F18FE523 + + includeInIndex + 1 + isa + PBXFileReference + lastKnownFileType + sourcecode.c.h + path + Pods-ProtocolBuffers-prefix.pch + sourceTree + <group> + + 2664B96014E04470A26C3D9D + + includeInIndex + 1 + isa + PBXFileReference + lastKnownFileType + sourcecode.c.h + name + table_builder.h + path + include/leveldb/table_builder.h + sourceTree + <group> + + 266782D2AC97BCEB5178979A + + includeInIndex + 1 + isa + PBXFileReference + name + testutil.cc + path + util/testutil.cc + sourceTree + <group> + + 266DAA6EBCF551D9AEAC871C + + fileRef + 6ECCB645A8F8ED5BE9077872 + isa + PBXBuildFile + settings + + COMPILER_FLAGS + -DOS_MACOSX -DLEVELDB_PLATFORM_POSIX -fno-objc-arc + + + 26B8112D009B6B9B7222DD44 + + children + + 45D773EB9646F5737851BE36 + 709DF1D98B3C9C42CAF24380 + EF2FF83F2D1859670CC23AED + 5B478B6CBEC7E1D741845A85 + 642C40CEA832189EA815BFB3 + D44E766CBE117F485D9966D6 + 58BAFF5AE5BD38325DEB1084 + 05EB2194F0C07155D1BD9FCA + 97EB22142C17FCFC08DBACC8 + D870E25799E17DF48DFC3485 + 71719F88BF2DF73256F6D359 + C7D48636C10C7744165FB31A + + isa + PBXGroup + name + Products + sourceTree + <group> + + 26C84946B53B2A2E7A0EDC8F + + fileRef + 2A9067C886DE85ABCF36D13D + isa + PBXBuildFile + settings + + COMPILER_FLAGS + -DOS_MACOSX -DLEVELDB_PLATFORM_POSIX -fno-objc-arc + + + 26E94E31D25EB6E6B8D3514F + + baseConfigurationReference + BC1331C7F2BB36605A024EE3 + buildSettings + + ALWAYS_SEARCH_USER_PATHS + NO + COPY_PHASE_STRIP + NO + DSTROOT + /tmp/xcodeproj.dst + GCC_DYNAMIC_NO_PIC + NO + GCC_OPTIMIZATION_LEVEL + 0 + GCC_PRECOMPILE_PREFIX_HEADER + YES + GCC_PREPROCESSOR_DEFINITIONS + + DEBUG=1 + $(inherited) + + GCC_SYMBOLS_PRIVATE_EXTERN + NO + INSTALL_PATH + $(BUILT_PRODUCTS_DIR) + IPHONEOS_DEPLOYMENT_TARGET + 6.0 + OTHER_LDFLAGS + + OTHER_LIBTOOLFLAGS + + PRODUCT_NAME + $(TARGET_NAME) + PUBLIC_HEADERS_FOLDER_PATH + $(TARGET_NAME) + SDKROOT + iphoneos + SKIP_INSTALL + YES + + isa + XCBuildConfiguration + name + Debug + + 2789D3C72809AAD6A403B520 + + includeInIndex + 1 + isa + PBXFileReference + lastKnownFileType + sourcecode.c.objc + name + AFURLConnectionOperation.m + path + AFNetworking/AFURLConnectionOperation.m + sourceTree + <group> + + 27B3A704ACD64CD44DDCBD1E + + buildConfigurations + + 3DBA83E882D8F63321FB00ED + C1D6ACBC8299FB8FCAF5B47E + + defaultConfigurationIsVisible + 0 + defaultConfigurationName + Release + isa + XCConfigurationList + + 280A524E026C941535C7A99E + + fileRef + 3A9F4AC69A272E5270CC8406 + isa + PBXBuildFile + + 288B5E95FFC7C966C96178C8 + + fileRef + 8FC24A9C5749968730CC0338 + isa + PBXBuildFile + + 28DCF641CAC83536782FA512 + + fileRef + 552A55BCA9263CA49874E0A5 + isa + PBXBuildFile + + 29598778BBE6B89A3377757B + + children + + 917A9FEEA37059C3E2F9B3FB + + isa + PBXGroup + name + Resources + sourceTree + <group> + + 2A4CFDDD4D4A36CBCC470176 + + isa + PBXTargetDependency + name + Pods-MBProgressHUD + target + 45FFB846AD2C35316261CE26 + targetProxy + 153A0E397CF589CBCA9C1700 + + 2A5A7341CD4236064A18FEBD + + fileRef + B2C7A5F4AD5D9E7D5B2745D1 + isa + PBXBuildFile + settings + + COMPILER_FLAGS + -DOS_MACOSX -DLEVELDB_PLATFORM_POSIX -fno-objc-arc + + + 2A9067C886DE85ABCF36D13D + + includeInIndex + 1 + isa + PBXFileReference + name + filename.cc + path + db/filename.cc + sourceTree + <group> + + 2A9C68E11F7A415F7CB97BDC + + buildActionMask + 2147483647 + files + + C01F4F52C1997C1E5B1CE567 + + isa + PBXFrameworksBuildPhase + runOnlyForDeploymentPostprocessing + 0 + + 2AA8151F40837D2700B5EF47 + + fileRef + F4D61FBDB3D46D0EE9CFAA1A + isa + PBXBuildFile + + 2B695DA71970230574B43D40 + + includeInIndex + 1 + isa + PBXFileReference + lastKnownFileType + text.xcconfig + path + Pods-MBProgressHUD.xcconfig + sourceTree + <group> + + 2B6BD15E531A436BA82D7D30 + + baseConfigurationReference + 083933610D4312DE9AB65E85 + buildSettings + + ALWAYS_SEARCH_USER_PATHS + NO + COPY_PHASE_STRIP + NO + DSTROOT + /tmp/xcodeproj.dst + GCC_DYNAMIC_NO_PIC + NO + GCC_OPTIMIZATION_LEVEL + 0 + GCC_PRECOMPILE_PREFIX_HEADER + YES + GCC_PREFIX_HEADER + Target Support Files/Pods-HPGrowingTextView/Pods-HPGrowingTextView-prefix.pch + GCC_PREPROCESSOR_DEFINITIONS + + DEBUG=1 + $(inherited) + + GCC_SYMBOLS_PRIVATE_EXTERN + NO + INSTALL_PATH + $(BUILT_PRODUCTS_DIR) + IPHONEOS_DEPLOYMENT_TARGET + 6.0 + OTHER_LDFLAGS + + OTHER_LIBTOOLFLAGS + + PRODUCT_NAME + $(TARGET_NAME) + PUBLIC_HEADERS_FOLDER_PATH + $(TARGET_NAME) + SDKROOT + iphoneos + SKIP_INSTALL + YES + + isa + XCBuildConfiguration + name + Debug + + 2B8CA4FFC42ED9343BEBF19D + + fileRef + 4F967D6B41FFC92C8BAB90C3 + isa + PBXBuildFile + + 2BC5038DF6D7CEDECB6EB489 + + baseConfigurationReference + 6D4610683470F0D825193013 + buildSettings + + ALWAYS_SEARCH_USER_PATHS + NO + COPY_PHASE_STRIP + NO + DSTROOT + /tmp/xcodeproj.dst + GCC_DYNAMIC_NO_PIC + NO + GCC_OPTIMIZATION_LEVEL + 0 + GCC_PRECOMPILE_PREFIX_HEADER + YES + GCC_PREFIX_HEADER + Target Support Files/Pods-FMDB/Pods-FMDB-prefix.pch + GCC_PREPROCESSOR_DEFINITIONS + + DEBUG=1 + $(inherited) + + GCC_SYMBOLS_PRIVATE_EXTERN + NO + INSTALL_PATH + $(BUILT_PRODUCTS_DIR) + IPHONEOS_DEPLOYMENT_TARGET + 6.0 + OTHER_LDFLAGS + + OTHER_LIBTOOLFLAGS + + PRODUCT_NAME + $(TARGET_NAME) + PUBLIC_HEADERS_FOLDER_PATH + $(TARGET_NAME) + SDKROOT + iphoneos + SKIP_INSTALL + YES + + isa + XCBuildConfiguration + name + Debug + + 2BE5A7338E285626D5375315 + + isa + PBXTargetDependency + name + Pods-ProtocolBuffers + target + 4C9AB3E89C35EEA3084D58F3 + targetProxy + AA5CAF930252693792DB9C68 + + 2CF32DE5EB11E0DE3C1EDB94 + + baseConfigurationReference + 6FF528D39989A2C35688A3DA + buildSettings + + ALWAYS_SEARCH_USER_PATHS + NO + COPY_PHASE_STRIP + NO + DSTROOT + /tmp/xcodeproj.dst + GCC_DYNAMIC_NO_PIC + NO + GCC_OPTIMIZATION_LEVEL + 0 + GCC_PRECOMPILE_PREFIX_HEADER + YES + GCC_PREFIX_HEADER + Target Support Files/Pods-PSTCollectionView/Pods-PSTCollectionView-prefix.pch + GCC_PREPROCESSOR_DEFINITIONS + + DEBUG=1 + $(inherited) + + GCC_SYMBOLS_PRIVATE_EXTERN + NO + INSTALL_PATH + $(BUILT_PRODUCTS_DIR) + IPHONEOS_DEPLOYMENT_TARGET + 6.0 + OTHER_LDFLAGS + + OTHER_LIBTOOLFLAGS + + PRODUCT_NAME + $(TARGET_NAME) + PUBLIC_HEADERS_FOLDER_PATH + $(TARGET_NAME) + SDKROOT + iphoneos + SKIP_INSTALL + YES + + isa + XCBuildConfiguration + name + Debug + + 2CFF4C9145609587718F8584 + + includeInIndex + 1 + isa + PBXFileReference + lastKnownFileType + sourcecode.c.h + path + MBProgressHUD.h + sourceTree + <group> + + 2D2FF48671C1E5AF634255AF + + children + + 56E47069783ADD00A31EA280 + F0DA9628331484011ADCCEEE + 621A89489B9B0C3A13363E61 + 9ED83F250C61C92BDFCEF9DE + + isa + PBXGroup + name + Support Files + path + ../Target Support Files/Pods-DACircularProgress + sourceTree + <group> + + 2DBE80325A693315C948FC80 + + children + + 669EAE7DE1ED17F9C051F30D + 0D44E9FA3B915143671C7BB7 + + isa + PBXGroup + name + Security + sourceTree + <group> + + 2DEDD05DF1CEE040F591C410 + + includeInIndex + 1 + isa + PBXFileReference + name + histogram.cc + path + util/histogram.cc + sourceTree + <group> + + 2E42719EDE41C967F415A24D + + fileRef + E90C8002FB08810C2A006EDD + isa + PBXBuildFile + + 2E74376FD0149AFBAD342B49 + + children + + 8D7B75790F25EBFA869D3042 + 6FC71B102CAE9873DADE34D5 + 2D2FF48671C1E5AF634255AF + + isa + PBXGroup + name + DACircularProgress + path + DACircularProgress + sourceTree + <group> + + 2F288AE1428914244800922E + + includeInIndex + 1 + isa + PBXFileReference + lastKnownFileType + sourcecode.c.h + name + db.h + path + include/leveldb/db.h + sourceTree + <group> + + 2FB8A6CD2750F5411D32E044 + + buildActionMask + 2147483647 + files + + 0D2D1F778605EB3B977ABD85 + B691DD5164855DE328CD4667 + AC5A72531A1FDD542137A7D0 + E9D3FB3DCAD31ABD664DACB5 + A96C57DBDA6062C7971A154B + 6DAA7E603B07D3FCAB05E6FB + + isa + PBXHeadersBuildPhase + runOnlyForDeploymentPostprocessing + 0 + + 300185658B768A994214DAA7 + + children + + 94A05A05CBF0EBB3D68909AF + B894532EF13442EF355249F8 + B517148A5BC72E9005CFAFFD + 3D10C0F53638694244519BCC + 47D922FA54FC3C3045B13491 + 9F5D3B0DED0285CBEE564F52 + F021064D4A15F1EFE5E6378F + 94D826954323FB898ADC26D0 + 69B5C61F0BA419F844533310 + C214372F6590692E084E2D5F + F29A397831A0F7E88AFF6C4F + F4D61FBDB3D46D0EE9CFAA1A + 3CC6468951DC779062F5BF45 + B2EBBC364774B0291BF6794F + 0F997A972D99D16202B345E1 + 117DC2290330919560CE4621 + 477D6A7C5445614F0EC92BEF + 22B26915D88B0A5F805CD9C3 + F0E45C93060176FF51747061 + 29598778BBE6B89A3377757B + ED3F5FEC7C7321FEA60F8E20 + + isa + PBXGroup + name + MWPhotoBrowser + path + MWPhotoBrowser + sourceTree + <group> + + 303988E1D59A2BCC860889D7 + + baseConfigurationReference + 899CAF7A6402EF48A2DB63B0 + buildSettings + + ALWAYS_SEARCH_USER_PATHS + NO + COPY_PHASE_STRIP + YES + DSTROOT + /tmp/xcodeproj.dst + GCC_PRECOMPILE_PREFIX_HEADER + YES + INSTALL_PATH + $(BUILT_PRODUCTS_DIR) + IPHONEOS_DEPLOYMENT_TARGET + 6.0 + OTHER_CFLAGS + + -DNS_BLOCK_ASSERTIONS=1 + $(inherited) + + OTHER_CPLUSPLUSFLAGS + + -DNS_BLOCK_ASSERTIONS=1 + $(inherited) + + OTHER_LDFLAGS + + OTHER_LIBTOOLFLAGS + + PRODUCT_NAME + $(TARGET_NAME) + PUBLIC_HEADERS_FOLDER_PATH + $(TARGET_NAME) + SDKROOT + iphoneos + SKIP_INSTALL + YES + VALIDATE_PRODUCT + YES + + isa + XCBuildConfiguration + name + Release + + 30431FFB84F65FE60696E689 + + includeInIndex + 1 + isa + PBXFileReference + lastKnownFileType + text.plist.xml + path + Pods-acknowledgements.plist + sourceTree + <group> + + 307B56AFBB065E27C3CBB279 + + fileRef + F2D467336D5A63A3507849C5 + isa + PBXBuildFile + settings + + COMPILER_FLAGS + -DOS_MACOSX -DLEVELDB_PLATFORM_POSIX -fno-objc-arc + + + 3137847C12737C5F132D2ED8 + + children + + 0920E0BD1922A66BE990F164 + 2E74376FD0149AFBAD342B49 + D2E07E59587D5971B5194FF4 + 9A9B88BCEB4678DD93727B93 + 20C4E0FBFE52EFAE82DAB4E0 + 300185658B768A994214DAA7 + EE7E7A1AC778EF09E52FCC45 + F4AC1B9E5BCBAFF474A08C05 + A5899C85DA3E096BB2B43934 + 91AC0D09CF77F17A5B64C763 + C80B59F7F32BBD752961FA0F + + isa + PBXGroup + name + Pods + sourceTree + <group> + + 31AA646DEB8B5D246415A7AF + + containerPortal + 32F15B3A8A99ACC37FCE0E4A + isa + PBXContainerItemProxy + proxyType + 1 + remoteGlobalIDString + 45FFB846AD2C35316261CE26 + remoteInfo + Pods-MBProgressHUD + + 32070D04AC56830D11B96B3E + + fileRef + C0A3C4CFF66805E6D8C81FF2 + isa + PBXBuildFile + + 326B2BFA523C5193368A7E79 + + fileRef + 6FC71B102CAE9873DADE34D5 + isa + PBXBuildFile + settings + + COMPILER_FLAGS + -DOS_OBJECT_USE_OBJC=0 + + + 32BF81DBCE8922CC2CF4C2DC + + fileRef + 8CE38F828C808EF79A144EFB + isa + PBXBuildFile + settings + + COMPILER_FLAGS + -DOS_OBJECT_USE_OBJC=0 + + + 32EC93C854539B2E033F08F5 + + fileRef + 22B424E560CB2A89AE0EB255 + isa + PBXBuildFile + + 32F15B3A8A99ACC37FCE0E4A + + attributes + + LastUpgradeCheck + 0510 + + buildConfigurationList + 27B3A704ACD64CD44DDCBD1E + compatibilityVersion + Xcode 3.2 + developmentRegion + English + hasScannedForEncodings + 0 + isa + PBXProject + knownRegions + + en + + mainGroup + C789EFA649CE5511A5034CB4 + productRefGroup + 26B8112D009B6B9B7222DD44 + projectDirPath + + projectReferences + + projectRoot + + targets + + 36C1E64DE39865525EB9A1BF + B68C69F6738C61A824DDA397 + 5BC12A63DA507D16082F87B8 + 81C7539C5773E295433603AB + 6360D6708B351012B4113963 + 45FFB846AD2C35316261CE26 + 133A25A0D319725FEC1884B0 + B2CC9370F3764EE84221A3DA + 4C9AB3E89C35EEA3084D58F3 + B92B573335D8EBD876E5BAB3 + 436B9F8EBC9F4E16A3FE4A8E + 09A20CC0DB72732970F408DF + + + 332AE27CA379C6B29497E05B + + fileRef + DC7599049970BBDD0032E7ED + isa + PBXBuildFile + + 34FF922B2CA28ECD6719B90C + + fileRef + 98B6D5E9EFB0A69AD65B7598 + isa + PBXBuildFile + settings + + COMPILER_FLAGS + -DOS_OBJECT_USE_OBJC=0 + + + 355987259D3D4D8C6ED844AC + + includeInIndex + 1 + isa + PBXFileReference + lastKnownFileType + sourcecode.c.objc + path + Pods-ProtocolBuffers-dummy.m + sourceTree + <group> + + 35C65B49A6538028143BA3F1 + + fileRef + 4C36B817E4055677B5421327 + isa + PBXBuildFile + + 363C7382E2696A0FC947E7B3 + + fileRef + 22B26915D88B0A5F805CD9C3 + isa + PBXBuildFile + + 36948A2B0B64D5282D8D5BEF + + fileRef + F90F234921C5A6988D8F29F4 + isa + PBXBuildFile + settings + + COMPILER_FLAGS + -DOS_OBJECT_USE_OBJC=0 + + + 36A92433F1C460134470E808 + + fileRef + A3B73F738CF58459F9A0A978 + isa + PBXBuildFile + + 36C1E64DE39865525EB9A1BF + + buildConfigurationList + 0CA64C2CD908BCD291ABD244 + buildPhases + + 8586A2835B816D33F293D914 + 0A2D601202909065405557C7 + + buildRules + + dependencies + + C7295B4DA373498D1F71361A + 7AAB7FFD11BA24CE1D781C97 + 48D379D7B13645BC1FA4DC0E + 96F1070F6D0E4D754CF9294B + 2A4CFDDD4D4A36CBCC470176 + 5894353B5CEE51EBB3DAF212 + 9E6165B67754BEA18EF7B637 + 2BE5A7338E285626D5375315 + D07153D8BF8FDDB6ADA3BC94 + 00FA19206218DE6083F024EC + C4B40005F0D8D2FF21103FE5 + + isa + PBXNativeTarget + name + Pods + productName + Pods + productReference + 45D773EB9646F5737851BE36 + productType + com.apple.product-type.library.static + + 3752BB0CE2C29682AB862649 + + isa + PBXFileReference + lastKnownFileType + wrapper.framework + name + ImageIO.framework + path + Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS7.1.sdk/System/Library/Frameworks/ImageIO.framework + sourceTree + DEVELOPER_DIR + + 379EDEE95B52C97052942DC8 + + includeInIndex + 1 + isa + PBXFileReference + lastKnownFileType + sourcecode.c.objc + name + UIImageView+AFNetworking.m + path + UIKit+AFNetworking/UIImageView+AFNetworking.m + sourceTree + <group> + + 3822E2E211073EB29819DEEA + + fileRef + 223837A87FA5DCB75ED915CA + isa + PBXBuildFile + + 383593281A16833B4249471A + + includeInIndex + 1 + isa + PBXFileReference + lastKnownFileType + text.xcconfig + path + Pods-leveldb-library.xcconfig + sourceTree + <group> + + 388299DD69D2CC010DD19CD3 + + fileRef + FA45AB72D3AB3F2139080C14 + isa + PBXBuildFile + settings + + COMPILER_FLAGS + -DOS_OBJECT_USE_OBJC=0 + + + 38F06966FE24AB86B612DD3B + + includeInIndex + 1 + isa + PBXFileReference + lastKnownFileType + sourcecode.c.objc + path + Pods-PSTCollectionView-dummy.m + sourceTree + <group> + + 3A9F4AC69A272E5270CC8406 + + includeInIndex + 1 + isa + PBXFileReference + lastKnownFileType + sourcecode.c.objc + name + ExtendableMessage.m + path + src/runtime/Classes/ExtendableMessage.m + sourceTree + <group> + + 3B02CA5EA32F0989DA4F60EA + + buildActionMask + 2147483647 + files + + 3822E2E211073EB29819DEEA + 555DBE83FB1A840E8B185344 + + isa + PBXFrameworksBuildPhase + runOnlyForDeploymentPostprocessing + 0 + + 3B85D4CB465FD514E58237A6 + + fileRef + 74DC8A4071B473E99802DAD1 + isa + PBXBuildFile + + 3BD4E3C873BF588961842ED7 + + containerPortal + 32F15B3A8A99ACC37FCE0E4A + isa + PBXContainerItemProxy + proxyType + 1 + remoteGlobalIDString + B92B573335D8EBD876E5BAB3 + remoteInfo + Pods-SCLAlertView-Objective-C + + 3BFC38A4A9607CB34B33C589 + + fileRef + 6E62D46280CC328E94E46521 + isa + PBXBuildFile + + 3BFFF03A100816AA71EBC1FC + + fileRef + 8D7B75790F25EBFA869D3042 + isa + PBXBuildFile + + 3C425BD30A9130578244A99D + + fileRef + D510F74D5B9F22F1A17A825C + isa + PBXBuildFile + settings + + COMPILER_FLAGS + -DOS_OBJECT_USE_OBJC=0 + + + 3C5A96D689E3ADAFEE73A1B8 + + includeInIndex + 1 + isa + PBXFileReference + lastKnownFileType + sourcecode.c.objc + name + UIProgressView+AFNetworking.m + path + UIKit+AFNetworking/UIProgressView+AFNetworking.m + sourceTree + <group> + + 3CC6468951DC779062F5BF45 + + includeInIndex + 1 + isa + PBXFileReference + lastKnownFileType + sourcecode.c.h + name + MWPhotoProtocol.h + path + MWPhotoBrowser/Classes/MWPhotoProtocol.h + sourceTree + <group> + + 3D10C0F53638694244519BCC + + includeInIndex + 1 + isa + PBXFileReference + lastKnownFileType + sourcecode.c.h + name + MWGridCell.h + path + MWPhotoBrowser/Classes/MWGridCell.h + sourceTree + <group> + + 3D3E42AB2ED904817B1F7B70 + + fileRef + F9E7DA9C46BEC071E7ED6457 + isa + PBXBuildFile + settings + + COMPILER_FLAGS + -DOS_MACOSX -DLEVELDB_PLATFORM_POSIX -fno-objc-arc + + + 3D6A401A0F4D6944FAB89588 + + includeInIndex + 1 + isa + PBXFileReference + name + block_builder.cc + path + table/block_builder.cc + sourceTree + <group> + + 3DBA83E882D8F63321FB00ED + + buildSettings + + ALWAYS_SEARCH_USER_PATHS + NO + CLANG_CXX_LANGUAGE_STANDARD + gnu++0x + CLANG_CXX_LIBRARY + libc++ + CLANG_ENABLE_MODULES + YES + CLANG_ENABLE_OBJC_ARC + YES + CLANG_WARN_BOOL_CONVERSION + YES + CLANG_WARN_CONSTANT_CONVERSION + YES + CLANG_WARN_DIRECT_OBJC_ISA_USAGE + YES + CLANG_WARN_EMPTY_BODY + YES + CLANG_WARN_ENUM_CONVERSION + YES + CLANG_WARN_INT_CONVERSION + YES + CLANG_WARN_OBJC_ROOT_CLASS + YES + COPY_PHASE_STRIP + YES + GCC_C_LANGUAGE_STANDARD + gnu99 + GCC_DYNAMIC_NO_PIC + NO + GCC_OPTIMIZATION_LEVEL + 0 + GCC_PREPROCESSOR_DEFINITIONS + + DEBUG=1 + $(inherited) + + GCC_SYMBOLS_PRIVATE_EXTERN + NO + GCC_WARN_64_TO_32_BIT_CONVERSION + YES + GCC_WARN_ABOUT_RETURN_TYPE + YES + GCC_WARN_UNDECLARED_SELECTOR + YES + GCC_WARN_UNINITIALIZED_AUTOS + YES + GCC_WARN_UNUSED_FUNCTION + YES + GCC_WARN_UNUSED_VARIABLE + YES + IPHONEOS_DEPLOYMENT_TARGET + 6.0 + ONLY_ACTIVE_ARCH + YES + STRIP_INSTALLED_PRODUCT + NO + + isa + XCBuildConfiguration + name + Debug + + 3DBE9366C24E56098BF26590 + + fileRef + EF08F0AD71749C672D55C040 + isa + PBXBuildFile + + 3EB2AB40155920F357CBE280 + + includeInIndex + 1 + isa + PBXFileReference + lastKnownFileType + sourcecode.c.h + name + CodedOutputStream.h + path + src/runtime/Classes/CodedOutputStream.h + sourceTree + <group> + + 3EC4DCED927DA0E602EDB8F1 + + includeInIndex + 1 + isa + PBXFileReference + lastKnownFileType + sourcecode.c.h + name + AFNetworking.h + path + AFNetworking/AFNetworking.h + sourceTree + <group> + + 3F8ED30C239BAFDD5B8DFF60 + + fileRef + F4ED4D5B270DD429F10CA8C2 + isa + PBXBuildFile + settings + + COMPILER_FLAGS + -DOS_OBJECT_USE_OBJC=0 + + + 3FD4932A47564EEA68C63804 + + includeInIndex + 1 + isa + PBXFileReference + lastKnownFileType + sourcecode.c.h + name + PSTCollectionViewUpdateItem.h + path + PSTCollectionView/PSTCollectionViewUpdateItem.h + sourceTree + <group> + + 4000A459693DA456A9F260BB + + fileRef + 223837A87FA5DCB75ED915CA + isa + PBXBuildFile + + 402BB63A10FDE616CDE7149A + + buildActionMask + 2147483647 + files + + F4D405575168A967C6F43D20 + 3DBE9366C24E56098BF26590 + + isa + PBXSourcesBuildPhase + runOnlyForDeploymentPostprocessing + 0 + + 4031E4A092D2F7C268F34980 + + fileRef + 65F7069DDDB709F84C123389 + isa + PBXBuildFile + settings + + COMPILER_FLAGS + -DOS_MACOSX -DLEVELDB_PLATFORM_POSIX -fno-objc-arc + + + 40499E70D308BA2A338F6886 + + includeInIndex + 1 + isa + PBXFileReference + lastKnownFileType + sourcecode.c.h + name + MessageBuilder.h + path + src/runtime/Classes/MessageBuilder.h + sourceTree + <group> + + 40A513B574E6F4D0985773E1 + + buildActionMask + 2147483647 + files + + C12B69172B63B72AD0EEC876 + D1090AC882A2758438195F9C + A7DFB1C822356A2522821643 + + isa + PBXFrameworksBuildPhase + runOnlyForDeploymentPostprocessing + 0 + + 410AF7EC006A7BE85F130790 + + fileRef + C14AD3034BE5D559CD38D152 + isa + PBXBuildFile + + 4150DFA8C688167143510BB4 + + fileRef + A4076CCDEDD6B27F0F0B2CEC + isa + PBXBuildFile + + 41B7D6E5AE00DD9497F8E109 + + includeInIndex + 1 + isa + PBXFileReference + lastKnownFileType + sourcecode.c.h + name + SCLButton.h + path + SCLAlertView/SCLButton.h + sourceTree + <group> + + 425D1AA4CA667230BD03B228 + + fileRef + F021064D4A15F1EFE5E6378F + isa + PBXBuildFile + settings + + COMPILER_FLAGS + -DOS_OBJECT_USE_OBJC=0 + + + 4293BA942D0258CD05084577 + + fileRef + DEF488A26ED34AD6C91108EB + isa + PBXBuildFile + + 433DBE8012005DACD07D65EF + + includeInIndex + 1 + isa + PBXFileReference + lastKnownFileType + sourcecode.c.h + name + CodedInputStream.h + path + src/runtime/Classes/CodedInputStream.h + sourceTree + <group> + + 436B9F8EBC9F4E16A3FE4A8E + + buildConfigurationList + F8EE7A3FF58F2974C05C7D68 + buildPhases + + 689E71881C7A7E0CD0E3B7AF + F8A8A377242E3B94EF492CCE + 82CE53307F70BF005035BCD4 + + buildRules + + dependencies + + isa + PBXNativeTarget + name + Pods-SDWebImage + productName + Pods-SDWebImage + productReference + 71719F88BF2DF73256F6D359 + productType + com.apple.product-type.library.static + + 43B36CA39A94A8B358609C33 + + fileRef + 223837A87FA5DCB75ED915CA + isa + PBXBuildFile + + 43C7202C034BD7F7F5DE09DE + + fileRef + 223837A87FA5DCB75ED915CA + isa + PBXBuildFile + + 44791A1DC8CBDB321013967D + + includeInIndex + 1 + isa + PBXFileReference + lastKnownFileType + sourcecode.c.objc + name + SCLAlertViewResponder.m + path + SCLAlertView/SCLAlertViewResponder.m + sourceTree + <group> + + 45D773EB9646F5737851BE36 + + explicitFileType + archive.ar + includeInIndex + 0 + isa + PBXFileReference + path + libPods.a + sourceTree + BUILT_PRODUCTS_DIR + + 45FD5AE5B54AE822710D71AD + + includeInIndex + 1 + isa + PBXFileReference + lastKnownFileType + sourcecode.c.h + name + filter_policy.h + path + include/leveldb/filter_policy.h + sourceTree + <group> + + 45FFB846AD2C35316261CE26 + + buildConfigurationList + 0126B4E3DC7E900E873706C2 + buildPhases + + 402BB63A10FDE616CDE7149A + D6A21361BCA70D18B24AD6C3 + D57246A24D83BA5D0F739840 + + buildRules + + dependencies + + isa + PBXNativeTarget + name + Pods-MBProgressHUD + productName + Pods-MBProgressHUD + productReference + D44E766CBE117F485D9966D6 + productType + com.apple.product-type.library.static + + 46084CECE5E6479249631903 + + includeInIndex + 1 + isa + PBXFileReference + name + bloom.cc + path + util/bloom.cc + sourceTree + <group> + + 4687AE4C66B1F5A1AB143D40 + + includeInIndex + 1 + isa + PBXFileReference + lastKnownFileType + sourcecode.c.h + name + ForwardDeclarations.h + path + src/runtime/Classes/ForwardDeclarations.h + sourceTree + <group> + + 46A348EECBDEFB7DCCA2BB94 + + includeInIndex + 1 + isa + PBXFileReference + lastKnownFileType + sourcecode.c.h + name + UIButton+WebCache.h + path + SDWebImage/UIButton+WebCache.h + sourceTree + <group> + + 477D6A7C5445614F0EC92BEF + + includeInIndex + 1 + isa + PBXFileReference + lastKnownFileType + sourcecode.c.objc + name + MWTapDetectingView.m + path + MWPhotoBrowser/Classes/MWTapDetectingView.m + sourceTree + <group> + + 47A78CC7A9590DAD7A45E2D4 + + baseConfigurationReference + DD220FA10AB47E9B70474A47 + buildSettings + + ALWAYS_SEARCH_USER_PATHS + NO + COPY_PHASE_STRIP + YES + DSTROOT + /tmp/xcodeproj.dst + GCC_PRECOMPILE_PREFIX_HEADER + YES + GCC_PREFIX_HEADER + Target Support Files/Pods-MBProgressHUD/Pods-MBProgressHUD-prefix.pch + INSTALL_PATH + $(BUILT_PRODUCTS_DIR) + IPHONEOS_DEPLOYMENT_TARGET + 6.0 + OTHER_CFLAGS + + -DNS_BLOCK_ASSERTIONS=1 + $(inherited) + + OTHER_CPLUSPLUSFLAGS + + -DNS_BLOCK_ASSERTIONS=1 + $(inherited) + + OTHER_LDFLAGS + + OTHER_LIBTOOLFLAGS + + PRODUCT_NAME + $(TARGET_NAME) + PUBLIC_HEADERS_FOLDER_PATH + $(TARGET_NAME) + SDKROOT + iphoneos + SKIP_INSTALL + YES + VALIDATE_PRODUCT + YES + + isa + XCBuildConfiguration + name + Release + + 47B3F8EE8E24DA3833D634DA + + fileRef + 45FD5AE5B54AE822710D71AD + isa + PBXBuildFile + + 47D922FA54FC3C3045B13491 + + includeInIndex + 1 + isa + PBXFileReference + lastKnownFileType + sourcecode.c.objc + name + MWGridCell.m + path + MWPhotoBrowser/Classes/MWGridCell.m + sourceTree + <group> + + 488E191A992E650602A6E668 + + buildActionMask + 2147483647 + files + + 5E1CD2006C9615AC7583E402 + + isa + PBXFrameworksBuildPhase + runOnlyForDeploymentPostprocessing + 0 + + 48CE8DAE1D7962A7FCABE465 + + fileRef + D4BB92CC59FB58F99D6432FC + isa + PBXBuildFile + + 48D379D7B13645BC1FA4DC0E + + isa + PBXTargetDependency + name + Pods-FMDB + target + 81C7539C5773E295433603AB + targetProxy + 18A124FFB8D7508B0D333A73 + + 48DFB8216AF86E5ED4CF577B + + buildConfigurations + + 0CE348E3F868EB1254F26D08 + B4A8031A8E26837EAE3D2C82 + + defaultConfigurationIsVisible + 0 + defaultConfigurationName + Release + isa + XCConfigurationList + + 49AC65C76420ED77634048BA + + includeInIndex + 1 + isa + PBXFileReference + lastKnownFileType + sourcecode.c.objc + name + SDWebImageDecoder.m + path + SDWebImage/SDWebImageDecoder.m + sourceTree + <group> + + 49FF77FF50895DF43120841F + + fileRef + 0DE31D4A559CEA4BAAEB43FA + isa + PBXBuildFile + + 4A99FEF88DBDD45C34D0CEEC + + fileRef + FCC3E938BAC0E348818BD8BE + isa + PBXBuildFile + + 4ACA21E5C05E643E5B37F3A1 + + fileRef + 55264D37382246C8001B1E41 + isa + PBXBuildFile + settings + + COMPILER_FLAGS + -DOS_MACOSX -DLEVELDB_PLATFORM_POSIX -fno-objc-arc + + + 4B325765210BAB16F8B85788 + + fileRef + F5E7971956E2814255293312 + isa + PBXBuildFile + + 4B44DD7E04CDC67F8CFE6767 + + children + + D17A26C1FADA059FA06C58BA + + isa + PBXGroup + name + Frameworks + sourceTree + <group> + + 4B70F0352F54A3FB980841FE + + includeInIndex + 1 + isa + PBXFileReference + lastKnownFileType + sourcecode.c.h + path + Pods-leveldb-library-prefix.pch + sourceTree + <group> + + 4BB07B8ED9E4BEA7018D8195 + + buildConfigurations + + A712DD190C8A2DC1F6840E37 + BADF1612A352CC9A346F3D3B + + defaultConfigurationIsVisible + 0 + defaultConfigurationName + Release + isa + XCConfigurationList + + 4BCD84D3892CB1B0EAA4D794 + + includeInIndex + 1 + isa + PBXFileReference + lastKnownFileType + sourcecode.c.objc + name + UIImage+GIF.m + path + SDWebImage/UIImage+GIF.m + sourceTree + <group> + + 4C36B817E4055677B5421327 + + includeInIndex + 1 + isa + PBXFileReference + lastKnownFileType + sourcecode.c.h + name + UIImageView+WebCache.h + path + SDWebImage/UIImageView+WebCache.h + sourceTree + <group> + + 4C9AB3E89C35EEA3084D58F3 + + buildConfigurationList + 9EACBA66AC00CFCEC1661305 + buildPhases + + F62C1713D4D2480D28335202 + BEB024A1F5BD014D07626678 + A5AD30701B4EEA9A8E582A8A + + buildRules + + dependencies + + isa + PBXNativeTarget + name + Pods-ProtocolBuffers + productName + Pods-ProtocolBuffers + productReference + 97EB22142C17FCFC08DBACC8 + productType + com.apple.product-type.library.static + + 4D63C82E1237C980377587C4 + + fileRef + A002E6C9939624372369F622 + isa + PBXBuildFile + settings + + COMPILER_FLAGS + -DOS_MACOSX -DLEVELDB_PLATFORM_POSIX -fno-objc-arc + + + 4D66AA358AB651C3B3CDFC8F + + fileRef + 8713D88CE5ED4B4CC40A3DC5 + isa + PBXBuildFile + settings + + COMPILER_FLAGS + -DOS_MACOSX -DLEVELDB_PLATFORM_POSIX -fno-objc-arc + + + 4D888E40EC697EA505BF5393 + + fileRef + 2500C99B3FB11290FFFD347B + isa + PBXBuildFile + + 4EB9F151CB99E080156E610F + + fileRef + 223837A87FA5DCB75ED915CA + isa + PBXBuildFile + + 4F967D6B41FFC92C8BAB90C3 + + includeInIndex + 1 + isa + PBXFileReference + lastKnownFileType + sourcecode.c.h + name + PBArray.h + path + src/runtime/Classes/PBArray.h + sourceTree + <group> + + 507165A17F2C83D61F165C39 + + buildConfigurations + + 99486657B6547FA998F7FE00 + 730BE8365656FDFCEAE2DF24 + + defaultConfigurationIsVisible + 0 + defaultConfigurationName + Release + isa + XCConfigurationList + + 50C4B8B7C970B8AF644F7A72 + + fileRef + 993DE3DBE9B9B2FE96D70D49 + isa + PBXBuildFile + + 5124313076B630667C19EDE6 + + fileRef + 41B7D6E5AE00DD9497F8E109 + isa + PBXBuildFile + + 51AB06AB9EA1276A1A943219 + + fileRef + 6975B09D41EAAC0E44FAD082 + isa + PBXBuildFile + + 51FB13E9C1A4B9C76C2E2FAC + + includeInIndex + 1 + isa + PBXFileReference + lastKnownFileType + sourcecode.c.h + name + AFURLRequestSerialization.h + path + AFNetworking/AFURLRequestSerialization.h + sourceTree + <group> + + 526508973462BCD64B635E1F + + children + + 1BFC6BE71F25532EC7D1D612 + 083933610D4312DE9AB65E85 + 546CBE54C8042B64E57CFE44 + A3A6FCA5F26E01C518B63727 + + isa + PBXGroup + name + Support Files + path + ../Target Support Files/Pods-HPGrowingTextView + sourceTree + <group> + + 5289EE3E54D831F5B642A1EE + + fileRef + C214372F6590692E084E2D5F + isa + PBXBuildFile + + 52CBD74D817CD4FAE8C171FA + + fileRef + C3E04B58C6B03BACEF7C93C3 + isa + PBXBuildFile + + 52FE5DBECBFB296EF121C288 + + fileRef + 69B5C61F0BA419F844533310 + isa + PBXBuildFile + settings + + COMPILER_FLAGS + -DOS_OBJECT_USE_OBJC=0 + + + 53887B679828B24D705F8369 + + fileRef + 06D5E5B356DDEE0016B2DF8B + isa + PBXBuildFile + settings + + COMPILER_FLAGS + -DOS_MACOSX -DLEVELDB_PLATFORM_POSIX -fno-objc-arc + + + 53ED7E6AEDA46C6D5C6F6026 + + includeInIndex + 1 + isa + PBXFileReference + lastKnownFileType + sourcecode.c.h + path + Pods-SCLAlertView-Objective-C-prefix.pch + sourceTree + <group> + + 5405042C9F88C5EDFA7C8BC4 + + includeInIndex + 1 + isa + PBXFileReference + name + log_writer.cc + path + db/log_writer.cc + sourceTree + <group> + + 546CBE54C8042B64E57CFE44 + + includeInIndex + 1 + isa + PBXFileReference + lastKnownFileType + sourcecode.c.objc + path + Pods-HPGrowingTextView-dummy.m + sourceTree + <group> + + 55264D37382246C8001B1E41 + + includeInIndex + 1 + isa + PBXFileReference + name + builder.cc + path + db/builder.cc + sourceTree + <group> + + 552A55BCA9263CA49874E0A5 + + includeInIndex + 1 + isa + PBXFileReference + lastKnownFileType + sourcecode.c.objc + name + Utilities.m + path + src/runtime/Classes/Utilities.m + sourceTree + <group> + + 555DBE83FB1A840E8B185344 + + fileRef + 55FF4BF7CF588A412D3821E5 + isa + PBXBuildFile + + 55FF4BF7CF588A412D3821E5 + + isa + PBXFileReference + lastKnownFileType + wrapper.framework + name + QuartzCore.framework + path + Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS7.1.sdk/System/Library/Frameworks/QuartzCore.framework + sourceTree + DEVELOPER_DIR + + 56551ACFEAD4E92EB9BDEDA9 + + children + + 0EDA4C917EBBC882035EC388 + CC57503D74577BEA95AD137D + 74D974F59BC8193D74C5DDD2 + 0B2F9B6195920ACCC9915767 + + isa + PBXGroup + name + Support Files + path + ../Target Support Files/Pods-AFNetworking + sourceTree + <group> + + 56E47069783ADD00A31EA280 + + includeInIndex + 1 + isa + PBXFileReference + lastKnownFileType + text.xcconfig + path + Pods-DACircularProgress.xcconfig + sourceTree + <group> + + 575A1806C24DDD22FB1F3D76 + + includeInIndex + 1 + isa + PBXFileReference + lastKnownFileType + sourcecode.c.objc + name + SDWebImageDownloader.m + path + SDWebImage/SDWebImageDownloader.m + sourceTree + <group> + + 5776121BD52D034B76CF1482 + + includeInIndex + 1 + isa + PBXFileReference + name + merger.cc + path + table/merger.cc + sourceTree + <group> + + 5894353B5CEE51EBB3DAF212 + + isa + PBXTargetDependency + name + Pods-MWPhotoBrowser + target + 133A25A0D319725FEC1884B0 + targetProxy + 7F95CB24E9214EE56C3D857F + + 58B1FC1184E0438262917355 + + fileRef + C09793BD54D60BA0EDA79542 + isa + PBXBuildFile + + 58BAFF5AE5BD38325DEB1084 + + explicitFileType + archive.ar + includeInIndex + 0 + isa + PBXFileReference + path + libPods-MWPhotoBrowser.a + sourceTree + BUILT_PRODUCTS_DIR + + 597ACAAD687A7126693DBADB + + fileRef + D4129F77C3956981E45F0823 + isa + PBXBuildFile + + 5A1345CE0ECC3404E6FA251A + + fileRef + E3AB5079457C309BE972EB9E + isa + PBXBuildFile + + 5A64F59DD84722FB401FA6CF + + fileRef + 0C94A4F4543A58C11920B4B8 + isa + PBXBuildFile + + 5AC04AE113F7F019A53EA380 + + buildActionMask + 2147483647 + files + + 3BFFF03A100816AA71EBC1FC + + isa + PBXHeadersBuildPhase + runOnlyForDeploymentPostprocessing + 0 + + 5ACC307A39A4549B8E4B31CC + + includeInIndex + 1 + isa + PBXFileReference + lastKnownFileType + sourcecode.c.h + name + table.h + path + include/leveldb/table.h + sourceTree + <group> + + 5B478B6CBEC7E1D741845A85 + + explicitFileType + archive.ar + includeInIndex + 0 + isa + PBXFileReference + path + libPods-FMDB.a + sourceTree + BUILT_PRODUCTS_DIR + + 5B5AEE1888F87E8B26E3B489 + + includeInIndex + 1 + isa + PBXFileReference + lastKnownFileType + sourcecode.c.h + name + ConcreteExtensionField.h + path + src/runtime/Classes/ConcreteExtensionField.h + sourceTree + <group> + + 5BC12A63DA507D16082F87B8 + + buildConfigurationList + 4BB07B8ED9E4BEA7018D8195 + buildPhases + + D7CBA5D051FE225A2B801952 + 3B02CA5EA32F0989DA4F60EA + 5AC04AE113F7F019A53EA380 + + buildRules + + dependencies + + isa + PBXNativeTarget + name + Pods-DACircularProgress + productName + Pods-DACircularProgress + productReference + EF2FF83F2D1859670CC23AED + productType + com.apple.product-type.library.static + + 5CC6907B06E2D7E899F6EB42 + + fileRef + 6A817E6BB7C645D1AC92FAB0 + isa + PBXBuildFile + + 5D65C0C9FCA9B2EB9494A5D4 + + fileRef + 9F5D3B0DED0285CBEE564F52 + isa + PBXBuildFile + + 5DA409F5198AB2BD27F12AC6 + + baseConfigurationReference + DD220FA10AB47E9B70474A47 + buildSettings + + ALWAYS_SEARCH_USER_PATHS + NO + COPY_PHASE_STRIP + NO + DSTROOT + /tmp/xcodeproj.dst + GCC_DYNAMIC_NO_PIC + NO + GCC_OPTIMIZATION_LEVEL + 0 + GCC_PRECOMPILE_PREFIX_HEADER + YES + GCC_PREFIX_HEADER + Target Support Files/Pods-MBProgressHUD/Pods-MBProgressHUD-prefix.pch + GCC_PREPROCESSOR_DEFINITIONS + + DEBUG=1 + $(inherited) + + GCC_SYMBOLS_PRIVATE_EXTERN + NO + INSTALL_PATH + $(BUILT_PRODUCTS_DIR) + IPHONEOS_DEPLOYMENT_TARGET + 6.0 + OTHER_LDFLAGS + + OTHER_LIBTOOLFLAGS + + PRODUCT_NAME + $(TARGET_NAME) + PUBLIC_HEADERS_FOLDER_PATH + $(TARGET_NAME) + SDKROOT + iphoneos + SKIP_INSTALL + YES + + isa + XCBuildConfiguration + name + Debug + + 5E07C588667132BE4D76C386 + + includeInIndex + 1 + isa + PBXFileReference + lastKnownFileType + sourcecode.c.h + name + PSTGridLayoutItem.h + path + PSTCollectionView/PSTGridLayoutItem.h + sourceTree + <group> + + 5E1CD2006C9615AC7583E402 + + fileRef + 223837A87FA5DCB75ED915CA + isa + PBXBuildFile + + 5E532C2FE266B181F2A33B15 + + includeInIndex + 1 + isa + PBXFileReference + lastKnownFileType + sourcecode.c.h + name + Message.h + path + src/runtime/Classes/Message.h + sourceTree + <group> + + 5EC214EE3238E1135C34AD2A + + includeInIndex + 1 + isa + PBXFileReference + lastKnownFileType + sourcecode.c.h + name + UIView+WebCacheOperation.h + path + SDWebImage/UIView+WebCacheOperation.h + sourceTree + <group> + + 5F4E89B41EA219EB1540D95A + + fileRef + 46A348EECBDEFB7DCCA2BB94 + isa + PBXBuildFile + + 5FC96DEF4A95E3B34E908D1B + + fileRef + 12651ADB50AA76461BF5272A + isa + PBXBuildFile + + 5FD1AFC29DDCF9CCE15CDEBE + + includeInIndex + 1 + isa + PBXFileReference + lastKnownFileType + sourcecode.c.objc + name + TextFormat.m + path + src/runtime/Classes/TextFormat.m + sourceTree + <group> + + 6038AAB955ACF62FA2D6BF88 + + fileRef + 5E07C588667132BE4D76C386 + isa + PBXBuildFile + + 608ED333FCA41508710034C1 + + includeInIndex + 1 + isa + PBXFileReference + lastKnownFileType + sourcecode.c.h + name + FMDatabaseAdditions.h + path + src/fmdb/FMDatabaseAdditions.h + sourceTree + <group> + + 610702CC0D07AEC4A4BD0EDD + + fileRef + A9E2882AB83795C4238FA11A + isa + PBXBuildFile + + 6160490FB9FD266A240C709A + + includeInIndex + 1 + isa + PBXFileReference + lastKnownFileType + sourcecode.c.h + name + UIWebView+AFNetworking.h + path + UIKit+AFNetworking/UIWebView+AFNetworking.h + sourceTree + <group> + + 621A89489B9B0C3A13363E61 + + includeInIndex + 1 + isa + PBXFileReference + lastKnownFileType + sourcecode.c.objc + path + Pods-DACircularProgress-dummy.m + sourceTree + <group> + + 6221677C8CCE2562427ED2E1 + + includeInIndex + 1 + isa + PBXFileReference + lastKnownFileType + text.xcconfig + path + Pods-MWPhotoBrowser.xcconfig + sourceTree + <group> + + 628B417A08CDD15DA33A0FE9 + + includeInIndex + 1 + isa + PBXFileReference + name + logging.cc + path + util/logging.cc + sourceTree + <group> + + 62941C9C2F0AD9458A53B972 + + fileRef + 203F5506F66F6388F3636144 + isa + PBXBuildFile + settings + + COMPILER_FLAGS + -DOS_MACOSX -DLEVELDB_PLATFORM_POSIX -fno-objc-arc + + + 6360D6708B351012B4113963 + + buildConfigurationList + CE6472F7605774D3C01343EB + buildPhases + + 1328F74BB611C8C0974F01DF + 2A9C68E11F7A415F7CB97BDC + A9F075A7EE80A39E723F1A38 + + buildRules + + dependencies + + isa + PBXNativeTarget + name + Pods-HPGrowingTextView + productName + Pods-HPGrowingTextView + productReference + 642C40CEA832189EA815BFB3 + productType + com.apple.product-type.library.static + + 63DBCDAB0F366C2F406BC1F8 + + fileRef + EC0BF631A888536456ED3CC5 + isa + PBXBuildFile + + 642C40CEA832189EA815BFB3 + + explicitFileType + archive.ar + includeInIndex + 0 + isa + PBXFileReference + path + libPods-HPGrowingTextView.a + sourceTree + BUILT_PRODUCTS_DIR + + 650B231D482769904A477885 + + baseConfigurationReference + 8AAB857E284C046BD52EDCBC + buildSettings + + ALWAYS_SEARCH_USER_PATHS + NO + COPY_PHASE_STRIP + NO + DSTROOT + /tmp/xcodeproj.dst + GCC_DYNAMIC_NO_PIC + NO + GCC_OPTIMIZATION_LEVEL + 0 + GCC_PRECOMPILE_PREFIX_HEADER + YES + GCC_PREFIX_HEADER + Target Support Files/Pods-SCLAlertView-Objective-C/Pods-SCLAlertView-Objective-C-prefix.pch + GCC_PREPROCESSOR_DEFINITIONS + + DEBUG=1 + $(inherited) + + GCC_SYMBOLS_PRIVATE_EXTERN + NO + INSTALL_PATH + $(BUILT_PRODUCTS_DIR) + IPHONEOS_DEPLOYMENT_TARGET + 6.0 + OTHER_LDFLAGS + + OTHER_LIBTOOLFLAGS + + PRODUCT_NAME + $(TARGET_NAME) + PUBLIC_HEADERS_FOLDER_PATH + $(TARGET_NAME) + SDKROOT + iphoneos + SKIP_INSTALL + YES + + isa + XCBuildConfiguration + name + Debug + + 65346457B779AFE58B0B18A3 + + includeInIndex + 1 + isa + PBXFileReference + lastKnownFileType + text.xcconfig + path + Pods-FMDB.xcconfig + sourceTree + <group> + + 6591C2B8DB6C61C21963E2E8 + + containerPortal + 32F15B3A8A99ACC37FCE0E4A + isa + PBXContainerItemProxy + proxyType + 1 + remoteGlobalIDString + 5BC12A63DA507D16082F87B8 + remoteInfo + Pods-DACircularProgress + + 65F7069DDDB709F84C123389 + + includeInIndex + 1 + isa + PBXFileReference + name + c.cc + path + db/c.cc + sourceTree + <group> + + 6605C580797700F2CB5BD172 + + includeInIndex + 1 + isa + PBXFileReference + lastKnownFileType + sourcecode.c.objc + name + SCLAlertViewStyleKit.m + path + SCLAlertView/SCLAlertViewStyleKit.m + sourceTree + <group> + + 66077F98AAB96EA20A74BC27 + + fileRef + 223837A87FA5DCB75ED915CA + isa + PBXBuildFile + + 661264FDE0337383E10C08BC + + includeInIndex + 1 + isa + PBXFileReference + name + two_level_iterator.cc + path + table/two_level_iterator.cc + sourceTree + <group> + + 6629B1BB47511B7643B557DD + + children + + 65346457B779AFE58B0B18A3 + 6D4610683470F0D825193013 + FA0BAB27170E98482241483B + 17793F1AA6528675492C3B3B + + isa + PBXGroup + name + Support Files + path + ../Target Support Files/Pods-FMDB + sourceTree + <group> + + 6672134C5065CC7C0DF1C7C7 + + includeInIndex + 1 + isa + PBXFileReference + lastKnownFileType + sourcecode.c.objc + name + FMDatabase.m + path + src/fmdb/FMDatabase.m + sourceTree + <group> + + 669EAE7DE1ED17F9C051F30D + + includeInIndex + 1 + isa + PBXFileReference + lastKnownFileType + sourcecode.c.h + name + AFSecurityPolicy.h + path + AFNetworking/AFSecurityPolicy.h + sourceTree + <group> + + 66A9540760E965F58EA271D9 + + fileRef + 546CBE54C8042B64E57CFE44 + isa + PBXBuildFile + + 66E3A7D3E017E03A74EB7F95 + + fileRef + C1117E2F0150481788D938F2 + isa + PBXBuildFile + + 6871CC4088D36CC9FA1A68A2 + + includeInIndex + 1 + isa + PBXFileReference + lastKnownFileType + sourcecode.c.h + name + Bootstrap.h + path + src/runtime/Classes/Bootstrap.h + sourceTree + <group> + + 689E71881C7A7E0CD0E3B7AF + + buildActionMask + 2147483647 + files + + F9EAEF9FC3454DA72C3A9AFD + BE1A4AFE81B70CD36F6CA796 + 70AE5CB28488876F1C8D6ADE + D6E244B591B684EAF6EC227F + FFC195D25171B1330A3E38A2 + DE4CC53A9D56B0817F67127B + B1A55E792360098E9BB6A6A1 + 22669C9937AD12B16D26BBD6 + 9698B91C1658656846931E00 + 3F8ED30C239BAFDD5B8DFF60 + 84096BD095D429CA50F5AF53 + 0CA8A045EE47A2291C7304E2 + 7F46BF93B04E744E49FBE7A1 + AEDACF7508E7EA00D2158F31 + EDFACE50892F79E87647CBED + + isa + PBXSourcesBuildPhase + runOnlyForDeploymentPostprocessing + 0 + + 6914D820882607BBC74E1C6C + + includeInIndex + 1 + isa + PBXFileReference + name + iterator.cc + path + table/iterator.cc + sourceTree + <group> + + 691AD669B45CD24586817605 + + children + + F05F2BB273021B735FCA7575 + 924B19B4B3E5C8F127FCFA65 + A3B73F738CF58459F9A0A978 + 953BBF7EEA4B94E552FF1031 + 154045BA6367553FBB8C1A76 + 7ADF52066E703AFEB43EEAD7 + C856BC052BAA0CD252EC9990 + 954A5890AD5BE684A2A12315 + C89CFFFC2C903CF2D3DCA125 + 379EDEE95B52C97052942DC8 + C1D97FD9ADE54714DD83CCD9 + 1ECDBC93F6B81E068C62FC47 + 3C5A96D689E3ADAFEE73A1B8 + 8844F3EBAE61DCAB0FD2B50C + 12651ADB50AA76461BF5272A + 6160490FB9FD266A240C709A + 6C07D3845C8008A011D639C6 + + isa + PBXGroup + name + UIKit + sourceTree + <group> + + 6975B09D41EAAC0E44FAD082 + + includeInIndex + 1 + isa + PBXFileReference + lastKnownFileType + sourcecode.c.objc + name + AbstractMessage.m + path + src/runtime/Classes/AbstractMessage.m + sourceTree + <group> + + 69B5C61F0BA419F844533310 + + includeInIndex + 1 + isa + PBXFileReference + lastKnownFileType + sourcecode.c.objc + name + MWPhoto.m + path + MWPhotoBrowser/Classes/MWPhoto.m + sourceTree + <group> + + 6A48B1D11FDDAF84A874CC7B + + includeInIndex + 1 + isa + PBXFileReference + lastKnownFileType + sourcecode.c.h + name + iterator.h + path + include/leveldb/iterator.h + sourceTree + <group> + + 6A6FD52A5C67C666EB8B636B + + fileRef + AFF5674E2C7106B5D373EAC2 + isa + PBXBuildFile + settings + + COMPILER_FLAGS + -DOS_OBJECT_USE_OBJC=0 + + + 6A7151943CF676671302C872 + + includeInIndex + 1 + isa + PBXFileReference + lastKnownFileType + sourcecode.c.h + name + slice.h + path + include/leveldb/slice.h + sourceTree + <group> + + 6A7A1115E1E14736728165AE + + fileRef + F9E4B238BC99105235F99C68 + isa + PBXBuildFile + + 6A817E6BB7C645D1AC92FAB0 + + includeInIndex + 1 + isa + PBXFileReference + lastKnownFileType + sourcecode.c.objc + name + ConcreteExtensionField.m + path + src/runtime/Classes/ConcreteExtensionField.m + sourceTree + <group> + + 6AA9328DE75F77A4949E306C + + includeInIndex + 1 + isa + PBXFileReference + lastKnownFileType + sourcecode.c.h + name + Utilities.h + path + src/runtime/Classes/Utilities.h + sourceTree + <group> + + 6AAD773CF99897A09D77F12D + + includeInIndex + 1 + isa + PBXFileReference + name + leveldb_main.cc + path + db/leveldb_main.cc + sourceTree + <group> + + 6B695B4DF68F0B3D11B4F5E5 + + includeInIndex + 1 + isa + PBXFileReference + lastKnownFileType + text.xcconfig + path + Pods-ProtocolBuffers.xcconfig + sourceTree + <group> + + 6C07D3845C8008A011D639C6 + + includeInIndex + 1 + isa + PBXFileReference + lastKnownFileType + sourcecode.c.objc + name + UIWebView+AFNetworking.m + path + UIKit+AFNetworking/UIWebView+AFNetworking.m + sourceTree + <group> + + 6CAA5935EFAA40E3B141E12E + + includeInIndex + 1 + isa + PBXFileReference + lastKnownFileType + sourcecode.c.objc + name + AFHTTPRequestOperation.m + path + AFNetworking/AFHTTPRequestOperation.m + sourceTree + <group> + + 6CDC6879AF78DCDE258DC7AF + + includeInIndex + 1 + isa + PBXFileReference + name + port_posix.cc + path + port/port_posix.cc + sourceTree + <group> + + 6D275BAAE9C0A621F74877ED + + baseConfigurationReference + CC57503D74577BEA95AD137D + buildSettings + + ALWAYS_SEARCH_USER_PATHS + NO + COPY_PHASE_STRIP + YES + DSTROOT + /tmp/xcodeproj.dst + GCC_PRECOMPILE_PREFIX_HEADER + YES + GCC_PREFIX_HEADER + Target Support Files/Pods-AFNetworking/Pods-AFNetworking-prefix.pch + INSTALL_PATH + $(BUILT_PRODUCTS_DIR) + IPHONEOS_DEPLOYMENT_TARGET + 6.0 + OTHER_CFLAGS + + -DNS_BLOCK_ASSERTIONS=1 + $(inherited) + + OTHER_CPLUSPLUSFLAGS + + -DNS_BLOCK_ASSERTIONS=1 + $(inherited) + + OTHER_LDFLAGS + + OTHER_LIBTOOLFLAGS + + PRODUCT_NAME + $(TARGET_NAME) + PUBLIC_HEADERS_FOLDER_PATH + $(TARGET_NAME) + SDKROOT + iphoneos + SKIP_INSTALL + YES + VALIDATE_PRODUCT + YES + + isa + XCBuildConfiguration + name + Release + + 6D29B63CC100E45C7425A5A3 + + fileRef + B0C9A3B700D043167657927B + isa + PBXBuildFile + + 6D4610683470F0D825193013 + + includeInIndex + 1 + isa + PBXFileReference + lastKnownFileType + text.xcconfig + path + Pods-FMDB-Private.xcconfig + sourceTree + <group> + + 6D5D05C03292EC531E62C2F8 + + includeInIndex + 1 + isa + PBXFileReference + lastKnownFileType + sourcecode.c.objc + name + HPGrowingTextView.m + path + class/HPGrowingTextView.m + sourceTree + <group> + + 6D8E0BE5DCD72AF477C04A4E + + includeInIndex + 1 + isa + PBXFileReference + lastKnownFileType + sourcecode.c.h + name + HPGrowingTextView.h + path + class/HPGrowingTextView.h + sourceTree + <group> + + 6D956C6D6E6AF865A3CE2D49 + + includeInIndex + 1 + isa + PBXFileReference + lastKnownFileType + sourcecode.c.h + name + GeneratedMessageBuilder.h + path + src/runtime/Classes/GeneratedMessageBuilder.h + sourceTree + <group> + + 6DAA7E603B07D3FCAB05E6FB + + fileRef + 21F53906ABFA0F22EF18210B + isa + PBXBuildFile + + 6E62D46280CC328E94E46521 + + includeInIndex + 1 + isa + PBXFileReference + lastKnownFileType + sourcecode.c.objc + name + CodedOutputStream.m + path + src/runtime/Classes/CodedOutputStream.m + sourceTree + <group> + + 6ECCB645A8F8ED5BE9077872 + + includeInIndex + 1 + isa + PBXFileReference + name + table.cc + path + table/table.cc + sourceTree + <group> + + 6EF9945F9FE83F8CE273C341 + + fileRef + 6D8E0BE5DCD72AF477C04A4E + isa + PBXBuildFile + + 6F3E1CB2CC75A3ADB97053BF + + fileRef + 7EFCC14C3250B082B9F7133B + isa + PBXBuildFile + settings + + COMPILER_FLAGS + -DOS_OBJECT_USE_OBJC=0 + + + 6F988C5FD6B631998BB380B8 + + fileRef + 72D9AD46C3FA92963D7F2328 + isa + PBXBuildFile + + 6FA48799977EE9A8D2029E9A + + fileRef + B96501197C22DD4EE943EC8B + isa + PBXBuildFile + settings + + COMPILER_FLAGS + -DOS_MACOSX -DLEVELDB_PLATFORM_POSIX -fno-objc-arc + + + 6FBF81F6138401E0F4C51799 + + includeInIndex + 1 + isa + PBXFileReference + lastKnownFileType + sourcecode.c.objc + name + GeneratedMessage.m + path + src/runtime/Classes/GeneratedMessage.m + sourceTree + <group> + + 6FC71B102CAE9873DADE34D5 + + includeInIndex + 1 + isa + PBXFileReference + lastKnownFileType + sourcecode.c.objc + name + DACircularProgressView.m + path + DACircularProgress/DACircularProgressView.m + sourceTree + <group> + + 6FF528D39989A2C35688A3DA + + includeInIndex + 1 + isa + PBXFileReference + lastKnownFileType + text.xcconfig + path + Pods-PSTCollectionView-Private.xcconfig + sourceTree + <group> + + 709DF1D98B3C9C42CAF24380 + + explicitFileType + archive.ar + includeInIndex + 0 + isa + PBXFileReference + path + libPods-AFNetworking.a + sourceTree + BUILT_PRODUCTS_DIR + + 70A5CBFB8AB58A3998482FF0 + + fileRef + 6672134C5065CC7C0DF1C7C7 + isa + PBXBuildFile + settings + + COMPILER_FLAGS + -DOS_OBJECT_USE_OBJC=0 + + + 70AE5CB28488876F1C8D6ADE + + fileRef + BAAE0FCC823CAB821068161E + isa + PBXBuildFile + settings + + COMPILER_FLAGS + -DOS_OBJECT_USE_OBJC=0 + + + 70FCEA8DA45D1600994D3464 + + fileRef + 17E406215ACE33340EE78A51 + isa + PBXBuildFile + + 71719F88BF2DF73256F6D359 + + explicitFileType + archive.ar + includeInIndex + 0 + isa + PBXFileReference + path + libPods-SDWebImage.a + sourceTree + BUILT_PRODUCTS_DIR + + 72D9AD46C3FA92963D7F2328 + + includeInIndex + 1 + isa + PBXFileReference + lastKnownFileType + sourcecode.c.objc + name + MutableField.m + path + src/runtime/Classes/MutableField.m + sourceTree + <group> + + 730BE8365656FDFCEAE2DF24 + + baseConfigurationReference + 25E731136E9378DFA707E0CA + buildSettings + + ALWAYS_SEARCH_USER_PATHS + NO + COPY_PHASE_STRIP + YES + DSTROOT + /tmp/xcodeproj.dst + GCC_PRECOMPILE_PREFIX_HEADER + YES + GCC_PREFIX_HEADER + Target Support Files/Pods-MWPhotoBrowser/Pods-MWPhotoBrowser-prefix.pch + INSTALL_PATH + $(BUILT_PRODUCTS_DIR) + IPHONEOS_DEPLOYMENT_TARGET + 6.0 + OTHER_CFLAGS + + -DNS_BLOCK_ASSERTIONS=1 + $(inherited) + + OTHER_CPLUSPLUSFLAGS + + -DNS_BLOCK_ASSERTIONS=1 + $(inherited) + + OTHER_LDFLAGS + + OTHER_LIBTOOLFLAGS + + PRODUCT_NAME + $(TARGET_NAME) + PUBLIC_HEADERS_FOLDER_PATH + $(TARGET_NAME) + SDKROOT + iphoneos + SKIP_INSTALL + YES + VALIDATE_PRODUCT + YES + + isa + XCBuildConfiguration + name + Release + + 735A4AC8A7FDACB8D2CB8D36 + + buildConfigurations + + 2BC5038DF6D7CEDECB6EB489 + F3D3BE29D7966D70DE8D8E45 + + defaultConfigurationIsVisible + 0 + defaultConfigurationName + Release + isa + XCConfigurationList + + 74B7CC8F615847035EDBBE6D + + fileRef + 355987259D3D4D8C6ED844AC + isa + PBXBuildFile + + 74D974F59BC8193D74C5DDD2 + + includeInIndex + 1 + isa + PBXFileReference + lastKnownFileType + sourcecode.c.objc + path + Pods-AFNetworking-dummy.m + sourceTree + <group> + + 74DC8A4071B473E99802DAD1 + + includeInIndex + 1 + isa + PBXFileReference + lastKnownFileType + sourcecode.c.objc + name + AbstractMessageBuilder.m + path + src/runtime/Classes/AbstractMessageBuilder.m + sourceTree + <group> + + 752B4F74095974C4652C4AA1 + + includeInIndex + 1 + isa + PBXFileReference + name + format.cc + path + table/format.cc + sourceTree + <group> + + 7662894EE22A63E012D37362 + + buildActionMask + 2147483647 + files + + A59B212F1FC98F8D1F61442F + 66077F98AAB96EA20A74BC27 + 0C29014DB4725172127EB83B + 5A64F59DD84722FB401FA6CF + 86364F4D2F741D4ABD270983 + + isa + PBXFrameworksBuildPhase + runOnlyForDeploymentPostprocessing + 0 + + 76C0D313B14653EC632FC7FA + + fileRef + 10184A70DD0CFEA6D44A466D + isa + PBXBuildFile + + 78132618E256BD59BCFB2283 + + fileRef + B894532EF13442EF355249F8 + isa + PBXBuildFile + settings + + COMPILER_FLAGS + -DOS_OBJECT_USE_OBJC=0 + + + 7879CDC65866A1CC80645283 + + fileRef + 5B5AEE1888F87E8B26E3B489 + isa + PBXBuildFile + + 7AAB7FFD11BA24CE1D781C97 + + isa + PBXTargetDependency + name + Pods-DACircularProgress + target + 5BC12A63DA507D16082F87B8 + targetProxy + 6591C2B8DB6C61C21963E2E8 + + 7AD2F899ED0331F97A7CF969 + + includeInIndex + 1 + isa + PBXFileReference + lastKnownFileType + sourcecode.c.objc + name + Descriptor.pb.m + path + src/runtime/Classes/Descriptor.pb.m + sourceTree + <group> + + 7ADF52066E703AFEB43EEAD7 + + includeInIndex + 1 + isa + PBXFileReference + lastKnownFileType + sourcecode.c.objc + name + UIAlertView+AFNetworking.m + path + UIKit+AFNetworking/UIAlertView+AFNetworking.m + sourceTree + <group> + + 7B131D9B353CAF0C8595C9DB + + includeInIndex + 1 + isa + PBXFileReference + lastKnownFileType + sourcecode.c.objc + name + PSTCollectionViewItemKey.m + path + PSTCollectionView/PSTCollectionViewItemKey.m + sourceTree + <group> + + 7B699AAD05008839A2F61832 + + fileRef + 3EC4DCED927DA0E602EDB8F1 + isa + PBXBuildFile + + 7C36E10C0195774F43983480 + + includeInIndex + 1 + isa + PBXFileReference + lastKnownFileType + sourcecode.c.objc + name + UnknownFieldSet.m + path + src/runtime/Classes/UnknownFieldSet.m + sourceTree + <group> + + 7C4C2D9CE27785732081B6A3 + + includeInIndex + 1 + isa + PBXFileReference + lastKnownFileType + sourcecode.c.objc + name + AFURLResponseSerialization.m + path + AFNetworking/AFURLResponseSerialization.m + sourceTree + <group> + + 7CD0C9C43D74FBBEEF9678C2 + + children + + A7C710B0531AD9B9F8BF4EEF + C34261195314A22D360C684C + D8A205F92D93FD2738602AB0 + 92C088AAAAC36DD58EF9052F + + isa + PBXGroup + name + Support Files + path + ../Target Support Files/Pods-SDWebImage + sourceTree + <group> + + 7D3D2A4CCBCE96813BD74C8F + + fileRef + 6AA9328DE75F77A4949E306C + isa + PBXBuildFile + + 7E1258B7E1E85AF1FEE532FC + + fileRef + 2CFF4C9145609587718F8584 + isa + PBXBuildFile + + 7E14A75597ED49D4E36A6726 + + buildActionMask + 2147483647 + files + + B2F5F4AA758E568F3DE3AAFF + 207EDE5354467A76ACAA0F46 + 6A7A1115E1E14736728165AE + B0AE50EB835F578EB1F0DF39 + D2E4AF4B3D0853C3C87E4036 + 4293BA942D0258CD05084577 + 47B3F8EE8E24DA3833D634DA + 16EE467E350A17008126F601 + D5DFA9D7D827C73FD0C51426 + AD535EBB8CFB044B82F4DB45 + 58B1FC1184E0438262917355 + 8B381AF285F36CEC185ED310 + 9F7BB164CCA2B3BB8F4B3E5A + E68C2FE29EBBB8B8723DB891 + + isa + PBXHeadersBuildPhase + runOnlyForDeploymentPostprocessing + 0 + + 7E3C0F37DA1306281ADF59F9 + + fileRef + 5E532C2FE266B181F2A33B15 + isa + PBXBuildFile + + 7E4D46311C2E01A909F2C29B + + includeInIndex + 1 + isa + PBXFileReference + lastKnownFileType + sourcecode.c.objc + name + SCLButton.m + path + SCLAlertView/SCLButton.m + sourceTree + <group> + + 7EAEF684C195D3DDDC8A6111 + + includeInIndex + 1 + isa + PBXFileReference + name + filter_block.cc + path + table/filter_block.cc + sourceTree + <group> + + 7EFCC14C3250B082B9F7133B + + includeInIndex + 1 + isa + PBXFileReference + lastKnownFileType + sourcecode.c.objc + name + FMDatabaseQueue.m + path + src/fmdb/FMDatabaseQueue.m + sourceTree + <group> + + 7F38231A1C35E330BAB7FA3C + + includeInIndex + 1 + isa + PBXFileReference + lastKnownFileType + sourcecode.c.objc + name + PSTCollectionViewData.m + path + PSTCollectionView/PSTCollectionViewData.m + sourceTree + <group> + + 7F46BF93B04E744E49FBE7A1 + + fileRef + D2D56399A17A7F7607BDEE81 + isa + PBXBuildFile + settings + + COMPILER_FLAGS + -DOS_OBJECT_USE_OBJC=0 + + + 7F95CB24E9214EE56C3D857F + + containerPortal + 32F15B3A8A99ACC37FCE0E4A + isa + PBXContainerItemProxy + proxyType + 1 + remoteGlobalIDString + 133A25A0D319725FEC1884B0 + remoteInfo + Pods-MWPhotoBrowser + + 7FCBFCCCDE72A3B0F546D46D + + fileRef + FD5E5F030A7222CD04099C96 + isa + PBXBuildFile + + 801EA99ACD0E9DF3D8C8B053 + + includeInIndex + 1 + isa + PBXFileReference + name + cache.cc + path + util/cache.cc + sourceTree + <group> + + 80C3C93A0CCA916B9A547AC0 + + includeInIndex + 1 + isa + PBXFileReference + name + db_iter.cc + path + db/db_iter.cc + sourceTree + <group> + + 80DB483BB0FCA8DFFF623FBC + + includeInIndex + 1 + isa + PBXFileReference + lastKnownFileType + sourcecode.c.h + name + FMDatabaseQueue.h + path + src/fmdb/FMDatabaseQueue.h + sourceTree + <group> + + 81BB69CFFC97F65D74173A39 + + fileRef + AF0270B25935FACF1A187AEF + isa + PBXBuildFile + settings + + COMPILER_FLAGS + -DOS_OBJECT_USE_OBJC=0 + + + 81C7539C5773E295433603AB + + buildConfigurationList + 735A4AC8A7FDACB8D2CB8D36 + buildPhases + + E58D5B14872390B2BD156281 + 488E191A992E650602A6E668 + 2FB8A6CD2750F5411D32E044 + + buildRules + + dependencies + + isa + PBXNativeTarget + name + Pods-FMDB + productName + Pods-FMDB + productReference + 5B478B6CBEC7E1D741845A85 + productType + com.apple.product-type.library.static + + 82CE53307F70BF005035BCD4 + + buildActionMask + 2147483647 + files + + F0AFCE32A60AB10F7FC8AB8A + E90FB6F54C2B3DFA6B8E182B + 597ACAAD687A7126693DBADB + CB6F531783D1B86BF197D0DD + B19FC54FCF071A31A30B99D2 + E67941409329CEE9F940F5FB + B6D4ED35722A9748E9BC2E0E + 48CE8DAE1D7962A7FCABE465 + BFC558A4791B470449398D99 + 5F4E89B41EA219EB1540D95A + E5E2B268AD581DF7A0A6581F + D4A3FF96418E6E69081F1910 + C0070AB1CF15DD13E9C1CF9A + 35C65B49A6538028143BA3F1 + F82253E01F19CAC8A8F94000 + + isa + PBXHeadersBuildPhase + runOnlyForDeploymentPostprocessing + 0 + + 83B6A3A2E938078CB6F9068F + + includeInIndex + 1 + isa + PBXFileReference + lastKnownFileType + sourcecode.c.h + name + write_batch.h + path + include/leveldb/write_batch.h + sourceTree + <group> + + 8405C9828FBD675691D7A099 + + includeInIndex + 1 + isa + PBXFileReference + lastKnownFileType + sourcecode.c.objc + name + PSTGridLayoutSection.m + path + PSTCollectionView/PSTGridLayoutSection.m + sourceTree + <group> + + 84096BD095D429CA50F5AF53 + + fileRef + 4BCD84D3892CB1B0EAA4D794 + isa + PBXBuildFile + settings + + COMPILER_FLAGS + -DOS_OBJECT_USE_OBJC=0 + + + 844B3136436D2C2877AB3C1C + + fileRef + AFC6280004D82AED47282BDB + isa + PBXBuildFile + + 84E01E61624B40A8BC4FE0F3 + + fileRef + A7F7B9F8095B1921610D00B3 + isa + PBXBuildFile + settings + + COMPILER_FLAGS + -DOS_OBJECT_USE_OBJC=0 + + + 8533DD5601B6AA7F353167C5 + + children + + 248D08C04B2C14981063CD8E + 6FF528D39989A2C35688A3DA + 38F06966FE24AB86B612DD3B + B782F08D51BFC8B5240B3287 + + isa + PBXGroup + name + Support Files + path + ../Target Support Files/Pods-PSTCollectionView + sourceTree + <group> + + 85859F6FA181E668B7F7D0C7 + + includeInIndex + 1 + isa + PBXFileReference + lastKnownFileType + sourcecode.c.h + name + AFHTTPSessionManager.h + path + AFNetworking/AFHTTPSessionManager.h + sourceTree + <group> + + 8586A2835B816D33F293D914 + + buildActionMask + 2147483647 + files + + 16AF482DD25DFC1DBE337AFB + + isa + PBXSourcesBuildPhase + runOnlyForDeploymentPostprocessing + 0 + + 86364F4D2F741D4ABD270983 + + fileRef + 8A2F10DCB98B2F4A20118541 + isa + PBXBuildFile + + 868E2549F34C6C9DA7D98A7A + + fileRef + A70D8225F43007DAD1FB9CD2 + isa + PBXBuildFile + + 86B67FBDC525A9C65FEA3B4E + + fileRef + 8EE7A75E274391BF68ED4413 + isa + PBXBuildFile + settings + + COMPILER_FLAGS + -DOS_MACOSX -DLEVELDB_PLATFORM_POSIX -fno-objc-arc + + + 8713D88CE5ED4B4CC40A3DC5 + + includeInIndex + 1 + isa + PBXFileReference + name + table_cache.cc + path + db/table_cache.cc + sourceTree + <group> + + 8844B09E07162D932351DFDB + + includeInIndex + 1 + isa + PBXFileReference + lastKnownFileType + sourcecode.c.objc + name + UnknownFieldSetBuilder.m + path + src/runtime/Classes/UnknownFieldSetBuilder.m + sourceTree + <group> + + 8844F3EBAE61DCAB0FD2B50C + + includeInIndex + 1 + isa + PBXFileReference + lastKnownFileType + sourcecode.c.h + name + UIRefreshControl+AFNetworking.h + path + UIKit+AFNetworking/UIRefreshControl+AFNetworking.h + sourceTree + <group> + + 895402CC98EE23BD0D5B83AB + + fileRef + 954A5890AD5BE684A2A12315 + isa + PBXBuildFile + + 899CAF7A6402EF48A2DB63B0 + + includeInIndex + 1 + isa + PBXFileReference + lastKnownFileType + text.xcconfig + path + Pods.release.xcconfig + sourceTree + <group> + + 8A238155E0A0CF2D867C877F + + fileRef + 85859F6FA181E668B7F7D0C7 + isa + PBXBuildFile + + 8A2F10DCB98B2F4A20118541 + + isa + PBXFileReference + lastKnownFileType + wrapper.framework + name + SystemConfiguration.framework + path + Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS7.1.sdk/System/Library/Frameworks/SystemConfiguration.framework + sourceTree + DEVELOPER_DIR + + 8AAB857E284C046BD52EDCBC + + includeInIndex + 1 + isa + PBXFileReference + lastKnownFileType + text.xcconfig + path + Pods-SCLAlertView-Objective-C-Private.xcconfig + sourceTree + <group> + + 8AE8F74A62F028021D6AB42E + + fileRef + F29A397831A0F7E88AFF6C4F + isa + PBXBuildFile + settings + + COMPILER_FLAGS + -DOS_OBJECT_USE_OBJC=0 + + + 8B12F7F1DCB5D368319E8A3A + + includeInIndex + 1 + isa + PBXFileReference + lastKnownFileType + sourcecode.c.objc + name + AFHTTPRequestOperationManager.m + path + AFNetworking/AFHTTPRequestOperationManager.m + sourceTree + <group> + + 8B381AF285F36CEC185ED310 + + fileRef + 5ACC307A39A4549B8E4B31CC + isa + PBXBuildFile + + 8BCED965400307CB87F69224 + + includeInIndex + 1 + isa + PBXFileReference + lastKnownFileType + sourcecode.c.h + name + SCLAlertViewResponder.h + path + SCLAlertView/SCLAlertViewResponder.h + sourceTree + <group> + + 8CE38F828C808EF79A144EFB + + includeInIndex + 1 + isa + PBXFileReference + lastKnownFileType + sourcecode.c.objc + name + NSIndexPath+PSTCollectionViewAdditions.m + path + PSTCollectionView/NSIndexPath+PSTCollectionViewAdditions.m + sourceTree + <group> + + 8D6E7F6E401465F9A4C0A651 + + fileRef + 7AD2F899ED0331F97A7CF969 + isa + PBXBuildFile + + 8D7B75790F25EBFA869D3042 + + includeInIndex + 1 + isa + PBXFileReference + lastKnownFileType + sourcecode.c.h + name + DACircularProgressView.h + path + DACircularProgress/DACircularProgressView.h + sourceTree + <group> + + 8D9482B6C87566E1994EBCA2 + + includeInIndex + 1 + isa + PBXFileReference + name + hash.cc + path + util/hash.cc + sourceTree + <group> + + 8E7632F11DF0C77693FCC98F + + fileRef + E9FE05F74DA1E7F24F4F3325 + isa + PBXBuildFile + + 8EB9680B2C763E85EF347AB4 + + fileRef + C89CFFFC2C903CF2D3DCA125 + isa + PBXBuildFile + + 8EE7A75E274391BF68ED4413 + + includeInIndex + 1 + isa + PBXFileReference + name + status.cc + path + util/status.cc + sourceTree + <group> + + 8EED9532FCCFF04F90DF9029 + + children + + AD9E67453D61C1A792FC25AF + 30431FFB84F65FE60696E689 + 916DBA74F33694108E4C10F1 + 256AD2C6EA58C4053DF2AC1B + 1C51BF66DDDA9E648D4FB284 + BC1331C7F2BB36605A024EE3 + 899CAF7A6402EF48A2DB63B0 + + isa + PBXGroup + name + Pods + path + Target Support Files/Pods + sourceTree + <group> + + 8FC24A9C5749968730CC0338 + + includeInIndex + 1 + isa + PBXFileReference + lastKnownFileType + sourcecode.c.h + name + PSTCollectionViewCommon.h + path + PSTCollectionView/PSTCollectionViewCommon.h + sourceTree + <group> + + 90AB4BEE583FB7BCA4A0AD3D + + includeInIndex + 1 + isa + PBXFileReference + name + crc32c.cc + path + util/crc32c.cc + sourceTree + <group> + + 90D60C6B788237734C94B78C + + baseConfigurationReference + C445ADD65DE09EA6923A57DB + buildSettings + + ALWAYS_SEARCH_USER_PATHS + NO + COPY_PHASE_STRIP + YES + DSTROOT + /tmp/xcodeproj.dst + GCC_PRECOMPILE_PREFIX_HEADER + YES + GCC_PREFIX_HEADER + Target Support Files/Pods-ProtocolBuffers/Pods-ProtocolBuffers-prefix.pch + INSTALL_PATH + $(BUILT_PRODUCTS_DIR) + IPHONEOS_DEPLOYMENT_TARGET + 6.0 + OTHER_CFLAGS + + -DNS_BLOCK_ASSERTIONS=1 + $(inherited) + + OTHER_CPLUSPLUSFLAGS + + -DNS_BLOCK_ASSERTIONS=1 + $(inherited) + + OTHER_LDFLAGS + + OTHER_LIBTOOLFLAGS + + PRODUCT_NAME + $(TARGET_NAME) + PUBLIC_HEADERS_FOLDER_PATH + $(TARGET_NAME) + SDKROOT + iphoneos + SKIP_INSTALL + YES + VALIDATE_PRODUCT + YES + + isa + XCBuildConfiguration + name + Release + + 913FED115D82825A3D32EBE3 + + includeInIndex + 1 + isa + PBXFileReference + lastKnownFileType + sourcecode.c.h + name + Field.h + path + src/runtime/Classes/Field.h + sourceTree + <group> + + 916DBA74F33694108E4C10F1 + + includeInIndex + 1 + isa + PBXFileReference + lastKnownFileType + sourcecode.c.objc + path + Pods-dummy.m + sourceTree + <group> + + 917A9FEEA37059C3E2F9B3FB + + includeInIndex + 1 + isa + PBXFileReference + lastKnownFileType + wrapper.plug-in + name + MWPhotoBrowser.bundle + path + MWPhotoBrowser/MWPhotoBrowser.bundle + sourceTree + <group> + + 91AC0D09CF77F17A5B64C763 + + children + + D9A9FC0E7A4F50A49361D701 + 7CD0C9C43D74FBBEEF9678C2 + + isa + PBXGroup + name + SDWebImage + path + SDWebImage + sourceTree + <group> + + 924B19B4B3E5C8F127FCFA65 + + includeInIndex + 1 + isa + PBXFileReference + lastKnownFileType + sourcecode.c.objc + name + AFNetworkActivityIndicatorManager.m + path + UIKit+AFNetworking/AFNetworkActivityIndicatorManager.m + sourceTree + <group> + + 925166FE3DABD3B90304140A + + includeInIndex + 1 + isa + PBXFileReference + lastKnownFileType + sourcecode.c.h + name + AFURLSessionManager.h + path + AFNetworking/AFURLSessionManager.h + sourceTree + <group> + + 929748361FA52C5C9E57FF1B + + includeInIndex + 1 + isa + PBXFileReference + lastKnownFileType + sourcecode.c.objc + name + Field.m + path + src/runtime/Classes/Field.m + sourceTree + <group> + + 92C088AAAAC36DD58EF9052F + + includeInIndex + 1 + isa + PBXFileReference + lastKnownFileType + sourcecode.c.h + path + Pods-SDWebImage-prefix.pch + sourceTree + <group> + + 92C42F814B71E9746F2C5635 + + includeInIndex + 1 + isa + PBXFileReference + lastKnownFileType + sourcecode.c.objc + name + UIImageView+WebCache.m + path + SDWebImage/UIImageView+WebCache.m + sourceTree + <group> + + 93C022C444EF438A285333B2 + + fileRef + C1D97FD9ADE54714DD83CCD9 + isa + PBXBuildFile + + 9410F4786A0143E3503C0238 + + includeInIndex + 1 + isa + PBXFileReference + lastKnownFileType + sourcecode.c.h + name + PSTCollectionViewLayout+Internals.h + path + PSTCollectionView/PSTCollectionViewLayout+Internals.h + sourceTree + <group> + + 9429544EDF5304F7822D624C + + fileRef + 7ADF52066E703AFEB43EEAD7 + isa + PBXBuildFile + + 946BDDF26C67A082A4235D06 + + fileRef + 134F09CA937A8239AF65247E + isa + PBXBuildFile + + 94A05A05CBF0EBB3D68909AF + + includeInIndex + 1 + isa + PBXFileReference + lastKnownFileType + sourcecode.c.h + name + MWCaptionView.h + path + MWPhotoBrowser/Classes/MWCaptionView.h + sourceTree + <group> + + 94A8AFC08B5E086819C308EC + + fileRef + 189A7D5B9253201FCF76E504 + isa + PBXBuildFile + + 94D826954323FB898ADC26D0 + + includeInIndex + 1 + isa + PBXFileReference + lastKnownFileType + sourcecode.c.h + name + MWPhoto.h + path + MWPhotoBrowser/Classes/MWPhoto.h + sourceTree + <group> + + 953B4C95F2441080647FB12E + + fileRef + 929748361FA52C5C9E57FF1B + isa + PBXBuildFile + + 953BBF7EEA4B94E552FF1031 + + includeInIndex + 1 + isa + PBXFileReference + lastKnownFileType + sourcecode.c.objc + name + UIActivityIndicatorView+AFNetworking.m + path + UIKit+AFNetworking/UIActivityIndicatorView+AFNetworking.m + sourceTree + <group> + + 954A5890AD5BE684A2A12315 + + includeInIndex + 1 + isa + PBXFileReference + lastKnownFileType + sourcecode.c.objc + name + UIButton+AFNetworking.m + path + UIKit+AFNetworking/UIButton+AFNetworking.m + sourceTree + <group> + + 954E9CDF1D4B885EE1B34569 + + fileRef + 379EDEE95B52C97052942DC8 + isa + PBXBuildFile + + 960C1B0DC2E1B1011490DCCA + + includeInIndex + 1 + isa + PBXFileReference + lastKnownFileType + sourcecode.c.h + name + dumpfile.h + path + include/leveldb/dumpfile.h + sourceTree + <group> + + 9698B91C1658656846931E00 + + fileRef + 1D954353E6F68F9112161DBF + isa + PBXBuildFile + settings + + COMPILER_FLAGS + -DOS_OBJECT_USE_OBJC=0 + + + 96C9887F2629E485953143B9 + + fileRef + F05F2BB273021B735FCA7575 + isa + PBXBuildFile + + 96DF7F825B4E5D59980CEF80 + + includeInIndex + 1 + isa + PBXFileReference + name + testharness.cc + path + util/testharness.cc + sourceTree + <group> + + 96F1070F6D0E4D754CF9294B + + isa + PBXTargetDependency + name + Pods-HPGrowingTextView + target + 6360D6708B351012B4113963 + targetProxy + 04C2C3EE7F98B8E4F94ACA04 + + 97B7F767A50D4ABB1CCC4A9F + + fileRef + F0E45C93060176FF51747061 + isa + PBXBuildFile + settings + + COMPILER_FLAGS + -DOS_OBJECT_USE_OBJC=0 + + + 97EB22142C17FCFC08DBACC8 + + explicitFileType + archive.ar + includeInIndex + 0 + isa + PBXFileReference + path + libPods-ProtocolBuffers.a + sourceTree + BUILT_PRODUCTS_DIR + + 9816C87F1DDD73D2D8E2235C + + fileRef + A4BCFB832F151BB333475948 + isa + PBXBuildFile + + 98936A7C58EBE6A2962C4607 + + includeInIndex + 1 + isa + PBXFileReference + lastKnownFileType + sourcecode.c.h + name + Descriptor.pb.h + path + src/runtime/Classes/Descriptor.pb.h + sourceTree + <group> + + 98B6D5E9EFB0A69AD65B7598 + + includeInIndex + 1 + isa + PBXFileReference + lastKnownFileType + sourcecode.c.objc + name + PSTGridLayoutRow.m + path + PSTCollectionView/PSTGridLayoutRow.m + sourceTree + <group> + + 9911F290C4DF0CCEB9B3FAC5 + + fileRef + C990C35FAD9F51DCBD118D76 + isa + PBXBuildFile + + 993DE3DBE9B9B2FE96D70D49 + + includeInIndex + 1 + isa + PBXFileReference + lastKnownFileType + sourcecode.c.objc + path + Pods-SCLAlertView-Objective-C-dummy.m + sourceTree + <group> + + 99486657B6547FA998F7FE00 + + baseConfigurationReference + 25E731136E9378DFA707E0CA + buildSettings + + ALWAYS_SEARCH_USER_PATHS + NO + COPY_PHASE_STRIP + NO + DSTROOT + /tmp/xcodeproj.dst + GCC_DYNAMIC_NO_PIC + NO + GCC_OPTIMIZATION_LEVEL + 0 + GCC_PRECOMPILE_PREFIX_HEADER + YES + GCC_PREFIX_HEADER + Target Support Files/Pods-MWPhotoBrowser/Pods-MWPhotoBrowser-prefix.pch + GCC_PREPROCESSOR_DEFINITIONS + + DEBUG=1 + $(inherited) + + GCC_SYMBOLS_PRIVATE_EXTERN + NO + INSTALL_PATH + $(BUILT_PRODUCTS_DIR) + IPHONEOS_DEPLOYMENT_TARGET + 6.0 + OTHER_LDFLAGS + + OTHER_LIBTOOLFLAGS + + PRODUCT_NAME + $(TARGET_NAME) + PUBLIC_HEADERS_FOLDER_PATH + $(TARGET_NAME) + SDKROOT + iphoneos + SKIP_INSTALL + YES + + isa + XCBuildConfiguration + name + Debug + + 994FEDAB754303A9320036EA + + includeInIndex + 1 + isa + PBXFileReference + name + env.cc + path + util/env.cc + sourceTree + <group> + + 9988565EA7926C091DEE74B1 + + fileRef + CC748A2C78201671F1B5513E + isa + PBXBuildFile + + 99AE7BB5349DE93D2C8B95CD + + includeInIndex + 1 + isa + PBXFileReference + lastKnownFileType + sourcecode.c.h + name + PSTGridLayoutSection.h + path + PSTCollectionView/PSTGridLayoutSection.h + sourceTree + <group> + + 9A9B88BCEB4678DD93727B93 + + children + + 6D8E0BE5DCD72AF477C04A4E + 6D5D05C03292EC531E62C2F8 + DD04C9A6E193790AB5702BC1 + F90F234921C5A6988D8F29F4 + 526508973462BCD64B635E1F + + isa + PBXGroup + name + HPGrowingTextView + path + HPGrowingTextView + sourceTree + <group> + + 9AB9306524DC665A8F9B9720 + + buildConfigurations + + 2CF32DE5EB11E0DE3C1EDB94 + 0F8C1A3C28941B880470AD90 + + defaultConfigurationIsVisible + 0 + defaultConfigurationName + Release + isa + XCConfigurationList + + 9BE60A8CA8A01ECD8F4583C2 + + fileRef + 8BCED965400307CB87F69224 + isa + PBXBuildFile + + 9CA2D4A21195643A6E17B1B6 + + fileRef + 223837A87FA5DCB75ED915CA + isa + PBXBuildFile + + 9CCA7CBCA659AEB048CF0E90 + + fileRef + 8844B09E07162D932351DFDB + isa + PBXBuildFile + + 9DD82C0A7DA6BD87D0BEB9F8 + + includeInIndex + 1 + isa + PBXFileReference + lastKnownFileType + sourcecode.c.h + path + Pods-MBProgressHUD-prefix.pch + sourceTree + <group> + + 9E17A3BC7E0AFA7F1F1C1A69 + + fileRef + 2789D3C72809AAD6A403B520 + isa + PBXBuildFile + + 9E6165B67754BEA18EF7B637 + + isa + PBXTargetDependency + name + Pods-PSTCollectionView + target + B2CC9370F3764EE84221A3DA + targetProxy + D3AAEEDFBD8C160B71E49463 + + 9EACBA66AC00CFCEC1661305 + + buildConfigurations + + FBAE885B5A12097FDD72D80A + 90D60C6B788237734C94B78C + + defaultConfigurationIsVisible + 0 + defaultConfigurationName + Release + isa + XCConfigurationList + + 9ED83F250C61C92BDFCEF9DE + + includeInIndex + 1 + isa + PBXFileReference + lastKnownFileType + sourcecode.c.h + path + Pods-DACircularProgress-prefix.pch + sourceTree + <group> + + 9F5D3B0DED0285CBEE564F52 + + includeInIndex + 1 + isa + PBXFileReference + lastKnownFileType + sourcecode.c.h + name + MWGridViewController.h + path + MWPhotoBrowser/Classes/MWGridViewController.h + sourceTree + <group> + + 9F7BB164CCA2B3BB8F4B3E5A + + fileRef + 2664B96014E04470A26C3D9D + isa + PBXBuildFile + + 9FC24B0D25DBE3EF6712A044 + + fileRef + C5C87B64DB1567BAA02CAA8A + isa + PBXBuildFile + + A002E6C9939624372369F622 + + includeInIndex + 1 + isa + PBXFileReference + name + filter_policy.cc + path + util/filter_policy.cc + sourceTree + <group> + + A11C91177C7D6830D9E3D714 + + includeInIndex + 1 + isa + PBXFileReference + name + table_builder.cc + path + table/table_builder.cc + sourceTree + <group> + + A1E08F4C7CFB44F6C8515E9C + + fileRef + 7C36E10C0195774F43983480 + isa + PBXBuildFile + + A2459E0CB4C7BF82A90C946B + + fileRef + F691C7DF885835E30E5094F9 + isa + PBXBuildFile + + A31DBF5CE8480E4CAC587BED + + children + + 51FB13E9C1A4B9C76C2E2FAC + AFC6280004D82AED47282BDB + 2500C99B3FB11290FFFD347B + 7C4C2D9CE27785732081B6A3 + + isa + PBXGroup + name + Serialization + sourceTree + <group> + + A32268C080A7CB0A84DA87C0 + + includeInIndex + 1 + isa + PBXFileReference + lastKnownFileType + sourcecode.c.h + name + UIImageView+HighlightedWebCache.h + path + SDWebImage/UIImageView+HighlightedWebCache.h + sourceTree + <group> + + A3A6FCA5F26E01C518B63727 + + includeInIndex + 1 + isa + PBXFileReference + lastKnownFileType + sourcecode.c.h + path + Pods-HPGrowingTextView-prefix.pch + sourceTree + <group> + + A3B73F738CF58459F9A0A978 + + includeInIndex + 1 + isa + PBXFileReference + lastKnownFileType + sourcecode.c.h + name + UIActivityIndicatorView+AFNetworking.h + path + UIKit+AFNetworking/UIActivityIndicatorView+AFNetworking.h + sourceTree + <group> + + A3CC9FE7F7D3A97337FB28FD + + fileRef + D0223147AE81F668AF8A94BB + isa + PBXBuildFile + + A4076CCDEDD6B27F0F0B2CEC + + includeInIndex + 1 + isa + PBXFileReference + lastKnownFileType + sourcecode.c.h + name + MutableField.h + path + src/runtime/Classes/MutableField.h + sourceTree + <group> + + A42ADC337E4B5E17C00F6616 + + fileRef + EA8762D76449CE7876E8F132 + isa + PBXBuildFile + settings + + COMPILER_FLAGS + -DOS_MACOSX -DLEVELDB_PLATFORM_POSIX -fno-objc-arc + + + A4BCFB832F151BB333475948 + + includeInIndex + 1 + isa + PBXFileReference + lastKnownFileType + sourcecode.c.objc + path + Pods-leveldb-library-dummy.m + sourceTree + <group> + + A4F0C5321C168E3D41FC8A2A + + isa + PBXFileReference + lastKnownFileType + wrapper.framework + name + UIKit.framework + path + Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS7.1.sdk/System/Library/Frameworks/UIKit.framework + sourceTree + DEVELOPER_DIR + + A58116FD5C16C1F0CEB464D8 + + fileRef + 46084CECE5E6479249631903 + isa + PBXBuildFile + settings + + COMPILER_FLAGS + -DOS_MACOSX -DLEVELDB_PLATFORM_POSIX -fno-objc-arc + + + A5899C85DA3E096BB2B43934 + + children + + B066D77D37E751FDEC2B319B + D0223147AE81F668AF8A94BB + 8BCED965400307CB87F69224 + 44791A1DC8CBDB321013967D + 031A6739DE63A8B5C23C2C2A + 6605C580797700F2CB5BD172 + 41B7D6E5AE00DD9497F8E109 + 7E4D46311C2E01A909F2C29B + D6AE328B91D52C532428C353 + CC748A2C78201671F1B5513E + D53BD60EA11AB6C149ED398F + + isa + PBXGroup + name + SCLAlertView-Objective-C + path + SCLAlertView-Objective-C + sourceTree + <group> + + A598A41D5D2C489605FAE958 + + fileRef + 44791A1DC8CBDB321013967D + isa + PBXBuildFile + + A59B212F1FC98F8D1F61442F + + fileRef + C576E19B4146090A7A7B835E + isa + PBXBuildFile + + A5AD30701B4EEA9A8E582A8A + + buildActionMask + 2147483647 + files + + E247D4F351D9B7CF02DEB27E + 11E28228F469927B0D4BE3BB + 0D006504014BCFB940691563 + 1EB5EED28F13B582578C046D + B68790F5CB72380C68CA7D01 + 7879CDC65866A1CC80645283 + 07913D913A559DBEC47E490D + A2459E0CB4C7BF82A90C946B + CAF762070158A31E5714BF33 + FE619E7BA032E95A856F867C + 70FCEA8DA45D1600994D3464 + FB5BBC68625373C8219E8423 + E719AA1D6F4EF3E4E2C662DD + 94A8AFC08B5E086819C308EC + 1896F26A3AE7E0F78B862106 + 7E3C0F37DA1306281ADF59F9 + FBCC8ED4C06FBA17B993C2A7 + A8C938D2DB77B3FF1F5DEE06 + 4150DFA8C688167143510BB4 + 2B8CA4FFC42ED9343BEBF19D + 5A1345CE0ECC3404E6FA251A + 1EE8225012F97A9C456D1106 + 332AE27CA379C6B29497E05B + DFA296D550112B43C29F8A03 + 4A99FEF88DBDD45C34D0CEEC + 7D3D2A4CCBCE96813BD74C8F + F1C544C92D75F9E26C48066D + + isa + PBXHeadersBuildPhase + runOnlyForDeploymentPostprocessing + 0 + + A604ABA1E3E88ADBF1656250 + + buildActionMask + 2147483647 + files + + AF40A1B89AEC1AE8018D7C58 + E6C2B39C323DFE25B9EBD98C + 9FC24B0D25DBE3EF6712A044 + 16944116D1D304953B4BFF5A + 946BDDF26C67A082A4235D06 + 25EEC171E79E6F6D138830EB + 9E17A3BC7E0AFA7F1F1C1A69 + 844B3136436D2C2877AB3C1C + F0E4FE8FC41CF583255E5454 + BB21BDA4B3EF344733623D40 + AC9050AC72499AFCD60426CC + C2C6E0474786D3709DDC2F04 + 9429544EDF5304F7822D624C + 895402CC98EE23BD0D5B83AB + 954E9CDF1D4B885EE1B34569 + D3D41A60E1DFE3BCACCF72BD + 5FC96DEF4A95E3B34E908D1B + DC7BC349B35431AD23BBEBB9 + + isa + PBXSourcesBuildPhase + runOnlyForDeploymentPostprocessing + 0 + + A628A4BEF1965D3C2406CCF4 + + includeInIndex + 1 + isa + PBXFileReference + lastKnownFileType + sourcecode.c.h + name + SDWebImagePrefetcher.h + path + SDWebImage/SDWebImagePrefetcher.h + sourceTree + <group> + + A63ACBDB288925BE8E8032CC + + containerPortal + 32F15B3A8A99ACC37FCE0E4A + isa + PBXContainerItemProxy + proxyType + 1 + remoteGlobalIDString + B68C69F6738C61A824DDA397 + remoteInfo + Pods-AFNetworking + + A6E45E38279C209A79866A73 + + includeInIndex + 1 + isa + PBXFileReference + lastKnownFileType + sourcecode.c.h + name + c.h + path + include/leveldb/c.h + sourceTree + <group> + + A6F30E2A50EC157661A84DEF + + includeInIndex + 1 + isa + PBXFileReference + lastKnownFileType + sourcecode.c.objc + name + PSTCollectionViewLayout.m + path + PSTCollectionView/PSTCollectionViewLayout.m + sourceTree + <group> + + A70D8225F43007DAD1FB9CD2 + + includeInIndex + 1 + isa + PBXFileReference + lastKnownFileType + sourcecode.c.h + name + PSTCollectionViewFlowLayout.h + path + PSTCollectionView/PSTCollectionViewFlowLayout.h + sourceTree + <group> + + A712DD190C8A2DC1F6840E37 + + baseConfigurationReference + F0DA9628331484011ADCCEEE + buildSettings + + ALWAYS_SEARCH_USER_PATHS + NO + COPY_PHASE_STRIP + NO + DSTROOT + /tmp/xcodeproj.dst + GCC_DYNAMIC_NO_PIC + NO + GCC_OPTIMIZATION_LEVEL + 0 + GCC_PRECOMPILE_PREFIX_HEADER + YES + GCC_PREFIX_HEADER + Target Support Files/Pods-DACircularProgress/Pods-DACircularProgress-prefix.pch + GCC_PREPROCESSOR_DEFINITIONS + + DEBUG=1 + $(inherited) + + GCC_SYMBOLS_PRIVATE_EXTERN + NO + INSTALL_PATH + $(BUILT_PRODUCTS_DIR) + IPHONEOS_DEPLOYMENT_TARGET + 6.0 + OTHER_LDFLAGS + + OTHER_LIBTOOLFLAGS + + PRODUCT_NAME + $(TARGET_NAME) + PUBLIC_HEADERS_FOLDER_PATH + $(TARGET_NAME) + SDKROOT + iphoneos + SKIP_INSTALL + YES + + isa + XCBuildConfiguration + name + Debug + + A76D8B7CECD0A1A22035B322 + + includeInIndex + 1 + isa + PBXFileReference + lastKnownFileType + sourcecode.c.h + name + SDImageCache.h + path + SDWebImage/SDImageCache.h + sourceTree + <group> + + A7C710B0531AD9B9F8BF4EEF + + includeInIndex + 1 + isa + PBXFileReference + lastKnownFileType + text.xcconfig + path + Pods-SDWebImage.xcconfig + sourceTree + <group> + + A7DFB1C822356A2522821643 + + fileRef + A4F0C5321C168E3D41FC8A2A + isa + PBXBuildFile + + A7F7B9F8095B1921610D00B3 + + includeInIndex + 1 + isa + PBXFileReference + lastKnownFileType + sourcecode.c.objc + name + PSTCollectionViewCell.m + path + PSTCollectionView/PSTCollectionViewCell.m + sourceTree + <group> + + A82656F3FDA490D2C48608C5 + + fileRef + B38984288D16B98B2B0199C6 + isa + PBXBuildFile + + A8AAF46F5CFBA86AD0FA4690 + + fileRef + 5FD1AFC29DDCF9CCE15CDEBE + isa + PBXBuildFile + + A8C938D2DB77B3FF1F5DEE06 + + fileRef + 0474ED89B2559A9B9503ACFA + isa + PBXBuildFile + + A95C977833BC75ACC2FBDBE4 + + buildActionMask + 2147483647 + files + + 32070D04AC56830D11B96B3E + 43B36CA39A94A8B358609C33 + 0EC0B78B7B9E0258E437799F + 6D29B63CC100E45C7425A5A3 + E072575F13318B9926EE43AF + D948ABF29763F579D0916BD4 + + isa + PBXFrameworksBuildPhase + runOnlyForDeploymentPostprocessing + 0 + + A95E1DE563AD958A41A2F4D0 + + fileRef + D2D45AA58D26CAE1C3C7C6C8 + isa + PBXBuildFile + settings + + COMPILER_FLAGS + -DOS_MACOSX -DLEVELDB_PLATFORM_POSIX -fno-objc-arc + + + A96C57DBDA6062C7971A154B + + fileRef + 80DB483BB0FCA8DFFF623FBC + isa + PBXBuildFile + + A9B0A91892D2D36F894C1485 + + fileRef + BF4590E90CD7A8EFD52F4736 + isa + PBXBuildFile + settings + + COMPILER_FLAGS + -DOS_MACOSX -DLEVELDB_PLATFORM_POSIX -fno-objc-arc + + + A9E2882AB83795C4238FA11A + + includeInIndex + 1 + isa + PBXFileReference + lastKnownFileType + sourcecode.c.h + name + PSTCollectionView.h + path + PSTCollectionView/PSTCollectionView.h + sourceTree + <group> + + A9F075A7EE80A39E723F1A38 + + buildActionMask + 2147483647 + files + + 6EF9945F9FE83F8CE273C341 + 0F568728BB516A65EF729E07 + + isa + PBXHeadersBuildPhase + runOnlyForDeploymentPostprocessing + 0 + + AA5CAF930252693792DB9C68 + + containerPortal + 32F15B3A8A99ACC37FCE0E4A + isa + PBXContainerItemProxy + proxyType + 1 + remoteGlobalIDString + 4C9AB3E89C35EEA3084D58F3 + remoteInfo + Pods-ProtocolBuffers + + AA61E920D95885BA88122ABA + + fileRef + 94A05A05CBF0EBB3D68909AF + isa + PBXBuildFile + + AAB748FC210BDEC8B479FC0C + + includeInIndex + 1 + isa + PBXFileReference + lastKnownFileType + sourcecode.c.objc + path + Pods-MWPhotoBrowser-dummy.m + sourceTree + <group> + + AB66D5880E96270410AF2EA5 + + includeInIndex + 1 + isa + PBXFileReference + lastKnownFileType + sourcecode.c.objc + name + UIImage+MultiFormat.m + path + SDWebImage/UIImage+MultiFormat.m + sourceTree + <group> + + AB8A384B09297D3F23928914 + + isa + PBXTargetDependency + name + Pods-DACircularProgress + target + 5BC12A63DA507D16082F87B8 + targetProxy + E9399B8FACEF7F7BA707A0A0 + + AC5A72531A1FDD542137A7D0 + + fileRef + 608ED333FCA41508710034C1 + isa + PBXBuildFile + + AC9050AC72499AFCD60426CC + + fileRef + 74D974F59BC8193D74C5DDD2 + isa + PBXBuildFile + + ACD54170F1B31B45C1627148 + + fileRef + 6FBF81F6138401E0F4C51799 + isa + PBXBuildFile + + AD405BE9F24F05AF726DCDFB + + buildActionMask + 2147483647 + files + + DA44E64574D83F54017BC687 + 9BE60A8CA8A01ECD8F4583C2 + D5502CED4A71BF9E8FB25E0D + 5124313076B630667C19EDE6 + F13CCC2835E3441D809C4B26 + + isa + PBXHeadersBuildPhase + runOnlyForDeploymentPostprocessing + 0 + + AD535EBB8CFB044B82F4DB45 + + fileRef + 6A7151943CF676671302C872 + isa + PBXBuildFile + + AD9E67453D61C1A792FC25AF + + includeInIndex + 1 + isa + PBXFileReference + lastKnownFileType + text + path + Pods-acknowledgements.markdown + sourceTree + <group> + + ADD4CBB75BD43CD983713F7F + + children + + 2B695DA71970230574B43D40 + DD220FA10AB47E9B70474A47 + EF08F0AD71749C672D55C040 + 9DD82C0A7DA6BD87D0BEB9F8 + + isa + PBXGroup + name + Support Files + path + ../Target Support Files/Pods-MBProgressHUD + sourceTree + <group> + + ADF56C3A2DA18898F5648030 + + fileRef + C3B7B40505C8E1891051856B + isa + PBXBuildFile + settings + + COMPILER_FLAGS + -DOS_MACOSX -DLEVELDB_PLATFORM_POSIX -fno-objc-arc + + + AE21AD5206DD8941D3862813 + + includeInIndex + 1 + isa + PBXFileReference + lastKnownFileType + sourcecode.c.h + name + FMDB.h + path + src/fmdb/FMDB.h + sourceTree + <group> + + AEDACF7508E7EA00D2158F31 + + fileRef + 92C42F814B71E9746F2C5635 + isa + PBXBuildFile + settings + + COMPILER_FLAGS + -DOS_OBJECT_USE_OBJC=0 + + + AF0270B25935FACF1A187AEF + + includeInIndex + 1 + isa + PBXFileReference + lastKnownFileType + sourcecode.c.objc + name + PSTGridLayoutItem.m + path + PSTCollectionView/PSTGridLayoutItem.m + sourceTree + <group> + + AF40A1B89AEC1AE8018D7C58 + + fileRef + 6CAA5935EFAA40E3B141E12E + isa + PBXBuildFile + + AF8CEE98DD4589CB45393A4F + + includeInIndex + 1 + isa + PBXFileReference + lastKnownFileType + sourcecode.c.h + name + AFNetworkReachabilityManager.h + path + AFNetworking/AFNetworkReachabilityManager.h + sourceTree + <group> + + AFC6280004D82AED47282BDB + + includeInIndex + 1 + isa + PBXFileReference + lastKnownFileType + sourcecode.c.objc + name + AFURLRequestSerialization.m + path + AFNetworking/AFURLRequestSerialization.m + sourceTree + <group> + + AFF5674E2C7106B5D373EAC2 + + includeInIndex + 1 + isa + PBXFileReference + lastKnownFileType + sourcecode.c.objc + name + PSTCollectionView.m + path + PSTCollectionView/PSTCollectionView.m + sourceTree + <group> + + B037739ACF85C9EB9C172C7D + + fileRef + 117DC2290330919560CE4621 + isa + PBXBuildFile + + B066D77D37E751FDEC2B319B + + includeInIndex + 1 + isa + PBXFileReference + lastKnownFileType + sourcecode.c.h + name + SCLAlertView.h + path + SCLAlertView/SCLAlertView.h + sourceTree + <group> + + B0AE50EB835F578EB1F0DF39 + + fileRef + 2F288AE1428914244800922E + isa + PBXBuildFile + + B0C9A3B700D043167657927B + + isa + PBXFileReference + lastKnownFileType + wrapper.framework + name + MapKit.framework + path + Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS7.1.sdk/System/Library/Frameworks/MapKit.framework + sourceTree + DEVELOPER_DIR + + B10D3DBC3B4F75C11781B1E4 + + fileRef + 0E700B59905A929816067FBE + isa + PBXBuildFile + + B19FC54FCF071A31A30B99D2 + + fileRef + 2219374AB1AA9A28B514A4DB + isa + PBXBuildFile + + B1A55E792360098E9BB6A6A1 + + fileRef + ECD28DB5C4E6CB99FB8A619F + isa + PBXBuildFile + settings + + COMPILER_FLAGS + -DOS_OBJECT_USE_OBJC=0 + + + B1D7C1DD2B26593144DCEAF1 + + fileRef + 266782D2AC97BCEB5178979A + isa + PBXBuildFile + settings + + COMPILER_FLAGS + -DOS_MACOSX -DLEVELDB_PLATFORM_POSIX -fno-objc-arc + + + B2C7A5F4AD5D9E7D5B2745D1 + + includeInIndex + 1 + isa + PBXFileReference + name + env_posix.cc + path + util/env_posix.cc + sourceTree + <group> + + B2CC9370F3764EE84221A3DA + + buildConfigurationList + 9AB9306524DC665A8F9B9720 + buildPhases + + ED71FDE855C9C8FB27DEFCBA + 40A513B574E6F4D0985773E1 + D9FDA668449F714342D58579 + + buildRules + + dependencies + + isa + PBXNativeTarget + name + Pods-PSTCollectionView + productName + Pods-PSTCollectionView + productReference + 05EB2194F0C07155D1BD9FCA + productType + com.apple.product-type.library.static + + B2EBBC364774B0291BF6794F + + includeInIndex + 1 + isa + PBXFileReference + lastKnownFileType + sourcecode.c.h + name + MWTapDetectingImageView.h + path + MWPhotoBrowser/Classes/MWTapDetectingImageView.h + sourceTree + <group> + + B2F5F4AA758E568F3DE3AAFF + + fileRef + A6E45E38279C209A79866A73 + isa + PBXBuildFile + + B363485271A2026AFE5E22F1 + + fileRef + 8844F3EBAE61DCAB0FD2B50C + isa + PBXBuildFile + + B38984288D16B98B2B0199C6 + + includeInIndex + 1 + isa + PBXFileReference + lastKnownFileType + sourcecode.c.objc + name + PBArray.m + path + src/runtime/Classes/PBArray.m + sourceTree + <group> + + B4A8031A8E26837EAE3D2C82 + + baseConfigurationReference + EEC82B355AAA5C5E29EE7833 + buildSettings + + ALWAYS_SEARCH_USER_PATHS + NO + COPY_PHASE_STRIP + YES + DSTROOT + /tmp/xcodeproj.dst + GCC_PRECOMPILE_PREFIX_HEADER + YES + GCC_PREFIX_HEADER + Target Support Files/Pods-leveldb-library/Pods-leveldb-library-prefix.pch + INSTALL_PATH + $(BUILT_PRODUCTS_DIR) + IPHONEOS_DEPLOYMENT_TARGET + 6.0 + OTHER_CFLAGS + + -DNS_BLOCK_ASSERTIONS=1 + $(inherited) + + OTHER_CPLUSPLUSFLAGS + + -DNS_BLOCK_ASSERTIONS=1 + $(inherited) + + OTHER_LDFLAGS + + OTHER_LIBTOOLFLAGS + + PRODUCT_NAME + $(TARGET_NAME) + PUBLIC_HEADERS_FOLDER_PATH + $(TARGET_NAME) + SDKROOT + iphoneos + SKIP_INSTALL + YES + VALIDATE_PRODUCT + YES + + isa + XCBuildConfiguration + name + Release + + B502FCD7B072CAB123EF98A8 + + includeInIndex + 1 + isa + PBXFileReference + lastKnownFileType + text + name + Podfile + path + ../Podfile + sourceTree + SOURCE_ROOT + xcLanguageSpecificationIdentifier + xcode.lang.ruby + + B517148A5BC72E9005CFAFFD + + includeInIndex + 1 + isa + PBXFileReference + lastKnownFileType + sourcecode.c.h + name + MWCommon.h + path + MWPhotoBrowser/Classes/MWCommon.h + sourceTree + <group> + + B5382AD412DDA1EF83EC3113 + + isa + PBXTargetDependency + name + Pods-SDWebImage + target + 436B9F8EBC9F4E16A3FE4A8E + targetProxy + C7E0E34A3BC7DD39C738A993 + + B663D4B8172F651C053C3449 + + fileRef + 223837A87FA5DCB75ED915CA + isa + PBXBuildFile + + B68790F5CB72380C68CA7D01 + + fileRef + 3EB2AB40155920F357CBE280 + isa + PBXBuildFile + + B68C69F6738C61A824DDA397 + + buildConfigurationList + E6C5D9C4B6C36624AE971740 + buildPhases + + A604ABA1E3E88ADBF1656250 + 7662894EE22A63E012D37362 + DD99BBD142CD906BCA8F18F1 + + buildRules + + dependencies + + isa + PBXNativeTarget + name + Pods-AFNetworking + productName + Pods-AFNetworking + productReference + 709DF1D98B3C9C42CAF24380 + productType + com.apple.product-type.library.static + + B691DD5164855DE328CD4667 + + fileRef + BC5A1DD8838051712DD1B148 + isa + PBXBuildFile + + B6D4ED35722A9748E9BC2E0E + + fileRef + E57E503B6BB3E35D65709641 + isa + PBXBuildFile + + B6DF5E8ED2F58C83470CB7F1 + + includeInIndex + 1 + isa + PBXFileReference + lastKnownFileType + sourcecode.c.h + name + options.h + path + include/leveldb/options.h + sourceTree + <group> + + B782F08D51BFC8B5240B3287 + + includeInIndex + 1 + isa + PBXFileReference + lastKnownFileType + sourcecode.c.h + path + Pods-PSTCollectionView-prefix.pch + sourceTree + <group> + + B894532EF13442EF355249F8 + + includeInIndex + 1 + isa + PBXFileReference + lastKnownFileType + sourcecode.c.objc + name + MWCaptionView.m + path + MWPhotoBrowser/Classes/MWCaptionView.m + sourceTree + <group> + + B91C710449B99BACCFF7514A + + fileRef + 3D6A401A0F4D6944FAB89588 + isa + PBXBuildFile + settings + + COMPILER_FLAGS + -DOS_MACOSX -DLEVELDB_PLATFORM_POSIX -fno-objc-arc + + + B92B573335D8EBD876E5BAB3 + + buildConfigurationList + 04A67BC2BEF06219139ED97C + buildPhases + + BCDA02CD7A641ECD941F34F8 + FA1581E65085E31B583071BA + AD405BE9F24F05AF726DCDFB + + buildRules + + dependencies + + isa + PBXNativeTarget + name + Pods-SCLAlertView-Objective-C + productName + Pods-SCLAlertView-Objective-C + productReference + D870E25799E17DF48DFC3485 + productType + com.apple.product-type.library.static + + B96501197C22DD4EE943EC8B + + includeInIndex + 1 + isa + PBXFileReference + name + version_edit.cc + path + db/version_edit.cc + sourceTree + <group> + + B9999E6C77ADC794DF3028D5 + + fileRef + 09AF0DA308729036EA8F80DF + isa + PBXBuildFile + settings + + COMPILER_FLAGS + -DOS_OBJECT_USE_OBJC=0 + + + B9A58CF978CF82508D32B365 + + baseConfigurationReference + 083933610D4312DE9AB65E85 + buildSettings + + ALWAYS_SEARCH_USER_PATHS + NO + COPY_PHASE_STRIP + YES + DSTROOT + /tmp/xcodeproj.dst + GCC_PRECOMPILE_PREFIX_HEADER + YES + GCC_PREFIX_HEADER + Target Support Files/Pods-HPGrowingTextView/Pods-HPGrowingTextView-prefix.pch + INSTALL_PATH + $(BUILT_PRODUCTS_DIR) + IPHONEOS_DEPLOYMENT_TARGET + 6.0 + OTHER_CFLAGS + + -DNS_BLOCK_ASSERTIONS=1 + $(inherited) + + OTHER_CPLUSPLUSFLAGS + + -DNS_BLOCK_ASSERTIONS=1 + $(inherited) + + OTHER_LDFLAGS + + OTHER_LIBTOOLFLAGS + + PRODUCT_NAME + $(TARGET_NAME) + PUBLIC_HEADERS_FOLDER_PATH + $(TARGET_NAME) + SDKROOT + iphoneos + SKIP_INSTALL + YES + VALIDATE_PRODUCT + YES + + isa + XCBuildConfiguration + name + Release + + BAAE0FCC823CAB821068161E + + includeInIndex + 1 + isa + PBXFileReference + lastKnownFileType + sourcecode.c.objc + name + SDImageCache.m + path + SDWebImage/SDImageCache.m + sourceTree + <group> + + BADF1612A352CC9A346F3D3B + + baseConfigurationReference + F0DA9628331484011ADCCEEE + buildSettings + + ALWAYS_SEARCH_USER_PATHS + NO + COPY_PHASE_STRIP + YES + DSTROOT + /tmp/xcodeproj.dst + GCC_PRECOMPILE_PREFIX_HEADER + YES + GCC_PREFIX_HEADER + Target Support Files/Pods-DACircularProgress/Pods-DACircularProgress-prefix.pch + INSTALL_PATH + $(BUILT_PRODUCTS_DIR) + IPHONEOS_DEPLOYMENT_TARGET + 6.0 + OTHER_CFLAGS + + -DNS_BLOCK_ASSERTIONS=1 + $(inherited) + + OTHER_CPLUSPLUSFLAGS + + -DNS_BLOCK_ASSERTIONS=1 + $(inherited) + + OTHER_LDFLAGS + + OTHER_LIBTOOLFLAGS + + PRODUCT_NAME + $(TARGET_NAME) + PUBLIC_HEADERS_FOLDER_PATH + $(TARGET_NAME) + SDKROOT + iphoneos + SKIP_INSTALL + YES + VALIDATE_PRODUCT + YES + + isa + XCBuildConfiguration + name + Release + + BB21BDA4B3EF344733623D40 + + fileRef + 20EEC719BB609EF7E68B081E + isa + PBXBuildFile + + BC1331C7F2BB36605A024EE3 + + includeInIndex + 1 + isa + PBXFileReference + lastKnownFileType + text.xcconfig + path + Pods.debug.xcconfig + sourceTree + <group> + + BC5A1DD8838051712DD1B148 + + includeInIndex + 1 + isa + PBXFileReference + lastKnownFileType + sourcecode.c.h + name + FMDatabase.h + path + src/fmdb/FMDatabase.h + sourceTree + <group> + + BCD458FFF5C0E345447F2331 + + fileRef + 3752BB0CE2C29682AB862649 + isa + PBXBuildFile + + BCDA02CD7A641ECD941F34F8 + + buildActionMask + 2147483647 + files + + 50C4B8B7C970B8AF644F7A72 + A3CC9FE7F7D3A97337FB28FD + A598A41D5D2C489605FAE958 + 1BAFF8B33D566F451E7265DC + FBA69645F5F2D2234FAEFE11 + 9988565EA7926C091DEE74B1 + + isa + PBXSourcesBuildPhase + runOnlyForDeploymentPostprocessing + 0 + + BD93B9E6E2FECBED8D1B76CF + + fileRef + EB0E4A04795B5570D0FCD14A + isa + PBXBuildFile + + BD9755826D5D690B487574E4 + + includeInIndex + 1 + isa + PBXFileReference + lastKnownFileType + sourcecode.c.h + name + RingBuffer.h + path + src/runtime/Classes/RingBuffer.h + sourceTree + <group> + + BD9A2FB9A19FD77320F67CFC + + baseConfigurationReference + C34261195314A22D360C684C + buildSettings + + ALWAYS_SEARCH_USER_PATHS + NO + COPY_PHASE_STRIP + NO + DSTROOT + /tmp/xcodeproj.dst + GCC_DYNAMIC_NO_PIC + NO + GCC_OPTIMIZATION_LEVEL + 0 + GCC_PRECOMPILE_PREFIX_HEADER + YES + GCC_PREFIX_HEADER + Target Support Files/Pods-SDWebImage/Pods-SDWebImage-prefix.pch + GCC_PREPROCESSOR_DEFINITIONS + + DEBUG=1 + $(inherited) + + GCC_SYMBOLS_PRIVATE_EXTERN + NO + INSTALL_PATH + $(BUILT_PRODUCTS_DIR) + IPHONEOS_DEPLOYMENT_TARGET + 6.0 + OTHER_LDFLAGS + + OTHER_LIBTOOLFLAGS + + PRODUCT_NAME + $(TARGET_NAME) + PUBLIC_HEADERS_FOLDER_PATH + $(TARGET_NAME) + SDKROOT + iphoneos + SKIP_INSTALL + YES + + isa + XCBuildConfiguration + name + Debug + + BE1A4AFE81B70CD36F6CA796 + + fileRef + D8A205F92D93FD2738602AB0 + isa + PBXBuildFile + + BEB024A1F5BD014D07626678 + + buildActionMask + 2147483647 + files + + 4EB9F151CB99E080156E610F + + isa + PBXFrameworksBuildPhase + runOnlyForDeploymentPostprocessing + 0 + + BF4590E90CD7A8EFD52F4736 + + includeInIndex + 1 + isa + PBXFileReference + name + repair.cc + path + db/repair.cc + sourceTree + <group> + + BFC558A4791B470449398D99 + + fileRef + A628A4BEF1965D3C2406CCF4 + isa + PBXBuildFile + + C0070AB1CF15DD13E9C1CF9A + + fileRef + A32268C080A7CB0A84DA87C0 + isa + PBXBuildFile + + C01F4F52C1997C1E5B1CE567 + + fileRef + 223837A87FA5DCB75ED915CA + isa + PBXBuildFile + + C066E7853B6B2691E32F3670 + + includeInIndex + 1 + isa + PBXFileReference + lastKnownFileType + sourcecode.c.h + name + AbstractMessage.h + path + src/runtime/Classes/AbstractMessage.h + sourceTree + <group> + + C09793BD54D60BA0EDA79542 + + includeInIndex + 1 + isa + PBXFileReference + lastKnownFileType + sourcecode.c.h + name + status.h + path + include/leveldb/status.h + sourceTree + <group> + + C0A3C4CFF66805E6D8C81FF2 + + isa + PBXFileReference + lastKnownFileType + wrapper.framework + name + AssetsLibrary.framework + path + Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS7.1.sdk/System/Library/Frameworks/AssetsLibrary.framework + sourceTree + DEVELOPER_DIR + + C1117E2F0150481788D938F2 + + includeInIndex + 1 + isa + PBXFileReference + lastKnownFileType + sourcecode.c.objc + name + MutableExtensionRegistry.m + path + src/runtime/Classes/MutableExtensionRegistry.m + sourceTree + <group> + + C12B69172B63B72AD0EEC876 + + fileRef + 223837A87FA5DCB75ED915CA + isa + PBXBuildFile + + C14AD3034BE5D559CD38D152 + + includeInIndex + 1 + isa + PBXFileReference + lastKnownFileType + sourcecode.c.objc + name + RingBuffer.m + path + src/runtime/Classes/RingBuffer.m + sourceTree + <group> + + C18E37B41AA810A4ACA38F0A + + buildActionMask + 2147483647 + files + + 9CA2D4A21195643A6E17B1B6 + + isa + PBXFrameworksBuildPhase + runOnlyForDeploymentPostprocessing + 0 + + C1D6ACBC8299FB8FCAF5B47E + + buildSettings + + ALWAYS_SEARCH_USER_PATHS + NO + CLANG_CXX_LANGUAGE_STANDARD + gnu++0x + CLANG_CXX_LIBRARY + libc++ + CLANG_ENABLE_MODULES + YES + CLANG_ENABLE_OBJC_ARC + YES + CLANG_WARN_BOOL_CONVERSION + YES + CLANG_WARN_CONSTANT_CONVERSION + YES + CLANG_WARN_DIRECT_OBJC_ISA_USAGE + YES + CLANG_WARN_EMPTY_BODY + YES + CLANG_WARN_ENUM_CONVERSION + YES + CLANG_WARN_INT_CONVERSION + YES + CLANG_WARN_OBJC_ROOT_CLASS + YES + COPY_PHASE_STRIP + NO + ENABLE_NS_ASSERTIONS + NO + GCC_C_LANGUAGE_STANDARD + gnu99 + GCC_PREPROCESSOR_DEFINITIONS + + RELEASE=1 + + GCC_WARN_64_TO_32_BIT_CONVERSION + YES + GCC_WARN_ABOUT_RETURN_TYPE + YES + GCC_WARN_UNDECLARED_SELECTOR + YES + GCC_WARN_UNINITIALIZED_AUTOS + YES + GCC_WARN_UNUSED_FUNCTION + YES + GCC_WARN_UNUSED_VARIABLE + YES + IPHONEOS_DEPLOYMENT_TARGET + 6.0 + STRIP_INSTALLED_PRODUCT + NO + VALIDATE_PRODUCT + YES + + isa + XCBuildConfiguration + name + Release + + C1D97FD9ADE54714DD83CCD9 + + includeInIndex + 1 + isa + PBXFileReference + lastKnownFileType + sourcecode.c.h + name + UIKit+AFNetworking.h + path + UIKit+AFNetworking/UIKit+AFNetworking.h + sourceTree + <group> + + C214372F6590692E084E2D5F + + includeInIndex + 1 + isa + PBXFileReference + lastKnownFileType + sourcecode.c.h + name + MWPhotoBrowser.h + path + MWPhotoBrowser/Classes/MWPhotoBrowser.h + sourceTree + <group> + + C2C6E0474786D3709DDC2F04 + + fileRef + 953BBF7EEA4B94E552FF1031 + isa + PBXBuildFile + + C34261195314A22D360C684C + + includeInIndex + 1 + isa + PBXFileReference + lastKnownFileType + text.xcconfig + path + Pods-SDWebImage-Private.xcconfig + sourceTree + <group> + + C3B7B40505C8E1891051856B + + includeInIndex + 1 + isa + PBXFileReference + name + dumpfile.cc + path + db/dumpfile.cc + sourceTree + <group> + + C3E04B58C6B03BACEF7C93C3 + + includeInIndex + 1 + isa + PBXFileReference + lastKnownFileType + sourcecode.c.h + name + PSTCollectionViewController.h + path + PSTCollectionView/PSTCollectionViewController.h + sourceTree + <group> + + C445ADD65DE09EA6923A57DB + + includeInIndex + 1 + isa + PBXFileReference + lastKnownFileType + text.xcconfig + path + Pods-ProtocolBuffers-Private.xcconfig + sourceTree + <group> + + C4B40005F0D8D2FF21103FE5 + + isa + PBXTargetDependency + name + Pods-leveldb-library + target + 09A20CC0DB72732970F408DF + targetProxy + E093B0893648D29BED97714F + + C576E19B4146090A7A7B835E + + isa + PBXFileReference + lastKnownFileType + wrapper.framework + name + CoreGraphics.framework + path + Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS7.1.sdk/System/Library/Frameworks/CoreGraphics.framework + sourceTree + DEVELOPER_DIR + + C5BE2F15E77F3A6C876C56A6 + + fileRef + 8405C9828FBD675691D7A099 + isa + PBXBuildFile + settings + + COMPILER_FLAGS + -DOS_OBJECT_USE_OBJC=0 + + + C5C87B64DB1567BAA02CAA8A + + includeInIndex + 1 + isa + PBXFileReference + lastKnownFileType + sourcecode.c.objc + name + AFHTTPSessionManager.m + path + AFNetworking/AFHTTPSessionManager.m + sourceTree + <group> + + C7295B4DA373498D1F71361A + + isa + PBXTargetDependency + name + Pods-AFNetworking + target + B68C69F6738C61A824DDA397 + targetProxy + A63ACBDB288925BE8E8032CC + + C730C155A102EF724BE687DA + + fileRef + FA0BAB27170E98482241483B + isa + PBXBuildFile + + C789EFA649CE5511A5034CB4 + + children + + B502FCD7B072CAB123EF98A8 + 4B44DD7E04CDC67F8CFE6767 + 3137847C12737C5F132D2ED8 + 26B8112D009B6B9B7222DD44 + F72612C572C83933DF4C29AE + + isa + PBXGroup + sourceTree + <group> + + C7D48636C10C7744165FB31A + + explicitFileType + archive.ar + includeInIndex + 0 + isa + PBXFileReference + path + libPods-leveldb-library.a + sourceTree + BUILT_PRODUCTS_DIR + + C7E0E34A3BC7DD39C738A993 + + containerPortal + 32F15B3A8A99ACC37FCE0E4A + isa + PBXContainerItemProxy + proxyType + 1 + remoteGlobalIDString + 436B9F8EBC9F4E16A3FE4A8E + remoteInfo + Pods-SDWebImage + + C80B59F7F32BBD752961FA0F + + children + + 203F5506F66F6388F3636144 + EA8762D76449CE7876E8F132 + 3D6A401A0F4D6944FAB89588 + 46084CECE5E6479249631903 + 55264D37382246C8001B1E41 + 65F7069DDDB709F84C123389 + A6E45E38279C209A79866A73 + 801EA99ACD0E9DF3D8C8B053 + 1804BCFDD93BEF23F93BE360 + F2D467336D5A63A3507849C5 + 1B28AAF75F073830F0B0FFEB + F9E4B238BC99105235F99C68 + 90AB4BEE583FB7BCA4A0AD3D + 2F288AE1428914244800922E + 11D4CFF8D6847996107DE84C + 06CBE569D706D994B4682D20 + 80C3C93A0CCA916B9A547AC0 + 0B75A723EBE7AEEDCD821F78 + C3B7B40505C8E1891051856B + 960C1B0DC2E1B1011490DCCA + 994FEDAB754303A9320036EA + DEF488A26ED34AD6C91108EB + B2C7A5F4AD5D9E7D5B2745D1 + 2A9067C886DE85ABCF36D13D + 7EAEF684C195D3DDDC8A6111 + A002E6C9939624372369F622 + 45FD5AE5B54AE822710D71AD + 752B4F74095974C4652C4AA1 + 8D9482B6C87566E1994EBCA2 + 2DEDD05DF1CEE040F591C410 + 6914D820882607BBC74E1C6C + 6A48B1D11FDDAF84A874CC7B + 6AAD773CF99897A09D77F12D + D2D45AA58D26CAE1C3C7C6C8 + 5405042C9F88C5EDFA7C8BC4 + 628B417A08CDD15DA33A0FE9 + E029A3D104E6F50FE9CA4244 + 5776121BD52D034B76CF1482 + F9E7DA9C46BEC071E7ED6457 + B6DF5E8ED2F58C83470CB7F1 + 6CDC6879AF78DCDE258DC7AF + BF4590E90CD7A8EFD52F4736 + 6A7151943CF676671302C872 + 8EE7A75E274391BF68ED4413 + C09793BD54D60BA0EDA79542 + 6ECCB645A8F8ED5BE9077872 + 5ACC307A39A4549B8E4B31CC + A11C91177C7D6830D9E3D714 + 2664B96014E04470A26C3D9D + 8713D88CE5ED4B4CC40A3DC5 + 96DF7F825B4E5D59980CEF80 + 266782D2AC97BCEB5178979A + 661264FDE0337383E10C08BC + B96501197C22DD4EE943EC8B + ECA1FB0B08B8EC33433A4969 + 06D5E5B356DDEE0016B2DF8B + 83B6A3A2E938078CB6F9068F + F4B8D42C4A286A4335CF2F27 + + isa + PBXGroup + name + leveldb-library + path + leveldb-library + sourceTree + <group> + + C84E0A20800C38A11B9565DE + + fileRef + 0F997A972D99D16202B345E1 + isa + PBXBuildFile + settings + + COMPILER_FLAGS + -DOS_OBJECT_USE_OBJC=0 + + + C856BC052BAA0CD252EC9990 + + includeInIndex + 1 + isa + PBXFileReference + lastKnownFileType + sourcecode.c.h + name + UIButton+AFNetworking.h + path + UIKit+AFNetworking/UIButton+AFNetworking.h + sourceTree + <group> + + C89CFFFC2C903CF2D3DCA125 + + includeInIndex + 1 + isa + PBXFileReference + lastKnownFileType + sourcecode.c.h + name + UIImageView+AFNetworking.h + path + UIKit+AFNetworking/UIImageView+AFNetworking.h + sourceTree + <group> + + C8A1651143CF857E2247043C + + fileRef + 99AE7BB5349DE93D2C8B95CD + isa + PBXBuildFile + + C990C35FAD9F51DCBD118D76 + + includeInIndex + 1 + isa + PBXFileReference + lastKnownFileType + sourcecode.c.h + name + PSTCollectionViewLayout.h + path + PSTCollectionView/PSTCollectionViewLayout.h + sourceTree + <group> + + C9A0B31406DE1C1FB7271422 + + fileRef + 1B28AAF75F073830F0B0FFEB + isa + PBXBuildFile + settings + + COMPILER_FLAGS + -DOS_MACOSX -DLEVELDB_PLATFORM_POSIX -fno-objc-arc + + + C9BDB6930D43A23FD358C521 + + fileRef + AF8CEE98DD4589CB45393A4F + isa + PBXBuildFile + + CAC7F15F99528D9395171A66 + + fileRef + 1F9551963550E6B397CC9405 + isa + PBXBuildFile + settings + + COMPILER_FLAGS + -DOS_OBJECT_USE_OBJC=0 + + + CAF762070158A31E5714BF33 + + fileRef + D84273C78CF615440F5D1AE4 + isa + PBXBuildFile + + CB3AF522D26A2C534A6F49BA + + fileRef + 90AB4BEE583FB7BCA4A0AD3D + isa + PBXBuildFile + settings + + COMPILER_FLAGS + -DOS_MACOSX -DLEVELDB_PLATFORM_POSIX -fno-objc-arc + + + CB6F531783D1B86BF197D0DD + + fileRef + 04D5F8B792321841AE66C196 + isa + PBXBuildFile + + CC57503D74577BEA95AD137D + + includeInIndex + 1 + isa + PBXFileReference + lastKnownFileType + text.xcconfig + path + Pods-AFNetworking-Private.xcconfig + sourceTree + <group> + + CC748A2C78201671F1B5513E + + includeInIndex + 1 + isa + PBXFileReference + lastKnownFileType + sourcecode.c.objc + name + UIImage+ImageEffects.m + path + SCLAlertView/UIImage+ImageEffects.m + sourceTree + <group> + + CC8E06B1A9C21833447AFF71 + + fileRef + 621A89489B9B0C3A13363E61 + isa + PBXBuildFile + + CCCFBD2E30C570609AD671A9 + + fileRef + 9410F4786A0143E3503C0238 + isa + PBXBuildFile + + CD2B0C3081ECC8CAF0500549 + + buildActionMask + 2147483647 + files + + AA61E920D95885BA88122ABA + E06A6037F6A0D1C353F8370A + E2303FC7B1819BF6175FBF55 + 5D65C0C9FCA9B2EB9494A5D4 + 0F3AE90A79AA3D752538CB37 + 5289EE3E54D831F5B642A1EE + 2AA8151F40837D2700B5EF47 + 16B22AE9AA5F6640B831C45A + 1EBF46F409D0C38D6E0B98AA + B037739ACF85C9EB9C172C7D + 363C7382E2696A0FC947E7B3 + + isa + PBXHeadersBuildPhase + runOnlyForDeploymentPostprocessing + 0 + + CE6472F7605774D3C01343EB + + buildConfigurations + + 2B6BD15E531A436BA82D7D30 + B9A58CF978CF82508D32B365 + + defaultConfigurationIsVisible + 0 + defaultConfigurationName + Release + isa + XCConfigurationList + + CEB678AE3E0BEFDEBA68EC79 + + fileRef + 26090EAB64012ACD35014B0E + isa + PBXBuildFile + settings + + COMPILER_FLAGS + -DOS_OBJECT_USE_OBJC=0 + + + CF0C0551F1B6D22C79F97295 + + fileRef + 477D6A7C5445614F0EC92BEF + isa + PBXBuildFile + settings + + COMPILER_FLAGS + -DOS_OBJECT_USE_OBJC=0 + + + D0223147AE81F668AF8A94BB + + includeInIndex + 1 + isa + PBXFileReference + lastKnownFileType + sourcecode.c.objc + name + SCLAlertView.m + path + SCLAlertView/SCLAlertView.m + sourceTree + <group> + + D07153D8BF8FDDB6ADA3BC94 + + isa + PBXTargetDependency + name + Pods-SCLAlertView-Objective-C + target + B92B573335D8EBD876E5BAB3 + targetProxy + 3BD4E3C873BF588961842ED7 + + D1090AC882A2758438195F9C + + fileRef + 55FF4BF7CF588A412D3821E5 + isa + PBXBuildFile + + D13010101311635ADF49DFE0 + + includeInIndex + 1 + isa + PBXFileReference + lastKnownFileType + sourcecode.c.h + name + ExtensionField.h + path + src/runtime/Classes/ExtensionField.h + sourceTree + <group> + + D17A26C1FADA059FA06C58BA + + children + + C0A3C4CFF66805E6D8C81FF2 + C576E19B4146090A7A7B835E + 223837A87FA5DCB75ED915CA + 3752BB0CE2C29682AB862649 + B0C9A3B700D043167657927B + 041E19F1C2C9563727945FC2 + F66AD7C4F4978D0D0BE1F36F + 55FF4BF7CF588A412D3821E5 + 0C94A4F4543A58C11920B4B8 + 8A2F10DCB98B2F4A20118541 + A4F0C5321C168E3D41FC8A2A + + isa + PBXGroup + name + iOS + sourceTree + <group> + + D26CF69AF59FE6F0EFA3908E + + fileRef + 7F38231A1C35E330BAB7FA3C + isa + PBXBuildFile + settings + + COMPILER_FLAGS + -DOS_OBJECT_USE_OBJC=0 + + + D2D45AA58D26CAE1C3C7C6C8 + + includeInIndex + 1 + isa + PBXFileReference + name + log_reader.cc + path + db/log_reader.cc + sourceTree + <group> + + D2D56399A17A7F7607BDEE81 + + includeInIndex + 1 + isa + PBXFileReference + lastKnownFileType + sourcecode.c.objc + name + UIImageView+HighlightedWebCache.m + path + SDWebImage/UIImageView+HighlightedWebCache.m + sourceTree + <group> + + D2E07E59587D5971B5194FF4 + + children + + 6629B1BB47511B7643B557DD + 24BEB24D94467F828A8EF0A9 + + isa + PBXGroup + name + FMDB + path + FMDB + sourceTree + <group> + + D2E4AF4B3D0853C3C87E4036 + + fileRef + 960C1B0DC2E1B1011490DCCA + isa + PBXBuildFile + + D3AAEEDFBD8C160B71E49463 + + containerPortal + 32F15B3A8A99ACC37FCE0E4A + isa + PBXContainerItemProxy + proxyType + 1 + remoteGlobalIDString + B2CC9370F3764EE84221A3DA + remoteInfo + Pods-PSTCollectionView + + D3D41A60E1DFE3BCACCF72BD + + fileRef + 3C5A96D689E3ADAFEE73A1B8 + isa + PBXBuildFile + + D4129F77C3956981E45F0823 + + includeInIndex + 1 + isa + PBXFileReference + lastKnownFileType + sourcecode.c.h + name + SDWebImageCompat.h + path + SDWebImage/SDWebImageCompat.h + sourceTree + <group> + + D44E766CBE117F485D9966D6 + + explicitFileType + archive.ar + includeInIndex + 0 + isa + PBXFileReference + path + libPods-MBProgressHUD.a + sourceTree + BUILT_PRODUCTS_DIR + + D4A3FF96418E6E69081F1910 + + fileRef + DDD894B8672E2F3E721294A2 + isa + PBXBuildFile + + D4AE4A8671B4B6E08F0EEDE1 + + includeInIndex + 1 + isa + PBXFileReference + lastKnownFileType + sourcecode.c.h + name + PSTCollectionViewCell.h + path + PSTCollectionView/PSTCollectionViewCell.h + sourceTree + <group> + + D4BB92CC59FB58F99D6432FC + + includeInIndex + 1 + isa + PBXFileReference + lastKnownFileType + sourcecode.c.h + name + SDWebImageOperation.h + path + SDWebImage/SDWebImageOperation.h + sourceTree + <group> + + D510F74D5B9F22F1A17A825C + + includeInIndex + 1 + isa + PBXFileReference + lastKnownFileType + sourcecode.c.objc + name + PSTGridLayoutInfo.m + path + PSTCollectionView/PSTGridLayoutInfo.m + sourceTree + <group> + + D53BD60EA11AB6C149ED398F + + children + + E737E48117EBF0E0081C4456 + 8AAB857E284C046BD52EDCBC + 993DE3DBE9B9B2FE96D70D49 + 53ED7E6AEDA46C6D5C6F6026 + + isa + PBXGroup + name + Support Files + path + ../Target Support Files/Pods-SCLAlertView-Objective-C + sourceTree + <group> + + D5502CED4A71BF9E8FB25E0D + + fileRef + 031A6739DE63A8B5C23C2C2A + isa + PBXBuildFile + + D57246A24D83BA5D0F739840 + + buildActionMask + 2147483647 + files + + 7E1258B7E1E85AF1FEE532FC + + isa + PBXHeadersBuildPhase + runOnlyForDeploymentPostprocessing + 0 + + D598D703A6AE974BFA3D592F + + includeInIndex + 1 + isa + PBXFileReference + lastKnownFileType + sourcecode.c.h + name + UIImage+GIF.h + path + SDWebImage/UIImage+GIF.h + sourceTree + <group> + + D5DFA9D7D827C73FD0C51426 + + fileRef + B6DF5E8ED2F58C83470CB7F1 + isa + PBXBuildFile + + D6A21361BCA70D18B24AD6C3 + + buildActionMask + 2147483647 + files + + F794B935C33D34482AB795CE + 4000A459693DA456A9F260BB + + isa + PBXFrameworksBuildPhase + runOnlyForDeploymentPostprocessing + 0 + + D6AE328B91D52C532428C353 + + includeInIndex + 1 + isa + PBXFileReference + lastKnownFileType + sourcecode.c.h + name + UIImage+ImageEffects.h + path + SCLAlertView/UIImage+ImageEffects.h + sourceTree + <group> + + D6B22E3B6B72695A5E1B06E4 + + fileRef + 752B4F74095974C4652C4AA1 + isa + PBXBuildFile + settings + + COMPILER_FLAGS + -DOS_MACOSX -DLEVELDB_PLATFORM_POSIX -fno-objc-arc + + + D6E244B591B684EAF6EC227F + + fileRef + F815BA7E9774B8ADAC4A54DE + isa + PBXBuildFile + settings + + COMPILER_FLAGS + -DOS_OBJECT_USE_OBJC=0 + + + D7CBA5D051FE225A2B801952 + + buildActionMask + 2147483647 + files + + 326B2BFA523C5193368A7E79 + CC8E06B1A9C21833447AFF71 + + isa + PBXSourcesBuildPhase + runOnlyForDeploymentPostprocessing + 0 + + D84273C78CF615440F5D1AE4 + + includeInIndex + 1 + isa + PBXFileReference + lastKnownFileType + sourcecode.c.h + name + ExtendableMessageBuilder.h + path + src/runtime/Classes/ExtendableMessageBuilder.h + sourceTree + <group> + + D870E25799E17DF48DFC3485 + + explicitFileType + archive.ar + includeInIndex + 0 + isa + PBXFileReference + path + libPods-SCLAlertView-Objective-C.a + sourceTree + BUILT_PRODUCTS_DIR + + D8A205F92D93FD2738602AB0 + + includeInIndex + 1 + isa + PBXFileReference + lastKnownFileType + sourcecode.c.objc + path + Pods-SDWebImage-dummy.m + sourceTree + <group> + + D948ABF29763F579D0916BD4 + + fileRef + 55FF4BF7CF588A412D3821E5 + isa + PBXBuildFile + + D9A9FC0E7A4F50A49361D701 + + children + + F2CF4B3F00EAECAFED760C81 + F253B46C0C1A08E7A6DDB20F + A76D8B7CECD0A1A22035B322 + BAAE0FCC823CAB821068161E + D4129F77C3956981E45F0823 + F815BA7E9774B8ADAC4A54DE + 04D5F8B792321841AE66C196 + 49AC65C76420ED77634048BA + 2219374AB1AA9A28B514A4DB + 575A1806C24DDD22FB1F3D76 + F5BC0DF9654C4957C668F68F + ECD28DB5C4E6CB99FB8A619F + E57E503B6BB3E35D65709641 + 12B2407E3501674C2B74C217 + D4BB92CC59FB58F99D6432FC + A628A4BEF1965D3C2406CCF4 + 1D954353E6F68F9112161DBF + 46A348EECBDEFB7DCCA2BB94 + F4ED4D5B270DD429F10CA8C2 + D598D703A6AE974BFA3D592F + 4BCD84D3892CB1B0EAA4D794 + DDD894B8672E2F3E721294A2 + AB66D5880E96270410AF2EA5 + A32268C080A7CB0A84DA87C0 + D2D56399A17A7F7607BDEE81 + 4C36B817E4055677B5421327 + 92C42F814B71E9746F2C5635 + 5EC214EE3238E1135C34AD2A + 1733531BD18C8422A71FCB17 + + isa + PBXGroup + name + Core + sourceTree + <group> + + D9FDA668449F714342D58579 + + buildActionMask + 2147483647 + files + + B10D3DBC3B4F75C11781B1E4 + 610702CC0D07AEC4A4BD0EDD + E9921F00608A8BBBAD0320D5 + 288B5E95FFC7C966C96178C8 + 52CBD74D817CD4FAE8C171FA + 2E42719EDE41C967F415A24D + 868E2549F34C6C9DA7D98A7A + BD93B9E6E2FECBED8D1B76CF + CCCFBD2E30C570609AD671A9 + 9911F290C4DF0CCEB9B3FAC5 + F2A2BE694448203F720DB763 + 4B325765210BAB16F8B85788 + 6038AAB955ACF62FA2D6BF88 + 2112856F5B4BF40635226F25 + C8A1651143CF857E2247043C + + isa + PBXHeadersBuildPhase + runOnlyForDeploymentPostprocessing + 0 + + DA44E64574D83F54017BC687 + + fileRef + B066D77D37E751FDEC2B319B + isa + PBXBuildFile + + DBE623A41725980641125A09 + + fileRef + 223837A87FA5DCB75ED915CA + isa + PBXBuildFile + + DC7599049970BBDD0032E7ED + + includeInIndex + 1 + isa + PBXFileReference + lastKnownFileType + sourcecode.c.h + name + TextFormat.h + path + src/runtime/Classes/TextFormat.h + sourceTree + <group> + + DC7BC349B35431AD23BBEBB9 + + fileRef + 6C07D3845C8008A011D639C6 + isa + PBXBuildFile + + DC86D8F594D591B774933B6C + + fileRef + 6160490FB9FD266A240C709A + isa + PBXBuildFile + + DD04C9A6E193790AB5702BC1 + + includeInIndex + 1 + isa + PBXFileReference + lastKnownFileType + sourcecode.c.h + name + HPTextViewInternal.h + path + class/HPTextViewInternal.h + sourceTree + <group> + + DD220FA10AB47E9B70474A47 + + includeInIndex + 1 + isa + PBXFileReference + lastKnownFileType + text.xcconfig + path + Pods-MBProgressHUD-Private.xcconfig + sourceTree + <group> + + DD2B27A1FD088D6827076FC6 + + children + + 85859F6FA181E668B7F7D0C7 + C5C87B64DB1567BAA02CAA8A + 925166FE3DABD3B90304140A + 20EEC719BB609EF7E68B081E + + isa + PBXGroup + name + NSURLSession + sourceTree + <group> + + DD99BBD142CD906BCA8F18F1 + + buildActionMask + 2147483647 + files + + 8E7632F11DF0C77693FCC98F + 1D27CE8C4A280C391AE28ED3 + 8A238155E0A0CF2D867C877F + 96C9887F2629E485953143B9 + C9BDB6930D43A23FD358C521 + 7B699AAD05008839A2F61832 + F6DBCCD18DC92C84D7FFE5F7 + 49FF77FF50895DF43120841F + F6360F7DA39CF5CEB5E55E6B + 4D888E40EC697EA505BF5393 + 0490DD2DD8E984B4CEC44B79 + 36A92433F1C460134470E808 + F8B2829302DCCF86EC1501D9 + 035A00D1283FE86740DD4328 + 8EB9680B2C763E85EF347AB4 + 93C022C444EF438A285333B2 + FC963FE83D77CC2BD651F006 + B363485271A2026AFE5E22F1 + DC86D8F594D591B774933B6C + + isa + PBXHeadersBuildPhase + runOnlyForDeploymentPostprocessing + 0 + + DDD894B8672E2F3E721294A2 + + includeInIndex + 1 + isa + PBXFileReference + lastKnownFileType + sourcecode.c.h + name + UIImage+MultiFormat.h + path + SDWebImage/UIImage+MultiFormat.h + sourceTree + <group> + + DE310BDAEDBE5DAA09A09B58 + + fileRef + 6914D820882607BBC74E1C6C + isa + PBXBuildFile + settings + + COMPILER_FLAGS + -DOS_MACOSX -DLEVELDB_PLATFORM_POSIX -fno-objc-arc + + + DE4CC53A9D56B0817F67127B + + fileRef + 575A1806C24DDD22FB1F3D76 + isa + PBXBuildFile + settings + + COMPILER_FLAGS + -DOS_OBJECT_USE_OBJC=0 + + + DECE8C2E0AD103679C0C9C86 + + includeInIndex + 1 + isa + PBXFileReference + lastKnownFileType + sourcecode.c.h + path + Pods-MWPhotoBrowser-prefix.pch + sourceTree + <group> + + DEF488A26ED34AD6C91108EB + + includeInIndex + 1 + isa + PBXFileReference + lastKnownFileType + sourcecode.c.h + name + env.h + path + include/leveldb/env.h + sourceTree + <group> + + DF777A3A37029DF979CD57FD + + isa + PBXTargetDependency + name + Pods-MBProgressHUD + target + 45FFB846AD2C35316261CE26 + targetProxy + 31AA646DEB8B5D246415A7AF + + DFA296D550112B43C29F8A03 + + fileRef + 14B377FB1843736348EDDEA5 + isa + PBXBuildFile + + E0088F6EBBCD6C8F7AF2B26D + + fileRef + 06EAABF561F969D7EDC12021 + isa + PBXBuildFile + + E029A3D104E6F50FE9CA4244 + + includeInIndex + 1 + isa + PBXFileReference + name + memtable.cc + path + db/memtable.cc + sourceTree + <group> + + E06A6037F6A0D1C353F8370A + + fileRef + B517148A5BC72E9005CFAFFD + isa + PBXBuildFile + + E072575F13318B9926EE43AF + + fileRef + 041E19F1C2C9563727945FC2 + isa + PBXBuildFile + + E085885AEC926627A0118690 + + fileRef + 47D922FA54FC3C3045B13491 + isa + PBXBuildFile + settings + + COMPILER_FLAGS + -DOS_OBJECT_USE_OBJC=0 + + + E093B0893648D29BED97714F + + containerPortal + 32F15B3A8A99ACC37FCE0E4A + isa + PBXContainerItemProxy + proxyType + 1 + remoteGlobalIDString + 09A20CC0DB72732970F408DF + remoteInfo + Pods-leveldb-library + + E0A7964EA43A5E3E6D880E44 + + includeInIndex + 1 + isa + PBXFileReference + lastKnownFileType + sourcecode.c.h + name + AbstractMessageBuilder.h + path + src/runtime/Classes/AbstractMessageBuilder.h + sourceTree + <group> + + E2303FC7B1819BF6175FBF55 + + fileRef + 3D10C0F53638694244519BCC + isa + PBXBuildFile + + E247D4F351D9B7CF02DEB27E + + fileRef + C066E7853B6B2691E32F3670 + isa + PBXBuildFile + + E264B4AFE255FC2DE2EB44A1 + + fileRef + 628B417A08CDD15DA33A0FE9 + isa + PBXBuildFile + settings + + COMPILER_FLAGS + -DOS_MACOSX -DLEVELDB_PLATFORM_POSIX -fno-objc-arc + + + E3AB5079457C309BE972EB9E + + includeInIndex + 1 + isa + PBXFileReference + lastKnownFileType + sourcecode.c.h + name + ProtocolBuffers.h + path + src/runtime/Classes/ProtocolBuffers.h + sourceTree + <group> + + E5720203BEF96608DB601CC6 + + fileRef + 2DEDD05DF1CEE040F591C410 + isa + PBXBuildFile + settings + + COMPILER_FLAGS + -DOS_MACOSX -DLEVELDB_PLATFORM_POSIX -fno-objc-arc + + + E57E503B6BB3E35D65709641 + + includeInIndex + 1 + isa + PBXFileReference + lastKnownFileType + sourcecode.c.h + name + SDWebImageManager.h + path + SDWebImage/SDWebImageManager.h + sourceTree + <group> + + E58D5B14872390B2BD156281 + + buildActionMask + 2147483647 + files + + 70A5CBFB8AB58A3998482FF0 + FEFB1B7CEAD4201B58BDF2BC + B9999E6C77ADC794DF3028D5 + 6F3E1CB2CC75A3ADB97053BF + CAC7F15F99528D9395171A66 + C730C155A102EF724BE687DA + + isa + PBXSourcesBuildPhase + runOnlyForDeploymentPostprocessing + 0 + + E5E2B268AD581DF7A0A6581F + + fileRef + D598D703A6AE974BFA3D592F + isa + PBXBuildFile + + E67941409329CEE9F940F5FB + + fileRef + F5BC0DF9654C4957C668F68F + isa + PBXBuildFile + + E68C2FE29EBBB8B8723DB891 + + fileRef + 83B6A3A2E938078CB6F9068F + isa + PBXBuildFile + + E6C2B39C323DFE25B9EBD98C + + fileRef + 8B12F7F1DCB5D368319E8A3A + isa + PBXBuildFile + + E6C5D9C4B6C36624AE971740 + + buildConfigurations + + 020FA5C0FCF0FCD206BC1A64 + 6D275BAAE9C0A621F74877ED + + defaultConfigurationIsVisible + 0 + defaultConfigurationName + Release + isa + XCConfigurationList + + E70CADF856BD80E345ED975F + + fileRef + 7B131D9B353CAF0C8595C9DB + isa + PBXBuildFile + settings + + COMPILER_FLAGS + -DOS_OBJECT_USE_OBJC=0 + + + E719AA1D6F4EF3E4E2C662DD + + fileRef + 4687AE4C66B1F5A1AB143D40 + isa + PBXBuildFile + + E737E48117EBF0E0081C4456 + + includeInIndex + 1 + isa + PBXFileReference + lastKnownFileType + text.xcconfig + path + Pods-SCLAlertView-Objective-C.xcconfig + sourceTree + <group> + + E760123E99E784B2598D7C71 + + fileRef + 96DF7F825B4E5D59980CEF80 + isa + PBXBuildFile + settings + + COMPILER_FLAGS + -DOS_MACOSX -DLEVELDB_PLATFORM_POSIX -fno-objc-arc + + + E84ABC7F3A9EEE8D1008FC22 + + containerPortal + 32F15B3A8A99ACC37FCE0E4A + isa + PBXContainerItemProxy + proxyType + 1 + remoteGlobalIDString + 436B9F8EBC9F4E16A3FE4A8E + remoteInfo + Pods-SDWebImage + + E90C8002FB08810C2A006EDD + + includeInIndex + 1 + isa + PBXFileReference + lastKnownFileType + sourcecode.c.h + name + PSTCollectionViewData.h + path + PSTCollectionView/PSTCollectionViewData.h + sourceTree + <group> + + E90FB6F54C2B3DFA6B8E182B + + fileRef + A76D8B7CECD0A1A22035B322 + isa + PBXBuildFile + + E9322072BD227F89D465C3E3 + + children + + E9FE05F74DA1E7F24F4F3325 + 6CAA5935EFAA40E3B141E12E + EECD5A9A6925D5D18354177A + 8B12F7F1DCB5D368319E8A3A + 0DE31D4A559CEA4BAAEB43FA + 2789D3C72809AAD6A403B520 + + isa + PBXGroup + name + NSURLConnection + sourceTree + <group> + + E9399B8FACEF7F7BA707A0A0 + + containerPortal + 32F15B3A8A99ACC37FCE0E4A + isa + PBXContainerItemProxy + proxyType + 1 + remoteGlobalIDString + 5BC12A63DA507D16082F87B8 + remoteInfo + Pods-DACircularProgress + + E9921F00608A8BBBAD0320D5 + + fileRef + D4AE4A8671B4B6E08F0EEDE1 + isa + PBXBuildFile + + E9BEDCE9400DA48B9D83EA13 + + buildActionMask + 2147483647 + files + + 9816C87F1DDD73D2D8E2235C + 62941C9C2F0AD9458A53B972 + A42ADC337E4B5E17C00F6616 + B91C710449B99BACCFF7514A + A58116FD5C16C1F0CEB464D8 + 4ACA21E5C05E643E5B37F3A1 + 4031E4A092D2F7C268F34980 + EC9A0CD7F103801F020FABA6 + 307B56AFBB065E27C3CBB279 + C9A0B31406DE1C1FB7271422 + CB3AF522D26A2C534A6F49BA + 1EC60600D79AE4EBA2E2029C + 0A12B2B6017AC4319D9A8652 + 14595BD59DE8382D09CB3EC8 + 134B70A7A25D73B28E189003 + ADF56C3A2DA18898F5648030 + 11ACB1BBA37F7EFFA5CD0B1C + 2A5A7341CD4236064A18FEBD + 26C84946B53B2A2E7A0EDC8F + FD62CDA33CBCDA73777D9E16 + 4D63C82E1237C980377587C4 + D6B22E3B6B72695A5E1B06E4 + 00A8D8FAD20BA69D8DD8ED92 + E5720203BEF96608DB601CC6 + DE310BDAEDBE5DAA09A09B58 + 264F2686AC1D7A3259DE7584 + A95E1DE563AD958A41A2F4D0 + FE02C37442750C4415076A4A + E264B4AFE255FC2DE2EB44A1 + 04A48876E1246EDB856C82D7 + F38388F1D76A74A0C4F8D02C + 3D3E42AB2ED904817B1F7B70 + EDFFF46244058EBC676D9315 + A9B0A91892D2D36F894C1485 + 86B67FBDC525A9C65FEA3B4E + 266DAA6EBCF551D9AEAC871C + F43D0845B19BA271E247D5EF + 4D66AA358AB651C3B3CDFC8F + E760123E99E784B2598D7C71 + B1D7C1DD2B26593144DCEAF1 + 1BE238282F474E10B9E55FAA + 6FA48799977EE9A8D2029E9A + F62A24F8CB8BE02E0143EC0C + 53887B679828B24D705F8369 + + isa + PBXSourcesBuildPhase + runOnlyForDeploymentPostprocessing + 0 + + E9D3FB3DCAD31ABD664DACB5 + + fileRef + 0C99167FA1FE4618CB7A1E96 + isa + PBXBuildFile + + E9FE05F74DA1E7F24F4F3325 + + includeInIndex + 1 + isa + PBXFileReference + lastKnownFileType + sourcecode.c.h + name + AFHTTPRequestOperation.h + path + AFNetworking/AFHTTPRequestOperation.h + sourceTree + <group> + + EA386BB4F08F849B26C99F4E + + fileRef + 6D5D05C03292EC531E62C2F8 + isa + PBXBuildFile + settings + + COMPILER_FLAGS + -DOS_OBJECT_USE_OBJC=0 + + + EA8762D76449CE7876E8F132 + + includeInIndex + 1 + isa + PBXFileReference + name + block.cc + path + table/block.cc + sourceTree + <group> + + EAD1807B4D09F3162EF52A14 + + baseConfigurationReference + C34261195314A22D360C684C + buildSettings + + ALWAYS_SEARCH_USER_PATHS + NO + COPY_PHASE_STRIP + YES + DSTROOT + /tmp/xcodeproj.dst + GCC_PRECOMPILE_PREFIX_HEADER + YES + GCC_PREFIX_HEADER + Target Support Files/Pods-SDWebImage/Pods-SDWebImage-prefix.pch + INSTALL_PATH + $(BUILT_PRODUCTS_DIR) + IPHONEOS_DEPLOYMENT_TARGET + 6.0 + OTHER_CFLAGS + + -DNS_BLOCK_ASSERTIONS=1 + $(inherited) + + OTHER_CPLUSPLUSFLAGS + + -DNS_BLOCK_ASSERTIONS=1 + $(inherited) + + OTHER_LDFLAGS + + OTHER_LIBTOOLFLAGS + + PRODUCT_NAME + $(TARGET_NAME) + PUBLIC_HEADERS_FOLDER_PATH + $(TARGET_NAME) + SDKROOT + iphoneos + SKIP_INSTALL + YES + VALIDATE_PRODUCT + YES + + isa + XCBuildConfiguration + name + Release + + EB0E4A04795B5570D0FCD14A + + includeInIndex + 1 + isa + PBXFileReference + lastKnownFileType + sourcecode.c.h + name + PSTCollectionViewItemKey.h + path + PSTCollectionView/PSTCollectionViewItemKey.h + sourceTree + <group> + + EC0BF631A888536456ED3CC5 + + includeInIndex + 1 + isa + PBXFileReference + lastKnownFileType + sourcecode.c.objc + name + GeneratedMessageBuilder.m + path + src/runtime/Classes/GeneratedMessageBuilder.m + sourceTree + <group> + + EC9A0CD7F103801F020FABA6 + + fileRef + 801EA99ACD0E9DF3D8C8B053 + isa + PBXBuildFile + settings + + COMPILER_FLAGS + -DOS_MACOSX -DLEVELDB_PLATFORM_POSIX -fno-objc-arc + + + ECA1FB0B08B8EC33433A4969 + + includeInIndex + 1 + isa + PBXFileReference + name + version_set.cc + path + db/version_set.cc + sourceTree + <group> + + ECD28DB5C4E6CB99FB8A619F + + includeInIndex + 1 + isa + PBXFileReference + lastKnownFileType + sourcecode.c.objc + name + SDWebImageDownloaderOperation.m + path + SDWebImage/SDWebImageDownloaderOperation.m + sourceTree + <group> + + ED3F5FEC7C7321FEA60F8E20 + + children + + 6221677C8CCE2562427ED2E1 + 25E731136E9378DFA707E0CA + AAB748FC210BDEC8B479FC0C + DECE8C2E0AD103679C0C9C86 + + isa + PBXGroup + name + Support Files + path + ../Target Support Files/Pods-MWPhotoBrowser + sourceTree + <group> + + ED71FDE855C9C8FB27DEFCBA + + buildActionMask + 2147483647 + files + + 32BF81DBCE8922CC2CF4C2DC + 6A6FD52A5C67C666EB8B636B + 84E01E61624B40A8BC4FE0F3 + CEB678AE3E0BEFDEBA68EC79 + D26CF69AF59FE6F0EFA3908E + 388299DD69D2CC010DD19CD3 + E70CADF856BD80E345ED975F + F64960B43DFDCB7A2792FC06 + 2127A5794249D556C258884E + 3C425BD30A9130578244A99D + 81BB69CFFC97F65D74173A39 + 34FF922B2CA28ECD6719B90C + C5BE2F15E77F3A6C876C56A6 + F8715F4C51B67AF2EF1B0FE4 + + isa + PBXSourcesBuildPhase + runOnlyForDeploymentPostprocessing + 0 + + EDFACE50892F79E87647CBED + + fileRef + 1733531BD18C8422A71FCB17 + isa + PBXBuildFile + settings + + COMPILER_FLAGS + -DOS_OBJECT_USE_OBJC=0 + + + EDFFF46244058EBC676D9315 + + fileRef + 6CDC6879AF78DCDE258DC7AF + isa + PBXBuildFile + settings + + COMPILER_FLAGS + -DOS_MACOSX -DLEVELDB_PLATFORM_POSIX -fno-objc-arc + + + EE21F90792467DB80ECA97BC + + includeInIndex + 1 + isa + PBXFileReference + lastKnownFileType + sourcecode.c.objc + name + PSTCollectionViewUpdateItem.m + path + PSTCollectionView/PSTCollectionViewUpdateItem.m + sourceTree + <group> + + EE7E7A1AC778EF09E52FCC45 + + children + + 0E700B59905A929816067FBE + 8CE38F828C808EF79A144EFB + A9E2882AB83795C4238FA11A + AFF5674E2C7106B5D373EAC2 + D4AE4A8671B4B6E08F0EEDE1 + A7F7B9F8095B1921610D00B3 + 8FC24A9C5749968730CC0338 + C3E04B58C6B03BACEF7C93C3 + 26090EAB64012ACD35014B0E + E90C8002FB08810C2A006EDD + 7F38231A1C35E330BAB7FA3C + A70D8225F43007DAD1FB9CD2 + FA45AB72D3AB3F2139080C14 + EB0E4A04795B5570D0FCD14A + 7B131D9B353CAF0C8595C9DB + C990C35FAD9F51DCBD118D76 + A6F30E2A50EC157661A84DEF + 9410F4786A0143E3503C0238 + 3FD4932A47564EEA68C63804 + EE21F90792467DB80ECA97BC + F5E7971956E2814255293312 + D510F74D5B9F22F1A17A825C + 5E07C588667132BE4D76C386 + AF0270B25935FACF1A187AEF + 04D48DB2E059E48F88B66E2A + 98B6D5E9EFB0A69AD65B7598 + 99AE7BB5349DE93D2C8B95CD + 8405C9828FBD675691D7A099 + 8533DD5601B6AA7F353167C5 + + isa + PBXGroup + name + PSTCollectionView + path + PSTCollectionView + sourceTree + <group> + + EEC7584373E7F6F10FF13B80 + + fileRef + AAB748FC210BDEC8B479FC0C + isa + PBXBuildFile + + EEC82B355AAA5C5E29EE7833 + + includeInIndex + 1 + isa + PBXFileReference + lastKnownFileType + text.xcconfig + path + Pods-leveldb-library-Private.xcconfig + sourceTree + <group> + + EECD5A9A6925D5D18354177A + + includeInIndex + 1 + isa + PBXFileReference + lastKnownFileType + sourcecode.c.h + name + AFHTTPRequestOperationManager.h + path + AFNetworking/AFHTTPRequestOperationManager.h + sourceTree + <group> + + EF08F0AD71749C672D55C040 + + includeInIndex + 1 + isa + PBXFileReference + lastKnownFileType + sourcecode.c.objc + path + Pods-MBProgressHUD-dummy.m + sourceTree + <group> + + EF2FF83F2D1859670CC23AED + + explicitFileType + archive.ar + includeInIndex + 0 + isa + PBXFileReference + path + libPods-DACircularProgress.a + sourceTree + BUILT_PRODUCTS_DIR + + F021064D4A15F1EFE5E6378F + + includeInIndex + 1 + isa + PBXFileReference + lastKnownFileType + sourcecode.c.objc + name + MWGridViewController.m + path + MWPhotoBrowser/Classes/MWGridViewController.m + sourceTree + <group> + + F05F2BB273021B735FCA7575 + + includeInIndex + 1 + isa + PBXFileReference + lastKnownFileType + sourcecode.c.h + name + AFNetworkActivityIndicatorManager.h + path + UIKit+AFNetworking/AFNetworkActivityIndicatorManager.h + sourceTree + <group> + + F0AFCE32A60AB10F7FC8AB8A + + fileRef + F2CF4B3F00EAECAFED760C81 + isa + PBXBuildFile + + F0DA9628331484011ADCCEEE + + includeInIndex + 1 + isa + PBXFileReference + lastKnownFileType + text.xcconfig + path + Pods-DACircularProgress-Private.xcconfig + sourceTree + <group> + + F0E45C93060176FF51747061 + + includeInIndex + 1 + isa + PBXFileReference + lastKnownFileType + sourcecode.c.objc + name + MWZoomingScrollView.m + path + MWPhotoBrowser/Classes/MWZoomingScrollView.m + sourceTree + <group> + + F0E4FE8FC41CF583255E5454 + + fileRef + 7C4C2D9CE27785732081B6A3 + isa + PBXBuildFile + + F13CCC2835E3441D809C4B26 + + fileRef + D6AE328B91D52C532428C353 + isa + PBXBuildFile + + F1C544C92D75F9E26C48066D + + fileRef + 2081D35AE4041B5506F9B8AD + isa + PBXBuildFile + + F253B46C0C1A08E7A6DDB20F + + includeInIndex + 1 + isa + PBXFileReference + lastKnownFileType + sourcecode.c.objc + name + NSData+ImageContentType.m + path + SDWebImage/NSData+ImageContentType.m + sourceTree + <group> + + F29A397831A0F7E88AFF6C4F + + includeInIndex + 1 + isa + PBXFileReference + lastKnownFileType + sourcecode.c.objc + name + MWPhotoBrowser.m + path + MWPhotoBrowser/Classes/MWPhotoBrowser.m + sourceTree + <group> + + F2A2BE694448203F720DB763 + + fileRef + 3FD4932A47564EEA68C63804 + isa + PBXBuildFile + + F2CF4B3F00EAECAFED760C81 + + includeInIndex + 1 + isa + PBXFileReference + lastKnownFileType + sourcecode.c.h + name + NSData+ImageContentType.h + path + SDWebImage/NSData+ImageContentType.h + sourceTree + <group> + + F2D467336D5A63A3507849C5 + + includeInIndex + 1 + isa + PBXFileReference + name + coding.cc + path + util/coding.cc + sourceTree + <group> + + F2E6DEF05A16FEF8DD6E3A10 + + includeInIndex + 1 + isa + PBXFileReference + lastKnownFileType + sourcecode.c.objc + path + MBProgressHUD.m + sourceTree + <group> + + F38388F1D76A74A0C4F8D02C + + fileRef + 5776121BD52D034B76CF1482 + isa + PBXBuildFile + settings + + COMPILER_FLAGS + -DOS_MACOSX -DLEVELDB_PLATFORM_POSIX -fno-objc-arc + + + F3D3BE29D7966D70DE8D8E45 + + baseConfigurationReference + 6D4610683470F0D825193013 + buildSettings + + ALWAYS_SEARCH_USER_PATHS + NO + COPY_PHASE_STRIP + YES + DSTROOT + /tmp/xcodeproj.dst + GCC_PRECOMPILE_PREFIX_HEADER + YES + GCC_PREFIX_HEADER + Target Support Files/Pods-FMDB/Pods-FMDB-prefix.pch + INSTALL_PATH + $(BUILT_PRODUCTS_DIR) + IPHONEOS_DEPLOYMENT_TARGET + 6.0 + OTHER_CFLAGS + + -DNS_BLOCK_ASSERTIONS=1 + $(inherited) + + OTHER_CPLUSPLUSFLAGS + + -DNS_BLOCK_ASSERTIONS=1 + $(inherited) + + OTHER_LDFLAGS + + OTHER_LIBTOOLFLAGS + + PRODUCT_NAME + $(TARGET_NAME) + PUBLIC_HEADERS_FOLDER_PATH + $(TARGET_NAME) + SDKROOT + iphoneos + SKIP_INSTALL + YES + VALIDATE_PRODUCT + YES + + isa + XCBuildConfiguration + name + Release + + F43D0845B19BA271E247D5EF + + fileRef + A11C91177C7D6830D9E3D714 + isa + PBXBuildFile + settings + + COMPILER_FLAGS + -DOS_MACOSX -DLEVELDB_PLATFORM_POSIX -fno-objc-arc + + + F4AC1B9E5BCBAFF474A08C05 + + children + + C066E7853B6B2691E32F3670 + 6975B09D41EAAC0E44FAD082 + E0A7964EA43A5E3E6D880E44 + 74DC8A4071B473E99802DAD1 + 6871CC4088D36CC9FA1A68A2 + 433DBE8012005DACD07D65EF + 22B424E560CB2A89AE0EB255 + 3EB2AB40155920F357CBE280 + 6E62D46280CC328E94E46521 + 5B5AEE1888F87E8B26E3B489 + 6A817E6BB7C645D1AC92FAB0 + 98936A7C58EBE6A2962C4607 + 7AD2F899ED0331F97A7CF969 + F691C7DF885835E30E5094F9 + 3A9F4AC69A272E5270CC8406 + D84273C78CF615440F5D1AE4 + 10184A70DD0CFEA6D44A466D + D13010101311635ADF49DFE0 + 17E406215ACE33340EE78A51 + FD5E5F030A7222CD04099C96 + 913FED115D82825A3D32EBE3 + 929748361FA52C5C9E57FF1B + 4687AE4C66B1F5A1AB143D40 + 189A7D5B9253201FCF76E504 + 6FBF81F6138401E0F4C51799 + 6D956C6D6E6AF865A3CE2D49 + EC0BF631A888536456ED3CC5 + 5E532C2FE266B181F2A33B15 + 40499E70D308BA2A338F6886 + 0474ED89B2559A9B9503ACFA + C1117E2F0150481788D938F2 + A4076CCDEDD6B27F0F0B2CEC + 72D9AD46C3FA92963D7F2328 + 4F967D6B41FFC92C8BAB90C3 + B38984288D16B98B2B0199C6 + E3AB5079457C309BE972EB9E + BD9755826D5D690B487574E4 + C14AD3034BE5D559CD38D152 + DC7599049970BBDD0032E7ED + 5FD1AFC29DDCF9CCE15CDEBE + 14B377FB1843736348EDDEA5 + 7C36E10C0195774F43983480 + FCC3E938BAC0E348818BD8BE + 8844B09E07162D932351DFDB + 6AA9328DE75F77A4949E306C + 552A55BCA9263CA49874E0A5 + 2081D35AE4041B5506F9B8AD + 06EAABF561F969D7EDC12021 + 1452623912D26097FEBC0975 + + isa + PBXGroup + name + ProtocolBuffers + path + ProtocolBuffers + sourceTree + <group> + + F4B8D42C4A286A4335CF2F27 + + children + + 383593281A16833B4249471A + EEC82B355AAA5C5E29EE7833 + A4BCFB832F151BB333475948 + 4B70F0352F54A3FB980841FE + + isa + PBXGroup + name + Support Files + path + ../Target Support Files/Pods-leveldb-library + sourceTree + <group> + + F4D405575168A967C6F43D20 + + fileRef + F2E6DEF05A16FEF8DD6E3A10 + isa + PBXBuildFile + settings + + COMPILER_FLAGS + -DOS_OBJECT_USE_OBJC=0 + + + F4D61FBDB3D46D0EE9CFAA1A + + includeInIndex + 1 + isa + PBXFileReference + lastKnownFileType + sourcecode.c.h + name + MWPhotoBrowserPrivate.h + path + MWPhotoBrowser/Classes/MWPhotoBrowserPrivate.h + sourceTree + <group> + + F4ED4D5B270DD429F10CA8C2 + + includeInIndex + 1 + isa + PBXFileReference + lastKnownFileType + sourcecode.c.objc + name + UIButton+WebCache.m + path + SDWebImage/UIButton+WebCache.m + sourceTree + <group> + + F5BC0DF9654C4957C668F68F + + includeInIndex + 1 + isa + PBXFileReference + lastKnownFileType + sourcecode.c.h + name + SDWebImageDownloaderOperation.h + path + SDWebImage/SDWebImageDownloaderOperation.h + sourceTree + <group> + + F5E7971956E2814255293312 + + includeInIndex + 1 + isa + PBXFileReference + lastKnownFileType + sourcecode.c.h + name + PSTGridLayoutInfo.h + path + PSTCollectionView/PSTGridLayoutInfo.h + sourceTree + <group> + + F62A24F8CB8BE02E0143EC0C + + fileRef + ECA1FB0B08B8EC33433A4969 + isa + PBXBuildFile + settings + + COMPILER_FLAGS + -DOS_MACOSX -DLEVELDB_PLATFORM_POSIX -fno-objc-arc + + + F62C1713D4D2480D28335202 + + buildActionMask + 2147483647 + files + + 51AB06AB9EA1276A1A943219 + 3B85D4CB465FD514E58237A6 + 32EC93C854539B2E033F08F5 + 3BFC38A4A9607CB34B33C589 + 5CC6907B06E2D7E899F6EB42 + 8D6E7F6E401465F9A4C0A651 + 280A524E026C941535C7A99E + 76C0D313B14653EC632FC7FA + 7FCBFCCCDE72A3B0F546D46D + 953B4C95F2441080647FB12E + ACD54170F1B31B45C1627148 + 63DBCDAB0F366C2F406BC1F8 + 66E3A7D3E017E03A74EB7F95 + 6F988C5FD6B631998BB380B8 + A82656F3FDA490D2C48608C5 + 74B7CC8F615847035EDBBE6D + 410AF7EC006A7BE85F130790 + A8AAF46F5CFBA86AD0FA4690 + A1E08F4C7CFB44F6C8515E9C + 9CCA7CBCA659AEB048CF0E90 + 28DCF641CAC83536782FA512 + E0088F6EBBCD6C8F7AF2B26D + + isa + PBXSourcesBuildPhase + runOnlyForDeploymentPostprocessing + 0 + + F6360F7DA39CF5CEB5E55E6B + + fileRef + 51FB13E9C1A4B9C76C2E2FAC + isa + PBXBuildFile + + F64960B43DFDCB7A2792FC06 + + fileRef + A6F30E2A50EC157661A84DEF + isa + PBXBuildFile + settings + + COMPILER_FLAGS + -DOS_OBJECT_USE_OBJC=0 + + + F66AD7C4F4978D0D0BE1F36F + + isa + PBXFileReference + lastKnownFileType + wrapper.framework + name + MobileCoreServices.framework + path + Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS7.1.sdk/System/Library/Frameworks/MobileCoreServices.framework + sourceTree + DEVELOPER_DIR + + F691C7DF885835E30E5094F9 + + includeInIndex + 1 + isa + PBXFileReference + lastKnownFileType + sourcecode.c.h + name + ExtendableMessage.h + path + src/runtime/Classes/ExtendableMessage.h + sourceTree + <group> + + F6DBCCD18DC92C84D7FFE5F7 + + fileRef + 669EAE7DE1ED17F9C051F30D + isa + PBXBuildFile + + F72612C572C83933DF4C29AE + + children + + 8EED9532FCCFF04F90DF9029 + + isa + PBXGroup + name + Targets Support Files + sourceTree + <group> + + F794B935C33D34482AB795CE + + fileRef + C576E19B4146090A7A7B835E + isa + PBXBuildFile + + F815BA7E9774B8ADAC4A54DE + + includeInIndex + 1 + isa + PBXFileReference + lastKnownFileType + sourcecode.c.objc + name + SDWebImageCompat.m + path + SDWebImage/SDWebImageCompat.m + sourceTree + <group> + + F82253E01F19CAC8A8F94000 + + fileRef + 5EC214EE3238E1135C34AD2A + isa + PBXBuildFile + + F8715F4C51B67AF2EF1B0FE4 + + fileRef + 38F06966FE24AB86B612DD3B + isa + PBXBuildFile + + F8A8A377242E3B94EF492CCE + + buildActionMask + 2147483647 + files + + 43C7202C034BD7F7F5DE09DE + BCD458FFF5C0E345447F2331 + + isa + PBXFrameworksBuildPhase + runOnlyForDeploymentPostprocessing + 0 + + F8B2829302DCCF86EC1501D9 + + fileRef + 154045BA6367553FBB8C1A76 + isa + PBXBuildFile + + F8EE7A3FF58F2974C05C7D68 + + buildConfigurations + + BD9A2FB9A19FD77320F67CFC + EAD1807B4D09F3162EF52A14 + + defaultConfigurationIsVisible + 0 + defaultConfigurationName + Release + isa + XCConfigurationList + + F90F234921C5A6988D8F29F4 + + includeInIndex + 1 + isa + PBXFileReference + lastKnownFileType + sourcecode.c.objc + name + HPTextViewInternal.m + path + class/HPTextViewInternal.m + sourceTree + <group> + + F9E4B238BC99105235F99C68 + + includeInIndex + 1 + isa + PBXFileReference + lastKnownFileType + sourcecode.c.h + name + comparator.h + path + include/leveldb/comparator.h + sourceTree + <group> + + F9E7DA9C46BEC071E7ED6457 + + includeInIndex + 1 + isa + PBXFileReference + name + options.cc + path + util/options.cc + sourceTree + <group> + + F9EAEF9FC3454DA72C3A9AFD + + fileRef + F253B46C0C1A08E7A6DDB20F + isa + PBXBuildFile + settings + + COMPILER_FLAGS + -DOS_OBJECT_USE_OBJC=0 + + + FA0BAB27170E98482241483B + + includeInIndex + 1 + isa + PBXFileReference + lastKnownFileType + sourcecode.c.objc + path + Pods-FMDB-dummy.m + sourceTree + <group> + + FA1581E65085E31B583071BA + + buildActionMask + 2147483647 + files + + DBE623A41725980641125A09 + + isa + PBXFrameworksBuildPhase + runOnlyForDeploymentPostprocessing + 0 + + FA45AB72D3AB3F2139080C14 + + includeInIndex + 1 + isa + PBXFileReference + lastKnownFileType + sourcecode.c.objc + name + PSTCollectionViewFlowLayout.m + path + PSTCollectionView/PSTCollectionViewFlowLayout.m + sourceTree + <group> + + FB4AE529C15E6A86153C1C3D + + includeInIndex + 1 + isa + PBXFileReference + lastKnownFileType + sourcecode.c.objc + name + FMDatabaseAdditions.m + path + src/fmdb/FMDatabaseAdditions.m + sourceTree + <group> + + FB5BBC68625373C8219E8423 + + fileRef + 913FED115D82825A3D32EBE3 + isa + PBXBuildFile + + FBA69645F5F2D2234FAEFE11 + + fileRef + 7E4D46311C2E01A909F2C29B + isa + PBXBuildFile + + FBAE885B5A12097FDD72D80A + + baseConfigurationReference + C445ADD65DE09EA6923A57DB + buildSettings + + ALWAYS_SEARCH_USER_PATHS + NO + COPY_PHASE_STRIP + NO + DSTROOT + /tmp/xcodeproj.dst + GCC_DYNAMIC_NO_PIC + NO + GCC_OPTIMIZATION_LEVEL + 0 + GCC_PRECOMPILE_PREFIX_HEADER + YES + GCC_PREFIX_HEADER + Target Support Files/Pods-ProtocolBuffers/Pods-ProtocolBuffers-prefix.pch + GCC_PREPROCESSOR_DEFINITIONS + + DEBUG=1 + $(inherited) + + GCC_SYMBOLS_PRIVATE_EXTERN + NO + INSTALL_PATH + $(BUILT_PRODUCTS_DIR) + IPHONEOS_DEPLOYMENT_TARGET + 6.0 + OTHER_LDFLAGS + + OTHER_LIBTOOLFLAGS + + PRODUCT_NAME + $(TARGET_NAME) + PUBLIC_HEADERS_FOLDER_PATH + $(TARGET_NAME) + SDKROOT + iphoneos + SKIP_INSTALL + YES + + isa + XCBuildConfiguration + name + Debug + + FBCC8ED4C06FBA17B993C2A7 + + fileRef + 40499E70D308BA2A338F6886 + isa + PBXBuildFile + + FC963FE83D77CC2BD651F006 + + fileRef + 1ECDBC93F6B81E068C62FC47 + isa + PBXBuildFile + + FCC3E938BAC0E348818BD8BE + + includeInIndex + 1 + isa + PBXFileReference + lastKnownFileType + sourcecode.c.h + name + UnknownFieldSetBuilder.h + path + src/runtime/Classes/UnknownFieldSetBuilder.h + sourceTree + <group> + + FD5E5F030A7222CD04099C96 + + includeInIndex + 1 + isa + PBXFileReference + lastKnownFileType + sourcecode.c.objc + name + ExtensionRegistry.m + path + src/runtime/Classes/ExtensionRegistry.m + sourceTree + <group> + + FD62CDA33CBCDA73777D9E16 + + fileRef + 7EAEF684C195D3DDDC8A6111 + isa + PBXBuildFile + settings + + COMPILER_FLAGS + -DOS_MACOSX -DLEVELDB_PLATFORM_POSIX -fno-objc-arc + + + FE02C37442750C4415076A4A + + fileRef + 5405042C9F88C5EDFA7C8BC4 + isa + PBXBuildFile + settings + + COMPILER_FLAGS + -DOS_MACOSX -DLEVELDB_PLATFORM_POSIX -fno-objc-arc + + + FE619E7BA032E95A856F867C + + fileRef + D13010101311635ADF49DFE0 + isa + PBXBuildFile + + FEFB1B7CEAD4201B58BDF2BC + + fileRef + FB4AE529C15E6A86153C1C3D + isa + PBXBuildFile + settings + + COMPILER_FLAGS + -DOS_OBJECT_USE_OBJC=0 + + + FFC195D25171B1330A3E38A2 + + fileRef + 49AC65C76420ED77634048BA + isa + PBXBuildFile + settings + + COMPILER_FLAGS + -DOS_OBJECT_USE_OBJC=0 + + + + rootObject + 32F15B3A8A99ACC37FCE0E4A + + diff --git a/ios/Pods/Pods.xcodeproj/project.xcworkspace/contents.xcworkspacedata b/ios/Pods/Pods.xcodeproj/project.xcworkspace/contents.xcworkspacedata new file mode 100644 index 000000000..d25c45c36 --- /dev/null +++ b/ios/Pods/Pods.xcodeproj/project.xcworkspace/contents.xcworkspacedata @@ -0,0 +1,7 @@ + + + + + diff --git a/ios/Pods/Pods.xcodeproj/project.xcworkspace/xcshareddata/Pods.xccheckout b/ios/Pods/Pods.xcodeproj/project.xcworkspace/xcshareddata/Pods.xccheckout new file mode 100644 index 000000000..0a42e50a8 --- /dev/null +++ b/ios/Pods/Pods.xcodeproj/project.xcworkspace/xcshareddata/Pods.xccheckout @@ -0,0 +1,41 @@ + + + + + IDESourceControlProjectFavoriteDictionaryKey + + IDESourceControlProjectIdentifier + 81E42C91-A2AB-46F8-BFE5-B1F460211EC2 + IDESourceControlProjectName + Pods + IDESourceControlProjectOriginsDictionary + + AF42C6DA9F3B77838B1BC908C0E388C0190EF50F + gitlab.mogujie.org:dongxie/teamtalk-ios.git + + IDESourceControlProjectPath + Pods/Pods.xcodeproj + IDESourceControlProjectRelativeInstallPathDictionary + + AF42C6DA9F3B77838B1BC908C0E388C0190EF50F + ../../.. + + IDESourceControlProjectURL + gitlab.mogujie.org:dongxie/teamtalk-ios.git + IDESourceControlProjectVersion + 111 + IDESourceControlProjectWCCIdentifier + AF42C6DA9F3B77838B1BC908C0E388C0190EF50F + IDESourceControlProjectWCConfigurations + + + IDESourceControlRepositoryExtensionIdentifierKey + public.vcs.git + IDESourceControlWCCIdentifierKey + AF42C6DA9F3B77838B1BC908C0E388C0190EF50F + IDESourceControlWCCName + teamtalk-ios + + + + diff --git a/ios/Pods/Pods.xcodeproj/project.xcworkspace/xcuserdata/scorpio.xcuserdatad/UserInterfaceState.xcuserstate b/ios/Pods/Pods.xcodeproj/project.xcworkspace/xcuserdata/scorpio.xcuserdatad/UserInterfaceState.xcuserstate new file mode 100644 index 000000000..98b480347 Binary files /dev/null and b/ios/Pods/Pods.xcodeproj/project.xcworkspace/xcuserdata/scorpio.xcuserdatad/UserInterfaceState.xcuserstate differ diff --git a/ios/Pods/Pods.xcodeproj/xcuserdata/Jerry.xcuserdatad/xcschemes/Pods-AFNetworking.xcscheme b/ios/Pods/Pods.xcodeproj/xcuserdata/Jerry.xcuserdatad/xcschemes/Pods-AFNetworking.xcscheme new file mode 100644 index 000000000..5f5079c6e --- /dev/null +++ b/ios/Pods/Pods.xcodeproj/xcuserdata/Jerry.xcuserdatad/xcschemes/Pods-AFNetworking.xcscheme @@ -0,0 +1,77 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/ios/Pods/Pods.xcodeproj/xcuserdata/Jerry.xcuserdatad/xcschemes/Pods-DACircularProgress.xcscheme b/ios/Pods/Pods.xcodeproj/xcuserdata/Jerry.xcuserdatad/xcschemes/Pods-DACircularProgress.xcscheme new file mode 100644 index 000000000..37206252b --- /dev/null +++ b/ios/Pods/Pods.xcodeproj/xcuserdata/Jerry.xcuserdatad/xcschemes/Pods-DACircularProgress.xcscheme @@ -0,0 +1,77 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/ios/Pods/Pods.xcodeproj/xcuserdata/Jerry.xcuserdatad/xcschemes/Pods-FMDB.xcscheme b/ios/Pods/Pods.xcodeproj/xcuserdata/Jerry.xcuserdatad/xcschemes/Pods-FMDB.xcscheme new file mode 100644 index 000000000..9c10a8a6a --- /dev/null +++ b/ios/Pods/Pods.xcodeproj/xcuserdata/Jerry.xcuserdatad/xcschemes/Pods-FMDB.xcscheme @@ -0,0 +1,77 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/ios/Pods/Pods.xcodeproj/xcuserdata/Jerry.xcuserdatad/xcschemes/Pods-HPGrowingTextView.xcscheme b/ios/Pods/Pods.xcodeproj/xcuserdata/Jerry.xcuserdatad/xcschemes/Pods-HPGrowingTextView.xcscheme new file mode 100644 index 000000000..605b953c6 --- /dev/null +++ b/ios/Pods/Pods.xcodeproj/xcuserdata/Jerry.xcuserdatad/xcschemes/Pods-HPGrowingTextView.xcscheme @@ -0,0 +1,77 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/ios/Pods/Pods.xcodeproj/xcuserdata/Jerry.xcuserdatad/xcschemes/Pods-MBProgressHUD.xcscheme b/ios/Pods/Pods.xcodeproj/xcuserdata/Jerry.xcuserdatad/xcschemes/Pods-MBProgressHUD.xcscheme new file mode 100644 index 000000000..00d98c43e --- /dev/null +++ b/ios/Pods/Pods.xcodeproj/xcuserdata/Jerry.xcuserdatad/xcschemes/Pods-MBProgressHUD.xcscheme @@ -0,0 +1,77 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/ios/Pods/Pods.xcodeproj/xcuserdata/Jerry.xcuserdatad/xcschemes/Pods-PSTCollectionView.xcscheme b/ios/Pods/Pods.xcodeproj/xcuserdata/Jerry.xcuserdatad/xcschemes/Pods-PSTCollectionView.xcscheme new file mode 100644 index 000000000..cc102220b --- /dev/null +++ b/ios/Pods/Pods.xcodeproj/xcuserdata/Jerry.xcuserdatad/xcschemes/Pods-PSTCollectionView.xcscheme @@ -0,0 +1,77 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/ios/Pods/Pods.xcodeproj/xcuserdata/Jerry.xcuserdatad/xcschemes/Pods-SDWebImage.xcscheme b/ios/Pods/Pods.xcodeproj/xcuserdata/Jerry.xcuserdatad/xcschemes/Pods-SDWebImage.xcscheme new file mode 100644 index 000000000..23c757699 --- /dev/null +++ b/ios/Pods/Pods.xcodeproj/xcuserdata/Jerry.xcuserdatad/xcschemes/Pods-SDWebImage.xcscheme @@ -0,0 +1,77 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/ios/Pods/Pods.xcodeproj/xcuserdata/Jerry.xcuserdatad/xcschemes/Pods.xcscheme b/ios/Pods/Pods.xcodeproj/xcuserdata/Jerry.xcuserdatad/xcschemes/Pods.xcscheme new file mode 100644 index 000000000..2cca96305 --- /dev/null +++ b/ios/Pods/Pods.xcodeproj/xcuserdata/Jerry.xcuserdatad/xcschemes/Pods.xcscheme @@ -0,0 +1,77 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/ios/Pods/Pods.xcodeproj/xcuserdata/Jerry.xcuserdatad/xcschemes/xcschememanagement.plist b/ios/Pods/Pods.xcodeproj/xcuserdata/Jerry.xcuserdatad/xcschemes/xcschememanagement.plist new file mode 100644 index 000000000..e79dd3ed6 --- /dev/null +++ b/ios/Pods/Pods.xcodeproj/xcuserdata/Jerry.xcuserdatad/xcschemes/xcschememanagement.plist @@ -0,0 +1,92 @@ + + + + + SchemeUserState + + Pods-AFNetworking.xcscheme + + orderHint + 2 + + Pods-DACircularProgress.xcscheme + + orderHint + 3 + + Pods-FMDB.xcscheme + + orderHint + 4 + + Pods-HPGrowingTextView.xcscheme + + orderHint + 5 + + Pods-MBProgressHUD.xcscheme + + orderHint + 6 + + Pods-PSTCollectionView.xcscheme + + orderHint + 7 + + Pods-SDWebImage.xcscheme + + orderHint + 8 + + Pods.xcscheme + + orderHint + 1 + + + SuppressBuildableAutocreation + + 13A67AD884FF4FBDB442AE71 + + primary + + + 2AC3313D48E245198EF6E097 + + primary + + + 7989B25ABCB44FB88015DE9F + + primary + + + 84CFA08D163D4AD0BEC37ABA + + primary + + + 8D55CFE933564CFB9B3E3372 + + primary + + + D677F7827166425CBE5C8CEB + + primary + + + DDC0CD7C0AF648D8B09FA131 + + primary + + + EDCC7D9519444E7EA3162ED9 + + primary + + + + + diff --git a/ios/Pods/Pods.xcodeproj/xcuserdata/Michael.xcuserdatad/xcschemes/Pods-AFNetworking.xcscheme b/ios/Pods/Pods.xcodeproj/xcuserdata/Michael.xcuserdatad/xcschemes/Pods-AFNetworking.xcscheme new file mode 100644 index 000000000..42869acd1 --- /dev/null +++ b/ios/Pods/Pods.xcodeproj/xcuserdata/Michael.xcuserdatad/xcschemes/Pods-AFNetworking.xcscheme @@ -0,0 +1,59 @@ + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/ios/Pods/Pods.xcodeproj/xcuserdata/Michael.xcuserdatad/xcschemes/Pods-DACircularProgress.xcscheme b/ios/Pods/Pods.xcodeproj/xcuserdata/Michael.xcuserdatad/xcschemes/Pods-DACircularProgress.xcscheme new file mode 100644 index 000000000..7e1cc5ec3 --- /dev/null +++ b/ios/Pods/Pods.xcodeproj/xcuserdata/Michael.xcuserdatad/xcschemes/Pods-DACircularProgress.xcscheme @@ -0,0 +1,59 @@ + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/ios/Pods/Pods.xcodeproj/xcuserdata/Michael.xcuserdatad/xcschemes/Pods-FMDB.xcscheme b/ios/Pods/Pods.xcodeproj/xcuserdata/Michael.xcuserdatad/xcschemes/Pods-FMDB.xcscheme new file mode 100644 index 000000000..2aad21422 --- /dev/null +++ b/ios/Pods/Pods.xcodeproj/xcuserdata/Michael.xcuserdatad/xcschemes/Pods-FMDB.xcscheme @@ -0,0 +1,59 @@ + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/ios/Pods/Pods.xcodeproj/xcuserdata/Michael.xcuserdatad/xcschemes/Pods-HPGrowingTextView.xcscheme b/ios/Pods/Pods.xcodeproj/xcuserdata/Michael.xcuserdatad/xcschemes/Pods-HPGrowingTextView.xcscheme new file mode 100644 index 000000000..d5c3ab1e2 --- /dev/null +++ b/ios/Pods/Pods.xcodeproj/xcuserdata/Michael.xcuserdatad/xcschemes/Pods-HPGrowingTextView.xcscheme @@ -0,0 +1,59 @@ + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/ios/Pods/Pods.xcodeproj/xcuserdata/Michael.xcuserdatad/xcschemes/Pods-MBProgressHUD.xcscheme b/ios/Pods/Pods.xcodeproj/xcuserdata/Michael.xcuserdatad/xcschemes/Pods-MBProgressHUD.xcscheme new file mode 100644 index 000000000..07ac8bd93 --- /dev/null +++ b/ios/Pods/Pods.xcodeproj/xcuserdata/Michael.xcuserdatad/xcschemes/Pods-MBProgressHUD.xcscheme @@ -0,0 +1,59 @@ + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/ios/Pods/Pods.xcodeproj/xcuserdata/Michael.xcuserdatad/xcschemes/Pods-MWPhotoBrowser.xcscheme b/ios/Pods/Pods.xcodeproj/xcuserdata/Michael.xcuserdatad/xcschemes/Pods-MWPhotoBrowser.xcscheme new file mode 100644 index 000000000..04720258e --- /dev/null +++ b/ios/Pods/Pods.xcodeproj/xcuserdata/Michael.xcuserdatad/xcschemes/Pods-MWPhotoBrowser.xcscheme @@ -0,0 +1,59 @@ + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/ios/Pods/Pods.xcodeproj/xcuserdata/Michael.xcuserdatad/xcschemes/Pods-PSTCollectionView.xcscheme b/ios/Pods/Pods.xcodeproj/xcuserdata/Michael.xcuserdatad/xcschemes/Pods-PSTCollectionView.xcscheme new file mode 100644 index 000000000..329cd77e9 --- /dev/null +++ b/ios/Pods/Pods.xcodeproj/xcuserdata/Michael.xcuserdatad/xcschemes/Pods-PSTCollectionView.xcscheme @@ -0,0 +1,59 @@ + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/ios/Pods/Pods.xcodeproj/xcuserdata/Michael.xcuserdatad/xcschemes/Pods-ProtocolBuffers.xcscheme b/ios/Pods/Pods.xcodeproj/xcuserdata/Michael.xcuserdatad/xcschemes/Pods-ProtocolBuffers.xcscheme new file mode 100644 index 000000000..c893b2b7b --- /dev/null +++ b/ios/Pods/Pods.xcodeproj/xcuserdata/Michael.xcuserdatad/xcschemes/Pods-ProtocolBuffers.xcscheme @@ -0,0 +1,59 @@ + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/ios/Pods/Pods.xcodeproj/xcuserdata/Michael.xcuserdatad/xcschemes/Pods-SCLAlertView-Objective-C.xcscheme b/ios/Pods/Pods.xcodeproj/xcuserdata/Michael.xcuserdatad/xcschemes/Pods-SCLAlertView-Objective-C.xcscheme new file mode 100644 index 000000000..0fd4fb107 --- /dev/null +++ b/ios/Pods/Pods.xcodeproj/xcuserdata/Michael.xcuserdatad/xcschemes/Pods-SCLAlertView-Objective-C.xcscheme @@ -0,0 +1,59 @@ + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/ios/Pods/Pods.xcodeproj/xcuserdata/Michael.xcuserdatad/xcschemes/Pods-SDWebImage.xcscheme b/ios/Pods/Pods.xcodeproj/xcuserdata/Michael.xcuserdatad/xcschemes/Pods-SDWebImage.xcscheme new file mode 100644 index 000000000..172585ffe --- /dev/null +++ b/ios/Pods/Pods.xcodeproj/xcuserdata/Michael.xcuserdatad/xcschemes/Pods-SDWebImage.xcscheme @@ -0,0 +1,59 @@ + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/ios/Pods/Pods.xcodeproj/xcuserdata/Michael.xcuserdatad/xcschemes/Pods-leveldb-library.xcscheme b/ios/Pods/Pods.xcodeproj/xcuserdata/Michael.xcuserdatad/xcschemes/Pods-leveldb-library.xcscheme new file mode 100644 index 000000000..bb12ac44c --- /dev/null +++ b/ios/Pods/Pods.xcodeproj/xcuserdata/Michael.xcuserdatad/xcschemes/Pods-leveldb-library.xcscheme @@ -0,0 +1,59 @@ + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/ios/Pods/Pods.xcodeproj/xcuserdata/Michael.xcuserdatad/xcschemes/Pods.xcscheme b/ios/Pods/Pods.xcodeproj/xcuserdata/Michael.xcuserdatad/xcschemes/Pods.xcscheme new file mode 100644 index 000000000..605031623 --- /dev/null +++ b/ios/Pods/Pods.xcodeproj/xcuserdata/Michael.xcuserdatad/xcschemes/Pods.xcscheme @@ -0,0 +1,59 @@ + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/ios/Pods/Pods.xcodeproj/xcuserdata/Michael.xcuserdatad/xcschemes/xcschememanagement.plist b/ios/Pods/Pods.xcodeproj/xcuserdata/Michael.xcuserdatad/xcschemes/xcschememanagement.plist new file mode 100644 index 000000000..b94a9cfa8 --- /dev/null +++ b/ios/Pods/Pods.xcodeproj/xcuserdata/Michael.xcuserdatad/xcschemes/xcschememanagement.plist @@ -0,0 +1,132 @@ + + + + + SchemeUserState + + Pods-AFNetworking.xcscheme + + isShown + + + Pods-DACircularProgress.xcscheme + + isShown + + + Pods-FMDB.xcscheme + + isShown + + + Pods-HPGrowingTextView.xcscheme + + isShown + + + Pods-MBProgressHUD.xcscheme + + isShown + + + Pods-MWPhotoBrowser.xcscheme + + isShown + + + Pods-PSTCollectionView.xcscheme + + isShown + + + Pods-ProtocolBuffers.xcscheme + + isShown + + + Pods-SCLAlertView-Objective-C.xcscheme + + isShown + + + Pods-SDWebImage.xcscheme + + isShown + + + Pods-leveldb-library.xcscheme + + isShown + + + Pods.xcscheme + + isShown + + + + SuppressBuildableAutocreation + + 09A20CC0DB72732970F408DF + + primary + + + 133A25A0D319725FEC1884B0 + + primary + + + 36C1E64DE39865525EB9A1BF + + primary + + + 436B9F8EBC9F4E16A3FE4A8E + + primary + + + 45FFB846AD2C35316261CE26 + + primary + + + 4C9AB3E89C35EEA3084D58F3 + + primary + + + 5BC12A63DA507D16082F87B8 + + primary + + + 6360D6708B351012B4113963 + + primary + + + 81C7539C5773E295433603AB + + primary + + + B2CC9370F3764EE84221A3DA + + primary + + + B68C69F6738C61A824DDA397 + + primary + + + B92B573335D8EBD876E5BAB3 + + primary + + + + + diff --git a/ios/Pods/Pods.xcodeproj/xcuserdata/lanhu.xcuserdatad/xcschemes/Pods-AFNetworking.xcscheme b/ios/Pods/Pods.xcodeproj/xcuserdata/lanhu.xcuserdatad/xcschemes/Pods-AFNetworking.xcscheme new file mode 100644 index 000000000..23c993304 --- /dev/null +++ b/ios/Pods/Pods.xcodeproj/xcuserdata/lanhu.xcuserdatad/xcschemes/Pods-AFNetworking.xcscheme @@ -0,0 +1,77 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/ios/Pods/Pods.xcodeproj/xcuserdata/lanhu.xcuserdatad/xcschemes/Pods-DACircularProgress.xcscheme b/ios/Pods/Pods.xcodeproj/xcuserdata/lanhu.xcuserdatad/xcschemes/Pods-DACircularProgress.xcscheme new file mode 100644 index 000000000..dca180b8c --- /dev/null +++ b/ios/Pods/Pods.xcodeproj/xcuserdata/lanhu.xcuserdatad/xcschemes/Pods-DACircularProgress.xcscheme @@ -0,0 +1,77 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/ios/Pods/Pods.xcodeproj/xcuserdata/lanhu.xcuserdatad/xcschemes/Pods-FMDB.xcscheme b/ios/Pods/Pods.xcodeproj/xcuserdata/lanhu.xcuserdatad/xcschemes/Pods-FMDB.xcscheme new file mode 100644 index 000000000..ffe3b0313 --- /dev/null +++ b/ios/Pods/Pods.xcodeproj/xcuserdata/lanhu.xcuserdatad/xcschemes/Pods-FMDB.xcscheme @@ -0,0 +1,77 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/ios/Pods/Pods.xcodeproj/xcuserdata/lanhu.xcuserdatad/xcschemes/Pods-HPGrowingTextView.xcscheme b/ios/Pods/Pods.xcodeproj/xcuserdata/lanhu.xcuserdatad/xcschemes/Pods-HPGrowingTextView.xcscheme new file mode 100644 index 000000000..894f98d04 --- /dev/null +++ b/ios/Pods/Pods.xcodeproj/xcuserdata/lanhu.xcuserdatad/xcschemes/Pods-HPGrowingTextView.xcscheme @@ -0,0 +1,77 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/ios/Pods/Pods.xcodeproj/xcuserdata/lanhu.xcuserdatad/xcschemes/Pods-MBProgressHUD.xcscheme b/ios/Pods/Pods.xcodeproj/xcuserdata/lanhu.xcuserdatad/xcschemes/Pods-MBProgressHUD.xcscheme new file mode 100644 index 000000000..86a1fde69 --- /dev/null +++ b/ios/Pods/Pods.xcodeproj/xcuserdata/lanhu.xcuserdatad/xcschemes/Pods-MBProgressHUD.xcscheme @@ -0,0 +1,77 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/ios/Pods/Pods.xcodeproj/xcuserdata/lanhu.xcuserdatad/xcschemes/Pods-MWPhotoBrowser.xcscheme b/ios/Pods/Pods.xcodeproj/xcuserdata/lanhu.xcuserdatad/xcschemes/Pods-MWPhotoBrowser.xcscheme new file mode 100644 index 000000000..5c2a8ddb9 --- /dev/null +++ b/ios/Pods/Pods.xcodeproj/xcuserdata/lanhu.xcuserdatad/xcschemes/Pods-MWPhotoBrowser.xcscheme @@ -0,0 +1,77 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/ios/Pods/Pods.xcodeproj/xcuserdata/lanhu.xcuserdatad/xcschemes/Pods-PSTCollectionView.xcscheme b/ios/Pods/Pods.xcodeproj/xcuserdata/lanhu.xcuserdatad/xcschemes/Pods-PSTCollectionView.xcscheme new file mode 100644 index 000000000..729eaf149 --- /dev/null +++ b/ios/Pods/Pods.xcodeproj/xcuserdata/lanhu.xcuserdatad/xcschemes/Pods-PSTCollectionView.xcscheme @@ -0,0 +1,77 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/ios/Pods/Pods.xcodeproj/xcuserdata/lanhu.xcuserdatad/xcschemes/Pods-ProtocolBuffers.xcscheme b/ios/Pods/Pods.xcodeproj/xcuserdata/lanhu.xcuserdatad/xcschemes/Pods-ProtocolBuffers.xcscheme new file mode 100644 index 000000000..0c2473336 --- /dev/null +++ b/ios/Pods/Pods.xcodeproj/xcuserdata/lanhu.xcuserdatad/xcschemes/Pods-ProtocolBuffers.xcscheme @@ -0,0 +1,77 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/ios/Pods/Pods.xcodeproj/xcuserdata/lanhu.xcuserdatad/xcschemes/Pods-SCLAlertView-Objective-C.xcscheme b/ios/Pods/Pods.xcodeproj/xcuserdata/lanhu.xcuserdatad/xcschemes/Pods-SCLAlertView-Objective-C.xcscheme new file mode 100644 index 000000000..ad401ebec --- /dev/null +++ b/ios/Pods/Pods.xcodeproj/xcuserdata/lanhu.xcuserdatad/xcschemes/Pods-SCLAlertView-Objective-C.xcscheme @@ -0,0 +1,77 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/ios/Pods/Pods.xcodeproj/xcuserdata/lanhu.xcuserdatad/xcschemes/Pods-SDWebImage.xcscheme b/ios/Pods/Pods.xcodeproj/xcuserdata/lanhu.xcuserdatad/xcschemes/Pods-SDWebImage.xcscheme new file mode 100644 index 000000000..0664968f2 --- /dev/null +++ b/ios/Pods/Pods.xcodeproj/xcuserdata/lanhu.xcuserdatad/xcschemes/Pods-SDWebImage.xcscheme @@ -0,0 +1,77 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/ios/Pods/Pods.xcodeproj/xcuserdata/lanhu.xcuserdatad/xcschemes/Pods-leveldb-library.xcscheme b/ios/Pods/Pods.xcodeproj/xcuserdata/lanhu.xcuserdatad/xcschemes/Pods-leveldb-library.xcscheme new file mode 100644 index 000000000..3014102fe --- /dev/null +++ b/ios/Pods/Pods.xcodeproj/xcuserdata/lanhu.xcuserdatad/xcschemes/Pods-leveldb-library.xcscheme @@ -0,0 +1,77 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/ios/Pods/Pods.xcodeproj/xcuserdata/lanhu.xcuserdatad/xcschemes/Pods.xcscheme b/ios/Pods/Pods.xcodeproj/xcuserdata/lanhu.xcuserdatad/xcschemes/Pods.xcscheme new file mode 100644 index 000000000..e685d4f24 --- /dev/null +++ b/ios/Pods/Pods.xcodeproj/xcuserdata/lanhu.xcuserdatad/xcschemes/Pods.xcscheme @@ -0,0 +1,77 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/ios/Pods/Pods.xcodeproj/xcuserdata/lanhu.xcuserdatad/xcschemes/xcschememanagement.plist b/ios/Pods/Pods.xcodeproj/xcuserdata/lanhu.xcuserdatad/xcschemes/xcschememanagement.plist new file mode 100644 index 000000000..fa11bd8fa --- /dev/null +++ b/ios/Pods/Pods.xcodeproj/xcuserdata/lanhu.xcuserdatad/xcschemes/xcschememanagement.plist @@ -0,0 +1,132 @@ + + + + + SchemeUserState + + Pods-AFNetworking.xcscheme + + orderHint + 2 + + Pods-DACircularProgress.xcscheme + + orderHint + 3 + + Pods-FMDB.xcscheme + + orderHint + 4 + + Pods-HPGrowingTextView.xcscheme + + orderHint + 5 + + Pods-MBProgressHUD.xcscheme + + orderHint + 6 + + Pods-MWPhotoBrowser.xcscheme + + orderHint + 7 + + Pods-PSTCollectionView.xcscheme + + orderHint + 8 + + Pods-ProtocolBuffers.xcscheme + + orderHint + 9 + + Pods-SCLAlertView-Objective-C.xcscheme + + orderHint + 10 + + Pods-SDWebImage.xcscheme + + orderHint + 11 + + Pods-leveldb-library.xcscheme + + orderHint + 12 + + Pods.xcscheme + + orderHint + 1 + + + SuppressBuildableAutocreation + + 09A20CC0DB72732970F408DF + + primary + + + 133A25A0D319725FEC1884B0 + + primary + + + 36C1E64DE39865525EB9A1BF + + primary + + + 436B9F8EBC9F4E16A3FE4A8E + + primary + + + 45FFB846AD2C35316261CE26 + + primary + + + 4C9AB3E89C35EEA3084D58F3 + + primary + + + 5BC12A63DA507D16082F87B8 + + primary + + + 6360D6708B351012B4113963 + + primary + + + 81C7539C5773E295433603AB + + primary + + + B2CC9370F3764EE84221A3DA + + primary + + + B68C69F6738C61A824DDA397 + + primary + + + B92B573335D8EBD876E5BAB3 + + primary + + + + + diff --git a/ios/Pods/Pods.xcodeproj/xcuserdata/scorpio.xcuserdatad/xcschemes/Pods-AFNetworking.xcscheme b/ios/Pods/Pods.xcodeproj/xcuserdata/scorpio.xcuserdatad/xcschemes/Pods-AFNetworking.xcscheme new file mode 100644 index 000000000..8fa41c4af --- /dev/null +++ b/ios/Pods/Pods.xcodeproj/xcuserdata/scorpio.xcuserdatad/xcschemes/Pods-AFNetworking.xcscheme @@ -0,0 +1,59 @@ + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/ios/Pods/Pods.xcodeproj/xcuserdata/scorpio.xcuserdatad/xcschemes/Pods-DACircularProgress.xcscheme b/ios/Pods/Pods.xcodeproj/xcuserdata/scorpio.xcuserdatad/xcschemes/Pods-DACircularProgress.xcscheme new file mode 100644 index 000000000..8f102a08a --- /dev/null +++ b/ios/Pods/Pods.xcodeproj/xcuserdata/scorpio.xcuserdatad/xcschemes/Pods-DACircularProgress.xcscheme @@ -0,0 +1,59 @@ + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/ios/Pods/Pods.xcodeproj/xcuserdata/scorpio.xcuserdatad/xcschemes/Pods-FMDB.xcscheme b/ios/Pods/Pods.xcodeproj/xcuserdata/scorpio.xcuserdatad/xcschemes/Pods-FMDB.xcscheme new file mode 100644 index 000000000..91cf8fe03 --- /dev/null +++ b/ios/Pods/Pods.xcodeproj/xcuserdata/scorpio.xcuserdatad/xcschemes/Pods-FMDB.xcscheme @@ -0,0 +1,59 @@ + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/ios/Pods/Pods.xcodeproj/xcuserdata/scorpio.xcuserdatad/xcschemes/Pods-HPGrowingTextView.xcscheme b/ios/Pods/Pods.xcodeproj/xcuserdata/scorpio.xcuserdatad/xcschemes/Pods-HPGrowingTextView.xcscheme new file mode 100644 index 000000000..f9ccf856a --- /dev/null +++ b/ios/Pods/Pods.xcodeproj/xcuserdata/scorpio.xcuserdatad/xcschemes/Pods-HPGrowingTextView.xcscheme @@ -0,0 +1,59 @@ + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/ios/Pods/Pods.xcodeproj/xcuserdata/scorpio.xcuserdatad/xcschemes/Pods-MBProgressHUD.xcscheme b/ios/Pods/Pods.xcodeproj/xcuserdata/scorpio.xcuserdatad/xcschemes/Pods-MBProgressHUD.xcscheme new file mode 100644 index 000000000..84c211c13 --- /dev/null +++ b/ios/Pods/Pods.xcodeproj/xcuserdata/scorpio.xcuserdatad/xcschemes/Pods-MBProgressHUD.xcscheme @@ -0,0 +1,59 @@ + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/ios/Pods/Pods.xcodeproj/xcuserdata/scorpio.xcuserdatad/xcschemes/Pods-PSTCollectionView.xcscheme b/ios/Pods/Pods.xcodeproj/xcuserdata/scorpio.xcuserdatad/xcschemes/Pods-PSTCollectionView.xcscheme new file mode 100644 index 000000000..da9437dc7 --- /dev/null +++ b/ios/Pods/Pods.xcodeproj/xcuserdata/scorpio.xcuserdatad/xcschemes/Pods-PSTCollectionView.xcscheme @@ -0,0 +1,59 @@ + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/ios/Pods/Pods.xcodeproj/xcuserdata/scorpio.xcuserdatad/xcschemes/Pods-ProtocolBuffers.xcscheme b/ios/Pods/Pods.xcodeproj/xcuserdata/scorpio.xcuserdatad/xcschemes/Pods-ProtocolBuffers.xcscheme new file mode 100644 index 000000000..3eff4d692 --- /dev/null +++ b/ios/Pods/Pods.xcodeproj/xcuserdata/scorpio.xcuserdatad/xcschemes/Pods-ProtocolBuffers.xcscheme @@ -0,0 +1,59 @@ + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/ios/Pods/Pods.xcodeproj/xcuserdata/scorpio.xcuserdatad/xcschemes/Pods-SDWebImage.xcscheme b/ios/Pods/Pods.xcodeproj/xcuserdata/scorpio.xcuserdatad/xcschemes/Pods-SDWebImage.xcscheme new file mode 100644 index 000000000..05e38d31a --- /dev/null +++ b/ios/Pods/Pods.xcodeproj/xcuserdata/scorpio.xcuserdatad/xcschemes/Pods-SDWebImage.xcscheme @@ -0,0 +1,59 @@ + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/ios/Pods/Pods.xcodeproj/xcuserdata/scorpio.xcuserdatad/xcschemes/Pods-leveldb-library.xcscheme b/ios/Pods/Pods.xcodeproj/xcuserdata/scorpio.xcuserdatad/xcschemes/Pods-leveldb-library.xcscheme new file mode 100644 index 000000000..fd910944e --- /dev/null +++ b/ios/Pods/Pods.xcodeproj/xcuserdata/scorpio.xcuserdatad/xcschemes/Pods-leveldb-library.xcscheme @@ -0,0 +1,59 @@ + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/ios/Pods/Pods.xcodeproj/xcuserdata/scorpio.xcuserdatad/xcschemes/Pods.xcscheme b/ios/Pods/Pods.xcodeproj/xcuserdata/scorpio.xcuserdatad/xcschemes/Pods.xcscheme new file mode 100644 index 000000000..660a642d9 --- /dev/null +++ b/ios/Pods/Pods.xcodeproj/xcuserdata/scorpio.xcuserdatad/xcschemes/Pods.xcscheme @@ -0,0 +1,59 @@ + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/ios/Pods/Pods.xcodeproj/xcuserdata/scorpio.xcuserdatad/xcschemes/xcschememanagement.plist b/ios/Pods/Pods.xcodeproj/xcuserdata/scorpio.xcuserdatad/xcschemes/xcschememanagement.plist new file mode 100644 index 000000000..048f24ce8 --- /dev/null +++ b/ios/Pods/Pods.xcodeproj/xcuserdata/scorpio.xcuserdatad/xcschemes/xcschememanagement.plist @@ -0,0 +1,112 @@ + + + + + SchemeUserState + + Pods-AFNetworking.xcscheme + + isShown + + + Pods-DACircularProgress.xcscheme + + isShown + + + Pods-FMDB.xcscheme + + isShown + + + Pods-HPGrowingTextView.xcscheme + + isShown + + + Pods-MBProgressHUD.xcscheme + + isShown + + + Pods-PSTCollectionView.xcscheme + + isShown + + + Pods-ProtocolBuffers.xcscheme + + isShown + + + Pods-SDWebImage.xcscheme + + isShown + + + Pods-leveldb-library.xcscheme + + isShown + + + Pods.xcscheme + + isShown + + + + SuppressBuildableAutocreation + + 0EFE6B44E20C2BBA069A1044 + + primary + + + 2950C41F98D48B4535CCA75E + + primary + + + 3CB1CB02B0DD333BEA8D6A10 + + primary + + + 4D13BB07CD5A81581C758842 + + primary + + + 572FE3DED003891544C66FF6 + + primary + + + 74D98A64FF4B8A093C472D5A + + primary + + + 978ED7EBC352D4C9A77377D5 + + primary + + + A84920EA7273C8D4F725CEBB + + primary + + + AE9187021EB6AA9C97D78F06 + + primary + + + C95723CB9A46322FB2862015 + + primary + + + + + diff --git a/ios/Pods/ProtocolBuffers/README.md b/ios/Pods/ProtocolBuffers/README.md new file mode 100644 index 000000000..cf0dbde37 --- /dev/null +++ b/ios/Pods/ProtocolBuffers/README.md @@ -0,0 +1,71 @@ +Protocol Buffers for Objective-C +================================ + +[![Build Status](https://travis-ci.org/alexeyxo/protobuf-objc.svg?branch=master)](https://travis-ci.org/alexeyxo/protobuf-objc) [![Version](http://img.shields.io/cocoapods/v/ProtocolBuffers.svg)](http://cocoapods.org/?q=ProtocolBuffers) [![Platform](http://img.shields.io/cocoapods/p/ProtocolBuffers.svg)](http://cocoapods.org/?q=ProtocolBuffers) + +An implementation of Protocol Buffers in Objective C. + +Protocol Buffers are a way of encoding structured data in an efficient yet extensible format. This project is based on an implementation of Protocol Buffers from Google. See the [Google protobuf project](https://developers.google.com/protocol-buffers/docs/overview) for more information. + +This fork contains only ARC version of library. + +How To Install Protobuf +----------------------- + +1.`ruby -e "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install)"` + +2.`brew install automake` + +3.`brew install libtool` + +4.`brew instal protobuf` + +5.`ln -s /usr/local/Cellar/protobuf/2.6.1/bin/protoc /usr/local/bin` (optional) + +6.`git clone git@github.com:alexeyxo/protobuf-objc.git` + +7.`./build.sh` + +8.Add `/src/runtime/ProtocolBuffers.xcodeproj` in your project. + +##Installing from CocoaPods + +... + +8.`cd ` + +9.`echo -e "platform :ios , 6.0 \nlink_with '', '' \npod 'ProtocolBuffers', '1.9.2' " > Podfile` + +10.`pod install` + +Compile ".proto" files. +----------------------- + +`protoc --plugin=/usr/local/bin/protoc-gen-objc person.proto --objc_out="./"` + +Example +------- + +### Web + +Server-side requires Ruby(2.0+) and Sinatra gem. + +To start `ruby sinatra.rb` in /Example/Web + +if you need to recompile ruby proto models please install ruby_protobuf gem and make 'rprotoc person.proto' + +### iOS Example + +/Example/iOS/Proto.xcodeproj + +Project contains protobuf example and small json comparison. + +### Credits + +Maintainer - Alexey Khokhlov + +Booyah Inc. - Jon Parise + +Google Protocol Buffers, Objective C - Cyrus Najmabadi - Sergey Martynov + +Google Protocol Buffers - Kenton Varda, Sanjay Ghemawat, Jeff Dean, and others diff --git a/ios/Pods/ProtocolBuffers/src/runtime/Classes/AbstractMessage.h b/ios/Pods/ProtocolBuffers/src/runtime/Classes/AbstractMessage.h new file mode 100644 index 000000000..b3004c750 --- /dev/null +++ b/ios/Pods/ProtocolBuffers/src/runtime/Classes/AbstractMessage.h @@ -0,0 +1,37 @@ +// Protocol Buffers for Objective C +// +// Copyright 2010 Booyah Inc. +// Copyright 2008 Cyrus Najmabadi +// +// 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. + +#import "Message.h" + +/** + * A partial implementation of the {@link Message} interface which implements + * as many methods of that interface as possible in terms of other methods. + * + * @author Cyrus Najmabadi + */ +@interface PBAbstractMessage : NSObject { +@private +} + +/** + * Writes a string description of the message into the given mutable string + * respecting a given indent. + */ +- (void)writeDescriptionTo:(NSMutableString*) output + withIndent:(NSString*) indent; + +@end diff --git a/ios/Pods/ProtocolBuffers/src/runtime/Classes/AbstractMessage.m b/ios/Pods/ProtocolBuffers/src/runtime/Classes/AbstractMessage.m new file mode 100644 index 000000000..f81991531 --- /dev/null +++ b/ios/Pods/ProtocolBuffers/src/runtime/Classes/AbstractMessage.m @@ -0,0 +1,95 @@ +// Protocol Buffers for Objective C +// +// Copyright 2010 Booyah Inc. +// Copyright 2008 Cyrus Najmabadi +// +// 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. + +#import "AbstractMessage.h" + +#import "CodedOutputStream.h" + +@implementation PBAbstractMessage + +- (id) init { + if ((self = [super init])) { + } + + return self; +} + + +- (NSData*) data { + NSMutableData* data = [NSMutableData dataWithLength:self.serializedSize]; + PBCodedOutputStream* stream = [PBCodedOutputStream streamWithData:data]; + [self writeToCodedOutputStream:stream]; + return data; +} + + +- (BOOL) isInitialized { + @throw [NSException exceptionWithName:@"ImproperSubclassing" reason:@"" userInfo:nil]; +} + + +- (SInt32) serializedSize { + @throw [NSException exceptionWithName:@"ImproperSubclassing" reason:@"" userInfo:nil]; +} + + +- (void) writeToCodedOutputStream:(PBCodedOutputStream*) output { + @throw [NSException exceptionWithName:@"ImproperSubclassing" reason:@"" userInfo:nil]; +} + + +- (void) writeToOutputStream:(NSOutputStream*) output { + PBCodedOutputStream* codedOutput = [PBCodedOutputStream streamWithOutputStream:output]; + [self writeToCodedOutputStream:codedOutput]; + [codedOutput flush]; +} + + +- (id) defaultInstance { + @throw [NSException exceptionWithName:@"ImproperSubclassing" reason:@"" userInfo:nil]; +} + + +- (PBUnknownFieldSet*) unknownFields { + @throw [NSException exceptionWithName:@"ImproperSubclassing" reason:@"" userInfo:nil]; +} + + +- (id) builder { + @throw [NSException exceptionWithName:@"ImproperSubclassing" reason:@"" userInfo:nil]; +} + + +- (id) toBuilder { + @throw [NSException exceptionWithName:@"ImproperSubclassing" reason:@"" userInfo:nil]; +} + + +- (void) writeDescriptionTo:(NSMutableString*) output + withIndent:(NSString*) indent { + @throw [NSException exceptionWithName:@"ImproperSubclassing" reason:@"" userInfo:nil]; +} + + +- (NSString*) description { + NSMutableString* output = [NSMutableString string]; + [self writeDescriptionTo:output withIndent:@""]; + return output; +} + + +@end diff --git a/ios/Pods/ProtocolBuffers/src/runtime/Classes/AbstractMessageBuilder.h b/ios/Pods/ProtocolBuffers/src/runtime/Classes/AbstractMessageBuilder.h new file mode 100644 index 000000000..9c454d4e4 --- /dev/null +++ b/ios/Pods/ProtocolBuffers/src/runtime/Classes/AbstractMessageBuilder.h @@ -0,0 +1,29 @@ +// Protocol Buffers for Objective C +// +// Copyright 2010 Booyah Inc. +// Copyright 2008 Cyrus Najmabadi +// +// 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. + +#import "MessageBuilder.h" + +/** + * A partial implementation of the {@link Message.Builder} interface which + * implements as many methods of that interface as possible in terms of + * other methods. + */ +@interface PBAbstractMessageBuilder : NSObject { +} + +@end + diff --git a/ios/Pods/ProtocolBuffers/src/runtime/Classes/AbstractMessageBuilder.m b/ios/Pods/ProtocolBuffers/src/runtime/Classes/AbstractMessageBuilder.m new file mode 100644 index 000000000..1d162efdd --- /dev/null +++ b/ios/Pods/ProtocolBuffers/src/runtime/Classes/AbstractMessageBuilder.m @@ -0,0 +1,123 @@ +// Protocol Buffers for Objective C +// +// Copyright 2010 Booyah Inc. +// Copyright 2008 Cyrus Najmabadi +// +// 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. + +#import "AbstractMessageBuilder.h" + +#import "CodedInputStream.h" +#import "ExtensionRegistry.h" +#import "MessageBuilder.h" +#import "UnknownFieldSet.h" +#import "UnknownFieldSetBuilder.h" + + +@implementation PBAbstractMessageBuilder + +- (id) clone { + @throw [NSException exceptionWithName:@"ImproperSubclassing" reason:@"" userInfo:nil]; +} + + +- (id) clear { + @throw [NSException exceptionWithName:@"ImproperSubclassing" reason:@"" userInfo:nil]; +} + + +- (id) mergeFromCodedInputStream:(PBCodedInputStream*) input { + return [self mergeFromCodedInputStream:input extensionRegistry:[PBExtensionRegistry emptyRegistry]]; +} + + +- (id) mergeFromCodedInputStream:(PBCodedInputStream*) input + extensionRegistry:(PBExtensionRegistry*) extensionRegistry { + @throw [NSException exceptionWithName:@"ImproperSubclassing" reason:@"" userInfo:nil]; +} + + +- (id) mergeUnknownFields:(PBUnknownFieldSet*) unknownFields { + PBUnknownFieldSet* merged = + [[[PBUnknownFieldSet builderWithUnknownFields:self.unknownFields] + mergeUnknownFields:unknownFields] build]; + + [self setUnknownFields:merged]; + return self; +} + + +- (id) mergeFromData:(NSData*) data { + PBCodedInputStream* input = [PBCodedInputStream streamWithData:data]; + [self mergeFromCodedInputStream:input]; + [input checkLastTagWas:0]; + return self; +} + + +- (id) mergeFromData:(NSData*) data + extensionRegistry:(PBExtensionRegistry*) extensionRegistry { + PBCodedInputStream* input = [PBCodedInputStream streamWithData:data]; + [self mergeFromCodedInputStream:input extensionRegistry:extensionRegistry]; + [input checkLastTagWas:0]; + return self; +} + + +- (id) mergeFromInputStream:(NSInputStream*) input { + PBCodedInputStream* codedInput = [PBCodedInputStream streamWithInputStream:input]; + [self mergeFromCodedInputStream:codedInput]; + [codedInput checkLastTagWas:0]; + return self; +} + + +- (id) mergeFromInputStream:(NSInputStream*) input + extensionRegistry:(PBExtensionRegistry*) extensionRegistry { + PBCodedInputStream* codedInput = [PBCodedInputStream streamWithInputStream:input]; + [self mergeFromCodedInputStream:codedInput extensionRegistry:extensionRegistry]; + [codedInput checkLastTagWas:0]; + return self; +} + + +- (id) build { + @throw [NSException exceptionWithName:@"ImproperSubclassing" reason:@"" userInfo:nil]; +} + + +- (id) buildPartial { + @throw [NSException exceptionWithName:@"ImproperSubclassing" reason:@"" userInfo:nil]; +} + + +- (BOOL) isInitialized { + @throw [NSException exceptionWithName:@"ImproperSubclassing" reason:@"" userInfo:nil]; +} + + +- (id) defaultInstance { + @throw [NSException exceptionWithName:@"ImproperSubclassing" reason:@"" userInfo:nil]; +} + + +- (PBUnknownFieldSet*) unknownFields { + @throw [NSException exceptionWithName:@"ImproperSubclassing" reason:@"" userInfo:nil]; +} + + +- (id) setUnknownFields:(PBUnknownFieldSet*) unknownFields { + @throw [NSException exceptionWithName:@"ImproperSubclassing" reason:@"" userInfo:nil]; +} + +@end diff --git a/ios/Pods/ProtocolBuffers/src/runtime/Classes/Bootstrap.h b/ios/Pods/ProtocolBuffers/src/runtime/Classes/Bootstrap.h new file mode 100644 index 000000000..8928c1ad5 --- /dev/null +++ b/ios/Pods/ProtocolBuffers/src/runtime/Classes/Bootstrap.h @@ -0,0 +1,30 @@ +// Protocol Buffers for Objective C +// +// Copyright 2010 Booyah Inc. +// Copyright 2008 Cyrus Najmabadi +// +// 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. + +#import "ForwardDeclarations.h" + +#import "CodedInputStream.h" +#import "CodedOutputStream.h" +#import "ExtendableMessage.h" +#import "ExtendableMessageBuilder.h" +#import "ExtensionRegistry.h" +#import "GeneratedMessage.h" +#import "GeneratedMessageBuilder.h" +#import "MessageBuilder.h" +#import "UnknownFieldSet.h" +#import "UnknownFieldSetBuilder.h" +#import "Utilities.h" diff --git a/ios/Pods/ProtocolBuffers/src/runtime/Classes/CodedInputStream.h b/ios/Pods/ProtocolBuffers/src/runtime/Classes/CodedInputStream.h new file mode 100644 index 000000000..0170cb44b --- /dev/null +++ b/ios/Pods/ProtocolBuffers/src/runtime/Classes/CodedInputStream.h @@ -0,0 +1,166 @@ +// Protocol Buffers for Objective C +// +// Copyright 2010 Booyah Inc. +// Copyright 2008 Cyrus Najmabadi +// +// 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. + +@class PBExtensionRegistry; +@class PBUnknownFieldSetBuilder; +@protocol PBMessageBuilder; + +/** + * Reads and decodes protocol message fields. + * + * This class contains two kinds of methods: methods that read specific + * protocol message constructs and field types (e.g. {@link #readTag()} and + * {@link #readInt32()}) and methods that read low-level values (e.g. + * {@link #readRawVarint32()} and {@link #readRawBytes}). If you are reading + * encoded protocol messages, you should use the former methods, but if you are + * reading some other format of your own design, use the latter. + * + * @author Cyrus Najmabadi + */ +@interface PBCodedInputStream : NSObject { +@private + NSMutableData* buffer; + SInt32 bufferSize; + SInt32 bufferSizeAfterLimit; + SInt32 bufferPos; + NSInputStream* input; + SInt32 lastTag; + + /** + * The total number of bytes read before the current buffer. The total + * bytes read up to the current position can be computed as + * {@code totalBytesRetired + bufferPos}. + */ + SInt32 totalBytesRetired; + + /** The absolute position of the end of the current message. */ + SInt32 currentLimit; + + /** See setRecursionLimit() */ + SInt32 recursionDepth; + SInt32 recursionLimit; + + /** See setSizeLimit() */ + SInt32 sizeLimit; +} + ++ (PBCodedInputStream*) streamWithData:(NSData*) data; ++ (PBCodedInputStream*) streamWithInputStream:(NSInputStream*) input; + +/** + * Attempt to read a field tag, returning zero if we have reached EOF. + * Protocol message parsers use this to read tags, since a protocol message + * may legally end wherever a tag occurs, and zero is not a valid tag number. + */ +- (SInt32) readTag; +- (BOOL) refillBuffer:(BOOL) mustSucceed; + +- (Float64) readDouble; +- (Float32) readFloat; +- (SInt64) readUInt64; +- (SInt32) readUInt32; +- (SInt64) readInt64; +- (SInt32) readInt32; +- (SInt64) readFixed64; +- (SInt32) readFixed32; +- (SInt32) readEnum; +- (SInt32) readSFixed32; +- (SInt64) readSFixed64; +- (SInt32) readSInt32; +- (SInt64) readSInt64; + +/** + * Read one byte from the input. + * + * @throws InvalidProtocolBuffer The end of the stream or the current + * limit was reached. + */ +- (int8_t) readRawByte; + +/** + * Read a raw Varint from the stream. If larger than 32 bits, discard the + * upper bits. + */ +- (SInt32) readRawVarint32; +- (SInt64) readRawVarint64; +- (SInt32) readRawLittleEndian32; +- (SInt64) readRawLittleEndian64; + +/** + * Read a fixed size of bytes from the input. + * + * @throws InvalidProtocolBuffer The end of the stream or the current + * limit was reached. + */ +- (NSData*) readRawData:(SInt32) size; + +/** + * Reads and discards a single field, given its tag value. + * + * @return {@code false} if the tag is an endgroup tag, in which case + * nothing is skipped. Otherwise, returns {@code true}. + */ +- (BOOL) skipField:(SInt32) tag; + + +/** + * Reads and discards {@code size} bytes. + * + * @throws InvalidProtocolBuffer The end of the stream or the current + * limit was reached. + */ +- (void) skipRawData:(SInt32) size; + +/** + * Reads and discards an entire message. This will read either until EOF + * or until an endgroup tag, whichever comes first. + */ +- (void) skipMessage; + +- (BOOL) isAtEnd; +- (SInt32) pushLimit:(SInt32) byteLimit; +- (void) recomputeBufferSizeAfterLimit; +- (void) popLimit:(SInt32) oldLimit; +- (SInt32) bytesUntilLimit; + + +/** Read an embedded message field value from the stream. */ +- (void) readMessage:(id) builder extensionRegistry:(PBExtensionRegistry*) extensionRegistry; + +- (BOOL) readBool; +- (NSString*) readString; +- (NSData*) readData; + +- (void) readGroup:(SInt32) fieldNumber builder:(id) builder extensionRegistry:(PBExtensionRegistry*) extensionRegistry; + +/** + * Reads a {@code group} field value from the stream and merges it into the + * given {@link UnknownFieldSet}. + */ +- (void) readUnknownGroup:(SInt32) fieldNumber builder:(PBUnknownFieldSetBuilder*) builder; + +/** + * Verifies that the last call to readTag() returned the given tag value. + * This is used to verify that a nested group ended with the correct + * end tag. + * + * @throws InvalidProtocolBuffer {@code value} does not match the + * last tag. + */ +- (void) checkLastTagWas:(SInt32) value; + +@end diff --git a/ios/Pods/ProtocolBuffers/src/runtime/Classes/CodedInputStream.m b/ios/Pods/ProtocolBuffers/src/runtime/Classes/CodedInputStream.m new file mode 100644 index 000000000..47d24501b --- /dev/null +++ b/ios/Pods/ProtocolBuffers/src/runtime/Classes/CodedInputStream.m @@ -0,0 +1,763 @@ +// Protocol Buffers for Objective C +// +// Copyright 2010 Booyah Inc. +// Copyright 2008 Cyrus Najmabadi +// +// 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. + +#import "CodedInputStream.h" + +#import "MessageBuilder.h" +#import "Utilities.h" +#import "WireFormat.h" +#import "UnknownFieldSetBuilder.h" +#import "UnknownFieldSet.h" + + +@interface PBCodedInputStream () +@property (strong) NSMutableData* buffer; +@property (strong) NSInputStream* input; +@end + + +@implementation PBCodedInputStream + +const SInt32 DEFAULT_RECURSION_LIMIT = 64; +const SInt32 DEFAULT_SIZE_LIMIT = 64 << 20; // 64MB +const SInt32 BUFFER_SIZE = 4096; + +@synthesize buffer; +@synthesize input; + + + + +- (void) commonInit { + currentLimit = INT_MAX; + recursionLimit = DEFAULT_RECURSION_LIMIT; + sizeLimit = DEFAULT_SIZE_LIMIT; +} + + +- (id) initWithData:(NSData*) data { + if ((self = [super init])) { + self.buffer = [NSMutableData dataWithData:data]; + bufferSize = (UInt32)buffer.length; + self.input = nil; + [self commonInit]; + } + + return self; +} + + +- (id) initWithInputStream:(NSInputStream*) input_ { + if ((self = [super init])) { + self.buffer = [NSMutableData dataWithLength:BUFFER_SIZE]; + bufferSize = 0; + self.input = input_; + [input open]; + [self commonInit]; + } + + return self; +} + + ++ (PBCodedInputStream*) streamWithData:(NSData*) data { + return [[PBCodedInputStream alloc] initWithData:data]; +} + + ++ (PBCodedInputStream*) streamWithInputStream:(NSInputStream*) input { + return [[PBCodedInputStream alloc] initWithInputStream:input]; +} + + +/** + * Attempt to read a field tag, returning zero if we have reached EOF. + * Protocol message parsers use this to read tags, since a protocol message + * may legally end wherever a tag occurs, and zero is not a valid tag number. + */ +- (SInt32) readTag { + if (self.isAtEnd) { + lastTag = 0; + return 0; + } + + lastTag = [self readRawVarint32]; + if (lastTag == 0) { + // If we actually read zero, that's not a valid tag. + @throw [NSException exceptionWithName:@"InvalidProtocolBuffer" reason:@"Invalid Tag" userInfo:nil]; + } + return lastTag; +} + +/** + * Verifies that the last call to readTag() returned the given tag value. + * This is used to verify that a nested group ended with the correct + * end tag. + * + * @throws InvalidProtocolBufferException {@code value} does not match the + * last tag. + */ +- (void) checkLastTagWas:(SInt32) value { + if (lastTag != value) { + @throw [NSException exceptionWithName:@"InvalidProtocolBuffer" reason:@"Invalid End Tag" userInfo:nil]; + } +} + +/** + * Reads and discards a single field, given its tag value. + * + * @return {@code NO} if the tag is an endgroup tag, in which case + * nothing is skipped. Otherwise, returns {@code YES}. + */ +- (BOOL) skipField:(SInt32) tag { + switch (PBWireFormatGetTagWireType(tag)) { + case PBWireFormatVarint: + [self readInt32]; + return YES; + case PBWireFormatFixed64: + [self readRawLittleEndian64]; + return YES; + case PBWireFormatLengthDelimited: + [self skipRawData:[self readRawVarint32]]; + return YES; + case PBWireFormatStartGroup: + [self skipMessage]; + [self checkLastTagWas: + PBWireFormatMakeTag(PBWireFormatGetTagFieldNumber(tag), + PBWireFormatEndGroup)]; + return YES; + case PBWireFormatEndGroup: + return NO; + case PBWireFormatFixed32: + [self readRawLittleEndian32]; + return YES; + default: + @throw [NSException exceptionWithName:@"InvalidProtocolBuffer" reason:@"Invalid Wire Type" userInfo:nil]; + } +} + + +/** + * Reads and discards an entire message. This will read either until EOF + * or until an endgroup tag, whichever comes first. + */ +- (void) skipMessage { + while (YES) { + SInt32 tag = [self readTag]; + if (tag == 0 || ![self skipField:tag]) { + return; + } + } +} + + +/** Read a {@code double} field value from the stream. */ +- (Float64) readDouble { + return convertInt64ToFloat64([self readRawLittleEndian64]); +} + + +/** Read a {@code float} field value from the stream. */ +- (Float32) readFloat { + return convertInt32ToFloat32([self readRawLittleEndian32]); +} + + +/** Read a {@code uint64} field value from the stream. */ +- (SInt64) readUInt64 { + return [self readRawVarint64]; +} + + +/** Read an {@code int64} field value from the stream. */ +- (SInt64) readInt64 { + return [self readRawVarint64]; +} + + +/** Read an {@code int32} field value from the stream. */ +- (SInt32) readInt32 { + return [self readRawVarint32]; +} + + +/** Read a {@code fixed64} field value from the stream. */ +- (SInt64) readFixed64 { + return [self readRawLittleEndian64]; +} + + +/** Read a {@code fixed32} field value from the stream. */ +- (SInt32) readFixed32 { + return [self readRawLittleEndian32]; +} + + +/** Read a {@code bool} field value from the stream. */ +- (BOOL) readBool { + return [self readRawVarint32] != 0; +} + + +/** Read a {@code string} field value from the stream. */ +- (NSString*) readString { + SInt32 size = [self readRawVarint32]; + if (size <= (bufferSize - bufferPos) && size > 0) { + // Fast path: We already have the bytes in a contiguous buffer, so + // just copy directly from it. + // new String(buffer, bufferPos, size, "UTF-8"); + NSString* result = [[NSString alloc] initWithBytes:(((uint8_t*) buffer.bytes) + bufferPos) + length:size + encoding:NSUTF8StringEncoding]; + bufferPos += size; + return result; + } else { + // Slow path: Build a byte array first then copy it. + NSData* data = [self readRawData:size]; + return [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding]; + } +} + + +/** Read a {@code group} field value from the stream. */ +- (void) readGroup:(SInt32) fieldNumber + builder:(id) builder + extensionRegistry:(PBExtensionRegistry*) extensionRegistry { + if (recursionDepth >= recursionLimit) { + @throw [NSException exceptionWithName:@"InvalidProtocolBuffer" reason:@"Recursion Limit Exceeded" userInfo:nil]; + } + ++recursionDepth; + [builder mergeFromCodedInputStream:self extensionRegistry:extensionRegistry]; + [self checkLastTagWas:PBWireFormatMakeTag(fieldNumber, PBWireFormatEndGroup)]; + --recursionDepth; +} + + +/** + * Reads a {@code group} field value from the stream and merges it into the + * given {@link PBUnknownFieldSet}. + */ +- (void) readUnknownGroup:(SInt32) fieldNumber + builder:(PBUnknownFieldSetBuilder*) builder { + if (recursionDepth >= recursionLimit) { + @throw [NSException exceptionWithName:@"InvalidProtocolBuffer" reason:@"Recursion Limit Exceeded" userInfo:nil]; + } + ++recursionDepth; + [builder mergeFromCodedInputStream:self]; + [self checkLastTagWas:PBWireFormatMakeTag(fieldNumber, PBWireFormatEndGroup)]; + --recursionDepth; +} + + +/** Read an embedded message field value from the stream. */ +- (void) readMessage:(id) builder + extensionRegistry:(PBExtensionRegistry*) extensionRegistry { + SInt32 length = [self readRawVarint32]; + if (recursionDepth >= recursionLimit) { + @throw [NSException exceptionWithName:@"InvalidProtocolBuffer" reason:@"Recursion Limit Exceeded" userInfo:nil]; + } + SInt32 oldLimit = [self pushLimit:length]; + ++recursionDepth; + [builder mergeFromCodedInputStream:self extensionRegistry:extensionRegistry]; + [self checkLastTagWas:0]; + --recursionDepth; + [self popLimit:oldLimit]; +} + + +/** Read a {@code bytes} field value from the stream. */ +- (NSData*) readData { + SInt32 size = [self readRawVarint32]; + if (size < bufferSize - bufferPos && size > 0) { + // Fast path: We already have the bytes in a contiguous buffer, so + // just copy directly from it. + NSData* result = [NSData dataWithBytes:(((uint8_t*) buffer.bytes) + bufferPos) length:size]; + bufferPos += size; + return result; + } else { + // Slow path: Build a byte array first then copy it. + return [self readRawData:size]; + } +} + + +/** Read a {@code uint32} field value from the stream. */ +- (SInt32) readUInt32 { + return [self readRawVarint32]; +} + + +/** + * Read an enum field value from the stream. Caller is responsible + * for converting the numeric value to an actual enum. + */ +- (SInt32) readEnum { + return [self readRawVarint32]; +} + + +/** Read an {@code sfixed32} field value from the stream. */ +- (SInt32) readSFixed32 { + return [self readRawLittleEndian32]; +} + + +/** Read an {@code sfixed64} field value from the stream. */ +- (SInt64) readSFixed64 { + return [self readRawLittleEndian64]; +} + + +/** Read an {@code sint32} field value from the stream. */ +- (SInt32) readSInt32 { + return decodeZigZag32([self readRawVarint32]); +} + + +/** Read an {@code sint64} field value from the stream. */ +- (SInt64) readSInt64 { + return decodeZigZag64([self readRawVarint64]); +} + + +// ================================================================= + +/** + * Read a raw Varint from the stream. If larger than 32 bits, discard the + * upper bits. + */ +- (SInt32) readRawVarint32 { + int8_t tmp = [self readRawByte]; + if (tmp >= 0) { + return tmp; + } + SInt32 result = tmp & 0x7f; + if ((tmp = [self readRawByte]) >= 0) { + result |= tmp << 7; + } else { + result |= (tmp & 0x7f) << 7; + if ((tmp = [self readRawByte]) >= 0) { + result |= tmp << 14; + } else { + result |= (tmp & 0x7f) << 14; + if ((tmp = [self readRawByte]) >= 0) { + result |= tmp << 21; + } else { + result |= (tmp & 0x7f) << 21; + result |= (tmp = [self readRawByte]) << 28; + if (tmp < 0) { + // Discard upper 32 bits. + for (int i = 0; i < 5; i++) { + if ([self readRawByte] >= 0) { + return result; + } + } + @throw [NSException exceptionWithName:@"InvalidProtocolBuffer" reason:@"malformedVarint" userInfo:nil]; + } + } + } + } + return result; +} + + +/** Read a raw Varint from the stream. */ +- (SInt64) readRawVarint64 { + SInt32 shift = 0; + SInt64 result = 0; + while (shift < 64) { + int8_t b = [self readRawByte]; + result |= (SInt64)(b & 0x7F) << shift; + if ((b & 0x80) == 0) { + return result; + } + shift += 7; + } + @throw [NSException exceptionWithName:@"InvalidProtocolBuffer" reason:@"malformedVarint" userInfo:nil]; +} + + +/** Read a 32-bit little-endian integer from the stream. */ +- (SInt32) readRawLittleEndian32 { + int8_t b1 = [self readRawByte]; + int8_t b2 = [self readRawByte]; + int8_t b3 = [self readRawByte]; + int8_t b4 = [self readRawByte]; + return + (((SInt32)b1 & 0xff) ) | + (((SInt32)b2 & 0xff) << 8) | + (((SInt32)b3 & 0xff) << 16) | + (((SInt32)b4 & 0xff) << 24); +} + + +/** Read a 64-bit little-endian integer from the stream. */ +- (SInt64) readRawLittleEndian64 { + int8_t b1 = [self readRawByte]; + int8_t b2 = [self readRawByte]; + int8_t b3 = [self readRawByte]; + int8_t b4 = [self readRawByte]; + int8_t b5 = [self readRawByte]; + int8_t b6 = [self readRawByte]; + int8_t b7 = [self readRawByte]; + int8_t b8 = [self readRawByte]; + return + (((SInt64)b1 & 0xff) ) | + (((SInt64)b2 & 0xff) << 8) | + (((SInt64)b3 & 0xff) << 16) | + (((SInt64)b4 & 0xff) << 24) | + (((SInt64)b5 & 0xff) << 32) | + (((SInt64)b6 & 0xff) << 40) | + (((SInt64)b7 & 0xff) << 48) | + (((SInt64)b8 & 0xff) << 56); +} + + +/** + * Set the maximum message recursion depth. In order to prevent malicious + * messages from causing stack overflows, {@code PBCodedInputStream} limits + * how deeply messages may be nested. The default limit is 64. + * + * @return the old limit. + */ +- (SInt32) setRecursionLimit:(SInt32) limit { + if (limit < 0) { + @throw [NSException exceptionWithName:@"IllegalArgument" reason:@"Recursion limit cannot be negative" userInfo:nil]; + } + SInt32 oldLimit = recursionLimit; + recursionLimit = limit; + return oldLimit; +} + + +/** + * Set the maximum message size. In order to prevent malicious + * messages from exhausting memory or causing integer overflows, + * {@code PBCodedInputStream} limits how large a message may be. + * The default limit is 64MB. You should set this limit as small + * as you can without harming your app's functionality. Note that + * size limits only apply when reading from an {@code InputStream}, not + * when constructed around a raw byte array. + * + * @return the old limit. + */ +- (SInt32) setSizeLimit:(SInt32) limit { + if (limit < 0) { + @throw [NSException exceptionWithName:@"IllegalArgument" reason:@"Size limit cannot be negative:" userInfo:nil]; + } + SInt32 oldLimit = sizeLimit; + sizeLimit = limit; + return oldLimit; +} + + +/** + * Resets the current size counter to zero (see {@link #setSizeLimit(int)}). + */ +- (void) resetSizeCounter { + totalBytesRetired = 0; +} + + +/** + * Sets {@code currentLimit} to (current position) + {@code byteLimit}. This + * is called when descending into a length-delimited embedded message. + * + * @return the old limit. + */ +- (SInt32) pushLimit:(SInt32) byteLimit { + if (byteLimit < 0) { + @throw [NSException exceptionWithName:@"InvalidProtocolBuffer" reason:@"negativeSize" userInfo:nil]; + } + byteLimit += totalBytesRetired + bufferPos; + SInt32 oldLimit = currentLimit; + if (byteLimit > oldLimit) { + @throw [NSException exceptionWithName:@"InvalidProtocolBuffer" reason:@"truncatedMessage" userInfo:nil]; + } + currentLimit = byteLimit; + + [self recomputeBufferSizeAfterLimit]; + + return oldLimit; +} + + +- (void) recomputeBufferSizeAfterLimit { + bufferSize += bufferSizeAfterLimit; + SInt32 bufferEnd = totalBytesRetired + bufferSize; + if (bufferEnd > currentLimit) { + // Limit is in current buffer. + bufferSizeAfterLimit = bufferEnd - currentLimit; + bufferSize -= bufferSizeAfterLimit; + } else { + bufferSizeAfterLimit = 0; + } +} + + +/** + * Discards the current limit, returning to the previous limit. + * + * @param oldLimit The old limit, as returned by {@code pushLimit}. + */ +- (void) popLimit:(SInt32) oldLimit { + currentLimit = oldLimit; + [self recomputeBufferSizeAfterLimit]; +} + + +/** + * Returns the number of bytes to be read before the current limit. + * If no limit is set, returns -1. + */ +- (SInt32) bytesUntilLimit { + if (currentLimit == INT_MAX) { + return -1; + } + + SInt32 currentAbsolutePosition = totalBytesRetired + bufferPos; + return currentLimit - currentAbsolutePosition; +} + +/** + * Returns true if the stream has reached the end of the input. This is the + * case if either the end of the underlying input source has been reached or + * if the stream has reached a limit created using {@link #pushLimit(int)}. + */ +- (BOOL) isAtEnd { + return bufferPos == bufferSize && ![self refillBuffer:NO]; +} + + +/** + * Called with {@code this.buffer} is empty to read more bytes from the + * input. If {@code mustSucceed} is YES, refillBuffer() gurantees that + * either there will be at least one byte in the buffer when it returns + * or it will throw an exception. If {@code mustSucceed} is NO, + * refillBuffer() returns NO if no more bytes were available. + */ +- (BOOL) refillBuffer:(BOOL) mustSucceed { + if (bufferPos < bufferSize) { + @throw [NSException exceptionWithName:@"IllegalState" reason:@"refillBuffer called when buffer wasn't empty." userInfo:nil]; + } + + if (totalBytesRetired + bufferSize == currentLimit) { + // Oops, we hit a limit. + if (mustSucceed) { + @throw [NSException exceptionWithName:@"InvalidProtocolBuffer" reason:@"truncatedMessage" userInfo:nil]; + } else { + return NO; + } + } + + totalBytesRetired += bufferSize; + + // TODO(cyrusn): does NSInputStream behave the same as java.io.InputStream + // when there is no more data? + bufferPos = 0; + bufferSize = 0; + if (input != nil) { + bufferSize = (SInt32)[input read:buffer.mutableBytes maxLength:buffer.length]; + } + + if (bufferSize <= 0) { + bufferSize = 0; + if (mustSucceed) { + @throw [NSException exceptionWithName:@"InvalidProtocolBuffer" reason:@"truncatedMessage" userInfo:nil]; + } else { + return NO; + } + } else { + [self recomputeBufferSizeAfterLimit]; + SInt32 totalBytesRead = totalBytesRetired + bufferSize + bufferSizeAfterLimit; + if (totalBytesRead > sizeLimit || totalBytesRead < 0) { + @throw [NSException exceptionWithName:@"InvalidProtocolBuffer" reason:@"sizeLimitExceeded" userInfo:nil]; + } + return YES; + } +} + + +/** + * Read one byte from the input. + * + * @throws InvalidProtocolBufferException The end of the stream or the current + * limit was reached. + */ +- (int8_t) readRawByte { + if (bufferPos == bufferSize) { + [self refillBuffer:YES]; + } + int8_t* bytes = (int8_t*)buffer.bytes; + return bytes[bufferPos++]; +} + + +/** + * Read a fixed size of bytes from the input. + * + * @throws InvalidProtocolBufferException The end of the stream or the current + * limit was reached. + */ +- (NSData*) readRawData:(SInt32) size { + if (size < 0) { + @throw [NSException exceptionWithName:@"InvalidProtocolBuffer" reason:@"negativeSize" userInfo:nil]; + } + + if (totalBytesRetired + bufferPos + size > currentLimit) { + // Read to the end of the stream anyway. + [self skipRawData:currentLimit - totalBytesRetired - bufferPos]; + // Then fail. + @throw [NSException exceptionWithName:@"InvalidProtocolBuffer" reason:@"truncatedMessage" userInfo:nil]; + } + + if (size <= bufferSize - bufferPos) { + // We have all the bytes we need already. + NSData* data = [NSData dataWithBytes:(((int8_t*) buffer.bytes) + bufferPos) length:size]; + bufferPos += size; + return data; + } else if (size < BUFFER_SIZE) { + // Reading more bytes than are in the buffer, but not an excessive number + // of bytes. We can safely allocate the resulting array ahead of time. + + // First copy what we have. + NSMutableData* bytes = [NSMutableData dataWithLength:size]; + SInt32 pos = bufferSize - bufferPos; + memcpy(bytes.mutableBytes, ((int8_t*)buffer.bytes) + bufferPos, pos); + bufferPos = bufferSize; + + // We want to use refillBuffer() and then copy from the buffer into our + // byte array rather than reading directly into our byte array because + // the input may be unbuffered. + [self refillBuffer:YES]; + + while (size - pos > bufferSize) { + memcpy(((int8_t*)bytes.mutableBytes) + pos, buffer.bytes, bufferSize); + pos += bufferSize; + bufferPos = bufferSize; + [self refillBuffer:YES]; + } + + memcpy(((int8_t*)bytes.mutableBytes) + pos, buffer.bytes, size - pos); + bufferPos = size - pos; + + return bytes; + } else { + // The size is very large. For security reasons, we can't allocate the + // entire byte array yet. The size comes directly from the input, so a + // maliciously-crafted message could provide a bogus very large size in + // order to trick the app into allocating a lot of memory. We avoid this + // by allocating and reading only a small chunk at a time, so that the + // malicious message must actuall* e* extremely large to cause + // problems. Meanwhile, we limit the allowed size of a message elsewhere. + + // Remember the buffer markers since we'll have to copy the bytes out of + // it later. + SInt32 originalBufferPos = bufferPos; + SInt32 originalBufferSize = bufferSize; + + // Mark the current buffer consumed. + totalBytesRetired += bufferSize; + bufferPos = 0; + bufferSize = 0; + + // Read all the rest of the bytes we need. + SInt32 sizeLeft = size - (originalBufferSize - originalBufferPos); + NSMutableArray* chunks = [NSMutableArray array]; + + while (sizeLeft > 0) { + NSMutableData* chunk = [NSMutableData dataWithLength:MIN(sizeLeft, BUFFER_SIZE)]; + + SInt32 pos = 0; + while (pos < chunk.length) { + SInt32 n = 0; + if (input != nil) { + n = (SInt32)[input read:(((uint8_t*) chunk.mutableBytes) + pos) maxLength:chunk.length - pos]; + } + if (n <= 0) { + @throw [NSException exceptionWithName:@"InvalidProtocolBuffer" reason:@"truncatedMessage" userInfo:nil]; + } + totalBytesRetired += n; + pos += n; + } + sizeLeft -= chunk.length; + [chunks addObject:chunk]; + } + + // OK, got everything. Now concatenate it all into one buffer. + NSMutableData* bytes = [NSMutableData dataWithLength:size]; + + // Start by copying the leftover bytes from this.buffer. + SInt32 pos = originalBufferSize - originalBufferPos; + memcpy(bytes.mutableBytes, ((int8_t*)buffer.bytes) + originalBufferPos, pos); + + // And now all the chunks. + for (NSData* chunk in chunks) { + memcpy(((int8_t*)bytes.mutableBytes) + pos, chunk.bytes, chunk.length); + pos += chunk.length; + } + + // Done. + return bytes; + } +} + + +/** + * Reads and discards {@code size} bytes. + * + * @throws InvalidProtocolBufferException The end of the stream or the current + * limit was reached. + */ +- (void) skipRawData:(SInt32) size { + if (size < 0) { + @throw [NSException exceptionWithName:@"InvalidProtocolBuffer" reason:@"negativeSize" userInfo:nil]; + } + + if (totalBytesRetired + bufferPos + size > currentLimit) { + // Read to the end of the stream anyway. + [self skipRawData:currentLimit - totalBytesRetired - bufferPos]; + // Then fail. + @throw [NSException exceptionWithName:@"InvalidProtocolBuffer" reason:@"truncatedMessage" userInfo:nil]; + } + + if (size <= (bufferSize - bufferPos)) { + // We have all the bytes we need already. + bufferPos += size; + } else { + // Skipping more bytes than are in the buffer. First skip what we have. + SInt32 pos = bufferSize - bufferPos; + totalBytesRetired += pos; + bufferPos = 0; + bufferSize = 0; + + // Then skip directly from the InputStream for the rest. + while (pos < size) { + NSMutableData* data = [NSMutableData dataWithLength:(size - pos)]; + SInt32 n = (input == nil) ? -1 : (SInt32)[input read:data.mutableBytes maxLength:(size - pos)]; + if (n <= 0) { + @throw [NSException exceptionWithName:@"InvalidProtocolBuffer" reason:@"truncatedMessage" userInfo:nil]; + } + pos += n; + totalBytesRetired += n; + } + } +} + + + +@end diff --git a/ios/Pods/ProtocolBuffers/src/runtime/Classes/CodedOutputStream.h b/ios/Pods/ProtocolBuffers/src/runtime/Classes/CodedOutputStream.h new file mode 100644 index 000000000..d9f47a4a2 --- /dev/null +++ b/ios/Pods/ProtocolBuffers/src/runtime/Classes/CodedOutputStream.h @@ -0,0 +1,137 @@ +// Protocol Buffers for Objective C +// +// Copyright 2010 Booyah Inc. +// Copyright 2008 Cyrus Najmabadi +// +// 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. + +/** + * Encodes and writes protocol message fields. + * + *

This class contains two kinds of methods: methods that write specific + * protocol message constructs and field types (e.g. {@link #writeTag} and + * {@link #writeInt32}) and methods that write low-level values (e.g. + * {@link #writeRawVarint32} and {@link #writeRawBytes}). If you are + * writing encoded protocol messages, you should use the former methods, but if + * you are writing some other format of your own design, use the latter. + * + *

This class is totally unsynchronized. + * + * @author Cyrus Najmabadi + */ + +@class PBUnknownFieldSet; +@class RingBuffer; +@protocol PBMessage; + +@interface PBCodedOutputStream : NSObject { + NSOutputStream *output; + RingBuffer *buffer; +} + ++ (PBCodedOutputStream*) streamWithData:(NSMutableData*) data; ++ (PBCodedOutputStream*) streamWithOutputStream:(NSOutputStream*) output; ++ (PBCodedOutputStream*) streamWithOutputStream:(NSOutputStream*) output bufferSize:(SInt32) bufferSize; + +/** + * Flushes the stream and forces any buffered bytes to be written. This + * does not flush the underlying NSOutputStream. Returns free space in buffer. + */ +- (void) flush; + +/** Write a single byte. */ +- (void) writeRawByte:(uint8_t) value; + +/** Encode and write a tag. */ +- (void) writeTag:(SInt32) fieldNumber format:(SInt32) format; + +/** Write a little-endian 32-bit integer. */ +- (void) writeRawLittleEndian32:(SInt32) value; +/** Write a little-endian 64-bit integer. */ +- (void) writeRawLittleEndian64:(SInt64) value; + +/** + * Encode and write a varint. {@code value} is treated as + * unsigned, so it won't be sign-extended if negative. + */ +- (void) writeRawVarint32:(SInt32) value; +/** Encode and write a varint. */ +- (void) writeRawVarint64:(SInt64) value; + +//- (void) writeRawLittleEndian32:(SInt32) value; +//- (void) writeRawLittleEndian64:(SInt64) value; + +/** Write an array of bytes. */ +- (void) writeRawData:(const NSData*) data; +- (void) writeRawData:(const NSData*) data offset:(SInt32) offset length:(SInt32) length; + +- (void) writeData:(SInt32) fieldNumber value:(const NSData*) value; + +- (void) writeDouble:(SInt32) fieldNumber value:(Float64) value; +- (void) writeFloat:(SInt32) fieldNumber value:(Float32) value; +- (void) writeUInt64:(SInt32) fieldNumber value:(SInt64) value; +- (void) writeInt64:(SInt32) fieldNumber value:(SInt64) value; +- (void) writeInt32:(SInt32) fieldNumber value:(SInt32) value; +- (void) writeFixed64:(SInt32) fieldNumber value:(SInt64) value; +- (void) writeFixed32:(SInt32) fieldNumber value:(SInt32) value; +- (void) writeBool:(SInt32) fieldNumber value:(BOOL) value; +- (void) writeString:(SInt32) fieldNumber value:(const NSString*) value; +- (void) writeGroup:(SInt32) fieldNumber value:(const id) value; +- (void) writeUnknownGroup:(SInt32) fieldNumber value:(const PBUnknownFieldSet*) value; +- (void) writeMessage:(SInt32) fieldNumber value:(const id) value; +- (void) writeUInt32:(SInt32) fieldNumber value:(SInt32) value; +- (void) writeSFixed32:(SInt32) fieldNumber value:(SInt32) value; +- (void) writeSFixed64:(SInt32) fieldNumber value:(SInt64) value; +- (void) writeSInt32:(SInt32) fieldNumber value:(SInt32) value; +- (void) writeSInt64:(SInt32) fieldNumber value:(SInt64) value; + +- (void) writeDoubleNoTag:(Float64) value; +- (void) writeFloatNoTag:(Float32) value; +- (void) writeUInt64NoTag:(SInt64) value; +- (void) writeInt64NoTag:(SInt64) value; +- (void) writeInt32NoTag:(SInt32) value; +- (void) writeFixed64NoTag:(SInt64) value; +- (void) writeFixed32NoTag:(SInt32) value; +- (void) writeBoolNoTag:(BOOL) value; +- (void) writeStringNoTag:(const NSString*) value; +- (void) writeGroupNoTag:(SInt32) fieldNumber value:(const id) value; +- (void) writeUnknownGroupNoTag:(SInt32) fieldNumber value:(const PBUnknownFieldSet*) value; +- (void) writeMessageNoTag:(const id) value; +- (void) writeDataNoTag:(const NSData*) value; +- (void) writeUInt32NoTag:(SInt32) value; +- (void) writeEnumNoTag:(SInt32) value; +- (void) writeSFixed32NoTag:(SInt32) value; +- (void) writeSFixed64NoTag:(SInt64) value; +- (void) writeSInt32NoTag:(SInt32) value; +- (void) writeSInt64NoTag:(SInt64) value; + + +/** + * Write a MessageSet extension field to the stream. For historical reasons, + * the wire format differs from normal fields. + */ +- (void) writeMessageSetExtension:(SInt32) fieldNumber value:(const id) value; + +/** + * Write an unparsed MessageSet extension field to the stream. For + * historical reasons, the wire format differs from normal fields. + */ +- (void) writeRawMessageSetExtension:(SInt32) fieldNumber value:(const NSData*) value; + +/** + * Write an enum field, including tag, to the stream. Caller is responsible + * for converting the enum value to its numeric value. + */ +- (void) writeEnum:(SInt32) fieldNumber value:(SInt32) value; + +@end diff --git a/ios/Pods/ProtocolBuffers/src/runtime/Classes/CodedOutputStream.m b/ios/Pods/ProtocolBuffers/src/runtime/Classes/CodedOutputStream.m new file mode 100644 index 000000000..2682ebcee --- /dev/null +++ b/ios/Pods/ProtocolBuffers/src/runtime/Classes/CodedOutputStream.m @@ -0,0 +1,402 @@ +// Protocol Buffers for Objective C +// +// Copyright 2010 Booyah Inc. +// Copyright 2008 Cyrus Najmabadi +// +// 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. + +#import "CodedOutputStream.h" +#import "RingBuffer.h" +#import "Message.h" +#import "Utilities.h" +#import "WireFormat.h" +#import "UnknownFieldSetBuilder.h" +#import "UnknownFieldSet.h" + + +@implementation PBCodedOutputStream + +const SInt32 DEFAULT_BUFFER_SIZE = 4 * 1024; + + +- (id)initWithOutputStream:(NSOutputStream*)_output data:(NSMutableData*)data { + if ( (self = [super init]) ) { + output = _output; + buffer = [[RingBuffer alloc] initWithData:data]; + } + return self; +} + ++ (PBCodedOutputStream*)streamWithOutputStream:(NSOutputStream*)output bufferSize:(SInt32)bufferSize { + NSMutableData *data = [NSMutableData dataWithLength:bufferSize]; + return [[PBCodedOutputStream alloc] initWithOutputStream:output data:data]; +} + + ++ (PBCodedOutputStream*)streamWithOutputStream:(NSOutputStream*)output { + return [PBCodedOutputStream streamWithOutputStream:output bufferSize:DEFAULT_BUFFER_SIZE]; +} + + ++ (PBCodedOutputStream*)streamWithData:(NSMutableData*)data { + return [[PBCodedOutputStream alloc] initWithOutputStream:nil data:data]; +} + + +- (void)flush { + if (output == nil) { + // We're writing to a single buffer. + @throw [NSException exceptionWithName:@"OutOfSpace" reason:@"" userInfo:nil]; + } + + [buffer flushToOutputStream:output]; +} + + +- (void)writeRawByte:(uint8_t)value { + while (![buffer appendByte:value]) { + [self flush]; + } +} + + +- (void)writeRawData:(const NSData*)data { + [self writeRawData:data offset:0 length:(SInt32)data.length]; +} + + +- (void)writeRawData:(const NSData*)value offset:(SInt32)offset length:(SInt32)length { + while (length > 0) { + SInt32 written = [buffer appendData:value offset:offset length:length]; + offset += written; + length -= written; + if (!written || length > 0) { + [self flush]; + } + } +} + + +- (void)writeDoubleNoTag:(Float64)value { + [self writeRawLittleEndian64:convertFloat64ToInt64(value)]; +} + + +/** Write a {@code double} field, including tag, to the stream. */ +- (void)writeDouble:(SInt32)fieldNumber value:(Float64)value { + [self writeTag:fieldNumber format:PBWireFormatFixed64]; + [self writeDoubleNoTag:value]; +} + + +- (void)writeFloatNoTag:(Float32)value { + [self writeRawLittleEndian32:convertFloat32ToInt32(value)]; +} + + +/** Write a {@code float} field, including tag, to the stream. */ +- (void)writeFloat:(SInt32)fieldNumber value:(Float32)value { + [self writeTag:fieldNumber format:PBWireFormatFixed32]; + [self writeFloatNoTag:value]; +} + + +- (void)writeUInt64NoTag:(SInt64)value { + [self writeRawVarint64:value]; +} + + +/** Write a {@code uint64} field, including tag, to the stream. */ +- (void)writeUInt64:(SInt32)fieldNumber value:(SInt64)value { + [self writeTag:fieldNumber format:PBWireFormatVarint]; + [self writeUInt64NoTag:value]; +} + + +- (void)writeInt64NoTag:(SInt64)value { + [self writeRawVarint64:value]; +} + + +/** Write an {@code int64} field, including tag, to the stream. */ +- (void)writeInt64:(SInt32)fieldNumber value:(SInt64)value { + [self writeTag:fieldNumber format:PBWireFormatVarint]; + [self writeInt64NoTag:value]; +} + + +- (void)writeInt32NoTag:(SInt32)value { + if (value >= 0) { + [self writeRawVarint32:value]; + } else { + // Must sign-extend + [self writeRawVarint64:value]; + } +} + + +/** Write an {@code int32} field, including tag, to the stream. */ +- (void)writeInt32:(SInt32)fieldNumber value:(SInt32)value { + [self writeTag:fieldNumber format:PBWireFormatVarint]; + [self writeInt32NoTag:value]; +} + + +- (void)writeFixed64NoTag:(SInt64)value { + [self writeRawLittleEndian64:value]; +} + + +/** Write a {@code fixed64} field, including tag, to the stream. */ +- (void)writeFixed64:(SInt32)fieldNumber value:(SInt64)value { + [self writeTag:fieldNumber format:PBWireFormatFixed64]; + [self writeFixed64NoTag:value]; +} + + +- (void)writeFixed32NoTag:(SInt32)value { + [self writeRawLittleEndian32:value]; +} + + +/** Write a {@code fixed32} field, including tag, to the stream. */ +- (void)writeFixed32:(SInt32)fieldNumber value:(SInt32)value { + [self writeTag:fieldNumber format:PBWireFormatFixed32]; + [self writeFixed32NoTag:value]; +} + + +- (void)writeBoolNoTag:(BOOL)value { + [self writeRawByte:(value ? 1 : 0)]; +} + + +/** Write a {@code bool} field, including tag, to the stream. */ +- (void)writeBool:(SInt32)fieldNumber value:(BOOL)value { + [self writeTag:fieldNumber format:PBWireFormatVarint]; + [self writeBoolNoTag:value]; +} + + +- (void)writeStringNoTag:(const NSString*)value { + NSData* data = [value dataUsingEncoding:NSUTF8StringEncoding]; + [self writeRawVarint32:(SInt32)data.length]; + [self writeRawData:data]; +} + + +/** Write a {@code string} field, including tag, to the stream. */ +- (void)writeString:(SInt32)fieldNumber value:(const NSString*)value { + [self writeTag:fieldNumber format:PBWireFormatLengthDelimited]; + [self writeStringNoTag:value]; +} + + +- (void)writeGroupNoTag:(SInt32)fieldNumber value:(const id)value { + [value writeToCodedOutputStream:self]; + [self writeTag:fieldNumber format:PBWireFormatEndGroup]; +} + + +/** Write a {@code group} field, including tag, to the stream. */ +- (void)writeGroup:(SInt32)fieldNumber value:(const id)value { + [self writeTag:fieldNumber format:PBWireFormatStartGroup]; + [self writeGroupNoTag:fieldNumber value:value]; +} + + +- (void)writeUnknownGroupNoTag:(SInt32)fieldNumber value:(const PBUnknownFieldSet*)value { + [value writeToCodedOutputStream:self]; + [self writeTag:fieldNumber format:PBWireFormatEndGroup]; +} + + +/** Write a group represented by an {@link PBUnknownFieldSet}. */ +- (void)writeUnknownGroup:(SInt32)fieldNumber value:(const PBUnknownFieldSet*)value { + [self writeTag:fieldNumber format:PBWireFormatStartGroup]; + [self writeUnknownGroupNoTag:fieldNumber value:value]; +} + + +- (void)writeMessageNoTag:(const id)value { + [self writeRawVarint32:[value serializedSize]]; + [value writeToCodedOutputStream:self]; +} + + +/** Write an embedded message field, including tag, to the stream. */ +- (void)writeMessage:(SInt32)fieldNumber value:(const id)value { + [self writeTag:fieldNumber format:PBWireFormatLengthDelimited]; + [self writeMessageNoTag:value]; +} + + +- (void)writeDataNoTag:(const NSData*)value { + [self writeRawVarint32:(SInt32)value.length]; + [self writeRawData:value]; +} + + +/** Write a {@code bytes} field, including tag, to the stream. */ +- (void)writeData:(SInt32)fieldNumber value:(const NSData*)value { + [self writeTag:fieldNumber format:PBWireFormatLengthDelimited]; + [self writeDataNoTag:value]; +} + + +- (void)writeUInt32NoTag:(SInt32)value { + [self writeRawVarint32:value]; +} + + +/** Write a {@code uint32} field, including tag, to the stream. */ +- (void)writeUInt32:(SInt32)fieldNumber value:(SInt32)value { + [self writeTag:fieldNumber format:PBWireFormatVarint]; + [self writeUInt32NoTag:value]; +} + + +- (void)writeEnumNoTag:(SInt32)value { + [self writeRawVarint32:value]; +} + + +- (void)writeEnum:(SInt32)fieldNumber value:(SInt32)value { + [self writeTag:fieldNumber format:PBWireFormatVarint]; + [self writeEnumNoTag:value]; +} + + +- (void)writeSFixed32NoTag:(SInt32)value { + [self writeRawLittleEndian32:value]; +} + + +/** Write an {@code sfixed32} field, including tag, to the stream. */ +- (void)writeSFixed32:(SInt32)fieldNumber value:(SInt32)value { + [self writeTag:fieldNumber format:PBWireFormatFixed32]; + [self writeSFixed32NoTag:value]; +} + + +- (void)writeSFixed64NoTag:(SInt64)value { + [self writeRawLittleEndian64:value]; +} + + +/** Write an {@code sfixed64} field, including tag, to the stream. */ +- (void)writeSFixed64:(SInt32)fieldNumber value:(SInt64)value { + [self writeTag:fieldNumber format:PBWireFormatFixed64]; + [self writeSFixed64NoTag:value]; +} + + +- (void)writeSInt32NoTag:(SInt32)value { + [self writeRawVarint32:encodeZigZag32(value)]; +} + + +/** Write an {@code sint32} field, including tag, to the stream. */ +- (void)writeSInt32:(SInt32)fieldNumber value:(SInt32)value { + [self writeTag:fieldNumber format:PBWireFormatVarint]; + [self writeSInt32NoTag:value]; +} + + +- (void)writeSInt64NoTag:(SInt64)value { + [self writeRawVarint64:encodeZigZag64(value)]; +} + + +/** Write an {@code sint64} field, including tag, to the stream. */ +- (void)writeSInt64:(SInt32)fieldNumber value:(SInt64)value { + [self writeTag:fieldNumber format:PBWireFormatVarint]; + [self writeSInt64NoTag:value]; +} + + +/** + * Write a MessageSet extension field to the stream. For historical reasons, + * the wire format differs from normal fields. + */ +- (void)writeMessageSetExtension:(SInt32)fieldNumber value:(const id)value { + [self writeTag:PBWireFormatMessageSetItem format:PBWireFormatStartGroup]; + [self writeUInt32:PBWireFormatMessageSetTypeId value:fieldNumber]; + [self writeMessage:PBWireFormatMessageSetMessage value:value]; + [self writeTag:PBWireFormatMessageSetItem format:PBWireFormatEndGroup]; +} + + +/** + * Write an unparsed MessageSet extension field to the stream. For + * historical reasons, the wire format differs from normal fields. + */ +- (void)writeRawMessageSetExtension:(SInt32)fieldNumber value:(const NSData*)value { + [self writeTag:PBWireFormatMessageSetItem format:PBWireFormatStartGroup]; + [self writeUInt32:PBWireFormatMessageSetTypeId value:fieldNumber]; + [self writeData:PBWireFormatMessageSetMessage value:value]; + [self writeTag:PBWireFormatMessageSetItem format:PBWireFormatEndGroup]; +} + + +- (void)writeTag:(SInt32)fieldNumber format:(SInt32)format { + [self writeRawVarint32:PBWireFormatMakeTag(fieldNumber, format)]; +} + + +- (void)writeRawVarint32:(SInt32)value { + while (YES) { + if ((value & ~0x7F) == 0) { + [self writeRawByte:value]; + return; + } else { + [self writeRawByte:((value & 0x7F) | 0x80)]; + value = logicalRightShift32(value, 7); + } + } +} + + +- (void)writeRawVarint64:(SInt64)value { + while (YES) { + if ((value & ~0x7FL) == 0) { + [self writeRawByte:((SInt32)value)]; + return; + } else { + [self writeRawByte:(((SInt32)value & 0x7F) | 0x80)]; + value = logicalRightShift64(value, 7); + } + } +} + + +- (void)writeRawLittleEndian32:(SInt32)value { + [self writeRawByte:((value ) & 0xFF)]; + [self writeRawByte:((value >> 8) & 0xFF)]; + [self writeRawByte:((value >> 16) & 0xFF)]; + [self writeRawByte:((value >> 24) & 0xFF)]; +} + + +- (void)writeRawLittleEndian64:(SInt64)value { + [self writeRawByte:((SInt32)(value ) & 0xFF)]; + [self writeRawByte:((SInt32)(value >> 8) & 0xFF)]; + [self writeRawByte:((SInt32)(value >> 16) & 0xFF)]; + [self writeRawByte:((SInt32)(value >> 24) & 0xFF)]; + [self writeRawByte:((SInt32)(value >> 32) & 0xFF)]; + [self writeRawByte:((SInt32)(value >> 40) & 0xFF)]; + [self writeRawByte:((SInt32)(value >> 48) & 0xFF)]; + [self writeRawByte:((SInt32)(value >> 56) & 0xFF)]; +} + +@end diff --git a/ios/Pods/ProtocolBuffers/src/runtime/Classes/ConcreteExtensionField.h b/ios/Pods/ProtocolBuffers/src/runtime/Classes/ConcreteExtensionField.h new file mode 100644 index 000000000..7524d46b6 --- /dev/null +++ b/ios/Pods/ProtocolBuffers/src/runtime/Classes/ConcreteExtensionField.h @@ -0,0 +1,65 @@ +// Protocol Buffers for Objective C +// +// Copyright 2010 Booyah Inc. +// Copyright 2008 Cyrus Najmabadi +// +// 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. + +#import "ExtensionField.h" + +typedef enum { + PBExtensionTypeBool, + PBExtensionTypeFixed32, + PBExtensionTypeSFixed32, + PBExtensionTypeFloat, + PBExtensionTypeFixed64, + PBExtensionTypeSFixed64, + PBExtensionTypeDouble, + PBExtensionTypeInt32, + PBExtensionTypeInt64, + PBExtensionTypeSInt32, + PBExtensionTypeSInt64, + PBExtensionTypeUInt32, + PBExtensionTypeUInt64, + PBExtensionTypeBytes, + PBExtensionTypeString, + PBExtensionTypeMessage, + PBExtensionTypeGroup, + PBExtensionTypeEnum +} PBExtensionType; + +@interface PBConcreteExtensionField : NSObject { +@private + PBExtensionType type; + + Class extendedClass; + SInt32 fieldNumber; + id defaultValue; + + Class messageOrGroupClass; + + BOOL isRepeated; + BOOL isPacked; + BOOL isMessageSetWireFormat; +} + ++ (PBConcreteExtensionField*) extensionWithType:(PBExtensionType) type + extendedClass:(Class) extendedClass + fieldNumber:(SInt32) fieldNumber + defaultValue:(id) defaultValue + messageOrGroupClass:(Class) messageOrGroupClass + isRepeated:(BOOL) isRepeated + isPacked:(BOOL) isPacked + isMessageSetWireFormat:(BOOL) isMessageSetWireFormat; + +@end diff --git a/ios/Pods/ProtocolBuffers/src/runtime/Classes/ConcreteExtensionField.m b/ios/Pods/ProtocolBuffers/src/runtime/Classes/ConcreteExtensionField.m new file mode 100644 index 000000000..d7567c435 --- /dev/null +++ b/ios/Pods/ProtocolBuffers/src/runtime/Classes/ConcreteExtensionField.m @@ -0,0 +1,582 @@ +// Protocol Buffers for Objective C +// +// Copyright 2010 Booyah Inc. +// Copyright 2008 Cyrus Najmabadi +// +// 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. + +#import "ConcreteExtensionField.h" + +#import "AbstractMessage.h" +#import "CodedInputStream.h" +#import "CodedOutputStream.h" +#import "ExtendableMessageBuilder.h" +#import "MessageBuilder.h" +#import "Utilities.h" +#import "WireFormat.h" + +@interface PBConcreteExtensionField() +@property PBExtensionType type; +@property (assign) Class extendedClass; +@property SInt32 fieldNumber; +@property (strong) id defaultValue; +@property (assign) Class messageOrGroupClass; +@property BOOL isRepeated; +@property BOOL isPacked; +@property BOOL isMessageSetWireFormat; +@end + +@implementation PBConcreteExtensionField + +@synthesize type; +@synthesize extendedClass; +@synthesize fieldNumber; +@synthesize defaultValue; +@synthesize messageOrGroupClass; +@synthesize isRepeated; +@synthesize isPacked; +@synthesize isMessageSetWireFormat; + + + +- (id) initWithType:(PBExtensionType) type_ + extendedClass:(Class) extendedClass_ + fieldNumber:(SInt32) fieldNumber_ + defaultValue:(id) defaultValue_ + messageOrGroupClass:(Class) messageOrGroupClass_ + isRepeated:(BOOL) isRepeated_ + isPacked:(BOOL) isPacked_ + isMessageSetWireFormat:(BOOL) isMessageSetWireFormat_ { + if ((self = [super init])) { + self.type = type_; + self.extendedClass = extendedClass_; + self.fieldNumber = fieldNumber_; + self.defaultValue = defaultValue_; + self.messageOrGroupClass = messageOrGroupClass_; + self.isRepeated = isRepeated_; + self.isPacked = isPacked_; + self.isMessageSetWireFormat = isMessageSetWireFormat_; + } + + return self; +} + + ++ (PBConcreteExtensionField*) extensionWithType:(PBExtensionType) type + extendedClass:(Class) extendedClass + fieldNumber:(SInt32) fieldNumber + defaultValue:(id) defaultValue + messageOrGroupClass:(Class) messageOrGroupClass + isRepeated:(BOOL) isRepeated + isPacked:(BOOL) isPacked + isMessageSetWireFormat:(BOOL) isMessageSetWireFormat { + return [[PBConcreteExtensionField alloc] initWithType:type + extendedClass:extendedClass + fieldNumber:fieldNumber + defaultValue:defaultValue + messageOrGroupClass:messageOrGroupClass + isRepeated:isRepeated + isPacked:isPacked + isMessageSetWireFormat:isMessageSetWireFormat]; +} + + +- (PBWireFormat) wireType { + if (isPacked) { + return PBWireFormatLengthDelimited; + } + + switch (type) { + case PBExtensionTypeBool: return PBWireFormatVarint; + case PBExtensionTypeFixed32: return PBWireFormatFixed32; + case PBExtensionTypeSFixed32: return PBWireFormatFixed32; + case PBExtensionTypeFloat: return PBWireFormatFixed32; + case PBExtensionTypeFixed64: return PBWireFormatFixed64; + case PBExtensionTypeSFixed64: return PBWireFormatFixed64; + case PBExtensionTypeDouble: return PBWireFormatFixed64; + case PBExtensionTypeInt32: return PBWireFormatVarint; + case PBExtensionTypeInt64: return PBWireFormatVarint; + case PBExtensionTypeSInt32: return PBWireFormatVarint; + case PBExtensionTypeSInt64: return PBWireFormatVarint; + case PBExtensionTypeUInt32: return PBWireFormatVarint; + case PBExtensionTypeUInt64: return PBWireFormatVarint; + case PBExtensionTypeBytes: return PBWireFormatLengthDelimited; + case PBExtensionTypeString: return PBWireFormatLengthDelimited; + case PBExtensionTypeMessage: return PBWireFormatLengthDelimited; + case PBExtensionTypeGroup: return PBWireFormatStartGroup; + case PBExtensionTypeEnum: return PBWireFormatVarint; + } + + @throw [NSException exceptionWithName:@"InternalError" reason:@"" userInfo:nil]; +} + + +BOOL typeIsFixedSize(PBExtensionType type) { + switch (type) { + case PBExtensionTypeBool: + case PBExtensionTypeFixed32: + case PBExtensionTypeSFixed32: + case PBExtensionTypeFloat: + case PBExtensionTypeFixed64: + case PBExtensionTypeSFixed64: + case PBExtensionTypeDouble: + return YES; + default: + return NO; + } +} + + +SInt32 typeSize(PBExtensionType type) { + switch (type) { + case PBExtensionTypeBool: + return 1; + case PBExtensionTypeFixed32: + case PBExtensionTypeSFixed32: + case PBExtensionTypeFloat: + return 4; + case PBExtensionTypeFixed64: + case PBExtensionTypeSFixed64: + case PBExtensionTypeDouble: + return 8; + default: + break; + } + + @throw [NSException exceptionWithName:@"InternalError" reason:@"" userInfo:nil]; +} + + +- (void) writeSingleValue:(id) value + includingTagToCodedOutputStream:(PBCodedOutputStream*) output { + switch (type) { + case PBExtensionTypeBool: + [output writeBool:fieldNumber value:[value boolValue]]; + return; + case PBExtensionTypeFixed32: + [output writeFixed32:fieldNumber value:(SInt32)[value integerValue]]; + return; + case PBExtensionTypeSFixed32: + [output writeSFixed32:fieldNumber value:(SInt32)[value integerValue]]; + return; + case PBExtensionTypeFloat: + [output writeFloat:fieldNumber value:[value floatValue]]; + return; + case PBExtensionTypeFixed64: + [output writeFixed64:fieldNumber value:[value longLongValue]]; + return; + case PBExtensionTypeSFixed64: + [output writeSFixed64:fieldNumber value:[value longLongValue]]; + return; + case PBExtensionTypeDouble: + [output writeDouble:fieldNumber value:[value doubleValue]]; + return; + case PBExtensionTypeInt32: + [output writeInt32:fieldNumber value:(SInt32)[value integerValue]]; + return; + case PBExtensionTypeInt64: + [output writeInt64:fieldNumber value:[value longLongValue]]; + return; + case PBExtensionTypeSInt32: + [output writeSInt32:fieldNumber value:(SInt32)[value integerValue]]; + return; + case PBExtensionTypeSInt64: + [output writeSInt64:fieldNumber value:[value longLongValue]]; + return; + case PBExtensionTypeUInt32: + [output writeUInt32:fieldNumber value:(SInt32)[value integerValue]]; + return; + case PBExtensionTypeUInt64: + [output writeUInt64:fieldNumber value:[value longLongValue]]; + return; + case PBExtensionTypeBytes: + [output writeData:fieldNumber value:value]; + return; + case PBExtensionTypeString: + [output writeString:fieldNumber value:value]; + return; + case PBExtensionTypeGroup: + [output writeGroup:fieldNumber value:value]; + return; + case PBExtensionTypeEnum: + [output writeEnum:fieldNumber value:(SInt32)[value integerValue]]; + return; + case PBExtensionTypeMessage: + if (isMessageSetWireFormat) { + [output writeMessageSetExtension:fieldNumber value:value]; + } else { + [output writeMessage:fieldNumber value:value]; + } + return; + } + + @throw [NSException exceptionWithName:@"InternalError" reason:@"" userInfo:nil]; +} + + +- (void) writeSingleValue:(id) value + noTagToCodedOutputStream:(PBCodedOutputStream*) output { + switch (type) { + case PBExtensionTypeBool: + [output writeBoolNoTag:[value boolValue]]; + return; + case PBExtensionTypeFixed32: + [output writeFixed32NoTag:(SInt32)[value integerValue]]; + return; + case PBExtensionTypeSFixed32: + [output writeSFixed32NoTag:(SInt32)[value integerValue]]; + return; + case PBExtensionTypeFloat: + [output writeFloatNoTag:[value floatValue]]; + return; + case PBExtensionTypeFixed64: + [output writeFixed64NoTag:[value longLongValue]]; + return; + case PBExtensionTypeSFixed64: + [output writeSFixed64NoTag:[value longLongValue]]; + return; + case PBExtensionTypeDouble: + [output writeDoubleNoTag:[value doubleValue]]; + return; + case PBExtensionTypeInt32: + [output writeInt32NoTag:(SInt32)[value integerValue]]; + return; + case PBExtensionTypeInt64: + [output writeInt64NoTag:[value longLongValue]]; + return; + case PBExtensionTypeSInt32: + [output writeSInt32NoTag:(SInt32)[value integerValue]]; + return; + case PBExtensionTypeSInt64: + [output writeSInt64NoTag:[value longLongValue]]; + return; + case PBExtensionTypeUInt32: + [output writeUInt32NoTag:(SInt32)[value integerValue]]; + return; + case PBExtensionTypeUInt64: + [output writeUInt64NoTag:[value longLongValue]]; + return; + case PBExtensionTypeBytes: + [output writeDataNoTag:value]; + return; + case PBExtensionTypeString: + [output writeStringNoTag:value]; + return; + case PBExtensionTypeGroup: + [output writeGroupNoTag:fieldNumber value:value]; + return; + case PBExtensionTypeEnum: + [output writeEnumNoTag:(SInt32)[value integerValue]]; + return; + case PBExtensionTypeMessage: + [output writeMessageNoTag:value]; + return; + } + + @throw [NSException exceptionWithName:@"InternalError" reason:@"" userInfo:nil]; +} + + +- (SInt32) computeSingleSerializedSizeNoTag:(id) value { + switch (type) { + case PBExtensionTypeBool: return computeBoolSizeNoTag([value boolValue]); + case PBExtensionTypeFixed32: return computeFixed32SizeNoTag((SInt32)[value integerValue]); + case PBExtensionTypeSFixed32: return computeSFixed32SizeNoTag((SInt32)[value integerValue]); + case PBExtensionTypeFloat: return computeFloatSizeNoTag([value floatValue]); + case PBExtensionTypeFixed64: return computeFixed64SizeNoTag([value longLongValue]); + case PBExtensionTypeSFixed64: return computeSFixed64SizeNoTag([value longLongValue]); + case PBExtensionTypeDouble: return computeDoubleSizeNoTag([value doubleValue]); + case PBExtensionTypeInt32: return computeInt32SizeNoTag((SInt32)[value integerValue]); + case PBExtensionTypeInt64: return computeInt64SizeNoTag([value longLongValue]); + case PBExtensionTypeSInt32: return computeSInt32SizeNoTag((SInt32)[value integerValue]); + case PBExtensionTypeSInt64: return computeSInt64SizeNoTag([value longLongValue]); + case PBExtensionTypeUInt32: return computeUInt32SizeNoTag((SInt32)[value integerValue]); + case PBExtensionTypeUInt64: return computeUInt64SizeNoTag([value longLongValue]); + case PBExtensionTypeBytes: return computeDataSizeNoTag(value); + case PBExtensionTypeString: return computeStringSizeNoTag(value); + case PBExtensionTypeGroup: return computeGroupSizeNoTag(value); + case PBExtensionTypeEnum: return computeEnumSizeNoTag((SInt32)[value integerValue]); + case PBExtensionTypeMessage: return computeMessageSizeNoTag(value); + } + + @throw [NSException exceptionWithName:@"InternalError" reason:@"" userInfo:nil]; +} + + +- (SInt32) computeSingleSerializedSizeIncludingTag:(id) value { + switch (type) { + case PBExtensionTypeBool: return computeBoolSize(fieldNumber, [value boolValue]); + case PBExtensionTypeFixed32: return computeFixed32Size(fieldNumber,(SInt32) [value integerValue]); + case PBExtensionTypeSFixed32: return computeSFixed32Size(fieldNumber, (SInt32)[value integerValue]); + case PBExtensionTypeFloat: return computeFloatSize(fieldNumber, [value floatValue]); + case PBExtensionTypeFixed64: return computeFixed64Size(fieldNumber, [value longLongValue]); + case PBExtensionTypeSFixed64: return computeSFixed64Size(fieldNumber, [value longLongValue]); + case PBExtensionTypeDouble: return computeDoubleSize(fieldNumber, [value doubleValue]); + case PBExtensionTypeInt32: return computeInt32Size(fieldNumber, (SInt32)[value integerValue]); + case PBExtensionTypeInt64: return computeInt64Size(fieldNumber, [value longLongValue]); + case PBExtensionTypeSInt32: return computeSInt32Size(fieldNumber, (SInt32)[value integerValue]); + case PBExtensionTypeSInt64: return computeSInt64Size(fieldNumber, [value longLongValue]); + case PBExtensionTypeUInt32: return computeUInt32Size(fieldNumber, (SInt32)[value integerValue]); + case PBExtensionTypeUInt64: return computeUInt64Size(fieldNumber, [value longLongValue]); + case PBExtensionTypeBytes: return computeDataSize(fieldNumber, value); + case PBExtensionTypeString: return computeStringSize(fieldNumber, value); + case PBExtensionTypeGroup: return computeGroupSize(fieldNumber, value); + case PBExtensionTypeEnum: return computeEnumSize(fieldNumber, (SInt32)[value integerValue]); + case PBExtensionTypeMessage: + if (isMessageSetWireFormat) { + return computeMessageSetExtensionSize(fieldNumber, value); + } else { + return computeMessageSize(fieldNumber, value); + } + } + + @throw [NSException exceptionWithName:@"InternalError" reason:@"" userInfo:nil]; +} + + +- (void) writeDescriptionOfSingleValue:(id) value + to:(NSMutableString*) output + withIndent:(NSString*) indent { + switch (type) { + case PBExtensionTypeBool: + case PBExtensionTypeFixed32: + case PBExtensionTypeSFixed32: + case PBExtensionTypeFloat: + case PBExtensionTypeFixed64: + case PBExtensionTypeSFixed64: + case PBExtensionTypeDouble: + case PBExtensionTypeInt32: + case PBExtensionTypeInt64: + case PBExtensionTypeSInt32: + case PBExtensionTypeSInt64: + case PBExtensionTypeUInt32: + case PBExtensionTypeUInt64: + case PBExtensionTypeBytes: + case PBExtensionTypeString: + case PBExtensionTypeEnum: + [output appendFormat:@"%@%@\n", indent, value]; + return; + case PBExtensionTypeGroup: + case PBExtensionTypeMessage: + [((PBAbstractMessage *)value) writeDescriptionTo:output withIndent:indent]; + return; + } + @throw [NSException exceptionWithName:@"InternalError" reason:@"" userInfo:nil]; +} + + +- (void)writeRepeatedValues:(NSArray*) values includingTagsToCodedOutputStream:(PBCodedOutputStream*) output { + if (isPacked) { + [output writeTag:fieldNumber format:PBWireFormatLengthDelimited]; + SInt32 dataSize = 0; + if (typeIsFixedSize(type)) { + dataSize = (SInt32)(values.count * typeSize(type)); + } else { + for (id value in values) { + dataSize += [self computeSingleSerializedSizeNoTag:value]; + } + } + [output writeRawVarint32:dataSize]; + for (id value in values) { + [self writeSingleValue:value noTagToCodedOutputStream:output]; + } + } else { + for (id value in values) { + [self writeSingleValue:value includingTagToCodedOutputStream:output]; + } + } +} + + +- (void) writeValue:(id) value includingTagToCodedOutputStream:(PBCodedOutputStream*) output { + if (isRepeated) { + [self writeRepeatedValues:value includingTagsToCodedOutputStream:output]; + } else { + [self writeSingleValue:value includingTagToCodedOutputStream:output]; + } +} + + +- (SInt32) computeRepeatedSerializedSizeIncludingTags:(NSArray*) values { + if (isPacked) { + SInt32 size = 0; + if (typeIsFixedSize(type)) { + size = (SInt32)(values.count * typeSize(type)); + } else { + for (id value in values) { + size += [self computeSingleSerializedSizeNoTag:value]; + } + } + return size + computeTagSize(fieldNumber) + computeRawVarint32Size(size); + } else { + SInt32 size = 0; + for (id value in values) { + size += [self computeSingleSerializedSizeIncludingTag:value]; + } + return size; + } +} + + +- (SInt32) computeSerializedSizeIncludingTag:(id) value { + if (isRepeated) { + return [self computeRepeatedSerializedSizeIncludingTags:value]; + } else { + return [self computeSingleSerializedSizeIncludingTag:value]; + } +} + + +- (void) writeDescriptionOf:(id)value + to:(NSMutableString *)output + withIndent:(NSString *)indent { + if (isRepeated) { + NSArray* values = value; + for (id singleValue in values) { + [self writeDescriptionOfSingleValue:singleValue to:output withIndent:indent]; + } + } else { + [self writeDescriptionOfSingleValue:value to:output withIndent:indent]; + } +} + +- (void) mergeMessageSetExtentionFromCodedInputStream:(PBCodedInputStream*) input + unknownFields:(PBUnknownFieldSetBuilder*) unknownFields { + @throw [NSException exceptionWithName:@"NYI" reason:@"" userInfo:nil]; + + // The wire format for MessageSet is: + // message MessageSet { + // repeated group Item = 1 { + // required int32 typeId = 2; + // required bytes message = 3; + // } + // } + // "typeId" is the extension's field number. The extension can only be + // a message type, where "message" contains the encoded bytes of that + // message. + // + // In practice, we will probably never see a MessageSet item in which + // the message appears before the type ID, or where either field does not + // appear exactly once. However, in theory such cases are valid, so we + // should be prepared to accept them. + + //int typeId = 0; +// ByteString rawBytes = null; +// +// while (true) { +// final int tag = input.readTag(); +// if (tag == 0) { +// break; +// } +// +// if (tag == WireFormat.MESSAGE_SET_TYPE_ID_TAG) { +// typeId = input.readUInt32(); +// // Zero is not a valid type ID. +// if (typeId != 0) { +// if (rawBytes != null) { +// unknownFields.mergeField(typeId, +// UnknownFieldSet.Field.newBuilder() +// .addLengthDelimited(rawBytes) +// .build()); +// rawBytes = null; +// } +// } +// } else if (tag == WireFormat.MESSAGE_SET_MESSAGE_TAG) { +// if (typeId == 0) { +// // We haven't seen a type ID yet, so we have to store the raw bytes +// // for now. +// rawBytes = input.readBytes(); +// } else { +// unknownFields.mergeField(typeId, +// UnknownFieldSet.Field.newBuilder() +// .addLengthDelimited(input.readBytes()) +// .build()); +// } +// } else { +// // Unknown fieldNumber. Skip it. +// if (!input.skipField(tag)) { +// break; // end of group +// } +// } +// } +// +// input.checkLastTagWas(WireFormat.MESSAGE_SET_ITEM_END_TAG); +} + + +- (id) readSingleValueFromCodedInputStream:(PBCodedInputStream*) input + extensionRegistry:(PBExtensionRegistry*) extensionRegistry { + switch (type) { + case PBExtensionTypeBool: return [NSNumber numberWithBool:[input readBool]]; + case PBExtensionTypeFixed32: return @([input readFixed32]); + case PBExtensionTypeSFixed32: return @([input readSFixed32]); + case PBExtensionTypeFloat: return [NSNumber numberWithFloat:[input readFloat]]; + case PBExtensionTypeFixed64: return [NSNumber numberWithLongLong:[input readFixed64]]; + case PBExtensionTypeSFixed64: return [NSNumber numberWithLongLong:[input readSFixed64]]; + case PBExtensionTypeDouble: return [NSNumber numberWithDouble:[input readDouble]]; + case PBExtensionTypeInt32: return @([input readInt32]); + case PBExtensionTypeInt64: return [NSNumber numberWithLongLong:[input readInt64]]; + case PBExtensionTypeSInt32: return @([input readSInt32]); + case PBExtensionTypeSInt64: return [NSNumber numberWithLongLong:[input readSInt64]]; + case PBExtensionTypeUInt32: return @([input readUInt32]); + case PBExtensionTypeUInt64: return [NSNumber numberWithLongLong:[input readUInt64]]; + case PBExtensionTypeBytes: return [input readData]; + case PBExtensionTypeString: return [input readString]; + case PBExtensionTypeEnum: return @([input readEnum]); + case PBExtensionTypeGroup: + { + id builder = [messageOrGroupClass builder]; + [input readGroup:fieldNumber builder:builder extensionRegistry:extensionRegistry]; + return [builder build]; + } + + case PBExtensionTypeMessage: + { + id builder = [messageOrGroupClass builder]; + [input readMessage:builder extensionRegistry:extensionRegistry]; + return [builder build]; + } + } + + @throw [NSException exceptionWithName:@"InternalError" reason:@"" userInfo:nil]; +} + + +- (void) mergeFromCodedInputStream:(PBCodedInputStream*) input + unknownFields:(PBUnknownFieldSetBuilder*) unknownFields + extensionRegistry:(PBExtensionRegistry*) extensionRegistry + builder:(PBExtendableMessageBuilder*) builder + tag:(SInt32) tag { + if (isPacked) { + SInt32 length = [input readRawVarint32]; + SInt32 limit = [input pushLimit:length]; + while ([input bytesUntilLimit] > 0) { + id value = [self readSingleValueFromCodedInputStream:input extensionRegistry:extensionRegistry]; + [builder addExtension:self value:value]; + } + [input popLimit:limit]; + } else if (isMessageSetWireFormat) { + [self mergeMessageSetExtentionFromCodedInputStream:input + unknownFields:unknownFields]; + } else { + id value = [self readSingleValueFromCodedInputStream:input extensionRegistry:extensionRegistry]; + if (isRepeated) { + [builder addExtension:self value:value]; + } else { + [builder setExtension:self value:value]; + } + } +} + + +@end diff --git a/ios/Pods/ProtocolBuffers/src/runtime/Classes/Descriptor.pb.h b/ios/Pods/ProtocolBuffers/src/runtime/Classes/Descriptor.pb.h new file mode 100644 index 000000000..4567b9e92 --- /dev/null +++ b/ios/Pods/ProtocolBuffers/src/runtime/Classes/Descriptor.pb.h @@ -0,0 +1,1796 @@ +// Generated by the protocol buffer compiler. DO NOT EDIT! + +// @@protoc_insertion_point(imports) +#import "ProtocolBuffers.h" + +@class PBDescriptorProto; +@class PBDescriptorProtoBuilder; +@class PBDescriptorProtoExtensionRange; +@class PBDescriptorProtoExtensionRangeBuilder; +@class PBEnumDescriptorProto; +@class PBEnumDescriptorProtoBuilder; +@class PBEnumOptions; +@class PBEnumOptionsBuilder; +@class PBEnumValueDescriptorProto; +@class PBEnumValueDescriptorProtoBuilder; +@class PBEnumValueOptions; +@class PBEnumValueOptionsBuilder; +@class PBFieldDescriptorProto; +@class PBFieldDescriptorProtoBuilder; +@class PBFieldOptions; +@class PBFieldOptionsBuilder; +@class PBFileDescriptorProto; +@class PBFileDescriptorProtoBuilder; +@class PBFileDescriptorSet; +@class PBFileDescriptorSetBuilder; +@class PBFileOptions; +@class PBFileOptionsBuilder; +@class PBMessageOptions; +@class PBMessageOptionsBuilder; +@class PBMethodDescriptorProto; +@class PBMethodDescriptorProtoBuilder; +@class PBMethodOptions; +@class PBMethodOptionsBuilder; +@class PBOneofDescriptorProto; +@class PBOneofDescriptorProtoBuilder; +@class PBServiceDescriptorProto; +@class PBServiceDescriptorProtoBuilder; +@class PBServiceOptions; +@class PBServiceOptionsBuilder; +@class PBSourceCodeInfo; +@class PBSourceCodeInfoBuilder; +@class PBSourceCodeInfoLocation; +@class PBSourceCodeInfoLocationBuilder; +@class PBUninterpretedOption; +@class PBUninterpretedOptionBuilder; +@class PBUninterpretedOptionNamePart; +@class PBUninterpretedOptionNamePartBuilder; +#ifndef __has_feature + #define __has_feature(x) 0 // Compatibility with non-clang compilers. +#endif // __has_feature + +#ifndef NS_RETURNS_NOT_RETAINED + #if __has_feature(attribute_ns_returns_not_retained) + #define NS_RETURNS_NOT_RETAINED __attribute__((ns_returns_not_retained)) + #else + #define NS_RETURNS_NOT_RETAINED + #endif +#endif + +typedef enum { + PBFieldDescriptorProtoTypeTypeDouble = 1, + PBFieldDescriptorProtoTypeTypeFloat = 2, + PBFieldDescriptorProtoTypeTypeInt64 = 3, + PBFieldDescriptorProtoTypeTypeUint64 = 4, + PBFieldDescriptorProtoTypeTypeInt32 = 5, + PBFieldDescriptorProtoTypeTypeFixed64 = 6, + PBFieldDescriptorProtoTypeTypeFixed32 = 7, + PBFieldDescriptorProtoTypeTypeBool = 8, + PBFieldDescriptorProtoTypeTypeString = 9, + PBFieldDescriptorProtoTypeTypeGroup = 10, + PBFieldDescriptorProtoTypeTypeMessage = 11, + PBFieldDescriptorProtoTypeTypeBytes = 12, + PBFieldDescriptorProtoTypeTypeUint32 = 13, + PBFieldDescriptorProtoTypeTypeEnum = 14, + PBFieldDescriptorProtoTypeTypeSfixed32 = 15, + PBFieldDescriptorProtoTypeTypeSfixed64 = 16, + PBFieldDescriptorProtoTypeTypeSint32 = 17, + PBFieldDescriptorProtoTypeTypeSint64 = 18, +} PBFieldDescriptorProtoType; + +BOOL PBFieldDescriptorProtoTypeIsValidValue(PBFieldDescriptorProtoType value); + +typedef enum { + PBFieldDescriptorProtoLabelLabelOptional = 1, + PBFieldDescriptorProtoLabelLabelRequired = 2, + PBFieldDescriptorProtoLabelLabelRepeated = 3, +} PBFieldDescriptorProtoLabel; + +BOOL PBFieldDescriptorProtoLabelIsValidValue(PBFieldDescriptorProtoLabel value); + +typedef enum { + PBFileOptionsOptimizeModeSpeed = 1, + PBFileOptionsOptimizeModeCodeSize = 2, + PBFileOptionsOptimizeModeLiteRuntime = 3, +} PBFileOptionsOptimizeMode; + +BOOL PBFileOptionsOptimizeModeIsValidValue(PBFileOptionsOptimizeMode value); + +typedef enum { + PBFieldOptionsCTypeString = 0, + PBFieldOptionsCTypeCord = 1, + PBFieldOptionsCTypeStringPiece = 2, +} PBFieldOptionsCType; + +BOOL PBFieldOptionsCTypeIsValidValue(PBFieldOptionsCType value); + + +@interface PBDescriptorRoot : NSObject { +} ++ (PBExtensionRegistry*) extensionRegistry; ++ (void) registerAllExtensions:(PBMutableExtensionRegistry*) registry; +@end + +@interface PBFileDescriptorSet : PBGeneratedMessage { +@private + NSMutableArray * fileArray; +} +@property (readonly, strong) NSArray * file; +- (PBFileDescriptorProto*)fileAtIndex:(NSUInteger)index; + ++ (PBFileDescriptorSet*) defaultInstance; +- (PBFileDescriptorSet*) defaultInstance; + +- (BOOL) isInitialized; +- (void) writeToCodedOutputStream:(PBCodedOutputStream*) output; +- (PBFileDescriptorSetBuilder*) builder; ++ (PBFileDescriptorSetBuilder*) builder; ++ (PBFileDescriptorSetBuilder*) builderWithPrototype:(PBFileDescriptorSet*) prototype; +- (PBFileDescriptorSetBuilder*) toBuilder; + ++ (PBFileDescriptorSet*) parseFromData:(NSData*) data; ++ (PBFileDescriptorSet*) parseFromData:(NSData*) data extensionRegistry:(PBExtensionRegistry*) extensionRegistry; ++ (PBFileDescriptorSet*) parseFromInputStream:(NSInputStream*) input; ++ (PBFileDescriptorSet*) parseFromInputStream:(NSInputStream*) input extensionRegistry:(PBExtensionRegistry*) extensionRegistry; ++ (PBFileDescriptorSet*) parseFromCodedInputStream:(PBCodedInputStream*) input; ++ (PBFileDescriptorSet*) parseFromCodedInputStream:(PBCodedInputStream*) input extensionRegistry:(PBExtensionRegistry*) extensionRegistry; +@end + +@interface PBFileDescriptorSetBuilder : PBGeneratedMessageBuilder { +@private + PBFileDescriptorSet* result; +} + +- (PBFileDescriptorSet*) defaultInstance; + +- (PBFileDescriptorSetBuilder*) clear; +- (PBFileDescriptorSetBuilder*) clone; + +- (PBFileDescriptorSet*) build; +- (PBFileDescriptorSet*) buildPartial; + +- (PBFileDescriptorSetBuilder*) mergeFrom:(PBFileDescriptorSet*) other; +- (PBFileDescriptorSetBuilder*) mergeFromCodedInputStream:(PBCodedInputStream*) input; +- (PBFileDescriptorSetBuilder*) mergeFromCodedInputStream:(PBCodedInputStream*) input extensionRegistry:(PBExtensionRegistry*) extensionRegistry; + +- (NSMutableArray *)file; +- (PBFileDescriptorProto*)fileAtIndex:(NSUInteger)index; +- (PBFileDescriptorSetBuilder *)addFile:(PBFileDescriptorProto*)value; +- (PBFileDescriptorSetBuilder *)setFileArray:(NSArray *)array; +- (PBFileDescriptorSetBuilder *)clearFile; +@end + +@interface PBFileDescriptorProto : PBGeneratedMessage { +@private + BOOL hasName_:1; + BOOL hasPackage_:1; + BOOL hasOptions_:1; + BOOL hasSourceCodeInfo_:1; + NSString* name; + NSString* package; + PBFileOptions* options; + PBSourceCodeInfo* sourceCodeInfo; + PBAppendableArray * publicDependencyArray; + PBAppendableArray * weakDependencyArray; + NSMutableArray * dependencyArray; + NSMutableArray * messageTypeArray; + NSMutableArray * enumTypeArray; + NSMutableArray * serviceArray; + NSMutableArray * extensionArray; +} +- (BOOL) hasName; +- (BOOL) hasPackage; +- (BOOL) hasOptions; +- (BOOL) hasSourceCodeInfo; +@property (readonly, strong) NSString* name; +@property (readonly, strong) NSString* package; +@property (readonly, strong) PBArray * dependency; +@property (readonly, strong) PBArray * publicDependency; +@property (readonly, strong) PBArray * weakDependency; +@property (readonly, strong) NSArray * messageType; +@property (readonly, strong) NSArray * enumType; +@property (readonly, strong) NSArray * service; +@property (readonly, strong) NSArray * extension; +@property (readonly, strong) PBFileOptions* options; +@property (readonly, strong) PBSourceCodeInfo* sourceCodeInfo; +- (NSString*)dependencyAtIndex:(NSUInteger)index; +- (SInt32)publicDependencyAtIndex:(NSUInteger)index; +- (SInt32)weakDependencyAtIndex:(NSUInteger)index; +- (PBDescriptorProto*)messageTypeAtIndex:(NSUInteger)index; +- (PBEnumDescriptorProto*)enumTypeAtIndex:(NSUInteger)index; +- (PBServiceDescriptorProto*)serviceAtIndex:(NSUInteger)index; +- (PBFieldDescriptorProto*)extensionAtIndex:(NSUInteger)index; + ++ (PBFileDescriptorProto*) defaultInstance; +- (PBFileDescriptorProto*) defaultInstance; + +- (BOOL) isInitialized; +- (void) writeToCodedOutputStream:(PBCodedOutputStream*) output; +- (PBFileDescriptorProtoBuilder*) builder; ++ (PBFileDescriptorProtoBuilder*) builder; ++ (PBFileDescriptorProtoBuilder*) builderWithPrototype:(PBFileDescriptorProto*) prototype; +- (PBFileDescriptorProtoBuilder*) toBuilder; + ++ (PBFileDescriptorProto*) parseFromData:(NSData*) data; ++ (PBFileDescriptorProto*) parseFromData:(NSData*) data extensionRegistry:(PBExtensionRegistry*) extensionRegistry; ++ (PBFileDescriptorProto*) parseFromInputStream:(NSInputStream*) input; ++ (PBFileDescriptorProto*) parseFromInputStream:(NSInputStream*) input extensionRegistry:(PBExtensionRegistry*) extensionRegistry; ++ (PBFileDescriptorProto*) parseFromCodedInputStream:(PBCodedInputStream*) input; ++ (PBFileDescriptorProto*) parseFromCodedInputStream:(PBCodedInputStream*) input extensionRegistry:(PBExtensionRegistry*) extensionRegistry; +@end + +@interface PBFileDescriptorProtoBuilder : PBGeneratedMessageBuilder { +@private + PBFileDescriptorProto* result; +} + +- (PBFileDescriptorProto*) defaultInstance; + +- (PBFileDescriptorProtoBuilder*) clear; +- (PBFileDescriptorProtoBuilder*) clone; + +- (PBFileDescriptorProto*) build; +- (PBFileDescriptorProto*) buildPartial; + +- (PBFileDescriptorProtoBuilder*) mergeFrom:(PBFileDescriptorProto*) other; +- (PBFileDescriptorProtoBuilder*) mergeFromCodedInputStream:(PBCodedInputStream*) input; +- (PBFileDescriptorProtoBuilder*) mergeFromCodedInputStream:(PBCodedInputStream*) input extensionRegistry:(PBExtensionRegistry*) extensionRegistry; + +- (BOOL) hasName; +- (NSString*) name; +- (PBFileDescriptorProtoBuilder*) setName:(NSString*) value; +- (PBFileDescriptorProtoBuilder*) clearName; + +- (BOOL) hasPackage; +- (NSString*) package; +- (PBFileDescriptorProtoBuilder*) setPackage:(NSString*) value; +- (PBFileDescriptorProtoBuilder*) clearPackage; + +- (NSMutableArray *)dependency; +- (NSString*)dependencyAtIndex:(NSUInteger)index; +- (PBFileDescriptorProtoBuilder *)addDependency:(NSString*)value; +- (PBFileDescriptorProtoBuilder *)setDependencyArray:(NSArray *)array; +- (PBFileDescriptorProtoBuilder *)clearDependency; + +- (PBAppendableArray *)publicDependency; +- (SInt32)publicDependencyAtIndex:(NSUInteger)index; +- (PBFileDescriptorProtoBuilder *)addPublicDependency:(SInt32)value; +- (PBFileDescriptorProtoBuilder *)setPublicDependencyArray:(NSArray *)array; +- (PBFileDescriptorProtoBuilder *)setPublicDependencyValues:(const SInt32 *)values count:(NSUInteger)count; +- (PBFileDescriptorProtoBuilder *)clearPublicDependency; + +- (PBAppendableArray *)weakDependency; +- (SInt32)weakDependencyAtIndex:(NSUInteger)index; +- (PBFileDescriptorProtoBuilder *)addWeakDependency:(SInt32)value; +- (PBFileDescriptorProtoBuilder *)setWeakDependencyArray:(NSArray *)array; +- (PBFileDescriptorProtoBuilder *)setWeakDependencyValues:(const SInt32 *)values count:(NSUInteger)count; +- (PBFileDescriptorProtoBuilder *)clearWeakDependency; + +- (NSMutableArray *)messageType; +- (PBDescriptorProto*)messageTypeAtIndex:(NSUInteger)index; +- (PBFileDescriptorProtoBuilder *)addMessageType:(PBDescriptorProto*)value; +- (PBFileDescriptorProtoBuilder *)setMessageTypeArray:(NSArray *)array; +- (PBFileDescriptorProtoBuilder *)clearMessageType; + +- (NSMutableArray *)enumType; +- (PBEnumDescriptorProto*)enumTypeAtIndex:(NSUInteger)index; +- (PBFileDescriptorProtoBuilder *)addEnumType:(PBEnumDescriptorProto*)value; +- (PBFileDescriptorProtoBuilder *)setEnumTypeArray:(NSArray *)array; +- (PBFileDescriptorProtoBuilder *)clearEnumType; + +- (NSMutableArray *)service; +- (PBServiceDescriptorProto*)serviceAtIndex:(NSUInteger)index; +- (PBFileDescriptorProtoBuilder *)addService:(PBServiceDescriptorProto*)value; +- (PBFileDescriptorProtoBuilder *)setServiceArray:(NSArray *)array; +- (PBFileDescriptorProtoBuilder *)clearService; + +- (NSMutableArray *)extension; +- (PBFieldDescriptorProto*)extensionAtIndex:(NSUInteger)index; +- (PBFileDescriptorProtoBuilder *)addExtension:(PBFieldDescriptorProto*)value; +- (PBFileDescriptorProtoBuilder *)setExtensionArray:(NSArray *)array; +- (PBFileDescriptorProtoBuilder *)clearExtension; + +- (BOOL) hasOptions; +- (PBFileOptions*) options; +- (PBFileDescriptorProtoBuilder*) setOptions:(PBFileOptions*) value; +- (PBFileDescriptorProtoBuilder*) setOptionsBuilder:(PBFileOptionsBuilder*) builderForValue; +- (PBFileDescriptorProtoBuilder*) mergeOptions:(PBFileOptions*) value; +- (PBFileDescriptorProtoBuilder*) clearOptions; + +- (BOOL) hasSourceCodeInfo; +- (PBSourceCodeInfo*) sourceCodeInfo; +- (PBFileDescriptorProtoBuilder*) setSourceCodeInfo:(PBSourceCodeInfo*) value; +- (PBFileDescriptorProtoBuilder*) setSourceCodeInfoBuilder:(PBSourceCodeInfoBuilder*) builderForValue; +- (PBFileDescriptorProtoBuilder*) mergeSourceCodeInfo:(PBSourceCodeInfo*) value; +- (PBFileDescriptorProtoBuilder*) clearSourceCodeInfo; +@end + +@interface PBDescriptorProto : PBGeneratedMessage { +@private + BOOL hasName_:1; + BOOL hasOptions_:1; + NSString* name; + PBMessageOptions* options; + NSMutableArray * fieldArray; + NSMutableArray * extensionArray; + NSMutableArray * nestedTypeArray; + NSMutableArray * enumTypeArray; + NSMutableArray * extensionRangeArray; + NSMutableArray * oneofDeclArray; +} +- (BOOL) hasName; +- (BOOL) hasOptions; +@property (readonly, strong) NSString* name; +@property (readonly, strong) NSArray * field; +@property (readonly, strong) NSArray * extension; +@property (readonly, strong) NSArray * nestedType; +@property (readonly, strong) NSArray * enumType; +@property (readonly, strong) NSArray * extensionRange; +@property (readonly, strong) NSArray * oneofDecl; +@property (readonly, strong) PBMessageOptions* options; +- (PBFieldDescriptorProto*)fieldAtIndex:(NSUInteger)index; +- (PBFieldDescriptorProto*)extensionAtIndex:(NSUInteger)index; +- (PBDescriptorProto*)nestedTypeAtIndex:(NSUInteger)index; +- (PBEnumDescriptorProto*)enumTypeAtIndex:(NSUInteger)index; +- (PBDescriptorProtoExtensionRange*)extensionRangeAtIndex:(NSUInteger)index; +- (PBOneofDescriptorProto*)oneofDeclAtIndex:(NSUInteger)index; + ++ (PBDescriptorProto*) defaultInstance; +- (PBDescriptorProto*) defaultInstance; + +- (BOOL) isInitialized; +- (void) writeToCodedOutputStream:(PBCodedOutputStream*) output; +- (PBDescriptorProtoBuilder*) builder; ++ (PBDescriptorProtoBuilder*) builder; ++ (PBDescriptorProtoBuilder*) builderWithPrototype:(PBDescriptorProto*) prototype; +- (PBDescriptorProtoBuilder*) toBuilder; + ++ (PBDescriptorProto*) parseFromData:(NSData*) data; ++ (PBDescriptorProto*) parseFromData:(NSData*) data extensionRegistry:(PBExtensionRegistry*) extensionRegistry; ++ (PBDescriptorProto*) parseFromInputStream:(NSInputStream*) input; ++ (PBDescriptorProto*) parseFromInputStream:(NSInputStream*) input extensionRegistry:(PBExtensionRegistry*) extensionRegistry; ++ (PBDescriptorProto*) parseFromCodedInputStream:(PBCodedInputStream*) input; ++ (PBDescriptorProto*) parseFromCodedInputStream:(PBCodedInputStream*) input extensionRegistry:(PBExtensionRegistry*) extensionRegistry; +@end + +@interface PBDescriptorProtoExtensionRange : PBGeneratedMessage { +@private + BOOL hasStart_:1; + BOOL hasEnd_:1; + SInt32 start; + SInt32 end; +} +- (BOOL) hasStart; +- (BOOL) hasEnd; +@property (readonly) SInt32 start; +@property (readonly) SInt32 end; + ++ (PBDescriptorProtoExtensionRange*) defaultInstance; +- (PBDescriptorProtoExtensionRange*) defaultInstance; + +- (BOOL) isInitialized; +- (void) writeToCodedOutputStream:(PBCodedOutputStream*) output; +- (PBDescriptorProtoExtensionRangeBuilder*) builder; ++ (PBDescriptorProtoExtensionRangeBuilder*) builder; ++ (PBDescriptorProtoExtensionRangeBuilder*) builderWithPrototype:(PBDescriptorProtoExtensionRange*) prototype; +- (PBDescriptorProtoExtensionRangeBuilder*) toBuilder; + ++ (PBDescriptorProtoExtensionRange*) parseFromData:(NSData*) data; ++ (PBDescriptorProtoExtensionRange*) parseFromData:(NSData*) data extensionRegistry:(PBExtensionRegistry*) extensionRegistry; ++ (PBDescriptorProtoExtensionRange*) parseFromInputStream:(NSInputStream*) input; ++ (PBDescriptorProtoExtensionRange*) parseFromInputStream:(NSInputStream*) input extensionRegistry:(PBExtensionRegistry*) extensionRegistry; ++ (PBDescriptorProtoExtensionRange*) parseFromCodedInputStream:(PBCodedInputStream*) input; ++ (PBDescriptorProtoExtensionRange*) parseFromCodedInputStream:(PBCodedInputStream*) input extensionRegistry:(PBExtensionRegistry*) extensionRegistry; +@end + +@interface PBDescriptorProtoExtensionRangeBuilder : PBGeneratedMessageBuilder { +@private + PBDescriptorProtoExtensionRange* result; +} + +- (PBDescriptorProtoExtensionRange*) defaultInstance; + +- (PBDescriptorProtoExtensionRangeBuilder*) clear; +- (PBDescriptorProtoExtensionRangeBuilder*) clone; + +- (PBDescriptorProtoExtensionRange*) build; +- (PBDescriptorProtoExtensionRange*) buildPartial; + +- (PBDescriptorProtoExtensionRangeBuilder*) mergeFrom:(PBDescriptorProtoExtensionRange*) other; +- (PBDescriptorProtoExtensionRangeBuilder*) mergeFromCodedInputStream:(PBCodedInputStream*) input; +- (PBDescriptorProtoExtensionRangeBuilder*) mergeFromCodedInputStream:(PBCodedInputStream*) input extensionRegistry:(PBExtensionRegistry*) extensionRegistry; + +- (BOOL) hasStart; +- (SInt32) start; +- (PBDescriptorProtoExtensionRangeBuilder*) setStart:(SInt32) value; +- (PBDescriptorProtoExtensionRangeBuilder*) clearStart; + +- (BOOL) hasEnd; +- (SInt32) end; +- (PBDescriptorProtoExtensionRangeBuilder*) setEnd:(SInt32) value; +- (PBDescriptorProtoExtensionRangeBuilder*) clearEnd; +@end + +@interface PBDescriptorProtoBuilder : PBGeneratedMessageBuilder { +@private + PBDescriptorProto* result; +} + +- (PBDescriptorProto*) defaultInstance; + +- (PBDescriptorProtoBuilder*) clear; +- (PBDescriptorProtoBuilder*) clone; + +- (PBDescriptorProto*) build; +- (PBDescriptorProto*) buildPartial; + +- (PBDescriptorProtoBuilder*) mergeFrom:(PBDescriptorProto*) other; +- (PBDescriptorProtoBuilder*) mergeFromCodedInputStream:(PBCodedInputStream*) input; +- (PBDescriptorProtoBuilder*) mergeFromCodedInputStream:(PBCodedInputStream*) input extensionRegistry:(PBExtensionRegistry*) extensionRegistry; + +- (BOOL) hasName; +- (NSString*) name; +- (PBDescriptorProtoBuilder*) setName:(NSString*) value; +- (PBDescriptorProtoBuilder*) clearName; + +- (NSMutableArray *)field; +- (PBFieldDescriptorProto*)fieldAtIndex:(NSUInteger)index; +- (PBDescriptorProtoBuilder *)addField:(PBFieldDescriptorProto*)value; +- (PBDescriptorProtoBuilder *)setFieldArray:(NSArray *)array; +- (PBDescriptorProtoBuilder *)clearField; + +- (NSMutableArray *)extension; +- (PBFieldDescriptorProto*)extensionAtIndex:(NSUInteger)index; +- (PBDescriptorProtoBuilder *)addExtension:(PBFieldDescriptorProto*)value; +- (PBDescriptorProtoBuilder *)setExtensionArray:(NSArray *)array; +- (PBDescriptorProtoBuilder *)clearExtension; + +- (NSMutableArray *)nestedType; +- (PBDescriptorProto*)nestedTypeAtIndex:(NSUInteger)index; +- (PBDescriptorProtoBuilder *)addNestedType:(PBDescriptorProto*)value; +- (PBDescriptorProtoBuilder *)setNestedTypeArray:(NSArray *)array; +- (PBDescriptorProtoBuilder *)clearNestedType; + +- (NSMutableArray *)enumType; +- (PBEnumDescriptorProto*)enumTypeAtIndex:(NSUInteger)index; +- (PBDescriptorProtoBuilder *)addEnumType:(PBEnumDescriptorProto*)value; +- (PBDescriptorProtoBuilder *)setEnumTypeArray:(NSArray *)array; +- (PBDescriptorProtoBuilder *)clearEnumType; + +- (NSMutableArray *)extensionRange; +- (PBDescriptorProtoExtensionRange*)extensionRangeAtIndex:(NSUInteger)index; +- (PBDescriptorProtoBuilder *)addExtensionRange:(PBDescriptorProtoExtensionRange*)value; +- (PBDescriptorProtoBuilder *)setExtensionRangeArray:(NSArray *)array; +- (PBDescriptorProtoBuilder *)clearExtensionRange; + +- (NSMutableArray *)oneofDecl; +- (PBOneofDescriptorProto*)oneofDeclAtIndex:(NSUInteger)index; +- (PBDescriptorProtoBuilder *)addOneofDecl:(PBOneofDescriptorProto*)value; +- (PBDescriptorProtoBuilder *)setOneofDeclArray:(NSArray *)array; +- (PBDescriptorProtoBuilder *)clearOneofDecl; + +- (BOOL) hasOptions; +- (PBMessageOptions*) options; +- (PBDescriptorProtoBuilder*) setOptions:(PBMessageOptions*) value; +- (PBDescriptorProtoBuilder*) setOptionsBuilder:(PBMessageOptionsBuilder*) builderForValue; +- (PBDescriptorProtoBuilder*) mergeOptions:(PBMessageOptions*) value; +- (PBDescriptorProtoBuilder*) clearOptions; +@end + +@interface PBFieldDescriptorProto : PBGeneratedMessage { +@private + BOOL hasNumber_:1; + BOOL hasOneofIndex_:1; + BOOL hasName_:1; + BOOL hasTypeName_:1; + BOOL hasExtendee_:1; + BOOL hasDefaultValue_:1; + BOOL hasOptions_:1; + BOOL hasLabel_:1; + BOOL hasType_:1; + SInt32 number; + SInt32 oneofIndex; + NSString* name; + NSString* typeName; + NSString* extendee; + NSString* defaultValue; + PBFieldOptions* options; + PBFieldDescriptorProtoLabel label; + PBFieldDescriptorProtoType type; +} +- (BOOL) hasName; +- (BOOL) hasNumber; +- (BOOL) hasLabel; +- (BOOL) hasType; +- (BOOL) hasTypeName; +- (BOOL) hasExtendee; +- (BOOL) hasDefaultValue; +- (BOOL) hasOneofIndex; +- (BOOL) hasOptions; +@property (readonly, strong) NSString* name; +@property (readonly) SInt32 number; +@property (readonly) PBFieldDescriptorProtoLabel label; +@property (readonly) PBFieldDescriptorProtoType type; +@property (readonly, strong) NSString* typeName; +@property (readonly, strong) NSString* extendee; +@property (readonly, strong) NSString* defaultValue; +@property (readonly) SInt32 oneofIndex; +@property (readonly, strong) PBFieldOptions* options; + ++ (PBFieldDescriptorProto*) defaultInstance; +- (PBFieldDescriptorProto*) defaultInstance; + +- (BOOL) isInitialized; +- (void) writeToCodedOutputStream:(PBCodedOutputStream*) output; +- (PBFieldDescriptorProtoBuilder*) builder; ++ (PBFieldDescriptorProtoBuilder*) builder; ++ (PBFieldDescriptorProtoBuilder*) builderWithPrototype:(PBFieldDescriptorProto*) prototype; +- (PBFieldDescriptorProtoBuilder*) toBuilder; + ++ (PBFieldDescriptorProto*) parseFromData:(NSData*) data; ++ (PBFieldDescriptorProto*) parseFromData:(NSData*) data extensionRegistry:(PBExtensionRegistry*) extensionRegistry; ++ (PBFieldDescriptorProto*) parseFromInputStream:(NSInputStream*) input; ++ (PBFieldDescriptorProto*) parseFromInputStream:(NSInputStream*) input extensionRegistry:(PBExtensionRegistry*) extensionRegistry; ++ (PBFieldDescriptorProto*) parseFromCodedInputStream:(PBCodedInputStream*) input; ++ (PBFieldDescriptorProto*) parseFromCodedInputStream:(PBCodedInputStream*) input extensionRegistry:(PBExtensionRegistry*) extensionRegistry; +@end + +@interface PBFieldDescriptorProtoBuilder : PBGeneratedMessageBuilder { +@private + PBFieldDescriptorProto* result; +} + +- (PBFieldDescriptorProto*) defaultInstance; + +- (PBFieldDescriptorProtoBuilder*) clear; +- (PBFieldDescriptorProtoBuilder*) clone; + +- (PBFieldDescriptorProto*) build; +- (PBFieldDescriptorProto*) buildPartial; + +- (PBFieldDescriptorProtoBuilder*) mergeFrom:(PBFieldDescriptorProto*) other; +- (PBFieldDescriptorProtoBuilder*) mergeFromCodedInputStream:(PBCodedInputStream*) input; +- (PBFieldDescriptorProtoBuilder*) mergeFromCodedInputStream:(PBCodedInputStream*) input extensionRegistry:(PBExtensionRegistry*) extensionRegistry; + +- (BOOL) hasName; +- (NSString*) name; +- (PBFieldDescriptorProtoBuilder*) setName:(NSString*) value; +- (PBFieldDescriptorProtoBuilder*) clearName; + +- (BOOL) hasNumber; +- (SInt32) number; +- (PBFieldDescriptorProtoBuilder*) setNumber:(SInt32) value; +- (PBFieldDescriptorProtoBuilder*) clearNumber; + +- (BOOL) hasLabel; +- (PBFieldDescriptorProtoLabel) label; +- (PBFieldDescriptorProtoBuilder*) setLabel:(PBFieldDescriptorProtoLabel) value; +- (PBFieldDescriptorProtoBuilder*) clearLabel; + +- (BOOL) hasType; +- (PBFieldDescriptorProtoType) type; +- (PBFieldDescriptorProtoBuilder*) setType:(PBFieldDescriptorProtoType) value; +- (PBFieldDescriptorProtoBuilder*) clearType; + +- (BOOL) hasTypeName; +- (NSString*) typeName; +- (PBFieldDescriptorProtoBuilder*) setTypeName:(NSString*) value; +- (PBFieldDescriptorProtoBuilder*) clearTypeName; + +- (BOOL) hasExtendee; +- (NSString*) extendee; +- (PBFieldDescriptorProtoBuilder*) setExtendee:(NSString*) value; +- (PBFieldDescriptorProtoBuilder*) clearExtendee; + +- (BOOL) hasDefaultValue; +- (NSString*) defaultValue; +- (PBFieldDescriptorProtoBuilder*) setDefaultValue:(NSString*) value; +- (PBFieldDescriptorProtoBuilder*) clearDefaultValue; + +- (BOOL) hasOneofIndex; +- (SInt32) oneofIndex; +- (PBFieldDescriptorProtoBuilder*) setOneofIndex:(SInt32) value; +- (PBFieldDescriptorProtoBuilder*) clearOneofIndex; + +- (BOOL) hasOptions; +- (PBFieldOptions*) options; +- (PBFieldDescriptorProtoBuilder*) setOptions:(PBFieldOptions*) value; +- (PBFieldDescriptorProtoBuilder*) setOptionsBuilder:(PBFieldOptionsBuilder*) builderForValue; +- (PBFieldDescriptorProtoBuilder*) mergeOptions:(PBFieldOptions*) value; +- (PBFieldDescriptorProtoBuilder*) clearOptions; +@end + +@interface PBOneofDescriptorProto : PBGeneratedMessage { +@private + BOOL hasName_:1; + NSString* name; +} +- (BOOL) hasName; +@property (readonly, strong) NSString* name; + ++ (PBOneofDescriptorProto*) defaultInstance; +- (PBOneofDescriptorProto*) defaultInstance; + +- (BOOL) isInitialized; +- (void) writeToCodedOutputStream:(PBCodedOutputStream*) output; +- (PBOneofDescriptorProtoBuilder*) builder; ++ (PBOneofDescriptorProtoBuilder*) builder; ++ (PBOneofDescriptorProtoBuilder*) builderWithPrototype:(PBOneofDescriptorProto*) prototype; +- (PBOneofDescriptorProtoBuilder*) toBuilder; + ++ (PBOneofDescriptorProto*) parseFromData:(NSData*) data; ++ (PBOneofDescriptorProto*) parseFromData:(NSData*) data extensionRegistry:(PBExtensionRegistry*) extensionRegistry; ++ (PBOneofDescriptorProto*) parseFromInputStream:(NSInputStream*) input; ++ (PBOneofDescriptorProto*) parseFromInputStream:(NSInputStream*) input extensionRegistry:(PBExtensionRegistry*) extensionRegistry; ++ (PBOneofDescriptorProto*) parseFromCodedInputStream:(PBCodedInputStream*) input; ++ (PBOneofDescriptorProto*) parseFromCodedInputStream:(PBCodedInputStream*) input extensionRegistry:(PBExtensionRegistry*) extensionRegistry; +@end + +@interface PBOneofDescriptorProtoBuilder : PBGeneratedMessageBuilder { +@private + PBOneofDescriptorProto* result; +} + +- (PBOneofDescriptorProto*) defaultInstance; + +- (PBOneofDescriptorProtoBuilder*) clear; +- (PBOneofDescriptorProtoBuilder*) clone; + +- (PBOneofDescriptorProto*) build; +- (PBOneofDescriptorProto*) buildPartial; + +- (PBOneofDescriptorProtoBuilder*) mergeFrom:(PBOneofDescriptorProto*) other; +- (PBOneofDescriptorProtoBuilder*) mergeFromCodedInputStream:(PBCodedInputStream*) input; +- (PBOneofDescriptorProtoBuilder*) mergeFromCodedInputStream:(PBCodedInputStream*) input extensionRegistry:(PBExtensionRegistry*) extensionRegistry; + +- (BOOL) hasName; +- (NSString*) name; +- (PBOneofDescriptorProtoBuilder*) setName:(NSString*) value; +- (PBOneofDescriptorProtoBuilder*) clearName; +@end + +@interface PBEnumDescriptorProto : PBGeneratedMessage { +@private + BOOL hasName_:1; + BOOL hasOptions_:1; + NSString* name; + PBEnumOptions* options; + NSMutableArray * valueArray; +} +- (BOOL) hasName; +- (BOOL) hasOptions; +@property (readonly, strong) NSString* name; +@property (readonly, strong) NSArray * value; +@property (readonly, strong) PBEnumOptions* options; +- (PBEnumValueDescriptorProto*)valueAtIndex:(NSUInteger)index; + ++ (PBEnumDescriptorProto*) defaultInstance; +- (PBEnumDescriptorProto*) defaultInstance; + +- (BOOL) isInitialized; +- (void) writeToCodedOutputStream:(PBCodedOutputStream*) output; +- (PBEnumDescriptorProtoBuilder*) builder; ++ (PBEnumDescriptorProtoBuilder*) builder; ++ (PBEnumDescriptorProtoBuilder*) builderWithPrototype:(PBEnumDescriptorProto*) prototype; +- (PBEnumDescriptorProtoBuilder*) toBuilder; + ++ (PBEnumDescriptorProto*) parseFromData:(NSData*) data; ++ (PBEnumDescriptorProto*) parseFromData:(NSData*) data extensionRegistry:(PBExtensionRegistry*) extensionRegistry; ++ (PBEnumDescriptorProto*) parseFromInputStream:(NSInputStream*) input; ++ (PBEnumDescriptorProto*) parseFromInputStream:(NSInputStream*) input extensionRegistry:(PBExtensionRegistry*) extensionRegistry; ++ (PBEnumDescriptorProto*) parseFromCodedInputStream:(PBCodedInputStream*) input; ++ (PBEnumDescriptorProto*) parseFromCodedInputStream:(PBCodedInputStream*) input extensionRegistry:(PBExtensionRegistry*) extensionRegistry; +@end + +@interface PBEnumDescriptorProtoBuilder : PBGeneratedMessageBuilder { +@private + PBEnumDescriptorProto* result; +} + +- (PBEnumDescriptorProto*) defaultInstance; + +- (PBEnumDescriptorProtoBuilder*) clear; +- (PBEnumDescriptorProtoBuilder*) clone; + +- (PBEnumDescriptorProto*) build; +- (PBEnumDescriptorProto*) buildPartial; + +- (PBEnumDescriptorProtoBuilder*) mergeFrom:(PBEnumDescriptorProto*) other; +- (PBEnumDescriptorProtoBuilder*) mergeFromCodedInputStream:(PBCodedInputStream*) input; +- (PBEnumDescriptorProtoBuilder*) mergeFromCodedInputStream:(PBCodedInputStream*) input extensionRegistry:(PBExtensionRegistry*) extensionRegistry; + +- (BOOL) hasName; +- (NSString*) name; +- (PBEnumDescriptorProtoBuilder*) setName:(NSString*) value; +- (PBEnumDescriptorProtoBuilder*) clearName; + +- (NSMutableArray *)value; +- (PBEnumValueDescriptorProto*)valueAtIndex:(NSUInteger)index; +- (PBEnumDescriptorProtoBuilder *)addValue:(PBEnumValueDescriptorProto*)value; +- (PBEnumDescriptorProtoBuilder *)setValueArray:(NSArray *)array; +- (PBEnumDescriptorProtoBuilder *)clearValue; + +- (BOOL) hasOptions; +- (PBEnumOptions*) options; +- (PBEnumDescriptorProtoBuilder*) setOptions:(PBEnumOptions*) value; +- (PBEnumDescriptorProtoBuilder*) setOptionsBuilder:(PBEnumOptionsBuilder*) builderForValue; +- (PBEnumDescriptorProtoBuilder*) mergeOptions:(PBEnumOptions*) value; +- (PBEnumDescriptorProtoBuilder*) clearOptions; +@end + +@interface PBEnumValueDescriptorProto : PBGeneratedMessage { +@private + BOOL hasNumber_:1; + BOOL hasName_:1; + BOOL hasOptions_:1; + SInt32 number; + NSString* name; + PBEnumValueOptions* options; +} +- (BOOL) hasName; +- (BOOL) hasNumber; +- (BOOL) hasOptions; +@property (readonly, strong) NSString* name; +@property (readonly) SInt32 number; +@property (readonly, strong) PBEnumValueOptions* options; + ++ (PBEnumValueDescriptorProto*) defaultInstance; +- (PBEnumValueDescriptorProto*) defaultInstance; + +- (BOOL) isInitialized; +- (void) writeToCodedOutputStream:(PBCodedOutputStream*) output; +- (PBEnumValueDescriptorProtoBuilder*) builder; ++ (PBEnumValueDescriptorProtoBuilder*) builder; ++ (PBEnumValueDescriptorProtoBuilder*) builderWithPrototype:(PBEnumValueDescriptorProto*) prototype; +- (PBEnumValueDescriptorProtoBuilder*) toBuilder; + ++ (PBEnumValueDescriptorProto*) parseFromData:(NSData*) data; ++ (PBEnumValueDescriptorProto*) parseFromData:(NSData*) data extensionRegistry:(PBExtensionRegistry*) extensionRegistry; ++ (PBEnumValueDescriptorProto*) parseFromInputStream:(NSInputStream*) input; ++ (PBEnumValueDescriptorProto*) parseFromInputStream:(NSInputStream*) input extensionRegistry:(PBExtensionRegistry*) extensionRegistry; ++ (PBEnumValueDescriptorProto*) parseFromCodedInputStream:(PBCodedInputStream*) input; ++ (PBEnumValueDescriptorProto*) parseFromCodedInputStream:(PBCodedInputStream*) input extensionRegistry:(PBExtensionRegistry*) extensionRegistry; +@end + +@interface PBEnumValueDescriptorProtoBuilder : PBGeneratedMessageBuilder { +@private + PBEnumValueDescriptorProto* result; +} + +- (PBEnumValueDescriptorProto*) defaultInstance; + +- (PBEnumValueDescriptorProtoBuilder*) clear; +- (PBEnumValueDescriptorProtoBuilder*) clone; + +- (PBEnumValueDescriptorProto*) build; +- (PBEnumValueDescriptorProto*) buildPartial; + +- (PBEnumValueDescriptorProtoBuilder*) mergeFrom:(PBEnumValueDescriptorProto*) other; +- (PBEnumValueDescriptorProtoBuilder*) mergeFromCodedInputStream:(PBCodedInputStream*) input; +- (PBEnumValueDescriptorProtoBuilder*) mergeFromCodedInputStream:(PBCodedInputStream*) input extensionRegistry:(PBExtensionRegistry*) extensionRegistry; + +- (BOOL) hasName; +- (NSString*) name; +- (PBEnumValueDescriptorProtoBuilder*) setName:(NSString*) value; +- (PBEnumValueDescriptorProtoBuilder*) clearName; + +- (BOOL) hasNumber; +- (SInt32) number; +- (PBEnumValueDescriptorProtoBuilder*) setNumber:(SInt32) value; +- (PBEnumValueDescriptorProtoBuilder*) clearNumber; + +- (BOOL) hasOptions; +- (PBEnumValueOptions*) options; +- (PBEnumValueDescriptorProtoBuilder*) setOptions:(PBEnumValueOptions*) value; +- (PBEnumValueDescriptorProtoBuilder*) setOptionsBuilder:(PBEnumValueOptionsBuilder*) builderForValue; +- (PBEnumValueDescriptorProtoBuilder*) mergeOptions:(PBEnumValueOptions*) value; +- (PBEnumValueDescriptorProtoBuilder*) clearOptions; +@end + +@interface PBServiceDescriptorProto : PBGeneratedMessage { +@private + BOOL hasName_:1; + BOOL hasOptions_:1; + NSString* name; + PBServiceOptions* options; + NSMutableArray * methodArray; +} +- (BOOL) hasName; +- (BOOL) hasOptions; +@property (readonly, strong) NSString* name; +@property (readonly, strong) NSArray * method; +@property (readonly, strong) PBServiceOptions* options; +- (PBMethodDescriptorProto*)methodAtIndex:(NSUInteger)index; + ++ (PBServiceDescriptorProto*) defaultInstance; +- (PBServiceDescriptorProto*) defaultInstance; + +- (BOOL) isInitialized; +- (void) writeToCodedOutputStream:(PBCodedOutputStream*) output; +- (PBServiceDescriptorProtoBuilder*) builder; ++ (PBServiceDescriptorProtoBuilder*) builder; ++ (PBServiceDescriptorProtoBuilder*) builderWithPrototype:(PBServiceDescriptorProto*) prototype; +- (PBServiceDescriptorProtoBuilder*) toBuilder; + ++ (PBServiceDescriptorProto*) parseFromData:(NSData*) data; ++ (PBServiceDescriptorProto*) parseFromData:(NSData*) data extensionRegistry:(PBExtensionRegistry*) extensionRegistry; ++ (PBServiceDescriptorProto*) parseFromInputStream:(NSInputStream*) input; ++ (PBServiceDescriptorProto*) parseFromInputStream:(NSInputStream*) input extensionRegistry:(PBExtensionRegistry*) extensionRegistry; ++ (PBServiceDescriptorProto*) parseFromCodedInputStream:(PBCodedInputStream*) input; ++ (PBServiceDescriptorProto*) parseFromCodedInputStream:(PBCodedInputStream*) input extensionRegistry:(PBExtensionRegistry*) extensionRegistry; +@end + +@interface PBServiceDescriptorProtoBuilder : PBGeneratedMessageBuilder { +@private + PBServiceDescriptorProto* result; +} + +- (PBServiceDescriptorProto*) defaultInstance; + +- (PBServiceDescriptorProtoBuilder*) clear; +- (PBServiceDescriptorProtoBuilder*) clone; + +- (PBServiceDescriptorProto*) build; +- (PBServiceDescriptorProto*) buildPartial; + +- (PBServiceDescriptorProtoBuilder*) mergeFrom:(PBServiceDescriptorProto*) other; +- (PBServiceDescriptorProtoBuilder*) mergeFromCodedInputStream:(PBCodedInputStream*) input; +- (PBServiceDescriptorProtoBuilder*) mergeFromCodedInputStream:(PBCodedInputStream*) input extensionRegistry:(PBExtensionRegistry*) extensionRegistry; + +- (BOOL) hasName; +- (NSString*) name; +- (PBServiceDescriptorProtoBuilder*) setName:(NSString*) value; +- (PBServiceDescriptorProtoBuilder*) clearName; + +- (NSMutableArray *)method; +- (PBMethodDescriptorProto*)methodAtIndex:(NSUInteger)index; +- (PBServiceDescriptorProtoBuilder *)addMethod:(PBMethodDescriptorProto*)value; +- (PBServiceDescriptorProtoBuilder *)setMethodArray:(NSArray *)array; +- (PBServiceDescriptorProtoBuilder *)clearMethod; + +- (BOOL) hasOptions; +- (PBServiceOptions*) options; +- (PBServiceDescriptorProtoBuilder*) setOptions:(PBServiceOptions*) value; +- (PBServiceDescriptorProtoBuilder*) setOptionsBuilder:(PBServiceOptionsBuilder*) builderForValue; +- (PBServiceDescriptorProtoBuilder*) mergeOptions:(PBServiceOptions*) value; +- (PBServiceDescriptorProtoBuilder*) clearOptions; +@end + +@interface PBMethodDescriptorProto : PBGeneratedMessage { +@private + BOOL hasName_:1; + BOOL hasInputType_:1; + BOOL hasOutputType_:1; + BOOL hasOptions_:1; + NSString* name; + NSString* inputType; + NSString* outputType; + PBMethodOptions* options; +} +- (BOOL) hasName; +- (BOOL) hasInputType; +- (BOOL) hasOutputType; +- (BOOL) hasOptions; +@property (readonly, strong) NSString* name; +@property (readonly, strong) NSString* inputType; +@property (readonly, strong) NSString* outputType; +@property (readonly, strong) PBMethodOptions* options; + ++ (PBMethodDescriptorProto*) defaultInstance; +- (PBMethodDescriptorProto*) defaultInstance; + +- (BOOL) isInitialized; +- (void) writeToCodedOutputStream:(PBCodedOutputStream*) output; +- (PBMethodDescriptorProtoBuilder*) builder; ++ (PBMethodDescriptorProtoBuilder*) builder; ++ (PBMethodDescriptorProtoBuilder*) builderWithPrototype:(PBMethodDescriptorProto*) prototype; +- (PBMethodDescriptorProtoBuilder*) toBuilder; + ++ (PBMethodDescriptorProto*) parseFromData:(NSData*) data; ++ (PBMethodDescriptorProto*) parseFromData:(NSData*) data extensionRegistry:(PBExtensionRegistry*) extensionRegistry; ++ (PBMethodDescriptorProto*) parseFromInputStream:(NSInputStream*) input; ++ (PBMethodDescriptorProto*) parseFromInputStream:(NSInputStream*) input extensionRegistry:(PBExtensionRegistry*) extensionRegistry; ++ (PBMethodDescriptorProto*) parseFromCodedInputStream:(PBCodedInputStream*) input; ++ (PBMethodDescriptorProto*) parseFromCodedInputStream:(PBCodedInputStream*) input extensionRegistry:(PBExtensionRegistry*) extensionRegistry; +@end + +@interface PBMethodDescriptorProtoBuilder : PBGeneratedMessageBuilder { +@private + PBMethodDescriptorProto* result; +} + +- (PBMethodDescriptorProto*) defaultInstance; + +- (PBMethodDescriptorProtoBuilder*) clear; +- (PBMethodDescriptorProtoBuilder*) clone; + +- (PBMethodDescriptorProto*) build; +- (PBMethodDescriptorProto*) buildPartial; + +- (PBMethodDescriptorProtoBuilder*) mergeFrom:(PBMethodDescriptorProto*) other; +- (PBMethodDescriptorProtoBuilder*) mergeFromCodedInputStream:(PBCodedInputStream*) input; +- (PBMethodDescriptorProtoBuilder*) mergeFromCodedInputStream:(PBCodedInputStream*) input extensionRegistry:(PBExtensionRegistry*) extensionRegistry; + +- (BOOL) hasName; +- (NSString*) name; +- (PBMethodDescriptorProtoBuilder*) setName:(NSString*) value; +- (PBMethodDescriptorProtoBuilder*) clearName; + +- (BOOL) hasInputType; +- (NSString*) inputType; +- (PBMethodDescriptorProtoBuilder*) setInputType:(NSString*) value; +- (PBMethodDescriptorProtoBuilder*) clearInputType; + +- (BOOL) hasOutputType; +- (NSString*) outputType; +- (PBMethodDescriptorProtoBuilder*) setOutputType:(NSString*) value; +- (PBMethodDescriptorProtoBuilder*) clearOutputType; + +- (BOOL) hasOptions; +- (PBMethodOptions*) options; +- (PBMethodDescriptorProtoBuilder*) setOptions:(PBMethodOptions*) value; +- (PBMethodDescriptorProtoBuilder*) setOptionsBuilder:(PBMethodOptionsBuilder*) builderForValue; +- (PBMethodDescriptorProtoBuilder*) mergeOptions:(PBMethodOptions*) value; +- (PBMethodDescriptorProtoBuilder*) clearOptions; +@end + +@interface PBFileOptions : PBExtendableMessage { +@private + BOOL hasJavaMultipleFiles_:1; + BOOL hasJavaGenerateEqualsAndHash_:1; + BOOL hasJavaStringCheckUtf8_:1; + BOOL hasCcGenericServices_:1; + BOOL hasJavaGenericServices_:1; + BOOL hasPyGenericServices_:1; + BOOL hasDeprecated_:1; + BOOL hasJavaPackage_:1; + BOOL hasJavaOuterClassname_:1; + BOOL hasGoPackage_:1; + BOOL hasOptimizeFor_:1; + BOOL javaMultipleFiles_:1; + BOOL javaGenerateEqualsAndHash_:1; + BOOL javaStringCheckUtf8_:1; + BOOL ccGenericServices_:1; + BOOL javaGenericServices_:1; + BOOL pyGenericServices_:1; + BOOL deprecated_:1; + NSString* javaPackage; + NSString* javaOuterClassname; + NSString* goPackage; + PBFileOptionsOptimizeMode optimizeFor; + NSMutableArray * uninterpretedOptionArray; +} +- (BOOL) hasJavaPackage; +- (BOOL) hasJavaOuterClassname; +- (BOOL) hasJavaMultipleFiles; +- (BOOL) hasJavaGenerateEqualsAndHash; +- (BOOL) hasJavaStringCheckUtf8; +- (BOOL) hasOptimizeFor; +- (BOOL) hasGoPackage; +- (BOOL) hasCcGenericServices; +- (BOOL) hasJavaGenericServices; +- (BOOL) hasPyGenericServices; +- (BOOL) hasDeprecated; +@property (readonly, strong) NSString* javaPackage; +@property (readonly, strong) NSString* javaOuterClassname; +- (BOOL) javaMultipleFiles; +- (BOOL) javaGenerateEqualsAndHash; +- (BOOL) javaStringCheckUtf8; +@property (readonly) PBFileOptionsOptimizeMode optimizeFor; +@property (readonly, strong) NSString* goPackage; +- (BOOL) ccGenericServices; +- (BOOL) javaGenericServices; +- (BOOL) pyGenericServices; +- (BOOL) deprecated; +@property (readonly, strong) NSArray * uninterpretedOption; +- (PBUninterpretedOption*)uninterpretedOptionAtIndex:(NSUInteger)index; + ++ (PBFileOptions*) defaultInstance; +- (PBFileOptions*) defaultInstance; + +- (BOOL) isInitialized; +- (void) writeToCodedOutputStream:(PBCodedOutputStream*) output; +- (PBFileOptionsBuilder*) builder; ++ (PBFileOptionsBuilder*) builder; ++ (PBFileOptionsBuilder*) builderWithPrototype:(PBFileOptions*) prototype; +- (PBFileOptionsBuilder*) toBuilder; + ++ (PBFileOptions*) parseFromData:(NSData*) data; ++ (PBFileOptions*) parseFromData:(NSData*) data extensionRegistry:(PBExtensionRegistry*) extensionRegistry; ++ (PBFileOptions*) parseFromInputStream:(NSInputStream*) input; ++ (PBFileOptions*) parseFromInputStream:(NSInputStream*) input extensionRegistry:(PBExtensionRegistry*) extensionRegistry; ++ (PBFileOptions*) parseFromCodedInputStream:(PBCodedInputStream*) input; ++ (PBFileOptions*) parseFromCodedInputStream:(PBCodedInputStream*) input extensionRegistry:(PBExtensionRegistry*) extensionRegistry; +@end + +@interface PBFileOptionsBuilder : PBExtendableMessageBuilder { +@private + PBFileOptions* result; +} + +- (PBFileOptions*) defaultInstance; + +- (PBFileOptionsBuilder*) clear; +- (PBFileOptionsBuilder*) clone; + +- (PBFileOptions*) build; +- (PBFileOptions*) buildPartial; + +- (PBFileOptionsBuilder*) mergeFrom:(PBFileOptions*) other; +- (PBFileOptionsBuilder*) mergeFromCodedInputStream:(PBCodedInputStream*) input; +- (PBFileOptionsBuilder*) mergeFromCodedInputStream:(PBCodedInputStream*) input extensionRegistry:(PBExtensionRegistry*) extensionRegistry; + +- (BOOL) hasJavaPackage; +- (NSString*) javaPackage; +- (PBFileOptionsBuilder*) setJavaPackage:(NSString*) value; +- (PBFileOptionsBuilder*) clearJavaPackage; + +- (BOOL) hasJavaOuterClassname; +- (NSString*) javaOuterClassname; +- (PBFileOptionsBuilder*) setJavaOuterClassname:(NSString*) value; +- (PBFileOptionsBuilder*) clearJavaOuterClassname; + +- (BOOL) hasJavaMultipleFiles; +- (BOOL) javaMultipleFiles; +- (PBFileOptionsBuilder*) setJavaMultipleFiles:(BOOL) value; +- (PBFileOptionsBuilder*) clearJavaMultipleFiles; + +- (BOOL) hasJavaGenerateEqualsAndHash; +- (BOOL) javaGenerateEqualsAndHash; +- (PBFileOptionsBuilder*) setJavaGenerateEqualsAndHash:(BOOL) value; +- (PBFileOptionsBuilder*) clearJavaGenerateEqualsAndHash; + +- (BOOL) hasJavaStringCheckUtf8; +- (BOOL) javaStringCheckUtf8; +- (PBFileOptionsBuilder*) setJavaStringCheckUtf8:(BOOL) value; +- (PBFileOptionsBuilder*) clearJavaStringCheckUtf8; + +- (BOOL) hasOptimizeFor; +- (PBFileOptionsOptimizeMode) optimizeFor; +- (PBFileOptionsBuilder*) setOptimizeFor:(PBFileOptionsOptimizeMode) value; +- (PBFileOptionsBuilder*) clearOptimizeFor; + +- (BOOL) hasGoPackage; +- (NSString*) goPackage; +- (PBFileOptionsBuilder*) setGoPackage:(NSString*) value; +- (PBFileOptionsBuilder*) clearGoPackage; + +- (BOOL) hasCcGenericServices; +- (BOOL) ccGenericServices; +- (PBFileOptionsBuilder*) setCcGenericServices:(BOOL) value; +- (PBFileOptionsBuilder*) clearCcGenericServices; + +- (BOOL) hasJavaGenericServices; +- (BOOL) javaGenericServices; +- (PBFileOptionsBuilder*) setJavaGenericServices:(BOOL) value; +- (PBFileOptionsBuilder*) clearJavaGenericServices; + +- (BOOL) hasPyGenericServices; +- (BOOL) pyGenericServices; +- (PBFileOptionsBuilder*) setPyGenericServices:(BOOL) value; +- (PBFileOptionsBuilder*) clearPyGenericServices; + +- (BOOL) hasDeprecated; +- (BOOL) deprecated; +- (PBFileOptionsBuilder*) setDeprecated:(BOOL) value; +- (PBFileOptionsBuilder*) clearDeprecated; + +- (NSMutableArray *)uninterpretedOption; +- (PBUninterpretedOption*)uninterpretedOptionAtIndex:(NSUInteger)index; +- (PBFileOptionsBuilder *)addUninterpretedOption:(PBUninterpretedOption*)value; +- (PBFileOptionsBuilder *)setUninterpretedOptionArray:(NSArray *)array; +- (PBFileOptionsBuilder *)clearUninterpretedOption; +@end + +@interface PBMessageOptions : PBExtendableMessage { +@private + BOOL hasMessageSetWireFormat_:1; + BOOL hasNoStandardDescriptorAccessor_:1; + BOOL hasDeprecated_:1; + BOOL messageSetWireFormat_:1; + BOOL noStandardDescriptorAccessor_:1; + BOOL deprecated_:1; + NSMutableArray * uninterpretedOptionArray; +} +- (BOOL) hasMessageSetWireFormat; +- (BOOL) hasNoStandardDescriptorAccessor; +- (BOOL) hasDeprecated; +- (BOOL) messageSetWireFormat; +- (BOOL) noStandardDescriptorAccessor; +- (BOOL) deprecated; +@property (readonly, strong) NSArray * uninterpretedOption; +- (PBUninterpretedOption*)uninterpretedOptionAtIndex:(NSUInteger)index; + ++ (PBMessageOptions*) defaultInstance; +- (PBMessageOptions*) defaultInstance; + +- (BOOL) isInitialized; +- (void) writeToCodedOutputStream:(PBCodedOutputStream*) output; +- (PBMessageOptionsBuilder*) builder; ++ (PBMessageOptionsBuilder*) builder; ++ (PBMessageOptionsBuilder*) builderWithPrototype:(PBMessageOptions*) prototype; +- (PBMessageOptionsBuilder*) toBuilder; + ++ (PBMessageOptions*) parseFromData:(NSData*) data; ++ (PBMessageOptions*) parseFromData:(NSData*) data extensionRegistry:(PBExtensionRegistry*) extensionRegistry; ++ (PBMessageOptions*) parseFromInputStream:(NSInputStream*) input; ++ (PBMessageOptions*) parseFromInputStream:(NSInputStream*) input extensionRegistry:(PBExtensionRegistry*) extensionRegistry; ++ (PBMessageOptions*) parseFromCodedInputStream:(PBCodedInputStream*) input; ++ (PBMessageOptions*) parseFromCodedInputStream:(PBCodedInputStream*) input extensionRegistry:(PBExtensionRegistry*) extensionRegistry; +@end + +@interface PBMessageOptionsBuilder : PBExtendableMessageBuilder { +@private + PBMessageOptions* result; +} + +- (PBMessageOptions*) defaultInstance; + +- (PBMessageOptionsBuilder*) clear; +- (PBMessageOptionsBuilder*) clone; + +- (PBMessageOptions*) build; +- (PBMessageOptions*) buildPartial; + +- (PBMessageOptionsBuilder*) mergeFrom:(PBMessageOptions*) other; +- (PBMessageOptionsBuilder*) mergeFromCodedInputStream:(PBCodedInputStream*) input; +- (PBMessageOptionsBuilder*) mergeFromCodedInputStream:(PBCodedInputStream*) input extensionRegistry:(PBExtensionRegistry*) extensionRegistry; + +- (BOOL) hasMessageSetWireFormat; +- (BOOL) messageSetWireFormat; +- (PBMessageOptionsBuilder*) setMessageSetWireFormat:(BOOL) value; +- (PBMessageOptionsBuilder*) clearMessageSetWireFormat; + +- (BOOL) hasNoStandardDescriptorAccessor; +- (BOOL) noStandardDescriptorAccessor; +- (PBMessageOptionsBuilder*) setNoStandardDescriptorAccessor:(BOOL) value; +- (PBMessageOptionsBuilder*) clearNoStandardDescriptorAccessor; + +- (BOOL) hasDeprecated; +- (BOOL) deprecated; +- (PBMessageOptionsBuilder*) setDeprecated:(BOOL) value; +- (PBMessageOptionsBuilder*) clearDeprecated; + +- (NSMutableArray *)uninterpretedOption; +- (PBUninterpretedOption*)uninterpretedOptionAtIndex:(NSUInteger)index; +- (PBMessageOptionsBuilder *)addUninterpretedOption:(PBUninterpretedOption*)value; +- (PBMessageOptionsBuilder *)setUninterpretedOptionArray:(NSArray *)array; +- (PBMessageOptionsBuilder *)clearUninterpretedOption; +@end + +@interface PBFieldOptions : PBExtendableMessage { +@private + BOOL hasPacked_:1; + BOOL hasLazy_:1; + BOOL hasDeprecated_:1; + BOOL hasWeak_:1; + BOOL hasExperimentalMapKey_:1; + BOOL hasCtype_:1; + BOOL packed_:1; + BOOL lazy_:1; + BOOL deprecated_:1; + BOOL weak_:1; + NSString* experimentalMapKey; + PBFieldOptionsCType ctype; + NSMutableArray * uninterpretedOptionArray; +} +- (BOOL) hasCtype; +- (BOOL) hasPacked; +- (BOOL) hasLazy; +- (BOOL) hasDeprecated; +- (BOOL) hasExperimentalMapKey; +- (BOOL) hasWeak; +@property (readonly) PBFieldOptionsCType ctype; +- (BOOL) packed; +- (BOOL) lazy; +- (BOOL) deprecated; +@property (readonly, strong) NSString* experimentalMapKey; +- (BOOL) weak; +@property (readonly, strong) NSArray * uninterpretedOption; +- (PBUninterpretedOption*)uninterpretedOptionAtIndex:(NSUInteger)index; + ++ (PBFieldOptions*) defaultInstance; +- (PBFieldOptions*) defaultInstance; + +- (BOOL) isInitialized; +- (void) writeToCodedOutputStream:(PBCodedOutputStream*) output; +- (PBFieldOptionsBuilder*) builder; ++ (PBFieldOptionsBuilder*) builder; ++ (PBFieldOptionsBuilder*) builderWithPrototype:(PBFieldOptions*) prototype; +- (PBFieldOptionsBuilder*) toBuilder; + ++ (PBFieldOptions*) parseFromData:(NSData*) data; ++ (PBFieldOptions*) parseFromData:(NSData*) data extensionRegistry:(PBExtensionRegistry*) extensionRegistry; ++ (PBFieldOptions*) parseFromInputStream:(NSInputStream*) input; ++ (PBFieldOptions*) parseFromInputStream:(NSInputStream*) input extensionRegistry:(PBExtensionRegistry*) extensionRegistry; ++ (PBFieldOptions*) parseFromCodedInputStream:(PBCodedInputStream*) input; ++ (PBFieldOptions*) parseFromCodedInputStream:(PBCodedInputStream*) input extensionRegistry:(PBExtensionRegistry*) extensionRegistry; +@end + +@interface PBFieldOptionsBuilder : PBExtendableMessageBuilder { +@private + PBFieldOptions* result; +} + +- (PBFieldOptions*) defaultInstance; + +- (PBFieldOptionsBuilder*) clear; +- (PBFieldOptionsBuilder*) clone; + +- (PBFieldOptions*) build; +- (PBFieldOptions*) buildPartial; + +- (PBFieldOptionsBuilder*) mergeFrom:(PBFieldOptions*) other; +- (PBFieldOptionsBuilder*) mergeFromCodedInputStream:(PBCodedInputStream*) input; +- (PBFieldOptionsBuilder*) mergeFromCodedInputStream:(PBCodedInputStream*) input extensionRegistry:(PBExtensionRegistry*) extensionRegistry; + +- (BOOL) hasCtype; +- (PBFieldOptionsCType) ctype; +- (PBFieldOptionsBuilder*) setCtype:(PBFieldOptionsCType) value; +- (PBFieldOptionsBuilder*) clearCtype; + +- (BOOL) hasPacked; +- (BOOL) packed; +- (PBFieldOptionsBuilder*) setPacked:(BOOL) value; +- (PBFieldOptionsBuilder*) clearPacked; + +- (BOOL) hasLazy; +- (BOOL) lazy; +- (PBFieldOptionsBuilder*) setLazy:(BOOL) value; +- (PBFieldOptionsBuilder*) clearLazy; + +- (BOOL) hasDeprecated; +- (BOOL) deprecated; +- (PBFieldOptionsBuilder*) setDeprecated:(BOOL) value; +- (PBFieldOptionsBuilder*) clearDeprecated; + +- (BOOL) hasExperimentalMapKey; +- (NSString*) experimentalMapKey; +- (PBFieldOptionsBuilder*) setExperimentalMapKey:(NSString*) value; +- (PBFieldOptionsBuilder*) clearExperimentalMapKey; + +- (BOOL) hasWeak; +- (BOOL) weak; +- (PBFieldOptionsBuilder*) setWeak:(BOOL) value; +- (PBFieldOptionsBuilder*) clearWeak; + +- (NSMutableArray *)uninterpretedOption; +- (PBUninterpretedOption*)uninterpretedOptionAtIndex:(NSUInteger)index; +- (PBFieldOptionsBuilder *)addUninterpretedOption:(PBUninterpretedOption*)value; +- (PBFieldOptionsBuilder *)setUninterpretedOptionArray:(NSArray *)array; +- (PBFieldOptionsBuilder *)clearUninterpretedOption; +@end + +@interface PBEnumOptions : PBExtendableMessage { +@private + BOOL hasAllowAlias_:1; + BOOL hasDeprecated_:1; + BOOL allowAlias_:1; + BOOL deprecated_:1; + NSMutableArray * uninterpretedOptionArray; +} +- (BOOL) hasAllowAlias; +- (BOOL) hasDeprecated; +- (BOOL) allowAlias; +- (BOOL) deprecated; +@property (readonly, strong) NSArray * uninterpretedOption; +- (PBUninterpretedOption*)uninterpretedOptionAtIndex:(NSUInteger)index; + ++ (PBEnumOptions*) defaultInstance; +- (PBEnumOptions*) defaultInstance; + +- (BOOL) isInitialized; +- (void) writeToCodedOutputStream:(PBCodedOutputStream*) output; +- (PBEnumOptionsBuilder*) builder; ++ (PBEnumOptionsBuilder*) builder; ++ (PBEnumOptionsBuilder*) builderWithPrototype:(PBEnumOptions*) prototype; +- (PBEnumOptionsBuilder*) toBuilder; + ++ (PBEnumOptions*) parseFromData:(NSData*) data; ++ (PBEnumOptions*) parseFromData:(NSData*) data extensionRegistry:(PBExtensionRegistry*) extensionRegistry; ++ (PBEnumOptions*) parseFromInputStream:(NSInputStream*) input; ++ (PBEnumOptions*) parseFromInputStream:(NSInputStream*) input extensionRegistry:(PBExtensionRegistry*) extensionRegistry; ++ (PBEnumOptions*) parseFromCodedInputStream:(PBCodedInputStream*) input; ++ (PBEnumOptions*) parseFromCodedInputStream:(PBCodedInputStream*) input extensionRegistry:(PBExtensionRegistry*) extensionRegistry; +@end + +@interface PBEnumOptionsBuilder : PBExtendableMessageBuilder { +@private + PBEnumOptions* result; +} + +- (PBEnumOptions*) defaultInstance; + +- (PBEnumOptionsBuilder*) clear; +- (PBEnumOptionsBuilder*) clone; + +- (PBEnumOptions*) build; +- (PBEnumOptions*) buildPartial; + +- (PBEnumOptionsBuilder*) mergeFrom:(PBEnumOptions*) other; +- (PBEnumOptionsBuilder*) mergeFromCodedInputStream:(PBCodedInputStream*) input; +- (PBEnumOptionsBuilder*) mergeFromCodedInputStream:(PBCodedInputStream*) input extensionRegistry:(PBExtensionRegistry*) extensionRegistry; + +- (BOOL) hasAllowAlias; +- (BOOL) allowAlias; +- (PBEnumOptionsBuilder*) setAllowAlias:(BOOL) value; +- (PBEnumOptionsBuilder*) clearAllowAlias; + +- (BOOL) hasDeprecated; +- (BOOL) deprecated; +- (PBEnumOptionsBuilder*) setDeprecated:(BOOL) value; +- (PBEnumOptionsBuilder*) clearDeprecated; + +- (NSMutableArray *)uninterpretedOption; +- (PBUninterpretedOption*)uninterpretedOptionAtIndex:(NSUInteger)index; +- (PBEnumOptionsBuilder *)addUninterpretedOption:(PBUninterpretedOption*)value; +- (PBEnumOptionsBuilder *)setUninterpretedOptionArray:(NSArray *)array; +- (PBEnumOptionsBuilder *)clearUninterpretedOption; +@end + +@interface PBEnumValueOptions : PBExtendableMessage { +@private + BOOL hasDeprecated_:1; + BOOL deprecated_:1; + NSMutableArray * uninterpretedOptionArray; +} +- (BOOL) hasDeprecated; +- (BOOL) deprecated; +@property (readonly, strong) NSArray * uninterpretedOption; +- (PBUninterpretedOption*)uninterpretedOptionAtIndex:(NSUInteger)index; + ++ (PBEnumValueOptions*) defaultInstance; +- (PBEnumValueOptions*) defaultInstance; + +- (BOOL) isInitialized; +- (void) writeToCodedOutputStream:(PBCodedOutputStream*) output; +- (PBEnumValueOptionsBuilder*) builder; ++ (PBEnumValueOptionsBuilder*) builder; ++ (PBEnumValueOptionsBuilder*) builderWithPrototype:(PBEnumValueOptions*) prototype; +- (PBEnumValueOptionsBuilder*) toBuilder; + ++ (PBEnumValueOptions*) parseFromData:(NSData*) data; ++ (PBEnumValueOptions*) parseFromData:(NSData*) data extensionRegistry:(PBExtensionRegistry*) extensionRegistry; ++ (PBEnumValueOptions*) parseFromInputStream:(NSInputStream*) input; ++ (PBEnumValueOptions*) parseFromInputStream:(NSInputStream*) input extensionRegistry:(PBExtensionRegistry*) extensionRegistry; ++ (PBEnumValueOptions*) parseFromCodedInputStream:(PBCodedInputStream*) input; ++ (PBEnumValueOptions*) parseFromCodedInputStream:(PBCodedInputStream*) input extensionRegistry:(PBExtensionRegistry*) extensionRegistry; +@end + +@interface PBEnumValueOptionsBuilder : PBExtendableMessageBuilder { +@private + PBEnumValueOptions* result; +} + +- (PBEnumValueOptions*) defaultInstance; + +- (PBEnumValueOptionsBuilder*) clear; +- (PBEnumValueOptionsBuilder*) clone; + +- (PBEnumValueOptions*) build; +- (PBEnumValueOptions*) buildPartial; + +- (PBEnumValueOptionsBuilder*) mergeFrom:(PBEnumValueOptions*) other; +- (PBEnumValueOptionsBuilder*) mergeFromCodedInputStream:(PBCodedInputStream*) input; +- (PBEnumValueOptionsBuilder*) mergeFromCodedInputStream:(PBCodedInputStream*) input extensionRegistry:(PBExtensionRegistry*) extensionRegistry; + +- (BOOL) hasDeprecated; +- (BOOL) deprecated; +- (PBEnumValueOptionsBuilder*) setDeprecated:(BOOL) value; +- (PBEnumValueOptionsBuilder*) clearDeprecated; + +- (NSMutableArray *)uninterpretedOption; +- (PBUninterpretedOption*)uninterpretedOptionAtIndex:(NSUInteger)index; +- (PBEnumValueOptionsBuilder *)addUninterpretedOption:(PBUninterpretedOption*)value; +- (PBEnumValueOptionsBuilder *)setUninterpretedOptionArray:(NSArray *)array; +- (PBEnumValueOptionsBuilder *)clearUninterpretedOption; +@end + +@interface PBServiceOptions : PBExtendableMessage { +@private + BOOL hasDeprecated_:1; + BOOL deprecated_:1; + NSMutableArray * uninterpretedOptionArray; +} +- (BOOL) hasDeprecated; +- (BOOL) deprecated; +@property (readonly, strong) NSArray * uninterpretedOption; +- (PBUninterpretedOption*)uninterpretedOptionAtIndex:(NSUInteger)index; + ++ (PBServiceOptions*) defaultInstance; +- (PBServiceOptions*) defaultInstance; + +- (BOOL) isInitialized; +- (void) writeToCodedOutputStream:(PBCodedOutputStream*) output; +- (PBServiceOptionsBuilder*) builder; ++ (PBServiceOptionsBuilder*) builder; ++ (PBServiceOptionsBuilder*) builderWithPrototype:(PBServiceOptions*) prototype; +- (PBServiceOptionsBuilder*) toBuilder; + ++ (PBServiceOptions*) parseFromData:(NSData*) data; ++ (PBServiceOptions*) parseFromData:(NSData*) data extensionRegistry:(PBExtensionRegistry*) extensionRegistry; ++ (PBServiceOptions*) parseFromInputStream:(NSInputStream*) input; ++ (PBServiceOptions*) parseFromInputStream:(NSInputStream*) input extensionRegistry:(PBExtensionRegistry*) extensionRegistry; ++ (PBServiceOptions*) parseFromCodedInputStream:(PBCodedInputStream*) input; ++ (PBServiceOptions*) parseFromCodedInputStream:(PBCodedInputStream*) input extensionRegistry:(PBExtensionRegistry*) extensionRegistry; +@end + +@interface PBServiceOptionsBuilder : PBExtendableMessageBuilder { +@private + PBServiceOptions* result; +} + +- (PBServiceOptions*) defaultInstance; + +- (PBServiceOptionsBuilder*) clear; +- (PBServiceOptionsBuilder*) clone; + +- (PBServiceOptions*) build; +- (PBServiceOptions*) buildPartial; + +- (PBServiceOptionsBuilder*) mergeFrom:(PBServiceOptions*) other; +- (PBServiceOptionsBuilder*) mergeFromCodedInputStream:(PBCodedInputStream*) input; +- (PBServiceOptionsBuilder*) mergeFromCodedInputStream:(PBCodedInputStream*) input extensionRegistry:(PBExtensionRegistry*) extensionRegistry; + +- (BOOL) hasDeprecated; +- (BOOL) deprecated; +- (PBServiceOptionsBuilder*) setDeprecated:(BOOL) value; +- (PBServiceOptionsBuilder*) clearDeprecated; + +- (NSMutableArray *)uninterpretedOption; +- (PBUninterpretedOption*)uninterpretedOptionAtIndex:(NSUInteger)index; +- (PBServiceOptionsBuilder *)addUninterpretedOption:(PBUninterpretedOption*)value; +- (PBServiceOptionsBuilder *)setUninterpretedOptionArray:(NSArray *)array; +- (PBServiceOptionsBuilder *)clearUninterpretedOption; +@end + +@interface PBMethodOptions : PBExtendableMessage { +@private + BOOL hasDeprecated_:1; + BOOL deprecated_:1; + NSMutableArray * uninterpretedOptionArray; +} +- (BOOL) hasDeprecated; +- (BOOL) deprecated; +@property (readonly, strong) NSArray * uninterpretedOption; +- (PBUninterpretedOption*)uninterpretedOptionAtIndex:(NSUInteger)index; + ++ (PBMethodOptions*) defaultInstance; +- (PBMethodOptions*) defaultInstance; + +- (BOOL) isInitialized; +- (void) writeToCodedOutputStream:(PBCodedOutputStream*) output; +- (PBMethodOptionsBuilder*) builder; ++ (PBMethodOptionsBuilder*) builder; ++ (PBMethodOptionsBuilder*) builderWithPrototype:(PBMethodOptions*) prototype; +- (PBMethodOptionsBuilder*) toBuilder; + ++ (PBMethodOptions*) parseFromData:(NSData*) data; ++ (PBMethodOptions*) parseFromData:(NSData*) data extensionRegistry:(PBExtensionRegistry*) extensionRegistry; ++ (PBMethodOptions*) parseFromInputStream:(NSInputStream*) input; ++ (PBMethodOptions*) parseFromInputStream:(NSInputStream*) input extensionRegistry:(PBExtensionRegistry*) extensionRegistry; ++ (PBMethodOptions*) parseFromCodedInputStream:(PBCodedInputStream*) input; ++ (PBMethodOptions*) parseFromCodedInputStream:(PBCodedInputStream*) input extensionRegistry:(PBExtensionRegistry*) extensionRegistry; +@end + +@interface PBMethodOptionsBuilder : PBExtendableMessageBuilder { +@private + PBMethodOptions* result; +} + +- (PBMethodOptions*) defaultInstance; + +- (PBMethodOptionsBuilder*) clear; +- (PBMethodOptionsBuilder*) clone; + +- (PBMethodOptions*) build; +- (PBMethodOptions*) buildPartial; + +- (PBMethodOptionsBuilder*) mergeFrom:(PBMethodOptions*) other; +- (PBMethodOptionsBuilder*) mergeFromCodedInputStream:(PBCodedInputStream*) input; +- (PBMethodOptionsBuilder*) mergeFromCodedInputStream:(PBCodedInputStream*) input extensionRegistry:(PBExtensionRegistry*) extensionRegistry; + +- (BOOL) hasDeprecated; +- (BOOL) deprecated; +- (PBMethodOptionsBuilder*) setDeprecated:(BOOL) value; +- (PBMethodOptionsBuilder*) clearDeprecated; + +- (NSMutableArray *)uninterpretedOption; +- (PBUninterpretedOption*)uninterpretedOptionAtIndex:(NSUInteger)index; +- (PBMethodOptionsBuilder *)addUninterpretedOption:(PBUninterpretedOption*)value; +- (PBMethodOptionsBuilder *)setUninterpretedOptionArray:(NSArray *)array; +- (PBMethodOptionsBuilder *)clearUninterpretedOption; +@end + +@interface PBUninterpretedOption : PBGeneratedMessage { +@private + BOOL hasDoubleValue_:1; + BOOL hasNegativeIntValue_:1; + BOOL hasPositiveIntValue_:1; + BOOL hasIdentifierValue_:1; + BOOL hasAggregateValue_:1; + BOOL hasStringValue_:1; + Float64 doubleValue; + SInt64 negativeIntValue; + UInt64 positiveIntValue; + NSString* identifierValue; + NSString* aggregateValue; + NSData* stringValue; + NSMutableArray * nameArray; +} +- (BOOL) hasIdentifierValue; +- (BOOL) hasPositiveIntValue; +- (BOOL) hasNegativeIntValue; +- (BOOL) hasDoubleValue; +- (BOOL) hasStringValue; +- (BOOL) hasAggregateValue; +@property (readonly, strong) NSArray * name; +@property (readonly, strong) NSString* identifierValue; +@property (readonly) UInt64 positiveIntValue; +@property (readonly) SInt64 negativeIntValue; +@property (readonly) Float64 doubleValue; +@property (readonly, strong) NSData* stringValue; +@property (readonly, strong) NSString* aggregateValue; +- (PBUninterpretedOptionNamePart*)nameAtIndex:(NSUInteger)index; + ++ (PBUninterpretedOption*) defaultInstance; +- (PBUninterpretedOption*) defaultInstance; + +- (BOOL) isInitialized; +- (void) writeToCodedOutputStream:(PBCodedOutputStream*) output; +- (PBUninterpretedOptionBuilder*) builder; ++ (PBUninterpretedOptionBuilder*) builder; ++ (PBUninterpretedOptionBuilder*) builderWithPrototype:(PBUninterpretedOption*) prototype; +- (PBUninterpretedOptionBuilder*) toBuilder; + ++ (PBUninterpretedOption*) parseFromData:(NSData*) data; ++ (PBUninterpretedOption*) parseFromData:(NSData*) data extensionRegistry:(PBExtensionRegistry*) extensionRegistry; ++ (PBUninterpretedOption*) parseFromInputStream:(NSInputStream*) input; ++ (PBUninterpretedOption*) parseFromInputStream:(NSInputStream*) input extensionRegistry:(PBExtensionRegistry*) extensionRegistry; ++ (PBUninterpretedOption*) parseFromCodedInputStream:(PBCodedInputStream*) input; ++ (PBUninterpretedOption*) parseFromCodedInputStream:(PBCodedInputStream*) input extensionRegistry:(PBExtensionRegistry*) extensionRegistry; +@end + +@interface PBUninterpretedOptionNamePart : PBGeneratedMessage { +@private + BOOL hasIsExtension_:1; + BOOL hasNamePart_:1; + BOOL isExtension_:1; + NSString* namePart; +} +- (BOOL) hasNamePart; +- (BOOL) hasIsExtension; +@property (readonly, strong) NSString* namePart; +- (BOOL) isExtension; + ++ (PBUninterpretedOptionNamePart*) defaultInstance; +- (PBUninterpretedOptionNamePart*) defaultInstance; + +- (BOOL) isInitialized; +- (void) writeToCodedOutputStream:(PBCodedOutputStream*) output; +- (PBUninterpretedOptionNamePartBuilder*) builder; ++ (PBUninterpretedOptionNamePartBuilder*) builder; ++ (PBUninterpretedOptionNamePartBuilder*) builderWithPrototype:(PBUninterpretedOptionNamePart*) prototype; +- (PBUninterpretedOptionNamePartBuilder*) toBuilder; + ++ (PBUninterpretedOptionNamePart*) parseFromData:(NSData*) data; ++ (PBUninterpretedOptionNamePart*) parseFromData:(NSData*) data extensionRegistry:(PBExtensionRegistry*) extensionRegistry; ++ (PBUninterpretedOptionNamePart*) parseFromInputStream:(NSInputStream*) input; ++ (PBUninterpretedOptionNamePart*) parseFromInputStream:(NSInputStream*) input extensionRegistry:(PBExtensionRegistry*) extensionRegistry; ++ (PBUninterpretedOptionNamePart*) parseFromCodedInputStream:(PBCodedInputStream*) input; ++ (PBUninterpretedOptionNamePart*) parseFromCodedInputStream:(PBCodedInputStream*) input extensionRegistry:(PBExtensionRegistry*) extensionRegistry; +@end + +@interface PBUninterpretedOptionNamePartBuilder : PBGeneratedMessageBuilder { +@private + PBUninterpretedOptionNamePart* result; +} + +- (PBUninterpretedOptionNamePart*) defaultInstance; + +- (PBUninterpretedOptionNamePartBuilder*) clear; +- (PBUninterpretedOptionNamePartBuilder*) clone; + +- (PBUninterpretedOptionNamePart*) build; +- (PBUninterpretedOptionNamePart*) buildPartial; + +- (PBUninterpretedOptionNamePartBuilder*) mergeFrom:(PBUninterpretedOptionNamePart*) other; +- (PBUninterpretedOptionNamePartBuilder*) mergeFromCodedInputStream:(PBCodedInputStream*) input; +- (PBUninterpretedOptionNamePartBuilder*) mergeFromCodedInputStream:(PBCodedInputStream*) input extensionRegistry:(PBExtensionRegistry*) extensionRegistry; + +- (BOOL) hasNamePart; +- (NSString*) namePart; +- (PBUninterpretedOptionNamePartBuilder*) setNamePart:(NSString*) value; +- (PBUninterpretedOptionNamePartBuilder*) clearNamePart; + +- (BOOL) hasIsExtension; +- (BOOL) isExtension; +- (PBUninterpretedOptionNamePartBuilder*) setIsExtension:(BOOL) value; +- (PBUninterpretedOptionNamePartBuilder*) clearIsExtension; +@end + +@interface PBUninterpretedOptionBuilder : PBGeneratedMessageBuilder { +@private + PBUninterpretedOption* result; +} + +- (PBUninterpretedOption*) defaultInstance; + +- (PBUninterpretedOptionBuilder*) clear; +- (PBUninterpretedOptionBuilder*) clone; + +- (PBUninterpretedOption*) build; +- (PBUninterpretedOption*) buildPartial; + +- (PBUninterpretedOptionBuilder*) mergeFrom:(PBUninterpretedOption*) other; +- (PBUninterpretedOptionBuilder*) mergeFromCodedInputStream:(PBCodedInputStream*) input; +- (PBUninterpretedOptionBuilder*) mergeFromCodedInputStream:(PBCodedInputStream*) input extensionRegistry:(PBExtensionRegistry*) extensionRegistry; + +- (NSMutableArray *)name; +- (PBUninterpretedOptionNamePart*)nameAtIndex:(NSUInteger)index; +- (PBUninterpretedOptionBuilder *)addName:(PBUninterpretedOptionNamePart*)value; +- (PBUninterpretedOptionBuilder *)setNameArray:(NSArray *)array; +- (PBUninterpretedOptionBuilder *)clearName; + +- (BOOL) hasIdentifierValue; +- (NSString*) identifierValue; +- (PBUninterpretedOptionBuilder*) setIdentifierValue:(NSString*) value; +- (PBUninterpretedOptionBuilder*) clearIdentifierValue; + +- (BOOL) hasPositiveIntValue; +- (UInt64) positiveIntValue; +- (PBUninterpretedOptionBuilder*) setPositiveIntValue:(UInt64) value; +- (PBUninterpretedOptionBuilder*) clearPositiveIntValue; + +- (BOOL) hasNegativeIntValue; +- (SInt64) negativeIntValue; +- (PBUninterpretedOptionBuilder*) setNegativeIntValue:(SInt64) value; +- (PBUninterpretedOptionBuilder*) clearNegativeIntValue; + +- (BOOL) hasDoubleValue; +- (Float64) doubleValue; +- (PBUninterpretedOptionBuilder*) setDoubleValue:(Float64) value; +- (PBUninterpretedOptionBuilder*) clearDoubleValue; + +- (BOOL) hasStringValue; +- (NSData*) stringValue; +- (PBUninterpretedOptionBuilder*) setStringValue:(NSData*) value; +- (PBUninterpretedOptionBuilder*) clearStringValue; + +- (BOOL) hasAggregateValue; +- (NSString*) aggregateValue; +- (PBUninterpretedOptionBuilder*) setAggregateValue:(NSString*) value; +- (PBUninterpretedOptionBuilder*) clearAggregateValue; +@end + +@interface PBSourceCodeInfo : PBGeneratedMessage { +@private + NSMutableArray * locationArray; +} +@property (readonly, strong) NSArray * location; +- (PBSourceCodeInfoLocation*)locationAtIndex:(NSUInteger)index; + ++ (PBSourceCodeInfo*) defaultInstance; +- (PBSourceCodeInfo*) defaultInstance; + +- (BOOL) isInitialized; +- (void) writeToCodedOutputStream:(PBCodedOutputStream*) output; +- (PBSourceCodeInfoBuilder*) builder; ++ (PBSourceCodeInfoBuilder*) builder; ++ (PBSourceCodeInfoBuilder*) builderWithPrototype:(PBSourceCodeInfo*) prototype; +- (PBSourceCodeInfoBuilder*) toBuilder; + ++ (PBSourceCodeInfo*) parseFromData:(NSData*) data; ++ (PBSourceCodeInfo*) parseFromData:(NSData*) data extensionRegistry:(PBExtensionRegistry*) extensionRegistry; ++ (PBSourceCodeInfo*) parseFromInputStream:(NSInputStream*) input; ++ (PBSourceCodeInfo*) parseFromInputStream:(NSInputStream*) input extensionRegistry:(PBExtensionRegistry*) extensionRegistry; ++ (PBSourceCodeInfo*) parseFromCodedInputStream:(PBCodedInputStream*) input; ++ (PBSourceCodeInfo*) parseFromCodedInputStream:(PBCodedInputStream*) input extensionRegistry:(PBExtensionRegistry*) extensionRegistry; +@end + +@interface PBSourceCodeInfoLocation : PBGeneratedMessage { +@private + BOOL hasLeadingComments_:1; + BOOL hasTrailingComments_:1; + NSString* leadingComments; + NSString* trailingComments; + PBAppendableArray * pathArray; + SInt32 pathMemoizedSerializedSize; + PBAppendableArray * spanArray; + SInt32 spanMemoizedSerializedSize; +} +- (BOOL) hasLeadingComments; +- (BOOL) hasTrailingComments; +@property (readonly, strong) PBArray * path; +@property (readonly, strong) PBArray * span; +@property (readonly, strong) NSString* leadingComments; +@property (readonly, strong) NSString* trailingComments; +- (SInt32)pathAtIndex:(NSUInteger)index; +- (SInt32)spanAtIndex:(NSUInteger)index; + ++ (PBSourceCodeInfoLocation*) defaultInstance; +- (PBSourceCodeInfoLocation*) defaultInstance; + +- (BOOL) isInitialized; +- (void) writeToCodedOutputStream:(PBCodedOutputStream*) output; +- (PBSourceCodeInfoLocationBuilder*) builder; ++ (PBSourceCodeInfoLocationBuilder*) builder; ++ (PBSourceCodeInfoLocationBuilder*) builderWithPrototype:(PBSourceCodeInfoLocation*) prototype; +- (PBSourceCodeInfoLocationBuilder*) toBuilder; + ++ (PBSourceCodeInfoLocation*) parseFromData:(NSData*) data; ++ (PBSourceCodeInfoLocation*) parseFromData:(NSData*) data extensionRegistry:(PBExtensionRegistry*) extensionRegistry; ++ (PBSourceCodeInfoLocation*) parseFromInputStream:(NSInputStream*) input; ++ (PBSourceCodeInfoLocation*) parseFromInputStream:(NSInputStream*) input extensionRegistry:(PBExtensionRegistry*) extensionRegistry; ++ (PBSourceCodeInfoLocation*) parseFromCodedInputStream:(PBCodedInputStream*) input; ++ (PBSourceCodeInfoLocation*) parseFromCodedInputStream:(PBCodedInputStream*) input extensionRegistry:(PBExtensionRegistry*) extensionRegistry; +@end + +@interface PBSourceCodeInfoLocationBuilder : PBGeneratedMessageBuilder { +@private + PBSourceCodeInfoLocation* result; +} + +- (PBSourceCodeInfoLocation*) defaultInstance; + +- (PBSourceCodeInfoLocationBuilder*) clear; +- (PBSourceCodeInfoLocationBuilder*) clone; + +- (PBSourceCodeInfoLocation*) build; +- (PBSourceCodeInfoLocation*) buildPartial; + +- (PBSourceCodeInfoLocationBuilder*) mergeFrom:(PBSourceCodeInfoLocation*) other; +- (PBSourceCodeInfoLocationBuilder*) mergeFromCodedInputStream:(PBCodedInputStream*) input; +- (PBSourceCodeInfoLocationBuilder*) mergeFromCodedInputStream:(PBCodedInputStream*) input extensionRegistry:(PBExtensionRegistry*) extensionRegistry; + +- (PBAppendableArray *)path; +- (SInt32)pathAtIndex:(NSUInteger)index; +- (PBSourceCodeInfoLocationBuilder *)addPath:(SInt32)value; +- (PBSourceCodeInfoLocationBuilder *)setPathArray:(NSArray *)array; +- (PBSourceCodeInfoLocationBuilder *)setPathValues:(const SInt32 *)values count:(NSUInteger)count; +- (PBSourceCodeInfoLocationBuilder *)clearPath; + +- (PBAppendableArray *)span; +- (SInt32)spanAtIndex:(NSUInteger)index; +- (PBSourceCodeInfoLocationBuilder *)addSpan:(SInt32)value; +- (PBSourceCodeInfoLocationBuilder *)setSpanArray:(NSArray *)array; +- (PBSourceCodeInfoLocationBuilder *)setSpanValues:(const SInt32 *)values count:(NSUInteger)count; +- (PBSourceCodeInfoLocationBuilder *)clearSpan; + +- (BOOL) hasLeadingComments; +- (NSString*) leadingComments; +- (PBSourceCodeInfoLocationBuilder*) setLeadingComments:(NSString*) value; +- (PBSourceCodeInfoLocationBuilder*) clearLeadingComments; + +- (BOOL) hasTrailingComments; +- (NSString*) trailingComments; +- (PBSourceCodeInfoLocationBuilder*) setTrailingComments:(NSString*) value; +- (PBSourceCodeInfoLocationBuilder*) clearTrailingComments; +@end + +@interface PBSourceCodeInfoBuilder : PBGeneratedMessageBuilder { +@private + PBSourceCodeInfo* result; +} + +- (PBSourceCodeInfo*) defaultInstance; + +- (PBSourceCodeInfoBuilder*) clear; +- (PBSourceCodeInfoBuilder*) clone; + +- (PBSourceCodeInfo*) build; +- (PBSourceCodeInfo*) buildPartial; + +- (PBSourceCodeInfoBuilder*) mergeFrom:(PBSourceCodeInfo*) other; +- (PBSourceCodeInfoBuilder*) mergeFromCodedInputStream:(PBCodedInputStream*) input; +- (PBSourceCodeInfoBuilder*) mergeFromCodedInputStream:(PBCodedInputStream*) input extensionRegistry:(PBExtensionRegistry*) extensionRegistry; + +- (NSMutableArray *)location; +- (PBSourceCodeInfoLocation*)locationAtIndex:(NSUInteger)index; +- (PBSourceCodeInfoBuilder *)addLocation:(PBSourceCodeInfoLocation*)value; +- (PBSourceCodeInfoBuilder *)setLocationArray:(NSArray *)array; +- (PBSourceCodeInfoBuilder *)clearLocation; +@end + + +// @@protoc_insertion_point(global_scope) diff --git a/ios/Pods/ProtocolBuffers/src/runtime/Classes/Descriptor.pb.m b/ios/Pods/ProtocolBuffers/src/runtime/Classes/Descriptor.pb.m new file mode 100644 index 000000000..872bbbc0a --- /dev/null +++ b/ios/Pods/ProtocolBuffers/src/runtime/Classes/Descriptor.pb.m @@ -0,0 +1,8515 @@ +// Generated by the protocol buffer compiler. DO NOT EDIT! + + +#import "Descriptor.pb.h" + +// @@protoc_insertion_point(imports) + +@implementation PBDescriptorRoot +static PBExtensionRegistry* extensionRegistry = nil; ++ (PBExtensionRegistry*) extensionRegistry { + return extensionRegistry; +} + ++ (void) initialize { + if (self == [PBDescriptorRoot class]) { + PBMutableExtensionRegistry* registry = [PBMutableExtensionRegistry registry]; + [self registerAllExtensions:registry]; + extensionRegistry = registry; + } +} ++ (void) registerAllExtensions:(PBMutableExtensionRegistry*) registry { +} +@end + +@interface PBFileDescriptorSet () +@property (strong) NSMutableArray * fileArray; +@end + +@implementation PBFileDescriptorSet + +@synthesize fileArray; +@dynamic file; +- (id) init { + if ((self = [super init])) { + } + return self; +} +static PBFileDescriptorSet* defaultPBFileDescriptorSetInstance = nil; ++ (void) initialize { + if (self == [PBFileDescriptorSet class]) { + defaultPBFileDescriptorSetInstance = [[PBFileDescriptorSet alloc] init]; + } +} ++ (PBFileDescriptorSet*) defaultInstance { + return defaultPBFileDescriptorSetInstance; +} +- (PBFileDescriptorSet*) defaultInstance { + return defaultPBFileDescriptorSetInstance; +} +- (NSArray *)file { + return fileArray; +} +- (PBFileDescriptorProto*)fileAtIndex:(NSUInteger)index { + return [fileArray objectAtIndex:index]; +} +- (BOOL) isInitialized { + __block BOOL isInitfile = YES; + [self.file enumerateObjectsUsingBlock:^(PBFileDescriptorProto *element, NSUInteger idx, BOOL *stop) { + if (!element.isInitialized) { + isInitfile = NO; + *stop = YES; + } + }]; + if (!isInitfile) return isInitfile; + return YES; +} +- (void) writeToCodedOutputStream:(PBCodedOutputStream*) output { + [self.fileArray enumerateObjectsUsingBlock:^(PBFileDescriptorProto *element, NSUInteger idx, BOOL *stop) { + [output writeMessage:1 value:element]; + }]; + [self.unknownFields writeToCodedOutputStream:output]; +} +- (SInt32) serializedSize { + __block SInt32 size_ = memoizedSerializedSize; + if (size_ != -1) { + return size_; + } + + size_ = 0; + [self.fileArray enumerateObjectsUsingBlock:^(PBFileDescriptorProto *element, NSUInteger idx, BOOL *stop) { + size_ += computeMessageSize(1, element); + }]; + size_ += self.unknownFields.serializedSize; + memoizedSerializedSize = size_; + return size_; +} ++ (PBFileDescriptorSet*) parseFromData:(NSData*) data { + return (PBFileDescriptorSet*)[[[PBFileDescriptorSet builder] mergeFromData:data] build]; +} ++ (PBFileDescriptorSet*) parseFromData:(NSData*) data extensionRegistry:(PBExtensionRegistry*) extensionRegistry { + return (PBFileDescriptorSet*)[[[PBFileDescriptorSet builder] mergeFromData:data extensionRegistry:extensionRegistry] build]; +} ++ (PBFileDescriptorSet*) parseFromInputStream:(NSInputStream*) input { + return (PBFileDescriptorSet*)[[[PBFileDescriptorSet builder] mergeFromInputStream:input] build]; +} ++ (PBFileDescriptorSet*) parseFromInputStream:(NSInputStream*) input extensionRegistry:(PBExtensionRegistry*) extensionRegistry { + return (PBFileDescriptorSet*)[[[PBFileDescriptorSet builder] mergeFromInputStream:input extensionRegistry:extensionRegistry] build]; +} ++ (PBFileDescriptorSet*) parseFromCodedInputStream:(PBCodedInputStream*) input { + return (PBFileDescriptorSet*)[[[PBFileDescriptorSet builder] mergeFromCodedInputStream:input] build]; +} ++ (PBFileDescriptorSet*) parseFromCodedInputStream:(PBCodedInputStream*) input extensionRegistry:(PBExtensionRegistry*) extensionRegistry { + return (PBFileDescriptorSet*)[[[PBFileDescriptorSet builder] mergeFromCodedInputStream:input extensionRegistry:extensionRegistry] build]; +} ++ (PBFileDescriptorSetBuilder*) builder { + return [[PBFileDescriptorSetBuilder alloc] init]; +} ++ (PBFileDescriptorSetBuilder*) builderWithPrototype:(PBFileDescriptorSet*) prototype { + return [[PBFileDescriptorSet builder] mergeFrom:prototype]; +} +- (PBFileDescriptorSetBuilder*) builder { + return [PBFileDescriptorSet builder]; +} +- (PBFileDescriptorSetBuilder*) toBuilder { + return [PBFileDescriptorSet builderWithPrototype:self]; +} +- (void) writeDescriptionTo:(NSMutableString*) output withIndent:(NSString*) indent { + [self.fileArray enumerateObjectsUsingBlock:^(PBFileDescriptorProto *element, NSUInteger idx, BOOL *stop) { + [output appendFormat:@"%@%@ {\n", indent, @"file"]; + [element writeDescriptionTo:output + withIndent:[NSString stringWithFormat:@"%@ ", indent]]; + [output appendFormat:@"%@}\n", indent]; + }]; + [self.unknownFields writeDescriptionTo:output withIndent:indent]; +} +- (BOOL) isEqual:(id)other { + if (other == self) { + return YES; + } + if (![other isKindOfClass:[PBFileDescriptorSet class]]) { + return NO; + } + PBFileDescriptorSet *otherMessage = other; + return + [self.fileArray isEqualToArray:otherMessage.fileArray] && + (self.unknownFields == otherMessage.unknownFields || (self.unknownFields != nil && [self.unknownFields isEqual:otherMessage.unknownFields])); +} +- (NSUInteger) hash { + __block NSUInteger hashCode = 7; + [self.fileArray enumerateObjectsUsingBlock:^(PBFileDescriptorProto *element, NSUInteger idx, BOOL *stop) { + hashCode = hashCode * 31 + [element hash]; + }]; + hashCode = hashCode * 31 + [self.unknownFields hash]; + return hashCode; +} +@end + +@interface PBFileDescriptorSetBuilder() +@property (strong) PBFileDescriptorSet* result; +@end + +@implementation PBFileDescriptorSetBuilder +@synthesize result; +- (id) init { + if ((self = [super init])) { + self.result = [[PBFileDescriptorSet alloc] init]; + } + return self; +} +- (PBGeneratedMessage*) internalGetResult { + return result; +} +- (PBFileDescriptorSetBuilder*) clear { + self.result = [[PBFileDescriptorSet alloc] init]; + return self; +} +- (PBFileDescriptorSetBuilder*) clone { + return [PBFileDescriptorSet builderWithPrototype:result]; +} +- (PBFileDescriptorSet*) defaultInstance { + return [PBFileDescriptorSet defaultInstance]; +} +- (PBFileDescriptorSet*) build { + [self checkInitialized]; + return [self buildPartial]; +} +- (PBFileDescriptorSet*) buildPartial { + PBFileDescriptorSet* returnMe = result; + self.result = nil; + return returnMe; +} +- (PBFileDescriptorSetBuilder*) mergeFrom:(PBFileDescriptorSet*) other { + if (other == [PBFileDescriptorSet defaultInstance]) { + return self; + } + if (other.fileArray.count > 0) { + if (result.fileArray == nil) { + result.fileArray = [[NSMutableArray alloc] initWithArray:other.fileArray]; + } else { + [result.fileArray addObjectsFromArray:other.fileArray]; + } + } + [self mergeUnknownFields:other.unknownFields]; + return self; +} +- (PBFileDescriptorSetBuilder*) mergeFromCodedInputStream:(PBCodedInputStream*) input { + return [self mergeFromCodedInputStream:input extensionRegistry:[PBExtensionRegistry emptyRegistry]]; +} +- (PBFileDescriptorSetBuilder*) mergeFromCodedInputStream:(PBCodedInputStream*) input extensionRegistry:(PBExtensionRegistry*) extensionRegistry { + PBUnknownFieldSetBuilder* unknownFields = [PBUnknownFieldSet builderWithUnknownFields:self.unknownFields]; + while (YES) { + SInt32 tag = [input readTag]; + switch (tag) { + case 0: + [self setUnknownFields:[unknownFields build]]; + return self; + default: { + if (![self parseUnknownField:input unknownFields:unknownFields extensionRegistry:extensionRegistry tag:tag]) { + [self setUnknownFields:[unknownFields build]]; + return self; + } + break; + } + case 10: { + PBFileDescriptorProtoBuilder* subBuilder = [PBFileDescriptorProto builder]; + [input readMessage:subBuilder extensionRegistry:extensionRegistry]; + [self addFile:[subBuilder buildPartial]]; + break; + } + } + } +} +- (NSMutableArray *)file { + return result.fileArray; +} +- (PBFileDescriptorProto*)fileAtIndex:(NSUInteger)index { + return [result fileAtIndex:index]; +} +- (PBFileDescriptorSetBuilder *)addFile:(PBFileDescriptorProto*)value { + if (result.fileArray == nil) { + result.fileArray = [[NSMutableArray alloc]init]; + } + [result.fileArray addObject:value]; + return self; +} +- (PBFileDescriptorSetBuilder *)setFileArray:(NSArray *)array { + result.fileArray = [[NSMutableArray alloc]initWithArray:array]; + return self; +} +- (PBFileDescriptorSetBuilder *)clearFile { + result.fileArray = nil; + return self; +} +@end + +@interface PBFileDescriptorProto () +@property (strong) NSString* name; +@property (strong) NSString* package; +@property (strong) NSMutableArray * dependencyArray; +@property (strong) PBAppendableArray * publicDependencyArray; +@property (strong) PBAppendableArray * weakDependencyArray; +@property (strong) NSMutableArray * messageTypeArray; +@property (strong) NSMutableArray * enumTypeArray; +@property (strong) NSMutableArray * serviceArray; +@property (strong) NSMutableArray * extensionArray; +@property (strong) PBFileOptions* options; +@property (strong) PBSourceCodeInfo* sourceCodeInfo; +@end + +@implementation PBFileDescriptorProto + +- (BOOL) hasName { + return !!hasName_; +} +- (void) setHasName:(BOOL) value_ { + hasName_ = !!value_; +} +@synthesize name; +- (BOOL) hasPackage { + return !!hasPackage_; +} +- (void) setHasPackage:(BOOL) value_ { + hasPackage_ = !!value_; +} +@synthesize package; +@synthesize dependencyArray; +@dynamic dependency; +@synthesize publicDependencyArray; +@dynamic publicDependency; +@synthesize weakDependencyArray; +@dynamic weakDependency; +@synthesize messageTypeArray; +@dynamic messageType; +@synthesize enumTypeArray; +@dynamic enumType; +@synthesize serviceArray; +@dynamic service; +@synthesize extensionArray; +@dynamic extension; +- (BOOL) hasOptions { + return !!hasOptions_; +} +- (void) setHasOptions:(BOOL) value_ { + hasOptions_ = !!value_; +} +@synthesize options; +- (BOOL) hasSourceCodeInfo { + return !!hasSourceCodeInfo_; +} +- (void) setHasSourceCodeInfo:(BOOL) value_ { + hasSourceCodeInfo_ = !!value_; +} +@synthesize sourceCodeInfo; +- (id) init { + if ((self = [super init])) { + self.name = @""; + self.package = @""; + self.options = [PBFileOptions defaultInstance]; + self.sourceCodeInfo = [PBSourceCodeInfo defaultInstance]; + } + return self; +} +static PBFileDescriptorProto* defaultPBFileDescriptorProtoInstance = nil; ++ (void) initialize { + if (self == [PBFileDescriptorProto class]) { + defaultPBFileDescriptorProtoInstance = [[PBFileDescriptorProto alloc] init]; + } +} ++ (PBFileDescriptorProto*) defaultInstance { + return defaultPBFileDescriptorProtoInstance; +} +- (PBFileDescriptorProto*) defaultInstance { + return defaultPBFileDescriptorProtoInstance; +} +- (NSArray *)dependency { + return dependencyArray; +} +- (NSString*)dependencyAtIndex:(NSUInteger)index { + return [dependencyArray objectAtIndex:index]; +} +- (PBArray *)publicDependency { + return publicDependencyArray; +} +- (SInt32)publicDependencyAtIndex:(NSUInteger)index { + return [publicDependencyArray int32AtIndex:index]; +} +- (PBArray *)weakDependency { + return weakDependencyArray; +} +- (SInt32)weakDependencyAtIndex:(NSUInteger)index { + return [weakDependencyArray int32AtIndex:index]; +} +- (NSArray *)messageType { + return messageTypeArray; +} +- (PBDescriptorProto*)messageTypeAtIndex:(NSUInteger)index { + return [messageTypeArray objectAtIndex:index]; +} +- (NSArray *)enumType { + return enumTypeArray; +} +- (PBEnumDescriptorProto*)enumTypeAtIndex:(NSUInteger)index { + return [enumTypeArray objectAtIndex:index]; +} +- (NSArray *)service { + return serviceArray; +} +- (PBServiceDescriptorProto*)serviceAtIndex:(NSUInteger)index { + return [serviceArray objectAtIndex:index]; +} +- (NSArray *)extension { + return extensionArray; +} +- (PBFieldDescriptorProto*)extensionAtIndex:(NSUInteger)index { + return [extensionArray objectAtIndex:index]; +} +- (BOOL) isInitialized { + __block BOOL isInitmessageType = YES; + [self.messageType enumerateObjectsUsingBlock:^(PBDescriptorProto *element, NSUInteger idx, BOOL *stop) { + if (!element.isInitialized) { + isInitmessageType = NO; + *stop = YES; + } + }]; + if (!isInitmessageType) return isInitmessageType; + __block BOOL isInitenumType = YES; + [self.enumType enumerateObjectsUsingBlock:^(PBEnumDescriptorProto *element, NSUInteger idx, BOOL *stop) { + if (!element.isInitialized) { + isInitenumType = NO; + *stop = YES; + } + }]; + if (!isInitenumType) return isInitenumType; + __block BOOL isInitservice = YES; + [self.service enumerateObjectsUsingBlock:^(PBServiceDescriptorProto *element, NSUInteger idx, BOOL *stop) { + if (!element.isInitialized) { + isInitservice = NO; + *stop = YES; + } + }]; + if (!isInitservice) return isInitservice; + __block BOOL isInitextension = YES; + [self.extension enumerateObjectsUsingBlock:^(PBFieldDescriptorProto *element, NSUInteger idx, BOOL *stop) { + if (!element.isInitialized) { + isInitextension = NO; + *stop = YES; + } + }]; + if (!isInitextension) return isInitextension; + if (self.hasOptions) { + if (!self.options.isInitialized) { + return NO; + } + } + return YES; +} +- (void) writeToCodedOutputStream:(PBCodedOutputStream*) output { + if (self.hasName) { + [output writeString:1 value:self.name]; + } + if (self.hasPackage) { + [output writeString:2 value:self.package]; + } + [self.dependencyArray enumerateObjectsUsingBlock:^(NSString *element, NSUInteger idx, BOOL *stop) { + [output writeString:3 value:element]; + }]; + [self.messageTypeArray enumerateObjectsUsingBlock:^(PBDescriptorProto *element, NSUInteger idx, BOOL *stop) { + [output writeMessage:4 value:element]; + }]; + [self.enumTypeArray enumerateObjectsUsingBlock:^(PBEnumDescriptorProto *element, NSUInteger idx, BOOL *stop) { + [output writeMessage:5 value:element]; + }]; + [self.serviceArray enumerateObjectsUsingBlock:^(PBServiceDescriptorProto *element, NSUInteger idx, BOOL *stop) { + [output writeMessage:6 value:element]; + }]; + [self.extensionArray enumerateObjectsUsingBlock:^(PBFieldDescriptorProto *element, NSUInteger idx, BOOL *stop) { + [output writeMessage:7 value:element]; + }]; + if (self.hasOptions) { + [output writeMessage:8 value:self.options]; + } + if (self.hasSourceCodeInfo) { + [output writeMessage:9 value:self.sourceCodeInfo]; + } + const NSUInteger publicDependencyArrayCount = self.publicDependencyArray.count; + if (publicDependencyArrayCount > 0) { + const SInt32 *values = (const SInt32 *)self.publicDependencyArray.data; + for (NSUInteger i = 0; i < publicDependencyArrayCount; ++i) { + [output writeInt32:10 value:values[i]]; + } + } + const NSUInteger weakDependencyArrayCount = self.weakDependencyArray.count; + if (weakDependencyArrayCount > 0) { + const SInt32 *values = (const SInt32 *)self.weakDependencyArray.data; + for (NSUInteger i = 0; i < weakDependencyArrayCount; ++i) { + [output writeInt32:11 value:values[i]]; + } + } + [self.unknownFields writeToCodedOutputStream:output]; +} +- (SInt32) serializedSize { + __block SInt32 size_ = memoizedSerializedSize; + if (size_ != -1) { + return size_; + } + + size_ = 0; + if (self.hasName) { + size_ += computeStringSize(1, self.name); + } + if (self.hasPackage) { + size_ += computeStringSize(2, self.package); + } + { + __block SInt32 dataSize = 0; + const NSUInteger count = self.dependencyArray.count; + [self.dependencyArray enumerateObjectsUsingBlock:^(NSString *element, NSUInteger idx, BOOL *stop) { + dataSize += computeStringSizeNoTag(element); + }]; + size_ += dataSize; + size_ += (SInt32)(1 * count); + } + [self.messageTypeArray enumerateObjectsUsingBlock:^(PBDescriptorProto *element, NSUInteger idx, BOOL *stop) { + size_ += computeMessageSize(4, element); + }]; + [self.enumTypeArray enumerateObjectsUsingBlock:^(PBEnumDescriptorProto *element, NSUInteger idx, BOOL *stop) { + size_ += computeMessageSize(5, element); + }]; + [self.serviceArray enumerateObjectsUsingBlock:^(PBServiceDescriptorProto *element, NSUInteger idx, BOOL *stop) { + size_ += computeMessageSize(6, element); + }]; + [self.extensionArray enumerateObjectsUsingBlock:^(PBFieldDescriptorProto *element, NSUInteger idx, BOOL *stop) { + size_ += computeMessageSize(7, element); + }]; + if (self.hasOptions) { + size_ += computeMessageSize(8, self.options); + } + if (self.hasSourceCodeInfo) { + size_ += computeMessageSize(9, self.sourceCodeInfo); + } + { + __block SInt32 dataSize = 0; + const NSUInteger count = self.publicDependencyArray.count; + const SInt32 *values = (const SInt32 *)self.publicDependencyArray.data; + for (NSUInteger i = 0; i < count; ++i) { + dataSize += computeInt32SizeNoTag(values[i]); + } + size_ += dataSize; + size_ += (SInt32)(1 * count); + } + { + __block SInt32 dataSize = 0; + const NSUInteger count = self.weakDependencyArray.count; + const SInt32 *values = (const SInt32 *)self.weakDependencyArray.data; + for (NSUInteger i = 0; i < count; ++i) { + dataSize += computeInt32SizeNoTag(values[i]); + } + size_ += dataSize; + size_ += (SInt32)(1 * count); + } + size_ += self.unknownFields.serializedSize; + memoizedSerializedSize = size_; + return size_; +} ++ (PBFileDescriptorProto*) parseFromData:(NSData*) data { + return (PBFileDescriptorProto*)[[[PBFileDescriptorProto builder] mergeFromData:data] build]; +} ++ (PBFileDescriptorProto*) parseFromData:(NSData*) data extensionRegistry:(PBExtensionRegistry*) extensionRegistry { + return (PBFileDescriptorProto*)[[[PBFileDescriptorProto builder] mergeFromData:data extensionRegistry:extensionRegistry] build]; +} ++ (PBFileDescriptorProto*) parseFromInputStream:(NSInputStream*) input { + return (PBFileDescriptorProto*)[[[PBFileDescriptorProto builder] mergeFromInputStream:input] build]; +} ++ (PBFileDescriptorProto*) parseFromInputStream:(NSInputStream*) input extensionRegistry:(PBExtensionRegistry*) extensionRegistry { + return (PBFileDescriptorProto*)[[[PBFileDescriptorProto builder] mergeFromInputStream:input extensionRegistry:extensionRegistry] build]; +} ++ (PBFileDescriptorProto*) parseFromCodedInputStream:(PBCodedInputStream*) input { + return (PBFileDescriptorProto*)[[[PBFileDescriptorProto builder] mergeFromCodedInputStream:input] build]; +} ++ (PBFileDescriptorProto*) parseFromCodedInputStream:(PBCodedInputStream*) input extensionRegistry:(PBExtensionRegistry*) extensionRegistry { + return (PBFileDescriptorProto*)[[[PBFileDescriptorProto builder] mergeFromCodedInputStream:input extensionRegistry:extensionRegistry] build]; +} ++ (PBFileDescriptorProtoBuilder*) builder { + return [[PBFileDescriptorProtoBuilder alloc] init]; +} ++ (PBFileDescriptorProtoBuilder*) builderWithPrototype:(PBFileDescriptorProto*) prototype { + return [[PBFileDescriptorProto builder] mergeFrom:prototype]; +} +- (PBFileDescriptorProtoBuilder*) builder { + return [PBFileDescriptorProto builder]; +} +- (PBFileDescriptorProtoBuilder*) toBuilder { + return [PBFileDescriptorProto builderWithPrototype:self]; +} +- (void) writeDescriptionTo:(NSMutableString*) output withIndent:(NSString*) indent { + if (self.hasName) { + [output appendFormat:@"%@%@: %@\n", indent, @"name", self.name]; + } + if (self.hasPackage) { + [output appendFormat:@"%@%@: %@\n", indent, @"package", self.package]; + } + [self.dependencyArray enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) { + [output appendFormat:@"%@%@: %@\n", indent, @"dependency", obj]; + }]; + [self.messageTypeArray enumerateObjectsUsingBlock:^(PBDescriptorProto *element, NSUInteger idx, BOOL *stop) { + [output appendFormat:@"%@%@ {\n", indent, @"messageType"]; + [element writeDescriptionTo:output + withIndent:[NSString stringWithFormat:@"%@ ", indent]]; + [output appendFormat:@"%@}\n", indent]; + }]; + [self.enumTypeArray enumerateObjectsUsingBlock:^(PBEnumDescriptorProto *element, NSUInteger idx, BOOL *stop) { + [output appendFormat:@"%@%@ {\n", indent, @"enumType"]; + [element writeDescriptionTo:output + withIndent:[NSString stringWithFormat:@"%@ ", indent]]; + [output appendFormat:@"%@}\n", indent]; + }]; + [self.serviceArray enumerateObjectsUsingBlock:^(PBServiceDescriptorProto *element, NSUInteger idx, BOOL *stop) { + [output appendFormat:@"%@%@ {\n", indent, @"service"]; + [element writeDescriptionTo:output + withIndent:[NSString stringWithFormat:@"%@ ", indent]]; + [output appendFormat:@"%@}\n", indent]; + }]; + [self.extensionArray enumerateObjectsUsingBlock:^(PBFieldDescriptorProto *element, NSUInteger idx, BOOL *stop) { + [output appendFormat:@"%@%@ {\n", indent, @"extension"]; + [element writeDescriptionTo:output + withIndent:[NSString stringWithFormat:@"%@ ", indent]]; + [output appendFormat:@"%@}\n", indent]; + }]; + if (self.hasOptions) { + [output appendFormat:@"%@%@ {\n", indent, @"options"]; + [self.options writeDescriptionTo:output + withIndent:[NSString stringWithFormat:@"%@ ", indent]]; + [output appendFormat:@"%@}\n", indent]; + } + if (self.hasSourceCodeInfo) { + [output appendFormat:@"%@%@ {\n", indent, @"sourceCodeInfo"]; + [self.sourceCodeInfo writeDescriptionTo:output + withIndent:[NSString stringWithFormat:@"%@ ", indent]]; + [output appendFormat:@"%@}\n", indent]; + } + [self.publicDependencyArray enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) { + [output appendFormat:@"%@%@: %@\n", indent, @"publicDependency", obj]; + }]; + [self.weakDependencyArray enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) { + [output appendFormat:@"%@%@: %@\n", indent, @"weakDependency", obj]; + }]; + [self.unknownFields writeDescriptionTo:output withIndent:indent]; +} +- (BOOL) isEqual:(id)other { + if (other == self) { + return YES; + } + if (![other isKindOfClass:[PBFileDescriptorProto class]]) { + return NO; + } + PBFileDescriptorProto *otherMessage = other; + return + self.hasName == otherMessage.hasName && + (!self.hasName || [self.name isEqual:otherMessage.name]) && + self.hasPackage == otherMessage.hasPackage && + (!self.hasPackage || [self.package isEqual:otherMessage.package]) && + [self.dependencyArray isEqualToArray:otherMessage.dependencyArray] && + [self.messageTypeArray isEqualToArray:otherMessage.messageTypeArray] && + [self.enumTypeArray isEqualToArray:otherMessage.enumTypeArray] && + [self.serviceArray isEqualToArray:otherMessage.serviceArray] && + [self.extensionArray isEqualToArray:otherMessage.extensionArray] && + self.hasOptions == otherMessage.hasOptions && + (!self.hasOptions || [self.options isEqual:otherMessage.options]) && + self.hasSourceCodeInfo == otherMessage.hasSourceCodeInfo && + (!self.hasSourceCodeInfo || [self.sourceCodeInfo isEqual:otherMessage.sourceCodeInfo]) && + [self.publicDependencyArray isEqualToArray:otherMessage.publicDependencyArray] && + [self.weakDependencyArray isEqualToArray:otherMessage.weakDependencyArray] && + (self.unknownFields == otherMessage.unknownFields || (self.unknownFields != nil && [self.unknownFields isEqual:otherMessage.unknownFields])); +} +- (NSUInteger) hash { + __block NSUInteger hashCode = 7; + if (self.hasName) { + hashCode = hashCode * 31 + [self.name hash]; + } + if (self.hasPackage) { + hashCode = hashCode * 31 + [self.package hash]; + } + [self.dependencyArray enumerateObjectsUsingBlock:^(id element, NSUInteger idx, BOOL *stop) { + hashCode = hashCode * 31 + [element hash]; + }]; + [self.messageTypeArray enumerateObjectsUsingBlock:^(PBDescriptorProto *element, NSUInteger idx, BOOL *stop) { + hashCode = hashCode * 31 + [element hash]; + }]; + [self.enumTypeArray enumerateObjectsUsingBlock:^(PBEnumDescriptorProto *element, NSUInteger idx, BOOL *stop) { + hashCode = hashCode * 31 + [element hash]; + }]; + [self.serviceArray enumerateObjectsUsingBlock:^(PBServiceDescriptorProto *element, NSUInteger idx, BOOL *stop) { + hashCode = hashCode * 31 + [element hash]; + }]; + [self.extensionArray enumerateObjectsUsingBlock:^(PBFieldDescriptorProto *element, NSUInteger idx, BOOL *stop) { + hashCode = hashCode * 31 + [element hash]; + }]; + if (self.hasOptions) { + hashCode = hashCode * 31 + [self.options hash]; + } + if (self.hasSourceCodeInfo) { + hashCode = hashCode * 31 + [self.sourceCodeInfo hash]; + } + [self.publicDependencyArray enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) { + hashCode = hashCode * 31 + [obj longValue]; + }]; + [self.weakDependencyArray enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) { + hashCode = hashCode * 31 + [obj longValue]; + }]; + hashCode = hashCode * 31 + [self.unknownFields hash]; + return hashCode; +} +@end + +@interface PBFileDescriptorProtoBuilder() +@property (strong) PBFileDescriptorProto* result; +@end + +@implementation PBFileDescriptorProtoBuilder +@synthesize result; +- (id) init { + if ((self = [super init])) { + self.result = [[PBFileDescriptorProto alloc] init]; + } + return self; +} +- (PBGeneratedMessage*) internalGetResult { + return result; +} +- (PBFileDescriptorProtoBuilder*) clear { + self.result = [[PBFileDescriptorProto alloc] init]; + return self; +} +- (PBFileDescriptorProtoBuilder*) clone { + return [PBFileDescriptorProto builderWithPrototype:result]; +} +- (PBFileDescriptorProto*) defaultInstance { + return [PBFileDescriptorProto defaultInstance]; +} +- (PBFileDescriptorProto*) build { + [self checkInitialized]; + return [self buildPartial]; +} +- (PBFileDescriptorProto*) buildPartial { + PBFileDescriptorProto* returnMe = result; + self.result = nil; + return returnMe; +} +- (PBFileDescriptorProtoBuilder*) mergeFrom:(PBFileDescriptorProto*) other { + if (other == [PBFileDescriptorProto defaultInstance]) { + return self; + } + if (other.hasName) { + [self setName:other.name]; + } + if (other.hasPackage) { + [self setPackage:other.package]; + } + if (other.dependencyArray.count > 0) { + if (result.dependencyArray == nil) { + result.dependencyArray = [[NSMutableArray alloc] initWithArray:other.dependencyArray]; + } else { + [result.dependencyArray addObjectsFromArray:other.dependencyArray]; + } + } + if (other.publicDependencyArray.count > 0) { + if (result.publicDependencyArray == nil) { + result.publicDependencyArray = [other.publicDependencyArray copy]; + } else { + [result.publicDependencyArray appendArray:other.publicDependencyArray]; + } + } + if (other.weakDependencyArray.count > 0) { + if (result.weakDependencyArray == nil) { + result.weakDependencyArray = [other.weakDependencyArray copy]; + } else { + [result.weakDependencyArray appendArray:other.weakDependencyArray]; + } + } + if (other.messageTypeArray.count > 0) { + if (result.messageTypeArray == nil) { + result.messageTypeArray = [[NSMutableArray alloc] initWithArray:other.messageTypeArray]; + } else { + [result.messageTypeArray addObjectsFromArray:other.messageTypeArray]; + } + } + if (other.enumTypeArray.count > 0) { + if (result.enumTypeArray == nil) { + result.enumTypeArray = [[NSMutableArray alloc] initWithArray:other.enumTypeArray]; + } else { + [result.enumTypeArray addObjectsFromArray:other.enumTypeArray]; + } + } + if (other.serviceArray.count > 0) { + if (result.serviceArray == nil) { + result.serviceArray = [[NSMutableArray alloc] initWithArray:other.serviceArray]; + } else { + [result.serviceArray addObjectsFromArray:other.serviceArray]; + } + } + if (other.extensionArray.count > 0) { + if (result.extensionArray == nil) { + result.extensionArray = [[NSMutableArray alloc] initWithArray:other.extensionArray]; + } else { + [result.extensionArray addObjectsFromArray:other.extensionArray]; + } + } + if (other.hasOptions) { + [self mergeOptions:other.options]; + } + if (other.hasSourceCodeInfo) { + [self mergeSourceCodeInfo:other.sourceCodeInfo]; + } + [self mergeUnknownFields:other.unknownFields]; + return self; +} +- (PBFileDescriptorProtoBuilder*) mergeFromCodedInputStream:(PBCodedInputStream*) input { + return [self mergeFromCodedInputStream:input extensionRegistry:[PBExtensionRegistry emptyRegistry]]; +} +- (PBFileDescriptorProtoBuilder*) mergeFromCodedInputStream:(PBCodedInputStream*) input extensionRegistry:(PBExtensionRegistry*) extensionRegistry { + PBUnknownFieldSetBuilder* unknownFields = [PBUnknownFieldSet builderWithUnknownFields:self.unknownFields]; + while (YES) { + SInt32 tag = [input readTag]; + switch (tag) { + case 0: + [self setUnknownFields:[unknownFields build]]; + return self; + default: { + if (![self parseUnknownField:input unknownFields:unknownFields extensionRegistry:extensionRegistry tag:tag]) { + [self setUnknownFields:[unknownFields build]]; + return self; + } + break; + } + case 10: { + [self setName:[input readString]]; + break; + } + case 18: { + [self setPackage:[input readString]]; + break; + } + case 26: { + [self addDependency:[input readString]]; + break; + } + case 34: { + PBDescriptorProtoBuilder* subBuilder = [PBDescriptorProto builder]; + [input readMessage:subBuilder extensionRegistry:extensionRegistry]; + [self addMessageType:[subBuilder buildPartial]]; + break; + } + case 42: { + PBEnumDescriptorProtoBuilder* subBuilder = [PBEnumDescriptorProto builder]; + [input readMessage:subBuilder extensionRegistry:extensionRegistry]; + [self addEnumType:[subBuilder buildPartial]]; + break; + } + case 50: { + PBServiceDescriptorProtoBuilder* subBuilder = [PBServiceDescriptorProto builder]; + [input readMessage:subBuilder extensionRegistry:extensionRegistry]; + [self addService:[subBuilder buildPartial]]; + break; + } + case 58: { + PBFieldDescriptorProtoBuilder* subBuilder = [PBFieldDescriptorProto builder]; + [input readMessage:subBuilder extensionRegistry:extensionRegistry]; + [self addExtension:[subBuilder buildPartial]]; + break; + } + case 66: { + PBFileOptionsBuilder* subBuilder = [PBFileOptions builder]; + if (self.hasOptions) { + [subBuilder mergeFrom:self.options]; + } + [input readMessage:subBuilder extensionRegistry:extensionRegistry]; + [self setOptions:[subBuilder buildPartial]]; + break; + } + case 74: { + PBSourceCodeInfoBuilder* subBuilder = [PBSourceCodeInfo builder]; + if (self.hasSourceCodeInfo) { + [subBuilder mergeFrom:self.sourceCodeInfo]; + } + [input readMessage:subBuilder extensionRegistry:extensionRegistry]; + [self setSourceCodeInfo:[subBuilder buildPartial]]; + break; + } + case 80: { + [self addPublicDependency:[input readInt32]]; + break; + } + case 88: { + [self addWeakDependency:[input readInt32]]; + break; + } + } + } +} +- (BOOL) hasName { + return result.hasName; +} +- (NSString*) name { + return result.name; +} +- (PBFileDescriptorProtoBuilder*) setName:(NSString*) value { + result.hasName = YES; + result.name = value; + return self; +} +- (PBFileDescriptorProtoBuilder*) clearName { + result.hasName = NO; + result.name = @""; + return self; +} +- (BOOL) hasPackage { + return result.hasPackage; +} +- (NSString*) package { + return result.package; +} +- (PBFileDescriptorProtoBuilder*) setPackage:(NSString*) value { + result.hasPackage = YES; + result.package = value; + return self; +} +- (PBFileDescriptorProtoBuilder*) clearPackage { + result.hasPackage = NO; + result.package = @""; + return self; +} +- (NSMutableArray *)dependency { + return result.dependencyArray; +} +- (NSString*)dependencyAtIndex:(NSUInteger)index { + return [result dependencyAtIndex:index]; +} +- (PBFileDescriptorProtoBuilder *)addDependency:(NSString*)value { + if (result.dependencyArray == nil) { + result.dependencyArray = [[NSMutableArray alloc]init]; + } + [result.dependencyArray addObject:value]; + return self; +} +- (PBFileDescriptorProtoBuilder *)setDependencyArray:(NSArray *)array { + result.dependencyArray = [[NSMutableArray alloc] initWithArray:array]; + return self; +} +- (PBFileDescriptorProtoBuilder *)clearDependency { + result.dependencyArray = nil; + return self; +} +- (PBAppendableArray *)publicDependency { + return result.publicDependencyArray; +} +- (SInt32)publicDependencyAtIndex:(NSUInteger)index { + return [result publicDependencyAtIndex:index]; +} +- (PBFileDescriptorProtoBuilder *)addPublicDependency:(SInt32)value { + if (result.publicDependencyArray == nil) { + result.publicDependencyArray = [PBAppendableArray arrayWithValueType:PBArrayValueTypeInt32]; + } + [result.publicDependencyArray addInt32:value]; + return self; +} +- (PBFileDescriptorProtoBuilder *)setPublicDependencyArray:(NSArray *)array { + result.publicDependencyArray = [PBAppendableArray arrayWithArray:array valueType:PBArrayValueTypeInt32]; + return self; +} +- (PBFileDescriptorProtoBuilder *)setPublicDependencyValues:(const SInt32 *)values count:(NSUInteger)count { + result.publicDependencyArray = [PBAppendableArray arrayWithValues:values count:count valueType:PBArrayValueTypeInt32]; + return self; +} +- (PBFileDescriptorProtoBuilder *)clearPublicDependency { + result.publicDependencyArray = nil; + return self; +} +- (PBAppendableArray *)weakDependency { + return result.weakDependencyArray; +} +- (SInt32)weakDependencyAtIndex:(NSUInteger)index { + return [result weakDependencyAtIndex:index]; +} +- (PBFileDescriptorProtoBuilder *)addWeakDependency:(SInt32)value { + if (result.weakDependencyArray == nil) { + result.weakDependencyArray = [PBAppendableArray arrayWithValueType:PBArrayValueTypeInt32]; + } + [result.weakDependencyArray addInt32:value]; + return self; +} +- (PBFileDescriptorProtoBuilder *)setWeakDependencyArray:(NSArray *)array { + result.weakDependencyArray = [PBAppendableArray arrayWithArray:array valueType:PBArrayValueTypeInt32]; + return self; +} +- (PBFileDescriptorProtoBuilder *)setWeakDependencyValues:(const SInt32 *)values count:(NSUInteger)count { + result.weakDependencyArray = [PBAppendableArray arrayWithValues:values count:count valueType:PBArrayValueTypeInt32]; + return self; +} +- (PBFileDescriptorProtoBuilder *)clearWeakDependency { + result.weakDependencyArray = nil; + return self; +} +- (NSMutableArray *)messageType { + return result.messageTypeArray; +} +- (PBDescriptorProto*)messageTypeAtIndex:(NSUInteger)index { + return [result messageTypeAtIndex:index]; +} +- (PBFileDescriptorProtoBuilder *)addMessageType:(PBDescriptorProto*)value { + if (result.messageTypeArray == nil) { + result.messageTypeArray = [[NSMutableArray alloc]init]; + } + [result.messageTypeArray addObject:value]; + return self; +} +- (PBFileDescriptorProtoBuilder *)setMessageTypeArray:(NSArray *)array { + result.messageTypeArray = [[NSMutableArray alloc]initWithArray:array]; + return self; +} +- (PBFileDescriptorProtoBuilder *)clearMessageType { + result.messageTypeArray = nil; + return self; +} +- (NSMutableArray *)enumType { + return result.enumTypeArray; +} +- (PBEnumDescriptorProto*)enumTypeAtIndex:(NSUInteger)index { + return [result enumTypeAtIndex:index]; +} +- (PBFileDescriptorProtoBuilder *)addEnumType:(PBEnumDescriptorProto*)value { + if (result.enumTypeArray == nil) { + result.enumTypeArray = [[NSMutableArray alloc]init]; + } + [result.enumTypeArray addObject:value]; + return self; +} +- (PBFileDescriptorProtoBuilder *)setEnumTypeArray:(NSArray *)array { + result.enumTypeArray = [[NSMutableArray alloc]initWithArray:array]; + return self; +} +- (PBFileDescriptorProtoBuilder *)clearEnumType { + result.enumTypeArray = nil; + return self; +} +- (NSMutableArray *)service { + return result.serviceArray; +} +- (PBServiceDescriptorProto*)serviceAtIndex:(NSUInteger)index { + return [result serviceAtIndex:index]; +} +- (PBFileDescriptorProtoBuilder *)addService:(PBServiceDescriptorProto*)value { + if (result.serviceArray == nil) { + result.serviceArray = [[NSMutableArray alloc]init]; + } + [result.serviceArray addObject:value]; + return self; +} +- (PBFileDescriptorProtoBuilder *)setServiceArray:(NSArray *)array { + result.serviceArray = [[NSMutableArray alloc]initWithArray:array]; + return self; +} +- (PBFileDescriptorProtoBuilder *)clearService { + result.serviceArray = nil; + return self; +} +- (NSMutableArray *)extension { + return result.extensionArray; +} +- (PBFieldDescriptorProto*)extensionAtIndex:(NSUInteger)index { + return [result extensionAtIndex:index]; +} +- (PBFileDescriptorProtoBuilder *)addExtension:(PBFieldDescriptorProto*)value { + if (result.extensionArray == nil) { + result.extensionArray = [[NSMutableArray alloc]init]; + } + [result.extensionArray addObject:value]; + return self; +} +- (PBFileDescriptorProtoBuilder *)setExtensionArray:(NSArray *)array { + result.extensionArray = [[NSMutableArray alloc]initWithArray:array]; + return self; +} +- (PBFileDescriptorProtoBuilder *)clearExtension { + result.extensionArray = nil; + return self; +} +- (BOOL) hasOptions { + return result.hasOptions; +} +- (PBFileOptions*) options { + return result.options; +} +- (PBFileDescriptorProtoBuilder*) setOptions:(PBFileOptions*) value { + result.hasOptions = YES; + result.options = value; + return self; +} +- (PBFileDescriptorProtoBuilder*) setOptionsBuilder:(PBFileOptionsBuilder*) builderForValue { + return [self setOptions:[builderForValue build]]; +} +- (PBFileDescriptorProtoBuilder*) mergeOptions:(PBFileOptions*) value { + if (result.hasOptions && + result.options != [PBFileOptions defaultInstance]) { + result.options = + [[[PBFileOptions builderWithPrototype:result.options] mergeFrom:value] buildPartial]; + } else { + result.options = value; + } + result.hasOptions = YES; + return self; +} +- (PBFileDescriptorProtoBuilder*) clearOptions { + result.hasOptions = NO; + result.options = [PBFileOptions defaultInstance]; + return self; +} +- (BOOL) hasSourceCodeInfo { + return result.hasSourceCodeInfo; +} +- (PBSourceCodeInfo*) sourceCodeInfo { + return result.sourceCodeInfo; +} +- (PBFileDescriptorProtoBuilder*) setSourceCodeInfo:(PBSourceCodeInfo*) value { + result.hasSourceCodeInfo = YES; + result.sourceCodeInfo = value; + return self; +} +- (PBFileDescriptorProtoBuilder*) setSourceCodeInfoBuilder:(PBSourceCodeInfoBuilder*) builderForValue { + return [self setSourceCodeInfo:[builderForValue build]]; +} +- (PBFileDescriptorProtoBuilder*) mergeSourceCodeInfo:(PBSourceCodeInfo*) value { + if (result.hasSourceCodeInfo && + result.sourceCodeInfo != [PBSourceCodeInfo defaultInstance]) { + result.sourceCodeInfo = + [[[PBSourceCodeInfo builderWithPrototype:result.sourceCodeInfo] mergeFrom:value] buildPartial]; + } else { + result.sourceCodeInfo = value; + } + result.hasSourceCodeInfo = YES; + return self; +} +- (PBFileDescriptorProtoBuilder*) clearSourceCodeInfo { + result.hasSourceCodeInfo = NO; + result.sourceCodeInfo = [PBSourceCodeInfo defaultInstance]; + return self; +} +@end + +@interface PBDescriptorProto () +@property (strong) NSString* name; +@property (strong) NSMutableArray * fieldArray; +@property (strong) NSMutableArray * extensionArray; +@property (strong) NSMutableArray * nestedTypeArray; +@property (strong) NSMutableArray * enumTypeArray; +@property (strong) NSMutableArray * extensionRangeArray; +@property (strong) NSMutableArray * oneofDeclArray; +@property (strong) PBMessageOptions* options; +@end + +@implementation PBDescriptorProto + +- (BOOL) hasName { + return !!hasName_; +} +- (void) setHasName:(BOOL) value_ { + hasName_ = !!value_; +} +@synthesize name; +@synthesize fieldArray; +@dynamic field; +@synthesize extensionArray; +@dynamic extension; +@synthesize nestedTypeArray; +@dynamic nestedType; +@synthesize enumTypeArray; +@dynamic enumType; +@synthesize extensionRangeArray; +@dynamic extensionRange; +@synthesize oneofDeclArray; +@dynamic oneofDecl; +- (BOOL) hasOptions { + return !!hasOptions_; +} +- (void) setHasOptions:(BOOL) value_ { + hasOptions_ = !!value_; +} +@synthesize options; +- (id) init { + if ((self = [super init])) { + self.name = @""; + self.options = [PBMessageOptions defaultInstance]; + } + return self; +} +static PBDescriptorProto* defaultPBDescriptorProtoInstance = nil; ++ (void) initialize { + if (self == [PBDescriptorProto class]) { + defaultPBDescriptorProtoInstance = [[PBDescriptorProto alloc] init]; + } +} ++ (PBDescriptorProto*) defaultInstance { + return defaultPBDescriptorProtoInstance; +} +- (PBDescriptorProto*) defaultInstance { + return defaultPBDescriptorProtoInstance; +} +- (NSArray *)field { + return fieldArray; +} +- (PBFieldDescriptorProto*)fieldAtIndex:(NSUInteger)index { + return [fieldArray objectAtIndex:index]; +} +- (NSArray *)extension { + return extensionArray; +} +- (PBFieldDescriptorProto*)extensionAtIndex:(NSUInteger)index { + return [extensionArray objectAtIndex:index]; +} +- (NSArray *)nestedType { + return nestedTypeArray; +} +- (PBDescriptorProto*)nestedTypeAtIndex:(NSUInteger)index { + return [nestedTypeArray objectAtIndex:index]; +} +- (NSArray *)enumType { + return enumTypeArray; +} +- (PBEnumDescriptorProto*)enumTypeAtIndex:(NSUInteger)index { + return [enumTypeArray objectAtIndex:index]; +} +- (NSArray *)extensionRange { + return extensionRangeArray; +} +- (PBDescriptorProtoExtensionRange*)extensionRangeAtIndex:(NSUInteger)index { + return [extensionRangeArray objectAtIndex:index]; +} +- (NSArray *)oneofDecl { + return oneofDeclArray; +} +- (PBOneofDescriptorProto*)oneofDeclAtIndex:(NSUInteger)index { + return [oneofDeclArray objectAtIndex:index]; +} +- (BOOL) isInitialized { + __block BOOL isInitfield = YES; + [self.field enumerateObjectsUsingBlock:^(PBFieldDescriptorProto *element, NSUInteger idx, BOOL *stop) { + if (!element.isInitialized) { + isInitfield = NO; + *stop = YES; + } + }]; + if (!isInitfield) return isInitfield; + __block BOOL isInitextension = YES; + [self.extension enumerateObjectsUsingBlock:^(PBFieldDescriptorProto *element, NSUInteger idx, BOOL *stop) { + if (!element.isInitialized) { + isInitextension = NO; + *stop = YES; + } + }]; + if (!isInitextension) return isInitextension; + __block BOOL isInitnestedType = YES; + [self.nestedType enumerateObjectsUsingBlock:^(PBDescriptorProto *element, NSUInteger idx, BOOL *stop) { + if (!element.isInitialized) { + isInitnestedType = NO; + *stop = YES; + } + }]; + if (!isInitnestedType) return isInitnestedType; + __block BOOL isInitenumType = YES; + [self.enumType enumerateObjectsUsingBlock:^(PBEnumDescriptorProto *element, NSUInteger idx, BOOL *stop) { + if (!element.isInitialized) { + isInitenumType = NO; + *stop = YES; + } + }]; + if (!isInitenumType) return isInitenumType; + if (self.hasOptions) { + if (!self.options.isInitialized) { + return NO; + } + } + return YES; +} +- (void) writeToCodedOutputStream:(PBCodedOutputStream*) output { + if (self.hasName) { + [output writeString:1 value:self.name]; + } + [self.fieldArray enumerateObjectsUsingBlock:^(PBFieldDescriptorProto *element, NSUInteger idx, BOOL *stop) { + [output writeMessage:2 value:element]; + }]; + [self.nestedTypeArray enumerateObjectsUsingBlock:^(PBDescriptorProto *element, NSUInteger idx, BOOL *stop) { + [output writeMessage:3 value:element]; + }]; + [self.enumTypeArray enumerateObjectsUsingBlock:^(PBEnumDescriptorProto *element, NSUInteger idx, BOOL *stop) { + [output writeMessage:4 value:element]; + }]; + [self.extensionRangeArray enumerateObjectsUsingBlock:^(PBDescriptorProtoExtensionRange *element, NSUInteger idx, BOOL *stop) { + [output writeMessage:5 value:element]; + }]; + [self.extensionArray enumerateObjectsUsingBlock:^(PBFieldDescriptorProto *element, NSUInteger idx, BOOL *stop) { + [output writeMessage:6 value:element]; + }]; + if (self.hasOptions) { + [output writeMessage:7 value:self.options]; + } + [self.oneofDeclArray enumerateObjectsUsingBlock:^(PBOneofDescriptorProto *element, NSUInteger idx, BOOL *stop) { + [output writeMessage:8 value:element]; + }]; + [self.unknownFields writeToCodedOutputStream:output]; +} +- (SInt32) serializedSize { + __block SInt32 size_ = memoizedSerializedSize; + if (size_ != -1) { + return size_; + } + + size_ = 0; + if (self.hasName) { + size_ += computeStringSize(1, self.name); + } + [self.fieldArray enumerateObjectsUsingBlock:^(PBFieldDescriptorProto *element, NSUInteger idx, BOOL *stop) { + size_ += computeMessageSize(2, element); + }]; + [self.nestedTypeArray enumerateObjectsUsingBlock:^(PBDescriptorProto *element, NSUInteger idx, BOOL *stop) { + size_ += computeMessageSize(3, element); + }]; + [self.enumTypeArray enumerateObjectsUsingBlock:^(PBEnumDescriptorProto *element, NSUInteger idx, BOOL *stop) { + size_ += computeMessageSize(4, element); + }]; + [self.extensionRangeArray enumerateObjectsUsingBlock:^(PBDescriptorProtoExtensionRange *element, NSUInteger idx, BOOL *stop) { + size_ += computeMessageSize(5, element); + }]; + [self.extensionArray enumerateObjectsUsingBlock:^(PBFieldDescriptorProto *element, NSUInteger idx, BOOL *stop) { + size_ += computeMessageSize(6, element); + }]; + if (self.hasOptions) { + size_ += computeMessageSize(7, self.options); + } + [self.oneofDeclArray enumerateObjectsUsingBlock:^(PBOneofDescriptorProto *element, NSUInteger idx, BOOL *stop) { + size_ += computeMessageSize(8, element); + }]; + size_ += self.unknownFields.serializedSize; + memoizedSerializedSize = size_; + return size_; +} ++ (PBDescriptorProto*) parseFromData:(NSData*) data { + return (PBDescriptorProto*)[[[PBDescriptorProto builder] mergeFromData:data] build]; +} ++ (PBDescriptorProto*) parseFromData:(NSData*) data extensionRegistry:(PBExtensionRegistry*) extensionRegistry { + return (PBDescriptorProto*)[[[PBDescriptorProto builder] mergeFromData:data extensionRegistry:extensionRegistry] build]; +} ++ (PBDescriptorProto*) parseFromInputStream:(NSInputStream*) input { + return (PBDescriptorProto*)[[[PBDescriptorProto builder] mergeFromInputStream:input] build]; +} ++ (PBDescriptorProto*) parseFromInputStream:(NSInputStream*) input extensionRegistry:(PBExtensionRegistry*) extensionRegistry { + return (PBDescriptorProto*)[[[PBDescriptorProto builder] mergeFromInputStream:input extensionRegistry:extensionRegistry] build]; +} ++ (PBDescriptorProto*) parseFromCodedInputStream:(PBCodedInputStream*) input { + return (PBDescriptorProto*)[[[PBDescriptorProto builder] mergeFromCodedInputStream:input] build]; +} ++ (PBDescriptorProto*) parseFromCodedInputStream:(PBCodedInputStream*) input extensionRegistry:(PBExtensionRegistry*) extensionRegistry { + return (PBDescriptorProto*)[[[PBDescriptorProto builder] mergeFromCodedInputStream:input extensionRegistry:extensionRegistry] build]; +} ++ (PBDescriptorProtoBuilder*) builder { + return [[PBDescriptorProtoBuilder alloc] init]; +} ++ (PBDescriptorProtoBuilder*) builderWithPrototype:(PBDescriptorProto*) prototype { + return [[PBDescriptorProto builder] mergeFrom:prototype]; +} +- (PBDescriptorProtoBuilder*) builder { + return [PBDescriptorProto builder]; +} +- (PBDescriptorProtoBuilder*) toBuilder { + return [PBDescriptorProto builderWithPrototype:self]; +} +- (void) writeDescriptionTo:(NSMutableString*) output withIndent:(NSString*) indent { + if (self.hasName) { + [output appendFormat:@"%@%@: %@\n", indent, @"name", self.name]; + } + [self.fieldArray enumerateObjectsUsingBlock:^(PBFieldDescriptorProto *element, NSUInteger idx, BOOL *stop) { + [output appendFormat:@"%@%@ {\n", indent, @"field"]; + [element writeDescriptionTo:output + withIndent:[NSString stringWithFormat:@"%@ ", indent]]; + [output appendFormat:@"%@}\n", indent]; + }]; + [self.nestedTypeArray enumerateObjectsUsingBlock:^(PBDescriptorProto *element, NSUInteger idx, BOOL *stop) { + [output appendFormat:@"%@%@ {\n", indent, @"nestedType"]; + [element writeDescriptionTo:output + withIndent:[NSString stringWithFormat:@"%@ ", indent]]; + [output appendFormat:@"%@}\n", indent]; + }]; + [self.enumTypeArray enumerateObjectsUsingBlock:^(PBEnumDescriptorProto *element, NSUInteger idx, BOOL *stop) { + [output appendFormat:@"%@%@ {\n", indent, @"enumType"]; + [element writeDescriptionTo:output + withIndent:[NSString stringWithFormat:@"%@ ", indent]]; + [output appendFormat:@"%@}\n", indent]; + }]; + [self.extensionRangeArray enumerateObjectsUsingBlock:^(PBDescriptorProtoExtensionRange *element, NSUInteger idx, BOOL *stop) { + [output appendFormat:@"%@%@ {\n", indent, @"extensionRange"]; + [element writeDescriptionTo:output + withIndent:[NSString stringWithFormat:@"%@ ", indent]]; + [output appendFormat:@"%@}\n", indent]; + }]; + [self.extensionArray enumerateObjectsUsingBlock:^(PBFieldDescriptorProto *element, NSUInteger idx, BOOL *stop) { + [output appendFormat:@"%@%@ {\n", indent, @"extension"]; + [element writeDescriptionTo:output + withIndent:[NSString stringWithFormat:@"%@ ", indent]]; + [output appendFormat:@"%@}\n", indent]; + }]; + if (self.hasOptions) { + [output appendFormat:@"%@%@ {\n", indent, @"options"]; + [self.options writeDescriptionTo:output + withIndent:[NSString stringWithFormat:@"%@ ", indent]]; + [output appendFormat:@"%@}\n", indent]; + } + [self.oneofDeclArray enumerateObjectsUsingBlock:^(PBOneofDescriptorProto *element, NSUInteger idx, BOOL *stop) { + [output appendFormat:@"%@%@ {\n", indent, @"oneofDecl"]; + [element writeDescriptionTo:output + withIndent:[NSString stringWithFormat:@"%@ ", indent]]; + [output appendFormat:@"%@}\n", indent]; + }]; + [self.unknownFields writeDescriptionTo:output withIndent:indent]; +} +- (BOOL) isEqual:(id)other { + if (other == self) { + return YES; + } + if (![other isKindOfClass:[PBDescriptorProto class]]) { + return NO; + } + PBDescriptorProto *otherMessage = other; + return + self.hasName == otherMessage.hasName && + (!self.hasName || [self.name isEqual:otherMessage.name]) && + [self.fieldArray isEqualToArray:otherMessage.fieldArray] && + [self.nestedTypeArray isEqualToArray:otherMessage.nestedTypeArray] && + [self.enumTypeArray isEqualToArray:otherMessage.enumTypeArray] && + [self.extensionRangeArray isEqualToArray:otherMessage.extensionRangeArray] && + [self.extensionArray isEqualToArray:otherMessage.extensionArray] && + self.hasOptions == otherMessage.hasOptions && + (!self.hasOptions || [self.options isEqual:otherMessage.options]) && + [self.oneofDeclArray isEqualToArray:otherMessage.oneofDeclArray] && + (self.unknownFields == otherMessage.unknownFields || (self.unknownFields != nil && [self.unknownFields isEqual:otherMessage.unknownFields])); +} +- (NSUInteger) hash { + __block NSUInteger hashCode = 7; + if (self.hasName) { + hashCode = hashCode * 31 + [self.name hash]; + } + [self.fieldArray enumerateObjectsUsingBlock:^(PBFieldDescriptorProto *element, NSUInteger idx, BOOL *stop) { + hashCode = hashCode * 31 + [element hash]; + }]; + [self.nestedTypeArray enumerateObjectsUsingBlock:^(PBDescriptorProto *element, NSUInteger idx, BOOL *stop) { + hashCode = hashCode * 31 + [element hash]; + }]; + [self.enumTypeArray enumerateObjectsUsingBlock:^(PBEnumDescriptorProto *element, NSUInteger idx, BOOL *stop) { + hashCode = hashCode * 31 + [element hash]; + }]; + [self.extensionRangeArray enumerateObjectsUsingBlock:^(PBDescriptorProtoExtensionRange *element, NSUInteger idx, BOOL *stop) { + hashCode = hashCode * 31 + [element hash]; + }]; + [self.extensionArray enumerateObjectsUsingBlock:^(PBFieldDescriptorProto *element, NSUInteger idx, BOOL *stop) { + hashCode = hashCode * 31 + [element hash]; + }]; + if (self.hasOptions) { + hashCode = hashCode * 31 + [self.options hash]; + } + [self.oneofDeclArray enumerateObjectsUsingBlock:^(PBOneofDescriptorProto *element, NSUInteger idx, BOOL *stop) { + hashCode = hashCode * 31 + [element hash]; + }]; + hashCode = hashCode * 31 + [self.unknownFields hash]; + return hashCode; +} +@end + +@interface PBDescriptorProtoExtensionRange () +@property SInt32 start; +@property SInt32 end; +@end + +@implementation PBDescriptorProtoExtensionRange + +- (BOOL) hasStart { + return !!hasStart_; +} +- (void) setHasStart:(BOOL) value_ { + hasStart_ = !!value_; +} +@synthesize start; +- (BOOL) hasEnd { + return !!hasEnd_; +} +- (void) setHasEnd:(BOOL) value_ { + hasEnd_ = !!value_; +} +@synthesize end; +- (id) init { + if ((self = [super init])) { + self.start = 0; + self.end = 0; + } + return self; +} +static PBDescriptorProtoExtensionRange* defaultPBDescriptorProtoExtensionRangeInstance = nil; ++ (void) initialize { + if (self == [PBDescriptorProtoExtensionRange class]) { + defaultPBDescriptorProtoExtensionRangeInstance = [[PBDescriptorProtoExtensionRange alloc] init]; + } +} ++ (PBDescriptorProtoExtensionRange*) defaultInstance { + return defaultPBDescriptorProtoExtensionRangeInstance; +} +- (PBDescriptorProtoExtensionRange*) defaultInstance { + return defaultPBDescriptorProtoExtensionRangeInstance; +} +- (BOOL) isInitialized { + return YES; +} +- (void) writeToCodedOutputStream:(PBCodedOutputStream*) output { + if (self.hasStart) { + [output writeInt32:1 value:self.start]; + } + if (self.hasEnd) { + [output writeInt32:2 value:self.end]; + } + [self.unknownFields writeToCodedOutputStream:output]; +} +- (SInt32) serializedSize { + __block SInt32 size_ = memoizedSerializedSize; + if (size_ != -1) { + return size_; + } + + size_ = 0; + if (self.hasStart) { + size_ += computeInt32Size(1, self.start); + } + if (self.hasEnd) { + size_ += computeInt32Size(2, self.end); + } + size_ += self.unknownFields.serializedSize; + memoizedSerializedSize = size_; + return size_; +} ++ (PBDescriptorProtoExtensionRange*) parseFromData:(NSData*) data { + return (PBDescriptorProtoExtensionRange*)[[[PBDescriptorProtoExtensionRange builder] mergeFromData:data] build]; +} ++ (PBDescriptorProtoExtensionRange*) parseFromData:(NSData*) data extensionRegistry:(PBExtensionRegistry*) extensionRegistry { + return (PBDescriptorProtoExtensionRange*)[[[PBDescriptorProtoExtensionRange builder] mergeFromData:data extensionRegistry:extensionRegistry] build]; +} ++ (PBDescriptorProtoExtensionRange*) parseFromInputStream:(NSInputStream*) input { + return (PBDescriptorProtoExtensionRange*)[[[PBDescriptorProtoExtensionRange builder] mergeFromInputStream:input] build]; +} ++ (PBDescriptorProtoExtensionRange*) parseFromInputStream:(NSInputStream*) input extensionRegistry:(PBExtensionRegistry*) extensionRegistry { + return (PBDescriptorProtoExtensionRange*)[[[PBDescriptorProtoExtensionRange builder] mergeFromInputStream:input extensionRegistry:extensionRegistry] build]; +} ++ (PBDescriptorProtoExtensionRange*) parseFromCodedInputStream:(PBCodedInputStream*) input { + return (PBDescriptorProtoExtensionRange*)[[[PBDescriptorProtoExtensionRange builder] mergeFromCodedInputStream:input] build]; +} ++ (PBDescriptorProtoExtensionRange*) parseFromCodedInputStream:(PBCodedInputStream*) input extensionRegistry:(PBExtensionRegistry*) extensionRegistry { + return (PBDescriptorProtoExtensionRange*)[[[PBDescriptorProtoExtensionRange builder] mergeFromCodedInputStream:input extensionRegistry:extensionRegistry] build]; +} ++ (PBDescriptorProtoExtensionRangeBuilder*) builder { + return [[PBDescriptorProtoExtensionRangeBuilder alloc] init]; +} ++ (PBDescriptorProtoExtensionRangeBuilder*) builderWithPrototype:(PBDescriptorProtoExtensionRange*) prototype { + return [[PBDescriptorProtoExtensionRange builder] mergeFrom:prototype]; +} +- (PBDescriptorProtoExtensionRangeBuilder*) builder { + return [PBDescriptorProtoExtensionRange builder]; +} +- (PBDescriptorProtoExtensionRangeBuilder*) toBuilder { + return [PBDescriptorProtoExtensionRange builderWithPrototype:self]; +} +- (void) writeDescriptionTo:(NSMutableString*) output withIndent:(NSString*) indent { + if (self.hasStart) { + [output appendFormat:@"%@%@: %@\n", indent, @"start", [NSNumber numberWithInteger:self.start]]; + } + if (self.hasEnd) { + [output appendFormat:@"%@%@: %@\n", indent, @"end", [NSNumber numberWithInteger:self.end]]; + } + [self.unknownFields writeDescriptionTo:output withIndent:indent]; +} +- (BOOL) isEqual:(id)other { + if (other == self) { + return YES; + } + if (![other isKindOfClass:[PBDescriptorProtoExtensionRange class]]) { + return NO; + } + PBDescriptorProtoExtensionRange *otherMessage = other; + return + self.hasStart == otherMessage.hasStart && + (!self.hasStart || self.start == otherMessage.start) && + self.hasEnd == otherMessage.hasEnd && + (!self.hasEnd || self.end == otherMessage.end) && + (self.unknownFields == otherMessage.unknownFields || (self.unknownFields != nil && [self.unknownFields isEqual:otherMessage.unknownFields])); +} +- (NSUInteger) hash { + __block NSUInteger hashCode = 7; + if (self.hasStart) { + hashCode = hashCode * 31 + [[NSNumber numberWithInteger:self.start] hash]; + } + if (self.hasEnd) { + hashCode = hashCode * 31 + [[NSNumber numberWithInteger:self.end] hash]; + } + hashCode = hashCode * 31 + [self.unknownFields hash]; + return hashCode; +} +@end + +@interface PBDescriptorProtoExtensionRangeBuilder() +@property (strong) PBDescriptorProtoExtensionRange* result; +@end + +@implementation PBDescriptorProtoExtensionRangeBuilder +@synthesize result; +- (id) init { + if ((self = [super init])) { + self.result = [[PBDescriptorProtoExtensionRange alloc] init]; + } + return self; +} +- (PBGeneratedMessage*) internalGetResult { + return result; +} +- (PBDescriptorProtoExtensionRangeBuilder*) clear { + self.result = [[PBDescriptorProtoExtensionRange alloc] init]; + return self; +} +- (PBDescriptorProtoExtensionRangeBuilder*) clone { + return [PBDescriptorProtoExtensionRange builderWithPrototype:result]; +} +- (PBDescriptorProtoExtensionRange*) defaultInstance { + return [PBDescriptorProtoExtensionRange defaultInstance]; +} +- (PBDescriptorProtoExtensionRange*) build { + [self checkInitialized]; + return [self buildPartial]; +} +- (PBDescriptorProtoExtensionRange*) buildPartial { + PBDescriptorProtoExtensionRange* returnMe = result; + self.result = nil; + return returnMe; +} +- (PBDescriptorProtoExtensionRangeBuilder*) mergeFrom:(PBDescriptorProtoExtensionRange*) other { + if (other == [PBDescriptorProtoExtensionRange defaultInstance]) { + return self; + } + if (other.hasStart) { + [self setStart:other.start]; + } + if (other.hasEnd) { + [self setEnd:other.end]; + } + [self mergeUnknownFields:other.unknownFields]; + return self; +} +- (PBDescriptorProtoExtensionRangeBuilder*) mergeFromCodedInputStream:(PBCodedInputStream*) input { + return [self mergeFromCodedInputStream:input extensionRegistry:[PBExtensionRegistry emptyRegistry]]; +} +- (PBDescriptorProtoExtensionRangeBuilder*) mergeFromCodedInputStream:(PBCodedInputStream*) input extensionRegistry:(PBExtensionRegistry*) extensionRegistry { + PBUnknownFieldSetBuilder* unknownFields = [PBUnknownFieldSet builderWithUnknownFields:self.unknownFields]; + while (YES) { + SInt32 tag = [input readTag]; + switch (tag) { + case 0: + [self setUnknownFields:[unknownFields build]]; + return self; + default: { + if (![self parseUnknownField:input unknownFields:unknownFields extensionRegistry:extensionRegistry tag:tag]) { + [self setUnknownFields:[unknownFields build]]; + return self; + } + break; + } + case 8: { + [self setStart:[input readInt32]]; + break; + } + case 16: { + [self setEnd:[input readInt32]]; + break; + } + } + } +} +- (BOOL) hasStart { + return result.hasStart; +} +- (SInt32) start { + return result.start; +} +- (PBDescriptorProtoExtensionRangeBuilder*) setStart:(SInt32) value { + result.hasStart = YES; + result.start = value; + return self; +} +- (PBDescriptorProtoExtensionRangeBuilder*) clearStart { + result.hasStart = NO; + result.start = 0; + return self; +} +- (BOOL) hasEnd { + return result.hasEnd; +} +- (SInt32) end { + return result.end; +} +- (PBDescriptorProtoExtensionRangeBuilder*) setEnd:(SInt32) value { + result.hasEnd = YES; + result.end = value; + return self; +} +- (PBDescriptorProtoExtensionRangeBuilder*) clearEnd { + result.hasEnd = NO; + result.end = 0; + return self; +} +@end + +@interface PBDescriptorProtoBuilder() +@property (strong) PBDescriptorProto* result; +@end + +@implementation PBDescriptorProtoBuilder +@synthesize result; +- (id) init { + if ((self = [super init])) { + self.result = [[PBDescriptorProto alloc] init]; + } + return self; +} +- (PBGeneratedMessage*) internalGetResult { + return result; +} +- (PBDescriptorProtoBuilder*) clear { + self.result = [[PBDescriptorProto alloc] init]; + return self; +} +- (PBDescriptorProtoBuilder*) clone { + return [PBDescriptorProto builderWithPrototype:result]; +} +- (PBDescriptorProto*) defaultInstance { + return [PBDescriptorProto defaultInstance]; +} +- (PBDescriptorProto*) build { + [self checkInitialized]; + return [self buildPartial]; +} +- (PBDescriptorProto*) buildPartial { + PBDescriptorProto* returnMe = result; + self.result = nil; + return returnMe; +} +- (PBDescriptorProtoBuilder*) mergeFrom:(PBDescriptorProto*) other { + if (other == [PBDescriptorProto defaultInstance]) { + return self; + } + if (other.hasName) { + [self setName:other.name]; + } + if (other.fieldArray.count > 0) { + if (result.fieldArray == nil) { + result.fieldArray = [[NSMutableArray alloc] initWithArray:other.fieldArray]; + } else { + [result.fieldArray addObjectsFromArray:other.fieldArray]; + } + } + if (other.extensionArray.count > 0) { + if (result.extensionArray == nil) { + result.extensionArray = [[NSMutableArray alloc] initWithArray:other.extensionArray]; + } else { + [result.extensionArray addObjectsFromArray:other.extensionArray]; + } + } + if (other.nestedTypeArray.count > 0) { + if (result.nestedTypeArray == nil) { + result.nestedTypeArray = [[NSMutableArray alloc] initWithArray:other.nestedTypeArray]; + } else { + [result.nestedTypeArray addObjectsFromArray:other.nestedTypeArray]; + } + } + if (other.enumTypeArray.count > 0) { + if (result.enumTypeArray == nil) { + result.enumTypeArray = [[NSMutableArray alloc] initWithArray:other.enumTypeArray]; + } else { + [result.enumTypeArray addObjectsFromArray:other.enumTypeArray]; + } + } + if (other.extensionRangeArray.count > 0) { + if (result.extensionRangeArray == nil) { + result.extensionRangeArray = [[NSMutableArray alloc] initWithArray:other.extensionRangeArray]; + } else { + [result.extensionRangeArray addObjectsFromArray:other.extensionRangeArray]; + } + } + if (other.oneofDeclArray.count > 0) { + if (result.oneofDeclArray == nil) { + result.oneofDeclArray = [[NSMutableArray alloc] initWithArray:other.oneofDeclArray]; + } else { + [result.oneofDeclArray addObjectsFromArray:other.oneofDeclArray]; + } + } + if (other.hasOptions) { + [self mergeOptions:other.options]; + } + [self mergeUnknownFields:other.unknownFields]; + return self; +} +- (PBDescriptorProtoBuilder*) mergeFromCodedInputStream:(PBCodedInputStream*) input { + return [self mergeFromCodedInputStream:input extensionRegistry:[PBExtensionRegistry emptyRegistry]]; +} +- (PBDescriptorProtoBuilder*) mergeFromCodedInputStream:(PBCodedInputStream*) input extensionRegistry:(PBExtensionRegistry*) extensionRegistry { + PBUnknownFieldSetBuilder* unknownFields = [PBUnknownFieldSet builderWithUnknownFields:self.unknownFields]; + while (YES) { + SInt32 tag = [input readTag]; + switch (tag) { + case 0: + [self setUnknownFields:[unknownFields build]]; + return self; + default: { + if (![self parseUnknownField:input unknownFields:unknownFields extensionRegistry:extensionRegistry tag:tag]) { + [self setUnknownFields:[unknownFields build]]; + return self; + } + break; + } + case 10: { + [self setName:[input readString]]; + break; + } + case 18: { + PBFieldDescriptorProtoBuilder* subBuilder = [PBFieldDescriptorProto builder]; + [input readMessage:subBuilder extensionRegistry:extensionRegistry]; + [self addField:[subBuilder buildPartial]]; + break; + } + case 26: { + PBDescriptorProtoBuilder* subBuilder = [PBDescriptorProto builder]; + [input readMessage:subBuilder extensionRegistry:extensionRegistry]; + [self addNestedType:[subBuilder buildPartial]]; + break; + } + case 34: { + PBEnumDescriptorProtoBuilder* subBuilder = [PBEnumDescriptorProto builder]; + [input readMessage:subBuilder extensionRegistry:extensionRegistry]; + [self addEnumType:[subBuilder buildPartial]]; + break; + } + case 42: { + PBDescriptorProtoExtensionRangeBuilder* subBuilder = [PBDescriptorProtoExtensionRange builder]; + [input readMessage:subBuilder extensionRegistry:extensionRegistry]; + [self addExtensionRange:[subBuilder buildPartial]]; + break; + } + case 50: { + PBFieldDescriptorProtoBuilder* subBuilder = [PBFieldDescriptorProto builder]; + [input readMessage:subBuilder extensionRegistry:extensionRegistry]; + [self addExtension:[subBuilder buildPartial]]; + break; + } + case 58: { + PBMessageOptionsBuilder* subBuilder = [PBMessageOptions builder]; + if (self.hasOptions) { + [subBuilder mergeFrom:self.options]; + } + [input readMessage:subBuilder extensionRegistry:extensionRegistry]; + [self setOptions:[subBuilder buildPartial]]; + break; + } + case 66: { + PBOneofDescriptorProtoBuilder* subBuilder = [PBOneofDescriptorProto builder]; + [input readMessage:subBuilder extensionRegistry:extensionRegistry]; + [self addOneofDecl:[subBuilder buildPartial]]; + break; + } + } + } +} +- (BOOL) hasName { + return result.hasName; +} +- (NSString*) name { + return result.name; +} +- (PBDescriptorProtoBuilder*) setName:(NSString*) value { + result.hasName = YES; + result.name = value; + return self; +} +- (PBDescriptorProtoBuilder*) clearName { + result.hasName = NO; + result.name = @""; + return self; +} +- (NSMutableArray *)field { + return result.fieldArray; +} +- (PBFieldDescriptorProto*)fieldAtIndex:(NSUInteger)index { + return [result fieldAtIndex:index]; +} +- (PBDescriptorProtoBuilder *)addField:(PBFieldDescriptorProto*)value { + if (result.fieldArray == nil) { + result.fieldArray = [[NSMutableArray alloc]init]; + } + [result.fieldArray addObject:value]; + return self; +} +- (PBDescriptorProtoBuilder *)setFieldArray:(NSArray *)array { + result.fieldArray = [[NSMutableArray alloc]initWithArray:array]; + return self; +} +- (PBDescriptorProtoBuilder *)clearField { + result.fieldArray = nil; + return self; +} +- (NSMutableArray *)extension { + return result.extensionArray; +} +- (PBFieldDescriptorProto*)extensionAtIndex:(NSUInteger)index { + return [result extensionAtIndex:index]; +} +- (PBDescriptorProtoBuilder *)addExtension:(PBFieldDescriptorProto*)value { + if (result.extensionArray == nil) { + result.extensionArray = [[NSMutableArray alloc]init]; + } + [result.extensionArray addObject:value]; + return self; +} +- (PBDescriptorProtoBuilder *)setExtensionArray:(NSArray *)array { + result.extensionArray = [[NSMutableArray alloc]initWithArray:array]; + return self; +} +- (PBDescriptorProtoBuilder *)clearExtension { + result.extensionArray = nil; + return self; +} +- (NSMutableArray *)nestedType { + return result.nestedTypeArray; +} +- (PBDescriptorProto*)nestedTypeAtIndex:(NSUInteger)index { + return [result nestedTypeAtIndex:index]; +} +- (PBDescriptorProtoBuilder *)addNestedType:(PBDescriptorProto*)value { + if (result.nestedTypeArray == nil) { + result.nestedTypeArray = [[NSMutableArray alloc]init]; + } + [result.nestedTypeArray addObject:value]; + return self; +} +- (PBDescriptorProtoBuilder *)setNestedTypeArray:(NSArray *)array { + result.nestedTypeArray = [[NSMutableArray alloc]initWithArray:array]; + return self; +} +- (PBDescriptorProtoBuilder *)clearNestedType { + result.nestedTypeArray = nil; + return self; +} +- (NSMutableArray *)enumType { + return result.enumTypeArray; +} +- (PBEnumDescriptorProto*)enumTypeAtIndex:(NSUInteger)index { + return [result enumTypeAtIndex:index]; +} +- (PBDescriptorProtoBuilder *)addEnumType:(PBEnumDescriptorProto*)value { + if (result.enumTypeArray == nil) { + result.enumTypeArray = [[NSMutableArray alloc]init]; + } + [result.enumTypeArray addObject:value]; + return self; +} +- (PBDescriptorProtoBuilder *)setEnumTypeArray:(NSArray *)array { + result.enumTypeArray = [[NSMutableArray alloc]initWithArray:array]; + return self; +} +- (PBDescriptorProtoBuilder *)clearEnumType { + result.enumTypeArray = nil; + return self; +} +- (NSMutableArray *)extensionRange { + return result.extensionRangeArray; +} +- (PBDescriptorProtoExtensionRange*)extensionRangeAtIndex:(NSUInteger)index { + return [result extensionRangeAtIndex:index]; +} +- (PBDescriptorProtoBuilder *)addExtensionRange:(PBDescriptorProtoExtensionRange*)value { + if (result.extensionRangeArray == nil) { + result.extensionRangeArray = [[NSMutableArray alloc]init]; + } + [result.extensionRangeArray addObject:value]; + return self; +} +- (PBDescriptorProtoBuilder *)setExtensionRangeArray:(NSArray *)array { + result.extensionRangeArray = [[NSMutableArray alloc]initWithArray:array]; + return self; +} +- (PBDescriptorProtoBuilder *)clearExtensionRange { + result.extensionRangeArray = nil; + return self; +} +- (NSMutableArray *)oneofDecl { + return result.oneofDeclArray; +} +- (PBOneofDescriptorProto*)oneofDeclAtIndex:(NSUInteger)index { + return [result oneofDeclAtIndex:index]; +} +- (PBDescriptorProtoBuilder *)addOneofDecl:(PBOneofDescriptorProto*)value { + if (result.oneofDeclArray == nil) { + result.oneofDeclArray = [[NSMutableArray alloc]init]; + } + [result.oneofDeclArray addObject:value]; + return self; +} +- (PBDescriptorProtoBuilder *)setOneofDeclArray:(NSArray *)array { + result.oneofDeclArray = [[NSMutableArray alloc]initWithArray:array]; + return self; +} +- (PBDescriptorProtoBuilder *)clearOneofDecl { + result.oneofDeclArray = nil; + return self; +} +- (BOOL) hasOptions { + return result.hasOptions; +} +- (PBMessageOptions*) options { + return result.options; +} +- (PBDescriptorProtoBuilder*) setOptions:(PBMessageOptions*) value { + result.hasOptions = YES; + result.options = value; + return self; +} +- (PBDescriptorProtoBuilder*) setOptionsBuilder:(PBMessageOptionsBuilder*) builderForValue { + return [self setOptions:[builderForValue build]]; +} +- (PBDescriptorProtoBuilder*) mergeOptions:(PBMessageOptions*) value { + if (result.hasOptions && + result.options != [PBMessageOptions defaultInstance]) { + result.options = + [[[PBMessageOptions builderWithPrototype:result.options] mergeFrom:value] buildPartial]; + } else { + result.options = value; + } + result.hasOptions = YES; + return self; +} +- (PBDescriptorProtoBuilder*) clearOptions { + result.hasOptions = NO; + result.options = [PBMessageOptions defaultInstance]; + return self; +} +@end + +@interface PBFieldDescriptorProto () +@property (strong) NSString* name; +@property SInt32 number; +@property PBFieldDescriptorProtoLabel label; +@property PBFieldDescriptorProtoType type; +@property (strong) NSString* typeName; +@property (strong) NSString* extendee; +@property (strong) NSString* defaultValue; +@property SInt32 oneofIndex; +@property (strong) PBFieldOptions* options; +@end + +@implementation PBFieldDescriptorProto + +- (BOOL) hasName { + return !!hasName_; +} +- (void) setHasName:(BOOL) value_ { + hasName_ = !!value_; +} +@synthesize name; +- (BOOL) hasNumber { + return !!hasNumber_; +} +- (void) setHasNumber:(BOOL) value_ { + hasNumber_ = !!value_; +} +@synthesize number; +- (BOOL) hasLabel { + return !!hasLabel_; +} +- (void) setHasLabel:(BOOL) value_ { + hasLabel_ = !!value_; +} +@synthesize label; +- (BOOL) hasType { + return !!hasType_; +} +- (void) setHasType:(BOOL) value_ { + hasType_ = !!value_; +} +@synthesize type; +- (BOOL) hasTypeName { + return !!hasTypeName_; +} +- (void) setHasTypeName:(BOOL) value_ { + hasTypeName_ = !!value_; +} +@synthesize typeName; +- (BOOL) hasExtendee { + return !!hasExtendee_; +} +- (void) setHasExtendee:(BOOL) value_ { + hasExtendee_ = !!value_; +} +@synthesize extendee; +- (BOOL) hasDefaultValue { + return !!hasDefaultValue_; +} +- (void) setHasDefaultValue:(BOOL) value_ { + hasDefaultValue_ = !!value_; +} +@synthesize defaultValue; +- (BOOL) hasOneofIndex { + return !!hasOneofIndex_; +} +- (void) setHasOneofIndex:(BOOL) value_ { + hasOneofIndex_ = !!value_; +} +@synthesize oneofIndex; +- (BOOL) hasOptions { + return !!hasOptions_; +} +- (void) setHasOptions:(BOOL) value_ { + hasOptions_ = !!value_; +} +@synthesize options; +- (id) init { + if ((self = [super init])) { + self.name = @""; + self.number = 0; + self.label = PBFieldDescriptorProtoLabelLabelOptional; + self.type = PBFieldDescriptorProtoTypeTypeDouble; + self.typeName = @""; + self.extendee = @""; + self.defaultValue = @""; + self.oneofIndex = 0; + self.options = [PBFieldOptions defaultInstance]; + } + return self; +} +static PBFieldDescriptorProto* defaultPBFieldDescriptorProtoInstance = nil; ++ (void) initialize { + if (self == [PBFieldDescriptorProto class]) { + defaultPBFieldDescriptorProtoInstance = [[PBFieldDescriptorProto alloc] init]; + } +} ++ (PBFieldDescriptorProto*) defaultInstance { + return defaultPBFieldDescriptorProtoInstance; +} +- (PBFieldDescriptorProto*) defaultInstance { + return defaultPBFieldDescriptorProtoInstance; +} +- (BOOL) isInitialized { + if (self.hasOptions) { + if (!self.options.isInitialized) { + return NO; + } + } + return YES; +} +- (void) writeToCodedOutputStream:(PBCodedOutputStream*) output { + if (self.hasName) { + [output writeString:1 value:self.name]; + } + if (self.hasExtendee) { + [output writeString:2 value:self.extendee]; + } + if (self.hasNumber) { + [output writeInt32:3 value:self.number]; + } + if (self.hasLabel) { + [output writeEnum:4 value:self.label]; + } + if (self.hasType) { + [output writeEnum:5 value:self.type]; + } + if (self.hasTypeName) { + [output writeString:6 value:self.typeName]; + } + if (self.hasDefaultValue) { + [output writeString:7 value:self.defaultValue]; + } + if (self.hasOptions) { + [output writeMessage:8 value:self.options]; + } + if (self.hasOneofIndex) { + [output writeInt32:9 value:self.oneofIndex]; + } + [self.unknownFields writeToCodedOutputStream:output]; +} +- (SInt32) serializedSize { + __block SInt32 size_ = memoizedSerializedSize; + if (size_ != -1) { + return size_; + } + + size_ = 0; + if (self.hasName) { + size_ += computeStringSize(1, self.name); + } + if (self.hasExtendee) { + size_ += computeStringSize(2, self.extendee); + } + if (self.hasNumber) { + size_ += computeInt32Size(3, self.number); + } + if (self.hasLabel) { + size_ += computeEnumSize(4, self.label); + } + if (self.hasType) { + size_ += computeEnumSize(5, self.type); + } + if (self.hasTypeName) { + size_ += computeStringSize(6, self.typeName); + } + if (self.hasDefaultValue) { + size_ += computeStringSize(7, self.defaultValue); + } + if (self.hasOptions) { + size_ += computeMessageSize(8, self.options); + } + if (self.hasOneofIndex) { + size_ += computeInt32Size(9, self.oneofIndex); + } + size_ += self.unknownFields.serializedSize; + memoizedSerializedSize = size_; + return size_; +} ++ (PBFieldDescriptorProto*) parseFromData:(NSData*) data { + return (PBFieldDescriptorProto*)[[[PBFieldDescriptorProto builder] mergeFromData:data] build]; +} ++ (PBFieldDescriptorProto*) parseFromData:(NSData*) data extensionRegistry:(PBExtensionRegistry*) extensionRegistry { + return (PBFieldDescriptorProto*)[[[PBFieldDescriptorProto builder] mergeFromData:data extensionRegistry:extensionRegistry] build]; +} ++ (PBFieldDescriptorProto*) parseFromInputStream:(NSInputStream*) input { + return (PBFieldDescriptorProto*)[[[PBFieldDescriptorProto builder] mergeFromInputStream:input] build]; +} ++ (PBFieldDescriptorProto*) parseFromInputStream:(NSInputStream*) input extensionRegistry:(PBExtensionRegistry*) extensionRegistry { + return (PBFieldDescriptorProto*)[[[PBFieldDescriptorProto builder] mergeFromInputStream:input extensionRegistry:extensionRegistry] build]; +} ++ (PBFieldDescriptorProto*) parseFromCodedInputStream:(PBCodedInputStream*) input { + return (PBFieldDescriptorProto*)[[[PBFieldDescriptorProto builder] mergeFromCodedInputStream:input] build]; +} ++ (PBFieldDescriptorProto*) parseFromCodedInputStream:(PBCodedInputStream*) input extensionRegistry:(PBExtensionRegistry*) extensionRegistry { + return (PBFieldDescriptorProto*)[[[PBFieldDescriptorProto builder] mergeFromCodedInputStream:input extensionRegistry:extensionRegistry] build]; +} ++ (PBFieldDescriptorProtoBuilder*) builder { + return [[PBFieldDescriptorProtoBuilder alloc] init]; +} ++ (PBFieldDescriptorProtoBuilder*) builderWithPrototype:(PBFieldDescriptorProto*) prototype { + return [[PBFieldDescriptorProto builder] mergeFrom:prototype]; +} +- (PBFieldDescriptorProtoBuilder*) builder { + return [PBFieldDescriptorProto builder]; +} +- (PBFieldDescriptorProtoBuilder*) toBuilder { + return [PBFieldDescriptorProto builderWithPrototype:self]; +} +- (void) writeDescriptionTo:(NSMutableString*) output withIndent:(NSString*) indent { + if (self.hasName) { + [output appendFormat:@"%@%@: %@\n", indent, @"name", self.name]; + } + if (self.hasExtendee) { + [output appendFormat:@"%@%@: %@\n", indent, @"extendee", self.extendee]; + } + if (self.hasNumber) { + [output appendFormat:@"%@%@: %@\n", indent, @"number", [NSNumber numberWithInteger:self.number]]; + } + if (self.hasLabel) { + [output appendFormat:@"%@%@: %d\n", indent, @"label", self.label]; + } + if (self.hasType) { + [output appendFormat:@"%@%@: %d\n", indent, @"type", self.type]; + } + if (self.hasTypeName) { + [output appendFormat:@"%@%@: %@\n", indent, @"typeName", self.typeName]; + } + if (self.hasDefaultValue) { + [output appendFormat:@"%@%@: %@\n", indent, @"defaultValue", self.defaultValue]; + } + if (self.hasOptions) { + [output appendFormat:@"%@%@ {\n", indent, @"options"]; + [self.options writeDescriptionTo:output + withIndent:[NSString stringWithFormat:@"%@ ", indent]]; + [output appendFormat:@"%@}\n", indent]; + } + if (self.hasOneofIndex) { + [output appendFormat:@"%@%@: %@\n", indent, @"oneofIndex", [NSNumber numberWithInteger:self.oneofIndex]]; + } + [self.unknownFields writeDescriptionTo:output withIndent:indent]; +} +- (BOOL) isEqual:(id)other { + if (other == self) { + return YES; + } + if (![other isKindOfClass:[PBFieldDescriptorProto class]]) { + return NO; + } + PBFieldDescriptorProto *otherMessage = other; + return + self.hasName == otherMessage.hasName && + (!self.hasName || [self.name isEqual:otherMessage.name]) && + self.hasExtendee == otherMessage.hasExtendee && + (!self.hasExtendee || [self.extendee isEqual:otherMessage.extendee]) && + self.hasNumber == otherMessage.hasNumber && + (!self.hasNumber || self.number == otherMessage.number) && + self.hasLabel == otherMessage.hasLabel && + (!self.hasLabel || self.label == otherMessage.label) && + self.hasType == otherMessage.hasType && + (!self.hasType || self.type == otherMessage.type) && + self.hasTypeName == otherMessage.hasTypeName && + (!self.hasTypeName || [self.typeName isEqual:otherMessage.typeName]) && + self.hasDefaultValue == otherMessage.hasDefaultValue && + (!self.hasDefaultValue || [self.defaultValue isEqual:otherMessage.defaultValue]) && + self.hasOptions == otherMessage.hasOptions && + (!self.hasOptions || [self.options isEqual:otherMessage.options]) && + self.hasOneofIndex == otherMessage.hasOneofIndex && + (!self.hasOneofIndex || self.oneofIndex == otherMessage.oneofIndex) && + (self.unknownFields == otherMessage.unknownFields || (self.unknownFields != nil && [self.unknownFields isEqual:otherMessage.unknownFields])); +} +- (NSUInteger) hash { + __block NSUInteger hashCode = 7; + if (self.hasName) { + hashCode = hashCode * 31 + [self.name hash]; + } + if (self.hasExtendee) { + hashCode = hashCode * 31 + [self.extendee hash]; + } + if (self.hasNumber) { + hashCode = hashCode * 31 + [[NSNumber numberWithInteger:self.number] hash]; + } + if (self.hasLabel) { + hashCode = hashCode * 31 + self.label; + } + if (self.hasType) { + hashCode = hashCode * 31 + self.type; + } + if (self.hasTypeName) { + hashCode = hashCode * 31 + [self.typeName hash]; + } + if (self.hasDefaultValue) { + hashCode = hashCode * 31 + [self.defaultValue hash]; + } + if (self.hasOptions) { + hashCode = hashCode * 31 + [self.options hash]; + } + if (self.hasOneofIndex) { + hashCode = hashCode * 31 + [[NSNumber numberWithInteger:self.oneofIndex] hash]; + } + hashCode = hashCode * 31 + [self.unknownFields hash]; + return hashCode; +} +@end + +BOOL PBFieldDescriptorProtoTypeIsValidValue(PBFieldDescriptorProtoType value) { + switch (value) { + case PBFieldDescriptorProtoTypeTypeDouble: + case PBFieldDescriptorProtoTypeTypeFloat: + case PBFieldDescriptorProtoTypeTypeInt64: + case PBFieldDescriptorProtoTypeTypeUint64: + case PBFieldDescriptorProtoTypeTypeInt32: + case PBFieldDescriptorProtoTypeTypeFixed64: + case PBFieldDescriptorProtoTypeTypeFixed32: + case PBFieldDescriptorProtoTypeTypeBool: + case PBFieldDescriptorProtoTypeTypeString: + case PBFieldDescriptorProtoTypeTypeGroup: + case PBFieldDescriptorProtoTypeTypeMessage: + case PBFieldDescriptorProtoTypeTypeBytes: + case PBFieldDescriptorProtoTypeTypeUint32: + case PBFieldDescriptorProtoTypeTypeEnum: + case PBFieldDescriptorProtoTypeTypeSfixed32: + case PBFieldDescriptorProtoTypeTypeSfixed64: + case PBFieldDescriptorProtoTypeTypeSint32: + case PBFieldDescriptorProtoTypeTypeSint64: + return YES; + default: + return NO; + } +} +BOOL PBFieldDescriptorProtoLabelIsValidValue(PBFieldDescriptorProtoLabel value) { + switch (value) { + case PBFieldDescriptorProtoLabelLabelOptional: + case PBFieldDescriptorProtoLabelLabelRequired: + case PBFieldDescriptorProtoLabelLabelRepeated: + return YES; + default: + return NO; + } +} +@interface PBFieldDescriptorProtoBuilder() +@property (strong) PBFieldDescriptorProto* result; +@end + +@implementation PBFieldDescriptorProtoBuilder +@synthesize result; +- (id) init { + if ((self = [super init])) { + self.result = [[PBFieldDescriptorProto alloc] init]; + } + return self; +} +- (PBGeneratedMessage*) internalGetResult { + return result; +} +- (PBFieldDescriptorProtoBuilder*) clear { + self.result = [[PBFieldDescriptorProto alloc] init]; + return self; +} +- (PBFieldDescriptorProtoBuilder*) clone { + return [PBFieldDescriptorProto builderWithPrototype:result]; +} +- (PBFieldDescriptorProto*) defaultInstance { + return [PBFieldDescriptorProto defaultInstance]; +} +- (PBFieldDescriptorProto*) build { + [self checkInitialized]; + return [self buildPartial]; +} +- (PBFieldDescriptorProto*) buildPartial { + PBFieldDescriptorProto* returnMe = result; + self.result = nil; + return returnMe; +} +- (PBFieldDescriptorProtoBuilder*) mergeFrom:(PBFieldDescriptorProto*) other { + if (other == [PBFieldDescriptorProto defaultInstance]) { + return self; + } + if (other.hasName) { + [self setName:other.name]; + } + if (other.hasNumber) { + [self setNumber:other.number]; + } + if (other.hasLabel) { + [self setLabel:other.label]; + } + if (other.hasType) { + [self setType:other.type]; + } + if (other.hasTypeName) { + [self setTypeName:other.typeName]; + } + if (other.hasExtendee) { + [self setExtendee:other.extendee]; + } + if (other.hasDefaultValue) { + [self setDefaultValue:other.defaultValue]; + } + if (other.hasOneofIndex) { + [self setOneofIndex:other.oneofIndex]; + } + if (other.hasOptions) { + [self mergeOptions:other.options]; + } + [self mergeUnknownFields:other.unknownFields]; + return self; +} +- (PBFieldDescriptorProtoBuilder*) mergeFromCodedInputStream:(PBCodedInputStream*) input { + return [self mergeFromCodedInputStream:input extensionRegistry:[PBExtensionRegistry emptyRegistry]]; +} +- (PBFieldDescriptorProtoBuilder*) mergeFromCodedInputStream:(PBCodedInputStream*) input extensionRegistry:(PBExtensionRegistry*) extensionRegistry { + PBUnknownFieldSetBuilder* unknownFields = [PBUnknownFieldSet builderWithUnknownFields:self.unknownFields]; + while (YES) { + SInt32 tag = [input readTag]; + switch (tag) { + case 0: + [self setUnknownFields:[unknownFields build]]; + return self; + default: { + if (![self parseUnknownField:input unknownFields:unknownFields extensionRegistry:extensionRegistry tag:tag]) { + [self setUnknownFields:[unknownFields build]]; + return self; + } + break; + } + case 10: { + [self setName:[input readString]]; + break; + } + case 18: { + [self setExtendee:[input readString]]; + break; + } + case 24: { + [self setNumber:[input readInt32]]; + break; + } + case 32: { + PBFieldDescriptorProtoLabel value = (PBFieldDescriptorProtoLabel)[input readEnum]; + if (PBFieldDescriptorProtoLabelIsValidValue(value)) { + [self setLabel:value]; + } else { + [unknownFields mergeVarintField:4 value:value]; + } + break; + } + case 40: { + PBFieldDescriptorProtoType value = (PBFieldDescriptorProtoType)[input readEnum]; + if (PBFieldDescriptorProtoTypeIsValidValue(value)) { + [self setType:value]; + } else { + [unknownFields mergeVarintField:5 value:value]; + } + break; + } + case 50: { + [self setTypeName:[input readString]]; + break; + } + case 58: { + [self setDefaultValue:[input readString]]; + break; + } + case 66: { + PBFieldOptionsBuilder* subBuilder = [PBFieldOptions builder]; + if (self.hasOptions) { + [subBuilder mergeFrom:self.options]; + } + [input readMessage:subBuilder extensionRegistry:extensionRegistry]; + [self setOptions:[subBuilder buildPartial]]; + break; + } + case 72: { + [self setOneofIndex:[input readInt32]]; + break; + } + } + } +} +- (BOOL) hasName { + return result.hasName; +} +- (NSString*) name { + return result.name; +} +- (PBFieldDescriptorProtoBuilder*) setName:(NSString*) value { + result.hasName = YES; + result.name = value; + return self; +} +- (PBFieldDescriptorProtoBuilder*) clearName { + result.hasName = NO; + result.name = @""; + return self; +} +- (BOOL) hasNumber { + return result.hasNumber; +} +- (SInt32) number { + return result.number; +} +- (PBFieldDescriptorProtoBuilder*) setNumber:(SInt32) value { + result.hasNumber = YES; + result.number = value; + return self; +} +- (PBFieldDescriptorProtoBuilder*) clearNumber { + result.hasNumber = NO; + result.number = 0; + return self; +} +- (BOOL) hasLabel { + return result.hasLabel; +} +- (PBFieldDescriptorProtoLabel) label { + return result.label; +} +- (PBFieldDescriptorProtoBuilder*) setLabel:(PBFieldDescriptorProtoLabel) value { + result.hasLabel = YES; + result.label = value; + return self; +} +- (PBFieldDescriptorProtoBuilder*) clearLabel { + result.hasLabel = NO; + result.label = PBFieldDescriptorProtoLabelLabelOptional; + return self; +} +- (BOOL) hasType { + return result.hasType; +} +- (PBFieldDescriptorProtoType) type { + return result.type; +} +- (PBFieldDescriptorProtoBuilder*) setType:(PBFieldDescriptorProtoType) value { + result.hasType = YES; + result.type = value; + return self; +} +- (PBFieldDescriptorProtoBuilder*) clearType { + result.hasType = NO; + result.type = PBFieldDescriptorProtoTypeTypeDouble; + return self; +} +- (BOOL) hasTypeName { + return result.hasTypeName; +} +- (NSString*) typeName { + return result.typeName; +} +- (PBFieldDescriptorProtoBuilder*) setTypeName:(NSString*) value { + result.hasTypeName = YES; + result.typeName = value; + return self; +} +- (PBFieldDescriptorProtoBuilder*) clearTypeName { + result.hasTypeName = NO; + result.typeName = @""; + return self; +} +- (BOOL) hasExtendee { + return result.hasExtendee; +} +- (NSString*) extendee { + return result.extendee; +} +- (PBFieldDescriptorProtoBuilder*) setExtendee:(NSString*) value { + result.hasExtendee = YES; + result.extendee = value; + return self; +} +- (PBFieldDescriptorProtoBuilder*) clearExtendee { + result.hasExtendee = NO; + result.extendee = @""; + return self; +} +- (BOOL) hasDefaultValue { + return result.hasDefaultValue; +} +- (NSString*) defaultValue { + return result.defaultValue; +} +- (PBFieldDescriptorProtoBuilder*) setDefaultValue:(NSString*) value { + result.hasDefaultValue = YES; + result.defaultValue = value; + return self; +} +- (PBFieldDescriptorProtoBuilder*) clearDefaultValue { + result.hasDefaultValue = NO; + result.defaultValue = @""; + return self; +} +- (BOOL) hasOneofIndex { + return result.hasOneofIndex; +} +- (SInt32) oneofIndex { + return result.oneofIndex; +} +- (PBFieldDescriptorProtoBuilder*) setOneofIndex:(SInt32) value { + result.hasOneofIndex = YES; + result.oneofIndex = value; + return self; +} +- (PBFieldDescriptorProtoBuilder*) clearOneofIndex { + result.hasOneofIndex = NO; + result.oneofIndex = 0; + return self; +} +- (BOOL) hasOptions { + return result.hasOptions; +} +- (PBFieldOptions*) options { + return result.options; +} +- (PBFieldDescriptorProtoBuilder*) setOptions:(PBFieldOptions*) value { + result.hasOptions = YES; + result.options = value; + return self; +} +- (PBFieldDescriptorProtoBuilder*) setOptionsBuilder:(PBFieldOptionsBuilder*) builderForValue { + return [self setOptions:[builderForValue build]]; +} +- (PBFieldDescriptorProtoBuilder*) mergeOptions:(PBFieldOptions*) value { + if (result.hasOptions && + result.options != [PBFieldOptions defaultInstance]) { + result.options = + [[[PBFieldOptions builderWithPrototype:result.options] mergeFrom:value] buildPartial]; + } else { + result.options = value; + } + result.hasOptions = YES; + return self; +} +- (PBFieldDescriptorProtoBuilder*) clearOptions { + result.hasOptions = NO; + result.options = [PBFieldOptions defaultInstance]; + return self; +} +@end + +@interface PBOneofDescriptorProto () +@property (strong) NSString* name; +@end + +@implementation PBOneofDescriptorProto + +- (BOOL) hasName { + return !!hasName_; +} +- (void) setHasName:(BOOL) value_ { + hasName_ = !!value_; +} +@synthesize name; +- (id) init { + if ((self = [super init])) { + self.name = @""; + } + return self; +} +static PBOneofDescriptorProto* defaultPBOneofDescriptorProtoInstance = nil; ++ (void) initialize { + if (self == [PBOneofDescriptorProto class]) { + defaultPBOneofDescriptorProtoInstance = [[PBOneofDescriptorProto alloc] init]; + } +} ++ (PBOneofDescriptorProto*) defaultInstance { + return defaultPBOneofDescriptorProtoInstance; +} +- (PBOneofDescriptorProto*) defaultInstance { + return defaultPBOneofDescriptorProtoInstance; +} +- (BOOL) isInitialized { + return YES; +} +- (void) writeToCodedOutputStream:(PBCodedOutputStream*) output { + if (self.hasName) { + [output writeString:1 value:self.name]; + } + [self.unknownFields writeToCodedOutputStream:output]; +} +- (SInt32) serializedSize { + __block SInt32 size_ = memoizedSerializedSize; + if (size_ != -1) { + return size_; + } + + size_ = 0; + if (self.hasName) { + size_ += computeStringSize(1, self.name); + } + size_ += self.unknownFields.serializedSize; + memoizedSerializedSize = size_; + return size_; +} ++ (PBOneofDescriptorProto*) parseFromData:(NSData*) data { + return (PBOneofDescriptorProto*)[[[PBOneofDescriptorProto builder] mergeFromData:data] build]; +} ++ (PBOneofDescriptorProto*) parseFromData:(NSData*) data extensionRegistry:(PBExtensionRegistry*) extensionRegistry { + return (PBOneofDescriptorProto*)[[[PBOneofDescriptorProto builder] mergeFromData:data extensionRegistry:extensionRegistry] build]; +} ++ (PBOneofDescriptorProto*) parseFromInputStream:(NSInputStream*) input { + return (PBOneofDescriptorProto*)[[[PBOneofDescriptorProto builder] mergeFromInputStream:input] build]; +} ++ (PBOneofDescriptorProto*) parseFromInputStream:(NSInputStream*) input extensionRegistry:(PBExtensionRegistry*) extensionRegistry { + return (PBOneofDescriptorProto*)[[[PBOneofDescriptorProto builder] mergeFromInputStream:input extensionRegistry:extensionRegistry] build]; +} ++ (PBOneofDescriptorProto*) parseFromCodedInputStream:(PBCodedInputStream*) input { + return (PBOneofDescriptorProto*)[[[PBOneofDescriptorProto builder] mergeFromCodedInputStream:input] build]; +} ++ (PBOneofDescriptorProto*) parseFromCodedInputStream:(PBCodedInputStream*) input extensionRegistry:(PBExtensionRegistry*) extensionRegistry { + return (PBOneofDescriptorProto*)[[[PBOneofDescriptorProto builder] mergeFromCodedInputStream:input extensionRegistry:extensionRegistry] build]; +} ++ (PBOneofDescriptorProtoBuilder*) builder { + return [[PBOneofDescriptorProtoBuilder alloc] init]; +} ++ (PBOneofDescriptorProtoBuilder*) builderWithPrototype:(PBOneofDescriptorProto*) prototype { + return [[PBOneofDescriptorProto builder] mergeFrom:prototype]; +} +- (PBOneofDescriptorProtoBuilder*) builder { + return [PBOneofDescriptorProto builder]; +} +- (PBOneofDescriptorProtoBuilder*) toBuilder { + return [PBOneofDescriptorProto builderWithPrototype:self]; +} +- (void) writeDescriptionTo:(NSMutableString*) output withIndent:(NSString*) indent { + if (self.hasName) { + [output appendFormat:@"%@%@: %@\n", indent, @"name", self.name]; + } + [self.unknownFields writeDescriptionTo:output withIndent:indent]; +} +- (BOOL) isEqual:(id)other { + if (other == self) { + return YES; + } + if (![other isKindOfClass:[PBOneofDescriptorProto class]]) { + return NO; + } + PBOneofDescriptorProto *otherMessage = other; + return + self.hasName == otherMessage.hasName && + (!self.hasName || [self.name isEqual:otherMessage.name]) && + (self.unknownFields == otherMessage.unknownFields || (self.unknownFields != nil && [self.unknownFields isEqual:otherMessage.unknownFields])); +} +- (NSUInteger) hash { + __block NSUInteger hashCode = 7; + if (self.hasName) { + hashCode = hashCode * 31 + [self.name hash]; + } + hashCode = hashCode * 31 + [self.unknownFields hash]; + return hashCode; +} +@end + +@interface PBOneofDescriptorProtoBuilder() +@property (strong) PBOneofDescriptorProto* result; +@end + +@implementation PBOneofDescriptorProtoBuilder +@synthesize result; +- (id) init { + if ((self = [super init])) { + self.result = [[PBOneofDescriptorProto alloc] init]; + } + return self; +} +- (PBGeneratedMessage*) internalGetResult { + return result; +} +- (PBOneofDescriptorProtoBuilder*) clear { + self.result = [[PBOneofDescriptorProto alloc] init]; + return self; +} +- (PBOneofDescriptorProtoBuilder*) clone { + return [PBOneofDescriptorProto builderWithPrototype:result]; +} +- (PBOneofDescriptorProto*) defaultInstance { + return [PBOneofDescriptorProto defaultInstance]; +} +- (PBOneofDescriptorProto*) build { + [self checkInitialized]; + return [self buildPartial]; +} +- (PBOneofDescriptorProto*) buildPartial { + PBOneofDescriptorProto* returnMe = result; + self.result = nil; + return returnMe; +} +- (PBOneofDescriptorProtoBuilder*) mergeFrom:(PBOneofDescriptorProto*) other { + if (other == [PBOneofDescriptorProto defaultInstance]) { + return self; + } + if (other.hasName) { + [self setName:other.name]; + } + [self mergeUnknownFields:other.unknownFields]; + return self; +} +- (PBOneofDescriptorProtoBuilder*) mergeFromCodedInputStream:(PBCodedInputStream*) input { + return [self mergeFromCodedInputStream:input extensionRegistry:[PBExtensionRegistry emptyRegistry]]; +} +- (PBOneofDescriptorProtoBuilder*) mergeFromCodedInputStream:(PBCodedInputStream*) input extensionRegistry:(PBExtensionRegistry*) extensionRegistry { + PBUnknownFieldSetBuilder* unknownFields = [PBUnknownFieldSet builderWithUnknownFields:self.unknownFields]; + while (YES) { + SInt32 tag = [input readTag]; + switch (tag) { + case 0: + [self setUnknownFields:[unknownFields build]]; + return self; + default: { + if (![self parseUnknownField:input unknownFields:unknownFields extensionRegistry:extensionRegistry tag:tag]) { + [self setUnknownFields:[unknownFields build]]; + return self; + } + break; + } + case 10: { + [self setName:[input readString]]; + break; + } + } + } +} +- (BOOL) hasName { + return result.hasName; +} +- (NSString*) name { + return result.name; +} +- (PBOneofDescriptorProtoBuilder*) setName:(NSString*) value { + result.hasName = YES; + result.name = value; + return self; +} +- (PBOneofDescriptorProtoBuilder*) clearName { + result.hasName = NO; + result.name = @""; + return self; +} +@end + +@interface PBEnumDescriptorProto () +@property (strong) NSString* name; +@property (strong) NSMutableArray * valueArray; +@property (strong) PBEnumOptions* options; +@end + +@implementation PBEnumDescriptorProto + +- (BOOL) hasName { + return !!hasName_; +} +- (void) setHasName:(BOOL) value_ { + hasName_ = !!value_; +} +@synthesize name; +@synthesize valueArray; +@dynamic value; +- (BOOL) hasOptions { + return !!hasOptions_; +} +- (void) setHasOptions:(BOOL) value_ { + hasOptions_ = !!value_; +} +@synthesize options; +- (id) init { + if ((self = [super init])) { + self.name = @""; + self.options = [PBEnumOptions defaultInstance]; + } + return self; +} +static PBEnumDescriptorProto* defaultPBEnumDescriptorProtoInstance = nil; ++ (void) initialize { + if (self == [PBEnumDescriptorProto class]) { + defaultPBEnumDescriptorProtoInstance = [[PBEnumDescriptorProto alloc] init]; + } +} ++ (PBEnumDescriptorProto*) defaultInstance { + return defaultPBEnumDescriptorProtoInstance; +} +- (PBEnumDescriptorProto*) defaultInstance { + return defaultPBEnumDescriptorProtoInstance; +} +- (NSArray *)value { + return valueArray; +} +- (PBEnumValueDescriptorProto*)valueAtIndex:(NSUInteger)index { + return [valueArray objectAtIndex:index]; +} +- (BOOL) isInitialized { + __block BOOL isInitvalue = YES; + [self.value enumerateObjectsUsingBlock:^(PBEnumValueDescriptorProto *element, NSUInteger idx, BOOL *stop) { + if (!element.isInitialized) { + isInitvalue = NO; + *stop = YES; + } + }]; + if (!isInitvalue) return isInitvalue; + if (self.hasOptions) { + if (!self.options.isInitialized) { + return NO; + } + } + return YES; +} +- (void) writeToCodedOutputStream:(PBCodedOutputStream*) output { + if (self.hasName) { + [output writeString:1 value:self.name]; + } + [self.valueArray enumerateObjectsUsingBlock:^(PBEnumValueDescriptorProto *element, NSUInteger idx, BOOL *stop) { + [output writeMessage:2 value:element]; + }]; + if (self.hasOptions) { + [output writeMessage:3 value:self.options]; + } + [self.unknownFields writeToCodedOutputStream:output]; +} +- (SInt32) serializedSize { + __block SInt32 size_ = memoizedSerializedSize; + if (size_ != -1) { + return size_; + } + + size_ = 0; + if (self.hasName) { + size_ += computeStringSize(1, self.name); + } + [self.valueArray enumerateObjectsUsingBlock:^(PBEnumValueDescriptorProto *element, NSUInteger idx, BOOL *stop) { + size_ += computeMessageSize(2, element); + }]; + if (self.hasOptions) { + size_ += computeMessageSize(3, self.options); + } + size_ += self.unknownFields.serializedSize; + memoizedSerializedSize = size_; + return size_; +} ++ (PBEnumDescriptorProto*) parseFromData:(NSData*) data { + return (PBEnumDescriptorProto*)[[[PBEnumDescriptorProto builder] mergeFromData:data] build]; +} ++ (PBEnumDescriptorProto*) parseFromData:(NSData*) data extensionRegistry:(PBExtensionRegistry*) extensionRegistry { + return (PBEnumDescriptorProto*)[[[PBEnumDescriptorProto builder] mergeFromData:data extensionRegistry:extensionRegistry] build]; +} ++ (PBEnumDescriptorProto*) parseFromInputStream:(NSInputStream*) input { + return (PBEnumDescriptorProto*)[[[PBEnumDescriptorProto builder] mergeFromInputStream:input] build]; +} ++ (PBEnumDescriptorProto*) parseFromInputStream:(NSInputStream*) input extensionRegistry:(PBExtensionRegistry*) extensionRegistry { + return (PBEnumDescriptorProto*)[[[PBEnumDescriptorProto builder] mergeFromInputStream:input extensionRegistry:extensionRegistry] build]; +} ++ (PBEnumDescriptorProto*) parseFromCodedInputStream:(PBCodedInputStream*) input { + return (PBEnumDescriptorProto*)[[[PBEnumDescriptorProto builder] mergeFromCodedInputStream:input] build]; +} ++ (PBEnumDescriptorProto*) parseFromCodedInputStream:(PBCodedInputStream*) input extensionRegistry:(PBExtensionRegistry*) extensionRegistry { + return (PBEnumDescriptorProto*)[[[PBEnumDescriptorProto builder] mergeFromCodedInputStream:input extensionRegistry:extensionRegistry] build]; +} ++ (PBEnumDescriptorProtoBuilder*) builder { + return [[PBEnumDescriptorProtoBuilder alloc] init]; +} ++ (PBEnumDescriptorProtoBuilder*) builderWithPrototype:(PBEnumDescriptorProto*) prototype { + return [[PBEnumDescriptorProto builder] mergeFrom:prototype]; +} +- (PBEnumDescriptorProtoBuilder*) builder { + return [PBEnumDescriptorProto builder]; +} +- (PBEnumDescriptorProtoBuilder*) toBuilder { + return [PBEnumDescriptorProto builderWithPrototype:self]; +} +- (void) writeDescriptionTo:(NSMutableString*) output withIndent:(NSString*) indent { + if (self.hasName) { + [output appendFormat:@"%@%@: %@\n", indent, @"name", self.name]; + } + [self.valueArray enumerateObjectsUsingBlock:^(PBEnumValueDescriptorProto *element, NSUInteger idx, BOOL *stop) { + [output appendFormat:@"%@%@ {\n", indent, @"value"]; + [element writeDescriptionTo:output + withIndent:[NSString stringWithFormat:@"%@ ", indent]]; + [output appendFormat:@"%@}\n", indent]; + }]; + if (self.hasOptions) { + [output appendFormat:@"%@%@ {\n", indent, @"options"]; + [self.options writeDescriptionTo:output + withIndent:[NSString stringWithFormat:@"%@ ", indent]]; + [output appendFormat:@"%@}\n", indent]; + } + [self.unknownFields writeDescriptionTo:output withIndent:indent]; +} +- (BOOL) isEqual:(id)other { + if (other == self) { + return YES; + } + if (![other isKindOfClass:[PBEnumDescriptorProto class]]) { + return NO; + } + PBEnumDescriptorProto *otherMessage = other; + return + self.hasName == otherMessage.hasName && + (!self.hasName || [self.name isEqual:otherMessage.name]) && + [self.valueArray isEqualToArray:otherMessage.valueArray] && + self.hasOptions == otherMessage.hasOptions && + (!self.hasOptions || [self.options isEqual:otherMessage.options]) && + (self.unknownFields == otherMessage.unknownFields || (self.unknownFields != nil && [self.unknownFields isEqual:otherMessage.unknownFields])); +} +- (NSUInteger) hash { + __block NSUInteger hashCode = 7; + if (self.hasName) { + hashCode = hashCode * 31 + [self.name hash]; + } + [self.valueArray enumerateObjectsUsingBlock:^(PBEnumValueDescriptorProto *element, NSUInteger idx, BOOL *stop) { + hashCode = hashCode * 31 + [element hash]; + }]; + if (self.hasOptions) { + hashCode = hashCode * 31 + [self.options hash]; + } + hashCode = hashCode * 31 + [self.unknownFields hash]; + return hashCode; +} +@end + +@interface PBEnumDescriptorProtoBuilder() +@property (strong) PBEnumDescriptorProto* result; +@end + +@implementation PBEnumDescriptorProtoBuilder +@synthesize result; +- (id) init { + if ((self = [super init])) { + self.result = [[PBEnumDescriptorProto alloc] init]; + } + return self; +} +- (PBGeneratedMessage*) internalGetResult { + return result; +} +- (PBEnumDescriptorProtoBuilder*) clear { + self.result = [[PBEnumDescriptorProto alloc] init]; + return self; +} +- (PBEnumDescriptorProtoBuilder*) clone { + return [PBEnumDescriptorProto builderWithPrototype:result]; +} +- (PBEnumDescriptorProto*) defaultInstance { + return [PBEnumDescriptorProto defaultInstance]; +} +- (PBEnumDescriptorProto*) build { + [self checkInitialized]; + return [self buildPartial]; +} +- (PBEnumDescriptorProto*) buildPartial { + PBEnumDescriptorProto* returnMe = result; + self.result = nil; + return returnMe; +} +- (PBEnumDescriptorProtoBuilder*) mergeFrom:(PBEnumDescriptorProto*) other { + if (other == [PBEnumDescriptorProto defaultInstance]) { + return self; + } + if (other.hasName) { + [self setName:other.name]; + } + if (other.valueArray.count > 0) { + if (result.valueArray == nil) { + result.valueArray = [[NSMutableArray alloc] initWithArray:other.valueArray]; + } else { + [result.valueArray addObjectsFromArray:other.valueArray]; + } + } + if (other.hasOptions) { + [self mergeOptions:other.options]; + } + [self mergeUnknownFields:other.unknownFields]; + return self; +} +- (PBEnumDescriptorProtoBuilder*) mergeFromCodedInputStream:(PBCodedInputStream*) input { + return [self mergeFromCodedInputStream:input extensionRegistry:[PBExtensionRegistry emptyRegistry]]; +} +- (PBEnumDescriptorProtoBuilder*) mergeFromCodedInputStream:(PBCodedInputStream*) input extensionRegistry:(PBExtensionRegistry*) extensionRegistry { + PBUnknownFieldSetBuilder* unknownFields = [PBUnknownFieldSet builderWithUnknownFields:self.unknownFields]; + while (YES) { + SInt32 tag = [input readTag]; + switch (tag) { + case 0: + [self setUnknownFields:[unknownFields build]]; + return self; + default: { + if (![self parseUnknownField:input unknownFields:unknownFields extensionRegistry:extensionRegistry tag:tag]) { + [self setUnknownFields:[unknownFields build]]; + return self; + } + break; + } + case 10: { + [self setName:[input readString]]; + break; + } + case 18: { + PBEnumValueDescriptorProtoBuilder* subBuilder = [PBEnumValueDescriptorProto builder]; + [input readMessage:subBuilder extensionRegistry:extensionRegistry]; + [self addValue:[subBuilder buildPartial]]; + break; + } + case 26: { + PBEnumOptionsBuilder* subBuilder = [PBEnumOptions builder]; + if (self.hasOptions) { + [subBuilder mergeFrom:self.options]; + } + [input readMessage:subBuilder extensionRegistry:extensionRegistry]; + [self setOptions:[subBuilder buildPartial]]; + break; + } + } + } +} +- (BOOL) hasName { + return result.hasName; +} +- (NSString*) name { + return result.name; +} +- (PBEnumDescriptorProtoBuilder*) setName:(NSString*) value { + result.hasName = YES; + result.name = value; + return self; +} +- (PBEnumDescriptorProtoBuilder*) clearName { + result.hasName = NO; + result.name = @""; + return self; +} +- (NSMutableArray *)value { + return result.valueArray; +} +- (PBEnumValueDescriptorProto*)valueAtIndex:(NSUInteger)index { + return [result valueAtIndex:index]; +} +- (PBEnumDescriptorProtoBuilder *)addValue:(PBEnumValueDescriptorProto*)value { + if (result.valueArray == nil) { + result.valueArray = [[NSMutableArray alloc]init]; + } + [result.valueArray addObject:value]; + return self; +} +- (PBEnumDescriptorProtoBuilder *)setValueArray:(NSArray *)array { + result.valueArray = [[NSMutableArray alloc]initWithArray:array]; + return self; +} +- (PBEnumDescriptorProtoBuilder *)clearValue { + result.valueArray = nil; + return self; +} +- (BOOL) hasOptions { + return result.hasOptions; +} +- (PBEnumOptions*) options { + return result.options; +} +- (PBEnumDescriptorProtoBuilder*) setOptions:(PBEnumOptions*) value { + result.hasOptions = YES; + result.options = value; + return self; +} +- (PBEnumDescriptorProtoBuilder*) setOptionsBuilder:(PBEnumOptionsBuilder*) builderForValue { + return [self setOptions:[builderForValue build]]; +} +- (PBEnumDescriptorProtoBuilder*) mergeOptions:(PBEnumOptions*) value { + if (result.hasOptions && + result.options != [PBEnumOptions defaultInstance]) { + result.options = + [[[PBEnumOptions builderWithPrototype:result.options] mergeFrom:value] buildPartial]; + } else { + result.options = value; + } + result.hasOptions = YES; + return self; +} +- (PBEnumDescriptorProtoBuilder*) clearOptions { + result.hasOptions = NO; + result.options = [PBEnumOptions defaultInstance]; + return self; +} +@end + +@interface PBEnumValueDescriptorProto () +@property (strong) NSString* name; +@property SInt32 number; +@property (strong) PBEnumValueOptions* options; +@end + +@implementation PBEnumValueDescriptorProto + +- (BOOL) hasName { + return !!hasName_; +} +- (void) setHasName:(BOOL) value_ { + hasName_ = !!value_; +} +@synthesize name; +- (BOOL) hasNumber { + return !!hasNumber_; +} +- (void) setHasNumber:(BOOL) value_ { + hasNumber_ = !!value_; +} +@synthesize number; +- (BOOL) hasOptions { + return !!hasOptions_; +} +- (void) setHasOptions:(BOOL) value_ { + hasOptions_ = !!value_; +} +@synthesize options; +- (id) init { + if ((self = [super init])) { + self.name = @""; + self.number = 0; + self.options = [PBEnumValueOptions defaultInstance]; + } + return self; +} +static PBEnumValueDescriptorProto* defaultPBEnumValueDescriptorProtoInstance = nil; ++ (void) initialize { + if (self == [PBEnumValueDescriptorProto class]) { + defaultPBEnumValueDescriptorProtoInstance = [[PBEnumValueDescriptorProto alloc] init]; + } +} ++ (PBEnumValueDescriptorProto*) defaultInstance { + return defaultPBEnumValueDescriptorProtoInstance; +} +- (PBEnumValueDescriptorProto*) defaultInstance { + return defaultPBEnumValueDescriptorProtoInstance; +} +- (BOOL) isInitialized { + if (self.hasOptions) { + if (!self.options.isInitialized) { + return NO; + } + } + return YES; +} +- (void) writeToCodedOutputStream:(PBCodedOutputStream*) output { + if (self.hasName) { + [output writeString:1 value:self.name]; + } + if (self.hasNumber) { + [output writeInt32:2 value:self.number]; + } + if (self.hasOptions) { + [output writeMessage:3 value:self.options]; + } + [self.unknownFields writeToCodedOutputStream:output]; +} +- (SInt32) serializedSize { + __block SInt32 size_ = memoizedSerializedSize; + if (size_ != -1) { + return size_; + } + + size_ = 0; + if (self.hasName) { + size_ += computeStringSize(1, self.name); + } + if (self.hasNumber) { + size_ += computeInt32Size(2, self.number); + } + if (self.hasOptions) { + size_ += computeMessageSize(3, self.options); + } + size_ += self.unknownFields.serializedSize; + memoizedSerializedSize = size_; + return size_; +} ++ (PBEnumValueDescriptorProto*) parseFromData:(NSData*) data { + return (PBEnumValueDescriptorProto*)[[[PBEnumValueDescriptorProto builder] mergeFromData:data] build]; +} ++ (PBEnumValueDescriptorProto*) parseFromData:(NSData*) data extensionRegistry:(PBExtensionRegistry*) extensionRegistry { + return (PBEnumValueDescriptorProto*)[[[PBEnumValueDescriptorProto builder] mergeFromData:data extensionRegistry:extensionRegistry] build]; +} ++ (PBEnumValueDescriptorProto*) parseFromInputStream:(NSInputStream*) input { + return (PBEnumValueDescriptorProto*)[[[PBEnumValueDescriptorProto builder] mergeFromInputStream:input] build]; +} ++ (PBEnumValueDescriptorProto*) parseFromInputStream:(NSInputStream*) input extensionRegistry:(PBExtensionRegistry*) extensionRegistry { + return (PBEnumValueDescriptorProto*)[[[PBEnumValueDescriptorProto builder] mergeFromInputStream:input extensionRegistry:extensionRegistry] build]; +} ++ (PBEnumValueDescriptorProto*) parseFromCodedInputStream:(PBCodedInputStream*) input { + return (PBEnumValueDescriptorProto*)[[[PBEnumValueDescriptorProto builder] mergeFromCodedInputStream:input] build]; +} ++ (PBEnumValueDescriptorProto*) parseFromCodedInputStream:(PBCodedInputStream*) input extensionRegistry:(PBExtensionRegistry*) extensionRegistry { + return (PBEnumValueDescriptorProto*)[[[PBEnumValueDescriptorProto builder] mergeFromCodedInputStream:input extensionRegistry:extensionRegistry] build]; +} ++ (PBEnumValueDescriptorProtoBuilder*) builder { + return [[PBEnumValueDescriptorProtoBuilder alloc] init]; +} ++ (PBEnumValueDescriptorProtoBuilder*) builderWithPrototype:(PBEnumValueDescriptorProto*) prototype { + return [[PBEnumValueDescriptorProto builder] mergeFrom:prototype]; +} +- (PBEnumValueDescriptorProtoBuilder*) builder { + return [PBEnumValueDescriptorProto builder]; +} +- (PBEnumValueDescriptorProtoBuilder*) toBuilder { + return [PBEnumValueDescriptorProto builderWithPrototype:self]; +} +- (void) writeDescriptionTo:(NSMutableString*) output withIndent:(NSString*) indent { + if (self.hasName) { + [output appendFormat:@"%@%@: %@\n", indent, @"name", self.name]; + } + if (self.hasNumber) { + [output appendFormat:@"%@%@: %@\n", indent, @"number", [NSNumber numberWithInteger:self.number]]; + } + if (self.hasOptions) { + [output appendFormat:@"%@%@ {\n", indent, @"options"]; + [self.options writeDescriptionTo:output + withIndent:[NSString stringWithFormat:@"%@ ", indent]]; + [output appendFormat:@"%@}\n", indent]; + } + [self.unknownFields writeDescriptionTo:output withIndent:indent]; +} +- (BOOL) isEqual:(id)other { + if (other == self) { + return YES; + } + if (![other isKindOfClass:[PBEnumValueDescriptorProto class]]) { + return NO; + } + PBEnumValueDescriptorProto *otherMessage = other; + return + self.hasName == otherMessage.hasName && + (!self.hasName || [self.name isEqual:otherMessage.name]) && + self.hasNumber == otherMessage.hasNumber && + (!self.hasNumber || self.number == otherMessage.number) && + self.hasOptions == otherMessage.hasOptions && + (!self.hasOptions || [self.options isEqual:otherMessage.options]) && + (self.unknownFields == otherMessage.unknownFields || (self.unknownFields != nil && [self.unknownFields isEqual:otherMessage.unknownFields])); +} +- (NSUInteger) hash { + __block NSUInteger hashCode = 7; + if (self.hasName) { + hashCode = hashCode * 31 + [self.name hash]; + } + if (self.hasNumber) { + hashCode = hashCode * 31 + [[NSNumber numberWithInteger:self.number] hash]; + } + if (self.hasOptions) { + hashCode = hashCode * 31 + [self.options hash]; + } + hashCode = hashCode * 31 + [self.unknownFields hash]; + return hashCode; +} +@end + +@interface PBEnumValueDescriptorProtoBuilder() +@property (strong) PBEnumValueDescriptorProto* result; +@end + +@implementation PBEnumValueDescriptorProtoBuilder +@synthesize result; +- (id) init { + if ((self = [super init])) { + self.result = [[PBEnumValueDescriptorProto alloc] init]; + } + return self; +} +- (PBGeneratedMessage*) internalGetResult { + return result; +} +- (PBEnumValueDescriptorProtoBuilder*) clear { + self.result = [[PBEnumValueDescriptorProto alloc] init]; + return self; +} +- (PBEnumValueDescriptorProtoBuilder*) clone { + return [PBEnumValueDescriptorProto builderWithPrototype:result]; +} +- (PBEnumValueDescriptorProto*) defaultInstance { + return [PBEnumValueDescriptorProto defaultInstance]; +} +- (PBEnumValueDescriptorProto*) build { + [self checkInitialized]; + return [self buildPartial]; +} +- (PBEnumValueDescriptorProto*) buildPartial { + PBEnumValueDescriptorProto* returnMe = result; + self.result = nil; + return returnMe; +} +- (PBEnumValueDescriptorProtoBuilder*) mergeFrom:(PBEnumValueDescriptorProto*) other { + if (other == [PBEnumValueDescriptorProto defaultInstance]) { + return self; + } + if (other.hasName) { + [self setName:other.name]; + } + if (other.hasNumber) { + [self setNumber:other.number]; + } + if (other.hasOptions) { + [self mergeOptions:other.options]; + } + [self mergeUnknownFields:other.unknownFields]; + return self; +} +- (PBEnumValueDescriptorProtoBuilder*) mergeFromCodedInputStream:(PBCodedInputStream*) input { + return [self mergeFromCodedInputStream:input extensionRegistry:[PBExtensionRegistry emptyRegistry]]; +} +- (PBEnumValueDescriptorProtoBuilder*) mergeFromCodedInputStream:(PBCodedInputStream*) input extensionRegistry:(PBExtensionRegistry*) extensionRegistry { + PBUnknownFieldSetBuilder* unknownFields = [PBUnknownFieldSet builderWithUnknownFields:self.unknownFields]; + while (YES) { + SInt32 tag = [input readTag]; + switch (tag) { + case 0: + [self setUnknownFields:[unknownFields build]]; + return self; + default: { + if (![self parseUnknownField:input unknownFields:unknownFields extensionRegistry:extensionRegistry tag:tag]) { + [self setUnknownFields:[unknownFields build]]; + return self; + } + break; + } + case 10: { + [self setName:[input readString]]; + break; + } + case 16: { + [self setNumber:[input readInt32]]; + break; + } + case 26: { + PBEnumValueOptionsBuilder* subBuilder = [PBEnumValueOptions builder]; + if (self.hasOptions) { + [subBuilder mergeFrom:self.options]; + } + [input readMessage:subBuilder extensionRegistry:extensionRegistry]; + [self setOptions:[subBuilder buildPartial]]; + break; + } + } + } +} +- (BOOL) hasName { + return result.hasName; +} +- (NSString*) name { + return result.name; +} +- (PBEnumValueDescriptorProtoBuilder*) setName:(NSString*) value { + result.hasName = YES; + result.name = value; + return self; +} +- (PBEnumValueDescriptorProtoBuilder*) clearName { + result.hasName = NO; + result.name = @""; + return self; +} +- (BOOL) hasNumber { + return result.hasNumber; +} +- (SInt32) number { + return result.number; +} +- (PBEnumValueDescriptorProtoBuilder*) setNumber:(SInt32) value { + result.hasNumber = YES; + result.number = value; + return self; +} +- (PBEnumValueDescriptorProtoBuilder*) clearNumber { + result.hasNumber = NO; + result.number = 0; + return self; +} +- (BOOL) hasOptions { + return result.hasOptions; +} +- (PBEnumValueOptions*) options { + return result.options; +} +- (PBEnumValueDescriptorProtoBuilder*) setOptions:(PBEnumValueOptions*) value { + result.hasOptions = YES; + result.options = value; + return self; +} +- (PBEnumValueDescriptorProtoBuilder*) setOptionsBuilder:(PBEnumValueOptionsBuilder*) builderForValue { + return [self setOptions:[builderForValue build]]; +} +- (PBEnumValueDescriptorProtoBuilder*) mergeOptions:(PBEnumValueOptions*) value { + if (result.hasOptions && + result.options != [PBEnumValueOptions defaultInstance]) { + result.options = + [[[PBEnumValueOptions builderWithPrototype:result.options] mergeFrom:value] buildPartial]; + } else { + result.options = value; + } + result.hasOptions = YES; + return self; +} +- (PBEnumValueDescriptorProtoBuilder*) clearOptions { + result.hasOptions = NO; + result.options = [PBEnumValueOptions defaultInstance]; + return self; +} +@end + +@interface PBServiceDescriptorProto () +@property (strong) NSString* name; +@property (strong) NSMutableArray * methodArray; +@property (strong) PBServiceOptions* options; +@end + +@implementation PBServiceDescriptorProto + +- (BOOL) hasName { + return !!hasName_; +} +- (void) setHasName:(BOOL) value_ { + hasName_ = !!value_; +} +@synthesize name; +@synthesize methodArray; +@dynamic method; +- (BOOL) hasOptions { + return !!hasOptions_; +} +- (void) setHasOptions:(BOOL) value_ { + hasOptions_ = !!value_; +} +@synthesize options; +- (id) init { + if ((self = [super init])) { + self.name = @""; + self.options = [PBServiceOptions defaultInstance]; + } + return self; +} +static PBServiceDescriptorProto* defaultPBServiceDescriptorProtoInstance = nil; ++ (void) initialize { + if (self == [PBServiceDescriptorProto class]) { + defaultPBServiceDescriptorProtoInstance = [[PBServiceDescriptorProto alloc] init]; + } +} ++ (PBServiceDescriptorProto*) defaultInstance { + return defaultPBServiceDescriptorProtoInstance; +} +- (PBServiceDescriptorProto*) defaultInstance { + return defaultPBServiceDescriptorProtoInstance; +} +- (NSArray *)method { + return methodArray; +} +- (PBMethodDescriptorProto*)methodAtIndex:(NSUInteger)index { + return [methodArray objectAtIndex:index]; +} +- (BOOL) isInitialized { + __block BOOL isInitmethod = YES; + [self.method enumerateObjectsUsingBlock:^(PBMethodDescriptorProto *element, NSUInteger idx, BOOL *stop) { + if (!element.isInitialized) { + isInitmethod = NO; + *stop = YES; + } + }]; + if (!isInitmethod) return isInitmethod; + if (self.hasOptions) { + if (!self.options.isInitialized) { + return NO; + } + } + return YES; +} +- (void) writeToCodedOutputStream:(PBCodedOutputStream*) output { + if (self.hasName) { + [output writeString:1 value:self.name]; + } + [self.methodArray enumerateObjectsUsingBlock:^(PBMethodDescriptorProto *element, NSUInteger idx, BOOL *stop) { + [output writeMessage:2 value:element]; + }]; + if (self.hasOptions) { + [output writeMessage:3 value:self.options]; + } + [self.unknownFields writeToCodedOutputStream:output]; +} +- (SInt32) serializedSize { + __block SInt32 size_ = memoizedSerializedSize; + if (size_ != -1) { + return size_; + } + + size_ = 0; + if (self.hasName) { + size_ += computeStringSize(1, self.name); + } + [self.methodArray enumerateObjectsUsingBlock:^(PBMethodDescriptorProto *element, NSUInteger idx, BOOL *stop) { + size_ += computeMessageSize(2, element); + }]; + if (self.hasOptions) { + size_ += computeMessageSize(3, self.options); + } + size_ += self.unknownFields.serializedSize; + memoizedSerializedSize = size_; + return size_; +} ++ (PBServiceDescriptorProto*) parseFromData:(NSData*) data { + return (PBServiceDescriptorProto*)[[[PBServiceDescriptorProto builder] mergeFromData:data] build]; +} ++ (PBServiceDescriptorProto*) parseFromData:(NSData*) data extensionRegistry:(PBExtensionRegistry*) extensionRegistry { + return (PBServiceDescriptorProto*)[[[PBServiceDescriptorProto builder] mergeFromData:data extensionRegistry:extensionRegistry] build]; +} ++ (PBServiceDescriptorProto*) parseFromInputStream:(NSInputStream*) input { + return (PBServiceDescriptorProto*)[[[PBServiceDescriptorProto builder] mergeFromInputStream:input] build]; +} ++ (PBServiceDescriptorProto*) parseFromInputStream:(NSInputStream*) input extensionRegistry:(PBExtensionRegistry*) extensionRegistry { + return (PBServiceDescriptorProto*)[[[PBServiceDescriptorProto builder] mergeFromInputStream:input extensionRegistry:extensionRegistry] build]; +} ++ (PBServiceDescriptorProto*) parseFromCodedInputStream:(PBCodedInputStream*) input { + return (PBServiceDescriptorProto*)[[[PBServiceDescriptorProto builder] mergeFromCodedInputStream:input] build]; +} ++ (PBServiceDescriptorProto*) parseFromCodedInputStream:(PBCodedInputStream*) input extensionRegistry:(PBExtensionRegistry*) extensionRegistry { + return (PBServiceDescriptorProto*)[[[PBServiceDescriptorProto builder] mergeFromCodedInputStream:input extensionRegistry:extensionRegistry] build]; +} ++ (PBServiceDescriptorProtoBuilder*) builder { + return [[PBServiceDescriptorProtoBuilder alloc] init]; +} ++ (PBServiceDescriptorProtoBuilder*) builderWithPrototype:(PBServiceDescriptorProto*) prototype { + return [[PBServiceDescriptorProto builder] mergeFrom:prototype]; +} +- (PBServiceDescriptorProtoBuilder*) builder { + return [PBServiceDescriptorProto builder]; +} +- (PBServiceDescriptorProtoBuilder*) toBuilder { + return [PBServiceDescriptorProto builderWithPrototype:self]; +} +- (void) writeDescriptionTo:(NSMutableString*) output withIndent:(NSString*) indent { + if (self.hasName) { + [output appendFormat:@"%@%@: %@\n", indent, @"name", self.name]; + } + [self.methodArray enumerateObjectsUsingBlock:^(PBMethodDescriptorProto *element, NSUInteger idx, BOOL *stop) { + [output appendFormat:@"%@%@ {\n", indent, @"method"]; + [element writeDescriptionTo:output + withIndent:[NSString stringWithFormat:@"%@ ", indent]]; + [output appendFormat:@"%@}\n", indent]; + }]; + if (self.hasOptions) { + [output appendFormat:@"%@%@ {\n", indent, @"options"]; + [self.options writeDescriptionTo:output + withIndent:[NSString stringWithFormat:@"%@ ", indent]]; + [output appendFormat:@"%@}\n", indent]; + } + [self.unknownFields writeDescriptionTo:output withIndent:indent]; +} +- (BOOL) isEqual:(id)other { + if (other == self) { + return YES; + } + if (![other isKindOfClass:[PBServiceDescriptorProto class]]) { + return NO; + } + PBServiceDescriptorProto *otherMessage = other; + return + self.hasName == otherMessage.hasName && + (!self.hasName || [self.name isEqual:otherMessage.name]) && + [self.methodArray isEqualToArray:otherMessage.methodArray] && + self.hasOptions == otherMessage.hasOptions && + (!self.hasOptions || [self.options isEqual:otherMessage.options]) && + (self.unknownFields == otherMessage.unknownFields || (self.unknownFields != nil && [self.unknownFields isEqual:otherMessage.unknownFields])); +} +- (NSUInteger) hash { + __block NSUInteger hashCode = 7; + if (self.hasName) { + hashCode = hashCode * 31 + [self.name hash]; + } + [self.methodArray enumerateObjectsUsingBlock:^(PBMethodDescriptorProto *element, NSUInteger idx, BOOL *stop) { + hashCode = hashCode * 31 + [element hash]; + }]; + if (self.hasOptions) { + hashCode = hashCode * 31 + [self.options hash]; + } + hashCode = hashCode * 31 + [self.unknownFields hash]; + return hashCode; +} +@end + +@interface PBServiceDescriptorProtoBuilder() +@property (strong) PBServiceDescriptorProto* result; +@end + +@implementation PBServiceDescriptorProtoBuilder +@synthesize result; +- (id) init { + if ((self = [super init])) { + self.result = [[PBServiceDescriptorProto alloc] init]; + } + return self; +} +- (PBGeneratedMessage*) internalGetResult { + return result; +} +- (PBServiceDescriptorProtoBuilder*) clear { + self.result = [[PBServiceDescriptorProto alloc] init]; + return self; +} +- (PBServiceDescriptorProtoBuilder*) clone { + return [PBServiceDescriptorProto builderWithPrototype:result]; +} +- (PBServiceDescriptorProto*) defaultInstance { + return [PBServiceDescriptorProto defaultInstance]; +} +- (PBServiceDescriptorProto*) build { + [self checkInitialized]; + return [self buildPartial]; +} +- (PBServiceDescriptorProto*) buildPartial { + PBServiceDescriptorProto* returnMe = result; + self.result = nil; + return returnMe; +} +- (PBServiceDescriptorProtoBuilder*) mergeFrom:(PBServiceDescriptorProto*) other { + if (other == [PBServiceDescriptorProto defaultInstance]) { + return self; + } + if (other.hasName) { + [self setName:other.name]; + } + if (other.methodArray.count > 0) { + if (result.methodArray == nil) { + result.methodArray = [[NSMutableArray alloc] initWithArray:other.methodArray]; + } else { + [result.methodArray addObjectsFromArray:other.methodArray]; + } + } + if (other.hasOptions) { + [self mergeOptions:other.options]; + } + [self mergeUnknownFields:other.unknownFields]; + return self; +} +- (PBServiceDescriptorProtoBuilder*) mergeFromCodedInputStream:(PBCodedInputStream*) input { + return [self mergeFromCodedInputStream:input extensionRegistry:[PBExtensionRegistry emptyRegistry]]; +} +- (PBServiceDescriptorProtoBuilder*) mergeFromCodedInputStream:(PBCodedInputStream*) input extensionRegistry:(PBExtensionRegistry*) extensionRegistry { + PBUnknownFieldSetBuilder* unknownFields = [PBUnknownFieldSet builderWithUnknownFields:self.unknownFields]; + while (YES) { + SInt32 tag = [input readTag]; + switch (tag) { + case 0: + [self setUnknownFields:[unknownFields build]]; + return self; + default: { + if (![self parseUnknownField:input unknownFields:unknownFields extensionRegistry:extensionRegistry tag:tag]) { + [self setUnknownFields:[unknownFields build]]; + return self; + } + break; + } + case 10: { + [self setName:[input readString]]; + break; + } + case 18: { + PBMethodDescriptorProtoBuilder* subBuilder = [PBMethodDescriptorProto builder]; + [input readMessage:subBuilder extensionRegistry:extensionRegistry]; + [self addMethod:[subBuilder buildPartial]]; + break; + } + case 26: { + PBServiceOptionsBuilder* subBuilder = [PBServiceOptions builder]; + if (self.hasOptions) { + [subBuilder mergeFrom:self.options]; + } + [input readMessage:subBuilder extensionRegistry:extensionRegistry]; + [self setOptions:[subBuilder buildPartial]]; + break; + } + } + } +} +- (BOOL) hasName { + return result.hasName; +} +- (NSString*) name { + return result.name; +} +- (PBServiceDescriptorProtoBuilder*) setName:(NSString*) value { + result.hasName = YES; + result.name = value; + return self; +} +- (PBServiceDescriptorProtoBuilder*) clearName { + result.hasName = NO; + result.name = @""; + return self; +} +- (NSMutableArray *)method { + return result.methodArray; +} +- (PBMethodDescriptorProto*)methodAtIndex:(NSUInteger)index { + return [result methodAtIndex:index]; +} +- (PBServiceDescriptorProtoBuilder *)addMethod:(PBMethodDescriptorProto*)value { + if (result.methodArray == nil) { + result.methodArray = [[NSMutableArray alloc]init]; + } + [result.methodArray addObject:value]; + return self; +} +- (PBServiceDescriptorProtoBuilder *)setMethodArray:(NSArray *)array { + result.methodArray = [[NSMutableArray alloc]initWithArray:array]; + return self; +} +- (PBServiceDescriptorProtoBuilder *)clearMethod { + result.methodArray = nil; + return self; +} +- (BOOL) hasOptions { + return result.hasOptions; +} +- (PBServiceOptions*) options { + return result.options; +} +- (PBServiceDescriptorProtoBuilder*) setOptions:(PBServiceOptions*) value { + result.hasOptions = YES; + result.options = value; + return self; +} +- (PBServiceDescriptorProtoBuilder*) setOptionsBuilder:(PBServiceOptionsBuilder*) builderForValue { + return [self setOptions:[builderForValue build]]; +} +- (PBServiceDescriptorProtoBuilder*) mergeOptions:(PBServiceOptions*) value { + if (result.hasOptions && + result.options != [PBServiceOptions defaultInstance]) { + result.options = + [[[PBServiceOptions builderWithPrototype:result.options] mergeFrom:value] buildPartial]; + } else { + result.options = value; + } + result.hasOptions = YES; + return self; +} +- (PBServiceDescriptorProtoBuilder*) clearOptions { + result.hasOptions = NO; + result.options = [PBServiceOptions defaultInstance]; + return self; +} +@end + +@interface PBMethodDescriptorProto () +@property (strong) NSString* name; +@property (strong) NSString* inputType; +@property (strong) NSString* outputType; +@property (strong) PBMethodOptions* options; +@end + +@implementation PBMethodDescriptorProto + +- (BOOL) hasName { + return !!hasName_; +} +- (void) setHasName:(BOOL) value_ { + hasName_ = !!value_; +} +@synthesize name; +- (BOOL) hasInputType { + return !!hasInputType_; +} +- (void) setHasInputType:(BOOL) value_ { + hasInputType_ = !!value_; +} +@synthesize inputType; +- (BOOL) hasOutputType { + return !!hasOutputType_; +} +- (void) setHasOutputType:(BOOL) value_ { + hasOutputType_ = !!value_; +} +@synthesize outputType; +- (BOOL) hasOptions { + return !!hasOptions_; +} +- (void) setHasOptions:(BOOL) value_ { + hasOptions_ = !!value_; +} +@synthesize options; +- (id) init { + if ((self = [super init])) { + self.name = @""; + self.inputType = @""; + self.outputType = @""; + self.options = [PBMethodOptions defaultInstance]; + } + return self; +} +static PBMethodDescriptorProto* defaultPBMethodDescriptorProtoInstance = nil; ++ (void) initialize { + if (self == [PBMethodDescriptorProto class]) { + defaultPBMethodDescriptorProtoInstance = [[PBMethodDescriptorProto alloc] init]; + } +} ++ (PBMethodDescriptorProto*) defaultInstance { + return defaultPBMethodDescriptorProtoInstance; +} +- (PBMethodDescriptorProto*) defaultInstance { + return defaultPBMethodDescriptorProtoInstance; +} +- (BOOL) isInitialized { + if (self.hasOptions) { + if (!self.options.isInitialized) { + return NO; + } + } + return YES; +} +- (void) writeToCodedOutputStream:(PBCodedOutputStream*) output { + if (self.hasName) { + [output writeString:1 value:self.name]; + } + if (self.hasInputType) { + [output writeString:2 value:self.inputType]; + } + if (self.hasOutputType) { + [output writeString:3 value:self.outputType]; + } + if (self.hasOptions) { + [output writeMessage:4 value:self.options]; + } + [self.unknownFields writeToCodedOutputStream:output]; +} +- (SInt32) serializedSize { + __block SInt32 size_ = memoizedSerializedSize; + if (size_ != -1) { + return size_; + } + + size_ = 0; + if (self.hasName) { + size_ += computeStringSize(1, self.name); + } + if (self.hasInputType) { + size_ += computeStringSize(2, self.inputType); + } + if (self.hasOutputType) { + size_ += computeStringSize(3, self.outputType); + } + if (self.hasOptions) { + size_ += computeMessageSize(4, self.options); + } + size_ += self.unknownFields.serializedSize; + memoizedSerializedSize = size_; + return size_; +} ++ (PBMethodDescriptorProto*) parseFromData:(NSData*) data { + return (PBMethodDescriptorProto*)[[[PBMethodDescriptorProto builder] mergeFromData:data] build]; +} ++ (PBMethodDescriptorProto*) parseFromData:(NSData*) data extensionRegistry:(PBExtensionRegistry*) extensionRegistry { + return (PBMethodDescriptorProto*)[[[PBMethodDescriptorProto builder] mergeFromData:data extensionRegistry:extensionRegistry] build]; +} ++ (PBMethodDescriptorProto*) parseFromInputStream:(NSInputStream*) input { + return (PBMethodDescriptorProto*)[[[PBMethodDescriptorProto builder] mergeFromInputStream:input] build]; +} ++ (PBMethodDescriptorProto*) parseFromInputStream:(NSInputStream*) input extensionRegistry:(PBExtensionRegistry*) extensionRegistry { + return (PBMethodDescriptorProto*)[[[PBMethodDescriptorProto builder] mergeFromInputStream:input extensionRegistry:extensionRegistry] build]; +} ++ (PBMethodDescriptorProto*) parseFromCodedInputStream:(PBCodedInputStream*) input { + return (PBMethodDescriptorProto*)[[[PBMethodDescriptorProto builder] mergeFromCodedInputStream:input] build]; +} ++ (PBMethodDescriptorProto*) parseFromCodedInputStream:(PBCodedInputStream*) input extensionRegistry:(PBExtensionRegistry*) extensionRegistry { + return (PBMethodDescriptorProto*)[[[PBMethodDescriptorProto builder] mergeFromCodedInputStream:input extensionRegistry:extensionRegistry] build]; +} ++ (PBMethodDescriptorProtoBuilder*) builder { + return [[PBMethodDescriptorProtoBuilder alloc] init]; +} ++ (PBMethodDescriptorProtoBuilder*) builderWithPrototype:(PBMethodDescriptorProto*) prototype { + return [[PBMethodDescriptorProto builder] mergeFrom:prototype]; +} +- (PBMethodDescriptorProtoBuilder*) builder { + return [PBMethodDescriptorProto builder]; +} +- (PBMethodDescriptorProtoBuilder*) toBuilder { + return [PBMethodDescriptorProto builderWithPrototype:self]; +} +- (void) writeDescriptionTo:(NSMutableString*) output withIndent:(NSString*) indent { + if (self.hasName) { + [output appendFormat:@"%@%@: %@\n", indent, @"name", self.name]; + } + if (self.hasInputType) { + [output appendFormat:@"%@%@: %@\n", indent, @"inputType", self.inputType]; + } + if (self.hasOutputType) { + [output appendFormat:@"%@%@: %@\n", indent, @"outputType", self.outputType]; + } + if (self.hasOptions) { + [output appendFormat:@"%@%@ {\n", indent, @"options"]; + [self.options writeDescriptionTo:output + withIndent:[NSString stringWithFormat:@"%@ ", indent]]; + [output appendFormat:@"%@}\n", indent]; + } + [self.unknownFields writeDescriptionTo:output withIndent:indent]; +} +- (BOOL) isEqual:(id)other { + if (other == self) { + return YES; + } + if (![other isKindOfClass:[PBMethodDescriptorProto class]]) { + return NO; + } + PBMethodDescriptorProto *otherMessage = other; + return + self.hasName == otherMessage.hasName && + (!self.hasName || [self.name isEqual:otherMessage.name]) && + self.hasInputType == otherMessage.hasInputType && + (!self.hasInputType || [self.inputType isEqual:otherMessage.inputType]) && + self.hasOutputType == otherMessage.hasOutputType && + (!self.hasOutputType || [self.outputType isEqual:otherMessage.outputType]) && + self.hasOptions == otherMessage.hasOptions && + (!self.hasOptions || [self.options isEqual:otherMessage.options]) && + (self.unknownFields == otherMessage.unknownFields || (self.unknownFields != nil && [self.unknownFields isEqual:otherMessage.unknownFields])); +} +- (NSUInteger) hash { + __block NSUInteger hashCode = 7; + if (self.hasName) { + hashCode = hashCode * 31 + [self.name hash]; + } + if (self.hasInputType) { + hashCode = hashCode * 31 + [self.inputType hash]; + } + if (self.hasOutputType) { + hashCode = hashCode * 31 + [self.outputType hash]; + } + if (self.hasOptions) { + hashCode = hashCode * 31 + [self.options hash]; + } + hashCode = hashCode * 31 + [self.unknownFields hash]; + return hashCode; +} +@end + +@interface PBMethodDescriptorProtoBuilder() +@property (strong) PBMethodDescriptorProto* result; +@end + +@implementation PBMethodDescriptorProtoBuilder +@synthesize result; +- (id) init { + if ((self = [super init])) { + self.result = [[PBMethodDescriptorProto alloc] init]; + } + return self; +} +- (PBGeneratedMessage*) internalGetResult { + return result; +} +- (PBMethodDescriptorProtoBuilder*) clear { + self.result = [[PBMethodDescriptorProto alloc] init]; + return self; +} +- (PBMethodDescriptorProtoBuilder*) clone { + return [PBMethodDescriptorProto builderWithPrototype:result]; +} +- (PBMethodDescriptorProto*) defaultInstance { + return [PBMethodDescriptorProto defaultInstance]; +} +- (PBMethodDescriptorProto*) build { + [self checkInitialized]; + return [self buildPartial]; +} +- (PBMethodDescriptorProto*) buildPartial { + PBMethodDescriptorProto* returnMe = result; + self.result = nil; + return returnMe; +} +- (PBMethodDescriptorProtoBuilder*) mergeFrom:(PBMethodDescriptorProto*) other { + if (other == [PBMethodDescriptorProto defaultInstance]) { + return self; + } + if (other.hasName) { + [self setName:other.name]; + } + if (other.hasInputType) { + [self setInputType:other.inputType]; + } + if (other.hasOutputType) { + [self setOutputType:other.outputType]; + } + if (other.hasOptions) { + [self mergeOptions:other.options]; + } + [self mergeUnknownFields:other.unknownFields]; + return self; +} +- (PBMethodDescriptorProtoBuilder*) mergeFromCodedInputStream:(PBCodedInputStream*) input { + return [self mergeFromCodedInputStream:input extensionRegistry:[PBExtensionRegistry emptyRegistry]]; +} +- (PBMethodDescriptorProtoBuilder*) mergeFromCodedInputStream:(PBCodedInputStream*) input extensionRegistry:(PBExtensionRegistry*) extensionRegistry { + PBUnknownFieldSetBuilder* unknownFields = [PBUnknownFieldSet builderWithUnknownFields:self.unknownFields]; + while (YES) { + SInt32 tag = [input readTag]; + switch (tag) { + case 0: + [self setUnknownFields:[unknownFields build]]; + return self; + default: { + if (![self parseUnknownField:input unknownFields:unknownFields extensionRegistry:extensionRegistry tag:tag]) { + [self setUnknownFields:[unknownFields build]]; + return self; + } + break; + } + case 10: { + [self setName:[input readString]]; + break; + } + case 18: { + [self setInputType:[input readString]]; + break; + } + case 26: { + [self setOutputType:[input readString]]; + break; + } + case 34: { + PBMethodOptionsBuilder* subBuilder = [PBMethodOptions builder]; + if (self.hasOptions) { + [subBuilder mergeFrom:self.options]; + } + [input readMessage:subBuilder extensionRegistry:extensionRegistry]; + [self setOptions:[subBuilder buildPartial]]; + break; + } + } + } +} +- (BOOL) hasName { + return result.hasName; +} +- (NSString*) name { + return result.name; +} +- (PBMethodDescriptorProtoBuilder*) setName:(NSString*) value { + result.hasName = YES; + result.name = value; + return self; +} +- (PBMethodDescriptorProtoBuilder*) clearName { + result.hasName = NO; + result.name = @""; + return self; +} +- (BOOL) hasInputType { + return result.hasInputType; +} +- (NSString*) inputType { + return result.inputType; +} +- (PBMethodDescriptorProtoBuilder*) setInputType:(NSString*) value { + result.hasInputType = YES; + result.inputType = value; + return self; +} +- (PBMethodDescriptorProtoBuilder*) clearInputType { + result.hasInputType = NO; + result.inputType = @""; + return self; +} +- (BOOL) hasOutputType { + return result.hasOutputType; +} +- (NSString*) outputType { + return result.outputType; +} +- (PBMethodDescriptorProtoBuilder*) setOutputType:(NSString*) value { + result.hasOutputType = YES; + result.outputType = value; + return self; +} +- (PBMethodDescriptorProtoBuilder*) clearOutputType { + result.hasOutputType = NO; + result.outputType = @""; + return self; +} +- (BOOL) hasOptions { + return result.hasOptions; +} +- (PBMethodOptions*) options { + return result.options; +} +- (PBMethodDescriptorProtoBuilder*) setOptions:(PBMethodOptions*) value { + result.hasOptions = YES; + result.options = value; + return self; +} +- (PBMethodDescriptorProtoBuilder*) setOptionsBuilder:(PBMethodOptionsBuilder*) builderForValue { + return [self setOptions:[builderForValue build]]; +} +- (PBMethodDescriptorProtoBuilder*) mergeOptions:(PBMethodOptions*) value { + if (result.hasOptions && + result.options != [PBMethodOptions defaultInstance]) { + result.options = + [[[PBMethodOptions builderWithPrototype:result.options] mergeFrom:value] buildPartial]; + } else { + result.options = value; + } + result.hasOptions = YES; + return self; +} +- (PBMethodDescriptorProtoBuilder*) clearOptions { + result.hasOptions = NO; + result.options = [PBMethodOptions defaultInstance]; + return self; +} +@end + +@interface PBFileOptions () +@property (strong) NSString* javaPackage; +@property (strong) NSString* javaOuterClassname; +@property BOOL javaMultipleFiles; +@property BOOL javaGenerateEqualsAndHash; +@property BOOL javaStringCheckUtf8; +@property PBFileOptionsOptimizeMode optimizeFor; +@property (strong) NSString* goPackage; +@property BOOL ccGenericServices; +@property BOOL javaGenericServices; +@property BOOL pyGenericServices; +@property BOOL deprecated; +@property (strong) NSMutableArray * uninterpretedOptionArray; +@end + +@implementation PBFileOptions + +- (BOOL) hasJavaPackage { + return !!hasJavaPackage_; +} +- (void) setHasJavaPackage:(BOOL) value_ { + hasJavaPackage_ = !!value_; +} +@synthesize javaPackage; +- (BOOL) hasJavaOuterClassname { + return !!hasJavaOuterClassname_; +} +- (void) setHasJavaOuterClassname:(BOOL) value_ { + hasJavaOuterClassname_ = !!value_; +} +@synthesize javaOuterClassname; +- (BOOL) hasJavaMultipleFiles { + return !!hasJavaMultipleFiles_; +} +- (void) setHasJavaMultipleFiles:(BOOL) value_ { + hasJavaMultipleFiles_ = !!value_; +} +- (BOOL) javaMultipleFiles { + return !!javaMultipleFiles_; +} +- (void) setJavaMultipleFiles:(BOOL) value_ { + javaMultipleFiles_ = !!value_; +} +- (BOOL) hasJavaGenerateEqualsAndHash { + return !!hasJavaGenerateEqualsAndHash_; +} +- (void) setHasJavaGenerateEqualsAndHash:(BOOL) value_ { + hasJavaGenerateEqualsAndHash_ = !!value_; +} +- (BOOL) javaGenerateEqualsAndHash { + return !!javaGenerateEqualsAndHash_; +} +- (void) setJavaGenerateEqualsAndHash:(BOOL) value_ { + javaGenerateEqualsAndHash_ = !!value_; +} +- (BOOL) hasJavaStringCheckUtf8 { + return !!hasJavaStringCheckUtf8_; +} +- (void) setHasJavaStringCheckUtf8:(BOOL) value_ { + hasJavaStringCheckUtf8_ = !!value_; +} +- (BOOL) javaStringCheckUtf8 { + return !!javaStringCheckUtf8_; +} +- (void) setJavaStringCheckUtf8:(BOOL) value_ { + javaStringCheckUtf8_ = !!value_; +} +- (BOOL) hasOptimizeFor { + return !!hasOptimizeFor_; +} +- (void) setHasOptimizeFor:(BOOL) value_ { + hasOptimizeFor_ = !!value_; +} +@synthesize optimizeFor; +- (BOOL) hasGoPackage { + return !!hasGoPackage_; +} +- (void) setHasGoPackage:(BOOL) value_ { + hasGoPackage_ = !!value_; +} +@synthesize goPackage; +- (BOOL) hasCcGenericServices { + return !!hasCcGenericServices_; +} +- (void) setHasCcGenericServices:(BOOL) value_ { + hasCcGenericServices_ = !!value_; +} +- (BOOL) ccGenericServices { + return !!ccGenericServices_; +} +- (void) setCcGenericServices:(BOOL) value_ { + ccGenericServices_ = !!value_; +} +- (BOOL) hasJavaGenericServices { + return !!hasJavaGenericServices_; +} +- (void) setHasJavaGenericServices:(BOOL) value_ { + hasJavaGenericServices_ = !!value_; +} +- (BOOL) javaGenericServices { + return !!javaGenericServices_; +} +- (void) setJavaGenericServices:(BOOL) value_ { + javaGenericServices_ = !!value_; +} +- (BOOL) hasPyGenericServices { + return !!hasPyGenericServices_; +} +- (void) setHasPyGenericServices:(BOOL) value_ { + hasPyGenericServices_ = !!value_; +} +- (BOOL) pyGenericServices { + return !!pyGenericServices_; +} +- (void) setPyGenericServices:(BOOL) value_ { + pyGenericServices_ = !!value_; +} +- (BOOL) hasDeprecated { + return !!hasDeprecated_; +} +- (void) setHasDeprecated:(BOOL) value_ { + hasDeprecated_ = !!value_; +} +- (BOOL) deprecated { + return !!deprecated_; +} +- (void) setDeprecated:(BOOL) value_ { + deprecated_ = !!value_; +} +@synthesize uninterpretedOptionArray; +@dynamic uninterpretedOption; +- (id) init { + if ((self = [super init])) { + self.javaPackage = @""; + self.javaOuterClassname = @""; + self.javaMultipleFiles = NO; + self.javaGenerateEqualsAndHash = NO; + self.javaStringCheckUtf8 = NO; + self.optimizeFor = PBFileOptionsOptimizeModeSpeed; + self.goPackage = @""; + self.ccGenericServices = NO; + self.javaGenericServices = NO; + self.pyGenericServices = NO; + self.deprecated = NO; + } + return self; +} +static PBFileOptions* defaultPBFileOptionsInstance = nil; ++ (void) initialize { + if (self == [PBFileOptions class]) { + defaultPBFileOptionsInstance = [[PBFileOptions alloc] init]; + } +} ++ (PBFileOptions*) defaultInstance { + return defaultPBFileOptionsInstance; +} +- (PBFileOptions*) defaultInstance { + return defaultPBFileOptionsInstance; +} +- (NSArray *)uninterpretedOption { + return uninterpretedOptionArray; +} +- (PBUninterpretedOption*)uninterpretedOptionAtIndex:(NSUInteger)index { + return [uninterpretedOptionArray objectAtIndex:index]; +} +- (BOOL) isInitialized { + __block BOOL isInituninterpretedOption = YES; + [self.uninterpretedOption enumerateObjectsUsingBlock:^(PBUninterpretedOption *element, NSUInteger idx, BOOL *stop) { + if (!element.isInitialized) { + isInituninterpretedOption = NO; + *stop = YES; + } + }]; + if (!isInituninterpretedOption) return isInituninterpretedOption; + if (!self.extensionsAreInitialized) { + return NO; + } + return YES; +} +- (void) writeToCodedOutputStream:(PBCodedOutputStream*) output { + if (self.hasJavaPackage) { + [output writeString:1 value:self.javaPackage]; + } + if (self.hasJavaOuterClassname) { + [output writeString:8 value:self.javaOuterClassname]; + } + if (self.hasOptimizeFor) { + [output writeEnum:9 value:self.optimizeFor]; + } + if (self.hasJavaMultipleFiles) { + [output writeBool:10 value:self.javaMultipleFiles]; + } + if (self.hasGoPackage) { + [output writeString:11 value:self.goPackage]; + } + if (self.hasCcGenericServices) { + [output writeBool:16 value:self.ccGenericServices]; + } + if (self.hasJavaGenericServices) { + [output writeBool:17 value:self.javaGenericServices]; + } + if (self.hasPyGenericServices) { + [output writeBool:18 value:self.pyGenericServices]; + } + if (self.hasJavaGenerateEqualsAndHash) { + [output writeBool:20 value:self.javaGenerateEqualsAndHash]; + } + if (self.hasDeprecated) { + [output writeBool:23 value:self.deprecated]; + } + if (self.hasJavaStringCheckUtf8) { + [output writeBool:27 value:self.javaStringCheckUtf8]; + } + [self.uninterpretedOptionArray enumerateObjectsUsingBlock:^(PBUninterpretedOption *element, NSUInteger idx, BOOL *stop) { + [output writeMessage:999 value:element]; + }]; + [self writeExtensionsToCodedOutputStream:output + from:1000 + to:536870912]; + [self.unknownFields writeToCodedOutputStream:output]; +} +- (SInt32) serializedSize { + __block SInt32 size_ = memoizedSerializedSize; + if (size_ != -1) { + return size_; + } + + size_ = 0; + if (self.hasJavaPackage) { + size_ += computeStringSize(1, self.javaPackage); + } + if (self.hasJavaOuterClassname) { + size_ += computeStringSize(8, self.javaOuterClassname); + } + if (self.hasOptimizeFor) { + size_ += computeEnumSize(9, self.optimizeFor); + } + if (self.hasJavaMultipleFiles) { + size_ += computeBoolSize(10, self.javaMultipleFiles); + } + if (self.hasGoPackage) { + size_ += computeStringSize(11, self.goPackage); + } + if (self.hasCcGenericServices) { + size_ += computeBoolSize(16, self.ccGenericServices); + } + if (self.hasJavaGenericServices) { + size_ += computeBoolSize(17, self.javaGenericServices); + } + if (self.hasPyGenericServices) { + size_ += computeBoolSize(18, self.pyGenericServices); + } + if (self.hasJavaGenerateEqualsAndHash) { + size_ += computeBoolSize(20, self.javaGenerateEqualsAndHash); + } + if (self.hasDeprecated) { + size_ += computeBoolSize(23, self.deprecated); + } + if (self.hasJavaStringCheckUtf8) { + size_ += computeBoolSize(27, self.javaStringCheckUtf8); + } + [self.uninterpretedOptionArray enumerateObjectsUsingBlock:^(PBUninterpretedOption *element, NSUInteger idx, BOOL *stop) { + size_ += computeMessageSize(999, element); + }]; + size_ += [self extensionsSerializedSize]; + size_ += self.unknownFields.serializedSize; + memoizedSerializedSize = size_; + return size_; +} ++ (PBFileOptions*) parseFromData:(NSData*) data { + return (PBFileOptions*)[[[PBFileOptions builder] mergeFromData:data] build]; +} ++ (PBFileOptions*) parseFromData:(NSData*) data extensionRegistry:(PBExtensionRegistry*) extensionRegistry { + return (PBFileOptions*)[[[PBFileOptions builder] mergeFromData:data extensionRegistry:extensionRegistry] build]; +} ++ (PBFileOptions*) parseFromInputStream:(NSInputStream*) input { + return (PBFileOptions*)[[[PBFileOptions builder] mergeFromInputStream:input] build]; +} ++ (PBFileOptions*) parseFromInputStream:(NSInputStream*) input extensionRegistry:(PBExtensionRegistry*) extensionRegistry { + return (PBFileOptions*)[[[PBFileOptions builder] mergeFromInputStream:input extensionRegistry:extensionRegistry] build]; +} ++ (PBFileOptions*) parseFromCodedInputStream:(PBCodedInputStream*) input { + return (PBFileOptions*)[[[PBFileOptions builder] mergeFromCodedInputStream:input] build]; +} ++ (PBFileOptions*) parseFromCodedInputStream:(PBCodedInputStream*) input extensionRegistry:(PBExtensionRegistry*) extensionRegistry { + return (PBFileOptions*)[[[PBFileOptions builder] mergeFromCodedInputStream:input extensionRegistry:extensionRegistry] build]; +} ++ (PBFileOptionsBuilder*) builder { + return [[PBFileOptionsBuilder alloc] init]; +} ++ (PBFileOptionsBuilder*) builderWithPrototype:(PBFileOptions*) prototype { + return [[PBFileOptions builder] mergeFrom:prototype]; +} +- (PBFileOptionsBuilder*) builder { + return [PBFileOptions builder]; +} +- (PBFileOptionsBuilder*) toBuilder { + return [PBFileOptions builderWithPrototype:self]; +} +- (void) writeDescriptionTo:(NSMutableString*) output withIndent:(NSString*) indent { + if (self.hasJavaPackage) { + [output appendFormat:@"%@%@: %@\n", indent, @"javaPackage", self.javaPackage]; + } + if (self.hasJavaOuterClassname) { + [output appendFormat:@"%@%@: %@\n", indent, @"javaOuterClassname", self.javaOuterClassname]; + } + if (self.hasOptimizeFor) { + [output appendFormat:@"%@%@: %d\n", indent, @"optimizeFor", self.optimizeFor]; + } + if (self.hasJavaMultipleFiles) { + [output appendFormat:@"%@%@: %@\n", indent, @"javaMultipleFiles", [NSNumber numberWithBool:self.javaMultipleFiles]]; + } + if (self.hasGoPackage) { + [output appendFormat:@"%@%@: %@\n", indent, @"goPackage", self.goPackage]; + } + if (self.hasCcGenericServices) { + [output appendFormat:@"%@%@: %@\n", indent, @"ccGenericServices", [NSNumber numberWithBool:self.ccGenericServices]]; + } + if (self.hasJavaGenericServices) { + [output appendFormat:@"%@%@: %@\n", indent, @"javaGenericServices", [NSNumber numberWithBool:self.javaGenericServices]]; + } + if (self.hasPyGenericServices) { + [output appendFormat:@"%@%@: %@\n", indent, @"pyGenericServices", [NSNumber numberWithBool:self.pyGenericServices]]; + } + if (self.hasJavaGenerateEqualsAndHash) { + [output appendFormat:@"%@%@: %@\n", indent, @"javaGenerateEqualsAndHash", [NSNumber numberWithBool:self.javaGenerateEqualsAndHash]]; + } + if (self.hasDeprecated) { + [output appendFormat:@"%@%@: %@\n", indent, @"deprecated", [NSNumber numberWithBool:self.deprecated]]; + } + if (self.hasJavaStringCheckUtf8) { + [output appendFormat:@"%@%@: %@\n", indent, @"javaStringCheckUtf8", [NSNumber numberWithBool:self.javaStringCheckUtf8]]; + } + [self.uninterpretedOptionArray enumerateObjectsUsingBlock:^(PBUninterpretedOption *element, NSUInteger idx, BOOL *stop) { + [output appendFormat:@"%@%@ {\n", indent, @"uninterpretedOption"]; + [element writeDescriptionTo:output + withIndent:[NSString stringWithFormat:@"%@ ", indent]]; + [output appendFormat:@"%@}\n", indent]; + }]; + [self writeExtensionDescriptionToMutableString:(NSMutableString*)output + from:1000 + to:536870912 + withIndent:indent]; + [self.unknownFields writeDescriptionTo:output withIndent:indent]; +} +- (BOOL) isEqual:(id)other { + if (other == self) { + return YES; + } + if (![other isKindOfClass:[PBFileOptions class]]) { + return NO; + } + PBFileOptions *otherMessage = other; + return + self.hasJavaPackage == otherMessage.hasJavaPackage && + (!self.hasJavaPackage || [self.javaPackage isEqual:otherMessage.javaPackage]) && + self.hasJavaOuterClassname == otherMessage.hasJavaOuterClassname && + (!self.hasJavaOuterClassname || [self.javaOuterClassname isEqual:otherMessage.javaOuterClassname]) && + self.hasOptimizeFor == otherMessage.hasOptimizeFor && + (!self.hasOptimizeFor || self.optimizeFor == otherMessage.optimizeFor) && + self.hasJavaMultipleFiles == otherMessage.hasJavaMultipleFiles && + (!self.hasJavaMultipleFiles || self.javaMultipleFiles == otherMessage.javaMultipleFiles) && + self.hasGoPackage == otherMessage.hasGoPackage && + (!self.hasGoPackage || [self.goPackage isEqual:otherMessage.goPackage]) && + self.hasCcGenericServices == otherMessage.hasCcGenericServices && + (!self.hasCcGenericServices || self.ccGenericServices == otherMessage.ccGenericServices) && + self.hasJavaGenericServices == otherMessage.hasJavaGenericServices && + (!self.hasJavaGenericServices || self.javaGenericServices == otherMessage.javaGenericServices) && + self.hasPyGenericServices == otherMessage.hasPyGenericServices && + (!self.hasPyGenericServices || self.pyGenericServices == otherMessage.pyGenericServices) && + self.hasJavaGenerateEqualsAndHash == otherMessage.hasJavaGenerateEqualsAndHash && + (!self.hasJavaGenerateEqualsAndHash || self.javaGenerateEqualsAndHash == otherMessage.javaGenerateEqualsAndHash) && + self.hasDeprecated == otherMessage.hasDeprecated && + (!self.hasDeprecated || self.deprecated == otherMessage.deprecated) && + self.hasJavaStringCheckUtf8 == otherMessage.hasJavaStringCheckUtf8 && + (!self.hasJavaStringCheckUtf8 || self.javaStringCheckUtf8 == otherMessage.javaStringCheckUtf8) && + [self.uninterpretedOptionArray isEqualToArray:otherMessage.uninterpretedOptionArray] && + [self isEqualExtensionsInOther:otherMessage from:1000 to:536870912] && + + (self.unknownFields == otherMessage.unknownFields || (self.unknownFields != nil && [self.unknownFields isEqual:otherMessage.unknownFields])); +} +- (NSUInteger) hash { + __block NSUInteger hashCode = 7; + if (self.hasJavaPackage) { + hashCode = hashCode * 31 + [self.javaPackage hash]; + } + if (self.hasJavaOuterClassname) { + hashCode = hashCode * 31 + [self.javaOuterClassname hash]; + } + if (self.hasOptimizeFor) { + hashCode = hashCode * 31 + self.optimizeFor; + } + if (self.hasJavaMultipleFiles) { + hashCode = hashCode * 31 + [[NSNumber numberWithBool:self.javaMultipleFiles] hash]; + } + if (self.hasGoPackage) { + hashCode = hashCode * 31 + [self.goPackage hash]; + } + if (self.hasCcGenericServices) { + hashCode = hashCode * 31 + [[NSNumber numberWithBool:self.ccGenericServices] hash]; + } + if (self.hasJavaGenericServices) { + hashCode = hashCode * 31 + [[NSNumber numberWithBool:self.javaGenericServices] hash]; + } + if (self.hasPyGenericServices) { + hashCode = hashCode * 31 + [[NSNumber numberWithBool:self.pyGenericServices] hash]; + } + if (self.hasJavaGenerateEqualsAndHash) { + hashCode = hashCode * 31 + [[NSNumber numberWithBool:self.javaGenerateEqualsAndHash] hash]; + } + if (self.hasDeprecated) { + hashCode = hashCode * 31 + [[NSNumber numberWithBool:self.deprecated] hash]; + } + if (self.hasJavaStringCheckUtf8) { + hashCode = hashCode * 31 + [[NSNumber numberWithBool:self.javaStringCheckUtf8] hash]; + } + [self.uninterpretedOptionArray enumerateObjectsUsingBlock:^(PBUninterpretedOption *element, NSUInteger idx, BOOL *stop) { + hashCode = hashCode * 31 + [element hash]; + }]; + hashCode = hashCode * 31 + [self hashExtensionsFrom:1000 to:536870912]; + hashCode = hashCode * 31 + [self.unknownFields hash]; + return hashCode; +} +@end + +BOOL PBFileOptionsOptimizeModeIsValidValue(PBFileOptionsOptimizeMode value) { + switch (value) { + case PBFileOptionsOptimizeModeSpeed: + case PBFileOptionsOptimizeModeCodeSize: + case PBFileOptionsOptimizeModeLiteRuntime: + return YES; + default: + return NO; + } +} +@interface PBFileOptionsBuilder() +@property (strong) PBFileOptions* result; +@end + +@implementation PBFileOptionsBuilder +@synthesize result; +- (id) init { + if ((self = [super init])) { + self.result = [[PBFileOptions alloc] init]; + } + return self; +} +- (PBExtendableMessage*) internalGetResult { + return result; +} +- (PBFileOptionsBuilder*) clear { + self.result = [[PBFileOptions alloc] init]; + return self; +} +- (PBFileOptionsBuilder*) clone { + return [PBFileOptions builderWithPrototype:result]; +} +- (PBFileOptions*) defaultInstance { + return [PBFileOptions defaultInstance]; +} +- (PBFileOptions*) build { + [self checkInitialized]; + return [self buildPartial]; +} +- (PBFileOptions*) buildPartial { + PBFileOptions* returnMe = result; + self.result = nil; + return returnMe; +} +- (PBFileOptionsBuilder*) mergeFrom:(PBFileOptions*) other { + if (other == [PBFileOptions defaultInstance]) { + return self; + } + if (other.hasJavaPackage) { + [self setJavaPackage:other.javaPackage]; + } + if (other.hasJavaOuterClassname) { + [self setJavaOuterClassname:other.javaOuterClassname]; + } + if (other.hasJavaMultipleFiles) { + [self setJavaMultipleFiles:other.javaMultipleFiles]; + } + if (other.hasJavaGenerateEqualsAndHash) { + [self setJavaGenerateEqualsAndHash:other.javaGenerateEqualsAndHash]; + } + if (other.hasJavaStringCheckUtf8) { + [self setJavaStringCheckUtf8:other.javaStringCheckUtf8]; + } + if (other.hasOptimizeFor) { + [self setOptimizeFor:other.optimizeFor]; + } + if (other.hasGoPackage) { + [self setGoPackage:other.goPackage]; + } + if (other.hasCcGenericServices) { + [self setCcGenericServices:other.ccGenericServices]; + } + if (other.hasJavaGenericServices) { + [self setJavaGenericServices:other.javaGenericServices]; + } + if (other.hasPyGenericServices) { + [self setPyGenericServices:other.pyGenericServices]; + } + if (other.hasDeprecated) { + [self setDeprecated:other.deprecated]; + } + if (other.uninterpretedOptionArray.count > 0) { + if (result.uninterpretedOptionArray == nil) { + result.uninterpretedOptionArray = [[NSMutableArray alloc] initWithArray:other.uninterpretedOptionArray]; + } else { + [result.uninterpretedOptionArray addObjectsFromArray:other.uninterpretedOptionArray]; + } + } + [self mergeExtensionFields:other]; + [self mergeUnknownFields:other.unknownFields]; + return self; +} +- (PBFileOptionsBuilder*) mergeFromCodedInputStream:(PBCodedInputStream*) input { + return [self mergeFromCodedInputStream:input extensionRegistry:[PBExtensionRegistry emptyRegistry]]; +} +- (PBFileOptionsBuilder*) mergeFromCodedInputStream:(PBCodedInputStream*) input extensionRegistry:(PBExtensionRegistry*) extensionRegistry { + PBUnknownFieldSetBuilder* unknownFields = [PBUnknownFieldSet builderWithUnknownFields:self.unknownFields]; + while (YES) { + SInt32 tag = [input readTag]; + switch (tag) { + case 0: + [self setUnknownFields:[unknownFields build]]; + return self; + default: { + if (![self parseUnknownField:input unknownFields:unknownFields extensionRegistry:extensionRegistry tag:tag]) { + [self setUnknownFields:[unknownFields build]]; + return self; + } + break; + } + case 10: { + [self setJavaPackage:[input readString]]; + break; + } + case 66: { + [self setJavaOuterClassname:[input readString]]; + break; + } + case 72: { + PBFileOptionsOptimizeMode value = (PBFileOptionsOptimizeMode)[input readEnum]; + if (PBFileOptionsOptimizeModeIsValidValue(value)) { + [self setOptimizeFor:value]; + } else { + [unknownFields mergeVarintField:9 value:value]; + } + break; + } + case 80: { + [self setJavaMultipleFiles:[input readBool]]; + break; + } + case 90: { + [self setGoPackage:[input readString]]; + break; + } + case 128: { + [self setCcGenericServices:[input readBool]]; + break; + } + case 136: { + [self setJavaGenericServices:[input readBool]]; + break; + } + case 144: { + [self setPyGenericServices:[input readBool]]; + break; + } + case 160: { + [self setJavaGenerateEqualsAndHash:[input readBool]]; + break; + } + case 184: { + [self setDeprecated:[input readBool]]; + break; + } + case 216: { + [self setJavaStringCheckUtf8:[input readBool]]; + break; + } + case 7994: { + PBUninterpretedOptionBuilder* subBuilder = [PBUninterpretedOption builder]; + [input readMessage:subBuilder extensionRegistry:extensionRegistry]; + [self addUninterpretedOption:[subBuilder buildPartial]]; + break; + } + } + } +} +- (BOOL) hasJavaPackage { + return result.hasJavaPackage; +} +- (NSString*) javaPackage { + return result.javaPackage; +} +- (PBFileOptionsBuilder*) setJavaPackage:(NSString*) value { + result.hasJavaPackage = YES; + result.javaPackage = value; + return self; +} +- (PBFileOptionsBuilder*) clearJavaPackage { + result.hasJavaPackage = NO; + result.javaPackage = @""; + return self; +} +- (BOOL) hasJavaOuterClassname { + return result.hasJavaOuterClassname; +} +- (NSString*) javaOuterClassname { + return result.javaOuterClassname; +} +- (PBFileOptionsBuilder*) setJavaOuterClassname:(NSString*) value { + result.hasJavaOuterClassname = YES; + result.javaOuterClassname = value; + return self; +} +- (PBFileOptionsBuilder*) clearJavaOuterClassname { + result.hasJavaOuterClassname = NO; + result.javaOuterClassname = @""; + return self; +} +- (BOOL) hasJavaMultipleFiles { + return result.hasJavaMultipleFiles; +} +- (BOOL) javaMultipleFiles { + return result.javaMultipleFiles; +} +- (PBFileOptionsBuilder*) setJavaMultipleFiles:(BOOL) value { + result.hasJavaMultipleFiles = YES; + result.javaMultipleFiles = value; + return self; +} +- (PBFileOptionsBuilder*) clearJavaMultipleFiles { + result.hasJavaMultipleFiles = NO; + result.javaMultipleFiles = NO; + return self; +} +- (BOOL) hasJavaGenerateEqualsAndHash { + return result.hasJavaGenerateEqualsAndHash; +} +- (BOOL) javaGenerateEqualsAndHash { + return result.javaGenerateEqualsAndHash; +} +- (PBFileOptionsBuilder*) setJavaGenerateEqualsAndHash:(BOOL) value { + result.hasJavaGenerateEqualsAndHash = YES; + result.javaGenerateEqualsAndHash = value; + return self; +} +- (PBFileOptionsBuilder*) clearJavaGenerateEqualsAndHash { + result.hasJavaGenerateEqualsAndHash = NO; + result.javaGenerateEqualsAndHash = NO; + return self; +} +- (BOOL) hasJavaStringCheckUtf8 { + return result.hasJavaStringCheckUtf8; +} +- (BOOL) javaStringCheckUtf8 { + return result.javaStringCheckUtf8; +} +- (PBFileOptionsBuilder*) setJavaStringCheckUtf8:(BOOL) value { + result.hasJavaStringCheckUtf8 = YES; + result.javaStringCheckUtf8 = value; + return self; +} +- (PBFileOptionsBuilder*) clearJavaStringCheckUtf8 { + result.hasJavaStringCheckUtf8 = NO; + result.javaStringCheckUtf8 = NO; + return self; +} +- (BOOL) hasOptimizeFor { + return result.hasOptimizeFor; +} +- (PBFileOptionsOptimizeMode) optimizeFor { + return result.optimizeFor; +} +- (PBFileOptionsBuilder*) setOptimizeFor:(PBFileOptionsOptimizeMode) value { + result.hasOptimizeFor = YES; + result.optimizeFor = value; + return self; +} +- (PBFileOptionsBuilder*) clearOptimizeFor { + result.hasOptimizeFor = NO; + result.optimizeFor = PBFileOptionsOptimizeModeSpeed; + return self; +} +- (BOOL) hasGoPackage { + return result.hasGoPackage; +} +- (NSString*) goPackage { + return result.goPackage; +} +- (PBFileOptionsBuilder*) setGoPackage:(NSString*) value { + result.hasGoPackage = YES; + result.goPackage = value; + return self; +} +- (PBFileOptionsBuilder*) clearGoPackage { + result.hasGoPackage = NO; + result.goPackage = @""; + return self; +} +- (BOOL) hasCcGenericServices { + return result.hasCcGenericServices; +} +- (BOOL) ccGenericServices { + return result.ccGenericServices; +} +- (PBFileOptionsBuilder*) setCcGenericServices:(BOOL) value { + result.hasCcGenericServices = YES; + result.ccGenericServices = value; + return self; +} +- (PBFileOptionsBuilder*) clearCcGenericServices { + result.hasCcGenericServices = NO; + result.ccGenericServices = NO; + return self; +} +- (BOOL) hasJavaGenericServices { + return result.hasJavaGenericServices; +} +- (BOOL) javaGenericServices { + return result.javaGenericServices; +} +- (PBFileOptionsBuilder*) setJavaGenericServices:(BOOL) value { + result.hasJavaGenericServices = YES; + result.javaGenericServices = value; + return self; +} +- (PBFileOptionsBuilder*) clearJavaGenericServices { + result.hasJavaGenericServices = NO; + result.javaGenericServices = NO; + return self; +} +- (BOOL) hasPyGenericServices { + return result.hasPyGenericServices; +} +- (BOOL) pyGenericServices { + return result.pyGenericServices; +} +- (PBFileOptionsBuilder*) setPyGenericServices:(BOOL) value { + result.hasPyGenericServices = YES; + result.pyGenericServices = value; + return self; +} +- (PBFileOptionsBuilder*) clearPyGenericServices { + result.hasPyGenericServices = NO; + result.pyGenericServices = NO; + return self; +} +- (BOOL) hasDeprecated { + return result.hasDeprecated; +} +- (BOOL) deprecated { + return result.deprecated; +} +- (PBFileOptionsBuilder*) setDeprecated:(BOOL) value { + result.hasDeprecated = YES; + result.deprecated = value; + return self; +} +- (PBFileOptionsBuilder*) clearDeprecated { + result.hasDeprecated = NO; + result.deprecated = NO; + return self; +} +- (NSMutableArray *)uninterpretedOption { + return result.uninterpretedOptionArray; +} +- (PBUninterpretedOption*)uninterpretedOptionAtIndex:(NSUInteger)index { + return [result uninterpretedOptionAtIndex:index]; +} +- (PBFileOptionsBuilder *)addUninterpretedOption:(PBUninterpretedOption*)value { + if (result.uninterpretedOptionArray == nil) { + result.uninterpretedOptionArray = [[NSMutableArray alloc]init]; + } + [result.uninterpretedOptionArray addObject:value]; + return self; +} +- (PBFileOptionsBuilder *)setUninterpretedOptionArray:(NSArray *)array { + result.uninterpretedOptionArray = [[NSMutableArray alloc]initWithArray:array]; + return self; +} +- (PBFileOptionsBuilder *)clearUninterpretedOption { + result.uninterpretedOptionArray = nil; + return self; +} +@end + +@interface PBMessageOptions () +@property BOOL messageSetWireFormat; +@property BOOL noStandardDescriptorAccessor; +@property BOOL deprecated; +@property (strong) NSMutableArray * uninterpretedOptionArray; +@end + +@implementation PBMessageOptions + +- (BOOL) hasMessageSetWireFormat { + return !!hasMessageSetWireFormat_; +} +- (void) setHasMessageSetWireFormat:(BOOL) value_ { + hasMessageSetWireFormat_ = !!value_; +} +- (BOOL) messageSetWireFormat { + return !!messageSetWireFormat_; +} +- (void) setMessageSetWireFormat:(BOOL) value_ { + messageSetWireFormat_ = !!value_; +} +- (BOOL) hasNoStandardDescriptorAccessor { + return !!hasNoStandardDescriptorAccessor_; +} +- (void) setHasNoStandardDescriptorAccessor:(BOOL) value_ { + hasNoStandardDescriptorAccessor_ = !!value_; +} +- (BOOL) noStandardDescriptorAccessor { + return !!noStandardDescriptorAccessor_; +} +- (void) setNoStandardDescriptorAccessor:(BOOL) value_ { + noStandardDescriptorAccessor_ = !!value_; +} +- (BOOL) hasDeprecated { + return !!hasDeprecated_; +} +- (void) setHasDeprecated:(BOOL) value_ { + hasDeprecated_ = !!value_; +} +- (BOOL) deprecated { + return !!deprecated_; +} +- (void) setDeprecated:(BOOL) value_ { + deprecated_ = !!value_; +} +@synthesize uninterpretedOptionArray; +@dynamic uninterpretedOption; +- (id) init { + if ((self = [super init])) { + self.messageSetWireFormat = NO; + self.noStandardDescriptorAccessor = NO; + self.deprecated = NO; + } + return self; +} +static PBMessageOptions* defaultPBMessageOptionsInstance = nil; ++ (void) initialize { + if (self == [PBMessageOptions class]) { + defaultPBMessageOptionsInstance = [[PBMessageOptions alloc] init]; + } +} ++ (PBMessageOptions*) defaultInstance { + return defaultPBMessageOptionsInstance; +} +- (PBMessageOptions*) defaultInstance { + return defaultPBMessageOptionsInstance; +} +- (NSArray *)uninterpretedOption { + return uninterpretedOptionArray; +} +- (PBUninterpretedOption*)uninterpretedOptionAtIndex:(NSUInteger)index { + return [uninterpretedOptionArray objectAtIndex:index]; +} +- (BOOL) isInitialized { + __block BOOL isInituninterpretedOption = YES; + [self.uninterpretedOption enumerateObjectsUsingBlock:^(PBUninterpretedOption *element, NSUInteger idx, BOOL *stop) { + if (!element.isInitialized) { + isInituninterpretedOption = NO; + *stop = YES; + } + }]; + if (!isInituninterpretedOption) return isInituninterpretedOption; + if (!self.extensionsAreInitialized) { + return NO; + } + return YES; +} +- (void) writeToCodedOutputStream:(PBCodedOutputStream*) output { + if (self.hasMessageSetWireFormat) { + [output writeBool:1 value:self.messageSetWireFormat]; + } + if (self.hasNoStandardDescriptorAccessor) { + [output writeBool:2 value:self.noStandardDescriptorAccessor]; + } + if (self.hasDeprecated) { + [output writeBool:3 value:self.deprecated]; + } + [self.uninterpretedOptionArray enumerateObjectsUsingBlock:^(PBUninterpretedOption *element, NSUInteger idx, BOOL *stop) { + [output writeMessage:999 value:element]; + }]; + [self writeExtensionsToCodedOutputStream:output + from:1000 + to:536870912]; + [self.unknownFields writeToCodedOutputStream:output]; +} +- (SInt32) serializedSize { + __block SInt32 size_ = memoizedSerializedSize; + if (size_ != -1) { + return size_; + } + + size_ = 0; + if (self.hasMessageSetWireFormat) { + size_ += computeBoolSize(1, self.messageSetWireFormat); + } + if (self.hasNoStandardDescriptorAccessor) { + size_ += computeBoolSize(2, self.noStandardDescriptorAccessor); + } + if (self.hasDeprecated) { + size_ += computeBoolSize(3, self.deprecated); + } + [self.uninterpretedOptionArray enumerateObjectsUsingBlock:^(PBUninterpretedOption *element, NSUInteger idx, BOOL *stop) { + size_ += computeMessageSize(999, element); + }]; + size_ += [self extensionsSerializedSize]; + size_ += self.unknownFields.serializedSize; + memoizedSerializedSize = size_; + return size_; +} ++ (PBMessageOptions*) parseFromData:(NSData*) data { + return (PBMessageOptions*)[[[PBMessageOptions builder] mergeFromData:data] build]; +} ++ (PBMessageOptions*) parseFromData:(NSData*) data extensionRegistry:(PBExtensionRegistry*) extensionRegistry { + return (PBMessageOptions*)[[[PBMessageOptions builder] mergeFromData:data extensionRegistry:extensionRegistry] build]; +} ++ (PBMessageOptions*) parseFromInputStream:(NSInputStream*) input { + return (PBMessageOptions*)[[[PBMessageOptions builder] mergeFromInputStream:input] build]; +} ++ (PBMessageOptions*) parseFromInputStream:(NSInputStream*) input extensionRegistry:(PBExtensionRegistry*) extensionRegistry { + return (PBMessageOptions*)[[[PBMessageOptions builder] mergeFromInputStream:input extensionRegistry:extensionRegistry] build]; +} ++ (PBMessageOptions*) parseFromCodedInputStream:(PBCodedInputStream*) input { + return (PBMessageOptions*)[[[PBMessageOptions builder] mergeFromCodedInputStream:input] build]; +} ++ (PBMessageOptions*) parseFromCodedInputStream:(PBCodedInputStream*) input extensionRegistry:(PBExtensionRegistry*) extensionRegistry { + return (PBMessageOptions*)[[[PBMessageOptions builder] mergeFromCodedInputStream:input extensionRegistry:extensionRegistry] build]; +} ++ (PBMessageOptionsBuilder*) builder { + return [[PBMessageOptionsBuilder alloc] init]; +} ++ (PBMessageOptionsBuilder*) builderWithPrototype:(PBMessageOptions*) prototype { + return [[PBMessageOptions builder] mergeFrom:prototype]; +} +- (PBMessageOptionsBuilder*) builder { + return [PBMessageOptions builder]; +} +- (PBMessageOptionsBuilder*) toBuilder { + return [PBMessageOptions builderWithPrototype:self]; +} +- (void) writeDescriptionTo:(NSMutableString*) output withIndent:(NSString*) indent { + if (self.hasMessageSetWireFormat) { + [output appendFormat:@"%@%@: %@\n", indent, @"messageSetWireFormat", [NSNumber numberWithBool:self.messageSetWireFormat]]; + } + if (self.hasNoStandardDescriptorAccessor) { + [output appendFormat:@"%@%@: %@\n", indent, @"noStandardDescriptorAccessor", [NSNumber numberWithBool:self.noStandardDescriptorAccessor]]; + } + if (self.hasDeprecated) { + [output appendFormat:@"%@%@: %@\n", indent, @"deprecated", [NSNumber numberWithBool:self.deprecated]]; + } + [self.uninterpretedOptionArray enumerateObjectsUsingBlock:^(PBUninterpretedOption *element, NSUInteger idx, BOOL *stop) { + [output appendFormat:@"%@%@ {\n", indent, @"uninterpretedOption"]; + [element writeDescriptionTo:output + withIndent:[NSString stringWithFormat:@"%@ ", indent]]; + [output appendFormat:@"%@}\n", indent]; + }]; + [self writeExtensionDescriptionToMutableString:(NSMutableString*)output + from:1000 + to:536870912 + withIndent:indent]; + [self.unknownFields writeDescriptionTo:output withIndent:indent]; +} +- (BOOL) isEqual:(id)other { + if (other == self) { + return YES; + } + if (![other isKindOfClass:[PBMessageOptions class]]) { + return NO; + } + PBMessageOptions *otherMessage = other; + return + self.hasMessageSetWireFormat == otherMessage.hasMessageSetWireFormat && + (!self.hasMessageSetWireFormat || self.messageSetWireFormat == otherMessage.messageSetWireFormat) && + self.hasNoStandardDescriptorAccessor == otherMessage.hasNoStandardDescriptorAccessor && + (!self.hasNoStandardDescriptorAccessor || self.noStandardDescriptorAccessor == otherMessage.noStandardDescriptorAccessor) && + self.hasDeprecated == otherMessage.hasDeprecated && + (!self.hasDeprecated || self.deprecated == otherMessage.deprecated) && + [self.uninterpretedOptionArray isEqualToArray:otherMessage.uninterpretedOptionArray] && + [self isEqualExtensionsInOther:otherMessage from:1000 to:536870912] && + + (self.unknownFields == otherMessage.unknownFields || (self.unknownFields != nil && [self.unknownFields isEqual:otherMessage.unknownFields])); +} +- (NSUInteger) hash { + __block NSUInteger hashCode = 7; + if (self.hasMessageSetWireFormat) { + hashCode = hashCode * 31 + [[NSNumber numberWithBool:self.messageSetWireFormat] hash]; + } + if (self.hasNoStandardDescriptorAccessor) { + hashCode = hashCode * 31 + [[NSNumber numberWithBool:self.noStandardDescriptorAccessor] hash]; + } + if (self.hasDeprecated) { + hashCode = hashCode * 31 + [[NSNumber numberWithBool:self.deprecated] hash]; + } + [self.uninterpretedOptionArray enumerateObjectsUsingBlock:^(PBUninterpretedOption *element, NSUInteger idx, BOOL *stop) { + hashCode = hashCode * 31 + [element hash]; + }]; + hashCode = hashCode * 31 + [self hashExtensionsFrom:1000 to:536870912]; + hashCode = hashCode * 31 + [self.unknownFields hash]; + return hashCode; +} +@end + +@interface PBMessageOptionsBuilder() +@property (strong) PBMessageOptions* result; +@end + +@implementation PBMessageOptionsBuilder +@synthesize result; +- (id) init { + if ((self = [super init])) { + self.result = [[PBMessageOptions alloc] init]; + } + return self; +} +- (PBExtendableMessage*) internalGetResult { + return result; +} +- (PBMessageOptionsBuilder*) clear { + self.result = [[PBMessageOptions alloc] init]; + return self; +} +- (PBMessageOptionsBuilder*) clone { + return [PBMessageOptions builderWithPrototype:result]; +} +- (PBMessageOptions*) defaultInstance { + return [PBMessageOptions defaultInstance]; +} +- (PBMessageOptions*) build { + [self checkInitialized]; + return [self buildPartial]; +} +- (PBMessageOptions*) buildPartial { + PBMessageOptions* returnMe = result; + self.result = nil; + return returnMe; +} +- (PBMessageOptionsBuilder*) mergeFrom:(PBMessageOptions*) other { + if (other == [PBMessageOptions defaultInstance]) { + return self; + } + if (other.hasMessageSetWireFormat) { + [self setMessageSetWireFormat:other.messageSetWireFormat]; + } + if (other.hasNoStandardDescriptorAccessor) { + [self setNoStandardDescriptorAccessor:other.noStandardDescriptorAccessor]; + } + if (other.hasDeprecated) { + [self setDeprecated:other.deprecated]; + } + if (other.uninterpretedOptionArray.count > 0) { + if (result.uninterpretedOptionArray == nil) { + result.uninterpretedOptionArray = [[NSMutableArray alloc] initWithArray:other.uninterpretedOptionArray]; + } else { + [result.uninterpretedOptionArray addObjectsFromArray:other.uninterpretedOptionArray]; + } + } + [self mergeExtensionFields:other]; + [self mergeUnknownFields:other.unknownFields]; + return self; +} +- (PBMessageOptionsBuilder*) mergeFromCodedInputStream:(PBCodedInputStream*) input { + return [self mergeFromCodedInputStream:input extensionRegistry:[PBExtensionRegistry emptyRegistry]]; +} +- (PBMessageOptionsBuilder*) mergeFromCodedInputStream:(PBCodedInputStream*) input extensionRegistry:(PBExtensionRegistry*) extensionRegistry { + PBUnknownFieldSetBuilder* unknownFields = [PBUnknownFieldSet builderWithUnknownFields:self.unknownFields]; + while (YES) { + SInt32 tag = [input readTag]; + switch (tag) { + case 0: + [self setUnknownFields:[unknownFields build]]; + return self; + default: { + if (![self parseUnknownField:input unknownFields:unknownFields extensionRegistry:extensionRegistry tag:tag]) { + [self setUnknownFields:[unknownFields build]]; + return self; + } + break; + } + case 8: { + [self setMessageSetWireFormat:[input readBool]]; + break; + } + case 16: { + [self setNoStandardDescriptorAccessor:[input readBool]]; + break; + } + case 24: { + [self setDeprecated:[input readBool]]; + break; + } + case 7994: { + PBUninterpretedOptionBuilder* subBuilder = [PBUninterpretedOption builder]; + [input readMessage:subBuilder extensionRegistry:extensionRegistry]; + [self addUninterpretedOption:[subBuilder buildPartial]]; + break; + } + } + } +} +- (BOOL) hasMessageSetWireFormat { + return result.hasMessageSetWireFormat; +} +- (BOOL) messageSetWireFormat { + return result.messageSetWireFormat; +} +- (PBMessageOptionsBuilder*) setMessageSetWireFormat:(BOOL) value { + result.hasMessageSetWireFormat = YES; + result.messageSetWireFormat = value; + return self; +} +- (PBMessageOptionsBuilder*) clearMessageSetWireFormat { + result.hasMessageSetWireFormat = NO; + result.messageSetWireFormat = NO; + return self; +} +- (BOOL) hasNoStandardDescriptorAccessor { + return result.hasNoStandardDescriptorAccessor; +} +- (BOOL) noStandardDescriptorAccessor { + return result.noStandardDescriptorAccessor; +} +- (PBMessageOptionsBuilder*) setNoStandardDescriptorAccessor:(BOOL) value { + result.hasNoStandardDescriptorAccessor = YES; + result.noStandardDescriptorAccessor = value; + return self; +} +- (PBMessageOptionsBuilder*) clearNoStandardDescriptorAccessor { + result.hasNoStandardDescriptorAccessor = NO; + result.noStandardDescriptorAccessor = NO; + return self; +} +- (BOOL) hasDeprecated { + return result.hasDeprecated; +} +- (BOOL) deprecated { + return result.deprecated; +} +- (PBMessageOptionsBuilder*) setDeprecated:(BOOL) value { + result.hasDeprecated = YES; + result.deprecated = value; + return self; +} +- (PBMessageOptionsBuilder*) clearDeprecated { + result.hasDeprecated = NO; + result.deprecated = NO; + return self; +} +- (NSMutableArray *)uninterpretedOption { + return result.uninterpretedOptionArray; +} +- (PBUninterpretedOption*)uninterpretedOptionAtIndex:(NSUInteger)index { + return [result uninterpretedOptionAtIndex:index]; +} +- (PBMessageOptionsBuilder *)addUninterpretedOption:(PBUninterpretedOption*)value { + if (result.uninterpretedOptionArray == nil) { + result.uninterpretedOptionArray = [[NSMutableArray alloc]init]; + } + [result.uninterpretedOptionArray addObject:value]; + return self; +} +- (PBMessageOptionsBuilder *)setUninterpretedOptionArray:(NSArray *)array { + result.uninterpretedOptionArray = [[NSMutableArray alloc]initWithArray:array]; + return self; +} +- (PBMessageOptionsBuilder *)clearUninterpretedOption { + result.uninterpretedOptionArray = nil; + return self; +} +@end + +@interface PBFieldOptions () +@property PBFieldOptionsCType ctype; +@property BOOL packed; +@property BOOL lazy; +@property BOOL deprecated; +@property (strong) NSString* experimentalMapKey; +@property BOOL weak; +@property (strong) NSMutableArray * uninterpretedOptionArray; +@end + +@implementation PBFieldOptions + +- (BOOL) hasCtype { + return !!hasCtype_; +} +- (void) setHasCtype:(BOOL) value_ { + hasCtype_ = !!value_; +} +@synthesize ctype; +- (BOOL) hasPacked { + return !!hasPacked_; +} +- (void) setHasPacked:(BOOL) value_ { + hasPacked_ = !!value_; +} +- (BOOL) packed { + return !!packed_; +} +- (void) setPacked:(BOOL) value_ { + packed_ = !!value_; +} +- (BOOL) hasLazy { + return !!hasLazy_; +} +- (void) setHasLazy:(BOOL) value_ { + hasLazy_ = !!value_; +} +- (BOOL) lazy { + return !!lazy_; +} +- (void) setLazy:(BOOL) value_ { + lazy_ = !!value_; +} +- (BOOL) hasDeprecated { + return !!hasDeprecated_; +} +- (void) setHasDeprecated:(BOOL) value_ { + hasDeprecated_ = !!value_; +} +- (BOOL) deprecated { + return !!deprecated_; +} +- (void) setDeprecated:(BOOL) value_ { + deprecated_ = !!value_; +} +- (BOOL) hasExperimentalMapKey { + return !!hasExperimentalMapKey_; +} +- (void) setHasExperimentalMapKey:(BOOL) value_ { + hasExperimentalMapKey_ = !!value_; +} +@synthesize experimentalMapKey; +- (BOOL) hasWeak { + return !!hasWeak_; +} +- (void) setHasWeak:(BOOL) value_ { + hasWeak_ = !!value_; +} +- (BOOL) weak { + return !!weak_; +} +- (void) setWeak:(BOOL) value_ { + weak_ = !!value_; +} +@synthesize uninterpretedOptionArray; +@dynamic uninterpretedOption; +- (id) init { + if ((self = [super init])) { + self.ctype = PBFieldOptionsCTypeString; + self.packed = NO; + self.lazy = NO; + self.deprecated = NO; + self.experimentalMapKey = @""; + self.weak = NO; + } + return self; +} +static PBFieldOptions* defaultPBFieldOptionsInstance = nil; ++ (void) initialize { + if (self == [PBFieldOptions class]) { + defaultPBFieldOptionsInstance = [[PBFieldOptions alloc] init]; + } +} ++ (PBFieldOptions*) defaultInstance { + return defaultPBFieldOptionsInstance; +} +- (PBFieldOptions*) defaultInstance { + return defaultPBFieldOptionsInstance; +} +- (NSArray *)uninterpretedOption { + return uninterpretedOptionArray; +} +- (PBUninterpretedOption*)uninterpretedOptionAtIndex:(NSUInteger)index { + return [uninterpretedOptionArray objectAtIndex:index]; +} +- (BOOL) isInitialized { + __block BOOL isInituninterpretedOption = YES; + [self.uninterpretedOption enumerateObjectsUsingBlock:^(PBUninterpretedOption *element, NSUInteger idx, BOOL *stop) { + if (!element.isInitialized) { + isInituninterpretedOption = NO; + *stop = YES; + } + }]; + if (!isInituninterpretedOption) return isInituninterpretedOption; + if (!self.extensionsAreInitialized) { + return NO; + } + return YES; +} +- (void) writeToCodedOutputStream:(PBCodedOutputStream*) output { + if (self.hasCtype) { + [output writeEnum:1 value:self.ctype]; + } + if (self.hasPacked) { + [output writeBool:2 value:self.packed]; + } + if (self.hasDeprecated) { + [output writeBool:3 value:self.deprecated]; + } + if (self.hasLazy) { + [output writeBool:5 value:self.lazy]; + } + if (self.hasExperimentalMapKey) { + [output writeString:9 value:self.experimentalMapKey]; + } + if (self.hasWeak) { + [output writeBool:10 value:self.weak]; + } + [self.uninterpretedOptionArray enumerateObjectsUsingBlock:^(PBUninterpretedOption *element, NSUInteger idx, BOOL *stop) { + [output writeMessage:999 value:element]; + }]; + [self writeExtensionsToCodedOutputStream:output + from:1000 + to:536870912]; + [self.unknownFields writeToCodedOutputStream:output]; +} +- (SInt32) serializedSize { + __block SInt32 size_ = memoizedSerializedSize; + if (size_ != -1) { + return size_; + } + + size_ = 0; + if (self.hasCtype) { + size_ += computeEnumSize(1, self.ctype); + } + if (self.hasPacked) { + size_ += computeBoolSize(2, self.packed); + } + if (self.hasDeprecated) { + size_ += computeBoolSize(3, self.deprecated); + } + if (self.hasLazy) { + size_ += computeBoolSize(5, self.lazy); + } + if (self.hasExperimentalMapKey) { + size_ += computeStringSize(9, self.experimentalMapKey); + } + if (self.hasWeak) { + size_ += computeBoolSize(10, self.weak); + } + [self.uninterpretedOptionArray enumerateObjectsUsingBlock:^(PBUninterpretedOption *element, NSUInteger idx, BOOL *stop) { + size_ += computeMessageSize(999, element); + }]; + size_ += [self extensionsSerializedSize]; + size_ += self.unknownFields.serializedSize; + memoizedSerializedSize = size_; + return size_; +} ++ (PBFieldOptions*) parseFromData:(NSData*) data { + return (PBFieldOptions*)[[[PBFieldOptions builder] mergeFromData:data] build]; +} ++ (PBFieldOptions*) parseFromData:(NSData*) data extensionRegistry:(PBExtensionRegistry*) extensionRegistry { + return (PBFieldOptions*)[[[PBFieldOptions builder] mergeFromData:data extensionRegistry:extensionRegistry] build]; +} ++ (PBFieldOptions*) parseFromInputStream:(NSInputStream*) input { + return (PBFieldOptions*)[[[PBFieldOptions builder] mergeFromInputStream:input] build]; +} ++ (PBFieldOptions*) parseFromInputStream:(NSInputStream*) input extensionRegistry:(PBExtensionRegistry*) extensionRegistry { + return (PBFieldOptions*)[[[PBFieldOptions builder] mergeFromInputStream:input extensionRegistry:extensionRegistry] build]; +} ++ (PBFieldOptions*) parseFromCodedInputStream:(PBCodedInputStream*) input { + return (PBFieldOptions*)[[[PBFieldOptions builder] mergeFromCodedInputStream:input] build]; +} ++ (PBFieldOptions*) parseFromCodedInputStream:(PBCodedInputStream*) input extensionRegistry:(PBExtensionRegistry*) extensionRegistry { + return (PBFieldOptions*)[[[PBFieldOptions builder] mergeFromCodedInputStream:input extensionRegistry:extensionRegistry] build]; +} ++ (PBFieldOptionsBuilder*) builder { + return [[PBFieldOptionsBuilder alloc] init]; +} ++ (PBFieldOptionsBuilder*) builderWithPrototype:(PBFieldOptions*) prototype { + return [[PBFieldOptions builder] mergeFrom:prototype]; +} +- (PBFieldOptionsBuilder*) builder { + return [PBFieldOptions builder]; +} +- (PBFieldOptionsBuilder*) toBuilder { + return [PBFieldOptions builderWithPrototype:self]; +} +- (void) writeDescriptionTo:(NSMutableString*) output withIndent:(NSString*) indent { + if (self.hasCtype) { + [output appendFormat:@"%@%@: %d\n", indent, @"ctype", self.ctype]; + } + if (self.hasPacked) { + [output appendFormat:@"%@%@: %@\n", indent, @"packed", [NSNumber numberWithBool:self.packed]]; + } + if (self.hasDeprecated) { + [output appendFormat:@"%@%@: %@\n", indent, @"deprecated", [NSNumber numberWithBool:self.deprecated]]; + } + if (self.hasLazy) { + [output appendFormat:@"%@%@: %@\n", indent, @"lazy", [NSNumber numberWithBool:self.lazy]]; + } + if (self.hasExperimentalMapKey) { + [output appendFormat:@"%@%@: %@\n", indent, @"experimentalMapKey", self.experimentalMapKey]; + } + if (self.hasWeak) { + [output appendFormat:@"%@%@: %@\n", indent, @"weak", [NSNumber numberWithBool:self.weak]]; + } + [self.uninterpretedOptionArray enumerateObjectsUsingBlock:^(PBUninterpretedOption *element, NSUInteger idx, BOOL *stop) { + [output appendFormat:@"%@%@ {\n", indent, @"uninterpretedOption"]; + [element writeDescriptionTo:output + withIndent:[NSString stringWithFormat:@"%@ ", indent]]; + [output appendFormat:@"%@}\n", indent]; + }]; + [self writeExtensionDescriptionToMutableString:(NSMutableString*)output + from:1000 + to:536870912 + withIndent:indent]; + [self.unknownFields writeDescriptionTo:output withIndent:indent]; +} +- (BOOL) isEqual:(id)other { + if (other == self) { + return YES; + } + if (![other isKindOfClass:[PBFieldOptions class]]) { + return NO; + } + PBFieldOptions *otherMessage = other; + return + self.hasCtype == otherMessage.hasCtype && + (!self.hasCtype || self.ctype == otherMessage.ctype) && + self.hasPacked == otherMessage.hasPacked && + (!self.hasPacked || self.packed == otherMessage.packed) && + self.hasDeprecated == otherMessage.hasDeprecated && + (!self.hasDeprecated || self.deprecated == otherMessage.deprecated) && + self.hasLazy == otherMessage.hasLazy && + (!self.hasLazy || self.lazy == otherMessage.lazy) && + self.hasExperimentalMapKey == otherMessage.hasExperimentalMapKey && + (!self.hasExperimentalMapKey || [self.experimentalMapKey isEqual:otherMessage.experimentalMapKey]) && + self.hasWeak == otherMessage.hasWeak && + (!self.hasWeak || self.weak == otherMessage.weak) && + [self.uninterpretedOptionArray isEqualToArray:otherMessage.uninterpretedOptionArray] && + [self isEqualExtensionsInOther:otherMessage from:1000 to:536870912] && + + (self.unknownFields == otherMessage.unknownFields || (self.unknownFields != nil && [self.unknownFields isEqual:otherMessage.unknownFields])); +} +- (NSUInteger) hash { + __block NSUInteger hashCode = 7; + if (self.hasCtype) { + hashCode = hashCode * 31 + self.ctype; + } + if (self.hasPacked) { + hashCode = hashCode * 31 + [[NSNumber numberWithBool:self.packed] hash]; + } + if (self.hasDeprecated) { + hashCode = hashCode * 31 + [[NSNumber numberWithBool:self.deprecated] hash]; + } + if (self.hasLazy) { + hashCode = hashCode * 31 + [[NSNumber numberWithBool:self.lazy] hash]; + } + if (self.hasExperimentalMapKey) { + hashCode = hashCode * 31 + [self.experimentalMapKey hash]; + } + if (self.hasWeak) { + hashCode = hashCode * 31 + [[NSNumber numberWithBool:self.weak] hash]; + } + [self.uninterpretedOptionArray enumerateObjectsUsingBlock:^(PBUninterpretedOption *element, NSUInteger idx, BOOL *stop) { + hashCode = hashCode * 31 + [element hash]; + }]; + hashCode = hashCode * 31 + [self hashExtensionsFrom:1000 to:536870912]; + hashCode = hashCode * 31 + [self.unknownFields hash]; + return hashCode; +} +@end + +BOOL PBFieldOptionsCTypeIsValidValue(PBFieldOptionsCType value) { + switch (value) { + case PBFieldOptionsCTypeString: + case PBFieldOptionsCTypeCord: + case PBFieldOptionsCTypeStringPiece: + return YES; + default: + return NO; + } +} +@interface PBFieldOptionsBuilder() +@property (strong) PBFieldOptions* result; +@end + +@implementation PBFieldOptionsBuilder +@synthesize result; +- (id) init { + if ((self = [super init])) { + self.result = [[PBFieldOptions alloc] init]; + } + return self; +} +- (PBExtendableMessage*) internalGetResult { + return result; +} +- (PBFieldOptionsBuilder*) clear { + self.result = [[PBFieldOptions alloc] init]; + return self; +} +- (PBFieldOptionsBuilder*) clone { + return [PBFieldOptions builderWithPrototype:result]; +} +- (PBFieldOptions*) defaultInstance { + return [PBFieldOptions defaultInstance]; +} +- (PBFieldOptions*) build { + [self checkInitialized]; + return [self buildPartial]; +} +- (PBFieldOptions*) buildPartial { + PBFieldOptions* returnMe = result; + self.result = nil; + return returnMe; +} +- (PBFieldOptionsBuilder*) mergeFrom:(PBFieldOptions*) other { + if (other == [PBFieldOptions defaultInstance]) { + return self; + } + if (other.hasCtype) { + [self setCtype:other.ctype]; + } + if (other.hasPacked) { + [self setPacked:other.packed]; + } + if (other.hasLazy) { + [self setLazy:other.lazy]; + } + if (other.hasDeprecated) { + [self setDeprecated:other.deprecated]; + } + if (other.hasExperimentalMapKey) { + [self setExperimentalMapKey:other.experimentalMapKey]; + } + if (other.hasWeak) { + [self setWeak:other.weak]; + } + if (other.uninterpretedOptionArray.count > 0) { + if (result.uninterpretedOptionArray == nil) { + result.uninterpretedOptionArray = [[NSMutableArray alloc] initWithArray:other.uninterpretedOptionArray]; + } else { + [result.uninterpretedOptionArray addObjectsFromArray:other.uninterpretedOptionArray]; + } + } + [self mergeExtensionFields:other]; + [self mergeUnknownFields:other.unknownFields]; + return self; +} +- (PBFieldOptionsBuilder*) mergeFromCodedInputStream:(PBCodedInputStream*) input { + return [self mergeFromCodedInputStream:input extensionRegistry:[PBExtensionRegistry emptyRegistry]]; +} +- (PBFieldOptionsBuilder*) mergeFromCodedInputStream:(PBCodedInputStream*) input extensionRegistry:(PBExtensionRegistry*) extensionRegistry { + PBUnknownFieldSetBuilder* unknownFields = [PBUnknownFieldSet builderWithUnknownFields:self.unknownFields]; + while (YES) { + SInt32 tag = [input readTag]; + switch (tag) { + case 0: + [self setUnknownFields:[unknownFields build]]; + return self; + default: { + if (![self parseUnknownField:input unknownFields:unknownFields extensionRegistry:extensionRegistry tag:tag]) { + [self setUnknownFields:[unknownFields build]]; + return self; + } + break; + } + case 8: { + PBFieldOptionsCType value = (PBFieldOptionsCType)[input readEnum]; + if (PBFieldOptionsCTypeIsValidValue(value)) { + [self setCtype:value]; + } else { + [unknownFields mergeVarintField:1 value:value]; + } + break; + } + case 16: { + [self setPacked:[input readBool]]; + break; + } + case 24: { + [self setDeprecated:[input readBool]]; + break; + } + case 40: { + [self setLazy:[input readBool]]; + break; + } + case 74: { + [self setExperimentalMapKey:[input readString]]; + break; + } + case 80: { + [self setWeak:[input readBool]]; + break; + } + case 7994: { + PBUninterpretedOptionBuilder* subBuilder = [PBUninterpretedOption builder]; + [input readMessage:subBuilder extensionRegistry:extensionRegistry]; + [self addUninterpretedOption:[subBuilder buildPartial]]; + break; + } + } + } +} +- (BOOL) hasCtype { + return result.hasCtype; +} +- (PBFieldOptionsCType) ctype { + return result.ctype; +} +- (PBFieldOptionsBuilder*) setCtype:(PBFieldOptionsCType) value { + result.hasCtype = YES; + result.ctype = value; + return self; +} +- (PBFieldOptionsBuilder*) clearCtype { + result.hasCtype = NO; + result.ctype = PBFieldOptionsCTypeString; + return self; +} +- (BOOL) hasPacked { + return result.hasPacked; +} +- (BOOL) packed { + return result.packed; +} +- (PBFieldOptionsBuilder*) setPacked:(BOOL) value { + result.hasPacked = YES; + result.packed = value; + return self; +} +- (PBFieldOptionsBuilder*) clearPacked { + result.hasPacked = NO; + result.packed = NO; + return self; +} +- (BOOL) hasLazy { + return result.hasLazy; +} +- (BOOL) lazy { + return result.lazy; +} +- (PBFieldOptionsBuilder*) setLazy:(BOOL) value { + result.hasLazy = YES; + result.lazy = value; + return self; +} +- (PBFieldOptionsBuilder*) clearLazy { + result.hasLazy = NO; + result.lazy = NO; + return self; +} +- (BOOL) hasDeprecated { + return result.hasDeprecated; +} +- (BOOL) deprecated { + return result.deprecated; +} +- (PBFieldOptionsBuilder*) setDeprecated:(BOOL) value { + result.hasDeprecated = YES; + result.deprecated = value; + return self; +} +- (PBFieldOptionsBuilder*) clearDeprecated { + result.hasDeprecated = NO; + result.deprecated = NO; + return self; +} +- (BOOL) hasExperimentalMapKey { + return result.hasExperimentalMapKey; +} +- (NSString*) experimentalMapKey { + return result.experimentalMapKey; +} +- (PBFieldOptionsBuilder*) setExperimentalMapKey:(NSString*) value { + result.hasExperimentalMapKey = YES; + result.experimentalMapKey = value; + return self; +} +- (PBFieldOptionsBuilder*) clearExperimentalMapKey { + result.hasExperimentalMapKey = NO; + result.experimentalMapKey = @""; + return self; +} +- (BOOL) hasWeak { + return result.hasWeak; +} +- (BOOL) weak { + return result.weak; +} +- (PBFieldOptionsBuilder*) setWeak:(BOOL) value { + result.hasWeak = YES; + result.weak = value; + return self; +} +- (PBFieldOptionsBuilder*) clearWeak { + result.hasWeak = NO; + result.weak = NO; + return self; +} +- (NSMutableArray *)uninterpretedOption { + return result.uninterpretedOptionArray; +} +- (PBUninterpretedOption*)uninterpretedOptionAtIndex:(NSUInteger)index { + return [result uninterpretedOptionAtIndex:index]; +} +- (PBFieldOptionsBuilder *)addUninterpretedOption:(PBUninterpretedOption*)value { + if (result.uninterpretedOptionArray == nil) { + result.uninterpretedOptionArray = [[NSMutableArray alloc]init]; + } + [result.uninterpretedOptionArray addObject:value]; + return self; +} +- (PBFieldOptionsBuilder *)setUninterpretedOptionArray:(NSArray *)array { + result.uninterpretedOptionArray = [[NSMutableArray alloc]initWithArray:array]; + return self; +} +- (PBFieldOptionsBuilder *)clearUninterpretedOption { + result.uninterpretedOptionArray = nil; + return self; +} +@end + +@interface PBEnumOptions () +@property BOOL allowAlias; +@property BOOL deprecated; +@property (strong) NSMutableArray * uninterpretedOptionArray; +@end + +@implementation PBEnumOptions + +- (BOOL) hasAllowAlias { + return !!hasAllowAlias_; +} +- (void) setHasAllowAlias:(BOOL) value_ { + hasAllowAlias_ = !!value_; +} +- (BOOL) allowAlias { + return !!allowAlias_; +} +- (void) setAllowAlias:(BOOL) value_ { + allowAlias_ = !!value_; +} +- (BOOL) hasDeprecated { + return !!hasDeprecated_; +} +- (void) setHasDeprecated:(BOOL) value_ { + hasDeprecated_ = !!value_; +} +- (BOOL) deprecated { + return !!deprecated_; +} +- (void) setDeprecated:(BOOL) value_ { + deprecated_ = !!value_; +} +@synthesize uninterpretedOptionArray; +@dynamic uninterpretedOption; +- (id) init { + if ((self = [super init])) { + self.allowAlias = NO; + self.deprecated = NO; + } + return self; +} +static PBEnumOptions* defaultPBEnumOptionsInstance = nil; ++ (void) initialize { + if (self == [PBEnumOptions class]) { + defaultPBEnumOptionsInstance = [[PBEnumOptions alloc] init]; + } +} ++ (PBEnumOptions*) defaultInstance { + return defaultPBEnumOptionsInstance; +} +- (PBEnumOptions*) defaultInstance { + return defaultPBEnumOptionsInstance; +} +- (NSArray *)uninterpretedOption { + return uninterpretedOptionArray; +} +- (PBUninterpretedOption*)uninterpretedOptionAtIndex:(NSUInteger)index { + return [uninterpretedOptionArray objectAtIndex:index]; +} +- (BOOL) isInitialized { + __block BOOL isInituninterpretedOption = YES; + [self.uninterpretedOption enumerateObjectsUsingBlock:^(PBUninterpretedOption *element, NSUInteger idx, BOOL *stop) { + if (!element.isInitialized) { + isInituninterpretedOption = NO; + *stop = YES; + } + }]; + if (!isInituninterpretedOption) return isInituninterpretedOption; + if (!self.extensionsAreInitialized) { + return NO; + } + return YES; +} +- (void) writeToCodedOutputStream:(PBCodedOutputStream*) output { + if (self.hasAllowAlias) { + [output writeBool:2 value:self.allowAlias]; + } + if (self.hasDeprecated) { + [output writeBool:3 value:self.deprecated]; + } + [self.uninterpretedOptionArray enumerateObjectsUsingBlock:^(PBUninterpretedOption *element, NSUInteger idx, BOOL *stop) { + [output writeMessage:999 value:element]; + }]; + [self writeExtensionsToCodedOutputStream:output + from:1000 + to:536870912]; + [self.unknownFields writeToCodedOutputStream:output]; +} +- (SInt32) serializedSize { + __block SInt32 size_ = memoizedSerializedSize; + if (size_ != -1) { + return size_; + } + + size_ = 0; + if (self.hasAllowAlias) { + size_ += computeBoolSize(2, self.allowAlias); + } + if (self.hasDeprecated) { + size_ += computeBoolSize(3, self.deprecated); + } + [self.uninterpretedOptionArray enumerateObjectsUsingBlock:^(PBUninterpretedOption *element, NSUInteger idx, BOOL *stop) { + size_ += computeMessageSize(999, element); + }]; + size_ += [self extensionsSerializedSize]; + size_ += self.unknownFields.serializedSize; + memoizedSerializedSize = size_; + return size_; +} ++ (PBEnumOptions*) parseFromData:(NSData*) data { + return (PBEnumOptions*)[[[PBEnumOptions builder] mergeFromData:data] build]; +} ++ (PBEnumOptions*) parseFromData:(NSData*) data extensionRegistry:(PBExtensionRegistry*) extensionRegistry { + return (PBEnumOptions*)[[[PBEnumOptions builder] mergeFromData:data extensionRegistry:extensionRegistry] build]; +} ++ (PBEnumOptions*) parseFromInputStream:(NSInputStream*) input { + return (PBEnumOptions*)[[[PBEnumOptions builder] mergeFromInputStream:input] build]; +} ++ (PBEnumOptions*) parseFromInputStream:(NSInputStream*) input extensionRegistry:(PBExtensionRegistry*) extensionRegistry { + return (PBEnumOptions*)[[[PBEnumOptions builder] mergeFromInputStream:input extensionRegistry:extensionRegistry] build]; +} ++ (PBEnumOptions*) parseFromCodedInputStream:(PBCodedInputStream*) input { + return (PBEnumOptions*)[[[PBEnumOptions builder] mergeFromCodedInputStream:input] build]; +} ++ (PBEnumOptions*) parseFromCodedInputStream:(PBCodedInputStream*) input extensionRegistry:(PBExtensionRegistry*) extensionRegistry { + return (PBEnumOptions*)[[[PBEnumOptions builder] mergeFromCodedInputStream:input extensionRegistry:extensionRegistry] build]; +} ++ (PBEnumOptionsBuilder*) builder { + return [[PBEnumOptionsBuilder alloc] init]; +} ++ (PBEnumOptionsBuilder*) builderWithPrototype:(PBEnumOptions*) prototype { + return [[PBEnumOptions builder] mergeFrom:prototype]; +} +- (PBEnumOptionsBuilder*) builder { + return [PBEnumOptions builder]; +} +- (PBEnumOptionsBuilder*) toBuilder { + return [PBEnumOptions builderWithPrototype:self]; +} +- (void) writeDescriptionTo:(NSMutableString*) output withIndent:(NSString*) indent { + if (self.hasAllowAlias) { + [output appendFormat:@"%@%@: %@\n", indent, @"allowAlias", [NSNumber numberWithBool:self.allowAlias]]; + } + if (self.hasDeprecated) { + [output appendFormat:@"%@%@: %@\n", indent, @"deprecated", [NSNumber numberWithBool:self.deprecated]]; + } + [self.uninterpretedOptionArray enumerateObjectsUsingBlock:^(PBUninterpretedOption *element, NSUInteger idx, BOOL *stop) { + [output appendFormat:@"%@%@ {\n", indent, @"uninterpretedOption"]; + [element writeDescriptionTo:output + withIndent:[NSString stringWithFormat:@"%@ ", indent]]; + [output appendFormat:@"%@}\n", indent]; + }]; + [self writeExtensionDescriptionToMutableString:(NSMutableString*)output + from:1000 + to:536870912 + withIndent:indent]; + [self.unknownFields writeDescriptionTo:output withIndent:indent]; +} +- (BOOL) isEqual:(id)other { + if (other == self) { + return YES; + } + if (![other isKindOfClass:[PBEnumOptions class]]) { + return NO; + } + PBEnumOptions *otherMessage = other; + return + self.hasAllowAlias == otherMessage.hasAllowAlias && + (!self.hasAllowAlias || self.allowAlias == otherMessage.allowAlias) && + self.hasDeprecated == otherMessage.hasDeprecated && + (!self.hasDeprecated || self.deprecated == otherMessage.deprecated) && + [self.uninterpretedOptionArray isEqualToArray:otherMessage.uninterpretedOptionArray] && + [self isEqualExtensionsInOther:otherMessage from:1000 to:536870912] && + + (self.unknownFields == otherMessage.unknownFields || (self.unknownFields != nil && [self.unknownFields isEqual:otherMessage.unknownFields])); +} +- (NSUInteger) hash { + __block NSUInteger hashCode = 7; + if (self.hasAllowAlias) { + hashCode = hashCode * 31 + [[NSNumber numberWithBool:self.allowAlias] hash]; + } + if (self.hasDeprecated) { + hashCode = hashCode * 31 + [[NSNumber numberWithBool:self.deprecated] hash]; + } + [self.uninterpretedOptionArray enumerateObjectsUsingBlock:^(PBUninterpretedOption *element, NSUInteger idx, BOOL *stop) { + hashCode = hashCode * 31 + [element hash]; + }]; + hashCode = hashCode * 31 + [self hashExtensionsFrom:1000 to:536870912]; + hashCode = hashCode * 31 + [self.unknownFields hash]; + return hashCode; +} +@end + +@interface PBEnumOptionsBuilder() +@property (strong) PBEnumOptions* result; +@end + +@implementation PBEnumOptionsBuilder +@synthesize result; +- (id) init { + if ((self = [super init])) { + self.result = [[PBEnumOptions alloc] init]; + } + return self; +} +- (PBExtendableMessage*) internalGetResult { + return result; +} +- (PBEnumOptionsBuilder*) clear { + self.result = [[PBEnumOptions alloc] init]; + return self; +} +- (PBEnumOptionsBuilder*) clone { + return [PBEnumOptions builderWithPrototype:result]; +} +- (PBEnumOptions*) defaultInstance { + return [PBEnumOptions defaultInstance]; +} +- (PBEnumOptions*) build { + [self checkInitialized]; + return [self buildPartial]; +} +- (PBEnumOptions*) buildPartial { + PBEnumOptions* returnMe = result; + self.result = nil; + return returnMe; +} +- (PBEnumOptionsBuilder*) mergeFrom:(PBEnumOptions*) other { + if (other == [PBEnumOptions defaultInstance]) { + return self; + } + if (other.hasAllowAlias) { + [self setAllowAlias:other.allowAlias]; + } + if (other.hasDeprecated) { + [self setDeprecated:other.deprecated]; + } + if (other.uninterpretedOptionArray.count > 0) { + if (result.uninterpretedOptionArray == nil) { + result.uninterpretedOptionArray = [[NSMutableArray alloc] initWithArray:other.uninterpretedOptionArray]; + } else { + [result.uninterpretedOptionArray addObjectsFromArray:other.uninterpretedOptionArray]; + } + } + [self mergeExtensionFields:other]; + [self mergeUnknownFields:other.unknownFields]; + return self; +} +- (PBEnumOptionsBuilder*) mergeFromCodedInputStream:(PBCodedInputStream*) input { + return [self mergeFromCodedInputStream:input extensionRegistry:[PBExtensionRegistry emptyRegistry]]; +} +- (PBEnumOptionsBuilder*) mergeFromCodedInputStream:(PBCodedInputStream*) input extensionRegistry:(PBExtensionRegistry*) extensionRegistry { + PBUnknownFieldSetBuilder* unknownFields = [PBUnknownFieldSet builderWithUnknownFields:self.unknownFields]; + while (YES) { + SInt32 tag = [input readTag]; + switch (tag) { + case 0: + [self setUnknownFields:[unknownFields build]]; + return self; + default: { + if (![self parseUnknownField:input unknownFields:unknownFields extensionRegistry:extensionRegistry tag:tag]) { + [self setUnknownFields:[unknownFields build]]; + return self; + } + break; + } + case 16: { + [self setAllowAlias:[input readBool]]; + break; + } + case 24: { + [self setDeprecated:[input readBool]]; + break; + } + case 7994: { + PBUninterpretedOptionBuilder* subBuilder = [PBUninterpretedOption builder]; + [input readMessage:subBuilder extensionRegistry:extensionRegistry]; + [self addUninterpretedOption:[subBuilder buildPartial]]; + break; + } + } + } +} +- (BOOL) hasAllowAlias { + return result.hasAllowAlias; +} +- (BOOL) allowAlias { + return result.allowAlias; +} +- (PBEnumOptionsBuilder*) setAllowAlias:(BOOL) value { + result.hasAllowAlias = YES; + result.allowAlias = value; + return self; +} +- (PBEnumOptionsBuilder*) clearAllowAlias { + result.hasAllowAlias = NO; + result.allowAlias = NO; + return self; +} +- (BOOL) hasDeprecated { + return result.hasDeprecated; +} +- (BOOL) deprecated { + return result.deprecated; +} +- (PBEnumOptionsBuilder*) setDeprecated:(BOOL) value { + result.hasDeprecated = YES; + result.deprecated = value; + return self; +} +- (PBEnumOptionsBuilder*) clearDeprecated { + result.hasDeprecated = NO; + result.deprecated = NO; + return self; +} +- (NSMutableArray *)uninterpretedOption { + return result.uninterpretedOptionArray; +} +- (PBUninterpretedOption*)uninterpretedOptionAtIndex:(NSUInteger)index { + return [result uninterpretedOptionAtIndex:index]; +} +- (PBEnumOptionsBuilder *)addUninterpretedOption:(PBUninterpretedOption*)value { + if (result.uninterpretedOptionArray == nil) { + result.uninterpretedOptionArray = [[NSMutableArray alloc]init]; + } + [result.uninterpretedOptionArray addObject:value]; + return self; +} +- (PBEnumOptionsBuilder *)setUninterpretedOptionArray:(NSArray *)array { + result.uninterpretedOptionArray = [[NSMutableArray alloc]initWithArray:array]; + return self; +} +- (PBEnumOptionsBuilder *)clearUninterpretedOption { + result.uninterpretedOptionArray = nil; + return self; +} +@end + +@interface PBEnumValueOptions () +@property BOOL deprecated; +@property (strong) NSMutableArray * uninterpretedOptionArray; +@end + +@implementation PBEnumValueOptions + +- (BOOL) hasDeprecated { + return !!hasDeprecated_; +} +- (void) setHasDeprecated:(BOOL) value_ { + hasDeprecated_ = !!value_; +} +- (BOOL) deprecated { + return !!deprecated_; +} +- (void) setDeprecated:(BOOL) value_ { + deprecated_ = !!value_; +} +@synthesize uninterpretedOptionArray; +@dynamic uninterpretedOption; +- (id) init { + if ((self = [super init])) { + self.deprecated = NO; + } + return self; +} +static PBEnumValueOptions* defaultPBEnumValueOptionsInstance = nil; ++ (void) initialize { + if (self == [PBEnumValueOptions class]) { + defaultPBEnumValueOptionsInstance = [[PBEnumValueOptions alloc] init]; + } +} ++ (PBEnumValueOptions*) defaultInstance { + return defaultPBEnumValueOptionsInstance; +} +- (PBEnumValueOptions*) defaultInstance { + return defaultPBEnumValueOptionsInstance; +} +- (NSArray *)uninterpretedOption { + return uninterpretedOptionArray; +} +- (PBUninterpretedOption*)uninterpretedOptionAtIndex:(NSUInteger)index { + return [uninterpretedOptionArray objectAtIndex:index]; +} +- (BOOL) isInitialized { + __block BOOL isInituninterpretedOption = YES; + [self.uninterpretedOption enumerateObjectsUsingBlock:^(PBUninterpretedOption *element, NSUInteger idx, BOOL *stop) { + if (!element.isInitialized) { + isInituninterpretedOption = NO; + *stop = YES; + } + }]; + if (!isInituninterpretedOption) return isInituninterpretedOption; + if (!self.extensionsAreInitialized) { + return NO; + } + return YES; +} +- (void) writeToCodedOutputStream:(PBCodedOutputStream*) output { + if (self.hasDeprecated) { + [output writeBool:1 value:self.deprecated]; + } + [self.uninterpretedOptionArray enumerateObjectsUsingBlock:^(PBUninterpretedOption *element, NSUInteger idx, BOOL *stop) { + [output writeMessage:999 value:element]; + }]; + [self writeExtensionsToCodedOutputStream:output + from:1000 + to:536870912]; + [self.unknownFields writeToCodedOutputStream:output]; +} +- (SInt32) serializedSize { + __block SInt32 size_ = memoizedSerializedSize; + if (size_ != -1) { + return size_; + } + + size_ = 0; + if (self.hasDeprecated) { + size_ += computeBoolSize(1, self.deprecated); + } + [self.uninterpretedOptionArray enumerateObjectsUsingBlock:^(PBUninterpretedOption *element, NSUInteger idx, BOOL *stop) { + size_ += computeMessageSize(999, element); + }]; + size_ += [self extensionsSerializedSize]; + size_ += self.unknownFields.serializedSize; + memoizedSerializedSize = size_; + return size_; +} ++ (PBEnumValueOptions*) parseFromData:(NSData*) data { + return (PBEnumValueOptions*)[[[PBEnumValueOptions builder] mergeFromData:data] build]; +} ++ (PBEnumValueOptions*) parseFromData:(NSData*) data extensionRegistry:(PBExtensionRegistry*) extensionRegistry { + return (PBEnumValueOptions*)[[[PBEnumValueOptions builder] mergeFromData:data extensionRegistry:extensionRegistry] build]; +} ++ (PBEnumValueOptions*) parseFromInputStream:(NSInputStream*) input { + return (PBEnumValueOptions*)[[[PBEnumValueOptions builder] mergeFromInputStream:input] build]; +} ++ (PBEnumValueOptions*) parseFromInputStream:(NSInputStream*) input extensionRegistry:(PBExtensionRegistry*) extensionRegistry { + return (PBEnumValueOptions*)[[[PBEnumValueOptions builder] mergeFromInputStream:input extensionRegistry:extensionRegistry] build]; +} ++ (PBEnumValueOptions*) parseFromCodedInputStream:(PBCodedInputStream*) input { + return (PBEnumValueOptions*)[[[PBEnumValueOptions builder] mergeFromCodedInputStream:input] build]; +} ++ (PBEnumValueOptions*) parseFromCodedInputStream:(PBCodedInputStream*) input extensionRegistry:(PBExtensionRegistry*) extensionRegistry { + return (PBEnumValueOptions*)[[[PBEnumValueOptions builder] mergeFromCodedInputStream:input extensionRegistry:extensionRegistry] build]; +} ++ (PBEnumValueOptionsBuilder*) builder { + return [[PBEnumValueOptionsBuilder alloc] init]; +} ++ (PBEnumValueOptionsBuilder*) builderWithPrototype:(PBEnumValueOptions*) prototype { + return [[PBEnumValueOptions builder] mergeFrom:prototype]; +} +- (PBEnumValueOptionsBuilder*) builder { + return [PBEnumValueOptions builder]; +} +- (PBEnumValueOptionsBuilder*) toBuilder { + return [PBEnumValueOptions builderWithPrototype:self]; +} +- (void) writeDescriptionTo:(NSMutableString*) output withIndent:(NSString*) indent { + if (self.hasDeprecated) { + [output appendFormat:@"%@%@: %@\n", indent, @"deprecated", [NSNumber numberWithBool:self.deprecated]]; + } + [self.uninterpretedOptionArray enumerateObjectsUsingBlock:^(PBUninterpretedOption *element, NSUInteger idx, BOOL *stop) { + [output appendFormat:@"%@%@ {\n", indent, @"uninterpretedOption"]; + [element writeDescriptionTo:output + withIndent:[NSString stringWithFormat:@"%@ ", indent]]; + [output appendFormat:@"%@}\n", indent]; + }]; + [self writeExtensionDescriptionToMutableString:(NSMutableString*)output + from:1000 + to:536870912 + withIndent:indent]; + [self.unknownFields writeDescriptionTo:output withIndent:indent]; +} +- (BOOL) isEqual:(id)other { + if (other == self) { + return YES; + } + if (![other isKindOfClass:[PBEnumValueOptions class]]) { + return NO; + } + PBEnumValueOptions *otherMessage = other; + return + self.hasDeprecated == otherMessage.hasDeprecated && + (!self.hasDeprecated || self.deprecated == otherMessage.deprecated) && + [self.uninterpretedOptionArray isEqualToArray:otherMessage.uninterpretedOptionArray] && + [self isEqualExtensionsInOther:otherMessage from:1000 to:536870912] && + + (self.unknownFields == otherMessage.unknownFields || (self.unknownFields != nil && [self.unknownFields isEqual:otherMessage.unknownFields])); +} +- (NSUInteger) hash { + __block NSUInteger hashCode = 7; + if (self.hasDeprecated) { + hashCode = hashCode * 31 + [[NSNumber numberWithBool:self.deprecated] hash]; + } + [self.uninterpretedOptionArray enumerateObjectsUsingBlock:^(PBUninterpretedOption *element, NSUInteger idx, BOOL *stop) { + hashCode = hashCode * 31 + [element hash]; + }]; + hashCode = hashCode * 31 + [self hashExtensionsFrom:1000 to:536870912]; + hashCode = hashCode * 31 + [self.unknownFields hash]; + return hashCode; +} +@end + +@interface PBEnumValueOptionsBuilder() +@property (strong) PBEnumValueOptions* result; +@end + +@implementation PBEnumValueOptionsBuilder +@synthesize result; +- (id) init { + if ((self = [super init])) { + self.result = [[PBEnumValueOptions alloc] init]; + } + return self; +} +- (PBExtendableMessage*) internalGetResult { + return result; +} +- (PBEnumValueOptionsBuilder*) clear { + self.result = [[PBEnumValueOptions alloc] init]; + return self; +} +- (PBEnumValueOptionsBuilder*) clone { + return [PBEnumValueOptions builderWithPrototype:result]; +} +- (PBEnumValueOptions*) defaultInstance { + return [PBEnumValueOptions defaultInstance]; +} +- (PBEnumValueOptions*) build { + [self checkInitialized]; + return [self buildPartial]; +} +- (PBEnumValueOptions*) buildPartial { + PBEnumValueOptions* returnMe = result; + self.result = nil; + return returnMe; +} +- (PBEnumValueOptionsBuilder*) mergeFrom:(PBEnumValueOptions*) other { + if (other == [PBEnumValueOptions defaultInstance]) { + return self; + } + if (other.hasDeprecated) { + [self setDeprecated:other.deprecated]; + } + if (other.uninterpretedOptionArray.count > 0) { + if (result.uninterpretedOptionArray == nil) { + result.uninterpretedOptionArray = [[NSMutableArray alloc] initWithArray:other.uninterpretedOptionArray]; + } else { + [result.uninterpretedOptionArray addObjectsFromArray:other.uninterpretedOptionArray]; + } + } + [self mergeExtensionFields:other]; + [self mergeUnknownFields:other.unknownFields]; + return self; +} +- (PBEnumValueOptionsBuilder*) mergeFromCodedInputStream:(PBCodedInputStream*) input { + return [self mergeFromCodedInputStream:input extensionRegistry:[PBExtensionRegistry emptyRegistry]]; +} +- (PBEnumValueOptionsBuilder*) mergeFromCodedInputStream:(PBCodedInputStream*) input extensionRegistry:(PBExtensionRegistry*) extensionRegistry { + PBUnknownFieldSetBuilder* unknownFields = [PBUnknownFieldSet builderWithUnknownFields:self.unknownFields]; + while (YES) { + SInt32 tag = [input readTag]; + switch (tag) { + case 0: + [self setUnknownFields:[unknownFields build]]; + return self; + default: { + if (![self parseUnknownField:input unknownFields:unknownFields extensionRegistry:extensionRegistry tag:tag]) { + [self setUnknownFields:[unknownFields build]]; + return self; + } + break; + } + case 8: { + [self setDeprecated:[input readBool]]; + break; + } + case 7994: { + PBUninterpretedOptionBuilder* subBuilder = [PBUninterpretedOption builder]; + [input readMessage:subBuilder extensionRegistry:extensionRegistry]; + [self addUninterpretedOption:[subBuilder buildPartial]]; + break; + } + } + } +} +- (BOOL) hasDeprecated { + return result.hasDeprecated; +} +- (BOOL) deprecated { + return result.deprecated; +} +- (PBEnumValueOptionsBuilder*) setDeprecated:(BOOL) value { + result.hasDeprecated = YES; + result.deprecated = value; + return self; +} +- (PBEnumValueOptionsBuilder*) clearDeprecated { + result.hasDeprecated = NO; + result.deprecated = NO; + return self; +} +- (NSMutableArray *)uninterpretedOption { + return result.uninterpretedOptionArray; +} +- (PBUninterpretedOption*)uninterpretedOptionAtIndex:(NSUInteger)index { + return [result uninterpretedOptionAtIndex:index]; +} +- (PBEnumValueOptionsBuilder *)addUninterpretedOption:(PBUninterpretedOption*)value { + if (result.uninterpretedOptionArray == nil) { + result.uninterpretedOptionArray = [[NSMutableArray alloc]init]; + } + [result.uninterpretedOptionArray addObject:value]; + return self; +} +- (PBEnumValueOptionsBuilder *)setUninterpretedOptionArray:(NSArray *)array { + result.uninterpretedOptionArray = [[NSMutableArray alloc]initWithArray:array]; + return self; +} +- (PBEnumValueOptionsBuilder *)clearUninterpretedOption { + result.uninterpretedOptionArray = nil; + return self; +} +@end + +@interface PBServiceOptions () +@property BOOL deprecated; +@property (strong) NSMutableArray * uninterpretedOptionArray; +@end + +@implementation PBServiceOptions + +- (BOOL) hasDeprecated { + return !!hasDeprecated_; +} +- (void) setHasDeprecated:(BOOL) value_ { + hasDeprecated_ = !!value_; +} +- (BOOL) deprecated { + return !!deprecated_; +} +- (void) setDeprecated:(BOOL) value_ { + deprecated_ = !!value_; +} +@synthesize uninterpretedOptionArray; +@dynamic uninterpretedOption; +- (id) init { + if ((self = [super init])) { + self.deprecated = NO; + } + return self; +} +static PBServiceOptions* defaultPBServiceOptionsInstance = nil; ++ (void) initialize { + if (self == [PBServiceOptions class]) { + defaultPBServiceOptionsInstance = [[PBServiceOptions alloc] init]; + } +} ++ (PBServiceOptions*) defaultInstance { + return defaultPBServiceOptionsInstance; +} +- (PBServiceOptions*) defaultInstance { + return defaultPBServiceOptionsInstance; +} +- (NSArray *)uninterpretedOption { + return uninterpretedOptionArray; +} +- (PBUninterpretedOption*)uninterpretedOptionAtIndex:(NSUInteger)index { + return [uninterpretedOptionArray objectAtIndex:index]; +} +- (BOOL) isInitialized { + __block BOOL isInituninterpretedOption = YES; + [self.uninterpretedOption enumerateObjectsUsingBlock:^(PBUninterpretedOption *element, NSUInteger idx, BOOL *stop) { + if (!element.isInitialized) { + isInituninterpretedOption = NO; + *stop = YES; + } + }]; + if (!isInituninterpretedOption) return isInituninterpretedOption; + if (!self.extensionsAreInitialized) { + return NO; + } + return YES; +} +- (void) writeToCodedOutputStream:(PBCodedOutputStream*) output { + if (self.hasDeprecated) { + [output writeBool:33 value:self.deprecated]; + } + [self.uninterpretedOptionArray enumerateObjectsUsingBlock:^(PBUninterpretedOption *element, NSUInteger idx, BOOL *stop) { + [output writeMessage:999 value:element]; + }]; + [self writeExtensionsToCodedOutputStream:output + from:1000 + to:536870912]; + [self.unknownFields writeToCodedOutputStream:output]; +} +- (SInt32) serializedSize { + __block SInt32 size_ = memoizedSerializedSize; + if (size_ != -1) { + return size_; + } + + size_ = 0; + if (self.hasDeprecated) { + size_ += computeBoolSize(33, self.deprecated); + } + [self.uninterpretedOptionArray enumerateObjectsUsingBlock:^(PBUninterpretedOption *element, NSUInteger idx, BOOL *stop) { + size_ += computeMessageSize(999, element); + }]; + size_ += [self extensionsSerializedSize]; + size_ += self.unknownFields.serializedSize; + memoizedSerializedSize = size_; + return size_; +} ++ (PBServiceOptions*) parseFromData:(NSData*) data { + return (PBServiceOptions*)[[[PBServiceOptions builder] mergeFromData:data] build]; +} ++ (PBServiceOptions*) parseFromData:(NSData*) data extensionRegistry:(PBExtensionRegistry*) extensionRegistry { + return (PBServiceOptions*)[[[PBServiceOptions builder] mergeFromData:data extensionRegistry:extensionRegistry] build]; +} ++ (PBServiceOptions*) parseFromInputStream:(NSInputStream*) input { + return (PBServiceOptions*)[[[PBServiceOptions builder] mergeFromInputStream:input] build]; +} ++ (PBServiceOptions*) parseFromInputStream:(NSInputStream*) input extensionRegistry:(PBExtensionRegistry*) extensionRegistry { + return (PBServiceOptions*)[[[PBServiceOptions builder] mergeFromInputStream:input extensionRegistry:extensionRegistry] build]; +} ++ (PBServiceOptions*) parseFromCodedInputStream:(PBCodedInputStream*) input { + return (PBServiceOptions*)[[[PBServiceOptions builder] mergeFromCodedInputStream:input] build]; +} ++ (PBServiceOptions*) parseFromCodedInputStream:(PBCodedInputStream*) input extensionRegistry:(PBExtensionRegistry*) extensionRegistry { + return (PBServiceOptions*)[[[PBServiceOptions builder] mergeFromCodedInputStream:input extensionRegistry:extensionRegistry] build]; +} ++ (PBServiceOptionsBuilder*) builder { + return [[PBServiceOptionsBuilder alloc] init]; +} ++ (PBServiceOptionsBuilder*) builderWithPrototype:(PBServiceOptions*) prototype { + return [[PBServiceOptions builder] mergeFrom:prototype]; +} +- (PBServiceOptionsBuilder*) builder { + return [PBServiceOptions builder]; +} +- (PBServiceOptionsBuilder*) toBuilder { + return [PBServiceOptions builderWithPrototype:self]; +} +- (void) writeDescriptionTo:(NSMutableString*) output withIndent:(NSString*) indent { + if (self.hasDeprecated) { + [output appendFormat:@"%@%@: %@\n", indent, @"deprecated", [NSNumber numberWithBool:self.deprecated]]; + } + [self.uninterpretedOptionArray enumerateObjectsUsingBlock:^(PBUninterpretedOption *element, NSUInteger idx, BOOL *stop) { + [output appendFormat:@"%@%@ {\n", indent, @"uninterpretedOption"]; + [element writeDescriptionTo:output + withIndent:[NSString stringWithFormat:@"%@ ", indent]]; + [output appendFormat:@"%@}\n", indent]; + }]; + [self writeExtensionDescriptionToMutableString:(NSMutableString*)output + from:1000 + to:536870912 + withIndent:indent]; + [self.unknownFields writeDescriptionTo:output withIndent:indent]; +} +- (BOOL) isEqual:(id)other { + if (other == self) { + return YES; + } + if (![other isKindOfClass:[PBServiceOptions class]]) { + return NO; + } + PBServiceOptions *otherMessage = other; + return + self.hasDeprecated == otherMessage.hasDeprecated && + (!self.hasDeprecated || self.deprecated == otherMessage.deprecated) && + [self.uninterpretedOptionArray isEqualToArray:otherMessage.uninterpretedOptionArray] && + [self isEqualExtensionsInOther:otherMessage from:1000 to:536870912] && + + (self.unknownFields == otherMessage.unknownFields || (self.unknownFields != nil && [self.unknownFields isEqual:otherMessage.unknownFields])); +} +- (NSUInteger) hash { + __block NSUInteger hashCode = 7; + if (self.hasDeprecated) { + hashCode = hashCode * 31 + [[NSNumber numberWithBool:self.deprecated] hash]; + } + [self.uninterpretedOptionArray enumerateObjectsUsingBlock:^(PBUninterpretedOption *element, NSUInteger idx, BOOL *stop) { + hashCode = hashCode * 31 + [element hash]; + }]; + hashCode = hashCode * 31 + [self hashExtensionsFrom:1000 to:536870912]; + hashCode = hashCode * 31 + [self.unknownFields hash]; + return hashCode; +} +@end + +@interface PBServiceOptionsBuilder() +@property (strong) PBServiceOptions* result; +@end + +@implementation PBServiceOptionsBuilder +@synthesize result; +- (id) init { + if ((self = [super init])) { + self.result = [[PBServiceOptions alloc] init]; + } + return self; +} +- (PBExtendableMessage*) internalGetResult { + return result; +} +- (PBServiceOptionsBuilder*) clear { + self.result = [[PBServiceOptions alloc] init]; + return self; +} +- (PBServiceOptionsBuilder*) clone { + return [PBServiceOptions builderWithPrototype:result]; +} +- (PBServiceOptions*) defaultInstance { + return [PBServiceOptions defaultInstance]; +} +- (PBServiceOptions*) build { + [self checkInitialized]; + return [self buildPartial]; +} +- (PBServiceOptions*) buildPartial { + PBServiceOptions* returnMe = result; + self.result = nil; + return returnMe; +} +- (PBServiceOptionsBuilder*) mergeFrom:(PBServiceOptions*) other { + if (other == [PBServiceOptions defaultInstance]) { + return self; + } + if (other.hasDeprecated) { + [self setDeprecated:other.deprecated]; + } + if (other.uninterpretedOptionArray.count > 0) { + if (result.uninterpretedOptionArray == nil) { + result.uninterpretedOptionArray = [[NSMutableArray alloc] initWithArray:other.uninterpretedOptionArray]; + } else { + [result.uninterpretedOptionArray addObjectsFromArray:other.uninterpretedOptionArray]; + } + } + [self mergeExtensionFields:other]; + [self mergeUnknownFields:other.unknownFields]; + return self; +} +- (PBServiceOptionsBuilder*) mergeFromCodedInputStream:(PBCodedInputStream*) input { + return [self mergeFromCodedInputStream:input extensionRegistry:[PBExtensionRegistry emptyRegistry]]; +} +- (PBServiceOptionsBuilder*) mergeFromCodedInputStream:(PBCodedInputStream*) input extensionRegistry:(PBExtensionRegistry*) extensionRegistry { + PBUnknownFieldSetBuilder* unknownFields = [PBUnknownFieldSet builderWithUnknownFields:self.unknownFields]; + while (YES) { + SInt32 tag = [input readTag]; + switch (tag) { + case 0: + [self setUnknownFields:[unknownFields build]]; + return self; + default: { + if (![self parseUnknownField:input unknownFields:unknownFields extensionRegistry:extensionRegistry tag:tag]) { + [self setUnknownFields:[unknownFields build]]; + return self; + } + break; + } + case 264: { + [self setDeprecated:[input readBool]]; + break; + } + case 7994: { + PBUninterpretedOptionBuilder* subBuilder = [PBUninterpretedOption builder]; + [input readMessage:subBuilder extensionRegistry:extensionRegistry]; + [self addUninterpretedOption:[subBuilder buildPartial]]; + break; + } + } + } +} +- (BOOL) hasDeprecated { + return result.hasDeprecated; +} +- (BOOL) deprecated { + return result.deprecated; +} +- (PBServiceOptionsBuilder*) setDeprecated:(BOOL) value { + result.hasDeprecated = YES; + result.deprecated = value; + return self; +} +- (PBServiceOptionsBuilder*) clearDeprecated { + result.hasDeprecated = NO; + result.deprecated = NO; + return self; +} +- (NSMutableArray *)uninterpretedOption { + return result.uninterpretedOptionArray; +} +- (PBUninterpretedOption*)uninterpretedOptionAtIndex:(NSUInteger)index { + return [result uninterpretedOptionAtIndex:index]; +} +- (PBServiceOptionsBuilder *)addUninterpretedOption:(PBUninterpretedOption*)value { + if (result.uninterpretedOptionArray == nil) { + result.uninterpretedOptionArray = [[NSMutableArray alloc]init]; + } + [result.uninterpretedOptionArray addObject:value]; + return self; +} +- (PBServiceOptionsBuilder *)setUninterpretedOptionArray:(NSArray *)array { + result.uninterpretedOptionArray = [[NSMutableArray alloc]initWithArray:array]; + return self; +} +- (PBServiceOptionsBuilder *)clearUninterpretedOption { + result.uninterpretedOptionArray = nil; + return self; +} +@end + +@interface PBMethodOptions () +@property BOOL deprecated; +@property (strong) NSMutableArray * uninterpretedOptionArray; +@end + +@implementation PBMethodOptions + +- (BOOL) hasDeprecated { + return !!hasDeprecated_; +} +- (void) setHasDeprecated:(BOOL) value_ { + hasDeprecated_ = !!value_; +} +- (BOOL) deprecated { + return !!deprecated_; +} +- (void) setDeprecated:(BOOL) value_ { + deprecated_ = !!value_; +} +@synthesize uninterpretedOptionArray; +@dynamic uninterpretedOption; +- (id) init { + if ((self = [super init])) { + self.deprecated = NO; + } + return self; +} +static PBMethodOptions* defaultPBMethodOptionsInstance = nil; ++ (void) initialize { + if (self == [PBMethodOptions class]) { + defaultPBMethodOptionsInstance = [[PBMethodOptions alloc] init]; + } +} ++ (PBMethodOptions*) defaultInstance { + return defaultPBMethodOptionsInstance; +} +- (PBMethodOptions*) defaultInstance { + return defaultPBMethodOptionsInstance; +} +- (NSArray *)uninterpretedOption { + return uninterpretedOptionArray; +} +- (PBUninterpretedOption*)uninterpretedOptionAtIndex:(NSUInteger)index { + return [uninterpretedOptionArray objectAtIndex:index]; +} +- (BOOL) isInitialized { + __block BOOL isInituninterpretedOption = YES; + [self.uninterpretedOption enumerateObjectsUsingBlock:^(PBUninterpretedOption *element, NSUInteger idx, BOOL *stop) { + if (!element.isInitialized) { + isInituninterpretedOption = NO; + *stop = YES; + } + }]; + if (!isInituninterpretedOption) return isInituninterpretedOption; + if (!self.extensionsAreInitialized) { + return NO; + } + return YES; +} +- (void) writeToCodedOutputStream:(PBCodedOutputStream*) output { + if (self.hasDeprecated) { + [output writeBool:33 value:self.deprecated]; + } + [self.uninterpretedOptionArray enumerateObjectsUsingBlock:^(PBUninterpretedOption *element, NSUInteger idx, BOOL *stop) { + [output writeMessage:999 value:element]; + }]; + [self writeExtensionsToCodedOutputStream:output + from:1000 + to:536870912]; + [self.unknownFields writeToCodedOutputStream:output]; +} +- (SInt32) serializedSize { + __block SInt32 size_ = memoizedSerializedSize; + if (size_ != -1) { + return size_; + } + + size_ = 0; + if (self.hasDeprecated) { + size_ += computeBoolSize(33, self.deprecated); + } + [self.uninterpretedOptionArray enumerateObjectsUsingBlock:^(PBUninterpretedOption *element, NSUInteger idx, BOOL *stop) { + size_ += computeMessageSize(999, element); + }]; + size_ += [self extensionsSerializedSize]; + size_ += self.unknownFields.serializedSize; + memoizedSerializedSize = size_; + return size_; +} ++ (PBMethodOptions*) parseFromData:(NSData*) data { + return (PBMethodOptions*)[[[PBMethodOptions builder] mergeFromData:data] build]; +} ++ (PBMethodOptions*) parseFromData:(NSData*) data extensionRegistry:(PBExtensionRegistry*) extensionRegistry { + return (PBMethodOptions*)[[[PBMethodOptions builder] mergeFromData:data extensionRegistry:extensionRegistry] build]; +} ++ (PBMethodOptions*) parseFromInputStream:(NSInputStream*) input { + return (PBMethodOptions*)[[[PBMethodOptions builder] mergeFromInputStream:input] build]; +} ++ (PBMethodOptions*) parseFromInputStream:(NSInputStream*) input extensionRegistry:(PBExtensionRegistry*) extensionRegistry { + return (PBMethodOptions*)[[[PBMethodOptions builder] mergeFromInputStream:input extensionRegistry:extensionRegistry] build]; +} ++ (PBMethodOptions*) parseFromCodedInputStream:(PBCodedInputStream*) input { + return (PBMethodOptions*)[[[PBMethodOptions builder] mergeFromCodedInputStream:input] build]; +} ++ (PBMethodOptions*) parseFromCodedInputStream:(PBCodedInputStream*) input extensionRegistry:(PBExtensionRegistry*) extensionRegistry { + return (PBMethodOptions*)[[[PBMethodOptions builder] mergeFromCodedInputStream:input extensionRegistry:extensionRegistry] build]; +} ++ (PBMethodOptionsBuilder*) builder { + return [[PBMethodOptionsBuilder alloc] init]; +} ++ (PBMethodOptionsBuilder*) builderWithPrototype:(PBMethodOptions*) prototype { + return [[PBMethodOptions builder] mergeFrom:prototype]; +} +- (PBMethodOptionsBuilder*) builder { + return [PBMethodOptions builder]; +} +- (PBMethodOptionsBuilder*) toBuilder { + return [PBMethodOptions builderWithPrototype:self]; +} +- (void) writeDescriptionTo:(NSMutableString*) output withIndent:(NSString*) indent { + if (self.hasDeprecated) { + [output appendFormat:@"%@%@: %@\n", indent, @"deprecated", [NSNumber numberWithBool:self.deprecated]]; + } + [self.uninterpretedOptionArray enumerateObjectsUsingBlock:^(PBUninterpretedOption *element, NSUInteger idx, BOOL *stop) { + [output appendFormat:@"%@%@ {\n", indent, @"uninterpretedOption"]; + [element writeDescriptionTo:output + withIndent:[NSString stringWithFormat:@"%@ ", indent]]; + [output appendFormat:@"%@}\n", indent]; + }]; + [self writeExtensionDescriptionToMutableString:(NSMutableString*)output + from:1000 + to:536870912 + withIndent:indent]; + [self.unknownFields writeDescriptionTo:output withIndent:indent]; +} +- (BOOL) isEqual:(id)other { + if (other == self) { + return YES; + } + if (![other isKindOfClass:[PBMethodOptions class]]) { + return NO; + } + PBMethodOptions *otherMessage = other; + return + self.hasDeprecated == otherMessage.hasDeprecated && + (!self.hasDeprecated || self.deprecated == otherMessage.deprecated) && + [self.uninterpretedOptionArray isEqualToArray:otherMessage.uninterpretedOptionArray] && + [self isEqualExtensionsInOther:otherMessage from:1000 to:536870912] && + + (self.unknownFields == otherMessage.unknownFields || (self.unknownFields != nil && [self.unknownFields isEqual:otherMessage.unknownFields])); +} +- (NSUInteger) hash { + __block NSUInteger hashCode = 7; + if (self.hasDeprecated) { + hashCode = hashCode * 31 + [[NSNumber numberWithBool:self.deprecated] hash]; + } + [self.uninterpretedOptionArray enumerateObjectsUsingBlock:^(PBUninterpretedOption *element, NSUInteger idx, BOOL *stop) { + hashCode = hashCode * 31 + [element hash]; + }]; + hashCode = hashCode * 31 + [self hashExtensionsFrom:1000 to:536870912]; + hashCode = hashCode * 31 + [self.unknownFields hash]; + return hashCode; +} +@end + +@interface PBMethodOptionsBuilder() +@property (strong) PBMethodOptions* result; +@end + +@implementation PBMethodOptionsBuilder +@synthesize result; +- (id) init { + if ((self = [super init])) { + self.result = [[PBMethodOptions alloc] init]; + } + return self; +} +- (PBExtendableMessage*) internalGetResult { + return result; +} +- (PBMethodOptionsBuilder*) clear { + self.result = [[PBMethodOptions alloc] init]; + return self; +} +- (PBMethodOptionsBuilder*) clone { + return [PBMethodOptions builderWithPrototype:result]; +} +- (PBMethodOptions*) defaultInstance { + return [PBMethodOptions defaultInstance]; +} +- (PBMethodOptions*) build { + [self checkInitialized]; + return [self buildPartial]; +} +- (PBMethodOptions*) buildPartial { + PBMethodOptions* returnMe = result; + self.result = nil; + return returnMe; +} +- (PBMethodOptionsBuilder*) mergeFrom:(PBMethodOptions*) other { + if (other == [PBMethodOptions defaultInstance]) { + return self; + } + if (other.hasDeprecated) { + [self setDeprecated:other.deprecated]; + } + if (other.uninterpretedOptionArray.count > 0) { + if (result.uninterpretedOptionArray == nil) { + result.uninterpretedOptionArray = [[NSMutableArray alloc] initWithArray:other.uninterpretedOptionArray]; + } else { + [result.uninterpretedOptionArray addObjectsFromArray:other.uninterpretedOptionArray]; + } + } + [self mergeExtensionFields:other]; + [self mergeUnknownFields:other.unknownFields]; + return self; +} +- (PBMethodOptionsBuilder*) mergeFromCodedInputStream:(PBCodedInputStream*) input { + return [self mergeFromCodedInputStream:input extensionRegistry:[PBExtensionRegistry emptyRegistry]]; +} +- (PBMethodOptionsBuilder*) mergeFromCodedInputStream:(PBCodedInputStream*) input extensionRegistry:(PBExtensionRegistry*) extensionRegistry { + PBUnknownFieldSetBuilder* unknownFields = [PBUnknownFieldSet builderWithUnknownFields:self.unknownFields]; + while (YES) { + SInt32 tag = [input readTag]; + switch (tag) { + case 0: + [self setUnknownFields:[unknownFields build]]; + return self; + default: { + if (![self parseUnknownField:input unknownFields:unknownFields extensionRegistry:extensionRegistry tag:tag]) { + [self setUnknownFields:[unknownFields build]]; + return self; + } + break; + } + case 264: { + [self setDeprecated:[input readBool]]; + break; + } + case 7994: { + PBUninterpretedOptionBuilder* subBuilder = [PBUninterpretedOption builder]; + [input readMessage:subBuilder extensionRegistry:extensionRegistry]; + [self addUninterpretedOption:[subBuilder buildPartial]]; + break; + } + } + } +} +- (BOOL) hasDeprecated { + return result.hasDeprecated; +} +- (BOOL) deprecated { + return result.deprecated; +} +- (PBMethodOptionsBuilder*) setDeprecated:(BOOL) value { + result.hasDeprecated = YES; + result.deprecated = value; + return self; +} +- (PBMethodOptionsBuilder*) clearDeprecated { + result.hasDeprecated = NO; + result.deprecated = NO; + return self; +} +- (NSMutableArray *)uninterpretedOption { + return result.uninterpretedOptionArray; +} +- (PBUninterpretedOption*)uninterpretedOptionAtIndex:(NSUInteger)index { + return [result uninterpretedOptionAtIndex:index]; +} +- (PBMethodOptionsBuilder *)addUninterpretedOption:(PBUninterpretedOption*)value { + if (result.uninterpretedOptionArray == nil) { + result.uninterpretedOptionArray = [[NSMutableArray alloc]init]; + } + [result.uninterpretedOptionArray addObject:value]; + return self; +} +- (PBMethodOptionsBuilder *)setUninterpretedOptionArray:(NSArray *)array { + result.uninterpretedOptionArray = [[NSMutableArray alloc]initWithArray:array]; + return self; +} +- (PBMethodOptionsBuilder *)clearUninterpretedOption { + result.uninterpretedOptionArray = nil; + return self; +} +@end + +@interface PBUninterpretedOption () +@property (strong) NSMutableArray * nameArray; +@property (strong) NSString* identifierValue; +@property UInt64 positiveIntValue; +@property SInt64 negativeIntValue; +@property Float64 doubleValue; +@property (strong) NSData* stringValue; +@property (strong) NSString* aggregateValue; +@end + +@implementation PBUninterpretedOption + +@synthesize nameArray; +@dynamic name; +- (BOOL) hasIdentifierValue { + return !!hasIdentifierValue_; +} +- (void) setHasIdentifierValue:(BOOL) value_ { + hasIdentifierValue_ = !!value_; +} +@synthesize identifierValue; +- (BOOL) hasPositiveIntValue { + return !!hasPositiveIntValue_; +} +- (void) setHasPositiveIntValue:(BOOL) value_ { + hasPositiveIntValue_ = !!value_; +} +@synthesize positiveIntValue; +- (BOOL) hasNegativeIntValue { + return !!hasNegativeIntValue_; +} +- (void) setHasNegativeIntValue:(BOOL) value_ { + hasNegativeIntValue_ = !!value_; +} +@synthesize negativeIntValue; +- (BOOL) hasDoubleValue { + return !!hasDoubleValue_; +} +- (void) setHasDoubleValue:(BOOL) value_ { + hasDoubleValue_ = !!value_; +} +@synthesize doubleValue; +- (BOOL) hasStringValue { + return !!hasStringValue_; +} +- (void) setHasStringValue:(BOOL) value_ { + hasStringValue_ = !!value_; +} +@synthesize stringValue; +- (BOOL) hasAggregateValue { + return !!hasAggregateValue_; +} +- (void) setHasAggregateValue:(BOOL) value_ { + hasAggregateValue_ = !!value_; +} +@synthesize aggregateValue; +- (id) init { + if ((self = [super init])) { + self.identifierValue = @""; + self.positiveIntValue = 0L; + self.negativeIntValue = 0L; + self.doubleValue = 0; + self.stringValue = [NSData data]; + self.aggregateValue = @""; + } + return self; +} +static PBUninterpretedOption* defaultPBUninterpretedOptionInstance = nil; ++ (void) initialize { + if (self == [PBUninterpretedOption class]) { + defaultPBUninterpretedOptionInstance = [[PBUninterpretedOption alloc] init]; + } +} ++ (PBUninterpretedOption*) defaultInstance { + return defaultPBUninterpretedOptionInstance; +} +- (PBUninterpretedOption*) defaultInstance { + return defaultPBUninterpretedOptionInstance; +} +- (NSArray *)name { + return nameArray; +} +- (PBUninterpretedOptionNamePart*)nameAtIndex:(NSUInteger)index { + return [nameArray objectAtIndex:index]; +} +- (BOOL) isInitialized { + __block BOOL isInitname = YES; + [self.name enumerateObjectsUsingBlock:^(PBUninterpretedOptionNamePart *element, NSUInteger idx, BOOL *stop) { + if (!element.isInitialized) { + isInitname = NO; + *stop = YES; + } + }]; + if (!isInitname) return isInitname; + return YES; +} +- (void) writeToCodedOutputStream:(PBCodedOutputStream*) output { + [self.nameArray enumerateObjectsUsingBlock:^(PBUninterpretedOptionNamePart *element, NSUInteger idx, BOOL *stop) { + [output writeMessage:2 value:element]; + }]; + if (self.hasIdentifierValue) { + [output writeString:3 value:self.identifierValue]; + } + if (self.hasPositiveIntValue) { + [output writeUInt64:4 value:self.positiveIntValue]; + } + if (self.hasNegativeIntValue) { + [output writeInt64:5 value:self.negativeIntValue]; + } + if (self.hasDoubleValue) { + [output writeDouble:6 value:self.doubleValue]; + } + if (self.hasStringValue) { + [output writeData:7 value:self.stringValue]; + } + if (self.hasAggregateValue) { + [output writeString:8 value:self.aggregateValue]; + } + [self.unknownFields writeToCodedOutputStream:output]; +} +- (SInt32) serializedSize { + __block SInt32 size_ = memoizedSerializedSize; + if (size_ != -1) { + return size_; + } + + size_ = 0; + [self.nameArray enumerateObjectsUsingBlock:^(PBUninterpretedOptionNamePart *element, NSUInteger idx, BOOL *stop) { + size_ += computeMessageSize(2, element); + }]; + if (self.hasIdentifierValue) { + size_ += computeStringSize(3, self.identifierValue); + } + if (self.hasPositiveIntValue) { + size_ += computeUInt64Size(4, self.positiveIntValue); + } + if (self.hasNegativeIntValue) { + size_ += computeInt64Size(5, self.negativeIntValue); + } + if (self.hasDoubleValue) { + size_ += computeDoubleSize(6, self.doubleValue); + } + if (self.hasStringValue) { + size_ += computeDataSize(7, self.stringValue); + } + if (self.hasAggregateValue) { + size_ += computeStringSize(8, self.aggregateValue); + } + size_ += self.unknownFields.serializedSize; + memoizedSerializedSize = size_; + return size_; +} ++ (PBUninterpretedOption*) parseFromData:(NSData*) data { + return (PBUninterpretedOption*)[[[PBUninterpretedOption builder] mergeFromData:data] build]; +} ++ (PBUninterpretedOption*) parseFromData:(NSData*) data extensionRegistry:(PBExtensionRegistry*) extensionRegistry { + return (PBUninterpretedOption*)[[[PBUninterpretedOption builder] mergeFromData:data extensionRegistry:extensionRegistry] build]; +} ++ (PBUninterpretedOption*) parseFromInputStream:(NSInputStream*) input { + return (PBUninterpretedOption*)[[[PBUninterpretedOption builder] mergeFromInputStream:input] build]; +} ++ (PBUninterpretedOption*) parseFromInputStream:(NSInputStream*) input extensionRegistry:(PBExtensionRegistry*) extensionRegistry { + return (PBUninterpretedOption*)[[[PBUninterpretedOption builder] mergeFromInputStream:input extensionRegistry:extensionRegistry] build]; +} ++ (PBUninterpretedOption*) parseFromCodedInputStream:(PBCodedInputStream*) input { + return (PBUninterpretedOption*)[[[PBUninterpretedOption builder] mergeFromCodedInputStream:input] build]; +} ++ (PBUninterpretedOption*) parseFromCodedInputStream:(PBCodedInputStream*) input extensionRegistry:(PBExtensionRegistry*) extensionRegistry { + return (PBUninterpretedOption*)[[[PBUninterpretedOption builder] mergeFromCodedInputStream:input extensionRegistry:extensionRegistry] build]; +} ++ (PBUninterpretedOptionBuilder*) builder { + return [[PBUninterpretedOptionBuilder alloc] init]; +} ++ (PBUninterpretedOptionBuilder*) builderWithPrototype:(PBUninterpretedOption*) prototype { + return [[PBUninterpretedOption builder] mergeFrom:prototype]; +} +- (PBUninterpretedOptionBuilder*) builder { + return [PBUninterpretedOption builder]; +} +- (PBUninterpretedOptionBuilder*) toBuilder { + return [PBUninterpretedOption builderWithPrototype:self]; +} +- (void) writeDescriptionTo:(NSMutableString*) output withIndent:(NSString*) indent { + [self.nameArray enumerateObjectsUsingBlock:^(PBUninterpretedOptionNamePart *element, NSUInteger idx, BOOL *stop) { + [output appendFormat:@"%@%@ {\n", indent, @"name"]; + [element writeDescriptionTo:output + withIndent:[NSString stringWithFormat:@"%@ ", indent]]; + [output appendFormat:@"%@}\n", indent]; + }]; + if (self.hasIdentifierValue) { + [output appendFormat:@"%@%@: %@\n", indent, @"identifierValue", self.identifierValue]; + } + if (self.hasPositiveIntValue) { + [output appendFormat:@"%@%@: %@\n", indent, @"positiveIntValue", [NSNumber numberWithLongLong:self.positiveIntValue]]; + } + if (self.hasNegativeIntValue) { + [output appendFormat:@"%@%@: %@\n", indent, @"negativeIntValue", [NSNumber numberWithLongLong:self.negativeIntValue]]; + } + if (self.hasDoubleValue) { + [output appendFormat:@"%@%@: %@\n", indent, @"doubleValue", [NSNumber numberWithDouble:self.doubleValue]]; + } + if (self.hasStringValue) { + [output appendFormat:@"%@%@: %@\n", indent, @"stringValue", self.stringValue]; + } + if (self.hasAggregateValue) { + [output appendFormat:@"%@%@: %@\n", indent, @"aggregateValue", self.aggregateValue]; + } + [self.unknownFields writeDescriptionTo:output withIndent:indent]; +} +- (BOOL) isEqual:(id)other { + if (other == self) { + return YES; + } + if (![other isKindOfClass:[PBUninterpretedOption class]]) { + return NO; + } + PBUninterpretedOption *otherMessage = other; + return + [self.nameArray isEqualToArray:otherMessage.nameArray] && + self.hasIdentifierValue == otherMessage.hasIdentifierValue && + (!self.hasIdentifierValue || [self.identifierValue isEqual:otherMessage.identifierValue]) && + self.hasPositiveIntValue == otherMessage.hasPositiveIntValue && + (!self.hasPositiveIntValue || self.positiveIntValue == otherMessage.positiveIntValue) && + self.hasNegativeIntValue == otherMessage.hasNegativeIntValue && + (!self.hasNegativeIntValue || self.negativeIntValue == otherMessage.negativeIntValue) && + self.hasDoubleValue == otherMessage.hasDoubleValue && + (!self.hasDoubleValue || self.doubleValue == otherMessage.doubleValue) && + self.hasStringValue == otherMessage.hasStringValue && + (!self.hasStringValue || [self.stringValue isEqual:otherMessage.stringValue]) && + self.hasAggregateValue == otherMessage.hasAggregateValue && + (!self.hasAggregateValue || [self.aggregateValue isEqual:otherMessage.aggregateValue]) && + (self.unknownFields == otherMessage.unknownFields || (self.unknownFields != nil && [self.unknownFields isEqual:otherMessage.unknownFields])); +} +- (NSUInteger) hash { + __block NSUInteger hashCode = 7; + [self.nameArray enumerateObjectsUsingBlock:^(PBUninterpretedOptionNamePart *element, NSUInteger idx, BOOL *stop) { + hashCode = hashCode * 31 + [element hash]; + }]; + if (self.hasIdentifierValue) { + hashCode = hashCode * 31 + [self.identifierValue hash]; + } + if (self.hasPositiveIntValue) { + hashCode = hashCode * 31 + [[NSNumber numberWithLongLong:self.positiveIntValue] hash]; + } + if (self.hasNegativeIntValue) { + hashCode = hashCode * 31 + [[NSNumber numberWithLongLong:self.negativeIntValue] hash]; + } + if (self.hasDoubleValue) { + hashCode = hashCode * 31 + [[NSNumber numberWithDouble:self.doubleValue] hash]; + } + if (self.hasStringValue) { + hashCode = hashCode * 31 + [self.stringValue hash]; + } + if (self.hasAggregateValue) { + hashCode = hashCode * 31 + [self.aggregateValue hash]; + } + hashCode = hashCode * 31 + [self.unknownFields hash]; + return hashCode; +} +@end + +@interface PBUninterpretedOptionNamePart () +@property (strong) NSString* namePart; +@property BOOL isExtension; +@end + +@implementation PBUninterpretedOptionNamePart + +- (BOOL) hasNamePart { + return !!hasNamePart_; +} +- (void) setHasNamePart:(BOOL) value_ { + hasNamePart_ = !!value_; +} +@synthesize namePart; +- (BOOL) hasIsExtension { + return !!hasIsExtension_; +} +- (void) setHasIsExtension:(BOOL) value_ { + hasIsExtension_ = !!value_; +} +- (BOOL) isExtension { + return !!isExtension_; +} +- (void) setIsExtension:(BOOL) value_ { + isExtension_ = !!value_; +} +- (id) init { + if ((self = [super init])) { + self.namePart = @""; + self.isExtension = NO; + } + return self; +} +static PBUninterpretedOptionNamePart* defaultPBUninterpretedOptionNamePartInstance = nil; ++ (void) initialize { + if (self == [PBUninterpretedOptionNamePart class]) { + defaultPBUninterpretedOptionNamePartInstance = [[PBUninterpretedOptionNamePart alloc] init]; + } +} ++ (PBUninterpretedOptionNamePart*) defaultInstance { + return defaultPBUninterpretedOptionNamePartInstance; +} +- (PBUninterpretedOptionNamePart*) defaultInstance { + return defaultPBUninterpretedOptionNamePartInstance; +} +- (BOOL) isInitialized { + if (!self.hasNamePart) { + return NO; + } + if (!self.hasIsExtension) { + return NO; + } + return YES; +} +- (void) writeToCodedOutputStream:(PBCodedOutputStream*) output { + if (self.hasNamePart) { + [output writeString:1 value:self.namePart]; + } + if (self.hasIsExtension) { + [output writeBool:2 value:self.isExtension]; + } + [self.unknownFields writeToCodedOutputStream:output]; +} +- (SInt32) serializedSize { + __block SInt32 size_ = memoizedSerializedSize; + if (size_ != -1) { + return size_; + } + + size_ = 0; + if (self.hasNamePart) { + size_ += computeStringSize(1, self.namePart); + } + if (self.hasIsExtension) { + size_ += computeBoolSize(2, self.isExtension); + } + size_ += self.unknownFields.serializedSize; + memoizedSerializedSize = size_; + return size_; +} ++ (PBUninterpretedOptionNamePart*) parseFromData:(NSData*) data { + return (PBUninterpretedOptionNamePart*)[[[PBUninterpretedOptionNamePart builder] mergeFromData:data] build]; +} ++ (PBUninterpretedOptionNamePart*) parseFromData:(NSData*) data extensionRegistry:(PBExtensionRegistry*) extensionRegistry { + return (PBUninterpretedOptionNamePart*)[[[PBUninterpretedOptionNamePart builder] mergeFromData:data extensionRegistry:extensionRegistry] build]; +} ++ (PBUninterpretedOptionNamePart*) parseFromInputStream:(NSInputStream*) input { + return (PBUninterpretedOptionNamePart*)[[[PBUninterpretedOptionNamePart builder] mergeFromInputStream:input] build]; +} ++ (PBUninterpretedOptionNamePart*) parseFromInputStream:(NSInputStream*) input extensionRegistry:(PBExtensionRegistry*) extensionRegistry { + return (PBUninterpretedOptionNamePart*)[[[PBUninterpretedOptionNamePart builder] mergeFromInputStream:input extensionRegistry:extensionRegistry] build]; +} ++ (PBUninterpretedOptionNamePart*) parseFromCodedInputStream:(PBCodedInputStream*) input { + return (PBUninterpretedOptionNamePart*)[[[PBUninterpretedOptionNamePart builder] mergeFromCodedInputStream:input] build]; +} ++ (PBUninterpretedOptionNamePart*) parseFromCodedInputStream:(PBCodedInputStream*) input extensionRegistry:(PBExtensionRegistry*) extensionRegistry { + return (PBUninterpretedOptionNamePart*)[[[PBUninterpretedOptionNamePart builder] mergeFromCodedInputStream:input extensionRegistry:extensionRegistry] build]; +} ++ (PBUninterpretedOptionNamePartBuilder*) builder { + return [[PBUninterpretedOptionNamePartBuilder alloc] init]; +} ++ (PBUninterpretedOptionNamePartBuilder*) builderWithPrototype:(PBUninterpretedOptionNamePart*) prototype { + return [[PBUninterpretedOptionNamePart builder] mergeFrom:prototype]; +} +- (PBUninterpretedOptionNamePartBuilder*) builder { + return [PBUninterpretedOptionNamePart builder]; +} +- (PBUninterpretedOptionNamePartBuilder*) toBuilder { + return [PBUninterpretedOptionNamePart builderWithPrototype:self]; +} +- (void) writeDescriptionTo:(NSMutableString*) output withIndent:(NSString*) indent { + if (self.hasNamePart) { + [output appendFormat:@"%@%@: %@\n", indent, @"namePart", self.namePart]; + } + if (self.hasIsExtension) { + [output appendFormat:@"%@%@: %@\n", indent, @"isExtension", [NSNumber numberWithBool:self.isExtension]]; + } + [self.unknownFields writeDescriptionTo:output withIndent:indent]; +} +- (BOOL) isEqual:(id)other { + if (other == self) { + return YES; + } + if (![other isKindOfClass:[PBUninterpretedOptionNamePart class]]) { + return NO; + } + PBUninterpretedOptionNamePart *otherMessage = other; + return + self.hasNamePart == otherMessage.hasNamePart && + (!self.hasNamePart || [self.namePart isEqual:otherMessage.namePart]) && + self.hasIsExtension == otherMessage.hasIsExtension && + (!self.hasIsExtension || self.isExtension == otherMessage.isExtension) && + (self.unknownFields == otherMessage.unknownFields || (self.unknownFields != nil && [self.unknownFields isEqual:otherMessage.unknownFields])); +} +- (NSUInteger) hash { + __block NSUInteger hashCode = 7; + if (self.hasNamePart) { + hashCode = hashCode * 31 + [self.namePart hash]; + } + if (self.hasIsExtension) { + hashCode = hashCode * 31 + [[NSNumber numberWithBool:self.isExtension] hash]; + } + hashCode = hashCode * 31 + [self.unknownFields hash]; + return hashCode; +} +@end + +@interface PBUninterpretedOptionNamePartBuilder() +@property (strong) PBUninterpretedOptionNamePart* result; +@end + +@implementation PBUninterpretedOptionNamePartBuilder +@synthesize result; +- (id) init { + if ((self = [super init])) { + self.result = [[PBUninterpretedOptionNamePart alloc] init]; + } + return self; +} +- (PBGeneratedMessage*) internalGetResult { + return result; +} +- (PBUninterpretedOptionNamePartBuilder*) clear { + self.result = [[PBUninterpretedOptionNamePart alloc] init]; + return self; +} +- (PBUninterpretedOptionNamePartBuilder*) clone { + return [PBUninterpretedOptionNamePart builderWithPrototype:result]; +} +- (PBUninterpretedOptionNamePart*) defaultInstance { + return [PBUninterpretedOptionNamePart defaultInstance]; +} +- (PBUninterpretedOptionNamePart*) build { + [self checkInitialized]; + return [self buildPartial]; +} +- (PBUninterpretedOptionNamePart*) buildPartial { + PBUninterpretedOptionNamePart* returnMe = result; + self.result = nil; + return returnMe; +} +- (PBUninterpretedOptionNamePartBuilder*) mergeFrom:(PBUninterpretedOptionNamePart*) other { + if (other == [PBUninterpretedOptionNamePart defaultInstance]) { + return self; + } + if (other.hasNamePart) { + [self setNamePart:other.namePart]; + } + if (other.hasIsExtension) { + [self setIsExtension:other.isExtension]; + } + [self mergeUnknownFields:other.unknownFields]; + return self; +} +- (PBUninterpretedOptionNamePartBuilder*) mergeFromCodedInputStream:(PBCodedInputStream*) input { + return [self mergeFromCodedInputStream:input extensionRegistry:[PBExtensionRegistry emptyRegistry]]; +} +- (PBUninterpretedOptionNamePartBuilder*) mergeFromCodedInputStream:(PBCodedInputStream*) input extensionRegistry:(PBExtensionRegistry*) extensionRegistry { + PBUnknownFieldSetBuilder* unknownFields = [PBUnknownFieldSet builderWithUnknownFields:self.unknownFields]; + while (YES) { + SInt32 tag = [input readTag]; + switch (tag) { + case 0: + [self setUnknownFields:[unknownFields build]]; + return self; + default: { + if (![self parseUnknownField:input unknownFields:unknownFields extensionRegistry:extensionRegistry tag:tag]) { + [self setUnknownFields:[unknownFields build]]; + return self; + } + break; + } + case 10: { + [self setNamePart:[input readString]]; + break; + } + case 16: { + [self setIsExtension:[input readBool]]; + break; + } + } + } +} +- (BOOL) hasNamePart { + return result.hasNamePart; +} +- (NSString*) namePart { + return result.namePart; +} +- (PBUninterpretedOptionNamePartBuilder*) setNamePart:(NSString*) value { + result.hasNamePart = YES; + result.namePart = value; + return self; +} +- (PBUninterpretedOptionNamePartBuilder*) clearNamePart { + result.hasNamePart = NO; + result.namePart = @""; + return self; +} +- (BOOL) hasIsExtension { + return result.hasIsExtension; +} +- (BOOL) isExtension { + return result.isExtension; +} +- (PBUninterpretedOptionNamePartBuilder*) setIsExtension:(BOOL) value { + result.hasIsExtension = YES; + result.isExtension = value; + return self; +} +- (PBUninterpretedOptionNamePartBuilder*) clearIsExtension { + result.hasIsExtension = NO; + result.isExtension = NO; + return self; +} +@end + +@interface PBUninterpretedOptionBuilder() +@property (strong) PBUninterpretedOption* result; +@end + +@implementation PBUninterpretedOptionBuilder +@synthesize result; +- (id) init { + if ((self = [super init])) { + self.result = [[PBUninterpretedOption alloc] init]; + } + return self; +} +- (PBGeneratedMessage*) internalGetResult { + return result; +} +- (PBUninterpretedOptionBuilder*) clear { + self.result = [[PBUninterpretedOption alloc] init]; + return self; +} +- (PBUninterpretedOptionBuilder*) clone { + return [PBUninterpretedOption builderWithPrototype:result]; +} +- (PBUninterpretedOption*) defaultInstance { + return [PBUninterpretedOption defaultInstance]; +} +- (PBUninterpretedOption*) build { + [self checkInitialized]; + return [self buildPartial]; +} +- (PBUninterpretedOption*) buildPartial { + PBUninterpretedOption* returnMe = result; + self.result = nil; + return returnMe; +} +- (PBUninterpretedOptionBuilder*) mergeFrom:(PBUninterpretedOption*) other { + if (other == [PBUninterpretedOption defaultInstance]) { + return self; + } + if (other.nameArray.count > 0) { + if (result.nameArray == nil) { + result.nameArray = [[NSMutableArray alloc] initWithArray:other.nameArray]; + } else { + [result.nameArray addObjectsFromArray:other.nameArray]; + } + } + if (other.hasIdentifierValue) { + [self setIdentifierValue:other.identifierValue]; + } + if (other.hasPositiveIntValue) { + [self setPositiveIntValue:other.positiveIntValue]; + } + if (other.hasNegativeIntValue) { + [self setNegativeIntValue:other.negativeIntValue]; + } + if (other.hasDoubleValue) { + [self setDoubleValue:other.doubleValue]; + } + if (other.hasStringValue) { + [self setStringValue:other.stringValue]; + } + if (other.hasAggregateValue) { + [self setAggregateValue:other.aggregateValue]; + } + [self mergeUnknownFields:other.unknownFields]; + return self; +} +- (PBUninterpretedOptionBuilder*) mergeFromCodedInputStream:(PBCodedInputStream*) input { + return [self mergeFromCodedInputStream:input extensionRegistry:[PBExtensionRegistry emptyRegistry]]; +} +- (PBUninterpretedOptionBuilder*) mergeFromCodedInputStream:(PBCodedInputStream*) input extensionRegistry:(PBExtensionRegistry*) extensionRegistry { + PBUnknownFieldSetBuilder* unknownFields = [PBUnknownFieldSet builderWithUnknownFields:self.unknownFields]; + while (YES) { + SInt32 tag = [input readTag]; + switch (tag) { + case 0: + [self setUnknownFields:[unknownFields build]]; + return self; + default: { + if (![self parseUnknownField:input unknownFields:unknownFields extensionRegistry:extensionRegistry tag:tag]) { + [self setUnknownFields:[unknownFields build]]; + return self; + } + break; + } + case 18: { + PBUninterpretedOptionNamePartBuilder* subBuilder = [PBUninterpretedOptionNamePart builder]; + [input readMessage:subBuilder extensionRegistry:extensionRegistry]; + [self addName:[subBuilder buildPartial]]; + break; + } + case 26: { + [self setIdentifierValue:[input readString]]; + break; + } + case 32: { + [self setPositiveIntValue:[input readUInt64]]; + break; + } + case 40: { + [self setNegativeIntValue:[input readInt64]]; + break; + } + case 49: { + [self setDoubleValue:[input readDouble]]; + break; + } + case 58: { + [self setStringValue:[input readData]]; + break; + } + case 66: { + [self setAggregateValue:[input readString]]; + break; + } + } + } +} +- (NSMutableArray *)name { + return result.nameArray; +} +- (PBUninterpretedOptionNamePart*)nameAtIndex:(NSUInteger)index { + return [result nameAtIndex:index]; +} +- (PBUninterpretedOptionBuilder *)addName:(PBUninterpretedOptionNamePart*)value { + if (result.nameArray == nil) { + result.nameArray = [[NSMutableArray alloc]init]; + } + [result.nameArray addObject:value]; + return self; +} +- (PBUninterpretedOptionBuilder *)setNameArray:(NSArray *)array { + result.nameArray = [[NSMutableArray alloc]initWithArray:array]; + return self; +} +- (PBUninterpretedOptionBuilder *)clearName { + result.nameArray = nil; + return self; +} +- (BOOL) hasIdentifierValue { + return result.hasIdentifierValue; +} +- (NSString*) identifierValue { + return result.identifierValue; +} +- (PBUninterpretedOptionBuilder*) setIdentifierValue:(NSString*) value { + result.hasIdentifierValue = YES; + result.identifierValue = value; + return self; +} +- (PBUninterpretedOptionBuilder*) clearIdentifierValue { + result.hasIdentifierValue = NO; + result.identifierValue = @""; + return self; +} +- (BOOL) hasPositiveIntValue { + return result.hasPositiveIntValue; +} +- (UInt64) positiveIntValue { + return result.positiveIntValue; +} +- (PBUninterpretedOptionBuilder*) setPositiveIntValue:(UInt64) value { + result.hasPositiveIntValue = YES; + result.positiveIntValue = value; + return self; +} +- (PBUninterpretedOptionBuilder*) clearPositiveIntValue { + result.hasPositiveIntValue = NO; + result.positiveIntValue = 0L; + return self; +} +- (BOOL) hasNegativeIntValue { + return result.hasNegativeIntValue; +} +- (SInt64) negativeIntValue { + return result.negativeIntValue; +} +- (PBUninterpretedOptionBuilder*) setNegativeIntValue:(SInt64) value { + result.hasNegativeIntValue = YES; + result.negativeIntValue = value; + return self; +} +- (PBUninterpretedOptionBuilder*) clearNegativeIntValue { + result.hasNegativeIntValue = NO; + result.negativeIntValue = 0L; + return self; +} +- (BOOL) hasDoubleValue { + return result.hasDoubleValue; +} +- (Float64) doubleValue { + return result.doubleValue; +} +- (PBUninterpretedOptionBuilder*) setDoubleValue:(Float64) value { + result.hasDoubleValue = YES; + result.doubleValue = value; + return self; +} +- (PBUninterpretedOptionBuilder*) clearDoubleValue { + result.hasDoubleValue = NO; + result.doubleValue = 0; + return self; +} +- (BOOL) hasStringValue { + return result.hasStringValue; +} +- (NSData*) stringValue { + return result.stringValue; +} +- (PBUninterpretedOptionBuilder*) setStringValue:(NSData*) value { + result.hasStringValue = YES; + result.stringValue = value; + return self; +} +- (PBUninterpretedOptionBuilder*) clearStringValue { + result.hasStringValue = NO; + result.stringValue = [NSData data]; + return self; +} +- (BOOL) hasAggregateValue { + return result.hasAggregateValue; +} +- (NSString*) aggregateValue { + return result.aggregateValue; +} +- (PBUninterpretedOptionBuilder*) setAggregateValue:(NSString*) value { + result.hasAggregateValue = YES; + result.aggregateValue = value; + return self; +} +- (PBUninterpretedOptionBuilder*) clearAggregateValue { + result.hasAggregateValue = NO; + result.aggregateValue = @""; + return self; +} +@end + +@interface PBSourceCodeInfo () +@property (strong) NSMutableArray * locationArray; +@end + +@implementation PBSourceCodeInfo + +@synthesize locationArray; +@dynamic location; +- (id) init { + if ((self = [super init])) { + } + return self; +} +static PBSourceCodeInfo* defaultPBSourceCodeInfoInstance = nil; ++ (void) initialize { + if (self == [PBSourceCodeInfo class]) { + defaultPBSourceCodeInfoInstance = [[PBSourceCodeInfo alloc] init]; + } +} ++ (PBSourceCodeInfo*) defaultInstance { + return defaultPBSourceCodeInfoInstance; +} +- (PBSourceCodeInfo*) defaultInstance { + return defaultPBSourceCodeInfoInstance; +} +- (NSArray *)location { + return locationArray; +} +- (PBSourceCodeInfoLocation*)locationAtIndex:(NSUInteger)index { + return [locationArray objectAtIndex:index]; +} +- (BOOL) isInitialized { + return YES; +} +- (void) writeToCodedOutputStream:(PBCodedOutputStream*) output { + [self.locationArray enumerateObjectsUsingBlock:^(PBSourceCodeInfoLocation *element, NSUInteger idx, BOOL *stop) { + [output writeMessage:1 value:element]; + }]; + [self.unknownFields writeToCodedOutputStream:output]; +} +- (SInt32) serializedSize { + __block SInt32 size_ = memoizedSerializedSize; + if (size_ != -1) { + return size_; + } + + size_ = 0; + [self.locationArray enumerateObjectsUsingBlock:^(PBSourceCodeInfoLocation *element, NSUInteger idx, BOOL *stop) { + size_ += computeMessageSize(1, element); + }]; + size_ += self.unknownFields.serializedSize; + memoizedSerializedSize = size_; + return size_; +} ++ (PBSourceCodeInfo*) parseFromData:(NSData*) data { + return (PBSourceCodeInfo*)[[[PBSourceCodeInfo builder] mergeFromData:data] build]; +} ++ (PBSourceCodeInfo*) parseFromData:(NSData*) data extensionRegistry:(PBExtensionRegistry*) extensionRegistry { + return (PBSourceCodeInfo*)[[[PBSourceCodeInfo builder] mergeFromData:data extensionRegistry:extensionRegistry] build]; +} ++ (PBSourceCodeInfo*) parseFromInputStream:(NSInputStream*) input { + return (PBSourceCodeInfo*)[[[PBSourceCodeInfo builder] mergeFromInputStream:input] build]; +} ++ (PBSourceCodeInfo*) parseFromInputStream:(NSInputStream*) input extensionRegistry:(PBExtensionRegistry*) extensionRegistry { + return (PBSourceCodeInfo*)[[[PBSourceCodeInfo builder] mergeFromInputStream:input extensionRegistry:extensionRegistry] build]; +} ++ (PBSourceCodeInfo*) parseFromCodedInputStream:(PBCodedInputStream*) input { + return (PBSourceCodeInfo*)[[[PBSourceCodeInfo builder] mergeFromCodedInputStream:input] build]; +} ++ (PBSourceCodeInfo*) parseFromCodedInputStream:(PBCodedInputStream*) input extensionRegistry:(PBExtensionRegistry*) extensionRegistry { + return (PBSourceCodeInfo*)[[[PBSourceCodeInfo builder] mergeFromCodedInputStream:input extensionRegistry:extensionRegistry] build]; +} ++ (PBSourceCodeInfoBuilder*) builder { + return [[PBSourceCodeInfoBuilder alloc] init]; +} ++ (PBSourceCodeInfoBuilder*) builderWithPrototype:(PBSourceCodeInfo*) prototype { + return [[PBSourceCodeInfo builder] mergeFrom:prototype]; +} +- (PBSourceCodeInfoBuilder*) builder { + return [PBSourceCodeInfo builder]; +} +- (PBSourceCodeInfoBuilder*) toBuilder { + return [PBSourceCodeInfo builderWithPrototype:self]; +} +- (void) writeDescriptionTo:(NSMutableString*) output withIndent:(NSString*) indent { + [self.locationArray enumerateObjectsUsingBlock:^(PBSourceCodeInfoLocation *element, NSUInteger idx, BOOL *stop) { + [output appendFormat:@"%@%@ {\n", indent, @"location"]; + [element writeDescriptionTo:output + withIndent:[NSString stringWithFormat:@"%@ ", indent]]; + [output appendFormat:@"%@}\n", indent]; + }]; + [self.unknownFields writeDescriptionTo:output withIndent:indent]; +} +- (BOOL) isEqual:(id)other { + if (other == self) { + return YES; + } + if (![other isKindOfClass:[PBSourceCodeInfo class]]) { + return NO; + } + PBSourceCodeInfo *otherMessage = other; + return + [self.locationArray isEqualToArray:otherMessage.locationArray] && + (self.unknownFields == otherMessage.unknownFields || (self.unknownFields != nil && [self.unknownFields isEqual:otherMessage.unknownFields])); +} +- (NSUInteger) hash { + __block NSUInteger hashCode = 7; + [self.locationArray enumerateObjectsUsingBlock:^(PBSourceCodeInfoLocation *element, NSUInteger idx, BOOL *stop) { + hashCode = hashCode * 31 + [element hash]; + }]; + hashCode = hashCode * 31 + [self.unknownFields hash]; + return hashCode; +} +@end + +@interface PBSourceCodeInfoLocation () +@property (strong) PBAppendableArray * pathArray; +@property (strong) PBAppendableArray * spanArray; +@property (strong) NSString* leadingComments; +@property (strong) NSString* trailingComments; +@end + +@implementation PBSourceCodeInfoLocation + +@synthesize pathArray; +@dynamic path; +@synthesize spanArray; +@dynamic span; +- (BOOL) hasLeadingComments { + return !!hasLeadingComments_; +} +- (void) setHasLeadingComments:(BOOL) value_ { + hasLeadingComments_ = !!value_; +} +@synthesize leadingComments; +- (BOOL) hasTrailingComments { + return !!hasTrailingComments_; +} +- (void) setHasTrailingComments:(BOOL) value_ { + hasTrailingComments_ = !!value_; +} +@synthesize trailingComments; +- (id) init { + if ((self = [super init])) { + self.leadingComments = @""; + self.trailingComments = @""; + } + return self; +} +static PBSourceCodeInfoLocation* defaultPBSourceCodeInfoLocationInstance = nil; ++ (void) initialize { + if (self == [PBSourceCodeInfoLocation class]) { + defaultPBSourceCodeInfoLocationInstance = [[PBSourceCodeInfoLocation alloc] init]; + } +} ++ (PBSourceCodeInfoLocation*) defaultInstance { + return defaultPBSourceCodeInfoLocationInstance; +} +- (PBSourceCodeInfoLocation*) defaultInstance { + return defaultPBSourceCodeInfoLocationInstance; +} +- (PBArray *)path { + return pathArray; +} +- (SInt32)pathAtIndex:(NSUInteger)index { + return [pathArray int32AtIndex:index]; +} +- (PBArray *)span { + return spanArray; +} +- (SInt32)spanAtIndex:(NSUInteger)index { + return [spanArray int32AtIndex:index]; +} +- (BOOL) isInitialized { + return YES; +} +- (void) writeToCodedOutputStream:(PBCodedOutputStream*) output { + const NSUInteger pathArrayCount = self.pathArray.count; + if (pathArrayCount > 0) { + const SInt32 *values = (const SInt32 *)self.pathArray.data; + [output writeRawVarint32:10]; + [output writeRawVarint32:pathMemoizedSerializedSize]; + for (NSUInteger i = 0; i < pathArrayCount; ++i) { + [output writeInt32NoTag:values[i]]; + } + } + const NSUInteger spanArrayCount = self.spanArray.count; + if (spanArrayCount > 0) { + const SInt32 *values = (const SInt32 *)self.spanArray.data; + [output writeRawVarint32:18]; + [output writeRawVarint32:spanMemoizedSerializedSize]; + for (NSUInteger i = 0; i < spanArrayCount; ++i) { + [output writeInt32NoTag:values[i]]; + } + } + if (self.hasLeadingComments) { + [output writeString:3 value:self.leadingComments]; + } + if (self.hasTrailingComments) { + [output writeString:4 value:self.trailingComments]; + } + [self.unknownFields writeToCodedOutputStream:output]; +} +- (SInt32) serializedSize { + __block SInt32 size_ = memoizedSerializedSize; + if (size_ != -1) { + return size_; + } + + size_ = 0; + { + __block SInt32 dataSize = 0; + const NSUInteger count = self.pathArray.count; + const SInt32 *values = (const SInt32 *)self.pathArray.data; + for (NSUInteger i = 0; i < count; ++i) { + dataSize += computeInt32SizeNoTag(values[i]); + } + size_ += dataSize; + if (count > 0) { + size_ += 1; + size_ += computeInt32SizeNoTag(dataSize); + } + pathMemoizedSerializedSize = dataSize; + } + { + __block SInt32 dataSize = 0; + const NSUInteger count = self.spanArray.count; + const SInt32 *values = (const SInt32 *)self.spanArray.data; + for (NSUInteger i = 0; i < count; ++i) { + dataSize += computeInt32SizeNoTag(values[i]); + } + size_ += dataSize; + if (count > 0) { + size_ += 1; + size_ += computeInt32SizeNoTag(dataSize); + } + spanMemoizedSerializedSize = dataSize; + } + if (self.hasLeadingComments) { + size_ += computeStringSize(3, self.leadingComments); + } + if (self.hasTrailingComments) { + size_ += computeStringSize(4, self.trailingComments); + } + size_ += self.unknownFields.serializedSize; + memoizedSerializedSize = size_; + return size_; +} ++ (PBSourceCodeInfoLocation*) parseFromData:(NSData*) data { + return (PBSourceCodeInfoLocation*)[[[PBSourceCodeInfoLocation builder] mergeFromData:data] build]; +} ++ (PBSourceCodeInfoLocation*) parseFromData:(NSData*) data extensionRegistry:(PBExtensionRegistry*) extensionRegistry { + return (PBSourceCodeInfoLocation*)[[[PBSourceCodeInfoLocation builder] mergeFromData:data extensionRegistry:extensionRegistry] build]; +} ++ (PBSourceCodeInfoLocation*) parseFromInputStream:(NSInputStream*) input { + return (PBSourceCodeInfoLocation*)[[[PBSourceCodeInfoLocation builder] mergeFromInputStream:input] build]; +} ++ (PBSourceCodeInfoLocation*) parseFromInputStream:(NSInputStream*) input extensionRegistry:(PBExtensionRegistry*) extensionRegistry { + return (PBSourceCodeInfoLocation*)[[[PBSourceCodeInfoLocation builder] mergeFromInputStream:input extensionRegistry:extensionRegistry] build]; +} ++ (PBSourceCodeInfoLocation*) parseFromCodedInputStream:(PBCodedInputStream*) input { + return (PBSourceCodeInfoLocation*)[[[PBSourceCodeInfoLocation builder] mergeFromCodedInputStream:input] build]; +} ++ (PBSourceCodeInfoLocation*) parseFromCodedInputStream:(PBCodedInputStream*) input extensionRegistry:(PBExtensionRegistry*) extensionRegistry { + return (PBSourceCodeInfoLocation*)[[[PBSourceCodeInfoLocation builder] mergeFromCodedInputStream:input extensionRegistry:extensionRegistry] build]; +} ++ (PBSourceCodeInfoLocationBuilder*) builder { + return [[PBSourceCodeInfoLocationBuilder alloc] init]; +} ++ (PBSourceCodeInfoLocationBuilder*) builderWithPrototype:(PBSourceCodeInfoLocation*) prototype { + return [[PBSourceCodeInfoLocation builder] mergeFrom:prototype]; +} +- (PBSourceCodeInfoLocationBuilder*) builder { + return [PBSourceCodeInfoLocation builder]; +} +- (PBSourceCodeInfoLocationBuilder*) toBuilder { + return [PBSourceCodeInfoLocation builderWithPrototype:self]; +} +- (void) writeDescriptionTo:(NSMutableString*) output withIndent:(NSString*) indent { + [self.pathArray enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) { + [output appendFormat:@"%@%@: %@\n", indent, @"path", obj]; + }]; + [self.spanArray enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) { + [output appendFormat:@"%@%@: %@\n", indent, @"span", obj]; + }]; + if (self.hasLeadingComments) { + [output appendFormat:@"%@%@: %@\n", indent, @"leadingComments", self.leadingComments]; + } + if (self.hasTrailingComments) { + [output appendFormat:@"%@%@: %@\n", indent, @"trailingComments", self.trailingComments]; + } + [self.unknownFields writeDescriptionTo:output withIndent:indent]; +} +- (BOOL) isEqual:(id)other { + if (other == self) { + return YES; + } + if (![other isKindOfClass:[PBSourceCodeInfoLocation class]]) { + return NO; + } + PBSourceCodeInfoLocation *otherMessage = other; + return + [self.pathArray isEqualToArray:otherMessage.pathArray] && + [self.spanArray isEqualToArray:otherMessage.spanArray] && + self.hasLeadingComments == otherMessage.hasLeadingComments && + (!self.hasLeadingComments || [self.leadingComments isEqual:otherMessage.leadingComments]) && + self.hasTrailingComments == otherMessage.hasTrailingComments && + (!self.hasTrailingComments || [self.trailingComments isEqual:otherMessage.trailingComments]) && + (self.unknownFields == otherMessage.unknownFields || (self.unknownFields != nil && [self.unknownFields isEqual:otherMessage.unknownFields])); +} +- (NSUInteger) hash { + __block NSUInteger hashCode = 7; + [self.pathArray enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) { + hashCode = hashCode * 31 + [obj longValue]; + }]; + [self.spanArray enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) { + hashCode = hashCode * 31 + [obj longValue]; + }]; + if (self.hasLeadingComments) { + hashCode = hashCode * 31 + [self.leadingComments hash]; + } + if (self.hasTrailingComments) { + hashCode = hashCode * 31 + [self.trailingComments hash]; + } + hashCode = hashCode * 31 + [self.unknownFields hash]; + return hashCode; +} +@end + +@interface PBSourceCodeInfoLocationBuilder() +@property (strong) PBSourceCodeInfoLocation* result; +@end + +@implementation PBSourceCodeInfoLocationBuilder +@synthesize result; +- (id) init { + if ((self = [super init])) { + self.result = [[PBSourceCodeInfoLocation alloc] init]; + } + return self; +} +- (PBGeneratedMessage*) internalGetResult { + return result; +} +- (PBSourceCodeInfoLocationBuilder*) clear { + self.result = [[PBSourceCodeInfoLocation alloc] init]; + return self; +} +- (PBSourceCodeInfoLocationBuilder*) clone { + return [PBSourceCodeInfoLocation builderWithPrototype:result]; +} +- (PBSourceCodeInfoLocation*) defaultInstance { + return [PBSourceCodeInfoLocation defaultInstance]; +} +- (PBSourceCodeInfoLocation*) build { + [self checkInitialized]; + return [self buildPartial]; +} +- (PBSourceCodeInfoLocation*) buildPartial { + PBSourceCodeInfoLocation* returnMe = result; + self.result = nil; + return returnMe; +} +- (PBSourceCodeInfoLocationBuilder*) mergeFrom:(PBSourceCodeInfoLocation*) other { + if (other == [PBSourceCodeInfoLocation defaultInstance]) { + return self; + } + if (other.pathArray.count > 0) { + if (result.pathArray == nil) { + result.pathArray = [other.pathArray copy]; + } else { + [result.pathArray appendArray:other.pathArray]; + } + } + if (other.spanArray.count > 0) { + if (result.spanArray == nil) { + result.spanArray = [other.spanArray copy]; + } else { + [result.spanArray appendArray:other.spanArray]; + } + } + if (other.hasLeadingComments) { + [self setLeadingComments:other.leadingComments]; + } + if (other.hasTrailingComments) { + [self setTrailingComments:other.trailingComments]; + } + [self mergeUnknownFields:other.unknownFields]; + return self; +} +- (PBSourceCodeInfoLocationBuilder*) mergeFromCodedInputStream:(PBCodedInputStream*) input { + return [self mergeFromCodedInputStream:input extensionRegistry:[PBExtensionRegistry emptyRegistry]]; +} +- (PBSourceCodeInfoLocationBuilder*) mergeFromCodedInputStream:(PBCodedInputStream*) input extensionRegistry:(PBExtensionRegistry*) extensionRegistry { + PBUnknownFieldSetBuilder* unknownFields = [PBUnknownFieldSet builderWithUnknownFields:self.unknownFields]; + while (YES) { + SInt32 tag = [input readTag]; + switch (tag) { + case 0: + [self setUnknownFields:[unknownFields build]]; + return self; + default: { + if (![self parseUnknownField:input unknownFields:unknownFields extensionRegistry:extensionRegistry tag:tag]) { + [self setUnknownFields:[unknownFields build]]; + return self; + } + break; + } + case 10: { + SInt32 length = [input readRawVarint32]; + SInt32 limit = [input pushLimit:length]; + if (result.pathArray == nil) { + result.pathArray = [PBAppendableArray arrayWithValueType:PBArrayValueTypeInt32]; + } + while (input.bytesUntilLimit > 0) { + [result.pathArray addInt32:[input readInt32]]; + } + [input popLimit:limit]; + break; + } + case 18: { + SInt32 length = [input readRawVarint32]; + SInt32 limit = [input pushLimit:length]; + if (result.spanArray == nil) { + result.spanArray = [PBAppendableArray arrayWithValueType:PBArrayValueTypeInt32]; + } + while (input.bytesUntilLimit > 0) { + [result.spanArray addInt32:[input readInt32]]; + } + [input popLimit:limit]; + break; + } + case 26: { + [self setLeadingComments:[input readString]]; + break; + } + case 34: { + [self setTrailingComments:[input readString]]; + break; + } + } + } +} +- (PBAppendableArray *)path { + return result.pathArray; +} +- (SInt32)pathAtIndex:(NSUInteger)index { + return [result pathAtIndex:index]; +} +- (PBSourceCodeInfoLocationBuilder *)addPath:(SInt32)value { + if (result.pathArray == nil) { + result.pathArray = [PBAppendableArray arrayWithValueType:PBArrayValueTypeInt32]; + } + [result.pathArray addInt32:value]; + return self; +} +- (PBSourceCodeInfoLocationBuilder *)setPathArray:(NSArray *)array { + result.pathArray = [PBAppendableArray arrayWithArray:array valueType:PBArrayValueTypeInt32]; + return self; +} +- (PBSourceCodeInfoLocationBuilder *)setPathValues:(const SInt32 *)values count:(NSUInteger)count { + result.pathArray = [PBAppendableArray arrayWithValues:values count:count valueType:PBArrayValueTypeInt32]; + return self; +} +- (PBSourceCodeInfoLocationBuilder *)clearPath { + result.pathArray = nil; + return self; +} +- (PBAppendableArray *)span { + return result.spanArray; +} +- (SInt32)spanAtIndex:(NSUInteger)index { + return [result spanAtIndex:index]; +} +- (PBSourceCodeInfoLocationBuilder *)addSpan:(SInt32)value { + if (result.spanArray == nil) { + result.spanArray = [PBAppendableArray arrayWithValueType:PBArrayValueTypeInt32]; + } + [result.spanArray addInt32:value]; + return self; +} +- (PBSourceCodeInfoLocationBuilder *)setSpanArray:(NSArray *)array { + result.spanArray = [PBAppendableArray arrayWithArray:array valueType:PBArrayValueTypeInt32]; + return self; +} +- (PBSourceCodeInfoLocationBuilder *)setSpanValues:(const SInt32 *)values count:(NSUInteger)count { + result.spanArray = [PBAppendableArray arrayWithValues:values count:count valueType:PBArrayValueTypeInt32]; + return self; +} +- (PBSourceCodeInfoLocationBuilder *)clearSpan { + result.spanArray = nil; + return self; +} +- (BOOL) hasLeadingComments { + return result.hasLeadingComments; +} +- (NSString*) leadingComments { + return result.leadingComments; +} +- (PBSourceCodeInfoLocationBuilder*) setLeadingComments:(NSString*) value { + result.hasLeadingComments = YES; + result.leadingComments = value; + return self; +} +- (PBSourceCodeInfoLocationBuilder*) clearLeadingComments { + result.hasLeadingComments = NO; + result.leadingComments = @""; + return self; +} +- (BOOL) hasTrailingComments { + return result.hasTrailingComments; +} +- (NSString*) trailingComments { + return result.trailingComments; +} +- (PBSourceCodeInfoLocationBuilder*) setTrailingComments:(NSString*) value { + result.hasTrailingComments = YES; + result.trailingComments = value; + return self; +} +- (PBSourceCodeInfoLocationBuilder*) clearTrailingComments { + result.hasTrailingComments = NO; + result.trailingComments = @""; + return self; +} +@end + +@interface PBSourceCodeInfoBuilder() +@property (strong) PBSourceCodeInfo* result; +@end + +@implementation PBSourceCodeInfoBuilder +@synthesize result; +- (id) init { + if ((self = [super init])) { + self.result = [[PBSourceCodeInfo alloc] init]; + } + return self; +} +- (PBGeneratedMessage*) internalGetResult { + return result; +} +- (PBSourceCodeInfoBuilder*) clear { + self.result = [[PBSourceCodeInfo alloc] init]; + return self; +} +- (PBSourceCodeInfoBuilder*) clone { + return [PBSourceCodeInfo builderWithPrototype:result]; +} +- (PBSourceCodeInfo*) defaultInstance { + return [PBSourceCodeInfo defaultInstance]; +} +- (PBSourceCodeInfo*) build { + [self checkInitialized]; + return [self buildPartial]; +} +- (PBSourceCodeInfo*) buildPartial { + PBSourceCodeInfo* returnMe = result; + self.result = nil; + return returnMe; +} +- (PBSourceCodeInfoBuilder*) mergeFrom:(PBSourceCodeInfo*) other { + if (other == [PBSourceCodeInfo defaultInstance]) { + return self; + } + if (other.locationArray.count > 0) { + if (result.locationArray == nil) { + result.locationArray = [[NSMutableArray alloc] initWithArray:other.locationArray]; + } else { + [result.locationArray addObjectsFromArray:other.locationArray]; + } + } + [self mergeUnknownFields:other.unknownFields]; + return self; +} +- (PBSourceCodeInfoBuilder*) mergeFromCodedInputStream:(PBCodedInputStream*) input { + return [self mergeFromCodedInputStream:input extensionRegistry:[PBExtensionRegistry emptyRegistry]]; +} +- (PBSourceCodeInfoBuilder*) mergeFromCodedInputStream:(PBCodedInputStream*) input extensionRegistry:(PBExtensionRegistry*) extensionRegistry { + PBUnknownFieldSetBuilder* unknownFields = [PBUnknownFieldSet builderWithUnknownFields:self.unknownFields]; + while (YES) { + SInt32 tag = [input readTag]; + switch (tag) { + case 0: + [self setUnknownFields:[unknownFields build]]; + return self; + default: { + if (![self parseUnknownField:input unknownFields:unknownFields extensionRegistry:extensionRegistry tag:tag]) { + [self setUnknownFields:[unknownFields build]]; + return self; + } + break; + } + case 10: { + PBSourceCodeInfoLocationBuilder* subBuilder = [PBSourceCodeInfoLocation builder]; + [input readMessage:subBuilder extensionRegistry:extensionRegistry]; + [self addLocation:[subBuilder buildPartial]]; + break; + } + } + } +} +- (NSMutableArray *)location { + return result.locationArray; +} +- (PBSourceCodeInfoLocation*)locationAtIndex:(NSUInteger)index { + return [result locationAtIndex:index]; +} +- (PBSourceCodeInfoBuilder *)addLocation:(PBSourceCodeInfoLocation*)value { + if (result.locationArray == nil) { + result.locationArray = [[NSMutableArray alloc]init]; + } + [result.locationArray addObject:value]; + return self; +} +- (PBSourceCodeInfoBuilder *)setLocationArray:(NSArray *)array { + result.locationArray = [[NSMutableArray alloc]initWithArray:array]; + return self; +} +- (PBSourceCodeInfoBuilder *)clearLocation { + result.locationArray = nil; + return self; +} +@end + + +// @@protoc_insertion_point(global_scope) diff --git a/ios/Pods/ProtocolBuffers/src/runtime/Classes/ExtendableMessage.h b/ios/Pods/ProtocolBuffers/src/runtime/Classes/ExtendableMessage.h new file mode 100644 index 000000000..43c3eb78e --- /dev/null +++ b/ios/Pods/ProtocolBuffers/src/runtime/Classes/ExtendableMessage.h @@ -0,0 +1,90 @@ +// Protocol Buffers for Objective C +// +// Copyright 2010 Booyah Inc. +// Copyright 2008 Cyrus Najmabadi +// +// 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. + +#import "GeneratedMessage.h" + +#import "ExtensionField.h" + +/** + * Generated message classes for message types that contain extension ranges + * subclass this. + * + *

This class implements type-safe accessors for extensions. They + * implement all the same operations that you can do with normal fields -- + * e.g. "has", "get", and "getCount" -- but for extensions. The extensions + * are identified using instances of the class {@link GeneratedExtension}; + * the protocol compiler generates a static instance of this class for every + * extension in its input. Through the magic of generics, all is made + * type-safe. + * + *

For example, imagine you have the {@code .proto} file: + * + *

+ * option java_class = "MyProto";
+ *
+ * message Foo {
+ *   extensions 1000 to max;
+ * }
+ *
+ * extend Foo {
+ *   optional int32 bar;
+ * }
+ * 
+ * + *

Then you might write code like: + * + *

+ * MyProto.Foo foo = getFoo();
+ * int i = foo.getExtension(MyProto.bar);
+ * 
+ * + *

See also {@link ExtendableBuilder}. + */ +@interface PBExtendableMessage : PBGeneratedMessage { +@private + NSMutableDictionary* extensionMap; + NSMutableDictionary* extensionRegistry; +} + +@property (strong) NSMutableDictionary* extensionMap; +@property (strong) NSMutableDictionary* extensionRegistry; + +- (BOOL) hasExtension:(id) extension; +- (id) getExtension:(id) extension; + +//@protected +- (BOOL) extensionsAreInitialized; +- (SInt32) extensionsSerializedSize; +- (void) writeExtensionsToCodedOutputStream:(PBCodedOutputStream*) output + from:(SInt32) startInclusive + to:(SInt32) endExclusive; +- (void) writeExtensionDescriptionToMutableString:(NSMutableString*) output + from:(SInt32) startInclusive + to:(SInt32) endExclusive + withIndent:(NSString*) indent; +- (BOOL) isEqualExtensionsInOther:(PBExtendableMessage*)otherMessage + from:(SInt32) startInclusive + to:(SInt32) endExclusive; +- (NSUInteger) hashExtensionsFrom:(SInt32) startInclusive + to:(SInt32) endExclusive; + + + +/* @internal */ +- (void) ensureExtensionIsRegistered:(id) extension; + +@end diff --git a/ios/Pods/ProtocolBuffers/src/runtime/Classes/ExtendableMessage.m b/ios/Pods/ProtocolBuffers/src/runtime/Classes/ExtendableMessage.m new file mode 100644 index 000000000..549563792 --- /dev/null +++ b/ios/Pods/ProtocolBuffers/src/runtime/Classes/ExtendableMessage.m @@ -0,0 +1,155 @@ +// Protocol Buffers for Objective C +// +// Copyright 2010 Booyah Inc. +// Copyright 2008 Cyrus Najmabadi +// +// 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. + +#import "ExtendableMessage.h" + +#import "ExtensionField.h" + +@implementation PBExtendableMessage + +@synthesize extensionMap; +@synthesize extensionRegistry; + + + + +- (BOOL) isInitialized:(id) object { + if ([object isKindOfClass:[NSArray class]]) { + for (id child in object) { + if (![self isInitialized:child]) { + return NO; + } + } + } else if ([object conformsToProtocol:@protocol(PBMessage)]) { + return [object isInitialized]; + } + + return YES; +} + + +- (BOOL) extensionsAreInitialized { + return [self isInitialized:extensionMap.allValues]; +} + + +- (id) getExtension:(id) extension { + [self ensureExtensionIsRegistered:extension]; + id value = [extensionMap objectForKey:@([extension fieldNumber])]; + if (value != nil) { + return value; + } + + return [extension defaultValue]; +} + + +- (void) ensureExtensionIsRegistered:(id) extension { + if ([extension extendedClass] != [self class]) { + @throw [NSException exceptionWithName:@"IllegalArgument" reason:@"Trying to use an extension for another type" userInfo:nil]; + } + + if (extensionRegistry == nil) { + self.extensionRegistry = [NSMutableDictionary dictionary]; + } + [extensionRegistry setObject:extension + forKey:@([extension fieldNumber])]; +} + + +- (BOOL) hasExtension:(id) extension { + return nil != [extensionMap objectForKey:@([extension fieldNumber])]; +} + + +- (void) writeExtensionsToCodedOutputStream:(PBCodedOutputStream*) output + from:(SInt32) startInclusive + to:(SInt32) endExclusive { + // man, i really wish Cocoa had a Sorted/TreeMap + NSArray* sortedKeys = [extensionMap.allKeys sortedArrayUsingSelector:@selector(compare:)]; + for (NSNumber* number in sortedKeys) { + SInt32 fieldNumber = (SInt32)[number integerValue]; + if (fieldNumber >= startInclusive && fieldNumber < endExclusive) { + id extension = [extensionRegistry objectForKey:number]; + id value = [extensionMap objectForKey:number]; + [extension writeValue:value includingTagToCodedOutputStream:output]; + } + } +} + + +- (void) writeExtensionDescriptionToMutableString:(NSMutableString*) output + from:(SInt32) startInclusive + to:(SInt32) endExclusive + withIndent:(NSString*) indent { + NSArray* sortedKeys = [extensionMap.allKeys sortedArrayUsingSelector:@selector(compare:)]; + for (NSNumber* number in sortedKeys) { + SInt32 fieldNumber = (SInt32)[number integerValue]; + if (fieldNumber >= startInclusive && fieldNumber < endExclusive) { + id extension = [extensionRegistry objectForKey:number]; + id value = [extensionMap objectForKey:number]; + [extension writeDescriptionOf:value to:output withIndent:indent]; + } + } +} + + +- (BOOL) isEqualExtensionsInOther:(PBExtendableMessage*)otherMessage + from:(SInt32) startInclusive + to:(SInt32) endExclusive { + NSArray* sortedKeys = [extensionMap.allKeys sortedArrayUsingSelector:@selector(compare:)]; + for (NSNumber* number in sortedKeys) { + SInt32 fieldNumber = (SInt32)[number integerValue]; + if (fieldNumber >= startInclusive && fieldNumber < endExclusive) { + id value = [extensionMap objectForKey:number]; + id otherValue = [otherMessage.extensionMap objectForKey:number]; + if (![value isEqual:otherValue]) { + return NO; + } + } + } + return YES; +} + + +- (NSUInteger) hashExtensionsFrom:(SInt32) startInclusive + to:(SInt32) endExclusive { + NSUInteger hashCode = 0; + NSArray* sortedKeys = [extensionMap.allKeys sortedArrayUsingSelector:@selector(compare:)]; + for (NSNumber* number in sortedKeys) { + SInt32 fieldNumber = (SInt32)[number integerValue]; + if (fieldNumber >= startInclusive && fieldNumber < endExclusive) { + id value = [extensionMap objectForKey:number]; + hashCode = hashCode * 31 + (NSUInteger)[value hash]; + } + } + return hashCode; +} + + +- (SInt32) extensionsSerializedSize { + SInt32 size = 0; + for (NSNumber* number in extensionMap) { + id extension = [extensionRegistry objectForKey:number]; + id value = [extensionMap objectForKey:number]; + size += [extension computeSerializedSizeIncludingTag:value]; + } + + return size; +} + +@end diff --git a/ios/Pods/ProtocolBuffers/src/runtime/Classes/ExtendableMessageBuilder.h b/ios/Pods/ProtocolBuffers/src/runtime/Classes/ExtendableMessageBuilder.h new file mode 100644 index 000000000..764629b05 --- /dev/null +++ b/ios/Pods/ProtocolBuffers/src/runtime/Classes/ExtendableMessageBuilder.h @@ -0,0 +1,78 @@ +// Protocol Buffers for Objective C +// +// Copyright 2010 Booyah Inc. +// Copyright 2008 Cyrus Najmabadi +// +// 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. + +#import "GeneratedMessageBuilder.h" + +#import "ExtensionField.h" + +@class PBExtendableMessage; + +/** + * Generated message builders for message types that contain extension ranges + * subclass this. + * + *

This class implements type-safe accessors for extensions. They + * implement all the same operations that you can do with normal fields -- + * e.g. "get", "set", and "add" -- but for extensions. The extensions are + * identified using instances of the class {@link GeneratedExtension}; the + * protocol compiler generates a static instance of this class for every + * extension in its input. Through the magic of generics, all is made + * type-safe. + * + *

For example, imagine you have the {@code .proto} file: + * + *

+ * option java_class = "MyProto";
+ *
+ * message Foo {
+ *   extensions 1000 to max;
+ * }
+ *
+ * extend Foo {
+ *   optional int32 bar;
+ * }
+ * 
+ * + *

Then you might write code like: + * + *

+ * MyProto.Foo foo =
+ *   MyProto.Foo.newBuilder()
+ *     .setExtension(MyProto.bar, 123)
+ *     .build();
+ * 
+ * + *

See also {@link ExtendableMessage}. + */ +@interface PBExtendableMessageBuilder : PBGeneratedMessageBuilder { +} + +- (id) getExtension:(id) extension; +- (BOOL) hasExtension:(id) extension; +- (PBExtendableMessageBuilder*) setExtension:(id) extension + value:(id) value; +- (PBExtendableMessageBuilder*) addExtension:(id) extension + value:(id) value; +- (PBExtendableMessageBuilder*) setExtension:(id) extension + index:(SInt32) index + value:(id) value; +- (PBExtendableMessageBuilder*) clearExtension:(id) extension; + +/* @protected */ +- (void) mergeExtensionFields:(PBExtendableMessage*) other; + +@end diff --git a/ios/Pods/ProtocolBuffers/src/runtime/Classes/ExtendableMessageBuilder.m b/ios/Pods/ProtocolBuffers/src/runtime/Classes/ExtendableMessageBuilder.m new file mode 100644 index 000000000..5a56b0429 --- /dev/null +++ b/ios/Pods/ProtocolBuffers/src/runtime/Classes/ExtendableMessageBuilder.m @@ -0,0 +1,175 @@ +// Protocol Buffers for Objective C +// +// Copyright 2010 Booyah Inc. +// Copyright 2008 Cyrus Najmabadi +// +// 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. + +#import "ExtendableMessageBuilder.h" + +#import "ExtendableMessage.h" +#import "ExtensionRegistry.h" +#import "WireFormat.h" + +@implementation PBExtendableMessageBuilder + +- (PBExtendableMessage*) internalGetResult { + @throw [NSException exceptionWithName:@"ImproperSubclassing" reason:@"" userInfo:nil]; +} + + +/** + * Called by subclasses to parse an unknown field or an extension. + * @return {@code YES} unless the tag is an end-group tag. + */ +- (BOOL) parseUnknownField:(PBCodedInputStream*) input + unknownFields:(PBUnknownFieldSetBuilder*) unknownFields + extensionRegistry:(PBExtensionRegistry*) extensionRegistry + tag:(SInt32) tag { + PBExtendableMessage* message = [self internalGetResult]; + SInt32 wireType = PBWireFormatGetTagWireType(tag); + SInt32 fieldNumber = PBWireFormatGetTagFieldNumber(tag); + + id extension = [extensionRegistry getExtension:[message class] + fieldNumber:fieldNumber]; + + if (extension != nil) { + if ([extension wireType] == wireType) { + [extension mergeFromCodedInputStream:input + unknownFields:unknownFields + extensionRegistry:extensionRegistry + builder:self + tag:tag]; + return YES; + } + } + + return [super parseUnknownField:input unknownFields:unknownFields extensionRegistry:extensionRegistry tag:tag]; +} + + +- (id) getExtension:(id) extension { + return [[self internalGetResult] getExtension:extension]; +} + + +- (BOOL) hasExtension:(id) extension { + return [[self internalGetResult] hasExtension:extension]; +} + + +- (PBExtendableMessageBuilder*) setExtension:(id) extension + value:(id) value { + PBExtendableMessage* message = [self internalGetResult]; + [message ensureExtensionIsRegistered:extension]; + + if ([extension isRepeated]) { + @throw [NSException exceptionWithName:@"IllegalArgument" reason:@"Must call addExtension() for repeated types." userInfo:nil]; + } + + if (message.extensionMap == nil) { + message.extensionMap = [NSMutableDictionary dictionary]; + } + [message.extensionMap setObject:value forKey:@([extension fieldNumber])]; + return self; +} + + +- (PBExtendableMessageBuilder*) addExtension:(id) extension + value:(id) value { + PBExtendableMessage* message = [self internalGetResult]; + [message ensureExtensionIsRegistered:extension]; + + if (![extension isRepeated]) { + @throw [NSException exceptionWithName:@"IllegalArgument" reason:@"Must call setExtension() for singular types." userInfo:nil]; + } + + if (message.extensionMap == nil) { + message.extensionMap = [NSMutableDictionary dictionary]; + } + NSNumber* fieldNumber = @([extension fieldNumber]); + NSMutableArray* list = [message.extensionMap objectForKey:fieldNumber]; + if (list == nil) { + list = [NSMutableArray array]; + [message.extensionMap setObject:list forKey:fieldNumber]; + } + + [list addObject:value]; + return self; +} + + +- (PBExtendableMessageBuilder*) setExtension:(id) extension + index:(SInt32) index + value:(id) value { + PBExtendableMessage* message = [self internalGetResult]; + [message ensureExtensionIsRegistered:extension]; + + if (![extension isRepeated]) { + @throw [NSException exceptionWithName:@"IllegalArgument" reason:@"Must call setExtension() for singular types." userInfo:nil]; + } + + if (message.extensionMap == nil) { + message.extensionMap = [NSMutableDictionary dictionary]; + } + + NSNumber* fieldNumber = @([extension fieldNumber]); + NSMutableArray* list = [message.extensionMap objectForKey:fieldNumber]; + + [list replaceObjectAtIndex:index withObject:value]; + + return self; +} + + +- (PBExtendableMessageBuilder*) clearExtension:(id) extension { + PBExtendableMessage* message = [self internalGetResult]; + [message ensureExtensionIsRegistered:extension]; + [message.extensionMap removeObjectForKey:@([extension fieldNumber])]; + + return self; +} + + +- (void) mergeExtensionFields:(PBExtendableMessage*) other { + PBExtendableMessage* thisMessage = [self internalGetResult]; + if ([thisMessage class] != [other class]) { + @throw [NSException exceptionWithName:@"IllegalArgument" reason:@"Cannot merge extensions from a different type" userInfo:nil]; + } + + if (other.extensionMap.count > 0) { + if (thisMessage.extensionMap == nil) { + thisMessage.extensionMap = [NSMutableDictionary dictionary]; + } + + NSDictionary* registry = other.extensionRegistry; + for (NSNumber* fieldNumber in other.extensionMap) { + id thisField = [registry objectForKey:fieldNumber]; + id value = [other.extensionMap objectForKey:fieldNumber]; + + if ([thisField isRepeated]) { + NSMutableArray* list = [thisMessage.extensionMap objectForKey:fieldNumber]; + if (list == nil) { + list = [NSMutableArray array]; + [thisMessage.extensionMap setObject:list forKey:fieldNumber]; + } + + [list addObjectsFromArray:value]; + } else { + [thisMessage.extensionMap setObject:value forKey:fieldNumber]; + } + } + } +} + +@end diff --git a/ios/Pods/ProtocolBuffers/src/runtime/Classes/ExtensionField.h b/ios/Pods/ProtocolBuffers/src/runtime/Classes/ExtensionField.h new file mode 100644 index 000000000..29f7a4fdd --- /dev/null +++ b/ios/Pods/ProtocolBuffers/src/runtime/Classes/ExtensionField.h @@ -0,0 +1,43 @@ +// Protocol Buffers for Objective C +// +// Copyright 2010 Booyah Inc. +// Copyright 2008 Cyrus Najmabadi +// +// 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. + +#import "WireFormat.h" + +@class PBCodedInputStream; +@class PBCodedOutputStream; +@class PBExtendableMessageBuilder; +@class PBExtensionRegistry; +@class PBUnknownFieldSetBuilder; + +@protocol PBExtensionField +- (SInt32) fieldNumber; +- (PBWireFormat) wireType; +- (BOOL) isRepeated; +- (Class) extendedClass; +- (id) defaultValue; + +- (void) mergeFromCodedInputStream:(PBCodedInputStream*) input + unknownFields:(PBUnknownFieldSetBuilder*) unknownFields + extensionRegistry:(PBExtensionRegistry*) extensionRegistry + builder:(PBExtendableMessageBuilder*) builder + tag:(SInt32) tag; +- (void) writeValue:(id) value includingTagToCodedOutputStream:(PBCodedOutputStream*) output; +- (SInt32) computeSerializedSizeIncludingTag:(id) value; +- (void) writeDescriptionOf:(id) value + to:(NSMutableString*) output + withIndent:(NSString*) indent; +@end diff --git a/ios/Pods/ProtocolBuffers/src/runtime/Classes/ExtensionRegistry.h b/ios/Pods/ProtocolBuffers/src/runtime/Classes/ExtensionRegistry.h new file mode 100644 index 000000000..733730e97 --- /dev/null +++ b/ios/Pods/ProtocolBuffers/src/runtime/Classes/ExtensionRegistry.h @@ -0,0 +1,86 @@ +// Protocol Buffers for Objective C +// +// Copyright 2010 Booyah Inc. +// Copyright 2008 Cyrus Najmabadi +// +// 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. + +/** + * A table of known extensions, searchable by name or field number. When + * parsing a protocol message that might have extensions, you must provide + * an {@code ExtensionRegistry} in which you have registered any extensions + * that you want to be able to parse. Otherwise, those extensions will just + * be treated like unknown fields. + * + *

For example, if you had the {@code .proto} file: + * + *

+ * option java_class = "MyProto";
+ *
+ * message Foo {
+ *   extensions 1000 to max;
+ * }
+ *
+ * extend Foo {
+ *   optional int32 bar;
+ * }
+ * 
+ * + * Then you might write code like: + * + *
+ * ExtensionRegistry registry = ExtensionRegistry.newInstance();
+ * registry.add(MyProto.bar);
+ * MyProto.Foo message = MyProto.Foo.parseFrom(input, registry);
+ * 
+ * + *

Background: + * + *

You might wonder why this is necessary. Two alternatives might come to + * mind. First, you might imagine a system where generated extensions are + * automatically registered when their containing classes are loaded. This + * is a popular technique, but is bad design; among other things, it creates a + * situation where behavior can change depending on what classes happen to be + * loaded. It also introduces a security vulnerability, because an + * unprivileged class could cause its code to be called unexpectedly from a + * privileged class by registering itself as an extension of the right type. + * + *

Another option you might consider is lazy parsing: do not parse an + * extension until it is first requested, at which point the caller must + * provide a type to use. This introduces a different set of problems. First, + * it would require a mutex lock any time an extension was accessed, which + * would be slow. Second, corrupt data would not be detected until first + * access, at which point it would be much harder to deal with it. Third, it + * could violate the expectation that message objects are immutable, since the + * type provided could be any arbitrary message class. An unpriviledged user + * could take advantage of this to inject a mutable object into a message + * belonging to priviledged code and create mischief. + * + * @author Cyrus Najmabadi + */ + +#import "ExtensionField.h" + +@interface PBExtensionRegistry : NSObject { +@protected + NSDictionary* classMap; +} + ++ (PBExtensionRegistry*) emptyRegistry; +- (id) getExtension:(Class) clazz fieldNumber:(SInt32) fieldNumber; + +/* @protected */ +- (id) initWithClassMap:(NSDictionary*) classMap; +- (id) keyForClass:(Class) clazz; + +@end diff --git a/ios/Pods/ProtocolBuffers/src/runtime/Classes/ExtensionRegistry.m b/ios/Pods/ProtocolBuffers/src/runtime/Classes/ExtensionRegistry.m new file mode 100644 index 000000000..42528887d --- /dev/null +++ b/ios/Pods/ProtocolBuffers/src/runtime/Classes/ExtensionRegistry.m @@ -0,0 +1,62 @@ +// Protocol Buffers for Objective C +// +// Copyright 2010 Booyah Inc. +// Copyright 2008 Cyrus Najmabadi +// +// 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. + +#import "ExtensionRegistry.h" + +@interface PBExtensionRegistry() +@property (strong) NSDictionary* classMap; +@end + +@implementation PBExtensionRegistry + +@synthesize classMap; + + +static PBExtensionRegistry* emptyRegistry = nil; + ++ (void) initialize { + if (self == [PBExtensionRegistry class]) { + emptyRegistry = [[PBExtensionRegistry alloc] initWithClassMap:[NSDictionary dictionary]]; + } +} + + +- (id) initWithClassMap:(NSDictionary*) map_{ + if ((self = [super init])) { + self.classMap = map_; + } + + return self; +} + + +- (id) keyForClass:(Class) clazz { + return NSStringFromClass(clazz); +} + + ++ (PBExtensionRegistry*) emptyRegistry { + return emptyRegistry; +} + + +- (id) getExtension:(Class) clazz fieldNumber:(SInt32) fieldNumber { + NSDictionary* extensionMap = [classMap objectForKey:[self keyForClass:clazz]]; + return [extensionMap objectForKey:[NSNumber numberWithInteger:fieldNumber]]; +} + +@end diff --git a/ios/Pods/ProtocolBuffers/src/runtime/Classes/Field.h b/ios/Pods/ProtocolBuffers/src/runtime/Classes/Field.h new file mode 100644 index 000000000..8c794bc71 --- /dev/null +++ b/ios/Pods/ProtocolBuffers/src/runtime/Classes/Field.h @@ -0,0 +1,50 @@ +// Protocol Buffers for Objective C +// +// Copyright 2010 Booyah Inc. +// Copyright 2008 Cyrus Najmabadi +// +// 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. + +#import + +@class PBArray; +@class PBAppendableArray; +@class PBCodedOutputStream; + +@interface PBField : NSObject +{ +@protected + PBAppendableArray * _varintArray; + PBAppendableArray * _fixed32Array; + PBAppendableArray * _fixed64Array; + NSMutableArray * _lengthDelimitedArray; + NSMutableArray * _groupArray; +} + +@property (nonatomic,strong,readonly) PBArray * varintArray; +@property (nonatomic,strong,readonly) PBArray * fixed32Array; +@property (nonatomic,strong,readonly) PBArray * fixed64Array; +@property (nonatomic,strong,readonly) NSArray * lengthDelimitedArray; +@property (nonatomic,strong,readonly) NSArray * groupArray; + ++ (PBField *)defaultInstance; + +- (SInt32)getSerializedSize:(SInt32)fieldNumber; +- (SInt32)getSerializedSizeAsMessageSetExtension:(SInt32)fieldNumber; + +- (void)writeTo:(SInt32) fieldNumber output:(PBCodedOutputStream *)output; +- (void)writeAsMessageSetExtensionTo:(SInt32)fieldNumber output:(PBCodedOutputStream *)output; +- (void)writeDescriptionFor:(SInt32) fieldNumber + to:(NSMutableString*) output + withIndent:(NSString*) indent; +@end diff --git a/ios/Pods/ProtocolBuffers/src/runtime/Classes/Field.m b/ios/Pods/ProtocolBuffers/src/runtime/Classes/Field.m new file mode 100644 index 000000000..2bf76b158 --- /dev/null +++ b/ios/Pods/ProtocolBuffers/src/runtime/Classes/Field.m @@ -0,0 +1,159 @@ +// Protocol Buffers for Objective C +// +// Copyright 2010 Booyah Inc. +// Copyright 2008 Cyrus Najmabadi +// +// 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. + +#import "Field.h" + +#import "CodedOutputStream.h" +#import "PBArray.h" +#import "UnknownFieldSet.h" +#import "Utilities.h" + +@implementation PBField + +@synthesize varintArray = _varintArray; +@synthesize fixed32Array = _fixed32Array; +@synthesize fixed64Array = _fixed64Array; +@synthesize lengthDelimitedArray = _lengthDelimitedArray; +@synthesize groupArray = _groupArray; + +static PBField *sDefaultInstance = nil; + ++ (void)initialize { + if (self == [PBField class]) { + sDefaultInstance = [[PBField alloc] init]; + } +} + + ++ (PBField *)defaultInstance { + return sDefaultInstance; +} + +- (SInt32)getSerializedSize:(SInt32)fieldNumber { + SInt32 result = 0; + + const SInt64 *varintValues = (const SInt64 *)_varintArray.data; + if (varintValues) { + const NSUInteger count = _varintArray.count; + for (UInt32 i = 0; i < count; ++i) { + result += computeInt64Size(fieldNumber, varintValues[i]); + } + } + + const SInt32 *fixed32Values = (const SInt32 *)_fixed32Array.data; + if (fixed32Values) { + const NSUInteger count = _fixed32Array.count; + for (UInt32 i = 0; i < count; ++i) { + result += computeFixed32Size(fieldNumber, fixed32Values[i]); + } + } + + const SInt64 *fixed64Values = (const SInt64 *)_fixed64Array.data; + if (fixed64Values) { + const NSUInteger count = _fixed64Array.count; + for (NSUInteger i = 0; i < count; ++i) { + result += computeFixed64Size(fieldNumber, fixed64Values[i]); + } + } + + for (NSData *value in _lengthDelimitedArray) { + result += computeDataSize(fieldNumber, value); + } + + for (PBUnknownFieldSet *value in _groupArray) { + result += computeUnknownGroupSize(fieldNumber, value); + } + + return result; +} + +- (SInt32)getSerializedSizeAsMessageSetExtension:(SInt32)fieldNumber { + SInt32 result = 0; + + for (NSData *value in _lengthDelimitedArray) { + result += computeRawMessageSetExtensionSize(fieldNumber, value); + } + + return result; +} + +- (void)writeTo:(SInt32)fieldNumber output:(PBCodedOutputStream *) output { + const SInt64 *varintValues = (const SInt64 *)_varintArray.data; + if (varintValues) { + const NSUInteger count = _varintArray.count; + for (NSUInteger i = 0; i < count; ++i) { + [output writeInt64:fieldNumber value:varintValues[i]]; + } + } + + const SInt32 *fixed32Values = (const SInt32 *)_fixed32Array.data; + if (fixed32Values) { + const NSUInteger count = _fixed32Array.count; + for (NSUInteger i = 0; i < count; ++i) { + [output writeFixed32:fieldNumber value:fixed32Values[i]]; + } + } + + const SInt64 *fixed64Values = (const SInt64 *)_fixed64Array.data; + if (fixed64Values) { + const NSUInteger count = _fixed64Array.count; + for (NSUInteger i = 0; i < count; ++i) { + [output writeFixed64:fieldNumber value:fixed64Values[i]]; + } + } + + for (NSData *value in _lengthDelimitedArray) { + [output writeData:fieldNumber value:value]; + } + + for (PBUnknownFieldSet *value in _groupArray) { + [output writeUnknownGroup:fieldNumber value:value]; + } +} + +- (void)writeDescriptionFor:(SInt32) fieldNumber + to:(NSMutableString*) output + withIndent:(NSString*) indent { + [self.varintArray enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) { + + }]; + [self.varintArray enumerateObjectsUsingBlock:^(NSNumber* value, NSUInteger idx, BOOL *stop) { + [output appendFormat:@"%@%ld: %qi\n", indent, (long)fieldNumber, value.longLongValue]; + }]; + [self.fixed32Array enumerateObjectsUsingBlock:^(NSNumber* value, NSUInteger idx, BOOL *stop) { + [output appendFormat:@"%@%ld: %ld\n", indent, (long)fieldNumber, (long)value.integerValue]; + }]; + [self.fixed64Array enumerateObjectsUsingBlock:^(NSNumber* value, NSUInteger idx, BOOL *stop) { + [output appendFormat:@"%@%ld: %lld\n", indent, (long)fieldNumber, value.longLongValue]; + }]; + for (NSData* value in self.lengthDelimitedArray) { + [output appendFormat:@"%@%ld: %@\n", indent, (long)fieldNumber, value]; + } + for (PBUnknownFieldSet* value in self.groupArray) { + [output appendFormat:@"%@%ld: [\n", indent, (long)fieldNumber]; + [value writeDescriptionTo:output withIndent:[NSString stringWithFormat:@"%@ ", indent]]; + [output appendFormat:@"%@]", indent]; + } +} + +- (void)writeAsMessageSetExtensionTo:(SInt32)fieldNumber output:(PBCodedOutputStream *) output { + for (NSData *value in _lengthDelimitedArray) { + [output writeRawMessageSetExtension:fieldNumber value:value]; + } +} + +@end \ No newline at end of file diff --git a/ios/Pods/ProtocolBuffers/src/runtime/Classes/ForwardDeclarations.h b/ios/Pods/ProtocolBuffers/src/runtime/Classes/ForwardDeclarations.h new file mode 100644 index 000000000..cd776e3a4 --- /dev/null +++ b/ios/Pods/ProtocolBuffers/src/runtime/Classes/ForwardDeclarations.h @@ -0,0 +1,35 @@ +// Protocol Buffers for Objective C +// +// Copyright 2010 Booyah Inc. +// Copyright 2008 Cyrus Najmabadi +// +// 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. + +@protocol PBMessage; +@protocol PBMessageBuilder; +@protocol PBExtensionField; + +@class PBAbstractMessage; +@class PBCodedInputStream; +@class PBCodedOutputStream; +@class PBConcreteExtensionField; +@class PBExtendableMessageBuilder; +@class PBExtendableMessage; +@class PBExtensionRegistry; +@class PBField; +@class PBGeneratedMessage; +@class PBGeneratedMessageBuilder; +@class PBMutableExtensionRegistry; +@class PBMutableField; +@class PBUnknownFieldSet; +@class PBUnknownFieldSetBuilder; diff --git a/ios/Pods/ProtocolBuffers/src/runtime/Classes/GeneratedMessage.h b/ios/Pods/ProtocolBuffers/src/runtime/Classes/GeneratedMessage.h new file mode 100644 index 000000000..c94a2656b --- /dev/null +++ b/ios/Pods/ProtocolBuffers/src/runtime/Classes/GeneratedMessage.h @@ -0,0 +1,36 @@ +// Protocol Buffers for Objective C +// +// Copyright 2010 Booyah Inc. +// Copyright 2008 Cyrus Najmabadi +// +// 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. + +#import "AbstractMessage.h" + +/** + * All generated protocol message classes extend this class. This class + * implements most of the Message and Builder interfaces using Java reflection. + * Users can ignore this class and pretend that generated messages implement + * the Message interface directly. + * + * @author Cyrus Najmabadi + */ +@interface PBGeneratedMessage : PBAbstractMessage { +@private + PBUnknownFieldSet* unknownFields; + +@protected + SInt32 memoizedSerializedSize; +} + +@end diff --git a/ios/Pods/ProtocolBuffers/src/runtime/Classes/GeneratedMessage.m b/ios/Pods/ProtocolBuffers/src/runtime/Classes/GeneratedMessage.m new file mode 100644 index 000000000..08e4dd8d8 --- /dev/null +++ b/ios/Pods/ProtocolBuffers/src/runtime/Classes/GeneratedMessage.m @@ -0,0 +1,40 @@ +// Protocol Buffers for Objective C +// +// Copyright 2010 Booyah Inc. +// Copyright 2008 Cyrus Najmabadi +// +// 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. + +#import "GeneratedMessage.h" + +#import "UnknownFieldSet.h" + +@interface PBGeneratedMessage () +@property (strong) PBUnknownFieldSet* unknownFields; +@end + + +@implementation PBGeneratedMessage + +@synthesize unknownFields; + +- (id) init { + if ((self = [super init])) { + self.unknownFields = [PBUnknownFieldSet defaultInstance]; + memoizedSerializedSize = -1; + } + + return self; +} + +@end diff --git a/ios/Pods/ProtocolBuffers/src/runtime/Classes/GeneratedMessageBuilder.h b/ios/Pods/ProtocolBuffers/src/runtime/Classes/GeneratedMessageBuilder.h new file mode 100644 index 000000000..a8c84f413 --- /dev/null +++ b/ios/Pods/ProtocolBuffers/src/runtime/Classes/GeneratedMessageBuilder.h @@ -0,0 +1,33 @@ +// Protocol Buffers for Objective C +// +// Copyright 2010 Booyah Inc. +// Copyright 2008 Cyrus Najmabadi +// +// 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. + +#import "AbstractMessageBuilder.h" + +@class PBUnknownFieldSetBuilder; + +@interface PBGeneratedMessageBuilder : PBAbstractMessageBuilder { +} + +/* @protected */ +- (BOOL) parseUnknownField:(PBCodedInputStream*) input + unknownFields:(PBUnknownFieldSetBuilder*) unknownFields + extensionRegistry:(PBExtensionRegistry*) extensionRegistry + tag:(SInt32) tag; + +- (void) checkInitialized; + +@end diff --git a/ios/Pods/ProtocolBuffers/src/runtime/Classes/GeneratedMessageBuilder.m b/ios/Pods/ProtocolBuffers/src/runtime/Classes/GeneratedMessageBuilder.m new file mode 100644 index 000000000..09fe852e6 --- /dev/null +++ b/ios/Pods/ProtocolBuffers/src/runtime/Classes/GeneratedMessageBuilder.m @@ -0,0 +1,95 @@ +// Protocol Buffers for Objective C +// +// Copyright 2010 Booyah Inc. +// Copyright 2008 Cyrus Najmabadi +// +// 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. + +#import "GeneratedMessageBuilder.h" + +#import "GeneratedMessage.h" +#import "Message.h" +#import "MessageBuilder.h" +#import "UnknownFieldSet.h" +#import "UnknownFieldSetBuilder.h" + + +@interface PBGeneratedMessage () +@property (strong) PBUnknownFieldSet* unknownFields; +@end + + +@implementation PBGeneratedMessageBuilder + +/** + * Get the message being built. We don't just pass this to the + * constructor because it becomes null when build() is called. + */ +- (PBGeneratedMessage*) internalGetResult { + @throw [NSException exceptionWithName:@"ImproperSubclassing" reason:@"" userInfo:nil]; +} + + +- (void) checkInitialized { + PBGeneratedMessage* result = self.internalGetResult; + if (result != nil && !result.isInitialized) { + @throw [NSException exceptionWithName:@"UninitializedMessage" reason:@"" userInfo:nil]; + } +} + + +- (PBUnknownFieldSet*) unknownFields { + return self.internalGetResult.unknownFields; +} + + +- (id) setUnknownFields:(PBUnknownFieldSet*) unknownFields { + self.internalGetResult.unknownFields = unknownFields; + return self; +} + + +- (id) mergeUnknownFields:(PBUnknownFieldSet*) unknownFields { + PBGeneratedMessage* result = self.internalGetResult; + result.unknownFields = + [[[PBUnknownFieldSet builderWithUnknownFields:result.unknownFields] + mergeUnknownFields:unknownFields] build]; + return self; +} + + +- (BOOL) isInitialized { + return self.internalGetResult.isInitialized; +} + + +/** + * Called by subclasses to parse an unknown field. + * @return {@code YES} unless the tag is an end-group tag. + */ +- (BOOL) parseUnknownField:(PBCodedInputStream*) input + unknownFields:(PBUnknownFieldSetBuilder*) unknownFields + extensionRegistry:(PBExtensionRegistry*) extensionRegistry + tag:(SInt32) tag { + return [unknownFields mergeFieldFrom:tag input:input]; +} + + +- (void) checkInitializedParsed { + PBGeneratedMessage* result = self.internalGetResult; + if (result != nil && !result.isInitialized) { + @throw [NSException exceptionWithName:@"InvalidProtocolBuffer" reason:@"" userInfo:nil]; + } +} + +@end diff --git a/ios/Pods/ProtocolBuffers/src/runtime/Classes/Message.h b/ios/Pods/ProtocolBuffers/src/runtime/Classes/Message.h new file mode 100644 index 000000000..e488e9e4b --- /dev/null +++ b/ios/Pods/ProtocolBuffers/src/runtime/Classes/Message.h @@ -0,0 +1,85 @@ +// Protocol Buffers for Objective C +// +// Copyright 2010 Booyah Inc. +// Copyright 2008 Cyrus Najmabadi +// +// 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. + +@class PBCodedOutputStream; +@class PBUnknownFieldSet; +@protocol PBMessageBuilder; + +/** + * Abstract interface implemented by Protocol Message objects. + * + * @author Cyrus Najmabadi + */ +@protocol PBMessage +/** + * Get an instance of the type with all fields set to their default values. + * This may or may not be a singleton. This differs from the + * {@code getDefaultInstance()} method of generated message classes in that + * this method is an abstract method of the {@code Message} interface + * whereas {@code getDefaultInstance()} is a static method of a specific + * class. They return the same thing. + */ +- (id) defaultInstance; + +/** + * Get the {@code UnknownFieldSet} + */ +- (PBUnknownFieldSet*) unknownFields; + +/** + * Get the number of bytes required to encode this message. The result + * is only computed on the first call and memoized after that. + */ +- (SInt32) serializedSize; + +/** + * Returns true if all required fields in the message and all embedded + * messages are set, false otherwise. + */ +- (BOOL) isInitialized; + +/** + * Serializes the message and writes it to {@code output}. This does not + * flush or close the stream. + */ +- (void) writeToCodedOutputStream:(PBCodedOutputStream*) output; +- (void) writeToOutputStream:(NSOutputStream*) output; + +/** + * Serializes the message to a {@code ByteString} and returns it. This is + * just a trivial wrapper around + * {@link #writeTo(CodedOutputStream)}. + */ +- (NSData*) data; + +/** + * Constructs a new builder for a message of the same type as this message. + */ +- (id) builder; + +/** + * Constructs a builder initialized with the current message. Use this to + * derive a new message from the current one. + */ +- (id) toBuilder; + +/** + * Returns a string description of the message. + */ +- (NSString*) description; + +@end diff --git a/ios/Pods/ProtocolBuffers/src/runtime/Classes/MessageBuilder.h b/ios/Pods/ProtocolBuffers/src/runtime/Classes/MessageBuilder.h new file mode 100644 index 000000000..d7d7d2add --- /dev/null +++ b/ios/Pods/ProtocolBuffers/src/runtime/Classes/MessageBuilder.h @@ -0,0 +1,136 @@ +// Protocol Buffers for Objective C +// +// Copyright 2010 Booyah Inc. +// Copyright 2008 Cyrus Najmabadi +// +// 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. + +#import "Message.h" + +@class PBCodedInputStream; +@class PBExtensionRegistry; + +/** + * Abstract interface implemented by Protocol Message builders. + */ +@protocol PBMessageBuilder +/** Resets all fields to their default values. */ +- (id) clear; + +/** + * Construct the final message. Once this is called, the Builder is no + * longer valid, and calling any other method may throw a + * NullPointerException. If you need to continue working with the builder + * after calling {@code build()}, {@code clone()} it first. + * @throws UninitializedMessageException The message is missing one or more + * required fields (i.e. {@link #isInitialized()} returns false). + * Use {@link #buildPartial()} to bypass this check. + */ +- (id) build; + +/** + * Like {@link #build()}, but does not throw an exception if the message + * is missing required fields. Instead, a partial message is returned. + */ +- (id) buildPartial; +- (id) clone; + +/** + * Returns true if all required fields in the message and all embedded + * messages are set, false otherwise. + */ +- (BOOL) isInitialized; + +/** + * Get the message's type's default instance. + * See {@link Message#getDefaultInstanceForType()}. + */ +- (id) defaultInstance; + +- (PBUnknownFieldSet*) unknownFields; +- (id) setUnknownFields:(PBUnknownFieldSet*) unknownFields; + +/** + * Merge some unknown fields into the {@link UnknownFieldSet} for this + * message. + */ +- (id) mergeUnknownFields:(PBUnknownFieldSet*) unknownFields; + +/** + * Parses a message of this type from the input and merges it with this + * message, as if using {@link Builder#mergeFrom(Message)}. + * + *

Warning: This does not verify that all required fields are present in + * the input message. If you call {@link #build()} without setting all + * required fields, it will throw an {@link UninitializedMessageException}, + * which is a {@code RuntimeException} and thus might not be caught. There + * are a few good ways to deal with this: + *

    + *
  • Call {@link #isInitialized()} to verify that all required fields + * are set before building. + *
  • Parse the message separately using one of the static + * {@code parseFrom} methods, then use {@link #mergeFrom(Message)} + * to merge it with this one. {@code parseFrom} will throw an + * {@link InvalidProtocolBufferException} (an {@code IOException}) + * if some required fields are missing. + *
  • Use {@code buildPartial()} to build, which ignores missing + * required fields. + *
+ * + *

Note: The caller should call + * {@link CodedInputStream#checkLastTagWas(int)} after calling this to + * verify that the last tag seen was the appropriate end-group tag, + * or zero for EOF. + */ +- (id) mergeFromCodedInputStream:(PBCodedInputStream*) input; + +/** + * Like {@link Builder#mergeFrom(CodedInputStream)}, but also + * parses extensions. The extensions that you want to be able to parse + * must be registered in {@code extensionRegistry}. Extensions not in + * the registry will be treated as unknown fields. + */ +- (id) mergeFromCodedInputStream:(PBCodedInputStream*) input extensionRegistry:(PBExtensionRegistry*) extensionRegistry; + +/** + * Parse {@code data} as a message of this type and merge it with the + * message being built. This is just a small wrapper around + * {@link #mergeFrom(CodedInputStream)}. + */ +- (id) mergeFromData:(NSData*) data; + +/** + * Parse {@code data} as a message of this type and merge it with the + * message being built. This is just a small wrapper around + * {@link #mergeFrom(CodedInputStream,ExtensionRegistry)}. + */ +- (id) mergeFromData:(NSData*) data extensionRegistry:(PBExtensionRegistry*) extensionRegistry; + +/** + * Parse a message of this type from {@code input} and merge it with the + * message being built. This is just a small wrapper around + * {@link #mergeFrom(CodedInputStream)}. Note that this method always + * reads the entire input (unless it throws an exception). If you + * want it to stop earlier, you will need to wrap your input in some + * wrapper stream that limits reading. Despite usually reading the entire + * input, this does not close the stream. + */ +- (id) mergeFromInputStream:(NSInputStream*) input; + +/** + * Parse a message of this type from {@code input} and merge it with the + * message being built. This is just a small wrapper around + * {@link #mergeFrom(CodedInputStream,ExtensionRegistry)}. + */ +- (id) mergeFromInputStream:(NSInputStream*) input extensionRegistry:(PBExtensionRegistry*) extensionRegistry; +@end diff --git a/ios/Pods/ProtocolBuffers/src/runtime/Classes/MutableExtensionRegistry.h b/ios/Pods/ProtocolBuffers/src/runtime/Classes/MutableExtensionRegistry.h new file mode 100644 index 000000000..dcb97a31f --- /dev/null +++ b/ios/Pods/ProtocolBuffers/src/runtime/Classes/MutableExtensionRegistry.h @@ -0,0 +1,29 @@ +// Protocol Buffers for Objective C +// +// Copyright 2010 Booyah Inc. +// Copyright 2008 Cyrus Najmabadi +// +// 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. + +#import "ExtensionRegistry.h" + +@interface PBMutableExtensionRegistry : PBExtensionRegistry { +@private + NSMutableDictionary* mutableClassMap; +} + ++ (PBMutableExtensionRegistry*) registry; + +- (void) addExtension:(id) extension; + +@end diff --git a/ios/Pods/ProtocolBuffers/src/runtime/Classes/MutableExtensionRegistry.m b/ios/Pods/ProtocolBuffers/src/runtime/Classes/MutableExtensionRegistry.m new file mode 100644 index 000000000..37e6b4b54 --- /dev/null +++ b/ios/Pods/ProtocolBuffers/src/runtime/Classes/MutableExtensionRegistry.m @@ -0,0 +1,65 @@ +// Protocol Buffers for Objective C +// +// Copyright 2010 Booyah Inc. +// Copyright 2008 Cyrus Najmabadi +// +// 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. + +#import "MutableExtensionRegistry.h" + +#import "ExtensionField.h" + +@interface PBMutableExtensionRegistry() +@property (strong) NSMutableDictionary* mutableClassMap; +@end + +@implementation PBMutableExtensionRegistry + +@synthesize mutableClassMap; + + + +- (id) initWithClassMap:(NSMutableDictionary*) mutableClassMap_ { + if ((self = [super initWithClassMap:mutableClassMap_])) { + self.mutableClassMap = mutableClassMap_; + } + + return self; +} + + ++ (PBMutableExtensionRegistry*) registry { + return [[PBMutableExtensionRegistry alloc] initWithClassMap:[NSMutableDictionary dictionary]]; +} + + +- (void) addExtension:(id) extension { + if (extension == nil) { + return; + } + + Class extendedClass = [extension extendedClass]; + id key = [self keyForClass:extendedClass]; + + NSMutableDictionary* extensionMap = [classMap objectForKey:key]; + if (extensionMap == nil) { + extensionMap = [NSMutableDictionary dictionary]; + [mutableClassMap setObject:extensionMap forKey:key]; + } + + [extensionMap setObject:extension + forKey:[NSNumber numberWithInteger:[extension fieldNumber]]]; +} + + +@end diff --git a/ios/Pods/ProtocolBuffers/src/runtime/Classes/MutableField.h b/ios/Pods/ProtocolBuffers/src/runtime/Classes/MutableField.h new file mode 100644 index 000000000..c2096bd86 --- /dev/null +++ b/ios/Pods/ProtocolBuffers/src/runtime/Classes/MutableField.h @@ -0,0 +1,35 @@ +// Protocol Buffers for Objective C +// +// Copyright 2010 Booyah Inc. +// Copyright 2008 Cyrus Najmabadi +// +// 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. + +#import "Field.h" + +@class PBUnknownFieldSet; + +@interface PBMutableField : PBField + ++ (PBMutableField *)field; + +- (PBMutableField *)mergeFromField:(PBField *)other; + +- (PBMutableField *)clear; +- (PBMutableField *)addVarint:(SInt64)value; +- (PBMutableField *)addFixed32:(SInt32)value; +- (PBMutableField *)addFixed64:(SInt64)value; +- (PBMutableField *)addLengthDelimited:(NSData *)value; +- (PBMutableField *)addGroup:(PBUnknownFieldSet *)value; + +@end \ No newline at end of file diff --git a/ios/Pods/ProtocolBuffers/src/runtime/Classes/MutableField.m b/ios/Pods/ProtocolBuffers/src/runtime/Classes/MutableField.m new file mode 100644 index 000000000..843da43c5 --- /dev/null +++ b/ios/Pods/ProtocolBuffers/src/runtime/Classes/MutableField.m @@ -0,0 +1,130 @@ +// Protocol Buffers for Objective C +// +// Copyright 2010 Booyah Inc. +// Copyright 2008 Cyrus Najmabadi +// +// 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. + +#import "MutableField.h" + +#import "Field.h" +#import "PBArray.h" + +@implementation PBMutableField + + ++ (PBMutableField *)field { + return [[PBMutableField alloc] init]; +} + +- (PBMutableField *)clear { + + _varintArray = nil; + _fixed32Array = nil; + _fixed64Array = nil; + _lengthDelimitedArray = nil; + _groupArray = nil; + + return self; +} + +- (PBMutableField *)mergeFromField:(PBField *)other { + if (other.varintArray.count > 0) { + if (_varintArray == nil) { + _varintArray = [other.varintArray copy]; + } else { + [_varintArray appendArray:other.varintArray]; + } + } + + if (other.fixed32Array.count > 0) { + if (_fixed32Array == nil) { + _fixed32Array = [other.fixed32Array copy]; + } else { + [_fixed32Array appendArray:other.fixed32Array]; + } + } + + if (other.fixed64Array.count > 0) { + if (_fixed64Array == nil) { + _fixed64Array = [other.fixed64Array copy]; + } else { + [_fixed64Array appendArray:other.fixed64Array]; + } + } + + if (other.lengthDelimitedArray.count > 0) { + if (_lengthDelimitedArray == nil) { + _lengthDelimitedArray = [other.lengthDelimitedArray copy]; + } else { + [_lengthDelimitedArray addObjectsFromArray:other.lengthDelimitedArray]; + } + } + + if (other.groupArray.count > 0) { + if (_groupArray == nil) { + _groupArray = [other.groupArray copy]; + } else { + [_groupArray addObjectsFromArray:other.groupArray]; + } + } + + return self; +} + +- (PBMutableField *)addVarint:(SInt64)value { + if (_varintArray == nil) { + _varintArray = [[PBAppendableArray alloc] initWithValueType:PBArrayValueTypeInt64]; + } + [_varintArray addInt64:value]; + + return self; +} + +- (PBMutableField *)addFixed32:(SInt32)value { + if (_fixed32Array == nil) { + _fixed32Array = [[PBAppendableArray alloc] initWithValueType:PBArrayValueTypeInt32]; + } + [_fixed32Array addInt32:value]; + + return self; +} + +- (PBMutableField *)addFixed64:(SInt64)value { + if (_fixed64Array == nil) { + _fixed64Array = [[PBAppendableArray alloc] initWithValueType:PBArrayValueTypeInt64]; + } + [_fixed64Array addInt64:value]; + + return self; +} + +- (PBMutableField *)addLengthDelimited:(NSData *)value { + if (_lengthDelimitedArray == nil) { + _lengthDelimitedArray = [[NSMutableArray alloc] init]; + } + [_lengthDelimitedArray addObject:value]; + + return self; +} + +- (PBMutableField *)addGroup:(PBUnknownFieldSet *)value { + if (_groupArray == nil) { + _groupArray = [[NSMutableArray alloc] init]; + } + [_groupArray addObject:value]; + + return self; +} + +@end \ No newline at end of file diff --git a/ios/Pods/ProtocolBuffers/src/runtime/Classes/PBArray.h b/ios/Pods/ProtocolBuffers/src/runtime/Classes/PBArray.h new file mode 100644 index 000000000..fa720cb39 --- /dev/null +++ b/ios/Pods/ProtocolBuffers/src/runtime/Classes/PBArray.h @@ -0,0 +1,106 @@ +// Protocol Buffers for Objective C +// +// Copyright 2010 Booyah Inc. +// +// 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. +// +// Author: Jon Parise + +#import + +extern NSString * const PBArrayTypeMismatchException; +extern NSString * const PBArrayNumberExpectedException; +extern NSString * const PBArrayAllocationFailureException; + +typedef enum _PBArrayValueType +{ + PBArrayValueTypeBool, + PBArrayValueTypeInt32, + PBArrayValueTypeUInt32, + PBArrayValueTypeInt64, + PBArrayValueTypeUInt64, + PBArrayValueTypeFloat, + PBArrayValueTypeDouble, +} PBArrayValueType; + +// PBArray is an immutable array class that's optimized for storing primitive +// values. All values stored in an PBArray instance must have the same type +// (PBArrayValueType). Object values (PBArrayValueTypeObject) are retained. +@interface PBArray : NSObject +{ +@protected + PBArrayValueType _valueType; + NSUInteger _capacity; + NSUInteger _count; + void * _data; + +} + +- (NSUInteger)count; +- (BOOL)boolAtIndex:(NSUInteger)index; +- (SInt32)int32AtIndex:(NSUInteger)index; +- (SInt32)enumAtIndex:(NSUInteger)index; +- (UInt32)uint32AtIndex:(NSUInteger)index; +- (SInt64)int64AtIndex:(NSUInteger)index; +- (UInt64)uint64AtIndex:(NSUInteger)index; +- (Float32)floatAtIndex:(NSUInteger)index; +- (Float64)doubleAtIndex:(NSUInteger)index; +- (BOOL)isEqualToArray:(PBArray *)array; +- (void)enumerateObjectsUsingBlock:(void (^)(id obj, NSUInteger idx, BOOL *stop))block; +- (NSUInteger)indexOfObjectPassingTest:(BOOL (^)(id obj, NSUInteger idx, BOOL *stop))predicate; + +//This Methods automaticaly pack/unpack in NSNumber primitive values +- (id)firstObject; +- (id)lastObject; +- (id)objectAtIndexedSubscript:(NSUInteger)idx; + +@property (nonatomic,assign,readonly) PBArrayValueType valueType; +@property (nonatomic,assign,readonly) const void * data; +@property (nonatomic,assign,readonly,getter=count) NSUInteger count; + +@end + +@interface PBArray (PBArrayExtended) + +- (id)arrayByAppendingArray:(PBArray *)array; +- (PBArray *)filteredArrayUsingPredicate:(NSPredicate *)predicate; +@end + +@interface PBArray (PBArrayCreation) + ++ (id)arrayWithValueType:(PBArrayValueType)valueType; ++ (id)arrayWithValues:(const void *)values count:(NSUInteger)count valueType:(PBArrayValueType)valueType; ++ (id)arrayWithArray:(NSArray *)array valueType:(PBArrayValueType)valueType; +- (id)initWithValueType:(PBArrayValueType)valueType; +- (id)initWithValues:(const void *)values count:(NSUInteger)count valueType:(PBArrayValueType)valueType; +- (id)initWithArray:(NSArray *)array valueType:(PBArrayValueType)valueType; + +@end + +// PBAppendableArray extends PBArray with the ability to append new values to +// the end of the array. +@interface PBAppendableArray : PBArray + +- (void)addBool:(BOOL)value; +- (void)addInt32:(SInt32)value; +- (void)addUint32:(UInt32)value; +- (void)addInt64:(SInt64)value; +- (void)addUint64:(UInt64)value; +- (void)addFloat:(Float32)value; +- (void)addDouble:(Float64)value; +- (void)addEnum:(SInt32)value; + +- (void)appendArray:(PBArray *)array; +- (void)appendValues:(const void *)values count:(UInt32)count; + +@end diff --git a/ios/Pods/ProtocolBuffers/src/runtime/Classes/PBArray.m b/ios/Pods/ProtocolBuffers/src/runtime/Classes/PBArray.m new file mode 100644 index 000000000..be99c006a --- /dev/null +++ b/ios/Pods/ProtocolBuffers/src/runtime/Classes/PBArray.m @@ -0,0 +1,582 @@ +// Protocol Buffers for Objective C +// +// Copyright 2010 Booyah Inc. +// +// 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. +// +// Author: Jon Parise + +#import "PBArray.h" + +NSString * const PBArrayTypeMismatchException = @"PBArrayTypeMismatchException"; +NSString * const PBArrayNumberExpectedException = @"PBArrayNumberExpectedException"; +NSString * const PBArrayAllocationFailureException = @"PBArrayAllocationFailureException"; + +#pragma mark NSNumber Setters + +typedef void (*PBArrayValueSetter)(NSNumber *number, void *value); + +static void PBArraySetBoolValue(NSNumber *number, void *value) +{ + *((BOOL *)value) = [number charValue]; +} + +static void PBArraySetInt32Value(NSNumber *number, void *value) +{ + *((SInt32 *)value) = (SInt32)[number integerValue]; +} + +static void PBArraySetUInt32Value(NSNumber *number, void *value) +{ + *((UInt32 *)value) = (UInt32)[number unsignedIntegerValue]; +} + +static void PBArraySetInt64Value(NSNumber *number, void *value) +{ + *((SInt64 *)value) = (SInt64)[number longLongValue]; +} + +static void PBArraySetUInt64Value(NSNumber *number, void *value) +{ + *((UInt64 *)value) = (UInt64)[number unsignedLongLongValue]; +} + +static void PBArraySetFloatValue(NSNumber *number, void *value) +{ + *((Float32 *)value) = [number floatValue]; +} + +static void PBArraySetDoubleValue(NSNumber *number, void *value) +{ + *((Float64 *)value) = [number doubleValue]; +} + +#pragma mark Array Value Types + +typedef struct _PBArrayValueTypeInfo +{ + const size_t size; + const PBArrayValueSetter setter; + +} PBArrayValueTypeInfo; + +static PBArrayValueTypeInfo PBValueTypes[] = +{ + { sizeof(BOOL), PBArraySetBoolValue }, + { sizeof(SInt32), PBArraySetInt32Value }, + { sizeof(UInt32), PBArraySetUInt32Value }, + { sizeof(SInt64), PBArraySetInt64Value }, + { sizeof(UInt64), PBArraySetUInt64Value }, + { sizeof(Float32), PBArraySetFloatValue }, + { sizeof(Float64), PBArraySetDoubleValue }, +}; + +#define PBArrayValueTypeSize(type) PBValueTypes[type].size +#define PBArrayValueTypeSetter(type) PBValueTypes[type].setter + +#pragma mark Helper Macros + +#define PBArraySlot(index) (_data + (index * PBArrayValueTypeSize(_valueType))) + +#define PBArrayForEachObject(__data, __count, x) \ + if (_valueType == PBArrayValueTypeObject) \ + for (NSUInteger i = 0; i < __count; ++i) { id object = ((id *)__data)[i]; [object x]; } + +#define PBArrayValueTypeAssert(type) \ + if (__builtin_expect(_valueType != type, 0)) \ + [NSException raise:PBArrayTypeMismatchException \ + format:@"array value type mismatch (expected '%s')", #type]; + +#define PBArrayValueRangeAssert(index) \ + if (__builtin_expect(index >= _count, 0)) \ + [NSException raise:NSRangeException format: @"index (%lu) beyond bounds (%lu)", (unsigned long)index, (unsigned long)_count]; + +#define PBArrayNumberAssert(value) \ + if (__builtin_expect(![value isKindOfClass:[NSNumber class]], 0)) \ + [NSException raise:PBArrayNumberExpectedException format:@"NSNumber expected (got '%@')", [value class]]; + +#define PBArrayAllocationAssert(p, size) \ + if (__builtin_expect(p == NULL, 0)) \ + [NSException raise:PBArrayAllocationFailureException format:@"failed to allocate %lu bytes", size]; + +#pragma mark - +#pragma mark PBArray + +@implementation PBArray + +@synthesize valueType = _valueType; +@dynamic data; + +- (id)initWithCount:(NSUInteger)count valueType:(PBArrayValueType)valueType +{ + if ((self = [super init])) + { + _valueType = valueType; + _count = count; + _capacity = count; + + if (_capacity) + { + _data = malloc(_capacity * PBArrayValueTypeSize(_valueType)); + if (_data == NULL) + { + self = nil; + } + } + } + + return self; +} + +- (id)copyWithZone:(NSZone *)zone +{ + PBArray *copy = [[[self class] allocWithZone:zone] initWithCount:_count valueType:_valueType]; + if (copy) + { + memcpy(copy->_data, _data, _count * PBArrayValueTypeSize(_valueType)); + } + + return copy; +} + +- (void)dealloc +{ + if (_data) + { + free(_data); + } +} + +- (NSString *)description +{ + return [NSString stringWithFormat:@"<%@ %p>{valueType = %d, count = %ld, capacity = %ld, data = %p}", + [self class], self, _valueType, (long)_count, (long)_capacity, _data]; +} + +- (NSUInteger)count +{ + return _count; +} + +- (const void *)data +{ + return _data; +} + +- (BOOL)boolAtIndex:(NSUInteger)index +{ + PBArrayValueRangeAssert(index); + PBArrayValueTypeAssert(PBArrayValueTypeBool); + return ((BOOL *)_data)[index]; +} + +- (SInt32)int32AtIndex:(NSUInteger)index +{ + PBArrayValueRangeAssert((unsigned long)index); + PBArrayValueTypeAssert(PBArrayValueTypeInt32); + return ((SInt32 *)_data)[index]; +} + +- (UInt32)uint32AtIndex:(NSUInteger)index +{ + PBArrayValueRangeAssert((unsigned long)index); + PBArrayValueTypeAssert(PBArrayValueTypeUInt32); + return ((UInt32 *)_data)[index]; +} + +- (SInt32)enumAtIndex:(NSUInteger)index +{ + PBArrayValueRangeAssert(index); + PBArrayValueTypeAssert(PBArrayValueTypeInt32); + return ((SInt32 *)_data)[index]; +} + + +- (SInt64)int64AtIndex:(NSUInteger)index +{ + PBArrayValueRangeAssert(index); + PBArrayValueTypeAssert(PBArrayValueTypeInt64); + return ((SInt64 *)_data)[index]; +} + +- (UInt64)uint64AtIndex:(NSUInteger)index +{ + PBArrayValueRangeAssert(index); + PBArrayValueTypeAssert(PBArrayValueTypeUInt64); + return ((UInt64 *)_data)[index]; +} + +- (Float32)floatAtIndex:(NSUInteger)index +{ + PBArrayValueRangeAssert(index); + PBArrayValueTypeAssert(PBArrayValueTypeFloat); + return ((Float32 *)_data)[index]; +} + +- (Float64)doubleAtIndex:(NSUInteger)index +{ + PBArrayValueRangeAssert(index); + PBArrayValueTypeAssert(PBArrayValueTypeDouble); + return ((Float64 *)_data)[index]; +} + +- (BOOL)isEqualToArray:(PBArray *)array +{ + if (self == array) + { + return YES; + } + else if (array->_count != _count) + { + return NO; + } + else + { + return memcmp(array->_data, _data, _count * PBArrayValueTypeSize(_valueType)) == 0; + } +} + +- (BOOL)isEqual:(id)object +{ + BOOL equal = NO; + if ([object isKindOfClass:[PBArray class]]) + { + equal = [self isEqualToArray:object]; + } + return equal; +} + +-(id)firstObject +{ + if (self.count>0) { + return [self objectAtIndexedSubscript:0]; + } + return nil; +} + +-(id)lastObject +{ + if (self.count>0) { + return [self objectAtIndexedSubscript:self.count - 1]; + } + return nil; +} + +- (id)objectAtIndexedSubscript:(NSUInteger)idx +{ + + if (idx < self.count) { + if (PBArrayValueTypeBool == _valueType) + { + return [NSNumber numberWithBool:[self boolAtIndex:idx]]; + } + else if (PBArrayValueTypeInt32 == _valueType) + { + return [NSNumber numberWithLong:[self int32AtIndex:idx]]; + } + else if (PBArrayValueTypeInt64 == _valueType) + { + return [NSNumber numberWithLongLong:[self int64AtIndex:idx]]; + } + else if (PBArrayValueTypeUInt32 == _valueType) + { + return [NSNumber numberWithUnsignedLong:[self uint32AtIndex:idx]]; + } + else if (PBArrayValueTypeUInt64 == _valueType) + { + return [NSNumber numberWithUnsignedLongLong:[self uint64AtIndex:idx]]; + } + else if (_valueType == PBArrayValueTypeFloat) + { + return [NSNumber numberWithFloat:[self floatAtIndex:idx]]; + } + else if (_valueType == PBArrayValueTypeDouble) + { + return [NSNumber numberWithDouble:[self doubleAtIndex:idx]]; + } + } + return nil; + +} + + + +- (void)enumerateObjectsUsingBlock:(void (^)(id obj, NSUInteger idx, BOOL *stop))block +{ + if (!block) return; + BOOL stop = NO; + for (NSInteger i = 0; i < self.count; i++) { + block([self objectAtIndexedSubscript:i],i,&stop); + if(stop){ + break; + } + } +} + +-(NSUInteger)indexOfObjectPassingTest:(BOOL (^)(id obj, NSUInteger, BOOL *stop))predicate +{ + if (!predicate) return NSNotFound; + __block BOOL bb; + __block NSUInteger index; + [self enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) { + + bb = predicate(obj,idx,stop); + if (bb) { + index = idx; + } + }]; + if (bb) { + return index; + } + return NSNotFound; +} + +@end + +@implementation PBArray (PBArrayExtended) + +-(PBArray *) filteredArrayUsingPredicate:(NSPredicate *)predicate +{ + __block PBAppendableArray *newArray = [[PBAppendableArray alloc] initWithValueType:_valueType]; + [self enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) { + + BOOL result = [predicate evaluateWithObject:obj]; + if (result) + { + if (PBArrayValueTypeBool == _valueType) + { + [newArray addBool:[(NSNumber *)obj boolValue]]; + } + else if (PBArrayValueTypeInt32 == _valueType) + { + [newArray addInt32:(SInt32)[(NSNumber *)obj longValue]]; + } + else if (PBArrayValueTypeInt64 == _valueType) + { + [newArray addInt64:[(NSNumber *)obj longLongValue]]; + } + else if (PBArrayValueTypeUInt32 == _valueType) + { + [newArray addUint32:(UInt32)[(NSNumber *)obj unsignedLongValue]]; + } + else if (PBArrayValueTypeUInt64 == _valueType) + { + [newArray addUint64:[(NSNumber *)obj unsignedLongLongValue]]; + } + else if (_valueType == PBArrayValueTypeFloat) + { + [newArray addFloat:[(NSNumber *)obj floatValue]]; + } + else if (_valueType == PBArrayValueTypeDouble) + { + [newArray addDouble:[(NSNumber *)obj doubleValue]]; + } + + + } + }]; + return newArray; +} + +- (id)arrayByAppendingArray:(PBArray *)array +{ + PBArrayValueTypeAssert(array.valueType); + + PBArray *result = [[[self class] alloc] initWithCount:_count + array.count valueType:_valueType]; + if (result) + { + const size_t elementSize = PBArrayValueTypeSize(_valueType); + const size_t originalSize = _count * elementSize; + + memcpy(result->_data, _data, originalSize); + memcpy(result->_data + originalSize, array.data, array.count * elementSize); + } + + return result; +} + +@end + +@implementation PBArray (PBArrayCreation) + ++ (id)arrayWithValueType:(PBArrayValueType)valueType +{ + return [[self alloc] initWithValueType:valueType]; +} + ++ (id)arrayWithValues:(const void *)values count:(NSUInteger)count valueType:(PBArrayValueType)valueType +{ + return [[self alloc] initWithValues:values count:count valueType:valueType]; +} + ++ (id)arrayWithArray:(NSArray *)array valueType:(PBArrayValueType)valueType +{ + return [[self alloc] initWithArray:array valueType:valueType]; +} + +- (id)initWithValueType:(PBArrayValueType)valueType +{ + return [self initWithCount:0 valueType:valueType]; +} + +- (id)initWithValues:(const void *)values count:(NSUInteger)count valueType:(PBArrayValueType)valueType +{ + if ((self = [self initWithCount:count valueType:valueType])) + { + memcpy(_data, values, count * PBArrayValueTypeSize(_valueType)); + } + + return self; +} + +- (id)initWithArray:(NSArray *)array valueType:(PBArrayValueType)valueType +{ + if ((self = [self initWithCount:[array count] valueType:valueType])) + { + const size_t elementSize = PBArrayValueTypeSize(valueType); + size_t offset = 0; + + PBArrayValueSetter setter = PBArrayValueTypeSetter(valueType); + for (id object in array) + { + PBArrayNumberAssert(object); + setter((NSNumber *)object, _data + offset); + offset += elementSize; + } + + } + + return self; +} + +@end + +#pragma mark - +#pragma mark PBAppendableArray + +@implementation PBAppendableArray + +- (void)ensureAdditionalCapacity:(NSUInteger)additionalSlots +{ + const NSUInteger requiredSlots = _count + additionalSlots; + + if (requiredSlots > _capacity) + { + // If we haven't allocated any capacity yet, simply reserve + // enough capacity to cover the required number of slots. + if (_capacity == 0) + { + _capacity = requiredSlots; + } + else + { + // Otherwise, continue to double our capacity until we + // can accomodate the required number of slots. + while (_capacity < requiredSlots) + { + _capacity *= 2; + } + } + + const size_t size = _capacity * PBArrayValueTypeSize(_valueType); + _data = reallocf(_data, size); + PBArrayAllocationAssert(_data, size); + } +} + + + +- (void)addBool:(BOOL)value +{ + PBArrayValueTypeAssert(PBArrayValueTypeBool); + [self ensureAdditionalCapacity:1]; + *(BOOL *)PBArraySlot(_count) = value; + _count++; +} + +- (void)addInt32:(SInt32)value +{ + PBArrayValueTypeAssert(PBArrayValueTypeInt32); + [self ensureAdditionalCapacity:1]; + *(SInt32 *)PBArraySlot(_count) = value; + _count++; +} + +- (void)addUint32:(UInt32)value +{ + PBArrayValueTypeAssert(PBArrayValueTypeUInt32); + [self ensureAdditionalCapacity:1]; + *(UInt32 *)PBArraySlot(_count) = value; + _count++; +} + +- (void)addEnum:(SInt32)value +{ + PBArrayValueTypeAssert(PBArrayValueTypeInt32); + [self ensureAdditionalCapacity:1]; + *(SInt32 *)PBArraySlot(_count) = value; + _count++; +} + +- (void)addInt64:(int64_t)value +{ + PBArrayValueTypeAssert(PBArrayValueTypeInt64); + [self ensureAdditionalCapacity:1]; + *(SInt64 *)PBArraySlot(_count) = value; + _count++; +} + +- (void)addUint64:(uint64_t)value +{ + PBArrayValueTypeAssert(PBArrayValueTypeUInt64); + [self ensureAdditionalCapacity:1]; + *(UInt64 *)PBArraySlot(_count) = value; + _count++; +} + +- (void)addFloat:(Float32)value +{ + PBArrayValueTypeAssert(PBArrayValueTypeFloat); + [self ensureAdditionalCapacity:1]; + *(Float32 *)PBArraySlot(_count) = value; + _count++; +} + +- (void)addDouble:(Float64)value +{ + PBArrayValueTypeAssert(PBArrayValueTypeDouble); + [self ensureAdditionalCapacity:1]; + *(Float64 *)PBArraySlot(_count) = value; + _count++; +} + +- (void)appendArray:(PBArray *)array +{ + PBArrayValueTypeAssert(array.valueType); + [self ensureAdditionalCapacity:array.count]; + + const size_t elementSize = PBArrayValueTypeSize(_valueType); + memcpy(_data + (_count * elementSize), array.data, array.count * elementSize); + _count += array.count; +} + +- (void)appendValues:(const void *)values count:(UInt32)count +{ + [self ensureAdditionalCapacity:count]; + + const size_t elementSize = PBArrayValueTypeSize(_valueType); + memcpy(_data + (_count * elementSize), values, count * elementSize); + _count += count; +} + +@end diff --git a/ios/Pods/ProtocolBuffers/src/runtime/Classes/ProtocolBuffers.h b/ios/Pods/ProtocolBuffers/src/runtime/Classes/ProtocolBuffers.h new file mode 100644 index 000000000..01c6cc639 --- /dev/null +++ b/ios/Pods/ProtocolBuffers/src/runtime/Classes/ProtocolBuffers.h @@ -0,0 +1,40 @@ +// Protocol Buffers for Objective C +// +// Copyright 2010 Booyah Inc. +// Copyright 2008 Cyrus Najmabadi +// +// 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. + +#import +#import "Bootstrap.h" +#import "AbstractMessage.h" +#import "AbstractMessageBuilder.h" +#import "CodedInputStream.h" +#import "CodedOutputStream.h" +#import "ConcreteExtensionField.h" +#import "ExtendableMessage.h" +#import "ExtendableMessageBuilder.h" +#import "ExtensionField.h" +#import "ExtensionRegistry.h" +#import "Field.h" +#import "GeneratedMessage.h" +#import "GeneratedMessageBuilder.h" +#import "Message.h" +#import "MessageBuilder.h" +#import "MutableExtensionRegistry.h" +#import "MutableField.h" +#import "PBArray.h" +#import "UnknownFieldSet.h" +#import "UnknownFieldSetBuilder.h" +#import "Utilities.h" +#import "WireFormat.h" diff --git a/ios/Pods/ProtocolBuffers/src/runtime/Classes/RingBuffer.h b/ios/Pods/ProtocolBuffers/src/runtime/Classes/RingBuffer.h new file mode 100644 index 000000000..f543f4a4a --- /dev/null +++ b/ios/Pods/ProtocolBuffers/src/runtime/Classes/RingBuffer.h @@ -0,0 +1,21 @@ +#import + +@interface RingBuffer : NSObject { + NSMutableData *buffer; + SInt32 position; + SInt32 tail; +} +@property (nonatomic, readonly) UInt32 freeSpace; + +- (id)initWithData:(NSMutableData*)data; + +// Returns false if there is not enough free space in buffer +- (BOOL)appendByte:(uint8_t)byte; + +// Returns number of bytes written +- (SInt32)appendData:(const NSData*)value offset:(SInt32)offset length:(SInt32)length; + +// Returns number of bytes written +- (SInt32)flushToOutputStream:(NSOutputStream*)stream; + +@end diff --git a/ios/Pods/ProtocolBuffers/src/runtime/Classes/RingBuffer.m b/ios/Pods/ProtocolBuffers/src/runtime/Classes/RingBuffer.m new file mode 100644 index 000000000..5978c2c7b --- /dev/null +++ b/ios/Pods/ProtocolBuffers/src/runtime/Classes/RingBuffer.m @@ -0,0 +1,92 @@ +#import "RingBuffer.h" + +@implementation RingBuffer + +- (id)initWithData:(NSMutableData*)data { + if ((self = [super init])) { + buffer = data; + } + return self; +} + + +- (UInt32)freeSpace { + return (UInt32)(position < tail ? tail - position : (buffer.length - position) + tail) - (tail ? 1 : 0); +} + + +- (BOOL)appendByte:(uint8_t)byte { + if (self.freeSpace < 1) return NO; + ((uint8_t*)buffer.mutableBytes)[position++] = byte; + return YES; +} + + +- (SInt32)appendData:(const NSData*)value offset:(SInt32)offset length:(SInt32)length { + SInt32 totalWritten = 0; + const uint8_t *input = value.bytes; + uint8_t *data = buffer.mutableBytes; + + if (position >= tail) { + totalWritten = MIN((UInt32)buffer.length - position, length); + memcpy(data + position, input + offset, totalWritten); + position += totalWritten; + if (totalWritten == length) return length; + length -= totalWritten; + offset += totalWritten; + } + + UInt32 freeSpace = self.freeSpace; + if (!freeSpace) return totalWritten; + + if (position == buffer.length) { + position = 0; + } + + // position < tail + SInt32 written = MIN(freeSpace, length); + memcpy(data + position, input + offset, written); + position += written; + totalWritten += written; + + return totalWritten; +} + + +- (SInt32)flushToOutputStream:(NSOutputStream*)stream { + SInt32 totalWritten = 0; + const uint8_t *data = buffer.bytes; + + if (tail > position) { + SInt32 written = (SInt32)[stream write:data + tail maxLength:buffer.length - tail]; + if (written <= 0) return totalWritten; + totalWritten += written; + tail += written; + if (tail == buffer.length) { + tail = 0; + } + } + + if (tail < position) { + SInt32 written = (SInt32)[stream write:data + tail maxLength:position - tail]; + if (written <= 0) return totalWritten; + totalWritten += written; + tail += written; + } + + if (tail == position) { + tail = position = 0; + } + + if (position == buffer.length && tail > 0) { + position = 0; + } + + if (tail == buffer.length) { + tail = 0; + } + + return totalWritten; +} + +@end diff --git a/ios/Pods/ProtocolBuffers/src/runtime/Classes/TextFormat.h b/ios/Pods/ProtocolBuffers/src/runtime/Classes/TextFormat.h new file mode 100644 index 000000000..74f6a1168 --- /dev/null +++ b/ios/Pods/ProtocolBuffers/src/runtime/Classes/TextFormat.h @@ -0,0 +1,29 @@ +// Protocol Buffers for Objective C +// +// Copyright 2010 Booyah Inc. +// Copyright 2008 Cyrus Najmabadi +// +// 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. + +@interface PBTextFormat : NSObject { + +} + ++ (SInt32) parseInt32:(NSString*) text; ++ (SInt32) parseUInt32:(NSString*) text; ++ (SInt64) parseInt64:(NSString*) text; ++ (SInt64) parseUInt64:(NSString*) text; + ++ (NSData*) unescapeBytes:(NSString*) input; + +@end diff --git a/ios/Pods/ProtocolBuffers/src/runtime/Classes/TextFormat.m b/ios/Pods/ProtocolBuffers/src/runtime/Classes/TextFormat.m new file mode 100644 index 000000000..4b7ff0088 --- /dev/null +++ b/ios/Pods/ProtocolBuffers/src/runtime/Classes/TextFormat.m @@ -0,0 +1,236 @@ +// Protocol Buffers for Objective C +// +// Copyright 2010 Booyah Inc. +// Copyright 2008 Cyrus Najmabadi +// +// 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. + +#import "TextFormat.h" + +#import "Utilities.h" + +@implementation PBTextFormat + + +BOOL allZeroes(NSString* string) { + for (int i = 0; i < string.length; i++) { + if ([string characterAtIndex:i] != '0') { + return NO; + } + } + + return YES; +} + + +/** Is this an octal digit? */ +BOOL isOctal(unichar c) { + return '0' <= c && c <= '7'; +} + + +/** Is this an octal digit? */ +BOOL isDecimal(unichar c) { + return '0' <= c && c <= '9'; +} + +/** Is this a hex digit? */ +BOOL isHex(unichar c) { + return + isDecimal(c) || + ('a' <= c && c <= 'f') || + ('A' <= c && c <= 'F'); +} + + ++ (SInt64) parseInteger:(NSString*) text + isSigned:(BOOL) isSigned + isLong:(BOOL) isLong { + if (text.length == 0) { + @throw [NSException exceptionWithName:@"NumberFormat" reason:@"Number was blank" userInfo:nil]; + } + + if (isblank([text characterAtIndex:0])) { + @throw [NSException exceptionWithName:@"NumberFormat" reason:@"Invalid character" userInfo:nil]; + } + + if ([text hasPrefix:@"-"]) { + if (!isSigned) { + @throw [NSException exceptionWithName:@"NumberFormat" reason:@"Number must be positive" userInfo:nil]; + } + } + + // now call into the appropriate conversion utilities. + SInt64 result; + const char* in_string = text.UTF8String; + char* out_string = NULL; + errno = 0; + if (isLong) { + if (isSigned) { + result = strtoll(in_string, &out_string, 0); + } else { + result = convertUInt64ToInt64(strtoull(in_string, &out_string, 0)); + } + } else { + if (isSigned) { + result = strtol(in_string, &out_string, 0); + } else { + result = convertUInt32ToInt32((SInt32)strtoul(in_string, &out_string, 0)); + } + } + + // from the man pages: + // (Thus, i* tr is not `\0' but **endptr is `\0' on return, the entire + // string was valid.) + if (*in_string == 0 || *out_string != 0) { + @throw [NSException exceptionWithName:@"NumberFormat" reason:@"IllegalNumber" userInfo:nil]; + } + + if (errno == ERANGE) { + @throw [NSException exceptionWithName:@"NumberFormat" reason:@"Number out of range" userInfo:nil]; + } + + return result; +} + + +/** + * Parse a 32-bit signed integer from the text. This function recognizes + * the prefixes "0x" and "0" to signify hexidecimal and octal numbers, + * respectively. + */ ++ (SInt32) parseInt32:(NSString*) text { + return (SInt32)[self parseInteger:text isSigned:YES isLong:NO]; +} + + +/** + * Parse a 32-bit unsigned integer from the text. This function recognizes + * the prefixes "0x" and "0" to signify hexidecimal and octal numbers, + * respectively. The result is coerced to a (signed) {@code int} when returned. + */ ++ (SInt32) parseUInt32:(NSString*) text { + return (SInt32)[self parseInteger:text isSigned:NO isLong:NO]; +} + + +/** + * Parse a 64-bit signed integer from the text. This function recognizes + * the prefixes "0x" and "0" to signify hexidecimal and octal numbers, + * respectively. + */ ++ (SInt64) parseInt64:(NSString*) text { + return [self parseInteger:text isSigned:YES isLong:YES]; +} + + +/** + * Parse a 64-bit unsigned integer from the text. This function recognizes + * the prefixes "0x" and "0" to signify hexidecimal and octal numbers, + * respectively. The result is coerced to a (signed) {@code SInt32} when + * returned. + */ ++ (SInt64) parseUInt64:(NSString*) text { + return [self parseInteger:text isSigned:NO isLong:YES]; +} + +/** + * Interpret a character as a digit (in any base up to 36) and return the + * numeric value. This is like {@code Character.digit()} but we don't accept + * non-ASCII digits. + */ +SInt32 digitValue(unichar c) { + if ('0' <= c && c <= '9') { + return c - '0'; + } else if ('a' <= c && c <= 'z') { + return c - 'a' + 10; + } else { + return c - 'A' + 10; + } +} + + +/** + * Un-escape a byte sequence as escaped using + * {@link #escapeBytes(ByteString)}. Two-digit hex escapes (starting with + * "\x") are also recognized. + */ ++ (NSData*) unescapeBytes:(NSString*) input { + NSMutableData* result = [NSMutableData dataWithLength:input.length]; + + SInt32 pos = 0; + for (SInt32 i = 0; i < input.length; i++) { + unichar c = [input characterAtIndex:i]; + if (c == '\\') { + if (i + 1 < input.length) { + ++i; + c = [input characterAtIndex:i]; + if (isOctal(c)) { + // Octal escape. + SInt32 code = digitValue(c); + if (i + 1 < input.length && isOctal([input characterAtIndex:(i + 1)])) { + ++i; + code = code * 8 + digitValue([input characterAtIndex:i]); + } + if (i + 1 < input.length && isOctal([input characterAtIndex:(i + 1)])) { + ++i; + code = code * 8 + digitValue([input characterAtIndex:i]); + } + ((int8_t*)result.mutableBytes)[pos++] = (int8_t)code; + } else { + switch (c) { + case 'a' : ((int8_t*)result.mutableBytes)[pos++] = 0x07; break; + case 'b' : ((int8_t*)result.mutableBytes)[pos++] = '\b'; break; + case 'f' : ((int8_t*)result.mutableBytes)[pos++] = '\f'; break; + case 'n' : ((int8_t*)result.mutableBytes)[pos++] = '\n'; break; + case 'r' : ((int8_t*)result.mutableBytes)[pos++] = '\r'; break; + case 't' : ((int8_t*)result.mutableBytes)[pos++] = '\t'; break; + case 'v' : ((int8_t*)result.mutableBytes)[pos++] = 0x0b; break; + case '\\': ((int8_t*)result.mutableBytes)[pos++] = '\\'; break; + case '\'': ((int8_t*)result.mutableBytes)[pos++] = '\''; break; + case '"' : ((int8_t*)result.mutableBytes)[pos++] = '\"'; break; + + case 'x': // hex escape + { + SInt32 code = 0; + if (i + 1 < input.length && isHex([input characterAtIndex:(i + 1)])) { + ++i; + code = digitValue([input characterAtIndex:i]); + } else { + @throw [NSException exceptionWithName:@"InvalidEscape" reason:@"Invalid escape sequence: '\\x' with no digits" userInfo:nil]; + } + if (i + 1 < input.length && isHex([input characterAtIndex:(i + 1)])) { + ++i; + code = code * 16 + digitValue([input characterAtIndex:i]); + } + ((int8_t*)result.mutableBytes)[pos++] = (int8_t)code; + break; + } + + default: + @throw [NSException exceptionWithName:@"InvalidEscape" reason:@"Invalid escape sequence" userInfo:nil]; + } + } + } else { + @throw [NSException exceptionWithName:@"InvalidEscape" reason:@"Invalid escape sequence: '\\' at end of string" userInfo:nil]; + } + } else { + ((int8_t*)result.mutableBytes)[pos++] = (int8_t)c; + } + } + + [result setLength:pos]; + return result; +} + +@end diff --git a/ios/Pods/ProtocolBuffers/src/runtime/Classes/UnknownFieldSet.h b/ios/Pods/ProtocolBuffers/src/runtime/Classes/UnknownFieldSet.h new file mode 100644 index 000000000..922d107a1 --- /dev/null +++ b/ios/Pods/ProtocolBuffers/src/runtime/Classes/UnknownFieldSet.h @@ -0,0 +1,50 @@ +// Protocol Buffers for Objective C +// +// Copyright 2010 Booyah Inc. +// Copyright 2008 Cyrus Najmabadi +// +// 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. + +@class PBCodedOutputStream; +@class PBField; +@class PBUnknownFieldSetBuilder; + +@interface PBUnknownFieldSet : NSObject { +@private + NSDictionary* fields; +} + +@property (readonly, strong) NSDictionary* fields; + ++ (PBUnknownFieldSet*) defaultInstance; + ++ (PBUnknownFieldSet*) setWithFields:(NSMutableDictionary*) fields; ++ (PBUnknownFieldSet*) parseFromData:(NSData*) data; + ++ (PBUnknownFieldSetBuilder*) builder; ++ (PBUnknownFieldSetBuilder*) builderWithUnknownFields:(PBUnknownFieldSet*) other; + +- (void) writeAsMessageSetTo:(PBCodedOutputStream*) output; +- (void) writeToCodedOutputStream:(PBCodedOutputStream*) output; +- (NSData*) data; + +- (SInt32) serializedSize; +- (SInt32) serializedSizeAsMessageSet; + +- (BOOL) hasField:(SInt32) number; +- (PBField*) getField:(SInt32) number; + +- (void) writeDescriptionTo:(NSMutableString*) output + withIndent:(NSString*) indent; + +@end diff --git a/ios/Pods/ProtocolBuffers/src/runtime/Classes/UnknownFieldSet.m b/ios/Pods/ProtocolBuffers/src/runtime/Classes/UnknownFieldSet.m new file mode 100644 index 000000000..4f3a00dc7 --- /dev/null +++ b/ios/Pods/ProtocolBuffers/src/runtime/Classes/UnknownFieldSet.m @@ -0,0 +1,172 @@ +// Protocol Buffers for Objective C +// +// Copyright 2010 Booyah Inc. +// Copyright 2008 Cyrus Najmabadi +// +// 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. + +#import "UnknownFieldSet.h" + +#import "CodedInputStream.h" +#import "CodedOutputStream.h" +#import "Field.h" +#import "UnknownFieldSetBuilder.h" + +@interface PBUnknownFieldSet() +@property (strong) NSDictionary* fields; +@end + + +@implementation PBUnknownFieldSet + +static PBUnknownFieldSet* defaultInstance = nil; + ++ (void) initialize { + if (self == [PBUnknownFieldSet class]) { + defaultInstance = [PBUnknownFieldSet setWithFields:[NSMutableDictionary dictionary]]; + } +} + + +@synthesize fields; + + + + ++ (PBUnknownFieldSet*) defaultInstance { + return defaultInstance; +} + + +- (id) initWithFields:(NSMutableDictionary*) fields_ { + if ((self = [super init])) { + self.fields = fields_; + } + + return self; +} + + ++ (PBUnknownFieldSet*) setWithFields:(NSMutableDictionary*) fields { + return [[PBUnknownFieldSet alloc] initWithFields:fields]; +} + + +- (BOOL) hasField:(SInt32) number { + return [fields objectForKey:@(number)] != nil; +} + + +- (PBField*) getField:(SInt32) number { + PBField* result = [fields objectForKey:@(number)]; + return (result == nil) ? [PBField defaultInstance] : result; +} + + +- (void) writeToCodedOutputStream:(PBCodedOutputStream*) output { + NSArray* sortedKeys = [fields.allKeys sortedArrayUsingSelector:@selector(compare:)]; + for (NSNumber* number in sortedKeys) { + PBField* value = [fields objectForKey:number]; + [value writeTo:(SInt32)number.integerValue output:output]; + } +} + + +- (void) writeToOutputStream:(NSOutputStream*) output { + PBCodedOutputStream* codedOutput = [PBCodedOutputStream streamWithOutputStream:output]; + [self writeToCodedOutputStream:codedOutput]; + [codedOutput flush]; +} + + +- (void) writeDescriptionTo:(NSMutableString*) output + withIndent:(NSString *)indent { + NSArray* sortedKeys = [fields.allKeys sortedArrayUsingSelector:@selector(compare:)]; + for (NSNumber* number in sortedKeys) { + PBField* value = [fields objectForKey:number]; + [value writeDescriptionFor:(SInt32)number.integerValue to:output withIndent:indent]; + } +} + + ++ (PBUnknownFieldSet*) parseFromCodedInputStream:(PBCodedInputStream*) input { + return [[[PBUnknownFieldSet builder] mergeFromCodedInputStream:input] build]; +} + + ++ (PBUnknownFieldSet*) parseFromData:(NSData*) data { + return [[[PBUnknownFieldSet builder] mergeFromData:data] build]; +} + + ++ (PBUnknownFieldSet*) parseFromInputStream:(NSInputStream*) input { + return [[[PBUnknownFieldSet builder] mergeFromInputStream:input] build]; +} + + ++ (PBUnknownFieldSetBuilder*) builder { + return [[PBUnknownFieldSetBuilder alloc] init]; +} + + ++ (PBUnknownFieldSetBuilder*) builderWithUnknownFields:(PBUnknownFieldSet*) copyFrom { + return [[PBUnknownFieldSet builder] mergeUnknownFields:copyFrom]; +} + + +/** Get the number of bytes required to encode this set. */ +- (SInt32) serializedSize { + SInt32 result = 0; + for (NSNumber* number in fields) { + result += [[fields objectForKey:number] getSerializedSize:(SInt32)number.integerValue]; + } + return result; +} + +/** + * Serializes the set and writes it to {@code output} using + * {@code MessageSet} wire format. + */ +- (void) writeAsMessageSetTo:(PBCodedOutputStream*) output { + for (NSNumber* number in fields) { + [[fields objectForKey:number] writeAsMessageSetExtensionTo:(SInt32)number.integerValue output:output]; + } +} + + +/** + * Get the number of bytes required to encode this set using + * {@code MessageSet} wire format. + */ +- (SInt32) serializedSizeAsMessageSet { + SInt32 result = 0; + for (NSNumber* number in fields) { + result += [[fields objectForKey:number] getSerializedSizeAsMessageSetExtension:(SInt32)number.integerValue]; + } + return result; +} + + +/** + * Serializes the message to a {@code ByteString} and returns it. This is + * just a trivial wrapper around {@link #writeTo(PBCodedOutputStream)}. + */ +- (NSData*) data { + NSMutableData* data = [NSMutableData dataWithLength:self.serializedSize]; + PBCodedOutputStream* output = [PBCodedOutputStream streamWithData:data]; + + [self writeToCodedOutputStream:output]; + return data; +} + +@end diff --git a/ios/Pods/ProtocolBuffers/src/runtime/Classes/UnknownFieldSetBuilder.h b/ios/Pods/ProtocolBuffers/src/runtime/Classes/UnknownFieldSetBuilder.h new file mode 100644 index 000000000..3b0b08058 --- /dev/null +++ b/ios/Pods/ProtocolBuffers/src/runtime/Classes/UnknownFieldSetBuilder.h @@ -0,0 +1,53 @@ +// Protocol Buffers for Objective C +// +// Copyright 2010 Booyah Inc. +// Copyright 2008 Cyrus Najmabadi +// +// 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. + +#import "MessageBuilder.h" + +@class PBField; +@class PBMutableField; + +@interface PBUnknownFieldSetBuilder : NSObject { +@private + NSMutableDictionary* fields; + + // Optimization: We keep around a builder for the last field that was + // modified so that we can efficiently add to it multiple times in a + // row (important when parsing an unknown repeated field). + SInt32 lastFieldNumber; + + PBMutableField* lastField; +} + ++ (PBUnknownFieldSetBuilder*) createBuilder:(PBUnknownFieldSet*) unknownFields; + +- (PBUnknownFieldSet*) build; +- (PBUnknownFieldSetBuilder*) mergeUnknownFields:(PBUnknownFieldSet*) other; + +- (PBUnknownFieldSetBuilder*) mergeFromCodedInputStream:(PBCodedInputStream*) input; +- (PBUnknownFieldSetBuilder*) mergeFromData:(NSData*) data; +- (PBUnknownFieldSetBuilder*) mergeFromInputStream:(NSInputStream*) input; + +- (PBUnknownFieldSetBuilder*) mergeVarintField:(SInt32) number value:(SInt32) value; + +- (BOOL) mergeFieldFrom:(SInt32) tag input:(PBCodedInputStream*) input; + +- (PBUnknownFieldSetBuilder*) addField:(PBField*) field forNumber:(SInt32) number; + +- (PBUnknownFieldSetBuilder*) clear; +- (PBUnknownFieldSetBuilder*) mergeField:(PBField*) field forNumber:(SInt32) number; + +@end diff --git a/ios/Pods/ProtocolBuffers/src/runtime/Classes/UnknownFieldSetBuilder.m b/ios/Pods/ProtocolBuffers/src/runtime/Classes/UnknownFieldSetBuilder.m new file mode 100644 index 000000000..0d30c77a0 --- /dev/null +++ b/ios/Pods/ProtocolBuffers/src/runtime/Classes/UnknownFieldSetBuilder.m @@ -0,0 +1,270 @@ +// Protocol Buffers for Objective C +// +// Copyright 2010 Booyah Inc. +// Copyright 2008 Cyrus Najmabadi +// +// 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. + +#import "UnknownFieldSetBuilder.h" + +#import "CodedInputStream.h" +#import "Field.h" +#import "MutableField.h" +#import "UnknownFieldSet.h" +#import "WireFormat.h" + +@interface PBUnknownFieldSetBuilder () +@property (strong) NSMutableDictionary* fields; +@property SInt32 lastFieldNumber; +@property (strong) PBMutableField* lastField; +@end + + +@implementation PBUnknownFieldSetBuilder + +@synthesize fields; +@synthesize lastFieldNumber; +@synthesize lastField; + + +- (id) init { + if ((self = [super init])) { + self.fields = [NSMutableDictionary dictionary]; + } + return self; +} + + ++ (PBUnknownFieldSetBuilder*) createBuilder:(PBUnknownFieldSet*) unknownFields { + PBUnknownFieldSetBuilder* builder = [[PBUnknownFieldSetBuilder alloc] init]; + [builder mergeUnknownFields:unknownFields]; + return builder; +} + + +/** + * Add a field to the {@code PBUnknownFieldSet}. If a field with the same + * number already exists, it is removed. + */ +- (PBUnknownFieldSetBuilder*) addField:(PBField*) field forNumber:(SInt32) number { + if (number == 0) { + @throw [NSException exceptionWithName:@"IllegalArgument" reason:@"" userInfo:nil]; + } + if (lastField != nil && lastFieldNumber == number) { + // Discard this. + self.lastField = nil; + lastFieldNumber = 0; + } + [fields setObject:field forKey:@(number)]; + return self; +} + + +/** + * Get a field builder for the given field number which includes any + * values that already exist. + */ +- (PBMutableField*) getFieldBuilder:(SInt32) number { + if (lastField != nil) { + if (number == lastFieldNumber) { + return lastField; + } + // Note: addField() will reset lastField and lastFieldNumber. + [self addField:lastField forNumber:lastFieldNumber]; + } + if (number == 0) { + return nil; + } else { + PBField* existing = [fields objectForKey:@(number)]; + lastFieldNumber = number; + self.lastField = [PBMutableField field]; + if (existing != nil) { + [lastField mergeFromField:existing]; + } + return lastField; + } +} + + +- (PBUnknownFieldSet*) build { + [self getFieldBuilder:0]; // Force lastField to be built. + PBUnknownFieldSet* result; + if (fields.count == 0) { + result = [PBUnknownFieldSet defaultInstance]; + } else { + result = [PBUnknownFieldSet setWithFields:fields]; + } + self.fields = nil; + return result; +} + +- (PBUnknownFieldSet*) buildPartial { + @throw [NSException exceptionWithName:@"UnsupportedMethod" reason:@"" userInfo:nil]; +} + +- (PBUnknownFieldSet*) clone { + @throw [NSException exceptionWithName:@"UnsupportedMethod" reason:@"" userInfo:nil]; +} + +- (BOOL) isInitialized { + return YES; +} + +- (PBUnknownFieldSet*) defaultInstance { + @throw [NSException exceptionWithName:@"UnsupportedMethod" reason:@"" userInfo:nil]; +} + +- (PBUnknownFieldSet*) unknownFields { + return [self build]; +} + +- (id) setUnknownFields:(PBUnknownFieldSet*) unknownFields { + @throw [NSException exceptionWithName:@"UnsupportedMethod" reason:@"" userInfo:nil]; +} + +/** Check if the given field number is present in the set. */ +- (BOOL) hasField:(SInt32) number { + if (number == 0) { + @throw [NSException exceptionWithName:@"IllegalArgument" reason:@"" userInfo:nil]; + } + + return number == lastFieldNumber || ([fields objectForKey:@(number)] != nil); +} + + +/** + * Add a field to the {@code PBUnknownFieldSet}. If a field with the same + * number already exists, the two are merged. + */ +- (PBUnknownFieldSetBuilder*) mergeField:(PBField*) field forNumber:(SInt32) number { + if (number == 0) { + @throw [NSException exceptionWithName:@"IllegalArgument" reason:@"" userInfo:nil]; + } + if ([self hasField:number]) { + [[self getFieldBuilder:number] mergeFromField:field]; + } else { + // Optimization: We could call getFieldBuilder(number).mergeFrom(field) + // in this case, but that would create a copy of the PBField object. + // We'd rather reuse the one passed to us, so call addField() instead. + [self addField:field forNumber:number]; + } + + return self; +} + + +- (PBUnknownFieldSetBuilder*) mergeUnknownFields:(PBUnknownFieldSet*) other { + if (other != [PBUnknownFieldSet defaultInstance]) { + for (NSNumber* number in other.fields) { + PBField* field = [other.fields objectForKey:number]; + [self mergeField:field forNumber:(SInt32)[number integerValue]]; + } + } + return self; +} + + +- (PBUnknownFieldSetBuilder*) mergeFromData:(NSData*) data { + PBCodedInputStream* input = [PBCodedInputStream streamWithData:data]; + [self mergeFromCodedInputStream:input]; + [input checkLastTagWas:0]; + return self; +} + + +- (PBUnknownFieldSetBuilder*) mergeFromData:(NSData*) data extensionRegistry:(PBExtensionRegistry*) extensionRegistry { + PBCodedInputStream* input = [PBCodedInputStream streamWithData:data]; + [self mergeFromCodedInputStream:input extensionRegistry:extensionRegistry]; + [input checkLastTagWas:0]; + return self; +} + + +- (PBUnknownFieldSetBuilder*) mergeFromInputStream:(NSInputStream*) input { + @throw [NSException exceptionWithName:@"UnsupportedMethod" reason:@"" userInfo:nil]; +} + +- (PBUnknownFieldSetBuilder*) mergeFromInputStream:(NSInputStream*) input extensionRegistry:(PBExtensionRegistry*) extensionRegistry { + @throw [NSException exceptionWithName:@"UnsupportedMethod" reason:@"" userInfo:nil]; +} + +- (PBUnknownFieldSetBuilder*) mergeVarintField:(SInt32) number value:(SInt32) value { + if (number == 0) { + @throw [NSException exceptionWithName:@"IllegalArgument" reason:@"Zero is not a valid field number." userInfo:nil]; + } + + [[self getFieldBuilder:number] addVarint:value]; + return self; +} + + +/** + * Parse a single field from {@code input} and merge it into this set. + * @param tag The field's tag number, which was already parsed. + * @return {@code NO} if the tag is an engroup tag. + */ +- (BOOL) mergeFieldFrom:(SInt32) tag input:(PBCodedInputStream*) input { + SInt32 number = PBWireFormatGetTagFieldNumber(tag); + switch (PBWireFormatGetTagWireType(tag)) { + case PBWireFormatVarint: + [[self getFieldBuilder:number] addVarint:[input readInt64]]; + return YES; + case PBWireFormatFixed64: + [[self getFieldBuilder:number] addFixed64:[input readFixed64]]; + return YES; + case PBWireFormatLengthDelimited: + [[self getFieldBuilder:number] addLengthDelimited:[input readData]]; + return YES; + case PBWireFormatStartGroup: { + PBUnknownFieldSetBuilder* subBuilder = [PBUnknownFieldSet builder]; + [input readUnknownGroup:number builder:subBuilder]; + [[self getFieldBuilder:number] addGroup:[subBuilder build]]; + return YES; + } + case PBWireFormatEndGroup: + return NO; + case PBWireFormatFixed32: + [[self getFieldBuilder:number] addFixed32:[input readFixed32]]; + return YES; + default: + @throw [NSException exceptionWithName:@"InvalidProtocolBuffer" reason:@"" userInfo:nil]; + } +} + + +/** + * Parse an entire message from {@code input} and merge its fields into + * this set. + */ +- (PBUnknownFieldSetBuilder*) mergeFromCodedInputStream:(PBCodedInputStream*) input { + while (YES) { + SInt32 tag = [input readTag]; + if (tag == 0 || ![self mergeFieldFrom:tag input:input]) { + break; + } + } + return self; +} + +- (PBUnknownFieldSetBuilder*) mergeFromCodedInputStream:(PBCodedInputStream*) input extensionRegistry:(PBExtensionRegistry*) extensionRegistry { + @throw [NSException exceptionWithName:@"UnsupportedMethod" reason:@"" userInfo:nil]; +} + +- (PBUnknownFieldSetBuilder*) clear { + self.fields = [NSMutableDictionary dictionary]; + self.lastFieldNumber = 0; + self.lastField = nil; + return self; +} + +@end diff --git a/ios/Pods/ProtocolBuffers/src/runtime/Classes/Utilities.h b/ios/Pods/ProtocolBuffers/src/runtime/Classes/Utilities.h new file mode 100644 index 000000000..96f432a83 --- /dev/null +++ b/ios/Pods/ProtocolBuffers/src/runtime/Classes/Utilities.h @@ -0,0 +1,335 @@ +// Protocol Buffers for Objective C +// +// Copyright 2010 Booyah Inc. +// Copyright 2008 Cyrus Najmabadi +// +// 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. + +#import "Message.h" + +SInt64 convertFloat64ToInt64(Float64 f); +SInt32 convertFloat32ToInt32(Float32 f); +Float64 convertInt64ToFloat64(SInt64 f); +Float32 convertInt32ToFloat32(SInt32 f); + +UInt64 convertInt64ToUInt64(SInt64 i); +SInt64 convertUInt64ToInt64(UInt64 u); +UInt32 convertInt32ToUInt32(SInt32 i); +SInt32 convertUInt32ToInt32(UInt32 u); + +SInt32 logicalRightShift32(SInt32 value, SInt32 spaces); +SInt64 logicalRightShift64(SInt64 value, SInt32 spaces); + + +/** + * Decode a ZigZag-encoded 32-bit value. ZigZag encodes signed integers + * into values that can be efficiently encoded with varint. (Otherwise, + * negative values must be sign-extended to 64 bits to be varint encoded, + * thus always taking 10 bytes on the wire.) + * + * @param n An unsigned 32-bit integer, stored in a signed int. + * @return A signed 32-bit integer. + */ +SInt32 decodeZigZag32(SInt32 n); + +/** + * Decode a ZigZag-encoded 64-bit value. ZigZag encodes signed integers + * into values that can be efficiently encoded with varint. (Otherwise, + * negative values must be sign-extended to 64 bits to be varint encoded, + * thus always taking 10 bytes on the wire.) + * + * @param n An unsigned 64-bit integer, stored in a signed int. + * @return A signed 64-bit integer. + */ +SInt64 decodeZigZag64(SInt64 n); + + +/** + * Encode a ZigZag-encoded 32-bit value. ZigZag encodes signed integers + * into values that can be efficiently encoded with varint. (Otherwise, + * negative values must be sign-extended to 64 bits to be varint encoded, + * thus always taking 10 bytes on the wire.) + * + * @param n A signed 32-bit integer. + * @return An unsigned 32-bit integer, stored in a signed int. + */ +SInt32 encodeZigZag32(SInt32 n); + +/** + * Encode a ZigZag-encoded 64-bit value. ZigZag encodes signed integers + * into values that can be efficiently encoded with varint. (Otherwise, + * negative values must be sign-extended to 64 bits to be varint encoded, + * thus always taking 10 bytes on the wire.) + * + * @param n A signed 64-bit integer. + * @return An unsigned 64-bit integer, stored in a signed int. + */ +SInt64 encodeZigZag64(SInt64 n); + +/** + * Compute the number of bytes that would be needed to encode a + * {@code double} field, including tag. + */ +SInt32 computeDoubleSize(SInt32 fieldNumber, Float64 value); + +/** + * Compute the number of bytes that would be needed to encode a + * {@code float} field, including tag. + */ +SInt32 computeFloatSize(SInt32 fieldNumber, Float32 value); + +/** + * Compute the number of bytes that would be needed to encode a + * {@code uint64} field, including tag. + */ +SInt32 computeUInt64Size(SInt32 fieldNumber, SInt64 value); + +/** + * Compute the number of bytes that would be needed to encode an + * {@code int64} field, including tag. + */ +SInt32 computeInt64Size(SInt32 fieldNumber, SInt64 value); + +/** + * Compute the number of bytes that would be needed to encode an + * {@code int32} field, including tag. + */ +SInt32 computeInt32Size(SInt32 fieldNumber, SInt32 value); + +/** + * Compute the number of bytes that would be needed to encode a + * {@code fixed64} field, including tag. + */ +SInt32 computeFixed64Size(SInt32 fieldNumber, SInt64 value); + +/** + * Compute the number of bytes that would be needed to encode a + * {@code fixed32} field, including tag. + */ +SInt32 computeFixed32Size(SInt32 fieldNumber, SInt32 value); + +/** + * Compute the number of bytes that would be needed to encode a + * {@code bool} field, including tag. + */ +SInt32 computeBoolSize(SInt32 fieldNumber, BOOL value); + +/** + * Compute the number of bytes that would be needed to encode a + * {@code string} field, including tag. + */ +SInt32 computeStringSize(SInt32 fieldNumber, const NSString* value); + +/** + * Compute the number of bytes that would be needed to encode a + * {@code group} field, including tag. + */ +SInt32 computeGroupSize(SInt32 fieldNumber, const id value); + +/** + * Compute the number of bytes that would be needed to encode a + * {@code group} field represented by an {@code PBUnknownFieldSet}, including + * tag. + */ +SInt32 computeUnknownGroupSize(SInt32 fieldNumber, const PBUnknownFieldSet* value); + +/** + * Compute the number of bytes that would be needed to encode an + * embedded message field, including tag. + */ +SInt32 computeMessageSize(SInt32 fieldNumber, const id value); + +/** + * Compute the number of bytes that would be needed to encode a + * {@code bytes} field, including tag. + */ +SInt32 computeDataSize(SInt32 fieldNumber, const NSData* value); + +/** + * Compute the number of bytes that would be needed to encode a + * {@code uint32} field, including tag. + */ +SInt32 computeUInt32Size(SInt32 fieldNumber, SInt32 value); + +/** + * Compute the number of bytes that would be needed to encode an + * {@code sfixed32} field, including tag. + */ +SInt32 computeSFixed32Size(SInt32 fieldNumber, SInt32 value); + +/** + * Compute the number of bytes that would be needed to encode an + * {@code sfixed64} field, including tag. + */ +SInt32 computeSFixed64Size(SInt32 fieldNumber, SInt64 value); + +/** + * Compute the number of bytes that would be needed to encode an + * {@code sint32} field, including tag. + */ +SInt32 computeSInt32Size(SInt32 fieldNumber, SInt32 value); + +/** + * Compute the number of bytes that would be needed to encode an + * {@code sint64} field, including tag. + */ +SInt32 computeSInt64Size(SInt32 fieldNumber, SInt64 value); + +/** Compute the number of bytes that would be needed to encode a tag. */ +SInt32 computeTagSize(SInt32 fieldNumber); + +/** + * Compute the number of bytes that would be needed to encode a + * {@code double} field, including tag. + */ +SInt32 computeDoubleSizeNoTag(Float64 value); + +/** + * Compute the number of bytes that would be needed to encode a + * {@code float} field, including tag. + */ +SInt32 computeFloatSizeNoTag(Float32 value); + +/** + * Compute the number of bytes that would be needed to encode a + * {@code uint64} field, including tag. + */ +SInt32 computeUInt64SizeNoTag(SInt64 value); + +/** + * Compute the number of bytes that would be needed to encode an + * {@code int64} field, including tag. + */ +SInt32 computeInt64SizeNoTag(SInt64 value); +/** + * Compute the number of bytes that would be needed to encode an + * {@code int32} field, including tag. + */ +SInt32 computeInt32SizeNoTag(SInt32 value); + +/** + * Compute the number of bytes that would be needed to encode a + * {@code fixed64} field, including tag. + */ +SInt32 computeFixed64SizeNoTag(SInt64 value); + +/** + * Compute the number of bytes that would be needed to encode a + * {@code fixed32} field, including tag. + */ +SInt32 computeFixed32SizeNoTag(SInt32 value); + +/** + * Compute the number of bytes that would be needed to encode a + * {@code bool} field, including tag. + */ +SInt32 computeBoolSizeNoTag(BOOL value); + +/** + * Compute the number of bytes that would be needed to encode a + * {@code string} field, including tag. + */ +SInt32 computeStringSizeNoTag(const NSString* value); + +/** + * Compute the number of bytes that would be needed to encode a + * {@code group} field, including tag. + */ +SInt32 computeGroupSizeNoTag(const id value); + +/** + * Compute the number of bytes that would be needed to encode a + * {@code group} field represented by an {@code PBUnknownFieldSet}, including + * tag. + */ +SInt32 computeUnknownGroupSizeNoTag(const PBUnknownFieldSet* value); + +/** + * Compute the number of bytes that would be needed to encode an + * embedded message field, including tag. + */ +SInt32 computeMessageSizeNoTag(const id value); + +/** + * Compute the number of bytes that would be needed to encode a + * {@code bytes} field, including tag. + */ +SInt32 computeDataSizeNoTag(const NSData* value); + +/** + * Compute the number of bytes that would be needed to encode a + * {@code uint32} field, including tag. + */ +SInt32 computeUInt32SizeNoTag(SInt32 value); + +/** + * Compute the number of bytes that would be needed to encode an + * enum field, including tag. Caller is responsible for converting the + * enum value to its numeric value. + */ +SInt32 computeEnumSizeNoTag(SInt32 value); + +/** + * Compute the number of bytes that would be needed to encode an + * {@code sfixed32} field, including tag. + */ +SInt32 computeSFixed32SizeNoTag(SInt32 value); + +/** + * Compute the number of bytes that would be needed to encode an + * {@code sfixed64} field, including tag. + */ +SInt32 computeSFixed64SizeNoTag(SInt64 value); + +/** + * Compute the number of bytes that would be needed to encode an + * {@code sint32} field, including tag. + */ +SInt32 computeSInt32SizeNoTag(SInt32 value); + +/** + * Compute the number of bytes that would be needed to encode an + * {@code sint64} field, including tag. + */ +SInt32 computeSInt64SizeNoTag(SInt64 value); + +/** + * Compute the number of bytes that would be needed to encode a varint. + * {@code value} is treated as unsigned, so it won't be sign-extended if + * negative. + */ +SInt32 computeRawVarint32Size(SInt32 value); + +/** Compute the number of bytes that would be needed to encode a varint. */ +SInt32 computeRawVarint64Size(SInt64 value); + +/** + * Compute the number of bytes that would be needed to encode a + * MessageSet extension to the stream. For historical reasons, + * the wire format differs from normal fields. + */ +SInt32 computeMessageSetExtensionSize(SInt32 fieldNumber, const id value); + +/** + * Compute the number of bytes that would be needed to encode an + * unparsed MessageSet extension field to the stream. For + * historical reasons, the wire format differs from normal fields. + */ +SInt32 computeRawMessageSetExtensionSize(SInt32 fieldNumber, const NSData* value); + +/** + * Compute the number of bytes that would be needed to encode an + * enum field, including tag. Caller is responsible for converting the + * enum value to its numeric value. + */ +SInt32 computeEnumSize(SInt32 fieldNumber, SInt32 value); diff --git a/ios/Pods/ProtocolBuffers/src/runtime/Classes/Utilities.m b/ios/Pods/ProtocolBuffers/src/runtime/Classes/Utilities.m new file mode 100644 index 000000000..a8f951fc9 --- /dev/null +++ b/ios/Pods/ProtocolBuffers/src/runtime/Classes/Utilities.m @@ -0,0 +1,351 @@ +// Protocol Buffers for Objective C +// +// Copyright 2010 Booyah Inc. +// Copyright 2008 Cyrus Najmabadi +// +// 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. + +#import "Utilities.h" + +#import "UnknownFieldSet.h" +#import "WireFormat.h" + +const SInt32 LITTLE_ENDIAN_32_SIZE = 4; +const SInt32 LITTLE_ENDIAN_64_SIZE = 8; + + +SInt64 convertFloat64ToInt64(Float64 v) { + union { Float64 f; SInt64 i; } u; + u.f = v; + return u.i; +} + + +SInt32 convertFloat32ToInt32(Float32 v) { + union { Float32 f; SInt32 i; } u; + u.f = v; + return u.i; +} + + +Float64 convertInt64ToFloat64(SInt64 v) { + union { Float64 f; SInt64 i; } u; + u.i = v; + return u.f; +} + + +Float32 convertInt32ToFloat32(SInt32 v) { + union { Float32 f; SInt32 i; } u; + u.i = v; + return u.f; +} + + +UInt64 convertInt64ToUInt64(SInt64 v) { + union { SInt64 i; UInt64 u; } u; + u.i = v; + return u.u; +} + + +SInt64 convertUInt64ToInt64(UInt64 v) { + union { SInt64 i; UInt64 u; } u; + u.u = v; + return u.i; +} + +UInt32 convertInt32ToUInt32(SInt32 v) { + union { SInt32 i; UInt32 u; } u; + u.i = v; + return u.u; +} + + +SInt32 convertUInt32ToInt32(UInt32 v) { + union { SInt32 i; UInt32 u; } u; + u.u = v; + return u.i; +} + + +SInt32 logicalRightShift32(SInt32 value, SInt32 spaces) { + return convertUInt32ToInt32((convertInt32ToUInt32(value) >> spaces)); +} + + +SInt64 logicalRightShift64(SInt64 value, SInt32 spaces) { + return convertUInt64ToInt64((convertInt64ToUInt64(value) >> spaces)); +} + + +SInt32 decodeZigZag32(SInt32 n) { + return logicalRightShift32(n, 1) ^ -(n & 1); +} + + +SInt64 decodeZigZag64(SInt64 n) { + return logicalRightShift64(n, 1) ^ -(n & 1); +} + + +SInt32 encodeZigZag32(SInt32 n) { + // Note: the right-shift must be arithmetic + return (n << 1) ^ (n >> 31); +} + + +SInt64 encodeZigZag64(SInt64 n) { + // Note: the right-shift must be arithmetic + return (n << 1) ^ (n >> 63); +} + + +SInt32 computeDoubleSizeNoTag(Float64 value) { + return LITTLE_ENDIAN_64_SIZE; +} + + +SInt32 computeFloatSizeNoTag(Float32 value) { + return LITTLE_ENDIAN_32_SIZE; +} + + +SInt32 computeUInt64SizeNoTag(SInt64 value) { + return computeRawVarint64Size(value); +} + + +SInt32 computeInt64SizeNoTag(SInt64 value) { + return computeRawVarint64Size(value); +} + + +SInt32 computeInt32SizeNoTag(SInt32 value) { + if (value >= 0) { + return computeRawVarint32Size(value); + } else { + // Must sign-extend. + return 10; + } +} + + +SInt32 computeFixed64SizeNoTag(SInt64 value) { + return LITTLE_ENDIAN_64_SIZE; +} + + +SInt32 computeFixed32SizeNoTag(SInt32 value) { + return LITTLE_ENDIAN_32_SIZE; +} + + +SInt32 computeBoolSizeNoTag(BOOL value) { + return 1; +} + + +SInt32 computeStringSizeNoTag(const NSString* value) { + const UInt32 length = (UInt32)[value lengthOfBytesUsingEncoding:NSUTF8StringEncoding]; + return computeRawVarint32Size(length) + length; +} + + +SInt32 computeGroupSizeNoTag(const id value) { + return [value serializedSize]; +} + + +SInt32 computeUnknownGroupSizeNoTag(const PBUnknownFieldSet* value) { + return value.serializedSize; +} + + +SInt32 computeMessageSizeNoTag(const id value) { + SInt32 size = [value serializedSize]; + return computeRawVarint32Size(size) + size; +} + + +SInt32 computeDataSizeNoTag(const NSData* value) { + return computeRawVarint32Size((UInt32)value.length) + (UInt32)value.length; +} + + +SInt32 computeUInt32SizeNoTag(SInt32 value) { + return computeRawVarint32Size(value); +} + + +SInt32 computeEnumSizeNoTag(SInt32 value) { + return computeRawVarint32Size(value); +} + + +SInt32 computeSFixed32SizeNoTag(SInt32 value) { + return LITTLE_ENDIAN_32_SIZE; +} + + +SInt32 computeSFixed64SizeNoTag(SInt64 value) { + return LITTLE_ENDIAN_64_SIZE; +} + + +SInt32 computeSInt32SizeNoTag(SInt32 value) { + return computeRawVarint32Size(encodeZigZag32(value)); +} + + +SInt32 computeSInt64SizeNoTag(SInt64 value) { + return computeRawVarint64Size(encodeZigZag64(value)); +} + + +SInt32 computeDoubleSize(SInt32 fieldNumber, Float64 value) { + return computeTagSize(fieldNumber) + computeDoubleSizeNoTag(value); +} + + +SInt32 computeFloatSize(SInt32 fieldNumber, Float32 value) { + return computeTagSize(fieldNumber) + computeFloatSizeNoTag(value); +} + + +SInt32 computeUInt64Size(SInt32 fieldNumber, SInt64 value) { + return computeTagSize(fieldNumber) + computeUInt64SizeNoTag(value); +} + + +SInt32 computeInt64Size(SInt32 fieldNumber, SInt64 value) { + return computeTagSize(fieldNumber) + computeInt64SizeNoTag(value); +} + + +SInt32 computeInt32Size(SInt32 fieldNumber, SInt32 value) { + return computeTagSize(fieldNumber) + computeInt32SizeNoTag(value); +} + + +SInt32 computeFixed64Size(SInt32 fieldNumber, SInt64 value) { + return computeTagSize(fieldNumber) + computeFixed64SizeNoTag(value); +} + + +SInt32 computeFixed32Size(SInt32 fieldNumber, SInt32 value) { + return computeTagSize(fieldNumber) + computeFixed32SizeNoTag(value); +} + + +SInt32 computeBoolSize(SInt32 fieldNumber, BOOL value) { + return computeTagSize(fieldNumber) + computeBoolSizeNoTag(value); +} + + +SInt32 computeStringSize(SInt32 fieldNumber, const NSString* value) { + return computeTagSize(fieldNumber) + computeStringSizeNoTag(value); +} + + +SInt32 computeGroupSize(SInt32 fieldNumber, const id value) { + return computeTagSize(fieldNumber) * 2 + computeGroupSizeNoTag(value); +} + + +SInt32 computeUnknownGroupSize(SInt32 fieldNumber, const PBUnknownFieldSet* value) { + return computeTagSize(fieldNumber) * 2 + computeUnknownGroupSizeNoTag(value); +} + + +SInt32 computeMessageSize(SInt32 fieldNumber, const id value) { + return computeTagSize(fieldNumber) + computeMessageSizeNoTag(value); +} + + +SInt32 computeDataSize(SInt32 fieldNumber, const NSData* value) { + return computeTagSize(fieldNumber) + computeDataSizeNoTag(value); +} + + +SInt32 computeUInt32Size(SInt32 fieldNumber, SInt32 value) { + return computeTagSize(fieldNumber) + computeUInt32SizeNoTag(value); +} + + +SInt32 computeEnumSize(SInt32 fieldNumber, SInt32 value) { + return computeTagSize(fieldNumber) + computeEnumSizeNoTag(value); +} + + +SInt32 computeSFixed32Size(SInt32 fieldNumber, SInt32 value) { + return computeTagSize(fieldNumber) + computeSFixed32SizeNoTag(value); +} + + +SInt32 computeSFixed64Size(SInt32 fieldNumber, SInt64 value) { + return computeTagSize(fieldNumber) + computeSFixed64SizeNoTag(value); +} + + +SInt32 computeSInt32Size(SInt32 fieldNumber, SInt32 value) { + return computeTagSize(fieldNumber) + computeSInt32SizeNoTag(value); +} + + +SInt32 computeTagSize(SInt32 fieldNumber) { + return computeRawVarint32Size(PBWireFormatMakeTag(fieldNumber, 0)); +} + + +SInt32 computeSInt64Size(SInt32 fieldNumber, SInt64 value) { + return computeTagSize(fieldNumber) + + computeRawVarint64Size(encodeZigZag64(value)); +} + + +SInt32 computeRawVarint32Size(SInt32 value) { + if ((value & (0xffffffff << 7)) == 0) return 1; + if ((value & (0xffffffff << 14)) == 0) return 2; + if ((value & (0xffffffff << 21)) == 0) return 3; + if ((value & (0xffffffff << 28)) == 0) return 4; + return 5; +} + + +SInt32 computeRawVarint64Size(SInt64 value) { + if ((value & (0xffffffffffffffffL << 7)) == 0) return 1; + if ((value & (0xffffffffffffffffL << 14)) == 0) return 2; + if ((value & (0xffffffffffffffffL << 21)) == 0) return 3; + if ((value & (0xffffffffffffffffL << 28)) == 0) return 4; + if ((value & (0xffffffffffffffffL << 35)) == 0) return 5; + if ((value & (0xffffffffffffffffL << 42)) == 0) return 6; + if ((value & (0xffffffffffffffffL << 49)) == 0) return 7; + if ((value & (0xffffffffffffffffL << 56)) == 0) return 8; + if ((value & (0xffffffffffffffffL << 63)) == 0) return 9; + return 10; +} + + +SInt32 computeMessageSetExtensionSize(SInt32 fieldNumber, const id value) { + return computeTagSize(PBWireFormatMessageSetItem) * 2 + + computeUInt32Size(PBWireFormatMessageSetTypeId, fieldNumber) + + computeMessageSize(PBWireFormatMessageSetMessage, value); +} + + +SInt32 computeRawMessageSetExtensionSize(SInt32 fieldNumber, const NSData* value) { + return computeTagSize(PBWireFormatMessageSetItem) * 2 + + computeUInt32Size(PBWireFormatMessageSetTypeId, fieldNumber) + + computeDataSize(PBWireFormatMessageSetMessage, value); +} diff --git a/ios/Pods/ProtocolBuffers/src/runtime/Classes/WireFormat.h b/ios/Pods/ProtocolBuffers/src/runtime/Classes/WireFormat.h new file mode 100644 index 000000000..a0753616b --- /dev/null +++ b/ios/Pods/ProtocolBuffers/src/runtime/Classes/WireFormat.h @@ -0,0 +1,41 @@ +// Protocol Buffers for Objective C +// +// Copyright 2010 Booyah Inc. +// Copyright 2008 Cyrus Najmabadi +// +// 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. + +typedef enum { + PBWireFormatVarint = 0, + PBWireFormatFixed64 = 1, + PBWireFormatLengthDelimited = 2, + PBWireFormatStartGroup = 3, + PBWireFormatEndGroup = 4, + PBWireFormatFixed32 = 5, + + PBWireFormatTagTypeBits = 3, + PBWireFormatTagTypeMask = 7 /* = (1 << PBWireFormatTagTypeBits) - 1*/, + + PBWireFormatMessageSetItem = 1, + PBWireFormatMessageSetTypeId = 2, + PBWireFormatMessageSetMessage = 3 +} PBWireFormat; + +SInt32 PBWireFormatMakeTag(SInt32 fieldNumber, SInt32 wireType); +SInt32 PBWireFormatGetTagWireType(SInt32 tag); +SInt32 PBWireFormatGetTagFieldNumber(SInt32 tag); + +#define PBWireFormatMessageSetItemTag (PBWireFormatMakeTag(PBWireFormatMessageSetItem, PBWireFormatStartGroup)) +#define PBWireFormatMessageSetItemEndTag (PBWireFormatMakeTag(PBWireFormatMessageSetItem, PBWireFormatEndGroup)) +#define PBWireFormatMessageSetTypeIdTag (PBWireFormatMakeTag(PBWireFormatMessageSetTypeId, PBWireFormatVarint)) +#define PBWireFormatMessageSetMessageTag (PBWireFormatMakeTag(PBWireFormatMessageSetMessage, PBWireFormatLengthDelimited)) diff --git a/ios/Pods/ProtocolBuffers/src/runtime/Classes/WireFormat.m b/ios/Pods/ProtocolBuffers/src/runtime/Classes/WireFormat.m new file mode 100644 index 000000000..6152f0fb9 --- /dev/null +++ b/ios/Pods/ProtocolBuffers/src/runtime/Classes/WireFormat.m @@ -0,0 +1,34 @@ +// Protocol Buffers for Objective C +// +// Copyright 2010 Booyah Inc. +// Copyright 2008 Cyrus Najmabadi +// +// 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. + +#import "WireFormat.h" + +#import "Utilities.h" + +SInt32 PBWireFormatMakeTag(SInt32 fieldNumber, SInt32 wireType) { + return (fieldNumber << PBWireFormatTagTypeBits) | wireType; +} + + +SInt32 PBWireFormatGetTagWireType(SInt32 tag) { + return tag & PBWireFormatTagTypeMask; +} + + +SInt32 PBWireFormatGetTagFieldNumber(SInt32 tag) { + return logicalRightShift32(tag, PBWireFormatTagTypeBits); +} diff --git a/ios/Pods/SCLAlertView-Objective-C/LICENSE b/ios/Pods/SCLAlertView-Objective-C/LICENSE new file mode 100644 index 000000000..cb4203d76 --- /dev/null +++ b/ios/Pods/SCLAlertView-Objective-C/LICENSE @@ -0,0 +1,19 @@ +Copyright (c) 2013-2014 SCLAlertView-Objective-C by Diogo Autilio + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. \ No newline at end of file diff --git a/ios/Pods/SCLAlertView-Objective-C/README.md b/ios/Pods/SCLAlertView-Objective-C/README.md new file mode 100644 index 000000000..3518e8bea --- /dev/null +++ b/ios/Pods/SCLAlertView-Objective-C/README.md @@ -0,0 +1,207 @@ +SCLAlertView-Objective-C +============ + +Animated Alert View written in Swift but ported to Objective-C, which can be used as a `UIAlertView` or `UIAlertController` replacement. + +[![Build Status](https://travis-ci.org/dogo/SCLAlertView.svg?branch=master)](https://travis-ci.org/dogo/SCLAlertView) +[![Cocoapods](http://img.shields.io/cocoapods/v/SCLAlertView-Objective-C.svg)](http://cocoapods.org/?q=SCLAlertView-Objective-C) + +![BackgroundImage](https://raw.githubusercontent.com/dogo/SCLAlertView/master/ScreenShots/ScreenShot.png)_ +![BackgroundImage](https://raw.githubusercontent.com/dogo/SCLAlertView/master/ScreenShots/ScreenShot2.png) +![BackgroundImage](https://raw.githubusercontent.com/dogo/SCLAlertView/master/ScreenShots/ScreenShot3.png) +![BackgroundImage](https://raw.githubusercontent.com/dogo/SCLAlertView/master/ScreenShots/ScreenShot4.png) +![BackgroundImage](https://raw.githubusercontent.com/dogo/SCLAlertView/master/ScreenShots/ScreenShot5.png) + +###Easy to use +```Objective-C +// Get started +SCLAlertView *alert = [[SCLAlertView alloc] init]; + +[alert showSuccess:self title:@"Hello World" subTitle:@"This is a more descriptive text." closeButtonTitle:@"Done" duration:0.0f]; + +// Alternative alert types +[alert showError:self title:@"Hello Error" subTitle:@"This is a more descriptive error text." closeButtonTitle:@"OK" duration:0.0f]; // Error +[alert showNotice:self title:@"Hello Notice" subTitle:@"This is a more descriptive notice text." closeButtonTitle:@"Done" duration:0.0f]; // Notice +[alert showWarning:self title:@"Hello Warning" subTitle:@"This is a more descriptive warning text." closeButtonTitle:@"Done" duration:0.0f]; // Warning +[alert showInfo:self title:@"Hello Info" subTitle:@"This is a more descriptive info text." closeButtonTitle:@"Done" duration:0.0f]; // Info +[alert showEdit:self title:@"Hello Edit" subTitle:@"This is a more descriptive info text with a edit textbox" closeButtonTitle:@"Done" duration:0.0f]; // Edit +[alert showCustom:self image:[UIImage imageNamed:@"git"] color:color title:@"Custom" subTitle:@"Add a custom icon and color for your own type of alert!" closeButtonTitle:@"OK" duration:0.0f]; // Custom +``` + +###Advanced +```Objective-C +SCLAlertView *alert = [[SCLAlertView alloc] init]; + +[alert showTitle:self // Parent view controller + title:@"Congratulations" // Title of view + subTitle:@"Operation successfully completed." // String of view + style:Success // Styles - see below. + completeText:@"Done" // Optional button value + duration:2.0f]; // Duration to show before closing automatically +``` + +###Add buttons +```Objective-C +SCLAlertView *alert = [[SCLAlertView alloc] init]; + +//Using Selector +[alert addButton:@"First Button" target:self selector:@selector(firstButton)]; + +//Using Block +[alert addButton:@"Second Button" actionBlock:^(void) { + NSLog(@"Second button tapped"); +}]; + +//Using Blocks With Validation +[alert addButton:@"Validate" validationBlock:^BOOL { + BOOL passedValidation = .... + return passedValidation; + +} actionBlock:^{ + // handle successful validation here +}]; + +[alert showSuccess:self title:@"Button View" subTitle:@"This alert view has buttons" closeButtonTitle:@"Done" duration:0.0f]; +``` + +###Add Text Attributes +```Objective-C +SCLAlertView *alert = [[SCLAlertView alloc] init]; + +alert.attributedFormatBlock = ^NSAttributedString* (NSString *value) +{ + NSMutableAttributedString *subTitle = [[NSMutableAttributedString alloc]initWithString:value]; + + NSRange redRange = [value rangeOfString:@"Attributed" options:NSCaseInsensitiveSearch]; + [subTitle addAttribute:NSForegroundColorAttributeName value:[UIColor redColor] range:redRange]; + + NSRange greenRange = [value rangeOfString:@"successfully" options:NSCaseInsensitiveSearch]; + [subTitle addAttribute:NSForegroundColorAttributeName value:[UIColor greenColor] range:greenRange]; + + NSRange underline = [value rangeOfString:@"completed" options:NSCaseInsensitiveSearch]; + [subTitle addAttributes:@{NSUnderlineStyleAttributeName:@(NSUnderlineStyleSingle)} range:underline]; + + return subTitle; +}; + +[alert showSuccess:self title:@"Button View" subTitle:@"Attributed string operation successfully completed." closeButtonTitle:@"Done" duration:0.0f]; +``` +###Add a text field +```Objective-C +SCLAlertView *alert = [[SCLAlertView alloc] init]; + +UITextField *textField = [alert addTextField:@"Enter your name"]; + +[alert addButton:@"Show Name" actionBlock:^(void) { + NSLog(@"Text value: %@", textField.text); +}]; + +[alert showEdit:self title:@"Edit View" subTitle:@"This alert view shows a text box" closeButtonTitle:@"Done" duration:0.0f]; +``` + +###Indeterminate progress +```Objective-C +SCLAlertView *alert = [[SCLAlertView alloc] init]; + +[alert showWaiting:self title:@"Waiting..." subTitle:@"Blah de blah de blah, blah. Blah de blah de" closeButtonTitle:nil duration:5.0f]; +``` + + +###SCLAlertView properties +```Objective-C +//Dismiss on tap outside (Default is NO) +alert.shouldDismissOnTapOutside = YES; + +//Hide animation type (Default is FadeOut) +alert.hideAnimationType = SlideOutToBottom; + +//Show animation type (Default is SlideInFromTop) +alert.showAnimationType = SlideInFromLeft; + +//Set background type (Default is Shadow) +alert.backgroundType = Blur; + +//Using sound +alert.soundURL = [NSURL fileURLWithPath:[NSString stringWithFormat:@"%@/right_answer.mp3", [[NSBundle mainBundle] resourcePath]]]; +``` + +###Helpers +```Objective-C +//Receiving information that SCLAlertView is dismissed +[alert alertIsDismissed:^{ + NSLog(@"SCLAlertView dismissed!"); +}]; +``` + +####Alert View Styles +```Objective-C +typedef NS_ENUM(NSInteger, SCLAlertViewStyle) +{ + Success, + Error, + Notice, + Warning, + Info, + Edit, + Waiting, + Custom +}; +``` +####Alert View hide animation styles +```Objective-C +typedef NS_ENUM(NSInteger, SCLAlertViewHideAnimation) +{ + FadeOut, + SlideOutToBottom, + SlideOutToTop, + SlideOutToLeft, + SlideOutToRight, + SlideOutToCenter, + SlideOutFromCenter +}; +``` +####Alert View show animation styles +```Objective-C +typedef NS_ENUM(NSInteger, SCLAlertViewShowAnimation) +{ + FadeIn, + SlideInFromBottom, + SlideInFromTop, + SlideInFromLeft, + SlideInFromRight, + SlideInFromCenter, + SlideInToCenter +}; +``` + +####Alert View background styles +```Objective-C +typedef NS_ENUM(NSInteger, SCLAlertViewBackground) +{ + Shadow, + Blur +}; +``` + +### Installation + +SCLAlertView-Objective-C is available through [CocoaPods](http://cocoapods.org). + +To install add the following line to your Podfile: + + pod 'SCLAlertView-Objective-C' + +### Collaboration +I tried to build an easy to use API, while beeing flexible enough for multiple variations, but I'm sure there are ways of improving and adding more features, so feel free to collaborate with ideas, issues and/or pull requests. + +###Incoming improvements +- More animations +- Performance tests +- Remove some hardcode values + +### Thanks to the original team +- Design [@SherzodMx](https://twitter.com/SherzodMx) Sherzod Max +- Development [@hackua](https://twitter.com/hackua) Viktor Radchenko +- Improvements by [@bih](http://github.com/bih) Bilawal Hameed, [@rizjoj](http://github.com/rizjoj) Riz Joj + +https://github.com/vikmeup/SCLAlertView-Swift diff --git a/ios/Pods/SCLAlertView-Objective-C/SCLAlertView/SCLAlertView.h b/ios/Pods/SCLAlertView-Objective-C/SCLAlertView/SCLAlertView.h new file mode 100755 index 000000000..ee6fac3f5 --- /dev/null +++ b/ios/Pods/SCLAlertView-Objective-C/SCLAlertView/SCLAlertView.h @@ -0,0 +1,279 @@ +// +// SCLAlertView.h +// SCLAlertView +// +// Created by Diogo Autilio on 9/26/14. +// Copyright (c) 2014 AnyKey Entertainment. All rights reserved. +// + +#import +#import "SCLButton.h" + +typedef NSAttributedString* (^SCLAttributedFormatBlock)(NSString *value); +typedef void (^DismissBlock)(void); + +@interface SCLAlertView : UIViewController + +/** Alert Styles + * + * Set SCLAlertView Style + */ +typedef NS_ENUM(NSInteger, SCLAlertViewStyle) +{ + Success, + Error, + Notice, + Warning, + Info, + Edit, + Waiting, + Custom +}; + +/** Alert hide animation styles + * + * Set SCLAlertView hide animation type. + */ +typedef NS_ENUM(NSInteger, SCLAlertViewHideAnimation) +{ + FadeOut, + SlideOutToBottom, + SlideOutToTop, + SlideOutToLeft, + SlideOutToRight, + SlideOutToCenter, + SlideOutFromCenter +}; + +/** Alert show animation styles + * + * Set SCLAlertView show animation type. + */ +typedef NS_ENUM(NSInteger, SCLAlertViewShowAnimation) +{ + FadeIn, + SlideInFromBottom, + SlideInFromTop, + SlideInFromLeft, + SlideInFromRight, + SlideInFromCenter, + SlideInToCenter +}; + +/** Alert background styles + * + * Set SCLAlertView background type. + */ +typedef NS_ENUM(NSInteger, SCLAlertViewBackground) +{ + Shadow, + Blur +}; + +/** Title Label + * + * The text displayed as title. + */ +@property UILabel *labelTitle; + +/** Text view with the body message + * + * Holds the textview. + */ +@property UITextView *viewText; + +/** Activity Indicator + * + * Holds the activityIndicator. + */ +@property UIActivityIndicatorView *activityIndicatorView; + +/** Dismiss on tap outside + * + * A boolean value that determines whether to dismiss when tapping outside the SCLAlertView. + * (Default: NO) + */ +@property (nonatomic, assign) BOOL shouldDismissOnTapOutside; + +/** Sound URL + * + * Holds the sound NSURL path. + */ +@property (nonatomic, strong) NSURL *soundURL; + +/** Set text attributed format block + * + * Holds the attributed string. + */ +@property (nonatomic, copy) SCLAttributedFormatBlock attributedFormatBlock; + +/** Set button format block. + * + * Holds the button format block. + * Support keys : backgroundColor, textColor + */ +@property (nonatomic, copy) CompleteButtonFormatBlock completeButtonFormatBlock; + +/** Hide animation type + * + * Holds the hide animation type. + * (Default: FadeOut) + */ +@property (nonatomic) SCLAlertViewHideAnimation hideAnimationType; + +/** Show animation type + * + * Holds the show animation type. + * (Default: SlideInFromTop) + */ +@property (nonatomic) SCLAlertViewShowAnimation showAnimationType; + +/** Set SCLAlertView background type. + * + * SCLAlertView background type. + * (Default: Shadow) + */ +@property (nonatomic) SCLAlertViewBackground backgroundType; + +/** Warns that alerts is gone + * + * Warns that alerts is gone using block + */ +- (void)alertIsDismissed:(DismissBlock)dismissBlock; + +/** Hide SCLAlertView + * + * Hide SCLAlertView using animation and removing from super view. + */ +- (void)hideView; + +/** Add Text Field + * + * @param title The text displayed on the textfield. + */ +- (UITextField *)addTextField:(NSString *)title; + +/** Set SubTitle Height + * + * @param value Height of scrollable subtitle text field. + */ +- (void)setSubTitleHeight:(CGFloat)value; + +/** Add a Button with a title and a block to handle when the button is pressed. + * + * @param title The text displayed on the button. + * @param action A block of code to be executed when the button is pressed. + */ +- (SCLButton *)addButton:(NSString *)title actionBlock:(SCLActionBlock)action; + +/** Add a Button with a title, a block to handle validation, and a block to handle when the button is pressed and validation succeeds. + * + * @param title The text displayed on the button. + * @param validationBlock A block of code that will allow you to validate fields or do any other logic you may want to do to determine if the alert should be dismissed or not. Inside of this block, return a BOOL indicating whether or not the action block should be called and the alert dismissed. + * @param action A block of code to be executed when the button is pressed and validation passes. + */ +- (SCLButton *)addButton:(NSString *)title validationBlock:(SCLValidationBlock)validationBlock actionBlock:(SCLActionBlock)action; + +/** Add a Button with a title, a target and a selector to handle when the button is pressed. + * + * @param title The text displayed on the button. + * @param target Add target for particular event. + * @param selector A method to be executed when the button is pressed. + */ +- (SCLButton *)addButton:(NSString *)title target:(id)target selector:(SEL)selector; + +/** Show Success SCLAlertView + * + * @param vc The view controller the alert view will be displayed in. + * @param title The text displayed on the button. + * @param subTitle The subtitle text of the alert view. + * @param closeButtonTitle The text for the close button. + * @param duration The amount of time the alert will remain on screen until it is automatically dismissed. If automatic dismissal is not desired, set to 0. + */ +- (void)showSuccess:(UIViewController *)vc title:(NSString *)title subTitle:(NSString *)subTitle closeButtonTitle:(NSString *)closeButtonTitle duration:(NSTimeInterval)duration; + +/** Show Error SCLAlertView + * + * @param vc The view controller the alert view will be displayed in. + * @param title The text displayed on the button. + * @param subTitle The subtitle text of the alert view. + * @param closeButtonTitle The text for the close button. + * @param duration The amount of time the alert will remain on screen until it is automatically dismissed. If automatic dismissal is not desired, set to 0. + */ +- (void)showError:(UIViewController *)vc title:(NSString *)title subTitle:(NSString *)subTitle closeButtonTitle:(NSString *)closeButtonTitle duration:(NSTimeInterval)duration; + +/** Show Notice SCLAlertView + * + * @param vc The view controller the alert view will be displayed in. + * @param title The text displayed on the button. + * @param subTitle The subtitle text of the alert view. + * @param closeButtonTitle The text for the close button. + * @param duration The amount of time the alert will remain on screen until it is automatically dismissed. If automatic dismissal is not desired, set to 0. + */ +- (void)showNotice:(UIViewController *)vc title:(NSString *)title subTitle:(NSString *)subTitle closeButtonTitle:(NSString *)closeButtonTitle duration:(NSTimeInterval)duration; + +/** Show Warning SCLAlertView + * + * @param vc The view controller the alert view will be displayed in. + * @param title The text displayed on the button. + * @param subTitle The subtitle text of the alert view. + * @param closeButtonTitle The text for the close button. + * @param duration The amount of time the alert will remain on screen until it is automatically dismissed. If automatic dismissal is not desired, set to 0. + */ +- (void)showWarning:(UIViewController *)vc title:(NSString *)title subTitle:(NSString *)subTitle closeButtonTitle:(NSString *)closeButtonTitle duration:(NSTimeInterval)duration; + +/** Show Info SCLAlertView + * + * @param vc The view controller the alert view will be displayed in. + * @param title The text displayed on the button. + * @param subTitle The subtitle text of the alert view. + * @param closeButtonTitle The text for the close button. + * @param duration The amount of time the alert will remain on screen until it is automatically dismissed. If automatic dismissal is not desired, set to 0. + */ +- (void)showInfo:(UIViewController *)vc title:(NSString *)title subTitle:(NSString *)subTitle closeButtonTitle:(NSString *)closeButtonTitle duration:(NSTimeInterval)duration; + +/** Show Edit SCLAlertView + * + * @param vc The view controller the alert view will be displayed in. + * @param title The text displayed on the button. + * @param subTitle The subtitle text of the alert view. + * @param closeButtonTitle The text for the close button. + * @param duration The amount of time the alert will remain on screen until it is automatically dismissed. If automatic dismissal is not desired, set to 0. + */ +- (void)showEdit:(UIViewController *)vc title:(NSString *)title subTitle:(NSString *)subTitle closeButtonTitle:(NSString *)closeButtonTitle duration:(NSTimeInterval)duration; + +/** Show Title SCLAlertView using a predefined type + * + * @param vc The view controller the alert view will be displayed in. + * @param title The text displayed on the button. + * @param subTitle The subtitle text of the alert view. + * @param style One of predefined SCLAlertView styles. + * @param closeButtonTitle The text for the close button. + * @param duration The amount of time the alert will remain on screen until it is automatically dismissed. If automatic dismissal is not desired, set to 0. + */ +- (void)showTitle:(UIViewController *)vc title:(NSString *)title subTitle:(NSString *)subTitle style:(SCLAlertViewStyle)style closeButtonTitle:(NSString *)closeButtonTitle duration:(NSTimeInterval)duration; + +/** Shows a custom SCLAlertView without using a predefined type, allowing for a custom image and color to be specified. + * + * @param vc The view controller the alert view will be displayed in. + * @param image A UIImage object to be used as the icon for the alert view. + * @param color A UIColor object to be used to tint the background of the icon circle and the buttons. + * @param title The title text of the alert view. + * @param subTitle The subtitle text of the alert view. + * @param closeButtonTitle The text for the close button. + * @param duration The amount of time the alert will remain on screen until it is automatically dismissed. If automatic dismissal is not desired, set to 0. + */ +- (void)showCustom:(UIViewController *)vc image:(UIImage *)image color:(UIColor *)color title:(NSString *)title subTitle:(NSString *)subTitle closeButtonTitle:(NSString *)closeButtonTitle duration:(NSTimeInterval)duration; + +/** Show Waiting SCLAlertView with UIActityIndicator. + * + * @param vc The view controller the alert view will be displayed in. + * @param title The text displayed on the button. + * @param subTitle The subtitle text of the alert view. + * @param closeButtonTitle The text for the close button. + * @param duration The amount of time the alert will remain on screen until it is automatically dismissed. If automatic dismissal is not desired, set to 0. + */ +- (void)showWaiting:(UIViewController *)vc title:(NSString *)title subTitle:(NSString *)subTitle closeButtonTitle:(NSString *)closeButtonTitle duration:(NSTimeInterval)duration; + + +@end diff --git a/ios/Pods/SCLAlertView-Objective-C/SCLAlertView/SCLAlertView.m b/ios/Pods/SCLAlertView-Objective-C/SCLAlertView/SCLAlertView.m new file mode 100755 index 000000000..be157f1fc --- /dev/null +++ b/ios/Pods/SCLAlertView-Objective-C/SCLAlertView/SCLAlertView.m @@ -0,0 +1,1072 @@ +// +// SCLAlertView.m +// SCLAlertView +// +// Created by Diogo Autilio on 9/26/14. +// Copyright (c) 2014 AnyKey Entertainment. All rights reserved. +// + +#import "SCLAlertView.h" +#import "SCLAlertViewResponder.h" +#import "SCLAlertViewStyleKit.h" +#import "UIImage+ImageEffects.h" +#import + +#define UIColorFromRGB(rgbValue) [UIColor \ +colorWithRed:((float)((rgbValue & 0xFF0000) >> 16))/255.0 \ +green:((float)((rgbValue & 0xFF00) >> 8))/255.0 \ +blue:((float)(rgbValue & 0xFF))/255.0 alpha:1.0] + +#define SYSTEM_VERSION_EQUAL_TO(v) ([[[UIDevice currentDevice] systemVersion] compare:v options:NSNumericSearch] == NSOrderedSame) +#define SYSTEM_VERSION_GREATER_THAN(v) ([[[UIDevice currentDevice] systemVersion] compare:v options:NSNumericSearch] == NSOrderedDescending) +#define SYSTEM_VERSION_GREATER_THAN_OR_EQUAL_TO(v) ([[[UIDevice currentDevice] systemVersion] compare:v options:NSNumericSearch] != NSOrderedAscending) +#define SYSTEM_VERSION_LESS_THAN(v) ([[[UIDevice currentDevice] systemVersion] compare:v options:NSNumericSearch] == NSOrderedAscending) +#define SYSTEM_VERSION_LESS_THAN_OR_EQUAL_TO(v) ([[[UIDevice currentDevice] systemVersion] compare:v options:NSNumericSearch] != NSOrderedDescending) + +#define KEYBOARD_HEIGHT 80 +#define PREDICTION_BAR_HEIGHT 40 + +@interface SCLAlertView () + +@property (nonatomic, strong) NSMutableArray *inputs; +@property (nonatomic, strong) NSMutableArray *buttons; +@property (nonatomic, strong) UIImageView *circleIconImageView; +@property (nonatomic, strong) UIView *circleView; +@property (nonatomic, strong) UIView *contentView; +@property (nonatomic, strong) UIView *circleViewBackground; +@property (nonatomic, strong) UIImageView *backgroundView; +@property (nonatomic, strong) AVAudioPlayer *audioPlayer; +@property (nonatomic, strong) UITapGestureRecognizer *gestureRecognizer; +@property (nonatomic, copy) DismissBlock dismissBlock; +@property (nonatomic) BOOL canAddObservers; +@property (nonatomic) BOOL keyboardIsVisible; +@property (nonatomic) CGFloat backgroundOpacity; + +@end + +@implementation SCLAlertView + +CGFloat kCircleHeight; +CGFloat kCircleTopPosition; +CGFloat kCircleBackgroundTopPosition; +CGFloat kCircleHeightBackground; +CGFloat kCircleIconHeight; +CGFloat kActivityIndicatorHeight; +CGFloat kWindowWidth; +CGFloat kWindowHeight; +CGFloat kTextHeight; + +// Subtitle +CGFloat kSubTitleHeight; + +// Font +NSString *kDefaultFont = @"HelveticaNeue"; +NSString *kButtonFont = @"HelveticaNeue-Bold"; + +// Timer +NSTimer *durationTimer; + +#pragma mark - Initialization + +- (id)initWithCoder:(NSCoder *)aDecoder +{ + @throw [NSException exceptionWithName:NSInternalInconsistencyException + reason:@"NSCoding not supported" + userInfo:nil]; +} + +- (instancetype)init +{ + self = [super init]; + if (self) + { + // Default values + kCircleHeight = 56.0f; + kCircleTopPosition = -12.0f; + kCircleBackgroundTopPosition = -15.0f; + kCircleHeightBackground = 62.0f; + kCircleIconHeight = 20.0f; + kActivityIndicatorHeight = 40.0f; + kWindowWidth = 240.0f; + kWindowHeight = 178.0f; + kSubTitleHeight = 90.0f; + kTextHeight = 90.0f; + _shouldDismissOnTapOutside = NO; + _canAddObservers = YES; + _keyboardIsVisible = NO; + _hideAnimationType = FadeOut; + _showAnimationType = SlideInFromTop; + _backgroundType = Shadow; + + // Init + _labelTitle = [[UILabel alloc] init]; + _viewText = [[UITextView alloc] init]; + _contentView = [[UIView alloc] init]; + _circleView = [[UIView alloc] init]; + _circleViewBackground = [[UIView alloc] init]; + _circleIconImageView = [[UIImageView alloc] init]; + _backgroundView = [[UIImageView alloc]initWithFrame:[self mainScreenFrame]]; + _buttons = [[NSMutableArray alloc] init]; + _inputs = [[NSMutableArray alloc] init]; + _activityIndicatorView = [[UIActivityIndicatorView alloc] initWithActivityIndicatorStyle:UIActivityIndicatorViewStyleWhiteLarge]; + + // Add Subviews + [self.view addSubview:_contentView]; + [self.view addSubview:_circleViewBackground]; + [self.view addSubview:_circleView]; + + [_circleView addSubview:_circleIconImageView]; + [_circleView addSubview:_activityIndicatorView]; + [_contentView addSubview:_labelTitle]; + [_contentView addSubview:_viewText]; + + // Content View + _contentView.layer.cornerRadius = 5.0f; + _contentView.layer.masksToBounds = YES; + _contentView.layer.borderWidth = 0.5f; + + // Circle View Background + _circleViewBackground.backgroundColor = [UIColor whiteColor]; + + // Background View + _backgroundView.userInteractionEnabled = YES; + + // Title + _labelTitle.numberOfLines = 1; + _labelTitle.textAlignment = NSTextAlignmentCenter; + _labelTitle.font = [UIFont fontWithName:kDefaultFont size:20.0f]; + + // View text + _viewText.editable = NO; + _viewText.allowsEditingTextAttributes = YES; + _viewText.textAlignment = NSTextAlignmentCenter; + _viewText.font = [UIFont fontWithName:kDefaultFont size:14.0f]; + + if (SYSTEM_VERSION_GREATER_THAN_OR_EQUAL_TO(@"7.0")) + { + _viewText.textContainerInset = UIEdgeInsetsZero; + _viewText.textContainer.lineFragmentPadding = 0; + } + + // Colors + _contentView.backgroundColor = [UIColor whiteColor]; + _labelTitle.textColor = UIColorFromRGB(0x4D4D4D); + _viewText.textColor = UIColorFromRGB(0x4D4D4D); + _contentView.layer.borderColor = UIColorFromRGB(0xCCCCCC).CGColor; + } + return self; +} + +- (void)dealloc +{ + [self removeObservers]; +} + +- (void)addObservers +{ + if(_canAddObservers) + { + [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(keyboardDidShow:) name:UIKeyboardDidShowNotification object:nil]; + [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(keyboardDidHide:) name:UIKeyboardDidHideNotification object:nil]; + _canAddObservers = NO; + } +} + +- (void)removeObservers +{ + [[NSNotificationCenter defaultCenter] removeObserver:self name:UIKeyboardWillShowNotification object:nil]; + [[NSNotificationCenter defaultCenter] removeObserver:self name:UIKeyboardWillHideNotification object:nil]; +} + +#pragma mark - View Cycle + +-(void)viewWillLayoutSubviews +{ + [super viewWillLayoutSubviews]; + + CGSize sz = [UIScreen mainScreen].bounds.size; + + if (SYSTEM_VERSION_LESS_THAN(@"8.0")) + { + // iOS versions before 7.0 did not switch the width and height on device roration + if UIInterfaceOrientationIsLandscape([[UIApplication sharedApplication] statusBarOrientation]) + { + CGSize ssz = sz; + sz = CGSizeMake(ssz.height, ssz.width); + } + } + + // Set background frame + CGRect newFrame = self.backgroundView.frame; + newFrame.size = sz; + self.backgroundView.frame = newFrame; + + // Set frames + CGRect r; + if (self.view.superview != nil) + { + // View is showing, position at center of screen + r = CGRectMake((sz.width-kWindowWidth)/2, (sz.height-kWindowHeight)/2, kWindowWidth, kWindowHeight); + } + else + { + // View is not visible, position outside screen bounds + r = CGRectMake((sz.width-kWindowWidth)/2, -kWindowHeight, kWindowWidth, kWindowHeight); + } + + self.view.frame = r; + _contentView.frame = CGRectMake(0.0f, kCircleHeight / 4, kWindowWidth, kWindowHeight); + _circleViewBackground.frame = CGRectMake(kWindowWidth / 2 - kCircleHeightBackground / 2, kCircleBackgroundTopPosition, kCircleHeightBackground, kCircleHeightBackground); + _circleViewBackground.layer.cornerRadius = _circleViewBackground.frame.size.height / 2; + _circleView.frame = CGRectMake(kWindowWidth / 2 - kCircleHeight / 2, kCircleTopPosition, kCircleHeight, kCircleHeight); + _circleView.layer.cornerRadius = self.circleView.frame.size.height / 2; + _circleIconImageView.frame = CGRectMake(kCircleHeight / 2 - kCircleIconHeight / 2, kCircleHeight / 2 - kCircleIconHeight / 2, kCircleIconHeight, kCircleIconHeight); + _activityIndicatorView.frame =CGRectMake(kCircleHeight / 2 - kActivityIndicatorHeight / 2, kCircleHeight / 2 - kActivityIndicatorHeight / 2, kActivityIndicatorHeight, kActivityIndicatorHeight); + + _labelTitle.frame = CGRectMake(12.0f, kCircleHeight / 2 + 12.0f, kWindowWidth - 24.0f, 40.0f); + _viewText.frame = CGRectMake(12.0f, 74.0f, kWindowWidth - 24.0f, kTextHeight); + + // Title is nil, we can move the body message to center + if(_labelTitle.text == nil) + { + _viewText.frame = CGRectMake(12.0f, kCircleHeight, kWindowWidth - 24.0f, kTextHeight); + } + + // Text fields + CGFloat y = 74.0f + kTextHeight + 14.0f; + for (UITextField *textField in _inputs) + { + textField.frame = CGRectMake(12.0f, y, kWindowWidth - 24.0f, 30.0f); + textField.layer.cornerRadius = 3; + y += 40.0f; + } + + // Buttons + for (SCLButton *btn in _buttons) + { + btn.frame = CGRectMake(12.0f, y, kWindowWidth - 24, 35.0f); + btn.layer.cornerRadius = 3; + y += 45.0; + } +} + +#pragma mark - Handle gesture + +- (void)handleTap:(UITapGestureRecognizer *)gesture +{ + if (_shouldDismissOnTapOutside) + { + BOOL hide = _shouldDismissOnTapOutside; + + for(UITextField *txt in _inputs) + { + // Check if there is any keyboard on screen and dismiss + if ([txt isEditing]) + { + [txt resignFirstResponder]; + hide = NO; + } + } + if(hide)[self hideView]; + } +} + +- (void)setShouldDismissOnTapOutside:(BOOL)shouldDismissOnTapOutside +{ + _shouldDismissOnTapOutside = shouldDismissOnTapOutside; + + if(_shouldDismissOnTapOutside) + { + self.gestureRecognizer = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(handleTap:)]; + [_backgroundView addGestureRecognizer:_gestureRecognizer]; + } +} + +#pragma mark - Sound + +- (void)setSoundURL:(NSURL *)soundURL +{ + NSError *error; + _soundURL = soundURL; + _audioPlayer = [[AVAudioPlayer alloc] initWithContentsOfURL:_soundURL error:&error]; +} + +#pragma mark - Subtitle Height + +- (void)setSubTitleHeight:(CGFloat)value +{ + kSubTitleHeight = value; +} + +#pragma mark - TextField + +- (UITextField *)addTextField:(NSString *)title +{ + [self addObservers]; + + // Update view height + kWindowHeight += 40.0; + + // Add text field + UITextField *txt = [[UITextField alloc] init]; + txt.delegate = self; + txt.returnKeyType = UIReturnKeyDone; + txt.borderStyle = UITextBorderStyleRoundedRect; + txt.font = [UIFont fontWithName:kDefaultFont size:14.0f]; + txt.autocapitalizationType = UITextAutocapitalizationTypeWords; + txt.clearButtonMode = UITextFieldViewModeWhileEditing; + txt.layer.masksToBounds = YES; + txt.layer.borderWidth = 1.0f; + + if (title != nil) + { + txt.placeholder = title; + } + + [_contentView addSubview:txt]; + [_inputs addObject:txt]; + + // If there are other fields in the inputs array, get the previous field and set the + // return key type on that to next. + if (_inputs.count > 1) + { + NSUInteger indexOfCurrentField = [_inputs indexOfObject:txt]; + UITextField *priorField = _inputs[indexOfCurrentField - 1]; + priorField.returnKeyType = UIReturnKeyNext; + } + return txt; +} + +# pragma mark - UITextFieldDelegate + +- (BOOL)textFieldShouldReturn:(UITextField *)textField +{ + // If this is the last object in the inputs array, resign first responder + // as the form is at the end. + if (textField == [_inputs lastObject]) + { + [textField resignFirstResponder]; + } + else // Otherwise find the next field and make it first responder. + { + NSUInteger indexOfCurrentField = [_inputs indexOfObject:textField]; + UITextField *nextField = _inputs[indexOfCurrentField + 1]; + [nextField becomeFirstResponder]; + } + return NO; +} + +- (void)keyboardDidShow:(NSNotification *)notification +{ + if(_keyboardIsVisible) return; + + [UIView animateWithDuration:0.2f animations:^{ + CGRect f = self.view.frame; + f.origin.y -= KEYBOARD_HEIGHT + PREDICTION_BAR_HEIGHT; + self.view.frame = f; + }]; + _keyboardIsVisible = YES; +} + +-(void)keyboardDidHide:(NSNotification *)notification +{ + [UIView animateWithDuration:0.2f animations:^{ + CGRect f = self.view.frame; + f.origin.y += KEYBOARD_HEIGHT + PREDICTION_BAR_HEIGHT; + self.view.frame = f; + }]; + _keyboardIsVisible = NO; +} + +#pragma mark - Buttons + +- (SCLButton *)addButton:(NSString *)title +{ + // Update view height + kWindowHeight += 45.0; + + // Add button + SCLButton *btn = [[SCLButton alloc] init]; + btn.layer.masksToBounds = YES; + [btn setTitle:title forState:UIControlStateNormal]; + btn.titleLabel.font = [UIFont fontWithName:kButtonFont size:14.0f]; + + [_contentView addSubview:btn]; + [_buttons addObject:btn]; + + return btn; +} + +- (SCLButton *)addDoneButtonWithTitle:(NSString *)title +{ + SCLButton *btn = [self addButton:title]; + + if (_completeButtonFormatBlock != nil) + { + btn.completeButtonFormatBlock = _completeButtonFormatBlock; + } + + [btn addTarget:self action:@selector(hideView) forControlEvents:UIControlEventTouchUpInside]; + + return btn; +} + +- (SCLButton *)addButton:(NSString *)title actionBlock:(SCLActionBlock)action +{ + SCLButton *btn = [self addButton:title]; + btn.actionType = Block; + btn.actionBlock = action; + [btn addTarget:self action:@selector(buttonTapped:) forControlEvents:UIControlEventTouchUpInside]; + + return btn; +} + +- (SCLButton *)addButton:(NSString *)title validationBlock:(SCLValidationBlock)validationBlock actionBlock:(SCLActionBlock)action +{ + SCLButton *btn = [self addButton:title actionBlock:action]; + btn.validationBlock = validationBlock; + + return btn; +} + +- (SCLButton *)addButton:(NSString *)title target:(id)target selector:(SEL)selector +{ + SCLButton *btn = [self addButton:title]; + btn.actionType = Selector; + btn.target = target; + btn.selector = selector; + [btn addTarget:self action:@selector(buttonTapped:) forControlEvents:UIControlEventTouchUpInside]; + + return btn; +} + +- (void)buttonTapped:(SCLButton *)btn +{ + // If the button has a validation block, and the validation block returns NO, validation + // failed, so we should bail. + if (btn.validationBlock && !btn.validationBlock()) { + return; + } + if (btn.actionType == Block) + { + if (btn.actionBlock) + btn.actionBlock(); + } + else if (btn.actionType == Selector) + { + UIControl *ctrl = [[UIControl alloc] init]; + [ctrl sendAction:btn.selector to:btn.target forEvent:nil]; + } + else + { + NSLog(@"Unknown action type for button"); + } + if([self isVisible]) + { + [self hideView]; + } +} + +#pragma mark - Show Alert + +-(SCLAlertViewResponder *)showTitle:(UIViewController *)vc image:(UIImage *)image color:(UIColor *)color title:(NSString *)title subTitle:(NSString *)subTitle duration:(NSTimeInterval)duration completeText:(NSString *)completeText style:(SCLAlertViewStyle)style +{ + UIWindow *window = [[UIApplication sharedApplication] keyWindow]; + + self.view.alpha = 0; + + [self setBackground]; + + _backgroundView.frame = vc.view.bounds; + + // Add subviews + [window addSubview:_backgroundView]; + [window addSubview:self.view]; + [vc addChildViewController:self]; + + // Alert color/icon + UIColor *viewColor; + UIImage *iconImage; + + // Icon style + switch (style) + { + case Success: + viewColor = UIColorFromRGB(0x22B573); + iconImage = SCLAlertViewStyleKit.imageOfCheckmark; + break; + + case Error: + viewColor = UIColorFromRGB(0xC1272D); + iconImage = SCLAlertViewStyleKit.imageOfCross; + break; + + case Notice: + viewColor = UIColorFromRGB(0x727375); + iconImage = SCLAlertViewStyleKit.imageOfNotice; + break; + + case Warning: + viewColor = UIColorFromRGB(0xFFD110); + iconImage = SCLAlertViewStyleKit.imageOfWarning; + break; + + case Info: + viewColor = UIColorFromRGB(0x2866BF); + iconImage = SCLAlertViewStyleKit.imageOfInfo; + break; + + case Edit: + viewColor = UIColorFromRGB(0xA429FF); + iconImage = SCLAlertViewStyleKit.imageOfEdit; + break; + + case Waiting: + viewColor = UIColorFromRGB(0x6c125d); + break; + + case Custom: + viewColor = color; + iconImage = image; + kCircleIconHeight = kCircleIconHeight * 2; + break; + } + + // Title + if([title stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]].length > 0) + { + self.labelTitle.text = title; + } + + // Subtitle + if([subTitle stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]].length > 0) + { + // No custom text + if (_attributedFormatBlock == nil) + { + _viewText.text = subTitle; + } + else + { + _viewText.attributedText = self.attributedFormatBlock(subTitle); + } + + // Adjust text view size, if necessary + CGSize sz = CGSizeMake(kWindowWidth - 24.0f, kSubTitleHeight); + NSDictionary *attr = @{NSFontAttributeName:self.viewText.font}; + + if (SYSTEM_VERSION_GREATER_THAN_OR_EQUAL_TO(@"7.0")) + { + NSString *str = subTitle; + CGRect r = [str boundingRectWithSize:sz options:NSStringDrawingUsesLineFragmentOrigin attributes:attr context:nil]; + CGFloat ht = ceil(r.size.height); + if (ht < kTextHeight) + { + kWindowHeight -= (kTextHeight - ht); + kTextHeight = ht; + }else{ + kWindowHeight += (ht - kTextHeight); + kTextHeight = ht; + } + } + else + { + NSAttributedString *str =[[NSAttributedString alloc] initWithString:subTitle attributes:attr]; + CGRect r = [str boundingRectWithSize:sz options:NSStringDrawingUsesLineFragmentOrigin context:nil]; + CGFloat ht = ceil(r.size.height) + 10; + if (ht < kTextHeight) + { + kWindowHeight -= (kTextHeight - ht); + kTextHeight = ht; + }else{ + kWindowHeight += (ht - kTextHeight); + kTextHeight = ht; + } + } + } + + // Play sound, if necessary + if(_soundURL != nil) + { + if (_audioPlayer == nil) + { + NSLog(@"You need to set your sound file first"); + } + else + { + [_audioPlayer play]; + } + } + + // Add button, if necessary + if(completeText != nil) + { + [self addDoneButtonWithTitle:completeText]; + } + + // Alert view colour and images + self.circleView.backgroundColor = viewColor; + + if (style == Waiting) { + [self.activityIndicatorView startAnimating]; + } else { + self.circleIconImageView.image = iconImage; + } + + + for (UITextField *textField in _inputs) + { + textField.layer.borderColor = viewColor.CGColor; + } + + for (SCLButton *btn in _buttons) + { + if (btn.completeButtonFormatBlock != nil) + { + [btn parseConfig:btn.completeButtonFormatBlock()]; + } + else if (btn.buttonFormatBlock != nil) + { + [btn parseConfig:btn.buttonFormatBlock()]; + } + else + { + btn.defaultBackgroundColor = viewColor; + } + if (style == Warning) + { + [btn setTitleColor:[UIColor blackColor] forState:UIControlStateNormal]; + } + } + + // Adding duration + if (duration > 0) + { + [durationTimer invalidate]; + durationTimer = [NSTimer scheduledTimerWithTimeInterval:duration + target:self + selector:@selector(hideView) + userInfo:nil + repeats:NO]; + } + + // Show the alert view + [self showView]; + + // Chainable objects + return [[SCLAlertViewResponder alloc] init:self]; +} + +- (void)showSuccess:(UIViewController *)vc title:(NSString *)title subTitle:(NSString *)subTitle closeButtonTitle:(NSString *)closeButtonTitle duration:(NSTimeInterval)duration +{ + [self showTitle:vc image:nil color:nil title:title subTitle:subTitle duration:duration completeText:closeButtonTitle style:Success]; +} + +- (void)showError:(UIViewController *)vc title:(NSString *)title subTitle:(NSString *)subTitle closeButtonTitle:(NSString *)closeButtonTitle duration:(NSTimeInterval)duration +{ + [self showTitle:vc image:nil color:nil title:title subTitle:subTitle duration:duration completeText:closeButtonTitle style:Error]; +} + +- (void)showNotice:(UIViewController *)vc title:(NSString *)title subTitle:(NSString *)subTitle closeButtonTitle:(NSString *)closeButtonTitle duration:(NSTimeInterval)duration +{ + [self showTitle:vc image:nil color:nil title:title subTitle:subTitle duration:duration completeText:closeButtonTitle style:Notice]; +} + +- (void)showWarning:(UIViewController *)vc title:(NSString *)title subTitle:(NSString *)subTitle closeButtonTitle:(NSString *)closeButtonTitle duration:(NSTimeInterval)duration +{ + [self showTitle:vc image:nil color:nil title:title subTitle:subTitle duration:duration completeText:closeButtonTitle style:Warning]; +} + +- (void)showInfo:(UIViewController *)vc title:(NSString *)title subTitle:(NSString *)subTitle closeButtonTitle:(NSString *)closeButtonTitle duration:(NSTimeInterval)duration +{ + [self showTitle:vc image:nil color:nil title:title subTitle:subTitle duration:duration completeText:closeButtonTitle style:Info]; +} + +- (void)showEdit:(UIViewController *)vc title:(NSString *)title subTitle:(NSString *)subTitle closeButtonTitle:(NSString *)closeButtonTitle duration:(NSTimeInterval)duration +{ + [self showTitle:vc image:nil color:nil title:title subTitle:subTitle duration:duration completeText:closeButtonTitle style:Edit]; +} + +- (void)showTitle:(UIViewController *)vc title:(NSString *)title subTitle:(NSString *)subTitle style:(SCLAlertViewStyle)style closeButtonTitle:(NSString *)closeButtonTitle duration:(NSTimeInterval)duration +{ + [self showTitle:vc image:nil color:nil title:title subTitle:subTitle duration:duration completeText:closeButtonTitle style:style]; +} + +- (void)showCustom:(UIViewController *)vc image:(UIImage *)image color:(UIColor *)color title:(NSString *)title subTitle:(NSString *)subTitle closeButtonTitle:(NSString *)closeButtonTitle duration:(NSTimeInterval)duration +{ + [self showTitle:vc image:image color:color title:title subTitle:subTitle duration:duration completeText:closeButtonTitle style:Custom]; +} + +- (void)showWaiting:(UIViewController *)vc title:(NSString *)title subTitle:(NSString *)subTitle closeButtonTitle:(NSString *)closeButtonTitle duration:(NSTimeInterval)duration +{ + [self showTitle:vc image:nil color:nil title:title subTitle:subTitle duration:duration completeText:closeButtonTitle style:Waiting]; +} + +#pragma mark - Visibility + +- (BOOL)isVisible +{ + return (self.backgroundView.alpha && self.view.alpha); +} + +- (void)alertIsDismissed:(DismissBlock)dismissBlock +{ + self.dismissBlock = dismissBlock; +} + +- (CGRect)mainScreenFrame +{ + return [UIScreen mainScreen].bounds; +} + +#pragma mark - Background Effects + +- (void)makeShadowBackground +{ + _backgroundView.autoresizingMask = UIViewAutoresizingFlexibleHeight | UIViewAutoresizingFlexibleWidth; + _backgroundView.backgroundColor = [UIColor blackColor]; + _backgroundView.alpha = 0.7f; + _backgroundOpacity = 0.7f; +} + +- (void)makeBlurBackground +{ + UIImage *image = [UIImage convertViewToImage]; + UIImage *blurSnapshotImage = [image applyBlurWithRadius:5.0f + tintColor:[UIColor colorWithWhite:0.2f + alpha:0.7f] + saturationDeltaFactor:1.8f + maskImage:nil]; + + _backgroundView.image = blurSnapshotImage; + _backgroundView.alpha = 0.0f; + _backgroundOpacity = 1.0f; +} + +- (void)setBackground +{ + switch (_backgroundType) + { + case Shadow: + [self makeShadowBackground]; + break; + + case Blur: + [self makeBlurBackground]; + break; + } +} + +#pragma mark - Show Alert + +- (void)showView +{ + switch (_showAnimationType) + { + case FadeIn: + [self fadeIn]; + break; + + case SlideInFromBottom: + [self slideInFromBottom]; + break; + + case SlideInFromTop: + [self slideInFromTop]; + break; + + case SlideInFromLeft: + [self slideInFromLeft]; + break; + + case SlideInFromRight: + [self slideInFromRight]; + break; + + case SlideInFromCenter: + [self slideInFromCenter]; + break; + + case SlideInToCenter: + [self slideInToCenter]; + break; + } +} + +#pragma mark - Hide Alert + +- (void)hideView +{ + switch (_hideAnimationType) + { + case FadeOut: + [self fadeOut]; + break; + + case SlideOutToBottom: + [self slideOutToBottom]; + break; + + case SlideOutToTop: + [self slideOutToTop]; + break; + + case SlideOutToLeft: + [self slideOutToLeft]; + break; + + case SlideOutToRight: + [self slideOutToRight]; + break; + + case SlideOutToCenter: + [self slideOutToCenter]; + break; + + case SlideOutFromCenter: + [self slideOutFromCenter]; + break; + } + + [_activityIndicatorView stopAnimating]; + + if (self.dismissBlock) + { + self.dismissBlock(); + } +} + +#pragma mark - Hide Animations + +- (void)fadeOut +{ + [UIView animateWithDuration:0.3f animations:^{ + self.backgroundView.alpha = 0.0f; + self.view.alpha = 0.0f; + } completion:^(BOOL completed) { + [self.backgroundView removeFromSuperview]; + [self.view removeFromSuperview]; + [self removeFromParentViewController]; + }]; +} + +- (void)slideOutToBottom +{ + [UIView animateWithDuration:0.3f animations:^{ + CGRect frame = self.view.frame; + frame.origin.y += self.backgroundView.frame.size.height; + self.view.frame = frame; + } completion:^(BOOL completed) { + [self fadeOut]; + }]; +} + +- (void)slideOutToTop +{ + [UIView animateWithDuration:0.3f animations:^{ + CGRect frame = self.view.frame; + frame.origin.y -= self.backgroundView.frame.size.height; + self.view.frame = frame; + } completion:^(BOOL completed) { + [self fadeOut]; + }]; +} + +- (void)slideOutToLeft +{ + [UIView animateWithDuration:0.3f animations:^{ + CGRect frame = self.view.frame; + frame.origin.x -= self.backgroundView.frame.size.width; + self.view.frame = frame; + } completion:^(BOOL completed) { + [self fadeOut]; + }]; +} + +- (void)slideOutToRight +{ + [UIView animateWithDuration:0.3f animations:^{ + CGRect frame = self.view.frame; + frame.origin.x += self.backgroundView.frame.size.width; + self.view.frame = frame; + } completion:^(BOOL completed) { + [self fadeOut]; + }]; +} + +- (void)slideOutToCenter +{ + [UIView animateWithDuration:0.3f animations:^{ + self.view.transform = + CGAffineTransformConcat(CGAffineTransformIdentity, + CGAffineTransformMakeScale(0.1f, 0.1f)); + self.view.alpha = 0.0f; + } completion:^(BOOL completed) { + [self fadeOut]; + }]; +} + +- (void)slideOutFromCenter +{ + [UIView animateWithDuration:0.3f animations:^{ + self.view.transform = + CGAffineTransformConcat(CGAffineTransformIdentity, + CGAffineTransformMakeScale(3.0f, 3.0f)); + self.view.alpha = 0.0f; + } completion:^(BOOL completed) { + [self fadeOut]; + }]; +} + +#pragma mark - Show Animations + +- (void)fadeIn +{ + self.backgroundView.alpha = 0.0f; + self.view.alpha = 0.0f; + + [UIView animateWithDuration:0.3f + delay:0.0f + options:UIViewAnimationOptionCurveEaseIn + animations:^{ + self.backgroundView.alpha = _backgroundOpacity; + self.view.alpha = 1.0f; + } + completion:nil]; +} + +- (void)slideInFromTop +{ + //From Frame + CGRect frame = self.backgroundView.frame; + frame.origin.y = -self.backgroundView.frame.size.height; + self.view.frame = frame; + + [UIView animateWithDuration:0.3f animations:^{ + self.backgroundView.alpha = _backgroundOpacity; + + //To Frame + CGRect frame = self.backgroundView.frame; + frame.origin.y = 0; + self.view.frame = frame; + + self.view.alpha = 1.0f; + } completion:^(BOOL completed) { + [UIView animateWithDuration:0.2f animations:^{ + self.view.center = _backgroundView.center; + }]; + }]; +} + +- (void)slideInFromBottom +{ + //From Frame + CGRect frame = self.backgroundView.frame; + frame.origin.y = self.backgroundView.frame.size.height; + self.view.frame = frame; + + [UIView animateWithDuration:0.3f animations:^{ + self.backgroundView.alpha = _backgroundOpacity; + + //To Frame + CGRect frame = self.backgroundView.frame; + frame.origin.y = 0; + self.view.frame = frame; + + self.view.alpha = 1.0f; + } completion:^(BOOL completed) { + [UIView animateWithDuration:0.2f animations:^{ + self.view.center = _backgroundView.center; + }]; + }]; +} + +- (void)slideInFromLeft +{ + //From Frame + CGRect frame = self.backgroundView.frame; + frame.origin.x = -self.backgroundView.frame.size.width; + self.view.frame = frame; + + [UIView animateWithDuration:0.3f animations:^{ + self.backgroundView.alpha = _backgroundOpacity; + + //To Frame + CGRect frame = self.backgroundView.frame; + frame.origin.x = 0; + self.view.frame = frame; + + self.view.alpha = 1.0f; + } completion:^(BOOL completed) { + [UIView animateWithDuration:0.2f animations:^{ + self.view.center = _backgroundView.center; + }]; + }]; +} + +- (void)slideInFromRight +{ + //From Frame + CGRect frame = self.backgroundView.frame; + frame.origin.x = self.backgroundView.frame.size.width; + self.view.frame = frame; + + [UIView animateWithDuration:0.3f animations:^{ + self.backgroundView.alpha = _backgroundOpacity; + + //To Frame + CGRect frame = self.backgroundView.frame; + frame.origin.x = 0; + self.view.frame = frame; + + self.view.alpha = 1.0f; + } completion:^(BOOL completed) { + [UIView animateWithDuration:0.2f animations:^{ + self.view.center = _backgroundView.center; + }]; + }]; +} + +- (void)slideInFromCenter +{ + //From + self.view.transform = CGAffineTransformConcat(CGAffineTransformIdentity, + CGAffineTransformMakeScale(3.0f, 3.0f)); + self.view.alpha = 0.0f; + + [UIView animateWithDuration:0.3f animations:^{ + self.backgroundView.alpha = _backgroundOpacity; + + //To + self.view.transform = CGAffineTransformConcat(CGAffineTransformIdentity, + CGAffineTransformMakeScale(1.0f, 1.0f)); + self.view.alpha = 1.0f; + } completion:^(BOOL completed) { + [UIView animateWithDuration:0.2f animations:^{ + self.view.center = _backgroundView.center; + }]; + }]; +} + +- (void)slideInToCenter +{ + //From + self.view.transform = CGAffineTransformConcat(CGAffineTransformIdentity, + CGAffineTransformMakeScale(0.1f, 0.1f)); + self.view.alpha = 0.0f; + + [UIView animateWithDuration:0.3f animations:^{ + self.backgroundView.alpha = _backgroundOpacity; + + //To + self.view.transform = CGAffineTransformConcat(CGAffineTransformIdentity, + CGAffineTransformMakeScale(1.0f, 1.0f)); + self.view.alpha = 1.0f; + } completion:^(BOOL completed) { + [UIView animateWithDuration:0.2f animations:^{ + self.view.center = _backgroundView.center; + }]; + }]; +} + +@end diff --git a/ios/Pods/SCLAlertView-Objective-C/SCLAlertView/SCLAlertViewResponder.h b/ios/Pods/SCLAlertView-Objective-C/SCLAlertView/SCLAlertViewResponder.h new file mode 100644 index 000000000..2704dcb42 --- /dev/null +++ b/ios/Pods/SCLAlertView-Objective-C/SCLAlertView/SCLAlertViewResponder.h @@ -0,0 +1,26 @@ +// +// SCLAlertViewResponder.h +// SCLAlertView +// +// Created by Diogo Autilio on 9/26/14. +// Copyright (c) 2014 AnyKey Entertainment. All rights reserved. +// + +#import +#import "SCLAlertView.h" + +@interface SCLAlertViewResponder : NSObject + +/** TODO + * + * TODO + */ +- (instancetype)init:(SCLAlertView *)alertview; + +/** TODO + * + * TODO + */ +- (void)close; + +@end diff --git a/ios/Pods/SCLAlertView-Objective-C/SCLAlertView/SCLAlertViewResponder.m b/ios/Pods/SCLAlertView-Objective-C/SCLAlertView/SCLAlertViewResponder.m new file mode 100644 index 000000000..c55dcc7aa --- /dev/null +++ b/ios/Pods/SCLAlertView-Objective-C/SCLAlertView/SCLAlertViewResponder.m @@ -0,0 +1,45 @@ +// +// SCLAlertViewResponder.m +// SCLAlertView +// +// Created by Diogo Autilio on 9/26/14. +// Copyright (c) 2014 AnyKey Entertainment. All rights reserved. +// + +#import "SCLAlertViewResponder.h" + +@interface SCLAlertViewResponder () + +@property SCLAlertView *alertview; + +@end + +@implementation SCLAlertViewResponder + +// +//// Allow alerts to be closed/renamed in a chainable manner +//// Example: SCLAlertView().showSuccess(self, title: "Test", subTitle: "Value").close() + +// Initialisation and Title/Subtitle/Close functions +- (instancetype)init:(SCLAlertView *)alertview +{ + self.alertview = alertview; + return self; +} + +- (void)setTitletitle:(NSString *)title +{ + self.alertview.labelTitle.text = title; +} + +- (void)setSubTitle:(NSString *)subTitle +{ + self.alertview.viewText.text = subTitle; +} + +- (void)close +{ + [self.alertview hideView]; +} + +@end diff --git a/ios/Pods/SCLAlertView-Objective-C/SCLAlertView/SCLAlertViewStyleKit.h b/ios/Pods/SCLAlertView-Objective-C/SCLAlertView/SCLAlertViewStyleKit.h new file mode 100644 index 000000000..58aca3a80 --- /dev/null +++ b/ios/Pods/SCLAlertView-Objective-C/SCLAlertView/SCLAlertViewStyleKit.h @@ -0,0 +1,87 @@ +// +// SCLAlertViewStyleKit.h +// SCLAlertView +// +// Created by Diogo Autilio on 9/26/14. +// Copyright (c) 2014 AnyKey Entertainment. All rights reserved. +// + +#import +#import + +@interface SCLAlertViewStyleKit : NSObject + +// Images +/** TODO + * + * TODO + */ ++ (UIImage*)imageOfCheckmark; + +/** TODO + * + * TODO + */ ++ (UIImage*)imageOfCross; + +/** TODO + * + * TODO + */ ++ (UIImage*)imageOfNotice; + +/** TODO + * + * TODO + */ ++ (UIImage*)imageOfWarning; + +/** TODO + * + * TODO + */ ++ (UIImage*)imageOfInfo; + +/** TODO + * + * TODO + */ ++ (UIImage*)imageOfEdit; + +/** TODO + * + * TODO + */ ++ (void)drawCheckmark; + +/** TODO + * + * TODO + */ ++ (void)drawCross; + +/** TODO + * + * TODO + */ ++ (void)drawNotice; + +/** TODO + * + * TODO + */ ++ (void)drawWarning; + +/** TODO + * + * TODO + */ ++ (void)drawInfo; + +/** TODO + * + * TODO + */ ++ (void)drawEdit; + +@end diff --git a/ios/Pods/SCLAlertView-Objective-C/SCLAlertView/SCLAlertViewStyleKit.m b/ios/Pods/SCLAlertView-Objective-C/SCLAlertView/SCLAlertViewStyleKit.m new file mode 100644 index 000000000..0a487aab1 --- /dev/null +++ b/ios/Pods/SCLAlertView-Objective-C/SCLAlertView/SCLAlertViewStyleKit.m @@ -0,0 +1,331 @@ +// +// SCLAlertViewStyleKit.m +// SCLAlertView +// +// Created by Diogo Autilio on 9/26/14. +// Copyright (c) 2014 AnyKey Entertainment. All rights reserved. +// + +#import "SCLAlertViewStyleKit.h" + +// ------------------------------------ +// Icon drawing +// Code generated by PaintCode +// ------------------------------------ +@implementation SCLAlertViewStyleKit + +#pragma mark - Cache + +static UIImage *imageOfCheckmark = nil; +static UIImage *imageOfCross = nil; +static UIImage *imageOfNotice = nil; +static UIImage *imageOfWarning = nil; +static UIImage *imageOfInfo = nil; +static UIImage *imageOfEdit = nil; + +#pragma mark - Initialization + ++ (void)initialize +{ + // Do something +} + +#pragma mark - Drawing Methods + ++ (void)drawCheckmark +{ + // Checkmark Shape Drawing + UIBezierPath *checkmarkShapePath = [[UIBezierPath alloc] init]; + [checkmarkShapePath moveToPoint:CGPointMake(73.25, 14.05)]; + [checkmarkShapePath addCurveToPoint:CGPointMake(64.51, 13.86) controlPoint1: CGPointMake(70.98, 11.44) controlPoint2: CGPointMake(66.78, 11.26)]; + [checkmarkShapePath addLineToPoint:CGPointMake(27.46, 52)]; + [checkmarkShapePath addLineToPoint:CGPointMake(15.75, 39.54)]; + [checkmarkShapePath addCurveToPoint:CGPointMake(6.84, 39.54) controlPoint1: CGPointMake(13.48, 36.93) controlPoint2: CGPointMake(9.28, 36.93)]; + [checkmarkShapePath addCurveToPoint:CGPointMake(6.84, 49.02) controlPoint1: CGPointMake(4.39, 42.14) controlPoint2: CGPointMake(4.39, 46.42)]; + [checkmarkShapePath addLineToPoint:CGPointMake(22.91, 66.14)]; + [checkmarkShapePath addCurveToPoint:CGPointMake(27.28, 68) controlPoint1: CGPointMake(24.14, 67.44) controlPoint2: CGPointMake(25.71, 68)]; + [checkmarkShapePath addCurveToPoint:CGPointMake(31.65, 66.14) controlPoint1: CGPointMake(28.86, 68) controlPoint2: CGPointMake(30.43, 67.26)]; + [checkmarkShapePath addLineToPoint:CGPointMake(73.08, 23.35)]; + [checkmarkShapePath addCurveToPoint:CGPointMake(73.25, 14.05) controlPoint1: CGPointMake(75.52, 20.75) controlPoint2: CGPointMake(75.7, 16.65)]; + [checkmarkShapePath closePath]; + checkmarkShapePath.miterLimit = 4; + + [[UIColor whiteColor] setFill]; + [checkmarkShapePath fill]; +} + ++ (void)drawCross +{ + // Cross Shape Drawing + UIBezierPath *crossShapePath = [[UIBezierPath alloc] init]; + [crossShapePath moveToPoint:CGPointMake(10, 70)]; + [crossShapePath addLineToPoint:CGPointMake(70, 10)]; + [crossShapePath moveToPoint:CGPointMake(10, 10)]; + [crossShapePath addLineToPoint:CGPointMake(70, 70)]; + + crossShapePath.lineCapStyle = kCGLineCapRound; + crossShapePath.lineJoinStyle = kCGLineJoinRound; + + [[UIColor whiteColor] setStroke]; + crossShapePath.lineWidth = 14; + [crossShapePath stroke]; +} + ++ (void)drawNotice +{ + // Notice Shape Drawing + UIBezierPath *noticeShapePath = [[UIBezierPath alloc] init]; + [noticeShapePath moveToPoint:CGPointMake(72, 48.54)]; + [noticeShapePath addLineToPoint:CGPointMake(72, 39.9)]; + [noticeShapePath addCurveToPoint:CGPointMake(66.38, 34.01) controlPoint1: CGPointMake(72, 36.76) controlPoint2: CGPointMake(69.48, 34.01)]; + [noticeShapePath addCurveToPoint:CGPointMake(61.53, 35.97) controlPoint1: CGPointMake(64.82, 34.01) controlPoint2: CGPointMake(62.69, 34.8)]; + [noticeShapePath addCurveToPoint:CGPointMake(60.36, 35.78) controlPoint1: CGPointMake(61.33, 35.97) controlPoint2: CGPointMake(62.3, 35.78)]; + [noticeShapePath addLineToPoint:CGPointMake(60.36, 33.22)]; + [noticeShapePath addCurveToPoint:CGPointMake(54.16, 26.16) controlPoint1: CGPointMake(60.36, 29.3) controlPoint2: CGPointMake(57.65, 26.16)]; + [noticeShapePath addCurveToPoint:CGPointMake(48.73, 29.89) controlPoint1: CGPointMake(51.64, 26.16) controlPoint2: CGPointMake(50.67, 27.73)]; + [noticeShapePath addLineToPoint:CGPointMake(48.73, 28.71)]; + [noticeShapePath addCurveToPoint:CGPointMake(43.49, 21.64) controlPoint1: CGPointMake(48.73, 24.78) controlPoint2: CGPointMake(46.98, 21.64)]; + [noticeShapePath addCurveToPoint:CGPointMake(39.03, 25.37) controlPoint1: CGPointMake(40.97, 21.64) controlPoint2: CGPointMake(39.03, 23.01)]; + [noticeShapePath addLineToPoint:CGPointMake(39.03, 9.07)]; + [noticeShapePath addCurveToPoint:CGPointMake(32.24, 2) controlPoint1: CGPointMake(39.03, 5.14) controlPoint2: CGPointMake(35.73, 2)]; + [noticeShapePath addCurveToPoint:CGPointMake(25.45, 9.07) controlPoint1: CGPointMake(28.56, 2) controlPoint2: CGPointMake(25.45, 5.14)]; + [noticeShapePath addLineToPoint:CGPointMake(25.45, 41.47)]; + [noticeShapePath addCurveToPoint:CGPointMake(24.29, 43.44) controlPoint1: CGPointMake(25.45, 42.45) controlPoint2: CGPointMake(24.68, 43.04)]; + [noticeShapePath addCurveToPoint:CGPointMake(9.55, 43.04) controlPoint1: CGPointMake(16.73, 40.88) controlPoint2: CGPointMake(11.88, 40.69)]; + [noticeShapePath addCurveToPoint:CGPointMake(8, 46.58) controlPoint1: CGPointMake(8.58, 43.83) controlPoint2: CGPointMake(8, 45.2)]; + [noticeShapePath addCurveToPoint:CGPointMake(14.4, 55.81) controlPoint1: CGPointMake(8.19, 50.31) controlPoint2: CGPointMake(12.07, 53.84)]; + [noticeShapePath addLineToPoint:CGPointMake(27.2, 69.56)]; + [noticeShapePath addCurveToPoint:CGPointMake(42.91, 77.8) controlPoint1: CGPointMake(30.5, 74.47) controlPoint2: CGPointMake(35.73, 77.21)]; + [noticeShapePath addCurveToPoint:CGPointMake(43.88, 77.8) controlPoint1: CGPointMake(43.3, 77.8) controlPoint2: CGPointMake(43.68, 77.8)]; + [noticeShapePath addCurveToPoint:CGPointMake(47.18, 78) controlPoint1: CGPointMake(45.04, 77.8) controlPoint2: CGPointMake(46.01, 78)]; + [noticeShapePath addLineToPoint:CGPointMake(48.34, 78)]; + [noticeShapePath addLineToPoint:CGPointMake(48.34, 78)]; + [noticeShapePath addCurveToPoint:CGPointMake(71.61, 52.08) controlPoint1: CGPointMake(56.48, 78) controlPoint2: CGPointMake(69.87, 75.05)]; + [noticeShapePath addCurveToPoint:CGPointMake(72, 48.54) controlPoint1: CGPointMake(71.81, 51.29) controlPoint2: CGPointMake(72, 49.72)]; + [noticeShapePath closePath]; + noticeShapePath.miterLimit = 4; + + [[UIColor whiteColor] setFill]; + [noticeShapePath fill]; +} + ++ (void)drawWarning +{ + // Color Declarations + UIColor *greyColor = [UIColor colorWithRed:0.236 green:0.236 blue:0.236 alpha:1.000]; + + // Warning Group + // Warning Circle Drawing + UIBezierPath *warningCirclePath = [[UIBezierPath alloc] init]; + [warningCirclePath moveToPoint:CGPointMake(40.94, 63.39)]; + [warningCirclePath addCurveToPoint:CGPointMake(36.03, 65.55) controlPoint1: CGPointMake(39.06, 63.39) controlPoint2: CGPointMake(37.36, 64.18)]; + [warningCirclePath addCurveToPoint:CGPointMake(34.14, 70.45) controlPoint1: CGPointMake(34.9, 66.92) controlPoint2: CGPointMake(34.14, 68.49)]; + [warningCirclePath addCurveToPoint:CGPointMake(36.22, 75.54) controlPoint1: CGPointMake(34.14, 72.41) controlPoint2: CGPointMake(34.9, 74.17)]; + [warningCirclePath addCurveToPoint:CGPointMake(40.94, 77.5) controlPoint1: CGPointMake(37.54, 76.91) controlPoint2: CGPointMake(39.06, 77.5)]; + [warningCirclePath addCurveToPoint:CGPointMake(45.86, 75.35) controlPoint1: CGPointMake(42.83, 77.5) controlPoint2: CGPointMake(44.53, 76.72)]; + [warningCirclePath addCurveToPoint:CGPointMake(47.93, 70.45) controlPoint1: CGPointMake(47.18, 74.17) controlPoint2: CGPointMake(47.93, 72.41)]; + [warningCirclePath addCurveToPoint:CGPointMake(45.86, 65.35) controlPoint1: CGPointMake(47.93, 68.49) controlPoint2: CGPointMake(47.18, 66.72)]; + [warningCirclePath addCurveToPoint:CGPointMake(40.94, 63.39) controlPoint1: CGPointMake(44.53, 64.18) controlPoint2: CGPointMake(42.83, 63.39)]; + [warningCirclePath closePath]; + warningCirclePath.miterLimit = 4; + + [greyColor setFill]; + [warningCirclePath fill]; + + + //// Warning Shape Drawing + UIBezierPath *warningShapePath = [[UIBezierPath alloc] init]; + [warningShapePath moveToPoint:CGPointMake(46.23, 4.26)]; + [warningShapePath addCurveToPoint:CGPointMake(40.94, 2.5) controlPoint1: CGPointMake(44.91, 3.09) controlPoint2: CGPointMake(43.02, 2.5)]; + [warningShapePath addCurveToPoint:CGPointMake(34.71, 4.26) controlPoint1: CGPointMake(38.68, 2.5) controlPoint2: CGPointMake(36.03, 3.09)]; + [warningShapePath addCurveToPoint:CGPointMake(31.5, 8.77) controlPoint1: CGPointMake(33.01, 5.44) controlPoint2: CGPointMake(31.5, 7.01)]; + [warningShapePath addLineToPoint:CGPointMake(31.5, 19.36)]; + [warningShapePath addLineToPoint:CGPointMake(34.71, 54.44)]; + [warningShapePath addCurveToPoint:CGPointMake(40.38, 58.16) controlPoint1: CGPointMake(34.9, 56.2) controlPoint2: CGPointMake(36.41, 58.16)]; + [warningShapePath addCurveToPoint:CGPointMake(45.67, 54.44) controlPoint1: CGPointMake(44.34, 58.16) controlPoint2: CGPointMake(45.67, 56.01)]; + [warningShapePath addLineToPoint:CGPointMake(48.5, 19.36)]; + [warningShapePath addLineToPoint:CGPointMake(48.5, 8.77)]; + [warningShapePath addCurveToPoint:CGPointMake(46.23, 4.26) controlPoint1: CGPointMake(48.5, 7.01) controlPoint2: CGPointMake(47.74, 5.44)]; + [warningShapePath closePath]; + warningShapePath.miterLimit = 4; + + [greyColor setFill]; + [warningShapePath fill]; +} + ++ (void)drawInfo +{ + // Color Declarations + UIColor *color0 = [UIColor colorWithRed:1.000 green:1.000 blue:1.000 alpha:1.000]; + + // Info Shape Drawing + UIBezierPath *infoShapePath = [[UIBezierPath alloc] init]; + [infoShapePath moveToPoint:CGPointMake(45.66, 15.96)]; + [infoShapePath addCurveToPoint:CGPointMake(45.66, 5.22) controlPoint1: CGPointMake(48.78, 12.99) controlPoint2: CGPointMake(48.78, 8.19)]; + [infoShapePath addCurveToPoint:CGPointMake(34.34, 5.22) controlPoint1: CGPointMake(42.53, 2.26) controlPoint2: CGPointMake(37.47, 2.26)]; + [infoShapePath addCurveToPoint:CGPointMake(34.34, 15.96) controlPoint1: CGPointMake(31.22, 8.19) controlPoint2: CGPointMake(31.22, 12.99)]; + [infoShapePath addCurveToPoint:CGPointMake(45.66, 15.96) controlPoint1: CGPointMake(37.47, 18.92) controlPoint2: CGPointMake(42.53, 18.92)]; + [infoShapePath closePath]; + + [infoShapePath moveToPoint:CGPointMake(48, 69.41)]; + [infoShapePath addCurveToPoint:CGPointMake(40, 77) controlPoint1: CGPointMake(48, 73.58) controlPoint2: CGPointMake(44.4, 77)]; + [infoShapePath addLineToPoint:CGPointMake(40, 77)]; + [infoShapePath addCurveToPoint:CGPointMake(32, 69.41) controlPoint1: CGPointMake(35.6, 77) controlPoint2: CGPointMake(32, 73.58)]; + [infoShapePath addLineToPoint:CGPointMake(32, 35.26)]; + [infoShapePath addCurveToPoint:CGPointMake(40, 27.67) controlPoint1: CGPointMake(32, 31.08) controlPoint2: CGPointMake(35.6, 27.67)]; + [infoShapePath addLineToPoint:CGPointMake(40, 27.67)]; + [infoShapePath addCurveToPoint:CGPointMake(48, 35.26) controlPoint1: CGPointMake(44.4, 27.67) controlPoint2: CGPointMake(48, 31.08)]; + [infoShapePath addLineToPoint:CGPointMake(48, 69.41)]; + [infoShapePath closePath]; + + [color0 setFill]; + [infoShapePath fill]; +} + ++ (void)drawEdit +{ + // Color Declarations + UIColor *color = [UIColor colorWithRed:1.0 green:1.0 blue:1.0 alpha:1.0]; + + // Edit shape Drawing + UIBezierPath *editPathPath = [[UIBezierPath alloc] init]; + [editPathPath moveToPoint:CGPointMake(71, 2.7)]; + [editPathPath addCurveToPoint:CGPointMake(71.9, 15.2) controlPoint1:CGPointMake(74.7, 5.9) controlPoint2:CGPointMake(75.1, 11.6)]; + [editPathPath addLineToPoint:CGPointMake(64.5, 23.7)]; + [editPathPath addLineToPoint:CGPointMake(49.9, 11.1)]; + [editPathPath addLineToPoint:CGPointMake(57.3, 2.6)]; + [editPathPath addCurveToPoint:CGPointMake(69.7, 1.7) controlPoint1:CGPointMake(60.4, -1.1) controlPoint2:CGPointMake(66.1, -1.5)]; + [editPathPath addLineToPoint:CGPointMake(71, 2.7)]; + [editPathPath addLineToPoint:CGPointMake(71, 2.7)]; + [editPathPath closePath]; + + [editPathPath moveToPoint:CGPointMake(47.8, 13.5)]; + [editPathPath addLineToPoint:CGPointMake(13.4, 53.1)]; + [editPathPath addLineToPoint:CGPointMake(15.7, 55.1)]; + [editPathPath addLineToPoint:CGPointMake(50.1, 15.5)]; + [editPathPath addLineToPoint:CGPointMake(47.8, 13.5)]; + [editPathPath addLineToPoint:CGPointMake(47.8, 13.5)]; + [editPathPath closePath]; + + [editPathPath moveToPoint:CGPointMake(17.7, 56.7)]; + [editPathPath addLineToPoint:CGPointMake(23.8, 62.2)]; + [editPathPath addLineToPoint:CGPointMake(58.2, 22.6)]; + [editPathPath addLineToPoint:CGPointMake(52, 17.1)]; + [editPathPath addLineToPoint:CGPointMake(17.7, 56.7)]; + [editPathPath addLineToPoint:CGPointMake(17.7, 56.7)]; + [editPathPath closePath]; + + [editPathPath moveToPoint:CGPointMake(25.8, 63.8)]; + [editPathPath addLineToPoint:CGPointMake(60.1, 24.2)]; + [editPathPath addLineToPoint:CGPointMake(62.3, 26.1)]; + [editPathPath addLineToPoint:CGPointMake(28.1, 65.7)]; + [editPathPath addLineToPoint:CGPointMake(25.8, 63.8)]; + [editPathPath addLineToPoint:CGPointMake(25.8, 63.8)]; + [editPathPath closePath]; + + [editPathPath moveToPoint:CGPointMake(25.9, 68.1)]; + [editPathPath addLineToPoint:CGPointMake(4.2, 79.5)]; + [editPathPath addLineToPoint:CGPointMake(11.3, 55.5)]; + [editPathPath addLineToPoint:CGPointMake(25.9, 68.1)]; + [editPathPath closePath]; + + editPathPath.miterLimit = 4; + editPathPath.usesEvenOddFillRule = YES; + [color setFill]; + [editPathPath fill]; +} + +#pragma mark - Images + ++ (UIImage*)imageOfCheckmark +{ + if (imageOfCheckmark != nil) + { + return imageOfCheckmark; + } + + UIGraphicsBeginImageContextWithOptions(CGSizeMake(80, 80), NO, 0); + [SCLAlertViewStyleKit drawCheckmark]; + imageOfCheckmark = UIGraphicsGetImageFromCurrentImageContext(); + UIGraphicsEndImageContext(); + + return imageOfCheckmark; +} + + ++ (UIImage*)imageOfCross +{ + if (imageOfCross != nil) + { + return imageOfCross; + } + + UIGraphicsBeginImageContextWithOptions(CGSizeMake(80, 80), NO, 0); + [SCLAlertViewStyleKit drawCross]; + imageOfCross = UIGraphicsGetImageFromCurrentImageContext(); + UIGraphicsEndImageContext(); + + return imageOfCross; +} + ++ (UIImage*)imageOfNotice +{ + if (imageOfNotice != nil) + { + return imageOfNotice; + } + + UIGraphicsBeginImageContextWithOptions(CGSizeMake(80, 80), NO, 0); + [SCLAlertViewStyleKit drawNotice]; + imageOfNotice = UIGraphicsGetImageFromCurrentImageContext(); + UIGraphicsEndImageContext(); + + return imageOfNotice; +} + ++ (UIImage*)imageOfWarning +{ + if (imageOfWarning != nil) + { + return imageOfWarning; + } + + UIGraphicsBeginImageContextWithOptions(CGSizeMake(80, 80), NO, 0); + [SCLAlertViewStyleKit drawWarning]; + imageOfWarning = UIGraphicsGetImageFromCurrentImageContext(); + UIGraphicsEndImageContext(); + + return imageOfWarning; +} + ++ (UIImage*)imageOfInfo +{ + if (imageOfInfo != nil) + { + return imageOfInfo; + } + + UIGraphicsBeginImageContextWithOptions(CGSizeMake(80, 80), NO, 0); + [SCLAlertViewStyleKit drawInfo]; + imageOfInfo = UIGraphicsGetImageFromCurrentImageContext(); + UIGraphicsEndImageContext(); + + return imageOfInfo; +} + ++ (UIImage*)imageOfEdit +{ + if (imageOfEdit != nil) + { + return imageOfEdit; + } + + UIGraphicsBeginImageContextWithOptions(CGSizeMake(80, 80), NO, 0); + [SCLAlertViewStyleKit drawEdit]; + imageOfEdit = UIGraphicsGetImageFromCurrentImageContext(); + UIGraphicsEndImageContext(); + + return imageOfEdit; +} + +@end diff --git a/ios/Pods/SCLAlertView-Objective-C/SCLAlertView/SCLButton.h b/ios/Pods/SCLAlertView-Objective-C/SCLAlertView/SCLButton.h new file mode 100644 index 000000000..5957853c5 --- /dev/null +++ b/ios/Pods/SCLAlertView-Objective-C/SCLAlertView/SCLButton.h @@ -0,0 +1,83 @@ +// +// SCLButton.h +// SCLAlertView +// +// Created by Diogo Autilio on 9/26/14. +// Copyright (c) 2014 AnyKey Entertainment. All rights reserved. +// + +#import + +@interface SCLButton : UIButton + +typedef void (^SCLActionBlock)(void); +typedef BOOL (^SCLValidationBlock)(void); +typedef NSDictionary* (^CompleteButtonFormatBlock)(void); +typedef NSDictionary* (^ButtonFormatBlock)(void); + +// Action Types +typedef NS_ENUM(NSInteger, SCLActionType) +{ + None, + Selector, + Block +}; + +/** Set button action type. + * + * Holds the button action type. + */ +@property SCLActionType actionType; + +/** TODO + * + * TODO + */ +@property (nonatomic, copy) SCLActionBlock actionBlock; + +/** TODO + * + * TODO + */ +@property (nonatomic, copy) SCLValidationBlock validationBlock; + +/** Set Complete button format block. + * + * Holds the complete button format block. + * Support keys : backgroundColor, borderColor, textColor + */ +@property (nonatomic, copy) CompleteButtonFormatBlock completeButtonFormatBlock; + +/** Set button format block. + * + * Holds the button format block. + * Support keys : backgroundColor, borderColor, textColor + */ +@property (nonatomic, copy) ButtonFormatBlock buttonFormatBlock; + +/** TODO + * + * TODO + */ +@property (nonatomic, strong) UIColor *defaultBackgroundColor; + +/** TODO + * + * TODO + */ +@property id target; + +/** TODO + * + * TODO + */ +@property SEL selector; + +/** Parse button configuration + * + * Parse ButtonFormatBlock and CompleteButtonFormatBlock setting custom configuration. + * Set keys : backgroundColor, borderColor, textColor + */ +- (void)parseConfig:(NSDictionary *)buttonConfig; + +@end diff --git a/ios/Pods/SCLAlertView-Objective-C/SCLAlertView/SCLButton.m b/ios/Pods/SCLAlertView-Objective-C/SCLAlertView/SCLButton.m new file mode 100644 index 000000000..3bcc81971 --- /dev/null +++ b/ios/Pods/SCLAlertView-Objective-C/SCLAlertView/SCLButton.m @@ -0,0 +1,93 @@ +// +// SCLButton.m +// SCLAlertView +// +// Created by Diogo Autilio on 9/26/14. +// Copyright (c) 2014 AnyKey Entertainment. All rights reserved. +// + +#import "SCLButton.h" + +@implementation SCLButton + +- (id)init +{ + self = [super init]; + if (self) { + // Do something + } + return self; +} + +- (id)initWithCoder:(NSCoder *)aDecoder +{ + self = [super initWithCoder:aDecoder]; + if(self) { + // Do something + } + return self; +} + +- (id)initWithFrame:(CGRect)frame +{ + self = [super initWithFrame:frame]; + if (self) { + // Do something + } + return self; +} + +- (void)setHighlighted:(BOOL)highlighted +{ + self.backgroundColor = (highlighted) ? [self darkerColorForColor:_defaultBackgroundColor] : _defaultBackgroundColor; + [super setHighlighted:highlighted]; +} + +- (void)setDefaultBackgroundColor:(UIColor *)defaultBackgroundColor +{ + self.backgroundColor = _defaultBackgroundColor = defaultBackgroundColor; +} + +#pragma mark - Button Apperance + +- (void)parseConfig:(NSDictionary *)buttonConfig +{ + if (buttonConfig[@"backgroundColor"]) + { + self.defaultBackgroundColor = buttonConfig[@"backgroundColor"]; + } + if (buttonConfig[@"borderColor"]) + { + self.layer.borderColor = ((UIColor*)buttonConfig[@"borderColor"]).CGColor; + } + if (buttonConfig[@"textColor"]) + { + [self setTitleColor:buttonConfig[@"textColor"] forState:UIControlStateNormal]; + } +} + +#pragma mark - Helpers + +- (UIColor *)darkerColorForColor:(UIColor *)color +{ + CGFloat r, g, b, a; + if ([color getRed:&r green:&g blue:&b alpha:&a]) + return [UIColor colorWithRed:MAX(r - 0.2f, 0.0f) + green:MAX(g - 0.2f, 0.0f) + blue:MAX(b - 0.2f, 0.0f) + alpha:a]; + return nil; +} + +- (UIColor *)lighterColorForColor:(UIColor *)color +{ + CGFloat r, g, b, a; + if ([color getRed:&r green:&g blue:&b alpha:&a]) + return [UIColor colorWithRed:MIN(r + 0.2f, 1.0f) + green:MIN(g + 0.2f, 1.0f) + blue:MIN(b + 0.2f, 1.0f) + alpha:a]; + return nil; +} + +@end diff --git a/ios/Pods/SCLAlertView-Objective-C/SCLAlertView/UIImage+ImageEffects.h b/ios/Pods/SCLAlertView-Objective-C/SCLAlertView/UIImage+ImageEffects.h new file mode 100755 index 000000000..d3bbfb8d0 --- /dev/null +++ b/ios/Pods/SCLAlertView-Objective-C/SCLAlertView/UIImage+ImageEffects.h @@ -0,0 +1,109 @@ +/* + File: UIImage+ImageEffects.h + Abstract: This is a category of UIImage that adds methods to apply blur and tint effects to an image. This is the code you’ll want to look out to find out how to use vImage to efficiently calculate a blur. + Version: 1.0 + + Disclaimer: IMPORTANT: This Apple software is supplied to you by Apple + Inc. ("Apple") in consideration of your agreement to the following + terms, and your use, installation, modification or redistribution of + this Apple software constitutes acceptance of these terms. If you do + not agree with these terms, please do not use, install, modify or + redistribute this Apple software. + + In consideration of your agreement to abide by the following terms, and + subject to these terms, Apple grants you a personal, non-exclusive + license, under Apple's copyrights in this original Apple software (the + "Apple Software"), to use, reproduce, modify and redistribute the Apple + Software, with or without modifications, in source and/or binary forms; + provided that if you redistribute the Apple Software in its entirety and + without modifications, you must retain this notice and the following + text and disclaimers in all such redistributions of the Apple Software. + Neither the name, trademarks, service marks or logos of Apple Inc. may + be used to endorse or promote products derived from the Apple Software + without specific prior written permission from Apple. Except as + expressly stated in this notice, no other rights or licenses, express or + implied, are granted by Apple herein, including but not limited to any + patent rights that may be infringed by your derivative works or by other + works in which the Apple Software may be incorporated. + + The Apple Software is provided by Apple on an "AS IS" basis. APPLE + MAKES NO WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION + THE IMPLIED WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS + FOR A PARTICULAR PURPOSE, REGARDING THE APPLE SOFTWARE OR ITS USE AND + OPERATION ALONE OR IN COMBINATION WITH YOUR PRODUCTS. + + IN NO EVENT SHALL APPLE BE LIABLE FOR ANY SPECIAL, INDIRECT, INCIDENTAL + OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + INTERRUPTION) ARISING IN ANY WAY OUT OF THE USE, REPRODUCTION, + MODIFICATION AND/OR DISTRIBUTION OF THE APPLE SOFTWARE, HOWEVER CAUSED + AND WHETHER UNDER THEORY OF CONTRACT, TORT (INCLUDING NEGLIGENCE), + STRICT LIABILITY OR OTHERWISE, EVEN IF APPLE HAS BEEN ADVISED OF THE + POSSIBILITY OF SUCH DAMAGE. + + Copyright (C) 2013 Apple Inc. All Rights Reserved. + + + Copyright © 2013 Apple Inc. All rights reserved. + WWDC 2013 License + + NOTE: This Apple Software was supplied by Apple as part of a WWDC 2013 + Session. Please refer to the applicable WWDC 2013 Session for further + information. + + IMPORTANT: This Apple software is supplied to you by Apple Inc. + ("Apple") in consideration of your agreement to the following terms, and + your use, installation, modification or redistribution of this Apple + software constitutes acceptance of these terms. If you do not agree with + these terms, please do not use, install, modify or redistribute this + Apple software. + + In consideration of your agreement to abide by the following terms, and + subject to these terms, Apple grants you a non-exclusive license, under + Apple's copyrights in this original Apple software (the "Apple + Software"), to use, reproduce, modify and redistribute the Apple + Software, with or without modifications, in source and/or binary forms; + provided that if you redistribute the Apple Software in its entirety and + without modifications, you must retain this notice and the following + text and disclaimers in all such redistributions of the Apple Software. + Neither the name, trademarks, service marks or logos of Apple Inc. may + be used to endorse or promote products derived from the Apple Software + without specific prior written permission from Apple. Except as + expressly stated in this notice, no other rights or licenses, express or + implied, are granted by Apple herein, including but not limited to any + patent rights that may be infringed by your derivative works or by other + works in which the Apple Software may be incorporated. + + The Apple Software is provided by Apple on an "AS IS" basis. APPLE MAKES + NO WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION THE + IMPLIED WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS FOR + A PARTICULAR PURPOSE, REGARDING THE APPLE SOFTWARE OR ITS USE AND + OPERATION ALONE OR IN COMBINATION WITH YOUR PRODUCTS. + + IN NO EVENT SHALL APPLE BE LIABLE FOR ANY SPECIAL, INDIRECT, INCIDENTAL + OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + INTERRUPTION) ARISING IN ANY WAY OUT OF THE USE, REPRODUCTION, + MODIFICATION AND/OR DISTRIBUTION OF THE APPLE SOFTWARE, HOWEVER CAUSED + AND WHETHER UNDER THEORY OF CONTRACT, TORT (INCLUDING NEGLIGENCE), + STRICT LIABILITY OR OTHERWISE, EVEN IF APPLE HAS BEEN ADVISED OF THE + POSSIBILITY OF SUCH DAMAGE. + + EA1002 + 5/3/2013 + */ + +@import UIKit; + +@interface UIImage (ImageEffects) + +- (UIImage *)applyLightEffect; +- (UIImage *)applyExtraLightEffect; +- (UIImage *)applyDarkEffect; +- (UIImage *)applyTintEffectWithColor:(UIColor *)tintColor; + +- (UIImage *)applyBlurWithRadius:(CGFloat)blurRadius tintColor:(UIColor *)tintColor saturationDeltaFactor:(CGFloat)saturationDeltaFactor maskImage:(UIImage *)maskImage; + ++ (UIImage *)imageWithColor:(UIColor *)color; ++ (UIImage *)convertViewToImage; +@end diff --git a/ios/Pods/SCLAlertView-Objective-C/SCLAlertView/UIImage+ImageEffects.m b/ios/Pods/SCLAlertView-Objective-C/SCLAlertView/UIImage+ImageEffects.m new file mode 100755 index 000000000..8b3d69605 --- /dev/null +++ b/ios/Pods/SCLAlertView-Objective-C/SCLAlertView/UIImage+ImageEffects.m @@ -0,0 +1,305 @@ +/* + File: UIImage+ImageEffects.m + Abstract: This is a category of UIImage that adds methods to apply blur and tint effects to an image. This is the code you’ll want to look out to find out how to use vImage to efficiently calculate a blur. + Version: 1.0 + + Disclaimer: IMPORTANT: This Apple software is supplied to you by Apple + Inc. ("Apple") in consideration of your agreement to the following + terms, and your use, installation, modification or redistribution of + this Apple software constitutes acceptance of these terms. If you do + not agree with these terms, please do not use, install, modify or + redistribute this Apple software. + + In consideration of your agreement to abide by the following terms, and + subject to these terms, Apple grants you a personal, non-exclusive + license, under Apple's copyrights in this original Apple software (the + "Apple Software"), to use, reproduce, modify and redistribute the Apple + Software, with or without modifications, in source and/or binary forms; + provided that if you redistribute the Apple Software in its entirety and + without modifications, you must retain this notice and the following + text and disclaimers in all such redistributions of the Apple Software. + Neither the name, trademarks, service marks or logos of Apple Inc. may + be used to endorse or promote products derived from the Apple Software + without specific prior written permission from Apple. Except as + expressly stated in this notice, no other rights or licenses, express or + implied, are granted by Apple herein, including but not limited to any + patent rights that may be infringed by your derivative works or by other + works in which the Apple Software may be incorporated. + + The Apple Software is provided by Apple on an "AS IS" basis. APPLE + MAKES NO WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION + THE IMPLIED WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS + FOR A PARTICULAR PURPOSE, REGARDING THE APPLE SOFTWARE OR ITS USE AND + OPERATION ALONE OR IN COMBINATION WITH YOUR PRODUCTS. + + IN NO EVENT SHALL APPLE BE LIABLE FOR ANY SPECIAL, INDIRECT, INCIDENTAL + OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + INTERRUPTION) ARISING IN ANY WAY OUT OF THE USE, REPRODUCTION, + MODIFICATION AND/OR DISTRIBUTION OF THE APPLE SOFTWARE, HOWEVER CAUSED + AND WHETHER UNDER THEORY OF CONTRACT, TORT (INCLUDING NEGLIGENCE), + STRICT LIABILITY OR OTHERWISE, EVEN IF APPLE HAS BEEN ADVISED OF THE + POSSIBILITY OF SUCH DAMAGE. + + Copyright (C) 2013 Apple Inc. All Rights Reserved. + + + Copyright © 2013 Apple Inc. All rights reserved. + WWDC 2013 License + + NOTE: This Apple Software was supplied by Apple as part of a WWDC 2013 + Session. Please refer to the applicable WWDC 2013 Session for further + information. + + IMPORTANT: This Apple software is supplied to you by Apple Inc. + ("Apple") in consideration of your agreement to the following terms, and + your use, installation, modification or redistribution of this Apple + software constitutes acceptance of these terms. If you do not agree with + these terms, please do not use, install, modify or redistribute this + Apple software. + + In consideration of your agreement to abide by the following terms, and + subject to these terms, Apple grants you a non-exclusive license, under + Apple's copyrights in this original Apple software (the "Apple + Software"), to use, reproduce, modify and redistribute the Apple + Software, with or without modifications, in source and/or binary forms; + provided that if you redistribute the Apple Software in its entirety and + without modifications, you must retain this notice and the following + text and disclaimers in all such redistributions of the Apple Software. + Neither the name, trademarks, service marks or logos of Apple Inc. may + be used to endorse or promote products derived from the Apple Software + without specific prior written permission from Apple. Except as + expressly stated in this notice, no other rights or licenses, express or + implied, are granted by Apple herein, including but not limited to any + patent rights that may be infringed by your derivative works or by other + works in which the Apple Software may be incorporated. + + The Apple Software is provided by Apple on an "AS IS" basis. APPLE MAKES + NO WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION THE + IMPLIED WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS FOR + A PARTICULAR PURPOSE, REGARDING THE APPLE SOFTWARE OR ITS USE AND + OPERATION ALONE OR IN COMBINATION WITH YOUR PRODUCTS. + + IN NO EVENT SHALL APPLE BE LIABLE FOR ANY SPECIAL, INDIRECT, INCIDENTAL + OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + INTERRUPTION) ARISING IN ANY WAY OUT OF THE USE, REPRODUCTION, + MODIFICATION AND/OR DISTRIBUTION OF THE APPLE SOFTWARE, HOWEVER CAUSED + AND WHETHER UNDER THEORY OF CONTRACT, TORT (INCLUDING NEGLIGENCE), + STRICT LIABILITY OR OTHERWISE, EVEN IF APPLE HAS BEEN ADVISED OF THE + POSSIBILITY OF SUCH DAMAGE. + + EA1002 + 5/3/2013 + */ + +#import "UIImage+ImageEffects.h" + +@import Accelerate; +#import + + +@implementation UIImage (ImageEffects) + + +- (UIImage *)applyLightEffect +{ + UIColor *tintColor = [UIColor colorWithWhite:1.0 alpha:0.3]; + return [self applyBlurWithRadius:30 tintColor:tintColor saturationDeltaFactor:1.8 maskImage:nil]; +} + + +- (UIImage *)applyExtraLightEffect +{ + UIColor *tintColor = [UIColor colorWithWhite:0.97 alpha:0.82]; + return [self applyBlurWithRadius:20 tintColor:tintColor saturationDeltaFactor:1.8 maskImage:nil]; +} + + +- (UIImage *)applyDarkEffect +{ + UIColor *tintColor = [UIColor colorWithWhite:0.11 alpha:0.73]; + return [self applyBlurWithRadius:20 tintColor:tintColor saturationDeltaFactor:1.8 maskImage:nil]; +} + + +- (UIImage *)applyTintEffectWithColor:(UIColor *)tintColor +{ + const CGFloat EffectColorAlpha = 0.6; + UIColor *effectColor = tintColor; + NSUInteger componentCount = CGColorGetNumberOfComponents(tintColor.CGColor); + if (componentCount == 2) { + CGFloat b; + if ([tintColor getWhite:&b alpha:NULL]) { + effectColor = [UIColor colorWithWhite:b alpha:EffectColorAlpha]; + } + } + else { + CGFloat r, g, b; + if ([tintColor getRed:&r green:&g blue:&b alpha:NULL]) { + effectColor = [UIColor colorWithRed:r green:g blue:b alpha:EffectColorAlpha]; + } + } + return [self applyBlurWithRadius:10 tintColor:effectColor saturationDeltaFactor:-1.0 maskImage:nil]; +} + + +- (UIImage *)applyBlurWithRadius:(CGFloat)blurRadius tintColor:(UIColor *)tintColor saturationDeltaFactor:(CGFloat)saturationDeltaFactor maskImage:(UIImage *)maskImage +{ + // Check pre-conditions. + if (self.size.width < 1 || self.size.height < 1) { + NSLog (@"*** error: invalid size: (%.2f x %.2f). Both dimensions must be >= 1: %@", self.size.width, self.size.height, self); + return nil; + } + if (!self.CGImage) { + NSLog (@"*** error: image must be backed by a CGImage: %@", self); + return nil; + } + if (maskImage && !maskImage.CGImage) { + NSLog (@"*** error: maskImage must be backed by a CGImage: %@", maskImage); + return nil; + } + + CGRect imageRect = { CGPointZero, self.size }; + UIImage *effectImage = self; + + BOOL hasBlur = blurRadius > __FLT_EPSILON__; + BOOL hasSaturationChange = fabs(saturationDeltaFactor - 1.) > __FLT_EPSILON__; + if (hasBlur || hasSaturationChange) { + UIGraphicsBeginImageContextWithOptions(self.size, NO, [[UIScreen mainScreen] scale]); + CGContextRef effectInContext = UIGraphicsGetCurrentContext(); + CGContextScaleCTM(effectInContext, 1.0, -1.0); + CGContextTranslateCTM(effectInContext, 0, -self.size.height); + CGContextDrawImage(effectInContext, imageRect, self.CGImage); + + vImage_Buffer effectInBuffer; + effectInBuffer.data = CGBitmapContextGetData(effectInContext); + effectInBuffer.width = CGBitmapContextGetWidth(effectInContext); + effectInBuffer.height = CGBitmapContextGetHeight(effectInContext); + effectInBuffer.rowBytes = CGBitmapContextGetBytesPerRow(effectInContext); + + UIGraphicsBeginImageContextWithOptions(self.size, NO, [[UIScreen mainScreen] scale]); + CGContextRef effectOutContext = UIGraphicsGetCurrentContext(); + vImage_Buffer effectOutBuffer; + effectOutBuffer.data = CGBitmapContextGetData(effectOutContext); + effectOutBuffer.width = CGBitmapContextGetWidth(effectOutContext); + effectOutBuffer.height = CGBitmapContextGetHeight(effectOutContext); + effectOutBuffer.rowBytes = CGBitmapContextGetBytesPerRow(effectOutContext); + + if (hasBlur) { + // A description of how to compute the box kernel width from the Gaussian + // radius (aka standard deviation) appears in the SVG spec: + // http://www.w3.org/TR/SVG/filters.html#feGaussianBlurElement + // + // For larger values of 's' (s >= 2.0), an approximation can be used: Three + // successive box-blurs build a piece-wise quadratic convolution kernel, which + // approximates the Gaussian kernel to within roughly 3%. + // + // let d = floor(s * 3*sqrt(2*pi)/4 + 0.5) + // + // ... if d is odd, use three box-blurs of size 'd', centered on the output pixel. + // + CGFloat inputRadius = blurRadius * [[UIScreen mainScreen] scale]; + uint32_t radius = floor(inputRadius * 3. * sqrt(2 * M_PI) / 4 + 0.5); + if (radius % 2 != 1) { + radius += 1; // force radius to be odd so that the three box-blur methodology works. + } + vImageBoxConvolve_ARGB8888(&effectInBuffer, &effectOutBuffer, NULL, 0, 0, radius, radius, 0, kvImageEdgeExtend); + vImageBoxConvolve_ARGB8888(&effectOutBuffer, &effectInBuffer, NULL, 0, 0, radius, radius, 0, kvImageEdgeExtend); + vImageBoxConvolve_ARGB8888(&effectInBuffer, &effectOutBuffer, NULL, 0, 0, radius, radius, 0, kvImageEdgeExtend); + } + BOOL effectImageBuffersAreSwapped = NO; + if (hasSaturationChange) { + CGFloat s = saturationDeltaFactor; + CGFloat floatingPointSaturationMatrix[] = { + 0.0722 + 0.9278 * s, 0.0722 - 0.0722 * s, 0.0722 - 0.0722 * s, 0, + 0.7152 - 0.7152 * s, 0.7152 + 0.2848 * s, 0.7152 - 0.7152 * s, 0, + 0.2126 - 0.2126 * s, 0.2126 - 0.2126 * s, 0.2126 + 0.7873 * s, 0, + 0, 0, 0, 1, + }; + const int32_t divisor = 256; + NSUInteger matrixSize = sizeof(floatingPointSaturationMatrix)/sizeof(floatingPointSaturationMatrix[0]); + int16_t saturationMatrix[matrixSize]; + for (NSUInteger i = 0; i < matrixSize; ++i) { + saturationMatrix[i] = (int16_t)roundf(floatingPointSaturationMatrix[i] * divisor); + } + if (hasBlur) { + vImageMatrixMultiply_ARGB8888(&effectOutBuffer, &effectInBuffer, saturationMatrix, divisor, NULL, NULL, kvImageNoFlags); + effectImageBuffersAreSwapped = YES; + } + else { + vImageMatrixMultiply_ARGB8888(&effectInBuffer, &effectOutBuffer, saturationMatrix, divisor, NULL, NULL, kvImageNoFlags); + } + } + if (!effectImageBuffersAreSwapped) + effectImage = UIGraphicsGetImageFromCurrentImageContext(); + UIGraphicsEndImageContext(); + + if (effectImageBuffersAreSwapped) + effectImage = UIGraphicsGetImageFromCurrentImageContext(); + UIGraphicsEndImageContext(); + } + + // Set up output context. + UIGraphicsBeginImageContextWithOptions(self.size, NO, [[UIScreen mainScreen] scale]); + CGContextRef outputContext = UIGraphicsGetCurrentContext(); + CGContextScaleCTM(outputContext, 1.0, -1.0); + CGContextTranslateCTM(outputContext, 0, -self.size.height); + + // Draw base image. + CGContextDrawImage(outputContext, imageRect, self.CGImage); + + // Draw effect image. + if (hasBlur) { + CGContextSaveGState(outputContext); + if (maskImage) { + CGContextClipToMask(outputContext, imageRect, maskImage.CGImage); + } + CGContextDrawImage(outputContext, imageRect, effectImage.CGImage); + CGContextRestoreGState(outputContext); + } + + // Add in color tint. + if (tintColor) { + CGContextSaveGState(outputContext); + CGContextSetFillColorWithColor(outputContext, tintColor.CGColor); + CGContextFillRect(outputContext, imageRect); + CGContextRestoreGState(outputContext); + } + + // Output image is ready. + UIImage *outputImage = UIGraphicsGetImageFromCurrentImageContext(); + UIGraphicsEndImageContext(); + + return outputImage; +} + ++ (UIImage *)imageWithColor:(UIColor *)color +{ + CGRect rect = CGRectMake(0.0f, 0.0f, 1.0f, 1.0f); + UIGraphicsBeginImageContext(rect.size); + CGContextRef context = UIGraphicsGetCurrentContext(); + + CGContextSetFillColorWithColor(context, [color CGColor]); + CGContextFillRect(context, rect); + + UIImage *image = UIGraphicsGetImageFromCurrentImageContext(); + UIGraphicsEndImageContext(); + + return image; +} + ++ (UIImage *)convertViewToImage +{ + UIWindow *keyWindow = [[UIApplication sharedApplication]keyWindow]; + CGRect rect = [keyWindow bounds]; + UIGraphicsBeginImageContextWithOptions(rect.size, YES, 0.0f); + CGContextRef context = UIGraphicsGetCurrentContext(); + [keyWindow.layer renderInContext:context]; + UIImage *capturedScreen = UIGraphicsGetImageFromCurrentImageContext(); + UIGraphicsEndImageContext(); + + return capturedScreen; +} + +@end diff --git a/ios/Pods/SDWebImage/LICENSE b/ios/Pods/SDWebImage/LICENSE new file mode 100644 index 000000000..ae783e175 --- /dev/null +++ b/ios/Pods/SDWebImage/LICENSE @@ -0,0 +1,20 @@ +Copyright (c) 2009 Olivier Poitrey + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is furnished +to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + diff --git a/ios/Pods/SDWebImage/README.md b/ios/Pods/SDWebImage/README.md new file mode 100644 index 000000000..9bbcca5fc --- /dev/null +++ b/ios/Pods/SDWebImage/README.md @@ -0,0 +1,280 @@ +Web Image +========= +[![Build Status](http://img.shields.io/travis/rs/SDWebImage/master.svg?style=flat)](https://travis-ci.org/rs/SDWebImage) +[![Pod Version](http://img.shields.io/cocoapods/v/SDWebImage.svg?style=flat)](http://cocoadocs.org/docsets/SDWebImage/) +[![Pod Platform](http://img.shields.io/cocoapods/p/SDWebImage.svg?style=flat)](http://cocoadocs.org/docsets/SDWebImage/) +[![Pod License](http://img.shields.io/cocoapods/l/SDWebImage.svg?style=flat)](https://www.apache.org/licenses/LICENSE-2.0.html) + +This library provides a category for UIImageView with support for remote images coming from the web. + +It provides: + +- An UIImageView category adding web image and cache management to the Cocoa Touch framework +- An asynchronous image downloader +- An asynchronous memory + disk image caching with automatic cache expiration handling +- Animated GIF support +- WebP format support +- A background image decompression +- A guarantee that the same URL won't be downloaded several times +- A guarantee that bogus URLs won't be retried again and again +- A guarantee that main thread will never be blocked +- Performances! +- Use GCD and ARC +- Arm64 support + +NOTE: The version 3.0 of SDWebImage isn't fully backward compatible with 2.0 and requires iOS 5.1.1 +minimum deployement version. If you need iOS < 5.0 support, please use the last [2.0 version](https://github.com/rs/SDWebImage/tree/2.0-compat). + +[How is SDWebImage better than X?](https://github.com/rs/SDWebImage/wiki/How-is-SDWebImage-better-than-X%3F) + +Who Use It +---------- + +Find out [who uses SDWebImage](https://github.com/rs/SDWebImage/wiki/Who-Uses-SDWebImage) and add your app to the list. + +How To Use +---------- + +API documentation is available at [http://hackemist.com/SDWebImage/doc/](http://hackemist.com/SDWebImage/doc/) + +### Using UIImageView+WebCache category with UITableView + +Just #import the UIImageView+WebCache.h header, and call the setImageWithURL:placeholderImage: +method from the tableView:cellForRowAtIndexPath: UITableViewDataSource method. Everything will be +handled for you, from async downloads to caching management. + +```objective-c +#import + +... + +- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath +{ + static NSString *MyIdentifier = @"MyIdentifier"; + + UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:MyIdentifier]; + + if (cell == nil) + { + cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault + reuseIdentifier:MyIdentifier] autorelease]; + } + + // Here we use the new provided setImageWithURL: method to load the web image + [cell.imageView setImageWithURL:[NSURL URLWithString:@"http://www.domain.com/path/to/image.jpg"] + placeholderImage:[UIImage imageNamed:@"placeholder.png"]]; + + cell.textLabel.text = @"My Text"; + return cell; +} +``` + +### Using blocks + +With blocks, you can be notified about the image download progress and whenever the image retrival +has completed with success or not: + +```objective-c +// Here we use the new provided setImageWithURL: method to load the web image +[cell.imageView setImageWithURL:[NSURL URLWithString:@"http://www.domain.com/path/to/image.jpg"] + placeholderImage:[UIImage imageNamed:@"placeholder.png"] + completed:^(UIImage *image, NSError *error, SDImageCacheType cacheType) {... completion code here ...}]; +``` + +Note: neither your success nor failure block will be call if your image request is canceled before completion. + +### Using SDWebImageManager + +The SDWebImageManager is the class behind the UIImageView+WebCache category. It ties the +asynchronous downloader with the image cache store. You can use this class directly to benefit +from web image downloading with caching in another context than a UIView (ie: with Cocoa). + +Here is a simple example of how to use SDWebImageManager: + +```objective-c +SDWebImageManager *manager = [SDWebImageManager sharedManager]; +[manager downloadWithURL:imageURL + options:0 + progress:^(NSInteger receivedSize, NSInteger expectedSize) + { + // progression tracking code + } + completed:^(UIImage *image, NSError *error, SDImageCacheType cacheType, BOOL finished) + { + if (image) + { + // do something with image + } + }]; +``` + +### Using Asynchronous Image Downloader Independently + +It's also possible to use the async image downloader independently: + +```objective-c +[SDWebImageDownloader.sharedDownloader downloadImageWithURL:imageURL + options:0 + progress:^(NSInteger receivedSize, NSInteger expectedSize) + { + // progression tracking code + } + completed:^(UIImage *image, NSData *data, NSError *error, BOOL finished) + { + if (image && finished) + { + // do something with image + } + }]; +``` + +### Using Asynchronous Image Caching Independently + +It is also possible to use the aync based image cache store independently. SDImageCache +maintains a memory cache and an optional disk cache. Disk cache write operations are performed +asynchronous so it doesn't add unnecessary latency to the UI. + +The SDImageCache class provides a singleton instance for convenience but you can create your own +instance if you want to create separated cache namespace. + +To lookup the cache, you use the `queryDiskCacheForKey:done:` method. If the method returns nil, it means the cache +doesn't currently own the image. You are thus responsible for generating and caching it. The cache +key is an application unique identifier for the image to cache. It is generally the absolute URL of +the image. + +```objective-c +SDImageCache *imageCache = [[SDImageCache alloc] initWithNamespace:@"myNamespace"]; +[imageCache queryDiskCacheForKey:myCacheKey done:^(UIImage *image) +{ + // image is not nil if image was found +}]; +``` + +By default SDImageCache will lookup the disk cache if an image can't be found in the memory cache. +You can prevent this from happening by calling the alternative method `imageFromMemoryCacheForKey:`. + +To store an image into the cache, you use the storeImage:forKey: method: + +```objective-c +[[SDImageCache sharedImageCache] storeImage:myImage forKey:myCacheKey]; +``` + +By default, the image will be stored in memory cache as well as on disk cache (asynchronously). If +you want only the memory cache, use the alternative method storeImage:forKey:toDisk: with a negative +third argument. + +### Using cache key filter + +Sometime, you may not want to use the image URL as cache key because part of the URL is dynamic +(i.e.: for access control purpose). SDWebImageManager provides a way to set a cache key filter that +takes the NSURL as input, and output a cache key NSString. + +The following example sets a filter in the application delegate that will remove any query-string from +the URL before to use it as a cache key: + +```objective-c +- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions +{ + SDWebImageManager.sharedManager.cacheKeyFilter:^(NSURL *url) + { + url = [[[NSURL alloc] initWithScheme:url.scheme host:url.host path:url.path] autorelease]; + return [url absoluteString]; + }; + + // Your app init code... + return YES; +} +``` + + +Common Problems +--------------- + +### Using dynamic image size with UITableViewCell + +UITableView determins the size of the image by the first image set for a cell. If your remote images +don't have the same size as your placeholder image, you may experience strange anamorphic scaling issue. +The following article gives a way to workaround this issue: + +[http://www.wrichards.com/blog/2011/11/sdwebimage-fixed-width-cell-images/](http://www.wrichards.com/blog/2011/11/sdwebimage-fixed-width-cell-images/) + + +### Handle image refresh + +SDWebImage does very aggressive caching by default. It ignores all kind of caching control header returned by the HTTP server and cache the returned images with no time restriction. It implies your images URLs are static URLs pointing to images that never change. If the pointed image happen to change, some parts of the URL should change accordingly. + +If you don't control the image server you're using, you may not be able to change the URL when its content is updated. This is the case for Facebook avatar URLs for instance. In such case, you may use the `SDWebImageRefreshCached` flag. This will slightly degrade the performance but will respect the HTTP caching control headers: + +``` objective-c +[imageView setImageWithURL:[NSURL URLWithString:@"https://graph.facebook.com/olivier.poitrey/picture"] + placeholderImage:[UIImage imageNamed:@"avatar-placeholder.png"] + options:SDWebImageRefreshCached]; +``` + +### Add a progress indicator + +See this category: https://github.com/JJSaccolo/UIActivityIndicator-for-SDWebImage + +Installation +------------ + +There are three ways to use SDWebImage in your project: +- using Cocoapods +- copying all the files into your project +- importing the project as a static library + +### Installation with CocoaPods + +[CocoaPods](http://cocoapods.org/) is a dependency manager for Objective-C, which automates and simplifies the process of using 3rd-party libraries in your projects. See the [Get Started](http://cocoapods.org/#get_started) section for more details. + +#### Podfile +``` +platform :ios, '6.1' +pod 'SDWebImage', '~>3.6' +``` + +### Add the SDWebImage project to your project + +- Download and unzip the last version of the framework from the [download page](https://github.com/rs/SDWebImage/releases) +- Right-click on the project navigator and select "Add Files to "Your Project": +- In the dialog, select SDWebImage.framework: +- Check the "Copy items into destination group's folder (if needed)" checkbox + +### Add dependencies + +- In you application project app’s target settings, find the "Build Phases" section and open the "Link Binary With Libraries" block: +- Click the "+" button again and select the "ImageIO.framework", this is needed by the progressive download feature: + +### Add Linker Flag + +Open the "Build Settings" tab, in the "Linking" section, locate the "Other Linker Flags" setting and add the "-ObjC" flag: + +![Other Linker Flags](http://dl.dropbox.com/u/123346/SDWebImage/10_other_linker_flags.jpg) + +Alternatively, if this causes compilation problems with frameworks that extend optional libraries, such as Parse, RestKit or opencv2, instead of the -ObjC flag use: + +``` +-force_load SDWebImage.framework/Versions/Current/SDWebImage +``` + +### Import headers in your source files + +In the source files where you need to use the library, import the header file: + +```objective-c +#import +``` + +### Build Project + +At this point your workspace should build without error. If you are having problem, post to the Issue and the +community can help you solve it. + +Future Enhancements +------------------- + +- LRU memory cache cleanup instead of reset on memory warning + +## Licenses + +All source code is licensed under the [MIT License](https://raw.github.com/rs/SDWebImage/master/LICENSE). diff --git a/ios/Pods/SDWebImage/SDWebImage/NSData+ImageContentType.h b/ios/Pods/SDWebImage/SDWebImage/NSData+ImageContentType.h new file mode 100644 index 000000000..69c76dc77 --- /dev/null +++ b/ios/Pods/SDWebImage/SDWebImage/NSData+ImageContentType.h @@ -0,0 +1,26 @@ +// +// Created by Fabrice Aneche on 06/01/14. +// Copyright (c) 2014 Dailymotion. All rights reserved. +// + +#import + +@interface NSData (ImageContentType) + +/** + * Compute the content type for an image data + * + * @param data the input data + * + * @return the content type as string (i.e. image/jpeg, image/gif) + */ ++ (NSString *)sd_contentTypeForImageData:(NSData *)data; + +@end + + +@interface NSData (ImageContentTypeDeprecated) + ++ (NSString *)contentTypeForImageData:(NSData *)data __deprecated_msg("Use `sd_contentTypeForImageData:`"); + +@end diff --git a/ios/Pods/SDWebImage/SDWebImage/NSData+ImageContentType.m b/ios/Pods/SDWebImage/SDWebImage/NSData+ImageContentType.m new file mode 100644 index 000000000..0941cfaa0 --- /dev/null +++ b/ios/Pods/SDWebImage/SDWebImage/NSData+ImageContentType.m @@ -0,0 +1,49 @@ +// +// Created by Fabrice Aneche on 06/01/14. +// Copyright (c) 2014 Dailymotion. All rights reserved. +// + +#import "NSData+ImageContentType.h" + + +@implementation NSData (ImageContentType) + ++ (NSString *)sd_contentTypeForImageData:(NSData *)data { + uint8_t c; + [data getBytes:&c length:1]; + switch (c) { + case 0xFF: + return @"image/jpeg"; + case 0x89: + return @"image/png"; + case 0x47: + return @"image/gif"; + case 0x49: + case 0x4D: + return @"image/tiff"; + case 0x52: + // R as RIFF for WEBP + if ([data length] < 12) { + return nil; + } + + NSString *testString = [[NSString alloc] initWithData:[data subdataWithRange:NSMakeRange(0, 12)] encoding:NSASCIIStringEncoding]; + if ([testString hasPrefix:@"RIFF"] && [testString hasSuffix:@"WEBP"]) { + return @"image/webp"; + } + + return nil; + } + return nil; +} + +@end + + +@implementation NSData (ImageContentTypeDeprecated) + ++ (NSString *)contentTypeForImageData:(NSData *)data { + return [self sd_contentTypeForImageData:data]; +} + +@end diff --git a/ios/Pods/SDWebImage/SDWebImage/SDImageCache.h b/ios/Pods/SDWebImage/SDWebImage/SDImageCache.h new file mode 100644 index 000000000..bde9d5dd7 --- /dev/null +++ b/ios/Pods/SDWebImage/SDWebImage/SDImageCache.h @@ -0,0 +1,241 @@ +/* + * This file is part of the SDWebImage package. + * (c) Olivier Poitrey + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +#import +#import "SDWebImageCompat.h" + +typedef NS_ENUM(NSInteger, SDImageCacheType) { + /** + * The image wasn't available the SDWebImage caches, but was downloaded from the web. + */ + SDImageCacheTypeNone, + /** + * The image was obtained from the disk cache. + */ + SDImageCacheTypeDisk, + /** + * The image was obtained from the memory cache. + */ + SDImageCacheTypeMemory +}; + +typedef void(^SDWebImageQueryCompletedBlock)(UIImage *image, SDImageCacheType cacheType); + +typedef void(^SDWebImageCheckCacheCompletionBlock)(BOOL isInCache); + +typedef void(^SDWebImageCalculateSizeBlock)(NSUInteger fileCount, NSUInteger totalSize); + +/** + * SDImageCache maintains a memory cache and an optional disk cache. Disk cache write operations are performed + * asynchronous so it doesn’t add unnecessary latency to the UI. + */ +@interface SDImageCache : NSObject + +/** + * The maximum "total cost" of the in-memory image cache. The cost function is the number of pixels held in memory. + */ +@property (assign, nonatomic) NSUInteger maxMemoryCost; + +/** + * The maximum length of time to keep an image in the cache, in seconds + */ +@property (assign, nonatomic) NSInteger maxCacheAge; + +/** + * The maximum size of the cache, in bytes. + */ +@property (assign, nonatomic) NSUInteger maxCacheSize; + +/** + * Returns global shared cache instance + * + * @return SDImageCache global instance + */ ++ (SDImageCache *)sharedImageCache; + +/** + * Init a new cache store with a specific namespace + * + * @param ns The namespace to use for this cache store + */ +- (id)initWithNamespace:(NSString *)ns; + +/** + * Add a read-only cache path to search for images pre-cached by SDImageCache + * Useful if you want to bundle pre-loaded images with your app + * + * @param path The path to use for this read-only cache path + */ +- (void)addReadOnlyCachePath:(NSString *)path; + +/** + * Store an image into memory and disk cache at the given key. + * + * @param image The image to store + * @param key The unique image cache key, usually it's image absolute URL + */ +- (void)storeImage:(UIImage *)image forKey:(NSString *)key; + +/** + * Store an image into memory and optionally disk cache at the given key. + * + * @param image The image to store + * @param key The unique image cache key, usually it's image absolute URL + * @param toDisk Store the image to disk cache if YES + */ +- (void)storeImage:(UIImage *)image forKey:(NSString *)key toDisk:(BOOL)toDisk; + +/** + * Store an image into memory and optionally disk cache at the given key. + * + * @param image The image to store + * @param recalculate BOOL indicates if imageData can be used or a new data should be constructed from the UIImage + * @param imageData The image data as returned by the server, this representation will be used for disk storage + * instead of converting the given image object into a storable/compressed image format in order + * to save quality and CPU + * @param key The unique image cache key, usually it's image absolute URL + * @param toDisk Store the image to disk cache if YES + */ +- (void)storeImage:(UIImage *)image recalculateFromImage:(BOOL)recalculate imageData:(NSData *)imageData forKey:(NSString *)key toDisk:(BOOL)toDisk; + +/** + * Query the disk cache asynchronously. + * + * @param key The unique key used to store the wanted image + */ +- (NSOperation *)queryDiskCacheForKey:(NSString *)key done:(SDWebImageQueryCompletedBlock)doneBlock; + +/** + * Query the memory cache synchronously. + * + * @param key The unique key used to store the wanted image + */ +- (UIImage *)imageFromMemoryCacheForKey:(NSString *)key; + +/** + * Query the disk cache synchronously after checking the memory cache. + * + * @param key The unique key used to store the wanted image + */ +- (UIImage *)imageFromDiskCacheForKey:(NSString *)key; + +/** + * Remove the image from memory and disk cache synchronously + * + * @param key The unique image cache key + */ +- (void)removeImageForKey:(NSString *)key; + + +/** + * Remove the image from memory and disk cache synchronously + * + * @param key The unique image cache key + * @param completionBlock An block that should be executed after the image has been removed (optional) + */ +- (void)removeImageForKey:(NSString *)key withCompletion:(SDWebImageNoParamsBlock)completion; + +/** + * Remove the image from memory and optionally disk cache synchronously + * + * @param key The unique image cache key + * @param fromDisk Also remove cache entry from disk if YES + */ +- (void)removeImageForKey:(NSString *)key fromDisk:(BOOL)fromDisk; + +/** + * Remove the image from memory and optionally disk cache synchronously + * + * @param key The unique image cache key + * @param fromDisk Also remove cache entry from disk if YES + * @param completionBlock An block that should be executed after the image has been removed (optional) + */ +- (void)removeImageForKey:(NSString *)key fromDisk:(BOOL)fromDisk withCompletion:(SDWebImageNoParamsBlock)completion; + +/** + * Clear all memory cached images + */ +- (void)clearMemory; + +/** + * Clear all disk cached images. Non-blocking method - returns immediately. + * @param completionBlock An block that should be executed after cache expiration completes (optional) + */ +- (void)clearDiskOnCompletion:(SDWebImageNoParamsBlock)completion; + +/** + * Clear all disk cached images + * @see clearDiskOnCompletion: + */ +- (void)clearDisk; + +/** + * Remove all expired cached image from disk. Non-blocking method - returns immediately. + * @param completionBlock An block that should be executed after cache expiration completes (optional) + */ +- (void)cleanDiskWithCompletionBlock:(SDWebImageNoParamsBlock)completionBlock; + +/** + * Remove all expired cached image from disk + * @see cleanDiskWithCompletionBlock: + */ +- (void)cleanDisk; + +/** + * Get the size used by the disk cache + */ +- (NSUInteger)getSize; + +/** + * Get the number of images in the disk cache + */ +- (NSUInteger)getDiskCount; + +/** + * Asynchronously calculate the disk cache's size. + */ +- (void)calculateSizeWithCompletionBlock:(SDWebImageCalculateSizeBlock)completionBlock; + +/** + * Async check if image exists in disk cache already (does not load the image) + * + * @param key the key describing the url + * @param completionBlock the block to be executed when the check is done. + * @note the completion block will be always executed on the main queue + */ +- (void)diskImageExistsWithKey:(NSString *)key completion:(SDWebImageCheckCacheCompletionBlock)completionBlock; + +/** + * Check if image exists in disk cache already (does not load the image) + * + * @param key the key describing the url + * + * @return YES if an image exists for the given key + */ +- (BOOL)diskImageExistsWithKey:(NSString *)key; + +/** + * Get the cache path for a certain key (needs the cache path root folder) + * + * @param key the key (can be obtained from url using cacheKeyForURL) + * @param path the cach path root folder + * + * @return the cache path + */ +- (NSString *)cachePathForKey:(NSString *)key inPath:(NSString *)path; + +/** + * Get the default cache path for a certain key + * + * @param key the key (can be obtained from url using cacheKeyForURL) + * + * @return the default cache path + */ +- (NSString *)defaultCachePathForKey:(NSString *)key; + +@end diff --git a/ios/Pods/SDWebImage/SDWebImage/SDImageCache.m b/ios/Pods/SDWebImage/SDWebImage/SDImageCache.m new file mode 100644 index 000000000..59c347146 --- /dev/null +++ b/ios/Pods/SDWebImage/SDWebImage/SDImageCache.m @@ -0,0 +1,534 @@ +/* + * This file is part of the SDWebImage package. + * (c) Olivier Poitrey + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +#import "SDImageCache.h" +#import "SDWebImageDecoder.h" +#import "UIImage+MultiFormat.h" +#import + +static const NSInteger kDefaultCacheMaxCacheAge = 60 * 60 * 24 * 7; // 1 week +// PNG signature bytes and data (below) +static unsigned char kPNGSignatureBytes[8] = {0x89, 0x50, 0x4E, 0x47, 0x0D, 0x0A, 0x1A, 0x0A}; +static NSData *kPNGSignatureData = nil; + +BOOL ImageDataHasPNGPreffix(NSData *data); + +BOOL ImageDataHasPNGPreffix(NSData *data) { + NSUInteger pngSignatureLength = [kPNGSignatureData length]; + if ([data length] >= pngSignatureLength) { + if ([[data subdataWithRange:NSMakeRange(0, pngSignatureLength)] isEqualToData:kPNGSignatureData]) { + return YES; + } + } + + return NO; +} + +@interface SDImageCache () + +@property (strong, nonatomic) NSCache *memCache; +@property (strong, nonatomic) NSString *diskCachePath; +@property (strong, nonatomic) NSMutableArray *customPaths; +@property (SDDispatchQueueSetterSementics, nonatomic) dispatch_queue_t ioQueue; + +@end + + +@implementation SDImageCache { + NSFileManager *_fileManager; +} + ++ (SDImageCache *)sharedImageCache { + static dispatch_once_t once; + static id instance; + dispatch_once(&once, ^{ + instance = [self new]; + kPNGSignatureData = [NSData dataWithBytes:kPNGSignatureBytes length:8]; + }); + return instance; +} + +- (id)init { + return [self initWithNamespace:@"default"]; +} + +- (id)initWithNamespace:(NSString *)ns { + if ((self = [super init])) { + NSString *fullNamespace = [@"com.hackemist.SDWebImageCache." stringByAppendingString:ns]; + + // Create IO serial queue + _ioQueue = dispatch_queue_create("com.hackemist.SDWebImageCache", DISPATCH_QUEUE_SERIAL); + + // Init default values + _maxCacheAge = kDefaultCacheMaxCacheAge; + + // Init the memory cache + _memCache = [[NSCache alloc] init]; + _memCache.name = fullNamespace; + + // Init the disk cache + NSArray *paths = NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES); + _diskCachePath = [paths[0] stringByAppendingPathComponent:fullNamespace]; + + dispatch_sync(_ioQueue, ^{ + _fileManager = [NSFileManager new]; + }); + +#if TARGET_OS_IPHONE + // Subscribe to app events + [[NSNotificationCenter defaultCenter] addObserver:self + selector:@selector(clearMemory) + name:UIApplicationDidReceiveMemoryWarningNotification + object:nil]; + + [[NSNotificationCenter defaultCenter] addObserver:self + selector:@selector(cleanDisk) + name:UIApplicationWillTerminateNotification + object:nil]; + + [[NSNotificationCenter defaultCenter] addObserver:self + selector:@selector(backgroundCleanDisk) + name:UIApplicationDidEnterBackgroundNotification + object:nil]; +#endif + } + + return self; +} + +- (void)dealloc { + [[NSNotificationCenter defaultCenter] removeObserver:self]; + SDDispatchQueueRelease(_ioQueue); +} + +- (void)addReadOnlyCachePath:(NSString *)path { + if (!self.customPaths) { + self.customPaths = [NSMutableArray new]; + } + + if (![self.customPaths containsObject:path]) { + [self.customPaths addObject:path]; + } +} + +- (NSString *)cachePathForKey:(NSString *)key inPath:(NSString *)path { + NSString *filename = [self cachedFileNameForKey:key]; + return [path stringByAppendingPathComponent:filename]; +} + +- (NSString *)defaultCachePathForKey:(NSString *)key { + return [self cachePathForKey:key inPath:self.diskCachePath]; +} + +#pragma mark SDImageCache (private) + +- (NSString *)cachedFileNameForKey:(NSString *)key { + const char *str = [key UTF8String]; + if (str == NULL) { + str = ""; + } + unsigned char r[CC_MD5_DIGEST_LENGTH]; + CC_MD5(str, (CC_LONG)strlen(str), r); + NSString *filename = [NSString stringWithFormat:@"%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x", + r[0], r[1], r[2], r[3], r[4], r[5], r[6], r[7], r[8], r[9], r[10], r[11], r[12], r[13], r[14], r[15]]; + + return filename; +} + +#pragma mark ImageCache + +- (void)storeImage:(UIImage *)image recalculateFromImage:(BOOL)recalculate imageData:(NSData *)imageData forKey:(NSString *)key toDisk:(BOOL)toDisk { + if (!image || !key) { + return; + } + + [self.memCache setObject:image forKey:key cost:image.size.height * image.size.width * image.scale]; + + if (toDisk) { + dispatch_async(self.ioQueue, ^{ + NSData *data = imageData; + + if (image && (recalculate || !data)) { +#if TARGET_OS_IPHONE + // We need to determine if the image is a PNG or a JPEG + // PNGs are easier to detect because they have a unique signature (http://www.w3.org/TR/PNG-Structure.html) + // The first eight bytes of a PNG file always contain the following (decimal) values: + // 137 80 78 71 13 10 26 10 + + // We assume the image is PNG, in case the imageData is nil (i.e. if trying to save a UIImage directly), + // we will consider it PNG to avoid loosing the transparency + BOOL imageIsPng = YES; + + // But if we have an image data, we will look at the preffix + if ([imageData length] >= [kPNGSignatureData length]) { + imageIsPng = ImageDataHasPNGPreffix(imageData); + } + + if (imageIsPng) { + data = UIImagePNGRepresentation(image); + } + else { + data = UIImageJPEGRepresentation(image, (CGFloat)1.0); + } +#else + data = [NSBitmapImageRep representationOfImageRepsInArray:image.representations usingType: NSJPEGFileType properties:nil]; +#endif + } + + if (data) { + if (![_fileManager fileExistsAtPath:_diskCachePath]) { + [_fileManager createDirectoryAtPath:_diskCachePath withIntermediateDirectories:YES attributes:nil error:NULL]; + } + + [_fileManager createFileAtPath:[self defaultCachePathForKey:key] contents:data attributes:nil]; + } + }); + } +} + +- (void)storeImage:(UIImage *)image forKey:(NSString *)key { + [self storeImage:image recalculateFromImage:YES imageData:nil forKey:key toDisk:YES]; +} + +- (void)storeImage:(UIImage *)image forKey:(NSString *)key toDisk:(BOOL)toDisk { + [self storeImage:image recalculateFromImage:YES imageData:nil forKey:key toDisk:toDisk]; +} + +- (BOOL)diskImageExistsWithKey:(NSString *)key { + BOOL exists = NO; + + // this is an exception to access the filemanager on another queue than ioQueue, but we are using the shared instance + // from apple docs on NSFileManager: The methods of the shared NSFileManager object can be called from multiple threads safely. + exists = [[NSFileManager defaultManager] fileExistsAtPath:[self defaultCachePathForKey:key]]; + + return exists; +} + +- (void)diskImageExistsWithKey:(NSString *)key completion:(SDWebImageCheckCacheCompletionBlock)completionBlock { + dispatch_async(_ioQueue, ^{ + BOOL exists = [_fileManager fileExistsAtPath:[self defaultCachePathForKey:key]]; + if (completionBlock) { + dispatch_async(dispatch_get_main_queue(), ^{ + completionBlock(exists); + }); + } + }); +} + +- (UIImage *)imageFromMemoryCacheForKey:(NSString *)key { + return [self.memCache objectForKey:key]; +} + +- (UIImage *)imageFromDiskCacheForKey:(NSString *)key { + // First check the in-memory cache... + UIImage *image = [self imageFromMemoryCacheForKey:key]; + if (image) { + return image; + } + + // Second check the disk cache... + UIImage *diskImage = [self diskImageForKey:key]; + if (diskImage) { + CGFloat cost = diskImage.size.height * diskImage.size.width * diskImage.scale; + [self.memCache setObject:diskImage forKey:key cost:cost]; + } + + return diskImage; +} + +- (NSData *)diskImageDataBySearchingAllPathsForKey:(NSString *)key { + NSString *defaultPath = [self defaultCachePathForKey:key]; + NSData *data = [NSData dataWithContentsOfFile:defaultPath]; + if (data) { + return data; + } + + for (NSString *path in self.customPaths) { + NSString *filePath = [self cachePathForKey:key inPath:path]; + NSData *imageData = [NSData dataWithContentsOfFile:filePath]; + if (imageData) { + return imageData; + } + } + + return nil; +} + +- (UIImage *)diskImageForKey:(NSString *)key { + NSData *data = [self diskImageDataBySearchingAllPathsForKey:key]; + if (data) { + UIImage *image = [UIImage sd_imageWithData:data]; + image = [self scaledImageForKey:key image:image]; + image = [UIImage decodedImageWithImage:image]; + return image; + } + else { + return nil; + } +} + +- (UIImage *)scaledImageForKey:(NSString *)key image:(UIImage *)image { + return SDScaledImageForKey(key, image); +} + +- (NSOperation *)queryDiskCacheForKey:(NSString *)key done:(SDWebImageQueryCompletedBlock)doneBlock { + if (!doneBlock) { + return nil; + } + + if (!key) { + doneBlock(nil, SDImageCacheTypeNone); + return nil; + } + + // First check the in-memory cache... + UIImage *image = [self imageFromMemoryCacheForKey:key]; + if (image) { + doneBlock(image, SDImageCacheTypeMemory); + return nil; + } + + NSOperation *operation = [NSOperation new]; + dispatch_async(self.ioQueue, ^{ + if (operation.isCancelled) { + return; + } + + @autoreleasepool { + UIImage *diskImage = [self diskImageForKey:key]; + if (diskImage) { + CGFloat cost = diskImage.size.height * diskImage.size.width * diskImage.scale; + [self.memCache setObject:diskImage forKey:key cost:cost]; + } + + dispatch_async(dispatch_get_main_queue(), ^{ + doneBlock(diskImage, SDImageCacheTypeDisk); + }); + } + }); + + return operation; +} + +- (void)removeImageForKey:(NSString *)key { + [self removeImageForKey:key withCompletion:nil]; +} + +- (void)removeImageForKey:(NSString *)key withCompletion:(SDWebImageNoParamsBlock)completion { + [self removeImageForKey:key fromDisk:YES withCompletion:completion]; +} + +- (void)removeImageForKey:(NSString *)key fromDisk:(BOOL)fromDisk { + [self removeImageForKey:key fromDisk:fromDisk withCompletion:nil]; +} + +- (void)removeImageForKey:(NSString *)key fromDisk:(BOOL)fromDisk withCompletion:(SDWebImageNoParamsBlock)completion { + + if (key == nil) { + return; + } + + [self.memCache removeObjectForKey:key]; + + if (fromDisk) { + dispatch_async(self.ioQueue, ^{ + [_fileManager removeItemAtPath:[self defaultCachePathForKey:key] error:nil]; + + if (completion) { + dispatch_async(dispatch_get_main_queue(), ^{ + completion(); + }); + } + }); + } else if (completion){ + completion(); + } + +} + +- (void)setMaxMemoryCost:(NSUInteger)maxMemoryCost { + self.memCache.totalCostLimit = maxMemoryCost; +} + +- (NSUInteger)maxMemoryCost { + return self.memCache.totalCostLimit; +} + +- (void)clearMemory { + [self.memCache removeAllObjects]; +} + +- (void)clearDisk { + [self clearDiskOnCompletion:nil]; +} + +- (void)clearDiskOnCompletion:(SDWebImageNoParamsBlock)completion +{ + dispatch_async(self.ioQueue, ^{ + [_fileManager removeItemAtPath:self.diskCachePath error:nil]; + [_fileManager createDirectoryAtPath:self.diskCachePath + withIntermediateDirectories:YES + attributes:nil + error:NULL]; + + if (completion) { + dispatch_async(dispatch_get_main_queue(), ^{ + completion(); + }); + } + }); +} + +- (void)cleanDisk { + [self cleanDiskWithCompletionBlock:nil]; +} + +- (void)cleanDiskWithCompletionBlock:(SDWebImageNoParamsBlock)completionBlock { + dispatch_async(self.ioQueue, ^{ + NSURL *diskCacheURL = [NSURL fileURLWithPath:self.diskCachePath isDirectory:YES]; + NSArray *resourceKeys = @[NSURLIsDirectoryKey, NSURLContentModificationDateKey, NSURLTotalFileAllocatedSizeKey]; + + // This enumerator prefetches useful properties for our cache files. + NSDirectoryEnumerator *fileEnumerator = [_fileManager enumeratorAtURL:diskCacheURL + includingPropertiesForKeys:resourceKeys + options:NSDirectoryEnumerationSkipsHiddenFiles + errorHandler:NULL]; + + NSDate *expirationDate = [NSDate dateWithTimeIntervalSinceNow:-self.maxCacheAge]; + NSMutableDictionary *cacheFiles = [NSMutableDictionary dictionary]; + NSUInteger currentCacheSize = 0; + + // Enumerate all of the files in the cache directory. This loop has two purposes: + // + // 1. Removing files that are older than the expiration date. + // 2. Storing file attributes for the size-based cleanup pass. + NSMutableArray *urlsToDelete = [[NSMutableArray alloc] init]; + for (NSURL *fileURL in fileEnumerator) { + NSDictionary *resourceValues = [fileURL resourceValuesForKeys:resourceKeys error:NULL]; + + // Skip directories. + if ([resourceValues[NSURLIsDirectoryKey] boolValue]) { + continue; + } + + // Remove files that are older than the expiration date; + NSDate *modificationDate = resourceValues[NSURLContentModificationDateKey]; + if ([[modificationDate laterDate:expirationDate] isEqualToDate:expirationDate]) { + [urlsToDelete addObject:fileURL]; + continue; + } + + // Store a reference to this file and account for its total size. + NSNumber *totalAllocatedSize = resourceValues[NSURLTotalFileAllocatedSizeKey]; + currentCacheSize += [totalAllocatedSize unsignedIntegerValue]; + [cacheFiles setObject:resourceValues forKey:fileURL]; + } + + for (NSURL *fileURL in urlsToDelete) { + [_fileManager removeItemAtURL:fileURL error:nil]; + } + + // If our remaining disk cache exceeds a configured maximum size, perform a second + // size-based cleanup pass. We delete the oldest files first. + if (self.maxCacheSize > 0 && currentCacheSize > self.maxCacheSize) { + // Target half of our maximum cache size for this cleanup pass. + const NSUInteger desiredCacheSize = self.maxCacheSize / 2; + + // Sort the remaining cache files by their last modification time (oldest first). + NSArray *sortedFiles = [cacheFiles keysSortedByValueWithOptions:NSSortConcurrent + usingComparator:^NSComparisonResult(id obj1, id obj2) { + return [obj1[NSURLContentModificationDateKey] compare:obj2[NSURLContentModificationDateKey]]; + }]; + + // Delete files until we fall below our desired cache size. + for (NSURL *fileURL in sortedFiles) { + if ([_fileManager removeItemAtURL:fileURL error:nil]) { + NSDictionary *resourceValues = cacheFiles[fileURL]; + NSNumber *totalAllocatedSize = resourceValues[NSURLTotalFileAllocatedSizeKey]; + currentCacheSize -= [totalAllocatedSize unsignedIntegerValue]; + + if (currentCacheSize < desiredCacheSize) { + break; + } + } + } + } + if (completionBlock) { + dispatch_async(dispatch_get_main_queue(), ^{ + completionBlock(); + }); + } + }); +} + +- (void)backgroundCleanDisk { + UIApplication *application = [UIApplication sharedApplication]; + __block UIBackgroundTaskIdentifier bgTask = [application beginBackgroundTaskWithExpirationHandler:^{ + // Clean up any unfinished task business by marking where you + // stopped or ending the task outright. + [application endBackgroundTask:bgTask]; + bgTask = UIBackgroundTaskInvalid; + }]; + + // Start the long-running task and return immediately. + [self cleanDiskWithCompletionBlock:^{ + [application endBackgroundTask:bgTask]; + bgTask = UIBackgroundTaskInvalid; + }]; +} + +- (NSUInteger)getSize { + __block NSUInteger size = 0; + dispatch_sync(self.ioQueue, ^{ + NSDirectoryEnumerator *fileEnumerator = [_fileManager enumeratorAtPath:self.diskCachePath]; + for (NSString *fileName in fileEnumerator) { + NSString *filePath = [self.diskCachePath stringByAppendingPathComponent:fileName]; + NSDictionary *attrs = [[NSFileManager defaultManager] attributesOfItemAtPath:filePath error:nil]; + size += [attrs fileSize]; + } + }); + return size; +} + +- (NSUInteger)getDiskCount { + __block NSUInteger count = 0; + dispatch_sync(self.ioQueue, ^{ + NSDirectoryEnumerator *fileEnumerator = [_fileManager enumeratorAtPath:self.diskCachePath]; + count = [[fileEnumerator allObjects] count]; + }); + return count; +} + +- (void)calculateSizeWithCompletionBlock:(SDWebImageCalculateSizeBlock)completionBlock { + NSURL *diskCacheURL = [NSURL fileURLWithPath:self.diskCachePath isDirectory:YES]; + + dispatch_async(self.ioQueue, ^{ + NSUInteger fileCount = 0; + NSUInteger totalSize = 0; + + NSDirectoryEnumerator *fileEnumerator = [_fileManager enumeratorAtURL:diskCacheURL + includingPropertiesForKeys:@[NSFileSize] + options:NSDirectoryEnumerationSkipsHiddenFiles + errorHandler:NULL]; + + for (NSURL *fileURL in fileEnumerator) { + NSNumber *fileSize; + [fileURL getResourceValue:&fileSize forKey:NSURLFileSizeKey error:NULL]; + totalSize += [fileSize unsignedIntegerValue]; + fileCount += 1; + } + + if (completionBlock) { + dispatch_async(dispatch_get_main_queue(), ^{ + completionBlock(fileCount, totalSize); + }); + } + }); +} + +@end diff --git a/ios/Pods/SDWebImage/SDWebImage/SDWebImageCompat.h b/ios/Pods/SDWebImage/SDWebImage/SDWebImageCompat.h new file mode 100644 index 000000000..a0555fdf7 --- /dev/null +++ b/ios/Pods/SDWebImage/SDWebImage/SDWebImageCompat.h @@ -0,0 +1,70 @@ +/* + * This file is part of the SDWebImage package. + * (c) Olivier Poitrey + * (c) Jamie Pinkham + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +#import + +#ifdef __OBJC_GC__ +#error SDWebImage does not support Objective-C Garbage Collection +#endif + +#if __IPHONE_OS_VERSION_MIN_REQUIRED < __IPHONE_5_0 +#error SDWebImage doesn't support Deployement Target version < 5.0 +#endif + +#if !TARGET_OS_IPHONE +#import +#ifndef UIImage +#define UIImage NSImage +#endif +#ifndef UIImageView +#define UIImageView NSImageView +#endif +#else + +#import + +#endif + +#ifndef NS_ENUM +#define NS_ENUM(_type, _name) enum _name : _type _name; enum _name : _type +#endif + +#ifndef NS_OPTIONS +#define NS_OPTIONS(_type, _name) enum _name : _type _name; enum _name : _type +#endif + +#if OS_OBJECT_USE_OBJC + #undef SDDispatchQueueRelease + #undef SDDispatchQueueSetterSementics + #define SDDispatchQueueRelease(q) + #define SDDispatchQueueSetterSementics strong +#else +#undef SDDispatchQueueRelease +#undef SDDispatchQueueSetterSementics +#define SDDispatchQueueRelease(q) (dispatch_release(q)) +#define SDDispatchQueueSetterSementics assign +#endif + +extern UIImage *SDScaledImageForKey(NSString *key, UIImage *image); + +typedef void(^SDWebImageNoParamsBlock)(); + +#define dispatch_main_sync_safe(block)\ + if ([NSThread isMainThread]) {\ + block();\ + } else {\ + dispatch_sync(dispatch_get_main_queue(), block);\ + } + +#define dispatch_main_async_safe(block)\ + if ([NSThread isMainThread]) {\ + block();\ + } else {\ + dispatch_async(dispatch_get_main_queue(), block);\ + } diff --git a/ios/Pods/SDWebImage/SDWebImage/SDWebImageCompat.m b/ios/Pods/SDWebImage/SDWebImage/SDWebImageCompat.m new file mode 100644 index 000000000..8c7d345ab --- /dev/null +++ b/ios/Pods/SDWebImage/SDWebImage/SDWebImageCompat.m @@ -0,0 +1,45 @@ +// +// SDWebImageCompat.m +// SDWebImage +// +// Created by Olivier Poitrey on 11/12/12. +// Copyright (c) 2012 Dailymotion. All rights reserved. +// + +#import "SDWebImageCompat.h" + +#if !__has_feature(objc_arc) +#error SDWebImage is ARC only. Either turn on ARC for the project or use -fobjc-arc flag +#endif + +inline UIImage *SDScaledImageForKey(NSString *key, UIImage *image) { + if (!image) { + return nil; + } + + if ([image.images count] > 0) { + NSMutableArray *scaledImages = [NSMutableArray array]; + + for (UIImage *tempImage in image.images) { + [scaledImages addObject:SDScaledImageForKey(key, tempImage)]; + } + + return [UIImage animatedImageWithImages:scaledImages duration:image.duration]; + } + else { + if ([[UIScreen mainScreen] respondsToSelector:@selector(scale)]) { + CGFloat scale = 1.0; + if (key.length >= 8) { + // Search @2x. at the end of the string, before a 3 to 4 extension length (only if key len is 8 or more @2x. + 4 len ext) + NSRange range = [key rangeOfString:@"@2x." options:0 range:NSMakeRange(key.length - 8, 5)]; + if (range.location != NSNotFound) { + scale = 2.0; + } + } + + UIImage *scaledImage = [[UIImage alloc] initWithCGImage:image.CGImage scale:scale orientation:image.imageOrientation]; + image = scaledImage; + } + return image; + } +} diff --git a/ios/Pods/SDWebImage/SDWebImage/SDWebImageDecoder.h b/ios/Pods/SDWebImage/SDWebImage/SDWebImageDecoder.h new file mode 100644 index 000000000..0176a7bae --- /dev/null +++ b/ios/Pods/SDWebImage/SDWebImage/SDWebImageDecoder.h @@ -0,0 +1,18 @@ +/* + * This file is part of the SDWebImage package. + * (c) Olivier Poitrey + * + * Created by james on 9/28/11. + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +#import +#import "SDWebImageCompat.h" + +@interface UIImage (ForceDecode) + ++ (UIImage *)decodedImageWithImage:(UIImage *)image; + +@end diff --git a/ios/Pods/SDWebImage/SDWebImage/SDWebImageDecoder.m b/ios/Pods/SDWebImage/SDWebImage/SDWebImageDecoder.m new file mode 100644 index 000000000..79ddb30f6 --- /dev/null +++ b/ios/Pods/SDWebImage/SDWebImage/SDWebImageDecoder.m @@ -0,0 +1,72 @@ +/* + * This file is part of the SDWebImage package. + * (c) Olivier Poitrey + * + * Created by james on 9/28/11. + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +#import "SDWebImageDecoder.h" + +@implementation UIImage (ForceDecode) + ++ (UIImage *)decodedImageWithImage:(UIImage *)image { + if (image.images) { + // Do not decode animated images + return image; + } + + CGImageRef imageRef = image.CGImage; + CGSize imageSize = CGSizeMake(CGImageGetWidth(imageRef), CGImageGetHeight(imageRef)); + CGRect imageRect = (CGRect){.origin = CGPointZero, .size = imageSize}; + + CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB(); + CGBitmapInfo bitmapInfo = CGImageGetBitmapInfo(imageRef); + + int infoMask = (bitmapInfo & kCGBitmapAlphaInfoMask); + BOOL anyNonAlpha = (infoMask == kCGImageAlphaNone || + infoMask == kCGImageAlphaNoneSkipFirst || + infoMask == kCGImageAlphaNoneSkipLast); + + // CGBitmapContextCreate doesn't support kCGImageAlphaNone with RGB. + // https://developer.apple.com/library/mac/#qa/qa1037/_index.html + if (infoMask == kCGImageAlphaNone && CGColorSpaceGetNumberOfComponents(colorSpace) > 1) { + // Unset the old alpha info. + bitmapInfo &= ~kCGBitmapAlphaInfoMask; + + // Set noneSkipFirst. + bitmapInfo |= kCGImageAlphaNoneSkipFirst; + } + // Some PNGs tell us they have alpha but only 3 components. Odd. + else if (!anyNonAlpha && CGColorSpaceGetNumberOfComponents(colorSpace) == 3) { + // Unset the old alpha info. + bitmapInfo &= ~kCGBitmapAlphaInfoMask; + bitmapInfo |= kCGImageAlphaPremultipliedFirst; + } + + // It calculates the bytes-per-row based on the bitsPerComponent and width arguments. + CGContextRef context = CGBitmapContextCreate(NULL, + imageSize.width, + imageSize.height, + CGImageGetBitsPerComponent(imageRef), + 0, + colorSpace, + bitmapInfo); + CGColorSpaceRelease(colorSpace); + + // If failed, return undecompressed image + if (!context) return image; + + CGContextDrawImage(context, imageRect, imageRef); + CGImageRef decompressedImageRef = CGBitmapContextCreateImage(context); + + CGContextRelease(context); + + UIImage *decompressedImage = [UIImage imageWithCGImage:decompressedImageRef scale:image.scale orientation:image.imageOrientation]; + CGImageRelease(decompressedImageRef); + return decompressedImage; +} + +@end diff --git a/ios/Pods/SDWebImage/SDWebImage/SDWebImageDownloader.h b/ios/Pods/SDWebImage/SDWebImage/SDWebImageDownloader.h new file mode 100644 index 000000000..008231aff --- /dev/null +++ b/ios/Pods/SDWebImage/SDWebImage/SDWebImageDownloader.h @@ -0,0 +1,173 @@ +/* + * This file is part of the SDWebImage package. + * (c) Olivier Poitrey + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +#import +#import "SDWebImageCompat.h" +#import "SDWebImageOperation.h" + +typedef NS_OPTIONS(NSUInteger, SDWebImageDownloaderOptions) { + SDWebImageDownloaderLowPriority = 1 << 0, + SDWebImageDownloaderProgressiveDownload = 1 << 1, + + /** + * By default, request prevent the of NSURLCache. With this flag, NSURLCache + * is used with default policies. + */ + SDWebImageDownloaderUseNSURLCache = 1 << 2, + + /** + * Call completion block with nil image/imageData if the image was read from NSURLCache + * (to be combined with `SDWebImageDownloaderUseNSURLCache`). + */ + + SDWebImageDownloaderIgnoreCachedResponse = 1 << 3, + /** + * In iOS 4+, continue the download of the image if the app goes to background. This is achieved by asking the system for + * extra time in background to let the request finish. If the background task expires the operation will be cancelled. + */ + + SDWebImageDownloaderContinueInBackground = 1 << 4, + + /** + * Handles cookies stored in NSHTTPCookieStore by setting + * NSMutableURLRequest.HTTPShouldHandleCookies = YES; + */ + SDWebImageDownloaderHandleCookies = 1 << 5, + + /** + * Enable to allow untrusted SSL ceriticates. + * Useful for testing purposes. Use with caution in production. + */ + SDWebImageDownloaderAllowInvalidSSLCertificates = 1 << 6, + + /** + * Put the image in the high priority queue. + */ + SDWebImageDownloaderHighPriority = 1 << 7, + + +}; + +typedef NS_ENUM(NSInteger, SDWebImageDownloaderExecutionOrder) { + /** + * Default value. All download operations will execute in queue style (first-in-first-out). + */ + SDWebImageDownloaderFIFOExecutionOrder, + + /** + * All download operations will execute in stack style (last-in-first-out). + */ + SDWebImageDownloaderLIFOExecutionOrder +}; + +extern NSString *const SDWebImageDownloadStartNotification; +extern NSString *const SDWebImageDownloadStopNotification; + +typedef void(^SDWebImageDownloaderProgressBlock)(NSInteger receivedSize, NSInteger expectedSize); + +typedef void(^SDWebImageDownloaderCompletedBlock)(UIImage *image, NSData *data, NSError *error, BOOL finished); + +typedef NSDictionary *(^SDWebImageDownloaderHeadersFilterBlock)(NSURL *url, NSDictionary *headers); + +/** + * Asynchronous downloader dedicated and optimized for image loading. + */ +@interface SDWebImageDownloader : NSObject + +@property (assign, nonatomic) NSInteger maxConcurrentDownloads; + +/** + * Shows the current amount of downloads that still need to be downloaded + */ + +@property (readonly, nonatomic) NSUInteger currentDownloadCount; + + +/** + * The timeout value (in seconds) for the download operation. Default: 15.0. + */ +@property (assign, nonatomic) NSTimeInterval downloadTimeout; + + +/** + * Changes download operations execution order. Default value is `SDWebImageDownloaderFIFOExecutionOrder`. + */ +@property (assign, nonatomic) SDWebImageDownloaderExecutionOrder executionOrder; + +/** + * Singleton method, returns the shared instance + * + * @return global shared instance of downloader class + */ ++ (SDWebImageDownloader *)sharedDownloader; + +/** + * Set username + */ +@property (strong, nonatomic) NSString *username; + +/** + * Set password + */ +@property (strong, nonatomic) NSString *password; + +/** + * Set filter to pick headers for downloading image HTTP request. + * + * This block will be invoked for each downloading image request, returned + * NSDictionary will be used as headers in corresponding HTTP request. + */ +@property (nonatomic, copy) SDWebImageDownloaderHeadersFilterBlock headersFilter; + +/** + * Set a value for a HTTP header to be appended to each download HTTP request. + * + * @param value The value for the header field. Use `nil` value to remove the header. + * @param field The name of the header field to set. + */ +- (void)setValue:(NSString *)value forHTTPHeaderField:(NSString *)field; + +/** + * Returns the value of the specified HTTP header field. + * + * @return The value associated with the header field field, or `nil` if there is no corresponding header field. + */ +- (NSString *)valueForHTTPHeaderField:(NSString *)field; + +/** + * Creates a SDWebImageDownloader async downloader instance with a given URL + * + * The delegate will be informed when the image is finish downloaded or an error has happen. + * + * @see SDWebImageDownloaderDelegate + * + * @param url The URL to the image to download + * @param options The options to be used for this download + * @param progressBlock A block called repeatedly while the image is downloading + * @param completedBlock A block called once the download is completed. + * If the download succeeded, the image parameter is set, in case of error, + * error parameter is set with the error. The last parameter is always YES + * if SDWebImageDownloaderProgressiveDownload isn't use. With the + * SDWebImageDownloaderProgressiveDownload option, this block is called + * repeatedly with the partial image object and the finished argument set to NO + * before to be called a last time with the full image and finished argument + * set to YES. In case of error, the finished argument is always YES. + * + * @return A cancellable SDWebImageOperation + */ +- (id )downloadImageWithURL:(NSURL *)url + options:(SDWebImageDownloaderOptions)options + progress:(SDWebImageDownloaderProgressBlock)progressBlock + completed:(SDWebImageDownloaderCompletedBlock)completedBlock; + +/** + * Sets the download queue suspension state + */ +- (void)setSuspended:(BOOL)suspended; + +@end diff --git a/ios/Pods/SDWebImage/SDWebImage/SDWebImageDownloader.m b/ios/Pods/SDWebImage/SDWebImage/SDWebImageDownloader.m new file mode 100644 index 000000000..60914db3e --- /dev/null +++ b/ios/Pods/SDWebImage/SDWebImage/SDWebImageDownloader.m @@ -0,0 +1,225 @@ +/* + * This file is part of the SDWebImage package. + * (c) Olivier Poitrey + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +#import "SDWebImageDownloader.h" +#import "SDWebImageDownloaderOperation.h" +#import + +NSString *const SDWebImageDownloadStartNotification = @"SDWebImageDownloadStartNotification"; +NSString *const SDWebImageDownloadStopNotification = @"SDWebImageDownloadStopNotification"; + +static NSString *const kProgressCallbackKey = @"progress"; +static NSString *const kCompletedCallbackKey = @"completed"; + +@interface SDWebImageDownloader () + +@property (strong, nonatomic) NSOperationQueue *downloadQueue; +@property (weak, nonatomic) NSOperation *lastAddedOperation; +@property (strong, nonatomic) NSMutableDictionary *URLCallbacks; +@property (strong, nonatomic) NSMutableDictionary *HTTPHeaders; +// This queue is used to serialize the handling of the network responses of all the download operation in a single queue +@property (SDDispatchQueueSetterSementics, nonatomic) dispatch_queue_t barrierQueue; + +@end + +@implementation SDWebImageDownloader + ++ (void)initialize { + // Bind SDNetworkActivityIndicator if available (download it here: http://github.com/rs/SDNetworkActivityIndicator ) + // To use it, just add #import "SDNetworkActivityIndicator.h" in addition to the SDWebImage import + if (NSClassFromString(@"SDNetworkActivityIndicator")) { + +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Warc-performSelector-leaks" + id activityIndicator = [NSClassFromString(@"SDNetworkActivityIndicator") performSelector:NSSelectorFromString(@"sharedActivityIndicator")]; +#pragma clang diagnostic pop + + // Remove observer in case it was previously added. + [[NSNotificationCenter defaultCenter] removeObserver:activityIndicator name:SDWebImageDownloadStartNotification object:nil]; + [[NSNotificationCenter defaultCenter] removeObserver:activityIndicator name:SDWebImageDownloadStopNotification object:nil]; + + [[NSNotificationCenter defaultCenter] addObserver:activityIndicator + selector:NSSelectorFromString(@"startActivity") + name:SDWebImageDownloadStartNotification object:nil]; + [[NSNotificationCenter defaultCenter] addObserver:activityIndicator + selector:NSSelectorFromString(@"stopActivity") + name:SDWebImageDownloadStopNotification object:nil]; + } +} + ++ (SDWebImageDownloader *)sharedDownloader { + static dispatch_once_t once; + static id instance; + dispatch_once(&once, ^{ + instance = [self new]; + }); + return instance; +} + +- (id)init { + if ((self = [super init])) { + _executionOrder = SDWebImageDownloaderFIFOExecutionOrder; + _downloadQueue = [NSOperationQueue new]; + _downloadQueue.maxConcurrentOperationCount = 2; + _URLCallbacks = [NSMutableDictionary new]; + _HTTPHeaders = [NSMutableDictionary dictionaryWithObject:@"image/webp,image/*;q=0.8" forKey:@"Accept"]; + _barrierQueue = dispatch_queue_create("com.hackemist.SDWebImageDownloaderBarrierQueue", DISPATCH_QUEUE_CONCURRENT); + _downloadTimeout = 15.0; + } + return self; +} + +- (void)dealloc { + [self.downloadQueue cancelAllOperations]; + SDDispatchQueueRelease(_barrierQueue); +} + +- (void)setValue:(NSString *)value forHTTPHeaderField:(NSString *)field { + if (value) { + self.HTTPHeaders[field] = value; + } + else { + [self.HTTPHeaders removeObjectForKey:field]; + } +} + +- (NSString *)valueForHTTPHeaderField:(NSString *)field { + return self.HTTPHeaders[field]; +} + +- (void)setMaxConcurrentDownloads:(NSInteger)maxConcurrentDownloads { + _downloadQueue.maxConcurrentOperationCount = maxConcurrentDownloads; +} + +- (NSUInteger)currentDownloadCount { + return _downloadQueue.operationCount; +} + +- (NSInteger)maxConcurrentDownloads { + return _downloadQueue.maxConcurrentOperationCount; +} + +- (id )downloadImageWithURL:(NSURL *)url options:(SDWebImageDownloaderOptions)options progress:(SDWebImageDownloaderProgressBlock)progressBlock completed:(SDWebImageDownloaderCompletedBlock)completedBlock { + __block SDWebImageDownloaderOperation *operation; + __weak SDWebImageDownloader *wself = self; + + [self addProgressCallback:progressBlock andCompletedBlock:completedBlock forURL:url createCallback:^{ + NSTimeInterval timeoutInterval = wself.downloadTimeout; + if (timeoutInterval == 0.0) { + timeoutInterval = 15.0; + } + + // In order to prevent from potential duplicate caching (NSURLCache + SDImageCache) we disable the cache for image requests if told otherwise + NSMutableURLRequest *request = [[NSMutableURLRequest alloc] initWithURL:url cachePolicy:(options & SDWebImageDownloaderUseNSURLCache ? NSURLRequestUseProtocolCachePolicy : NSURLRequestReloadIgnoringLocalCacheData) timeoutInterval:timeoutInterval]; + request.HTTPShouldHandleCookies = (options & SDWebImageDownloaderHandleCookies); + request.HTTPShouldUsePipelining = YES; + if (wself.headersFilter) { + request.allHTTPHeaderFields = wself.headersFilter(url, [wself.HTTPHeaders copy]); + } + else { + request.allHTTPHeaderFields = wself.HTTPHeaders; + } + operation = [[SDWebImageDownloaderOperation alloc] initWithRequest:request + options:options + progress:^(NSInteger receivedSize, NSInteger expectedSize) { + SDWebImageDownloader *sself = wself; + if (!sself) return; + NSArray *callbacksForURL = [sself callbacksForURL:url]; + for (NSDictionary *callbacks in callbacksForURL) { + SDWebImageDownloaderProgressBlock callback = callbacks[kProgressCallbackKey]; + if (callback) callback(receivedSize, expectedSize); + } + } + completed:^(UIImage *image, NSData *data, NSError *error, BOOL finished) { + SDWebImageDownloader *sself = wself; + if (!sself) return; + NSArray *callbacksForURL = [sself callbacksForURL:url]; + if (finished) { + [sself removeCallbacksForURL:url]; + } + for (NSDictionary *callbacks in callbacksForURL) { + SDWebImageDownloaderCompletedBlock callback = callbacks[kCompletedCallbackKey]; + if (callback) callback(image, data, error, finished); + } + } + cancelled:^{ + SDWebImageDownloader *sself = wself; + if (!sself) return; + [sself removeCallbacksForURL:url]; + }]; + + if (wself.username && wself.password) { + operation.credential = [NSURLCredential credentialWithUser:wself.username password:wself.password persistence:NSURLCredentialPersistenceForSession]; + } + + if (options & SDWebImageDownloaderHighPriority) { + operation.queuePriority = NSOperationQueuePriorityHigh; + } else if (options & SDWebImageDownloaderLowPriority) { + operation.queuePriority = NSOperationQueuePriorityLow; + } + + [wself.downloadQueue addOperation:operation]; + if (wself.executionOrder == SDWebImageDownloaderLIFOExecutionOrder) { + // Emulate LIFO execution order by systematically adding new operations as last operation's dependency + [wself.lastAddedOperation addDependency:operation]; + wself.lastAddedOperation = operation; + } + }]; + + return operation; +} + +- (void)addProgressCallback:(SDWebImageDownloaderProgressBlock)progressBlock andCompletedBlock:(SDWebImageDownloaderCompletedBlock)completedBlock forURL:(NSURL *)url createCallback:(SDWebImageNoParamsBlock)createCallback { + // The URL will be used as the key to the callbacks dictionary so it cannot be nil. If it is nil immediately call the completed block with no image or data. + if (url == nil) { + if (completedBlock != nil) { + completedBlock(nil, nil, nil, NO); + } + return; + } + + dispatch_barrier_sync(self.barrierQueue, ^{ + BOOL first = NO; + if (!self.URLCallbacks[url]) { + self.URLCallbacks[url] = [NSMutableArray new]; + first = YES; + } + + // Handle single download of simultaneous download request for the same URL + NSMutableArray *callbacksForURL = self.URLCallbacks[url]; + NSMutableDictionary *callbacks = [NSMutableDictionary new]; + if (progressBlock) callbacks[kProgressCallbackKey] = [progressBlock copy]; + if (completedBlock) callbacks[kCompletedCallbackKey] = [completedBlock copy]; + [callbacksForURL addObject:callbacks]; + self.URLCallbacks[url] = callbacksForURL; + + if (first) { + createCallback(); + } + }); +} + +- (NSArray *)callbacksForURL:(NSURL *)url { + __block NSArray *callbacksForURL; + dispatch_sync(self.barrierQueue, ^{ + callbacksForURL = self.URLCallbacks[url]; + }); + return [callbacksForURL copy]; +} + +- (void)removeCallbacksForURL:(NSURL *)url { + dispatch_barrier_async(self.barrierQueue, ^{ + [self.URLCallbacks removeObjectForKey:url]; + }); +} + +- (void)setSuspended:(BOOL)suspended { + [self.downloadQueue setSuspended:suspended]; +} + +@end diff --git a/ios/Pods/SDWebImage/SDWebImage/SDWebImageDownloaderOperation.h b/ios/Pods/SDWebImage/SDWebImage/SDWebImageDownloaderOperation.h new file mode 100644 index 000000000..21a3106a4 --- /dev/null +++ b/ios/Pods/SDWebImage/SDWebImage/SDWebImageDownloaderOperation.h @@ -0,0 +1,60 @@ +/* + * This file is part of the SDWebImage package. + * (c) Olivier Poitrey + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +#import +#import "SDWebImageDownloader.h" +#import "SDWebImageOperation.h" + +@interface SDWebImageDownloaderOperation : NSOperation + +/** + * The request used by the operation's connection. + */ +@property (strong, nonatomic, readonly) NSURLRequest *request; + +/** + * Whether the URL connection should consult the credential storage for authenticating the connection. `YES` by default. + * + * This is the value that is returned in the `NSURLConnectionDelegate` method `-connectionShouldUseCredentialStorage:`. + */ +@property (nonatomic, assign) BOOL shouldUseCredentialStorage; + +/** + * The credential used for authentication challenges in `-connection:didReceiveAuthenticationChallenge:`. + * + * This will be overridden by any shared credentials that exist for the username or password of the request URL, if present. + */ +@property (nonatomic, strong) NSURLCredential *credential; + +/** + * The SDWebImageDownloaderOptions for the receiver. + */ +@property (assign, nonatomic, readonly) SDWebImageDownloaderOptions options; + +/** + * Initializes a `SDWebImageDownloaderOperation` object + * + * @see SDWebImageDownloaderOperation + * + * @param request the URL request + * @param options downloader options + * @param progressBlock the block executed when a new chunk of data arrives. + * @note the progress block is executed on a background queue + * @param completedBlock the block executed when the download is done. + * @note the completed block is executed on the main queue for success. If errors are found, there is a chance the block will be executed on a background queue + * @param cancelBlock the block executed if the download (operation) is cancelled + * + * @return the initialized instance + */ +- (id)initWithRequest:(NSURLRequest *)request + options:(SDWebImageDownloaderOptions)options + progress:(SDWebImageDownloaderProgressBlock)progressBlock + completed:(SDWebImageDownloaderCompletedBlock)completedBlock + cancelled:(SDWebImageNoParamsBlock)cancelBlock; + +@end diff --git a/ios/Pods/SDWebImage/SDWebImage/SDWebImageDownloaderOperation.m b/ios/Pods/SDWebImage/SDWebImage/SDWebImageDownloaderOperation.m new file mode 100644 index 000000000..333e316bc --- /dev/null +++ b/ios/Pods/SDWebImage/SDWebImage/SDWebImageDownloaderOperation.m @@ -0,0 +1,414 @@ +/* + * This file is part of the SDWebImage package. + * (c) Olivier Poitrey + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +#import "SDWebImageDownloaderOperation.h" +#import "SDWebImageDecoder.h" +#import "UIImage+MultiFormat.h" +#import +#import "SDWebImageManager.h" + +@interface SDWebImageDownloaderOperation () + +@property (copy, nonatomic) SDWebImageDownloaderProgressBlock progressBlock; +@property (copy, nonatomic) SDWebImageDownloaderCompletedBlock completedBlock; +@property (copy, nonatomic) SDWebImageNoParamsBlock cancelBlock; + +@property (assign, nonatomic, getter = isExecuting) BOOL executing; +@property (assign, nonatomic, getter = isFinished) BOOL finished; +@property (assign, nonatomic) NSInteger expectedSize; +@property (strong, nonatomic) NSMutableData *imageData; +@property (strong, nonatomic) NSURLConnection *connection; +@property (strong, atomic) NSThread *thread; + +#if TARGET_OS_IPHONE && __IPHONE_OS_VERSION_MAX_ALLOWED >= __IPHONE_4_0 +@property (assign, nonatomic) UIBackgroundTaskIdentifier backgroundTaskId; +#endif + +@end + +@implementation SDWebImageDownloaderOperation { + size_t width, height; + UIImageOrientation orientation; + BOOL responseFromCached; +} + +@synthesize executing = _executing; +@synthesize finished = _finished; + +- (id)initWithRequest:(NSURLRequest *)request + options:(SDWebImageDownloaderOptions)options + progress:(SDWebImageDownloaderProgressBlock)progressBlock + completed:(SDWebImageDownloaderCompletedBlock)completedBlock + cancelled:(SDWebImageNoParamsBlock)cancelBlock { + if ((self = [super init])) { + _request = request; + _shouldUseCredentialStorage = YES; + _options = options; + _progressBlock = [progressBlock copy]; + _completedBlock = [completedBlock copy]; + _cancelBlock = [cancelBlock copy]; + _executing = NO; + _finished = NO; + _expectedSize = 0; + responseFromCached = YES; // Initially wrong until `connection:willCacheResponse:` is called or not called + } + return self; +} + +- (void)start { + @synchronized (self) { + if (self.isCancelled) { + self.finished = YES; + [self reset]; + return; + } + +#if TARGET_OS_IPHONE && __IPHONE_OS_VERSION_MAX_ALLOWED >= __IPHONE_4_0 + if ([self shouldContinueWhenAppEntersBackground]) { + __weak __typeof__ (self) wself = self; + self.backgroundTaskId = [[UIApplication sharedApplication] beginBackgroundTaskWithExpirationHandler:^{ + __strong __typeof (wself) sself = wself; + + if (sself) { + [sself cancel]; + + [[UIApplication sharedApplication] endBackgroundTask:sself.backgroundTaskId]; + sself.backgroundTaskId = UIBackgroundTaskInvalid; + } + }]; + } +#endif + + self.executing = YES; + self.connection = [[NSURLConnection alloc] initWithRequest:self.request delegate:self startImmediately:NO]; + self.thread = [NSThread currentThread]; + } + + [self.connection start]; + + if (self.connection) { + if (self.progressBlock) { + self.progressBlock(0, NSURLResponseUnknownLength); + } + [[NSNotificationCenter defaultCenter] postNotificationName:SDWebImageDownloadStartNotification object:self]; + + if (floor(NSFoundationVersionNumber) <= NSFoundationVersionNumber_iOS_5_1) { + // Make sure to run the runloop in our background thread so it can process downloaded data + // Note: we use a timeout to work around an issue with NSURLConnection cancel under iOS 5 + // not waking up the runloop, leading to dead threads (see https://github.com/rs/SDWebImage/issues/466) + CFRunLoopRunInMode(kCFRunLoopDefaultMode, 10, false); + } + else { + CFRunLoopRun(); + } + + if (!self.isFinished) { + [self.connection cancel]; + [self connection:self.connection didFailWithError:[NSError errorWithDomain:NSURLErrorDomain code:NSURLErrorTimedOut userInfo:@{NSURLErrorFailingURLErrorKey : self.request.URL}]]; + } + } + else { + if (self.completedBlock) { + self.completedBlock(nil, nil, [NSError errorWithDomain:NSURLErrorDomain code:0 userInfo:@{NSLocalizedDescriptionKey : @"Connection can't be initialized"}], YES); + } + } + +#if TARGET_OS_IPHONE && __IPHONE_OS_VERSION_MAX_ALLOWED >= __IPHONE_4_0 + if (self.backgroundTaskId != UIBackgroundTaskInvalid) { + [[UIApplication sharedApplication] endBackgroundTask:self.backgroundTaskId]; + self.backgroundTaskId = UIBackgroundTaskInvalid; + } +#endif +} + +- (void)cancel { + @synchronized (self) { + if (self.thread) { + [self performSelector:@selector(cancelInternalAndStop) onThread:self.thread withObject:nil waitUntilDone:NO]; + } + else { + [self cancelInternal]; + } + } +} + +- (void)cancelInternalAndStop { + if (self.isFinished) return; + [self cancelInternal]; + CFRunLoopStop(CFRunLoopGetCurrent()); +} + +- (void)cancelInternal { + if (self.isFinished) return; + [super cancel]; + if (self.cancelBlock) self.cancelBlock(); + + if (self.connection) { + [self.connection cancel]; + [[NSNotificationCenter defaultCenter] postNotificationName:SDWebImageDownloadStopNotification object:self]; + + // As we cancelled the connection, its callback won't be called and thus won't + // maintain the isFinished and isExecuting flags. + if (self.isExecuting) self.executing = NO; + if (!self.isFinished) self.finished = YES; + } + + [self reset]; +} + +- (void)done { + self.finished = YES; + self.executing = NO; + [self reset]; +} + +- (void)reset { + self.cancelBlock = nil; + self.completedBlock = nil; + self.progressBlock = nil; + self.connection = nil; + self.imageData = nil; + self.thread = nil; +} + +- (void)setFinished:(BOOL)finished { + [self willChangeValueForKey:@"isFinished"]; + _finished = finished; + [self didChangeValueForKey:@"isFinished"]; +} + +- (void)setExecuting:(BOOL)executing { + [self willChangeValueForKey:@"isExecuting"]; + _executing = executing; + [self didChangeValueForKey:@"isExecuting"]; +} + +- (BOOL)isConcurrent { + return YES; +} + +#pragma mark NSURLConnection (delegate) + +- (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response { + if (![response respondsToSelector:@selector(statusCode)] || [((NSHTTPURLResponse *)response) statusCode] < 400) { + NSInteger expected = response.expectedContentLength > 0 ? (NSInteger)response.expectedContentLength : 0; + self.expectedSize = expected; + if (self.progressBlock) { + self.progressBlock(0, expected); + } + + self.imageData = [[NSMutableData alloc] initWithCapacity:expected]; + } + else { + [self.connection cancel]; + + [[NSNotificationCenter defaultCenter] postNotificationName:SDWebImageDownloadStopNotification object:nil]; + + if (self.completedBlock) { + self.completedBlock(nil, nil, [NSError errorWithDomain:NSURLErrorDomain code:[((NSHTTPURLResponse *)response) statusCode] userInfo:nil], YES); + } + CFRunLoopStop(CFRunLoopGetCurrent()); + [self done]; + } +} + +- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data { + [self.imageData appendData:data]; + + if ((self.options & SDWebImageDownloaderProgressiveDownload) && self.expectedSize > 0 && self.completedBlock) { + // The following code is from http://www.cocoaintheshell.com/2011/05/progressive-images-download-imageio/ + // Thanks to the author @Nyx0uf + + // Get the total bytes downloaded + const NSInteger totalSize = self.imageData.length; + + // Update the data source, we must pass ALL the data, not just the new bytes + CGImageSourceRef imageSource = CGImageSourceCreateIncremental(NULL); + CGImageSourceUpdateData(imageSource, (__bridge CFDataRef)self.imageData, totalSize == self.expectedSize); + + if (width + height == 0) { + CFDictionaryRef properties = CGImageSourceCopyPropertiesAtIndex(imageSource, 0, NULL); + if (properties) { + NSInteger orientationValue = -1; + CFTypeRef val = CFDictionaryGetValue(properties, kCGImagePropertyPixelHeight); + if (val) CFNumberGetValue(val, kCFNumberLongType, &height); + val = CFDictionaryGetValue(properties, kCGImagePropertyPixelWidth); + if (val) CFNumberGetValue(val, kCFNumberLongType, &width); + val = CFDictionaryGetValue(properties, kCGImagePropertyOrientation); + if (val) CFNumberGetValue(val, kCFNumberNSIntegerType, &orientationValue); + CFRelease(properties); + + // When we draw to Core Graphics, we lose orientation information, + // which means the image below born of initWithCGIImage will be + // oriented incorrectly sometimes. (Unlike the image born of initWithData + // in connectionDidFinishLoading.) So save it here and pass it on later. + orientation = [[self class] orientationFromPropertyValue:(orientationValue == -1 ? 1 : orientationValue)]; + } + + } + + if (width + height > 0 && totalSize < self.expectedSize) { + // Create the image + CGImageRef partialImageRef = CGImageSourceCreateImageAtIndex(imageSource, 0, NULL); + +#ifdef TARGET_OS_IPHONE + // Workaround for iOS anamorphic image + if (partialImageRef) { + const size_t partialHeight = CGImageGetHeight(partialImageRef); + CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB(); + CGContextRef bmContext = CGBitmapContextCreate(NULL, width, height, 8, width * 4, colorSpace, kCGBitmapByteOrderDefault | kCGImageAlphaPremultipliedFirst); + CGColorSpaceRelease(colorSpace); + if (bmContext) { + CGContextDrawImage(bmContext, (CGRect){.origin.x = 0.0f, .origin.y = 0.0f, .size.width = width, .size.height = partialHeight}, partialImageRef); + CGImageRelease(partialImageRef); + partialImageRef = CGBitmapContextCreateImage(bmContext); + CGContextRelease(bmContext); + } + else { + CGImageRelease(partialImageRef); + partialImageRef = nil; + } + } +#endif + + if (partialImageRef) { + UIImage *image = [UIImage imageWithCGImage:partialImageRef scale:1 orientation:orientation]; + NSString *key = [[SDWebImageManager sharedManager] cacheKeyForURL:self.request.URL]; + UIImage *scaledImage = [self scaledImageForKey:key image:image]; + image = [UIImage decodedImageWithImage:scaledImage]; + CGImageRelease(partialImageRef); + dispatch_main_sync_safe(^{ + if (self.completedBlock) { + self.completedBlock(image, nil, nil, NO); + } + }); + } + } + + CFRelease(imageSource); + } + + if (self.progressBlock) { + self.progressBlock(self.imageData.length, self.expectedSize); + } +} + ++ (UIImageOrientation)orientationFromPropertyValue:(NSInteger)value { + switch (value) { + case 1: + return UIImageOrientationUp; + case 3: + return UIImageOrientationDown; + case 8: + return UIImageOrientationLeft; + case 6: + return UIImageOrientationRight; + case 2: + return UIImageOrientationUpMirrored; + case 4: + return UIImageOrientationDownMirrored; + case 5: + return UIImageOrientationLeftMirrored; + case 7: + return UIImageOrientationRightMirrored; + default: + return UIImageOrientationUp; + } +} + +- (UIImage *)scaledImageForKey:(NSString *)key image:(UIImage *)image { + return SDScaledImageForKey(key, image); +} + +- (void)connectionDidFinishLoading:(NSURLConnection *)aConnection { + SDWebImageDownloaderCompletedBlock completionBlock = self.completedBlock; + @synchronized(self) { + CFRunLoopStop(CFRunLoopGetCurrent()); + self.thread = nil; + self.connection = nil; + [[NSNotificationCenter defaultCenter] postNotificationName:SDWebImageDownloadStopNotification object:nil]; + } + + if (![[NSURLCache sharedURLCache] cachedResponseForRequest:_request]) { + responseFromCached = NO; + } + + if (completionBlock) + { + if (self.options & SDWebImageDownloaderIgnoreCachedResponse && responseFromCached) { + completionBlock(nil, nil, nil, YES); + } + else { + UIImage *image = [UIImage sd_imageWithData:self.imageData]; + NSString *key = [[SDWebImageManager sharedManager] cacheKeyForURL:self.request.URL]; + image = [self scaledImageForKey:key image:image]; + + // Do not force decoding animated GIFs + if (!image.images) { + image = [UIImage decodedImageWithImage:image]; + } + if (CGSizeEqualToSize(image.size, CGSizeZero)) { + completionBlock(nil, nil, [NSError errorWithDomain:@"SDWebImageErrorDomain" code:0 userInfo:@{NSLocalizedDescriptionKey : @"Downloaded image has 0 pixels"}], YES); + } + else { + completionBlock(image, self.imageData, nil, YES); + } + } + } + self.completionBlock = nil; + [self done]; +} + +- (void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error { + CFRunLoopStop(CFRunLoopGetCurrent()); + [[NSNotificationCenter defaultCenter] postNotificationName:SDWebImageDownloadStopNotification object:nil]; + + if (self.completedBlock) { + self.completedBlock(nil, nil, error, YES); + } + + [self done]; +} + +- (NSCachedURLResponse *)connection:(NSURLConnection *)connection willCacheResponse:(NSCachedURLResponse *)cachedResponse { + responseFromCached = NO; // If this method is called, it means the response wasn't read from cache + if (self.request.cachePolicy == NSURLRequestReloadIgnoringLocalCacheData) { + // Prevents caching of responses + return nil; + } + else { + return cachedResponse; + } +} + +- (BOOL)shouldContinueWhenAppEntersBackground { + return self.options & SDWebImageDownloaderContinueInBackground; +} + +- (BOOL)connectionShouldUseCredentialStorage:(NSURLConnection __unused *)connection { + return self.shouldUseCredentialStorage; +} + +- (void)connection:(NSURLConnection *)connection willSendRequestForAuthenticationChallenge:(NSURLAuthenticationChallenge *)challenge{ + if ([challenge.protectionSpace.authenticationMethod isEqualToString:NSURLAuthenticationMethodServerTrust]) { + NSURLCredential *credential = [NSURLCredential credentialForTrust:challenge.protectionSpace.serverTrust]; + [[challenge sender] useCredential:credential forAuthenticationChallenge:challenge]; + } else { + if ([challenge previousFailureCount] == 0) { + if (self.credential) { + [[challenge sender] useCredential:self.credential forAuthenticationChallenge:challenge]; + } else { + [[challenge sender] continueWithoutCredentialForAuthenticationChallenge:challenge]; + } + } else { + [[challenge sender] continueWithoutCredentialForAuthenticationChallenge:challenge]; + } + } +} + +@end diff --git a/ios/Pods/SDWebImage/SDWebImage/SDWebImageManager.h b/ios/Pods/SDWebImage/SDWebImage/SDWebImageManager.h new file mode 100644 index 000000000..6bb0dcfaf --- /dev/null +++ b/ios/Pods/SDWebImage/SDWebImage/SDWebImageManager.h @@ -0,0 +1,285 @@ +/* + * This file is part of the SDWebImage package. + * (c) Olivier Poitrey + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +#import "SDWebImageCompat.h" +#import "SDWebImageOperation.h" +#import "SDWebImageDownloader.h" +#import "SDImageCache.h" + +typedef NS_OPTIONS(NSUInteger, SDWebImageOptions) { + /** + * By default, when a URL fail to be downloaded, the URL is blacklisted so the library won't keep trying. + * This flag disable this blacklisting. + */ + SDWebImageRetryFailed = 1 << 0, + + /** + * By default, image downloads are started during UI interactions, this flags disable this feature, + * leading to delayed download on UIScrollView deceleration for instance. + */ + SDWebImageLowPriority = 1 << 1, + + /** + * This flag disables on-disk caching + */ + SDWebImageCacheMemoryOnly = 1 << 2, + + /** + * This flag enables progressive download, the image is displayed progressively during download as a browser would do. + * By default, the image is only displayed once completely downloaded. + */ + SDWebImageProgressiveDownload = 1 << 3, + + /** + * Even if the image is cached, respect the HTTP response cache control, and refresh the image from remote location if needed. + * The disk caching will be handled by NSURLCache instead of SDWebImage leading to slight performance degradation. + * This option helps deal with images changing behind the same request URL, e.g. Facebook graph api profile pics. + * If a cached image is refreshed, the completion block is called once with the cached image and again with the final image. + * + * Use this flag only if you can't make your URLs static with embeded cache busting parameter. + */ + SDWebImageRefreshCached = 1 << 4, + + /** + * In iOS 4+, continue the download of the image if the app goes to background. This is achieved by asking the system for + * extra time in background to let the request finish. If the background task expires the operation will be cancelled. + */ + SDWebImageContinueInBackground = 1 << 5, + + /** + * Handles cookies stored in NSHTTPCookieStore by setting + * NSMutableURLRequest.HTTPShouldHandleCookies = YES; + */ + SDWebImageHandleCookies = 1 << 6, + + /** + * Enable to allow untrusted SSL ceriticates. + * Useful for testing purposes. Use with caution in production. + */ + SDWebImageAllowInvalidSSLCertificates = 1 << 7, + + /** + * By default, image are loaded in the order they were queued. This flag move them to + * the front of the queue and is loaded immediately instead of waiting for the current queue to be loaded (which + * could take a while). + */ + SDWebImageHighPriority = 1 << 8, + + /** + * By default, placeholder images are loaded while the image is loading. This flag will delay the loading + * of the placeholder image until after the image has finished loading. + */ + SDWebImageDelayPlaceholder = 1 << 9 +}; + +typedef void(^SDWebImageCompletionBlock)(UIImage *image, NSError *error, SDImageCacheType cacheType, NSURL *imageURL); + +typedef void(^SDWebImageCompletionWithFinishedBlock)(UIImage *image, NSError *error, SDImageCacheType cacheType, BOOL finished, NSURL *imageURL); + +typedef NSString *(^SDWebImageCacheKeyFilterBlock)(NSURL *url); + + +@class SDWebImageManager; + +@protocol SDWebImageManagerDelegate + +@optional + +/** + * Controls which image should be downloaded when the image is not found in the cache. + * + * @param imageManager The current `SDWebImageManager` + * @param imageURL The url of the image to be downloaded + * + * @return Return NO to prevent the downloading of the image on cache misses. If not implemented, YES is implied. + */ +- (BOOL)imageManager:(SDWebImageManager *)imageManager shouldDownloadImageForURL:(NSURL *)imageURL; + +/** + * Allows to transform the image immediately after it has been downloaded and just before to cache it on disk and memory. + * NOTE: This method is called from a global queue in order to not to block the main thread. + * + * @param imageManager The current `SDWebImageManager` + * @param image The image to transform + * @param imageURL The url of the image to transform + * + * @return The transformed image object. + */ +- (UIImage *)imageManager:(SDWebImageManager *)imageManager transformDownloadedImage:(UIImage *)image withURL:(NSURL *)imageURL; + +@end + +/** + * The SDWebImageManager is the class behind the UIImageView+WebCache category and likes. + * It ties the asynchronous downloader (SDWebImageDownloader) with the image cache store (SDImageCache). + * You can use this class directly to benefit from web image downloading with caching in another context than + * a UIView. + * + * Here is a simple example of how to use SDWebImageManager: + * + * @code + +SDWebImageManager *manager = [SDWebImageManager sharedManager]; +[manager downloadWithURL:imageURL + options:0 + progress:nil + completed:^(UIImage *image, NSError *error, SDImageCacheType cacheType, BOOL finished, NSURL *imageURL) { + if (image) { + // do something with image + } + }]; + + * @endcode + */ +@interface SDWebImageManager : NSObject + +@property (weak, nonatomic) id delegate; + +@property (strong, nonatomic, readonly) SDImageCache *imageCache; +@property (strong, nonatomic, readonly) SDWebImageDownloader *imageDownloader; + +/** + * The cache filter is a block used each time SDWebImageManager need to convert an URL into a cache key. This can + * be used to remove dynamic part of an image URL. + * + * The following example sets a filter in the application delegate that will remove any query-string from the + * URL before to use it as a cache key: + * + * @code + +[[SDWebImageManager sharedManager] setCacheKeyFilter:^(NSURL *url) { + url = [[NSURL alloc] initWithScheme:url.scheme host:url.host path:url.path]; + return [url absoluteString]; +}]; + + * @endcode + */ +@property (copy) SDWebImageCacheKeyFilterBlock cacheKeyFilter; + +/** + * Returns global SDWebImageManager instance. + * + * @return SDWebImageManager shared instance + */ ++ (SDWebImageManager *)sharedManager; + +/** + * Downloads the image at the given URL if not present in cache or return the cached version otherwise. + * + * @param url The URL to the image + * @param options A mask to specify options to use for this request + * @param progressBlock A block called while image is downloading + * @param completedBlock A block called when operation has been completed. + * + * This parameter is required. + * + * This block has no return value and takes the requested UIImage as first parameter. + * In case of error the image parameter is nil and the second parameter may contain an NSError. + * + * The third parameter is an `SDImageCacheType` enum indicating if the image was retrived from the local cache + * or from the memory cache or from the network. + * + * The last parameter is set to NO when the SDWebImageProgressiveDownload option is used and the image is + * downloading. This block is thus called repetidly with a partial image. When image is fully downloaded, the + * block is called a last time with the full image and the last parameter set to YES. + * + * @return Returns an NSObject conforming to SDWebImageOperation. Should be an instance of SDWebImageDownloaderOperation + */ +- (id )downloadImageWithURL:(NSURL *)url + options:(SDWebImageOptions)options + progress:(SDWebImageDownloaderProgressBlock)progressBlock + completed:(SDWebImageCompletionWithFinishedBlock)completedBlock; + +/** + * Saves image to cache for given URL + * + * @param image The image to cache + * @param url The URL to the image + * + */ + +- (void)saveImageToCache:(UIImage *)image forURL:(NSURL *)url; + +/** + * Cancel all current opreations + */ +- (void)cancelAll; + +/** + * Check one or more operations running + */ +- (BOOL)isRunning; + +/** + * Check if image has already been cached + * + * @param url image url + * + * @return if the image was already cached + */ +- (BOOL)cachedImageExistsForURL:(NSURL *)url; + +/** + * Check if image has already been cached on disk only + * + * @param url image url + * + * @return if the image was already cached (disk only) + */ +- (BOOL)diskImageExistsForURL:(NSURL *)url; + +/** + * Async check if image has already been cached + * + * @param url image url + * @param completionBlock the block to be executed when the check is finished + * + * @note the completion block is always executed on the main queue + */ +- (void)cachedImageExistsForURL:(NSURL *)url + completion:(SDWebImageCheckCacheCompletionBlock)completionBlock; + +/** + * Async check if image has already been cached on disk only + * + * @param url image url + * @param completionBlock the block to be executed when the check is finished + * + * @note the completion block is always executed on the main queue + */ +- (void)diskImageExistsForURL:(NSURL *)url + completion:(SDWebImageCheckCacheCompletionBlock)completionBlock; + + +/** + *Return the cache key for a given URL + */ +- (NSString *)cacheKeyForURL:(NSURL *)url; + +@end + + +#pragma mark - Deprecated + +typedef void(^SDWebImageCompletedBlock)(UIImage *image, NSError *error, SDImageCacheType cacheType) __deprecated_msg("Block type deprecated. Use `SDWebImageCompletionBlock`"); +typedef void(^SDWebImageCompletedWithFinishedBlock)(UIImage *image, NSError *error, SDImageCacheType cacheType, BOOL finished) __deprecated_msg("Block type deprecated. Use `SDWebImageCompletionWithFinishedBlock`"); + + +@interface SDWebImageManager (Deprecated) + +/** + * Downloads the image at the given URL if not present in cache or return the cached version otherwise. + * + * @deprecated This method has been deprecated. Use `downloadImageWithURL:options:progress:completed:` + */ +- (id )downloadWithURL:(NSURL *)url + options:(SDWebImageOptions)options + progress:(SDWebImageDownloaderProgressBlock)progressBlock + completed:(SDWebImageCompletedWithFinishedBlock)completedBlock __deprecated_msg("Method deprecated. Use `downloadImageWithURL:options:progress:completed:`"); + +@end diff --git a/ios/Pods/SDWebImage/SDWebImage/SDWebImageManager.m b/ios/Pods/SDWebImage/SDWebImage/SDWebImageManager.m new file mode 100644 index 000000000..2781ec876 --- /dev/null +++ b/ios/Pods/SDWebImage/SDWebImage/SDWebImageManager.m @@ -0,0 +1,346 @@ +/* + * This file is part of the SDWebImage package. + * (c) Olivier Poitrey + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +#import "SDWebImageManager.h" +#import + +@interface SDWebImageCombinedOperation : NSObject + +@property (assign, nonatomic, getter = isCancelled) BOOL cancelled; +@property (copy, nonatomic) SDWebImageNoParamsBlock cancelBlock; +@property (strong, nonatomic) NSOperation *cacheOperation; + +@end + +@interface SDWebImageManager () + +@property (strong, nonatomic, readwrite) SDImageCache *imageCache; +@property (strong, nonatomic, readwrite) SDWebImageDownloader *imageDownloader; +@property (strong, nonatomic) NSMutableArray *failedURLs; +@property (strong, nonatomic) NSMutableArray *runningOperations; + +@end + +@implementation SDWebImageManager + ++ (id)sharedManager { + static dispatch_once_t once; + static id instance; + dispatch_once(&once, ^{ + instance = [self new]; + }); + return instance; +} + +- (id)init { + if ((self = [super init])) { + _imageCache = [self createCache]; + _imageDownloader = [SDWebImageDownloader sharedDownloader]; + _failedURLs = [NSMutableArray new]; + _runningOperations = [NSMutableArray new]; + } + return self; +} + +- (SDImageCache *)createCache { + return [SDImageCache sharedImageCache]; +} + +- (NSString *)cacheKeyForURL:(NSURL *)url { + if (self.cacheKeyFilter) { + return self.cacheKeyFilter(url); + } + else { + return [url absoluteString]; + } +} + +- (BOOL)cachedImageExistsForURL:(NSURL *)url { + NSString *key = [self cacheKeyForURL:url]; + if ([self.imageCache imageFromMemoryCacheForKey:key] != nil) return YES; + return [self.imageCache diskImageExistsWithKey:key]; +} + +- (BOOL)diskImageExistsForURL:(NSURL *)url { + NSString *key = [self cacheKeyForURL:url]; + return [self.imageCache diskImageExistsWithKey:key]; +} + +- (void)cachedImageExistsForURL:(NSURL *)url + completion:(SDWebImageCheckCacheCompletionBlock)completionBlock { + NSString *key = [self cacheKeyForURL:url]; + + BOOL isInMemoryCache = ([self.imageCache imageFromMemoryCacheForKey:key] != nil); + + if (isInMemoryCache) { + // making sure we call the completion block on the main queue + dispatch_async(dispatch_get_main_queue(), ^{ + if (completionBlock) { + completionBlock(YES); + } + }); + return; + } + + [self.imageCache diskImageExistsWithKey:key completion:^(BOOL isInDiskCache) { + // the completion block of checkDiskCacheForImageWithKey:completion: is always called on the main queue, no need to further dispatch + if (completionBlock) { + completionBlock(isInDiskCache); + } + }]; +} + +- (void)diskImageExistsForURL:(NSURL *)url + completion:(SDWebImageCheckCacheCompletionBlock)completionBlock { + NSString *key = [self cacheKeyForURL:url]; + + [self.imageCache diskImageExistsWithKey:key completion:^(BOOL isInDiskCache) { + // the completion block of checkDiskCacheForImageWithKey:completion: is always called on the main queue, no need to further dispatch + if (completionBlock) { + completionBlock(isInDiskCache); + } + }]; +} + +- (id )downloadImageWithURL:(NSURL *)url + options:(SDWebImageOptions)options + progress:(SDWebImageDownloaderProgressBlock)progressBlock + completed:(SDWebImageCompletionWithFinishedBlock)completedBlock { + // Invoking this method without a completedBlock is pointless + NSParameterAssert(completedBlock); + + // Very common mistake is to send the URL using NSString object instead of NSURL. For some strange reason, XCode won't + // throw any warning for this type mismatch. Here we failsafe this error by allowing URLs to be passed as NSString. + if ([url isKindOfClass:NSString.class]) { + url = [NSURL URLWithString:(NSString *)url]; + } + + // Prevents app crashing on argument type error like sending NSNull instead of NSURL + if (![url isKindOfClass:NSURL.class]) { + url = nil; + } + + __block SDWebImageCombinedOperation *operation = [SDWebImageCombinedOperation new]; + __weak SDWebImageCombinedOperation *weakOperation = operation; + + BOOL isFailedUrl = NO; + @synchronized (self.failedURLs) { + isFailedUrl = [self.failedURLs containsObject:url]; + } + + if (!url || (!(options & SDWebImageRetryFailed) && isFailedUrl)) { + dispatch_main_sync_safe(^{ + NSError *error = [NSError errorWithDomain:NSURLErrorDomain code:NSURLErrorFileDoesNotExist userInfo:nil]; + completedBlock(nil, error, SDImageCacheTypeNone, YES, url); + }); + return operation; + } + + @synchronized (self.runningOperations) { + [self.runningOperations addObject:operation]; + } + NSString *key = [self cacheKeyForURL:url]; + + operation.cacheOperation = [self.imageCache queryDiskCacheForKey:key done:^(UIImage *image, SDImageCacheType cacheType) { + if (operation.isCancelled) { + @synchronized (self.runningOperations) { + [self.runningOperations removeObject:operation]; + } + + return; + } + + if ((!image || options & SDWebImageRefreshCached) && (![self.delegate respondsToSelector:@selector(imageManager:shouldDownloadImageForURL:)] || [self.delegate imageManager:self shouldDownloadImageForURL:url])) { + if (image && options & SDWebImageRefreshCached) { + dispatch_main_sync_safe(^{ + // If image was found in the cache bug SDWebImageRefreshCached is provided, notify about the cached image + // AND try to re-download it in order to let a chance to NSURLCache to refresh it from server. + completedBlock(image, nil, cacheType, YES, url); + }); + } + + // download if no image or requested to refresh anyway, and download allowed by delegate + SDWebImageDownloaderOptions downloaderOptions = 0; + if (options & SDWebImageLowPriority) downloaderOptions |= SDWebImageDownloaderLowPriority; + if (options & SDWebImageProgressiveDownload) downloaderOptions |= SDWebImageDownloaderProgressiveDownload; + if (options & SDWebImageRefreshCached) downloaderOptions |= SDWebImageDownloaderUseNSURLCache; + if (options & SDWebImageContinueInBackground) downloaderOptions |= SDWebImageDownloaderContinueInBackground; + if (options & SDWebImageHandleCookies) downloaderOptions |= SDWebImageDownloaderHandleCookies; + if (options & SDWebImageAllowInvalidSSLCertificates) downloaderOptions |= SDWebImageDownloaderAllowInvalidSSLCertificates; + if (options & SDWebImageHighPriority) downloaderOptions |= SDWebImageDownloaderHighPriority; + if (image && options & SDWebImageRefreshCached) { + // force progressive off if image already cached but forced refreshing + downloaderOptions &= ~SDWebImageDownloaderProgressiveDownload; + // ignore image read from NSURLCache if image if cached but force refreshing + downloaderOptions |= SDWebImageDownloaderIgnoreCachedResponse; + } + id subOperation = [self.imageDownloader downloadImageWithURL:url options:downloaderOptions progress:progressBlock completed:^(UIImage *downloadedImage, NSData *data, NSError *error, BOOL finished) { + if (weakOperation.isCancelled) { + // Do nothing if the operation was cancelled + // See #699 for more details + // if we would call the completedBlock, there could be a race condition between this block and another completedBlock for the same object, so if this one is called second, we will overwrite the new data + } + else if (error) { + dispatch_main_sync_safe(^{ + if (!weakOperation.isCancelled) { + completedBlock(nil, error, SDImageCacheTypeNone, finished, url); + } + }); + + if (error.code != NSURLErrorNotConnectedToInternet && error.code != NSURLErrorCancelled && error.code != NSURLErrorTimedOut) { + @synchronized (self.failedURLs) { + [self.failedURLs addObject:url]; + } + } + } + else { + BOOL cacheOnDisk = !(options & SDWebImageCacheMemoryOnly); + + if (options & SDWebImageRefreshCached && image && !downloadedImage) { + // Image refresh hit the NSURLCache cache, do not call the completion block + } + // NOTE: We don't call transformDownloadedImage delegate method on animated images as most transformation code would mangle it + else if (downloadedImage && !downloadedImage.images && [self.delegate respondsToSelector:@selector(imageManager:transformDownloadedImage:withURL:)]) { + dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0), ^{ + UIImage *transformedImage = [self.delegate imageManager:self transformDownloadedImage:downloadedImage withURL:url]; + + if (transformedImage && finished) { + BOOL imageWasTransformed = ![transformedImage isEqual:downloadedImage]; + [self.imageCache storeImage:transformedImage recalculateFromImage:imageWasTransformed imageData:data forKey:key toDisk:cacheOnDisk]; + } + + dispatch_main_sync_safe(^{ + if (!weakOperation.isCancelled) { + completedBlock(transformedImage, nil, SDImageCacheTypeNone, finished, url); + } + }); + }); + } + else { + if (downloadedImage && finished) { + [self.imageCache storeImage:downloadedImage recalculateFromImage:NO imageData:data forKey:key toDisk:cacheOnDisk]; + } + + dispatch_main_sync_safe(^{ + if (!weakOperation.isCancelled) { + completedBlock(downloadedImage, nil, SDImageCacheTypeNone, finished, url); + } + }); + } + } + + if (finished) { + @synchronized (self.runningOperations) { + [self.runningOperations removeObject:operation]; + } + } + }]; + operation.cancelBlock = ^{ + [subOperation cancel]; + + @synchronized (self.runningOperations) { + [self.runningOperations removeObject:weakOperation]; + } + }; + } + else if (image) { + dispatch_main_sync_safe(^{ + if (!weakOperation.isCancelled) { + completedBlock(image, nil, cacheType, YES, url); + } + }); + @synchronized (self.runningOperations) { + [self.runningOperations removeObject:operation]; + } + } + else { + // Image not in cache and download disallowed by delegate + dispatch_main_sync_safe(^{ + if (!weakOperation.isCancelled) { + completedBlock(nil, nil, SDImageCacheTypeNone, YES, url); + } + }); + @synchronized (self.runningOperations) { + [self.runningOperations removeObject:operation]; + } + } + }]; + + return operation; +} + +- (void)saveImageToCache:(UIImage *)image forURL:(NSURL *)url { + if (image && url) { + NSString *key = [self cacheKeyForURL:url]; + [self.imageCache storeImage:image forKey:key toDisk:YES]; + } +} + +- (void)cancelAll { + @synchronized (self.runningOperations) { + [self.runningOperations makeObjectsPerformSelector:@selector(cancel)]; + [self.runningOperations removeAllObjects]; + } +} + +- (BOOL)isRunning { + return self.runningOperations.count > 0; +} + +@end + + +@implementation SDWebImageCombinedOperation + +- (void)setCancelBlock:(SDWebImageNoParamsBlock)cancelBlock { + // check if the operation is already cancelled, then we just call the cancelBlock + if (self.isCancelled) { + if (cancelBlock) { + cancelBlock(); + } + _cancelBlock = nil; // don't forget to nil the cancelBlock, otherwise we will get crashes + } else { + _cancelBlock = [cancelBlock copy]; + } +} + +- (void)cancel { + self.cancelled = YES; + if (self.cacheOperation) { + [self.cacheOperation cancel]; + self.cacheOperation = nil; + } + if (self.cancelBlock) { + self.cancelBlock(); + + // TODO: this is a temporary fix to #809. + // Until we can figure the exact cause of the crash, going with the ivar instead of the setter +// self.cancelBlock = nil; + _cancelBlock = nil; + } +} + +@end + + +@implementation SDWebImageManager (Deprecated) + +// deprecated method, uses the non deprecated method +// adapter for the completion block +- (id )downloadWithURL:(NSURL *)url options:(SDWebImageOptions)options progress:(SDWebImageDownloaderProgressBlock)progressBlock completed:(SDWebImageCompletedWithFinishedBlock)completedBlock { + return [self downloadImageWithURL:url + options:options + progress:progressBlock + completed:^(UIImage *image, NSError *error, SDImageCacheType cacheType, BOOL finished, NSURL *imageURL) { + if (completedBlock) { + completedBlock(image, error, cacheType, finished); + } + }]; +} + +@end diff --git a/ios/Pods/SDWebImage/SDWebImage/SDWebImageOperation.h b/ios/Pods/SDWebImage/SDWebImage/SDWebImageOperation.h new file mode 100644 index 000000000..71094ee36 --- /dev/null +++ b/ios/Pods/SDWebImage/SDWebImage/SDWebImageOperation.h @@ -0,0 +1,15 @@ +/* + * This file is part of the SDWebImage package. + * (c) Olivier Poitrey + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +#import + +@protocol SDWebImageOperation + +- (void)cancel; + +@end diff --git a/ios/Pods/SDWebImage/SDWebImage/SDWebImagePrefetcher.h b/ios/Pods/SDWebImage/SDWebImage/SDWebImagePrefetcher.h new file mode 100644 index 000000000..4f14fa290 --- /dev/null +++ b/ios/Pods/SDWebImage/SDWebImage/SDWebImagePrefetcher.h @@ -0,0 +1,98 @@ +/* + * This file is part of the SDWebImage package. + * (c) Olivier Poitrey + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +#import +#import "SDWebImageManager.h" + +@class SDWebImagePrefetcher; + +@protocol SDWebImagePrefetcherDelegate + +@optional + +/** + * Called when an image was prefetched. + * + * @param imagePrefetcher The current image prefetcher + * @param imageURL The image url that was prefetched + * @param finishedCount The total number of images that were prefetched (successful or not) + * @param totalCount The total number of images that were to be prefetched + */ +- (void)imagePrefetcher:(SDWebImagePrefetcher *)imagePrefetcher didPrefetchURL:(NSURL *)imageURL finishedCount:(NSUInteger)finishedCount totalCount:(NSUInteger)totalCount; + +/** + * Called when all images are prefetched. + * @param imagePrefetcher The current image prefetcher + * @param totalCount The total number of images that were prefetched (whether successful or not) + * @param skippedCount The total number of images that were skipped + */ +- (void)imagePrefetcher:(SDWebImagePrefetcher *)imagePrefetcher didFinishWithTotalCount:(NSUInteger)totalCount skippedCount:(NSUInteger)skippedCount; + +@end + +typedef void(^SDWebImagePrefetcherProgressBlock)(NSUInteger noOfFinishedUrls, NSUInteger noOfTotalUrls); +typedef void(^SDWebImagePrefetcherCompletionBlock)(NSUInteger noOfFinishedUrls, NSUInteger noOfSkippedUrls); + +/** + * Prefetch some URLs in the cache for future use. Images are downloaded in low priority. + */ +@interface SDWebImagePrefetcher : NSObject + +/** + * The web image manager + */ +@property (strong, nonatomic, readonly) SDWebImageManager *manager; + +/** + * Maximum number of URLs to prefetch at the same time. Defaults to 3. + */ +@property (nonatomic, assign) NSUInteger maxConcurrentDownloads; + +/** + * SDWebImageOptions for prefetcher. Defaults to SDWebImageLowPriority. + */ +@property (nonatomic, assign) SDWebImageOptions options; + +@property (weak, nonatomic) id delegate; + +/** + * Return the global image prefetcher instance. + */ ++ (SDWebImagePrefetcher *)sharedImagePrefetcher; + +/** + * Assign list of URLs to let SDWebImagePrefetcher to queue the prefetching, + * currently one image is downloaded at a time, + * and skips images for failed downloads and proceed to the next image in the list + * + * @param urls list of URLs to prefetch + */ +- (void)prefetchURLs:(NSArray *)urls; + +/** + * Assign list of URLs to let SDWebImagePrefetcher to queue the prefetching, + * currently one image is downloaded at a time, + * and skips images for failed downloads and proceed to the next image in the list + * + * @param urls list of URLs to prefetch + * @param progressBlock block to be called when progress updates; + * first parameter is the number of completed (successful or not) requests, + * second parameter is the total number of images originally requested to be prefetched + * @param completionBlock block to be called when prefetching is completed + * first param is the number of completed (successful or not) requests, + * second parameter is the number of skipped requests + */ +- (void)prefetchURLs:(NSArray *)urls progress:(SDWebImagePrefetcherProgressBlock)progressBlock completed:(SDWebImagePrefetcherCompletionBlock)completionBlock; + +/** + * Remove and cancel queued list + */ +- (void)cancelPrefetching; + + +@end diff --git a/ios/Pods/SDWebImage/SDWebImage/SDWebImagePrefetcher.m b/ios/Pods/SDWebImage/SDWebImage/SDWebImagePrefetcher.m new file mode 100644 index 000000000..4087e4a94 --- /dev/null +++ b/ios/Pods/SDWebImage/SDWebImage/SDWebImagePrefetcher.m @@ -0,0 +1,138 @@ +/* + * This file is part of the SDWebImage package. + * (c) Olivier Poitrey + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +#import "SDWebImagePrefetcher.h" + +#if !defined(DEBUG) && !defined (SD_VERBOSE) +#define NSLog(...) +#endif + +@interface SDWebImagePrefetcher () + +@property (strong, nonatomic) SDWebImageManager *manager; +@property (strong, nonatomic) NSArray *prefetchURLs; +@property (assign, nonatomic) NSUInteger requestedCount; +@property (assign, nonatomic) NSUInteger skippedCount; +@property (assign, nonatomic) NSUInteger finishedCount; +@property (assign, nonatomic) NSTimeInterval startedTime; +@property (copy, nonatomic) SDWebImagePrefetcherCompletionBlock completionBlock; +@property (copy, nonatomic) SDWebImagePrefetcherProgressBlock progressBlock; + +@end + +@implementation SDWebImagePrefetcher + ++ (SDWebImagePrefetcher *)sharedImagePrefetcher { + static dispatch_once_t once; + static id instance; + dispatch_once(&once, ^{ + instance = [self new]; + }); + return instance; +} + +- (id)init { + if ((self = [super init])) { + _manager = [SDWebImageManager new]; + _options = SDWebImageLowPriority; + self.maxConcurrentDownloads = 3; + } + return self; +} + +- (void)setMaxConcurrentDownloads:(NSUInteger)maxConcurrentDownloads { + self.manager.imageDownloader.maxConcurrentDownloads = maxConcurrentDownloads; +} + +- (NSUInteger)maxConcurrentDownloads { + return self.manager.imageDownloader.maxConcurrentDownloads; +} + +- (void)startPrefetchingAtIndex:(NSUInteger)index { + if (index >= self.prefetchURLs.count) return; + self.requestedCount++; + [self.manager downloadImageWithURL:self.prefetchURLs[index] options:self.options progress:nil completed:^(UIImage *image, NSError *error, SDImageCacheType cacheType, BOOL finished, NSURL *imageURL) { + if (!finished) return; + self.finishedCount++; + + if (image) { + if (self.progressBlock) { + self.progressBlock(self.finishedCount,[self.prefetchURLs count]); + } + NSLog(@"Prefetched %@ out of %@", @(self.finishedCount), @(self.prefetchURLs.count)); + } + else { + if (self.progressBlock) { + self.progressBlock(self.finishedCount,[self.prefetchURLs count]); + } + NSLog(@"Prefetched %@ out of %@ (Failed)", @(self.finishedCount), @(self.prefetchURLs.count)); + + // Add last failed + self.skippedCount++; + } + if ([self.delegate respondsToSelector:@selector(imagePrefetcher:didPrefetchURL:finishedCount:totalCount:)]) { + [self.delegate imagePrefetcher:self + didPrefetchURL:self.prefetchURLs[index] + finishedCount:self.finishedCount + totalCount:self.prefetchURLs.count + ]; + } + + if (self.prefetchURLs.count > self.requestedCount) { + dispatch_async(dispatch_get_main_queue(), ^{ + [self startPrefetchingAtIndex:self.requestedCount]; + }); + } + else if (self.finishedCount == self.requestedCount) { + [self reportStatus]; + if (self.completionBlock) { + self.completionBlock(self.finishedCount, self.skippedCount); + self.completionBlock = nil; + } + } + }]; +} + +- (void)reportStatus { + NSUInteger total = [self.prefetchURLs count]; + NSLog(@"Finished prefetching (%@ successful, %@ skipped, timeElasped %.2f)", @(total - self.skippedCount), @(self.skippedCount), CFAbsoluteTimeGetCurrent() - self.startedTime); + if ([self.delegate respondsToSelector:@selector(imagePrefetcher:didFinishWithTotalCount:skippedCount:)]) { + [self.delegate imagePrefetcher:self + didFinishWithTotalCount:(total - self.skippedCount) + skippedCount:self.skippedCount + ]; + } +} + +- (void)prefetchURLs:(NSArray *)urls { + [self prefetchURLs:urls progress:nil completed:nil]; +} + +- (void)prefetchURLs:(NSArray *)urls progress:(SDWebImagePrefetcherProgressBlock)progressBlock completed:(SDWebImagePrefetcherCompletionBlock)completionBlock { + [self cancelPrefetching]; // Prevent duplicate prefetch request + self.startedTime = CFAbsoluteTimeGetCurrent(); + self.prefetchURLs = urls; + self.completionBlock = completionBlock; + self.progressBlock = progressBlock; + + // Starts prefetching from the very first image on the list with the max allowed concurrency + NSUInteger listCount = self.prefetchURLs.count; + for (NSUInteger i = 0; i < self.maxConcurrentDownloads && self.requestedCount < listCount; i++) { + [self startPrefetchingAtIndex:i]; + } +} + +- (void)cancelPrefetching { + self.prefetchURLs = nil; + self.skippedCount = 0; + self.requestedCount = 0; + self.finishedCount = 0; + [self.manager cancelAll]; +} + +@end diff --git a/ios/Pods/SDWebImage/SDWebImage/UIButton+WebCache.h b/ios/Pods/SDWebImage/SDWebImage/UIButton+WebCache.h new file mode 100644 index 000000000..7a6e867f4 --- /dev/null +++ b/ios/Pods/SDWebImage/SDWebImage/UIButton+WebCache.h @@ -0,0 +1,229 @@ +/* + * This file is part of the SDWebImage package. + * (c) Olivier Poitrey + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +#import "SDWebImageCompat.h" +#import "SDWebImageManager.h" + +/** + * Integrates SDWebImage async downloading and caching of remote images with UIButtonView. + */ +@interface UIButton (WebCache) + +/** + * Get the current image URL. + */ +- (NSURL *)sd_currentImageURL; + +/** + * Get the image URL for a control state. + * + * @param state Which state you want to know the URL for. The values are described in UIControlState. + */ +- (NSURL *)sd_imageURLForState:(UIControlState)state; + +/** + * Set the imageView `image` with an `url`. + * + * The download is asynchronous and cached. + * + * @param url The url for the image. + * @param state The state that uses the specified title. The values are described in UIControlState. + */ +- (void)sd_setImageWithURL:(NSURL *)url forState:(UIControlState)state; + +/** + * Set the imageView `image` with an `url` and a placeholder. + * + * The download is asynchronous and cached. + * + * @param url The url for the image. + * @param state The state that uses the specified title. The values are described in UIControlState. + * @param placeholder The image to be set initially, until the image request finishes. + * @see sd_setImageWithURL:placeholderImage:options: + */ +- (void)sd_setImageWithURL:(NSURL *)url forState:(UIControlState)state placeholderImage:(UIImage *)placeholder; + +/** + * Set the imageView `image` with an `url`, placeholder and custom options. + * + * The download is asynchronous and cached. + * + * @param url The url for the image. + * @param state The state that uses the specified title. The values are described in UIControlState. + * @param placeholder The image to be set initially, until the image request finishes. + * @param options The options to use when downloading the image. @see SDWebImageOptions for the possible values. + */ +- (void)sd_setImageWithURL:(NSURL *)url forState:(UIControlState)state placeholderImage:(UIImage *)placeholder options:(SDWebImageOptions)options; + +/** + * Set the imageView `image` with an `url`. + * + * The download is asynchronous and cached. + * + * @param url The url for the image. + * @param state The state that uses the specified title. The values are described in UIControlState. + * @param completedBlock A block called when operation has been completed. This block has no return value + * and takes the requested UIImage as first parameter. In case of error the image parameter + * is nil and the second parameter may contain an NSError. The third parameter is a Boolean + * indicating if the image was retrived from the local cache of from the network. + * The forth parameter is the original image url. + */ +- (void)sd_setImageWithURL:(NSURL *)url forState:(UIControlState)state completed:(SDWebImageCompletionBlock)completedBlock; + +/** + * Set the imageView `image` with an `url`, placeholder. + * + * The download is asynchronous and cached. + * + * @param url The url for the image. + * @param state The state that uses the specified title. The values are described in UIControlState. + * @param placeholder The image to be set initially, until the image request finishes. + * @param completedBlock A block called when operation has been completed. This block has no return value + * and takes the requested UIImage as first parameter. In case of error the image parameter + * is nil and the second parameter may contain an NSError. The third parameter is a Boolean + * indicating if the image was retrived from the local cache of from the network. + * The forth parameter is the original image url. + */ +- (void)sd_setImageWithURL:(NSURL *)url forState:(UIControlState)state placeholderImage:(UIImage *)placeholder completed:(SDWebImageCompletionBlock)completedBlock; + +/** + * Set the imageView `image` with an `url`, placeholder and custom options. + * + * The download is asynchronous and cached. + * + * @param url The url for the image. + * @param state The state that uses the specified title. The values are described in UIControlState. + * @param placeholder The image to be set initially, until the image request finishes. + * @param options The options to use when downloading the image. @see SDWebImageOptions for the possible values. + * @param completedBlock A block called when operation has been completed. This block has no return value + * and takes the requested UIImage as first parameter. In case of error the image parameter + * is nil and the second parameter may contain an NSError. The third parameter is a Boolean + * indicating if the image was retrived from the local cache of from the network. + * The forth parameter is the original image url. + */ +- (void)sd_setImageWithURL:(NSURL *)url forState:(UIControlState)state placeholderImage:(UIImage *)placeholder options:(SDWebImageOptions)options completed:(SDWebImageCompletionBlock)completedBlock; + +/** + * Set the backgroundImageView `image` with an `url`. + * + * The download is asynchronous and cached. + * + * @param url The url for the image. + * @param state The state that uses the specified title. The values are described in UIControlState. + */ +- (void)sd_setBackgroundImageWithURL:(NSURL *)url forState:(UIControlState)state; + +/** + * Set the backgroundImageView `image` with an `url` and a placeholder. + * + * The download is asynchronous and cached. + * + * @param url The url for the image. + * @param state The state that uses the specified title. The values are described in UIControlState. + * @param placeholder The image to be set initially, until the image request finishes. + * @see sd_setImageWithURL:placeholderImage:options: + */ +- (void)sd_setBackgroundImageWithURL:(NSURL *)url forState:(UIControlState)state placeholderImage:(UIImage *)placeholder; + +/** + * Set the backgroundImageView `image` with an `url`, placeholder and custom options. + * + * The download is asynchronous and cached. + * + * @param url The url for the image. + * @param state The state that uses the specified title. The values are described in UIControlState. + * @param placeholder The image to be set initially, until the image request finishes. + * @param options The options to use when downloading the image. @see SDWebImageOptions for the possible values. + */ +- (void)sd_setBackgroundImageWithURL:(NSURL *)url forState:(UIControlState)state placeholderImage:(UIImage *)placeholder options:(SDWebImageOptions)options; + +/** + * Set the backgroundImageView `image` with an `url`. + * + * The download is asynchronous and cached. + * + * @param url The url for the image. + * @param state The state that uses the specified title. The values are described in UIControlState. + * @param completedBlock A block called when operation has been completed. This block has no return value + * and takes the requested UIImage as first parameter. In case of error the image parameter + * is nil and the second parameter may contain an NSError. The third parameter is a Boolean + * indicating if the image was retrived from the local cache of from the network. + * The forth parameter is the original image url. + */ +- (void)sd_setBackgroundImageWithURL:(NSURL *)url forState:(UIControlState)state completed:(SDWebImageCompletionBlock)completedBlock; + +/** + * Set the backgroundImageView `image` with an `url`, placeholder. + * + * The download is asynchronous and cached. + * + * @param url The url for the image. + * @param state The state that uses the specified title. The values are described in UIControlState. + * @param placeholder The image to be set initially, until the image request finishes. + * @param completedBlock A block called when operation has been completed. This block has no return value + * and takes the requested UIImage as first parameter. In case of error the image parameter + * is nil and the second parameter may contain an NSError. The third parameter is a Boolean + * indicating if the image was retrived from the local cache of from the network. + * The forth parameter is the original image url. + */ +- (void)sd_setBackgroundImageWithURL:(NSURL *)url forState:(UIControlState)state placeholderImage:(UIImage *)placeholder completed:(SDWebImageCompletionBlock)completedBlock; + +/** + * Set the backgroundImageView `image` with an `url`, placeholder and custom options. + * + * The download is asynchronous and cached. + * + * @param url The url for the image. + * @param placeholder The image to be set initially, until the image request finishes. + * @param options The options to use when downloading the image. @see SDWebImageOptions for the possible values. + * @param completedBlock A block called when operation has been completed. This block has no return value + * and takes the requested UIImage as first parameter. In case of error the image parameter + * is nil and the second parameter may contain an NSError. The third parameter is a Boolean + * indicating if the image was retrived from the local cache of from the network. + * The forth parameter is the original image url. + */ +- (void)sd_setBackgroundImageWithURL:(NSURL *)url forState:(UIControlState)state placeholderImage:(UIImage *)placeholder options:(SDWebImageOptions)options completed:(SDWebImageCompletionBlock)completedBlock; + +/** + * Cancel the current image download + */ +- (void)sd_cancelImageLoadForState:(UIControlState)state; + +/** + * Cancel the current backgroundImage download + */ +- (void)sd_cancelBackgroundImageLoadForState:(UIControlState)state; + +@end + + +@interface UIButton (WebCacheDeprecated) + +- (NSURL *)currentImageURL __deprecated_msg("Use `sd_currentImageURL`"); +- (NSURL *)imageURLForState:(UIControlState)state __deprecated_msg("Use `sd_imageURLForState:`"); + +- (void)setImageWithURL:(NSURL *)url forState:(UIControlState)state __deprecated_msg("Method deprecated. Use `sd_setImageWithURL:forState:`"); +- (void)setImageWithURL:(NSURL *)url forState:(UIControlState)state placeholderImage:(UIImage *)placeholder __deprecated_msg("Method deprecated. Use `sd_setImageWithURL:forState:placeholderImage:`"); +- (void)setImageWithURL:(NSURL *)url forState:(UIControlState)state placeholderImage:(UIImage *)placeholder options:(SDWebImageOptions)options __deprecated_msg("Method deprecated. Use `sd_setImageWithURL:forState:placeholderImage:options:`"); + +- (void)setImageWithURL:(NSURL *)url forState:(UIControlState)state completed:(SDWebImageCompletedBlock)completedBlock __deprecated_msg("Method deprecated. Use `sd_setImageWithURL:forState:completed:`"); +- (void)setImageWithURL:(NSURL *)url forState:(UIControlState)state placeholderImage:(UIImage *)placeholder completed:(SDWebImageCompletedBlock)completedBlock __deprecated_msg("Method deprecated. Use `sd_setImageWithURL:forState:placeholderImage:completed:`"); +- (void)setImageWithURL:(NSURL *)url forState:(UIControlState)state placeholderImage:(UIImage *)placeholder options:(SDWebImageOptions)options completed:(SDWebImageCompletedBlock)completedBlock __deprecated_msg("Method deprecated. Use `sd_setImageWithURL:forState:placeholderImage:options:completed:`"); + +- (void)setBackgroundImageWithURL:(NSURL *)url forState:(UIControlState)state __deprecated_msg("Method deprecated. Use `sd_setBackgroundImageWithURL:forState:`"); +- (void)setBackgroundImageWithURL:(NSURL *)url forState:(UIControlState)state placeholderImage:(UIImage *)placeholder __deprecated_msg("Method deprecated. Use `sd_setBackgroundImageWithURL:forState:placeholderImage:`"); +- (void)setBackgroundImageWithURL:(NSURL *)url forState:(UIControlState)state placeholderImage:(UIImage *)placeholder options:(SDWebImageOptions)options __deprecated_msg("Method deprecated. Use `sd_setBackgroundImageWithURL:forState:placeholderImage:options:`"); + +- (void)setBackgroundImageWithURL:(NSURL *)url forState:(UIControlState)state completed:(SDWebImageCompletedBlock)completedBlock __deprecated_msg("Method deprecated. Use `sd_setBackgroundImageWithURL:forState:completed:`"); +- (void)setBackgroundImageWithURL:(NSURL *)url forState:(UIControlState)state placeholderImage:(UIImage *)placeholder completed:(SDWebImageCompletedBlock)completedBlock __deprecated_msg("Method deprecated. Use `sd_setBackgroundImageWithURL:forState:placeholderImage:completed:`"); +- (void)setBackgroundImageWithURL:(NSURL *)url forState:(UIControlState)state placeholderImage:(UIImage *)placeholder options:(SDWebImageOptions)options completed:(SDWebImageCompletedBlock)completedBlock __deprecated_msg("Method deprecated. Use `sd_setBackgroundImageWithURL:forState:placeholderImage:options:completed:`"); + +- (void)cancelCurrentImageLoad __deprecated_msg("Use `sd_cancelImageLoadForState:`"); +- (void)cancelBackgroundImageLoadForState:(UIControlState)state __deprecated_msg("Use `sd_cancelBackgroundImageLoadForState:`"); + +@end diff --git a/ios/Pods/SDWebImage/SDWebImage/UIButton+WebCache.m b/ios/Pods/SDWebImage/SDWebImage/UIButton+WebCache.m new file mode 100644 index 000000000..8e076ae56 --- /dev/null +++ b/ios/Pods/SDWebImage/SDWebImage/UIButton+WebCache.m @@ -0,0 +1,260 @@ +/* + * This file is part of the SDWebImage package. + * (c) Olivier Poitrey + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +#import "UIButton+WebCache.h" +#import "objc/runtime.h" +#import "UIView+WebCacheOperation.h" + +static char imageURLStorageKey; + +@implementation UIButton (WebCache) + +- (NSURL *)sd_currentImageURL { + NSURL *url = self.imageURLStorage[@(self.state)]; + + if (!url) { + url = self.imageURLStorage[@(UIControlStateNormal)]; + } + + return url; +} + +- (NSURL *)sd_imageURLForState:(UIControlState)state { + return self.imageURLStorage[@(state)]; +} + +- (void)sd_setImageWithURL:(NSURL *)url forState:(UIControlState)state { + [self sd_setImageWithURL:url forState:state placeholderImage:nil options:0 completed:nil]; +} + +- (void)sd_setImageWithURL:(NSURL *)url forState:(UIControlState)state placeholderImage:(UIImage *)placeholder { + [self sd_setImageWithURL:url forState:state placeholderImage:placeholder options:0 completed:nil]; +} + +- (void)sd_setImageWithURL:(NSURL *)url forState:(UIControlState)state placeholderImage:(UIImage *)placeholder options:(SDWebImageOptions)options { + [self sd_setImageWithURL:url forState:state placeholderImage:placeholder options:options completed:nil]; +} + +- (void)sd_setImageWithURL:(NSURL *)url forState:(UIControlState)state completed:(SDWebImageCompletionBlock)completedBlock { + [self sd_setImageWithURL:url forState:state placeholderImage:nil options:0 completed:completedBlock]; +} + +- (void)sd_setImageWithURL:(NSURL *)url forState:(UIControlState)state placeholderImage:(UIImage *)placeholder completed:(SDWebImageCompletionBlock)completedBlock { + [self sd_setImageWithURL:url forState:state placeholderImage:placeholder options:0 completed:completedBlock]; +} + +- (void)sd_setImageWithURL:(NSURL *)url forState:(UIControlState)state placeholderImage:(UIImage *)placeholder options:(SDWebImageOptions)options completed:(SDWebImageCompletionBlock)completedBlock { + + [self setImage:placeholder forState:state]; + [self sd_cancelImageLoadForState:state]; + + if (!url) { + [self.imageURLStorage removeObjectForKey:@(state)]; + + dispatch_main_async_safe(^{ + NSError *error = [NSError errorWithDomain:@"SDWebImageErrorDomain" code:-1 userInfo:@{NSLocalizedDescriptionKey : @"Trying to load a nil url"}]; + if (completedBlock) { + completedBlock(nil, error, SDImageCacheTypeNone, url); + } + }); + + return; + } + + self.imageURLStorage[@(state)] = url; + + __weak UIButton *wself = self; + id operation = [SDWebImageManager.sharedManager downloadImageWithURL:url options:options progress:nil completed:^(UIImage *image, NSError *error, SDImageCacheType cacheType, BOOL finished, NSURL *imageURL) { + if (!wself) return; + dispatch_main_sync_safe(^{ + __strong UIButton *sself = wself; + if (!sself) return; + if (image) { + [sself setImage:image forState:state]; + } + if (completedBlock && finished) { + completedBlock(image, error, cacheType, url); + } + }); + }]; + [self sd_setImageLoadOperation:operation forState:state]; +} + +- (void)sd_setBackgroundImageWithURL:(NSURL *)url forState:(UIControlState)state { + [self sd_setBackgroundImageWithURL:url forState:state placeholderImage:nil options:0 completed:nil]; +} + +- (void)sd_setBackgroundImageWithURL:(NSURL *)url forState:(UIControlState)state placeholderImage:(UIImage *)placeholder { + [self sd_setBackgroundImageWithURL:url forState:state placeholderImage:placeholder options:0 completed:nil]; +} + +- (void)sd_setBackgroundImageWithURL:(NSURL *)url forState:(UIControlState)state placeholderImage:(UIImage *)placeholder options:(SDWebImageOptions)options { + [self sd_setBackgroundImageWithURL:url forState:state placeholderImage:placeholder options:options completed:nil]; +} + +- (void)sd_setBackgroundImageWithURL:(NSURL *)url forState:(UIControlState)state completed:(SDWebImageCompletionBlock)completedBlock { + [self sd_setBackgroundImageWithURL:url forState:state placeholderImage:nil options:0 completed:completedBlock]; +} + +- (void)sd_setBackgroundImageWithURL:(NSURL *)url forState:(UIControlState)state placeholderImage:(UIImage *)placeholder completed:(SDWebImageCompletionBlock)completedBlock { + [self sd_setBackgroundImageWithURL:url forState:state placeholderImage:placeholder options:0 completed:completedBlock]; +} + +- (void)sd_setBackgroundImageWithURL:(NSURL *)url forState:(UIControlState)state placeholderImage:(UIImage *)placeholder options:(SDWebImageOptions)options completed:(SDWebImageCompletionBlock)completedBlock { + [self sd_cancelImageLoadForState:state]; + + [self setBackgroundImage:placeholder forState:state]; + + if (url) { + __weak UIButton *wself = self; + id operation = [SDWebImageManager.sharedManager downloadImageWithURL:url options:options progress:nil completed:^(UIImage *image, NSError *error, SDImageCacheType cacheType, BOOL finished, NSURL *imageURL) { + if (!wself) return; + dispatch_main_sync_safe(^{ + __strong UIButton *sself = wself; + if (!sself) return; + if (image) { + [sself setBackgroundImage:image forState:state]; + } + if (completedBlock && finished) { + completedBlock(image, error, cacheType, url); + } + }); + }]; + [self sd_setBackgroundImageLoadOperation:operation forState:state]; + } else { + dispatch_main_async_safe(^{ + NSError *error = [NSError errorWithDomain:@"SDWebImageErrorDomain" code:-1 userInfo:@{NSLocalizedDescriptionKey : @"Trying to load a nil url"}]; + if (completedBlock) { + completedBlock(nil, error, SDImageCacheTypeNone, url); + } + }); + } +} + +- (void)sd_setImageLoadOperation:(id)operation forState:(UIControlState)state { + [self sd_setImageLoadOperation:operation forKey:[NSString stringWithFormat:@"UIButtonImageOperation%@", @(state)]]; +} + +- (void)sd_cancelImageLoadForState:(UIControlState)state { + [self sd_cancelImageLoadOperationWithKey:[NSString stringWithFormat:@"UIButtonImageOperation%@", @(state)]]; +} + +- (void)sd_setBackgroundImageLoadOperation:(id)operation forState:(UIControlState)state { + [self sd_setImageLoadOperation:operation forKey:[NSString stringWithFormat:@"UIButtonBackgroundImageOperation%@", @(state)]]; +} + +- (void)sd_cancelBackgroundImageLoadForState:(UIControlState)state { + [self sd_cancelImageLoadOperationWithKey:[NSString stringWithFormat:@"UIButtonBackgroundImageOperation%@", @(state)]]; +} + +- (NSMutableDictionary *)imageURLStorage { + NSMutableDictionary *storage = objc_getAssociatedObject(self, &imageURLStorageKey); + if (!storage) + { + storage = [NSMutableDictionary dictionary]; + objc_setAssociatedObject(self, &imageURLStorageKey, storage, OBJC_ASSOCIATION_RETAIN_NONATOMIC); + } + + return storage; +} + +@end + + +@implementation UIButton (WebCacheDeprecated) + +- (NSURL *)currentImageURL { + return [self sd_currentImageURL]; +} + +- (NSURL *)imageURLForState:(UIControlState)state { + return [self sd_imageURLForState:state]; +} + +- (void)setImageWithURL:(NSURL *)url forState:(UIControlState)state { + [self sd_setImageWithURL:url forState:state placeholderImage:nil options:0 completed:nil]; +} + +- (void)setImageWithURL:(NSURL *)url forState:(UIControlState)state placeholderImage:(UIImage *)placeholder { + [self sd_setImageWithURL:url forState:state placeholderImage:placeholder options:0 completed:nil]; +} + +- (void)setImageWithURL:(NSURL *)url forState:(UIControlState)state placeholderImage:(UIImage *)placeholder options:(SDWebImageOptions)options { + [self sd_setImageWithURL:url forState:state placeholderImage:placeholder options:options completed:nil]; +} + +- (void)setImageWithURL:(NSURL *)url forState:(UIControlState)state completed:(SDWebImageCompletedBlock)completedBlock { + [self sd_setImageWithURL:url forState:state placeholderImage:nil options:0 completed:^(UIImage *image, NSError *error, SDImageCacheType cacheType, NSURL *imageURL) { + if (completedBlock) { + completedBlock(image, error, cacheType); + } + }]; +} + +- (void)setImageWithURL:(NSURL *)url forState:(UIControlState)state placeholderImage:(UIImage *)placeholder completed:(SDWebImageCompletedBlock)completedBlock { + [self sd_setImageWithURL:url forState:state placeholderImage:placeholder options:0 completed:^(UIImage *image, NSError *error, SDImageCacheType cacheType, NSURL *imageURL) { + if (completedBlock) { + completedBlock(image, error, cacheType); + } + }]; +} + +- (void)setImageWithURL:(NSURL *)url forState:(UIControlState)state placeholderImage:(UIImage *)placeholder options:(SDWebImageOptions)options completed:(SDWebImageCompletedBlock)completedBlock { + [self sd_setImageWithURL:url forState:state placeholderImage:placeholder options:options completed:^(UIImage *image, NSError *error, SDImageCacheType cacheType, NSURL *imageURL) { + if (completedBlock) { + completedBlock(image, error, cacheType); + } + }]; +} + +- (void)setBackgroundImageWithURL:(NSURL *)url forState:(UIControlState)state { + [self sd_setBackgroundImageWithURL:url forState:state placeholderImage:nil options:0 completed:nil]; +} + +- (void)setBackgroundImageWithURL:(NSURL *)url forState:(UIControlState)state placeholderImage:(UIImage *)placeholder { + [self sd_setBackgroundImageWithURL:url forState:state placeholderImage:placeholder options:0 completed:nil]; +} + +- (void)setBackgroundImageWithURL:(NSURL *)url forState:(UIControlState)state placeholderImage:(UIImage *)placeholder options:(SDWebImageOptions)options { + [self sd_setBackgroundImageWithURL:url forState:state placeholderImage:placeholder options:options completed:nil]; +} + +- (void)setBackgroundImageWithURL:(NSURL *)url forState:(UIControlState)state completed:(SDWebImageCompletedBlock)completedBlock { + [self sd_setBackgroundImageWithURL:url forState:state placeholderImage:nil options:0 completed:^(UIImage *image, NSError *error, SDImageCacheType cacheType, NSURL *imageURL) { + if (completedBlock) { + completedBlock(image, error, cacheType); + } + }]; +} + +- (void)setBackgroundImageWithURL:(NSURL *)url forState:(UIControlState)state placeholderImage:(UIImage *)placeholder completed:(SDWebImageCompletedBlock)completedBlock { + [self sd_setBackgroundImageWithURL:url forState:state placeholderImage:placeholder options:0 completed:^(UIImage *image, NSError *error, SDImageCacheType cacheType, NSURL *imageURL) { + if (completedBlock) { + completedBlock(image, error, cacheType); + } + }]; +} + +- (void)setBackgroundImageWithURL:(NSURL *)url forState:(UIControlState)state placeholderImage:(UIImage *)placeholder options:(SDWebImageOptions)options completed:(SDWebImageCompletedBlock)completedBlock { + [self sd_setBackgroundImageWithURL:url forState:state placeholderImage:placeholder options:options completed:^(UIImage *image, NSError *error, SDImageCacheType cacheType, NSURL *imageURL) { + if (completedBlock) { + completedBlock(image, error, cacheType); + } + }]; +} + +- (void)cancelCurrentImageLoad { + // in a backwards compatible manner, cancel for current state + [self sd_cancelImageLoadForState:self.state]; +} + +- (void)cancelBackgroundImageLoadForState:(UIControlState)state { + [self sd_cancelBackgroundImageLoadForState:state]; +} + +@end diff --git a/ios/Pods/SDWebImage/SDWebImage/UIImage+GIF.h b/ios/Pods/SDWebImage/SDWebImage/UIImage+GIF.h new file mode 100755 index 000000000..084f42415 --- /dev/null +++ b/ios/Pods/SDWebImage/SDWebImage/UIImage+GIF.h @@ -0,0 +1,19 @@ +// +// UIImage+GIF.h +// LBGIFImage +// +// Created by Laurin Brandner on 06.01.12. +// Copyright (c) 2012 __MyCompanyName__. All rights reserved. +// + +#import + +@interface UIImage (GIF) + ++ (UIImage *)sd_animatedGIFNamed:(NSString *)name; + ++ (UIImage *)sd_animatedGIFWithData:(NSData *)data; + +- (UIImage *)sd_animatedImageByScalingAndCroppingToSize:(CGSize)size; + +@end diff --git a/ios/Pods/SDWebImage/SDWebImage/UIImage+GIF.m b/ios/Pods/SDWebImage/SDWebImage/UIImage+GIF.m new file mode 100755 index 000000000..a7036372a --- /dev/null +++ b/ios/Pods/SDWebImage/SDWebImage/UIImage+GIF.m @@ -0,0 +1,158 @@ +// +// UIImage+GIF.m +// LBGIFImage +// +// Created by Laurin Brandner on 06.01.12. +// Copyright (c) 2012 __MyCompanyName__. All rights reserved. +// + +#import "UIImage+GIF.h" +#import + +@implementation UIImage (GIF) + ++ (UIImage *)sd_animatedGIFWithData:(NSData *)data { + if (!data) { + return nil; + } + + CGImageSourceRef source = CGImageSourceCreateWithData((__bridge CFDataRef)data, NULL); + + size_t count = CGImageSourceGetCount(source); + + UIImage *animatedImage; + + if (count <= 1) { + animatedImage = [[UIImage alloc] initWithData:data]; + } + else { + NSMutableArray *images = [NSMutableArray array]; + + NSTimeInterval duration = 0.0f; + + for (size_t i = 0; i < count; i++) { + CGImageRef image = CGImageSourceCreateImageAtIndex(source, i, NULL); + + duration += [self sd_frameDurationAtIndex:i source:source]; + + [images addObject:[UIImage imageWithCGImage:image scale:[UIScreen mainScreen].scale orientation:UIImageOrientationUp]]; + + CGImageRelease(image); + } + + if (!duration) { + duration = (1.0f / 10.0f) * count; + } + + animatedImage = [UIImage animatedImageWithImages:images duration:duration]; + } + + CFRelease(source); + + return animatedImage; +} + ++ (float)sd_frameDurationAtIndex:(NSUInteger)index source:(CGImageSourceRef)source { + float frameDuration = 0.1f; + CFDictionaryRef cfFrameProperties = CGImageSourceCopyPropertiesAtIndex(source, index, nil); + NSDictionary *frameProperties = (__bridge NSDictionary *)cfFrameProperties; + NSDictionary *gifProperties = frameProperties[(NSString *)kCGImagePropertyGIFDictionary]; + + NSNumber *delayTimeUnclampedProp = gifProperties[(NSString *)kCGImagePropertyGIFUnclampedDelayTime]; + if (delayTimeUnclampedProp) { + frameDuration = [delayTimeUnclampedProp floatValue]; + } + else { + + NSNumber *delayTimeProp = gifProperties[(NSString *)kCGImagePropertyGIFDelayTime]; + if (delayTimeProp) { + frameDuration = [delayTimeProp floatValue]; + } + } + + // Many annoying ads specify a 0 duration to make an image flash as quickly as possible. + // We follow Firefox's behavior and use a duration of 100 ms for any frames that specify + // a duration of <= 10 ms. See and + // for more information. + + if (frameDuration < 0.011f) { + frameDuration = 0.100f; + } + + CFRelease(cfFrameProperties); + return frameDuration; +} + ++ (UIImage *)sd_animatedGIFNamed:(NSString *)name { + CGFloat scale = [UIScreen mainScreen].scale; + + if (scale > 1.0f) { + NSString *retinaPath = [[NSBundle mainBundle] pathForResource:[name stringByAppendingString:@"@2x"] ofType:@"gif"]; + + NSData *data = [NSData dataWithContentsOfFile:retinaPath]; + + if (data) { + return [UIImage sd_animatedGIFWithData:data]; + } + + NSString *path = [[NSBundle mainBundle] pathForResource:name ofType:@"gif"]; + + data = [NSData dataWithContentsOfFile:path]; + + if (data) { + return [UIImage sd_animatedGIFWithData:data]; + } + + return [UIImage imageNamed:name]; + } + else { + NSString *path = [[NSBundle mainBundle] pathForResource:name ofType:@"gif"]; + + NSData *data = [NSData dataWithContentsOfFile:path]; + + if (data) { + return [UIImage sd_animatedGIFWithData:data]; + } + + return [UIImage imageNamed:name]; + } +} + +- (UIImage *)sd_animatedImageByScalingAndCroppingToSize:(CGSize)size { + if (CGSizeEqualToSize(self.size, size) || CGSizeEqualToSize(size, CGSizeZero)) { + return self; + } + + CGSize scaledSize = size; + CGPoint thumbnailPoint = CGPointZero; + + CGFloat widthFactor = size.width / self.size.width; + CGFloat heightFactor = size.height / self.size.height; + CGFloat scaleFactor = (widthFactor > heightFactor) ? widthFactor : heightFactor; + scaledSize.width = self.size.width * scaleFactor; + scaledSize.height = self.size.height * scaleFactor; + + if (widthFactor > heightFactor) { + thumbnailPoint.y = (size.height - scaledSize.height) * 0.5; + } + else if (widthFactor < heightFactor) { + thumbnailPoint.x = (size.width - scaledSize.width) * 0.5; + } + + NSMutableArray *scaledImages = [NSMutableArray array]; + + UIGraphicsBeginImageContextWithOptions(size, NO, 0.0); + + for (UIImage *image in self.images) { + [image drawInRect:CGRectMake(thumbnailPoint.x, thumbnailPoint.y, scaledSize.width, scaledSize.height)]; + UIImage *newImage = UIGraphicsGetImageFromCurrentImageContext(); + + [scaledImages addObject:newImage]; + } + + UIGraphicsEndImageContext(); + + return [UIImage animatedImageWithImages:scaledImages duration:self.duration]; +} + +@end diff --git a/ios/Pods/SDWebImage/SDWebImage/UIImage+MultiFormat.h b/ios/Pods/SDWebImage/SDWebImage/UIImage+MultiFormat.h new file mode 100644 index 000000000..186ebc0a5 --- /dev/null +++ b/ios/Pods/SDWebImage/SDWebImage/UIImage+MultiFormat.h @@ -0,0 +1,15 @@ +// +// UIImage+MultiFormat.h +// SDWebImage +// +// Created by Olivier Poitrey on 07/06/13. +// Copyright (c) 2013 Dailymotion. All rights reserved. +// + +#import + +@interface UIImage (MultiFormat) + ++ (UIImage *)sd_imageWithData:(NSData *)data; + +@end diff --git a/ios/Pods/SDWebImage/SDWebImage/UIImage+MultiFormat.m b/ios/Pods/SDWebImage/SDWebImage/UIImage+MultiFormat.m new file mode 100644 index 000000000..5395280d2 --- /dev/null +++ b/ios/Pods/SDWebImage/SDWebImage/UIImage+MultiFormat.m @@ -0,0 +1,114 @@ +// +// UIImage+MultiFormat.m +// SDWebImage +// +// Created by Olivier Poitrey on 07/06/13. +// Copyright (c) 2013 Dailymotion. All rights reserved. +// + +#import "UIImage+MultiFormat.h" +#import "UIImage+GIF.h" +#import "NSData+ImageContentType.h" +#import + +#ifdef SD_WEBP +#import "UIImage+WebP.h" +#endif + +@implementation UIImage (MultiFormat) + ++ (UIImage *)sd_imageWithData:(NSData *)data { + UIImage *image; + NSString *imageContentType = [NSData sd_contentTypeForImageData:data]; + if ([imageContentType isEqualToString:@"image/gif"]) { + image = [UIImage sd_animatedGIFWithData:data]; + } +#ifdef SD_WEBP + else if ([imageContentType isEqualToString:@"image/webp"]) + { + image = [UIImage sd_imageWithWebPData:data]; + } +#endif + else { + image = [[UIImage alloc] initWithData:data]; + UIImageOrientation orientation = [self sd_imageOrientationFromImageData:data]; + if (orientation != UIImageOrientationUp) { + image = [UIImage imageWithCGImage:image.CGImage + scale:image.scale + orientation:orientation]; + } + } + + + return image; +} + + ++(UIImageOrientation)sd_imageOrientationFromImageData:(NSData *)imageData { + UIImageOrientation result = UIImageOrientationUp; + CGImageSourceRef imageSource = CGImageSourceCreateWithData((__bridge CFDataRef)imageData, NULL); + if (imageSource) { + CFDictionaryRef properties = CGImageSourceCopyPropertiesAtIndex(imageSource, 0, NULL); + if (properties) { + CFTypeRef val; + int exifOrientation; + val = CFDictionaryGetValue(properties, kCGImagePropertyOrientation); + if (val) { + CFNumberGetValue(val, kCFNumberIntType, &exifOrientation); + result = [self sd_exifOrientationToiOSOrientation:exifOrientation]; + } // else - if it's not set it remains at up + CFRelease((CFTypeRef) properties); + } else { + //NSLog(@"NO PROPERTIES, FAIL"); + } + CFRelease(imageSource); + } + return result; +} + +#pragma mark EXIF orientation tag converter +// Convert an EXIF image orientation to an iOS one. +// reference see here: http://sylvana.net/jpegcrop/exif_orientation.html ++ (UIImageOrientation) sd_exifOrientationToiOSOrientation:(int)exifOrientation { + UIImageOrientation orientation = UIImageOrientationUp; + switch (exifOrientation) { + case 1: + orientation = UIImageOrientationUp; + break; + + case 3: + orientation = UIImageOrientationDown; + break; + + case 8: + orientation = UIImageOrientationLeft; + break; + + case 6: + orientation = UIImageOrientationRight; + break; + + case 2: + orientation = UIImageOrientationUpMirrored; + break; + + case 4: + orientation = UIImageOrientationDownMirrored; + break; + + case 5: + orientation = UIImageOrientationLeftMirrored; + break; + + case 7: + orientation = UIImageOrientationRightMirrored; + break; + default: + break; + } + return orientation; +} + + + +@end diff --git a/ios/Pods/SDWebImage/SDWebImage/UIImageView+HighlightedWebCache.h b/ios/Pods/SDWebImage/SDWebImage/UIImageView+HighlightedWebCache.h new file mode 100644 index 000000000..6b0036635 --- /dev/null +++ b/ios/Pods/SDWebImage/SDWebImage/UIImageView+HighlightedWebCache.h @@ -0,0 +1,100 @@ +/* + * This file is part of the SDWebImage package. + * (c) Olivier Poitrey + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +#import +#import "SDWebImageCompat.h" +#import "SDWebImageManager.h" + +/** + * Integrates SDWebImage async downloading and caching of remote images with UIImageView for highlighted state. + */ +@interface UIImageView (HighlightedWebCache) + +/** + * Set the imageView `highlightedImage` with an `url`. + * + * The download is asynchronous and cached. + * + * @param url The url for the image. + */ +- (void)sd_setHighlightedImageWithURL:(NSURL *)url; + +/** + * Set the imageView `highlightedImage` with an `url` and custom options. + * + * The download is asynchronous and cached. + * + * @param url The url for the image. + * @param options The options to use when downloading the image. @see SDWebImageOptions for the possible values. + */ +- (void)sd_setHighlightedImageWithURL:(NSURL *)url options:(SDWebImageOptions)options; + +/** + * Set the imageView `highlightedImage` with an `url`. + * + * The download is asynchronous and cached. + * + * @param url The url for the image. + * @param completedBlock A block called when operation has been completed. This block has no return value + * and takes the requested UIImage as first parameter. In case of error the image parameter + * is nil and the second parameter may contain an NSError. The third parameter is a Boolean + * indicating if the image was retrived from the local cache of from the network. + * The forth parameter is the original image url. + */ +- (void)sd_setHighlightedImageWithURL:(NSURL *)url completed:(SDWebImageCompletionBlock)completedBlock; + +/** + * Set the imageView `highlightedImage` with an `url` and custom options. + * + * The download is asynchronous and cached. + * + * @param url The url for the image. + * @param options The options to use when downloading the image. @see SDWebImageOptions for the possible values. + * @param completedBlock A block called when operation has been completed. This block has no return value + * and takes the requested UIImage as first parameter. In case of error the image parameter + * is nil and the second parameter may contain an NSError. The third parameter is a Boolean + * indicating if the image was retrived from the local cache of from the network. + * The forth parameter is the original image url. + */ +- (void)sd_setHighlightedImageWithURL:(NSURL *)url options:(SDWebImageOptions)options completed:(SDWebImageCompletionBlock)completedBlock; + +/** + * Set the imageView `highlightedImage` with an `url` and custom options. + * + * The download is asynchronous and cached. + * + * @param url The url for the image. + * @param options The options to use when downloading the image. @see SDWebImageOptions for the possible values. + * @param progressBlock A block called while image is downloading + * @param completedBlock A block called when operation has been completed. This block has no return value + * and takes the requested UIImage as first parameter. In case of error the image parameter + * is nil and the second parameter may contain an NSError. The third parameter is a Boolean + * indicating if the image was retrived from the local cache of from the network. + * The forth parameter is the original image url. + */ +- (void)sd_setHighlightedImageWithURL:(NSURL *)url options:(SDWebImageOptions)options progress:(SDWebImageDownloaderProgressBlock)progressBlock completed:(SDWebImageCompletionBlock)completedBlock; + +/** + * Cancel the current download + */ +- (void)sd_cancelCurrentHighlightedImageLoad; + +@end + + +@interface UIImageView (HighlightedWebCacheDeprecated) + +- (void)setHighlightedImageWithURL:(NSURL *)url __deprecated_msg("Method deprecated. Use `sd_setHighlightedImageWithURL:`"); +- (void)setHighlightedImageWithURL:(NSURL *)url options:(SDWebImageOptions)options __deprecated_msg("Method deprecated. Use `sd_setHighlightedImageWithURL:options:`"); +- (void)setHighlightedImageWithURL:(NSURL *)url completed:(SDWebImageCompletedBlock)completedBlock __deprecated_msg("Method deprecated. Use `sd_setHighlightedImageWithURL:completed:`"); +- (void)setHighlightedImageWithURL:(NSURL *)url options:(SDWebImageOptions)options completed:(SDWebImageCompletedBlock)completedBlock __deprecated_msg("Method deprecated. Use `sd_setHighlightedImageWithURL:options:completed:`"); +- (void)setHighlightedImageWithURL:(NSURL *)url options:(SDWebImageOptions)options progress:(SDWebImageDownloaderProgressBlock)progressBlock completed:(SDWebImageCompletedBlock)completedBlock __deprecated_msg("Method deprecated. Use `sd_setHighlightedImageWithURL:options:progress:completed:`"); + +- (void)cancelCurrentHighlightedImageLoad __deprecated_msg("Use `sd_cancelCurrentHighlightedImageLoad`"); + +@end diff --git a/ios/Pods/SDWebImage/SDWebImage/UIImageView+HighlightedWebCache.m b/ios/Pods/SDWebImage/SDWebImage/UIImageView+HighlightedWebCache.m new file mode 100644 index 000000000..ae73610fa --- /dev/null +++ b/ios/Pods/SDWebImage/SDWebImage/UIImageView+HighlightedWebCache.m @@ -0,0 +1,107 @@ +/* + * This file is part of the SDWebImage package. + * (c) Olivier Poitrey + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +#import "UIImageView+HighlightedWebCache.h" +#import "UIView+WebCacheOperation.h" + +#define UIImageViewHighlightedWebCacheOperationKey @"highlightedImage" + +@implementation UIImageView (HighlightedWebCache) + +- (void)sd_setHighlightedImageWithURL:(NSURL *)url { + [self sd_setHighlightedImageWithURL:url options:0 progress:nil completed:nil]; +} + +- (void)sd_setHighlightedImageWithURL:(NSURL *)url options:(SDWebImageOptions)options { + [self sd_setHighlightedImageWithURL:url options:options progress:nil completed:nil]; +} + +- (void)sd_setHighlightedImageWithURL:(NSURL *)url completed:(SDWebImageCompletionBlock)completedBlock { + [self sd_setHighlightedImageWithURL:url options:0 progress:nil completed:completedBlock]; +} + +- (void)sd_setHighlightedImageWithURL:(NSURL *)url options:(SDWebImageOptions)options completed:(SDWebImageCompletionBlock)completedBlock { + [self sd_setHighlightedImageWithURL:url options:options progress:nil completed:completedBlock]; +} + +- (void)sd_setHighlightedImageWithURL:(NSURL *)url options:(SDWebImageOptions)options progress:(SDWebImageDownloaderProgressBlock)progressBlock completed:(SDWebImageCompletionBlock)completedBlock { + [self sd_cancelCurrentHighlightedImageLoad]; + + if (url) { + __weak UIImageView *wself = self; + id operation = [SDWebImageManager.sharedManager downloadImageWithURL:url options:options progress:progressBlock completed:^(UIImage *image, NSError *error, SDImageCacheType cacheType, BOOL finished, NSURL *imageURL) { + if (!wself) return; + dispatch_main_sync_safe (^ + { + if (!wself) return; + if (image) { + wself.highlightedImage = image; + [wself setNeedsLayout]; + } + if (completedBlock && finished) { + completedBlock(image, error, cacheType, url); + } + }); + }]; + [self sd_setImageLoadOperation:operation forKey:UIImageViewHighlightedWebCacheOperationKey]; + } else { + dispatch_main_async_safe(^{ + NSError *error = [NSError errorWithDomain:@"SDWebImageErrorDomain" code:-1 userInfo:@{NSLocalizedDescriptionKey : @"Trying to load a nil url"}]; + if (completedBlock) { + completedBlock(nil, error, SDImageCacheTypeNone, url); + } + }); + } +} + +- (void)sd_cancelCurrentHighlightedImageLoad { + [self sd_cancelImageLoadOperationWithKey:UIImageViewHighlightedWebCacheOperationKey]; +} + +@end + + +@implementation UIImageView (HighlightedWebCacheDeprecated) + +- (void)setHighlightedImageWithURL:(NSURL *)url { + [self sd_setHighlightedImageWithURL:url options:0 progress:nil completed:nil]; +} + +- (void)setHighlightedImageWithURL:(NSURL *)url options:(SDWebImageOptions)options { + [self sd_setHighlightedImageWithURL:url options:options progress:nil completed:nil]; +} + +- (void)setHighlightedImageWithURL:(NSURL *)url completed:(SDWebImageCompletedBlock)completedBlock { + [self sd_setHighlightedImageWithURL:url options:0 progress:nil completed:^(UIImage *image, NSError *error, SDImageCacheType cacheType, NSURL *imageURL) { + if (completedBlock) { + completedBlock(image, error, cacheType); + } + }]; +} + +- (void)setHighlightedImageWithURL:(NSURL *)url options:(SDWebImageOptions)options completed:(SDWebImageCompletedBlock)completedBlock { + [self sd_setHighlightedImageWithURL:url options:options progress:nil completed:^(UIImage *image, NSError *error, SDImageCacheType cacheType, NSURL *imageURL) { + if (completedBlock) { + completedBlock(image, error, cacheType); + } + }]; +} + +- (void)setHighlightedImageWithURL:(NSURL *)url options:(SDWebImageOptions)options progress:(SDWebImageDownloaderProgressBlock)progressBlock completed:(SDWebImageCompletedBlock)completedBlock { + [self sd_setHighlightedImageWithURL:url options:0 progress:progressBlock completed:^(UIImage *image, NSError *error, SDImageCacheType cacheType, NSURL *imageURL) { + if (completedBlock) { + completedBlock(image, error, cacheType); + } + }]; +} + +- (void)cancelCurrentHighlightedImageLoad { + [self sd_cancelCurrentHighlightedImageLoad]; +} + +@end diff --git a/ios/Pods/SDWebImage/SDWebImage/UIImageView+WebCache.h b/ios/Pods/SDWebImage/SDWebImage/UIImageView+WebCache.h new file mode 100644 index 000000000..717d39388 --- /dev/null +++ b/ios/Pods/SDWebImage/SDWebImage/UIImageView+WebCache.h @@ -0,0 +1,201 @@ +/* + * This file is part of the SDWebImage package. + * (c) Olivier Poitrey + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +#import "SDWebImageCompat.h" +#import "SDWebImageManager.h" + +/** + * Integrates SDWebImage async downloading and caching of remote images with UIImageView. + * + * Usage with a UITableViewCell sub-class: + * + * @code + +#import + +... + +- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath +{ + static NSString *MyIdentifier = @"MyIdentifier"; + + UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:MyIdentifier]; + + if (cell == nil) { + cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:MyIdentifier] + autorelease]; + } + + // Here we use the provided sd_setImageWithURL: method to load the web image + // Ensure you use a placeholder image otherwise cells will be initialized with no image + [cell.imageView sd_setImageWithURL:[NSURL URLWithString:@"http://example.com/image.jpg"] + placeholderImage:[UIImage imageNamed:@"placeholder"]]; + + cell.textLabel.text = @"My Text"; + return cell; +} + + * @endcode + */ +@interface UIImageView (WebCache) + +/** + * Get the current image URL. + * + * Note that because of the limitations of categories this property can get out of sync + * if you use sd_setImage: directly. + */ +- (NSURL *)sd_imageURL; + +/** + * Set the imageView `image` with an `url`. + * + * The download is asynchronous and cached. + * + * @param url The url for the image. + */ +- (void)sd_setImageWithURL:(NSURL *)url; + +/** + * Set the imageView `image` with an `url` and a placeholder. + * + * The download is asynchronous and cached. + * + * @param url The url for the image. + * @param placeholder The image to be set initially, until the image request finishes. + * @see sd_setImageWithURL:placeholderImage:options: + */ +- (void)sd_setImageWithURL:(NSURL *)url placeholderImage:(UIImage *)placeholder; + +/** + * Set the imageView `image` with an `url`, placeholder and custom options. + * + * The download is asynchronous and cached. + * + * @param url The url for the image. + * @param placeholder The image to be set initially, until the image request finishes. + * @param options The options to use when downloading the image. @see SDWebImageOptions for the possible values. + */ +- (void)sd_setImageWithURL:(NSURL *)url placeholderImage:(UIImage *)placeholder options:(SDWebImageOptions)options; + +/** + * Set the imageView `image` with an `url`. + * + * The download is asynchronous and cached. + * + * @param url The url for the image. + * @param completedBlock A block called when operation has been completed. This block has no return value + * and takes the requested UIImage as first parameter. In case of error the image parameter + * is nil and the second parameter may contain an NSError. The third parameter is a Boolean + * indicating if the image was retrived from the local cache of from the network. + * The forth parameter is the original image url. + */ +- (void)sd_setImageWithURL:(NSURL *)url completed:(SDWebImageCompletionBlock)completedBlock; + +/** + * Set the imageView `image` with an `url`, placeholder. + * + * The download is asynchronous and cached. + * + * @param url The url for the image. + * @param placeholder The image to be set initially, until the image request finishes. + * @param completedBlock A block called when operation has been completed. This block has no return value + * and takes the requested UIImage as first parameter. In case of error the image parameter + * is nil and the second parameter may contain an NSError. The third parameter is a Boolean + * indicating if the image was retrived from the local cache of from the network. + * The forth parameter is the original image url. + */ +- (void)sd_setImageWithURL:(NSURL *)url placeholderImage:(UIImage *)placeholder completed:(SDWebImageCompletionBlock)completedBlock; + +/** + * Set the imageView `image` with an `url`, placeholder and custom options. + * + * The download is asynchronous and cached. + * + * @param url The url for the image. + * @param placeholder The image to be set initially, until the image request finishes. + * @param options The options to use when downloading the image. @see SDWebImageOptions for the possible values. + * @param completedBlock A block called when operation has been completed. This block has no return value + * and takes the requested UIImage as first parameter. In case of error the image parameter + * is nil and the second parameter may contain an NSError. The third parameter is a Boolean + * indicating if the image was retrived from the local cache of from the network. + * The forth parameter is the original image url. + */ +- (void)sd_setImageWithURL:(NSURL *)url placeholderImage:(UIImage *)placeholder options:(SDWebImageOptions)options completed:(SDWebImageCompletionBlock)completedBlock; + +/** + * Set the imageView `image` with an `url`, placeholder and custom options. + * + * The download is asynchronous and cached. + * + * @param url The url for the image. + * @param placeholder The image to be set initially, until the image request finishes. + * @param options The options to use when downloading the image. @see SDWebImageOptions for the possible values. + * @param progressBlock A block called while image is downloading + * @param completedBlock A block called when operation has been completed. This block has no return value + * and takes the requested UIImage as first parameter. In case of error the image parameter + * is nil and the second parameter may contain an NSError. The third parameter is a Boolean + * indicating if the image was retrived from the local cache of from the network. + * The forth parameter is the original image url. + */ +- (void)sd_setImageWithURL:(NSURL *)url placeholderImage:(UIImage *)placeholder options:(SDWebImageOptions)options progress:(SDWebImageDownloaderProgressBlock)progressBlock completed:(SDWebImageCompletionBlock)completedBlock; + +/** + * Set the imageView `image` with an `url` and a optionaly placeholder image. + * + * The download is asynchronous and cached. + * + * @param url The url for the image. + * @param placeholder The image to be set initially, until the image request finishes. + * @param options The options to use when downloading the image. @see SDWebImageOptions for the possible values. + * @param progressBlock A block called while image is downloading + * @param completedBlock A block called when operation has been completed. This block has no return value + * and takes the requested UIImage as first parameter. In case of error the image parameter + * is nil and the second parameter may contain an NSError. The third parameter is a Boolean + * indicating if the image was retrived from the local cache of from the network. + * The forth parameter is the original image url. + */ +- (void)sd_setImageWithPreviousCachedImageWithURL:(NSURL *)url andPlaceholderImage:(UIImage *)placeholder options:(SDWebImageOptions)options progress:(SDWebImageDownloaderProgressBlock)progressBlock completed:(SDWebImageCompletionBlock)completedBlock; + +/** + * Download an array of images and starts them in an animation loop + * + * @param arrayOfURLs An array of NSURL + */ +- (void)sd_setAnimationImagesWithURLs:(NSArray *)arrayOfURLs; + +/** + * Cancel the current download + */ +- (void)sd_cancelCurrentImageLoad; + +- (void)sd_cancelCurrentAnimationImagesLoad; + +@end + + +@interface UIImageView (WebCacheDeprecated) + +- (NSURL *)imageURL __deprecated_msg("Use `sd_imageURL`"); + +- (void)setImageWithURL:(NSURL *)url __deprecated_msg("Method deprecated. Use `sd_setImageWithURL:`"); +- (void)setImageWithURL:(NSURL *)url placeholderImage:(UIImage *)placeholder __deprecated_msg("Method deprecated. Use `sd_setImageWithURL:placeholderImage:`"); +- (void)setImageWithURL:(NSURL *)url placeholderImage:(UIImage *)placeholder options:(SDWebImageOptions)options __deprecated_msg("Method deprecated. Use `sd_setImageWithURL:placeholderImage:options`"); + +- (void)setImageWithURL:(NSURL *)url completed:(SDWebImageCompletedBlock)completedBlock __deprecated_msg("Method deprecated. Use `sd_setImageWithURL:completed:`"); +- (void)setImageWithURL:(NSURL *)url placeholderImage:(UIImage *)placeholder completed:(SDWebImageCompletedBlock)completedBlock __deprecated_msg("Method deprecated. Use `sd_setImageWithURL:placeholderImage:completed:`"); +- (void)setImageWithURL:(NSURL *)url placeholderImage:(UIImage *)placeholder options:(SDWebImageOptions)options completed:(SDWebImageCompletedBlock)completedBlock __deprecated_msg("Method deprecated. Use `sd_setImageWithURL:placeholderImage:options:completed:`"); +- (void)setImageWithURL:(NSURL *)url placeholderImage:(UIImage *)placeholder options:(SDWebImageOptions)options progress:(SDWebImageDownloaderProgressBlock)progressBlock completed:(SDWebImageCompletedBlock)completedBlock __deprecated_msg("Method deprecated. Use `sd_setImageWithURL:placeholderImage:options:progress:completed:`"); + +- (void)setAnimationImagesWithURLs:(NSArray *)arrayOfURLs __deprecated_msg("Use `sd_setAnimationImagesWithURLs:`"); + +- (void)cancelCurrentArrayLoad __deprecated_msg("Use `sd_cancelCurrentAnimationImagesLoad`"); + +- (void)cancelCurrentImageLoad __deprecated_msg("Use `sd_cancelCurrentImageLoad`"); + +@end diff --git a/ios/Pods/SDWebImage/SDWebImage/UIImageView+WebCache.m b/ios/Pods/SDWebImage/SDWebImage/UIImageView+WebCache.m new file mode 100644 index 000000000..51663dd47 --- /dev/null +++ b/ios/Pods/SDWebImage/SDWebImage/UIImageView+WebCache.m @@ -0,0 +1,195 @@ +/* + * This file is part of the SDWebImage package. + * (c) Olivier Poitrey + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +#import "UIImageView+WebCache.h" +#import "objc/runtime.h" +#import "UIView+WebCacheOperation.h" + +static char imageURLKey; + +@implementation UIImageView (WebCache) + +- (void)sd_setImageWithURL:(NSURL *)url { + [self sd_setImageWithURL:url placeholderImage:nil options:0 progress:nil completed:nil]; +} + +- (void)sd_setImageWithURL:(NSURL *)url placeholderImage:(UIImage *)placeholder { + [self sd_setImageWithURL:url placeholderImage:placeholder options:0 progress:nil completed:nil]; +} + +- (void)sd_setImageWithURL:(NSURL *)url placeholderImage:(UIImage *)placeholder options:(SDWebImageOptions)options { + [self sd_setImageWithURL:url placeholderImage:placeholder options:options progress:nil completed:nil]; +} + +- (void)sd_setImageWithURL:(NSURL *)url completed:(SDWebImageCompletionBlock)completedBlock { + [self sd_setImageWithURL:url placeholderImage:nil options:0 progress:nil completed:completedBlock]; +} + +- (void)sd_setImageWithURL:(NSURL *)url placeholderImage:(UIImage *)placeholder completed:(SDWebImageCompletionBlock)completedBlock { + [self sd_setImageWithURL:url placeholderImage:placeholder options:0 progress:nil completed:completedBlock]; +} + +- (void)sd_setImageWithURL:(NSURL *)url placeholderImage:(UIImage *)placeholder options:(SDWebImageOptions)options completed:(SDWebImageCompletionBlock)completedBlock { + [self sd_setImageWithURL:url placeholderImage:placeholder options:options progress:nil completed:completedBlock]; +} + +- (void)sd_setImageWithURL:(NSURL *)url placeholderImage:(UIImage *)placeholder options:(SDWebImageOptions)options progress:(SDWebImageDownloaderProgressBlock)progressBlock completed:(SDWebImageCompletionBlock)completedBlock { + [self sd_cancelCurrentImageLoad]; + objc_setAssociatedObject(self, &imageURLKey, url, OBJC_ASSOCIATION_RETAIN_NONATOMIC); + + if (!(options & SDWebImageDelayPlaceholder)) { + self.image = placeholder; + } + + if (url) { + __weak UIImageView *wself = self; + id operation = [SDWebImageManager.sharedManager downloadImageWithURL:url options:options progress:progressBlock completed:^(UIImage *image, NSError *error, SDImageCacheType cacheType, BOOL finished, NSURL *imageURL) { + if (!wself) return; + dispatch_main_sync_safe(^{ + if (!wself) return; + if (image) { + wself.image = image; + [wself setNeedsLayout]; + } else { + if ((options & SDWebImageDelayPlaceholder)) { + wself.image = placeholder; + [wself setNeedsLayout]; + } + } + if (completedBlock && finished) { + completedBlock(image, error, cacheType, url); + } + }); + }]; + [self sd_setImageLoadOperation:operation forKey:@"UIImageViewImageLoad"]; + } else { + dispatch_main_async_safe(^{ + NSError *error = [NSError errorWithDomain:@"SDWebImageErrorDomain" code:-1 userInfo:@{NSLocalizedDescriptionKey : @"Trying to load a nil url"}]; + if (completedBlock) { + completedBlock(nil, error, SDImageCacheTypeNone, url); + } + }); + } +} + +- (void)sd_setImageWithPreviousCachedImageWithURL:(NSURL *)url andPlaceholderImage:(UIImage *)placeholder options:(SDWebImageOptions)options progress:(SDWebImageDownloaderProgressBlock)progressBlock completed:(SDWebImageCompletionBlock)completedBlock { + NSString *key = [[SDWebImageManager sharedManager] cacheKeyForURL:url]; + UIImage *lastPreviousCachedImage = [[SDImageCache sharedImageCache] imageFromDiskCacheForKey:key]; + + [self sd_setImageWithURL:url placeholderImage:lastPreviousCachedImage ?: placeholder options:options progress:progressBlock completed:completedBlock]; +} + +- (NSURL *)sd_imageURL { + return objc_getAssociatedObject(self, &imageURLKey); +} + +- (void)sd_setAnimationImagesWithURLs:(NSArray *)arrayOfURLs { + [self sd_cancelCurrentAnimationImagesLoad]; + __weak UIImageView *wself = self; + + NSMutableArray *operationsArray = [[NSMutableArray alloc] init]; + + for (NSURL *logoImageURL in arrayOfURLs) { + id operation = [SDWebImageManager.sharedManager downloadImageWithURL:logoImageURL options:0 progress:nil completed:^(UIImage *image, NSError *error, SDImageCacheType cacheType, BOOL finished, NSURL *imageURL) { + if (!wself) return; + dispatch_main_sync_safe(^{ + __strong UIImageView *sself = wself; + [sself stopAnimating]; + if (sself && image) { + NSMutableArray *currentImages = [[sself animationImages] mutableCopy]; + if (!currentImages) { + currentImages = [[NSMutableArray alloc] init]; + } + [currentImages addObject:image]; + + sself.animationImages = currentImages; + [sself setNeedsLayout]; + } + [sself startAnimating]; + }); + }]; + [operationsArray addObject:operation]; + } + + [self sd_setImageLoadOperation:[NSArray arrayWithArray:operationsArray] forKey:@"UIImageViewAnimationImages"]; +} + +- (void)sd_cancelCurrentImageLoad { + [self sd_cancelImageLoadOperationWithKey:@"UIImageViewImageLoad"]; +} + +- (void)sd_cancelCurrentAnimationImagesLoad { + [self sd_cancelImageLoadOperationWithKey:@"UIImageViewAnimationImages"]; +} + +@end + + +@implementation UIImageView (WebCacheDeprecated) + +- (NSURL *)imageURL { + return [self sd_imageURL]; +} + +- (void)setImageWithURL:(NSURL *)url { + [self sd_setImageWithURL:url placeholderImage:nil options:0 progress:nil completed:nil]; +} + +- (void)setImageWithURL:(NSURL *)url placeholderImage:(UIImage *)placeholder { + [self sd_setImageWithURL:url placeholderImage:placeholder options:0 progress:nil completed:nil]; +} + +- (void)setImageWithURL:(NSURL *)url placeholderImage:(UIImage *)placeholder options:(SDWebImageOptions)options { + [self sd_setImageWithURL:url placeholderImage:placeholder options:options progress:nil completed:nil]; +} + +- (void)setImageWithURL:(NSURL *)url completed:(SDWebImageCompletedBlock)completedBlock { + [self sd_setImageWithURL:url placeholderImage:nil options:0 progress:nil completed:^(UIImage *image, NSError *error, SDImageCacheType cacheType, NSURL *imageURL) { + if (completedBlock) { + completedBlock(image, error, cacheType); + } + }]; +} + +- (void)setImageWithURL:(NSURL *)url placeholderImage:(UIImage *)placeholder completed:(SDWebImageCompletedBlock)completedBlock { + [self sd_setImageWithURL:url placeholderImage:placeholder options:0 progress:nil completed:^(UIImage *image, NSError *error, SDImageCacheType cacheType, NSURL *imageURL) { + if (completedBlock) { + completedBlock(image, error, cacheType); + } + }]; +} + +- (void)setImageWithURL:(NSURL *)url placeholderImage:(UIImage *)placeholder options:(SDWebImageOptions)options completed:(SDWebImageCompletedBlock)completedBlock { + [self sd_setImageWithURL:url placeholderImage:placeholder options:options progress:nil completed:^(UIImage *image, NSError *error, SDImageCacheType cacheType, NSURL *imageURL) { + if (completedBlock) { + completedBlock(image, error, cacheType); + } + }]; +} + +- (void)setImageWithURL:(NSURL *)url placeholderImage:(UIImage *)placeholder options:(SDWebImageOptions)options progress:(SDWebImageDownloaderProgressBlock)progressBlock completed:(SDWebImageCompletedBlock)completedBlock { + [self sd_setImageWithURL:url placeholderImage:placeholder options:options progress:progressBlock completed:^(UIImage *image, NSError *error, SDImageCacheType cacheType, NSURL *imageURL) { + if (completedBlock) { + completedBlock(image, error, cacheType); + } + }]; +} + +- (void)cancelCurrentArrayLoad { + [self sd_cancelCurrentAnimationImagesLoad]; +} + +- (void)cancelCurrentImageLoad { + [self sd_cancelCurrentImageLoad]; +} + +- (void)setAnimationImagesWithURLs:(NSArray *)arrayOfURLs { + [self sd_setAnimationImagesWithURLs:arrayOfURLs]; +} + +@end diff --git a/ios/Pods/SDWebImage/SDWebImage/UIView+WebCacheOperation.h b/ios/Pods/SDWebImage/SDWebImage/UIView+WebCacheOperation.h new file mode 100644 index 000000000..67190362d --- /dev/null +++ b/ios/Pods/SDWebImage/SDWebImage/UIView+WebCacheOperation.h @@ -0,0 +1,36 @@ +/* + * This file is part of the SDWebImage package. + * (c) Olivier Poitrey + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +#import +#import "SDWebImageManager.h" + +@interface UIView (WebCacheOperation) + +/** + * Set the image load operation (storage in a UIView based dictionary) + * + * @param operation the operation + * @param key key for storing the operation + */ +- (void)sd_setImageLoadOperation:(id)operation forKey:(NSString *)key; + +/** + * Cancel all operations for the current UIView and key + * + * @param key key for identifying the operations + */ +- (void)sd_cancelImageLoadOperationWithKey:(NSString *)key; + +/** + * Just remove the operations corresponding to the current UIView and key without cancelling them + * + * @param key key for identifying the operations + */ +- (void)sd_removeImageLoadOperationWithKey:(NSString *)key; + +@end diff --git a/ios/Pods/SDWebImage/SDWebImage/UIView+WebCacheOperation.m b/ios/Pods/SDWebImage/SDWebImage/UIView+WebCacheOperation.m new file mode 100644 index 000000000..92194780d --- /dev/null +++ b/ios/Pods/SDWebImage/SDWebImage/UIView+WebCacheOperation.m @@ -0,0 +1,55 @@ +/* + * This file is part of the SDWebImage package. + * (c) Olivier Poitrey + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +#import "UIView+WebCacheOperation.h" +#import "objc/runtime.h" + +static char loadOperationKey; + +@implementation UIView (WebCacheOperation) + +- (NSMutableDictionary *)operationDictionary { + NSMutableDictionary *operations = objc_getAssociatedObject(self, &loadOperationKey); + if (operations) { + return operations; + } + operations = [NSMutableDictionary dictionary]; + objc_setAssociatedObject(self, &loadOperationKey, operations, OBJC_ASSOCIATION_RETAIN_NONATOMIC); + return operations; +} + +- (void)sd_setImageLoadOperation:(id)operation forKey:(NSString *)key { + [self sd_cancelImageLoadOperationWithKey:key]; + NSMutableDictionary *operationDictionary = [self operationDictionary]; + [operationDictionary setObject:operation forKey:key]; +} + +- (void)sd_cancelImageLoadOperationWithKey:(NSString *)key { + // Cancel in progress downloader from queue + NSMutableDictionary *operationDictionary = [self operationDictionary]; + id operations = [operationDictionary objectForKey:key]; + if (operations) { + if ([operations isKindOfClass:[NSArray class]]) { + for (id operation in operations) { + if (operation) { + [operation cancel]; + } + } + } else if ([operations conformsToProtocol:@protocol(SDWebImageOperation)]){ + [(id) operations cancel]; + } + [operationDictionary removeObjectForKey:key]; + } +} + +- (void)sd_removeImageLoadOperationWithKey:(NSString *)key { + NSMutableDictionary *operationDictionary = [self operationDictionary]; + [operationDictionary removeObjectForKey:key]; +} + +@end diff --git a/ios/Pods/Target Support Files/Pods-AFNetworking/Pods-AFNetworking-Private.xcconfig b/ios/Pods/Target Support Files/Pods-AFNetworking/Pods-AFNetworking-Private.xcconfig new file mode 100644 index 000000000..73ec57eed --- /dev/null +++ b/ios/Pods/Target Support Files/Pods-AFNetworking/Pods-AFNetworking-Private.xcconfig @@ -0,0 +1,5 @@ +#include "Pods-AFNetworking.xcconfig" +GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1 +HEADER_SEARCH_PATHS = "${PODS_ROOT}/Headers/Build" "${PODS_ROOT}/Headers/Build/AFNetworking" "${PODS_ROOT}/Headers/Public" "${PODS_ROOT}/Headers/Public/AFNetworking" "${PODS_ROOT}/Headers/Public/DACircularProgress" "${PODS_ROOT}/Headers/Public/FMDB" "${PODS_ROOT}/Headers/Public/HPGrowingTextView" "${PODS_ROOT}/Headers/Public/MBProgressHUD" "${PODS_ROOT}/Headers/Public/MWPhotoBrowser" "${PODS_ROOT}/Headers/Public/PSTCollectionView" "${PODS_ROOT}/Headers/Public/ProtocolBuffers" "${PODS_ROOT}/Headers/Public/ProtocolBuffers/ProtocolBuffers" "${PODS_ROOT}/Headers/Public/SCLAlertView-Objective-C" "${PODS_ROOT}/Headers/Public/SDWebImage" "${PODS_ROOT}/Headers/Public/leveldb-library" "${PODS_ROOT}/Headers/Public/leveldb-library/leveldb" +OTHER_LDFLAGS = ${PODS_AFNETWORKING_OTHER_LDFLAGS} -ObjC +PODS_ROOT = ${SRCROOT} \ No newline at end of file diff --git a/ios/Pods/Target Support Files/Pods-AFNetworking/Pods-AFNetworking-dummy.m b/ios/Pods/Target Support Files/Pods-AFNetworking/Pods-AFNetworking-dummy.m new file mode 100644 index 000000000..c50a8c616 --- /dev/null +++ b/ios/Pods/Target Support Files/Pods-AFNetworking/Pods-AFNetworking-dummy.m @@ -0,0 +1,5 @@ +#import +@interface PodsDummy_Pods_AFNetworking : NSObject +@end +@implementation PodsDummy_Pods_AFNetworking +@end diff --git a/ios/Pods/Target Support Files/Pods-AFNetworking/Pods-AFNetworking-prefix.pch b/ios/Pods/Target Support Files/Pods-AFNetworking/Pods-AFNetworking-prefix.pch new file mode 100644 index 000000000..95cf11d9f --- /dev/null +++ b/ios/Pods/Target Support Files/Pods-AFNetworking/Pods-AFNetworking-prefix.pch @@ -0,0 +1,5 @@ +#ifdef __OBJC__ +#import +#endif + +#import "Pods-environment.h" diff --git a/ios/Pods/Target Support Files/Pods-AFNetworking/Pods-AFNetworking.xcconfig b/ios/Pods/Target Support Files/Pods-AFNetworking/Pods-AFNetworking.xcconfig new file mode 100644 index 000000000..c2f387a45 --- /dev/null +++ b/ios/Pods/Target Support Files/Pods-AFNetworking/Pods-AFNetworking.xcconfig @@ -0,0 +1 @@ +PODS_AFNETWORKING_OTHER_LDFLAGS = -framework "CoreGraphics" -framework "MobileCoreServices" -framework "Security" -framework "SystemConfiguration" \ No newline at end of file diff --git a/ios/Pods/Target Support Files/Pods-DACircularProgress/Pods-DACircularProgress-Private.xcconfig b/ios/Pods/Target Support Files/Pods-DACircularProgress/Pods-DACircularProgress-Private.xcconfig new file mode 100644 index 000000000..eb4188c56 --- /dev/null +++ b/ios/Pods/Target Support Files/Pods-DACircularProgress/Pods-DACircularProgress-Private.xcconfig @@ -0,0 +1,5 @@ +#include "Pods-DACircularProgress.xcconfig" +GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1 +HEADER_SEARCH_PATHS = "${PODS_ROOT}/Headers/Build" "${PODS_ROOT}/Headers/Build/DACircularProgress" "${PODS_ROOT}/Headers/Public" "${PODS_ROOT}/Headers/Public/AFNetworking" "${PODS_ROOT}/Headers/Public/DACircularProgress" "${PODS_ROOT}/Headers/Public/FMDB" "${PODS_ROOT}/Headers/Public/HPGrowingTextView" "${PODS_ROOT}/Headers/Public/MBProgressHUD" "${PODS_ROOT}/Headers/Public/MWPhotoBrowser" "${PODS_ROOT}/Headers/Public/PSTCollectionView" "${PODS_ROOT}/Headers/Public/ProtocolBuffers" "${PODS_ROOT}/Headers/Public/ProtocolBuffers/ProtocolBuffers" "${PODS_ROOT}/Headers/Public/SCLAlertView-Objective-C" "${PODS_ROOT}/Headers/Public/SDWebImage" "${PODS_ROOT}/Headers/Public/leveldb-library" "${PODS_ROOT}/Headers/Public/leveldb-library/leveldb" +OTHER_LDFLAGS = ${PODS_DACIRCULARPROGRESS_OTHER_LDFLAGS} -ObjC +PODS_ROOT = ${SRCROOT} \ No newline at end of file diff --git a/ios/Pods/Target Support Files/Pods-DACircularProgress/Pods-DACircularProgress-dummy.m b/ios/Pods/Target Support Files/Pods-DACircularProgress/Pods-DACircularProgress-dummy.m new file mode 100644 index 000000000..42b1ea3d7 --- /dev/null +++ b/ios/Pods/Target Support Files/Pods-DACircularProgress/Pods-DACircularProgress-dummy.m @@ -0,0 +1,5 @@ +#import +@interface PodsDummy_Pods_DACircularProgress : NSObject +@end +@implementation PodsDummy_Pods_DACircularProgress +@end diff --git a/ios/Pods/Target Support Files/Pods-DACircularProgress/Pods-DACircularProgress-prefix.pch b/ios/Pods/Target Support Files/Pods-DACircularProgress/Pods-DACircularProgress-prefix.pch new file mode 100644 index 000000000..95cf11d9f --- /dev/null +++ b/ios/Pods/Target Support Files/Pods-DACircularProgress/Pods-DACircularProgress-prefix.pch @@ -0,0 +1,5 @@ +#ifdef __OBJC__ +#import +#endif + +#import "Pods-environment.h" diff --git a/ios/Pods/Target Support Files/Pods-DACircularProgress/Pods-DACircularProgress.xcconfig b/ios/Pods/Target Support Files/Pods-DACircularProgress/Pods-DACircularProgress.xcconfig new file mode 100644 index 000000000..3e1517320 --- /dev/null +++ b/ios/Pods/Target Support Files/Pods-DACircularProgress/Pods-DACircularProgress.xcconfig @@ -0,0 +1 @@ +PODS_DACIRCULARPROGRESS_OTHER_LDFLAGS = -framework "QuartzCore" \ No newline at end of file diff --git a/ios/Pods/Target Support Files/Pods-FMDB/Pods-FMDB-Private.xcconfig b/ios/Pods/Target Support Files/Pods-FMDB/Pods-FMDB-Private.xcconfig new file mode 100644 index 000000000..599dd8cde --- /dev/null +++ b/ios/Pods/Target Support Files/Pods-FMDB/Pods-FMDB-Private.xcconfig @@ -0,0 +1,5 @@ +#include "Pods-FMDB.xcconfig" +GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1 +HEADER_SEARCH_PATHS = "${PODS_ROOT}/Headers/Build" "${PODS_ROOT}/Headers/Build/FMDB" "${PODS_ROOT}/Headers/Public" "${PODS_ROOT}/Headers/Public/AFNetworking" "${PODS_ROOT}/Headers/Public/DACircularProgress" "${PODS_ROOT}/Headers/Public/FMDB" "${PODS_ROOT}/Headers/Public/HPGrowingTextView" "${PODS_ROOT}/Headers/Public/MBProgressHUD" "${PODS_ROOT}/Headers/Public/MWPhotoBrowser" "${PODS_ROOT}/Headers/Public/PSTCollectionView" "${PODS_ROOT}/Headers/Public/ProtocolBuffers" "${PODS_ROOT}/Headers/Public/ProtocolBuffers/ProtocolBuffers" "${PODS_ROOT}/Headers/Public/SCLAlertView-Objective-C" "${PODS_ROOT}/Headers/Public/SDWebImage" "${PODS_ROOT}/Headers/Public/leveldb-library" "${PODS_ROOT}/Headers/Public/leveldb-library/leveldb" +OTHER_LDFLAGS = ${PODS_FMDB_OTHER_LDFLAGS} -ObjC +PODS_ROOT = ${SRCROOT} \ No newline at end of file diff --git a/ios/Pods/Target Support Files/Pods-FMDB/Pods-FMDB-dummy.m b/ios/Pods/Target Support Files/Pods-FMDB/Pods-FMDB-dummy.m new file mode 100644 index 000000000..9f21ee33f --- /dev/null +++ b/ios/Pods/Target Support Files/Pods-FMDB/Pods-FMDB-dummy.m @@ -0,0 +1,5 @@ +#import +@interface PodsDummy_Pods_FMDB : NSObject +@end +@implementation PodsDummy_Pods_FMDB +@end diff --git a/ios/Pods/Target Support Files/Pods-FMDB/Pods-FMDB-prefix.pch b/ios/Pods/Target Support Files/Pods-FMDB/Pods-FMDB-prefix.pch new file mode 100644 index 000000000..95cf11d9f --- /dev/null +++ b/ios/Pods/Target Support Files/Pods-FMDB/Pods-FMDB-prefix.pch @@ -0,0 +1,5 @@ +#ifdef __OBJC__ +#import +#endif + +#import "Pods-environment.h" diff --git a/ios/Pods/Target Support Files/Pods-FMDB/Pods-FMDB.xcconfig b/ios/Pods/Target Support Files/Pods-FMDB/Pods-FMDB.xcconfig new file mode 100644 index 000000000..dc1e7e4d2 --- /dev/null +++ b/ios/Pods/Target Support Files/Pods-FMDB/Pods-FMDB.xcconfig @@ -0,0 +1 @@ +PODS_FMDB_OTHER_LDFLAGS = -l"sqlite3" \ No newline at end of file diff --git a/ios/Pods/Target Support Files/Pods-HPGrowingTextView/Pods-HPGrowingTextView-Private.xcconfig b/ios/Pods/Target Support Files/Pods-HPGrowingTextView/Pods-HPGrowingTextView-Private.xcconfig new file mode 100644 index 000000000..6fd8547c6 --- /dev/null +++ b/ios/Pods/Target Support Files/Pods-HPGrowingTextView/Pods-HPGrowingTextView-Private.xcconfig @@ -0,0 +1,5 @@ +#include "Pods-HPGrowingTextView.xcconfig" +GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1 +HEADER_SEARCH_PATHS = "${PODS_ROOT}/Headers/Build" "${PODS_ROOT}/Headers/Build/HPGrowingTextView" "${PODS_ROOT}/Headers/Public" "${PODS_ROOT}/Headers/Public/AFNetworking" "${PODS_ROOT}/Headers/Public/DACircularProgress" "${PODS_ROOT}/Headers/Public/FMDB" "${PODS_ROOT}/Headers/Public/HPGrowingTextView" "${PODS_ROOT}/Headers/Public/MBProgressHUD" "${PODS_ROOT}/Headers/Public/MWPhotoBrowser" "${PODS_ROOT}/Headers/Public/PSTCollectionView" "${PODS_ROOT}/Headers/Public/ProtocolBuffers" "${PODS_ROOT}/Headers/Public/ProtocolBuffers/ProtocolBuffers" "${PODS_ROOT}/Headers/Public/SCLAlertView-Objective-C" "${PODS_ROOT}/Headers/Public/SDWebImage" "${PODS_ROOT}/Headers/Public/leveldb-library" "${PODS_ROOT}/Headers/Public/leveldb-library/leveldb" +OTHER_LDFLAGS = -ObjC +PODS_ROOT = ${SRCROOT} \ No newline at end of file diff --git a/ios/Pods/Target Support Files/Pods-HPGrowingTextView/Pods-HPGrowingTextView-dummy.m b/ios/Pods/Target Support Files/Pods-HPGrowingTextView/Pods-HPGrowingTextView-dummy.m new file mode 100644 index 000000000..040436322 --- /dev/null +++ b/ios/Pods/Target Support Files/Pods-HPGrowingTextView/Pods-HPGrowingTextView-dummy.m @@ -0,0 +1,5 @@ +#import +@interface PodsDummy_Pods_HPGrowingTextView : NSObject +@end +@implementation PodsDummy_Pods_HPGrowingTextView +@end diff --git a/ios/Pods/Target Support Files/Pods-HPGrowingTextView/Pods-HPGrowingTextView-prefix.pch b/ios/Pods/Target Support Files/Pods-HPGrowingTextView/Pods-HPGrowingTextView-prefix.pch new file mode 100644 index 000000000..95cf11d9f --- /dev/null +++ b/ios/Pods/Target Support Files/Pods-HPGrowingTextView/Pods-HPGrowingTextView-prefix.pch @@ -0,0 +1,5 @@ +#ifdef __OBJC__ +#import +#endif + +#import "Pods-environment.h" diff --git a/ios/Pods/Target Support Files/Pods-HPGrowingTextView/Pods-HPGrowingTextView.xcconfig b/ios/Pods/Target Support Files/Pods-HPGrowingTextView/Pods-HPGrowingTextView.xcconfig new file mode 100644 index 000000000..e69de29bb diff --git a/ios/Pods/Target Support Files/Pods-MBProgressHUD/Pods-MBProgressHUD-Private.xcconfig b/ios/Pods/Target Support Files/Pods-MBProgressHUD/Pods-MBProgressHUD-Private.xcconfig new file mode 100644 index 000000000..e908bb717 --- /dev/null +++ b/ios/Pods/Target Support Files/Pods-MBProgressHUD/Pods-MBProgressHUD-Private.xcconfig @@ -0,0 +1,5 @@ +#include "Pods-MBProgressHUD.xcconfig" +GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1 +HEADER_SEARCH_PATHS = "${PODS_ROOT}/Headers/Build" "${PODS_ROOT}/Headers/Build/MBProgressHUD" "${PODS_ROOT}/Headers/Public" "${PODS_ROOT}/Headers/Public/AFNetworking" "${PODS_ROOT}/Headers/Public/DACircularProgress" "${PODS_ROOT}/Headers/Public/FMDB" "${PODS_ROOT}/Headers/Public/HPGrowingTextView" "${PODS_ROOT}/Headers/Public/MBProgressHUD" "${PODS_ROOT}/Headers/Public/MWPhotoBrowser" "${PODS_ROOT}/Headers/Public/PSTCollectionView" "${PODS_ROOT}/Headers/Public/ProtocolBuffers" "${PODS_ROOT}/Headers/Public/ProtocolBuffers/ProtocolBuffers" "${PODS_ROOT}/Headers/Public/SCLAlertView-Objective-C" "${PODS_ROOT}/Headers/Public/SDWebImage" "${PODS_ROOT}/Headers/Public/leveldb-library" "${PODS_ROOT}/Headers/Public/leveldb-library/leveldb" +OTHER_LDFLAGS = ${PODS_MBPROGRESSHUD_OTHER_LDFLAGS} -ObjC +PODS_ROOT = ${SRCROOT} \ No newline at end of file diff --git a/ios/Pods/Target Support Files/Pods-MBProgressHUD/Pods-MBProgressHUD-dummy.m b/ios/Pods/Target Support Files/Pods-MBProgressHUD/Pods-MBProgressHUD-dummy.m new file mode 100644 index 000000000..10d445d68 --- /dev/null +++ b/ios/Pods/Target Support Files/Pods-MBProgressHUD/Pods-MBProgressHUD-dummy.m @@ -0,0 +1,5 @@ +#import +@interface PodsDummy_Pods_MBProgressHUD : NSObject +@end +@implementation PodsDummy_Pods_MBProgressHUD +@end diff --git a/ios/Pods/Target Support Files/Pods-MBProgressHUD/Pods-MBProgressHUD-prefix.pch b/ios/Pods/Target Support Files/Pods-MBProgressHUD/Pods-MBProgressHUD-prefix.pch new file mode 100644 index 000000000..95cf11d9f --- /dev/null +++ b/ios/Pods/Target Support Files/Pods-MBProgressHUD/Pods-MBProgressHUD-prefix.pch @@ -0,0 +1,5 @@ +#ifdef __OBJC__ +#import +#endif + +#import "Pods-environment.h" diff --git a/ios/Pods/Target Support Files/Pods-MBProgressHUD/Pods-MBProgressHUD.xcconfig b/ios/Pods/Target Support Files/Pods-MBProgressHUD/Pods-MBProgressHUD.xcconfig new file mode 100644 index 000000000..9bf825373 --- /dev/null +++ b/ios/Pods/Target Support Files/Pods-MBProgressHUD/Pods-MBProgressHUD.xcconfig @@ -0,0 +1 @@ +PODS_MBPROGRESSHUD_OTHER_LDFLAGS = -framework "CoreGraphics" \ No newline at end of file diff --git a/ios/Pods/Target Support Files/Pods-MWPhotoBrowser/Pods-MWPhotoBrowser-Private.xcconfig b/ios/Pods/Target Support Files/Pods-MWPhotoBrowser/Pods-MWPhotoBrowser-Private.xcconfig new file mode 100644 index 000000000..2b6c66776 --- /dev/null +++ b/ios/Pods/Target Support Files/Pods-MWPhotoBrowser/Pods-MWPhotoBrowser-Private.xcconfig @@ -0,0 +1,5 @@ +#include "Pods-MWPhotoBrowser.xcconfig" +GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1 +HEADER_SEARCH_PATHS = "${PODS_ROOT}/Headers/Build" "${PODS_ROOT}/Headers/Build/MWPhotoBrowser" "${PODS_ROOT}/Headers/Public" "${PODS_ROOT}/Headers/Public/AFNetworking" "${PODS_ROOT}/Headers/Public/DACircularProgress" "${PODS_ROOT}/Headers/Public/FMDB" "${PODS_ROOT}/Headers/Public/HPGrowingTextView" "${PODS_ROOT}/Headers/Public/MBProgressHUD" "${PODS_ROOT}/Headers/Public/MWPhotoBrowser" "${PODS_ROOT}/Headers/Public/PSTCollectionView" "${PODS_ROOT}/Headers/Public/ProtocolBuffers" "${PODS_ROOT}/Headers/Public/ProtocolBuffers/ProtocolBuffers" "${PODS_ROOT}/Headers/Public/SCLAlertView-Objective-C" "${PODS_ROOT}/Headers/Public/SDWebImage" "${PODS_ROOT}/Headers/Public/leveldb-library" "${PODS_ROOT}/Headers/Public/leveldb-library/leveldb" +OTHER_LDFLAGS = ${PODS_MWPHOTOBROWSER_OTHER_LDFLAGS} -ObjC +PODS_ROOT = ${SRCROOT} \ No newline at end of file diff --git a/ios/Pods/Target Support Files/Pods-MWPhotoBrowser/Pods-MWPhotoBrowser-dummy.m b/ios/Pods/Target Support Files/Pods-MWPhotoBrowser/Pods-MWPhotoBrowser-dummy.m new file mode 100644 index 000000000..9e0162fb1 --- /dev/null +++ b/ios/Pods/Target Support Files/Pods-MWPhotoBrowser/Pods-MWPhotoBrowser-dummy.m @@ -0,0 +1,5 @@ +#import +@interface PodsDummy_Pods_MWPhotoBrowser : NSObject +@end +@implementation PodsDummy_Pods_MWPhotoBrowser +@end diff --git a/ios/Pods/Target Support Files/Pods-MWPhotoBrowser/Pods-MWPhotoBrowser-prefix.pch b/ios/Pods/Target Support Files/Pods-MWPhotoBrowser/Pods-MWPhotoBrowser-prefix.pch new file mode 100644 index 000000000..95cf11d9f --- /dev/null +++ b/ios/Pods/Target Support Files/Pods-MWPhotoBrowser/Pods-MWPhotoBrowser-prefix.pch @@ -0,0 +1,5 @@ +#ifdef __OBJC__ +#import +#endif + +#import "Pods-environment.h" diff --git a/ios/Pods/Target Support Files/Pods-MWPhotoBrowser/Pods-MWPhotoBrowser.xcconfig b/ios/Pods/Target Support Files/Pods-MWPhotoBrowser/Pods-MWPhotoBrowser.xcconfig new file mode 100644 index 000000000..a99d35e4b --- /dev/null +++ b/ios/Pods/Target Support Files/Pods-MWPhotoBrowser/Pods-MWPhotoBrowser.xcconfig @@ -0,0 +1 @@ +PODS_MWPHOTOBROWSER_OTHER_LDFLAGS = -framework "AssetsLibrary" -framework "ImageIO" -framework "MapKit" -framework "MessageUI" -framework "QuartzCore" \ No newline at end of file diff --git a/ios/Pods/Target Support Files/Pods-PSTCollectionView/Pods-PSTCollectionView-Private.xcconfig b/ios/Pods/Target Support Files/Pods-PSTCollectionView/Pods-PSTCollectionView-Private.xcconfig new file mode 100644 index 000000000..537141b08 --- /dev/null +++ b/ios/Pods/Target Support Files/Pods-PSTCollectionView/Pods-PSTCollectionView-Private.xcconfig @@ -0,0 +1,5 @@ +#include "Pods-PSTCollectionView.xcconfig" +GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1 +HEADER_SEARCH_PATHS = "${PODS_ROOT}/Headers/Build" "${PODS_ROOT}/Headers/Build/PSTCollectionView" "${PODS_ROOT}/Headers/Public" "${PODS_ROOT}/Headers/Public/AFNetworking" "${PODS_ROOT}/Headers/Public/DACircularProgress" "${PODS_ROOT}/Headers/Public/FMDB" "${PODS_ROOT}/Headers/Public/HPGrowingTextView" "${PODS_ROOT}/Headers/Public/MBProgressHUD" "${PODS_ROOT}/Headers/Public/MWPhotoBrowser" "${PODS_ROOT}/Headers/Public/PSTCollectionView" "${PODS_ROOT}/Headers/Public/ProtocolBuffers" "${PODS_ROOT}/Headers/Public/ProtocolBuffers/ProtocolBuffers" "${PODS_ROOT}/Headers/Public/SCLAlertView-Objective-C" "${PODS_ROOT}/Headers/Public/SDWebImage" "${PODS_ROOT}/Headers/Public/leveldb-library" "${PODS_ROOT}/Headers/Public/leveldb-library/leveldb" +OTHER_LDFLAGS = ${PODS_PSTCOLLECTIONVIEW_OTHER_LDFLAGS} -ObjC +PODS_ROOT = ${SRCROOT} \ No newline at end of file diff --git a/ios/Pods/Target Support Files/Pods-PSTCollectionView/Pods-PSTCollectionView-dummy.m b/ios/Pods/Target Support Files/Pods-PSTCollectionView/Pods-PSTCollectionView-dummy.m new file mode 100644 index 000000000..e7afdfb1b --- /dev/null +++ b/ios/Pods/Target Support Files/Pods-PSTCollectionView/Pods-PSTCollectionView-dummy.m @@ -0,0 +1,5 @@ +#import +@interface PodsDummy_Pods_PSTCollectionView : NSObject +@end +@implementation PodsDummy_Pods_PSTCollectionView +@end diff --git a/ios/Pods/Target Support Files/Pods-PSTCollectionView/Pods-PSTCollectionView-prefix.pch b/ios/Pods/Target Support Files/Pods-PSTCollectionView/Pods-PSTCollectionView-prefix.pch new file mode 100644 index 000000000..95cf11d9f --- /dev/null +++ b/ios/Pods/Target Support Files/Pods-PSTCollectionView/Pods-PSTCollectionView-prefix.pch @@ -0,0 +1,5 @@ +#ifdef __OBJC__ +#import +#endif + +#import "Pods-environment.h" diff --git a/ios/Pods/Target Support Files/Pods-PSTCollectionView/Pods-PSTCollectionView.xcconfig b/ios/Pods/Target Support Files/Pods-PSTCollectionView/Pods-PSTCollectionView.xcconfig new file mode 100644 index 000000000..07a1e46ea --- /dev/null +++ b/ios/Pods/Target Support Files/Pods-PSTCollectionView/Pods-PSTCollectionView.xcconfig @@ -0,0 +1 @@ +PODS_PSTCOLLECTIONVIEW_OTHER_LDFLAGS = -framework "QuartzCore" -framework "UIKit" \ No newline at end of file diff --git a/ios/Pods/Target Support Files/Pods-ProtocolBuffers/Pods-ProtocolBuffers-Private.xcconfig b/ios/Pods/Target Support Files/Pods-ProtocolBuffers/Pods-ProtocolBuffers-Private.xcconfig new file mode 100644 index 000000000..35e505eab --- /dev/null +++ b/ios/Pods/Target Support Files/Pods-ProtocolBuffers/Pods-ProtocolBuffers-Private.xcconfig @@ -0,0 +1,5 @@ +#include "Pods-ProtocolBuffers.xcconfig" +GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1 +HEADER_SEARCH_PATHS = "${PODS_ROOT}/Headers/Build" "${PODS_ROOT}/Headers/Build/ProtocolBuffers" "${PODS_ROOT}/Headers/Build/ProtocolBuffers/ProtocolBuffers" "${PODS_ROOT}/Headers/Public" "${PODS_ROOT}/Headers/Public/AFNetworking" "${PODS_ROOT}/Headers/Public/DACircularProgress" "${PODS_ROOT}/Headers/Public/FMDB" "${PODS_ROOT}/Headers/Public/HPGrowingTextView" "${PODS_ROOT}/Headers/Public/MBProgressHUD" "${PODS_ROOT}/Headers/Public/MWPhotoBrowser" "${PODS_ROOT}/Headers/Public/PSTCollectionView" "${PODS_ROOT}/Headers/Public/ProtocolBuffers" "${PODS_ROOT}/Headers/Public/ProtocolBuffers/ProtocolBuffers" "${PODS_ROOT}/Headers/Public/SCLAlertView-Objective-C" "${PODS_ROOT}/Headers/Public/SDWebImage" "${PODS_ROOT}/Headers/Public/leveldb-library" "${PODS_ROOT}/Headers/Public/leveldb-library/leveldb" +OTHER_LDFLAGS = ${PODS_PROTOCOLBUFFERS_OTHER_LDFLAGS} -ObjC +PODS_ROOT = ${SRCROOT} \ No newline at end of file diff --git a/ios/Pods/Target Support Files/Pods-ProtocolBuffers/Pods-ProtocolBuffers-dummy.m b/ios/Pods/Target Support Files/Pods-ProtocolBuffers/Pods-ProtocolBuffers-dummy.m new file mode 100644 index 000000000..42bb4016b --- /dev/null +++ b/ios/Pods/Target Support Files/Pods-ProtocolBuffers/Pods-ProtocolBuffers-dummy.m @@ -0,0 +1,5 @@ +#import +@interface PodsDummy_Pods_ProtocolBuffers : NSObject +@end +@implementation PodsDummy_Pods_ProtocolBuffers +@end diff --git a/ios/Pods/Target Support Files/Pods-ProtocolBuffers/Pods-ProtocolBuffers-prefix.pch b/ios/Pods/Target Support Files/Pods-ProtocolBuffers/Pods-ProtocolBuffers-prefix.pch new file mode 100644 index 000000000..95cf11d9f --- /dev/null +++ b/ios/Pods/Target Support Files/Pods-ProtocolBuffers/Pods-ProtocolBuffers-prefix.pch @@ -0,0 +1,5 @@ +#ifdef __OBJC__ +#import +#endif + +#import "Pods-environment.h" diff --git a/ios/Pods/Target Support Files/Pods-ProtocolBuffers/Pods-ProtocolBuffers.xcconfig b/ios/Pods/Target Support Files/Pods-ProtocolBuffers/Pods-ProtocolBuffers.xcconfig new file mode 100644 index 000000000..95b77204b --- /dev/null +++ b/ios/Pods/Target Support Files/Pods-ProtocolBuffers/Pods-ProtocolBuffers.xcconfig @@ -0,0 +1 @@ +PODS_PROTOCOLBUFFERS_OTHER_LDFLAGS = -framework "Foundation" \ No newline at end of file diff --git a/ios/Pods/Target Support Files/Pods-SCLAlertView-Objective-C/Pods-SCLAlertView-Objective-C-Private.xcconfig b/ios/Pods/Target Support Files/Pods-SCLAlertView-Objective-C/Pods-SCLAlertView-Objective-C-Private.xcconfig new file mode 100644 index 000000000..15816fd9a --- /dev/null +++ b/ios/Pods/Target Support Files/Pods-SCLAlertView-Objective-C/Pods-SCLAlertView-Objective-C-Private.xcconfig @@ -0,0 +1,5 @@ +#include "Pods-SCLAlertView-Objective-C.xcconfig" +GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1 +HEADER_SEARCH_PATHS = "${PODS_ROOT}/Headers/Build" "${PODS_ROOT}/Headers/Build/SCLAlertView-Objective-C" "${PODS_ROOT}/Headers/Public" "${PODS_ROOT}/Headers/Public/AFNetworking" "${PODS_ROOT}/Headers/Public/DACircularProgress" "${PODS_ROOT}/Headers/Public/FMDB" "${PODS_ROOT}/Headers/Public/HPGrowingTextView" "${PODS_ROOT}/Headers/Public/MBProgressHUD" "${PODS_ROOT}/Headers/Public/MWPhotoBrowser" "${PODS_ROOT}/Headers/Public/PSTCollectionView" "${PODS_ROOT}/Headers/Public/ProtocolBuffers" "${PODS_ROOT}/Headers/Public/ProtocolBuffers/ProtocolBuffers" "${PODS_ROOT}/Headers/Public/SCLAlertView-Objective-C" "${PODS_ROOT}/Headers/Public/SDWebImage" "${PODS_ROOT}/Headers/Public/leveldb-library" "${PODS_ROOT}/Headers/Public/leveldb-library/leveldb" +OTHER_LDFLAGS = -ObjC +PODS_ROOT = ${SRCROOT} \ No newline at end of file diff --git a/ios/Pods/Target Support Files/Pods-SCLAlertView-Objective-C/Pods-SCLAlertView-Objective-C-dummy.m b/ios/Pods/Target Support Files/Pods-SCLAlertView-Objective-C/Pods-SCLAlertView-Objective-C-dummy.m new file mode 100644 index 000000000..aa5e0130f --- /dev/null +++ b/ios/Pods/Target Support Files/Pods-SCLAlertView-Objective-C/Pods-SCLAlertView-Objective-C-dummy.m @@ -0,0 +1,5 @@ +#import +@interface PodsDummy_Pods_SCLAlertView_Objective_C : NSObject +@end +@implementation PodsDummy_Pods_SCLAlertView_Objective_C +@end diff --git a/ios/Pods/Target Support Files/Pods-SCLAlertView-Objective-C/Pods-SCLAlertView-Objective-C-prefix.pch b/ios/Pods/Target Support Files/Pods-SCLAlertView-Objective-C/Pods-SCLAlertView-Objective-C-prefix.pch new file mode 100644 index 000000000..95cf11d9f --- /dev/null +++ b/ios/Pods/Target Support Files/Pods-SCLAlertView-Objective-C/Pods-SCLAlertView-Objective-C-prefix.pch @@ -0,0 +1,5 @@ +#ifdef __OBJC__ +#import +#endif + +#import "Pods-environment.h" diff --git a/ios/Pods/Target Support Files/Pods-SCLAlertView-Objective-C/Pods-SCLAlertView-Objective-C.xcconfig b/ios/Pods/Target Support Files/Pods-SCLAlertView-Objective-C/Pods-SCLAlertView-Objective-C.xcconfig new file mode 100644 index 000000000..e69de29bb diff --git a/ios/Pods/Target Support Files/Pods-SDWebImage/Pods-SDWebImage-Private.xcconfig b/ios/Pods/Target Support Files/Pods-SDWebImage/Pods-SDWebImage-Private.xcconfig new file mode 100644 index 000000000..2fbd1b6da --- /dev/null +++ b/ios/Pods/Target Support Files/Pods-SDWebImage/Pods-SDWebImage-Private.xcconfig @@ -0,0 +1,5 @@ +#include "Pods-SDWebImage.xcconfig" +GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1 +HEADER_SEARCH_PATHS = "${PODS_ROOT}/Headers/Build" "${PODS_ROOT}/Headers/Build/SDWebImage" "${PODS_ROOT}/Headers/Public" "${PODS_ROOT}/Headers/Public/AFNetworking" "${PODS_ROOT}/Headers/Public/DACircularProgress" "${PODS_ROOT}/Headers/Public/FMDB" "${PODS_ROOT}/Headers/Public/HPGrowingTextView" "${PODS_ROOT}/Headers/Public/MBProgressHUD" "${PODS_ROOT}/Headers/Public/MWPhotoBrowser" "${PODS_ROOT}/Headers/Public/PSTCollectionView" "${PODS_ROOT}/Headers/Public/ProtocolBuffers" "${PODS_ROOT}/Headers/Public/ProtocolBuffers/ProtocolBuffers" "${PODS_ROOT}/Headers/Public/SCLAlertView-Objective-C" "${PODS_ROOT}/Headers/Public/SDWebImage" "${PODS_ROOT}/Headers/Public/leveldb-library" "${PODS_ROOT}/Headers/Public/leveldb-library/leveldb" +OTHER_LDFLAGS = ${PODS_SDWEBIMAGE_OTHER_LDFLAGS} -ObjC +PODS_ROOT = ${SRCROOT} \ No newline at end of file diff --git a/ios/Pods/Target Support Files/Pods-SDWebImage/Pods-SDWebImage-dummy.m b/ios/Pods/Target Support Files/Pods-SDWebImage/Pods-SDWebImage-dummy.m new file mode 100644 index 000000000..1e978bb52 --- /dev/null +++ b/ios/Pods/Target Support Files/Pods-SDWebImage/Pods-SDWebImage-dummy.m @@ -0,0 +1,5 @@ +#import +@interface PodsDummy_Pods_SDWebImage : NSObject +@end +@implementation PodsDummy_Pods_SDWebImage +@end diff --git a/ios/Pods/Target Support Files/Pods-SDWebImage/Pods-SDWebImage-prefix.pch b/ios/Pods/Target Support Files/Pods-SDWebImage/Pods-SDWebImage-prefix.pch new file mode 100644 index 000000000..95cf11d9f --- /dev/null +++ b/ios/Pods/Target Support Files/Pods-SDWebImage/Pods-SDWebImage-prefix.pch @@ -0,0 +1,5 @@ +#ifdef __OBJC__ +#import +#endif + +#import "Pods-environment.h" diff --git a/ios/Pods/Target Support Files/Pods-SDWebImage/Pods-SDWebImage.xcconfig b/ios/Pods/Target Support Files/Pods-SDWebImage/Pods-SDWebImage.xcconfig new file mode 100644 index 000000000..b82befe9b --- /dev/null +++ b/ios/Pods/Target Support Files/Pods-SDWebImage/Pods-SDWebImage.xcconfig @@ -0,0 +1 @@ +PODS_SDWEBIMAGE_OTHER_LDFLAGS = -framework "ImageIO" \ No newline at end of file diff --git a/ios/Pods/Target Support Files/Pods-leveldb-library/Pods-leveldb-library-Private.xcconfig b/ios/Pods/Target Support Files/Pods-leveldb-library/Pods-leveldb-library-Private.xcconfig new file mode 100644 index 000000000..476b4b35f --- /dev/null +++ b/ios/Pods/Target Support Files/Pods-leveldb-library/Pods-leveldb-library-Private.xcconfig @@ -0,0 +1,7 @@ +#include "Pods-leveldb-library.xcconfig" +CC = ${PODS_LEVELDB_LIBRARY_CC} +CXX = ${PODS_LEVELDB_LIBRARY_CXX} +GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1 +HEADER_SEARCH_PATHS = "${PODS_ROOT}/Headers/Build" "${PODS_ROOT}/Headers/Build/leveldb-library" "${PODS_ROOT}/Headers/Build/leveldb-library/leveldb" "${PODS_ROOT}/Headers/Public" "${PODS_ROOT}/Headers/Public/AFNetworking" "${PODS_ROOT}/Headers/Public/DACircularProgress" "${PODS_ROOT}/Headers/Public/FMDB" "${PODS_ROOT}/Headers/Public/HPGrowingTextView" "${PODS_ROOT}/Headers/Public/MBProgressHUD" "${PODS_ROOT}/Headers/Public/MWPhotoBrowser" "${PODS_ROOT}/Headers/Public/PSTCollectionView" "${PODS_ROOT}/Headers/Public/ProtocolBuffers" "${PODS_ROOT}/Headers/Public/ProtocolBuffers/ProtocolBuffers" "${PODS_ROOT}/Headers/Public/SCLAlertView-Objective-C" "${PODS_ROOT}/Headers/Public/SDWebImage" "${PODS_ROOT}/Headers/Public/leveldb-library" "${PODS_ROOT}/Headers/Public/leveldb-library/leveldb" ${PODS_LEVELDB_LIBRARY_HEADER_SEARCH_PATHS} +OTHER_LDFLAGS = ${PODS_LEVELDB_LIBRARY_OTHER_LDFLAGS} -ObjC +PODS_ROOT = ${SRCROOT} \ No newline at end of file diff --git a/ios/Pods/Target Support Files/Pods-leveldb-library/Pods-leveldb-library-dummy.m b/ios/Pods/Target Support Files/Pods-leveldb-library/Pods-leveldb-library-dummy.m new file mode 100644 index 000000000..89f3c129f --- /dev/null +++ b/ios/Pods/Target Support Files/Pods-leveldb-library/Pods-leveldb-library-dummy.m @@ -0,0 +1,5 @@ +#import +@interface PodsDummy_Pods_leveldb_library : NSObject +@end +@implementation PodsDummy_Pods_leveldb_library +@end diff --git a/ios/Pods/Target Support Files/Pods-leveldb-library/Pods-leveldb-library-prefix.pch b/ios/Pods/Target Support Files/Pods-leveldb-library/Pods-leveldb-library-prefix.pch new file mode 100644 index 000000000..95cf11d9f --- /dev/null +++ b/ios/Pods/Target Support Files/Pods-leveldb-library/Pods-leveldb-library-prefix.pch @@ -0,0 +1,5 @@ +#ifdef __OBJC__ +#import +#endif + +#import "Pods-environment.h" diff --git a/ios/Pods/Target Support Files/Pods-leveldb-library/Pods-leveldb-library.xcconfig b/ios/Pods/Target Support Files/Pods-leveldb-library/Pods-leveldb-library.xcconfig new file mode 100644 index 000000000..dc91818a4 --- /dev/null +++ b/ios/Pods/Target Support Files/Pods-leveldb-library/Pods-leveldb-library.xcconfig @@ -0,0 +1,4 @@ +PODS_LEVELDB_LIBRARY_CC = clang +PODS_LEVELDB_LIBRARY_CXX = clang++ +PODS_LEVELDB_LIBRARY_HEADER_SEARCH_PATHS = "${PODS_ROOT}/leveldb-library/" "${PODS_ROOT}/leveldb-library/include" +PODS_LEVELDB_LIBRARY_OTHER_LDFLAGS = -l"c++" \ No newline at end of file diff --git a/ios/Pods/Target Support Files/Pods/Pods-acknowledgements.markdown b/ios/Pods/Target Support Files/Pods/Pods-acknowledgements.markdown new file mode 100644 index 000000000..20ec991d5 --- /dev/null +++ b/ios/Pods/Target Support Files/Pods/Pods-acknowledgements.markdown @@ -0,0 +1,265 @@ +# Acknowledgements +This application makes use of the following third party libraries: + +## AFNetworking + +Copyright (c) 2013-2014 AFNetworking (http://afnetworking.com/) + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + + +## DACircularProgress + +# License + +## MIT License + +Copyright (c) 2013 Daniel Amitay (http://danielamitay.com) + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + +## FMDB + +If you are using fmdb in your project, I'd love to hear about it. Let me +know at gus@flyingmeat.com. + +In short, this is the MIT License. + +Copyright (c) 2008 Flying Meat Inc. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + +## HPGrowingTextView + +MIT License + +Copyright (c) 2011 Hans Pinckaers + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + +## MBProgressHUD + +Copyright (c) 2013 Matej Bukovinski + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + +## MWPhotoBrowser + +Copyright (c) 2010 Michael Waterfall + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + +## PSTCollectionView + +Copyright (c) 2012-2013 Peter Steinberger + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is furnished +to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + + +## ProtocolBuffers + +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. + +Copyright 2008 Google Inc. + + + +## SCLAlertView-Objective-C + +Copyright (c) 2013-2014 SCLAlertView-Objective-C by Diogo Autilio + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + +## SDWebImage + +Copyright (c) 2009 Olivier Poitrey + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is furnished +to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + + + +## leveldb-library + +Copyright (c) 2011 The LevelDB Authors. All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright +notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above +copyright notice, this list of conditions and the following disclaimer +in the documentation and/or other materials provided with the +distribution. + * Neither the name of Google Inc. nor the names of its +contributors may be used to endorse or promote products derived from +this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +Generated by CocoaPods - http://cocoapods.org diff --git a/ios/Pods/Target Support Files/Pods/Pods-acknowledgements.plist b/ios/Pods/Target Support Files/Pods/Pods-acknowledgements.plist new file mode 100644 index 000000000..d63d9f700 --- /dev/null +++ b/ios/Pods/Target Support Files/Pods/Pods-acknowledgements.plist @@ -0,0 +1,335 @@ + + + + + PreferenceSpecifiers + + + FooterText + This application makes use of the following third party libraries: + Title + Acknowledgements + Type + PSGroupSpecifier + + + FooterText + Copyright (c) 2013-2014 AFNetworking (http://afnetworking.com/) + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + + Title + AFNetworking + Type + PSGroupSpecifier + + + FooterText + # License + +## MIT License + +Copyright (c) 2013 Daniel Amitay (http://danielamitay.com) + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + Title + DACircularProgress + Type + PSGroupSpecifier + + + FooterText + If you are using fmdb in your project, I'd love to hear about it. Let me +know at gus@flyingmeat.com. + +In short, this is the MIT License. + +Copyright (c) 2008 Flying Meat Inc. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + Title + FMDB + Type + PSGroupSpecifier + + + FooterText + MIT License + +Copyright (c) 2011 Hans Pinckaers + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + Title + HPGrowingTextView + Type + PSGroupSpecifier + + + FooterText + Copyright (c) 2013 Matej Bukovinski + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + Title + MBProgressHUD + Type + PSGroupSpecifier + + + FooterText + Copyright (c) 2010 Michael Waterfall <michaelwaterfall@gmail.com> + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + Title + MWPhotoBrowser + Type + PSGroupSpecifier + + + FooterText + Copyright (c) 2012-2013 Peter Steinberger <steipete@gmail.com> + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is furnished +to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + + Title + PSTCollectionView + Type + PSGroupSpecifier + + + FooterText + 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. + +Copyright 2008 Google Inc. + + + Title + ProtocolBuffers + Type + PSGroupSpecifier + + + FooterText + Copyright (c) 2013-2014 SCLAlertView-Objective-C by Diogo Autilio + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + Title + SCLAlertView-Objective-C + Type + PSGroupSpecifier + + + FooterText + Copyright (c) 2009 Olivier Poitrey <rs@dailymotion.com> + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is furnished +to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + + + Title + SDWebImage + Type + PSGroupSpecifier + + + FooterText + Copyright (c) 2011 The LevelDB Authors. All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright +notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above +copyright notice, this list of conditions and the following disclaimer +in the documentation and/or other materials provided with the +distribution. + * Neither the name of Google Inc. nor the names of its +contributors may be used to endorse or promote products derived from +this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + Title + leveldb-library + Type + PSGroupSpecifier + + + FooterText + Generated by CocoaPods - http://cocoapods.org + Title + + Type + PSGroupSpecifier + + + StringsTable + Acknowledgements + Title + Acknowledgements + + diff --git a/ios/Pods/Target Support Files/Pods/Pods-dummy.m b/ios/Pods/Target Support Files/Pods/Pods-dummy.m new file mode 100644 index 000000000..ade64bd1a --- /dev/null +++ b/ios/Pods/Target Support Files/Pods/Pods-dummy.m @@ -0,0 +1,5 @@ +#import +@interface PodsDummy_Pods : NSObject +@end +@implementation PodsDummy_Pods +@end diff --git a/ios/Pods/Target Support Files/Pods/Pods-environment.h b/ios/Pods/Target Support Files/Pods/Pods-environment.h new file mode 100644 index 000000000..39e81a443 --- /dev/null +++ b/ios/Pods/Target Support Files/Pods/Pods-environment.h @@ -0,0 +1,128 @@ + +// To check if a library is compiled with CocoaPods you +// can use the `COCOAPODS` macro definition which is +// defined in the xcconfigs so it is available in +// headers also when they are imported in the client +// project. + + +// AFNetworking +#define COCOAPODS_POD_AVAILABLE_AFNetworking +#define COCOAPODS_VERSION_MAJOR_AFNetworking 2 +#define COCOAPODS_VERSION_MINOR_AFNetworking 3 +#define COCOAPODS_VERSION_PATCH_AFNetworking 1 + +// AFNetworking/NSURLConnection +#define COCOAPODS_POD_AVAILABLE_AFNetworking_NSURLConnection +#define COCOAPODS_VERSION_MAJOR_AFNetworking_NSURLConnection 2 +#define COCOAPODS_VERSION_MINOR_AFNetworking_NSURLConnection 3 +#define COCOAPODS_VERSION_PATCH_AFNetworking_NSURLConnection 1 + +// AFNetworking/NSURLSession +#define COCOAPODS_POD_AVAILABLE_AFNetworking_NSURLSession +#define COCOAPODS_VERSION_MAJOR_AFNetworking_NSURLSession 2 +#define COCOAPODS_VERSION_MINOR_AFNetworking_NSURLSession 3 +#define COCOAPODS_VERSION_PATCH_AFNetworking_NSURLSession 1 + +// AFNetworking/Reachability +#define COCOAPODS_POD_AVAILABLE_AFNetworking_Reachability +#define COCOAPODS_VERSION_MAJOR_AFNetworking_Reachability 2 +#define COCOAPODS_VERSION_MINOR_AFNetworking_Reachability 3 +#define COCOAPODS_VERSION_PATCH_AFNetworking_Reachability 1 + +// AFNetworking/Security +#define COCOAPODS_POD_AVAILABLE_AFNetworking_Security +#define COCOAPODS_VERSION_MAJOR_AFNetworking_Security 2 +#define COCOAPODS_VERSION_MINOR_AFNetworking_Security 3 +#define COCOAPODS_VERSION_PATCH_AFNetworking_Security 1 + +// AFNetworking/Serialization +#define COCOAPODS_POD_AVAILABLE_AFNetworking_Serialization +#define COCOAPODS_VERSION_MAJOR_AFNetworking_Serialization 2 +#define COCOAPODS_VERSION_MINOR_AFNetworking_Serialization 3 +#define COCOAPODS_VERSION_PATCH_AFNetworking_Serialization 1 + +// AFNetworking/UIKit +#define COCOAPODS_POD_AVAILABLE_AFNetworking_UIKit +#define COCOAPODS_VERSION_MAJOR_AFNetworking_UIKit 2 +#define COCOAPODS_VERSION_MINOR_AFNetworking_UIKit 3 +#define COCOAPODS_VERSION_PATCH_AFNetworking_UIKit 1 + +// DACircularProgress +#define COCOAPODS_POD_AVAILABLE_DACircularProgress +#define COCOAPODS_VERSION_MAJOR_DACircularProgress 2 +#define COCOAPODS_VERSION_MINOR_DACircularProgress 2 +#define COCOAPODS_VERSION_PATCH_DACircularProgress 0 + +// FMDB +#define COCOAPODS_POD_AVAILABLE_FMDB +#define COCOAPODS_VERSION_MAJOR_FMDB 2 +#define COCOAPODS_VERSION_MINOR_FMDB 4 +#define COCOAPODS_VERSION_PATCH_FMDB 0 + +// FMDB/common +#define COCOAPODS_POD_AVAILABLE_FMDB_common +#define COCOAPODS_VERSION_MAJOR_FMDB_common 2 +#define COCOAPODS_VERSION_MINOR_FMDB_common 4 +#define COCOAPODS_VERSION_PATCH_FMDB_common 0 + +// FMDB/standard +#define COCOAPODS_POD_AVAILABLE_FMDB_standard +#define COCOAPODS_VERSION_MAJOR_FMDB_standard 2 +#define COCOAPODS_VERSION_MINOR_FMDB_standard 4 +#define COCOAPODS_VERSION_PATCH_FMDB_standard 0 + +// HPGrowingTextView +#define COCOAPODS_POD_AVAILABLE_HPGrowingTextView +#define COCOAPODS_VERSION_MAJOR_HPGrowingTextView 1 +#define COCOAPODS_VERSION_MINOR_HPGrowingTextView 1 +#define COCOAPODS_VERSION_PATCH_HPGrowingTextView 0 + +// MBProgressHUD +#define COCOAPODS_POD_AVAILABLE_MBProgressHUD +#define COCOAPODS_VERSION_MAJOR_MBProgressHUD 0 +#define COCOAPODS_VERSION_MINOR_MBProgressHUD 9 +#define COCOAPODS_VERSION_PATCH_MBProgressHUD 0 + +// MWPhotoBrowser +#define COCOAPODS_POD_AVAILABLE_MWPhotoBrowser +#define COCOAPODS_VERSION_MAJOR_MWPhotoBrowser 1 +#define COCOAPODS_VERSION_MINOR_MWPhotoBrowser 4 +#define COCOAPODS_VERSION_PATCH_MWPhotoBrowser 1 + +// PSTCollectionView +#define COCOAPODS_POD_AVAILABLE_PSTCollectionView +#define COCOAPODS_VERSION_MAJOR_PSTCollectionView 1 +#define COCOAPODS_VERSION_MINOR_PSTCollectionView 2 +#define COCOAPODS_VERSION_PATCH_PSTCollectionView 3 + +// ProtocolBuffers +#define COCOAPODS_POD_AVAILABLE_ProtocolBuffers +#define COCOAPODS_VERSION_MAJOR_ProtocolBuffers 1 +#define COCOAPODS_VERSION_MINOR_ProtocolBuffers 9 +#define COCOAPODS_VERSION_PATCH_ProtocolBuffers 3 + +// SCLAlertView-Objective-C +#define COCOAPODS_POD_AVAILABLE_SCLAlertView_Objective_C +#define COCOAPODS_VERSION_MAJOR_SCLAlertView_Objective_C 0 +#define COCOAPODS_VERSION_MINOR_SCLAlertView_Objective_C 3 +#define COCOAPODS_VERSION_PATCH_SCLAlertView_Objective_C 7 + +// SDWebImage +#define COCOAPODS_POD_AVAILABLE_SDWebImage +#define COCOAPODS_VERSION_MAJOR_SDWebImage 3 +#define COCOAPODS_VERSION_MINOR_SDWebImage 7 +#define COCOAPODS_VERSION_PATCH_SDWebImage 1 + +// SDWebImage/Core +#define COCOAPODS_POD_AVAILABLE_SDWebImage_Core +#define COCOAPODS_VERSION_MAJOR_SDWebImage_Core 3 +#define COCOAPODS_VERSION_MINOR_SDWebImage_Core 7 +#define COCOAPODS_VERSION_PATCH_SDWebImage_Core 1 + +// leveldb-library +#define COCOAPODS_POD_AVAILABLE_leveldb_library +#define COCOAPODS_VERSION_MAJOR_leveldb_library 1 +#define COCOAPODS_VERSION_MINOR_leveldb_library 18 +#define COCOAPODS_VERSION_PATCH_leveldb_library 1 + diff --git a/ios/Pods/Target Support Files/Pods/Pods-resources.sh b/ios/Pods/Target Support Files/Pods/Pods-resources.sh new file mode 100755 index 000000000..71465f620 --- /dev/null +++ b/ios/Pods/Target Support Files/Pods/Pods-resources.sh @@ -0,0 +1,75 @@ +#!/bin/sh +set -e + +mkdir -p "${CONFIGURATION_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}" + +RESOURCES_TO_COPY=${PODS_ROOT}/resources-to-copy-${TARGETNAME}.txt +> "$RESOURCES_TO_COPY" + +install_resource() +{ + case $1 in + *.storyboard) + echo "ibtool --reference-external-strings-file --errors --warnings --notices --output-format human-readable-text --compile ${CONFIGURATION_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename \"$1\" .storyboard`.storyboardc ${PODS_ROOT}/$1 --sdk ${SDKROOT}" + ibtool --reference-external-strings-file --errors --warnings --notices --output-format human-readable-text --compile "${CONFIGURATION_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename \"$1\" .storyboard`.storyboardc" "${PODS_ROOT}/$1" --sdk "${SDKROOT}" + ;; + *.xib) + echo "ibtool --reference-external-strings-file --errors --warnings --notices --output-format human-readable-text --compile ${CONFIGURATION_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename \"$1\" .xib`.nib ${PODS_ROOT}/$1 --sdk ${SDKROOT}" + ibtool --reference-external-strings-file --errors --warnings --notices --output-format human-readable-text --compile "${CONFIGURATION_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename \"$1\" .xib`.nib" "${PODS_ROOT}/$1" --sdk "${SDKROOT}" + ;; + *.framework) + echo "mkdir -p ${CONFIGURATION_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}" + mkdir -p "${CONFIGURATION_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}" + echo "rsync -av ${PODS_ROOT}/$1 ${CONFIGURATION_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}" + rsync -av "${PODS_ROOT}/$1" "${CONFIGURATION_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}" + ;; + *.xcdatamodel) + echo "xcrun momc \"${PODS_ROOT}/$1\" \"${CONFIGURATION_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename "$1"`.mom\"" + xcrun momc "${PODS_ROOT}/$1" "${CONFIGURATION_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename "$1" .xcdatamodel`.mom" + ;; + *.xcdatamodeld) + echo "xcrun momc \"${PODS_ROOT}/$1\" \"${CONFIGURATION_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename "$1" .xcdatamodeld`.momd\"" + xcrun momc "${PODS_ROOT}/$1" "${CONFIGURATION_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename "$1" .xcdatamodeld`.momd" + ;; + *.xcmappingmodel) + echo "xcrun mapc \"${PODS_ROOT}/$1\" \"${CONFIGURATION_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename "$1" .xcmappingmodel`.cdm\"" + xcrun mapc "${PODS_ROOT}/$1" "${CONFIGURATION_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename "$1" .xcmappingmodel`.cdm" + ;; + *.xcassets) + ;; + /*) + echo "$1" + echo "$1" >> "$RESOURCES_TO_COPY" + ;; + *) + echo "${PODS_ROOT}/$1" + echo "${PODS_ROOT}/$1" >> "$RESOURCES_TO_COPY" + ;; + esac +} + install_resource "MWPhotoBrowser/MWPhotoBrowser/MWPhotoBrowser.bundle" + +rsync -avr --copy-links --no-relative --exclude '*/.svn/*' --files-from="$RESOURCES_TO_COPY" / "${CONFIGURATION_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}" +if [[ "${ACTION}" == "install" ]]; then + rsync -avr --copy-links --no-relative --exclude '*/.svn/*' --files-from="$RESOURCES_TO_COPY" / "${INSTALL_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}" +fi +rm -f "$RESOURCES_TO_COPY" + +if [[ -n "${WRAPPER_EXTENSION}" ]] && [ "`xcrun --find actool`" ] && [ `find . -name '*.xcassets' | wc -l` -ne 0 ] +then + case "${TARGETED_DEVICE_FAMILY}" in + 1,2) + TARGET_DEVICE_ARGS="--target-device ipad --target-device iphone" + ;; + 1) + TARGET_DEVICE_ARGS="--target-device iphone" + ;; + 2) + TARGET_DEVICE_ARGS="--target-device ipad" + ;; + *) + TARGET_DEVICE_ARGS="--target-device mac" + ;; + esac + find "${PWD}" -name "*.xcassets" -print0 | xargs -0 actool --output-format human-readable-text --notices --warnings --platform "${PLATFORM_NAME}" --minimum-deployment-target "${IPHONEOS_DEPLOYMENT_TARGET}" ${TARGET_DEVICE_ARGS} --compress-pngs --compile "${BUILT_PRODUCTS_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}" +fi diff --git a/ios/Pods/Target Support Files/Pods/Pods.debug.xcconfig b/ios/Pods/Target Support Files/Pods/Pods.debug.xcconfig new file mode 100644 index 000000000..6592e0320 --- /dev/null +++ b/ios/Pods/Target Support Files/Pods/Pods.debug.xcconfig @@ -0,0 +1,8 @@ +CC = clang +CXX = clang++ +GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1 +HEADER_SEARCH_PATHS = "${PODS_ROOT}/Headers/Public" "${PODS_ROOT}/Headers/Public/AFNetworking" "${PODS_ROOT}/Headers/Public/DACircularProgress" "${PODS_ROOT}/Headers/Public/FMDB" "${PODS_ROOT}/Headers/Public/HPGrowingTextView" "${PODS_ROOT}/Headers/Public/MBProgressHUD" "${PODS_ROOT}/Headers/Public/MWPhotoBrowser" "${PODS_ROOT}/Headers/Public/PSTCollectionView" "${PODS_ROOT}/Headers/Public/ProtocolBuffers" "${PODS_ROOT}/Headers/Public/ProtocolBuffers/ProtocolBuffers" "${PODS_ROOT}/Headers/Public/SCLAlertView-Objective-C" "${PODS_ROOT}/Headers/Public/SDWebImage" "${PODS_ROOT}/Headers/Public/leveldb-library" "${PODS_ROOT}/Headers/Public/leveldb-library/leveldb" "${PODS_ROOT}/leveldb-library/" "${PODS_ROOT}/leveldb-library/include" +OTHER_CFLAGS = $(inherited) -isystem "${PODS_ROOT}/Headers/Public" -isystem "${PODS_ROOT}/Headers/Public/AFNetworking" -isystem "${PODS_ROOT}/Headers/Public/DACircularProgress" -isystem "${PODS_ROOT}/Headers/Public/FMDB" -isystem "${PODS_ROOT}/Headers/Public/HPGrowingTextView" -isystem "${PODS_ROOT}/Headers/Public/MBProgressHUD" -isystem "${PODS_ROOT}/Headers/Public/MWPhotoBrowser" -isystem "${PODS_ROOT}/Headers/Public/PSTCollectionView" -isystem "${PODS_ROOT}/Headers/Public/ProtocolBuffers" -isystem "${PODS_ROOT}/Headers/Public/ProtocolBuffers/ProtocolBuffers" -isystem "${PODS_ROOT}/Headers/Public/SCLAlertView-Objective-C" -isystem "${PODS_ROOT}/Headers/Public/SDWebImage" -isystem "${PODS_ROOT}/Headers/Public/leveldb-library" -isystem "${PODS_ROOT}/Headers/Public/leveldb-library/leveldb" +OTHER_LDFLAGS = -ObjC -l"Pods-AFNetworking" -l"Pods-DACircularProgress" -l"Pods-FMDB" -l"Pods-HPGrowingTextView" -l"Pods-MBProgressHUD" -l"Pods-MWPhotoBrowser" -l"Pods-PSTCollectionView" -l"Pods-ProtocolBuffers" -l"Pods-SCLAlertView-Objective-C" -l"Pods-SDWebImage" -l"Pods-leveldb-library" -l"c++" -l"sqlite3" -framework "AssetsLibrary" -framework "CoreGraphics" -framework "Foundation" -framework "ImageIO" -framework "MapKit" -framework "MessageUI" -framework "MobileCoreServices" -framework "QuartzCore" -framework "Security" -framework "SystemConfiguration" -framework "UIKit" +OTHER_LIBTOOLFLAGS = $(OTHER_LDFLAGS) +PODS_ROOT = ${SRCROOT}/Pods \ No newline at end of file diff --git a/ios/Pods/Target Support Files/Pods/Pods.release.xcconfig b/ios/Pods/Target Support Files/Pods/Pods.release.xcconfig new file mode 100644 index 000000000..6592e0320 --- /dev/null +++ b/ios/Pods/Target Support Files/Pods/Pods.release.xcconfig @@ -0,0 +1,8 @@ +CC = clang +CXX = clang++ +GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1 +HEADER_SEARCH_PATHS = "${PODS_ROOT}/Headers/Public" "${PODS_ROOT}/Headers/Public/AFNetworking" "${PODS_ROOT}/Headers/Public/DACircularProgress" "${PODS_ROOT}/Headers/Public/FMDB" "${PODS_ROOT}/Headers/Public/HPGrowingTextView" "${PODS_ROOT}/Headers/Public/MBProgressHUD" "${PODS_ROOT}/Headers/Public/MWPhotoBrowser" "${PODS_ROOT}/Headers/Public/PSTCollectionView" "${PODS_ROOT}/Headers/Public/ProtocolBuffers" "${PODS_ROOT}/Headers/Public/ProtocolBuffers/ProtocolBuffers" "${PODS_ROOT}/Headers/Public/SCLAlertView-Objective-C" "${PODS_ROOT}/Headers/Public/SDWebImage" "${PODS_ROOT}/Headers/Public/leveldb-library" "${PODS_ROOT}/Headers/Public/leveldb-library/leveldb" "${PODS_ROOT}/leveldb-library/" "${PODS_ROOT}/leveldb-library/include" +OTHER_CFLAGS = $(inherited) -isystem "${PODS_ROOT}/Headers/Public" -isystem "${PODS_ROOT}/Headers/Public/AFNetworking" -isystem "${PODS_ROOT}/Headers/Public/DACircularProgress" -isystem "${PODS_ROOT}/Headers/Public/FMDB" -isystem "${PODS_ROOT}/Headers/Public/HPGrowingTextView" -isystem "${PODS_ROOT}/Headers/Public/MBProgressHUD" -isystem "${PODS_ROOT}/Headers/Public/MWPhotoBrowser" -isystem "${PODS_ROOT}/Headers/Public/PSTCollectionView" -isystem "${PODS_ROOT}/Headers/Public/ProtocolBuffers" -isystem "${PODS_ROOT}/Headers/Public/ProtocolBuffers/ProtocolBuffers" -isystem "${PODS_ROOT}/Headers/Public/SCLAlertView-Objective-C" -isystem "${PODS_ROOT}/Headers/Public/SDWebImage" -isystem "${PODS_ROOT}/Headers/Public/leveldb-library" -isystem "${PODS_ROOT}/Headers/Public/leveldb-library/leveldb" +OTHER_LDFLAGS = -ObjC -l"Pods-AFNetworking" -l"Pods-DACircularProgress" -l"Pods-FMDB" -l"Pods-HPGrowingTextView" -l"Pods-MBProgressHUD" -l"Pods-MWPhotoBrowser" -l"Pods-PSTCollectionView" -l"Pods-ProtocolBuffers" -l"Pods-SCLAlertView-Objective-C" -l"Pods-SDWebImage" -l"Pods-leveldb-library" -l"c++" -l"sqlite3" -framework "AssetsLibrary" -framework "CoreGraphics" -framework "Foundation" -framework "ImageIO" -framework "MapKit" -framework "MessageUI" -framework "MobileCoreServices" -framework "QuartzCore" -framework "Security" -framework "SystemConfiguration" -framework "UIKit" +OTHER_LIBTOOLFLAGS = $(OTHER_LDFLAGS) +PODS_ROOT = ${SRCROOT}/Pods \ No newline at end of file diff --git a/ios/Pods/leveldb-library/LICENSE b/ios/Pods/leveldb-library/LICENSE new file mode 100644 index 000000000..8e80208cd --- /dev/null +++ b/ios/Pods/leveldb-library/LICENSE @@ -0,0 +1,27 @@ +Copyright (c) 2011 The LevelDB Authors. All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright +notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above +copyright notice, this list of conditions and the following disclaimer +in the documentation and/or other materials provided with the +distribution. + * Neither the name of Google Inc. nor the names of its +contributors may be used to endorse or promote products derived from +this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/ios/Pods/leveldb-library/README b/ios/Pods/leveldb-library/README new file mode 100644 index 000000000..3618adeee --- /dev/null +++ b/ios/Pods/leveldb-library/README @@ -0,0 +1,51 @@ +leveldb: A key-value store +Authors: Sanjay Ghemawat (sanjay@google.com) and Jeff Dean (jeff@google.com) + +The code under this directory implements a system for maintaining a +persistent key/value store. + +See doc/index.html for more explanation. +See doc/impl.html for a brief overview of the implementation. + +The public interface is in include/*.h. Callers should not include or +rely on the details of any other header files in this package. Those +internal APIs may be changed without warning. + +Guide to header files: + +include/db.h + Main interface to the DB: Start here + +include/options.h + Control over the behavior of an entire database, and also + control over the behavior of individual reads and writes. + +include/comparator.h + Abstraction for user-specified comparison function. If you want + just bytewise comparison of keys, you can use the default comparator, + but clients can write their own comparator implementations if they + want custom ordering (e.g. to handle different character + encodings, etc.) + +include/iterator.h + Interface for iterating over data. You can get an iterator + from a DB object. + +include/write_batch.h + Interface for atomically applying multiple updates to a database. + +include/slice.h + A simple module for maintaining a pointer and a length into some + other byte array. + +include/status.h + Status is returned from many of the public interfaces and is used + to report success and various kinds of errors. + +include/env.h + Abstraction of the OS environment. A posix implementation of + this interface is in util/env_posix.cc + +include/table.h +include/table_builder.h + Lower-level modules that most clients probably won't use directly diff --git a/ios/Pods/leveldb-library/README.md b/ios/Pods/leveldb-library/README.md new file mode 100644 index 000000000..480affb5c --- /dev/null +++ b/ios/Pods/leveldb-library/README.md @@ -0,0 +1,138 @@ +**LevelDB is a fast key-value storage library written at Google that provides an ordered mapping from string keys to string values.** + +Authors: Sanjay Ghemawat (sanjay@google.com) and Jeff Dean (jeff@google.com) + +# Features + * Keys and values are arbitrary byte arrays. + * Data is stored sorted by key. + * Callers can provide a custom comparison function to override the sort order. + * The basic operations are `Put(key,value)`, `Get(key)`, `Delete(key)`. + * Multiple changes can be made in one atomic batch. + * Users can create a transient snapshot to get a consistent view of data. + * Forward and backward iteration is supported over the data. + * Data is automatically compressed using the [Snappy compression library](http://code.google.com/p/snappy). + * External activity (file system operations etc.) is relayed through a virtual interface so users can customize the operating system interactions. + * [Detailed documentation](http://htmlpreview.github.io/?https://github.com/google/leveldb/blob/master/doc/index.html) about how to use the library is included with the source code. + + +# Limitations + * This is not a SQL database. It does not have a relational data model, it does not support SQL queries, and it has no support for indexes. + * Only a single process (possibly multi-threaded) can access a particular database at a time. + * There is no client-server support builtin to the library. An application that needs such support will have to wrap their own server around the library. + +# Performance + +Here is a performance report (with explanations) from the run of the +included db_bench program. The results are somewhat noisy, but should +be enough to get a ballpark performance estimate. + +## Setup + +We use a database with a million entries. Each entry has a 16 byte +key, and a 100 byte value. Values used by the benchmark compress to +about half their original size. + + LevelDB: version 1.1 + Date: Sun May 1 12:11:26 2011 + CPU: 4 x Intel(R) Core(TM)2 Quad CPU Q6600 @ 2.40GHz + CPUCache: 4096 KB + Keys: 16 bytes each + Values: 100 bytes each (50 bytes after compression) + Entries: 1000000 + Raw Size: 110.6 MB (estimated) + File Size: 62.9 MB (estimated) + +## Write performance + +The "fill" benchmarks create a brand new database, in either +sequential, or random order. The "fillsync" benchmark flushes data +from the operating system to the disk after every operation; the other +write operations leave the data sitting in the operating system buffer +cache for a while. The "overwrite" benchmark does random writes that +update existing keys in the database. + + fillseq : 1.765 micros/op; 62.7 MB/s + fillsync : 268.409 micros/op; 0.4 MB/s (10000 ops) + fillrandom : 2.460 micros/op; 45.0 MB/s + overwrite : 2.380 micros/op; 46.5 MB/s + +Each "op" above corresponds to a write of a single key/value pair. +I.e., a random write benchmark goes at approximately 400,000 writes per second. + +Each "fillsync" operation costs much less (0.3 millisecond) +than a disk seek (typically 10 milliseconds). We suspect that this is +because the hard disk itself is buffering the update in its memory and +responding before the data has been written to the platter. This may +or may not be safe based on whether or not the hard disk has enough +power to save its memory in the event of a power failure. + +## Read performance + +We list the performance of reading sequentially in both the forward +and reverse direction, and also the performance of a random lookup. +Note that the database created by the benchmark is quite small. +Therefore the report characterizes the performance of leveldb when the +working set fits in memory. The cost of reading a piece of data that +is not present in the operating system buffer cache will be dominated +by the one or two disk seeks needed to fetch the data from disk. +Write performance will be mostly unaffected by whether or not the +working set fits in memory. + + readrandom : 16.677 micros/op; (approximately 60,000 reads per second) + readseq : 0.476 micros/op; 232.3 MB/s + readreverse : 0.724 micros/op; 152.9 MB/s + +LevelDB compacts its underlying storage data in the background to +improve read performance. The results listed above were done +immediately after a lot of random writes. The results after +compactions (which are usually triggered automatically) are better. + + readrandom : 11.602 micros/op; (approximately 85,000 reads per second) + readseq : 0.423 micros/op; 261.8 MB/s + readreverse : 0.663 micros/op; 166.9 MB/s + +Some of the high cost of reads comes from repeated decompression of blocks +read from disk. If we supply enough cache to the leveldb so it can hold the +uncompressed blocks in memory, the read performance improves again: + + readrandom : 9.775 micros/op; (approximately 100,000 reads per second before compaction) + readrandom : 5.215 micros/op; (approximately 190,000 reads per second after compaction) + +## Repository contents + +See doc/index.html for more explanation. See doc/impl.html for a brief overview of the implementation. + +The public interface is in include/*.h. Callers should not include or +rely on the details of any other header files in this package. Those +internal APIs may be changed without warning. + +Guide to header files: + +* **include/db.h**: Main interface to the DB: Start here + +* **include/options.h**: Control over the behavior of an entire database, +and also control over the behavior of individual reads and writes. + +* **include/comparator.h**: Abstraction for user-specified comparison function. +If you want just bytewise comparison of keys, you can use the default +comparator, but clients can write their own comparator implementations if they +want custom ordering (e.g. to handle different character encodings, etc.) + +* **include/iterator.h**: Interface for iterating over data. You can get +an iterator from a DB object. + +* **include/write_batch.h**: Interface for atomically applying multiple +updates to a database. + +* **include/slice.h**: A simple module for maintaining a pointer and a +length into some other byte array. + +* **include/status.h**: Status is returned from many of the public interfaces +and is used to report success and various kinds of errors. + +* **include/env.h**: +Abstraction of the OS environment. A posix implementation of this interface is +in util/env_posix.cc + +* **include/table.h, include/table_builder.h**: Lower-level modules that most +clients probably won't use directly diff --git a/ios/Pods/leveldb-library/db/autocompact_test.cc b/ios/Pods/leveldb-library/db/autocompact_test.cc new file mode 100644 index 000000000..d20a2362c --- /dev/null +++ b/ios/Pods/leveldb-library/db/autocompact_test.cc @@ -0,0 +1,118 @@ +// Copyright (c) 2013 The LevelDB Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. See the AUTHORS file for names of contributors. + +#include "leveldb/db.h" +#include "db/db_impl.h" +#include "leveldb/cache.h" +#include "util/testharness.h" +#include "util/testutil.h" + +namespace leveldb { + +class AutoCompactTest { + public: + std::string dbname_; + Cache* tiny_cache_; + Options options_; + DB* db_; + + AutoCompactTest() { + dbname_ = test::TmpDir() + "/autocompact_test"; + tiny_cache_ = NewLRUCache(100); + options_.block_cache = tiny_cache_; + DestroyDB(dbname_, options_); + options_.create_if_missing = true; + options_.compression = kNoCompression; + ASSERT_OK(DB::Open(options_, dbname_, &db_)); + } + + ~AutoCompactTest() { + delete db_; + DestroyDB(dbname_, Options()); + delete tiny_cache_; + } + + std::string Key(int i) { + char buf[100]; + snprintf(buf, sizeof(buf), "key%06d", i); + return std::string(buf); + } + + uint64_t Size(const Slice& start, const Slice& limit) { + Range r(start, limit); + uint64_t size; + db_->GetApproximateSizes(&r, 1, &size); + return size; + } + + void DoReads(int n); +}; + +static const int kValueSize = 200 * 1024; +static const int kTotalSize = 100 * 1024 * 1024; +static const int kCount = kTotalSize / kValueSize; + +// Read through the first n keys repeatedly and check that they get +// compacted (verified by checking the size of the key space). +void AutoCompactTest::DoReads(int n) { + std::string value(kValueSize, 'x'); + DBImpl* dbi = reinterpret_cast(db_); + + // Fill database + for (int i = 0; i < kCount; i++) { + ASSERT_OK(db_->Put(WriteOptions(), Key(i), value)); + } + ASSERT_OK(dbi->TEST_CompactMemTable()); + + // Delete everything + for (int i = 0; i < kCount; i++) { + ASSERT_OK(db_->Delete(WriteOptions(), Key(i))); + } + ASSERT_OK(dbi->TEST_CompactMemTable()); + + // Get initial measurement of the space we will be reading. + const int64_t initial_size = Size(Key(0), Key(n)); + const int64_t initial_other_size = Size(Key(n), Key(kCount)); + + // Read until size drops significantly. + std::string limit_key = Key(n); + for (int read = 0; true; read++) { + ASSERT_LT(read, 100) << "Taking too long to compact"; + Iterator* iter = db_->NewIterator(ReadOptions()); + for (iter->SeekToFirst(); + iter->Valid() && iter->key().ToString() < limit_key; + iter->Next()) { + // Drop data + } + delete iter; + // Wait a little bit to allow any triggered compactions to complete. + Env::Default()->SleepForMicroseconds(1000000); + uint64_t size = Size(Key(0), Key(n)); + fprintf(stderr, "iter %3d => %7.3f MB [other %7.3f MB]\n", + read+1, size/1048576.0, Size(Key(n), Key(kCount))/1048576.0); + if (size <= initial_size/10) { + break; + } + } + + // Verify that the size of the key space not touched by the reads + // is pretty much unchanged. + const int64_t final_other_size = Size(Key(n), Key(kCount)); + ASSERT_LE(final_other_size, initial_other_size + 1048576); + ASSERT_GE(final_other_size, initial_other_size/5 - 1048576); +} + +TEST(AutoCompactTest, ReadAll) { + DoReads(kCount); +} + +TEST(AutoCompactTest, ReadHalf) { + DoReads(kCount/2); +} + +} // namespace leveldb + +int main(int argc, char** argv) { + return leveldb::test::RunAllTests(); +} diff --git a/ios/Pods/leveldb-library/db/builder.cc b/ios/Pods/leveldb-library/db/builder.cc new file mode 100644 index 000000000..f41988219 --- /dev/null +++ b/ios/Pods/leveldb-library/db/builder.cc @@ -0,0 +1,88 @@ +// Copyright (c) 2011 The LevelDB Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. See the AUTHORS file for names of contributors. + +#include "db/builder.h" + +#include "db/filename.h" +#include "db/dbformat.h" +#include "db/table_cache.h" +#include "db/version_edit.h" +#include "leveldb/db.h" +#include "leveldb/env.h" +#include "leveldb/iterator.h" + +namespace leveldb { + +Status BuildTable(const std::string& dbname, + Env* env, + const Options& options, + TableCache* table_cache, + Iterator* iter, + FileMetaData* meta) { + Status s; + meta->file_size = 0; + iter->SeekToFirst(); + + std::string fname = TableFileName(dbname, meta->number); + if (iter->Valid()) { + WritableFile* file; + s = env->NewWritableFile(fname, &file); + if (!s.ok()) { + return s; + } + + TableBuilder* builder = new TableBuilder(options, file); + meta->smallest.DecodeFrom(iter->key()); + for (; iter->Valid(); iter->Next()) { + Slice key = iter->key(); + meta->largest.DecodeFrom(key); + builder->Add(key, iter->value()); + } + + // Finish and check for builder errors + if (s.ok()) { + s = builder->Finish(); + if (s.ok()) { + meta->file_size = builder->FileSize(); + assert(meta->file_size > 0); + } + } else { + builder->Abandon(); + } + delete builder; + + // Finish and check for file errors + if (s.ok()) { + s = file->Sync(); + } + if (s.ok()) { + s = file->Close(); + } + delete file; + file = NULL; + + if (s.ok()) { + // Verify that the table is usable + Iterator* it = table_cache->NewIterator(ReadOptions(), + meta->number, + meta->file_size); + s = it->status(); + delete it; + } + } + + // Check for input iterator errors + if (!iter->status().ok()) { + s = iter->status(); + } + + if (s.ok() && meta->file_size > 0) { + // Keep it + } else { + env->DeleteFile(fname); + } + return s; +} + +} // namespace leveldb diff --git a/ios/Pods/leveldb-library/db/builder.h b/ios/Pods/leveldb-library/db/builder.h new file mode 100644 index 000000000..62431fcf4 --- /dev/null +++ b/ios/Pods/leveldb-library/db/builder.h @@ -0,0 +1,34 @@ +// Copyright (c) 2011 The LevelDB Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. See the AUTHORS file for names of contributors. + +#ifndef STORAGE_LEVELDB_DB_BUILDER_H_ +#define STORAGE_LEVELDB_DB_BUILDER_H_ + +#include "leveldb/status.h" + +namespace leveldb { + +struct Options; +struct FileMetaData; + +class Env; +class Iterator; +class TableCache; +class VersionEdit; + +// Build a Table file from the contents of *iter. The generated file +// will be named according to meta->number. On success, the rest of +// *meta will be filled with metadata about the generated table. +// If no data is present in *iter, meta->file_size will be set to +// zero, and no Table file will be produced. +extern Status BuildTable(const std::string& dbname, + Env* env, + const Options& options, + TableCache* table_cache, + Iterator* iter, + FileMetaData* meta); + +} // namespace leveldb + +#endif // STORAGE_LEVELDB_DB_BUILDER_H_ diff --git a/ios/Pods/leveldb-library/db/c.cc b/ios/Pods/leveldb-library/db/c.cc new file mode 100644 index 000000000..08ff0ad90 --- /dev/null +++ b/ios/Pods/leveldb-library/db/c.cc @@ -0,0 +1,595 @@ +// Copyright (c) 2011 The LevelDB Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. See the AUTHORS file for names of contributors. + +#include "leveldb/c.h" + +#include +#include +#include "leveldb/cache.h" +#include "leveldb/comparator.h" +#include "leveldb/db.h" +#include "leveldb/env.h" +#include "leveldb/filter_policy.h" +#include "leveldb/iterator.h" +#include "leveldb/options.h" +#include "leveldb/status.h" +#include "leveldb/write_batch.h" + +using leveldb::Cache; +using leveldb::Comparator; +using leveldb::CompressionType; +using leveldb::DB; +using leveldb::Env; +using leveldb::FileLock; +using leveldb::FilterPolicy; +using leveldb::Iterator; +using leveldb::kMajorVersion; +using leveldb::kMinorVersion; +using leveldb::Logger; +using leveldb::NewBloomFilterPolicy; +using leveldb::NewLRUCache; +using leveldb::Options; +using leveldb::RandomAccessFile; +using leveldb::Range; +using leveldb::ReadOptions; +using leveldb::SequentialFile; +using leveldb::Slice; +using leveldb::Snapshot; +using leveldb::Status; +using leveldb::WritableFile; +using leveldb::WriteBatch; +using leveldb::WriteOptions; + +extern "C" { + +struct leveldb_t { DB* rep; }; +struct leveldb_iterator_t { Iterator* rep; }; +struct leveldb_writebatch_t { WriteBatch rep; }; +struct leveldb_snapshot_t { const Snapshot* rep; }; +struct leveldb_readoptions_t { ReadOptions rep; }; +struct leveldb_writeoptions_t { WriteOptions rep; }; +struct leveldb_options_t { Options rep; }; +struct leveldb_cache_t { Cache* rep; }; +struct leveldb_seqfile_t { SequentialFile* rep; }; +struct leveldb_randomfile_t { RandomAccessFile* rep; }; +struct leveldb_writablefile_t { WritableFile* rep; }; +struct leveldb_logger_t { Logger* rep; }; +struct leveldb_filelock_t { FileLock* rep; }; + +struct leveldb_comparator_t : public Comparator { + void* state_; + void (*destructor_)(void*); + int (*compare_)( + void*, + const char* a, size_t alen, + const char* b, size_t blen); + const char* (*name_)(void*); + + virtual ~leveldb_comparator_t() { + (*destructor_)(state_); + } + + virtual int Compare(const Slice& a, const Slice& b) const { + return (*compare_)(state_, a.data(), a.size(), b.data(), b.size()); + } + + virtual const char* Name() const { + return (*name_)(state_); + } + + // No-ops since the C binding does not support key shortening methods. + virtual void FindShortestSeparator(std::string*, const Slice&) const { } + virtual void FindShortSuccessor(std::string* key) const { } +}; + +struct leveldb_filterpolicy_t : public FilterPolicy { + void* state_; + void (*destructor_)(void*); + const char* (*name_)(void*); + char* (*create_)( + void*, + const char* const* key_array, const size_t* key_length_array, + int num_keys, + size_t* filter_length); + unsigned char (*key_match_)( + void*, + const char* key, size_t length, + const char* filter, size_t filter_length); + + virtual ~leveldb_filterpolicy_t() { + (*destructor_)(state_); + } + + virtual const char* Name() const { + return (*name_)(state_); + } + + virtual void CreateFilter(const Slice* keys, int n, std::string* dst) const { + std::vector key_pointers(n); + std::vector key_sizes(n); + for (int i = 0; i < n; i++) { + key_pointers[i] = keys[i].data(); + key_sizes[i] = keys[i].size(); + } + size_t len; + char* filter = (*create_)(state_, &key_pointers[0], &key_sizes[0], n, &len); + dst->append(filter, len); + free(filter); + } + + virtual bool KeyMayMatch(const Slice& key, const Slice& filter) const { + return (*key_match_)(state_, key.data(), key.size(), + filter.data(), filter.size()); + } +}; + +struct leveldb_env_t { + Env* rep; + bool is_default; +}; + +static bool SaveError(char** errptr, const Status& s) { + assert(errptr != NULL); + if (s.ok()) { + return false; + } else if (*errptr == NULL) { + *errptr = strdup(s.ToString().c_str()); + } else { + // TODO(sanjay): Merge with existing error? + free(*errptr); + *errptr = strdup(s.ToString().c_str()); + } + return true; +} + +static char* CopyString(const std::string& str) { + char* result = reinterpret_cast(malloc(sizeof(char) * str.size())); + memcpy(result, str.data(), sizeof(char) * str.size()); + return result; +} + +leveldb_t* leveldb_open( + const leveldb_options_t* options, + const char* name, + char** errptr) { + DB* db; + if (SaveError(errptr, DB::Open(options->rep, std::string(name), &db))) { + return NULL; + } + leveldb_t* result = new leveldb_t; + result->rep = db; + return result; +} + +void leveldb_close(leveldb_t* db) { + delete db->rep; + delete db; +} + +void leveldb_put( + leveldb_t* db, + const leveldb_writeoptions_t* options, + const char* key, size_t keylen, + const char* val, size_t vallen, + char** errptr) { + SaveError(errptr, + db->rep->Put(options->rep, Slice(key, keylen), Slice(val, vallen))); +} + +void leveldb_delete( + leveldb_t* db, + const leveldb_writeoptions_t* options, + const char* key, size_t keylen, + char** errptr) { + SaveError(errptr, db->rep->Delete(options->rep, Slice(key, keylen))); +} + + +void leveldb_write( + leveldb_t* db, + const leveldb_writeoptions_t* options, + leveldb_writebatch_t* batch, + char** errptr) { + SaveError(errptr, db->rep->Write(options->rep, &batch->rep)); +} + +char* leveldb_get( + leveldb_t* db, + const leveldb_readoptions_t* options, + const char* key, size_t keylen, + size_t* vallen, + char** errptr) { + char* result = NULL; + std::string tmp; + Status s = db->rep->Get(options->rep, Slice(key, keylen), &tmp); + if (s.ok()) { + *vallen = tmp.size(); + result = CopyString(tmp); + } else { + *vallen = 0; + if (!s.IsNotFound()) { + SaveError(errptr, s); + } + } + return result; +} + +leveldb_iterator_t* leveldb_create_iterator( + leveldb_t* db, + const leveldb_readoptions_t* options) { + leveldb_iterator_t* result = new leveldb_iterator_t; + result->rep = db->rep->NewIterator(options->rep); + return result; +} + +const leveldb_snapshot_t* leveldb_create_snapshot( + leveldb_t* db) { + leveldb_snapshot_t* result = new leveldb_snapshot_t; + result->rep = db->rep->GetSnapshot(); + return result; +} + +void leveldb_release_snapshot( + leveldb_t* db, + const leveldb_snapshot_t* snapshot) { + db->rep->ReleaseSnapshot(snapshot->rep); + delete snapshot; +} + +char* leveldb_property_value( + leveldb_t* db, + const char* propname) { + std::string tmp; + if (db->rep->GetProperty(Slice(propname), &tmp)) { + // We use strdup() since we expect human readable output. + return strdup(tmp.c_str()); + } else { + return NULL; + } +} + +void leveldb_approximate_sizes( + leveldb_t* db, + int num_ranges, + const char* const* range_start_key, const size_t* range_start_key_len, + const char* const* range_limit_key, const size_t* range_limit_key_len, + uint64_t* sizes) { + Range* ranges = new Range[num_ranges]; + for (int i = 0; i < num_ranges; i++) { + ranges[i].start = Slice(range_start_key[i], range_start_key_len[i]); + ranges[i].limit = Slice(range_limit_key[i], range_limit_key_len[i]); + } + db->rep->GetApproximateSizes(ranges, num_ranges, sizes); + delete[] ranges; +} + +void leveldb_compact_range( + leveldb_t* db, + const char* start_key, size_t start_key_len, + const char* limit_key, size_t limit_key_len) { + Slice a, b; + db->rep->CompactRange( + // Pass NULL Slice if corresponding "const char*" is NULL + (start_key ? (a = Slice(start_key, start_key_len), &a) : NULL), + (limit_key ? (b = Slice(limit_key, limit_key_len), &b) : NULL)); +} + +void leveldb_destroy_db( + const leveldb_options_t* options, + const char* name, + char** errptr) { + SaveError(errptr, DestroyDB(name, options->rep)); +} + +void leveldb_repair_db( + const leveldb_options_t* options, + const char* name, + char** errptr) { + SaveError(errptr, RepairDB(name, options->rep)); +} + +void leveldb_iter_destroy(leveldb_iterator_t* iter) { + delete iter->rep; + delete iter; +} + +unsigned char leveldb_iter_valid(const leveldb_iterator_t* iter) { + return iter->rep->Valid(); +} + +void leveldb_iter_seek_to_first(leveldb_iterator_t* iter) { + iter->rep->SeekToFirst(); +} + +void leveldb_iter_seek_to_last(leveldb_iterator_t* iter) { + iter->rep->SeekToLast(); +} + +void leveldb_iter_seek(leveldb_iterator_t* iter, const char* k, size_t klen) { + iter->rep->Seek(Slice(k, klen)); +} + +void leveldb_iter_next(leveldb_iterator_t* iter) { + iter->rep->Next(); +} + +void leveldb_iter_prev(leveldb_iterator_t* iter) { + iter->rep->Prev(); +} + +const char* leveldb_iter_key(const leveldb_iterator_t* iter, size_t* klen) { + Slice s = iter->rep->key(); + *klen = s.size(); + return s.data(); +} + +const char* leveldb_iter_value(const leveldb_iterator_t* iter, size_t* vlen) { + Slice s = iter->rep->value(); + *vlen = s.size(); + return s.data(); +} + +void leveldb_iter_get_error(const leveldb_iterator_t* iter, char** errptr) { + SaveError(errptr, iter->rep->status()); +} + +leveldb_writebatch_t* leveldb_writebatch_create() { + return new leveldb_writebatch_t; +} + +void leveldb_writebatch_destroy(leveldb_writebatch_t* b) { + delete b; +} + +void leveldb_writebatch_clear(leveldb_writebatch_t* b) { + b->rep.Clear(); +} + +void leveldb_writebatch_put( + leveldb_writebatch_t* b, + const char* key, size_t klen, + const char* val, size_t vlen) { + b->rep.Put(Slice(key, klen), Slice(val, vlen)); +} + +void leveldb_writebatch_delete( + leveldb_writebatch_t* b, + const char* key, size_t klen) { + b->rep.Delete(Slice(key, klen)); +} + +void leveldb_writebatch_iterate( + leveldb_writebatch_t* b, + void* state, + void (*put)(void*, const char* k, size_t klen, const char* v, size_t vlen), + void (*deleted)(void*, const char* k, size_t klen)) { + class H : public WriteBatch::Handler { + public: + void* state_; + void (*put_)(void*, const char* k, size_t klen, const char* v, size_t vlen); + void (*deleted_)(void*, const char* k, size_t klen); + virtual void Put(const Slice& key, const Slice& value) { + (*put_)(state_, key.data(), key.size(), value.data(), value.size()); + } + virtual void Delete(const Slice& key) { + (*deleted_)(state_, key.data(), key.size()); + } + }; + H handler; + handler.state_ = state; + handler.put_ = put; + handler.deleted_ = deleted; + b->rep.Iterate(&handler); +} + +leveldb_options_t* leveldb_options_create() { + return new leveldb_options_t; +} + +void leveldb_options_destroy(leveldb_options_t* options) { + delete options; +} + +void leveldb_options_set_comparator( + leveldb_options_t* opt, + leveldb_comparator_t* cmp) { + opt->rep.comparator = cmp; +} + +void leveldb_options_set_filter_policy( + leveldb_options_t* opt, + leveldb_filterpolicy_t* policy) { + opt->rep.filter_policy = policy; +} + +void leveldb_options_set_create_if_missing( + leveldb_options_t* opt, unsigned char v) { + opt->rep.create_if_missing = v; +} + +void leveldb_options_set_error_if_exists( + leveldb_options_t* opt, unsigned char v) { + opt->rep.error_if_exists = v; +} + +void leveldb_options_set_paranoid_checks( + leveldb_options_t* opt, unsigned char v) { + opt->rep.paranoid_checks = v; +} + +void leveldb_options_set_env(leveldb_options_t* opt, leveldb_env_t* env) { + opt->rep.env = (env ? env->rep : NULL); +} + +void leveldb_options_set_info_log(leveldb_options_t* opt, leveldb_logger_t* l) { + opt->rep.info_log = (l ? l->rep : NULL); +} + +void leveldb_options_set_write_buffer_size(leveldb_options_t* opt, size_t s) { + opt->rep.write_buffer_size = s; +} + +void leveldb_options_set_max_open_files(leveldb_options_t* opt, int n) { + opt->rep.max_open_files = n; +} + +void leveldb_options_set_cache(leveldb_options_t* opt, leveldb_cache_t* c) { + opt->rep.block_cache = c->rep; +} + +void leveldb_options_set_block_size(leveldb_options_t* opt, size_t s) { + opt->rep.block_size = s; +} + +void leveldb_options_set_block_restart_interval(leveldb_options_t* opt, int n) { + opt->rep.block_restart_interval = n; +} + +void leveldb_options_set_compression(leveldb_options_t* opt, int t) { + opt->rep.compression = static_cast(t); +} + +leveldb_comparator_t* leveldb_comparator_create( + void* state, + void (*destructor)(void*), + int (*compare)( + void*, + const char* a, size_t alen, + const char* b, size_t blen), + const char* (*name)(void*)) { + leveldb_comparator_t* result = new leveldb_comparator_t; + result->state_ = state; + result->destructor_ = destructor; + result->compare_ = compare; + result->name_ = name; + return result; +} + +void leveldb_comparator_destroy(leveldb_comparator_t* cmp) { + delete cmp; +} + +leveldb_filterpolicy_t* leveldb_filterpolicy_create( + void* state, + void (*destructor)(void*), + char* (*create_filter)( + void*, + const char* const* key_array, const size_t* key_length_array, + int num_keys, + size_t* filter_length), + unsigned char (*key_may_match)( + void*, + const char* key, size_t length, + const char* filter, size_t filter_length), + const char* (*name)(void*)) { + leveldb_filterpolicy_t* result = new leveldb_filterpolicy_t; + result->state_ = state; + result->destructor_ = destructor; + result->create_ = create_filter; + result->key_match_ = key_may_match; + result->name_ = name; + return result; +} + +void leveldb_filterpolicy_destroy(leveldb_filterpolicy_t* filter) { + delete filter; +} + +leveldb_filterpolicy_t* leveldb_filterpolicy_create_bloom(int bits_per_key) { + // Make a leveldb_filterpolicy_t, but override all of its methods so + // they delegate to a NewBloomFilterPolicy() instead of user + // supplied C functions. + struct Wrapper : public leveldb_filterpolicy_t { + const FilterPolicy* rep_; + ~Wrapper() { delete rep_; } + const char* Name() const { return rep_->Name(); } + void CreateFilter(const Slice* keys, int n, std::string* dst) const { + return rep_->CreateFilter(keys, n, dst); + } + bool KeyMayMatch(const Slice& key, const Slice& filter) const { + return rep_->KeyMayMatch(key, filter); + } + static void DoNothing(void*) { } + }; + Wrapper* wrapper = new Wrapper; + wrapper->rep_ = NewBloomFilterPolicy(bits_per_key); + wrapper->state_ = NULL; + wrapper->destructor_ = &Wrapper::DoNothing; + return wrapper; +} + +leveldb_readoptions_t* leveldb_readoptions_create() { + return new leveldb_readoptions_t; +} + +void leveldb_readoptions_destroy(leveldb_readoptions_t* opt) { + delete opt; +} + +void leveldb_readoptions_set_verify_checksums( + leveldb_readoptions_t* opt, + unsigned char v) { + opt->rep.verify_checksums = v; +} + +void leveldb_readoptions_set_fill_cache( + leveldb_readoptions_t* opt, unsigned char v) { + opt->rep.fill_cache = v; +} + +void leveldb_readoptions_set_snapshot( + leveldb_readoptions_t* opt, + const leveldb_snapshot_t* snap) { + opt->rep.snapshot = (snap ? snap->rep : NULL); +} + +leveldb_writeoptions_t* leveldb_writeoptions_create() { + return new leveldb_writeoptions_t; +} + +void leveldb_writeoptions_destroy(leveldb_writeoptions_t* opt) { + delete opt; +} + +void leveldb_writeoptions_set_sync( + leveldb_writeoptions_t* opt, unsigned char v) { + opt->rep.sync = v; +} + +leveldb_cache_t* leveldb_cache_create_lru(size_t capacity) { + leveldb_cache_t* c = new leveldb_cache_t; + c->rep = NewLRUCache(capacity); + return c; +} + +void leveldb_cache_destroy(leveldb_cache_t* cache) { + delete cache->rep; + delete cache; +} + +leveldb_env_t* leveldb_create_default_env() { + leveldb_env_t* result = new leveldb_env_t; + result->rep = Env::Default(); + result->is_default = true; + return result; +} + +void leveldb_env_destroy(leveldb_env_t* env) { + if (!env->is_default) delete env->rep; + delete env; +} + +void leveldb_free(void* ptr) { + free(ptr); +} + +int leveldb_major_version() { + return kMajorVersion; +} + +int leveldb_minor_version() { + return kMinorVersion; +} + +} // end extern "C" diff --git a/ios/Pods/leveldb-library/db/c_test.c b/ios/Pods/leveldb-library/db/c_test.c new file mode 100644 index 000000000..7cd5ee020 --- /dev/null +++ b/ios/Pods/leveldb-library/db/c_test.c @@ -0,0 +1,390 @@ +/* Copyright (c) 2011 The LevelDB Authors. All rights reserved. + Use of this source code is governed by a BSD-style license that can be + found in the LICENSE file. See the AUTHORS file for names of contributors. */ + +#include "leveldb/c.h" + +#include +#include +#include +#include +#include +#include + +const char* phase = ""; +static char dbname[200]; + +static void StartPhase(const char* name) { + fprintf(stderr, "=== Test %s\n", name); + phase = name; +} + +static const char* GetTempDir(void) { + const char* ret = getenv("TEST_TMPDIR"); + if (ret == NULL || ret[0] == '\0') + ret = "/tmp"; + return ret; +} + +#define CheckNoError(err) \ + if ((err) != NULL) { \ + fprintf(stderr, "%s:%d: %s: %s\n", __FILE__, __LINE__, phase, (err)); \ + abort(); \ + } + +#define CheckCondition(cond) \ + if (!(cond)) { \ + fprintf(stderr, "%s:%d: %s: %s\n", __FILE__, __LINE__, phase, #cond); \ + abort(); \ + } + +static void CheckEqual(const char* expected, const char* v, size_t n) { + if (expected == NULL && v == NULL) { + // ok + } else if (expected != NULL && v != NULL && n == strlen(expected) && + memcmp(expected, v, n) == 0) { + // ok + return; + } else { + fprintf(stderr, "%s: expected '%s', got '%s'\n", + phase, + (expected ? expected : "(null)"), + (v ? v : "(null")); + abort(); + } +} + +static void Free(char** ptr) { + if (*ptr) { + free(*ptr); + *ptr = NULL; + } +} + +static void CheckGet( + leveldb_t* db, + const leveldb_readoptions_t* options, + const char* key, + const char* expected) { + char* err = NULL; + size_t val_len; + char* val; + val = leveldb_get(db, options, key, strlen(key), &val_len, &err); + CheckNoError(err); + CheckEqual(expected, val, val_len); + Free(&val); +} + +static void CheckIter(leveldb_iterator_t* iter, + const char* key, const char* val) { + size_t len; + const char* str; + str = leveldb_iter_key(iter, &len); + CheckEqual(key, str, len); + str = leveldb_iter_value(iter, &len); + CheckEqual(val, str, len); +} + +// Callback from leveldb_writebatch_iterate() +static void CheckPut(void* ptr, + const char* k, size_t klen, + const char* v, size_t vlen) { + int* state = (int*) ptr; + CheckCondition(*state < 2); + switch (*state) { + case 0: + CheckEqual("bar", k, klen); + CheckEqual("b", v, vlen); + break; + case 1: + CheckEqual("box", k, klen); + CheckEqual("c", v, vlen); + break; + } + (*state)++; +} + +// Callback from leveldb_writebatch_iterate() +static void CheckDel(void* ptr, const char* k, size_t klen) { + int* state = (int*) ptr; + CheckCondition(*state == 2); + CheckEqual("bar", k, klen); + (*state)++; +} + +static void CmpDestroy(void* arg) { } + +static int CmpCompare(void* arg, const char* a, size_t alen, + const char* b, size_t blen) { + int n = (alen < blen) ? alen : blen; + int r = memcmp(a, b, n); + if (r == 0) { + if (alen < blen) r = -1; + else if (alen > blen) r = +1; + } + return r; +} + +static const char* CmpName(void* arg) { + return "foo"; +} + +// Custom filter policy +static unsigned char fake_filter_result = 1; +static void FilterDestroy(void* arg) { } +static const char* FilterName(void* arg) { + return "TestFilter"; +} +static char* FilterCreate( + void* arg, + const char* const* key_array, const size_t* key_length_array, + int num_keys, + size_t* filter_length) { + *filter_length = 4; + char* result = malloc(4); + memcpy(result, "fake", 4); + return result; +} +unsigned char FilterKeyMatch( + void* arg, + const char* key, size_t length, + const char* filter, size_t filter_length) { + CheckCondition(filter_length == 4); + CheckCondition(memcmp(filter, "fake", 4) == 0); + return fake_filter_result; +} + +int main(int argc, char** argv) { + leveldb_t* db; + leveldb_comparator_t* cmp; + leveldb_cache_t* cache; + leveldb_env_t* env; + leveldb_options_t* options; + leveldb_readoptions_t* roptions; + leveldb_writeoptions_t* woptions; + char* err = NULL; + int run = -1; + + CheckCondition(leveldb_major_version() >= 1); + CheckCondition(leveldb_minor_version() >= 1); + + snprintf(dbname, sizeof(dbname), + "%s/leveldb_c_test-%d", + GetTempDir(), + ((int) geteuid())); + + StartPhase("create_objects"); + cmp = leveldb_comparator_create(NULL, CmpDestroy, CmpCompare, CmpName); + env = leveldb_create_default_env(); + cache = leveldb_cache_create_lru(100000); + + options = leveldb_options_create(); + leveldb_options_set_comparator(options, cmp); + leveldb_options_set_error_if_exists(options, 1); + leveldb_options_set_cache(options, cache); + leveldb_options_set_env(options, env); + leveldb_options_set_info_log(options, NULL); + leveldb_options_set_write_buffer_size(options, 100000); + leveldb_options_set_paranoid_checks(options, 1); + leveldb_options_set_max_open_files(options, 10); + leveldb_options_set_block_size(options, 1024); + leveldb_options_set_block_restart_interval(options, 8); + leveldb_options_set_compression(options, leveldb_no_compression); + + roptions = leveldb_readoptions_create(); + leveldb_readoptions_set_verify_checksums(roptions, 1); + leveldb_readoptions_set_fill_cache(roptions, 0); + + woptions = leveldb_writeoptions_create(); + leveldb_writeoptions_set_sync(woptions, 1); + + StartPhase("destroy"); + leveldb_destroy_db(options, dbname, &err); + Free(&err); + + StartPhase("open_error"); + db = leveldb_open(options, dbname, &err); + CheckCondition(err != NULL); + Free(&err); + + StartPhase("leveldb_free"); + db = leveldb_open(options, dbname, &err); + CheckCondition(err != NULL); + leveldb_free(err); + err = NULL; + + StartPhase("open"); + leveldb_options_set_create_if_missing(options, 1); + db = leveldb_open(options, dbname, &err); + CheckNoError(err); + CheckGet(db, roptions, "foo", NULL); + + StartPhase("put"); + leveldb_put(db, woptions, "foo", 3, "hello", 5, &err); + CheckNoError(err); + CheckGet(db, roptions, "foo", "hello"); + + StartPhase("compactall"); + leveldb_compact_range(db, NULL, 0, NULL, 0); + CheckGet(db, roptions, "foo", "hello"); + + StartPhase("compactrange"); + leveldb_compact_range(db, "a", 1, "z", 1); + CheckGet(db, roptions, "foo", "hello"); + + StartPhase("writebatch"); + { + leveldb_writebatch_t* wb = leveldb_writebatch_create(); + leveldb_writebatch_put(wb, "foo", 3, "a", 1); + leveldb_writebatch_clear(wb); + leveldb_writebatch_put(wb, "bar", 3, "b", 1); + leveldb_writebatch_put(wb, "box", 3, "c", 1); + leveldb_writebatch_delete(wb, "bar", 3); + leveldb_write(db, woptions, wb, &err); + CheckNoError(err); + CheckGet(db, roptions, "foo", "hello"); + CheckGet(db, roptions, "bar", NULL); + CheckGet(db, roptions, "box", "c"); + int pos = 0; + leveldb_writebatch_iterate(wb, &pos, CheckPut, CheckDel); + CheckCondition(pos == 3); + leveldb_writebatch_destroy(wb); + } + + StartPhase("iter"); + { + leveldb_iterator_t* iter = leveldb_create_iterator(db, roptions); + CheckCondition(!leveldb_iter_valid(iter)); + leveldb_iter_seek_to_first(iter); + CheckCondition(leveldb_iter_valid(iter)); + CheckIter(iter, "box", "c"); + leveldb_iter_next(iter); + CheckIter(iter, "foo", "hello"); + leveldb_iter_prev(iter); + CheckIter(iter, "box", "c"); + leveldb_iter_prev(iter); + CheckCondition(!leveldb_iter_valid(iter)); + leveldb_iter_seek_to_last(iter); + CheckIter(iter, "foo", "hello"); + leveldb_iter_seek(iter, "b", 1); + CheckIter(iter, "box", "c"); + leveldb_iter_get_error(iter, &err); + CheckNoError(err); + leveldb_iter_destroy(iter); + } + + StartPhase("approximate_sizes"); + { + int i; + int n = 20000; + char keybuf[100]; + char valbuf[100]; + uint64_t sizes[2]; + const char* start[2] = { "a", "k00000000000000010000" }; + size_t start_len[2] = { 1, 21 }; + const char* limit[2] = { "k00000000000000010000", "z" }; + size_t limit_len[2] = { 21, 1 }; + leveldb_writeoptions_set_sync(woptions, 0); + for (i = 0; i < n; i++) { + snprintf(keybuf, sizeof(keybuf), "k%020d", i); + snprintf(valbuf, sizeof(valbuf), "v%020d", i); + leveldb_put(db, woptions, keybuf, strlen(keybuf), valbuf, strlen(valbuf), + &err); + CheckNoError(err); + } + leveldb_approximate_sizes(db, 2, start, start_len, limit, limit_len, sizes); + CheckCondition(sizes[0] > 0); + CheckCondition(sizes[1] > 0); + } + + StartPhase("property"); + { + char* prop = leveldb_property_value(db, "nosuchprop"); + CheckCondition(prop == NULL); + prop = leveldb_property_value(db, "leveldb.stats"); + CheckCondition(prop != NULL); + Free(&prop); + } + + StartPhase("snapshot"); + { + const leveldb_snapshot_t* snap; + snap = leveldb_create_snapshot(db); + leveldb_delete(db, woptions, "foo", 3, &err); + CheckNoError(err); + leveldb_readoptions_set_snapshot(roptions, snap); + CheckGet(db, roptions, "foo", "hello"); + leveldb_readoptions_set_snapshot(roptions, NULL); + CheckGet(db, roptions, "foo", NULL); + leveldb_release_snapshot(db, snap); + } + + StartPhase("repair"); + { + leveldb_close(db); + leveldb_options_set_create_if_missing(options, 0); + leveldb_options_set_error_if_exists(options, 0); + leveldb_repair_db(options, dbname, &err); + CheckNoError(err); + db = leveldb_open(options, dbname, &err); + CheckNoError(err); + CheckGet(db, roptions, "foo", NULL); + CheckGet(db, roptions, "bar", NULL); + CheckGet(db, roptions, "box", "c"); + leveldb_options_set_create_if_missing(options, 1); + leveldb_options_set_error_if_exists(options, 1); + } + + StartPhase("filter"); + for (run = 0; run < 2; run++) { + // First run uses custom filter, second run uses bloom filter + CheckNoError(err); + leveldb_filterpolicy_t* policy; + if (run == 0) { + policy = leveldb_filterpolicy_create( + NULL, FilterDestroy, FilterCreate, FilterKeyMatch, FilterName); + } else { + policy = leveldb_filterpolicy_create_bloom(10); + } + + // Create new database + leveldb_close(db); + leveldb_destroy_db(options, dbname, &err); + leveldb_options_set_filter_policy(options, policy); + db = leveldb_open(options, dbname, &err); + CheckNoError(err); + leveldb_put(db, woptions, "foo", 3, "foovalue", 8, &err); + CheckNoError(err); + leveldb_put(db, woptions, "bar", 3, "barvalue", 8, &err); + CheckNoError(err); + leveldb_compact_range(db, NULL, 0, NULL, 0); + + fake_filter_result = 1; + CheckGet(db, roptions, "foo", "foovalue"); + CheckGet(db, roptions, "bar", "barvalue"); + if (phase == 0) { + // Must not find value when custom filter returns false + fake_filter_result = 0; + CheckGet(db, roptions, "foo", NULL); + CheckGet(db, roptions, "bar", NULL); + fake_filter_result = 1; + + CheckGet(db, roptions, "foo", "foovalue"); + CheckGet(db, roptions, "bar", "barvalue"); + } + leveldb_options_set_filter_policy(options, NULL); + leveldb_filterpolicy_destroy(policy); + } + + StartPhase("cleanup"); + leveldb_close(db); + leveldb_options_destroy(options); + leveldb_readoptions_destroy(roptions); + leveldb_writeoptions_destroy(woptions); + leveldb_cache_destroy(cache); + leveldb_comparator_destroy(cmp); + leveldb_env_destroy(env); + + fprintf(stderr, "PASS\n"); + return 0; +} diff --git a/ios/Pods/leveldb-library/db/corruption_test.cc b/ios/Pods/leveldb-library/db/corruption_test.cc new file mode 100644 index 000000000..96afc6891 --- /dev/null +++ b/ios/Pods/leveldb-library/db/corruption_test.cc @@ -0,0 +1,374 @@ +// Copyright (c) 2011 The LevelDB Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. See the AUTHORS file for names of contributors. + +#include "leveldb/db.h" + +#include +#include +#include +#include +#include "leveldb/cache.h" +#include "leveldb/env.h" +#include "leveldb/table.h" +#include "leveldb/write_batch.h" +#include "db/db_impl.h" +#include "db/filename.h" +#include "db/log_format.h" +#include "db/version_set.h" +#include "util/logging.h" +#include "util/testharness.h" +#include "util/testutil.h" + +namespace leveldb { + +static const int kValueSize = 1000; + +class CorruptionTest { + public: + test::ErrorEnv env_; + std::string dbname_; + Cache* tiny_cache_; + Options options_; + DB* db_; + + CorruptionTest() { + tiny_cache_ = NewLRUCache(100); + options_.env = &env_; + options_.block_cache = tiny_cache_; + dbname_ = test::TmpDir() + "/db_test"; + DestroyDB(dbname_, options_); + + db_ = NULL; + options_.create_if_missing = true; + Reopen(); + options_.create_if_missing = false; + } + + ~CorruptionTest() { + delete db_; + DestroyDB(dbname_, Options()); + delete tiny_cache_; + } + + Status TryReopen() { + delete db_; + db_ = NULL; + return DB::Open(options_, dbname_, &db_); + } + + void Reopen() { + ASSERT_OK(TryReopen()); + } + + void RepairDB() { + delete db_; + db_ = NULL; + ASSERT_OK(::leveldb::RepairDB(dbname_, options_)); + } + + void Build(int n) { + std::string key_space, value_space; + WriteBatch batch; + for (int i = 0; i < n; i++) { + //if ((i % 100) == 0) fprintf(stderr, "@ %d of %d\n", i, n); + Slice key = Key(i, &key_space); + batch.Clear(); + batch.Put(key, Value(i, &value_space)); + WriteOptions options; + // Corrupt() doesn't work without this sync on windows; stat reports 0 for + // the file size. + if (i == n - 1) { + options.sync = true; + } + ASSERT_OK(db_->Write(options, &batch)); + } + } + + void Check(int min_expected, int max_expected) { + int next_expected = 0; + int missed = 0; + int bad_keys = 0; + int bad_values = 0; + int correct = 0; + std::string value_space; + Iterator* iter = db_->NewIterator(ReadOptions()); + for (iter->SeekToFirst(); iter->Valid(); iter->Next()) { + uint64_t key; + Slice in(iter->key()); + if (in == "" || in == "~") { + // Ignore boundary keys. + continue; + } + if (!ConsumeDecimalNumber(&in, &key) || + !in.empty() || + key < next_expected) { + bad_keys++; + continue; + } + missed += (key - next_expected); + next_expected = key + 1; + if (iter->value() != Value(key, &value_space)) { + bad_values++; + } else { + correct++; + } + } + delete iter; + + fprintf(stderr, + "expected=%d..%d; got=%d; bad_keys=%d; bad_values=%d; missed=%d\n", + min_expected, max_expected, correct, bad_keys, bad_values, missed); + ASSERT_LE(min_expected, correct); + ASSERT_GE(max_expected, correct); + } + + void Corrupt(FileType filetype, int offset, int bytes_to_corrupt) { + // Pick file to corrupt + std::vector filenames; + ASSERT_OK(env_.GetChildren(dbname_, &filenames)); + uint64_t number; + FileType type; + std::string fname; + int picked_number = -1; + for (size_t i = 0; i < filenames.size(); i++) { + if (ParseFileName(filenames[i], &number, &type) && + type == filetype && + int(number) > picked_number) { // Pick latest file + fname = dbname_ + "/" + filenames[i]; + picked_number = number; + } + } + ASSERT_TRUE(!fname.empty()) << filetype; + + struct stat sbuf; + if (stat(fname.c_str(), &sbuf) != 0) { + const char* msg = strerror(errno); + ASSERT_TRUE(false) << fname << ": " << msg; + } + + if (offset < 0) { + // Relative to end of file; make it absolute + if (-offset > sbuf.st_size) { + offset = 0; + } else { + offset = sbuf.st_size + offset; + } + } + if (offset > sbuf.st_size) { + offset = sbuf.st_size; + } + if (offset + bytes_to_corrupt > sbuf.st_size) { + bytes_to_corrupt = sbuf.st_size - offset; + } + + // Do it + std::string contents; + Status s = ReadFileToString(Env::Default(), fname, &contents); + ASSERT_TRUE(s.ok()) << s.ToString(); + for (int i = 0; i < bytes_to_corrupt; i++) { + contents[i + offset] ^= 0x80; + } + s = WriteStringToFile(Env::Default(), contents, fname); + ASSERT_TRUE(s.ok()) << s.ToString(); + } + + int Property(const std::string& name) { + std::string property; + int result; + if (db_->GetProperty(name, &property) && + sscanf(property.c_str(), "%d", &result) == 1) { + return result; + } else { + return -1; + } + } + + // Return the ith key + Slice Key(int i, std::string* storage) { + char buf[100]; + snprintf(buf, sizeof(buf), "%016d", i); + storage->assign(buf, strlen(buf)); + return Slice(*storage); + } + + // Return the value to associate with the specified key + Slice Value(int k, std::string* storage) { + Random r(k); + return test::RandomString(&r, kValueSize, storage); + } +}; + +TEST(CorruptionTest, Recovery) { + Build(100); + Check(100, 100); + Corrupt(kLogFile, 19, 1); // WriteBatch tag for first record + Corrupt(kLogFile, log::kBlockSize + 1000, 1); // Somewhere in second block + Reopen(); + + // The 64 records in the first two log blocks are completely lost. + Check(36, 36); +} + +TEST(CorruptionTest, RecoverWriteError) { + env_.writable_file_error_ = true; + Status s = TryReopen(); + ASSERT_TRUE(!s.ok()); +} + +TEST(CorruptionTest, NewFileErrorDuringWrite) { + // Do enough writing to force minor compaction + env_.writable_file_error_ = true; + const int num = 3 + (Options().write_buffer_size / kValueSize); + std::string value_storage; + Status s; + for (int i = 0; s.ok() && i < num; i++) { + WriteBatch batch; + batch.Put("a", Value(100, &value_storage)); + s = db_->Write(WriteOptions(), &batch); + } + ASSERT_TRUE(!s.ok()); + ASSERT_GE(env_.num_writable_file_errors_, 1); + env_.writable_file_error_ = false; + Reopen(); +} + +TEST(CorruptionTest, TableFile) { + Build(100); + DBImpl* dbi = reinterpret_cast(db_); + dbi->TEST_CompactMemTable(); + dbi->TEST_CompactRange(0, NULL, NULL); + dbi->TEST_CompactRange(1, NULL, NULL); + + Corrupt(kTableFile, 100, 1); + Check(90, 99); +} + +TEST(CorruptionTest, TableFileRepair) { + options_.block_size = 2 * kValueSize; // Limit scope of corruption + options_.paranoid_checks = true; + Reopen(); + Build(100); + DBImpl* dbi = reinterpret_cast(db_); + dbi->TEST_CompactMemTable(); + dbi->TEST_CompactRange(0, NULL, NULL); + dbi->TEST_CompactRange(1, NULL, NULL); + + Corrupt(kTableFile, 100, 1); + RepairDB(); + Reopen(); + Check(95, 99); +} + +TEST(CorruptionTest, TableFileIndexData) { + Build(10000); // Enough to build multiple Tables + DBImpl* dbi = reinterpret_cast(db_); + dbi->TEST_CompactMemTable(); + + Corrupt(kTableFile, -2000, 500); + Reopen(); + Check(5000, 9999); +} + +TEST(CorruptionTest, MissingDescriptor) { + Build(1000); + RepairDB(); + Reopen(); + Check(1000, 1000); +} + +TEST(CorruptionTest, SequenceNumberRecovery) { + ASSERT_OK(db_->Put(WriteOptions(), "foo", "v1")); + ASSERT_OK(db_->Put(WriteOptions(), "foo", "v2")); + ASSERT_OK(db_->Put(WriteOptions(), "foo", "v3")); + ASSERT_OK(db_->Put(WriteOptions(), "foo", "v4")); + ASSERT_OK(db_->Put(WriteOptions(), "foo", "v5")); + RepairDB(); + Reopen(); + std::string v; + ASSERT_OK(db_->Get(ReadOptions(), "foo", &v)); + ASSERT_EQ("v5", v); + // Write something. If sequence number was not recovered properly, + // it will be hidden by an earlier write. + ASSERT_OK(db_->Put(WriteOptions(), "foo", "v6")); + ASSERT_OK(db_->Get(ReadOptions(), "foo", &v)); + ASSERT_EQ("v6", v); + Reopen(); + ASSERT_OK(db_->Get(ReadOptions(), "foo", &v)); + ASSERT_EQ("v6", v); +} + +TEST(CorruptionTest, CorruptedDescriptor) { + ASSERT_OK(db_->Put(WriteOptions(), "foo", "hello")); + DBImpl* dbi = reinterpret_cast(db_); + dbi->TEST_CompactMemTable(); + dbi->TEST_CompactRange(0, NULL, NULL); + + Corrupt(kDescriptorFile, 0, 1000); + Status s = TryReopen(); + ASSERT_TRUE(!s.ok()); + + RepairDB(); + Reopen(); + std::string v; + ASSERT_OK(db_->Get(ReadOptions(), "foo", &v)); + ASSERT_EQ("hello", v); +} + +TEST(CorruptionTest, CompactionInputError) { + Build(10); + DBImpl* dbi = reinterpret_cast(db_); + dbi->TEST_CompactMemTable(); + const int last = config::kMaxMemCompactLevel; + ASSERT_EQ(1, Property("leveldb.num-files-at-level" + NumberToString(last))); + + Corrupt(kTableFile, 100, 1); + Check(5, 9); + + // Force compactions by writing lots of values + Build(10000); + Check(10000, 10000); +} + +TEST(CorruptionTest, CompactionInputErrorParanoid) { + options_.paranoid_checks = true; + options_.write_buffer_size = 512 << 10; + Reopen(); + DBImpl* dbi = reinterpret_cast(db_); + + // Make multiple inputs so we need to compact. + for (int i = 0; i < 2; i++) { + Build(10); + dbi->TEST_CompactMemTable(); + Corrupt(kTableFile, 100, 1); + env_.SleepForMicroseconds(100000); + } + dbi->CompactRange(NULL, NULL); + + // Write must fail because of corrupted table + std::string tmp1, tmp2; + Status s = db_->Put(WriteOptions(), Key(5, &tmp1), Value(5, &tmp2)); + ASSERT_TRUE(!s.ok()) << "write did not fail in corrupted paranoid db"; +} + +TEST(CorruptionTest, UnrelatedKeys) { + Build(10); + DBImpl* dbi = reinterpret_cast(db_); + dbi->TEST_CompactMemTable(); + Corrupt(kTableFile, 100, 1); + + std::string tmp1, tmp2; + ASSERT_OK(db_->Put(WriteOptions(), Key(1000, &tmp1), Value(1000, &tmp2))); + std::string v; + ASSERT_OK(db_->Get(ReadOptions(), Key(1000, &tmp1), &v)); + ASSERT_EQ(Value(1000, &tmp2).ToString(), v); + dbi->TEST_CompactMemTable(); + ASSERT_OK(db_->Get(ReadOptions(), Key(1000, &tmp1), &v)); + ASSERT_EQ(Value(1000, &tmp2).ToString(), v); +} + +} // namespace leveldb + +int main(int argc, char** argv) { + return leveldb::test::RunAllTests(); +} diff --git a/ios/Pods/leveldb-library/db/db_bench.cc b/ios/Pods/leveldb-library/db/db_bench.cc new file mode 100644 index 000000000..705a170aa --- /dev/null +++ b/ios/Pods/leveldb-library/db/db_bench.cc @@ -0,0 +1,978 @@ +// Copyright (c) 2011 The LevelDB Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. See the AUTHORS file for names of contributors. + +#include +#include +#include +#include "db/db_impl.h" +#include "db/version_set.h" +#include "leveldb/cache.h" +#include "leveldb/db.h" +#include "leveldb/env.h" +#include "leveldb/write_batch.h" +#include "port/port.h" +#include "util/crc32c.h" +#include "util/histogram.h" +#include "util/mutexlock.h" +#include "util/random.h" +#include "util/testutil.h" + +// Comma-separated list of operations to run in the specified order +// Actual benchmarks: +// fillseq -- write N values in sequential key order in async mode +// fillrandom -- write N values in random key order in async mode +// overwrite -- overwrite N values in random key order in async mode +// fillsync -- write N/100 values in random key order in sync mode +// fill100K -- write N/1000 100K values in random order in async mode +// deleteseq -- delete N keys in sequential order +// deleterandom -- delete N keys in random order +// readseq -- read N times sequentially +// readreverse -- read N times in reverse order +// readrandom -- read N times in random order +// readmissing -- read N missing keys in random order +// readhot -- read N times in random order from 1% section of DB +// seekrandom -- N random seeks +// crc32c -- repeated crc32c of 4K of data +// acquireload -- load N*1000 times +// Meta operations: +// compact -- Compact the entire DB +// stats -- Print DB stats +// sstables -- Print sstable info +// heapprofile -- Dump a heap profile (if supported by this port) +static const char* FLAGS_benchmarks = + "fillseq," + "fillsync," + "fillrandom," + "overwrite," + "readrandom," + "readrandom," // Extra run to allow previous compactions to quiesce + "readseq," + "readreverse," + "compact," + "readrandom," + "readseq," + "readreverse," + "fill100K," + "crc32c," + "snappycomp," + "snappyuncomp," + "acquireload," + ; + +// Number of key/values to place in database +static int FLAGS_num = 1000000; + +// Number of read operations to do. If negative, do FLAGS_num reads. +static int FLAGS_reads = -1; + +// Number of concurrent threads to run. +static int FLAGS_threads = 1; + +// Size of each value +static int FLAGS_value_size = 100; + +// Arrange to generate values that shrink to this fraction of +// their original size after compression +static double FLAGS_compression_ratio = 0.5; + +// Print histogram of operation timings +static bool FLAGS_histogram = false; + +// Number of bytes to buffer in memtable before compacting +// (initialized to default value by "main") +static int FLAGS_write_buffer_size = 0; + +// Number of bytes to use as a cache of uncompressed data. +// Negative means use default settings. +static int FLAGS_cache_size = -1; + +// Maximum number of files to keep open at the same time (use default if == 0) +static int FLAGS_open_files = 0; + +// Bloom filter bits per key. +// Negative means use default settings. +static int FLAGS_bloom_bits = -1; + +// If true, do not destroy the existing database. If you set this +// flag and also specify a benchmark that wants a fresh database, that +// benchmark will fail. +static bool FLAGS_use_existing_db = false; + +// Use the db with the following name. +static const char* FLAGS_db = NULL; + +namespace leveldb { + +namespace { + +// Helper for quickly generating random data. +class RandomGenerator { + private: + std::string data_; + int pos_; + + public: + RandomGenerator() { + // We use a limited amount of data over and over again and ensure + // that it is larger than the compression window (32KB), and also + // large enough to serve all typical value sizes we want to write. + Random rnd(301); + std::string piece; + while (data_.size() < 1048576) { + // Add a short fragment that is as compressible as specified + // by FLAGS_compression_ratio. + test::CompressibleString(&rnd, FLAGS_compression_ratio, 100, &piece); + data_.append(piece); + } + pos_ = 0; + } + + Slice Generate(size_t len) { + if (pos_ + len > data_.size()) { + pos_ = 0; + assert(len < data_.size()); + } + pos_ += len; + return Slice(data_.data() + pos_ - len, len); + } +}; + +static Slice TrimSpace(Slice s) { + size_t start = 0; + while (start < s.size() && isspace(s[start])) { + start++; + } + size_t limit = s.size(); + while (limit > start && isspace(s[limit-1])) { + limit--; + } + return Slice(s.data() + start, limit - start); +} + +static void AppendWithSpace(std::string* str, Slice msg) { + if (msg.empty()) return; + if (!str->empty()) { + str->push_back(' '); + } + str->append(msg.data(), msg.size()); +} + +class Stats { + private: + double start_; + double finish_; + double seconds_; + int done_; + int next_report_; + int64_t bytes_; + double last_op_finish_; + Histogram hist_; + std::string message_; + + public: + Stats() { Start(); } + + void Start() { + next_report_ = 100; + last_op_finish_ = start_; + hist_.Clear(); + done_ = 0; + bytes_ = 0; + seconds_ = 0; + start_ = Env::Default()->NowMicros(); + finish_ = start_; + message_.clear(); + } + + void Merge(const Stats& other) { + hist_.Merge(other.hist_); + done_ += other.done_; + bytes_ += other.bytes_; + seconds_ += other.seconds_; + if (other.start_ < start_) start_ = other.start_; + if (other.finish_ > finish_) finish_ = other.finish_; + + // Just keep the messages from one thread + if (message_.empty()) message_ = other.message_; + } + + void Stop() { + finish_ = Env::Default()->NowMicros(); + seconds_ = (finish_ - start_) * 1e-6; + } + + void AddMessage(Slice msg) { + AppendWithSpace(&message_, msg); + } + + void FinishedSingleOp() { + if (FLAGS_histogram) { + double now = Env::Default()->NowMicros(); + double micros = now - last_op_finish_; + hist_.Add(micros); + if (micros > 20000) { + fprintf(stderr, "long op: %.1f micros%30s\r", micros, ""); + fflush(stderr); + } + last_op_finish_ = now; + } + + done_++; + if (done_ >= next_report_) { + if (next_report_ < 1000) next_report_ += 100; + else if (next_report_ < 5000) next_report_ += 500; + else if (next_report_ < 10000) next_report_ += 1000; + else if (next_report_ < 50000) next_report_ += 5000; + else if (next_report_ < 100000) next_report_ += 10000; + else if (next_report_ < 500000) next_report_ += 50000; + else next_report_ += 100000; + fprintf(stderr, "... finished %d ops%30s\r", done_, ""); + fflush(stderr); + } + } + + void AddBytes(int64_t n) { + bytes_ += n; + } + + void Report(const Slice& name) { + // Pretend at least one op was done in case we are running a benchmark + // that does not call FinishedSingleOp(). + if (done_ < 1) done_ = 1; + + std::string extra; + if (bytes_ > 0) { + // Rate is computed on actual elapsed time, not the sum of per-thread + // elapsed times. + double elapsed = (finish_ - start_) * 1e-6; + char rate[100]; + snprintf(rate, sizeof(rate), "%6.1f MB/s", + (bytes_ / 1048576.0) / elapsed); + extra = rate; + } + AppendWithSpace(&extra, message_); + + fprintf(stdout, "%-12s : %11.3f micros/op;%s%s\n", + name.ToString().c_str(), + seconds_ * 1e6 / done_, + (extra.empty() ? "" : " "), + extra.c_str()); + if (FLAGS_histogram) { + fprintf(stdout, "Microseconds per op:\n%s\n", hist_.ToString().c_str()); + } + fflush(stdout); + } +}; + +// State shared by all concurrent executions of the same benchmark. +struct SharedState { + port::Mutex mu; + port::CondVar cv; + int total; + + // Each thread goes through the following states: + // (1) initializing + // (2) waiting for others to be initialized + // (3) running + // (4) done + + int num_initialized; + int num_done; + bool start; + + SharedState() : cv(&mu) { } +}; + +// Per-thread state for concurrent executions of the same benchmark. +struct ThreadState { + int tid; // 0..n-1 when running in n threads + Random rand; // Has different seeds for different threads + Stats stats; + SharedState* shared; + + ThreadState(int index) + : tid(index), + rand(1000 + index) { + } +}; + +} // namespace + +class Benchmark { + private: + Cache* cache_; + const FilterPolicy* filter_policy_; + DB* db_; + int num_; + int value_size_; + int entries_per_batch_; + WriteOptions write_options_; + int reads_; + int heap_counter_; + + void PrintHeader() { + const int kKeySize = 16; + PrintEnvironment(); + fprintf(stdout, "Keys: %d bytes each\n", kKeySize); + fprintf(stdout, "Values: %d bytes each (%d bytes after compression)\n", + FLAGS_value_size, + static_cast(FLAGS_value_size * FLAGS_compression_ratio + 0.5)); + fprintf(stdout, "Entries: %d\n", num_); + fprintf(stdout, "RawSize: %.1f MB (estimated)\n", + ((static_cast(kKeySize + FLAGS_value_size) * num_) + / 1048576.0)); + fprintf(stdout, "FileSize: %.1f MB (estimated)\n", + (((kKeySize + FLAGS_value_size * FLAGS_compression_ratio) * num_) + / 1048576.0)); + PrintWarnings(); + fprintf(stdout, "------------------------------------------------\n"); + } + + void PrintWarnings() { +#if defined(__GNUC__) && !defined(__OPTIMIZE__) + fprintf(stdout, + "WARNING: Optimization is disabled: benchmarks unnecessarily slow\n" + ); +#endif +#ifndef NDEBUG + fprintf(stdout, + "WARNING: Assertions are enabled; benchmarks unnecessarily slow\n"); +#endif + + // See if snappy is working by attempting to compress a compressible string + const char text[] = "yyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyy"; + std::string compressed; + if (!port::Snappy_Compress(text, sizeof(text), &compressed)) { + fprintf(stdout, "WARNING: Snappy compression is not enabled\n"); + } else if (compressed.size() >= sizeof(text)) { + fprintf(stdout, "WARNING: Snappy compression is not effective\n"); + } + } + + void PrintEnvironment() { + fprintf(stderr, "LevelDB: version %d.%d\n", + kMajorVersion, kMinorVersion); + +#if defined(__linux) + time_t now = time(NULL); + fprintf(stderr, "Date: %s", ctime(&now)); // ctime() adds newline + + FILE* cpuinfo = fopen("/proc/cpuinfo", "r"); + if (cpuinfo != NULL) { + char line[1000]; + int num_cpus = 0; + std::string cpu_type; + std::string cache_size; + while (fgets(line, sizeof(line), cpuinfo) != NULL) { + const char* sep = strchr(line, ':'); + if (sep == NULL) { + continue; + } + Slice key = TrimSpace(Slice(line, sep - 1 - line)); + Slice val = TrimSpace(Slice(sep + 1)); + if (key == "model name") { + ++num_cpus; + cpu_type = val.ToString(); + } else if (key == "cache size") { + cache_size = val.ToString(); + } + } + fclose(cpuinfo); + fprintf(stderr, "CPU: %d * %s\n", num_cpus, cpu_type.c_str()); + fprintf(stderr, "CPUCache: %s\n", cache_size.c_str()); + } +#endif + } + + public: + Benchmark() + : cache_(FLAGS_cache_size >= 0 ? NewLRUCache(FLAGS_cache_size) : NULL), + filter_policy_(FLAGS_bloom_bits >= 0 + ? NewBloomFilterPolicy(FLAGS_bloom_bits) + : NULL), + db_(NULL), + num_(FLAGS_num), + value_size_(FLAGS_value_size), + entries_per_batch_(1), + reads_(FLAGS_reads < 0 ? FLAGS_num : FLAGS_reads), + heap_counter_(0) { + std::vector files; + Env::Default()->GetChildren(FLAGS_db, &files); + for (size_t i = 0; i < files.size(); i++) { + if (Slice(files[i]).starts_with("heap-")) { + Env::Default()->DeleteFile(std::string(FLAGS_db) + "/" + files[i]); + } + } + if (!FLAGS_use_existing_db) { + DestroyDB(FLAGS_db, Options()); + } + } + + ~Benchmark() { + delete db_; + delete cache_; + delete filter_policy_; + } + + void Run() { + PrintHeader(); + Open(); + + const char* benchmarks = FLAGS_benchmarks; + while (benchmarks != NULL) { + const char* sep = strchr(benchmarks, ','); + Slice name; + if (sep == NULL) { + name = benchmarks; + benchmarks = NULL; + } else { + name = Slice(benchmarks, sep - benchmarks); + benchmarks = sep + 1; + } + + // Reset parameters that may be overridden below + num_ = FLAGS_num; + reads_ = (FLAGS_reads < 0 ? FLAGS_num : FLAGS_reads); + value_size_ = FLAGS_value_size; + entries_per_batch_ = 1; + write_options_ = WriteOptions(); + + void (Benchmark::*method)(ThreadState*) = NULL; + bool fresh_db = false; + int num_threads = FLAGS_threads; + + if (name == Slice("fillseq")) { + fresh_db = true; + method = &Benchmark::WriteSeq; + } else if (name == Slice("fillbatch")) { + fresh_db = true; + entries_per_batch_ = 1000; + method = &Benchmark::WriteSeq; + } else if (name == Slice("fillrandom")) { + fresh_db = true; + method = &Benchmark::WriteRandom; + } else if (name == Slice("overwrite")) { + fresh_db = false; + method = &Benchmark::WriteRandom; + } else if (name == Slice("fillsync")) { + fresh_db = true; + num_ /= 1000; + write_options_.sync = true; + method = &Benchmark::WriteRandom; + } else if (name == Slice("fill100K")) { + fresh_db = true; + num_ /= 1000; + value_size_ = 100 * 1000; + method = &Benchmark::WriteRandom; + } else if (name == Slice("readseq")) { + method = &Benchmark::ReadSequential; + } else if (name == Slice("readreverse")) { + method = &Benchmark::ReadReverse; + } else if (name == Slice("readrandom")) { + method = &Benchmark::ReadRandom; + } else if (name == Slice("readmissing")) { + method = &Benchmark::ReadMissing; + } else if (name == Slice("seekrandom")) { + method = &Benchmark::SeekRandom; + } else if (name == Slice("readhot")) { + method = &Benchmark::ReadHot; + } else if (name == Slice("readrandomsmall")) { + reads_ /= 1000; + method = &Benchmark::ReadRandom; + } else if (name == Slice("deleteseq")) { + method = &Benchmark::DeleteSeq; + } else if (name == Slice("deleterandom")) { + method = &Benchmark::DeleteRandom; + } else if (name == Slice("readwhilewriting")) { + num_threads++; // Add extra thread for writing + method = &Benchmark::ReadWhileWriting; + } else if (name == Slice("compact")) { + method = &Benchmark::Compact; + } else if (name == Slice("crc32c")) { + method = &Benchmark::Crc32c; + } else if (name == Slice("acquireload")) { + method = &Benchmark::AcquireLoad; + } else if (name == Slice("snappycomp")) { + method = &Benchmark::SnappyCompress; + } else if (name == Slice("snappyuncomp")) { + method = &Benchmark::SnappyUncompress; + } else if (name == Slice("heapprofile")) { + HeapProfile(); + } else if (name == Slice("stats")) { + PrintStats("leveldb.stats"); + } else if (name == Slice("sstables")) { + PrintStats("leveldb.sstables"); + } else { + if (name != Slice()) { // No error message for empty name + fprintf(stderr, "unknown benchmark '%s'\n", name.ToString().c_str()); + } + } + + if (fresh_db) { + if (FLAGS_use_existing_db) { + fprintf(stdout, "%-12s : skipped (--use_existing_db is true)\n", + name.ToString().c_str()); + method = NULL; + } else { + delete db_; + db_ = NULL; + DestroyDB(FLAGS_db, Options()); + Open(); + } + } + + if (method != NULL) { + RunBenchmark(num_threads, name, method); + } + } + } + + private: + struct ThreadArg { + Benchmark* bm; + SharedState* shared; + ThreadState* thread; + void (Benchmark::*method)(ThreadState*); + }; + + static void ThreadBody(void* v) { + ThreadArg* arg = reinterpret_cast(v); + SharedState* shared = arg->shared; + ThreadState* thread = arg->thread; + { + MutexLock l(&shared->mu); + shared->num_initialized++; + if (shared->num_initialized >= shared->total) { + shared->cv.SignalAll(); + } + while (!shared->start) { + shared->cv.Wait(); + } + } + + thread->stats.Start(); + (arg->bm->*(arg->method))(thread); + thread->stats.Stop(); + + { + MutexLock l(&shared->mu); + shared->num_done++; + if (shared->num_done >= shared->total) { + shared->cv.SignalAll(); + } + } + } + + void RunBenchmark(int n, Slice name, + void (Benchmark::*method)(ThreadState*)) { + SharedState shared; + shared.total = n; + shared.num_initialized = 0; + shared.num_done = 0; + shared.start = false; + + ThreadArg* arg = new ThreadArg[n]; + for (int i = 0; i < n; i++) { + arg[i].bm = this; + arg[i].method = method; + arg[i].shared = &shared; + arg[i].thread = new ThreadState(i); + arg[i].thread->shared = &shared; + Env::Default()->StartThread(ThreadBody, &arg[i]); + } + + shared.mu.Lock(); + while (shared.num_initialized < n) { + shared.cv.Wait(); + } + + shared.start = true; + shared.cv.SignalAll(); + while (shared.num_done < n) { + shared.cv.Wait(); + } + shared.mu.Unlock(); + + for (int i = 1; i < n; i++) { + arg[0].thread->stats.Merge(arg[i].thread->stats); + } + arg[0].thread->stats.Report(name); + + for (int i = 0; i < n; i++) { + delete arg[i].thread; + } + delete[] arg; + } + + void Crc32c(ThreadState* thread) { + // Checksum about 500MB of data total + const int size = 4096; + const char* label = "(4K per op)"; + std::string data(size, 'x'); + int64_t bytes = 0; + uint32_t crc = 0; + while (bytes < 500 * 1048576) { + crc = crc32c::Value(data.data(), size); + thread->stats.FinishedSingleOp(); + bytes += size; + } + // Print so result is not dead + fprintf(stderr, "... crc=0x%x\r", static_cast(crc)); + + thread->stats.AddBytes(bytes); + thread->stats.AddMessage(label); + } + + void AcquireLoad(ThreadState* thread) { + int dummy; + port::AtomicPointer ap(&dummy); + int count = 0; + void *ptr = NULL; + thread->stats.AddMessage("(each op is 1000 loads)"); + while (count < 100000) { + for (int i = 0; i < 1000; i++) { + ptr = ap.Acquire_Load(); + } + count++; + thread->stats.FinishedSingleOp(); + } + if (ptr == NULL) exit(1); // Disable unused variable warning. + } + + void SnappyCompress(ThreadState* thread) { + RandomGenerator gen; + Slice input = gen.Generate(Options().block_size); + int64_t bytes = 0; + int64_t produced = 0; + bool ok = true; + std::string compressed; + while (ok && bytes < 1024 * 1048576) { // Compress 1G + ok = port::Snappy_Compress(input.data(), input.size(), &compressed); + produced += compressed.size(); + bytes += input.size(); + thread->stats.FinishedSingleOp(); + } + + if (!ok) { + thread->stats.AddMessage("(snappy failure)"); + } else { + char buf[100]; + snprintf(buf, sizeof(buf), "(output: %.1f%%)", + (produced * 100.0) / bytes); + thread->stats.AddMessage(buf); + thread->stats.AddBytes(bytes); + } + } + + void SnappyUncompress(ThreadState* thread) { + RandomGenerator gen; + Slice input = gen.Generate(Options().block_size); + std::string compressed; + bool ok = port::Snappy_Compress(input.data(), input.size(), &compressed); + int64_t bytes = 0; + char* uncompressed = new char[input.size()]; + while (ok && bytes < 1024 * 1048576) { // Compress 1G + ok = port::Snappy_Uncompress(compressed.data(), compressed.size(), + uncompressed); + bytes += input.size(); + thread->stats.FinishedSingleOp(); + } + delete[] uncompressed; + + if (!ok) { + thread->stats.AddMessage("(snappy failure)"); + } else { + thread->stats.AddBytes(bytes); + } + } + + void Open() { + assert(db_ == NULL); + Options options; + options.create_if_missing = !FLAGS_use_existing_db; + options.block_cache = cache_; + options.write_buffer_size = FLAGS_write_buffer_size; + options.max_open_files = FLAGS_open_files; + options.filter_policy = filter_policy_; + Status s = DB::Open(options, FLAGS_db, &db_); + if (!s.ok()) { + fprintf(stderr, "open error: %s\n", s.ToString().c_str()); + exit(1); + } + } + + void WriteSeq(ThreadState* thread) { + DoWrite(thread, true); + } + + void WriteRandom(ThreadState* thread) { + DoWrite(thread, false); + } + + void DoWrite(ThreadState* thread, bool seq) { + if (num_ != FLAGS_num) { + char msg[100]; + snprintf(msg, sizeof(msg), "(%d ops)", num_); + thread->stats.AddMessage(msg); + } + + RandomGenerator gen; + WriteBatch batch; + Status s; + int64_t bytes = 0; + for (int i = 0; i < num_; i += entries_per_batch_) { + batch.Clear(); + for (int j = 0; j < entries_per_batch_; j++) { + const int k = seq ? i+j : (thread->rand.Next() % FLAGS_num); + char key[100]; + snprintf(key, sizeof(key), "%016d", k); + batch.Put(key, gen.Generate(value_size_)); + bytes += value_size_ + strlen(key); + thread->stats.FinishedSingleOp(); + } + s = db_->Write(write_options_, &batch); + if (!s.ok()) { + fprintf(stderr, "put error: %s\n", s.ToString().c_str()); + exit(1); + } + } + thread->stats.AddBytes(bytes); + } + + void ReadSequential(ThreadState* thread) { + Iterator* iter = db_->NewIterator(ReadOptions()); + int i = 0; + int64_t bytes = 0; + for (iter->SeekToFirst(); i < reads_ && iter->Valid(); iter->Next()) { + bytes += iter->key().size() + iter->value().size(); + thread->stats.FinishedSingleOp(); + ++i; + } + delete iter; + thread->stats.AddBytes(bytes); + } + + void ReadReverse(ThreadState* thread) { + Iterator* iter = db_->NewIterator(ReadOptions()); + int i = 0; + int64_t bytes = 0; + for (iter->SeekToLast(); i < reads_ && iter->Valid(); iter->Prev()) { + bytes += iter->key().size() + iter->value().size(); + thread->stats.FinishedSingleOp(); + ++i; + } + delete iter; + thread->stats.AddBytes(bytes); + } + + void ReadRandom(ThreadState* thread) { + ReadOptions options; + std::string value; + int found = 0; + for (int i = 0; i < reads_; i++) { + char key[100]; + const int k = thread->rand.Next() % FLAGS_num; + snprintf(key, sizeof(key), "%016d", k); + if (db_->Get(options, key, &value).ok()) { + found++; + } + thread->stats.FinishedSingleOp(); + } + char msg[100]; + snprintf(msg, sizeof(msg), "(%d of %d found)", found, num_); + thread->stats.AddMessage(msg); + } + + void ReadMissing(ThreadState* thread) { + ReadOptions options; + std::string value; + for (int i = 0; i < reads_; i++) { + char key[100]; + const int k = thread->rand.Next() % FLAGS_num; + snprintf(key, sizeof(key), "%016d.", k); + db_->Get(options, key, &value); + thread->stats.FinishedSingleOp(); + } + } + + void ReadHot(ThreadState* thread) { + ReadOptions options; + std::string value; + const int range = (FLAGS_num + 99) / 100; + for (int i = 0; i < reads_; i++) { + char key[100]; + const int k = thread->rand.Next() % range; + snprintf(key, sizeof(key), "%016d", k); + db_->Get(options, key, &value); + thread->stats.FinishedSingleOp(); + } + } + + void SeekRandom(ThreadState* thread) { + ReadOptions options; + int found = 0; + for (int i = 0; i < reads_; i++) { + Iterator* iter = db_->NewIterator(options); + char key[100]; + const int k = thread->rand.Next() % FLAGS_num; + snprintf(key, sizeof(key), "%016d", k); + iter->Seek(key); + if (iter->Valid() && iter->key() == key) found++; + delete iter; + thread->stats.FinishedSingleOp(); + } + char msg[100]; + snprintf(msg, sizeof(msg), "(%d of %d found)", found, num_); + thread->stats.AddMessage(msg); + } + + void DoDelete(ThreadState* thread, bool seq) { + RandomGenerator gen; + WriteBatch batch; + Status s; + for (int i = 0; i < num_; i += entries_per_batch_) { + batch.Clear(); + for (int j = 0; j < entries_per_batch_; j++) { + const int k = seq ? i+j : (thread->rand.Next() % FLAGS_num); + char key[100]; + snprintf(key, sizeof(key), "%016d", k); + batch.Delete(key); + thread->stats.FinishedSingleOp(); + } + s = db_->Write(write_options_, &batch); + if (!s.ok()) { + fprintf(stderr, "del error: %s\n", s.ToString().c_str()); + exit(1); + } + } + } + + void DeleteSeq(ThreadState* thread) { + DoDelete(thread, true); + } + + void DeleteRandom(ThreadState* thread) { + DoDelete(thread, false); + } + + void ReadWhileWriting(ThreadState* thread) { + if (thread->tid > 0) { + ReadRandom(thread); + } else { + // Special thread that keeps writing until other threads are done. + RandomGenerator gen; + while (true) { + { + MutexLock l(&thread->shared->mu); + if (thread->shared->num_done + 1 >= thread->shared->num_initialized) { + // Other threads have finished + break; + } + } + + const int k = thread->rand.Next() % FLAGS_num; + char key[100]; + snprintf(key, sizeof(key), "%016d", k); + Status s = db_->Put(write_options_, key, gen.Generate(value_size_)); + if (!s.ok()) { + fprintf(stderr, "put error: %s\n", s.ToString().c_str()); + exit(1); + } + } + + // Do not count any of the preceding work/delay in stats. + thread->stats.Start(); + } + } + + void Compact(ThreadState* thread) { + db_->CompactRange(NULL, NULL); + } + + void PrintStats(const char* key) { + std::string stats; + if (!db_->GetProperty(key, &stats)) { + stats = "(failed)"; + } + fprintf(stdout, "\n%s\n", stats.c_str()); + } + + static void WriteToFile(void* arg, const char* buf, int n) { + reinterpret_cast(arg)->Append(Slice(buf, n)); + } + + void HeapProfile() { + char fname[100]; + snprintf(fname, sizeof(fname), "%s/heap-%04d", FLAGS_db, ++heap_counter_); + WritableFile* file; + Status s = Env::Default()->NewWritableFile(fname, &file); + if (!s.ok()) { + fprintf(stderr, "%s\n", s.ToString().c_str()); + return; + } + bool ok = port::GetHeapProfile(WriteToFile, file); + delete file; + if (!ok) { + fprintf(stderr, "heap profiling not supported\n"); + Env::Default()->DeleteFile(fname); + } + } +}; + +} // namespace leveldb + +int main(int argc, char** argv) { + FLAGS_write_buffer_size = leveldb::Options().write_buffer_size; + FLAGS_open_files = leveldb::Options().max_open_files; + std::string default_db_path; + + for (int i = 1; i < argc; i++) { + double d; + int n; + char junk; + if (leveldb::Slice(argv[i]).starts_with("--benchmarks=")) { + FLAGS_benchmarks = argv[i] + strlen("--benchmarks="); + } else if (sscanf(argv[i], "--compression_ratio=%lf%c", &d, &junk) == 1) { + FLAGS_compression_ratio = d; + } else if (sscanf(argv[i], "--histogram=%d%c", &n, &junk) == 1 && + (n == 0 || n == 1)) { + FLAGS_histogram = n; + } else if (sscanf(argv[i], "--use_existing_db=%d%c", &n, &junk) == 1 && + (n == 0 || n == 1)) { + FLAGS_use_existing_db = n; + } else if (sscanf(argv[i], "--num=%d%c", &n, &junk) == 1) { + FLAGS_num = n; + } else if (sscanf(argv[i], "--reads=%d%c", &n, &junk) == 1) { + FLAGS_reads = n; + } else if (sscanf(argv[i], "--threads=%d%c", &n, &junk) == 1) { + FLAGS_threads = n; + } else if (sscanf(argv[i], "--value_size=%d%c", &n, &junk) == 1) { + FLAGS_value_size = n; + } else if (sscanf(argv[i], "--write_buffer_size=%d%c", &n, &junk) == 1) { + FLAGS_write_buffer_size = n; + } else if (sscanf(argv[i], "--cache_size=%d%c", &n, &junk) == 1) { + FLAGS_cache_size = n; + } else if (sscanf(argv[i], "--bloom_bits=%d%c", &n, &junk) == 1) { + FLAGS_bloom_bits = n; + } else if (sscanf(argv[i], "--open_files=%d%c", &n, &junk) == 1) { + FLAGS_open_files = n; + } else if (strncmp(argv[i], "--db=", 5) == 0) { + FLAGS_db = argv[i] + 5; + } else { + fprintf(stderr, "Invalid flag '%s'\n", argv[i]); + exit(1); + } + } + + // Choose a location for the test database if none given with --db= + if (FLAGS_db == NULL) { + leveldb::Env::Default()->GetTestDirectory(&default_db_path); + default_db_path += "/dbbench"; + FLAGS_db = default_db_path.c_str(); + } + + leveldb::Benchmark benchmark; + benchmark.Run(); + return 0; +} diff --git a/ios/Pods/leveldb-library/db/db_impl.cc b/ios/Pods/leveldb-library/db/db_impl.cc new file mode 100644 index 000000000..49b95953b --- /dev/null +++ b/ios/Pods/leveldb-library/db/db_impl.cc @@ -0,0 +1,1513 @@ +// Copyright (c) 2011 The LevelDB Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. See the AUTHORS file for names of contributors. + +#include "db/db_impl.h" + +#include +#include +#include +#include +#include +#include +#include "db/builder.h" +#include "db/db_iter.h" +#include "db/dbformat.h" +#include "db/filename.h" +#include "db/log_reader.h" +#include "db/log_writer.h" +#include "db/memtable.h" +#include "db/table_cache.h" +#include "db/version_set.h" +#include "db/write_batch_internal.h" +#include "leveldb/db.h" +#include "leveldb/env.h" +#include "leveldb/status.h" +#include "leveldb/table.h" +#include "leveldb/table_builder.h" +#include "port/port.h" +#include "table/block.h" +#include "table/merger.h" +#include "table/two_level_iterator.h" +#include "util/coding.h" +#include "util/logging.h" +#include "util/mutexlock.h" + +namespace leveldb { + +const int kNumNonTableCacheFiles = 10; + +// Information kept for every waiting writer +struct DBImpl::Writer { + Status status; + WriteBatch* batch; + bool sync; + bool done; + port::CondVar cv; + + explicit Writer(port::Mutex* mu) : cv(mu) { } +}; + +struct DBImpl::CompactionState { + Compaction* const compaction; + + // Sequence numbers < smallest_snapshot are not significant since we + // will never have to service a snapshot below smallest_snapshot. + // Therefore if we have seen a sequence number S <= smallest_snapshot, + // we can drop all entries for the same key with sequence numbers < S. + SequenceNumber smallest_snapshot; + + // Files produced by compaction + struct Output { + uint64_t number; + uint64_t file_size; + InternalKey smallest, largest; + }; + std::vector outputs; + + // State kept for output being generated + WritableFile* outfile; + TableBuilder* builder; + + uint64_t total_bytes; + + Output* current_output() { return &outputs[outputs.size()-1]; } + + explicit CompactionState(Compaction* c) + : compaction(c), + outfile(NULL), + builder(NULL), + total_bytes(0) { + } +}; + +// Fix user-supplied options to be reasonable +template +static void ClipToRange(T* ptr, V minvalue, V maxvalue) { + if (static_cast(*ptr) > maxvalue) *ptr = maxvalue; + if (static_cast(*ptr) < minvalue) *ptr = minvalue; +} +Options SanitizeOptions(const std::string& dbname, + const InternalKeyComparator* icmp, + const InternalFilterPolicy* ipolicy, + const Options& src) { + Options result = src; + result.comparator = icmp; + result.filter_policy = (src.filter_policy != NULL) ? ipolicy : NULL; + ClipToRange(&result.max_open_files, 64 + kNumNonTableCacheFiles, 50000); + ClipToRange(&result.write_buffer_size, 64<<10, 1<<30); + ClipToRange(&result.block_size, 1<<10, 4<<20); + if (result.info_log == NULL) { + // Open a log file in the same directory as the db + src.env->CreateDir(dbname); // In case it does not exist + src.env->RenameFile(InfoLogFileName(dbname), OldInfoLogFileName(dbname)); + Status s = src.env->NewLogger(InfoLogFileName(dbname), &result.info_log); + if (!s.ok()) { + // No place suitable for logging + result.info_log = NULL; + } + } + if (result.block_cache == NULL) { + result.block_cache = NewLRUCache(8 << 20); + } + return result; +} + +DBImpl::DBImpl(const Options& raw_options, const std::string& dbname) + : env_(raw_options.env), + internal_comparator_(raw_options.comparator), + internal_filter_policy_(raw_options.filter_policy), + options_(SanitizeOptions(dbname, &internal_comparator_, + &internal_filter_policy_, raw_options)), + owns_info_log_(options_.info_log != raw_options.info_log), + owns_cache_(options_.block_cache != raw_options.block_cache), + dbname_(dbname), + db_lock_(NULL), + shutting_down_(NULL), + bg_cv_(&mutex_), + mem_(new MemTable(internal_comparator_)), + imm_(NULL), + logfile_(NULL), + logfile_number_(0), + log_(NULL), + seed_(0), + tmp_batch_(new WriteBatch), + bg_compaction_scheduled_(false), + manual_compaction_(NULL) { + mem_->Ref(); + has_imm_.Release_Store(NULL); + + // Reserve ten files or so for other uses and give the rest to TableCache. + const int table_cache_size = options_.max_open_files - kNumNonTableCacheFiles; + table_cache_ = new TableCache(dbname_, &options_, table_cache_size); + + versions_ = new VersionSet(dbname_, &options_, table_cache_, + &internal_comparator_); +} + +DBImpl::~DBImpl() { + // Wait for background work to finish + mutex_.Lock(); + shutting_down_.Release_Store(this); // Any non-NULL value is ok + while (bg_compaction_scheduled_) { + bg_cv_.Wait(); + } + mutex_.Unlock(); + + if (db_lock_ != NULL) { + env_->UnlockFile(db_lock_); + } + + delete versions_; + if (mem_ != NULL) mem_->Unref(); + if (imm_ != NULL) imm_->Unref(); + delete tmp_batch_; + delete log_; + delete logfile_; + delete table_cache_; + + if (owns_info_log_) { + delete options_.info_log; + } + if (owns_cache_) { + delete options_.block_cache; + } +} + +Status DBImpl::NewDB() { + VersionEdit new_db; + new_db.SetComparatorName(user_comparator()->Name()); + new_db.SetLogNumber(0); + new_db.SetNextFile(2); + new_db.SetLastSequence(0); + + const std::string manifest = DescriptorFileName(dbname_, 1); + WritableFile* file; + Status s = env_->NewWritableFile(manifest, &file); + if (!s.ok()) { + return s; + } + { + log::Writer log(file); + std::string record; + new_db.EncodeTo(&record); + s = log.AddRecord(record); + if (s.ok()) { + s = file->Close(); + } + } + delete file; + if (s.ok()) { + // Make "CURRENT" file that points to the new manifest file. + s = SetCurrentFile(env_, dbname_, 1); + } else { + env_->DeleteFile(manifest); + } + return s; +} + +void DBImpl::MaybeIgnoreError(Status* s) const { + if (s->ok() || options_.paranoid_checks) { + // No change needed + } else { + Log(options_.info_log, "Ignoring error %s", s->ToString().c_str()); + *s = Status::OK(); + } +} + +void DBImpl::DeleteObsoleteFiles() { + if (!bg_error_.ok()) { + // After a background error, we don't know whether a new version may + // or may not have been committed, so we cannot safely garbage collect. + return; + } + + // Make a set of all of the live files + std::set live = pending_outputs_; + versions_->AddLiveFiles(&live); + + std::vector filenames; + env_->GetChildren(dbname_, &filenames); // Ignoring errors on purpose + uint64_t number; + FileType type; + for (size_t i = 0; i < filenames.size(); i++) { + if (ParseFileName(filenames[i], &number, &type)) { + bool keep = true; + switch (type) { + case kLogFile: + keep = ((number >= versions_->LogNumber()) || + (number == versions_->PrevLogNumber())); + break; + case kDescriptorFile: + // Keep my manifest file, and any newer incarnations' + // (in case there is a race that allows other incarnations) + keep = (number >= versions_->ManifestFileNumber()); + break; + case kTableFile: + keep = (live.find(number) != live.end()); + break; + case kTempFile: + // Any temp files that are currently being written to must + // be recorded in pending_outputs_, which is inserted into "live" + keep = (live.find(number) != live.end()); + break; + case kCurrentFile: + case kDBLockFile: + case kInfoLogFile: + keep = true; + break; + } + + if (!keep) { + if (type == kTableFile) { + table_cache_->Evict(number); + } + Log(options_.info_log, "Delete type=%d #%lld\n", + int(type), + static_cast(number)); + env_->DeleteFile(dbname_ + "/" + filenames[i]); + } + } + } +} + +Status DBImpl::Recover(VersionEdit* edit) { + mutex_.AssertHeld(); + + // Ignore error from CreateDir since the creation of the DB is + // committed only when the descriptor is created, and this directory + // may already exist from a previous failed creation attempt. + env_->CreateDir(dbname_); + assert(db_lock_ == NULL); + Status s = env_->LockFile(LockFileName(dbname_), &db_lock_); + if (!s.ok()) { + return s; + } + + if (!env_->FileExists(CurrentFileName(dbname_))) { + if (options_.create_if_missing) { + s = NewDB(); + if (!s.ok()) { + return s; + } + } else { + return Status::InvalidArgument( + dbname_, "does not exist (create_if_missing is false)"); + } + } else { + if (options_.error_if_exists) { + return Status::InvalidArgument( + dbname_, "exists (error_if_exists is true)"); + } + } + + s = versions_->Recover(); + if (s.ok()) { + SequenceNumber max_sequence(0); + + // Recover from all newer log files than the ones named in the + // descriptor (new log files may have been added by the previous + // incarnation without registering them in the descriptor). + // + // Note that PrevLogNumber() is no longer used, but we pay + // attention to it in case we are recovering a database + // produced by an older version of leveldb. + const uint64_t min_log = versions_->LogNumber(); + const uint64_t prev_log = versions_->PrevLogNumber(); + std::vector filenames; + s = env_->GetChildren(dbname_, &filenames); + if (!s.ok()) { + return s; + } + std::set expected; + versions_->AddLiveFiles(&expected); + uint64_t number; + FileType type; + std::vector logs; + for (size_t i = 0; i < filenames.size(); i++) { + if (ParseFileName(filenames[i], &number, &type)) { + expected.erase(number); + if (type == kLogFile && ((number >= min_log) || (number == prev_log))) + logs.push_back(number); + } + } + if (!expected.empty()) { + char buf[50]; + snprintf(buf, sizeof(buf), "%d missing files; e.g.", + static_cast(expected.size())); + return Status::Corruption(buf, TableFileName(dbname_, *(expected.begin()))); + } + + // Recover in the order in which the logs were generated + std::sort(logs.begin(), logs.end()); + for (size_t i = 0; i < logs.size(); i++) { + s = RecoverLogFile(logs[i], edit, &max_sequence); + + // The previous incarnation may not have written any MANIFEST + // records after allocating this log number. So we manually + // update the file number allocation counter in VersionSet. + versions_->MarkFileNumberUsed(logs[i]); + } + + if (s.ok()) { + if (versions_->LastSequence() < max_sequence) { + versions_->SetLastSequence(max_sequence); + } + } + } + + return s; +} + +Status DBImpl::RecoverLogFile(uint64_t log_number, + VersionEdit* edit, + SequenceNumber* max_sequence) { + struct LogReporter : public log::Reader::Reporter { + Env* env; + Logger* info_log; + const char* fname; + Status* status; // NULL if options_.paranoid_checks==false + virtual void Corruption(size_t bytes, const Status& s) { + Log(info_log, "%s%s: dropping %d bytes; %s", + (this->status == NULL ? "(ignoring error) " : ""), + fname, static_cast(bytes), s.ToString().c_str()); + if (this->status != NULL && this->status->ok()) *this->status = s; + } + }; + + mutex_.AssertHeld(); + + // Open the log file + std::string fname = LogFileName(dbname_, log_number); + SequentialFile* file; + Status status = env_->NewSequentialFile(fname, &file); + if (!status.ok()) { + MaybeIgnoreError(&status); + return status; + } + + // Create the log reader. + LogReporter reporter; + reporter.env = env_; + reporter.info_log = options_.info_log; + reporter.fname = fname.c_str(); + reporter.status = (options_.paranoid_checks ? &status : NULL); + // We intentionally make log::Reader do checksumming even if + // paranoid_checks==false so that corruptions cause entire commits + // to be skipped instead of propagating bad information (like overly + // large sequence numbers). + log::Reader reader(file, &reporter, true/*checksum*/, + 0/*initial_offset*/); + Log(options_.info_log, "Recovering log #%llu", + (unsigned long long) log_number); + + // Read all the records and add to a memtable + std::string scratch; + Slice record; + WriteBatch batch; + MemTable* mem = NULL; + while (reader.ReadRecord(&record, &scratch) && + status.ok()) { + if (record.size() < 12) { + reporter.Corruption( + record.size(), Status::Corruption("log record too small")); + continue; + } + WriteBatchInternal::SetContents(&batch, record); + + if (mem == NULL) { + mem = new MemTable(internal_comparator_); + mem->Ref(); + } + status = WriteBatchInternal::InsertInto(&batch, mem); + MaybeIgnoreError(&status); + if (!status.ok()) { + break; + } + const SequenceNumber last_seq = + WriteBatchInternal::Sequence(&batch) + + WriteBatchInternal::Count(&batch) - 1; + if (last_seq > *max_sequence) { + *max_sequence = last_seq; + } + + if (mem->ApproximateMemoryUsage() > options_.write_buffer_size) { + status = WriteLevel0Table(mem, edit, NULL); + if (!status.ok()) { + // Reflect errors immediately so that conditions like full + // file-systems cause the DB::Open() to fail. + break; + } + mem->Unref(); + mem = NULL; + } + } + + if (status.ok() && mem != NULL) { + status = WriteLevel0Table(mem, edit, NULL); + // Reflect errors immediately so that conditions like full + // file-systems cause the DB::Open() to fail. + } + + if (mem != NULL) mem->Unref(); + delete file; + return status; +} + +Status DBImpl::WriteLevel0Table(MemTable* mem, VersionEdit* edit, + Version* base) { + mutex_.AssertHeld(); + const uint64_t start_micros = env_->NowMicros(); + FileMetaData meta; + meta.number = versions_->NewFileNumber(); + pending_outputs_.insert(meta.number); + Iterator* iter = mem->NewIterator(); + Log(options_.info_log, "Level-0 table #%llu: started", + (unsigned long long) meta.number); + + Status s; + { + mutex_.Unlock(); + s = BuildTable(dbname_, env_, options_, table_cache_, iter, &meta); + mutex_.Lock(); + } + + Log(options_.info_log, "Level-0 table #%llu: %lld bytes %s", + (unsigned long long) meta.number, + (unsigned long long) meta.file_size, + s.ToString().c_str()); + delete iter; + pending_outputs_.erase(meta.number); + + + // Note that if file_size is zero, the file has been deleted and + // should not be added to the manifest. + int level = 0; + if (s.ok() && meta.file_size > 0) { + const Slice min_user_key = meta.smallest.user_key(); + const Slice max_user_key = meta.largest.user_key(); + if (base != NULL) { + level = base->PickLevelForMemTableOutput(min_user_key, max_user_key); + } + edit->AddFile(level, meta.number, meta.file_size, + meta.smallest, meta.largest); + } + + CompactionStats stats; + stats.micros = env_->NowMicros() - start_micros; + stats.bytes_written = meta.file_size; + stats_[level].Add(stats); + return s; +} + +void DBImpl::CompactMemTable() { + mutex_.AssertHeld(); + assert(imm_ != NULL); + + // Save the contents of the memtable as a new Table + VersionEdit edit; + Version* base = versions_->current(); + base->Ref(); + Status s = WriteLevel0Table(imm_, &edit, base); + base->Unref(); + + if (s.ok() && shutting_down_.Acquire_Load()) { + s = Status::IOError("Deleting DB during memtable compaction"); + } + + // Replace immutable memtable with the generated Table + if (s.ok()) { + edit.SetPrevLogNumber(0); + edit.SetLogNumber(logfile_number_); // Earlier logs no longer needed + s = versions_->LogAndApply(&edit, &mutex_); + } + + if (s.ok()) { + // Commit to the new state + imm_->Unref(); + imm_ = NULL; + has_imm_.Release_Store(NULL); + DeleteObsoleteFiles(); + } else { + RecordBackgroundError(s); + } +} + +void DBImpl::CompactRange(const Slice* begin, const Slice* end) { + int max_level_with_files = 1; + { + MutexLock l(&mutex_); + Version* base = versions_->current(); + for (int level = 1; level < config::kNumLevels; level++) { + if (base->OverlapInLevel(level, begin, end)) { + max_level_with_files = level; + } + } + } + TEST_CompactMemTable(); // TODO(sanjay): Skip if memtable does not overlap + for (int level = 0; level < max_level_with_files; level++) { + TEST_CompactRange(level, begin, end); + } +} + +void DBImpl::TEST_CompactRange(int level, const Slice* begin,const Slice* end) { + assert(level >= 0); + assert(level + 1 < config::kNumLevels); + + InternalKey begin_storage, end_storage; + + ManualCompaction manual; + manual.level = level; + manual.done = false; + if (begin == NULL) { + manual.begin = NULL; + } else { + begin_storage = InternalKey(*begin, kMaxSequenceNumber, kValueTypeForSeek); + manual.begin = &begin_storage; + } + if (end == NULL) { + manual.end = NULL; + } else { + end_storage = InternalKey(*end, 0, static_cast(0)); + manual.end = &end_storage; + } + + MutexLock l(&mutex_); + while (!manual.done && !shutting_down_.Acquire_Load() && bg_error_.ok()) { + if (manual_compaction_ == NULL) { // Idle + manual_compaction_ = &manual; + MaybeScheduleCompaction(); + } else { // Running either my compaction or another compaction. + bg_cv_.Wait(); + } + } + if (manual_compaction_ == &manual) { + // Cancel my manual compaction since we aborted early for some reason. + manual_compaction_ = NULL; + } +} + +Status DBImpl::TEST_CompactMemTable() { + // NULL batch means just wait for earlier writes to be done + Status s = Write(WriteOptions(), NULL); + if (s.ok()) { + // Wait until the compaction completes + MutexLock l(&mutex_); + while (imm_ != NULL && bg_error_.ok()) { + bg_cv_.Wait(); + } + if (imm_ != NULL) { + s = bg_error_; + } + } + return s; +} + +void DBImpl::RecordBackgroundError(const Status& s) { + mutex_.AssertHeld(); + if (bg_error_.ok()) { + bg_error_ = s; + bg_cv_.SignalAll(); + } +} + +void DBImpl::MaybeScheduleCompaction() { + mutex_.AssertHeld(); + if (bg_compaction_scheduled_) { + // Already scheduled + } else if (shutting_down_.Acquire_Load()) { + // DB is being deleted; no more background compactions + } else if (!bg_error_.ok()) { + // Already got an error; no more changes + } else if (imm_ == NULL && + manual_compaction_ == NULL && + !versions_->NeedsCompaction()) { + // No work to be done + } else { + bg_compaction_scheduled_ = true; + env_->Schedule(&DBImpl::BGWork, this); + } +} + +void DBImpl::BGWork(void* db) { + reinterpret_cast(db)->BackgroundCall(); +} + +void DBImpl::BackgroundCall() { + MutexLock l(&mutex_); + assert(bg_compaction_scheduled_); + if (shutting_down_.Acquire_Load()) { + // No more background work when shutting down. + } else if (!bg_error_.ok()) { + // No more background work after a background error. + } else { + BackgroundCompaction(); + } + + bg_compaction_scheduled_ = false; + + // Previous compaction may have produced too many files in a level, + // so reschedule another compaction if needed. + MaybeScheduleCompaction(); + bg_cv_.SignalAll(); +} + +void DBImpl::BackgroundCompaction() { + mutex_.AssertHeld(); + + if (imm_ != NULL) { + CompactMemTable(); + return; + } + + Compaction* c; + bool is_manual = (manual_compaction_ != NULL); + InternalKey manual_end; + if (is_manual) { + ManualCompaction* m = manual_compaction_; + c = versions_->CompactRange(m->level, m->begin, m->end); + m->done = (c == NULL); + if (c != NULL) { + manual_end = c->input(0, c->num_input_files(0) - 1)->largest; + } + Log(options_.info_log, + "Manual compaction at level-%d from %s .. %s; will stop at %s\n", + m->level, + (m->begin ? m->begin->DebugString().c_str() : "(begin)"), + (m->end ? m->end->DebugString().c_str() : "(end)"), + (m->done ? "(end)" : manual_end.DebugString().c_str())); + } else { + c = versions_->PickCompaction(); + } + + Status status; + if (c == NULL) { + // Nothing to do + } else if (!is_manual && c->IsTrivialMove()) { + // Move file to next level + assert(c->num_input_files(0) == 1); + FileMetaData* f = c->input(0, 0); + c->edit()->DeleteFile(c->level(), f->number); + c->edit()->AddFile(c->level() + 1, f->number, f->file_size, + f->smallest, f->largest); + status = versions_->LogAndApply(c->edit(), &mutex_); + if (!status.ok()) { + RecordBackgroundError(status); + } + VersionSet::LevelSummaryStorage tmp; + Log(options_.info_log, "Moved #%lld to level-%d %lld bytes %s: %s\n", + static_cast(f->number), + c->level() + 1, + static_cast(f->file_size), + status.ToString().c_str(), + versions_->LevelSummary(&tmp)); + } else { + CompactionState* compact = new CompactionState(c); + status = DoCompactionWork(compact); + if (!status.ok()) { + RecordBackgroundError(status); + } + CleanupCompaction(compact); + c->ReleaseInputs(); + DeleteObsoleteFiles(); + } + delete c; + + if (status.ok()) { + // Done + } else if (shutting_down_.Acquire_Load()) { + // Ignore compaction errors found during shutting down + } else { + Log(options_.info_log, + "Compaction error: %s", status.ToString().c_str()); + } + + if (is_manual) { + ManualCompaction* m = manual_compaction_; + if (!status.ok()) { + m->done = true; + } + if (!m->done) { + // We only compacted part of the requested range. Update *m + // to the range that is left to be compacted. + m->tmp_storage = manual_end; + m->begin = &m->tmp_storage; + } + manual_compaction_ = NULL; + } +} + +void DBImpl::CleanupCompaction(CompactionState* compact) { + mutex_.AssertHeld(); + if (compact->builder != NULL) { + // May happen if we get a shutdown call in the middle of compaction + compact->builder->Abandon(); + delete compact->builder; + } else { + assert(compact->outfile == NULL); + } + delete compact->outfile; + for (size_t i = 0; i < compact->outputs.size(); i++) { + const CompactionState::Output& out = compact->outputs[i]; + pending_outputs_.erase(out.number); + } + delete compact; +} + +Status DBImpl::OpenCompactionOutputFile(CompactionState* compact) { + assert(compact != NULL); + assert(compact->builder == NULL); + uint64_t file_number; + { + mutex_.Lock(); + file_number = versions_->NewFileNumber(); + pending_outputs_.insert(file_number); + CompactionState::Output out; + out.number = file_number; + out.smallest.Clear(); + out.largest.Clear(); + compact->outputs.push_back(out); + mutex_.Unlock(); + } + + // Make the output file + std::string fname = TableFileName(dbname_, file_number); + Status s = env_->NewWritableFile(fname, &compact->outfile); + if (s.ok()) { + compact->builder = new TableBuilder(options_, compact->outfile); + } + return s; +} + +Status DBImpl::FinishCompactionOutputFile(CompactionState* compact, + Iterator* input) { + assert(compact != NULL); + assert(compact->outfile != NULL); + assert(compact->builder != NULL); + + const uint64_t output_number = compact->current_output()->number; + assert(output_number != 0); + + // Check for iterator errors + Status s = input->status(); + const uint64_t current_entries = compact->builder->NumEntries(); + if (s.ok()) { + s = compact->builder->Finish(); + } else { + compact->builder->Abandon(); + } + const uint64_t current_bytes = compact->builder->FileSize(); + compact->current_output()->file_size = current_bytes; + compact->total_bytes += current_bytes; + delete compact->builder; + compact->builder = NULL; + + // Finish and check for file errors + if (s.ok()) { + s = compact->outfile->Sync(); + } + if (s.ok()) { + s = compact->outfile->Close(); + } + delete compact->outfile; + compact->outfile = NULL; + + if (s.ok() && current_entries > 0) { + // Verify that the table is usable + Iterator* iter = table_cache_->NewIterator(ReadOptions(), + output_number, + current_bytes); + s = iter->status(); + delete iter; + if (s.ok()) { + Log(options_.info_log, + "Generated table #%llu: %lld keys, %lld bytes", + (unsigned long long) output_number, + (unsigned long long) current_entries, + (unsigned long long) current_bytes); + } + } + return s; +} + + +Status DBImpl::InstallCompactionResults(CompactionState* compact) { + mutex_.AssertHeld(); + Log(options_.info_log, "Compacted %d@%d + %d@%d files => %lld bytes", + compact->compaction->num_input_files(0), + compact->compaction->level(), + compact->compaction->num_input_files(1), + compact->compaction->level() + 1, + static_cast(compact->total_bytes)); + + // Add compaction outputs + compact->compaction->AddInputDeletions(compact->compaction->edit()); + const int level = compact->compaction->level(); + for (size_t i = 0; i < compact->outputs.size(); i++) { + const CompactionState::Output& out = compact->outputs[i]; + compact->compaction->edit()->AddFile( + level + 1, + out.number, out.file_size, out.smallest, out.largest); + } + return versions_->LogAndApply(compact->compaction->edit(), &mutex_); +} + +Status DBImpl::DoCompactionWork(CompactionState* compact) { + const uint64_t start_micros = env_->NowMicros(); + int64_t imm_micros = 0; // Micros spent doing imm_ compactions + + Log(options_.info_log, "Compacting %d@%d + %d@%d files", + compact->compaction->num_input_files(0), + compact->compaction->level(), + compact->compaction->num_input_files(1), + compact->compaction->level() + 1); + + assert(versions_->NumLevelFiles(compact->compaction->level()) > 0); + assert(compact->builder == NULL); + assert(compact->outfile == NULL); + if (snapshots_.empty()) { + compact->smallest_snapshot = versions_->LastSequence(); + } else { + compact->smallest_snapshot = snapshots_.oldest()->number_; + } + + // Release mutex while we're actually doing the compaction work + mutex_.Unlock(); + + Iterator* input = versions_->MakeInputIterator(compact->compaction); + input->SeekToFirst(); + Status status; + ParsedInternalKey ikey; + std::string current_user_key; + bool has_current_user_key = false; + SequenceNumber last_sequence_for_key = kMaxSequenceNumber; + for (; input->Valid() && !shutting_down_.Acquire_Load(); ) { + // Prioritize immutable compaction work + if (has_imm_.NoBarrier_Load() != NULL) { + const uint64_t imm_start = env_->NowMicros(); + mutex_.Lock(); + if (imm_ != NULL) { + CompactMemTable(); + bg_cv_.SignalAll(); // Wakeup MakeRoomForWrite() if necessary + } + mutex_.Unlock(); + imm_micros += (env_->NowMicros() - imm_start); + } + + Slice key = input->key(); + if (compact->compaction->ShouldStopBefore(key) && + compact->builder != NULL) { + status = FinishCompactionOutputFile(compact, input); + if (!status.ok()) { + break; + } + } + + // Handle key/value, add to state, etc. + bool drop = false; + if (!ParseInternalKey(key, &ikey)) { + // Do not hide error keys + current_user_key.clear(); + has_current_user_key = false; + last_sequence_for_key = kMaxSequenceNumber; + } else { + if (!has_current_user_key || + user_comparator()->Compare(ikey.user_key, + Slice(current_user_key)) != 0) { + // First occurrence of this user key + current_user_key.assign(ikey.user_key.data(), ikey.user_key.size()); + has_current_user_key = true; + last_sequence_for_key = kMaxSequenceNumber; + } + + if (last_sequence_for_key <= compact->smallest_snapshot) { + // Hidden by an newer entry for same user key + drop = true; // (A) + } else if (ikey.type == kTypeDeletion && + ikey.sequence <= compact->smallest_snapshot && + compact->compaction->IsBaseLevelForKey(ikey.user_key)) { + // For this user key: + // (1) there is no data in higher levels + // (2) data in lower levels will have larger sequence numbers + // (3) data in layers that are being compacted here and have + // smaller sequence numbers will be dropped in the next + // few iterations of this loop (by rule (A) above). + // Therefore this deletion marker is obsolete and can be dropped. + drop = true; + } + + last_sequence_for_key = ikey.sequence; + } +#if 0 + Log(options_.info_log, + " Compact: %s, seq %d, type: %d %d, drop: %d, is_base: %d, " + "%d smallest_snapshot: %d", + ikey.user_key.ToString().c_str(), + (int)ikey.sequence, ikey.type, kTypeValue, drop, + compact->compaction->IsBaseLevelForKey(ikey.user_key), + (int)last_sequence_for_key, (int)compact->smallest_snapshot); +#endif + + if (!drop) { + // Open output file if necessary + if (compact->builder == NULL) { + status = OpenCompactionOutputFile(compact); + if (!status.ok()) { + break; + } + } + if (compact->builder->NumEntries() == 0) { + compact->current_output()->smallest.DecodeFrom(key); + } + compact->current_output()->largest.DecodeFrom(key); + compact->builder->Add(key, input->value()); + + // Close output file if it is big enough + if (compact->builder->FileSize() >= + compact->compaction->MaxOutputFileSize()) { + status = FinishCompactionOutputFile(compact, input); + if (!status.ok()) { + break; + } + } + } + + input->Next(); + } + + if (status.ok() && shutting_down_.Acquire_Load()) { + status = Status::IOError("Deleting DB during compaction"); + } + if (status.ok() && compact->builder != NULL) { + status = FinishCompactionOutputFile(compact, input); + } + if (status.ok()) { + status = input->status(); + } + delete input; + input = NULL; + + CompactionStats stats; + stats.micros = env_->NowMicros() - start_micros - imm_micros; + for (int which = 0; which < 2; which++) { + for (int i = 0; i < compact->compaction->num_input_files(which); i++) { + stats.bytes_read += compact->compaction->input(which, i)->file_size; + } + } + for (size_t i = 0; i < compact->outputs.size(); i++) { + stats.bytes_written += compact->outputs[i].file_size; + } + + mutex_.Lock(); + stats_[compact->compaction->level() + 1].Add(stats); + + if (status.ok()) { + status = InstallCompactionResults(compact); + } + if (!status.ok()) { + RecordBackgroundError(status); + } + VersionSet::LevelSummaryStorage tmp; + Log(options_.info_log, + "compacted to: %s", versions_->LevelSummary(&tmp)); + return status; +} + +namespace { +struct IterState { + port::Mutex* mu; + Version* version; + MemTable* mem; + MemTable* imm; +}; + +static void CleanupIteratorState(void* arg1, void* arg2) { + IterState* state = reinterpret_cast(arg1); + state->mu->Lock(); + state->mem->Unref(); + if (state->imm != NULL) state->imm->Unref(); + state->version->Unref(); + state->mu->Unlock(); + delete state; +} +} // namespace + +Iterator* DBImpl::NewInternalIterator(const ReadOptions& options, + SequenceNumber* latest_snapshot, + uint32_t* seed) { + IterState* cleanup = new IterState; + mutex_.Lock(); + *latest_snapshot = versions_->LastSequence(); + + // Collect together all needed child iterators + std::vector list; + list.push_back(mem_->NewIterator()); + mem_->Ref(); + if (imm_ != NULL) { + list.push_back(imm_->NewIterator()); + imm_->Ref(); + } + versions_->current()->AddIterators(options, &list); + Iterator* internal_iter = + NewMergingIterator(&internal_comparator_, &list[0], list.size()); + versions_->current()->Ref(); + + cleanup->mu = &mutex_; + cleanup->mem = mem_; + cleanup->imm = imm_; + cleanup->version = versions_->current(); + internal_iter->RegisterCleanup(CleanupIteratorState, cleanup, NULL); + + *seed = ++seed_; + mutex_.Unlock(); + return internal_iter; +} + +Iterator* DBImpl::TEST_NewInternalIterator() { + SequenceNumber ignored; + uint32_t ignored_seed; + return NewInternalIterator(ReadOptions(), &ignored, &ignored_seed); +} + +int64_t DBImpl::TEST_MaxNextLevelOverlappingBytes() { + MutexLock l(&mutex_); + return versions_->MaxNextLevelOverlappingBytes(); +} + +Status DBImpl::Get(const ReadOptions& options, + const Slice& key, + std::string* value) { + Status s; + MutexLock l(&mutex_); + SequenceNumber snapshot; + if (options.snapshot != NULL) { + snapshot = reinterpret_cast(options.snapshot)->number_; + } else { + snapshot = versions_->LastSequence(); + } + + MemTable* mem = mem_; + MemTable* imm = imm_; + Version* current = versions_->current(); + mem->Ref(); + if (imm != NULL) imm->Ref(); + current->Ref(); + + bool have_stat_update = false; + Version::GetStats stats; + + // Unlock while reading from files and memtables + { + mutex_.Unlock(); + // First look in the memtable, then in the immutable memtable (if any). + LookupKey lkey(key, snapshot); + if (mem->Get(lkey, value, &s)) { + // Done + } else if (imm != NULL && imm->Get(lkey, value, &s)) { + // Done + } else { + s = current->Get(options, lkey, value, &stats); + have_stat_update = true; + } + mutex_.Lock(); + } + + if (have_stat_update && current->UpdateStats(stats)) { + MaybeScheduleCompaction(); + } + mem->Unref(); + if (imm != NULL) imm->Unref(); + current->Unref(); + return s; +} + +Iterator* DBImpl::NewIterator(const ReadOptions& options) { + SequenceNumber latest_snapshot; + uint32_t seed; + Iterator* iter = NewInternalIterator(options, &latest_snapshot, &seed); + return NewDBIterator( + this, user_comparator(), iter, + (options.snapshot != NULL + ? reinterpret_cast(options.snapshot)->number_ + : latest_snapshot), + seed); +} + +void DBImpl::RecordReadSample(Slice key) { + MutexLock l(&mutex_); + if (versions_->current()->RecordReadSample(key)) { + MaybeScheduleCompaction(); + } +} + +const Snapshot* DBImpl::GetSnapshot() { + MutexLock l(&mutex_); + return snapshots_.New(versions_->LastSequence()); +} + +void DBImpl::ReleaseSnapshot(const Snapshot* s) { + MutexLock l(&mutex_); + snapshots_.Delete(reinterpret_cast(s)); +} + +// Convenience methods +Status DBImpl::Put(const WriteOptions& o, const Slice& key, const Slice& val) { + return DB::Put(o, key, val); +} + +Status DBImpl::Delete(const WriteOptions& options, const Slice& key) { + return DB::Delete(options, key); +} + +Status DBImpl::Write(const WriteOptions& options, WriteBatch* my_batch) { + Writer w(&mutex_); + w.batch = my_batch; + w.sync = options.sync; + w.done = false; + + MutexLock l(&mutex_); + writers_.push_back(&w); + while (!w.done && &w != writers_.front()) { + w.cv.Wait(); + } + if (w.done) { + return w.status; + } + + // May temporarily unlock and wait. + Status status = MakeRoomForWrite(my_batch == NULL); + uint64_t last_sequence = versions_->LastSequence(); + Writer* last_writer = &w; + if (status.ok() && my_batch != NULL) { // NULL batch is for compactions + WriteBatch* updates = BuildBatchGroup(&last_writer); + WriteBatchInternal::SetSequence(updates, last_sequence + 1); + last_sequence += WriteBatchInternal::Count(updates); + + // Add to log and apply to memtable. We can release the lock + // during this phase since &w is currently responsible for logging + // and protects against concurrent loggers and concurrent writes + // into mem_. + { + mutex_.Unlock(); + status = log_->AddRecord(WriteBatchInternal::Contents(updates)); + bool sync_error = false; + if (status.ok() && options.sync) { + status = logfile_->Sync(); + if (!status.ok()) { + sync_error = true; + } + } + if (status.ok()) { + status = WriteBatchInternal::InsertInto(updates, mem_); + } + mutex_.Lock(); + if (sync_error) { + // The state of the log file is indeterminate: the log record we + // just added may or may not show up when the DB is re-opened. + // So we force the DB into a mode where all future writes fail. + RecordBackgroundError(status); + } + } + if (updates == tmp_batch_) tmp_batch_->Clear(); + + versions_->SetLastSequence(last_sequence); + } + + while (true) { + Writer* ready = writers_.front(); + writers_.pop_front(); + if (ready != &w) { + ready->status = status; + ready->done = true; + ready->cv.Signal(); + } + if (ready == last_writer) break; + } + + // Notify new head of write queue + if (!writers_.empty()) { + writers_.front()->cv.Signal(); + } + + return status; +} + +// REQUIRES: Writer list must be non-empty +// REQUIRES: First writer must have a non-NULL batch +WriteBatch* DBImpl::BuildBatchGroup(Writer** last_writer) { + assert(!writers_.empty()); + Writer* first = writers_.front(); + WriteBatch* result = first->batch; + assert(result != NULL); + + size_t size = WriteBatchInternal::ByteSize(first->batch); + + // Allow the group to grow up to a maximum size, but if the + // original write is small, limit the growth so we do not slow + // down the small write too much. + size_t max_size = 1 << 20; + if (size <= (128<<10)) { + max_size = size + (128<<10); + } + + *last_writer = first; + std::deque::iterator iter = writers_.begin(); + ++iter; // Advance past "first" + for (; iter != writers_.end(); ++iter) { + Writer* w = *iter; + if (w->sync && !first->sync) { + // Do not include a sync write into a batch handled by a non-sync write. + break; + } + + if (w->batch != NULL) { + size += WriteBatchInternal::ByteSize(w->batch); + if (size > max_size) { + // Do not make batch too big + break; + } + + // Append to *result + if (result == first->batch) { + // Switch to temporary batch instead of disturbing caller's batch + result = tmp_batch_; + assert(WriteBatchInternal::Count(result) == 0); + WriteBatchInternal::Append(result, first->batch); + } + WriteBatchInternal::Append(result, w->batch); + } + *last_writer = w; + } + return result; +} + +// REQUIRES: mutex_ is held +// REQUIRES: this thread is currently at the front of the writer queue +Status DBImpl::MakeRoomForWrite(bool force) { + mutex_.AssertHeld(); + assert(!writers_.empty()); + bool allow_delay = !force; + Status s; + while (true) { + if (!bg_error_.ok()) { + // Yield previous error + s = bg_error_; + break; + } else if ( + allow_delay && + versions_->NumLevelFiles(0) >= config::kL0_SlowdownWritesTrigger) { + // We are getting close to hitting a hard limit on the number of + // L0 files. Rather than delaying a single write by several + // seconds when we hit the hard limit, start delaying each + // individual write by 1ms to reduce latency variance. Also, + // this delay hands over some CPU to the compaction thread in + // case it is sharing the same core as the writer. + mutex_.Unlock(); + env_->SleepForMicroseconds(1000); + allow_delay = false; // Do not delay a single write more than once + mutex_.Lock(); + } else if (!force && + (mem_->ApproximateMemoryUsage() <= options_.write_buffer_size)) { + // There is room in current memtable + break; + } else if (imm_ != NULL) { + // We have filled up the current memtable, but the previous + // one is still being compacted, so we wait. + Log(options_.info_log, "Current memtable full; waiting...\n"); + bg_cv_.Wait(); + } else if (versions_->NumLevelFiles(0) >= config::kL0_StopWritesTrigger) { + // There are too many level-0 files. + Log(options_.info_log, "Too many L0 files; waiting...\n"); + bg_cv_.Wait(); + } else { + // Attempt to switch to a new memtable and trigger compaction of old + assert(versions_->PrevLogNumber() == 0); + uint64_t new_log_number = versions_->NewFileNumber(); + WritableFile* lfile = NULL; + s = env_->NewWritableFile(LogFileName(dbname_, new_log_number), &lfile); + if (!s.ok()) { + // Avoid chewing through file number space in a tight loop. + versions_->ReuseFileNumber(new_log_number); + break; + } + delete log_; + delete logfile_; + logfile_ = lfile; + logfile_number_ = new_log_number; + log_ = new log::Writer(lfile); + imm_ = mem_; + has_imm_.Release_Store(imm_); + mem_ = new MemTable(internal_comparator_); + mem_->Ref(); + force = false; // Do not force another compaction if have room + MaybeScheduleCompaction(); + } + } + return s; +} + +bool DBImpl::GetProperty(const Slice& property, std::string* value) { + value->clear(); + + MutexLock l(&mutex_); + Slice in = property; + Slice prefix("leveldb."); + if (!in.starts_with(prefix)) return false; + in.remove_prefix(prefix.size()); + + if (in.starts_with("num-files-at-level")) { + in.remove_prefix(strlen("num-files-at-level")); + uint64_t level; + bool ok = ConsumeDecimalNumber(&in, &level) && in.empty(); + if (!ok || level >= config::kNumLevels) { + return false; + } else { + char buf[100]; + snprintf(buf, sizeof(buf), "%d", + versions_->NumLevelFiles(static_cast(level))); + *value = buf; + return true; + } + } else if (in == "stats") { + char buf[200]; + snprintf(buf, sizeof(buf), + " Compactions\n" + "Level Files Size(MB) Time(sec) Read(MB) Write(MB)\n" + "--------------------------------------------------\n" + ); + value->append(buf); + for (int level = 0; level < config::kNumLevels; level++) { + int files = versions_->NumLevelFiles(level); + if (stats_[level].micros > 0 || files > 0) { + snprintf( + buf, sizeof(buf), + "%3d %8d %8.0f %9.0f %8.0f %9.0f\n", + level, + files, + versions_->NumLevelBytes(level) / 1048576.0, + stats_[level].micros / 1e6, + stats_[level].bytes_read / 1048576.0, + stats_[level].bytes_written / 1048576.0); + value->append(buf); + } + } + return true; + } else if (in == "sstables") { + *value = versions_->current()->DebugString(); + return true; + } + + return false; +} + +void DBImpl::GetApproximateSizes( + const Range* range, int n, + uint64_t* sizes) { + // TODO(opt): better implementation + Version* v; + { + MutexLock l(&mutex_); + versions_->current()->Ref(); + v = versions_->current(); + } + + for (int i = 0; i < n; i++) { + // Convert user_key into a corresponding internal key. + InternalKey k1(range[i].start, kMaxSequenceNumber, kValueTypeForSeek); + InternalKey k2(range[i].limit, kMaxSequenceNumber, kValueTypeForSeek); + uint64_t start = versions_->ApproximateOffsetOf(v, k1); + uint64_t limit = versions_->ApproximateOffsetOf(v, k2); + sizes[i] = (limit >= start ? limit - start : 0); + } + + { + MutexLock l(&mutex_); + v->Unref(); + } +} + +// Default implementations of convenience methods that subclasses of DB +// can call if they wish +Status DB::Put(const WriteOptions& opt, const Slice& key, const Slice& value) { + WriteBatch batch; + batch.Put(key, value); + return Write(opt, &batch); +} + +Status DB::Delete(const WriteOptions& opt, const Slice& key) { + WriteBatch batch; + batch.Delete(key); + return Write(opt, &batch); +} + +DB::~DB() { } + +Status DB::Open(const Options& options, const std::string& dbname, + DB** dbptr) { + *dbptr = NULL; + + DBImpl* impl = new DBImpl(options, dbname); + impl->mutex_.Lock(); + VersionEdit edit; + Status s = impl->Recover(&edit); // Handles create_if_missing, error_if_exists + if (s.ok()) { + uint64_t new_log_number = impl->versions_->NewFileNumber(); + WritableFile* lfile; + s = options.env->NewWritableFile(LogFileName(dbname, new_log_number), + &lfile); + if (s.ok()) { + edit.SetLogNumber(new_log_number); + impl->logfile_ = lfile; + impl->logfile_number_ = new_log_number; + impl->log_ = new log::Writer(lfile); + s = impl->versions_->LogAndApply(&edit, &impl->mutex_); + } + if (s.ok()) { + impl->DeleteObsoleteFiles(); + impl->MaybeScheduleCompaction(); + } + } + impl->mutex_.Unlock(); + if (s.ok()) { + *dbptr = impl; + } else { + delete impl; + } + return s; +} + +Snapshot::~Snapshot() { +} + +Status DestroyDB(const std::string& dbname, const Options& options) { + Env* env = options.env; + std::vector filenames; + // Ignore error in case directory does not exist + env->GetChildren(dbname, &filenames); + if (filenames.empty()) { + return Status::OK(); + } + + FileLock* lock; + const std::string lockname = LockFileName(dbname); + Status result = env->LockFile(lockname, &lock); + if (result.ok()) { + uint64_t number; + FileType type; + for (size_t i = 0; i < filenames.size(); i++) { + if (ParseFileName(filenames[i], &number, &type) && + type != kDBLockFile) { // Lock file will be deleted at end + Status del = env->DeleteFile(dbname + "/" + filenames[i]); + if (result.ok() && !del.ok()) { + result = del; + } + } + } + env->UnlockFile(lock); // Ignore error since state is already gone + env->DeleteFile(lockname); + env->DeleteDir(dbname); // Ignore error in case dir contains other files + } + return result; +} + +} // namespace leveldb diff --git a/ios/Pods/leveldb-library/db/db_impl.h b/ios/Pods/leveldb-library/db/db_impl.h new file mode 100644 index 000000000..cfc998164 --- /dev/null +++ b/ios/Pods/leveldb-library/db/db_impl.h @@ -0,0 +1,211 @@ +// Copyright (c) 2011 The LevelDB Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. See the AUTHORS file for names of contributors. + +#ifndef STORAGE_LEVELDB_DB_DB_IMPL_H_ +#define STORAGE_LEVELDB_DB_DB_IMPL_H_ + +#include +#include +#include "db/dbformat.h" +#include "db/log_writer.h" +#include "db/snapshot.h" +#include "leveldb/db.h" +#include "leveldb/env.h" +#include "port/port.h" +#include "port/thread_annotations.h" + +namespace leveldb { + +class MemTable; +class TableCache; +class Version; +class VersionEdit; +class VersionSet; + +class DBImpl : public DB { + public: + DBImpl(const Options& options, const std::string& dbname); + virtual ~DBImpl(); + + // Implementations of the DB interface + virtual Status Put(const WriteOptions&, const Slice& key, const Slice& value); + virtual Status Delete(const WriteOptions&, const Slice& key); + virtual Status Write(const WriteOptions& options, WriteBatch* updates); + virtual Status Get(const ReadOptions& options, + const Slice& key, + std::string* value); + virtual Iterator* NewIterator(const ReadOptions&); + virtual const Snapshot* GetSnapshot(); + virtual void ReleaseSnapshot(const Snapshot* snapshot); + virtual bool GetProperty(const Slice& property, std::string* value); + virtual void GetApproximateSizes(const Range* range, int n, uint64_t* sizes); + virtual void CompactRange(const Slice* begin, const Slice* end); + + // Extra methods (for testing) that are not in the public DB interface + + // Compact any files in the named level that overlap [*begin,*end] + void TEST_CompactRange(int level, const Slice* begin, const Slice* end); + + // Force current memtable contents to be compacted. + Status TEST_CompactMemTable(); + + // Return an internal iterator over the current state of the database. + // The keys of this iterator are internal keys (see format.h). + // The returned iterator should be deleted when no longer needed. + Iterator* TEST_NewInternalIterator(); + + // Return the maximum overlapping data (in bytes) at next level for any + // file at a level >= 1. + int64_t TEST_MaxNextLevelOverlappingBytes(); + + // Record a sample of bytes read at the specified internal key. + // Samples are taken approximately once every config::kReadBytesPeriod + // bytes. + void RecordReadSample(Slice key); + + private: + friend class DB; + struct CompactionState; + struct Writer; + + Iterator* NewInternalIterator(const ReadOptions&, + SequenceNumber* latest_snapshot, + uint32_t* seed); + + Status NewDB(); + + // Recover the descriptor from persistent storage. May do a significant + // amount of work to recover recently logged updates. Any changes to + // be made to the descriptor are added to *edit. + Status Recover(VersionEdit* edit) EXCLUSIVE_LOCKS_REQUIRED(mutex_); + + void MaybeIgnoreError(Status* s) const; + + // Delete any unneeded files and stale in-memory entries. + void DeleteObsoleteFiles(); + + // Compact the in-memory write buffer to disk. Switches to a new + // log-file/memtable and writes a new descriptor iff successful. + // Errors are recorded in bg_error_. + void CompactMemTable() EXCLUSIVE_LOCKS_REQUIRED(mutex_); + + Status RecoverLogFile(uint64_t log_number, + VersionEdit* edit, + SequenceNumber* max_sequence) + EXCLUSIVE_LOCKS_REQUIRED(mutex_); + + Status WriteLevel0Table(MemTable* mem, VersionEdit* edit, Version* base) + EXCLUSIVE_LOCKS_REQUIRED(mutex_); + + Status MakeRoomForWrite(bool force /* compact even if there is room? */) + EXCLUSIVE_LOCKS_REQUIRED(mutex_); + WriteBatch* BuildBatchGroup(Writer** last_writer); + + void RecordBackgroundError(const Status& s); + + void MaybeScheduleCompaction() EXCLUSIVE_LOCKS_REQUIRED(mutex_); + static void BGWork(void* db); + void BackgroundCall(); + void BackgroundCompaction() EXCLUSIVE_LOCKS_REQUIRED(mutex_); + void CleanupCompaction(CompactionState* compact) + EXCLUSIVE_LOCKS_REQUIRED(mutex_); + Status DoCompactionWork(CompactionState* compact) + EXCLUSIVE_LOCKS_REQUIRED(mutex_); + + Status OpenCompactionOutputFile(CompactionState* compact); + Status FinishCompactionOutputFile(CompactionState* compact, Iterator* input); + Status InstallCompactionResults(CompactionState* compact) + EXCLUSIVE_LOCKS_REQUIRED(mutex_); + + // Constant after construction + Env* const env_; + const InternalKeyComparator internal_comparator_; + const InternalFilterPolicy internal_filter_policy_; + const Options options_; // options_.comparator == &internal_comparator_ + bool owns_info_log_; + bool owns_cache_; + const std::string dbname_; + + // table_cache_ provides its own synchronization + TableCache* table_cache_; + + // Lock over the persistent DB state. Non-NULL iff successfully acquired. + FileLock* db_lock_; + + // State below is protected by mutex_ + port::Mutex mutex_; + port::AtomicPointer shutting_down_; + port::CondVar bg_cv_; // Signalled when background work finishes + MemTable* mem_; + MemTable* imm_; // Memtable being compacted + port::AtomicPointer has_imm_; // So bg thread can detect non-NULL imm_ + WritableFile* logfile_; + uint64_t logfile_number_; + log::Writer* log_; + uint32_t seed_; // For sampling. + + // Queue of writers. + std::deque writers_; + WriteBatch* tmp_batch_; + + SnapshotList snapshots_; + + // Set of table files to protect from deletion because they are + // part of ongoing compactions. + std::set pending_outputs_; + + // Has a background compaction been scheduled or is running? + bool bg_compaction_scheduled_; + + // Information for a manual compaction + struct ManualCompaction { + int level; + bool done; + const InternalKey* begin; // NULL means beginning of key range + const InternalKey* end; // NULL means end of key range + InternalKey tmp_storage; // Used to keep track of compaction progress + }; + ManualCompaction* manual_compaction_; + + VersionSet* versions_; + + // Have we encountered a background error in paranoid mode? + Status bg_error_; + + // Per level compaction stats. stats_[level] stores the stats for + // compactions that produced data for the specified "level". + struct CompactionStats { + int64_t micros; + int64_t bytes_read; + int64_t bytes_written; + + CompactionStats() : micros(0), bytes_read(0), bytes_written(0) { } + + void Add(const CompactionStats& c) { + this->micros += c.micros; + this->bytes_read += c.bytes_read; + this->bytes_written += c.bytes_written; + } + }; + CompactionStats stats_[config::kNumLevels]; + + // No copying allowed + DBImpl(const DBImpl&); + void operator=(const DBImpl&); + + const Comparator* user_comparator() const { + return internal_comparator_.user_comparator(); + } +}; + +// Sanitize db options. The caller should delete result.info_log if +// it is not equal to src.info_log. +extern Options SanitizeOptions(const std::string& db, + const InternalKeyComparator* icmp, + const InternalFilterPolicy* ipolicy, + const Options& src); + +} // namespace leveldb + +#endif // STORAGE_LEVELDB_DB_DB_IMPL_H_ diff --git a/ios/Pods/leveldb-library/db/db_iter.cc b/ios/Pods/leveldb-library/db/db_iter.cc new file mode 100644 index 000000000..3b2035e9e --- /dev/null +++ b/ios/Pods/leveldb-library/db/db_iter.cc @@ -0,0 +1,317 @@ +// Copyright (c) 2011 The LevelDB Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. See the AUTHORS file for names of contributors. + +#include "db/db_iter.h" + +#include "db/filename.h" +#include "db/db_impl.h" +#include "db/dbformat.h" +#include "leveldb/env.h" +#include "leveldb/iterator.h" +#include "port/port.h" +#include "util/logging.h" +#include "util/mutexlock.h" +#include "util/random.h" + +namespace leveldb { + +#if 0 +static void DumpInternalIter(Iterator* iter) { + for (iter->SeekToFirst(); iter->Valid(); iter->Next()) { + ParsedInternalKey k; + if (!ParseInternalKey(iter->key(), &k)) { + fprintf(stderr, "Corrupt '%s'\n", EscapeString(iter->key()).c_str()); + } else { + fprintf(stderr, "@ '%s'\n", k.DebugString().c_str()); + } + } +} +#endif + +namespace { + +// Memtables and sstables that make the DB representation contain +// (userkey,seq,type) => uservalue entries. DBIter +// combines multiple entries for the same userkey found in the DB +// representation into a single entry while accounting for sequence +// numbers, deletion markers, overwrites, etc. +class DBIter: public Iterator { + public: + // Which direction is the iterator currently moving? + // (1) When moving forward, the internal iterator is positioned at + // the exact entry that yields this->key(), this->value() + // (2) When moving backwards, the internal iterator is positioned + // just before all entries whose user key == this->key(). + enum Direction { + kForward, + kReverse + }; + + DBIter(DBImpl* db, const Comparator* cmp, Iterator* iter, SequenceNumber s, + uint32_t seed) + : db_(db), + user_comparator_(cmp), + iter_(iter), + sequence_(s), + direction_(kForward), + valid_(false), + rnd_(seed), + bytes_counter_(RandomPeriod()) { + } + virtual ~DBIter() { + delete iter_; + } + virtual bool Valid() const { return valid_; } + virtual Slice key() const { + assert(valid_); + return (direction_ == kForward) ? ExtractUserKey(iter_->key()) : saved_key_; + } + virtual Slice value() const { + assert(valid_); + return (direction_ == kForward) ? iter_->value() : saved_value_; + } + virtual Status status() const { + if (status_.ok()) { + return iter_->status(); + } else { + return status_; + } + } + + virtual void Next(); + virtual void Prev(); + virtual void Seek(const Slice& target); + virtual void SeekToFirst(); + virtual void SeekToLast(); + + private: + void FindNextUserEntry(bool skipping, std::string* skip); + void FindPrevUserEntry(); + bool ParseKey(ParsedInternalKey* key); + + inline void SaveKey(const Slice& k, std::string* dst) { + dst->assign(k.data(), k.size()); + } + + inline void ClearSavedValue() { + if (saved_value_.capacity() > 1048576) { + std::string empty; + swap(empty, saved_value_); + } else { + saved_value_.clear(); + } + } + + // Pick next gap with average value of config::kReadBytesPeriod. + ssize_t RandomPeriod() { + return rnd_.Uniform(2*config::kReadBytesPeriod); + } + + DBImpl* db_; + const Comparator* const user_comparator_; + Iterator* const iter_; + SequenceNumber const sequence_; + + Status status_; + std::string saved_key_; // == current key when direction_==kReverse + std::string saved_value_; // == current raw value when direction_==kReverse + Direction direction_; + bool valid_; + + Random rnd_; + ssize_t bytes_counter_; + + // No copying allowed + DBIter(const DBIter&); + void operator=(const DBIter&); +}; + +inline bool DBIter::ParseKey(ParsedInternalKey* ikey) { + Slice k = iter_->key(); + ssize_t n = k.size() + iter_->value().size(); + bytes_counter_ -= n; + while (bytes_counter_ < 0) { + bytes_counter_ += RandomPeriod(); + db_->RecordReadSample(k); + } + if (!ParseInternalKey(k, ikey)) { + status_ = Status::Corruption("corrupted internal key in DBIter"); + return false; + } else { + return true; + } +} + +void DBIter::Next() { + assert(valid_); + + if (direction_ == kReverse) { // Switch directions? + direction_ = kForward; + // iter_ is pointing just before the entries for this->key(), + // so advance into the range of entries for this->key() and then + // use the normal skipping code below. + if (!iter_->Valid()) { + iter_->SeekToFirst(); + } else { + iter_->Next(); + } + if (!iter_->Valid()) { + valid_ = false; + saved_key_.clear(); + return; + } + // saved_key_ already contains the key to skip past. + } else { + // Store in saved_key_ the current key so we skip it below. + SaveKey(ExtractUserKey(iter_->key()), &saved_key_); + } + + FindNextUserEntry(true, &saved_key_); +} + +void DBIter::FindNextUserEntry(bool skipping, std::string* skip) { + // Loop until we hit an acceptable entry to yield + assert(iter_->Valid()); + assert(direction_ == kForward); + do { + ParsedInternalKey ikey; + if (ParseKey(&ikey) && ikey.sequence <= sequence_) { + switch (ikey.type) { + case kTypeDeletion: + // Arrange to skip all upcoming entries for this key since + // they are hidden by this deletion. + SaveKey(ikey.user_key, skip); + skipping = true; + break; + case kTypeValue: + if (skipping && + user_comparator_->Compare(ikey.user_key, *skip) <= 0) { + // Entry hidden + } else { + valid_ = true; + saved_key_.clear(); + return; + } + break; + } + } + iter_->Next(); + } while (iter_->Valid()); + saved_key_.clear(); + valid_ = false; +} + +void DBIter::Prev() { + assert(valid_); + + if (direction_ == kForward) { // Switch directions? + // iter_ is pointing at the current entry. Scan backwards until + // the key changes so we can use the normal reverse scanning code. + assert(iter_->Valid()); // Otherwise valid_ would have been false + SaveKey(ExtractUserKey(iter_->key()), &saved_key_); + while (true) { + iter_->Prev(); + if (!iter_->Valid()) { + valid_ = false; + saved_key_.clear(); + ClearSavedValue(); + return; + } + if (user_comparator_->Compare(ExtractUserKey(iter_->key()), + saved_key_) < 0) { + break; + } + } + direction_ = kReverse; + } + + FindPrevUserEntry(); +} + +void DBIter::FindPrevUserEntry() { + assert(direction_ == kReverse); + + ValueType value_type = kTypeDeletion; + if (iter_->Valid()) { + do { + ParsedInternalKey ikey; + if (ParseKey(&ikey) && ikey.sequence <= sequence_) { + if ((value_type != kTypeDeletion) && + user_comparator_->Compare(ikey.user_key, saved_key_) < 0) { + // We encountered a non-deleted value in entries for previous keys, + break; + } + value_type = ikey.type; + if (value_type == kTypeDeletion) { + saved_key_.clear(); + ClearSavedValue(); + } else { + Slice raw_value = iter_->value(); + if (saved_value_.capacity() > raw_value.size() + 1048576) { + std::string empty; + swap(empty, saved_value_); + } + SaveKey(ExtractUserKey(iter_->key()), &saved_key_); + saved_value_.assign(raw_value.data(), raw_value.size()); + } + } + iter_->Prev(); + } while (iter_->Valid()); + } + + if (value_type == kTypeDeletion) { + // End + valid_ = false; + saved_key_.clear(); + ClearSavedValue(); + direction_ = kForward; + } else { + valid_ = true; + } +} + +void DBIter::Seek(const Slice& target) { + direction_ = kForward; + ClearSavedValue(); + saved_key_.clear(); + AppendInternalKey( + &saved_key_, ParsedInternalKey(target, sequence_, kValueTypeForSeek)); + iter_->Seek(saved_key_); + if (iter_->Valid()) { + FindNextUserEntry(false, &saved_key_ /* temporary storage */); + } else { + valid_ = false; + } +} + +void DBIter::SeekToFirst() { + direction_ = kForward; + ClearSavedValue(); + iter_->SeekToFirst(); + if (iter_->Valid()) { + FindNextUserEntry(false, &saved_key_ /* temporary storage */); + } else { + valid_ = false; + } +} + +void DBIter::SeekToLast() { + direction_ = kReverse; + ClearSavedValue(); + iter_->SeekToLast(); + FindPrevUserEntry(); +} + +} // anonymous namespace + +Iterator* NewDBIterator( + DBImpl* db, + const Comparator* user_key_comparator, + Iterator* internal_iter, + SequenceNumber sequence, + uint32_t seed) { + return new DBIter(db, user_key_comparator, internal_iter, sequence, seed); +} + +} // namespace leveldb diff --git a/ios/Pods/leveldb-library/db/db_iter.h b/ios/Pods/leveldb-library/db/db_iter.h new file mode 100644 index 000000000..04927e937 --- /dev/null +++ b/ios/Pods/leveldb-library/db/db_iter.h @@ -0,0 +1,28 @@ +// Copyright (c) 2011 The LevelDB Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. See the AUTHORS file for names of contributors. + +#ifndef STORAGE_LEVELDB_DB_DB_ITER_H_ +#define STORAGE_LEVELDB_DB_DB_ITER_H_ + +#include +#include "leveldb/db.h" +#include "db/dbformat.h" + +namespace leveldb { + +class DBImpl; + +// Return a new iterator that converts internal keys (yielded by +// "*internal_iter") that were live at the specified "sequence" number +// into appropriate user keys. +extern Iterator* NewDBIterator( + DBImpl* db, + const Comparator* user_key_comparator, + Iterator* internal_iter, + SequenceNumber sequence, + uint32_t seed); + +} // namespace leveldb + +#endif // STORAGE_LEVELDB_DB_DB_ITER_H_ diff --git a/ios/Pods/leveldb-library/db/db_test.cc b/ios/Pods/leveldb-library/db/db_test.cc new file mode 100644 index 000000000..0fed9137d --- /dev/null +++ b/ios/Pods/leveldb-library/db/db_test.cc @@ -0,0 +1,2128 @@ +// Copyright (c) 2011 The LevelDB Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. See the AUTHORS file for names of contributors. + +#include "leveldb/db.h" +#include "leveldb/filter_policy.h" +#include "db/db_impl.h" +#include "db/filename.h" +#include "db/version_set.h" +#include "db/write_batch_internal.h" +#include "leveldb/cache.h" +#include "leveldb/env.h" +#include "leveldb/table.h" +#include "util/hash.h" +#include "util/logging.h" +#include "util/mutexlock.h" +#include "util/testharness.h" +#include "util/testutil.h" + +namespace leveldb { + +static std::string RandomString(Random* rnd, int len) { + std::string r; + test::RandomString(rnd, len, &r); + return r; +} + +namespace { +class AtomicCounter { + private: + port::Mutex mu_; + int count_; + public: + AtomicCounter() : count_(0) { } + void Increment() { + IncrementBy(1); + } + void IncrementBy(int count) { + MutexLock l(&mu_); + count_ += count; + } + int Read() { + MutexLock l(&mu_); + return count_; + } + void Reset() { + MutexLock l(&mu_); + count_ = 0; + } +}; + +void DelayMilliseconds(int millis) { + Env::Default()->SleepForMicroseconds(millis * 1000); +} +} + +// Special Env used to delay background operations +class SpecialEnv : public EnvWrapper { + public: + // sstable/log Sync() calls are blocked while this pointer is non-NULL. + port::AtomicPointer delay_data_sync_; + + // sstable/log Sync() calls return an error. + port::AtomicPointer data_sync_error_; + + // Simulate no-space errors while this pointer is non-NULL. + port::AtomicPointer no_space_; + + // Simulate non-writable file system while this pointer is non-NULL + port::AtomicPointer non_writable_; + + // Force sync of manifest files to fail while this pointer is non-NULL + port::AtomicPointer manifest_sync_error_; + + // Force write to manifest files to fail while this pointer is non-NULL + port::AtomicPointer manifest_write_error_; + + bool count_random_reads_; + AtomicCounter random_read_counter_; + + explicit SpecialEnv(Env* base) : EnvWrapper(base) { + delay_data_sync_.Release_Store(NULL); + data_sync_error_.Release_Store(NULL); + no_space_.Release_Store(NULL); + non_writable_.Release_Store(NULL); + count_random_reads_ = false; + manifest_sync_error_.Release_Store(NULL); + manifest_write_error_.Release_Store(NULL); + } + + Status NewWritableFile(const std::string& f, WritableFile** r) { + class DataFile : public WritableFile { + private: + SpecialEnv* env_; + WritableFile* base_; + + public: + DataFile(SpecialEnv* env, WritableFile* base) + : env_(env), + base_(base) { + } + ~DataFile() { delete base_; } + Status Append(const Slice& data) { + if (env_->no_space_.Acquire_Load() != NULL) { + // Drop writes on the floor + return Status::OK(); + } else { + return base_->Append(data); + } + } + Status Close() { return base_->Close(); } + Status Flush() { return base_->Flush(); } + Status Sync() { + if (env_->data_sync_error_.Acquire_Load() != NULL) { + return Status::IOError("simulated data sync error"); + } + while (env_->delay_data_sync_.Acquire_Load() != NULL) { + DelayMilliseconds(100); + } + return base_->Sync(); + } + }; + class ManifestFile : public WritableFile { + private: + SpecialEnv* env_; + WritableFile* base_; + public: + ManifestFile(SpecialEnv* env, WritableFile* b) : env_(env), base_(b) { } + ~ManifestFile() { delete base_; } + Status Append(const Slice& data) { + if (env_->manifest_write_error_.Acquire_Load() != NULL) { + return Status::IOError("simulated writer error"); + } else { + return base_->Append(data); + } + } + Status Close() { return base_->Close(); } + Status Flush() { return base_->Flush(); } + Status Sync() { + if (env_->manifest_sync_error_.Acquire_Load() != NULL) { + return Status::IOError("simulated sync error"); + } else { + return base_->Sync(); + } + } + }; + + if (non_writable_.Acquire_Load() != NULL) { + return Status::IOError("simulated write error"); + } + + Status s = target()->NewWritableFile(f, r); + if (s.ok()) { + if (strstr(f.c_str(), ".ldb") != NULL || + strstr(f.c_str(), ".log") != NULL) { + *r = new DataFile(this, *r); + } else if (strstr(f.c_str(), "MANIFEST") != NULL) { + *r = new ManifestFile(this, *r); + } + } + return s; + } + + Status NewRandomAccessFile(const std::string& f, RandomAccessFile** r) { + class CountingFile : public RandomAccessFile { + private: + RandomAccessFile* target_; + AtomicCounter* counter_; + public: + CountingFile(RandomAccessFile* target, AtomicCounter* counter) + : target_(target), counter_(counter) { + } + virtual ~CountingFile() { delete target_; } + virtual Status Read(uint64_t offset, size_t n, Slice* result, + char* scratch) const { + counter_->Increment(); + return target_->Read(offset, n, result, scratch); + } + }; + + Status s = target()->NewRandomAccessFile(f, r); + if (s.ok() && count_random_reads_) { + *r = new CountingFile(*r, &random_read_counter_); + } + return s; + } +}; + +class DBTest { + private: + const FilterPolicy* filter_policy_; + + // Sequence of option configurations to try + enum OptionConfig { + kDefault, + kFilter, + kUncompressed, + kEnd + }; + int option_config_; + + public: + std::string dbname_; + SpecialEnv* env_; + DB* db_; + + Options last_options_; + + DBTest() : option_config_(kDefault), + env_(new SpecialEnv(Env::Default())) { + filter_policy_ = NewBloomFilterPolicy(10); + dbname_ = test::TmpDir() + "/db_test"; + DestroyDB(dbname_, Options()); + db_ = NULL; + Reopen(); + } + + ~DBTest() { + delete db_; + DestroyDB(dbname_, Options()); + delete env_; + delete filter_policy_; + } + + // Switch to a fresh database with the next option configuration to + // test. Return false if there are no more configurations to test. + bool ChangeOptions() { + option_config_++; + if (option_config_ >= kEnd) { + return false; + } else { + DestroyAndReopen(); + return true; + } + } + + // Return the current option configuration. + Options CurrentOptions() { + Options options; + switch (option_config_) { + case kFilter: + options.filter_policy = filter_policy_; + break; + case kUncompressed: + options.compression = kNoCompression; + break; + default: + break; + } + return options; + } + + DBImpl* dbfull() { + return reinterpret_cast(db_); + } + + void Reopen(Options* options = NULL) { + ASSERT_OK(TryReopen(options)); + } + + void Close() { + delete db_; + db_ = NULL; + } + + void DestroyAndReopen(Options* options = NULL) { + delete db_; + db_ = NULL; + DestroyDB(dbname_, Options()); + ASSERT_OK(TryReopen(options)); + } + + Status TryReopen(Options* options) { + delete db_; + db_ = NULL; + Options opts; + if (options != NULL) { + opts = *options; + } else { + opts = CurrentOptions(); + opts.create_if_missing = true; + } + last_options_ = opts; + + return DB::Open(opts, dbname_, &db_); + } + + Status Put(const std::string& k, const std::string& v) { + return db_->Put(WriteOptions(), k, v); + } + + Status Delete(const std::string& k) { + return db_->Delete(WriteOptions(), k); + } + + std::string Get(const std::string& k, const Snapshot* snapshot = NULL) { + ReadOptions options; + options.snapshot = snapshot; + std::string result; + Status s = db_->Get(options, k, &result); + if (s.IsNotFound()) { + result = "NOT_FOUND"; + } else if (!s.ok()) { + result = s.ToString(); + } + return result; + } + + // Return a string that contains all key,value pairs in order, + // formatted like "(k1->v1)(k2->v2)". + std::string Contents() { + std::vector forward; + std::string result; + Iterator* iter = db_->NewIterator(ReadOptions()); + for (iter->SeekToFirst(); iter->Valid(); iter->Next()) { + std::string s = IterStatus(iter); + result.push_back('('); + result.append(s); + result.push_back(')'); + forward.push_back(s); + } + + // Check reverse iteration results are the reverse of forward results + size_t matched = 0; + for (iter->SeekToLast(); iter->Valid(); iter->Prev()) { + ASSERT_LT(matched, forward.size()); + ASSERT_EQ(IterStatus(iter), forward[forward.size() - matched - 1]); + matched++; + } + ASSERT_EQ(matched, forward.size()); + + delete iter; + return result; + } + + std::string AllEntriesFor(const Slice& user_key) { + Iterator* iter = dbfull()->TEST_NewInternalIterator(); + InternalKey target(user_key, kMaxSequenceNumber, kTypeValue); + iter->Seek(target.Encode()); + std::string result; + if (!iter->status().ok()) { + result = iter->status().ToString(); + } else { + result = "[ "; + bool first = true; + while (iter->Valid()) { + ParsedInternalKey ikey; + if (!ParseInternalKey(iter->key(), &ikey)) { + result += "CORRUPTED"; + } else { + if (last_options_.comparator->Compare(ikey.user_key, user_key) != 0) { + break; + } + if (!first) { + result += ", "; + } + first = false; + switch (ikey.type) { + case kTypeValue: + result += iter->value().ToString(); + break; + case kTypeDeletion: + result += "DEL"; + break; + } + } + iter->Next(); + } + if (!first) { + result += " "; + } + result += "]"; + } + delete iter; + return result; + } + + int NumTableFilesAtLevel(int level) { + std::string property; + ASSERT_TRUE( + db_->GetProperty("leveldb.num-files-at-level" + NumberToString(level), + &property)); + return atoi(property.c_str()); + } + + int TotalTableFiles() { + int result = 0; + for (int level = 0; level < config::kNumLevels; level++) { + result += NumTableFilesAtLevel(level); + } + return result; + } + + // Return spread of files per level + std::string FilesPerLevel() { + std::string result; + int last_non_zero_offset = 0; + for (int level = 0; level < config::kNumLevels; level++) { + int f = NumTableFilesAtLevel(level); + char buf[100]; + snprintf(buf, sizeof(buf), "%s%d", (level ? "," : ""), f); + result += buf; + if (f > 0) { + last_non_zero_offset = result.size(); + } + } + result.resize(last_non_zero_offset); + return result; + } + + int CountFiles() { + std::vector files; + env_->GetChildren(dbname_, &files); + return static_cast(files.size()); + } + + uint64_t Size(const Slice& start, const Slice& limit) { + Range r(start, limit); + uint64_t size; + db_->GetApproximateSizes(&r, 1, &size); + return size; + } + + void Compact(const Slice& start, const Slice& limit) { + db_->CompactRange(&start, &limit); + } + + // Do n memtable compactions, each of which produces an sstable + // covering the range [small,large]. + void MakeTables(int n, const std::string& small, const std::string& large) { + for (int i = 0; i < n; i++) { + Put(small, "begin"); + Put(large, "end"); + dbfull()->TEST_CompactMemTable(); + } + } + + // Prevent pushing of new sstables into deeper levels by adding + // tables that cover a specified range to all levels. + void FillLevels(const std::string& smallest, const std::string& largest) { + MakeTables(config::kNumLevels, smallest, largest); + } + + void DumpFileCounts(const char* label) { + fprintf(stderr, "---\n%s:\n", label); + fprintf(stderr, "maxoverlap: %lld\n", + static_cast( + dbfull()->TEST_MaxNextLevelOverlappingBytes())); + for (int level = 0; level < config::kNumLevels; level++) { + int num = NumTableFilesAtLevel(level); + if (num > 0) { + fprintf(stderr, " level %3d : %d files\n", level, num); + } + } + } + + std::string DumpSSTableList() { + std::string property; + db_->GetProperty("leveldb.sstables", &property); + return property; + } + + std::string IterStatus(Iterator* iter) { + std::string result; + if (iter->Valid()) { + result = iter->key().ToString() + "->" + iter->value().ToString(); + } else { + result = "(invalid)"; + } + return result; + } + + bool DeleteAnSSTFile() { + std::vector filenames; + ASSERT_OK(env_->GetChildren(dbname_, &filenames)); + uint64_t number; + FileType type; + for (size_t i = 0; i < filenames.size(); i++) { + if (ParseFileName(filenames[i], &number, &type) && type == kTableFile) { + ASSERT_OK(env_->DeleteFile(TableFileName(dbname_, number))); + return true; + } + } + return false; + } + + // Returns number of files renamed. + int RenameLDBToSST() { + std::vector filenames; + ASSERT_OK(env_->GetChildren(dbname_, &filenames)); + uint64_t number; + FileType type; + int files_renamed = 0; + for (size_t i = 0; i < filenames.size(); i++) { + if (ParseFileName(filenames[i], &number, &type) && type == kTableFile) { + const std::string from = TableFileName(dbname_, number); + const std::string to = SSTTableFileName(dbname_, number); + ASSERT_OK(env_->RenameFile(from, to)); + files_renamed++; + } + } + return files_renamed; + } +}; + +TEST(DBTest, Empty) { + do { + ASSERT_TRUE(db_ != NULL); + ASSERT_EQ("NOT_FOUND", Get("foo")); + } while (ChangeOptions()); +} + +TEST(DBTest, ReadWrite) { + do { + ASSERT_OK(Put("foo", "v1")); + ASSERT_EQ("v1", Get("foo")); + ASSERT_OK(Put("bar", "v2")); + ASSERT_OK(Put("foo", "v3")); + ASSERT_EQ("v3", Get("foo")); + ASSERT_EQ("v2", Get("bar")); + } while (ChangeOptions()); +} + +TEST(DBTest, PutDeleteGet) { + do { + ASSERT_OK(db_->Put(WriteOptions(), "foo", "v1")); + ASSERT_EQ("v1", Get("foo")); + ASSERT_OK(db_->Put(WriteOptions(), "foo", "v2")); + ASSERT_EQ("v2", Get("foo")); + ASSERT_OK(db_->Delete(WriteOptions(), "foo")); + ASSERT_EQ("NOT_FOUND", Get("foo")); + } while (ChangeOptions()); +} + +TEST(DBTest, GetFromImmutableLayer) { + do { + Options options = CurrentOptions(); + options.env = env_; + options.write_buffer_size = 100000; // Small write buffer + Reopen(&options); + + ASSERT_OK(Put("foo", "v1")); + ASSERT_EQ("v1", Get("foo")); + + env_->delay_data_sync_.Release_Store(env_); // Block sync calls + Put("k1", std::string(100000, 'x')); // Fill memtable + Put("k2", std::string(100000, 'y')); // Trigger compaction + ASSERT_EQ("v1", Get("foo")); + env_->delay_data_sync_.Release_Store(NULL); // Release sync calls + } while (ChangeOptions()); +} + +TEST(DBTest, GetFromVersions) { + do { + ASSERT_OK(Put("foo", "v1")); + dbfull()->TEST_CompactMemTable(); + ASSERT_EQ("v1", Get("foo")); + } while (ChangeOptions()); +} + +TEST(DBTest, GetSnapshot) { + do { + // Try with both a short key and a long key + for (int i = 0; i < 2; i++) { + std::string key = (i == 0) ? std::string("foo") : std::string(200, 'x'); + ASSERT_OK(Put(key, "v1")); + const Snapshot* s1 = db_->GetSnapshot(); + ASSERT_OK(Put(key, "v2")); + ASSERT_EQ("v2", Get(key)); + ASSERT_EQ("v1", Get(key, s1)); + dbfull()->TEST_CompactMemTable(); + ASSERT_EQ("v2", Get(key)); + ASSERT_EQ("v1", Get(key, s1)); + db_->ReleaseSnapshot(s1); + } + } while (ChangeOptions()); +} + +TEST(DBTest, GetLevel0Ordering) { + do { + // Check that we process level-0 files in correct order. The code + // below generates two level-0 files where the earlier one comes + // before the later one in the level-0 file list since the earlier + // one has a smaller "smallest" key. + ASSERT_OK(Put("bar", "b")); + ASSERT_OK(Put("foo", "v1")); + dbfull()->TEST_CompactMemTable(); + ASSERT_OK(Put("foo", "v2")); + dbfull()->TEST_CompactMemTable(); + ASSERT_EQ("v2", Get("foo")); + } while (ChangeOptions()); +} + +TEST(DBTest, GetOrderedByLevels) { + do { + ASSERT_OK(Put("foo", "v1")); + Compact("a", "z"); + ASSERT_EQ("v1", Get("foo")); + ASSERT_OK(Put("foo", "v2")); + ASSERT_EQ("v2", Get("foo")); + dbfull()->TEST_CompactMemTable(); + ASSERT_EQ("v2", Get("foo")); + } while (ChangeOptions()); +} + +TEST(DBTest, GetPicksCorrectFile) { + do { + // Arrange to have multiple files in a non-level-0 level. + ASSERT_OK(Put("a", "va")); + Compact("a", "b"); + ASSERT_OK(Put("x", "vx")); + Compact("x", "y"); + ASSERT_OK(Put("f", "vf")); + Compact("f", "g"); + ASSERT_EQ("va", Get("a")); + ASSERT_EQ("vf", Get("f")); + ASSERT_EQ("vx", Get("x")); + } while (ChangeOptions()); +} + +TEST(DBTest, GetEncountersEmptyLevel) { + do { + // Arrange for the following to happen: + // * sstable A in level 0 + // * nothing in level 1 + // * sstable B in level 2 + // Then do enough Get() calls to arrange for an automatic compaction + // of sstable A. A bug would cause the compaction to be marked as + // occurring at level 1 (instead of the correct level 0). + + // Step 1: First place sstables in levels 0 and 2 + int compaction_count = 0; + while (NumTableFilesAtLevel(0) == 0 || + NumTableFilesAtLevel(2) == 0) { + ASSERT_LE(compaction_count, 100) << "could not fill levels 0 and 2"; + compaction_count++; + Put("a", "begin"); + Put("z", "end"); + dbfull()->TEST_CompactMemTable(); + } + + // Step 2: clear level 1 if necessary. + dbfull()->TEST_CompactRange(1, NULL, NULL); + ASSERT_EQ(NumTableFilesAtLevel(0), 1); + ASSERT_EQ(NumTableFilesAtLevel(1), 0); + ASSERT_EQ(NumTableFilesAtLevel(2), 1); + + // Step 3: read a bunch of times + for (int i = 0; i < 1000; i++) { + ASSERT_EQ("NOT_FOUND", Get("missing")); + } + + // Step 4: Wait for compaction to finish + DelayMilliseconds(1000); + + ASSERT_EQ(NumTableFilesAtLevel(0), 0); + } while (ChangeOptions()); +} + +TEST(DBTest, IterEmpty) { + Iterator* iter = db_->NewIterator(ReadOptions()); + + iter->SeekToFirst(); + ASSERT_EQ(IterStatus(iter), "(invalid)"); + + iter->SeekToLast(); + ASSERT_EQ(IterStatus(iter), "(invalid)"); + + iter->Seek("foo"); + ASSERT_EQ(IterStatus(iter), "(invalid)"); + + delete iter; +} + +TEST(DBTest, IterSingle) { + ASSERT_OK(Put("a", "va")); + Iterator* iter = db_->NewIterator(ReadOptions()); + + iter->SeekToFirst(); + ASSERT_EQ(IterStatus(iter), "a->va"); + iter->Next(); + ASSERT_EQ(IterStatus(iter), "(invalid)"); + iter->SeekToFirst(); + ASSERT_EQ(IterStatus(iter), "a->va"); + iter->Prev(); + ASSERT_EQ(IterStatus(iter), "(invalid)"); + + iter->SeekToLast(); + ASSERT_EQ(IterStatus(iter), "a->va"); + iter->Next(); + ASSERT_EQ(IterStatus(iter), "(invalid)"); + iter->SeekToLast(); + ASSERT_EQ(IterStatus(iter), "a->va"); + iter->Prev(); + ASSERT_EQ(IterStatus(iter), "(invalid)"); + + iter->Seek(""); + ASSERT_EQ(IterStatus(iter), "a->va"); + iter->Next(); + ASSERT_EQ(IterStatus(iter), "(invalid)"); + + iter->Seek("a"); + ASSERT_EQ(IterStatus(iter), "a->va"); + iter->Next(); + ASSERT_EQ(IterStatus(iter), "(invalid)"); + + iter->Seek("b"); + ASSERT_EQ(IterStatus(iter), "(invalid)"); + + delete iter; +} + +TEST(DBTest, IterMulti) { + ASSERT_OK(Put("a", "va")); + ASSERT_OK(Put("b", "vb")); + ASSERT_OK(Put("c", "vc")); + Iterator* iter = db_->NewIterator(ReadOptions()); + + iter->SeekToFirst(); + ASSERT_EQ(IterStatus(iter), "a->va"); + iter->Next(); + ASSERT_EQ(IterStatus(iter), "b->vb"); + iter->Next(); + ASSERT_EQ(IterStatus(iter), "c->vc"); + iter->Next(); + ASSERT_EQ(IterStatus(iter), "(invalid)"); + iter->SeekToFirst(); + ASSERT_EQ(IterStatus(iter), "a->va"); + iter->Prev(); + ASSERT_EQ(IterStatus(iter), "(invalid)"); + + iter->SeekToLast(); + ASSERT_EQ(IterStatus(iter), "c->vc"); + iter->Prev(); + ASSERT_EQ(IterStatus(iter), "b->vb"); + iter->Prev(); + ASSERT_EQ(IterStatus(iter), "a->va"); + iter->Prev(); + ASSERT_EQ(IterStatus(iter), "(invalid)"); + iter->SeekToLast(); + ASSERT_EQ(IterStatus(iter), "c->vc"); + iter->Next(); + ASSERT_EQ(IterStatus(iter), "(invalid)"); + + iter->Seek(""); + ASSERT_EQ(IterStatus(iter), "a->va"); + iter->Seek("a"); + ASSERT_EQ(IterStatus(iter), "a->va"); + iter->Seek("ax"); + ASSERT_EQ(IterStatus(iter), "b->vb"); + iter->Seek("b"); + ASSERT_EQ(IterStatus(iter), "b->vb"); + iter->Seek("z"); + ASSERT_EQ(IterStatus(iter), "(invalid)"); + + // Switch from reverse to forward + iter->SeekToLast(); + iter->Prev(); + iter->Prev(); + iter->Next(); + ASSERT_EQ(IterStatus(iter), "b->vb"); + + // Switch from forward to reverse + iter->SeekToFirst(); + iter->Next(); + iter->Next(); + iter->Prev(); + ASSERT_EQ(IterStatus(iter), "b->vb"); + + // Make sure iter stays at snapshot + ASSERT_OK(Put("a", "va2")); + ASSERT_OK(Put("a2", "va3")); + ASSERT_OK(Put("b", "vb2")); + ASSERT_OK(Put("c", "vc2")); + ASSERT_OK(Delete("b")); + iter->SeekToFirst(); + ASSERT_EQ(IterStatus(iter), "a->va"); + iter->Next(); + ASSERT_EQ(IterStatus(iter), "b->vb"); + iter->Next(); + ASSERT_EQ(IterStatus(iter), "c->vc"); + iter->Next(); + ASSERT_EQ(IterStatus(iter), "(invalid)"); + iter->SeekToLast(); + ASSERT_EQ(IterStatus(iter), "c->vc"); + iter->Prev(); + ASSERT_EQ(IterStatus(iter), "b->vb"); + iter->Prev(); + ASSERT_EQ(IterStatus(iter), "a->va"); + iter->Prev(); + ASSERT_EQ(IterStatus(iter), "(invalid)"); + + delete iter; +} + +TEST(DBTest, IterSmallAndLargeMix) { + ASSERT_OK(Put("a", "va")); + ASSERT_OK(Put("b", std::string(100000, 'b'))); + ASSERT_OK(Put("c", "vc")); + ASSERT_OK(Put("d", std::string(100000, 'd'))); + ASSERT_OK(Put("e", std::string(100000, 'e'))); + + Iterator* iter = db_->NewIterator(ReadOptions()); + + iter->SeekToFirst(); + ASSERT_EQ(IterStatus(iter), "a->va"); + iter->Next(); + ASSERT_EQ(IterStatus(iter), "b->" + std::string(100000, 'b')); + iter->Next(); + ASSERT_EQ(IterStatus(iter), "c->vc"); + iter->Next(); + ASSERT_EQ(IterStatus(iter), "d->" + std::string(100000, 'd')); + iter->Next(); + ASSERT_EQ(IterStatus(iter), "e->" + std::string(100000, 'e')); + iter->Next(); + ASSERT_EQ(IterStatus(iter), "(invalid)"); + + iter->SeekToLast(); + ASSERT_EQ(IterStatus(iter), "e->" + std::string(100000, 'e')); + iter->Prev(); + ASSERT_EQ(IterStatus(iter), "d->" + std::string(100000, 'd')); + iter->Prev(); + ASSERT_EQ(IterStatus(iter), "c->vc"); + iter->Prev(); + ASSERT_EQ(IterStatus(iter), "b->" + std::string(100000, 'b')); + iter->Prev(); + ASSERT_EQ(IterStatus(iter), "a->va"); + iter->Prev(); + ASSERT_EQ(IterStatus(iter), "(invalid)"); + + delete iter; +} + +TEST(DBTest, IterMultiWithDelete) { + do { + ASSERT_OK(Put("a", "va")); + ASSERT_OK(Put("b", "vb")); + ASSERT_OK(Put("c", "vc")); + ASSERT_OK(Delete("b")); + ASSERT_EQ("NOT_FOUND", Get("b")); + + Iterator* iter = db_->NewIterator(ReadOptions()); + iter->Seek("c"); + ASSERT_EQ(IterStatus(iter), "c->vc"); + iter->Prev(); + ASSERT_EQ(IterStatus(iter), "a->va"); + delete iter; + } while (ChangeOptions()); +} + +TEST(DBTest, Recover) { + do { + ASSERT_OK(Put("foo", "v1")); + ASSERT_OK(Put("baz", "v5")); + + Reopen(); + ASSERT_EQ("v1", Get("foo")); + + ASSERT_EQ("v1", Get("foo")); + ASSERT_EQ("v5", Get("baz")); + ASSERT_OK(Put("bar", "v2")); + ASSERT_OK(Put("foo", "v3")); + + Reopen(); + ASSERT_EQ("v3", Get("foo")); + ASSERT_OK(Put("foo", "v4")); + ASSERT_EQ("v4", Get("foo")); + ASSERT_EQ("v2", Get("bar")); + ASSERT_EQ("v5", Get("baz")); + } while (ChangeOptions()); +} + +TEST(DBTest, RecoveryWithEmptyLog) { + do { + ASSERT_OK(Put("foo", "v1")); + ASSERT_OK(Put("foo", "v2")); + Reopen(); + Reopen(); + ASSERT_OK(Put("foo", "v3")); + Reopen(); + ASSERT_EQ("v3", Get("foo")); + } while (ChangeOptions()); +} + +// Check that writes done during a memtable compaction are recovered +// if the database is shutdown during the memtable compaction. +TEST(DBTest, RecoverDuringMemtableCompaction) { + do { + Options options = CurrentOptions(); + options.env = env_; + options.write_buffer_size = 1000000; + Reopen(&options); + + // Trigger a long memtable compaction and reopen the database during it + ASSERT_OK(Put("foo", "v1")); // Goes to 1st log file + ASSERT_OK(Put("big1", std::string(10000000, 'x'))); // Fills memtable + ASSERT_OK(Put("big2", std::string(1000, 'y'))); // Triggers compaction + ASSERT_OK(Put("bar", "v2")); // Goes to new log file + + Reopen(&options); + ASSERT_EQ("v1", Get("foo")); + ASSERT_EQ("v2", Get("bar")); + ASSERT_EQ(std::string(10000000, 'x'), Get("big1")); + ASSERT_EQ(std::string(1000, 'y'), Get("big2")); + } while (ChangeOptions()); +} + +static std::string Key(int i) { + char buf[100]; + snprintf(buf, sizeof(buf), "key%06d", i); + return std::string(buf); +} + +TEST(DBTest, MinorCompactionsHappen) { + Options options = CurrentOptions(); + options.write_buffer_size = 10000; + Reopen(&options); + + const int N = 500; + + int starting_num_tables = TotalTableFiles(); + for (int i = 0; i < N; i++) { + ASSERT_OK(Put(Key(i), Key(i) + std::string(1000, 'v'))); + } + int ending_num_tables = TotalTableFiles(); + ASSERT_GT(ending_num_tables, starting_num_tables); + + for (int i = 0; i < N; i++) { + ASSERT_EQ(Key(i) + std::string(1000, 'v'), Get(Key(i))); + } + + Reopen(); + + for (int i = 0; i < N; i++) { + ASSERT_EQ(Key(i) + std::string(1000, 'v'), Get(Key(i))); + } +} + +TEST(DBTest, RecoverWithLargeLog) { + { + Options options = CurrentOptions(); + Reopen(&options); + ASSERT_OK(Put("big1", std::string(200000, '1'))); + ASSERT_OK(Put("big2", std::string(200000, '2'))); + ASSERT_OK(Put("small3", std::string(10, '3'))); + ASSERT_OK(Put("small4", std::string(10, '4'))); + ASSERT_EQ(NumTableFilesAtLevel(0), 0); + } + + // Make sure that if we re-open with a small write buffer size that + // we flush table files in the middle of a large log file. + Options options = CurrentOptions(); + options.write_buffer_size = 100000; + Reopen(&options); + ASSERT_EQ(NumTableFilesAtLevel(0), 3); + ASSERT_EQ(std::string(200000, '1'), Get("big1")); + ASSERT_EQ(std::string(200000, '2'), Get("big2")); + ASSERT_EQ(std::string(10, '3'), Get("small3")); + ASSERT_EQ(std::string(10, '4'), Get("small4")); + ASSERT_GT(NumTableFilesAtLevel(0), 1); +} + +TEST(DBTest, CompactionsGenerateMultipleFiles) { + Options options = CurrentOptions(); + options.write_buffer_size = 100000000; // Large write buffer + Reopen(&options); + + Random rnd(301); + + // Write 8MB (80 values, each 100K) + ASSERT_EQ(NumTableFilesAtLevel(0), 0); + std::vector values; + for (int i = 0; i < 80; i++) { + values.push_back(RandomString(&rnd, 100000)); + ASSERT_OK(Put(Key(i), values[i])); + } + + // Reopening moves updates to level-0 + Reopen(&options); + dbfull()->TEST_CompactRange(0, NULL, NULL); + + ASSERT_EQ(NumTableFilesAtLevel(0), 0); + ASSERT_GT(NumTableFilesAtLevel(1), 1); + for (int i = 0; i < 80; i++) { + ASSERT_EQ(Get(Key(i)), values[i]); + } +} + +TEST(DBTest, RepeatedWritesToSameKey) { + Options options = CurrentOptions(); + options.env = env_; + options.write_buffer_size = 100000; // Small write buffer + Reopen(&options); + + // We must have at most one file per level except for level-0, + // which may have up to kL0_StopWritesTrigger files. + const int kMaxFiles = config::kNumLevels + config::kL0_StopWritesTrigger; + + Random rnd(301); + std::string value = RandomString(&rnd, 2 * options.write_buffer_size); + for (int i = 0; i < 5 * kMaxFiles; i++) { + Put("key", value); + ASSERT_LE(TotalTableFiles(), kMaxFiles); + fprintf(stderr, "after %d: %d files\n", int(i+1), TotalTableFiles()); + } +} + +TEST(DBTest, SparseMerge) { + Options options = CurrentOptions(); + options.compression = kNoCompression; + Reopen(&options); + + FillLevels("A", "Z"); + + // Suppose there is: + // small amount of data with prefix A + // large amount of data with prefix B + // small amount of data with prefix C + // and that recent updates have made small changes to all three prefixes. + // Check that we do not do a compaction that merges all of B in one shot. + const std::string value(1000, 'x'); + Put("A", "va"); + // Write approximately 100MB of "B" values + for (int i = 0; i < 100000; i++) { + char key[100]; + snprintf(key, sizeof(key), "B%010d", i); + Put(key, value); + } + Put("C", "vc"); + dbfull()->TEST_CompactMemTable(); + dbfull()->TEST_CompactRange(0, NULL, NULL); + + // Make sparse update + Put("A", "va2"); + Put("B100", "bvalue2"); + Put("C", "vc2"); + dbfull()->TEST_CompactMemTable(); + + // Compactions should not cause us to create a situation where + // a file overlaps too much data at the next level. + ASSERT_LE(dbfull()->TEST_MaxNextLevelOverlappingBytes(), 20*1048576); + dbfull()->TEST_CompactRange(0, NULL, NULL); + ASSERT_LE(dbfull()->TEST_MaxNextLevelOverlappingBytes(), 20*1048576); + dbfull()->TEST_CompactRange(1, NULL, NULL); + ASSERT_LE(dbfull()->TEST_MaxNextLevelOverlappingBytes(), 20*1048576); +} + +static bool Between(uint64_t val, uint64_t low, uint64_t high) { + bool result = (val >= low) && (val <= high); + if (!result) { + fprintf(stderr, "Value %llu is not in range [%llu, %llu]\n", + (unsigned long long)(val), + (unsigned long long)(low), + (unsigned long long)(high)); + } + return result; +} + +TEST(DBTest, ApproximateSizes) { + do { + Options options = CurrentOptions(); + options.write_buffer_size = 100000000; // Large write buffer + options.compression = kNoCompression; + DestroyAndReopen(); + + ASSERT_TRUE(Between(Size("", "xyz"), 0, 0)); + Reopen(&options); + ASSERT_TRUE(Between(Size("", "xyz"), 0, 0)); + + // Write 8MB (80 values, each 100K) + ASSERT_EQ(NumTableFilesAtLevel(0), 0); + const int N = 80; + static const int S1 = 100000; + static const int S2 = 105000; // Allow some expansion from metadata + Random rnd(301); + for (int i = 0; i < N; i++) { + ASSERT_OK(Put(Key(i), RandomString(&rnd, S1))); + } + + // 0 because GetApproximateSizes() does not account for memtable space + ASSERT_TRUE(Between(Size("", Key(50)), 0, 0)); + + // Check sizes across recovery by reopening a few times + for (int run = 0; run < 3; run++) { + Reopen(&options); + + for (int compact_start = 0; compact_start < N; compact_start += 10) { + for (int i = 0; i < N; i += 10) { + ASSERT_TRUE(Between(Size("", Key(i)), S1*i, S2*i)); + ASSERT_TRUE(Between(Size("", Key(i)+".suffix"), S1*(i+1), S2*(i+1))); + ASSERT_TRUE(Between(Size(Key(i), Key(i+10)), S1*10, S2*10)); + } + ASSERT_TRUE(Between(Size("", Key(50)), S1*50, S2*50)); + ASSERT_TRUE(Between(Size("", Key(50)+".suffix"), S1*50, S2*50)); + + std::string cstart_str = Key(compact_start); + std::string cend_str = Key(compact_start + 9); + Slice cstart = cstart_str; + Slice cend = cend_str; + dbfull()->TEST_CompactRange(0, &cstart, &cend); + } + + ASSERT_EQ(NumTableFilesAtLevel(0), 0); + ASSERT_GT(NumTableFilesAtLevel(1), 0); + } + } while (ChangeOptions()); +} + +TEST(DBTest, ApproximateSizes_MixOfSmallAndLarge) { + do { + Options options = CurrentOptions(); + options.compression = kNoCompression; + Reopen(); + + Random rnd(301); + std::string big1 = RandomString(&rnd, 100000); + ASSERT_OK(Put(Key(0), RandomString(&rnd, 10000))); + ASSERT_OK(Put(Key(1), RandomString(&rnd, 10000))); + ASSERT_OK(Put(Key(2), big1)); + ASSERT_OK(Put(Key(3), RandomString(&rnd, 10000))); + ASSERT_OK(Put(Key(4), big1)); + ASSERT_OK(Put(Key(5), RandomString(&rnd, 10000))); + ASSERT_OK(Put(Key(6), RandomString(&rnd, 300000))); + ASSERT_OK(Put(Key(7), RandomString(&rnd, 10000))); + + // Check sizes across recovery by reopening a few times + for (int run = 0; run < 3; run++) { + Reopen(&options); + + ASSERT_TRUE(Between(Size("", Key(0)), 0, 0)); + ASSERT_TRUE(Between(Size("", Key(1)), 10000, 11000)); + ASSERT_TRUE(Between(Size("", Key(2)), 20000, 21000)); + ASSERT_TRUE(Between(Size("", Key(3)), 120000, 121000)); + ASSERT_TRUE(Between(Size("", Key(4)), 130000, 131000)); + ASSERT_TRUE(Between(Size("", Key(5)), 230000, 231000)); + ASSERT_TRUE(Between(Size("", Key(6)), 240000, 241000)); + ASSERT_TRUE(Between(Size("", Key(7)), 540000, 541000)); + ASSERT_TRUE(Between(Size("", Key(8)), 550000, 560000)); + + ASSERT_TRUE(Between(Size(Key(3), Key(5)), 110000, 111000)); + + dbfull()->TEST_CompactRange(0, NULL, NULL); + } + } while (ChangeOptions()); +} + +TEST(DBTest, IteratorPinsRef) { + Put("foo", "hello"); + + // Get iterator that will yield the current contents of the DB. + Iterator* iter = db_->NewIterator(ReadOptions()); + + // Write to force compactions + Put("foo", "newvalue1"); + for (int i = 0; i < 100; i++) { + ASSERT_OK(Put(Key(i), Key(i) + std::string(100000, 'v'))); // 100K values + } + Put("foo", "newvalue2"); + + iter->SeekToFirst(); + ASSERT_TRUE(iter->Valid()); + ASSERT_EQ("foo", iter->key().ToString()); + ASSERT_EQ("hello", iter->value().ToString()); + iter->Next(); + ASSERT_TRUE(!iter->Valid()); + delete iter; +} + +TEST(DBTest, Snapshot) { + do { + Put("foo", "v1"); + const Snapshot* s1 = db_->GetSnapshot(); + Put("foo", "v2"); + const Snapshot* s2 = db_->GetSnapshot(); + Put("foo", "v3"); + const Snapshot* s3 = db_->GetSnapshot(); + + Put("foo", "v4"); + ASSERT_EQ("v1", Get("foo", s1)); + ASSERT_EQ("v2", Get("foo", s2)); + ASSERT_EQ("v3", Get("foo", s3)); + ASSERT_EQ("v4", Get("foo")); + + db_->ReleaseSnapshot(s3); + ASSERT_EQ("v1", Get("foo", s1)); + ASSERT_EQ("v2", Get("foo", s2)); + ASSERT_EQ("v4", Get("foo")); + + db_->ReleaseSnapshot(s1); + ASSERT_EQ("v2", Get("foo", s2)); + ASSERT_EQ("v4", Get("foo")); + + db_->ReleaseSnapshot(s2); + ASSERT_EQ("v4", Get("foo")); + } while (ChangeOptions()); +} + +TEST(DBTest, HiddenValuesAreRemoved) { + do { + Random rnd(301); + FillLevels("a", "z"); + + std::string big = RandomString(&rnd, 50000); + Put("foo", big); + Put("pastfoo", "v"); + const Snapshot* snapshot = db_->GetSnapshot(); + Put("foo", "tiny"); + Put("pastfoo2", "v2"); // Advance sequence number one more + + ASSERT_OK(dbfull()->TEST_CompactMemTable()); + ASSERT_GT(NumTableFilesAtLevel(0), 0); + + ASSERT_EQ(big, Get("foo", snapshot)); + ASSERT_TRUE(Between(Size("", "pastfoo"), 50000, 60000)); + db_->ReleaseSnapshot(snapshot); + ASSERT_EQ(AllEntriesFor("foo"), "[ tiny, " + big + " ]"); + Slice x("x"); + dbfull()->TEST_CompactRange(0, NULL, &x); + ASSERT_EQ(AllEntriesFor("foo"), "[ tiny ]"); + ASSERT_EQ(NumTableFilesAtLevel(0), 0); + ASSERT_GE(NumTableFilesAtLevel(1), 1); + dbfull()->TEST_CompactRange(1, NULL, &x); + ASSERT_EQ(AllEntriesFor("foo"), "[ tiny ]"); + + ASSERT_TRUE(Between(Size("", "pastfoo"), 0, 1000)); + } while (ChangeOptions()); +} + +TEST(DBTest, DeletionMarkers1) { + Put("foo", "v1"); + ASSERT_OK(dbfull()->TEST_CompactMemTable()); + const int last = config::kMaxMemCompactLevel; + ASSERT_EQ(NumTableFilesAtLevel(last), 1); // foo => v1 is now in last level + + // Place a table at level last-1 to prevent merging with preceding mutation + Put("a", "begin"); + Put("z", "end"); + dbfull()->TEST_CompactMemTable(); + ASSERT_EQ(NumTableFilesAtLevel(last), 1); + ASSERT_EQ(NumTableFilesAtLevel(last-1), 1); + + Delete("foo"); + Put("foo", "v2"); + ASSERT_EQ(AllEntriesFor("foo"), "[ v2, DEL, v1 ]"); + ASSERT_OK(dbfull()->TEST_CompactMemTable()); // Moves to level last-2 + ASSERT_EQ(AllEntriesFor("foo"), "[ v2, DEL, v1 ]"); + Slice z("z"); + dbfull()->TEST_CompactRange(last-2, NULL, &z); + // DEL eliminated, but v1 remains because we aren't compacting that level + // (DEL can be eliminated because v2 hides v1). + ASSERT_EQ(AllEntriesFor("foo"), "[ v2, v1 ]"); + dbfull()->TEST_CompactRange(last-1, NULL, NULL); + // Merging last-1 w/ last, so we are the base level for "foo", so + // DEL is removed. (as is v1). + ASSERT_EQ(AllEntriesFor("foo"), "[ v2 ]"); +} + +TEST(DBTest, DeletionMarkers2) { + Put("foo", "v1"); + ASSERT_OK(dbfull()->TEST_CompactMemTable()); + const int last = config::kMaxMemCompactLevel; + ASSERT_EQ(NumTableFilesAtLevel(last), 1); // foo => v1 is now in last level + + // Place a table at level last-1 to prevent merging with preceding mutation + Put("a", "begin"); + Put("z", "end"); + dbfull()->TEST_CompactMemTable(); + ASSERT_EQ(NumTableFilesAtLevel(last), 1); + ASSERT_EQ(NumTableFilesAtLevel(last-1), 1); + + Delete("foo"); + ASSERT_EQ(AllEntriesFor("foo"), "[ DEL, v1 ]"); + ASSERT_OK(dbfull()->TEST_CompactMemTable()); // Moves to level last-2 + ASSERT_EQ(AllEntriesFor("foo"), "[ DEL, v1 ]"); + dbfull()->TEST_CompactRange(last-2, NULL, NULL); + // DEL kept: "last" file overlaps + ASSERT_EQ(AllEntriesFor("foo"), "[ DEL, v1 ]"); + dbfull()->TEST_CompactRange(last-1, NULL, NULL); + // Merging last-1 w/ last, so we are the base level for "foo", so + // DEL is removed. (as is v1). + ASSERT_EQ(AllEntriesFor("foo"), "[ ]"); +} + +TEST(DBTest, OverlapInLevel0) { + do { + ASSERT_EQ(config::kMaxMemCompactLevel, 2) << "Fix test to match config"; + + // Fill levels 1 and 2 to disable the pushing of new memtables to levels > 0. + ASSERT_OK(Put("100", "v100")); + ASSERT_OK(Put("999", "v999")); + dbfull()->TEST_CompactMemTable(); + ASSERT_OK(Delete("100")); + ASSERT_OK(Delete("999")); + dbfull()->TEST_CompactMemTable(); + ASSERT_EQ("0,1,1", FilesPerLevel()); + + // Make files spanning the following ranges in level-0: + // files[0] 200 .. 900 + // files[1] 300 .. 500 + // Note that files are sorted by smallest key. + ASSERT_OK(Put("300", "v300")); + ASSERT_OK(Put("500", "v500")); + dbfull()->TEST_CompactMemTable(); + ASSERT_OK(Put("200", "v200")); + ASSERT_OK(Put("600", "v600")); + ASSERT_OK(Put("900", "v900")); + dbfull()->TEST_CompactMemTable(); + ASSERT_EQ("2,1,1", FilesPerLevel()); + + // Compact away the placeholder files we created initially + dbfull()->TEST_CompactRange(1, NULL, NULL); + dbfull()->TEST_CompactRange(2, NULL, NULL); + ASSERT_EQ("2", FilesPerLevel()); + + // Do a memtable compaction. Before bug-fix, the compaction would + // not detect the overlap with level-0 files and would incorrectly place + // the deletion in a deeper level. + ASSERT_OK(Delete("600")); + dbfull()->TEST_CompactMemTable(); + ASSERT_EQ("3", FilesPerLevel()); + ASSERT_EQ("NOT_FOUND", Get("600")); + } while (ChangeOptions()); +} + +TEST(DBTest, L0_CompactionBug_Issue44_a) { + Reopen(); + ASSERT_OK(Put("b", "v")); + Reopen(); + ASSERT_OK(Delete("b")); + ASSERT_OK(Delete("a")); + Reopen(); + ASSERT_OK(Delete("a")); + Reopen(); + ASSERT_OK(Put("a", "v")); + Reopen(); + Reopen(); + ASSERT_EQ("(a->v)", Contents()); + DelayMilliseconds(1000); // Wait for compaction to finish + ASSERT_EQ("(a->v)", Contents()); +} + +TEST(DBTest, L0_CompactionBug_Issue44_b) { + Reopen(); + Put("",""); + Reopen(); + Delete("e"); + Put("",""); + Reopen(); + Put("c", "cv"); + Reopen(); + Put("",""); + Reopen(); + Put("",""); + DelayMilliseconds(1000); // Wait for compaction to finish + Reopen(); + Put("d","dv"); + Reopen(); + Put("",""); + Reopen(); + Delete("d"); + Delete("b"); + Reopen(); + ASSERT_EQ("(->)(c->cv)", Contents()); + DelayMilliseconds(1000); // Wait for compaction to finish + ASSERT_EQ("(->)(c->cv)", Contents()); +} + +TEST(DBTest, ComparatorCheck) { + class NewComparator : public Comparator { + public: + virtual const char* Name() const { return "leveldb.NewComparator"; } + virtual int Compare(const Slice& a, const Slice& b) const { + return BytewiseComparator()->Compare(a, b); + } + virtual void FindShortestSeparator(std::string* s, const Slice& l) const { + BytewiseComparator()->FindShortestSeparator(s, l); + } + virtual void FindShortSuccessor(std::string* key) const { + BytewiseComparator()->FindShortSuccessor(key); + } + }; + NewComparator cmp; + Options new_options = CurrentOptions(); + new_options.comparator = &cmp; + Status s = TryReopen(&new_options); + ASSERT_TRUE(!s.ok()); + ASSERT_TRUE(s.ToString().find("comparator") != std::string::npos) + << s.ToString(); +} + +TEST(DBTest, CustomComparator) { + class NumberComparator : public Comparator { + public: + virtual const char* Name() const { return "test.NumberComparator"; } + virtual int Compare(const Slice& a, const Slice& b) const { + return ToNumber(a) - ToNumber(b); + } + virtual void FindShortestSeparator(std::string* s, const Slice& l) const { + ToNumber(*s); // Check format + ToNumber(l); // Check format + } + virtual void FindShortSuccessor(std::string* key) const { + ToNumber(*key); // Check format + } + private: + static int ToNumber(const Slice& x) { + // Check that there are no extra characters. + ASSERT_TRUE(x.size() >= 2 && x[0] == '[' && x[x.size()-1] == ']') + << EscapeString(x); + int val; + char ignored; + ASSERT_TRUE(sscanf(x.ToString().c_str(), "[%i]%c", &val, &ignored) == 1) + << EscapeString(x); + return val; + } + }; + NumberComparator cmp; + Options new_options = CurrentOptions(); + new_options.create_if_missing = true; + new_options.comparator = &cmp; + new_options.filter_policy = NULL; // Cannot use bloom filters + new_options.write_buffer_size = 1000; // Compact more often + DestroyAndReopen(&new_options); + ASSERT_OK(Put("[10]", "ten")); + ASSERT_OK(Put("[0x14]", "twenty")); + for (int i = 0; i < 2; i++) { + ASSERT_EQ("ten", Get("[10]")); + ASSERT_EQ("ten", Get("[0xa]")); + ASSERT_EQ("twenty", Get("[20]")); + ASSERT_EQ("twenty", Get("[0x14]")); + ASSERT_EQ("NOT_FOUND", Get("[15]")); + ASSERT_EQ("NOT_FOUND", Get("[0xf]")); + Compact("[0]", "[9999]"); + } + + for (int run = 0; run < 2; run++) { + for (int i = 0; i < 1000; i++) { + char buf[100]; + snprintf(buf, sizeof(buf), "[%d]", i*10); + ASSERT_OK(Put(buf, buf)); + } + Compact("[0]", "[1000000]"); + } +} + +TEST(DBTest, ManualCompaction) { + ASSERT_EQ(config::kMaxMemCompactLevel, 2) + << "Need to update this test to match kMaxMemCompactLevel"; + + MakeTables(3, "p", "q"); + ASSERT_EQ("1,1,1", FilesPerLevel()); + + // Compaction range falls before files + Compact("", "c"); + ASSERT_EQ("1,1,1", FilesPerLevel()); + + // Compaction range falls after files + Compact("r", "z"); + ASSERT_EQ("1,1,1", FilesPerLevel()); + + // Compaction range overlaps files + Compact("p1", "p9"); + ASSERT_EQ("0,0,1", FilesPerLevel()); + + // Populate a different range + MakeTables(3, "c", "e"); + ASSERT_EQ("1,1,2", FilesPerLevel()); + + // Compact just the new range + Compact("b", "f"); + ASSERT_EQ("0,0,2", FilesPerLevel()); + + // Compact all + MakeTables(1, "a", "z"); + ASSERT_EQ("0,1,2", FilesPerLevel()); + db_->CompactRange(NULL, NULL); + ASSERT_EQ("0,0,1", FilesPerLevel()); +} + +TEST(DBTest, DBOpen_Options) { + std::string dbname = test::TmpDir() + "/db_options_test"; + DestroyDB(dbname, Options()); + + // Does not exist, and create_if_missing == false: error + DB* db = NULL; + Options opts; + opts.create_if_missing = false; + Status s = DB::Open(opts, dbname, &db); + ASSERT_TRUE(strstr(s.ToString().c_str(), "does not exist") != NULL); + ASSERT_TRUE(db == NULL); + + // Does not exist, and create_if_missing == true: OK + opts.create_if_missing = true; + s = DB::Open(opts, dbname, &db); + ASSERT_OK(s); + ASSERT_TRUE(db != NULL); + + delete db; + db = NULL; + + // Does exist, and error_if_exists == true: error + opts.create_if_missing = false; + opts.error_if_exists = true; + s = DB::Open(opts, dbname, &db); + ASSERT_TRUE(strstr(s.ToString().c_str(), "exists") != NULL); + ASSERT_TRUE(db == NULL); + + // Does exist, and error_if_exists == false: OK + opts.create_if_missing = true; + opts.error_if_exists = false; + s = DB::Open(opts, dbname, &db); + ASSERT_OK(s); + ASSERT_TRUE(db != NULL); + + delete db; + db = NULL; +} + +TEST(DBTest, Locking) { + DB* db2 = NULL; + Status s = DB::Open(CurrentOptions(), dbname_, &db2); + ASSERT_TRUE(!s.ok()) << "Locking did not prevent re-opening db"; +} + +// Check that number of files does not grow when we are out of space +TEST(DBTest, NoSpace) { + Options options = CurrentOptions(); + options.env = env_; + Reopen(&options); + + ASSERT_OK(Put("foo", "v1")); + ASSERT_EQ("v1", Get("foo")); + Compact("a", "z"); + const int num_files = CountFiles(); + env_->no_space_.Release_Store(env_); // Force out-of-space errors + for (int i = 0; i < 10; i++) { + for (int level = 0; level < config::kNumLevels-1; level++) { + dbfull()->TEST_CompactRange(level, NULL, NULL); + } + } + env_->no_space_.Release_Store(NULL); + ASSERT_LT(CountFiles(), num_files + 3); +} + +TEST(DBTest, NonWritableFileSystem) { + Options options = CurrentOptions(); + options.write_buffer_size = 1000; + options.env = env_; + Reopen(&options); + ASSERT_OK(Put("foo", "v1")); + env_->non_writable_.Release_Store(env_); // Force errors for new files + std::string big(100000, 'x'); + int errors = 0; + for (int i = 0; i < 20; i++) { + fprintf(stderr, "iter %d; errors %d\n", i, errors); + if (!Put("foo", big).ok()) { + errors++; + DelayMilliseconds(100); + } + } + ASSERT_GT(errors, 0); + env_->non_writable_.Release_Store(NULL); +} + +TEST(DBTest, WriteSyncError) { + // Check that log sync errors cause the DB to disallow future writes. + + // (a) Cause log sync calls to fail + Options options = CurrentOptions(); + options.env = env_; + Reopen(&options); + env_->data_sync_error_.Release_Store(env_); + + // (b) Normal write should succeed + WriteOptions w; + ASSERT_OK(db_->Put(w, "k1", "v1")); + ASSERT_EQ("v1", Get("k1")); + + // (c) Do a sync write; should fail + w.sync = true; + ASSERT_TRUE(!db_->Put(w, "k2", "v2").ok()); + ASSERT_EQ("v1", Get("k1")); + ASSERT_EQ("NOT_FOUND", Get("k2")); + + // (d) make sync behave normally + env_->data_sync_error_.Release_Store(NULL); + + // (e) Do a non-sync write; should fail + w.sync = false; + ASSERT_TRUE(!db_->Put(w, "k3", "v3").ok()); + ASSERT_EQ("v1", Get("k1")); + ASSERT_EQ("NOT_FOUND", Get("k2")); + ASSERT_EQ("NOT_FOUND", Get("k3")); +} + +TEST(DBTest, ManifestWriteError) { + // Test for the following problem: + // (a) Compaction produces file F + // (b) Log record containing F is written to MANIFEST file, but Sync() fails + // (c) GC deletes F + // (d) After reopening DB, reads fail since deleted F is named in log record + + // We iterate twice. In the second iteration, everything is the + // same except the log record never makes it to the MANIFEST file. + for (int iter = 0; iter < 2; iter++) { + port::AtomicPointer* error_type = (iter == 0) + ? &env_->manifest_sync_error_ + : &env_->manifest_write_error_; + + // Insert foo=>bar mapping + Options options = CurrentOptions(); + options.env = env_; + options.create_if_missing = true; + options.error_if_exists = false; + DestroyAndReopen(&options); + ASSERT_OK(Put("foo", "bar")); + ASSERT_EQ("bar", Get("foo")); + + // Memtable compaction (will succeed) + dbfull()->TEST_CompactMemTable(); + ASSERT_EQ("bar", Get("foo")); + const int last = config::kMaxMemCompactLevel; + ASSERT_EQ(NumTableFilesAtLevel(last), 1); // foo=>bar is now in last level + + // Merging compaction (will fail) + error_type->Release_Store(env_); + dbfull()->TEST_CompactRange(last, NULL, NULL); // Should fail + ASSERT_EQ("bar", Get("foo")); + + // Recovery: should not lose data + error_type->Release_Store(NULL); + Reopen(&options); + ASSERT_EQ("bar", Get("foo")); + } +} + +TEST(DBTest, MissingSSTFile) { + ASSERT_OK(Put("foo", "bar")); + ASSERT_EQ("bar", Get("foo")); + + // Dump the memtable to disk. + dbfull()->TEST_CompactMemTable(); + ASSERT_EQ("bar", Get("foo")); + + Close(); + ASSERT_TRUE(DeleteAnSSTFile()); + Options options = CurrentOptions(); + options.paranoid_checks = true; + Status s = TryReopen(&options); + ASSERT_TRUE(!s.ok()); + ASSERT_TRUE(s.ToString().find("issing") != std::string::npos) + << s.ToString(); +} + +TEST(DBTest, StillReadSST) { + ASSERT_OK(Put("foo", "bar")); + ASSERT_EQ("bar", Get("foo")); + + // Dump the memtable to disk. + dbfull()->TEST_CompactMemTable(); + ASSERT_EQ("bar", Get("foo")); + Close(); + ASSERT_GT(RenameLDBToSST(), 0); + Options options = CurrentOptions(); + options.paranoid_checks = true; + Status s = TryReopen(&options); + ASSERT_TRUE(s.ok()); + ASSERT_EQ("bar", Get("foo")); +} + +TEST(DBTest, FilesDeletedAfterCompaction) { + ASSERT_OK(Put("foo", "v2")); + Compact("a", "z"); + const int num_files = CountFiles(); + for (int i = 0; i < 10; i++) { + ASSERT_OK(Put("foo", "v2")); + Compact("a", "z"); + } + ASSERT_EQ(CountFiles(), num_files); +} + +TEST(DBTest, BloomFilter) { + env_->count_random_reads_ = true; + Options options = CurrentOptions(); + options.env = env_; + options.block_cache = NewLRUCache(0); // Prevent cache hits + options.filter_policy = NewBloomFilterPolicy(10); + Reopen(&options); + + // Populate multiple layers + const int N = 10000; + for (int i = 0; i < N; i++) { + ASSERT_OK(Put(Key(i), Key(i))); + } + Compact("a", "z"); + for (int i = 0; i < N; i += 100) { + ASSERT_OK(Put(Key(i), Key(i))); + } + dbfull()->TEST_CompactMemTable(); + + // Prevent auto compactions triggered by seeks + env_->delay_data_sync_.Release_Store(env_); + + // Lookup present keys. Should rarely read from small sstable. + env_->random_read_counter_.Reset(); + for (int i = 0; i < N; i++) { + ASSERT_EQ(Key(i), Get(Key(i))); + } + int reads = env_->random_read_counter_.Read(); + fprintf(stderr, "%d present => %d reads\n", N, reads); + ASSERT_GE(reads, N); + ASSERT_LE(reads, N + 2*N/100); + + // Lookup present keys. Should rarely read from either sstable. + env_->random_read_counter_.Reset(); + for (int i = 0; i < N; i++) { + ASSERT_EQ("NOT_FOUND", Get(Key(i) + ".missing")); + } + reads = env_->random_read_counter_.Read(); + fprintf(stderr, "%d missing => %d reads\n", N, reads); + ASSERT_LE(reads, 3*N/100); + + env_->delay_data_sync_.Release_Store(NULL); + Close(); + delete options.block_cache; + delete options.filter_policy; +} + +// Multi-threaded test: +namespace { + +static const int kNumThreads = 4; +static const int kTestSeconds = 10; +static const int kNumKeys = 1000; + +struct MTState { + DBTest* test; + port::AtomicPointer stop; + port::AtomicPointer counter[kNumThreads]; + port::AtomicPointer thread_done[kNumThreads]; +}; + +struct MTThread { + MTState* state; + int id; +}; + +static void MTThreadBody(void* arg) { + MTThread* t = reinterpret_cast(arg); + int id = t->id; + DB* db = t->state->test->db_; + uintptr_t counter = 0; + fprintf(stderr, "... starting thread %d\n", id); + Random rnd(1000 + id); + std::string value; + char valbuf[1500]; + while (t->state->stop.Acquire_Load() == NULL) { + t->state->counter[id].Release_Store(reinterpret_cast(counter)); + + int key = rnd.Uniform(kNumKeys); + char keybuf[20]; + snprintf(keybuf, sizeof(keybuf), "%016d", key); + + if (rnd.OneIn(2)) { + // Write values of the form . + // We add some padding for force compactions. + snprintf(valbuf, sizeof(valbuf), "%d.%d.%-1000d", + key, id, static_cast(counter)); + ASSERT_OK(db->Put(WriteOptions(), Slice(keybuf), Slice(valbuf))); + } else { + // Read a value and verify that it matches the pattern written above. + Status s = db->Get(ReadOptions(), Slice(keybuf), &value); + if (s.IsNotFound()) { + // Key has not yet been written + } else { + // Check that the writer thread counter is >= the counter in the value + ASSERT_OK(s); + int k, w, c; + ASSERT_EQ(3, sscanf(value.c_str(), "%d.%d.%d", &k, &w, &c)) << value; + ASSERT_EQ(k, key); + ASSERT_GE(w, 0); + ASSERT_LT(w, kNumThreads); + ASSERT_LE(static_cast(c), reinterpret_cast( + t->state->counter[w].Acquire_Load())); + } + } + counter++; + } + t->state->thread_done[id].Release_Store(t); + fprintf(stderr, "... stopping thread %d after %d ops\n", id, int(counter)); +} + +} // namespace + +TEST(DBTest, MultiThreaded) { + do { + // Initialize state + MTState mt; + mt.test = this; + mt.stop.Release_Store(0); + for (int id = 0; id < kNumThreads; id++) { + mt.counter[id].Release_Store(0); + mt.thread_done[id].Release_Store(0); + } + + // Start threads + MTThread thread[kNumThreads]; + for (int id = 0; id < kNumThreads; id++) { + thread[id].state = &mt; + thread[id].id = id; + env_->StartThread(MTThreadBody, &thread[id]); + } + + // Let them run for a while + DelayMilliseconds(kTestSeconds * 1000); + + // Stop the threads and wait for them to finish + mt.stop.Release_Store(&mt); + for (int id = 0; id < kNumThreads; id++) { + while (mt.thread_done[id].Acquire_Load() == NULL) { + DelayMilliseconds(100); + } + } + } while (ChangeOptions()); +} + +namespace { +typedef std::map KVMap; +} + +class ModelDB: public DB { + public: + class ModelSnapshot : public Snapshot { + public: + KVMap map_; + }; + + explicit ModelDB(const Options& options): options_(options) { } + ~ModelDB() { } + virtual Status Put(const WriteOptions& o, const Slice& k, const Slice& v) { + return DB::Put(o, k, v); + } + virtual Status Delete(const WriteOptions& o, const Slice& key) { + return DB::Delete(o, key); + } + virtual Status Get(const ReadOptions& options, + const Slice& key, std::string* value) { + assert(false); // Not implemented + return Status::NotFound(key); + } + virtual Iterator* NewIterator(const ReadOptions& options) { + if (options.snapshot == NULL) { + KVMap* saved = new KVMap; + *saved = map_; + return new ModelIter(saved, true); + } else { + const KVMap* snapshot_state = + &(reinterpret_cast(options.snapshot)->map_); + return new ModelIter(snapshot_state, false); + } + } + virtual const Snapshot* GetSnapshot() { + ModelSnapshot* snapshot = new ModelSnapshot; + snapshot->map_ = map_; + return snapshot; + } + + virtual void ReleaseSnapshot(const Snapshot* snapshot) { + delete reinterpret_cast(snapshot); + } + virtual Status Write(const WriteOptions& options, WriteBatch* batch) { + class Handler : public WriteBatch::Handler { + public: + KVMap* map_; + virtual void Put(const Slice& key, const Slice& value) { + (*map_)[key.ToString()] = value.ToString(); + } + virtual void Delete(const Slice& key) { + map_->erase(key.ToString()); + } + }; + Handler handler; + handler.map_ = &map_; + return batch->Iterate(&handler); + } + + virtual bool GetProperty(const Slice& property, std::string* value) { + return false; + } + virtual void GetApproximateSizes(const Range* r, int n, uint64_t* sizes) { + for (int i = 0; i < n; i++) { + sizes[i] = 0; + } + } + virtual void CompactRange(const Slice* start, const Slice* end) { + } + + private: + class ModelIter: public Iterator { + public: + ModelIter(const KVMap* map, bool owned) + : map_(map), owned_(owned), iter_(map_->end()) { + } + ~ModelIter() { + if (owned_) delete map_; + } + virtual bool Valid() const { return iter_ != map_->end(); } + virtual void SeekToFirst() { iter_ = map_->begin(); } + virtual void SeekToLast() { + if (map_->empty()) { + iter_ = map_->end(); + } else { + iter_ = map_->find(map_->rbegin()->first); + } + } + virtual void Seek(const Slice& k) { + iter_ = map_->lower_bound(k.ToString()); + } + virtual void Next() { ++iter_; } + virtual void Prev() { --iter_; } + virtual Slice key() const { return iter_->first; } + virtual Slice value() const { return iter_->second; } + virtual Status status() const { return Status::OK(); } + private: + const KVMap* const map_; + const bool owned_; // Do we own map_ + KVMap::const_iterator iter_; + }; + const Options options_; + KVMap map_; +}; + +static std::string RandomKey(Random* rnd) { + int len = (rnd->OneIn(3) + ? 1 // Short sometimes to encourage collisions + : (rnd->OneIn(100) ? rnd->Skewed(10) : rnd->Uniform(10))); + return test::RandomKey(rnd, len); +} + +static bool CompareIterators(int step, + DB* model, + DB* db, + const Snapshot* model_snap, + const Snapshot* db_snap) { + ReadOptions options; + options.snapshot = model_snap; + Iterator* miter = model->NewIterator(options); + options.snapshot = db_snap; + Iterator* dbiter = db->NewIterator(options); + bool ok = true; + int count = 0; + for (miter->SeekToFirst(), dbiter->SeekToFirst(); + ok && miter->Valid() && dbiter->Valid(); + miter->Next(), dbiter->Next()) { + count++; + if (miter->key().compare(dbiter->key()) != 0) { + fprintf(stderr, "step %d: Key mismatch: '%s' vs. '%s'\n", + step, + EscapeString(miter->key()).c_str(), + EscapeString(dbiter->key()).c_str()); + ok = false; + break; + } + + if (miter->value().compare(dbiter->value()) != 0) { + fprintf(stderr, "step %d: Value mismatch for key '%s': '%s' vs. '%s'\n", + step, + EscapeString(miter->key()).c_str(), + EscapeString(miter->value()).c_str(), + EscapeString(miter->value()).c_str()); + ok = false; + } + } + + if (ok) { + if (miter->Valid() != dbiter->Valid()) { + fprintf(stderr, "step %d: Mismatch at end of iterators: %d vs. %d\n", + step, miter->Valid(), dbiter->Valid()); + ok = false; + } + } + fprintf(stderr, "%d entries compared: ok=%d\n", count, ok); + delete miter; + delete dbiter; + return ok; +} + +TEST(DBTest, Randomized) { + Random rnd(test::RandomSeed()); + do { + ModelDB model(CurrentOptions()); + const int N = 10000; + const Snapshot* model_snap = NULL; + const Snapshot* db_snap = NULL; + std::string k, v; + for (int step = 0; step < N; step++) { + if (step % 100 == 0) { + fprintf(stderr, "Step %d of %d\n", step, N); + } + // TODO(sanjay): Test Get() works + int p = rnd.Uniform(100); + if (p < 45) { // Put + k = RandomKey(&rnd); + v = RandomString(&rnd, + rnd.OneIn(20) + ? 100 + rnd.Uniform(100) + : rnd.Uniform(8)); + ASSERT_OK(model.Put(WriteOptions(), k, v)); + ASSERT_OK(db_->Put(WriteOptions(), k, v)); + + } else if (p < 90) { // Delete + k = RandomKey(&rnd); + ASSERT_OK(model.Delete(WriteOptions(), k)); + ASSERT_OK(db_->Delete(WriteOptions(), k)); + + + } else { // Multi-element batch + WriteBatch b; + const int num = rnd.Uniform(8); + for (int i = 0; i < num; i++) { + if (i == 0 || !rnd.OneIn(10)) { + k = RandomKey(&rnd); + } else { + // Periodically re-use the same key from the previous iter, so + // we have multiple entries in the write batch for the same key + } + if (rnd.OneIn(2)) { + v = RandomString(&rnd, rnd.Uniform(10)); + b.Put(k, v); + } else { + b.Delete(k); + } + } + ASSERT_OK(model.Write(WriteOptions(), &b)); + ASSERT_OK(db_->Write(WriteOptions(), &b)); + } + + if ((step % 100) == 0) { + ASSERT_TRUE(CompareIterators(step, &model, db_, NULL, NULL)); + ASSERT_TRUE(CompareIterators(step, &model, db_, model_snap, db_snap)); + // Save a snapshot from each DB this time that we'll use next + // time we compare things, to make sure the current state is + // preserved with the snapshot + if (model_snap != NULL) model.ReleaseSnapshot(model_snap); + if (db_snap != NULL) db_->ReleaseSnapshot(db_snap); + + Reopen(); + ASSERT_TRUE(CompareIterators(step, &model, db_, NULL, NULL)); + + model_snap = model.GetSnapshot(); + db_snap = db_->GetSnapshot(); + } + } + if (model_snap != NULL) model.ReleaseSnapshot(model_snap); + if (db_snap != NULL) db_->ReleaseSnapshot(db_snap); + } while (ChangeOptions()); +} + +std::string MakeKey(unsigned int num) { + char buf[30]; + snprintf(buf, sizeof(buf), "%016u", num); + return std::string(buf); +} + +void BM_LogAndApply(int iters, int num_base_files) { + std::string dbname = test::TmpDir() + "/leveldb_test_benchmark"; + DestroyDB(dbname, Options()); + + DB* db = NULL; + Options opts; + opts.create_if_missing = true; + Status s = DB::Open(opts, dbname, &db); + ASSERT_OK(s); + ASSERT_TRUE(db != NULL); + + delete db; + db = NULL; + + Env* env = Env::Default(); + + port::Mutex mu; + MutexLock l(&mu); + + InternalKeyComparator cmp(BytewiseComparator()); + Options options; + VersionSet vset(dbname, &options, NULL, &cmp); + ASSERT_OK(vset.Recover()); + VersionEdit vbase; + uint64_t fnum = 1; + for (int i = 0; i < num_base_files; i++) { + InternalKey start(MakeKey(2*fnum), 1, kTypeValue); + InternalKey limit(MakeKey(2*fnum+1), 1, kTypeDeletion); + vbase.AddFile(2, fnum++, 1 /* file size */, start, limit); + } + ASSERT_OK(vset.LogAndApply(&vbase, &mu)); + + uint64_t start_micros = env->NowMicros(); + + for (int i = 0; i < iters; i++) { + VersionEdit vedit; + vedit.DeleteFile(2, fnum); + InternalKey start(MakeKey(2*fnum), 1, kTypeValue); + InternalKey limit(MakeKey(2*fnum+1), 1, kTypeDeletion); + vedit.AddFile(2, fnum++, 1 /* file size */, start, limit); + vset.LogAndApply(&vedit, &mu); + } + uint64_t stop_micros = env->NowMicros(); + unsigned int us = stop_micros - start_micros; + char buf[16]; + snprintf(buf, sizeof(buf), "%d", num_base_files); + fprintf(stderr, + "BM_LogAndApply/%-6s %8d iters : %9u us (%7.0f us / iter)\n", + buf, iters, us, ((float)us) / iters); +} + +} // namespace leveldb + +int main(int argc, char** argv) { + if (argc > 1 && std::string(argv[1]) == "--benchmark") { + leveldb::BM_LogAndApply(1000, 1); + leveldb::BM_LogAndApply(1000, 100); + leveldb::BM_LogAndApply(1000, 10000); + leveldb::BM_LogAndApply(100, 100000); + return 0; + } + + return leveldb::test::RunAllTests(); +} diff --git a/ios/Pods/leveldb-library/db/dbformat.cc b/ios/Pods/leveldb-library/db/dbformat.cc new file mode 100644 index 000000000..20a7ca446 --- /dev/null +++ b/ios/Pods/leveldb-library/db/dbformat.cc @@ -0,0 +1,140 @@ +// Copyright (c) 2011 The LevelDB Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. See the AUTHORS file for names of contributors. + +#include +#include "db/dbformat.h" +#include "port/port.h" +#include "util/coding.h" + +namespace leveldb { + +static uint64_t PackSequenceAndType(uint64_t seq, ValueType t) { + assert(seq <= kMaxSequenceNumber); + assert(t <= kValueTypeForSeek); + return (seq << 8) | t; +} + +void AppendInternalKey(std::string* result, const ParsedInternalKey& key) { + result->append(key.user_key.data(), key.user_key.size()); + PutFixed64(result, PackSequenceAndType(key.sequence, key.type)); +} + +std::string ParsedInternalKey::DebugString() const { + char buf[50]; + snprintf(buf, sizeof(buf), "' @ %llu : %d", + (unsigned long long) sequence, + int(type)); + std::string result = "'"; + result += EscapeString(user_key.ToString()); + result += buf; + return result; +} + +std::string InternalKey::DebugString() const { + std::string result; + ParsedInternalKey parsed; + if (ParseInternalKey(rep_, &parsed)) { + result = parsed.DebugString(); + } else { + result = "(bad)"; + result.append(EscapeString(rep_)); + } + return result; +} + +const char* InternalKeyComparator::Name() const { + return "leveldb.InternalKeyComparator"; +} + +int InternalKeyComparator::Compare(const Slice& akey, const Slice& bkey) const { + // Order by: + // increasing user key (according to user-supplied comparator) + // decreasing sequence number + // decreasing type (though sequence# should be enough to disambiguate) + int r = user_comparator_->Compare(ExtractUserKey(akey), ExtractUserKey(bkey)); + if (r == 0) { + const uint64_t anum = DecodeFixed64(akey.data() + akey.size() - 8); + const uint64_t bnum = DecodeFixed64(bkey.data() + bkey.size() - 8); + if (anum > bnum) { + r = -1; + } else if (anum < bnum) { + r = +1; + } + } + return r; +} + +void InternalKeyComparator::FindShortestSeparator( + std::string* start, + const Slice& limit) const { + // Attempt to shorten the user portion of the key + Slice user_start = ExtractUserKey(*start); + Slice user_limit = ExtractUserKey(limit); + std::string tmp(user_start.data(), user_start.size()); + user_comparator_->FindShortestSeparator(&tmp, user_limit); + if (tmp.size() < user_start.size() && + user_comparator_->Compare(user_start, tmp) < 0) { + // User key has become shorter physically, but larger logically. + // Tack on the earliest possible number to the shortened user key. + PutFixed64(&tmp, PackSequenceAndType(kMaxSequenceNumber,kValueTypeForSeek)); + assert(this->Compare(*start, tmp) < 0); + assert(this->Compare(tmp, limit) < 0); + start->swap(tmp); + } +} + +void InternalKeyComparator::FindShortSuccessor(std::string* key) const { + Slice user_key = ExtractUserKey(*key); + std::string tmp(user_key.data(), user_key.size()); + user_comparator_->FindShortSuccessor(&tmp); + if (tmp.size() < user_key.size() && + user_comparator_->Compare(user_key, tmp) < 0) { + // User key has become shorter physically, but larger logically. + // Tack on the earliest possible number to the shortened user key. + PutFixed64(&tmp, PackSequenceAndType(kMaxSequenceNumber,kValueTypeForSeek)); + assert(this->Compare(*key, tmp) < 0); + key->swap(tmp); + } +} + +const char* InternalFilterPolicy::Name() const { + return user_policy_->Name(); +} + +void InternalFilterPolicy::CreateFilter(const Slice* keys, int n, + std::string* dst) const { + // We rely on the fact that the code in table.cc does not mind us + // adjusting keys[]. + Slice* mkey = const_cast(keys); + for (int i = 0; i < n; i++) { + mkey[i] = ExtractUserKey(keys[i]); + // TODO(sanjay): Suppress dups? + } + user_policy_->CreateFilter(keys, n, dst); +} + +bool InternalFilterPolicy::KeyMayMatch(const Slice& key, const Slice& f) const { + return user_policy_->KeyMayMatch(ExtractUserKey(key), f); +} + +LookupKey::LookupKey(const Slice& user_key, SequenceNumber s) { + size_t usize = user_key.size(); + size_t needed = usize + 13; // A conservative estimate + char* dst; + if (needed <= sizeof(space_)) { + dst = space_; + } else { + dst = new char[needed]; + } + start_ = dst; + dst = EncodeVarint32(dst, usize + 8); + kstart_ = dst; + memcpy(dst, user_key.data(), usize); + dst += usize; + EncodeFixed64(dst, PackSequenceAndType(s, kValueTypeForSeek)); + dst += 8; + end_ = dst; +} + +} // namespace leveldb diff --git a/ios/Pods/leveldb-library/db/dbformat.h b/ios/Pods/leveldb-library/db/dbformat.h new file mode 100644 index 000000000..ea897b13c --- /dev/null +++ b/ios/Pods/leveldb-library/db/dbformat.h @@ -0,0 +1,230 @@ +// Copyright (c) 2011 The LevelDB Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. See the AUTHORS file for names of contributors. + +#ifndef STORAGE_LEVELDB_DB_DBFORMAT_H_ +#define STORAGE_LEVELDB_DB_DBFORMAT_H_ + +#include +#include "leveldb/comparator.h" +#include "leveldb/db.h" +#include "leveldb/filter_policy.h" +#include "leveldb/slice.h" +#include "leveldb/table_builder.h" +#include "util/coding.h" +#include "util/logging.h" + +namespace leveldb { + +// Grouping of constants. We may want to make some of these +// parameters set via options. +namespace config { +static const int kNumLevels = 7; + +// Level-0 compaction is started when we hit this many files. +static const int kL0_CompactionTrigger = 4; + +// Soft limit on number of level-0 files. We slow down writes at this point. +static const int kL0_SlowdownWritesTrigger = 8; + +// Maximum number of level-0 files. We stop writes at this point. +static const int kL0_StopWritesTrigger = 12; + +// Maximum level to which a new compacted memtable is pushed if it +// does not create overlap. We try to push to level 2 to avoid the +// relatively expensive level 0=>1 compactions and to avoid some +// expensive manifest file operations. We do not push all the way to +// the largest level since that can generate a lot of wasted disk +// space if the same key space is being repeatedly overwritten. +static const int kMaxMemCompactLevel = 2; + +// Approximate gap in bytes between samples of data read during iteration. +static const int kReadBytesPeriod = 1048576; + +} // namespace config + +class InternalKey; + +// Value types encoded as the last component of internal keys. +// DO NOT CHANGE THESE ENUM VALUES: they are embedded in the on-disk +// data structures. +enum ValueType { + kTypeDeletion = 0x0, + kTypeValue = 0x1 +}; +// kValueTypeForSeek defines the ValueType that should be passed when +// constructing a ParsedInternalKey object for seeking to a particular +// sequence number (since we sort sequence numbers in decreasing order +// and the value type is embedded as the low 8 bits in the sequence +// number in internal keys, we need to use the highest-numbered +// ValueType, not the lowest). +static const ValueType kValueTypeForSeek = kTypeValue; + +typedef uint64_t SequenceNumber; + +// We leave eight bits empty at the bottom so a type and sequence# +// can be packed together into 64-bits. +static const SequenceNumber kMaxSequenceNumber = + ((0x1ull << 56) - 1); + +struct ParsedInternalKey { + Slice user_key; + SequenceNumber sequence; + ValueType type; + + ParsedInternalKey() { } // Intentionally left uninitialized (for speed) + ParsedInternalKey(const Slice& u, const SequenceNumber& seq, ValueType t) + : user_key(u), sequence(seq), type(t) { } + std::string DebugString() const; +}; + +// Return the length of the encoding of "key". +inline size_t InternalKeyEncodingLength(const ParsedInternalKey& key) { + return key.user_key.size() + 8; +} + +// Append the serialization of "key" to *result. +extern void AppendInternalKey(std::string* result, + const ParsedInternalKey& key); + +// Attempt to parse an internal key from "internal_key". On success, +// stores the parsed data in "*result", and returns true. +// +// On error, returns false, leaves "*result" in an undefined state. +extern bool ParseInternalKey(const Slice& internal_key, + ParsedInternalKey* result); + +// Returns the user key portion of an internal key. +inline Slice ExtractUserKey(const Slice& internal_key) { + assert(internal_key.size() >= 8); + return Slice(internal_key.data(), internal_key.size() - 8); +} + +inline ValueType ExtractValueType(const Slice& internal_key) { + assert(internal_key.size() >= 8); + const size_t n = internal_key.size(); + uint64_t num = DecodeFixed64(internal_key.data() + n - 8); + unsigned char c = num & 0xff; + return static_cast(c); +} + +// A comparator for internal keys that uses a specified comparator for +// the user key portion and breaks ties by decreasing sequence number. +class InternalKeyComparator : public Comparator { + private: + const Comparator* user_comparator_; + public: + explicit InternalKeyComparator(const Comparator* c) : user_comparator_(c) { } + virtual const char* Name() const; + virtual int Compare(const Slice& a, const Slice& b) const; + virtual void FindShortestSeparator( + std::string* start, + const Slice& limit) const; + virtual void FindShortSuccessor(std::string* key) const; + + const Comparator* user_comparator() const { return user_comparator_; } + + int Compare(const InternalKey& a, const InternalKey& b) const; +}; + +// Filter policy wrapper that converts from internal keys to user keys +class InternalFilterPolicy : public FilterPolicy { + private: + const FilterPolicy* const user_policy_; + public: + explicit InternalFilterPolicy(const FilterPolicy* p) : user_policy_(p) { } + virtual const char* Name() const; + virtual void CreateFilter(const Slice* keys, int n, std::string* dst) const; + virtual bool KeyMayMatch(const Slice& key, const Slice& filter) const; +}; + +// Modules in this directory should keep internal keys wrapped inside +// the following class instead of plain strings so that we do not +// incorrectly use string comparisons instead of an InternalKeyComparator. +class InternalKey { + private: + std::string rep_; + public: + InternalKey() { } // Leave rep_ as empty to indicate it is invalid + InternalKey(const Slice& user_key, SequenceNumber s, ValueType t) { + AppendInternalKey(&rep_, ParsedInternalKey(user_key, s, t)); + } + + void DecodeFrom(const Slice& s) { rep_.assign(s.data(), s.size()); } + Slice Encode() const { + assert(!rep_.empty()); + return rep_; + } + + Slice user_key() const { return ExtractUserKey(rep_); } + + void SetFrom(const ParsedInternalKey& p) { + rep_.clear(); + AppendInternalKey(&rep_, p); + } + + void Clear() { rep_.clear(); } + + std::string DebugString() const; +}; + +inline int InternalKeyComparator::Compare( + const InternalKey& a, const InternalKey& b) const { + return Compare(a.Encode(), b.Encode()); +} + +inline bool ParseInternalKey(const Slice& internal_key, + ParsedInternalKey* result) { + const size_t n = internal_key.size(); + if (n < 8) return false; + uint64_t num = DecodeFixed64(internal_key.data() + n - 8); + unsigned char c = num & 0xff; + result->sequence = num >> 8; + result->type = static_cast(c); + result->user_key = Slice(internal_key.data(), n - 8); + return (c <= static_cast(kTypeValue)); +} + +// A helper class useful for DBImpl::Get() +class LookupKey { + public: + // Initialize *this for looking up user_key at a snapshot with + // the specified sequence number. + LookupKey(const Slice& user_key, SequenceNumber sequence); + + ~LookupKey(); + + // Return a key suitable for lookup in a MemTable. + Slice memtable_key() const { return Slice(start_, end_ - start_); } + + // Return an internal key (suitable for passing to an internal iterator) + Slice internal_key() const { return Slice(kstart_, end_ - kstart_); } + + // Return the user key + Slice user_key() const { return Slice(kstart_, end_ - kstart_ - 8); } + + private: + // We construct a char array of the form: + // klength varint32 <-- start_ + // userkey char[klength] <-- kstart_ + // tag uint64 + // <-- end_ + // The array is a suitable MemTable key. + // The suffix starting with "userkey" can be used as an InternalKey. + const char* start_; + const char* kstart_; + const char* end_; + char space_[200]; // Avoid allocation for short keys + + // No copying allowed + LookupKey(const LookupKey&); + void operator=(const LookupKey&); +}; + +inline LookupKey::~LookupKey() { + if (start_ != space_) delete[] start_; +} + +} // namespace leveldb + +#endif // STORAGE_LEVELDB_DB_DBFORMAT_H_ diff --git a/ios/Pods/leveldb-library/db/dbformat_test.cc b/ios/Pods/leveldb-library/db/dbformat_test.cc new file mode 100644 index 000000000..5d82f5d31 --- /dev/null +++ b/ios/Pods/leveldb-library/db/dbformat_test.cc @@ -0,0 +1,112 @@ +// Copyright (c) 2011 The LevelDB Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. See the AUTHORS file for names of contributors. + +#include "db/dbformat.h" +#include "util/logging.h" +#include "util/testharness.h" + +namespace leveldb { + +static std::string IKey(const std::string& user_key, + uint64_t seq, + ValueType vt) { + std::string encoded; + AppendInternalKey(&encoded, ParsedInternalKey(user_key, seq, vt)); + return encoded; +} + +static std::string Shorten(const std::string& s, const std::string& l) { + std::string result = s; + InternalKeyComparator(BytewiseComparator()).FindShortestSeparator(&result, l); + return result; +} + +static std::string ShortSuccessor(const std::string& s) { + std::string result = s; + InternalKeyComparator(BytewiseComparator()).FindShortSuccessor(&result); + return result; +} + +static void TestKey(const std::string& key, + uint64_t seq, + ValueType vt) { + std::string encoded = IKey(key, seq, vt); + + Slice in(encoded); + ParsedInternalKey decoded("", 0, kTypeValue); + + ASSERT_TRUE(ParseInternalKey(in, &decoded)); + ASSERT_EQ(key, decoded.user_key.ToString()); + ASSERT_EQ(seq, decoded.sequence); + ASSERT_EQ(vt, decoded.type); + + ASSERT_TRUE(!ParseInternalKey(Slice("bar"), &decoded)); +} + +class FormatTest { }; + +TEST(FormatTest, InternalKey_EncodeDecode) { + const char* keys[] = { "", "k", "hello", "longggggggggggggggggggggg" }; + const uint64_t seq[] = { + 1, 2, 3, + (1ull << 8) - 1, 1ull << 8, (1ull << 8) + 1, + (1ull << 16) - 1, 1ull << 16, (1ull << 16) + 1, + (1ull << 32) - 1, 1ull << 32, (1ull << 32) + 1 + }; + for (int k = 0; k < sizeof(keys) / sizeof(keys[0]); k++) { + for (int s = 0; s < sizeof(seq) / sizeof(seq[0]); s++) { + TestKey(keys[k], seq[s], kTypeValue); + TestKey("hello", 1, kTypeDeletion); + } + } +} + +TEST(FormatTest, InternalKeyShortSeparator) { + // When user keys are same + ASSERT_EQ(IKey("foo", 100, kTypeValue), + Shorten(IKey("foo", 100, kTypeValue), + IKey("foo", 99, kTypeValue))); + ASSERT_EQ(IKey("foo", 100, kTypeValue), + Shorten(IKey("foo", 100, kTypeValue), + IKey("foo", 101, kTypeValue))); + ASSERT_EQ(IKey("foo", 100, kTypeValue), + Shorten(IKey("foo", 100, kTypeValue), + IKey("foo", 100, kTypeValue))); + ASSERT_EQ(IKey("foo", 100, kTypeValue), + Shorten(IKey("foo", 100, kTypeValue), + IKey("foo", 100, kTypeDeletion))); + + // When user keys are misordered + ASSERT_EQ(IKey("foo", 100, kTypeValue), + Shorten(IKey("foo", 100, kTypeValue), + IKey("bar", 99, kTypeValue))); + + // When user keys are different, but correctly ordered + ASSERT_EQ(IKey("g", kMaxSequenceNumber, kValueTypeForSeek), + Shorten(IKey("foo", 100, kTypeValue), + IKey("hello", 200, kTypeValue))); + + // When start user key is prefix of limit user key + ASSERT_EQ(IKey("foo", 100, kTypeValue), + Shorten(IKey("foo", 100, kTypeValue), + IKey("foobar", 200, kTypeValue))); + + // When limit user key is prefix of start user key + ASSERT_EQ(IKey("foobar", 100, kTypeValue), + Shorten(IKey("foobar", 100, kTypeValue), + IKey("foo", 200, kTypeValue))); +} + +TEST(FormatTest, InternalKeyShortestSuccessor) { + ASSERT_EQ(IKey("g", kMaxSequenceNumber, kValueTypeForSeek), + ShortSuccessor(IKey("foo", 100, kTypeValue))); + ASSERT_EQ(IKey("\xff\xff", 100, kTypeValue), + ShortSuccessor(IKey("\xff\xff", 100, kTypeValue))); +} + +} // namespace leveldb + +int main(int argc, char** argv) { + return leveldb::test::RunAllTests(); +} diff --git a/ios/Pods/leveldb-library/db/dumpfile.cc b/ios/Pods/leveldb-library/db/dumpfile.cc new file mode 100644 index 000000000..61c47c2ff --- /dev/null +++ b/ios/Pods/leveldb-library/db/dumpfile.cc @@ -0,0 +1,225 @@ +// Copyright (c) 2012 The LevelDB Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. See the AUTHORS file for names of contributors. + +#include +#include "db/dbformat.h" +#include "db/filename.h" +#include "db/log_reader.h" +#include "db/version_edit.h" +#include "db/write_batch_internal.h" +#include "leveldb/env.h" +#include "leveldb/iterator.h" +#include "leveldb/options.h" +#include "leveldb/status.h" +#include "leveldb/table.h" +#include "leveldb/write_batch.h" +#include "util/logging.h" + +namespace leveldb { + +namespace { + +bool GuessType(const std::string& fname, FileType* type) { + size_t pos = fname.rfind('/'); + std::string basename; + if (pos == std::string::npos) { + basename = fname; + } else { + basename = std::string(fname.data() + pos + 1, fname.size() - pos - 1); + } + uint64_t ignored; + return ParseFileName(basename, &ignored, type); +} + +// Notified when log reader encounters corruption. +class CorruptionReporter : public log::Reader::Reporter { + public: + WritableFile* dst_; + virtual void Corruption(size_t bytes, const Status& status) { + std::string r = "corruption: "; + AppendNumberTo(&r, bytes); + r += " bytes; "; + r += status.ToString(); + r.push_back('\n'); + dst_->Append(r); + } +}; + +// Print contents of a log file. (*func)() is called on every record. +Status PrintLogContents(Env* env, const std::string& fname, + void (*func)(uint64_t, Slice, WritableFile*), + WritableFile* dst) { + SequentialFile* file; + Status s = env->NewSequentialFile(fname, &file); + if (!s.ok()) { + return s; + } + CorruptionReporter reporter; + reporter.dst_ = dst; + log::Reader reader(file, &reporter, true, 0); + Slice record; + std::string scratch; + while (reader.ReadRecord(&record, &scratch)) { + (*func)(reader.LastRecordOffset(), record, dst); + } + delete file; + return Status::OK(); +} + +// Called on every item found in a WriteBatch. +class WriteBatchItemPrinter : public WriteBatch::Handler { + public: + WritableFile* dst_; + virtual void Put(const Slice& key, const Slice& value) { + std::string r = " put '"; + AppendEscapedStringTo(&r, key); + r += "' '"; + AppendEscapedStringTo(&r, value); + r += "'\n"; + dst_->Append(r); + } + virtual void Delete(const Slice& key) { + std::string r = " del '"; + AppendEscapedStringTo(&r, key); + r += "'\n"; + dst_->Append(r); + } +}; + + +// Called on every log record (each one of which is a WriteBatch) +// found in a kLogFile. +static void WriteBatchPrinter(uint64_t pos, Slice record, WritableFile* dst) { + std::string r = "--- offset "; + AppendNumberTo(&r, pos); + r += "; "; + if (record.size() < 12) { + r += "log record length "; + AppendNumberTo(&r, record.size()); + r += " is too small\n"; + dst->Append(r); + return; + } + WriteBatch batch; + WriteBatchInternal::SetContents(&batch, record); + r += "sequence "; + AppendNumberTo(&r, WriteBatchInternal::Sequence(&batch)); + r.push_back('\n'); + dst->Append(r); + WriteBatchItemPrinter batch_item_printer; + batch_item_printer.dst_ = dst; + Status s = batch.Iterate(&batch_item_printer); + if (!s.ok()) { + dst->Append(" error: " + s.ToString() + "\n"); + } +} + +Status DumpLog(Env* env, const std::string& fname, WritableFile* dst) { + return PrintLogContents(env, fname, WriteBatchPrinter, dst); +} + +// Called on every log record (each one of which is a WriteBatch) +// found in a kDescriptorFile. +static void VersionEditPrinter(uint64_t pos, Slice record, WritableFile* dst) { + std::string r = "--- offset "; + AppendNumberTo(&r, pos); + r += "; "; + VersionEdit edit; + Status s = edit.DecodeFrom(record); + if (!s.ok()) { + r += s.ToString(); + r.push_back('\n'); + } else { + r += edit.DebugString(); + } + dst->Append(r); +} + +Status DumpDescriptor(Env* env, const std::string& fname, WritableFile* dst) { + return PrintLogContents(env, fname, VersionEditPrinter, dst); +} + +Status DumpTable(Env* env, const std::string& fname, WritableFile* dst) { + uint64_t file_size; + RandomAccessFile* file = NULL; + Table* table = NULL; + Status s = env->GetFileSize(fname, &file_size); + if (s.ok()) { + s = env->NewRandomAccessFile(fname, &file); + } + if (s.ok()) { + // We use the default comparator, which may or may not match the + // comparator used in this database. However this should not cause + // problems since we only use Table operations that do not require + // any comparisons. In particular, we do not call Seek or Prev. + s = Table::Open(Options(), file, file_size, &table); + } + if (!s.ok()) { + delete table; + delete file; + return s; + } + + ReadOptions ro; + ro.fill_cache = false; + Iterator* iter = table->NewIterator(ro); + std::string r; + for (iter->SeekToFirst(); iter->Valid(); iter->Next()) { + r.clear(); + ParsedInternalKey key; + if (!ParseInternalKey(iter->key(), &key)) { + r = "badkey '"; + AppendEscapedStringTo(&r, iter->key()); + r += "' => '"; + AppendEscapedStringTo(&r, iter->value()); + r += "'\n"; + dst->Append(r); + } else { + r = "'"; + AppendEscapedStringTo(&r, key.user_key); + r += "' @ "; + AppendNumberTo(&r, key.sequence); + r += " : "; + if (key.type == kTypeDeletion) { + r += "del"; + } else if (key.type == kTypeValue) { + r += "val"; + } else { + AppendNumberTo(&r, key.type); + } + r += " => '"; + AppendEscapedStringTo(&r, iter->value()); + r += "'\n"; + dst->Append(r); + } + } + s = iter->status(); + if (!s.ok()) { + dst->Append("iterator error: " + s.ToString() + "\n"); + } + + delete iter; + delete table; + delete file; + return Status::OK(); +} + +} // namespace + +Status DumpFile(Env* env, const std::string& fname, WritableFile* dst) { + FileType ftype; + if (!GuessType(fname, &ftype)) { + return Status::InvalidArgument(fname + ": unknown file type"); + } + switch (ftype) { + case kLogFile: return DumpLog(env, fname, dst); + case kDescriptorFile: return DumpDescriptor(env, fname, dst); + case kTableFile: return DumpTable(env, fname, dst); + default: + break; + } + return Status::InvalidArgument(fname + ": not a dump-able file type"); +} + +} // namespace leveldb diff --git a/ios/Pods/leveldb-library/db/filename.cc b/ios/Pods/leveldb-library/db/filename.cc new file mode 100644 index 000000000..da32946d9 --- /dev/null +++ b/ios/Pods/leveldb-library/db/filename.cc @@ -0,0 +1,144 @@ +// Copyright (c) 2011 The LevelDB Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. See the AUTHORS file for names of contributors. + +#include +#include +#include "db/filename.h" +#include "db/dbformat.h" +#include "leveldb/env.h" +#include "util/logging.h" + +namespace leveldb { + +// A utility routine: write "data" to the named file and Sync() it. +extern Status WriteStringToFileSync(Env* env, const Slice& data, + const std::string& fname); + +static std::string MakeFileName(const std::string& name, uint64_t number, + const char* suffix) { + char buf[100]; + snprintf(buf, sizeof(buf), "/%06llu.%s", + static_cast(number), + suffix); + return name + buf; +} + +std::string LogFileName(const std::string& name, uint64_t number) { + assert(number > 0); + return MakeFileName(name, number, "log"); +} + +std::string TableFileName(const std::string& name, uint64_t number) { + assert(number > 0); + return MakeFileName(name, number, "ldb"); +} + +std::string SSTTableFileName(const std::string& name, uint64_t number) { + assert(number > 0); + return MakeFileName(name, number, "sst"); +} + +std::string DescriptorFileName(const std::string& dbname, uint64_t number) { + assert(number > 0); + char buf[100]; + snprintf(buf, sizeof(buf), "/MANIFEST-%06llu", + static_cast(number)); + return dbname + buf; +} + +std::string CurrentFileName(const std::string& dbname) { + return dbname + "/CURRENT"; +} + +std::string LockFileName(const std::string& dbname) { + return dbname + "/LOCK"; +} + +std::string TempFileName(const std::string& dbname, uint64_t number) { + assert(number > 0); + return MakeFileName(dbname, number, "dbtmp"); +} + +std::string InfoLogFileName(const std::string& dbname) { + return dbname + "/LOG"; +} + +// Return the name of the old info log file for "dbname". +std::string OldInfoLogFileName(const std::string& dbname) { + return dbname + "/LOG.old"; +} + + +// Owned filenames have the form: +// dbname/CURRENT +// dbname/LOCK +// dbname/LOG +// dbname/LOG.old +// dbname/MANIFEST-[0-9]+ +// dbname/[0-9]+.(log|sst|ldb) +bool ParseFileName(const std::string& fname, + uint64_t* number, + FileType* type) { + Slice rest(fname); + if (rest == "CURRENT") { + *number = 0; + *type = kCurrentFile; + } else if (rest == "LOCK") { + *number = 0; + *type = kDBLockFile; + } else if (rest == "LOG" || rest == "LOG.old") { + *number = 0; + *type = kInfoLogFile; + } else if (rest.starts_with("MANIFEST-")) { + rest.remove_prefix(strlen("MANIFEST-")); + uint64_t num; + if (!ConsumeDecimalNumber(&rest, &num)) { + return false; + } + if (!rest.empty()) { + return false; + } + *type = kDescriptorFile; + *number = num; + } else { + // Avoid strtoull() to keep filename format independent of the + // current locale + uint64_t num; + if (!ConsumeDecimalNumber(&rest, &num)) { + return false; + } + Slice suffix = rest; + if (suffix == Slice(".log")) { + *type = kLogFile; + } else if (suffix == Slice(".sst") || suffix == Slice(".ldb")) { + *type = kTableFile; + } else if (suffix == Slice(".dbtmp")) { + *type = kTempFile; + } else { + return false; + } + *number = num; + } + return true; +} + +Status SetCurrentFile(Env* env, const std::string& dbname, + uint64_t descriptor_number) { + // Remove leading "dbname/" and add newline to manifest file name + std::string manifest = DescriptorFileName(dbname, descriptor_number); + Slice contents = manifest; + assert(contents.starts_with(dbname + "/")); + contents.remove_prefix(dbname.size() + 1); + std::string tmp = TempFileName(dbname, descriptor_number); + Status s = WriteStringToFileSync(env, contents.ToString() + "\n", tmp); + if (s.ok()) { + s = env->RenameFile(tmp, CurrentFileName(dbname)); + } + if (!s.ok()) { + env->DeleteFile(tmp); + } + return s; +} + +} // namespace leveldb diff --git a/ios/Pods/leveldb-library/db/filename.h b/ios/Pods/leveldb-library/db/filename.h new file mode 100644 index 000000000..87a752605 --- /dev/null +++ b/ios/Pods/leveldb-library/db/filename.h @@ -0,0 +1,85 @@ +// Copyright (c) 2011 The LevelDB Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. See the AUTHORS file for names of contributors. +// +// File names used by DB code + +#ifndef STORAGE_LEVELDB_DB_FILENAME_H_ +#define STORAGE_LEVELDB_DB_FILENAME_H_ + +#include +#include +#include "leveldb/slice.h" +#include "leveldb/status.h" +#include "port/port.h" + +namespace leveldb { + +class Env; + +enum FileType { + kLogFile, + kDBLockFile, + kTableFile, + kDescriptorFile, + kCurrentFile, + kTempFile, + kInfoLogFile // Either the current one, or an old one +}; + +// Return the name of the log file with the specified number +// in the db named by "dbname". The result will be prefixed with +// "dbname". +extern std::string LogFileName(const std::string& dbname, uint64_t number); + +// Return the name of the sstable with the specified number +// in the db named by "dbname". The result will be prefixed with +// "dbname". +extern std::string TableFileName(const std::string& dbname, uint64_t number); + +// Return the legacy file name for an sstable with the specified number +// in the db named by "dbname". The result will be prefixed with +// "dbname". +extern std::string SSTTableFileName(const std::string& dbname, uint64_t number); + +// Return the name of the descriptor file for the db named by +// "dbname" and the specified incarnation number. The result will be +// prefixed with "dbname". +extern std::string DescriptorFileName(const std::string& dbname, + uint64_t number); + +// Return the name of the current file. This file contains the name +// of the current manifest file. The result will be prefixed with +// "dbname". +extern std::string CurrentFileName(const std::string& dbname); + +// Return the name of the lock file for the db named by +// "dbname". The result will be prefixed with "dbname". +extern std::string LockFileName(const std::string& dbname); + +// Return the name of a temporary file owned by the db named "dbname". +// The result will be prefixed with "dbname". +extern std::string TempFileName(const std::string& dbname, uint64_t number); + +// Return the name of the info log file for "dbname". +extern std::string InfoLogFileName(const std::string& dbname); + +// Return the name of the old info log file for "dbname". +extern std::string OldInfoLogFileName(const std::string& dbname); + +// If filename is a leveldb file, store the type of the file in *type. +// The number encoded in the filename is stored in *number. If the +// filename was successfully parsed, returns true. Else return false. +extern bool ParseFileName(const std::string& filename, + uint64_t* number, + FileType* type); + +// Make the CURRENT file point to the descriptor file with the +// specified number. +extern Status SetCurrentFile(Env* env, const std::string& dbname, + uint64_t descriptor_number); + + +} // namespace leveldb + +#endif // STORAGE_LEVELDB_DB_FILENAME_H_ diff --git a/ios/Pods/leveldb-library/db/filename_test.cc b/ios/Pods/leveldb-library/db/filename_test.cc new file mode 100644 index 000000000..a32556dea --- /dev/null +++ b/ios/Pods/leveldb-library/db/filename_test.cc @@ -0,0 +1,123 @@ +// Copyright (c) 2011 The LevelDB Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. See the AUTHORS file for names of contributors. + +#include "db/filename.h" + +#include "db/dbformat.h" +#include "port/port.h" +#include "util/logging.h" +#include "util/testharness.h" + +namespace leveldb { + +class FileNameTest { }; + +TEST(FileNameTest, Parse) { + Slice db; + FileType type; + uint64_t number; + + // Successful parses + static struct { + const char* fname; + uint64_t number; + FileType type; + } cases[] = { + { "100.log", 100, kLogFile }, + { "0.log", 0, kLogFile }, + { "0.sst", 0, kTableFile }, + { "0.ldb", 0, kTableFile }, + { "CURRENT", 0, kCurrentFile }, + { "LOCK", 0, kDBLockFile }, + { "MANIFEST-2", 2, kDescriptorFile }, + { "MANIFEST-7", 7, kDescriptorFile }, + { "LOG", 0, kInfoLogFile }, + { "LOG.old", 0, kInfoLogFile }, + { "18446744073709551615.log", 18446744073709551615ull, kLogFile }, + }; + for (int i = 0; i < sizeof(cases) / sizeof(cases[0]); i++) { + std::string f = cases[i].fname; + ASSERT_TRUE(ParseFileName(f, &number, &type)) << f; + ASSERT_EQ(cases[i].type, type) << f; + ASSERT_EQ(cases[i].number, number) << f; + } + + // Errors + static const char* errors[] = { + "", + "foo", + "foo-dx-100.log", + ".log", + "", + "manifest", + "CURREN", + "CURRENTX", + "MANIFES", + "MANIFEST", + "MANIFEST-", + "XMANIFEST-3", + "MANIFEST-3x", + "LOC", + "LOCKx", + "LO", + "LOGx", + "18446744073709551616.log", + "184467440737095516150.log", + "100", + "100.", + "100.lop" + }; + for (int i = 0; i < sizeof(errors) / sizeof(errors[0]); i++) { + std::string f = errors[i]; + ASSERT_TRUE(!ParseFileName(f, &number, &type)) << f; + } +} + +TEST(FileNameTest, Construction) { + uint64_t number; + FileType type; + std::string fname; + + fname = CurrentFileName("foo"); + ASSERT_EQ("foo/", std::string(fname.data(), 4)); + ASSERT_TRUE(ParseFileName(fname.c_str() + 4, &number, &type)); + ASSERT_EQ(0, number); + ASSERT_EQ(kCurrentFile, type); + + fname = LockFileName("foo"); + ASSERT_EQ("foo/", std::string(fname.data(), 4)); + ASSERT_TRUE(ParseFileName(fname.c_str() + 4, &number, &type)); + ASSERT_EQ(0, number); + ASSERT_EQ(kDBLockFile, type); + + fname = LogFileName("foo", 192); + ASSERT_EQ("foo/", std::string(fname.data(), 4)); + ASSERT_TRUE(ParseFileName(fname.c_str() + 4, &number, &type)); + ASSERT_EQ(192, number); + ASSERT_EQ(kLogFile, type); + + fname = TableFileName("bar", 200); + ASSERT_EQ("bar/", std::string(fname.data(), 4)); + ASSERT_TRUE(ParseFileName(fname.c_str() + 4, &number, &type)); + ASSERT_EQ(200, number); + ASSERT_EQ(kTableFile, type); + + fname = DescriptorFileName("bar", 100); + ASSERT_EQ("bar/", std::string(fname.data(), 4)); + ASSERT_TRUE(ParseFileName(fname.c_str() + 4, &number, &type)); + ASSERT_EQ(100, number); + ASSERT_EQ(kDescriptorFile, type); + + fname = TempFileName("tmp", 999); + ASSERT_EQ("tmp/", std::string(fname.data(), 4)); + ASSERT_TRUE(ParseFileName(fname.c_str() + 4, &number, &type)); + ASSERT_EQ(999, number); + ASSERT_EQ(kTempFile, type); +} + +} // namespace leveldb + +int main(int argc, char** argv) { + return leveldb::test::RunAllTests(); +} diff --git a/ios/Pods/leveldb-library/db/leveldb_main.cc b/ios/Pods/leveldb-library/db/leveldb_main.cc new file mode 100644 index 000000000..9f4b7dd70 --- /dev/null +++ b/ios/Pods/leveldb-library/db/leveldb_main.cc @@ -0,0 +1,64 @@ +// Copyright (c) 2012 The LevelDB Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. See the AUTHORS file for names of contributors. + +#include +#include "leveldb/dumpfile.h" +#include "leveldb/env.h" +#include "leveldb/status.h" + +namespace leveldb { +namespace { + +class StdoutPrinter : public WritableFile { + public: + virtual Status Append(const Slice& data) { + fwrite(data.data(), 1, data.size(), stdout); + return Status::OK(); + } + virtual Status Close() { return Status::OK(); } + virtual Status Flush() { return Status::OK(); } + virtual Status Sync() { return Status::OK(); } +}; + +bool HandleDumpCommand(Env* env, char** files, int num) { + StdoutPrinter printer; + bool ok = true; + for (int i = 0; i < num; i++) { + Status s = DumpFile(env, files[i], &printer); + if (!s.ok()) { + fprintf(stderr, "%s\n", s.ToString().c_str()); + ok = false; + } + } + return ok; +} + +} // namespace +} // namespace leveldb + +static void Usage() { + fprintf( + stderr, + "Usage: leveldbutil command...\n" + " dump files... -- dump contents of specified files\n" + ); +} + +int main(int argc, char** argv) { + leveldb::Env* env = leveldb::Env::Default(); + bool ok = true; + if (argc < 2) { + Usage(); + ok = false; + } else { + std::string command = argv[1]; + if (command == "dump") { + ok = leveldb::HandleDumpCommand(env, argv+2, argc-2); + } else { + Usage(); + ok = false; + } + } + return (ok ? 0 : 1); +} diff --git a/ios/Pods/leveldb-library/db/log_format.h b/ios/Pods/leveldb-library/db/log_format.h new file mode 100644 index 000000000..a8c06efe1 --- /dev/null +++ b/ios/Pods/leveldb-library/db/log_format.h @@ -0,0 +1,35 @@ +// Copyright (c) 2011 The LevelDB Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. See the AUTHORS file for names of contributors. +// +// Log format information shared by reader and writer. +// See ../doc/log_format.txt for more detail. + +#ifndef STORAGE_LEVELDB_DB_LOG_FORMAT_H_ +#define STORAGE_LEVELDB_DB_LOG_FORMAT_H_ + +namespace leveldb { +namespace log { + +enum RecordType { + // Zero is reserved for preallocated files + kZeroType = 0, + + kFullType = 1, + + // For fragments + kFirstType = 2, + kMiddleType = 3, + kLastType = 4 +}; +static const int kMaxRecordType = kLastType; + +static const int kBlockSize = 32768; + +// Header is checksum (4 bytes), length (2 bytes), type (1 byte). +static const int kHeaderSize = 4 + 2 + 1; + +} // namespace log +} // namespace leveldb + +#endif // STORAGE_LEVELDB_DB_LOG_FORMAT_H_ diff --git a/ios/Pods/leveldb-library/db/log_reader.cc b/ios/Pods/leveldb-library/db/log_reader.cc new file mode 100644 index 000000000..e44b66c85 --- /dev/null +++ b/ios/Pods/leveldb-library/db/log_reader.cc @@ -0,0 +1,266 @@ +// Copyright (c) 2011 The LevelDB Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. See the AUTHORS file for names of contributors. + +#include "db/log_reader.h" + +#include +#include "leveldb/env.h" +#include "util/coding.h" +#include "util/crc32c.h" + +namespace leveldb { +namespace log { + +Reader::Reporter::~Reporter() { +} + +Reader::Reader(SequentialFile* file, Reporter* reporter, bool checksum, + uint64_t initial_offset) + : file_(file), + reporter_(reporter), + checksum_(checksum), + backing_store_(new char[kBlockSize]), + buffer_(), + eof_(false), + last_record_offset_(0), + end_of_buffer_offset_(0), + initial_offset_(initial_offset) { +} + +Reader::~Reader() { + delete[] backing_store_; +} + +bool Reader::SkipToInitialBlock() { + size_t offset_in_block = initial_offset_ % kBlockSize; + uint64_t block_start_location = initial_offset_ - offset_in_block; + + // Don't search a block if we'd be in the trailer + if (offset_in_block > kBlockSize - 6) { + offset_in_block = 0; + block_start_location += kBlockSize; + } + + end_of_buffer_offset_ = block_start_location; + + // Skip to start of first block that can contain the initial record + if (block_start_location > 0) { + Status skip_status = file_->Skip(block_start_location); + if (!skip_status.ok()) { + ReportDrop(block_start_location, skip_status); + return false; + } + } + + return true; +} + +bool Reader::ReadRecord(Slice* record, std::string* scratch) { + if (last_record_offset_ < initial_offset_) { + if (!SkipToInitialBlock()) { + return false; + } + } + + scratch->clear(); + record->clear(); + bool in_fragmented_record = false; + // Record offset of the logical record that we're reading + // 0 is a dummy value to make compilers happy + uint64_t prospective_record_offset = 0; + + Slice fragment; + while (true) { + uint64_t physical_record_offset = end_of_buffer_offset_ - buffer_.size(); + const unsigned int record_type = ReadPhysicalRecord(&fragment); + switch (record_type) { + case kFullType: + if (in_fragmented_record) { + // Handle bug in earlier versions of log::Writer where + // it could emit an empty kFirstType record at the tail end + // of a block followed by a kFullType or kFirstType record + // at the beginning of the next block. + if (scratch->empty()) { + in_fragmented_record = false; + } else { + ReportCorruption(scratch->size(), "partial record without end(1)"); + } + } + prospective_record_offset = physical_record_offset; + scratch->clear(); + *record = fragment; + last_record_offset_ = prospective_record_offset; + return true; + + case kFirstType: + if (in_fragmented_record) { + // Handle bug in earlier versions of log::Writer where + // it could emit an empty kFirstType record at the tail end + // of a block followed by a kFullType or kFirstType record + // at the beginning of the next block. + if (scratch->empty()) { + in_fragmented_record = false; + } else { + ReportCorruption(scratch->size(), "partial record without end(2)"); + } + } + prospective_record_offset = physical_record_offset; + scratch->assign(fragment.data(), fragment.size()); + in_fragmented_record = true; + break; + + case kMiddleType: + if (!in_fragmented_record) { + ReportCorruption(fragment.size(), + "missing start of fragmented record(1)"); + } else { + scratch->append(fragment.data(), fragment.size()); + } + break; + + case kLastType: + if (!in_fragmented_record) { + ReportCorruption(fragment.size(), + "missing start of fragmented record(2)"); + } else { + scratch->append(fragment.data(), fragment.size()); + *record = Slice(*scratch); + last_record_offset_ = prospective_record_offset; + return true; + } + break; + + case kEof: + if (in_fragmented_record) { + // This can be caused by the writer dying immediately after + // writing a physical record but before completing the next; don't + // treat it as a corruption, just ignore the entire logical record. + scratch->clear(); + } + return false; + + case kBadRecord: + if (in_fragmented_record) { + ReportCorruption(scratch->size(), "error in middle of record"); + in_fragmented_record = false; + scratch->clear(); + } + break; + + default: { + char buf[40]; + snprintf(buf, sizeof(buf), "unknown record type %u", record_type); + ReportCorruption( + (fragment.size() + (in_fragmented_record ? scratch->size() : 0)), + buf); + in_fragmented_record = false; + scratch->clear(); + break; + } + } + } + return false; +} + +uint64_t Reader::LastRecordOffset() { + return last_record_offset_; +} + +void Reader::ReportCorruption(uint64_t bytes, const char* reason) { + ReportDrop(bytes, Status::Corruption(reason)); +} + +void Reader::ReportDrop(uint64_t bytes, const Status& reason) { + if (reporter_ != NULL && + end_of_buffer_offset_ - buffer_.size() - bytes >= initial_offset_) { + reporter_->Corruption(static_cast(bytes), reason); + } +} + +unsigned int Reader::ReadPhysicalRecord(Slice* result) { + while (true) { + if (buffer_.size() < kHeaderSize) { + if (!eof_) { + // Last read was a full read, so this is a trailer to skip + buffer_.clear(); + Status status = file_->Read(kBlockSize, &buffer_, backing_store_); + end_of_buffer_offset_ += buffer_.size(); + if (!status.ok()) { + buffer_.clear(); + ReportDrop(kBlockSize, status); + eof_ = true; + return kEof; + } else if (buffer_.size() < kBlockSize) { + eof_ = true; + } + continue; + } else { + // Note that if buffer_ is non-empty, we have a truncated header at the + // end of the file, which can be caused by the writer crashing in the + // middle of writing the header. Instead of considering this an error, + // just report EOF. + buffer_.clear(); + return kEof; + } + } + + // Parse the header + const char* header = buffer_.data(); + const uint32_t a = static_cast(header[4]) & 0xff; + const uint32_t b = static_cast(header[5]) & 0xff; + const unsigned int type = header[6]; + const uint32_t length = a | (b << 8); + if (kHeaderSize + length > buffer_.size()) { + size_t drop_size = buffer_.size(); + buffer_.clear(); + if (!eof_) { + ReportCorruption(drop_size, "bad record length"); + return kBadRecord; + } + // If the end of the file has been reached without reading |length| bytes + // of payload, assume the writer died in the middle of writing the record. + // Don't report a corruption. + return kEof; + } + + if (type == kZeroType && length == 0) { + // Skip zero length record without reporting any drops since + // such records are produced by the mmap based writing code in + // env_posix.cc that preallocates file regions. + buffer_.clear(); + return kBadRecord; + } + + // Check crc + if (checksum_) { + uint32_t expected_crc = crc32c::Unmask(DecodeFixed32(header)); + uint32_t actual_crc = crc32c::Value(header + 6, 1 + length); + if (actual_crc != expected_crc) { + // Drop the rest of the buffer since "length" itself may have + // been corrupted and if we trust it, we could find some + // fragment of a real log record that just happens to look + // like a valid log record. + size_t drop_size = buffer_.size(); + buffer_.clear(); + ReportCorruption(drop_size, "checksum mismatch"); + return kBadRecord; + } + } + + buffer_.remove_prefix(kHeaderSize + length); + + // Skip physical record that started before initial_offset_ + if (end_of_buffer_offset_ - buffer_.size() - kHeaderSize - length < + initial_offset_) { + result->clear(); + return kBadRecord; + } + + *result = Slice(header + kHeaderSize, length); + return type; + } +} + +} // namespace log +} // namespace leveldb diff --git a/ios/Pods/leveldb-library/db/log_reader.h b/ios/Pods/leveldb-library/db/log_reader.h new file mode 100644 index 000000000..6aff79171 --- /dev/null +++ b/ios/Pods/leveldb-library/db/log_reader.h @@ -0,0 +1,108 @@ +// Copyright (c) 2011 The LevelDB Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. See the AUTHORS file for names of contributors. + +#ifndef STORAGE_LEVELDB_DB_LOG_READER_H_ +#define STORAGE_LEVELDB_DB_LOG_READER_H_ + +#include + +#include "db/log_format.h" +#include "leveldb/slice.h" +#include "leveldb/status.h" + +namespace leveldb { + +class SequentialFile; + +namespace log { + +class Reader { + public: + // Interface for reporting errors. + class Reporter { + public: + virtual ~Reporter(); + + // Some corruption was detected. "size" is the approximate number + // of bytes dropped due to the corruption. + virtual void Corruption(size_t bytes, const Status& status) = 0; + }; + + // Create a reader that will return log records from "*file". + // "*file" must remain live while this Reader is in use. + // + // If "reporter" is non-NULL, it is notified whenever some data is + // dropped due to a detected corruption. "*reporter" must remain + // live while this Reader is in use. + // + // If "checksum" is true, verify checksums if available. + // + // The Reader will start reading at the first record located at physical + // position >= initial_offset within the file. + Reader(SequentialFile* file, Reporter* reporter, bool checksum, + uint64_t initial_offset); + + ~Reader(); + + // Read the next record into *record. Returns true if read + // successfully, false if we hit end of the input. May use + // "*scratch" as temporary storage. The contents filled in *record + // will only be valid until the next mutating operation on this + // reader or the next mutation to *scratch. + bool ReadRecord(Slice* record, std::string* scratch); + + // Returns the physical offset of the last record returned by ReadRecord. + // + // Undefined before the first call to ReadRecord. + uint64_t LastRecordOffset(); + + private: + SequentialFile* const file_; + Reporter* const reporter_; + bool const checksum_; + char* const backing_store_; + Slice buffer_; + bool eof_; // Last Read() indicated EOF by returning < kBlockSize + + // Offset of the last record returned by ReadRecord. + uint64_t last_record_offset_; + // Offset of the first location past the end of buffer_. + uint64_t end_of_buffer_offset_; + + // Offset at which to start looking for the first record to return + uint64_t const initial_offset_; + + // Extend record types with the following special values + enum { + kEof = kMaxRecordType + 1, + // Returned whenever we find an invalid physical record. + // Currently there are three situations in which this happens: + // * The record has an invalid CRC (ReadPhysicalRecord reports a drop) + // * The record is a 0-length record (No drop is reported) + // * The record is below constructor's initial_offset (No drop is reported) + kBadRecord = kMaxRecordType + 2 + }; + + // Skips all blocks that are completely before "initial_offset_". + // + // Returns true on success. Handles reporting. + bool SkipToInitialBlock(); + + // Return type, or one of the preceding special values + unsigned int ReadPhysicalRecord(Slice* result); + + // Reports dropped bytes to the reporter. + // buffer_ must be updated to remove the dropped bytes prior to invocation. + void ReportCorruption(uint64_t bytes, const char* reason); + void ReportDrop(uint64_t bytes, const Status& reason); + + // No copying allowed + Reader(const Reader&); + void operator=(const Reader&); +}; + +} // namespace log +} // namespace leveldb + +#endif // STORAGE_LEVELDB_DB_LOG_READER_H_ diff --git a/ios/Pods/leveldb-library/db/log_test.cc b/ios/Pods/leveldb-library/db/log_test.cc new file mode 100644 index 000000000..dcf056265 --- /dev/null +++ b/ios/Pods/leveldb-library/db/log_test.cc @@ -0,0 +1,530 @@ +// Copyright (c) 2011 The LevelDB Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. See the AUTHORS file for names of contributors. + +#include "db/log_reader.h" +#include "db/log_writer.h" +#include "leveldb/env.h" +#include "util/coding.h" +#include "util/crc32c.h" +#include "util/random.h" +#include "util/testharness.h" + +namespace leveldb { +namespace log { + +// Construct a string of the specified length made out of the supplied +// partial string. +static std::string BigString(const std::string& partial_string, size_t n) { + std::string result; + while (result.size() < n) { + result.append(partial_string); + } + result.resize(n); + return result; +} + +// Construct a string from a number +static std::string NumberString(int n) { + char buf[50]; + snprintf(buf, sizeof(buf), "%d.", n); + return std::string(buf); +} + +// Return a skewed potentially long string +static std::string RandomSkewedString(int i, Random* rnd) { + return BigString(NumberString(i), rnd->Skewed(17)); +} + +class LogTest { + private: + class StringDest : public WritableFile { + public: + std::string contents_; + + virtual Status Close() { return Status::OK(); } + virtual Status Flush() { return Status::OK(); } + virtual Status Sync() { return Status::OK(); } + virtual Status Append(const Slice& slice) { + contents_.append(slice.data(), slice.size()); + return Status::OK(); + } + }; + + class StringSource : public SequentialFile { + public: + Slice contents_; + bool force_error_; + bool returned_partial_; + StringSource() : force_error_(false), returned_partial_(false) { } + + virtual Status Read(size_t n, Slice* result, char* scratch) { + ASSERT_TRUE(!returned_partial_) << "must not Read() after eof/error"; + + if (force_error_) { + force_error_ = false; + returned_partial_ = true; + return Status::Corruption("read error"); + } + + if (contents_.size() < n) { + n = contents_.size(); + returned_partial_ = true; + } + *result = Slice(contents_.data(), n); + contents_.remove_prefix(n); + return Status::OK(); + } + + virtual Status Skip(uint64_t n) { + if (n > contents_.size()) { + contents_.clear(); + return Status::NotFound("in-memory file skipepd past end"); + } + + contents_.remove_prefix(n); + + return Status::OK(); + } + }; + + class ReportCollector : public Reader::Reporter { + public: + size_t dropped_bytes_; + std::string message_; + + ReportCollector() : dropped_bytes_(0) { } + virtual void Corruption(size_t bytes, const Status& status) { + dropped_bytes_ += bytes; + message_.append(status.ToString()); + } + }; + + StringDest dest_; + StringSource source_; + ReportCollector report_; + bool reading_; + Writer writer_; + Reader reader_; + + // Record metadata for testing initial offset functionality + static size_t initial_offset_record_sizes_[]; + static uint64_t initial_offset_last_record_offsets_[]; + + public: + LogTest() : reading_(false), + writer_(&dest_), + reader_(&source_, &report_, true/*checksum*/, + 0/*initial_offset*/) { + } + + void Write(const std::string& msg) { + ASSERT_TRUE(!reading_) << "Write() after starting to read"; + writer_.AddRecord(Slice(msg)); + } + + size_t WrittenBytes() const { + return dest_.contents_.size(); + } + + std::string Read() { + if (!reading_) { + reading_ = true; + source_.contents_ = Slice(dest_.contents_); + } + std::string scratch; + Slice record; + if (reader_.ReadRecord(&record, &scratch)) { + return record.ToString(); + } else { + return "EOF"; + } + } + + void IncrementByte(int offset, int delta) { + dest_.contents_[offset] += delta; + } + + void SetByte(int offset, char new_byte) { + dest_.contents_[offset] = new_byte; + } + + void ShrinkSize(int bytes) { + dest_.contents_.resize(dest_.contents_.size() - bytes); + } + + void FixChecksum(int header_offset, int len) { + // Compute crc of type/len/data + uint32_t crc = crc32c::Value(&dest_.contents_[header_offset+6], 1 + len); + crc = crc32c::Mask(crc); + EncodeFixed32(&dest_.contents_[header_offset], crc); + } + + void ForceError() { + source_.force_error_ = true; + } + + size_t DroppedBytes() const { + return report_.dropped_bytes_; + } + + std::string ReportMessage() const { + return report_.message_; + } + + // Returns OK iff recorded error message contains "msg" + std::string MatchError(const std::string& msg) const { + if (report_.message_.find(msg) == std::string::npos) { + return report_.message_; + } else { + return "OK"; + } + } + + void WriteInitialOffsetLog() { + for (int i = 0; i < 4; i++) { + std::string record(initial_offset_record_sizes_[i], + static_cast('a' + i)); + Write(record); + } + } + + void CheckOffsetPastEndReturnsNoRecords(uint64_t offset_past_end) { + WriteInitialOffsetLog(); + reading_ = true; + source_.contents_ = Slice(dest_.contents_); + Reader* offset_reader = new Reader(&source_, &report_, true/*checksum*/, + WrittenBytes() + offset_past_end); + Slice record; + std::string scratch; + ASSERT_TRUE(!offset_reader->ReadRecord(&record, &scratch)); + delete offset_reader; + } + + void CheckInitialOffsetRecord(uint64_t initial_offset, + int expected_record_offset) { + WriteInitialOffsetLog(); + reading_ = true; + source_.contents_ = Slice(dest_.contents_); + Reader* offset_reader = new Reader(&source_, &report_, true/*checksum*/, + initial_offset); + Slice record; + std::string scratch; + ASSERT_TRUE(offset_reader->ReadRecord(&record, &scratch)); + ASSERT_EQ(initial_offset_record_sizes_[expected_record_offset], + record.size()); + ASSERT_EQ(initial_offset_last_record_offsets_[expected_record_offset], + offset_reader->LastRecordOffset()); + ASSERT_EQ((char)('a' + expected_record_offset), record.data()[0]); + delete offset_reader; + } + +}; + +size_t LogTest::initial_offset_record_sizes_[] = + {10000, // Two sizable records in first block + 10000, + 2 * log::kBlockSize - 1000, // Span three blocks + 1}; + +uint64_t LogTest::initial_offset_last_record_offsets_[] = + {0, + kHeaderSize + 10000, + 2 * (kHeaderSize + 10000), + 2 * (kHeaderSize + 10000) + + (2 * log::kBlockSize - 1000) + 3 * kHeaderSize}; + + +TEST(LogTest, Empty) { + ASSERT_EQ("EOF", Read()); +} + +TEST(LogTest, ReadWrite) { + Write("foo"); + Write("bar"); + Write(""); + Write("xxxx"); + ASSERT_EQ("foo", Read()); + ASSERT_EQ("bar", Read()); + ASSERT_EQ("", Read()); + ASSERT_EQ("xxxx", Read()); + ASSERT_EQ("EOF", Read()); + ASSERT_EQ("EOF", Read()); // Make sure reads at eof work +} + +TEST(LogTest, ManyBlocks) { + for (int i = 0; i < 100000; i++) { + Write(NumberString(i)); + } + for (int i = 0; i < 100000; i++) { + ASSERT_EQ(NumberString(i), Read()); + } + ASSERT_EQ("EOF", Read()); +} + +TEST(LogTest, Fragmentation) { + Write("small"); + Write(BigString("medium", 50000)); + Write(BigString("large", 100000)); + ASSERT_EQ("small", Read()); + ASSERT_EQ(BigString("medium", 50000), Read()); + ASSERT_EQ(BigString("large", 100000), Read()); + ASSERT_EQ("EOF", Read()); +} + +TEST(LogTest, MarginalTrailer) { + // Make a trailer that is exactly the same length as an empty record. + const int n = kBlockSize - 2*kHeaderSize; + Write(BigString("foo", n)); + ASSERT_EQ(kBlockSize - kHeaderSize, WrittenBytes()); + Write(""); + Write("bar"); + ASSERT_EQ(BigString("foo", n), Read()); + ASSERT_EQ("", Read()); + ASSERT_EQ("bar", Read()); + ASSERT_EQ("EOF", Read()); +} + +TEST(LogTest, MarginalTrailer2) { + // Make a trailer that is exactly the same length as an empty record. + const int n = kBlockSize - 2*kHeaderSize; + Write(BigString("foo", n)); + ASSERT_EQ(kBlockSize - kHeaderSize, WrittenBytes()); + Write("bar"); + ASSERT_EQ(BigString("foo", n), Read()); + ASSERT_EQ("bar", Read()); + ASSERT_EQ("EOF", Read()); + ASSERT_EQ(0, DroppedBytes()); + ASSERT_EQ("", ReportMessage()); +} + +TEST(LogTest, ShortTrailer) { + const int n = kBlockSize - 2*kHeaderSize + 4; + Write(BigString("foo", n)); + ASSERT_EQ(kBlockSize - kHeaderSize + 4, WrittenBytes()); + Write(""); + Write("bar"); + ASSERT_EQ(BigString("foo", n), Read()); + ASSERT_EQ("", Read()); + ASSERT_EQ("bar", Read()); + ASSERT_EQ("EOF", Read()); +} + +TEST(LogTest, AlignedEof) { + const int n = kBlockSize - 2*kHeaderSize + 4; + Write(BigString("foo", n)); + ASSERT_EQ(kBlockSize - kHeaderSize + 4, WrittenBytes()); + ASSERT_EQ(BigString("foo", n), Read()); + ASSERT_EQ("EOF", Read()); +} + +TEST(LogTest, RandomRead) { + const int N = 500; + Random write_rnd(301); + for (int i = 0; i < N; i++) { + Write(RandomSkewedString(i, &write_rnd)); + } + Random read_rnd(301); + for (int i = 0; i < N; i++) { + ASSERT_EQ(RandomSkewedString(i, &read_rnd), Read()); + } + ASSERT_EQ("EOF", Read()); +} + +// Tests of all the error paths in log_reader.cc follow: + +TEST(LogTest, ReadError) { + Write("foo"); + ForceError(); + ASSERT_EQ("EOF", Read()); + ASSERT_EQ(kBlockSize, DroppedBytes()); + ASSERT_EQ("OK", MatchError("read error")); +} + +TEST(LogTest, BadRecordType) { + Write("foo"); + // Type is stored in header[6] + IncrementByte(6, 100); + FixChecksum(0, 3); + ASSERT_EQ("EOF", Read()); + ASSERT_EQ(3, DroppedBytes()); + ASSERT_EQ("OK", MatchError("unknown record type")); +} + +TEST(LogTest, TruncatedTrailingRecordIsIgnored) { + Write("foo"); + ShrinkSize(4); // Drop all payload as well as a header byte + ASSERT_EQ("EOF", Read()); + // Truncated last record is ignored, not treated as an error. + ASSERT_EQ(0, DroppedBytes()); + ASSERT_EQ("", ReportMessage()); +} + +TEST(LogTest, BadLength) { + const int kPayloadSize = kBlockSize - kHeaderSize; + Write(BigString("bar", kPayloadSize)); + Write("foo"); + // Least significant size byte is stored in header[4]. + IncrementByte(4, 1); + ASSERT_EQ("foo", Read()); + ASSERT_EQ(kBlockSize, DroppedBytes()); + ASSERT_EQ("OK", MatchError("bad record length")); +} + +TEST(LogTest, BadLengthAtEndIsIgnored) { + Write("foo"); + ShrinkSize(1); + ASSERT_EQ("EOF", Read()); + ASSERT_EQ(0, DroppedBytes()); + ASSERT_EQ("", ReportMessage()); +} + +TEST(LogTest, ChecksumMismatch) { + Write("foo"); + IncrementByte(0, 10); + ASSERT_EQ("EOF", Read()); + ASSERT_EQ(10, DroppedBytes()); + ASSERT_EQ("OK", MatchError("checksum mismatch")); +} + +TEST(LogTest, UnexpectedMiddleType) { + Write("foo"); + SetByte(6, kMiddleType); + FixChecksum(0, 3); + ASSERT_EQ("EOF", Read()); + ASSERT_EQ(3, DroppedBytes()); + ASSERT_EQ("OK", MatchError("missing start")); +} + +TEST(LogTest, UnexpectedLastType) { + Write("foo"); + SetByte(6, kLastType); + FixChecksum(0, 3); + ASSERT_EQ("EOF", Read()); + ASSERT_EQ(3, DroppedBytes()); + ASSERT_EQ("OK", MatchError("missing start")); +} + +TEST(LogTest, UnexpectedFullType) { + Write("foo"); + Write("bar"); + SetByte(6, kFirstType); + FixChecksum(0, 3); + ASSERT_EQ("bar", Read()); + ASSERT_EQ("EOF", Read()); + ASSERT_EQ(3, DroppedBytes()); + ASSERT_EQ("OK", MatchError("partial record without end")); +} + +TEST(LogTest, UnexpectedFirstType) { + Write("foo"); + Write(BigString("bar", 100000)); + SetByte(6, kFirstType); + FixChecksum(0, 3); + ASSERT_EQ(BigString("bar", 100000), Read()); + ASSERT_EQ("EOF", Read()); + ASSERT_EQ(3, DroppedBytes()); + ASSERT_EQ("OK", MatchError("partial record without end")); +} + +TEST(LogTest, MissingLastIsIgnored) { + Write(BigString("bar", kBlockSize)); + // Remove the LAST block, including header. + ShrinkSize(14); + ASSERT_EQ("EOF", Read()); + ASSERT_EQ("", ReportMessage()); + ASSERT_EQ(0, DroppedBytes()); +} + +TEST(LogTest, PartialLastIsIgnored) { + Write(BigString("bar", kBlockSize)); + // Cause a bad record length in the LAST block. + ShrinkSize(1); + ASSERT_EQ("EOF", Read()); + ASSERT_EQ("", ReportMessage()); + ASSERT_EQ(0, DroppedBytes()); +} + +TEST(LogTest, ErrorJoinsRecords) { + // Consider two fragmented records: + // first(R1) last(R1) first(R2) last(R2) + // where the middle two fragments disappear. We do not want + // first(R1),last(R2) to get joined and returned as a valid record. + + // Write records that span two blocks + Write(BigString("foo", kBlockSize)); + Write(BigString("bar", kBlockSize)); + Write("correct"); + + // Wipe the middle block + for (int offset = kBlockSize; offset < 2*kBlockSize; offset++) { + SetByte(offset, 'x'); + } + + ASSERT_EQ("correct", Read()); + ASSERT_EQ("EOF", Read()); + const size_t dropped = DroppedBytes(); + ASSERT_LE(dropped, 2*kBlockSize + 100); + ASSERT_GE(dropped, 2*kBlockSize); +} + +TEST(LogTest, ReadStart) { + CheckInitialOffsetRecord(0, 0); +} + +TEST(LogTest, ReadSecondOneOff) { + CheckInitialOffsetRecord(1, 1); +} + +TEST(LogTest, ReadSecondTenThousand) { + CheckInitialOffsetRecord(10000, 1); +} + +TEST(LogTest, ReadSecondStart) { + CheckInitialOffsetRecord(10007, 1); +} + +TEST(LogTest, ReadThirdOneOff) { + CheckInitialOffsetRecord(10008, 2); +} + +TEST(LogTest, ReadThirdStart) { + CheckInitialOffsetRecord(20014, 2); +} + +TEST(LogTest, ReadFourthOneOff) { + CheckInitialOffsetRecord(20015, 3); +} + +TEST(LogTest, ReadFourthFirstBlockTrailer) { + CheckInitialOffsetRecord(log::kBlockSize - 4, 3); +} + +TEST(LogTest, ReadFourthMiddleBlock) { + CheckInitialOffsetRecord(log::kBlockSize + 1, 3); +} + +TEST(LogTest, ReadFourthLastBlock) { + CheckInitialOffsetRecord(2 * log::kBlockSize + 1, 3); +} + +TEST(LogTest, ReadFourthStart) { + CheckInitialOffsetRecord( + 2 * (kHeaderSize + 1000) + (2 * log::kBlockSize - 1000) + 3 * kHeaderSize, + 3); +} + +TEST(LogTest, ReadEnd) { + CheckOffsetPastEndReturnsNoRecords(0); +} + +TEST(LogTest, ReadPastEnd) { + CheckOffsetPastEndReturnsNoRecords(5); +} + +} // namespace log +} // namespace leveldb + +int main(int argc, char** argv) { + return leveldb::test::RunAllTests(); +} diff --git a/ios/Pods/leveldb-library/db/log_writer.cc b/ios/Pods/leveldb-library/db/log_writer.cc new file mode 100644 index 000000000..2da99ac08 --- /dev/null +++ b/ios/Pods/leveldb-library/db/log_writer.cc @@ -0,0 +1,103 @@ +// Copyright (c) 2011 The LevelDB Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. See the AUTHORS file for names of contributors. + +#include "db/log_writer.h" + +#include +#include "leveldb/env.h" +#include "util/coding.h" +#include "util/crc32c.h" + +namespace leveldb { +namespace log { + +Writer::Writer(WritableFile* dest) + : dest_(dest), + block_offset_(0) { + for (int i = 0; i <= kMaxRecordType; i++) { + char t = static_cast(i); + type_crc_[i] = crc32c::Value(&t, 1); + } +} + +Writer::~Writer() { +} + +Status Writer::AddRecord(const Slice& slice) { + const char* ptr = slice.data(); + size_t left = slice.size(); + + // Fragment the record if necessary and emit it. Note that if slice + // is empty, we still want to iterate once to emit a single + // zero-length record + Status s; + bool begin = true; + do { + const int leftover = kBlockSize - block_offset_; + assert(leftover >= 0); + if (leftover < kHeaderSize) { + // Switch to a new block + if (leftover > 0) { + // Fill the trailer (literal below relies on kHeaderSize being 7) + assert(kHeaderSize == 7); + dest_->Append(Slice("\x00\x00\x00\x00\x00\x00", leftover)); + } + block_offset_ = 0; + } + + // Invariant: we never leave < kHeaderSize bytes in a block. + assert(kBlockSize - block_offset_ - kHeaderSize >= 0); + + const size_t avail = kBlockSize - block_offset_ - kHeaderSize; + const size_t fragment_length = (left < avail) ? left : avail; + + RecordType type; + const bool end = (left == fragment_length); + if (begin && end) { + type = kFullType; + } else if (begin) { + type = kFirstType; + } else if (end) { + type = kLastType; + } else { + type = kMiddleType; + } + + s = EmitPhysicalRecord(type, ptr, fragment_length); + ptr += fragment_length; + left -= fragment_length; + begin = false; + } while (s.ok() && left > 0); + return s; +} + +Status Writer::EmitPhysicalRecord(RecordType t, const char* ptr, size_t n) { + assert(n <= 0xffff); // Must fit in two bytes + assert(block_offset_ + kHeaderSize + n <= kBlockSize); + + // Format the header + char buf[kHeaderSize]; + buf[4] = static_cast(n & 0xff); + buf[5] = static_cast(n >> 8); + buf[6] = static_cast(t); + + // Compute the crc of the record type and the payload. + uint32_t crc = crc32c::Extend(type_crc_[t], ptr, n); + crc = crc32c::Mask(crc); // Adjust for storage + EncodeFixed32(buf, crc); + + // Write the header and the payload + Status s = dest_->Append(Slice(buf, kHeaderSize)); + if (s.ok()) { + s = dest_->Append(Slice(ptr, n)); + if (s.ok()) { + s = dest_->Flush(); + } + } + block_offset_ += kHeaderSize + n; + return s; +} + +} // namespace log +} // namespace leveldb diff --git a/ios/Pods/leveldb-library/db/log_writer.h b/ios/Pods/leveldb-library/db/log_writer.h new file mode 100644 index 000000000..a3a954d96 --- /dev/null +++ b/ios/Pods/leveldb-library/db/log_writer.h @@ -0,0 +1,48 @@ +// Copyright (c) 2011 The LevelDB Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. See the AUTHORS file for names of contributors. + +#ifndef STORAGE_LEVELDB_DB_LOG_WRITER_H_ +#define STORAGE_LEVELDB_DB_LOG_WRITER_H_ + +#include +#include "db/log_format.h" +#include "leveldb/slice.h" +#include "leveldb/status.h" + +namespace leveldb { + +class WritableFile; + +namespace log { + +class Writer { + public: + // Create a writer that will append data to "*dest". + // "*dest" must be initially empty. + // "*dest" must remain live while this Writer is in use. + explicit Writer(WritableFile* dest); + ~Writer(); + + Status AddRecord(const Slice& slice); + + private: + WritableFile* dest_; + int block_offset_; // Current offset in block + + // crc32c values for all supported record types. These are + // pre-computed to reduce the overhead of computing the crc of the + // record type stored in the header. + uint32_t type_crc_[kMaxRecordType + 1]; + + Status EmitPhysicalRecord(RecordType type, const char* ptr, size_t length); + + // No copying allowed + Writer(const Writer&); + void operator=(const Writer&); +}; + +} // namespace log +} // namespace leveldb + +#endif // STORAGE_LEVELDB_DB_LOG_WRITER_H_ diff --git a/ios/Pods/leveldb-library/db/memtable.cc b/ios/Pods/leveldb-library/db/memtable.cc new file mode 100644 index 000000000..bfec0a7e7 --- /dev/null +++ b/ios/Pods/leveldb-library/db/memtable.cc @@ -0,0 +1,145 @@ +// Copyright (c) 2011 The LevelDB Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. See the AUTHORS file for names of contributors. + +#include "db/memtable.h" +#include "db/dbformat.h" +#include "leveldb/comparator.h" +#include "leveldb/env.h" +#include "leveldb/iterator.h" +#include "util/coding.h" + +namespace leveldb { + +static Slice GetLengthPrefixedSlice(const char* data) { + uint32_t len; + const char* p = data; + p = GetVarint32Ptr(p, p + 5, &len); // +5: we assume "p" is not corrupted + return Slice(p, len); +} + +MemTable::MemTable(const InternalKeyComparator& cmp) + : comparator_(cmp), + refs_(0), + table_(comparator_, &arena_) { +} + +MemTable::~MemTable() { + assert(refs_ == 0); +} + +size_t MemTable::ApproximateMemoryUsage() { return arena_.MemoryUsage(); } + +int MemTable::KeyComparator::operator()(const char* aptr, const char* bptr) + const { + // Internal keys are encoded as length-prefixed strings. + Slice a = GetLengthPrefixedSlice(aptr); + Slice b = GetLengthPrefixedSlice(bptr); + return comparator.Compare(a, b); +} + +// Encode a suitable internal key target for "target" and return it. +// Uses *scratch as scratch space, and the returned pointer will point +// into this scratch space. +static const char* EncodeKey(std::string* scratch, const Slice& target) { + scratch->clear(); + PutVarint32(scratch, target.size()); + scratch->append(target.data(), target.size()); + return scratch->data(); +} + +class MemTableIterator: public Iterator { + public: + explicit MemTableIterator(MemTable::Table* table) : iter_(table) { } + + virtual bool Valid() const { return iter_.Valid(); } + virtual void Seek(const Slice& k) { iter_.Seek(EncodeKey(&tmp_, k)); } + virtual void SeekToFirst() { iter_.SeekToFirst(); } + virtual void SeekToLast() { iter_.SeekToLast(); } + virtual void Next() { iter_.Next(); } + virtual void Prev() { iter_.Prev(); } + virtual Slice key() const { return GetLengthPrefixedSlice(iter_.key()); } + virtual Slice value() const { + Slice key_slice = GetLengthPrefixedSlice(iter_.key()); + return GetLengthPrefixedSlice(key_slice.data() + key_slice.size()); + } + + virtual Status status() const { return Status::OK(); } + + private: + MemTable::Table::Iterator iter_; + std::string tmp_; // For passing to EncodeKey + + // No copying allowed + MemTableIterator(const MemTableIterator&); + void operator=(const MemTableIterator&); +}; + +Iterator* MemTable::NewIterator() { + return new MemTableIterator(&table_); +} + +void MemTable::Add(SequenceNumber s, ValueType type, + const Slice& key, + const Slice& value) { + // Format of an entry is concatenation of: + // key_size : varint32 of internal_key.size() + // key bytes : char[internal_key.size()] + // value_size : varint32 of value.size() + // value bytes : char[value.size()] + size_t key_size = key.size(); + size_t val_size = value.size(); + size_t internal_key_size = key_size + 8; + const size_t encoded_len = + VarintLength(internal_key_size) + internal_key_size + + VarintLength(val_size) + val_size; + char* buf = arena_.Allocate(encoded_len); + char* p = EncodeVarint32(buf, internal_key_size); + memcpy(p, key.data(), key_size); + p += key_size; + EncodeFixed64(p, (s << 8) | type); + p += 8; + p = EncodeVarint32(p, val_size); + memcpy(p, value.data(), val_size); + assert((p + val_size) - buf == encoded_len); + table_.Insert(buf); +} + +bool MemTable::Get(const LookupKey& key, std::string* value, Status* s) { + Slice memkey = key.memtable_key(); + Table::Iterator iter(&table_); + iter.Seek(memkey.data()); + if (iter.Valid()) { + // entry format is: + // klength varint32 + // userkey char[klength] + // tag uint64 + // vlength varint32 + // value char[vlength] + // Check that it belongs to same user key. We do not check the + // sequence number since the Seek() call above should have skipped + // all entries with overly large sequence numbers. + const char* entry = iter.key(); + uint32_t key_length; + const char* key_ptr = GetVarint32Ptr(entry, entry+5, &key_length); + if (comparator_.comparator.user_comparator()->Compare( + Slice(key_ptr, key_length - 8), + key.user_key()) == 0) { + // Correct user key + const uint64_t tag = DecodeFixed64(key_ptr + key_length - 8); + switch (static_cast(tag & 0xff)) { + case kTypeValue: { + Slice v = GetLengthPrefixedSlice(key_ptr + key_length); + value->assign(v.data(), v.size()); + return true; + } + case kTypeDeletion: + *s = Status::NotFound(Slice()); + return true; + } + } + } + return false; +} + +} // namespace leveldb diff --git a/ios/Pods/leveldb-library/db/memtable.h b/ios/Pods/leveldb-library/db/memtable.h new file mode 100644 index 000000000..92e90bb09 --- /dev/null +++ b/ios/Pods/leveldb-library/db/memtable.h @@ -0,0 +1,91 @@ +// Copyright (c) 2011 The LevelDB Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. See the AUTHORS file for names of contributors. + +#ifndef STORAGE_LEVELDB_DB_MEMTABLE_H_ +#define STORAGE_LEVELDB_DB_MEMTABLE_H_ + +#include +#include "leveldb/db.h" +#include "db/dbformat.h" +#include "db/skiplist.h" +#include "util/arena.h" + +namespace leveldb { + +class InternalKeyComparator; +class Mutex; +class MemTableIterator; + +class MemTable { + public: + // MemTables are reference counted. The initial reference count + // is zero and the caller must call Ref() at least once. + explicit MemTable(const InternalKeyComparator& comparator); + + // Increase reference count. + void Ref() { ++refs_; } + + // Drop reference count. Delete if no more references exist. + void Unref() { + --refs_; + assert(refs_ >= 0); + if (refs_ <= 0) { + delete this; + } + } + + // Returns an estimate of the number of bytes of data in use by this + // data structure. + // + // REQUIRES: external synchronization to prevent simultaneous + // operations on the same MemTable. + size_t ApproximateMemoryUsage(); + + // Return an iterator that yields the contents of the memtable. + // + // The caller must ensure that the underlying MemTable remains live + // while the returned iterator is live. The keys returned by this + // iterator are internal keys encoded by AppendInternalKey in the + // db/format.{h,cc} module. + Iterator* NewIterator(); + + // Add an entry into memtable that maps key to value at the + // specified sequence number and with the specified type. + // Typically value will be empty if type==kTypeDeletion. + void Add(SequenceNumber seq, ValueType type, + const Slice& key, + const Slice& value); + + // If memtable contains a value for key, store it in *value and return true. + // If memtable contains a deletion for key, store a NotFound() error + // in *status and return true. + // Else, return false. + bool Get(const LookupKey& key, std::string* value, Status* s); + + private: + ~MemTable(); // Private since only Unref() should be used to delete it + + struct KeyComparator { + const InternalKeyComparator comparator; + explicit KeyComparator(const InternalKeyComparator& c) : comparator(c) { } + int operator()(const char* a, const char* b) const; + }; + friend class MemTableIterator; + friend class MemTableBackwardIterator; + + typedef SkipList Table; + + KeyComparator comparator_; + int refs_; + Arena arena_; + Table table_; + + // No copying allowed + MemTable(const MemTable&); + void operator=(const MemTable&); +}; + +} // namespace leveldb + +#endif // STORAGE_LEVELDB_DB_MEMTABLE_H_ diff --git a/ios/Pods/leveldb-library/db/repair.cc b/ios/Pods/leveldb-library/db/repair.cc new file mode 100644 index 000000000..4cd4bb047 --- /dev/null +++ b/ios/Pods/leveldb-library/db/repair.cc @@ -0,0 +1,461 @@ +// Copyright (c) 2011 The LevelDB Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. See the AUTHORS file for names of contributors. +// +// We recover the contents of the descriptor from the other files we find. +// (1) Any log files are first converted to tables +// (2) We scan every table to compute +// (a) smallest/largest for the table +// (b) largest sequence number in the table +// (3) We generate descriptor contents: +// - log number is set to zero +// - next-file-number is set to 1 + largest file number we found +// - last-sequence-number is set to largest sequence# found across +// all tables (see 2c) +// - compaction pointers are cleared +// - every table file is added at level 0 +// +// Possible optimization 1: +// (a) Compute total size and use to pick appropriate max-level M +// (b) Sort tables by largest sequence# in the table +// (c) For each table: if it overlaps earlier table, place in level-0, +// else place in level-M. +// Possible optimization 2: +// Store per-table metadata (smallest, largest, largest-seq#, ...) +// in the table's meta section to speed up ScanTable. + +#include "db/builder.h" +#include "db/db_impl.h" +#include "db/dbformat.h" +#include "db/filename.h" +#include "db/log_reader.h" +#include "db/log_writer.h" +#include "db/memtable.h" +#include "db/table_cache.h" +#include "db/version_edit.h" +#include "db/write_batch_internal.h" +#include "leveldb/comparator.h" +#include "leveldb/db.h" +#include "leveldb/env.h" + +namespace leveldb { + +namespace { + +class Repairer { + public: + Repairer(const std::string& dbname, const Options& options) + : dbname_(dbname), + env_(options.env), + icmp_(options.comparator), + ipolicy_(options.filter_policy), + options_(SanitizeOptions(dbname, &icmp_, &ipolicy_, options)), + owns_info_log_(options_.info_log != options.info_log), + owns_cache_(options_.block_cache != options.block_cache), + next_file_number_(1) { + // TableCache can be small since we expect each table to be opened once. + table_cache_ = new TableCache(dbname_, &options_, 10); + } + + ~Repairer() { + delete table_cache_; + if (owns_info_log_) { + delete options_.info_log; + } + if (owns_cache_) { + delete options_.block_cache; + } + } + + Status Run() { + Status status = FindFiles(); + if (status.ok()) { + ConvertLogFilesToTables(); + ExtractMetaData(); + status = WriteDescriptor(); + } + if (status.ok()) { + unsigned long long bytes = 0; + for (size_t i = 0; i < tables_.size(); i++) { + bytes += tables_[i].meta.file_size; + } + Log(options_.info_log, + "**** Repaired leveldb %s; " + "recovered %d files; %llu bytes. " + "Some data may have been lost. " + "****", + dbname_.c_str(), + static_cast(tables_.size()), + bytes); + } + return status; + } + + private: + struct TableInfo { + FileMetaData meta; + SequenceNumber max_sequence; + }; + + std::string const dbname_; + Env* const env_; + InternalKeyComparator const icmp_; + InternalFilterPolicy const ipolicy_; + Options const options_; + bool owns_info_log_; + bool owns_cache_; + TableCache* table_cache_; + VersionEdit edit_; + + std::vector manifests_; + std::vector table_numbers_; + std::vector logs_; + std::vector tables_; + uint64_t next_file_number_; + + Status FindFiles() { + std::vector filenames; + Status status = env_->GetChildren(dbname_, &filenames); + if (!status.ok()) { + return status; + } + if (filenames.empty()) { + return Status::IOError(dbname_, "repair found no files"); + } + + uint64_t number; + FileType type; + for (size_t i = 0; i < filenames.size(); i++) { + if (ParseFileName(filenames[i], &number, &type)) { + if (type == kDescriptorFile) { + manifests_.push_back(filenames[i]); + } else { + if (number + 1 > next_file_number_) { + next_file_number_ = number + 1; + } + if (type == kLogFile) { + logs_.push_back(number); + } else if (type == kTableFile) { + table_numbers_.push_back(number); + } else { + // Ignore other files + } + } + } + } + return status; + } + + void ConvertLogFilesToTables() { + for (size_t i = 0; i < logs_.size(); i++) { + std::string logname = LogFileName(dbname_, logs_[i]); + Status status = ConvertLogToTable(logs_[i]); + if (!status.ok()) { + Log(options_.info_log, "Log #%llu: ignoring conversion error: %s", + (unsigned long long) logs_[i], + status.ToString().c_str()); + } + ArchiveFile(logname); + } + } + + Status ConvertLogToTable(uint64_t log) { + struct LogReporter : public log::Reader::Reporter { + Env* env; + Logger* info_log; + uint64_t lognum; + virtual void Corruption(size_t bytes, const Status& s) { + // We print error messages for corruption, but continue repairing. + Log(info_log, "Log #%llu: dropping %d bytes; %s", + (unsigned long long) lognum, + static_cast(bytes), + s.ToString().c_str()); + } + }; + + // Open the log file + std::string logname = LogFileName(dbname_, log); + SequentialFile* lfile; + Status status = env_->NewSequentialFile(logname, &lfile); + if (!status.ok()) { + return status; + } + + // Create the log reader. + LogReporter reporter; + reporter.env = env_; + reporter.info_log = options_.info_log; + reporter.lognum = log; + // We intentionally make log::Reader do checksumming so that + // corruptions cause entire commits to be skipped instead of + // propagating bad information (like overly large sequence + // numbers). + log::Reader reader(lfile, &reporter, false/*do not checksum*/, + 0/*initial_offset*/); + + // Read all the records and add to a memtable + std::string scratch; + Slice record; + WriteBatch batch; + MemTable* mem = new MemTable(icmp_); + mem->Ref(); + int counter = 0; + while (reader.ReadRecord(&record, &scratch)) { + if (record.size() < 12) { + reporter.Corruption( + record.size(), Status::Corruption("log record too small")); + continue; + } + WriteBatchInternal::SetContents(&batch, record); + status = WriteBatchInternal::InsertInto(&batch, mem); + if (status.ok()) { + counter += WriteBatchInternal::Count(&batch); + } else { + Log(options_.info_log, "Log #%llu: ignoring %s", + (unsigned long long) log, + status.ToString().c_str()); + status = Status::OK(); // Keep going with rest of file + } + } + delete lfile; + + // Do not record a version edit for this conversion to a Table + // since ExtractMetaData() will also generate edits. + FileMetaData meta; + meta.number = next_file_number_++; + Iterator* iter = mem->NewIterator(); + status = BuildTable(dbname_, env_, options_, table_cache_, iter, &meta); + delete iter; + mem->Unref(); + mem = NULL; + if (status.ok()) { + if (meta.file_size > 0) { + table_numbers_.push_back(meta.number); + } + } + Log(options_.info_log, "Log #%llu: %d ops saved to Table #%llu %s", + (unsigned long long) log, + counter, + (unsigned long long) meta.number, + status.ToString().c_str()); + return status; + } + + void ExtractMetaData() { + for (size_t i = 0; i < table_numbers_.size(); i++) { + ScanTable(table_numbers_[i]); + } + } + + Iterator* NewTableIterator(const FileMetaData& meta) { + // Same as compaction iterators: if paranoid_checks are on, turn + // on checksum verification. + ReadOptions r; + r.verify_checksums = options_.paranoid_checks; + return table_cache_->NewIterator(r, meta.number, meta.file_size); + } + + void ScanTable(uint64_t number) { + TableInfo t; + t.meta.number = number; + std::string fname = TableFileName(dbname_, number); + Status status = env_->GetFileSize(fname, &t.meta.file_size); + if (!status.ok()) { + // Try alternate file name. + fname = SSTTableFileName(dbname_, number); + Status s2 = env_->GetFileSize(fname, &t.meta.file_size); + if (s2.ok()) { + status = Status::OK(); + } + } + if (!status.ok()) { + ArchiveFile(TableFileName(dbname_, number)); + ArchiveFile(SSTTableFileName(dbname_, number)); + Log(options_.info_log, "Table #%llu: dropped: %s", + (unsigned long long) t.meta.number, + status.ToString().c_str()); + return; + } + + // Extract metadata by scanning through table. + int counter = 0; + Iterator* iter = NewTableIterator(t.meta); + bool empty = true; + ParsedInternalKey parsed; + t.max_sequence = 0; + for (iter->SeekToFirst(); iter->Valid(); iter->Next()) { + Slice key = iter->key(); + if (!ParseInternalKey(key, &parsed)) { + Log(options_.info_log, "Table #%llu: unparsable key %s", + (unsigned long long) t.meta.number, + EscapeString(key).c_str()); + continue; + } + + counter++; + if (empty) { + empty = false; + t.meta.smallest.DecodeFrom(key); + } + t.meta.largest.DecodeFrom(key); + if (parsed.sequence > t.max_sequence) { + t.max_sequence = parsed.sequence; + } + } + if (!iter->status().ok()) { + status = iter->status(); + } + delete iter; + Log(options_.info_log, "Table #%llu: %d entries %s", + (unsigned long long) t.meta.number, + counter, + status.ToString().c_str()); + + if (status.ok()) { + tables_.push_back(t); + } else { + RepairTable(fname, t); // RepairTable archives input file. + } + } + + void RepairTable(const std::string& src, TableInfo t) { + // We will copy src contents to a new table and then rename the + // new table over the source. + + // Create builder. + std::string copy = TableFileName(dbname_, next_file_number_++); + WritableFile* file; + Status s = env_->NewWritableFile(copy, &file); + if (!s.ok()) { + return; + } + TableBuilder* builder = new TableBuilder(options_, file); + + // Copy data. + Iterator* iter = NewTableIterator(t.meta); + int counter = 0; + for (iter->SeekToFirst(); iter->Valid(); iter->Next()) { + builder->Add(iter->key(), iter->value()); + counter++; + } + delete iter; + + ArchiveFile(src); + if (counter == 0) { + builder->Abandon(); // Nothing to save + } else { + s = builder->Finish(); + if (s.ok()) { + t.meta.file_size = builder->FileSize(); + } + } + delete builder; + builder = NULL; + + if (s.ok()) { + s = file->Close(); + } + delete file; + file = NULL; + + if (counter > 0 && s.ok()) { + std::string orig = TableFileName(dbname_, t.meta.number); + s = env_->RenameFile(copy, orig); + if (s.ok()) { + Log(options_.info_log, "Table #%llu: %d entries repaired", + (unsigned long long) t.meta.number, counter); + tables_.push_back(t); + } + } + if (!s.ok()) { + env_->DeleteFile(copy); + } + } + + Status WriteDescriptor() { + std::string tmp = TempFileName(dbname_, 1); + WritableFile* file; + Status status = env_->NewWritableFile(tmp, &file); + if (!status.ok()) { + return status; + } + + SequenceNumber max_sequence = 0; + for (size_t i = 0; i < tables_.size(); i++) { + if (max_sequence < tables_[i].max_sequence) { + max_sequence = tables_[i].max_sequence; + } + } + + edit_.SetComparatorName(icmp_.user_comparator()->Name()); + edit_.SetLogNumber(0); + edit_.SetNextFile(next_file_number_); + edit_.SetLastSequence(max_sequence); + + for (size_t i = 0; i < tables_.size(); i++) { + // TODO(opt): separate out into multiple levels + const TableInfo& t = tables_[i]; + edit_.AddFile(0, t.meta.number, t.meta.file_size, + t.meta.smallest, t.meta.largest); + } + + //fprintf(stderr, "NewDescriptor:\n%s\n", edit_.DebugString().c_str()); + { + log::Writer log(file); + std::string record; + edit_.EncodeTo(&record); + status = log.AddRecord(record); + } + if (status.ok()) { + status = file->Close(); + } + delete file; + file = NULL; + + if (!status.ok()) { + env_->DeleteFile(tmp); + } else { + // Discard older manifests + for (size_t i = 0; i < manifests_.size(); i++) { + ArchiveFile(dbname_ + "/" + manifests_[i]); + } + + // Install new manifest + status = env_->RenameFile(tmp, DescriptorFileName(dbname_, 1)); + if (status.ok()) { + status = SetCurrentFile(env_, dbname_, 1); + } else { + env_->DeleteFile(tmp); + } + } + return status; + } + + void ArchiveFile(const std::string& fname) { + // Move into another directory. E.g., for + // dir/foo + // rename to + // dir/lost/foo + const char* slash = strrchr(fname.c_str(), '/'); + std::string new_dir; + if (slash != NULL) { + new_dir.assign(fname.data(), slash - fname.data()); + } + new_dir.append("/lost"); + env_->CreateDir(new_dir); // Ignore error + std::string new_file = new_dir; + new_file.append("/"); + new_file.append((slash == NULL) ? fname.c_str() : slash + 1); + Status s = env_->RenameFile(fname, new_file); + Log(options_.info_log, "Archiving %s: %s\n", + fname.c_str(), s.ToString().c_str()); + } +}; +} // namespace + +Status RepairDB(const std::string& dbname, const Options& options) { + Repairer repairer(dbname, options); + return repairer.Run(); +} + +} // namespace leveldb diff --git a/ios/Pods/leveldb-library/db/skiplist.h b/ios/Pods/leveldb-library/db/skiplist.h new file mode 100644 index 000000000..ed8b09220 --- /dev/null +++ b/ios/Pods/leveldb-library/db/skiplist.h @@ -0,0 +1,384 @@ +#ifndef STORAGE_LEVELDB_DB_SKIPLIST_H_ +#define STORAGE_LEVELDB_DB_SKIPLIST_H_ + +// Copyright (c) 2011 The LevelDB Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. See the AUTHORS file for names of contributors. +// +// Thread safety +// ------------- +// +// Writes require external synchronization, most likely a mutex. +// Reads require a guarantee that the SkipList will not be destroyed +// while the read is in progress. Apart from that, reads progress +// without any internal locking or synchronization. +// +// Invariants: +// +// (1) Allocated nodes are never deleted until the SkipList is +// destroyed. This is trivially guaranteed by the code since we +// never delete any skip list nodes. +// +// (2) The contents of a Node except for the next/prev pointers are +// immutable after the Node has been linked into the SkipList. +// Only Insert() modifies the list, and it is careful to initialize +// a node and use release-stores to publish the nodes in one or +// more lists. +// +// ... prev vs. next pointer ordering ... + +#include +#include +#include "port/port.h" +#include "util/arena.h" +#include "util/random.h" + +namespace leveldb { + +class Arena; + +template +class SkipList { + private: + struct Node; + + public: + // Create a new SkipList object that will use "cmp" for comparing keys, + // and will allocate memory using "*arena". Objects allocated in the arena + // must remain allocated for the lifetime of the skiplist object. + explicit SkipList(Comparator cmp, Arena* arena); + + // Insert key into the list. + // REQUIRES: nothing that compares equal to key is currently in the list. + void Insert(const Key& key); + + // Returns true iff an entry that compares equal to key is in the list. + bool Contains(const Key& key) const; + + // Iteration over the contents of a skip list + class Iterator { + public: + // Initialize an iterator over the specified list. + // The returned iterator is not valid. + explicit Iterator(const SkipList* list); + + // Returns true iff the iterator is positioned at a valid node. + bool Valid() const; + + // Returns the key at the current position. + // REQUIRES: Valid() + const Key& key() const; + + // Advances to the next position. + // REQUIRES: Valid() + void Next(); + + // Advances to the previous position. + // REQUIRES: Valid() + void Prev(); + + // Advance to the first entry with a key >= target + void Seek(const Key& target); + + // Position at the first entry in list. + // Final state of iterator is Valid() iff list is not empty. + void SeekToFirst(); + + // Position at the last entry in list. + // Final state of iterator is Valid() iff list is not empty. + void SeekToLast(); + + private: + const SkipList* list_; + Node* node_; + // Intentionally copyable + }; + + private: + enum { kMaxHeight = 12 }; + + // Immutable after construction + Comparator const compare_; + Arena* const arena_; // Arena used for allocations of nodes + + Node* const head_; + + // Modified only by Insert(). Read racily by readers, but stale + // values are ok. + port::AtomicPointer max_height_; // Height of the entire list + + inline int GetMaxHeight() const { + return static_cast( + reinterpret_cast(max_height_.NoBarrier_Load())); + } + + // Read/written only by Insert(). + Random rnd_; + + Node* NewNode(const Key& key, int height); + int RandomHeight(); + bool Equal(const Key& a, const Key& b) const { return (compare_(a, b) == 0); } + + // Return true if key is greater than the data stored in "n" + bool KeyIsAfterNode(const Key& key, Node* n) const; + + // Return the earliest node that comes at or after key. + // Return NULL if there is no such node. + // + // If prev is non-NULL, fills prev[level] with pointer to previous + // node at "level" for every level in [0..max_height_-1]. + Node* FindGreaterOrEqual(const Key& key, Node** prev) const; + + // Return the latest node with a key < key. + // Return head_ if there is no such node. + Node* FindLessThan(const Key& key) const; + + // Return the last node in the list. + // Return head_ if list is empty. + Node* FindLast() const; + + // No copying allowed + SkipList(const SkipList&); + void operator=(const SkipList&); +}; + +// Implementation details follow +template +struct SkipList::Node { + explicit Node(const Key& k) : key(k) { } + + Key const key; + + // Accessors/mutators for links. Wrapped in methods so we can + // add the appropriate barriers as necessary. + Node* Next(int n) { + assert(n >= 0); + // Use an 'acquire load' so that we observe a fully initialized + // version of the returned Node. + return reinterpret_cast(next_[n].Acquire_Load()); + } + void SetNext(int n, Node* x) { + assert(n >= 0); + // Use a 'release store' so that anybody who reads through this + // pointer observes a fully initialized version of the inserted node. + next_[n].Release_Store(x); + } + + // No-barrier variants that can be safely used in a few locations. + Node* NoBarrier_Next(int n) { + assert(n >= 0); + return reinterpret_cast(next_[n].NoBarrier_Load()); + } + void NoBarrier_SetNext(int n, Node* x) { + assert(n >= 0); + next_[n].NoBarrier_Store(x); + } + + private: + // Array of length equal to the node height. next_[0] is lowest level link. + port::AtomicPointer next_[1]; +}; + +template +typename SkipList::Node* +SkipList::NewNode(const Key& key, int height) { + char* mem = arena_->AllocateAligned( + sizeof(Node) + sizeof(port::AtomicPointer) * (height - 1)); + return new (mem) Node(key); +} + +template +inline SkipList::Iterator::Iterator(const SkipList* list) { + list_ = list; + node_ = NULL; +} + +template +inline bool SkipList::Iterator::Valid() const { + return node_ != NULL; +} + +template +inline const Key& SkipList::Iterator::key() const { + assert(Valid()); + return node_->key; +} + +template +inline void SkipList::Iterator::Next() { + assert(Valid()); + node_ = node_->Next(0); +} + +template +inline void SkipList::Iterator::Prev() { + // Instead of using explicit "prev" links, we just search for the + // last node that falls before key. + assert(Valid()); + node_ = list_->FindLessThan(node_->key); + if (node_ == list_->head_) { + node_ = NULL; + } +} + +template +inline void SkipList::Iterator::Seek(const Key& target) { + node_ = list_->FindGreaterOrEqual(target, NULL); +} + +template +inline void SkipList::Iterator::SeekToFirst() { + node_ = list_->head_->Next(0); +} + +template +inline void SkipList::Iterator::SeekToLast() { + node_ = list_->FindLast(); + if (node_ == list_->head_) { + node_ = NULL; + } +} + +template +int SkipList::RandomHeight() { + // Increase height with probability 1 in kBranching + static const unsigned int kBranching = 4; + int height = 1; + while (height < kMaxHeight && ((rnd_.Next() % kBranching) == 0)) { + height++; + } + assert(height > 0); + assert(height <= kMaxHeight); + return height; +} + +template +bool SkipList::KeyIsAfterNode(const Key& key, Node* n) const { + // NULL n is considered infinite + return (n != NULL) && (compare_(n->key, key) < 0); +} + +template +typename SkipList::Node* SkipList::FindGreaterOrEqual(const Key& key, Node** prev) + const { + Node* x = head_; + int level = GetMaxHeight() - 1; + while (true) { + Node* next = x->Next(level); + if (KeyIsAfterNode(key, next)) { + // Keep searching in this list + x = next; + } else { + if (prev != NULL) prev[level] = x; + if (level == 0) { + return next; + } else { + // Switch to next list + level--; + } + } + } +} + +template +typename SkipList::Node* +SkipList::FindLessThan(const Key& key) const { + Node* x = head_; + int level = GetMaxHeight() - 1; + while (true) { + assert(x == head_ || compare_(x->key, key) < 0); + Node* next = x->Next(level); + if (next == NULL || compare_(next->key, key) >= 0) { + if (level == 0) { + return x; + } else { + // Switch to next list + level--; + } + } else { + x = next; + } + } +} + +template +typename SkipList::Node* SkipList::FindLast() + const { + Node* x = head_; + int level = GetMaxHeight() - 1; + while (true) { + Node* next = x->Next(level); + if (next == NULL) { + if (level == 0) { + return x; + } else { + // Switch to next list + level--; + } + } else { + x = next; + } + } +} + +template +SkipList::SkipList(Comparator cmp, Arena* arena) + : compare_(cmp), + arena_(arena), + head_(NewNode(0 /* any key will do */, kMaxHeight)), + max_height_(reinterpret_cast(1)), + rnd_(0xdeadbeef) { + for (int i = 0; i < kMaxHeight; i++) { + head_->SetNext(i, NULL); + } +} + +template +void SkipList::Insert(const Key& key) { + // TODO(opt): We can use a barrier-free variant of FindGreaterOrEqual() + // here since Insert() is externally synchronized. + Node* prev[kMaxHeight]; + Node* x = FindGreaterOrEqual(key, prev); + + // Our data structure does not allow duplicate insertion + assert(x == NULL || !Equal(key, x->key)); + + int height = RandomHeight(); + if (height > GetMaxHeight()) { + for (int i = GetMaxHeight(); i < height; i++) { + prev[i] = head_; + } + //fprintf(stderr, "Change height from %d to %d\n", max_height_, height); + + // It is ok to mutate max_height_ without any synchronization + // with concurrent readers. A concurrent reader that observes + // the new value of max_height_ will see either the old value of + // new level pointers from head_ (NULL), or a new value set in + // the loop below. In the former case the reader will + // immediately drop to the next level since NULL sorts after all + // keys. In the latter case the reader will use the new node. + max_height_.NoBarrier_Store(reinterpret_cast(height)); + } + + x = NewNode(key, height); + for (int i = 0; i < height; i++) { + // NoBarrier_SetNext() suffices since we will add a barrier when + // we publish a pointer to "x" in prev[i]. + x->NoBarrier_SetNext(i, prev[i]->NoBarrier_Next(i)); + prev[i]->SetNext(i, x); + } +} + +template +bool SkipList::Contains(const Key& key) const { + Node* x = FindGreaterOrEqual(key, NULL); + if (x != NULL && Equal(key, x->key)) { + return true; + } else { + return false; + } +} + +} // namespace leveldb + +#endif // STORAGE_LEVELDB_DB_SKIPLIST_H_ diff --git a/ios/Pods/leveldb-library/db/skiplist_test.cc b/ios/Pods/leveldb-library/db/skiplist_test.cc new file mode 100644 index 000000000..c78f4b4fb --- /dev/null +++ b/ios/Pods/leveldb-library/db/skiplist_test.cc @@ -0,0 +1,378 @@ +// Copyright (c) 2011 The LevelDB Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. See the AUTHORS file for names of contributors. + +#include "db/skiplist.h" +#include +#include "leveldb/env.h" +#include "util/arena.h" +#include "util/hash.h" +#include "util/random.h" +#include "util/testharness.h" + +namespace leveldb { + +typedef uint64_t Key; + +struct Comparator { + int operator()(const Key& a, const Key& b) const { + if (a < b) { + return -1; + } else if (a > b) { + return +1; + } else { + return 0; + } + } +}; + +class SkipTest { }; + +TEST(SkipTest, Empty) { + Arena arena; + Comparator cmp; + SkipList list(cmp, &arena); + ASSERT_TRUE(!list.Contains(10)); + + SkipList::Iterator iter(&list); + ASSERT_TRUE(!iter.Valid()); + iter.SeekToFirst(); + ASSERT_TRUE(!iter.Valid()); + iter.Seek(100); + ASSERT_TRUE(!iter.Valid()); + iter.SeekToLast(); + ASSERT_TRUE(!iter.Valid()); +} + +TEST(SkipTest, InsertAndLookup) { + const int N = 2000; + const int R = 5000; + Random rnd(1000); + std::set keys; + Arena arena; + Comparator cmp; + SkipList list(cmp, &arena); + for (int i = 0; i < N; i++) { + Key key = rnd.Next() % R; + if (keys.insert(key).second) { + list.Insert(key); + } + } + + for (int i = 0; i < R; i++) { + if (list.Contains(i)) { + ASSERT_EQ(keys.count(i), 1); + } else { + ASSERT_EQ(keys.count(i), 0); + } + } + + // Simple iterator tests + { + SkipList::Iterator iter(&list); + ASSERT_TRUE(!iter.Valid()); + + iter.Seek(0); + ASSERT_TRUE(iter.Valid()); + ASSERT_EQ(*(keys.begin()), iter.key()); + + iter.SeekToFirst(); + ASSERT_TRUE(iter.Valid()); + ASSERT_EQ(*(keys.begin()), iter.key()); + + iter.SeekToLast(); + ASSERT_TRUE(iter.Valid()); + ASSERT_EQ(*(keys.rbegin()), iter.key()); + } + + // Forward iteration test + for (int i = 0; i < R; i++) { + SkipList::Iterator iter(&list); + iter.Seek(i); + + // Compare against model iterator + std::set::iterator model_iter = keys.lower_bound(i); + for (int j = 0; j < 3; j++) { + if (model_iter == keys.end()) { + ASSERT_TRUE(!iter.Valid()); + break; + } else { + ASSERT_TRUE(iter.Valid()); + ASSERT_EQ(*model_iter, iter.key()); + ++model_iter; + iter.Next(); + } + } + } + + // Backward iteration test + { + SkipList::Iterator iter(&list); + iter.SeekToLast(); + + // Compare against model iterator + for (std::set::reverse_iterator model_iter = keys.rbegin(); + model_iter != keys.rend(); + ++model_iter) { + ASSERT_TRUE(iter.Valid()); + ASSERT_EQ(*model_iter, iter.key()); + iter.Prev(); + } + ASSERT_TRUE(!iter.Valid()); + } +} + +// We want to make sure that with a single writer and multiple +// concurrent readers (with no synchronization other than when a +// reader's iterator is created), the reader always observes all the +// data that was present in the skip list when the iterator was +// constructor. Because insertions are happening concurrently, we may +// also observe new values that were inserted since the iterator was +// constructed, but we should never miss any values that were present +// at iterator construction time. +// +// We generate multi-part keys: +// +// where: +// key is in range [0..K-1] +// gen is a generation number for key +// hash is hash(key,gen) +// +// The insertion code picks a random key, sets gen to be 1 + the last +// generation number inserted for that key, and sets hash to Hash(key,gen). +// +// At the beginning of a read, we snapshot the last inserted +// generation number for each key. We then iterate, including random +// calls to Next() and Seek(). For every key we encounter, we +// check that it is either expected given the initial snapshot or has +// been concurrently added since the iterator started. +class ConcurrentTest { + private: + static const uint32_t K = 4; + + static uint64_t key(Key key) { return (key >> 40); } + static uint64_t gen(Key key) { return (key >> 8) & 0xffffffffu; } + static uint64_t hash(Key key) { return key & 0xff; } + + static uint64_t HashNumbers(uint64_t k, uint64_t g) { + uint64_t data[2] = { k, g }; + return Hash(reinterpret_cast(data), sizeof(data), 0); + } + + static Key MakeKey(uint64_t k, uint64_t g) { + assert(sizeof(Key) == sizeof(uint64_t)); + assert(k <= K); // We sometimes pass K to seek to the end of the skiplist + assert(g <= 0xffffffffu); + return ((k << 40) | (g << 8) | (HashNumbers(k, g) & 0xff)); + } + + static bool IsValidKey(Key k) { + return hash(k) == (HashNumbers(key(k), gen(k)) & 0xff); + } + + static Key RandomTarget(Random* rnd) { + switch (rnd->Next() % 10) { + case 0: + // Seek to beginning + return MakeKey(0, 0); + case 1: + // Seek to end + return MakeKey(K, 0); + default: + // Seek to middle + return MakeKey(rnd->Next() % K, 0); + } + } + + // Per-key generation + struct State { + port::AtomicPointer generation[K]; + void Set(int k, intptr_t v) { + generation[k].Release_Store(reinterpret_cast(v)); + } + intptr_t Get(int k) { + return reinterpret_cast(generation[k].Acquire_Load()); + } + + State() { + for (int k = 0; k < K; k++) { + Set(k, 0); + } + } + }; + + // Current state of the test + State current_; + + Arena arena_; + + // SkipList is not protected by mu_. We just use a single writer + // thread to modify it. + SkipList list_; + + public: + ConcurrentTest() : list_(Comparator(), &arena_) { } + + // REQUIRES: External synchronization + void WriteStep(Random* rnd) { + const uint32_t k = rnd->Next() % K; + const intptr_t g = current_.Get(k) + 1; + const Key key = MakeKey(k, g); + list_.Insert(key); + current_.Set(k, g); + } + + void ReadStep(Random* rnd) { + // Remember the initial committed state of the skiplist. + State initial_state; + for (int k = 0; k < K; k++) { + initial_state.Set(k, current_.Get(k)); + } + + Key pos = RandomTarget(rnd); + SkipList::Iterator iter(&list_); + iter.Seek(pos); + while (true) { + Key current; + if (!iter.Valid()) { + current = MakeKey(K, 0); + } else { + current = iter.key(); + ASSERT_TRUE(IsValidKey(current)) << current; + } + ASSERT_LE(pos, current) << "should not go backwards"; + + // Verify that everything in [pos,current) was not present in + // initial_state. + while (pos < current) { + ASSERT_LT(key(pos), K) << pos; + + // Note that generation 0 is never inserted, so it is ok if + // <*,0,*> is missing. + ASSERT_TRUE((gen(pos) == 0) || + (gen(pos) > initial_state.Get(key(pos))) + ) << "key: " << key(pos) + << "; gen: " << gen(pos) + << "; initgen: " + << initial_state.Get(key(pos)); + + // Advance to next key in the valid key space + if (key(pos) < key(current)) { + pos = MakeKey(key(pos) + 1, 0); + } else { + pos = MakeKey(key(pos), gen(pos) + 1); + } + } + + if (!iter.Valid()) { + break; + } + + if (rnd->Next() % 2) { + iter.Next(); + pos = MakeKey(key(pos), gen(pos) + 1); + } else { + Key new_target = RandomTarget(rnd); + if (new_target > pos) { + pos = new_target; + iter.Seek(new_target); + } + } + } + } +}; +const uint32_t ConcurrentTest::K; + +// Simple test that does single-threaded testing of the ConcurrentTest +// scaffolding. +TEST(SkipTest, ConcurrentWithoutThreads) { + ConcurrentTest test; + Random rnd(test::RandomSeed()); + for (int i = 0; i < 10000; i++) { + test.ReadStep(&rnd); + test.WriteStep(&rnd); + } +} + +class TestState { + public: + ConcurrentTest t_; + int seed_; + port::AtomicPointer quit_flag_; + + enum ReaderState { + STARTING, + RUNNING, + DONE + }; + + explicit TestState(int s) + : seed_(s), + quit_flag_(NULL), + state_(STARTING), + state_cv_(&mu_) {} + + void Wait(ReaderState s) { + mu_.Lock(); + while (state_ != s) { + state_cv_.Wait(); + } + mu_.Unlock(); + } + + void Change(ReaderState s) { + mu_.Lock(); + state_ = s; + state_cv_.Signal(); + mu_.Unlock(); + } + + private: + port::Mutex mu_; + ReaderState state_; + port::CondVar state_cv_; +}; + +static void ConcurrentReader(void* arg) { + TestState* state = reinterpret_cast(arg); + Random rnd(state->seed_); + int64_t reads = 0; + state->Change(TestState::RUNNING); + while (!state->quit_flag_.Acquire_Load()) { + state->t_.ReadStep(&rnd); + ++reads; + } + state->Change(TestState::DONE); +} + +static void RunConcurrent(int run) { + const int seed = test::RandomSeed() + (run * 100); + Random rnd(seed); + const int N = 1000; + const int kSize = 1000; + for (int i = 0; i < N; i++) { + if ((i % 100) == 0) { + fprintf(stderr, "Run %d of %d\n", i, N); + } + TestState state(seed + 1); + Env::Default()->Schedule(ConcurrentReader, &state); + state.Wait(TestState::RUNNING); + for (int i = 0; i < kSize; i++) { + state.t_.WriteStep(&rnd); + } + state.quit_flag_.Release_Store(&state); // Any non-NULL arg will do + state.Wait(TestState::DONE); + } +} + +TEST(SkipTest, Concurrent1) { RunConcurrent(1); } +TEST(SkipTest, Concurrent2) { RunConcurrent(2); } +TEST(SkipTest, Concurrent3) { RunConcurrent(3); } +TEST(SkipTest, Concurrent4) { RunConcurrent(4); } +TEST(SkipTest, Concurrent5) { RunConcurrent(5); } + +} // namespace leveldb + +int main(int argc, char** argv) { + return leveldb::test::RunAllTests(); +} diff --git a/ios/Pods/leveldb-library/db/snapshot.h b/ios/Pods/leveldb-library/db/snapshot.h new file mode 100644 index 000000000..e7f8fd2c3 --- /dev/null +++ b/ios/Pods/leveldb-library/db/snapshot.h @@ -0,0 +1,66 @@ +// Copyright (c) 2011 The LevelDB Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. See the AUTHORS file for names of contributors. + +#ifndef STORAGE_LEVELDB_DB_SNAPSHOT_H_ +#define STORAGE_LEVELDB_DB_SNAPSHOT_H_ + +#include "leveldb/db.h" + +namespace leveldb { + +class SnapshotList; + +// Snapshots are kept in a doubly-linked list in the DB. +// Each SnapshotImpl corresponds to a particular sequence number. +class SnapshotImpl : public Snapshot { + public: + SequenceNumber number_; // const after creation + + private: + friend class SnapshotList; + + // SnapshotImpl is kept in a doubly-linked circular list + SnapshotImpl* prev_; + SnapshotImpl* next_; + + SnapshotList* list_; // just for sanity checks +}; + +class SnapshotList { + public: + SnapshotList() { + list_.prev_ = &list_; + list_.next_ = &list_; + } + + bool empty() const { return list_.next_ == &list_; } + SnapshotImpl* oldest() const { assert(!empty()); return list_.next_; } + SnapshotImpl* newest() const { assert(!empty()); return list_.prev_; } + + const SnapshotImpl* New(SequenceNumber seq) { + SnapshotImpl* s = new SnapshotImpl; + s->number_ = seq; + s->list_ = this; + s->next_ = &list_; + s->prev_ = list_.prev_; + s->prev_->next_ = s; + s->next_->prev_ = s; + return s; + } + + void Delete(const SnapshotImpl* s) { + assert(s->list_ == this); + s->prev_->next_ = s->next_; + s->next_->prev_ = s->prev_; + delete s; + } + + private: + // Dummy head of doubly-linked list of snapshots + SnapshotImpl list_; +}; + +} // namespace leveldb + +#endif // STORAGE_LEVELDB_DB_SNAPSHOT_H_ diff --git a/ios/Pods/leveldb-library/db/table_cache.cc b/ios/Pods/leveldb-library/db/table_cache.cc new file mode 100644 index 000000000..e3d82cd3e --- /dev/null +++ b/ios/Pods/leveldb-library/db/table_cache.cc @@ -0,0 +1,127 @@ +// Copyright (c) 2011 The LevelDB Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. See the AUTHORS file for names of contributors. + +#include "db/table_cache.h" + +#include "db/filename.h" +#include "leveldb/env.h" +#include "leveldb/table.h" +#include "util/coding.h" + +namespace leveldb { + +struct TableAndFile { + RandomAccessFile* file; + Table* table; +}; + +static void DeleteEntry(const Slice& key, void* value) { + TableAndFile* tf = reinterpret_cast(value); + delete tf->table; + delete tf->file; + delete tf; +} + +static void UnrefEntry(void* arg1, void* arg2) { + Cache* cache = reinterpret_cast(arg1); + Cache::Handle* h = reinterpret_cast(arg2); + cache->Release(h); +} + +TableCache::TableCache(const std::string& dbname, + const Options* options, + int entries) + : env_(options->env), + dbname_(dbname), + options_(options), + cache_(NewLRUCache(entries)) { +} + +TableCache::~TableCache() { + delete cache_; +} + +Status TableCache::FindTable(uint64_t file_number, uint64_t file_size, + Cache::Handle** handle) { + Status s; + char buf[sizeof(file_number)]; + EncodeFixed64(buf, file_number); + Slice key(buf, sizeof(buf)); + *handle = cache_->Lookup(key); + if (*handle == NULL) { + std::string fname = TableFileName(dbname_, file_number); + RandomAccessFile* file = NULL; + Table* table = NULL; + s = env_->NewRandomAccessFile(fname, &file); + if (!s.ok()) { + std::string old_fname = SSTTableFileName(dbname_, file_number); + if (env_->NewRandomAccessFile(old_fname, &file).ok()) { + s = Status::OK(); + } + } + if (s.ok()) { + s = Table::Open(*options_, file, file_size, &table); + } + + if (!s.ok()) { + assert(table == NULL); + delete file; + // We do not cache error results so that if the error is transient, + // or somebody repairs the file, we recover automatically. + } else { + TableAndFile* tf = new TableAndFile; + tf->file = file; + tf->table = table; + *handle = cache_->Insert(key, tf, 1, &DeleteEntry); + } + } + return s; +} + +Iterator* TableCache::NewIterator(const ReadOptions& options, + uint64_t file_number, + uint64_t file_size, + Table** tableptr) { + if (tableptr != NULL) { + *tableptr = NULL; + } + + Cache::Handle* handle = NULL; + Status s = FindTable(file_number, file_size, &handle); + if (!s.ok()) { + return NewErrorIterator(s); + } + + Table* table = reinterpret_cast(cache_->Value(handle))->table; + Iterator* result = table->NewIterator(options); + result->RegisterCleanup(&UnrefEntry, cache_, handle); + if (tableptr != NULL) { + *tableptr = table; + } + return result; +} + +Status TableCache::Get(const ReadOptions& options, + uint64_t file_number, + uint64_t file_size, + const Slice& k, + void* arg, + void (*saver)(void*, const Slice&, const Slice&)) { + Cache::Handle* handle = NULL; + Status s = FindTable(file_number, file_size, &handle); + if (s.ok()) { + Table* t = reinterpret_cast(cache_->Value(handle))->table; + s = t->InternalGet(options, k, arg, saver); + cache_->Release(handle); + } + return s; +} + +void TableCache::Evict(uint64_t file_number) { + char buf[sizeof(file_number)]; + EncodeFixed64(buf, file_number); + cache_->Erase(Slice(buf, sizeof(buf))); +} + +} // namespace leveldb diff --git a/ios/Pods/leveldb-library/db/table_cache.h b/ios/Pods/leveldb-library/db/table_cache.h new file mode 100644 index 000000000..8cf4aaf12 --- /dev/null +++ b/ios/Pods/leveldb-library/db/table_cache.h @@ -0,0 +1,61 @@ +// Copyright (c) 2011 The LevelDB Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. See the AUTHORS file for names of contributors. +// +// Thread-safe (provides internal synchronization) + +#ifndef STORAGE_LEVELDB_DB_TABLE_CACHE_H_ +#define STORAGE_LEVELDB_DB_TABLE_CACHE_H_ + +#include +#include +#include "db/dbformat.h" +#include "leveldb/cache.h" +#include "leveldb/table.h" +#include "port/port.h" + +namespace leveldb { + +class Env; + +class TableCache { + public: + TableCache(const std::string& dbname, const Options* options, int entries); + ~TableCache(); + + // Return an iterator for the specified file number (the corresponding + // file length must be exactly "file_size" bytes). If "tableptr" is + // non-NULL, also sets "*tableptr" to point to the Table object + // underlying the returned iterator, or NULL if no Table object underlies + // the returned iterator. The returned "*tableptr" object is owned by + // the cache and should not be deleted, and is valid for as long as the + // returned iterator is live. + Iterator* NewIterator(const ReadOptions& options, + uint64_t file_number, + uint64_t file_size, + Table** tableptr = NULL); + + // If a seek to internal key "k" in specified file finds an entry, + // call (*handle_result)(arg, found_key, found_value). + Status Get(const ReadOptions& options, + uint64_t file_number, + uint64_t file_size, + const Slice& k, + void* arg, + void (*handle_result)(void*, const Slice&, const Slice&)); + + // Evict any entry for the specified file number + void Evict(uint64_t file_number); + + private: + Env* const env_; + const std::string dbname_; + const Options* options_; + Cache* cache_; + + Status FindTable(uint64_t file_number, uint64_t file_size, Cache::Handle**); +}; + +} // namespace leveldb + +#endif // STORAGE_LEVELDB_DB_TABLE_CACHE_H_ diff --git a/ios/Pods/leveldb-library/db/version_edit.cc b/ios/Pods/leveldb-library/db/version_edit.cc new file mode 100644 index 000000000..f10a2d58b --- /dev/null +++ b/ios/Pods/leveldb-library/db/version_edit.cc @@ -0,0 +1,266 @@ +// Copyright (c) 2011 The LevelDB Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. See the AUTHORS file for names of contributors. + +#include "db/version_edit.h" + +#include "db/version_set.h" +#include "util/coding.h" + +namespace leveldb { + +// Tag numbers for serialized VersionEdit. These numbers are written to +// disk and should not be changed. +enum Tag { + kComparator = 1, + kLogNumber = 2, + kNextFileNumber = 3, + kLastSequence = 4, + kCompactPointer = 5, + kDeletedFile = 6, + kNewFile = 7, + // 8 was used for large value refs + kPrevLogNumber = 9 +}; + +void VersionEdit::Clear() { + comparator_.clear(); + log_number_ = 0; + prev_log_number_ = 0; + last_sequence_ = 0; + next_file_number_ = 0; + has_comparator_ = false; + has_log_number_ = false; + has_prev_log_number_ = false; + has_next_file_number_ = false; + has_last_sequence_ = false; + deleted_files_.clear(); + new_files_.clear(); +} + +void VersionEdit::EncodeTo(std::string* dst) const { + if (has_comparator_) { + PutVarint32(dst, kComparator); + PutLengthPrefixedSlice(dst, comparator_); + } + if (has_log_number_) { + PutVarint32(dst, kLogNumber); + PutVarint64(dst, log_number_); + } + if (has_prev_log_number_) { + PutVarint32(dst, kPrevLogNumber); + PutVarint64(dst, prev_log_number_); + } + if (has_next_file_number_) { + PutVarint32(dst, kNextFileNumber); + PutVarint64(dst, next_file_number_); + } + if (has_last_sequence_) { + PutVarint32(dst, kLastSequence); + PutVarint64(dst, last_sequence_); + } + + for (size_t i = 0; i < compact_pointers_.size(); i++) { + PutVarint32(dst, kCompactPointer); + PutVarint32(dst, compact_pointers_[i].first); // level + PutLengthPrefixedSlice(dst, compact_pointers_[i].second.Encode()); + } + + for (DeletedFileSet::const_iterator iter = deleted_files_.begin(); + iter != deleted_files_.end(); + ++iter) { + PutVarint32(dst, kDeletedFile); + PutVarint32(dst, iter->first); // level + PutVarint64(dst, iter->second); // file number + } + + for (size_t i = 0; i < new_files_.size(); i++) { + const FileMetaData& f = new_files_[i].second; + PutVarint32(dst, kNewFile); + PutVarint32(dst, new_files_[i].first); // level + PutVarint64(dst, f.number); + PutVarint64(dst, f.file_size); + PutLengthPrefixedSlice(dst, f.smallest.Encode()); + PutLengthPrefixedSlice(dst, f.largest.Encode()); + } +} + +static bool GetInternalKey(Slice* input, InternalKey* dst) { + Slice str; + if (GetLengthPrefixedSlice(input, &str)) { + dst->DecodeFrom(str); + return true; + } else { + return false; + } +} + +static bool GetLevel(Slice* input, int* level) { + uint32_t v; + if (GetVarint32(input, &v) && + v < config::kNumLevels) { + *level = v; + return true; + } else { + return false; + } +} + +Status VersionEdit::DecodeFrom(const Slice& src) { + Clear(); + Slice input = src; + const char* msg = NULL; + uint32_t tag; + + // Temporary storage for parsing + int level; + uint64_t number; + FileMetaData f; + Slice str; + InternalKey key; + + while (msg == NULL && GetVarint32(&input, &tag)) { + switch (tag) { + case kComparator: + if (GetLengthPrefixedSlice(&input, &str)) { + comparator_ = str.ToString(); + has_comparator_ = true; + } else { + msg = "comparator name"; + } + break; + + case kLogNumber: + if (GetVarint64(&input, &log_number_)) { + has_log_number_ = true; + } else { + msg = "log number"; + } + break; + + case kPrevLogNumber: + if (GetVarint64(&input, &prev_log_number_)) { + has_prev_log_number_ = true; + } else { + msg = "previous log number"; + } + break; + + case kNextFileNumber: + if (GetVarint64(&input, &next_file_number_)) { + has_next_file_number_ = true; + } else { + msg = "next file number"; + } + break; + + case kLastSequence: + if (GetVarint64(&input, &last_sequence_)) { + has_last_sequence_ = true; + } else { + msg = "last sequence number"; + } + break; + + case kCompactPointer: + if (GetLevel(&input, &level) && + GetInternalKey(&input, &key)) { + compact_pointers_.push_back(std::make_pair(level, key)); + } else { + msg = "compaction pointer"; + } + break; + + case kDeletedFile: + if (GetLevel(&input, &level) && + GetVarint64(&input, &number)) { + deleted_files_.insert(std::make_pair(level, number)); + } else { + msg = "deleted file"; + } + break; + + case kNewFile: + if (GetLevel(&input, &level) && + GetVarint64(&input, &f.number) && + GetVarint64(&input, &f.file_size) && + GetInternalKey(&input, &f.smallest) && + GetInternalKey(&input, &f.largest)) { + new_files_.push_back(std::make_pair(level, f)); + } else { + msg = "new-file entry"; + } + break; + + default: + msg = "unknown tag"; + break; + } + } + + if (msg == NULL && !input.empty()) { + msg = "invalid tag"; + } + + Status result; + if (msg != NULL) { + result = Status::Corruption("VersionEdit", msg); + } + return result; +} + +std::string VersionEdit::DebugString() const { + std::string r; + r.append("VersionEdit {"); + if (has_comparator_) { + r.append("\n Comparator: "); + r.append(comparator_); + } + if (has_log_number_) { + r.append("\n LogNumber: "); + AppendNumberTo(&r, log_number_); + } + if (has_prev_log_number_) { + r.append("\n PrevLogNumber: "); + AppendNumberTo(&r, prev_log_number_); + } + if (has_next_file_number_) { + r.append("\n NextFile: "); + AppendNumberTo(&r, next_file_number_); + } + if (has_last_sequence_) { + r.append("\n LastSeq: "); + AppendNumberTo(&r, last_sequence_); + } + for (size_t i = 0; i < compact_pointers_.size(); i++) { + r.append("\n CompactPointer: "); + AppendNumberTo(&r, compact_pointers_[i].first); + r.append(" "); + r.append(compact_pointers_[i].second.DebugString()); + } + for (DeletedFileSet::const_iterator iter = deleted_files_.begin(); + iter != deleted_files_.end(); + ++iter) { + r.append("\n DeleteFile: "); + AppendNumberTo(&r, iter->first); + r.append(" "); + AppendNumberTo(&r, iter->second); + } + for (size_t i = 0; i < new_files_.size(); i++) { + const FileMetaData& f = new_files_[i].second; + r.append("\n AddFile: "); + AppendNumberTo(&r, new_files_[i].first); + r.append(" "); + AppendNumberTo(&r, f.number); + r.append(" "); + AppendNumberTo(&r, f.file_size); + r.append(" "); + r.append(f.smallest.DebugString()); + r.append(" .. "); + r.append(f.largest.DebugString()); + } + r.append("\n}\n"); + return r; +} + +} // namespace leveldb diff --git a/ios/Pods/leveldb-library/db/version_edit.h b/ios/Pods/leveldb-library/db/version_edit.h new file mode 100644 index 000000000..eaef77b32 --- /dev/null +++ b/ios/Pods/leveldb-library/db/version_edit.h @@ -0,0 +1,107 @@ +// Copyright (c) 2011 The LevelDB Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. See the AUTHORS file for names of contributors. + +#ifndef STORAGE_LEVELDB_DB_VERSION_EDIT_H_ +#define STORAGE_LEVELDB_DB_VERSION_EDIT_H_ + +#include +#include +#include +#include "db/dbformat.h" + +namespace leveldb { + +class VersionSet; + +struct FileMetaData { + int refs; + int allowed_seeks; // Seeks allowed until compaction + uint64_t number; + uint64_t file_size; // File size in bytes + InternalKey smallest; // Smallest internal key served by table + InternalKey largest; // Largest internal key served by table + + FileMetaData() : refs(0), allowed_seeks(1 << 30), file_size(0) { } +}; + +class VersionEdit { + public: + VersionEdit() { Clear(); } + ~VersionEdit() { } + + void Clear(); + + void SetComparatorName(const Slice& name) { + has_comparator_ = true; + comparator_ = name.ToString(); + } + void SetLogNumber(uint64_t num) { + has_log_number_ = true; + log_number_ = num; + } + void SetPrevLogNumber(uint64_t num) { + has_prev_log_number_ = true; + prev_log_number_ = num; + } + void SetNextFile(uint64_t num) { + has_next_file_number_ = true; + next_file_number_ = num; + } + void SetLastSequence(SequenceNumber seq) { + has_last_sequence_ = true; + last_sequence_ = seq; + } + void SetCompactPointer(int level, const InternalKey& key) { + compact_pointers_.push_back(std::make_pair(level, key)); + } + + // Add the specified file at the specified number. + // REQUIRES: This version has not been saved (see VersionSet::SaveTo) + // REQUIRES: "smallest" and "largest" are smallest and largest keys in file + void AddFile(int level, uint64_t file, + uint64_t file_size, + const InternalKey& smallest, + const InternalKey& largest) { + FileMetaData f; + f.number = file; + f.file_size = file_size; + f.smallest = smallest; + f.largest = largest; + new_files_.push_back(std::make_pair(level, f)); + } + + // Delete the specified "file" from the specified "level". + void DeleteFile(int level, uint64_t file) { + deleted_files_.insert(std::make_pair(level, file)); + } + + void EncodeTo(std::string* dst) const; + Status DecodeFrom(const Slice& src); + + std::string DebugString() const; + + private: + friend class VersionSet; + + typedef std::set< std::pair > DeletedFileSet; + + std::string comparator_; + uint64_t log_number_; + uint64_t prev_log_number_; + uint64_t next_file_number_; + SequenceNumber last_sequence_; + bool has_comparator_; + bool has_log_number_; + bool has_prev_log_number_; + bool has_next_file_number_; + bool has_last_sequence_; + + std::vector< std::pair > compact_pointers_; + DeletedFileSet deleted_files_; + std::vector< std::pair > new_files_; +}; + +} // namespace leveldb + +#endif // STORAGE_LEVELDB_DB_VERSION_EDIT_H_ diff --git a/ios/Pods/leveldb-library/db/version_edit_test.cc b/ios/Pods/leveldb-library/db/version_edit_test.cc new file mode 100644 index 000000000..280310b49 --- /dev/null +++ b/ios/Pods/leveldb-library/db/version_edit_test.cc @@ -0,0 +1,46 @@ +// Copyright (c) 2011 The LevelDB Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. See the AUTHORS file for names of contributors. + +#include "db/version_edit.h" +#include "util/testharness.h" + +namespace leveldb { + +static void TestEncodeDecode(const VersionEdit& edit) { + std::string encoded, encoded2; + edit.EncodeTo(&encoded); + VersionEdit parsed; + Status s = parsed.DecodeFrom(encoded); + ASSERT_TRUE(s.ok()) << s.ToString(); + parsed.EncodeTo(&encoded2); + ASSERT_EQ(encoded, encoded2); +} + +class VersionEditTest { }; + +TEST(VersionEditTest, EncodeDecode) { + static const uint64_t kBig = 1ull << 50; + + VersionEdit edit; + for (int i = 0; i < 4; i++) { + TestEncodeDecode(edit); + edit.AddFile(3, kBig + 300 + i, kBig + 400 + i, + InternalKey("foo", kBig + 500 + i, kTypeValue), + InternalKey("zoo", kBig + 600 + i, kTypeDeletion)); + edit.DeleteFile(4, kBig + 700 + i); + edit.SetCompactPointer(i, InternalKey("x", kBig + 900 + i, kTypeValue)); + } + + edit.SetComparatorName("foo"); + edit.SetLogNumber(kBig + 100); + edit.SetNextFile(kBig + 200); + edit.SetLastSequence(kBig + 1000); + TestEncodeDecode(edit); +} + +} // namespace leveldb + +int main(int argc, char** argv) { + return leveldb::test::RunAllTests(); +} diff --git a/ios/Pods/leveldb-library/db/version_set.cc b/ios/Pods/leveldb-library/db/version_set.cc new file mode 100644 index 000000000..aa83df55e --- /dev/null +++ b/ios/Pods/leveldb-library/db/version_set.cc @@ -0,0 +1,1484 @@ +// Copyright (c) 2011 The LevelDB Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. See the AUTHORS file for names of contributors. + +#include "db/version_set.h" + +#include +#include +#include "db/filename.h" +#include "db/log_reader.h" +#include "db/log_writer.h" +#include "db/memtable.h" +#include "db/table_cache.h" +#include "leveldb/env.h" +#include "leveldb/table_builder.h" +#include "table/merger.h" +#include "table/two_level_iterator.h" +#include "util/coding.h" +#include "util/logging.h" + +namespace leveldb { + +static const int kTargetFileSize = 2 * 1048576; + +// Maximum bytes of overlaps in grandparent (i.e., level+2) before we +// stop building a single file in a level->level+1 compaction. +static const int64_t kMaxGrandParentOverlapBytes = 10 * kTargetFileSize; + +// Maximum number of bytes in all compacted files. We avoid expanding +// the lower level file set of a compaction if it would make the +// total compaction cover more than this many bytes. +static const int64_t kExpandedCompactionByteSizeLimit = 25 * kTargetFileSize; + +static double MaxBytesForLevel(int level) { + // Note: the result for level zero is not really used since we set + // the level-0 compaction threshold based on number of files. + double result = 10 * 1048576.0; // Result for both level-0 and level-1 + while (level > 1) { + result *= 10; + level--; + } + return result; +} + +static uint64_t MaxFileSizeForLevel(int level) { + return kTargetFileSize; // We could vary per level to reduce number of files? +} + +static int64_t TotalFileSize(const std::vector& files) { + int64_t sum = 0; + for (size_t i = 0; i < files.size(); i++) { + sum += files[i]->file_size; + } + return sum; +} + +Version::~Version() { + assert(refs_ == 0); + + // Remove from linked list + prev_->next_ = next_; + next_->prev_ = prev_; + + // Drop references to files + for (int level = 0; level < config::kNumLevels; level++) { + for (size_t i = 0; i < files_[level].size(); i++) { + FileMetaData* f = files_[level][i]; + assert(f->refs > 0); + f->refs--; + if (f->refs <= 0) { + delete f; + } + } + } +} + +int FindFile(const InternalKeyComparator& icmp, + const std::vector& files, + const Slice& key) { + uint32_t left = 0; + uint32_t right = files.size(); + while (left < right) { + uint32_t mid = (left + right) / 2; + const FileMetaData* f = files[mid]; + if (icmp.InternalKeyComparator::Compare(f->largest.Encode(), key) < 0) { + // Key at "mid.largest" is < "target". Therefore all + // files at or before "mid" are uninteresting. + left = mid + 1; + } else { + // Key at "mid.largest" is >= "target". Therefore all files + // after "mid" are uninteresting. + right = mid; + } + } + return right; +} + +static bool AfterFile(const Comparator* ucmp, + const Slice* user_key, const FileMetaData* f) { + // NULL user_key occurs before all keys and is therefore never after *f + return (user_key != NULL && + ucmp->Compare(*user_key, f->largest.user_key()) > 0); +} + +static bool BeforeFile(const Comparator* ucmp, + const Slice* user_key, const FileMetaData* f) { + // NULL user_key occurs after all keys and is therefore never before *f + return (user_key != NULL && + ucmp->Compare(*user_key, f->smallest.user_key()) < 0); +} + +bool SomeFileOverlapsRange( + const InternalKeyComparator& icmp, + bool disjoint_sorted_files, + const std::vector& files, + const Slice* smallest_user_key, + const Slice* largest_user_key) { + const Comparator* ucmp = icmp.user_comparator(); + if (!disjoint_sorted_files) { + // Need to check against all files + for (size_t i = 0; i < files.size(); i++) { + const FileMetaData* f = files[i]; + if (AfterFile(ucmp, smallest_user_key, f) || + BeforeFile(ucmp, largest_user_key, f)) { + // No overlap + } else { + return true; // Overlap + } + } + return false; + } + + // Binary search over file list + uint32_t index = 0; + if (smallest_user_key != NULL) { + // Find the earliest possible internal key for smallest_user_key + InternalKey small(*smallest_user_key, kMaxSequenceNumber,kValueTypeForSeek); + index = FindFile(icmp, files, small.Encode()); + } + + if (index >= files.size()) { + // beginning of range is after all files, so no overlap. + return false; + } + + return !BeforeFile(ucmp, largest_user_key, files[index]); +} + +// An internal iterator. For a given version/level pair, yields +// information about the files in the level. For a given entry, key() +// is the largest key that occurs in the file, and value() is an +// 16-byte value containing the file number and file size, both +// encoded using EncodeFixed64. +class Version::LevelFileNumIterator : public Iterator { + public: + LevelFileNumIterator(const InternalKeyComparator& icmp, + const std::vector* flist) + : icmp_(icmp), + flist_(flist), + index_(flist->size()) { // Marks as invalid + } + virtual bool Valid() const { + return index_ < flist_->size(); + } + virtual void Seek(const Slice& target) { + index_ = FindFile(icmp_, *flist_, target); + } + virtual void SeekToFirst() { index_ = 0; } + virtual void SeekToLast() { + index_ = flist_->empty() ? 0 : flist_->size() - 1; + } + virtual void Next() { + assert(Valid()); + index_++; + } + virtual void Prev() { + assert(Valid()); + if (index_ == 0) { + index_ = flist_->size(); // Marks as invalid + } else { + index_--; + } + } + Slice key() const { + assert(Valid()); + return (*flist_)[index_]->largest.Encode(); + } + Slice value() const { + assert(Valid()); + EncodeFixed64(value_buf_, (*flist_)[index_]->number); + EncodeFixed64(value_buf_+8, (*flist_)[index_]->file_size); + return Slice(value_buf_, sizeof(value_buf_)); + } + virtual Status status() const { return Status::OK(); } + private: + const InternalKeyComparator icmp_; + const std::vector* const flist_; + uint32_t index_; + + // Backing store for value(). Holds the file number and size. + mutable char value_buf_[16]; +}; + +static Iterator* GetFileIterator(void* arg, + const ReadOptions& options, + const Slice& file_value) { + TableCache* cache = reinterpret_cast(arg); + if (file_value.size() != 16) { + return NewErrorIterator( + Status::Corruption("FileReader invoked with unexpected value")); + } else { + return cache->NewIterator(options, + DecodeFixed64(file_value.data()), + DecodeFixed64(file_value.data() + 8)); + } +} + +Iterator* Version::NewConcatenatingIterator(const ReadOptions& options, + int level) const { + return NewTwoLevelIterator( + new LevelFileNumIterator(vset_->icmp_, &files_[level]), + &GetFileIterator, vset_->table_cache_, options); +} + +void Version::AddIterators(const ReadOptions& options, + std::vector* iters) { + // Merge all level zero files together since they may overlap + for (size_t i = 0; i < files_[0].size(); i++) { + iters->push_back( + vset_->table_cache_->NewIterator( + options, files_[0][i]->number, files_[0][i]->file_size)); + } + + // For levels > 0, we can use a concatenating iterator that sequentially + // walks through the non-overlapping files in the level, opening them + // lazily. + for (int level = 1; level < config::kNumLevels; level++) { + if (!files_[level].empty()) { + iters->push_back(NewConcatenatingIterator(options, level)); + } + } +} + +// Callback from TableCache::Get() +namespace { +enum SaverState { + kNotFound, + kFound, + kDeleted, + kCorrupt, +}; +struct Saver { + SaverState state; + const Comparator* ucmp; + Slice user_key; + std::string* value; +}; +} +static void SaveValue(void* arg, const Slice& ikey, const Slice& v) { + Saver* s = reinterpret_cast(arg); + ParsedInternalKey parsed_key; + if (!ParseInternalKey(ikey, &parsed_key)) { + s->state = kCorrupt; + } else { + if (s->ucmp->Compare(parsed_key.user_key, s->user_key) == 0) { + s->state = (parsed_key.type == kTypeValue) ? kFound : kDeleted; + if (s->state == kFound) { + s->value->assign(v.data(), v.size()); + } + } + } +} + +static bool NewestFirst(FileMetaData* a, FileMetaData* b) { + return a->number > b->number; +} + +void Version::ForEachOverlapping(Slice user_key, Slice internal_key, + void* arg, + bool (*func)(void*, int, FileMetaData*)) { + // TODO(sanjay): Change Version::Get() to use this function. + const Comparator* ucmp = vset_->icmp_.user_comparator(); + + // Search level-0 in order from newest to oldest. + std::vector tmp; + tmp.reserve(files_[0].size()); + for (uint32_t i = 0; i < files_[0].size(); i++) { + FileMetaData* f = files_[0][i]; + if (ucmp->Compare(user_key, f->smallest.user_key()) >= 0 && + ucmp->Compare(user_key, f->largest.user_key()) <= 0) { + tmp.push_back(f); + } + } + if (!tmp.empty()) { + std::sort(tmp.begin(), tmp.end(), NewestFirst); + for (uint32_t i = 0; i < tmp.size(); i++) { + if (!(*func)(arg, 0, tmp[i])) { + return; + } + } + } + + // Search other levels. + for (int level = 1; level < config::kNumLevels; level++) { + size_t num_files = files_[level].size(); + if (num_files == 0) continue; + + // Binary search to find earliest index whose largest key >= internal_key. + uint32_t index = FindFile(vset_->icmp_, files_[level], internal_key); + if (index < num_files) { + FileMetaData* f = files_[level][index]; + if (ucmp->Compare(user_key, f->smallest.user_key()) < 0) { + // All of "f" is past any data for user_key + } else { + if (!(*func)(arg, level, f)) { + return; + } + } + } + } +} + +Status Version::Get(const ReadOptions& options, + const LookupKey& k, + std::string* value, + GetStats* stats) { + Slice ikey = k.internal_key(); + Slice user_key = k.user_key(); + const Comparator* ucmp = vset_->icmp_.user_comparator(); + Status s; + + stats->seek_file = NULL; + stats->seek_file_level = -1; + FileMetaData* last_file_read = NULL; + int last_file_read_level = -1; + + // We can search level-by-level since entries never hop across + // levels. Therefore we are guaranteed that if we find data + // in an smaller level, later levels are irrelevant. + std::vector tmp; + FileMetaData* tmp2; + for (int level = 0; level < config::kNumLevels; level++) { + size_t num_files = files_[level].size(); + if (num_files == 0) continue; + + // Get the list of files to search in this level + FileMetaData* const* files = &files_[level][0]; + if (level == 0) { + // Level-0 files may overlap each other. Find all files that + // overlap user_key and process them in order from newest to oldest. + tmp.reserve(num_files); + for (uint32_t i = 0; i < num_files; i++) { + FileMetaData* f = files[i]; + if (ucmp->Compare(user_key, f->smallest.user_key()) >= 0 && + ucmp->Compare(user_key, f->largest.user_key()) <= 0) { + tmp.push_back(f); + } + } + if (tmp.empty()) continue; + + std::sort(tmp.begin(), tmp.end(), NewestFirst); + files = &tmp[0]; + num_files = tmp.size(); + } else { + // Binary search to find earliest index whose largest key >= ikey. + uint32_t index = FindFile(vset_->icmp_, files_[level], ikey); + if (index >= num_files) { + files = NULL; + num_files = 0; + } else { + tmp2 = files[index]; + if (ucmp->Compare(user_key, tmp2->smallest.user_key()) < 0) { + // All of "tmp2" is past any data for user_key + files = NULL; + num_files = 0; + } else { + files = &tmp2; + num_files = 1; + } + } + } + + for (uint32_t i = 0; i < num_files; ++i) { + if (last_file_read != NULL && stats->seek_file == NULL) { + // We have had more than one seek for this read. Charge the 1st file. + stats->seek_file = last_file_read; + stats->seek_file_level = last_file_read_level; + } + + FileMetaData* f = files[i]; + last_file_read = f; + last_file_read_level = level; + + Saver saver; + saver.state = kNotFound; + saver.ucmp = ucmp; + saver.user_key = user_key; + saver.value = value; + s = vset_->table_cache_->Get(options, f->number, f->file_size, + ikey, &saver, SaveValue); + if (!s.ok()) { + return s; + } + switch (saver.state) { + case kNotFound: + break; // Keep searching in other files + case kFound: + return s; + case kDeleted: + s = Status::NotFound(Slice()); // Use empty error message for speed + return s; + case kCorrupt: + s = Status::Corruption("corrupted key for ", user_key); + return s; + } + } + } + + return Status::NotFound(Slice()); // Use an empty error message for speed +} + +bool Version::UpdateStats(const GetStats& stats) { + FileMetaData* f = stats.seek_file; + if (f != NULL) { + f->allowed_seeks--; + if (f->allowed_seeks <= 0 && file_to_compact_ == NULL) { + file_to_compact_ = f; + file_to_compact_level_ = stats.seek_file_level; + return true; + } + } + return false; +} + +bool Version::RecordReadSample(Slice internal_key) { + ParsedInternalKey ikey; + if (!ParseInternalKey(internal_key, &ikey)) { + return false; + } + + struct State { + GetStats stats; // Holds first matching file + int matches; + + static bool Match(void* arg, int level, FileMetaData* f) { + State* state = reinterpret_cast(arg); + state->matches++; + if (state->matches == 1) { + // Remember first match. + state->stats.seek_file = f; + state->stats.seek_file_level = level; + } + // We can stop iterating once we have a second match. + return state->matches < 2; + } + }; + + State state; + state.matches = 0; + ForEachOverlapping(ikey.user_key, internal_key, &state, &State::Match); + + // Must have at least two matches since we want to merge across + // files. But what if we have a single file that contains many + // overwrites and deletions? Should we have another mechanism for + // finding such files? + if (state.matches >= 2) { + // 1MB cost is about 1 seek (see comment in Builder::Apply). + return UpdateStats(state.stats); + } + return false; +} + +void Version::Ref() { + ++refs_; +} + +void Version::Unref() { + assert(this != &vset_->dummy_versions_); + assert(refs_ >= 1); + --refs_; + if (refs_ == 0) { + delete this; + } +} + +bool Version::OverlapInLevel(int level, + const Slice* smallest_user_key, + const Slice* largest_user_key) { + return SomeFileOverlapsRange(vset_->icmp_, (level > 0), files_[level], + smallest_user_key, largest_user_key); +} + +int Version::PickLevelForMemTableOutput( + const Slice& smallest_user_key, + const Slice& largest_user_key) { + int level = 0; + if (!OverlapInLevel(0, &smallest_user_key, &largest_user_key)) { + // Push to next level if there is no overlap in next level, + // and the #bytes overlapping in the level after that are limited. + InternalKey start(smallest_user_key, kMaxSequenceNumber, kValueTypeForSeek); + InternalKey limit(largest_user_key, 0, static_cast(0)); + std::vector overlaps; + while (level < config::kMaxMemCompactLevel) { + if (OverlapInLevel(level + 1, &smallest_user_key, &largest_user_key)) { + break; + } + if (level + 2 < config::kNumLevels) { + // Check that file does not overlap too many grandparent bytes. + GetOverlappingInputs(level + 2, &start, &limit, &overlaps); + const int64_t sum = TotalFileSize(overlaps); + if (sum > kMaxGrandParentOverlapBytes) { + break; + } + } + level++; + } + } + return level; +} + +// Store in "*inputs" all files in "level" that overlap [begin,end] +void Version::GetOverlappingInputs( + int level, + const InternalKey* begin, + const InternalKey* end, + std::vector* inputs) { + assert(level >= 0); + assert(level < config::kNumLevels); + inputs->clear(); + Slice user_begin, user_end; + if (begin != NULL) { + user_begin = begin->user_key(); + } + if (end != NULL) { + user_end = end->user_key(); + } + const Comparator* user_cmp = vset_->icmp_.user_comparator(); + for (size_t i = 0; i < files_[level].size(); ) { + FileMetaData* f = files_[level][i++]; + const Slice file_start = f->smallest.user_key(); + const Slice file_limit = f->largest.user_key(); + if (begin != NULL && user_cmp->Compare(file_limit, user_begin) < 0) { + // "f" is completely before specified range; skip it + } else if (end != NULL && user_cmp->Compare(file_start, user_end) > 0) { + // "f" is completely after specified range; skip it + } else { + inputs->push_back(f); + if (level == 0) { + // Level-0 files may overlap each other. So check if the newly + // added file has expanded the range. If so, restart search. + if (begin != NULL && user_cmp->Compare(file_start, user_begin) < 0) { + user_begin = file_start; + inputs->clear(); + i = 0; + } else if (end != NULL && user_cmp->Compare(file_limit, user_end) > 0) { + user_end = file_limit; + inputs->clear(); + i = 0; + } + } + } + } +} + +std::string Version::DebugString() const { + std::string r; + for (int level = 0; level < config::kNumLevels; level++) { + // E.g., + // --- level 1 --- + // 17:123['a' .. 'd'] + // 20:43['e' .. 'g'] + r.append("--- level "); + AppendNumberTo(&r, level); + r.append(" ---\n"); + const std::vector& files = files_[level]; + for (size_t i = 0; i < files.size(); i++) { + r.push_back(' '); + AppendNumberTo(&r, files[i]->number); + r.push_back(':'); + AppendNumberTo(&r, files[i]->file_size); + r.append("["); + r.append(files[i]->smallest.DebugString()); + r.append(" .. "); + r.append(files[i]->largest.DebugString()); + r.append("]\n"); + } + } + return r; +} + +// A helper class so we can efficiently apply a whole sequence +// of edits to a particular state without creating intermediate +// Versions that contain full copies of the intermediate state. +class VersionSet::Builder { + private: + // Helper to sort by v->files_[file_number].smallest + struct BySmallestKey { + const InternalKeyComparator* internal_comparator; + + bool operator()(FileMetaData* f1, FileMetaData* f2) const { + int r = internal_comparator->Compare(f1->smallest, f2->smallest); + if (r != 0) { + return (r < 0); + } else { + // Break ties by file number + return (f1->number < f2->number); + } + } + }; + + typedef std::set FileSet; + struct LevelState { + std::set deleted_files; + FileSet* added_files; + }; + + VersionSet* vset_; + Version* base_; + LevelState levels_[config::kNumLevels]; + + public: + // Initialize a builder with the files from *base and other info from *vset + Builder(VersionSet* vset, Version* base) + : vset_(vset), + base_(base) { + base_->Ref(); + BySmallestKey cmp; + cmp.internal_comparator = &vset_->icmp_; + for (int level = 0; level < config::kNumLevels; level++) { + levels_[level].added_files = new FileSet(cmp); + } + } + + ~Builder() { + for (int level = 0; level < config::kNumLevels; level++) { + const FileSet* added = levels_[level].added_files; + std::vector to_unref; + to_unref.reserve(added->size()); + for (FileSet::const_iterator it = added->begin(); + it != added->end(); ++it) { + to_unref.push_back(*it); + } + delete added; + for (uint32_t i = 0; i < to_unref.size(); i++) { + FileMetaData* f = to_unref[i]; + f->refs--; + if (f->refs <= 0) { + delete f; + } + } + } + base_->Unref(); + } + + // Apply all of the edits in *edit to the current state. + void Apply(VersionEdit* edit) { + // Update compaction pointers + for (size_t i = 0; i < edit->compact_pointers_.size(); i++) { + const int level = edit->compact_pointers_[i].first; + vset_->compact_pointer_[level] = + edit->compact_pointers_[i].second.Encode().ToString(); + } + + // Delete files + const VersionEdit::DeletedFileSet& del = edit->deleted_files_; + for (VersionEdit::DeletedFileSet::const_iterator iter = del.begin(); + iter != del.end(); + ++iter) { + const int level = iter->first; + const uint64_t number = iter->second; + levels_[level].deleted_files.insert(number); + } + + // Add new files + for (size_t i = 0; i < edit->new_files_.size(); i++) { + const int level = edit->new_files_[i].first; + FileMetaData* f = new FileMetaData(edit->new_files_[i].second); + f->refs = 1; + + // We arrange to automatically compact this file after + // a certain number of seeks. Let's assume: + // (1) One seek costs 10ms + // (2) Writing or reading 1MB costs 10ms (100MB/s) + // (3) A compaction of 1MB does 25MB of IO: + // 1MB read from this level + // 10-12MB read from next level (boundaries may be misaligned) + // 10-12MB written to next level + // This implies that 25 seeks cost the same as the compaction + // of 1MB of data. I.e., one seek costs approximately the + // same as the compaction of 40KB of data. We are a little + // conservative and allow approximately one seek for every 16KB + // of data before triggering a compaction. + f->allowed_seeks = (f->file_size / 16384); + if (f->allowed_seeks < 100) f->allowed_seeks = 100; + + levels_[level].deleted_files.erase(f->number); + levels_[level].added_files->insert(f); + } + } + + // Save the current state in *v. + void SaveTo(Version* v) { + BySmallestKey cmp; + cmp.internal_comparator = &vset_->icmp_; + for (int level = 0; level < config::kNumLevels; level++) { + // Merge the set of added files with the set of pre-existing files. + // Drop any deleted files. Store the result in *v. + const std::vector& base_files = base_->files_[level]; + std::vector::const_iterator base_iter = base_files.begin(); + std::vector::const_iterator base_end = base_files.end(); + const FileSet* added = levels_[level].added_files; + v->files_[level].reserve(base_files.size() + added->size()); + for (FileSet::const_iterator added_iter = added->begin(); + added_iter != added->end(); + ++added_iter) { + // Add all smaller files listed in base_ + for (std::vector::const_iterator bpos + = std::upper_bound(base_iter, base_end, *added_iter, cmp); + base_iter != bpos; + ++base_iter) { + MaybeAddFile(v, level, *base_iter); + } + + MaybeAddFile(v, level, *added_iter); + } + + // Add remaining base files + for (; base_iter != base_end; ++base_iter) { + MaybeAddFile(v, level, *base_iter); + } + +#ifndef NDEBUG + // Make sure there is no overlap in levels > 0 + if (level > 0) { + for (uint32_t i = 1; i < v->files_[level].size(); i++) { + const InternalKey& prev_end = v->files_[level][i-1]->largest; + const InternalKey& this_begin = v->files_[level][i]->smallest; + if (vset_->icmp_.Compare(prev_end, this_begin) >= 0) { + fprintf(stderr, "overlapping ranges in same level %s vs. %s\n", + prev_end.DebugString().c_str(), + this_begin.DebugString().c_str()); + abort(); + } + } + } +#endif + } + } + + void MaybeAddFile(Version* v, int level, FileMetaData* f) { + if (levels_[level].deleted_files.count(f->number) > 0) { + // File is deleted: do nothing + } else { + std::vector* files = &v->files_[level]; + if (level > 0 && !files->empty()) { + // Must not overlap + assert(vset_->icmp_.Compare((*files)[files->size()-1]->largest, + f->smallest) < 0); + } + f->refs++; + files->push_back(f); + } + } +}; + +VersionSet::VersionSet(const std::string& dbname, + const Options* options, + TableCache* table_cache, + const InternalKeyComparator* cmp) + : env_(options->env), + dbname_(dbname), + options_(options), + table_cache_(table_cache), + icmp_(*cmp), + next_file_number_(2), + manifest_file_number_(0), // Filled by Recover() + last_sequence_(0), + log_number_(0), + prev_log_number_(0), + descriptor_file_(NULL), + descriptor_log_(NULL), + dummy_versions_(this), + current_(NULL) { + AppendVersion(new Version(this)); +} + +VersionSet::~VersionSet() { + current_->Unref(); + assert(dummy_versions_.next_ == &dummy_versions_); // List must be empty + delete descriptor_log_; + delete descriptor_file_; +} + +void VersionSet::AppendVersion(Version* v) { + // Make "v" current + assert(v->refs_ == 0); + assert(v != current_); + if (current_ != NULL) { + current_->Unref(); + } + current_ = v; + v->Ref(); + + // Append to linked list + v->prev_ = dummy_versions_.prev_; + v->next_ = &dummy_versions_; + v->prev_->next_ = v; + v->next_->prev_ = v; +} + +Status VersionSet::LogAndApply(VersionEdit* edit, port::Mutex* mu) { + if (edit->has_log_number_) { + assert(edit->log_number_ >= log_number_); + assert(edit->log_number_ < next_file_number_); + } else { + edit->SetLogNumber(log_number_); + } + + if (!edit->has_prev_log_number_) { + edit->SetPrevLogNumber(prev_log_number_); + } + + edit->SetNextFile(next_file_number_); + edit->SetLastSequence(last_sequence_); + + Version* v = new Version(this); + { + Builder builder(this, current_); + builder.Apply(edit); + builder.SaveTo(v); + } + Finalize(v); + + // Initialize new descriptor log file if necessary by creating + // a temporary file that contains a snapshot of the current version. + std::string new_manifest_file; + Status s; + if (descriptor_log_ == NULL) { + // No reason to unlock *mu here since we only hit this path in the + // first call to LogAndApply (when opening the database). + assert(descriptor_file_ == NULL); + new_manifest_file = DescriptorFileName(dbname_, manifest_file_number_); + edit->SetNextFile(next_file_number_); + s = env_->NewWritableFile(new_manifest_file, &descriptor_file_); + if (s.ok()) { + descriptor_log_ = new log::Writer(descriptor_file_); + s = WriteSnapshot(descriptor_log_); + } + } + + // Unlock during expensive MANIFEST log write + { + mu->Unlock(); + + // Write new record to MANIFEST log + if (s.ok()) { + std::string record; + edit->EncodeTo(&record); + s = descriptor_log_->AddRecord(record); + if (s.ok()) { + s = descriptor_file_->Sync(); + } + if (!s.ok()) { + Log(options_->info_log, "MANIFEST write: %s\n", s.ToString().c_str()); + } + } + + // If we just created a new descriptor file, install it by writing a + // new CURRENT file that points to it. + if (s.ok() && !new_manifest_file.empty()) { + s = SetCurrentFile(env_, dbname_, manifest_file_number_); + } + + mu->Lock(); + } + + // Install the new version + if (s.ok()) { + AppendVersion(v); + log_number_ = edit->log_number_; + prev_log_number_ = edit->prev_log_number_; + } else { + delete v; + if (!new_manifest_file.empty()) { + delete descriptor_log_; + delete descriptor_file_; + descriptor_log_ = NULL; + descriptor_file_ = NULL; + env_->DeleteFile(new_manifest_file); + } + } + + return s; +} + +Status VersionSet::Recover() { + struct LogReporter : public log::Reader::Reporter { + Status* status; + virtual void Corruption(size_t bytes, const Status& s) { + if (this->status->ok()) *this->status = s; + } + }; + + // Read "CURRENT" file, which contains a pointer to the current manifest file + std::string current; + Status s = ReadFileToString(env_, CurrentFileName(dbname_), ¤t); + if (!s.ok()) { + return s; + } + if (current.empty() || current[current.size()-1] != '\n') { + return Status::Corruption("CURRENT file does not end with newline"); + } + current.resize(current.size() - 1); + + std::string dscname = dbname_ + "/" + current; + SequentialFile* file; + s = env_->NewSequentialFile(dscname, &file); + if (!s.ok()) { + return s; + } + + bool have_log_number = false; + bool have_prev_log_number = false; + bool have_next_file = false; + bool have_last_sequence = false; + uint64_t next_file = 0; + uint64_t last_sequence = 0; + uint64_t log_number = 0; + uint64_t prev_log_number = 0; + Builder builder(this, current_); + + { + LogReporter reporter; + reporter.status = &s; + log::Reader reader(file, &reporter, true/*checksum*/, 0/*initial_offset*/); + Slice record; + std::string scratch; + while (reader.ReadRecord(&record, &scratch) && s.ok()) { + VersionEdit edit; + s = edit.DecodeFrom(record); + if (s.ok()) { + if (edit.has_comparator_ && + edit.comparator_ != icmp_.user_comparator()->Name()) { + s = Status::InvalidArgument( + edit.comparator_ + " does not match existing comparator ", + icmp_.user_comparator()->Name()); + } + } + + if (s.ok()) { + builder.Apply(&edit); + } + + if (edit.has_log_number_) { + log_number = edit.log_number_; + have_log_number = true; + } + + if (edit.has_prev_log_number_) { + prev_log_number = edit.prev_log_number_; + have_prev_log_number = true; + } + + if (edit.has_next_file_number_) { + next_file = edit.next_file_number_; + have_next_file = true; + } + + if (edit.has_last_sequence_) { + last_sequence = edit.last_sequence_; + have_last_sequence = true; + } + } + } + delete file; + file = NULL; + + if (s.ok()) { + if (!have_next_file) { + s = Status::Corruption("no meta-nextfile entry in descriptor"); + } else if (!have_log_number) { + s = Status::Corruption("no meta-lognumber entry in descriptor"); + } else if (!have_last_sequence) { + s = Status::Corruption("no last-sequence-number entry in descriptor"); + } + + if (!have_prev_log_number) { + prev_log_number = 0; + } + + MarkFileNumberUsed(prev_log_number); + MarkFileNumberUsed(log_number); + } + + if (s.ok()) { + Version* v = new Version(this); + builder.SaveTo(v); + // Install recovered version + Finalize(v); + AppendVersion(v); + manifest_file_number_ = next_file; + next_file_number_ = next_file + 1; + last_sequence_ = last_sequence; + log_number_ = log_number; + prev_log_number_ = prev_log_number; + } + + return s; +} + +void VersionSet::MarkFileNumberUsed(uint64_t number) { + if (next_file_number_ <= number) { + next_file_number_ = number + 1; + } +} + +void VersionSet::Finalize(Version* v) { + // Precomputed best level for next compaction + int best_level = -1; + double best_score = -1; + + for (int level = 0; level < config::kNumLevels-1; level++) { + double score; + if (level == 0) { + // We treat level-0 specially by bounding the number of files + // instead of number of bytes for two reasons: + // + // (1) With larger write-buffer sizes, it is nice not to do too + // many level-0 compactions. + // + // (2) The files in level-0 are merged on every read and + // therefore we wish to avoid too many files when the individual + // file size is small (perhaps because of a small write-buffer + // setting, or very high compression ratios, or lots of + // overwrites/deletions). + score = v->files_[level].size() / + static_cast(config::kL0_CompactionTrigger); + } else { + // Compute the ratio of current size to size limit. + const uint64_t level_bytes = TotalFileSize(v->files_[level]); + score = static_cast(level_bytes) / MaxBytesForLevel(level); + } + + if (score > best_score) { + best_level = level; + best_score = score; + } + } + + v->compaction_level_ = best_level; + v->compaction_score_ = best_score; +} + +Status VersionSet::WriteSnapshot(log::Writer* log) { + // TODO: Break up into multiple records to reduce memory usage on recovery? + + // Save metadata + VersionEdit edit; + edit.SetComparatorName(icmp_.user_comparator()->Name()); + + // Save compaction pointers + for (int level = 0; level < config::kNumLevels; level++) { + if (!compact_pointer_[level].empty()) { + InternalKey key; + key.DecodeFrom(compact_pointer_[level]); + edit.SetCompactPointer(level, key); + } + } + + // Save files + for (int level = 0; level < config::kNumLevels; level++) { + const std::vector& files = current_->files_[level]; + for (size_t i = 0; i < files.size(); i++) { + const FileMetaData* f = files[i]; + edit.AddFile(level, f->number, f->file_size, f->smallest, f->largest); + } + } + + std::string record; + edit.EncodeTo(&record); + return log->AddRecord(record); +} + +int VersionSet::NumLevelFiles(int level) const { + assert(level >= 0); + assert(level < config::kNumLevels); + return current_->files_[level].size(); +} + +const char* VersionSet::LevelSummary(LevelSummaryStorage* scratch) const { + // Update code if kNumLevels changes + assert(config::kNumLevels == 7); + snprintf(scratch->buffer, sizeof(scratch->buffer), + "files[ %d %d %d %d %d %d %d ]", + int(current_->files_[0].size()), + int(current_->files_[1].size()), + int(current_->files_[2].size()), + int(current_->files_[3].size()), + int(current_->files_[4].size()), + int(current_->files_[5].size()), + int(current_->files_[6].size())); + return scratch->buffer; +} + +uint64_t VersionSet::ApproximateOffsetOf(Version* v, const InternalKey& ikey) { + uint64_t result = 0; + for (int level = 0; level < config::kNumLevels; level++) { + const std::vector& files = v->files_[level]; + for (size_t i = 0; i < files.size(); i++) { + if (icmp_.Compare(files[i]->largest, ikey) <= 0) { + // Entire file is before "ikey", so just add the file size + result += files[i]->file_size; + } else if (icmp_.Compare(files[i]->smallest, ikey) > 0) { + // Entire file is after "ikey", so ignore + if (level > 0) { + // Files other than level 0 are sorted by meta->smallest, so + // no further files in this level will contain data for + // "ikey". + break; + } + } else { + // "ikey" falls in the range for this table. Add the + // approximate offset of "ikey" within the table. + Table* tableptr; + Iterator* iter = table_cache_->NewIterator( + ReadOptions(), files[i]->number, files[i]->file_size, &tableptr); + if (tableptr != NULL) { + result += tableptr->ApproximateOffsetOf(ikey.Encode()); + } + delete iter; + } + } + } + return result; +} + +void VersionSet::AddLiveFiles(std::set* live) { + for (Version* v = dummy_versions_.next_; + v != &dummy_versions_; + v = v->next_) { + for (int level = 0; level < config::kNumLevels; level++) { + const std::vector& files = v->files_[level]; + for (size_t i = 0; i < files.size(); i++) { + live->insert(files[i]->number); + } + } + } +} + +int64_t VersionSet::NumLevelBytes(int level) const { + assert(level >= 0); + assert(level < config::kNumLevels); + return TotalFileSize(current_->files_[level]); +} + +int64_t VersionSet::MaxNextLevelOverlappingBytes() { + int64_t result = 0; + std::vector overlaps; + for (int level = 1; level < config::kNumLevels - 1; level++) { + for (size_t i = 0; i < current_->files_[level].size(); i++) { + const FileMetaData* f = current_->files_[level][i]; + current_->GetOverlappingInputs(level+1, &f->smallest, &f->largest, + &overlaps); + const int64_t sum = TotalFileSize(overlaps); + if (sum > result) { + result = sum; + } + } + } + return result; +} + +// Stores the minimal range that covers all entries in inputs in +// *smallest, *largest. +// REQUIRES: inputs is not empty +void VersionSet::GetRange(const std::vector& inputs, + InternalKey* smallest, + InternalKey* largest) { + assert(!inputs.empty()); + smallest->Clear(); + largest->Clear(); + for (size_t i = 0; i < inputs.size(); i++) { + FileMetaData* f = inputs[i]; + if (i == 0) { + *smallest = f->smallest; + *largest = f->largest; + } else { + if (icmp_.Compare(f->smallest, *smallest) < 0) { + *smallest = f->smallest; + } + if (icmp_.Compare(f->largest, *largest) > 0) { + *largest = f->largest; + } + } + } +} + +// Stores the minimal range that covers all entries in inputs1 and inputs2 +// in *smallest, *largest. +// REQUIRES: inputs is not empty +void VersionSet::GetRange2(const std::vector& inputs1, + const std::vector& inputs2, + InternalKey* smallest, + InternalKey* largest) { + std::vector all = inputs1; + all.insert(all.end(), inputs2.begin(), inputs2.end()); + GetRange(all, smallest, largest); +} + +Iterator* VersionSet::MakeInputIterator(Compaction* c) { + ReadOptions options; + options.verify_checksums = options_->paranoid_checks; + options.fill_cache = false; + + // Level-0 files have to be merged together. For other levels, + // we will make a concatenating iterator per level. + // TODO(opt): use concatenating iterator for level-0 if there is no overlap + const int space = (c->level() == 0 ? c->inputs_[0].size() + 1 : 2); + Iterator** list = new Iterator*[space]; + int num = 0; + for (int which = 0; which < 2; which++) { + if (!c->inputs_[which].empty()) { + if (c->level() + which == 0) { + const std::vector& files = c->inputs_[which]; + for (size_t i = 0; i < files.size(); i++) { + list[num++] = table_cache_->NewIterator( + options, files[i]->number, files[i]->file_size); + } + } else { + // Create concatenating iterator for the files from this level + list[num++] = NewTwoLevelIterator( + new Version::LevelFileNumIterator(icmp_, &c->inputs_[which]), + &GetFileIterator, table_cache_, options); + } + } + } + assert(num <= space); + Iterator* result = NewMergingIterator(&icmp_, list, num); + delete[] list; + return result; +} + +Compaction* VersionSet::PickCompaction() { + Compaction* c; + int level; + + // We prefer compactions triggered by too much data in a level over + // the compactions triggered by seeks. + const bool size_compaction = (current_->compaction_score_ >= 1); + const bool seek_compaction = (current_->file_to_compact_ != NULL); + if (size_compaction) { + level = current_->compaction_level_; + assert(level >= 0); + assert(level+1 < config::kNumLevels); + c = new Compaction(level); + + // Pick the first file that comes after compact_pointer_[level] + for (size_t i = 0; i < current_->files_[level].size(); i++) { + FileMetaData* f = current_->files_[level][i]; + if (compact_pointer_[level].empty() || + icmp_.Compare(f->largest.Encode(), compact_pointer_[level]) > 0) { + c->inputs_[0].push_back(f); + break; + } + } + if (c->inputs_[0].empty()) { + // Wrap-around to the beginning of the key space + c->inputs_[0].push_back(current_->files_[level][0]); + } + } else if (seek_compaction) { + level = current_->file_to_compact_level_; + c = new Compaction(level); + c->inputs_[0].push_back(current_->file_to_compact_); + } else { + return NULL; + } + + c->input_version_ = current_; + c->input_version_->Ref(); + + // Files in level 0 may overlap each other, so pick up all overlapping ones + if (level == 0) { + InternalKey smallest, largest; + GetRange(c->inputs_[0], &smallest, &largest); + // Note that the next call will discard the file we placed in + // c->inputs_[0] earlier and replace it with an overlapping set + // which will include the picked file. + current_->GetOverlappingInputs(0, &smallest, &largest, &c->inputs_[0]); + assert(!c->inputs_[0].empty()); + } + + SetupOtherInputs(c); + + return c; +} + +void VersionSet::SetupOtherInputs(Compaction* c) { + const int level = c->level(); + InternalKey smallest, largest; + GetRange(c->inputs_[0], &smallest, &largest); + + current_->GetOverlappingInputs(level+1, &smallest, &largest, &c->inputs_[1]); + + // Get entire range covered by compaction + InternalKey all_start, all_limit; + GetRange2(c->inputs_[0], c->inputs_[1], &all_start, &all_limit); + + // See if we can grow the number of inputs in "level" without + // changing the number of "level+1" files we pick up. + if (!c->inputs_[1].empty()) { + std::vector expanded0; + current_->GetOverlappingInputs(level, &all_start, &all_limit, &expanded0); + const int64_t inputs0_size = TotalFileSize(c->inputs_[0]); + const int64_t inputs1_size = TotalFileSize(c->inputs_[1]); + const int64_t expanded0_size = TotalFileSize(expanded0); + if (expanded0.size() > c->inputs_[0].size() && + inputs1_size + expanded0_size < kExpandedCompactionByteSizeLimit) { + InternalKey new_start, new_limit; + GetRange(expanded0, &new_start, &new_limit); + std::vector expanded1; + current_->GetOverlappingInputs(level+1, &new_start, &new_limit, + &expanded1); + if (expanded1.size() == c->inputs_[1].size()) { + Log(options_->info_log, + "Expanding@%d %d+%d (%ld+%ld bytes) to %d+%d (%ld+%ld bytes)\n", + level, + int(c->inputs_[0].size()), + int(c->inputs_[1].size()), + long(inputs0_size), long(inputs1_size), + int(expanded0.size()), + int(expanded1.size()), + long(expanded0_size), long(inputs1_size)); + smallest = new_start; + largest = new_limit; + c->inputs_[0] = expanded0; + c->inputs_[1] = expanded1; + GetRange2(c->inputs_[0], c->inputs_[1], &all_start, &all_limit); + } + } + } + + // Compute the set of grandparent files that overlap this compaction + // (parent == level+1; grandparent == level+2) + if (level + 2 < config::kNumLevels) { + current_->GetOverlappingInputs(level + 2, &all_start, &all_limit, + &c->grandparents_); + } + + if (false) { + Log(options_->info_log, "Compacting %d '%s' .. '%s'", + level, + smallest.DebugString().c_str(), + largest.DebugString().c_str()); + } + + // Update the place where we will do the next compaction for this level. + // We update this immediately instead of waiting for the VersionEdit + // to be applied so that if the compaction fails, we will try a different + // key range next time. + compact_pointer_[level] = largest.Encode().ToString(); + c->edit_.SetCompactPointer(level, largest); +} + +Compaction* VersionSet::CompactRange( + int level, + const InternalKey* begin, + const InternalKey* end) { + std::vector inputs; + current_->GetOverlappingInputs(level, begin, end, &inputs); + if (inputs.empty()) { + return NULL; + } + + // Avoid compacting too much in one shot in case the range is large. + // But we cannot do this for level-0 since level-0 files can overlap + // and we must not pick one file and drop another older file if the + // two files overlap. + if (level > 0) { + const uint64_t limit = MaxFileSizeForLevel(level); + uint64_t total = 0; + for (size_t i = 0; i < inputs.size(); i++) { + uint64_t s = inputs[i]->file_size; + total += s; + if (total >= limit) { + inputs.resize(i + 1); + break; + } + } + } + + Compaction* c = new Compaction(level); + c->input_version_ = current_; + c->input_version_->Ref(); + c->inputs_[0] = inputs; + SetupOtherInputs(c); + return c; +} + +Compaction::Compaction(int level) + : level_(level), + max_output_file_size_(MaxFileSizeForLevel(level)), + input_version_(NULL), + grandparent_index_(0), + seen_key_(false), + overlapped_bytes_(0) { + for (int i = 0; i < config::kNumLevels; i++) { + level_ptrs_[i] = 0; + } +} + +Compaction::~Compaction() { + if (input_version_ != NULL) { + input_version_->Unref(); + } +} + +bool Compaction::IsTrivialMove() const { + // Avoid a move if there is lots of overlapping grandparent data. + // Otherwise, the move could create a parent file that will require + // a very expensive merge later on. + return (num_input_files(0) == 1 && + num_input_files(1) == 0 && + TotalFileSize(grandparents_) <= kMaxGrandParentOverlapBytes); +} + +void Compaction::AddInputDeletions(VersionEdit* edit) { + for (int which = 0; which < 2; which++) { + for (size_t i = 0; i < inputs_[which].size(); i++) { + edit->DeleteFile(level_ + which, inputs_[which][i]->number); + } + } +} + +bool Compaction::IsBaseLevelForKey(const Slice& user_key) { + // Maybe use binary search to find right entry instead of linear search? + const Comparator* user_cmp = input_version_->vset_->icmp_.user_comparator(); + for (int lvl = level_ + 2; lvl < config::kNumLevels; lvl++) { + const std::vector& files = input_version_->files_[lvl]; + for (; level_ptrs_[lvl] < files.size(); ) { + FileMetaData* f = files[level_ptrs_[lvl]]; + if (user_cmp->Compare(user_key, f->largest.user_key()) <= 0) { + // We've advanced far enough + if (user_cmp->Compare(user_key, f->smallest.user_key()) >= 0) { + // Key falls in this file's range, so definitely not base level + return false; + } + break; + } + level_ptrs_[lvl]++; + } + } + return true; +} + +bool Compaction::ShouldStopBefore(const Slice& internal_key) { + // Scan to find earliest grandparent file that contains key. + const InternalKeyComparator* icmp = &input_version_->vset_->icmp_; + while (grandparent_index_ < grandparents_.size() && + icmp->Compare(internal_key, + grandparents_[grandparent_index_]->largest.Encode()) > 0) { + if (seen_key_) { + overlapped_bytes_ += grandparents_[grandparent_index_]->file_size; + } + grandparent_index_++; + } + seen_key_ = true; + + if (overlapped_bytes_ > kMaxGrandParentOverlapBytes) { + // Too much overlap for current output; start new output + overlapped_bytes_ = 0; + return true; + } else { + return false; + } +} + +void Compaction::ReleaseInputs() { + if (input_version_ != NULL) { + input_version_->Unref(); + input_version_ = NULL; + } +} + +} // namespace leveldb diff --git a/ios/Pods/leveldb-library/db/version_set.h b/ios/Pods/leveldb-library/db/version_set.h new file mode 100644 index 000000000..8dc14b8e0 --- /dev/null +++ b/ios/Pods/leveldb-library/db/version_set.h @@ -0,0 +1,396 @@ +// Copyright (c) 2011 The LevelDB Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. See the AUTHORS file for names of contributors. +// +// The representation of a DBImpl consists of a set of Versions. The +// newest version is called "current". Older versions may be kept +// around to provide a consistent view to live iterators. +// +// Each Version keeps track of a set of Table files per level. The +// entire set of versions is maintained in a VersionSet. +// +// Version,VersionSet are thread-compatible, but require external +// synchronization on all accesses. + +#ifndef STORAGE_LEVELDB_DB_VERSION_SET_H_ +#define STORAGE_LEVELDB_DB_VERSION_SET_H_ + +#include +#include +#include +#include "db/dbformat.h" +#include "db/version_edit.h" +#include "port/port.h" +#include "port/thread_annotations.h" + +namespace leveldb { + +namespace log { class Writer; } + +class Compaction; +class Iterator; +class MemTable; +class TableBuilder; +class TableCache; +class Version; +class VersionSet; +class WritableFile; + +// Return the smallest index i such that files[i]->largest >= key. +// Return files.size() if there is no such file. +// REQUIRES: "files" contains a sorted list of non-overlapping files. +extern int FindFile(const InternalKeyComparator& icmp, + const std::vector& files, + const Slice& key); + +// Returns true iff some file in "files" overlaps the user key range +// [*smallest,*largest]. +// smallest==NULL represents a key smaller than all keys in the DB. +// largest==NULL represents a key largest than all keys in the DB. +// REQUIRES: If disjoint_sorted_files, files[] contains disjoint ranges +// in sorted order. +extern bool SomeFileOverlapsRange( + const InternalKeyComparator& icmp, + bool disjoint_sorted_files, + const std::vector& files, + const Slice* smallest_user_key, + const Slice* largest_user_key); + +class Version { + public: + // Append to *iters a sequence of iterators that will + // yield the contents of this Version when merged together. + // REQUIRES: This version has been saved (see VersionSet::SaveTo) + void AddIterators(const ReadOptions&, std::vector* iters); + + // Lookup the value for key. If found, store it in *val and + // return OK. Else return a non-OK status. Fills *stats. + // REQUIRES: lock is not held + struct GetStats { + FileMetaData* seek_file; + int seek_file_level; + }; + Status Get(const ReadOptions&, const LookupKey& key, std::string* val, + GetStats* stats); + + // Adds "stats" into the current state. Returns true if a new + // compaction may need to be triggered, false otherwise. + // REQUIRES: lock is held + bool UpdateStats(const GetStats& stats); + + // Record a sample of bytes read at the specified internal key. + // Samples are taken approximately once every config::kReadBytesPeriod + // bytes. Returns true if a new compaction may need to be triggered. + // REQUIRES: lock is held + bool RecordReadSample(Slice key); + + // Reference count management (so Versions do not disappear out from + // under live iterators) + void Ref(); + void Unref(); + + void GetOverlappingInputs( + int level, + const InternalKey* begin, // NULL means before all keys + const InternalKey* end, // NULL means after all keys + std::vector* inputs); + + // Returns true iff some file in the specified level overlaps + // some part of [*smallest_user_key,*largest_user_key]. + // smallest_user_key==NULL represents a key smaller than all keys in the DB. + // largest_user_key==NULL represents a key largest than all keys in the DB. + bool OverlapInLevel(int level, + const Slice* smallest_user_key, + const Slice* largest_user_key); + + // Return the level at which we should place a new memtable compaction + // result that covers the range [smallest_user_key,largest_user_key]. + int PickLevelForMemTableOutput(const Slice& smallest_user_key, + const Slice& largest_user_key); + + int NumFiles(int level) const { return files_[level].size(); } + + // Return a human readable string that describes this version's contents. + std::string DebugString() const; + + private: + friend class Compaction; + friend class VersionSet; + + class LevelFileNumIterator; + Iterator* NewConcatenatingIterator(const ReadOptions&, int level) const; + + // Call func(arg, level, f) for every file that overlaps user_key in + // order from newest to oldest. If an invocation of func returns + // false, makes no more calls. + // + // REQUIRES: user portion of internal_key == user_key. + void ForEachOverlapping(Slice user_key, Slice internal_key, + void* arg, + bool (*func)(void*, int, FileMetaData*)); + + VersionSet* vset_; // VersionSet to which this Version belongs + Version* next_; // Next version in linked list + Version* prev_; // Previous version in linked list + int refs_; // Number of live refs to this version + + // List of files per level + std::vector files_[config::kNumLevels]; + + // Next file to compact based on seek stats. + FileMetaData* file_to_compact_; + int file_to_compact_level_; + + // Level that should be compacted next and its compaction score. + // Score < 1 means compaction is not strictly needed. These fields + // are initialized by Finalize(). + double compaction_score_; + int compaction_level_; + + explicit Version(VersionSet* vset) + : vset_(vset), next_(this), prev_(this), refs_(0), + file_to_compact_(NULL), + file_to_compact_level_(-1), + compaction_score_(-1), + compaction_level_(-1) { + } + + ~Version(); + + // No copying allowed + Version(const Version&); + void operator=(const Version&); +}; + +class VersionSet { + public: + VersionSet(const std::string& dbname, + const Options* options, + TableCache* table_cache, + const InternalKeyComparator*); + ~VersionSet(); + + // Apply *edit to the current version to form a new descriptor that + // is both saved to persistent state and installed as the new + // current version. Will release *mu while actually writing to the file. + // REQUIRES: *mu is held on entry. + // REQUIRES: no other thread concurrently calls LogAndApply() + Status LogAndApply(VersionEdit* edit, port::Mutex* mu) + EXCLUSIVE_LOCKS_REQUIRED(mu); + + // Recover the last saved descriptor from persistent storage. + Status Recover(); + + // Return the current version. + Version* current() const { return current_; } + + // Return the current manifest file number + uint64_t ManifestFileNumber() const { return manifest_file_number_; } + + // Allocate and return a new file number + uint64_t NewFileNumber() { return next_file_number_++; } + + // Arrange to reuse "file_number" unless a newer file number has + // already been allocated. + // REQUIRES: "file_number" was returned by a call to NewFileNumber(). + void ReuseFileNumber(uint64_t file_number) { + if (next_file_number_ == file_number + 1) { + next_file_number_ = file_number; + } + } + + // Return the number of Table files at the specified level. + int NumLevelFiles(int level) const; + + // Return the combined file size of all files at the specified level. + int64_t NumLevelBytes(int level) const; + + // Return the last sequence number. + uint64_t LastSequence() const { return last_sequence_; } + + // Set the last sequence number to s. + void SetLastSequence(uint64_t s) { + assert(s >= last_sequence_); + last_sequence_ = s; + } + + // Mark the specified file number as used. + void MarkFileNumberUsed(uint64_t number); + + // Return the current log file number. + uint64_t LogNumber() const { return log_number_; } + + // Return the log file number for the log file that is currently + // being compacted, or zero if there is no such log file. + uint64_t PrevLogNumber() const { return prev_log_number_; } + + // Pick level and inputs for a new compaction. + // Returns NULL if there is no compaction to be done. + // Otherwise returns a pointer to a heap-allocated object that + // describes the compaction. Caller should delete the result. + Compaction* PickCompaction(); + + // Return a compaction object for compacting the range [begin,end] in + // the specified level. Returns NULL if there is nothing in that + // level that overlaps the specified range. Caller should delete + // the result. + Compaction* CompactRange( + int level, + const InternalKey* begin, + const InternalKey* end); + + // Return the maximum overlapping data (in bytes) at next level for any + // file at a level >= 1. + int64_t MaxNextLevelOverlappingBytes(); + + // Create an iterator that reads over the compaction inputs for "*c". + // The caller should delete the iterator when no longer needed. + Iterator* MakeInputIterator(Compaction* c); + + // Returns true iff some level needs a compaction. + bool NeedsCompaction() const { + Version* v = current_; + return (v->compaction_score_ >= 1) || (v->file_to_compact_ != NULL); + } + + // Add all files listed in any live version to *live. + // May also mutate some internal state. + void AddLiveFiles(std::set* live); + + // Return the approximate offset in the database of the data for + // "key" as of version "v". + uint64_t ApproximateOffsetOf(Version* v, const InternalKey& key); + + // Return a human-readable short (single-line) summary of the number + // of files per level. Uses *scratch as backing store. + struct LevelSummaryStorage { + char buffer[100]; + }; + const char* LevelSummary(LevelSummaryStorage* scratch) const; + + private: + class Builder; + + friend class Compaction; + friend class Version; + + void Finalize(Version* v); + + void GetRange(const std::vector& inputs, + InternalKey* smallest, + InternalKey* largest); + + void GetRange2(const std::vector& inputs1, + const std::vector& inputs2, + InternalKey* smallest, + InternalKey* largest); + + void SetupOtherInputs(Compaction* c); + + // Save current contents to *log + Status WriteSnapshot(log::Writer* log); + + void AppendVersion(Version* v); + + Env* const env_; + const std::string dbname_; + const Options* const options_; + TableCache* const table_cache_; + const InternalKeyComparator icmp_; + uint64_t next_file_number_; + uint64_t manifest_file_number_; + uint64_t last_sequence_; + uint64_t log_number_; + uint64_t prev_log_number_; // 0 or backing store for memtable being compacted + + // Opened lazily + WritableFile* descriptor_file_; + log::Writer* descriptor_log_; + Version dummy_versions_; // Head of circular doubly-linked list of versions. + Version* current_; // == dummy_versions_.prev_ + + // Per-level key at which the next compaction at that level should start. + // Either an empty string, or a valid InternalKey. + std::string compact_pointer_[config::kNumLevels]; + + // No copying allowed + VersionSet(const VersionSet&); + void operator=(const VersionSet&); +}; + +// A Compaction encapsulates information about a compaction. +class Compaction { + public: + ~Compaction(); + + // Return the level that is being compacted. Inputs from "level" + // and "level+1" will be merged to produce a set of "level+1" files. + int level() const { return level_; } + + // Return the object that holds the edits to the descriptor done + // by this compaction. + VersionEdit* edit() { return &edit_; } + + // "which" must be either 0 or 1 + int num_input_files(int which) const { return inputs_[which].size(); } + + // Return the ith input file at "level()+which" ("which" must be 0 or 1). + FileMetaData* input(int which, int i) const { return inputs_[which][i]; } + + // Maximum size of files to build during this compaction. + uint64_t MaxOutputFileSize() const { return max_output_file_size_; } + + // Is this a trivial compaction that can be implemented by just + // moving a single input file to the next level (no merging or splitting) + bool IsTrivialMove() const; + + // Add all inputs to this compaction as delete operations to *edit. + void AddInputDeletions(VersionEdit* edit); + + // Returns true if the information we have available guarantees that + // the compaction is producing data in "level+1" for which no data exists + // in levels greater than "level+1". + bool IsBaseLevelForKey(const Slice& user_key); + + // Returns true iff we should stop building the current output + // before processing "internal_key". + bool ShouldStopBefore(const Slice& internal_key); + + // Release the input version for the compaction, once the compaction + // is successful. + void ReleaseInputs(); + + private: + friend class Version; + friend class VersionSet; + + explicit Compaction(int level); + + int level_; + uint64_t max_output_file_size_; + Version* input_version_; + VersionEdit edit_; + + // Each compaction reads inputs from "level_" and "level_+1" + std::vector inputs_[2]; // The two sets of inputs + + // State used to check for number of of overlapping grandparent files + // (parent == level_ + 1, grandparent == level_ + 2) + std::vector grandparents_; + size_t grandparent_index_; // Index in grandparent_starts_ + bool seen_key_; // Some output key has been seen + int64_t overlapped_bytes_; // Bytes of overlap between current output + // and grandparent files + + // State for implementing IsBaseLevelForKey + + // level_ptrs_ holds indices into input_version_->levels_: our state + // is that we are positioned at one of the file ranges for each + // higher level than the ones involved in this compaction (i.e. for + // all L >= level_ + 2). + size_t level_ptrs_[config::kNumLevels]; +}; + +} // namespace leveldb + +#endif // STORAGE_LEVELDB_DB_VERSION_SET_H_ diff --git a/ios/Pods/leveldb-library/db/version_set_test.cc b/ios/Pods/leveldb-library/db/version_set_test.cc new file mode 100644 index 000000000..501e34d13 --- /dev/null +++ b/ios/Pods/leveldb-library/db/version_set_test.cc @@ -0,0 +1,179 @@ +// Copyright (c) 2011 The LevelDB Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. See the AUTHORS file for names of contributors. + +#include "db/version_set.h" +#include "util/logging.h" +#include "util/testharness.h" +#include "util/testutil.h" + +namespace leveldb { + +class FindFileTest { + public: + std::vector files_; + bool disjoint_sorted_files_; + + FindFileTest() : disjoint_sorted_files_(true) { } + + ~FindFileTest() { + for (int i = 0; i < files_.size(); i++) { + delete files_[i]; + } + } + + void Add(const char* smallest, const char* largest, + SequenceNumber smallest_seq = 100, + SequenceNumber largest_seq = 100) { + FileMetaData* f = new FileMetaData; + f->number = files_.size() + 1; + f->smallest = InternalKey(smallest, smallest_seq, kTypeValue); + f->largest = InternalKey(largest, largest_seq, kTypeValue); + files_.push_back(f); + } + + int Find(const char* key) { + InternalKey target(key, 100, kTypeValue); + InternalKeyComparator cmp(BytewiseComparator()); + return FindFile(cmp, files_, target.Encode()); + } + + bool Overlaps(const char* smallest, const char* largest) { + InternalKeyComparator cmp(BytewiseComparator()); + Slice s(smallest != NULL ? smallest : ""); + Slice l(largest != NULL ? largest : ""); + return SomeFileOverlapsRange(cmp, disjoint_sorted_files_, files_, + (smallest != NULL ? &s : NULL), + (largest != NULL ? &l : NULL)); + } +}; + +TEST(FindFileTest, Empty) { + ASSERT_EQ(0, Find("foo")); + ASSERT_TRUE(! Overlaps("a", "z")); + ASSERT_TRUE(! Overlaps(NULL, "z")); + ASSERT_TRUE(! Overlaps("a", NULL)); + ASSERT_TRUE(! Overlaps(NULL, NULL)); +} + +TEST(FindFileTest, Single) { + Add("p", "q"); + ASSERT_EQ(0, Find("a")); + ASSERT_EQ(0, Find("p")); + ASSERT_EQ(0, Find("p1")); + ASSERT_EQ(0, Find("q")); + ASSERT_EQ(1, Find("q1")); + ASSERT_EQ(1, Find("z")); + + ASSERT_TRUE(! Overlaps("a", "b")); + ASSERT_TRUE(! Overlaps("z1", "z2")); + ASSERT_TRUE(Overlaps("a", "p")); + ASSERT_TRUE(Overlaps("a", "q")); + ASSERT_TRUE(Overlaps("a", "z")); + ASSERT_TRUE(Overlaps("p", "p1")); + ASSERT_TRUE(Overlaps("p", "q")); + ASSERT_TRUE(Overlaps("p", "z")); + ASSERT_TRUE(Overlaps("p1", "p2")); + ASSERT_TRUE(Overlaps("p1", "z")); + ASSERT_TRUE(Overlaps("q", "q")); + ASSERT_TRUE(Overlaps("q", "q1")); + + ASSERT_TRUE(! Overlaps(NULL, "j")); + ASSERT_TRUE(! Overlaps("r", NULL)); + ASSERT_TRUE(Overlaps(NULL, "p")); + ASSERT_TRUE(Overlaps(NULL, "p1")); + ASSERT_TRUE(Overlaps("q", NULL)); + ASSERT_TRUE(Overlaps(NULL, NULL)); +} + + +TEST(FindFileTest, Multiple) { + Add("150", "200"); + Add("200", "250"); + Add("300", "350"); + Add("400", "450"); + ASSERT_EQ(0, Find("100")); + ASSERT_EQ(0, Find("150")); + ASSERT_EQ(0, Find("151")); + ASSERT_EQ(0, Find("199")); + ASSERT_EQ(0, Find("200")); + ASSERT_EQ(1, Find("201")); + ASSERT_EQ(1, Find("249")); + ASSERT_EQ(1, Find("250")); + ASSERT_EQ(2, Find("251")); + ASSERT_EQ(2, Find("299")); + ASSERT_EQ(2, Find("300")); + ASSERT_EQ(2, Find("349")); + ASSERT_EQ(2, Find("350")); + ASSERT_EQ(3, Find("351")); + ASSERT_EQ(3, Find("400")); + ASSERT_EQ(3, Find("450")); + ASSERT_EQ(4, Find("451")); + + ASSERT_TRUE(! Overlaps("100", "149")); + ASSERT_TRUE(! Overlaps("251", "299")); + ASSERT_TRUE(! Overlaps("451", "500")); + ASSERT_TRUE(! Overlaps("351", "399")); + + ASSERT_TRUE(Overlaps("100", "150")); + ASSERT_TRUE(Overlaps("100", "200")); + ASSERT_TRUE(Overlaps("100", "300")); + ASSERT_TRUE(Overlaps("100", "400")); + ASSERT_TRUE(Overlaps("100", "500")); + ASSERT_TRUE(Overlaps("375", "400")); + ASSERT_TRUE(Overlaps("450", "450")); + ASSERT_TRUE(Overlaps("450", "500")); +} + +TEST(FindFileTest, MultipleNullBoundaries) { + Add("150", "200"); + Add("200", "250"); + Add("300", "350"); + Add("400", "450"); + ASSERT_TRUE(! Overlaps(NULL, "149")); + ASSERT_TRUE(! Overlaps("451", NULL)); + ASSERT_TRUE(Overlaps(NULL, NULL)); + ASSERT_TRUE(Overlaps(NULL, "150")); + ASSERT_TRUE(Overlaps(NULL, "199")); + ASSERT_TRUE(Overlaps(NULL, "200")); + ASSERT_TRUE(Overlaps(NULL, "201")); + ASSERT_TRUE(Overlaps(NULL, "400")); + ASSERT_TRUE(Overlaps(NULL, "800")); + ASSERT_TRUE(Overlaps("100", NULL)); + ASSERT_TRUE(Overlaps("200", NULL)); + ASSERT_TRUE(Overlaps("449", NULL)); + ASSERT_TRUE(Overlaps("450", NULL)); +} + +TEST(FindFileTest, OverlapSequenceChecks) { + Add("200", "200", 5000, 3000); + ASSERT_TRUE(! Overlaps("199", "199")); + ASSERT_TRUE(! Overlaps("201", "300")); + ASSERT_TRUE(Overlaps("200", "200")); + ASSERT_TRUE(Overlaps("190", "200")); + ASSERT_TRUE(Overlaps("200", "210")); +} + +TEST(FindFileTest, OverlappingFiles) { + Add("150", "600"); + Add("400", "500"); + disjoint_sorted_files_ = false; + ASSERT_TRUE(! Overlaps("100", "149")); + ASSERT_TRUE(! Overlaps("601", "700")); + ASSERT_TRUE(Overlaps("100", "150")); + ASSERT_TRUE(Overlaps("100", "200")); + ASSERT_TRUE(Overlaps("100", "300")); + ASSERT_TRUE(Overlaps("100", "400")); + ASSERT_TRUE(Overlaps("100", "500")); + ASSERT_TRUE(Overlaps("375", "400")); + ASSERT_TRUE(Overlaps("450", "450")); + ASSERT_TRUE(Overlaps("450", "500")); + ASSERT_TRUE(Overlaps("450", "700")); + ASSERT_TRUE(Overlaps("600", "700")); +} + +} // namespace leveldb + +int main(int argc, char** argv) { + return leveldb::test::RunAllTests(); +} diff --git a/ios/Pods/leveldb-library/db/write_batch.cc b/ios/Pods/leveldb-library/db/write_batch.cc new file mode 100644 index 000000000..33f4a4257 --- /dev/null +++ b/ios/Pods/leveldb-library/db/write_batch.cc @@ -0,0 +1,147 @@ +// Copyright (c) 2011 The LevelDB Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. See the AUTHORS file for names of contributors. +// +// WriteBatch::rep_ := +// sequence: fixed64 +// count: fixed32 +// data: record[count] +// record := +// kTypeValue varstring varstring | +// kTypeDeletion varstring +// varstring := +// len: varint32 +// data: uint8[len] + +#include "leveldb/write_batch.h" + +#include "leveldb/db.h" +#include "db/dbformat.h" +#include "db/memtable.h" +#include "db/write_batch_internal.h" +#include "util/coding.h" + +namespace leveldb { + +// WriteBatch header has an 8-byte sequence number followed by a 4-byte count. +static const size_t kHeader = 12; + +WriteBatch::WriteBatch() { + Clear(); +} + +WriteBatch::~WriteBatch() { } + +WriteBatch::Handler::~Handler() { } + +void WriteBatch::Clear() { + rep_.clear(); + rep_.resize(kHeader); +} + +Status WriteBatch::Iterate(Handler* handler) const { + Slice input(rep_); + if (input.size() < kHeader) { + return Status::Corruption("malformed WriteBatch (too small)"); + } + + input.remove_prefix(kHeader); + Slice key, value; + int found = 0; + while (!input.empty()) { + found++; + char tag = input[0]; + input.remove_prefix(1); + switch (tag) { + case kTypeValue: + if (GetLengthPrefixedSlice(&input, &key) && + GetLengthPrefixedSlice(&input, &value)) { + handler->Put(key, value); + } else { + return Status::Corruption("bad WriteBatch Put"); + } + break; + case kTypeDeletion: + if (GetLengthPrefixedSlice(&input, &key)) { + handler->Delete(key); + } else { + return Status::Corruption("bad WriteBatch Delete"); + } + break; + default: + return Status::Corruption("unknown WriteBatch tag"); + } + } + if (found != WriteBatchInternal::Count(this)) { + return Status::Corruption("WriteBatch has wrong count"); + } else { + return Status::OK(); + } +} + +int WriteBatchInternal::Count(const WriteBatch* b) { + return DecodeFixed32(b->rep_.data() + 8); +} + +void WriteBatchInternal::SetCount(WriteBatch* b, int n) { + EncodeFixed32(&b->rep_[8], n); +} + +SequenceNumber WriteBatchInternal::Sequence(const WriteBatch* b) { + return SequenceNumber(DecodeFixed64(b->rep_.data())); +} + +void WriteBatchInternal::SetSequence(WriteBatch* b, SequenceNumber seq) { + EncodeFixed64(&b->rep_[0], seq); +} + +void WriteBatch::Put(const Slice& key, const Slice& value) { + WriteBatchInternal::SetCount(this, WriteBatchInternal::Count(this) + 1); + rep_.push_back(static_cast(kTypeValue)); + PutLengthPrefixedSlice(&rep_, key); + PutLengthPrefixedSlice(&rep_, value); +} + +void WriteBatch::Delete(const Slice& key) { + WriteBatchInternal::SetCount(this, WriteBatchInternal::Count(this) + 1); + rep_.push_back(static_cast(kTypeDeletion)); + PutLengthPrefixedSlice(&rep_, key); +} + +namespace { +class MemTableInserter : public WriteBatch::Handler { + public: + SequenceNumber sequence_; + MemTable* mem_; + + virtual void Put(const Slice& key, const Slice& value) { + mem_->Add(sequence_, kTypeValue, key, value); + sequence_++; + } + virtual void Delete(const Slice& key) { + mem_->Add(sequence_, kTypeDeletion, key, Slice()); + sequence_++; + } +}; +} // namespace + +Status WriteBatchInternal::InsertInto(const WriteBatch* b, + MemTable* memtable) { + MemTableInserter inserter; + inserter.sequence_ = WriteBatchInternal::Sequence(b); + inserter.mem_ = memtable; + return b->Iterate(&inserter); +} + +void WriteBatchInternal::SetContents(WriteBatch* b, const Slice& contents) { + assert(contents.size() >= kHeader); + b->rep_.assign(contents.data(), contents.size()); +} + +void WriteBatchInternal::Append(WriteBatch* dst, const WriteBatch* src) { + SetCount(dst, Count(dst) + Count(src)); + assert(src->rep_.size() >= kHeader); + dst->rep_.append(src->rep_.data() + kHeader, src->rep_.size() - kHeader); +} + +} // namespace leveldb diff --git a/ios/Pods/leveldb-library/db/write_batch_internal.h b/ios/Pods/leveldb-library/db/write_batch_internal.h new file mode 100644 index 000000000..310a3c891 --- /dev/null +++ b/ios/Pods/leveldb-library/db/write_batch_internal.h @@ -0,0 +1,49 @@ +// Copyright (c) 2011 The LevelDB Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. See the AUTHORS file for names of contributors. + +#ifndef STORAGE_LEVELDB_DB_WRITE_BATCH_INTERNAL_H_ +#define STORAGE_LEVELDB_DB_WRITE_BATCH_INTERNAL_H_ + +#include "leveldb/write_batch.h" + +namespace leveldb { + +class MemTable; + +// WriteBatchInternal provides static methods for manipulating a +// WriteBatch that we don't want in the public WriteBatch interface. +class WriteBatchInternal { + public: + // Return the number of entries in the batch. + static int Count(const WriteBatch* batch); + + // Set the count for the number of entries in the batch. + static void SetCount(WriteBatch* batch, int n); + + // Return the sequence number for the start of this batch. + static SequenceNumber Sequence(const WriteBatch* batch); + + // Store the specified number as the sequence number for the start of + // this batch. + static void SetSequence(WriteBatch* batch, SequenceNumber seq); + + static Slice Contents(const WriteBatch* batch) { + return Slice(batch->rep_); + } + + static size_t ByteSize(const WriteBatch* batch) { + return batch->rep_.size(); + } + + static void SetContents(WriteBatch* batch, const Slice& contents); + + static Status InsertInto(const WriteBatch* batch, MemTable* memtable); + + static void Append(WriteBatch* dst, const WriteBatch* src); +}; + +} // namespace leveldb + + +#endif // STORAGE_LEVELDB_DB_WRITE_BATCH_INTERNAL_H_ diff --git a/ios/Pods/leveldb-library/db/write_batch_test.cc b/ios/Pods/leveldb-library/db/write_batch_test.cc new file mode 100644 index 000000000..9064e3d85 --- /dev/null +++ b/ios/Pods/leveldb-library/db/write_batch_test.cc @@ -0,0 +1,120 @@ +// Copyright (c) 2011 The LevelDB Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. See the AUTHORS file for names of contributors. + +#include "leveldb/db.h" + +#include "db/memtable.h" +#include "db/write_batch_internal.h" +#include "leveldb/env.h" +#include "util/logging.h" +#include "util/testharness.h" + +namespace leveldb { + +static std::string PrintContents(WriteBatch* b) { + InternalKeyComparator cmp(BytewiseComparator()); + MemTable* mem = new MemTable(cmp); + mem->Ref(); + std::string state; + Status s = WriteBatchInternal::InsertInto(b, mem); + int count = 0; + Iterator* iter = mem->NewIterator(); + for (iter->SeekToFirst(); iter->Valid(); iter->Next()) { + ParsedInternalKey ikey; + ASSERT_TRUE(ParseInternalKey(iter->key(), &ikey)); + switch (ikey.type) { + case kTypeValue: + state.append("Put("); + state.append(ikey.user_key.ToString()); + state.append(", "); + state.append(iter->value().ToString()); + state.append(")"); + count++; + break; + case kTypeDeletion: + state.append("Delete("); + state.append(ikey.user_key.ToString()); + state.append(")"); + count++; + break; + } + state.append("@"); + state.append(NumberToString(ikey.sequence)); + } + delete iter; + if (!s.ok()) { + state.append("ParseError()"); + } else if (count != WriteBatchInternal::Count(b)) { + state.append("CountMismatch()"); + } + mem->Unref(); + return state; +} + +class WriteBatchTest { }; + +TEST(WriteBatchTest, Empty) { + WriteBatch batch; + ASSERT_EQ("", PrintContents(&batch)); + ASSERT_EQ(0, WriteBatchInternal::Count(&batch)); +} + +TEST(WriteBatchTest, Multiple) { + WriteBatch batch; + batch.Put(Slice("foo"), Slice("bar")); + batch.Delete(Slice("box")); + batch.Put(Slice("baz"), Slice("boo")); + WriteBatchInternal::SetSequence(&batch, 100); + ASSERT_EQ(100, WriteBatchInternal::Sequence(&batch)); + ASSERT_EQ(3, WriteBatchInternal::Count(&batch)); + ASSERT_EQ("Put(baz, boo)@102" + "Delete(box)@101" + "Put(foo, bar)@100", + PrintContents(&batch)); +} + +TEST(WriteBatchTest, Corruption) { + WriteBatch batch; + batch.Put(Slice("foo"), Slice("bar")); + batch.Delete(Slice("box")); + WriteBatchInternal::SetSequence(&batch, 200); + Slice contents = WriteBatchInternal::Contents(&batch); + WriteBatchInternal::SetContents(&batch, + Slice(contents.data(),contents.size()-1)); + ASSERT_EQ("Put(foo, bar)@200" + "ParseError()", + PrintContents(&batch)); +} + +TEST(WriteBatchTest, Append) { + WriteBatch b1, b2; + WriteBatchInternal::SetSequence(&b1, 200); + WriteBatchInternal::SetSequence(&b2, 300); + WriteBatchInternal::Append(&b1, &b2); + ASSERT_EQ("", + PrintContents(&b1)); + b2.Put("a", "va"); + WriteBatchInternal::Append(&b1, &b2); + ASSERT_EQ("Put(a, va)@200", + PrintContents(&b1)); + b2.Clear(); + b2.Put("b", "vb"); + WriteBatchInternal::Append(&b1, &b2); + ASSERT_EQ("Put(a, va)@200" + "Put(b, vb)@201", + PrintContents(&b1)); + b2.Delete("foo"); + WriteBatchInternal::Append(&b1, &b2); + ASSERT_EQ("Put(a, va)@200" + "Put(b, vb)@202" + "Put(b, vb)@201" + "Delete(foo)@203", + PrintContents(&b1)); +} + +} // namespace leveldb + +int main(int argc, char** argv) { + return leveldb::test::RunAllTests(); +} diff --git a/ios/Pods/leveldb-library/include/leveldb/c.h b/ios/Pods/leveldb-library/include/leveldb/c.h new file mode 100644 index 000000000..1048fe3b8 --- /dev/null +++ b/ios/Pods/leveldb-library/include/leveldb/c.h @@ -0,0 +1,290 @@ +/* Copyright (c) 2011 The LevelDB Authors. All rights reserved. + Use of this source code is governed by a BSD-style license that can be + found in the LICENSE file. See the AUTHORS file for names of contributors. + + C bindings for leveldb. May be useful as a stable ABI that can be + used by programs that keep leveldb in a shared library, or for + a JNI api. + + Does not support: + . getters for the option types + . custom comparators that implement key shortening + . custom iter, db, env, cache implementations using just the C bindings + + Some conventions: + + (1) We expose just opaque struct pointers and functions to clients. + This allows us to change internal representations without having to + recompile clients. + + (2) For simplicity, there is no equivalent to the Slice type. Instead, + the caller has to pass the pointer and length as separate + arguments. + + (3) Errors are represented by a null-terminated c string. NULL + means no error. All operations that can raise an error are passed + a "char** errptr" as the last argument. One of the following must + be true on entry: + *errptr == NULL + *errptr points to a malloc()ed null-terminated error message + (On Windows, *errptr must have been malloc()-ed by this library.) + On success, a leveldb routine leaves *errptr unchanged. + On failure, leveldb frees the old value of *errptr and + set *errptr to a malloc()ed error message. + + (4) Bools have the type unsigned char (0 == false; rest == true) + + (5) All of the pointer arguments must be non-NULL. +*/ + +#ifndef STORAGE_LEVELDB_INCLUDE_C_H_ +#define STORAGE_LEVELDB_INCLUDE_C_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +#include +#include +#include + +/* Exported types */ + +typedef struct leveldb_t leveldb_t; +typedef struct leveldb_cache_t leveldb_cache_t; +typedef struct leveldb_comparator_t leveldb_comparator_t; +typedef struct leveldb_env_t leveldb_env_t; +typedef struct leveldb_filelock_t leveldb_filelock_t; +typedef struct leveldb_filterpolicy_t leveldb_filterpolicy_t; +typedef struct leveldb_iterator_t leveldb_iterator_t; +typedef struct leveldb_logger_t leveldb_logger_t; +typedef struct leveldb_options_t leveldb_options_t; +typedef struct leveldb_randomfile_t leveldb_randomfile_t; +typedef struct leveldb_readoptions_t leveldb_readoptions_t; +typedef struct leveldb_seqfile_t leveldb_seqfile_t; +typedef struct leveldb_snapshot_t leveldb_snapshot_t; +typedef struct leveldb_writablefile_t leveldb_writablefile_t; +typedef struct leveldb_writebatch_t leveldb_writebatch_t; +typedef struct leveldb_writeoptions_t leveldb_writeoptions_t; + +/* DB operations */ + +extern leveldb_t* leveldb_open( + const leveldb_options_t* options, + const char* name, + char** errptr); + +extern void leveldb_close(leveldb_t* db); + +extern void leveldb_put( + leveldb_t* db, + const leveldb_writeoptions_t* options, + const char* key, size_t keylen, + const char* val, size_t vallen, + char** errptr); + +extern void leveldb_delete( + leveldb_t* db, + const leveldb_writeoptions_t* options, + const char* key, size_t keylen, + char** errptr); + +extern void leveldb_write( + leveldb_t* db, + const leveldb_writeoptions_t* options, + leveldb_writebatch_t* batch, + char** errptr); + +/* Returns NULL if not found. A malloc()ed array otherwise. + Stores the length of the array in *vallen. */ +extern char* leveldb_get( + leveldb_t* db, + const leveldb_readoptions_t* options, + const char* key, size_t keylen, + size_t* vallen, + char** errptr); + +extern leveldb_iterator_t* leveldb_create_iterator( + leveldb_t* db, + const leveldb_readoptions_t* options); + +extern const leveldb_snapshot_t* leveldb_create_snapshot( + leveldb_t* db); + +extern void leveldb_release_snapshot( + leveldb_t* db, + const leveldb_snapshot_t* snapshot); + +/* Returns NULL if property name is unknown. + Else returns a pointer to a malloc()-ed null-terminated value. */ +extern char* leveldb_property_value( + leveldb_t* db, + const char* propname); + +extern void leveldb_approximate_sizes( + leveldb_t* db, + int num_ranges, + const char* const* range_start_key, const size_t* range_start_key_len, + const char* const* range_limit_key, const size_t* range_limit_key_len, + uint64_t* sizes); + +extern void leveldb_compact_range( + leveldb_t* db, + const char* start_key, size_t start_key_len, + const char* limit_key, size_t limit_key_len); + +/* Management operations */ + +extern void leveldb_destroy_db( + const leveldb_options_t* options, + const char* name, + char** errptr); + +extern void leveldb_repair_db( + const leveldb_options_t* options, + const char* name, + char** errptr); + +/* Iterator */ + +extern void leveldb_iter_destroy(leveldb_iterator_t*); +extern unsigned char leveldb_iter_valid(const leveldb_iterator_t*); +extern void leveldb_iter_seek_to_first(leveldb_iterator_t*); +extern void leveldb_iter_seek_to_last(leveldb_iterator_t*); +extern void leveldb_iter_seek(leveldb_iterator_t*, const char* k, size_t klen); +extern void leveldb_iter_next(leveldb_iterator_t*); +extern void leveldb_iter_prev(leveldb_iterator_t*); +extern const char* leveldb_iter_key(const leveldb_iterator_t*, size_t* klen); +extern const char* leveldb_iter_value(const leveldb_iterator_t*, size_t* vlen); +extern void leveldb_iter_get_error(const leveldb_iterator_t*, char** errptr); + +/* Write batch */ + +extern leveldb_writebatch_t* leveldb_writebatch_create(); +extern void leveldb_writebatch_destroy(leveldb_writebatch_t*); +extern void leveldb_writebatch_clear(leveldb_writebatch_t*); +extern void leveldb_writebatch_put( + leveldb_writebatch_t*, + const char* key, size_t klen, + const char* val, size_t vlen); +extern void leveldb_writebatch_delete( + leveldb_writebatch_t*, + const char* key, size_t klen); +extern void leveldb_writebatch_iterate( + leveldb_writebatch_t*, + void* state, + void (*put)(void*, const char* k, size_t klen, const char* v, size_t vlen), + void (*deleted)(void*, const char* k, size_t klen)); + +/* Options */ + +extern leveldb_options_t* leveldb_options_create(); +extern void leveldb_options_destroy(leveldb_options_t*); +extern void leveldb_options_set_comparator( + leveldb_options_t*, + leveldb_comparator_t*); +extern void leveldb_options_set_filter_policy( + leveldb_options_t*, + leveldb_filterpolicy_t*); +extern void leveldb_options_set_create_if_missing( + leveldb_options_t*, unsigned char); +extern void leveldb_options_set_error_if_exists( + leveldb_options_t*, unsigned char); +extern void leveldb_options_set_paranoid_checks( + leveldb_options_t*, unsigned char); +extern void leveldb_options_set_env(leveldb_options_t*, leveldb_env_t*); +extern void leveldb_options_set_info_log(leveldb_options_t*, leveldb_logger_t*); +extern void leveldb_options_set_write_buffer_size(leveldb_options_t*, size_t); +extern void leveldb_options_set_max_open_files(leveldb_options_t*, int); +extern void leveldb_options_set_cache(leveldb_options_t*, leveldb_cache_t*); +extern void leveldb_options_set_block_size(leveldb_options_t*, size_t); +extern void leveldb_options_set_block_restart_interval(leveldb_options_t*, int); + +enum { + leveldb_no_compression = 0, + leveldb_snappy_compression = 1 +}; +extern void leveldb_options_set_compression(leveldb_options_t*, int); + +/* Comparator */ + +extern leveldb_comparator_t* leveldb_comparator_create( + void* state, + void (*destructor)(void*), + int (*compare)( + void*, + const char* a, size_t alen, + const char* b, size_t blen), + const char* (*name)(void*)); +extern void leveldb_comparator_destroy(leveldb_comparator_t*); + +/* Filter policy */ + +extern leveldb_filterpolicy_t* leveldb_filterpolicy_create( + void* state, + void (*destructor)(void*), + char* (*create_filter)( + void*, + const char* const* key_array, const size_t* key_length_array, + int num_keys, + size_t* filter_length), + unsigned char (*key_may_match)( + void*, + const char* key, size_t length, + const char* filter, size_t filter_length), + const char* (*name)(void*)); +extern void leveldb_filterpolicy_destroy(leveldb_filterpolicy_t*); + +extern leveldb_filterpolicy_t* leveldb_filterpolicy_create_bloom( + int bits_per_key); + +/* Read options */ + +extern leveldb_readoptions_t* leveldb_readoptions_create(); +extern void leveldb_readoptions_destroy(leveldb_readoptions_t*); +extern void leveldb_readoptions_set_verify_checksums( + leveldb_readoptions_t*, + unsigned char); +extern void leveldb_readoptions_set_fill_cache( + leveldb_readoptions_t*, unsigned char); +extern void leveldb_readoptions_set_snapshot( + leveldb_readoptions_t*, + const leveldb_snapshot_t*); + +/* Write options */ + +extern leveldb_writeoptions_t* leveldb_writeoptions_create(); +extern void leveldb_writeoptions_destroy(leveldb_writeoptions_t*); +extern void leveldb_writeoptions_set_sync( + leveldb_writeoptions_t*, unsigned char); + +/* Cache */ + +extern leveldb_cache_t* leveldb_cache_create_lru(size_t capacity); +extern void leveldb_cache_destroy(leveldb_cache_t* cache); + +/* Env */ + +extern leveldb_env_t* leveldb_create_default_env(); +extern void leveldb_env_destroy(leveldb_env_t*); + +/* Utility */ + +/* Calls free(ptr). + REQUIRES: ptr was malloc()-ed and returned by one of the routines + in this file. Note that in certain cases (typically on Windows), you + may need to call this routine instead of free(ptr) to dispose of + malloc()-ed memory returned by this library. */ +extern void leveldb_free(void* ptr); + +/* Return the major version number for this release. */ +extern int leveldb_major_version(); + +/* Return the minor version number for this release. */ +extern int leveldb_minor_version(); + +#ifdef __cplusplus +} /* end extern "C" */ +#endif + +#endif /* STORAGE_LEVELDB_INCLUDE_C_H_ */ diff --git a/ios/Pods/leveldb-library/include/leveldb/cache.h b/ios/Pods/leveldb-library/include/leveldb/cache.h new file mode 100644 index 000000000..1a201e5e0 --- /dev/null +++ b/ios/Pods/leveldb-library/include/leveldb/cache.h @@ -0,0 +1,99 @@ +// Copyright (c) 2011 The LevelDB Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. See the AUTHORS file for names of contributors. +// +// A Cache is an interface that maps keys to values. It has internal +// synchronization and may be safely accessed concurrently from +// multiple threads. It may automatically evict entries to make room +// for new entries. Values have a specified charge against the cache +// capacity. For example, a cache where the values are variable +// length strings, may use the length of the string as the charge for +// the string. +// +// A builtin cache implementation with a least-recently-used eviction +// policy is provided. Clients may use their own implementations if +// they want something more sophisticated (like scan-resistance, a +// custom eviction policy, variable cache sizing, etc.) + +#ifndef STORAGE_LEVELDB_INCLUDE_CACHE_H_ +#define STORAGE_LEVELDB_INCLUDE_CACHE_H_ + +#include +#include "leveldb/slice.h" + +namespace leveldb { + +class Cache; + +// Create a new cache with a fixed size capacity. This implementation +// of Cache uses a least-recently-used eviction policy. +extern Cache* NewLRUCache(size_t capacity); + +class Cache { + public: + Cache() { } + + // Destroys all existing entries by calling the "deleter" + // function that was passed to the constructor. + virtual ~Cache(); + + // Opaque handle to an entry stored in the cache. + struct Handle { }; + + // Insert a mapping from key->value into the cache and assign it + // the specified charge against the total cache capacity. + // + // Returns a handle that corresponds to the mapping. The caller + // must call this->Release(handle) when the returned mapping is no + // longer needed. + // + // When the inserted entry is no longer needed, the key and + // value will be passed to "deleter". + virtual Handle* Insert(const Slice& key, void* value, size_t charge, + void (*deleter)(const Slice& key, void* value)) = 0; + + // If the cache has no mapping for "key", returns NULL. + // + // Else return a handle that corresponds to the mapping. The caller + // must call this->Release(handle) when the returned mapping is no + // longer needed. + virtual Handle* Lookup(const Slice& key) = 0; + + // Release a mapping returned by a previous Lookup(). + // REQUIRES: handle must not have been released yet. + // REQUIRES: handle must have been returned by a method on *this. + virtual void Release(Handle* handle) = 0; + + // Return the value encapsulated in a handle returned by a + // successful Lookup(). + // REQUIRES: handle must not have been released yet. + // REQUIRES: handle must have been returned by a method on *this. + virtual void* Value(Handle* handle) = 0; + + // If the cache contains entry for key, erase it. Note that the + // underlying entry will be kept around until all existing handles + // to it have been released. + virtual void Erase(const Slice& key) = 0; + + // Return a new numeric id. May be used by multiple clients who are + // sharing the same cache to partition the key space. Typically the + // client will allocate a new id at startup and prepend the id to + // its cache keys. + virtual uint64_t NewId() = 0; + + private: + void LRU_Remove(Handle* e); + void LRU_Append(Handle* e); + void Unref(Handle* e); + + struct Rep; + Rep* rep_; + + // No copying allowed + Cache(const Cache&); + void operator=(const Cache&); +}; + +} // namespace leveldb + +#endif // STORAGE_LEVELDB_INCLUDE_CACHE_H_ diff --git a/ios/Pods/leveldb-library/include/leveldb/comparator.h b/ios/Pods/leveldb-library/include/leveldb/comparator.h new file mode 100644 index 000000000..556b984c7 --- /dev/null +++ b/ios/Pods/leveldb-library/include/leveldb/comparator.h @@ -0,0 +1,63 @@ +// Copyright (c) 2011 The LevelDB Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. See the AUTHORS file for names of contributors. + +#ifndef STORAGE_LEVELDB_INCLUDE_COMPARATOR_H_ +#define STORAGE_LEVELDB_INCLUDE_COMPARATOR_H_ + +#include + +namespace leveldb { + +class Slice; + +// A Comparator object provides a total order across slices that are +// used as keys in an sstable or a database. A Comparator implementation +// must be thread-safe since leveldb may invoke its methods concurrently +// from multiple threads. +class Comparator { + public: + virtual ~Comparator(); + + // Three-way comparison. Returns value: + // < 0 iff "a" < "b", + // == 0 iff "a" == "b", + // > 0 iff "a" > "b" + virtual int Compare(const Slice& a, const Slice& b) const = 0; + + // The name of the comparator. Used to check for comparator + // mismatches (i.e., a DB created with one comparator is + // accessed using a different comparator. + // + // The client of this package should switch to a new name whenever + // the comparator implementation changes in a way that will cause + // the relative ordering of any two keys to change. + // + // Names starting with "leveldb." are reserved and should not be used + // by any clients of this package. + virtual const char* Name() const = 0; + + // Advanced functions: these are used to reduce the space requirements + // for internal data structures like index blocks. + + // If *start < limit, changes *start to a short string in [start,limit). + // Simple comparator implementations may return with *start unchanged, + // i.e., an implementation of this method that does nothing is correct. + virtual void FindShortestSeparator( + std::string* start, + const Slice& limit) const = 0; + + // Changes *key to a short string >= *key. + // Simple comparator implementations may return with *key unchanged, + // i.e., an implementation of this method that does nothing is correct. + virtual void FindShortSuccessor(std::string* key) const = 0; +}; + +// Return a builtin comparator that uses lexicographic byte-wise +// ordering. The result remains the property of this module and +// must not be deleted. +extern const Comparator* BytewiseComparator(); + +} // namespace leveldb + +#endif // STORAGE_LEVELDB_INCLUDE_COMPARATOR_H_ diff --git a/ios/Pods/leveldb-library/include/leveldb/db.h b/ios/Pods/leveldb-library/include/leveldb/db.h new file mode 100644 index 000000000..4c169bf22 --- /dev/null +++ b/ios/Pods/leveldb-library/include/leveldb/db.h @@ -0,0 +1,161 @@ +// Copyright (c) 2011 The LevelDB Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. See the AUTHORS file for names of contributors. + +#ifndef STORAGE_LEVELDB_INCLUDE_DB_H_ +#define STORAGE_LEVELDB_INCLUDE_DB_H_ + +#include +#include +#include "leveldb/iterator.h" +#include "leveldb/options.h" + +namespace leveldb { + +// Update Makefile if you change these +static const int kMajorVersion = 1; +static const int kMinorVersion = 18; + +struct Options; +struct ReadOptions; +struct WriteOptions; +class WriteBatch; + +// Abstract handle to particular state of a DB. +// A Snapshot is an immutable object and can therefore be safely +// accessed from multiple threads without any external synchronization. +class Snapshot { + protected: + virtual ~Snapshot(); +}; + +// A range of keys +struct Range { + Slice start; // Included in the range + Slice limit; // Not included in the range + + Range() { } + Range(const Slice& s, const Slice& l) : start(s), limit(l) { } +}; + +// A DB is a persistent ordered map from keys to values. +// A DB is safe for concurrent access from multiple threads without +// any external synchronization. +class DB { + public: + // Open the database with the specified "name". + // Stores a pointer to a heap-allocated database in *dbptr and returns + // OK on success. + // Stores NULL in *dbptr and returns a non-OK status on error. + // Caller should delete *dbptr when it is no longer needed. + static Status Open(const Options& options, + const std::string& name, + DB** dbptr); + + DB() { } + virtual ~DB(); + + // Set the database entry for "key" to "value". Returns OK on success, + // and a non-OK status on error. + // Note: consider setting options.sync = true. + virtual Status Put(const WriteOptions& options, + const Slice& key, + const Slice& value) = 0; + + // Remove the database entry (if any) for "key". Returns OK on + // success, and a non-OK status on error. It is not an error if "key" + // did not exist in the database. + // Note: consider setting options.sync = true. + virtual Status Delete(const WriteOptions& options, const Slice& key) = 0; + + // Apply the specified updates to the database. + // Returns OK on success, non-OK on failure. + // Note: consider setting options.sync = true. + virtual Status Write(const WriteOptions& options, WriteBatch* updates) = 0; + + // If the database contains an entry for "key" store the + // corresponding value in *value and return OK. + // + // If there is no entry for "key" leave *value unchanged and return + // a status for which Status::IsNotFound() returns true. + // + // May return some other Status on an error. + virtual Status Get(const ReadOptions& options, + const Slice& key, std::string* value) = 0; + + // Return a heap-allocated iterator over the contents of the database. + // The result of NewIterator() is initially invalid (caller must + // call one of the Seek methods on the iterator before using it). + // + // Caller should delete the iterator when it is no longer needed. + // The returned iterator should be deleted before this db is deleted. + virtual Iterator* NewIterator(const ReadOptions& options) = 0; + + // Return a handle to the current DB state. Iterators created with + // this handle will all observe a stable snapshot of the current DB + // state. The caller must call ReleaseSnapshot(result) when the + // snapshot is no longer needed. + virtual const Snapshot* GetSnapshot() = 0; + + // Release a previously acquired snapshot. The caller must not + // use "snapshot" after this call. + virtual void ReleaseSnapshot(const Snapshot* snapshot) = 0; + + // DB implementations can export properties about their state + // via this method. If "property" is a valid property understood by this + // DB implementation, fills "*value" with its current value and returns + // true. Otherwise returns false. + // + // + // Valid property names include: + // + // "leveldb.num-files-at-level" - return the number of files at level , + // where is an ASCII representation of a level number (e.g. "0"). + // "leveldb.stats" - returns a multi-line string that describes statistics + // about the internal operation of the DB. + // "leveldb.sstables" - returns a multi-line string that describes all + // of the sstables that make up the db contents. + virtual bool GetProperty(const Slice& property, std::string* value) = 0; + + // For each i in [0,n-1], store in "sizes[i]", the approximate + // file system space used by keys in "[range[i].start .. range[i].limit)". + // + // Note that the returned sizes measure file system space usage, so + // if the user data compresses by a factor of ten, the returned + // sizes will be one-tenth the size of the corresponding user data size. + // + // The results may not include the sizes of recently written data. + virtual void GetApproximateSizes(const Range* range, int n, + uint64_t* sizes) = 0; + + // Compact the underlying storage for the key range [*begin,*end]. + // In particular, deleted and overwritten versions are discarded, + // and the data is rearranged to reduce the cost of operations + // needed to access the data. This operation should typically only + // be invoked by users who understand the underlying implementation. + // + // begin==NULL is treated as a key before all keys in the database. + // end==NULL is treated as a key after all keys in the database. + // Therefore the following call will compact the entire database: + // db->CompactRange(NULL, NULL); + virtual void CompactRange(const Slice* begin, const Slice* end) = 0; + + private: + // No copying allowed + DB(const DB&); + void operator=(const DB&); +}; + +// Destroy the contents of the specified database. +// Be very careful using this method. +Status DestroyDB(const std::string& name, const Options& options); + +// If a DB cannot be opened, you may attempt to call this method to +// resurrect as much of the contents of the database as possible. +// Some data may be lost, so be careful when calling this function +// on a database that contains important information. +Status RepairDB(const std::string& dbname, const Options& options); + +} // namespace leveldb + +#endif // STORAGE_LEVELDB_INCLUDE_DB_H_ diff --git a/ios/Pods/leveldb-library/include/leveldb/dumpfile.h b/ios/Pods/leveldb-library/include/leveldb/dumpfile.h new file mode 100644 index 000000000..3f97fda16 --- /dev/null +++ b/ios/Pods/leveldb-library/include/leveldb/dumpfile.h @@ -0,0 +1,25 @@ +// Copyright (c) 2014 The LevelDB Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. See the AUTHORS file for names of contributors. + +#ifndef STORAGE_LEVELDB_INCLUDE_DUMPFILE_H_ +#define STORAGE_LEVELDB_INCLUDE_DUMPFILE_H_ + +#include +#include "leveldb/env.h" +#include "leveldb/status.h" + +namespace leveldb { + +// Dump the contents of the file named by fname in text format to +// *dst. Makes a sequence of dst->Append() calls; each call is passed +// the newline-terminated text corresponding to a single item found +// in the file. +// +// Returns a non-OK result if fname does not name a leveldb storage +// file, or if the file cannot be read. +Status DumpFile(Env* env, const std::string& fname, WritableFile* dst); + +} // namespace leveldb + +#endif // STORAGE_LEVELDB_INCLUDE_DUMPFILE_H_ diff --git a/ios/Pods/leveldb-library/include/leveldb/env.h b/ios/Pods/leveldb-library/include/leveldb/env.h new file mode 100644 index 000000000..f709514da --- /dev/null +++ b/ios/Pods/leveldb-library/include/leveldb/env.h @@ -0,0 +1,333 @@ +// Copyright (c) 2011 The LevelDB Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. See the AUTHORS file for names of contributors. +// +// An Env is an interface used by the leveldb implementation to access +// operating system functionality like the filesystem etc. Callers +// may wish to provide a custom Env object when opening a database to +// get fine gain control; e.g., to rate limit file system operations. +// +// All Env implementations are safe for concurrent access from +// multiple threads without any external synchronization. + +#ifndef STORAGE_LEVELDB_INCLUDE_ENV_H_ +#define STORAGE_LEVELDB_INCLUDE_ENV_H_ + +#include +#include +#include +#include +#include "leveldb/status.h" + +namespace leveldb { + +class FileLock; +class Logger; +class RandomAccessFile; +class SequentialFile; +class Slice; +class WritableFile; + +class Env { + public: + Env() { } + virtual ~Env(); + + // Return a default environment suitable for the current operating + // system. Sophisticated users may wish to provide their own Env + // implementation instead of relying on this default environment. + // + // The result of Default() belongs to leveldb and must never be deleted. + static Env* Default(); + + // Create a brand new sequentially-readable file with the specified name. + // On success, stores a pointer to the new file in *result and returns OK. + // On failure stores NULL in *result and returns non-OK. If the file does + // not exist, returns a non-OK status. + // + // The returned file will only be accessed by one thread at a time. + virtual Status NewSequentialFile(const std::string& fname, + SequentialFile** result) = 0; + + // Create a brand new random access read-only file with the + // specified name. On success, stores a pointer to the new file in + // *result and returns OK. On failure stores NULL in *result and + // returns non-OK. If the file does not exist, returns a non-OK + // status. + // + // The returned file may be concurrently accessed by multiple threads. + virtual Status NewRandomAccessFile(const std::string& fname, + RandomAccessFile** result) = 0; + + // Create an object that writes to a new file with the specified + // name. Deletes any existing file with the same name and creates a + // new file. On success, stores a pointer to the new file in + // *result and returns OK. On failure stores NULL in *result and + // returns non-OK. + // + // The returned file will only be accessed by one thread at a time. + virtual Status NewWritableFile(const std::string& fname, + WritableFile** result) = 0; + + // Returns true iff the named file exists. + virtual bool FileExists(const std::string& fname) = 0; + + // Store in *result the names of the children of the specified directory. + // The names are relative to "dir". + // Original contents of *results are dropped. + virtual Status GetChildren(const std::string& dir, + std::vector* result) = 0; + + // Delete the named file. + virtual Status DeleteFile(const std::string& fname) = 0; + + // Create the specified directory. + virtual Status CreateDir(const std::string& dirname) = 0; + + // Delete the specified directory. + virtual Status DeleteDir(const std::string& dirname) = 0; + + // Store the size of fname in *file_size. + virtual Status GetFileSize(const std::string& fname, uint64_t* file_size) = 0; + + // Rename file src to target. + virtual Status RenameFile(const std::string& src, + const std::string& target) = 0; + + // Lock the specified file. Used to prevent concurrent access to + // the same db by multiple processes. On failure, stores NULL in + // *lock and returns non-OK. + // + // On success, stores a pointer to the object that represents the + // acquired lock in *lock and returns OK. The caller should call + // UnlockFile(*lock) to release the lock. If the process exits, + // the lock will be automatically released. + // + // If somebody else already holds the lock, finishes immediately + // with a failure. I.e., this call does not wait for existing locks + // to go away. + // + // May create the named file if it does not already exist. + virtual Status LockFile(const std::string& fname, FileLock** lock) = 0; + + // Release the lock acquired by a previous successful call to LockFile. + // REQUIRES: lock was returned by a successful LockFile() call + // REQUIRES: lock has not already been unlocked. + virtual Status UnlockFile(FileLock* lock) = 0; + + // Arrange to run "(*function)(arg)" once in a background thread. + // + // "function" may run in an unspecified thread. Multiple functions + // added to the same Env may run concurrently in different threads. + // I.e., the caller may not assume that background work items are + // serialized. + virtual void Schedule( + void (*function)(void* arg), + void* arg) = 0; + + // Start a new thread, invoking "function(arg)" within the new thread. + // When "function(arg)" returns, the thread will be destroyed. + virtual void StartThread(void (*function)(void* arg), void* arg) = 0; + + // *path is set to a temporary directory that can be used for testing. It may + // or many not have just been created. The directory may or may not differ + // between runs of the same process, but subsequent calls will return the + // same directory. + virtual Status GetTestDirectory(std::string* path) = 0; + + // Create and return a log file for storing informational messages. + virtual Status NewLogger(const std::string& fname, Logger** result) = 0; + + // Returns the number of micro-seconds since some fixed point in time. Only + // useful for computing deltas of time. + virtual uint64_t NowMicros() = 0; + + // Sleep/delay the thread for the prescribed number of micro-seconds. + virtual void SleepForMicroseconds(int micros) = 0; + + private: + // No copying allowed + Env(const Env&); + void operator=(const Env&); +}; + +// A file abstraction for reading sequentially through a file +class SequentialFile { + public: + SequentialFile() { } + virtual ~SequentialFile(); + + // Read up to "n" bytes from the file. "scratch[0..n-1]" may be + // written by this routine. Sets "*result" to the data that was + // read (including if fewer than "n" bytes were successfully read). + // May set "*result" to point at data in "scratch[0..n-1]", so + // "scratch[0..n-1]" must be live when "*result" is used. + // If an error was encountered, returns a non-OK status. + // + // REQUIRES: External synchronization + virtual Status Read(size_t n, Slice* result, char* scratch) = 0; + + // Skip "n" bytes from the file. This is guaranteed to be no + // slower that reading the same data, but may be faster. + // + // If end of file is reached, skipping will stop at the end of the + // file, and Skip will return OK. + // + // REQUIRES: External synchronization + virtual Status Skip(uint64_t n) = 0; + + private: + // No copying allowed + SequentialFile(const SequentialFile&); + void operator=(const SequentialFile&); +}; + +// A file abstraction for randomly reading the contents of a file. +class RandomAccessFile { + public: + RandomAccessFile() { } + virtual ~RandomAccessFile(); + + // Read up to "n" bytes from the file starting at "offset". + // "scratch[0..n-1]" may be written by this routine. Sets "*result" + // to the data that was read (including if fewer than "n" bytes were + // successfully read). May set "*result" to point at data in + // "scratch[0..n-1]", so "scratch[0..n-1]" must be live when + // "*result" is used. If an error was encountered, returns a non-OK + // status. + // + // Safe for concurrent use by multiple threads. + virtual Status Read(uint64_t offset, size_t n, Slice* result, + char* scratch) const = 0; + + private: + // No copying allowed + RandomAccessFile(const RandomAccessFile&); + void operator=(const RandomAccessFile&); +}; + +// A file abstraction for sequential writing. The implementation +// must provide buffering since callers may append small fragments +// at a time to the file. +class WritableFile { + public: + WritableFile() { } + virtual ~WritableFile(); + + virtual Status Append(const Slice& data) = 0; + virtual Status Close() = 0; + virtual Status Flush() = 0; + virtual Status Sync() = 0; + + private: + // No copying allowed + WritableFile(const WritableFile&); + void operator=(const WritableFile&); +}; + +// An interface for writing log messages. +class Logger { + public: + Logger() { } + virtual ~Logger(); + + // Write an entry to the log file with the specified format. + virtual void Logv(const char* format, va_list ap) = 0; + + private: + // No copying allowed + Logger(const Logger&); + void operator=(const Logger&); +}; + + +// Identifies a locked file. +class FileLock { + public: + FileLock() { } + virtual ~FileLock(); + private: + // No copying allowed + FileLock(const FileLock&); + void operator=(const FileLock&); +}; + +// Log the specified data to *info_log if info_log is non-NULL. +extern void Log(Logger* info_log, const char* format, ...) +# if defined(__GNUC__) || defined(__clang__) + __attribute__((__format__ (__printf__, 2, 3))) +# endif + ; + +// A utility routine: write "data" to the named file. +extern Status WriteStringToFile(Env* env, const Slice& data, + const std::string& fname); + +// A utility routine: read contents of named file into *data +extern Status ReadFileToString(Env* env, const std::string& fname, + std::string* data); + +// An implementation of Env that forwards all calls to another Env. +// May be useful to clients who wish to override just part of the +// functionality of another Env. +class EnvWrapper : public Env { + public: + // Initialize an EnvWrapper that delegates all calls to *t + explicit EnvWrapper(Env* t) : target_(t) { } + virtual ~EnvWrapper(); + + // Return the target to which this Env forwards all calls + Env* target() const { return target_; } + + // The following text is boilerplate that forwards all methods to target() + Status NewSequentialFile(const std::string& f, SequentialFile** r) { + return target_->NewSequentialFile(f, r); + } + Status NewRandomAccessFile(const std::string& f, RandomAccessFile** r) { + return target_->NewRandomAccessFile(f, r); + } + Status NewWritableFile(const std::string& f, WritableFile** r) { + return target_->NewWritableFile(f, r); + } + bool FileExists(const std::string& f) { return target_->FileExists(f); } + Status GetChildren(const std::string& dir, std::vector* r) { + return target_->GetChildren(dir, r); + } + Status DeleteFile(const std::string& f) { return target_->DeleteFile(f); } + Status CreateDir(const std::string& d) { return target_->CreateDir(d); } + Status DeleteDir(const std::string& d) { return target_->DeleteDir(d); } + Status GetFileSize(const std::string& f, uint64_t* s) { + return target_->GetFileSize(f, s); + } + Status RenameFile(const std::string& s, const std::string& t) { + return target_->RenameFile(s, t); + } + Status LockFile(const std::string& f, FileLock** l) { + return target_->LockFile(f, l); + } + Status UnlockFile(FileLock* l) { return target_->UnlockFile(l); } + void Schedule(void (*f)(void*), void* a) { + return target_->Schedule(f, a); + } + void StartThread(void (*f)(void*), void* a) { + return target_->StartThread(f, a); + } + virtual Status GetTestDirectory(std::string* path) { + return target_->GetTestDirectory(path); + } + virtual Status NewLogger(const std::string& fname, Logger** result) { + return target_->NewLogger(fname, result); + } + uint64_t NowMicros() { + return target_->NowMicros(); + } + void SleepForMicroseconds(int micros) { + target_->SleepForMicroseconds(micros); + } + private: + Env* target_; +}; + +} // namespace leveldb + +#endif // STORAGE_LEVELDB_INCLUDE_ENV_H_ diff --git a/ios/Pods/leveldb-library/include/leveldb/filter_policy.h b/ios/Pods/leveldb-library/include/leveldb/filter_policy.h new file mode 100644 index 000000000..1fba08001 --- /dev/null +++ b/ios/Pods/leveldb-library/include/leveldb/filter_policy.h @@ -0,0 +1,70 @@ +// Copyright (c) 2012 The LevelDB Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. See the AUTHORS file for names of contributors. +// +// A database can be configured with a custom FilterPolicy object. +// This object is responsible for creating a small filter from a set +// of keys. These filters are stored in leveldb and are consulted +// automatically by leveldb to decide whether or not to read some +// information from disk. In many cases, a filter can cut down the +// number of disk seeks form a handful to a single disk seek per +// DB::Get() call. +// +// Most people will want to use the builtin bloom filter support (see +// NewBloomFilterPolicy() below). + +#ifndef STORAGE_LEVELDB_INCLUDE_FILTER_POLICY_H_ +#define STORAGE_LEVELDB_INCLUDE_FILTER_POLICY_H_ + +#include + +namespace leveldb { + +class Slice; + +class FilterPolicy { + public: + virtual ~FilterPolicy(); + + // Return the name of this policy. Note that if the filter encoding + // changes in an incompatible way, the name returned by this method + // must be changed. Otherwise, old incompatible filters may be + // passed to methods of this type. + virtual const char* Name() const = 0; + + // keys[0,n-1] contains a list of keys (potentially with duplicates) + // that are ordered according to the user supplied comparator. + // Append a filter that summarizes keys[0,n-1] to *dst. + // + // Warning: do not change the initial contents of *dst. Instead, + // append the newly constructed filter to *dst. + virtual void CreateFilter(const Slice* keys, int n, std::string* dst) + const = 0; + + // "filter" contains the data appended by a preceding call to + // CreateFilter() on this class. This method must return true if + // the key was in the list of keys passed to CreateFilter(). + // This method may return true or false if the key was not on the + // list, but it should aim to return false with a high probability. + virtual bool KeyMayMatch(const Slice& key, const Slice& filter) const = 0; +}; + +// Return a new filter policy that uses a bloom filter with approximately +// the specified number of bits per key. A good value for bits_per_key +// is 10, which yields a filter with ~ 1% false positive rate. +// +// Callers must delete the result after any database that is using the +// result has been closed. +// +// Note: if you are using a custom comparator that ignores some parts +// of the keys being compared, you must not use NewBloomFilterPolicy() +// and must provide your own FilterPolicy that also ignores the +// corresponding parts of the keys. For example, if the comparator +// ignores trailing spaces, it would be incorrect to use a +// FilterPolicy (like NewBloomFilterPolicy) that does not ignore +// trailing spaces in keys. +extern const FilterPolicy* NewBloomFilterPolicy(int bits_per_key); + +} + +#endif // STORAGE_LEVELDB_INCLUDE_FILTER_POLICY_H_ diff --git a/ios/Pods/leveldb-library/include/leveldb/iterator.h b/ios/Pods/leveldb-library/include/leveldb/iterator.h new file mode 100644 index 000000000..76aced04b --- /dev/null +++ b/ios/Pods/leveldb-library/include/leveldb/iterator.h @@ -0,0 +1,100 @@ +// Copyright (c) 2011 The LevelDB Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. See the AUTHORS file for names of contributors. +// +// An iterator yields a sequence of key/value pairs from a source. +// The following class defines the interface. Multiple implementations +// are provided by this library. In particular, iterators are provided +// to access the contents of a Table or a DB. +// +// Multiple threads can invoke const methods on an Iterator without +// external synchronization, but if any of the threads may call a +// non-const method, all threads accessing the same Iterator must use +// external synchronization. + +#ifndef STORAGE_LEVELDB_INCLUDE_ITERATOR_H_ +#define STORAGE_LEVELDB_INCLUDE_ITERATOR_H_ + +#include "leveldb/slice.h" +#include "leveldb/status.h" + +namespace leveldb { + +class Iterator { + public: + Iterator(); + virtual ~Iterator(); + + // An iterator is either positioned at a key/value pair, or + // not valid. This method returns true iff the iterator is valid. + virtual bool Valid() const = 0; + + // Position at the first key in the source. The iterator is Valid() + // after this call iff the source is not empty. + virtual void SeekToFirst() = 0; + + // Position at the last key in the source. The iterator is + // Valid() after this call iff the source is not empty. + virtual void SeekToLast() = 0; + + // Position at the first key in the source that at or past target + // The iterator is Valid() after this call iff the source contains + // an entry that comes at or past target. + virtual void Seek(const Slice& target) = 0; + + // Moves to the next entry in the source. After this call, Valid() is + // true iff the iterator was not positioned at the last entry in the source. + // REQUIRES: Valid() + virtual void Next() = 0; + + // Moves to the previous entry in the source. After this call, Valid() is + // true iff the iterator was not positioned at the first entry in source. + // REQUIRES: Valid() + virtual void Prev() = 0; + + // Return the key for the current entry. The underlying storage for + // the returned slice is valid only until the next modification of + // the iterator. + // REQUIRES: Valid() + virtual Slice key() const = 0; + + // Return the value for the current entry. The underlying storage for + // the returned slice is valid only until the next modification of + // the iterator. + // REQUIRES: Valid() + virtual Slice value() const = 0; + + // If an error has occurred, return it. Else return an ok status. + virtual Status status() const = 0; + + // Clients are allowed to register function/arg1/arg2 triples that + // will be invoked when this iterator is destroyed. + // + // Note that unlike all of the preceding methods, this method is + // not abstract and therefore clients should not override it. + typedef void (*CleanupFunction)(void* arg1, void* arg2); + void RegisterCleanup(CleanupFunction function, void* arg1, void* arg2); + + private: + struct Cleanup { + CleanupFunction function; + void* arg1; + void* arg2; + Cleanup* next; + }; + Cleanup cleanup_; + + // No copying allowed + Iterator(const Iterator&); + void operator=(const Iterator&); +}; + +// Return an empty iterator (yields nothing). +extern Iterator* NewEmptyIterator(); + +// Return an empty iterator with the specified status. +extern Iterator* NewErrorIterator(const Status& status); + +} // namespace leveldb + +#endif // STORAGE_LEVELDB_INCLUDE_ITERATOR_H_ diff --git a/ios/Pods/leveldb-library/include/leveldb/options.h b/ios/Pods/leveldb-library/include/leveldb/options.h new file mode 100644 index 000000000..7c9b97345 --- /dev/null +++ b/ios/Pods/leveldb-library/include/leveldb/options.h @@ -0,0 +1,195 @@ +// Copyright (c) 2011 The LevelDB Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. See the AUTHORS file for names of contributors. + +#ifndef STORAGE_LEVELDB_INCLUDE_OPTIONS_H_ +#define STORAGE_LEVELDB_INCLUDE_OPTIONS_H_ + +#include + +namespace leveldb { + +class Cache; +class Comparator; +class Env; +class FilterPolicy; +class Logger; +class Snapshot; + +// DB contents are stored in a set of blocks, each of which holds a +// sequence of key,value pairs. Each block may be compressed before +// being stored in a file. The following enum describes which +// compression method (if any) is used to compress a block. +enum CompressionType { + // NOTE: do not change the values of existing entries, as these are + // part of the persistent format on disk. + kNoCompression = 0x0, + kSnappyCompression = 0x1 +}; + +// Options to control the behavior of a database (passed to DB::Open) +struct Options { + // ------------------- + // Parameters that affect behavior + + // Comparator used to define the order of keys in the table. + // Default: a comparator that uses lexicographic byte-wise ordering + // + // REQUIRES: The client must ensure that the comparator supplied + // here has the same name and orders keys *exactly* the same as the + // comparator provided to previous open calls on the same DB. + const Comparator* comparator; + + // If true, the database will be created if it is missing. + // Default: false + bool create_if_missing; + + // If true, an error is raised if the database already exists. + // Default: false + bool error_if_exists; + + // If true, the implementation will do aggressive checking of the + // data it is processing and will stop early if it detects any + // errors. This may have unforeseen ramifications: for example, a + // corruption of one DB entry may cause a large number of entries to + // become unreadable or for the entire DB to become unopenable. + // Default: false + bool paranoid_checks; + + // Use the specified object to interact with the environment, + // e.g. to read/write files, schedule background work, etc. + // Default: Env::Default() + Env* env; + + // Any internal progress/error information generated by the db will + // be written to info_log if it is non-NULL, or to a file stored + // in the same directory as the DB contents if info_log is NULL. + // Default: NULL + Logger* info_log; + + // ------------------- + // Parameters that affect performance + + // Amount of data to build up in memory (backed by an unsorted log + // on disk) before converting to a sorted on-disk file. + // + // Larger values increase performance, especially during bulk loads. + // Up to two write buffers may be held in memory at the same time, + // so you may wish to adjust this parameter to control memory usage. + // Also, a larger write buffer will result in a longer recovery time + // the next time the database is opened. + // + // Default: 4MB + size_t write_buffer_size; + + // Number of open files that can be used by the DB. You may need to + // increase this if your database has a large working set (budget + // one open file per 2MB of working set). + // + // Default: 1000 + int max_open_files; + + // Control over blocks (user data is stored in a set of blocks, and + // a block is the unit of reading from disk). + + // If non-NULL, use the specified cache for blocks. + // If NULL, leveldb will automatically create and use an 8MB internal cache. + // Default: NULL + Cache* block_cache; + + // Approximate size of user data packed per block. Note that the + // block size specified here corresponds to uncompressed data. The + // actual size of the unit read from disk may be smaller if + // compression is enabled. This parameter can be changed dynamically. + // + // Default: 4K + size_t block_size; + + // Number of keys between restart points for delta encoding of keys. + // This parameter can be changed dynamically. Most clients should + // leave this parameter alone. + // + // Default: 16 + int block_restart_interval; + + // Compress blocks using the specified compression algorithm. This + // parameter can be changed dynamically. + // + // Default: kSnappyCompression, which gives lightweight but fast + // compression. + // + // Typical speeds of kSnappyCompression on an Intel(R) Core(TM)2 2.4GHz: + // ~200-500MB/s compression + // ~400-800MB/s decompression + // Note that these speeds are significantly faster than most + // persistent storage speeds, and therefore it is typically never + // worth switching to kNoCompression. Even if the input data is + // incompressible, the kSnappyCompression implementation will + // efficiently detect that and will switch to uncompressed mode. + CompressionType compression; + + // If non-NULL, use the specified filter policy to reduce disk reads. + // Many applications will benefit from passing the result of + // NewBloomFilterPolicy() here. + // + // Default: NULL + const FilterPolicy* filter_policy; + + // Create an Options object with default values for all fields. + Options(); +}; + +// Options that control read operations +struct ReadOptions { + // If true, all data read from underlying storage will be + // verified against corresponding checksums. + // Default: false + bool verify_checksums; + + // Should the data read for this iteration be cached in memory? + // Callers may wish to set this field to false for bulk scans. + // Default: true + bool fill_cache; + + // If "snapshot" is non-NULL, read as of the supplied snapshot + // (which must belong to the DB that is being read and which must + // not have been released). If "snapshot" is NULL, use an implicit + // snapshot of the state at the beginning of this read operation. + // Default: NULL + const Snapshot* snapshot; + + ReadOptions() + : verify_checksums(false), + fill_cache(true), + snapshot(NULL) { + } +}; + +// Options that control write operations +struct WriteOptions { + // If true, the write will be flushed from the operating system + // buffer cache (by calling WritableFile::Sync()) before the write + // is considered complete. If this flag is true, writes will be + // slower. + // + // If this flag is false, and the machine crashes, some recent + // writes may be lost. Note that if it is just the process that + // crashes (i.e., the machine does not reboot), no writes will be + // lost even if sync==false. + // + // In other words, a DB write with sync==false has similar + // crash semantics as the "write()" system call. A DB write + // with sync==true has similar crash semantics to a "write()" + // system call followed by "fsync()". + // + // Default: false + bool sync; + + WriteOptions() + : sync(false) { + } +}; + +} // namespace leveldb + +#endif // STORAGE_LEVELDB_INCLUDE_OPTIONS_H_ diff --git a/ios/Pods/leveldb-library/include/leveldb/slice.h b/ios/Pods/leveldb-library/include/leveldb/slice.h new file mode 100644 index 000000000..bc367986f --- /dev/null +++ b/ios/Pods/leveldb-library/include/leveldb/slice.h @@ -0,0 +1,109 @@ +// Copyright (c) 2011 The LevelDB Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. See the AUTHORS file for names of contributors. +// +// Slice is a simple structure containing a pointer into some external +// storage and a size. The user of a Slice must ensure that the slice +// is not used after the corresponding external storage has been +// deallocated. +// +// Multiple threads can invoke const methods on a Slice without +// external synchronization, but if any of the threads may call a +// non-const method, all threads accessing the same Slice must use +// external synchronization. + +#ifndef STORAGE_LEVELDB_INCLUDE_SLICE_H_ +#define STORAGE_LEVELDB_INCLUDE_SLICE_H_ + +#include +#include +#include +#include + +namespace leveldb { + +class Slice { + public: + // Create an empty slice. + Slice() : data_(""), size_(0) { } + + // Create a slice that refers to d[0,n-1]. + Slice(const char* d, size_t n) : data_(d), size_(n) { } + + // Create a slice that refers to the contents of "s" + Slice(const std::string& s) : data_(s.data()), size_(s.size()) { } + + // Create a slice that refers to s[0,strlen(s)-1] + Slice(const char* s) : data_(s), size_(strlen(s)) { } + + // Return a pointer to the beginning of the referenced data + const char* data() const { return data_; } + + // Return the length (in bytes) of the referenced data + size_t size() const { return size_; } + + // Return true iff the length of the referenced data is zero + bool empty() const { return size_ == 0; } + + // Return the ith byte in the referenced data. + // REQUIRES: n < size() + char operator[](size_t n) const { + assert(n < size()); + return data_[n]; + } + + // Change this slice to refer to an empty array + void clear() { data_ = ""; size_ = 0; } + + // Drop the first "n" bytes from this slice. + void remove_prefix(size_t n) { + assert(n <= size()); + data_ += n; + size_ -= n; + } + + // Return a string that contains the copy of the referenced data. + std::string ToString() const { return std::string(data_, size_); } + + // Three-way comparison. Returns value: + // < 0 iff "*this" < "b", + // == 0 iff "*this" == "b", + // > 0 iff "*this" > "b" + int compare(const Slice& b) const; + + // Return true iff "x" is a prefix of "*this" + bool starts_with(const Slice& x) const { + return ((size_ >= x.size_) && + (memcmp(data_, x.data_, x.size_) == 0)); + } + + private: + const char* data_; + size_t size_; + + // Intentionally copyable +}; + +inline bool operator==(const Slice& x, const Slice& y) { + return ((x.size() == y.size()) && + (memcmp(x.data(), y.data(), x.size()) == 0)); +} + +inline bool operator!=(const Slice& x, const Slice& y) { + return !(x == y); +} + +inline int Slice::compare(const Slice& b) const { + const size_t min_len = (size_ < b.size_) ? size_ : b.size_; + int r = memcmp(data_, b.data_, min_len); + if (r == 0) { + if (size_ < b.size_) r = -1; + else if (size_ > b.size_) r = +1; + } + return r; +} + +} // namespace leveldb + + +#endif // STORAGE_LEVELDB_INCLUDE_SLICE_H_ diff --git a/ios/Pods/leveldb-library/include/leveldb/status.h b/ios/Pods/leveldb-library/include/leveldb/status.h new file mode 100644 index 000000000..11dbd4b47 --- /dev/null +++ b/ios/Pods/leveldb-library/include/leveldb/status.h @@ -0,0 +1,106 @@ +// Copyright (c) 2011 The LevelDB Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. See the AUTHORS file for names of contributors. +// +// A Status encapsulates the result of an operation. It may indicate success, +// or it may indicate an error with an associated error message. +// +// Multiple threads can invoke const methods on a Status without +// external synchronization, but if any of the threads may call a +// non-const method, all threads accessing the same Status must use +// external synchronization. + +#ifndef STORAGE_LEVELDB_INCLUDE_STATUS_H_ +#define STORAGE_LEVELDB_INCLUDE_STATUS_H_ + +#include +#include "leveldb/slice.h" + +namespace leveldb { + +class Status { + public: + // Create a success status. + Status() : state_(NULL) { } + ~Status() { delete[] state_; } + + // Copy the specified status. + Status(const Status& s); + void operator=(const Status& s); + + // Return a success status. + static Status OK() { return Status(); } + + // Return error status of an appropriate type. + static Status NotFound(const Slice& msg, const Slice& msg2 = Slice()) { + return Status(kNotFound, msg, msg2); + } + static Status Corruption(const Slice& msg, const Slice& msg2 = Slice()) { + return Status(kCorruption, msg, msg2); + } + static Status NotSupported(const Slice& msg, const Slice& msg2 = Slice()) { + return Status(kNotSupported, msg, msg2); + } + static Status InvalidArgument(const Slice& msg, const Slice& msg2 = Slice()) { + return Status(kInvalidArgument, msg, msg2); + } + static Status IOError(const Slice& msg, const Slice& msg2 = Slice()) { + return Status(kIOError, msg, msg2); + } + + // Returns true iff the status indicates success. + bool ok() const { return (state_ == NULL); } + + // Returns true iff the status indicates a NotFound error. + bool IsNotFound() const { return code() == kNotFound; } + + // Returns true iff the status indicates a Corruption error. + bool IsCorruption() const { return code() == kCorruption; } + + // Returns true iff the status indicates an IOError. + bool IsIOError() const { return code() == kIOError; } + + // Return a string representation of this status suitable for printing. + // Returns the string "OK" for success. + std::string ToString() const; + + private: + // OK status has a NULL state_. Otherwise, state_ is a new[] array + // of the following form: + // state_[0..3] == length of message + // state_[4] == code + // state_[5..] == message + const char* state_; + + enum Code { + kOk = 0, + kNotFound = 1, + kCorruption = 2, + kNotSupported = 3, + kInvalidArgument = 4, + kIOError = 5 + }; + + Code code() const { + return (state_ == NULL) ? kOk : static_cast(state_[4]); + } + + Status(Code code, const Slice& msg, const Slice& msg2); + static const char* CopyState(const char* s); +}; + +inline Status::Status(const Status& s) { + state_ = (s.state_ == NULL) ? NULL : CopyState(s.state_); +} +inline void Status::operator=(const Status& s) { + // The following condition catches both aliasing (when this == &s), + // and the common case where both s and *this are ok. + if (state_ != s.state_) { + delete[] state_; + state_ = (s.state_ == NULL) ? NULL : CopyState(s.state_); + } +} + +} // namespace leveldb + +#endif // STORAGE_LEVELDB_INCLUDE_STATUS_H_ diff --git a/ios/Pods/leveldb-library/include/leveldb/table.h b/ios/Pods/leveldb-library/include/leveldb/table.h new file mode 100644 index 000000000..a9746c3f5 --- /dev/null +++ b/ios/Pods/leveldb-library/include/leveldb/table.h @@ -0,0 +1,85 @@ +// Copyright (c) 2011 The LevelDB Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. See the AUTHORS file for names of contributors. + +#ifndef STORAGE_LEVELDB_INCLUDE_TABLE_H_ +#define STORAGE_LEVELDB_INCLUDE_TABLE_H_ + +#include +#include "leveldb/iterator.h" + +namespace leveldb { + +class Block; +class BlockHandle; +class Footer; +struct Options; +class RandomAccessFile; +struct ReadOptions; +class TableCache; + +// A Table is a sorted map from strings to strings. Tables are +// immutable and persistent. A Table may be safely accessed from +// multiple threads without external synchronization. +class Table { + public: + // Attempt to open the table that is stored in bytes [0..file_size) + // of "file", and read the metadata entries necessary to allow + // retrieving data from the table. + // + // If successful, returns ok and sets "*table" to the newly opened + // table. The client should delete "*table" when no longer needed. + // If there was an error while initializing the table, sets "*table" + // to NULL and returns a non-ok status. Does not take ownership of + // "*source", but the client must ensure that "source" remains live + // for the duration of the returned table's lifetime. + // + // *file must remain live while this Table is in use. + static Status Open(const Options& options, + RandomAccessFile* file, + uint64_t file_size, + Table** table); + + ~Table(); + + // Returns a new iterator over the table contents. + // The result of NewIterator() is initially invalid (caller must + // call one of the Seek methods on the iterator before using it). + Iterator* NewIterator(const ReadOptions&) const; + + // Given a key, return an approximate byte offset in the file where + // the data for that key begins (or would begin if the key were + // present in the file). The returned value is in terms of file + // bytes, and so includes effects like compression of the underlying data. + // E.g., the approximate offset of the last key in the table will + // be close to the file length. + uint64_t ApproximateOffsetOf(const Slice& key) const; + + private: + struct Rep; + Rep* rep_; + + explicit Table(Rep* rep) { rep_ = rep; } + static Iterator* BlockReader(void*, const ReadOptions&, const Slice&); + + // Calls (*handle_result)(arg, ...) with the entry found after a call + // to Seek(key). May not make such a call if filter policy says + // that key is not present. + friend class TableCache; + Status InternalGet( + const ReadOptions&, const Slice& key, + void* arg, + void (*handle_result)(void* arg, const Slice& k, const Slice& v)); + + + void ReadMeta(const Footer& footer); + void ReadFilter(const Slice& filter_handle_value); + + // No copying allowed + Table(const Table&); + void operator=(const Table&); +}; + +} // namespace leveldb + +#endif // STORAGE_LEVELDB_INCLUDE_TABLE_H_ diff --git a/ios/Pods/leveldb-library/include/leveldb/table_builder.h b/ios/Pods/leveldb-library/include/leveldb/table_builder.h new file mode 100644 index 000000000..5fd1dc71f --- /dev/null +++ b/ios/Pods/leveldb-library/include/leveldb/table_builder.h @@ -0,0 +1,92 @@ +// Copyright (c) 2011 The LevelDB Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. See the AUTHORS file for names of contributors. +// +// TableBuilder provides the interface used to build a Table +// (an immutable and sorted map from keys to values). +// +// Multiple threads can invoke const methods on a TableBuilder without +// external synchronization, but if any of the threads may call a +// non-const method, all threads accessing the same TableBuilder must use +// external synchronization. + +#ifndef STORAGE_LEVELDB_INCLUDE_TABLE_BUILDER_H_ +#define STORAGE_LEVELDB_INCLUDE_TABLE_BUILDER_H_ + +#include +#include "leveldb/options.h" +#include "leveldb/status.h" + +namespace leveldb { + +class BlockBuilder; +class BlockHandle; +class WritableFile; + +class TableBuilder { + public: + // Create a builder that will store the contents of the table it is + // building in *file. Does not close the file. It is up to the + // caller to close the file after calling Finish(). + TableBuilder(const Options& options, WritableFile* file); + + // REQUIRES: Either Finish() or Abandon() has been called. + ~TableBuilder(); + + // Change the options used by this builder. Note: only some of the + // option fields can be changed after construction. If a field is + // not allowed to change dynamically and its value in the structure + // passed to the constructor is different from its value in the + // structure passed to this method, this method will return an error + // without changing any fields. + Status ChangeOptions(const Options& options); + + // Add key,value to the table being constructed. + // REQUIRES: key is after any previously added key according to comparator. + // REQUIRES: Finish(), Abandon() have not been called + void Add(const Slice& key, const Slice& value); + + // Advanced operation: flush any buffered key/value pairs to file. + // Can be used to ensure that two adjacent entries never live in + // the same data block. Most clients should not need to use this method. + // REQUIRES: Finish(), Abandon() have not been called + void Flush(); + + // Return non-ok iff some error has been detected. + Status status() const; + + // Finish building the table. Stops using the file passed to the + // constructor after this function returns. + // REQUIRES: Finish(), Abandon() have not been called + Status Finish(); + + // Indicate that the contents of this builder should be abandoned. Stops + // using the file passed to the constructor after this function returns. + // If the caller is not going to call Finish(), it must call Abandon() + // before destroying this builder. + // REQUIRES: Finish(), Abandon() have not been called + void Abandon(); + + // Number of calls to Add() so far. + uint64_t NumEntries() const; + + // Size of the file generated so far. If invoked after a successful + // Finish() call, returns the size of the final generated file. + uint64_t FileSize() const; + + private: + bool ok() const { return status().ok(); } + void WriteBlock(BlockBuilder* block, BlockHandle* handle); + void WriteRawBlock(const Slice& data, CompressionType, BlockHandle* handle); + + struct Rep; + Rep* rep_; + + // No copying allowed + TableBuilder(const TableBuilder&); + void operator=(const TableBuilder&); +}; + +} // namespace leveldb + +#endif // STORAGE_LEVELDB_INCLUDE_TABLE_BUILDER_H_ diff --git a/ios/Pods/leveldb-library/include/leveldb/write_batch.h b/ios/Pods/leveldb-library/include/leveldb/write_batch.h new file mode 100644 index 000000000..ee9aab68e --- /dev/null +++ b/ios/Pods/leveldb-library/include/leveldb/write_batch.h @@ -0,0 +1,64 @@ +// Copyright (c) 2011 The LevelDB Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. See the AUTHORS file for names of contributors. +// +// WriteBatch holds a collection of updates to apply atomically to a DB. +// +// The updates are applied in the order in which they are added +// to the WriteBatch. For example, the value of "key" will be "v3" +// after the following batch is written: +// +// batch.Put("key", "v1"); +// batch.Delete("key"); +// batch.Put("key", "v2"); +// batch.Put("key", "v3"); +// +// Multiple threads can invoke const methods on a WriteBatch without +// external synchronization, but if any of the threads may call a +// non-const method, all threads accessing the same WriteBatch must use +// external synchronization. + +#ifndef STORAGE_LEVELDB_INCLUDE_WRITE_BATCH_H_ +#define STORAGE_LEVELDB_INCLUDE_WRITE_BATCH_H_ + +#include +#include "leveldb/status.h" + +namespace leveldb { + +class Slice; + +class WriteBatch { + public: + WriteBatch(); + ~WriteBatch(); + + // Store the mapping "key->value" in the database. + void Put(const Slice& key, const Slice& value); + + // If the database contains a mapping for "key", erase it. Else do nothing. + void Delete(const Slice& key); + + // Clear all updates buffered in this batch. + void Clear(); + + // Support for iterating over the contents of a batch. + class Handler { + public: + virtual ~Handler(); + virtual void Put(const Slice& key, const Slice& value) = 0; + virtual void Delete(const Slice& key) = 0; + }; + Status Iterate(Handler* handler) const; + + private: + friend class WriteBatchInternal; + + std::string rep_; // See comment in write_batch.cc for the format of rep_ + + // Intentionally copyable +}; + +} // namespace leveldb + +#endif // STORAGE_LEVELDB_INCLUDE_WRITE_BATCH_H_ diff --git a/ios/Pods/leveldb-library/port/README b/ios/Pods/leveldb-library/port/README new file mode 100644 index 000000000..422563e25 --- /dev/null +++ b/ios/Pods/leveldb-library/port/README @@ -0,0 +1,10 @@ +This directory contains interfaces and implementations that isolate the +rest of the package from platform details. + +Code in the rest of the package includes "port.h" from this directory. +"port.h" in turn includes a platform specific "port_.h" file +that provides the platform specific implementation. + +See port_posix.h for an example of what must be provided in a platform +specific header file. + diff --git a/ios/Pods/leveldb-library/port/atomic_pointer.h b/ios/Pods/leveldb-library/port/atomic_pointer.h new file mode 100644 index 000000000..9bf091f75 --- /dev/null +++ b/ios/Pods/leveldb-library/port/atomic_pointer.h @@ -0,0 +1,223 @@ +// Copyright (c) 2011 The LevelDB Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. See the AUTHORS file for names of contributors. + +// AtomicPointer provides storage for a lock-free pointer. +// Platform-dependent implementation of AtomicPointer: +// - If the platform provides a cheap barrier, we use it with raw pointers +// - If is present (on newer versions of gcc, it is), we use +// a -based AtomicPointer. However we prefer the memory +// barrier based version, because at least on a gcc 4.4 32-bit build +// on linux, we have encountered a buggy implementation. +// Also, some implementations are much slower than a memory-barrier +// based implementation (~16ns for based acquire-load vs. ~1ns for +// a barrier based acquire-load). +// This code is based on atomicops-internals-* in Google's perftools: +// http://code.google.com/p/google-perftools/source/browse/#svn%2Ftrunk%2Fsrc%2Fbase + +#ifndef PORT_ATOMIC_POINTER_H_ +#define PORT_ATOMIC_POINTER_H_ + +#include +#ifdef LEVELDB_ATOMIC_PRESENT +#include +#endif +#ifdef OS_WIN +#include +#endif +#ifdef OS_MACOSX +#include +#endif + +#if defined(_M_X64) || defined(__x86_64__) +#define ARCH_CPU_X86_FAMILY 1 +#elif defined(_M_IX86) || defined(__i386__) || defined(__i386) +#define ARCH_CPU_X86_FAMILY 1 +#elif defined(__ARMEL__) +#define ARCH_CPU_ARM_FAMILY 1 +#elif defined(__ppc__) || defined(__powerpc__) || defined(__powerpc64__) +#define ARCH_CPU_PPC_FAMILY 1 +#endif + +namespace leveldb { +namespace port { + +// Define MemoryBarrier() if available +// Windows on x86 +#if defined(OS_WIN) && defined(COMPILER_MSVC) && defined(ARCH_CPU_X86_FAMILY) +// windows.h already provides a MemoryBarrier(void) macro +// http://msdn.microsoft.com/en-us/library/ms684208(v=vs.85).aspx +#define LEVELDB_HAVE_MEMORY_BARRIER + +// Mac OS +#elif defined(OS_MACOSX) +inline void MemoryBarrier() { + OSMemoryBarrier(); +} +#define LEVELDB_HAVE_MEMORY_BARRIER + +// Gcc on x86 +#elif defined(ARCH_CPU_X86_FAMILY) && defined(__GNUC__) +inline void MemoryBarrier() { + // See http://gcc.gnu.org/ml/gcc/2003-04/msg01180.html for a discussion on + // this idiom. Also see http://en.wikipedia.org/wiki/Memory_ordering. + __asm__ __volatile__("" : : : "memory"); +} +#define LEVELDB_HAVE_MEMORY_BARRIER + +// Sun Studio +#elif defined(ARCH_CPU_X86_FAMILY) && defined(__SUNPRO_CC) +inline void MemoryBarrier() { + // See http://gcc.gnu.org/ml/gcc/2003-04/msg01180.html for a discussion on + // this idiom. Also see http://en.wikipedia.org/wiki/Memory_ordering. + asm volatile("" : : : "memory"); +} +#define LEVELDB_HAVE_MEMORY_BARRIER + +// ARM Linux +#elif defined(ARCH_CPU_ARM_FAMILY) && defined(__linux__) +typedef void (*LinuxKernelMemoryBarrierFunc)(void); +// The Linux ARM kernel provides a highly optimized device-specific memory +// barrier function at a fixed memory address that is mapped in every +// user-level process. +// +// This beats using CPU-specific instructions which are, on single-core +// devices, un-necessary and very costly (e.g. ARMv7-A "dmb" takes more +// than 180ns on a Cortex-A8 like the one on a Nexus One). Benchmarking +// shows that the extra function call cost is completely negligible on +// multi-core devices. +// +inline void MemoryBarrier() { + (*(LinuxKernelMemoryBarrierFunc)0xffff0fa0)(); +} +#define LEVELDB_HAVE_MEMORY_BARRIER + +// PPC +#elif defined(ARCH_CPU_PPC_FAMILY) && defined(__GNUC__) +inline void MemoryBarrier() { + // TODO for some powerpc expert: is there a cheaper suitable variant? + // Perhaps by having separate barriers for acquire and release ops. + asm volatile("sync" : : : "memory"); +} +#define LEVELDB_HAVE_MEMORY_BARRIER + +#endif + +// AtomicPointer built using platform-specific MemoryBarrier() +#if defined(LEVELDB_HAVE_MEMORY_BARRIER) +class AtomicPointer { + private: + void* rep_; + public: + AtomicPointer() { } + explicit AtomicPointer(void* p) : rep_(p) {} + inline void* NoBarrier_Load() const { return rep_; } + inline void NoBarrier_Store(void* v) { rep_ = v; } + inline void* Acquire_Load() const { + void* result = rep_; + MemoryBarrier(); + return result; + } + inline void Release_Store(void* v) { + MemoryBarrier(); + rep_ = v; + } +}; + +// AtomicPointer based on +#elif defined(LEVELDB_ATOMIC_PRESENT) +class AtomicPointer { + private: + std::atomic rep_; + public: + AtomicPointer() { } + explicit AtomicPointer(void* v) : rep_(v) { } + inline void* Acquire_Load() const { + return rep_.load(std::memory_order_acquire); + } + inline void Release_Store(void* v) { + rep_.store(v, std::memory_order_release); + } + inline void* NoBarrier_Load() const { + return rep_.load(std::memory_order_relaxed); + } + inline void NoBarrier_Store(void* v) { + rep_.store(v, std::memory_order_relaxed); + } +}; + +// Atomic pointer based on sparc memory barriers +#elif defined(__sparcv9) && defined(__GNUC__) +class AtomicPointer { + private: + void* rep_; + public: + AtomicPointer() { } + explicit AtomicPointer(void* v) : rep_(v) { } + inline void* Acquire_Load() const { + void* val; + __asm__ __volatile__ ( + "ldx [%[rep_]], %[val] \n\t" + "membar #LoadLoad|#LoadStore \n\t" + : [val] "=r" (val) + : [rep_] "r" (&rep_) + : "memory"); + return val; + } + inline void Release_Store(void* v) { + __asm__ __volatile__ ( + "membar #LoadStore|#StoreStore \n\t" + "stx %[v], [%[rep_]] \n\t" + : + : [rep_] "r" (&rep_), [v] "r" (v) + : "memory"); + } + inline void* NoBarrier_Load() const { return rep_; } + inline void NoBarrier_Store(void* v) { rep_ = v; } +}; + +// Atomic pointer based on ia64 acq/rel +#elif defined(__ia64) && defined(__GNUC__) +class AtomicPointer { + private: + void* rep_; + public: + AtomicPointer() { } + explicit AtomicPointer(void* v) : rep_(v) { } + inline void* Acquire_Load() const { + void* val ; + __asm__ __volatile__ ( + "ld8.acq %[val] = [%[rep_]] \n\t" + : [val] "=r" (val) + : [rep_] "r" (&rep_) + : "memory" + ); + return val; + } + inline void Release_Store(void* v) { + __asm__ __volatile__ ( + "st8.rel [%[rep_]] = %[v] \n\t" + : + : [rep_] "r" (&rep_), [v] "r" (v) + : "memory" + ); + } + inline void* NoBarrier_Load() const { return rep_; } + inline void NoBarrier_Store(void* v) { rep_ = v; } +}; + +// We have neither MemoryBarrier(), nor +#else +#error Please implement AtomicPointer for this platform. + +#endif + +#undef LEVELDB_HAVE_MEMORY_BARRIER +#undef ARCH_CPU_X86_FAMILY +#undef ARCH_CPU_ARM_FAMILY +#undef ARCH_CPU_PPC_FAMILY + +} // namespace port +} // namespace leveldb + +#endif // PORT_ATOMIC_POINTER_H_ diff --git a/ios/Pods/leveldb-library/port/port.h b/ios/Pods/leveldb-library/port/port.h new file mode 100644 index 000000000..e667db40d --- /dev/null +++ b/ios/Pods/leveldb-library/port/port.h @@ -0,0 +1,19 @@ +// Copyright (c) 2011 The LevelDB Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. See the AUTHORS file for names of contributors. + +#ifndef STORAGE_LEVELDB_PORT_PORT_H_ +#define STORAGE_LEVELDB_PORT_PORT_H_ + +#include + +// Include the appropriate platform specific file below. If you are +// porting to a new platform, see "port_example.h" for documentation +// of what the new port_.h file must provide. +#if defined(LEVELDB_PLATFORM_POSIX) +# include "port/port_posix.h" +#elif defined(LEVELDB_PLATFORM_CHROMIUM) +# include "port/port_chromium.h" +#endif + +#endif // STORAGE_LEVELDB_PORT_PORT_H_ diff --git a/ios/Pods/leveldb-library/port/port_example.h b/ios/Pods/leveldb-library/port/port_example.h new file mode 100644 index 000000000..ab9e489b3 --- /dev/null +++ b/ios/Pods/leveldb-library/port/port_example.h @@ -0,0 +1,135 @@ +// Copyright (c) 2011 The LevelDB Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. See the AUTHORS file for names of contributors. +// +// This file contains the specification, but not the implementations, +// of the types/operations/etc. that should be defined by a platform +// specific port_.h file. Use this file as a reference for +// how to port this package to a new platform. + +#ifndef STORAGE_LEVELDB_PORT_PORT_EXAMPLE_H_ +#define STORAGE_LEVELDB_PORT_PORT_EXAMPLE_H_ + +namespace leveldb { +namespace port { + +// TODO(jorlow): Many of these belong more in the environment class rather than +// here. We should try moving them and see if it affects perf. + +// The following boolean constant must be true on a little-endian machine +// and false otherwise. +static const bool kLittleEndian = true /* or some other expression */; + +// ------------------ Threading ------------------- + +// A Mutex represents an exclusive lock. +class Mutex { + public: + Mutex(); + ~Mutex(); + + // Lock the mutex. Waits until other lockers have exited. + // Will deadlock if the mutex is already locked by this thread. + void Lock(); + + // Unlock the mutex. + // REQUIRES: This mutex was locked by this thread. + void Unlock(); + + // Optionally crash if this thread does not hold this mutex. + // The implementation must be fast, especially if NDEBUG is + // defined. The implementation is allowed to skip all checks. + void AssertHeld(); +}; + +class CondVar { + public: + explicit CondVar(Mutex* mu); + ~CondVar(); + + // Atomically release *mu and block on this condition variable until + // either a call to SignalAll(), or a call to Signal() that picks + // this thread to wakeup. + // REQUIRES: this thread holds *mu + void Wait(); + + // If there are some threads waiting, wake up at least one of them. + void Signal(); + + // Wake up all waiting threads. + void SignallAll(); +}; + +// Thread-safe initialization. +// Used as follows: +// static port::OnceType init_control = LEVELDB_ONCE_INIT; +// static void Initializer() { ... do something ...; } +// ... +// port::InitOnce(&init_control, &Initializer); +typedef intptr_t OnceType; +#define LEVELDB_ONCE_INIT 0 +extern void InitOnce(port::OnceType*, void (*initializer)()); + +// A type that holds a pointer that can be read or written atomically +// (i.e., without word-tearing.) +class AtomicPointer { + private: + intptr_t rep_; + public: + // Initialize to arbitrary value + AtomicPointer(); + + // Initialize to hold v + explicit AtomicPointer(void* v) : rep_(v) { } + + // Read and return the stored pointer with the guarantee that no + // later memory access (read or write) by this thread can be + // reordered ahead of this read. + void* Acquire_Load() const; + + // Set v as the stored pointer with the guarantee that no earlier + // memory access (read or write) by this thread can be reordered + // after this store. + void Release_Store(void* v); + + // Read the stored pointer with no ordering guarantees. + void* NoBarrier_Load() const; + + // Set va as the stored pointer with no ordering guarantees. + void NoBarrier_Store(void* v); +}; + +// ------------------ Compression ------------------- + +// Store the snappy compression of "input[0,input_length-1]" in *output. +// Returns false if snappy is not supported by this port. +extern bool Snappy_Compress(const char* input, size_t input_length, + std::string* output); + +// If input[0,input_length-1] looks like a valid snappy compressed +// buffer, store the size of the uncompressed data in *result and +// return true. Else return false. +extern bool Snappy_GetUncompressedLength(const char* input, size_t length, + size_t* result); + +// Attempt to snappy uncompress input[0,input_length-1] into *output. +// Returns true if successful, false if the input is invalid lightweight +// compressed data. +// +// REQUIRES: at least the first "n" bytes of output[] must be writable +// where "n" is the result of a successful call to +// Snappy_GetUncompressedLength. +extern bool Snappy_Uncompress(const char* input_data, size_t input_length, + char* output); + +// ------------------ Miscellaneous ------------------- + +// If heap profiling is not supported, returns false. +// Else repeatedly calls (*func)(arg, data, n) and then returns true. +// The concatenation of all "data[0,n-1]" fragments is the heap profile. +extern bool GetHeapProfile(void (*func)(void*, const char*, int), void* arg); + +} // namespace port +} // namespace leveldb + +#endif // STORAGE_LEVELDB_PORT_PORT_EXAMPLE_H_ diff --git a/ios/Pods/leveldb-library/port/port_posix.cc b/ios/Pods/leveldb-library/port/port_posix.cc new file mode 100644 index 000000000..5ba127a5b --- /dev/null +++ b/ios/Pods/leveldb-library/port/port_posix.cc @@ -0,0 +1,54 @@ +// Copyright (c) 2011 The LevelDB Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. See the AUTHORS file for names of contributors. + +#include "port/port_posix.h" + +#include +#include +#include +#include "util/logging.h" + +namespace leveldb { +namespace port { + +static void PthreadCall(const char* label, int result) { + if (result != 0) { + fprintf(stderr, "pthread %s: %s\n", label, strerror(result)); + abort(); + } +} + +Mutex::Mutex() { PthreadCall("init mutex", pthread_mutex_init(&mu_, NULL)); } + +Mutex::~Mutex() { PthreadCall("destroy mutex", pthread_mutex_destroy(&mu_)); } + +void Mutex::Lock() { PthreadCall("lock", pthread_mutex_lock(&mu_)); } + +void Mutex::Unlock() { PthreadCall("unlock", pthread_mutex_unlock(&mu_)); } + +CondVar::CondVar(Mutex* mu) + : mu_(mu) { + PthreadCall("init cv", pthread_cond_init(&cv_, NULL)); +} + +CondVar::~CondVar() { PthreadCall("destroy cv", pthread_cond_destroy(&cv_)); } + +void CondVar::Wait() { + PthreadCall("wait", pthread_cond_wait(&cv_, &mu_->mu_)); +} + +void CondVar::Signal() { + PthreadCall("signal", pthread_cond_signal(&cv_)); +} + +void CondVar::SignalAll() { + PthreadCall("broadcast", pthread_cond_broadcast(&cv_)); +} + +void InitOnce(OnceType* once, void (*initializer)()) { + PthreadCall("once", pthread_once(once, initializer)); +} + +} // namespace port +} // namespace leveldb diff --git a/ios/Pods/leveldb-library/port/port_posix.h b/ios/Pods/leveldb-library/port/port_posix.h new file mode 100644 index 000000000..89fc222c0 --- /dev/null +++ b/ios/Pods/leveldb-library/port/port_posix.h @@ -0,0 +1,154 @@ +// Copyright (c) 2011 The LevelDB Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. See the AUTHORS file for names of contributors. +// +// See port_example.h for documentation for the following types/functions. + +#ifndef STORAGE_LEVELDB_PORT_PORT_POSIX_H_ +#define STORAGE_LEVELDB_PORT_PORT_POSIX_H_ + +#undef PLATFORM_IS_LITTLE_ENDIAN +#if defined(OS_MACOSX) + #include + #if defined(__DARWIN_LITTLE_ENDIAN) && defined(__DARWIN_BYTE_ORDER) + #define PLATFORM_IS_LITTLE_ENDIAN \ + (__DARWIN_BYTE_ORDER == __DARWIN_LITTLE_ENDIAN) + #endif +#elif defined(OS_SOLARIS) + #include + #ifdef _LITTLE_ENDIAN + #define PLATFORM_IS_LITTLE_ENDIAN true + #else + #define PLATFORM_IS_LITTLE_ENDIAN false + #endif +#elif defined(OS_FREEBSD) || defined(OS_OPENBSD) ||\ + defined(OS_NETBSD) || defined(OS_DRAGONFLYBSD) + #include + #include + #define PLATFORM_IS_LITTLE_ENDIAN (_BYTE_ORDER == _LITTLE_ENDIAN) +#elif defined(OS_HPUX) + #define PLATFORM_IS_LITTLE_ENDIAN false +#elif defined(OS_ANDROID) + // Due to a bug in the NDK x86 definition, + // _BYTE_ORDER must be used instead of __BYTE_ORDER on Android. + // See http://code.google.com/p/android/issues/detail?id=39824 + #include + #define PLATFORM_IS_LITTLE_ENDIAN (_BYTE_ORDER == _LITTLE_ENDIAN) +#else + #include +#endif + +#include +#ifdef SNAPPY +#include +#endif +#include +#include +#include "port/atomic_pointer.h" + +#ifndef PLATFORM_IS_LITTLE_ENDIAN +#define PLATFORM_IS_LITTLE_ENDIAN (__BYTE_ORDER == __LITTLE_ENDIAN) +#endif + +#if defined(OS_MACOSX) || defined(OS_SOLARIS) || defined(OS_FREEBSD) ||\ + defined(OS_NETBSD) || defined(OS_OPENBSD) || defined(OS_DRAGONFLYBSD) ||\ + defined(OS_ANDROID) || defined(OS_HPUX) || defined(CYGWIN) +// Use fread/fwrite/fflush on platforms without _unlocked variants +#define fread_unlocked fread +#define fwrite_unlocked fwrite +#define fflush_unlocked fflush +#endif + +#if defined(OS_MACOSX) || defined(OS_FREEBSD) ||\ + defined(OS_OPENBSD) || defined(OS_DRAGONFLYBSD) +// Use fsync() on platforms without fdatasync() +#define fdatasync fsync +#endif + +#if defined(OS_ANDROID) && __ANDROID_API__ < 9 +// fdatasync() was only introduced in API level 9 on Android. Use fsync() +// when targetting older platforms. +#define fdatasync fsync +#endif + +namespace leveldb { +namespace port { + +static const bool kLittleEndian = PLATFORM_IS_LITTLE_ENDIAN; +#undef PLATFORM_IS_LITTLE_ENDIAN + +class CondVar; + +class Mutex { + public: + Mutex(); + ~Mutex(); + + void Lock(); + void Unlock(); + void AssertHeld() { } + + private: + friend class CondVar; + pthread_mutex_t mu_; + + // No copying + Mutex(const Mutex&); + void operator=(const Mutex&); +}; + +class CondVar { + public: + explicit CondVar(Mutex* mu); + ~CondVar(); + void Wait(); + void Signal(); + void SignalAll(); + private: + pthread_cond_t cv_; + Mutex* mu_; +}; + +typedef pthread_once_t OnceType; +#define LEVELDB_ONCE_INIT PTHREAD_ONCE_INIT +extern void InitOnce(OnceType* once, void (*initializer)()); + +inline bool Snappy_Compress(const char* input, size_t length, + ::std::string* output) { +#ifdef SNAPPY + output->resize(snappy::MaxCompressedLength(length)); + size_t outlen; + snappy::RawCompress(input, length, &(*output)[0], &outlen); + output->resize(outlen); + return true; +#endif + + return false; +} + +inline bool Snappy_GetUncompressedLength(const char* input, size_t length, + size_t* result) { +#ifdef SNAPPY + return snappy::GetUncompressedLength(input, length, result); +#else + return false; +#endif +} + +inline bool Snappy_Uncompress(const char* input, size_t length, + char* output) { +#ifdef SNAPPY + return snappy::RawUncompress(input, length, output); +#else + return false; +#endif +} + +inline bool GetHeapProfile(void (*func)(void*, const char*, int), void* arg) { + return false; +} + +} // namespace port +} // namespace leveldb + +#endif // STORAGE_LEVELDB_PORT_PORT_POSIX_H_ diff --git a/ios/Pods/leveldb-library/port/thread_annotations.h b/ios/Pods/leveldb-library/port/thread_annotations.h new file mode 100644 index 000000000..9470ef587 --- /dev/null +++ b/ios/Pods/leveldb-library/port/thread_annotations.h @@ -0,0 +1,60 @@ +// Copyright (c) 2012 The LevelDB Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. See the AUTHORS file for names of contributors. + +#ifndef STORAGE_LEVELDB_PORT_THREAD_ANNOTATIONS_H_ +#define STORAGE_LEVELDB_PORT_THREAD_ANNOTATIONS_H_ + +// Some environments provide custom macros to aid in static thread-safety +// analysis. Provide empty definitions of such macros unless they are already +// defined. + +#ifndef EXCLUSIVE_LOCKS_REQUIRED +#define EXCLUSIVE_LOCKS_REQUIRED(...) +#endif + +#ifndef SHARED_LOCKS_REQUIRED +#define SHARED_LOCKS_REQUIRED(...) +#endif + +#ifndef LOCKS_EXCLUDED +#define LOCKS_EXCLUDED(...) +#endif + +#ifndef LOCK_RETURNED +#define LOCK_RETURNED(x) +#endif + +#ifndef LOCKABLE +#define LOCKABLE +#endif + +#ifndef SCOPED_LOCKABLE +#define SCOPED_LOCKABLE +#endif + +#ifndef EXCLUSIVE_LOCK_FUNCTION +#define EXCLUSIVE_LOCK_FUNCTION(...) +#endif + +#ifndef SHARED_LOCK_FUNCTION +#define SHARED_LOCK_FUNCTION(...) +#endif + +#ifndef EXCLUSIVE_TRYLOCK_FUNCTION +#define EXCLUSIVE_TRYLOCK_FUNCTION(...) +#endif + +#ifndef SHARED_TRYLOCK_FUNCTION +#define SHARED_TRYLOCK_FUNCTION(...) +#endif + +#ifndef UNLOCK_FUNCTION +#define UNLOCK_FUNCTION(...) +#endif + +#ifndef NO_THREAD_SAFETY_ANALYSIS +#define NO_THREAD_SAFETY_ANALYSIS +#endif + +#endif // STORAGE_LEVELDB_PORT_THREAD_ANNOTATIONS_H_ diff --git a/ios/Pods/leveldb-library/port/win/stdint.h b/ios/Pods/leveldb-library/port/win/stdint.h new file mode 100644 index 000000000..39edd0db1 --- /dev/null +++ b/ios/Pods/leveldb-library/port/win/stdint.h @@ -0,0 +1,24 @@ +// Copyright (c) 2011 The LevelDB Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. See the AUTHORS file for names of contributors. + +// MSVC didn't ship with this file until the 2010 version. + +#ifndef STORAGE_LEVELDB_PORT_WIN_STDINT_H_ +#define STORAGE_LEVELDB_PORT_WIN_STDINT_H_ + +#if !defined(_MSC_VER) +#error This file should only be included when compiling with MSVC. +#endif + +// Define C99 equivalent types. +typedef signed char int8_t; +typedef signed short int16_t; +typedef signed int int32_t; +typedef signed long long int64_t; +typedef unsigned char uint8_t; +typedef unsigned short uint16_t; +typedef unsigned int uint32_t; +typedef unsigned long long uint64_t; + +#endif // STORAGE_LEVELDB_PORT_WIN_STDINT_H_ diff --git a/ios/Pods/leveldb-library/table/block.cc b/ios/Pods/leveldb-library/table/block.cc new file mode 100644 index 000000000..43e402c9c --- /dev/null +++ b/ios/Pods/leveldb-library/table/block.cc @@ -0,0 +1,268 @@ +// Copyright (c) 2011 The LevelDB Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. See the AUTHORS file for names of contributors. +// +// Decodes the blocks generated by block_builder.cc. + +#include "table/block.h" + +#include +#include +#include "leveldb/comparator.h" +#include "table/format.h" +#include "util/coding.h" +#include "util/logging.h" + +namespace leveldb { + +inline uint32_t Block::NumRestarts() const { + assert(size_ >= sizeof(uint32_t)); + return DecodeFixed32(data_ + size_ - sizeof(uint32_t)); +} + +Block::Block(const BlockContents& contents) + : data_(contents.data.data()), + size_(contents.data.size()), + owned_(contents.heap_allocated) { + if (size_ < sizeof(uint32_t)) { + size_ = 0; // Error marker + } else { + size_t max_restarts_allowed = (size_-sizeof(uint32_t)) / sizeof(uint32_t); + if (NumRestarts() > max_restarts_allowed) { + // The size is too small for NumRestarts() + size_ = 0; + } else { + restart_offset_ = size_ - (1 + NumRestarts()) * sizeof(uint32_t); + } + } +} + +Block::~Block() { + if (owned_) { + delete[] data_; + } +} + +// Helper routine: decode the next block entry starting at "p", +// storing the number of shared key bytes, non_shared key bytes, +// and the length of the value in "*shared", "*non_shared", and +// "*value_length", respectively. Will not dereference past "limit". +// +// If any errors are detected, returns NULL. Otherwise, returns a +// pointer to the key delta (just past the three decoded values). +static inline const char* DecodeEntry(const char* p, const char* limit, + uint32_t* shared, + uint32_t* non_shared, + uint32_t* value_length) { + if (limit - p < 3) return NULL; + *shared = reinterpret_cast(p)[0]; + *non_shared = reinterpret_cast(p)[1]; + *value_length = reinterpret_cast(p)[2]; + if ((*shared | *non_shared | *value_length) < 128) { + // Fast path: all three values are encoded in one byte each + p += 3; + } else { + if ((p = GetVarint32Ptr(p, limit, shared)) == NULL) return NULL; + if ((p = GetVarint32Ptr(p, limit, non_shared)) == NULL) return NULL; + if ((p = GetVarint32Ptr(p, limit, value_length)) == NULL) return NULL; + } + + if (static_cast(limit - p) < (*non_shared + *value_length)) { + return NULL; + } + return p; +} + +class Block::Iter : public Iterator { + private: + const Comparator* const comparator_; + const char* const data_; // underlying block contents + uint32_t const restarts_; // Offset of restart array (list of fixed32) + uint32_t const num_restarts_; // Number of uint32_t entries in restart array + + // current_ is offset in data_ of current entry. >= restarts_ if !Valid + uint32_t current_; + uint32_t restart_index_; // Index of restart block in which current_ falls + std::string key_; + Slice value_; + Status status_; + + inline int Compare(const Slice& a, const Slice& b) const { + return comparator_->Compare(a, b); + } + + // Return the offset in data_ just past the end of the current entry. + inline uint32_t NextEntryOffset() const { + return (value_.data() + value_.size()) - data_; + } + + uint32_t GetRestartPoint(uint32_t index) { + assert(index < num_restarts_); + return DecodeFixed32(data_ + restarts_ + index * sizeof(uint32_t)); + } + + void SeekToRestartPoint(uint32_t index) { + key_.clear(); + restart_index_ = index; + // current_ will be fixed by ParseNextKey(); + + // ParseNextKey() starts at the end of value_, so set value_ accordingly + uint32_t offset = GetRestartPoint(index); + value_ = Slice(data_ + offset, 0); + } + + public: + Iter(const Comparator* comparator, + const char* data, + uint32_t restarts, + uint32_t num_restarts) + : comparator_(comparator), + data_(data), + restarts_(restarts), + num_restarts_(num_restarts), + current_(restarts_), + restart_index_(num_restarts_) { + assert(num_restarts_ > 0); + } + + virtual bool Valid() const { return current_ < restarts_; } + virtual Status status() const { return status_; } + virtual Slice key() const { + assert(Valid()); + return key_; + } + virtual Slice value() const { + assert(Valid()); + return value_; + } + + virtual void Next() { + assert(Valid()); + ParseNextKey(); + } + + virtual void Prev() { + assert(Valid()); + + // Scan backwards to a restart point before current_ + const uint32_t original = current_; + while (GetRestartPoint(restart_index_) >= original) { + if (restart_index_ == 0) { + // No more entries + current_ = restarts_; + restart_index_ = num_restarts_; + return; + } + restart_index_--; + } + + SeekToRestartPoint(restart_index_); + do { + // Loop until end of current entry hits the start of original entry + } while (ParseNextKey() && NextEntryOffset() < original); + } + + virtual void Seek(const Slice& target) { + // Binary search in restart array to find the last restart point + // with a key < target + uint32_t left = 0; + uint32_t right = num_restarts_ - 1; + while (left < right) { + uint32_t mid = (left + right + 1) / 2; + uint32_t region_offset = GetRestartPoint(mid); + uint32_t shared, non_shared, value_length; + const char* key_ptr = DecodeEntry(data_ + region_offset, + data_ + restarts_, + &shared, &non_shared, &value_length); + if (key_ptr == NULL || (shared != 0)) { + CorruptionError(); + return; + } + Slice mid_key(key_ptr, non_shared); + if (Compare(mid_key, target) < 0) { + // Key at "mid" is smaller than "target". Therefore all + // blocks before "mid" are uninteresting. + left = mid; + } else { + // Key at "mid" is >= "target". Therefore all blocks at or + // after "mid" are uninteresting. + right = mid - 1; + } + } + + // Linear search (within restart block) for first key >= target + SeekToRestartPoint(left); + while (true) { + if (!ParseNextKey()) { + return; + } + if (Compare(key_, target) >= 0) { + return; + } + } + } + + virtual void SeekToFirst() { + SeekToRestartPoint(0); + ParseNextKey(); + } + + virtual void SeekToLast() { + SeekToRestartPoint(num_restarts_ - 1); + while (ParseNextKey() && NextEntryOffset() < restarts_) { + // Keep skipping + } + } + + private: + void CorruptionError() { + current_ = restarts_; + restart_index_ = num_restarts_; + status_ = Status::Corruption("bad entry in block"); + key_.clear(); + value_.clear(); + } + + bool ParseNextKey() { + current_ = NextEntryOffset(); + const char* p = data_ + current_; + const char* limit = data_ + restarts_; // Restarts come right after data + if (p >= limit) { + // No more entries to return. Mark as invalid. + current_ = restarts_; + restart_index_ = num_restarts_; + return false; + } + + // Decode next entry + uint32_t shared, non_shared, value_length; + p = DecodeEntry(p, limit, &shared, &non_shared, &value_length); + if (p == NULL || key_.size() < shared) { + CorruptionError(); + return false; + } else { + key_.resize(shared); + key_.append(p, non_shared); + value_ = Slice(p + non_shared, value_length); + while (restart_index_ + 1 < num_restarts_ && + GetRestartPoint(restart_index_ + 1) < current_) { + ++restart_index_; + } + return true; + } + } +}; + +Iterator* Block::NewIterator(const Comparator* cmp) { + if (size_ < sizeof(uint32_t)) { + return NewErrorIterator(Status::Corruption("bad block contents")); + } + const uint32_t num_restarts = NumRestarts(); + if (num_restarts == 0) { + return NewEmptyIterator(); + } else { + return new Iter(cmp, data_, restart_offset_, num_restarts); + } +} + +} // namespace leveldb diff --git a/ios/Pods/leveldb-library/table/block.h b/ios/Pods/leveldb-library/table/block.h new file mode 100644 index 000000000..2493eb9f9 --- /dev/null +++ b/ios/Pods/leveldb-library/table/block.h @@ -0,0 +1,44 @@ +// Copyright (c) 2011 The LevelDB Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. See the AUTHORS file for names of contributors. + +#ifndef STORAGE_LEVELDB_TABLE_BLOCK_H_ +#define STORAGE_LEVELDB_TABLE_BLOCK_H_ + +#include +#include +#include "leveldb/iterator.h" + +namespace leveldb { + +struct BlockContents; +class Comparator; + +class Block { + public: + // Initialize the block with the specified contents. + explicit Block(const BlockContents& contents); + + ~Block(); + + size_t size() const { return size_; } + Iterator* NewIterator(const Comparator* comparator); + + private: + uint32_t NumRestarts() const; + + const char* data_; + size_t size_; + uint32_t restart_offset_; // Offset in data_ of restart array + bool owned_; // Block owns data_[] + + // No copying allowed + Block(const Block&); + void operator=(const Block&); + + class Iter; +}; + +} // namespace leveldb + +#endif // STORAGE_LEVELDB_TABLE_BLOCK_H_ diff --git a/ios/Pods/leveldb-library/table/block_builder.cc b/ios/Pods/leveldb-library/table/block_builder.cc new file mode 100644 index 000000000..db660cd07 --- /dev/null +++ b/ios/Pods/leveldb-library/table/block_builder.cc @@ -0,0 +1,109 @@ +// Copyright (c) 2011 The LevelDB Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. See the AUTHORS file for names of contributors. +// +// BlockBuilder generates blocks where keys are prefix-compressed: +// +// When we store a key, we drop the prefix shared with the previous +// string. This helps reduce the space requirement significantly. +// Furthermore, once every K keys, we do not apply the prefix +// compression and store the entire key. We call this a "restart +// point". The tail end of the block stores the offsets of all of the +// restart points, and can be used to do a binary search when looking +// for a particular key. Values are stored as-is (without compression) +// immediately following the corresponding key. +// +// An entry for a particular key-value pair has the form: +// shared_bytes: varint32 +// unshared_bytes: varint32 +// value_length: varint32 +// key_delta: char[unshared_bytes] +// value: char[value_length] +// shared_bytes == 0 for restart points. +// +// The trailer of the block has the form: +// restarts: uint32[num_restarts] +// num_restarts: uint32 +// restarts[i] contains the offset within the block of the ith restart point. + +#include "table/block_builder.h" + +#include +#include +#include "leveldb/comparator.h" +#include "leveldb/table_builder.h" +#include "util/coding.h" + +namespace leveldb { + +BlockBuilder::BlockBuilder(const Options* options) + : options_(options), + restarts_(), + counter_(0), + finished_(false) { + assert(options->block_restart_interval >= 1); + restarts_.push_back(0); // First restart point is at offset 0 +} + +void BlockBuilder::Reset() { + buffer_.clear(); + restarts_.clear(); + restarts_.push_back(0); // First restart point is at offset 0 + counter_ = 0; + finished_ = false; + last_key_.clear(); +} + +size_t BlockBuilder::CurrentSizeEstimate() const { + return (buffer_.size() + // Raw data buffer + restarts_.size() * sizeof(uint32_t) + // Restart array + sizeof(uint32_t)); // Restart array length +} + +Slice BlockBuilder::Finish() { + // Append restart array + for (size_t i = 0; i < restarts_.size(); i++) { + PutFixed32(&buffer_, restarts_[i]); + } + PutFixed32(&buffer_, restarts_.size()); + finished_ = true; + return Slice(buffer_); +} + +void BlockBuilder::Add(const Slice& key, const Slice& value) { + Slice last_key_piece(last_key_); + assert(!finished_); + assert(counter_ <= options_->block_restart_interval); + assert(buffer_.empty() // No values yet? + || options_->comparator->Compare(key, last_key_piece) > 0); + size_t shared = 0; + if (counter_ < options_->block_restart_interval) { + // See how much sharing to do with previous string + const size_t min_length = std::min(last_key_piece.size(), key.size()); + while ((shared < min_length) && (last_key_piece[shared] == key[shared])) { + shared++; + } + } else { + // Restart compression + restarts_.push_back(buffer_.size()); + counter_ = 0; + } + const size_t non_shared = key.size() - shared; + + // Add "" to buffer_ + PutVarint32(&buffer_, shared); + PutVarint32(&buffer_, non_shared); + PutVarint32(&buffer_, value.size()); + + // Add string delta to buffer_ followed by value + buffer_.append(key.data() + shared, non_shared); + buffer_.append(value.data(), value.size()); + + // Update state + last_key_.resize(shared); + last_key_.append(key.data() + shared, non_shared); + assert(Slice(last_key_) == key); + counter_++; +} + +} // namespace leveldb diff --git a/ios/Pods/leveldb-library/table/block_builder.h b/ios/Pods/leveldb-library/table/block_builder.h new file mode 100644 index 000000000..4fbcb3397 --- /dev/null +++ b/ios/Pods/leveldb-library/table/block_builder.h @@ -0,0 +1,57 @@ +// Copyright (c) 2011 The LevelDB Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. See the AUTHORS file for names of contributors. + +#ifndef STORAGE_LEVELDB_TABLE_BLOCK_BUILDER_H_ +#define STORAGE_LEVELDB_TABLE_BLOCK_BUILDER_H_ + +#include + +#include +#include "leveldb/slice.h" + +namespace leveldb { + +struct Options; + +class BlockBuilder { + public: + explicit BlockBuilder(const Options* options); + + // Reset the contents as if the BlockBuilder was just constructed. + void Reset(); + + // REQUIRES: Finish() has not been called since the last call to Reset(). + // REQUIRES: key is larger than any previously added key + void Add(const Slice& key, const Slice& value); + + // Finish building the block and return a slice that refers to the + // block contents. The returned slice will remain valid for the + // lifetime of this builder or until Reset() is called. + Slice Finish(); + + // Returns an estimate of the current (uncompressed) size of the block + // we are building. + size_t CurrentSizeEstimate() const; + + // Return true iff no entries have been added since the last Reset() + bool empty() const { + return buffer_.empty(); + } + + private: + const Options* options_; + std::string buffer_; // Destination buffer + std::vector restarts_; // Restart points + int counter_; // Number of entries emitted since restart + bool finished_; // Has Finish() been called? + std::string last_key_; + + // No copying allowed + BlockBuilder(const BlockBuilder&); + void operator=(const BlockBuilder&); +}; + +} // namespace leveldb + +#endif // STORAGE_LEVELDB_TABLE_BLOCK_BUILDER_H_ diff --git a/ios/Pods/leveldb-library/table/filter_block.cc b/ios/Pods/leveldb-library/table/filter_block.cc new file mode 100644 index 000000000..203e15c8b --- /dev/null +++ b/ios/Pods/leveldb-library/table/filter_block.cc @@ -0,0 +1,111 @@ +// Copyright (c) 2012 The LevelDB Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. See the AUTHORS file for names of contributors. + +#include "table/filter_block.h" + +#include "leveldb/filter_policy.h" +#include "util/coding.h" + +namespace leveldb { + +// See doc/table_format.txt for an explanation of the filter block format. + +// Generate new filter every 2KB of data +static const size_t kFilterBaseLg = 11; +static const size_t kFilterBase = 1 << kFilterBaseLg; + +FilterBlockBuilder::FilterBlockBuilder(const FilterPolicy* policy) + : policy_(policy) { +} + +void FilterBlockBuilder::StartBlock(uint64_t block_offset) { + uint64_t filter_index = (block_offset / kFilterBase); + assert(filter_index >= filter_offsets_.size()); + while (filter_index > filter_offsets_.size()) { + GenerateFilter(); + } +} + +void FilterBlockBuilder::AddKey(const Slice& key) { + Slice k = key; + start_.push_back(keys_.size()); + keys_.append(k.data(), k.size()); +} + +Slice FilterBlockBuilder::Finish() { + if (!start_.empty()) { + GenerateFilter(); + } + + // Append array of per-filter offsets + const uint32_t array_offset = result_.size(); + for (size_t i = 0; i < filter_offsets_.size(); i++) { + PutFixed32(&result_, filter_offsets_[i]); + } + + PutFixed32(&result_, array_offset); + result_.push_back(kFilterBaseLg); // Save encoding parameter in result + return Slice(result_); +} + +void FilterBlockBuilder::GenerateFilter() { + const size_t num_keys = start_.size(); + if (num_keys == 0) { + // Fast path if there are no keys for this filter + filter_offsets_.push_back(result_.size()); + return; + } + + // Make list of keys from flattened key structure + start_.push_back(keys_.size()); // Simplify length computation + tmp_keys_.resize(num_keys); + for (size_t i = 0; i < num_keys; i++) { + const char* base = keys_.data() + start_[i]; + size_t length = start_[i+1] - start_[i]; + tmp_keys_[i] = Slice(base, length); + } + + // Generate filter for current set of keys and append to result_. + filter_offsets_.push_back(result_.size()); + policy_->CreateFilter(&tmp_keys_[0], num_keys, &result_); + + tmp_keys_.clear(); + keys_.clear(); + start_.clear(); +} + +FilterBlockReader::FilterBlockReader(const FilterPolicy* policy, + const Slice& contents) + : policy_(policy), + data_(NULL), + offset_(NULL), + num_(0), + base_lg_(0) { + size_t n = contents.size(); + if (n < 5) return; // 1 byte for base_lg_ and 4 for start of offset array + base_lg_ = contents[n-1]; + uint32_t last_word = DecodeFixed32(contents.data() + n - 5); + if (last_word > n - 5) return; + data_ = contents.data(); + offset_ = data_ + last_word; + num_ = (n - 5 - last_word) / 4; +} + +bool FilterBlockReader::KeyMayMatch(uint64_t block_offset, const Slice& key) { + uint64_t index = block_offset >> base_lg_; + if (index < num_) { + uint32_t start = DecodeFixed32(offset_ + index*4); + uint32_t limit = DecodeFixed32(offset_ + index*4 + 4); + if (start <= limit && limit <= (offset_ - data_)) { + Slice filter = Slice(data_ + start, limit - start); + return policy_->KeyMayMatch(key, filter); + } else if (start == limit) { + // Empty filters do not match any keys + return false; + } + } + return true; // Errors are treated as potential matches +} + +} diff --git a/ios/Pods/leveldb-library/table/filter_block.h b/ios/Pods/leveldb-library/table/filter_block.h new file mode 100644 index 000000000..c67d010bd --- /dev/null +++ b/ios/Pods/leveldb-library/table/filter_block.h @@ -0,0 +1,68 @@ +// Copyright (c) 2012 The LevelDB Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. See the AUTHORS file for names of contributors. +// +// A filter block is stored near the end of a Table file. It contains +// filters (e.g., bloom filters) for all data blocks in the table combined +// into a single filter block. + +#ifndef STORAGE_LEVELDB_TABLE_FILTER_BLOCK_H_ +#define STORAGE_LEVELDB_TABLE_FILTER_BLOCK_H_ + +#include +#include +#include +#include +#include "leveldb/slice.h" +#include "util/hash.h" + +namespace leveldb { + +class FilterPolicy; + +// A FilterBlockBuilder is used to construct all of the filters for a +// particular Table. It generates a single string which is stored as +// a special block in the Table. +// +// The sequence of calls to FilterBlockBuilder must match the regexp: +// (StartBlock AddKey*)* Finish +class FilterBlockBuilder { + public: + explicit FilterBlockBuilder(const FilterPolicy*); + + void StartBlock(uint64_t block_offset); + void AddKey(const Slice& key); + Slice Finish(); + + private: + void GenerateFilter(); + + const FilterPolicy* policy_; + std::string keys_; // Flattened key contents + std::vector start_; // Starting index in keys_ of each key + std::string result_; // Filter data computed so far + std::vector tmp_keys_; // policy_->CreateFilter() argument + std::vector filter_offsets_; + + // No copying allowed + FilterBlockBuilder(const FilterBlockBuilder&); + void operator=(const FilterBlockBuilder&); +}; + +class FilterBlockReader { + public: + // REQUIRES: "contents" and *policy must stay live while *this is live. + FilterBlockReader(const FilterPolicy* policy, const Slice& contents); + bool KeyMayMatch(uint64_t block_offset, const Slice& key); + + private: + const FilterPolicy* policy_; + const char* data_; // Pointer to filter data (at block-start) + const char* offset_; // Pointer to beginning of offset array (at block-end) + size_t num_; // Number of entries in offset array + size_t base_lg_; // Encoding parameter (see kFilterBaseLg in .cc file) +}; + +} + +#endif // STORAGE_LEVELDB_TABLE_FILTER_BLOCK_H_ diff --git a/ios/Pods/leveldb-library/table/filter_block_test.cc b/ios/Pods/leveldb-library/table/filter_block_test.cc new file mode 100644 index 000000000..8c4a4741f --- /dev/null +++ b/ios/Pods/leveldb-library/table/filter_block_test.cc @@ -0,0 +1,128 @@ +// Copyright (c) 2012 The LevelDB Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. See the AUTHORS file for names of contributors. + +#include "table/filter_block.h" + +#include "leveldb/filter_policy.h" +#include "util/coding.h" +#include "util/hash.h" +#include "util/logging.h" +#include "util/testharness.h" +#include "util/testutil.h" + +namespace leveldb { + +// For testing: emit an array with one hash value per key +class TestHashFilter : public FilterPolicy { + public: + virtual const char* Name() const { + return "TestHashFilter"; + } + + virtual void CreateFilter(const Slice* keys, int n, std::string* dst) const { + for (int i = 0; i < n; i++) { + uint32_t h = Hash(keys[i].data(), keys[i].size(), 1); + PutFixed32(dst, h); + } + } + + virtual bool KeyMayMatch(const Slice& key, const Slice& filter) const { + uint32_t h = Hash(key.data(), key.size(), 1); + for (size_t i = 0; i + 4 <= filter.size(); i += 4) { + if (h == DecodeFixed32(filter.data() + i)) { + return true; + } + } + return false; + } +}; + +class FilterBlockTest { + public: + TestHashFilter policy_; +}; + +TEST(FilterBlockTest, EmptyBuilder) { + FilterBlockBuilder builder(&policy_); + Slice block = builder.Finish(); + ASSERT_EQ("\\x00\\x00\\x00\\x00\\x0b", EscapeString(block)); + FilterBlockReader reader(&policy_, block); + ASSERT_TRUE(reader.KeyMayMatch(0, "foo")); + ASSERT_TRUE(reader.KeyMayMatch(100000, "foo")); +} + +TEST(FilterBlockTest, SingleChunk) { + FilterBlockBuilder builder(&policy_); + builder.StartBlock(100); + builder.AddKey("foo"); + builder.AddKey("bar"); + builder.AddKey("box"); + builder.StartBlock(200); + builder.AddKey("box"); + builder.StartBlock(300); + builder.AddKey("hello"); + Slice block = builder.Finish(); + FilterBlockReader reader(&policy_, block); + ASSERT_TRUE(reader.KeyMayMatch(100, "foo")); + ASSERT_TRUE(reader.KeyMayMatch(100, "bar")); + ASSERT_TRUE(reader.KeyMayMatch(100, "box")); + ASSERT_TRUE(reader.KeyMayMatch(100, "hello")); + ASSERT_TRUE(reader.KeyMayMatch(100, "foo")); + ASSERT_TRUE(! reader.KeyMayMatch(100, "missing")); + ASSERT_TRUE(! reader.KeyMayMatch(100, "other")); +} + +TEST(FilterBlockTest, MultiChunk) { + FilterBlockBuilder builder(&policy_); + + // First filter + builder.StartBlock(0); + builder.AddKey("foo"); + builder.StartBlock(2000); + builder.AddKey("bar"); + + // Second filter + builder.StartBlock(3100); + builder.AddKey("box"); + + // Third filter is empty + + // Last filter + builder.StartBlock(9000); + builder.AddKey("box"); + builder.AddKey("hello"); + + Slice block = builder.Finish(); + FilterBlockReader reader(&policy_, block); + + // Check first filter + ASSERT_TRUE(reader.KeyMayMatch(0, "foo")); + ASSERT_TRUE(reader.KeyMayMatch(2000, "bar")); + ASSERT_TRUE(! reader.KeyMayMatch(0, "box")); + ASSERT_TRUE(! reader.KeyMayMatch(0, "hello")); + + // Check second filter + ASSERT_TRUE(reader.KeyMayMatch(3100, "box")); + ASSERT_TRUE(! reader.KeyMayMatch(3100, "foo")); + ASSERT_TRUE(! reader.KeyMayMatch(3100, "bar")); + ASSERT_TRUE(! reader.KeyMayMatch(3100, "hello")); + + // Check third filter (empty) + ASSERT_TRUE(! reader.KeyMayMatch(4100, "foo")); + ASSERT_TRUE(! reader.KeyMayMatch(4100, "bar")); + ASSERT_TRUE(! reader.KeyMayMatch(4100, "box")); + ASSERT_TRUE(! reader.KeyMayMatch(4100, "hello")); + + // Check last filter + ASSERT_TRUE(reader.KeyMayMatch(9000, "box")); + ASSERT_TRUE(reader.KeyMayMatch(9000, "hello")); + ASSERT_TRUE(! reader.KeyMayMatch(9000, "foo")); + ASSERT_TRUE(! reader.KeyMayMatch(9000, "bar")); +} + +} // namespace leveldb + +int main(int argc, char** argv) { + return leveldb::test::RunAllTests(); +} diff --git a/ios/Pods/leveldb-library/table/format.cc b/ios/Pods/leveldb-library/table/format.cc new file mode 100644 index 000000000..aa63144c9 --- /dev/null +++ b/ios/Pods/leveldb-library/table/format.cc @@ -0,0 +1,145 @@ +// Copyright (c) 2011 The LevelDB Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. See the AUTHORS file for names of contributors. + +#include "table/format.h" + +#include "leveldb/env.h" +#include "port/port.h" +#include "table/block.h" +#include "util/coding.h" +#include "util/crc32c.h" + +namespace leveldb { + +void BlockHandle::EncodeTo(std::string* dst) const { + // Sanity check that all fields have been set + assert(offset_ != ~static_cast(0)); + assert(size_ != ~static_cast(0)); + PutVarint64(dst, offset_); + PutVarint64(dst, size_); +} + +Status BlockHandle::DecodeFrom(Slice* input) { + if (GetVarint64(input, &offset_) && + GetVarint64(input, &size_)) { + return Status::OK(); + } else { + return Status::Corruption("bad block handle"); + } +} + +void Footer::EncodeTo(std::string* dst) const { +#ifndef NDEBUG + const size_t original_size = dst->size(); +#endif + metaindex_handle_.EncodeTo(dst); + index_handle_.EncodeTo(dst); + dst->resize(2 * BlockHandle::kMaxEncodedLength); // Padding + PutFixed32(dst, static_cast(kTableMagicNumber & 0xffffffffu)); + PutFixed32(dst, static_cast(kTableMagicNumber >> 32)); + assert(dst->size() == original_size + kEncodedLength); +} + +Status Footer::DecodeFrom(Slice* input) { + const char* magic_ptr = input->data() + kEncodedLength - 8; + const uint32_t magic_lo = DecodeFixed32(magic_ptr); + const uint32_t magic_hi = DecodeFixed32(magic_ptr + 4); + const uint64_t magic = ((static_cast(magic_hi) << 32) | + (static_cast(magic_lo))); + if (magic != kTableMagicNumber) { + return Status::Corruption("not an sstable (bad magic number)"); + } + + Status result = metaindex_handle_.DecodeFrom(input); + if (result.ok()) { + result = index_handle_.DecodeFrom(input); + } + if (result.ok()) { + // We skip over any leftover data (just padding for now) in "input" + const char* end = magic_ptr + 8; + *input = Slice(end, input->data() + input->size() - end); + } + return result; +} + +Status ReadBlock(RandomAccessFile* file, + const ReadOptions& options, + const BlockHandle& handle, + BlockContents* result) { + result->data = Slice(); + result->cachable = false; + result->heap_allocated = false; + + // Read the block contents as well as the type/crc footer. + // See table_builder.cc for the code that built this structure. + size_t n = static_cast(handle.size()); + char* buf = new char[n + kBlockTrailerSize]; + Slice contents; + Status s = file->Read(handle.offset(), n + kBlockTrailerSize, &contents, buf); + if (!s.ok()) { + delete[] buf; + return s; + } + if (contents.size() != n + kBlockTrailerSize) { + delete[] buf; + return Status::Corruption("truncated block read"); + } + + // Check the crc of the type and the block contents + const char* data = contents.data(); // Pointer to where Read put the data + if (options.verify_checksums) { + const uint32_t crc = crc32c::Unmask(DecodeFixed32(data + n + 1)); + const uint32_t actual = crc32c::Value(data, n + 1); + if (actual != crc) { + delete[] buf; + s = Status::Corruption("block checksum mismatch"); + return s; + } + } + + switch (data[n]) { + case kNoCompression: + if (data != buf) { + // File implementation gave us pointer to some other data. + // Use it directly under the assumption that it will be live + // while the file is open. + delete[] buf; + result->data = Slice(data, n); + result->heap_allocated = false; + result->cachable = false; // Do not double-cache + } else { + result->data = Slice(buf, n); + result->heap_allocated = true; + result->cachable = true; + } + + // Ok + break; + case kSnappyCompression: { + size_t ulength = 0; + if (!port::Snappy_GetUncompressedLength(data, n, &ulength)) { + delete[] buf; + return Status::Corruption("corrupted compressed block contents"); + } + char* ubuf = new char[ulength]; + if (!port::Snappy_Uncompress(data, n, ubuf)) { + delete[] buf; + delete[] ubuf; + return Status::Corruption("corrupted compressed block contents"); + } + delete[] buf; + result->data = Slice(ubuf, ulength); + result->heap_allocated = true; + result->cachable = true; + break; + } + default: + delete[] buf; + return Status::Corruption("bad block type"); + } + + return Status::OK(); +} + +} // namespace leveldb diff --git a/ios/Pods/leveldb-library/table/format.h b/ios/Pods/leveldb-library/table/format.h new file mode 100644 index 000000000..6c0b80c01 --- /dev/null +++ b/ios/Pods/leveldb-library/table/format.h @@ -0,0 +1,108 @@ +// Copyright (c) 2011 The LevelDB Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. See the AUTHORS file for names of contributors. + +#ifndef STORAGE_LEVELDB_TABLE_FORMAT_H_ +#define STORAGE_LEVELDB_TABLE_FORMAT_H_ + +#include +#include +#include "leveldb/slice.h" +#include "leveldb/status.h" +#include "leveldb/table_builder.h" + +namespace leveldb { + +class Block; +class RandomAccessFile; +struct ReadOptions; + +// BlockHandle is a pointer to the extent of a file that stores a data +// block or a meta block. +class BlockHandle { + public: + BlockHandle(); + + // The offset of the block in the file. + uint64_t offset() const { return offset_; } + void set_offset(uint64_t offset) { offset_ = offset; } + + // The size of the stored block + uint64_t size() const { return size_; } + void set_size(uint64_t size) { size_ = size; } + + void EncodeTo(std::string* dst) const; + Status DecodeFrom(Slice* input); + + // Maximum encoding length of a BlockHandle + enum { kMaxEncodedLength = 10 + 10 }; + + private: + uint64_t offset_; + uint64_t size_; +}; + +// Footer encapsulates the fixed information stored at the tail +// end of every table file. +class Footer { + public: + Footer() { } + + // The block handle for the metaindex block of the table + const BlockHandle& metaindex_handle() const { return metaindex_handle_; } + void set_metaindex_handle(const BlockHandle& h) { metaindex_handle_ = h; } + + // The block handle for the index block of the table + const BlockHandle& index_handle() const { + return index_handle_; + } + void set_index_handle(const BlockHandle& h) { + index_handle_ = h; + } + + void EncodeTo(std::string* dst) const; + Status DecodeFrom(Slice* input); + + // Encoded length of a Footer. Note that the serialization of a + // Footer will always occupy exactly this many bytes. It consists + // of two block handles and a magic number. + enum { + kEncodedLength = 2*BlockHandle::kMaxEncodedLength + 8 + }; + + private: + BlockHandle metaindex_handle_; + BlockHandle index_handle_; +}; + +// kTableMagicNumber was picked by running +// echo http://code.google.com/p/leveldb/ | sha1sum +// and taking the leading 64 bits. +static const uint64_t kTableMagicNumber = 0xdb4775248b80fb57ull; + +// 1-byte type + 32-bit crc +static const size_t kBlockTrailerSize = 5; + +struct BlockContents { + Slice data; // Actual contents of data + bool cachable; // True iff data can be cached + bool heap_allocated; // True iff caller should delete[] data.data() +}; + +// Read the block identified by "handle" from "file". On failure +// return non-OK. On success fill *result and return OK. +extern Status ReadBlock(RandomAccessFile* file, + const ReadOptions& options, + const BlockHandle& handle, + BlockContents* result); + +// Implementation details follow. Clients should ignore, + +inline BlockHandle::BlockHandle() + : offset_(~static_cast(0)), + size_(~static_cast(0)) { +} + +} // namespace leveldb + +#endif // STORAGE_LEVELDB_TABLE_FORMAT_H_ diff --git a/ios/Pods/leveldb-library/table/iterator.cc b/ios/Pods/leveldb-library/table/iterator.cc new file mode 100644 index 000000000..3d1c87fde --- /dev/null +++ b/ios/Pods/leveldb-library/table/iterator.cc @@ -0,0 +1,67 @@ +// Copyright (c) 2011 The LevelDB Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. See the AUTHORS file for names of contributors. + +#include "leveldb/iterator.h" + +namespace leveldb { + +Iterator::Iterator() { + cleanup_.function = NULL; + cleanup_.next = NULL; +} + +Iterator::~Iterator() { + if (cleanup_.function != NULL) { + (*cleanup_.function)(cleanup_.arg1, cleanup_.arg2); + for (Cleanup* c = cleanup_.next; c != NULL; ) { + (*c->function)(c->arg1, c->arg2); + Cleanup* next = c->next; + delete c; + c = next; + } + } +} + +void Iterator::RegisterCleanup(CleanupFunction func, void* arg1, void* arg2) { + assert(func != NULL); + Cleanup* c; + if (cleanup_.function == NULL) { + c = &cleanup_; + } else { + c = new Cleanup; + c->next = cleanup_.next; + cleanup_.next = c; + } + c->function = func; + c->arg1 = arg1; + c->arg2 = arg2; +} + +namespace { +class EmptyIterator : public Iterator { + public: + EmptyIterator(const Status& s) : status_(s) { } + virtual bool Valid() const { return false; } + virtual void Seek(const Slice& target) { } + virtual void SeekToFirst() { } + virtual void SeekToLast() { } + virtual void Next() { assert(false); } + virtual void Prev() { assert(false); } + Slice key() const { assert(false); return Slice(); } + Slice value() const { assert(false); return Slice(); } + virtual Status status() const { return status_; } + private: + Status status_; +}; +} // namespace + +Iterator* NewEmptyIterator() { + return new EmptyIterator(Status::OK()); +} + +Iterator* NewErrorIterator(const Status& status) { + return new EmptyIterator(status); +} + +} // namespace leveldb diff --git a/ios/Pods/leveldb-library/table/iterator_wrapper.h b/ios/Pods/leveldb-library/table/iterator_wrapper.h new file mode 100644 index 000000000..9e16b3dbe --- /dev/null +++ b/ios/Pods/leveldb-library/table/iterator_wrapper.h @@ -0,0 +1,63 @@ +// Copyright (c) 2011 The LevelDB Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. See the AUTHORS file for names of contributors. + +#ifndef STORAGE_LEVELDB_TABLE_ITERATOR_WRAPPER_H_ +#define STORAGE_LEVELDB_TABLE_ITERATOR_WRAPPER_H_ + +namespace leveldb { + +// A internal wrapper class with an interface similar to Iterator that +// caches the valid() and key() results for an underlying iterator. +// This can help avoid virtual function calls and also gives better +// cache locality. +class IteratorWrapper { + public: + IteratorWrapper(): iter_(NULL), valid_(false) { } + explicit IteratorWrapper(Iterator* iter): iter_(NULL) { + Set(iter); + } + ~IteratorWrapper() { delete iter_; } + Iterator* iter() const { return iter_; } + + // Takes ownership of "iter" and will delete it when destroyed, or + // when Set() is invoked again. + void Set(Iterator* iter) { + delete iter_; + iter_ = iter; + if (iter_ == NULL) { + valid_ = false; + } else { + Update(); + } + } + + + // Iterator interface methods + bool Valid() const { return valid_; } + Slice key() const { assert(Valid()); return key_; } + Slice value() const { assert(Valid()); return iter_->value(); } + // Methods below require iter() != NULL + Status status() const { assert(iter_); return iter_->status(); } + void Next() { assert(iter_); iter_->Next(); Update(); } + void Prev() { assert(iter_); iter_->Prev(); Update(); } + void Seek(const Slice& k) { assert(iter_); iter_->Seek(k); Update(); } + void SeekToFirst() { assert(iter_); iter_->SeekToFirst(); Update(); } + void SeekToLast() { assert(iter_); iter_->SeekToLast(); Update(); } + + private: + void Update() { + valid_ = iter_->Valid(); + if (valid_) { + key_ = iter_->key(); + } + } + + Iterator* iter_; + bool valid_; + Slice key_; +}; + +} // namespace leveldb + +#endif // STORAGE_LEVELDB_TABLE_ITERATOR_WRAPPER_H_ diff --git a/ios/Pods/leveldb-library/table/merger.cc b/ios/Pods/leveldb-library/table/merger.cc new file mode 100644 index 000000000..2dde4dc21 --- /dev/null +++ b/ios/Pods/leveldb-library/table/merger.cc @@ -0,0 +1,197 @@ +// Copyright (c) 2011 The LevelDB Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. See the AUTHORS file for names of contributors. + +#include "table/merger.h" + +#include "leveldb/comparator.h" +#include "leveldb/iterator.h" +#include "table/iterator_wrapper.h" + +namespace leveldb { + +namespace { +class MergingIterator : public Iterator { + public: + MergingIterator(const Comparator* comparator, Iterator** children, int n) + : comparator_(comparator), + children_(new IteratorWrapper[n]), + n_(n), + current_(NULL), + direction_(kForward) { + for (int i = 0; i < n; i++) { + children_[i].Set(children[i]); + } + } + + virtual ~MergingIterator() { + delete[] children_; + } + + virtual bool Valid() const { + return (current_ != NULL); + } + + virtual void SeekToFirst() { + for (int i = 0; i < n_; i++) { + children_[i].SeekToFirst(); + } + FindSmallest(); + direction_ = kForward; + } + + virtual void SeekToLast() { + for (int i = 0; i < n_; i++) { + children_[i].SeekToLast(); + } + FindLargest(); + direction_ = kReverse; + } + + virtual void Seek(const Slice& target) { + for (int i = 0; i < n_; i++) { + children_[i].Seek(target); + } + FindSmallest(); + direction_ = kForward; + } + + virtual void Next() { + assert(Valid()); + + // Ensure that all children are positioned after key(). + // If we are moving in the forward direction, it is already + // true for all of the non-current_ children since current_ is + // the smallest child and key() == current_->key(). Otherwise, + // we explicitly position the non-current_ children. + if (direction_ != kForward) { + for (int i = 0; i < n_; i++) { + IteratorWrapper* child = &children_[i]; + if (child != current_) { + child->Seek(key()); + if (child->Valid() && + comparator_->Compare(key(), child->key()) == 0) { + child->Next(); + } + } + } + direction_ = kForward; + } + + current_->Next(); + FindSmallest(); + } + + virtual void Prev() { + assert(Valid()); + + // Ensure that all children are positioned before key(). + // If we are moving in the reverse direction, it is already + // true for all of the non-current_ children since current_ is + // the largest child and key() == current_->key(). Otherwise, + // we explicitly position the non-current_ children. + if (direction_ != kReverse) { + for (int i = 0; i < n_; i++) { + IteratorWrapper* child = &children_[i]; + if (child != current_) { + child->Seek(key()); + if (child->Valid()) { + // Child is at first entry >= key(). Step back one to be < key() + child->Prev(); + } else { + // Child has no entries >= key(). Position at last entry. + child->SeekToLast(); + } + } + } + direction_ = kReverse; + } + + current_->Prev(); + FindLargest(); + } + + virtual Slice key() const { + assert(Valid()); + return current_->key(); + } + + virtual Slice value() const { + assert(Valid()); + return current_->value(); + } + + virtual Status status() const { + Status status; + for (int i = 0; i < n_; i++) { + status = children_[i].status(); + if (!status.ok()) { + break; + } + } + return status; + } + + private: + void FindSmallest(); + void FindLargest(); + + // We might want to use a heap in case there are lots of children. + // For now we use a simple array since we expect a very small number + // of children in leveldb. + const Comparator* comparator_; + IteratorWrapper* children_; + int n_; + IteratorWrapper* current_; + + // Which direction is the iterator moving? + enum Direction { + kForward, + kReverse + }; + Direction direction_; +}; + +void MergingIterator::FindSmallest() { + IteratorWrapper* smallest = NULL; + for (int i = 0; i < n_; i++) { + IteratorWrapper* child = &children_[i]; + if (child->Valid()) { + if (smallest == NULL) { + smallest = child; + } else if (comparator_->Compare(child->key(), smallest->key()) < 0) { + smallest = child; + } + } + } + current_ = smallest; +} + +void MergingIterator::FindLargest() { + IteratorWrapper* largest = NULL; + for (int i = n_-1; i >= 0; i--) { + IteratorWrapper* child = &children_[i]; + if (child->Valid()) { + if (largest == NULL) { + largest = child; + } else if (comparator_->Compare(child->key(), largest->key()) > 0) { + largest = child; + } + } + } + current_ = largest; +} +} // namespace + +Iterator* NewMergingIterator(const Comparator* cmp, Iterator** list, int n) { + assert(n >= 0); + if (n == 0) { + return NewEmptyIterator(); + } else if (n == 1) { + return list[0]; + } else { + return new MergingIterator(cmp, list, n); + } +} + +} // namespace leveldb diff --git a/ios/Pods/leveldb-library/table/merger.h b/ios/Pods/leveldb-library/table/merger.h new file mode 100644 index 000000000..91ddd80fa --- /dev/null +++ b/ios/Pods/leveldb-library/table/merger.h @@ -0,0 +1,26 @@ +// Copyright (c) 2011 The LevelDB Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. See the AUTHORS file for names of contributors. + +#ifndef STORAGE_LEVELDB_TABLE_MERGER_H_ +#define STORAGE_LEVELDB_TABLE_MERGER_H_ + +namespace leveldb { + +class Comparator; +class Iterator; + +// Return an iterator that provided the union of the data in +// children[0,n-1]. Takes ownership of the child iterators and +// will delete them when the result iterator is deleted. +// +// The result does no duplicate suppression. I.e., if a particular +// key is present in K child iterators, it will be yielded K times. +// +// REQUIRES: n >= 0 +extern Iterator* NewMergingIterator( + const Comparator* comparator, Iterator** children, int n); + +} // namespace leveldb + +#endif // STORAGE_LEVELDB_TABLE_MERGER_H_ diff --git a/ios/Pods/leveldb-library/table/table.cc b/ios/Pods/leveldb-library/table/table.cc new file mode 100644 index 000000000..dff8a8259 --- /dev/null +++ b/ios/Pods/leveldb-library/table/table.cc @@ -0,0 +1,285 @@ +// Copyright (c) 2011 The LevelDB Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. See the AUTHORS file for names of contributors. + +#include "leveldb/table.h" + +#include "leveldb/cache.h" +#include "leveldb/comparator.h" +#include "leveldb/env.h" +#include "leveldb/filter_policy.h" +#include "leveldb/options.h" +#include "table/block.h" +#include "table/filter_block.h" +#include "table/format.h" +#include "table/two_level_iterator.h" +#include "util/coding.h" + +namespace leveldb { + +struct Table::Rep { + ~Rep() { + delete filter; + delete [] filter_data; + delete index_block; + } + + Options options; + Status status; + RandomAccessFile* file; + uint64_t cache_id; + FilterBlockReader* filter; + const char* filter_data; + + BlockHandle metaindex_handle; // Handle to metaindex_block: saved from footer + Block* index_block; +}; + +Status Table::Open(const Options& options, + RandomAccessFile* file, + uint64_t size, + Table** table) { + *table = NULL; + if (size < Footer::kEncodedLength) { + return Status::Corruption("file is too short to be an sstable"); + } + + char footer_space[Footer::kEncodedLength]; + Slice footer_input; + Status s = file->Read(size - Footer::kEncodedLength, Footer::kEncodedLength, + &footer_input, footer_space); + if (!s.ok()) return s; + + Footer footer; + s = footer.DecodeFrom(&footer_input); + if (!s.ok()) return s; + + // Read the index block + BlockContents contents; + Block* index_block = NULL; + if (s.ok()) { + ReadOptions opt; + if (options.paranoid_checks) { + opt.verify_checksums = true; + } + s = ReadBlock(file, opt, footer.index_handle(), &contents); + if (s.ok()) { + index_block = new Block(contents); + } + } + + if (s.ok()) { + // We've successfully read the footer and the index block: we're + // ready to serve requests. + Rep* rep = new Table::Rep; + rep->options = options; + rep->file = file; + rep->metaindex_handle = footer.metaindex_handle(); + rep->index_block = index_block; + rep->cache_id = (options.block_cache ? options.block_cache->NewId() : 0); + rep->filter_data = NULL; + rep->filter = NULL; + *table = new Table(rep); + (*table)->ReadMeta(footer); + } else { + if (index_block) delete index_block; + } + + return s; +} + +void Table::ReadMeta(const Footer& footer) { + if (rep_->options.filter_policy == NULL) { + return; // Do not need any metadata + } + + // TODO(sanjay): Skip this if footer.metaindex_handle() size indicates + // it is an empty block. + ReadOptions opt; + if (rep_->options.paranoid_checks) { + opt.verify_checksums = true; + } + BlockContents contents; + if (!ReadBlock(rep_->file, opt, footer.metaindex_handle(), &contents).ok()) { + // Do not propagate errors since meta info is not needed for operation + return; + } + Block* meta = new Block(contents); + + Iterator* iter = meta->NewIterator(BytewiseComparator()); + std::string key = "filter."; + key.append(rep_->options.filter_policy->Name()); + iter->Seek(key); + if (iter->Valid() && iter->key() == Slice(key)) { + ReadFilter(iter->value()); + } + delete iter; + delete meta; +} + +void Table::ReadFilter(const Slice& filter_handle_value) { + Slice v = filter_handle_value; + BlockHandle filter_handle; + if (!filter_handle.DecodeFrom(&v).ok()) { + return; + } + + // We might want to unify with ReadBlock() if we start + // requiring checksum verification in Table::Open. + ReadOptions opt; + if (rep_->options.paranoid_checks) { + opt.verify_checksums = true; + } + BlockContents block; + if (!ReadBlock(rep_->file, opt, filter_handle, &block).ok()) { + return; + } + if (block.heap_allocated) { + rep_->filter_data = block.data.data(); // Will need to delete later + } + rep_->filter = new FilterBlockReader(rep_->options.filter_policy, block.data); +} + +Table::~Table() { + delete rep_; +} + +static void DeleteBlock(void* arg, void* ignored) { + delete reinterpret_cast(arg); +} + +static void DeleteCachedBlock(const Slice& key, void* value) { + Block* block = reinterpret_cast(value); + delete block; +} + +static void ReleaseBlock(void* arg, void* h) { + Cache* cache = reinterpret_cast(arg); + Cache::Handle* handle = reinterpret_cast(h); + cache->Release(handle); +} + +// Convert an index iterator value (i.e., an encoded BlockHandle) +// into an iterator over the contents of the corresponding block. +Iterator* Table::BlockReader(void* arg, + const ReadOptions& options, + const Slice& index_value) { + Table* table = reinterpret_cast(arg); + Cache* block_cache = table->rep_->options.block_cache; + Block* block = NULL; + Cache::Handle* cache_handle = NULL; + + BlockHandle handle; + Slice input = index_value; + Status s = handle.DecodeFrom(&input); + // We intentionally allow extra stuff in index_value so that we + // can add more features in the future. + + if (s.ok()) { + BlockContents contents; + if (block_cache != NULL) { + char cache_key_buffer[16]; + EncodeFixed64(cache_key_buffer, table->rep_->cache_id); + EncodeFixed64(cache_key_buffer+8, handle.offset()); + Slice key(cache_key_buffer, sizeof(cache_key_buffer)); + cache_handle = block_cache->Lookup(key); + if (cache_handle != NULL) { + block = reinterpret_cast(block_cache->Value(cache_handle)); + } else { + s = ReadBlock(table->rep_->file, options, handle, &contents); + if (s.ok()) { + block = new Block(contents); + if (contents.cachable && options.fill_cache) { + cache_handle = block_cache->Insert( + key, block, block->size(), &DeleteCachedBlock); + } + } + } + } else { + s = ReadBlock(table->rep_->file, options, handle, &contents); + if (s.ok()) { + block = new Block(contents); + } + } + } + + Iterator* iter; + if (block != NULL) { + iter = block->NewIterator(table->rep_->options.comparator); + if (cache_handle == NULL) { + iter->RegisterCleanup(&DeleteBlock, block, NULL); + } else { + iter->RegisterCleanup(&ReleaseBlock, block_cache, cache_handle); + } + } else { + iter = NewErrorIterator(s); + } + return iter; +} + +Iterator* Table::NewIterator(const ReadOptions& options) const { + return NewTwoLevelIterator( + rep_->index_block->NewIterator(rep_->options.comparator), + &Table::BlockReader, const_cast(this), options); +} + +Status Table::InternalGet(const ReadOptions& options, const Slice& k, + void* arg, + void (*saver)(void*, const Slice&, const Slice&)) { + Status s; + Iterator* iiter = rep_->index_block->NewIterator(rep_->options.comparator); + iiter->Seek(k); + if (iiter->Valid()) { + Slice handle_value = iiter->value(); + FilterBlockReader* filter = rep_->filter; + BlockHandle handle; + if (filter != NULL && + handle.DecodeFrom(&handle_value).ok() && + !filter->KeyMayMatch(handle.offset(), k)) { + // Not found + } else { + Iterator* block_iter = BlockReader(this, options, iiter->value()); + block_iter->Seek(k); + if (block_iter->Valid()) { + (*saver)(arg, block_iter->key(), block_iter->value()); + } + s = block_iter->status(); + delete block_iter; + } + } + if (s.ok()) { + s = iiter->status(); + } + delete iiter; + return s; +} + + +uint64_t Table::ApproximateOffsetOf(const Slice& key) const { + Iterator* index_iter = + rep_->index_block->NewIterator(rep_->options.comparator); + index_iter->Seek(key); + uint64_t result; + if (index_iter->Valid()) { + BlockHandle handle; + Slice input = index_iter->value(); + Status s = handle.DecodeFrom(&input); + if (s.ok()) { + result = handle.offset(); + } else { + // Strange: we can't decode the block handle in the index block. + // We'll just return the offset of the metaindex block, which is + // close to the whole file size for this case. + result = rep_->metaindex_handle.offset(); + } + } else { + // key is past the last key in the file. Approximate the offset + // by returning the offset of the metaindex block (which is + // right near the end of the file). + result = rep_->metaindex_handle.offset(); + } + delete index_iter; + return result; +} + +} // namespace leveldb diff --git a/ios/Pods/leveldb-library/table/table_builder.cc b/ios/Pods/leveldb-library/table/table_builder.cc new file mode 100644 index 000000000..62002c84f --- /dev/null +++ b/ios/Pods/leveldb-library/table/table_builder.cc @@ -0,0 +1,270 @@ +// Copyright (c) 2011 The LevelDB Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. See the AUTHORS file for names of contributors. + +#include "leveldb/table_builder.h" + +#include +#include "leveldb/comparator.h" +#include "leveldb/env.h" +#include "leveldb/filter_policy.h" +#include "leveldb/options.h" +#include "table/block_builder.h" +#include "table/filter_block.h" +#include "table/format.h" +#include "util/coding.h" +#include "util/crc32c.h" + +namespace leveldb { + +struct TableBuilder::Rep { + Options options; + Options index_block_options; + WritableFile* file; + uint64_t offset; + Status status; + BlockBuilder data_block; + BlockBuilder index_block; + std::string last_key; + int64_t num_entries; + bool closed; // Either Finish() or Abandon() has been called. + FilterBlockBuilder* filter_block; + + // We do not emit the index entry for a block until we have seen the + // first key for the next data block. This allows us to use shorter + // keys in the index block. For example, consider a block boundary + // between the keys "the quick brown fox" and "the who". We can use + // "the r" as the key for the index block entry since it is >= all + // entries in the first block and < all entries in subsequent + // blocks. + // + // Invariant: r->pending_index_entry is true only if data_block is empty. + bool pending_index_entry; + BlockHandle pending_handle; // Handle to add to index block + + std::string compressed_output; + + Rep(const Options& opt, WritableFile* f) + : options(opt), + index_block_options(opt), + file(f), + offset(0), + data_block(&options), + index_block(&index_block_options), + num_entries(0), + closed(false), + filter_block(opt.filter_policy == NULL ? NULL + : new FilterBlockBuilder(opt.filter_policy)), + pending_index_entry(false) { + index_block_options.block_restart_interval = 1; + } +}; + +TableBuilder::TableBuilder(const Options& options, WritableFile* file) + : rep_(new Rep(options, file)) { + if (rep_->filter_block != NULL) { + rep_->filter_block->StartBlock(0); + } +} + +TableBuilder::~TableBuilder() { + assert(rep_->closed); // Catch errors where caller forgot to call Finish() + delete rep_->filter_block; + delete rep_; +} + +Status TableBuilder::ChangeOptions(const Options& options) { + // Note: if more fields are added to Options, update + // this function to catch changes that should not be allowed to + // change in the middle of building a Table. + if (options.comparator != rep_->options.comparator) { + return Status::InvalidArgument("changing comparator while building table"); + } + + // Note that any live BlockBuilders point to rep_->options and therefore + // will automatically pick up the updated options. + rep_->options = options; + rep_->index_block_options = options; + rep_->index_block_options.block_restart_interval = 1; + return Status::OK(); +} + +void TableBuilder::Add(const Slice& key, const Slice& value) { + Rep* r = rep_; + assert(!r->closed); + if (!ok()) return; + if (r->num_entries > 0) { + assert(r->options.comparator->Compare(key, Slice(r->last_key)) > 0); + } + + if (r->pending_index_entry) { + assert(r->data_block.empty()); + r->options.comparator->FindShortestSeparator(&r->last_key, key); + std::string handle_encoding; + r->pending_handle.EncodeTo(&handle_encoding); + r->index_block.Add(r->last_key, Slice(handle_encoding)); + r->pending_index_entry = false; + } + + if (r->filter_block != NULL) { + r->filter_block->AddKey(key); + } + + r->last_key.assign(key.data(), key.size()); + r->num_entries++; + r->data_block.Add(key, value); + + const size_t estimated_block_size = r->data_block.CurrentSizeEstimate(); + if (estimated_block_size >= r->options.block_size) { + Flush(); + } +} + +void TableBuilder::Flush() { + Rep* r = rep_; + assert(!r->closed); + if (!ok()) return; + if (r->data_block.empty()) return; + assert(!r->pending_index_entry); + WriteBlock(&r->data_block, &r->pending_handle); + if (ok()) { + r->pending_index_entry = true; + r->status = r->file->Flush(); + } + if (r->filter_block != NULL) { + r->filter_block->StartBlock(r->offset); + } +} + +void TableBuilder::WriteBlock(BlockBuilder* block, BlockHandle* handle) { + // File format contains a sequence of blocks where each block has: + // block_data: uint8[n] + // type: uint8 + // crc: uint32 + assert(ok()); + Rep* r = rep_; + Slice raw = block->Finish(); + + Slice block_contents; + CompressionType type = r->options.compression; + // TODO(postrelease): Support more compression options: zlib? + switch (type) { + case kNoCompression: + block_contents = raw; + break; + + case kSnappyCompression: { + std::string* compressed = &r->compressed_output; + if (port::Snappy_Compress(raw.data(), raw.size(), compressed) && + compressed->size() < raw.size() - (raw.size() / 8u)) { + block_contents = *compressed; + } else { + // Snappy not supported, or compressed less than 12.5%, so just + // store uncompressed form + block_contents = raw; + type = kNoCompression; + } + break; + } + } + WriteRawBlock(block_contents, type, handle); + r->compressed_output.clear(); + block->Reset(); +} + +void TableBuilder::WriteRawBlock(const Slice& block_contents, + CompressionType type, + BlockHandle* handle) { + Rep* r = rep_; + handle->set_offset(r->offset); + handle->set_size(block_contents.size()); + r->status = r->file->Append(block_contents); + if (r->status.ok()) { + char trailer[kBlockTrailerSize]; + trailer[0] = type; + uint32_t crc = crc32c::Value(block_contents.data(), block_contents.size()); + crc = crc32c::Extend(crc, trailer, 1); // Extend crc to cover block type + EncodeFixed32(trailer+1, crc32c::Mask(crc)); + r->status = r->file->Append(Slice(trailer, kBlockTrailerSize)); + if (r->status.ok()) { + r->offset += block_contents.size() + kBlockTrailerSize; + } + } +} + +Status TableBuilder::status() const { + return rep_->status; +} + +Status TableBuilder::Finish() { + Rep* r = rep_; + Flush(); + assert(!r->closed); + r->closed = true; + + BlockHandle filter_block_handle, metaindex_block_handle, index_block_handle; + + // Write filter block + if (ok() && r->filter_block != NULL) { + WriteRawBlock(r->filter_block->Finish(), kNoCompression, + &filter_block_handle); + } + + // Write metaindex block + if (ok()) { + BlockBuilder meta_index_block(&r->options); + if (r->filter_block != NULL) { + // Add mapping from "filter.Name" to location of filter data + std::string key = "filter."; + key.append(r->options.filter_policy->Name()); + std::string handle_encoding; + filter_block_handle.EncodeTo(&handle_encoding); + meta_index_block.Add(key, handle_encoding); + } + + // TODO(postrelease): Add stats and other meta blocks + WriteBlock(&meta_index_block, &metaindex_block_handle); + } + + // Write index block + if (ok()) { + if (r->pending_index_entry) { + r->options.comparator->FindShortSuccessor(&r->last_key); + std::string handle_encoding; + r->pending_handle.EncodeTo(&handle_encoding); + r->index_block.Add(r->last_key, Slice(handle_encoding)); + r->pending_index_entry = false; + } + WriteBlock(&r->index_block, &index_block_handle); + } + + // Write footer + if (ok()) { + Footer footer; + footer.set_metaindex_handle(metaindex_block_handle); + footer.set_index_handle(index_block_handle); + std::string footer_encoding; + footer.EncodeTo(&footer_encoding); + r->status = r->file->Append(footer_encoding); + if (r->status.ok()) { + r->offset += footer_encoding.size(); + } + } + return r->status; +} + +void TableBuilder::Abandon() { + Rep* r = rep_; + assert(!r->closed); + r->closed = true; +} + +uint64_t TableBuilder::NumEntries() const { + return rep_->num_entries; +} + +uint64_t TableBuilder::FileSize() const { + return rep_->offset; +} + +} // namespace leveldb diff --git a/ios/Pods/leveldb-library/table/table_test.cc b/ios/Pods/leveldb-library/table/table_test.cc new file mode 100644 index 000000000..c723bf84c --- /dev/null +++ b/ios/Pods/leveldb-library/table/table_test.cc @@ -0,0 +1,868 @@ +// Copyright (c) 2011 The LevelDB Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. See the AUTHORS file for names of contributors. + +#include "leveldb/table.h" + +#include +#include +#include "db/dbformat.h" +#include "db/memtable.h" +#include "db/write_batch_internal.h" +#include "leveldb/db.h" +#include "leveldb/env.h" +#include "leveldb/iterator.h" +#include "leveldb/table_builder.h" +#include "table/block.h" +#include "table/block_builder.h" +#include "table/format.h" +#include "util/random.h" +#include "util/testharness.h" +#include "util/testutil.h" + +namespace leveldb { + +// Return reverse of "key". +// Used to test non-lexicographic comparators. +static std::string Reverse(const Slice& key) { + std::string str(key.ToString()); + std::string rev(""); + for (std::string::reverse_iterator rit = str.rbegin(); + rit != str.rend(); ++rit) { + rev.push_back(*rit); + } + return rev; +} + +namespace { +class ReverseKeyComparator : public Comparator { + public: + virtual const char* Name() const { + return "leveldb.ReverseBytewiseComparator"; + } + + virtual int Compare(const Slice& a, const Slice& b) const { + return BytewiseComparator()->Compare(Reverse(a), Reverse(b)); + } + + virtual void FindShortestSeparator( + std::string* start, + const Slice& limit) const { + std::string s = Reverse(*start); + std::string l = Reverse(limit); + BytewiseComparator()->FindShortestSeparator(&s, l); + *start = Reverse(s); + } + + virtual void FindShortSuccessor(std::string* key) const { + std::string s = Reverse(*key); + BytewiseComparator()->FindShortSuccessor(&s); + *key = Reverse(s); + } +}; +} // namespace +static ReverseKeyComparator reverse_key_comparator; + +static void Increment(const Comparator* cmp, std::string* key) { + if (cmp == BytewiseComparator()) { + key->push_back('\0'); + } else { + assert(cmp == &reverse_key_comparator); + std::string rev = Reverse(*key); + rev.push_back('\0'); + *key = Reverse(rev); + } +} + +// An STL comparator that uses a Comparator +namespace { +struct STLLessThan { + const Comparator* cmp; + + STLLessThan() : cmp(BytewiseComparator()) { } + STLLessThan(const Comparator* c) : cmp(c) { } + bool operator()(const std::string& a, const std::string& b) const { + return cmp->Compare(Slice(a), Slice(b)) < 0; + } +}; +} // namespace + +class StringSink: public WritableFile { + public: + ~StringSink() { } + + const std::string& contents() const { return contents_; } + + virtual Status Close() { return Status::OK(); } + virtual Status Flush() { return Status::OK(); } + virtual Status Sync() { return Status::OK(); } + + virtual Status Append(const Slice& data) { + contents_.append(data.data(), data.size()); + return Status::OK(); + } + + private: + std::string contents_; +}; + + +class StringSource: public RandomAccessFile { + public: + StringSource(const Slice& contents) + : contents_(contents.data(), contents.size()) { + } + + virtual ~StringSource() { } + + uint64_t Size() const { return contents_.size(); } + + virtual Status Read(uint64_t offset, size_t n, Slice* result, + char* scratch) const { + if (offset > contents_.size()) { + return Status::InvalidArgument("invalid Read offset"); + } + if (offset + n > contents_.size()) { + n = contents_.size() - offset; + } + memcpy(scratch, &contents_[offset], n); + *result = Slice(scratch, n); + return Status::OK(); + } + + private: + std::string contents_; +}; + +typedef std::map KVMap; + +// Helper class for tests to unify the interface between +// BlockBuilder/TableBuilder and Block/Table. +class Constructor { + public: + explicit Constructor(const Comparator* cmp) : data_(STLLessThan(cmp)) { } + virtual ~Constructor() { } + + void Add(const std::string& key, const Slice& value) { + data_[key] = value.ToString(); + } + + // Finish constructing the data structure with all the keys that have + // been added so far. Returns the keys in sorted order in "*keys" + // and stores the key/value pairs in "*kvmap" + void Finish(const Options& options, + std::vector* keys, + KVMap* kvmap) { + *kvmap = data_; + keys->clear(); + for (KVMap::const_iterator it = data_.begin(); + it != data_.end(); + ++it) { + keys->push_back(it->first); + } + data_.clear(); + Status s = FinishImpl(options, *kvmap); + ASSERT_TRUE(s.ok()) << s.ToString(); + } + + // Construct the data structure from the data in "data" + virtual Status FinishImpl(const Options& options, const KVMap& data) = 0; + + virtual Iterator* NewIterator() const = 0; + + virtual const KVMap& data() { return data_; } + + virtual DB* db() const { return NULL; } // Overridden in DBConstructor + + private: + KVMap data_; +}; + +class BlockConstructor: public Constructor { + public: + explicit BlockConstructor(const Comparator* cmp) + : Constructor(cmp), + comparator_(cmp), + block_(NULL) { } + ~BlockConstructor() { + delete block_; + } + virtual Status FinishImpl(const Options& options, const KVMap& data) { + delete block_; + block_ = NULL; + BlockBuilder builder(&options); + + for (KVMap::const_iterator it = data.begin(); + it != data.end(); + ++it) { + builder.Add(it->first, it->second); + } + // Open the block + data_ = builder.Finish().ToString(); + BlockContents contents; + contents.data = data_; + contents.cachable = false; + contents.heap_allocated = false; + block_ = new Block(contents); + return Status::OK(); + } + virtual Iterator* NewIterator() const { + return block_->NewIterator(comparator_); + } + + private: + const Comparator* comparator_; + std::string data_; + Block* block_; + + BlockConstructor(); +}; + +class TableConstructor: public Constructor { + public: + TableConstructor(const Comparator* cmp) + : Constructor(cmp), + source_(NULL), table_(NULL) { + } + ~TableConstructor() { + Reset(); + } + virtual Status FinishImpl(const Options& options, const KVMap& data) { + Reset(); + StringSink sink; + TableBuilder builder(options, &sink); + + for (KVMap::const_iterator it = data.begin(); + it != data.end(); + ++it) { + builder.Add(it->first, it->second); + ASSERT_TRUE(builder.status().ok()); + } + Status s = builder.Finish(); + ASSERT_TRUE(s.ok()) << s.ToString(); + + ASSERT_EQ(sink.contents().size(), builder.FileSize()); + + // Open the table + source_ = new StringSource(sink.contents()); + Options table_options; + table_options.comparator = options.comparator; + return Table::Open(table_options, source_, sink.contents().size(), &table_); + } + + virtual Iterator* NewIterator() const { + return table_->NewIterator(ReadOptions()); + } + + uint64_t ApproximateOffsetOf(const Slice& key) const { + return table_->ApproximateOffsetOf(key); + } + + private: + void Reset() { + delete table_; + delete source_; + table_ = NULL; + source_ = NULL; + } + + StringSource* source_; + Table* table_; + + TableConstructor(); +}; + +// A helper class that converts internal format keys into user keys +class KeyConvertingIterator: public Iterator { + public: + explicit KeyConvertingIterator(Iterator* iter) : iter_(iter) { } + virtual ~KeyConvertingIterator() { delete iter_; } + virtual bool Valid() const { return iter_->Valid(); } + virtual void Seek(const Slice& target) { + ParsedInternalKey ikey(target, kMaxSequenceNumber, kTypeValue); + std::string encoded; + AppendInternalKey(&encoded, ikey); + iter_->Seek(encoded); + } + virtual void SeekToFirst() { iter_->SeekToFirst(); } + virtual void SeekToLast() { iter_->SeekToLast(); } + virtual void Next() { iter_->Next(); } + virtual void Prev() { iter_->Prev(); } + + virtual Slice key() const { + assert(Valid()); + ParsedInternalKey key; + if (!ParseInternalKey(iter_->key(), &key)) { + status_ = Status::Corruption("malformed internal key"); + return Slice("corrupted key"); + } + return key.user_key; + } + + virtual Slice value() const { return iter_->value(); } + virtual Status status() const { + return status_.ok() ? iter_->status() : status_; + } + + private: + mutable Status status_; + Iterator* iter_; + + // No copying allowed + KeyConvertingIterator(const KeyConvertingIterator&); + void operator=(const KeyConvertingIterator&); +}; + +class MemTableConstructor: public Constructor { + public: + explicit MemTableConstructor(const Comparator* cmp) + : Constructor(cmp), + internal_comparator_(cmp) { + memtable_ = new MemTable(internal_comparator_); + memtable_->Ref(); + } + ~MemTableConstructor() { + memtable_->Unref(); + } + virtual Status FinishImpl(const Options& options, const KVMap& data) { + memtable_->Unref(); + memtable_ = new MemTable(internal_comparator_); + memtable_->Ref(); + int seq = 1; + for (KVMap::const_iterator it = data.begin(); + it != data.end(); + ++it) { + memtable_->Add(seq, kTypeValue, it->first, it->second); + seq++; + } + return Status::OK(); + } + virtual Iterator* NewIterator() const { + return new KeyConvertingIterator(memtable_->NewIterator()); + } + + private: + InternalKeyComparator internal_comparator_; + MemTable* memtable_; +}; + +class DBConstructor: public Constructor { + public: + explicit DBConstructor(const Comparator* cmp) + : Constructor(cmp), + comparator_(cmp) { + db_ = NULL; + NewDB(); + } + ~DBConstructor() { + delete db_; + } + virtual Status FinishImpl(const Options& options, const KVMap& data) { + delete db_; + db_ = NULL; + NewDB(); + for (KVMap::const_iterator it = data.begin(); + it != data.end(); + ++it) { + WriteBatch batch; + batch.Put(it->first, it->second); + ASSERT_TRUE(db_->Write(WriteOptions(), &batch).ok()); + } + return Status::OK(); + } + virtual Iterator* NewIterator() const { + return db_->NewIterator(ReadOptions()); + } + + virtual DB* db() const { return db_; } + + private: + void NewDB() { + std::string name = test::TmpDir() + "/table_testdb"; + + Options options; + options.comparator = comparator_; + Status status = DestroyDB(name, options); + ASSERT_TRUE(status.ok()) << status.ToString(); + + options.create_if_missing = true; + options.error_if_exists = true; + options.write_buffer_size = 10000; // Something small to force merging + status = DB::Open(options, name, &db_); + ASSERT_TRUE(status.ok()) << status.ToString(); + } + + const Comparator* comparator_; + DB* db_; +}; + +enum TestType { + TABLE_TEST, + BLOCK_TEST, + MEMTABLE_TEST, + DB_TEST +}; + +struct TestArgs { + TestType type; + bool reverse_compare; + int restart_interval; +}; + +static const TestArgs kTestArgList[] = { + { TABLE_TEST, false, 16 }, + { TABLE_TEST, false, 1 }, + { TABLE_TEST, false, 1024 }, + { TABLE_TEST, true, 16 }, + { TABLE_TEST, true, 1 }, + { TABLE_TEST, true, 1024 }, + + { BLOCK_TEST, false, 16 }, + { BLOCK_TEST, false, 1 }, + { BLOCK_TEST, false, 1024 }, + { BLOCK_TEST, true, 16 }, + { BLOCK_TEST, true, 1 }, + { BLOCK_TEST, true, 1024 }, + + // Restart interval does not matter for memtables + { MEMTABLE_TEST, false, 16 }, + { MEMTABLE_TEST, true, 16 }, + + // Do not bother with restart interval variations for DB + { DB_TEST, false, 16 }, + { DB_TEST, true, 16 }, +}; +static const int kNumTestArgs = sizeof(kTestArgList) / sizeof(kTestArgList[0]); + +class Harness { + public: + Harness() : constructor_(NULL) { } + + void Init(const TestArgs& args) { + delete constructor_; + constructor_ = NULL; + options_ = Options(); + + options_.block_restart_interval = args.restart_interval; + // Use shorter block size for tests to exercise block boundary + // conditions more. + options_.block_size = 256; + if (args.reverse_compare) { + options_.comparator = &reverse_key_comparator; + } + switch (args.type) { + case TABLE_TEST: + constructor_ = new TableConstructor(options_.comparator); + break; + case BLOCK_TEST: + constructor_ = new BlockConstructor(options_.comparator); + break; + case MEMTABLE_TEST: + constructor_ = new MemTableConstructor(options_.comparator); + break; + case DB_TEST: + constructor_ = new DBConstructor(options_.comparator); + break; + } + } + + ~Harness() { + delete constructor_; + } + + void Add(const std::string& key, const std::string& value) { + constructor_->Add(key, value); + } + + void Test(Random* rnd) { + std::vector keys; + KVMap data; + constructor_->Finish(options_, &keys, &data); + + TestForwardScan(keys, data); + TestBackwardScan(keys, data); + TestRandomAccess(rnd, keys, data); + } + + void TestForwardScan(const std::vector& keys, + const KVMap& data) { + Iterator* iter = constructor_->NewIterator(); + ASSERT_TRUE(!iter->Valid()); + iter->SeekToFirst(); + for (KVMap::const_iterator model_iter = data.begin(); + model_iter != data.end(); + ++model_iter) { + ASSERT_EQ(ToString(data, model_iter), ToString(iter)); + iter->Next(); + } + ASSERT_TRUE(!iter->Valid()); + delete iter; + } + + void TestBackwardScan(const std::vector& keys, + const KVMap& data) { + Iterator* iter = constructor_->NewIterator(); + ASSERT_TRUE(!iter->Valid()); + iter->SeekToLast(); + for (KVMap::const_reverse_iterator model_iter = data.rbegin(); + model_iter != data.rend(); + ++model_iter) { + ASSERT_EQ(ToString(data, model_iter), ToString(iter)); + iter->Prev(); + } + ASSERT_TRUE(!iter->Valid()); + delete iter; + } + + void TestRandomAccess(Random* rnd, + const std::vector& keys, + const KVMap& data) { + static const bool kVerbose = false; + Iterator* iter = constructor_->NewIterator(); + ASSERT_TRUE(!iter->Valid()); + KVMap::const_iterator model_iter = data.begin(); + if (kVerbose) fprintf(stderr, "---\n"); + for (int i = 0; i < 200; i++) { + const int toss = rnd->Uniform(5); + switch (toss) { + case 0: { + if (iter->Valid()) { + if (kVerbose) fprintf(stderr, "Next\n"); + iter->Next(); + ++model_iter; + ASSERT_EQ(ToString(data, model_iter), ToString(iter)); + } + break; + } + + case 1: { + if (kVerbose) fprintf(stderr, "SeekToFirst\n"); + iter->SeekToFirst(); + model_iter = data.begin(); + ASSERT_EQ(ToString(data, model_iter), ToString(iter)); + break; + } + + case 2: { + std::string key = PickRandomKey(rnd, keys); + model_iter = data.lower_bound(key); + if (kVerbose) fprintf(stderr, "Seek '%s'\n", + EscapeString(key).c_str()); + iter->Seek(Slice(key)); + ASSERT_EQ(ToString(data, model_iter), ToString(iter)); + break; + } + + case 3: { + if (iter->Valid()) { + if (kVerbose) fprintf(stderr, "Prev\n"); + iter->Prev(); + if (model_iter == data.begin()) { + model_iter = data.end(); // Wrap around to invalid value + } else { + --model_iter; + } + ASSERT_EQ(ToString(data, model_iter), ToString(iter)); + } + break; + } + + case 4: { + if (kVerbose) fprintf(stderr, "SeekToLast\n"); + iter->SeekToLast(); + if (keys.empty()) { + model_iter = data.end(); + } else { + std::string last = data.rbegin()->first; + model_iter = data.lower_bound(last); + } + ASSERT_EQ(ToString(data, model_iter), ToString(iter)); + break; + } + } + } + delete iter; + } + + std::string ToString(const KVMap& data, const KVMap::const_iterator& it) { + if (it == data.end()) { + return "END"; + } else { + return "'" + it->first + "->" + it->second + "'"; + } + } + + std::string ToString(const KVMap& data, + const KVMap::const_reverse_iterator& it) { + if (it == data.rend()) { + return "END"; + } else { + return "'" + it->first + "->" + it->second + "'"; + } + } + + std::string ToString(const Iterator* it) { + if (!it->Valid()) { + return "END"; + } else { + return "'" + it->key().ToString() + "->" + it->value().ToString() + "'"; + } + } + + std::string PickRandomKey(Random* rnd, const std::vector& keys) { + if (keys.empty()) { + return "foo"; + } else { + const int index = rnd->Uniform(keys.size()); + std::string result = keys[index]; + switch (rnd->Uniform(3)) { + case 0: + // Return an existing key + break; + case 1: { + // Attempt to return something smaller than an existing key + if (result.size() > 0 && result[result.size()-1] > '\0') { + result[result.size()-1]--; + } + break; + } + case 2: { + // Return something larger than an existing key + Increment(options_.comparator, &result); + break; + } + } + return result; + } + } + + // Returns NULL if not running against a DB + DB* db() const { return constructor_->db(); } + + private: + Options options_; + Constructor* constructor_; +}; + +// Test empty table/block. +TEST(Harness, Empty) { + for (int i = 0; i < kNumTestArgs; i++) { + Init(kTestArgList[i]); + Random rnd(test::RandomSeed() + 1); + Test(&rnd); + } +} + +// Special test for a block with no restart entries. The C++ leveldb +// code never generates such blocks, but the Java version of leveldb +// seems to. +TEST(Harness, ZeroRestartPointsInBlock) { + char data[sizeof(uint32_t)]; + memset(data, 0, sizeof(data)); + BlockContents contents; + contents.data = Slice(data, sizeof(data)); + contents.cachable = false; + contents.heap_allocated = false; + Block block(contents); + Iterator* iter = block.NewIterator(BytewiseComparator()); + iter->SeekToFirst(); + ASSERT_TRUE(!iter->Valid()); + iter->SeekToLast(); + ASSERT_TRUE(!iter->Valid()); + iter->Seek("foo"); + ASSERT_TRUE(!iter->Valid()); + delete iter; +} + +// Test the empty key +TEST(Harness, SimpleEmptyKey) { + for (int i = 0; i < kNumTestArgs; i++) { + Init(kTestArgList[i]); + Random rnd(test::RandomSeed() + 1); + Add("", "v"); + Test(&rnd); + } +} + +TEST(Harness, SimpleSingle) { + for (int i = 0; i < kNumTestArgs; i++) { + Init(kTestArgList[i]); + Random rnd(test::RandomSeed() + 2); + Add("abc", "v"); + Test(&rnd); + } +} + +TEST(Harness, SimpleMulti) { + for (int i = 0; i < kNumTestArgs; i++) { + Init(kTestArgList[i]); + Random rnd(test::RandomSeed() + 3); + Add("abc", "v"); + Add("abcd", "v"); + Add("ac", "v2"); + Test(&rnd); + } +} + +TEST(Harness, SimpleSpecialKey) { + for (int i = 0; i < kNumTestArgs; i++) { + Init(kTestArgList[i]); + Random rnd(test::RandomSeed() + 4); + Add("\xff\xff", "v3"); + Test(&rnd); + } +} + +TEST(Harness, Randomized) { + for (int i = 0; i < kNumTestArgs; i++) { + Init(kTestArgList[i]); + Random rnd(test::RandomSeed() + 5); + for (int num_entries = 0; num_entries < 2000; + num_entries += (num_entries < 50 ? 1 : 200)) { + if ((num_entries % 10) == 0) { + fprintf(stderr, "case %d of %d: num_entries = %d\n", + (i + 1), int(kNumTestArgs), num_entries); + } + for (int e = 0; e < num_entries; e++) { + std::string v; + Add(test::RandomKey(&rnd, rnd.Skewed(4)), + test::RandomString(&rnd, rnd.Skewed(5), &v).ToString()); + } + Test(&rnd); + } + } +} + +TEST(Harness, RandomizedLongDB) { + Random rnd(test::RandomSeed()); + TestArgs args = { DB_TEST, false, 16 }; + Init(args); + int num_entries = 100000; + for (int e = 0; e < num_entries; e++) { + std::string v; + Add(test::RandomKey(&rnd, rnd.Skewed(4)), + test::RandomString(&rnd, rnd.Skewed(5), &v).ToString()); + } + Test(&rnd); + + // We must have created enough data to force merging + int files = 0; + for (int level = 0; level < config::kNumLevels; level++) { + std::string value; + char name[100]; + snprintf(name, sizeof(name), "leveldb.num-files-at-level%d", level); + ASSERT_TRUE(db()->GetProperty(name, &value)); + files += atoi(value.c_str()); + } + ASSERT_GT(files, 0); +} + +class MemTableTest { }; + +TEST(MemTableTest, Simple) { + InternalKeyComparator cmp(BytewiseComparator()); + MemTable* memtable = new MemTable(cmp); + memtable->Ref(); + WriteBatch batch; + WriteBatchInternal::SetSequence(&batch, 100); + batch.Put(std::string("k1"), std::string("v1")); + batch.Put(std::string("k2"), std::string("v2")); + batch.Put(std::string("k3"), std::string("v3")); + batch.Put(std::string("largekey"), std::string("vlarge")); + ASSERT_TRUE(WriteBatchInternal::InsertInto(&batch, memtable).ok()); + + Iterator* iter = memtable->NewIterator(); + iter->SeekToFirst(); + while (iter->Valid()) { + fprintf(stderr, "key: '%s' -> '%s'\n", + iter->key().ToString().c_str(), + iter->value().ToString().c_str()); + iter->Next(); + } + + delete iter; + memtable->Unref(); +} + +static bool Between(uint64_t val, uint64_t low, uint64_t high) { + bool result = (val >= low) && (val <= high); + if (!result) { + fprintf(stderr, "Value %llu is not in range [%llu, %llu]\n", + (unsigned long long)(val), + (unsigned long long)(low), + (unsigned long long)(high)); + } + return result; +} + +class TableTest { }; + +TEST(TableTest, ApproximateOffsetOfPlain) { + TableConstructor c(BytewiseComparator()); + c.Add("k01", "hello"); + c.Add("k02", "hello2"); + c.Add("k03", std::string(10000, 'x')); + c.Add("k04", std::string(200000, 'x')); + c.Add("k05", std::string(300000, 'x')); + c.Add("k06", "hello3"); + c.Add("k07", std::string(100000, 'x')); + std::vector keys; + KVMap kvmap; + Options options; + options.block_size = 1024; + options.compression = kNoCompression; + c.Finish(options, &keys, &kvmap); + + ASSERT_TRUE(Between(c.ApproximateOffsetOf("abc"), 0, 0)); + ASSERT_TRUE(Between(c.ApproximateOffsetOf("k01"), 0, 0)); + ASSERT_TRUE(Between(c.ApproximateOffsetOf("k01a"), 0, 0)); + ASSERT_TRUE(Between(c.ApproximateOffsetOf("k02"), 0, 0)); + ASSERT_TRUE(Between(c.ApproximateOffsetOf("k03"), 0, 0)); + ASSERT_TRUE(Between(c.ApproximateOffsetOf("k04"), 10000, 11000)); + ASSERT_TRUE(Between(c.ApproximateOffsetOf("k04a"), 210000, 211000)); + ASSERT_TRUE(Between(c.ApproximateOffsetOf("k05"), 210000, 211000)); + ASSERT_TRUE(Between(c.ApproximateOffsetOf("k06"), 510000, 511000)); + ASSERT_TRUE(Between(c.ApproximateOffsetOf("k07"), 510000, 511000)); + ASSERT_TRUE(Between(c.ApproximateOffsetOf("xyz"), 610000, 612000)); + +} + +static bool SnappyCompressionSupported() { + std::string out; + Slice in = "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"; + return port::Snappy_Compress(in.data(), in.size(), &out); +} + +TEST(TableTest, ApproximateOffsetOfCompressed) { + if (!SnappyCompressionSupported()) { + fprintf(stderr, "skipping compression tests\n"); + return; + } + + Random rnd(301); + TableConstructor c(BytewiseComparator()); + std::string tmp; + c.Add("k01", "hello"); + c.Add("k02", test::CompressibleString(&rnd, 0.25, 10000, &tmp)); + c.Add("k03", "hello3"); + c.Add("k04", test::CompressibleString(&rnd, 0.25, 10000, &tmp)); + std::vector keys; + KVMap kvmap; + Options options; + options.block_size = 1024; + options.compression = kSnappyCompression; + c.Finish(options, &keys, &kvmap); + + ASSERT_TRUE(Between(c.ApproximateOffsetOf("abc"), 0, 0)); + ASSERT_TRUE(Between(c.ApproximateOffsetOf("k01"), 0, 0)); + ASSERT_TRUE(Between(c.ApproximateOffsetOf("k02"), 0, 0)); + ASSERT_TRUE(Between(c.ApproximateOffsetOf("k03"), 2000, 3000)); + ASSERT_TRUE(Between(c.ApproximateOffsetOf("k04"), 2000, 3000)); + ASSERT_TRUE(Between(c.ApproximateOffsetOf("xyz"), 4000, 6000)); +} + +} // namespace leveldb + +int main(int argc, char** argv) { + return leveldb::test::RunAllTests(); +} diff --git a/ios/Pods/leveldb-library/table/two_level_iterator.cc b/ios/Pods/leveldb-library/table/two_level_iterator.cc new file mode 100644 index 000000000..7822ebab9 --- /dev/null +++ b/ios/Pods/leveldb-library/table/two_level_iterator.cc @@ -0,0 +1,182 @@ +// Copyright (c) 2011 The LevelDB Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. See the AUTHORS file for names of contributors. + +#include "table/two_level_iterator.h" + +#include "leveldb/table.h" +#include "table/block.h" +#include "table/format.h" +#include "table/iterator_wrapper.h" + +namespace leveldb { + +namespace { + +typedef Iterator* (*BlockFunction)(void*, const ReadOptions&, const Slice&); + +class TwoLevelIterator: public Iterator { + public: + TwoLevelIterator( + Iterator* index_iter, + BlockFunction block_function, + void* arg, + const ReadOptions& options); + + virtual ~TwoLevelIterator(); + + virtual void Seek(const Slice& target); + virtual void SeekToFirst(); + virtual void SeekToLast(); + virtual void Next(); + virtual void Prev(); + + virtual bool Valid() const { + return data_iter_.Valid(); + } + virtual Slice key() const { + assert(Valid()); + return data_iter_.key(); + } + virtual Slice value() const { + assert(Valid()); + return data_iter_.value(); + } + virtual Status status() const { + // It'd be nice if status() returned a const Status& instead of a Status + if (!index_iter_.status().ok()) { + return index_iter_.status(); + } else if (data_iter_.iter() != NULL && !data_iter_.status().ok()) { + return data_iter_.status(); + } else { + return status_; + } + } + + private: + void SaveError(const Status& s) { + if (status_.ok() && !s.ok()) status_ = s; + } + void SkipEmptyDataBlocksForward(); + void SkipEmptyDataBlocksBackward(); + void SetDataIterator(Iterator* data_iter); + void InitDataBlock(); + + BlockFunction block_function_; + void* arg_; + const ReadOptions options_; + Status status_; + IteratorWrapper index_iter_; + IteratorWrapper data_iter_; // May be NULL + // If data_iter_ is non-NULL, then "data_block_handle_" holds the + // "index_value" passed to block_function_ to create the data_iter_. + std::string data_block_handle_; +}; + +TwoLevelIterator::TwoLevelIterator( + Iterator* index_iter, + BlockFunction block_function, + void* arg, + const ReadOptions& options) + : block_function_(block_function), + arg_(arg), + options_(options), + index_iter_(index_iter), + data_iter_(NULL) { +} + +TwoLevelIterator::~TwoLevelIterator() { +} + +void TwoLevelIterator::Seek(const Slice& target) { + index_iter_.Seek(target); + InitDataBlock(); + if (data_iter_.iter() != NULL) data_iter_.Seek(target); + SkipEmptyDataBlocksForward(); +} + +void TwoLevelIterator::SeekToFirst() { + index_iter_.SeekToFirst(); + InitDataBlock(); + if (data_iter_.iter() != NULL) data_iter_.SeekToFirst(); + SkipEmptyDataBlocksForward(); +} + +void TwoLevelIterator::SeekToLast() { + index_iter_.SeekToLast(); + InitDataBlock(); + if (data_iter_.iter() != NULL) data_iter_.SeekToLast(); + SkipEmptyDataBlocksBackward(); +} + +void TwoLevelIterator::Next() { + assert(Valid()); + data_iter_.Next(); + SkipEmptyDataBlocksForward(); +} + +void TwoLevelIterator::Prev() { + assert(Valid()); + data_iter_.Prev(); + SkipEmptyDataBlocksBackward(); +} + + +void TwoLevelIterator::SkipEmptyDataBlocksForward() { + while (data_iter_.iter() == NULL || !data_iter_.Valid()) { + // Move to next block + if (!index_iter_.Valid()) { + SetDataIterator(NULL); + return; + } + index_iter_.Next(); + InitDataBlock(); + if (data_iter_.iter() != NULL) data_iter_.SeekToFirst(); + } +} + +void TwoLevelIterator::SkipEmptyDataBlocksBackward() { + while (data_iter_.iter() == NULL || !data_iter_.Valid()) { + // Move to next block + if (!index_iter_.Valid()) { + SetDataIterator(NULL); + return; + } + index_iter_.Prev(); + InitDataBlock(); + if (data_iter_.iter() != NULL) data_iter_.SeekToLast(); + } +} + +void TwoLevelIterator::SetDataIterator(Iterator* data_iter) { + if (data_iter_.iter() != NULL) SaveError(data_iter_.status()); + data_iter_.Set(data_iter); +} + +void TwoLevelIterator::InitDataBlock() { + if (!index_iter_.Valid()) { + SetDataIterator(NULL); + } else { + Slice handle = index_iter_.value(); + if (data_iter_.iter() != NULL && handle.compare(data_block_handle_) == 0) { + // data_iter_ is already constructed with this iterator, so + // no need to change anything + } else { + Iterator* iter = (*block_function_)(arg_, options_, handle); + data_block_handle_.assign(handle.data(), handle.size()); + SetDataIterator(iter); + } + } +} + +} // namespace + +Iterator* NewTwoLevelIterator( + Iterator* index_iter, + BlockFunction block_function, + void* arg, + const ReadOptions& options) { + return new TwoLevelIterator(index_iter, block_function, arg, options); +} + +} // namespace leveldb diff --git a/ios/Pods/leveldb-library/table/two_level_iterator.h b/ios/Pods/leveldb-library/table/two_level_iterator.h new file mode 100644 index 000000000..629ca3452 --- /dev/null +++ b/ios/Pods/leveldb-library/table/two_level_iterator.h @@ -0,0 +1,34 @@ +// Copyright (c) 2011 The LevelDB Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. See the AUTHORS file for names of contributors. + +#ifndef STORAGE_LEVELDB_TABLE_TWO_LEVEL_ITERATOR_H_ +#define STORAGE_LEVELDB_TABLE_TWO_LEVEL_ITERATOR_H_ + +#include "leveldb/iterator.h" + +namespace leveldb { + +struct ReadOptions; + +// Return a new two level iterator. A two-level iterator contains an +// index iterator whose values point to a sequence of blocks where +// each block is itself a sequence of key,value pairs. The returned +// two-level iterator yields the concatenation of all key/value pairs +// in the sequence of blocks. Takes ownership of "index_iter" and +// will delete it when no longer needed. +// +// Uses a supplied function to convert an index_iter value into +// an iterator over the contents of the corresponding block. +extern Iterator* NewTwoLevelIterator( + Iterator* index_iter, + Iterator* (*block_function)( + void* arg, + const ReadOptions& options, + const Slice& index_value), + void* arg, + const ReadOptions& options); + +} // namespace leveldb + +#endif // STORAGE_LEVELDB_TABLE_TWO_LEVEL_ITERATOR_H_ diff --git a/ios/Pods/leveldb-library/util/arena.cc b/ios/Pods/leveldb-library/util/arena.cc new file mode 100644 index 000000000..9367f7149 --- /dev/null +++ b/ios/Pods/leveldb-library/util/arena.cc @@ -0,0 +1,68 @@ +// Copyright (c) 2011 The LevelDB Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. See the AUTHORS file for names of contributors. + +#include "util/arena.h" +#include + +namespace leveldb { + +static const int kBlockSize = 4096; + +Arena::Arena() { + blocks_memory_ = 0; + alloc_ptr_ = NULL; // First allocation will allocate a block + alloc_bytes_remaining_ = 0; +} + +Arena::~Arena() { + for (size_t i = 0; i < blocks_.size(); i++) { + delete[] blocks_[i]; + } +} + +char* Arena::AllocateFallback(size_t bytes) { + if (bytes > kBlockSize / 4) { + // Object is more than a quarter of our block size. Allocate it separately + // to avoid wasting too much space in leftover bytes. + char* result = AllocateNewBlock(bytes); + return result; + } + + // We waste the remaining space in the current block. + alloc_ptr_ = AllocateNewBlock(kBlockSize); + alloc_bytes_remaining_ = kBlockSize; + + char* result = alloc_ptr_; + alloc_ptr_ += bytes; + alloc_bytes_remaining_ -= bytes; + return result; +} + +char* Arena::AllocateAligned(size_t bytes) { + const int align = (sizeof(void*) > 8) ? sizeof(void*) : 8; + assert((align & (align-1)) == 0); // Pointer size should be a power of 2 + size_t current_mod = reinterpret_cast(alloc_ptr_) & (align-1); + size_t slop = (current_mod == 0 ? 0 : align - current_mod); + size_t needed = bytes + slop; + char* result; + if (needed <= alloc_bytes_remaining_) { + result = alloc_ptr_ + slop; + alloc_ptr_ += needed; + alloc_bytes_remaining_ -= needed; + } else { + // AllocateFallback always returned aligned memory + result = AllocateFallback(bytes); + } + assert((reinterpret_cast(result) & (align-1)) == 0); + return result; +} + +char* Arena::AllocateNewBlock(size_t block_bytes) { + char* result = new char[block_bytes]; + blocks_memory_ += block_bytes; + blocks_.push_back(result); + return result; +} + +} // namespace leveldb diff --git a/ios/Pods/leveldb-library/util/arena.h b/ios/Pods/leveldb-library/util/arena.h new file mode 100644 index 000000000..73bbf1cb9 --- /dev/null +++ b/ios/Pods/leveldb-library/util/arena.h @@ -0,0 +1,68 @@ +// Copyright (c) 2011 The LevelDB Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. See the AUTHORS file for names of contributors. + +#ifndef STORAGE_LEVELDB_UTIL_ARENA_H_ +#define STORAGE_LEVELDB_UTIL_ARENA_H_ + +#include +#include +#include +#include + +namespace leveldb { + +class Arena { + public: + Arena(); + ~Arena(); + + // Return a pointer to a newly allocated memory block of "bytes" bytes. + char* Allocate(size_t bytes); + + // Allocate memory with the normal alignment guarantees provided by malloc + char* AllocateAligned(size_t bytes); + + // Returns an estimate of the total memory usage of data allocated + // by the arena (including space allocated but not yet used for user + // allocations). + size_t MemoryUsage() const { + return blocks_memory_ + blocks_.capacity() * sizeof(char*); + } + + private: + char* AllocateFallback(size_t bytes); + char* AllocateNewBlock(size_t block_bytes); + + // Allocation state + char* alloc_ptr_; + size_t alloc_bytes_remaining_; + + // Array of new[] allocated memory blocks + std::vector blocks_; + + // Bytes of memory in blocks allocated so far + size_t blocks_memory_; + + // No copying allowed + Arena(const Arena&); + void operator=(const Arena&); +}; + +inline char* Arena::Allocate(size_t bytes) { + // The semantics of what to return are a bit messy if we allow + // 0-byte allocations, so we disallow them here (we don't need + // them for our internal use). + assert(bytes > 0); + if (bytes <= alloc_bytes_remaining_) { + char* result = alloc_ptr_; + alloc_ptr_ += bytes; + alloc_bytes_remaining_ -= bytes; + return result; + } + return AllocateFallback(bytes); +} + +} // namespace leveldb + +#endif // STORAGE_LEVELDB_UTIL_ARENA_H_ diff --git a/ios/Pods/leveldb-library/util/arena_test.cc b/ios/Pods/leveldb-library/util/arena_test.cc new file mode 100644 index 000000000..58e870ec4 --- /dev/null +++ b/ios/Pods/leveldb-library/util/arena_test.cc @@ -0,0 +1,68 @@ +// Copyright (c) 2011 The LevelDB Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. See the AUTHORS file for names of contributors. + +#include "util/arena.h" + +#include "util/random.h" +#include "util/testharness.h" + +namespace leveldb { + +class ArenaTest { }; + +TEST(ArenaTest, Empty) { + Arena arena; +} + +TEST(ArenaTest, Simple) { + std::vector > allocated; + Arena arena; + const int N = 100000; + size_t bytes = 0; + Random rnd(301); + for (int i = 0; i < N; i++) { + size_t s; + if (i % (N / 10) == 0) { + s = i; + } else { + s = rnd.OneIn(4000) ? rnd.Uniform(6000) : + (rnd.OneIn(10) ? rnd.Uniform(100) : rnd.Uniform(20)); + } + if (s == 0) { + // Our arena disallows size 0 allocations. + s = 1; + } + char* r; + if (rnd.OneIn(10)) { + r = arena.AllocateAligned(s); + } else { + r = arena.Allocate(s); + } + + for (size_t b = 0; b < s; b++) { + // Fill the "i"th allocation with a known bit pattern + r[b] = i % 256; + } + bytes += s; + allocated.push_back(std::make_pair(s, r)); + ASSERT_GE(arena.MemoryUsage(), bytes); + if (i > N/10) { + ASSERT_LE(arena.MemoryUsage(), bytes * 1.10); + } + } + for (size_t i = 0; i < allocated.size(); i++) { + size_t num_bytes = allocated[i].first; + const char* p = allocated[i].second; + for (size_t b = 0; b < num_bytes; b++) { + // Check the "i"th allocation for the known bit pattern + ASSERT_EQ(int(p[b]) & 0xff, i % 256); + } + } +} + +} // namespace leveldb + +int main(int argc, char** argv) { + return leveldb::test::RunAllTests(); +} diff --git a/ios/Pods/leveldb-library/util/bloom.cc b/ios/Pods/leveldb-library/util/bloom.cc new file mode 100644 index 000000000..a27a2ace2 --- /dev/null +++ b/ios/Pods/leveldb-library/util/bloom.cc @@ -0,0 +1,95 @@ +// Copyright (c) 2012 The LevelDB Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. See the AUTHORS file for names of contributors. + +#include "leveldb/filter_policy.h" + +#include "leveldb/slice.h" +#include "util/hash.h" + +namespace leveldb { + +namespace { +static uint32_t BloomHash(const Slice& key) { + return Hash(key.data(), key.size(), 0xbc9f1d34); +} + +class BloomFilterPolicy : public FilterPolicy { + private: + size_t bits_per_key_; + size_t k_; + + public: + explicit BloomFilterPolicy(int bits_per_key) + : bits_per_key_(bits_per_key) { + // We intentionally round down to reduce probing cost a little bit + k_ = static_cast(bits_per_key * 0.69); // 0.69 =~ ln(2) + if (k_ < 1) k_ = 1; + if (k_ > 30) k_ = 30; + } + + virtual const char* Name() const { + return "leveldb.BuiltinBloomFilter2"; + } + + virtual void CreateFilter(const Slice* keys, int n, std::string* dst) const { + // Compute bloom filter size (in both bits and bytes) + size_t bits = n * bits_per_key_; + + // For small n, we can see a very high false positive rate. Fix it + // by enforcing a minimum bloom filter length. + if (bits < 64) bits = 64; + + size_t bytes = (bits + 7) / 8; + bits = bytes * 8; + + const size_t init_size = dst->size(); + dst->resize(init_size + bytes, 0); + dst->push_back(static_cast(k_)); // Remember # of probes in filter + char* array = &(*dst)[init_size]; + for (size_t i = 0; i < n; i++) { + // Use double-hashing to generate a sequence of hash values. + // See analysis in [Kirsch,Mitzenmacher 2006]. + uint32_t h = BloomHash(keys[i]); + const uint32_t delta = (h >> 17) | (h << 15); // Rotate right 17 bits + for (size_t j = 0; j < k_; j++) { + const uint32_t bitpos = h % bits; + array[bitpos/8] |= (1 << (bitpos % 8)); + h += delta; + } + } + } + + virtual bool KeyMayMatch(const Slice& key, const Slice& bloom_filter) const { + const size_t len = bloom_filter.size(); + if (len < 2) return false; + + const char* array = bloom_filter.data(); + const size_t bits = (len - 1) * 8; + + // Use the encoded k so that we can read filters generated by + // bloom filters created using different parameters. + const size_t k = array[len-1]; + if (k > 30) { + // Reserved for potentially new encodings for short bloom filters. + // Consider it a match. + return true; + } + + uint32_t h = BloomHash(key); + const uint32_t delta = (h >> 17) | (h << 15); // Rotate right 17 bits + for (size_t j = 0; j < k; j++) { + const uint32_t bitpos = h % bits; + if ((array[bitpos/8] & (1 << (bitpos % 8))) == 0) return false; + h += delta; + } + return true; + } +}; +} + +const FilterPolicy* NewBloomFilterPolicy(int bits_per_key) { + return new BloomFilterPolicy(bits_per_key); +} + +} // namespace leveldb diff --git a/ios/Pods/leveldb-library/util/bloom_test.cc b/ios/Pods/leveldb-library/util/bloom_test.cc new file mode 100644 index 000000000..77fb1b315 --- /dev/null +++ b/ios/Pods/leveldb-library/util/bloom_test.cc @@ -0,0 +1,161 @@ +// Copyright (c) 2012 The LevelDB Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. See the AUTHORS file for names of contributors. + +#include "leveldb/filter_policy.h" + +#include "util/coding.h" +#include "util/logging.h" +#include "util/testharness.h" +#include "util/testutil.h" + +namespace leveldb { + +static const int kVerbose = 1; + +static Slice Key(int i, char* buffer) { + EncodeFixed32(buffer, i); + return Slice(buffer, sizeof(uint32_t)); +} + +class BloomTest { + private: + const FilterPolicy* policy_; + std::string filter_; + std::vector keys_; + + public: + BloomTest() : policy_(NewBloomFilterPolicy(10)) { } + + ~BloomTest() { + delete policy_; + } + + void Reset() { + keys_.clear(); + filter_.clear(); + } + + void Add(const Slice& s) { + keys_.push_back(s.ToString()); + } + + void Build() { + std::vector key_slices; + for (size_t i = 0; i < keys_.size(); i++) { + key_slices.push_back(Slice(keys_[i])); + } + filter_.clear(); + policy_->CreateFilter(&key_slices[0], key_slices.size(), &filter_); + keys_.clear(); + if (kVerbose >= 2) DumpFilter(); + } + + size_t FilterSize() const { + return filter_.size(); + } + + void DumpFilter() { + fprintf(stderr, "F("); + for (size_t i = 0; i+1 < filter_.size(); i++) { + const unsigned int c = static_cast(filter_[i]); + for (int j = 0; j < 8; j++) { + fprintf(stderr, "%c", (c & (1 <KeyMayMatch(s, filter_); + } + + double FalsePositiveRate() { + char buffer[sizeof(int)]; + int result = 0; + for (int i = 0; i < 10000; i++) { + if (Matches(Key(i + 1000000000, buffer))) { + result++; + } + } + return result / 10000.0; + } +}; + +TEST(BloomTest, EmptyFilter) { + ASSERT_TRUE(! Matches("hello")); + ASSERT_TRUE(! Matches("world")); +} + +TEST(BloomTest, Small) { + Add("hello"); + Add("world"); + ASSERT_TRUE(Matches("hello")); + ASSERT_TRUE(Matches("world")); + ASSERT_TRUE(! Matches("x")); + ASSERT_TRUE(! Matches("foo")); +} + +static int NextLength(int length) { + if (length < 10) { + length += 1; + } else if (length < 100) { + length += 10; + } else if (length < 1000) { + length += 100; + } else { + length += 1000; + } + return length; +} + +TEST(BloomTest, VaryingLengths) { + char buffer[sizeof(int)]; + + // Count number of filters that significantly exceed the false positive rate + int mediocre_filters = 0; + int good_filters = 0; + + for (int length = 1; length <= 10000; length = NextLength(length)) { + Reset(); + for (int i = 0; i < length; i++) { + Add(Key(i, buffer)); + } + Build(); + + ASSERT_LE(FilterSize(), static_cast((length * 10 / 8) + 40)) + << length; + + // All added keys must match + for (int i = 0; i < length; i++) { + ASSERT_TRUE(Matches(Key(i, buffer))) + << "Length " << length << "; key " << i; + } + + // Check false positive rate + double rate = FalsePositiveRate(); + if (kVerbose >= 1) { + fprintf(stderr, "False positives: %5.2f%% @ length = %6d ; bytes = %6d\n", + rate*100.0, length, static_cast(FilterSize())); + } + ASSERT_LE(rate, 0.02); // Must not be over 2% + if (rate > 0.0125) mediocre_filters++; // Allowed, but not too often + else good_filters++; + } + if (kVerbose >= 1) { + fprintf(stderr, "Filters: %d good, %d mediocre\n", + good_filters, mediocre_filters); + } + ASSERT_LE(mediocre_filters, good_filters/5); +} + +// Different bits-per-byte + +} // namespace leveldb + +int main(int argc, char** argv) { + return leveldb::test::RunAllTests(); +} diff --git a/ios/Pods/leveldb-library/util/cache.cc b/ios/Pods/leveldb-library/util/cache.cc new file mode 100644 index 000000000..8b197bc02 --- /dev/null +++ b/ios/Pods/leveldb-library/util/cache.cc @@ -0,0 +1,325 @@ +// Copyright (c) 2011 The LevelDB Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. See the AUTHORS file for names of contributors. + +#include +#include +#include + +#include "leveldb/cache.h" +#include "port/port.h" +#include "util/hash.h" +#include "util/mutexlock.h" + +namespace leveldb { + +Cache::~Cache() { +} + +namespace { + +// LRU cache implementation + +// An entry is a variable length heap-allocated structure. Entries +// are kept in a circular doubly linked list ordered by access time. +struct LRUHandle { + void* value; + void (*deleter)(const Slice&, void* value); + LRUHandle* next_hash; + LRUHandle* next; + LRUHandle* prev; + size_t charge; // TODO(opt): Only allow uint32_t? + size_t key_length; + uint32_t refs; + uint32_t hash; // Hash of key(); used for fast sharding and comparisons + char key_data[1]; // Beginning of key + + Slice key() const { + // For cheaper lookups, we allow a temporary Handle object + // to store a pointer to a key in "value". + if (next == this) { + return *(reinterpret_cast(value)); + } else { + return Slice(key_data, key_length); + } + } +}; + +// We provide our own simple hash table since it removes a whole bunch +// of porting hacks and is also faster than some of the built-in hash +// table implementations in some of the compiler/runtime combinations +// we have tested. E.g., readrandom speeds up by ~5% over the g++ +// 4.4.3's builtin hashtable. +class HandleTable { + public: + HandleTable() : length_(0), elems_(0), list_(NULL) { Resize(); } + ~HandleTable() { delete[] list_; } + + LRUHandle* Lookup(const Slice& key, uint32_t hash) { + return *FindPointer(key, hash); + } + + LRUHandle* Insert(LRUHandle* h) { + LRUHandle** ptr = FindPointer(h->key(), h->hash); + LRUHandle* old = *ptr; + h->next_hash = (old == NULL ? NULL : old->next_hash); + *ptr = h; + if (old == NULL) { + ++elems_; + if (elems_ > length_) { + // Since each cache entry is fairly large, we aim for a small + // average linked list length (<= 1). + Resize(); + } + } + return old; + } + + LRUHandle* Remove(const Slice& key, uint32_t hash) { + LRUHandle** ptr = FindPointer(key, hash); + LRUHandle* result = *ptr; + if (result != NULL) { + *ptr = result->next_hash; + --elems_; + } + return result; + } + + private: + // The table consists of an array of buckets where each bucket is + // a linked list of cache entries that hash into the bucket. + uint32_t length_; + uint32_t elems_; + LRUHandle** list_; + + // Return a pointer to slot that points to a cache entry that + // matches key/hash. If there is no such cache entry, return a + // pointer to the trailing slot in the corresponding linked list. + LRUHandle** FindPointer(const Slice& key, uint32_t hash) { + LRUHandle** ptr = &list_[hash & (length_ - 1)]; + while (*ptr != NULL && + ((*ptr)->hash != hash || key != (*ptr)->key())) { + ptr = &(*ptr)->next_hash; + } + return ptr; + } + + void Resize() { + uint32_t new_length = 4; + while (new_length < elems_) { + new_length *= 2; + } + LRUHandle** new_list = new LRUHandle*[new_length]; + memset(new_list, 0, sizeof(new_list[0]) * new_length); + uint32_t count = 0; + for (uint32_t i = 0; i < length_; i++) { + LRUHandle* h = list_[i]; + while (h != NULL) { + LRUHandle* next = h->next_hash; + uint32_t hash = h->hash; + LRUHandle** ptr = &new_list[hash & (new_length - 1)]; + h->next_hash = *ptr; + *ptr = h; + h = next; + count++; + } + } + assert(elems_ == count); + delete[] list_; + list_ = new_list; + length_ = new_length; + } +}; + +// A single shard of sharded cache. +class LRUCache { + public: + LRUCache(); + ~LRUCache(); + + // Separate from constructor so caller can easily make an array of LRUCache + void SetCapacity(size_t capacity) { capacity_ = capacity; } + + // Like Cache methods, but with an extra "hash" parameter. + Cache::Handle* Insert(const Slice& key, uint32_t hash, + void* value, size_t charge, + void (*deleter)(const Slice& key, void* value)); + Cache::Handle* Lookup(const Slice& key, uint32_t hash); + void Release(Cache::Handle* handle); + void Erase(const Slice& key, uint32_t hash); + + private: + void LRU_Remove(LRUHandle* e); + void LRU_Append(LRUHandle* e); + void Unref(LRUHandle* e); + + // Initialized before use. + size_t capacity_; + + // mutex_ protects the following state. + port::Mutex mutex_; + size_t usage_; + + // Dummy head of LRU list. + // lru.prev is newest entry, lru.next is oldest entry. + LRUHandle lru_; + + HandleTable table_; +}; + +LRUCache::LRUCache() + : usage_(0) { + // Make empty circular linked list + lru_.next = &lru_; + lru_.prev = &lru_; +} + +LRUCache::~LRUCache() { + for (LRUHandle* e = lru_.next; e != &lru_; ) { + LRUHandle* next = e->next; + assert(e->refs == 1); // Error if caller has an unreleased handle + Unref(e); + e = next; + } +} + +void LRUCache::Unref(LRUHandle* e) { + assert(e->refs > 0); + e->refs--; + if (e->refs <= 0) { + usage_ -= e->charge; + (*e->deleter)(e->key(), e->value); + free(e); + } +} + +void LRUCache::LRU_Remove(LRUHandle* e) { + e->next->prev = e->prev; + e->prev->next = e->next; +} + +void LRUCache::LRU_Append(LRUHandle* e) { + // Make "e" newest entry by inserting just before lru_ + e->next = &lru_; + e->prev = lru_.prev; + e->prev->next = e; + e->next->prev = e; +} + +Cache::Handle* LRUCache::Lookup(const Slice& key, uint32_t hash) { + MutexLock l(&mutex_); + LRUHandle* e = table_.Lookup(key, hash); + if (e != NULL) { + e->refs++; + LRU_Remove(e); + LRU_Append(e); + } + return reinterpret_cast(e); +} + +void LRUCache::Release(Cache::Handle* handle) { + MutexLock l(&mutex_); + Unref(reinterpret_cast(handle)); +} + +Cache::Handle* LRUCache::Insert( + const Slice& key, uint32_t hash, void* value, size_t charge, + void (*deleter)(const Slice& key, void* value)) { + MutexLock l(&mutex_); + + LRUHandle* e = reinterpret_cast( + malloc(sizeof(LRUHandle)-1 + key.size())); + e->value = value; + e->deleter = deleter; + e->charge = charge; + e->key_length = key.size(); + e->hash = hash; + e->refs = 2; // One from LRUCache, one for the returned handle + memcpy(e->key_data, key.data(), key.size()); + LRU_Append(e); + usage_ += charge; + + LRUHandle* old = table_.Insert(e); + if (old != NULL) { + LRU_Remove(old); + Unref(old); + } + + while (usage_ > capacity_ && lru_.next != &lru_) { + LRUHandle* old = lru_.next; + LRU_Remove(old); + table_.Remove(old->key(), old->hash); + Unref(old); + } + + return reinterpret_cast(e); +} + +void LRUCache::Erase(const Slice& key, uint32_t hash) { + MutexLock l(&mutex_); + LRUHandle* e = table_.Remove(key, hash); + if (e != NULL) { + LRU_Remove(e); + Unref(e); + } +} + +static const int kNumShardBits = 4; +static const int kNumShards = 1 << kNumShardBits; + +class ShardedLRUCache : public Cache { + private: + LRUCache shard_[kNumShards]; + port::Mutex id_mutex_; + uint64_t last_id_; + + static inline uint32_t HashSlice(const Slice& s) { + return Hash(s.data(), s.size(), 0); + } + + static uint32_t Shard(uint32_t hash) { + return hash >> (32 - kNumShardBits); + } + + public: + explicit ShardedLRUCache(size_t capacity) + : last_id_(0) { + const size_t per_shard = (capacity + (kNumShards - 1)) / kNumShards; + for (int s = 0; s < kNumShards; s++) { + shard_[s].SetCapacity(per_shard); + } + } + virtual ~ShardedLRUCache() { } + virtual Handle* Insert(const Slice& key, void* value, size_t charge, + void (*deleter)(const Slice& key, void* value)) { + const uint32_t hash = HashSlice(key); + return shard_[Shard(hash)].Insert(key, hash, value, charge, deleter); + } + virtual Handle* Lookup(const Slice& key) { + const uint32_t hash = HashSlice(key); + return shard_[Shard(hash)].Lookup(key, hash); + } + virtual void Release(Handle* handle) { + LRUHandle* h = reinterpret_cast(handle); + shard_[Shard(h->hash)].Release(handle); + } + virtual void Erase(const Slice& key) { + const uint32_t hash = HashSlice(key); + shard_[Shard(hash)].Erase(key, hash); + } + virtual void* Value(Handle* handle) { + return reinterpret_cast(handle)->value; + } + virtual uint64_t NewId() { + MutexLock l(&id_mutex_); + return ++(last_id_); + } +}; + +} // end anonymous namespace + +Cache* NewLRUCache(size_t capacity) { + return new ShardedLRUCache(capacity); +} + +} // namespace leveldb diff --git a/ios/Pods/leveldb-library/util/cache_test.cc b/ios/Pods/leveldb-library/util/cache_test.cc new file mode 100644 index 000000000..43716715a --- /dev/null +++ b/ios/Pods/leveldb-library/util/cache_test.cc @@ -0,0 +1,186 @@ +// Copyright (c) 2011 The LevelDB Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. See the AUTHORS file for names of contributors. + +#include "leveldb/cache.h" + +#include +#include "util/coding.h" +#include "util/testharness.h" + +namespace leveldb { + +// Conversions between numeric keys/values and the types expected by Cache. +static std::string EncodeKey(int k) { + std::string result; + PutFixed32(&result, k); + return result; +} +static int DecodeKey(const Slice& k) { + assert(k.size() == 4); + return DecodeFixed32(k.data()); +} +static void* EncodeValue(uintptr_t v) { return reinterpret_cast(v); } +static int DecodeValue(void* v) { return reinterpret_cast(v); } + +class CacheTest { + public: + static CacheTest* current_; + + static void Deleter(const Slice& key, void* v) { + current_->deleted_keys_.push_back(DecodeKey(key)); + current_->deleted_values_.push_back(DecodeValue(v)); + } + + static const int kCacheSize = 1000; + std::vector deleted_keys_; + std::vector deleted_values_; + Cache* cache_; + + CacheTest() : cache_(NewLRUCache(kCacheSize)) { + current_ = this; + } + + ~CacheTest() { + delete cache_; + } + + int Lookup(int key) { + Cache::Handle* handle = cache_->Lookup(EncodeKey(key)); + const int r = (handle == NULL) ? -1 : DecodeValue(cache_->Value(handle)); + if (handle != NULL) { + cache_->Release(handle); + } + return r; + } + + void Insert(int key, int value, int charge = 1) { + cache_->Release(cache_->Insert(EncodeKey(key), EncodeValue(value), charge, + &CacheTest::Deleter)); + } + + void Erase(int key) { + cache_->Erase(EncodeKey(key)); + } +}; +CacheTest* CacheTest::current_; + +TEST(CacheTest, HitAndMiss) { + ASSERT_EQ(-1, Lookup(100)); + + Insert(100, 101); + ASSERT_EQ(101, Lookup(100)); + ASSERT_EQ(-1, Lookup(200)); + ASSERT_EQ(-1, Lookup(300)); + + Insert(200, 201); + ASSERT_EQ(101, Lookup(100)); + ASSERT_EQ(201, Lookup(200)); + ASSERT_EQ(-1, Lookup(300)); + + Insert(100, 102); + ASSERT_EQ(102, Lookup(100)); + ASSERT_EQ(201, Lookup(200)); + ASSERT_EQ(-1, Lookup(300)); + + ASSERT_EQ(1, deleted_keys_.size()); + ASSERT_EQ(100, deleted_keys_[0]); + ASSERT_EQ(101, deleted_values_[0]); +} + +TEST(CacheTest, Erase) { + Erase(200); + ASSERT_EQ(0, deleted_keys_.size()); + + Insert(100, 101); + Insert(200, 201); + Erase(100); + ASSERT_EQ(-1, Lookup(100)); + ASSERT_EQ(201, Lookup(200)); + ASSERT_EQ(1, deleted_keys_.size()); + ASSERT_EQ(100, deleted_keys_[0]); + ASSERT_EQ(101, deleted_values_[0]); + + Erase(100); + ASSERT_EQ(-1, Lookup(100)); + ASSERT_EQ(201, Lookup(200)); + ASSERT_EQ(1, deleted_keys_.size()); +} + +TEST(CacheTest, EntriesArePinned) { + Insert(100, 101); + Cache::Handle* h1 = cache_->Lookup(EncodeKey(100)); + ASSERT_EQ(101, DecodeValue(cache_->Value(h1))); + + Insert(100, 102); + Cache::Handle* h2 = cache_->Lookup(EncodeKey(100)); + ASSERT_EQ(102, DecodeValue(cache_->Value(h2))); + ASSERT_EQ(0, deleted_keys_.size()); + + cache_->Release(h1); + ASSERT_EQ(1, deleted_keys_.size()); + ASSERT_EQ(100, deleted_keys_[0]); + ASSERT_EQ(101, deleted_values_[0]); + + Erase(100); + ASSERT_EQ(-1, Lookup(100)); + ASSERT_EQ(1, deleted_keys_.size()); + + cache_->Release(h2); + ASSERT_EQ(2, deleted_keys_.size()); + ASSERT_EQ(100, deleted_keys_[1]); + ASSERT_EQ(102, deleted_values_[1]); +} + +TEST(CacheTest, EvictionPolicy) { + Insert(100, 101); + Insert(200, 201); + + // Frequently used entry must be kept around + for (int i = 0; i < kCacheSize + 100; i++) { + Insert(1000+i, 2000+i); + ASSERT_EQ(2000+i, Lookup(1000+i)); + ASSERT_EQ(101, Lookup(100)); + } + ASSERT_EQ(101, Lookup(100)); + ASSERT_EQ(-1, Lookup(200)); +} + +TEST(CacheTest, HeavyEntries) { + // Add a bunch of light and heavy entries and then count the combined + // size of items still in the cache, which must be approximately the + // same as the total capacity. + const int kLight = 1; + const int kHeavy = 10; + int added = 0; + int index = 0; + while (added < 2*kCacheSize) { + const int weight = (index & 1) ? kLight : kHeavy; + Insert(index, 1000+index, weight); + added += weight; + index++; + } + + int cached_weight = 0; + for (int i = 0; i < index; i++) { + const int weight = (i & 1 ? kLight : kHeavy); + int r = Lookup(i); + if (r >= 0) { + cached_weight += weight; + ASSERT_EQ(1000+i, r); + } + } + ASSERT_LE(cached_weight, kCacheSize + kCacheSize/10); +} + +TEST(CacheTest, NewId) { + uint64_t a = cache_->NewId(); + uint64_t b = cache_->NewId(); + ASSERT_NE(a, b); +} + +} // namespace leveldb + +int main(int argc, char** argv) { + return leveldb::test::RunAllTests(); +} diff --git a/ios/Pods/leveldb-library/util/coding.cc b/ios/Pods/leveldb-library/util/coding.cc new file mode 100644 index 000000000..21e3186d5 --- /dev/null +++ b/ios/Pods/leveldb-library/util/coding.cc @@ -0,0 +1,194 @@ +// Copyright (c) 2011 The LevelDB Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. See the AUTHORS file for names of contributors. + +#include "util/coding.h" + +namespace leveldb { + +void EncodeFixed32(char* buf, uint32_t value) { + if (port::kLittleEndian) { + memcpy(buf, &value, sizeof(value)); + } else { + buf[0] = value & 0xff; + buf[1] = (value >> 8) & 0xff; + buf[2] = (value >> 16) & 0xff; + buf[3] = (value >> 24) & 0xff; + } +} + +void EncodeFixed64(char* buf, uint64_t value) { + if (port::kLittleEndian) { + memcpy(buf, &value, sizeof(value)); + } else { + buf[0] = value & 0xff; + buf[1] = (value >> 8) & 0xff; + buf[2] = (value >> 16) & 0xff; + buf[3] = (value >> 24) & 0xff; + buf[4] = (value >> 32) & 0xff; + buf[5] = (value >> 40) & 0xff; + buf[6] = (value >> 48) & 0xff; + buf[7] = (value >> 56) & 0xff; + } +} + +void PutFixed32(std::string* dst, uint32_t value) { + char buf[sizeof(value)]; + EncodeFixed32(buf, value); + dst->append(buf, sizeof(buf)); +} + +void PutFixed64(std::string* dst, uint64_t value) { + char buf[sizeof(value)]; + EncodeFixed64(buf, value); + dst->append(buf, sizeof(buf)); +} + +char* EncodeVarint32(char* dst, uint32_t v) { + // Operate on characters as unsigneds + unsigned char* ptr = reinterpret_cast(dst); + static const int B = 128; + if (v < (1<<7)) { + *(ptr++) = v; + } else if (v < (1<<14)) { + *(ptr++) = v | B; + *(ptr++) = v>>7; + } else if (v < (1<<21)) { + *(ptr++) = v | B; + *(ptr++) = (v>>7) | B; + *(ptr++) = v>>14; + } else if (v < (1<<28)) { + *(ptr++) = v | B; + *(ptr++) = (v>>7) | B; + *(ptr++) = (v>>14) | B; + *(ptr++) = v>>21; + } else { + *(ptr++) = v | B; + *(ptr++) = (v>>7) | B; + *(ptr++) = (v>>14) | B; + *(ptr++) = (v>>21) | B; + *(ptr++) = v>>28; + } + return reinterpret_cast(ptr); +} + +void PutVarint32(std::string* dst, uint32_t v) { + char buf[5]; + char* ptr = EncodeVarint32(buf, v); + dst->append(buf, ptr - buf); +} + +char* EncodeVarint64(char* dst, uint64_t v) { + static const int B = 128; + unsigned char* ptr = reinterpret_cast(dst); + while (v >= B) { + *(ptr++) = (v & (B-1)) | B; + v >>= 7; + } + *(ptr++) = static_cast(v); + return reinterpret_cast(ptr); +} + +void PutVarint64(std::string* dst, uint64_t v) { + char buf[10]; + char* ptr = EncodeVarint64(buf, v); + dst->append(buf, ptr - buf); +} + +void PutLengthPrefixedSlice(std::string* dst, const Slice& value) { + PutVarint32(dst, value.size()); + dst->append(value.data(), value.size()); +} + +int VarintLength(uint64_t v) { + int len = 1; + while (v >= 128) { + v >>= 7; + len++; + } + return len; +} + +const char* GetVarint32PtrFallback(const char* p, + const char* limit, + uint32_t* value) { + uint32_t result = 0; + for (uint32_t shift = 0; shift <= 28 && p < limit; shift += 7) { + uint32_t byte = *(reinterpret_cast(p)); + p++; + if (byte & 128) { + // More bytes are present + result |= ((byte & 127) << shift); + } else { + result |= (byte << shift); + *value = result; + return reinterpret_cast(p); + } + } + return NULL; +} + +bool GetVarint32(Slice* input, uint32_t* value) { + const char* p = input->data(); + const char* limit = p + input->size(); + const char* q = GetVarint32Ptr(p, limit, value); + if (q == NULL) { + return false; + } else { + *input = Slice(q, limit - q); + return true; + } +} + +const char* GetVarint64Ptr(const char* p, const char* limit, uint64_t* value) { + uint64_t result = 0; + for (uint32_t shift = 0; shift <= 63 && p < limit; shift += 7) { + uint64_t byte = *(reinterpret_cast(p)); + p++; + if (byte & 128) { + // More bytes are present + result |= ((byte & 127) << shift); + } else { + result |= (byte << shift); + *value = result; + return reinterpret_cast(p); + } + } + return NULL; +} + +bool GetVarint64(Slice* input, uint64_t* value) { + const char* p = input->data(); + const char* limit = p + input->size(); + const char* q = GetVarint64Ptr(p, limit, value); + if (q == NULL) { + return false; + } else { + *input = Slice(q, limit - q); + return true; + } +} + +const char* GetLengthPrefixedSlice(const char* p, const char* limit, + Slice* result) { + uint32_t len; + p = GetVarint32Ptr(p, limit, &len); + if (p == NULL) return NULL; + if (p + len > limit) return NULL; + *result = Slice(p, len); + return p + len; +} + +bool GetLengthPrefixedSlice(Slice* input, Slice* result) { + uint32_t len; + if (GetVarint32(input, &len) && + input->size() >= len) { + *result = Slice(input->data(), len); + input->remove_prefix(len); + return true; + } else { + return false; + } +} + +} // namespace leveldb diff --git a/ios/Pods/leveldb-library/util/coding.h b/ios/Pods/leveldb-library/util/coding.h new file mode 100644 index 000000000..3993c4a75 --- /dev/null +++ b/ios/Pods/leveldb-library/util/coding.h @@ -0,0 +1,104 @@ +// Copyright (c) 2011 The LevelDB Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. See the AUTHORS file for names of contributors. +// +// Endian-neutral encoding: +// * Fixed-length numbers are encoded with least-significant byte first +// * In addition we support variable length "varint" encoding +// * Strings are encoded prefixed by their length in varint format + +#ifndef STORAGE_LEVELDB_UTIL_CODING_H_ +#define STORAGE_LEVELDB_UTIL_CODING_H_ + +#include +#include +#include +#include "leveldb/slice.h" +#include "port/port.h" + +namespace leveldb { + +// Standard Put... routines append to a string +extern void PutFixed32(std::string* dst, uint32_t value); +extern void PutFixed64(std::string* dst, uint64_t value); +extern void PutVarint32(std::string* dst, uint32_t value); +extern void PutVarint64(std::string* dst, uint64_t value); +extern void PutLengthPrefixedSlice(std::string* dst, const Slice& value); + +// Standard Get... routines parse a value from the beginning of a Slice +// and advance the slice past the parsed value. +extern bool GetVarint32(Slice* input, uint32_t* value); +extern bool GetVarint64(Slice* input, uint64_t* value); +extern bool GetLengthPrefixedSlice(Slice* input, Slice* result); + +// Pointer-based variants of GetVarint... These either store a value +// in *v and return a pointer just past the parsed value, or return +// NULL on error. These routines only look at bytes in the range +// [p..limit-1] +extern const char* GetVarint32Ptr(const char* p,const char* limit, uint32_t* v); +extern const char* GetVarint64Ptr(const char* p,const char* limit, uint64_t* v); + +// Returns the length of the varint32 or varint64 encoding of "v" +extern int VarintLength(uint64_t v); + +// Lower-level versions of Put... that write directly into a character buffer +// REQUIRES: dst has enough space for the value being written +extern void EncodeFixed32(char* dst, uint32_t value); +extern void EncodeFixed64(char* dst, uint64_t value); + +// Lower-level versions of Put... that write directly into a character buffer +// and return a pointer just past the last byte written. +// REQUIRES: dst has enough space for the value being written +extern char* EncodeVarint32(char* dst, uint32_t value); +extern char* EncodeVarint64(char* dst, uint64_t value); + +// Lower-level versions of Get... that read directly from a character buffer +// without any bounds checking. + +inline uint32_t DecodeFixed32(const char* ptr) { + if (port::kLittleEndian) { + // Load the raw bytes + uint32_t result; + memcpy(&result, ptr, sizeof(result)); // gcc optimizes this to a plain load + return result; + } else { + return ((static_cast(static_cast(ptr[0]))) + | (static_cast(static_cast(ptr[1])) << 8) + | (static_cast(static_cast(ptr[2])) << 16) + | (static_cast(static_cast(ptr[3])) << 24)); + } +} + +inline uint64_t DecodeFixed64(const char* ptr) { + if (port::kLittleEndian) { + // Load the raw bytes + uint64_t result; + memcpy(&result, ptr, sizeof(result)); // gcc optimizes this to a plain load + return result; + } else { + uint64_t lo = DecodeFixed32(ptr); + uint64_t hi = DecodeFixed32(ptr + 4); + return (hi << 32) | lo; + } +} + +// Internal routine for use by fallback path of GetVarint32Ptr +extern const char* GetVarint32PtrFallback(const char* p, + const char* limit, + uint32_t* value); +inline const char* GetVarint32Ptr(const char* p, + const char* limit, + uint32_t* value) { + if (p < limit) { + uint32_t result = *(reinterpret_cast(p)); + if ((result & 128) == 0) { + *value = result; + return p + 1; + } + } + return GetVarint32PtrFallback(p, limit, value); +} + +} // namespace leveldb + +#endif // STORAGE_LEVELDB_UTIL_CODING_H_ diff --git a/ios/Pods/leveldb-library/util/coding_test.cc b/ios/Pods/leveldb-library/util/coding_test.cc new file mode 100644 index 000000000..521541ea6 --- /dev/null +++ b/ios/Pods/leveldb-library/util/coding_test.cc @@ -0,0 +1,196 @@ +// Copyright (c) 2011 The LevelDB Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. See the AUTHORS file for names of contributors. + +#include "util/coding.h" + +#include "util/testharness.h" + +namespace leveldb { + +class Coding { }; + +TEST(Coding, Fixed32) { + std::string s; + for (uint32_t v = 0; v < 100000; v++) { + PutFixed32(&s, v); + } + + const char* p = s.data(); + for (uint32_t v = 0; v < 100000; v++) { + uint32_t actual = DecodeFixed32(p); + ASSERT_EQ(v, actual); + p += sizeof(uint32_t); + } +} + +TEST(Coding, Fixed64) { + std::string s; + for (int power = 0; power <= 63; power++) { + uint64_t v = static_cast(1) << power; + PutFixed64(&s, v - 1); + PutFixed64(&s, v + 0); + PutFixed64(&s, v + 1); + } + + const char* p = s.data(); + for (int power = 0; power <= 63; power++) { + uint64_t v = static_cast(1) << power; + uint64_t actual; + actual = DecodeFixed64(p); + ASSERT_EQ(v-1, actual); + p += sizeof(uint64_t); + + actual = DecodeFixed64(p); + ASSERT_EQ(v+0, actual); + p += sizeof(uint64_t); + + actual = DecodeFixed64(p); + ASSERT_EQ(v+1, actual); + p += sizeof(uint64_t); + } +} + +// Test that encoding routines generate little-endian encodings +TEST(Coding, EncodingOutput) { + std::string dst; + PutFixed32(&dst, 0x04030201); + ASSERT_EQ(4, dst.size()); + ASSERT_EQ(0x01, static_cast(dst[0])); + ASSERT_EQ(0x02, static_cast(dst[1])); + ASSERT_EQ(0x03, static_cast(dst[2])); + ASSERT_EQ(0x04, static_cast(dst[3])); + + dst.clear(); + PutFixed64(&dst, 0x0807060504030201ull); + ASSERT_EQ(8, dst.size()); + ASSERT_EQ(0x01, static_cast(dst[0])); + ASSERT_EQ(0x02, static_cast(dst[1])); + ASSERT_EQ(0x03, static_cast(dst[2])); + ASSERT_EQ(0x04, static_cast(dst[3])); + ASSERT_EQ(0x05, static_cast(dst[4])); + ASSERT_EQ(0x06, static_cast(dst[5])); + ASSERT_EQ(0x07, static_cast(dst[6])); + ASSERT_EQ(0x08, static_cast(dst[7])); +} + +TEST(Coding, Varint32) { + std::string s; + for (uint32_t i = 0; i < (32 * 32); i++) { + uint32_t v = (i / 32) << (i % 32); + PutVarint32(&s, v); + } + + const char* p = s.data(); + const char* limit = p + s.size(); + for (uint32_t i = 0; i < (32 * 32); i++) { + uint32_t expected = (i / 32) << (i % 32); + uint32_t actual; + const char* start = p; + p = GetVarint32Ptr(p, limit, &actual); + ASSERT_TRUE(p != NULL); + ASSERT_EQ(expected, actual); + ASSERT_EQ(VarintLength(actual), p - start); + } + ASSERT_EQ(p, s.data() + s.size()); +} + +TEST(Coding, Varint64) { + // Construct the list of values to check + std::vector values; + // Some special values + values.push_back(0); + values.push_back(100); + values.push_back(~static_cast(0)); + values.push_back(~static_cast(0) - 1); + for (uint32_t k = 0; k < 64; k++) { + // Test values near powers of two + const uint64_t power = 1ull << k; + values.push_back(power); + values.push_back(power-1); + values.push_back(power+1); + } + + std::string s; + for (size_t i = 0; i < values.size(); i++) { + PutVarint64(&s, values[i]); + } + + const char* p = s.data(); + const char* limit = p + s.size(); + for (size_t i = 0; i < values.size(); i++) { + ASSERT_TRUE(p < limit); + uint64_t actual; + const char* start = p; + p = GetVarint64Ptr(p, limit, &actual); + ASSERT_TRUE(p != NULL); + ASSERT_EQ(values[i], actual); + ASSERT_EQ(VarintLength(actual), p - start); + } + ASSERT_EQ(p, limit); + +} + +TEST(Coding, Varint32Overflow) { + uint32_t result; + std::string input("\x81\x82\x83\x84\x85\x11"); + ASSERT_TRUE(GetVarint32Ptr(input.data(), input.data() + input.size(), &result) + == NULL); +} + +TEST(Coding, Varint32Truncation) { + uint32_t large_value = (1u << 31) + 100; + std::string s; + PutVarint32(&s, large_value); + uint32_t result; + for (size_t len = 0; len < s.size() - 1; len++) { + ASSERT_TRUE(GetVarint32Ptr(s.data(), s.data() + len, &result) == NULL); + } + ASSERT_TRUE(GetVarint32Ptr(s.data(), s.data() + s.size(), &result) != NULL); + ASSERT_EQ(large_value, result); +} + +TEST(Coding, Varint64Overflow) { + uint64_t result; + std::string input("\x81\x82\x83\x84\x85\x81\x82\x83\x84\x85\x11"); + ASSERT_TRUE(GetVarint64Ptr(input.data(), input.data() + input.size(), &result) + == NULL); +} + +TEST(Coding, Varint64Truncation) { + uint64_t large_value = (1ull << 63) + 100ull; + std::string s; + PutVarint64(&s, large_value); + uint64_t result; + for (size_t len = 0; len < s.size() - 1; len++) { + ASSERT_TRUE(GetVarint64Ptr(s.data(), s.data() + len, &result) == NULL); + } + ASSERT_TRUE(GetVarint64Ptr(s.data(), s.data() + s.size(), &result) != NULL); + ASSERT_EQ(large_value, result); +} + +TEST(Coding, Strings) { + std::string s; + PutLengthPrefixedSlice(&s, Slice("")); + PutLengthPrefixedSlice(&s, Slice("foo")); + PutLengthPrefixedSlice(&s, Slice("bar")); + PutLengthPrefixedSlice(&s, Slice(std::string(200, 'x'))); + + Slice input(s); + Slice v; + ASSERT_TRUE(GetLengthPrefixedSlice(&input, &v)); + ASSERT_EQ("", v.ToString()); + ASSERT_TRUE(GetLengthPrefixedSlice(&input, &v)); + ASSERT_EQ("foo", v.ToString()); + ASSERT_TRUE(GetLengthPrefixedSlice(&input, &v)); + ASSERT_EQ("bar", v.ToString()); + ASSERT_TRUE(GetLengthPrefixedSlice(&input, &v)); + ASSERT_EQ(std::string(200, 'x'), v.ToString()); + ASSERT_EQ("", input.ToString()); +} + +} // namespace leveldb + +int main(int argc, char** argv) { + return leveldb::test::RunAllTests(); +} diff --git a/ios/Pods/leveldb-library/util/comparator.cc b/ios/Pods/leveldb-library/util/comparator.cc new file mode 100644 index 000000000..4b7b5724e --- /dev/null +++ b/ios/Pods/leveldb-library/util/comparator.cc @@ -0,0 +1,81 @@ +// Copyright (c) 2011 The LevelDB Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. See the AUTHORS file for names of contributors. + +#include +#include +#include "leveldb/comparator.h" +#include "leveldb/slice.h" +#include "port/port.h" +#include "util/logging.h" + +namespace leveldb { + +Comparator::~Comparator() { } + +namespace { +class BytewiseComparatorImpl : public Comparator { + public: + BytewiseComparatorImpl() { } + + virtual const char* Name() const { + return "leveldb.BytewiseComparator"; + } + + virtual int Compare(const Slice& a, const Slice& b) const { + return a.compare(b); + } + + virtual void FindShortestSeparator( + std::string* start, + const Slice& limit) const { + // Find length of common prefix + size_t min_length = std::min(start->size(), limit.size()); + size_t diff_index = 0; + while ((diff_index < min_length) && + ((*start)[diff_index] == limit[diff_index])) { + diff_index++; + } + + if (diff_index >= min_length) { + // Do not shorten if one string is a prefix of the other + } else { + uint8_t diff_byte = static_cast((*start)[diff_index]); + if (diff_byte < static_cast(0xff) && + diff_byte + 1 < static_cast(limit[diff_index])) { + (*start)[diff_index]++; + start->resize(diff_index + 1); + assert(Compare(*start, limit) < 0); + } + } + } + + virtual void FindShortSuccessor(std::string* key) const { + // Find first character that can be incremented + size_t n = key->size(); + for (size_t i = 0; i < n; i++) { + const uint8_t byte = (*key)[i]; + if (byte != static_cast(0xff)) { + (*key)[i] = byte + 1; + key->resize(i+1); + return; + } + } + // *key is a run of 0xffs. Leave it alone. + } +}; +} // namespace + +static port::OnceType once = LEVELDB_ONCE_INIT; +static const Comparator* bytewise; + +static void InitModule() { + bytewise = new BytewiseComparatorImpl; +} + +const Comparator* BytewiseComparator() { + port::InitOnce(&once, InitModule); + return bytewise; +} + +} // namespace leveldb diff --git a/ios/Pods/leveldb-library/util/crc32c.cc b/ios/Pods/leveldb-library/util/crc32c.cc new file mode 100644 index 000000000..6db9e7707 --- /dev/null +++ b/ios/Pods/leveldb-library/util/crc32c.cc @@ -0,0 +1,332 @@ +// Copyright (c) 2011 The LevelDB Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. See the AUTHORS file for names of contributors. +// +// A portable implementation of crc32c, optimized to handle +// four bytes at a time. + +#include "util/crc32c.h" + +#include +#include "util/coding.h" + +namespace leveldb { +namespace crc32c { + +static const uint32_t table0_[256] = { + 0x00000000, 0xf26b8303, 0xe13b70f7, 0x1350f3f4, + 0xc79a971f, 0x35f1141c, 0x26a1e7e8, 0xd4ca64eb, + 0x8ad958cf, 0x78b2dbcc, 0x6be22838, 0x9989ab3b, + 0x4d43cfd0, 0xbf284cd3, 0xac78bf27, 0x5e133c24, + 0x105ec76f, 0xe235446c, 0xf165b798, 0x030e349b, + 0xd7c45070, 0x25afd373, 0x36ff2087, 0xc494a384, + 0x9a879fa0, 0x68ec1ca3, 0x7bbcef57, 0x89d76c54, + 0x5d1d08bf, 0xaf768bbc, 0xbc267848, 0x4e4dfb4b, + 0x20bd8ede, 0xd2d60ddd, 0xc186fe29, 0x33ed7d2a, + 0xe72719c1, 0x154c9ac2, 0x061c6936, 0xf477ea35, + 0xaa64d611, 0x580f5512, 0x4b5fa6e6, 0xb93425e5, + 0x6dfe410e, 0x9f95c20d, 0x8cc531f9, 0x7eaeb2fa, + 0x30e349b1, 0xc288cab2, 0xd1d83946, 0x23b3ba45, + 0xf779deae, 0x05125dad, 0x1642ae59, 0xe4292d5a, + 0xba3a117e, 0x4851927d, 0x5b016189, 0xa96ae28a, + 0x7da08661, 0x8fcb0562, 0x9c9bf696, 0x6ef07595, + 0x417b1dbc, 0xb3109ebf, 0xa0406d4b, 0x522bee48, + 0x86e18aa3, 0x748a09a0, 0x67dafa54, 0x95b17957, + 0xcba24573, 0x39c9c670, 0x2a993584, 0xd8f2b687, + 0x0c38d26c, 0xfe53516f, 0xed03a29b, 0x1f682198, + 0x5125dad3, 0xa34e59d0, 0xb01eaa24, 0x42752927, + 0x96bf4dcc, 0x64d4cecf, 0x77843d3b, 0x85efbe38, + 0xdbfc821c, 0x2997011f, 0x3ac7f2eb, 0xc8ac71e8, + 0x1c661503, 0xee0d9600, 0xfd5d65f4, 0x0f36e6f7, + 0x61c69362, 0x93ad1061, 0x80fde395, 0x72966096, + 0xa65c047d, 0x5437877e, 0x4767748a, 0xb50cf789, + 0xeb1fcbad, 0x197448ae, 0x0a24bb5a, 0xf84f3859, + 0x2c855cb2, 0xdeeedfb1, 0xcdbe2c45, 0x3fd5af46, + 0x7198540d, 0x83f3d70e, 0x90a324fa, 0x62c8a7f9, + 0xb602c312, 0x44694011, 0x5739b3e5, 0xa55230e6, + 0xfb410cc2, 0x092a8fc1, 0x1a7a7c35, 0xe811ff36, + 0x3cdb9bdd, 0xceb018de, 0xdde0eb2a, 0x2f8b6829, + 0x82f63b78, 0x709db87b, 0x63cd4b8f, 0x91a6c88c, + 0x456cac67, 0xb7072f64, 0xa457dc90, 0x563c5f93, + 0x082f63b7, 0xfa44e0b4, 0xe9141340, 0x1b7f9043, + 0xcfb5f4a8, 0x3dde77ab, 0x2e8e845f, 0xdce5075c, + 0x92a8fc17, 0x60c37f14, 0x73938ce0, 0x81f80fe3, + 0x55326b08, 0xa759e80b, 0xb4091bff, 0x466298fc, + 0x1871a4d8, 0xea1a27db, 0xf94ad42f, 0x0b21572c, + 0xdfeb33c7, 0x2d80b0c4, 0x3ed04330, 0xccbbc033, + 0xa24bb5a6, 0x502036a5, 0x4370c551, 0xb11b4652, + 0x65d122b9, 0x97baa1ba, 0x84ea524e, 0x7681d14d, + 0x2892ed69, 0xdaf96e6a, 0xc9a99d9e, 0x3bc21e9d, + 0xef087a76, 0x1d63f975, 0x0e330a81, 0xfc588982, + 0xb21572c9, 0x407ef1ca, 0x532e023e, 0xa145813d, + 0x758fe5d6, 0x87e466d5, 0x94b49521, 0x66df1622, + 0x38cc2a06, 0xcaa7a905, 0xd9f75af1, 0x2b9cd9f2, + 0xff56bd19, 0x0d3d3e1a, 0x1e6dcdee, 0xec064eed, + 0xc38d26c4, 0x31e6a5c7, 0x22b65633, 0xd0ddd530, + 0x0417b1db, 0xf67c32d8, 0xe52cc12c, 0x1747422f, + 0x49547e0b, 0xbb3ffd08, 0xa86f0efc, 0x5a048dff, + 0x8ecee914, 0x7ca56a17, 0x6ff599e3, 0x9d9e1ae0, + 0xd3d3e1ab, 0x21b862a8, 0x32e8915c, 0xc083125f, + 0x144976b4, 0xe622f5b7, 0xf5720643, 0x07198540, + 0x590ab964, 0xab613a67, 0xb831c993, 0x4a5a4a90, + 0x9e902e7b, 0x6cfbad78, 0x7fab5e8c, 0x8dc0dd8f, + 0xe330a81a, 0x115b2b19, 0x020bd8ed, 0xf0605bee, + 0x24aa3f05, 0xd6c1bc06, 0xc5914ff2, 0x37faccf1, + 0x69e9f0d5, 0x9b8273d6, 0x88d28022, 0x7ab90321, + 0xae7367ca, 0x5c18e4c9, 0x4f48173d, 0xbd23943e, + 0xf36e6f75, 0x0105ec76, 0x12551f82, 0xe03e9c81, + 0x34f4f86a, 0xc69f7b69, 0xd5cf889d, 0x27a40b9e, + 0x79b737ba, 0x8bdcb4b9, 0x988c474d, 0x6ae7c44e, + 0xbe2da0a5, 0x4c4623a6, 0x5f16d052, 0xad7d5351 +}; +static const uint32_t table1_[256] = { + 0x00000000, 0x13a29877, 0x274530ee, 0x34e7a899, + 0x4e8a61dc, 0x5d28f9ab, 0x69cf5132, 0x7a6dc945, + 0x9d14c3b8, 0x8eb65bcf, 0xba51f356, 0xa9f36b21, + 0xd39ea264, 0xc03c3a13, 0xf4db928a, 0xe7790afd, + 0x3fc5f181, 0x2c6769f6, 0x1880c16f, 0x0b225918, + 0x714f905d, 0x62ed082a, 0x560aa0b3, 0x45a838c4, + 0xa2d13239, 0xb173aa4e, 0x859402d7, 0x96369aa0, + 0xec5b53e5, 0xfff9cb92, 0xcb1e630b, 0xd8bcfb7c, + 0x7f8be302, 0x6c297b75, 0x58ced3ec, 0x4b6c4b9b, + 0x310182de, 0x22a31aa9, 0x1644b230, 0x05e62a47, + 0xe29f20ba, 0xf13db8cd, 0xc5da1054, 0xd6788823, + 0xac154166, 0xbfb7d911, 0x8b507188, 0x98f2e9ff, + 0x404e1283, 0x53ec8af4, 0x670b226d, 0x74a9ba1a, + 0x0ec4735f, 0x1d66eb28, 0x298143b1, 0x3a23dbc6, + 0xdd5ad13b, 0xcef8494c, 0xfa1fe1d5, 0xe9bd79a2, + 0x93d0b0e7, 0x80722890, 0xb4958009, 0xa737187e, + 0xff17c604, 0xecb55e73, 0xd852f6ea, 0xcbf06e9d, + 0xb19da7d8, 0xa23f3faf, 0x96d89736, 0x857a0f41, + 0x620305bc, 0x71a19dcb, 0x45463552, 0x56e4ad25, + 0x2c896460, 0x3f2bfc17, 0x0bcc548e, 0x186eccf9, + 0xc0d23785, 0xd370aff2, 0xe797076b, 0xf4359f1c, + 0x8e585659, 0x9dface2e, 0xa91d66b7, 0xbabffec0, + 0x5dc6f43d, 0x4e646c4a, 0x7a83c4d3, 0x69215ca4, + 0x134c95e1, 0x00ee0d96, 0x3409a50f, 0x27ab3d78, + 0x809c2506, 0x933ebd71, 0xa7d915e8, 0xb47b8d9f, + 0xce1644da, 0xddb4dcad, 0xe9537434, 0xfaf1ec43, + 0x1d88e6be, 0x0e2a7ec9, 0x3acdd650, 0x296f4e27, + 0x53028762, 0x40a01f15, 0x7447b78c, 0x67e52ffb, + 0xbf59d487, 0xacfb4cf0, 0x981ce469, 0x8bbe7c1e, + 0xf1d3b55b, 0xe2712d2c, 0xd69685b5, 0xc5341dc2, + 0x224d173f, 0x31ef8f48, 0x050827d1, 0x16aabfa6, + 0x6cc776e3, 0x7f65ee94, 0x4b82460d, 0x5820de7a, + 0xfbc3faf9, 0xe861628e, 0xdc86ca17, 0xcf245260, + 0xb5499b25, 0xa6eb0352, 0x920cabcb, 0x81ae33bc, + 0x66d73941, 0x7575a136, 0x419209af, 0x523091d8, + 0x285d589d, 0x3bffc0ea, 0x0f186873, 0x1cbaf004, + 0xc4060b78, 0xd7a4930f, 0xe3433b96, 0xf0e1a3e1, + 0x8a8c6aa4, 0x992ef2d3, 0xadc95a4a, 0xbe6bc23d, + 0x5912c8c0, 0x4ab050b7, 0x7e57f82e, 0x6df56059, + 0x1798a91c, 0x043a316b, 0x30dd99f2, 0x237f0185, + 0x844819fb, 0x97ea818c, 0xa30d2915, 0xb0afb162, + 0xcac27827, 0xd960e050, 0xed8748c9, 0xfe25d0be, + 0x195cda43, 0x0afe4234, 0x3e19eaad, 0x2dbb72da, + 0x57d6bb9f, 0x447423e8, 0x70938b71, 0x63311306, + 0xbb8de87a, 0xa82f700d, 0x9cc8d894, 0x8f6a40e3, + 0xf50789a6, 0xe6a511d1, 0xd242b948, 0xc1e0213f, + 0x26992bc2, 0x353bb3b5, 0x01dc1b2c, 0x127e835b, + 0x68134a1e, 0x7bb1d269, 0x4f567af0, 0x5cf4e287, + 0x04d43cfd, 0x1776a48a, 0x23910c13, 0x30339464, + 0x4a5e5d21, 0x59fcc556, 0x6d1b6dcf, 0x7eb9f5b8, + 0x99c0ff45, 0x8a626732, 0xbe85cfab, 0xad2757dc, + 0xd74a9e99, 0xc4e806ee, 0xf00fae77, 0xe3ad3600, + 0x3b11cd7c, 0x28b3550b, 0x1c54fd92, 0x0ff665e5, + 0x759baca0, 0x663934d7, 0x52de9c4e, 0x417c0439, + 0xa6050ec4, 0xb5a796b3, 0x81403e2a, 0x92e2a65d, + 0xe88f6f18, 0xfb2df76f, 0xcfca5ff6, 0xdc68c781, + 0x7b5fdfff, 0x68fd4788, 0x5c1aef11, 0x4fb87766, + 0x35d5be23, 0x26772654, 0x12908ecd, 0x013216ba, + 0xe64b1c47, 0xf5e98430, 0xc10e2ca9, 0xd2acb4de, + 0xa8c17d9b, 0xbb63e5ec, 0x8f844d75, 0x9c26d502, + 0x449a2e7e, 0x5738b609, 0x63df1e90, 0x707d86e7, + 0x0a104fa2, 0x19b2d7d5, 0x2d557f4c, 0x3ef7e73b, + 0xd98eedc6, 0xca2c75b1, 0xfecbdd28, 0xed69455f, + 0x97048c1a, 0x84a6146d, 0xb041bcf4, 0xa3e32483 +}; +static const uint32_t table2_[256] = { + 0x00000000, 0xa541927e, 0x4f6f520d, 0xea2ec073, + 0x9edea41a, 0x3b9f3664, 0xd1b1f617, 0x74f06469, + 0x38513ec5, 0x9d10acbb, 0x773e6cc8, 0xd27ffeb6, + 0xa68f9adf, 0x03ce08a1, 0xe9e0c8d2, 0x4ca15aac, + 0x70a27d8a, 0xd5e3eff4, 0x3fcd2f87, 0x9a8cbdf9, + 0xee7cd990, 0x4b3d4bee, 0xa1138b9d, 0x045219e3, + 0x48f3434f, 0xedb2d131, 0x079c1142, 0xa2dd833c, + 0xd62de755, 0x736c752b, 0x9942b558, 0x3c032726, + 0xe144fb14, 0x4405696a, 0xae2ba919, 0x0b6a3b67, + 0x7f9a5f0e, 0xdadbcd70, 0x30f50d03, 0x95b49f7d, + 0xd915c5d1, 0x7c5457af, 0x967a97dc, 0x333b05a2, + 0x47cb61cb, 0xe28af3b5, 0x08a433c6, 0xade5a1b8, + 0x91e6869e, 0x34a714e0, 0xde89d493, 0x7bc846ed, + 0x0f382284, 0xaa79b0fa, 0x40577089, 0xe516e2f7, + 0xa9b7b85b, 0x0cf62a25, 0xe6d8ea56, 0x43997828, + 0x37691c41, 0x92288e3f, 0x78064e4c, 0xdd47dc32, + 0xc76580d9, 0x622412a7, 0x880ad2d4, 0x2d4b40aa, + 0x59bb24c3, 0xfcfab6bd, 0x16d476ce, 0xb395e4b0, + 0xff34be1c, 0x5a752c62, 0xb05bec11, 0x151a7e6f, + 0x61ea1a06, 0xc4ab8878, 0x2e85480b, 0x8bc4da75, + 0xb7c7fd53, 0x12866f2d, 0xf8a8af5e, 0x5de93d20, + 0x29195949, 0x8c58cb37, 0x66760b44, 0xc337993a, + 0x8f96c396, 0x2ad751e8, 0xc0f9919b, 0x65b803e5, + 0x1148678c, 0xb409f5f2, 0x5e273581, 0xfb66a7ff, + 0x26217bcd, 0x8360e9b3, 0x694e29c0, 0xcc0fbbbe, + 0xb8ffdfd7, 0x1dbe4da9, 0xf7908dda, 0x52d11fa4, + 0x1e704508, 0xbb31d776, 0x511f1705, 0xf45e857b, + 0x80aee112, 0x25ef736c, 0xcfc1b31f, 0x6a802161, + 0x56830647, 0xf3c29439, 0x19ec544a, 0xbcadc634, + 0xc85da25d, 0x6d1c3023, 0x8732f050, 0x2273622e, + 0x6ed23882, 0xcb93aafc, 0x21bd6a8f, 0x84fcf8f1, + 0xf00c9c98, 0x554d0ee6, 0xbf63ce95, 0x1a225ceb, + 0x8b277743, 0x2e66e53d, 0xc448254e, 0x6109b730, + 0x15f9d359, 0xb0b84127, 0x5a968154, 0xffd7132a, + 0xb3764986, 0x1637dbf8, 0xfc191b8b, 0x595889f5, + 0x2da8ed9c, 0x88e97fe2, 0x62c7bf91, 0xc7862def, + 0xfb850ac9, 0x5ec498b7, 0xb4ea58c4, 0x11abcaba, + 0x655baed3, 0xc01a3cad, 0x2a34fcde, 0x8f756ea0, + 0xc3d4340c, 0x6695a672, 0x8cbb6601, 0x29faf47f, + 0x5d0a9016, 0xf84b0268, 0x1265c21b, 0xb7245065, + 0x6a638c57, 0xcf221e29, 0x250cde5a, 0x804d4c24, + 0xf4bd284d, 0x51fcba33, 0xbbd27a40, 0x1e93e83e, + 0x5232b292, 0xf77320ec, 0x1d5de09f, 0xb81c72e1, + 0xccec1688, 0x69ad84f6, 0x83834485, 0x26c2d6fb, + 0x1ac1f1dd, 0xbf8063a3, 0x55aea3d0, 0xf0ef31ae, + 0x841f55c7, 0x215ec7b9, 0xcb7007ca, 0x6e3195b4, + 0x2290cf18, 0x87d15d66, 0x6dff9d15, 0xc8be0f6b, + 0xbc4e6b02, 0x190ff97c, 0xf321390f, 0x5660ab71, + 0x4c42f79a, 0xe90365e4, 0x032da597, 0xa66c37e9, + 0xd29c5380, 0x77ddc1fe, 0x9df3018d, 0x38b293f3, + 0x7413c95f, 0xd1525b21, 0x3b7c9b52, 0x9e3d092c, + 0xeacd6d45, 0x4f8cff3b, 0xa5a23f48, 0x00e3ad36, + 0x3ce08a10, 0x99a1186e, 0x738fd81d, 0xd6ce4a63, + 0xa23e2e0a, 0x077fbc74, 0xed517c07, 0x4810ee79, + 0x04b1b4d5, 0xa1f026ab, 0x4bdee6d8, 0xee9f74a6, + 0x9a6f10cf, 0x3f2e82b1, 0xd50042c2, 0x7041d0bc, + 0xad060c8e, 0x08479ef0, 0xe2695e83, 0x4728ccfd, + 0x33d8a894, 0x96993aea, 0x7cb7fa99, 0xd9f668e7, + 0x9557324b, 0x3016a035, 0xda386046, 0x7f79f238, + 0x0b899651, 0xaec8042f, 0x44e6c45c, 0xe1a75622, + 0xdda47104, 0x78e5e37a, 0x92cb2309, 0x378ab177, + 0x437ad51e, 0xe63b4760, 0x0c158713, 0xa954156d, + 0xe5f54fc1, 0x40b4ddbf, 0xaa9a1dcc, 0x0fdb8fb2, + 0x7b2bebdb, 0xde6a79a5, 0x3444b9d6, 0x91052ba8 +}; +static const uint32_t table3_[256] = { + 0x00000000, 0xdd45aab8, 0xbf672381, 0x62228939, + 0x7b2231f3, 0xa6679b4b, 0xc4451272, 0x1900b8ca, + 0xf64463e6, 0x2b01c95e, 0x49234067, 0x9466eadf, + 0x8d665215, 0x5023f8ad, 0x32017194, 0xef44db2c, + 0xe964b13d, 0x34211b85, 0x560392bc, 0x8b463804, + 0x924680ce, 0x4f032a76, 0x2d21a34f, 0xf06409f7, + 0x1f20d2db, 0xc2657863, 0xa047f15a, 0x7d025be2, + 0x6402e328, 0xb9474990, 0xdb65c0a9, 0x06206a11, + 0xd725148b, 0x0a60be33, 0x6842370a, 0xb5079db2, + 0xac072578, 0x71428fc0, 0x136006f9, 0xce25ac41, + 0x2161776d, 0xfc24ddd5, 0x9e0654ec, 0x4343fe54, + 0x5a43469e, 0x8706ec26, 0xe524651f, 0x3861cfa7, + 0x3e41a5b6, 0xe3040f0e, 0x81268637, 0x5c632c8f, + 0x45639445, 0x98263efd, 0xfa04b7c4, 0x27411d7c, + 0xc805c650, 0x15406ce8, 0x7762e5d1, 0xaa274f69, + 0xb327f7a3, 0x6e625d1b, 0x0c40d422, 0xd1057e9a, + 0xaba65fe7, 0x76e3f55f, 0x14c17c66, 0xc984d6de, + 0xd0846e14, 0x0dc1c4ac, 0x6fe34d95, 0xb2a6e72d, + 0x5de23c01, 0x80a796b9, 0xe2851f80, 0x3fc0b538, + 0x26c00df2, 0xfb85a74a, 0x99a72e73, 0x44e284cb, + 0x42c2eeda, 0x9f874462, 0xfda5cd5b, 0x20e067e3, + 0x39e0df29, 0xe4a57591, 0x8687fca8, 0x5bc25610, + 0xb4868d3c, 0x69c32784, 0x0be1aebd, 0xd6a40405, + 0xcfa4bccf, 0x12e11677, 0x70c39f4e, 0xad8635f6, + 0x7c834b6c, 0xa1c6e1d4, 0xc3e468ed, 0x1ea1c255, + 0x07a17a9f, 0xdae4d027, 0xb8c6591e, 0x6583f3a6, + 0x8ac7288a, 0x57828232, 0x35a00b0b, 0xe8e5a1b3, + 0xf1e51979, 0x2ca0b3c1, 0x4e823af8, 0x93c79040, + 0x95e7fa51, 0x48a250e9, 0x2a80d9d0, 0xf7c57368, + 0xeec5cba2, 0x3380611a, 0x51a2e823, 0x8ce7429b, + 0x63a399b7, 0xbee6330f, 0xdcc4ba36, 0x0181108e, + 0x1881a844, 0xc5c402fc, 0xa7e68bc5, 0x7aa3217d, + 0x52a0c93f, 0x8fe56387, 0xedc7eabe, 0x30824006, + 0x2982f8cc, 0xf4c75274, 0x96e5db4d, 0x4ba071f5, + 0xa4e4aad9, 0x79a10061, 0x1b838958, 0xc6c623e0, + 0xdfc69b2a, 0x02833192, 0x60a1b8ab, 0xbde41213, + 0xbbc47802, 0x6681d2ba, 0x04a35b83, 0xd9e6f13b, + 0xc0e649f1, 0x1da3e349, 0x7f816a70, 0xa2c4c0c8, + 0x4d801be4, 0x90c5b15c, 0xf2e73865, 0x2fa292dd, + 0x36a22a17, 0xebe780af, 0x89c50996, 0x5480a32e, + 0x8585ddb4, 0x58c0770c, 0x3ae2fe35, 0xe7a7548d, + 0xfea7ec47, 0x23e246ff, 0x41c0cfc6, 0x9c85657e, + 0x73c1be52, 0xae8414ea, 0xcca69dd3, 0x11e3376b, + 0x08e38fa1, 0xd5a62519, 0xb784ac20, 0x6ac10698, + 0x6ce16c89, 0xb1a4c631, 0xd3864f08, 0x0ec3e5b0, + 0x17c35d7a, 0xca86f7c2, 0xa8a47efb, 0x75e1d443, + 0x9aa50f6f, 0x47e0a5d7, 0x25c22cee, 0xf8878656, + 0xe1873e9c, 0x3cc29424, 0x5ee01d1d, 0x83a5b7a5, + 0xf90696d8, 0x24433c60, 0x4661b559, 0x9b241fe1, + 0x8224a72b, 0x5f610d93, 0x3d4384aa, 0xe0062e12, + 0x0f42f53e, 0xd2075f86, 0xb025d6bf, 0x6d607c07, + 0x7460c4cd, 0xa9256e75, 0xcb07e74c, 0x16424df4, + 0x106227e5, 0xcd278d5d, 0xaf050464, 0x7240aedc, + 0x6b401616, 0xb605bcae, 0xd4273597, 0x09629f2f, + 0xe6264403, 0x3b63eebb, 0x59416782, 0x8404cd3a, + 0x9d0475f0, 0x4041df48, 0x22635671, 0xff26fcc9, + 0x2e238253, 0xf36628eb, 0x9144a1d2, 0x4c010b6a, + 0x5501b3a0, 0x88441918, 0xea669021, 0x37233a99, + 0xd867e1b5, 0x05224b0d, 0x6700c234, 0xba45688c, + 0xa345d046, 0x7e007afe, 0x1c22f3c7, 0xc167597f, + 0xc747336e, 0x1a0299d6, 0x782010ef, 0xa565ba57, + 0xbc65029d, 0x6120a825, 0x0302211c, 0xde478ba4, + 0x31035088, 0xec46fa30, 0x8e647309, 0x5321d9b1, + 0x4a21617b, 0x9764cbc3, 0xf54642fa, 0x2803e842 +}; + +// Used to fetch a naturally-aligned 32-bit word in little endian byte-order +static inline uint32_t LE_LOAD32(const uint8_t *p) { + return DecodeFixed32(reinterpret_cast(p)); +} + +uint32_t Extend(uint32_t crc, const char* buf, size_t size) { + const uint8_t *p = reinterpret_cast(buf); + const uint8_t *e = p + size; + uint32_t l = crc ^ 0xffffffffu; + +#define STEP1 do { \ + int c = (l & 0xff) ^ *p++; \ + l = table0_[c] ^ (l >> 8); \ +} while (0) +#define STEP4 do { \ + uint32_t c = l ^ LE_LOAD32(p); \ + p += 4; \ + l = table3_[c & 0xff] ^ \ + table2_[(c >> 8) & 0xff] ^ \ + table1_[(c >> 16) & 0xff] ^ \ + table0_[c >> 24]; \ +} while (0) + + // Point x at first 4-byte aligned byte in string. This might be + // just past the end of the string. + const uintptr_t pval = reinterpret_cast(p); + const uint8_t* x = reinterpret_cast(((pval + 3) >> 2) << 2); + if (x <= e) { + // Process bytes until finished or p is 4-byte aligned + while (p != x) { + STEP1; + } + } + // Process bytes 16 at a time + while ((e-p) >= 16) { + STEP4; STEP4; STEP4; STEP4; + } + // Process bytes 4 at a time + while ((e-p) >= 4) { + STEP4; + } + // Process the last few bytes + while (p != e) { + STEP1; + } +#undef STEP4 +#undef STEP1 + return l ^ 0xffffffffu; +} + +} // namespace crc32c +} // namespace leveldb diff --git a/ios/Pods/leveldb-library/util/crc32c.h b/ios/Pods/leveldb-library/util/crc32c.h new file mode 100644 index 000000000..1d7e5c075 --- /dev/null +++ b/ios/Pods/leveldb-library/util/crc32c.h @@ -0,0 +1,45 @@ +// Copyright (c) 2011 The LevelDB Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. See the AUTHORS file for names of contributors. + +#ifndef STORAGE_LEVELDB_UTIL_CRC32C_H_ +#define STORAGE_LEVELDB_UTIL_CRC32C_H_ + +#include +#include + +namespace leveldb { +namespace crc32c { + +// Return the crc32c of concat(A, data[0,n-1]) where init_crc is the +// crc32c of some string A. Extend() is often used to maintain the +// crc32c of a stream of data. +extern uint32_t Extend(uint32_t init_crc, const char* data, size_t n); + +// Return the crc32c of data[0,n-1] +inline uint32_t Value(const char* data, size_t n) { + return Extend(0, data, n); +} + +static const uint32_t kMaskDelta = 0xa282ead8ul; + +// Return a masked representation of crc. +// +// Motivation: it is problematic to compute the CRC of a string that +// contains embedded CRCs. Therefore we recommend that CRCs stored +// somewhere (e.g., in files) should be masked before being stored. +inline uint32_t Mask(uint32_t crc) { + // Rotate right by 15 bits and add a constant. + return ((crc >> 15) | (crc << 17)) + kMaskDelta; +} + +// Return the crc whose masked representation is masked_crc. +inline uint32_t Unmask(uint32_t masked_crc) { + uint32_t rot = masked_crc - kMaskDelta; + return ((rot >> 17) | (rot << 15)); +} + +} // namespace crc32c +} // namespace leveldb + +#endif // STORAGE_LEVELDB_UTIL_CRC32C_H_ diff --git a/ios/Pods/leveldb-library/util/crc32c_test.cc b/ios/Pods/leveldb-library/util/crc32c_test.cc new file mode 100644 index 000000000..4b957ee12 --- /dev/null +++ b/ios/Pods/leveldb-library/util/crc32c_test.cc @@ -0,0 +1,72 @@ +// Copyright (c) 2011 The LevelDB Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. See the AUTHORS file for names of contributors. + +#include "util/crc32c.h" +#include "util/testharness.h" + +namespace leveldb { +namespace crc32c { + +class CRC { }; + +TEST(CRC, StandardResults) { + // From rfc3720 section B.4. + char buf[32]; + + memset(buf, 0, sizeof(buf)); + ASSERT_EQ(0x8a9136aa, Value(buf, sizeof(buf))); + + memset(buf, 0xff, sizeof(buf)); + ASSERT_EQ(0x62a8ab43, Value(buf, sizeof(buf))); + + for (int i = 0; i < 32; i++) { + buf[i] = i; + } + ASSERT_EQ(0x46dd794e, Value(buf, sizeof(buf))); + + for (int i = 0; i < 32; i++) { + buf[i] = 31 - i; + } + ASSERT_EQ(0x113fdb5c, Value(buf, sizeof(buf))); + + unsigned char data[48] = { + 0x01, 0xc0, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + 0x14, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x04, 0x00, + 0x00, 0x00, 0x00, 0x14, + 0x00, 0x00, 0x00, 0x18, + 0x28, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + 0x02, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + }; + ASSERT_EQ(0xd9963a56, Value(reinterpret_cast(data), sizeof(data))); +} + +TEST(CRC, Values) { + ASSERT_NE(Value("a", 1), Value("foo", 3)); +} + +TEST(CRC, Extend) { + ASSERT_EQ(Value("hello world", 11), + Extend(Value("hello ", 6), "world", 5)); +} + +TEST(CRC, Mask) { + uint32_t crc = Value("foo", 3); + ASSERT_NE(crc, Mask(crc)); + ASSERT_NE(crc, Mask(Mask(crc))); + ASSERT_EQ(crc, Unmask(Mask(crc))); + ASSERT_EQ(crc, Unmask(Unmask(Mask(Mask(crc))))); +} + +} // namespace crc32c +} // namespace leveldb + +int main(int argc, char** argv) { + return leveldb::test::RunAllTests(); +} diff --git a/ios/Pods/leveldb-library/util/env.cc b/ios/Pods/leveldb-library/util/env.cc new file mode 100644 index 000000000..c2600e964 --- /dev/null +++ b/ios/Pods/leveldb-library/util/env.cc @@ -0,0 +1,96 @@ +// Copyright (c) 2011 The LevelDB Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. See the AUTHORS file for names of contributors. + +#include "leveldb/env.h" + +namespace leveldb { + +Env::~Env() { +} + +SequentialFile::~SequentialFile() { +} + +RandomAccessFile::~RandomAccessFile() { +} + +WritableFile::~WritableFile() { +} + +Logger::~Logger() { +} + +FileLock::~FileLock() { +} + +void Log(Logger* info_log, const char* format, ...) { + if (info_log != NULL) { + va_list ap; + va_start(ap, format); + info_log->Logv(format, ap); + va_end(ap); + } +} + +static Status DoWriteStringToFile(Env* env, const Slice& data, + const std::string& fname, + bool should_sync) { + WritableFile* file; + Status s = env->NewWritableFile(fname, &file); + if (!s.ok()) { + return s; + } + s = file->Append(data); + if (s.ok() && should_sync) { + s = file->Sync(); + } + if (s.ok()) { + s = file->Close(); + } + delete file; // Will auto-close if we did not close above + if (!s.ok()) { + env->DeleteFile(fname); + } + return s; +} + +Status WriteStringToFile(Env* env, const Slice& data, + const std::string& fname) { + return DoWriteStringToFile(env, data, fname, false); +} + +Status WriteStringToFileSync(Env* env, const Slice& data, + const std::string& fname) { + return DoWriteStringToFile(env, data, fname, true); +} + +Status ReadFileToString(Env* env, const std::string& fname, std::string* data) { + data->clear(); + SequentialFile* file; + Status s = env->NewSequentialFile(fname, &file); + if (!s.ok()) { + return s; + } + static const int kBufferSize = 8192; + char* space = new char[kBufferSize]; + while (true) { + Slice fragment; + s = file->Read(kBufferSize, &fragment, space); + if (!s.ok()) { + break; + } + data->append(fragment.data(), fragment.size()); + if (fragment.empty()) { + break; + } + } + delete[] space; + delete file; + return s; +} + +EnvWrapper::~EnvWrapper() { +} + +} // namespace leveldb diff --git a/ios/Pods/leveldb-library/util/env_posix.cc b/ios/Pods/leveldb-library/util/env_posix.cc new file mode 100644 index 000000000..ad56131ae --- /dev/null +++ b/ios/Pods/leveldb-library/util/env_posix.cc @@ -0,0 +1,605 @@ +// Copyright (c) 2011 The LevelDB Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. See the AUTHORS file for names of contributors. + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "leveldb/env.h" +#include "leveldb/slice.h" +#include "port/port.h" +#include "util/logging.h" +#include "util/mutexlock.h" +#include "util/posix_logger.h" + +namespace leveldb { + +namespace { + +static Status IOError(const std::string& context, int err_number) { + return Status::IOError(context, strerror(err_number)); +} + +class PosixSequentialFile: public SequentialFile { + private: + std::string filename_; + FILE* file_; + + public: + PosixSequentialFile(const std::string& fname, FILE* f) + : filename_(fname), file_(f) { } + virtual ~PosixSequentialFile() { fclose(file_); } + + virtual Status Read(size_t n, Slice* result, char* scratch) { + Status s; + size_t r = fread_unlocked(scratch, 1, n, file_); + *result = Slice(scratch, r); + if (r < n) { + if (feof(file_)) { + // We leave status as ok if we hit the end of the file + } else { + // A partial read with an error: return a non-ok status + s = IOError(filename_, errno); + } + } + return s; + } + + virtual Status Skip(uint64_t n) { + if (fseek(file_, n, SEEK_CUR)) { + return IOError(filename_, errno); + } + return Status::OK(); + } +}; + +// pread() based random-access +class PosixRandomAccessFile: public RandomAccessFile { + private: + std::string filename_; + int fd_; + + public: + PosixRandomAccessFile(const std::string& fname, int fd) + : filename_(fname), fd_(fd) { } + virtual ~PosixRandomAccessFile() { close(fd_); } + + virtual Status Read(uint64_t offset, size_t n, Slice* result, + char* scratch) const { + Status s; + ssize_t r = pread(fd_, scratch, n, static_cast(offset)); + *result = Slice(scratch, (r < 0) ? 0 : r); + if (r < 0) { + // An error: return a non-ok status + s = IOError(filename_, errno); + } + return s; + } +}; + +// Helper class to limit mmap file usage so that we do not end up +// running out virtual memory or running into kernel performance +// problems for very large databases. +class MmapLimiter { + public: + // Up to 1000 mmaps for 64-bit binaries; none for smaller pointer sizes. + MmapLimiter() { + SetAllowed(sizeof(void*) >= 8 ? 1000 : 0); + } + + // If another mmap slot is available, acquire it and return true. + // Else return false. + bool Acquire() { + if (GetAllowed() <= 0) { + return false; + } + MutexLock l(&mu_); + intptr_t x = GetAllowed(); + if (x <= 0) { + return false; + } else { + SetAllowed(x - 1); + return true; + } + } + + // Release a slot acquired by a previous call to Acquire() that returned true. + void Release() { + MutexLock l(&mu_); + SetAllowed(GetAllowed() + 1); + } + + private: + port::Mutex mu_; + port::AtomicPointer allowed_; + + intptr_t GetAllowed() const { + return reinterpret_cast(allowed_.Acquire_Load()); + } + + // REQUIRES: mu_ must be held + void SetAllowed(intptr_t v) { + allowed_.Release_Store(reinterpret_cast(v)); + } + + MmapLimiter(const MmapLimiter&); + void operator=(const MmapLimiter&); +}; + +// mmap() based random-access +class PosixMmapReadableFile: public RandomAccessFile { + private: + std::string filename_; + void* mmapped_region_; + size_t length_; + MmapLimiter* limiter_; + + public: + // base[0,length-1] contains the mmapped contents of the file. + PosixMmapReadableFile(const std::string& fname, void* base, size_t length, + MmapLimiter* limiter) + : filename_(fname), mmapped_region_(base), length_(length), + limiter_(limiter) { + } + + virtual ~PosixMmapReadableFile() { + munmap(mmapped_region_, length_); + limiter_->Release(); + } + + virtual Status Read(uint64_t offset, size_t n, Slice* result, + char* scratch) const { + Status s; + if (offset + n > length_) { + *result = Slice(); + s = IOError(filename_, EINVAL); + } else { + *result = Slice(reinterpret_cast(mmapped_region_) + offset, n); + } + return s; + } +}; + +class PosixWritableFile : public WritableFile { + private: + std::string filename_; + FILE* file_; + + public: + PosixWritableFile(const std::string& fname, FILE* f) + : filename_(fname), file_(f) { } + + ~PosixWritableFile() { + if (file_ != NULL) { + // Ignoring any potential errors + fclose(file_); + } + } + + virtual Status Append(const Slice& data) { + size_t r = fwrite_unlocked(data.data(), 1, data.size(), file_); + if (r != data.size()) { + return IOError(filename_, errno); + } + return Status::OK(); + } + + virtual Status Close() { + Status result; + if (fclose(file_) != 0) { + result = IOError(filename_, errno); + } + file_ = NULL; + return result; + } + + virtual Status Flush() { + if (fflush_unlocked(file_) != 0) { + return IOError(filename_, errno); + } + return Status::OK(); + } + + Status SyncDirIfManifest() { + const char* f = filename_.c_str(); + const char* sep = strrchr(f, '/'); + Slice basename; + std::string dir; + if (sep == NULL) { + dir = "."; + basename = f; + } else { + dir = std::string(f, sep - f); + basename = sep + 1; + } + Status s; + if (basename.starts_with("MANIFEST")) { + int fd = open(dir.c_str(), O_RDONLY); + if (fd < 0) { + s = IOError(dir, errno); + } else { + if (fsync(fd) < 0) { + s = IOError(dir, errno); + } + close(fd); + } + } + return s; + } + + virtual Status Sync() { + // Ensure new files referred to by the manifest are in the filesystem. + Status s = SyncDirIfManifest(); + if (!s.ok()) { + return s; + } + if (fflush_unlocked(file_) != 0 || + fdatasync(fileno(file_)) != 0) { + s = Status::IOError(filename_, strerror(errno)); + } + return s; + } +}; + +static int LockOrUnlock(int fd, bool lock) { + errno = 0; + struct flock f; + memset(&f, 0, sizeof(f)); + f.l_type = (lock ? F_WRLCK : F_UNLCK); + f.l_whence = SEEK_SET; + f.l_start = 0; + f.l_len = 0; // Lock/unlock entire file + return fcntl(fd, F_SETLK, &f); +} + +class PosixFileLock : public FileLock { + public: + int fd_; + std::string name_; +}; + +// Set of locked files. We keep a separate set instead of just +// relying on fcntrl(F_SETLK) since fcntl(F_SETLK) does not provide +// any protection against multiple uses from the same process. +class PosixLockTable { + private: + port::Mutex mu_; + std::set locked_files_; + public: + bool Insert(const std::string& fname) { + MutexLock l(&mu_); + return locked_files_.insert(fname).second; + } + void Remove(const std::string& fname) { + MutexLock l(&mu_); + locked_files_.erase(fname); + } +}; + +class PosixEnv : public Env { + public: + PosixEnv(); + virtual ~PosixEnv() { + char msg[] = "Destroying Env::Default()\n"; + fwrite(msg, 1, sizeof(msg), stderr); + abort(); + } + + virtual Status NewSequentialFile(const std::string& fname, + SequentialFile** result) { + FILE* f = fopen(fname.c_str(), "r"); + if (f == NULL) { + *result = NULL; + return IOError(fname, errno); + } else { + *result = new PosixSequentialFile(fname, f); + return Status::OK(); + } + } + + virtual Status NewRandomAccessFile(const std::string& fname, + RandomAccessFile** result) { + *result = NULL; + Status s; + int fd = open(fname.c_str(), O_RDONLY); + if (fd < 0) { + s = IOError(fname, errno); + } else if (mmap_limit_.Acquire()) { + uint64_t size; + s = GetFileSize(fname, &size); + if (s.ok()) { + void* base = mmap(NULL, size, PROT_READ, MAP_SHARED, fd, 0); + if (base != MAP_FAILED) { + *result = new PosixMmapReadableFile(fname, base, size, &mmap_limit_); + } else { + s = IOError(fname, errno); + } + } + close(fd); + if (!s.ok()) { + mmap_limit_.Release(); + } + } else { + *result = new PosixRandomAccessFile(fname, fd); + } + return s; + } + + virtual Status NewWritableFile(const std::string& fname, + WritableFile** result) { + Status s; + FILE* f = fopen(fname.c_str(), "w"); + if (f == NULL) { + *result = NULL; + s = IOError(fname, errno); + } else { + *result = new PosixWritableFile(fname, f); + } + return s; + } + + virtual bool FileExists(const std::string& fname) { + return access(fname.c_str(), F_OK) == 0; + } + + virtual Status GetChildren(const std::string& dir, + std::vector* result) { + result->clear(); + DIR* d = opendir(dir.c_str()); + if (d == NULL) { + return IOError(dir, errno); + } + struct dirent* entry; + while ((entry = readdir(d)) != NULL) { + result->push_back(entry->d_name); + } + closedir(d); + return Status::OK(); + } + + virtual Status DeleteFile(const std::string& fname) { + Status result; + if (unlink(fname.c_str()) != 0) { + result = IOError(fname, errno); + } + return result; + } + + virtual Status CreateDir(const std::string& name) { + Status result; + if (mkdir(name.c_str(), 0755) != 0) { + result = IOError(name, errno); + } + return result; + } + + virtual Status DeleteDir(const std::string& name) { + Status result; + if (rmdir(name.c_str()) != 0) { + result = IOError(name, errno); + } + return result; + } + + virtual Status GetFileSize(const std::string& fname, uint64_t* size) { + Status s; + struct stat sbuf; + if (stat(fname.c_str(), &sbuf) != 0) { + *size = 0; + s = IOError(fname, errno); + } else { + *size = sbuf.st_size; + } + return s; + } + + virtual Status RenameFile(const std::string& src, const std::string& target) { + Status result; + if (rename(src.c_str(), target.c_str()) != 0) { + result = IOError(src, errno); + } + return result; + } + + virtual Status LockFile(const std::string& fname, FileLock** lock) { + *lock = NULL; + Status result; + int fd = open(fname.c_str(), O_RDWR | O_CREAT, 0644); + if (fd < 0) { + result = IOError(fname, errno); + } else if (!locks_.Insert(fname)) { + close(fd); + result = Status::IOError("lock " + fname, "already held by process"); + } else if (LockOrUnlock(fd, true) == -1) { + result = IOError("lock " + fname, errno); + close(fd); + locks_.Remove(fname); + } else { + PosixFileLock* my_lock = new PosixFileLock; + my_lock->fd_ = fd; + my_lock->name_ = fname; + *lock = my_lock; + } + return result; + } + + virtual Status UnlockFile(FileLock* lock) { + PosixFileLock* my_lock = reinterpret_cast(lock); + Status result; + if (LockOrUnlock(my_lock->fd_, false) == -1) { + result = IOError("unlock", errno); + } + locks_.Remove(my_lock->name_); + close(my_lock->fd_); + delete my_lock; + return result; + } + + virtual void Schedule(void (*function)(void*), void* arg); + + virtual void StartThread(void (*function)(void* arg), void* arg); + + virtual Status GetTestDirectory(std::string* result) { + const char* env = getenv("TEST_TMPDIR"); + if (env && env[0] != '\0') { + *result = env; + } else { + char buf[100]; + snprintf(buf, sizeof(buf), "/tmp/leveldbtest-%d", int(geteuid())); + *result = buf; + } + // Directory may already exist + CreateDir(*result); + return Status::OK(); + } + + static uint64_t gettid() { + pthread_t tid = pthread_self(); + uint64_t thread_id = 0; + memcpy(&thread_id, &tid, std::min(sizeof(thread_id), sizeof(tid))); + return thread_id; + } + + virtual Status NewLogger(const std::string& fname, Logger** result) { + FILE* f = fopen(fname.c_str(), "w"); + if (f == NULL) { + *result = NULL; + return IOError(fname, errno); + } else { + *result = new PosixLogger(f, &PosixEnv::gettid); + return Status::OK(); + } + } + + virtual uint64_t NowMicros() { + struct timeval tv; + gettimeofday(&tv, NULL); + return static_cast(tv.tv_sec) * 1000000 + tv.tv_usec; + } + + virtual void SleepForMicroseconds(int micros) { + usleep(micros); + } + + private: + void PthreadCall(const char* label, int result) { + if (result != 0) { + fprintf(stderr, "pthread %s: %s\n", label, strerror(result)); + abort(); + } + } + + // BGThread() is the body of the background thread + void BGThread(); + static void* BGThreadWrapper(void* arg) { + reinterpret_cast(arg)->BGThread(); + return NULL; + } + + pthread_mutex_t mu_; + pthread_cond_t bgsignal_; + pthread_t bgthread_; + bool started_bgthread_; + + // Entry per Schedule() call + struct BGItem { void* arg; void (*function)(void*); }; + typedef std::deque BGQueue; + BGQueue queue_; + + PosixLockTable locks_; + MmapLimiter mmap_limit_; +}; + +PosixEnv::PosixEnv() : started_bgthread_(false) { + PthreadCall("mutex_init", pthread_mutex_init(&mu_, NULL)); + PthreadCall("cvar_init", pthread_cond_init(&bgsignal_, NULL)); +} + +void PosixEnv::Schedule(void (*function)(void*), void* arg) { + PthreadCall("lock", pthread_mutex_lock(&mu_)); + + // Start background thread if necessary + if (!started_bgthread_) { + started_bgthread_ = true; + PthreadCall( + "create thread", + pthread_create(&bgthread_, NULL, &PosixEnv::BGThreadWrapper, this)); + } + + // If the queue is currently empty, the background thread may currently be + // waiting. + if (queue_.empty()) { + PthreadCall("signal", pthread_cond_signal(&bgsignal_)); + } + + // Add to priority queue + queue_.push_back(BGItem()); + queue_.back().function = function; + queue_.back().arg = arg; + + PthreadCall("unlock", pthread_mutex_unlock(&mu_)); +} + +void PosixEnv::BGThread() { + while (true) { + // Wait until there is an item that is ready to run + PthreadCall("lock", pthread_mutex_lock(&mu_)); + while (queue_.empty()) { + PthreadCall("wait", pthread_cond_wait(&bgsignal_, &mu_)); + } + + void (*function)(void*) = queue_.front().function; + void* arg = queue_.front().arg; + queue_.pop_front(); + + PthreadCall("unlock", pthread_mutex_unlock(&mu_)); + (*function)(arg); + } +} + +namespace { +struct StartThreadState { + void (*user_function)(void*); + void* arg; +}; +} +static void* StartThreadWrapper(void* arg) { + StartThreadState* state = reinterpret_cast(arg); + state->user_function(state->arg); + delete state; + return NULL; +} + +void PosixEnv::StartThread(void (*function)(void* arg), void* arg) { + pthread_t t; + StartThreadState* state = new StartThreadState; + state->user_function = function; + state->arg = arg; + PthreadCall("start thread", + pthread_create(&t, NULL, &StartThreadWrapper, state)); +} + +} // namespace + +static pthread_once_t once = PTHREAD_ONCE_INIT; +static Env* default_env; +static void InitDefaultEnv() { default_env = new PosixEnv; } + +Env* Env::Default() { + pthread_once(&once, InitDefaultEnv); + return default_env; +} + +} // namespace leveldb diff --git a/ios/Pods/leveldb-library/util/env_test.cc b/ios/Pods/leveldb-library/util/env_test.cc new file mode 100644 index 000000000..b72cb4438 --- /dev/null +++ b/ios/Pods/leveldb-library/util/env_test.cc @@ -0,0 +1,104 @@ +// Copyright (c) 2011 The LevelDB Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. See the AUTHORS file for names of contributors. + +#include "leveldb/env.h" + +#include "port/port.h" +#include "util/testharness.h" + +namespace leveldb { + +static const int kDelayMicros = 100000; + +class EnvPosixTest { + private: + port::Mutex mu_; + std::string events_; + + public: + Env* env_; + EnvPosixTest() : env_(Env::Default()) { } +}; + +static void SetBool(void* ptr) { + reinterpret_cast(ptr)->NoBarrier_Store(ptr); +} + +TEST(EnvPosixTest, RunImmediately) { + port::AtomicPointer called (NULL); + env_->Schedule(&SetBool, &called); + Env::Default()->SleepForMicroseconds(kDelayMicros); + ASSERT_TRUE(called.NoBarrier_Load() != NULL); +} + +TEST(EnvPosixTest, RunMany) { + port::AtomicPointer last_id (NULL); + + struct CB { + port::AtomicPointer* last_id_ptr; // Pointer to shared slot + uintptr_t id; // Order# for the execution of this callback + + CB(port::AtomicPointer* p, int i) : last_id_ptr(p), id(i) { } + + static void Run(void* v) { + CB* cb = reinterpret_cast(v); + void* cur = cb->last_id_ptr->NoBarrier_Load(); + ASSERT_EQ(cb->id-1, reinterpret_cast(cur)); + cb->last_id_ptr->Release_Store(reinterpret_cast(cb->id)); + } + }; + + // Schedule in different order than start time + CB cb1(&last_id, 1); + CB cb2(&last_id, 2); + CB cb3(&last_id, 3); + CB cb4(&last_id, 4); + env_->Schedule(&CB::Run, &cb1); + env_->Schedule(&CB::Run, &cb2); + env_->Schedule(&CB::Run, &cb3); + env_->Schedule(&CB::Run, &cb4); + + Env::Default()->SleepForMicroseconds(kDelayMicros); + void* cur = last_id.Acquire_Load(); + ASSERT_EQ(4, reinterpret_cast(cur)); +} + +struct State { + port::Mutex mu; + int val; + int num_running; +}; + +static void ThreadBody(void* arg) { + State* s = reinterpret_cast(arg); + s->mu.Lock(); + s->val += 1; + s->num_running -= 1; + s->mu.Unlock(); +} + +TEST(EnvPosixTest, StartThread) { + State state; + state.val = 0; + state.num_running = 3; + for (int i = 0; i < 3; i++) { + env_->StartThread(&ThreadBody, &state); + } + while (true) { + state.mu.Lock(); + int num = state.num_running; + state.mu.Unlock(); + if (num == 0) { + break; + } + Env::Default()->SleepForMicroseconds(kDelayMicros); + } + ASSERT_EQ(state.val, 3); +} + +} // namespace leveldb + +int main(int argc, char** argv) { + return leveldb::test::RunAllTests(); +} diff --git a/ios/Pods/leveldb-library/util/filter_policy.cc b/ios/Pods/leveldb-library/util/filter_policy.cc new file mode 100644 index 000000000..7b045c8c9 --- /dev/null +++ b/ios/Pods/leveldb-library/util/filter_policy.cc @@ -0,0 +1,11 @@ +// Copyright (c) 2012 The LevelDB Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. See the AUTHORS file for names of contributors. + +#include "leveldb/filter_policy.h" + +namespace leveldb { + +FilterPolicy::~FilterPolicy() { } + +} // namespace leveldb diff --git a/ios/Pods/leveldb-library/util/hash.cc b/ios/Pods/leveldb-library/util/hash.cc new file mode 100644 index 000000000..ed439ce7a --- /dev/null +++ b/ios/Pods/leveldb-library/util/hash.cc @@ -0,0 +1,52 @@ +// Copyright (c) 2011 The LevelDB Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. See the AUTHORS file for names of contributors. + +#include +#include "util/coding.h" +#include "util/hash.h" + +// The FALLTHROUGH_INTENDED macro can be used to annotate implicit fall-through +// between switch labels. The real definition should be provided externally. +// This one is a fallback version for unsupported compilers. +#ifndef FALLTHROUGH_INTENDED +#define FALLTHROUGH_INTENDED do { } while (0) +#endif + +namespace leveldb { + +uint32_t Hash(const char* data, size_t n, uint32_t seed) { + // Similar to murmur hash + const uint32_t m = 0xc6a4a793; + const uint32_t r = 24; + const char* limit = data + n; + uint32_t h = seed ^ (n * m); + + // Pick up four bytes at a time + while (data + 4 <= limit) { + uint32_t w = DecodeFixed32(data); + data += 4; + h += w; + h *= m; + h ^= (h >> 16); + } + + // Pick up remaining bytes + switch (limit - data) { + case 3: + h += static_cast(data[2]) << 16; + FALLTHROUGH_INTENDED; + case 2: + h += static_cast(data[1]) << 8; + FALLTHROUGH_INTENDED; + case 1: + h += static_cast(data[0]); + h *= m; + h ^= (h >> r); + break; + } + return h; +} + + +} // namespace leveldb diff --git a/ios/Pods/leveldb-library/util/hash.h b/ios/Pods/leveldb-library/util/hash.h new file mode 100644 index 000000000..8889d56be --- /dev/null +++ b/ios/Pods/leveldb-library/util/hash.h @@ -0,0 +1,19 @@ +// Copyright (c) 2011 The LevelDB Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. See the AUTHORS file for names of contributors. +// +// Simple hash function used for internal data structures + +#ifndef STORAGE_LEVELDB_UTIL_HASH_H_ +#define STORAGE_LEVELDB_UTIL_HASH_H_ + +#include +#include + +namespace leveldb { + +extern uint32_t Hash(const char* data, size_t n, uint32_t seed); + +} + +#endif // STORAGE_LEVELDB_UTIL_HASH_H_ diff --git a/ios/Pods/leveldb-library/util/hash_test.cc b/ios/Pods/leveldb-library/util/hash_test.cc new file mode 100644 index 000000000..eaa1c92c2 --- /dev/null +++ b/ios/Pods/leveldb-library/util/hash_test.cc @@ -0,0 +1,54 @@ +// Copyright (c) 2011 The LevelDB Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. See the AUTHORS file for names of contributors. + +#include "util/hash.h" +#include "util/testharness.h" + +namespace leveldb { + +class HASH { }; + +TEST(HASH, SignedUnsignedIssue) { + const unsigned char data1[1] = {0x62}; + const unsigned char data2[2] = {0xc3, 0x97}; + const unsigned char data3[3] = {0xe2, 0x99, 0xa5}; + const unsigned char data4[4] = {0xe1, 0x80, 0xb9, 0x32}; + const unsigned char data5[48] = { + 0x01, 0xc0, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + 0x14, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x04, 0x00, + 0x00, 0x00, 0x00, 0x14, + 0x00, 0x00, 0x00, 0x18, + 0x28, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + 0x02, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + }; + + ASSERT_EQ(Hash(0, 0, 0xbc9f1d34), 0xbc9f1d34); + ASSERT_EQ( + Hash(reinterpret_cast(data1), sizeof(data1), 0xbc9f1d34), + 0xef1345c4); + ASSERT_EQ( + Hash(reinterpret_cast(data2), sizeof(data2), 0xbc9f1d34), + 0x5b663814); + ASSERT_EQ( + Hash(reinterpret_cast(data3), sizeof(data3), 0xbc9f1d34), + 0x323c078f); + ASSERT_EQ( + Hash(reinterpret_cast(data4), sizeof(data4), 0xbc9f1d34), + 0xed21633a); + ASSERT_EQ( + Hash(reinterpret_cast(data5), sizeof(data5), 0x12345678), + 0xf333dabb); +} + +} // namespace leveldb + +int main(int argc, char** argv) { + return leveldb::test::RunAllTests(); +} diff --git a/ios/Pods/leveldb-library/util/histogram.cc b/ios/Pods/leveldb-library/util/histogram.cc new file mode 100644 index 000000000..bb95f583e --- /dev/null +++ b/ios/Pods/leveldb-library/util/histogram.cc @@ -0,0 +1,139 @@ +// Copyright (c) 2011 The LevelDB Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. See the AUTHORS file for names of contributors. + +#include +#include +#include "port/port.h" +#include "util/histogram.h" + +namespace leveldb { + +const double Histogram::kBucketLimit[kNumBuckets] = { + 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 12, 14, 16, 18, 20, 25, 30, 35, 40, 45, + 50, 60, 70, 80, 90, 100, 120, 140, 160, 180, 200, 250, 300, 350, 400, 450, + 500, 600, 700, 800, 900, 1000, 1200, 1400, 1600, 1800, 2000, 2500, 3000, + 3500, 4000, 4500, 5000, 6000, 7000, 8000, 9000, 10000, 12000, 14000, + 16000, 18000, 20000, 25000, 30000, 35000, 40000, 45000, 50000, 60000, + 70000, 80000, 90000, 100000, 120000, 140000, 160000, 180000, 200000, + 250000, 300000, 350000, 400000, 450000, 500000, 600000, 700000, 800000, + 900000, 1000000, 1200000, 1400000, 1600000, 1800000, 2000000, 2500000, + 3000000, 3500000, 4000000, 4500000, 5000000, 6000000, 7000000, 8000000, + 9000000, 10000000, 12000000, 14000000, 16000000, 18000000, 20000000, + 25000000, 30000000, 35000000, 40000000, 45000000, 50000000, 60000000, + 70000000, 80000000, 90000000, 100000000, 120000000, 140000000, 160000000, + 180000000, 200000000, 250000000, 300000000, 350000000, 400000000, + 450000000, 500000000, 600000000, 700000000, 800000000, 900000000, + 1000000000, 1200000000, 1400000000, 1600000000, 1800000000, 2000000000, + 2500000000.0, 3000000000.0, 3500000000.0, 4000000000.0, 4500000000.0, + 5000000000.0, 6000000000.0, 7000000000.0, 8000000000.0, 9000000000.0, + 1e200, +}; + +void Histogram::Clear() { + min_ = kBucketLimit[kNumBuckets-1]; + max_ = 0; + num_ = 0; + sum_ = 0; + sum_squares_ = 0; + for (int i = 0; i < kNumBuckets; i++) { + buckets_[i] = 0; + } +} + +void Histogram::Add(double value) { + // Linear search is fast enough for our usage in db_bench + int b = 0; + while (b < kNumBuckets - 1 && kBucketLimit[b] <= value) { + b++; + } + buckets_[b] += 1.0; + if (min_ > value) min_ = value; + if (max_ < value) max_ = value; + num_++; + sum_ += value; + sum_squares_ += (value * value); +} + +void Histogram::Merge(const Histogram& other) { + if (other.min_ < min_) min_ = other.min_; + if (other.max_ > max_) max_ = other.max_; + num_ += other.num_; + sum_ += other.sum_; + sum_squares_ += other.sum_squares_; + for (int b = 0; b < kNumBuckets; b++) { + buckets_[b] += other.buckets_[b]; + } +} + +double Histogram::Median() const { + return Percentile(50.0); +} + +double Histogram::Percentile(double p) const { + double threshold = num_ * (p / 100.0); + double sum = 0; + for (int b = 0; b < kNumBuckets; b++) { + sum += buckets_[b]; + if (sum >= threshold) { + // Scale linearly within this bucket + double left_point = (b == 0) ? 0 : kBucketLimit[b-1]; + double right_point = kBucketLimit[b]; + double left_sum = sum - buckets_[b]; + double right_sum = sum; + double pos = (threshold - left_sum) / (right_sum - left_sum); + double r = left_point + (right_point - left_point) * pos; + if (r < min_) r = min_; + if (r > max_) r = max_; + return r; + } + } + return max_; +} + +double Histogram::Average() const { + if (num_ == 0.0) return 0; + return sum_ / num_; +} + +double Histogram::StandardDeviation() const { + if (num_ == 0.0) return 0; + double variance = (sum_squares_ * num_ - sum_ * sum_) / (num_ * num_); + return sqrt(variance); +} + +std::string Histogram::ToString() const { + std::string r; + char buf[200]; + snprintf(buf, sizeof(buf), + "Count: %.0f Average: %.4f StdDev: %.2f\n", + num_, Average(), StandardDeviation()); + r.append(buf); + snprintf(buf, sizeof(buf), + "Min: %.4f Median: %.4f Max: %.4f\n", + (num_ == 0.0 ? 0.0 : min_), Median(), max_); + r.append(buf); + r.append("------------------------------------------------------\n"); + const double mult = 100.0 / num_; + double sum = 0; + for (int b = 0; b < kNumBuckets; b++) { + if (buckets_[b] <= 0.0) continue; + sum += buckets_[b]; + snprintf(buf, sizeof(buf), + "[ %7.0f, %7.0f ) %7.0f %7.3f%% %7.3f%% ", + ((b == 0) ? 0.0 : kBucketLimit[b-1]), // left + kBucketLimit[b], // right + buckets_[b], // count + mult * buckets_[b], // percentage + mult * sum); // cumulative percentage + r.append(buf); + + // Add hash marks based on percentage; 20 marks for 100%. + int marks = static_cast(20*(buckets_[b] / num_) + 0.5); + r.append(marks, '#'); + r.push_back('\n'); + } + return r; +} + +} // namespace leveldb diff --git a/ios/Pods/leveldb-library/util/histogram.h b/ios/Pods/leveldb-library/util/histogram.h new file mode 100644 index 000000000..1ef9f3c8a --- /dev/null +++ b/ios/Pods/leveldb-library/util/histogram.h @@ -0,0 +1,42 @@ +// Copyright (c) 2011 The LevelDB Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. See the AUTHORS file for names of contributors. + +#ifndef STORAGE_LEVELDB_UTIL_HISTOGRAM_H_ +#define STORAGE_LEVELDB_UTIL_HISTOGRAM_H_ + +#include + +namespace leveldb { + +class Histogram { + public: + Histogram() { } + ~Histogram() { } + + void Clear(); + void Add(double value); + void Merge(const Histogram& other); + + std::string ToString() const; + + private: + double min_; + double max_; + double num_; + double sum_; + double sum_squares_; + + enum { kNumBuckets = 154 }; + static const double kBucketLimit[kNumBuckets]; + double buckets_[kNumBuckets]; + + double Median() const; + double Percentile(double p) const; + double Average() const; + double StandardDeviation() const; +}; + +} // namespace leveldb + +#endif // STORAGE_LEVELDB_UTIL_HISTOGRAM_H_ diff --git a/ios/Pods/leveldb-library/util/logging.cc b/ios/Pods/leveldb-library/util/logging.cc new file mode 100644 index 000000000..ca6b32440 --- /dev/null +++ b/ios/Pods/leveldb-library/util/logging.cc @@ -0,0 +1,72 @@ +// Copyright (c) 2011 The LevelDB Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. See the AUTHORS file for names of contributors. + +#include "util/logging.h" + +#include +#include +#include +#include +#include "leveldb/env.h" +#include "leveldb/slice.h" + +namespace leveldb { + +void AppendNumberTo(std::string* str, uint64_t num) { + char buf[30]; + snprintf(buf, sizeof(buf), "%llu", (unsigned long long) num); + str->append(buf); +} + +void AppendEscapedStringTo(std::string* str, const Slice& value) { + for (size_t i = 0; i < value.size(); i++) { + char c = value[i]; + if (c >= ' ' && c <= '~') { + str->push_back(c); + } else { + char buf[10]; + snprintf(buf, sizeof(buf), "\\x%02x", + static_cast(c) & 0xff); + str->append(buf); + } + } +} + +std::string NumberToString(uint64_t num) { + std::string r; + AppendNumberTo(&r, num); + return r; +} + +std::string EscapeString(const Slice& value) { + std::string r; + AppendEscapedStringTo(&r, value); + return r; +} + +bool ConsumeDecimalNumber(Slice* in, uint64_t* val) { + uint64_t v = 0; + int digits = 0; + while (!in->empty()) { + char c = (*in)[0]; + if (c >= '0' && c <= '9') { + ++digits; + const int delta = (c - '0'); + static const uint64_t kMaxUint64 = ~static_cast(0); + if (v > kMaxUint64/10 || + (v == kMaxUint64/10 && delta > kMaxUint64%10)) { + // Overflow + return false; + } + v = (v * 10) + delta; + in->remove_prefix(1); + } else { + break; + } + } + *val = v; + return (digits > 0); +} + +} // namespace leveldb diff --git a/ios/Pods/leveldb-library/util/logging.h b/ios/Pods/leveldb-library/util/logging.h new file mode 100644 index 000000000..1b450d248 --- /dev/null +++ b/ios/Pods/leveldb-library/util/logging.h @@ -0,0 +1,43 @@ +// Copyright (c) 2011 The LevelDB Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. See the AUTHORS file for names of contributors. +// +// Must not be included from any .h files to avoid polluting the namespace +// with macros. + +#ifndef STORAGE_LEVELDB_UTIL_LOGGING_H_ +#define STORAGE_LEVELDB_UTIL_LOGGING_H_ + +#include +#include +#include +#include "port/port.h" + +namespace leveldb { + +class Slice; +class WritableFile; + +// Append a human-readable printout of "num" to *str +extern void AppendNumberTo(std::string* str, uint64_t num); + +// Append a human-readable printout of "value" to *str. +// Escapes any non-printable characters found in "value". +extern void AppendEscapedStringTo(std::string* str, const Slice& value); + +// Return a human-readable printout of "num" +extern std::string NumberToString(uint64_t num); + +// Return a human-readable version of "value". +// Escapes any non-printable characters found in "value". +extern std::string EscapeString(const Slice& value); + +// Parse a human-readable number from "*in" into *value. On success, +// advances "*in" past the consumed number and sets "*val" to the +// numeric value. Otherwise, returns false and leaves *in in an +// unspecified state. +extern bool ConsumeDecimalNumber(Slice* in, uint64_t* val); + +} // namespace leveldb + +#endif // STORAGE_LEVELDB_UTIL_LOGGING_H_ diff --git a/ios/Pods/leveldb-library/util/mutexlock.h b/ios/Pods/leveldb-library/util/mutexlock.h new file mode 100644 index 000000000..1ff5a9efa --- /dev/null +++ b/ios/Pods/leveldb-library/util/mutexlock.h @@ -0,0 +1,41 @@ +// Copyright (c) 2011 The LevelDB Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. See the AUTHORS file for names of contributors. + +#ifndef STORAGE_LEVELDB_UTIL_MUTEXLOCK_H_ +#define STORAGE_LEVELDB_UTIL_MUTEXLOCK_H_ + +#include "port/port.h" +#include "port/thread_annotations.h" + +namespace leveldb { + +// Helper class that locks a mutex on construction and unlocks the mutex when +// the destructor of the MutexLock object is invoked. +// +// Typical usage: +// +// void MyClass::MyMethod() { +// MutexLock l(&mu_); // mu_ is an instance variable +// ... some complex code, possibly with multiple return paths ... +// } + +class SCOPED_LOCKABLE MutexLock { + public: + explicit MutexLock(port::Mutex *mu) EXCLUSIVE_LOCK_FUNCTION(mu) + : mu_(mu) { + this->mu_->Lock(); + } + ~MutexLock() UNLOCK_FUNCTION() { this->mu_->Unlock(); } + + private: + port::Mutex *const mu_; + // No copying allowed + MutexLock(const MutexLock&); + void operator=(const MutexLock&); +}; + +} // namespace leveldb + + +#endif // STORAGE_LEVELDB_UTIL_MUTEXLOCK_H_ diff --git a/ios/Pods/leveldb-library/util/options.cc b/ios/Pods/leveldb-library/util/options.cc new file mode 100644 index 000000000..76af5b930 --- /dev/null +++ b/ios/Pods/leveldb-library/util/options.cc @@ -0,0 +1,29 @@ +// Copyright (c) 2011 The LevelDB Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. See the AUTHORS file for names of contributors. + +#include "leveldb/options.h" + +#include "leveldb/comparator.h" +#include "leveldb/env.h" + +namespace leveldb { + +Options::Options() + : comparator(BytewiseComparator()), + create_if_missing(false), + error_if_exists(false), + paranoid_checks(false), + env(Env::Default()), + info_log(NULL), + write_buffer_size(4<<20), + max_open_files(1000), + block_cache(NULL), + block_size(4096), + block_restart_interval(16), + compression(kSnappyCompression), + filter_policy(NULL) { +} + + +} // namespace leveldb diff --git a/ios/Pods/leveldb-library/util/posix_logger.h b/ios/Pods/leveldb-library/util/posix_logger.h new file mode 100644 index 000000000..9741b1afa --- /dev/null +++ b/ios/Pods/leveldb-library/util/posix_logger.h @@ -0,0 +1,98 @@ +// Copyright (c) 2011 The LevelDB Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. See the AUTHORS file for names of contributors. +// +// Logger implementation that can be shared by all environments +// where enough posix functionality is available. + +#ifndef STORAGE_LEVELDB_UTIL_POSIX_LOGGER_H_ +#define STORAGE_LEVELDB_UTIL_POSIX_LOGGER_H_ + +#include +#include +#include +#include +#include "leveldb/env.h" + +namespace leveldb { + +class PosixLogger : public Logger { + private: + FILE* file_; + uint64_t (*gettid_)(); // Return the thread id for the current thread + public: + PosixLogger(FILE* f, uint64_t (*gettid)()) : file_(f), gettid_(gettid) { } + virtual ~PosixLogger() { + fclose(file_); + } + virtual void Logv(const char* format, va_list ap) { + const uint64_t thread_id = (*gettid_)(); + + // We try twice: the first time with a fixed-size stack allocated buffer, + // and the second time with a much larger dynamically allocated buffer. + char buffer[500]; + for (int iter = 0; iter < 2; iter++) { + char* base; + int bufsize; + if (iter == 0) { + bufsize = sizeof(buffer); + base = buffer; + } else { + bufsize = 30000; + base = new char[bufsize]; + } + char* p = base; + char* limit = base + bufsize; + + struct timeval now_tv; + gettimeofday(&now_tv, NULL); + const time_t seconds = now_tv.tv_sec; + struct tm t; + localtime_r(&seconds, &t); + p += snprintf(p, limit - p, + "%04d/%02d/%02d-%02d:%02d:%02d.%06d %llx ", + t.tm_year + 1900, + t.tm_mon + 1, + t.tm_mday, + t.tm_hour, + t.tm_min, + t.tm_sec, + static_cast(now_tv.tv_usec), + static_cast(thread_id)); + + // Print the message + if (p < limit) { + va_list backup_ap; + va_copy(backup_ap, ap); + p += vsnprintf(p, limit - p, format, backup_ap); + va_end(backup_ap); + } + + // Truncate to available space if necessary + if (p >= limit) { + if (iter == 0) { + continue; // Try again with larger buffer + } else { + p = limit - 1; + } + } + + // Add newline if necessary + if (p == base || p[-1] != '\n') { + *p++ = '\n'; + } + + assert(p <= limit); + fwrite(base, 1, p - base, file_); + fflush(file_); + if (base != buffer) { + delete[] base; + } + break; + } + } +}; + +} // namespace leveldb + +#endif // STORAGE_LEVELDB_UTIL_POSIX_LOGGER_H_ diff --git a/ios/Pods/leveldb-library/util/random.h b/ios/Pods/leveldb-library/util/random.h new file mode 100644 index 000000000..ddd51b1c7 --- /dev/null +++ b/ios/Pods/leveldb-library/util/random.h @@ -0,0 +1,64 @@ +// Copyright (c) 2011 The LevelDB Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. See the AUTHORS file for names of contributors. + +#ifndef STORAGE_LEVELDB_UTIL_RANDOM_H_ +#define STORAGE_LEVELDB_UTIL_RANDOM_H_ + +#include + +namespace leveldb { + +// A very simple random number generator. Not especially good at +// generating truly random bits, but good enough for our needs in this +// package. +class Random { + private: + uint32_t seed_; + public: + explicit Random(uint32_t s) : seed_(s & 0x7fffffffu) { + // Avoid bad seeds. + if (seed_ == 0 || seed_ == 2147483647L) { + seed_ = 1; + } + } + uint32_t Next() { + static const uint32_t M = 2147483647L; // 2^31-1 + static const uint64_t A = 16807; // bits 14, 8, 7, 5, 2, 1, 0 + // We are computing + // seed_ = (seed_ * A) % M, where M = 2^31-1 + // + // seed_ must not be zero or M, or else all subsequent computed values + // will be zero or M respectively. For all other values, seed_ will end + // up cycling through every number in [1,M-1] + uint64_t product = seed_ * A; + + // Compute (product % M) using the fact that ((x << 31) % M) == x. + seed_ = static_cast((product >> 31) + (product & M)); + // The first reduction may overflow by 1 bit, so we may need to + // repeat. mod == M is not possible; using > allows the faster + // sign-bit-based test. + if (seed_ > M) { + seed_ -= M; + } + return seed_; + } + // Returns a uniformly distributed value in the range [0..n-1] + // REQUIRES: n > 0 + uint32_t Uniform(int n) { return Next() % n; } + + // Randomly returns true ~"1/n" of the time, and false otherwise. + // REQUIRES: n > 0 + bool OneIn(int n) { return (Next() % n) == 0; } + + // Skewed: pick "base" uniformly from range [0,max_log] and then + // return "base" random bits. The effect is to pick a number in the + // range [0,2^max_log-1] with exponential bias towards smaller numbers. + uint32_t Skewed(int max_log) { + return Uniform(1 << Uniform(max_log + 1)); + } +}; + +} // namespace leveldb + +#endif // STORAGE_LEVELDB_UTIL_RANDOM_H_ diff --git a/ios/Pods/leveldb-library/util/status.cc b/ios/Pods/leveldb-library/util/status.cc new file mode 100644 index 000000000..a44f35b31 --- /dev/null +++ b/ios/Pods/leveldb-library/util/status.cc @@ -0,0 +1,75 @@ +// Copyright (c) 2011 The LevelDB Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. See the AUTHORS file for names of contributors. + +#include +#include "port/port.h" +#include "leveldb/status.h" + +namespace leveldb { + +const char* Status::CopyState(const char* state) { + uint32_t size; + memcpy(&size, state, sizeof(size)); + char* result = new char[size + 5]; + memcpy(result, state, size + 5); + return result; +} + +Status::Status(Code code, const Slice& msg, const Slice& msg2) { + assert(code != kOk); + const uint32_t len1 = msg.size(); + const uint32_t len2 = msg2.size(); + const uint32_t size = len1 + (len2 ? (2 + len2) : 0); + char* result = new char[size + 5]; + memcpy(result, &size, sizeof(size)); + result[4] = static_cast(code); + memcpy(result + 5, msg.data(), len1); + if (len2) { + result[5 + len1] = ':'; + result[6 + len1] = ' '; + memcpy(result + 7 + len1, msg2.data(), len2); + } + state_ = result; +} + +std::string Status::ToString() const { + if (state_ == NULL) { + return "OK"; + } else { + char tmp[30]; + const char* type; + switch (code()) { + case kOk: + type = "OK"; + break; + case kNotFound: + type = "NotFound: "; + break; + case kCorruption: + type = "Corruption: "; + break; + case kNotSupported: + type = "Not implemented: "; + break; + case kInvalidArgument: + type = "Invalid argument: "; + break; + case kIOError: + type = "IO error: "; + break; + default: + snprintf(tmp, sizeof(tmp), "Unknown code(%d): ", + static_cast(code())); + type = tmp; + break; + } + std::string result(type); + uint32_t length; + memcpy(&length, state_, sizeof(length)); + result.append(state_ + 5, length); + return result; + } +} + +} // namespace leveldb diff --git a/ios/Pods/leveldb-library/util/testharness.cc b/ios/Pods/leveldb-library/util/testharness.cc new file mode 100644 index 000000000..402fab34d --- /dev/null +++ b/ios/Pods/leveldb-library/util/testharness.cc @@ -0,0 +1,77 @@ +// Copyright (c) 2011 The LevelDB Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. See the AUTHORS file for names of contributors. + +#include "util/testharness.h" + +#include +#include +#include +#include + +namespace leveldb { +namespace test { + +namespace { +struct Test { + const char* base; + const char* name; + void (*func)(); +}; +std::vector* tests; +} + +bool RegisterTest(const char* base, const char* name, void (*func)()) { + if (tests == NULL) { + tests = new std::vector; + } + Test t; + t.base = base; + t.name = name; + t.func = func; + tests->push_back(t); + return true; +} + +int RunAllTests() { + const char* matcher = getenv("LEVELDB_TESTS"); + + int num = 0; + if (tests != NULL) { + for (size_t i = 0; i < tests->size(); i++) { + const Test& t = (*tests)[i]; + if (matcher != NULL) { + std::string name = t.base; + name.push_back('.'); + name.append(t.name); + if (strstr(name.c_str(), matcher) == NULL) { + continue; + } + } + fprintf(stderr, "==== Test %s.%s\n", t.base, t.name); + (*t.func)(); + ++num; + } + } + fprintf(stderr, "==== PASSED %d tests\n", num); + return 0; +} + +std::string TmpDir() { + std::string dir; + Status s = Env::Default()->GetTestDirectory(&dir); + ASSERT_TRUE(s.ok()) << s.ToString(); + return dir; +} + +int RandomSeed() { + const char* env = getenv("TEST_RANDOM_SEED"); + int result = (env != NULL ? atoi(env) : 301); + if (result <= 0) { + result = 301; + } + return result; +} + +} // namespace test +} // namespace leveldb diff --git a/ios/Pods/leveldb-library/util/testharness.h b/ios/Pods/leveldb-library/util/testharness.h new file mode 100644 index 000000000..da4fe68bb --- /dev/null +++ b/ios/Pods/leveldb-library/util/testharness.h @@ -0,0 +1,138 @@ +// Copyright (c) 2011 The LevelDB Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. See the AUTHORS file for names of contributors. + +#ifndef STORAGE_LEVELDB_UTIL_TESTHARNESS_H_ +#define STORAGE_LEVELDB_UTIL_TESTHARNESS_H_ + +#include +#include +#include +#include "leveldb/env.h" +#include "leveldb/slice.h" +#include "util/random.h" + +namespace leveldb { +namespace test { + +// Run some of the tests registered by the TEST() macro. If the +// environment variable "LEVELDB_TESTS" is not set, runs all tests. +// Otherwise, runs only the tests whose name contains the value of +// "LEVELDB_TESTS" as a substring. E.g., suppose the tests are: +// TEST(Foo, Hello) { ... } +// TEST(Foo, World) { ... } +// LEVELDB_TESTS=Hello will run the first test +// LEVELDB_TESTS=o will run both tests +// LEVELDB_TESTS=Junk will run no tests +// +// Returns 0 if all tests pass. +// Dies or returns a non-zero value if some test fails. +extern int RunAllTests(); + +// Return the directory to use for temporary storage. +extern std::string TmpDir(); + +// Return a randomization seed for this run. Typically returns the +// same number on repeated invocations of this binary, but automated +// runs may be able to vary the seed. +extern int RandomSeed(); + +// An instance of Tester is allocated to hold temporary state during +// the execution of an assertion. +class Tester { + private: + bool ok_; + const char* fname_; + int line_; + std::stringstream ss_; + + public: + Tester(const char* f, int l) + : ok_(true), fname_(f), line_(l) { + } + + ~Tester() { + if (!ok_) { + fprintf(stderr, "%s:%d:%s\n", fname_, line_, ss_.str().c_str()); + exit(1); + } + } + + Tester& Is(bool b, const char* msg) { + if (!b) { + ss_ << " Assertion failure " << msg; + ok_ = false; + } + return *this; + } + + Tester& IsOk(const Status& s) { + if (!s.ok()) { + ss_ << " " << s.ToString(); + ok_ = false; + } + return *this; + } + +#define BINARY_OP(name,op) \ + template \ + Tester& name(const X& x, const Y& y) { \ + if (! (x op y)) { \ + ss_ << " failed: " << x << (" " #op " ") << y; \ + ok_ = false; \ + } \ + return *this; \ + } + + BINARY_OP(IsEq, ==) + BINARY_OP(IsNe, !=) + BINARY_OP(IsGe, >=) + BINARY_OP(IsGt, >) + BINARY_OP(IsLe, <=) + BINARY_OP(IsLt, <) +#undef BINARY_OP + + // Attach the specified value to the error message if an error has occurred + template + Tester& operator<<(const V& value) { + if (!ok_) { + ss_ << " " << value; + } + return *this; + } +}; + +#define ASSERT_TRUE(c) ::leveldb::test::Tester(__FILE__, __LINE__).Is((c), #c) +#define ASSERT_OK(s) ::leveldb::test::Tester(__FILE__, __LINE__).IsOk((s)) +#define ASSERT_EQ(a,b) ::leveldb::test::Tester(__FILE__, __LINE__).IsEq((a),(b)) +#define ASSERT_NE(a,b) ::leveldb::test::Tester(__FILE__, __LINE__).IsNe((a),(b)) +#define ASSERT_GE(a,b) ::leveldb::test::Tester(__FILE__, __LINE__).IsGe((a),(b)) +#define ASSERT_GT(a,b) ::leveldb::test::Tester(__FILE__, __LINE__).IsGt((a),(b)) +#define ASSERT_LE(a,b) ::leveldb::test::Tester(__FILE__, __LINE__).IsLe((a),(b)) +#define ASSERT_LT(a,b) ::leveldb::test::Tester(__FILE__, __LINE__).IsLt((a),(b)) + +#define TCONCAT(a,b) TCONCAT1(a,b) +#define TCONCAT1(a,b) a##b + +#define TEST(base,name) \ +class TCONCAT(_Test_,name) : public base { \ + public: \ + void _Run(); \ + static void _RunIt() { \ + TCONCAT(_Test_,name) t; \ + t._Run(); \ + } \ +}; \ +bool TCONCAT(_Test_ignored_,name) = \ + ::leveldb::test::RegisterTest(#base, #name, &TCONCAT(_Test_,name)::_RunIt); \ +void TCONCAT(_Test_,name)::_Run() + +// Register the specified test. Typically not used directly, but +// invoked via the macro expansion of TEST. +extern bool RegisterTest(const char* base, const char* name, void (*func)()); + + +} // namespace test +} // namespace leveldb + +#endif // STORAGE_LEVELDB_UTIL_TESTHARNESS_H_ diff --git a/ios/Pods/leveldb-library/util/testutil.cc b/ios/Pods/leveldb-library/util/testutil.cc new file mode 100644 index 000000000..bee56bf75 --- /dev/null +++ b/ios/Pods/leveldb-library/util/testutil.cc @@ -0,0 +1,51 @@ +// Copyright (c) 2011 The LevelDB Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. See the AUTHORS file for names of contributors. + +#include "util/testutil.h" + +#include "util/random.h" + +namespace leveldb { +namespace test { + +Slice RandomString(Random* rnd, int len, std::string* dst) { + dst->resize(len); + for (int i = 0; i < len; i++) { + (*dst)[i] = static_cast(' ' + rnd->Uniform(95)); // ' ' .. '~' + } + return Slice(*dst); +} + +std::string RandomKey(Random* rnd, int len) { + // Make sure to generate a wide variety of characters so we + // test the boundary conditions for short-key optimizations. + static const char kTestChars[] = { + '\0', '\1', 'a', 'b', 'c', 'd', 'e', '\xfd', '\xfe', '\xff' + }; + std::string result; + for (int i = 0; i < len; i++) { + result += kTestChars[rnd->Uniform(sizeof(kTestChars))]; + } + return result; +} + + +extern Slice CompressibleString(Random* rnd, double compressed_fraction, + size_t len, std::string* dst) { + int raw = static_cast(len * compressed_fraction); + if (raw < 1) raw = 1; + std::string raw_data; + RandomString(rnd, raw, &raw_data); + + // Duplicate the random data until we have filled "len" bytes + dst->clear(); + while (dst->size() < len) { + dst->append(raw_data); + } + dst->resize(len); + return Slice(*dst); +} + +} // namespace test +} // namespace leveldb diff --git a/ios/Pods/leveldb-library/util/testutil.h b/ios/Pods/leveldb-library/util/testutil.h new file mode 100644 index 000000000..adad3fc1e --- /dev/null +++ b/ios/Pods/leveldb-library/util/testutil.h @@ -0,0 +1,53 @@ +// Copyright (c) 2011 The LevelDB Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. See the AUTHORS file for names of contributors. + +#ifndef STORAGE_LEVELDB_UTIL_TESTUTIL_H_ +#define STORAGE_LEVELDB_UTIL_TESTUTIL_H_ + +#include "leveldb/env.h" +#include "leveldb/slice.h" +#include "util/random.h" + +namespace leveldb { +namespace test { + +// Store in *dst a random string of length "len" and return a Slice that +// references the generated data. +extern Slice RandomString(Random* rnd, int len, std::string* dst); + +// Return a random key with the specified length that may contain interesting +// characters (e.g. \x00, \xff, etc.). +extern std::string RandomKey(Random* rnd, int len); + +// Store in *dst a string of length "len" that will compress to +// "N*compressed_fraction" bytes and return a Slice that references +// the generated data. +extern Slice CompressibleString(Random* rnd, double compressed_fraction, + size_t len, std::string* dst); + +// A wrapper that allows injection of errors. +class ErrorEnv : public EnvWrapper { + public: + bool writable_file_error_; + int num_writable_file_errors_; + + ErrorEnv() : EnvWrapper(Env::Default()), + writable_file_error_(false), + num_writable_file_errors_(0) { } + + virtual Status NewWritableFile(const std::string& fname, + WritableFile** result) { + if (writable_file_error_) { + ++num_writable_file_errors_; + *result = NULL; + return Status::IOError(fname, "fake error"); + } + return target()->NewWritableFile(fname, result); + } +}; + +} // namespace test +} // namespace leveldb + +#endif // STORAGE_LEVELDB_UTIL_TESTUTIL_H_ diff --git a/ios/TeamTalk-Info.plist b/ios/TeamTalk-Info.plist new file mode 100644 index 000000000..81d02fbdd --- /dev/null +++ b/ios/TeamTalk-Info.plist @@ -0,0 +1,54 @@ + + + + + CFBundleDevelopmentRegion + en + CFBundleDisplayName + ${PRODUCT_NAME} + CFBundleExecutable + ${EXECUTABLE_NAME} + CFBundleIcons + + CFBundleIcons~ipad + + CFBundleIdentifier + com.juangua.teamtalk + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + ${PRODUCT_NAME} + CFBundlePackageType + APPL + CFBundleShortVersionString + 1.2 + CFBundleSignature + ???? + CFBundleVersion + 1.0 + LSApplicationCategoryType + + LSRequiresIPhoneOS + + UIAppFonts + + FZLanTingHei-L-GBK.TTF + + UILaunchStoryboardName + Launch Screen + UIRequiredDeviceCapabilities + + armv7 + + UIStatusBarHidden + + UIStatusBarStyle + UIStatusBarStyleLightContent + UISupportedInterfaceOrientations + + UIInterfaceOrientationPortrait + + UIViewControllerBasedStatusBarAppearance + + + diff --git a/ios/TeamTalk.xcodeproj/project.pbxproj b/ios/TeamTalk.xcodeproj/project.pbxproj new file mode 100644 index 000000000..de6565a2e --- /dev/null +++ b/ios/TeamTalk.xcodeproj/project.pbxproj @@ -0,0 +1,2824 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 46; + objects = { + +/* Begin PBXBuildFile section */ + 4C0C0F0C1A314E060094CCD2 /* SessionModule.m in Sources */ = {isa = PBXBuildFile; fileRef = 4C0C0F0B1A314E060094CCD2 /* SessionModule.m */; }; + 4C12E7F51A77920A00F1DD54 /* Launch Screen.xib in Resources */ = {isa = PBXBuildFile; fileRef = 4C12E7F41A77920A00F1DD54 /* Launch Screen.xib */; }; + 4C1CEEC81A3581160015C355 /* GetMessageQueueAPI.m in Sources */ = {isa = PBXBuildFile; fileRef = 4C1CEEC71A3581160015C355 /* GetMessageQueueAPI.m */; }; + 4C1E441919961889005CB2DB /* DDReceiveMessageACKAPI.m in Sources */ = {isa = PBXBuildFile; fileRef = 4C1E441819961889005CB2DB /* DDReceiveMessageACKAPI.m */; }; + 4C21749719C197F3006F4BFC /* DDUserDetailInfoAPI.m in Sources */ = {isa = PBXBuildFile; fileRef = 4C21749619C197F3006F4BFC /* DDUserDetailInfoAPI.m */; }; + 4C31EB5619CAB471004A3B2C /* GetGroupInfoAPi.m in Sources */ = {isa = PBXBuildFile; fileRef = 4C31EB5519CAB471004A3B2C /* GetGroupInfoAPi.m */; }; + 4C39B7FE1974D6E4001B4AEF /* Images.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 4C39B7FD1974D6E4001B4AEF /* Images.xcassets */; }; + 4C39B8071974EF18001B4AEF /* MainViewControll.m in Sources */ = {isa = PBXBuildFile; fileRef = 4C39B8051974EF18001B4AEF /* MainViewControll.m */; }; + 4C39B8081974EF18001B4AEF /* MainViewControll.xib in Resources */ = {isa = PBXBuildFile; fileRef = 4C39B8061974EF18001B4AEF /* MainViewControll.xib */; }; + 4C39B80F1974F388001B4AEF /* MyProfileViewControll.m in Sources */ = {isa = PBXBuildFile; fileRef = 4C39B80D1974F388001B4AEF /* MyProfileViewControll.m */; }; + 4C39B8101974F388001B4AEF /* MyProfileViewControll.xib in Resources */ = {isa = PBXBuildFile; fileRef = 4C39B80E1974F388001B4AEF /* MyProfileViewControll.xib */; }; + 4C3A74CE1A8C84C9009400A2 /* 221.gif in Resources */ = {isa = PBXBuildFile; fileRef = 4C3A74A61A8C84C9009400A2 /* 221.gif */; }; + 4C3A74CF1A8C84C9009400A2 /* 221@2x.gif in Resources */ = {isa = PBXBuildFile; fileRef = 4C3A74A71A8C84C9009400A2 /* 221@2x.gif */; }; + 4C3A74D01A8C84C9009400A2 /* 222.gif in Resources */ = {isa = PBXBuildFile; fileRef = 4C3A74A81A8C84C9009400A2 /* 222.gif */; }; + 4C3A74D11A8C84C9009400A2 /* 222@2x.gif in Resources */ = {isa = PBXBuildFile; fileRef = 4C3A74A91A8C84C9009400A2 /* 222@2x.gif */; }; + 4C3A74D21A8C84C9009400A2 /* 223.gif in Resources */ = {isa = PBXBuildFile; fileRef = 4C3A74AA1A8C84C9009400A2 /* 223.gif */; }; + 4C3A74D31A8C84C9009400A2 /* 223@2x.gif in Resources */ = {isa = PBXBuildFile; fileRef = 4C3A74AB1A8C84C9009400A2 /* 223@2x.gif */; }; + 4C3A74D41A8C84C9009400A2 /* 224.gif in Resources */ = {isa = PBXBuildFile; fileRef = 4C3A74AC1A8C84C9009400A2 /* 224.gif */; }; + 4C3A74D51A8C84C9009400A2 /* 224@2x.gif in Resources */ = {isa = PBXBuildFile; fileRef = 4C3A74AD1A8C84C9009400A2 /* 224@2x.gif */; }; + 4C3A74D61A8C84C9009400A2 /* 225.gif in Resources */ = {isa = PBXBuildFile; fileRef = 4C3A74AE1A8C84C9009400A2 /* 225.gif */; }; + 4C3A74D71A8C84C9009400A2 /* 225@2x.gif in Resources */ = {isa = PBXBuildFile; fileRef = 4C3A74AF1A8C84C9009400A2 /* 225@2x.gif */; }; + 4C3A74D81A8C84C9009400A2 /* 226.gif in Resources */ = {isa = PBXBuildFile; fileRef = 4C3A74B01A8C84C9009400A2 /* 226.gif */; }; + 4C3A74D91A8C84C9009400A2 /* 226@2x.gif in Resources */ = {isa = PBXBuildFile; fileRef = 4C3A74B11A8C84C9009400A2 /* 226@2x.gif */; }; + 4C3A74DA1A8C84C9009400A2 /* 227.gif in Resources */ = {isa = PBXBuildFile; fileRef = 4C3A74B21A8C84C9009400A2 /* 227.gif */; }; + 4C3A74DB1A8C84C9009400A2 /* 227@2x.gif in Resources */ = {isa = PBXBuildFile; fileRef = 4C3A74B31A8C84C9009400A2 /* 227@2x.gif */; }; + 4C3A74DC1A8C84C9009400A2 /* 228.gif in Resources */ = {isa = PBXBuildFile; fileRef = 4C3A74B41A8C84C9009400A2 /* 228.gif */; }; + 4C3A74DD1A8C84C9009400A2 /* 228@2x.gif in Resources */ = {isa = PBXBuildFile; fileRef = 4C3A74B51A8C84C9009400A2 /* 228@2x.gif */; }; + 4C3A74DE1A8C84C9009400A2 /* 229.gif in Resources */ = {isa = PBXBuildFile; fileRef = 4C3A74B61A8C84C9009400A2 /* 229.gif */; }; + 4C3A74DF1A8C84C9009400A2 /* 229@2x.gif in Resources */ = {isa = PBXBuildFile; fileRef = 4C3A74B71A8C84C9009400A2 /* 229@2x.gif */; }; + 4C3A74E01A8C84C9009400A2 /* 230.gif in Resources */ = {isa = PBXBuildFile; fileRef = 4C3A74B81A8C84C9009400A2 /* 230.gif */; }; + 4C3A74E11A8C84C9009400A2 /* 230@2x.gif in Resources */ = {isa = PBXBuildFile; fileRef = 4C3A74B91A8C84C9009400A2 /* 230@2x.gif */; }; + 4C3A74E21A8C84C9009400A2 /* 231.gif in Resources */ = {isa = PBXBuildFile; fileRef = 4C3A74BA1A8C84C9009400A2 /* 231.gif */; }; + 4C3A74E31A8C84C9009400A2 /* 231@2x.gif in Resources */ = {isa = PBXBuildFile; fileRef = 4C3A74BB1A8C84C9009400A2 /* 231@2x.gif */; }; + 4C3A74E41A8C84C9009400A2 /* 232.gif in Resources */ = {isa = PBXBuildFile; fileRef = 4C3A74BC1A8C84C9009400A2 /* 232.gif */; }; + 4C3A74E51A8C84C9009400A2 /* 232@2x.gif in Resources */ = {isa = PBXBuildFile; fileRef = 4C3A74BD1A8C84C9009400A2 /* 232@2x.gif */; }; + 4C3A74E61A8C84C9009400A2 /* 233.gif in Resources */ = {isa = PBXBuildFile; fileRef = 4C3A74BE1A8C84C9009400A2 /* 233.gif */; }; + 4C3A74E71A8C84C9009400A2 /* 233@2x.gif in Resources */ = {isa = PBXBuildFile; fileRef = 4C3A74BF1A8C84C9009400A2 /* 233@2x.gif */; }; + 4C3A74E81A8C84C9009400A2 /* 234.gif in Resources */ = {isa = PBXBuildFile; fileRef = 4C3A74C01A8C84C9009400A2 /* 234.gif */; }; + 4C3A74E91A8C84C9009400A2 /* 234@2x.gif in Resources */ = {isa = PBXBuildFile; fileRef = 4C3A74C11A8C84C9009400A2 /* 234@2x.gif */; }; + 4C3A74EA1A8C84C9009400A2 /* 235.gif in Resources */ = {isa = PBXBuildFile; fileRef = 4C3A74C21A8C84C9009400A2 /* 235.gif */; }; + 4C3A74EB1A8C84C9009400A2 /* 235@2x.gif in Resources */ = {isa = PBXBuildFile; fileRef = 4C3A74C31A8C84C9009400A2 /* 235@2x.gif */; }; + 4C3A74EC1A8C84C9009400A2 /* 236.gif in Resources */ = {isa = PBXBuildFile; fileRef = 4C3A74C41A8C84C9009400A2 /* 236.gif */; }; + 4C3A74ED1A8C84C9009400A2 /* 236@2x.gif in Resources */ = {isa = PBXBuildFile; fileRef = 4C3A74C51A8C84C9009400A2 /* 236@2x.gif */; }; + 4C3A74EE1A8C84C9009400A2 /* 237.gif in Resources */ = {isa = PBXBuildFile; fileRef = 4C3A74C61A8C84C9009400A2 /* 237.gif */; }; + 4C3A74EF1A8C84C9009400A2 /* 237@2x.gif in Resources */ = {isa = PBXBuildFile; fileRef = 4C3A74C71A8C84C9009400A2 /* 237@2x.gif */; }; + 4C3A74F01A8C84C9009400A2 /* 238.gif in Resources */ = {isa = PBXBuildFile; fileRef = 4C3A74C81A8C84C9009400A2 /* 238.gif */; }; + 4C3A74F11A8C84C9009400A2 /* 238@2x.gif in Resources */ = {isa = PBXBuildFile; fileRef = 4C3A74C91A8C84C9009400A2 /* 238@2x.gif */; }; + 4C3A74F21A8C84C9009400A2 /* 239.gif in Resources */ = {isa = PBXBuildFile; fileRef = 4C3A74CA1A8C84C9009400A2 /* 239.gif */; }; + 4C3A74F31A8C84C9009400A2 /* 239@2x.gif in Resources */ = {isa = PBXBuildFile; fileRef = 4C3A74CB1A8C84C9009400A2 /* 239@2x.gif */; }; + 4C3A74F41A8C84C9009400A2 /* 240.gif in Resources */ = {isa = PBXBuildFile; fileRef = 4C3A74CC1A8C84C9009400A2 /* 240.gif */; }; + 4C3A74F51A8C84C9009400A2 /* 240@2x.gif in Resources */ = {isa = PBXBuildFile; fileRef = 4C3A74CD1A8C84C9009400A2 /* 240@2x.gif */; }; + 4C3A74F81A8C84F7009400A2 /* delImage.png in Resources */ = {isa = PBXBuildFile; fileRef = 4C3A74F61A8C84F7009400A2 /* delImage.png */; }; + 4C3A74F91A8C84F7009400A2 /* delImage@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = 4C3A74F71A8C84F7009400A2 /* delImage@2x.png */; }; + 4C3A74FF1A8C8577009400A2 /* Sequencer.m in Sources */ = {isa = PBXBuildFile; fileRef = 4C3A74FE1A8C8577009400A2 /* Sequencer.m */; }; + 4C3A75041A8C85C1009400A2 /* DBHelper.mm in Sources */ = {isa = PBXBuildFile; fileRef = 4C3A75011A8C85C1009400A2 /* DBHelper.mm */; }; + 4C3A75051A8C85C1009400A2 /* DBManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 4C3A75031A8C85C1009400A2 /* DBManager.m */; }; + 4C3A75081A8C860F009400A2 /* RootViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 4C3A75071A8C860F009400A2 /* RootViewController.m */; }; + 4C3A750C1A8C861E009400A2 /* RuntimeStatus.m in Sources */ = {isa = PBXBuildFile; fileRef = 4C3A750B1A8C861E009400A2 /* RuntimeStatus.m */; }; + 4C3A750F1A8C8650009400A2 /* TTHttpsRequest.m in Sources */ = {isa = PBXBuildFile; fileRef = 4C3A750E1A8C8650009400A2 /* TTHttpsRequest.m */; }; + 4C3A75121A8C865A009400A2 /* DDAppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = 4C3A75111A8C865A009400A2 /* DDAppDelegate.m */; }; + 4C4657BD19EF5DC300334DD2 /* UnAckMessageManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 4C4657BC19EF5DC300334DD2 /* UnAckMessageManager.m */; }; + 4C5486CF1A70EA8000ED8735 /* DDEmotionCell.m in Sources */ = {isa = PBXBuildFile; fileRef = 4C5486CE1A70EA8000ED8735 /* DDEmotionCell.m */; }; + 4C5CA06019C13341007CE792 /* DDDeleteMemberFromGroupAPI.m in Sources */ = {isa = PBXBuildFile; fileRef = 4C5CA05F19C13341007CE792 /* DDDeleteMemberFromGroupAPI.m */; }; + 4C5CC9B81A38221C0067B124 /* RemoveSessionAPI.m in Sources */ = {isa = PBXBuildFile; fileRef = 4C5CC9B71A38221C0067B124 /* RemoveSessionAPI.m */; }; + 4C5D70571990C1AE009AF959 /* DDDepartmentAPI.m in Sources */ = {isa = PBXBuildFile; fileRef = 4C5D70561990C1AE009AF959 /* DDDepartmentAPI.m */; }; + 4C5E374419D408CE00D1042B /* GroupAvatarImage.m in Sources */ = {isa = PBXBuildFile; fileRef = 4C5E374319D408CE00D1042B /* GroupAvatarImage.m */; }; + 4C5F3F291A2EE29D003684B2 /* GetRecentSession.mm in Sources */ = {isa = PBXBuildFile; fileRef = 4C5F3F281A2EE29D003684B2 /* GetRecentSession.mm */; }; + 4C6BBC191A7B8DD40028B892 /* UIImage+UIImageAddition.m in Sources */ = {isa = PBXBuildFile; fileRef = 4C6BBC181A7B8DD40028B892 /* UIImage+UIImageAddition.m */; }; + 4C77C2911A8852F8001E5885 /* ScanQRCodePage.m in Sources */ = {isa = PBXBuildFile; fileRef = 4C77C28F1A8852F8001E5885 /* ScanQRCodePage.m */; }; + 4C77C2921A8852F8001E5885 /* ScanQRCodePage.xib in Resources */ = {isa = PBXBuildFile; fileRef = 4C77C2901A8852F8001E5885 /* ScanQRCodePage.xib */; }; + 4C77C2951A88CFEC001E5885 /* BlurView.m in Sources */ = {isa = PBXBuildFile; fileRef = 4C77C2941A88CFEC001E5885 /* BlurView.m */; }; + 4C79D2B31AB7C19200706E32 /* GetDepartment.m in Sources */ = {isa = PBXBuildFile; fileRef = 4C79D2B21AB7C19200706E32 /* GetDepartment.m */; }; + 4C79D2C01AB7C9A500706E32 /* IMBaseDefine.pb.m in Sources */ = {isa = PBXBuildFile; fileRef = 4C79D2B51AB7C9A500706E32 /* IMBaseDefine.pb.m */; }; + 4C79D2C11AB7C9A500706E32 /* IMBuddy.pb.m in Sources */ = {isa = PBXBuildFile; fileRef = 4C79D2B71AB7C9A500706E32 /* IMBuddy.pb.m */; }; + 4C79D2C21AB7C9A500706E32 /* IMGroup.pb.m in Sources */ = {isa = PBXBuildFile; fileRef = 4C79D2B91AB7C9A500706E32 /* IMGroup.pb.m */; }; + 4C79D2C31AB7C9A500706E32 /* IMLogin.pb.m in Sources */ = {isa = PBXBuildFile; fileRef = 4C79D2BB1AB7C9A500706E32 /* IMLogin.pb.m */; }; + 4C79D2C41AB7C9A500706E32 /* IMMessage.pb.m in Sources */ = {isa = PBXBuildFile; fileRef = 4C79D2BD1AB7C9A500706E32 /* IMMessage.pb.m */; }; + 4C79D2C51AB7C9A500706E32 /* IMOther.pb.m in Sources */ = {isa = PBXBuildFile; fileRef = 4C79D2BF1AB7C9A500706E32 /* IMOther.pb.m */; }; + 4C837EE9197F949300C3D758 /* DDAllUserAPI.m in Sources */ = {isa = PBXBuildFile; fileRef = 4C837EE8197F949300C3D758 /* DDAllUserAPI.m */; }; + 4C837F38197F94F400C3D758 /* ContactsModule.m in Sources */ = {isa = PBXBuildFile; fileRef = 4C837F32197F94F400C3D758 /* ContactsModule.m */; }; + 4C837F3A197F94F400C3D758 /* PublicProfileViewControll.m in Sources */ = {isa = PBXBuildFile; fileRef = 4C837F36197F94F400C3D758 /* PublicProfileViewControll.m */; }; + 4C837F3B197F94F400C3D758 /* PublicProfileViewControll.xib in Resources */ = {isa = PBXBuildFile; fileRef = 4C837F37197F94F400C3D758 /* PublicProfileViewControll.xib */; }; + 4C837F3F197F951600C3D758 /* DDChattingEditViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 4C837F3D197F951600C3D758 /* DDChattingEditViewController.m */; }; + 4C837F40197F951600C3D758 /* DDChattingEditViewController.xib in Resources */ = {isa = PBXBuildFile; fileRef = 4C837F3E197F951600C3D758 /* DDChattingEditViewController.xib */; }; + 4C837F43197F952800C3D758 /* ChattingEditModule.m in Sources */ = {isa = PBXBuildFile; fileRef = 4C837F42197F952800C3D758 /* ChattingEditModule.m */; }; + 4C837F46197F954500C3D758 /* DDCreateGroupAPI.m in Sources */ = {isa = PBXBuildFile; fileRef = 4C837F45197F954500C3D758 /* DDCreateGroupAPI.m */; }; + 4C837F49197F95A400C3D758 /* GroupEntity.m in Sources */ = {isa = PBXBuildFile; fileRef = 4C837F48197F95A400C3D758 /* GroupEntity.m */; }; + 4C837F4C197F95FF00C3D758 /* ContactsViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 4C837F4B197F95FF00C3D758 /* ContactsViewController.m */; }; + 4C88A0C519D50FFA0071DA9C /* libz.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = 4C88A0C419D50FFA0071DA9C /* libz.dylib */; }; + 4C92734819EB9C8200F6C370 /* NetwrokStatusNotifyUI.m in Sources */ = {isa = PBXBuildFile; fileRef = 4C92734719EB9C8200F6C370 /* NetwrokStatusNotifyUI.m */; }; + 4C92D7CD1ABA67EC00709CC6 /* libsecurity.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 4C92D7CC1ABA67EC00709CC6 /* libsecurity.a */; }; + 4C98355419C06F6D00DE8874 /* EditContactsCell.m in Sources */ = {isa = PBXBuildFile; fileRef = 4C98355319C06F6D00DE8874 /* EditContactsCell.m */; }; + 4CA0BA011A5C0E2800102EC7 /* NSData+Conversion.m in Sources */ = {isa = PBXBuildFile; fileRef = 4CA0BA001A5C0E2800102EC7 /* NSData+Conversion.m */; }; + 4CA50CC919A435E20032DE24 /* DDPersonEditCollectionCell.m in Sources */ = {isa = PBXBuildFile; fileRef = 4CA50CC819A435E20032DE24 /* DDPersonEditCollectionCell.m */; }; + 4CA50CCD19A47B9A0032DE24 /* SpellLibrary.m in Sources */ = {isa = PBXBuildFile; fileRef = 4CA50CCC19A47B9A0032DE24 /* SpellLibrary.m */; }; + 4CA50CD019A47C690032DE24 /* DDSearch.m in Sources */ = {isa = PBXBuildFile; fileRef = 4CA50CCF19A47C690032DE24 /* DDSearch.m */; }; + 4CA6CE111A2C1F6E00405BB6 /* add.png in Resources */ = {isa = PBXBuildFile; fileRef = 4CA6CDA91A2C1F6E00405BB6 /* add.png */; }; + 4CA6CE121A2C1F6E00405BB6 /* add@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = 4CA6CDAA1A2C1F6E00405BB6 /* add@2x.png */; }; + 4CA6CE131A2C1F6E00405BB6 /* chat.png in Resources */ = {isa = PBXBuildFile; fileRef = 4CA6CDAB1A2C1F6E00405BB6 /* chat.png */; }; + 4CA6CE141A2C1F6E00405BB6 /* chat@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = 4CA6CDAC1A2C1F6E00405BB6 /* chat@2x.png */; }; + 4CA6CE151A2C1F6E00405BB6 /* contact_selected.png in Resources */ = {isa = PBXBuildFile; fileRef = 4CA6CDAD1A2C1F6E00405BB6 /* contact_selected.png */; }; + 4CA6CE161A2C1F6E00405BB6 /* contact_selected@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = 4CA6CDAE1A2C1F6E00405BB6 /* contact_selected@2x.png */; }; + 4CA6CE171A2C1F6E00405BB6 /* contact.png in Resources */ = {isa = PBXBuildFile; fileRef = 4CA6CDAF1A2C1F6E00405BB6 /* contact.png */; }; + 4CA6CE181A2C1F6E00405BB6 /* contact@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = 4CA6CDB01A2C1F6E00405BB6 /* contact@2x.png */; }; + 4CA6CE191A2C1F6E00405BB6 /* conversation_selected.png in Resources */ = {isa = PBXBuildFile; fileRef = 4CA6CDB11A2C1F6E00405BB6 /* conversation_selected.png */; }; + 4CA6CE1A1A2C1F6E00405BB6 /* conversation_selected@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = 4CA6CDB21A2C1F6E00405BB6 /* conversation_selected@2x.png */; }; + 4CA6CE1B1A2C1F6E00405BB6 /* conversation.png in Resources */ = {isa = PBXBuildFile; fileRef = 4CA6CDB31A2C1F6E00405BB6 /* conversation.png */; }; + 4CA6CE1C1A2C1F6E00405BB6 /* conversation@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = 4CA6CDB41A2C1F6E00405BB6 /* conversation@2x.png */; }; + 4CA6CE1D1A2C1F6E00405BB6 /* dd_album.png in Resources */ = {isa = PBXBuildFile; fileRef = 4CA6CDB51A2C1F6E00405BB6 /* dd_album.png */; }; + 4CA6CE1E1A2C1F6E00405BB6 /* dd_album@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = 4CA6CDB61A2C1F6E00405BB6 /* dd_album@2x.png */; }; + 4CA6CE1F1A2C1F6E00405BB6 /* dd_cancel_send_record.png in Resources */ = {isa = PBXBuildFile; fileRef = 4CA6CDB71A2C1F6E00405BB6 /* dd_cancel_send_record.png */; }; + 4CA6CE201A2C1F6E00405BB6 /* dd_cancel_send_record@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = 4CA6CDB81A2C1F6E00405BB6 /* dd_cancel_send_record@2x.png */; }; + 4CA6CE211A2C1F6E00405BB6 /* dd_emoji_delete.png in Resources */ = {isa = PBXBuildFile; fileRef = 4CA6CDB91A2C1F6E00405BB6 /* dd_emoji_delete.png */; }; + 4CA6CE221A2C1F6E00405BB6 /* dd_emoji_delete@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = 4CA6CDBA1A2C1F6E00405BB6 /* dd_emoji_delete@2x.png */; }; + 4CA6CE231A2C1F6E00405BB6 /* dd_emotion.png in Resources */ = {isa = PBXBuildFile; fileRef = 4CA6CDBB1A2C1F6E00405BB6 /* dd_emotion.png */; }; + 4CA6CE241A2C1F6E00405BB6 /* dd_emotion@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = 4CA6CDBC1A2C1F6E00405BB6 /* dd_emotion@2x.png */; }; + 4CA6CE251A2C1F6E00405BB6 /* dd_has_unread_message.png in Resources */ = {isa = PBXBuildFile; fileRef = 4CA6CDBD1A2C1F6E00405BB6 /* dd_has_unread_message.png */; }; + 4CA6CE261A2C1F6E00405BB6 /* dd_has_unread_message@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = 4CA6CDBE1A2C1F6E00405BB6 /* dd_has_unread_message@2x.png */; }; + 4CA6CE271A2C1F6E00405BB6 /* dd_image_send.png in Resources */ = {isa = PBXBuildFile; fileRef = 4CA6CDBF1A2C1F6E00405BB6 /* dd_image_send.png */; }; + 4CA6CE281A2C1F6E00405BB6 /* dd_image_send@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = 4CA6CDC01A2C1F6E00405BB6 /* dd_image_send@2x.png */; }; + 4CA6CE291A2C1F6E00405BB6 /* dd_input_normal.png in Resources */ = {isa = PBXBuildFile; fileRef = 4CA6CDC11A2C1F6E00405BB6 /* dd_input_normal.png */; }; + 4CA6CE2A1A2C1F6E00405BB6 /* dd_input_normal@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = 4CA6CDC21A2C1F6E00405BB6 /* dd_input_normal@2x.png */; }; + 4CA6CE2B1A2C1F6E00405BB6 /* dd_left_voice_one.png in Resources */ = {isa = PBXBuildFile; fileRef = 4CA6CDC31A2C1F6E00405BB6 /* dd_left_voice_one.png */; }; + 4CA6CE2C1A2C1F6E00405BB6 /* dd_left_voice_one@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = 4CA6CDC41A2C1F6E00405BB6 /* dd_left_voice_one@2x.png */; }; + 4CA6CE2D1A2C1F6E00405BB6 /* dd_left_voice_three.png in Resources */ = {isa = PBXBuildFile; fileRef = 4CA6CDC51A2C1F6E00405BB6 /* dd_left_voice_three.png */; }; + 4CA6CE2E1A2C1F6E00405BB6 /* dd_left_voice_three@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = 4CA6CDC61A2C1F6E00405BB6 /* dd_left_voice_three@2x.png */; }; + 4CA6CE2F1A2C1F6E00405BB6 /* dd_left_voice_two.png in Resources */ = {isa = PBXBuildFile; fileRef = 4CA6CDC71A2C1F6E00405BB6 /* dd_left_voice_two.png */; }; + 4CA6CE301A2C1F6E00405BB6 /* dd_left_voice_two@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = 4CA6CDC81A2C1F6E00405BB6 /* dd_left_voice_two@2x.png */; }; + 4CA6CE311A2C1F6E00405BB6 /* dd_photo_back.png in Resources */ = {isa = PBXBuildFile; fileRef = 4CA6CDC91A2C1F6E00405BB6 /* dd_photo_back.png */; }; + 4CA6CE321A2C1F6E00405BB6 /* dd_photo_back@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = 4CA6CDCA1A2C1F6E00405BB6 /* dd_photo_back@2x.png */; }; + 4CA6CE331A2C1F6E00405BB6 /* dd_press_to_say_normal.png in Resources */ = {isa = PBXBuildFile; fileRef = 4CA6CDCB1A2C1F6E00405BB6 /* dd_press_to_say_normal.png */; }; + 4CA6CE341A2C1F6E00405BB6 /* dd_press_to_say_normal@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = 4CA6CDCC1A2C1F6E00405BB6 /* dd_press_to_say_normal@2x.png */; }; + 4CA6CE351A2C1F6E00405BB6 /* dd_preview_select.png in Resources */ = {isa = PBXBuildFile; fileRef = 4CA6CDCD1A2C1F6E00405BB6 /* dd_preview_select.png */; }; + 4CA6CE361A2C1F6E00405BB6 /* dd_preview_select@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = 4CA6CDCE1A2C1F6E00405BB6 /* dd_preview_select@2x.png */; }; + 4CA6CE381A2C1F6E00405BB6 /* dd_recent_contacts.png in Resources */ = {isa = PBXBuildFile; fileRef = 4CA6CDD01A2C1F6E00405BB6 /* dd_recent_contacts.png */; }; + 4CA6CE391A2C1F6E00405BB6 /* dd_recent_contacts@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = 4CA6CDD11A2C1F6E00405BB6 /* dd_recent_contacts@2x.png */; }; + 4CA6CE3A1A2C1F6E00405BB6 /* dd_record_normal.png in Resources */ = {isa = PBXBuildFile; fileRef = 4CA6CDD21A2C1F6E00405BB6 /* dd_record_normal.png */; }; + 4CA6CE3B1A2C1F6E00405BB6 /* dd_record_normal@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = 4CA6CDD31A2C1F6E00405BB6 /* dd_record_normal@2x.png */; }; + 4CA6CE3C1A2C1F6E00405BB6 /* dd_record_release_end.png in Resources */ = {isa = PBXBuildFile; fileRef = 4CA6CDD41A2C1F6E00405BB6 /* dd_record_release_end.png */; }; + 4CA6CE3D1A2C1F6E00405BB6 /* dd_record_release_end@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = 4CA6CDD51A2C1F6E00405BB6 /* dd_record_release_end@2x.png */; }; + 4CA6CE3E1A2C1F6E00405BB6 /* dd_record_too_short.png in Resources */ = {isa = PBXBuildFile; fileRef = 4CA6CDD61A2C1F6E00405BB6 /* dd_record_too_short.png */; }; + 4CA6CE3F1A2C1F6E00405BB6 /* dd_record_too_short@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = 4CA6CDD71A2C1F6E00405BB6 /* dd_record_too_short@2x.png */; }; + 4CA6CE401A2C1F6E00405BB6 /* dd_recording.png in Resources */ = {isa = PBXBuildFile; fileRef = 4CA6CDD81A2C1F6E00405BB6 /* dd_recording.png */; }; + 4CA6CE411A2C1F6E00405BB6 /* dd_recording@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = 4CA6CDD91A2C1F6E00405BB6 /* dd_recording@2x.png */; }; + 4CA6CE421A2C1F6E00405BB6 /* dd_right_voice_one.png in Resources */ = {isa = PBXBuildFile; fileRef = 4CA6CDDA1A2C1F6E00405BB6 /* dd_right_voice_one.png */; }; + 4CA6CE431A2C1F6E00405BB6 /* dd_right_voice_one@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = 4CA6CDDB1A2C1F6E00405BB6 /* dd_right_voice_one@2x.png */; }; + 4CA6CE441A2C1F6E00405BB6 /* dd_right_voice_three.png in Resources */ = {isa = PBXBuildFile; fileRef = 4CA6CDDC1A2C1F6E00405BB6 /* dd_right_voice_three.png */; }; + 4CA6CE451A2C1F6E00405BB6 /* dd_right_voice_three@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = 4CA6CDDD1A2C1F6E00405BB6 /* dd_right_voice_three@2x.png */; }; + 4CA6CE461A2C1F6E00405BB6 /* dd_right_voice_two.png in Resources */ = {isa = PBXBuildFile; fileRef = 4CA6CDDE1A2C1F6E00405BB6 /* dd_right_voice_two.png */; }; + 4CA6CE471A2C1F6E00405BB6 /* dd_right_voice_two@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = 4CA6CDDF1A2C1F6E00405BB6 /* dd_right_voice_two@2x.png */; }; + 4CA6CE481A2C1F6E00405BB6 /* dd_selected_photo.png in Resources */ = {isa = PBXBuildFile; fileRef = 4CA6CDE01A2C1F6E00405BB6 /* dd_selected_photo.png */; }; + 4CA6CE491A2C1F6E00405BB6 /* dd_selected_photo@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = 4CA6CDE11A2C1F6E00405BB6 /* dd_selected_photo@2x.png */; }; + 4CA6CE4A1A2C1F6E00405BB6 /* dd_send_failed.png in Resources */ = {isa = PBXBuildFile; fileRef = 4CA6CDE21A2C1F6E00405BB6 /* dd_send_failed.png */; }; + 4CA6CE4B1A2C1F6E00405BB6 /* dd_send_failed@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = 4CA6CDE31A2C1F6E00405BB6 /* dd_send_failed@2x.png */; }; + 4CA6CE4C1A2C1F6E00405BB6 /* dd_take-photo.png in Resources */ = {isa = PBXBuildFile; fileRef = 4CA6CDE41A2C1F6E00405BB6 /* dd_take-photo.png */; }; + 4CA6CE4D1A2C1F6E00405BB6 /* dd_take-photo@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = 4CA6CDE51A2C1F6E00405BB6 /* dd_take-photo@2x.png */; }; + 4CA6CE4E1A2C1F6E00405BB6 /* dd_utility.png in Resources */ = {isa = PBXBuildFile; fileRef = 4CA6CDE61A2C1F6E00405BB6 /* dd_utility.png */; }; + 4CA6CE4F1A2C1F6E00405BB6 /* dd_utility@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = 4CA6CDE71A2C1F6E00405BB6 /* dd_utility@2x.png */; }; + 4CA6CE501A2C1F6E00405BB6 /* dd_volumn.png in Resources */ = {isa = PBXBuildFile; fileRef = 4CA6CDE81A2C1F6E00405BB6 /* dd_volumn.png */; }; + 4CA6CE511A2C1F6E00405BB6 /* dd_volumn@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = 4CA6CDE91A2C1F6E00405BB6 /* dd_volumn@2x.png */; }; + 4CA6CE521A2C1F6E00405BB6 /* delete.png in Resources */ = {isa = PBXBuildFile; fileRef = 4CA6CDEA1A2C1F6E00405BB6 /* delete.png */; }; + 4CA6CE531A2C1F6F00405BB6 /* delete@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = 4CA6CDEB1A2C1F6E00405BB6 /* delete@2x.png */; }; + 4CA6CE541A2C1F6F00405BB6 /* edit.png in Resources */ = {isa = PBXBuildFile; fileRef = 4CA6CDEC1A2C1F6E00405BB6 /* edit.png */; }; + 4CA6CE551A2C1F6F00405BB6 /* edit@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = 4CA6CDED1A2C1F6E00405BB6 /* edit@2x.png */; }; + 4CA6CE561A2C1F6F00405BB6 /* email.png in Resources */ = {isa = PBXBuildFile; fileRef = 4CA6CDEE1A2C1F6E00405BB6 /* email.png */; }; + 4CA6CE571A2C1F6F00405BB6 /* email@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = 4CA6CDEF1A2C1F6E00405BB6 /* email@2x.png */; }; + 4CA6CE581A2C1F6F00405BB6 /* group_default.png in Resources */ = {isa = PBXBuildFile; fileRef = 4CA6CDF01A2C1F6E00405BB6 /* group_default.png */; }; + 4CA6CE591A2C1F6F00405BB6 /* group_default@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = 4CA6CDF11A2C1F6E00405BB6 /* group_default@2x.png */; }; + 4CA6CE5A1A2C1F6F00405BB6 /* jiantou.png in Resources */ = {isa = PBXBuildFile; fileRef = 4CA6CDF21A2C1F6E00405BB6 /* jiantou.png */; }; + 4CA6CE5B1A2C1F6F00405BB6 /* jiantou@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = 4CA6CDF31A2C1F6E00405BB6 /* jiantou@2x.png */; }; + 4CA6CE5F1A2C1F6F00405BB6 /* loginlogo.jpg in Resources */ = {isa = PBXBuildFile; fileRef = 4CA6CDF71A2C1F6E00405BB6 /* loginlogo.jpg */; }; + 4CA6CE601A2C1F6F00405BB6 /* loginlogo.png in Resources */ = {isa = PBXBuildFile; fileRef = 4CA6CDF81A2C1F6E00405BB6 /* loginlogo.png */; }; + 4CA6CE611A2C1F6F00405BB6 /* msg.caf in Resources */ = {isa = PBXBuildFile; fileRef = 4CA6CDF91A2C1F6E00405BB6 /* msg.caf */; }; + 4CA6CE621A2C1F6F00405BB6 /* myprofile_selected.png in Resources */ = {isa = PBXBuildFile; fileRef = 4CA6CDFA1A2C1F6E00405BB6 /* myprofile_selected.png */; }; + 4CA6CE631A2C1F6F00405BB6 /* myprofile_selected@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = 4CA6CDFB1A2C1F6E00405BB6 /* myprofile_selected@2x.png */; }; + 4CA6CE641A2C1F6F00405BB6 /* myprofile.png in Resources */ = {isa = PBXBuildFile; fileRef = 4CA6CDFC1A2C1F6E00405BB6 /* myprofile.png */; }; + 4CA6CE651A2C1F6F00405BB6 /* myprofile@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = 4CA6CDFD1A2C1F6E00405BB6 /* myprofile@2x.png */; }; + 4CA6CE661A2C1F6F00405BB6 /* password.png in Resources */ = {isa = PBXBuildFile; fileRef = 4CA6CDFE1A2C1F6E00405BB6 /* password.png */; }; + 4CA6CE671A2C1F6F00405BB6 /* password@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = 4CA6CDFF1A2C1F6E00405BB6 /* password@2x.png */; }; + 4CA6CE6A1A2C1F6F00405BB6 /* select.png in Resources */ = {isa = PBXBuildFile; fileRef = 4CA6CE021A2C1F6E00405BB6 /* select.png */; }; + 4CA6CE6B1A2C1F6F00405BB6 /* select@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = 4CA6CE031A2C1F6E00405BB6 /* select@2x.png */; }; + 4CA6CE6C1A2C1F6F00405BB6 /* setting.png in Resources */ = {isa = PBXBuildFile; fileRef = 4CA6CE041A2C1F6E00405BB6 /* setting.png */; }; + 4CA6CE6D1A2C1F6F00405BB6 /* setting@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = 4CA6CE051A2C1F6E00405BB6 /* setting@2x.png */; }; + 4CA6CE6E1A2C1F6F00405BB6 /* star.png in Resources */ = {isa = PBXBuildFile; fileRef = 4CA6CE061A2C1F6E00405BB6 /* star.png */; }; + 4CA6CE6F1A2C1F6F00405BB6 /* star@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = 4CA6CE071A2C1F6E00405BB6 /* star@2x.png */; }; + 4CA6CE701A2C1F6F00405BB6 /* TeamTalk.xcworkspace in Resources */ = {isa = PBXBuildFile; fileRef = 4CA6CE081A2C1F6E00405BB6 /* TeamTalk.xcworkspace */; }; + 4CA6CE711A2C1F6F00405BB6 /* tel.png in Resources */ = {isa = PBXBuildFile; fileRef = 4CA6CE091A2C1F6E00405BB6 /* tel.png */; }; + 4CA6CE721A2C1F6F00405BB6 /* tel@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = 4CA6CE0A1A2C1F6E00405BB6 /* tel@2x.png */; }; + 4CA6CE731A2C1F6F00405BB6 /* unselected.png in Resources */ = {isa = PBXBuildFile; fileRef = 4CA6CE0B1A2C1F6E00405BB6 /* unselected.png */; }; + 4CA6CE741A2C1F6F00405BB6 /* unselected@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = 4CA6CE0C1A2C1F6E00405BB6 /* unselected@2x.png */; }; + 4CA6CE751A2C1F6F00405BB6 /* username.png in Resources */ = {isa = PBXBuildFile; fileRef = 4CA6CE0D1A2C1F6E00405BB6 /* username.png */; }; + 4CA6CE761A2C1F6F00405BB6 /* username@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = 4CA6CE0E1A2C1F6E00405BB6 /* username@2x.png */; }; + 4CA6CE771A2C1F6F00405BB6 /* x.png in Resources */ = {isa = PBXBuildFile; fileRef = 4CA6CE0F1A2C1F6E00405BB6 /* x.png */; }; + 4CA6CE781A2C1F6F00405BB6 /* x@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = 4CA6CE101A2C1F6E00405BB6 /* x@2x.png */; }; + 4CA6CE7B1A2C1FA700405BB6 /* LoginViewController.h in Sources */ = {isa = PBXBuildFile; fileRef = 4CA6CE791A2C1FA700405BB6 /* LoginViewController.h */; }; + 4CA6CE7C1A2C1FA700405BB6 /* LoginViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 4CA6CE7A1A2C1FA700405BB6 /* LoginViewController.m */; }; + 4CA6CE7E1A2C1FBA00405BB6 /* LoginViewController.xib in Resources */ = {isa = PBXBuildFile; fileRef = 4CA6CE7D1A2C1FBA00405BB6 /* LoginViewController.xib */; }; + 4CB23CAB19B457AD004FCF10 /* EditGroupViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 4CB23CA919B457AD004FCF10 /* EditGroupViewController.m */; }; + 4CB23CAC19B457AD004FCF10 /* EditGroupViewController.xib in Resources */ = {isa = PBXBuildFile; fileRef = 4CB23CAA19B457AD004FCF10 /* EditGroupViewController.xib */; }; + 4CB23CAF19B4590D004FCF10 /* EditGroupViewCell.m in Sources */ = {isa = PBXBuildFile; fileRef = 4CB23CAE19B4590D004FCF10 /* EditGroupViewCell.m */; }; + 4CB3D91A19F4A22800DC9B9D /* ShieldGroupMessageAPI.m in Sources */ = {isa = PBXBuildFile; fileRef = 4CB3D91919F4A22800DC9B9D /* ShieldGroupMessageAPI.m */; }; + 4CB3D91D19F4B48200DC9B9D /* LogoutAPI.m in Sources */ = {isa = PBXBuildFile; fileRef = 4CB3D91C19F4B48200DC9B9D /* LogoutAPI.m */; }; + 4CB3D92119F4FA7F00DC9B9D /* SearchContentViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 4CB3D91F19F4FA7F00DC9B9D /* SearchContentViewController.m */; }; + 4CB58EAC1991FF98006B24D3 /* DDepartment.m in Sources */ = {isa = PBXBuildFile; fileRef = 4CB58EAB1991FF98006B24D3 /* DDepartment.m */; }; + 4CB6AA0D198F7F550075BDB4 /* ChatEditTableViewCell.m in Sources */ = {isa = PBXBuildFile; fileRef = 4CB6AA0C198F7F550075BDB4 /* ChatEditTableViewCell.m */; }; + 4CB8F6D319A7171800C4C27D /* DDContactsCell.m in Sources */ = {isa = PBXBuildFile; fileRef = 4CB8F6D219A7171800C4C27D /* DDContactsCell.m */; }; + 4CC35AA91A83097200E6224D /* GetLatestMsgId.m in Sources */ = {isa = PBXBuildFile; fileRef = 4CC35AA81A83097200E6224D /* GetLatestMsgId.m */; }; + 4CC35AAC1A83585E00E6224D /* GetMsgByMsgIDsAPI.m in Sources */ = {isa = PBXBuildFile; fileRef = 4CC35AAB1A83585E00E6224D /* GetMsgByMsgIDsAPI.m */; }; + 4CC41F831A4D120600DE434F /* PublicProfileCell.m in Sources */ = {isa = PBXBuildFile; fileRef = 4CC41F821A4D120600DE434F /* PublicProfileCell.m */; }; + 4CD156681998A36300B11233 /* DDAddMemberToGroupAPI.m in Sources */ = {isa = PBXBuildFile; fileRef = 4CD156591998A36300B11233 /* DDAddMemberToGroupAPI.m */; }; + 4CD156691998A36300B11233 /* DDFixedGroupAPI.m in Sources */ = {isa = PBXBuildFile; fileRef = 4CD1565B1998A36300B11233 /* DDFixedGroupAPI.m */; }; + 4CD1566B1998A36300B11233 /* MsgReadACKAPI.m in Sources */ = {isa = PBXBuildFile; fileRef = 4CD1565F1998A36300B11233 /* MsgReadACKAPI.m */; }; + 4CD1566D1998A36300B11233 /* DDReceiveGroupAddMemberAPI.m in Sources */ = {isa = PBXBuildFile; fileRef = 4CD156631998A36300B11233 /* DDReceiveGroupAddMemberAPI.m */; }; + 4CD156781998B70D00B11233 /* DDGroupModule.m in Sources */ = {isa = PBXBuildFile; fileRef = 4CD156771998B70D00B11233 /* DDGroupModule.m */; }; + 4CD3EDDB1A0C6FE100795A0C /* NSString+Additions.m in Sources */ = {isa = PBXBuildFile; fileRef = 4CD3EDDA1A0C6FE100795A0C /* NSString+Additions.m */; }; + 4CD995F5199F420700025C9C /* DDBaseEntity.m in Sources */ = {isa = PBXBuildFile; fileRef = 4CD995F4199F420700025C9C /* DDBaseEntity.m */; }; + 4CE135E819C91EB20098A5E4 /* SendPushTokenAPI.m in Sources */ = {isa = PBXBuildFile; fileRef = 4CE135E719C91EB20098A5E4 /* SendPushTokenAPI.m */; }; + 4CE95F3119AAD0E8000CD0C6 /* ContactAvatarTools.m in Sources */ = {isa = PBXBuildFile; fileRef = 4CE95F3019AAD0E8000CD0C6 /* ContactAvatarTools.m */; }; + 4CF7D530198A268500F0272B /* JSDismissiveTextView.m in Sources */ = {isa = PBXBuildFile; fileRef = 4CF7D523198A268500F0272B /* JSDismissiveTextView.m */; }; + 4CF7D531198A268500F0272B /* JSMessageInputView.m in Sources */ = {isa = PBXBuildFile; fileRef = 4CF7D525198A268500F0272B /* JSMessageInputView.m */; }; + 4CF7D532198A268500F0272B /* JSMessageTextView.m in Sources */ = {isa = PBXBuildFile; fileRef = 4CF7D527198A268500F0272B /* JSMessageTextView.m */; }; + 4CFC9FB21A4412E3002E7A5A /* MsgReadNotify.m in Sources */ = {isa = PBXBuildFile; fileRef = 4CFC9FB11A4412E3002E7A5A /* MsgReadNotify.m */; }; + 81B75A131A58CC090039E5B5 /* search_bar.png in Resources */ = {isa = PBXBuildFile; fileRef = 81B75A111A58CC090039E5B5 /* search_bar.png */; }; + 81B75A141A58CC090039E5B5 /* search_bar@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = 81B75A121A58CC090039E5B5 /* search_bar@2x.png */; }; + 81B75A161A58CC1F0039E5B5 /* logo.png in Resources */ = {isa = PBXBuildFile; fileRef = 81B75A151A58CC1F0039E5B5 /* logo.png */; }; + 81B75A191A58CCC90039E5B5 /* phone.png in Resources */ = {isa = PBXBuildFile; fileRef = 81B75A171A58CCC90039E5B5 /* phone.png */; }; + 81B75A1A1A58CCC90039E5B5 /* phone@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = 81B75A181A58CCC90039E5B5 /* phone@2x.png */; }; + 81B75A1D1A58CD830039E5B5 /* right.png in Resources */ = {isa = PBXBuildFile; fileRef = 81B75A1B1A58CD830039E5B5 /* right.png */; }; + 81B75A1E1A58CD830039E5B5 /* right@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = 81B75A1C1A58CD830039E5B5 /* right@2x.png */; }; + 81B75A211A58CD8C0039E5B5 /* left.png in Resources */ = {isa = PBXBuildFile; fileRef = 81B75A1F1A58CD8C0039E5B5 /* left.png */; }; + 81B75A221A58CD8C0039E5B5 /* left@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = 81B75A201A58CD8C0039E5B5 /* left@2x.png */; }; + C46061D6194E9D8A00FF3966 /* SystemConfiguration.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = C46061D5194E9D8A00FF3966 /* SystemConfiguration.framework */; }; + C46061D8194E9D9300FF3966 /* MobileCoreServices.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = C46061D7194E9D9300FF3966 /* MobileCoreServices.framework */; }; + C485E8E719F78D800061DAFE /* FinderViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = C485E8E519F78D800061DAFE /* FinderViewController.m */; }; + C485E8E819F78D800061DAFE /* FinderViewController.xib in Resources */ = {isa = PBXBuildFile; fileRef = C485E8E619F78D800061DAFE /* FinderViewController.xib */; }; + C485E8EB19F7CB630061DAFE /* OpenSourcePRViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = C485E8EA19F7CB630061DAFE /* OpenSourcePRViewController.m */; }; + C485E8EE19F7D6250061DAFE /* WifiViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = C485E8ED19F7D6250061DAFE /* WifiViewController.m */; }; + C493DFB61962A50900B39106 /* NSDate+DDAddition.m in Sources */ = {isa = PBXBuildFile; fileRef = C493DDCD1962A50900B39106 /* NSDate+DDAddition.m */; }; + C493DFB71962A50900B39106 /* NSDictionary+JSON.m in Sources */ = {isa = PBXBuildFile; fileRef = C493DDCF1962A50900B39106 /* NSDictionary+JSON.m */; }; + C493DFB81962A50900B39106 /* NSDictionary+Safe.m in Sources */ = {isa = PBXBuildFile; fileRef = C493DDD11962A50900B39106 /* NSDictionary+Safe.m */; }; + C493DFB91962A50900B39106 /* NSIndexSet+AQIndexesOutsideSet.m in Sources */ = {isa = PBXBuildFile; fileRef = C493DDD31962A50900B39106 /* NSIndexSet+AQIndexesOutsideSet.m */; }; + C493DFBA1962A50900B39106 /* NSIndexSet+AQIsSetContiguous.m in Sources */ = {isa = PBXBuildFile; fileRef = C493DDD51962A50900B39106 /* NSIndexSet+AQIsSetContiguous.m */; }; + C493DFBD1962A50900B39106 /* NSString+DDPath.m in Sources */ = {isa = PBXBuildFile; fileRef = C493DDDB1962A50900B39106 /* NSString+DDPath.m */; }; + C493DFBE1962A50900B39106 /* NSString+JSMessagesView.m in Sources */ = {isa = PBXBuildFile; fileRef = C493DDDD1962A50900B39106 /* NSString+JSMessagesView.m */; }; + C493DFBF1962A50900B39106 /* UIButton+JSMessagesView.m in Sources */ = {isa = PBXBuildFile; fileRef = C493DDDF1962A50900B39106 /* UIButton+JSMessagesView.m */; }; + C493DFC01962A50900B39106 /* UIColor+AQGridView.m in Sources */ = {isa = PBXBuildFile; fileRef = C493DDE11962A50900B39106 /* UIColor+AQGridView.m */; }; + C493DFC11962A50900B39106 /* UIColor+JSMessagesView.m in Sources */ = {isa = PBXBuildFile; fileRef = C493DDE31962A50900B39106 /* UIColor+JSMessagesView.m */; }; + C493DFC31962A50900B39106 /* UIImage+JSMessagesView.m in Sources */ = {isa = PBXBuildFile; fileRef = C493DDE71962A50900B39106 /* UIImage+JSMessagesView.m */; }; + C493DFC41962A50900B39106 /* UIView+AnimationOptionsForCurve.m in Sources */ = {isa = PBXBuildFile; fileRef = C493DDE91962A50900B39106 /* UIView+AnimationOptionsForCurve.m */; }; + C493DFC51962A50900B39106 /* UIView+DDAddition.m in Sources */ = {isa = PBXBuildFile; fileRef = C493DDEB1962A50900B39106 /* UIView+DDAddition.m */; }; + C493DFC61962A50900B39106 /* DDMessageEntity.mm in Sources */ = {isa = PBXBuildFile; fileRef = C493DDEF1962A50900B39106 /* DDMessageEntity.mm */; }; + C493DFC71962A50900B39106 /* SessionEntity.m in Sources */ = {isa = PBXBuildFile; fileRef = C493DDF11962A50900B39106 /* SessionEntity.m */; }; + C493DFC81962A50900B39106 /* DDUserEntity.m in Sources */ = {isa = PBXBuildFile; fileRef = C493DDF31962A50900B39106 /* DDUserEntity.m */; }; + C493DFCA1962A50900B39106 /* DDDatabaseUtil.m in Sources */ = {isa = PBXBuildFile; fileRef = C493DDF91962A50900B39106 /* DDDatabaseUtil.m */; }; + C493DFCC1962A50900B39106 /* DDAFClient.m in Sources */ = {isa = PBXBuildFile; fileRef = C493DDFF1962A50900B39106 /* DDAFClient.m */; }; + C493DFCF1962A50900B39106 /* DDHttpServer.m in Sources */ = {isa = PBXBuildFile; fileRef = C493DE061962A50900B39106 /* DDHttpServer.m */; }; + C493DFD21962A50900B39106 /* DDMsgServer.m in Sources */ = {isa = PBXBuildFile; fileRef = C493DE0C1962A50900B39106 /* DDMsgServer.m */; }; + C493DFD31962A50900B39106 /* DDTcpServer.m in Sources */ = {isa = PBXBuildFile; fileRef = C493DE0E1962A50900B39106 /* DDTcpServer.m */; }; + C493DFD51962A50900B39106 /* DDMessageModule.m in Sources */ = {isa = PBXBuildFile; fileRef = C493DE131962A50900B39106 /* DDMessageModule.m */; }; + C493DFD61962A50900B39106 /* DDMessageSendManager.mm in Sources */ = {isa = PBXBuildFile; fileRef = C493DE151962A50900B39106 /* DDMessageSendManager.mm */; }; + C493DFD71962A50900B39106 /* DDUserModule.m in Sources */ = {isa = PBXBuildFile; fileRef = C493DE181962A50900B39106 /* DDUserModule.m */; }; + C493E0141962A50A00B39106 /* DDClientState.m in Sources */ = {isa = PBXBuildFile; fileRef = C493DE581962A50900B39106 /* DDClientState.m */; }; + C493E0151962A50A00B39106 /* DDClientStateMaintenanceManager.m in Sources */ = {isa = PBXBuildFile; fileRef = C493DE5A1962A50900B39106 /* DDClientStateMaintenanceManager.m */; }; + C493E0161962A50A00B39106 /* std.m in Sources */ = {isa = PBXBuildFile; fileRef = C493DE5B1962A50900B39106 /* std.m */; }; + C493E0171962A50A00B39106 /* DDNotificationHelp.m in Sources */ = {isa = PBXBuildFile; fileRef = C493DE5E1962A50900B39106 /* DDNotificationHelp.m */; }; + C493E0181962A50A00B39106 /* DDSundriesCenter.m in Sources */ = {isa = PBXBuildFile; fileRef = C493DE601962A50900B39106 /* DDSundriesCenter.m */; }; + C493E0191962A50A00B39106 /* DataOutputStream+Addition.m in Sources */ = {isa = PBXBuildFile; fileRef = C493DE631962A50900B39106 /* DataOutputStream+Addition.m */; }; + C493E01A1962A50A00B39106 /* DDAPISchedule.m in Sources */ = {isa = PBXBuildFile; fileRef = C493DE651962A50900B39106 /* DDAPISchedule.m */; }; + C493E01B1962A50A00B39106 /* DDDataInputStream.m in Sources */ = {isa = PBXBuildFile; fileRef = C493DE691962A50900B39106 /* DDDataInputStream.m */; }; + C493E01C1962A50A00B39106 /* DDDataOutputStream.m in Sources */ = {isa = PBXBuildFile; fileRef = C493DE6B1962A50900B39106 /* DDDataOutputStream.m */; }; + C493E01D1962A50A00B39106 /* DDReachability.m in Sources */ = {isa = PBXBuildFile; fileRef = C493DE6D1962A50900B39106 /* DDReachability.m */; }; + C493E01E1962A50A00B39106 /* DDSendBuffer.m in Sources */ = {isa = PBXBuildFile; fileRef = C493DE6F1962A50900B39106 /* DDSendBuffer.m */; }; + C493E01F1962A50A00B39106 /* DDSuperAPI.m in Sources */ = {isa = PBXBuildFile; fileRef = C493DE711962A50900B39106 /* DDSuperAPI.m */; }; + C493E0201962A50A00B39106 /* DDTcpClientManager.m in Sources */ = {isa = PBXBuildFile; fileRef = C493DE731962A50900B39106 /* DDTcpClientManager.m */; }; + C493E0211962A50A00B39106 /* DDTcpProtocolHeader.m in Sources */ = {isa = PBXBuildFile; fileRef = C493DE751962A50900B39106 /* DDTcpProtocolHeader.m */; }; + C493E0221962A50A00B39106 /* DDUnrequestSuperAPI.m in Sources */ = {isa = PBXBuildFile; fileRef = C493DE771962A50900B39106 /* DDUnrequestSuperAPI.m */; }; + C493E0231962A50A00B39106 /* NSStream+NSStreamAddition.m in Sources */ = {isa = PBXBuildFile; fileRef = C493DE791962A50900B39106 /* NSStream+NSStreamAddition.m */; }; + C493E0251962A50A00B39106 /* HeartbeatAPI.m in Sources */ = {isa = PBXBuildFile; fileRef = C493DE801962A50900B39106 /* HeartbeatAPI.m */; }; + C493E0261962A50A00B39106 /* LoginAPI.mm in Sources */ = {isa = PBXBuildFile; fileRef = C493DE821962A50900B39106 /* LoginAPI.mm */; }; + C493E0291962A50A00B39106 /* GetUnreadMessagesAPI.m in Sources */ = {isa = PBXBuildFile; fileRef = C493DE891962A50900B39106 /* GetUnreadMessagesAPI.m */; }; + C493E02A1962A50A00B39106 /* SendMessageAPI.m in Sources */ = {isa = PBXBuildFile; fileRef = C493DE8B1962A50900B39106 /* SendMessageAPI.m */; }; + C493E02C1962A50A00B39106 /* DDSendPhotoMessageAPI.m in Sources */ = {isa = PBXBuildFile; fileRef = C493DE8F1962A50900B39106 /* DDSendPhotoMessageAPI.m */; }; + C493E0311962A50A00B39106 /* ReceiveKickoffAPI.m in Sources */ = {isa = PBXBuildFile; fileRef = C493DE9C1962A50900B39106 /* ReceiveKickoffAPI.m */; }; + C493E0321962A50A00B39106 /* DDReceiveMessageAPI.m in Sources */ = {isa = PBXBuildFile; fileRef = C493DE9F1962A50900B39106 /* DDReceiveMessageAPI.m */; }; + C493E0331962A50A00B39106 /* AQGridView.m in Sources */ = {isa = PBXBuildFile; fileRef = C493DEA51962A50900B39106 /* AQGridView.m */; }; + C493E0341962A50A00B39106 /* AQGridViewAnimatorItem.m in Sources */ = {isa = PBXBuildFile; fileRef = C493DEA71962A50900B39106 /* AQGridViewAnimatorItem.m */; }; + C493E0351962A50A00B39106 /* AQGridViewCell.m in Sources */ = {isa = PBXBuildFile; fileRef = C493DEAA1962A50900B39106 /* AQGridViewCell.m */; }; + C493E0361962A50A00B39106 /* AQGridViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = C493DEAC1962A50900B39106 /* AQGridViewController.m */; }; + C493E0371962A50A00B39106 /* AQGridViewData.m in Sources */ = {isa = PBXBuildFile; fileRef = C493DEAE1962A50900B39106 /* AQGridViewData.m */; }; + C493E0381962A50A00B39106 /* AQGridViewUpdateInfo.m in Sources */ = {isa = PBXBuildFile; fileRef = C493DEB01962A50900B39106 /* AQGridViewUpdateInfo.m */; }; + C493E0391962A50A00B39106 /* AQGridViewUpdateItem.m in Sources */ = {isa = PBXBuildFile; fileRef = C493DEB21962A50900B39106 /* AQGridViewUpdateItem.m */; }; + C493E04D1962A50A00B39106 /* DDChatBaseCell.m in Sources */ = {isa = PBXBuildFile; fileRef = C493DEE21962A50900B39106 /* DDChatBaseCell.m */; }; + C493E04E1962A50A00B39106 /* DDChatImageCell.m in Sources */ = {isa = PBXBuildFile; fileRef = C493DEE51962A50900B39106 /* DDChatImageCell.m */; }; + C493E04F1962A50A00B39106 /* DDChatImagePreviewViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = C493DEE71962A50900B39106 /* DDChatImagePreviewViewController.m */; }; + C493E0501962A50A00B39106 /* DDChatTextCell.m in Sources */ = {isa = PBXBuildFile; fileRef = C493DEE91962A50900B39106 /* DDChatTextCell.m */; }; + C493E0511962A50A00B39106 /* DDChatTextCell.xib in Resources */ = {isa = PBXBuildFile; fileRef = C493DEEA1962A50900B39106 /* DDChatTextCell.xib */; }; + C493E0521962A50A00B39106 /* DDChatVoiceCell.m in Sources */ = {isa = PBXBuildFile; fileRef = C493DEEC1962A50900B39106 /* DDChatVoiceCell.m */; }; + C493E0541962A50A00B39106 /* DDPromptCell.m in Sources */ = {isa = PBXBuildFile; fileRef = C493DEF01962A50900B39106 /* DDPromptCell.m */; }; + C493E0551962A50A00B39106 /* DDAlbumDetailsViewControll.m in Sources */ = {isa = PBXBuildFile; fileRef = C493DEF31962A50900B39106 /* DDAlbumDetailsViewControll.m */; }; + C493E0561962A50A00B39106 /* AlbumViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = C493DEF51962A50900B39106 /* AlbumViewController.m */; }; + C493E0581962A50A00B39106 /* ChatUtilityViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = C493DEF91962A50900B39106 /* ChatUtilityViewController.m */; }; + C493E0591962A50A00B39106 /* EmojiFaceView.m in Sources */ = {isa = PBXBuildFile; fileRef = C493DEFB1962A50900B39106 /* EmojiFaceView.m */; }; + C493E05A1962A50A00B39106 /* EmotionsModule.m in Sources */ = {isa = PBXBuildFile; fileRef = C493DEFD1962A50900B39106 /* EmotionsModule.m */; }; + C493E05B1962A50A00B39106 /* EmotionsViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = C493DEFF1962A50900B39106 /* EmotionsViewController.m */; }; + C493E05D1962A50A00B39106 /* AnalysisImage.m in Sources */ = {isa = PBXBuildFile; fileRef = C493DF031962A50900B39106 /* AnalysisImage.m */; }; + C493E05F1962A50A00B39106 /* ChattingMainViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = C493DF071962A50900B39106 /* ChattingMainViewController.m */; }; + C493E0601962A50A00B39106 /* ChattingMainViewController.xib in Resources */ = {isa = PBXBuildFile; fileRef = C493DF081962A50900B39106 /* ChattingMainViewController.xib */; }; + C493E0611962A50A00B39106 /* ChattingModule.m in Sources */ = {isa = PBXBuildFile; fileRef = C493DF0A1962A50900B39106 /* ChattingModule.m */; }; + C493E0641962A50A00B39106 /* MenuImageView.m in Sources */ = {isa = PBXBuildFile; fileRef = C493DF0F1962A50900B39106 /* MenuImageView.m */; }; + C493E0651962A50A00B39106 /* RecordingView.m in Sources */ = {isa = PBXBuildFile; fileRef = C493DF111962A50900B39106 /* RecordingView.m */; }; + C493E0661962A50A00B39106 /* TouchDownGestureRecognizer.m in Sources */ = {isa = PBXBuildFile; fileRef = C493DF131962A50900B39106 /* TouchDownGestureRecognizer.m */; }; + C493E0671962A50A00B39106 /* AlbumDetailsBottomBar.m in Sources */ = {isa = PBXBuildFile; fileRef = C493DF151962A50900B39106 /* AlbumDetailsBottomBar.m */; }; + C493E0691962A50A00B39106 /* LoginModule.m in Sources */ = {isa = PBXBuildFile; fileRef = C493DF191962A50900B39106 /* LoginModule.m */; }; + C493E06C1962A50A00B39106 /* Photo.m in Sources */ = {isa = PBXBuildFile; fileRef = C493DF1E1962A50900B39106 /* Photo.m */; }; + C493E06D1962A50A00B39106 /* PhotosCache.m in Sources */ = {isa = PBXBuildFile; fileRef = C493DF201962A50900B39106 /* PhotosCache.m */; }; + C493E06E1962A50A00B39106 /* ImageGridViewCell.m in Sources */ = {isa = PBXBuildFile; fileRef = C493DF221962A50900B39106 /* ImageGridViewCell.m */; }; + C493E06F1962A50A00B39106 /* RecentUserCell.m in Sources */ = {isa = PBXBuildFile; fileRef = C493DF251962A50900B39106 /* RecentUserCell.m */; }; + C493E0701962A50A00B39106 /* RecentUserCell.xib in Resources */ = {isa = PBXBuildFile; fileRef = C493DF261962A50900B39106 /* RecentUserCell.xib */; }; + C493E0711962A50A00B39106 /* RecentUsersViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = C493DF281962A50900B39106 /* RecentUsersViewController.m */; }; + C493E0721962A50A00B39106 /* RecentUsersViewController.xib in Resources */ = {isa = PBXBuildFile; fileRef = C493DF291962A50900B39106 /* RecentUsersViewController.xib */; }; + C493E0741962A50A00B39106 /* bitwise.c in Sources */ = {isa = PBXBuildFile; fileRef = C493DF311962A50900B39106 /* bitwise.c */; }; + C493E0751962A50A00B39106 /* framing.c in Sources */ = {isa = PBXBuildFile; fileRef = C493DF321962A50900B39106 /* framing.c */; }; + C493E0761962A50A00B39106 /* bits.c in Sources */ = {isa = PBXBuildFile; fileRef = C493DF391962A50900B39106 /* bits.c */; }; + C493E0771962A50A00B39106 /* buffer.c in Sources */ = {isa = PBXBuildFile; fileRef = C493DF3A1962A50900B39106 /* buffer.c */; }; + C493E0781962A50A00B39106 /* cb_search.c in Sources */ = {isa = PBXBuildFile; fileRef = C493DF3B1962A50900B39106 /* cb_search.c */; }; + C493E0791962A50A00B39106 /* exc_10_16_table.c in Sources */ = {isa = PBXBuildFile; fileRef = C493DF401962A50900B39106 /* exc_10_16_table.c */; }; + C493E07A1962A50A00B39106 /* exc_10_32_table.c in Sources */ = {isa = PBXBuildFile; fileRef = C493DF411962A50900B39106 /* exc_10_32_table.c */; }; + C493E07B1962A50A00B39106 /* exc_20_32_table.c in Sources */ = {isa = PBXBuildFile; fileRef = C493DF421962A50900B39106 /* exc_20_32_table.c */; }; + C493E07C1962A50A00B39106 /* exc_5_256_table.c in Sources */ = {isa = PBXBuildFile; fileRef = C493DF431962A50900B39106 /* exc_5_256_table.c */; }; + C493E07D1962A50A00B39106 /* exc_5_64_table.c in Sources */ = {isa = PBXBuildFile; fileRef = C493DF441962A50900B39106 /* exc_5_64_table.c */; }; + C493E07E1962A50A00B39106 /* exc_8_128_table.c in Sources */ = {isa = PBXBuildFile; fileRef = C493DF451962A50900B39106 /* exc_8_128_table.c */; }; + C493E07F1962A50A00B39106 /* fftwrap.c in Sources */ = {isa = PBXBuildFile; fileRef = C493DF461962A50900B39106 /* fftwrap.c */; }; + C493E0801962A50A00B39106 /* filterbank.c in Sources */ = {isa = PBXBuildFile; fileRef = C493DF481962A50900B39106 /* filterbank.c */; }; + C493E0811962A50A00B39106 /* filters.c in Sources */ = {isa = PBXBuildFile; fileRef = C493DF4A1962A50900B39106 /* filters.c */; }; + C493E0821962A50A00B39106 /* gain_table.c in Sources */ = {isa = PBXBuildFile; fileRef = C493DF541962A50900B39106 /* gain_table.c */; }; + C493E0831962A50A00B39106 /* gain_table_lbr.c in Sources */ = {isa = PBXBuildFile; fileRef = C493DF551962A50900B39106 /* gain_table_lbr.c */; }; + C493E0841962A50A00B39106 /* hexc_10_32_table.c in Sources */ = {isa = PBXBuildFile; fileRef = C493DF561962A50900B39106 /* hexc_10_32_table.c */; }; + C493E0851962A50A00B39106 /* hexc_table.c in Sources */ = {isa = PBXBuildFile; fileRef = C493DF571962A50900B39106 /* hexc_table.c */; }; + C493E0861962A50A00B39106 /* high_lsp_tables.c in Sources */ = {isa = PBXBuildFile; fileRef = C493DF581962A50900B39106 /* high_lsp_tables.c */; }; + C493E0871962A50A00B39106 /* jitter.c in Sources */ = {isa = PBXBuildFile; fileRef = C493DF591962A50900B39106 /* jitter.c */; }; + C493E0881962A50A00B39106 /* kiss_fft.c in Sources */ = {isa = PBXBuildFile; fileRef = C493DF5A1962A50900B39106 /* kiss_fft.c */; }; + C493E0891962A50A00B39106 /* kiss_fftr.c in Sources */ = {isa = PBXBuildFile; fileRef = C493DF5C1962A50900B39106 /* kiss_fftr.c */; }; + C493E08A1962A50A00B39106 /* lpc.c in Sources */ = {isa = PBXBuildFile; fileRef = C493DF5E1962A50900B39106 /* lpc.c */; }; + C493E08B1962A50A00B39106 /* lsp.c in Sources */ = {isa = PBXBuildFile; fileRef = C493DF611962A50900B39106 /* lsp.c */; }; + C493E08C1962A50A00B39106 /* lsp_tables_nb.c in Sources */ = {isa = PBXBuildFile; fileRef = C493DF641962A50900B39106 /* lsp_tables_nb.c */; }; + C493E08D1962A50A00B39106 /* ltp.c in Sources */ = {isa = PBXBuildFile; fileRef = C493DF651962A50900B39106 /* ltp.c */; }; + C493E08E1962A50A00B39106 /* mdf.c in Sources */ = {isa = PBXBuildFile; fileRef = C493DF6B1962A50900B39106 /* mdf.c */; }; + C493E08F1962A50A00B39106 /* modes.c in Sources */ = {isa = PBXBuildFile; fileRef = C493DF6D1962A50900B39106 /* modes.c */; }; + C493E0901962A50A00B39106 /* modes_wb.c in Sources */ = {isa = PBXBuildFile; fileRef = C493DF6F1962A50900B39106 /* modes_wb.c */; }; + C493E0911962A50A00B39106 /* nb_celp.c in Sources */ = {isa = PBXBuildFile; fileRef = C493DF701962A50900B39106 /* nb_celp.c */; }; + C493E0921962A50A00B39106 /* preprocess.c in Sources */ = {isa = PBXBuildFile; fileRef = C493DF731962A50900B39106 /* preprocess.c */; }; + C493E0931962A50A00B39106 /* quant_lsp.c in Sources */ = {isa = PBXBuildFile; fileRef = C493DF751962A50900B39106 /* quant_lsp.c */; }; + C493E0941962A50A00B39106 /* resample.c in Sources */ = {isa = PBXBuildFile; fileRef = C493DF781962A50900B39106 /* resample.c */; }; + C493E0951962A50A00B39106 /* sb_celp.c in Sources */ = {isa = PBXBuildFile; fileRef = C493DF7A1962A50900B39106 /* sb_celp.c */; }; + C493E0961962A50A00B39106 /* scal.c in Sources */ = {isa = PBXBuildFile; fileRef = C493DF7C1962A50900B39106 /* scal.c */; }; + C493E0971962A50A00B39106 /* smallft.c in Sources */ = {isa = PBXBuildFile; fileRef = C493DF7D1962A50900B39106 /* smallft.c */; }; + C493E0981962A50A00B39106 /* speex_config_types.h.in in Resources */ = {isa = PBXBuildFile; fileRef = C493DF851962A50900B39106 /* speex_config_types.h.in */; }; + C493E0991962A50A00B39106 /* speex.c in Sources */ = {isa = PBXBuildFile; fileRef = C493DF8D1962A50900B39106 /* speex.c */; }; + C493E09A1962A50A00B39106 /* speex_callbacks.c in Sources */ = {isa = PBXBuildFile; fileRef = C493DF8E1962A50900B39106 /* speex_callbacks.c */; }; + C493E09B1962A50A00B39106 /* speex_header.c in Sources */ = {isa = PBXBuildFile; fileRef = C493DF8F1962A50900B39106 /* speex_header.c */; }; + C493E09C1962A50A00B39106 /* stereo.c in Sources */ = {isa = PBXBuildFile; fileRef = C493DF911962A50900B39106 /* stereo.c */; }; + C493E09D1962A50A00B39106 /* vbr.c in Sources */ = {isa = PBXBuildFile; fileRef = C493DF921962A50900B39106 /* vbr.c */; }; + C493E09E1962A50A00B39106 /* vq.c in Sources */ = {isa = PBXBuildFile; fileRef = C493DF951962A50900B39106 /* vq.c */; }; + C493E09F1962A50A00B39106 /* window.c in Sources */ = {isa = PBXBuildFile; fileRef = C493DF9A1962A50900B39106 /* window.c */; }; + C493E0A01962A50A00B39106 /* AQRecorder.mm in Sources */ = {isa = PBXBuildFile; fileRef = C493DF9D1962A50900B39106 /* AQRecorder.mm */; }; + C493E0A11962A50A00B39106 /* SpeexCodec.m in Sources */ = {isa = PBXBuildFile; fileRef = C493DFA11962A50900B39106 /* SpeexCodec.m */; }; + C493E0A21962A50A00B39106 /* Decapsulator.m in Sources */ = {isa = PBXBuildFile; fileRef = C493DFA31962A50900B39106 /* Decapsulator.m */; }; + C493E0A31962A50A00B39106 /* Encapsulator.m in Sources */ = {isa = PBXBuildFile; fileRef = C493DFA51962A50900B39106 /* Encapsulator.m */; }; + C493E0A41962A50A00B39106 /* PlayerManager.m in Sources */ = {isa = PBXBuildFile; fileRef = C493DFA71962A50900B39106 /* PlayerManager.m */; }; + C493E0A51962A50A00B39106 /* CADebugMacros.cpp in Sources */ = {isa = PBXBuildFile; fileRef = C493DFA91962A50900B39106 /* CADebugMacros.cpp */; }; + C493E0A61962A50A00B39106 /* CAStreamBasicDescription.cpp in Sources */ = {isa = PBXBuildFile; fileRef = C493DFAC1962A50900B39106 /* CAStreamBasicDescription.cpp */; }; + C493E0A71962A50A00B39106 /* CAXException.cpp in Sources */ = {isa = PBXBuildFile; fileRef = C493DFAE1962A50900B39106 /* CAXException.cpp */; }; + C493E0A81962A50A00B39106 /* RawAudioDataPlayer.m in Sources */ = {isa = PBXBuildFile; fileRef = C493DFB11962A50900B39106 /* RawAudioDataPlayer.m */; }; + C493E0A91962A50A00B39106 /* RecorderManager.mm in Sources */ = {isa = PBXBuildFile; fileRef = C493DFB31962A50900B39106 /* RecorderManager.mm */; }; + C493E0B21962A54F00B39106 /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = C493E0B11962A54F00B39106 /* main.m */; }; + C4AFD7D6193D67350054ECFD /* AVFoundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = C4AFD7D5193D67350054ECFD /* AVFoundation.framework */; }; + C4AFD883193D7B490054ECFD /* CoreAudio.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = C4AFD882193D7B490054ECFD /* CoreAudio.framework */; }; + C4AFD885193D7B580054ECFD /* AudioToolbox.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = C4AFD884193D7B580054ECFD /* AudioToolbox.framework */; }; + C4EBA738192F279100B72723 /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = C4EBA737192F279100B72723 /* Foundation.framework */; }; + C4EBA73A192F279100B72723 /* CoreGraphics.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = C4EBA739192F279100B72723 /* CoreGraphics.framework */; }; + C4EBA73C192F279100B72723 /* UIKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = C4EBA73B192F279100B72723 /* UIKit.framework */; }; +/* End PBXBuildFile section */ + +/* Begin PBXFileReference section */ + 19B78DA8A3707C0C507EF626 /* Pods.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = Pods.release.xcconfig; path = "Pods/Target Support Files/Pods/Pods.release.xcconfig"; sourceTree = ""; }; + 3EFE09922227481999813B37 /* libPods.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libPods.a; sourceTree = BUILT_PRODUCTS_DIR; }; + 4C0C0F0A1A314E060094CCD2 /* SessionModule.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SessionModule.h; sourceTree = ""; }; + 4C0C0F0B1A314E060094CCD2 /* SessionModule.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SessionModule.m; sourceTree = ""; }; + 4C12E7F41A77920A00F1DD54 /* Launch Screen.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = "Launch Screen.xib"; sourceTree = ""; }; + 4C1CEEC61A3581160015C355 /* GetMessageQueueAPI.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = GetMessageQueueAPI.h; sourceTree = ""; }; + 4C1CEEC71A3581160015C355 /* GetMessageQueueAPI.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GetMessageQueueAPI.m; sourceTree = ""; }; + 4C1E441719961889005CB2DB /* DDReceiveMessageACKAPI.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DDReceiveMessageACKAPI.h; sourceTree = ""; }; + 4C1E441819961889005CB2DB /* DDReceiveMessageACKAPI.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = DDReceiveMessageACKAPI.m; sourceTree = ""; }; + 4C21749519C197F3006F4BFC /* DDUserDetailInfoAPI.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DDUserDetailInfoAPI.h; sourceTree = ""; }; + 4C21749619C197F3006F4BFC /* DDUserDetailInfoAPI.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = DDUserDetailInfoAPI.m; sourceTree = ""; }; + 4C31EB5419CAB471004A3B2C /* GetGroupInfoAPi.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = GetGroupInfoAPi.h; path = RequestAPI/Users/GetGroupInfoAPi.h; sourceTree = ""; }; + 4C31EB5519CAB471004A3B2C /* GetGroupInfoAPi.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = GetGroupInfoAPi.m; path = RequestAPI/Users/GetGroupInfoAPi.m; sourceTree = ""; }; + 4C39B7FD1974D6E4001B4AEF /* Images.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Images.xcassets; sourceTree = ""; }; + 4C39B8041974EF18001B4AEF /* MainViewControll.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MainViewControll.h; sourceTree = ""; }; + 4C39B8051974EF18001B4AEF /* MainViewControll.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MainViewControll.m; sourceTree = ""; }; + 4C39B8061974EF18001B4AEF /* MainViewControll.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = MainViewControll.xib; sourceTree = ""; }; + 4C39B80C1974F388001B4AEF /* MyProfileViewControll.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MyProfileViewControll.h; sourceTree = ""; }; + 4C39B80D1974F388001B4AEF /* MyProfileViewControll.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MyProfileViewControll.m; sourceTree = ""; }; + 4C39B80E1974F388001B4AEF /* MyProfileViewControll.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = MyProfileViewControll.xib; sourceTree = ""; }; + 4C3A74A61A8C84C9009400A2 /* 221.gif */ = {isa = PBXFileReference; lastKnownFileType = image.gif; name = 221.gif; path = emotions/221.gif; sourceTree = ""; }; + 4C3A74A71A8C84C9009400A2 /* 221@2x.gif */ = {isa = PBXFileReference; lastKnownFileType = image.gif; name = "221@2x.gif"; path = "emotions/221@2x.gif"; sourceTree = ""; }; + 4C3A74A81A8C84C9009400A2 /* 222.gif */ = {isa = PBXFileReference; lastKnownFileType = image.gif; name = 222.gif; path = emotions/222.gif; sourceTree = ""; }; + 4C3A74A91A8C84C9009400A2 /* 222@2x.gif */ = {isa = PBXFileReference; lastKnownFileType = image.gif; name = "222@2x.gif"; path = "emotions/222@2x.gif"; sourceTree = ""; }; + 4C3A74AA1A8C84C9009400A2 /* 223.gif */ = {isa = PBXFileReference; lastKnownFileType = image.gif; name = 223.gif; path = emotions/223.gif; sourceTree = ""; }; + 4C3A74AB1A8C84C9009400A2 /* 223@2x.gif */ = {isa = PBXFileReference; lastKnownFileType = image.gif; name = "223@2x.gif"; path = "emotions/223@2x.gif"; sourceTree = ""; }; + 4C3A74AC1A8C84C9009400A2 /* 224.gif */ = {isa = PBXFileReference; lastKnownFileType = image.gif; name = 224.gif; path = emotions/224.gif; sourceTree = ""; }; + 4C3A74AD1A8C84C9009400A2 /* 224@2x.gif */ = {isa = PBXFileReference; lastKnownFileType = image.gif; name = "224@2x.gif"; path = "emotions/224@2x.gif"; sourceTree = ""; }; + 4C3A74AE1A8C84C9009400A2 /* 225.gif */ = {isa = PBXFileReference; lastKnownFileType = image.gif; name = 225.gif; path = emotions/225.gif; sourceTree = ""; }; + 4C3A74AF1A8C84C9009400A2 /* 225@2x.gif */ = {isa = PBXFileReference; lastKnownFileType = image.gif; name = "225@2x.gif"; path = "emotions/225@2x.gif"; sourceTree = ""; }; + 4C3A74B01A8C84C9009400A2 /* 226.gif */ = {isa = PBXFileReference; lastKnownFileType = image.gif; name = 226.gif; path = emotions/226.gif; sourceTree = ""; }; + 4C3A74B11A8C84C9009400A2 /* 226@2x.gif */ = {isa = PBXFileReference; lastKnownFileType = image.gif; name = "226@2x.gif"; path = "emotions/226@2x.gif"; sourceTree = ""; }; + 4C3A74B21A8C84C9009400A2 /* 227.gif */ = {isa = PBXFileReference; lastKnownFileType = image.gif; name = 227.gif; path = emotions/227.gif; sourceTree = ""; }; + 4C3A74B31A8C84C9009400A2 /* 227@2x.gif */ = {isa = PBXFileReference; lastKnownFileType = image.gif; name = "227@2x.gif"; path = "emotions/227@2x.gif"; sourceTree = ""; }; + 4C3A74B41A8C84C9009400A2 /* 228.gif */ = {isa = PBXFileReference; lastKnownFileType = image.gif; name = 228.gif; path = emotions/228.gif; sourceTree = ""; }; + 4C3A74B51A8C84C9009400A2 /* 228@2x.gif */ = {isa = PBXFileReference; lastKnownFileType = image.gif; name = "228@2x.gif"; path = "emotions/228@2x.gif"; sourceTree = ""; }; + 4C3A74B61A8C84C9009400A2 /* 229.gif */ = {isa = PBXFileReference; lastKnownFileType = image.gif; name = 229.gif; path = emotions/229.gif; sourceTree = ""; }; + 4C3A74B71A8C84C9009400A2 /* 229@2x.gif */ = {isa = PBXFileReference; lastKnownFileType = image.gif; name = "229@2x.gif"; path = "emotions/229@2x.gif"; sourceTree = ""; }; + 4C3A74B81A8C84C9009400A2 /* 230.gif */ = {isa = PBXFileReference; lastKnownFileType = image.gif; name = 230.gif; path = emotions/230.gif; sourceTree = ""; }; + 4C3A74B91A8C84C9009400A2 /* 230@2x.gif */ = {isa = PBXFileReference; lastKnownFileType = image.gif; name = "230@2x.gif"; path = "emotions/230@2x.gif"; sourceTree = ""; }; + 4C3A74BA1A8C84C9009400A2 /* 231.gif */ = {isa = PBXFileReference; lastKnownFileType = image.gif; name = 231.gif; path = emotions/231.gif; sourceTree = ""; }; + 4C3A74BB1A8C84C9009400A2 /* 231@2x.gif */ = {isa = PBXFileReference; lastKnownFileType = image.gif; name = "231@2x.gif"; path = "emotions/231@2x.gif"; sourceTree = ""; }; + 4C3A74BC1A8C84C9009400A2 /* 232.gif */ = {isa = PBXFileReference; lastKnownFileType = image.gif; name = 232.gif; path = emotions/232.gif; sourceTree = ""; }; + 4C3A74BD1A8C84C9009400A2 /* 232@2x.gif */ = {isa = PBXFileReference; lastKnownFileType = image.gif; name = "232@2x.gif"; path = "emotions/232@2x.gif"; sourceTree = ""; }; + 4C3A74BE1A8C84C9009400A2 /* 233.gif */ = {isa = PBXFileReference; lastKnownFileType = image.gif; name = 233.gif; path = emotions/233.gif; sourceTree = ""; }; + 4C3A74BF1A8C84C9009400A2 /* 233@2x.gif */ = {isa = PBXFileReference; lastKnownFileType = image.gif; name = "233@2x.gif"; path = "emotions/233@2x.gif"; sourceTree = ""; }; + 4C3A74C01A8C84C9009400A2 /* 234.gif */ = {isa = PBXFileReference; lastKnownFileType = image.gif; name = 234.gif; path = emotions/234.gif; sourceTree = ""; }; + 4C3A74C11A8C84C9009400A2 /* 234@2x.gif */ = {isa = PBXFileReference; lastKnownFileType = image.gif; name = "234@2x.gif"; path = "emotions/234@2x.gif"; sourceTree = ""; }; + 4C3A74C21A8C84C9009400A2 /* 235.gif */ = {isa = PBXFileReference; lastKnownFileType = image.gif; name = 235.gif; path = emotions/235.gif; sourceTree = ""; }; + 4C3A74C31A8C84C9009400A2 /* 235@2x.gif */ = {isa = PBXFileReference; lastKnownFileType = image.gif; name = "235@2x.gif"; path = "emotions/235@2x.gif"; sourceTree = ""; }; + 4C3A74C41A8C84C9009400A2 /* 236.gif */ = {isa = PBXFileReference; lastKnownFileType = image.gif; name = 236.gif; path = emotions/236.gif; sourceTree = ""; }; + 4C3A74C51A8C84C9009400A2 /* 236@2x.gif */ = {isa = PBXFileReference; lastKnownFileType = image.gif; name = "236@2x.gif"; path = "emotions/236@2x.gif"; sourceTree = ""; }; + 4C3A74C61A8C84C9009400A2 /* 237.gif */ = {isa = PBXFileReference; lastKnownFileType = image.gif; name = 237.gif; path = emotions/237.gif; sourceTree = ""; }; + 4C3A74C71A8C84C9009400A2 /* 237@2x.gif */ = {isa = PBXFileReference; lastKnownFileType = image.gif; name = "237@2x.gif"; path = "emotions/237@2x.gif"; sourceTree = ""; }; + 4C3A74C81A8C84C9009400A2 /* 238.gif */ = {isa = PBXFileReference; lastKnownFileType = image.gif; name = 238.gif; path = emotions/238.gif; sourceTree = ""; }; + 4C3A74C91A8C84C9009400A2 /* 238@2x.gif */ = {isa = PBXFileReference; lastKnownFileType = image.gif; name = "238@2x.gif"; path = "emotions/238@2x.gif"; sourceTree = ""; }; + 4C3A74CA1A8C84C9009400A2 /* 239.gif */ = {isa = PBXFileReference; lastKnownFileType = image.gif; name = 239.gif; path = emotions/239.gif; sourceTree = ""; }; + 4C3A74CB1A8C84C9009400A2 /* 239@2x.gif */ = {isa = PBXFileReference; lastKnownFileType = image.gif; name = "239@2x.gif"; path = "emotions/239@2x.gif"; sourceTree = ""; }; + 4C3A74CC1A8C84C9009400A2 /* 240.gif */ = {isa = PBXFileReference; lastKnownFileType = image.gif; name = 240.gif; path = emotions/240.gif; sourceTree = ""; }; + 4C3A74CD1A8C84C9009400A2 /* 240@2x.gif */ = {isa = PBXFileReference; lastKnownFileType = image.gif; name = "240@2x.gif"; path = "emotions/240@2x.gif"; sourceTree = ""; }; + 4C3A74F61A8C84F7009400A2 /* delImage.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = delImage.png; path = resources/delImage.png; sourceTree = ""; }; + 4C3A74F71A8C84F7009400A2 /* delImage@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = "delImage@2x.png"; path = "resources/delImage@2x.png"; sourceTree = ""; }; + 4C3A74FD1A8C8577009400A2 /* Sequencer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = Sequencer.h; path = IOSDuoduo/Sequencer/Sequencer.h; sourceTree = ""; }; + 4C3A74FE1A8C8577009400A2 /* Sequencer.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = Sequencer.m; path = IOSDuoduo/Sequencer/Sequencer.m; sourceTree = ""; }; + 4C3A75001A8C85C1009400A2 /* DBHelper.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = DBHelper.h; path = IOSDuoduo/DB/DBHelper.h; sourceTree = ""; }; + 4C3A75011A8C85C1009400A2 /* DBHelper.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; name = DBHelper.mm; path = IOSDuoduo/DB/DBHelper.mm; sourceTree = ""; }; + 4C3A75021A8C85C1009400A2 /* DBManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = DBManager.h; path = IOSDuoduo/DB/DBManager.h; sourceTree = ""; }; + 4C3A75031A8C85C1009400A2 /* DBManager.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = DBManager.m; path = IOSDuoduo/DB/DBManager.m; sourceTree = ""; }; + 4C3A75061A8C860F009400A2 /* RootViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RootViewController.h; sourceTree = ""; }; + 4C3A75071A8C860F009400A2 /* RootViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RootViewController.m; sourceTree = ""; }; + 4C3A750A1A8C861E009400A2 /* RuntimeStatus.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RuntimeStatus.h; sourceTree = ""; }; + 4C3A750B1A8C861E009400A2 /* RuntimeStatus.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RuntimeStatus.m; sourceTree = ""; }; + 4C3A750D1A8C8650009400A2 /* TTHttpsRequest.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = TTHttpsRequest.h; sourceTree = ""; }; + 4C3A750E1A8C8650009400A2 /* TTHttpsRequest.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = TTHttpsRequest.m; sourceTree = ""; }; + 4C3A75101A8C865A009400A2 /* DDAppDelegate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DDAppDelegate.h; sourceTree = ""; }; + 4C3A75111A8C865A009400A2 /* DDAppDelegate.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = DDAppDelegate.m; sourceTree = ""; }; + 4C4169E21AB815E600B753FE /* security.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = security.h; sourceTree = ""; }; + 4C4657BB19EF5DC300334DD2 /* UnAckMessageManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = UnAckMessageManager.h; sourceTree = ""; }; + 4C4657BC19EF5DC300334DD2 /* UnAckMessageManager.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = UnAckMessageManager.m; sourceTree = ""; }; + 4C5486CD1A70EA8000ED8735 /* DDEmotionCell.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DDEmotionCell.h; sourceTree = ""; }; + 4C5486CE1A70EA8000ED8735 /* DDEmotionCell.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = DDEmotionCell.m; sourceTree = ""; }; + 4C5CA05E19C13341007CE792 /* DDDeleteMemberFromGroupAPI.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DDDeleteMemberFromGroupAPI.h; sourceTree = ""; }; + 4C5CA05F19C13341007CE792 /* DDDeleteMemberFromGroupAPI.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = DDDeleteMemberFromGroupAPI.m; sourceTree = ""; }; + 4C5CC9B61A38221C0067B124 /* RemoveSessionAPI.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RemoveSessionAPI.h; sourceTree = ""; }; + 4C5CC9B71A38221C0067B124 /* RemoveSessionAPI.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RemoveSessionAPI.m; sourceTree = ""; }; + 4C5D70551990C1AE009AF959 /* DDDepartmentAPI.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DDDepartmentAPI.h; sourceTree = ""; }; + 4C5D70561990C1AE009AF959 /* DDDepartmentAPI.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = DDDepartmentAPI.m; sourceTree = ""; }; + 4C5E374219D408CE00D1042B /* GroupAvatarImage.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = GroupAvatarImage.h; sourceTree = ""; }; + 4C5E374319D408CE00D1042B /* GroupAvatarImage.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GroupAvatarImage.m; sourceTree = ""; }; + 4C5F3F271A2EE29D003684B2 /* GetRecentSession.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = GetRecentSession.h; sourceTree = ""; }; + 4C5F3F281A2EE29D003684B2 /* GetRecentSession.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = GetRecentSession.mm; sourceTree = ""; }; + 4C6BBC171A7B8DD40028B892 /* UIImage+UIImageAddition.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "UIImage+UIImageAddition.h"; sourceTree = ""; }; + 4C6BBC181A7B8DD40028B892 /* UIImage+UIImageAddition.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "UIImage+UIImageAddition.m"; sourceTree = ""; }; + 4C77C28E1A8852F8001E5885 /* ScanQRCodePage.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ScanQRCodePage.h; sourceTree = ""; }; + 4C77C28F1A8852F8001E5885 /* ScanQRCodePage.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ScanQRCodePage.m; sourceTree = ""; }; + 4C77C2901A8852F8001E5885 /* ScanQRCodePage.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = ScanQRCodePage.xib; sourceTree = ""; }; + 4C77C2931A88CFEC001E5885 /* BlurView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = BlurView.h; sourceTree = ""; }; + 4C77C2941A88CFEC001E5885 /* BlurView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = BlurView.m; sourceTree = ""; }; + 4C79D2B11AB7C19200706E32 /* GetDepartment.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = GetDepartment.h; sourceTree = ""; }; + 4C79D2B21AB7C19200706E32 /* GetDepartment.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GetDepartment.m; sourceTree = ""; }; + 4C79D2B41AB7C9A500706E32 /* IMBaseDefine.pb.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = IMBaseDefine.pb.h; sourceTree = ""; }; + 4C79D2B51AB7C9A500706E32 /* IMBaseDefine.pb.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = IMBaseDefine.pb.m; sourceTree = ""; }; + 4C79D2B61AB7C9A500706E32 /* IMBuddy.pb.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = IMBuddy.pb.h; sourceTree = ""; }; + 4C79D2B71AB7C9A500706E32 /* IMBuddy.pb.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = IMBuddy.pb.m; sourceTree = ""; }; + 4C79D2B81AB7C9A500706E32 /* IMGroup.pb.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = IMGroup.pb.h; sourceTree = ""; }; + 4C79D2B91AB7C9A500706E32 /* IMGroup.pb.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = IMGroup.pb.m; sourceTree = ""; }; + 4C79D2BA1AB7C9A500706E32 /* IMLogin.pb.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = IMLogin.pb.h; sourceTree = ""; }; + 4C79D2BB1AB7C9A500706E32 /* IMLogin.pb.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = IMLogin.pb.m; sourceTree = ""; }; + 4C79D2BC1AB7C9A500706E32 /* IMMessage.pb.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = IMMessage.pb.h; sourceTree = ""; }; + 4C79D2BD1AB7C9A500706E32 /* IMMessage.pb.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = IMMessage.pb.m; sourceTree = ""; }; + 4C79D2BE1AB7C9A500706E32 /* IMOther.pb.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = IMOther.pb.h; sourceTree = ""; }; + 4C79D2BF1AB7C9A500706E32 /* IMOther.pb.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = IMOther.pb.m; sourceTree = ""; }; + 4C837EE7197F949300C3D758 /* DDAllUserAPI.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DDAllUserAPI.h; sourceTree = ""; }; + 4C837EE8197F949300C3D758 /* DDAllUserAPI.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = DDAllUserAPI.m; sourceTree = ""; }; + 4C837F31197F94F400C3D758 /* ContactsModule.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ContactsModule.h; sourceTree = ""; }; + 4C837F32197F94F400C3D758 /* ContactsModule.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ContactsModule.m; sourceTree = ""; }; + 4C837F35197F94F400C3D758 /* PublicProfileViewControll.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PublicProfileViewControll.h; sourceTree = ""; }; + 4C837F36197F94F400C3D758 /* PublicProfileViewControll.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = PublicProfileViewControll.m; sourceTree = ""; }; + 4C837F37197F94F400C3D758 /* PublicProfileViewControll.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = PublicProfileViewControll.xib; sourceTree = ""; }; + 4C837F3C197F951600C3D758 /* DDChattingEditViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DDChattingEditViewController.h; sourceTree = ""; }; + 4C837F3D197F951600C3D758 /* DDChattingEditViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = DDChattingEditViewController.m; sourceTree = ""; }; + 4C837F3E197F951600C3D758 /* DDChattingEditViewController.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = DDChattingEditViewController.xib; sourceTree = ""; }; + 4C837F41197F952800C3D758 /* ChattingEditModule.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = ChattingEditModule.h; path = Chatting/ChattingEditModule.h; sourceTree = ""; }; + 4C837F42197F952800C3D758 /* ChattingEditModule.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = ChattingEditModule.m; path = Chatting/ChattingEditModule.m; sourceTree = ""; }; + 4C837F44197F954500C3D758 /* DDCreateGroupAPI.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DDCreateGroupAPI.h; sourceTree = ""; }; + 4C837F45197F954500C3D758 /* DDCreateGroupAPI.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = DDCreateGroupAPI.m; sourceTree = ""; }; + 4C837F47197F95A400C3D758 /* GroupEntity.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = GroupEntity.h; sourceTree = ""; }; + 4C837F48197F95A400C3D758 /* GroupEntity.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GroupEntity.m; sourceTree = ""; }; + 4C837F4A197F95FF00C3D758 /* ContactsViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ContactsViewController.h; sourceTree = ""; }; + 4C837F4B197F95FF00C3D758 /* ContactsViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ContactsViewController.m; sourceTree = ""; }; + 4C88A0C119D50FC20071DA9C /* libMobClickLibrary.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; path = libMobClickLibrary.a; sourceTree = ""; }; + 4C88A0C319D50FD00071DA9C /* MobClick.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MobClick.h; sourceTree = ""; }; + 4C88A0C419D50FFA0071DA9C /* libz.dylib */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.dylib"; name = libz.dylib; path = usr/lib/libz.dylib; sourceTree = SDKROOT; }; + 4C92734619EB9C8200F6C370 /* NetwrokStatusNotifyUI.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = NetwrokStatusNotifyUI.h; sourceTree = ""; }; + 4C92734719EB9C8200F6C370 /* NetwrokStatusNotifyUI.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = NetwrokStatusNotifyUI.m; sourceTree = ""; }; + 4C92D7CC1ABA67EC00709CC6 /* libsecurity.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; path = libsecurity.a; sourceTree = ""; }; + 4C98355219C06F6D00DE8874 /* EditContactsCell.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = EditContactsCell.h; sourceTree = ""; }; + 4C98355319C06F6D00DE8874 /* EditContactsCell.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = EditContactsCell.m; sourceTree = ""; }; + 4CA0B9FF1A5C0E2800102EC7 /* NSData+Conversion.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "NSData+Conversion.h"; sourceTree = ""; }; + 4CA0BA001A5C0E2800102EC7 /* NSData+Conversion.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "NSData+Conversion.m"; sourceTree = ""; }; + 4CA50CC719A435E20032DE24 /* DDPersonEditCollectionCell.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DDPersonEditCollectionCell.h; sourceTree = ""; }; + 4CA50CC819A435E20032DE24 /* DDPersonEditCollectionCell.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = DDPersonEditCollectionCell.m; sourceTree = ""; }; + 4CA50CCB19A47B9A0032DE24 /* SpellLibrary.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SpellLibrary.h; sourceTree = ""; }; + 4CA50CCC19A47B9A0032DE24 /* SpellLibrary.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SpellLibrary.m; sourceTree = ""; }; + 4CA50CCE19A47C690032DE24 /* DDSearch.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DDSearch.h; sourceTree = ""; }; + 4CA50CCF19A47C690032DE24 /* DDSearch.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = DDSearch.m; sourceTree = ""; }; + 4CA6CDA91A2C1F6E00405BB6 /* add.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = add.png; path = resources/add.png; sourceTree = ""; }; + 4CA6CDAA1A2C1F6E00405BB6 /* add@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = "add@2x.png"; path = "resources/add@2x.png"; sourceTree = ""; }; + 4CA6CDAB1A2C1F6E00405BB6 /* chat.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = chat.png; path = resources/chat.png; sourceTree = ""; }; + 4CA6CDAC1A2C1F6E00405BB6 /* chat@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = "chat@2x.png"; path = "resources/chat@2x.png"; sourceTree = ""; }; + 4CA6CDAD1A2C1F6E00405BB6 /* contact_selected.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = contact_selected.png; path = resources/contact_selected.png; sourceTree = ""; }; + 4CA6CDAE1A2C1F6E00405BB6 /* contact_selected@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = "contact_selected@2x.png"; path = "resources/contact_selected@2x.png"; sourceTree = ""; }; + 4CA6CDAF1A2C1F6E00405BB6 /* contact.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = contact.png; path = resources/contact.png; sourceTree = ""; }; + 4CA6CDB01A2C1F6E00405BB6 /* contact@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = "contact@2x.png"; path = "resources/contact@2x.png"; sourceTree = ""; }; + 4CA6CDB11A2C1F6E00405BB6 /* conversation_selected.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = conversation_selected.png; path = resources/conversation_selected.png; sourceTree = ""; }; + 4CA6CDB21A2C1F6E00405BB6 /* conversation_selected@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = "conversation_selected@2x.png"; path = "resources/conversation_selected@2x.png"; sourceTree = ""; }; + 4CA6CDB31A2C1F6E00405BB6 /* conversation.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = conversation.png; path = resources/conversation.png; sourceTree = ""; }; + 4CA6CDB41A2C1F6E00405BB6 /* conversation@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = "conversation@2x.png"; path = "resources/conversation@2x.png"; sourceTree = ""; }; + 4CA6CDB51A2C1F6E00405BB6 /* dd_album.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = dd_album.png; path = resources/dd_album.png; sourceTree = ""; }; + 4CA6CDB61A2C1F6E00405BB6 /* dd_album@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = "dd_album@2x.png"; path = "resources/dd_album@2x.png"; sourceTree = ""; }; + 4CA6CDB71A2C1F6E00405BB6 /* dd_cancel_send_record.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = dd_cancel_send_record.png; path = resources/dd_cancel_send_record.png; sourceTree = ""; }; + 4CA6CDB81A2C1F6E00405BB6 /* dd_cancel_send_record@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = "dd_cancel_send_record@2x.png"; path = "resources/dd_cancel_send_record@2x.png"; sourceTree = ""; }; + 4CA6CDB91A2C1F6E00405BB6 /* dd_emoji_delete.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = dd_emoji_delete.png; path = resources/dd_emoji_delete.png; sourceTree = ""; }; + 4CA6CDBA1A2C1F6E00405BB6 /* dd_emoji_delete@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = "dd_emoji_delete@2x.png"; path = "resources/dd_emoji_delete@2x.png"; sourceTree = ""; }; + 4CA6CDBB1A2C1F6E00405BB6 /* dd_emotion.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = dd_emotion.png; path = resources/dd_emotion.png; sourceTree = ""; }; + 4CA6CDBC1A2C1F6E00405BB6 /* dd_emotion@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = "dd_emotion@2x.png"; path = "resources/dd_emotion@2x.png"; sourceTree = ""; }; + 4CA6CDBD1A2C1F6E00405BB6 /* dd_has_unread_message.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = dd_has_unread_message.png; path = resources/dd_has_unread_message.png; sourceTree = ""; }; + 4CA6CDBE1A2C1F6E00405BB6 /* dd_has_unread_message@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = "dd_has_unread_message@2x.png"; path = "resources/dd_has_unread_message@2x.png"; sourceTree = ""; }; + 4CA6CDBF1A2C1F6E00405BB6 /* dd_image_send.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = dd_image_send.png; path = resources/dd_image_send.png; sourceTree = ""; }; + 4CA6CDC01A2C1F6E00405BB6 /* dd_image_send@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = "dd_image_send@2x.png"; path = "resources/dd_image_send@2x.png"; sourceTree = ""; }; + 4CA6CDC11A2C1F6E00405BB6 /* dd_input_normal.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = dd_input_normal.png; path = resources/dd_input_normal.png; sourceTree = ""; }; + 4CA6CDC21A2C1F6E00405BB6 /* dd_input_normal@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = "dd_input_normal@2x.png"; path = "resources/dd_input_normal@2x.png"; sourceTree = ""; }; + 4CA6CDC31A2C1F6E00405BB6 /* dd_left_voice_one.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = dd_left_voice_one.png; path = resources/dd_left_voice_one.png; sourceTree = ""; }; + 4CA6CDC41A2C1F6E00405BB6 /* dd_left_voice_one@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = "dd_left_voice_one@2x.png"; path = "resources/dd_left_voice_one@2x.png"; sourceTree = ""; }; + 4CA6CDC51A2C1F6E00405BB6 /* dd_left_voice_three.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = dd_left_voice_three.png; path = resources/dd_left_voice_three.png; sourceTree = ""; }; + 4CA6CDC61A2C1F6E00405BB6 /* dd_left_voice_three@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = "dd_left_voice_three@2x.png"; path = "resources/dd_left_voice_three@2x.png"; sourceTree = ""; }; + 4CA6CDC71A2C1F6E00405BB6 /* dd_left_voice_two.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = dd_left_voice_two.png; path = resources/dd_left_voice_two.png; sourceTree = ""; }; + 4CA6CDC81A2C1F6E00405BB6 /* dd_left_voice_two@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = "dd_left_voice_two@2x.png"; path = "resources/dd_left_voice_two@2x.png"; sourceTree = ""; }; + 4CA6CDC91A2C1F6E00405BB6 /* dd_photo_back.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = dd_photo_back.png; path = resources/dd_photo_back.png; sourceTree = ""; }; + 4CA6CDCA1A2C1F6E00405BB6 /* dd_photo_back@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = "dd_photo_back@2x.png"; path = "resources/dd_photo_back@2x.png"; sourceTree = ""; }; + 4CA6CDCB1A2C1F6E00405BB6 /* dd_press_to_say_normal.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = dd_press_to_say_normal.png; path = resources/dd_press_to_say_normal.png; sourceTree = ""; }; + 4CA6CDCC1A2C1F6E00405BB6 /* dd_press_to_say_normal@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = "dd_press_to_say_normal@2x.png"; path = "resources/dd_press_to_say_normal@2x.png"; sourceTree = ""; }; + 4CA6CDCD1A2C1F6E00405BB6 /* dd_preview_select.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = dd_preview_select.png; path = resources/dd_preview_select.png; sourceTree = ""; }; + 4CA6CDCE1A2C1F6E00405BB6 /* dd_preview_select@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = "dd_preview_select@2x.png"; path = "resources/dd_preview_select@2x.png"; sourceTree = ""; }; + 4CA6CDD01A2C1F6E00405BB6 /* dd_recent_contacts.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = dd_recent_contacts.png; path = resources/dd_recent_contacts.png; sourceTree = ""; }; + 4CA6CDD11A2C1F6E00405BB6 /* dd_recent_contacts@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = "dd_recent_contacts@2x.png"; path = "resources/dd_recent_contacts@2x.png"; sourceTree = ""; }; + 4CA6CDD21A2C1F6E00405BB6 /* dd_record_normal.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = dd_record_normal.png; path = resources/dd_record_normal.png; sourceTree = ""; }; + 4CA6CDD31A2C1F6E00405BB6 /* dd_record_normal@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = "dd_record_normal@2x.png"; path = "resources/dd_record_normal@2x.png"; sourceTree = ""; }; + 4CA6CDD41A2C1F6E00405BB6 /* dd_record_release_end.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = dd_record_release_end.png; path = resources/dd_record_release_end.png; sourceTree = ""; }; + 4CA6CDD51A2C1F6E00405BB6 /* dd_record_release_end@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = "dd_record_release_end@2x.png"; path = "resources/dd_record_release_end@2x.png"; sourceTree = ""; }; + 4CA6CDD61A2C1F6E00405BB6 /* dd_record_too_short.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = dd_record_too_short.png; path = resources/dd_record_too_short.png; sourceTree = ""; }; + 4CA6CDD71A2C1F6E00405BB6 /* dd_record_too_short@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = "dd_record_too_short@2x.png"; path = "resources/dd_record_too_short@2x.png"; sourceTree = ""; }; + 4CA6CDD81A2C1F6E00405BB6 /* dd_recording.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = dd_recording.png; path = resources/dd_recording.png; sourceTree = ""; }; + 4CA6CDD91A2C1F6E00405BB6 /* dd_recording@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = "dd_recording@2x.png"; path = "resources/dd_recording@2x.png"; sourceTree = ""; }; + 4CA6CDDA1A2C1F6E00405BB6 /* dd_right_voice_one.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = dd_right_voice_one.png; path = resources/dd_right_voice_one.png; sourceTree = ""; }; + 4CA6CDDB1A2C1F6E00405BB6 /* dd_right_voice_one@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = "dd_right_voice_one@2x.png"; path = "resources/dd_right_voice_one@2x.png"; sourceTree = ""; }; + 4CA6CDDC1A2C1F6E00405BB6 /* dd_right_voice_three.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = dd_right_voice_three.png; path = resources/dd_right_voice_three.png; sourceTree = ""; }; + 4CA6CDDD1A2C1F6E00405BB6 /* dd_right_voice_three@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = "dd_right_voice_three@2x.png"; path = "resources/dd_right_voice_three@2x.png"; sourceTree = ""; }; + 4CA6CDDE1A2C1F6E00405BB6 /* dd_right_voice_two.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = dd_right_voice_two.png; path = resources/dd_right_voice_two.png; sourceTree = ""; }; + 4CA6CDDF1A2C1F6E00405BB6 /* dd_right_voice_two@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = "dd_right_voice_two@2x.png"; path = "resources/dd_right_voice_two@2x.png"; sourceTree = ""; }; + 4CA6CDE01A2C1F6E00405BB6 /* dd_selected_photo.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = dd_selected_photo.png; path = resources/dd_selected_photo.png; sourceTree = ""; }; + 4CA6CDE11A2C1F6E00405BB6 /* dd_selected_photo@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = "dd_selected_photo@2x.png"; path = "resources/dd_selected_photo@2x.png"; sourceTree = ""; }; + 4CA6CDE21A2C1F6E00405BB6 /* dd_send_failed.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = dd_send_failed.png; path = resources/dd_send_failed.png; sourceTree = ""; }; + 4CA6CDE31A2C1F6E00405BB6 /* dd_send_failed@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = "dd_send_failed@2x.png"; path = "resources/dd_send_failed@2x.png"; sourceTree = ""; }; + 4CA6CDE41A2C1F6E00405BB6 /* dd_take-photo.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = "dd_take-photo.png"; path = "resources/dd_take-photo.png"; sourceTree = ""; }; + 4CA6CDE51A2C1F6E00405BB6 /* dd_take-photo@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = "dd_take-photo@2x.png"; path = "resources/dd_take-photo@2x.png"; sourceTree = ""; }; + 4CA6CDE61A2C1F6E00405BB6 /* dd_utility.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = dd_utility.png; path = resources/dd_utility.png; sourceTree = ""; }; + 4CA6CDE71A2C1F6E00405BB6 /* dd_utility@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = "dd_utility@2x.png"; path = "resources/dd_utility@2x.png"; sourceTree = ""; }; + 4CA6CDE81A2C1F6E00405BB6 /* dd_volumn.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = dd_volumn.png; path = resources/dd_volumn.png; sourceTree = ""; }; + 4CA6CDE91A2C1F6E00405BB6 /* dd_volumn@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = "dd_volumn@2x.png"; path = "resources/dd_volumn@2x.png"; sourceTree = ""; }; + 4CA6CDEA1A2C1F6E00405BB6 /* delete.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = delete.png; path = resources/delete.png; sourceTree = ""; }; + 4CA6CDEB1A2C1F6E00405BB6 /* delete@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = "delete@2x.png"; path = "resources/delete@2x.png"; sourceTree = ""; }; + 4CA6CDEC1A2C1F6E00405BB6 /* edit.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = edit.png; path = resources/edit.png; sourceTree = ""; }; + 4CA6CDED1A2C1F6E00405BB6 /* edit@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = "edit@2x.png"; path = "resources/edit@2x.png"; sourceTree = ""; }; + 4CA6CDEE1A2C1F6E00405BB6 /* email.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = email.png; path = resources/email.png; sourceTree = ""; }; + 4CA6CDEF1A2C1F6E00405BB6 /* email@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = "email@2x.png"; path = "resources/email@2x.png"; sourceTree = ""; }; + 4CA6CDF01A2C1F6E00405BB6 /* group_default.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = group_default.png; path = resources/group_default.png; sourceTree = ""; }; + 4CA6CDF11A2C1F6E00405BB6 /* group_default@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = "group_default@2x.png"; path = "resources/group_default@2x.png"; sourceTree = ""; }; + 4CA6CDF21A2C1F6E00405BB6 /* jiantou.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = jiantou.png; path = resources/jiantou.png; sourceTree = ""; }; + 4CA6CDF31A2C1F6E00405BB6 /* jiantou@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = "jiantou@2x.png"; path = "resources/jiantou@2x.png"; sourceTree = ""; }; + 4CA6CDF71A2C1F6E00405BB6 /* loginlogo.jpg */ = {isa = PBXFileReference; lastKnownFileType = image.jpeg; name = loginlogo.jpg; path = resources/loginlogo.jpg; sourceTree = ""; }; + 4CA6CDF81A2C1F6E00405BB6 /* loginlogo.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = loginlogo.png; path = resources/loginlogo.png; sourceTree = ""; }; + 4CA6CDF91A2C1F6E00405BB6 /* msg.caf */ = {isa = PBXFileReference; lastKnownFileType = file; name = msg.caf; path = resources/msg.caf; sourceTree = ""; }; + 4CA6CDFA1A2C1F6E00405BB6 /* myprofile_selected.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = myprofile_selected.png; path = resources/myprofile_selected.png; sourceTree = ""; }; + 4CA6CDFB1A2C1F6E00405BB6 /* myprofile_selected@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = "myprofile_selected@2x.png"; path = "resources/myprofile_selected@2x.png"; sourceTree = ""; }; + 4CA6CDFC1A2C1F6E00405BB6 /* myprofile.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = myprofile.png; path = resources/myprofile.png; sourceTree = ""; }; + 4CA6CDFD1A2C1F6E00405BB6 /* myprofile@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = "myprofile@2x.png"; path = "resources/myprofile@2x.png"; sourceTree = ""; }; + 4CA6CDFE1A2C1F6E00405BB6 /* password.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = password.png; path = resources/password.png; sourceTree = ""; }; + 4CA6CDFF1A2C1F6E00405BB6 /* password@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = "password@2x.png"; path = "resources/password@2x.png"; sourceTree = ""; }; + 4CA6CE021A2C1F6E00405BB6 /* select.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = select.png; path = resources/select.png; sourceTree = ""; }; + 4CA6CE031A2C1F6E00405BB6 /* select@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = "select@2x.png"; path = "resources/select@2x.png"; sourceTree = ""; }; + 4CA6CE041A2C1F6E00405BB6 /* setting.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = setting.png; path = resources/setting.png; sourceTree = ""; }; + 4CA6CE051A2C1F6E00405BB6 /* setting@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = "setting@2x.png"; path = "resources/setting@2x.png"; sourceTree = ""; }; + 4CA6CE061A2C1F6E00405BB6 /* star.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = star.png; path = resources/star.png; sourceTree = ""; }; + 4CA6CE071A2C1F6E00405BB6 /* star@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = "star@2x.png"; path = "resources/star@2x.png"; sourceTree = ""; }; + 4CA6CE081A2C1F6E00405BB6 /* TeamTalk.xcworkspace */ = {isa = PBXFileReference; lastKnownFileType = wrapper.workspace; name = TeamTalk.xcworkspace; path = resources/TeamTalk.xcworkspace; sourceTree = ""; }; + 4CA6CE091A2C1F6E00405BB6 /* tel.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = tel.png; path = resources/tel.png; sourceTree = ""; }; + 4CA6CE0A1A2C1F6E00405BB6 /* tel@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = "tel@2x.png"; path = "resources/tel@2x.png"; sourceTree = ""; }; + 4CA6CE0B1A2C1F6E00405BB6 /* unselected.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = unselected.png; path = resources/unselected.png; sourceTree = ""; }; + 4CA6CE0C1A2C1F6E00405BB6 /* unselected@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = "unselected@2x.png"; path = "resources/unselected@2x.png"; sourceTree = ""; }; + 4CA6CE0D1A2C1F6E00405BB6 /* username.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = username.png; path = resources/username.png; sourceTree = ""; }; + 4CA6CE0E1A2C1F6E00405BB6 /* username@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = "username@2x.png"; path = "resources/username@2x.png"; sourceTree = ""; }; + 4CA6CE0F1A2C1F6E00405BB6 /* x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = x.png; path = resources/x.png; sourceTree = ""; }; + 4CA6CE101A2C1F6E00405BB6 /* x@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = "x@2x.png"; path = "resources/x@2x.png"; sourceTree = ""; }; + 4CA6CE791A2C1FA700405BB6 /* LoginViewController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = LoginViewController.h; sourceTree = ""; }; + 4CA6CE7A1A2C1FA700405BB6 /* LoginViewController.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = LoginViewController.m; sourceTree = ""; }; + 4CA6CE7D1A2C1FBA00405BB6 /* LoginViewController.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = LoginViewController.xib; sourceTree = ""; }; + 4CB23CA819B457AD004FCF10 /* EditGroupViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = EditGroupViewController.h; sourceTree = ""; }; + 4CB23CA919B457AD004FCF10 /* EditGroupViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = EditGroupViewController.m; sourceTree = ""; }; + 4CB23CAA19B457AD004FCF10 /* EditGroupViewController.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = EditGroupViewController.xib; sourceTree = ""; }; + 4CB23CAD19B4590D004FCF10 /* EditGroupViewCell.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = EditGroupViewCell.h; sourceTree = ""; }; + 4CB23CAE19B4590D004FCF10 /* EditGroupViewCell.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = EditGroupViewCell.m; sourceTree = ""; }; + 4CB3D91819F4A22800DC9B9D /* ShieldGroupMessageAPI.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ShieldGroupMessageAPI.h; sourceTree = ""; }; + 4CB3D91919F4A22800DC9B9D /* ShieldGroupMessageAPI.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ShieldGroupMessageAPI.m; sourceTree = ""; }; + 4CB3D91B19F4B48200DC9B9D /* LogoutAPI.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = LogoutAPI.h; sourceTree = ""; }; + 4CB3D91C19F4B48200DC9B9D /* LogoutAPI.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = LogoutAPI.m; sourceTree = ""; }; + 4CB3D91E19F4FA7F00DC9B9D /* SearchContentViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SearchContentViewController.h; sourceTree = ""; }; + 4CB3D91F19F4FA7F00DC9B9D /* SearchContentViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SearchContentViewController.m; sourceTree = ""; }; + 4CB58EAA1991FF98006B24D3 /* DDepartment.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = DDepartment.h; path = ../TCPAPI/DDepartment.h; sourceTree = ""; }; + 4CB58EAB1991FF98006B24D3 /* DDepartment.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = DDepartment.m; path = ../TCPAPI/DDepartment.m; sourceTree = ""; }; + 4CB6AA0B198F7F550075BDB4 /* ChatEditTableViewCell.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ChatEditTableViewCell.h; sourceTree = ""; }; + 4CB6AA0C198F7F550075BDB4 /* ChatEditTableViewCell.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ChatEditTableViewCell.m; sourceTree = ""; }; + 4CB8F6C119A6D97D00C4C27D /* IOSDuoduo Tests-Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = "IOSDuoduo Tests-Info.plist"; sourceTree = ""; }; + 4CB8F6C319A6D97D00C4C27D /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/InfoPlist.strings; sourceTree = ""; }; + 4CB8F6C519A6D97D00C4C27D /* IOSDuoduo_Tests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = IOSDuoduo_Tests.m; sourceTree = ""; }; + 4CB8F6C719A6D97D00C4C27D /* IOSDuoduo Tests-Prefix.pch */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "IOSDuoduo Tests-Prefix.pch"; sourceTree = ""; }; + 4CB8F6D119A7171800C4C27D /* DDContactsCell.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DDContactsCell.h; sourceTree = ""; }; + 4CB8F6D219A7171800C4C27D /* DDContactsCell.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = DDContactsCell.m; sourceTree = ""; }; + 4CC35AA71A83097200E6224D /* GetLatestMsgId.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = GetLatestMsgId.h; sourceTree = ""; }; + 4CC35AA81A83097200E6224D /* GetLatestMsgId.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GetLatestMsgId.m; sourceTree = ""; }; + 4CC35AAA1A83585E00E6224D /* GetMsgByMsgIDsAPI.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = GetMsgByMsgIDsAPI.h; sourceTree = ""; }; + 4CC35AAB1A83585E00E6224D /* GetMsgByMsgIDsAPI.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GetMsgByMsgIDsAPI.m; sourceTree = ""; }; + 4CC41F811A4D120600DE434F /* PublicProfileCell.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PublicProfileCell.h; sourceTree = ""; }; + 4CC41F821A4D120600DE434F /* PublicProfileCell.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = PublicProfileCell.m; sourceTree = ""; }; + 4CD156581998A36300B11233 /* DDAddMemberToGroupAPI.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DDAddMemberToGroupAPI.h; sourceTree = ""; }; + 4CD156591998A36300B11233 /* DDAddMemberToGroupAPI.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = DDAddMemberToGroupAPI.m; sourceTree = ""; }; + 4CD1565A1998A36300B11233 /* DDFixedGroupAPI.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DDFixedGroupAPI.h; sourceTree = ""; }; + 4CD1565B1998A36300B11233 /* DDFixedGroupAPI.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = DDFixedGroupAPI.m; sourceTree = ""; }; + 4CD1565E1998A36300B11233 /* MsgReadACKAPI.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = MsgReadACKAPI.h; path = ../../MsgReadACKAPI.h; sourceTree = ""; }; + 4CD1565F1998A36300B11233 /* MsgReadACKAPI.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = MsgReadACKAPI.m; path = ../../MsgReadACKAPI.m; sourceTree = ""; }; + 4CD156621998A36300B11233 /* DDReceiveGroupAddMemberAPI.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DDReceiveGroupAddMemberAPI.h; sourceTree = ""; }; + 4CD156631998A36300B11233 /* DDReceiveGroupAddMemberAPI.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = DDReceiveGroupAddMemberAPI.m; sourceTree = ""; }; + 4CD156761998B70D00B11233 /* DDGroupModule.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DDGroupModule.h; sourceTree = ""; }; + 4CD156771998B70D00B11233 /* DDGroupModule.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = DDGroupModule.m; sourceTree = ""; }; + 4CD3EDD91A0C6FE100795A0C /* NSString+Additions.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "NSString+Additions.h"; sourceTree = ""; }; + 4CD3EDDA1A0C6FE100795A0C /* NSString+Additions.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "NSString+Additions.m"; sourceTree = ""; }; + 4CD995F3199F420700025C9C /* DDBaseEntity.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DDBaseEntity.h; sourceTree = ""; }; + 4CD995F4199F420700025C9C /* DDBaseEntity.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = DDBaseEntity.m; sourceTree = ""; }; + 4CE135E619C91EB20098A5E4 /* SendPushTokenAPI.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SendPushTokenAPI.h; sourceTree = ""; }; + 4CE135E719C91EB20098A5E4 /* SendPushTokenAPI.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SendPushTokenAPI.m; sourceTree = ""; }; + 4CE95F2F19AAD0E8000CD0C6 /* ContactAvatarTools.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ContactAvatarTools.h; sourceTree = ""; }; + 4CE95F3019AAD0E8000CD0C6 /* ContactAvatarTools.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ContactAvatarTools.m; sourceTree = ""; }; + 4CF7D522198A268500F0272B /* JSDismissiveTextView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JSDismissiveTextView.h; sourceTree = ""; }; + 4CF7D523198A268500F0272B /* JSDismissiveTextView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = JSDismissiveTextView.m; sourceTree = ""; }; + 4CF7D524198A268500F0272B /* JSMessageInputView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JSMessageInputView.h; sourceTree = ""; }; + 4CF7D525198A268500F0272B /* JSMessageInputView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = JSMessageInputView.m; sourceTree = ""; }; + 4CF7D526198A268500F0272B /* JSMessageTextView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JSMessageTextView.h; sourceTree = ""; }; + 4CF7D527198A268500F0272B /* JSMessageTextView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = JSMessageTextView.m; sourceTree = ""; }; + 4CFC9FB01A4412E3002E7A5A /* MsgReadNotify.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MsgReadNotify.h; sourceTree = ""; }; + 4CFC9FB11A4412E3002E7A5A /* MsgReadNotify.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MsgReadNotify.m; sourceTree = ""; }; + 5C1C2E789271519490720734 /* Pods.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = Pods.debug.xcconfig; path = "Pods/Target Support Files/Pods/Pods.debug.xcconfig"; sourceTree = ""; }; + 81419D121A53EAD900E25D46 /* libPods-ProtocolBuffers.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; name = "libPods-ProtocolBuffers.a"; path = "Pods/build/Debug-iphoneos/libPods-ProtocolBuffers.a"; sourceTree = ""; }; + 81B75A111A58CC090039E5B5 /* search_bar.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = search_bar.png; path = resources/search_bar.png; sourceTree = ""; }; + 81B75A121A58CC090039E5B5 /* search_bar@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = "search_bar@2x.png"; path = "resources/search_bar@2x.png"; sourceTree = ""; }; + 81B75A151A58CC1F0039E5B5 /* logo.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = logo.png; path = resources/logo.png; sourceTree = ""; }; + 81B75A171A58CCC90039E5B5 /* phone.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = phone.png; path = resources/phone.png; sourceTree = ""; }; + 81B75A181A58CCC90039E5B5 /* phone@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = "phone@2x.png"; path = "resources/phone@2x.png"; sourceTree = ""; }; + 81B75A1B1A58CD830039E5B5 /* right.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = right.png; path = resources/right.png; sourceTree = ""; }; + 81B75A1C1A58CD830039E5B5 /* right@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = "right@2x.png"; path = "resources/right@2x.png"; sourceTree = ""; }; + 81B75A1F1A58CD8C0039E5B5 /* left.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = left.png; path = resources/left.png; sourceTree = ""; }; + 81B75A201A58CD8C0039E5B5 /* left@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = "left@2x.png"; path = "resources/left@2x.png"; sourceTree = ""; }; + C46061D5194E9D8A00FF3966 /* SystemConfiguration.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = SystemConfiguration.framework; path = System/Library/Frameworks/SystemConfiguration.framework; sourceTree = SDKROOT; }; + C46061D7194E9D9300FF3966 /* MobileCoreServices.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = MobileCoreServices.framework; path = System/Library/Frameworks/MobileCoreServices.framework; sourceTree = SDKROOT; }; + C485E8E419F78D800061DAFE /* FinderViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = FinderViewController.h; sourceTree = ""; }; + C485E8E519F78D800061DAFE /* FinderViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = FinderViewController.m; sourceTree = ""; }; + C485E8E619F78D800061DAFE /* FinderViewController.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = FinderViewController.xib; sourceTree = ""; }; + C485E8E919F7CB630061DAFE /* OpenSourcePRViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = OpenSourcePRViewController.h; sourceTree = ""; }; + C485E8EA19F7CB630061DAFE /* OpenSourcePRViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = OpenSourcePRViewController.m; sourceTree = ""; }; + C485E8EC19F7D6250061DAFE /* WifiViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = WifiViewController.h; sourceTree = ""; }; + C485E8ED19F7D6250061DAFE /* WifiViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = WifiViewController.m; sourceTree = ""; }; + C493DDCC1962A50900B39106 /* NSDate+DDAddition.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "NSDate+DDAddition.h"; sourceTree = ""; }; + C493DDCD1962A50900B39106 /* NSDate+DDAddition.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "NSDate+DDAddition.m"; sourceTree = ""; }; + C493DDCE1962A50900B39106 /* NSDictionary+JSON.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "NSDictionary+JSON.h"; sourceTree = ""; }; + C493DDCF1962A50900B39106 /* NSDictionary+JSON.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "NSDictionary+JSON.m"; sourceTree = ""; }; + C493DDD01962A50900B39106 /* NSDictionary+Safe.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "NSDictionary+Safe.h"; sourceTree = ""; }; + C493DDD11962A50900B39106 /* NSDictionary+Safe.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "NSDictionary+Safe.m"; sourceTree = ""; }; + C493DDD21962A50900B39106 /* NSIndexSet+AQIndexesOutsideSet.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "NSIndexSet+AQIndexesOutsideSet.h"; sourceTree = ""; }; + C493DDD31962A50900B39106 /* NSIndexSet+AQIndexesOutsideSet.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "NSIndexSet+AQIndexesOutsideSet.m"; sourceTree = ""; }; + C493DDD41962A50900B39106 /* NSIndexSet+AQIsSetContiguous.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "NSIndexSet+AQIsSetContiguous.h"; sourceTree = ""; }; + C493DDD51962A50900B39106 /* NSIndexSet+AQIsSetContiguous.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "NSIndexSet+AQIsSetContiguous.m"; sourceTree = ""; }; + C493DDDA1962A50900B39106 /* NSString+DDPath.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "NSString+DDPath.h"; sourceTree = ""; }; + C493DDDB1962A50900B39106 /* NSString+DDPath.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "NSString+DDPath.m"; sourceTree = ""; }; + C493DDDC1962A50900B39106 /* NSString+JSMessagesView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "NSString+JSMessagesView.h"; sourceTree = ""; }; + C493DDDD1962A50900B39106 /* NSString+JSMessagesView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "NSString+JSMessagesView.m"; sourceTree = ""; }; + C493DDDE1962A50900B39106 /* UIButton+JSMessagesView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "UIButton+JSMessagesView.h"; sourceTree = ""; }; + C493DDDF1962A50900B39106 /* UIButton+JSMessagesView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "UIButton+JSMessagesView.m"; sourceTree = ""; }; + C493DDE01962A50900B39106 /* UIColor+AQGridView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "UIColor+AQGridView.h"; sourceTree = ""; }; + C493DDE11962A50900B39106 /* UIColor+AQGridView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "UIColor+AQGridView.m"; sourceTree = ""; }; + C493DDE21962A50900B39106 /* UIColor+JSMessagesView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "UIColor+JSMessagesView.h"; sourceTree = ""; }; + C493DDE31962A50900B39106 /* UIColor+JSMessagesView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "UIColor+JSMessagesView.m"; sourceTree = ""; }; + C493DDE61962A50900B39106 /* UIImage+JSMessagesView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "UIImage+JSMessagesView.h"; sourceTree = ""; }; + C493DDE71962A50900B39106 /* UIImage+JSMessagesView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "UIImage+JSMessagesView.m"; sourceTree = ""; }; + C493DDE81962A50900B39106 /* UIView+AnimationOptionsForCurve.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "UIView+AnimationOptionsForCurve.h"; sourceTree = ""; }; + C493DDE91962A50900B39106 /* UIView+AnimationOptionsForCurve.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "UIView+AnimationOptionsForCurve.m"; sourceTree = ""; }; + C493DDEA1962A50900B39106 /* UIView+DDAddition.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "UIView+DDAddition.h"; sourceTree = ""; }; + C493DDEB1962A50900B39106 /* UIView+DDAddition.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "UIView+DDAddition.m"; sourceTree = ""; }; + C493DDEC1962A50900B39106 /* DDCONSTANT.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DDCONSTANT.h; sourceTree = ""; }; + C493DDEE1962A50900B39106 /* DDMessageEntity.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DDMessageEntity.h; sourceTree = ""; }; + C493DDEF1962A50900B39106 /* DDMessageEntity.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = DDMessageEntity.mm; sourceTree = ""; }; + C493DDF01962A50900B39106 /* SessionEntity.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SessionEntity.h; sourceTree = ""; }; + C493DDF11962A50900B39106 /* SessionEntity.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SessionEntity.m; sourceTree = ""; }; + C493DDF21962A50900B39106 /* DDUserEntity.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DDUserEntity.h; sourceTree = ""; }; + C493DDF31962A50900B39106 /* DDUserEntity.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = DDUserEntity.m; sourceTree = ""; }; + C493DDF81962A50900B39106 /* DDDatabaseUtil.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DDDatabaseUtil.h; sourceTree = ""; }; + C493DDF91962A50900B39106 /* DDDatabaseUtil.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = DDDatabaseUtil.m; sourceTree = ""; }; + C493DDFE1962A50900B39106 /* DDAFClient.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DDAFClient.h; sourceTree = ""; }; + C493DDFF1962A50900B39106 /* DDAFClient.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = DDAFClient.m; sourceTree = ""; }; + C493DE051962A50900B39106 /* DDHttpServer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DDHttpServer.h; sourceTree = ""; }; + C493DE061962A50900B39106 /* DDHttpServer.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = DDHttpServer.m; sourceTree = ""; }; + C493DE0B1962A50900B39106 /* DDMsgServer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DDMsgServer.h; sourceTree = ""; }; + C493DE0C1962A50900B39106 /* DDMsgServer.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = DDMsgServer.m; sourceTree = ""; }; + C493DE0D1962A50900B39106 /* DDTcpServer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DDTcpServer.h; sourceTree = ""; }; + C493DE0E1962A50900B39106 /* DDTcpServer.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = DDTcpServer.m; sourceTree = ""; }; + C493DE121962A50900B39106 /* DDMessageModule.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DDMessageModule.h; sourceTree = ""; }; + C493DE131962A50900B39106 /* DDMessageModule.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = DDMessageModule.m; sourceTree = ""; }; + C493DE141962A50900B39106 /* DDMessageSendManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DDMessageSendManager.h; sourceTree = ""; }; + C493DE151962A50900B39106 /* DDMessageSendManager.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = DDMessageSendManager.mm; sourceTree = ""; }; + C493DE171962A50900B39106 /* DDUserModule.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DDUserModule.h; sourceTree = ""; }; + C493DE181962A50900B39106 /* DDUserModule.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = DDUserModule.m; sourceTree = ""; }; + C493DE571962A50900B39106 /* DDClientState.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DDClientState.h; sourceTree = ""; }; + C493DE581962A50900B39106 /* DDClientState.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = DDClientState.m; sourceTree = ""; }; + C493DE591962A50900B39106 /* DDClientStateMaintenanceManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DDClientStateMaintenanceManager.h; sourceTree = ""; }; + C493DE5A1962A50900B39106 /* DDClientStateMaintenanceManager.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = DDClientStateMaintenanceManager.m; sourceTree = ""; }; + C493DE5B1962A50900B39106 /* std.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = std.m; sourceTree = ""; }; + C493DE5D1962A50900B39106 /* DDNotificationHelp.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DDNotificationHelp.h; sourceTree = ""; }; + C493DE5E1962A50900B39106 /* DDNotificationHelp.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = DDNotificationHelp.m; sourceTree = ""; }; + C493DE5F1962A50900B39106 /* DDSundriesCenter.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DDSundriesCenter.h; sourceTree = ""; }; + C493DE601962A50900B39106 /* DDSundriesCenter.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = DDSundriesCenter.m; sourceTree = ""; }; + C493DE621962A50900B39106 /* DataOutputStream+Addition.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "DataOutputStream+Addition.h"; sourceTree = ""; }; + C493DE631962A50900B39106 /* DataOutputStream+Addition.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "DataOutputStream+Addition.m"; sourceTree = ""; }; + C493DE641962A50900B39106 /* DDAPISchedule.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DDAPISchedule.h; sourceTree = ""; }; + C493DE651962A50900B39106 /* DDAPISchedule.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = DDAPISchedule.m; sourceTree = ""; }; + C493DE661962A50900B39106 /* DDAPIScheduleProtocol.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DDAPIScheduleProtocol.h; sourceTree = ""; }; + C493DE671962A50900B39106 /* DDAPIUnrequestScheduleProtocol.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DDAPIUnrequestScheduleProtocol.h; sourceTree = ""; }; + C493DE681962A50900B39106 /* DDDataInputStream.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DDDataInputStream.h; sourceTree = ""; }; + C493DE691962A50900B39106 /* DDDataInputStream.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = DDDataInputStream.m; sourceTree = ""; }; + C493DE6A1962A50900B39106 /* DDDataOutputStream.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DDDataOutputStream.h; sourceTree = ""; }; + C493DE6B1962A50900B39106 /* DDDataOutputStream.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = DDDataOutputStream.m; sourceTree = ""; }; + C493DE6C1962A50900B39106 /* DDReachability.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DDReachability.h; sourceTree = ""; }; + C493DE6D1962A50900B39106 /* DDReachability.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = DDReachability.m; sourceTree = ""; }; + C493DE6E1962A50900B39106 /* DDSendBuffer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DDSendBuffer.h; sourceTree = ""; }; + C493DE6F1962A50900B39106 /* DDSendBuffer.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = DDSendBuffer.m; sourceTree = ""; }; + C493DE701962A50900B39106 /* DDSuperAPI.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DDSuperAPI.h; sourceTree = ""; }; + C493DE711962A50900B39106 /* DDSuperAPI.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = DDSuperAPI.m; sourceTree = ""; }; + C493DE721962A50900B39106 /* DDTcpClientManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DDTcpClientManager.h; sourceTree = ""; }; + C493DE731962A50900B39106 /* DDTcpClientManager.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = DDTcpClientManager.m; sourceTree = ""; }; + C493DE741962A50900B39106 /* DDTcpProtocolHeader.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DDTcpProtocolHeader.h; sourceTree = ""; }; + C493DE751962A50900B39106 /* DDTcpProtocolHeader.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = DDTcpProtocolHeader.m; sourceTree = ""; }; + C493DE761962A50900B39106 /* DDUnrequestSuperAPI.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DDUnrequestSuperAPI.h; sourceTree = ""; }; + C493DE771962A50900B39106 /* DDUnrequestSuperAPI.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = DDUnrequestSuperAPI.m; sourceTree = ""; }; + C493DE781962A50900B39106 /* NSStream+NSStreamAddition.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "NSStream+NSStreamAddition.h"; sourceTree = ""; }; + C493DE791962A50900B39106 /* NSStream+NSStreamAddition.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "NSStream+NSStreamAddition.m"; sourceTree = ""; }; + C493DE7F1962A50900B39106 /* HeartbeatAPI.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = HeartbeatAPI.h; sourceTree = ""; }; + C493DE801962A50900B39106 /* HeartbeatAPI.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = HeartbeatAPI.m; sourceTree = ""; }; + C493DE811962A50900B39106 /* LoginAPI.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = LoginAPI.h; sourceTree = ""; }; + C493DE821962A50900B39106 /* LoginAPI.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = LoginAPI.mm; sourceTree = ""; }; + C493DE881962A50900B39106 /* GetUnreadMessagesAPI.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = GetUnreadMessagesAPI.h; sourceTree = ""; }; + C493DE891962A50900B39106 /* GetUnreadMessagesAPI.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GetUnreadMessagesAPI.m; sourceTree = ""; }; + C493DE8A1962A50900B39106 /* SendMessageAPI.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SendMessageAPI.h; sourceTree = ""; }; + C493DE8B1962A50900B39106 /* SendMessageAPI.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SendMessageAPI.m; sourceTree = ""; }; + C493DE8E1962A50900B39106 /* DDSendPhotoMessageAPI.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DDSendPhotoMessageAPI.h; sourceTree = ""; }; + C493DE8F1962A50900B39106 /* DDSendPhotoMessageAPI.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = DDSendPhotoMessageAPI.m; sourceTree = ""; }; + C493DE9B1962A50900B39106 /* ReceiveKickoffAPI.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ReceiveKickoffAPI.h; sourceTree = ""; }; + C493DE9C1962A50900B39106 /* ReceiveKickoffAPI.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ReceiveKickoffAPI.m; sourceTree = ""; }; + C493DE9E1962A50900B39106 /* DDReceiveMessageAPI.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DDReceiveMessageAPI.h; sourceTree = ""; }; + C493DE9F1962A50900B39106 /* DDReceiveMessageAPI.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = DDReceiveMessageAPI.m; sourceTree = ""; }; + C493DEA21962A50900B39106 /* AQGridView+CellLayout.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "AQGridView+CellLayout.h"; sourceTree = ""; }; + C493DEA31962A50900B39106 /* AQGridView+CellLocationDelegation.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "AQGridView+CellLocationDelegation.h"; sourceTree = ""; }; + C493DEA41962A50900B39106 /* AQGridView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = AQGridView.h; sourceTree = ""; }; + C493DEA51962A50900B39106 /* AQGridView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = AQGridView.m; sourceTree = ""; }; + C493DEA61962A50900B39106 /* AQGridViewAnimatorItem.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = AQGridViewAnimatorItem.h; sourceTree = ""; }; + C493DEA71962A50900B39106 /* AQGridViewAnimatorItem.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = AQGridViewAnimatorItem.m; sourceTree = ""; }; + C493DEA81962A50900B39106 /* AQGridViewCell+AQGridViewCellPrivate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "AQGridViewCell+AQGridViewCellPrivate.h"; sourceTree = ""; }; + C493DEA91962A50900B39106 /* AQGridViewCell.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = AQGridViewCell.h; sourceTree = ""; }; + C493DEAA1962A50900B39106 /* AQGridViewCell.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = AQGridViewCell.m; sourceTree = ""; }; + C493DEAB1962A50900B39106 /* AQGridViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = AQGridViewController.h; sourceTree = ""; }; + C493DEAC1962A50900B39106 /* AQGridViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = AQGridViewController.m; sourceTree = ""; }; + C493DEAD1962A50900B39106 /* AQGridViewData.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = AQGridViewData.h; sourceTree = ""; }; + C493DEAE1962A50900B39106 /* AQGridViewData.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = AQGridViewData.m; sourceTree = ""; }; + C493DEAF1962A50900B39106 /* AQGridViewUpdateInfo.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = AQGridViewUpdateInfo.h; sourceTree = ""; }; + C493DEB01962A50900B39106 /* AQGridViewUpdateInfo.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = AQGridViewUpdateInfo.m; sourceTree = ""; }; + C493DEB11962A50900B39106 /* AQGridViewUpdateItem.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = AQGridViewUpdateItem.h; sourceTree = ""; }; + C493DEB21962A50900B39106 /* AQGridViewUpdateItem.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = AQGridViewUpdateItem.m; sourceTree = ""; }; + C493DEE11962A50900B39106 /* DDChatBaseCell.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DDChatBaseCell.h; sourceTree = ""; }; + C493DEE21962A50900B39106 /* DDChatBaseCell.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = DDChatBaseCell.m; sourceTree = ""; }; + C493DEE31962A50900B39106 /* DDChatCellProtocol.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DDChatCellProtocol.h; sourceTree = ""; }; + C493DEE41962A50900B39106 /* DDChatImageCell.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DDChatImageCell.h; sourceTree = ""; }; + C493DEE51962A50900B39106 /* DDChatImageCell.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = DDChatImageCell.m; sourceTree = ""; }; + C493DEE61962A50900B39106 /* DDChatImagePreviewViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DDChatImagePreviewViewController.h; sourceTree = ""; }; + C493DEE71962A50900B39106 /* DDChatImagePreviewViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = DDChatImagePreviewViewController.m; sourceTree = ""; }; + C493DEE81962A50900B39106 /* DDChatTextCell.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DDChatTextCell.h; sourceTree = ""; }; + C493DEE91962A50900B39106 /* DDChatTextCell.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = DDChatTextCell.m; sourceTree = ""; }; + C493DEEA1962A50900B39106 /* DDChatTextCell.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = DDChatTextCell.xib; sourceTree = ""; }; + C493DEEB1962A50900B39106 /* DDChatVoiceCell.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DDChatVoiceCell.h; sourceTree = ""; }; + C493DEEC1962A50900B39106 /* DDChatVoiceCell.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = DDChatVoiceCell.m; sourceTree = ""; }; + C493DEEF1962A50900B39106 /* DDPromptCell.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DDPromptCell.h; sourceTree = ""; }; + C493DEF01962A50900B39106 /* DDPromptCell.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = DDPromptCell.m; sourceTree = ""; }; + C493DEF21962A50900B39106 /* DDAlbumDetailsViewControll.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DDAlbumDetailsViewControll.h; sourceTree = ""; }; + C493DEF31962A50900B39106 /* DDAlbumDetailsViewControll.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = DDAlbumDetailsViewControll.m; sourceTree = ""; }; + C493DEF41962A50900B39106 /* AlbumViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = AlbumViewController.h; sourceTree = ""; }; + C493DEF51962A50900B39106 /* AlbumViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = AlbumViewController.m; sourceTree = ""; }; + C493DEF81962A50900B39106 /* ChatUtilityViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ChatUtilityViewController.h; sourceTree = ""; }; + C493DEF91962A50900B39106 /* ChatUtilityViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ChatUtilityViewController.m; sourceTree = ""; }; + C493DEFA1962A50900B39106 /* EmojiFaceView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = EmojiFaceView.h; sourceTree = ""; }; + C493DEFB1962A50900B39106 /* EmojiFaceView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = EmojiFaceView.m; sourceTree = ""; }; + C493DEFC1962A50900B39106 /* EmotionsModule.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = EmotionsModule.h; sourceTree = ""; }; + C493DEFD1962A50900B39106 /* EmotionsModule.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = EmotionsModule.m; sourceTree = ""; }; + C493DEFE1962A50900B39106 /* EmotionsViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = EmotionsViewController.h; sourceTree = ""; }; + C493DEFF1962A50900B39106 /* EmotionsViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = EmotionsViewController.m; sourceTree = ""; }; + C493DF021962A50900B39106 /* AnalysisImage.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = AnalysisImage.h; sourceTree = ""; }; + C493DF031962A50900B39106 /* AnalysisImage.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = AnalysisImage.m; sourceTree = ""; }; + C493DF061962A50900B39106 /* ChattingMainViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ChattingMainViewController.h; sourceTree = ""; }; + C493DF071962A50900B39106 /* ChattingMainViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ChattingMainViewController.m; sourceTree = ""; }; + C493DF081962A50900B39106 /* ChattingMainViewController.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = ChattingMainViewController.xib; sourceTree = ""; }; + C493DF091962A50900B39106 /* ChattingModule.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ChattingModule.h; sourceTree = ""; }; + C493DF0A1962A50900B39106 /* ChattingModule.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ChattingModule.m; sourceTree = ""; }; + C493DF0E1962A50900B39106 /* MenuImageView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MenuImageView.h; sourceTree = ""; }; + C493DF0F1962A50900B39106 /* MenuImageView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MenuImageView.m; sourceTree = ""; }; + C493DF101962A50900B39106 /* RecordingView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RecordingView.h; sourceTree = ""; }; + C493DF111962A50900B39106 /* RecordingView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RecordingView.m; sourceTree = ""; }; + C493DF121962A50900B39106 /* TouchDownGestureRecognizer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = TouchDownGestureRecognizer.h; sourceTree = ""; }; + C493DF131962A50900B39106 /* TouchDownGestureRecognizer.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = TouchDownGestureRecognizer.m; sourceTree = ""; }; + C493DF141962A50900B39106 /* AlbumDetailsBottomBar.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = AlbumDetailsBottomBar.h; sourceTree = ""; }; + C493DF151962A50900B39106 /* AlbumDetailsBottomBar.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = AlbumDetailsBottomBar.m; sourceTree = ""; }; + C493DF181962A50900B39106 /* LoginModule.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = LoginModule.h; sourceTree = ""; }; + C493DF191962A50900B39106 /* LoginModule.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = LoginModule.m; sourceTree = ""; }; + C493DF1D1962A50900B39106 /* Photo.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Photo.h; sourceTree = ""; }; + C493DF1E1962A50900B39106 /* Photo.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = Photo.m; sourceTree = ""; }; + C493DF1F1962A50900B39106 /* PhotosCache.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PhotosCache.h; sourceTree = ""; }; + C493DF201962A50900B39106 /* PhotosCache.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = PhotosCache.m; sourceTree = ""; }; + C493DF211962A50900B39106 /* ImageGridViewCell.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = ImageGridViewCell.h; path = ../../ImageGridViewCell.h; sourceTree = ""; }; + C493DF221962A50900B39106 /* ImageGridViewCell.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = ImageGridViewCell.m; path = ../../ImageGridViewCell.m; sourceTree = ""; }; + C493DF241962A50900B39106 /* RecentUserCell.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RecentUserCell.h; sourceTree = ""; }; + C493DF251962A50900B39106 /* RecentUserCell.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RecentUserCell.m; sourceTree = ""; }; + C493DF261962A50900B39106 /* RecentUserCell.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = RecentUserCell.xib; sourceTree = ""; }; + C493DF271962A50900B39106 /* RecentUsersViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RecentUsersViewController.h; sourceTree = ""; }; + C493DF281962A50900B39106 /* RecentUsersViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RecentUsersViewController.m; sourceTree = ""; }; + C493DF291962A50900B39106 /* RecentUsersViewController.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = RecentUsersViewController.xib; sourceTree = ""; }; + C493DF2F1962A50900B39106 /* config.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = config.h; sourceTree = ""; }; + C493DF311962A50900B39106 /* bitwise.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = bitwise.c; sourceTree = ""; }; + C493DF321962A50900B39106 /* framing.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = framing.c; sourceTree = ""; }; + C493DF341962A50900B39106 /* ogg.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ogg.h; sourceTree = ""; }; + C493DF351962A50900B39106 /* os_types.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = os_types.h; sourceTree = ""; }; + C493DF371962A50900B39106 /* _kiss_fft_guts.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = _kiss_fft_guts.h; sourceTree = ""; }; + C493DF381962A50900B39106 /* arch.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = arch.h; sourceTree = ""; }; + C493DF391962A50900B39106 /* bits.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = bits.c; sourceTree = ""; }; + C493DF3A1962A50900B39106 /* buffer.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = buffer.c; sourceTree = ""; }; + C493DF3B1962A50900B39106 /* cb_search.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = cb_search.c; sourceTree = ""; }; + C493DF3C1962A50900B39106 /* cb_search.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = cb_search.h; sourceTree = ""; }; + C493DF3D1962A50900B39106 /* cb_search_arm4.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = cb_search_arm4.h; sourceTree = ""; }; + C493DF3E1962A50900B39106 /* cb_search_bfin.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = cb_search_bfin.h; sourceTree = ""; }; + C493DF3F1962A50900B39106 /* cb_search_sse.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = cb_search_sse.h; sourceTree = ""; }; + C493DF401962A50900B39106 /* exc_10_16_table.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = exc_10_16_table.c; sourceTree = ""; }; + C493DF411962A50900B39106 /* exc_10_32_table.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = exc_10_32_table.c; sourceTree = ""; }; + C493DF421962A50900B39106 /* exc_20_32_table.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = exc_20_32_table.c; sourceTree = ""; }; + C493DF431962A50900B39106 /* exc_5_256_table.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = exc_5_256_table.c; sourceTree = ""; }; + C493DF441962A50900B39106 /* exc_5_64_table.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = exc_5_64_table.c; sourceTree = ""; }; + C493DF451962A50900B39106 /* exc_8_128_table.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = exc_8_128_table.c; sourceTree = ""; }; + C493DF461962A50900B39106 /* fftwrap.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = fftwrap.c; sourceTree = ""; }; + C493DF471962A50900B39106 /* fftwrap.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = fftwrap.h; sourceTree = ""; }; + C493DF481962A50900B39106 /* filterbank.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = filterbank.c; sourceTree = ""; }; + C493DF491962A50900B39106 /* filterbank.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = filterbank.h; sourceTree = ""; }; + C493DF4A1962A50900B39106 /* filters.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = filters.c; sourceTree = ""; }; + C493DF4B1962A50900B39106 /* filters.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = filters.h; sourceTree = ""; }; + C493DF4C1962A50900B39106 /* filters_arm4.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = filters_arm4.h; sourceTree = ""; }; + C493DF4D1962A50900B39106 /* filters_bfin.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = filters_bfin.h; sourceTree = ""; }; + C493DF4E1962A50900B39106 /* filters_sse.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = filters_sse.h; sourceTree = ""; }; + C493DF4F1962A50900B39106 /* fixed_arm4.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = fixed_arm4.h; sourceTree = ""; }; + C493DF501962A50900B39106 /* fixed_arm5e.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = fixed_arm5e.h; sourceTree = ""; }; + C493DF511962A50900B39106 /* fixed_bfin.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = fixed_bfin.h; sourceTree = ""; }; + C493DF521962A50900B39106 /* fixed_debug.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = fixed_debug.h; sourceTree = ""; }; + C493DF531962A50900B39106 /* fixed_generic.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = fixed_generic.h; sourceTree = ""; }; + C493DF541962A50900B39106 /* gain_table.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = gain_table.c; sourceTree = ""; }; + C493DF551962A50900B39106 /* gain_table_lbr.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = gain_table_lbr.c; sourceTree = ""; }; + C493DF561962A50900B39106 /* hexc_10_32_table.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = hexc_10_32_table.c; sourceTree = ""; }; + C493DF571962A50900B39106 /* hexc_table.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = hexc_table.c; sourceTree = ""; }; + C493DF581962A50900B39106 /* high_lsp_tables.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = high_lsp_tables.c; sourceTree = ""; }; + C493DF591962A50900B39106 /* jitter.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = jitter.c; sourceTree = ""; }; + C493DF5A1962A50900B39106 /* kiss_fft.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = kiss_fft.c; sourceTree = ""; }; + C493DF5B1962A50900B39106 /* kiss_fft.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = kiss_fft.h; sourceTree = ""; }; + C493DF5C1962A50900B39106 /* kiss_fftr.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = kiss_fftr.c; sourceTree = ""; }; + C493DF5D1962A50900B39106 /* kiss_fftr.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = kiss_fftr.h; sourceTree = ""; }; + C493DF5E1962A50900B39106 /* lpc.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = lpc.c; sourceTree = ""; }; + C493DF5F1962A50900B39106 /* lpc.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = lpc.h; sourceTree = ""; }; + C493DF601962A50900B39106 /* lpc_bfin.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = lpc_bfin.h; sourceTree = ""; }; + C493DF611962A50900B39106 /* lsp.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = lsp.c; sourceTree = ""; }; + C493DF621962A50900B39106 /* lsp.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = lsp.h; sourceTree = ""; }; + C493DF631962A50900B39106 /* lsp_bfin.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = lsp_bfin.h; sourceTree = ""; }; + C493DF641962A50900B39106 /* lsp_tables_nb.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = lsp_tables_nb.c; sourceTree = ""; }; + C493DF651962A50900B39106 /* ltp.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = ltp.c; sourceTree = ""; }; + C493DF661962A50900B39106 /* ltp.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ltp.h; sourceTree = ""; }; + C493DF671962A50900B39106 /* ltp_arm4.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ltp_arm4.h; sourceTree = ""; }; + C493DF681962A50900B39106 /* ltp_bfin.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ltp_bfin.h; sourceTree = ""; }; + C493DF691962A50900B39106 /* ltp_sse.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ltp_sse.h; sourceTree = ""; }; + C493DF6A1962A50900B39106 /* math_approx.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = math_approx.h; sourceTree = ""; }; + C493DF6B1962A50900B39106 /* mdf.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = mdf.c; sourceTree = ""; }; + C493DF6C1962A50900B39106 /* misc_bfin.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = misc_bfin.h; sourceTree = ""; }; + C493DF6D1962A50900B39106 /* modes.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = modes.c; sourceTree = ""; }; + C493DF6E1962A50900B39106 /* modes.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = modes.h; sourceTree = ""; }; + C493DF6F1962A50900B39106 /* modes_wb.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = modes_wb.c; sourceTree = ""; }; + C493DF701962A50900B39106 /* nb_celp.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = nb_celp.c; sourceTree = ""; }; + C493DF711962A50900B39106 /* nb_celp.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = nb_celp.h; sourceTree = ""; }; + C493DF721962A50900B39106 /* os_support.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = os_support.h; sourceTree = ""; }; + C493DF731962A50900B39106 /* preprocess.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = preprocess.c; sourceTree = ""; }; + C493DF741962A50900B39106 /* pseudofloat.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = pseudofloat.h; sourceTree = ""; }; + C493DF751962A50900B39106 /* quant_lsp.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = quant_lsp.c; sourceTree = ""; }; + C493DF761962A50900B39106 /* quant_lsp.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = quant_lsp.h; sourceTree = ""; }; + C493DF771962A50900B39106 /* quant_lsp_bfin.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = quant_lsp_bfin.h; sourceTree = ""; }; + C493DF781962A50900B39106 /* resample.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = resample.c; sourceTree = ""; }; + C493DF791962A50900B39106 /* resample_sse.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = resample_sse.h; sourceTree = ""; }; + C493DF7A1962A50900B39106 /* sb_celp.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = sb_celp.c; sourceTree = ""; }; + C493DF7B1962A50900B39106 /* sb_celp.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = sb_celp.h; sourceTree = ""; }; + C493DF7C1962A50900B39106 /* scal.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = scal.c; sourceTree = ""; }; + C493DF7D1962A50900B39106 /* smallft.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = smallft.c; sourceTree = ""; }; + C493DF7E1962A50900B39106 /* smallft.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = smallft.h; sourceTree = ""; }; + C493DF801962A50900B39106 /* speex.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = speex.h; sourceTree = ""; }; + C493DF811962A50900B39106 /* speex_bits.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = speex_bits.h; sourceTree = ""; }; + C493DF821962A50900B39106 /* speex_buffer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = speex_buffer.h; sourceTree = ""; }; + C493DF831962A50900B39106 /* speex_callbacks.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = speex_callbacks.h; sourceTree = ""; }; + C493DF841962A50900B39106 /* speex_config_types.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = speex_config_types.h; sourceTree = ""; }; + C493DF851962A50900B39106 /* speex_config_types.h.in */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = speex_config_types.h.in; sourceTree = ""; }; + C493DF861962A50900B39106 /* speex_echo.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = speex_echo.h; sourceTree = ""; }; + C493DF871962A50900B39106 /* speex_header.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = speex_header.h; sourceTree = ""; }; + C493DF881962A50900B39106 /* speex_jitter.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = speex_jitter.h; sourceTree = ""; }; + C493DF891962A50900B39106 /* speex_preprocess.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = speex_preprocess.h; sourceTree = ""; }; + C493DF8A1962A50900B39106 /* speex_resampler.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = speex_resampler.h; sourceTree = ""; }; + C493DF8B1962A50900B39106 /* speex_stereo.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = speex_stereo.h; sourceTree = ""; }; + C493DF8C1962A50900B39106 /* speex_types.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = speex_types.h; sourceTree = ""; }; + C493DF8D1962A50900B39106 /* speex.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = speex.c; sourceTree = ""; }; + C493DF8E1962A50900B39106 /* speex_callbacks.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = speex_callbacks.c; sourceTree = ""; }; + C493DF8F1962A50900B39106 /* speex_header.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = speex_header.c; sourceTree = ""; }; + C493DF901962A50900B39106 /* stack_alloc.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = stack_alloc.h; sourceTree = ""; }; + C493DF911962A50900B39106 /* stereo.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = stereo.c; sourceTree = ""; }; + C493DF921962A50900B39106 /* vbr.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = vbr.c; sourceTree = ""; }; + C493DF931962A50900B39106 /* vbr.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = vbr.h; sourceTree = ""; }; + C493DF941962A50900B39106 /* vorbis_psy.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = vorbis_psy.h; sourceTree = ""; }; + C493DF951962A50900B39106 /* vq.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = vq.c; sourceTree = ""; }; + C493DF961962A50900B39106 /* vq.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = vq.h; sourceTree = ""; }; + C493DF971962A50900B39106 /* vq_arm4.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = vq_arm4.h; sourceTree = ""; }; + C493DF981962A50900B39106 /* vq_bfin.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = vq_bfin.h; sourceTree = ""; }; + C493DF991962A50900B39106 /* vq_sse.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = vq_sse.h; sourceTree = ""; }; + C493DF9A1962A50900B39106 /* window.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = window.c; sourceTree = ""; }; + C493DF9C1962A50900B39106 /* AQRecorder.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = AQRecorder.h; sourceTree = ""; }; + C493DF9D1962A50900B39106 /* AQRecorder.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = AQRecorder.mm; sourceTree = ""; }; + C493DF9F1962A50900B39106 /* SpeexAllHeaders.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SpeexAllHeaders.h; sourceTree = ""; }; + C493DFA01962A50900B39106 /* SpeexCodec.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SpeexCodec.h; sourceTree = ""; }; + C493DFA11962A50900B39106 /* SpeexCodec.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SpeexCodec.m; sourceTree = ""; }; + C493DFA21962A50900B39106 /* Decapsulator.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Decapsulator.h; sourceTree = ""; }; + C493DFA31962A50900B39106 /* Decapsulator.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = Decapsulator.m; sourceTree = ""; }; + C493DFA41962A50900B39106 /* Encapsulator.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Encapsulator.h; sourceTree = ""; }; + C493DFA51962A50900B39106 /* Encapsulator.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = Encapsulator.m; sourceTree = ""; }; + C493DFA61962A50900B39106 /* PlayerManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PlayerManager.h; sourceTree = ""; }; + C493DFA71962A50900B39106 /* PlayerManager.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = PlayerManager.m; sourceTree = ""; }; + C493DFA91962A50900B39106 /* CADebugMacros.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = CADebugMacros.cpp; sourceTree = ""; }; + C493DFAA1962A50900B39106 /* CADebugMacros.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CADebugMacros.h; sourceTree = ""; }; + C493DFAB1962A50900B39106 /* CAMath.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CAMath.h; sourceTree = ""; }; + C493DFAC1962A50900B39106 /* CAStreamBasicDescription.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = CAStreamBasicDescription.cpp; sourceTree = ""; }; + C493DFAD1962A50900B39106 /* CAStreamBasicDescription.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CAStreamBasicDescription.h; sourceTree = ""; }; + C493DFAE1962A50900B39106 /* CAXException.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = CAXException.cpp; sourceTree = ""; }; + C493DFAF1962A50900B39106 /* CAXException.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CAXException.h; sourceTree = ""; }; + C493DFB01962A50900B39106 /* RawAudioDataPlayer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RawAudioDataPlayer.h; sourceTree = ""; }; + C493DFB11962A50900B39106 /* RawAudioDataPlayer.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RawAudioDataPlayer.m; sourceTree = ""; }; + C493DFB21962A50900B39106 /* RecorderManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RecorderManager.h; sourceTree = ""; }; + C493DFB31962A50900B39106 /* RecorderManager.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = RecorderManager.mm; sourceTree = ""; }; + C493DFB41962A50900B39106 /* SpeexAllHeaders.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SpeexAllHeaders.h; sourceTree = ""; }; + C493DFB51962A50900B39106 /* XLog.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = XLog.h; sourceTree = ""; }; + C493E0AE1962A53C00B39106 /* std.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = std.h; sourceTree = ""; }; + C493E0AF1962A54900B39106 /* TeamTalk-Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = "TeamTalk-Info.plist"; sourceTree = ""; }; + C493E0B11962A54F00B39106 /* main.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = ""; }; + C493E0B31962A62100B39106 /* TeamTalk-Prefix.pch */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = "TeamTalk-Prefix.pch"; path = "IOSDuoduo/TeamTalk-Prefix.pch"; sourceTree = ""; }; + C4AFD7D5193D67350054ECFD /* AVFoundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = AVFoundation.framework; path = System/Library/Frameworks/AVFoundation.framework; sourceTree = SDKROOT; }; + C4AFD882193D7B490054ECFD /* CoreAudio.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreAudio.framework; path = System/Library/Frameworks/CoreAudio.framework; sourceTree = SDKROOT; }; + C4AFD884193D7B580054ECFD /* AudioToolbox.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = AudioToolbox.framework; path = System/Library/Frameworks/AudioToolbox.framework; sourceTree = SDKROOT; }; + C4EBA734192F279100B72723 /* TeamTalk.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = TeamTalk.app; sourceTree = BUILT_PRODUCTS_DIR; }; + C4EBA737192F279100B72723 /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = System/Library/Frameworks/Foundation.framework; sourceTree = SDKROOT; }; + C4EBA739192F279100B72723 /* CoreGraphics.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreGraphics.framework; path = System/Library/Frameworks/CoreGraphics.framework; sourceTree = SDKROOT; }; + C4EBA73B192F279100B72723 /* UIKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = UIKit.framework; path = System/Library/Frameworks/UIKit.framework; sourceTree = SDKROOT; }; + C4EBA750192F279100B72723 /* XCTest.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = XCTest.framework; path = Library/Frameworks/XCTest.framework; sourceTree = DEVELOPER_DIR; }; + C4EBA758192F279100B72723 /* TeamTalkTests-Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = "TeamTalkTests-Info.plist"; sourceTree = ""; }; + C4EBA75A192F279100B72723 /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/InfoPlist.strings; sourceTree = ""; }; + C4EBA75C192F279100B72723 /* IOSDuoduoTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = IOSDuoduoTests.m; sourceTree = ""; }; +/* End PBXFileReference section */ + +/* Begin PBXFrameworksBuildPhase section */ + C4EBA731192F279100B72723 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + 4C88A0C519D50FFA0071DA9C /* libz.dylib in Frameworks */, + C46061D8194E9D9300FF3966 /* MobileCoreServices.framework in Frameworks */, + C46061D6194E9D8A00FF3966 /* SystemConfiguration.framework in Frameworks */, + 4C92D7CD1ABA67EC00709CC6 /* libsecurity.a in Frameworks */, + C4AFD885193D7B580054ECFD /* AudioToolbox.framework in Frameworks */, + C4AFD883193D7B490054ECFD /* CoreAudio.framework in Frameworks */, + C4AFD7D6193D67350054ECFD /* AVFoundation.framework in Frameworks */, + C4EBA73A192F279100B72723 /* CoreGraphics.framework in Frameworks */, + C4EBA73C192F279100B72723 /* UIKit.framework in Frameworks */, + C4EBA738192F279100B72723 /* Foundation.framework in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXFrameworksBuildPhase section */ + +/* Begin PBXGroup section */ + 4C0C0F091A314DF00094CCD2 /* Session */ = { + isa = PBXGroup; + children = ( + 4C0C0F0A1A314E060094CCD2 /* SessionModule.h */, + 4C0C0F0B1A314E060094CCD2 /* SessionModule.m */, + ); + name = Session; + sourceTree = ""; + }; + 4C1367ED194AF9440094E87D /* New Group */ = { + isa = PBXGroup; + children = ( + C4EBA735192F279100B72723 /* Products */, + ); + name = "New Group"; + sourceTree = ""; + }; + 4C3A75091A8C861E009400A2 /* RuntimeStatus */ = { + isa = PBXGroup; + children = ( + 4C3A750A1A8C861E009400A2 /* RuntimeStatus.h */, + 4C3A750B1A8C861E009400A2 /* RuntimeStatus.m */, + ); + path = RuntimeStatus; + sourceTree = ""; + }; + 4C5FE9A01A491F6D00B3DD44 /* Sequencer */ = { + isa = PBXGroup; + children = ( + 4C3A74FD1A8C8577009400A2 /* Sequencer.h */, + 4C3A74FE1A8C8577009400A2 /* Sequencer.m */, + ); + name = Sequencer; + sourceTree = ""; + }; + 4C62FA421A6E7CA1008F60EE /* emotions */ = { + isa = PBXGroup; + children = ( + 4C3A74A61A8C84C9009400A2 /* 221.gif */, + 4C3A74A71A8C84C9009400A2 /* 221@2x.gif */, + 4C3A74A81A8C84C9009400A2 /* 222.gif */, + 4C3A74A91A8C84C9009400A2 /* 222@2x.gif */, + 4C3A74AA1A8C84C9009400A2 /* 223.gif */, + 4C3A74AB1A8C84C9009400A2 /* 223@2x.gif */, + 4C3A74AC1A8C84C9009400A2 /* 224.gif */, + 4C3A74AD1A8C84C9009400A2 /* 224@2x.gif */, + 4C3A74AE1A8C84C9009400A2 /* 225.gif */, + 4C3A74AF1A8C84C9009400A2 /* 225@2x.gif */, + 4C3A74B01A8C84C9009400A2 /* 226.gif */, + 4C3A74B11A8C84C9009400A2 /* 226@2x.gif */, + 4C3A74B21A8C84C9009400A2 /* 227.gif */, + 4C3A74B31A8C84C9009400A2 /* 227@2x.gif */, + 4C3A74B41A8C84C9009400A2 /* 228.gif */, + 4C3A74B51A8C84C9009400A2 /* 228@2x.gif */, + 4C3A74B61A8C84C9009400A2 /* 229.gif */, + 4C3A74B71A8C84C9009400A2 /* 229@2x.gif */, + 4C3A74B81A8C84C9009400A2 /* 230.gif */, + 4C3A74B91A8C84C9009400A2 /* 230@2x.gif */, + 4C3A74BA1A8C84C9009400A2 /* 231.gif */, + 4C3A74BB1A8C84C9009400A2 /* 231@2x.gif */, + 4C3A74BC1A8C84C9009400A2 /* 232.gif */, + 4C3A74BD1A8C84C9009400A2 /* 232@2x.gif */, + 4C3A74BE1A8C84C9009400A2 /* 233.gif */, + 4C3A74BF1A8C84C9009400A2 /* 233@2x.gif */, + 4C3A74C01A8C84C9009400A2 /* 234.gif */, + 4C3A74C11A8C84C9009400A2 /* 234@2x.gif */, + 4C3A74C21A8C84C9009400A2 /* 235.gif */, + 4C3A74C31A8C84C9009400A2 /* 235@2x.gif */, + 4C3A74C41A8C84C9009400A2 /* 236.gif */, + 4C3A74C51A8C84C9009400A2 /* 236@2x.gif */, + 4C3A74C61A8C84C9009400A2 /* 237.gif */, + 4C3A74C71A8C84C9009400A2 /* 237@2x.gif */, + 4C3A74C81A8C84C9009400A2 /* 238.gif */, + 4C3A74C91A8C84C9009400A2 /* 238@2x.gif */, + 4C3A74CA1A8C84C9009400A2 /* 239.gif */, + 4C3A74CB1A8C84C9009400A2 /* 239@2x.gif */, + 4C3A74CC1A8C84C9009400A2 /* 240.gif */, + 4C3A74CD1A8C84C9009400A2 /* 240@2x.gif */, + ); + name = emotions; + sourceTree = ""; + }; + 4C6BBC1D1A7F532F0028B892 /* Security */ = { + isa = PBXGroup; + children = ( + 4C92D7CC1ABA67EC00709CC6 /* libsecurity.a */, + 4C4169E21AB815E600B753FE /* security.h */, + ); + name = Security; + sourceTree = ""; + }; + 4C8DC3BF1A5F778C00C8BF5A /* User */ = { + isa = PBXGroup; + children = ( + 4C21749519C197F3006F4BFC /* DDUserDetailInfoAPI.h */, + 4C21749619C197F3006F4BFC /* DDUserDetailInfoAPI.m */, + 4C837EE7197F949300C3D758 /* DDAllUserAPI.h */, + 4C837EE8197F949300C3D758 /* DDAllUserAPI.m */, + ); + name = User; + sourceTree = ""; + }; + 4C9C7FDB1A4A4CBC00A58066 /* LevelDB */ = { + isa = PBXGroup; + children = ( + 4C3A75001A8C85C1009400A2 /* DBHelper.h */, + 4C3A75011A8C85C1009400A2 /* DBHelper.mm */, + 4C3A75021A8C85C1009400A2 /* DBManager.h */, + 4C3A75031A8C85C1009400A2 /* DBManager.m */, + ); + name = LevelDB; + sourceTree = ""; + }; + 4CA50CCA19A47B7A0032DE24 /* Search */ = { + isa = PBXGroup; + children = ( + 4CA50CCE19A47C690032DE24 /* DDSearch.h */, + 4CA50CCF19A47C690032DE24 /* DDSearch.m */, + 4CA50CCB19A47B9A0032DE24 /* SpellLibrary.h */, + 4CA50CCC19A47B9A0032DE24 /* SpellLibrary.m */, + ); + name = Search; + sourceTree = ""; + }; + 4CB8F6BF19A6D97D00C4C27D /* IOSDuoduo Tests */ = { + isa = PBXGroup; + children = ( + 4CB8F6C519A6D97D00C4C27D /* IOSDuoduo_Tests.m */, + 4CB8F6C019A6D97D00C4C27D /* Supporting Files */, + ); + path = "IOSDuoduo Tests"; + sourceTree = ""; + }; + 4CB8F6C019A6D97D00C4C27D /* Supporting Files */ = { + isa = PBXGroup; + children = ( + 4CB8F6C119A6D97D00C4C27D /* IOSDuoduo Tests-Info.plist */, + 4CB8F6C219A6D97D00C4C27D /* InfoPlist.strings */, + 4CB8F6C719A6D97D00C4C27D /* IOSDuoduo Tests-Prefix.pch */, + ); + name = "Supporting Files"; + sourceTree = ""; + }; + 4CC134E21A493FD90016A0C2 /* PB */ = { + isa = PBXGroup; + children = ( + 4C79D2B41AB7C9A500706E32 /* IMBaseDefine.pb.h */, + 4C79D2B51AB7C9A500706E32 /* IMBaseDefine.pb.m */, + 4C79D2B61AB7C9A500706E32 /* IMBuddy.pb.h */, + 4C79D2B71AB7C9A500706E32 /* IMBuddy.pb.m */, + 4C79D2B81AB7C9A500706E32 /* IMGroup.pb.h */, + 4C79D2B91AB7C9A500706E32 /* IMGroup.pb.m */, + 4C79D2BA1AB7C9A500706E32 /* IMLogin.pb.h */, + 4C79D2BB1AB7C9A500706E32 /* IMLogin.pb.m */, + 4C79D2BC1AB7C9A500706E32 /* IMMessage.pb.h */, + 4C79D2BD1AB7C9A500706E32 /* IMMessage.pb.m */, + 4C79D2BE1AB7C9A500706E32 /* IMOther.pb.h */, + 4C79D2BF1AB7C9A500706E32 /* IMOther.pb.m */, + ); + name = PB; + sourceTree = ""; + }; + 4CC41F7D1A4BBA6A00DE434F /* Group */ = { + isa = PBXGroup; + children = ( + 4CB3D91819F4A22800DC9B9D /* ShieldGroupMessageAPI.h */, + 4CB3D91919F4A22800DC9B9D /* ShieldGroupMessageAPI.m */, + 4CD156581998A36300B11233 /* DDAddMemberToGroupAPI.h */, + 4CD156591998A36300B11233 /* DDAddMemberToGroupAPI.m */, + 4C5CA05E19C13341007CE792 /* DDDeleteMemberFromGroupAPI.h */, + 4C5CA05F19C13341007CE792 /* DDDeleteMemberFromGroupAPI.m */, + 4CD1565A1998A36300B11233 /* DDFixedGroupAPI.h */, + 4CD1565B1998A36300B11233 /* DDFixedGroupAPI.m */, + 4CD156621998A36300B11233 /* DDReceiveGroupAddMemberAPI.h */, + 4CD156631998A36300B11233 /* DDReceiveGroupAddMemberAPI.m */, + 4C837F44197F954500C3D758 /* DDCreateGroupAPI.h */, + 4C837F45197F954500C3D758 /* DDCreateGroupAPI.m */, + 4C31EB5419CAB471004A3B2C /* GetGroupInfoAPi.h */, + 4C31EB5519CAB471004A3B2C /* GetGroupInfoAPi.m */, + ); + name = Group; + sourceTree = ""; + }; + 4CE2F7C519B0242000415778 /* resources */ = { + isa = PBXGroup; + children = ( + 4C62FA421A6E7CA1008F60EE /* emotions */, + 81B75A111A58CC090039E5B5 /* search_bar.png */, + 81B75A121A58CC090039E5B5 /* search_bar@2x.png */, + 4CA6CDA91A2C1F6E00405BB6 /* add.png */, + 4CA6CDAA1A2C1F6E00405BB6 /* add@2x.png */, + 4C3A74F61A8C84F7009400A2 /* delImage.png */, + 4C3A74F71A8C84F7009400A2 /* delImage@2x.png */, + 4CA6CDAB1A2C1F6E00405BB6 /* chat.png */, + 4CA6CDAC1A2C1F6E00405BB6 /* chat@2x.png */, + 4CA6CDAD1A2C1F6E00405BB6 /* contact_selected.png */, + 4CA6CDAE1A2C1F6E00405BB6 /* contact_selected@2x.png */, + 4CA6CDAF1A2C1F6E00405BB6 /* contact.png */, + 4CA6CDB01A2C1F6E00405BB6 /* contact@2x.png */, + 4CA6CDB11A2C1F6E00405BB6 /* conversation_selected.png */, + 4CA6CDB21A2C1F6E00405BB6 /* conversation_selected@2x.png */, + 4CA6CDB31A2C1F6E00405BB6 /* conversation.png */, + 4CA6CDB41A2C1F6E00405BB6 /* conversation@2x.png */, + 4CA6CDB51A2C1F6E00405BB6 /* dd_album.png */, + 4CA6CDB61A2C1F6E00405BB6 /* dd_album@2x.png */, + 4CA6CDB71A2C1F6E00405BB6 /* dd_cancel_send_record.png */, + 4CA6CDB81A2C1F6E00405BB6 /* dd_cancel_send_record@2x.png */, + 4CA6CDB91A2C1F6E00405BB6 /* dd_emoji_delete.png */, + 4CA6CDBA1A2C1F6E00405BB6 /* dd_emoji_delete@2x.png */, + 4CA6CDBB1A2C1F6E00405BB6 /* dd_emotion.png */, + 4CA6CDBC1A2C1F6E00405BB6 /* dd_emotion@2x.png */, + 4CA6CDBD1A2C1F6E00405BB6 /* dd_has_unread_message.png */, + 4CA6CDBE1A2C1F6E00405BB6 /* dd_has_unread_message@2x.png */, + 4CA6CDBF1A2C1F6E00405BB6 /* dd_image_send.png */, + 4CA6CDC01A2C1F6E00405BB6 /* dd_image_send@2x.png */, + 4CA6CDC11A2C1F6E00405BB6 /* dd_input_normal.png */, + 4CA6CDC21A2C1F6E00405BB6 /* dd_input_normal@2x.png */, + 4CA6CDC31A2C1F6E00405BB6 /* dd_left_voice_one.png */, + 4CA6CDC41A2C1F6E00405BB6 /* dd_left_voice_one@2x.png */, + 4CA6CDC51A2C1F6E00405BB6 /* dd_left_voice_three.png */, + 4CA6CDC61A2C1F6E00405BB6 /* dd_left_voice_three@2x.png */, + 4CA6CDC71A2C1F6E00405BB6 /* dd_left_voice_two.png */, + 4CA6CDC81A2C1F6E00405BB6 /* dd_left_voice_two@2x.png */, + 4CA6CDC91A2C1F6E00405BB6 /* dd_photo_back.png */, + 4CA6CDCA1A2C1F6E00405BB6 /* dd_photo_back@2x.png */, + 4CA6CDCB1A2C1F6E00405BB6 /* dd_press_to_say_normal.png */, + 4CA6CDCC1A2C1F6E00405BB6 /* dd_press_to_say_normal@2x.png */, + 4CA6CDCD1A2C1F6E00405BB6 /* dd_preview_select.png */, + 4CA6CDCE1A2C1F6E00405BB6 /* dd_preview_select@2x.png */, + 4CA6CDD01A2C1F6E00405BB6 /* dd_recent_contacts.png */, + 4CA6CDD11A2C1F6E00405BB6 /* dd_recent_contacts@2x.png */, + 4CA6CDD21A2C1F6E00405BB6 /* dd_record_normal.png */, + 4CA6CDD31A2C1F6E00405BB6 /* dd_record_normal@2x.png */, + 4CA6CDD41A2C1F6E00405BB6 /* dd_record_release_end.png */, + 4CA6CDD51A2C1F6E00405BB6 /* dd_record_release_end@2x.png */, + 4CA6CDD61A2C1F6E00405BB6 /* dd_record_too_short.png */, + 4CA6CDD71A2C1F6E00405BB6 /* dd_record_too_short@2x.png */, + 4CA6CDD81A2C1F6E00405BB6 /* dd_recording.png */, + 4CA6CDD91A2C1F6E00405BB6 /* dd_recording@2x.png */, + 4CA6CDDA1A2C1F6E00405BB6 /* dd_right_voice_one.png */, + 4CA6CDDB1A2C1F6E00405BB6 /* dd_right_voice_one@2x.png */, + 4CA6CDDC1A2C1F6E00405BB6 /* dd_right_voice_three.png */, + 4CA6CDDD1A2C1F6E00405BB6 /* dd_right_voice_three@2x.png */, + 4CA6CDDE1A2C1F6E00405BB6 /* dd_right_voice_two.png */, + 4CA6CDDF1A2C1F6E00405BB6 /* dd_right_voice_two@2x.png */, + 4CA6CDE01A2C1F6E00405BB6 /* dd_selected_photo.png */, + 4CA6CDE11A2C1F6E00405BB6 /* dd_selected_photo@2x.png */, + 4CA6CDE21A2C1F6E00405BB6 /* dd_send_failed.png */, + 4CA6CDE31A2C1F6E00405BB6 /* dd_send_failed@2x.png */, + 4CA6CDE41A2C1F6E00405BB6 /* dd_take-photo.png */, + 4CA6CDE51A2C1F6E00405BB6 /* dd_take-photo@2x.png */, + 4CA6CDE61A2C1F6E00405BB6 /* dd_utility.png */, + 4CA6CDE71A2C1F6E00405BB6 /* dd_utility@2x.png */, + 4CA6CDE81A2C1F6E00405BB6 /* dd_volumn.png */, + 4CA6CDE91A2C1F6E00405BB6 /* dd_volumn@2x.png */, + 4CA6CDEA1A2C1F6E00405BB6 /* delete.png */, + 4CA6CDEB1A2C1F6E00405BB6 /* delete@2x.png */, + 4CA6CDEC1A2C1F6E00405BB6 /* edit.png */, + 4CA6CDED1A2C1F6E00405BB6 /* edit@2x.png */, + 4CA6CDEE1A2C1F6E00405BB6 /* email.png */, + 4CA6CDEF1A2C1F6E00405BB6 /* email@2x.png */, + 4CA6CDF01A2C1F6E00405BB6 /* group_default.png */, + 4CA6CDF11A2C1F6E00405BB6 /* group_default@2x.png */, + 4CA6CDF21A2C1F6E00405BB6 /* jiantou.png */, + 81B75A171A58CCC90039E5B5 /* phone.png */, + 81B75A181A58CCC90039E5B5 /* phone@2x.png */, + 81B75A151A58CC1F0039E5B5 /* logo.png */, + 4CA6CDF31A2C1F6E00405BB6 /* jiantou@2x.png */, + 4CA6CDF71A2C1F6E00405BB6 /* loginlogo.jpg */, + 4CA6CDF81A2C1F6E00405BB6 /* loginlogo.png */, + 4CA6CDF91A2C1F6E00405BB6 /* msg.caf */, + 4CA6CDFA1A2C1F6E00405BB6 /* myprofile_selected.png */, + 4CA6CDFB1A2C1F6E00405BB6 /* myprofile_selected@2x.png */, + 4CA6CDFC1A2C1F6E00405BB6 /* myprofile.png */, + 4CA6CDFD1A2C1F6E00405BB6 /* myprofile@2x.png */, + 4CA6CDFE1A2C1F6E00405BB6 /* password.png */, + 4CA6CDFF1A2C1F6E00405BB6 /* password@2x.png */, + 4CA6CE021A2C1F6E00405BB6 /* select.png */, + 4CA6CE031A2C1F6E00405BB6 /* select@2x.png */, + 4CA6CE041A2C1F6E00405BB6 /* setting.png */, + 4CA6CE051A2C1F6E00405BB6 /* setting@2x.png */, + 4CA6CE061A2C1F6E00405BB6 /* star.png */, + 4CA6CE071A2C1F6E00405BB6 /* star@2x.png */, + 4CA6CE081A2C1F6E00405BB6 /* TeamTalk.xcworkspace */, + 81B75A1F1A58CD8C0039E5B5 /* left.png */, + 81B75A201A58CD8C0039E5B5 /* left@2x.png */, + 4CA6CE091A2C1F6E00405BB6 /* tel.png */, + 4CA6CE0A1A2C1F6E00405BB6 /* tel@2x.png */, + 4CA6CE0B1A2C1F6E00405BB6 /* unselected.png */, + 81B75A1B1A58CD830039E5B5 /* right.png */, + 81B75A1C1A58CD830039E5B5 /* right@2x.png */, + 4CA6CE0C1A2C1F6E00405BB6 /* unselected@2x.png */, + 4CA6CE0D1A2C1F6E00405BB6 /* username.png */, + 4CA6CE0E1A2C1F6E00405BB6 /* username@2x.png */, + 4CA6CE0F1A2C1F6E00405BB6 /* x.png */, + 4CA6CE101A2C1F6E00405BB6 /* x@2x.png */, + ); + name = resources; + sourceTree = ""; + }; + A8257D727D24C0F620C5BCBC /* Pods */ = { + isa = PBXGroup; + children = ( + 5C1C2E789271519490720734 /* Pods.debug.xcconfig */, + 19B78DA8A3707C0C507EF626 /* Pods.release.xcconfig */, + ); + name = Pods; + sourceTree = ""; + }; + C485E8E319F78D380061DAFE /* Finder */ = { + isa = PBXGroup; + children = ( + 4C77C28E1A8852F8001E5885 /* ScanQRCodePage.h */, + 4C77C28F1A8852F8001E5885 /* ScanQRCodePage.m */, + 4C77C2901A8852F8001E5885 /* ScanQRCodePage.xib */, + 4CA6CE7D1A2C1FBA00405BB6 /* LoginViewController.xib */, + 4CA6CE791A2C1FA700405BB6 /* LoginViewController.h */, + 4CA6CE7A1A2C1FA700405BB6 /* LoginViewController.m */, + C485E8E419F78D800061DAFE /* FinderViewController.h */, + C485E8E519F78D800061DAFE /* FinderViewController.m */, + C485E8E619F78D800061DAFE /* FinderViewController.xib */, + C485E8E919F7CB630061DAFE /* OpenSourcePRViewController.h */, + C485E8EA19F7CB630061DAFE /* OpenSourcePRViewController.m */, + C485E8EC19F7D6250061DAFE /* WifiViewController.h */, + C485E8ED19F7D6250061DAFE /* WifiViewController.m */, + ); + name = Finder; + sourceTree = ""; + }; + C493DDCA1962A50900B39106 /* TeamTalk */ = { + isa = PBXGroup; + children = ( + 4C3A75101A8C865A009400A2 /* DDAppDelegate.h */, + 4C3A75111A8C865A009400A2 /* DDAppDelegate.m */, + 4C3A750D1A8C8650009400A2 /* TTHttpsRequest.h */, + 4C3A750E1A8C8650009400A2 /* TTHttpsRequest.m */, + 4C3A75091A8C861E009400A2 /* RuntimeStatus */, + 4CA50CCA19A47B7A0032DE24 /* Search */, + C493E0AE1962A53C00B39106 /* std.h */, + C493DE5B1962A50900B39106 /* std.m */, + C493DDEC1962A50900B39106 /* DDCONSTANT.h */, + C493DDCB1962A50900B39106 /* Category */, + C493DDED1962A50900B39106 /* Entity */, + C493DDF61962A50900B39106 /* Module */, + C493DE561962A50900B39106 /* StateMaintance */, + C493DE5C1962A50900B39106 /* SundriesCenter */, + C493DE611962A50900B39106 /* TCPAPI */, + C493DEA01962A50900B39106 /* ThridFramework */, + C493DEC71962A50900B39106 /* ToRemove */, + C493DEDE1962A50900B39106 /* VC */, + C493DF2C1962A50900B39106 /* Voice */, + C493DFB51962A50900B39106 /* XLog.h */, + 4C39B7FD1974D6E4001B4AEF /* Images.xcassets */, + ); + name = TeamTalk; + path = IOSDuoduo; + sourceTree = ""; + }; + C493DDCB1962A50900B39106 /* Category */ = { + isa = PBXGroup; + children = ( + 4CD3EDD91A0C6FE100795A0C /* NSString+Additions.h */, + 4CD3EDDA1A0C6FE100795A0C /* NSString+Additions.m */, + C493DDCC1962A50900B39106 /* NSDate+DDAddition.h */, + C493DDCD1962A50900B39106 /* NSDate+DDAddition.m */, + C493DDCE1962A50900B39106 /* NSDictionary+JSON.h */, + C493DDCF1962A50900B39106 /* NSDictionary+JSON.m */, + C493DDD01962A50900B39106 /* NSDictionary+Safe.h */, + C493DDD11962A50900B39106 /* NSDictionary+Safe.m */, + C493DDD21962A50900B39106 /* NSIndexSet+AQIndexesOutsideSet.h */, + C493DDD31962A50900B39106 /* NSIndexSet+AQIndexesOutsideSet.m */, + C493DDD41962A50900B39106 /* NSIndexSet+AQIsSetContiguous.h */, + C493DDD51962A50900B39106 /* NSIndexSet+AQIsSetContiguous.m */, + C493DDDA1962A50900B39106 /* NSString+DDPath.h */, + C493DDDB1962A50900B39106 /* NSString+DDPath.m */, + C493DDDC1962A50900B39106 /* NSString+JSMessagesView.h */, + C493DDDD1962A50900B39106 /* NSString+JSMessagesView.m */, + C493DDDE1962A50900B39106 /* UIButton+JSMessagesView.h */, + C493DDDF1962A50900B39106 /* UIButton+JSMessagesView.m */, + C493DDE01962A50900B39106 /* UIColor+AQGridView.h */, + C493DDE11962A50900B39106 /* UIColor+AQGridView.m */, + C493DDE21962A50900B39106 /* UIColor+JSMessagesView.h */, + C493DDE31962A50900B39106 /* UIColor+JSMessagesView.m */, + C493DDE61962A50900B39106 /* UIImage+JSMessagesView.h */, + C493DDE71962A50900B39106 /* UIImage+JSMessagesView.m */, + C493DDE81962A50900B39106 /* UIView+AnimationOptionsForCurve.h */, + C493DDE91962A50900B39106 /* UIView+AnimationOptionsForCurve.m */, + C493DDEA1962A50900B39106 /* UIView+DDAddition.h */, + C493DDEB1962A50900B39106 /* UIView+DDAddition.m */, + 4CA0B9FF1A5C0E2800102EC7 /* NSData+Conversion.h */, + 4CA0BA001A5C0E2800102EC7 /* NSData+Conversion.m */, + 4C6BBC171A7B8DD40028B892 /* UIImage+UIImageAddition.h */, + 4C6BBC181A7B8DD40028B892 /* UIImage+UIImageAddition.m */, + 4C77C2931A88CFEC001E5885 /* BlurView.h */, + 4C77C2941A88CFEC001E5885 /* BlurView.m */, + ); + path = Category; + sourceTree = ""; + }; + C493DDED1962A50900B39106 /* Entity */ = { + isa = PBXGroup; + children = ( + 4CB58EAA1991FF98006B24D3 /* DDepartment.h */, + 4CB58EAB1991FF98006B24D3 /* DDepartment.m */, + 4CD995F3199F420700025C9C /* DDBaseEntity.h */, + 4CD995F4199F420700025C9C /* DDBaseEntity.m */, + 4C837F47197F95A400C3D758 /* GroupEntity.h */, + 4C837F48197F95A400C3D758 /* GroupEntity.m */, + C493DDEE1962A50900B39106 /* DDMessageEntity.h */, + C493DDEF1962A50900B39106 /* DDMessageEntity.mm */, + C493DDF01962A50900B39106 /* SessionEntity.h */, + C493DDF11962A50900B39106 /* SessionEntity.m */, + C493DDF21962A50900B39106 /* DDUserEntity.h */, + C493DDF31962A50900B39106 /* DDUserEntity.m */, + ); + path = Entity; + sourceTree = ""; + }; + C493DDF61962A50900B39106 /* Module */ = { + isa = PBXGroup; + children = ( + 4C0C0F091A314DF00094CCD2 /* Session */, + C493DDF71962A50900B39106 /* DataBase */, + C493DDFD1962A50900B39106 /* Http */, + C493DE041962A50900B39106 /* Login */, + C493DE111962A50900B39106 /* Messages */, + C493DE161962A50900B39106 /* Users */, + 4CD156761998B70D00B11233 /* DDGroupModule.h */, + 4CD156771998B70D00B11233 /* DDGroupModule.m */, + ); + path = Module; + sourceTree = ""; + }; + C493DDF71962A50900B39106 /* DataBase */ = { + isa = PBXGroup; + children = ( + C493DDF81962A50900B39106 /* DDDatabaseUtil.h */, + C493DDF91962A50900B39106 /* DDDatabaseUtil.m */, + ); + path = DataBase; + sourceTree = ""; + }; + C493DDFD1962A50900B39106 /* Http */ = { + isa = PBXGroup; + children = ( + C493DDFE1962A50900B39106 /* DDAFClient.h */, + C493DDFF1962A50900B39106 /* DDAFClient.m */, + ); + path = Http; + sourceTree = ""; + }; + C493DE041962A50900B39106 /* Login */ = { + isa = PBXGroup; + children = ( + C493DE051962A50900B39106 /* DDHttpServer.h */, + C493DE061962A50900B39106 /* DDHttpServer.m */, + C493DE0B1962A50900B39106 /* DDMsgServer.h */, + C493DE0C1962A50900B39106 /* DDMsgServer.m */, + C493DE0D1962A50900B39106 /* DDTcpServer.h */, + C493DE0E1962A50900B39106 /* DDTcpServer.m */, + ); + path = Login; + sourceTree = ""; + }; + C493DE111962A50900B39106 /* Messages */ = { + isa = PBXGroup; + children = ( + C493DE121962A50900B39106 /* DDMessageModule.h */, + C493DE131962A50900B39106 /* DDMessageModule.m */, + C493DE141962A50900B39106 /* DDMessageSendManager.h */, + C493DE151962A50900B39106 /* DDMessageSendManager.mm */, + 4C4657BB19EF5DC300334DD2 /* UnAckMessageManager.h */, + 4C4657BC19EF5DC300334DD2 /* UnAckMessageManager.m */, + ); + path = Messages; + sourceTree = ""; + }; + C493DE161962A50900B39106 /* Users */ = { + isa = PBXGroup; + children = ( + C493DE171962A50900B39106 /* DDUserModule.h */, + C493DE181962A50900B39106 /* DDUserModule.m */, + ); + path = Users; + sourceTree = ""; + }; + C493DE561962A50900B39106 /* StateMaintance */ = { + isa = PBXGroup; + children = ( + C493DE571962A50900B39106 /* DDClientState.h */, + C493DE581962A50900B39106 /* DDClientState.m */, + C493DE591962A50900B39106 /* DDClientStateMaintenanceManager.h */, + C493DE5A1962A50900B39106 /* DDClientStateMaintenanceManager.m */, + ); + path = StateMaintance; + sourceTree = ""; + }; + C493DE5C1962A50900B39106 /* SundriesCenter */ = { + isa = PBXGroup; + children = ( + C493DE5D1962A50900B39106 /* DDNotificationHelp.h */, + C493DE5E1962A50900B39106 /* DDNotificationHelp.m */, + C493DE5F1962A50900B39106 /* DDSundriesCenter.h */, + C493DE601962A50900B39106 /* DDSundriesCenter.m */, + ); + path = SundriesCenter; + sourceTree = ""; + }; + C493DE611962A50900B39106 /* TCPAPI */ = { + isa = PBXGroup; + children = ( + 4C8DC3BF1A5F778C00C8BF5A /* User */, + 4CC41F7D1A4BBA6A00DE434F /* Group */, + C493DE621962A50900B39106 /* DataOutputStream+Addition.h */, + C493DE631962A50900B39106 /* DataOutputStream+Addition.m */, + C493DE641962A50900B39106 /* DDAPISchedule.h */, + C493DE651962A50900B39106 /* DDAPISchedule.m */, + C493DE661962A50900B39106 /* DDAPIScheduleProtocol.h */, + C493DE671962A50900B39106 /* DDAPIUnrequestScheduleProtocol.h */, + C493DE681962A50900B39106 /* DDDataInputStream.h */, + C493DE691962A50900B39106 /* DDDataInputStream.m */, + C493DE6A1962A50900B39106 /* DDDataOutputStream.h */, + C493DE6B1962A50900B39106 /* DDDataOutputStream.m */, + C493DE6C1962A50900B39106 /* DDReachability.h */, + C493DE6D1962A50900B39106 /* DDReachability.m */, + C493DE6E1962A50900B39106 /* DDSendBuffer.h */, + C493DE6F1962A50900B39106 /* DDSendBuffer.m */, + 4C5D70551990C1AE009AF959 /* DDDepartmentAPI.h */, + 4C5D70561990C1AE009AF959 /* DDDepartmentAPI.m */, + C493DE701962A50900B39106 /* DDSuperAPI.h */, + 4C79D2B11AB7C19200706E32 /* GetDepartment.h */, + 4C79D2B21AB7C19200706E32 /* GetDepartment.m */, + C493DE711962A50900B39106 /* DDSuperAPI.m */, + C493DE721962A50900B39106 /* DDTcpClientManager.h */, + C493DE731962A50900B39106 /* DDTcpClientManager.m */, + C493DE741962A50900B39106 /* DDTcpProtocolHeader.h */, + C493DE751962A50900B39106 /* DDTcpProtocolHeader.m */, + C493DE761962A50900B39106 /* DDUnrequestSuperAPI.h */, + C493DE771962A50900B39106 /* DDUnrequestSuperAPI.m */, + C493DE781962A50900B39106 /* NSStream+NSStreamAddition.h */, + C493DE791962A50900B39106 /* NSStream+NSStreamAddition.m */, + 4CE135E619C91EB20098A5E4 /* SendPushTokenAPI.h */, + 4CE135E719C91EB20098A5E4 /* SendPushTokenAPI.m */, + 4C5F3F271A2EE29D003684B2 /* GetRecentSession.h */, + 4C5F3F281A2EE29D003684B2 /* GetRecentSession.mm */, + 4C5CC9B61A38221C0067B124 /* RemoveSessionAPI.h */, + 4C5CC9B71A38221C0067B124 /* RemoveSessionAPI.m */, + 4CC35AA71A83097200E6224D /* GetLatestMsgId.h */, + 4CC35AA81A83097200E6224D /* GetLatestMsgId.m */, + 4CC35AAA1A83585E00E6224D /* GetMsgByMsgIDsAPI.h */, + 4CC35AAB1A83585E00E6224D /* GetMsgByMsgIDsAPI.m */, + C493DE7A1962A50900B39106 /* RequestAPI */, + C493DE991962A50900B39106 /* UnrequestAPI */, + 4CB3D91B19F4B48200DC9B9D /* LogoutAPI.h */, + 4CB3D91C19F4B48200DC9B9D /* LogoutAPI.m */, + ); + path = TCPAPI; + sourceTree = ""; + }; + C493DE7A1962A50900B39106 /* RequestAPI */ = { + isa = PBXGroup; + children = ( + C493DE7E1962A50900B39106 /* Login */, + C493DE851962A50900B39106 /* Msg */, + ); + path = RequestAPI; + sourceTree = ""; + }; + C493DE7E1962A50900B39106 /* Login */ = { + isa = PBXGroup; + children = ( + C493DE7F1962A50900B39106 /* HeartbeatAPI.h */, + C493DE801962A50900B39106 /* HeartbeatAPI.m */, + C493DE811962A50900B39106 /* LoginAPI.h */, + C493DE821962A50900B39106 /* LoginAPI.mm */, + ); + path = Login; + sourceTree = ""; + }; + C493DE851962A50900B39106 /* Msg */ = { + isa = PBXGroup; + children = ( + 4CD1565E1998A36300B11233 /* MsgReadACKAPI.h */, + 4CD1565F1998A36300B11233 /* MsgReadACKAPI.m */, + C493DE881962A50900B39106 /* GetUnreadMessagesAPI.h */, + C493DE891962A50900B39106 /* GetUnreadMessagesAPI.m */, + C493DE8A1962A50900B39106 /* SendMessageAPI.h */, + C493DE8B1962A50900B39106 /* SendMessageAPI.m */, + C493DE8E1962A50900B39106 /* DDSendPhotoMessageAPI.h */, + C493DE8F1962A50900B39106 /* DDSendPhotoMessageAPI.m */, + 4C1CEEC61A3581160015C355 /* GetMessageQueueAPI.h */, + 4C1CEEC71A3581160015C355 /* GetMessageQueueAPI.m */, + ); + path = Msg; + sourceTree = ""; + }; + C493DE991962A50900B39106 /* UnrequestAPI */ = { + isa = PBXGroup; + children = ( + C493DE9A1962A50900B39106 /* Kickoff */, + C493DE9D1962A50900B39106 /* Msg */, + ); + path = UnrequestAPI; + sourceTree = ""; + }; + C493DE9A1962A50900B39106 /* Kickoff */ = { + isa = PBXGroup; + children = ( + C493DE9B1962A50900B39106 /* ReceiveKickoffAPI.h */, + C493DE9C1962A50900B39106 /* ReceiveKickoffAPI.m */, + ); + path = Kickoff; + sourceTree = ""; + }; + C493DE9D1962A50900B39106 /* Msg */ = { + isa = PBXGroup; + children = ( + 4CFC9FB01A4412E3002E7A5A /* MsgReadNotify.h */, + 4CFC9FB11A4412E3002E7A5A /* MsgReadNotify.m */, + C493DE9E1962A50900B39106 /* DDReceiveMessageAPI.h */, + C493DE9F1962A50900B39106 /* DDReceiveMessageAPI.m */, + 4C1E441719961889005CB2DB /* DDReceiveMessageACKAPI.h */, + 4C1E441819961889005CB2DB /* DDReceiveMessageACKAPI.m */, + ); + path = Msg; + sourceTree = ""; + }; + C493DEA01962A50900B39106 /* ThridFramework */ = { + isa = PBXGroup; + children = ( + C493DEA11962A50900B39106 /* AQ */, + ); + path = ThridFramework; + sourceTree = ""; + }; + C493DEA11962A50900B39106 /* AQ */ = { + isa = PBXGroup; + children = ( + C493DEA21962A50900B39106 /* AQGridView+CellLayout.h */, + C493DEA31962A50900B39106 /* AQGridView+CellLocationDelegation.h */, + C493DEA41962A50900B39106 /* AQGridView.h */, + C493DEA51962A50900B39106 /* AQGridView.m */, + C493DEA61962A50900B39106 /* AQGridViewAnimatorItem.h */, + C493DEA71962A50900B39106 /* AQGridViewAnimatorItem.m */, + C493DEA81962A50900B39106 /* AQGridViewCell+AQGridViewCellPrivate.h */, + C493DEA91962A50900B39106 /* AQGridViewCell.h */, + C493DEAA1962A50900B39106 /* AQGridViewCell.m */, + C493DEAB1962A50900B39106 /* AQGridViewController.h */, + C493DEAC1962A50900B39106 /* AQGridViewController.m */, + C493DEAD1962A50900B39106 /* AQGridViewData.h */, + C493DEAE1962A50900B39106 /* AQGridViewData.m */, + C493DEAF1962A50900B39106 /* AQGridViewUpdateInfo.h */, + C493DEB01962A50900B39106 /* AQGridViewUpdateInfo.m */, + C493DEB11962A50900B39106 /* AQGridViewUpdateItem.h */, + C493DEB21962A50900B39106 /* AQGridViewUpdateItem.m */, + ); + path = AQ; + sourceTree = ""; + }; + C493DEC71962A50900B39106 /* ToRemove */ = { + isa = PBXGroup; + children = ( + 4CF7D522198A268500F0272B /* JSDismissiveTextView.h */, + 4CF7D523198A268500F0272B /* JSDismissiveTextView.m */, + 4CF7D524198A268500F0272B /* JSMessageInputView.h */, + 4CF7D525198A268500F0272B /* JSMessageInputView.m */, + 4CF7D526198A268500F0272B /* JSMessageTextView.h */, + 4CF7D527198A268500F0272B /* JSMessageTextView.m */, + ); + path = ToRemove; + sourceTree = ""; + }; + C493DEDE1962A50900B39106 /* VC */ = { + isa = PBXGroup; + children = ( + 4C3A75061A8C860F009400A2 /* RootViewController.h */, + 4C3A75071A8C860F009400A2 /* RootViewController.m */, + C485E8E319F78D380061DAFE /* Finder */, + 4C837F4A197F95FF00C3D758 /* ContactsViewController.h */, + 4C837F4B197F95FF00C3D758 /* ContactsViewController.m */, + 4CE95F2F19AAD0E8000CD0C6 /* ContactAvatarTools.h */, + 4CE95F3019AAD0E8000CD0C6 /* ContactAvatarTools.m */, + 4C837F41197F952800C3D758 /* ChattingEditModule.h */, + 4C837F42197F952800C3D758 /* ChattingEditModule.m */, + 4C837F31197F94F400C3D758 /* ContactsModule.h */, + 4C837F32197F94F400C3D758 /* ContactsModule.m */, + 4CB8F6D119A7171800C4C27D /* DDContactsCell.h */, + 4CB8F6D219A7171800C4C27D /* DDContactsCell.m */, + 4C5486CD1A70EA8000ED8735 /* DDEmotionCell.h */, + 4C5486CE1A70EA8000ED8735 /* DDEmotionCell.m */, + 4C837F35197F94F400C3D758 /* PublicProfileViewControll.h */, + 4C837F36197F94F400C3D758 /* PublicProfileViewControll.m */, + 4C837F37197F94F400C3D758 /* PublicProfileViewControll.xib */, + C493DEDF1962A50900B39106 /* Chatting */, + C493DF141962A50900B39106 /* AlbumDetailsBottomBar.h */, + C493DF151962A50900B39106 /* AlbumDetailsBottomBar.m */, + C493DF181962A50900B39106 /* LoginModule.h */, + C493DF191962A50900B39106 /* LoginModule.m */, + C493DF1D1962A50900B39106 /* Photo.h */, + C493DF1E1962A50900B39106 /* Photo.m */, + C493DF1F1962A50900B39106 /* PhotosCache.h */, + C493DF201962A50900B39106 /* PhotosCache.m */, + C493DF231962A50900B39106 /* RecentContacts */, + 4C39B8041974EF18001B4AEF /* MainViewControll.h */, + 4C39B8051974EF18001B4AEF /* MainViewControll.m */, + 4CC41F811A4D120600DE434F /* PublicProfileCell.h */, + 4CC41F821A4D120600DE434F /* PublicProfileCell.m */, + 4C39B8061974EF18001B4AEF /* MainViewControll.xib */, + 4C39B80C1974F388001B4AEF /* MyProfileViewControll.h */, + 4C39B80D1974F388001B4AEF /* MyProfileViewControll.m */, + 4C39B80E1974F388001B4AEF /* MyProfileViewControll.xib */, + 4C5E374219D408CE00D1042B /* GroupAvatarImage.h */, + 4C5E374319D408CE00D1042B /* GroupAvatarImage.m */, + 4C92734619EB9C8200F6C370 /* NetwrokStatusNotifyUI.h */, + 4C92734719EB9C8200F6C370 /* NetwrokStatusNotifyUI.m */, + 4CB3D91E19F4FA7F00DC9B9D /* SearchContentViewController.h */, + 4CB3D91F19F4FA7F00DC9B9D /* SearchContentViewController.m */, + ); + path = VC; + sourceTree = ""; + }; + C493DEDF1962A50900B39106 /* Chatting */ = { + isa = PBXGroup; + children = ( + 4C837F3C197F951600C3D758 /* DDChattingEditViewController.h */, + 4C837F3D197F951600C3D758 /* DDChattingEditViewController.m */, + 4CB23CA819B457AD004FCF10 /* EditGroupViewController.h */, + 4CB23CA919B457AD004FCF10 /* EditGroupViewController.m */, + 4CB23CAA19B457AD004FCF10 /* EditGroupViewController.xib */, + 4C98355219C06F6D00DE8874 /* EditContactsCell.h */, + 4C98355319C06F6D00DE8874 /* EditContactsCell.m */, + 4CB23CAD19B4590D004FCF10 /* EditGroupViewCell.h */, + 4CB23CAE19B4590D004FCF10 /* EditGroupViewCell.m */, + 4CA50CC719A435E20032DE24 /* DDPersonEditCollectionCell.h */, + 4CA50CC819A435E20032DE24 /* DDPersonEditCollectionCell.m */, + 4CB6AA0B198F7F550075BDB4 /* ChatEditTableViewCell.h */, + 4CB6AA0C198F7F550075BDB4 /* ChatEditTableViewCell.m */, + 4C837F3E197F951600C3D758 /* DDChattingEditViewController.xib */, + C493DEE01962A50900B39106 /* Cells */, + C493DEF11962A50900B39106 /* ChatUtility */, + C493DF021962A50900B39106 /* AnalysisImage.h */, + C493DF031962A50900B39106 /* AnalysisImage.m */, + C493DF061962A50900B39106 /* ChattingMainViewController.h */, + C493DF071962A50900B39106 /* ChattingMainViewController.m */, + C493DF081962A50900B39106 /* ChattingMainViewController.xib */, + C493DF091962A50900B39106 /* ChattingModule.h */, + C493DF0A1962A50900B39106 /* ChattingModule.m */, + C493DF0E1962A50900B39106 /* MenuImageView.h */, + C493DF0F1962A50900B39106 /* MenuImageView.m */, + C493DF101962A50900B39106 /* RecordingView.h */, + C493DF111962A50900B39106 /* RecordingView.m */, + C493DF121962A50900B39106 /* TouchDownGestureRecognizer.h */, + C493DF131962A50900B39106 /* TouchDownGestureRecognizer.m */, + ); + path = Chatting; + sourceTree = ""; + }; + C493DEE01962A50900B39106 /* Cells */ = { + isa = PBXGroup; + children = ( + C493DEE11962A50900B39106 /* DDChatBaseCell.h */, + C493DEE21962A50900B39106 /* DDChatBaseCell.m */, + C493DEE31962A50900B39106 /* DDChatCellProtocol.h */, + C493DEE41962A50900B39106 /* DDChatImageCell.h */, + C493DEE51962A50900B39106 /* DDChatImageCell.m */, + C493DEE61962A50900B39106 /* DDChatImagePreviewViewController.h */, + C493DEE71962A50900B39106 /* DDChatImagePreviewViewController.m */, + C493DEE81962A50900B39106 /* DDChatTextCell.h */, + C493DEE91962A50900B39106 /* DDChatTextCell.m */, + C493DEEA1962A50900B39106 /* DDChatTextCell.xib */, + C493DEEB1962A50900B39106 /* DDChatVoiceCell.h */, + C493DEEC1962A50900B39106 /* DDChatVoiceCell.m */, + C493DEEF1962A50900B39106 /* DDPromptCell.h */, + C493DEF01962A50900B39106 /* DDPromptCell.m */, + C493DF211962A50900B39106 /* ImageGridViewCell.h */, + C493DF221962A50900B39106 /* ImageGridViewCell.m */, + ); + path = Cells; + sourceTree = ""; + }; + C493DEF11962A50900B39106 /* ChatUtility */ = { + isa = PBXGroup; + children = ( + C493DEF21962A50900B39106 /* DDAlbumDetailsViewControll.h */, + C493DEF31962A50900B39106 /* DDAlbumDetailsViewControll.m */, + C493DEF41962A50900B39106 /* AlbumViewController.h */, + C493DEF51962A50900B39106 /* AlbumViewController.m */, + C493DEF81962A50900B39106 /* ChatUtilityViewController.h */, + C493DEF91962A50900B39106 /* ChatUtilityViewController.m */, + C493DEFA1962A50900B39106 /* EmojiFaceView.h */, + C493DEFB1962A50900B39106 /* EmojiFaceView.m */, + C493DEFC1962A50900B39106 /* EmotionsModule.h */, + C493DEFD1962A50900B39106 /* EmotionsModule.m */, + C493DEFE1962A50900B39106 /* EmotionsViewController.h */, + C493DEFF1962A50900B39106 /* EmotionsViewController.m */, + ); + path = ChatUtility; + sourceTree = ""; + }; + C493DF231962A50900B39106 /* RecentContacts */ = { + isa = PBXGroup; + children = ( + C493DF241962A50900B39106 /* RecentUserCell.h */, + C493DF251962A50900B39106 /* RecentUserCell.m */, + C493DF261962A50900B39106 /* RecentUserCell.xib */, + C493DF271962A50900B39106 /* RecentUsersViewController.h */, + C493DF281962A50900B39106 /* RecentUsersViewController.m */, + C493DF291962A50900B39106 /* RecentUsersViewController.xib */, + ); + path = RecentContacts; + sourceTree = ""; + }; + C493DF2C1962A50900B39106 /* Voice */ = { + isa = PBXGroup; + children = ( + C493DF2D1962A50900B39106 /* Code */, + C493DF9B1962A50900B39106 /* manager */, + C493DFB41962A50900B39106 /* SpeexAllHeaders.h */, + ); + path = Voice; + sourceTree = ""; + }; + C493DF2D1962A50900B39106 /* Code */ = { + isa = PBXGroup; + children = ( + C493DF2E1962A50900B39106 /* Libs */, + ); + path = Code; + sourceTree = ""; + }; + C493DF2E1962A50900B39106 /* Libs */ = { + isa = PBXGroup; + children = ( + C493DF2F1962A50900B39106 /* config.h */, + C493DF301962A50900B39106 /* libogg */, + C493DF361962A50900B39106 /* libspeex */, + ); + path = Libs; + sourceTree = ""; + }; + C493DF301962A50900B39106 /* libogg */ = { + isa = PBXGroup; + children = ( + C493DF311962A50900B39106 /* bitwise.c */, + C493DF321962A50900B39106 /* framing.c */, + C493DF331962A50900B39106 /* ogg */, + ); + path = libogg; + sourceTree = ""; + }; + C493DF331962A50900B39106 /* ogg */ = { + isa = PBXGroup; + children = ( + C493DF341962A50900B39106 /* ogg.h */, + C493DF351962A50900B39106 /* os_types.h */, + ); + path = ogg; + sourceTree = ""; + }; + C493DF361962A50900B39106 /* libspeex */ = { + isa = PBXGroup; + children = ( + C493DF371962A50900B39106 /* _kiss_fft_guts.h */, + C493DF381962A50900B39106 /* arch.h */, + C493DF391962A50900B39106 /* bits.c */, + C493DF3A1962A50900B39106 /* buffer.c */, + C493DF3B1962A50900B39106 /* cb_search.c */, + C493DF3C1962A50900B39106 /* cb_search.h */, + C493DF3D1962A50900B39106 /* cb_search_arm4.h */, + C493DF3E1962A50900B39106 /* cb_search_bfin.h */, + C493DF3F1962A50900B39106 /* cb_search_sse.h */, + C493DF401962A50900B39106 /* exc_10_16_table.c */, + C493DF411962A50900B39106 /* exc_10_32_table.c */, + C493DF421962A50900B39106 /* exc_20_32_table.c */, + C493DF431962A50900B39106 /* exc_5_256_table.c */, + C493DF441962A50900B39106 /* exc_5_64_table.c */, + C493DF451962A50900B39106 /* exc_8_128_table.c */, + C493DF461962A50900B39106 /* fftwrap.c */, + C493DF471962A50900B39106 /* fftwrap.h */, + C493DF481962A50900B39106 /* filterbank.c */, + C493DF491962A50900B39106 /* filterbank.h */, + C493DF4A1962A50900B39106 /* filters.c */, + C493DF4B1962A50900B39106 /* filters.h */, + C493DF4C1962A50900B39106 /* filters_arm4.h */, + C493DF4D1962A50900B39106 /* filters_bfin.h */, + C493DF4E1962A50900B39106 /* filters_sse.h */, + C493DF4F1962A50900B39106 /* fixed_arm4.h */, + C493DF501962A50900B39106 /* fixed_arm5e.h */, + C493DF511962A50900B39106 /* fixed_bfin.h */, + C493DF521962A50900B39106 /* fixed_debug.h */, + C493DF531962A50900B39106 /* fixed_generic.h */, + C493DF541962A50900B39106 /* gain_table.c */, + C493DF551962A50900B39106 /* gain_table_lbr.c */, + C493DF561962A50900B39106 /* hexc_10_32_table.c */, + C493DF571962A50900B39106 /* hexc_table.c */, + C493DF581962A50900B39106 /* high_lsp_tables.c */, + C493DF591962A50900B39106 /* jitter.c */, + C493DF5A1962A50900B39106 /* kiss_fft.c */, + C493DF5B1962A50900B39106 /* kiss_fft.h */, + C493DF5C1962A50900B39106 /* kiss_fftr.c */, + C493DF5D1962A50900B39106 /* kiss_fftr.h */, + C493DF5E1962A50900B39106 /* lpc.c */, + C493DF5F1962A50900B39106 /* lpc.h */, + C493DF601962A50900B39106 /* lpc_bfin.h */, + C493DF611962A50900B39106 /* lsp.c */, + C493DF621962A50900B39106 /* lsp.h */, + C493DF631962A50900B39106 /* lsp_bfin.h */, + C493DF641962A50900B39106 /* lsp_tables_nb.c */, + C493DF651962A50900B39106 /* ltp.c */, + C493DF661962A50900B39106 /* ltp.h */, + C493DF671962A50900B39106 /* ltp_arm4.h */, + C493DF681962A50900B39106 /* ltp_bfin.h */, + C493DF691962A50900B39106 /* ltp_sse.h */, + C493DF6A1962A50900B39106 /* math_approx.h */, + C493DF6B1962A50900B39106 /* mdf.c */, + C493DF6C1962A50900B39106 /* misc_bfin.h */, + C493DF6D1962A50900B39106 /* modes.c */, + C493DF6E1962A50900B39106 /* modes.h */, + C493DF6F1962A50900B39106 /* modes_wb.c */, + C493DF701962A50900B39106 /* nb_celp.c */, + C493DF711962A50900B39106 /* nb_celp.h */, + C493DF721962A50900B39106 /* os_support.h */, + C493DF731962A50900B39106 /* preprocess.c */, + C493DF741962A50900B39106 /* pseudofloat.h */, + C493DF751962A50900B39106 /* quant_lsp.c */, + C493DF761962A50900B39106 /* quant_lsp.h */, + C493DF771962A50900B39106 /* quant_lsp_bfin.h */, + C493DF781962A50900B39106 /* resample.c */, + C493DF791962A50900B39106 /* resample_sse.h */, + C493DF7A1962A50900B39106 /* sb_celp.c */, + C493DF7B1962A50900B39106 /* sb_celp.h */, + C493DF7C1962A50900B39106 /* scal.c */, + C493DF7D1962A50900B39106 /* smallft.c */, + C493DF7E1962A50900B39106 /* smallft.h */, + C493DF7F1962A50900B39106 /* speex */, + C493DF8D1962A50900B39106 /* speex.c */, + C493DF8E1962A50900B39106 /* speex_callbacks.c */, + C493DF8F1962A50900B39106 /* speex_header.c */, + C493DF901962A50900B39106 /* stack_alloc.h */, + C493DF911962A50900B39106 /* stereo.c */, + C493DF921962A50900B39106 /* vbr.c */, + C493DF931962A50900B39106 /* vbr.h */, + C493DF941962A50900B39106 /* vorbis_psy.h */, + C493DF951962A50900B39106 /* vq.c */, + C493DF961962A50900B39106 /* vq.h */, + C493DF971962A50900B39106 /* vq_arm4.h */, + C493DF981962A50900B39106 /* vq_bfin.h */, + C493DF991962A50900B39106 /* vq_sse.h */, + C493DF9A1962A50900B39106 /* window.c */, + ); + path = libspeex; + sourceTree = ""; + }; + C493DF7F1962A50900B39106 /* speex */ = { + isa = PBXGroup; + children = ( + C493DF801962A50900B39106 /* speex.h */, + C493DF811962A50900B39106 /* speex_bits.h */, + C493DF821962A50900B39106 /* speex_buffer.h */, + C493DF831962A50900B39106 /* speex_callbacks.h */, + C493DF841962A50900B39106 /* speex_config_types.h */, + C493DF851962A50900B39106 /* speex_config_types.h.in */, + C493DF861962A50900B39106 /* speex_echo.h */, + C493DF871962A50900B39106 /* speex_header.h */, + C493DF881962A50900B39106 /* speex_jitter.h */, + C493DF891962A50900B39106 /* speex_preprocess.h */, + C493DF8A1962A50900B39106 /* speex_resampler.h */, + C493DF8B1962A50900B39106 /* speex_stereo.h */, + C493DF8C1962A50900B39106 /* speex_types.h */, + ); + path = speex; + sourceTree = ""; + }; + C493DF9B1962A50900B39106 /* manager */ = { + isa = PBXGroup; + children = ( + C493DF9C1962A50900B39106 /* AQRecorder.h */, + C493DF9D1962A50900B39106 /* AQRecorder.mm */, + C493DF9E1962A50900B39106 /* Codec */, + C493DFA21962A50900B39106 /* Decapsulator.h */, + C493DFA31962A50900B39106 /* Decapsulator.m */, + C493DFA41962A50900B39106 /* Encapsulator.h */, + C493DFA51962A50900B39106 /* Encapsulator.m */, + C493DFA61962A50900B39106 /* PlayerManager.h */, + C493DFA71962A50900B39106 /* PlayerManager.m */, + C493DFA81962A50900B39106 /* PublicUtility */, + C493DFB01962A50900B39106 /* RawAudioDataPlayer.h */, + C493DFB11962A50900B39106 /* RawAudioDataPlayer.m */, + C493DFB21962A50900B39106 /* RecorderManager.h */, + C493DFB31962A50900B39106 /* RecorderManager.mm */, + ); + path = manager; + sourceTree = ""; + }; + C493DF9E1962A50900B39106 /* Codec */ = { + isa = PBXGroup; + children = ( + C493DF9F1962A50900B39106 /* SpeexAllHeaders.h */, + C493DFA01962A50900B39106 /* SpeexCodec.h */, + C493DFA11962A50900B39106 /* SpeexCodec.m */, + ); + path = Codec; + sourceTree = ""; + }; + C493DFA81962A50900B39106 /* PublicUtility */ = { + isa = PBXGroup; + children = ( + C493DFA91962A50900B39106 /* CADebugMacros.cpp */, + C493DFAA1962A50900B39106 /* CADebugMacros.h */, + C493DFAB1962A50900B39106 /* CAMath.h */, + C493DFAC1962A50900B39106 /* CAStreamBasicDescription.cpp */, + C493DFAD1962A50900B39106 /* CAStreamBasicDescription.h */, + C493DFAE1962A50900B39106 /* CAXException.cpp */, + C493DFAF1962A50900B39106 /* CAXException.h */, + ); + path = PublicUtility; + sourceTree = ""; + }; + C4EBA72B192F279100B72723 = { + isa = PBXGroup; + children = ( + 4C6BBC1D1A7F532F0028B892 /* Security */, + 4C12E7F41A77920A00F1DD54 /* Launch Screen.xib */, + 4C9C7FDB1A4A4CBC00A58066 /* LevelDB */, + 4CC134E21A493FD90016A0C2 /* PB */, + 4C5FE9A01A491F6D00B3DD44 /* Sequencer */, + 4CE2F7C519B0242000415778 /* resources */, + C493E0B31962A62100B39106 /* TeamTalk-Prefix.pch */, + C493E0AF1962A54900B39106 /* TeamTalk-Info.plist */, + C493E0B11962A54F00B39106 /* main.m */, + C493DDCA1962A50900B39106 /* TeamTalk */, + C4EBA756192F279100B72723 /* IOSDuoduoTests */, + 4CB8F6BF19A6D97D00C4C27D /* IOSDuoduo Tests */, + C4EBA736192F279100B72723 /* Frameworks */, + 4C1367ED194AF9440094E87D /* New Group */, + A8257D727D24C0F620C5BCBC /* Pods */, + ); + sourceTree = ""; + }; + C4EBA735192F279100B72723 /* Products */ = { + isa = PBXGroup; + children = ( + C4EBA734192F279100B72723 /* TeamTalk.app */, + ); + name = Products; + sourceTree = ""; + }; + C4EBA736192F279100B72723 /* Frameworks */ = { + isa = PBXGroup; + children = ( + 81419D121A53EAD900E25D46 /* libPods-ProtocolBuffers.a */, + 4C88A0C419D50FFA0071DA9C /* libz.dylib */, + 4C88A0C319D50FD00071DA9C /* MobClick.h */, + 4C88A0C119D50FC20071DA9C /* libMobClickLibrary.a */, + C46061D7194E9D9300FF3966 /* MobileCoreServices.framework */, + C46061D5194E9D8A00FF3966 /* SystemConfiguration.framework */, + C4AFD884193D7B580054ECFD /* AudioToolbox.framework */, + C4AFD882193D7B490054ECFD /* CoreAudio.framework */, + C4AFD7D5193D67350054ECFD /* AVFoundation.framework */, + C4EBA737192F279100B72723 /* Foundation.framework */, + C4EBA739192F279100B72723 /* CoreGraphics.framework */, + C4EBA73B192F279100B72723 /* UIKit.framework */, + C4EBA750192F279100B72723 /* XCTest.framework */, + 3EFE09922227481999813B37 /* libPods.a */, + ); + name = Frameworks; + sourceTree = ""; + }; + C4EBA756192F279100B72723 /* IOSDuoduoTests */ = { + isa = PBXGroup; + children = ( + C4EBA75C192F279100B72723 /* IOSDuoduoTests.m */, + C4EBA757192F279100B72723 /* Supporting Files */, + ); + path = IOSDuoduoTests; + sourceTree = ""; + }; + C4EBA757192F279100B72723 /* Supporting Files */ = { + isa = PBXGroup; + children = ( + C4EBA758192F279100B72723 /* TeamTalkTests-Info.plist */, + C4EBA759192F279100B72723 /* InfoPlist.strings */, + ); + name = "Supporting Files"; + sourceTree = ""; + }; +/* End PBXGroup section */ + +/* Begin PBXNativeTarget section */ + C4EBA733192F279100B72723 /* TeamTalk */ = { + isa = PBXNativeTarget; + buildConfigurationList = C4EBA760192F279100B72723 /* Build configuration list for PBXNativeTarget "TeamTalk" */; + buildPhases = ( + 44527AFD008B1BB96DF27FA1 /* Check Pods Manifest.lock */, + C4EBA730192F279100B72723 /* Sources */, + C4EBA731192F279100B72723 /* Frameworks */, + C4EBA732192F279100B72723 /* Resources */, + 8EC339B25AFD447EA0F7C26C /* Copy Pods Resources */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = TeamTalk; + productName = IOSDuoduo; + productReference = C4EBA734192F279100B72723 /* TeamTalk.app */; + productType = "com.apple.product-type.application"; + }; +/* End PBXNativeTarget section */ + +/* Begin PBXProject section */ + C4EBA72C192F279100B72723 /* Project object */ = { + isa = PBXProject; + attributes = { + CLASSPREFIX = ""; + LastUpgradeCheck = 0600; + ORGANIZATIONNAME = "Michael Hu"; + TargetAttributes = { + C4EBA733192F279100B72723 = { + DevelopmentTeam = 6U33YVLGCF; + }; + }; + }; + buildConfigurationList = C4EBA72F192F279100B72723 /* Build configuration list for PBXProject "TeamTalk" */; + compatibilityVersion = "Xcode 3.2"; + developmentRegion = English; + hasScannedForEncodings = 0; + knownRegions = ( + en, + ); + mainGroup = C4EBA72B192F279100B72723; + productRefGroup = C4EBA735192F279100B72723 /* Products */; + projectDirPath = ""; + projectRoot = ""; + targets = ( + C4EBA733192F279100B72723 /* TeamTalk */, + ); + }; +/* End PBXProject section */ + +/* Begin PBXResourcesBuildPhase section */ + C4EBA732192F279100B72723 /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 4C3A74D21A8C84C9009400A2 /* 223.gif in Resources */, + 4CA6CE7E1A2C1FBA00405BB6 /* LoginViewController.xib in Resources */, + 4CA6CE651A2C1F6F00405BB6 /* myprofile@2x.png in Resources */, + 4C3A74D41A8C84C9009400A2 /* 224.gif in Resources */, + 81B75A161A58CC1F0039E5B5 /* logo.png in Resources */, + 4CA6CE2D1A2C1F6E00405BB6 /* dd_left_voice_three.png in Resources */, + 4CA6CE261A2C1F6E00405BB6 /* dd_has_unread_message@2x.png in Resources */, + 4CA6CE751A2C1F6F00405BB6 /* username.png in Resources */, + 4CA6CE281A2C1F6E00405BB6 /* dd_image_send@2x.png in Resources */, + 4C3A74D81A8C84C9009400A2 /* 226.gif in Resources */, + 4CA6CE521A2C1F6E00405BB6 /* delete.png in Resources */, + 4CA6CE171A2C1F6E00405BB6 /* contact.png in Resources */, + 4CA6CE701A2C1F6F00405BB6 /* TeamTalk.xcworkspace in Resources */, + 4CA6CE181A2C1F6E00405BB6 /* contact@2x.png in Resources */, + 4CA6CE611A2C1F6F00405BB6 /* msg.caf in Resources */, + 4C3A74E51A8C84C9009400A2 /* 232@2x.gif in Resources */, + 4CA6CE511A2C1F6E00405BB6 /* dd_volumn@2x.png in Resources */, + 4C77C2921A8852F8001E5885 /* ScanQRCodePage.xib in Resources */, + 4CA6CE671A2C1F6F00405BB6 /* password@2x.png in Resources */, + 4CA6CE501A2C1F6E00405BB6 /* dd_volumn.png in Resources */, + 4C3A74EE1A8C84C9009400A2 /* 237.gif in Resources */, + 4CA6CE451A2C1F6E00405BB6 /* dd_right_voice_three@2x.png in Resources */, + 4CA6CE6E1A2C1F6F00405BB6 /* star.png in Resources */, + 4CA6CE2C1A2C1F6E00405BB6 /* dd_left_voice_one@2x.png in Resources */, + 4CB23CAC19B457AD004FCF10 /* EditGroupViewController.xib in Resources */, + 4CA6CE431A2C1F6E00405BB6 /* dd_right_voice_one@2x.png in Resources */, + C485E8E819F78D800061DAFE /* FinderViewController.xib in Resources */, + 4CA6CE1F1A2C1F6E00405BB6 /* dd_cancel_send_record.png in Resources */, + 4CA6CE761A2C1F6F00405BB6 /* username@2x.png in Resources */, + 4CA6CE1B1A2C1F6E00405BB6 /* conversation.png in Resources */, + 81B75A141A58CC090039E5B5 /* search_bar@2x.png in Resources */, + C493E0981962A50A00B39106 /* speex_config_types.h.in in Resources */, + 4C3A74EF1A8C84C9009400A2 /* 237@2x.gif in Resources */, + 4CA6CE111A2C1F6E00405BB6 /* add.png in Resources */, + 81B75A221A58CD8C0039E5B5 /* left@2x.png in Resources */, + 4C3A74D71A8C84C9009400A2 /* 225@2x.gif in Resources */, + 4CA6CE3B1A2C1F6E00405BB6 /* dd_record_normal@2x.png in Resources */, + 4CA6CE601A2C1F6F00405BB6 /* loginlogo.png in Resources */, + 4CA6CE351A2C1F6E00405BB6 /* dd_preview_select.png in Resources */, + 4CA6CE6A1A2C1F6F00405BB6 /* select.png in Resources */, + 4CA6CE481A2C1F6E00405BB6 /* dd_selected_photo.png in Resources */, + 4C3A74E81A8C84C9009400A2 /* 234.gif in Resources */, + 4CA6CE4F1A2C1F6E00405BB6 /* dd_utility@2x.png in Resources */, + 4CA6CE731A2C1F6F00405BB6 /* unselected.png in Resources */, + 4CA6CE581A2C1F6F00405BB6 /* group_default.png in Resources */, + 4C3A74CF1A8C84C9009400A2 /* 221@2x.gif in Resources */, + 81B75A1D1A58CD830039E5B5 /* right.png in Resources */, + 4C3A74DB1A8C84C9009400A2 /* 227@2x.gif in Resources */, + 4C3A74DD1A8C84C9009400A2 /* 228@2x.gif in Resources */, + 4CA6CE721A2C1F6F00405BB6 /* tel@2x.png in Resources */, + 4C3A74E61A8C84C9009400A2 /* 233.gif in Resources */, + 4CA6CE341A2C1F6E00405BB6 /* dd_press_to_say_normal@2x.png in Resources */, + 4C3A74D01A8C84C9009400A2 /* 222.gif in Resources */, + 4C3A74F11A8C84C9009400A2 /* 238@2x.gif in Resources */, + 4C3A74ED1A8C84C9009400A2 /* 236@2x.gif in Resources */, + 4CA6CE1D1A2C1F6E00405BB6 /* dd_album.png in Resources */, + 4CA6CE641A2C1F6F00405BB6 /* myprofile.png in Resources */, + 4CA6CE361A2C1F6E00405BB6 /* dd_preview_select@2x.png in Resources */, + 4CA6CE301A2C1F6E00405BB6 /* dd_left_voice_two@2x.png in Resources */, + 4CA6CE591A2C1F6F00405BB6 /* group_default@2x.png in Resources */, + 4CA6CE251A2C1F6E00405BB6 /* dd_has_unread_message.png in Resources */, + 4CA6CE3E1A2C1F6E00405BB6 /* dd_record_too_short.png in Resources */, + 4CA6CE441A2C1F6E00405BB6 /* dd_right_voice_three.png in Resources */, + 81B75A191A58CCC90039E5B5 /* phone.png in Resources */, + 81B75A211A58CD8C0039E5B5 /* left.png in Resources */, + 4CA6CE411A2C1F6E00405BB6 /* dd_recording@2x.png in Resources */, + 4CA6CE4B1A2C1F6E00405BB6 /* dd_send_failed@2x.png in Resources */, + 4C3A74E31A8C84C9009400A2 /* 231@2x.gif in Resources */, + 4C39B8101974F388001B4AEF /* MyProfileViewControll.xib in Resources */, + C493E0601962A50A00B39106 /* ChattingMainViewController.xib in Resources */, + 4CA6CE4A1A2C1F6E00405BB6 /* dd_send_failed.png in Resources */, + 4CA6CE3D1A2C1F6E00405BB6 /* dd_record_release_end@2x.png in Resources */, + 81B75A131A58CC090039E5B5 /* search_bar.png in Resources */, + 4CA6CE3F1A2C1F6E00405BB6 /* dd_record_too_short@2x.png in Resources */, + 4CA6CE391A2C1F6E00405BB6 /* dd_recent_contacts@2x.png in Resources */, + 4CA6CE231A2C1F6E00405BB6 /* dd_emotion.png in Resources */, + 4CA6CE741A2C1F6F00405BB6 /* unselected@2x.png in Resources */, + 4C3A74E91A8C84C9009400A2 /* 234@2x.gif in Resources */, + 4CA6CE331A2C1F6E00405BB6 /* dd_press_to_say_normal.png in Resources */, + 4CA6CE161A2C1F6E00405BB6 /* contact_selected@2x.png in Resources */, + 4CA6CE381A2C1F6E00405BB6 /* dd_recent_contacts.png in Resources */, + 4C3A74DE1A8C84C9009400A2 /* 229.gif in Resources */, + 4C3A74F51A8C84C9009400A2 /* 240@2x.gif in Resources */, + 4CA6CE5A1A2C1F6F00405BB6 /* jiantou.png in Resources */, + 4C12E7F51A77920A00F1DD54 /* Launch Screen.xib in Resources */, + 4CA6CE3C1A2C1F6E00405BB6 /* dd_record_release_end.png in Resources */, + 4CA6CE461A2C1F6E00405BB6 /* dd_right_voice_two.png in Resources */, + 4CA6CE151A2C1F6E00405BB6 /* contact_selected.png in Resources */, + 4CA6CE1C1A2C1F6E00405BB6 /* conversation@2x.png in Resources */, + 4C3A74F81A8C84F7009400A2 /* delImage.png in Resources */, + 4C39B7FE1974D6E4001B4AEF /* Images.xcassets in Resources */, + 4C3A74F41A8C84C9009400A2 /* 240.gif in Resources */, + 4CA6CE321A2C1F6E00405BB6 /* dd_photo_back@2x.png in Resources */, + 4CA6CE3A1A2C1F6E00405BB6 /* dd_record_normal.png in Resources */, + 4C39B8081974EF18001B4AEF /* MainViewControll.xib in Resources */, + 4CA6CE141A2C1F6E00405BB6 /* chat@2x.png in Resources */, + 4C837F40197F951600C3D758 /* DDChattingEditViewController.xib in Resources */, + 4C3A74F21A8C84C9009400A2 /* 239.gif in Resources */, + 4CA6CE221A2C1F6E00405BB6 /* dd_emoji_delete@2x.png in Resources */, + 4CA6CE2F1A2C1F6E00405BB6 /* dd_left_voice_two.png in Resources */, + 4CA6CE6F1A2C1F6F00405BB6 /* star@2x.png in Resources */, + 4CA6CE211A2C1F6E00405BB6 /* dd_emoji_delete.png in Resources */, + 4C3A74EB1A8C84C9009400A2 /* 235@2x.gif in Resources */, + 4CA6CE551A2C1F6F00405BB6 /* edit@2x.png in Resources */, + 4C3A74F91A8C84F7009400A2 /* delImage@2x.png in Resources */, + 4CA6CE1A1A2C1F6E00405BB6 /* conversation_selected@2x.png in Resources */, + 4CA6CE6B1A2C1F6F00405BB6 /* select@2x.png in Resources */, + 4C3A74E21A8C84C9009400A2 /* 231.gif in Resources */, + 4CA6CE661A2C1F6F00405BB6 /* password.png in Resources */, + 4C3A74D51A8C84C9009400A2 /* 224@2x.gif in Resources */, + 4CA6CE241A2C1F6E00405BB6 /* dd_emotion@2x.png in Resources */, + 4CA6CE4C1A2C1F6E00405BB6 /* dd_take-photo.png in Resources */, + 4CA6CE561A2C1F6F00405BB6 /* email.png in Resources */, + 4CA6CE4E1A2C1F6E00405BB6 /* dd_utility.png in Resources */, + 4CA6CE401A2C1F6E00405BB6 /* dd_recording.png in Resources */, + 81B75A1A1A58CCC90039E5B5 /* phone@2x.png in Resources */, + 4CA6CE191A2C1F6E00405BB6 /* conversation_selected.png in Resources */, + 4CA6CE711A2C1F6F00405BB6 /* tel.png in Resources */, + 81B75A1E1A58CD830039E5B5 /* right@2x.png in Resources */, + 4CA6CE5B1A2C1F6F00405BB6 /* jiantou@2x.png in Resources */, + 4CA6CE771A2C1F6F00405BB6 /* x.png in Resources */, + 4C3A74EC1A8C84C9009400A2 /* 236.gif in Resources */, + 4CA6CE471A2C1F6E00405BB6 /* dd_right_voice_two@2x.png in Resources */, + 4C3A74D31A8C84C9009400A2 /* 223@2x.gif in Resources */, + 4CA6CE531A2C1F6F00405BB6 /* delete@2x.png in Resources */, + 4C837F3B197F94F400C3D758 /* PublicProfileViewControll.xib in Resources */, + 4C3A74F01A8C84C9009400A2 /* 238.gif in Resources */, + 4CA6CE491A2C1F6E00405BB6 /* dd_selected_photo@2x.png in Resources */, + 4CA6CE291A2C1F6E00405BB6 /* dd_input_normal.png in Resources */, + 4CA6CE131A2C1F6E00405BB6 /* chat.png in Resources */, + 4CA6CE4D1A2C1F6E00405BB6 /* dd_take-photo@2x.png in Resources */, + 4CA6CE121A2C1F6E00405BB6 /* add@2x.png in Resources */, + 4CA6CE311A2C1F6E00405BB6 /* dd_photo_back.png in Resources */, + 4CA6CE2A1A2C1F6E00405BB6 /* dd_input_normal@2x.png in Resources */, + 4CA6CE781A2C1F6F00405BB6 /* x@2x.png in Resources */, + 4CA6CE421A2C1F6E00405BB6 /* dd_right_voice_one.png in Resources */, + 4CA6CE6D1A2C1F6F00405BB6 /* setting@2x.png in Resources */, + 4C3A74D11A8C84C9009400A2 /* 222@2x.gif in Resources */, + 4CA6CE6C1A2C1F6F00405BB6 /* setting.png in Resources */, + 4CA6CE271A2C1F6E00405BB6 /* dd_image_send.png in Resources */, + 4CA6CE201A2C1F6E00405BB6 /* dd_cancel_send_record@2x.png in Resources */, + 4C3A74DA1A8C84C9009400A2 /* 227.gif in Resources */, + 4CA6CE5F1A2C1F6F00405BB6 /* loginlogo.jpg in Resources */, + C493E0721962A50A00B39106 /* RecentUsersViewController.xib in Resources */, + 4C3A74DC1A8C84C9009400A2 /* 228.gif in Resources */, + 4C3A74E41A8C84C9009400A2 /* 232.gif in Resources */, + 4C3A74D91A8C84C9009400A2 /* 226@2x.gif in Resources */, + C493E0701962A50A00B39106 /* RecentUserCell.xib in Resources */, + 4C3A74CE1A8C84C9009400A2 /* 221.gif in Resources */, + 4CA6CE571A2C1F6F00405BB6 /* email@2x.png in Resources */, + 4CA6CE1E1A2C1F6E00405BB6 /* dd_album@2x.png in Resources */, + 4C3A74D61A8C84C9009400A2 /* 225.gif in Resources */, + 4C3A74E71A8C84C9009400A2 /* 233@2x.gif in Resources */, + 4CA6CE2B1A2C1F6E00405BB6 /* dd_left_voice_one.png in Resources */, + 4C3A74F31A8C84C9009400A2 /* 239@2x.gif in Resources */, + 4CA6CE631A2C1F6F00405BB6 /* myprofile_selected@2x.png in Resources */, + 4CA6CE541A2C1F6F00405BB6 /* edit.png in Resources */, + 4CA6CE2E1A2C1F6E00405BB6 /* dd_left_voice_three@2x.png in Resources */, + 4CA6CE621A2C1F6F00405BB6 /* myprofile_selected.png in Resources */, + 4C3A74EA1A8C84C9009400A2 /* 235.gif in Resources */, + 4C3A74DF1A8C84C9009400A2 /* 229@2x.gif in Resources */, + 4C3A74E01A8C84C9009400A2 /* 230.gif in Resources */, + 4C3A74E11A8C84C9009400A2 /* 230@2x.gif in Resources */, + C493E0511962A50A00B39106 /* DDChatTextCell.xib in Resources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXResourcesBuildPhase section */ + +/* Begin PBXShellScriptBuildPhase section */ + 44527AFD008B1BB96DF27FA1 /* Check Pods Manifest.lock */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputPaths = ( + ); + name = "Check Pods Manifest.lock"; + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "diff \"${PODS_ROOT}/../Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [[ $? != 0 ]] ; then\n cat << EOM\nerror: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\nEOM\n exit 1\nfi\n"; + showEnvVarsInLog = 0; + }; + 8EC339B25AFD447EA0F7C26C /* Copy Pods Resources */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputPaths = ( + ); + name = "Copy Pods Resources"; + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods/Pods-resources.sh\"\n"; + showEnvVarsInLog = 0; + }; +/* End PBXShellScriptBuildPhase section */ + +/* Begin PBXSourcesBuildPhase section */ + C4EBA730192F279100B72723 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 4CA6CE7B1A2C1FA700405BB6 /* LoginViewController.h in Sources */, + 4CA6CE7C1A2C1FA700405BB6 /* LoginViewController.m in Sources */, + C493E0221962A50A00B39106 /* DDUnrequestSuperAPI.m in Sources */, + 4C837F49197F95A400C3D758 /* GroupEntity.m in Sources */, + C493E0781962A50A00B39106 /* cb_search.c in Sources */, + 4C79D2C31AB7C9A500706E32 /* IMLogin.pb.m in Sources */, + C493E08C1962A50A00B39106 /* lsp_tables_nb.c in Sources */, + C493E0381962A50A00B39106 /* AQGridViewUpdateInfo.m in Sources */, + C493DFB91962A50900B39106 /* NSIndexSet+AQIndexesOutsideSet.m in Sources */, + C493E0161962A50A00B39106 /* std.m in Sources */, + 4CB3D91D19F4B48200DC9B9D /* LogoutAPI.m in Sources */, + C493E0641962A50A00B39106 /* MenuImageView.m in Sources */, + 4C837F43197F952800C3D758 /* ChattingEditModule.m in Sources */, + C493E0A61962A50A00B39106 /* CAStreamBasicDescription.cpp in Sources */, + C493E09C1962A50A00B39106 /* stereo.c in Sources */, + C493E01C1962A50A00B39106 /* DDDataOutputStream.m in Sources */, + 4CB3D91A19F4A22800DC9B9D /* ShieldGroupMessageAPI.m in Sources */, + 4CD156691998A36300B11233 /* DDFixedGroupAPI.m in Sources */, + C493E05B1962A50A00B39106 /* EmotionsViewController.m in Sources */, + C493E07C1962A50A00B39106 /* exc_5_256_table.c in Sources */, + C493E07B1962A50A00B39106 /* exc_20_32_table.c in Sources */, + C493E0A41962A50A00B39106 /* PlayerManager.m in Sources */, + C493E0521962A50A00B39106 /* DDChatVoiceCell.m in Sources */, + C493E0231962A50A00B39106 /* NSStream+NSStreamAddition.m in Sources */, + C493E0861962A50A00B39106 /* high_lsp_tables.c in Sources */, + 4CE95F3119AAD0E8000CD0C6 /* ContactAvatarTools.m in Sources */, + C493DFBE1962A50900B39106 /* NSString+JSMessagesView.m in Sources */, + 4C98355419C06F6D00DE8874 /* EditContactsCell.m in Sources */, + 4C79D2C11AB7C9A500706E32 /* IMBuddy.pb.m in Sources */, + C493E08F1962A50A00B39106 /* modes.c in Sources */, + C493E0771962A50A00B39106 /* buffer.c in Sources */, + C493DFC31962A50900B39106 /* UIImage+JSMessagesView.m in Sources */, + C493E05A1962A50A00B39106 /* EmotionsModule.m in Sources */, + C493E0671962A50A00B39106 /* AlbumDetailsBottomBar.m in Sources */, + C493E0A11962A50A00B39106 /* SpeexCodec.m in Sources */, + C493E0391962A50A00B39106 /* AQGridViewUpdateItem.m in Sources */, + 4C31EB5619CAB471004A3B2C /* GetGroupInfoAPi.m in Sources */, + C493E0211962A50A00B39106 /* DDTcpProtocolHeader.m in Sources */, + C493E0251962A50A00B39106 /* HeartbeatAPI.m in Sources */, + C493E0961962A50A00B39106 /* scal.c in Sources */, + C493E0741962A50A00B39106 /* bitwise.c in Sources */, + C485E8EB19F7CB630061DAFE /* OpenSourcePRViewController.m in Sources */, + 4CC41F831A4D120600DE434F /* PublicProfileCell.m in Sources */, + C493E0291962A50A00B39106 /* GetUnreadMessagesAPI.m in Sources */, + 4C77C2951A88CFEC001E5885 /* BlurView.m in Sources */, + C493E0891962A50A00B39106 /* kiss_fftr.c in Sources */, + C493E07A1962A50A00B39106 /* exc_10_32_table.c in Sources */, + C493E01A1962A50A00B39106 /* DDAPISchedule.m in Sources */, + 4C837F38197F94F400C3D758 /* ContactsModule.m in Sources */, + C493E0791962A50A00B39106 /* exc_10_16_table.c in Sources */, + 4C3A75081A8C860F009400A2 /* RootViewController.m in Sources */, + C493E0561962A50A00B39106 /* AlbumViewController.m in Sources */, + 4CB23CAF19B4590D004FCF10 /* EditGroupViewCell.m in Sources */, + C493E0311962A50A00B39106 /* ReceiveKickoffAPI.m in Sources */, + 4C39B80F1974F388001B4AEF /* MyProfileViewControll.m in Sources */, + C493E0551962A50A00B39106 /* DDAlbumDetailsViewControll.m in Sources */, + C493E0A01962A50A00B39106 /* AQRecorder.mm in Sources */, + 4CB8F6D319A7171800C4C27D /* DDContactsCell.m in Sources */, + 4CC35AA91A83097200E6224D /* GetLatestMsgId.m in Sources */, + C493E08E1962A50A00B39106 /* mdf.c in Sources */, + C493DFD31962A50900B39106 /* DDTcpServer.m in Sources */, + C493E0901962A50A00B39106 /* modes_wb.c in Sources */, + C493E04E1962A50A00B39106 /* DDChatImageCell.m in Sources */, + C493DFB71962A50900B39106 /* NSDictionary+JSON.m in Sources */, + C493DFBA1962A50900B39106 /* NSIndexSet+AQIsSetContiguous.m in Sources */, + 4C6BBC191A7B8DD40028B892 /* UIImage+UIImageAddition.m in Sources */, + C493E0261962A50A00B39106 /* LoginAPI.mm in Sources */, + C493DFCA1962A50900B39106 /* DDDatabaseUtil.m in Sources */, + C493DFC51962A50900B39106 /* UIView+DDAddition.m in Sources */, + C493E0201962A50A00B39106 /* DDTcpClientManager.m in Sources */, + C493E0B21962A54F00B39106 /* main.m in Sources */, + C493E0181962A50A00B39106 /* DDSundriesCenter.m in Sources */, + C493E0151962A50A00B39106 /* DDClientStateMaintenanceManager.m in Sources */, + C493E07D1962A50A00B39106 /* exc_5_64_table.c in Sources */, + C493E0A81962A50A00B39106 /* RawAudioDataPlayer.m in Sources */, + C493DFC71962A50900B39106 /* SessionEntity.m in Sources */, + 4CB3D92119F4FA7F00DC9B9D /* SearchContentViewController.m in Sources */, + C493E0171962A50A00B39106 /* DDNotificationHelp.m in Sources */, + C493E0691962A50A00B39106 /* LoginModule.m in Sources */, + 4CA50CD019A47C690032DE24 /* DDSearch.m in Sources */, + C485E8E719F78D800061DAFE /* FinderViewController.m in Sources */, + C493E0991962A50A00B39106 /* speex.c in Sources */, + 4CD1566B1998A36300B11233 /* MsgReadACKAPI.m in Sources */, + 4CD3EDDB1A0C6FE100795A0C /* NSString+Additions.m in Sources */, + C493DFCC1962A50900B39106 /* DDAFClient.m in Sources */, + C493DFC41962A50900B39106 /* UIView+AnimationOptionsForCurve.m in Sources */, + C493E0931962A50A00B39106 /* quant_lsp.c in Sources */, + C493E0911962A50A00B39106 /* nb_celp.c in Sources */, + C493E0941962A50A00B39106 /* resample.c in Sources */, + C493DFC61962A50900B39106 /* DDMessageEntity.mm in Sources */, + 4C79D2C41AB7C9A500706E32 /* IMMessage.pb.m in Sources */, + C493E08A1962A50A00B39106 /* lpc.c in Sources */, + 4C3A75041A8C85C1009400A2 /* DBHelper.mm in Sources */, + C493E0341962A50A00B39106 /* AQGridViewAnimatorItem.m in Sources */, + C493E09E1962A50A00B39106 /* vq.c in Sources */, + C493DFC81962A50900B39106 /* DDUserEntity.m in Sources */, + C493E0831962A50A00B39106 /* gain_table_lbr.c in Sources */, + 4C837F46197F954500C3D758 /* DDCreateGroupAPI.m in Sources */, + C493DFD61962A50900B39106 /* DDMessageSendManager.mm in Sources */, + C493E0661962A50A00B39106 /* TouchDownGestureRecognizer.m in Sources */, + C493E07F1962A50A00B39106 /* fftwrap.c in Sources */, + 4C3A75051A8C85C1009400A2 /* DBManager.m in Sources */, + C493E0851962A50A00B39106 /* hexc_table.c in Sources */, + C493E0811962A50A00B39106 /* filters.c in Sources */, + C493E0921962A50A00B39106 /* preprocess.c in Sources */, + 4C837EE9197F949300C3D758 /* DDAllUserAPI.m in Sources */, + C493E05D1962A50A00B39106 /* AnalysisImage.m in Sources */, + C493DFBD1962A50900B39106 /* NSString+DDPath.m in Sources */, + C493E09B1962A50A00B39106 /* speex_header.c in Sources */, + 4C5CA06019C13341007CE792 /* DDDeleteMemberFromGroupAPI.m in Sources */, + C493DFD71962A50900B39106 /* DDUserModule.m in Sources */, + C493E0611962A50A00B39106 /* ChattingModule.m in Sources */, + 4C21749719C197F3006F4BFC /* DDUserDetailInfoAPI.m in Sources */, + C493E08B1962A50A00B39106 /* lsp.c in Sources */, + C493E01B1962A50A00B39106 /* DDDataInputStream.m in Sources */, + C493E0751962A50A00B39106 /* framing.c in Sources */, + C493E0711962A50A00B39106 /* RecentUsersViewController.m in Sources */, + C493E0331962A50A00B39106 /* AQGridView.m in Sources */, + 4CA50CC919A435E20032DE24 /* DDPersonEditCollectionCell.m in Sources */, + C493E0881962A50A00B39106 /* kiss_fft.c in Sources */, + 4CF7D530198A268500F0272B /* JSDismissiveTextView.m in Sources */, + 4C79D2C01AB7C9A500706E32 /* IMBaseDefine.pb.m in Sources */, + C493E08D1962A50A00B39106 /* ltp.c in Sources */, + 4CF7D531198A268500F0272B /* JSMessageInputView.m in Sources */, + C493DFB61962A50900B39106 /* NSDate+DDAddition.m in Sources */, + 4C837F3F197F951600C3D758 /* DDChattingEditViewController.m in Sources */, + 4CE135E819C91EB20098A5E4 /* SendPushTokenAPI.m in Sources */, + C485E8EE19F7D6250061DAFE /* WifiViewController.m in Sources */, + 4C3A74FF1A8C8577009400A2 /* Sequencer.m in Sources */, + 4C5E374419D408CE00D1042B /* GroupAvatarImage.m in Sources */, + C493E0801962A50A00B39106 /* filterbank.c in Sources */, + 4C79D2C51AB7C9A500706E32 /* IMOther.pb.m in Sources */, + C493E0A91962A50A00B39106 /* RecorderManager.mm in Sources */, + C493E0A71962A50A00B39106 /* CAXException.cpp in Sources */, + 4CB58EAC1991FF98006B24D3 /* DDepartment.m in Sources */, + C493E0361962A50A00B39106 /* AQGridViewController.m in Sources */, + 4CFC9FB21A4412E3002E7A5A /* MsgReadNotify.m in Sources */, + C493E0841962A50A00B39106 /* hexc_10_32_table.c in Sources */, + C493E0971962A50A00B39106 /* smallft.c in Sources */, + C493E0A31962A50A00B39106 /* Encapsulator.m in Sources */, + 4CF7D532198A268500F0272B /* JSMessageTextView.m in Sources */, + C493DFC11962A50900B39106 /* UIColor+JSMessagesView.m in Sources */, + 4C3A75121A8C865A009400A2 /* DDAppDelegate.m in Sources */, + 4C5486CF1A70EA8000ED8735 /* DDEmotionCell.m in Sources */, + 4C5D70571990C1AE009AF959 /* DDDepartmentAPI.m in Sources */, + C493E0321962A50A00B39106 /* DDReceiveMessageAPI.m in Sources */, + 4CD1566D1998A36300B11233 /* DDReceiveGroupAddMemberAPI.m in Sources */, + C493E04D1962A50A00B39106 /* DDChatBaseCell.m in Sources */, + C493E0A51962A50A00B39106 /* CADebugMacros.cpp in Sources */, + C493E0951962A50A00B39106 /* sb_celp.c in Sources */, + C493E02C1962A50A00B39106 /* DDSendPhotoMessageAPI.m in Sources */, + C493E0141962A50A00B39106 /* DDClientState.m in Sources */, + C493DFD21962A50900B39106 /* DDMsgServer.m in Sources */, + 4C39B8071974EF18001B4AEF /* MainViewControll.m in Sources */, + C493E0761962A50A00B39106 /* bits.c in Sources */, + 4C3A750F1A8C8650009400A2 /* TTHttpsRequest.m in Sources */, + 4C77C2911A8852F8001E5885 /* ScanQRCodePage.m in Sources */, + C493E0651962A50A00B39106 /* RecordingView.m in Sources */, + C493E02A1962A50A00B39106 /* SendMessageAPI.m in Sources */, + 4CD156781998B70D00B11233 /* DDGroupModule.m in Sources */, + 4C837F3A197F94F400C3D758 /* PublicProfileViewControll.m in Sources */, + C493E0581962A50A00B39106 /* ChatUtilityViewController.m in Sources */, + C493E01E1962A50A00B39106 /* DDSendBuffer.m in Sources */, + 4C4657BD19EF5DC300334DD2 /* UnAckMessageManager.m in Sources */, + 4CB23CAB19B457AD004FCF10 /* EditGroupViewController.m in Sources */, + 4CA50CCD19A47B9A0032DE24 /* SpellLibrary.m in Sources */, + 4CA0BA011A5C0E2800102EC7 /* NSData+Conversion.m in Sources */, + 4C5CC9B81A38221C0067B124 /* RemoveSessionAPI.m in Sources */, + 4C92734819EB9C8200F6C370 /* NetwrokStatusNotifyUI.m in Sources */, + C493E0501962A50A00B39106 /* DDChatTextCell.m in Sources */, + C493DFCF1962A50900B39106 /* DDHttpServer.m in Sources */, + C493E09D1962A50A00B39106 /* vbr.c in Sources */, + C493E06F1962A50A00B39106 /* RecentUserCell.m in Sources */, + 4C837F4C197F95FF00C3D758 /* ContactsViewController.m in Sources */, + C493E0821962A50A00B39106 /* gain_table.c in Sources */, + 4CD156681998A36300B11233 /* DDAddMemberToGroupAPI.m in Sources */, + C493DFC01962A50900B39106 /* UIColor+AQGridView.m in Sources */, + 4CC35AAC1A83585E00E6224D /* GetMsgByMsgIDsAPI.m in Sources */, + C493E0371962A50A00B39106 /* AQGridViewData.m in Sources */, + C493E09F1962A50A00B39106 /* window.c in Sources */, + C493E01F1962A50A00B39106 /* DDSuperAPI.m in Sources */, + 4C79D2C21AB7C9A500706E32 /* IMGroup.pb.m in Sources */, + C493E05F1962A50A00B39106 /* ChattingMainViewController.m in Sources */, + 4C1CEEC81A3581160015C355 /* GetMessageQueueAPI.m in Sources */, + 4C0C0F0C1A314E060094CCD2 /* SessionModule.m in Sources */, + 4CD995F5199F420700025C9C /* DDBaseEntity.m in Sources */, + 4C1E441919961889005CB2DB /* DDReceiveMessageACKAPI.m in Sources */, + C493E06C1962A50A00B39106 /* Photo.m in Sources */, + 4C79D2B31AB7C19200706E32 /* GetDepartment.m in Sources */, + 4C5F3F291A2EE29D003684B2 /* GetRecentSession.mm in Sources */, + C493E06D1962A50A00B39106 /* PhotosCache.m in Sources */, + C493E0191962A50A00B39106 /* DataOutputStream+Addition.m in Sources */, + C493E01D1962A50A00B39106 /* DDReachability.m in Sources */, + 4CB6AA0D198F7F550075BDB4 /* ChatEditTableViewCell.m in Sources */, + 4C3A750C1A8C861E009400A2 /* RuntimeStatus.m in Sources */, + C493DFB81962A50900B39106 /* NSDictionary+Safe.m in Sources */, + C493E0A21962A50A00B39106 /* Decapsulator.m in Sources */, + C493E0591962A50A00B39106 /* EmojiFaceView.m in Sources */, + C493E09A1962A50A00B39106 /* speex_callbacks.c in Sources */, + C493E07E1962A50A00B39106 /* exc_8_128_table.c in Sources */, + C493DFBF1962A50900B39106 /* UIButton+JSMessagesView.m in Sources */, + C493E0351962A50A00B39106 /* AQGridViewCell.m in Sources */, + C493E0871962A50A00B39106 /* jitter.c in Sources */, + C493E0541962A50A00B39106 /* DDPromptCell.m in Sources */, + C493DFD51962A50900B39106 /* DDMessageModule.m in Sources */, + C493E06E1962A50A00B39106 /* ImageGridViewCell.m in Sources */, + C493E04F1962A50A00B39106 /* DDChatImagePreviewViewController.m in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase section */ + +/* Begin PBXVariantGroup section */ + 4CB8F6C219A6D97D00C4C27D /* InfoPlist.strings */ = { + isa = PBXVariantGroup; + children = ( + 4CB8F6C319A6D97D00C4C27D /* en */, + ); + name = InfoPlist.strings; + sourceTree = ""; + }; + C4EBA759192F279100B72723 /* InfoPlist.strings */ = { + isa = PBXVariantGroup; + children = ( + C4EBA75A192F279100B72723 /* en */, + ); + name = InfoPlist.strings; + sourceTree = ""; + }; +/* End PBXVariantGroup section */ + +/* Begin XCBuildConfiguration section */ + C4EBA75E192F279100B72723 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + CODE_SIGN_IDENTITY = ""; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = ""; + COPY_PHASE_STRIP = NO; + GCC_C_LANGUAGE_STANDARD = gnu99; + GCC_DYNAMIC_NO_PIC = NO; + GCC_OPTIMIZATION_LEVEL = 0; + GCC_PREPROCESSOR_DEFINITIONS = ( + "DEBUG=1", + "$(inherited)", + ); + GCC_SYMBOLS_PRIVATE_EXTERN = NO; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 6.0; + ONLY_ACTIVE_ARCH = YES; + PROVISIONING_PROFILE = "53879731-1196-4257-B8B4-B9196E51809C"; + SDKROOT = iphoneos; + }; + name = Debug; + }; + C4EBA75F192F279100B72723 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + CODE_SIGN_IDENTITY = ""; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = ""; + COPY_PHASE_STRIP = YES; + ENABLE_NS_ASSERTIONS = NO; + GCC_C_LANGUAGE_STANDARD = gnu99; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 6.0; + PROVISIONING_PROFILE = "53879731-1196-4257-B8B4-B9196E51809C"; + SDKROOT = iphoneos; + VALIDATE_PRODUCT = YES; + }; + name = Release; + }; + C4EBA761192F279100B72723 /* Debug */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 5C1C2E789271519490720734 /* Pods.debug.xcconfig */; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + ASSETCATALOG_COMPILER_LAUNCHIMAGE_NAME = LaunchImage; + CODE_SIGN_IDENTITY = "iPhone Developer: Michael Scofield (RFN7CLVWTX)"; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = ""; + FRAMEWORK_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)", + ); + GCC_PRECOMPILE_PREFIX_HEADER = YES; + GCC_PREFIX_HEADER = "IOSDuoduo/TeamTalk-Prefix.pch"; + GCC_PREPROCESSOR_DEFINITIONS = ( + "COCOAPODS=1", + "DEBUG=1", + ); + HEADER_SEARCH_PATHS = ( + "\"${PODS_ROOT}/Headers/Public\"", + "\"${PODS_ROOT}/Headers/Public/AFNetworking\"", + "\"${PODS_ROOT}/Headers/Public/DACircularProgress\"", + "\"${PODS_ROOT}/Headers/Public/FMDB\"", + "\"${PODS_ROOT}/Headers/Public/HPGrowingTextView\"", + "\"${PODS_ROOT}/Headers/Public/MBProgressHUD\"", + "\"${PODS_ROOT}/Headers/Public/PSTCollectionView\"", + "\"${PODS_ROOT}/Headers/Public/ProtocolBuffers\"", + "\"${PODS_ROOT}/Headers/Public/ProtocolBuffers/ProtocolBuffers\"", + "\"${PODS_ROOT}/Headers/Public/SDWebImage\"", + "\"${PODS_ROOT}/Headers/Public/leveldb-library\"", + "\"${PODS_ROOT}/Headers/Public/leveldb-library/leveldb\"", + "\"${PODS_ROOT}/leveldb-library/\"", + "\"${PODS_ROOT}/leveldb-library/include\"", + ); + INFOPLIST_FILE = "TeamTalk-Info.plist"; + IPHONEOS_DEPLOYMENT_TARGET = 6.0; + LIBRARY_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)", + "$(PROJECT_DIR)/Pods/build/Debug-iphoneos", + "$(PROJECT_DIR)/security", + ); + PRODUCT_NAME = TeamTalk; + PROVISIONING_PROFILE = "09d5788e-c95b-4682-8363-e5dba92ce932"; + TARGETED_DEVICE_FAMILY = 1; + WRAPPER_EXTENSION = app; + }; + name = Debug; + }; + C4EBA762192F279100B72723 /* Release */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 19B78DA8A3707C0C507EF626 /* Pods.release.xcconfig */; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + ASSETCATALOG_COMPILER_LAUNCHIMAGE_NAME = LaunchImage; + CODE_SIGN_IDENTITY = "iPhone Developer: Michael Scofield (RFN7CLVWTX)"; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = ""; + FRAMEWORK_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)", + ); + GCC_PRECOMPILE_PREFIX_HEADER = YES; + GCC_PREFIX_HEADER = "IOSDuoduo/TeamTalk-Prefix.pch"; + HEADER_SEARCH_PATHS = ( + "\"${PODS_ROOT}/Headers/Public\"", + "\"${PODS_ROOT}/Headers/Public/AFNetworking\"", + "\"${PODS_ROOT}/Headers/Public/DACircularProgress\"", + "\"${PODS_ROOT}/Headers/Public/FMDB\"", + "\"${PODS_ROOT}/Headers/Public/HPGrowingTextView\"", + "\"${PODS_ROOT}/Headers/Public/MBProgressHUD\"", + "\"${PODS_ROOT}/Headers/Public/PSTCollectionView\"", + "\"${PODS_ROOT}/Headers/Public/ProtocolBuffers\"", + "\"${PODS_ROOT}/Headers/Public/ProtocolBuffers/ProtocolBuffers\"", + "\"${PODS_ROOT}/Headers/Public/SDWebImage\"", + "\"${PODS_ROOT}/Headers/Public/leveldb-library\"", + "\"${PODS_ROOT}/Headers/Public/leveldb-library/leveldb\"", + "\"${PODS_ROOT}/leveldb-library/\"", + "\"${PODS_ROOT}/leveldb-library/include\"", + ); + INFOPLIST_FILE = "TeamTalk-Info.plist"; + IPHONEOS_DEPLOYMENT_TARGET = 6.0; + LIBRARY_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)", + "$(PROJECT_DIR)/Pods/build/Debug-iphoneos", + "$(PROJECT_DIR)/security", + ); + PRODUCT_NAME = TeamTalk; + PROVISIONING_PROFILE = "09d5788e-c95b-4682-8363-e5dba92ce932"; + TARGETED_DEVICE_FAMILY = 1; + WRAPPER_EXTENSION = app; + }; + name = Release; + }; +/* End XCBuildConfiguration section */ + +/* Begin XCConfigurationList section */ + C4EBA72F192F279100B72723 /* Build configuration list for PBXProject "TeamTalk" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + C4EBA75E192F279100B72723 /* Debug */, + C4EBA75F192F279100B72723 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + C4EBA760192F279100B72723 /* Build configuration list for PBXNativeTarget "TeamTalk" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + C4EBA761192F279100B72723 /* Debug */, + C4EBA762192F279100B72723 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; +/* End XCConfigurationList section */ + }; + rootObject = C4EBA72C192F279100B72723 /* Project object */; +} diff --git a/ios/TeamTalk.xcodeproj/project.xcworkspace/contents.xcworkspacedata b/ios/TeamTalk.xcodeproj/project.xcworkspace/contents.xcworkspacedata new file mode 100644 index 000000000..fa0db0eaa --- /dev/null +++ b/ios/TeamTalk.xcodeproj/project.xcworkspace/contents.xcworkspacedata @@ -0,0 +1,7 @@ + + + + + diff --git a/ios/TeamTalk.xcodeproj/project.xcworkspace/xcshareddata/IOSDuoduo.xccheckout b/ios/TeamTalk.xcodeproj/project.xcworkspace/xcshareddata/IOSDuoduo.xccheckout new file mode 100644 index 000000000..cbf94fb3f --- /dev/null +++ b/ios/TeamTalk.xcodeproj/project.xcworkspace/xcshareddata/IOSDuoduo.xccheckout @@ -0,0 +1,41 @@ + + + + + IDESourceControlProjectFavoriteDictionaryKey + + IDESourceControlProjectIdentifier + 8D9646DD-D2CD-407B-B98F-8616977516D0 + IDESourceControlProjectName + IOSDuoduo + IDESourceControlProjectOriginsDictionary + + 3EF53C7A-544D-4764-B270-E69415B922F8 + ssh://gitlab.mogujie.org/dongxie/ios-os-im.git + + IDESourceControlProjectPath + IOSDuoduo/IOSDuoduo.xcodeproj/project.xcworkspace + IDESourceControlProjectRelativeInstallPathDictionary + + 3EF53C7A-544D-4764-B270-E69415B922F8 + ../../.. + + IDESourceControlProjectURL + ssh://gitlab.mogujie.org/dongxie/ios-os-im.git + IDESourceControlProjectVersion + 110 + IDESourceControlProjectWCCIdentifier + 3EF53C7A-544D-4764-B270-E69415B922F8 + IDESourceControlProjectWCConfigurations + + + IDESourceControlRepositoryExtensionIdentifierKey + public.vcs.git + IDESourceControlWCCIdentifierKey + 3EF53C7A-544D-4764-B270-E69415B922F8 + IDESourceControlWCCName + ios-os-im + + + + diff --git a/ios/TeamTalk.xcodeproj/project.xcworkspace/xcshareddata/TeamTalk.xccheckout b/ios/TeamTalk.xcodeproj/project.xcworkspace/xcshareddata/TeamTalk.xccheckout new file mode 100644 index 000000000..271d00489 --- /dev/null +++ b/ios/TeamTalk.xcodeproj/project.xcworkspace/xcshareddata/TeamTalk.xccheckout @@ -0,0 +1,41 @@ + + + + + IDESourceControlProjectFavoriteDictionaryKey + + IDESourceControlProjectIdentifier + D21343C0-E675-4EE1-94E7-FC3C6F104689 + IDESourceControlProjectName + TeamTalk + IDESourceControlProjectOriginsDictionary + + 438AB9C685D2126C067FC6E0A59E9C7C05914A28 + gitlab.mogujie.org:im/ttopen.git + + IDESourceControlProjectPath + ios/TeamTalk.xcodeproj + IDESourceControlProjectRelativeInstallPathDictionary + + 438AB9C685D2126C067FC6E0A59E9C7C05914A28 + ../../.. + + IDESourceControlProjectURL + gitlab.mogujie.org:im/ttopen.git + IDESourceControlProjectVersion + 111 + IDESourceControlProjectWCCIdentifier + 438AB9C685D2126C067FC6E0A59E9C7C05914A28 + IDESourceControlProjectWCConfigurations + + + IDESourceControlRepositoryExtensionIdentifierKey + public.vcs.git + IDESourceControlWCCIdentifierKey + 438AB9C685D2126C067FC6E0A59E9C7C05914A28 + IDESourceControlWCCName + ttopen + + + + diff --git a/ios/TeamTalk.xcodeproj/project.xcworkspace/xcuserdata/Michael.xcuserdatad/UserInterfaceState.xcuserstate b/ios/TeamTalk.xcodeproj/project.xcworkspace/xcuserdata/Michael.xcuserdatad/UserInterfaceState.xcuserstate new file mode 100644 index 000000000..fb1fa5c9a Binary files /dev/null and b/ios/TeamTalk.xcodeproj/project.xcworkspace/xcuserdata/Michael.xcuserdatad/UserInterfaceState.xcuserstate differ diff --git a/ios/TeamTalk.xcodeproj/project.xcworkspace/xcuserdata/lanhu.xcuserdatad/UserInterfaceState.xcuserstate b/ios/TeamTalk.xcodeproj/project.xcworkspace/xcuserdata/lanhu.xcuserdatad/UserInterfaceState.xcuserstate new file mode 100644 index 000000000..0ccfac00a Binary files /dev/null and b/ios/TeamTalk.xcodeproj/project.xcworkspace/xcuserdata/lanhu.xcuserdatad/UserInterfaceState.xcuserstate differ diff --git a/ios/TeamTalk.xcodeproj/xcuserdata/Jerry.xcuserdatad/xcschemes/TeamTalk.xcscheme b/ios/TeamTalk.xcodeproj/xcuserdata/Jerry.xcuserdatad/xcschemes/TeamTalk.xcscheme new file mode 100644 index 000000000..dbabc857f --- /dev/null +++ b/ios/TeamTalk.xcodeproj/xcuserdata/Jerry.xcuserdatad/xcschemes/TeamTalk.xcscheme @@ -0,0 +1,110 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/ios/TeamTalk.xcodeproj/xcuserdata/Jerry.xcuserdatad/xcschemes/xcschememanagement.plist b/ios/TeamTalk.xcodeproj/xcuserdata/Jerry.xcuserdatad/xcschemes/xcschememanagement.plist new file mode 100644 index 000000000..4f3e4bba1 --- /dev/null +++ b/ios/TeamTalk.xcodeproj/xcuserdata/Jerry.xcuserdatad/xcschemes/xcschememanagement.plist @@ -0,0 +1,27 @@ + + + + + SchemeUserState + + TeamTalk.xcscheme + + orderHint + 0 + + + SuppressBuildableAutocreation + + C4EBA733192F279100B72723 + + primary + + + C4EBA74E192F279100B72723 + + primary + + + + + diff --git a/ios/TeamTalk.xcodeproj/xcuserdata/Michael.xcuserdatad/xcschemes/IOSDuoduo.xcscheme b/ios/TeamTalk.xcodeproj/xcuserdata/Michael.xcuserdatad/xcschemes/IOSDuoduo.xcscheme new file mode 100644 index 000000000..0f05a869e --- /dev/null +++ b/ios/TeamTalk.xcodeproj/xcuserdata/Michael.xcuserdatad/xcschemes/IOSDuoduo.xcscheme @@ -0,0 +1,96 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/ios/TeamTalk.xcodeproj/xcuserdata/Michael.xcuserdatad/xcschemes/IOSDuoduoTests.xcscheme b/ios/TeamTalk.xcodeproj/xcuserdata/Michael.xcuserdatad/xcschemes/IOSDuoduoTests.xcscheme new file mode 100644 index 000000000..eb441e8f1 --- /dev/null +++ b/ios/TeamTalk.xcodeproj/xcuserdata/Michael.xcuserdatad/xcschemes/IOSDuoduoTests.xcscheme @@ -0,0 +1,79 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/ios/TeamTalk.xcodeproj/xcuserdata/Michael.xcuserdatad/xcschemes/xcschememanagement.plist b/ios/TeamTalk.xcodeproj/xcuserdata/Michael.xcuserdatad/xcschemes/xcschememanagement.plist new file mode 100644 index 000000000..4be0b390a --- /dev/null +++ b/ios/TeamTalk.xcodeproj/xcuserdata/Michael.xcuserdatad/xcschemes/xcschememanagement.plist @@ -0,0 +1,37 @@ + + + + + SchemeUserState + + IOSDuoduo.xcscheme + + orderHint + 9 + + IOSDuoduoTests.xcscheme + + orderHint + 0 + + + SuppressBuildableAutocreation + + 4CB8F6BA19A6D97D00C4C27D + + primary + + + C4EBA733192F279100B72723 + + primary + + + C4EBA74E192F279100B72723 + + primary + + + + + diff --git a/ios/TeamTalk.xcodeproj/xcuserdata/lanhu.xcuserdatad/xcschemes/TeamTalk.xcscheme b/ios/TeamTalk.xcodeproj/xcuserdata/lanhu.xcuserdatad/xcschemes/TeamTalk.xcscheme new file mode 100644 index 000000000..1ba81134c --- /dev/null +++ b/ios/TeamTalk.xcodeproj/xcuserdata/lanhu.xcuserdatad/xcschemes/TeamTalk.xcscheme @@ -0,0 +1,86 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/ios/TeamTalk.xcodeproj/xcuserdata/lanhu.xcuserdatad/xcschemes/xcschememanagement.plist b/ios/TeamTalk.xcodeproj/xcuserdata/lanhu.xcuserdatad/xcschemes/xcschememanagement.plist new file mode 100644 index 000000000..aaa44b364 --- /dev/null +++ b/ios/TeamTalk.xcodeproj/xcuserdata/lanhu.xcuserdatad/xcschemes/xcschememanagement.plist @@ -0,0 +1,22 @@ + + + + + SchemeUserState + + TeamTalk.xcscheme + + orderHint + 0 + + + SuppressBuildableAutocreation + + C4EBA733192F279100B72723 + + primary + + + + + diff --git a/ios/TeamTalk.xcodeproj/xcuserdata/scorpio.xcuserdatad/xcschemes/TeamTalk.xcscheme b/ios/TeamTalk.xcodeproj/xcuserdata/scorpio.xcuserdatad/xcschemes/TeamTalk.xcscheme new file mode 100644 index 000000000..b41983add --- /dev/null +++ b/ios/TeamTalk.xcodeproj/xcuserdata/scorpio.xcuserdatad/xcschemes/TeamTalk.xcscheme @@ -0,0 +1,110 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/ios/TeamTalk.xcodeproj/xcuserdata/scorpio.xcuserdatad/xcschemes/xcschememanagement.plist b/ios/TeamTalk.xcodeproj/xcuserdata/scorpio.xcuserdatad/xcschemes/xcschememanagement.plist new file mode 100644 index 000000000..07705f8e1 --- /dev/null +++ b/ios/TeamTalk.xcodeproj/xcuserdata/scorpio.xcuserdatad/xcschemes/xcschememanagement.plist @@ -0,0 +1,27 @@ + + + + + SchemeUserState + + TeamTalk.xcscheme + + orderHint + 8 + + + SuppressBuildableAutocreation + + C4EBA733192F279100B72723 + + primary + + + C4EBA74E192F279100B72723 + + primary + + + + + diff --git a/ios/TeamTalk.xcworkspace/contents.xcworkspacedata b/ios/TeamTalk.xcworkspace/contents.xcworkspacedata new file mode 100644 index 000000000..6efd2cafe --- /dev/null +++ b/ios/TeamTalk.xcworkspace/contents.xcworkspacedata @@ -0,0 +1,10 @@ + + + + + + + diff --git a/ios/TeamTalk.xcworkspace/xcshareddata/TeamTalk.xccheckout b/ios/TeamTalk.xcworkspace/xcshareddata/TeamTalk.xccheckout new file mode 100644 index 000000000..d46f4d606 --- /dev/null +++ b/ios/TeamTalk.xcworkspace/xcshareddata/TeamTalk.xccheckout @@ -0,0 +1,41 @@ + + + + + IDESourceControlProjectFavoriteDictionaryKey + + IDESourceControlProjectIdentifier + 826EDA1C-4A1E-46A5-AD5B-A5BB48861DC5 + IDESourceControlProjectName + TeamTalk + IDESourceControlProjectOriginsDictionary + + 438AB9C685D2126C067FC6E0A59E9C7C05914A28 + http://gitlab.mogujie.org/im/ttopen.git + + IDESourceControlProjectPath + ios/TeamTalk.xcworkspace + IDESourceControlProjectRelativeInstallPathDictionary + + 438AB9C685D2126C067FC6E0A59E9C7C05914A28 + ../.. + + IDESourceControlProjectURL + http://gitlab.mogujie.org/im/ttopen.git + IDESourceControlProjectVersion + 111 + IDESourceControlProjectWCCIdentifier + 438AB9C685D2126C067FC6E0A59E9C7C05914A28 + IDESourceControlProjectWCConfigurations + + + IDESourceControlRepositoryExtensionIdentifierKey + public.vcs.git + IDESourceControlWCCIdentifierKey + 438AB9C685D2126C067FC6E0A59E9C7C05914A28 + IDESourceControlWCCName + ttopen + + + + diff --git a/ios/TeamTalk.xcworkspace/xcuserdata/Michael.xcuserdatad/UserInterfaceState.xcuserstate b/ios/TeamTalk.xcworkspace/xcuserdata/Michael.xcuserdatad/UserInterfaceState.xcuserstate new file mode 100644 index 000000000..2bae8ad27 Binary files /dev/null and b/ios/TeamTalk.xcworkspace/xcuserdata/Michael.xcuserdatad/UserInterfaceState.xcuserstate differ diff --git a/ios/TeamTalk.xcworkspace/xcuserdata/Michael.xcuserdatad/WorkspaceSettings.xcsettings b/ios/TeamTalk.xcworkspace/xcuserdata/Michael.xcuserdatad/WorkspaceSettings.xcsettings new file mode 100644 index 000000000..659c8766e --- /dev/null +++ b/ios/TeamTalk.xcworkspace/xcuserdata/Michael.xcuserdatad/WorkspaceSettings.xcsettings @@ -0,0 +1,10 @@ + + + + + HasAskedToTakeAutomaticSnapshotBeforeSignificantChanges + + SnapshotAutomaticallyBeforeSignificantChanges + + + diff --git a/ios/TeamTalk.xcworkspace/xcuserdata/Michael.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist b/ios/TeamTalk.xcworkspace/xcuserdata/Michael.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist new file mode 100644 index 000000000..174762697 --- /dev/null +++ b/ios/TeamTalk.xcworkspace/xcuserdata/Michael.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist @@ -0,0 +1,3367 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/ios/TeamTalk.xcworkspace/xcuserdata/lanhu.xcuserdatad/UserInterfaceState.xcuserstate b/ios/TeamTalk.xcworkspace/xcuserdata/lanhu.xcuserdatad/UserInterfaceState.xcuserstate new file mode 100644 index 000000000..829fc9124 Binary files /dev/null and b/ios/TeamTalk.xcworkspace/xcuserdata/lanhu.xcuserdatad/UserInterfaceState.xcuserstate differ diff --git a/ios/TeamTalk.xcworkspace/xcuserdata/scorpio.xcuserdatad/UserInterfaceState.xcuserstate b/ios/TeamTalk.xcworkspace/xcuserdata/scorpio.xcuserdatad/UserInterfaceState.xcuserstate new file mode 100644 index 000000000..3d65a5e12 Binary files /dev/null and b/ios/TeamTalk.xcworkspace/xcuserdata/scorpio.xcuserdatad/UserInterfaceState.xcuserstate differ diff --git a/ios/TeamTalk.xcworkspace/xcuserdata/scorpio.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist b/ios/TeamTalk.xcworkspace/xcuserdata/scorpio.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist new file mode 100644 index 000000000..e2573a594 --- /dev/null +++ b/ios/TeamTalk.xcworkspace/xcuserdata/scorpio.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist @@ -0,0 +1,17 @@ + + + + + + + + + diff --git a/ios/emotions/221.gif b/ios/emotions/221.gif new file mode 100755 index 000000000..d75703ebf Binary files /dev/null and b/ios/emotions/221.gif differ diff --git a/ios/emotions/221@2x.gif b/ios/emotions/221@2x.gif new file mode 100755 index 000000000..d75703ebf Binary files /dev/null and b/ios/emotions/221@2x.gif differ diff --git a/ios/emotions/222.gif b/ios/emotions/222.gif new file mode 100755 index 000000000..52883dd44 Binary files /dev/null and b/ios/emotions/222.gif differ diff --git a/ios/emotions/222@2x.gif b/ios/emotions/222@2x.gif new file mode 100755 index 000000000..52883dd44 Binary files /dev/null and b/ios/emotions/222@2x.gif differ diff --git a/ios/emotions/223.gif b/ios/emotions/223.gif new file mode 100755 index 000000000..54636150d Binary files /dev/null and b/ios/emotions/223.gif differ diff --git a/ios/emotions/223@2x.gif b/ios/emotions/223@2x.gif new file mode 100755 index 000000000..54636150d Binary files /dev/null and b/ios/emotions/223@2x.gif differ diff --git a/ios/emotions/224.gif b/ios/emotions/224.gif new file mode 100755 index 000000000..f7f9be2ae Binary files /dev/null and b/ios/emotions/224.gif differ diff --git a/ios/emotions/224@2x.gif b/ios/emotions/224@2x.gif new file mode 100755 index 000000000..f7f9be2ae Binary files /dev/null and b/ios/emotions/224@2x.gif differ diff --git a/ios/emotions/225.gif b/ios/emotions/225.gif new file mode 100755 index 000000000..5ea900f8c Binary files /dev/null and b/ios/emotions/225.gif differ diff --git a/ios/emotions/225@2x.gif b/ios/emotions/225@2x.gif new file mode 100755 index 000000000..5ea900f8c Binary files /dev/null and b/ios/emotions/225@2x.gif differ diff --git a/ios/emotions/226.gif b/ios/emotions/226.gif new file mode 100755 index 000000000..724fe54cf Binary files /dev/null and b/ios/emotions/226.gif differ diff --git a/ios/emotions/226@2x.gif b/ios/emotions/226@2x.gif new file mode 100755 index 000000000..724fe54cf Binary files /dev/null and b/ios/emotions/226@2x.gif differ diff --git a/ios/emotions/227.gif b/ios/emotions/227.gif new file mode 100755 index 000000000..a93f49f8d Binary files /dev/null and b/ios/emotions/227.gif differ diff --git a/ios/emotions/227@2x.gif b/ios/emotions/227@2x.gif new file mode 100755 index 000000000..a93f49f8d Binary files /dev/null and b/ios/emotions/227@2x.gif differ diff --git a/ios/emotions/228.gif b/ios/emotions/228.gif new file mode 100755 index 000000000..5ce7c7b09 Binary files /dev/null and b/ios/emotions/228.gif differ diff --git a/ios/emotions/228@2x.gif b/ios/emotions/228@2x.gif new file mode 100755 index 000000000..5ce7c7b09 Binary files /dev/null and b/ios/emotions/228@2x.gif differ diff --git a/ios/emotions/229.gif b/ios/emotions/229.gif new file mode 100755 index 000000000..86512d3c1 Binary files /dev/null and b/ios/emotions/229.gif differ diff --git a/ios/emotions/229@2x.gif b/ios/emotions/229@2x.gif new file mode 100755 index 000000000..86512d3c1 Binary files /dev/null and b/ios/emotions/229@2x.gif differ diff --git a/ios/emotions/230.gif b/ios/emotions/230.gif new file mode 100755 index 000000000..7064b50d9 Binary files /dev/null and b/ios/emotions/230.gif differ diff --git a/ios/emotions/230@2x.gif b/ios/emotions/230@2x.gif new file mode 100755 index 000000000..7064b50d9 Binary files /dev/null and b/ios/emotions/230@2x.gif differ diff --git a/ios/emotions/231.gif b/ios/emotions/231.gif new file mode 100755 index 000000000..276161541 Binary files /dev/null and b/ios/emotions/231.gif differ diff --git a/ios/emotions/231@2x.gif b/ios/emotions/231@2x.gif new file mode 100755 index 000000000..276161541 Binary files /dev/null and b/ios/emotions/231@2x.gif differ diff --git a/ios/emotions/232.gif b/ios/emotions/232.gif new file mode 100755 index 000000000..f913f56e5 Binary files /dev/null and b/ios/emotions/232.gif differ diff --git a/ios/emotions/232@2x.gif b/ios/emotions/232@2x.gif new file mode 100755 index 000000000..f913f56e5 Binary files /dev/null and b/ios/emotions/232@2x.gif differ diff --git a/ios/emotions/233.gif b/ios/emotions/233.gif new file mode 100755 index 000000000..656eb7904 Binary files /dev/null and b/ios/emotions/233.gif differ diff --git a/ios/emotions/233@2x.gif b/ios/emotions/233@2x.gif new file mode 100755 index 000000000..656eb7904 Binary files /dev/null and b/ios/emotions/233@2x.gif differ diff --git a/ios/emotions/234.gif b/ios/emotions/234.gif new file mode 100755 index 000000000..b46680c23 Binary files /dev/null and b/ios/emotions/234.gif differ diff --git a/ios/emotions/234@2x.gif b/ios/emotions/234@2x.gif new file mode 100755 index 000000000..b46680c23 Binary files /dev/null and b/ios/emotions/234@2x.gif differ diff --git a/ios/emotions/235.gif b/ios/emotions/235.gif new file mode 100755 index 000000000..f129cf3d4 Binary files /dev/null and b/ios/emotions/235.gif differ diff --git a/ios/emotions/235@2x.gif b/ios/emotions/235@2x.gif new file mode 100755 index 000000000..f129cf3d4 Binary files /dev/null and b/ios/emotions/235@2x.gif differ diff --git a/ios/emotions/236.gif b/ios/emotions/236.gif new file mode 100755 index 000000000..35cc1148d Binary files /dev/null and b/ios/emotions/236.gif differ diff --git a/ios/emotions/236@2x.gif b/ios/emotions/236@2x.gif new file mode 100755 index 000000000..35cc1148d Binary files /dev/null and b/ios/emotions/236@2x.gif differ diff --git a/ios/emotions/237.gif b/ios/emotions/237.gif new file mode 100755 index 000000000..0bfa22f79 Binary files /dev/null and b/ios/emotions/237.gif differ diff --git a/ios/emotions/237@2x.gif b/ios/emotions/237@2x.gif new file mode 100755 index 000000000..0bfa22f79 Binary files /dev/null and b/ios/emotions/237@2x.gif differ diff --git a/ios/emotions/238.gif b/ios/emotions/238.gif new file mode 100755 index 000000000..9edcf90af Binary files /dev/null and b/ios/emotions/238.gif differ diff --git a/ios/emotions/238@2x.gif b/ios/emotions/238@2x.gif new file mode 100755 index 000000000..9edcf90af Binary files /dev/null and b/ios/emotions/238@2x.gif differ diff --git a/ios/emotions/239.gif b/ios/emotions/239.gif new file mode 100755 index 000000000..6ca6e0d7e Binary files /dev/null and b/ios/emotions/239.gif differ diff --git a/ios/emotions/239@2x.gif b/ios/emotions/239@2x.gif new file mode 100755 index 000000000..6ca6e0d7e Binary files /dev/null and b/ios/emotions/239@2x.gif differ diff --git a/ios/emotions/240.gif b/ios/emotions/240.gif new file mode 100755 index 000000000..58662e29e Binary files /dev/null and b/ios/emotions/240.gif differ diff --git a/ios/emotions/240@2x.gif b/ios/emotions/240@2x.gif new file mode 100755 index 000000000..58662e29e Binary files /dev/null and b/ios/emotions/240@2x.gif differ diff --git a/ios/en.lproj/InfoPlist.strings b/ios/en.lproj/InfoPlist.strings new file mode 100644 index 000000000..477b28ff8 --- /dev/null +++ b/ios/en.lproj/InfoPlist.strings @@ -0,0 +1,2 @@ +/* Localized versions of Info.plist keys */ + diff --git a/ios/libsecurity.a b/ios/libsecurity.a new file mode 100644 index 000000000..7d0865a61 Binary files /dev/null and b/ios/libsecurity.a differ diff --git a/ios/main.m b/ios/main.m new file mode 100644 index 000000000..f0247c074 --- /dev/null +++ b/ios/main.m @@ -0,0 +1,20 @@ +// +// main.m +// IOSDuoduo +// +// Created by 独嘉 on 14-5-23. +// Copyright (c) 2014年 dujia. All rights reserved. +// +//jide viewed + +#import + +#import "DDAppDelegate.h" + +int main(int argc, char * argv[]) +{ + @autoreleasepool { + + return UIApplicationMain(argc, argv, nil, NSStringFromClass([DDAppDelegate class])); + } +} diff --git a/ios/resources/TeamTalk.xcworkspace/contents.xcworkspacedata b/ios/resources/TeamTalk.xcworkspace/contents.xcworkspacedata new file mode 100644 index 000000000..6efd2cafe --- /dev/null +++ b/ios/resources/TeamTalk.xcworkspace/contents.xcworkspacedata @@ -0,0 +1,10 @@ + + + + + + + diff --git a/ios/resources/TeamTalk.xcworkspace/xcshareddata/IOSDuoduo.xccheckout b/ios/resources/TeamTalk.xcworkspace/xcshareddata/IOSDuoduo.xccheckout new file mode 100644 index 000000000..84d3e2d26 --- /dev/null +++ b/ios/resources/TeamTalk.xcworkspace/xcshareddata/IOSDuoduo.xccheckout @@ -0,0 +1,41 @@ + + + + + IDESourceControlProjectFavoriteDictionaryKey + + IDESourceControlProjectIdentifier + 501691B6-E321-41E2-8696-A07C352F78D1 + IDESourceControlProjectName + IOSDuoduo + IDESourceControlProjectOriginsDictionary + + 3EF53C7A-544D-4764-B270-E69415B922F8 + ssh://gitlab.mogujie.org/dongxie/ios-os-im.git + + IDESourceControlProjectPath + IOSDuoduo/IOSDuoduo.xcworkspace + IDESourceControlProjectRelativeInstallPathDictionary + + 3EF53C7A-544D-4764-B270-E69415B922F8 + ../.. + + IDESourceControlProjectURL + ssh://gitlab.mogujie.org/dongxie/ios-os-im.git + IDESourceControlProjectVersion + 110 + IDESourceControlProjectWCCIdentifier + 3EF53C7A-544D-4764-B270-E69415B922F8 + IDESourceControlProjectWCConfigurations + + + IDESourceControlRepositoryExtensionIdentifierKey + public.vcs.git + IDESourceControlWCCIdentifierKey + 3EF53C7A-544D-4764-B270-E69415B922F8 + IDESourceControlWCCName + ios-os-im + + + + diff --git a/ios/resources/TeamTalk.xcworkspace/xcshareddata/TeamTalk.xccheckout b/ios/resources/TeamTalk.xcworkspace/xcshareddata/TeamTalk.xccheckout new file mode 100644 index 000000000..05dd162f0 --- /dev/null +++ b/ios/resources/TeamTalk.xcworkspace/xcshareddata/TeamTalk.xccheckout @@ -0,0 +1,53 @@ + + + + + IDESourceControlProjectFavoriteDictionaryKey + + IDESourceControlProjectIdentifier + 826EDA1C-4A1E-46A5-AD5B-A5BB48861DC5 + IDESourceControlProjectName + TeamTalk + IDESourceControlProjectOriginsDictionary + + 3EF53C7A-544D-4764-B270-E69415B922F8 + ssh://gitlab.mogujie.org/dongxie/ios-os-im.git + AF42C6DA9F3B77838B1BC908C0E388C0190EF50F + http://gitlab.mogujie.org/dongxie/teamtalk-ios.git + + IDESourceControlProjectPath + TeamTalk.xcworkspace + IDESourceControlProjectRelativeInstallPathDictionary + + 3EF53C7A-544D-4764-B270-E69415B922F8 + ../../ios-os-im + AF42C6DA9F3B77838B1BC908C0E388C0190EF50F + .. + + IDESourceControlProjectURL + http://gitlab.mogujie.org/dongxie/teamtalk-ios.git + IDESourceControlProjectVersion + 111 + IDESourceControlProjectWCCIdentifier + AF42C6DA9F3B77838B1BC908C0E388C0190EF50F + IDESourceControlProjectWCConfigurations + + + IDESourceControlRepositoryExtensionIdentifierKey + public.vcs.git + IDESourceControlWCCIdentifierKey + 3EF53C7A-544D-4764-B270-E69415B922F8 + IDESourceControlWCCName + ios-os-im + + + IDESourceControlRepositoryExtensionIdentifierKey + public.vcs.git + IDESourceControlWCCIdentifierKey + AF42C6DA9F3B77838B1BC908C0E388C0190EF50F + IDESourceControlWCCName + TeamTalk + + + + diff --git a/ios/resources/TeamTalk.xcworkspace/xcuserdata/Jerry.xcuserdatad/UserInterfaceState.xcuserstate b/ios/resources/TeamTalk.xcworkspace/xcuserdata/Jerry.xcuserdatad/UserInterfaceState.xcuserstate new file mode 100644 index 000000000..1cbb5b10e Binary files /dev/null and b/ios/resources/TeamTalk.xcworkspace/xcuserdata/Jerry.xcuserdatad/UserInterfaceState.xcuserstate differ diff --git a/ios/resources/TeamTalk.xcworkspace/xcuserdata/Jerry.xcuserdatad/WorkspaceSettings.xcsettings b/ios/resources/TeamTalk.xcworkspace/xcuserdata/Jerry.xcuserdatad/WorkspaceSettings.xcsettings new file mode 100644 index 000000000..659c8766e --- /dev/null +++ b/ios/resources/TeamTalk.xcworkspace/xcuserdata/Jerry.xcuserdatad/WorkspaceSettings.xcsettings @@ -0,0 +1,10 @@ + + + + + HasAskedToTakeAutomaticSnapshotBeforeSignificantChanges + + SnapshotAutomaticallyBeforeSignificantChanges + + + diff --git a/ios/resources/TeamTalk.xcworkspace/xcuserdata/Jerry.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist b/ios/resources/TeamTalk.xcworkspace/xcuserdata/Jerry.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist new file mode 100644 index 000000000..fe56d2193 --- /dev/null +++ b/ios/resources/TeamTalk.xcworkspace/xcuserdata/Jerry.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist @@ -0,0 +1,121 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/ios/resources/TeamTalk.xcworkspace/xcuserdata/Michael.xcuserdatad/UserInterfaceState.xcuserstate b/ios/resources/TeamTalk.xcworkspace/xcuserdata/Michael.xcuserdatad/UserInterfaceState.xcuserstate new file mode 100644 index 000000000..f9b4d6420 Binary files /dev/null and b/ios/resources/TeamTalk.xcworkspace/xcuserdata/Michael.xcuserdatad/UserInterfaceState.xcuserstate differ diff --git a/ios/resources/TeamTalk.xcworkspace/xcuserdata/Michael.xcuserdatad/WorkspaceSettings.xcsettings b/ios/resources/TeamTalk.xcworkspace/xcuserdata/Michael.xcuserdatad/WorkspaceSettings.xcsettings new file mode 100644 index 000000000..659c8766e --- /dev/null +++ b/ios/resources/TeamTalk.xcworkspace/xcuserdata/Michael.xcuserdatad/WorkspaceSettings.xcsettings @@ -0,0 +1,10 @@ + + + + + HasAskedToTakeAutomaticSnapshotBeforeSignificantChanges + + SnapshotAutomaticallyBeforeSignificantChanges + + + diff --git a/ios/resources/TeamTalk.xcworkspace/xcuserdata/Michael.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist b/ios/resources/TeamTalk.xcworkspace/xcuserdata/Michael.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist new file mode 100644 index 000000000..b5c0a53a6 --- /dev/null +++ b/ios/resources/TeamTalk.xcworkspace/xcuserdata/Michael.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist @@ -0,0 +1,1675 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/ios/resources/_launchimage.png b/ios/resources/_launchimage.png new file mode 100644 index 000000000..e75e0243b Binary files /dev/null and b/ios/resources/_launchimage.png differ diff --git a/ios/resources/add.png b/ios/resources/add.png new file mode 100644 index 000000000..a8b66ba55 Binary files /dev/null and b/ios/resources/add.png differ diff --git a/ios/resources/add@2x.png b/ios/resources/add@2x.png new file mode 100644 index 000000000..a8b66ba55 Binary files /dev/null and b/ios/resources/add@2x.png differ diff --git a/ios/resources/chat.png b/ios/resources/chat.png new file mode 100644 index 000000000..c6696f692 Binary files /dev/null and b/ios/resources/chat.png differ diff --git a/ios/resources/chat@2x.png b/ios/resources/chat@2x.png new file mode 100644 index 000000000..c6696f692 Binary files /dev/null and b/ios/resources/chat@2x.png differ diff --git a/ios/resources/contact.png b/ios/resources/contact.png new file mode 100644 index 000000000..e9c450774 Binary files /dev/null and b/ios/resources/contact.png differ diff --git a/ios/resources/contact@2x.png b/ios/resources/contact@2x.png new file mode 100644 index 000000000..e9c450774 Binary files /dev/null and b/ios/resources/contact@2x.png differ diff --git a/ios/resources/contact_selected.png b/ios/resources/contact_selected.png new file mode 100644 index 000000000..ee520848e Binary files /dev/null and b/ios/resources/contact_selected.png differ diff --git a/ios/resources/contact_selected@2x.png b/ios/resources/contact_selected@2x.png new file mode 100644 index 000000000..ee520848e Binary files /dev/null and b/ios/resources/contact_selected@2x.png differ diff --git a/ios/resources/conversation.png b/ios/resources/conversation.png new file mode 100644 index 000000000..383080e38 Binary files /dev/null and b/ios/resources/conversation.png differ diff --git a/ios/resources/conversation@2x.png b/ios/resources/conversation@2x.png new file mode 100644 index 000000000..383080e38 Binary files /dev/null and b/ios/resources/conversation@2x.png differ diff --git a/ios/resources/conversation_selected.png b/ios/resources/conversation_selected.png new file mode 100644 index 000000000..062b07432 Binary files /dev/null and b/ios/resources/conversation_selected.png differ diff --git a/ios/resources/conversation_selected@2x.png b/ios/resources/conversation_selected@2x.png new file mode 100644 index 000000000..062b07432 Binary files /dev/null and b/ios/resources/conversation_selected@2x.png differ diff --git a/ios/resources/dd_album.png b/ios/resources/dd_album.png new file mode 100644 index 000000000..4823046c1 Binary files /dev/null and b/ios/resources/dd_album.png differ diff --git a/ios/resources/dd_album@2x.png b/ios/resources/dd_album@2x.png new file mode 100644 index 000000000..042f7d0e4 Binary files /dev/null and b/ios/resources/dd_album@2x.png differ diff --git a/ios/resources/dd_cancel_send_record.png b/ios/resources/dd_cancel_send_record.png new file mode 100644 index 000000000..f7ea9f644 Binary files /dev/null and b/ios/resources/dd_cancel_send_record.png differ diff --git a/ios/resources/dd_cancel_send_record@2x.png b/ios/resources/dd_cancel_send_record@2x.png new file mode 100644 index 000000000..bc8dcbd60 Binary files /dev/null and b/ios/resources/dd_cancel_send_record@2x.png differ diff --git a/ios/resources/dd_emoji_delete.png b/ios/resources/dd_emoji_delete.png new file mode 100644 index 000000000..e970785f6 Binary files /dev/null and b/ios/resources/dd_emoji_delete.png differ diff --git a/ios/resources/dd_emoji_delete@2x.png b/ios/resources/dd_emoji_delete@2x.png new file mode 100644 index 000000000..a84979eca Binary files /dev/null and b/ios/resources/dd_emoji_delete@2x.png differ diff --git a/ios/resources/dd_emotion.png b/ios/resources/dd_emotion.png new file mode 100644 index 000000000..b19ccc5e3 Binary files /dev/null and b/ios/resources/dd_emotion.png differ diff --git a/ios/resources/dd_emotion@2x.png b/ios/resources/dd_emotion@2x.png new file mode 100644 index 000000000..b19ccc5e3 Binary files /dev/null and b/ios/resources/dd_emotion@2x.png differ diff --git a/ios/resources/dd_has_unread_message.png b/ios/resources/dd_has_unread_message.png new file mode 100644 index 000000000..4a4e1e088 Binary files /dev/null and b/ios/resources/dd_has_unread_message.png differ diff --git a/ios/resources/dd_has_unread_message@2x.png b/ios/resources/dd_has_unread_message@2x.png new file mode 100644 index 000000000..9ea81b9b1 Binary files /dev/null and b/ios/resources/dd_has_unread_message@2x.png differ diff --git a/ios/resources/dd_image_send.png b/ios/resources/dd_image_send.png new file mode 100644 index 000000000..3558bca9c Binary files /dev/null and b/ios/resources/dd_image_send.png differ diff --git a/ios/resources/dd_image_send@2x.png b/ios/resources/dd_image_send@2x.png new file mode 100644 index 000000000..5f751dae2 Binary files /dev/null and b/ios/resources/dd_image_send@2x.png differ diff --git a/ios/resources/dd_input_normal.png b/ios/resources/dd_input_normal.png new file mode 100644 index 000000000..4eebdc956 Binary files /dev/null and b/ios/resources/dd_input_normal.png differ diff --git a/ios/resources/dd_input_normal@2x.png b/ios/resources/dd_input_normal@2x.png new file mode 100644 index 000000000..4eebdc956 Binary files /dev/null and b/ios/resources/dd_input_normal@2x.png differ diff --git a/ios/resources/dd_left_voice_one.png b/ios/resources/dd_left_voice_one.png new file mode 100644 index 000000000..181a701ff Binary files /dev/null and b/ios/resources/dd_left_voice_one.png differ diff --git a/ios/resources/dd_left_voice_one@2x.png b/ios/resources/dd_left_voice_one@2x.png new file mode 100644 index 000000000..58265e7bc Binary files /dev/null and b/ios/resources/dd_left_voice_one@2x.png differ diff --git a/ios/resources/dd_left_voice_three.png b/ios/resources/dd_left_voice_three.png new file mode 100644 index 000000000..8871fe53f Binary files /dev/null and b/ios/resources/dd_left_voice_three.png differ diff --git a/ios/resources/dd_left_voice_three@2x.png b/ios/resources/dd_left_voice_three@2x.png new file mode 100644 index 000000000..b414e2d48 Binary files /dev/null and b/ios/resources/dd_left_voice_three@2x.png differ diff --git a/ios/resources/dd_left_voice_two.png b/ios/resources/dd_left_voice_two.png new file mode 100644 index 000000000..3ef674ba7 Binary files /dev/null and b/ios/resources/dd_left_voice_two.png differ diff --git a/ios/resources/dd_left_voice_two@2x.png b/ios/resources/dd_left_voice_two@2x.png new file mode 100644 index 000000000..36440660d Binary files /dev/null and b/ios/resources/dd_left_voice_two@2x.png differ diff --git a/ios/resources/dd_photo_back.png b/ios/resources/dd_photo_back.png new file mode 100644 index 000000000..7e66ba70c Binary files /dev/null and b/ios/resources/dd_photo_back.png differ diff --git a/ios/resources/dd_photo_back@2x.png b/ios/resources/dd_photo_back@2x.png new file mode 100644 index 000000000..a4b160b0b Binary files /dev/null and b/ios/resources/dd_photo_back@2x.png differ diff --git a/ios/resources/dd_press_to_say_normal.png b/ios/resources/dd_press_to_say_normal.png new file mode 100644 index 000000000..d410f4603 Binary files /dev/null and b/ios/resources/dd_press_to_say_normal.png differ diff --git a/ios/resources/dd_press_to_say_normal@2x.png b/ios/resources/dd_press_to_say_normal@2x.png new file mode 100644 index 000000000..52b8d03a8 Binary files /dev/null and b/ios/resources/dd_press_to_say_normal@2x.png differ diff --git a/ios/resources/dd_preview_select.png b/ios/resources/dd_preview_select.png new file mode 100644 index 000000000..f63c1ab70 Binary files /dev/null and b/ios/resources/dd_preview_select.png differ diff --git a/ios/resources/dd_preview_select@2x.png b/ios/resources/dd_preview_select@2x.png new file mode 100644 index 000000000..23397d7ab Binary files /dev/null and b/ios/resources/dd_preview_select@2x.png differ diff --git a/ios/resources/dd_recent_contacts.png b/ios/resources/dd_recent_contacts.png new file mode 100644 index 000000000..6c1141a36 Binary files /dev/null and b/ios/resources/dd_recent_contacts.png differ diff --git a/ios/resources/dd_recent_contacts@2x.png b/ios/resources/dd_recent_contacts@2x.png new file mode 100644 index 000000000..272d5edd0 Binary files /dev/null and b/ios/resources/dd_recent_contacts@2x.png differ diff --git a/ios/resources/dd_record_normal.png b/ios/resources/dd_record_normal.png new file mode 100644 index 000000000..a697d875f Binary files /dev/null and b/ios/resources/dd_record_normal.png differ diff --git a/ios/resources/dd_record_normal@2x.png b/ios/resources/dd_record_normal@2x.png new file mode 100644 index 000000000..a697d875f Binary files /dev/null and b/ios/resources/dd_record_normal@2x.png differ diff --git a/ios/resources/dd_record_release_end.png b/ios/resources/dd_record_release_end.png new file mode 100644 index 000000000..d8de29ca4 Binary files /dev/null and b/ios/resources/dd_record_release_end.png differ diff --git a/ios/resources/dd_record_release_end@2x.png b/ios/resources/dd_record_release_end@2x.png new file mode 100644 index 000000000..b078b90dc Binary files /dev/null and b/ios/resources/dd_record_release_end@2x.png differ diff --git a/ios/resources/dd_record_too_short.png b/ios/resources/dd_record_too_short.png new file mode 100644 index 000000000..4c5b1872a Binary files /dev/null and b/ios/resources/dd_record_too_short.png differ diff --git a/ios/resources/dd_record_too_short@2x.png b/ios/resources/dd_record_too_short@2x.png new file mode 100644 index 000000000..c656c71c8 Binary files /dev/null and b/ios/resources/dd_record_too_short@2x.png differ diff --git a/ios/resources/dd_recording.png b/ios/resources/dd_recording.png new file mode 100644 index 000000000..650e8e0e4 Binary files /dev/null and b/ios/resources/dd_recording.png differ diff --git a/ios/resources/dd_recording@2x.png b/ios/resources/dd_recording@2x.png new file mode 100644 index 000000000..fd046ac12 Binary files /dev/null and b/ios/resources/dd_recording@2x.png differ diff --git a/ios/resources/dd_right_voice_one.png b/ios/resources/dd_right_voice_one.png new file mode 100644 index 000000000..9c018a3c7 Binary files /dev/null and b/ios/resources/dd_right_voice_one.png differ diff --git a/ios/resources/dd_right_voice_one@2x.png b/ios/resources/dd_right_voice_one@2x.png new file mode 100644 index 000000000..164b7d88b Binary files /dev/null and b/ios/resources/dd_right_voice_one@2x.png differ diff --git a/ios/resources/dd_right_voice_three.png b/ios/resources/dd_right_voice_three.png new file mode 100644 index 000000000..beba2ec98 Binary files /dev/null and b/ios/resources/dd_right_voice_three.png differ diff --git a/ios/resources/dd_right_voice_three@2x.png b/ios/resources/dd_right_voice_three@2x.png new file mode 100644 index 000000000..077ba2fb9 Binary files /dev/null and b/ios/resources/dd_right_voice_three@2x.png differ diff --git a/ios/resources/dd_right_voice_two.png b/ios/resources/dd_right_voice_two.png new file mode 100644 index 000000000..0afce4090 Binary files /dev/null and b/ios/resources/dd_right_voice_two.png differ diff --git a/ios/resources/dd_right_voice_two@2x.png b/ios/resources/dd_right_voice_two@2x.png new file mode 100644 index 000000000..0ce2010c6 Binary files /dev/null and b/ios/resources/dd_right_voice_two@2x.png differ diff --git a/ios/resources/dd_selected_photo.png b/ios/resources/dd_selected_photo.png new file mode 100644 index 000000000..2cda24a93 Binary files /dev/null and b/ios/resources/dd_selected_photo.png differ diff --git a/ios/resources/dd_selected_photo@2x.png b/ios/resources/dd_selected_photo@2x.png new file mode 100644 index 000000000..9dbf7d589 Binary files /dev/null and b/ios/resources/dd_selected_photo@2x.png differ diff --git a/ios/resources/dd_send_failed.png b/ios/resources/dd_send_failed.png new file mode 100644 index 000000000..759ab7892 Binary files /dev/null and b/ios/resources/dd_send_failed.png differ diff --git a/ios/resources/dd_send_failed@2x.png b/ios/resources/dd_send_failed@2x.png new file mode 100644 index 000000000..9ff8770b3 Binary files /dev/null and b/ios/resources/dd_send_failed@2x.png differ diff --git a/ios/resources/dd_take-photo.png b/ios/resources/dd_take-photo.png new file mode 100644 index 000000000..e819e8c56 Binary files /dev/null and b/ios/resources/dd_take-photo.png differ diff --git a/ios/resources/dd_take-photo@2x.png b/ios/resources/dd_take-photo@2x.png new file mode 100644 index 000000000..d4280eeba Binary files /dev/null and b/ios/resources/dd_take-photo@2x.png differ diff --git a/ios/resources/dd_utility.png b/ios/resources/dd_utility.png new file mode 100644 index 000000000..2bfb449b0 Binary files /dev/null and b/ios/resources/dd_utility.png differ diff --git a/ios/resources/dd_utility@2x.png b/ios/resources/dd_utility@2x.png new file mode 100644 index 000000000..2bfb449b0 Binary files /dev/null and b/ios/resources/dd_utility@2x.png differ diff --git a/ios/resources/dd_volumn.png b/ios/resources/dd_volumn.png new file mode 100644 index 000000000..67cbef99f Binary files /dev/null and b/ios/resources/dd_volumn.png differ diff --git a/ios/resources/dd_volumn@2x.png b/ios/resources/dd_volumn@2x.png new file mode 100644 index 000000000..2b9d18dd3 Binary files /dev/null and b/ios/resources/dd_volumn@2x.png differ diff --git a/ios/resources/delImage.png b/ios/resources/delImage.png new file mode 100644 index 000000000..9af7e9eaf Binary files /dev/null and b/ios/resources/delImage.png differ diff --git a/ios/resources/delImage@2x.png b/ios/resources/delImage@2x.png new file mode 100644 index 000000000..9af7e9eaf Binary files /dev/null and b/ios/resources/delImage@2x.png differ diff --git a/ios/resources/delete.png b/ios/resources/delete.png new file mode 100644 index 000000000..f72b5ea58 Binary files /dev/null and b/ios/resources/delete.png differ diff --git a/ios/resources/delete@2x.png b/ios/resources/delete@2x.png new file mode 100644 index 000000000..f72b5ea58 Binary files /dev/null and b/ios/resources/delete@2x.png differ diff --git a/ios/resources/edit.png b/ios/resources/edit.png new file mode 100644 index 000000000..95c1c6534 Binary files /dev/null and b/ios/resources/edit.png differ diff --git a/ios/resources/edit@2x.png b/ios/resources/edit@2x.png new file mode 100644 index 000000000..95c1c6534 Binary files /dev/null and b/ios/resources/edit@2x.png differ diff --git a/ios/resources/email.png b/ios/resources/email.png new file mode 100644 index 000000000..7cea1126b Binary files /dev/null and b/ios/resources/email.png differ diff --git a/ios/resources/email@2x.png b/ios/resources/email@2x.png new file mode 100644 index 000000000..7cea1126b Binary files /dev/null and b/ios/resources/email@2x.png differ diff --git a/ios/resources/group_default.png b/ios/resources/group_default.png new file mode 100644 index 000000000..1315d0aa3 Binary files /dev/null and b/ios/resources/group_default.png differ diff --git a/ios/resources/group_default@2x.png b/ios/resources/group_default@2x.png new file mode 100644 index 000000000..1315d0aa3 Binary files /dev/null and b/ios/resources/group_default@2x.png differ diff --git a/ios/resources/jiantou.png b/ios/resources/jiantou.png new file mode 100644 index 000000000..bb94d0995 Binary files /dev/null and b/ios/resources/jiantou.png differ diff --git a/ios/resources/jiantou@2x.png b/ios/resources/jiantou@2x.png new file mode 100644 index 000000000..bb94d0995 Binary files /dev/null and b/ios/resources/jiantou@2x.png differ diff --git a/ios/resources/jiantou~.png b/ios/resources/jiantou~.png new file mode 100644 index 000000000..9ea839250 Binary files /dev/null and b/ios/resources/jiantou~.png differ diff --git a/ios/resources/jiantou~@2x.png b/ios/resources/jiantou~@2x.png new file mode 100644 index 000000000..9ea839250 Binary files /dev/null and b/ios/resources/jiantou~@2x.png differ diff --git a/ios/resources/left.png b/ios/resources/left.png new file mode 100644 index 000000000..92dfa9d33 Binary files /dev/null and b/ios/resources/left.png differ diff --git a/ios/resources/left@2x.png b/ios/resources/left@2x.png new file mode 100644 index 000000000..92dfa9d33 Binary files /dev/null and b/ios/resources/left@2x.png differ diff --git a/ios/resources/loginlogo.jpg b/ios/resources/loginlogo.jpg new file mode 100644 index 000000000..513f1827e Binary files /dev/null and b/ios/resources/loginlogo.jpg differ diff --git a/ios/resources/loginlogo.png b/ios/resources/loginlogo.png new file mode 100644 index 000000000..852f1d5db Binary files /dev/null and b/ios/resources/loginlogo.png differ diff --git a/ios/resources/logo.png b/ios/resources/logo.png new file mode 100644 index 000000000..82fa62e9e Binary files /dev/null and b/ios/resources/logo.png differ diff --git a/ios/resources/minus.png b/ios/resources/minus.png new file mode 100644 index 000000000..ca155f97b Binary files /dev/null and b/ios/resources/minus.png differ diff --git a/ios/resources/minus@2x.png b/ios/resources/minus@2x.png new file mode 100644 index 000000000..ca155f97b Binary files /dev/null and b/ios/resources/minus@2x.png differ diff --git a/ios/resources/msg.caf b/ios/resources/msg.caf new file mode 100644 index 000000000..b1749ce45 Binary files /dev/null and b/ios/resources/msg.caf differ diff --git a/ios/resources/myprofile.png b/ios/resources/myprofile.png new file mode 100644 index 000000000..61a10e6e8 Binary files /dev/null and b/ios/resources/myprofile.png differ diff --git a/ios/resources/myprofile@2x.png b/ios/resources/myprofile@2x.png new file mode 100644 index 000000000..61a10e6e8 Binary files /dev/null and b/ios/resources/myprofile@2x.png differ diff --git a/ios/resources/myprofile_selected.png b/ios/resources/myprofile_selected.png new file mode 100644 index 000000000..8ba59ca0c Binary files /dev/null and b/ios/resources/myprofile_selected.png differ diff --git a/ios/resources/myprofile_selected@2x.png b/ios/resources/myprofile_selected@2x.png new file mode 100644 index 000000000..8ba59ca0c Binary files /dev/null and b/ios/resources/myprofile_selected@2x.png differ diff --git a/ios/resources/password.png b/ios/resources/password.png new file mode 100644 index 000000000..06e097e00 Binary files /dev/null and b/ios/resources/password.png differ diff --git a/ios/resources/password@2x.png b/ios/resources/password@2x.png new file mode 100644 index 000000000..06e097e00 Binary files /dev/null and b/ios/resources/password@2x.png differ diff --git a/ios/resources/phone.png b/ios/resources/phone.png new file mode 100644 index 000000000..2a98ef6ed Binary files /dev/null and b/ios/resources/phone.png differ diff --git a/ios/resources/phone@2x.png b/ios/resources/phone@2x.png new file mode 100644 index 000000000..2a98ef6ed Binary files /dev/null and b/ios/resources/phone@2x.png differ diff --git a/ios/resources/plus.png b/ios/resources/plus.png new file mode 100644 index 000000000..f7e8b4e74 Binary files /dev/null and b/ios/resources/plus.png differ diff --git a/ios/resources/right.png b/ios/resources/right.png new file mode 100644 index 000000000..2c565bd8d Binary files /dev/null and b/ios/resources/right.png differ diff --git a/ios/resources/right@2x.png b/ios/resources/right@2x.png new file mode 100644 index 000000000..2c565bd8d Binary files /dev/null and b/ios/resources/right@2x.png differ diff --git a/ios/resources/search_bar.png b/ios/resources/search_bar.png new file mode 100644 index 000000000..da5619fb9 Binary files /dev/null and b/ios/resources/search_bar.png differ diff --git a/ios/resources/search_bar@2x.png b/ios/resources/search_bar@2x.png new file mode 100644 index 000000000..da5619fb9 Binary files /dev/null and b/ios/resources/search_bar@2x.png differ diff --git a/ios/resources/select.png b/ios/resources/select.png new file mode 100644 index 000000000..42931c260 Binary files /dev/null and b/ios/resources/select.png differ diff --git a/ios/resources/select@2x.png b/ios/resources/select@2x.png new file mode 100644 index 000000000..42931c260 Binary files /dev/null and b/ios/resources/select@2x.png differ diff --git a/ios/resources/setting.png b/ios/resources/setting.png new file mode 100644 index 000000000..f4bce5e72 Binary files /dev/null and b/ios/resources/setting.png differ diff --git a/ios/resources/setting@2x.png b/ios/resources/setting@2x.png new file mode 100644 index 000000000..f4bce5e72 Binary files /dev/null and b/ios/resources/setting@2x.png differ diff --git a/ios/resources/star.png b/ios/resources/star.png new file mode 100644 index 000000000..a50591bdb Binary files /dev/null and b/ios/resources/star.png differ diff --git a/ios/resources/star@2x.png b/ios/resources/star@2x.png new file mode 100644 index 000000000..a50591bdb Binary files /dev/null and b/ios/resources/star@2x.png differ diff --git a/ios/resources/tab_nav 2.png b/ios/resources/tab_nav 2.png new file mode 100644 index 000000000..aea83ddac Binary files /dev/null and b/ios/resources/tab_nav 2.png differ diff --git a/ios/resources/tab_nav.png b/ios/resources/tab_nav.png new file mode 100644 index 000000000..aea83ddac Binary files /dev/null and b/ios/resources/tab_nav.png differ diff --git a/ios/resources/tab_nav@2x.png b/ios/resources/tab_nav@2x.png new file mode 100644 index 000000000..aea83ddac Binary files /dev/null and b/ios/resources/tab_nav@2x.png differ diff --git a/ios/resources/tab_nav_select.png b/ios/resources/tab_nav_select.png new file mode 100644 index 000000000..11871232a Binary files /dev/null and b/ios/resources/tab_nav_select.png differ diff --git a/ios/resources/tab_nav_select@2x.png b/ios/resources/tab_nav_select@2x.png new file mode 100644 index 000000000..11871232a Binary files /dev/null and b/ios/resources/tab_nav_select@2x.png differ diff --git a/ios/resources/tel.png b/ios/resources/tel.png new file mode 100644 index 000000000..87c7519dd Binary files /dev/null and b/ios/resources/tel.png differ diff --git a/ios/resources/tel@2x.png b/ios/resources/tel@2x.png new file mode 100644 index 000000000..87c7519dd Binary files /dev/null and b/ios/resources/tel@2x.png differ diff --git a/ios/resources/unselected.png b/ios/resources/unselected.png new file mode 100644 index 000000000..4cca2af5b Binary files /dev/null and b/ios/resources/unselected.png differ diff --git a/ios/resources/unselected@2x.png b/ios/resources/unselected@2x.png new file mode 100644 index 000000000..4cca2af5b Binary files /dev/null and b/ios/resources/unselected@2x.png differ diff --git a/ios/resources/username.png b/ios/resources/username.png new file mode 100644 index 000000000..0b5b94513 Binary files /dev/null and b/ios/resources/username.png differ diff --git a/ios/resources/username@2x.png b/ios/resources/username@2x.png new file mode 100644 index 000000000..0b5b94513 Binary files /dev/null and b/ios/resources/username@2x.png differ diff --git a/ios/resources/x.png b/ios/resources/x.png new file mode 100644 index 000000000..a6f8667b8 Binary files /dev/null and b/ios/resources/x.png differ diff --git a/ios/resources/x@2x.png b/ios/resources/x@2x.png new file mode 100644 index 000000000..a6f8667b8 Binary files /dev/null and b/ios/resources/x@2x.png differ diff --git a/ios/security.h b/ios/security.h new file mode 100644 index 000000000..782cee369 --- /dev/null +++ b/ios/security.h @@ -0,0 +1,98 @@ +/*================================================================ +* Copyright (C) 2015 All rights reserved. +* +* 文件名称:security.h +* 创 建 者:Zhang Yuanhao +* 邮 箱:bluefoxah@gmail.com +* 创建日期:2015年01月29日 +* 描 述: +* +#pragma once +================================================================*/ + +#ifndef __SECURITY_H__ +#define __SECURITY_H__ + + +#ifdef _WIN32 +typedef char int8_t; +typedef short int16_t; +typedef int int32_t; +typedef long long int64_t; +typedef unsigned char uint8_t; +typedef unsigned short uint16_t; +typedef unsigned int uint32_t; +typedef unsigned long long uint64_t; +typedef int socklen_t; +#else +#include +#endif +typedef unsigned char uchar_t; + +#ifdef WIN32 +#define DLL_MODIFIER __declspec(dllexport) +#else +#define DLL_MODIFIER +#endif + + +#ifdef __cplusplus +extern "C" { +#endif + +#ifdef __ANDROID__ + jbyteArray Java_com_mogujie_tt_Security_EncryptMsg(JNIEnv* env, jobject obj, jstring jstr); + jbyteArray Java_com_mogujie_tt_Security_DecryptMsg(JNIEnv* env, jobject obj, jstring jstr); + jbyteArray Java_com_mogujie_tt_Security_EncryptPass(JNIEnv* env, jobject obj, jstring jstr); + +#else + /** + * 对消息加密 + * + * @param pInData 待加密的消息内容指针 + * @param nInLen 待加密消息内容长度 + * @param pOutData 加密后的文本 + * @param nOutLen 加密后的文本长度 + * + * @return 返回 0-成功; 其他-失败 + */ + DLL_MODIFIER int EncryptMsg(const char* pInData, uint32_t nInLen, char** pOutData, uint32_t& nOutLen); + + /** + * 对消息解密 + * + * @param pInData 待解密的消息内容指针 + * @param nInLen 待解密消息内容长度 + * @param pOutData 解密后的文本 + * @param nOutLen 解密后的文本长度 + * + * @return 返回 0-成功; 其他-失败 + */ + DLL_MODIFIER int DecryptMsg(const char* pInData, uint32_t nInLen, char** pOutData, uint32_t& nOutLen); + + /** + * 对密码进行加密 + * + * @param pInData 待解密的消息内容指针 + * @param nInLen 待解密消息内容长度 + * @param pOutData 解密后的文本 + * @param nOutLen 解密后的文本长度 + * @param pKey 32位密钥 + * + * @return 返回 0-成功; 其他-失败 + */ + DLL_MODIFIER int EncryptPass(const char* pInData, uint32_t nInLen, char** pOutData, uint32_t& nOutLen); + /** + * 释放资源 + * + * @param pOutData 需要释放的资源 + */ + DLL_MODIFIER void Free(char* pOutData); + +#endif + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/mac/CrashReporter.framework/CrashReporter b/mac/CrashReporter.framework/CrashReporter new file mode 120000 index 000000000..92b400e68 --- /dev/null +++ b/mac/CrashReporter.framework/CrashReporter @@ -0,0 +1 @@ +Versions/Current/CrashReporter \ No newline at end of file diff --git a/mac/CrashReporter.framework/Headers b/mac/CrashReporter.framework/Headers new file mode 120000 index 000000000..a177d2a6b --- /dev/null +++ b/mac/CrashReporter.framework/Headers @@ -0,0 +1 @@ +Versions/Current/Headers \ No newline at end of file diff --git a/mac/CrashReporter.framework/Resources b/mac/CrashReporter.framework/Resources new file mode 120000 index 000000000..953ee36f3 --- /dev/null +++ b/mac/CrashReporter.framework/Resources @@ -0,0 +1 @@ +Versions/Current/Resources \ No newline at end of file diff --git a/mac/CrashReporter.framework/Versions/A/CrashReporter b/mac/CrashReporter.framework/Versions/A/CrashReporter new file mode 100755 index 000000000..acd56fa68 Binary files /dev/null and b/mac/CrashReporter.framework/Versions/A/CrashReporter differ diff --git a/mac/CrashReporter.framework/Versions/A/Headers/CrashReporter.h b/mac/CrashReporter.framework/Versions/A/Headers/CrashReporter.h new file mode 100644 index 000000000..c65431911 --- /dev/null +++ b/mac/CrashReporter.framework/Versions/A/Headers/CrashReporter.h @@ -0,0 +1,363 @@ +/* + * Author: Landon Fuller + * + * Copyright (c) 2008-2009 Plausible Labs Cooperative, Inc. + * All rights reserved. + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ + +#import + +#ifdef __APPLE__ +#import +#endif + +// This must be included before any other PLCrashReporter includes, as +// it redefines symbol names +#import "PLCrashNamespace.h" + +#import "PLCrashReporter.h" +#import "PLCrashReport.h" +#import "PLCrashReportTextFormatter.h" + +/** + * @defgroup functions Crash Reporter Functions Reference + */ + +/** + * @defgroup types Crash Reporter Data Types Reference + */ + +/** + * @defgroup constants Crash Reporter Constants Reference + */ + +/** + * @internal + * @defgroup plcrash_internal Crash Reporter Internal Documentation + */ + +/** + * @defgroup enums Enumerations + * @ingroup constants + */ + +/** + * @defgroup globals Global Variables + * @ingroup constants + */ + +/** + * @defgroup exceptions Exceptions + * @ingroup constants + */ + +/* Exceptions */ +extern NSString *PLCrashReporterException; + +/* Error Domain and Codes */ +extern NSString *PLCrashReporterErrorDomain; + +/** + * NSError codes in the Plausible Crash Reporter error domain. + * @ingroup enums + */ +typedef enum { + /** An unknown error has occured. If this + * code is received, it is a bug, and should be reported. */ + PLCrashReporterErrorUnknown = 0, + + /** An Mach or POSIX operating system error has occured. The underlying NSError cause may be fetched from the userInfo + * dictionary using the NSUnderlyingErrorKey key. */ + PLCrashReporterErrorOperatingSystem = 1, + + /** The crash report log file is corrupt or invalid */ + PLCrashReporterErrorCrashReportInvalid = 2, + + /** An attempt to use a resource which was in use at the time in a manner which would have conflicted with the request. */ + PLCrashReporterErrorResourceBusy = 3 +} PLCrashReporterError; + + +/* Library Imports */ +#import "PLCrashReporter.h" +#import "PLCrashReport.h" +#import "PLCrashReportTextFormatter.h" + +/** + * @mainpage Plausible Crash Reporter + * + * @section intro_sec Introduction + * + * Plausile CrashReporter implements in-process crash reporting on the iPhone and Mac OS X. + * + * The following features are supported: + * + * - Implemented as an in-process signal handler. + * - Does not interfer with debugging in gdb.. + * - Handles both uncaught Objective-C exceptions and fatal signals (SIGSEGV, SIGBUS, etc). + * - Full thread state for all active threads (backtraces, register dumps) is provided. + * + * If your application crashes, a crash report will be written. When the application is next run, you may check for a + * pending crash report, and submit the report to your own HTTP server, send an e-mail, or even introspect the + * report locally. + * + * @section intro_encoding Crash Report Format + * + * Crash logs are encoded using google protobuf, and may be decoded + * using the provided PLCrashReport API. Additionally, the include plcrashutil handles conversion of binary crash reports to the + * symbolicate-compatible iPhone text format. + * + * @section doc_sections Documentation Sections + * - @subpage example_usage_iphone + * - @subpage error_handling + * - @subpage async_safety + */ + +/** + * @page example_usage_iphone Example iPhone Usage + * + * @code + * // + * // Called to handle a pending crash report. + * // + * - (void) handleCrashReport { + * PLCrashReporter *crashReporter = [PLCrashReporter sharedReporter]; + * NSData *crashData; + * NSError *error; + * + * // Try loading the crash report + * crashData = [crashReporter loadPendingCrashReportDataAndReturnError: &error]; + * if (crashData == nil) { + * NSLog(@"Could not load crash report: %@", error); + * goto finish; + * } + * + * // We could send the report from here, but we'll just print out + * // some debugging info instead + * PLCrashReport *report = [[[PLCrashReport alloc] initWithData: crashData error: &error] autorelease]; + * if (report == nil) { + * NSLog(@"Could not parse crash report"); + * goto finish; + * } + * + * NSLog(@"Crashed on %@", report.systemInfo.timestamp); + * NSLog(@"Crashed with signal %@ (code %@, address=0x%" PRIx64 ")", report.signalInfo.name, + * report.signalInfo.code, report.signalInfo.address); + * + * // Purge the report + * finish: + * [crashReporter purgePendingCrashReport]; + * return; + * } + * + * // from UIApplicationDelegate protocol + * - (void) applicationDidFinishLaunching: (UIApplication *) application { + * PLCrashReporter *crashReporter = [PLCrashReporter sharedReporter]; + * NSError *error; + * + * // Check if we previously crashed + * if ([crashReporter hasPendingCrashReport]) + * [self handleCrashReport]; + + * // Enable the Crash Reporter + * if (![crashReporter enableCrashReporterAndReturnError: &error]) + * NSLog(@"Warning: Could not enable crash reporter: %@", error); + * + * } + * @endcode + * + */ + +/** + * @page error_handling Error Handling Programming Guide + * + * Where a method may return an error, Plausible Crash Reporter provides access to the underlying + * cause via an optional NSError argument. + * + * All returned errors will be a member of one of the below defined domains, however, new domains and + * error codes may be added at any time. If you do not wish to report on the error cause, many methods + * support a simple form that requires no NSError argument. + * + * @section error_domains Error Domains, Codes, and User Info + * + * @subsection crashreporter_errors Crash Reporter Errors + * + * Any errors in Plausible Crash Reporter use the #PLCrashReporterErrorDomain error domain, and and one + * of the error codes defined in #PLCrashReporterError. + */ + +/** + * @page async_safety Async-Safe Programming Guide + * + * Plausible CrashReporter provides support for executing an application specified function in the context of the + * crash reporter's signal handler, after the crash report has been written to disk. This was a regularly requested + * feature, and provides the ability to implement application finalization in the event of a crash. However, writing + * code intended for execution inside of a signal handler is exceptionally difficult, and is not recommended. + * + * @section program_flow Program Flow and Signal Handlers + * + * When the signal handler is called the normal flow of the program is interrupted, and your program is an unknown + * state. Locks may be held, the heap may be corrupt (or in the process of being updated), and your signal + * handler may invoke a function that was being executed at the time of the signal. This may result in deadlocks, + * data corruption, and program termination. + * + * @section functions Async-Safe Functions + * + * A subset of functions are defined to be async-safe by the OS, and are safely callable from within a signal handler. If + * you do implement a custom post-crash handler, it must be async-safe. A table of POSIX-defined async-safe functions + * and additional information is available from the + * CERT programming guide - SIG30-C + * + * Most notably, the Objective-C runtime itself is not async-safe, and Objective-C may not be used within a signal + * handler. + * + * @sa PLCrashReporter::setCrashCallbacks: + */ + +/** + * @page mach_exceptions Mach Exceptions on Mac OS X and iOS + * + * PLCrashReporter includes support for monitoring crashes via an in-process Mach exception handler. There are a small + * number of crash cases that will not be caught with via a POSIX signal handler, but can be caught via a Mach + * exception handler: + * + * - Stack overflow. sigaltstack() is broken in later iOS releases, and even if functional, must be configured + * on a per-thread basis. + * - Internal Apple assertions that call libSystem's __assert. These include compiler-checked constraints + * for built-in functions, such as strcpy_chk(). The __abort() implementation actually disables the SIGABRT + * signal handler (resetting it to SIG_DFL) prior to to issueing a SIGABRT, bypassing signal-based crash + * reporters entirely. + * + * Unfortunately, the latter issue (__assert) can not be handled on iOS; trapping abort requires that + * a Mach exception handler operate out-of-process, which is impossible on iOS. On Mac OS X, this will + * only be handled once we've implemented fully out-of-process crash excution. + * + * On Mac OS X, the Mach exception implementation is fully supported using entirely public API. On iOS, + * the APIs required are not fully public -- more details on the implications of this for exception handling on + * iOS may be found in @ref mach_exceptions_ios below. It is worth noting that even where the Mach exception APIs + * are fully supported, kernel-internal constants, as well + * as architecture-specific trap information, may be required to fully interpret a Mach exception's root cause. + * + * For example, the EXC_SOFTWARE exception is dispatched for four different failure types, using the exception + * code to differentiate failure types: + * - Non-existent system call invoked (SIGSYS) + * - Write on a pipe with no reader (SIGPIPE) + * - Abort program (SIGABRT -- unused) + * - Kill program (SIGKILL) + * + * Of those four types, only the constant required to interpret the SIGKILL behavior (EXC_SOFT_SIGNAL) is publicly defined. + * Of the remaining three failure types, the constant values are kernel implementation-private, defined only in the available + * kernel sources. On iOS, these sources are unavailable, and while they generally do match the Mac OS X implementation, there + * are no gaurantees that this is -- or will remain -- the case in the future. + * + * Likewise, interpretation of particular fault types requires information regarding the underlying machine traps + * that triggered the Mach exceptions. For example, a floating point trap on x86/x86-64 will trigger an EXC_ARITHMETIC, + * with a subcode value containing the value of the FPU status register. Determining the exact FPU cause requires + * extracting the actual exception flags from status register as per the x86 architecture documentation. The exact format + * of this subcode value is not actually documented outside the kernel, and may change in future releases. + * + * While we have the advantage of access to the x86 kernel sources, the situation on ARM is even less clear. The actual + * use of the Mach exception codes and subcodes is largely undefined by both headers and publicly available documentation, + * and the available x86 kernel sources are of little use in interpreting this data. + * + * As such, while Mach exceptions may catch some cases that BSD signals can not, they are not a perfect solution, + * and may also provide less insight into the actual failures that occur. By comparison, the BSD signal interface + * is both fully defined and architecture independent, with any necessary interpretation of the Mach exception + * codes handled in-kernel at the time of exception dispatch. It is generally recommended by Apple as the preferred + * interface, and should generally be preferred by PLCrashReporter API clients. + * + * @section mach_exceptions_compatibility Compatibility Issues + * + * @subsection Debuggers + * + * Enabling in-process Mach exception handlers will conflict with any attached debuggers; the debugger + * may suspend the processes Mach exception handling thread, which will result in any exception messages + * sent via the debugger being lost, as the in-process handler will be unable to receive and forward + * the messages. + * + * @subsection Managed Runtimes (Xamarin, Unity) + * + * A Mach exception handler may conflict with any managed runtime that registers a BSD signal handler that + * can safely handle otherwise fatal signals, allowing execution to proceed. This includes products + * such as Xamarin for iOS. + * + * In such a case, PLCrashReporter will write a crash report for non-fatal signals, as there is no + * immediate mechanism for determining whether a signal handler exists and that it can safely + * handle the failure. This can result in unexpected delays in application execution, increased I/O to + * disk, and other undesirable operations. + * + * @section mach_exceptions_ios Mach Exceptions on iOS + * + * The APIs required for Mach exception handling are not fully public on iOS. After filing a request with + * Apple DTS to clarify the status of the Mach exception APIs on iOS, and implementing a Mach Exception + * handler using only supported API, they provided the following guidance: + * + * Our engineers have reviewed your request and have determined that this would be best handled as a bug report, + * which you have already filed. There is no documented way of accomplishing this, nor is there a workaround + * possible. + * + * Due to user request, PLCrashReporter provides an optional implementation of Mach exception handling for both + * iOS and Mac OS X. + * + * This implementation uses only supported API on Mac OS X, and depends on limited undefined API on iOS. The reporter + * may be excluded entirely at build time by modifying the PLCRASH_FEATURE_MACH_EXCEPTIONS build configuration; it + * may also be disabled at runtime by configuring the PLCrashReporter instance appropriately via PLCrashReporterConfig. + * + * The iOS implementation is implemented almost entirely using public API, and links against no actual private symbols; + * the use of undocumented functionality is limited to assuming the use of specific msgh_id values (see below + * for details). As a result, it may be considered perfectly safe to include the Mach Exception code in the + * standard build, and enable/disable it at runtime. + * + * The following issues exist in the iOS implementation: + * - The msgh_id values required for an exception reply message are not available from the available + * headers and must be hard-coded. This prevents one from safely replying to exception messages, which + * means that it is impossible to (correctly) inform the server that an exception has *not* been + * handled. + * + * Impact: + * This can lead to the process locking up and not dispatching to the host exception handler (eg, Apple's + * crash reporter), depending on the behavior of the kernel exception code. + * + * - The mach_* structure/type variants required by MACH_EXCEPTION_CODES are not publicly defined (on Mac OS X, + * these are provided by mach_exc.defs). This prevents one from forwarding exception messages to an existing + * handler that was registered with a MACH_EXCEPTION_CODES behavior (eg, forwarding is entirely non-functional + * on ARM64 devices). + * + * Impact: + * This can break forwarding to any task exception handler that registers itself with MACH_EXCEPTION_CODES, + * including other handlers registered within the current process, eg, by a managed runtime. This could + * also result in misinterpretation of a Mach exception message, in the case where the message format is + * modified by Apple to be incompatible with the existing 32-bit format. + * + * This is the case with LLDB; it will register a task exception handler with MACH_EXCEPTION_CODES set. Failure + * to correctly forward these exceptions will result in the debugger breaking in interesting ways; for example, + * changes to the set of dyld-loaded images are detected by setting a breakpoint on the dyld image registration + * funtions, and this functionality will break if the exception is not correctly forwarded. + * + * Since Mach exception handling is important for a fully functional crash reporter, we have also filed a radar + * to request that the API be made public: + * Radar: rdar://12939497 RFE: Provide mach_exc.defs for iOS + * + * At the time of this writing, the radar remains open/unresolved. + */ diff --git a/mac/CrashReporter.framework/Versions/A/Headers/PLCrashFeatureConfig.h b/mac/CrashReporter.framework/Versions/A/Headers/PLCrashFeatureConfig.h new file mode 100644 index 000000000..a4880481e --- /dev/null +++ b/mac/CrashReporter.framework/Versions/A/Headers/PLCrashFeatureConfig.h @@ -0,0 +1,104 @@ +/* + * Author: Landon Fuller + * + * Copyright (c) 2012-2013 Plausible Labs Cooperative, Inc. + * All rights reserved. + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ + +#ifndef PLCRASH_FEATURE_CONFIG_H +#define PLCRASH_FEATURE_CONFIG_H + +#include + +/** + * @internal + * + * Build-time configuration for PLCrashReporter. + * + * This is used to automatically enable/disable features on a per-platform and per-configuration + * basis; it may also be used by third-party vendors to configure a custom build of PLCrashReporter. + * + * @defgroup build_config Build Configuration + * @ingroup constants + * @{ + */ + +/* + * Defaults + */ + +/* + * For release builds, disable unused unwind implementations on targets that do not use them. For non-release + * builds, we include the unwind implementations to allow testing on a broader range of targets. + */ +#ifdef PLCF_RELEASE_BUILD +# if defined(__arm__) +# ifndef PLCRASH_FEATURE_UNWIND_DWARF +# define PLCRASH_FEATURE_UNWIND_DWARF 0 +# endif +# ifndef PLCRASH_FEATURE_UNWIND_COMPACT +# define PLCRASH_FEATURE_UNWIND_COMPACT 0 +# endif +# endif +#endif + +/* + * Configuration Flags + */ + + +#ifndef PLCRASH_FEATURE_MACH_EXCEPTIONS +/** + * If true, enable Mach exception support. On Mac OS X, the Mach exception implementation is fully supported, + * using publicly available API. On iOS, the APIs required for a complete implementation are not public. However, a + * popular commercial crash reporter is now shipping with support for Mach exceptions, which implies that either + * they've received special dispensation to use private APIs / private structures, they've found another way to do + * it, or they're just using undocumented functionality and hoping for the best. + * + * The exposed surface of undocumented API usage is relatively low, and there has been strong user demand to + * implement Mach exception handling regardless of concerns over API visiblity. Given this, we've enabled + * Mach exception handling by default, and provided both build-time and runtime configuration + * to disable its use. + * + * For more information on the potential issues with enabling mach exception support, @sa @ref mach_exceptions. + */ +# define PLCRASH_FEATURE_MACH_EXCEPTIONS 1 +#endif + +#ifndef PLCRASH_FEATURE_UNWIND_DWARF +/** If true, enable DWARF unwinding support. */ +# define PLCRASH_FEATURE_UNWIND_DWARF 1 +#endif + + +#ifndef PLCRASH_FEATURE_UNWIND_COMPACT +/** If true, enable compact unwinding support. */ +# define PLCRASH_FEATURE_UNWIND_COMPACT 1 +#endif + +/** + * @} + */ + +#endif /* PLCRASH_FEATURE_CONFIG_H */ diff --git a/mac/CrashReporter.framework/Versions/A/Headers/PLCrashNamespace.h b/mac/CrashReporter.framework/Versions/A/Headers/PLCrashNamespace.h new file mode 100644 index 000000000..571d0a27b --- /dev/null +++ b/mac/CrashReporter.framework/Versions/A/Headers/PLCrashNamespace.h @@ -0,0 +1,80 @@ +/* + * Author: Landon Fuller + * + * Copyright (c) 2012-2013 Plausible Labs Cooperative, Inc. + * All rights reserved. + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ + +/* + * For external library integrators: + * + * Set this value to any valid C symbol prefix. This will automatically + * prepend the given prefix to all external symbols in the library. + * + * This may be used to avoid symbol conflicts between multiple libraries + * that may both incorporate PLCrashReporter. + */ +// #define PLCRASHREPORTER_PREFIX AcmeCo + +#ifdef PLCRASHREPORTER_PREFIX + +// We need two extra layers of indirection to make CPP substitute +// the PLCRASHREPORTER_PREFIX define. +#define PLNS_impl2(prefix, symbol) prefix ## symbol +#define PLNS_impl(prefix, symbol) PLNS_impl2(prefix, symbol) +#define PLNS(symbol) PLNS_impl(PLCRASHREPORTER_PREFIX, symbol) + +#define PLCrashMachExceptionServer PLNS(PLCrashMachExceptionServer) +#define PLCrashReport PLNS(PLCrashReport) +#define PLCrashReportApplicationInfo PLNS(PLCrashReportApplicationInfo) +#define PLCrashReportBinaryImageInfo PLNS(PLCrashReportBinaryImageInfo) +#define PLCrashReportExceptionInfo PLNS(PLCrashReportExceptionInfo) +#define PLCrashReportMachExceptionInfo PLNS(PLCrashReportMachExceptionInfo) +#define PLCrashReportMachineInfo PLNS(PLCrashReportMachineInfo) +#define PLCrashReportProcessInfo PLNS(PLCrashReportProcessInfo) +#define PLCrashReportProcessorInfo PLNS(PLCrashReportProcessorInfo) +#define PLCrashReportRegisterInfo PLNS(PLCrashReportRegisterInfo) +#define PLCrashReportSignalInfo PLNS(PLCrashReportSignalInfo) +#define PLCrashReportStackFrameInfo PLNS(PLCrashReportStackFrameInfo) +#define PLCrashReportSymbolInfo PLNS(PLCrashReportSymbolInfo) +#define PLCrashReportSystemInfo PLNS(PLCrashReportSystemInfo) +#define PLCrashReportTextFormatter PLNS(PLCrashReportTextFormatter) +#define PLCrashReportThreadInfo PLNS(PLCrashReportThreadInfo) +#define PLCrashReporter PLNS(PLCrashReporter) +#define PLCrashSignalHandler PLNS(PLCrashSignalHandler) +#define PLCrashReportHostArchitecture PLNS(PLCrashReportHostArchitecture) +#define PLCrashReportHostOperatingSystem PLNS(PLCrashReportHostOperatingSystem) +#define PLCrashReporterErrorDomain PLNS(PLCrashReporterErrorDomain) +#define PLCrashReporterException PLNS(PLCrashReporterException) +#define PLCrashHostInfo PLNS(PLCrashHostInfo) +#define PLCrashMachExceptionPort PLNS(PLCrashMachExceptionPort) +#define PLCrashMachExceptionPortSet PLNS(PLCrashMachExceptionPortSet) +#define PLCrashProcessInfo PLNS(PLCrashProcessInfo) +#define PLCrashReporterConfig PLNS(PLCrashReporterConfig) +#define PLCrashUncaughtExceptionHandler PLNS(PLCrashUncaughtExceptionHandler) +#define PLCrashMachExceptionForward PLNS(PLCrashMachExceptionForward) +#define PLCrashSignalHandlerForward PLNS(PLCrashSignalHandlerForward) +#define plcrash_signal_handler PLNS(plcrash_signal_handler) + +#endif diff --git a/mac/CrashReporter.framework/Versions/A/Headers/PLCrashReport.h b/mac/CrashReporter.framework/Versions/A/Headers/PLCrashReport.h new file mode 100644 index 000000000..a179cd690 --- /dev/null +++ b/mac/CrashReporter.framework/Versions/A/Headers/PLCrashReport.h @@ -0,0 +1,200 @@ +/* + * Author: Landon Fuller + * + * Copyright (c) 2008-2013 Plausible Labs Cooperative, Inc. + * All rights reserved. + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ + +#import + +#import "PLCrashReportApplicationInfo.h" +#import "PLCrashReportBinaryImageInfo.h" +#import "PLCrashReportExceptionInfo.h" +#import "PLCrashReportMachineInfo.h" +#import "PLCrashReportMachExceptionInfo.h" +#import "PLCrashReportProcessInfo.h" +#import "PLCrashReportProcessorInfo.h" +#import "PLCrashReportRegisterInfo.h" +#import "PLCrashReportSignalInfo.h" +#import "PLCrashReportStackFrameInfo.h" +#import "PLCrashReportSymbolInfo.h" +#import "PLCrashReportSystemInfo.h" +#import "PLCrashReportThreadInfo.h" + +/** + * @ingroup constants + * Crash file magic identifier */ +#define PLCRASH_REPORT_FILE_MAGIC "plcrash" + +/** + * @ingroup constants + * Crash format version byte identifier. Will not change outside of the introduction of + * an entirely new crash log format. */ +#define PLCRASH_REPORT_FILE_VERSION 1 + +/** + * @ingroup types + * Crash log file header format. + * + * Crash log files start with 7 byte magic identifier (#PLCRASH_REPORT_FILE_MAGIC), + * followed by a single unsigned byte version number (#PLCRASH_REPORT_FILE_VERSION). + * The crash log message format itself is extensible, so this version number will only + * be incremented in the event of an incompatible encoding or format change. + */ +struct PLCrashReportFileHeader { + /** Crash log magic identifier, not NULL terminated */ + const char magic[7]; + + /** Crash log encoding/format version */ + const uint8_t version; + + /** File data */ + const uint8_t data[]; +} __attribute__((packed)); + + +/** + * @internal + * Private decoder instance variables (used to hide the underlying protobuf parser). + */ +typedef struct _PLCrashReportDecoder _PLCrashReportDecoder; + +@interface PLCrashReport : NSObject { +@private + /** Private implementation variables (used to hide the underlying protobuf parser) */ + _PLCrashReportDecoder *_decoder; + + /** System info */ + PLCrashReportSystemInfo *_systemInfo; + + /** Machine info */ + PLCrashReportMachineInfo *_machineInfo; + + /** Application info */ + PLCrashReportApplicationInfo *_applicationInfo; + + /** Process info */ + PLCrashReportProcessInfo *_processInfo; + + /** Signal info */ + PLCrashReportSignalInfo *_signalInfo; + + /** Mach exception info */ + PLCrashReportMachExceptionInfo *_machExceptionInfo; + + /** Thread info (PLCrashReportThreadInfo instances) */ + NSArray *_threads; + + /** Binary images (PLCrashReportBinaryImageInfo instances */ + NSArray *_images; + + /** Exception information (may be nil) */ + PLCrashReportExceptionInfo *_exceptionInfo; + + /** Report UUID */ + CFUUIDRef _uuid; +} + +- (id) initWithData: (NSData *) encodedData error: (NSError **) outError; + +- (PLCrashReportBinaryImageInfo *) imageForAddress: (uint64_t) address; + +/** + * System information. + */ +@property(nonatomic, readonly) PLCrashReportSystemInfo *systemInfo; + +/** + * YES if machine information is available. + */ +@property(nonatomic, readonly) BOOL hasMachineInfo; + +/** + * Machine information. Only available in later (v1.1+) crash report format versions. If not available, + * will be nil. + */ +@property(nonatomic, readonly) PLCrashReportMachineInfo *machineInfo; + +/** + * Application information. + */ +@property(nonatomic, readonly) PLCrashReportApplicationInfo *applicationInfo; + +/** + * YES if process information is available. + */ +@property(nonatomic, readonly) BOOL hasProcessInfo; + +/** + * Process information. Only available in later (v1.1+) crash report format versions. If not available, + * will be nil. + */ +@property(nonatomic, readonly) PLCrashReportProcessInfo *processInfo; + +/** + * Signal information. This provides the signal and signal code of the fatal signal. + */ +@property(nonatomic, readonly) PLCrashReportSignalInfo *signalInfo; + +/** + * Mach exception information, if available. This will only be included in the + * case that encoding crash reporter's exception-based reporting was enabled, and a Mach + * exception was caught. + * + * @warning If Mach exception information is available, the legacy signalInfo property will also be provided; this + * s required to maintain backwards compatibility with the established API. Note, however, that the signal info may be derived from the + * Mach exception info by the encoding crash reporter, and thus may not exactly match the kernel exception-to-signal + * mappings implemented in xnu. As such, when Mach exception info is available, its use should be preferred. + */ +@property(nonatomic, readonly) PLCrashReportMachExceptionInfo *machExceptionInfo; + +/** + * Thread information. Returns a list of PLCrashReportThreadInfo instances. + */ +@property(nonatomic, readonly) NSArray *threads; + +/** + * Binary image information. Returns a list of PLCrashReportBinaryImageInfo instances. + */ +@property(nonatomic, readonly) NSArray *images; + +/** + * YES if exception information is available. + */ +@property(nonatomic, readonly) BOOL hasExceptionInfo; + +/** + * Exception information. Only available if a crash was caused by an uncaught exception, + * otherwise nil. + */ +@property(nonatomic, readonly) PLCrashReportExceptionInfo *exceptionInfo; + +/** + * A client-generated 16-byte UUID. May be used to filter duplicate reports submitted or generated + * by a single client. Only available in later (v1.2+) crash report format versions. If not available, + * will be NULL. + */ +@property(nonatomic, readonly) CFUUIDRef uuidRef; + +@end diff --git a/mac/CrashReporter.framework/Versions/A/Headers/PLCrashReportApplicationInfo.h b/mac/CrashReporter.framework/Versions/A/Headers/PLCrashReportApplicationInfo.h new file mode 100644 index 000000000..0f84c8959 --- /dev/null +++ b/mac/CrashReporter.framework/Versions/A/Headers/PLCrashReportApplicationInfo.h @@ -0,0 +1,53 @@ +/* + * Author: Landon Fuller + * + * Copyright (c) 2008-2009 Plausible Labs Cooperative, Inc. + * All rights reserved. + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ + +#import + +@interface PLCrashReportApplicationInfo : NSObject { +@private + /** Application identifier */ + NSString *_applicationIdentifier; + + /** Application version */ + NSString *_applicationVersion; +} + +- (id) initWithApplicationIdentifier: (NSString *) applicationIdentifier + applicationVersion: (NSString *) applicationVersion; + +/** + * The application identifier. This is usually the application's CFBundleIdentifier value. + */ +@property(nonatomic, readonly) NSString *applicationIdentifier; + +/** + * The application version. This is usually the application's CFBundleVersion value. + */ +@property(nonatomic, readonly) NSString *applicationVersion; + +@end diff --git a/mac/CrashReporter.framework/Versions/A/Headers/PLCrashReportBinaryImageInfo.h b/mac/CrashReporter.framework/Versions/A/Headers/PLCrashReportBinaryImageInfo.h new file mode 100644 index 000000000..339fdbb08 --- /dev/null +++ b/mac/CrashReporter.framework/Versions/A/Headers/PLCrashReportBinaryImageInfo.h @@ -0,0 +1,90 @@ +/* + * Author: Landon Fuller + * + * Copyright (c) 2008-2009 Plausible Labs Cooperative, Inc. + * All rights reserved. + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ + +#import +#import "PLCrashReportProcessorInfo.h" + +@interface PLCrashReportBinaryImageInfo : NSObject { +@private + /** Code type */ + PLCrashReportProcessorInfo *_processorInfo; + + /** Base image address */ + uint64_t _baseAddress; + + /** Image segment size */ + uint64_t _imageSize; + + /** Name of binary image */ + NSString *_imageName; + + /** If the UUID is available */ + BOOL _hasImageUUID; + + /** 128-bit object UUID. May be nil. */ + NSString *_imageUUID; +} + +- (id) initWithCodeType: (PLCrashReportProcessorInfo *) processorInfo + baseAddress: (uint64_t) baseAddress + size: (uint64_t) imageSize + name: (NSString *) imageName + uuid: (NSData *) uuid; + +/** + * Image code type, or nil if unavailable. + */ +@property(nonatomic, readonly) PLCrashReportProcessorInfo *codeType; + +/** + * Image base address. + */ +@property(nonatomic, readonly) uint64_t imageBaseAddress; + +/** + * Segment size. + */ +@property(nonatomic, readonly) uint64_t imageSize; + +/** + * Image name (absolute path) + */ +@property(nonatomic, readonly) NSString *imageName; + + +/** + * YES if this image has an associated UUID. + */ +@property(nonatomic, readonly) BOOL hasImageUUID; + +/** + * 128-bit object UUID (matches Mach-O DWARF dSYM files). May be nil if unavailable. + */ +@property(nonatomic, readonly) NSString *imageUUID; + +@end diff --git a/mac/CrashReporter.framework/Versions/A/Headers/PLCrashReportExceptionInfo.h b/mac/CrashReporter.framework/Versions/A/Headers/PLCrashReportExceptionInfo.h new file mode 100644 index 000000000..623b1d4e1 --- /dev/null +++ b/mac/CrashReporter.framework/Versions/A/Headers/PLCrashReportExceptionInfo.h @@ -0,0 +1,65 @@ +/* + * Author: Landon Fuller + * + * Copyright (c) 2008-2009 Plausible Labs Cooperative, Inc. + * All rights reserved. + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ + +#import +#import "PLCrashReportThreadInfo.h" + + +@interface PLCrashReportExceptionInfo : NSObject { +@private + /** Name */ + NSString *_name; + + /** Reason */ + NSString *_reason; + + /** Ordered list of PLCrashReportStackFrame instances, or nil if unavailable. */ + NSArray *_stackFrames; +} + +- (id) initWithExceptionName: (NSString *) name reason: (NSString *) reason; + +- (id) initWithExceptionName: (NSString *) name + reason: (NSString *) reason + stackFrames: (NSArray *) stackFrames; + +/** + * The exception name. + */ +@property(nonatomic, readonly) NSString *exceptionName; + +/** + * The exception reason. + */ +@property(nonatomic, readonly) NSString *exceptionReason; + +/* The exception's original call stack, as an array of PLCrashReportStackFrameInfo instances, or nil if unavailable. + * This may be preserved across rethrow of an exception, and can be used to determine the original call stack. */ +@property(nonatomic, readonly) NSArray *stackFrames; + +@end diff --git a/mac/CrashReporter.framework/Versions/A/Headers/PLCrashReportFormatter.h b/mac/CrashReporter.framework/Versions/A/Headers/PLCrashReportFormatter.h new file mode 100644 index 000000000..77c2029fd --- /dev/null +++ b/mac/CrashReporter.framework/Versions/A/Headers/PLCrashReportFormatter.h @@ -0,0 +1,51 @@ +/* + * Author: Landon Fuller + * + * Copyright (c) 2008-2013 Plausible Labs Cooperative, Inc. + * All rights reserved. + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ + +#import + +#import "PLCrashReport.h" + +/** + * A crash report formatter accepts a PLCrashReport instance, formats it according to implementation-specified rules, + * (such as implementing text output support), and returns the result. + */ +@protocol PLCrashReportFormatter + +/** + * Format the provided @a report. + * + * @param report Report to be formatted. + * @param outError A pointer to an NSError object variable. If an error occurs, this pointer will contain an error + * object indicating why the pending crash report could not be formatted. If no error occurs, this parameter will + * be left unmodified. You may specify nil for this parameter, and no error information will be provided. + * + * @return Returns the formatted report data on success, or nil on failure. + */ +- (NSData *) formatReport: (PLCrashReport *) report error: (NSError **) outError; + +@end diff --git a/mac/CrashReporter.framework/Versions/A/Headers/PLCrashReportMachExceptionInfo.h b/mac/CrashReporter.framework/Versions/A/Headers/PLCrashReportMachExceptionInfo.h new file mode 100644 index 000000000..a9d7f7c24 --- /dev/null +++ b/mac/CrashReporter.framework/Versions/A/Headers/PLCrashReportMachExceptionInfo.h @@ -0,0 +1,48 @@ +/* + * Author: Landon Fuller + * + * Copyright (c) 2013 Plausible Labs Cooperative, Inc. + * All rights reserved. + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ + +#import + +@interface PLCrashReportMachExceptionInfo : NSObject { +@private + /** The Mach exception type. */ + uint64_t _type; + + /** The Mach exception codes, represented as an ordered array of NSNumber instances. */ + NSArray *_codes; +} + +- (id) initWithType: (uint64_t) type codes: (NSArray *) codes; + +/** The Mach exception type. */ +@property(nonatomic, readonly) uint64_t type; + +/** The Mach exception codes, represented as an ordered array of 64-bit unsigned NSNumber instances. */ +@property(nonatomic, readonly) NSArray *codes; + +@end diff --git a/mac/CrashReporter.framework/Versions/A/Headers/PLCrashReportMachineInfo.h b/mac/CrashReporter.framework/Versions/A/Headers/PLCrashReportMachineInfo.h new file mode 100644 index 000000000..4d0597c1d --- /dev/null +++ b/mac/CrashReporter.framework/Versions/A/Headers/PLCrashReportMachineInfo.h @@ -0,0 +1,73 @@ +/* + * Author: Landon Fuller + * + * Copyright (c) 2008-2013 Plausible Labs Cooperative, Inc. + * All rights reserved. + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ + +#import + +#import "PLCrashReportProcessorInfo.h" + +@interface PLCrashReportMachineInfo : NSObject { +@private + /** The hardware model name (eg, MacBookPro6,1). This may be unavailable, and this property will be nil. */ + NSString *_modelName; + + /** The processor type. */ + PLCrashReportProcessorInfo *_processorInfo; + + /* The number of actual physical processor cores. */ + NSUInteger _processorCount; + + /* The number of logical processors. */ + NSUInteger _logicalProcessorCount; +} + +- (id) initWithModelName: (NSString *) modelName + processorInfo: (PLCrashReportProcessorInfo *) processorInfo + processorCount: (NSUInteger) processorCount + logicalProcessorCount: (NSUInteger) logicalProcessorCount; + +/** The hardware model name (eg, MacBookPro6,1). This may be unavailable, and this property will be nil. */ +@property(nonatomic, readonly) NSString *modelName; + +/** The processor type. This will be unavailable in reports generated prior to PLCrashReporter 1.2, in which case this property will be nil. */ +@property(nonatomic, readonly) PLCrashReportProcessorInfo *processorInfo; + +/* + * The number of actual physical processor cores. Note that the number of active processors may be managed by the + * operating system's power management system, and this value may not reflect the number of active + * processors at the time of the crash. + */ +@property(nonatomic, readonly) NSUInteger processorCount; + +/* + * The number of logical processors. Note that the number of active processors may be managed by the + * operating system's power management system, and this value may not reflect the number of active + * processors at the time of the crash. + */ +@property(nonatomic, readonly) NSUInteger logicalProcessorCount; + +@end diff --git a/mac/CrashReporter.framework/Versions/A/Headers/PLCrashReportProcessInfo.h b/mac/CrashReporter.framework/Versions/A/Headers/PLCrashReportProcessInfo.h new file mode 100644 index 000000000..ca683d50d --- /dev/null +++ b/mac/CrashReporter.framework/Versions/A/Headers/PLCrashReportProcessInfo.h @@ -0,0 +1,103 @@ +/* + * Author: Damian Morris + * + * Copyright (c) 2010 MOSO Corporation, Pty Ltd. + * Copyright (c) 2010-2013 Plausible Labs Cooperative, Inc. + * + * All rights reserved. + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ + +#import + +@interface PLCrashReportProcessInfo : NSObject { +@private + /** Process name, or nil if unavailable. */ + NSString *_processName; + + /** Process ID */ + NSUInteger _processID; + + /** Process path */ + NSString* _processPath; + + /** Date and time that the crashing process was started. This may be unavailable, and this property + * will be nil. */ + NSDate *_processStartTime; + + /** Parent process name, or nil if unavailable. */ + NSString *_parentProcessName; + + /** Parent process ID */ + NSUInteger _parentProcessID; + + /** If false, the process is being run via process-level CPU emulation (such as Rosetta). */ + BOOL _native; +} + +- (id) initWithProcessName: (NSString *) processName + processID: (NSUInteger) processID + processPath: (NSString *) processPath + processStartTime: (NSDate *) processStartTime + parentProcessName: (NSString *) parentProcessName + parentProcessID: (NSUInteger) parentProcessID + native: (BOOL) native; + +/** + * The process name. This value may not be included in the crash report, in which case this property + * will be nil. + */ +@property(nonatomic, readonly) NSString *processName; + +/** + * The process ID. + */ +@property(nonatomic, readonly) NSUInteger processID; + +/** + * The path to the process executable. This value may not be included in the crash report, in which case this property + * will be nil. + */ +@property(nonatomic, readonly) NSString *processPath; + +/** + * Date and time that the crashing process was started. This value may not be included in the crash report, in which case this property + * will be nil. + */ +@property(nonatomic, readonly) NSDate *processStartTime; + +/** + * The parent process name. This value may not be included in the crash report, in which case this property + * will be nil. + */ +@property(nonatomic, readonly) NSString *parentProcessName; + +/** + * The parent process ID. + */ +@property(nonatomic, readonly) NSUInteger parentProcessID; + +/** The process' native execution status. If false, the process is being run via process-level CPU emulation (such as Rosetta). */ +@property(nonatomic, readonly) BOOL native; + +@end diff --git a/mac/CrashReporter.framework/Versions/A/Headers/PLCrashReportProcessorInfo.h b/mac/CrashReporter.framework/Versions/A/Headers/PLCrashReportProcessorInfo.h new file mode 100644 index 000000000..03d570bd4 --- /dev/null +++ b/mac/CrashReporter.framework/Versions/A/Headers/PLCrashReportProcessorInfo.h @@ -0,0 +1,74 @@ +/* + * Author: Landon Fuller + * + * Copyright (c) 2008-2013 Plausible Labs Cooperative, Inc. + * All rights reserved. + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ + +#import +#import + +/** + * @ingroup constants + * + * The type encodings supported for CPU types and subtypes. Currently only Apple + * Mach-O defined encodings are supported. + * + * @internal + * These enum values match the protobuf values. Keep them synchronized. + */ +typedef enum { + /** Unknown cpu type encoding. */ + PLCrashReportProcessorTypeEncodingUnknown = 0, + + /** Apple Mach-defined processor types. */ + PLCrashReportProcessorTypeEncodingMach = 1 +} PLCrashReportProcessorTypeEncoding; + +@interface PLCrashReportProcessorInfo : NSObject { +@private + /** Type encoding */ + PLCrashReportProcessorTypeEncoding _typeEncoding; + + /** CPU type */ + uint64_t _type; + + /** CPU subtype */ + uint64_t _subtype; +} + +- (id) initWithTypeEncoding: (PLCrashReportProcessorTypeEncoding) typeEncoding + type: (uint64_t) type + subtype: (uint64_t) subtype; + +/** The CPU type encoding. */ +@property(nonatomic, readonly) PLCrashReportProcessorTypeEncoding typeEncoding; + +/** The CPU type. */ +@property(nonatomic, readonly) uint64_t type; + +/** The CPU subtype. */ +@property(nonatomic, readonly) uint64_t subtype; + +@end diff --git a/mac/CrashReporter.framework/Versions/A/Headers/PLCrashReportRegisterInfo.h b/mac/CrashReporter.framework/Versions/A/Headers/PLCrashReportRegisterInfo.h new file mode 100644 index 000000000..20b618d74 --- /dev/null +++ b/mac/CrashReporter.framework/Versions/A/Headers/PLCrashReportRegisterInfo.h @@ -0,0 +1,52 @@ +/* + * Author: Landon Fuller + * + * Copyright (c) 2008-2013 Plausible Labs Cooperative, Inc. + * All rights reserved. + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ + +#import + +@interface PLCrashReportRegisterInfo : NSObject { +@private + /** Register name */ + NSString *_registerName; + + /** Register value */ + uint64_t _registerValue; +} + +- (id) initWithRegisterName: (NSString *) registerName registerValue: (uint64_t) registerValue; + +/** + * Register name. + */ +@property(nonatomic, readonly) NSString *registerName; + +/** + * Register value. + */ +@property(nonatomic, readonly) uint64_t registerValue; + +@end diff --git a/mac/CrashReporter.framework/Versions/A/Headers/PLCrashReportSignalInfo.h b/mac/CrashReporter.framework/Versions/A/Headers/PLCrashReportSignalInfo.h new file mode 100644 index 000000000..2c5c5fe23 --- /dev/null +++ b/mac/CrashReporter.framework/Versions/A/Headers/PLCrashReportSignalInfo.h @@ -0,0 +1,60 @@ +/* + * Author: Landon Fuller + * + * Copyright (c) 2008-2009 Plausible Labs Cooperative, Inc. + * All rights reserved. + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ + +#import + +@interface PLCrashReportSignalInfo : NSObject { +@private + /** Signal name */ + NSString *_name; + + /** Signal code */ + NSString *_code; + + /** Fauling instruction or address */ + uint64_t _address; +} + +- (id) initWithSignalName: (NSString *) name code: (NSString *) code address: (uint64_t) address; + +/** + * The signal name. + */ +@property(nonatomic, readonly) NSString *name; + +/** + * The signal code. + */ +@property(nonatomic, readonly) NSString *code; + +/** + * The faulting instruction or address. + */ +@property(nonatomic, readonly) uint64_t address; + +@end diff --git a/mac/CrashReporter.framework/Versions/A/Headers/PLCrashReportStackFrameInfo.h b/mac/CrashReporter.framework/Versions/A/Headers/PLCrashReportStackFrameInfo.h new file mode 100644 index 000000000..997e76265 --- /dev/null +++ b/mac/CrashReporter.framework/Versions/A/Headers/PLCrashReportStackFrameInfo.h @@ -0,0 +1,52 @@ +/* + * Author: Landon Fuller + * + * Copyright (c) 2008-2013 Plausible Labs Cooperative, Inc. + * All rights reserved. + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ + +#import +#import "PLCrashReportSymbolInfo.h" + +@interface PLCrashReportStackFrameInfo : NSObject { +@private + /** Frame instruction pointer. */ + uint64_t _instructionPointer; + + /** Symbol information, if available. Otherwise, will be nil. */ + PLCrashReportSymbolInfo *_symbolInfo; +} + +- (id) initWithInstructionPointer: (uint64_t) instructionPointer symbolInfo: (PLCrashReportSymbolInfo *) symbolInfo; + +/** + * Frame's instruction pointer. + */ +@property(nonatomic, readonly) uint64_t instructionPointer; + +/** Symbol information for this frame. + * This may be unavailable, and this property will be nil. */ +@property(nonatomic, readonly) PLCrashReportSymbolInfo *symbolInfo; + +@end diff --git a/mac/CrashReporter.framework/Versions/A/Headers/PLCrashReportSymbolInfo.h b/mac/CrashReporter.framework/Versions/A/Headers/PLCrashReportSymbolInfo.h new file mode 100644 index 000000000..c6ceb6c10 --- /dev/null +++ b/mac/CrashReporter.framework/Versions/A/Headers/PLCrashReportSymbolInfo.h @@ -0,0 +1,61 @@ +/* + * Author: Landon Fuller + * + * Copyright (c) 2012-2013 Plausible Labs Cooperative, Inc. + * All rights reserved. + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ + +#import + +@interface PLCrashReportSymbolInfo : NSObject { +@private + /** The symbol name. */ + NSString *_symbolName; + + /** The symbol start address. */ + uint64_t _startAddress; + + /** The symbol end address, if explicitly defined. Will be 0 if unknown. */ + uint64_t _endAddress; +} + +- (id) initWithSymbolName: (NSString *) symbolName + startAddress: (uint64_t) startAddress + endAddress: (uint64_t) endAddress; + +/** The symbol name. */ +@property(nonatomic, readonly) NSString *symbolName; + +/** The symbol start address. */ +@property(nonatomic, readonly) uint64_t startAddress; + +/* The symbol end address, if explicitly defined. This will only be included if the end address is + * explicitly defined (eg, by DWARF debugging information), will not be derived by best-guess + * heuristics. + * + * If unknown, the address will be 0. + */ +@property(nonatomic, readonly) uint64_t endAddress; + +@end diff --git a/mac/CrashReporter.framework/Versions/A/Headers/PLCrashReportSystemInfo.h b/mac/CrashReporter.framework/Versions/A/Headers/PLCrashReportSystemInfo.h new file mode 100644 index 000000000..e98c969c8 --- /dev/null +++ b/mac/CrashReporter.framework/Versions/A/Headers/PLCrashReportSystemInfo.h @@ -0,0 +1,145 @@ +/* + * Author: Landon Fuller + * + * Copyright (c) 2008-2009 Plausible Labs Cooperative, Inc. + * All rights reserved. + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ + +#import + +/** + * @ingroup constants + * + * Indicates the Operating System under which a Crash Log was generated. + * + * @internal + * These enum values match the protobuf values. Keep them synchronized. + */ +typedef enum { + /** Mac OS X. */ + PLCrashReportOperatingSystemMacOSX = 0, + + /** iPhone OS */ + PLCrashReportOperatingSystemiPhoneOS = 1, + + /** iPhone Simulator (Mac OS X with additional simulator-specific runtime libraries) */ + PLCrashReportOperatingSystemiPhoneSimulator = 2, + + /** Unknown operating system */ + PLCrashReportOperatingSystemUnknown = 3, +} PLCrashReportOperatingSystem; + +/** + * @ingroup constants + * + * Indicates the architecture under which a Crash Log was generated. + * + * @deprecated The architecture value has been deprecated in v1.1 and later crash reports. All new reports + * will make use of the new PLCrashReportProcessorInfo CPU type encodings. + * + * @internal + * These enum values match the protobuf values. Keep them synchronized. + */ +typedef enum { + /** x86-32. */ + PLCrashReportArchitectureX86_32 = 0, + + /** x86-64 */ + PLCrashReportArchitectureX86_64 = 1, + + /** ARMv6 */ + PLCrashReportArchitectureARMv6 = 2, + + /** + * ARMv6 + * @deprecated This value has been deprecated in favor of ARM subtype-specific + * values. + * @sa PLCrashReportArchitectureARMv6 + */ + PLCrashReportArchitectureARM = PLCrashReportArchitectureARMv6, + + /** PPC */ + PLCrashReportArchitecturePPC = 3, + + /** PPC64 */ + PLCrashReportArchitecturePPC64 = 4, + + /** ARMv7 */ + PLCrashReportArchitectureARMv7 = 5, + + /** Unknown */ + PLCrashReportArchitectureUnknown = 6 +} PLCrashReportArchitecture; + + +extern PLCrashReportOperatingSystem PLCrashReportHostOperatingSystem; +extern PLCrashReportArchitecture PLCrashReportHostArchitecture; + +@interface PLCrashReportSystemInfo : NSObject { +@private + /** Operating system */ + PLCrashReportOperatingSystem _operatingSystem; + + /** Operating system version */ + NSString *_osVersion; + + /** OS build. May be nil. */ + NSString *_osBuild; + + /** Architecture */ + PLCrashReportArchitecture _architecture; + + /** Date crash report was generated. May be nil if the date is unknown. */ + NSDate *_timestamp; +} + +- (id) initWithOperatingSystem: (PLCrashReportOperatingSystem) operatingSystem + operatingSystemVersion: (NSString *) operatingSystemVersion + architecture: (PLCrashReportArchitecture) architecture + timestamp: (NSDate *) timestamp; + +- (id) initWithOperatingSystem: (PLCrashReportOperatingSystem) operatingSystem + operatingSystemVersion: (NSString *) operatingSystemVersion + operatingSystemBuild: (NSString *) operatingSystemBuild + architecture: (PLCrashReportArchitecture) architecture + timestamp: (NSDate *) timestamp; + +/** The operating system. */ +@property(nonatomic, readonly) PLCrashReportOperatingSystem operatingSystem; + +/** The operating system's release version. */ +@property(nonatomic, readonly) NSString *operatingSystemVersion; + +/** The operating system's build identifier (eg, 10J869). This may be unavailable, and this property will be nil. */ +@property(nonatomic, readonly) NSString *operatingSystemBuild; + +/** Architecture. @deprecated The architecture value has been deprecated in v1.1 and later crash reports. All new reports + * include the CPU type as part of the crash report's machine info structure, using the PLCrashReportProcessorInfo + * extensible encoding. */ +@property(nonatomic, readonly) PLCrashReportArchitecture architecture; + +/** Date and time that the crash report was generated. This may be unavailable, and this property will be nil. */ +@property(nonatomic, readonly) NSDate *timestamp; + +@end diff --git a/mac/CrashReporter.framework/Versions/A/Headers/PLCrashReportTextFormatter.h b/mac/CrashReporter.framework/Versions/A/Headers/PLCrashReportTextFormatter.h new file mode 100644 index 000000000..2ba7e3503 --- /dev/null +++ b/mac/CrashReporter.framework/Versions/A/Headers/PLCrashReportTextFormatter.h @@ -0,0 +1,62 @@ +/* + * Authors: + * Landon Fuller + * Damian Morris + * + * Copyright (c) 2008-2013 Plausible Labs Cooperative, Inc. + * Copyright (c) 2010 MOSO Corporation, Pty Ltd. + * All rights reserved. + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ + + +#import + +#import "PLCrashReportFormatter.h" + +/** + * Supported text output formats. + * + * @ingroup enums + */ +typedef enum { + /** An iOS-compatible crash log text format. Compatible with the crash logs generated by the device and available + * through iTunes Connect. */ + PLCrashReportTextFormatiOS = 0 +} PLCrashReportTextFormat; + + +@interface PLCrashReportTextFormatter : NSObject { +@private + /** Text output format. */ + PLCrashReportTextFormat _textFormat; + + /** Encoding to use for string output. */ + NSStringEncoding _stringEncoding; +} + ++ (NSString *) stringValueForCrashReport: (PLCrashReport *) report withTextFormat: (PLCrashReportTextFormat) textFormat; + +- (id) initWithTextFormat: (PLCrashReportTextFormat) textFormat stringEncoding: (NSStringEncoding) stringEncoding; + +@end diff --git a/mac/CrashReporter.framework/Versions/A/Headers/PLCrashReportThreadInfo.h b/mac/CrashReporter.framework/Versions/A/Headers/PLCrashReportThreadInfo.h new file mode 100644 index 000000000..04c860445 --- /dev/null +++ b/mac/CrashReporter.framework/Versions/A/Headers/PLCrashReportThreadInfo.h @@ -0,0 +1,77 @@ +/* + * Author: Landon Fuller + * + * Copyright (c) 2008-2009 Plausible Labs Cooperative, Inc. + * All rights reserved. + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ + +#import + +#import "PLCrashReportStackFrameInfo.h" +#import "PLCrashReportRegisterInfo.h" + +@interface PLCrashReportThreadInfo : NSObject { +@private + /** The thread number. Should be unique within a given crash log. */ + NSInteger _threadNumber; + + /** Ordered list of PLCrashReportStackFrame instances */ + NSArray *_stackFrames; + + /** YES if this thread crashed. */ + BOOL _crashed; + + /** List of PLCrashReportRegister instances. Will be empty if _crashed is NO. */ + NSArray *_registers; +} + +- (id) initWithThreadNumber: (NSInteger) threadNumber + stackFrames: (NSArray *) stackFrames + crashed: (BOOL) crashed + registers: (NSArray *) registers; + +/** + * Application thread number. + */ +@property(nonatomic, readonly) NSInteger threadNumber; + +/** + * Thread backtrace. Provides an array of PLCrashReportStackFrameInfo instances. + * The array is ordered, last callee to first. + */ +@property(nonatomic, readonly) NSArray *stackFrames; + +/** + * If this thread crashed, set to YES. + */ +@property(nonatomic, readonly) BOOL crashed; + +/** + * State of the general purpose and related registers, as a list of + * PLCrashReportRegister instances. If this thead did not crash (crashed returns NO), + * this list will be empty. + */ +@property(nonatomic, readonly) NSArray *registers; + +@end diff --git a/mac/CrashReporter.framework/Versions/A/Headers/PLCrashReporter.h b/mac/CrashReporter.framework/Versions/A/Headers/PLCrashReporter.h new file mode 100644 index 000000000..88824a688 --- /dev/null +++ b/mac/CrashReporter.framework/Versions/A/Headers/PLCrashReporter.h @@ -0,0 +1,133 @@ +/* + * Author: Landon Fuller + * + * Copyright (c) 2008-2009 Plausible Labs Cooperative, Inc. + * All rights reserved. + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ + +#import +#import + +#import "PLCrashReporterConfig.h" + +@class PLCrashMachExceptionServer; +@class PLCrashMachExceptionPortSet; + +/** + * @ingroup functions + * + * Prototype of a callback function used to execute additional user code with signal information as provided + * by PLCrashReporter. Called upon completion of crash handling, after the crash report has been written to disk. + * + * @param info The signal info. + * @param uap The crash's threads context. + * @param context The API client's supplied context value. + * + * @sa @ref async_safety + * @sa PLCrashReporter::setPostCrashCallbacks: + */ +typedef void (*PLCrashReporterPostCrashSignalCallback)(siginfo_t *info, ucontext_t *uap, void *context); + +/** + * @ingroup types + * + * This structure contains callbacks supported by PLCrashReporter to allow the host application to perform + * additional tasks prior to program termination after a crash has occured. + * + * @sa @ref async_safety + */ +typedef struct PLCrashReporterCallbacks { + /** The version number of this structure. If not one of the defined version numbers for this type, the behavior + * is undefined. The current version of this structure is 0. */ + uint16_t version; + + /** An arbitrary user-supplied context value. This value may be NULL. */ + void *context; + + /** + * The callback used to report caught signal information. In version 0 of this structure, all crashes will be + * reported via this function. + * + * @warning When using PLCrashReporterSignalHandlerTypeMach, the siginfo_t argument to this function will be derived + * from the Mach exception data, and may be incorrect, or may otherwise not match the expected data as provided via + * PLCrashReporterSignalHandlerTypeBSD. In addition, the provided ucontext_t value will be zero-initialized, and will + * not provide valid thread state. + * + * This callback will be deprecated in favor of a Mach-compatible replacement in a future release; support is maintained + * here to allow clients that rely on post-crash callbacks without thread state to make use of Mach exceptions. + */ + PLCrashReporterPostCrashSignalCallback handleSignal; +} PLCrashReporterCallbacks; + +@interface PLCrashReporter : NSObject { +@private + /** Reporter configuration */ + PLCrashReporterConfig *_config; + + /** YES if the crash reporter has been enabled */ + BOOL _enabled; + +#if PLCRASH_FEATURE_MACH_EXCEPTIONS + /** The backing Mach exception server, if any. Nil if the reporter has not been enabled, or if + * the configured signal handler type is not PLCrashReporterSignalHandlerTypeMach. */ + PLCrashMachExceptionServer *_machServer; + + /** Previously registered Mach exception ports, if any. */ + PLCrashMachExceptionPortSet *_previousMachPorts; +#endif /* PLCRASH_FEATURE_MACH_EXCEPTIONS */ + + /** Application identifier */ + NSString *_applicationIdentifier; + + /** Application version */ + NSString *_applicationVersion; + + /** Path to the crash reporter internal data directory */ + NSString *_crashReportDirectory; +} + ++ (PLCrashReporter *) sharedReporter; + +- (instancetype) initWithConfiguration: (PLCrashReporterConfig *) config; + +- (BOOL) hasPendingCrashReport; + +- (NSData *) loadPendingCrashReportData; +- (NSData *) loadPendingCrashReportDataAndReturnError: (NSError **) outError; + +- (NSData *) generateLiveReportWithThread: (thread_t) thread; +- (NSData *) generateLiveReportWithThread: (thread_t) thread error: (NSError **) outError; + +- (NSData *) generateLiveReport; +- (NSData *) generateLiveReportAndReturnError: (NSError **) outError; + +- (BOOL) purgePendingCrashReport; +- (BOOL) purgePendingCrashReportAndReturnError: (NSError **) outError; + +- (BOOL) enableCrashReporter; +- (BOOL) enableCrashReporterAndReturnError: (NSError **) outError; + +- (void) setCrashCallbacks: (PLCrashReporterCallbacks *) callbacks; + +@end diff --git a/mac/CrashReporter.framework/Versions/A/Headers/PLCrashReporterConfig.h b/mac/CrashReporter.framework/Versions/A/Headers/PLCrashReporterConfig.h new file mode 100644 index 000000000..82f0bd9cf --- /dev/null +++ b/mac/CrashReporter.framework/Versions/A/Headers/PLCrashReporterConfig.h @@ -0,0 +1,165 @@ +/* + * Author: Landon Fuller + * + * Copyright (c) 2013 Plausible Labs Cooperative, Inc. + * All rights reserved. + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ + +#import +#import "PLCrashFeatureConfig.h" + +/** + * @ingroup enums + * Supported mechanisms for trapping and handling crashes. + */ +typedef NS_ENUM(NSUInteger, PLCrashReporterSignalHandlerType) { + /** + * Trap fatal signals via a sigaction(2)-registered BSD signal handler. + * + * PLCrashReporter's signal handler will supersede previously registered handlers; existing + * handlers will not be called. This behavior may be modified in a future release, and should + * not be relied upon as a mechanism to prevent existing signal handlers from being called. + * + * There are some limitations to signal-based crash handling on Mac OS X and iOS; specifically: + * + * - On Mac OS X, stack overflows will only be handled on the thread on which + * the crash reporter was initialized. This should generally be the main thread. + * - On iOS 6.0 and later, any stack overflows will not be handled due to sigaltstack() being + * non-functional on the device. (see rdar://13002712 - SA_ONSTACK/sigaltstack() ignored on iOS). + * - Some exit paths in Apple's Libc will deregister a signal handler before firing SIGABRT, resulting + * in the signal handler never being called (see rdar://14313497 - ___abort() disables SIGABRT signal + * handlers prior to raising SIGABRT). These __abort()-based checks are: + * - Implemented for unsafe memcpy/strcpy/snprintf C functions. + * - Only enabled when operating on a fixed-width target buffer (in which case the + * compiler rewrites the function calls to the built-in variants, and provides the fixed-width length as an argument). + * - Only trigger in the case that the source data exceeds the size of the fixed width target + * buffer, and the maximum length argument either isn't supplied by the caller (eg, when using strcpy), + * or a too-long argument is supplied (eg, strncpy with a length argument longer than the target buffer), + * AND that argument can't be checked at compile-time. + */ + PLCrashReporterSignalHandlerTypeBSD = 0, + +#if PLCRASH_FEATURE_MACH_EXCEPTIONS + /** + * Trap fatal signals via a Mach exception server. + * + * If any existing Mach exception server has been registered for the task, exceptions will be forwarded to that + * exception handler. Should the exceptions be handled by an existing handler, no report will be generated + * by PLCrashReporter. + * + * @par Mac OS X + * + * On Mac OS X, the Mach exception implementation is fully supported, using publicly available API -- note, + * however, that some kernel-internal constants, as well as architecture-specific trap information, + * may be required to fully interpret a Mach exception's root cause. + * + * @par iOS + * + * On iOS, the APIs required for a complete implementation are not fully public. + * + * The exposed surface of undocumented API usage is relatively low, and there has been strong user demand to + * implement Mach exception handling regardless of concerns over API visiblity. Given this, we've included + * Mach exception handling as an optional feature, with both build-time and runtime configuration + * to disable its inclusion or use, respectively. + * + * @par Debugger Incompatibility + * + * The Mach exception handler executes in-process, and will interfere with debuggers when they attempt to + * suspend all active threads (which will include the Mach exception handler). Mach-based handling + * should not be used when a debugger is attached. + * + * @par More Details + * + * For more information, refer to @ref mach_exceptions. + */ + PLCrashReporterSignalHandlerTypeMach = 1 +#endif /* PLCRASH_FEATURE_MACH_EXCEPTIONS */ +}; + +/** + * @ingroup enums + * Supported mechanisms for performing local symbolication. + * + * Local symbolication is performed using inexact heuristics and symbol data available at runtime; it may + * return information that is incorrect. This may still be useful in the case where DWARF data is unavailable + * for a given build; in that case, it can provide function and method names (though not line numbers) for a + * crash report that may otherwise be unusable. + * + * Note, however, this comes at the cost of a significant increase in code that must run within the critical + * crash reporting section, where failures may result in crash reports being corrupted or left unwritten. In + * addition, some of the provided symbolication strategies rely on knowledge of runtime internals that may + * change in future iOS releases. Given that DWARF symbolication data will always be more accurate, and + * the risks inherent in executing considerably more code at crash time, it is strongly recommended that local + * symbolication only be enabled for non-release builds. + * + * Multiple symbolication strategies may be enabled, in which case a best-match heuristic will be applied to the + * results. + */ +typedef NS_OPTIONS(NSUInteger, PLCrashReporterSymbolicationStrategy) { + /** No symbolication. */ + PLCrashReporterSymbolicationStrategyNone = 0, + + /** + * Use the standard binary symbol table. On iOS, this alone will return + * incomplete results, as most symbols are rewritten to the common '\' string. + */ + PLCrashReporterSymbolicationStrategySymbolTable = 1 << 0, + + /** + * Use Objective-C metadata to find method and class names. This relies on detailed parsing + * of the Objective-C runtime data, including undefined flags and other runtime internals. As such, + * it may return incorrect data should the runtime be changed incompatibly. + */ + PLCrashReporterSymbolicationStrategyObjC = 1 << 1, + + /** + * Enable all available symbolication strategies. + */ + PLCrashReporterSymbolicationStrategyAll = (PLCrashReporterSymbolicationStrategySymbolTable|PLCrashReporterSymbolicationStrategyObjC) +}; + +@interface PLCrashReporterConfig : NSObject { +@private + /** The configured signal handler type. */ + PLCrashReporterSignalHandlerType _signalHandlerType; + + /** The configured symbolication strategy. */ + PLCrashReporterSymbolicationStrategy _symbolicationStrategy; +} + ++ (instancetype) defaultConfiguration; + +- (instancetype) init; +- (instancetype) initWithSignalHandlerType: (PLCrashReporterSignalHandlerType) signalHandlerType + symbolicationStrategy: (PLCrashReporterSymbolicationStrategy) symbolicationStrategy; + +/** The configured signal handler type. */ +@property(nonatomic, readonly) PLCrashReporterSignalHandlerType signalHandlerType; + +/** The configured symbolication strategy. */ +@property(nonatomic, readonly) PLCrashReporterSymbolicationStrategy symbolicationStrategy; + + +@end + diff --git a/mac/CrashReporter.framework/Versions/A/Resources/Info.plist b/mac/CrashReporter.framework/Versions/A/Resources/Info.plist new file mode 100644 index 000000000..a86e074a6 --- /dev/null +++ b/mac/CrashReporter.framework/Versions/A/Resources/Info.plist @@ -0,0 +1,38 @@ + + + + + BuildMachineOSBuild + 13D65 + CFBundleDevelopmentRegion + English + CFBundleExecutable + CrashReporter + CFBundleIdentifier + coop.plausible.CrashReporter + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + CrashReporter + CFBundlePackageType + FMWK + CFBundleSignature + ???? + CFBundleVersion + 1.0 + DTCompiler + com.apple.compilers.llvm.clang.1_0 + DTPlatformBuild + 5B1008 + DTPlatformVersion + GM + DTSDKBuild + 13C64 + DTSDKName + macosx10.9 + DTXcode + 0511 + DTXcodeBuild + 5B1008 + + diff --git a/mac/CrashReporter.framework/Versions/Current b/mac/CrashReporter.framework/Versions/Current new file mode 120000 index 000000000..8c7e5a667 --- /dev/null +++ b/mac/CrashReporter.framework/Versions/Current @@ -0,0 +1 @@ +A \ No newline at end of file diff --git a/mac/Podfile b/mac/Podfile new file mode 100644 index 000000000..9ffac9e7a --- /dev/null +++ b/mac/Podfile @@ -0,0 +1,5 @@ +#source 'https://github.com/CocoaPods/Specs.git' +platform = :osx, "10.8" +pod 'FMDB', '~> 2.3' +pod "AFNetworking", "~> 2.5.0" +pod 'ProtocolBuffers', '~> 1.9.4' diff --git a/mac/README b/mac/README new file mode 100644 index 000000000..db4f9c5cc --- /dev/null +++ b/mac/README @@ -0,0 +1,3 @@ +Please Read Me +TT_3.0 +start from here diff --git a/mac/Sparkle.framework/Headers b/mac/Sparkle.framework/Headers new file mode 120000 index 000000000..a177d2a6b --- /dev/null +++ b/mac/Sparkle.framework/Headers @@ -0,0 +1 @@ +Versions/Current/Headers \ No newline at end of file diff --git a/mac/Sparkle.framework/Resources b/mac/Sparkle.framework/Resources new file mode 120000 index 000000000..953ee36f3 --- /dev/null +++ b/mac/Sparkle.framework/Resources @@ -0,0 +1 @@ +Versions/Current/Resources \ No newline at end of file diff --git a/mac/Sparkle.framework/Sparkle b/mac/Sparkle.framework/Sparkle new file mode 120000 index 000000000..b2c52731e --- /dev/null +++ b/mac/Sparkle.framework/Sparkle @@ -0,0 +1 @@ +Versions/Current/Sparkle \ No newline at end of file diff --git a/mac/Sparkle.framework/Versions/A/Headers/SUAppcast.h b/mac/Sparkle.framework/Versions/A/Headers/SUAppcast.h new file mode 100644 index 000000000..171148a4d --- /dev/null +++ b/mac/Sparkle.framework/Versions/A/Headers/SUAppcast.h @@ -0,0 +1,33 @@ +// +// SUAppcast.h +// Sparkle +// +// Created by Andy Matuschak on 3/12/06. +// Copyright 2006 Andy Matuschak. All rights reserved. +// + +#ifndef SUAPPCAST_H +#define SUAPPCAST_H + +@class SUAppcastItem; +@interface SUAppcast : NSObject { + NSArray *items; + NSString *userAgentString; + id delegate; + NSMutableData *incrementalData; +} + +- (void)fetchAppcastFromURL:(NSURL *)url; +- (void)setDelegate:delegate; +- (void)setUserAgentString:(NSString *)userAgentString; + +- (NSArray *)items; + +@end + +@interface NSObject (SUAppcastDelegate) +- (void)appcastDidFinishLoading:(SUAppcast *)appcast; +- (void)appcast:(SUAppcast *)appcast failedToLoadWithError:(NSError *)error; +@end + +#endif diff --git a/mac/Sparkle.framework/Versions/A/Headers/SUAppcastItem.h b/mac/Sparkle.framework/Versions/A/Headers/SUAppcastItem.h new file mode 100644 index 000000000..7f1ca65c0 --- /dev/null +++ b/mac/Sparkle.framework/Versions/A/Headers/SUAppcastItem.h @@ -0,0 +1,47 @@ +// +// SUAppcastItem.h +// Sparkle +// +// Created by Andy Matuschak on 3/12/06. +// Copyright 2006 Andy Matuschak. All rights reserved. +// + +#ifndef SUAPPCASTITEM_H +#define SUAPPCASTITEM_H + +@interface SUAppcastItem : NSObject { + NSString *title; + NSDate *date; + NSString *itemDescription; + + NSURL *releaseNotesURL; + + NSString *DSASignature; + NSString *minimumSystemVersion; + + NSURL *fileURL; + NSString *versionString; + NSString *displayVersionString; + + NSDictionary *propertiesDictionary; +} + +// Initializes with data from a dictionary provided by the RSS class. +- initWithDictionary:(NSDictionary *)dict; + +- (NSString *)title; +- (NSString *)versionString; +- (NSString *)displayVersionString; +- (NSDate *)date; +- (NSString *)itemDescription; +- (NSURL *)releaseNotesURL; +- (NSURL *)fileURL; +- (NSString *)DSASignature; +- (NSString *)minimumSystemVersion; + +// Returns the dictionary provided in initWithDictionary; this might be useful later for extensions. +- (NSDictionary *)propertiesDictionary; + +@end + +#endif diff --git a/mac/Sparkle.framework/Versions/A/Headers/SUUpdater.h b/mac/Sparkle.framework/Versions/A/Headers/SUUpdater.h new file mode 100644 index 000000000..e78c4d353 --- /dev/null +++ b/mac/Sparkle.framework/Versions/A/Headers/SUUpdater.h @@ -0,0 +1,118 @@ +// +// SUUpdater.h +// Sparkle +// +// Created by Andy Matuschak on 1/4/06. +// Copyright 2006 Andy Matuschak. All rights reserved. +// + +#ifndef SUUPDATER_H +#define SUUPDATER_H + +#import + +@class SUUpdateDriver, SUAppcastItem, SUHost, SUAppcast; +@interface SUUpdater : NSObject { + NSTimer *checkTimer; + SUUpdateDriver *driver; + + SUHost *host; + IBOutlet id delegate; +} + ++ (SUUpdater *)sharedUpdater; ++ (SUUpdater *)updaterForBundle:(NSBundle *)bundle; +- (NSBundle *)hostBundle; + +- (void)setDelegate:(id)delegate; +- delegate; + +- (void)setAutomaticallyChecksForUpdates:(BOOL)automaticallyChecks; +- (BOOL)automaticallyChecksForUpdates; + +- (void)setUpdateCheckInterval:(NSTimeInterval)interval; +- (NSTimeInterval)updateCheckInterval; + +- (void)setFeedURL:(NSURL *)feedURL; +- (NSURL *)feedURL; + +- (void)setSendsSystemProfile:(BOOL)sendsSystemProfile; +- (BOOL)sendsSystemProfile; + +- (void)setAutomaticallyDownloadsUpdates:(BOOL)automaticallyDownloadsUpdates; +- (BOOL)automaticallyDownloadsUpdates; + +// This IBAction is meant for a main menu item. Hook up any menu item to this action, +// and Sparkle will check for updates and report back its findings verbosely. +- (IBAction)checkForUpdates:sender; + +// This kicks off an update meant to be programmatically initiated. That is, it will display no UI unless it actually finds an update, +// in which case it proceeds as usual. If the fully automated updating is turned on, however, this will invoke that behavior, and if an +// update is found, it will be downloaded and prepped for installation. +- (void)checkForUpdatesInBackground; + +// Date of last update check. Returns null if no check has been performed. +- (NSDate*)lastUpdateCheckDate; + +// This begins a "probing" check for updates which will not actually offer to update to that version. The delegate methods, though, +// (up to updater:didFindValidUpdate: and updaterDidNotFindUpdate:), are called, so you can use that information in your UI. +- (void)checkForUpdateInformation; + +// Call this to appropriately schedule or cancel the update checking timer according to the preferences for time interval and automatic checks. This call does not change the date of the next check, but only the internal NSTimer. +- (void)resetUpdateCycle; + +- (BOOL)updateInProgress; +@end + +@interface NSObject (SUUpdaterDelegateInformalProtocol) +// This method allows you to add extra parameters to the appcast URL, potentially based on whether or not Sparkle will also be sending along the system profile. This method should return an array of dictionaries with keys: "key", "value", "displayKey", "displayValue", the latter two being specifically for display to the user. +- (NSArray *)feedParametersForUpdater:(SUUpdater *)updater sendingSystemProfile:(BOOL)sendingProfile; + +// Use this to override the default behavior for Sparkle prompting the user about automatic update checks. +- (BOOL)updaterShouldPromptForPermissionToCheckForUpdates:(SUUpdater *)bundle; + +// Implement this if you want to do some special handling with the appcast once it finishes loading. +- (void)updater:(SUUpdater *)updater didFinishLoadingAppcast:(SUAppcast *)appcast; + +// If you're using special logic or extensions in your appcast, implement this to use your own logic for finding +// a valid update, if any, in the given appcast. +- (SUAppcastItem *)bestValidUpdateInAppcast:(SUAppcast *)appcast forUpdater:(SUUpdater *)bundle; + +// Sent when a valid update is found by the update driver. +- (void)updater:(SUUpdater *)updater didFindValidUpdate:(SUAppcastItem *)update; + +// Sent when a valid update is not found. +- (void)updaterDidNotFindUpdate:(SUUpdater *)update; + +// Sent immediately before installing the specified update. +- (void)updater:(SUUpdater *)updater willInstallUpdate:(SUAppcastItem *)update; + +// Return YES to delay the relaunch until you do some processing; invoke the given NSInvocation to continue. +- (BOOL)updater:(SUUpdater *)updater shouldPostponeRelaunchForUpdate:(SUAppcastItem *)update untilInvoking:(NSInvocation *)invocation; + +// Called immediately before relaunching. +- (void)updaterWillRelaunchApplication:(SUUpdater *)updater; + +// This method allows you to provide a custom version comparator. +// If you don't implement this method or return nil, the standard version comparator will be used. +- (id )versionComparatorForUpdater:(SUUpdater *)updater; + +// Returns the path which is used to relaunch the client after the update is installed. By default, the path of the host bundle. +- (NSString *)pathToRelaunchForUpdater:(SUUpdater *)updater; + +@end + +// Define some minimum intervals to avoid DOS-like checking attacks. These are in seconds. +#ifdef DEBUG +#define SU_MIN_CHECK_INTERVAL 60 +#else +#define SU_MIN_CHECK_INTERVAL 60*60 +#endif + +#ifdef DEBUG +#define SU_DEFAULT_CHECK_INTERVAL 60 +#else +#define SU_DEFAULT_CHECK_INTERVAL 60*60*24 +#endif + +#endif diff --git a/mac/Sparkle.framework/Versions/A/Headers/SUVersionComparisonProtocol.h b/mac/Sparkle.framework/Versions/A/Headers/SUVersionComparisonProtocol.h new file mode 100644 index 000000000..3d11ae873 --- /dev/null +++ b/mac/Sparkle.framework/Versions/A/Headers/SUVersionComparisonProtocol.h @@ -0,0 +1,27 @@ +// +// SUVersionComparisonProtocol.h +// Sparkle +// +// Created by Andy Matuschak on 12/21/07. +// Copyright 2007 Andy Matuschak. All rights reserved. +// + +#ifndef SUVERSIONCOMPARISONPROTOCOL_H +#define SUVERSIONCOMPARISONPROTOCOL_H + +/*! + @protocol + @abstract Implement this protocol to provide version comparison facilities for Sparkle. +*/ +@protocol SUVersionComparison + +/*! + @method + @abstract An abstract method to compare two version strings. + @discussion Should return NSOrderedAscending if b > a, NSOrderedDescending if b < a, and NSOrderedSame if they are equivalent. +*/ +- (NSComparisonResult)compareVersion:(NSString *)versionA toVersion:(NSString *)versionB; + +@end + +#endif diff --git a/mac/Sparkle.framework/Versions/A/Headers/Sparkle.h b/mac/Sparkle.framework/Versions/A/Headers/Sparkle.h new file mode 100644 index 000000000..08dd57775 --- /dev/null +++ b/mac/Sparkle.framework/Versions/A/Headers/Sparkle.h @@ -0,0 +1,21 @@ +// +// Sparkle.h +// Sparkle +// +// Created by Andy Matuschak on 3/16/06. (Modified by CDHW on 23/12/07) +// Copyright 2006 Andy Matuschak. All rights reserved. +// + +#ifndef SPARKLE_H +#define SPARKLE_H + +// This list should include the shared headers. It doesn't matter if some of them aren't shared (unless +// there are name-space collisions) so we can list all of them to start with: + +#import + +#import +#import +#import + +#endif diff --git a/mac/Sparkle.framework/Versions/A/Resources/Info.plist b/mac/Sparkle.framework/Versions/A/Resources/Info.plist new file mode 100644 index 000000000..c7f277d04 --- /dev/null +++ b/mac/Sparkle.framework/Versions/A/Resources/Info.plist @@ -0,0 +1,24 @@ + + + + + CFBundleDevelopmentRegion + en + CFBundleExecutable + Sparkle + CFBundleIdentifier + org.andymatuschak.Sparkle + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + Sparkle + CFBundlePackageType + FMWK + CFBundleShortVersionString + 1.5 Beta 6 + CFBundleSignature + ???? + CFBundleVersion + 313 + + diff --git a/mac/Sparkle.framework/Versions/A/Resources/License.txt b/mac/Sparkle.framework/Versions/A/Resources/License.txt new file mode 100644 index 000000000..20466c417 --- /dev/null +++ b/mac/Sparkle.framework/Versions/A/Resources/License.txt @@ -0,0 +1,7 @@ +Copyright (c) 2006 Andy Matuschak + +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. \ No newline at end of file diff --git a/mac/Sparkle.framework/Versions/A/Resources/SUModelTranslation.plist b/mac/Sparkle.framework/Versions/A/Resources/SUModelTranslation.plist new file mode 100644 index 000000000..92ef9471e --- /dev/null +++ b/mac/Sparkle.framework/Versions/A/Resources/SUModelTranslation.plist @@ -0,0 +1,174 @@ + + + + + ADP2,1 + Developer Transition Kit + MacBook1,1 + MacBook (Core Duo) + MacBook2,1 + MacBook (Core 2 Duo) + MacBook4,1 + MacBook (Core 2 Duo Feb 2008) + MacBookAir1,1 + MacBook Air (January 2008) + MacBookPro1,1 + MacBook Pro Core Duo (15-inch) + MacBookPro1,2 + MacBook Pro Core Duo (17-inch) + MacBookPro2,1 + MacBook Pro Core 2 Duo (17-inch) + MacBookPro2,2 + MacBook Pro Core 2 Duo (15-inch) + MacBookPro3,1 + MacBook Pro Core 2 Duo (15-inch LED, Core 2 Duo) + MacBookPro3,2 + MacBook Pro Core 2 Duo (17-inch HD, Core 2 Duo) + MacBookPro4,1 + MacBook Pro (Core 2 Duo Feb 2008) + MacPro1,1 + Mac Pro (four-core) + MacPro2,1 + Mac Pro (eight-core) + MacPro3,1 + Mac Pro (January 2008 4- or 8- core "Harpertown") + Macmini1,1 + Mac Mini (Core Solo/Duo) + PowerBook1,1 + PowerBook G3 + PowerBook2,1 + iBook G3 + PowerBook2,2 + iBook G3 (FireWire) + PowerBook2,3 + iBook G3 + PowerBook2,4 + iBook G3 + PowerBook3,1 + PowerBook G3 (FireWire) + PowerBook3,2 + PowerBook G4 + PowerBook3,3 + PowerBook G4 (Gigabit Ethernet) + PowerBook3,4 + PowerBook G4 (DVI) + PowerBook3,5 + PowerBook G4 (1GHz / 867MHz) + PowerBook4,1 + iBook G3 (Dual USB, Late 2001) + PowerBook4,2 + iBook G3 (16MB VRAM) + PowerBook4,3 + iBook G3 Opaque 16MB VRAM, 32MB VRAM, Early 2003) + PowerBook5,1 + PowerBook G4 (17 inch) + PowerBook5,2 + PowerBook G4 (15 inch FW 800) + PowerBook5,3 + PowerBook G4 (17-inch 1.33GHz) + PowerBook5,4 + PowerBook G4 (15 inch 1.5/1.33GHz) + PowerBook5,5 + PowerBook G4 (17-inch 1.5GHz) + PowerBook5,6 + PowerBook G4 (15 inch 1.67GHz/1.5GHz) + PowerBook5,7 + PowerBook G4 (17-inch 1.67GHz) + PowerBook5,8 + PowerBook G4 (Double layer SD, 15 inch) + PowerBook5,9 + PowerBook G4 (Double layer SD, 17 inch) + PowerBook6,1 + PowerBook G4 (12 inch) + PowerBook6,2 + PowerBook G4 (12 inch, DVI) + PowerBook6,3 + iBook G4 + PowerBook6,4 + PowerBook G4 (12 inch 1.33GHz) + PowerBook6,5 + iBook G4 (Early-Late 2004) + PowerBook6,7 + iBook G4 (Mid 2005) + PowerBook6,8 + PowerBook G4 (12 inch 1.5GHz) + PowerMac1,1 + Power Macintosh G3 (Blue & White) + PowerMac1,2 + Power Macintosh G4 (PCI Graphics) + PowerMac10,1 + Mac Mini G4 + PowerMac10,2 + Mac Mini (Late 2005) + PowerMac11,2 + Power Macintosh G5 (Late 2005) + PowerMac12,1 + iMac G5 (iSight) + PowerMac2,1 + iMac G3 (Slot-loading CD-ROM) + PowerMac2,2 + iMac G3 (Summer 2000) + PowerMac3,1 + Power Macintosh G4 (AGP Graphics) + PowerMac3,2 + Power Macintosh G4 (AGP Graphics) + PowerMac3,3 + Power Macintosh G4 (Gigabit Ethernet) + PowerMac3,4 + Power Macintosh G4 (Digital Audio) + PowerMac3,5 + Power Macintosh G4 (Quick Silver) + PowerMac3,6 + Power Macintosh G4 (Mirrored Drive Door) + PowerMac4,1 + iMac G3 (Early/Summer 2001) + PowerMac4,2 + iMac G4 (Flat Panel) + PowerMac4,4 + eMac + PowerMac4,5 + iMac G4 (17-inch Flat Panel) + PowerMac5,1 + Power Macintosh G4 Cube + PowerMac6,1 + iMac G4 (USB 2.0) + PowerMac6,3 + iMac G4 (20-inch Flat Panel) + PowerMac6,4 + eMac (USB 2.0, 2005) + PowerMac7,2 + Power Macintosh G5 + PowerMac7,3 + Power Macintosh G5 + PowerMac8,1 + iMac G5 + PowerMac8,2 + iMac G5 (Ambient Light Sensor) + PowerMac9,1 + Power Macintosh G5 (Late 2005) + RackMac1,1 + Xserve G4 + RackMac1,2 + Xserve G4 (slot-loading, cluster node) + RackMac3,1 + Xserve G5 + Xserve1,1 + Xserve (Intel Xeon) + Xserve2,1 + Xserve (January 2008 quad-core) + iMac1,1 + iMac G3 (Rev A-D) + iMac4,1 + iMac (Core Duo) + iMac4,2 + iMac for Education (17-inch, Core Duo) + iMac5,1 + iMac (Core 2 Duo, 17 or 20 inch, SuperDrive) + iMac5,2 + iMac (Core 2 Duo, 17 inch, Combo Drive) + iMac6,1 + iMac (Core 2 Duo, 24 inch, SuperDrive) + iMac8,1 + iMac (April 2008) + + diff --git a/mac/Sparkle.framework/Versions/A/Resources/SUStatus.nib/classes.nib b/mac/Sparkle.framework/Versions/A/Resources/SUStatus.nib/classes.nib new file mode 100644 index 000000000..22f13f8b6 --- /dev/null +++ b/mac/Sparkle.framework/Versions/A/Resources/SUStatus.nib/classes.nib @@ -0,0 +1,56 @@ + + + + + IBClasses + + + CLASS + SUWindowController + LANGUAGE + ObjC + SUPERCLASS + NSWindowController + + + CLASS + NSApplication + LANGUAGE + ObjC + SUPERCLASS + NSResponder + + + CLASS + FirstResponder + LANGUAGE + ObjC + SUPERCLASS + NSObject + + + CLASS + NSObject + LANGUAGE + ObjC + + + CLASS + SUStatusController + LANGUAGE + ObjC + OUTLETS + + actionButton + NSButton + progressBar + NSProgressIndicator + + SUPERCLASS + SUWindowController + + + IBVersion + 1 + + diff --git a/mac/Sparkle.framework/Versions/A/Resources/SUStatus.nib/info.nib b/mac/Sparkle.framework/Versions/A/Resources/SUStatus.nib/info.nib new file mode 100644 index 000000000..a9ac8673c --- /dev/null +++ b/mac/Sparkle.framework/Versions/A/Resources/SUStatus.nib/info.nib @@ -0,0 +1,20 @@ + + + + + IBFramework Version + 670 + IBLastKnownRelativeProjectPath + Sparkle.xcodeproj + IBOldestOS + 5 + IBOpenObjects + + 6 + + IBSystem Version + 10A96 + targetFramework + IBCocoaFramework + + diff --git a/mac/Sparkle.framework/Versions/A/Resources/SUStatus.nib/keyedobjects.nib b/mac/Sparkle.framework/Versions/A/Resources/SUStatus.nib/keyedobjects.nib new file mode 100644 index 000000000..4f1d59817 Binary files /dev/null and b/mac/Sparkle.framework/Versions/A/Resources/SUStatus.nib/keyedobjects.nib differ diff --git a/mac/Sparkle.framework/Versions/A/Resources/de.lproj/SUAutomaticUpdateAlert.nib/classes.nib b/mac/Sparkle.framework/Versions/A/Resources/de.lproj/SUAutomaticUpdateAlert.nib/classes.nib new file mode 100644 index 000000000..4b1ab30e5 --- /dev/null +++ b/mac/Sparkle.framework/Versions/A/Resources/de.lproj/SUAutomaticUpdateAlert.nib/classes.nib @@ -0,0 +1,50 @@ + + + + + IBClasses + + + CLASS + SUWindowController + LANGUAGE + ObjC + SUPERCLASS + NSWindowController + + + ACTIONS + + doNotInstall + id + installLater + id + installNow + id + + CLASS + SUAutomaticUpdateAlert + LANGUAGE + ObjC + SUPERCLASS + SUWindowController + + + CLASS + FirstResponder + LANGUAGE + ObjC + SUPERCLASS + NSObject + + + CLASS + NSObject + LANGUAGE + ObjC + + + IBVersion + 1 + + diff --git a/mac/Sparkle.framework/Versions/A/Resources/de.lproj/SUAutomaticUpdateAlert.nib/info.nib b/mac/Sparkle.framework/Versions/A/Resources/de.lproj/SUAutomaticUpdateAlert.nib/info.nib new file mode 100644 index 000000000..2e04cfa03 --- /dev/null +++ b/mac/Sparkle.framework/Versions/A/Resources/de.lproj/SUAutomaticUpdateAlert.nib/info.nib @@ -0,0 +1,20 @@ + + + + + IBFramework Version + 667 + IBLastKnownRelativeProjectPath + ../Sparkle.xcodeproj + IBOldestOS + 5 + IBOpenObjects + + 6 + + IBSystem Version + 9D34 + targetFramework + IBCocoaFramework + + diff --git a/mac/Sparkle.framework/Versions/A/Resources/de.lproj/SUAutomaticUpdateAlert.nib/keyedobjects.nib b/mac/Sparkle.framework/Versions/A/Resources/de.lproj/SUAutomaticUpdateAlert.nib/keyedobjects.nib new file mode 100644 index 000000000..6b926302e Binary files /dev/null and b/mac/Sparkle.framework/Versions/A/Resources/de.lproj/SUAutomaticUpdateAlert.nib/keyedobjects.nib differ diff --git a/mac/Sparkle.framework/Versions/A/Resources/de.lproj/SUUpdateAlert.nib/classes.nib b/mac/Sparkle.framework/Versions/A/Resources/de.lproj/SUUpdateAlert.nib/classes.nib new file mode 100644 index 000000000..994d4c368 --- /dev/null +++ b/mac/Sparkle.framework/Versions/A/Resources/de.lproj/SUUpdateAlert.nib/classes.nib @@ -0,0 +1,67 @@ + + + + + IBClasses + + + CLASS + SUWindowController + LANGUAGE + ObjC + SUPERCLASS + NSWindowController + + + CLASS + NSApplication + LANGUAGE + ObjC + SUPERCLASS + NSResponder + + + ACTIONS + + installUpdate + id + remindMeLater + id + skipThisVersion + id + + CLASS + SUUpdateAlert + LANGUAGE + ObjC + OUTLETS + + delegate + id + description + NSTextField + releaseNotesView + WebView + + SUPERCLASS + SUWindowController + + + CLASS + FirstResponder + LANGUAGE + ObjC + SUPERCLASS + NSObject + + + CLASS + NSObject + LANGUAGE + ObjC + + + IBVersion + 1 + + diff --git a/mac/Sparkle.framework/Versions/A/Resources/de.lproj/SUUpdateAlert.nib/info.nib b/mac/Sparkle.framework/Versions/A/Resources/de.lproj/SUUpdateAlert.nib/info.nib new file mode 100644 index 000000000..2e04cfa03 --- /dev/null +++ b/mac/Sparkle.framework/Versions/A/Resources/de.lproj/SUUpdateAlert.nib/info.nib @@ -0,0 +1,20 @@ + + + + + IBFramework Version + 667 + IBLastKnownRelativeProjectPath + ../Sparkle.xcodeproj + IBOldestOS + 5 + IBOpenObjects + + 6 + + IBSystem Version + 9D34 + targetFramework + IBCocoaFramework + + diff --git a/mac/Sparkle.framework/Versions/A/Resources/de.lproj/SUUpdateAlert.nib/keyedobjects.nib b/mac/Sparkle.framework/Versions/A/Resources/de.lproj/SUUpdateAlert.nib/keyedobjects.nib new file mode 100644 index 000000000..b4353d2f7 Binary files /dev/null and b/mac/Sparkle.framework/Versions/A/Resources/de.lproj/SUUpdateAlert.nib/keyedobjects.nib differ diff --git a/mac/Sparkle.framework/Versions/A/Resources/de.lproj/SUUpdatePermissionPrompt.nib/classes.nib b/mac/Sparkle.framework/Versions/A/Resources/de.lproj/SUUpdatePermissionPrompt.nib/classes.nib new file mode 100644 index 000000000..5220a221f --- /dev/null +++ b/mac/Sparkle.framework/Versions/A/Resources/de.lproj/SUUpdatePermissionPrompt.nib/classes.nib @@ -0,0 +1,59 @@ + + + + + IBClasses + + + CLASS + SUWindowController + LANGUAGE + ObjC + SUPERCLASS + NSWindowController + + + ACTIONS + + finishPrompt + id + toggleMoreInfo + id + + CLASS + SUUpdatePermissionPrompt + LANGUAGE + ObjC + OUTLETS + + delegate + id + descriptionTextField + NSTextField + moreInfoButton + NSButton + moreInfoView + NSView + + SUPERCLASS + SUWindowController + + + CLASS + FirstResponder + LANGUAGE + ObjC + SUPERCLASS + NSObject + + + CLASS + NSObject + LANGUAGE + ObjC + + + IBVersion + 1 + + diff --git a/mac/Sparkle.framework/Versions/A/Resources/de.lproj/SUUpdatePermissionPrompt.nib/info.nib b/mac/Sparkle.framework/Versions/A/Resources/de.lproj/SUUpdatePermissionPrompt.nib/info.nib new file mode 100644 index 000000000..2e04cfa03 --- /dev/null +++ b/mac/Sparkle.framework/Versions/A/Resources/de.lproj/SUUpdatePermissionPrompt.nib/info.nib @@ -0,0 +1,20 @@ + + + + + IBFramework Version + 667 + IBLastKnownRelativeProjectPath + ../Sparkle.xcodeproj + IBOldestOS + 5 + IBOpenObjects + + 6 + + IBSystem Version + 9D34 + targetFramework + IBCocoaFramework + + diff --git a/mac/Sparkle.framework/Versions/A/Resources/de.lproj/SUUpdatePermissionPrompt.nib/keyedobjects.nib b/mac/Sparkle.framework/Versions/A/Resources/de.lproj/SUUpdatePermissionPrompt.nib/keyedobjects.nib new file mode 100644 index 000000000..b403a3e45 Binary files /dev/null and b/mac/Sparkle.framework/Versions/A/Resources/de.lproj/SUUpdatePermissionPrompt.nib/keyedobjects.nib differ diff --git a/mac/Sparkle.framework/Versions/A/Resources/de.lproj/Sparkle.strings b/mac/Sparkle.framework/Versions/A/Resources/de.lproj/Sparkle.strings new file mode 100644 index 000000000..b31f928fd Binary files /dev/null and b/mac/Sparkle.framework/Versions/A/Resources/de.lproj/Sparkle.strings differ diff --git a/mac/Sparkle.framework/Versions/A/Resources/en.lproj/SUAutomaticUpdateAlert.nib/classes.nib b/mac/Sparkle.framework/Versions/A/Resources/en.lproj/SUAutomaticUpdateAlert.nib/classes.nib new file mode 100644 index 000000000..4b1ab30e5 --- /dev/null +++ b/mac/Sparkle.framework/Versions/A/Resources/en.lproj/SUAutomaticUpdateAlert.nib/classes.nib @@ -0,0 +1,50 @@ + + + + + IBClasses + + + CLASS + SUWindowController + LANGUAGE + ObjC + SUPERCLASS + NSWindowController + + + ACTIONS + + doNotInstall + id + installLater + id + installNow + id + + CLASS + SUAutomaticUpdateAlert + LANGUAGE + ObjC + SUPERCLASS + SUWindowController + + + CLASS + FirstResponder + LANGUAGE + ObjC + SUPERCLASS + NSObject + + + CLASS + NSObject + LANGUAGE + ObjC + + + IBVersion + 1 + + diff --git a/mac/Sparkle.framework/Versions/A/Resources/en.lproj/SUAutomaticUpdateAlert.nib/info.nib b/mac/Sparkle.framework/Versions/A/Resources/en.lproj/SUAutomaticUpdateAlert.nib/info.nib new file mode 100644 index 000000000..ab36d3103 --- /dev/null +++ b/mac/Sparkle.framework/Versions/A/Resources/en.lproj/SUAutomaticUpdateAlert.nib/info.nib @@ -0,0 +1,20 @@ + + + + + IBFramework Version + 658 + IBLastKnownRelativeProjectPath + ../Sparkle.xcodeproj + IBOldestOS + 5 + IBOpenObjects + + 6 + + IBSystem Version + 9C7010 + targetFramework + IBCocoaFramework + + diff --git a/mac/Sparkle.framework/Versions/A/Resources/en.lproj/SUAutomaticUpdateAlert.nib/keyedobjects.nib b/mac/Sparkle.framework/Versions/A/Resources/en.lproj/SUAutomaticUpdateAlert.nib/keyedobjects.nib new file mode 100644 index 000000000..7630390c8 Binary files /dev/null and b/mac/Sparkle.framework/Versions/A/Resources/en.lproj/SUAutomaticUpdateAlert.nib/keyedobjects.nib differ diff --git a/mac/Sparkle.framework/Versions/A/Resources/en.lproj/SUUpdateAlert.nib/classes.nib b/mac/Sparkle.framework/Versions/A/Resources/en.lproj/SUUpdateAlert.nib/classes.nib new file mode 100644 index 000000000..994d4c368 --- /dev/null +++ b/mac/Sparkle.framework/Versions/A/Resources/en.lproj/SUUpdateAlert.nib/classes.nib @@ -0,0 +1,67 @@ + + + + + IBClasses + + + CLASS + SUWindowController + LANGUAGE + ObjC + SUPERCLASS + NSWindowController + + + CLASS + NSApplication + LANGUAGE + ObjC + SUPERCLASS + NSResponder + + + ACTIONS + + installUpdate + id + remindMeLater + id + skipThisVersion + id + + CLASS + SUUpdateAlert + LANGUAGE + ObjC + OUTLETS + + delegate + id + description + NSTextField + releaseNotesView + WebView + + SUPERCLASS + SUWindowController + + + CLASS + FirstResponder + LANGUAGE + ObjC + SUPERCLASS + NSObject + + + CLASS + NSObject + LANGUAGE + ObjC + + + IBVersion + 1 + + diff --git a/mac/Sparkle.framework/Versions/A/Resources/en.lproj/SUUpdateAlert.nib/info.nib b/mac/Sparkle.framework/Versions/A/Resources/en.lproj/SUUpdateAlert.nib/info.nib new file mode 100644 index 000000000..2fb8a8372 --- /dev/null +++ b/mac/Sparkle.framework/Versions/A/Resources/en.lproj/SUUpdateAlert.nib/info.nib @@ -0,0 +1,20 @@ + + + + + IBFramework Version + 670 + IBLastKnownRelativeProjectPath + ../Sparkle.xcodeproj + IBOldestOS + 5 + IBOpenObjects + + 18 + + IBSystem Version + 10A96 + targetFramework + IBCocoaFramework + + diff --git a/mac/Sparkle.framework/Versions/A/Resources/en.lproj/SUUpdateAlert.nib/keyedobjects.nib b/mac/Sparkle.framework/Versions/A/Resources/en.lproj/SUUpdateAlert.nib/keyedobjects.nib new file mode 100644 index 000000000..e7e7497db Binary files /dev/null and b/mac/Sparkle.framework/Versions/A/Resources/en.lproj/SUUpdateAlert.nib/keyedobjects.nib differ diff --git a/mac/Sparkle.framework/Versions/A/Resources/en.lproj/SUUpdatePermissionPrompt.nib/classes.nib b/mac/Sparkle.framework/Versions/A/Resources/en.lproj/SUUpdatePermissionPrompt.nib/classes.nib new file mode 100644 index 000000000..5220a221f --- /dev/null +++ b/mac/Sparkle.framework/Versions/A/Resources/en.lproj/SUUpdatePermissionPrompt.nib/classes.nib @@ -0,0 +1,59 @@ + + + + + IBClasses + + + CLASS + SUWindowController + LANGUAGE + ObjC + SUPERCLASS + NSWindowController + + + ACTIONS + + finishPrompt + id + toggleMoreInfo + id + + CLASS + SUUpdatePermissionPrompt + LANGUAGE + ObjC + OUTLETS + + delegate + id + descriptionTextField + NSTextField + moreInfoButton + NSButton + moreInfoView + NSView + + SUPERCLASS + SUWindowController + + + CLASS + FirstResponder + LANGUAGE + ObjC + SUPERCLASS + NSObject + + + CLASS + NSObject + LANGUAGE + ObjC + + + IBVersion + 1 + + diff --git a/mac/Sparkle.framework/Versions/A/Resources/en.lproj/SUUpdatePermissionPrompt.nib/info.nib b/mac/Sparkle.framework/Versions/A/Resources/en.lproj/SUUpdatePermissionPrompt.nib/info.nib new file mode 100644 index 000000000..b1cd28edd --- /dev/null +++ b/mac/Sparkle.framework/Versions/A/Resources/en.lproj/SUUpdatePermissionPrompt.nib/info.nib @@ -0,0 +1,21 @@ + + + + + IBFramework Version + 670 + IBLastKnownRelativeProjectPath + ../Sparkle.xcodeproj + IBOldestOS + 5 + IBOpenObjects + + 6 + 41 + + IBSystem Version + 10A96 + targetFramework + IBCocoaFramework + + diff --git a/mac/Sparkle.framework/Versions/A/Resources/en.lproj/SUUpdatePermissionPrompt.nib/keyedobjects.nib b/mac/Sparkle.framework/Versions/A/Resources/en.lproj/SUUpdatePermissionPrompt.nib/keyedobjects.nib new file mode 100644 index 000000000..e8dc5b880 Binary files /dev/null and b/mac/Sparkle.framework/Versions/A/Resources/en.lproj/SUUpdatePermissionPrompt.nib/keyedobjects.nib differ diff --git a/mac/Sparkle.framework/Versions/A/Resources/en.lproj/Sparkle.strings b/mac/Sparkle.framework/Versions/A/Resources/en.lproj/Sparkle.strings new file mode 100644 index 000000000..16e0787b4 Binary files /dev/null and b/mac/Sparkle.framework/Versions/A/Resources/en.lproj/Sparkle.strings differ diff --git a/mac/Sparkle.framework/Versions/A/Resources/es.lproj/SUAutomaticUpdateAlert.nib/classes.nib b/mac/Sparkle.framework/Versions/A/Resources/es.lproj/SUAutomaticUpdateAlert.nib/classes.nib new file mode 100644 index 000000000..4b1ab30e5 --- /dev/null +++ b/mac/Sparkle.framework/Versions/A/Resources/es.lproj/SUAutomaticUpdateAlert.nib/classes.nib @@ -0,0 +1,50 @@ + + + + + IBClasses + + + CLASS + SUWindowController + LANGUAGE + ObjC + SUPERCLASS + NSWindowController + + + ACTIONS + + doNotInstall + id + installLater + id + installNow + id + + CLASS + SUAutomaticUpdateAlert + LANGUAGE + ObjC + SUPERCLASS + SUWindowController + + + CLASS + FirstResponder + LANGUAGE + ObjC + SUPERCLASS + NSObject + + + CLASS + NSObject + LANGUAGE + ObjC + + + IBVersion + 1 + + diff --git a/mac/Sparkle.framework/Versions/A/Resources/es.lproj/SUAutomaticUpdateAlert.nib/info.nib b/mac/Sparkle.framework/Versions/A/Resources/es.lproj/SUAutomaticUpdateAlert.nib/info.nib new file mode 100644 index 000000000..2e04cfa03 --- /dev/null +++ b/mac/Sparkle.framework/Versions/A/Resources/es.lproj/SUAutomaticUpdateAlert.nib/info.nib @@ -0,0 +1,20 @@ + + + + + IBFramework Version + 667 + IBLastKnownRelativeProjectPath + ../Sparkle.xcodeproj + IBOldestOS + 5 + IBOpenObjects + + 6 + + IBSystem Version + 9D34 + targetFramework + IBCocoaFramework + + diff --git a/mac/Sparkle.framework/Versions/A/Resources/es.lproj/SUAutomaticUpdateAlert.nib/keyedobjects.nib b/mac/Sparkle.framework/Versions/A/Resources/es.lproj/SUAutomaticUpdateAlert.nib/keyedobjects.nib new file mode 100644 index 000000000..6b2f938f9 Binary files /dev/null and b/mac/Sparkle.framework/Versions/A/Resources/es.lproj/SUAutomaticUpdateAlert.nib/keyedobjects.nib differ diff --git a/mac/Sparkle.framework/Versions/A/Resources/es.lproj/SUUpdateAlert.nib/classes.nib b/mac/Sparkle.framework/Versions/A/Resources/es.lproj/SUUpdateAlert.nib/classes.nib new file mode 100644 index 000000000..994d4c368 --- /dev/null +++ b/mac/Sparkle.framework/Versions/A/Resources/es.lproj/SUUpdateAlert.nib/classes.nib @@ -0,0 +1,67 @@ + + + + + IBClasses + + + CLASS + SUWindowController + LANGUAGE + ObjC + SUPERCLASS + NSWindowController + + + CLASS + NSApplication + LANGUAGE + ObjC + SUPERCLASS + NSResponder + + + ACTIONS + + installUpdate + id + remindMeLater + id + skipThisVersion + id + + CLASS + SUUpdateAlert + LANGUAGE + ObjC + OUTLETS + + delegate + id + description + NSTextField + releaseNotesView + WebView + + SUPERCLASS + SUWindowController + + + CLASS + FirstResponder + LANGUAGE + ObjC + SUPERCLASS + NSObject + + + CLASS + NSObject + LANGUAGE + ObjC + + + IBVersion + 1 + + diff --git a/mac/Sparkle.framework/Versions/A/Resources/es.lproj/SUUpdateAlert.nib/info.nib b/mac/Sparkle.framework/Versions/A/Resources/es.lproj/SUUpdateAlert.nib/info.nib new file mode 100644 index 000000000..2e04cfa03 --- /dev/null +++ b/mac/Sparkle.framework/Versions/A/Resources/es.lproj/SUUpdateAlert.nib/info.nib @@ -0,0 +1,20 @@ + + + + + IBFramework Version + 667 + IBLastKnownRelativeProjectPath + ../Sparkle.xcodeproj + IBOldestOS + 5 + IBOpenObjects + + 6 + + IBSystem Version + 9D34 + targetFramework + IBCocoaFramework + + diff --git a/mac/Sparkle.framework/Versions/A/Resources/es.lproj/SUUpdateAlert.nib/keyedobjects.nib b/mac/Sparkle.framework/Versions/A/Resources/es.lproj/SUUpdateAlert.nib/keyedobjects.nib new file mode 100644 index 000000000..c9b1e7d88 Binary files /dev/null and b/mac/Sparkle.framework/Versions/A/Resources/es.lproj/SUUpdateAlert.nib/keyedobjects.nib differ diff --git a/mac/Sparkle.framework/Versions/A/Resources/es.lproj/SUUpdatePermissionPrompt.nib/classes.nib b/mac/Sparkle.framework/Versions/A/Resources/es.lproj/SUUpdatePermissionPrompt.nib/classes.nib new file mode 100644 index 000000000..5220a221f --- /dev/null +++ b/mac/Sparkle.framework/Versions/A/Resources/es.lproj/SUUpdatePermissionPrompt.nib/classes.nib @@ -0,0 +1,59 @@ + + + + + IBClasses + + + CLASS + SUWindowController + LANGUAGE + ObjC + SUPERCLASS + NSWindowController + + + ACTIONS + + finishPrompt + id + toggleMoreInfo + id + + CLASS + SUUpdatePermissionPrompt + LANGUAGE + ObjC + OUTLETS + + delegate + id + descriptionTextField + NSTextField + moreInfoButton + NSButton + moreInfoView + NSView + + SUPERCLASS + SUWindowController + + + CLASS + FirstResponder + LANGUAGE + ObjC + SUPERCLASS + NSObject + + + CLASS + NSObject + LANGUAGE + ObjC + + + IBVersion + 1 + + diff --git a/mac/Sparkle.framework/Versions/A/Resources/es.lproj/SUUpdatePermissionPrompt.nib/info.nib b/mac/Sparkle.framework/Versions/A/Resources/es.lproj/SUUpdatePermissionPrompt.nib/info.nib new file mode 100644 index 000000000..3eb7f818e --- /dev/null +++ b/mac/Sparkle.framework/Versions/A/Resources/es.lproj/SUUpdatePermissionPrompt.nib/info.nib @@ -0,0 +1,20 @@ + + + + + IBFramework Version + 667 + IBLastKnownRelativeProjectPath + ../../Sparkle.xcodeproj + IBOldestOS + 5 + IBOpenObjects + + 6 + + IBSystem Version + 9D34 + targetFramework + IBCocoaFramework + + diff --git a/mac/Sparkle.framework/Versions/A/Resources/es.lproj/SUUpdatePermissionPrompt.nib/keyedobjects.nib b/mac/Sparkle.framework/Versions/A/Resources/es.lproj/SUUpdatePermissionPrompt.nib/keyedobjects.nib new file mode 100644 index 000000000..8c54c217c Binary files /dev/null and b/mac/Sparkle.framework/Versions/A/Resources/es.lproj/SUUpdatePermissionPrompt.nib/keyedobjects.nib differ diff --git a/mac/Sparkle.framework/Versions/A/Resources/es.lproj/Sparkle.strings b/mac/Sparkle.framework/Versions/A/Resources/es.lproj/Sparkle.strings new file mode 100644 index 000000000..f83ea23cd Binary files /dev/null and b/mac/Sparkle.framework/Versions/A/Resources/es.lproj/Sparkle.strings differ diff --git a/mac/Sparkle.framework/Versions/A/Resources/fr.lproj/SUAutomaticUpdateAlert.nib/classes.nib b/mac/Sparkle.framework/Versions/A/Resources/fr.lproj/SUAutomaticUpdateAlert.nib/classes.nib new file mode 100644 index 000000000..4b1ab30e5 --- /dev/null +++ b/mac/Sparkle.framework/Versions/A/Resources/fr.lproj/SUAutomaticUpdateAlert.nib/classes.nib @@ -0,0 +1,50 @@ + + + + + IBClasses + + + CLASS + SUWindowController + LANGUAGE + ObjC + SUPERCLASS + NSWindowController + + + ACTIONS + + doNotInstall + id + installLater + id + installNow + id + + CLASS + SUAutomaticUpdateAlert + LANGUAGE + ObjC + SUPERCLASS + SUWindowController + + + CLASS + FirstResponder + LANGUAGE + ObjC + SUPERCLASS + NSObject + + + CLASS + NSObject + LANGUAGE + ObjC + + + IBVersion + 1 + + diff --git a/mac/Sparkle.framework/Versions/A/Resources/fr.lproj/SUAutomaticUpdateAlert.nib/info.nib b/mac/Sparkle.framework/Versions/A/Resources/fr.lproj/SUAutomaticUpdateAlert.nib/info.nib new file mode 100644 index 000000000..33a60200f --- /dev/null +++ b/mac/Sparkle.framework/Versions/A/Resources/fr.lproj/SUAutomaticUpdateAlert.nib/info.nib @@ -0,0 +1,16 @@ + + + + + IBFramework Version + 629 + IBOldestOS + 5 + IBOpenObjects + + IBSystem Version + 9D34 + targetFramework + IBCocoaFramework + + diff --git a/mac/Sparkle.framework/Versions/A/Resources/fr.lproj/SUAutomaticUpdateAlert.nib/keyedobjects.nib b/mac/Sparkle.framework/Versions/A/Resources/fr.lproj/SUAutomaticUpdateAlert.nib/keyedobjects.nib new file mode 100644 index 000000000..4cd529a56 Binary files /dev/null and b/mac/Sparkle.framework/Versions/A/Resources/fr.lproj/SUAutomaticUpdateAlert.nib/keyedobjects.nib differ diff --git a/mac/Sparkle.framework/Versions/A/Resources/fr.lproj/SUUpdateAlert.nib/classes.nib b/mac/Sparkle.framework/Versions/A/Resources/fr.lproj/SUUpdateAlert.nib/classes.nib new file mode 100644 index 000000000..994d4c368 --- /dev/null +++ b/mac/Sparkle.framework/Versions/A/Resources/fr.lproj/SUUpdateAlert.nib/classes.nib @@ -0,0 +1,67 @@ + + + + + IBClasses + + + CLASS + SUWindowController + LANGUAGE + ObjC + SUPERCLASS + NSWindowController + + + CLASS + NSApplication + LANGUAGE + ObjC + SUPERCLASS + NSResponder + + + ACTIONS + + installUpdate + id + remindMeLater + id + skipThisVersion + id + + CLASS + SUUpdateAlert + LANGUAGE + ObjC + OUTLETS + + delegate + id + description + NSTextField + releaseNotesView + WebView + + SUPERCLASS + SUWindowController + + + CLASS + FirstResponder + LANGUAGE + ObjC + SUPERCLASS + NSObject + + + CLASS + NSObject + LANGUAGE + ObjC + + + IBVersion + 1 + + diff --git a/mac/Sparkle.framework/Versions/A/Resources/fr.lproj/SUUpdateAlert.nib/info.nib b/mac/Sparkle.framework/Versions/A/Resources/fr.lproj/SUUpdateAlert.nib/info.nib new file mode 100644 index 000000000..d2586ea20 --- /dev/null +++ b/mac/Sparkle.framework/Versions/A/Resources/fr.lproj/SUUpdateAlert.nib/info.nib @@ -0,0 +1,16 @@ + + + + + IBFramework Version + 629 + IBOldestOS + 5 + IBOpenObjects + + IBSystem Version + 9E17 + targetFramework + IBCocoaFramework + + diff --git a/mac/Sparkle.framework/Versions/A/Resources/fr.lproj/SUUpdateAlert.nib/keyedobjects.nib b/mac/Sparkle.framework/Versions/A/Resources/fr.lproj/SUUpdateAlert.nib/keyedobjects.nib new file mode 100644 index 000000000..65dfc95e3 Binary files /dev/null and b/mac/Sparkle.framework/Versions/A/Resources/fr.lproj/SUUpdateAlert.nib/keyedobjects.nib differ diff --git a/mac/Sparkle.framework/Versions/A/Resources/fr.lproj/SUUpdatePermissionPrompt.nib/classes.nib b/mac/Sparkle.framework/Versions/A/Resources/fr.lproj/SUUpdatePermissionPrompt.nib/classes.nib new file mode 100644 index 000000000..5220a221f --- /dev/null +++ b/mac/Sparkle.framework/Versions/A/Resources/fr.lproj/SUUpdatePermissionPrompt.nib/classes.nib @@ -0,0 +1,59 @@ + + + + + IBClasses + + + CLASS + SUWindowController + LANGUAGE + ObjC + SUPERCLASS + NSWindowController + + + ACTIONS + + finishPrompt + id + toggleMoreInfo + id + + CLASS + SUUpdatePermissionPrompt + LANGUAGE + ObjC + OUTLETS + + delegate + id + descriptionTextField + NSTextField + moreInfoButton + NSButton + moreInfoView + NSView + + SUPERCLASS + SUWindowController + + + CLASS + FirstResponder + LANGUAGE + ObjC + SUPERCLASS + NSObject + + + CLASS + NSObject + LANGUAGE + ObjC + + + IBVersion + 1 + + diff --git a/mac/Sparkle.framework/Versions/A/Resources/fr.lproj/SUUpdatePermissionPrompt.nib/info.nib b/mac/Sparkle.framework/Versions/A/Resources/fr.lproj/SUUpdatePermissionPrompt.nib/info.nib new file mode 100644 index 000000000..d2586ea20 --- /dev/null +++ b/mac/Sparkle.framework/Versions/A/Resources/fr.lproj/SUUpdatePermissionPrompt.nib/info.nib @@ -0,0 +1,16 @@ + + + + + IBFramework Version + 629 + IBOldestOS + 5 + IBOpenObjects + + IBSystem Version + 9E17 + targetFramework + IBCocoaFramework + + diff --git a/mac/Sparkle.framework/Versions/A/Resources/fr.lproj/SUUpdatePermissionPrompt.nib/keyedobjects.nib b/mac/Sparkle.framework/Versions/A/Resources/fr.lproj/SUUpdatePermissionPrompt.nib/keyedobjects.nib new file mode 100644 index 000000000..4b7cc9054 Binary files /dev/null and b/mac/Sparkle.framework/Versions/A/Resources/fr.lproj/SUUpdatePermissionPrompt.nib/keyedobjects.nib differ diff --git a/mac/Sparkle.framework/Versions/A/Resources/fr.lproj/Sparkle.strings b/mac/Sparkle.framework/Versions/A/Resources/fr.lproj/Sparkle.strings new file mode 100644 index 000000000..ea175ae71 Binary files /dev/null and b/mac/Sparkle.framework/Versions/A/Resources/fr.lproj/Sparkle.strings differ diff --git a/mac/Sparkle.framework/Versions/A/Resources/fr.lproj/fr.lproj b/mac/Sparkle.framework/Versions/A/Resources/fr.lproj/fr.lproj new file mode 120000 index 000000000..88614fe23 --- /dev/null +++ b/mac/Sparkle.framework/Versions/A/Resources/fr.lproj/fr.lproj @@ -0,0 +1 @@ +/Users/andym/Development/Build Products/Release/Sparkle.framework/Resources/fr.lproj \ No newline at end of file diff --git a/mac/Sparkle.framework/Versions/A/Resources/fr_CA.lproj b/mac/Sparkle.framework/Versions/A/Resources/fr_CA.lproj new file mode 120000 index 000000000..88614fe23 --- /dev/null +++ b/mac/Sparkle.framework/Versions/A/Resources/fr_CA.lproj @@ -0,0 +1 @@ +/Users/andym/Development/Build Products/Release/Sparkle.framework/Resources/fr.lproj \ No newline at end of file diff --git a/mac/Sparkle.framework/Versions/A/Resources/it.lproj/SUAutomaticUpdateAlert.nib/classes.nib b/mac/Sparkle.framework/Versions/A/Resources/it.lproj/SUAutomaticUpdateAlert.nib/classes.nib new file mode 100644 index 000000000..4b1ab30e5 --- /dev/null +++ b/mac/Sparkle.framework/Versions/A/Resources/it.lproj/SUAutomaticUpdateAlert.nib/classes.nib @@ -0,0 +1,50 @@ + + + + + IBClasses + + + CLASS + SUWindowController + LANGUAGE + ObjC + SUPERCLASS + NSWindowController + + + ACTIONS + + doNotInstall + id + installLater + id + installNow + id + + CLASS + SUAutomaticUpdateAlert + LANGUAGE + ObjC + SUPERCLASS + SUWindowController + + + CLASS + FirstResponder + LANGUAGE + ObjC + SUPERCLASS + NSObject + + + CLASS + NSObject + LANGUAGE + ObjC + + + IBVersion + 1 + + diff --git a/mac/Sparkle.framework/Versions/A/Resources/it.lproj/SUAutomaticUpdateAlert.nib/info.nib b/mac/Sparkle.framework/Versions/A/Resources/it.lproj/SUAutomaticUpdateAlert.nib/info.nib new file mode 100644 index 000000000..2e04cfa03 --- /dev/null +++ b/mac/Sparkle.framework/Versions/A/Resources/it.lproj/SUAutomaticUpdateAlert.nib/info.nib @@ -0,0 +1,20 @@ + + + + + IBFramework Version + 667 + IBLastKnownRelativeProjectPath + ../Sparkle.xcodeproj + IBOldestOS + 5 + IBOpenObjects + + 6 + + IBSystem Version + 9D34 + targetFramework + IBCocoaFramework + + diff --git a/mac/Sparkle.framework/Versions/A/Resources/it.lproj/SUAutomaticUpdateAlert.nib/keyedobjects.nib b/mac/Sparkle.framework/Versions/A/Resources/it.lproj/SUAutomaticUpdateAlert.nib/keyedobjects.nib new file mode 100644 index 000000000..15ba8f4c8 Binary files /dev/null and b/mac/Sparkle.framework/Versions/A/Resources/it.lproj/SUAutomaticUpdateAlert.nib/keyedobjects.nib differ diff --git a/mac/Sparkle.framework/Versions/A/Resources/it.lproj/SUUpdateAlert.nib/classes.nib b/mac/Sparkle.framework/Versions/A/Resources/it.lproj/SUUpdateAlert.nib/classes.nib new file mode 100644 index 000000000..994d4c368 --- /dev/null +++ b/mac/Sparkle.framework/Versions/A/Resources/it.lproj/SUUpdateAlert.nib/classes.nib @@ -0,0 +1,67 @@ + + + + + IBClasses + + + CLASS + SUWindowController + LANGUAGE + ObjC + SUPERCLASS + NSWindowController + + + CLASS + NSApplication + LANGUAGE + ObjC + SUPERCLASS + NSResponder + + + ACTIONS + + installUpdate + id + remindMeLater + id + skipThisVersion + id + + CLASS + SUUpdateAlert + LANGUAGE + ObjC + OUTLETS + + delegate + id + description + NSTextField + releaseNotesView + WebView + + SUPERCLASS + SUWindowController + + + CLASS + FirstResponder + LANGUAGE + ObjC + SUPERCLASS + NSObject + + + CLASS + NSObject + LANGUAGE + ObjC + + + IBVersion + 1 + + diff --git a/mac/Sparkle.framework/Versions/A/Resources/it.lproj/SUUpdateAlert.nib/info.nib b/mac/Sparkle.framework/Versions/A/Resources/it.lproj/SUUpdateAlert.nib/info.nib new file mode 100644 index 000000000..2e04cfa03 --- /dev/null +++ b/mac/Sparkle.framework/Versions/A/Resources/it.lproj/SUUpdateAlert.nib/info.nib @@ -0,0 +1,20 @@ + + + + + IBFramework Version + 667 + IBLastKnownRelativeProjectPath + ../Sparkle.xcodeproj + IBOldestOS + 5 + IBOpenObjects + + 6 + + IBSystem Version + 9D34 + targetFramework + IBCocoaFramework + + diff --git a/mac/Sparkle.framework/Versions/A/Resources/it.lproj/SUUpdateAlert.nib/keyedobjects.nib b/mac/Sparkle.framework/Versions/A/Resources/it.lproj/SUUpdateAlert.nib/keyedobjects.nib new file mode 100644 index 000000000..298406450 Binary files /dev/null and b/mac/Sparkle.framework/Versions/A/Resources/it.lproj/SUUpdateAlert.nib/keyedobjects.nib differ diff --git a/mac/Sparkle.framework/Versions/A/Resources/it.lproj/SUUpdatePermissionPrompt.nib/classes.nib b/mac/Sparkle.framework/Versions/A/Resources/it.lproj/SUUpdatePermissionPrompt.nib/classes.nib new file mode 100644 index 000000000..5220a221f --- /dev/null +++ b/mac/Sparkle.framework/Versions/A/Resources/it.lproj/SUUpdatePermissionPrompt.nib/classes.nib @@ -0,0 +1,59 @@ + + + + + IBClasses + + + CLASS + SUWindowController + LANGUAGE + ObjC + SUPERCLASS + NSWindowController + + + ACTIONS + + finishPrompt + id + toggleMoreInfo + id + + CLASS + SUUpdatePermissionPrompt + LANGUAGE + ObjC + OUTLETS + + delegate + id + descriptionTextField + NSTextField + moreInfoButton + NSButton + moreInfoView + NSView + + SUPERCLASS + SUWindowController + + + CLASS + FirstResponder + LANGUAGE + ObjC + SUPERCLASS + NSObject + + + CLASS + NSObject + LANGUAGE + ObjC + + + IBVersion + 1 + + diff --git a/mac/Sparkle.framework/Versions/A/Resources/it.lproj/SUUpdatePermissionPrompt.nib/info.nib b/mac/Sparkle.framework/Versions/A/Resources/it.lproj/SUUpdatePermissionPrompt.nib/info.nib new file mode 100644 index 000000000..c4934850f --- /dev/null +++ b/mac/Sparkle.framework/Versions/A/Resources/it.lproj/SUUpdatePermissionPrompt.nib/info.nib @@ -0,0 +1,20 @@ + + + + + IBFramework Version + 667 + IBLastKnownRelativeProjectPath + ../Sparkle.xcodeproj + IBOldestOS + 5 + IBOpenObjects + + 5 + + IBSystem Version + 9D34 + targetFramework + IBCocoaFramework + + diff --git a/mac/Sparkle.framework/Versions/A/Resources/it.lproj/SUUpdatePermissionPrompt.nib/keyedobjects.nib b/mac/Sparkle.framework/Versions/A/Resources/it.lproj/SUUpdatePermissionPrompt.nib/keyedobjects.nib new file mode 100644 index 000000000..55cc2c271 Binary files /dev/null and b/mac/Sparkle.framework/Versions/A/Resources/it.lproj/SUUpdatePermissionPrompt.nib/keyedobjects.nib differ diff --git a/mac/Sparkle.framework/Versions/A/Resources/it.lproj/Sparkle.strings b/mac/Sparkle.framework/Versions/A/Resources/it.lproj/Sparkle.strings new file mode 100644 index 000000000..5c410d070 Binary files /dev/null and b/mac/Sparkle.framework/Versions/A/Resources/it.lproj/Sparkle.strings differ diff --git a/mac/Sparkle.framework/Versions/A/Resources/nl.lproj/SUAutomaticUpdateAlert.nib/classes.nib b/mac/Sparkle.framework/Versions/A/Resources/nl.lproj/SUAutomaticUpdateAlert.nib/classes.nib new file mode 100644 index 000000000..4b1ab30e5 --- /dev/null +++ b/mac/Sparkle.framework/Versions/A/Resources/nl.lproj/SUAutomaticUpdateAlert.nib/classes.nib @@ -0,0 +1,50 @@ + + + + + IBClasses + + + CLASS + SUWindowController + LANGUAGE + ObjC + SUPERCLASS + NSWindowController + + + ACTIONS + + doNotInstall + id + installLater + id + installNow + id + + CLASS + SUAutomaticUpdateAlert + LANGUAGE + ObjC + SUPERCLASS + SUWindowController + + + CLASS + FirstResponder + LANGUAGE + ObjC + SUPERCLASS + NSObject + + + CLASS + NSObject + LANGUAGE + ObjC + + + IBVersion + 1 + + diff --git a/mac/Sparkle.framework/Versions/A/Resources/nl.lproj/SUAutomaticUpdateAlert.nib/info.nib b/mac/Sparkle.framework/Versions/A/Resources/nl.lproj/SUAutomaticUpdateAlert.nib/info.nib new file mode 100644 index 000000000..3f0979083 --- /dev/null +++ b/mac/Sparkle.framework/Versions/A/Resources/nl.lproj/SUAutomaticUpdateAlert.nib/info.nib @@ -0,0 +1,18 @@ + + + + + IBFramework Version + 629 + IBOldestOS + 5 + IBOpenObjects + + 6 + + IBSystem Version + 9D34 + targetFramework + IBCocoaFramework + + diff --git a/mac/Sparkle.framework/Versions/A/Resources/nl.lproj/SUAutomaticUpdateAlert.nib/keyedobjects.nib b/mac/Sparkle.framework/Versions/A/Resources/nl.lproj/SUAutomaticUpdateAlert.nib/keyedobjects.nib new file mode 100644 index 000000000..aa38f86ba Binary files /dev/null and b/mac/Sparkle.framework/Versions/A/Resources/nl.lproj/SUAutomaticUpdateAlert.nib/keyedobjects.nib differ diff --git a/mac/Sparkle.framework/Versions/A/Resources/nl.lproj/SUUpdateAlert.nib/classes.nib b/mac/Sparkle.framework/Versions/A/Resources/nl.lproj/SUUpdateAlert.nib/classes.nib new file mode 100644 index 000000000..994d4c368 --- /dev/null +++ b/mac/Sparkle.framework/Versions/A/Resources/nl.lproj/SUUpdateAlert.nib/classes.nib @@ -0,0 +1,67 @@ + + + + + IBClasses + + + CLASS + SUWindowController + LANGUAGE + ObjC + SUPERCLASS + NSWindowController + + + CLASS + NSApplication + LANGUAGE + ObjC + SUPERCLASS + NSResponder + + + ACTIONS + + installUpdate + id + remindMeLater + id + skipThisVersion + id + + CLASS + SUUpdateAlert + LANGUAGE + ObjC + OUTLETS + + delegate + id + description + NSTextField + releaseNotesView + WebView + + SUPERCLASS + SUWindowController + + + CLASS + FirstResponder + LANGUAGE + ObjC + SUPERCLASS + NSObject + + + CLASS + NSObject + LANGUAGE + ObjC + + + IBVersion + 1 + + diff --git a/mac/Sparkle.framework/Versions/A/Resources/nl.lproj/SUUpdateAlert.nib/info.nib b/mac/Sparkle.framework/Versions/A/Resources/nl.lproj/SUUpdateAlert.nib/info.nib new file mode 100644 index 000000000..d2586ea20 --- /dev/null +++ b/mac/Sparkle.framework/Versions/A/Resources/nl.lproj/SUUpdateAlert.nib/info.nib @@ -0,0 +1,16 @@ + + + + + IBFramework Version + 629 + IBOldestOS + 5 + IBOpenObjects + + IBSystem Version + 9E17 + targetFramework + IBCocoaFramework + + diff --git a/mac/Sparkle.framework/Versions/A/Resources/nl.lproj/SUUpdateAlert.nib/keyedobjects.nib b/mac/Sparkle.framework/Versions/A/Resources/nl.lproj/SUUpdateAlert.nib/keyedobjects.nib new file mode 100644 index 000000000..c82d3581b Binary files /dev/null and b/mac/Sparkle.framework/Versions/A/Resources/nl.lproj/SUUpdateAlert.nib/keyedobjects.nib differ diff --git a/mac/Sparkle.framework/Versions/A/Resources/nl.lproj/SUUpdatePermissionPrompt.nib/classes.nib b/mac/Sparkle.framework/Versions/A/Resources/nl.lproj/SUUpdatePermissionPrompt.nib/classes.nib new file mode 100644 index 000000000..5220a221f --- /dev/null +++ b/mac/Sparkle.framework/Versions/A/Resources/nl.lproj/SUUpdatePermissionPrompt.nib/classes.nib @@ -0,0 +1,59 @@ + + + + + IBClasses + + + CLASS + SUWindowController + LANGUAGE + ObjC + SUPERCLASS + NSWindowController + + + ACTIONS + + finishPrompt + id + toggleMoreInfo + id + + CLASS + SUUpdatePermissionPrompt + LANGUAGE + ObjC + OUTLETS + + delegate + id + descriptionTextField + NSTextField + moreInfoButton + NSButton + moreInfoView + NSView + + SUPERCLASS + SUWindowController + + + CLASS + FirstResponder + LANGUAGE + ObjC + SUPERCLASS + NSObject + + + CLASS + NSObject + LANGUAGE + ObjC + + + IBVersion + 1 + + diff --git a/mac/Sparkle.framework/Versions/A/Resources/nl.lproj/SUUpdatePermissionPrompt.nib/info.nib b/mac/Sparkle.framework/Versions/A/Resources/nl.lproj/SUUpdatePermissionPrompt.nib/info.nib new file mode 100644 index 000000000..d2586ea20 --- /dev/null +++ b/mac/Sparkle.framework/Versions/A/Resources/nl.lproj/SUUpdatePermissionPrompt.nib/info.nib @@ -0,0 +1,16 @@ + + + + + IBFramework Version + 629 + IBOldestOS + 5 + IBOpenObjects + + IBSystem Version + 9E17 + targetFramework + IBCocoaFramework + + diff --git a/mac/Sparkle.framework/Versions/A/Resources/nl.lproj/SUUpdatePermissionPrompt.nib/keyedobjects.nib b/mac/Sparkle.framework/Versions/A/Resources/nl.lproj/SUUpdatePermissionPrompt.nib/keyedobjects.nib new file mode 100644 index 000000000..ac298ce7e Binary files /dev/null and b/mac/Sparkle.framework/Versions/A/Resources/nl.lproj/SUUpdatePermissionPrompt.nib/keyedobjects.nib differ diff --git a/mac/Sparkle.framework/Versions/A/Resources/nl.lproj/Sparkle.strings b/mac/Sparkle.framework/Versions/A/Resources/nl.lproj/Sparkle.strings new file mode 100644 index 000000000..67cf535ee Binary files /dev/null and b/mac/Sparkle.framework/Versions/A/Resources/nl.lproj/Sparkle.strings differ diff --git a/mac/Sparkle.framework/Versions/A/Resources/relaunch b/mac/Sparkle.framework/Versions/A/Resources/relaunch new file mode 100755 index 000000000..e7b96d614 Binary files /dev/null and b/mac/Sparkle.framework/Versions/A/Resources/relaunch differ diff --git a/mac/Sparkle.framework/Versions/A/Resources/ru.lproj/SUAutomaticUpdateAlert.nib/classes.nib b/mac/Sparkle.framework/Versions/A/Resources/ru.lproj/SUAutomaticUpdateAlert.nib/classes.nib new file mode 100644 index 000000000..4b1ab30e5 --- /dev/null +++ b/mac/Sparkle.framework/Versions/A/Resources/ru.lproj/SUAutomaticUpdateAlert.nib/classes.nib @@ -0,0 +1,50 @@ + + + + + IBClasses + + + CLASS + SUWindowController + LANGUAGE + ObjC + SUPERCLASS + NSWindowController + + + ACTIONS + + doNotInstall + id + installLater + id + installNow + id + + CLASS + SUAutomaticUpdateAlert + LANGUAGE + ObjC + SUPERCLASS + SUWindowController + + + CLASS + FirstResponder + LANGUAGE + ObjC + SUPERCLASS + NSObject + + + CLASS + NSObject + LANGUAGE + ObjC + + + IBVersion + 1 + + diff --git a/mac/Sparkle.framework/Versions/A/Resources/ru.lproj/SUAutomaticUpdateAlert.nib/info.nib b/mac/Sparkle.framework/Versions/A/Resources/ru.lproj/SUAutomaticUpdateAlert.nib/info.nib new file mode 100644 index 000000000..2b3d42576 --- /dev/null +++ b/mac/Sparkle.framework/Versions/A/Resources/ru.lproj/SUAutomaticUpdateAlert.nib/info.nib @@ -0,0 +1,20 @@ + + + + + IBFramework Version + 670 + IBLastKnownRelativeProjectPath + ../Sparkle.xcodeproj + IBOldestOS + 5 + IBOpenObjects + + 6 + + IBSystem Version + 9E17 + targetFramework + IBCocoaFramework + + diff --git a/mac/Sparkle.framework/Versions/A/Resources/ru.lproj/SUAutomaticUpdateAlert.nib/keyedobjects.nib b/mac/Sparkle.framework/Versions/A/Resources/ru.lproj/SUAutomaticUpdateAlert.nib/keyedobjects.nib new file mode 100644 index 000000000..1d4655c59 Binary files /dev/null and b/mac/Sparkle.framework/Versions/A/Resources/ru.lproj/SUAutomaticUpdateAlert.nib/keyedobjects.nib differ diff --git a/mac/Sparkle.framework/Versions/A/Resources/ru.lproj/SUUpdateAlert.nib/classes.nib b/mac/Sparkle.framework/Versions/A/Resources/ru.lproj/SUUpdateAlert.nib/classes.nib new file mode 100644 index 000000000..994d4c368 --- /dev/null +++ b/mac/Sparkle.framework/Versions/A/Resources/ru.lproj/SUUpdateAlert.nib/classes.nib @@ -0,0 +1,67 @@ + + + + + IBClasses + + + CLASS + SUWindowController + LANGUAGE + ObjC + SUPERCLASS + NSWindowController + + + CLASS + NSApplication + LANGUAGE + ObjC + SUPERCLASS + NSResponder + + + ACTIONS + + installUpdate + id + remindMeLater + id + skipThisVersion + id + + CLASS + SUUpdateAlert + LANGUAGE + ObjC + OUTLETS + + delegate + id + description + NSTextField + releaseNotesView + WebView + + SUPERCLASS + SUWindowController + + + CLASS + FirstResponder + LANGUAGE + ObjC + SUPERCLASS + NSObject + + + CLASS + NSObject + LANGUAGE + ObjC + + + IBVersion + 1 + + diff --git a/mac/Sparkle.framework/Versions/A/Resources/ru.lproj/SUUpdateAlert.nib/info.nib b/mac/Sparkle.framework/Versions/A/Resources/ru.lproj/SUUpdateAlert.nib/info.nib new file mode 100644 index 000000000..2b3d42576 --- /dev/null +++ b/mac/Sparkle.framework/Versions/A/Resources/ru.lproj/SUUpdateAlert.nib/info.nib @@ -0,0 +1,20 @@ + + + + + IBFramework Version + 670 + IBLastKnownRelativeProjectPath + ../Sparkle.xcodeproj + IBOldestOS + 5 + IBOpenObjects + + 6 + + IBSystem Version + 9E17 + targetFramework + IBCocoaFramework + + diff --git a/mac/Sparkle.framework/Versions/A/Resources/ru.lproj/SUUpdateAlert.nib/keyedobjects.nib b/mac/Sparkle.framework/Versions/A/Resources/ru.lproj/SUUpdateAlert.nib/keyedobjects.nib new file mode 100644 index 000000000..103b1cf84 Binary files /dev/null and b/mac/Sparkle.framework/Versions/A/Resources/ru.lproj/SUUpdateAlert.nib/keyedobjects.nib differ diff --git a/mac/Sparkle.framework/Versions/A/Resources/ru.lproj/SUUpdatePermissionPrompt.nib/classes.nib b/mac/Sparkle.framework/Versions/A/Resources/ru.lproj/SUUpdatePermissionPrompt.nib/classes.nib new file mode 100644 index 000000000..0f776c895 --- /dev/null +++ b/mac/Sparkle.framework/Versions/A/Resources/ru.lproj/SUUpdatePermissionPrompt.nib/classes.nib @@ -0,0 +1,59 @@ + + + + + IBClasses + + + CLASS + NSObject + LANGUAGE + ObjC + + + CLASS + SUWindowController + LANGUAGE + ObjC + SUPERCLASS + NSWindowController + + + ACTIONS + + finishPrompt + id + toggleMoreInfo + id + + CLASS + SUUpdatePermissionPrompt + LANGUAGE + ObjC + OUTLETS + + delegate + id + descriptionTextField + NSTextField + moreInfoButton + NSButton + moreInfoView + NSView + + SUPERCLASS + SUWindowController + + + CLASS + FirstResponder + LANGUAGE + ObjC + SUPERCLASS + NSObject + + + IBVersion + 1 + + diff --git a/mac/Sparkle.framework/Versions/A/Resources/ru.lproj/SUUpdatePermissionPrompt.nib/info.nib b/mac/Sparkle.framework/Versions/A/Resources/ru.lproj/SUUpdatePermissionPrompt.nib/info.nib new file mode 100644 index 000000000..5132e29f2 --- /dev/null +++ b/mac/Sparkle.framework/Versions/A/Resources/ru.lproj/SUUpdatePermissionPrompt.nib/info.nib @@ -0,0 +1,18 @@ + + + + + IBFramework Version + 670 + IBLastKnownRelativeProjectPath + ../Sparkle.xcodeproj + IBOldestOS + 5 + IBOpenObjects + + IBSystem Version + 9E17 + targetFramework + IBCocoaFramework + + diff --git a/mac/Sparkle.framework/Versions/A/Resources/ru.lproj/SUUpdatePermissionPrompt.nib/keyedobjects.nib b/mac/Sparkle.framework/Versions/A/Resources/ru.lproj/SUUpdatePermissionPrompt.nib/keyedobjects.nib new file mode 100644 index 000000000..c09d9e70d Binary files /dev/null and b/mac/Sparkle.framework/Versions/A/Resources/ru.lproj/SUUpdatePermissionPrompt.nib/keyedobjects.nib differ diff --git a/mac/Sparkle.framework/Versions/A/Resources/ru.lproj/Sparkle.strings b/mac/Sparkle.framework/Versions/A/Resources/ru.lproj/Sparkle.strings new file mode 100644 index 000000000..f3ff9d86c Binary files /dev/null and b/mac/Sparkle.framework/Versions/A/Resources/ru.lproj/Sparkle.strings differ diff --git a/mac/Sparkle.framework/Versions/A/Resources/sv.lproj/SUAutomaticUpdateAlert.nib/classes.nib b/mac/Sparkle.framework/Versions/A/Resources/sv.lproj/SUAutomaticUpdateAlert.nib/classes.nib new file mode 100644 index 000000000..4b1ab30e5 --- /dev/null +++ b/mac/Sparkle.framework/Versions/A/Resources/sv.lproj/SUAutomaticUpdateAlert.nib/classes.nib @@ -0,0 +1,50 @@ + + + + + IBClasses + + + CLASS + SUWindowController + LANGUAGE + ObjC + SUPERCLASS + NSWindowController + + + ACTIONS + + doNotInstall + id + installLater + id + installNow + id + + CLASS + SUAutomaticUpdateAlert + LANGUAGE + ObjC + SUPERCLASS + SUWindowController + + + CLASS + FirstResponder + LANGUAGE + ObjC + SUPERCLASS + NSObject + + + CLASS + NSObject + LANGUAGE + ObjC + + + IBVersion + 1 + + diff --git a/mac/Sparkle.framework/Versions/A/Resources/sv.lproj/SUAutomaticUpdateAlert.nib/info.nib b/mac/Sparkle.framework/Versions/A/Resources/sv.lproj/SUAutomaticUpdateAlert.nib/info.nib new file mode 100644 index 000000000..c5a067e89 --- /dev/null +++ b/mac/Sparkle.framework/Versions/A/Resources/sv.lproj/SUAutomaticUpdateAlert.nib/info.nib @@ -0,0 +1,20 @@ + + + + + IBFramework Version + 670 + IBLastKnownRelativeProjectPath + ../Sparkle.xcodeproj + IBOldestOS + 5 + IBOpenObjects + + 6 + + IBSystem Version + 10A96 + targetFramework + IBCocoaFramework + + diff --git a/mac/Sparkle.framework/Versions/A/Resources/sv.lproj/SUAutomaticUpdateAlert.nib/keyedobjects.nib b/mac/Sparkle.framework/Versions/A/Resources/sv.lproj/SUAutomaticUpdateAlert.nib/keyedobjects.nib new file mode 100644 index 000000000..53cb91a9b Binary files /dev/null and b/mac/Sparkle.framework/Versions/A/Resources/sv.lproj/SUAutomaticUpdateAlert.nib/keyedobjects.nib differ diff --git a/mac/Sparkle.framework/Versions/A/Resources/sv.lproj/SUUpdateAlert.nib/classes.nib b/mac/Sparkle.framework/Versions/A/Resources/sv.lproj/SUUpdateAlert.nib/classes.nib new file mode 100644 index 000000000..018710af8 --- /dev/null +++ b/mac/Sparkle.framework/Versions/A/Resources/sv.lproj/SUUpdateAlert.nib/classes.nib @@ -0,0 +1,39 @@ +{ + IBClasses = ( + { + CLASS = FirstResponder; + LANGUAGE = ObjC; + SUPERCLASS = NSObject; + }, + { + CLASS = NSApplication; + LANGUAGE = ObjC; + SUPERCLASS = NSResponder; + }, + { + CLASS = NSObject; + LANGUAGE = ObjC; + }, + { + ACTIONS = { + installUpdate = id; + remindMeLater = id; + skipThisVersion = id; + }; + CLASS = SUUpdateAlert; + LANGUAGE = ObjC; + OUTLETS = { + delegate = id; + description = NSTextField; + releaseNotesView = WebView; + }; + SUPERCLASS = SUWindowController; + }, + { + CLASS = SUWindowController; + LANGUAGE = ObjC; + SUPERCLASS = NSWindowController; + } + ); + IBVersion = 1; +} \ No newline at end of file diff --git a/mac/Sparkle.framework/Versions/A/Resources/sv.lproj/SUUpdateAlert.nib/info.nib b/mac/Sparkle.framework/Versions/A/Resources/sv.lproj/SUUpdateAlert.nib/info.nib new file mode 100644 index 000000000..6b787d4b9 --- /dev/null +++ b/mac/Sparkle.framework/Versions/A/Resources/sv.lproj/SUUpdateAlert.nib/info.nib @@ -0,0 +1,18 @@ + + + + + IBDocumentLocation + 69 14 356 240 0 0 1280 778 + IBFramework Version + 489.0 + IBLastKnownRelativeProjectPath + ../Sparkle.xcodeproj + IBOldestOS + 5 + IBSystem Version + 9D34 + targetFramework + IBCocoaFramework + + diff --git a/mac/Sparkle.framework/Versions/A/Resources/sv.lproj/SUUpdateAlert.nib/keyedobjects.nib b/mac/Sparkle.framework/Versions/A/Resources/sv.lproj/SUUpdateAlert.nib/keyedobjects.nib new file mode 100644 index 000000000..7e6d490e7 Binary files /dev/null and b/mac/Sparkle.framework/Versions/A/Resources/sv.lproj/SUUpdateAlert.nib/keyedobjects.nib differ diff --git a/mac/Sparkle.framework/Versions/A/Resources/sv.lproj/SUUpdatePermissionPrompt.nib/classes.nib b/mac/Sparkle.framework/Versions/A/Resources/sv.lproj/SUUpdatePermissionPrompt.nib/classes.nib new file mode 100644 index 000000000..5220a221f --- /dev/null +++ b/mac/Sparkle.framework/Versions/A/Resources/sv.lproj/SUUpdatePermissionPrompt.nib/classes.nib @@ -0,0 +1,59 @@ + + + + + IBClasses + + + CLASS + SUWindowController + LANGUAGE + ObjC + SUPERCLASS + NSWindowController + + + ACTIONS + + finishPrompt + id + toggleMoreInfo + id + + CLASS + SUUpdatePermissionPrompt + LANGUAGE + ObjC + OUTLETS + + delegate + id + descriptionTextField + NSTextField + moreInfoButton + NSButton + moreInfoView + NSView + + SUPERCLASS + SUWindowController + + + CLASS + FirstResponder + LANGUAGE + ObjC + SUPERCLASS + NSObject + + + CLASS + NSObject + LANGUAGE + ObjC + + + IBVersion + 1 + + diff --git a/mac/Sparkle.framework/Versions/A/Resources/sv.lproj/SUUpdatePermissionPrompt.nib/info.nib b/mac/Sparkle.framework/Versions/A/Resources/sv.lproj/SUUpdatePermissionPrompt.nib/info.nib new file mode 100644 index 000000000..c5a067e89 --- /dev/null +++ b/mac/Sparkle.framework/Versions/A/Resources/sv.lproj/SUUpdatePermissionPrompt.nib/info.nib @@ -0,0 +1,20 @@ + + + + + IBFramework Version + 670 + IBLastKnownRelativeProjectPath + ../Sparkle.xcodeproj + IBOldestOS + 5 + IBOpenObjects + + 6 + + IBSystem Version + 10A96 + targetFramework + IBCocoaFramework + + diff --git a/mac/Sparkle.framework/Versions/A/Resources/sv.lproj/SUUpdatePermissionPrompt.nib/keyedobjects.nib b/mac/Sparkle.framework/Versions/A/Resources/sv.lproj/SUUpdatePermissionPrompt.nib/keyedobjects.nib new file mode 100644 index 000000000..64babac12 Binary files /dev/null and b/mac/Sparkle.framework/Versions/A/Resources/sv.lproj/SUUpdatePermissionPrompt.nib/keyedobjects.nib differ diff --git a/mac/Sparkle.framework/Versions/A/Resources/sv.lproj/Sparkle.strings b/mac/Sparkle.framework/Versions/A/Resources/sv.lproj/Sparkle.strings new file mode 100644 index 000000000..b676a4f5d Binary files /dev/null and b/mac/Sparkle.framework/Versions/A/Resources/sv.lproj/Sparkle.strings differ diff --git a/mac/Sparkle.framework/Versions/A/Sparkle b/mac/Sparkle.framework/Versions/A/Sparkle new file mode 100755 index 000000000..0db0a8f01 Binary files /dev/null and b/mac/Sparkle.framework/Versions/A/Sparkle differ diff --git a/mac/Sparkle.framework/Versions/Current b/mac/Sparkle.framework/Versions/Current new file mode 120000 index 000000000..8c7e5a667 --- /dev/null +++ b/mac/Sparkle.framework/Versions/Current @@ -0,0 +1 @@ +A \ No newline at end of file diff --git a/mac/StyleSettings.plist b/mac/StyleSettings.plist new file mode 100644 index 000000000..da8517780 --- /dev/null +++ b/mac/StyleSettings.plist @@ -0,0 +1,87 @@ + + + + +kRequireSpaceAfterMethodType + +kRequireSpaceAfterReturnType + +kRequireSpaceAfterColon + +kRequireSpaceAfterParameterType + +kRequireOpenBraceOnMethodSignatureLine + +kRequireOpenBraceOnConditionalStatementLine + +kRequireSpaceAfterConditionalStatement + +kRequireEmptyLineAboveConditionalStatement + +kRequireEmptyLineAboveReturnStatement + +kRequireNoEmptyLineAsFirstLineInMethod + +kRequireSpaceAfterPropertyTypeDeclaration + +kRequireSpaceBeforeOpeningBrace + +KNumberOfEmptyLinesBetweenMethods +1 +kNumberOfEmptyLinesBeforeImplementation +1 +kNumberOfEmptyLinesAfterImplementation +1 +kMethodParameterPrefix + +kAsteriskSpacingRule +2 +kEqualSpacingRule +1 +kMathSpacingRule +1 +kElseFormatRule +0 +kElseIfFormatRule +0 +kRequireSpaceAboveBreak + +kRequireSpaceBeforeParameter + +kRequireSpaceBetweenTernaryOperators + +kRequireSpaceBeforeProtocolDeclarations + +kInterfaceColonSpacingRule +1 +kRequireSpaceAfterCommas + +kRequireSpaceBeforeCaseColons + +kSignatureAsteriskSpacingRule +2 +kNumberOfEmptyLinesAboveClassExtension +1 +kNumberOfEmptyLinesAboveInterface +1 +kViolationsShouldBeErrors + +kRequireSpaceAfterPropertyDeclaration + +kNumberOfEmptyLinesAboveCategory +1 +kStaticVariableAsteriskSpacingRule +1 +kNumberOfEmptyLinesBeforePragma +1 +kNumberOfEmptyLinesAfterPragma +1 +kNumberOfEmptyLinesAboveEnd +1 +kComparisonSpacingRule +1 +kAllowSingleLineIfStatements + + + + \ No newline at end of file diff --git a/mac/TeamTalk.xcodeproj/project.pbxproj b/mac/TeamTalk.xcodeproj/project.pbxproj new file mode 100644 index 000000000..dd144f9d2 --- /dev/null +++ b/mac/TeamTalk.xcodeproj/project.pbxproj @@ -0,0 +1,5626 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 46; + objects = { + +/* Begin PBXBuildFile section */ + 183B534218695FBA009073EC /* DDTaskManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 183B534118695FBA009073EC /* DDTaskManager.m */; }; + 183B536B186AFB27009073EC /* FileTransferEntity.m in Sources */ = {isa = PBXBuildFile; fileRef = 183B536A186AFB27009073EC /* FileTransferEntity.m */; }; + 183B5371186D58C2009073EC /* TcpProtocolHeader.m in Sources */ = {isa = PBXBuildFile; fileRef = 183B5370186D58C2009073EC /* TcpProtocolHeader.m */; }; + 183B5380187141A6009073EC /* NSData+NSJSONSerialization.m in Sources */ = {isa = PBXBuildFile; fileRef = 183B537F187141A6009073EC /* NSData+NSJSONSerialization.m */; }; + 183B5383187145A6009073EC /* MGJEntity.m in Sources */ = {isa = PBXBuildFile; fileRef = 183B5382187145A6009073EC /* MGJEntity.m */; }; + 183B538618714739009073EC /* NSDictionary+MGJ.m in Sources */ = {isa = PBXBuildFile; fileRef = 183B538518714739009073EC /* NSDictionary+MGJ.m */; }; + 183B538F1872976D009073EC /* NSNotification+DDLogic.m in Sources */ = {isa = PBXBuildFile; fileRef = 183B538E1872976D009073EC /* NSNotification+DDLogic.m */; }; + 183B53921872B720009073EC /* DDModuleDataManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 183B53911872B720009073EC /* DDModuleDataManager.m */; }; + 187FAC0518685D97006ACC30 /* DDModuleManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 187FAC0218685D97006ACC30 /* DDModuleManager.m */; }; + 187FAC0618685D97006ACC30 /* DDWatch.m in Sources */ = {isa = PBXBuildFile; fileRef = 187FAC0418685D97006ACC30 /* DDWatch.m */; }; + 187FAC0C18685DE2006ACC30 /* DDTaskOperation.m in Sources */ = {isa = PBXBuildFile; fileRef = 187FAC0918685DE2006ACC30 /* DDTaskOperation.m */; }; + 1886E1D31850A4ED00BA092C /* DDCommonApi.m in Sources */ = {isa = PBXBuildFile; fileRef = 1886E1D21850A4ED00BA092C /* DDCommonApi.m */; }; + 188B010F18505E8100A99E7A /* icon.icns in Resources */ = {isa = PBXBuildFile; fileRef = 188B010E18505E8100A99E7A /* icon.icns */; }; + 18906D3B18555843004B874E /* message.mp3 in Resources */ = {isa = PBXBuildFile; fileRef = 18906D3A18555843004B874E /* message.mp3 */; }; + 189B0A9C187694E600C3997A /* DDSharedDuoduo.m in Sources */ = {isa = PBXBuildFile; fileRef = 189B0A9B187694E600C3997A /* DDSharedDuoduo.m */; }; + 18A38FF1187A98BF00F3F19D /* DDMainModule.m in Sources */ = {isa = PBXBuildFile; fileRef = 18A38FF0187A98BF00F3F19D /* DDMainModule.m */; }; + 18A38FF7187AAD1A00F3F19D /* DDCommonModule.m in Sources */ = {isa = PBXBuildFile; fileRef = 18A38FF6187AAD1A00F3F19D /* DDCommonModule.m */; }; + 18C769FA188E444B0066AA8C /* SystemConfiguration.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 18C769F9188E444B0066AA8C /* SystemConfiguration.framework */; }; + 18C769FD188E44720066AA8C /* Reachability.m in Sources */ = {isa = PBXBuildFile; fileRef = 18C769FC188E44720066AA8C /* Reachability.m */; }; + 18FF1D18185177F700C19036 /* DDSound.m in Sources */ = {isa = PBXBuildFile; fileRef = 18FF1D17185177F700C19036 /* DDSound.m */; }; + 37E4C02E1A6CAE4600178EA8 /* MTDatabaseUtil.m in Sources */ = {isa = PBXBuildFile; fileRef = 37E4C02D1A6CAE4600178EA8 /* MTDatabaseUtil.m */; }; + 37E4C0381A6E486A00178EA8 /* MTSysConfigEntity.m in Sources */ = {isa = PBXBuildFile; fileRef = 37E4C0371A6E486A00178EA8 /* MTSysConfigEntity.m */; }; + 37E4C03B1A6E487E00178EA8 /* MTSysConfigModule.m in Sources */ = {isa = PBXBuildFile; fileRef = 37E4C03A1A6E487E00178EA8 /* MTSysConfigModule.m */; }; + 5700BF0918A8A4B00060092F /* Sparkle.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 5700BF0818A8A4B00060092F /* Sparkle.framework */; }; + 5700BF0C18A8A5AD0060092F /* dsa_pub.pem in Resources */ = {isa = PBXBuildFile; fileRef = 5700BF0B18A8A5AD0060092F /* dsa_pub.pem */; }; + 5709F94F1848682E0096D176 /* DDImageSpreadView.m in Sources */ = {isa = PBXBuildFile; fileRef = 5709F94E1848682E0096D176 /* DDImageSpreadView.m */; }; + 5709F95218486ABB0096D176 /* toolbar_bg_theme_gray.png in Resources */ = {isa = PBXBuildFile; fileRef = 5709F95018486ABB0096D176 /* toolbar_bg_theme_gray.png */; }; + 5709F95318486ABB0096D176 /* toolbar_bg_theme_gray@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = 5709F95118486ABB0096D176 /* toolbar_bg_theme_gray@2x.png */; }; + 5709F95818486DDA0096D176 /* seperator_left.png in Resources */ = {isa = PBXBuildFile; fileRef = 5709F95418486DDA0096D176 /* seperator_left.png */; }; + 5709F95918486DDA0096D176 /* seperator_left@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = 5709F95518486DDA0096D176 /* seperator_left@2x.png */; }; + 5709F95A18486DDA0096D176 /* seperator_right.png in Resources */ = {isa = PBXBuildFile; fileRef = 5709F95618486DDA0096D176 /* seperator_right.png */; }; + 5709F95B18486DDA0096D176 /* seperator_right@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = 5709F95718486DDA0096D176 /* seperator_right@2x.png */; }; + 5709F95E18486E320096D176 /* DDImageView.m in Sources */ = {isa = PBXBuildFile; fileRef = 5709F95D18486E320096D176 /* DDImageView.m */; }; + 5709F967184871A70096D176 /* icon_conversation_highlight_theme_gray.png in Resources */ = {isa = PBXBuildFile; fileRef = 5709F95F184871A70096D176 /* icon_conversation_highlight_theme_gray.png */; }; + 5709F968184871A70096D176 /* icon_conversation_highlight_theme_gray@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = 5709F960184871A70096D176 /* icon_conversation_highlight_theme_gray@2x.png */; }; + 5709F969184871A70096D176 /* icon_conversation_theme_gray.png in Resources */ = {isa = PBXBuildFile; fileRef = 5709F961184871A70096D176 /* icon_conversation_theme_gray.png */; }; + 5709F96A184871A70096D176 /* icon_conversation_theme_gray@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = 5709F962184871A70096D176 /* icon_conversation_theme_gray@2x.png */; }; + 5709F96B184871A70096D176 /* icon_organization_click_theme_gray.png in Resources */ = {isa = PBXBuildFile; fileRef = 5709F963184871A70096D176 /* icon_organization_click_theme_gray.png */; }; + 5709F96C184871A70096D176 /* icon_organization_click_theme_gray@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = 5709F964184871A70096D176 /* icon_organization_click_theme_gray@2x.png */; }; + 5709F96D184871A70096D176 /* icon_organization_highlight_theme_gray.png in Resources */ = {isa = PBXBuildFile; fileRef = 5709F965184871A70096D176 /* icon_organization_highlight_theme_gray.png */; }; + 5709F96E184871A70096D176 /* icon_organization_highlight_theme_gray@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = 5709F966184871A70096D176 /* icon_organization_highlight_theme_gray@2x.png */; }; + 570D6E461839B0E100F68CB0 /* AIImageDrawingAdditions.m in Sources */ = {isa = PBXBuildFile; fileRef = 570D6E451839B0E100F68CB0 /* AIImageDrawingAdditions.m */; }; + 570D6E491839B24200F68CB0 /* AIImageAdditions.m in Sources */ = {isa = PBXBuildFile; fileRef = 570D6E481839B24200F68CB0 /* AIImageAdditions.m */; }; + 570D6E4C1839B28000F68CB0 /* AIFileManagerAdditions.m in Sources */ = {isa = PBXBuildFile; fileRef = 570D6E4B1839B28000F68CB0 /* AIFileManagerAdditions.m */; }; + 570D6E52183A053E00F68CB0 /* Quartz.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 570D6E50183A053E00F68CB0 /* Quartz.framework */; }; + 570D6E53183A053E00F68CB0 /* QuartzCore.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 570D6E51183A053E00F68CB0 /* QuartzCore.framework */; }; + 57124E4B187AAEAD006D2DCA /* DDAlertWindowController.m in Sources */ = {isa = PBXBuildFile; fileRef = 57124E49187AAEAD006D2DCA /* DDAlertWindowController.m */; }; + 57124E4C187AAEAD006D2DCA /* DDAlertWindowController.xib in Resources */ = {isa = PBXBuildFile; fileRef = 57124E4A187AAEAD006D2DCA /* DDAlertWindowController.xib */; }; + 57124E56187E331A006D2DCA /* ImageAndTextCell.m in Sources */ = {isa = PBXBuildFile; fileRef = 57124E55187E331A006D2DCA /* ImageAndTextCell.m */; }; + 57124E59187E531D006D2DCA /* DDChattingContactListViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 57124E58187E531D006D2DCA /* DDChattingContactListViewController.m */; }; + 57124E5C187E6E3D006D2DCA /* DDTableView.m in Sources */ = {isa = PBXBuildFile; fileRef = 57124E5B187E6E3D006D2DCA /* DDTableView.m */; }; + 57124E62187E743A006D2DCA /* panel_bg_theme_gray.png in Resources */ = {isa = PBXBuildFile; fileRef = 57124E60187E743A006D2DCA /* panel_bg_theme_gray.png */; }; + 57124E63187E743A006D2DCA /* panel_bg_theme_gray@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = 57124E61187E743A006D2DCA /* panel_bg_theme_gray@2x.png */; }; + 57149F93184487C200DDBA25 /* EGOCache.m in Sources */ = {isa = PBXBuildFile; fileRef = 57149F8A184487C200DDBA25 /* EGOCache.m */; settings = {COMPILER_FLAGS = "-fno-objc-arc"; }; }; + 57149F94184487C200DDBA25 /* EGOImageLoadConnection.m in Sources */ = {isa = PBXBuildFile; fileRef = 57149F8C184487C200DDBA25 /* EGOImageLoadConnection.m */; settings = {COMPILER_FLAGS = "-fno-objc-arc"; }; }; + 57149F95184487C200DDBA25 /* EGOImageLoader.m in Sources */ = {isa = PBXBuildFile; fileRef = 57149F8E184487C200DDBA25 /* EGOImageLoader.m */; settings = {COMPILER_FLAGS = "-fno-objc-arc"; }; }; + 57149F96184487C200DDBA25 /* EGOImageView.m in Sources */ = {isa = PBXBuildFile; fileRef = 57149F90184487C200DDBA25 /* EGOImageView.m */; settings = {COMPILER_FLAGS = "-fno-objc-arc"; }; }; + 57149FF1184592B700DDBA25 /* DDAutoScrollView.m in Sources */ = {isa = PBXBuildFile; fileRef = 57149FF0184592B700DDBA25 /* DDAutoScrollView.m */; }; + 57149FFC1845D32E00DDBA25 /* CaptureView.m in Sources */ = {isa = PBXBuildFile; fileRef = 57149FF71845D32E00DDBA25 /* CaptureView.m */; }; + 57149FFD1845D32E00DDBA25 /* CaptureWindow.m in Sources */ = {isa = PBXBuildFile; fileRef = 57149FF91845D32E00DDBA25 /* CaptureWindow.m */; }; + 5714A0001845D45900DDBA25 /* Carbon.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 57149FFF1845D45900DDBA25 /* Carbon.framework */; }; + 5714A0031845D4D000DDBA25 /* ScreenCapture_toolbar_cancel.png in Resources */ = {isa = PBXBuildFile; fileRef = 5714A0011845D4D000DDBA25 /* ScreenCapture_toolbar_cancel.png */; }; + 5714A0041845D4D000DDBA25 /* ScreenCapture_toolbar_ok.png in Resources */ = {isa = PBXBuildFile; fileRef = 5714A0021845D4D000DDBA25 /* ScreenCapture_toolbar_ok.png */; }; + 571CFF9D188F92D30030E02C /* DDEmotionAttachment.m in Sources */ = {isa = PBXBuildFile; fileRef = 571CFF9C188F92D30030E02C /* DDEmotionAttachment.m */; }; + 571CFFA11890B41C0030E02C /* FMSearchTokenFieldCell.m in Sources */ = {isa = PBXBuildFile; fileRef = 571CFFA01890B41C0030E02C /* FMSearchTokenFieldCell.m */; }; + 571CFFA41890BD6A0030E02C /* FMSearchTokenAttachmentCell.m in Sources */ = {isa = PBXBuildFile; fileRef = 571CFFA31890BD6A0030E02C /* FMSearchTokenAttachmentCell.m */; }; + 571CFFA718920A010030E02C /* DDSearchFieldEditorDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = 571CFFA618920A010030E02C /* DDSearchFieldEditorDelegate.m */; }; + 571FD9B61868190300F7476B /* tabbar_bg_theme_gray.png in Resources */ = {isa = PBXBuildFile; fileRef = 571FD9B41868190300F7476B /* tabbar_bg_theme_gray.png */; }; + 571FD9B71868190300F7476B /* tabbar_bg_theme_gray@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = 571FD9B51868190300F7476B /* tabbar_bg_theme_gray@2x.png */; }; + 571FD9BA18681A5F00F7476B /* FMSearchTokenField.m in Sources */ = {isa = PBXBuildFile; fileRef = 571FD9B918681A5F00F7476B /* FMSearchTokenField.m */; }; + 57285D3C18AB60F100E90EC2 /* icon_folder.png in Resources */ = {isa = PBXBuildFile; fileRef = 57285D3A18AB60F100E90EC2 /* icon_folder.png */; }; + 57285D3D18AB60F100E90EC2 /* icon_folder@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = 57285D3B18AB60F100E90EC2 /* icon_folder@2x.png */; }; + 57285D4018AB63BE00E90EC2 /* preference_divider.png in Resources */ = {isa = PBXBuildFile; fileRef = 57285D3E18AB63BE00E90EC2 /* preference_divider.png */; }; + 57285D4118AB63BE00E90EC2 /* preference_divider@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = 57285D3F18AB63BE00E90EC2 /* preference_divider@2x.png */; }; + 57285D4F18AB814400E90EC2 /* DDPreferenceWinController.m in Sources */ = {isa = PBXBuildFile; fileRef = 57285D4D18AB814400E90EC2 /* DDPreferenceWinController.m */; }; + 57285D5018AB814400E90EC2 /* DDPreferenceWinController.xib in Resources */ = {isa = PBXBuildFile; fileRef = 57285D4E18AB814400E90EC2 /* DDPreferenceWinController.xib */; }; + 57285D5318AB860E00E90EC2 /* DDUserPreferences.m in Sources */ = {isa = PBXBuildFile; fileRef = 57285D5218AB860E00E90EC2 /* DDUserPreferences.m */; }; + 57285D5618B19BD000E90EC2 /* DDOptionsBase.m in Sources */ = {isa = PBXBuildFile; fileRef = 57285D5518B19BD000E90EC2 /* DDOptionsBase.m */; }; + 572A87C118B5ED96003E3FC8 /* icon_addcontacts_disable_theme_gray.png in Resources */ = {isa = PBXBuildFile; fileRef = 572A87BB18B5ED95003E3FC8 /* icon_addcontacts_disable_theme_gray.png */; }; + 572A87C218B5ED96003E3FC8 /* icon_addcontacts_disable_theme_gray@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = 572A87BC18B5ED96003E3FC8 /* icon_addcontacts_disable_theme_gray@2x.png */; }; + 572A87C318B5ED96003E3FC8 /* icon_addcontacts_highlight_theme_gray.png in Resources */ = {isa = PBXBuildFile; fileRef = 572A87BD18B5ED96003E3FC8 /* icon_addcontacts_highlight_theme_gray.png */; }; + 572A87C418B5ED96003E3FC8 /* icon_addcontacts_highlight_theme_gray@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = 572A87BE18B5ED96003E3FC8 /* icon_addcontacts_highlight_theme_gray@2x.png */; }; + 572A87C518B5ED96003E3FC8 /* icon_addcontacts_theme_gray.png in Resources */ = {isa = PBXBuildFile; fileRef = 572A87BF18B5ED96003E3FC8 /* icon_addcontacts_theme_gray.png */; }; + 572A87C618B5ED96003E3FC8 /* icon_addcontacts_theme_gray@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = 572A87C018B5ED96003E3FC8 /* icon_addcontacts_theme_gray@2x.png */; }; + 572A87E218B74E7B003E3FC8 /* DDClickCell.m in Sources */ = {isa = PBXBuildFile; fileRef = 572A87E118B74E7B003E3FC8 /* DDClickCell.m */; }; + 572A87E618B74E9F003E3FC8 /* DDAddChatGroupWindowController.m in Sources */ = {isa = PBXBuildFile; fileRef = 572A87E418B74E9F003E3FC8 /* DDAddChatGroupWindowController.m */; }; + 572A87E718B74E9F003E3FC8 /* DDAddChatGroupWindowController.xib in Resources */ = {isa = PBXBuildFile; fileRef = 572A87E518B74E9F003E3FC8 /* DDAddChatGroupWindowController.xib */; }; + 572A87EA18B75A21003E3FC8 /* icon_folder_h21.png in Resources */ = {isa = PBXBuildFile; fileRef = 572A87E818B75A21003E3FC8 /* icon_folder_h21.png */; }; + 572A87EB18B75A21003E3FC8 /* icon_folder_h21@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = 572A87E918B75A21003E3FC8 /* icon_folder_h21@2x.png */; }; + 572A87F618B75B04003E3FC8 /* icon_user_away_h28.png in Resources */ = {isa = PBXBuildFile; fileRef = 572A87EC18B75B04003E3FC8 /* icon_user_away_h28.png */; }; + 572A87F718B75B04003E3FC8 /* icon_user_away_h28@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = 572A87ED18B75B04003E3FC8 /* icon_user_away_h28@2x.png */; }; + 572A87F818B75B04003E3FC8 /* icon_user_female_away_h28.png in Resources */ = {isa = PBXBuildFile; fileRef = 572A87EE18B75B04003E3FC8 /* icon_user_female_away_h28.png */; }; + 572A87F918B75B04003E3FC8 /* icon_user_female_away_h28@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = 572A87EF18B75B04003E3FC8 /* icon_user_female_away_h28@2x.png */; }; + 572A87FA18B75B04003E3FC8 /* icon_user_female_h28.png in Resources */ = {isa = PBXBuildFile; fileRef = 572A87F018B75B04003E3FC8 /* icon_user_female_h28.png */; }; + 572A87FB18B75B04003E3FC8 /* icon_user_female_h28@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = 572A87F118B75B04003E3FC8 /* icon_user_female_h28@2x.png */; }; + 572A87FC18B75B04003E3FC8 /* icon_user_h28.png in Resources */ = {isa = PBXBuildFile; fileRef = 572A87F218B75B04003E3FC8 /* icon_user_h28.png */; }; + 572A87FD18B75B04003E3FC8 /* icon_user_h28@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = 572A87F318B75B04003E3FC8 /* icon_user_h28@2x.png */; }; + 572A87FE18B75B04003E3FC8 /* icon_user_offline_h28.png in Resources */ = {isa = PBXBuildFile; fileRef = 572A87F418B75B04003E3FC8 /* icon_user_offline_h28.png */; }; + 572A87FF18B75B04003E3FC8 /* icon_user_offline_h28@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = 572A87F518B75B04003E3FC8 /* icon_user_offline_h28@2x.png */; }; + 572A880518B773EF003E3FC8 /* BaseNode.m in Sources */ = {isa = PBXBuildFile; fileRef = 572A880218B773EF003E3FC8 /* BaseNode.m */; }; + 572A880618B773EF003E3FC8 /* ChildNode.m in Sources */ = {isa = PBXBuildFile; fileRef = 572A880418B773EF003E3FC8 /* ChildNode.m */; }; + 5733D829184F284400737695 /* DDWindowAdditions.m in Sources */ = {isa = PBXBuildFile; fileRef = 5733D828184F284400737695 /* DDWindowAdditions.m */; }; + 5733D82C184F2C4A00737695 /* AIAttributedStringAdditions.m in Sources */ = {isa = PBXBuildFile; fileRef = 5733D82B184F2C4A00737695 /* AIAttributedStringAdditions.m */; }; + 5733D82F184F2D1600737695 /* AIColorAdditions.m in Sources */ = {isa = PBXBuildFile; fileRef = 5733D82E184F2D1600737695 /* AIColorAdditions.m */; }; + 5733D832184F2DFF00737695 /* AITextAttributes.m in Sources */ = {isa = PBXBuildFile; fileRef = 5733D831184F2DFF00737695 /* AITextAttributes.m */; }; + 5733D835184F2E4D00737695 /* AIFontManagerAdditions.m in Sources */ = {isa = PBXBuildFile; fileRef = 5733D834184F2E4D00737695 /* AIFontManagerAdditions.m */; }; + 5733D838184F317200737695 /* AITextAttachmentExtension.m in Sources */ = {isa = PBXBuildFile; fileRef = 5733D837184F317200737695 /* AITextAttachmentExtension.m */; }; + 5733D83E184F326600737695 /* AITextAttachmentAdditions.m in Sources */ = {isa = PBXBuildFile; fileRef = 5733D83D184F326600737695 /* AITextAttachmentAdditions.m */; }; + 5733D841184F33F500737695 /* AIPasteboardAdditions.m in Sources */ = {isa = PBXBuildFile; fileRef = 5733D840184F33F500737695 /* AIPasteboardAdditions.m */; }; + 573847331820CDA000443653 /* Cocoa.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 573847321820CDA000443653 /* Cocoa.framework */; }; + 5738473D1820CDA000443653 /* InfoPlist.strings in Resources */ = {isa = PBXBuildFile; fileRef = 5738473B1820CDA000443653 /* InfoPlist.strings */; }; + 5738473F1820CDA000443653 /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 5738473E1820CDA000443653 /* main.m */; }; + 573847431820CDA000443653 /* Credits.rtf in Resources */ = {isa = PBXBuildFile; fileRef = 573847411820CDA000443653 /* Credits.rtf */; }; + 573847461820CDA000443653 /* DDAppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = 573847451820CDA000443653 /* DDAppDelegate.m */; }; + 573847491820CDA000443653 /* MainMenu.xib in Resources */ = {isa = PBXBuildFile; fileRef = 573847471820CDA000443653 /* MainMenu.xib */; }; + 5738474B1820CDA000443653 /* Images.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 5738474A1820CDA000443653 /* Images.xcassets */; }; + 573847861820CE9900443653 /* MessageEntity.m in Sources */ = {isa = PBXBuildFile; fileRef = 5738476A1820CE9900443653 /* MessageEntity.m */; }; + 573847881820CE9900443653 /* DataInputStream.m in Sources */ = {isa = PBXBuildFile; fileRef = 5738476E1820CE9900443653 /* DataInputStream.m */; }; + 573847891820CE9900443653 /* DataOutputStream.m in Sources */ = {isa = PBXBuildFile; fileRef = 573847701820CE9900443653 /* DataOutputStream.m */; }; + 5738478E1820CE9900443653 /* NSStream+NSStreamAddition.m in Sources */ = {isa = PBXBuildFile; fileRef = 5738477E1820CE9900443653 /* NSStream+NSStreamAddition.m */; }; + 573847911820CE9900443653 /* SendBuffer.m in Sources */ = {isa = PBXBuildFile; fileRef = 573847851820CE9900443653 /* SendBuffer.m */; }; + 5738479E1820D80E00443653 /* DDWindowController.m in Sources */ = {isa = PBXBuildFile; fileRef = 5738479D1820D80E00443653 /* DDWindowController.m */; }; + 573AF6041A67FA3A00B6D3B8 /* MTScreenCaptureModule.m in Sources */ = {isa = PBXBuildFile; fileRef = 573AF6031A67FA3A00B6D3B8 /* MTScreenCaptureModule.m */; }; + 573AF6071A67FED000B6D3B8 /* LoginEntity.m in Sources */ = {isa = PBXBuildFile; fileRef = 573AF6061A67FED000B6D3B8 /* LoginEntity.m */; }; + 5741BC321862E540003F2667 /* aio_recentsession_unreadmsg_selected_wide.png in Resources */ = {isa = PBXBuildFile; fileRef = 5741BC2A1862E540003F2667 /* aio_recentsession_unreadmsg_selected_wide.png */; }; + 5741BC331862E540003F2667 /* aio_recentsession_unreadmsg_selected_wide@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = 5741BC2B1862E540003F2667 /* aio_recentsession_unreadmsg_selected_wide@2x.png */; }; + 5741BC341862E540003F2667 /* aio_recentsession_unreadmsg_selected.png in Resources */ = {isa = PBXBuildFile; fileRef = 5741BC2C1862E540003F2667 /* aio_recentsession_unreadmsg_selected.png */; }; + 5741BC351862E540003F2667 /* aio_recentsession_unreadmsg_selected@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = 5741BC2D1862E540003F2667 /* aio_recentsession_unreadmsg_selected@2x.png */; }; + 5741BC361862E540003F2667 /* aio_recentsession_unreadmsg_wide.png in Resources */ = {isa = PBXBuildFile; fileRef = 5741BC2E1862E540003F2667 /* aio_recentsession_unreadmsg_wide.png */; }; + 5741BC371862E540003F2667 /* aio_recentsession_unreadmsg_wide@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = 5741BC2F1862E540003F2667 /* aio_recentsession_unreadmsg_wide@2x.png */; }; + 5741BC381862E540003F2667 /* aio_recentsession_unreadmsg.png in Resources */ = {isa = PBXBuildFile; fileRef = 5741BC301862E540003F2667 /* aio_recentsession_unreadmsg.png */; }; + 5741BC391862E540003F2667 /* aio_recentsession_unreadmsg@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = 5741BC311862E540003F2667 /* aio_recentsession_unreadmsg@2x.png */; }; + 576BA9671876D0BB002B40EC /* DDInterfaceController.m in Sources */ = {isa = PBXBuildFile; fileRef = 576BA9661876D0BB002B40EC /* DDInterfaceController.m */; }; + 576CE67B18D0764B00DEBCD5 /* icon_send_file_gray.png in Resources */ = {isa = PBXBuildFile; fileRef = 576CE67718D0764B00DEBCD5 /* icon_send_file_gray.png */; }; + 576CE67C18D0764B00DEBCD5 /* icon_send_file_gray@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = 576CE67818D0764B00DEBCD5 /* icon_send_file_gray@2x.png */; }; + 576CE67D18D0764B00DEBCD5 /* icon_send_file_highlight.png in Resources */ = {isa = PBXBuildFile; fileRef = 576CE67918D0764B00DEBCD5 /* icon_send_file_highlight.png */; }; + 576CE67E18D0764B00DEBCD5 /* icon_send_file_highlight@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = 576CE67A18D0764B00DEBCD5 /* icon_send_file_highlight@2x.png */; }; + 576CE6CF18D1B68B00DEBCD5 /* icon_refresh_arrow_down.png in Resources */ = {isa = PBXBuildFile; fileRef = 576CE6CB18D1B68B00DEBCD5 /* icon_refresh_arrow_down.png */; }; + 576CE6D018D1B68B00DEBCD5 /* icon_refresh_arrow_down@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = 576CE6CC18D1B68B00DEBCD5 /* icon_refresh_arrow_down@2x.png */; }; + 576CE6D118D1B68B00DEBCD5 /* icon_refresh_arrow.png in Resources */ = {isa = PBXBuildFile; fileRef = 576CE6CD18D1B68B00DEBCD5 /* icon_refresh_arrow.png */; }; + 576CE6D218D1B68B00DEBCD5 /* icon_refresh_arrow@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = 576CE6CE18D1B68B00DEBCD5 /* icon_refresh_arrow@2x.png */; }; + 5771F1411A7E5D0C003EDC6A /* MTGroupChangeMemberAPI.m in Sources */ = {isa = PBXBuildFile; fileRef = 5771F1401A7E5D0C003EDC6A /* MTGroupChangeMemberAPI.m */; }; + 5772C9C818D00B9B008FE09F /* pull-to-refresh-arrow.png in Resources */ = {isa = PBXBuildFile; fileRef = 5772C9C618D00B9B008FE09F /* pull-to-refresh-arrow.png */; }; + 5772C9C918D00B9B008FE09F /* release-to-refresh.png in Resources */ = {isa = PBXBuildFile; fileRef = 5772C9C718D00B9B008FE09F /* release-to-refresh.png */; }; + 5772C9CB18D00CBD008FE09F /* icon_close.png in Resources */ = {isa = PBXBuildFile; fileRef = 5772C9CA18D00CBD008FE09F /* icon_close.png */; }; + 5772C9CE18D00E62008FE09F /* icon_statusbar.tif in Resources */ = {isa = PBXBuildFile; fileRef = 5772C9CC18D00E62008FE09F /* icon_statusbar.tif */; }; + 577BB80B1A64F78E00264086 /* IMBaseDefine.pb.m in Sources */ = {isa = PBXBuildFile; fileRef = 577BB7FC1A64F78E00264086 /* IMBaseDefine.pb.m */; }; + 577BB80C1A64F78E00264086 /* IMBuddy.pb.m in Sources */ = {isa = PBXBuildFile; fileRef = 577BB7FE1A64F78E00264086 /* IMBuddy.pb.m */; }; + 577BB80D1A64F78E00264086 /* IMGroup.pb.m in Sources */ = {isa = PBXBuildFile; fileRef = 577BB8001A64F78E00264086 /* IMGroup.pb.m */; }; + 577BB80E1A64F78E00264086 /* IMLogin.pb.m in Sources */ = {isa = PBXBuildFile; fileRef = 577BB8021A64F78E00264086 /* IMLogin.pb.m */; }; + 577BB80F1A64F78E00264086 /* IMMessage.pb.m in Sources */ = {isa = PBXBuildFile; fileRef = 577BB8041A64F78E00264086 /* IMMessage.pb.m */; }; + 577BB8101A64F78E00264086 /* IMOther.pb.m in Sources */ = {isa = PBXBuildFile; fileRef = 577BB8061A64F78E00264086 /* IMOther.pb.m */; }; + 577BB8111A64F78E00264086 /* IMSwitchService.pb.m in Sources */ = {isa = PBXBuildFile; fileRef = 577BB8081A64F78E00264086 /* IMSwitchService.pb.m */; }; + 577BB8121A64F78E00264086 /* IMXIAOT.pb.m in Sources */ = {isa = PBXBuildFile; fileRef = 577BB80A1A64F78E00264086 /* IMXIAOT.pb.m */; }; + 577C167F18474005009718D7 /* DDMainWindow.xib in Resources */ = {isa = PBXBuildFile; fileRef = 577C167E18474005009718D7 /* DDMainWindow.xib */; }; + 577C168218474317009718D7 /* DDMainWindowController.m in Sources */ = {isa = PBXBuildFile; fileRef = 577C168118474317009718D7 /* DDMainWindowController.m */; }; + 577C168518474649009718D7 /* icon_online.png in Resources */ = {isa = PBXBuildFile; fileRef = 577C168318474649009718D7 /* icon_online.png */; }; + 577C168618474649009718D7 /* icon_online@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = 577C168418474649009718D7 /* icon_online@2x.png */; }; + 577C168D184749A1009718D7 /* icon_user_h51.png in Resources */ = {isa = PBXBuildFile; fileRef = 577C168B184749A1009718D7 /* icon_user_h51.png */; }; + 577C168E184749A1009718D7 /* icon_user_h51@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = 577C168C184749A1009718D7 /* icon_user_h51@2x.png */; }; + 577C169118475857009718D7 /* DDTabItemView.m in Sources */ = {isa = PBXBuildFile; fileRef = 577C169018475857009718D7 /* DDTabItemView.m */; }; + 577C169418476804009718D7 /* DDMainWindow.m in Sources */ = {isa = PBXBuildFile; fileRef = 577C169318476804009718D7 /* DDMainWindow.m */; }; + 578BB18818B49ECF007C2294 /* Sparkle.framework in Copy Files */ = {isa = PBXBuildFile; fileRef = 5700BF0818A8A4B00060092F /* Sparkle.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, ); }; }; + 578D5EA0187EC0C600568EE6 /* icon_offline.png in Resources */ = {isa = PBXBuildFile; fileRef = 578D5E9E187EC0C600568EE6 /* icon_offline.png */; }; + 578D5EA1187EC0C600568EE6 /* icon_offline@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = 578D5E9F187EC0C600568EE6 /* icon_offline@2x.png */; }; + 578D5EA4187EC0E600568EE6 /* icon_away.png in Resources */ = {isa = PBXBuildFile; fileRef = 578D5EA2187EC0E600568EE6 /* icon_away.png */; }; + 578D5EA5187EC0E600568EE6 /* icon_away@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = 578D5EA3187EC0E600568EE6 /* icon_away@2x.png */; }; + 578D5EAC187FC44A00568EE6 /* DDChattingHeadViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 578D5EAB187FC44A00568EE6 /* DDChattingHeadViewController.m */; }; + 578D5EAF188383EE00568EE6 /* DDImageMessage.m in Sources */ = {isa = PBXBuildFile; fileRef = 578D5EAE188383EE00568EE6 /* DDImageMessage.m */; }; + 579E54781A67C3B4003031A1 /* DDHttpEntity.m in Sources */ = {isa = PBXBuildFile; fileRef = 579E54751A67C3B4003031A1 /* DDHttpEntity.m */; }; + 579E54791A67C3B4003031A1 /* DDHttpModule.m in Sources */ = {isa = PBXBuildFile; fileRef = 579E54771A67C3B4003031A1 /* DDHttpModule.m */; }; + 579E547D1A67C426003031A1 /* DDLogic.m in Sources */ = {isa = PBXBuildFile; fileRef = 579E547B1A67C426003031A1 /* DDLogic.m */; }; + 57A4B5551A722E1700E16CBC /* MTChattingInputView.m in Sources */ = {isa = PBXBuildFile; fileRef = 57A4B5541A722E1700E16CBC /* MTChattingInputView.m */; }; + 57AB317D18287E6800B7766E /* DDKeychain.m in Sources */ = {isa = PBXBuildFile; fileRef = 57AB317C18287E6800B7766E /* DDKeychain.m */; }; + 57AB317F1828816100B7766E /* Security.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 57AB317E1828816100B7766E /* Security.framework */; }; + 57AB4F111821EAD500603621 /* NSEvent+DDEventAdditions.m in Sources */ = {isa = PBXBuildFile; fileRef = 57AB4F101821EAD500603621 /* NSEvent+DDEventAdditions.m */; }; + 57AB4F141821EFBC00603621 /* NSFileManager+DDFileManagerAdditions.m in Sources */ = {isa = PBXBuildFile; fileRef = 57AB4F131821EFBC00603621 /* NSFileManager+DDFileManagerAdditions.m */; }; + 57AB4F171821F00E00603621 /* NSString+DDStringAdditions.m in Sources */ = {isa = PBXBuildFile; fileRef = 57AB4F161821F00E00603621 /* NSString+DDStringAdditions.m */; }; + 57AF228A1820F2EF00758483 /* DDLoginWindowController.m in Sources */ = {isa = PBXBuildFile; fileRef = 57AF22891820F2EF00758483 /* DDLoginWindowController.m */; }; + 57AF228C1820F31600758483 /* LoginSelect.xib in Resources */ = {isa = PBXBuildFile; fileRef = 57AF228B1820F31600758483 /* LoginSelect.xib */; }; + 57AF2295182108E300758483 /* DDDictionaryAdditions.m in Sources */ = {isa = PBXBuildFile; fileRef = 57AF2294182108E300758483 /* DDDictionaryAdditions.m */; }; + 57AF229818210D8100758483 /* DDSharedWriterQueue.m in Sources */ = {isa = PBXBuildFile; fileRef = 57AF229718210D8100758483 /* DDSharedWriterQueue.m */; }; + 57AF72BA18683E4000C06257 /* tab_bg.png in Resources */ = {isa = PBXBuildFile; fileRef = 57AF72B918683E4000C06257 /* tab_bg.png */; }; + 57B2A60A18273BD2000A16FD /* duoduo.png in Resources */ = {isa = PBXBuildFile; fileRef = 57B2A60918273BD2000A16FD /* duoduo.png */; }; + 57B3902018349DA6007CD3E0 /* AIBezierPathAdditions.m in Sources */ = {isa = PBXBuildFile; fileRef = 57B3901F18349DA6007CD3E0 /* AIBezierPathAdditions.m */; }; + 57B390261834A970007CD3E0 /* DDImageCollectionView.m in Sources */ = {isa = PBXBuildFile; fileRef = 57B390251834A970007CD3E0 /* DDImageCollectionView.m */; }; + 57B3ACE818C0ACDD00F50C8F /* DDChattingViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 57B3ACE718C0ACDD00F50C8F /* DDChattingViewController.m */; }; + 57B62324183072FB00F2B249 /* NSObject+SBJson.m in Sources */ = {isa = PBXBuildFile; fileRef = 57B6230C183072FB00F2B249 /* NSObject+SBJson.m */; }; + 57B62325183072FB00F2B249 /* SBJsonParser.m in Sources */ = {isa = PBXBuildFile; fileRef = 57B6230F183072FB00F2B249 /* SBJsonParser.m */; }; + 57B62326183072FB00F2B249 /* SBJsonStreamParser.m in Sources */ = {isa = PBXBuildFile; fileRef = 57B62311183072FB00F2B249 /* SBJsonStreamParser.m */; }; + 57B62327183072FB00F2B249 /* SBJsonStreamParserAccumulator.m in Sources */ = {isa = PBXBuildFile; fileRef = 57B62313183072FB00F2B249 /* SBJsonStreamParserAccumulator.m */; }; + 57B62328183072FB00F2B249 /* SBJsonStreamParserAdapter.m in Sources */ = {isa = PBXBuildFile; fileRef = 57B62315183072FB00F2B249 /* SBJsonStreamParserAdapter.m */; }; + 57B62329183072FB00F2B249 /* SBJsonStreamParserState.m in Sources */ = {isa = PBXBuildFile; fileRef = 57B62317183072FB00F2B249 /* SBJsonStreamParserState.m */; }; + 57B6232A183072FB00F2B249 /* SBJsonStreamWriter.m in Sources */ = {isa = PBXBuildFile; fileRef = 57B62319183072FB00F2B249 /* SBJsonStreamWriter.m */; }; + 57B6232B183072FB00F2B249 /* SBJsonStreamWriterAccumulator.m in Sources */ = {isa = PBXBuildFile; fileRef = 57B6231B183072FB00F2B249 /* SBJsonStreamWriterAccumulator.m */; }; + 57B6232C183072FB00F2B249 /* SBJsonStreamWriterState.m in Sources */ = {isa = PBXBuildFile; fileRef = 57B6231D183072FB00F2B249 /* SBJsonStreamWriterState.m */; }; + 57B6232D183072FB00F2B249 /* SBJsonTokeniser.m in Sources */ = {isa = PBXBuildFile; fileRef = 57B6231F183072FB00F2B249 /* SBJsonTokeniser.m */; }; + 57B6232E183072FB00F2B249 /* SBJsonUTF8Stream.m in Sources */ = {isa = PBXBuildFile; fileRef = 57B62321183072FB00F2B249 /* SBJsonUTF8Stream.m */; }; + 57B6232F183072FB00F2B249 /* SBJsonWriter.m in Sources */ = {isa = PBXBuildFile; fileRef = 57B62323183072FB00F2B249 /* SBJsonWriter.m */; }; + 57B95BBC1A7CCEE8004DFB22 /* MASShortcut.m in Sources */ = {isa = PBXBuildFile; fileRef = 57B95BB31A7CCEE8004DFB22 /* MASShortcut.m */; }; + 57B95BBD1A7CCEE8004DFB22 /* MASShortcut+Monitoring.m in Sources */ = {isa = PBXBuildFile; fileRef = 57B95BB51A7CCEE8004DFB22 /* MASShortcut+Monitoring.m */; }; + 57B95BBE1A7CCEE8004DFB22 /* MASShortcut+UserDefaults.m in Sources */ = {isa = PBXBuildFile; fileRef = 57B95BB71A7CCEE8004DFB22 /* MASShortcut+UserDefaults.m */; }; + 57B95BBF1A7CCEE8004DFB22 /* MASShortcutView.m in Sources */ = {isa = PBXBuildFile; fileRef = 57B95BB91A7CCEE8004DFB22 /* MASShortcutView.m */; }; + 57B95BC01A7CCEE8004DFB22 /* MASShortcutView+UserDefaults.m in Sources */ = {isa = PBXBuildFile; fileRef = 57B95BBB1A7CCEE8004DFB22 /* MASShortcutView+UserDefaults.m */; }; + 57BB35161894D39B0094B553 /* DDSearchFieldController.m in Sources */ = {isa = PBXBuildFile; fileRef = 57BB35151894D39B0094B553 /* DDSearchFieldController.m */; }; + 57C0A8861A68B3B400ECDE45 /* AvatorImageView.m in Sources */ = {isa = PBXBuildFile; fileRef = 57C0A8851A68B3B400ECDE45 /* AvatorImageView.m */; }; + 57C0CE50183C7C320049DCE4 /* AIParagraphStyleAdditions.m in Sources */ = {isa = PBXBuildFile; fileRef = 57C0CE4F183C7C320049DCE4 /* AIParagraphStyleAdditions.m */; }; + 57C0CE56183C86B40049DCE4 /* AIWindowControllerAdditions.m in Sources */ = {isa = PBXBuildFile; fileRef = 57C0CE55183C86B40049DCE4 /* AIWindowControllerAdditions.m */; }; + 57C0CE5E183C98DE0049DCE4 /* DDMutableOwnerArray.m in Sources */ = {isa = PBXBuildFile; fileRef = 57C0CE5D183C98DE0049DCE4 /* DDMutableOwnerArray.m */; }; + 57C2D2EB1A74D3C500981552 /* DDAtUserListViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 57C2D2E91A74D3C500981552 /* DDAtUserListViewController.m */; }; + 57C2D2EC1A74D3C500981552 /* DDAtUserListViewController.xib in Resources */ = {isa = PBXBuildFile; fileRef = 57C2D2EA1A74D3C500981552 /* DDAtUserListViewController.xib */; }; + 57CA0F4D18D2D42D005C0B0D /* CrashReporter.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 57CA0F4C18D2D42D005C0B0D /* CrashReporter.framework */; settings = {ATTRIBUTES = (Weak, ); }; }; + 57CA0F4E18D2D43F005C0B0D /* CrashReporter.framework in Copy Files */ = {isa = PBXBuildFile; fileRef = 57CA0F4C18D2D42D005C0B0D /* CrashReporter.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, ); }; }; + 57D5D15F184C23AD00852738 /* DDChattingView.xib in Resources */ = {isa = PBXBuildFile; fileRef = 57D5D15D184C23AD00852738 /* DDChattingView.xib */; }; + 57D5D165184C76D900852738 /* DDSplitView.m in Sources */ = {isa = PBXBuildFile; fileRef = 57D5D164184C76D900852738 /* DDSplitView.m */; }; + 57D5D171184D770100852738 /* icon_screenshot_highlight.png in Resources */ = {isa = PBXBuildFile; fileRef = 57D5D169184D770100852738 /* icon_screenshot_highlight.png */; }; + 57D5D172184D770100852738 /* icon_screenshot_highlight@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = 57D5D16A184D770100852738 /* icon_screenshot_highlight@2x.png */; }; + 57D5D173184D770100852738 /* icon_screenshot.png in Resources */ = {isa = PBXBuildFile; fileRef = 57D5D16B184D770100852738 /* icon_screenshot.png */; }; + 57D5D174184D770100852738 /* icon_screenshot@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = 57D5D16C184D770100852738 /* icon_screenshot@2x.png */; }; + 57D5D175184D770100852738 /* icon_smile_highlight.png in Resources */ = {isa = PBXBuildFile; fileRef = 57D5D16D184D770100852738 /* icon_smile_highlight.png */; }; + 57D5D176184D770100852738 /* icon_smile_highlight@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = 57D5D16E184D770100852738 /* icon_smile_highlight@2x.png */; }; + 57D5D177184D770100852738 /* icon_smile.png in Resources */ = {isa = PBXBuildFile; fileRef = 57D5D16F184D770100852738 /* icon_smile.png */; }; + 57D5D178184D770100852738 /* icon_smile@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = 57D5D170184D770100852738 /* icon_smile@2x.png */; }; + 57D5D187184D840000852738 /* DDChattingInputView.m in Sources */ = {isa = PBXBuildFile; fileRef = 57D5D186184D840000852738 /* DDChattingInputView.m */; }; + 57D5D18E184EC85100852738 /* DDSendingTextView.m in Sources */ = {isa = PBXBuildFile; fileRef = 57D5D18D184EC85100852738 /* DDSendingTextView.m */; }; + 57DEB6921A7F833F00961C6F /* libsecurity.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 57DEB6901A7F75F500961C6F /* libsecurity.a */; }; + 57DEB6951A8222A800961C6F /* DDReceiveMsgDataReadNotifyAPI.m in Sources */ = {isa = PBXBuildFile; fileRef = 57DEB6941A8222A800961C6F /* DDReceiveMsgDataReadNotifyAPI.m */; }; + 57DF183B18DFD0E4003A19F6 /* libsqlite3.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = 57DF183A18DFD0E4003A19F6 /* libsqlite3.dylib */; }; + 57E18EAE186A857400D00D63 /* avatar_default.jpg_48x48.jpg in Resources */ = {isa = PBXBuildFile; fileRef = 57E18EAD186A857400D00D63 /* avatar_default.jpg_48x48.jpg */; }; + 57E1AA9F186AD9FF00D00D63 /* MainWindowSegmentedControl.m in Sources */ = {isa = PBXBuildFile; fileRef = 57E1AA9E186AD9FF00D00D63 /* MainWindowSegmentedControl.m */; }; + 57EFFADF1856C639006D8DE1 /* icon_unread_red_wide.png in Resources */ = {isa = PBXBuildFile; fileRef = 57EFFADB1856C639006D8DE1 /* icon_unread_red_wide.png */; }; + 57EFFAE01856C639006D8DE1 /* icon_unread_red_wide@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = 57EFFADC1856C639006D8DE1 /* icon_unread_red_wide@2x.png */; }; + 57EFFAE11856C639006D8DE1 /* icon_unread_red.png in Resources */ = {isa = PBXBuildFile; fileRef = 57EFFADD1856C639006D8DE1 /* icon_unread_red.png */; }; + 57EFFAE21856C639006D8DE1 /* icon_unread_red@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = 57EFFADE1856C639006D8DE1 /* icon_unread_red@2x.png */; }; + 57EFFB2818570324006D8DE1 /* icon_image_normal.png in Resources */ = {isa = PBXBuildFile; fileRef = 57EFFB2618570324006D8DE1 /* icon_image_normal.png */; }; + 57EFFB2918570324006D8DE1 /* icon_image_normal@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = 57EFFB2718570324006D8DE1 /* icon_image_normal@2x.png */; }; + 57EFFB2B18580FC2006D8DE1 /* libz.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = 57EFFB2A18580FC2006D8DE1 /* libz.dylib */; }; + 57F50075182F92080090115B /* DDHttpUtil.m in Sources */ = {isa = PBXBuildFile; fileRef = 57F50074182F92080090115B /* DDHttpUtil.m */; }; + 57F50078182F93D90090115B /* MD5.m in Sources */ = {isa = PBXBuildFile; fileRef = 57F50077182F93D90090115B /* MD5.m */; }; + 5E8EB9DD1934713A008B1890 /* ImageIO.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 5E8EB9DC1934713A008B1890 /* ImageIO.framework */; }; + 5EF517CC1923070400652421 /* 221.gif in Resources */ = {isa = PBXBuildFile; fileRef = 5EF517B81923070400652421 /* 221.gif */; }; + 5EF517CD1923070400652421 /* 222.gif in Resources */ = {isa = PBXBuildFile; fileRef = 5EF517B91923070400652421 /* 222.gif */; }; + 5EF517CE1923070400652421 /* 223.gif in Resources */ = {isa = PBXBuildFile; fileRef = 5EF517BA1923070400652421 /* 223.gif */; }; + 5EF517CF1923070400652421 /* 224.gif in Resources */ = {isa = PBXBuildFile; fileRef = 5EF517BB1923070400652421 /* 224.gif */; }; + 5EF517D01923070400652421 /* 225.gif in Resources */ = {isa = PBXBuildFile; fileRef = 5EF517BC1923070400652421 /* 225.gif */; }; + 5EF517D11923070400652421 /* 226.gif in Resources */ = {isa = PBXBuildFile; fileRef = 5EF517BD1923070400652421 /* 226.gif */; }; + 5EF517D21923070400652421 /* 227.gif in Resources */ = {isa = PBXBuildFile; fileRef = 5EF517BE1923070400652421 /* 227.gif */; }; + 5EF517D31923070400652421 /* 228.gif in Resources */ = {isa = PBXBuildFile; fileRef = 5EF517BF1923070400652421 /* 228.gif */; }; + 5EF517D41923070400652421 /* 229.gif in Resources */ = {isa = PBXBuildFile; fileRef = 5EF517C01923070400652421 /* 229.gif */; }; + 5EF517D51923070400652421 /* 230.gif in Resources */ = {isa = PBXBuildFile; fileRef = 5EF517C11923070400652421 /* 230.gif */; }; + 5EF517D61923070400652421 /* 231.gif in Resources */ = {isa = PBXBuildFile; fileRef = 5EF517C21923070400652421 /* 231.gif */; }; + 5EF517D71923070400652421 /* 232.gif in Resources */ = {isa = PBXBuildFile; fileRef = 5EF517C31923070400652421 /* 232.gif */; }; + 5EF517D81923070400652421 /* 233.gif in Resources */ = {isa = PBXBuildFile; fileRef = 5EF517C41923070400652421 /* 233.gif */; }; + 5EF517D91923070400652421 /* 234.gif in Resources */ = {isa = PBXBuildFile; fileRef = 5EF517C51923070400652421 /* 234.gif */; }; + 5EF517DA1923070400652421 /* 235.gif in Resources */ = {isa = PBXBuildFile; fileRef = 5EF517C61923070400652421 /* 235.gif */; }; + 5EF517DB1923070400652421 /* 236.gif in Resources */ = {isa = PBXBuildFile; fileRef = 5EF517C71923070400652421 /* 236.gif */; }; + 5EF517DC1923070400652421 /* 237.gif in Resources */ = {isa = PBXBuildFile; fileRef = 5EF517C81923070400652421 /* 237.gif */; }; + 5EF517DD1923070400652421 /* 238.gif in Resources */ = {isa = PBXBuildFile; fileRef = 5EF517C91923070400652421 /* 238.gif */; }; + 5EF517DE1923070400652421 /* 239.gif in Resources */ = {isa = PBXBuildFile; fileRef = 5EF517CA1923070400652421 /* 239.gif */; }; + 5EF517DF1923070400652421 /* 240.gif in Resources */ = {isa = PBXBuildFile; fileRef = 5EF517CB1923070400652421 /* 240.gif */; }; + 5EF517E519235FBA00652421 /* DDChattingMyLine.m in Sources */ = {isa = PBXBuildFile; fileRef = 5EF517E419235FBA00652421 /* DDChattingMyLine.m */; }; + 5EF517E819236EA600652421 /* input-background.png in Resources */ = {isa = PBXBuildFile; fileRef = 5EF517E619236EA600652421 /* input-background.png */; }; + 5EF517E919236EA600652421 /* input-background@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = 5EF517E719236EA600652421 /* input-background@2x.png */; }; + 5EF517EC19238C7B00652421 /* shake-window.png in Resources */ = {isa = PBXBuildFile; fileRef = 5EF517EA19238C7B00652421 /* shake-window.png */; }; + 5EF517ED19238C7B00652421 /* shake-window@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = 5EF517EB19238C7B00652421 /* shake-window@2x.png */; }; + 6D1CC79818A62FF0002CAE5F /* L4AppenderAttachable.m in Sources */ = {isa = PBXBuildFile; fileRef = 6D1CC75A18A62FF0002CAE5F /* L4AppenderAttachable.m */; }; + 6D1CC79918A62FF0002CAE5F /* L4AppenderSkeleton.m in Sources */ = {isa = PBXBuildFile; fileRef = 6D1CC75D18A62FF0002CAE5F /* L4AppenderSkeleton.m */; }; + 6D1CC79A18A62FF0002CAE5F /* L4BasicConfigurator.m in Sources */ = {isa = PBXBuildFile; fileRef = 6D1CC75F18A62FF0002CAE5F /* L4BasicConfigurator.m */; }; + 6D1CC79B18A62FF0002CAE5F /* L4ConsoleAppender.m in Sources */ = {isa = PBXBuildFile; fileRef = 6D1CC76118A62FF0002CAE5F /* L4ConsoleAppender.m */; }; + 6D1CC79C18A62FF0002CAE5F /* L4DailyRollingFileAppender.m in Sources */ = {isa = PBXBuildFile; fileRef = 6D1CC76318A62FF0002CAE5F /* L4DailyRollingFileAppender.m */; }; + 6D1CC79D18A62FF0002CAE5F /* L4DenyAllFilter.m in Sources */ = {isa = PBXBuildFile; fileRef = 6D1CC76518A62FF0002CAE5F /* L4DenyAllFilter.m */; }; + 6D1CC79E18A62FF0002CAE5F /* L4FileAppender.m in Sources */ = {isa = PBXBuildFile; fileRef = 6D1CC76718A62FF0002CAE5F /* L4FileAppender.m */; }; + 6D1CC79F18A62FF0002CAE5F /* L4Filter.m in Sources */ = {isa = PBXBuildFile; fileRef = 6D1CC76918A62FF0002CAE5F /* L4Filter.m */; }; + 6D1CC7A018A62FF0002CAE5F /* L4JSONLayout.m in Sources */ = {isa = PBXBuildFile; fileRef = 6D1CC76B18A62FF0002CAE5F /* L4JSONLayout.m */; }; + 6D1CC7A118A62FF0002CAE5F /* L4Layout.m in Sources */ = {isa = PBXBuildFile; fileRef = 6D1CC76D18A62FF0002CAE5F /* L4Layout.m */; }; + 6D1CC7A218A62FF0002CAE5F /* L4Level.m in Sources */ = {isa = PBXBuildFile; fileRef = 6D1CC76F18A62FF0002CAE5F /* L4Level.m */; }; + 6D1CC7A318A62FF0002CAE5F /* L4LevelMatchFilter.m in Sources */ = {isa = PBXBuildFile; fileRef = 6D1CC77118A62FF0002CAE5F /* L4LevelMatchFilter.m */; }; + 6D1CC7A418A62FF0002CAE5F /* L4LevelRangeFilter.m in Sources */ = {isa = PBXBuildFile; fileRef = 6D1CC77318A62FF0002CAE5F /* L4LevelRangeFilter.m */; }; + 6D1CC7A518A62FF0002CAE5F /* L4LogEvent.m in Sources */ = {isa = PBXBuildFile; fileRef = 6D1CC77518A62FF0002CAE5F /* L4LogEvent.m */; }; + 6D1CC7A618A62FF0002CAE5F /* L4Logger.m in Sources */ = {isa = PBXBuildFile; fileRef = 6D1CC77718A62FF0002CAE5F /* L4Logger.m */; }; + 6D1CC7A718A62FF0002CAE5F /* L4LoggerNameMatchFilter.m in Sources */ = {isa = PBXBuildFile; fileRef = 6D1CC77918A62FF0002CAE5F /* L4LoggerNameMatchFilter.m */; }; + 6D1CC7A818A62FF0002CAE5F /* L4LoggerStore.m in Sources */ = {isa = PBXBuildFile; fileRef = 6D1CC77C18A62FF0002CAE5F /* L4LoggerStore.m */; }; + 6D1CC7A918A62FF0002CAE5F /* L4Logging.m in Sources */ = {isa = PBXBuildFile; fileRef = 6D1CC77E18A62FF0002CAE5F /* L4Logging.m */; }; + 6D1CC7AA18A62FF0002CAE5F /* L4LogLog.m in Sources */ = {isa = PBXBuildFile; fileRef = 6D1CC78018A62FF0002CAE5F /* L4LogLog.m */; }; + 6D1CC7AB18A62FF0002CAE5F /* L4PatternLayout.m in Sources */ = {isa = PBXBuildFile; fileRef = 6D1CC78218A62FF0002CAE5F /* L4PatternLayout.m */; }; + 6D1CC7AC18A62FF0002CAE5F /* L4Properties.m in Sources */ = {isa = PBXBuildFile; fileRef = 6D1CC78418A62FF0002CAE5F /* L4Properties.m */; }; + 6D1CC7AD18A62FF0002CAE5F /* L4PropertyConfigurator.m in Sources */ = {isa = PBXBuildFile; fileRef = 6D1CC78618A62FF0002CAE5F /* L4PropertyConfigurator.m */; }; + 6D1CC7AE18A62FF0002CAE5F /* L4RollingFileAppender.m in Sources */ = {isa = PBXBuildFile; fileRef = 6D1CC78818A62FF0002CAE5F /* L4RollingFileAppender.m */; }; + 6D1CC7AF18A62FF0002CAE5F /* L4RootLogger.m in Sources */ = {isa = PBXBuildFile; fileRef = 6D1CC78A18A62FF0002CAE5F /* L4RootLogger.m */; }; + 6D1CC7B018A62FF0002CAE5F /* L4SimpleLayout.m in Sources */ = {isa = PBXBuildFile; fileRef = 6D1CC78C18A62FF0002CAE5F /* L4SimpleLayout.m */; }; + 6D1CC7B118A62FF0002CAE5F /* L4StringMatchFilter.m in Sources */ = {isa = PBXBuildFile; fileRef = 6D1CC78E18A62FF0002CAE5F /* L4StringMatchFilter.m */; }; + 6D1CC7B218A62FF0002CAE5F /* L4WriterAppender.m in Sources */ = {isa = PBXBuildFile; fileRef = 6D1CC79018A62FF0002CAE5F /* L4WriterAppender.m */; }; + 6D1CC7B318A62FF0002CAE5F /* L4XMLLayout.m in Sources */ = {isa = PBXBuildFile; fileRef = 6D1CC79218A62FF0002CAE5F /* L4XMLLayout.m */; }; + 6D1CC7B418A62FF0002CAE5F /* NSObject+Log4Cocoa.m in Sources */ = {isa = PBXBuildFile; fileRef = 6D1CC79718A62FF0002CAE5F /* NSObject+Log4Cocoa.m */; }; + 6D2A847E18B1D5E20004032B /* DDLoginWindow.m in Sources */ = {isa = PBXBuildFile; fileRef = 6D2A847D18B1D5E20004032B /* DDLoginWindow.m */; }; + 6D2A848118B1D9140004032B /* icon_go.png in Resources */ = {isa = PBXBuildFile; fileRef = 6D2A847F18B1D9140004032B /* icon_go.png */; }; + 6D2A848218B1D9140004032B /* icon_go@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = 6D2A848018B1D9140004032B /* icon_go@2x.png */; }; + 6D70EA351869ADAE00402CF5 /* bubble_left.png in Resources */ = {isa = PBXBuildFile; fileRef = 6D70EA311869ADAE00402CF5 /* bubble_left.png */; }; + 6D70EA361869ADAE00402CF5 /* bubble_left@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = 6D70EA321869ADAE00402CF5 /* bubble_left@2x.png */; }; + 6D70EA371869ADAE00402CF5 /* bubble_right.png in Resources */ = {isa = PBXBuildFile; fileRef = 6D70EA331869ADAE00402CF5 /* bubble_right.png */; }; + 6D70EA381869ADAE00402CF5 /* bubble_right@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = 6D70EA341869ADAE00402CF5 /* bubble_right@2x.png */; }; + 6D70EA94186C43C000402CF5 /* NSImage+Stretchable.m in Sources */ = {isa = PBXBuildFile; fileRef = 6D70EA93186C43C000402CF5 /* NSImage+Stretchable.m */; }; + 6D74358F18E26A02008ED227 /* BackgroudView.m in Sources */ = {isa = PBXBuildFile; fileRef = 6D74358E18E26A02008ED227 /* BackgroudView.m */; }; + 6D78A57E18D828450069A29B /* ScreenCapture_toolbar_ellipse.png in Resources */ = {isa = PBXBuildFile; fileRef = 6D78A57A18D828450069A29B /* ScreenCapture_toolbar_ellipse.png */; }; + 6D78A57F18D828450069A29B /* ScreenCapture_toolbar_ellipse@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = 6D78A57B18D828450069A29B /* ScreenCapture_toolbar_ellipse@2x.png */; }; + 6D78A58018D828450069A29B /* ScreenCapture_toolbar_rect.png in Resources */ = {isa = PBXBuildFile; fileRef = 6D78A57C18D828450069A29B /* ScreenCapture_toolbar_rect.png */; }; + 6D78A58118D828450069A29B /* ScreenCapture_toolbar_rect@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = 6D78A57D18D828450069A29B /* ScreenCapture_toolbar_rect@2x.png */; }; + 6D8B6AE418C462EE0081DAA2 /* filetransfer_offline.png in Resources */ = {isa = PBXBuildFile; fileRef = 6D8B6AE218C462EE0081DAA2 /* filetransfer_offline.png */; }; + 6D8B6AE518C462EE0081DAA2 /* filetransfer_offline@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = 6D8B6AE318C462EE0081DAA2 /* filetransfer_offline@2x.png */; }; + 6DCB32DA189201FF00FC86A3 /* DDApplication.m in Sources */ = {isa = PBXBuildFile; fileRef = 6DCB32D9189201FF00FC86A3 /* DDApplication.m */; }; + 6DCB338C189629F200FC86A3 /* filetransfer_avatar_receive.png in Resources */ = {isa = PBXBuildFile; fileRef = 6DCB3380189629F200FC86A3 /* filetransfer_avatar_receive.png */; }; + 6DCB338D189629F200FC86A3 /* filetransfer_avatar_receive@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = 6DCB3381189629F200FC86A3 /* filetransfer_avatar_receive@2x.png */; }; + 6DCB338E189629F200FC86A3 /* filetransfer_avatar_send.png in Resources */ = {isa = PBXBuildFile; fileRef = 6DCB3382189629F200FC86A3 /* filetransfer_avatar_send.png */; }; + 6DCB338F189629F200FC86A3 /* filetransfer_avatar_send@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = 6DCB3383189629F200FC86A3 /* filetransfer_avatar_send@2x.png */; }; + 6DCB3390189629F200FC86A3 /* filetransfer_close.png in Resources */ = {isa = PBXBuildFile; fileRef = 6DCB3384189629F200FC86A3 /* filetransfer_close.png */; }; + 6DCB3391189629F200FC86A3 /* filetransfer_close@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = 6DCB3385189629F200FC86A3 /* filetransfer_close@2x.png */; }; + 6DCB3392189629F200FC86A3 /* filetransfer_receiver.png in Resources */ = {isa = PBXBuildFile; fileRef = 6DCB3386189629F200FC86A3 /* filetransfer_receiver.png */; }; + 6DCB3393189629F200FC86A3 /* filetransfer_receiver@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = 6DCB3387189629F200FC86A3 /* filetransfer_receiver@2x.png */; }; + 6DCB3394189629F200FC86A3 /* filetransfer_refuse.png in Resources */ = {isa = PBXBuildFile; fileRef = 6DCB3388189629F200FC86A3 /* filetransfer_refuse.png */; }; + 6DCB3395189629F200FC86A3 /* filetransfer_refuse@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = 6DCB3389189629F200FC86A3 /* filetransfer_refuse@2x.png */; }; + 6DCB3396189629F200FC86A3 /* filetransfer_search.png in Resources */ = {isa = PBXBuildFile; fileRef = 6DCB338A189629F200FC86A3 /* filetransfer_search.png */; }; + 6DCB3397189629F200FC86A3 /* filetransfer_search@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = 6DCB338B189629F200FC86A3 /* filetransfer_search@2x.png */; }; + 6DD31979188E3C5200ED5FE8 /* EmotionViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 6DD31978188E3C5200ED5FE8 /* EmotionViewController.m */; }; + 6DD3197C188E3C8B00ED5FE8 /* EmotionCellView.m in Sources */ = {isa = PBXBuildFile; fileRef = 6DD3197B188E3C8B00ED5FE8 /* EmotionCellView.m */; }; + 6DD3197E188E3CD800ED5FE8 /* EmotionPopover.xib in Resources */ = {isa = PBXBuildFile; fileRef = 6DD3197D188E3CD800ED5FE8 /* EmotionPopover.xib */; }; + 6DD31A5D188E592200ED5FE8 /* 0.gif in Resources */ = {isa = PBXBuildFile; fileRef = 6DD31980188E592100ED5FE8 /* 0.gif */; }; + 6DD31A5E188E592200ED5FE8 /* 1.gif in Resources */ = {isa = PBXBuildFile; fileRef = 6DD31981188E592100ED5FE8 /* 1.gif */; }; + 6DD31A5F188E592200ED5FE8 /* 2.gif in Resources */ = {isa = PBXBuildFile; fileRef = 6DD31982188E592100ED5FE8 /* 2.gif */; }; + 6DD31A60188E592200ED5FE8 /* 3.gif in Resources */ = {isa = PBXBuildFile; fileRef = 6DD31983188E592100ED5FE8 /* 3.gif */; }; + 6DD31A61188E592200ED5FE8 /* 4.gif in Resources */ = {isa = PBXBuildFile; fileRef = 6DD31984188E592100ED5FE8 /* 4.gif */; }; + 6DD31A62188E592200ED5FE8 /* 5.gif in Resources */ = {isa = PBXBuildFile; fileRef = 6DD31985188E592100ED5FE8 /* 5.gif */; }; + 6DD31A63188E592200ED5FE8 /* 6.gif in Resources */ = {isa = PBXBuildFile; fileRef = 6DD31986188E592100ED5FE8 /* 6.gif */; }; + 6DD31A64188E592200ED5FE8 /* 7.gif in Resources */ = {isa = PBXBuildFile; fileRef = 6DD31987188E592100ED5FE8 /* 7.gif */; }; + 6DD31A65188E592200ED5FE8 /* 8.gif in Resources */ = {isa = PBXBuildFile; fileRef = 6DD31988188E592100ED5FE8 /* 8.gif */; }; + 6DD31A66188E592200ED5FE8 /* 9.gif in Resources */ = {isa = PBXBuildFile; fileRef = 6DD31989188E592100ED5FE8 /* 9.gif */; }; + 6DD31A67188E592200ED5FE8 /* 10.gif in Resources */ = {isa = PBXBuildFile; fileRef = 6DD3198A188E592100ED5FE8 /* 10.gif */; }; + 6DD31A68188E592200ED5FE8 /* 11.gif in Resources */ = {isa = PBXBuildFile; fileRef = 6DD3198B188E592100ED5FE8 /* 11.gif */; }; + 6DD31A69188E592200ED5FE8 /* 12.gif in Resources */ = {isa = PBXBuildFile; fileRef = 6DD3198C188E592100ED5FE8 /* 12.gif */; }; + 6DD31A6A188E592200ED5FE8 /* 13.gif in Resources */ = {isa = PBXBuildFile; fileRef = 6DD3198D188E592100ED5FE8 /* 13.gif */; }; + 6DD31A6B188E592200ED5FE8 /* 14.gif in Resources */ = {isa = PBXBuildFile; fileRef = 6DD3198E188E592100ED5FE8 /* 14.gif */; }; + 6DD31A6C188E592200ED5FE8 /* 15.gif in Resources */ = {isa = PBXBuildFile; fileRef = 6DD3198F188E592100ED5FE8 /* 15.gif */; }; + 6DD31A6D188E592200ED5FE8 /* 16.gif in Resources */ = {isa = PBXBuildFile; fileRef = 6DD31990188E592100ED5FE8 /* 16.gif */; }; + 6DD31A6E188E592200ED5FE8 /* 17.gif in Resources */ = {isa = PBXBuildFile; fileRef = 6DD31991188E592100ED5FE8 /* 17.gif */; }; + 6DD31A6F188E592200ED5FE8 /* 18.gif in Resources */ = {isa = PBXBuildFile; fileRef = 6DD31992188E592100ED5FE8 /* 18.gif */; }; + 6DD31A70188E592200ED5FE8 /* 19.gif in Resources */ = {isa = PBXBuildFile; fileRef = 6DD31993188E592100ED5FE8 /* 19.gif */; }; + 6DD31A71188E592200ED5FE8 /* 20.gif in Resources */ = {isa = PBXBuildFile; fileRef = 6DD31994188E592100ED5FE8 /* 20.gif */; }; + 6DD31A72188E592200ED5FE8 /* 21.gif in Resources */ = {isa = PBXBuildFile; fileRef = 6DD31995188E592100ED5FE8 /* 21.gif */; }; + 6DD31A73188E592200ED5FE8 /* 22.gif in Resources */ = {isa = PBXBuildFile; fileRef = 6DD31996188E592100ED5FE8 /* 22.gif */; }; + 6DD31A74188E592200ED5FE8 /* 23.gif in Resources */ = {isa = PBXBuildFile; fileRef = 6DD31997188E592100ED5FE8 /* 23.gif */; }; + 6DD31A75188E592200ED5FE8 /* 24.gif in Resources */ = {isa = PBXBuildFile; fileRef = 6DD31998188E592100ED5FE8 /* 24.gif */; }; + 6DD31A76188E592200ED5FE8 /* 25.gif in Resources */ = {isa = PBXBuildFile; fileRef = 6DD31999188E592100ED5FE8 /* 25.gif */; }; + 6DD31A77188E592200ED5FE8 /* 26.gif in Resources */ = {isa = PBXBuildFile; fileRef = 6DD3199A188E592100ED5FE8 /* 26.gif */; }; + 6DD31A78188E592200ED5FE8 /* 27.gif in Resources */ = {isa = PBXBuildFile; fileRef = 6DD3199B188E592100ED5FE8 /* 27.gif */; }; + 6DD31A79188E592200ED5FE8 /* 28.gif in Resources */ = {isa = PBXBuildFile; fileRef = 6DD3199C188E592100ED5FE8 /* 28.gif */; }; + 6DD31A7A188E592200ED5FE8 /* 29.gif in Resources */ = {isa = PBXBuildFile; fileRef = 6DD3199D188E592100ED5FE8 /* 29.gif */; }; + 6DD31A7B188E592200ED5FE8 /* 30.gif in Resources */ = {isa = PBXBuildFile; fileRef = 6DD3199E188E592100ED5FE8 /* 30.gif */; }; + 6DD31A7C188E592200ED5FE8 /* 31.gif in Resources */ = {isa = PBXBuildFile; fileRef = 6DD3199F188E592100ED5FE8 /* 31.gif */; }; + 6DD31A7D188E592200ED5FE8 /* 32.gif in Resources */ = {isa = PBXBuildFile; fileRef = 6DD319A0188E592100ED5FE8 /* 32.gif */; }; + 6DD31A7E188E592200ED5FE8 /* 33.gif in Resources */ = {isa = PBXBuildFile; fileRef = 6DD319A1188E592100ED5FE8 /* 33.gif */; }; + 6DD31A7F188E592200ED5FE8 /* 34.gif in Resources */ = {isa = PBXBuildFile; fileRef = 6DD319A2188E592100ED5FE8 /* 34.gif */; }; + 6DD31A80188E592200ED5FE8 /* 35.gif in Resources */ = {isa = PBXBuildFile; fileRef = 6DD319A3188E592100ED5FE8 /* 35.gif */; }; + 6DD31A81188E592200ED5FE8 /* 36.gif in Resources */ = {isa = PBXBuildFile; fileRef = 6DD319A4188E592100ED5FE8 /* 36.gif */; }; + 6DD31A82188E592200ED5FE8 /* 37.gif in Resources */ = {isa = PBXBuildFile; fileRef = 6DD319A5188E592100ED5FE8 /* 37.gif */; }; + 6DD31A83188E592200ED5FE8 /* 38.gif in Resources */ = {isa = PBXBuildFile; fileRef = 6DD319A6188E592100ED5FE8 /* 38.gif */; }; + 6DD31A84188E592200ED5FE8 /* 39.gif in Resources */ = {isa = PBXBuildFile; fileRef = 6DD319A7188E592100ED5FE8 /* 39.gif */; }; + 6DD31A85188E592200ED5FE8 /* 40.gif in Resources */ = {isa = PBXBuildFile; fileRef = 6DD319A8188E592100ED5FE8 /* 40.gif */; }; + 6DD31A86188E592200ED5FE8 /* 41.gif in Resources */ = {isa = PBXBuildFile; fileRef = 6DD319A9188E592100ED5FE8 /* 41.gif */; }; + 6DD31A87188E592200ED5FE8 /* 42.gif in Resources */ = {isa = PBXBuildFile; fileRef = 6DD319AA188E592100ED5FE8 /* 42.gif */; }; + 6DD31A88188E592200ED5FE8 /* 43.gif in Resources */ = {isa = PBXBuildFile; fileRef = 6DD319AB188E592100ED5FE8 /* 43.gif */; }; + 6DD31A89188E592200ED5FE8 /* 44.gif in Resources */ = {isa = PBXBuildFile; fileRef = 6DD319AC188E592100ED5FE8 /* 44.gif */; }; + 6DD31A8A188E592200ED5FE8 /* 45.gif in Resources */ = {isa = PBXBuildFile; fileRef = 6DD319AD188E592100ED5FE8 /* 45.gif */; }; + 6DD31A8B188E592200ED5FE8 /* 46.gif in Resources */ = {isa = PBXBuildFile; fileRef = 6DD319AE188E592100ED5FE8 /* 46.gif */; }; + 6DD31A8C188E592200ED5FE8 /* 47.gif in Resources */ = {isa = PBXBuildFile; fileRef = 6DD319AF188E592100ED5FE8 /* 47.gif */; }; + 6DD31A8D188E592200ED5FE8 /* 48.gif in Resources */ = {isa = PBXBuildFile; fileRef = 6DD319B0188E592100ED5FE8 /* 48.gif */; }; + 6DD31A8E188E592200ED5FE8 /* 49.gif in Resources */ = {isa = PBXBuildFile; fileRef = 6DD319B1188E592100ED5FE8 /* 49.gif */; }; + 6DD31A8F188E592200ED5FE8 /* 50.gif in Resources */ = {isa = PBXBuildFile; fileRef = 6DD319B2188E592100ED5FE8 /* 50.gif */; }; + 6DD31A90188E592200ED5FE8 /* 51.gif in Resources */ = {isa = PBXBuildFile; fileRef = 6DD319B3188E592100ED5FE8 /* 51.gif */; }; + 6DD31A91188E592200ED5FE8 /* 52.gif in Resources */ = {isa = PBXBuildFile; fileRef = 6DD319B4188E592100ED5FE8 /* 52.gif */; }; + 6DD31A92188E592200ED5FE8 /* 53.gif in Resources */ = {isa = PBXBuildFile; fileRef = 6DD319B5188E592100ED5FE8 /* 53.gif */; }; + 6DD31A93188E592200ED5FE8 /* 54.gif in Resources */ = {isa = PBXBuildFile; fileRef = 6DD319B6188E592100ED5FE8 /* 54.gif */; }; + 6DD31A94188E592200ED5FE8 /* 55.gif in Resources */ = {isa = PBXBuildFile; fileRef = 6DD319B7188E592100ED5FE8 /* 55.gif */; }; + 6DD31A95188E592200ED5FE8 /* 56.gif in Resources */ = {isa = PBXBuildFile; fileRef = 6DD319B8188E592100ED5FE8 /* 56.gif */; }; + 6DD31A96188E592200ED5FE8 /* 57.gif in Resources */ = {isa = PBXBuildFile; fileRef = 6DD319B9188E592100ED5FE8 /* 57.gif */; }; + 6DD31A97188E592200ED5FE8 /* 58.gif in Resources */ = {isa = PBXBuildFile; fileRef = 6DD319BA188E592100ED5FE8 /* 58.gif */; }; + 6DD31A98188E592200ED5FE8 /* 59.gif in Resources */ = {isa = PBXBuildFile; fileRef = 6DD319BB188E592100ED5FE8 /* 59.gif */; }; + 6DD31A99188E592200ED5FE8 /* 60.gif in Resources */ = {isa = PBXBuildFile; fileRef = 6DD319BC188E592100ED5FE8 /* 60.gif */; }; + 6DD31A9A188E592200ED5FE8 /* 61.gif in Resources */ = {isa = PBXBuildFile; fileRef = 6DD319BD188E592100ED5FE8 /* 61.gif */; }; + 6DD31A9B188E592200ED5FE8 /* 62.gif in Resources */ = {isa = PBXBuildFile; fileRef = 6DD319BE188E592100ED5FE8 /* 62.gif */; }; + 6DD31A9C188E592200ED5FE8 /* 63.gif in Resources */ = {isa = PBXBuildFile; fileRef = 6DD319BF188E592100ED5FE8 /* 63.gif */; }; + 6DD31A9D188E592200ED5FE8 /* 64.gif in Resources */ = {isa = PBXBuildFile; fileRef = 6DD319C0188E592100ED5FE8 /* 64.gif */; }; + 6DD31A9E188E592200ED5FE8 /* 65.gif in Resources */ = {isa = PBXBuildFile; fileRef = 6DD319C1188E592100ED5FE8 /* 65.gif */; }; + 6DD31A9F188E592200ED5FE8 /* 66.gif in Resources */ = {isa = PBXBuildFile; fileRef = 6DD319C2188E592100ED5FE8 /* 66.gif */; }; + 6DD31AA0188E592200ED5FE8 /* 67.gif in Resources */ = {isa = PBXBuildFile; fileRef = 6DD319C3188E592100ED5FE8 /* 67.gif */; }; + 6DD31AA1188E592200ED5FE8 /* 68.gif in Resources */ = {isa = PBXBuildFile; fileRef = 6DD319C4188E592100ED5FE8 /* 68.gif */; }; + 6DD31AA2188E592200ED5FE8 /* 69.gif in Resources */ = {isa = PBXBuildFile; fileRef = 6DD319C5188E592100ED5FE8 /* 69.gif */; }; + 6DD31AA3188E592200ED5FE8 /* 70.gif in Resources */ = {isa = PBXBuildFile; fileRef = 6DD319C6188E592100ED5FE8 /* 70.gif */; }; + 6DD31AA4188E592200ED5FE8 /* 71.gif in Resources */ = {isa = PBXBuildFile; fileRef = 6DD319C7188E592100ED5FE8 /* 71.gif */; }; + 6DD31AA5188E592200ED5FE8 /* 72.gif in Resources */ = {isa = PBXBuildFile; fileRef = 6DD319C8188E592100ED5FE8 /* 72.gif */; }; + 6DD31AA6188E592200ED5FE8 /* 73.gif in Resources */ = {isa = PBXBuildFile; fileRef = 6DD319C9188E592100ED5FE8 /* 73.gif */; }; + 6DD31AA7188E592200ED5FE8 /* 74.gif in Resources */ = {isa = PBXBuildFile; fileRef = 6DD319CA188E592100ED5FE8 /* 74.gif */; }; + 6DD31AA8188E592200ED5FE8 /* 75.gif in Resources */ = {isa = PBXBuildFile; fileRef = 6DD319CB188E592100ED5FE8 /* 75.gif */; }; + 6DD31AA9188E592200ED5FE8 /* 76.gif in Resources */ = {isa = PBXBuildFile; fileRef = 6DD319CC188E592100ED5FE8 /* 76.gif */; }; + 6DD31AAA188E592200ED5FE8 /* 77.gif in Resources */ = {isa = PBXBuildFile; fileRef = 6DD319CD188E592100ED5FE8 /* 77.gif */; }; + 6DD31AAB188E592200ED5FE8 /* 78.gif in Resources */ = {isa = PBXBuildFile; fileRef = 6DD319CE188E592100ED5FE8 /* 78.gif */; }; + 6DD31AAC188E592200ED5FE8 /* 79.gif in Resources */ = {isa = PBXBuildFile; fileRef = 6DD319CF188E592100ED5FE8 /* 79.gif */; }; + 6DD31AAD188E592200ED5FE8 /* 80.gif in Resources */ = {isa = PBXBuildFile; fileRef = 6DD319D0188E592100ED5FE8 /* 80.gif */; }; + 6DD31AAE188E592200ED5FE8 /* 81.gif in Resources */ = {isa = PBXBuildFile; fileRef = 6DD319D1188E592100ED5FE8 /* 81.gif */; }; + 6DD31AAF188E592200ED5FE8 /* 82.gif in Resources */ = {isa = PBXBuildFile; fileRef = 6DD319D2188E592100ED5FE8 /* 82.gif */; }; + 6DD31AB0188E592200ED5FE8 /* 83.gif in Resources */ = {isa = PBXBuildFile; fileRef = 6DD319D3188E592100ED5FE8 /* 83.gif */; }; + 6DD31AB1188E592200ED5FE8 /* 84.gif in Resources */ = {isa = PBXBuildFile; fileRef = 6DD319D4188E592100ED5FE8 /* 84.gif */; }; + 6DD31AB2188E592200ED5FE8 /* 85.gif in Resources */ = {isa = PBXBuildFile; fileRef = 6DD319D5188E592100ED5FE8 /* 85.gif */; }; + 6DD31AB3188E592200ED5FE8 /* 86.gif in Resources */ = {isa = PBXBuildFile; fileRef = 6DD319D6188E592100ED5FE8 /* 86.gif */; }; + 6DD31AB4188E592200ED5FE8 /* 87.gif in Resources */ = {isa = PBXBuildFile; fileRef = 6DD319D7188E592100ED5FE8 /* 87.gif */; }; + 6DD31AB5188E592200ED5FE8 /* 88.gif in Resources */ = {isa = PBXBuildFile; fileRef = 6DD319D8188E592100ED5FE8 /* 88.gif */; }; + 6DD31AB6188E592200ED5FE8 /* 89.gif in Resources */ = {isa = PBXBuildFile; fileRef = 6DD319D9188E592100ED5FE8 /* 89.gif */; }; + 6DD31AB7188E592200ED5FE8 /* 90.gif in Resources */ = {isa = PBXBuildFile; fileRef = 6DD319DA188E592100ED5FE8 /* 90.gif */; }; + 6DD31AB8188E592200ED5FE8 /* 91.gif in Resources */ = {isa = PBXBuildFile; fileRef = 6DD319DB188E592100ED5FE8 /* 91.gif */; }; + 6DD31AB9188E592200ED5FE8 /* 92.gif in Resources */ = {isa = PBXBuildFile; fileRef = 6DD319DC188E592100ED5FE8 /* 92.gif */; }; + 6DD31ABA188E592200ED5FE8 /* 93.gif in Resources */ = {isa = PBXBuildFile; fileRef = 6DD319DD188E592100ED5FE8 /* 93.gif */; }; + 6DD31ABB188E592200ED5FE8 /* 94.gif in Resources */ = {isa = PBXBuildFile; fileRef = 6DD319DE188E592100ED5FE8 /* 94.gif */; }; + 6DD31ABC188E592200ED5FE8 /* 95.gif in Resources */ = {isa = PBXBuildFile; fileRef = 6DD319DF188E592100ED5FE8 /* 95.gif */; }; + 6DD31ABD188E592200ED5FE8 /* 96.gif in Resources */ = {isa = PBXBuildFile; fileRef = 6DD319E0188E592100ED5FE8 /* 96.gif */; }; + 6DD31ABE188E592200ED5FE8 /* 97.gif in Resources */ = {isa = PBXBuildFile; fileRef = 6DD319E1188E592100ED5FE8 /* 97.gif */; }; + 6DD31ABF188E592200ED5FE8 /* 98.gif in Resources */ = {isa = PBXBuildFile; fileRef = 6DD319E2188E592100ED5FE8 /* 98.gif */; }; + 6DD31AC0188E592200ED5FE8 /* 99.gif in Resources */ = {isa = PBXBuildFile; fileRef = 6DD319E3188E592100ED5FE8 /* 99.gif */; }; + 6DD31AC1188E592200ED5FE8 /* 100.gif in Resources */ = {isa = PBXBuildFile; fileRef = 6DD319E4188E592100ED5FE8 /* 100.gif */; }; + 6DD31AC2188E592200ED5FE8 /* 101.gif in Resources */ = {isa = PBXBuildFile; fileRef = 6DD319E5188E592100ED5FE8 /* 101.gif */; }; + 6DD31AC3188E592200ED5FE8 /* 102.gif in Resources */ = {isa = PBXBuildFile; fileRef = 6DD319E6188E592100ED5FE8 /* 102.gif */; }; + 6DD31AC4188E592200ED5FE8 /* 103.gif in Resources */ = {isa = PBXBuildFile; fileRef = 6DD319E7188E592100ED5FE8 /* 103.gif */; }; + 6DD31AC5188E592200ED5FE8 /* 104.gif in Resources */ = {isa = PBXBuildFile; fileRef = 6DD319E8188E592100ED5FE8 /* 104.gif */; }; + 6DD31AC6188E592200ED5FE8 /* 105.gif in Resources */ = {isa = PBXBuildFile; fileRef = 6DD319E9188E592100ED5FE8 /* 105.gif */; }; + 6DD31AC7188E592200ED5FE8 /* 106.gif in Resources */ = {isa = PBXBuildFile; fileRef = 6DD319EA188E592100ED5FE8 /* 106.gif */; }; + 6DD31AC8188E592200ED5FE8 /* 107.gif in Resources */ = {isa = PBXBuildFile; fileRef = 6DD319EB188E592100ED5FE8 /* 107.gif */; }; + 6DD31AC9188E592200ED5FE8 /* 108.gif in Resources */ = {isa = PBXBuildFile; fileRef = 6DD319EC188E592100ED5FE8 /* 108.gif */; }; + 6DD31ACA188E592200ED5FE8 /* 109.gif in Resources */ = {isa = PBXBuildFile; fileRef = 6DD319ED188E592100ED5FE8 /* 109.gif */; }; + 6DD31ACB188E592200ED5FE8 /* 110.gif in Resources */ = {isa = PBXBuildFile; fileRef = 6DD319EE188E592100ED5FE8 /* 110.gif */; }; + 6DD31ACC188E592200ED5FE8 /* 111.gif in Resources */ = {isa = PBXBuildFile; fileRef = 6DD319EF188E592100ED5FE8 /* 111.gif */; }; + 6DD31ACD188E592200ED5FE8 /* 112.gif in Resources */ = {isa = PBXBuildFile; fileRef = 6DD319F0188E592100ED5FE8 /* 112.gif */; }; + 6DD31ACE188E592200ED5FE8 /* 113.gif in Resources */ = {isa = PBXBuildFile; fileRef = 6DD319F1188E592100ED5FE8 /* 113.gif */; }; + 6DD31ACF188E592200ED5FE8 /* 114.gif in Resources */ = {isa = PBXBuildFile; fileRef = 6DD319F2188E592100ED5FE8 /* 114.gif */; }; + 6DD31AD0188E592200ED5FE8 /* 115.gif in Resources */ = {isa = PBXBuildFile; fileRef = 6DD319F3188E592100ED5FE8 /* 115.gif */; }; + 6DD31AD1188E592200ED5FE8 /* 116.gif in Resources */ = {isa = PBXBuildFile; fileRef = 6DD319F4188E592100ED5FE8 /* 116.gif */; }; + 6DD31AD2188E592200ED5FE8 /* 117.gif in Resources */ = {isa = PBXBuildFile; fileRef = 6DD319F5188E592100ED5FE8 /* 117.gif */; }; + 6DD31AD3188E592200ED5FE8 /* 118.gif in Resources */ = {isa = PBXBuildFile; fileRef = 6DD319F6188E592100ED5FE8 /* 118.gif */; }; + 6DD31AD4188E592200ED5FE8 /* 119.gif in Resources */ = {isa = PBXBuildFile; fileRef = 6DD319F7188E592100ED5FE8 /* 119.gif */; }; + 6DD31AD5188E592200ED5FE8 /* 120.gif in Resources */ = {isa = PBXBuildFile; fileRef = 6DD319F8188E592100ED5FE8 /* 120.gif */; }; + 6DD31AD6188E592200ED5FE8 /* 121.gif in Resources */ = {isa = PBXBuildFile; fileRef = 6DD319F9188E592100ED5FE8 /* 121.gif */; }; + 6DD31AD7188E592200ED5FE8 /* 122.gif in Resources */ = {isa = PBXBuildFile; fileRef = 6DD319FA188E592100ED5FE8 /* 122.gif */; }; + 6DD31AD8188E592200ED5FE8 /* 123.gif in Resources */ = {isa = PBXBuildFile; fileRef = 6DD319FB188E592100ED5FE8 /* 123.gif */; }; + 6DD31AD9188E592200ED5FE8 /* 124.gif in Resources */ = {isa = PBXBuildFile; fileRef = 6DD319FC188E592100ED5FE8 /* 124.gif */; }; + 6DD31ADA188E592200ED5FE8 /* 125.gif in Resources */ = {isa = PBXBuildFile; fileRef = 6DD319FD188E592100ED5FE8 /* 125.gif */; }; + 6DD31ADB188E592200ED5FE8 /* 126.gif in Resources */ = {isa = PBXBuildFile; fileRef = 6DD319FE188E592100ED5FE8 /* 126.gif */; }; + 6DD31ADC188E592200ED5FE8 /* 127.gif in Resources */ = {isa = PBXBuildFile; fileRef = 6DD319FF188E592100ED5FE8 /* 127.gif */; }; + 6DD31ADD188E592200ED5FE8 /* 128.gif in Resources */ = {isa = PBXBuildFile; fileRef = 6DD31A00188E592100ED5FE8 /* 128.gif */; }; + 6DD31ADE188E592200ED5FE8 /* 129.gif in Resources */ = {isa = PBXBuildFile; fileRef = 6DD31A01188E592200ED5FE8 /* 129.gif */; }; + 6DD31ADF188E592200ED5FE8 /* 130.gif in Resources */ = {isa = PBXBuildFile; fileRef = 6DD31A02188E592200ED5FE8 /* 130.gif */; }; + 6DD31AE0188E592200ED5FE8 /* 131.gif in Resources */ = {isa = PBXBuildFile; fileRef = 6DD31A03188E592200ED5FE8 /* 131.gif */; }; + 6DD31AE1188E592200ED5FE8 /* 132.gif in Resources */ = {isa = PBXBuildFile; fileRef = 6DD31A04188E592200ED5FE8 /* 132.gif */; }; + 6DD31AE2188E592200ED5FE8 /* 133.gif in Resources */ = {isa = PBXBuildFile; fileRef = 6DD31A05188E592200ED5FE8 /* 133.gif */; }; + 6DD31AE3188E592200ED5FE8 /* 134.gif in Resources */ = {isa = PBXBuildFile; fileRef = 6DD31A06188E592200ED5FE8 /* 134.gif */; }; + 6DD31AE4188E592200ED5FE8 /* 135.gif in Resources */ = {isa = PBXBuildFile; fileRef = 6DD31A07188E592200ED5FE8 /* 135.gif */; }; + 6DD31AE5188E592200ED5FE8 /* 136.gif in Resources */ = {isa = PBXBuildFile; fileRef = 6DD31A08188E592200ED5FE8 /* 136.gif */; }; + 6DD31AE6188E592200ED5FE8 /* 137.gif in Resources */ = {isa = PBXBuildFile; fileRef = 6DD31A09188E592200ED5FE8 /* 137.gif */; }; + 6DD31AE7188E592200ED5FE8 /* 138.gif in Resources */ = {isa = PBXBuildFile; fileRef = 6DD31A0A188E592200ED5FE8 /* 138.gif */; }; + 6DD31AE8188E592200ED5FE8 /* 139.gif in Resources */ = {isa = PBXBuildFile; fileRef = 6DD31A0B188E592200ED5FE8 /* 139.gif */; }; + 6DD31AE9188E592200ED5FE8 /* 140.gif in Resources */ = {isa = PBXBuildFile; fileRef = 6DD31A0C188E592200ED5FE8 /* 140.gif */; }; + 6DD31AEA188E592200ED5FE8 /* 141.gif in Resources */ = {isa = PBXBuildFile; fileRef = 6DD31A0D188E592200ED5FE8 /* 141.gif */; }; + 6DD31AEB188E592200ED5FE8 /* 142.gif in Resources */ = {isa = PBXBuildFile; fileRef = 6DD31A0E188E592200ED5FE8 /* 142.gif */; }; + 6DD31AEC188E592200ED5FE8 /* 143.gif in Resources */ = {isa = PBXBuildFile; fileRef = 6DD31A0F188E592200ED5FE8 /* 143.gif */; }; + 6DD31AED188E592200ED5FE8 /* 144.gif in Resources */ = {isa = PBXBuildFile; fileRef = 6DD31A10188E592200ED5FE8 /* 144.gif */; }; + 6DD31AEE188E592200ED5FE8 /* 145.gif in Resources */ = {isa = PBXBuildFile; fileRef = 6DD31A11188E592200ED5FE8 /* 145.gif */; }; + 6DD31AEF188E592200ED5FE8 /* 146.gif in Resources */ = {isa = PBXBuildFile; fileRef = 6DD31A12188E592200ED5FE8 /* 146.gif */; }; + 6DD31AF0188E592200ED5FE8 /* 147.gif in Resources */ = {isa = PBXBuildFile; fileRef = 6DD31A13188E592200ED5FE8 /* 147.gif */; }; + 6DD31AF1188E592200ED5FE8 /* 148.gif in Resources */ = {isa = PBXBuildFile; fileRef = 6DD31A14188E592200ED5FE8 /* 148.gif */; }; + 6DD31AF2188E592200ED5FE8 /* 149.gif in Resources */ = {isa = PBXBuildFile; fileRef = 6DD31A15188E592200ED5FE8 /* 149.gif */; }; + 6DD31AF3188E592200ED5FE8 /* 150.gif in Resources */ = {isa = PBXBuildFile; fileRef = 6DD31A16188E592200ED5FE8 /* 150.gif */; }; + 6DD31AF4188E592200ED5FE8 /* 151.gif in Resources */ = {isa = PBXBuildFile; fileRef = 6DD31A17188E592200ED5FE8 /* 151.gif */; }; + 6DD31AF5188E592200ED5FE8 /* 152.gif in Resources */ = {isa = PBXBuildFile; fileRef = 6DD31A18188E592200ED5FE8 /* 152.gif */; }; + 6DD31AF6188E592200ED5FE8 /* 153.gif in Resources */ = {isa = PBXBuildFile; fileRef = 6DD31A19188E592200ED5FE8 /* 153.gif */; }; + 6DD31AF7188E592200ED5FE8 /* 154.gif in Resources */ = {isa = PBXBuildFile; fileRef = 6DD31A1A188E592200ED5FE8 /* 154.gif */; }; + 6DD31AF8188E592200ED5FE8 /* 155.gif in Resources */ = {isa = PBXBuildFile; fileRef = 6DD31A1B188E592200ED5FE8 /* 155.gif */; }; + 6DD31AF9188E592200ED5FE8 /* 156.gif in Resources */ = {isa = PBXBuildFile; fileRef = 6DD31A1C188E592200ED5FE8 /* 156.gif */; }; + 6DD31AFA188E592200ED5FE8 /* 157.gif in Resources */ = {isa = PBXBuildFile; fileRef = 6DD31A1D188E592200ED5FE8 /* 157.gif */; }; + 6DD31AFB188E592200ED5FE8 /* 158.gif in Resources */ = {isa = PBXBuildFile; fileRef = 6DD31A1E188E592200ED5FE8 /* 158.gif */; }; + 6DD31AFC188E592200ED5FE8 /* 159.gif in Resources */ = {isa = PBXBuildFile; fileRef = 6DD31A1F188E592200ED5FE8 /* 159.gif */; }; + 6DD31AFD188E592200ED5FE8 /* 160.gif in Resources */ = {isa = PBXBuildFile; fileRef = 6DD31A20188E592200ED5FE8 /* 160.gif */; }; + 6DD31AFE188E592200ED5FE8 /* 161.gif in Resources */ = {isa = PBXBuildFile; fileRef = 6DD31A21188E592200ED5FE8 /* 161.gif */; }; + 6DD31AFF188E592200ED5FE8 /* 162.gif in Resources */ = {isa = PBXBuildFile; fileRef = 6DD31A22188E592200ED5FE8 /* 162.gif */; }; + 6DD31B00188E592200ED5FE8 /* 163.gif in Resources */ = {isa = PBXBuildFile; fileRef = 6DD31A23188E592200ED5FE8 /* 163.gif */; }; + 6DD31B01188E592200ED5FE8 /* 164.gif in Resources */ = {isa = PBXBuildFile; fileRef = 6DD31A24188E592200ED5FE8 /* 164.gif */; }; + 6DD31B02188E592200ED5FE8 /* 165.gif in Resources */ = {isa = PBXBuildFile; fileRef = 6DD31A25188E592200ED5FE8 /* 165.gif */; }; + 6DD31B03188E592200ED5FE8 /* 166.gif in Resources */ = {isa = PBXBuildFile; fileRef = 6DD31A26188E592200ED5FE8 /* 166.gif */; }; + 6DD31B04188E592200ED5FE8 /* 167.gif in Resources */ = {isa = PBXBuildFile; fileRef = 6DD31A27188E592200ED5FE8 /* 167.gif */; }; + 6DD31B05188E592200ED5FE8 /* 168.gif in Resources */ = {isa = PBXBuildFile; fileRef = 6DD31A28188E592200ED5FE8 /* 168.gif */; }; + 6DD31B06188E592200ED5FE8 /* 169.gif in Resources */ = {isa = PBXBuildFile; fileRef = 6DD31A29188E592200ED5FE8 /* 169.gif */; }; + 6DD31B07188E592200ED5FE8 /* 170.gif in Resources */ = {isa = PBXBuildFile; fileRef = 6DD31A2A188E592200ED5FE8 /* 170.gif */; }; + 6DD31B08188E592200ED5FE8 /* 171.gif in Resources */ = {isa = PBXBuildFile; fileRef = 6DD31A2B188E592200ED5FE8 /* 171.gif */; }; + 6DD31B09188E592200ED5FE8 /* 172.gif in Resources */ = {isa = PBXBuildFile; fileRef = 6DD31A2C188E592200ED5FE8 /* 172.gif */; }; + 6DD31B0A188E592200ED5FE8 /* 173.gif in Resources */ = {isa = PBXBuildFile; fileRef = 6DD31A2D188E592200ED5FE8 /* 173.gif */; }; + 6DD31B0B188E592200ED5FE8 /* 174.gif in Resources */ = {isa = PBXBuildFile; fileRef = 6DD31A2E188E592200ED5FE8 /* 174.gif */; }; + 6DD31B0C188E592200ED5FE8 /* 175.gif in Resources */ = {isa = PBXBuildFile; fileRef = 6DD31A2F188E592200ED5FE8 /* 175.gif */; }; + 6DD31B0D188E592200ED5FE8 /* 176.gif in Resources */ = {isa = PBXBuildFile; fileRef = 6DD31A30188E592200ED5FE8 /* 176.gif */; }; + 6DD31B0E188E592200ED5FE8 /* 177.gif in Resources */ = {isa = PBXBuildFile; fileRef = 6DD31A31188E592200ED5FE8 /* 177.gif */; }; + 6DD31B0F188E592200ED5FE8 /* 178.gif in Resources */ = {isa = PBXBuildFile; fileRef = 6DD31A32188E592200ED5FE8 /* 178.gif */; }; + 6DD31B10188E592200ED5FE8 /* 179.gif in Resources */ = {isa = PBXBuildFile; fileRef = 6DD31A33188E592200ED5FE8 /* 179.gif */; }; + 6DD31B11188E592200ED5FE8 /* 180.gif in Resources */ = {isa = PBXBuildFile; fileRef = 6DD31A34188E592200ED5FE8 /* 180.gif */; }; + 6DD31B12188E592200ED5FE8 /* 181.gif in Resources */ = {isa = PBXBuildFile; fileRef = 6DD31A35188E592200ED5FE8 /* 181.gif */; }; + 6DD31B13188E592200ED5FE8 /* 182.gif in Resources */ = {isa = PBXBuildFile; fileRef = 6DD31A36188E592200ED5FE8 /* 182.gif */; }; + 6DD31B14188E592200ED5FE8 /* 183.gif in Resources */ = {isa = PBXBuildFile; fileRef = 6DD31A37188E592200ED5FE8 /* 183.gif */; }; + 6DD31B15188E592200ED5FE8 /* 184.gif in Resources */ = {isa = PBXBuildFile; fileRef = 6DD31A38188E592200ED5FE8 /* 184.gif */; }; + 6DD31B16188E592200ED5FE8 /* 185.gif in Resources */ = {isa = PBXBuildFile; fileRef = 6DD31A39188E592200ED5FE8 /* 185.gif */; }; + 6DD31B17188E592200ED5FE8 /* 186.gif in Resources */ = {isa = PBXBuildFile; fileRef = 6DD31A3A188E592200ED5FE8 /* 186.gif */; }; + 6DD31B18188E592200ED5FE8 /* 187.gif in Resources */ = {isa = PBXBuildFile; fileRef = 6DD31A3B188E592200ED5FE8 /* 187.gif */; }; + 6DD31B19188E592200ED5FE8 /* 188.gif in Resources */ = {isa = PBXBuildFile; fileRef = 6DD31A3C188E592200ED5FE8 /* 188.gif */; }; + 6DD31B1A188E592200ED5FE8 /* 189.gif in Resources */ = {isa = PBXBuildFile; fileRef = 6DD31A3D188E592200ED5FE8 /* 189.gif */; }; + 6DD31B1B188E592200ED5FE8 /* 190.gif in Resources */ = {isa = PBXBuildFile; fileRef = 6DD31A3E188E592200ED5FE8 /* 190.gif */; }; + 6DD31B1C188E592200ED5FE8 /* 191.gif in Resources */ = {isa = PBXBuildFile; fileRef = 6DD31A3F188E592200ED5FE8 /* 191.gif */; }; + 6DD31B1D188E592200ED5FE8 /* 192.gif in Resources */ = {isa = PBXBuildFile; fileRef = 6DD31A40188E592200ED5FE8 /* 192.gif */; }; + 6DD31B1E188E592200ED5FE8 /* 193.gif in Resources */ = {isa = PBXBuildFile; fileRef = 6DD31A41188E592200ED5FE8 /* 193.gif */; }; + 6DD31B1F188E592200ED5FE8 /* 194.gif in Resources */ = {isa = PBXBuildFile; fileRef = 6DD31A42188E592200ED5FE8 /* 194.gif */; }; + 6DD31B20188E592200ED5FE8 /* 195.gif in Resources */ = {isa = PBXBuildFile; fileRef = 6DD31A43188E592200ED5FE8 /* 195.gif */; }; + 6DD31B21188E592200ED5FE8 /* 196.gif in Resources */ = {isa = PBXBuildFile; fileRef = 6DD31A44188E592200ED5FE8 /* 196.gif */; }; + 6DD31B22188E592200ED5FE8 /* 197.gif in Resources */ = {isa = PBXBuildFile; fileRef = 6DD31A45188E592200ED5FE8 /* 197.gif */; }; + 6DD31B23188E592200ED5FE8 /* 198.gif in Resources */ = {isa = PBXBuildFile; fileRef = 6DD31A46188E592200ED5FE8 /* 198.gif */; }; + 6DD31B24188E592200ED5FE8 /* 199.gif in Resources */ = {isa = PBXBuildFile; fileRef = 6DD31A47188E592200ED5FE8 /* 199.gif */; }; + 6DD31B25188E592200ED5FE8 /* 200.gif in Resources */ = {isa = PBXBuildFile; fileRef = 6DD31A48188E592200ED5FE8 /* 200.gif */; }; + 6DD31B26188E592200ED5FE8 /* 201.gif in Resources */ = {isa = PBXBuildFile; fileRef = 6DD31A49188E592200ED5FE8 /* 201.gif */; }; + 6DD31B27188E592200ED5FE8 /* 202.gif in Resources */ = {isa = PBXBuildFile; fileRef = 6DD31A4A188E592200ED5FE8 /* 202.gif */; }; + 6DD31B28188E592200ED5FE8 /* 203.gif in Resources */ = {isa = PBXBuildFile; fileRef = 6DD31A4B188E592200ED5FE8 /* 203.gif */; }; + 6DD31B29188E592200ED5FE8 /* 204.gif in Resources */ = {isa = PBXBuildFile; fileRef = 6DD31A4C188E592200ED5FE8 /* 204.gif */; }; + 6DD31B2A188E592200ED5FE8 /* 205.gif in Resources */ = {isa = PBXBuildFile; fileRef = 6DD31A4D188E592200ED5FE8 /* 205.gif */; }; + 6DD31B2B188E592200ED5FE8 /* 206.gif in Resources */ = {isa = PBXBuildFile; fileRef = 6DD31A4E188E592200ED5FE8 /* 206.gif */; }; + 6DD31B2C188E592200ED5FE8 /* 207.gif in Resources */ = {isa = PBXBuildFile; fileRef = 6DD31A4F188E592200ED5FE8 /* 207.gif */; }; + 6DD31B2D188E592200ED5FE8 /* 208.gif in Resources */ = {isa = PBXBuildFile; fileRef = 6DD31A50188E592200ED5FE8 /* 208.gif */; }; + 6DD31B2E188E592200ED5FE8 /* 209.gif in Resources */ = {isa = PBXBuildFile; fileRef = 6DD31A51188E592200ED5FE8 /* 209.gif */; }; + 6DD31B2F188E592200ED5FE8 /* 210.gif in Resources */ = {isa = PBXBuildFile; fileRef = 6DD31A52188E592200ED5FE8 /* 210.gif */; }; + 6DD31B30188E592200ED5FE8 /* 211.gif in Resources */ = {isa = PBXBuildFile; fileRef = 6DD31A53188E592200ED5FE8 /* 211.gif */; }; + 6DD31B31188E592200ED5FE8 /* 212.gif in Resources */ = {isa = PBXBuildFile; fileRef = 6DD31A54188E592200ED5FE8 /* 212.gif */; }; + 6DD31B32188E592200ED5FE8 /* 213.gif in Resources */ = {isa = PBXBuildFile; fileRef = 6DD31A55188E592200ED5FE8 /* 213.gif */; }; + 6DD31B33188E592200ED5FE8 /* 214.gif in Resources */ = {isa = PBXBuildFile; fileRef = 6DD31A56188E592200ED5FE8 /* 214.gif */; }; + 6DD31B34188E592200ED5FE8 /* 215.gif in Resources */ = {isa = PBXBuildFile; fileRef = 6DD31A57188E592200ED5FE8 /* 215.gif */; }; + 6DD31B35188E592200ED5FE8 /* 216.gif in Resources */ = {isa = PBXBuildFile; fileRef = 6DD31A58188E592200ED5FE8 /* 216.gif */; }; + 6DD31B36188E592200ED5FE8 /* 217.gif in Resources */ = {isa = PBXBuildFile; fileRef = 6DD31A59188E592200ED5FE8 /* 217.gif */; }; + 6DD31B37188E592200ED5FE8 /* 218.gif in Resources */ = {isa = PBXBuildFile; fileRef = 6DD31A5A188E592200ED5FE8 /* 218.gif */; }; + 6DD31B38188E592200ED5FE8 /* 219.gif in Resources */ = {isa = PBXBuildFile; fileRef = 6DD31A5B188E592200ED5FE8 /* 219.gif */; }; + 6DD31B39188E592200ED5FE8 /* 220.gif in Resources */ = {isa = PBXBuildFile; fileRef = 6DD31A5C188E592200ED5FE8 /* 220.gif */; }; + 6DD31B99188F554500ED5FE8 /* EmotionListXmlParser.m in Sources */ = {isa = PBXBuildFile; fileRef = 6DD31B98188F554500ED5FE8 /* EmotionListXmlParser.m */; }; + 6DD31B9B188F55C800ED5FE8 /* emotionList.xml in Resources */ = {isa = PBXBuildFile; fileRef = 6DD31B9A188F55C800ED5FE8 /* emotionList.xml */; }; + 6DDB0D3A18EC17FF00A1DA57 /* GCDAsyncSocket.m in Sources */ = {isa = PBXBuildFile; fileRef = 6DDB0D3918EC17FF00A1DA57 /* GCDAsyncSocket.m */; }; + 6DE7621118867FE2000EDC39 /* PullToRefreshClipView.m in Sources */ = {isa = PBXBuildFile; fileRef = 6DE7620D18867FE2000EDC39 /* PullToRefreshClipView.m */; }; + 6DE7621218867FE2000EDC39 /* PullToRefreshScrollView.m in Sources */ = {isa = PBXBuildFile; fileRef = 6DE7621018867FE2000EDC39 /* PullToRefreshScrollView.m */; }; + 811405D41A68EFA6009CFC06 /* DDUnreadMessageAPI.m in Sources */ = {isa = PBXBuildFile; fileRef = 811405D31A68EFA6009CFC06 /* DDUnreadMessageAPI.m */; }; + 8195ED691A7651E700DA5CA0 /* bg.jpg in Resources */ = {isa = PBXBuildFile; fileRef = 8195ED4F1A7651E700DA5CA0 /* bg.jpg */; }; + 8195ED6A1A7651E700DA5CA0 /* blb.png in Resources */ = {isa = PBXBuildFile; fileRef = 8195ED501A7651E700DA5CA0 /* blb.png */; }; + 8195ED6B1A7651E700DA5CA0 /* blbb.png in Resources */ = {isa = PBXBuildFile; fileRef = 8195ED511A7651E700DA5CA0 /* blbb.png */; }; + 8195ED6C1A7651E700DA5CA0 /* brw.png in Resources */ = {isa = PBXBuildFile; fileRef = 8195ED521A7651E700DA5CA0 /* brw.png */; }; + 8195ED6D1A7651E700DA5CA0 /* brwb.png in Resources */ = {isa = PBXBuildFile; fileRef = 8195ED531A7651E700DA5CA0 /* brwb.png */; }; + 8195ED6E1A7651E700DA5CA0 /* highlight.default.css in Resources */ = {isa = PBXBuildFile; fileRef = 8195ED541A7651E700DA5CA0 /* highlight.default.css */; }; + 8195ED6F1A7651E700DA5CA0 /* highlight.min.js in Resources */ = {isa = PBXBuildFile; fileRef = 8195ED551A7651E700DA5CA0 /* highlight.min.js */; }; + 8195ED701A7651E700DA5CA0 /* highlight.pack.js in Resources */ = {isa = PBXBuildFile; fileRef = 8195ED561A7651E700DA5CA0 /* highlight.pack.js */; }; + 8195ED711A7651E700DA5CA0 /* hook-spinner.gif in Resources */ = {isa = PBXBuildFile; fileRef = 8195ED571A7651E700DA5CA0 /* hook-spinner.gif */; }; + 8195ED721A7651E700DA5CA0 /* hook.css in Resources */ = {isa = PBXBuildFile; fileRef = 8195ED581A7651E700DA5CA0 /* hook.css */; }; + 8195ED731A7651E700DA5CA0 /* hook.min.js in Resources */ = {isa = PBXBuildFile; fileRef = 8195ED591A7651E700DA5CA0 /* hook.min.js */; }; + 8195ED741A7651E700DA5CA0 /* iscroll-probe.js in Resources */ = {isa = PBXBuildFile; fileRef = 8195ED5A1A7651E700DA5CA0 /* iscroll-probe.js */; }; + 8195ED751A7651E700DA5CA0 /* iscroll.js in Resources */ = {isa = PBXBuildFile; fileRef = 8195ED5B1A7651E700DA5CA0 /* iscroll.js */; }; + 8195ED761A7651E700DA5CA0 /* jquery-2.1.1.min.js in Resources */ = {isa = PBXBuildFile; fileRef = 8195ED5C1A7651E700DA5CA0 /* jquery-2.1.1.min.js */; }; + 8195ED771A7651E700DA5CA0 /* jquery.scrollz.css in Resources */ = {isa = PBXBuildFile; fileRef = 8195ED5D1A7651E700DA5CA0 /* jquery.scrollz.css */; }; + 8195ED781A7651E700DA5CA0 /* jquery.scrollz.min.js in Resources */ = {isa = PBXBuildFile; fileRef = 8195ED5E1A7651E700DA5CA0 /* jquery.scrollz.min.js */; }; + 8195ED791A7651E700DA5CA0 /* main.css in Resources */ = {isa = PBXBuildFile; fileRef = 8195ED5F1A7651E700DA5CA0 /* main.css */; }; + 8195ED7A1A7651E700DA5CA0 /* message.html in Resources */ = {isa = PBXBuildFile; fileRef = 8195ED601A7651E700DA5CA0 /* message.html */; }; + 8195ED7B1A7651E700DA5CA0 /* moment-with-locales.min.js in Resources */ = {isa = PBXBuildFile; fileRef = 8195ED611A7651E700DA5CA0 /* moment-with-locales.min.js */; }; + 8195ED7C1A7651E700DA5CA0 /* mousewheel.js in Resources */ = {isa = PBXBuildFile; fileRef = 8195ED621A7651E700DA5CA0 /* mousewheel.js */; }; + 8195ED7D1A7651E700DA5CA0 /* msg.js in Resources */ = {isa = PBXBuildFile; fileRef = 8195ED631A7651E700DA5CA0 /* msg.js */; }; + 8195ED7E1A7651E700DA5CA0 /* pure-min.css in Resources */ = {isa = PBXBuildFile; fileRef = 8195ED641A7651E700DA5CA0 /* pure-min.css */; }; + 8195ED7F1A7651E700DA5CA0 /* scrollbar.css in Resources */ = {isa = PBXBuildFile; fileRef = 8195ED651A7651E700DA5CA0 /* scrollbar.css */; }; + 8195ED801A7651E700DA5CA0 /* solarized_dark.css in Resources */ = {isa = PBXBuildFile; fileRef = 8195ED661A7651E700DA5CA0 /* solarized_dark.css */; }; + 8195ED811A7651E700DA5CA0 /* solarized_light.css in Resources */ = {isa = PBXBuildFile; fileRef = 8195ED671A7651E700DA5CA0 /* solarized_light.css */; }; + 8195ED821A7651E700DA5CA0 /* template.js in Resources */ = {isa = PBXBuildFile; fileRef = 8195ED681A7651E700DA5CA0 /* template.js */; }; + 81DE59C51A833B0800040078 /* big.cur in Resources */ = {isa = PBXBuildFile; fileRef = 81DE59C41A831B9F00040078 /* big.cur */; }; + 81DEF5031A5B8D9900F0799D /* DDBaseEntity.m in Sources */ = {isa = PBXBuildFile; fileRef = 81DEF5001A5B8D9900F0799D /* DDBaseEntity.m */; }; + 81DEF50A1A5B8FE800F0799D /* DDepartment.m in Sources */ = {isa = PBXBuildFile; fileRef = 81DEF5091A5B8FE800F0799D /* DDepartment.m */; }; + 81DEF50D1A5B901B00F0799D /* NSDictionary+Safe.m in Sources */ = {isa = PBXBuildFile; fileRef = 81DEF50C1A5B901B00F0799D /* NSDictionary+Safe.m */; }; + 81DEF5101A5B908100F0799D /* NSString+Additions.m in Sources */ = {isa = PBXBuildFile; fileRef = 81DEF50F1A5B908100F0799D /* NSString+Additions.m */; }; + 81ECFE3D1A822E5500445985 /* voice_me.gif in Resources */ = {isa = PBXBuildFile; fileRef = 81ECFE3B1A822E5500445985 /* voice_me.gif */; }; + 81ECFE3E1A822E5500445985 /* voice_other.gif in Resources */ = {isa = PBXBuildFile; fileRef = 81ECFE3C1A822E5500445985 /* voice_other.gif */; }; + 81ECFE401A8230E700445985 /* gifffer.js in Resources */ = {isa = PBXBuildFile; fileRef = 81ECFE3F1A8230E700445985 /* gifffer.js */; }; + 81ECFE431A82338D00445985 /* voice_me.png in Resources */ = {isa = PBXBuildFile; fileRef = 81ECFE411A82338D00445985 /* voice_me.png */; }; + 81ECFE441A82338D00445985 /* voice_other.png in Resources */ = {isa = PBXBuildFile; fileRef = 81ECFE421A82338D00445985 /* voice_other.png */; }; + 81FA3B2A1A68DEBC00B379D1 /* DDHistoryMessageAPI.m in Sources */ = {isa = PBXBuildFile; fileRef = 81FA3B291A68DEBC00B379D1 /* DDHistoryMessageAPI.m */; }; + 8AEFB8421920968C006A5C88 /* DDSendP2PCmdAPI.m in Sources */ = {isa = PBXBuildFile; fileRef = 8AEFB8411920968C006A5C88 /* DDSendP2PCmdAPI.m */; }; + 9068ED71E21126C61D07D32B /* libPods.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 8F31B5BDBE8F1E507D5515C9 /* libPods.a */; }; + C40417B31A68C20E00242E20 /* MTLastMessageManager.m in Sources */ = {isa = PBXBuildFile; fileRef = C40417B21A68C20E00242E20 /* MTLastMessageManager.m */; }; + C40417B61A68D9B500242E20 /* MTUnreadMessageManager.m in Sources */ = {isa = PBXBuildFile; fileRef = C40417B51A68D9B500242E20 /* MTUnreadMessageManager.m */; }; + C40417B91A69047E00242E20 /* MTMessageEntity.mm in Sources */ = {isa = PBXBuildFile; fileRef = C40417B81A69047E00242E20 /* MTMessageEntity.mm */; }; + C406E6FA18D81850005092C3 /* NSAttributedString+Message.m in Sources */ = {isa = PBXBuildFile; fileRef = C406E6F918D81850005092C3 /* NSAttributedString+Message.m */; }; + C406E6FD18D81925005092C3 /* NSImage+Scale.m in Sources */ = {isa = PBXBuildFile; fileRef = C406E6FC18D81925005092C3 /* NSImage+Scale.m */; }; + C406E70018D82E84005092C3 /* EmotionManager.m in Sources */ = {isa = PBXBuildFile; fileRef = C406E6FF18D82E84005092C3 /* EmotionManager.m */; }; + C406E70318D84FD2005092C3 /* DDMessageTextView.m in Sources */ = {isa = PBXBuildFile; fileRef = C406E70218D84FD2005092C3 /* DDMessageTextView.m */; }; + C406E70918D8616B005092C3 /* DDChangableAttactment.m in Sources */ = {isa = PBXBuildFile; fileRef = C406E70818D8616B005092C3 /* DDChangableAttactment.m */; }; + C408E8AE191B48BD005F5150 /* DDSendMessageAPI.mm in Sources */ = {isa = PBXBuildFile; fileRef = C408E8AD191B48BD005F5150 /* DDSendMessageAPI.mm */; }; + C408E8B1191B57DE005F5150 /* DDCreateGroupAPI.m in Sources */ = {isa = PBXBuildFile; fileRef = C408E8B0191B57DE005F5150 /* DDCreateGroupAPI.m */; }; + C408E8C3191B83F3005F5150 /* DDOnlineUserListAPI.m in Sources */ = {isa = PBXBuildFile; fileRef = C408E8C2191B83F3005F5150 /* DDOnlineUserListAPI.m */; }; + C408E8C6191B8B70005F5150 /* DDReceiveKickAPI.m in Sources */ = {isa = PBXBuildFile; fileRef = C408E8C5191B8B70005F5150 /* DDReceiveKickAPI.m */; }; + C408E8CE191CDAE4005F5150 /* DDFileLoginAPI.m in Sources */ = {isa = PBXBuildFile; fileRef = C408E8CD191CDAE4005F5150 /* DDFileLoginAPI.m */; }; + C408E8D1191CDCDD005F5150 /* DDFileSendAPI.m in Sources */ = {isa = PBXBuildFile; fileRef = C408E8D0191CDCDD005F5150 /* DDFileSendAPI.m */; }; + C408E8D4191CE13E005F5150 /* DDGetOfflineFileAPI.m in Sources */ = {isa = PBXBuildFile; fileRef = C408E8D3191CE13E005F5150 /* DDGetOfflineFileAPI.m */; }; + C408E8DB191CE44E005F5150 /* DDOtherLinkFileServerAPI.m in Sources */ = {isa = PBXBuildFile; fileRef = C408E8DA191CE44E005F5150 /* DDOtherLinkFileServerAPI.m */; }; + C40F951A1919C69A005CACBF /* DDAllUserAPI.m in Sources */ = {isa = PBXBuildFile; fileRef = C40F95191919C69A005CACBF /* DDAllUserAPI.m */; }; + C40F95251919D682005CACBF /* DDUnrequestSuperAPI.m in Sources */ = {isa = PBXBuildFile; fileRef = C40F95241919D682005CACBF /* DDUnrequestSuperAPI.m */; }; + C40F95281919DDCC005CACBF /* DDReceiveMessageAPI.m in Sources */ = {isa = PBXBuildFile; fileRef = C40F95271919DDCC005CACBF /* DDReceiveMessageAPI.m */; }; + C40F952B1919FA00005CACBF /* DDMsgReadACKAPI.m in Sources */ = {isa = PBXBuildFile; fileRef = C40F952A1919FA00005CACBF /* DDMsgReadACKAPI.m */; }; + C40F952E1919FA90005CACBF /* DDGroupMsgReadACKAPI.m in Sources */ = {isa = PBXBuildFile; fileRef = C40F952D1919FA90005CACBF /* DDGroupMsgReadACKAPI.m */; }; + C40F95311919FB4F005CACBF /* DDUserMsgReceivedACKAPI.m in Sources */ = {isa = PBXBuildFile; fileRef = C40F95301919FB4F005CACBF /* DDUserMsgReceivedACKAPI.m */; }; + C40F95341919FB75005CACBF /* DDGroupMsgReceivedACKAPI.m in Sources */ = {isa = PBXBuildFile; fileRef = C40F95331919FB75005CACBF /* DDGroupMsgReceivedACKAPI.m */; }; + C40F953B191A011A005CACBF /* DDGroupInfoAPI.m in Sources */ = {isa = PBXBuildFile; fileRef = C40F953A191A011A005CACBF /* DDGroupInfoAPI.m */; }; + C40F9544191A563E005CACBF /* DDSeqNoManager.m in Sources */ = {isa = PBXBuildFile; fileRef = C40F9543191A563E005CACBF /* DDSeqNoManager.m */; }; + C40F9547191B1D32005CACBF /* DDUserOnlineStateAPI.m in Sources */ = {isa = PBXBuildFile; fileRef = C40F9546191B1D32005CACBF /* DDUserOnlineStateAPI.m */; }; + C40F954A191B26EE005CACBF /* DDReceiveStateChangedAPI.m in Sources */ = {isa = PBXBuildFile; fileRef = C40F9549191B26EE005CACBF /* DDReceiveStateChangedAPI.m */; }; + C417C3991A7370E2003984D7 /* MTImageCache.m in Sources */ = {isa = PBXBuildFile; fileRef = C417C3981A7370E2003984D7 /* MTImageCache.m */; }; + C417C39C1A737C2C003984D7 /* NSImageView+MTAddition.m in Sources */ = {isa = PBXBuildFile; fileRef = C417C39B1A737C2C003984D7 /* NSImageView+MTAddition.m */; }; + C417C39F1A738010003984D7 /* MTImageDownload.m in Sources */ = {isa = PBXBuildFile; fileRef = C417C39E1A738010003984D7 /* MTImageDownload.m */; }; + C41AB11A195A7EF2002AE7C7 /* DDIntranetViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = C41AB119195A7EF2002AE7C7 /* DDIntranetViewController.m */; }; + C41AB11D195AA10F002AE7C7 /* DDIntranetModule.m in Sources */ = {isa = PBXBuildFile; fileRef = C41AB11C195AA10F002AE7C7 /* DDIntranetModule.m */; }; + C41AB120195AA9DA002AE7C7 /* DDIntranetEntity.m in Sources */ = {isa = PBXBuildFile; fileRef = C41AB11F195AA9DA002AE7C7 /* DDIntranetEntity.m */; }; + C41AB125195AAAF4002AE7C7 /* DDIntranetCell.m in Sources */ = {isa = PBXBuildFile; fileRef = C41AB124195AAAF4002AE7C7 /* DDIntranetCell.m */; }; + C41AB127195AACE8002AE7C7 /* DDIntranentViewController.xib in Resources */ = {isa = PBXBuildFile; fileRef = C41AB126195AACE8002AE7C7 /* DDIntranentViewController.xib */; }; + C41AB12C195B0487002AE7C7 /* DDIntranetContentViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = C41AB12A195B0487002AE7C7 /* DDIntranetContentViewController.m */; }; + C41AB12D195B0487002AE7C7 /* DDIntranetContentViewController.xib in Resources */ = {isa = PBXBuildFile; fileRef = C41AB12B195B0487002AE7C7 /* DDIntranetContentViewController.xib */; }; + C422FF2319261A18006EEBF9 /* DDCornerView.m in Sources */ = {isa = PBXBuildFile; fileRef = C422FF2219261A18006EEBF9 /* DDCornerView.m */; }; + C42410CF199734E100B6B945 /* DDServiceAccountModule.m in Sources */ = {isa = PBXBuildFile; fileRef = C42410CE199734E100B6B945 /* DDServiceAccountModule.m */; }; + C427BF5E199E00F800A010AA /* almance.png in Resources */ = {isa = PBXBuildFile; fileRef = C427BF5A199E00F800A010AA /* almance.png */; }; + C427BF5F199E00F800A010AA /* almance@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = C427BF5B199E00F800A010AA /* almance@2x.png */; }; + C427BF60199E00F800A010AA /* bang.png in Resources */ = {isa = PBXBuildFile; fileRef = C427BF5C199E00F800A010AA /* bang.png */; }; + C427BF61199E00F800A010AA /* bang@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = C427BF5D199E00F800A010AA /* bang@2x.png */; }; + C427BF9119A32C0900A010AA /* MessageDate.m in Sources */ = {isa = PBXBuildFile; fileRef = C427BF9019A32C0900A010AA /* MessageDate.m */; }; + C42A070718E7D01D004461E1 /* NSWindow+Animation.m in Sources */ = {isa = PBXBuildFile; fileRef = C42A070618E7D01D004461E1 /* NSWindow+Animation.m */; }; + C42A070B18E80066004461E1 /* DDMessageSendManager.m in Sources */ = {isa = PBXBuildFile; fileRef = C42A070A18E80066004461E1 /* DDMessageSendManager.m */; }; + C42A070E18E80E49004461E1 /* DDImageUploader.m in Sources */ = {isa = PBXBuildFile; fileRef = C42A070D18E80E49004461E1 /* DDImageUploader.m */; }; + C42D4EA319247EEA00C7B6F6 /* PFMoveApplication.m in Sources */ = {isa = PBXBuildFile; fileRef = C42D4EA219247EEA00C7B6F6 /* PFMoveApplication.m */; settings = {COMPILER_FLAGS = "-fno-objc-arc"; }; }; + C42D4EA61924BBF000C7B6F6 /* Recent-cell-background.png in Resources */ = {isa = PBXBuildFile; fileRef = C42D4EA41924BBF000C7B6F6 /* Recent-cell-background.png */; }; + C42D4EA71924BBF000C7B6F6 /* Recent-cell-background@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = C42D4EA51924BBF000C7B6F6 /* Recent-cell-background@2x.png */; }; + C43802D218C4860B002555BB /* DDGroupDataWindow.m in Sources */ = {isa = PBXBuildFile; fileRef = C43802D118C4860B002555BB /* DDGroupDataWindow.m */; }; + C43802D518C48627002555BB /* DDGroupDataModule.m in Sources */ = {isa = PBXBuildFile; fileRef = C43802D418C48627002555BB /* DDGroupDataModule.m */; }; + C43802D718C48650002555BB /* DDGroupDataWindow.xib in Resources */ = {isa = PBXBuildFile; fileRef = C43802D618C48650002555BB /* DDGroupDataWindow.xib */; }; + C43802DA18C48A40002555BB /* DDGroupInfoCell.m in Sources */ = {isa = PBXBuildFile; fileRef = C43802D918C48A40002555BB /* DDGroupInfoCell.m */; }; + C438032418C5C916002555BB /* DDUserInfoManager.m in Sources */ = {isa = PBXBuildFile; fileRef = C438032318C5C916002555BB /* DDUserInfoManager.m */; }; + C438032718C5D130002555BB /* DDGroupInfoManager.m in Sources */ = {isa = PBXBuildFile; fileRef = C438032618C5D130002555BB /* DDGroupInfoManager.m */; }; + C4498A0718D71A92009FEA4A /* MessageShowView.m in Sources */ = {isa = PBXBuildFile; fileRef = C4498A0218D71A92009FEA4A /* MessageShowView.m */; }; + C4498A0818D71A92009FEA4A /* MessageViewFactory.m in Sources */ = {isa = PBXBuildFile; fileRef = C4498A0418D71A92009FEA4A /* MessageViewFactory.m */; }; + C4498A0918D71A92009FEA4A /* NSTextView+Rect.m in Sources */ = {isa = PBXBuildFile; fileRef = C4498A0618D71A92009FEA4A /* NSTextView+Rect.m */; }; + C4498A1D18D7D976009FEA4A /* DDChattingViewModule.m in Sources */ = {isa = PBXBuildFile; fileRef = C4498A1C18D7D976009FEA4A /* DDChattingViewModule.m */; }; + C44C20401900B2850069A31F /* DDMessageReviewWindowController.m in Sources */ = {isa = PBXBuildFile; fileRef = C44C203F1900B2850069A31F /* DDMessageReviewWindowController.m */; }; + C44C20431900B2AE0069A31F /* DDMessageReviewModule.m in Sources */ = {isa = PBXBuildFile; fileRef = C44C20421900B2AE0069A31F /* DDMessageReviewModule.m */; }; + C454AB0E18F914D90040BBF0 /* DDLoginServer.m in Sources */ = {isa = PBXBuildFile; fileRef = C454AB0D18F914D90040BBF0 /* DDLoginServer.m */; }; + C4563FBB1906365C009DEB05 /* DDChattingContactListModule.m in Sources */ = {isa = PBXBuildFile; fileRef = C4563FBA1906365C009DEB05 /* DDChattingContactListModule.m */; }; + C4563FBE1906384F009DEB05 /* DDSearch.m in Sources */ = {isa = PBXBuildFile; fileRef = C4563FBD1906384F009DEB05 /* DDSearch.m */; }; + C46B2D9818E3D8F000FE278B /* icon_statusbar_blue.png in Resources */ = {isa = PBXBuildFile; fileRef = C46B2D9718E3D8F000FE278B /* icon_statusbar_blue.png */; }; + C46B2D9A18E3D95F00FE278B /* icon_statusbar_blue@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = C46B2D9918E3D95F00FE278B /* icon_statusbar_blue@2x.png */; }; + C46B2D9D18E435E400FE278B /* DDSetting+OffLineReadMsgManager.m in Sources */ = {isa = PBXBuildFile; fileRef = C46B2D9C18E435E400FE278B /* DDSetting+OffLineReadMsgManager.m */; }; + C46C51BC18D2DBC000149B7F /* DDChattingContactListCell.m in Sources */ = {isa = PBXBuildFile; fileRef = C46C51BB18D2DBC000149B7F /* DDChattingContactListCell.m */; }; + C46C810F197500FA00157856 /* DDCornerRadiusTextField.m in Sources */ = {isa = PBXBuildFile; fileRef = C46C810E197500FA00157856 /* DDCornerRadiusTextField.m */; }; + C47934881915F217009C39AE /* NSView+LayerAddition.m in Sources */ = {isa = PBXBuildFile; fileRef = C47934871915F217009C39AE /* NSView+LayerAddition.m */; }; + C4793495191610AF009C39AE /* login-account.png in Resources */ = {isa = PBXBuildFile; fileRef = C4793489191610AF009C39AE /* login-account.png */; }; + C4793496191610AF009C39AE /* login-account@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = C479348A191610AF009C39AE /* login-account@2x.png */; }; + C4793497191610AF009C39AE /* login-avatar-background.png in Resources */ = {isa = PBXBuildFile; fileRef = C479348B191610AF009C39AE /* login-avatar-background.png */; }; + C4793498191610AF009C39AE /* login-avatar-background@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = C479348C191610AF009C39AE /* login-avatar-background@2x.png */; }; + C4793499191610AF009C39AE /* login-background.png in Resources */ = {isa = PBXBuildFile; fileRef = C479348D191610AF009C39AE /* login-background.png */; }; + C479349A191610AF009C39AE /* login-background@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = C479348E191610AF009C39AE /* login-background@2x.png */; }; + C479349B191610AF009C39AE /* login-input-background.png in Resources */ = {isa = PBXBuildFile; fileRef = C479348F191610AF009C39AE /* login-input-background.png */; }; + C479349C191610AF009C39AE /* login-input-background@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = C4793490191610AF009C39AE /* login-input-background@2x.png */; }; + C479349D191610AF009C39AE /* login-logining.png in Resources */ = {isa = PBXBuildFile; fileRef = C4793491191610AF009C39AE /* login-logining.png */; }; + C479349E191610AF009C39AE /* login-logining@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = C4793492191610AF009C39AE /* login-logining@2x.png */; }; + C479349F191610AF009C39AE /* login-password.png in Resources */ = {isa = PBXBuildFile; fileRef = C4793493191610AF009C39AE /* login-password.png */; }; + C47934A0191610AF009C39AE /* login-password@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = C4793494191610AF009C39AE /* login-password@2x.png */; }; + C47934A5191612A4009C39AE /* Teamtalk-bottom.png in Resources */ = {isa = PBXBuildFile; fileRef = C47934A1191612A4009C39AE /* Teamtalk-bottom.png */; }; + C47934A6191612A4009C39AE /* Teamtalk-bottom@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = C47934A2191612A4009C39AE /* Teamtalk-bottom@2x.png */; }; + C47934A7191612A4009C39AE /* TeamTalk-Top.png in Resources */ = {isa = PBXBuildFile; fileRef = C47934A3191612A4009C39AE /* TeamTalk-Top.png */; }; + C47934A8191612A4009C39AE /* TeamTalk-Top@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = C47934A4191612A4009C39AE /* TeamTalk-Top@2x.png */; }; + C47934AB19163477009C39AE /* DDCustomWindow.m in Sources */ = {isa = PBXBuildFile; fileRef = C47934AA19163477009C39AE /* DDCustomWindow.m */; }; + C47934AE191635D3009C39AE /* close.png in Resources */ = {isa = PBXBuildFile; fileRef = C47934AC191635D3009C39AE /* close.png */; }; + C47934AF191635D3009C39AE /* close@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = C47934AD191635D3009C39AE /* close@2x.png */; }; + C47934B219163C1F009C39AE /* HoverTableRowView.m in Sources */ = {isa = PBXBuildFile; fileRef = C47934B119163C1F009C39AE /* HoverTableRowView.m */; }; + C47934C1191656F8009C39AE /* addgroummember-unselected.png in Resources */ = {isa = PBXBuildFile; fileRef = C47934B3191656F8009C39AE /* addgroummember-unselected.png */; }; + C47934C2191656F8009C39AE /* addgroummember-unselected@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = C47934B4191656F8009C39AE /* addgroummember-unselected@2x.png */; }; + C47934C3191656F8009C39AE /* addgroupmember-arrow.png in Resources */ = {isa = PBXBuildFile; fileRef = C47934B5191656F8009C39AE /* addgroupmember-arrow.png */; }; + C47934C4191656F8009C39AE /* addgroupmember-arrow@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = C47934B6191656F8009C39AE /* addgroupmember-arrow@2x.png */; }; + C47934C5191656F8009C39AE /* addgroupmember-cancel.png in Resources */ = {isa = PBXBuildFile; fileRef = C47934B7191656F8009C39AE /* addgroupmember-cancel.png */; }; + C47934C6191656F8009C39AE /* addgroupmember-cancel@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = C47934B8191656F8009C39AE /* addgroupmember-cancel@2x.png */; }; + C47934C7191656F8009C39AE /* addgroupmember-cancel2.png in Resources */ = {isa = PBXBuildFile; fileRef = C47934B9191656F8009C39AE /* addgroupmember-cancel2.png */; }; + C47934C8191656F8009C39AE /* addgroupmember-cancel2@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = C47934BA191656F8009C39AE /* addgroupmember-cancel2@2x.png */; }; + C47934C9191656F8009C39AE /* addgroupmember-search-background.png in Resources */ = {isa = PBXBuildFile; fileRef = C47934BB191656F8009C39AE /* addgroupmember-search-background.png */; }; + C47934CA191656F8009C39AE /* addgroupmember-search-background@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = C47934BC191656F8009C39AE /* addgroupmember-search-background@2x.png */; }; + C47934CB191656F8009C39AE /* addgroupmember-selected.png in Resources */ = {isa = PBXBuildFile; fileRef = C47934BD191656F8009C39AE /* addgroupmember-selected.png */; }; + C47934CC191656F8009C39AE /* addgroupmember-selected@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = C47934BE191656F8009C39AE /* addgroupmember-selected@2x.png */; }; + C47934CD191656F8009C39AE /* addgroupmember-sure.png in Resources */ = {isa = PBXBuildFile; fileRef = C47934BF191656F8009C39AE /* addgroupmember-sure.png */; }; + C47934CE191656F8009C39AE /* addgroupmember-sure@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = C47934C0191656F8009C39AE /* addgroupmember-sure@2x.png */; }; + C47934D119165EB5009C39AE /* DDAddGroupMemberDepartmentCell.m in Sources */ = {isa = PBXBuildFile; fileRef = C47934D019165EB5009C39AE /* DDAddGroupMemberDepartmentCell.m */; }; + C47934D419166415009C39AE /* DDAddGroupMemberDepartmentRowView.m in Sources */ = {isa = PBXBuildFile; fileRef = C47934D319166415009C39AE /* DDAddGroupMemberDepartmentRowView.m */; }; + C47934D719167458009C39AE /* DDMultiSelectedOutlineView.m in Sources */ = {isa = PBXBuildFile; fileRef = C47934D619167458009C39AE /* DDMultiSelectedOutlineView.m */; }; + C47934DA19172063009C39AE /* DDUserInfoPanel.m in Sources */ = {isa = PBXBuildFile; fileRef = C47934D919172063009C39AE /* DDUserInfoPanel.m */; }; + C47934DC191724D5009C39AE /* DDUserInfoPanel.xib in Resources */ = {isa = PBXBuildFile; fileRef = C47934DB191724D5009C39AE /* DDUserInfoPanel.xib */; }; + C47934E119172599009C39AE /* person-info-background.png in Resources */ = {isa = PBXBuildFile; fileRef = C47934DD19172599009C39AE /* person-info-background.png */; }; + C47934E219172599009C39AE /* person-info-background@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = C47934DE19172599009C39AE /* person-info-background@2x.png */; }; + C47934E319172599009C39AE /* person-info-chat.png in Resources */ = {isa = PBXBuildFile; fileRef = C47934DF19172599009C39AE /* person-info-chat.png */; }; + C47934E419172599009C39AE /* person-info-chat@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = C47934E019172599009C39AE /* person-info-chat@2x.png */; }; + C47934E919173B00009C39AE /* group-info-background.png in Resources */ = {isa = PBXBuildFile; fileRef = C47934E519173B00009C39AE /* group-info-background.png */; }; + C47934EA19173B00009C39AE /* group-info-background@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = C47934E619173B00009C39AE /* group-info-background@2x.png */; }; + C47934EB19173B00009C39AE /* group-info-line.png in Resources */ = {isa = PBXBuildFile; fileRef = C47934E719173B00009C39AE /* group-info-line.png */; }; + C47934EC19173B00009C39AE /* group-info-line@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = C47934E819173B00009C39AE /* group-info-line@2x.png */; }; + C47934F519175F3E009C39AE /* file-transmit-background.png in Resources */ = {isa = PBXBuildFile; fileRef = C47934ED19175F3E009C39AE /* file-transmit-background.png */; }; + C47934F619175F3E009C39AE /* file-transmit-background@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = C47934EE19175F3E009C39AE /* file-transmit-background@2x.png */; }; + C47934F719175F3E009C39AE /* file-transmit-cancel.png in Resources */ = {isa = PBXBuildFile; fileRef = C47934EF19175F3E009C39AE /* file-transmit-cancel.png */; }; + C47934F819175F3E009C39AE /* file-transmit-cancel@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = C47934F019175F3E009C39AE /* file-transmit-cancel@2x.png */; }; + C47934F919175F3E009C39AE /* file-transmit-look.png in Resources */ = {isa = PBXBuildFile; fileRef = C47934F119175F3E009C39AE /* file-transmit-look.png */; }; + C47934FA19175F3E009C39AE /* file-transmit-look@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = C47934F219175F3E009C39AE /* file-transmit-look@2x.png */; }; + C47934FB19175F3E009C39AE /* file-transmit-update.png in Resources */ = {isa = PBXBuildFile; fileRef = C47934F319175F3E009C39AE /* file-transmit-update.png */; }; + C47934FC19175F3E009C39AE /* file-transmit-update@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = C47934F419175F3E009C39AE /* file-transmit-update@2x.png */; }; + C47934FE19177DF1009C39AE /* DDMessageReviewWindow.xib in Resources */ = {isa = PBXBuildFile; fileRef = C47934FD19177DF1009C39AE /* DDMessageReviewWindow.xib */; }; + C4793501191782E7009C39AE /* NSWindow+Addition.m in Sources */ = {isa = PBXBuildFile; fileRef = C4793500191782E7009C39AE /* NSWindow+Addition.m */; }; + C479350419178A69009C39AE /* DDMessageReviewContactsViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = C479350319178A69009C39AE /* DDMessageReviewContactsViewController.m */; }; + C479350719178A89009C39AE /* DDMessagesReviewContentViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = C479350619178A89009C39AE /* DDMessagesReviewContentViewController.m */; }; + C479350A19178CF5009C39AE /* DDMessageReviewContactsCellView.m in Sources */ = {isa = PBXBuildFile; fileRef = C479350919178CF5009C39AE /* DDMessageReviewContactsCellView.m */; }; + C479351019187782009C39AE /* DDMessagesReviewContentModule.m in Sources */ = {isa = PBXBuildFile; fileRef = C479350F19187782009C39AE /* DDMessagesReviewContentModule.m */; }; + C479351519188C50009C39AE /* message-review-last-page.png in Resources */ = {isa = PBXBuildFile; fileRef = C479351119188C50009C39AE /* message-review-last-page.png */; }; + C479351619188C50009C39AE /* message-review-last-page@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = C479351219188C50009C39AE /* message-review-last-page@2x.png */; }; + C479351719188C50009C39AE /* message-review-nextpage.png in Resources */ = {isa = PBXBuildFile; fileRef = C479351319188C50009C39AE /* message-review-nextpage.png */; }; + C479351819188C50009C39AE /* message-review-nextpage@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = C479351419188C50009C39AE /* message-review-nextpage@2x.png */; }; + C479351D19188DE4009C39AE /* message-review-double-lastpage.png in Resources */ = {isa = PBXBuildFile; fileRef = C479351919188DE4009C39AE /* message-review-double-lastpage.png */; }; + C479351E19188DE4009C39AE /* message-review-double-lastpage@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = C479351A19188DE4009C39AE /* message-review-double-lastpage@2x.png */; }; + C479351F19188DE4009C39AE /* message-review-double-nextpage.png in Resources */ = {isa = PBXBuildFile; fileRef = C479351B19188DE4009C39AE /* message-review-double-nextpage.png */; }; + C479352019188DE4009C39AE /* message-review-double-nextpage@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = C479351C19188DE4009C39AE /* message-review-double-nextpage@2x.png */; }; + C47935231918B765009C39AE /* window-titleBar-background.png in Resources */ = {isa = PBXBuildFile; fileRef = C47935211918B765009C39AE /* window-titleBar-background.png */; }; + C47935241918B765009C39AE /* window-titleBar-background@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = C47935221918B765009C39AE /* window-titleBar-background@2x.png */; }; + C47935271918B9C0009C39AE /* DDMessagesReviewWindow.m in Sources */ = {isa = PBXBuildFile; fileRef = C47935261918B9C0009C39AE /* DDMessagesReviewWindow.m */; }; + C479352A1918BD9F009C39AE /* DDMessageReviewTextView.m in Sources */ = {isa = PBXBuildFile; fileRef = C47935291918BD9F009C39AE /* DDMessageReviewTextView.m */; }; + C479352E1918E807009C39AE /* DDLoginAPI.mm in Sources */ = {isa = PBXBuildFile; fileRef = C479352D1918E807009C39AE /* DDLoginAPI.mm */; }; + C47935341918E88B009C39AE /* DDFixedGroupAPI.m in Sources */ = {isa = PBXBuildFile; fileRef = C47935331918E88B009C39AE /* DDFixedGroupAPI.m */; }; + C485913F18C73FD800DD30DD /* icon_fav.png in Resources */ = {isa = PBXBuildFile; fileRef = C485913D18C73FD800DD30DD /* icon_fav.png */; }; + C485914018C73FD800DD30DD /* icon_fav@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = C485913E18C73FD800DD30DD /* icon_fav@2x.png */; }; + C487386B18C8093D00C51541 /* lady_placeholder.png in Resources */ = {isa = PBXBuildFile; fileRef = C487386718C8093C00C51541 /* lady_placeholder.png */; }; + C487386C18C8093D00C51541 /* lady_placeholder@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = C487386818C8093C00C51541 /* lady_placeholder@2x.png */; }; + C487386D18C8093D00C51541 /* man_placeholder.png in Resources */ = {isa = PBXBuildFile; fileRef = C487386918C8093C00C51541 /* man_placeholder.png */; }; + C487386E18C8093D00C51541 /* man_placeholder@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = C487386A18C8093D00C51541 /* man_placeholder@2x.png */; }; + C487387118C814D700C51541 /* group_placeholder.png in Resources */ = {isa = PBXBuildFile; fileRef = C487386F18C814D700C51541 /* group_placeholder.png */; }; + C487387218C814D700C51541 /* group_placeholder@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = C487387018C814D700C51541 /* group_placeholder@2x.png */; }; + C48B104718D1AE9000DEF8C6 /* CrashReportManager.m in Sources */ = {isa = PBXBuildFile; fileRef = C48B104618D1AE9000DEF8C6 /* CrashReportManager.m */; }; + C48B104918D1B18500DEF8C6 /* IOKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = C48B104818D1B18500DEF8C6 /* IOKit.framework */; }; + C48D603518BC634A00F5ED30 /* DDUserDataWindowController.m in Sources */ = {isa = PBXBuildFile; fileRef = C48D603418BC634A00F5ED30 /* DDUserDataWindowController.m */; }; + C48D603A18BC670900F5ED30 /* DDUserDataModel.m in Sources */ = {isa = PBXBuildFile; fileRef = C48D603918BC670900F5ED30 /* DDUserDataModel.m */; }; + C48D604018BED99500F5ED30 /* SpellLibrary.m in Sources */ = {isa = PBXBuildFile; fileRef = C48D603F18BED99500F5ED30 /* SpellLibrary.m */; }; + C48E2F451A6224F1002F3FEB /* MTUserEntity.m in Sources */ = {isa = PBXBuildFile; fileRef = C48E2F441A6224F1002F3FEB /* MTUserEntity.m */; }; + C48E2F481A622506002F3FEB /* MTGroupEntity.m in Sources */ = {isa = PBXBuildFile; fileRef = C48E2F471A622506002F3FEB /* MTGroupEntity.m */; }; + C48E2F4E1A62258D002F3FEB /* MTGroupModule.m in Sources */ = {isa = PBXBuildFile; fileRef = C48E2F4D1A62258D002F3FEB /* MTGroupModule.m */; }; + C48E2F511A6225BA002F3FEB /* MTUserModule.m in Sources */ = {isa = PBXBuildFile; fileRef = C48E2F501A6225BA002F3FEB /* MTUserModule.m */; }; + C48E2F541A62264A002F3FEB /* DDOriginEntity.m in Sources */ = {isa = PBXBuildFile; fileRef = C48E2F531A62264A002F3FEB /* DDOriginEntity.m */; }; + C48E2F5D1A622886002F3FEB /* MTSessionEntity.m in Sources */ = {isa = PBXBuildFile; fileRef = C48E2F5C1A622886002F3FEB /* MTSessionEntity.m */; }; + C48E2F601A622899002F3FEB /* MTSessionModule.m in Sources */ = {isa = PBXBuildFile; fileRef = C48E2F5F1A622899002F3FEB /* MTSessionModule.m */; }; + C48E2F631A622BFC002F3FEB /* DDRootModule.m in Sources */ = {isa = PBXBuildFile; fileRef = C48E2F621A622BFC002F3FEB /* DDRootModule.m */; }; + C48E2F661A625A1F002F3FEB /* DDHeartBeatAPI.m in Sources */ = {isa = PBXBuildFile; fileRef = C48E2F651A625A1F002F3FEB /* DDHeartBeatAPI.m */; }; + C48E2F691A626C7F002F3FEB /* MTMessageModule.m in Sources */ = {isa = PBXBuildFile; fileRef = C48E2F681A626C7F002F3FEB /* MTMessageModule.m */; }; + C48E395B18F4E6C000C610EB /* DDCurrentUserState.m in Sources */ = {isa = PBXBuildFile; fileRef = C48E395A18F4E6C000C610EB /* DDCurrentUserState.m */; }; + C48E399E18F8EA4F00C610EB /* DDTcpClientManager.m in Sources */ = {isa = PBXBuildFile; fileRef = C48E399D18F8EA4F00C610EB /* DDTcpClientManager.m */; }; + C48E39A118F9112800C610EB /* DDClientStateMaintenanceManager.m in Sources */ = {isa = PBXBuildFile; fileRef = C48E39A018F9112800C610EB /* DDClientStateMaintenanceManager.m */; }; + C48E79E018FB861A00A1FA66 /* DDLoginWindowControllerModule.m in Sources */ = {isa = PBXBuildFile; fileRef = C48E79DF18FB861A00A1FA66 /* DDLoginWindowControllerModule.m */; }; + C48E79E618FBB28E00A1FA66 /* DDClientState.m in Sources */ = {isa = PBXBuildFile; fileRef = C48E79E518FBB28E00A1FA66 /* DDClientState.m */; }; + C48E79E918FCE31A00A1FA66 /* DDMainWindowControllerModule.m in Sources */ = {isa = PBXBuildFile; fileRef = C48E79E818FCE31A00A1FA66 /* DDMainWindowControllerModule.m */; }; + C48E79EB18FE1FAE00A1FA66 /* message.wav in Resources */ = {isa = PBXBuildFile; fileRef = C48E79EA18FE1FAE00A1FA66 /* message.wav */; }; + C48E79F018FE2AF000A1FA66 /* DDPathHelp.m in Sources */ = {isa = PBXBuildFile; fileRef = C48E79EF18FE2AF000A1FA66 /* DDPathHelp.m */; }; + C48E79F418FF686200A1FA66 /* DDApplicationUpdate.m in Sources */ = {isa = PBXBuildFile; fileRef = C48E79F318FF686200A1FA66 /* DDApplicationUpdate.m */; }; + C48E79F718FFAE7800A1FA66 /* NSImage+Addition.m in Sources */ = {isa = PBXBuildFile; fileRef = C48E79F618FFAE7800A1FA66 /* NSImage+Addition.m */; }; + C48EEE5418F0169E00FCB35B /* NotificationHelp.m in Sources */ = {isa = PBXBuildFile; fileRef = C48EEE5318F0169E00FCB35B /* NotificationHelp.m */; }; + C492F40718C2CEF4005A3AC9 /* DDAddChatGroupCell.m in Sources */ = {isa = PBXBuildFile; fileRef = C492F40618C2CEF4005A3AC9 /* DDAddChatGroupCell.m */; }; + C492F40C18C2D0F2005A3AC9 /* DDAddChatGroupModel.m in Sources */ = {isa = PBXBuildFile; fileRef = C492F40B18C2D0F2005A3AC9 /* DDAddChatGroupModel.m */; }; + C492F40F18C2E3DA005A3AC9 /* DDAddChatGroup.m in Sources */ = {isa = PBXBuildFile; fileRef = C492F40E18C2E3DA005A3AC9 /* DDAddChatGroup.m */; }; + C492F41218C2FD8A005A3AC9 /* DDAddGroupSelectedCell.m in Sources */ = {isa = PBXBuildFile; fileRef = C492F41118C2FD8A005A3AC9 /* DDAddGroupSelectedCell.m */; }; + C492F41718C30FF5005A3AC9 /* icon_check_empty.png in Resources */ = {isa = PBXBuildFile; fileRef = C492F41518C30FF5005A3AC9 /* icon_check_empty.png */; }; + C492F41818C30FF5005A3AC9 /* icon_check_empty@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = C492F41618C30FF5005A3AC9 /* icon_check_empty@2x.png */; }; + C492F41B18C31092005A3AC9 /* icon_check_filled.png in Resources */ = {isa = PBXBuildFile; fileRef = C492F41918C31092005A3AC9 /* icon_check_filled.png */; }; + C492F41C18C31092005A3AC9 /* icon_check_filled@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = C492F41A18C31092005A3AC9 /* icon_check_filled@2x.png */; }; + C4A09C8E190FC2AC00B39BF3 /* DDRecentContactsViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = C4A09C8D190FC2AC00B39BF3 /* DDRecentContactsViewController.m */; }; + C4A09C91190FC2FA00B39BF3 /* DDRecentContactsModule.m in Sources */ = {isa = PBXBuildFile; fileRef = C4A09C90190FC2FA00B39BF3 /* DDRecentContactsModule.m */; }; + C4A09C96190FC44400B39BF3 /* DDGroupViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = C4A09C95190FC44400B39BF3 /* DDGroupViewController.m */; }; + C4A09C99190FC4CA00B39BF3 /* DDGroupVCModule.m in Sources */ = {isa = PBXBuildFile; fileRef = C4A09C98190FC4CA00B39BF3 /* DDGroupVCModule.m */; }; + C4A09C9B190FC7B000B39BF3 /* DDRecentContactsViewController.xib in Resources */ = {isa = PBXBuildFile; fileRef = C4A09C9A190FC7B000B39BF3 /* DDRecentContactsViewController.xib */; }; + C4A09C9E191089A800B39BF3 /* DDRecentContactsCell.m in Sources */ = {isa = PBXBuildFile; fileRef = C4A09C9D191089A800B39BF3 /* DDRecentContactsCell.m */; }; + C4A09CA919108E7600B39BF3 /* recent-contacts-cell-background.png in Resources */ = {isa = PBXBuildFile; fileRef = C4A09C9F19108E7600B39BF3 /* recent-contacts-cell-background.png */; }; + C4A09CAA19108E7600B39BF3 /* recent-contacts-cell-background@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = C4A09CA019108E7600B39BF3 /* recent-contacts-cell-background@2x.png */; }; + C4A09CAB19108E7600B39BF3 /* search-background.png in Resources */ = {isa = PBXBuildFile; fileRef = C4A09CA119108E7600B39BF3 /* search-background.png */; }; + C4A09CAC19108E7600B39BF3 /* search-background@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = C4A09CA219108E7600B39BF3 /* search-background@2x.png */; }; + C4A09CAD19108E7600B39BF3 /* shield.png in Resources */ = {isa = PBXBuildFile; fileRef = C4A09CA319108E7600B39BF3 /* shield.png */; }; + C4A09CAE19108E7600B39BF3 /* shield@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = C4A09CA419108E7600B39BF3 /* shield@2x.png */; }; + C4A09CB119108E7600B39BF3 /* unread-count-background.png in Resources */ = {isa = PBXBuildFile; fileRef = C4A09CA719108E7600B39BF3 /* unread-count-background.png */; }; + C4A09CB219108E7600B39BF3 /* unread-count-background@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = C4A09CA819108E7600B39BF3 /* unread-count-background@2x.png */; }; + C4A09CBA1910AAC200B39BF3 /* DDGroupViewController.xib in Resources */ = {isa = PBXBuildFile; fileRef = C4A09CB91910AAC200B39BF3 /* DDGroupViewController.xib */; }; + C4A09CBD1910ABA600B39BF3 /* DDGroupCell.m in Sources */ = {isa = PBXBuildFile; fileRef = C4A09CBC1910ABA600B39BF3 /* DDGroupCell.m */; }; + C4A09CC01910D19B00B39BF3 /* DDSearchViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = C4A09CBF1910D19B00B39BF3 /* DDSearchViewController.m */; }; + C4A09CC31910D2BA00B39BF3 /* DDSearchResultCell.m in Sources */ = {isa = PBXBuildFile; fileRef = C4A09CC21910D2BA00B39BF3 /* DDSearchResultCell.m */; }; + C4A09CC61910EA2400B39BF3 /* DDAppBackgroundColorView.m in Sources */ = {isa = PBXBuildFile; fileRef = C4A09CC51910EA2400B39BF3 /* DDAppBackgroundColorView.m */; }; + C4A09CCD1910EFA800B39BF3 /* state-leave.png in Resources */ = {isa = PBXBuildFile; fileRef = C4A09CC71910EFA800B39BF3 /* state-leave.png */; }; + C4A09CCE1910EFA800B39BF3 /* state-leave@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = C4A09CC81910EFA800B39BF3 /* state-leave@2x.png */; }; + C4A09CCF1910EFA800B39BF3 /* state-offline.png in Resources */ = {isa = PBXBuildFile; fileRef = C4A09CC91910EFA800B39BF3 /* state-offline.png */; }; + C4A09CD01910EFA800B39BF3 /* state-offline@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = C4A09CCA1910EFA800B39BF3 /* state-offline@2x.png */; }; + C4A09CD11910EFA800B39BF3 /* state-online.png in Resources */ = {isa = PBXBuildFile; fileRef = C4A09CCB1910EFA800B39BF3 /* state-online.png */; }; + C4A09CD21910EFA800B39BF3 /* state-online@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = C4A09CCC1910EFA800B39BF3 /* state-online@2x.png */; }; + C4A09CD71910FB6700B39BF3 /* add-group-member.png in Resources */ = {isa = PBXBuildFile; fileRef = C4A09CD31910FB6700B39BF3 /* add-group-member.png */; }; + C4A09CD81910FB6700B39BF3 /* add-group-member@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = C4A09CD41910FB6700B39BF3 /* add-group-member@2x.png */; }; + C4A09CD91910FB6700B39BF3 /* transport-file.png in Resources */ = {isa = PBXBuildFile; fileRef = C4A09CD51910FB6700B39BF3 /* transport-file.png */; }; + C4A09CDA1910FB6700B39BF3 /* transport-file@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = C4A09CD61910FB6700B39BF3 /* transport-file@2x.png */; }; + C4A09CDF1910FED700B39BF3 /* emotion.png in Resources */ = {isa = PBXBuildFile; fileRef = C4A09CDB1910FED700B39BF3 /* emotion.png */; }; + C4A09CE01910FED700B39BF3 /* emotion@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = C4A09CDC1910FED700B39BF3 /* emotion@2x.png */; }; + C4A09CE11910FED700B39BF3 /* screen-shot.png in Resources */ = {isa = PBXBuildFile; fileRef = C4A09CDD1910FED700B39BF3 /* screen-shot.png */; }; + C4A09CE21910FED700B39BF3 /* screen-shot@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = C4A09CDE1910FED700B39BF3 /* screen-shot@2x.png */; }; + C4A6F1DF18EE4FD900A6AD61 /* StateMaintenanceManager.m in Sources */ = {isa = PBXBuildFile; fileRef = C4A6F1DE18EE4FD900A6AD61 /* StateMaintenanceManager.m */; }; + C4A6F1E318EFD61400A6AD61 /* DDLoginManager.m in Sources */ = {isa = PBXBuildFile; fileRef = C4A6F1E218EFD61400A6AD61 /* DDLoginManager.m */; }; + C4A6F1E618EFD69400A6AD61 /* DDHttpServer.m in Sources */ = {isa = PBXBuildFile; fileRef = C4A6F1E518EFD69400A6AD61 /* DDHttpServer.m */; }; + C4A6F1EC18EFD6CE00A6AD61 /* DDMsgServer.m in Sources */ = {isa = PBXBuildFile; fileRef = C4A6F1EB18EFD6CE00A6AD61 /* DDMsgServer.m */; }; + C4AB954618DAD5C9000181AD /* WhiteBackgroundView.m in Sources */ = {isa = PBXBuildFile; fileRef = C4AB954518DAD5C9000181AD /* WhiteBackgroundView.m */; }; + C4AB954B18DAE70F000181AD /* shield_gray.png in Resources */ = {isa = PBXBuildFile; fileRef = C4AB954718DAE70F000181AD /* shield_gray.png */; }; + C4AB954C18DAE70F000181AD /* shield_gray@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = C4AB954818DAE70F000181AD /* shield_gray@2x.png */; }; + C4AB954D18DAE70F000181AD /* shield_red.png in Resources */ = {isa = PBXBuildFile; fileRef = C4AB954918DAE70F000181AD /* shield_red.png */; }; + C4AB954E18DAE70F000181AD /* shield_red@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = C4AB954A18DAE70F000181AD /* shield_red@2x.png */; }; + C4AB955418DBF006000181AD /* DrawView.m in Sources */ = {isa = PBXBuildFile; fileRef = C4AB955318DBF006000181AD /* DrawView.m */; }; + C4AB95A918E16AEA000181AD /* DDSetting.m in Sources */ = {isa = PBXBuildFile; fileRef = C4AB95A818E16AEA000181AD /* DDSetting.m */; }; + C4C0724E1AA583F900C01D0D /* DDGetLastMessageIDAPI.m in Sources */ = {isa = PBXBuildFile; fileRef = C4C0724D1AA583F900C01D0D /* DDGetLastMessageIDAPI.m */; }; + C4C1CB85197E695000386AB0 /* DDModifyUserAvatarAPI.m in Sources */ = {isa = PBXBuildFile; fileRef = C4C1CB84197E695000386AB0 /* DDModifyUserAvatarAPI.m */; }; + C4C1CB88197FCB4600386AB0 /* dd_modisy_avatar@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = C4C1CB86197FCB4600386AB0 /* dd_modisy_avatar@2x.png */; }; + C4C1CB89197FCB4700386AB0 /* dd_modisy_avatar.png in Resources */ = {isa = PBXBuildFile; fileRef = C4C1CB87197FCB4600386AB0 /* dd_modisy_avatar.png */; }; + C4C472FC18EFE5EF00BC4E73 /* DDTcpServer.m in Sources */ = {isa = PBXBuildFile; fileRef = C4C472FB18EFE5EF00BC4E73 /* DDTcpServer.m */; }; + C4C926C2190DE988005B3234 /* DDContactsRowView.m in Sources */ = {isa = PBXBuildFile; fileRef = C4C926C1190DE988005B3234 /* DDContactsRowView.m */; }; + C4C926CE190F3C1D005B3234 /* background.png in Resources */ = {isa = PBXBuildFile; fileRef = C4C926C4190F3C1D005B3234 /* background.png */; }; + C4C926CF190F3C1D005B3234 /* background@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = C4C926C5190F3C1D005B3234 /* background@2x.png */; }; + C4C926D0190F3C1D005B3234 /* setting.png in Resources */ = {isa = PBXBuildFile; fileRef = C4C926C6190F3C1D005B3234 /* setting.png */; }; + C4C926D1190F3C1D005B3234 /* setting@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = C4C926C7190F3C1D005B3234 /* setting@2x.png */; }; + C4C926D4190F3C1D005B3234 /* left-bar-avatar.png in Resources */ = {isa = PBXBuildFile; fileRef = C4C926CA190F3C1D005B3234 /* left-bar-avatar.png */; }; + C4C926D5190F3C1D005B3234 /* left-bar-avatar@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = C4C926CB190F3C1D005B3234 /* left-bar-avatar@2x.png */; }; + C4C926D6190F3C1D005B3234 /* 形状-477.png in Resources */ = {isa = PBXBuildFile; fileRef = C4C926CC190F3C1D005B3234 /* 形状-477.png */; }; + C4C926D7190F3C1D005B3234 /* 形状-477@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = C4C926CD190F3C1D005B3234 /* 形状-477@2x.png */; }; + C4C926DB190F4274005B3234 /* DDGridBackgroundView.m in Sources */ = {isa = PBXBuildFile; fileRef = C4C926DA190F4274005B3234 /* DDGridBackgroundView.m */; }; + C4C926DE190F4778005B3234 /* state-background.png in Resources */ = {isa = PBXBuildFile; fileRef = C4C926DC190F4778005B3234 /* state-background.png */; }; + C4C926DF190F4778005B3234 /* state-background@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = C4C926DD190F4778005B3234 /* state-background@2x.png */; }; + C4C926EA190F4F28005B3234 /* group-selected.png in Resources */ = {isa = PBXBuildFile; fileRef = C4C926E0190F4F28005B3234 /* group-selected.png */; }; + C4C926EB190F4F28005B3234 /* group-selected@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = C4C926E1190F4F28005B3234 /* group-selected@2x.png */; }; + C4C926EC190F4F28005B3234 /* group-unselected.png in Resources */ = {isa = PBXBuildFile; fileRef = C4C926E2190F4F28005B3234 /* group-unselected.png */; }; + C4C926ED190F4F28005B3234 /* group-unselected@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = C4C926E3190F4F28005B3234 /* group-unselected@2x.png */; }; + C4C926EE190F4F28005B3234 /* left-bar-selected-background.png in Resources */ = {isa = PBXBuildFile; fileRef = C4C926E4190F4F28005B3234 /* left-bar-selected-background.png */; }; + C4C926EF190F4F28005B3234 /* left-bar-selected-background@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = C4C926E5190F4F28005B3234 /* left-bar-selected-background@2x.png */; }; + C4C926F0190F4F28005B3234 /* recent-chat-selected.png in Resources */ = {isa = PBXBuildFile; fileRef = C4C926E6190F4F28005B3234 /* recent-chat-selected.png */; }; + C4C926F1190F4F28005B3234 /* recent-chat-selected@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = C4C926E7190F4F28005B3234 /* recent-chat-selected@2x.png */; }; + C4C926F2190F4F28005B3234 /* recent-chat-unselected.png in Resources */ = {isa = PBXBuildFile; fileRef = C4C926E8190F4F28005B3234 /* recent-chat-unselected.png */; }; + C4C926F3190F4F28005B3234 /* recent-chat-unselected@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = C4C926E9190F4F28005B3234 /* recent-chat-unselected@2x.png */; }; + C4C926F6190F51C4005B3234 /* DDLeftBarViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = C4C926F5190F51C4005B3234 /* DDLeftBarViewController.m */; }; + C4C926F9190F526F005B3234 /* DDLeftBarItem.m in Sources */ = {isa = PBXBuildFile; fileRef = C4C926F8190F526F005B3234 /* DDLeftBarItem.m */; }; + C4D2EFF518B4B29A000F0B12 /* DDSearchResultCell.xib in Resources */ = {isa = PBXBuildFile; fileRef = C4D2EFF418B4B29A000F0B12 /* DDSearchResultCell.xib */; }; + C4D2EFF818B4B4C9000F0B12 /* DDSearchFieldResultCell.m in Sources */ = {isa = PBXBuildFile; fileRef = C4D2EFF718B4B4C9000F0B12 /* DDSearchFieldResultCell.m */; }; + C4D2EFFB18B70F1F000F0B12 /* NSView+Addition.m in Sources */ = {isa = PBXBuildFile; fileRef = C4D2EFFA18B70F1F000F0B12 /* NSView+Addition.m */; }; + C4E9763A196154B60009BE1E /* intranet_back.png in Resources */ = {isa = PBXBuildFile; fileRef = C4E9762C196154B60009BE1E /* intranet_back.png */; }; + C4E9763B196154B60009BE1E /* intranet_back@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = C4E9762D196154B60009BE1E /* intranet_back@2x.png */; }; + C4E9763C196154B60009BE1E /* intranet_forward.png in Resources */ = {isa = PBXBuildFile; fileRef = C4E9762E196154B60009BE1E /* intranet_forward.png */; }; + C4E9763D196154B60009BE1E /* intranet_forward@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = C4E9762F196154B60009BE1E /* intranet_forward@2x.png */; }; + C4E9763E196154B60009BE1E /* intranet_home.png in Resources */ = {isa = PBXBuildFile; fileRef = C4E97630196154B60009BE1E /* intranet_home.png */; }; + C4E9763F196154B60009BE1E /* intranet_home@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = C4E97631196154B60009BE1E /* intranet_home@2x.png */; }; + C4E97640196154B60009BE1E /* intranet_icon.png in Resources */ = {isa = PBXBuildFile; fileRef = C4E97632196154B60009BE1E /* intranet_icon.png */; }; + C4E97641196154B60009BE1E /* intranet_icon@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = C4E97633196154B60009BE1E /* intranet_icon@2x.png */; }; + C4E97642196154B60009BE1E /* intranet_refresh.png in Resources */ = {isa = PBXBuildFile; fileRef = C4E97634196154B60009BE1E /* intranet_refresh.png */; }; + C4E97643196154B60009BE1E /* intranet_refresh@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = C4E97635196154B60009BE1E /* intranet_refresh@2x.png */; }; + C4E97644196154B60009BE1E /* Intranet_unselected.png in Resources */ = {isa = PBXBuildFile; fileRef = C4E97636196154B60009BE1E /* Intranet_unselected.png */; }; + C4E97645196154B60009BE1E /* Intranet_unselected@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = C4E97637196154B60009BE1E /* Intranet_unselected@2x.png */; }; + C4E97648196163670009BE1E /* intranet_selected.png in Resources */ = {isa = PBXBuildFile; fileRef = C4E97646196163670009BE1E /* intranet_selected.png */; }; + C4E97649196163670009BE1E /* intranet_selected@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = C4E97647196163670009BE1E /* intranet_selected@2x.png */; }; + C4EBA726192D8E9C00B72723 /* No-File-transfor.png in Resources */ = {isa = PBXBuildFile; fileRef = C4EBA724192D8E9C00B72723 /* No-File-transfor.png */; }; + C4EBA727192D8E9C00B72723 /* No-File-transfor@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = C4EBA725192D8E9C00B72723 /* No-File-transfor@2x.png */; }; + C4EBA72A192D91E400B72723 /* DDUserDetailInfoAPI.m in Sources */ = {isa = PBXBuildFile; fileRef = C4EBA729192D91E400B72723 /* DDUserDetailInfoAPI.m */; }; + C4F7E5EF1907D24E006E31F3 /* DDSundriesCenter.m in Sources */ = {isa = PBXBuildFile; fileRef = C4F7E5EE1907D24E006E31F3 /* DDSundriesCenter.m */; }; + C4F90F9C1963DFE900DF2828 /* DDIntranetMessageEntity.m in Sources */ = {isa = PBXBuildFile; fileRef = C4F90F9B1963DFE900DF2828 /* DDIntranetMessageEntity.m */; }; + C4FA6BD61908E0640097849B /* DDAPISchedule.m in Sources */ = {isa = PBXBuildFile; fileRef = C4FA6BD51908E0640097849B /* DDAPISchedule.m */; }; + C4FA6BD91908F5BD0097849B /* DDSuperAPI.m in Sources */ = {isa = PBXBuildFile; fileRef = C4FA6BD81908F5BD0097849B /* DDSuperAPI.m */; }; + C4FA6BDC190909EA0097849B /* DDRecentConactsAPI.m in Sources */ = {isa = PBXBuildFile; fileRef = C4FA6BDB190909EA0097849B /* DDRecentConactsAPI.m */; }; + C4FA6BDF190B94350097849B /* DDChattingWindowManager.m in Sources */ = {isa = PBXBuildFile; fileRef = C4FA6BDE190B94350097849B /* DDChattingWindowManager.m */; }; + C4FE221A19205C1000FFB520 /* DDRemoveSessionAPI.m in Sources */ = {isa = PBXBuildFile; fileRef = C4FE221919205C1000FFB520 /* DDRemoveSessionAPI.m */; }; + C4FE221D192065CE00FFB520 /* top-session.png in Resources */ = {isa = PBXBuildFile; fileRef = C4FE221B192065CE00FFB520 /* top-session.png */; }; + C4FE221E192065CE00FFB520 /* top-session@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = C4FE221C192065CE00FFB520 /* top-session@2x.png */; }; + C4FE222119209B2300FFB520 /* DDReceiveP2PMessageAPI.m in Sources */ = {isa = PBXBuildFile; fileRef = C4FE222019209B2300FFB520 /* DDReceiveP2PMessageAPI.m */; }; + C4FE22241920B2A000FFB520 /* DDOtherFileResponseAPI.m in Sources */ = {isa = PBXBuildFile; fileRef = C4FE22231920B2A000FFB520 /* DDOtherFileResponseAPI.m */; }; + C4FE22271920B40100FFB520 /* DDAbortFileSendAPI.m in Sources */ = {isa = PBXBuildFile; fileRef = C4FE22261920B40100FFB520 /* DDAbortFileSendAPI.m */; }; + C4FE222A1920C04700FFB520 /* DDReceiveAbortFileSendAPI.m in Sources */ = {isa = PBXBuildFile; fileRef = C4FE22291920C04700FFB520 /* DDReceiveAbortFileSendAPI.m */; }; + C4FE222D1920C60300FFB520 /* DDSendOffLineFileAPI.m in Sources */ = {isa = PBXBuildFile; fileRef = C4FE222C1920C60300FFB520 /* DDSendOffLineFileAPI.m */; }; + C4FE22301920C8D700FFB520 /* DDOtherSendOfflineFileAPI.m in Sources */ = {isa = PBXBuildFile; fileRef = C4FE222F1920C8D700FFB520 /* DDOtherSendOfflineFileAPI.m */; }; + C4FE22361920CBB200FFB520 /* DDOfflineFileUploadFinishedAPI.m in Sources */ = {isa = PBXBuildFile; fileRef = C4FE22351920CBB200FFB520 /* DDOfflineFileUploadFinishedAPI.m */; }; + C4FE22391920CE5600FFB520 /* DDReceiveOtherOfflineFileUploadFinishedAPI.m in Sources */ = {isa = PBXBuildFile; fileRef = C4FE22381920CE5600FFB520 /* DDReceiveOtherOfflineFileUploadFinishedAPI.m */; }; + C4FE223C1920CF3700FFB520 /* DDAddOfflineFileAPI.m in Sources */ = {isa = PBXBuildFile; fileRef = C4FE223B1920CF3700FFB520 /* DDAddOfflineFileAPI.m */; }; + C4FE223F1920CF4A00FFB520 /* DDDeleteOfflineFileAPI.m in Sources */ = {isa = PBXBuildFile; fileRef = C4FE223E1920CF4A00FFB520 /* DDDeleteOfflineFileAPI.m */; }; + C4FE22421920DEE500FFB520 /* DDFileSendResponseAPI.m in Sources */ = {isa = PBXBuildFile; fileRef = C4FE22411920DEE500FFB520 /* DDFileSendResponseAPI.m */; }; + C4FE22451920E43600FFB520 /* DDReceiveOtherResponseAPI.m in Sources */ = {isa = PBXBuildFile; fileRef = C4FE22441920E43600FFB520 /* DDReceiveOtherResponseAPI.m */; }; + C4FE22481920EC4D00FFB520 /* DDReceiveOtherSendFileAPI.m in Sources */ = {isa = PBXBuildFile; fileRef = C4FE22471920EC4D00FFB520 /* DDReceiveOtherSendFileAPI.m */; }; + C4FE224B1920F11300FFB520 /* DDReadyReceiveFileAPI.m in Sources */ = {isa = PBXBuildFile; fileRef = C4FE224A1920F11300FFB520 /* DDReadyReceiveFileAPI.m */; }; + C4FE224E1920F35600FFB520 /* DDReceiveOtherReadyAcceptFileAPI.m in Sources */ = {isa = PBXBuildFile; fileRef = C4FE224D1920F35600FFB520 /* DDReceiveOtherReadyAcceptFileAPI.m */; }; + C4FF47381A7F4EB500B21A0D /* MTPreviewItem.m in Sources */ = {isa = PBXBuildFile; fileRef = C4FF47371A7F4EB500B21A0D /* MTPreviewItem.m */; }; + C4FF473B1A7FA0F800B21A0D /* DDReceiveGroupMemberChangedAPI.m in Sources */ = {isa = PBXBuildFile; fileRef = C4FF473A1A7FA0F800B21A0D /* DDReceiveGroupMemberChangedAPI.m */; }; + C4FF473E1A80ACA900B21A0D /* MTDraftManager.m in Sources */ = {isa = PBXBuildFile; fileRef = C4FF473D1A80ACA900B21A0D /* MTDraftManager.m */; }; + C4FF47411A80AD9100B21A0D /* MTInputHistoryManager.m in Sources */ = {isa = PBXBuildFile; fileRef = C4FF47401A80AD9100B21A0D /* MTInputHistoryManager.m */; }; + C4FF47431A81AF3700B21A0D /* msgfail.png in Resources */ = {isa = PBXBuildFile; fileRef = C4FF47421A81AF3700B21A0D /* msgfail.png */; }; + C4FF47521A823E5800B21A0D /* speexdec in Resources */ = {isa = PBXBuildFile; fileRef = C4FF47501A823E5800B21A0D /* speexdec */; }; + C4FF47531A823E5800B21A0D /* speexenc in Resources */ = {isa = PBXBuildFile; fileRef = C4FF47511A823E5800B21A0D /* speexenc */; }; + C4FF47591A83578200B21A0D /* DataOutputStream+Addition.m in Sources */ = {isa = PBXBuildFile; fileRef = C4FF47581A83578200B21A0D /* DataOutputStream+Addition.m */; }; + EF29F2BD1AB80077001FC3EE /* MTDepartmentManager.m in Sources */ = {isa = PBXBuildFile; fileRef = EF29F2BC1AB80077001FC3EE /* MTDepartmentManager.m */; }; + EF29F2C01AB81E15001FC3EE /* DDDepartmentInfoAPI.m in Sources */ = {isa = PBXBuildFile; fileRef = EF29F2BF1AB81E15001FC3EE /* DDDepartmentInfoAPI.m */; }; + EF29F2C31AB82087001FC3EE /* MTDepartmentEntity.m in Sources */ = {isa = PBXBuildFile; fileRef = EF29F2C21AB82087001FC3EE /* MTDepartmentEntity.m */; }; +/* End PBXBuildFile section */ + +/* Begin PBXBuildRule section */ + C407F20B19604CFD00ED6ED8 /* PBXBuildRule */ = { + isa = PBXBuildRule; + compilerSpec = com.apple.compilers.proxy.script; + fileType = pattern.proxy; + isEditable = 1; + outputFiles = ( + ); + script = ""; + }; +/* End PBXBuildRule section */ + +/* Begin PBXCopyFilesBuildPhase section */ + 5700BF0618A8A4880060092F /* Copy Files */ = { + isa = PBXCopyFilesBuildPhase; + buildActionMask = 12; + dstPath = ""; + dstSubfolderSpec = 10; + files = ( + 578BB18818B49ECF007C2294 /* Sparkle.framework in Copy Files */, + 57CA0F4E18D2D43F005C0B0D /* CrashReporter.framework in Copy Files */, + ); + name = "Copy Files"; + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXCopyFilesBuildPhase section */ + +/* Begin PBXFileReference section */ + 183B534018695FBA009073EC /* DDTaskManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = DDTaskManager.h; path = DDLogic/task/DDTaskManager.h; sourceTree = ""; }; + 183B534118695FBA009073EC /* DDTaskManager.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = DDTaskManager.m; path = DDLogic/task/DDTaskManager.m; sourceTree = ""; }; + 183B5369186AFB27009073EC /* FileTransferEntity.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = FileTransferEntity.h; sourceTree = ""; }; + 183B536A186AFB27009073EC /* FileTransferEntity.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = FileTransferEntity.m; sourceTree = ""; }; + 183B536F186D58C2009073EC /* TcpProtocolHeader.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = TcpProtocolHeader.h; sourceTree = ""; }; + 183B5370186D58C2009073EC /* TcpProtocolHeader.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = TcpProtocolHeader.m; sourceTree = ""; }; + 183B537E187141A6009073EC /* NSData+NSJSONSerialization.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = "NSData+NSJSONSerialization.h"; path = "utilities/Extensions/NSData+NSJSONSerialization.h"; sourceTree = ""; }; + 183B537F187141A6009073EC /* NSData+NSJSONSerialization.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = "NSData+NSJSONSerialization.m"; path = "utilities/Extensions/NSData+NSJSONSerialization.m"; sourceTree = ""; }; + 183B5381187145A6009073EC /* MGJEntity.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MGJEntity.h; sourceTree = ""; }; + 183B5382187145A6009073EC /* MGJEntity.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MGJEntity.m; sourceTree = ""; }; + 183B538418714739009073EC /* NSDictionary+MGJ.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = "NSDictionary+MGJ.h"; path = "utilities/Extensions/NSDictionary+MGJ.h"; sourceTree = ""; }; + 183B538518714739009073EC /* NSDictionary+MGJ.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = "NSDictionary+MGJ.m"; path = "utilities/Extensions/NSDictionary+MGJ.m"; sourceTree = ""; }; + 183B538D1872976D009073EC /* NSNotification+DDLogic.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = "NSNotification+DDLogic.h"; path = "utilities/Extensions/NSNotification+DDLogic.h"; sourceTree = ""; }; + 183B538E1872976D009073EC /* NSNotification+DDLogic.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = "NSNotification+DDLogic.m"; path = "utilities/Extensions/NSNotification+DDLogic.m"; sourceTree = ""; }; + 183B53901872B720009073EC /* DDModuleDataManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = DDModuleDataManager.h; path = DDLogic/module/DDModuleDataManager.h; sourceTree = ""; }; + 183B53911872B720009073EC /* DDModuleDataManager.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = DDModuleDataManager.m; path = DDLogic/module/DDModuleDataManager.m; sourceTree = ""; }; + 1861DC4C18686D54008AA109 /* DDModuleID.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = DDModuleID.h; path = DDLogic/module/DDModuleID.h; sourceTree = ""; }; + 187FAC0118685D97006ACC30 /* DDModuleManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = DDModuleManager.h; path = DDLogic/module/DDModuleManager.h; sourceTree = ""; }; + 187FAC0218685D97006ACC30 /* DDModuleManager.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = DDModuleManager.m; path = DDLogic/module/DDModuleManager.m; sourceTree = ""; }; + 187FAC0318685D97006ACC30 /* DDWatch.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = DDWatch.h; path = DDLogic/module/DDWatch.h; sourceTree = ""; }; + 187FAC0418685D97006ACC30 /* DDWatch.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = DDWatch.m; path = DDLogic/module/DDWatch.m; sourceTree = ""; }; + 187FAC0718685DE2006ACC30 /* DDTask.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = DDTask.h; path = DDLogic/task/DDTask.h; sourceTree = ""; }; + 187FAC0818685DE2006ACC30 /* DDTaskOperation.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = DDTaskOperation.h; path = DDLogic/task/DDTaskOperation.h; sourceTree = ""; }; + 187FAC0918685DE2006ACC30 /* DDTaskOperation.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = DDTaskOperation.m; path = DDLogic/task/DDTaskOperation.m; sourceTree = ""; }; + 1886E1D11850A4ED00BA092C /* DDCommonApi.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = DDCommonApi.h; path = utilities/DDCommonApi.h; sourceTree = ""; }; + 1886E1D21850A4ED00BA092C /* DDCommonApi.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = DDCommonApi.m; path = utilities/DDCommonApi.m; sourceTree = ""; }; + 1886E1D41850A65500BA092C /* AVFoundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = AVFoundation.framework; path = System/Library/Frameworks/AVFoundation.framework; sourceTree = SDKROOT; }; + 188B010E18505E8100A99E7A /* icon.icns */ = {isa = PBXFileReference; lastKnownFileType = image.icns; name = icon.icns; path = resource/icon.icns; sourceTree = ""; }; + 18906D3A18555843004B874E /* message.mp3 */ = {isa = PBXFileReference; lastKnownFileType = audio.mp3; name = message.mp3; path = resource/message.mp3; sourceTree = ""; }; + 189B0A9A187694E600C3997A /* DDSharedDuoduo.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DDSharedDuoduo.h; sourceTree = ""; }; + 189B0A9B187694E600C3997A /* DDSharedDuoduo.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = DDSharedDuoduo.m; sourceTree = ""; }; + 18A38FEF187A98BF00F3F19D /* DDMainModule.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = DDMainModule.h; path = modules/Main/DDMainModule.h; sourceTree = ""; }; + 18A38FF0187A98BF00F3F19D /* DDMainModule.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = DDMainModule.m; path = modules/Main/DDMainModule.m; sourceTree = ""; }; + 18A38FF5187AAD1A00F3F19D /* DDCommonModule.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = DDCommonModule.h; path = modules/common/DDCommonModule.h; sourceTree = ""; }; + 18A38FF6187AAD1A00F3F19D /* DDCommonModule.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = DDCommonModule.m; path = modules/common/DDCommonModule.m; sourceTree = ""; }; + 18C769F9188E444B0066AA8C /* SystemConfiguration.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = SystemConfiguration.framework; path = System/Library/Frameworks/SystemConfiguration.framework; sourceTree = SDKROOT; }; + 18C769FB188E44720066AA8C /* Reachability.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = Reachability.h; path = Libraries/Reachability/Reachability.h; sourceTree = ""; }; + 18C769FC188E44720066AA8C /* Reachability.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = Reachability.m; path = Libraries/Reachability/Reachability.m; sourceTree = ""; }; + 18FF1D16185177F700C19036 /* DDSound.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = DDSound.h; path = utilities/DDSound.h; sourceTree = ""; }; + 18FF1D17185177F700C19036 /* DDSound.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = DDSound.m; path = utilities/DDSound.m; sourceTree = ""; }; + 37E4C02C1A6CAE4600178EA8 /* MTDatabaseUtil.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MTDatabaseUtil.h; sourceTree = ""; }; + 37E4C02D1A6CAE4600178EA8 /* MTDatabaseUtil.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MTDatabaseUtil.m; sourceTree = ""; }; + 37E4C0361A6E486A00178EA8 /* MTSysConfigEntity.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MTSysConfigEntity.h; sourceTree = ""; }; + 37E4C0371A6E486A00178EA8 /* MTSysConfigEntity.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MTSysConfigEntity.m; sourceTree = ""; }; + 37E4C0391A6E487E00178EA8 /* MTSysConfigModule.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MTSysConfigModule.h; sourceTree = ""; }; + 37E4C03A1A6E487E00178EA8 /* MTSysConfigModule.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MTSysConfigModule.m; sourceTree = ""; }; + 535EC6602DDC418112EEFEF8 /* Pods.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = Pods.release.xcconfig; path = "Pods/Target Support Files/Pods/Pods.release.xcconfig"; sourceTree = ""; }; + 5700BF0818A8A4B00060092F /* Sparkle.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; path = Sparkle.framework; sourceTree = ""; }; + 5700BF0B18A8A5AD0060092F /* dsa_pub.pem */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = dsa_pub.pem; sourceTree = ""; }; + 5709F94D1848682D0096D176 /* DDImageSpreadView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = DDImageSpreadView.h; path = interface/mainWindow/DDImageSpreadView.h; sourceTree = ""; }; + 5709F94E1848682E0096D176 /* DDImageSpreadView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = DDImageSpreadView.m; path = interface/mainWindow/DDImageSpreadView.m; sourceTree = ""; }; + 5709F95018486ABB0096D176 /* toolbar_bg_theme_gray.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = toolbar_bg_theme_gray.png; path = resource/toolbar_bg_theme_gray.png; sourceTree = ""; }; + 5709F95118486ABB0096D176 /* toolbar_bg_theme_gray@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = "toolbar_bg_theme_gray@2x.png"; path = "resource/toolbar_bg_theme_gray@2x.png"; sourceTree = ""; }; + 5709F95418486DDA0096D176 /* seperator_left.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = seperator_left.png; path = resource/seperator_left.png; sourceTree = ""; }; + 5709F95518486DDA0096D176 /* seperator_left@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = "seperator_left@2x.png"; path = "resource/seperator_left@2x.png"; sourceTree = ""; }; + 5709F95618486DDA0096D176 /* seperator_right.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = seperator_right.png; path = resource/seperator_right.png; sourceTree = ""; }; + 5709F95718486DDA0096D176 /* seperator_right@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = "seperator_right@2x.png"; path = "resource/seperator_right@2x.png"; sourceTree = ""; }; + 5709F95C18486E320096D176 /* DDImageView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = DDImageView.h; path = interface/mainWindow/DDImageView.h; sourceTree = ""; }; + 5709F95D18486E320096D176 /* DDImageView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = DDImageView.m; path = interface/mainWindow/DDImageView.m; sourceTree = ""; }; + 5709F95F184871A70096D176 /* icon_conversation_highlight_theme_gray.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = icon_conversation_highlight_theme_gray.png; path = resource/icon_conversation_highlight_theme_gray.png; sourceTree = ""; }; + 5709F960184871A70096D176 /* icon_conversation_highlight_theme_gray@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = "icon_conversation_highlight_theme_gray@2x.png"; path = "resource/icon_conversation_highlight_theme_gray@2x.png"; sourceTree = ""; }; + 5709F961184871A70096D176 /* icon_conversation_theme_gray.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = icon_conversation_theme_gray.png; path = resource/icon_conversation_theme_gray.png; sourceTree = ""; }; + 5709F962184871A70096D176 /* icon_conversation_theme_gray@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = "icon_conversation_theme_gray@2x.png"; path = "resource/icon_conversation_theme_gray@2x.png"; sourceTree = ""; }; + 5709F963184871A70096D176 /* icon_organization_click_theme_gray.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = icon_organization_click_theme_gray.png; path = resource/icon_organization_click_theme_gray.png; sourceTree = ""; }; + 5709F964184871A70096D176 /* icon_organization_click_theme_gray@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = "icon_organization_click_theme_gray@2x.png"; path = "resource/icon_organization_click_theme_gray@2x.png"; sourceTree = ""; }; + 5709F965184871A70096D176 /* icon_organization_highlight_theme_gray.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = icon_organization_highlight_theme_gray.png; path = resource/icon_organization_highlight_theme_gray.png; sourceTree = ""; }; + 5709F966184871A70096D176 /* icon_organization_highlight_theme_gray@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = "icon_organization_highlight_theme_gray@2x.png"; path = "resource/icon_organization_highlight_theme_gray@2x.png"; sourceTree = ""; }; + 570D6E441839B0E100F68CB0 /* AIImageDrawingAdditions.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = AIImageDrawingAdditions.h; path = utilities/additions/AIImageDrawingAdditions.h; sourceTree = ""; }; + 570D6E451839B0E100F68CB0 /* AIImageDrawingAdditions.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = AIImageDrawingAdditions.m; path = utilities/additions/AIImageDrawingAdditions.m; sourceTree = ""; }; + 570D6E471839B24200F68CB0 /* AIImageAdditions.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = AIImageAdditions.h; path = utilities/additions/AIImageAdditions.h; sourceTree = ""; }; + 570D6E481839B24200F68CB0 /* AIImageAdditions.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = AIImageAdditions.m; path = utilities/additions/AIImageAdditions.m; sourceTree = ""; }; + 570D6E4A1839B28000F68CB0 /* AIFileManagerAdditions.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = AIFileManagerAdditions.h; path = utilities/additions/AIFileManagerAdditions.h; sourceTree = ""; }; + 570D6E4B1839B28000F68CB0 /* AIFileManagerAdditions.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = AIFileManagerAdditions.m; path = utilities/additions/AIFileManagerAdditions.m; sourceTree = ""; }; + 570D6E50183A053E00F68CB0 /* Quartz.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Quartz.framework; path = System/Library/Frameworks/Quartz.framework; sourceTree = SDKROOT; }; + 570D6E51183A053E00F68CB0 /* QuartzCore.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = QuartzCore.framework; path = System/Library/Frameworks/QuartzCore.framework; sourceTree = SDKROOT; }; + 57124E48187AAEAD006D2DCA /* DDAlertWindowController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = DDAlertWindowController.h; path = interface/altertWindow/DDAlertWindowController.h; sourceTree = ""; }; + 57124E49187AAEAD006D2DCA /* DDAlertWindowController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = DDAlertWindowController.m; path = interface/altertWindow/DDAlertWindowController.m; sourceTree = ""; }; + 57124E4A187AAEAD006D2DCA /* DDAlertWindowController.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; name = DDAlertWindowController.xib; path = interface/altertWindow/DDAlertWindowController.xib; sourceTree = ""; }; + 57124E54187E331A006D2DCA /* ImageAndTextCell.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = ImageAndTextCell.h; path = interface/chat/ImageAndTextCell.h; sourceTree = ""; }; + 57124E55187E331A006D2DCA /* ImageAndTextCell.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = ImageAndTextCell.m; path = interface/chat/ImageAndTextCell.m; sourceTree = ""; }; + 57124E57187E531D006D2DCA /* DDChattingContactListViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DDChattingContactListViewController.h; sourceTree = ""; }; + 57124E58187E531D006D2DCA /* DDChattingContactListViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = DDChattingContactListViewController.m; sourceTree = ""; }; + 57124E5A187E6E3D006D2DCA /* DDTableView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = DDTableView.h; path = interface/chat/DDTableView.h; sourceTree = ""; }; + 57124E5B187E6E3D006D2DCA /* DDTableView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = DDTableView.m; path = interface/chat/DDTableView.m; sourceTree = ""; }; + 57124E60187E743A006D2DCA /* panel_bg_theme_gray.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = panel_bg_theme_gray.png; path = resource/panel_bg_theme_gray.png; sourceTree = ""; }; + 57124E61187E743A006D2DCA /* panel_bg_theme_gray@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = "panel_bg_theme_gray@2x.png"; path = "resource/panel_bg_theme_gray@2x.png"; sourceTree = ""; }; + 57149F89184487C200DDBA25 /* EGOCache.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = EGOCache.h; sourceTree = ""; }; + 57149F8A184487C200DDBA25 /* EGOCache.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = EGOCache.m; sourceTree = ""; }; + 57149F8B184487C200DDBA25 /* EGOImageLoadConnection.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = EGOImageLoadConnection.h; sourceTree = ""; }; + 57149F8C184487C200DDBA25 /* EGOImageLoadConnection.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = EGOImageLoadConnection.m; sourceTree = ""; }; + 57149F8D184487C200DDBA25 /* EGOImageLoader.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = EGOImageLoader.h; sourceTree = ""; }; + 57149F8E184487C200DDBA25 /* EGOImageLoader.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = EGOImageLoader.m; sourceTree = ""; }; + 57149F8F184487C200DDBA25 /* EGOImageView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = EGOImageView.h; sourceTree = ""; }; + 57149F90184487C200DDBA25 /* EGOImageView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = EGOImageView.m; sourceTree = ""; }; + 57149FEF184592B700DDBA25 /* DDAutoScrollView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = DDAutoScrollView.h; path = utilities/scrollbarAutoHidding/DDAutoScrollView.h; sourceTree = ""; }; + 57149FF0184592B700DDBA25 /* DDAutoScrollView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = DDAutoScrollView.m; path = utilities/scrollbarAutoHidding/DDAutoScrollView.m; sourceTree = ""; }; + 57149FF61845D32E00DDBA25 /* CaptureView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CaptureView.h; sourceTree = ""; }; + 57149FF71845D32E00DDBA25 /* CaptureView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = CaptureView.m; sourceTree = ""; }; + 57149FF81845D32E00DDBA25 /* CaptureWindow.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CaptureWindow.h; sourceTree = ""; }; + 57149FF91845D32E00DDBA25 /* CaptureWindow.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = CaptureWindow.m; sourceTree = ""; }; + 57149FFF1845D45900DDBA25 /* Carbon.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Carbon.framework; path = System/Library/Frameworks/Carbon.framework; sourceTree = SDKROOT; }; + 5714A0011845D4D000DDBA25 /* ScreenCapture_toolbar_cancel.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = ScreenCapture_toolbar_cancel.png; path = resource/ScreenCapture_toolbar_cancel.png; sourceTree = ""; }; + 5714A0021845D4D000DDBA25 /* ScreenCapture_toolbar_ok.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = ScreenCapture_toolbar_ok.png; path = resource/ScreenCapture_toolbar_ok.png; sourceTree = ""; }; + 571CFF9B188F92D30030E02C /* DDEmotionAttachment.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = DDEmotionAttachment.h; path = interface/chat/DDEmotionAttachment.h; sourceTree = ""; }; + 571CFF9C188F92D30030E02C /* DDEmotionAttachment.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = DDEmotionAttachment.m; path = interface/chat/DDEmotionAttachment.m; sourceTree = ""; }; + 571CFF9F1890B41C0030E02C /* FMSearchTokenFieldCell.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = FMSearchTokenFieldCell.h; path = interface/mainWindow/searchField/FMSearchTokenFieldCell.h; sourceTree = ""; }; + 571CFFA01890B41C0030E02C /* FMSearchTokenFieldCell.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = FMSearchTokenFieldCell.m; path = interface/mainWindow/searchField/FMSearchTokenFieldCell.m; sourceTree = ""; }; + 571CFFA21890BD6A0030E02C /* FMSearchTokenAttachmentCell.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = FMSearchTokenAttachmentCell.h; path = interface/mainWindow/searchField/FMSearchTokenAttachmentCell.h; sourceTree = ""; }; + 571CFFA31890BD6A0030E02C /* FMSearchTokenAttachmentCell.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = FMSearchTokenAttachmentCell.m; path = interface/mainWindow/searchField/FMSearchTokenAttachmentCell.m; sourceTree = ""; }; + 571CFFA518920A010030E02C /* DDSearchFieldEditorDelegate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = DDSearchFieldEditorDelegate.h; path = interface/mainWindow/searchField/DDSearchFieldEditorDelegate.h; sourceTree = ""; }; + 571CFFA618920A010030E02C /* DDSearchFieldEditorDelegate.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = DDSearchFieldEditorDelegate.m; path = interface/mainWindow/searchField/DDSearchFieldEditorDelegate.m; sourceTree = ""; }; + 571FD9B41868190300F7476B /* tabbar_bg_theme_gray.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = tabbar_bg_theme_gray.png; path = resource/tabbar_bg_theme_gray.png; sourceTree = ""; }; + 571FD9B51868190300F7476B /* tabbar_bg_theme_gray@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = "tabbar_bg_theme_gray@2x.png"; path = "resource/tabbar_bg_theme_gray@2x.png"; sourceTree = ""; }; + 571FD9B818681A5F00F7476B /* FMSearchTokenField.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = FMSearchTokenField.h; path = interface/mainWindow/FMSearchTokenField.h; sourceTree = ""; }; + 571FD9B918681A5F00F7476B /* FMSearchTokenField.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = FMSearchTokenField.m; path = interface/mainWindow/FMSearchTokenField.m; sourceTree = ""; }; + 57285D3A18AB60F100E90EC2 /* icon_folder.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = icon_folder.png; path = resource/icon_folder.png; sourceTree = ""; }; + 57285D3B18AB60F100E90EC2 /* icon_folder@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = "icon_folder@2x.png"; path = "resource/icon_folder@2x.png"; sourceTree = ""; }; + 57285D3E18AB63BE00E90EC2 /* preference_divider.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = preference_divider.png; path = resource/preference_divider.png; sourceTree = ""; }; + 57285D3F18AB63BE00E90EC2 /* preference_divider@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = "preference_divider@2x.png"; path = "resource/preference_divider@2x.png"; sourceTree = ""; }; + 57285D4C18AB814400E90EC2 /* DDPreferenceWinController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = DDPreferenceWinController.h; path = preference/DDPreferenceWinController.h; sourceTree = ""; }; + 57285D4D18AB814400E90EC2 /* DDPreferenceWinController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = DDPreferenceWinController.m; path = preference/DDPreferenceWinController.m; sourceTree = ""; }; + 57285D4E18AB814400E90EC2 /* DDPreferenceWinController.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; name = DDPreferenceWinController.xib; path = preference/DDPreferenceWinController.xib; sourceTree = ""; }; + 57285D5118AB860E00E90EC2 /* DDUserPreferences.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = DDUserPreferences.h; path = preference/DDUserPreferences.h; sourceTree = ""; }; + 57285D5218AB860E00E90EC2 /* DDUserPreferences.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = DDUserPreferences.m; path = preference/DDUserPreferences.m; sourceTree = ""; }; + 57285D5418B19BD000E90EC2 /* DDOptionsBase.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = DDOptionsBase.h; path = preference/DDOptionsBase.h; sourceTree = ""; }; + 57285D5518B19BD000E90EC2 /* DDOptionsBase.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = DDOptionsBase.m; path = preference/DDOptionsBase.m; sourceTree = ""; }; + 572A87BB18B5ED95003E3FC8 /* icon_addcontacts_disable_theme_gray.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = icon_addcontacts_disable_theme_gray.png; path = resource/icon_addcontacts_disable_theme_gray.png; sourceTree = ""; }; + 572A87BC18B5ED96003E3FC8 /* icon_addcontacts_disable_theme_gray@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = "icon_addcontacts_disable_theme_gray@2x.png"; path = "resource/icon_addcontacts_disable_theme_gray@2x.png"; sourceTree = ""; }; + 572A87BD18B5ED96003E3FC8 /* icon_addcontacts_highlight_theme_gray.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = icon_addcontacts_highlight_theme_gray.png; path = resource/icon_addcontacts_highlight_theme_gray.png; sourceTree = ""; }; + 572A87BE18B5ED96003E3FC8 /* icon_addcontacts_highlight_theme_gray@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = "icon_addcontacts_highlight_theme_gray@2x.png"; path = "resource/icon_addcontacts_highlight_theme_gray@2x.png"; sourceTree = ""; }; + 572A87BF18B5ED96003E3FC8 /* icon_addcontacts_theme_gray.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = icon_addcontacts_theme_gray.png; path = resource/icon_addcontacts_theme_gray.png; sourceTree = ""; }; + 572A87C018B5ED96003E3FC8 /* icon_addcontacts_theme_gray@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = "icon_addcontacts_theme_gray@2x.png"; path = "resource/icon_addcontacts_theme_gray@2x.png"; sourceTree = ""; }; + 572A87E018B74E7B003E3FC8 /* DDClickCell.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = DDClickCell.h; path = interface/chat/addChatGroup/DDClickCell.h; sourceTree = ""; }; + 572A87E118B74E7B003E3FC8 /* DDClickCell.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = DDClickCell.m; path = interface/chat/addChatGroup/DDClickCell.m; sourceTree = ""; }; + 572A87E318B74E9F003E3FC8 /* DDAddChatGroupWindowController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = DDAddChatGroupWindowController.h; path = interface/chat/addChatGroup/DDAddChatGroupWindowController.h; sourceTree = ""; }; + 572A87E418B74E9F003E3FC8 /* DDAddChatGroupWindowController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = DDAddChatGroupWindowController.m; path = interface/chat/addChatGroup/DDAddChatGroupWindowController.m; sourceTree = ""; }; + 572A87E518B74E9F003E3FC8 /* DDAddChatGroupWindowController.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; name = DDAddChatGroupWindowController.xib; path = interface/chat/addChatGroup/DDAddChatGroupWindowController.xib; sourceTree = ""; }; + 572A87E818B75A21003E3FC8 /* icon_folder_h21.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = icon_folder_h21.png; path = resource/icon_folder_h21.png; sourceTree = ""; }; + 572A87E918B75A21003E3FC8 /* icon_folder_h21@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = "icon_folder_h21@2x.png"; path = "resource/icon_folder_h21@2x.png"; sourceTree = ""; }; + 572A87EC18B75B04003E3FC8 /* icon_user_away_h28.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = icon_user_away_h28.png; path = resource/icon_user_away_h28.png; sourceTree = ""; }; + 572A87ED18B75B04003E3FC8 /* icon_user_away_h28@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = "icon_user_away_h28@2x.png"; path = "resource/icon_user_away_h28@2x.png"; sourceTree = ""; }; + 572A87EE18B75B04003E3FC8 /* icon_user_female_away_h28.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = icon_user_female_away_h28.png; path = resource/icon_user_female_away_h28.png; sourceTree = ""; }; + 572A87EF18B75B04003E3FC8 /* icon_user_female_away_h28@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = "icon_user_female_away_h28@2x.png"; path = "resource/icon_user_female_away_h28@2x.png"; sourceTree = ""; }; + 572A87F018B75B04003E3FC8 /* icon_user_female_h28.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = icon_user_female_h28.png; path = resource/icon_user_female_h28.png; sourceTree = ""; }; + 572A87F118B75B04003E3FC8 /* icon_user_female_h28@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = "icon_user_female_h28@2x.png"; path = "resource/icon_user_female_h28@2x.png"; sourceTree = ""; }; + 572A87F218B75B04003E3FC8 /* icon_user_h28.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = icon_user_h28.png; path = resource/icon_user_h28.png; sourceTree = ""; }; + 572A87F318B75B04003E3FC8 /* icon_user_h28@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = "icon_user_h28@2x.png"; path = "resource/icon_user_h28@2x.png"; sourceTree = ""; }; + 572A87F418B75B04003E3FC8 /* icon_user_offline_h28.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = icon_user_offline_h28.png; path = resource/icon_user_offline_h28.png; sourceTree = ""; }; + 572A87F518B75B04003E3FC8 /* icon_user_offline_h28@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = "icon_user_offline_h28@2x.png"; path = "resource/icon_user_offline_h28@2x.png"; sourceTree = ""; }; + 572A880118B773EF003E3FC8 /* BaseNode.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = BaseNode.h; sourceTree = ""; }; + 572A880218B773EF003E3FC8 /* BaseNode.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = BaseNode.m; sourceTree = ""; }; + 572A880318B773EF003E3FC8 /* ChildNode.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ChildNode.h; sourceTree = ""; }; + 572A880418B773EF003E3FC8 /* ChildNode.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ChildNode.m; sourceTree = ""; }; + 5733D827184F284400737695 /* DDWindowAdditions.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = DDWindowAdditions.h; path = utilities/additions/DDWindowAdditions.h; sourceTree = ""; }; + 5733D828184F284400737695 /* DDWindowAdditions.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = DDWindowAdditions.m; path = utilities/additions/DDWindowAdditions.m; sourceTree = ""; }; + 5733D82A184F2C4A00737695 /* AIAttributedStringAdditions.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = AIAttributedStringAdditions.h; path = utilities/additions/AIAttributedStringAdditions.h; sourceTree = ""; }; + 5733D82B184F2C4A00737695 /* AIAttributedStringAdditions.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = AIAttributedStringAdditions.m; path = utilities/additions/AIAttributedStringAdditions.m; sourceTree = ""; }; + 5733D82D184F2D1600737695 /* AIColorAdditions.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = AIColorAdditions.h; path = utilities/additions/AIColorAdditions.h; sourceTree = ""; }; + 5733D82E184F2D1600737695 /* AIColorAdditions.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = AIColorAdditions.m; path = utilities/additions/AIColorAdditions.m; sourceTree = ""; }; + 5733D830184F2DFF00737695 /* AITextAttributes.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = AITextAttributes.h; path = utilities/additions/AITextAttributes.h; sourceTree = ""; }; + 5733D831184F2DFF00737695 /* AITextAttributes.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = AITextAttributes.m; path = utilities/additions/AITextAttributes.m; sourceTree = ""; }; + 5733D833184F2E4D00737695 /* AIFontManagerAdditions.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = AIFontManagerAdditions.h; path = utilities/additions/AIFontManagerAdditions.h; sourceTree = ""; }; + 5733D834184F2E4D00737695 /* AIFontManagerAdditions.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = AIFontManagerAdditions.m; path = utilities/additions/AIFontManagerAdditions.m; sourceTree = ""; }; + 5733D836184F317200737695 /* AITextAttachmentExtension.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = AITextAttachmentExtension.h; path = utilities/additions/AITextAttachmentExtension.h; sourceTree = ""; }; + 5733D837184F317200737695 /* AITextAttachmentExtension.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = AITextAttachmentExtension.m; path = utilities/additions/AITextAttachmentExtension.m; sourceTree = ""; }; + 5733D83C184F326600737695 /* AITextAttachmentAdditions.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = AITextAttachmentAdditions.h; path = utilities/additions/AITextAttachmentAdditions.h; sourceTree = ""; }; + 5733D83D184F326600737695 /* AITextAttachmentAdditions.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = AITextAttachmentAdditions.m; path = utilities/additions/AITextAttachmentAdditions.m; sourceTree = ""; }; + 5733D83F184F33F500737695 /* AIPasteboardAdditions.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = AIPasteboardAdditions.h; path = utilities/additions/AIPasteboardAdditions.h; sourceTree = ""; }; + 5733D840184F33F500737695 /* AIPasteboardAdditions.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = AIPasteboardAdditions.m; path = utilities/additions/AIPasteboardAdditions.m; sourceTree = ""; }; + 5738472F1820CDA000443653 /* TeamTalk.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = TeamTalk.app; sourceTree = BUILT_PRODUCTS_DIR; }; + 573847321820CDA000443653 /* Cocoa.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Cocoa.framework; path = System/Library/Frameworks/Cocoa.framework; sourceTree = SDKROOT; }; + 573847351820CDA000443653 /* AppKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = AppKit.framework; path = System/Library/Frameworks/AppKit.framework; sourceTree = SDKROOT; }; + 573847361820CDA000443653 /* CoreData.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreData.framework; path = System/Library/Frameworks/CoreData.framework; sourceTree = SDKROOT; }; + 573847371820CDA000443653 /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = System/Library/Frameworks/Foundation.framework; sourceTree = SDKROOT; }; + 5738473A1820CDA000443653 /* TeamTalk-Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = "TeamTalk-Info.plist"; sourceTree = ""; }; + 5738473C1820CDA000443653 /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/InfoPlist.strings; sourceTree = ""; }; + 5738473E1820CDA000443653 /* main.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = ""; }; + 573847401820CDA000443653 /* TeamTalk-Prefix.pch */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "TeamTalk-Prefix.pch"; sourceTree = ""; }; + 573847421820CDA000443653 /* en */ = {isa = PBXFileReference; lastKnownFileType = text.rtf; name = en; path = en.lproj/Credits.rtf; sourceTree = ""; }; + 573847441820CDA000443653 /* DDAppDelegate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = DDAppDelegate.h; sourceTree = ""; }; + 573847451820CDA000443653 /* DDAppDelegate.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = DDAppDelegate.m; sourceTree = ""; }; + 573847481820CDA000443653 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = Base; path = Base.lproj/MainMenu.xib; sourceTree = ""; }; + 5738474A1820CDA000443653 /* Images.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Images.xcassets; sourceTree = ""; }; + 573847581820CDA000443653 /* TeamTalkTests-Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = "TeamTalkTests-Info.plist"; sourceTree = ""; }; + 5738475A1820CDA000443653 /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/InfoPlist.strings; sourceTree = ""; }; + 5738475C1820CDA000443653 /* TeamTalkTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = TeamTalkTests.m; sourceTree = ""; }; + 573847691820CE9900443653 /* MessageEntity.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MessageEntity.h; sourceTree = ""; }; + 5738476A1820CE9900443653 /* MessageEntity.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MessageEntity.m; sourceTree = ""; }; + 5738476D1820CE9900443653 /* DataInputStream.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = DataInputStream.h; path = mtalk/DataInputStream.h; sourceTree = ""; }; + 5738476E1820CE9900443653 /* DataInputStream.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = DataInputStream.m; path = mtalk/DataInputStream.m; sourceTree = ""; }; + 5738476F1820CE9900443653 /* DataOutputStream.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = DataOutputStream.h; path = mtalk/DataOutputStream.h; sourceTree = ""; }; + 573847701820CE9900443653 /* DataOutputStream.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = DataOutputStream.m; path = mtalk/DataOutputStream.m; sourceTree = ""; }; + 5738477D1820CE9900443653 /* NSStream+NSStreamAddition.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "NSStream+NSStreamAddition.h"; sourceTree = ""; }; + 5738477E1820CE9900443653 /* NSStream+NSStreamAddition.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "NSStream+NSStreamAddition.m"; sourceTree = ""; }; + 573847841820CE9900443653 /* SendBuffer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = SendBuffer.h; path = ../util/SendBuffer.h; sourceTree = ""; }; + 573847851820CE9900443653 /* SendBuffer.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = SendBuffer.m; path = ../util/SendBuffer.m; sourceTree = ""; }; + 5738479C1820D80E00443653 /* DDWindowController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = DDWindowController.h; path = interface/DDWindowController.h; sourceTree = ""; }; + 5738479D1820D80E00443653 /* DDWindowController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = DDWindowController.m; path = interface/DDWindowController.m; sourceTree = ""; }; + 573AF6021A67FA3A00B6D3B8 /* MTScreenCaptureModule.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MTScreenCaptureModule.h; sourceTree = ""; }; + 573AF6031A67FA3A00B6D3B8 /* MTScreenCaptureModule.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MTScreenCaptureModule.m; sourceTree = ""; }; + 573AF6051A67FED000B6D3B8 /* LoginEntity.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = LoginEntity.h; sourceTree = ""; }; + 573AF6061A67FED000B6D3B8 /* LoginEntity.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = LoginEntity.m; sourceTree = ""; }; + 5741BC2A1862E540003F2667 /* aio_recentsession_unreadmsg_selected_wide.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = aio_recentsession_unreadmsg_selected_wide.png; path = resource/aio_recentsession_unreadmsg_selected_wide.png; sourceTree = ""; }; + 5741BC2B1862E540003F2667 /* aio_recentsession_unreadmsg_selected_wide@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = "aio_recentsession_unreadmsg_selected_wide@2x.png"; path = "resource/aio_recentsession_unreadmsg_selected_wide@2x.png"; sourceTree = ""; }; + 5741BC2C1862E540003F2667 /* aio_recentsession_unreadmsg_selected.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = aio_recentsession_unreadmsg_selected.png; path = resource/aio_recentsession_unreadmsg_selected.png; sourceTree = ""; }; + 5741BC2D1862E540003F2667 /* aio_recentsession_unreadmsg_selected@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = "aio_recentsession_unreadmsg_selected@2x.png"; path = "resource/aio_recentsession_unreadmsg_selected@2x.png"; sourceTree = ""; }; + 5741BC2E1862E540003F2667 /* aio_recentsession_unreadmsg_wide.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = aio_recentsession_unreadmsg_wide.png; path = resource/aio_recentsession_unreadmsg_wide.png; sourceTree = ""; }; + 5741BC2F1862E540003F2667 /* aio_recentsession_unreadmsg_wide@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = "aio_recentsession_unreadmsg_wide@2x.png"; path = "resource/aio_recentsession_unreadmsg_wide@2x.png"; sourceTree = ""; }; + 5741BC301862E540003F2667 /* aio_recentsession_unreadmsg.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = aio_recentsession_unreadmsg.png; path = resource/aio_recentsession_unreadmsg.png; sourceTree = ""; }; + 5741BC311862E540003F2667 /* aio_recentsession_unreadmsg@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = "aio_recentsession_unreadmsg@2x.png"; path = "resource/aio_recentsession_unreadmsg@2x.png"; sourceTree = ""; }; + 5743BF39183DB68D001448FB /* duoduo.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = duoduo.png; path = TeamTalk/resource/duoduo.png; sourceTree = SOURCE_ROOT; }; + 576BA9651876D0BB002B40EC /* DDInterfaceController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = DDInterfaceController.h; path = interface/DDInterfaceController.h; sourceTree = ""; }; + 576BA9661876D0BB002B40EC /* DDInterfaceController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = DDInterfaceController.m; path = interface/DDInterfaceController.m; sourceTree = ""; }; + 576CE67718D0764B00DEBCD5 /* icon_send_file_gray.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = icon_send_file_gray.png; path = resource/icon_send_file_gray.png; sourceTree = ""; }; + 576CE67818D0764B00DEBCD5 /* icon_send_file_gray@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = "icon_send_file_gray@2x.png"; path = "resource/icon_send_file_gray@2x.png"; sourceTree = ""; }; + 576CE67918D0764B00DEBCD5 /* icon_send_file_highlight.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = icon_send_file_highlight.png; path = resource/icon_send_file_highlight.png; sourceTree = ""; }; + 576CE67A18D0764B00DEBCD5 /* icon_send_file_highlight@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = "icon_send_file_highlight@2x.png"; path = "resource/icon_send_file_highlight@2x.png"; sourceTree = ""; }; + 576CE6CB18D1B68B00DEBCD5 /* icon_refresh_arrow_down.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = icon_refresh_arrow_down.png; path = resource/icon_refresh_arrow_down.png; sourceTree = ""; }; + 576CE6CC18D1B68B00DEBCD5 /* icon_refresh_arrow_down@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = "icon_refresh_arrow_down@2x.png"; path = "resource/icon_refresh_arrow_down@2x.png"; sourceTree = ""; }; + 576CE6CD18D1B68B00DEBCD5 /* icon_refresh_arrow.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = icon_refresh_arrow.png; path = resource/icon_refresh_arrow.png; sourceTree = ""; }; + 576CE6CE18D1B68B00DEBCD5 /* icon_refresh_arrow@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = "icon_refresh_arrow@2x.png"; path = "resource/icon_refresh_arrow@2x.png"; sourceTree = ""; }; + 5771F13F1A7E5D0C003EDC6A /* MTGroupChangeMemberAPI.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MTGroupChangeMemberAPI.h; sourceTree = ""; }; + 5771F1401A7E5D0C003EDC6A /* MTGroupChangeMemberAPI.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MTGroupChangeMemberAPI.m; sourceTree = ""; }; + 5772C9C618D00B9B008FE09F /* pull-to-refresh-arrow.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = "pull-to-refresh-arrow.png"; path = "resource/pull-to-refresh-arrow.png"; sourceTree = ""; }; + 5772C9C718D00B9B008FE09F /* release-to-refresh.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = "release-to-refresh.png"; path = "resource/release-to-refresh.png"; sourceTree = ""; }; + 5772C9CA18D00CBD008FE09F /* icon_close.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = icon_close.png; path = resource/icon_close.png; sourceTree = ""; }; + 5772C9CC18D00E62008FE09F /* icon_statusbar.tif */ = {isa = PBXFileReference; lastKnownFileType = image.tiff; name = icon_statusbar.tif; path = resource/icon_statusbar.tif; sourceTree = ""; }; + 5772C9CD18D00E62008FE09F /* tab_bg.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = tab_bg.png; path = resource/tab_bg.png; sourceTree = ""; }; + 577BB7FB1A64F78E00264086 /* IMBaseDefine.pb.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = IMBaseDefine.pb.h; sourceTree = ""; }; + 577BB7FC1A64F78E00264086 /* IMBaseDefine.pb.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = IMBaseDefine.pb.m; sourceTree = ""; }; + 577BB7FD1A64F78E00264086 /* IMBuddy.pb.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = IMBuddy.pb.h; sourceTree = ""; }; + 577BB7FE1A64F78E00264086 /* IMBuddy.pb.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = IMBuddy.pb.m; sourceTree = ""; }; + 577BB7FF1A64F78E00264086 /* IMGroup.pb.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = IMGroup.pb.h; sourceTree = ""; }; + 577BB8001A64F78E00264086 /* IMGroup.pb.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = IMGroup.pb.m; sourceTree = ""; }; + 577BB8011A64F78E00264086 /* IMLogin.pb.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = IMLogin.pb.h; sourceTree = ""; }; + 577BB8021A64F78E00264086 /* IMLogin.pb.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = IMLogin.pb.m; sourceTree = ""; }; + 577BB8031A64F78E00264086 /* IMMessage.pb.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = IMMessage.pb.h; sourceTree = ""; }; + 577BB8041A64F78E00264086 /* IMMessage.pb.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = IMMessage.pb.m; sourceTree = ""; }; + 577BB8051A64F78E00264086 /* IMOther.pb.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = IMOther.pb.h; sourceTree = ""; }; + 577BB8061A64F78E00264086 /* IMOther.pb.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = IMOther.pb.m; sourceTree = ""; }; + 577BB8071A64F78E00264086 /* IMSwitchService.pb.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = IMSwitchService.pb.h; sourceTree = ""; }; + 577BB8081A64F78E00264086 /* IMSwitchService.pb.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = IMSwitchService.pb.m; sourceTree = ""; }; + 577BB8091A64F78E00264086 /* IMXIAOT.pb.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = IMXIAOT.pb.h; sourceTree = ""; }; + 577BB80A1A64F78E00264086 /* IMXIAOT.pb.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = IMXIAOT.pb.m; sourceTree = ""; }; + 577C167E18474005009718D7 /* DDMainWindow.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; name = DDMainWindow.xib; path = interface/mainWindow/DDMainWindow.xib; sourceTree = ""; }; + 577C168018474317009718D7 /* DDMainWindowController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = DDMainWindowController.h; path = interface/mainWindow/DDMainWindowController.h; sourceTree = ""; }; + 577C168118474317009718D7 /* DDMainWindowController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = DDMainWindowController.m; path = interface/mainWindow/DDMainWindowController.m; sourceTree = ""; }; + 577C168318474649009718D7 /* icon_online.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = icon_online.png; path = resource/icon_online.png; sourceTree = ""; }; + 577C168418474649009718D7 /* icon_online@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = "icon_online@2x.png"; path = "resource/icon_online@2x.png"; sourceTree = ""; }; + 577C168718474669009718D7 /* icon_user_h51.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = icon_user_h51.png; path = resource/icon_user_h51.png; sourceTree = ""; }; + 577C168818474669009718D7 /* icon_user_h51@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = "icon_user_h51@2x.png"; path = "resource/icon_user_h51@2x.png"; sourceTree = ""; }; + 577C168B184749A1009718D7 /* icon_user_h51.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = icon_user_h51.png; path = resource/icon_user_h51.png; sourceTree = ""; }; + 577C168C184749A1009718D7 /* icon_user_h51@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = "icon_user_h51@2x.png"; path = "resource/icon_user_h51@2x.png"; sourceTree = ""; }; + 577C168F18475857009718D7 /* DDTabItemView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = DDTabItemView.h; path = interface/mainWindow/DDTabItemView.h; sourceTree = ""; }; + 577C169018475857009718D7 /* DDTabItemView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = DDTabItemView.m; path = interface/mainWindow/DDTabItemView.m; sourceTree = ""; }; + 577C169218476804009718D7 /* DDMainWindow.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = DDMainWindow.h; path = interface/DDMainWindow.h; sourceTree = ""; }; + 577C169318476804009718D7 /* DDMainWindow.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = DDMainWindow.m; path = interface/DDMainWindow.m; sourceTree = ""; }; + 578D5E9E187EC0C600568EE6 /* icon_offline.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = icon_offline.png; path = resource/icon_offline.png; sourceTree = ""; }; + 578D5E9F187EC0C600568EE6 /* icon_offline@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = "icon_offline@2x.png"; path = "resource/icon_offline@2x.png"; sourceTree = ""; }; + 578D5EA2187EC0E600568EE6 /* icon_away.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = icon_away.png; path = resource/icon_away.png; sourceTree = ""; }; + 578D5EA3187EC0E600568EE6 /* icon_away@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = "icon_away@2x.png"; path = "resource/icon_away@2x.png"; sourceTree = ""; }; + 578D5EAA187FC44A00568EE6 /* DDChattingHeadViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = DDChattingHeadViewController.h; path = interface/chat/DDChattingHeadViewController.h; sourceTree = ""; }; + 578D5EAB187FC44A00568EE6 /* DDChattingHeadViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = DDChattingHeadViewController.m; path = interface/chat/DDChattingHeadViewController.m; sourceTree = ""; }; + 578D5EAD188383EE00568EE6 /* DDImageMessage.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = DDImageMessage.h; path = interface/chat/DDImageMessage.h; sourceTree = ""; }; + 578D5EAE188383EE00568EE6 /* DDImageMessage.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = DDImageMessage.m; path = interface/chat/DDImageMessage.m; sourceTree = ""; }; + 579E54741A67C3B4003031A1 /* DDHttpEntity.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = DDHttpEntity.h; path = modules/Http/DDHttpEntity.h; sourceTree = ""; }; + 579E54751A67C3B4003031A1 /* DDHttpEntity.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = DDHttpEntity.m; path = modules/Http/DDHttpEntity.m; sourceTree = ""; }; + 579E54761A67C3B4003031A1 /* DDHttpModule.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = DDHttpModule.h; path = modules/Http/DDHttpModule.h; sourceTree = ""; }; + 579E54771A67C3B4003031A1 /* DDHttpModule.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = DDHttpModule.m; path = modules/Http/DDHttpModule.m; sourceTree = ""; }; + 579E547A1A67C426003031A1 /* DDLogic.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = DDLogic.h; path = DDLogic/DDLogic.h; sourceTree = ""; }; + 579E547B1A67C426003031A1 /* DDLogic.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = DDLogic.m; path = DDLogic/DDLogic.m; sourceTree = ""; }; + 579E547C1A67C426003031A1 /* DDLogicProtocol.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = DDLogicProtocol.h; path = DDLogic/DDLogicProtocol.h; sourceTree = ""; }; + 579E547E1A67C5D9003031A1 /* MGJMTalkIMessageHanlder.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MGJMTalkIMessageHanlder.h; sourceTree = ""; }; + 57A4B5531A722E1700E16CBC /* MTChattingInputView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = MTChattingInputView.h; path = modules/session/MTChattingInputView.h; sourceTree = ""; }; + 57A4B5541A722E1700E16CBC /* MTChattingInputView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = MTChattingInputView.m; path = modules/session/MTChattingInputView.m; sourceTree = ""; }; + 57AB317B18287E6800B7766E /* DDKeychain.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = DDKeychain.h; path = utilities/keychainAccess/DDKeychain.h; sourceTree = ""; }; + 57AB317C18287E6800B7766E /* DDKeychain.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = DDKeychain.m; path = utilities/keychainAccess/DDKeychain.m; sourceTree = ""; }; + 57AB317E1828816100B7766E /* Security.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Security.framework; path = System/Library/Frameworks/Security.framework; sourceTree = SDKROOT; }; + 57AB4F0F1821EAD500603621 /* NSEvent+DDEventAdditions.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = "NSEvent+DDEventAdditions.h"; path = "utilities/additions/NSEvent+DDEventAdditions.h"; sourceTree = ""; }; + 57AB4F101821EAD500603621 /* NSEvent+DDEventAdditions.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = "NSEvent+DDEventAdditions.m"; path = "utilities/additions/NSEvent+DDEventAdditions.m"; sourceTree = ""; }; + 57AB4F121821EFBC00603621 /* NSFileManager+DDFileManagerAdditions.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = "NSFileManager+DDFileManagerAdditions.h"; path = "utilities/additions/NSFileManager+DDFileManagerAdditions.h"; sourceTree = ""; }; + 57AB4F131821EFBC00603621 /* NSFileManager+DDFileManagerAdditions.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = "NSFileManager+DDFileManagerAdditions.m"; path = "utilities/additions/NSFileManager+DDFileManagerAdditions.m"; sourceTree = ""; }; + 57AB4F151821F00E00603621 /* NSString+DDStringAdditions.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = "NSString+DDStringAdditions.h"; path = "utilities/additions/NSString+DDStringAdditions.h"; sourceTree = ""; }; + 57AB4F161821F00E00603621 /* NSString+DDStringAdditions.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = "NSString+DDStringAdditions.m"; path = "utilities/additions/NSString+DDStringAdditions.m"; sourceTree = ""; }; + 57AF22881820F2EF00758483 /* DDLoginWindowController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = DDLoginWindowController.h; path = "interface/login window/DDLoginWindowController.h"; sourceTree = ""; }; + 57AF22891820F2EF00758483 /* DDLoginWindowController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = DDLoginWindowController.m; path = "interface/login window/DDLoginWindowController.m"; sourceTree = ""; }; + 57AF228B1820F31600758483 /* LoginSelect.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; name = LoginSelect.xib; path = "interface/login window/LoginSelect.xib"; sourceTree = ""; }; + 57AF2290182101B000758483 /* DDDuoduoProtocol.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DDDuoduoProtocol.h; sourceTree = ""; }; + 57AF2293182108E300758483 /* DDDictionaryAdditions.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = DDDictionaryAdditions.h; path = utilities/additions/DDDictionaryAdditions.h; sourceTree = ""; }; + 57AF2294182108E300758483 /* DDDictionaryAdditions.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = DDDictionaryAdditions.m; path = utilities/additions/DDDictionaryAdditions.m; sourceTree = ""; }; + 57AF229618210D8100758483 /* DDSharedWriterQueue.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = DDSharedWriterQueue.h; path = utilities/additions/DDSharedWriterQueue.h; sourceTree = ""; }; + 57AF229718210D8100758483 /* DDSharedWriterQueue.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = DDSharedWriterQueue.m; path = utilities/additions/DDSharedWriterQueue.m; sourceTree = ""; }; + 57AF72B918683E4000C06257 /* tab_bg.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = tab_bg.png; path = resource/tab_bg.png; sourceTree = ""; }; + 57B2A60918273BD2000A16FD /* duoduo.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = duoduo.png; path = resource/duoduo.png; sourceTree = ""; }; + 57B3901E18349DA6007CD3E0 /* AIBezierPathAdditions.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = AIBezierPathAdditions.h; path = utilities/additions/AIBezierPathAdditions.h; sourceTree = ""; }; + 57B3901F18349DA6007CD3E0 /* AIBezierPathAdditions.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = AIBezierPathAdditions.m; path = utilities/additions/AIBezierPathAdditions.m; sourceTree = ""; }; + 57B390241834A970007CD3E0 /* DDImageCollectionView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = DDImageCollectionView.h; path = utilities/funNewControls/gridIphotoStyleView/DDImageCollectionView.h; sourceTree = ""; }; + 57B390251834A970007CD3E0 /* DDImageCollectionView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = DDImageCollectionView.m; path = utilities/funNewControls/gridIphotoStyleView/DDImageCollectionView.m; sourceTree = ""; }; + 57B390271834ACB5007CD3E0 /* AIMathCompatibility.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = AIMathCompatibility.h; path = utilities/additions/AIMathCompatibility.h; sourceTree = ""; }; + 57B3902B1834B6EC007CD3E0 /* AIStringUtilities.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = AIStringUtilities.h; path = utilities/additions/AIStringUtilities.h; sourceTree = ""; }; + 57B3ACE718C0ACDD00F50C8F /* DDChattingViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = DDChattingViewController.m; path = interface/chat/DDChattingViewController.m; sourceTree = ""; }; + 57B6230B183072FB00F2B249 /* NSObject+SBJson.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "NSObject+SBJson.h"; sourceTree = ""; }; + 57B6230C183072FB00F2B249 /* NSObject+SBJson.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "NSObject+SBJson.m"; sourceTree = ""; }; + 57B6230D183072FB00F2B249 /* SBJson.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SBJson.h; sourceTree = ""; }; + 57B6230E183072FB00F2B249 /* SBJsonParser.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SBJsonParser.h; sourceTree = ""; }; + 57B6230F183072FB00F2B249 /* SBJsonParser.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SBJsonParser.m; sourceTree = ""; }; + 57B62310183072FB00F2B249 /* SBJsonStreamParser.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SBJsonStreamParser.h; sourceTree = ""; }; + 57B62311183072FB00F2B249 /* SBJsonStreamParser.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SBJsonStreamParser.m; sourceTree = ""; }; + 57B62312183072FB00F2B249 /* SBJsonStreamParserAccumulator.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SBJsonStreamParserAccumulator.h; sourceTree = ""; }; + 57B62313183072FB00F2B249 /* SBJsonStreamParserAccumulator.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SBJsonStreamParserAccumulator.m; sourceTree = ""; }; + 57B62314183072FB00F2B249 /* SBJsonStreamParserAdapter.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SBJsonStreamParserAdapter.h; sourceTree = ""; }; + 57B62315183072FB00F2B249 /* SBJsonStreamParserAdapter.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SBJsonStreamParserAdapter.m; sourceTree = ""; }; + 57B62316183072FB00F2B249 /* SBJsonStreamParserState.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SBJsonStreamParserState.h; sourceTree = ""; }; + 57B62317183072FB00F2B249 /* SBJsonStreamParserState.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SBJsonStreamParserState.m; sourceTree = ""; }; + 57B62318183072FB00F2B249 /* SBJsonStreamWriter.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SBJsonStreamWriter.h; sourceTree = ""; }; + 57B62319183072FB00F2B249 /* SBJsonStreamWriter.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SBJsonStreamWriter.m; sourceTree = ""; }; + 57B6231A183072FB00F2B249 /* SBJsonStreamWriterAccumulator.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SBJsonStreamWriterAccumulator.h; sourceTree = ""; }; + 57B6231B183072FB00F2B249 /* SBJsonStreamWriterAccumulator.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SBJsonStreamWriterAccumulator.m; sourceTree = ""; }; + 57B6231C183072FB00F2B249 /* SBJsonStreamWriterState.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SBJsonStreamWriterState.h; sourceTree = ""; }; + 57B6231D183072FB00F2B249 /* SBJsonStreamWriterState.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SBJsonStreamWriterState.m; sourceTree = ""; }; + 57B6231E183072FB00F2B249 /* SBJsonTokeniser.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SBJsonTokeniser.h; sourceTree = ""; }; + 57B6231F183072FB00F2B249 /* SBJsonTokeniser.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SBJsonTokeniser.m; sourceTree = ""; }; + 57B62320183072FB00F2B249 /* SBJsonUTF8Stream.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SBJsonUTF8Stream.h; sourceTree = ""; }; + 57B62321183072FB00F2B249 /* SBJsonUTF8Stream.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SBJsonUTF8Stream.m; sourceTree = ""; }; + 57B62322183072FB00F2B249 /* SBJsonWriter.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SBJsonWriter.h; sourceTree = ""; }; + 57B62323183072FB00F2B249 /* SBJsonWriter.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SBJsonWriter.m; sourceTree = ""; }; + 57B95BB21A7CCEE8004DFB22 /* MASShortcut.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = MASShortcut.h; path = shortcut/MASShortcut.h; sourceTree = ""; }; + 57B95BB31A7CCEE8004DFB22 /* MASShortcut.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = MASShortcut.m; path = shortcut/MASShortcut.m; sourceTree = ""; }; + 57B95BB41A7CCEE8004DFB22 /* MASShortcut+Monitoring.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = "MASShortcut+Monitoring.h"; path = "shortcut/MASShortcut+Monitoring.h"; sourceTree = ""; }; + 57B95BB51A7CCEE8004DFB22 /* MASShortcut+Monitoring.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = "MASShortcut+Monitoring.m"; path = "shortcut/MASShortcut+Monitoring.m"; sourceTree = ""; }; + 57B95BB61A7CCEE8004DFB22 /* MASShortcut+UserDefaults.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = "MASShortcut+UserDefaults.h"; path = "shortcut/MASShortcut+UserDefaults.h"; sourceTree = ""; }; + 57B95BB71A7CCEE8004DFB22 /* MASShortcut+UserDefaults.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = "MASShortcut+UserDefaults.m"; path = "shortcut/MASShortcut+UserDefaults.m"; sourceTree = ""; }; + 57B95BB81A7CCEE8004DFB22 /* MASShortcutView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = MASShortcutView.h; path = shortcut/MASShortcutView.h; sourceTree = ""; }; + 57B95BB91A7CCEE8004DFB22 /* MASShortcutView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = MASShortcutView.m; path = shortcut/MASShortcutView.m; sourceTree = ""; }; + 57B95BBA1A7CCEE8004DFB22 /* MASShortcutView+UserDefaults.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = "MASShortcutView+UserDefaults.h"; path = "shortcut/MASShortcutView+UserDefaults.h"; sourceTree = ""; }; + 57B95BBB1A7CCEE8004DFB22 /* MASShortcutView+UserDefaults.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = "MASShortcutView+UserDefaults.m"; path = "shortcut/MASShortcutView+UserDefaults.m"; sourceTree = ""; }; + 57BA8B8318BB1AA70093DC12 /* icon_close.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = icon_close.png; path = resource/icon_close.png; sourceTree = ""; }; + 57BB35141894D39B0094B553 /* DDSearchFieldController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = DDSearchFieldController.h; path = interface/mainWindow/searchField/DDSearchFieldController.h; sourceTree = ""; }; + 57BB35151894D39B0094B553 /* DDSearchFieldController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = DDSearchFieldController.m; path = interface/mainWindow/searchField/DDSearchFieldController.m; sourceTree = ""; }; + 57BEB811186958BC00CAFCF6 /* icon_conversation_theme_gray.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = icon_conversation_theme_gray.png; path = resource/icon_conversation_theme_gray.png; sourceTree = ""; }; + 57BEB812186958BC00CAFCF6 /* icon_conversation_theme_gray@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = "icon_conversation_theme_gray@2x.png"; path = "resource/icon_conversation_theme_gray@2x.png"; sourceTree = ""; }; + 57C0A8841A68B3B400ECDE45 /* AvatorImageView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = AvatorImageView.h; path = modules/Main/AvatorImageView.h; sourceTree = ""; }; + 57C0A8851A68B3B400ECDE45 /* AvatorImageView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = AvatorImageView.m; path = modules/Main/AvatorImageView.m; sourceTree = ""; }; + 57C0CE4E183C7C320049DCE4 /* AIParagraphStyleAdditions.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = AIParagraphStyleAdditions.h; path = utilities/additions/AIParagraphStyleAdditions.h; sourceTree = ""; }; + 57C0CE4F183C7C320049DCE4 /* AIParagraphStyleAdditions.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = AIParagraphStyleAdditions.m; path = utilities/additions/AIParagraphStyleAdditions.m; sourceTree = ""; }; + 57C0CE54183C86B40049DCE4 /* AIWindowControllerAdditions.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = AIWindowControllerAdditions.h; path = utilities/additions/AIWindowControllerAdditions.h; sourceTree = ""; }; + 57C0CE55183C86B40049DCE4 /* AIWindowControllerAdditions.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = AIWindowControllerAdditions.m; path = utilities/additions/AIWindowControllerAdditions.m; sourceTree = ""; }; + 57C0CE5C183C98DE0049DCE4 /* DDMutableOwnerArray.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = DDMutableOwnerArray.h; path = utilities/funNewClasses/DDMutableOwnerArray.h; sourceTree = ""; }; + 57C0CE5D183C98DE0049DCE4 /* DDMutableOwnerArray.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = DDMutableOwnerArray.m; path = utilities/funNewClasses/DDMutableOwnerArray.m; sourceTree = ""; }; + 57C2D2E81A74D3C500981552 /* DDAtUserListViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DDAtUserListViewController.h; sourceTree = ""; }; + 57C2D2E91A74D3C500981552 /* DDAtUserListViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = DDAtUserListViewController.m; sourceTree = ""; }; + 57C2D2EA1A74D3C500981552 /* DDAtUserListViewController.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = DDAtUserListViewController.xib; sourceTree = ""; }; + 57CA0F4C18D2D42D005C0B0D /* CrashReporter.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; path = CrashReporter.framework; sourceTree = ""; }; + 57D5D15B184C23AD00852738 /* DDChattingViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = DDChattingViewController.h; path = interface/chat/DDChattingViewController.h; sourceTree = ""; }; + 57D5D15D184C23AD00852738 /* DDChattingView.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; name = DDChattingView.xib; path = interface/chat/DDChattingView.xib; sourceTree = ""; }; + 57D5D163184C76D900852738 /* DDSplitView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = DDSplitView.h; path = interface/mainWindow/DDSplitView.h; sourceTree = ""; }; + 57D5D164184C76D900852738 /* DDSplitView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = DDSplitView.m; path = interface/mainWindow/DDSplitView.m; sourceTree = ""; }; + 57D5D169184D770100852738 /* icon_screenshot_highlight.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = icon_screenshot_highlight.png; path = resource/icon_screenshot_highlight.png; sourceTree = ""; }; + 57D5D16A184D770100852738 /* icon_screenshot_highlight@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = "icon_screenshot_highlight@2x.png"; path = "resource/icon_screenshot_highlight@2x.png"; sourceTree = ""; }; + 57D5D16B184D770100852738 /* icon_screenshot.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = icon_screenshot.png; path = resource/icon_screenshot.png; sourceTree = ""; }; + 57D5D16C184D770100852738 /* icon_screenshot@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = "icon_screenshot@2x.png"; path = "resource/icon_screenshot@2x.png"; sourceTree = ""; }; + 57D5D16D184D770100852738 /* icon_smile_highlight.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = icon_smile_highlight.png; path = resource/icon_smile_highlight.png; sourceTree = ""; }; + 57D5D16E184D770100852738 /* icon_smile_highlight@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = "icon_smile_highlight@2x.png"; path = "resource/icon_smile_highlight@2x.png"; sourceTree = ""; }; + 57D5D16F184D770100852738 /* icon_smile.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = icon_smile.png; path = resource/icon_smile.png; sourceTree = ""; }; + 57D5D170184D770100852738 /* icon_smile@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = "icon_smile@2x.png"; path = "resource/icon_smile@2x.png"; sourceTree = ""; }; + 57D5D185184D840000852738 /* DDChattingInputView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = DDChattingInputView.h; path = interface/chat/DDChattingInputView.h; sourceTree = ""; }; + 57D5D186184D840000852738 /* DDChattingInputView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = DDChattingInputView.m; path = interface/chat/DDChattingInputView.m; sourceTree = ""; }; + 57D5D18C184EC85100852738 /* DDSendingTextView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = DDSendingTextView.h; path = interface/chat/DDSendingTextView.h; sourceTree = ""; }; + 57D5D18D184EC85100852738 /* DDSendingTextView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = DDSendingTextView.m; path = interface/chat/DDSendingTextView.m; sourceTree = ""; }; + 57DEB68F1A7F622A00961C6F /* security.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = security.h; path = Libraries/libsecurity/security.h; sourceTree = ""; }; + 57DEB6901A7F75F500961C6F /* libsecurity.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; path = libsecurity.a; sourceTree = ""; }; + 57DEB6931A8222A800961C6F /* DDReceiveMsgDataReadNotifyAPI.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = DDReceiveMsgDataReadNotifyAPI.h; path = Message/DDReceiveMsgDataReadNotifyAPI.h; sourceTree = ""; }; + 57DEB6941A8222A800961C6F /* DDReceiveMsgDataReadNotifyAPI.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = DDReceiveMsgDataReadNotifyAPI.m; path = Message/DDReceiveMsgDataReadNotifyAPI.m; sourceTree = ""; }; + 57DF183A18DFD0E4003A19F6 /* libsqlite3.dylib */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.dylib"; name = libsqlite3.dylib; path = usr/lib/libsqlite3.dylib; sourceTree = SDKROOT; }; + 57E18EAD186A857400D00D63 /* avatar_default.jpg_48x48.jpg */ = {isa = PBXFileReference; lastKnownFileType = image.jpeg; name = avatar_default.jpg_48x48.jpg; path = resource/avatar_default.jpg_48x48.jpg; sourceTree = ""; }; + 57E1AA9D186AD9FF00D00D63 /* MainWindowSegmentedControl.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = MainWindowSegmentedControl.h; path = interface/contactList/contactList/MainWindowSegmentedControl.h; sourceTree = ""; }; + 57E1AA9E186AD9FF00D00D63 /* MainWindowSegmentedControl.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = MainWindowSegmentedControl.m; path = interface/contactList/contactList/MainWindowSegmentedControl.m; sourceTree = ""; }; + 57EFFADB1856C639006D8DE1 /* icon_unread_red_wide.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = icon_unread_red_wide.png; path = resource/icon_unread_red_wide.png; sourceTree = ""; }; + 57EFFADC1856C639006D8DE1 /* icon_unread_red_wide@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = "icon_unread_red_wide@2x.png"; path = "resource/icon_unread_red_wide@2x.png"; sourceTree = ""; }; + 57EFFADD1856C639006D8DE1 /* icon_unread_red.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = icon_unread_red.png; path = resource/icon_unread_red.png; sourceTree = ""; }; + 57EFFADE1856C639006D8DE1 /* icon_unread_red@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = "icon_unread_red@2x.png"; path = "resource/icon_unread_red@2x.png"; sourceTree = ""; }; + 57EFFB2618570324006D8DE1 /* icon_image_normal.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = icon_image_normal.png; path = resource/icon_image_normal.png; sourceTree = ""; }; + 57EFFB2718570324006D8DE1 /* icon_image_normal@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = "icon_image_normal@2x.png"; path = "resource/icon_image_normal@2x.png"; sourceTree = ""; }; + 57EFFB2A18580FC2006D8DE1 /* libz.dylib */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.dylib"; name = libz.dylib; path = usr/lib/libz.dylib; sourceTree = SDKROOT; }; + 57F50073182F92080090115B /* DDHttpUtil.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = DDHttpUtil.h; path = http/DDHttpUtil.h; sourceTree = ""; }; + 57F50074182F92080090115B /* DDHttpUtil.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = DDHttpUtil.m; path = http/DDHttpUtil.m; sourceTree = ""; }; + 57F50076182F93D90090115B /* MD5.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MD5.h; sourceTree = ""; }; + 57F50077182F93D90090115B /* MD5.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MD5.m; sourceTree = ""; }; + 57F50079182F976B0090115B /* libcommonCrypto.dylib */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.dylib"; name = libcommonCrypto.dylib; path = usr/lib/system/libcommonCrypto.dylib; sourceTree = SDKROOT; }; + 5E8EB9DC1934713A008B1890 /* ImageIO.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = ImageIO.framework; path = System/Library/Frameworks/ImageIO.framework; sourceTree = SDKROOT; }; + 5EF517B81923070400652421 /* 221.gif */ = {isa = PBXFileReference; lastKnownFileType = image.gif; path = 221.gif; sourceTree = ""; }; + 5EF517B91923070400652421 /* 222.gif */ = {isa = PBXFileReference; lastKnownFileType = image.gif; path = 222.gif; sourceTree = ""; }; + 5EF517BA1923070400652421 /* 223.gif */ = {isa = PBXFileReference; lastKnownFileType = image.gif; path = 223.gif; sourceTree = ""; }; + 5EF517BB1923070400652421 /* 224.gif */ = {isa = PBXFileReference; lastKnownFileType = image.gif; path = 224.gif; sourceTree = ""; }; + 5EF517BC1923070400652421 /* 225.gif */ = {isa = PBXFileReference; lastKnownFileType = image.gif; path = 225.gif; sourceTree = ""; }; + 5EF517BD1923070400652421 /* 226.gif */ = {isa = PBXFileReference; lastKnownFileType = image.gif; path = 226.gif; sourceTree = ""; }; + 5EF517BE1923070400652421 /* 227.gif */ = {isa = PBXFileReference; lastKnownFileType = image.gif; path = 227.gif; sourceTree = ""; }; + 5EF517BF1923070400652421 /* 228.gif */ = {isa = PBXFileReference; lastKnownFileType = image.gif; path = 228.gif; sourceTree = ""; }; + 5EF517C01923070400652421 /* 229.gif */ = {isa = PBXFileReference; lastKnownFileType = image.gif; path = 229.gif; sourceTree = ""; }; + 5EF517C11923070400652421 /* 230.gif */ = {isa = PBXFileReference; lastKnownFileType = image.gif; path = 230.gif; sourceTree = ""; }; + 5EF517C21923070400652421 /* 231.gif */ = {isa = PBXFileReference; lastKnownFileType = image.gif; path = 231.gif; sourceTree = ""; }; + 5EF517C31923070400652421 /* 232.gif */ = {isa = PBXFileReference; lastKnownFileType = image.gif; path = 232.gif; sourceTree = ""; }; + 5EF517C41923070400652421 /* 233.gif */ = {isa = PBXFileReference; lastKnownFileType = image.gif; path = 233.gif; sourceTree = ""; }; + 5EF517C51923070400652421 /* 234.gif */ = {isa = PBXFileReference; lastKnownFileType = image.gif; path = 234.gif; sourceTree = ""; }; + 5EF517C61923070400652421 /* 235.gif */ = {isa = PBXFileReference; lastKnownFileType = image.gif; path = 235.gif; sourceTree = ""; }; + 5EF517C71923070400652421 /* 236.gif */ = {isa = PBXFileReference; lastKnownFileType = image.gif; path = 236.gif; sourceTree = ""; }; + 5EF517C81923070400652421 /* 237.gif */ = {isa = PBXFileReference; lastKnownFileType = image.gif; path = 237.gif; sourceTree = ""; }; + 5EF517C91923070400652421 /* 238.gif */ = {isa = PBXFileReference; lastKnownFileType = image.gif; path = 238.gif; sourceTree = ""; }; + 5EF517CA1923070400652421 /* 239.gif */ = {isa = PBXFileReference; lastKnownFileType = image.gif; path = 239.gif; sourceTree = ""; }; + 5EF517CB1923070400652421 /* 240.gif */ = {isa = PBXFileReference; lastKnownFileType = image.gif; path = 240.gif; sourceTree = ""; }; + 5EF517E319235FBA00652421 /* DDChattingMyLine.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DDChattingMyLine.h; sourceTree = ""; }; + 5EF517E419235FBA00652421 /* DDChattingMyLine.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = DDChattingMyLine.m; sourceTree = ""; }; + 5EF517E619236EA600652421 /* input-background.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "input-background.png"; sourceTree = ""; }; + 5EF517E719236EA600652421 /* input-background@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "input-background@2x.png"; sourceTree = ""; }; + 5EF517EA19238C7B00652421 /* shake-window.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "shake-window.png"; sourceTree = ""; }; + 5EF517EB19238C7B00652421 /* shake-window@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "shake-window@2x.png"; sourceTree = ""; }; + 6D1CC75918A62FF0002CAE5F /* L4AppenderAttachable.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = L4AppenderAttachable.h; sourceTree = ""; }; + 6D1CC75A18A62FF0002CAE5F /* L4AppenderAttachable.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = L4AppenderAttachable.m; sourceTree = ""; }; + 6D1CC75B18A62FF0002CAE5F /* L4AppenderProtocols.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = L4AppenderProtocols.h; sourceTree = ""; }; + 6D1CC75C18A62FF0002CAE5F /* L4AppenderSkeleton.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = L4AppenderSkeleton.h; sourceTree = ""; }; + 6D1CC75D18A62FF0002CAE5F /* L4AppenderSkeleton.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = L4AppenderSkeleton.m; sourceTree = ""; }; + 6D1CC75E18A62FF0002CAE5F /* L4BasicConfigurator.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = L4BasicConfigurator.h; sourceTree = ""; }; + 6D1CC75F18A62FF0002CAE5F /* L4BasicConfigurator.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = L4BasicConfigurator.m; sourceTree = ""; }; + 6D1CC76018A62FF0002CAE5F /* L4ConsoleAppender.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = L4ConsoleAppender.h; sourceTree = ""; }; + 6D1CC76118A62FF0002CAE5F /* L4ConsoleAppender.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = L4ConsoleAppender.m; sourceTree = ""; }; + 6D1CC76218A62FF0002CAE5F /* L4DailyRollingFileAppender.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = L4DailyRollingFileAppender.h; sourceTree = ""; }; + 6D1CC76318A62FF0002CAE5F /* L4DailyRollingFileAppender.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = L4DailyRollingFileAppender.m; sourceTree = ""; }; + 6D1CC76418A62FF0002CAE5F /* L4DenyAllFilter.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = L4DenyAllFilter.h; sourceTree = ""; }; + 6D1CC76518A62FF0002CAE5F /* L4DenyAllFilter.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = L4DenyAllFilter.m; sourceTree = ""; }; + 6D1CC76618A62FF0002CAE5F /* L4FileAppender.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = L4FileAppender.h; sourceTree = ""; }; + 6D1CC76718A62FF0002CAE5F /* L4FileAppender.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = L4FileAppender.m; sourceTree = ""; }; + 6D1CC76818A62FF0002CAE5F /* L4Filter.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = L4Filter.h; sourceTree = ""; }; + 6D1CC76918A62FF0002CAE5F /* L4Filter.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = L4Filter.m; sourceTree = ""; }; + 6D1CC76A18A62FF0002CAE5F /* L4JSONLayout.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = L4JSONLayout.h; sourceTree = ""; }; + 6D1CC76B18A62FF0002CAE5F /* L4JSONLayout.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = L4JSONLayout.m; sourceTree = ""; }; + 6D1CC76C18A62FF0002CAE5F /* L4Layout.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = L4Layout.h; sourceTree = ""; }; + 6D1CC76D18A62FF0002CAE5F /* L4Layout.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = L4Layout.m; sourceTree = ""; }; + 6D1CC76E18A62FF0002CAE5F /* L4Level.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = L4Level.h; sourceTree = ""; }; + 6D1CC76F18A62FF0002CAE5F /* L4Level.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = L4Level.m; sourceTree = ""; }; + 6D1CC77018A62FF0002CAE5F /* L4LevelMatchFilter.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = L4LevelMatchFilter.h; sourceTree = ""; }; + 6D1CC77118A62FF0002CAE5F /* L4LevelMatchFilter.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = L4LevelMatchFilter.m; sourceTree = ""; }; + 6D1CC77218A62FF0002CAE5F /* L4LevelRangeFilter.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = L4LevelRangeFilter.h; sourceTree = ""; }; + 6D1CC77318A62FF0002CAE5F /* L4LevelRangeFilter.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = L4LevelRangeFilter.m; sourceTree = ""; }; + 6D1CC77418A62FF0002CAE5F /* L4LogEvent.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = L4LogEvent.h; sourceTree = ""; }; + 6D1CC77518A62FF0002CAE5F /* L4LogEvent.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = L4LogEvent.m; sourceTree = ""; }; + 6D1CC77618A62FF0002CAE5F /* L4Logger.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = L4Logger.h; sourceTree = ""; }; + 6D1CC77718A62FF0002CAE5F /* L4Logger.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = L4Logger.m; sourceTree = ""; }; + 6D1CC77818A62FF0002CAE5F /* L4LoggerNameMatchFilter.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = L4LoggerNameMatchFilter.h; sourceTree = ""; }; + 6D1CC77918A62FF0002CAE5F /* L4LoggerNameMatchFilter.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = L4LoggerNameMatchFilter.m; sourceTree = ""; }; + 6D1CC77A18A62FF0002CAE5F /* L4LoggerProtocols.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = L4LoggerProtocols.h; sourceTree = ""; }; + 6D1CC77B18A62FF0002CAE5F /* L4LoggerStore.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = L4LoggerStore.h; sourceTree = ""; }; + 6D1CC77C18A62FF0002CAE5F /* L4LoggerStore.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = L4LoggerStore.m; sourceTree = ""; }; + 6D1CC77D18A62FF0002CAE5F /* L4Logging.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = L4Logging.h; sourceTree = ""; }; + 6D1CC77E18A62FF0002CAE5F /* L4Logging.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = L4Logging.m; sourceTree = ""; }; + 6D1CC77F18A62FF0002CAE5F /* L4LogLog.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = L4LogLog.h; sourceTree = ""; }; + 6D1CC78018A62FF0002CAE5F /* L4LogLog.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = L4LogLog.m; sourceTree = ""; }; + 6D1CC78118A62FF0002CAE5F /* L4PatternLayout.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = L4PatternLayout.h; sourceTree = ""; }; + 6D1CC78218A62FF0002CAE5F /* L4PatternLayout.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = L4PatternLayout.m; sourceTree = ""; }; + 6D1CC78318A62FF0002CAE5F /* L4Properties.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = L4Properties.h; sourceTree = ""; }; + 6D1CC78418A62FF0002CAE5F /* L4Properties.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = L4Properties.m; sourceTree = ""; }; + 6D1CC78518A62FF0002CAE5F /* L4PropertyConfigurator.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = L4PropertyConfigurator.h; sourceTree = ""; }; + 6D1CC78618A62FF0002CAE5F /* L4PropertyConfigurator.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = L4PropertyConfigurator.m; sourceTree = ""; }; + 6D1CC78718A62FF0002CAE5F /* L4RollingFileAppender.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = L4RollingFileAppender.h; sourceTree = ""; }; + 6D1CC78818A62FF0002CAE5F /* L4RollingFileAppender.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = L4RollingFileAppender.m; sourceTree = ""; }; + 6D1CC78918A62FF0002CAE5F /* L4RootLogger.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = L4RootLogger.h; sourceTree = ""; }; + 6D1CC78A18A62FF0002CAE5F /* L4RootLogger.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = L4RootLogger.m; sourceTree = ""; }; + 6D1CC78B18A62FF0002CAE5F /* L4SimpleLayout.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = L4SimpleLayout.h; sourceTree = ""; }; + 6D1CC78C18A62FF0002CAE5F /* L4SimpleLayout.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = L4SimpleLayout.m; sourceTree = ""; }; + 6D1CC78D18A62FF0002CAE5F /* L4StringMatchFilter.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = L4StringMatchFilter.h; sourceTree = ""; }; + 6D1CC78E18A62FF0002CAE5F /* L4StringMatchFilter.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = L4StringMatchFilter.m; sourceTree = ""; }; + 6D1CC78F18A62FF0002CAE5F /* L4WriterAppender.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = L4WriterAppender.h; sourceTree = ""; }; + 6D1CC79018A62FF0002CAE5F /* L4WriterAppender.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = L4WriterAppender.m; sourceTree = ""; }; + 6D1CC79118A62FF0002CAE5F /* L4XMLLayout.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = L4XMLLayout.h; sourceTree = ""; }; + 6D1CC79218A62FF0002CAE5F /* L4XMLLayout.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = L4XMLLayout.m; sourceTree = ""; }; + 6D1CC79318A62FF0002CAE5F /* Log4Cocoa-Prefix.pch */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "Log4Cocoa-Prefix.pch"; sourceTree = ""; }; + 6D1CC79418A62FF0002CAE5F /* Log4Cocoa.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Log4Cocoa.h; sourceTree = ""; }; + 6D1CC79518A62FF0002CAE5F /* Log4CocoaDefines.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Log4CocoaDefines.h; sourceTree = ""; }; + 6D1CC79618A62FF0002CAE5F /* NSObject+Log4Cocoa.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "NSObject+Log4Cocoa.h"; sourceTree = ""; }; + 6D1CC79718A62FF0002CAE5F /* NSObject+Log4Cocoa.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "NSObject+Log4Cocoa.m"; sourceTree = ""; }; + 6D2A847C18B1D5E20004032B /* DDLoginWindow.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = DDLoginWindow.h; path = "interface/login window/DDLoginWindow.h"; sourceTree = ""; }; + 6D2A847D18B1D5E20004032B /* DDLoginWindow.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = DDLoginWindow.m; path = "interface/login window/DDLoginWindow.m"; sourceTree = ""; }; + 6D2A847F18B1D9140004032B /* icon_go.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = icon_go.png; path = resource/icon_go.png; sourceTree = ""; }; + 6D2A848018B1D9140004032B /* icon_go@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = "icon_go@2x.png"; path = "resource/icon_go@2x.png"; sourceTree = ""; }; + 6D70EA311869ADAE00402CF5 /* bubble_left.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = bubble_left.png; path = resource/bubble_left.png; sourceTree = ""; }; + 6D70EA321869ADAE00402CF5 /* bubble_left@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = "bubble_left@2x.png"; path = "resource/bubble_left@2x.png"; sourceTree = ""; }; + 6D70EA331869ADAE00402CF5 /* bubble_right.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = bubble_right.png; path = resource/bubble_right.png; sourceTree = ""; }; + 6D70EA341869ADAE00402CF5 /* bubble_right@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = "bubble_right@2x.png"; path = "resource/bubble_right@2x.png"; sourceTree = ""; }; + 6D70EA92186C43C000402CF5 /* NSImage+Stretchable.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = "NSImage+Stretchable.h"; path = "utilities/NSImage+Stretchable.h"; sourceTree = ""; }; + 6D70EA93186C43C000402CF5 /* NSImage+Stretchable.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = "NSImage+Stretchable.m"; path = "utilities/NSImage+Stretchable.m"; sourceTree = ""; }; + 6D74358D18E26A02008ED227 /* BackgroudView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = BackgroudView.h; sourceTree = ""; }; + 6D74358E18E26A02008ED227 /* BackgroudView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = BackgroudView.m; sourceTree = ""; }; + 6D78A57A18D828450069A29B /* ScreenCapture_toolbar_ellipse.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = ScreenCapture_toolbar_ellipse.png; path = resource/ScreenCapture_toolbar_ellipse.png; sourceTree = ""; }; + 6D78A57B18D828450069A29B /* ScreenCapture_toolbar_ellipse@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = "ScreenCapture_toolbar_ellipse@2x.png"; path = "resource/ScreenCapture_toolbar_ellipse@2x.png"; sourceTree = ""; }; + 6D78A57C18D828450069A29B /* ScreenCapture_toolbar_rect.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = ScreenCapture_toolbar_rect.png; path = resource/ScreenCapture_toolbar_rect.png; sourceTree = ""; }; + 6D78A57D18D828450069A29B /* ScreenCapture_toolbar_rect@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = "ScreenCapture_toolbar_rect@2x.png"; path = "resource/ScreenCapture_toolbar_rect@2x.png"; sourceTree = ""; }; + 6D8B6AE218C462EE0081DAA2 /* filetransfer_offline.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = filetransfer_offline.png; path = resource/fileTransfer/filetransfer_offline.png; sourceTree = ""; }; + 6D8B6AE318C462EE0081DAA2 /* filetransfer_offline@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = "filetransfer_offline@2x.png"; path = "resource/fileTransfer/filetransfer_offline@2x.png"; sourceTree = ""; }; + 6DCB32D8189201FF00FC86A3 /* DDApplication.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DDApplication.h; sourceTree = ""; }; + 6DCB32D9189201FF00FC86A3 /* DDApplication.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = DDApplication.m; sourceTree = ""; }; + 6DCB3380189629F200FC86A3 /* filetransfer_avatar_receive.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = filetransfer_avatar_receive.png; path = resource/fileTransfer/filetransfer_avatar_receive.png; sourceTree = ""; }; + 6DCB3381189629F200FC86A3 /* filetransfer_avatar_receive@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = "filetransfer_avatar_receive@2x.png"; path = "resource/fileTransfer/filetransfer_avatar_receive@2x.png"; sourceTree = ""; }; + 6DCB3382189629F200FC86A3 /* filetransfer_avatar_send.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = filetransfer_avatar_send.png; path = resource/fileTransfer/filetransfer_avatar_send.png; sourceTree = ""; }; + 6DCB3383189629F200FC86A3 /* filetransfer_avatar_send@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = "filetransfer_avatar_send@2x.png"; path = "resource/fileTransfer/filetransfer_avatar_send@2x.png"; sourceTree = ""; }; + 6DCB3384189629F200FC86A3 /* filetransfer_close.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = filetransfer_close.png; path = resource/fileTransfer/filetransfer_close.png; sourceTree = ""; }; + 6DCB3385189629F200FC86A3 /* filetransfer_close@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = "filetransfer_close@2x.png"; path = "resource/fileTransfer/filetransfer_close@2x.png"; sourceTree = ""; }; + 6DCB3386189629F200FC86A3 /* filetransfer_receiver.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = filetransfer_receiver.png; path = resource/fileTransfer/filetransfer_receiver.png; sourceTree = ""; }; + 6DCB3387189629F200FC86A3 /* filetransfer_receiver@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = "filetransfer_receiver@2x.png"; path = "resource/fileTransfer/filetransfer_receiver@2x.png"; sourceTree = ""; }; + 6DCB3388189629F200FC86A3 /* filetransfer_refuse.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = filetransfer_refuse.png; path = resource/fileTransfer/filetransfer_refuse.png; sourceTree = ""; }; + 6DCB3389189629F200FC86A3 /* filetransfer_refuse@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = "filetransfer_refuse@2x.png"; path = "resource/fileTransfer/filetransfer_refuse@2x.png"; sourceTree = ""; }; + 6DCB338A189629F200FC86A3 /* filetransfer_search.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = filetransfer_search.png; path = resource/fileTransfer/filetransfer_search.png; sourceTree = ""; }; + 6DCB338B189629F200FC86A3 /* filetransfer_search@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = "filetransfer_search@2x.png"; path = "resource/fileTransfer/filetransfer_search@2x.png"; sourceTree = ""; }; + 6DD31977188E3C5200ED5FE8 /* EmotionViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = EmotionViewController.h; path = interface/emotion/EmotionViewController.h; sourceTree = ""; }; + 6DD31978188E3C5200ED5FE8 /* EmotionViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = EmotionViewController.m; path = interface/emotion/EmotionViewController.m; sourceTree = ""; }; + 6DD3197A188E3C8B00ED5FE8 /* EmotionCellView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = EmotionCellView.h; path = interface/emotion/EmotionCellView.h; sourceTree = ""; }; + 6DD3197B188E3C8B00ED5FE8 /* EmotionCellView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = EmotionCellView.m; path = interface/emotion/EmotionCellView.m; sourceTree = ""; }; + 6DD3197D188E3CD800ED5FE8 /* EmotionPopover.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; name = EmotionPopover.xib; path = interface/emotion/EmotionPopover.xib; sourceTree = ""; }; + 6DD31980188E592100ED5FE8 /* 0.gif */ = {isa = PBXFileReference; lastKnownFileType = image.gif; name = 0.gif; path = resource/emotions/0.gif; sourceTree = ""; }; + 6DD31981188E592100ED5FE8 /* 1.gif */ = {isa = PBXFileReference; lastKnownFileType = image.gif; name = 1.gif; path = resource/emotions/1.gif; sourceTree = ""; }; + 6DD31982188E592100ED5FE8 /* 2.gif */ = {isa = PBXFileReference; lastKnownFileType = image.gif; name = 2.gif; path = resource/emotions/2.gif; sourceTree = ""; }; + 6DD31983188E592100ED5FE8 /* 3.gif */ = {isa = PBXFileReference; lastKnownFileType = image.gif; name = 3.gif; path = resource/emotions/3.gif; sourceTree = ""; }; + 6DD31984188E592100ED5FE8 /* 4.gif */ = {isa = PBXFileReference; lastKnownFileType = image.gif; name = 4.gif; path = resource/emotions/4.gif; sourceTree = ""; }; + 6DD31985188E592100ED5FE8 /* 5.gif */ = {isa = PBXFileReference; lastKnownFileType = image.gif; name = 5.gif; path = resource/emotions/5.gif; sourceTree = ""; }; + 6DD31986188E592100ED5FE8 /* 6.gif */ = {isa = PBXFileReference; lastKnownFileType = image.gif; name = 6.gif; path = resource/emotions/6.gif; sourceTree = ""; }; + 6DD31987188E592100ED5FE8 /* 7.gif */ = {isa = PBXFileReference; lastKnownFileType = image.gif; name = 7.gif; path = resource/emotions/7.gif; sourceTree = ""; }; + 6DD31988188E592100ED5FE8 /* 8.gif */ = {isa = PBXFileReference; lastKnownFileType = image.gif; name = 8.gif; path = resource/emotions/8.gif; sourceTree = ""; }; + 6DD31989188E592100ED5FE8 /* 9.gif */ = {isa = PBXFileReference; lastKnownFileType = image.gif; name = 9.gif; path = resource/emotions/9.gif; sourceTree = ""; }; + 6DD3198A188E592100ED5FE8 /* 10.gif */ = {isa = PBXFileReference; lastKnownFileType = image.gif; name = 10.gif; path = resource/emotions/10.gif; sourceTree = ""; }; + 6DD3198B188E592100ED5FE8 /* 11.gif */ = {isa = PBXFileReference; lastKnownFileType = image.gif; name = 11.gif; path = resource/emotions/11.gif; sourceTree = ""; }; + 6DD3198C188E592100ED5FE8 /* 12.gif */ = {isa = PBXFileReference; lastKnownFileType = image.gif; name = 12.gif; path = resource/emotions/12.gif; sourceTree = ""; }; + 6DD3198D188E592100ED5FE8 /* 13.gif */ = {isa = PBXFileReference; lastKnownFileType = image.gif; name = 13.gif; path = resource/emotions/13.gif; sourceTree = ""; }; + 6DD3198E188E592100ED5FE8 /* 14.gif */ = {isa = PBXFileReference; lastKnownFileType = image.gif; name = 14.gif; path = resource/emotions/14.gif; sourceTree = ""; }; + 6DD3198F188E592100ED5FE8 /* 15.gif */ = {isa = PBXFileReference; lastKnownFileType = image.gif; name = 15.gif; path = resource/emotions/15.gif; sourceTree = ""; }; + 6DD31990188E592100ED5FE8 /* 16.gif */ = {isa = PBXFileReference; lastKnownFileType = image.gif; name = 16.gif; path = resource/emotions/16.gif; sourceTree = ""; }; + 6DD31991188E592100ED5FE8 /* 17.gif */ = {isa = PBXFileReference; lastKnownFileType = image.gif; name = 17.gif; path = resource/emotions/17.gif; sourceTree = ""; }; + 6DD31992188E592100ED5FE8 /* 18.gif */ = {isa = PBXFileReference; lastKnownFileType = image.gif; name = 18.gif; path = resource/emotions/18.gif; sourceTree = ""; }; + 6DD31993188E592100ED5FE8 /* 19.gif */ = {isa = PBXFileReference; lastKnownFileType = image.gif; name = 19.gif; path = resource/emotions/19.gif; sourceTree = ""; }; + 6DD31994188E592100ED5FE8 /* 20.gif */ = {isa = PBXFileReference; lastKnownFileType = image.gif; name = 20.gif; path = resource/emotions/20.gif; sourceTree = ""; }; + 6DD31995188E592100ED5FE8 /* 21.gif */ = {isa = PBXFileReference; lastKnownFileType = image.gif; name = 21.gif; path = resource/emotions/21.gif; sourceTree = ""; }; + 6DD31996188E592100ED5FE8 /* 22.gif */ = {isa = PBXFileReference; lastKnownFileType = image.gif; name = 22.gif; path = resource/emotions/22.gif; sourceTree = ""; }; + 6DD31997188E592100ED5FE8 /* 23.gif */ = {isa = PBXFileReference; lastKnownFileType = image.gif; name = 23.gif; path = resource/emotions/23.gif; sourceTree = ""; }; + 6DD31998188E592100ED5FE8 /* 24.gif */ = {isa = PBXFileReference; lastKnownFileType = image.gif; name = 24.gif; path = resource/emotions/24.gif; sourceTree = ""; }; + 6DD31999188E592100ED5FE8 /* 25.gif */ = {isa = PBXFileReference; lastKnownFileType = image.gif; name = 25.gif; path = resource/emotions/25.gif; sourceTree = ""; }; + 6DD3199A188E592100ED5FE8 /* 26.gif */ = {isa = PBXFileReference; lastKnownFileType = image.gif; name = 26.gif; path = resource/emotions/26.gif; sourceTree = ""; }; + 6DD3199B188E592100ED5FE8 /* 27.gif */ = {isa = PBXFileReference; lastKnownFileType = image.gif; name = 27.gif; path = resource/emotions/27.gif; sourceTree = ""; }; + 6DD3199C188E592100ED5FE8 /* 28.gif */ = {isa = PBXFileReference; lastKnownFileType = image.gif; name = 28.gif; path = resource/emotions/28.gif; sourceTree = ""; }; + 6DD3199D188E592100ED5FE8 /* 29.gif */ = {isa = PBXFileReference; lastKnownFileType = image.gif; name = 29.gif; path = resource/emotions/29.gif; sourceTree = ""; }; + 6DD3199E188E592100ED5FE8 /* 30.gif */ = {isa = PBXFileReference; lastKnownFileType = image.gif; name = 30.gif; path = resource/emotions/30.gif; sourceTree = ""; }; + 6DD3199F188E592100ED5FE8 /* 31.gif */ = {isa = PBXFileReference; lastKnownFileType = image.gif; name = 31.gif; path = resource/emotions/31.gif; sourceTree = ""; }; + 6DD319A0188E592100ED5FE8 /* 32.gif */ = {isa = PBXFileReference; lastKnownFileType = image.gif; name = 32.gif; path = resource/emotions/32.gif; sourceTree = ""; }; + 6DD319A1188E592100ED5FE8 /* 33.gif */ = {isa = PBXFileReference; lastKnownFileType = image.gif; name = 33.gif; path = resource/emotions/33.gif; sourceTree = ""; }; + 6DD319A2188E592100ED5FE8 /* 34.gif */ = {isa = PBXFileReference; lastKnownFileType = image.gif; name = 34.gif; path = resource/emotions/34.gif; sourceTree = ""; }; + 6DD319A3188E592100ED5FE8 /* 35.gif */ = {isa = PBXFileReference; lastKnownFileType = image.gif; name = 35.gif; path = resource/emotions/35.gif; sourceTree = ""; }; + 6DD319A4188E592100ED5FE8 /* 36.gif */ = {isa = PBXFileReference; lastKnownFileType = image.gif; name = 36.gif; path = resource/emotions/36.gif; sourceTree = ""; }; + 6DD319A5188E592100ED5FE8 /* 37.gif */ = {isa = PBXFileReference; lastKnownFileType = image.gif; name = 37.gif; path = resource/emotions/37.gif; sourceTree = ""; }; + 6DD319A6188E592100ED5FE8 /* 38.gif */ = {isa = PBXFileReference; lastKnownFileType = image.gif; name = 38.gif; path = resource/emotions/38.gif; sourceTree = ""; }; + 6DD319A7188E592100ED5FE8 /* 39.gif */ = {isa = PBXFileReference; lastKnownFileType = image.gif; name = 39.gif; path = resource/emotions/39.gif; sourceTree = ""; }; + 6DD319A8188E592100ED5FE8 /* 40.gif */ = {isa = PBXFileReference; lastKnownFileType = image.gif; name = 40.gif; path = resource/emotions/40.gif; sourceTree = ""; }; + 6DD319A9188E592100ED5FE8 /* 41.gif */ = {isa = PBXFileReference; lastKnownFileType = image.gif; name = 41.gif; path = resource/emotions/41.gif; sourceTree = ""; }; + 6DD319AA188E592100ED5FE8 /* 42.gif */ = {isa = PBXFileReference; lastKnownFileType = image.gif; name = 42.gif; path = resource/emotions/42.gif; sourceTree = ""; }; + 6DD319AB188E592100ED5FE8 /* 43.gif */ = {isa = PBXFileReference; lastKnownFileType = image.gif; name = 43.gif; path = resource/emotions/43.gif; sourceTree = ""; }; + 6DD319AC188E592100ED5FE8 /* 44.gif */ = {isa = PBXFileReference; lastKnownFileType = image.gif; name = 44.gif; path = resource/emotions/44.gif; sourceTree = ""; }; + 6DD319AD188E592100ED5FE8 /* 45.gif */ = {isa = PBXFileReference; lastKnownFileType = image.gif; name = 45.gif; path = resource/emotions/45.gif; sourceTree = ""; }; + 6DD319AE188E592100ED5FE8 /* 46.gif */ = {isa = PBXFileReference; lastKnownFileType = image.gif; name = 46.gif; path = resource/emotions/46.gif; sourceTree = ""; }; + 6DD319AF188E592100ED5FE8 /* 47.gif */ = {isa = PBXFileReference; lastKnownFileType = image.gif; name = 47.gif; path = resource/emotions/47.gif; sourceTree = ""; }; + 6DD319B0188E592100ED5FE8 /* 48.gif */ = {isa = PBXFileReference; lastKnownFileType = image.gif; name = 48.gif; path = resource/emotions/48.gif; sourceTree = ""; }; + 6DD319B1188E592100ED5FE8 /* 49.gif */ = {isa = PBXFileReference; lastKnownFileType = image.gif; name = 49.gif; path = resource/emotions/49.gif; sourceTree = ""; }; + 6DD319B2188E592100ED5FE8 /* 50.gif */ = {isa = PBXFileReference; lastKnownFileType = image.gif; name = 50.gif; path = resource/emotions/50.gif; sourceTree = ""; }; + 6DD319B3188E592100ED5FE8 /* 51.gif */ = {isa = PBXFileReference; lastKnownFileType = image.gif; name = 51.gif; path = resource/emotions/51.gif; sourceTree = ""; }; + 6DD319B4188E592100ED5FE8 /* 52.gif */ = {isa = PBXFileReference; lastKnownFileType = image.gif; name = 52.gif; path = resource/emotions/52.gif; sourceTree = ""; }; + 6DD319B5188E592100ED5FE8 /* 53.gif */ = {isa = PBXFileReference; lastKnownFileType = image.gif; name = 53.gif; path = resource/emotions/53.gif; sourceTree = ""; }; + 6DD319B6188E592100ED5FE8 /* 54.gif */ = {isa = PBXFileReference; lastKnownFileType = image.gif; name = 54.gif; path = resource/emotions/54.gif; sourceTree = ""; }; + 6DD319B7188E592100ED5FE8 /* 55.gif */ = {isa = PBXFileReference; lastKnownFileType = image.gif; name = 55.gif; path = resource/emotions/55.gif; sourceTree = ""; }; + 6DD319B8188E592100ED5FE8 /* 56.gif */ = {isa = PBXFileReference; lastKnownFileType = image.gif; name = 56.gif; path = resource/emotions/56.gif; sourceTree = ""; }; + 6DD319B9188E592100ED5FE8 /* 57.gif */ = {isa = PBXFileReference; lastKnownFileType = image.gif; name = 57.gif; path = resource/emotions/57.gif; sourceTree = ""; }; + 6DD319BA188E592100ED5FE8 /* 58.gif */ = {isa = PBXFileReference; lastKnownFileType = image.gif; name = 58.gif; path = resource/emotions/58.gif; sourceTree = ""; }; + 6DD319BB188E592100ED5FE8 /* 59.gif */ = {isa = PBXFileReference; lastKnownFileType = image.gif; name = 59.gif; path = resource/emotions/59.gif; sourceTree = ""; }; + 6DD319BC188E592100ED5FE8 /* 60.gif */ = {isa = PBXFileReference; lastKnownFileType = image.gif; name = 60.gif; path = resource/emotions/60.gif; sourceTree = ""; }; + 6DD319BD188E592100ED5FE8 /* 61.gif */ = {isa = PBXFileReference; lastKnownFileType = image.gif; name = 61.gif; path = resource/emotions/61.gif; sourceTree = ""; }; + 6DD319BE188E592100ED5FE8 /* 62.gif */ = {isa = PBXFileReference; lastKnownFileType = image.gif; name = 62.gif; path = resource/emotions/62.gif; sourceTree = ""; }; + 6DD319BF188E592100ED5FE8 /* 63.gif */ = {isa = PBXFileReference; lastKnownFileType = image.gif; name = 63.gif; path = resource/emotions/63.gif; sourceTree = ""; }; + 6DD319C0188E592100ED5FE8 /* 64.gif */ = {isa = PBXFileReference; lastKnownFileType = image.gif; name = 64.gif; path = resource/emotions/64.gif; sourceTree = ""; }; + 6DD319C1188E592100ED5FE8 /* 65.gif */ = {isa = PBXFileReference; lastKnownFileType = image.gif; name = 65.gif; path = resource/emotions/65.gif; sourceTree = ""; }; + 6DD319C2188E592100ED5FE8 /* 66.gif */ = {isa = PBXFileReference; lastKnownFileType = image.gif; name = 66.gif; path = resource/emotions/66.gif; sourceTree = ""; }; + 6DD319C3188E592100ED5FE8 /* 67.gif */ = {isa = PBXFileReference; lastKnownFileType = image.gif; name = 67.gif; path = resource/emotions/67.gif; sourceTree = ""; }; + 6DD319C4188E592100ED5FE8 /* 68.gif */ = {isa = PBXFileReference; lastKnownFileType = image.gif; name = 68.gif; path = resource/emotions/68.gif; sourceTree = ""; }; + 6DD319C5188E592100ED5FE8 /* 69.gif */ = {isa = PBXFileReference; lastKnownFileType = image.gif; name = 69.gif; path = resource/emotions/69.gif; sourceTree = ""; }; + 6DD319C6188E592100ED5FE8 /* 70.gif */ = {isa = PBXFileReference; lastKnownFileType = image.gif; name = 70.gif; path = resource/emotions/70.gif; sourceTree = ""; }; + 6DD319C7188E592100ED5FE8 /* 71.gif */ = {isa = PBXFileReference; lastKnownFileType = image.gif; name = 71.gif; path = resource/emotions/71.gif; sourceTree = ""; }; + 6DD319C8188E592100ED5FE8 /* 72.gif */ = {isa = PBXFileReference; lastKnownFileType = image.gif; name = 72.gif; path = resource/emotions/72.gif; sourceTree = ""; }; + 6DD319C9188E592100ED5FE8 /* 73.gif */ = {isa = PBXFileReference; lastKnownFileType = image.gif; name = 73.gif; path = resource/emotions/73.gif; sourceTree = ""; }; + 6DD319CA188E592100ED5FE8 /* 74.gif */ = {isa = PBXFileReference; lastKnownFileType = image.gif; name = 74.gif; path = resource/emotions/74.gif; sourceTree = ""; }; + 6DD319CB188E592100ED5FE8 /* 75.gif */ = {isa = PBXFileReference; lastKnownFileType = image.gif; name = 75.gif; path = resource/emotions/75.gif; sourceTree = ""; }; + 6DD319CC188E592100ED5FE8 /* 76.gif */ = {isa = PBXFileReference; lastKnownFileType = image.gif; name = 76.gif; path = resource/emotions/76.gif; sourceTree = ""; }; + 6DD319CD188E592100ED5FE8 /* 77.gif */ = {isa = PBXFileReference; lastKnownFileType = image.gif; name = 77.gif; path = resource/emotions/77.gif; sourceTree = ""; }; + 6DD319CE188E592100ED5FE8 /* 78.gif */ = {isa = PBXFileReference; lastKnownFileType = image.gif; name = 78.gif; path = resource/emotions/78.gif; sourceTree = ""; }; + 6DD319CF188E592100ED5FE8 /* 79.gif */ = {isa = PBXFileReference; lastKnownFileType = image.gif; name = 79.gif; path = resource/emotions/79.gif; sourceTree = ""; }; + 6DD319D0188E592100ED5FE8 /* 80.gif */ = {isa = PBXFileReference; lastKnownFileType = image.gif; name = 80.gif; path = resource/emotions/80.gif; sourceTree = ""; }; + 6DD319D1188E592100ED5FE8 /* 81.gif */ = {isa = PBXFileReference; lastKnownFileType = image.gif; name = 81.gif; path = resource/emotions/81.gif; sourceTree = ""; }; + 6DD319D2188E592100ED5FE8 /* 82.gif */ = {isa = PBXFileReference; lastKnownFileType = image.gif; name = 82.gif; path = resource/emotions/82.gif; sourceTree = ""; }; + 6DD319D3188E592100ED5FE8 /* 83.gif */ = {isa = PBXFileReference; lastKnownFileType = image.gif; name = 83.gif; path = resource/emotions/83.gif; sourceTree = ""; }; + 6DD319D4188E592100ED5FE8 /* 84.gif */ = {isa = PBXFileReference; lastKnownFileType = image.gif; name = 84.gif; path = resource/emotions/84.gif; sourceTree = ""; }; + 6DD319D5188E592100ED5FE8 /* 85.gif */ = {isa = PBXFileReference; lastKnownFileType = image.gif; name = 85.gif; path = resource/emotions/85.gif; sourceTree = ""; }; + 6DD319D6188E592100ED5FE8 /* 86.gif */ = {isa = PBXFileReference; lastKnownFileType = image.gif; name = 86.gif; path = resource/emotions/86.gif; sourceTree = ""; }; + 6DD319D7188E592100ED5FE8 /* 87.gif */ = {isa = PBXFileReference; lastKnownFileType = image.gif; name = 87.gif; path = resource/emotions/87.gif; sourceTree = ""; }; + 6DD319D8188E592100ED5FE8 /* 88.gif */ = {isa = PBXFileReference; lastKnownFileType = image.gif; name = 88.gif; path = resource/emotions/88.gif; sourceTree = ""; }; + 6DD319D9188E592100ED5FE8 /* 89.gif */ = {isa = PBXFileReference; lastKnownFileType = image.gif; name = 89.gif; path = resource/emotions/89.gif; sourceTree = ""; }; + 6DD319DA188E592100ED5FE8 /* 90.gif */ = {isa = PBXFileReference; lastKnownFileType = image.gif; name = 90.gif; path = resource/emotions/90.gif; sourceTree = ""; }; + 6DD319DB188E592100ED5FE8 /* 91.gif */ = {isa = PBXFileReference; lastKnownFileType = image.gif; name = 91.gif; path = resource/emotions/91.gif; sourceTree = ""; }; + 6DD319DC188E592100ED5FE8 /* 92.gif */ = {isa = PBXFileReference; lastKnownFileType = image.gif; name = 92.gif; path = resource/emotions/92.gif; sourceTree = ""; }; + 6DD319DD188E592100ED5FE8 /* 93.gif */ = {isa = PBXFileReference; lastKnownFileType = image.gif; name = 93.gif; path = resource/emotions/93.gif; sourceTree = ""; }; + 6DD319DE188E592100ED5FE8 /* 94.gif */ = {isa = PBXFileReference; lastKnownFileType = image.gif; name = 94.gif; path = resource/emotions/94.gif; sourceTree = ""; }; + 6DD319DF188E592100ED5FE8 /* 95.gif */ = {isa = PBXFileReference; lastKnownFileType = image.gif; name = 95.gif; path = resource/emotions/95.gif; sourceTree = ""; }; + 6DD319E0188E592100ED5FE8 /* 96.gif */ = {isa = PBXFileReference; lastKnownFileType = image.gif; name = 96.gif; path = resource/emotions/96.gif; sourceTree = ""; }; + 6DD319E1188E592100ED5FE8 /* 97.gif */ = {isa = PBXFileReference; lastKnownFileType = image.gif; name = 97.gif; path = resource/emotions/97.gif; sourceTree = ""; }; + 6DD319E2188E592100ED5FE8 /* 98.gif */ = {isa = PBXFileReference; lastKnownFileType = image.gif; name = 98.gif; path = resource/emotions/98.gif; sourceTree = ""; }; + 6DD319E3188E592100ED5FE8 /* 99.gif */ = {isa = PBXFileReference; lastKnownFileType = image.gif; name = 99.gif; path = resource/emotions/99.gif; sourceTree = ""; }; + 6DD319E4188E592100ED5FE8 /* 100.gif */ = {isa = PBXFileReference; lastKnownFileType = image.gif; name = 100.gif; path = resource/emotions/100.gif; sourceTree = ""; }; + 6DD319E5188E592100ED5FE8 /* 101.gif */ = {isa = PBXFileReference; lastKnownFileType = image.gif; name = 101.gif; path = resource/emotions/101.gif; sourceTree = ""; }; + 6DD319E6188E592100ED5FE8 /* 102.gif */ = {isa = PBXFileReference; lastKnownFileType = image.gif; name = 102.gif; path = resource/emotions/102.gif; sourceTree = ""; }; + 6DD319E7188E592100ED5FE8 /* 103.gif */ = {isa = PBXFileReference; lastKnownFileType = image.gif; name = 103.gif; path = resource/emotions/103.gif; sourceTree = ""; }; + 6DD319E8188E592100ED5FE8 /* 104.gif */ = {isa = PBXFileReference; lastKnownFileType = image.gif; name = 104.gif; path = resource/emotions/104.gif; sourceTree = ""; }; + 6DD319E9188E592100ED5FE8 /* 105.gif */ = {isa = PBXFileReference; lastKnownFileType = image.gif; name = 105.gif; path = resource/emotions/105.gif; sourceTree = ""; }; + 6DD319EA188E592100ED5FE8 /* 106.gif */ = {isa = PBXFileReference; lastKnownFileType = image.gif; name = 106.gif; path = resource/emotions/106.gif; sourceTree = ""; }; + 6DD319EB188E592100ED5FE8 /* 107.gif */ = {isa = PBXFileReference; lastKnownFileType = image.gif; name = 107.gif; path = resource/emotions/107.gif; sourceTree = ""; }; + 6DD319EC188E592100ED5FE8 /* 108.gif */ = {isa = PBXFileReference; lastKnownFileType = image.gif; name = 108.gif; path = resource/emotions/108.gif; sourceTree = ""; }; + 6DD319ED188E592100ED5FE8 /* 109.gif */ = {isa = PBXFileReference; lastKnownFileType = image.gif; name = 109.gif; path = resource/emotions/109.gif; sourceTree = ""; }; + 6DD319EE188E592100ED5FE8 /* 110.gif */ = {isa = PBXFileReference; lastKnownFileType = image.gif; name = 110.gif; path = resource/emotions/110.gif; sourceTree = ""; }; + 6DD319EF188E592100ED5FE8 /* 111.gif */ = {isa = PBXFileReference; lastKnownFileType = image.gif; name = 111.gif; path = resource/emotions/111.gif; sourceTree = ""; }; + 6DD319F0188E592100ED5FE8 /* 112.gif */ = {isa = PBXFileReference; lastKnownFileType = image.gif; name = 112.gif; path = resource/emotions/112.gif; sourceTree = ""; }; + 6DD319F1188E592100ED5FE8 /* 113.gif */ = {isa = PBXFileReference; lastKnownFileType = image.gif; name = 113.gif; path = resource/emotions/113.gif; sourceTree = ""; }; + 6DD319F2188E592100ED5FE8 /* 114.gif */ = {isa = PBXFileReference; lastKnownFileType = image.gif; name = 114.gif; path = resource/emotions/114.gif; sourceTree = ""; }; + 6DD319F3188E592100ED5FE8 /* 115.gif */ = {isa = PBXFileReference; lastKnownFileType = image.gif; name = 115.gif; path = resource/emotions/115.gif; sourceTree = ""; }; + 6DD319F4188E592100ED5FE8 /* 116.gif */ = {isa = PBXFileReference; lastKnownFileType = image.gif; name = 116.gif; path = resource/emotions/116.gif; sourceTree = ""; }; + 6DD319F5188E592100ED5FE8 /* 117.gif */ = {isa = PBXFileReference; lastKnownFileType = image.gif; name = 117.gif; path = resource/emotions/117.gif; sourceTree = ""; }; + 6DD319F6188E592100ED5FE8 /* 118.gif */ = {isa = PBXFileReference; lastKnownFileType = image.gif; name = 118.gif; path = resource/emotions/118.gif; sourceTree = ""; }; + 6DD319F7188E592100ED5FE8 /* 119.gif */ = {isa = PBXFileReference; lastKnownFileType = image.gif; name = 119.gif; path = resource/emotions/119.gif; sourceTree = ""; }; + 6DD319F8188E592100ED5FE8 /* 120.gif */ = {isa = PBXFileReference; lastKnownFileType = image.gif; name = 120.gif; path = resource/emotions/120.gif; sourceTree = ""; }; + 6DD319F9188E592100ED5FE8 /* 121.gif */ = {isa = PBXFileReference; lastKnownFileType = image.gif; name = 121.gif; path = resource/emotions/121.gif; sourceTree = ""; }; + 6DD319FA188E592100ED5FE8 /* 122.gif */ = {isa = PBXFileReference; lastKnownFileType = image.gif; name = 122.gif; path = resource/emotions/122.gif; sourceTree = ""; }; + 6DD319FB188E592100ED5FE8 /* 123.gif */ = {isa = PBXFileReference; lastKnownFileType = image.gif; name = 123.gif; path = resource/emotions/123.gif; sourceTree = ""; }; + 6DD319FC188E592100ED5FE8 /* 124.gif */ = {isa = PBXFileReference; lastKnownFileType = image.gif; name = 124.gif; path = resource/emotions/124.gif; sourceTree = ""; }; + 6DD319FD188E592100ED5FE8 /* 125.gif */ = {isa = PBXFileReference; lastKnownFileType = image.gif; name = 125.gif; path = resource/emotions/125.gif; sourceTree = ""; }; + 6DD319FE188E592100ED5FE8 /* 126.gif */ = {isa = PBXFileReference; lastKnownFileType = image.gif; name = 126.gif; path = resource/emotions/126.gif; sourceTree = ""; }; + 6DD319FF188E592100ED5FE8 /* 127.gif */ = {isa = PBXFileReference; lastKnownFileType = image.gif; name = 127.gif; path = resource/emotions/127.gif; sourceTree = ""; }; + 6DD31A00188E592100ED5FE8 /* 128.gif */ = {isa = PBXFileReference; lastKnownFileType = image.gif; name = 128.gif; path = resource/emotions/128.gif; sourceTree = ""; }; + 6DD31A01188E592200ED5FE8 /* 129.gif */ = {isa = PBXFileReference; lastKnownFileType = image.gif; name = 129.gif; path = resource/emotions/129.gif; sourceTree = ""; }; + 6DD31A02188E592200ED5FE8 /* 130.gif */ = {isa = PBXFileReference; lastKnownFileType = image.gif; name = 130.gif; path = resource/emotions/130.gif; sourceTree = ""; }; + 6DD31A03188E592200ED5FE8 /* 131.gif */ = {isa = PBXFileReference; lastKnownFileType = image.gif; name = 131.gif; path = resource/emotions/131.gif; sourceTree = ""; }; + 6DD31A04188E592200ED5FE8 /* 132.gif */ = {isa = PBXFileReference; lastKnownFileType = image.gif; name = 132.gif; path = resource/emotions/132.gif; sourceTree = ""; }; + 6DD31A05188E592200ED5FE8 /* 133.gif */ = {isa = PBXFileReference; lastKnownFileType = image.gif; name = 133.gif; path = resource/emotions/133.gif; sourceTree = ""; }; + 6DD31A06188E592200ED5FE8 /* 134.gif */ = {isa = PBXFileReference; lastKnownFileType = image.gif; name = 134.gif; path = resource/emotions/134.gif; sourceTree = ""; }; + 6DD31A07188E592200ED5FE8 /* 135.gif */ = {isa = PBXFileReference; lastKnownFileType = image.gif; name = 135.gif; path = resource/emotions/135.gif; sourceTree = ""; }; + 6DD31A08188E592200ED5FE8 /* 136.gif */ = {isa = PBXFileReference; lastKnownFileType = image.gif; name = 136.gif; path = resource/emotions/136.gif; sourceTree = ""; }; + 6DD31A09188E592200ED5FE8 /* 137.gif */ = {isa = PBXFileReference; lastKnownFileType = image.gif; name = 137.gif; path = resource/emotions/137.gif; sourceTree = ""; }; + 6DD31A0A188E592200ED5FE8 /* 138.gif */ = {isa = PBXFileReference; lastKnownFileType = image.gif; name = 138.gif; path = resource/emotions/138.gif; sourceTree = ""; }; + 6DD31A0B188E592200ED5FE8 /* 139.gif */ = {isa = PBXFileReference; lastKnownFileType = image.gif; name = 139.gif; path = resource/emotions/139.gif; sourceTree = ""; }; + 6DD31A0C188E592200ED5FE8 /* 140.gif */ = {isa = PBXFileReference; lastKnownFileType = image.gif; name = 140.gif; path = resource/emotions/140.gif; sourceTree = ""; }; + 6DD31A0D188E592200ED5FE8 /* 141.gif */ = {isa = PBXFileReference; lastKnownFileType = image.gif; name = 141.gif; path = resource/emotions/141.gif; sourceTree = ""; }; + 6DD31A0E188E592200ED5FE8 /* 142.gif */ = {isa = PBXFileReference; lastKnownFileType = image.gif; name = 142.gif; path = resource/emotions/142.gif; sourceTree = ""; }; + 6DD31A0F188E592200ED5FE8 /* 143.gif */ = {isa = PBXFileReference; lastKnownFileType = image.gif; name = 143.gif; path = resource/emotions/143.gif; sourceTree = ""; }; + 6DD31A10188E592200ED5FE8 /* 144.gif */ = {isa = PBXFileReference; lastKnownFileType = image.gif; name = 144.gif; path = resource/emotions/144.gif; sourceTree = ""; }; + 6DD31A11188E592200ED5FE8 /* 145.gif */ = {isa = PBXFileReference; lastKnownFileType = image.gif; name = 145.gif; path = resource/emotions/145.gif; sourceTree = ""; }; + 6DD31A12188E592200ED5FE8 /* 146.gif */ = {isa = PBXFileReference; lastKnownFileType = image.gif; name = 146.gif; path = resource/emotions/146.gif; sourceTree = ""; }; + 6DD31A13188E592200ED5FE8 /* 147.gif */ = {isa = PBXFileReference; lastKnownFileType = image.gif; name = 147.gif; path = resource/emotions/147.gif; sourceTree = ""; }; + 6DD31A14188E592200ED5FE8 /* 148.gif */ = {isa = PBXFileReference; lastKnownFileType = image.gif; name = 148.gif; path = resource/emotions/148.gif; sourceTree = ""; }; + 6DD31A15188E592200ED5FE8 /* 149.gif */ = {isa = PBXFileReference; lastKnownFileType = image.gif; name = 149.gif; path = resource/emotions/149.gif; sourceTree = ""; }; + 6DD31A16188E592200ED5FE8 /* 150.gif */ = {isa = PBXFileReference; lastKnownFileType = image.gif; name = 150.gif; path = resource/emotions/150.gif; sourceTree = ""; }; + 6DD31A17188E592200ED5FE8 /* 151.gif */ = {isa = PBXFileReference; lastKnownFileType = image.gif; name = 151.gif; path = resource/emotions/151.gif; sourceTree = ""; }; + 6DD31A18188E592200ED5FE8 /* 152.gif */ = {isa = PBXFileReference; lastKnownFileType = image.gif; name = 152.gif; path = resource/emotions/152.gif; sourceTree = ""; }; + 6DD31A19188E592200ED5FE8 /* 153.gif */ = {isa = PBXFileReference; lastKnownFileType = image.gif; name = 153.gif; path = resource/emotions/153.gif; sourceTree = ""; }; + 6DD31A1A188E592200ED5FE8 /* 154.gif */ = {isa = PBXFileReference; lastKnownFileType = image.gif; name = 154.gif; path = resource/emotions/154.gif; sourceTree = ""; }; + 6DD31A1B188E592200ED5FE8 /* 155.gif */ = {isa = PBXFileReference; lastKnownFileType = image.gif; name = 155.gif; path = resource/emotions/155.gif; sourceTree = ""; }; + 6DD31A1C188E592200ED5FE8 /* 156.gif */ = {isa = PBXFileReference; lastKnownFileType = image.gif; name = 156.gif; path = resource/emotions/156.gif; sourceTree = ""; }; + 6DD31A1D188E592200ED5FE8 /* 157.gif */ = {isa = PBXFileReference; lastKnownFileType = image.gif; name = 157.gif; path = resource/emotions/157.gif; sourceTree = ""; }; + 6DD31A1E188E592200ED5FE8 /* 158.gif */ = {isa = PBXFileReference; lastKnownFileType = image.gif; name = 158.gif; path = resource/emotions/158.gif; sourceTree = ""; }; + 6DD31A1F188E592200ED5FE8 /* 159.gif */ = {isa = PBXFileReference; lastKnownFileType = image.gif; name = 159.gif; path = resource/emotions/159.gif; sourceTree = ""; }; + 6DD31A20188E592200ED5FE8 /* 160.gif */ = {isa = PBXFileReference; lastKnownFileType = image.gif; name = 160.gif; path = resource/emotions/160.gif; sourceTree = ""; }; + 6DD31A21188E592200ED5FE8 /* 161.gif */ = {isa = PBXFileReference; lastKnownFileType = image.gif; name = 161.gif; path = resource/emotions/161.gif; sourceTree = ""; }; + 6DD31A22188E592200ED5FE8 /* 162.gif */ = {isa = PBXFileReference; lastKnownFileType = image.gif; name = 162.gif; path = resource/emotions/162.gif; sourceTree = ""; }; + 6DD31A23188E592200ED5FE8 /* 163.gif */ = {isa = PBXFileReference; lastKnownFileType = image.gif; name = 163.gif; path = resource/emotions/163.gif; sourceTree = ""; }; + 6DD31A24188E592200ED5FE8 /* 164.gif */ = {isa = PBXFileReference; lastKnownFileType = image.gif; name = 164.gif; path = resource/emotions/164.gif; sourceTree = ""; }; + 6DD31A25188E592200ED5FE8 /* 165.gif */ = {isa = PBXFileReference; lastKnownFileType = image.gif; name = 165.gif; path = resource/emotions/165.gif; sourceTree = ""; }; + 6DD31A26188E592200ED5FE8 /* 166.gif */ = {isa = PBXFileReference; lastKnownFileType = image.gif; name = 166.gif; path = resource/emotions/166.gif; sourceTree = ""; }; + 6DD31A27188E592200ED5FE8 /* 167.gif */ = {isa = PBXFileReference; lastKnownFileType = image.gif; name = 167.gif; path = resource/emotions/167.gif; sourceTree = ""; }; + 6DD31A28188E592200ED5FE8 /* 168.gif */ = {isa = PBXFileReference; lastKnownFileType = image.gif; name = 168.gif; path = resource/emotions/168.gif; sourceTree = ""; }; + 6DD31A29188E592200ED5FE8 /* 169.gif */ = {isa = PBXFileReference; lastKnownFileType = image.gif; name = 169.gif; path = resource/emotions/169.gif; sourceTree = ""; }; + 6DD31A2A188E592200ED5FE8 /* 170.gif */ = {isa = PBXFileReference; lastKnownFileType = image.gif; name = 170.gif; path = resource/emotions/170.gif; sourceTree = ""; }; + 6DD31A2B188E592200ED5FE8 /* 171.gif */ = {isa = PBXFileReference; lastKnownFileType = image.gif; name = 171.gif; path = resource/emotions/171.gif; sourceTree = ""; }; + 6DD31A2C188E592200ED5FE8 /* 172.gif */ = {isa = PBXFileReference; lastKnownFileType = image.gif; name = 172.gif; path = resource/emotions/172.gif; sourceTree = ""; }; + 6DD31A2D188E592200ED5FE8 /* 173.gif */ = {isa = PBXFileReference; lastKnownFileType = image.gif; name = 173.gif; path = resource/emotions/173.gif; sourceTree = ""; }; + 6DD31A2E188E592200ED5FE8 /* 174.gif */ = {isa = PBXFileReference; lastKnownFileType = image.gif; name = 174.gif; path = resource/emotions/174.gif; sourceTree = ""; }; + 6DD31A2F188E592200ED5FE8 /* 175.gif */ = {isa = PBXFileReference; lastKnownFileType = image.gif; name = 175.gif; path = resource/emotions/175.gif; sourceTree = ""; }; + 6DD31A30188E592200ED5FE8 /* 176.gif */ = {isa = PBXFileReference; lastKnownFileType = image.gif; name = 176.gif; path = resource/emotions/176.gif; sourceTree = ""; }; + 6DD31A31188E592200ED5FE8 /* 177.gif */ = {isa = PBXFileReference; lastKnownFileType = image.gif; name = 177.gif; path = resource/emotions/177.gif; sourceTree = ""; }; + 6DD31A32188E592200ED5FE8 /* 178.gif */ = {isa = PBXFileReference; lastKnownFileType = image.gif; name = 178.gif; path = resource/emotions/178.gif; sourceTree = ""; }; + 6DD31A33188E592200ED5FE8 /* 179.gif */ = {isa = PBXFileReference; lastKnownFileType = image.gif; name = 179.gif; path = resource/emotions/179.gif; sourceTree = ""; }; + 6DD31A34188E592200ED5FE8 /* 180.gif */ = {isa = PBXFileReference; lastKnownFileType = image.gif; name = 180.gif; path = resource/emotions/180.gif; sourceTree = ""; }; + 6DD31A35188E592200ED5FE8 /* 181.gif */ = {isa = PBXFileReference; lastKnownFileType = image.gif; name = 181.gif; path = resource/emotions/181.gif; sourceTree = ""; }; + 6DD31A36188E592200ED5FE8 /* 182.gif */ = {isa = PBXFileReference; lastKnownFileType = image.gif; name = 182.gif; path = resource/emotions/182.gif; sourceTree = ""; }; + 6DD31A37188E592200ED5FE8 /* 183.gif */ = {isa = PBXFileReference; lastKnownFileType = image.gif; name = 183.gif; path = resource/emotions/183.gif; sourceTree = ""; }; + 6DD31A38188E592200ED5FE8 /* 184.gif */ = {isa = PBXFileReference; lastKnownFileType = image.gif; name = 184.gif; path = resource/emotions/184.gif; sourceTree = ""; }; + 6DD31A39188E592200ED5FE8 /* 185.gif */ = {isa = PBXFileReference; lastKnownFileType = image.gif; name = 185.gif; path = resource/emotions/185.gif; sourceTree = ""; }; + 6DD31A3A188E592200ED5FE8 /* 186.gif */ = {isa = PBXFileReference; lastKnownFileType = image.gif; name = 186.gif; path = resource/emotions/186.gif; sourceTree = ""; }; + 6DD31A3B188E592200ED5FE8 /* 187.gif */ = {isa = PBXFileReference; lastKnownFileType = image.gif; name = 187.gif; path = resource/emotions/187.gif; sourceTree = ""; }; + 6DD31A3C188E592200ED5FE8 /* 188.gif */ = {isa = PBXFileReference; lastKnownFileType = image.gif; name = 188.gif; path = resource/emotions/188.gif; sourceTree = ""; }; + 6DD31A3D188E592200ED5FE8 /* 189.gif */ = {isa = PBXFileReference; lastKnownFileType = image.gif; name = 189.gif; path = resource/emotions/189.gif; sourceTree = ""; }; + 6DD31A3E188E592200ED5FE8 /* 190.gif */ = {isa = PBXFileReference; lastKnownFileType = image.gif; name = 190.gif; path = resource/emotions/190.gif; sourceTree = ""; }; + 6DD31A3F188E592200ED5FE8 /* 191.gif */ = {isa = PBXFileReference; lastKnownFileType = image.gif; name = 191.gif; path = resource/emotions/191.gif; sourceTree = ""; }; + 6DD31A40188E592200ED5FE8 /* 192.gif */ = {isa = PBXFileReference; lastKnownFileType = image.gif; name = 192.gif; path = resource/emotions/192.gif; sourceTree = ""; }; + 6DD31A41188E592200ED5FE8 /* 193.gif */ = {isa = PBXFileReference; lastKnownFileType = image.gif; name = 193.gif; path = resource/emotions/193.gif; sourceTree = ""; }; + 6DD31A42188E592200ED5FE8 /* 194.gif */ = {isa = PBXFileReference; lastKnownFileType = image.gif; name = 194.gif; path = resource/emotions/194.gif; sourceTree = ""; }; + 6DD31A43188E592200ED5FE8 /* 195.gif */ = {isa = PBXFileReference; lastKnownFileType = image.gif; name = 195.gif; path = resource/emotions/195.gif; sourceTree = ""; }; + 6DD31A44188E592200ED5FE8 /* 196.gif */ = {isa = PBXFileReference; lastKnownFileType = image.gif; name = 196.gif; path = resource/emotions/196.gif; sourceTree = ""; }; + 6DD31A45188E592200ED5FE8 /* 197.gif */ = {isa = PBXFileReference; lastKnownFileType = image.gif; name = 197.gif; path = resource/emotions/197.gif; sourceTree = ""; }; + 6DD31A46188E592200ED5FE8 /* 198.gif */ = {isa = PBXFileReference; lastKnownFileType = image.gif; name = 198.gif; path = resource/emotions/198.gif; sourceTree = ""; }; + 6DD31A47188E592200ED5FE8 /* 199.gif */ = {isa = PBXFileReference; lastKnownFileType = image.gif; name = 199.gif; path = resource/emotions/199.gif; sourceTree = ""; }; + 6DD31A48188E592200ED5FE8 /* 200.gif */ = {isa = PBXFileReference; lastKnownFileType = image.gif; name = 200.gif; path = resource/emotions/200.gif; sourceTree = ""; }; + 6DD31A49188E592200ED5FE8 /* 201.gif */ = {isa = PBXFileReference; lastKnownFileType = image.gif; name = 201.gif; path = resource/emotions/201.gif; sourceTree = ""; }; + 6DD31A4A188E592200ED5FE8 /* 202.gif */ = {isa = PBXFileReference; lastKnownFileType = image.gif; name = 202.gif; path = resource/emotions/202.gif; sourceTree = ""; }; + 6DD31A4B188E592200ED5FE8 /* 203.gif */ = {isa = PBXFileReference; lastKnownFileType = image.gif; name = 203.gif; path = resource/emotions/203.gif; sourceTree = ""; }; + 6DD31A4C188E592200ED5FE8 /* 204.gif */ = {isa = PBXFileReference; lastKnownFileType = image.gif; name = 204.gif; path = resource/emotions/204.gif; sourceTree = ""; }; + 6DD31A4D188E592200ED5FE8 /* 205.gif */ = {isa = PBXFileReference; lastKnownFileType = image.gif; name = 205.gif; path = resource/emotions/205.gif; sourceTree = ""; }; + 6DD31A4E188E592200ED5FE8 /* 206.gif */ = {isa = PBXFileReference; lastKnownFileType = image.gif; name = 206.gif; path = resource/emotions/206.gif; sourceTree = ""; }; + 6DD31A4F188E592200ED5FE8 /* 207.gif */ = {isa = PBXFileReference; lastKnownFileType = image.gif; name = 207.gif; path = resource/emotions/207.gif; sourceTree = ""; }; + 6DD31A50188E592200ED5FE8 /* 208.gif */ = {isa = PBXFileReference; lastKnownFileType = image.gif; name = 208.gif; path = resource/emotions/208.gif; sourceTree = ""; }; + 6DD31A51188E592200ED5FE8 /* 209.gif */ = {isa = PBXFileReference; lastKnownFileType = image.gif; name = 209.gif; path = resource/emotions/209.gif; sourceTree = ""; }; + 6DD31A52188E592200ED5FE8 /* 210.gif */ = {isa = PBXFileReference; lastKnownFileType = image.gif; name = 210.gif; path = resource/emotions/210.gif; sourceTree = ""; }; + 6DD31A53188E592200ED5FE8 /* 211.gif */ = {isa = PBXFileReference; lastKnownFileType = image.gif; name = 211.gif; path = resource/emotions/211.gif; sourceTree = ""; }; + 6DD31A54188E592200ED5FE8 /* 212.gif */ = {isa = PBXFileReference; lastKnownFileType = image.gif; name = 212.gif; path = resource/emotions/212.gif; sourceTree = ""; }; + 6DD31A55188E592200ED5FE8 /* 213.gif */ = {isa = PBXFileReference; lastKnownFileType = image.gif; name = 213.gif; path = resource/emotions/213.gif; sourceTree = ""; }; + 6DD31A56188E592200ED5FE8 /* 214.gif */ = {isa = PBXFileReference; lastKnownFileType = image.gif; name = 214.gif; path = resource/emotions/214.gif; sourceTree = ""; }; + 6DD31A57188E592200ED5FE8 /* 215.gif */ = {isa = PBXFileReference; lastKnownFileType = image.gif; name = 215.gif; path = resource/emotions/215.gif; sourceTree = ""; }; + 6DD31A58188E592200ED5FE8 /* 216.gif */ = {isa = PBXFileReference; lastKnownFileType = image.gif; name = 216.gif; path = resource/emotions/216.gif; sourceTree = ""; }; + 6DD31A59188E592200ED5FE8 /* 217.gif */ = {isa = PBXFileReference; lastKnownFileType = image.gif; name = 217.gif; path = resource/emotions/217.gif; sourceTree = ""; }; + 6DD31A5A188E592200ED5FE8 /* 218.gif */ = {isa = PBXFileReference; lastKnownFileType = image.gif; name = 218.gif; path = resource/emotions/218.gif; sourceTree = ""; }; + 6DD31A5B188E592200ED5FE8 /* 219.gif */ = {isa = PBXFileReference; lastKnownFileType = image.gif; name = 219.gif; path = resource/emotions/219.gif; sourceTree = ""; }; + 6DD31A5C188E592200ED5FE8 /* 220.gif */ = {isa = PBXFileReference; lastKnownFileType = image.gif; name = 220.gif; path = resource/emotions/220.gif; sourceTree = ""; }; + 6DD31B97188F554500ED5FE8 /* EmotionListXmlParser.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = EmotionListXmlParser.h; path = interface/emotion/EmotionListXmlParser.h; sourceTree = ""; }; + 6DD31B98188F554500ED5FE8 /* EmotionListXmlParser.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = EmotionListXmlParser.m; path = interface/emotion/EmotionListXmlParser.m; sourceTree = ""; }; + 6DD31B9A188F55C800ED5FE8 /* emotionList.xml */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xml; name = emotionList.xml; path = interface/emotion/emotionList.xml; sourceTree = ""; }; + 6DDB0D3818EC17FF00A1DA57 /* GCDAsyncSocket.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = GCDAsyncSocket.h; path = FileTransfer/GCDAsyncSocket.h; sourceTree = ""; }; + 6DDB0D3918EC17FF00A1DA57 /* GCDAsyncSocket.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = GCDAsyncSocket.m; path = FileTransfer/GCDAsyncSocket.m; sourceTree = ""; }; + 6DE7620718867ED0000EDC39 /* pull-to-refresh-arrow.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = "pull-to-refresh-arrow.png"; path = "resource/pull-to-refresh-arrow.png"; sourceTree = ""; }; + 6DE7620818867ED0000EDC39 /* release-to-refresh.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = "release-to-refresh.png"; path = "resource/release-to-refresh.png"; sourceTree = ""; }; + 6DE7620C18867FE2000EDC39 /* PullToRefreshClipView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = PullToRefreshClipView.h; path = utilities/ScrollToRefresh/PullToRefreshClipView.h; sourceTree = ""; }; + 6DE7620D18867FE2000EDC39 /* PullToRefreshClipView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = PullToRefreshClipView.m; path = utilities/ScrollToRefresh/PullToRefreshClipView.m; sourceTree = ""; }; + 6DE7620E18867FE2000EDC39 /* PullToRefreshDelegate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = PullToRefreshDelegate.h; path = utilities/ScrollToRefresh/PullToRefreshDelegate.h; sourceTree = ""; }; + 6DE7620F18867FE2000EDC39 /* PullToRefreshScrollView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = PullToRefreshScrollView.h; path = utilities/ScrollToRefresh/PullToRefreshScrollView.h; sourceTree = ""; }; + 6DE7621018867FE2000EDC39 /* PullToRefreshScrollView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = PullToRefreshScrollView.m; path = utilities/ScrollToRefresh/PullToRefreshScrollView.m; sourceTree = ""; }; + 74019794B7AD12641993FBE9 /* Pods.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = Pods.debug.xcconfig; path = "Pods/Target Support Files/Pods/Pods.debug.xcconfig"; sourceTree = ""; }; + 811405D21A68EFA6009CFC06 /* DDUnreadMessageAPI.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DDUnreadMessageAPI.h; sourceTree = ""; }; + 811405D31A68EFA6009CFC06 /* DDUnreadMessageAPI.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = DDUnreadMessageAPI.m; sourceTree = ""; }; + 8195ED4F1A7651E700DA5CA0 /* bg.jpg */ = {isa = PBXFileReference; lastKnownFileType = image.jpeg; path = bg.jpg; sourceTree = ""; }; + 8195ED501A7651E700DA5CA0 /* blb.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = blb.png; sourceTree = ""; }; + 8195ED511A7651E700DA5CA0 /* blbb.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = blbb.png; sourceTree = ""; }; + 8195ED521A7651E700DA5CA0 /* brw.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = brw.png; sourceTree = ""; }; + 8195ED531A7651E700DA5CA0 /* brwb.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = brwb.png; sourceTree = ""; }; + 8195ED541A7651E700DA5CA0 /* highlight.default.css */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.css; path = highlight.default.css; sourceTree = ""; }; + 8195ED551A7651E700DA5CA0 /* highlight.min.js */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.javascript; path = highlight.min.js; sourceTree = ""; }; + 8195ED561A7651E700DA5CA0 /* highlight.pack.js */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.javascript; path = highlight.pack.js; sourceTree = ""; }; + 8195ED571A7651E700DA5CA0 /* hook-spinner.gif */ = {isa = PBXFileReference; lastKnownFileType = image.gif; path = "hook-spinner.gif"; sourceTree = ""; }; + 8195ED581A7651E700DA5CA0 /* hook.css */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.css; path = hook.css; sourceTree = ""; }; + 8195ED591A7651E700DA5CA0 /* hook.min.js */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.javascript; path = hook.min.js; sourceTree = ""; }; + 8195ED5A1A7651E700DA5CA0 /* iscroll-probe.js */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.javascript; path = "iscroll-probe.js"; sourceTree = ""; }; + 8195ED5B1A7651E700DA5CA0 /* iscroll.js */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.javascript; path = iscroll.js; sourceTree = ""; }; + 8195ED5C1A7651E700DA5CA0 /* jquery-2.1.1.min.js */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.javascript; path = "jquery-2.1.1.min.js"; sourceTree = ""; }; + 8195ED5D1A7651E700DA5CA0 /* jquery.scrollz.css */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.css; path = jquery.scrollz.css; sourceTree = ""; }; + 8195ED5E1A7651E700DA5CA0 /* jquery.scrollz.min.js */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.javascript; path = jquery.scrollz.min.js; sourceTree = ""; }; + 8195ED5F1A7651E700DA5CA0 /* main.css */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.css; path = main.css; sourceTree = ""; }; + 8195ED601A7651E700DA5CA0 /* message.html */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.html; path = message.html; sourceTree = ""; }; + 8195ED611A7651E700DA5CA0 /* moment-with-locales.min.js */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.javascript; path = "moment-with-locales.min.js"; sourceTree = ""; }; + 8195ED621A7651E700DA5CA0 /* mousewheel.js */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.javascript; path = mousewheel.js; sourceTree = ""; }; + 8195ED631A7651E700DA5CA0 /* msg.js */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.javascript; path = msg.js; sourceTree = ""; }; + 8195ED641A7651E700DA5CA0 /* pure-min.css */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.css; path = "pure-min.css"; sourceTree = ""; }; + 8195ED651A7651E700DA5CA0 /* scrollbar.css */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.css; path = scrollbar.css; sourceTree = ""; }; + 8195ED661A7651E700DA5CA0 /* solarized_dark.css */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.css; path = solarized_dark.css; sourceTree = ""; }; + 8195ED671A7651E700DA5CA0 /* solarized_light.css */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.css; path = solarized_light.css; sourceTree = ""; }; + 8195ED681A7651E700DA5CA0 /* template.js */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.javascript; path = template.js; sourceTree = ""; }; + 81DE59C41A831B9F00040078 /* big.cur */ = {isa = PBXFileReference; lastKnownFileType = file; path = big.cur; sourceTree = ""; }; + 81DEF4FF1A5B8D9900F0799D /* DDBaseEntity.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DDBaseEntity.h; sourceTree = ""; }; + 81DEF5001A5B8D9900F0799D /* DDBaseEntity.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = DDBaseEntity.m; sourceTree = ""; }; + 81DEF5081A5B8FE800F0799D /* DDepartment.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DDepartment.h; sourceTree = ""; }; + 81DEF5091A5B8FE800F0799D /* DDepartment.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = DDepartment.m; sourceTree = ""; }; + 81DEF50B1A5B901B00F0799D /* NSDictionary+Safe.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "NSDictionary+Safe.h"; sourceTree = ""; }; + 81DEF50C1A5B901B00F0799D /* NSDictionary+Safe.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "NSDictionary+Safe.m"; sourceTree = ""; }; + 81DEF50E1A5B908100F0799D /* NSString+Additions.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "NSString+Additions.h"; sourceTree = ""; }; + 81DEF50F1A5B908100F0799D /* NSString+Additions.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "NSString+Additions.m"; sourceTree = ""; }; + 81ECFE3B1A822E5500445985 /* voice_me.gif */ = {isa = PBXFileReference; lastKnownFileType = image.gif; path = voice_me.gif; sourceTree = ""; }; + 81ECFE3C1A822E5500445985 /* voice_other.gif */ = {isa = PBXFileReference; lastKnownFileType = image.gif; path = voice_other.gif; sourceTree = ""; }; + 81ECFE3F1A8230E700445985 /* gifffer.js */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.javascript; path = gifffer.js; sourceTree = ""; }; + 81ECFE411A82338D00445985 /* voice_me.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = voice_me.png; sourceTree = ""; }; + 81ECFE421A82338D00445985 /* voice_other.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = voice_other.png; sourceTree = ""; }; + 81FA3B281A68DEBC00B379D1 /* DDHistoryMessageAPI.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DDHistoryMessageAPI.h; sourceTree = ""; }; + 81FA3B291A68DEBC00B379D1 /* DDHistoryMessageAPI.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = DDHistoryMessageAPI.m; sourceTree = ""; }; + 8AEFB8401920968C006A5C88 /* DDSendP2PCmdAPI.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DDSendP2PCmdAPI.h; sourceTree = ""; }; + 8AEFB8411920968C006A5C88 /* DDSendP2PCmdAPI.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = DDSendP2PCmdAPI.m; sourceTree = ""; }; + 8F31B5BDBE8F1E507D5515C9 /* libPods.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libPods.a; sourceTree = BUILT_PRODUCTS_DIR; }; + C40417B11A68C20E00242E20 /* MTLastMessageManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = MTLastMessageManager.h; path = modules/message/MTLastMessageManager.h; sourceTree = ""; }; + C40417B21A68C20E00242E20 /* MTLastMessageManager.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = MTLastMessageManager.m; path = modules/message/MTLastMessageManager.m; sourceTree = ""; }; + C40417B41A68D9B500242E20 /* MTUnreadMessageManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MTUnreadMessageManager.h; sourceTree = ""; }; + C40417B51A68D9B500242E20 /* MTUnreadMessageManager.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MTUnreadMessageManager.m; sourceTree = ""; }; + C40417B71A69047E00242E20 /* MTMessageEntity.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = MTMessageEntity.h; path = modules/message/MTMessageEntity.h; sourceTree = ""; }; + C40417B81A69047E00242E20 /* MTMessageEntity.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; name = MTMessageEntity.mm; path = modules/message/MTMessageEntity.mm; sourceTree = ""; }; + C406E6F818D81850005092C3 /* NSAttributedString+Message.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "NSAttributedString+Message.h"; sourceTree = ""; }; + C406E6F918D81850005092C3 /* NSAttributedString+Message.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "NSAttributedString+Message.m"; sourceTree = ""; }; + C406E6FB18D81925005092C3 /* NSImage+Scale.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "NSImage+Scale.h"; sourceTree = ""; }; + C406E6FC18D81925005092C3 /* NSImage+Scale.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "NSImage+Scale.m"; sourceTree = ""; }; + C406E6FE18D82E84005092C3 /* EmotionManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = EmotionManager.h; sourceTree = ""; }; + C406E6FF18D82E84005092C3 /* EmotionManager.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = EmotionManager.m; sourceTree = ""; }; + C406E70118D84FD2005092C3 /* DDMessageTextView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DDMessageTextView.h; sourceTree = ""; }; + C406E70218D84FD2005092C3 /* DDMessageTextView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = DDMessageTextView.m; sourceTree = ""; }; + C406E70718D8616B005092C3 /* DDChangableAttactment.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DDChangableAttactment.h; sourceTree = ""; }; + C406E70818D8616B005092C3 /* DDChangableAttactment.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = DDChangableAttactment.m; sourceTree = ""; }; + C408E8AC191B48BD005F5150 /* DDSendMessageAPI.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DDSendMessageAPI.h; sourceTree = ""; }; + C408E8AD191B48BD005F5150 /* DDSendMessageAPI.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = DDSendMessageAPI.mm; sourceTree = ""; }; + C408E8AF191B57DE005F5150 /* DDCreateGroupAPI.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DDCreateGroupAPI.h; sourceTree = ""; }; + C408E8B0191B57DE005F5150 /* DDCreateGroupAPI.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = DDCreateGroupAPI.m; sourceTree = ""; }; + C408E8C1191B83F2005F5150 /* DDOnlineUserListAPI.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DDOnlineUserListAPI.h; sourceTree = ""; }; + C408E8C2191B83F3005F5150 /* DDOnlineUserListAPI.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = DDOnlineUserListAPI.m; sourceTree = ""; }; + C408E8C4191B8B70005F5150 /* DDReceiveKickAPI.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DDReceiveKickAPI.h; sourceTree = ""; }; + C408E8C5191B8B70005F5150 /* DDReceiveKickAPI.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = DDReceiveKickAPI.m; sourceTree = ""; }; + C408E8CC191CDAE4005F5150 /* DDFileLoginAPI.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DDFileLoginAPI.h; sourceTree = ""; }; + C408E8CD191CDAE4005F5150 /* DDFileLoginAPI.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = DDFileLoginAPI.m; sourceTree = ""; }; + C408E8CF191CDCDD005F5150 /* DDFileSendAPI.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DDFileSendAPI.h; sourceTree = ""; }; + C408E8D0191CDCDD005F5150 /* DDFileSendAPI.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = DDFileSendAPI.m; sourceTree = ""; }; + C408E8D2191CE13E005F5150 /* DDGetOfflineFileAPI.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DDGetOfflineFileAPI.h; sourceTree = ""; }; + C408E8D3191CE13E005F5150 /* DDGetOfflineFileAPI.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = DDGetOfflineFileAPI.m; sourceTree = ""; }; + C408E8D9191CE44E005F5150 /* DDOtherLinkFileServerAPI.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DDOtherLinkFileServerAPI.h; sourceTree = ""; }; + C408E8DA191CE44E005F5150 /* DDOtherLinkFileServerAPI.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = DDOtherLinkFileServerAPI.m; sourceTree = ""; }; + C40F95181919C69A005CACBF /* DDAllUserAPI.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DDAllUserAPI.h; sourceTree = ""; }; + C40F95191919C69A005CACBF /* DDAllUserAPI.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = DDAllUserAPI.m; sourceTree = ""; }; + C40F95211919D501005CACBF /* DDAPIUnrequestScheduleProtocol.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = DDAPIUnrequestScheduleProtocol.h; sourceTree = ""; }; + C40F95231919D682005CACBF /* DDUnrequestSuperAPI.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DDUnrequestSuperAPI.h; sourceTree = ""; }; + C40F95241919D682005CACBF /* DDUnrequestSuperAPI.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = DDUnrequestSuperAPI.m; sourceTree = ""; }; + C40F95261919DDCC005CACBF /* DDReceiveMessageAPI.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DDReceiveMessageAPI.h; sourceTree = ""; }; + C40F95271919DDCC005CACBF /* DDReceiveMessageAPI.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = DDReceiveMessageAPI.m; sourceTree = ""; }; + C40F95291919FA00005CACBF /* DDMsgReadACKAPI.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DDMsgReadACKAPI.h; sourceTree = ""; }; + C40F952A1919FA00005CACBF /* DDMsgReadACKAPI.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = DDMsgReadACKAPI.m; sourceTree = ""; }; + C40F952C1919FA90005CACBF /* DDGroupMsgReadACKAPI.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DDGroupMsgReadACKAPI.h; sourceTree = ""; }; + C40F952D1919FA90005CACBF /* DDGroupMsgReadACKAPI.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = DDGroupMsgReadACKAPI.m; sourceTree = ""; }; + C40F952F1919FB4F005CACBF /* DDUserMsgReceivedACKAPI.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DDUserMsgReceivedACKAPI.h; sourceTree = ""; }; + C40F95301919FB4F005CACBF /* DDUserMsgReceivedACKAPI.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = DDUserMsgReceivedACKAPI.m; sourceTree = ""; }; + C40F95321919FB75005CACBF /* DDGroupMsgReceivedACKAPI.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DDGroupMsgReceivedACKAPI.h; sourceTree = ""; }; + C40F95331919FB75005CACBF /* DDGroupMsgReceivedACKAPI.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = DDGroupMsgReceivedACKAPI.m; sourceTree = ""; }; + C40F9539191A011A005CACBF /* DDGroupInfoAPI.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DDGroupInfoAPI.h; sourceTree = ""; }; + C40F953A191A011A005CACBF /* DDGroupInfoAPI.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = DDGroupInfoAPI.m; sourceTree = ""; }; + C40F9542191A563D005CACBF /* DDSeqNoManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DDSeqNoManager.h; sourceTree = ""; }; + C40F9543191A563E005CACBF /* DDSeqNoManager.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = DDSeqNoManager.m; sourceTree = ""; }; + C40F9545191B1D32005CACBF /* DDUserOnlineStateAPI.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DDUserOnlineStateAPI.h; sourceTree = ""; }; + C40F9546191B1D32005CACBF /* DDUserOnlineStateAPI.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = DDUserOnlineStateAPI.m; sourceTree = ""; }; + C40F9548191B26EE005CACBF /* DDReceiveStateChangedAPI.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DDReceiveStateChangedAPI.h; sourceTree = ""; }; + C40F9549191B26EE005CACBF /* DDReceiveStateChangedAPI.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = DDReceiveStateChangedAPI.m; sourceTree = ""; }; + C417C3971A7370E2003984D7 /* MTImageCache.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MTImageCache.h; sourceTree = ""; }; + C417C3981A7370E2003984D7 /* MTImageCache.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MTImageCache.m; sourceTree = ""; }; + C417C39A1A737C2C003984D7 /* NSImageView+MTAddition.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "NSImageView+MTAddition.h"; sourceTree = ""; }; + C417C39B1A737C2C003984D7 /* NSImageView+MTAddition.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "NSImageView+MTAddition.m"; sourceTree = ""; }; + C417C39D1A738010003984D7 /* MTImageDownload.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MTImageDownload.h; sourceTree = ""; }; + C417C39E1A738010003984D7 /* MTImageDownload.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MTImageDownload.m; sourceTree = ""; }; + C41AB118195A7EF2002AE7C7 /* DDIntranetViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DDIntranetViewController.h; sourceTree = ""; }; + C41AB119195A7EF2002AE7C7 /* DDIntranetViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = DDIntranetViewController.m; sourceTree = ""; }; + C41AB11B195AA10F002AE7C7 /* DDIntranetModule.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DDIntranetModule.h; sourceTree = ""; }; + C41AB11C195AA10F002AE7C7 /* DDIntranetModule.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = DDIntranetModule.m; sourceTree = ""; }; + C41AB11E195AA9DA002AE7C7 /* DDIntranetEntity.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DDIntranetEntity.h; sourceTree = ""; }; + C41AB11F195AA9DA002AE7C7 /* DDIntranetEntity.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = DDIntranetEntity.m; sourceTree = ""; }; + C41AB123195AAAF4002AE7C7 /* DDIntranetCell.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DDIntranetCell.h; sourceTree = ""; }; + C41AB124195AAAF4002AE7C7 /* DDIntranetCell.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = DDIntranetCell.m; sourceTree = ""; }; + C41AB126195AACE8002AE7C7 /* DDIntranentViewController.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = DDIntranentViewController.xib; sourceTree = ""; }; + C41AB129195B0487002AE7C7 /* DDIntranetContentViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DDIntranetContentViewController.h; sourceTree = ""; }; + C41AB12A195B0487002AE7C7 /* DDIntranetContentViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = DDIntranetContentViewController.m; sourceTree = ""; }; + C41AB12B195B0487002AE7C7 /* DDIntranetContentViewController.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = DDIntranetContentViewController.xib; sourceTree = ""; }; + C422FF2119261A18006EEBF9 /* DDCornerView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DDCornerView.h; sourceTree = ""; }; + C422FF2219261A18006EEBF9 /* DDCornerView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = DDCornerView.m; sourceTree = ""; }; + C42410CD199734E100B6B945 /* DDServiceAccountModule.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DDServiceAccountModule.h; sourceTree = ""; }; + C42410CE199734E100B6B945 /* DDServiceAccountModule.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = DDServiceAccountModule.m; sourceTree = ""; }; + C427BF5A199E00F800A010AA /* almance.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = almance.png; sourceTree = ""; }; + C427BF5B199E00F800A010AA /* almance@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "almance@2x.png"; sourceTree = ""; }; + C427BF5C199E00F800A010AA /* bang.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = bang.png; sourceTree = ""; }; + C427BF5D199E00F800A010AA /* bang@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "bang@2x.png"; sourceTree = ""; }; + C427BF8F19A32C0900A010AA /* MessageDate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MessageDate.h; sourceTree = ""; }; + C427BF9019A32C0900A010AA /* MessageDate.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MessageDate.m; sourceTree = ""; }; + C42A070518E7D01D004461E1 /* NSWindow+Animation.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "NSWindow+Animation.h"; sourceTree = ""; }; + C42A070618E7D01D004461E1 /* NSWindow+Animation.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "NSWindow+Animation.m"; sourceTree = ""; }; + C42A070918E80066004461E1 /* DDMessageSendManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = DDMessageSendManager.h; path = modules/Chatting/DDMessageSendManager.h; sourceTree = ""; }; + C42A070A18E80066004461E1 /* DDMessageSendManager.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = DDMessageSendManager.m; path = modules/Chatting/DDMessageSendManager.m; sourceTree = ""; }; + C42A070C18E80E49004461E1 /* DDImageUploader.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = DDImageUploader.h; path = modules/Chatting/DDImageUploader.h; sourceTree = ""; }; + C42A070D18E80E49004461E1 /* DDImageUploader.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = DDImageUploader.m; path = modules/Chatting/DDImageUploader.m; sourceTree = ""; }; + C42D4EA119247EEA00C7B6F6 /* PFMoveApplication.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PFMoveApplication.h; sourceTree = ""; }; + C42D4EA219247EEA00C7B6F6 /* PFMoveApplication.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = PFMoveApplication.m; sourceTree = ""; }; + C42D4EA41924BBF000C7B6F6 /* Recent-cell-background.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "Recent-cell-background.png"; sourceTree = ""; }; + C42D4EA51924BBF000C7B6F6 /* Recent-cell-background@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "Recent-cell-background@2x.png"; sourceTree = ""; }; + C43802D018C4860B002555BB /* DDGroupDataWindow.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DDGroupDataWindow.h; sourceTree = ""; }; + C43802D118C4860B002555BB /* DDGroupDataWindow.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = DDGroupDataWindow.m; sourceTree = ""; }; + C43802D318C48627002555BB /* DDGroupDataModule.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DDGroupDataModule.h; sourceTree = ""; }; + C43802D418C48627002555BB /* DDGroupDataModule.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = DDGroupDataModule.m; sourceTree = ""; }; + C43802D618C48650002555BB /* DDGroupDataWindow.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = DDGroupDataWindow.xib; sourceTree = ""; }; + C43802D818C48A40002555BB /* DDGroupInfoCell.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DDGroupInfoCell.h; sourceTree = ""; }; + C43802D918C48A40002555BB /* DDGroupInfoCell.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = DDGroupInfoCell.m; sourceTree = ""; }; + C438032218C5C916002555BB /* DDUserInfoManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DDUserInfoManager.h; sourceTree = ""; }; + C438032318C5C916002555BB /* DDUserInfoManager.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = DDUserInfoManager.m; sourceTree = ""; }; + C438032518C5D130002555BB /* DDGroupInfoManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DDGroupInfoManager.h; sourceTree = ""; }; + C438032618C5D130002555BB /* DDGroupInfoManager.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = DDGroupInfoManager.m; sourceTree = ""; }; + C4498A0118D71A92009FEA4A /* MessageShowView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MessageShowView.h; sourceTree = ""; }; + C4498A0218D71A92009FEA4A /* MessageShowView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MessageShowView.m; sourceTree = ""; }; + C4498A0318D71A92009FEA4A /* MessageViewFactory.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MessageViewFactory.h; sourceTree = ""; }; + C4498A0418D71A92009FEA4A /* MessageViewFactory.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MessageViewFactory.m; sourceTree = ""; }; + C4498A0518D71A92009FEA4A /* NSTextView+Rect.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "NSTextView+Rect.h"; sourceTree = ""; }; + C4498A0618D71A92009FEA4A /* NSTextView+Rect.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "NSTextView+Rect.m"; sourceTree = ""; }; + C4498A1B18D7D976009FEA4A /* DDChattingViewModule.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DDChattingViewModule.h; sourceTree = ""; }; + C4498A1C18D7D976009FEA4A /* DDChattingViewModule.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = DDChattingViewModule.m; sourceTree = ""; }; + C44C203E1900B2850069A31F /* DDMessageReviewWindowController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DDMessageReviewWindowController.h; sourceTree = ""; }; + C44C203F1900B2850069A31F /* DDMessageReviewWindowController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = DDMessageReviewWindowController.m; sourceTree = ""; }; + C44C20411900B2AE0069A31F /* DDMessageReviewModule.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DDMessageReviewModule.h; sourceTree = ""; }; + C44C20421900B2AE0069A31F /* DDMessageReviewModule.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = DDMessageReviewModule.m; sourceTree = ""; }; + C454AB0C18F914D90040BBF0 /* DDLoginServer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = DDLoginServer.h; path = modules/login/DDLoginServer.h; sourceTree = ""; }; + C454AB0D18F914D90040BBF0 /* DDLoginServer.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = DDLoginServer.m; path = modules/login/DDLoginServer.m; sourceTree = ""; }; + C4563FB91906365C009DEB05 /* DDChattingContactListModule.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DDChattingContactListModule.h; sourceTree = ""; }; + C4563FBA1906365C009DEB05 /* DDChattingContactListModule.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = DDChattingContactListModule.m; sourceTree = ""; }; + C4563FBC1906384F009DEB05 /* DDSearch.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DDSearch.h; sourceTree = ""; }; + C4563FBD1906384F009DEB05 /* DDSearch.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = DDSearch.m; sourceTree = ""; }; + C46B2D9718E3D8F000FE278B /* icon_statusbar_blue.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = icon_statusbar_blue.png; path = resource/icon_statusbar_blue.png; sourceTree = ""; }; + C46B2D9918E3D95F00FE278B /* icon_statusbar_blue@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = "icon_statusbar_blue@2x.png"; path = "resource/icon_statusbar_blue@2x.png"; sourceTree = ""; }; + C46B2D9B18E435E400FE278B /* DDSetting+OffLineReadMsgManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "DDSetting+OffLineReadMsgManager.h"; sourceTree = ""; }; + C46B2D9C18E435E400FE278B /* DDSetting+OffLineReadMsgManager.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "DDSetting+OffLineReadMsgManager.m"; sourceTree = ""; }; + C46C51BA18D2DBC000149B7F /* DDChattingContactListCell.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DDChattingContactListCell.h; sourceTree = ""; }; + C46C51BB18D2DBC000149B7F /* DDChattingContactListCell.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = DDChattingContactListCell.m; sourceTree = ""; }; + C46C810D197500FA00157856 /* DDCornerRadiusTextField.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DDCornerRadiusTextField.h; sourceTree = ""; }; + C46C810E197500FA00157856 /* DDCornerRadiusTextField.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = DDCornerRadiusTextField.m; sourceTree = ""; }; + C47934861915F217009C39AE /* NSView+LayerAddition.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "NSView+LayerAddition.h"; sourceTree = ""; }; + C47934871915F217009C39AE /* NSView+LayerAddition.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "NSView+LayerAddition.m"; sourceTree = ""; }; + C4793489191610AF009C39AE /* login-account.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "login-account.png"; sourceTree = ""; }; + C479348A191610AF009C39AE /* login-account@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "login-account@2x.png"; sourceTree = ""; }; + C479348B191610AF009C39AE /* login-avatar-background.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "login-avatar-background.png"; sourceTree = ""; }; + C479348C191610AF009C39AE /* login-avatar-background@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "login-avatar-background@2x.png"; sourceTree = ""; }; + C479348D191610AF009C39AE /* login-background.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "login-background.png"; sourceTree = ""; }; + C479348E191610AF009C39AE /* login-background@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "login-background@2x.png"; sourceTree = ""; }; + C479348F191610AF009C39AE /* login-input-background.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "login-input-background.png"; sourceTree = ""; }; + C4793490191610AF009C39AE /* login-input-background@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "login-input-background@2x.png"; sourceTree = ""; }; + C4793491191610AF009C39AE /* login-logining.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "login-logining.png"; sourceTree = ""; }; + C4793492191610AF009C39AE /* login-logining@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "login-logining@2x.png"; sourceTree = ""; }; + C4793493191610AF009C39AE /* login-password.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "login-password.png"; sourceTree = ""; }; + C4793494191610AF009C39AE /* login-password@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "login-password@2x.png"; sourceTree = ""; }; + C47934A1191612A4009C39AE /* Teamtalk-bottom.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "Teamtalk-bottom.png"; sourceTree = ""; }; + C47934A2191612A4009C39AE /* Teamtalk-bottom@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "Teamtalk-bottom@2x.png"; sourceTree = ""; }; + C47934A3191612A4009C39AE /* TeamTalk-Top.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "TeamTalk-Top.png"; sourceTree = ""; }; + C47934A4191612A4009C39AE /* TeamTalk-Top@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "TeamTalk-Top@2x.png"; sourceTree = ""; }; + C47934A919163477009C39AE /* DDCustomWindow.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DDCustomWindow.h; sourceTree = ""; }; + C47934AA19163477009C39AE /* DDCustomWindow.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = DDCustomWindow.m; sourceTree = ""; }; + C47934AC191635D3009C39AE /* close.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = close.png; sourceTree = ""; }; + C47934AD191635D3009C39AE /* close@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "close@2x.png"; sourceTree = ""; }; + C47934B019163C1F009C39AE /* HoverTableRowView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = HoverTableRowView.h; path = modules/Main/HoverTableRowView.h; sourceTree = ""; }; + C47934B119163C1F009C39AE /* HoverTableRowView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = HoverTableRowView.m; path = modules/Main/HoverTableRowView.m; sourceTree = ""; }; + C47934B3191656F8009C39AE /* addgroummember-unselected.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "addgroummember-unselected.png"; sourceTree = ""; }; + C47934B4191656F8009C39AE /* addgroummember-unselected@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "addgroummember-unselected@2x.png"; sourceTree = ""; }; + C47934B5191656F8009C39AE /* addgroupmember-arrow.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "addgroupmember-arrow.png"; sourceTree = ""; }; + C47934B6191656F8009C39AE /* addgroupmember-arrow@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "addgroupmember-arrow@2x.png"; sourceTree = ""; }; + C47934B7191656F8009C39AE /* addgroupmember-cancel.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "addgroupmember-cancel.png"; sourceTree = ""; }; + C47934B8191656F8009C39AE /* addgroupmember-cancel@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "addgroupmember-cancel@2x.png"; sourceTree = ""; }; + C47934B9191656F8009C39AE /* addgroupmember-cancel2.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "addgroupmember-cancel2.png"; sourceTree = ""; }; + C47934BA191656F8009C39AE /* addgroupmember-cancel2@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "addgroupmember-cancel2@2x.png"; sourceTree = ""; }; + C47934BB191656F8009C39AE /* addgroupmember-search-background.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "addgroupmember-search-background.png"; sourceTree = ""; }; + C47934BC191656F8009C39AE /* addgroupmember-search-background@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "addgroupmember-search-background@2x.png"; sourceTree = ""; }; + C47934BD191656F8009C39AE /* addgroupmember-selected.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "addgroupmember-selected.png"; sourceTree = ""; }; + C47934BE191656F8009C39AE /* addgroupmember-selected@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "addgroupmember-selected@2x.png"; sourceTree = ""; }; + C47934BF191656F8009C39AE /* addgroupmember-sure.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "addgroupmember-sure.png"; sourceTree = ""; }; + C47934C0191656F8009C39AE /* addgroupmember-sure@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "addgroupmember-sure@2x.png"; sourceTree = ""; }; + C47934CF19165EB5009C39AE /* DDAddGroupMemberDepartmentCell.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = DDAddGroupMemberDepartmentCell.h; path = modules/session/DDAddGroupMemberDepartmentCell.h; sourceTree = ""; }; + C47934D019165EB5009C39AE /* DDAddGroupMemberDepartmentCell.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = DDAddGroupMemberDepartmentCell.m; path = modules/session/DDAddGroupMemberDepartmentCell.m; sourceTree = ""; }; + C47934D219166415009C39AE /* DDAddGroupMemberDepartmentRowView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = DDAddGroupMemberDepartmentRowView.h; path = modules/session/DDAddGroupMemberDepartmentRowView.h; sourceTree = ""; }; + C47934D319166415009C39AE /* DDAddGroupMemberDepartmentRowView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = DDAddGroupMemberDepartmentRowView.m; path = modules/session/DDAddGroupMemberDepartmentRowView.m; sourceTree = ""; }; + C47934D519167458009C39AE /* DDMultiSelectedOutlineView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = DDMultiSelectedOutlineView.h; path = modules/session/DDMultiSelectedOutlineView.h; sourceTree = ""; }; + C47934D619167458009C39AE /* DDMultiSelectedOutlineView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = DDMultiSelectedOutlineView.m; path = modules/session/DDMultiSelectedOutlineView.m; sourceTree = ""; }; + C47934D819172063009C39AE /* DDUserInfoPanel.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DDUserInfoPanel.h; sourceTree = ""; }; + C47934D919172063009C39AE /* DDUserInfoPanel.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = DDUserInfoPanel.m; sourceTree = ""; }; + C47934DB191724D5009C39AE /* DDUserInfoPanel.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = DDUserInfoPanel.xib; sourceTree = ""; }; + C47934DD19172599009C39AE /* person-info-background.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "person-info-background.png"; sourceTree = ""; }; + C47934DE19172599009C39AE /* person-info-background@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "person-info-background@2x.png"; sourceTree = ""; }; + C47934DF19172599009C39AE /* person-info-chat.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "person-info-chat.png"; sourceTree = ""; }; + C47934E019172599009C39AE /* person-info-chat@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "person-info-chat@2x.png"; sourceTree = ""; }; + C47934E519173B00009C39AE /* group-info-background.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "group-info-background.png"; sourceTree = ""; }; + C47934E619173B00009C39AE /* group-info-background@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "group-info-background@2x.png"; sourceTree = ""; }; + C47934E719173B00009C39AE /* group-info-line.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "group-info-line.png"; sourceTree = ""; }; + C47934E819173B00009C39AE /* group-info-line@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "group-info-line@2x.png"; sourceTree = ""; }; + C47934ED19175F3E009C39AE /* file-transmit-background.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "file-transmit-background.png"; sourceTree = ""; }; + C47934EE19175F3E009C39AE /* file-transmit-background@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "file-transmit-background@2x.png"; sourceTree = ""; }; + C47934EF19175F3E009C39AE /* file-transmit-cancel.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "file-transmit-cancel.png"; sourceTree = ""; }; + C47934F019175F3E009C39AE /* file-transmit-cancel@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "file-transmit-cancel@2x.png"; sourceTree = ""; }; + C47934F119175F3E009C39AE /* file-transmit-look.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "file-transmit-look.png"; sourceTree = ""; }; + C47934F219175F3E009C39AE /* file-transmit-look@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "file-transmit-look@2x.png"; sourceTree = ""; }; + C47934F319175F3E009C39AE /* file-transmit-update.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "file-transmit-update.png"; sourceTree = ""; }; + C47934F419175F3E009C39AE /* file-transmit-update@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "file-transmit-update@2x.png"; sourceTree = ""; }; + C47934FD19177DF1009C39AE /* DDMessageReviewWindow.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = DDMessageReviewWindow.xib; sourceTree = ""; }; + C47934FF191782E7009C39AE /* NSWindow+Addition.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "NSWindow+Addition.h"; sourceTree = ""; }; + C4793500191782E7009C39AE /* NSWindow+Addition.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "NSWindow+Addition.m"; sourceTree = ""; }; + C479350219178A69009C39AE /* DDMessageReviewContactsViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DDMessageReviewContactsViewController.h; sourceTree = ""; }; + C479350319178A69009C39AE /* DDMessageReviewContactsViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = DDMessageReviewContactsViewController.m; sourceTree = ""; }; + C479350519178A89009C39AE /* DDMessagesReviewContentViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DDMessagesReviewContentViewController.h; sourceTree = ""; }; + C479350619178A89009C39AE /* DDMessagesReviewContentViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = DDMessagesReviewContentViewController.m; sourceTree = ""; }; + C479350819178CF5009C39AE /* DDMessageReviewContactsCellView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DDMessageReviewContactsCellView.h; sourceTree = ""; }; + C479350919178CF5009C39AE /* DDMessageReviewContactsCellView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = DDMessageReviewContactsCellView.m; sourceTree = ""; }; + C479350E19187782009C39AE /* DDMessagesReviewContentModule.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DDMessagesReviewContentModule.h; sourceTree = ""; }; + C479350F19187782009C39AE /* DDMessagesReviewContentModule.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = DDMessagesReviewContentModule.m; sourceTree = ""; }; + C479351119188C50009C39AE /* message-review-last-page.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "message-review-last-page.png"; sourceTree = ""; }; + C479351219188C50009C39AE /* message-review-last-page@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "message-review-last-page@2x.png"; sourceTree = ""; }; + C479351319188C50009C39AE /* message-review-nextpage.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "message-review-nextpage.png"; sourceTree = ""; }; + C479351419188C50009C39AE /* message-review-nextpage@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "message-review-nextpage@2x.png"; sourceTree = ""; }; + C479351919188DE4009C39AE /* message-review-double-lastpage.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "message-review-double-lastpage.png"; sourceTree = ""; }; + C479351A19188DE4009C39AE /* message-review-double-lastpage@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "message-review-double-lastpage@2x.png"; sourceTree = ""; }; + C479351B19188DE4009C39AE /* message-review-double-nextpage.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "message-review-double-nextpage.png"; sourceTree = ""; }; + C479351C19188DE4009C39AE /* message-review-double-nextpage@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "message-review-double-nextpage@2x.png"; sourceTree = ""; }; + C47935211918B765009C39AE /* window-titleBar-background.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "window-titleBar-background.png"; sourceTree = ""; }; + C47935221918B765009C39AE /* window-titleBar-background@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "window-titleBar-background@2x.png"; sourceTree = ""; }; + C47935251918B9C0009C39AE /* DDMessagesReviewWindow.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DDMessagesReviewWindow.h; sourceTree = ""; }; + C47935261918B9C0009C39AE /* DDMessagesReviewWindow.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = DDMessagesReviewWindow.m; sourceTree = ""; }; + C47935281918BD9F009C39AE /* DDMessageReviewTextView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DDMessageReviewTextView.h; sourceTree = ""; }; + C47935291918BD9F009C39AE /* DDMessageReviewTextView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = DDMessageReviewTextView.m; sourceTree = ""; }; + C479352C1918E807009C39AE /* DDLoginAPI.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DDLoginAPI.h; sourceTree = ""; }; + C479352D1918E807009C39AE /* DDLoginAPI.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = DDLoginAPI.mm; sourceTree = ""; }; + C47935321918E88B009C39AE /* DDFixedGroupAPI.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DDFixedGroupAPI.h; sourceTree = ""; }; + C47935331918E88B009C39AE /* DDFixedGroupAPI.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = DDFixedGroupAPI.m; sourceTree = ""; }; + C485913D18C73FD800DD30DD /* icon_fav.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = icon_fav.png; path = resource/icon_fav.png; sourceTree = ""; }; + C485913E18C73FD800DD30DD /* icon_fav@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = "icon_fav@2x.png"; path = "resource/icon_fav@2x.png"; sourceTree = ""; }; + C487386718C8093C00C51541 /* lady_placeholder.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = lady_placeholder.png; path = resource/lady_placeholder.png; sourceTree = ""; }; + C487386818C8093C00C51541 /* lady_placeholder@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = "lady_placeholder@2x.png"; path = "resource/lady_placeholder@2x.png"; sourceTree = ""; }; + C487386918C8093C00C51541 /* man_placeholder.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = man_placeholder.png; path = resource/man_placeholder.png; sourceTree = ""; }; + C487386A18C8093D00C51541 /* man_placeholder@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = "man_placeholder@2x.png"; path = "resource/man_placeholder@2x.png"; sourceTree = ""; }; + C487386F18C814D700C51541 /* group_placeholder.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = group_placeholder.png; path = resource/group_placeholder.png; sourceTree = ""; }; + C487387018C814D700C51541 /* group_placeholder@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = "group_placeholder@2x.png"; path = "resource/group_placeholder@2x.png"; sourceTree = ""; }; + C48B104518D1AE9000DEF8C6 /* CrashReportManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = CrashReportManager.h; path = CrashReport/CrashReportManager.h; sourceTree = ""; }; + C48B104618D1AE9000DEF8C6 /* CrashReportManager.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = CrashReportManager.m; path = CrashReport/CrashReportManager.m; sourceTree = ""; }; + C48B104818D1B18500DEF8C6 /* IOKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = IOKit.framework; path = System/Library/Frameworks/IOKit.framework; sourceTree = SDKROOT; }; + C48D603318BC634A00F5ED30 /* DDUserDataWindowController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DDUserDataWindowController.h; sourceTree = ""; }; + C48D603418BC634A00F5ED30 /* DDUserDataWindowController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = DDUserDataWindowController.m; sourceTree = ""; }; + C48D603818BC670900F5ED30 /* DDUserDataModel.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DDUserDataModel.h; sourceTree = ""; }; + C48D603918BC670900F5ED30 /* DDUserDataModel.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = DDUserDataModel.m; sourceTree = ""; }; + C48D603E18BED99500F5ED30 /* SpellLibrary.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = SpellLibrary.h; path = interface/mainWindow/searchField/SpellLibrary.h; sourceTree = ""; }; + C48D603F18BED99500F5ED30 /* SpellLibrary.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = SpellLibrary.m; path = interface/mainWindow/searchField/SpellLibrary.m; sourceTree = ""; }; + C48E2F431A6224F1002F3FEB /* MTUserEntity.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MTUserEntity.h; sourceTree = ""; }; + C48E2F441A6224F1002F3FEB /* MTUserEntity.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MTUserEntity.m; sourceTree = ""; }; + C48E2F461A622506002F3FEB /* MTGroupEntity.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MTGroupEntity.h; sourceTree = ""; }; + C48E2F471A622506002F3FEB /* MTGroupEntity.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MTGroupEntity.m; sourceTree = ""; }; + C48E2F4B1A622543002F3FEB /* DDOriginModuleProtocol.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DDOriginModuleProtocol.h; sourceTree = ""; }; + C48E2F4C1A62258D002F3FEB /* MTGroupModule.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MTGroupModule.h; sourceTree = ""; }; + C48E2F4D1A62258D002F3FEB /* MTGroupModule.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MTGroupModule.m; sourceTree = ""; }; + C48E2F4F1A6225BA002F3FEB /* MTUserModule.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MTUserModule.h; sourceTree = ""; }; + C48E2F501A6225BA002F3FEB /* MTUserModule.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MTUserModule.m; sourceTree = ""; }; + C48E2F521A62264A002F3FEB /* DDOriginEntity.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DDOriginEntity.h; sourceTree = ""; }; + C48E2F531A62264A002F3FEB /* DDOriginEntity.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = DDOriginEntity.m; sourceTree = ""; }; + C48E2F5B1A622886002F3FEB /* MTSessionEntity.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MTSessionEntity.h; sourceTree = ""; }; + C48E2F5C1A622886002F3FEB /* MTSessionEntity.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MTSessionEntity.m; sourceTree = ""; }; + C48E2F5E1A622899002F3FEB /* MTSessionModule.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MTSessionModule.h; sourceTree = ""; }; + C48E2F5F1A622899002F3FEB /* MTSessionModule.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MTSessionModule.m; sourceTree = ""; }; + C48E2F611A622BFC002F3FEB /* DDRootModule.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = DDRootModule.h; path = modules/DDRootModule.h; sourceTree = ""; }; + C48E2F621A622BFC002F3FEB /* DDRootModule.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = DDRootModule.m; path = modules/DDRootModule.m; sourceTree = ""; }; + C48E2F641A625A1F002F3FEB /* DDHeartBeatAPI.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DDHeartBeatAPI.h; sourceTree = ""; }; + C48E2F651A625A1F002F3FEB /* DDHeartBeatAPI.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = DDHeartBeatAPI.m; sourceTree = ""; }; + C48E2F671A626C7F002F3FEB /* MTMessageModule.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = MTMessageModule.h; path = modules/message/MTMessageModule.h; sourceTree = ""; }; + C48E2F681A626C7F002F3FEB /* MTMessageModule.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = MTMessageModule.m; path = modules/message/MTMessageModule.m; sourceTree = ""; }; + C48E395918F4E6C000C610EB /* DDCurrentUserState.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DDCurrentUserState.h; sourceTree = ""; }; + C48E395A18F4E6C000C610EB /* DDCurrentUserState.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = DDCurrentUserState.m; sourceTree = ""; }; + C48E399C18F8EA4F00C610EB /* DDTcpClientManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DDTcpClientManager.h; sourceTree = ""; }; + C48E399D18F8EA4F00C610EB /* DDTcpClientManager.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = DDTcpClientManager.m; sourceTree = ""; }; + C48E399F18F9112800C610EB /* DDClientStateMaintenanceManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DDClientStateMaintenanceManager.h; sourceTree = ""; }; + C48E39A018F9112800C610EB /* DDClientStateMaintenanceManager.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = DDClientStateMaintenanceManager.m; sourceTree = ""; }; + C48E79DE18FB861A00A1FA66 /* DDLoginWindowControllerModule.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = DDLoginWindowControllerModule.h; path = modules/login/DDLoginWindowControllerModule.h; sourceTree = ""; }; + C48E79DF18FB861A00A1FA66 /* DDLoginWindowControllerModule.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = DDLoginWindowControllerModule.m; path = modules/login/DDLoginWindowControllerModule.m; sourceTree = ""; }; + C48E79E418FBB28E00A1FA66 /* DDClientState.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DDClientState.h; sourceTree = ""; }; + C48E79E518FBB28E00A1FA66 /* DDClientState.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = DDClientState.m; sourceTree = ""; }; + C48E79E718FCE31A00A1FA66 /* DDMainWindowControllerModule.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = DDMainWindowControllerModule.h; path = modules/Main/DDMainWindowControllerModule.h; sourceTree = ""; }; + C48E79E818FCE31A00A1FA66 /* DDMainWindowControllerModule.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = DDMainWindowControllerModule.m; path = modules/Main/DDMainWindowControllerModule.m; sourceTree = ""; }; + C48E79EA18FE1FAE00A1FA66 /* message.wav */ = {isa = PBXFileReference; lastKnownFileType = audio.wav; name = message.wav; path = resource/message.wav; sourceTree = ""; }; + C48E79EE18FE2AF000A1FA66 /* DDPathHelp.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DDPathHelp.h; sourceTree = ""; }; + C48E79EF18FE2AF000A1FA66 /* DDPathHelp.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = DDPathHelp.m; sourceTree = ""; }; + C48E79F218FF686200A1FA66 /* DDApplicationUpdate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DDApplicationUpdate.h; sourceTree = ""; }; + C48E79F318FF686200A1FA66 /* DDApplicationUpdate.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = DDApplicationUpdate.m; sourceTree = ""; }; + C48E79F518FFAE7800A1FA66 /* NSImage+Addition.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "NSImage+Addition.h"; sourceTree = ""; }; + C48E79F618FFAE7800A1FA66 /* NSImage+Addition.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "NSImage+Addition.m"; sourceTree = ""; }; + C48EEE5218F0169E00FCB35B /* NotificationHelp.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = NotificationHelp.h; sourceTree = ""; }; + C48EEE5318F0169E00FCB35B /* NotificationHelp.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = NotificationHelp.m; sourceTree = ""; }; + C492F40518C2CEF4005A3AC9 /* DDAddChatGroupCell.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = DDAddChatGroupCell.h; path = interface/chat/addChatGroup/DDAddChatGroupCell.h; sourceTree = ""; }; + C492F40618C2CEF4005A3AC9 /* DDAddChatGroupCell.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = DDAddChatGroupCell.m; path = interface/chat/addChatGroup/DDAddChatGroupCell.m; sourceTree = ""; }; + C492F40A18C2D0F2005A3AC9 /* DDAddChatGroupModel.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = DDAddChatGroupModel.h; path = interface/chat/addChatGroup/DDAddChatGroupModel.h; sourceTree = ""; }; + C492F40B18C2D0F2005A3AC9 /* DDAddChatGroupModel.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = DDAddChatGroupModel.m; path = interface/chat/addChatGroup/DDAddChatGroupModel.m; sourceTree = ""; }; + C492F40D18C2E3DA005A3AC9 /* DDAddChatGroup.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = DDAddChatGroup.h; path = interface/chat/addChatGroup/DDAddChatGroup.h; sourceTree = ""; }; + C492F40E18C2E3DA005A3AC9 /* DDAddChatGroup.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = DDAddChatGroup.m; path = interface/chat/addChatGroup/DDAddChatGroup.m; sourceTree = ""; }; + C492F41018C2FD8A005A3AC9 /* DDAddGroupSelectedCell.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = DDAddGroupSelectedCell.h; path = interface/chat/addChatGroup/DDAddGroupSelectedCell.h; sourceTree = ""; }; + C492F41118C2FD8A005A3AC9 /* DDAddGroupSelectedCell.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = DDAddGroupSelectedCell.m; path = interface/chat/addChatGroup/DDAddGroupSelectedCell.m; sourceTree = ""; }; + C492F41518C30FF5005A3AC9 /* icon_check_empty.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = icon_check_empty.png; path = resource/icon_check_empty.png; sourceTree = ""; }; + C492F41618C30FF5005A3AC9 /* icon_check_empty@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = "icon_check_empty@2x.png"; path = "resource/icon_check_empty@2x.png"; sourceTree = ""; }; + C492F41918C31092005A3AC9 /* icon_check_filled.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = icon_check_filled.png; path = resource/icon_check_filled.png; sourceTree = ""; }; + C492F41A18C31092005A3AC9 /* icon_check_filled@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = "icon_check_filled@2x.png"; path = "resource/icon_check_filled@2x.png"; sourceTree = ""; }; + C4A09C8C190FC2AC00B39BF3 /* DDRecentContactsViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = DDRecentContactsViewController.h; path = modules/Main/DDRecentContactsViewController.h; sourceTree = ""; }; + C4A09C8D190FC2AC00B39BF3 /* DDRecentContactsViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = DDRecentContactsViewController.m; path = modules/Main/DDRecentContactsViewController.m; sourceTree = ""; }; + C4A09C8F190FC2FA00B39BF3 /* DDRecentContactsModule.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = DDRecentContactsModule.h; path = modules/Main/DDRecentContactsModule.h; sourceTree = ""; }; + C4A09C90190FC2FA00B39BF3 /* DDRecentContactsModule.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = DDRecentContactsModule.m; path = modules/Main/DDRecentContactsModule.m; sourceTree = ""; }; + C4A09C94190FC44400B39BF3 /* DDGroupViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = DDGroupViewController.h; path = modules/Main/DDGroupViewController.h; sourceTree = ""; }; + C4A09C95190FC44400B39BF3 /* DDGroupViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = DDGroupViewController.m; path = modules/Main/DDGroupViewController.m; sourceTree = ""; }; + C4A09C97190FC4CA00B39BF3 /* DDGroupVCModule.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = DDGroupVCModule.h; path = modules/Main/DDGroupVCModule.h; sourceTree = ""; }; + C4A09C98190FC4CA00B39BF3 /* DDGroupVCModule.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = DDGroupVCModule.m; path = modules/Main/DDGroupVCModule.m; sourceTree = ""; }; + C4A09C9A190FC7B000B39BF3 /* DDRecentContactsViewController.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; name = DDRecentContactsViewController.xib; path = modules/Main/DDRecentContactsViewController.xib; sourceTree = ""; }; + C4A09C9C191089A800B39BF3 /* DDRecentContactsCell.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = DDRecentContactsCell.h; path = modules/Main/DDRecentContactsCell.h; sourceTree = ""; }; + C4A09C9D191089A800B39BF3 /* DDRecentContactsCell.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = DDRecentContactsCell.m; path = modules/Main/DDRecentContactsCell.m; sourceTree = ""; }; + C4A09C9F19108E7600B39BF3 /* recent-contacts-cell-background.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "recent-contacts-cell-background.png"; sourceTree = ""; }; + C4A09CA019108E7600B39BF3 /* recent-contacts-cell-background@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "recent-contacts-cell-background@2x.png"; sourceTree = ""; }; + C4A09CA119108E7600B39BF3 /* search-background.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "search-background.png"; sourceTree = ""; }; + C4A09CA219108E7600B39BF3 /* search-background@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "search-background@2x.png"; sourceTree = ""; }; + C4A09CA319108E7600B39BF3 /* shield.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = shield.png; sourceTree = ""; }; + C4A09CA419108E7600B39BF3 /* shield@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "shield@2x.png"; sourceTree = ""; }; + C4A09CA719108E7600B39BF3 /* unread-count-background.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "unread-count-background.png"; sourceTree = ""; }; + C4A09CA819108E7600B39BF3 /* unread-count-background@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "unread-count-background@2x.png"; sourceTree = ""; }; + C4A09CB91910AAC200B39BF3 /* DDGroupViewController.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = DDGroupViewController.xib; sourceTree = ""; }; + C4A09CBB1910ABA600B39BF3 /* DDGroupCell.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = DDGroupCell.h; path = modules/Main/DDGroupCell.h; sourceTree = ""; }; + C4A09CBC1910ABA600B39BF3 /* DDGroupCell.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = DDGroupCell.m; path = modules/Main/DDGroupCell.m; sourceTree = ""; }; + C4A09CBE1910D19B00B39BF3 /* DDSearchViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = DDSearchViewController.h; path = modules/Main/DDSearchViewController.h; sourceTree = ""; }; + C4A09CBF1910D19B00B39BF3 /* DDSearchViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = DDSearchViewController.m; path = modules/Main/DDSearchViewController.m; sourceTree = ""; }; + C4A09CC11910D2BA00B39BF3 /* DDSearchResultCell.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = DDSearchResultCell.h; path = modules/Main/DDSearchResultCell.h; sourceTree = ""; }; + C4A09CC21910D2BA00B39BF3 /* DDSearchResultCell.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = DDSearchResultCell.m; path = modules/Main/DDSearchResultCell.m; sourceTree = ""; }; + C4A09CC41910EA2300B39BF3 /* DDAppBackgroundColorView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DDAppBackgroundColorView.h; sourceTree = ""; }; + C4A09CC51910EA2400B39BF3 /* DDAppBackgroundColorView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = DDAppBackgroundColorView.m; sourceTree = ""; }; + C4A09CC71910EFA800B39BF3 /* state-leave.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "state-leave.png"; sourceTree = ""; }; + C4A09CC81910EFA800B39BF3 /* state-leave@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "state-leave@2x.png"; sourceTree = ""; }; + C4A09CC91910EFA800B39BF3 /* state-offline.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "state-offline.png"; sourceTree = ""; }; + C4A09CCA1910EFA800B39BF3 /* state-offline@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "state-offline@2x.png"; sourceTree = ""; }; + C4A09CCB1910EFA800B39BF3 /* state-online.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "state-online.png"; sourceTree = ""; }; + C4A09CCC1910EFA800B39BF3 /* state-online@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "state-online@2x.png"; sourceTree = ""; }; + C4A09CD31910FB6700B39BF3 /* add-group-member.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "add-group-member.png"; sourceTree = ""; }; + C4A09CD41910FB6700B39BF3 /* add-group-member@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "add-group-member@2x.png"; sourceTree = ""; }; + C4A09CD51910FB6700B39BF3 /* transport-file.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "transport-file.png"; sourceTree = ""; }; + C4A09CD61910FB6700B39BF3 /* transport-file@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "transport-file@2x.png"; sourceTree = ""; }; + C4A09CDB1910FED700B39BF3 /* emotion.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = emotion.png; sourceTree = ""; }; + C4A09CDC1910FED700B39BF3 /* emotion@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "emotion@2x.png"; sourceTree = ""; }; + C4A09CDD1910FED700B39BF3 /* screen-shot.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "screen-shot.png"; sourceTree = ""; }; + C4A09CDE1910FED700B39BF3 /* screen-shot@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "screen-shot@2x.png"; sourceTree = ""; }; + C4A6F1DD18EE4FD900A6AD61 /* StateMaintenanceManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = StateMaintenanceManager.h; sourceTree = ""; }; + C4A6F1DE18EE4FD900A6AD61 /* StateMaintenanceManager.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = StateMaintenanceManager.m; sourceTree = ""; }; + C4A6F1E118EFD61400A6AD61 /* DDLoginManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = DDLoginManager.h; path = modules/login/DDLoginManager.h; sourceTree = ""; }; + C4A6F1E218EFD61400A6AD61 /* DDLoginManager.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = DDLoginManager.m; path = modules/login/DDLoginManager.m; sourceTree = ""; }; + C4A6F1E418EFD69400A6AD61 /* DDHttpServer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = DDHttpServer.h; path = modules/login/DDHttpServer.h; sourceTree = ""; }; + C4A6F1E518EFD69400A6AD61 /* DDHttpServer.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = DDHttpServer.m; path = modules/login/DDHttpServer.m; sourceTree = ""; }; + C4A6F1EA18EFD6CE00A6AD61 /* DDMsgServer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = DDMsgServer.h; path = modules/login/DDMsgServer.h; sourceTree = ""; }; + C4A6F1EB18EFD6CE00A6AD61 /* DDMsgServer.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = DDMsgServer.m; path = modules/login/DDMsgServer.m; sourceTree = ""; }; + C4AB954418DAD5C9000181AD /* WhiteBackgroundView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = WhiteBackgroundView.h; sourceTree = ""; }; + C4AB954518DAD5C9000181AD /* WhiteBackgroundView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = WhiteBackgroundView.m; sourceTree = ""; }; + C4AB954718DAE70F000181AD /* shield_gray.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = shield_gray.png; path = resource/shield_gray.png; sourceTree = ""; }; + C4AB954818DAE70F000181AD /* shield_gray@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = "shield_gray@2x.png"; path = "resource/shield_gray@2x.png"; sourceTree = ""; }; + C4AB954918DAE70F000181AD /* shield_red.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = shield_red.png; path = resource/shield_red.png; sourceTree = ""; }; + C4AB954A18DAE70F000181AD /* shield_red@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = "shield_red@2x.png"; path = "resource/shield_red@2x.png"; sourceTree = ""; }; + C4AB955218DBF006000181AD /* DrawView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DrawView.h; sourceTree = ""; }; + C4AB955318DBF006000181AD /* DrawView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = DrawView.m; sourceTree = ""; }; + C4AB95A718E16AEA000181AD /* DDSetting.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DDSetting.h; sourceTree = ""; }; + C4AB95A818E16AEA000181AD /* DDSetting.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = DDSetting.m; sourceTree = ""; }; + C4C0724C1AA583F900C01D0D /* DDGetLastMessageIDAPI.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DDGetLastMessageIDAPI.h; sourceTree = ""; }; + C4C0724D1AA583F900C01D0D /* DDGetLastMessageIDAPI.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = DDGetLastMessageIDAPI.m; sourceTree = ""; }; + C4C1CB83197E695000386AB0 /* DDModifyUserAvatarAPI.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DDModifyUserAvatarAPI.h; sourceTree = ""; }; + C4C1CB84197E695000386AB0 /* DDModifyUserAvatarAPI.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = DDModifyUserAvatarAPI.m; sourceTree = ""; }; + C4C1CB86197FCB4600386AB0 /* dd_modisy_avatar@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = "dd_modisy_avatar@2x.png"; path = "resource/dd_modisy_avatar@2x.png"; sourceTree = ""; }; + C4C1CB87197FCB4600386AB0 /* dd_modisy_avatar.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = dd_modisy_avatar.png; path = resource/dd_modisy_avatar.png; sourceTree = ""; }; + C4C472FA18EFE5EF00BC4E73 /* DDTcpServer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = DDTcpServer.h; path = modules/login/DDTcpServer.h; sourceTree = ""; }; + C4C472FB18EFE5EF00BC4E73 /* DDTcpServer.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = DDTcpServer.m; path = modules/login/DDTcpServer.m; sourceTree = ""; }; + C4C926C0190DE988005B3234 /* DDContactsRowView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = DDContactsRowView.h; path = modules/Main/DDContactsRowView.h; sourceTree = ""; }; + C4C926C1190DE988005B3234 /* DDContactsRowView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = DDContactsRowView.m; path = modules/Main/DDContactsRowView.m; sourceTree = ""; }; + C4C926C4190F3C1D005B3234 /* background.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = background.png; sourceTree = ""; }; + C4C926C5190F3C1D005B3234 /* background@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "background@2x.png"; sourceTree = ""; }; + C4C926C6190F3C1D005B3234 /* setting.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = setting.png; sourceTree = ""; }; + C4C926C7190F3C1D005B3234 /* setting@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "setting@2x.png"; sourceTree = ""; }; + C4C926CA190F3C1D005B3234 /* left-bar-avatar.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "left-bar-avatar.png"; sourceTree = ""; }; + C4C926CB190F3C1D005B3234 /* left-bar-avatar@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "left-bar-avatar@2x.png"; sourceTree = ""; }; + C4C926CC190F3C1D005B3234 /* 形状-477.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "形状-477.png"; sourceTree = ""; }; + C4C926CD190F3C1D005B3234 /* 形状-477@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "形状-477@2x.png"; sourceTree = ""; }; + C4C926D9190F4274005B3234 /* DDGridBackgroundView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DDGridBackgroundView.h; sourceTree = ""; }; + C4C926DA190F4274005B3234 /* DDGridBackgroundView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = DDGridBackgroundView.m; sourceTree = ""; }; + C4C926DC190F4778005B3234 /* state-background.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "state-background.png"; sourceTree = ""; }; + C4C926DD190F4778005B3234 /* state-background@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "state-background@2x.png"; sourceTree = ""; }; + C4C926E0190F4F28005B3234 /* group-selected.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "group-selected.png"; sourceTree = ""; }; + C4C926E1190F4F28005B3234 /* group-selected@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "group-selected@2x.png"; sourceTree = ""; }; + C4C926E2190F4F28005B3234 /* group-unselected.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "group-unselected.png"; sourceTree = ""; }; + C4C926E3190F4F28005B3234 /* group-unselected@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "group-unselected@2x.png"; sourceTree = ""; }; + C4C926E4190F4F28005B3234 /* left-bar-selected-background.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "left-bar-selected-background.png"; sourceTree = ""; }; + C4C926E5190F4F28005B3234 /* left-bar-selected-background@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "left-bar-selected-background@2x.png"; sourceTree = ""; }; + C4C926E6190F4F28005B3234 /* recent-chat-selected.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "recent-chat-selected.png"; sourceTree = ""; }; + C4C926E7190F4F28005B3234 /* recent-chat-selected@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "recent-chat-selected@2x.png"; sourceTree = ""; }; + C4C926E8190F4F28005B3234 /* recent-chat-unselected.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "recent-chat-unselected.png"; sourceTree = ""; }; + C4C926E9190F4F28005B3234 /* recent-chat-unselected@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "recent-chat-unselected@2x.png"; sourceTree = ""; }; + C4C926F4190F51C4005B3234 /* DDLeftBarViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = DDLeftBarViewController.h; path = modules/Main/DDLeftBarViewController.h; sourceTree = ""; }; + C4C926F5190F51C4005B3234 /* DDLeftBarViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = DDLeftBarViewController.m; path = modules/Main/DDLeftBarViewController.m; sourceTree = ""; }; + C4C926F7190F526F005B3234 /* DDLeftBarItem.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = DDLeftBarItem.h; path = modules/Main/DDLeftBarItem.h; sourceTree = ""; }; + C4C926F8190F526F005B3234 /* DDLeftBarItem.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = DDLeftBarItem.m; path = modules/Main/DDLeftBarItem.m; sourceTree = ""; }; + C4D2EFA518B322D6000F0B12 /* CONSTANT.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = CONSTANT.h; sourceTree = ""; }; + C4D2EFF418B4B29A000F0B12 /* DDSearchResultCell.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = DDSearchResultCell.xib; sourceTree = ""; }; + C4D2EFF618B4B4C9000F0B12 /* DDSearchFieldResultCell.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = DDSearchFieldResultCell.h; path = interface/mainWindow/searchField/DDSearchFieldResultCell.h; sourceTree = ""; }; + C4D2EFF718B4B4C9000F0B12 /* DDSearchFieldResultCell.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = DDSearchFieldResultCell.m; path = interface/mainWindow/searchField/DDSearchFieldResultCell.m; sourceTree = ""; }; + C4D2EFF918B70F1F000F0B12 /* NSView+Addition.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = "NSView+Addition.h"; path = "utilities/NSView+Addition.h"; sourceTree = ""; }; + C4D2EFFA18B70F1F000F0B12 /* NSView+Addition.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = "NSView+Addition.m"; path = "utilities/NSView+Addition.m"; sourceTree = ""; }; + C4E9762C196154B60009BE1E /* intranet_back.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = intranet_back.png; path = TeamTalk/resource/intranet_back.png; sourceTree = SOURCE_ROOT; }; + C4E9762D196154B60009BE1E /* intranet_back@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = "intranet_back@2x.png"; path = "TeamTalk/resource/intranet_back@2x.png"; sourceTree = SOURCE_ROOT; }; + C4E9762E196154B60009BE1E /* intranet_forward.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = intranet_forward.png; path = TeamTalk/resource/intranet_forward.png; sourceTree = SOURCE_ROOT; }; + C4E9762F196154B60009BE1E /* intranet_forward@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = "intranet_forward@2x.png"; path = "TeamTalk/resource/intranet_forward@2x.png"; sourceTree = SOURCE_ROOT; }; + C4E97630196154B60009BE1E /* intranet_home.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = intranet_home.png; path = TeamTalk/resource/intranet_home.png; sourceTree = SOURCE_ROOT; }; + C4E97631196154B60009BE1E /* intranet_home@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = "intranet_home@2x.png"; path = "TeamTalk/resource/intranet_home@2x.png"; sourceTree = SOURCE_ROOT; }; + C4E97632196154B60009BE1E /* intranet_icon.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = intranet_icon.png; path = TeamTalk/resource/intranet_icon.png; sourceTree = SOURCE_ROOT; }; + C4E97633196154B60009BE1E /* intranet_icon@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = "intranet_icon@2x.png"; path = "TeamTalk/resource/intranet_icon@2x.png"; sourceTree = SOURCE_ROOT; }; + C4E97634196154B60009BE1E /* intranet_refresh.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = intranet_refresh.png; path = TeamTalk/resource/intranet_refresh.png; sourceTree = SOURCE_ROOT; }; + C4E97635196154B60009BE1E /* intranet_refresh@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = "intranet_refresh@2x.png"; path = "TeamTalk/resource/intranet_refresh@2x.png"; sourceTree = SOURCE_ROOT; }; + C4E97636196154B60009BE1E /* Intranet_unselected.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = Intranet_unselected.png; path = TeamTalk/resource/Intranet_unselected.png; sourceTree = SOURCE_ROOT; }; + C4E97637196154B60009BE1E /* Intranet_unselected@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = "Intranet_unselected@2x.png"; path = "TeamTalk/resource/Intranet_unselected@2x.png"; sourceTree = SOURCE_ROOT; }; + C4E97646196163670009BE1E /* intranet_selected.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = intranet_selected.png; path = TeamTalk/resource/intranet_selected.png; sourceTree = SOURCE_ROOT; }; + C4E97647196163670009BE1E /* intranet_selected@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = "intranet_selected@2x.png"; path = "TeamTalk/resource/intranet_selected@2x.png"; sourceTree = SOURCE_ROOT; }; + C4EBA724192D8E9C00B72723 /* No-File-transfor.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "No-File-transfor.png"; sourceTree = ""; }; + C4EBA725192D8E9C00B72723 /* No-File-transfor@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "No-File-transfor@2x.png"; sourceTree = ""; }; + C4EBA728192D91E400B72723 /* DDUserDetailInfoAPI.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DDUserDetailInfoAPI.h; sourceTree = ""; }; + C4EBA729192D91E400B72723 /* DDUserDetailInfoAPI.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = DDUserDetailInfoAPI.m; sourceTree = ""; }; + C4F7E5ED1907D24E006E31F3 /* DDSundriesCenter.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DDSundriesCenter.h; sourceTree = ""; }; + C4F7E5EE1907D24E006E31F3 /* DDSundriesCenter.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = DDSundriesCenter.m; sourceTree = ""; }; + C4F7E5F51908DA52006E31F3 /* DDAPIScheduleProtocol.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = DDAPIScheduleProtocol.h; sourceTree = ""; }; + C4F90F9A1963DFE900DF2828 /* DDIntranetMessageEntity.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DDIntranetMessageEntity.h; sourceTree = ""; }; + C4F90F9B1963DFE900DF2828 /* DDIntranetMessageEntity.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = DDIntranetMessageEntity.m; sourceTree = ""; }; + C4FA6BD41908E0640097849B /* DDAPISchedule.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DDAPISchedule.h; sourceTree = ""; }; + C4FA6BD51908E0640097849B /* DDAPISchedule.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = DDAPISchedule.m; sourceTree = ""; }; + C4FA6BD71908F5BD0097849B /* DDSuperAPI.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DDSuperAPI.h; sourceTree = ""; }; + C4FA6BD81908F5BD0097849B /* DDSuperAPI.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = DDSuperAPI.m; sourceTree = ""; }; + C4FA6BDA190909EA0097849B /* DDRecentConactsAPI.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = DDRecentConactsAPI.h; path = ../DDRecentConactsAPI.h; sourceTree = ""; }; + C4FA6BDB190909EA0097849B /* DDRecentConactsAPI.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = DDRecentConactsAPI.m; path = ../DDRecentConactsAPI.m; sourceTree = ""; }; + C4FA6BDD190B94350097849B /* DDChattingWindowManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = DDChattingWindowManager.h; path = modules/Main/DDChattingWindowManager.h; sourceTree = ""; }; + C4FA6BDE190B94350097849B /* DDChattingWindowManager.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = DDChattingWindowManager.m; path = modules/Main/DDChattingWindowManager.m; sourceTree = ""; }; + C4FE221819205C1000FFB520 /* DDRemoveSessionAPI.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DDRemoveSessionAPI.h; sourceTree = ""; }; + C4FE221919205C1000FFB520 /* DDRemoveSessionAPI.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = DDRemoveSessionAPI.m; sourceTree = ""; }; + C4FE221B192065CE00FFB520 /* top-session.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "top-session.png"; sourceTree = ""; }; + C4FE221C192065CE00FFB520 /* top-session@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "top-session@2x.png"; sourceTree = ""; }; + C4FE221F19209B2300FFB520 /* DDReceiveP2PMessageAPI.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DDReceiveP2PMessageAPI.h; sourceTree = ""; }; + C4FE222019209B2300FFB520 /* DDReceiveP2PMessageAPI.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = DDReceiveP2PMessageAPI.m; sourceTree = ""; }; + C4FE22221920B2A000FFB520 /* DDOtherFileResponseAPI.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DDOtherFileResponseAPI.h; sourceTree = ""; }; + C4FE22231920B2A000FFB520 /* DDOtherFileResponseAPI.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = DDOtherFileResponseAPI.m; sourceTree = ""; }; + C4FE22251920B40100FFB520 /* DDAbortFileSendAPI.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = DDAbortFileSendAPI.h; path = ../UnrequestAPI/DDAbortFileSendAPI.h; sourceTree = ""; }; + C4FE22261920B40100FFB520 /* DDAbortFileSendAPI.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = DDAbortFileSendAPI.m; path = ../UnrequestAPI/DDAbortFileSendAPI.m; sourceTree = ""; }; + C4FE22281920C04700FFB520 /* DDReceiveAbortFileSendAPI.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DDReceiveAbortFileSendAPI.h; sourceTree = ""; }; + C4FE22291920C04700FFB520 /* DDReceiveAbortFileSendAPI.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = DDReceiveAbortFileSendAPI.m; sourceTree = ""; }; + C4FE222B1920C60300FFB520 /* DDSendOffLineFileAPI.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DDSendOffLineFileAPI.h; sourceTree = ""; }; + C4FE222C1920C60300FFB520 /* DDSendOffLineFileAPI.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = DDSendOffLineFileAPI.m; sourceTree = ""; }; + C4FE222E1920C8D700FFB520 /* DDOtherSendOfflineFileAPI.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DDOtherSendOfflineFileAPI.h; sourceTree = ""; }; + C4FE222F1920C8D700FFB520 /* DDOtherSendOfflineFileAPI.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = DDOtherSendOfflineFileAPI.m; sourceTree = ""; }; + C4FE22341920CBB200FFB520 /* DDOfflineFileUploadFinishedAPI.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DDOfflineFileUploadFinishedAPI.h; sourceTree = ""; }; + C4FE22351920CBB200FFB520 /* DDOfflineFileUploadFinishedAPI.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = DDOfflineFileUploadFinishedAPI.m; sourceTree = ""; }; + C4FE22371920CE5600FFB520 /* DDReceiveOtherOfflineFileUploadFinishedAPI.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DDReceiveOtherOfflineFileUploadFinishedAPI.h; sourceTree = ""; }; + C4FE22381920CE5600FFB520 /* DDReceiveOtherOfflineFileUploadFinishedAPI.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = DDReceiveOtherOfflineFileUploadFinishedAPI.m; sourceTree = ""; }; + C4FE223A1920CF3700FFB520 /* DDAddOfflineFileAPI.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = DDAddOfflineFileAPI.h; path = ../UnrequestAPI/DDAddOfflineFileAPI.h; sourceTree = ""; }; + C4FE223B1920CF3700FFB520 /* DDAddOfflineFileAPI.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = DDAddOfflineFileAPI.m; path = ../UnrequestAPI/DDAddOfflineFileAPI.m; sourceTree = ""; }; + C4FE223D1920CF4A00FFB520 /* DDDeleteOfflineFileAPI.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = DDDeleteOfflineFileAPI.h; path = ../UnrequestAPI/DDDeleteOfflineFileAPI.h; sourceTree = ""; }; + C4FE223E1920CF4A00FFB520 /* DDDeleteOfflineFileAPI.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = DDDeleteOfflineFileAPI.m; path = ../UnrequestAPI/DDDeleteOfflineFileAPI.m; sourceTree = ""; }; + C4FE22401920DEE500FFB520 /* DDFileSendResponseAPI.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DDFileSendResponseAPI.h; sourceTree = ""; }; + C4FE22411920DEE500FFB520 /* DDFileSendResponseAPI.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = DDFileSendResponseAPI.m; sourceTree = ""; }; + C4FE22431920E43600FFB520 /* DDReceiveOtherResponseAPI.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DDReceiveOtherResponseAPI.h; sourceTree = ""; }; + C4FE22441920E43600FFB520 /* DDReceiveOtherResponseAPI.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = DDReceiveOtherResponseAPI.m; sourceTree = ""; }; + C4FE22461920EC4D00FFB520 /* DDReceiveOtherSendFileAPI.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DDReceiveOtherSendFileAPI.h; sourceTree = ""; }; + C4FE22471920EC4D00FFB520 /* DDReceiveOtherSendFileAPI.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = DDReceiveOtherSendFileAPI.m; sourceTree = ""; }; + C4FE22491920F11300FFB520 /* DDReadyReceiveFileAPI.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DDReadyReceiveFileAPI.h; sourceTree = ""; }; + C4FE224A1920F11300FFB520 /* DDReadyReceiveFileAPI.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = DDReadyReceiveFileAPI.m; sourceTree = ""; }; + C4FE224C1920F35600FFB520 /* DDReceiveOtherReadyAcceptFileAPI.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DDReceiveOtherReadyAcceptFileAPI.h; sourceTree = ""; }; + C4FE224D1920F35600FFB520 /* DDReceiveOtherReadyAcceptFileAPI.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = DDReceiveOtherReadyAcceptFileAPI.m; sourceTree = ""; }; + C4FF47361A7F4EB500B21A0D /* MTPreviewItem.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MTPreviewItem.h; sourceTree = ""; }; + C4FF47371A7F4EB500B21A0D /* MTPreviewItem.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MTPreviewItem.m; sourceTree = ""; }; + C4FF47391A7FA0F800B21A0D /* DDReceiveGroupMemberChangedAPI.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DDReceiveGroupMemberChangedAPI.h; sourceTree = ""; }; + C4FF473A1A7FA0F800B21A0D /* DDReceiveGroupMemberChangedAPI.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = DDReceiveGroupMemberChangedAPI.m; sourceTree = ""; }; + C4FF473C1A80ACA900B21A0D /* MTDraftManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MTDraftManager.h; sourceTree = ""; }; + C4FF473D1A80ACA900B21A0D /* MTDraftManager.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MTDraftManager.m; sourceTree = ""; }; + C4FF473F1A80AD9100B21A0D /* MTInputHistoryManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MTInputHistoryManager.h; sourceTree = ""; }; + C4FF47401A80AD9100B21A0D /* MTInputHistoryManager.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MTInputHistoryManager.m; sourceTree = ""; }; + C4FF47421A81AF3700B21A0D /* msgfail.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = msgfail.png; sourceTree = ""; }; + C4FF47501A823E5800B21A0D /* speexdec */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.executable"; path = speexdec; sourceTree = ""; }; + C4FF47511A823E5800B21A0D /* speexenc */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.executable"; path = speexenc; sourceTree = ""; }; + C4FF47571A83578200B21A0D /* DataOutputStream+Addition.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "DataOutputStream+Addition.h"; sourceTree = ""; }; + C4FF47581A83578200B21A0D /* DataOutputStream+Addition.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "DataOutputStream+Addition.m"; sourceTree = ""; }; + EF29F2BB1AB80077001FC3EE /* MTDepartmentManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MTDepartmentManager.h; sourceTree = ""; }; + EF29F2BC1AB80077001FC3EE /* MTDepartmentManager.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MTDepartmentManager.m; sourceTree = ""; }; + EF29F2BE1AB81E15001FC3EE /* DDDepartmentInfoAPI.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DDDepartmentInfoAPI.h; sourceTree = ""; }; + EF29F2BF1AB81E15001FC3EE /* DDDepartmentInfoAPI.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = DDDepartmentInfoAPI.m; sourceTree = ""; }; + EF29F2C11AB82087001FC3EE /* MTDepartmentEntity.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MTDepartmentEntity.h; sourceTree = ""; }; + EF29F2C21AB82087001FC3EE /* MTDepartmentEntity.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MTDepartmentEntity.m; sourceTree = ""; }; +/* End PBXFileReference section */ + +/* Begin PBXFrameworksBuildPhase section */ + 5738472C1820CDA000443653 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + 5E8EB9DD1934713A008B1890 /* ImageIO.framework in Frameworks */, + 57DF183B18DFD0E4003A19F6 /* libsqlite3.dylib in Frameworks */, + C48B104918D1B18500DEF8C6 /* IOKit.framework in Frameworks */, + 5714A0001845D45900DDBA25 /* Carbon.framework in Frameworks */, + 57CA0F4D18D2D42D005C0B0D /* CrashReporter.framework in Frameworks */, + 18C769FA188E444B0066AA8C /* SystemConfiguration.framework in Frameworks */, + 57DEB6921A7F833F00961C6F /* libsecurity.a in Frameworks */, + 57EFFB2B18580FC2006D8DE1 /* libz.dylib in Frameworks */, + 570D6E52183A053E00F68CB0 /* Quartz.framework in Frameworks */, + 570D6E53183A053E00F68CB0 /* QuartzCore.framework in Frameworks */, + 57AB317F1828816100B7766E /* Security.framework in Frameworks */, + 573847331820CDA000443653 /* Cocoa.framework in Frameworks */, + 5700BF0918A8A4B00060092F /* Sparkle.framework in Frameworks */, + 9068ED71E21126C61D07D32B /* libPods.a in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXFrameworksBuildPhase section */ + +/* Begin PBXGroup section */ + 183B53431869794E009073EC /* Modules */ = { + isa = PBXGroup; + children = ( + 37E4C0331A6E484B00178EA8 /* SysConfig */, + 37E4C02B1A6CAD5400178EA8 /* DB */, + 579E54731A67C39B003031A1 /* http */, + C48E2F611A622BFC002F3FEB /* DDRootModule.h */, + C48E2F621A622BFC002F3FEB /* DDRootModule.m */, + C48E2F581A622843002F3FEB /* Session1 */, + C48E2F3C1A6224B3002F3FEB /* OriginEntity */, + C48E2F3D1A6224B3002F3FEB /* OriginModule */, + 81DEF4E61A5B774600F0799D /* pb */, + C42410CC199734C300B6B945 /* ServiceAccount */, + C4F7E5F31908D7E0006E31F3 /* API */, + C48E79F818FFD73500A1FA66 /* MessageReview */, + C4A6F1DC18EE4FBA00A6AD61 /* StateMaintenance */, + C4AB95A618E16AC7000181AD /* Setting */, + C48B104418D1AE5900DEF8C6 /* CrashReport */, + C48D603218BC632500F5ED30 /* User group Data */, + 57285DFA18B32EDA00E90EC2 /* shortcut */, + 57D1379118AB57DD00E3E6A4 /* preference */, + 18A38FEE187A986B00F3F19D /* Main */, + 183B534E186AA2CD009073EC /* Login */, + 189B0A931875772300C3997A /* Message */, + 18A38FF3187AACC800F3F19D /* Common */, + 6D41DA1A1861962200C1FD65 /* FileTransfer */, + 57149FF51845D32E00DDBA25 /* ScreenCapture */, + 183B534418697989009073EC /* Session */, + ); + name = Modules; + sourceTree = ""; + }; + 183B534418697989009073EC /* Session */ = { + isa = PBXGroup; + children = ( + 57D5D155184C217800852738 /* chat */, + 6DD31976188E3BD000ED5FE8 /* emotion */, + ); + name = Session; + sourceTree = ""; + }; + 183B534E186AA2CD009073EC /* Login */ = { + isa = PBXGroup; + children = ( + C4A6F1E018EFD5EA00A6AD61 /* LoginModule */, + 57AF22881820F2EF00758483 /* DDLoginWindowController.h */, + 57AF22891820F2EF00758483 /* DDLoginWindowController.m */, + C48E79DE18FB861A00A1FA66 /* DDLoginWindowControllerModule.h */, + C48E79DF18FB861A00A1FA66 /* DDLoginWindowControllerModule.m */, + 57AF228B1820F31600758483 /* LoginSelect.xib */, + 6D2A847C18B1D5E20004032B /* DDLoginWindow.h */, + 6D2A847D18B1D5E20004032B /* DDLoginWindow.m */, + ); + name = Login; + sourceTree = ""; + }; + 183B5365186ACEFE009073EC /* Core Data */ = { + isa = PBXGroup; + children = ( + ); + name = "Core Data"; + sourceTree = ""; + }; + 183B537D18714138009073EC /* Extensions */ = { + isa = PBXGroup; + children = ( + 183B538418714739009073EC /* NSDictionary+MGJ.h */, + 183B538518714739009073EC /* NSDictionary+MGJ.m */, + 183B537E187141A6009073EC /* NSData+NSJSONSerialization.h */, + 183B537F187141A6009073EC /* NSData+NSJSONSerialization.m */, + 6D70EA92186C43C000402CF5 /* NSImage+Stretchable.h */, + 6D70EA93186C43C000402CF5 /* NSImage+Stretchable.m */, + 183B538D1872976D009073EC /* NSNotification+DDLogic.h */, + 183B538E1872976D009073EC /* NSNotification+DDLogic.m */, + ); + name = Extensions; + sourceTree = ""; + }; + 187FABD81868546A006ACC30 /* DDLogic */ = { + isa = PBXGroup; + children = ( + 579E547A1A67C426003031A1 /* DDLogic.h */, + 579E547B1A67C426003031A1 /* DDLogic.m */, + 579E547C1A67C426003031A1 /* DDLogicProtocol.h */, + 573847661820CE9900443653 /* TcpLink */, + 183B5365186ACEFE009073EC /* Core Data */, + 187FABF918685CFE006ACC30 /* Task */, + 187FABF818685CF7006ACC30 /* Module */, + ); + name = DDLogic; + sourceTree = ""; + }; + 187FABF818685CF7006ACC30 /* Module */ = { + isa = PBXGroup; + children = ( + 187FAC0118685D97006ACC30 /* DDModuleManager.h */, + 187FAC0218685D97006ACC30 /* DDModuleManager.m */, + 187FAC0318685D97006ACC30 /* DDWatch.h */, + 187FAC0418685D97006ACC30 /* DDWatch.m */, + 1861DC4C18686D54008AA109 /* DDModuleID.h */, + 183B53901872B720009073EC /* DDModuleDataManager.h */, + 183B53911872B720009073EC /* DDModuleDataManager.m */, + ); + name = Module; + sourceTree = ""; + }; + 187FABF918685CFE006ACC30 /* Task */ = { + isa = PBXGroup; + children = ( + 187FAC0718685DE2006ACC30 /* DDTask.h */, + 183B534018695FBA009073EC /* DDTaskManager.h */, + 183B534118695FBA009073EC /* DDTaskManager.m */, + 187FAC0818685DE2006ACC30 /* DDTaskOperation.h */, + 187FAC0918685DE2006ACC30 /* DDTaskOperation.m */, + ); + name = Task; + sourceTree = ""; + }; + 189B0A931875772300C3997A /* Message */ = { + isa = PBXGroup; + children = ( + C48E2F671A626C7F002F3FEB /* MTMessageModule.h */, + C48E2F681A626C7F002F3FEB /* MTMessageModule.m */, + C40417B11A68C20E00242E20 /* MTLastMessageManager.h */, + C40417B21A68C20E00242E20 /* MTLastMessageManager.m */, + C40417B41A68D9B500242E20 /* MTUnreadMessageManager.h */, + C40417B51A68D9B500242E20 /* MTUnreadMessageManager.m */, + C4FF473C1A80ACA900B21A0D /* MTDraftManager.h */, + C4FF473D1A80ACA900B21A0D /* MTDraftManager.m */, + C4FF473F1A80AD9100B21A0D /* MTInputHistoryManager.h */, + C4FF47401A80AD9100B21A0D /* MTInputHistoryManager.m */, + C40417B71A69047E00242E20 /* MTMessageEntity.h */, + C40417B81A69047E00242E20 /* MTMessageEntity.mm */, + ); + name = Message; + sourceTree = ""; + }; + 18A38FEE187A986B00F3F19D /* Main */ = { + isa = PBXGroup; + children = ( + 57C0A8841A68B3B400ECDE45 /* AvatorImageView.h */, + 57C0A8851A68B3B400ECDE45 /* AvatorImageView.m */, + 18A38FEF187A98BF00F3F19D /* DDMainModule.h */, + 18A38FF0187A98BF00F3F19D /* DDMainModule.m */, + 577C167D18473F2C009718D7 /* mainWindow */, + ); + name = Main; + sourceTree = ""; + }; + 18A38FF3187AACC800F3F19D /* Common */ = { + isa = PBXGroup; + children = ( + 18A38FF5187AAD1A00F3F19D /* DDCommonModule.h */, + 18A38FF6187AAD1A00F3F19D /* DDCommonModule.m */, + ); + name = Common; + sourceTree = ""; + }; + 18C769EF188E3FF50066AA8C /* Reachability */ = { + isa = PBXGroup; + children = ( + 18C769FB188E44720066AA8C /* Reachability.h */, + 18C769FC188E44720066AA8C /* Reachability.m */, + ); + name = Reachability; + sourceTree = ""; + }; + 37E4C02B1A6CAD5400178EA8 /* DB */ = { + isa = PBXGroup; + children = ( + 37E4C02C1A6CAE4600178EA8 /* MTDatabaseUtil.h */, + 37E4C02D1A6CAE4600178EA8 /* MTDatabaseUtil.m */, + ); + name = DB; + path = modules/DB; + sourceTree = ""; + }; + 37E4C0331A6E484B00178EA8 /* SysConfig */ = { + isa = PBXGroup; + children = ( + 37E4C0341A6E484B00178EA8 /* Entity */, + 37E4C0351A6E484B00178EA8 /* Module */, + ); + name = SysConfig; + path = modules/SysConfig; + sourceTree = ""; + }; + 37E4C0341A6E484B00178EA8 /* Entity */ = { + isa = PBXGroup; + children = ( + 37E4C0361A6E486A00178EA8 /* MTSysConfigEntity.h */, + 37E4C0371A6E486A00178EA8 /* MTSysConfigEntity.m */, + ); + path = Entity; + sourceTree = ""; + }; + 37E4C0351A6E484B00178EA8 /* Module */ = { + isa = PBXGroup; + children = ( + 37E4C0391A6E487E00178EA8 /* MTSysConfigModule.h */, + 37E4C03A1A6E487E00178EA8 /* MTSysConfigModule.m */, + ); + path = Module; + sourceTree = ""; + }; + 57124E44187AADD2006D2DCA /* alertWindow */ = { + isa = PBXGroup; + children = ( + 57124E48187AAEAD006D2DCA /* DDAlertWindowController.h */, + 57124E49187AAEAD006D2DCA /* DDAlertWindowController.m */, + 57124E4A187AAEAD006D2DCA /* DDAlertWindowController.xib */, + ); + name = alertWindow; + sourceTree = ""; + }; + 57149F88184487C200DDBA25 /* EGOImageLoader */ = { + isa = PBXGroup; + children = ( + 57149F89184487C200DDBA25 /* EGOCache.h */, + 57149F8A184487C200DDBA25 /* EGOCache.m */, + 57149F8B184487C200DDBA25 /* EGOImageLoadConnection.h */, + 57149F8C184487C200DDBA25 /* EGOImageLoadConnection.m */, + 57149F8D184487C200DDBA25 /* EGOImageLoader.h */, + 57149F8E184487C200DDBA25 /* EGOImageLoader.m */, + 57149F8F184487C200DDBA25 /* EGOImageView.h */, + 57149F90184487C200DDBA25 /* EGOImageView.m */, + ); + path = EGOImageLoader; + sourceTree = ""; + }; + 57149FEE1845926C00DDBA25 /* scrollbar auto-hiding */ = { + isa = PBXGroup; + children = ( + 57149FEF184592B700DDBA25 /* DDAutoScrollView.h */, + 57149FF0184592B700DDBA25 /* DDAutoScrollView.m */, + ); + name = "scrollbar auto-hiding"; + sourceTree = ""; + }; + 57149FF51845D32E00DDBA25 /* ScreenCapture */ = { + isa = PBXGroup; + children = ( + 57149FF61845D32E00DDBA25 /* CaptureView.h */, + 57149FF71845D32E00DDBA25 /* CaptureView.m */, + 57149FF81845D32E00DDBA25 /* CaptureWindow.h */, + 57149FF91845D32E00DDBA25 /* CaptureWindow.m */, + 6D74358D18E26A02008ED227 /* BackgroudView.h */, + 6D74358E18E26A02008ED227 /* BackgroudView.m */, + 573AF6021A67FA3A00B6D3B8 /* MTScreenCaptureModule.h */, + 573AF6031A67FA3A00B6D3B8 /* MTScreenCaptureModule.m */, + ); + path = ScreenCapture; + sourceTree = ""; + }; + 571CFF9E1890B3970030E02C /* searchBar */ = { + isa = PBXGroup; + children = ( + 571FD9B818681A5F00F7476B /* FMSearchTokenField.h */, + 571FD9B918681A5F00F7476B /* FMSearchTokenField.m */, + 571CFF9F1890B41C0030E02C /* FMSearchTokenFieldCell.h */, + 571CFFA01890B41C0030E02C /* FMSearchTokenFieldCell.m */, + 571CFFA21890BD6A0030E02C /* FMSearchTokenAttachmentCell.h */, + 571CFFA31890BD6A0030E02C /* FMSearchTokenAttachmentCell.m */, + 571CFFA518920A010030E02C /* DDSearchFieldEditorDelegate.h */, + 571CFFA618920A010030E02C /* DDSearchFieldEditorDelegate.m */, + 57BB35141894D39B0094B553 /* DDSearchFieldController.h */, + 57BB35151894D39B0094B553 /* DDSearchFieldController.m */, + C4D2EFF618B4B4C9000F0B12 /* DDSearchFieldResultCell.h */, + C4D2EFF718B4B4C9000F0B12 /* DDSearchFieldResultCell.m */, + C4D2EFF418B4B29A000F0B12 /* DDSearchResultCell.xib */, + C48D603E18BED99500F5ED30 /* SpellLibrary.h */, + C48D603F18BED99500F5ED30 /* SpellLibrary.m */, + ); + name = searchBar; + sourceTree = ""; + }; + 57285DFA18B32EDA00E90EC2 /* shortcut */ = { + isa = PBXGroup; + children = ( + 57B95BB21A7CCEE8004DFB22 /* MASShortcut.h */, + 57B95BB31A7CCEE8004DFB22 /* MASShortcut.m */, + 57B95BB41A7CCEE8004DFB22 /* MASShortcut+Monitoring.h */, + 57B95BB51A7CCEE8004DFB22 /* MASShortcut+Monitoring.m */, + 57B95BB61A7CCEE8004DFB22 /* MASShortcut+UserDefaults.h */, + 57B95BB71A7CCEE8004DFB22 /* MASShortcut+UserDefaults.m */, + 57B95BB81A7CCEE8004DFB22 /* MASShortcutView.h */, + 57B95BB91A7CCEE8004DFB22 /* MASShortcutView.m */, + 57B95BBA1A7CCEE8004DFB22 /* MASShortcutView+UserDefaults.h */, + 57B95BBB1A7CCEE8004DFB22 /* MASShortcutView+UserDefaults.m */, + ); + name = shortcut; + sourceTree = ""; + }; + 572A87DF18B74E2D003E3FC8 /* addChatGroup */ = { + isa = PBXGroup; + children = ( + 572A880018B773EF003E3FC8 /* tree support */, + C492F40A18C2D0F2005A3AC9 /* DDAddChatGroupModel.h */, + C492F40B18C2D0F2005A3AC9 /* DDAddChatGroupModel.m */, + C492F40D18C2E3DA005A3AC9 /* DDAddChatGroup.h */, + C492F40E18C2E3DA005A3AC9 /* DDAddChatGroup.m */, + 572A87E318B74E9F003E3FC8 /* DDAddChatGroupWindowController.h */, + 572A87E418B74E9F003E3FC8 /* DDAddChatGroupWindowController.m */, + 572A87E518B74E9F003E3FC8 /* DDAddChatGroupWindowController.xib */, + C492F40518C2CEF4005A3AC9 /* DDAddChatGroupCell.h */, + C492F40618C2CEF4005A3AC9 /* DDAddChatGroupCell.m */, + C47934CF19165EB5009C39AE /* DDAddGroupMemberDepartmentCell.h */, + C47934D019165EB5009C39AE /* DDAddGroupMemberDepartmentCell.m */, + C492F41018C2FD8A005A3AC9 /* DDAddGroupSelectedCell.h */, + C492F41118C2FD8A005A3AC9 /* DDAddGroupSelectedCell.m */, + 572A87E018B74E7B003E3FC8 /* DDClickCell.h */, + 572A87E118B74E7B003E3FC8 /* DDClickCell.m */, + C47934D219166415009C39AE /* DDAddGroupMemberDepartmentRowView.h */, + C47934D319166415009C39AE /* DDAddGroupMemberDepartmentRowView.m */, + C47934D519167458009C39AE /* DDMultiSelectedOutlineView.h */, + C47934D619167458009C39AE /* DDMultiSelectedOutlineView.m */, + ); + name = addChatGroup; + sourceTree = ""; + }; + 572A880018B773EF003E3FC8 /* tree support */ = { + isa = PBXGroup; + children = ( + 572A880118B773EF003E3FC8 /* BaseNode.h */, + 572A880218B773EF003E3FC8 /* BaseNode.m */, + 572A880318B773EF003E3FC8 /* ChildNode.h */, + 572A880418B773EF003E3FC8 /* ChildNode.m */, + ); + name = "tree support"; + path = "interface/chat/addChatGroup/tree support"; + sourceTree = ""; + }; + 573847261820CDA000443653 = { + isa = PBXGroup; + children = ( + 573847381820CDA000443653 /* TeamTalk */, + 573847561820CDA000443653 /* TeamTalkTests */, + 573847311820CDA000443653 /* Frameworks */, + 573847301820CDA000443653 /* Products */, + D2DB4085FFF0FDA637621A14 /* Pods */, + ); + sourceTree = ""; + }; + 573847301820CDA000443653 /* Products */ = { + isa = PBXGroup; + children = ( + 5738472F1820CDA000443653 /* TeamTalk.app */, + ); + name = Products; + sourceTree = ""; + }; + 573847311820CDA000443653 /* Frameworks */ = { + isa = PBXGroup; + children = ( + 57DEB6901A7F75F500961C6F /* libsecurity.a */, + 5E8EB9DC1934713A008B1890 /* ImageIO.framework */, + 57DF183A18DFD0E4003A19F6 /* libsqlite3.dylib */, + 57CA0F4C18D2D42D005C0B0D /* CrashReporter.framework */, + 5700BF0818A8A4B00060092F /* Sparkle.framework */, + 57EFFB2A18580FC2006D8DE1 /* libz.dylib */, + 18C769F9188E444B0066AA8C /* SystemConfiguration.framework */, + 1886E1D41850A65500BA092C /* AVFoundation.framework */, + 57149FFF1845D45900DDBA25 /* Carbon.framework */, + 570D6E50183A053E00F68CB0 /* Quartz.framework */, + 570D6E51183A053E00F68CB0 /* QuartzCore.framework */, + 57F50079182F976B0090115B /* libcommonCrypto.dylib */, + 57AB317E1828816100B7766E /* Security.framework */, + 573847321820CDA000443653 /* Cocoa.framework */, + 573847341820CDA000443653 /* Other Frameworks */, + 8F31B5BDBE8F1E507D5515C9 /* libPods.a */, + ); + name = Frameworks; + sourceTree = ""; + }; + 573847341820CDA000443653 /* Other Frameworks */ = { + isa = PBXGroup; + children = ( + 573847351820CDA000443653 /* AppKit.framework */, + 573847361820CDA000443653 /* CoreData.framework */, + 573847371820CDA000443653 /* Foundation.framework */, + ); + name = "Other Frameworks"; + sourceTree = ""; + }; + 573847381820CDA000443653 /* TeamTalk */ = { + isa = PBXGroup; + children = ( + 8179EECE1A6E5CBE000AADA3 /* html */, + C4C926D8190F424A005B3234 /* customView */, + C48E79F118FE861800A1FA66 /* Services */, + C48E79ED18FE2ABB00A1FA66 /* HelpLib */, + C42A070418E7D01D004461E1 /* Category */, + 183B53431869794E009073EC /* Modules */, + 187FABD81868546A006ACC30 /* DDLogic */, + 5743BF38183DAE08001448FB /* teamtalk */, + 5738479B1820D7DB00443653 /* views */, + 57EFFB2C18583BB9006D8DE1 /* Libraries */, + 57AF22911821083E00758483 /* utilities */, + 5738474A1820CDA000443653 /* Images.xcassets */, + 573847391820CDA000443653 /* Supporting Files */, + ); + path = TeamTalk; + sourceTree = ""; + }; + 573847391820CDA000443653 /* Supporting Files */ = { + isa = PBXGroup; + children = ( + C4C926C3190F3C1D005B3234 /* new resource */, + 576CE6CB18D1B68B00DEBCD5 /* icon_refresh_arrow_down.png */, + 576CE6CC18D1B68B00DEBCD5 /* icon_refresh_arrow_down@2x.png */, + 576CE6CD18D1B68B00DEBCD5 /* icon_refresh_arrow.png */, + 576CE6CE18D1B68B00DEBCD5 /* icon_refresh_arrow@2x.png */, + 57285D3E18AB63BE00E90EC2 /* preference_divider.png */, + 57285D3F18AB63BE00E90EC2 /* preference_divider@2x.png */, + C46B2D9718E3D8F000FE278B /* icon_statusbar_blue.png */, + C46B2D9918E3D95F00FE278B /* icon_statusbar_blue@2x.png */, + 57B2A59118273702000A16FD /* resource */, + 5738473A1820CDA000443653 /* TeamTalk-Info.plist */, + 5738473B1820CDA000443653 /* InfoPlist.strings */, + 5700BF0B18A8A5AD0060092F /* dsa_pub.pem */, + 5738473E1820CDA000443653 /* main.m */, + 573847401820CDA000443653 /* TeamTalk-Prefix.pch */, + 573847411820CDA000443653 /* Credits.rtf */, + 6DCB32D8189201FF00FC86A3 /* DDApplication.h */, + 6DCB32D9189201FF00FC86A3 /* DDApplication.m */, + ); + name = "Supporting Files"; + sourceTree = ""; + }; + 573847561820CDA000443653 /* TeamTalkTests */ = { + isa = PBXGroup; + children = ( + 5738475C1820CDA000443653 /* TeamTalkTests.m */, + 573847571820CDA000443653 /* Supporting Files */, + ); + path = TeamTalkTests; + sourceTree = ""; + }; + 573847571820CDA000443653 /* Supporting Files */ = { + isa = PBXGroup; + children = ( + 5743BF39183DB68D001448FB /* duoduo.png */, + 573847581820CDA000443653 /* TeamTalkTests-Info.plist */, + 573847591820CDA000443653 /* InfoPlist.strings */, + ); + name = "Supporting Files"; + sourceTree = ""; + }; + 573847661820CE9900443653 /* TcpLink */ = { + isa = PBXGroup; + children = ( + 5738476D1820CE9900443653 /* DataInputStream.h */, + 5738476E1820CE9900443653 /* DataInputStream.m */, + 5738476F1820CE9900443653 /* DataOutputStream.h */, + 573847701820CE9900443653 /* DataOutputStream.m */, + 573847681820CE9900443653 /* entities */, + 573847711820CE9900443653 /* tcpProtocol */, + 5738477C1820CE9900443653 /* mac */, + ); + name = TcpLink; + path = net; + sourceTree = ""; + }; + 573847681820CE9900443653 /* entities */ = { + isa = PBXGroup; + children = ( + 573AF6051A67FED000B6D3B8 /* LoginEntity.h */, + 573AF6061A67FED000B6D3B8 /* LoginEntity.m */, + 81DEF5081A5B8FE800F0799D /* DDepartment.h */, + 81DEF5091A5B8FE800F0799D /* DDepartment.m */, + 81DEF4FF1A5B8D9900F0799D /* DDBaseEntity.h */, + 81DEF5001A5B8D9900F0799D /* DDBaseEntity.m */, + 183B5381187145A6009073EC /* MGJEntity.h */, + 183B5382187145A6009073EC /* MGJEntity.m */, + 573847691820CE9900443653 /* MessageEntity.h */, + 5738476A1820CE9900443653 /* MessageEntity.m */, + C427BF8F19A32C0900A010AA /* MessageDate.h */, + C427BF9019A32C0900A010AA /* MessageDate.m */, + C4F90F9A1963DFE900DF2828 /* DDIntranetMessageEntity.h */, + C4F90F9B1963DFE900DF2828 /* DDIntranetMessageEntity.m */, + 183B5369186AFB27009073EC /* FileTransferEntity.h */, + 183B536A186AFB27009073EC /* FileTransferEntity.m */, + ); + name = entities; + path = mtalk/data; + sourceTree = ""; + }; + 573847711820CE9900443653 /* tcpProtocol */ = { + isa = PBXGroup; + children = ( + 579E547E1A67C5D9003031A1 /* MGJMTalkIMessageHanlder.h */, + 183B536F186D58C2009073EC /* TcpProtocolHeader.h */, + 183B5370186D58C2009073EC /* TcpProtocolHeader.m */, + 573847841820CE9900443653 /* SendBuffer.h */, + 573847851820CE9900443653 /* SendBuffer.m */, + ); + name = tcpProtocol; + path = mtalk/handlers; + sourceTree = ""; + }; + 5738477C1820CE9900443653 /* mac */ = { + isa = PBXGroup; + children = ( + 5738477D1820CE9900443653 /* NSStream+NSStreamAddition.h */, + 5738477E1820CE9900443653 /* NSStream+NSStreamAddition.m */, + ); + name = mac; + path = mtalk/mac; + sourceTree = ""; + }; + 5738479B1820D7DB00443653 /* views */ = { + isa = PBXGroup; + children = ( + 57124E44187AADD2006D2DCA /* alertWindow */, + 5738479C1820D80E00443653 /* DDWindowController.h */, + 5738479D1820D80E00443653 /* DDWindowController.m */, + ); + name = views; + sourceTree = ""; + }; + 5743BF38183DAE08001448FB /* teamtalk */ = { + isa = PBXGroup; + children = ( + 57AF2290182101B000758483 /* DDDuoduoProtocol.h */, + 573847441820CDA000443653 /* DDAppDelegate.h */, + 573847451820CDA000443653 /* DDAppDelegate.m */, + 573847471820CDA000443653 /* MainMenu.xib */, + 189B0A9A187694E600C3997A /* DDSharedDuoduo.h */, + 189B0A9B187694E600C3997A /* DDSharedDuoduo.m */, + 576BA9651876D0BB002B40EC /* DDInterfaceController.h */, + 576BA9661876D0BB002B40EC /* DDInterfaceController.m */, + ); + name = teamtalk; + sourceTree = ""; + }; + 577C167D18473F2C009718D7 /* mainWindow */ = { + isa = PBXGroup; + children = ( + C41AB128195B042F002AE7C7 /* IntranetContentw */, + 571CFF9E1890B3970030E02C /* searchBar */, + 577C167E18474005009718D7 /* DDMainWindow.xib */, + 577C168018474317009718D7 /* DDMainWindowController.h */, + 577C168118474317009718D7 /* DDMainWindowController.m */, + C48E79E718FCE31A00A1FA66 /* DDMainWindowControllerModule.h */, + C48E79E818FCE31A00A1FA66 /* DDMainWindowControllerModule.m */, + C4FA6BDD190B94350097849B /* DDChattingWindowManager.h */, + C4FA6BDE190B94350097849B /* DDChattingWindowManager.m */, + C4A09C8A190FC1C700B39BF3 /* LeftBar */, + C4A09C8B190FC1D800B39BF3 /* FirstColumn */, + 57E1AA9D186AD9FF00D00D63 /* MainWindowSegmentedControl.h */, + 57E1AA9E186AD9FF00D00D63 /* MainWindowSegmentedControl.m */, + 577C168F18475857009718D7 /* DDTabItemView.h */, + 577C169018475857009718D7 /* DDTabItemView.m */, + 577C169218476804009718D7 /* DDMainWindow.h */, + 577C169318476804009718D7 /* DDMainWindow.m */, + 5709F94D1848682D0096D176 /* DDImageSpreadView.h */, + 5709F94E1848682E0096D176 /* DDImageSpreadView.m */, + 5709F95C18486E320096D176 /* DDImageView.h */, + 5709F95D18486E320096D176 /* DDImageView.m */, + 57D5D163184C76D900852738 /* DDSplitView.h */, + 57D5D164184C76D900852738 /* DDSplitView.m */, + ); + name = mainWindow; + sourceTree = ""; + }; + 579E54731A67C39B003031A1 /* http */ = { + isa = PBXGroup; + children = ( + 579E54741A67C3B4003031A1 /* DDHttpEntity.h */, + 579E54751A67C3B4003031A1 /* DDHttpEntity.m */, + 579E54761A67C3B4003031A1 /* DDHttpModule.h */, + 579E54771A67C3B4003031A1 /* DDHttpModule.m */, + ); + name = http; + sourceTree = ""; + }; + 57AF22911821083E00758483 /* utilities */ = { + isa = PBXGroup; + children = ( + 18FF1D16185177F700C19036 /* DDSound.h */, + 18FF1D17185177F700C19036 /* DDSound.m */, + 1886E1D11850A4ED00BA092C /* DDCommonApi.h */, + 1886E1D21850A4ED00BA092C /* DDCommonApi.m */, + C4D2EFA418B322B9000F0B12 /* Constant */, + 6DE7620B18867F00000EDC39 /* ScrollToRefresh */, + 183B537D18714138009073EC /* Extensions */, + 57149FEE1845926C00DDBA25 /* scrollbar auto-hiding */, + 57C0CE58183C8DA70049DCE4 /* fun new classes */, + 57B3900E18347E1A007CD3E0 /* fun new controls */, + 57B2A60C182766AE000A16FD /* keychain access */, + 57AF22921821085100758483 /* additions */, + ); + name = utilities; + sourceTree = ""; + }; + 57AF22921821085100758483 /* additions */ = { + isa = PBXGroup; + children = ( + 57C0CE54183C86B40049DCE4 /* AIWindowControllerAdditions.h */, + 57C0CE55183C86B40049DCE4 /* AIWindowControllerAdditions.m */, + 57C0CE4E183C7C320049DCE4 /* AIParagraphStyleAdditions.h */, + 57C0CE4F183C7C320049DCE4 /* AIParagraphStyleAdditions.m */, + 570D6E4A1839B28000F68CB0 /* AIFileManagerAdditions.h */, + 570D6E4B1839B28000F68CB0 /* AIFileManagerAdditions.m */, + 57B390271834ACB5007CD3E0 /* AIMathCompatibility.h */, + 570D6E471839B24200F68CB0 /* AIImageAdditions.h */, + 570D6E481839B24200F68CB0 /* AIImageAdditions.m */, + 570D6E441839B0E100F68CB0 /* AIImageDrawingAdditions.h */, + 570D6E451839B0E100F68CB0 /* AIImageDrawingAdditions.m */, + 57B3902B1834B6EC007CD3E0 /* AIStringUtilities.h */, + 57B3901E18349DA6007CD3E0 /* AIBezierPathAdditions.h */, + 57B3901F18349DA6007CD3E0 /* AIBezierPathAdditions.m */, + 57AF2293182108E300758483 /* DDDictionaryAdditions.h */, + 57AF2294182108E300758483 /* DDDictionaryAdditions.m */, + 57AF229618210D8100758483 /* DDSharedWriterQueue.h */, + 57AF229718210D8100758483 /* DDSharedWriterQueue.m */, + 57AB4F0F1821EAD500603621 /* NSEvent+DDEventAdditions.h */, + 57AB4F101821EAD500603621 /* NSEvent+DDEventAdditions.m */, + 57AB4F121821EFBC00603621 /* NSFileManager+DDFileManagerAdditions.h */, + 57AB4F131821EFBC00603621 /* NSFileManager+DDFileManagerAdditions.m */, + 57AB4F151821F00E00603621 /* NSString+DDStringAdditions.h */, + 57AB4F161821F00E00603621 /* NSString+DDStringAdditions.m */, + 5733D827184F284400737695 /* DDWindowAdditions.h */, + 5733D828184F284400737695 /* DDWindowAdditions.m */, + 5733D82A184F2C4A00737695 /* AIAttributedStringAdditions.h */, + 5733D82B184F2C4A00737695 /* AIAttributedStringAdditions.m */, + 5733D82D184F2D1600737695 /* AIColorAdditions.h */, + 5733D82E184F2D1600737695 /* AIColorAdditions.m */, + 5733D830184F2DFF00737695 /* AITextAttributes.h */, + 5733D831184F2DFF00737695 /* AITextAttributes.m */, + 5733D833184F2E4D00737695 /* AIFontManagerAdditions.h */, + 5733D834184F2E4D00737695 /* AIFontManagerAdditions.m */, + 5733D836184F317200737695 /* AITextAttachmentExtension.h */, + 5733D837184F317200737695 /* AITextAttachmentExtension.m */, + 5733D83C184F326600737695 /* AITextAttachmentAdditions.h */, + 5733D83D184F326600737695 /* AITextAttachmentAdditions.m */, + 5733D83F184F33F500737695 /* AIPasteboardAdditions.h */, + 5733D840184F33F500737695 /* AIPasteboardAdditions.m */, + C4D2EFF918B70F1F000F0B12 /* NSView+Addition.h */, + C4D2EFFA18B70F1F000F0B12 /* NSView+Addition.m */, + ); + name = additions; + sourceTree = ""; + }; + 57B2A59118273702000A16FD /* resource */ = { + isa = PBXGroup; + children = ( + C4C1CB86197FCB4600386AB0 /* dd_modisy_avatar@2x.png */, + C4C1CB87197FCB4600386AB0 /* dd_modisy_avatar.png */, + C4AB954718DAE70F000181AD /* shield_gray.png */, + C4AB954818DAE70F000181AD /* shield_gray@2x.png */, + C4AB954918DAE70F000181AD /* shield_red.png */, + C4AB954A18DAE70F000181AD /* shield_red@2x.png */, + 6D78A57A18D828450069A29B /* ScreenCapture_toolbar_ellipse.png */, + 6D78A57B18D828450069A29B /* ScreenCapture_toolbar_ellipse@2x.png */, + 6D78A57C18D828450069A29B /* ScreenCapture_toolbar_rect.png */, + 6D78A57D18D828450069A29B /* ScreenCapture_toolbar_rect@2x.png */, + 576CE67718D0764B00DEBCD5 /* icon_send_file_gray.png */, + 576CE67818D0764B00DEBCD5 /* icon_send_file_gray@2x.png */, + 576CE67918D0764B00DEBCD5 /* icon_send_file_highlight.png */, + 576CE67A18D0764B00DEBCD5 /* icon_send_file_highlight@2x.png */, + 5772C9CC18D00E62008FE09F /* icon_statusbar.tif */, + 5772C9CD18D00E62008FE09F /* tab_bg.png */, + 5772C9CA18D00CBD008FE09F /* icon_close.png */, + 5772C9C618D00B9B008FE09F /* pull-to-refresh-arrow.png */, + 5772C9C718D00B9B008FE09F /* release-to-refresh.png */, + 57BA8B8318BB1AA70093DC12 /* icon_close.png */, + 572A87EC18B75B04003E3FC8 /* icon_user_away_h28.png */, + 572A87ED18B75B04003E3FC8 /* icon_user_away_h28@2x.png */, + 572A87EE18B75B04003E3FC8 /* icon_user_female_away_h28.png */, + 572A87EF18B75B04003E3FC8 /* icon_user_female_away_h28@2x.png */, + 572A87F018B75B04003E3FC8 /* icon_user_female_h28.png */, + 572A87F118B75B04003E3FC8 /* icon_user_female_h28@2x.png */, + 572A87F218B75B04003E3FC8 /* icon_user_h28.png */, + 572A87F318B75B04003E3FC8 /* icon_user_h28@2x.png */, + 572A87F418B75B04003E3FC8 /* icon_user_offline_h28.png */, + 572A87F518B75B04003E3FC8 /* icon_user_offline_h28@2x.png */, + 572A87E818B75A21003E3FC8 /* icon_folder_h21.png */, + 572A87E918B75A21003E3FC8 /* icon_folder_h21@2x.png */, + 6D2A847F18B1D9140004032B /* icon_go.png */, + 572A87BB18B5ED95003E3FC8 /* icon_addcontacts_disable_theme_gray.png */, + 572A87BC18B5ED96003E3FC8 /* icon_addcontacts_disable_theme_gray@2x.png */, + 572A87BD18B5ED96003E3FC8 /* icon_addcontacts_highlight_theme_gray.png */, + 572A87BE18B5ED96003E3FC8 /* icon_addcontacts_highlight_theme_gray@2x.png */, + 572A87BF18B5ED96003E3FC8 /* icon_addcontacts_theme_gray.png */, + 572A87C018B5ED96003E3FC8 /* icon_addcontacts_theme_gray@2x.png */, + 6D2A848018B1D9140004032B /* icon_go@2x.png */, + 57285D3A18AB60F100E90EC2 /* icon_folder.png */, + 57285D3B18AB60F100E90EC2 /* icon_folder@2x.png */, + C492F41518C30FF5005A3AC9 /* icon_check_empty.png */, + C492F41618C30FF5005A3AC9 /* icon_check_empty@2x.png */, + C487386718C8093C00C51541 /* lady_placeholder.png */, + C487386818C8093C00C51541 /* lady_placeholder@2x.png */, + C487386918C8093C00C51541 /* man_placeholder.png */, + C487386A18C8093D00C51541 /* man_placeholder@2x.png */, + 6DCB337F189628EB00FC86A3 /* fileTransfer */, + 6DD3197F188E58F400ED5FE8 /* emotions */, + 6DE7620718867ED0000EDC39 /* pull-to-refresh-arrow.png */, + 6DE7620818867ED0000EDC39 /* release-to-refresh.png */, + C492F41918C31092005A3AC9 /* icon_check_filled.png */, + C492F41A18C31092005A3AC9 /* icon_check_filled@2x.png */, + 578D5E9E187EC0C600568EE6 /* icon_offline.png */, + 578D5E9F187EC0C600568EE6 /* icon_offline@2x.png */, + 578D5EA2187EC0E600568EE6 /* icon_away.png */, + 578D5EA3187EC0E600568EE6 /* icon_away@2x.png */, + 57124E60187E743A006D2DCA /* panel_bg_theme_gray.png */, + 57124E61187E743A006D2DCA /* panel_bg_theme_gray@2x.png */, + 57BEB811186958BC00CAFCF6 /* icon_conversation_theme_gray.png */, + 57E18EAD186A857400D00D63 /* avatar_default.jpg_48x48.jpg */, + 57BEB812186958BC00CAFCF6 /* icon_conversation_theme_gray@2x.png */, + 57AF72B918683E4000C06257 /* tab_bg.png */, + 571FD9B41868190300F7476B /* tabbar_bg_theme_gray.png */, + 571FD9B51868190300F7476B /* tabbar_bg_theme_gray@2x.png */, + 5741BC2A1862E540003F2667 /* aio_recentsession_unreadmsg_selected_wide.png */, + 5741BC2B1862E540003F2667 /* aio_recentsession_unreadmsg_selected_wide@2x.png */, + 5741BC2C1862E540003F2667 /* aio_recentsession_unreadmsg_selected.png */, + C485913D18C73FD800DD30DD /* icon_fav.png */, + C485913E18C73FD800DD30DD /* icon_fav@2x.png */, + C487386F18C814D700C51541 /* group_placeholder.png */, + C487387018C814D700C51541 /* group_placeholder@2x.png */, + 5741BC2D1862E540003F2667 /* aio_recentsession_unreadmsg_selected@2x.png */, + 5741BC2E1862E540003F2667 /* aio_recentsession_unreadmsg_wide.png */, + 5741BC2F1862E540003F2667 /* aio_recentsession_unreadmsg_wide@2x.png */, + 5741BC301862E540003F2667 /* aio_recentsession_unreadmsg.png */, + 5741BC311862E540003F2667 /* aio_recentsession_unreadmsg@2x.png */, + 6D70EA311869ADAE00402CF5 /* bubble_left.png */, + 6D70EA321869ADAE00402CF5 /* bubble_left@2x.png */, + 6D70EA331869ADAE00402CF5 /* bubble_right.png */, + 6D70EA341869ADAE00402CF5 /* bubble_right@2x.png */, + 57EFFB2618570324006D8DE1 /* icon_image_normal.png */, + 57EFFB2718570324006D8DE1 /* icon_image_normal@2x.png */, + 57EFFADB1856C639006D8DE1 /* icon_unread_red_wide.png */, + 57EFFADC1856C639006D8DE1 /* icon_unread_red_wide@2x.png */, + 57EFFADD1856C639006D8DE1 /* icon_unread_red.png */, + 57EFFADE1856C639006D8DE1 /* icon_unread_red@2x.png */, + 57D5D169184D770100852738 /* icon_screenshot_highlight.png */, + 57D5D16A184D770100852738 /* icon_screenshot_highlight@2x.png */, + 57D5D16B184D770100852738 /* icon_screenshot.png */, + 57D5D16C184D770100852738 /* icon_screenshot@2x.png */, + 57D5D16D184D770100852738 /* icon_smile_highlight.png */, + 57D5D16E184D770100852738 /* icon_smile_highlight@2x.png */, + 188B010E18505E8100A99E7A /* icon.icns */, + 57D5D16F184D770100852738 /* icon_smile.png */, + 57D5D170184D770100852738 /* icon_smile@2x.png */, + 18906D3A18555843004B874E /* message.mp3 */, + C48E79EA18FE1FAE00A1FA66 /* message.wav */, + 5709F95F184871A70096D176 /* icon_conversation_highlight_theme_gray.png */, + 5709F960184871A70096D176 /* icon_conversation_highlight_theme_gray@2x.png */, + 5709F961184871A70096D176 /* icon_conversation_theme_gray.png */, + 5709F962184871A70096D176 /* icon_conversation_theme_gray@2x.png */, + 5709F963184871A70096D176 /* icon_organization_click_theme_gray.png */, + 5709F964184871A70096D176 /* icon_organization_click_theme_gray@2x.png */, + 5709F965184871A70096D176 /* icon_organization_highlight_theme_gray.png */, + 5709F966184871A70096D176 /* icon_organization_highlight_theme_gray@2x.png */, + 5709F95418486DDA0096D176 /* seperator_left.png */, + 5709F95518486DDA0096D176 /* seperator_left@2x.png */, + 5709F95618486DDA0096D176 /* seperator_right.png */, + 5709F95718486DDA0096D176 /* seperator_right@2x.png */, + 5709F95018486ABB0096D176 /* toolbar_bg_theme_gray.png */, + 5709F95118486ABB0096D176 /* toolbar_bg_theme_gray@2x.png */, + 577C168718474669009718D7 /* icon_user_h51.png */, + 577C168B184749A1009718D7 /* icon_user_h51.png */, + 577C168C184749A1009718D7 /* icon_user_h51@2x.png */, + 577C168818474669009718D7 /* icon_user_h51@2x.png */, + 577C168318474649009718D7 /* icon_online.png */, + 577C168418474649009718D7 /* icon_online@2x.png */, + 5714A0011845D4D000DDBA25 /* ScreenCapture_toolbar_cancel.png */, + 5714A0021845D4D000DDBA25 /* ScreenCapture_toolbar_ok.png */, + 57B2A60918273BD2000A16FD /* duoduo.png */, + ); + name = resource; + sourceTree = ""; + }; + 57B2A60C182766AE000A16FD /* keychain access */ = { + isa = PBXGroup; + children = ( + 57AB317B18287E6800B7766E /* DDKeychain.h */, + 57AB317C18287E6800B7766E /* DDKeychain.m */, + ); + name = "keychain access"; + sourceTree = ""; + }; + 57B3900E18347E1A007CD3E0 /* fun new controls */ = { + isa = PBXGroup; + children = ( + 57B390231834A8E8007CD3E0 /* grid iphoto style view */, + 57B3900F18347F36007CD3E0 /* image view with picker */, + ); + name = "fun new controls"; + sourceTree = ""; + }; + 57B3900F18347F36007CD3E0 /* image view with picker */ = { + isa = PBXGroup; + children = ( + ); + name = "image view with picker"; + sourceTree = ""; + }; + 57B390231834A8E8007CD3E0 /* grid iphoto style view */ = { + isa = PBXGroup; + children = ( + 57B390241834A970007CD3E0 /* DDImageCollectionView.h */, + 57B390251834A970007CD3E0 /* DDImageCollectionView.m */, + ); + name = "grid iphoto style view"; + sourceTree = ""; + }; + 57B6230A183072FB00F2B249 /* SBJson */ = { + isa = PBXGroup; + children = ( + 57B6230B183072FB00F2B249 /* NSObject+SBJson.h */, + 57B6230C183072FB00F2B249 /* NSObject+SBJson.m */, + 57B6230D183072FB00F2B249 /* SBJson.h */, + 57B6230E183072FB00F2B249 /* SBJsonParser.h */, + 57B6230F183072FB00F2B249 /* SBJsonParser.m */, + 57B62310183072FB00F2B249 /* SBJsonStreamParser.h */, + 57B62311183072FB00F2B249 /* SBJsonStreamParser.m */, + 57B62312183072FB00F2B249 /* SBJsonStreamParserAccumulator.h */, + 57B62313183072FB00F2B249 /* SBJsonStreamParserAccumulator.m */, + 57B62314183072FB00F2B249 /* SBJsonStreamParserAdapter.h */, + 57B62315183072FB00F2B249 /* SBJsonStreamParserAdapter.m */, + 57B62316183072FB00F2B249 /* SBJsonStreamParserState.h */, + 57B62317183072FB00F2B249 /* SBJsonStreamParserState.m */, + 57B62318183072FB00F2B249 /* SBJsonStreamWriter.h */, + 57B62319183072FB00F2B249 /* SBJsonStreamWriter.m */, + 57B6231A183072FB00F2B249 /* SBJsonStreamWriterAccumulator.h */, + 57B6231B183072FB00F2B249 /* SBJsonStreamWriterAccumulator.m */, + 57B6231C183072FB00F2B249 /* SBJsonStreamWriterState.h */, + 57B6231D183072FB00F2B249 /* SBJsonStreamWriterState.m */, + 57B6231E183072FB00F2B249 /* SBJsonTokeniser.h */, + 57B6231F183072FB00F2B249 /* SBJsonTokeniser.m */, + 57B62320183072FB00F2B249 /* SBJsonUTF8Stream.h */, + 57B62321183072FB00F2B249 /* SBJsonUTF8Stream.m */, + 57B62322183072FB00F2B249 /* SBJsonWriter.h */, + 57B62323183072FB00F2B249 /* SBJsonWriter.m */, + ); + path = SBJson; + sourceTree = ""; + }; + 57C0CE58183C8DA70049DCE4 /* fun new classes */ = { + isa = PBXGroup; + children = ( + 57C0CE5C183C98DE0049DCE4 /* DDMutableOwnerArray.h */, + 57C0CE5D183C98DE0049DCE4 /* DDMutableOwnerArray.m */, + ); + name = "fun new classes"; + sourceTree = ""; + }; + 57D1379118AB57DD00E3E6A4 /* preference */ = { + isa = PBXGroup; + children = ( + 57285D4C18AB814400E90EC2 /* DDPreferenceWinController.h */, + 57285D4D18AB814400E90EC2 /* DDPreferenceWinController.m */, + 57285D4E18AB814400E90EC2 /* DDPreferenceWinController.xib */, + 57285D5118AB860E00E90EC2 /* DDUserPreferences.h */, + 57285D5218AB860E00E90EC2 /* DDUserPreferences.m */, + 57285D5418B19BD000E90EC2 /* DDOptionsBase.h */, + 57285D5518B19BD000E90EC2 /* DDOptionsBase.m */, + ); + name = preference; + sourceTree = ""; + }; + 57D5D155184C217800852738 /* chat */ = { + isa = PBXGroup; + children = ( + C42A070818E80029004461E1 /* MsgSendManager */, + C4498A0018D71A92009FEA4A /* Chatting */, + 572A87DF18B74E2D003E3FC8 /* addChatGroup */, + 57124E54187E331A006D2DCA /* ImageAndTextCell.h */, + 57124E55187E331A006D2DCA /* ImageAndTextCell.m */, + 57D5D15B184C23AD00852738 /* DDChattingViewController.h */, + 57B3ACE718C0ACDD00F50C8F /* DDChattingViewController.m */, + C4FF47361A7F4EB500B21A0D /* MTPreviewItem.h */, + C4FF47371A7F4EB500B21A0D /* MTPreviewItem.m */, + C4498A1B18D7D976009FEA4A /* DDChattingViewModule.h */, + C4498A1C18D7D976009FEA4A /* DDChattingViewModule.m */, + 57D5D15D184C23AD00852738 /* DDChattingView.xib */, + 57D5D185184D840000852738 /* DDChattingInputView.h */, + 57D5D186184D840000852738 /* DDChattingInputView.m */, + 57D5D18C184EC85100852738 /* DDSendingTextView.h */, + 57D5D18D184EC85100852738 /* DDSendingTextView.m */, + 57124E57187E531D006D2DCA /* DDChattingContactListViewController.h */, + 57124E58187E531D006D2DCA /* DDChattingContactListViewController.m */, + C4563FB91906365C009DEB05 /* DDChattingContactListModule.h */, + C4563FBA1906365C009DEB05 /* DDChattingContactListModule.m */, + C46C51BA18D2DBC000149B7F /* DDChattingContactListCell.h */, + C46C51BB18D2DBC000149B7F /* DDChattingContactListCell.m */, + 57124E5A187E6E3D006D2DCA /* DDTableView.h */, + 57124E5B187E6E3D006D2DCA /* DDTableView.m */, + 578D5EAA187FC44A00568EE6 /* DDChattingHeadViewController.h */, + 578D5EAB187FC44A00568EE6 /* DDChattingHeadViewController.m */, + 5EF517E319235FBA00652421 /* DDChattingMyLine.h */, + 5EF517E419235FBA00652421 /* DDChattingMyLine.m */, + 578D5EAD188383EE00568EE6 /* DDImageMessage.h */, + 578D5EAE188383EE00568EE6 /* DDImageMessage.m */, + 571CFF9B188F92D30030E02C /* DDEmotionAttachment.h */, + 571CFF9C188F92D30030E02C /* DDEmotionAttachment.m */, + 57A4B5531A722E1700E16CBC /* MTChattingInputView.h */, + 57A4B5541A722E1700E16CBC /* MTChattingInputView.m */, + ); + name = chat; + sourceTree = ""; + }; + 57DEB68E1A7F621600961C6F /* libsecurity */ = { + isa = PBXGroup; + children = ( + 57DEB68F1A7F622A00961C6F /* security.h */, + ); + name = libsecurity; + sourceTree = ""; + }; + 57EFFB2C18583BB9006D8DE1 /* Libraries */ = { + isa = PBXGroup; + children = ( + C4FF474F1A823E5800B21A0D /* Speex */, + 57DEB68E1A7F621600961C6F /* libsecurity */, + C42D4EA019247ED900C7B6F6 /* MoveApplication */, + 6D1CC75818A62FF0002CAE5F /* Log4Cocoa */, + 18C769EF188E3FF50066AA8C /* Reachability */, + 57B6230A183072FB00F2B249 /* SBJson */, + 57F50072182F8FB50090115B /* http */, + 57149F88184487C200DDBA25 /* EGOImageLoader */, + ); + name = Libraries; + sourceTree = ""; + }; + 57F50072182F8FB50090115B /* http */ = { + isa = PBXGroup; + children = ( + 57F50076182F93D90090115B /* MD5.h */, + 57F50077182F93D90090115B /* MD5.m */, + 57F50073182F92080090115B /* DDHttpUtil.h */, + 57F50074182F92080090115B /* DDHttpUtil.m */, + ); + name = http; + sourceTree = ""; + }; + 6D1CC75818A62FF0002CAE5F /* Log4Cocoa */ = { + isa = PBXGroup; + children = ( + 6D1CC75918A62FF0002CAE5F /* L4AppenderAttachable.h */, + 6D1CC75A18A62FF0002CAE5F /* L4AppenderAttachable.m */, + 6D1CC75B18A62FF0002CAE5F /* L4AppenderProtocols.h */, + 6D1CC75C18A62FF0002CAE5F /* L4AppenderSkeleton.h */, + 6D1CC75D18A62FF0002CAE5F /* L4AppenderSkeleton.m */, + 6D1CC75E18A62FF0002CAE5F /* L4BasicConfigurator.h */, + 6D1CC75F18A62FF0002CAE5F /* L4BasicConfigurator.m */, + 6D1CC76018A62FF0002CAE5F /* L4ConsoleAppender.h */, + 6D1CC76118A62FF0002CAE5F /* L4ConsoleAppender.m */, + 6D1CC76218A62FF0002CAE5F /* L4DailyRollingFileAppender.h */, + 6D1CC76318A62FF0002CAE5F /* L4DailyRollingFileAppender.m */, + 6D1CC76418A62FF0002CAE5F /* L4DenyAllFilter.h */, + 6D1CC76518A62FF0002CAE5F /* L4DenyAllFilter.m */, + 6D1CC76618A62FF0002CAE5F /* L4FileAppender.h */, + 6D1CC76718A62FF0002CAE5F /* L4FileAppender.m */, + 6D1CC76818A62FF0002CAE5F /* L4Filter.h */, + 6D1CC76918A62FF0002CAE5F /* L4Filter.m */, + 6D1CC76A18A62FF0002CAE5F /* L4JSONLayout.h */, + 6D1CC76B18A62FF0002CAE5F /* L4JSONLayout.m */, + 6D1CC76C18A62FF0002CAE5F /* L4Layout.h */, + 6D1CC76D18A62FF0002CAE5F /* L4Layout.m */, + 6D1CC76E18A62FF0002CAE5F /* L4Level.h */, + 6D1CC76F18A62FF0002CAE5F /* L4Level.m */, + 6D1CC77018A62FF0002CAE5F /* L4LevelMatchFilter.h */, + 6D1CC77118A62FF0002CAE5F /* L4LevelMatchFilter.m */, + 6D1CC77218A62FF0002CAE5F /* L4LevelRangeFilter.h */, + 6D1CC77318A62FF0002CAE5F /* L4LevelRangeFilter.m */, + 6D1CC77418A62FF0002CAE5F /* L4LogEvent.h */, + 6D1CC77518A62FF0002CAE5F /* L4LogEvent.m */, + 6D1CC77618A62FF0002CAE5F /* L4Logger.h */, + 6D1CC77718A62FF0002CAE5F /* L4Logger.m */, + 6D1CC77818A62FF0002CAE5F /* L4LoggerNameMatchFilter.h */, + 6D1CC77918A62FF0002CAE5F /* L4LoggerNameMatchFilter.m */, + 6D1CC77A18A62FF0002CAE5F /* L4LoggerProtocols.h */, + 6D1CC77B18A62FF0002CAE5F /* L4LoggerStore.h */, + 6D1CC77C18A62FF0002CAE5F /* L4LoggerStore.m */, + 6D1CC77D18A62FF0002CAE5F /* L4Logging.h */, + 6D1CC77E18A62FF0002CAE5F /* L4Logging.m */, + 6D1CC77F18A62FF0002CAE5F /* L4LogLog.h */, + 6D1CC78018A62FF0002CAE5F /* L4LogLog.m */, + 6D1CC78118A62FF0002CAE5F /* L4PatternLayout.h */, + 6D1CC78218A62FF0002CAE5F /* L4PatternLayout.m */, + 6D1CC78318A62FF0002CAE5F /* L4Properties.h */, + 6D1CC78418A62FF0002CAE5F /* L4Properties.m */, + 6D1CC78518A62FF0002CAE5F /* L4PropertyConfigurator.h */, + 6D1CC78618A62FF0002CAE5F /* L4PropertyConfigurator.m */, + 6D1CC78718A62FF0002CAE5F /* L4RollingFileAppender.h */, + 6D1CC78818A62FF0002CAE5F /* L4RollingFileAppender.m */, + 6D1CC78918A62FF0002CAE5F /* L4RootLogger.h */, + 6D1CC78A18A62FF0002CAE5F /* L4RootLogger.m */, + 6D1CC78B18A62FF0002CAE5F /* L4SimpleLayout.h */, + 6D1CC78C18A62FF0002CAE5F /* L4SimpleLayout.m */, + 6D1CC78D18A62FF0002CAE5F /* L4StringMatchFilter.h */, + 6D1CC78E18A62FF0002CAE5F /* L4StringMatchFilter.m */, + 6D1CC78F18A62FF0002CAE5F /* L4WriterAppender.h */, + 6D1CC79018A62FF0002CAE5F /* L4WriterAppender.m */, + 6D1CC79118A62FF0002CAE5F /* L4XMLLayout.h */, + 6D1CC79218A62FF0002CAE5F /* L4XMLLayout.m */, + 6D1CC79318A62FF0002CAE5F /* Log4Cocoa-Prefix.pch */, + 6D1CC79418A62FF0002CAE5F /* Log4Cocoa.h */, + 6D1CC79518A62FF0002CAE5F /* Log4CocoaDefines.h */, + 6D1CC79618A62FF0002CAE5F /* NSObject+Log4Cocoa.h */, + 6D1CC79718A62FF0002CAE5F /* NSObject+Log4Cocoa.m */, + ); + name = Log4Cocoa; + path = Libraries/Log4Cocoa; + sourceTree = ""; + }; + 6D41DA1A1861962200C1FD65 /* FileTransfer */ = { + isa = PBXGroup; + children = ( + 6DDB0D3818EC17FF00A1DA57 /* GCDAsyncSocket.h */, + 6DDB0D3918EC17FF00A1DA57 /* GCDAsyncSocket.m */, + C422FF2119261A18006EEBF9 /* DDCornerView.h */, + C422FF2219261A18006EEBF9 /* DDCornerView.m */, + ); + name = FileTransfer; + sourceTree = ""; + }; + 6DCB337F189628EB00FC86A3 /* fileTransfer */ = { + isa = PBXGroup; + children = ( + 6D8B6AE218C462EE0081DAA2 /* filetransfer_offline.png */, + 6D8B6AE318C462EE0081DAA2 /* filetransfer_offline@2x.png */, + 6DCB3380189629F200FC86A3 /* filetransfer_avatar_receive.png */, + 6DCB3381189629F200FC86A3 /* filetransfer_avatar_receive@2x.png */, + 6DCB3382189629F200FC86A3 /* filetransfer_avatar_send.png */, + 6DCB3383189629F200FC86A3 /* filetransfer_avatar_send@2x.png */, + 6DCB3384189629F200FC86A3 /* filetransfer_close.png */, + 6DCB3385189629F200FC86A3 /* filetransfer_close@2x.png */, + 6DCB3386189629F200FC86A3 /* filetransfer_receiver.png */, + 6DCB3387189629F200FC86A3 /* filetransfer_receiver@2x.png */, + 6DCB3388189629F200FC86A3 /* filetransfer_refuse.png */, + 6DCB3389189629F200FC86A3 /* filetransfer_refuse@2x.png */, + 6DCB338A189629F200FC86A3 /* filetransfer_search.png */, + 6DCB338B189629F200FC86A3 /* filetransfer_search@2x.png */, + ); + name = fileTransfer; + sourceTree = ""; + }; + 6DD31976188E3BD000ED5FE8 /* emotion */ = { + isa = PBXGroup; + children = ( + 6DD31977188E3C5200ED5FE8 /* EmotionViewController.h */, + 6DD31978188E3C5200ED5FE8 /* EmotionViewController.m */, + 6DD3197A188E3C8B00ED5FE8 /* EmotionCellView.h */, + 6DD3197B188E3C8B00ED5FE8 /* EmotionCellView.m */, + 6DD3197D188E3CD800ED5FE8 /* EmotionPopover.xib */, + 6DD31B97188F554500ED5FE8 /* EmotionListXmlParser.h */, + 6DD31B98188F554500ED5FE8 /* EmotionListXmlParser.m */, + ); + name = emotion; + sourceTree = ""; + }; + 6DD3197F188E58F400ED5FE8 /* emotions */ = { + isa = PBXGroup; + children = ( + 5EF517B81923070400652421 /* 221.gif */, + 5EF517B91923070400652421 /* 222.gif */, + 5EF517BA1923070400652421 /* 223.gif */, + 5EF517BB1923070400652421 /* 224.gif */, + 5EF517BC1923070400652421 /* 225.gif */, + 5EF517BD1923070400652421 /* 226.gif */, + 5EF517BE1923070400652421 /* 227.gif */, + 5EF517BF1923070400652421 /* 228.gif */, + 5EF517C01923070400652421 /* 229.gif */, + 5EF517C11923070400652421 /* 230.gif */, + 5EF517C21923070400652421 /* 231.gif */, + 5EF517C31923070400652421 /* 232.gif */, + 5EF517C41923070400652421 /* 233.gif */, + 5EF517C51923070400652421 /* 234.gif */, + 5EF517C61923070400652421 /* 235.gif */, + 5EF517C71923070400652421 /* 236.gif */, + 5EF517C81923070400652421 /* 237.gif */, + 5EF517C91923070400652421 /* 238.gif */, + 5EF517CA1923070400652421 /* 239.gif */, + 5EF517CB1923070400652421 /* 240.gif */, + 6DD31B9A188F55C800ED5FE8 /* emotionList.xml */, + 6DD31980188E592100ED5FE8 /* 0.gif */, + 6DD31981188E592100ED5FE8 /* 1.gif */, + 6DD31982188E592100ED5FE8 /* 2.gif */, + 6DD31983188E592100ED5FE8 /* 3.gif */, + 6DD31984188E592100ED5FE8 /* 4.gif */, + 6DD31985188E592100ED5FE8 /* 5.gif */, + 6DD31986188E592100ED5FE8 /* 6.gif */, + 6DD31987188E592100ED5FE8 /* 7.gif */, + 6DD31988188E592100ED5FE8 /* 8.gif */, + 6DD31989188E592100ED5FE8 /* 9.gif */, + 6DD3198A188E592100ED5FE8 /* 10.gif */, + 6DD3198B188E592100ED5FE8 /* 11.gif */, + 6DD3198C188E592100ED5FE8 /* 12.gif */, + 6DD3198D188E592100ED5FE8 /* 13.gif */, + 6DD3198E188E592100ED5FE8 /* 14.gif */, + 6DD3198F188E592100ED5FE8 /* 15.gif */, + 6DD31990188E592100ED5FE8 /* 16.gif */, + 6DD31991188E592100ED5FE8 /* 17.gif */, + 6DD31992188E592100ED5FE8 /* 18.gif */, + 6DD31993188E592100ED5FE8 /* 19.gif */, + 6DD31994188E592100ED5FE8 /* 20.gif */, + 6DD31995188E592100ED5FE8 /* 21.gif */, + 6DD31996188E592100ED5FE8 /* 22.gif */, + 6DD31997188E592100ED5FE8 /* 23.gif */, + 6DD31998188E592100ED5FE8 /* 24.gif */, + 6DD31999188E592100ED5FE8 /* 25.gif */, + 6DD3199A188E592100ED5FE8 /* 26.gif */, + 6DD3199B188E592100ED5FE8 /* 27.gif */, + 6DD3199C188E592100ED5FE8 /* 28.gif */, + 6DD3199D188E592100ED5FE8 /* 29.gif */, + 6DD3199E188E592100ED5FE8 /* 30.gif */, + 6DD3199F188E592100ED5FE8 /* 31.gif */, + 6DD319A0188E592100ED5FE8 /* 32.gif */, + 6DD319A1188E592100ED5FE8 /* 33.gif */, + 6DD319A2188E592100ED5FE8 /* 34.gif */, + 6DD319A3188E592100ED5FE8 /* 35.gif */, + 6DD319A4188E592100ED5FE8 /* 36.gif */, + 6DD319A5188E592100ED5FE8 /* 37.gif */, + 6DD319A6188E592100ED5FE8 /* 38.gif */, + 6DD319A7188E592100ED5FE8 /* 39.gif */, + 6DD319A8188E592100ED5FE8 /* 40.gif */, + 6DD319A9188E592100ED5FE8 /* 41.gif */, + 6DD319AA188E592100ED5FE8 /* 42.gif */, + 6DD319AB188E592100ED5FE8 /* 43.gif */, + 6DD319AC188E592100ED5FE8 /* 44.gif */, + 6DD319AD188E592100ED5FE8 /* 45.gif */, + 6DD319AE188E592100ED5FE8 /* 46.gif */, + 6DD319AF188E592100ED5FE8 /* 47.gif */, + 6DD319B0188E592100ED5FE8 /* 48.gif */, + 6DD319B1188E592100ED5FE8 /* 49.gif */, + 6DD319B2188E592100ED5FE8 /* 50.gif */, + 6DD319B3188E592100ED5FE8 /* 51.gif */, + 6DD319B4188E592100ED5FE8 /* 52.gif */, + 6DD319B5188E592100ED5FE8 /* 53.gif */, + 6DD319B6188E592100ED5FE8 /* 54.gif */, + 6DD319B7188E592100ED5FE8 /* 55.gif */, + 6DD319B8188E592100ED5FE8 /* 56.gif */, + 6DD319B9188E592100ED5FE8 /* 57.gif */, + 6DD319BA188E592100ED5FE8 /* 58.gif */, + 6DD319BB188E592100ED5FE8 /* 59.gif */, + 6DD319BC188E592100ED5FE8 /* 60.gif */, + 6DD319BD188E592100ED5FE8 /* 61.gif */, + 6DD319BE188E592100ED5FE8 /* 62.gif */, + 6DD319BF188E592100ED5FE8 /* 63.gif */, + 6DD319C0188E592100ED5FE8 /* 64.gif */, + 6DD319C1188E592100ED5FE8 /* 65.gif */, + 6DD319C2188E592100ED5FE8 /* 66.gif */, + 6DD319C3188E592100ED5FE8 /* 67.gif */, + 6DD319C4188E592100ED5FE8 /* 68.gif */, + 6DD319C5188E592100ED5FE8 /* 69.gif */, + 6DD319C6188E592100ED5FE8 /* 70.gif */, + 6DD319C7188E592100ED5FE8 /* 71.gif */, + 6DD319C8188E592100ED5FE8 /* 72.gif */, + 6DD319C9188E592100ED5FE8 /* 73.gif */, + 6DD319CA188E592100ED5FE8 /* 74.gif */, + 6DD319CB188E592100ED5FE8 /* 75.gif */, + 6DD319CC188E592100ED5FE8 /* 76.gif */, + 6DD319CD188E592100ED5FE8 /* 77.gif */, + 6DD319CE188E592100ED5FE8 /* 78.gif */, + 6DD319CF188E592100ED5FE8 /* 79.gif */, + 6DD319D0188E592100ED5FE8 /* 80.gif */, + 6DD319D1188E592100ED5FE8 /* 81.gif */, + 6DD319D2188E592100ED5FE8 /* 82.gif */, + 6DD319D3188E592100ED5FE8 /* 83.gif */, + 6DD319D4188E592100ED5FE8 /* 84.gif */, + 6DD319D5188E592100ED5FE8 /* 85.gif */, + 6DD319D6188E592100ED5FE8 /* 86.gif */, + 6DD319D7188E592100ED5FE8 /* 87.gif */, + 6DD319D8188E592100ED5FE8 /* 88.gif */, + 6DD319D9188E592100ED5FE8 /* 89.gif */, + 6DD319DA188E592100ED5FE8 /* 90.gif */, + 6DD319DB188E592100ED5FE8 /* 91.gif */, + 6DD319DC188E592100ED5FE8 /* 92.gif */, + 6DD319DD188E592100ED5FE8 /* 93.gif */, + 6DD319DE188E592100ED5FE8 /* 94.gif */, + 6DD319DF188E592100ED5FE8 /* 95.gif */, + 6DD319E0188E592100ED5FE8 /* 96.gif */, + 6DD319E1188E592100ED5FE8 /* 97.gif */, + 6DD319E2188E592100ED5FE8 /* 98.gif */, + 6DD319E3188E592100ED5FE8 /* 99.gif */, + 6DD319E4188E592100ED5FE8 /* 100.gif */, + 6DD319E5188E592100ED5FE8 /* 101.gif */, + 6DD319E6188E592100ED5FE8 /* 102.gif */, + 6DD319E7188E592100ED5FE8 /* 103.gif */, + 6DD319E8188E592100ED5FE8 /* 104.gif */, + 6DD319E9188E592100ED5FE8 /* 105.gif */, + 6DD319EA188E592100ED5FE8 /* 106.gif */, + 6DD319EB188E592100ED5FE8 /* 107.gif */, + 6DD319EC188E592100ED5FE8 /* 108.gif */, + 6DD319ED188E592100ED5FE8 /* 109.gif */, + 6DD319EE188E592100ED5FE8 /* 110.gif */, + 6DD319EF188E592100ED5FE8 /* 111.gif */, + 6DD319F0188E592100ED5FE8 /* 112.gif */, + 6DD319F1188E592100ED5FE8 /* 113.gif */, + 6DD319F2188E592100ED5FE8 /* 114.gif */, + 6DD319F3188E592100ED5FE8 /* 115.gif */, + 6DD319F4188E592100ED5FE8 /* 116.gif */, + 6DD319F5188E592100ED5FE8 /* 117.gif */, + 6DD319F6188E592100ED5FE8 /* 118.gif */, + 6DD319F7188E592100ED5FE8 /* 119.gif */, + 6DD319F8188E592100ED5FE8 /* 120.gif */, + 6DD319F9188E592100ED5FE8 /* 121.gif */, + 6DD319FA188E592100ED5FE8 /* 122.gif */, + 6DD319FB188E592100ED5FE8 /* 123.gif */, + 6DD319FC188E592100ED5FE8 /* 124.gif */, + 6DD319FD188E592100ED5FE8 /* 125.gif */, + 6DD319FE188E592100ED5FE8 /* 126.gif */, + 6DD319FF188E592100ED5FE8 /* 127.gif */, + 6DD31A00188E592100ED5FE8 /* 128.gif */, + 6DD31A01188E592200ED5FE8 /* 129.gif */, + 6DD31A02188E592200ED5FE8 /* 130.gif */, + 6DD31A03188E592200ED5FE8 /* 131.gif */, + 6DD31A04188E592200ED5FE8 /* 132.gif */, + 6DD31A05188E592200ED5FE8 /* 133.gif */, + 6DD31A06188E592200ED5FE8 /* 134.gif */, + 6DD31A07188E592200ED5FE8 /* 135.gif */, + 6DD31A08188E592200ED5FE8 /* 136.gif */, + 6DD31A09188E592200ED5FE8 /* 137.gif */, + 6DD31A0A188E592200ED5FE8 /* 138.gif */, + 6DD31A0B188E592200ED5FE8 /* 139.gif */, + 6DD31A0C188E592200ED5FE8 /* 140.gif */, + 6DD31A0D188E592200ED5FE8 /* 141.gif */, + 6DD31A0E188E592200ED5FE8 /* 142.gif */, + 6DD31A0F188E592200ED5FE8 /* 143.gif */, + 6DD31A10188E592200ED5FE8 /* 144.gif */, + 6DD31A11188E592200ED5FE8 /* 145.gif */, + 6DD31A12188E592200ED5FE8 /* 146.gif */, + 6DD31A13188E592200ED5FE8 /* 147.gif */, + 6DD31A14188E592200ED5FE8 /* 148.gif */, + 6DD31A15188E592200ED5FE8 /* 149.gif */, + 6DD31A16188E592200ED5FE8 /* 150.gif */, + 6DD31A17188E592200ED5FE8 /* 151.gif */, + 6DD31A18188E592200ED5FE8 /* 152.gif */, + 6DD31A19188E592200ED5FE8 /* 153.gif */, + 6DD31A1A188E592200ED5FE8 /* 154.gif */, + 6DD31A1B188E592200ED5FE8 /* 155.gif */, + 6DD31A1C188E592200ED5FE8 /* 156.gif */, + 6DD31A1D188E592200ED5FE8 /* 157.gif */, + 6DD31A1E188E592200ED5FE8 /* 158.gif */, + 6DD31A1F188E592200ED5FE8 /* 159.gif */, + 6DD31A20188E592200ED5FE8 /* 160.gif */, + 6DD31A21188E592200ED5FE8 /* 161.gif */, + 6DD31A22188E592200ED5FE8 /* 162.gif */, + 6DD31A23188E592200ED5FE8 /* 163.gif */, + 6DD31A24188E592200ED5FE8 /* 164.gif */, + 6DD31A25188E592200ED5FE8 /* 165.gif */, + 6DD31A26188E592200ED5FE8 /* 166.gif */, + 6DD31A27188E592200ED5FE8 /* 167.gif */, + 6DD31A28188E592200ED5FE8 /* 168.gif */, + 6DD31A29188E592200ED5FE8 /* 169.gif */, + 6DD31A2A188E592200ED5FE8 /* 170.gif */, + 6DD31A2B188E592200ED5FE8 /* 171.gif */, + 6DD31A2C188E592200ED5FE8 /* 172.gif */, + 6DD31A2D188E592200ED5FE8 /* 173.gif */, + 6DD31A2E188E592200ED5FE8 /* 174.gif */, + 6DD31A2F188E592200ED5FE8 /* 175.gif */, + 6DD31A30188E592200ED5FE8 /* 176.gif */, + 6DD31A31188E592200ED5FE8 /* 177.gif */, + 6DD31A32188E592200ED5FE8 /* 178.gif */, + 6DD31A33188E592200ED5FE8 /* 179.gif */, + 6DD31A34188E592200ED5FE8 /* 180.gif */, + 6DD31A35188E592200ED5FE8 /* 181.gif */, + 6DD31A36188E592200ED5FE8 /* 182.gif */, + 6DD31A37188E592200ED5FE8 /* 183.gif */, + 6DD31A38188E592200ED5FE8 /* 184.gif */, + 6DD31A39188E592200ED5FE8 /* 185.gif */, + 6DD31A3A188E592200ED5FE8 /* 186.gif */, + 6DD31A3B188E592200ED5FE8 /* 187.gif */, + 6DD31A3C188E592200ED5FE8 /* 188.gif */, + 6DD31A3D188E592200ED5FE8 /* 189.gif */, + 6DD31A3E188E592200ED5FE8 /* 190.gif */, + 6DD31A3F188E592200ED5FE8 /* 191.gif */, + 6DD31A40188E592200ED5FE8 /* 192.gif */, + 6DD31A41188E592200ED5FE8 /* 193.gif */, + 6DD31A42188E592200ED5FE8 /* 194.gif */, + 6DD31A43188E592200ED5FE8 /* 195.gif */, + 6DD31A44188E592200ED5FE8 /* 196.gif */, + 6DD31A45188E592200ED5FE8 /* 197.gif */, + 6DD31A46188E592200ED5FE8 /* 198.gif */, + 6DD31A47188E592200ED5FE8 /* 199.gif */, + 6DD31A48188E592200ED5FE8 /* 200.gif */, + 6DD31A49188E592200ED5FE8 /* 201.gif */, + 6DD31A4A188E592200ED5FE8 /* 202.gif */, + 6DD31A4B188E592200ED5FE8 /* 203.gif */, + 6DD31A4C188E592200ED5FE8 /* 204.gif */, + 6DD31A4D188E592200ED5FE8 /* 205.gif */, + 6DD31A4E188E592200ED5FE8 /* 206.gif */, + 6DD31A4F188E592200ED5FE8 /* 207.gif */, + 6DD31A50188E592200ED5FE8 /* 208.gif */, + 6DD31A51188E592200ED5FE8 /* 209.gif */, + 6DD31A52188E592200ED5FE8 /* 210.gif */, + 6DD31A53188E592200ED5FE8 /* 211.gif */, + 6DD31A54188E592200ED5FE8 /* 212.gif */, + 6DD31A55188E592200ED5FE8 /* 213.gif */, + 6DD31A56188E592200ED5FE8 /* 214.gif */, + 6DD31A57188E592200ED5FE8 /* 215.gif */, + 6DD31A58188E592200ED5FE8 /* 216.gif */, + 6DD31A59188E592200ED5FE8 /* 217.gif */, + 6DD31A5A188E592200ED5FE8 /* 218.gif */, + 6DD31A5B188E592200ED5FE8 /* 219.gif */, + 6DD31A5C188E592200ED5FE8 /* 220.gif */, + ); + name = emotions; + sourceTree = ""; + }; + 6DE7620B18867F00000EDC39 /* ScrollToRefresh */ = { + isa = PBXGroup; + children = ( + 6DE7620C18867FE2000EDC39 /* PullToRefreshClipView.h */, + 6DE7620D18867FE2000EDC39 /* PullToRefreshClipView.m */, + 6DE7620E18867FE2000EDC39 /* PullToRefreshDelegate.h */, + 6DE7620F18867FE2000EDC39 /* PullToRefreshScrollView.h */, + 6DE7621018867FE2000EDC39 /* PullToRefreshScrollView.m */, + ); + name = ScrollToRefresh; + sourceTree = ""; + }; + 8179EECE1A6E5CBE000AADA3 /* html */ = { + isa = PBXGroup; + children = ( + C4FF47421A81AF3700B21A0D /* msgfail.png */, + 8195ED4F1A7651E700DA5CA0 /* bg.jpg */, + 81DE59C41A831B9F00040078 /* big.cur */, + 8195ED501A7651E700DA5CA0 /* blb.png */, + 81ECFE3B1A822E5500445985 /* voice_me.gif */, + 81ECFE3C1A822E5500445985 /* voice_other.gif */, + 8195ED511A7651E700DA5CA0 /* blbb.png */, + 81ECFE3F1A8230E700445985 /* gifffer.js */, + 81ECFE411A82338D00445985 /* voice_me.png */, + 81ECFE421A82338D00445985 /* voice_other.png */, + 8195ED521A7651E700DA5CA0 /* brw.png */, + 8195ED531A7651E700DA5CA0 /* brwb.png */, + 8195ED541A7651E700DA5CA0 /* highlight.default.css */, + 8195ED551A7651E700DA5CA0 /* highlight.min.js */, + 8195ED561A7651E700DA5CA0 /* highlight.pack.js */, + 8195ED571A7651E700DA5CA0 /* hook-spinner.gif */, + 8195ED581A7651E700DA5CA0 /* hook.css */, + 8195ED591A7651E700DA5CA0 /* hook.min.js */, + 8195ED5A1A7651E700DA5CA0 /* iscroll-probe.js */, + 8195ED5B1A7651E700DA5CA0 /* iscroll.js */, + 8195ED5C1A7651E700DA5CA0 /* jquery-2.1.1.min.js */, + 8195ED5D1A7651E700DA5CA0 /* jquery.scrollz.css */, + 8195ED5E1A7651E700DA5CA0 /* jquery.scrollz.min.js */, + 8195ED5F1A7651E700DA5CA0 /* main.css */, + 8195ED601A7651E700DA5CA0 /* message.html */, + 8195ED611A7651E700DA5CA0 /* moment-with-locales.min.js */, + 8195ED621A7651E700DA5CA0 /* mousewheel.js */, + 8195ED631A7651E700DA5CA0 /* msg.js */, + 8195ED641A7651E700DA5CA0 /* pure-min.css */, + 8195ED651A7651E700DA5CA0 /* scrollbar.css */, + 8195ED661A7651E700DA5CA0 /* solarized_dark.css */, + 8195ED671A7651E700DA5CA0 /* solarized_light.css */, + 8195ED681A7651E700DA5CA0 /* template.js */, + ); + path = html; + sourceTree = ""; + }; + 81DEF4E61A5B774600F0799D /* pb */ = { + isa = PBXGroup; + children = ( + 577BB7FB1A64F78E00264086 /* IMBaseDefine.pb.h */, + 577BB7FC1A64F78E00264086 /* IMBaseDefine.pb.m */, + 577BB7FD1A64F78E00264086 /* IMBuddy.pb.h */, + 577BB7FE1A64F78E00264086 /* IMBuddy.pb.m */, + 577BB7FF1A64F78E00264086 /* IMGroup.pb.h */, + 577BB8001A64F78E00264086 /* IMGroup.pb.m */, + 577BB8011A64F78E00264086 /* IMLogin.pb.h */, + 577BB8021A64F78E00264086 /* IMLogin.pb.m */, + 577BB8031A64F78E00264086 /* IMMessage.pb.h */, + 577BB8041A64F78E00264086 /* IMMessage.pb.m */, + 577BB8051A64F78E00264086 /* IMOther.pb.h */, + 577BB8061A64F78E00264086 /* IMOther.pb.m */, + 577BB8071A64F78E00264086 /* IMSwitchService.pb.h */, + 577BB8081A64F78E00264086 /* IMSwitchService.pb.m */, + 577BB8091A64F78E00264086 /* IMXIAOT.pb.h */, + 577BB80A1A64F78E00264086 /* IMXIAOT.pb.m */, + ); + name = pb; + path = modules/pb; + sourceTree = ""; + }; + C408E8C7191CD9D5005F5150 /* Users */ = { + isa = PBXGroup; + children = ( + C4FA6BDA190909EA0097849B /* DDRecentConactsAPI.h */, + C4FA6BDB190909EA0097849B /* DDRecentConactsAPI.m */, + C40F95181919C69A005CACBF /* DDAllUserAPI.h */, + C40F95191919C69A005CACBF /* DDAllUserAPI.m */, + C40F9545191B1D32005CACBF /* DDUserOnlineStateAPI.h */, + C40F9546191B1D32005CACBF /* DDUserOnlineStateAPI.m */, + C4EBA728192D91E400B72723 /* DDUserDetailInfoAPI.h */, + C4EBA729192D91E400B72723 /* DDUserDetailInfoAPI.m */, + C4C1CB83197E695000386AB0 /* DDModifyUserAvatarAPI.h */, + C4C1CB84197E695000386AB0 /* DDModifyUserAvatarAPI.m */, + EF29F2BE1AB81E15001FC3EE /* DDDepartmentInfoAPI.h */, + EF29F2BF1AB81E15001FC3EE /* DDDepartmentInfoAPI.m */, + ); + name = Users; + sourceTree = ""; + }; + C408E8C8191CDA0F005F5150 /* Group */ = { + isa = PBXGroup; + children = ( + C408E8AF191B57DE005F5150 /* DDCreateGroupAPI.h */, + C408E8B0191B57DE005F5150 /* DDCreateGroupAPI.m */, + C47935321918E88B009C39AE /* DDFixedGroupAPI.h */, + C47935331918E88B009C39AE /* DDFixedGroupAPI.m */, + C40F9539191A011A005CACBF /* DDGroupInfoAPI.h */, + C40F953A191A011A005CACBF /* DDGroupInfoAPI.m */, + 5771F13F1A7E5D0C003EDC6A /* MTGroupChangeMemberAPI.h */, + 5771F1401A7E5D0C003EDC6A /* MTGroupChangeMemberAPI.m */, + ); + name = Group; + sourceTree = ""; + }; + C408E8C9191CDA2B005F5150 /* Login */ = { + isa = PBXGroup; + children = ( + C479352C1918E807009C39AE /* DDLoginAPI.h */, + C479352D1918E807009C39AE /* DDLoginAPI.mm */, + C48E2F641A625A1F002F3FEB /* DDHeartBeatAPI.h */, + C48E2F651A625A1F002F3FEB /* DDHeartBeatAPI.m */, + ); + name = Login; + sourceTree = ""; + }; + C408E8CA191CDA41005F5150 /* Message */ = { + isa = PBXGroup; + children = ( + C408E8AC191B48BD005F5150 /* DDSendMessageAPI.h */, + C408E8AD191B48BD005F5150 /* DDSendMessageAPI.mm */, + 8AEFB8401920968C006A5C88 /* DDSendP2PCmdAPI.h */, + 8AEFB8411920968C006A5C88 /* DDSendP2PCmdAPI.m */, + 81FA3B281A68DEBC00B379D1 /* DDHistoryMessageAPI.h */, + 81FA3B291A68DEBC00B379D1 /* DDHistoryMessageAPI.m */, + 811405D21A68EFA6009CFC06 /* DDUnreadMessageAPI.h */, + 811405D31A68EFA6009CFC06 /* DDUnreadMessageAPI.m */, + C4C0724C1AA583F900C01D0D /* DDGetLastMessageIDAPI.h */, + C4C0724D1AA583F900C01D0D /* DDGetLastMessageIDAPI.m */, + ); + name = Message; + sourceTree = ""; + }; + C408E8CB191CDA68005F5150 /* File */ = { + isa = PBXGroup; + children = ( + C4FE22251920B40100FFB520 /* DDAbortFileSendAPI.h */, + C4FE22261920B40100FFB520 /* DDAbortFileSendAPI.m */, + C408E8CC191CDAE4005F5150 /* DDFileLoginAPI.h */, + C408E8CD191CDAE4005F5150 /* DDFileLoginAPI.m */, + C408E8CF191CDCDD005F5150 /* DDFileSendAPI.h */, + C408E8D0191CDCDD005F5150 /* DDFileSendAPI.m */, + C4FE22401920DEE500FFB520 /* DDFileSendResponseAPI.h */, + C4FE22411920DEE500FFB520 /* DDFileSendResponseAPI.m */, + C408E8D2191CE13E005F5150 /* DDGetOfflineFileAPI.h */, + C408E8D3191CE13E005F5150 /* DDGetOfflineFileAPI.m */, + C4FE222B1920C60300FFB520 /* DDSendOffLineFileAPI.h */, + C4FE222C1920C60300FFB520 /* DDSendOffLineFileAPI.m */, + C4FE22341920CBB200FFB520 /* DDOfflineFileUploadFinishedAPI.h */, + C4FE22351920CBB200FFB520 /* DDOfflineFileUploadFinishedAPI.m */, + C4FE223A1920CF3700FFB520 /* DDAddOfflineFileAPI.h */, + C4FE223B1920CF3700FFB520 /* DDAddOfflineFileAPI.m */, + C4FE223D1920CF4A00FFB520 /* DDDeleteOfflineFileAPI.h */, + C4FE223E1920CF4A00FFB520 /* DDDeleteOfflineFileAPI.m */, + C4FE22491920F11300FFB520 /* DDReadyReceiveFileAPI.h */, + C4FE224A1920F11300FFB520 /* DDReadyReceiveFileAPI.m */, + ); + name = File; + sourceTree = ""; + }; + C408E8D5191CE398005F5150 /* Message */ = { + isa = PBXGroup; + children = ( + C40F95261919DDCC005CACBF /* DDReceiveMessageAPI.h */, + C40F95271919DDCC005CACBF /* DDReceiveMessageAPI.m */, + C4FE221F19209B2300FFB520 /* DDReceiveP2PMessageAPI.h */, + C4FE222019209B2300FFB520 /* DDReceiveP2PMessageAPI.m */, + 57DEB6931A8222A800961C6F /* DDReceiveMsgDataReadNotifyAPI.h */, + 57DEB6941A8222A800961C6F /* DDReceiveMsgDataReadNotifyAPI.m */, + ); + name = Message; + sourceTree = ""; + }; + C408E8D6191CE3A4005F5150 /* OnlineState */ = { + isa = PBXGroup; + children = ( + C40F9548191B26EE005CACBF /* DDReceiveStateChangedAPI.h */, + C40F9549191B26EE005CACBF /* DDReceiveStateChangedAPI.m */, + C408E8C1191B83F2005F5150 /* DDOnlineUserListAPI.h */, + C408E8C2191B83F3005F5150 /* DDOnlineUserListAPI.m */, + C408E8C4191B8B70005F5150 /* DDReceiveKickAPI.h */, + C408E8C5191B8B70005F5150 /* DDReceiveKickAPI.m */, + ); + name = OnlineState; + sourceTree = ""; + }; + C408E8D7191CE3B8005F5150 /* Group */ = { + isa = PBXGroup; + children = ( + C4FF47391A7FA0F800B21A0D /* DDReceiveGroupMemberChangedAPI.h */, + C4FF473A1A7FA0F800B21A0D /* DDReceiveGroupMemberChangedAPI.m */, + ); + name = Group; + sourceTree = ""; + }; + C408E8D8191CE41A005F5150 /* File */ = { + isa = PBXGroup; + children = ( + C408E8D9191CE44E005F5150 /* DDOtherLinkFileServerAPI.h */, + C408E8DA191CE44E005F5150 /* DDOtherLinkFileServerAPI.m */, + C4FE22221920B2A000FFB520 /* DDOtherFileResponseAPI.h */, + C4FE22231920B2A000FFB520 /* DDOtherFileResponseAPI.m */, + C4FE22281920C04700FFB520 /* DDReceiveAbortFileSendAPI.h */, + C4FE22291920C04700FFB520 /* DDReceiveAbortFileSendAPI.m */, + C4FE222E1920C8D700FFB520 /* DDOtherSendOfflineFileAPI.h */, + C4FE222F1920C8D700FFB520 /* DDOtherSendOfflineFileAPI.m */, + C4FE22371920CE5600FFB520 /* DDReceiveOtherOfflineFileUploadFinishedAPI.h */, + C4FE22381920CE5600FFB520 /* DDReceiveOtherOfflineFileUploadFinishedAPI.m */, + C4FE22431920E43600FFB520 /* DDReceiveOtherResponseAPI.h */, + C4FE22441920E43600FFB520 /* DDReceiveOtherResponseAPI.m */, + C4FE22461920EC4D00FFB520 /* DDReceiveOtherSendFileAPI.h */, + C4FE22471920EC4D00FFB520 /* DDReceiveOtherSendFileAPI.m */, + C4FE224C1920F35600FFB520 /* DDReceiveOtherReadyAcceptFileAPI.h */, + C4FE224D1920F35600FFB520 /* DDReceiveOtherReadyAcceptFileAPI.m */, + ); + name = File; + sourceTree = ""; + }; + C40F95221919D62D005CACBF /* UnrequestAPI */ = { + isa = PBXGroup; + children = ( + C408E8D8191CE41A005F5150 /* File */, + C408E8D5191CE398005F5150 /* Message */, + C408E8D6191CE3A4005F5150 /* OnlineState */, + C408E8D7191CE3B8005F5150 /* Group */, + ); + path = UnrequestAPI; + sourceTree = ""; + }; + C40F95351919FB79005CACBF /* ACK */ = { + isa = PBXGroup; + children = ( + C40F95291919FA00005CACBF /* DDMsgReadACKAPI.h */, + C40F952A1919FA00005CACBF /* DDMsgReadACKAPI.m */, + C40F952F1919FB4F005CACBF /* DDUserMsgReceivedACKAPI.h */, + C40F95301919FB4F005CACBF /* DDUserMsgReceivedACKAPI.m */, + C40F952C1919FA90005CACBF /* DDGroupMsgReadACKAPI.h */, + C40F952D1919FA90005CACBF /* DDGroupMsgReadACKAPI.m */, + C40F95321919FB75005CACBF /* DDGroupMsgReceivedACKAPI.h */, + C40F95331919FB75005CACBF /* DDGroupMsgReceivedACKAPI.m */, + ); + name = ACK; + sourceTree = ""; + }; + C417C3961A7370C7003984D7 /* ImageCache */ = { + isa = PBXGroup; + children = ( + C417C3971A7370E2003984D7 /* MTImageCache.h */, + C417C3981A7370E2003984D7 /* MTImageCache.m */, + C417C39D1A738010003984D7 /* MTImageDownload.h */, + C417C39E1A738010003984D7 /* MTImageDownload.m */, + ); + path = ImageCache; + sourceTree = ""; + }; + C41AB117195A7EA8002AE7C7 /* Intranet */ = { + isa = PBXGroup; + children = ( + C41AB118195A7EF2002AE7C7 /* DDIntranetViewController.h */, + C41AB119195A7EF2002AE7C7 /* DDIntranetViewController.m */, + C41AB126195AACE8002AE7C7 /* DDIntranentViewController.xib */, + C41AB11B195AA10F002AE7C7 /* DDIntranetModule.h */, + C41AB11C195AA10F002AE7C7 /* DDIntranetModule.m */, + C41AB11E195AA9DA002AE7C7 /* DDIntranetEntity.h */, + C41AB11F195AA9DA002AE7C7 /* DDIntranetEntity.m */, + C41AB123195AAAF4002AE7C7 /* DDIntranetCell.h */, + C41AB124195AAAF4002AE7C7 /* DDIntranetCell.m */, + ); + name = Intranet; + sourceTree = ""; + }; + C41AB128195B042F002AE7C7 /* IntranetContentw */ = { + isa = PBXGroup; + children = ( + C41AB129195B0487002AE7C7 /* DDIntranetContentViewController.h */, + C41AB12A195B0487002AE7C7 /* DDIntranetContentViewController.m */, + C41AB12B195B0487002AE7C7 /* DDIntranetContentViewController.xib */, + ); + name = IntranetContentw; + sourceTree = ""; + }; + C42410CC199734C300B6B945 /* ServiceAccount */ = { + isa = PBXGroup; + children = ( + C42410CD199734E100B6B945 /* DDServiceAccountModule.h */, + C42410CE199734E100B6B945 /* DDServiceAccountModule.m */, + ); + path = ServiceAccount; + sourceTree = ""; + }; + C42A070418E7D01D004461E1 /* Category */ = { + isa = PBXGroup; + children = ( + 81DEF50E1A5B908100F0799D /* NSString+Additions.h */, + 81DEF50F1A5B908100F0799D /* NSString+Additions.m */, + 81DEF50B1A5B901B00F0799D /* NSDictionary+Safe.h */, + 81DEF50C1A5B901B00F0799D /* NSDictionary+Safe.m */, + C42A070518E7D01D004461E1 /* NSWindow+Animation.h */, + C42A070618E7D01D004461E1 /* NSWindow+Animation.m */, + C48E79F518FFAE7800A1FA66 /* NSImage+Addition.h */, + C48E79F618FFAE7800A1FA66 /* NSImage+Addition.m */, + C47934861915F217009C39AE /* NSView+LayerAddition.h */, + C47934871915F217009C39AE /* NSView+LayerAddition.m */, + C47934FF191782E7009C39AE /* NSWindow+Addition.h */, + C4793500191782E7009C39AE /* NSWindow+Addition.m */, + C417C39A1A737C2C003984D7 /* NSImageView+MTAddition.h */, + C417C39B1A737C2C003984D7 /* NSImageView+MTAddition.m */, + ); + path = Category; + sourceTree = ""; + }; + C42A070818E80029004461E1 /* MsgSendManager */ = { + isa = PBXGroup; + children = ( + C42A070918E80066004461E1 /* DDMessageSendManager.h */, + C42A070A18E80066004461E1 /* DDMessageSendManager.m */, + C42A070C18E80E49004461E1 /* DDImageUploader.h */, + C42A070D18E80E49004461E1 /* DDImageUploader.m */, + ); + name = MsgSendManager; + sourceTree = ""; + }; + C42D4EA019247ED900C7B6F6 /* MoveApplication */ = { + isa = PBXGroup; + children = ( + C42D4EA119247EEA00C7B6F6 /* PFMoveApplication.h */, + C42D4EA219247EEA00C7B6F6 /* PFMoveApplication.m */, + ); + name = MoveApplication; + sourceTree = ""; + }; + C4498A0018D71A92009FEA4A /* Chatting */ = { + isa = PBXGroup; + children = ( + C4498A0118D71A92009FEA4A /* MessageShowView.h */, + C4498A0218D71A92009FEA4A /* MessageShowView.m */, + C4498A0318D71A92009FEA4A /* MessageViewFactory.h */, + C4498A0418D71A92009FEA4A /* MessageViewFactory.m */, + C4AB954418DAD5C9000181AD /* WhiteBackgroundView.h */, + C4AB954518DAD5C9000181AD /* WhiteBackgroundView.m */, + C4AB955218DBF006000181AD /* DrawView.h */, + C4AB955318DBF006000181AD /* DrawView.m */, + C406E70118D84FD2005092C3 /* DDMessageTextView.h */, + C406E70218D84FD2005092C3 /* DDMessageTextView.m */, + C4498A0518D71A92009FEA4A /* NSTextView+Rect.h */, + C4498A0618D71A92009FEA4A /* NSTextView+Rect.m */, + C406E70718D8616B005092C3 /* DDChangableAttactment.h */, + C406E70818D8616B005092C3 /* DDChangableAttactment.m */, + C406E6F818D81850005092C3 /* NSAttributedString+Message.h */, + C406E6F918D81850005092C3 /* NSAttributedString+Message.m */, + C406E6FB18D81925005092C3 /* NSImage+Scale.h */, + C406E6FC18D81925005092C3 /* NSImage+Scale.m */, + C406E6FE18D82E84005092C3 /* EmotionManager.h */, + C406E6FF18D82E84005092C3 /* EmotionManager.m */, + 57C2D2E81A74D3C500981552 /* DDAtUserListViewController.h */, + 57C2D2E91A74D3C500981552 /* DDAtUserListViewController.m */, + 57C2D2EA1A74D3C500981552 /* DDAtUserListViewController.xib */, + ); + name = Chatting; + path = modules/Chatting; + sourceTree = ""; + }; + C479352B1918E7DB009C39AE /* APIGroup */ = { + isa = PBXGroup; + children = ( + C4FE221719205BF700FFB520 /* Session */, + C408E8CB191CDA68005F5150 /* File */, + C408E8CA191CDA41005F5150 /* Message */, + C408E8C9191CDA2B005F5150 /* Login */, + C408E8C8191CDA0F005F5150 /* Group */, + C408E8C7191CD9D5005F5150 /* Users */, + C40F95351919FB79005CACBF /* ACK */, + ); + path = APIGroup; + sourceTree = ""; + }; + C48B104418D1AE5900DEF8C6 /* CrashReport */ = { + isa = PBXGroup; + children = ( + C48B104518D1AE9000DEF8C6 /* CrashReportManager.h */, + C48B104618D1AE9000DEF8C6 /* CrashReportManager.m */, + ); + name = CrashReport; + sourceTree = ""; + }; + C48D603218BC632500F5ED30 /* User group Data */ = { + isa = PBXGroup; + children = ( + C48D603318BC634A00F5ED30 /* DDUserDataWindowController.h */, + C48D603418BC634A00F5ED30 /* DDUserDataWindowController.m */, + C48D603818BC670900F5ED30 /* DDUserDataModel.h */, + C48D603918BC670900F5ED30 /* DDUserDataModel.m */, + C43802D018C4860B002555BB /* DDGroupDataWindow.h */, + C43802D118C4860B002555BB /* DDGroupDataWindow.m */, + C43802D618C48650002555BB /* DDGroupDataWindow.xib */, + C43802D318C48627002555BB /* DDGroupDataModule.h */, + C43802D418C48627002555BB /* DDGroupDataModule.m */, + C43802D818C48A40002555BB /* DDGroupInfoCell.h */, + C43802D918C48A40002555BB /* DDGroupInfoCell.m */, + C438032218C5C916002555BB /* DDUserInfoManager.h */, + C438032318C5C916002555BB /* DDUserInfoManager.m */, + C438032518C5D130002555BB /* DDGroupInfoManager.h */, + C438032618C5D130002555BB /* DDGroupInfoManager.m */, + C47934D819172063009C39AE /* DDUserInfoPanel.h */, + C47934D919172063009C39AE /* DDUserInfoPanel.m */, + C47934DB191724D5009C39AE /* DDUserInfoPanel.xib */, + ); + name = "User group Data"; + path = interface/UserData; + sourceTree = ""; + }; + C48E2F3C1A6224B3002F3FEB /* OriginEntity */ = { + isa = PBXGroup; + children = ( + C48E2F411A6224F1002F3FEB /* Grouyp */, + C48E2F421A6224F1002F3FEB /* User */, + C48E2F521A62264A002F3FEB /* DDOriginEntity.h */, + C48E2F531A62264A002F3FEB /* DDOriginEntity.m */, + ); + name = OriginEntity; + path = modules/OriginEntity; + sourceTree = ""; + }; + C48E2F3D1A6224B3002F3FEB /* OriginModule */ = { + isa = PBXGroup; + children = ( + C48E2F4B1A622543002F3FEB /* DDOriginModuleProtocol.h */, + C48E2F491A622523002F3FEB /* GroupModule */, + C48E2F4A1A622523002F3FEB /* UserModule */, + ); + name = OriginModule; + path = modules/OriginModule; + sourceTree = ""; + }; + C48E2F411A6224F1002F3FEB /* Grouyp */ = { + isa = PBXGroup; + children = ( + C48E2F461A622506002F3FEB /* MTGroupEntity.h */, + C48E2F471A622506002F3FEB /* MTGroupEntity.m */, + ); + path = Grouyp; + sourceTree = ""; + }; + C48E2F421A6224F1002F3FEB /* User */ = { + isa = PBXGroup; + children = ( + C48E2F431A6224F1002F3FEB /* MTUserEntity.h */, + C48E2F441A6224F1002F3FEB /* MTUserEntity.m */, + EF29F2C11AB82087001FC3EE /* MTDepartmentEntity.h */, + EF29F2C21AB82087001FC3EE /* MTDepartmentEntity.m */, + ); + path = User; + sourceTree = ""; + }; + C48E2F491A622523002F3FEB /* GroupModule */ = { + isa = PBXGroup; + children = ( + C48E2F4C1A62258D002F3FEB /* MTGroupModule.h */, + C48E2F4D1A62258D002F3FEB /* MTGroupModule.m */, + ); + path = GroupModule; + sourceTree = ""; + }; + C48E2F4A1A622523002F3FEB /* UserModule */ = { + isa = PBXGroup; + children = ( + C48E2F4F1A6225BA002F3FEB /* MTUserModule.h */, + C48E2F501A6225BA002F3FEB /* MTUserModule.m */, + EF29F2BB1AB80077001FC3EE /* MTDepartmentManager.h */, + EF29F2BC1AB80077001FC3EE /* MTDepartmentManager.m */, + ); + path = UserModule; + sourceTree = ""; + }; + C48E2F581A622843002F3FEB /* Session1 */ = { + isa = PBXGroup; + children = ( + C48E2F591A622873002F3FEB /* Entity */, + C48E2F5A1A622873002F3FEB /* Module */, + ); + name = Session1; + path = modules/Session1; + sourceTree = ""; + }; + C48E2F591A622873002F3FEB /* Entity */ = { + isa = PBXGroup; + children = ( + C48E2F5B1A622886002F3FEB /* MTSessionEntity.h */, + C48E2F5C1A622886002F3FEB /* MTSessionEntity.m */, + ); + path = Entity; + sourceTree = ""; + }; + C48E2F5A1A622873002F3FEB /* Module */ = { + isa = PBXGroup; + children = ( + C48E2F5E1A622899002F3FEB /* MTSessionModule.h */, + C48E2F5F1A622899002F3FEB /* MTSessionModule.m */, + ); + path = Module; + sourceTree = ""; + }; + C48E79ED18FE2ABB00A1FA66 /* HelpLib */ = { + isa = PBXGroup; + children = ( + C417C3961A7370C7003984D7 /* ImageCache */, + C4F7E5EC1907D203006E31F3 /* SundriesCenter */, + C48EEE5118F0168300FCB35B /* Notification */, + C48E79EE18FE2AF000A1FA66 /* DDPathHelp.h */, + C48E79EF18FE2AF000A1FA66 /* DDPathHelp.m */, + ); + path = HelpLib; + sourceTree = ""; + }; + C48E79F118FE861800A1FA66 /* Services */ = { + isa = PBXGroup; + children = ( + C48E79F218FF686200A1FA66 /* DDApplicationUpdate.h */, + C48E79F318FF686200A1FA66 /* DDApplicationUpdate.m */, + C4563FBC1906384F009DEB05 /* DDSearch.h */, + C4563FBD1906384F009DEB05 /* DDSearch.m */, + ); + path = Services; + sourceTree = ""; + }; + C48E79F818FFD73500A1FA66 /* MessageReview */ = { + isa = PBXGroup; + children = ( + C44C203E1900B2850069A31F /* DDMessageReviewWindowController.h */, + C44C203F1900B2850069A31F /* DDMessageReviewWindowController.m */, + C47934FD19177DF1009C39AE /* DDMessageReviewWindow.xib */, + C44C20411900B2AE0069A31F /* DDMessageReviewModule.h */, + C44C20421900B2AE0069A31F /* DDMessageReviewModule.m */, + C479350219178A69009C39AE /* DDMessageReviewContactsViewController.h */, + C479350319178A69009C39AE /* DDMessageReviewContactsViewController.m */, + C479350819178CF5009C39AE /* DDMessageReviewContactsCellView.h */, + C479350919178CF5009C39AE /* DDMessageReviewContactsCellView.m */, + C479350519178A89009C39AE /* DDMessagesReviewContentViewController.h */, + C479350619178A89009C39AE /* DDMessagesReviewContentViewController.m */, + C479350E19187782009C39AE /* DDMessagesReviewContentModule.h */, + C479350F19187782009C39AE /* DDMessagesReviewContentModule.m */, + C47935251918B9C0009C39AE /* DDMessagesReviewWindow.h */, + C47935261918B9C0009C39AE /* DDMessagesReviewWindow.m */, + C47935281918BD9F009C39AE /* DDMessageReviewTextView.h */, + C47935291918BD9F009C39AE /* DDMessageReviewTextView.m */, + ); + path = MessageReview; + sourceTree = ""; + }; + C48EEE5118F0168300FCB35B /* Notification */ = { + isa = PBXGroup; + children = ( + C48EEE5218F0169E00FCB35B /* NotificationHelp.h */, + C48EEE5318F0169E00FCB35B /* NotificationHelp.m */, + ); + name = Notification; + path = ..; + sourceTree = ""; + }; + C4A09C8A190FC1C700B39BF3 /* LeftBar */ = { + isa = PBXGroup; + children = ( + C4C926F4190F51C4005B3234 /* DDLeftBarViewController.h */, + C4C926F5190F51C4005B3234 /* DDLeftBarViewController.m */, + C4C926F7190F526F005B3234 /* DDLeftBarItem.h */, + C4C926F8190F526F005B3234 /* DDLeftBarItem.m */, + ); + name = LeftBar; + sourceTree = ""; + }; + C4A09C8B190FC1D800B39BF3 /* FirstColumn */ = { + isa = PBXGroup; + children = ( + C41AB117195A7EA8002AE7C7 /* Intranet */, + C4A09C92190FC30500B39BF3 /* RecentContacts */, + C4A09C93190FC31400B39BF3 /* Group */, + ); + name = FirstColumn; + sourceTree = ""; + }; + C4A09C92190FC30500B39BF3 /* RecentContacts */ = { + isa = PBXGroup; + children = ( + C4A09C8C190FC2AC00B39BF3 /* DDRecentContactsViewController.h */, + C4A09C8D190FC2AC00B39BF3 /* DDRecentContactsViewController.m */, + C4A09C9A190FC7B000B39BF3 /* DDRecentContactsViewController.xib */, + C4A09C8F190FC2FA00B39BF3 /* DDRecentContactsModule.h */, + C4A09C90190FC2FA00B39BF3 /* DDRecentContactsModule.m */, + C4A09C9C191089A800B39BF3 /* DDRecentContactsCell.h */, + C4A09C9D191089A800B39BF3 /* DDRecentContactsCell.m */, + C4C926C0190DE988005B3234 /* DDContactsRowView.h */, + C4C926C1190DE988005B3234 /* DDContactsRowView.m */, + C4A09CBE1910D19B00B39BF3 /* DDSearchViewController.h */, + C4A09CBF1910D19B00B39BF3 /* DDSearchViewController.m */, + C4A09CC11910D2BA00B39BF3 /* DDSearchResultCell.h */, + C4A09CC21910D2BA00B39BF3 /* DDSearchResultCell.m */, + C47934B019163C1F009C39AE /* HoverTableRowView.h */, + C47934B119163C1F009C39AE /* HoverTableRowView.m */, + ); + name = RecentContacts; + sourceTree = ""; + }; + C4A09C93190FC31400B39BF3 /* Group */ = { + isa = PBXGroup; + children = ( + C4A09C94190FC44400B39BF3 /* DDGroupViewController.h */, + C4A09C95190FC44400B39BF3 /* DDGroupViewController.m */, + C4A09CB91910AAC200B39BF3 /* DDGroupViewController.xib */, + C4A09CBB1910ABA600B39BF3 /* DDGroupCell.h */, + C4A09CBC1910ABA600B39BF3 /* DDGroupCell.m */, + C4A09C97190FC4CA00B39BF3 /* DDGroupVCModule.h */, + C4A09C98190FC4CA00B39BF3 /* DDGroupVCModule.m */, + ); + name = Group; + sourceTree = ""; + }; + C4A6F1DC18EE4FBA00A6AD61 /* StateMaintenance */ = { + isa = PBXGroup; + children = ( + C4A6F1DD18EE4FD900A6AD61 /* StateMaintenanceManager.h */, + C4A6F1DE18EE4FD900A6AD61 /* StateMaintenanceManager.m */, + C48E395918F4E6C000C610EB /* DDCurrentUserState.h */, + C48E395A18F4E6C000C610EB /* DDCurrentUserState.m */, + C48E399F18F9112800C610EB /* DDClientStateMaintenanceManager.h */, + C48E39A018F9112800C610EB /* DDClientStateMaintenanceManager.m */, + C48E79E418FBB28E00A1FA66 /* DDClientState.h */, + C48E79E518FBB28E00A1FA66 /* DDClientState.m */, + ); + path = StateMaintenance; + sourceTree = ""; + }; + C4A6F1E018EFD5EA00A6AD61 /* LoginModule */ = { + isa = PBXGroup; + children = ( + C4A6F1E118EFD61400A6AD61 /* DDLoginManager.h */, + C4A6F1E218EFD61400A6AD61 /* DDLoginManager.m */, + C4A6F1E418EFD69400A6AD61 /* DDHttpServer.h */, + C4A6F1E518EFD69400A6AD61 /* DDHttpServer.m */, + C4C472FA18EFE5EF00BC4E73 /* DDTcpServer.h */, + C4C472FB18EFE5EF00BC4E73 /* DDTcpServer.m */, + C454AB0C18F914D90040BBF0 /* DDLoginServer.h */, + C454AB0D18F914D90040BBF0 /* DDLoginServer.m */, + C4A6F1EA18EFD6CE00A6AD61 /* DDMsgServer.h */, + C4A6F1EB18EFD6CE00A6AD61 /* DDMsgServer.m */, + C48E399C18F8EA4F00C610EB /* DDTcpClientManager.h */, + C48E399D18F8EA4F00C610EB /* DDTcpClientManager.m */, + ); + name = LoginModule; + sourceTree = ""; + }; + C4AB95A618E16AC7000181AD /* Setting */ = { + isa = PBXGroup; + children = ( + C4AB95A718E16AEA000181AD /* DDSetting.h */, + C4AB95A818E16AEA000181AD /* DDSetting.m */, + C46B2D9B18E435E400FE278B /* DDSetting+OffLineReadMsgManager.h */, + C46B2D9C18E435E400FE278B /* DDSetting+OffLineReadMsgManager.m */, + ); + name = Setting; + sourceTree = ""; + }; + C4C926C3190F3C1D005B3234 /* new resource */ = { + isa = PBXGroup; + children = ( + C427BF5A199E00F800A010AA /* almance.png */, + C427BF5B199E00F800A010AA /* almance@2x.png */, + C427BF5C199E00F800A010AA /* bang.png */, + C427BF5D199E00F800A010AA /* bang@2x.png */, + C4E97646196163670009BE1E /* intranet_selected.png */, + C4E97647196163670009BE1E /* intranet_selected@2x.png */, + C4E9762C196154B60009BE1E /* intranet_back.png */, + C4E9762D196154B60009BE1E /* intranet_back@2x.png */, + C4E9762E196154B60009BE1E /* intranet_forward.png */, + C4E9762F196154B60009BE1E /* intranet_forward@2x.png */, + C4E97630196154B60009BE1E /* intranet_home.png */, + C4E97631196154B60009BE1E /* intranet_home@2x.png */, + C4E97632196154B60009BE1E /* intranet_icon.png */, + C4E97633196154B60009BE1E /* intranet_icon@2x.png */, + C4E97634196154B60009BE1E /* intranet_refresh.png */, + C4E97635196154B60009BE1E /* intranet_refresh@2x.png */, + C4E97636196154B60009BE1E /* Intranet_unselected.png */, + C4E97637196154B60009BE1E /* Intranet_unselected@2x.png */, + C4EBA724192D8E9C00B72723 /* No-File-transfor.png */, + C4EBA725192D8E9C00B72723 /* No-File-transfor@2x.png */, + C42D4EA41924BBF000C7B6F6 /* Recent-cell-background.png */, + C42D4EA51924BBF000C7B6F6 /* Recent-cell-background@2x.png */, + 5EF517EA19238C7B00652421 /* shake-window.png */, + 5EF517EB19238C7B00652421 /* shake-window@2x.png */, + 5EF517E619236EA600652421 /* input-background.png */, + 5EF517E719236EA600652421 /* input-background@2x.png */, + C4FE221B192065CE00FFB520 /* top-session.png */, + C4FE221C192065CE00FFB520 /* top-session@2x.png */, + C47935211918B765009C39AE /* window-titleBar-background.png */, + C47935221918B765009C39AE /* window-titleBar-background@2x.png */, + C479351919188DE4009C39AE /* message-review-double-lastpage.png */, + C479351A19188DE4009C39AE /* message-review-double-lastpage@2x.png */, + C479351B19188DE4009C39AE /* message-review-double-nextpage.png */, + C479351C19188DE4009C39AE /* message-review-double-nextpage@2x.png */, + C479351119188C50009C39AE /* message-review-last-page.png */, + C479351219188C50009C39AE /* message-review-last-page@2x.png */, + C479351319188C50009C39AE /* message-review-nextpage.png */, + C479351419188C50009C39AE /* message-review-nextpage@2x.png */, + C47934ED19175F3E009C39AE /* file-transmit-background.png */, + C47934EE19175F3E009C39AE /* file-transmit-background@2x.png */, + C47934EF19175F3E009C39AE /* file-transmit-cancel.png */, + C47934F019175F3E009C39AE /* file-transmit-cancel@2x.png */, + C47934F119175F3E009C39AE /* file-transmit-look.png */, + C47934F219175F3E009C39AE /* file-transmit-look@2x.png */, + C47934F319175F3E009C39AE /* file-transmit-update.png */, + C47934F419175F3E009C39AE /* file-transmit-update@2x.png */, + C47934E519173B00009C39AE /* group-info-background.png */, + C47934E619173B00009C39AE /* group-info-background@2x.png */, + C47934E719173B00009C39AE /* group-info-line.png */, + C47934E819173B00009C39AE /* group-info-line@2x.png */, + C47934DD19172599009C39AE /* person-info-background.png */, + C47934DE19172599009C39AE /* person-info-background@2x.png */, + C47934DF19172599009C39AE /* person-info-chat.png */, + C47934E019172599009C39AE /* person-info-chat@2x.png */, + C47934B3191656F8009C39AE /* addgroummember-unselected.png */, + C47934B4191656F8009C39AE /* addgroummember-unselected@2x.png */, + C47934B5191656F8009C39AE /* addgroupmember-arrow.png */, + C47934B6191656F8009C39AE /* addgroupmember-arrow@2x.png */, + C47934B7191656F8009C39AE /* addgroupmember-cancel.png */, + C47934B8191656F8009C39AE /* addgroupmember-cancel@2x.png */, + C47934B9191656F8009C39AE /* addgroupmember-cancel2.png */, + C47934BA191656F8009C39AE /* addgroupmember-cancel2@2x.png */, + C47934BB191656F8009C39AE /* addgroupmember-search-background.png */, + C47934BC191656F8009C39AE /* addgroupmember-search-background@2x.png */, + C47934BD191656F8009C39AE /* addgroupmember-selected.png */, + C47934BE191656F8009C39AE /* addgroupmember-selected@2x.png */, + C47934BF191656F8009C39AE /* addgroupmember-sure.png */, + C47934C0191656F8009C39AE /* addgroupmember-sure@2x.png */, + C47934AC191635D3009C39AE /* close.png */, + C47934AD191635D3009C39AE /* close@2x.png */, + C47934A1191612A4009C39AE /* Teamtalk-bottom.png */, + C47934A2191612A4009C39AE /* Teamtalk-bottom@2x.png */, + C47934A3191612A4009C39AE /* TeamTalk-Top.png */, + C47934A4191612A4009C39AE /* TeamTalk-Top@2x.png */, + C4793489191610AF009C39AE /* login-account.png */, + C479348A191610AF009C39AE /* login-account@2x.png */, + C479348B191610AF009C39AE /* login-avatar-background.png */, + C479348C191610AF009C39AE /* login-avatar-background@2x.png */, + C479348D191610AF009C39AE /* login-background.png */, + C479348E191610AF009C39AE /* login-background@2x.png */, + C479348F191610AF009C39AE /* login-input-background.png */, + C4793490191610AF009C39AE /* login-input-background@2x.png */, + C4793491191610AF009C39AE /* login-logining.png */, + C4793492191610AF009C39AE /* login-logining@2x.png */, + C4793493191610AF009C39AE /* login-password.png */, + C4793494191610AF009C39AE /* login-password@2x.png */, + C4A09CDB1910FED700B39BF3 /* emotion.png */, + C4A09CDC1910FED700B39BF3 /* emotion@2x.png */, + C4A09CDD1910FED700B39BF3 /* screen-shot.png */, + C4A09CDE1910FED700B39BF3 /* screen-shot@2x.png */, + C4A09CD31910FB6700B39BF3 /* add-group-member.png */, + C4A09CD41910FB6700B39BF3 /* add-group-member@2x.png */, + C4A09CD51910FB6700B39BF3 /* transport-file.png */, + C4A09CD61910FB6700B39BF3 /* transport-file@2x.png */, + C4A09CC71910EFA800B39BF3 /* state-leave.png */, + C4A09CC81910EFA800B39BF3 /* state-leave@2x.png */, + C4A09CC91910EFA800B39BF3 /* state-offline.png */, + C4A09CCA1910EFA800B39BF3 /* state-offline@2x.png */, + C4A09CCB1910EFA800B39BF3 /* state-online.png */, + C4A09CCC1910EFA800B39BF3 /* state-online@2x.png */, + C4A09C9F19108E7600B39BF3 /* recent-contacts-cell-background.png */, + C4A09CA019108E7600B39BF3 /* recent-contacts-cell-background@2x.png */, + C4A09CA119108E7600B39BF3 /* search-background.png */, + C4A09CA219108E7600B39BF3 /* search-background@2x.png */, + C4A09CA319108E7600B39BF3 /* shield.png */, + C4A09CA419108E7600B39BF3 /* shield@2x.png */, + C4A09CA719108E7600B39BF3 /* unread-count-background.png */, + C4A09CA819108E7600B39BF3 /* unread-count-background@2x.png */, + C4C926DC190F4778005B3234 /* state-background.png */, + C4C926DD190F4778005B3234 /* state-background@2x.png */, + C4C926C4190F3C1D005B3234 /* background.png */, + C4C926C5190F3C1D005B3234 /* background@2x.png */, + C4C926C6190F3C1D005B3234 /* setting.png */, + C4C926C7190F3C1D005B3234 /* setting@2x.png */, + C4C926CA190F3C1D005B3234 /* left-bar-avatar.png */, + C4C926CB190F3C1D005B3234 /* left-bar-avatar@2x.png */, + C4C926CC190F3C1D005B3234 /* 形状-477.png */, + C4C926CD190F3C1D005B3234 /* 形状-477@2x.png */, + C4C926E0190F4F28005B3234 /* group-selected.png */, + C4C926E1190F4F28005B3234 /* group-selected@2x.png */, + C4C926E2190F4F28005B3234 /* group-unselected.png */, + C4C926E3190F4F28005B3234 /* group-unselected@2x.png */, + C4C926E4190F4F28005B3234 /* left-bar-selected-background.png */, + C4C926E5190F4F28005B3234 /* left-bar-selected-background@2x.png */, + C4C926E6190F4F28005B3234 /* recent-chat-selected.png */, + C4C926E7190F4F28005B3234 /* recent-chat-selected@2x.png */, + C4C926E8190F4F28005B3234 /* recent-chat-unselected.png */, + C4C926E9190F4F28005B3234 /* recent-chat-unselected@2x.png */, + ); + name = "new resource"; + path = "resource/new resource"; + sourceTree = ""; + }; + C4C926D8190F424A005B3234 /* customView */ = { + isa = PBXGroup; + children = ( + C4C926D9190F4274005B3234 /* DDGridBackgroundView.h */, + C4C926DA190F4274005B3234 /* DDGridBackgroundView.m */, + C4A09CC41910EA2300B39BF3 /* DDAppBackgroundColorView.h */, + C4A09CC51910EA2400B39BF3 /* DDAppBackgroundColorView.m */, + C47934A919163477009C39AE /* DDCustomWindow.h */, + C47934AA19163477009C39AE /* DDCustomWindow.m */, + C46C810D197500FA00157856 /* DDCornerRadiusTextField.h */, + C46C810E197500FA00157856 /* DDCornerRadiusTextField.m */, + ); + name = customView; + path = ColorfulView; + sourceTree = ""; + }; + C4D2EFA418B322B9000F0B12 /* Constant */ = { + isa = PBXGroup; + children = ( + C4D2EFA518B322D6000F0B12 /* CONSTANT.h */, + ); + name = Constant; + path = utilities/Constant; + sourceTree = ""; + }; + C4F7E5EC1907D203006E31F3 /* SundriesCenter */ = { + isa = PBXGroup; + children = ( + C4F7E5ED1907D24E006E31F3 /* DDSundriesCenter.h */, + C4F7E5EE1907D24E006E31F3 /* DDSundriesCenter.m */, + ); + name = SundriesCenter; + sourceTree = ""; + }; + C4F7E5F31908D7E0006E31F3 /* API */ = { + isa = PBXGroup; + children = ( + C4FF47571A83578200B21A0D /* DataOutputStream+Addition.h */, + C4FF47581A83578200B21A0D /* DataOutputStream+Addition.m */, + C4F7E5F51908DA52006E31F3 /* DDAPIScheduleProtocol.h */, + C40F95211919D501005CACBF /* DDAPIUnrequestScheduleProtocol.h */, + C4FA6BD41908E0640097849B /* DDAPISchedule.h */, + C4FA6BD51908E0640097849B /* DDAPISchedule.m */, + C4FA6BD71908F5BD0097849B /* DDSuperAPI.h */, + C4FA6BD81908F5BD0097849B /* DDSuperAPI.m */, + C40F9542191A563D005CACBF /* DDSeqNoManager.h */, + C40F9543191A563E005CACBF /* DDSeqNoManager.m */, + C40F95231919D682005CACBF /* DDUnrequestSuperAPI.h */, + C40F95241919D682005CACBF /* DDUnrequestSuperAPI.m */, + C40F95221919D62D005CACBF /* UnrequestAPI */, + C479352B1918E7DB009C39AE /* APIGroup */, + ); + path = API; + sourceTree = ""; + }; + C4FE221719205BF700FFB520 /* Session */ = { + isa = PBXGroup; + children = ( + C4FE221819205C1000FFB520 /* DDRemoveSessionAPI.h */, + C4FE221919205C1000FFB520 /* DDRemoveSessionAPI.m */, + ); + name = Session; + sourceTree = ""; + }; + C4FF474F1A823E5800B21A0D /* Speex */ = { + isa = PBXGroup; + children = ( + C4FF47501A823E5800B21A0D /* speexdec */, + C4FF47511A823E5800B21A0D /* speexenc */, + ); + name = Speex; + path = Libraries/Speex; + sourceTree = ""; + }; + D2DB4085FFF0FDA637621A14 /* Pods */ = { + isa = PBXGroup; + children = ( + 74019794B7AD12641993FBE9 /* Pods.debug.xcconfig */, + 535EC6602DDC418112EEFEF8 /* Pods.release.xcconfig */, + ); + name = Pods; + sourceTree = ""; + }; +/* End PBXGroup section */ + +/* Begin PBXNativeTarget section */ + 5738472E1820CDA000443653 /* TeamTalk */ = { + isa = PBXNativeTarget; + buildConfigurationList = 573847601820CDA000443653 /* Build configuration list for PBXNativeTarget "TeamTalk" */; + buildPhases = ( + 5B4EB9AF98993B8F2DA57993 /* Check Pods Manifest.lock */, + 5738472B1820CDA000443653 /* Sources */, + 5738472C1820CDA000443653 /* Frameworks */, + 5738472D1820CDA000443653 /* Resources */, + 5700BF0618A8A4880060092F /* Copy Files */, + 4339E9449C259D1050E09245 /* Copy Pods Resources */, + ); + buildRules = ( + C407F20B19604CFD00ED6ED8 /* PBXBuildRule */, + ); + dependencies = ( + ); + name = TeamTalk; + productName = TeamTalk; + productReference = 5738472F1820CDA000443653 /* TeamTalk.app */; + productType = "com.apple.product-type.application"; + }; +/* End PBXNativeTarget section */ + +/* Begin PBXProject section */ + 573847271820CDA000443653 /* Project object */ = { + isa = PBXProject; + attributes = { + CLASSPREFIX = DD; + LastUpgradeCheck = 0610; + ORGANIZATIONNAME = mogujie; + TargetAttributes = { + 5738472E1820CDA000443653 = { + DevelopmentTeam = X8LV58VH9V; + SystemCapabilities = { + com.apple.Sandbox = { + enabled = 0; + }; + }; + }; + }; + }; + buildConfigurationList = 5738472A1820CDA000443653 /* Build configuration list for PBXProject "TeamTalk" */; + compatibilityVersion = "Xcode 3.2"; + developmentRegion = English; + hasScannedForEncodings = 0; + knownRegions = ( + en, + Base, + ); + mainGroup = 573847261820CDA000443653; + productRefGroup = 573847301820CDA000443653 /* Products */; + projectDirPath = ""; + projectRoot = ""; + targets = ( + 5738472E1820CDA000443653 /* TeamTalk */, + ); + }; +/* End PBXProject section */ + +/* Begin PBXResourcesBuildPhase section */ + 5738472D1820CDA000443653 /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 81DE59C51A833B0800040078 /* big.cur in Resources */, + 8195ED741A7651E700DA5CA0 /* iscroll-probe.js in Resources */, + 6DD31A9C188E592200ED5FE8 /* 63.gif in Resources */, + 6DD31A75188E592200ED5FE8 /* 24.gif in Resources */, + 6DD31AB8188E592200ED5FE8 /* 91.gif in Resources */, + 572A87C318B5ED96003E3FC8 /* icon_addcontacts_highlight_theme_gray.png in Resources */, + C47934CD191656F8009C39AE /* addgroupmember-sure.png in Resources */, + C4C926EB190F4F28005B3234 /* group-selected@2x.png in Resources */, + 6DD31B0A188E592200ED5FE8 /* 173.gif in Resources */, + 6DD31A71188E592200ED5FE8 /* 20.gif in Resources */, + 6DD31A68188E592200ED5FE8 /* 11.gif in Resources */, + 6DD31B2C188E592200ED5FE8 /* 207.gif in Resources */, + 572A87C118B5ED96003E3FC8 /* icon_addcontacts_disable_theme_gray.png in Resources */, + C4FF47431A81AF3700B21A0D /* msgfail.png in Resources */, + 576CE6CF18D1B68B00DEBCD5 /* icon_refresh_arrow_down.png in Resources */, + 576CE67C18D0764B00DEBCD5 /* icon_send_file_gray@2x.png in Resources */, + C4C926D6190F3C1D005B3234 /* 形状-477.png in Resources */, + 8195ED7F1A7651E700DA5CA0 /* scrollbar.css in Resources */, + 57D5D176184D770100852738 /* icon_smile_highlight@2x.png in Resources */, + 6DD31A7E188E592200ED5FE8 /* 33.gif in Resources */, + 57EFFAE01856C639006D8DE1 /* icon_unread_red_wide@2x.png in Resources */, + 81ECFE401A8230E700445985 /* gifffer.js in Resources */, + 6DD31ABE188E592200ED5FE8 /* 97.gif in Resources */, + C492F41718C30FF5005A3AC9 /* icon_check_empty.png in Resources */, + 5709F96C184871A70096D176 /* icon_organization_click_theme_gray@2x.png in Resources */, + 8195ED6A1A7651E700DA5CA0 /* blb.png in Resources */, + C4A09CAE19108E7600B39BF3 /* shield@2x.png in Resources */, + 6DD31A78188E592200ED5FE8 /* 27.gif in Resources */, + 8195ED771A7651E700DA5CA0 /* jquery.scrollz.css in Resources */, + C4A09CE01910FED700B39BF3 /* emotion@2x.png in Resources */, + 6DD31A86188E592200ED5FE8 /* 41.gif in Resources */, + 5709F95B18486DDA0096D176 /* seperator_right@2x.png in Resources */, + C485914018C73FD800DD30DD /* icon_fav@2x.png in Resources */, + C47934E219172599009C39AE /* person-info-background@2x.png in Resources */, + 6D70EA371869ADAE00402CF5 /* bubble_right.png in Resources */, + 6DD31AD5188E592200ED5FE8 /* 120.gif in Resources */, + 6DD31AEE188E592200ED5FE8 /* 145.gif in Resources */, + 6DD31B33188E592200ED5FE8 /* 214.gif in Resources */, + 5709F95918486DDA0096D176 /* seperator_left@2x.png in Resources */, + C4C926F0190F4F28005B3234 /* recent-chat-selected.png in Resources */, + 5741BC341862E540003F2667 /* aio_recentsession_unreadmsg_selected.png in Resources */, + 6DD31A7C188E592200ED5FE8 /* 31.gif in Resources */, + 6DD31A9E188E592200ED5FE8 /* 65.gif in Resources */, + C4E97641196154B60009BE1E /* intranet_icon@2x.png in Resources */, + C4A09CCE1910EFA800B39BF3 /* state-leave@2x.png in Resources */, + 5741BC321862E540003F2667 /* aio_recentsession_unreadmsg_selected_wide.png in Resources */, + 5714A0041845D4D000DDBA25 /* ScreenCapture_toolbar_ok.png in Resources */, + 5709F96A184871A70096D176 /* icon_conversation_theme_gray@2x.png in Resources */, + 6DD31B15188E592200ED5FE8 /* 184.gif in Resources */, + 6DD31B14188E592200ED5FE8 /* 183.gif in Resources */, + 6DD31AF8188E592200ED5FE8 /* 155.gif in Resources */, + 8195ED711A7651E700DA5CA0 /* hook-spinner.gif in Resources */, + C4AB954E18DAE70F000181AD /* shield_red@2x.png in Resources */, + C47934A0191610AF009C39AE /* login-password@2x.png in Resources */, + 57124E63187E743A006D2DCA /* panel_bg_theme_gray@2x.png in Resources */, + 6DD31A76188E592200ED5FE8 /* 25.gif in Resources */, + 6DD31B2E188E592200ED5FE8 /* 209.gif in Resources */, + 6DD31AC4188E592200ED5FE8 /* 103.gif in Resources */, + 57D5D172184D770100852738 /* icon_screenshot_highlight@2x.png in Resources */, + C47934C8191656F8009C39AE /* addgroupmember-cancel2@2x.png in Resources */, + 5EF517D41923070400652421 /* 229.gif in Resources */, + 572A87FD18B75B04003E3FC8 /* icon_user_h28@2x.png in Resources */, + 5772C9CB18D00CBD008FE09F /* icon_close.png in Resources */, + 6DD31A90188E592200ED5FE8 /* 51.gif in Resources */, + 6DD31B27188E592200ED5FE8 /* 202.gif in Resources */, + C479349D191610AF009C39AE /* login-logining.png in Resources */, + C4C926F2190F4F28005B3234 /* recent-chat-unselected.png in Resources */, + 5EF517D71923070400652421 /* 232.gif in Resources */, + 6DD31AAF188E592200ED5FE8 /* 82.gif in Resources */, + C4C926D0190F3C1D005B3234 /* setting.png in Resources */, + 8195ED791A7651E700DA5CA0 /* main.css in Resources */, + 6DD31B17188E592200ED5FE8 /* 186.gif in Resources */, + C4E9763B196154B60009BE1E /* intranet_back@2x.png in Resources */, + 6DD31A60188E592200ED5FE8 /* 3.gif in Resources */, + 6DD31AD9188E592200ED5FE8 /* 124.gif in Resources */, + 6DCB3397189629F200FC86A3 /* filetransfer_search@2x.png in Resources */, + 6DD31B06188E592200ED5FE8 /* 169.gif in Resources */, + 6DD31AA3188E592200ED5FE8 /* 70.gif in Resources */, + 8195ED781A7651E700DA5CA0 /* jquery.scrollz.min.js in Resources */, + 6DD31A77188E592200ED5FE8 /* 26.gif in Resources */, + 6DD31A9F188E592200ED5FE8 /* 66.gif in Resources */, + 6DD31ADB188E592200ED5FE8 /* 126.gif in Resources */, + 6DD31B0C188E592200ED5FE8 /* 175.gif in Resources */, + 6DD31A6E188E592200ED5FE8 /* 17.gif in Resources */, + 6DD31AEB188E592200ED5FE8 /* 142.gif in Resources */, + 6DD31AB1188E592200ED5FE8 /* 84.gif in Resources */, + 57D5D15F184C23AD00852738 /* DDChattingView.xib in Resources */, + 57B2A60A18273BD2000A16FD /* duoduo.png in Resources */, + 6DD31ABF188E592200ED5FE8 /* 98.gif in Resources */, + 6D70EA381869ADAE00402CF5 /* bubble_right@2x.png in Resources */, + C4EBA727192D8E9C00B72723 /* No-File-transfor@2x.png in Resources */, + 6DD31ABB188E592200ED5FE8 /* 94.gif in Resources */, + 5EF517D81923070400652421 /* 233.gif in Resources */, + 572A87FC18B75B04003E3FC8 /* icon_user_h28.png in Resources */, + 5EF517D11923070400652421 /* 226.gif in Resources */, + 572A87C518B5ED96003E3FC8 /* icon_addcontacts_theme_gray.png in Resources */, + C47934CB191656F8009C39AE /* addgroupmember-selected.png in Resources */, + C4A09C9B190FC7B000B39BF3 /* DDRecentContactsViewController.xib in Resources */, + 6DD31B21188E592200ED5FE8 /* 196.gif in Resources */, + 6D78A57F18D828450069A29B /* ScreenCapture_toolbar_ellipse@2x.png in Resources */, + 6DD31A82188E592200ED5FE8 /* 37.gif in Resources */, + 6D78A58018D828450069A29B /* ScreenCapture_toolbar_rect.png in Resources */, + 5709F96B184871A70096D176 /* icon_organization_click_theme_gray.png in Resources */, + 57D5D174184D770100852738 /* icon_screenshot@2x.png in Resources */, + 6DD31B0E188E592200ED5FE8 /* 177.gif in Resources */, + 6DD31A63188E592200ED5FE8 /* 6.gif in Resources */, + 57AF72BA18683E4000C06257 /* tab_bg.png in Resources */, + C4C926F1190F4F28005B3234 /* recent-chat-selected@2x.png in Resources */, + C4A09CA919108E7600B39BF3 /* recent-contacts-cell-background.png in Resources */, + C4C926CF190F3C1D005B3234 /* background@2x.png in Resources */, + C4A09CCD1910EFA800B39BF3 /* state-leave.png in Resources */, + 6DD31B12188E592200ED5FE8 /* 181.gif in Resources */, + 6DD31AB6188E592200ED5FE8 /* 89.gif in Resources */, + 6DD31AD8188E592200ED5FE8 /* 123.gif in Resources */, + 572A87E718B74E9F003E3FC8 /* DDAddChatGroupWindowController.xib in Resources */, + 6DD31AA6188E592200ED5FE8 /* 73.gif in Resources */, + 6DD31A6A188E592200ED5FE8 /* 13.gif in Resources */, + C4D2EFF518B4B29A000F0B12 /* DDSearchResultCell.xib in Resources */, + C47934C2191656F8009C39AE /* addgroummember-unselected@2x.png in Resources */, + 5738473D1820CDA000443653 /* InfoPlist.strings in Resources */, + 6DD31AB5188E592200ED5FE8 /* 88.gif in Resources */, + 6DD31AE3188E592200ED5FE8 /* 134.gif in Resources */, + C4C926CE190F3C1D005B3234 /* background.png in Resources */, + 6DD31AC1188E592200ED5FE8 /* 100.gif in Resources */, + C4A09CB219108E7600B39BF3 /* unread-count-background@2x.png in Resources */, + 5EF517CE1923070400652421 /* 223.gif in Resources */, + 6DD31B05188E592200ED5FE8 /* 168.gif in Resources */, + 8195ED751A7651E700DA5CA0 /* iscroll.js in Resources */, + 571FD9B71868190300F7476B /* tabbar_bg_theme_gray@2x.png in Resources */, + 5EF517DA1923070400652421 /* 235.gif in Resources */, + 57285D4118AB63BE00E90EC2 /* preference_divider@2x.png in Resources */, + 6DD31B2F188E592200ED5FE8 /* 210.gif in Resources */, + 576CE67E18D0764B00DEBCD5 /* icon_send_file_highlight@2x.png in Resources */, + C47934CA191656F8009C39AE /* addgroupmember-search-background@2x.png in Resources */, + 572A87FE18B75B04003E3FC8 /* icon_user_offline_h28.png in Resources */, + 8195ED721A7651E700DA5CA0 /* hook.css in Resources */, + C47934E319172599009C39AE /* person-info-chat.png in Resources */, + 6DCB3394189629F200FC86A3 /* filetransfer_refuse.png in Resources */, + 5772C9C818D00B9B008FE09F /* pull-to-refresh-arrow.png in Resources */, + 6DD31B25188E592200ED5FE8 /* 200.gif in Resources */, + 6DCB338F189629F200FC86A3 /* filetransfer_avatar_send@2x.png in Resources */, + 6DD31A5F188E592200ED5FE8 /* 2.gif in Resources */, + C47934FC19175F3E009C39AE /* file-transmit-update@2x.png in Resources */, + C47934A8191612A4009C39AE /* TeamTalk-Top@2x.png in Resources */, + 6DCB3392189629F200FC86A3 /* filetransfer_receiver.png in Resources */, + C4C1CB89197FCB4700386AB0 /* dd_modisy_avatar.png in Resources */, + C4C926F3190F4F28005B3234 /* recent-chat-unselected@2x.png in Resources */, + C46B2D9818E3D8F000FE278B /* icon_statusbar_blue.png in Resources */, + 572A87C618B5ED96003E3FC8 /* icon_addcontacts_theme_gray@2x.png in Resources */, + 5EF517EC19238C7B00652421 /* shake-window.png in Resources */, + 8195ED6E1A7651E700DA5CA0 /* highlight.default.css in Resources */, + C4793498191610AF009C39AE /* login-avatar-background@2x.png in Resources */, + C4793497191610AF009C39AE /* login-avatar-background.png in Resources */, + 81ECFE3D1A822E5500445985 /* voice_me.gif in Resources */, + 5709F95218486ABB0096D176 /* toolbar_bg_theme_gray.png in Resources */, + 6DD31A67188E592200ED5FE8 /* 10.gif in Resources */, + C479349F191610AF009C39AE /* login-password.png in Resources */, + 8195ED761A7651E700DA5CA0 /* jquery-2.1.1.min.js in Resources */, + 5EF517D01923070400652421 /* 225.gif in Resources */, + 6DD31AE7188E592200ED5FE8 /* 138.gif in Resources */, + C47935241918B765009C39AE /* window-titleBar-background@2x.png in Resources */, + 57AF228C1820F31600758483 /* LoginSelect.xib in Resources */, + C47934AF191635D3009C39AE /* close@2x.png in Resources */, + 6DD31B0B188E592200ED5FE8 /* 174.gif in Resources */, + 6DCB3396189629F200FC86A3 /* filetransfer_search.png in Resources */, + C43802D718C48650002555BB /* DDGroupDataWindow.xib in Resources */, + 6DD31A99188E592200ED5FE8 /* 60.gif in Resources */, + C4E9763F196154B60009BE1E /* intranet_home@2x.png in Resources */, + 6DD31B1B188E592200ED5FE8 /* 190.gif in Resources */, + C4793495191610AF009C39AE /* login-account.png in Resources */, + 578D5EA1187EC0C600568EE6 /* icon_offline@2x.png in Resources */, + 6DD31AFD188E592200ED5FE8 /* 160.gif in Resources */, + 6DD31A9B188E592200ED5FE8 /* 62.gif in Resources */, + 8195ED7D1A7651E700DA5CA0 /* msg.js in Resources */, + 5EF517DE1923070400652421 /* 239.gif in Resources */, + 6D2A848118B1D9140004032B /* icon_go.png in Resources */, + C492F41C18C31092005A3AC9 /* icon_check_filled@2x.png in Resources */, + 6DD31AB3188E592200ED5FE8 /* 86.gif in Resources */, + C47934FA19175F3E009C39AE /* file-transmit-look@2x.png in Resources */, + C479351E19188DE4009C39AE /* message-review-double-lastpage@2x.png in Resources */, + 572A87C218B5ED96003E3FC8 /* icon_addcontacts_disable_theme_gray@2x.png in Resources */, + 6DD31B08188E592200ED5FE8 /* 171.gif in Resources */, + 576CE6D118D1B68B00DEBCD5 /* icon_refresh_arrow.png in Resources */, + C487386B18C8093D00C51541 /* lady_placeholder.png in Resources */, + 6DD31A72188E592200ED5FE8 /* 21.gif in Resources */, + 5709F967184871A70096D176 /* icon_conversation_highlight_theme_gray.png in Resources */, + 5EF517D91923070400652421 /* 234.gif in Resources */, + 6DD31AF6188E592200ED5FE8 /* 153.gif in Resources */, + 6DD31AAD188E592200ED5FE8 /* 80.gif in Resources */, + C4A09CAA19108E7600B39BF3 /* recent-contacts-cell-background@2x.png in Resources */, + C47934FB19175F3E009C39AE /* file-transmit-update.png in Resources */, + C46B2D9A18E3D95F00FE278B /* icon_statusbar_blue@2x.png in Resources */, + 6DD31A5D188E592200ED5FE8 /* 0.gif in Resources */, + 6DD31ACD188E592200ED5FE8 /* 112.gif in Resources */, + 6DD31AF1188E592200ED5FE8 /* 148.gif in Resources */, + 57EFFADF1856C639006D8DE1 /* icon_unread_red_wide.png in Resources */, + 5EF517CF1923070400652421 /* 224.gif in Resources */, + 6DD31B29188E592200ED5FE8 /* 204.gif in Resources */, + C4FE221D192065CE00FFB520 /* top-session.png in Resources */, + 18906D3B18555843004B874E /* message.mp3 in Resources */, + 6DD31B2B188E592200ED5FE8 /* 206.gif in Resources */, + C4AB954D18DAE70F000181AD /* shield_red.png in Resources */, + 6DD31AA1188E592200ED5FE8 /* 68.gif in Resources */, + C479351819188C50009C39AE /* message-review-nextpage@2x.png in Resources */, + 6DD31AAE188E592200ED5FE8 /* 81.gif in Resources */, + 6DD31A8C188E592200ED5FE8 /* 47.gif in Resources */, + 576CE67B18D0764B00DEBCD5 /* icon_send_file_gray.png in Resources */, + 6DD31B26188E592200ED5FE8 /* 201.gif in Resources */, + 5741BC391862E540003F2667 /* aio_recentsession_unreadmsg@2x.png in Resources */, + C479351619188C50009C39AE /* message-review-last-page@2x.png in Resources */, + 6DD31B36188E592200ED5FE8 /* 217.gif in Resources */, + 6DD31ACC188E592200ED5FE8 /* 111.gif in Resources */, + C4FF47531A823E5800B21A0D /* speexenc in Resources */, + 6DCB338E189629F200FC86A3 /* filetransfer_avatar_send.png in Resources */, + 6DD31A65188E592200ED5FE8 /* 8.gif in Resources */, + 8195ED7A1A7651E700DA5CA0 /* message.html in Resources */, + C4A09CBA1910AAC200B39BF3 /* DDGroupViewController.xib in Resources */, + 6DD31A8E188E592200ED5FE8 /* 49.gif in Resources */, + 6DD31AE6188E592200ED5FE8 /* 137.gif in Resources */, + 8195ED801A7651E700DA5CA0 /* solarized_dark.css in Resources */, + 571FD9B61868190300F7476B /* tabbar_bg_theme_gray.png in Resources */, + 6DD31AA5188E592200ED5FE8 /* 72.gif in Resources */, + 6DD31A7B188E592200ED5FE8 /* 30.gif in Resources */, + 5738474B1820CDA000443653 /* Images.xcassets in Resources */, + 5741BC331862E540003F2667 /* aio_recentsession_unreadmsg_selected_wide@2x.png in Resources */, + 6DD31AFE188E592200ED5FE8 /* 161.gif in Resources */, + C4C926EF190F4F28005B3234 /* left-bar-selected-background@2x.png in Resources */, + 6DD31A6C188E592200ED5FE8 /* 15.gif in Resources */, + C47934C1191656F8009C39AE /* addgroummember-unselected.png in Resources */, + 6DD31AA8188E592200ED5FE8 /* 75.gif in Resources */, + 8195ED7B1A7651E700DA5CA0 /* moment-with-locales.min.js in Resources */, + 6DD31AE1188E592200ED5FE8 /* 132.gif in Resources */, + 6DD31A79188E592200ED5FE8 /* 28.gif in Resources */, + C4C926D7190F3C1D005B3234 /* 形状-477@2x.png in Resources */, + 6DD31AF3188E592200ED5FE8 /* 150.gif in Resources */, + 6DD31A62188E592200ED5FE8 /* 5.gif in Resources */, + 6DD31ACF188E592200ED5FE8 /* 114.gif in Resources */, + C47935231918B765009C39AE /* window-titleBar-background.png in Resources */, + C479349C191610AF009C39AE /* login-input-background@2x.png in Resources */, + 6DD31AE2188E592200ED5FE8 /* 133.gif in Resources */, + 5714A0031845D4D000DDBA25 /* ScreenCapture_toolbar_cancel.png in Resources */, + C47934CE191656F8009C39AE /* addgroupmember-sure@2x.png in Resources */, + C479351D19188DE4009C39AE /* message-review-double-lastpage.png in Resources */, + C487387218C814D700C51541 /* group_placeholder@2x.png in Resources */, + 6DD31ADC188E592200ED5FE8 /* 127.gif in Resources */, + 5700BF0C18A8A5AD0060092F /* dsa_pub.pem in Resources */, + 5709F95A18486DDA0096D176 /* seperator_right.png in Resources */, + 6DD31AF9188E592200ED5FE8 /* 156.gif in Resources */, + 57285D3D18AB60F100E90EC2 /* icon_folder@2x.png in Resources */, + C41AB12D195B0487002AE7C7 /* DDIntranetContentViewController.xib in Resources */, + C4C926DF190F4778005B3234 /* state-background@2x.png in Resources */, + C4A09CD11910EFA800B39BF3 /* state-online.png in Resources */, + C4E97642196154B60009BE1E /* intranet_refresh.png in Resources */, + 6DD31AC2188E592200ED5FE8 /* 101.gif in Resources */, + 6DD31B28188E592200ED5FE8 /* 203.gif in Resources */, + 5741BC371862E540003F2667 /* aio_recentsession_unreadmsg_wide@2x.png in Resources */, + C4FF47521A823E5800B21A0D /* speexdec in Resources */, + C4C926EC190F4F28005B3234 /* group-unselected.png in Resources */, + 6DD31AF0188E592200ED5FE8 /* 147.gif in Resources */, + C47934A5191612A4009C39AE /* Teamtalk-bottom.png in Resources */, + 6DD31AB4188E592200ED5FE8 /* 87.gif in Resources */, + 6DD31B39188E592200ED5FE8 /* 220.gif in Resources */, + 6DD31B2A188E592200ED5FE8 /* 205.gif in Resources */, + C4A09CB119108E7600B39BF3 /* unread-count-background.png in Resources */, + 6DD31AC5188E592200ED5FE8 /* 104.gif in Resources */, + 6DD31B13188E592200ED5FE8 /* 182.gif in Resources */, + C47934A6191612A4009C39AE /* Teamtalk-bottom@2x.png in Resources */, + 6DD31AA0188E592200ED5FE8 /* 67.gif in Resources */, + 6DD31A8A188E592200ED5FE8 /* 45.gif in Resources */, + 6DD31ACB188E592200ED5FE8 /* 110.gif in Resources */, + C42D4EA71924BBF000C7B6F6 /* Recent-cell-background@2x.png in Resources */, + C4A09CD91910FB6700B39BF3 /* transport-file.png in Resources */, + C479351519188C50009C39AE /* message-review-last-page.png in Resources */, + 57C2D2EC1A74D3C500981552 /* DDAtUserListViewController.xib in Resources */, + 5EF517DC1923070400652421 /* 237.gif in Resources */, + C41AB127195AACE8002AE7C7 /* DDIntranentViewController.xib in Resources */, + 8195ED6D1A7651E700DA5CA0 /* brwb.png in Resources */, + 6DD31ABC188E592200ED5FE8 /* 95.gif in Resources */, + C47934DC191724D5009C39AE /* DDUserInfoPanel.xib in Resources */, + 57EFFB2818570324006D8DE1 /* icon_image_normal.png in Resources */, + 6DD31A9D188E592200ED5FE8 /* 64.gif in Resources */, + 6DD31A7F188E592200ED5FE8 /* 34.gif in Resources */, + C4C1CB88197FCB4600386AB0 /* dd_modisy_avatar@2x.png in Resources */, + 6DD31AFB188E592200ED5FE8 /* 158.gif in Resources */, + 8195ED811A7651E700DA5CA0 /* solarized_light.css in Resources */, + 6DD31A8F188E592200ED5FE8 /* 50.gif in Resources */, + 6DD31AF2188E592200ED5FE8 /* 149.gif in Resources */, + C4AB954C18DAE70F000181AD /* shield_gray@2x.png in Resources */, + 6DD31B0F188E592200ED5FE8 /* 178.gif in Resources */, + C479351719188C50009C39AE /* message-review-nextpage.png in Resources */, + 6DD31AC9188E592200ED5FE8 /* 108.gif in Resources */, + C47934C3191656F8009C39AE /* addgroupmember-arrow.png in Resources */, + 6DD31AD7188E592200ED5FE8 /* 122.gif in Resources */, + 8195ED821A7651E700DA5CA0 /* template.js in Resources */, + 576CE6D218D1B68B00DEBCD5 /* icon_refresh_arrow@2x.png in Resources */, + 6DD31A83188E592200ED5FE8 /* 38.gif in Resources */, + 6DD31A6F188E592200ED5FE8 /* 18.gif in Resources */, + 577C168E184749A1009718D7 /* icon_user_h51@2x.png in Resources */, + 6DD31B31188E592200ED5FE8 /* 212.gif in Resources */, + 6DD31A6D188E592200ED5FE8 /* 16.gif in Resources */, + C479351F19188DE4009C39AE /* message-review-double-nextpage.png in Resources */, + 6DD31AAA188E592200ED5FE8 /* 77.gif in Resources */, + 6DD31ACE188E592200ED5FE8 /* 113.gif in Resources */, + 6DD31AD4188E592200ED5FE8 /* 119.gif in Resources */, + 81ECFE3E1A822E5500445985 /* voice_other.gif in Resources */, + 6DD31B30188E592200ED5FE8 /* 211.gif in Resources */, + 576CE67D18D0764B00DEBCD5 /* icon_send_file_highlight.png in Resources */, + 8195ED731A7651E700DA5CA0 /* hook.min.js in Resources */, + C4C926EA190F4F28005B3234 /* group-selected.png in Resources */, + 6DD31B0D188E592200ED5FE8 /* 176.gif in Resources */, + 6DD31AB0188E592200ED5FE8 /* 83.gif in Resources */, + C42D4EA61924BBF000C7B6F6 /* Recent-cell-background.png in Resources */, + 6DD31A84188E592200ED5FE8 /* 39.gif in Resources */, + C4FE221E192065CE00FFB520 /* top-session@2x.png in Resources */, + 577C168618474649009718D7 /* icon_online@2x.png in Resources */, + 5EF517DF1923070400652421 /* 240.gif in Resources */, + 6DD31B02188E592200ED5FE8 /* 165.gif in Resources */, + 6DCB3391189629F200FC86A3 /* filetransfer_close@2x.png in Resources */, + 57124E62187E743A006D2DCA /* panel_bg_theme_gray.png in Resources */, + C427BF5E199E00F800A010AA /* almance.png in Resources */, + 57285D4018AB63BE00E90EC2 /* preference_divider.png in Resources */, + 6DD31B09188E592200ED5FE8 /* 172.gif in Resources */, + C4A09CDF1910FED700B39BF3 /* emotion.png in Resources */, + 6DD31B32188E592200ED5FE8 /* 213.gif in Resources */, + C47934EC19173B00009C39AE /* group-info-line@2x.png in Resources */, + C4E97640196154B60009BE1E /* intranet_icon.png in Resources */, + C47934F919175F3E009C39AE /* file-transmit-look.png in Resources */, + 6D8B6AE418C462EE0081DAA2 /* filetransfer_offline.png in Resources */, + 572A87F618B75B04003E3FC8 /* icon_user_away_h28.png in Resources */, + 6DD31B03188E592200ED5FE8 /* 166.gif in Resources */, + 6DD31B20188E592200ED5FE8 /* 195.gif in Resources */, + 6DD31B2D188E592200ED5FE8 /* 208.gif in Resources */, + 6DD31A85188E592200ED5FE8 /* 40.gif in Resources */, + C47934F619175F3E009C39AE /* file-transmit-background@2x.png in Resources */, + 5772C9C918D00B9B008FE09F /* release-to-refresh.png in Resources */, + 57EFFAE11856C639006D8DE1 /* icon_unread_red.png in Resources */, + 6DCB3395189629F200FC86A3 /* filetransfer_refuse@2x.png in Resources */, + 5709F969184871A70096D176 /* icon_conversation_theme_gray.png in Resources */, + C4A09CD81910FB6700B39BF3 /* add-group-member@2x.png in Resources */, + 6DD31AA9188E592200ED5FE8 /* 76.gif in Resources */, + C4A09CD71910FB6700B39BF3 /* add-group-member.png in Resources */, + 578D5EA4187EC0E600568EE6 /* icon_away.png in Resources */, + 5741BC381862E540003F2667 /* aio_recentsession_unreadmsg.png in Resources */, + 5EF517D21923070400652421 /* 227.gif in Resources */, + 6D78A57E18D828450069A29B /* ScreenCapture_toolbar_ellipse.png in Resources */, + 6DD31ADA188E592200ED5FE8 /* 125.gif in Resources */, + 6DD31A91188E592200ED5FE8 /* 52.gif in Resources */, + 5EF517E819236EA600652421 /* input-background.png in Resources */, + 6D2A848218B1D9140004032B /* icon_go@2x.png in Resources */, + C4A09CD21910EFA800B39BF3 /* state-online@2x.png in Resources */, + 5709F95818486DDA0096D176 /* seperator_left.png in Resources */, + 6DD31ADE188E592200ED5FE8 /* 129.gif in Resources */, + C48E79EB18FE1FAE00A1FA66 /* message.wav in Resources */, + 576CE6D018D1B68B00DEBCD5 /* icon_refresh_arrow_down@2x.png in Resources */, + 6DD31B34188E592200ED5FE8 /* 215.gif in Resources */, + 57285D3C18AB60F100E90EC2 /* icon_folder.png in Resources */, + 6DD31B1A188E592200ED5FE8 /* 189.gif in Resources */, + C47934C6191656F8009C39AE /* addgroupmember-cancel@2x.png in Resources */, + C47934AE191635D3009C39AE /* close.png in Resources */, + 5741BC351862E540003F2667 /* aio_recentsession_unreadmsg_selected@2x.png in Resources */, + C47934CC191656F8009C39AE /* addgroupmember-selected@2x.png in Resources */, + C4C926DE190F4778005B3234 /* state-background.png in Resources */, + C4A09CDA1910FB6700B39BF3 /* transport-file@2x.png in Resources */, + 6DD31B18188E592200ED5FE8 /* 187.gif in Resources */, + 578D5EA0187EC0C600568EE6 /* icon_offline.png in Resources */, + 8195ED701A7651E700DA5CA0 /* highlight.pack.js in Resources */, + 6DD31A95188E592200ED5FE8 /* 56.gif in Resources */, + 57E18EAE186A857400D00D63 /* avatar_default.jpg_48x48.jpg in Resources */, + C479349A191610AF009C39AE /* login-background@2x.png in Resources */, + 6D70EA351869ADAE00402CF5 /* bubble_left.png in Resources */, + C4A09CE21910FED700B39BF3 /* screen-shot@2x.png in Resources */, + 6DD31ADD188E592200ED5FE8 /* 128.gif in Resources */, + 6D78A58118D828450069A29B /* ScreenCapture_toolbar_rect@2x.png in Resources */, + C47934C9191656F8009C39AE /* addgroupmember-search-background.png in Resources */, + 5709F96D184871A70096D176 /* icon_organization_highlight_theme_gray.png in Resources */, + 5709F95318486ABB0096D176 /* toolbar_bg_theme_gray@2x.png in Resources */, + 6DD31A94188E592200ED5FE8 /* 55.gif in Resources */, + 6DD31A8D188E592200ED5FE8 /* 48.gif in Resources */, + C492F41B18C31092005A3AC9 /* icon_check_filled.png in Resources */, + C479349E191610AF009C39AE /* login-logining@2x.png in Resources */, + C47934EA19173B00009C39AE /* group-info-background@2x.png in Resources */, + 6DD31A97188E592200ED5FE8 /* 58.gif in Resources */, + C47934E419172599009C39AE /* person-info-chat@2x.png in Resources */, + 572A87F718B75B04003E3FC8 /* icon_user_away_h28@2x.png in Resources */, + 6DD3197E188E3CD800ED5FE8 /* EmotionPopover.xib in Resources */, + 6DD31A6B188E592200ED5FE8 /* 14.gif in Resources */, + 6DD31A7D188E592200ED5FE8 /* 32.gif in Resources */, + 6DD31AE8188E592200ED5FE8 /* 139.gif in Resources */, + 6DCB338C189629F200FC86A3 /* filetransfer_avatar_receive.png in Resources */, + C4E97644196154B60009BE1E /* Intranet_unselected.png in Resources */, + 5EF517D61923070400652421 /* 231.gif in Resources */, + 6DD31A73188E592200ED5FE8 /* 22.gif in Resources */, + 6DD31B10188E592200ED5FE8 /* 179.gif in Resources */, + 5EF517CC1923070400652421 /* 221.gif in Resources */, + C487386E18C8093D00C51541 /* man_placeholder@2x.png in Resources */, + C4A09CAC19108E7600B39BF3 /* search-background@2x.png in Resources */, + 6DD31AA2188E592200ED5FE8 /* 69.gif in Resources */, + 8195ED691A7651E700DA5CA0 /* bg.jpg in Resources */, + C427BF61199E00F800A010AA /* bang@2x.png in Resources */, + 5EF517E919236EA600652421 /* input-background@2x.png in Resources */, + 6DD31B1E188E592200ED5FE8 /* 193.gif in Resources */, + C4C926D4190F3C1D005B3234 /* left-bar-avatar.png in Resources */, + 572A87FB18B75B04003E3FC8 /* icon_user_female_h28@2x.png in Resources */, + 6DD31AFA188E592200ED5FE8 /* 157.gif in Resources */, + 6DD31B22188E592200ED5FE8 /* 197.gif in Resources */, + 6DD31AF4188E592200ED5FE8 /* 151.gif in Resources */, + 6DD31B24188E592200ED5FE8 /* 199.gif in Resources */, + 6DD31AD2188E592200ED5FE8 /* 117.gif in Resources */, + 5772C9CE18D00E62008FE09F /* icon_statusbar.tif in Resources */, + C4A09CE11910FED700B39BF3 /* screen-shot.png in Resources */, + 57D5D178184D770100852738 /* icon_smile@2x.png in Resources */, + 57285D5018AB814400E90EC2 /* DDPreferenceWinController.xib in Resources */, + 6DD31AD1188E592200ED5FE8 /* 116.gif in Resources */, + C427BF60199E00F800A010AA /* bang.png in Resources */, + C47934F819175F3E009C39AE /* file-transmit-cancel@2x.png in Resources */, + 6DD31AD3188E592200ED5FE8 /* 118.gif in Resources */, + 6DD31AC6188E592200ED5FE8 /* 105.gif in Resources */, + 6DD31A89188E592200ED5FE8 /* 44.gif in Resources */, + C4E97649196163670009BE1E /* intranet_selected@2x.png in Resources */, + 6DD31AE9188E592200ED5FE8 /* 140.gif in Resources */, + 6DD31B07188E592200ED5FE8 /* 170.gif in Resources */, + 6DD31AB7188E592200ED5FE8 /* 90.gif in Resources */, + 6DD31AEF188E592200ED5FE8 /* 146.gif in Resources */, + C4C926ED190F4F28005B3234 /* group-unselected@2x.png in Resources */, + 6DD31B35188E592200ED5FE8 /* 216.gif in Resources */, + 6DD31B1D188E592200ED5FE8 /* 192.gif in Resources */, + C4A09CAB19108E7600B39BF3 /* search-background.png in Resources */, + C487387118C814D700C51541 /* group_placeholder.png in Resources */, + 6DD31B9B188F55C800ED5FE8 /* emotionList.xml in Resources */, + 57D5D177184D770100852738 /* icon_smile.png in Resources */, + 6DD31AC3188E592200ED5FE8 /* 102.gif in Resources */, + C47934E119172599009C39AE /* person-info-background.png in Resources */, + 6DD31AC0188E592200ED5FE8 /* 99.gif in Resources */, + 6DD31A93188E592200ED5FE8 /* 54.gif in Resources */, + 6DD31AB9188E592200ED5FE8 /* 92.gif in Resources */, + 6DD31ABA188E592200ED5FE8 /* 93.gif in Resources */, + 6DD31AC8188E592200ED5FE8 /* 107.gif in Resources */, + C47934A7191612A4009C39AE /* TeamTalk-Top.png in Resources */, + 6DD31B04188E592200ED5FE8 /* 167.gif in Resources */, + C47934F519175F3E009C39AE /* file-transmit-background.png in Resources */, + 6DD31AE5188E592200ED5FE8 /* 136.gif in Resources */, + C4E9763C196154B60009BE1E /* intranet_forward.png in Resources */, + 6DD31A9A188E592200ED5FE8 /* 61.gif in Resources */, + C4793496191610AF009C39AE /* login-account@2x.png in Resources */, + 5741BC361862E540003F2667 /* aio_recentsession_unreadmsg_wide.png in Resources */, + 5EF517CD1923070400652421 /* 222.gif in Resources */, + C485913F18C73FD800DD30DD /* icon_fav.png in Resources */, + 6D8B6AE518C462EE0081DAA2 /* filetransfer_offline@2x.png in Resources */, + 8195ED6C1A7651E700DA5CA0 /* brw.png in Resources */, + 5EF517DB1923070400652421 /* 236.gif in Resources */, + 6DD31A8B188E592200ED5FE8 /* 46.gif in Resources */, + 6DD31AEA188E592200ED5FE8 /* 141.gif in Resources */, + 6DD31B37188E592200ED5FE8 /* 218.gif in Resources */, + C4AB954B18DAE70F000181AD /* shield_gray.png in Resources */, + C487386D18C8093D00C51541 /* man_placeholder.png in Resources */, + 6DD31A98188E592200ED5FE8 /* 59.gif in Resources */, + C487386C18C8093D00C51541 /* lady_placeholder@2x.png in Resources */, + 6DD31AEC188E592200ED5FE8 /* 143.gif in Resources */, + 6DCB3393189629F200FC86A3 /* filetransfer_receiver@2x.png in Resources */, + 8195ED7C1A7651E700DA5CA0 /* mousewheel.js in Resources */, + C4E9763E196154B60009BE1E /* intranet_home.png in Resources */, + 6DD31A66188E592200ED5FE8 /* 9.gif in Resources */, + 5709F968184871A70096D176 /* icon_conversation_highlight_theme_gray@2x.png in Resources */, + C4E9763D196154B60009BE1E /* intranet_forward@2x.png in Resources */, + 572A87EB18B75A21003E3FC8 /* icon_folder_h21@2x.png in Resources */, + 57D5D175184D770100852738 /* icon_smile_highlight.png in Resources */, + 572A87FA18B75B04003E3FC8 /* icon_user_female_h28.png in Resources */, + C4EBA726192D8E9C00B72723 /* No-File-transfor.png in Resources */, + C47934E919173B00009C39AE /* group-info-background.png in Resources */, + C4A09CCF1910EFA800B39BF3 /* state-offline.png in Resources */, + C4A09CAD19108E7600B39BF3 /* shield.png in Resources */, + 572A87F818B75B04003E3FC8 /* icon_user_female_away_h28.png in Resources */, + C479352019188DE4009C39AE /* message-review-double-nextpage@2x.png in Resources */, + 81ECFE441A82338D00445985 /* voice_other.png in Resources */, + 81ECFE431A82338D00445985 /* voice_me.png in Resources */, + 6DD31AE4188E592200ED5FE8 /* 135.gif in Resources */, + C47934C4191656F8009C39AE /* addgroupmember-arrow@2x.png in Resources */, + 6DD31A74188E592200ED5FE8 /* 23.gif in Resources */, + 6DD31AA4188E592200ED5FE8 /* 71.gif in Resources */, + 6DCB338D189629F200FC86A3 /* filetransfer_avatar_receive@2x.png in Resources */, + 5EF517ED19238C7B00652421 /* shake-window@2x.png in Resources */, + 5EF517DD1923070400652421 /* 238.gif in Resources */, + 6DD31B11188E592200ED5FE8 /* 180.gif in Resources */, + C4E97648196163670009BE1E /* intranet_selected.png in Resources */, + 5709F96E184871A70096D176 /* icon_organization_highlight_theme_gray@2x.png in Resources */, + 6DD31B01188E592200ED5FE8 /* 164.gif in Resources */, + 6DD31A88188E592200ED5FE8 /* 43.gif in Resources */, + 572A87EA18B75A21003E3FC8 /* icon_folder_h21.png in Resources */, + C479349B191610AF009C39AE /* login-input-background.png in Resources */, + C4C926D5190F3C1D005B3234 /* left-bar-avatar@2x.png in Resources */, + 6DD31AFC188E592200ED5FE8 /* 159.gif in Resources */, + 577C168D184749A1009718D7 /* icon_user_h51.png in Resources */, + 6DD31AB2188E592200ED5FE8 /* 85.gif in Resources */, + 6DD31AFF188E592200ED5FE8 /* 162.gif in Resources */, + 6DD31A64188E592200ED5FE8 /* 7.gif in Resources */, + 6DD31AF5188E592200ED5FE8 /* 152.gif in Resources */, + C47934F719175F3E009C39AE /* file-transmit-cancel.png in Resources */, + 8195ED6B1A7651E700DA5CA0 /* blbb.png in Resources */, + 188B010F18505E8100A99E7A /* icon.icns in Resources */, + 6DD31ADF188E592200ED5FE8 /* 130.gif in Resources */, + C4C926D1190F3C1D005B3234 /* setting@2x.png in Resources */, + C47934C7191656F8009C39AE /* addgroupmember-cancel2.png in Resources */, + C4A09CD01910EFA800B39BF3 /* state-offline@2x.png in Resources */, + 6DD31A61188E592200ED5FE8 /* 4.gif in Resources */, + C427BF5F199E00F800A010AA /* almance@2x.png in Resources */, + 578D5EA5187EC0E600568EE6 /* icon_away@2x.png in Resources */, + C47934C5191656F8009C39AE /* addgroupmember-cancel.png in Resources */, + 6DD31AAB188E592200ED5FE8 /* 78.gif in Resources */, + 577C168518474649009718D7 /* icon_online.png in Resources */, + 6DD31AD6188E592200ED5FE8 /* 121.gif in Resources */, + 6DD31AED188E592200ED5FE8 /* 144.gif in Resources */, + 6DD31B38188E592200ED5FE8 /* 219.gif in Resources */, + 8195ED6F1A7651E700DA5CA0 /* highlight.min.js in Resources */, + 6DD31AC7188E592200ED5FE8 /* 106.gif in Resources */, + C47934EB19173B00009C39AE /* group-info-line.png in Resources */, + 6DD31B1C188E592200ED5FE8 /* 191.gif in Resources */, + 6DD31ABD188E592200ED5FE8 /* 96.gif in Resources */, + 6D70EA361869ADAE00402CF5 /* bubble_left@2x.png in Resources */, + 57D5D173184D770100852738 /* icon_screenshot.png in Resources */, + 6DD31A92188E592200ED5FE8 /* 53.gif in Resources */, + 6DD31A69188E592200ED5FE8 /* 12.gif in Resources */, + C4E9763A196154B60009BE1E /* intranet_back.png in Resources */, + C4C926EE190F4F28005B3234 /* left-bar-selected-background.png in Resources */, + C4793499191610AF009C39AE /* login-background.png in Resources */, + 57D5D171184D770100852738 /* icon_screenshot_highlight.png in Resources */, + 6DD31AAC188E592200ED5FE8 /* 79.gif in Resources */, + 577C167F18474005009718D7 /* DDMainWindow.xib in Resources */, + 572A87FF18B75B04003E3FC8 /* icon_user_offline_h28@2x.png in Resources */, + 8195ED7E1A7651E700DA5CA0 /* pure-min.css in Resources */, + 6DD31AA7188E592200ED5FE8 /* 74.gif in Resources */, + 57EFFAE21856C639006D8DE1 /* icon_unread_red@2x.png in Resources */, + C47934FE19177DF1009C39AE /* DDMessageReviewWindow.xib in Resources */, + 6DD31B19188E592200ED5FE8 /* 188.gif in Resources */, + 5EF517D51923070400652421 /* 230.gif in Resources */, + 5EF517D31923070400652421 /* 228.gif in Resources */, + C492F41818C30FF5005A3AC9 /* icon_check_empty@2x.png in Resources */, + 572A87C418B5ED96003E3FC8 /* icon_addcontacts_highlight_theme_gray@2x.png in Resources */, + 57124E4C187AAEAD006D2DCA /* DDAlertWindowController.xib in Resources */, + 6DD31B1F188E592200ED5FE8 /* 194.gif in Resources */, + 6DD31B00188E592200ED5FE8 /* 163.gif in Resources */, + 57EFFB2918570324006D8DE1 /* icon_image_normal@2x.png in Resources */, + C4E97645196154B60009BE1E /* Intranet_unselected@2x.png in Resources */, + 6DD31A5E188E592200ED5FE8 /* 1.gif in Resources */, + 572A87F918B75B04003E3FC8 /* icon_user_female_away_h28@2x.png in Resources */, + 6DD31B16188E592200ED5FE8 /* 185.gif in Resources */, + 6DD31A80188E592200ED5FE8 /* 35.gif in Resources */, + 6DD31AD0188E592200ED5FE8 /* 115.gif in Resources */, + 6DD31A87188E592200ED5FE8 /* 42.gif in Resources */, + 6DD31AF7188E592200ED5FE8 /* 154.gif in Resources */, + 6DD31B23188E592200ED5FE8 /* 198.gif in Resources */, + 6DD31A81188E592200ED5FE8 /* 36.gif in Resources */, + C4E97643196154B60009BE1E /* intranet_refresh@2x.png in Resources */, + 6DD31ACA188E592200ED5FE8 /* 109.gif in Resources */, + 573847431820CDA000443653 /* Credits.rtf in Resources */, + 6DD31A7A188E592200ED5FE8 /* 29.gif in Resources */, + 6DD31A70188E592200ED5FE8 /* 19.gif in Resources */, + 573847491820CDA000443653 /* MainMenu.xib in Resources */, + 6DD31A96188E592200ED5FE8 /* 57.gif in Resources */, + 6DD31AE0188E592200ED5FE8 /* 131.gif in Resources */, + 6DCB3390189629F200FC86A3 /* filetransfer_close.png in Resources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXResourcesBuildPhase section */ + +/* Begin PBXShellScriptBuildPhase section */ + 4339E9449C259D1050E09245 /* Copy Pods Resources */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputPaths = ( + ); + name = "Copy Pods Resources"; + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods/Pods-resources.sh\"\n"; + showEnvVarsInLog = 0; + }; + 5B4EB9AF98993B8F2DA57993 /* Check Pods Manifest.lock */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputPaths = ( + ); + name = "Check Pods Manifest.lock"; + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "diff \"${PODS_ROOT}/../Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [[ $? != 0 ]] ; then\n cat << EOM\nerror: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\nEOM\n exit 1\nfi\n"; + showEnvVarsInLog = 0; + }; +/* End PBXShellScriptBuildPhase section */ + +/* Begin PBXSourcesBuildPhase section */ + 5738472B1820CDA000443653 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + C4FA6BD61908E0640097849B /* DDAPISchedule.m in Sources */, + 6D1CC7B218A62FF0002CAE5F /* L4WriterAppender.m in Sources */, + 573847891820CE9900443653 /* DataOutputStream.m in Sources */, + C408E8AE191B48BD005F5150 /* DDSendMessageAPI.mm in Sources */, + C41AB11A195A7EF2002AE7C7 /* DDIntranetViewController.m in Sources */, + C41AB120195AA9DA002AE7C7 /* DDIntranetEntity.m in Sources */, + 5733D83E184F326600737695 /* AITextAttachmentAdditions.m in Sources */, + C4A09C91190FC2FA00B39BF3 /* DDRecentContactsModule.m in Sources */, + 572A880618B773EF003E3FC8 /* ChildNode.m in Sources */, + 57285D5318AB860E00E90EC2 /* DDUserPreferences.m in Sources */, + C48E2F541A62264A002F3FEB /* DDOriginEntity.m in Sources */, + 6D1CC79D18A62FF0002CAE5F /* L4DenyAllFilter.m in Sources */, + C479350A19178CF5009C39AE /* DDMessageReviewContactsCellView.m in Sources */, + C4F7E5EF1907D24E006E31F3 /* DDSundriesCenter.m in Sources */, + C42D4EA319247EEA00C7B6F6 /* PFMoveApplication.m in Sources */, + C48E395B18F4E6C000C610EB /* DDCurrentUserState.m in Sources */, + EF29F2BD1AB80077001FC3EE /* MTDepartmentManager.m in Sources */, + C48E2F4E1A62258D002F3FEB /* MTGroupModule.m in Sources */, + C48D603518BC634A00F5ED30 /* DDUserDataWindowController.m in Sources */, + C48E2F451A6224F1002F3FEB /* MTUserEntity.m in Sources */, + C417C3991A7370E2003984D7 /* MTImageCache.m in Sources */, + 57D5D187184D840000852738 /* DDChattingInputView.m in Sources */, + C48E79F418FF686200A1FA66 /* DDApplicationUpdate.m in Sources */, + 5733D832184F2DFF00737695 /* AITextAttributes.m in Sources */, + 57B95BBD1A7CCEE8004DFB22 /* MASShortcut+Monitoring.m in Sources */, + 572A87E218B74E7B003E3FC8 /* DDClickCell.m in Sources */, + 6D1CC7AC18A62FF0002CAE5F /* L4Properties.m in Sources */, + 57124E56187E331A006D2DCA /* ImageAndTextCell.m in Sources */, + 573AF6071A67FED000B6D3B8 /* LoginEntity.m in Sources */, + C492F40718C2CEF4005A3AC9 /* DDAddChatGroupCell.m in Sources */, + 57149F93184487C200DDBA25 /* EGOCache.m in Sources */, + C4C926F6190F51C4005B3234 /* DDLeftBarViewController.m in Sources */, + C408E8CE191CDAE4005F5150 /* DDFileLoginAPI.m in Sources */, + 57D5D165184C76D900852738 /* DDSplitView.m in Sources */, + 572A880518B773EF003E3FC8 /* BaseNode.m in Sources */, + 57B62327183072FB00F2B249 /* SBJsonStreamParserAccumulator.m in Sources */, + C4AB955418DBF006000181AD /* DrawView.m in Sources */, + C408E8D1191CDCDD005F5150 /* DDFileSendAPI.m in Sources */, + 57F50078182F93D90090115B /* MD5.m in Sources */, + C48E39A118F9112800C610EB /* DDClientStateMaintenanceManager.m in Sources */, + 576BA9671876D0BB002B40EC /* DDInterfaceController.m in Sources */, + 577C169118475857009718D7 /* DDTabItemView.m in Sources */, + 57B62325183072FB00F2B249 /* SBJsonParser.m in Sources */, + C492F40C18C2D0F2005A3AC9 /* DDAddChatGroupModel.m in Sources */, + C4A09CBD1910ABA600B39BF3 /* DDGroupCell.m in Sources */, + C40F952B1919FA00005CACBF /* DDMsgReadACKAPI.m in Sources */, + 57B95BC01A7CCEE8004DFB22 /* MASShortcutView+UserDefaults.m in Sources */, + C40F95281919DDCC005CACBF /* DDReceiveMessageAPI.m in Sources */, + C408E8C6191B8B70005F5150 /* DDReceiveKickAPI.m in Sources */, + 37E4C0381A6E486A00178EA8 /* MTSysConfigEntity.m in Sources */, + C406E70018D82E84005092C3 /* EmotionManager.m in Sources */, + C40F952E1919FA90005CACBF /* DDGroupMsgReadACKAPI.m in Sources */, + C40417B61A68D9B500242E20 /* MTUnreadMessageManager.m in Sources */, + 183B534218695FBA009073EC /* DDTaskManager.m in Sources */, + 6D1CC7A718A62FF0002CAE5F /* L4LoggerNameMatchFilter.m in Sources */, + C479351019187782009C39AE /* DDMessagesReviewContentModule.m in Sources */, + 571CFF9D188F92D30030E02C /* DDEmotionAttachment.m in Sources */, + 57E1AA9F186AD9FF00D00D63 /* MainWindowSegmentedControl.m in Sources */, + 57149FFC1845D32E00DDBA25 /* CaptureView.m in Sources */, + 57124E59187E531D006D2DCA /* DDChattingContactListViewController.m in Sources */, + 6D70EA94186C43C000402CF5 /* NSImage+Stretchable.m in Sources */, + C48D604018BED99500F5ED30 /* SpellLibrary.m in Sources */, + C406E70918D8616B005092C3 /* DDChangableAttactment.m in Sources */, + 57B6232E183072FB00F2B249 /* SBJsonUTF8Stream.m in Sources */, + 578D5EAF188383EE00568EE6 /* DDImageMessage.m in Sources */, + C4A09C99190FC4CA00B39BF3 /* DDGroupVCModule.m in Sources */, + C40F95311919FB4F005CACBF /* DDUserMsgReceivedACKAPI.m in Sources */, + 572A87E618B74E9F003E3FC8 /* DDAddChatGroupWindowController.m in Sources */, + 6DCB32DA189201FF00FC86A3 /* DDApplication.m in Sources */, + 6D74358F18E26A02008ED227 /* BackgroudView.m in Sources */, + 570D6E4C1839B28000F68CB0 /* AIFileManagerAdditions.m in Sources */, + C40F95341919FB75005CACBF /* DDGroupMsgReceivedACKAPI.m in Sources */, + C4C926DB190F4274005B3234 /* DDGridBackgroundView.m in Sources */, + 5733D841184F33F500737695 /* AIPasteboardAdditions.m in Sources */, + 6D1CC7A618A62FF0002CAE5F /* L4Logger.m in Sources */, + C4A09CC01910D19B00B39BF3 /* DDSearchViewController.m in Sources */, + C41AB125195AAAF4002AE7C7 /* DDIntranetCell.m in Sources */, + 577C168218474317009718D7 /* DDMainWindowController.m in Sources */, + 18A38FF1187A98BF00F3F19D /* DDMainModule.m in Sources */, + C47934D119165EB5009C39AE /* DDAddGroupMemberDepartmentCell.m in Sources */, + C4563FBE1906384F009DEB05 /* DDSearch.m in Sources */, + 5738479E1820D80E00443653 /* DDWindowController.m in Sources */, + 81DEF50A1A5B8FE800F0799D /* DDepartment.m in Sources */, + 57B62328183072FB00F2B249 /* SBJsonStreamParserAdapter.m in Sources */, + C492F40F18C2E3DA005A3AC9 /* DDAddChatGroup.m in Sources */, + 37E4C02E1A6CAE4600178EA8 /* MTDatabaseUtil.m in Sources */, + C41AB12C195B0487002AE7C7 /* DDIntranetContentViewController.m in Sources */, + C48E2F661A625A1F002F3FEB /* DDHeartBeatAPI.m in Sources */, + C408E8DB191CE44E005F5150 /* DDOtherLinkFileServerAPI.m in Sources */, + C48E2F631A622BFC002F3FEB /* DDRootModule.m in Sources */, + C4498A0818D71A92009FEA4A /* MessageViewFactory.m in Sources */, + C47934D719167458009C39AE /* DDMultiSelectedOutlineView.m in Sources */, + C479352A1918BD9F009C39AE /* DDMessageReviewTextView.m in Sources */, + C4FA6BDF190B94350097849B /* DDChattingWindowManager.m in Sources */, + 187FAC0518685D97006ACC30 /* DDModuleManager.m in Sources */, + C4FE222A1920C04700FFB520 /* DDReceiveAbortFileSendAPI.m in Sources */, + 57B6232D183072FB00F2B249 /* SBJsonTokeniser.m in Sources */, + C4FE22421920DEE500FFB520 /* DDFileSendResponseAPI.m in Sources */, + 579E54791A67C3B4003031A1 /* DDHttpModule.m in Sources */, + C4FE22301920C8D700FFB520 /* DDOtherSendOfflineFileAPI.m in Sources */, + C4498A0918D71A92009FEA4A /* NSTextView+Rect.m in Sources */, + 577BB80D1A64F78E00264086 /* IMGroup.pb.m in Sources */, + 6D1CC7B118A62FF0002CAE5F /* L4StringMatchFilter.m in Sources */, + 57B95BBF1A7CCEE8004DFB22 /* MASShortcutView.m in Sources */, + C4C926F9190F526F005B3234 /* DDLeftBarItem.m in Sources */, + 18FF1D18185177F700C19036 /* DDSound.m in Sources */, + C40417B31A68C20E00242E20 /* MTLastMessageManager.m in Sources */, + 57B95BBC1A7CCEE8004DFB22 /* MASShortcut.m in Sources */, + C4D2EFFB18B70F1F000F0B12 /* NSView+Addition.m in Sources */, + 6D1CC7AA18A62FF0002CAE5F /* L4LogLog.m in Sources */, + 6DD31B99188F554500ED5FE8 /* EmotionListXmlParser.m in Sources */, + C4AB954618DAD5C9000181AD /* WhiteBackgroundView.m in Sources */, + 6D1CC7B318A62FF0002CAE5F /* L4XMLLayout.m in Sources */, + 57C0A8861A68B3B400ECDE45 /* AvatorImageView.m in Sources */, + C47935271918B9C0009C39AE /* DDMessagesReviewWindow.m in Sources */, + C4FE224B1920F11300FFB520 /* DDReadyReceiveFileAPI.m in Sources */, + 6D1CC7A318A62FF0002CAE5F /* L4LevelMatchFilter.m in Sources */, + C48E79E018FB861A00A1FA66 /* DDLoginWindowControllerModule.m in Sources */, + C47934D419166415009C39AE /* DDAddGroupMemberDepartmentRowView.m in Sources */, + C48B104718D1AE9000DEF8C6 /* CrashReportManager.m in Sources */, + C427BF9119A32C0900A010AA /* MessageDate.m in Sources */, + 183B53921872B720009073EC /* DDModuleDataManager.m in Sources */, + C4FF47381A7F4EB500B21A0D /* MTPreviewItem.m in Sources */, + 57124E4B187AAEAD006D2DCA /* DDAlertWindowController.m in Sources */, + C46C51BC18D2DBC000149B7F /* DDChattingContactListCell.m in Sources */, + EF29F2C31AB82087001FC3EE /* MTDepartmentEntity.m in Sources */, + C42410CF199734E100B6B945 /* DDServiceAccountModule.m in Sources */, + 577BB8101A64F78E00264086 /* IMOther.pb.m in Sources */, + 5709F95E18486E320096D176 /* DDImageView.m in Sources */, + C4FA6BD91908F5BD0097849B /* DDSuperAPI.m in Sources */, + C48E399E18F8EA4F00C610EB /* DDTcpClientManager.m in Sources */, + C47934B219163C1F009C39AE /* HoverTableRowView.m in Sources */, + 6DDB0D3A18EC17FF00A1DA57 /* GCDAsyncSocket.m in Sources */, + 577BB80F1A64F78E00264086 /* IMMessage.pb.m in Sources */, + 57285D5618B19BD000E90EC2 /* DDOptionsBase.m in Sources */, + C48E79F018FE2AF000A1FA66 /* DDPathHelp.m in Sources */, + C4FE223F1920CF4A00FFB520 /* DDDeleteOfflineFileAPI.m in Sources */, + C4A6F1E318EFD61400A6AD61 /* DDLoginManager.m in Sources */, + 57149FFD1845D32E00DDBA25 /* CaptureWindow.m in Sources */, + C44C20401900B2850069A31F /* DDMessageReviewWindowController.m in Sources */, + C48E2F511A6225BA002F3FEB /* MTUserModule.m in Sources */, + C438032718C5D130002555BB /* DDGroupInfoManager.m in Sources */, + 6D1CC7A918A62FF0002CAE5F /* L4Logging.m in Sources */, + 81FA3B2A1A68DEBC00B379D1 /* DDHistoryMessageAPI.m in Sources */, + 57AF229818210D8100758483 /* DDSharedWriterQueue.m in Sources */, + 57149F96184487C200DDBA25 /* EGOImageView.m in Sources */, + 57B95BBE1A7CCEE8004DFB22 /* MASShortcut+UserDefaults.m in Sources */, + 5EF517E519235FBA00652421 /* DDChattingMyLine.m in Sources */, + C40F9544191A563E005CACBF /* DDSeqNoManager.m in Sources */, + C47934DA19172063009C39AE /* DDUserInfoPanel.m in Sources */, + C4FE22241920B2A000FFB520 /* DDOtherFileResponseAPI.m in Sources */, + C4563FBB1906365C009DEB05 /* DDChattingContactListModule.m in Sources */, + C48EEE5418F0169E00FCB35B /* NotificationHelp.m in Sources */, + C406E70318D84FD2005092C3 /* DDMessageTextView.m in Sources */, + C41AB11D195AA10F002AE7C7 /* DDIntranetModule.m in Sources */, + 1886E1D31850A4ED00BA092C /* DDCommonApi.m in Sources */, + 57AB4F171821F00E00603621 /* NSString+DDStringAdditions.m in Sources */, + 6D1CC79818A62FF0002CAE5F /* L4AppenderAttachable.m in Sources */, + 571CFFA718920A010030E02C /* DDSearchFieldEditorDelegate.m in Sources */, + 573AF6041A67FA3A00B6D3B8 /* MTScreenCaptureModule.m in Sources */, + C47934AB19163477009C39AE /* DDCustomWindow.m in Sources */, + 57BB35161894D39B0094B553 /* DDSearchFieldController.m in Sources */, + C40417B91A69047E00242E20 /* MTMessageEntity.mm in Sources */, + 573847911820CE9900443653 /* SendBuffer.m in Sources */, + 811405D41A68EFA6009CFC06 /* DDUnreadMessageAPI.m in Sources */, + 570D6E491839B24200F68CB0 /* AIImageAdditions.m in Sources */, + C40F954A191B26EE005CACBF /* DDReceiveStateChangedAPI.m in Sources */, + 6D1CC7A018A62FF0002CAE5F /* L4JSONLayout.m in Sources */, + 6D1CC7AE18A62FF0002CAE5F /* L4RollingFileAppender.m in Sources */, + C40F951A1919C69A005CACBF /* DDAllUserAPI.m in Sources */, + 57B3902018349DA6007CD3E0 /* AIBezierPathAdditions.m in Sources */, + 57B3ACE818C0ACDD00F50C8F /* DDChattingViewController.m in Sources */, + C47935341918E88B009C39AE /* DDFixedGroupAPI.m in Sources */, + C48E79E618FBB28E00A1FA66 /* DDClientState.m in Sources */, + C48E2F5D1A622886002F3FEB /* MTSessionEntity.m in Sources */, + C4FE22391920CE5600FFB520 /* DDReceiveOtherOfflineFileUploadFinishedAPI.m in Sources */, + C4A09C9E191089A800B39BF3 /* DDRecentContactsCell.m in Sources */, + C4A09C96190FC44400B39BF3 /* DDGroupViewController.m in Sources */, + 57AB4F141821EFBC00603621 /* NSFileManager+DDFileManagerAdditions.m in Sources */, + 6D1CC7AB18A62FF0002CAE5F /* L4PatternLayout.m in Sources */, + C406E6FD18D81925005092C3 /* NSImage+Scale.m in Sources */, + 57AF228A1820F2EF00758483 /* DDLoginWindowController.m in Sources */, + 5771F1411A7E5D0C003EDC6A /* MTGroupChangeMemberAPI.m in Sources */, + C4C926C2190DE988005B3234 /* DDContactsRowView.m in Sources */, + C408E8C3191B83F3005F5150 /* DDOnlineUserListAPI.m in Sources */, + C42A070E18E80E49004461E1 /* DDImageUploader.m in Sources */, + 6D1CC7A418A62FF0002CAE5F /* L4LevelRangeFilter.m in Sources */, + 57B62326183072FB00F2B249 /* SBJsonStreamParser.m in Sources */, + C4A09CC31910D2BA00B39BF3 /* DDSearchResultCell.m in Sources */, + C4C472FC18EFE5EF00BC4E73 /* DDTcpServer.m in Sources */, + C4A6F1E618EFD69400A6AD61 /* DDHttpServer.m in Sources */, + 6DD3197C188E3C8B00ED5FE8 /* EmotionCellView.m in Sources */, + 577BB8121A64F78E00264086 /* IMXIAOT.pb.m in Sources */, + 6DD31979188E3C5200ED5FE8 /* EmotionViewController.m in Sources */, + 6D1CC79F18A62FF0002CAE5F /* L4Filter.m in Sources */, + C44C20431900B2AE0069A31F /* DDMessageReviewModule.m in Sources */, + 57B6232A183072FB00F2B249 /* SBJsonStreamWriter.m in Sources */, + 6D1CC79C18A62FF0002CAE5F /* L4DailyRollingFileAppender.m in Sources */, + C4FE222D1920C60300FFB520 /* DDSendOffLineFileAPI.m in Sources */, + C4FE221A19205C1000FFB520 /* DDRemoveSessionAPI.m in Sources */, + C48E79E918FCE31A00A1FA66 /* DDMainWindowControllerModule.m in Sources */, + 5733D829184F284400737695 /* DDWindowAdditions.m in Sources */, + 6DE7621218867FE2000EDC39 /* PullToRefreshScrollView.m in Sources */, + 57B6232F183072FB00F2B249 /* SBJsonWriter.m in Sources */, + C4D2EFF818B4B4C9000F0B12 /* DDSearchFieldResultCell.m in Sources */, + 5733D838184F317200737695 /* AITextAttachmentExtension.m in Sources */, + 6DE7621118867FE2000EDC39 /* PullToRefreshClipView.m in Sources */, + 57149F95184487C200DDBA25 /* EGOImageLoader.m in Sources */, + 6D1CC7AD18A62FF0002CAE5F /* L4PropertyConfigurator.m in Sources */, + 189B0A9C187694E600C3997A /* DDSharedDuoduo.m in Sources */, + 571CFFA11890B41C0030E02C /* FMSearchTokenFieldCell.m in Sources */, + C479350419178A69009C39AE /* DDMessageReviewContactsViewController.m in Sources */, + 187FAC0618685D97006ACC30 /* DDWatch.m in Sources */, + C4C1CB85197E695000386AB0 /* DDModifyUserAvatarAPI.m in Sources */, + C48E2F601A622899002F3FEB /* MTSessionModule.m in Sources */, + C4793501191782E7009C39AE /* NSWindow+Addition.m in Sources */, + 57D5D18E184EC85100852738 /* DDSendingTextView.m in Sources */, + C4FF47591A83578200B21A0D /* DataOutputStream+Addition.m in Sources */, + C4FE22451920E43600FFB520 /* DDReceiveOtherResponseAPI.m in Sources */, + C454AB0E18F914D90040BBF0 /* DDLoginServer.m in Sources */, + 578D5EAC187FC44A00568EE6 /* DDChattingHeadViewController.m in Sources */, + C4F90F9C1963DFE900DF2828 /* DDIntranetMessageEntity.m in Sources */, + 573847461820CDA000443653 /* DDAppDelegate.m in Sources */, + 57285D4F18AB814400E90EC2 /* DDPreferenceWinController.m in Sources */, + C408E8D4191CE13E005F5150 /* DDGetOfflineFileAPI.m in Sources */, + C43802D218C4860B002555BB /* DDGroupDataWindow.m in Sources */, + C4498A1D18D7D976009FEA4A /* DDChattingViewModule.m in Sources */, + 57149F94184487C200DDBA25 /* EGOImageLoadConnection.m in Sources */, + 57A4B5551A722E1700E16CBC /* MTChattingInputView.m in Sources */, + C43802D518C48627002555BB /* DDGroupDataModule.m in Sources */, + C4A6F1DF18EE4FD900A6AD61 /* StateMaintenanceManager.m in Sources */, + 5733D835184F2E4D00737695 /* AIFontManagerAdditions.m in Sources */, + 57B62329183072FB00F2B249 /* SBJsonStreamParserState.m in Sources */, + 571CFFA41890BD6A0030E02C /* FMSearchTokenAttachmentCell.m in Sources */, + 6D2A847E18B1D5E20004032B /* DDLoginWindow.m in Sources */, + 6D1CC7A818A62FF0002CAE5F /* L4LoggerStore.m in Sources */, + 8AEFB8421920968C006A5C88 /* DDSendP2PCmdAPI.m in Sources */, + C46C810F197500FA00157856 /* DDCornerRadiusTextField.m in Sources */, + 81DEF50D1A5B901B00F0799D /* NSDictionary+Safe.m in Sources */, + 6D1CC79918A62FF0002CAE5F /* L4AppenderSkeleton.m in Sources */, + 6D1CC7A218A62FF0002CAE5F /* L4Level.m in Sources */, + 57AB4F111821EAD500603621 /* NSEvent+DDEventAdditions.m in Sources */, + 57B390261834A970007CD3E0 /* DDImageCollectionView.m in Sources */, + 573847881820CE9900443653 /* DataInputStream.m in Sources */, + 18C769FD188E44720066AA8C /* Reachability.m in Sources */, + EF29F2C01AB81E15001FC3EE /* DDDepartmentInfoAPI.m in Sources */, + C4A09CC61910EA2400B39BF3 /* DDAppBackgroundColorView.m in Sources */, + 183B538F1872976D009073EC /* NSNotification+DDLogic.m in Sources */, + C4FF47411A80AD9100B21A0D /* MTInputHistoryManager.m in Sources */, + C4EBA72A192D91E400B72723 /* DDUserDetailInfoAPI.m in Sources */, + 57149FF1184592B700DDBA25 /* DDAutoScrollView.m in Sources */, + 57B6232B183072FB00F2B249 /* SBJsonStreamWriterAccumulator.m in Sources */, + C40F95251919D682005CACBF /* DDUnrequestSuperAPI.m in Sources */, + 183B538618714739009073EC /* NSDictionary+MGJ.m in Sources */, + C48D603A18BC670900F5ED30 /* DDUserDataModel.m in Sources */, + C4AB95A918E16AEA000181AD /* DDSetting.m in Sources */, + 6D1CC7AF18A62FF0002CAE5F /* L4RootLogger.m in Sources */, + 81DEF5031A5B8D9900F0799D /* DDBaseEntity.m in Sources */, + C4FE22361920CBB200FFB520 /* DDOfflineFileUploadFinishedAPI.m in Sources */, + 57C2D2EB1A74D3C500981552 /* DDAtUserListViewController.m in Sources */, + 18A38FF7187AAD1A00F3F19D /* DDCommonModule.m in Sources */, + C43802DA18C48A40002555BB /* DDGroupInfoCell.m in Sources */, + C4FE22481920EC4D00FFB520 /* DDReceiveOtherSendFileAPI.m in Sources */, + 571FD9BA18681A5F00F7476B /* FMSearchTokenField.m in Sources */, + 6D1CC7B018A62FF0002CAE5F /* L4SimpleLayout.m in Sources */, + C492F41218C2FD8A005A3AC9 /* DDAddGroupSelectedCell.m in Sources */, + 6D1CC79E18A62FF0002CAE5F /* L4FileAppender.m in Sources */, + 81DEF5101A5B908100F0799D /* NSString+Additions.m in Sources */, + 573847861820CE9900443653 /* MessageEntity.m in Sources */, + C4FF473E1A80ACA900B21A0D /* MTDraftManager.m in Sources */, + 57F50075182F92080090115B /* DDHttpUtil.m in Sources */, + 5738473F1820CDA000443653 /* main.m in Sources */, + 57C0CE5E183C98DE0049DCE4 /* DDMutableOwnerArray.m in Sources */, + C4FE224E1920F35600FFB520 /* DDReceiveOtherReadyAcceptFileAPI.m in Sources */, + 57B6232C183072FB00F2B249 /* SBJsonStreamWriterState.m in Sources */, + 570D6E461839B0E100F68CB0 /* AIImageDrawingAdditions.m in Sources */, + C479352E1918E807009C39AE /* DDLoginAPI.mm in Sources */, + 57C0CE50183C7C320049DCE4 /* AIParagraphStyleAdditions.m in Sources */, + 579E54781A67C3B4003031A1 /* DDHttpEntity.m in Sources */, + C479350719178A89009C39AE /* DDMessagesReviewContentViewController.m in Sources */, + C4FA6BDC190909EA0097849B /* DDRecentConactsAPI.m in Sources */, + 577BB80B1A64F78E00264086 /* IMBaseDefine.pb.m in Sources */, + C40F953B191A011A005CACBF /* DDGroupInfoAPI.m in Sources */, + C4A6F1EC18EFD6CE00A6AD61 /* DDMsgServer.m in Sources */, + 5733D82F184F2D1600737695 /* AIColorAdditions.m in Sources */, + C48E2F481A622506002F3FEB /* MTGroupEntity.m in Sources */, + 579E547D1A67C426003031A1 /* DDLogic.m in Sources */, + 577C169418476804009718D7 /* DDMainWindow.m in Sources */, + 5738478E1820CE9900443653 /* NSStream+NSStreamAddition.m in Sources */, + 183B5371186D58C2009073EC /* TcpProtocolHeader.m in Sources */, + 577BB8111A64F78E00264086 /* IMSwitchService.pb.m in Sources */, + C417C39C1A737C2C003984D7 /* NSImageView+MTAddition.m in Sources */, + 6D1CC7A518A62FF0002CAE5F /* L4LogEvent.m in Sources */, + 57B62324183072FB00F2B249 /* NSObject+SBJson.m in Sources */, + C4A09C8E190FC2AC00B39BF3 /* DDRecentContactsViewController.m in Sources */, + 57AB317D18287E6800B7766E /* DDKeychain.m in Sources */, + C4FE222119209B2300FFB520 /* DDReceiveP2PMessageAPI.m in Sources */, + C4FE22271920B40100FFB520 /* DDAbortFileSendAPI.m in Sources */, + 6D1CC79B18A62FF0002CAE5F /* L4ConsoleAppender.m in Sources */, + C4FE223C1920CF3700FFB520 /* DDAddOfflineFileAPI.m in Sources */, + 6D1CC79A18A62FF0002CAE5F /* L4BasicConfigurator.m in Sources */, + C42A070718E7D01D004461E1 /* NSWindow+Animation.m in Sources */, + 57DEB6951A8222A800961C6F /* DDReceiveMsgDataReadNotifyAPI.m in Sources */, + C422FF2319261A18006EEBF9 /* DDCornerView.m in Sources */, + 57C0CE56183C86B40049DCE4 /* AIWindowControllerAdditions.m in Sources */, + C4C0724E1AA583F900C01D0D /* DDGetLastMessageIDAPI.m in Sources */, + 187FAC0C18685DE2006ACC30 /* DDTaskOperation.m in Sources */, + C48E2F691A626C7F002F3FEB /* MTMessageModule.m in Sources */, + 6D1CC7A118A62FF0002CAE5F /* L4Layout.m in Sources */, + 57AF2295182108E300758483 /* DDDictionaryAdditions.m in Sources */, + C40F9547191B1D32005CACBF /* DDUserOnlineStateAPI.m in Sources */, + 5709F94F1848682E0096D176 /* DDImageSpreadView.m in Sources */, + C46B2D9D18E435E400FE278B /* DDSetting+OffLineReadMsgManager.m in Sources */, + C406E6FA18D81850005092C3 /* NSAttributedString+Message.m in Sources */, + C42A070B18E80066004461E1 /* DDMessageSendManager.m in Sources */, + 6D1CC7B418A62FF0002CAE5F /* NSObject+Log4Cocoa.m in Sources */, + C48E79F718FFAE7800A1FA66 /* NSImage+Addition.m in Sources */, + 183B536B186AFB27009073EC /* FileTransferEntity.m in Sources */, + C417C39F1A738010003984D7 /* MTImageDownload.m in Sources */, + 57124E5C187E6E3D006D2DCA /* DDTableView.m in Sources */, + 183B5383187145A6009073EC /* MGJEntity.m in Sources */, + C4FF473B1A7FA0F800B21A0D /* DDReceiveGroupMemberChangedAPI.m in Sources */, + 37E4C03B1A6E487E00178EA8 /* MTSysConfigModule.m in Sources */, + C408E8B1191B57DE005F5150 /* DDCreateGroupAPI.m in Sources */, + 183B5380187141A6009073EC /* NSData+NSJSONSerialization.m in Sources */, + 5733D82C184F2C4A00737695 /* AIAttributedStringAdditions.m in Sources */, + C4498A0718D71A92009FEA4A /* MessageShowView.m in Sources */, + 577BB80E1A64F78E00264086 /* IMLogin.pb.m in Sources */, + C47934881915F217009C39AE /* NSView+LayerAddition.m in Sources */, + C438032418C5C916002555BB /* DDUserInfoManager.m in Sources */, + 577BB80C1A64F78E00264086 /* IMBuddy.pb.m in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase section */ + +/* Begin PBXVariantGroup section */ + 5738473B1820CDA000443653 /* InfoPlist.strings */ = { + isa = PBXVariantGroup; + children = ( + 5738473C1820CDA000443653 /* en */, + ); + name = InfoPlist.strings; + sourceTree = ""; + }; + 573847411820CDA000443653 /* Credits.rtf */ = { + isa = PBXVariantGroup; + children = ( + 573847421820CDA000443653 /* en */, + ); + name = Credits.rtf; + sourceTree = ""; + }; + 573847471820CDA000443653 /* MainMenu.xib */ = { + isa = PBXVariantGroup; + children = ( + 573847481820CDA000443653 /* Base */, + ); + name = MainMenu.xib; + sourceTree = ""; + }; + 573847591820CDA000443653 /* InfoPlist.strings */ = { + isa = PBXVariantGroup; + children = ( + 5738475A1820CDA000443653 /* en */, + ); + name = InfoPlist.strings; + sourceTree = ""; + }; +/* End PBXVariantGroup section */ + +/* Begin XCBuildConfiguration section */ + 5738475E1820CDA000443653 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + COPY_PHASE_STRIP = NO; + GCC_C_LANGUAGE_STANDARD = gnu99; + GCC_DYNAMIC_NO_PIC = NO; + GCC_ENABLE_OBJC_EXCEPTIONS = YES; + GCC_OPTIMIZATION_LEVEL = 0; + GCC_PREPROCESSOR_DEFINITIONS = ( + "DEBUG=1", + "$(inherited)", + ); + GCC_SYMBOLS_PRIVATE_EXTERN = NO; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + MACOSX_DEPLOYMENT_TARGET = 10.8; + ONLY_ACTIVE_ARCH = YES; + SDKROOT = macosx10.8; + }; + name = Debug; + }; + 5738475F1820CDA000443653 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + COPY_PHASE_STRIP = YES; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + ENABLE_NS_ASSERTIONS = NO; + GCC_C_LANGUAGE_STANDARD = gnu99; + GCC_ENABLE_OBJC_EXCEPTIONS = YES; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + MACOSX_DEPLOYMENT_TARGET = 10.8; + SDKROOT = macosx10.8; + }; + name = Release; + }; + 573847611820CDA000443653 /* Debug */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 74019794B7AD12641993FBE9 /* Pods.debug.xcconfig */; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + COMBINE_HIDPI_IMAGES = YES; + FRAMEWORK_SEARCH_PATHS = "$(SRCROOT)"; + GCC_PRECOMPILE_PREFIX_HEADER = YES; + GCC_PREFIX_HEADER = "TeamTalk/TeamTalk-Prefix.pch"; + INFOPLIST_FILE = "TeamTalk/TeamTalk-Info.plist"; + LD_RUNPATH_SEARCH_PATHS = "$(SRCROOT)"; + LIBRARY_SEARCH_PATHS = ( + "$(inherited)", + "$(SDKROOT)/usr/lib/system", + "$(USER_LIBRARY_DIR)/Developer/Xcode/DerivedData/Duoduo-ecacnztivbkeggegyktnermxjnpy/Build/Products/Debug", + /Users/golastroom/Downloads, + "$(PROJECT_DIR)", + ); + MACOSX_DEPLOYMENT_TARGET = 10.8; + OTHER_CODE_SIGN_FLAGS = "--deep"; + PRODUCT_NAME = TeamTalk; + SDKROOT = macosx10.9; + USER_HEADER_SEARCH_PATHS = "$(PODS_ROOT)"; + WRAPPER_EXTENSION = app; + }; + name = Debug; + }; + 573847621820CDA000443653 /* Release */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 535EC6602DDC418112EEFEF8 /* Pods.release.xcconfig */; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + COMBINE_HIDPI_IMAGES = YES; + FRAMEWORK_SEARCH_PATHS = "$(SRCROOT)"; + GCC_PRECOMPILE_PREFIX_HEADER = YES; + GCC_PREFIX_HEADER = "TeamTalk/TeamTalk-Prefix.pch"; + INFOPLIST_FILE = "TeamTalk/TeamTalk-Info.plist"; + LD_RUNPATH_SEARCH_PATHS = "$(SRCROOT)"; + LIBRARY_SEARCH_PATHS = ( + "$(inherited)", + "$(SDKROOT)/usr/lib/system", + "$(USER_LIBRARY_DIR)/Developer/Xcode/DerivedData/Duoduo-ecacnztivbkeggegyktnermxjnpy/Build/Products/Debug", + /Users/golastroom/Downloads, + "$(PROJECT_DIR)", + ); + MACOSX_DEPLOYMENT_TARGET = 10.8; + OTHER_CODE_SIGN_FLAGS = "--deep"; + PRODUCT_NAME = TeamTalk; + SDKROOT = macosx10.9; + USER_HEADER_SEARCH_PATHS = "$(PODS_ROOT)"; + WRAPPER_EXTENSION = app; + }; + name = Release; + }; +/* End XCBuildConfiguration section */ + +/* Begin XCConfigurationList section */ + 5738472A1820CDA000443653 /* Build configuration list for PBXProject "TeamTalk" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 5738475E1820CDA000443653 /* Debug */, + 5738475F1820CDA000443653 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 573847601820CDA000443653 /* Build configuration list for PBXNativeTarget "TeamTalk" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 573847611820CDA000443653 /* Debug */, + 573847621820CDA000443653 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; +/* End XCConfigurationList section */ + }; + rootObject = 573847271820CDA000443653 /* Project object */; +} diff --git a/mac/TeamTalk.xcodeproj/project.xcworkspace/contents.xcworkspacedata b/mac/TeamTalk.xcodeproj/project.xcworkspace/contents.xcworkspacedata new file mode 100644 index 000000000..5875c6274 --- /dev/null +++ b/mac/TeamTalk.xcodeproj/project.xcworkspace/contents.xcworkspacedata @@ -0,0 +1,7 @@ + + + + + diff --git a/mac/TeamTalk.xcworkspace/contents.xcworkspacedata b/mac/TeamTalk.xcworkspace/contents.xcworkspacedata new file mode 100644 index 000000000..6efd2cafe --- /dev/null +++ b/mac/TeamTalk.xcworkspace/contents.xcworkspacedata @@ -0,0 +1,10 @@ + + + + + + + diff --git a/mac/TeamTalk/221.gif b/mac/TeamTalk/221.gif new file mode 100755 index 000000000..d75703ebf Binary files /dev/null and b/mac/TeamTalk/221.gif differ diff --git a/mac/TeamTalk/222.gif b/mac/TeamTalk/222.gif new file mode 100755 index 000000000..52883dd44 Binary files /dev/null and b/mac/TeamTalk/222.gif differ diff --git a/mac/TeamTalk/223.gif b/mac/TeamTalk/223.gif new file mode 100755 index 000000000..54636150d Binary files /dev/null and b/mac/TeamTalk/223.gif differ diff --git a/mac/TeamTalk/224.gif b/mac/TeamTalk/224.gif new file mode 100755 index 000000000..f7f9be2ae Binary files /dev/null and b/mac/TeamTalk/224.gif differ diff --git a/mac/TeamTalk/225.gif b/mac/TeamTalk/225.gif new file mode 100755 index 000000000..5ea900f8c Binary files /dev/null and b/mac/TeamTalk/225.gif differ diff --git a/mac/TeamTalk/226.gif b/mac/TeamTalk/226.gif new file mode 100755 index 000000000..724fe54cf Binary files /dev/null and b/mac/TeamTalk/226.gif differ diff --git a/mac/TeamTalk/227.gif b/mac/TeamTalk/227.gif new file mode 100755 index 000000000..a93f49f8d Binary files /dev/null and b/mac/TeamTalk/227.gif differ diff --git a/mac/TeamTalk/228.gif b/mac/TeamTalk/228.gif new file mode 100755 index 000000000..5ce7c7b09 Binary files /dev/null and b/mac/TeamTalk/228.gif differ diff --git a/mac/TeamTalk/229.gif b/mac/TeamTalk/229.gif new file mode 100755 index 000000000..86512d3c1 Binary files /dev/null and b/mac/TeamTalk/229.gif differ diff --git a/mac/TeamTalk/230.gif b/mac/TeamTalk/230.gif new file mode 100755 index 000000000..7064b50d9 Binary files /dev/null and b/mac/TeamTalk/230.gif differ diff --git a/mac/TeamTalk/231.gif b/mac/TeamTalk/231.gif new file mode 100755 index 000000000..276161541 Binary files /dev/null and b/mac/TeamTalk/231.gif differ diff --git a/mac/TeamTalk/232.gif b/mac/TeamTalk/232.gif new file mode 100755 index 000000000..f913f56e5 Binary files /dev/null and b/mac/TeamTalk/232.gif differ diff --git a/mac/TeamTalk/233.gif b/mac/TeamTalk/233.gif new file mode 100755 index 000000000..656eb7904 Binary files /dev/null and b/mac/TeamTalk/233.gif differ diff --git a/mac/TeamTalk/234.gif b/mac/TeamTalk/234.gif new file mode 100755 index 000000000..b46680c23 Binary files /dev/null and b/mac/TeamTalk/234.gif differ diff --git a/mac/TeamTalk/235.gif b/mac/TeamTalk/235.gif new file mode 100755 index 000000000..f129cf3d4 Binary files /dev/null and b/mac/TeamTalk/235.gif differ diff --git a/mac/TeamTalk/236.gif b/mac/TeamTalk/236.gif new file mode 100755 index 000000000..35cc1148d Binary files /dev/null and b/mac/TeamTalk/236.gif differ diff --git a/mac/TeamTalk/237.gif b/mac/TeamTalk/237.gif new file mode 100755 index 000000000..0bfa22f79 Binary files /dev/null and b/mac/TeamTalk/237.gif differ diff --git a/mac/TeamTalk/238.gif b/mac/TeamTalk/238.gif new file mode 100755 index 000000000..9edcf90af Binary files /dev/null and b/mac/TeamTalk/238.gif differ diff --git a/mac/TeamTalk/239.gif b/mac/TeamTalk/239.gif new file mode 100755 index 000000000..6ca6e0d7e Binary files /dev/null and b/mac/TeamTalk/239.gif differ diff --git a/mac/TeamTalk/240.gif b/mac/TeamTalk/240.gif new file mode 100755 index 000000000..58662e29e Binary files /dev/null and b/mac/TeamTalk/240.gif differ diff --git a/mac/TeamTalk/API/APIGroup/DDAllUserAPI.h b/mac/TeamTalk/API/APIGroup/DDAllUserAPI.h new file mode 100644 index 000000000..84c65d6e5 --- /dev/null +++ b/mac/TeamTalk/API/APIGroup/DDAllUserAPI.h @@ -0,0 +1,13 @@ +// +// DDAllUserAPI.h +// Duoduo +// +// Created by 独嘉 on 14-5-7. +// Copyright (c) 2014年 zuoye. All rights reserved. +// + +#import "DDSuperAPI.h" + +@interface DDAllUserAPI : DDSuperAPI + +@end diff --git a/mac/TeamTalk/API/APIGroup/DDAllUserAPI.m b/mac/TeamTalk/API/APIGroup/DDAllUserAPI.m new file mode 100644 index 000000000..72eec6a88 --- /dev/null +++ b/mac/TeamTalk/API/APIGroup/DDAllUserAPI.m @@ -0,0 +1,115 @@ +// +// DDAllUserAPI.m +// Duoduo +// +// Created by 独嘉 on 14-5-7. +// Copyright (c) 2014年 zuoye. All rights reserved. +// + +#import "DDAllUserAPI.h" +#import "MTUserEntity.h" +#import "IMBuddy.pb.h" + +@implementation DDAllUserAPI +/** + * 请求超时时间 + * + * @return 超时时间 + */ +- (int)requestTimeOutTimeInterval +{ + return 20; +} + +/** + * 请求的serviceID + * + * @return 对应的serviceID + */ +- (int)requestServiceID +{ + return MODULE_ID_SESSION; +} + +/** + * 请求返回的serviceID + * + * @return 对应的serviceID + */ +- (int)responseServiceID +{ + return MODULE_ID_SESSION; +} + +/** + * 请求的commendID + * + * @return 对应的commendID + */ +- (int)requestCommendID +{ + return CMD_FRI_ALL_USER_REQ; +} + +/** + * 请求返回的commendID + * + * @return 对应的commendID + */ +- (int)responseCommendID +{ + return CMD_FRI_ALL_USER_RES; +} + +/** + * 解析数据的block + * + * @return 解析数据的block + */ +- (Analysis)analysisReturnData +{ + + Analysis analysis = (id)^(NSData* data) + { + IMAllUserRsp *allUserRsp = [IMAllUserRsp parseFromData:data]; + uint32_t latestUpdateTime = allUserRsp.latestUpdateTime; + NSMutableDictionary *userAndVersion = [NSMutableDictionary new]; + [userAndVersion setObject:@(latestUpdateTime) forKey:@"latestUpdateTime"]; + NSMutableArray *userList = [[NSMutableArray alloc] init]; + for (UserInfo *userInfo in allUserRsp.userList) { + MTUserEntity *user = [[MTUserEntity alloc] initWithUserInfo:userInfo]; + [userList addObject:user]; + } + + [userAndVersion setObject:userList forKey:@"userlist"]; + return userAndVersion; + }; + return analysis; +} + +/** + * 打包数据的block + * + * @return 打包数据的block + */ +- (Package)packageRequestObject +{ + Package package = (id)^(id object,uint32_t seqNo) + { + IMAllUserReqBuilder *reqBuilder = [IMAllUserReq builder]; + NSInteger latestUpdateTime = [object[0] integerValue]; + [reqBuilder setUserId:0]; + [reqBuilder setLatestUpdateTime:(UInt32)latestUpdateTime]; + + DataOutputStream *dataout = [[DataOutputStream alloc] init]; + [dataout writeInt:0]; + [dataout writeTcpProtocolHeader:MODULE_ID_SESSION + cId:CMD_FRI_ALL_USER_REQ + seqNo:seqNo]; + [dataout directWriteBytes:[reqBuilder build].data]; + [dataout writeDataCount]; + return [dataout toByteArray]; + }; + return package; +} +@end diff --git a/mac/TeamTalk/API/APIGroup/DDCreateGroupAPI.h b/mac/TeamTalk/API/APIGroup/DDCreateGroupAPI.h new file mode 100644 index 000000000..0287c1390 --- /dev/null +++ b/mac/TeamTalk/API/APIGroup/DDCreateGroupAPI.h @@ -0,0 +1,16 @@ +// +// DDCreateGroupAPI.h +// Duoduo +// +// Created by 独嘉 on 14-5-8. +// Copyright (c) 2014年 zuoye. All rights reserved. +// + +#import "DDSuperAPI.h" + +/** + * 创建讨论组,object为数组,index1:groupName,index2:groupAvatar,index3:userlist + */ +@interface DDCreateGroupAPI : DDSuperAPI + +@end diff --git a/mac/TeamTalk/API/APIGroup/DDCreateGroupAPI.m b/mac/TeamTalk/API/APIGroup/DDCreateGroupAPI.m new file mode 100644 index 000000000..ddd160562 --- /dev/null +++ b/mac/TeamTalk/API/APIGroup/DDCreateGroupAPI.m @@ -0,0 +1,137 @@ +// +// DDCreateGroupAPI.m +// Duoduo +// +// Created by 独嘉 on 14-5-8. +// Copyright (c) 2014年 zuoye. All rights reserved. +// + +#import "DDCreateGroupAPI.h" +#import "MTGroupEntity.h" +#import "IMGroup.pb.h" +#import "DataOutputStream+Addition.h" + +@implementation DDCreateGroupAPI +/** + * 请求超时时间 + * + * @return 超时时间 + */ +- (int)requestTimeOutTimeInterval +{ + return 5; +} + +/** + * 请求的serviceID + * + * @return 对应的serviceID + */ +- (int)requestServiceID +{ + return SERVICE_GROUP; +} + +/** + * 请求返回的serviceID + * + * @return 对应的serviceID + */ +- (int)responseServiceID +{ + return SERVICE_GROUP; +} + +/** + * 请求的commendID + * + * @return 对应的commendID + */ +- (int)requestCommendID +{ + return CMD_ID_GROUP_CREATE_TMP_GROUP_REQ; +} + +/** + * 请求返回的commendID + * + * @return 对应的commendID + */ +- (int)responseCommendID +{ + return CMD_ID_GROUP_CREATE_TMP_GROUP_RES; +} + +/** + * 解析数据的block + * + * @return 解析数据的block + */ +- (Analysis)analysisReturnData +{ + Analysis analysis = (id)^(NSData* data) + { + IMGroupCreateRsp *rsp = [IMGroupCreateRsp parseFromData:data]; + uint32_t result = rsp.resultCode; + MTGroupEntity* group = nil; + if (result != 0) + { + return group; + } + else + { + NSString* creatorId = [NSString stringWithFormat:@"%d",rsp.userId]; + NSString *groupId = [NSString stringWithFormat:@"%d", rsp.groupId]; + NSString *groupName = rsp.groupName; + NSInteger userCnt =[rsp.userIdList count]; + + NSMutableArray* groupUserIds = [[NSMutableArray alloc] init]; + + for (uint32_t i = 0; i < userCnt; i++) { + NSInteger userIdFromServer = [rsp.userIdList[i] integerValue]; + NSString* userId = [NSString stringWithFormat:@"%ld", userIdFromServer]; + [groupUserIds addObject:userId]; + } + group = [[MTGroupEntity alloc] initWithGroupID:groupId groupType:DDTmpGroupType name:groupName avatar:@"" creatorId:creatorId shieldStatus:NO groupUserIds:groupUserIds version:1]; + return group; + } + }; + return analysis; +} + +/** + * 打包数据的block + * + * @return 打包数据的block + */ +- (Package)packageRequestObject +{ + Package package = (id)^(id object,uint16_t seqNo) + { + NSArray* array = (NSArray*)object; + NSString* groupName = array[0]; + NSString* groupAvatar = array[1]; + NSArray* groupUserList = array[2]; + + IMGroupCreateReqBuilder *req = [IMGroupCreateReq builder]; + [req setUserId:0]; + [req setGroupName:groupName]; + [req setGroupAvatar:groupAvatar]; + [req setGroupType:GroupTypeGroupTypeTmp]; + NSMutableArray *originalID = [NSMutableArray new]; + for (NSString *localID in groupUserList) { + int groupId = [localID intValue]; + [originalID addObject: @(groupId)]; + } + [req setMemberIdListArray:originalID]; + DataOutputStream *dataout = [[DataOutputStream alloc] init]; + [dataout writeInt:0]; + [dataout writeTcpProtocolHeader:SERVICE_GROUP + cId:CMD_ID_GROUP_CREATE_TMP_GROUP_REQ + seqNo:seqNo]; + [dataout directWriteBytes:[req build].data]; + [dataout writeDataCount]; + return [dataout toByteArray]; + }; + return package;} +@end diff --git a/mac/TeamTalk/API/APIGroup/DDDepartmentInfoAPI.h b/mac/TeamTalk/API/APIGroup/DDDepartmentInfoAPI.h new file mode 100644 index 000000000..b0fa057dd --- /dev/null +++ b/mac/TeamTalk/API/APIGroup/DDDepartmentInfoAPI.h @@ -0,0 +1,13 @@ +// +// DDDepartmentInfoAPI.h +// Duoduo +// +// Created by zuoye on 15/3/17. +// Copyright (c) 2015年 mogujie. All rights reserved. +// + +#import "DDSuperAPI.h" + +@interface DDDepartmentInfoAPI : DDSuperAPI + +@end diff --git a/mac/TeamTalk/API/APIGroup/DDDepartmentInfoAPI.m b/mac/TeamTalk/API/APIGroup/DDDepartmentInfoAPI.m new file mode 100644 index 000000000..d424b04de --- /dev/null +++ b/mac/TeamTalk/API/APIGroup/DDDepartmentInfoAPI.m @@ -0,0 +1,122 @@ +// +// DDDepartmentInfoAPI.m +// Duoduo +// +// Created by zuoye on 15/3/17. +// Copyright (c) 2015年 mogujie. All rights reserved. +// + +#import "DDDepartmentInfoAPI.h" +#import "IMBuddy.pb.h" +#import "MTDepartmentEntity.h" +@implementation DDDepartmentInfoAPI +/** + * 请求超时时间 + * + * @return 超时时间 + */ +- (int)requestTimeOutTimeInterval +{ + return 20; +} + +/** + * 请求的serviceID + * + * @return 对应的serviceID + */ +- (int)requestServiceID +{ + return MODULE_ID_SESSION; +} + +/** + * 请求返回的serviceID + * + * @return 对应的serviceID + */ +- (int)responseServiceID +{ + return MODULE_ID_SESSION; +} + +/** + * 请求的commendID + * + * @return 对应的commendID + */ +- (int)requestCommendID +{ + return CMD_FRI_LIST_DEPARTMENT_REQ; +} + +/** + * 请求返回的commendID + * + * @return 对应的commendID + */ +- (int)responseCommendID +{ + return CMD_FRI_LIST_DEPARTMENT_RES; +} + +/** + * 解析数据的block + * + * @return 解析数据的block + */ +- (Analysis)analysisReturnData +{ + + Analysis analysis = (id)^(NSData* data) + { + IMDepartmentRsp *departRsp = [IMDepartmentRsp parseFromData:data]; + NSInteger lastUpdateTime = departRsp.latestUpdateTime; + NSArray* departments = departRsp.deptList; + + NSMutableArray* theDepartments = [[NSMutableArray alloc] init]; + for (DepartInfo * departInfo in departments) + { + MTDepartmentEntity* departmentEntity = [[MTDepartmentEntity alloc] initWithDepartmentInfo:departInfo]; + [theDepartments addObject:departmentEntity]; + } + + NSDictionary* response = @{@"lastUpdateTime":@(lastUpdateTime),@"departments":theDepartments}; + + return response; + }; + return analysis; +} + +/** + * 打包数据的block + * + * @return 打包数据的block + */ +- (Package)packageRequestObject +{ + Package package = (id)^(id object,uint32_t seqNo) + { + IMDepartmentReqBuilder* requestBuilder = [IMDepartmentReq builder]; + + NSArray* array = (NSArray*)object; + + UInt32 lastestUpdateTime = [array[0] intValue]; + + UInt32 userID = [[DDClientState shareInstance].userID intValue]; + [requestBuilder setUserId:userID]; + + [requestBuilder setLatestUpdateTime:lastestUpdateTime]; + + DataOutputStream *dataout = [[DataOutputStream alloc] init]; + [dataout writeInt:0]; + [dataout writeTcpProtocolHeader:MODULE_ID_SESSION + cId:CMD_FRI_LIST_DEPARTMENT_REQ + seqNo:seqNo]; + [dataout directWriteBytes:[requestBuilder build].data]; + [dataout writeDataCount]; + return [dataout toByteArray]; + }; + return package; +} +@end diff --git a/mac/TeamTalk/API/APIGroup/DDFileLoginAPI.h b/mac/TeamTalk/API/APIGroup/DDFileLoginAPI.h new file mode 100644 index 000000000..51ab0fda4 --- /dev/null +++ b/mac/TeamTalk/API/APIGroup/DDFileLoginAPI.h @@ -0,0 +1,13 @@ +// +// DDFileLoginAPI.h +// Duoduo +// +// Created by 独嘉 on 14-5-9. +// Copyright (c) 2014年 zuoye. All rights reserved. +// + +#import "DDSuperAPI.h" + +@interface DDFileLoginAPI : DDSuperAPI + +@end diff --git a/mac/TeamTalk/API/APIGroup/DDFileLoginAPI.m b/mac/TeamTalk/API/APIGroup/DDFileLoginAPI.m new file mode 100644 index 000000000..584ed99de --- /dev/null +++ b/mac/TeamTalk/API/APIGroup/DDFileLoginAPI.m @@ -0,0 +1,107 @@ +// +// DDFileLoginAPI.m +// Duoduo +// +// Created by 独嘉 on 14-5-9. +// Copyright (c) 2014年 zuoye. All rights reserved. +// + +#import "DDFileLoginAPI.h" + +@implementation DDFileLoginAPI +/** + * 请求超时时间 + * + * @return 超时时间 + */ +- (int)requestTimeOutTimeInterval +{ + return 2; +} + +/** + * 请求的serviceID + * + * @return 对应的serviceID + */ +- (int)requestServiceID +{ + return MODULE_ID_FILETRANSFER; +} + +/** + * 请求返回的serviceID + * + * @return 对应的serviceID + */ +- (int)responseServiceID +{ + return MODULE_ID_FILETRANSFER; +} + +/** + * 请求的commendID + * + * @return 对应的commendID + */ +- (int)requestCommendID +{ + return CMD_FILE_LOGIN_REQ; +} + +/** + * 请求返回的commendID + * + * @return 对应的commendID + */ +- (int)responseCommendID +{ + return CMD_FILE_LOGIN_RES; +} + +/** + * 解析数据的block + * + * @return 解析数据的block + */ +- (Analysis)analysisReturnData +{ + Analysis analysis = (id)^(NSData* data) + { + DataInputStream *inputData = [DataInputStream dataInputStreamWithData:data]; + uint32_t result = [inputData readInt]; + DDLog(@"handleFileLoginRes, result=%d", result); + return [NSNumber numberWithInt:result]; + }; + return analysis; +} + +/** + * 打包数据的block + * + * @return 打包数据的block + */ +- (Package)packageRequestObject +{ + Package package = (id)^(id object,uint16_t seqNo) + { + NSArray* array = (NSArray*)object; + NSString* userId = array[0]; + NSString* token = array[1]; + + DataOutputStream *dataout = [[DataOutputStream alloc] init]; + uint32_t totalLen = 8 + IM_PDU_HEADER_LEN + + (uint32_t)[[userId dataUsingEncoding:NSUTF8StringEncoding] length] + + (uint32_t)[[token dataUsingEncoding:NSUTF8StringEncoding] length]; + + [dataout writeInt:totalLen]; + [dataout writeTcpProtocolHeader:MODULE_ID_FILETRANSFER cId:CMD_FILE_LOGIN_REQ seqNo:seqNo]; + [dataout writeUTF:userId]; + [dataout writeUTF:token]; + log4CInfo(@"serviceID:%i cmdID:%i --> login file server userID:%@ token:%@", + MODULE_ID_FILETRANSFER, CMD_FILE_LOGIN_REQ, userId,token); + return [dataout toByteArray]; + }; + return package; +} +@end diff --git a/mac/TeamTalk/API/APIGroup/DDFileSendAPI.h b/mac/TeamTalk/API/APIGroup/DDFileSendAPI.h new file mode 100644 index 000000000..32d745f86 --- /dev/null +++ b/mac/TeamTalk/API/APIGroup/DDFileSendAPI.h @@ -0,0 +1,16 @@ +// +// DDFileSendAPI.h +// Duoduo +// +// Created by 独嘉 on 14-5-9. +// Copyright (c) 2014年 zuoye. All rights reserved. +// + +#import "DDSuperAPI.h" + +/** + * 发送文件请求,object为数组,index0:fromID,index1:toID,index2:fileName,index3:fileSize + */ +@interface DDFileSendAPI : DDSuperAPI + +@end diff --git a/mac/TeamTalk/API/APIGroup/DDFileSendAPI.m b/mac/TeamTalk/API/APIGroup/DDFileSendAPI.m new file mode 100644 index 000000000..ec1900a06 --- /dev/null +++ b/mac/TeamTalk/API/APIGroup/DDFileSendAPI.m @@ -0,0 +1,104 @@ +// +// DDFileSendAPI.m +// Duoduo +// +// Created by 独嘉 on 14-5-9. +// Copyright (c) 2014年 zuoye. All rights reserved. +// + +#import "DDFileSendAPI.h" + +@implementation DDFileSendAPI +/** + * 请求超时时间 + * + * @return 超时时间 + */ +- (int)requestTimeOutTimeInterval +{ + return 0; +} + +/** + * 请求的serviceID + * + * @return 对应的serviceID + */ +- (int)requestServiceID +{ + return MODULE_ID_FILETRANSFER; +} + +/** + * 请求返回的serviceID + * + * @return 对应的serviceID + */ +- (int)responseServiceID +{ + return 0; +} + +/** + * 请求的commendID + * + * @return 对应的commendID + */ +- (int)requestCommendID +{ + return CMD_FILE_REQUEST; +} + +/** + * 请求返回的commendID + * + * @return 对应的commendID + */ +- (int)responseCommendID +{ + return 0; +} + +/** + * 解析数据的block + * + * @return 解析数据的block + */ +- (Analysis)analysisReturnData +{ + return nil; +} + +/** + * 打包数据的block + * + * @return 打包数据的block + */ +- (Package)packageRequestObject +{ + Package package = (id)^(id object,uint16_t seqNo) + { + + NSArray* array = (NSArray*)object; + NSString* fromUserId = array[0]; + NSString* toUserId = array[1]; + NSString* fileName = array[2]; + uint32_t fileSize = [array[3] intValue]; + + + DataOutputStream *dataout = [[DataOutputStream alloc] init]; + uint32_t totalLen = IM_PDU_HEADER_LEN + 4 * 4 + + strLen(fromUserId) + strLen(toUserId) + strLen(fileName); + + [dataout writeInt:totalLen]; + [dataout writeTcpProtocolHeader:MODULE_ID_FILETRANSFER cId:CMD_FILE_REQUEST seqNo:seqNo]; + [dataout writeUTF:fromUserId]; + [dataout writeUTF:toUserId]; + [dataout writeUTF:fileName]; + [dataout writeInt:fileSize]; + log4CInfo(@"serviceID:%i cmdID:%i --> get file request from user:%@ to user:%@ fileName:%@ fileSize:%i",MODULE_ID_FILETRANSFER,CMD_FILE_REQUEST,fromUserId,toUserId,fileName,fileSize); + return [dataout toByteArray]; + }; + return package; +} +@end diff --git a/mac/TeamTalk/API/APIGroup/DDFileSendResponseAPI.h b/mac/TeamTalk/API/APIGroup/DDFileSendResponseAPI.h new file mode 100644 index 000000000..07a9f95e9 --- /dev/null +++ b/mac/TeamTalk/API/APIGroup/DDFileSendResponseAPI.h @@ -0,0 +1,13 @@ +// +// DDFileSendResponseAPI.h +// Duoduo +// +// Created by 独嘉 on 14-5-12. +// Copyright (c) 2014年 zuoye. All rights reserved. +// + +#import "DDSuperAPI.h" + +@interface DDFileSendResponseAPI : DDSuperAPI + +@end diff --git a/mac/TeamTalk/API/APIGroup/DDFileSendResponseAPI.m b/mac/TeamTalk/API/APIGroup/DDFileSendResponseAPI.m new file mode 100644 index 000000000..da5ee5fe2 --- /dev/null +++ b/mac/TeamTalk/API/APIGroup/DDFileSendResponseAPI.m @@ -0,0 +1,106 @@ +// +// DDFileSendResponseAPI.m +// Duoduo +// +// Created by 独嘉 on 14-5-12. +// Copyright (c) 2014年 zuoye. All rights reserved. +// + +#import "DDFileSendResponseAPI.h" + +@implementation DDFileSendResponseAPI +/** + * 请求超时时间 + * + * @return 超时时间 + */ +- (int)requestTimeOutTimeInterval +{ + return 0; +} + +/** + * 请求的serviceID + * + * @return 对应的serviceID + */ +- (int)requestServiceID +{ + return MODULE_ID_FILETRANSFER; +} + +/** + * 请求返回的serviceID + * + * @return 对应的serviceID + */ +- (int)responseServiceID +{ + return 0; +} + +/** + * 请求的commendID + * + * @return 对应的commendID + */ +- (int)requestCommendID +{ + return CMD_FILE_RESPONSE; +} + +/** + * 请求返回的commendID + * + * @return 对应的commendID + */ +- (int)responseCommendID +{ + return 0; +} + +/** + * 解析数据的block + * + * @return 解析数据的block + */ +- (Analysis)analysisReturnData +{ + return nil; +} + +/** + * 打包数据的block + * + * @return 打包数据的block + */ +- (Package)packageRequestObject +{ + Package package = (id)^(id object,uint16_t seqNo) + { + NSArray* array = (NSArray*)object; + NSString* fromUserId = array[0]; + NSString* toUserId = array[1]; + NSString* fileName = array[2]; + int acceptFlag = [array[3] intValue]; + NSString* listenIp = nil; + int listenPort = 0; + + DataOutputStream *dataout = [[DataOutputStream alloc] init]; + uint32_t totalLen = IM_PDU_HEADER_LEN + 4 * 5 + 2 + + strLen(fromUserId) + strLen(toUserId) + strLen(fileName); + + [dataout writeInt:totalLen]; + [dataout writeTcpProtocolHeader:MODULE_ID_FILETRANSFER cId:CMD_FILE_RESPONSE seqNo:seqNo]; + [dataout writeUTF:fromUserId]; + [dataout writeUTF:toUserId]; + [dataout writeUTF:fileName]; + [dataout writeInt:acceptFlag]; + [dataout writeUTF:listenIp]; + [dataout writeShort:listenPort]; + log4CInfo(@"serviceID:%i cmdID:%i --> send file get response from user:%@ to user:%@ fileName:%@ acceptType:%i listenIP:%@ listenPort:%i",MODULE_ID_FILETRANSFER,CMD_FILE_RESPONSE,fromUserId,toUserId,fileName,acceptFlag,listenIp,listenPort); + return [dataout toByteArray]; + }; + return package; +} +@end diff --git a/mac/TeamTalk/API/APIGroup/DDFixedGroupAPI.h b/mac/TeamTalk/API/APIGroup/DDFixedGroupAPI.h new file mode 100644 index 000000000..a472cc63c --- /dev/null +++ b/mac/TeamTalk/API/APIGroup/DDFixedGroupAPI.h @@ -0,0 +1,13 @@ +// +// DDFixedGroupAPI.h +// Duoduo +// +// Created by 独嘉 on 14-5-6. +// Copyright (c) 2014年 zuoye. All rights reserved. +// + +#import "DDSuperAPI.h" + +@interface DDFixedGroupAPI : DDSuperAPI + +@end diff --git a/mac/TeamTalk/API/APIGroup/DDFixedGroupAPI.m b/mac/TeamTalk/API/APIGroup/DDFixedGroupAPI.m new file mode 100644 index 000000000..6860c5d7d --- /dev/null +++ b/mac/TeamTalk/API/APIGroup/DDFixedGroupAPI.m @@ -0,0 +1,112 @@ +// +// DDFixedGroupAPI.m +// Duoduo +// +// Created by 独嘉 on 14-5-6. +// Copyright (c) 2014年 zuoye. All rights reserved. +// + +#import "DDFixedGroupAPI.h" +#import "MTGroupEntity.h" +#import "IMGroup.pb.h" +#import "DataOutputStream+Addition.h" +@implementation DDFixedGroupAPI +/** + * 请求超时时间 + * + * @return 超时时间 + */ +- (int)requestTimeOutTimeInterval +{ + return 10; +} + +/** + * 请求的serviceID + * + * @return 对应的serviceID + */ +- (int)requestServiceID +{ + return ServiceIDSidGroup; +} + +/** + * 请求返回的serviceID + * + * @return 对应的serviceID + */ +- (int)responseServiceID +{ + return ServiceIDSidGroup; +} + +/** + * 请求的commendID + * + * @return 对应的commendID + */ +- (int)requestCommendID +{ + return GroupCmdIDCidGroupNormalListRequest; +} + +/** + * 请求返回的commendID + * + * @return 对应的commendID + */ +- (int)responseCommendID +{ + return GroupCmdIDCidGroupNormalListResponse; +} + +/** + * 解析数据的block + * + * @return 解析数据的block + */ +- (Analysis)analysisReturnData +{ + Analysis analysis = (id)^(NSData* data) + { + IMNormalGroupListRsp *allGroupRsp = [IMNormalGroupListRsp parseFromData:data]; + NSMutableDictionary *groupIdAndVersion = [NSMutableDictionary new]; + NSMutableArray* groupList = [[NSMutableArray alloc] init]; + for (GroupVersionInfo *groupVersionInfo in allGroupRsp.groupVersionList) { + NSString* groupId = [[NSNumber numberWithInt:groupVersionInfo.groupId] stringValue]; + NSString* version = [[NSNumber numberWithInt:groupVersionInfo.version] stringValue]; + NSMutableDictionary* groupVersion = [NSMutableDictionary dictionaryWithObjectsAndKeys:groupId,@"groupId",version,@"version",nil]; + [groupList addObject:groupVersion]; + } + [groupIdAndVersion setObject:groupList forKey:@"groupVersionList"]; + return groupIdAndVersion; + }; + return analysis; +} + +/** + * 打包数据的block + * + * @return 打包数据的block + */ +- (Package)packageRequestObject +{ + Package package = (id)^(id object,uint16_t seqNo) + { + IMNormalGroupListReqBuilder *req = [IMNormalGroupListReq builder]; + + UInt32 reqUserId = [[object objectForKey:@"reqUserId"] intValue]; + [req setUserId:reqUserId]; + DataOutputStream *dataout = [[DataOutputStream alloc] init]; + [dataout writeInt:0]; + [dataout writeTcpProtocolHeader:[self requestServiceID] + cId:[self requestCommendID] + seqNo:seqNo]; + [dataout directWriteBytes:[req build].data]; + [dataout writeDataCount]; + return [dataout toByteArray]; + }; + return package; +} +@end diff --git a/mac/TeamTalk/API/APIGroup/DDGetLastMessageIDAPI.h b/mac/TeamTalk/API/APIGroup/DDGetLastMessageIDAPI.h new file mode 100644 index 000000000..e7b7f4e16 --- /dev/null +++ b/mac/TeamTalk/API/APIGroup/DDGetLastMessageIDAPI.h @@ -0,0 +1,13 @@ +// +// DDGetLastMessageIDAPI.h +// Duoduo +// +// Created by 独嘉 on 15/3/3. +// Copyright (c) 2015年 mogujie. All rights reserved. +// + +#import "DDSuperAPI.h" +//sessionType,originID +@interface DDGetLastMessageIDAPI : DDSuperAPI + +@end diff --git a/mac/TeamTalk/API/APIGroup/DDGetLastMessageIDAPI.m b/mac/TeamTalk/API/APIGroup/DDGetLastMessageIDAPI.m new file mode 100644 index 000000000..65e402c58 --- /dev/null +++ b/mac/TeamTalk/API/APIGroup/DDGetLastMessageIDAPI.m @@ -0,0 +1,112 @@ +// +// DDGetLastMessageIDAPI.m +// Duoduo +// +// Created by 独嘉 on 15/3/3. +// Copyright (c) 2015年 mogujie. All rights reserved. +// + +#import "DDGetLastMessageIDAPI.h" +#import "IMMessage.pb.h" +@implementation DDGetLastMessageIDAPI +/** + * 请求超时时间 + * + * @return 超时时间 + */ +- (int)requestTimeOutTimeInterval +{ + return 8; +} + +/** + * 请求的serviceID + * + * @return 对应的serviceID + */ +- (int)requestServiceID +{ + return DDSERVICE_MESSAGE; +} + +/** + * 请求返回的serviceID + * + * @return 对应的serviceID + */ +- (int)responseServiceID +{ + return DDSERVICE_MESSAGE; +} + +/** + * 请求的commendID + * + * @return 对应的commendID + */ +- (int)requestCommendID +{ + return CMD_MSG_GET_LASTEST_MSG_ID_REQ; +} + +/** + * 请求返回的commendID + * + * @return 对应的commendID + */ +- (int)responseCommendID +{ + return CMD_MSG_GET_LASTEST_MSG_ID_RES; +} + +/** + * 解析数据的block + * + * @return 解析数据的block + */ +- (Analysis)analysisReturnData +{ + Analysis analysis = (id)^(NSData* data) + { + IMGetLatestMsgIdRsp* getLastestMsgIDRsp = [IMGetLatestMsgIdRsp parseFromData:data]; +// NSString* requestUserID = [NSString stringWithFormat:@"%i",getLastestMsgIDRsp.userId]; +// SessionType sessionType = getLastestMsgIDRsp.sessionType; +// NSString* originID = [NSString stringWithFormat:@"%i",getLastestMsgIDRsp.sessionId]; + int lastMsgId = getLastestMsgIDRsp.latestMsgId; + + return @(lastMsgId); + }; + return analysis; +} + +/** + * 打包数据的block + * + * @return 打包数据的block + */ +- (Package)packageRequestObject +{ + Package package = (id)^(id object,uint16_t seqNo) + { + IMGetLatestMsgIdReqBuilder *req = [IMGetLatestMsgIdReq builder]; + [req setUserId:[[DDClientState shareInstance].userID intValue]]; + + NSArray* array = (NSArray*)object; + SessionType sessionType = [array[0] intValue]; + int originID = [array[1] intValue]; + + [req setSessionType:sessionType]; + [req setSessionId:originID]; + + DataOutputStream *dataout = [[DataOutputStream alloc] init]; + [dataout writeInt:0]; + [dataout writeTcpProtocolHeader:DDSERVICE_MESSAGE + cId:CMD_MSG_GET_LASTEST_MSG_ID_REQ + seqNo:seqNo]; + [dataout directWriteBytes:[req build].data]; + [dataout writeDataCount]; + return [dataout toByteArray]; + }; + return package; +} +@end diff --git a/mac/TeamTalk/API/APIGroup/DDGetOfflineFileAPI.h b/mac/TeamTalk/API/APIGroup/DDGetOfflineFileAPI.h new file mode 100644 index 000000000..ca5c0e6a4 --- /dev/null +++ b/mac/TeamTalk/API/APIGroup/DDGetOfflineFileAPI.h @@ -0,0 +1,13 @@ +// +// DDGetOfflineFileAPI.h +// Duoduo +// +// Created by 独嘉 on 14-5-9. +// Copyright (c) 2014年 zuoye. All rights reserved. +// + +#import "DDSuperAPI.h" + +@interface DDGetOfflineFileAPI : DDSuperAPI + +@end diff --git a/mac/TeamTalk/API/APIGroup/DDGetOfflineFileAPI.m b/mac/TeamTalk/API/APIGroup/DDGetOfflineFileAPI.m new file mode 100644 index 000000000..6436e261d --- /dev/null +++ b/mac/TeamTalk/API/APIGroup/DDGetOfflineFileAPI.m @@ -0,0 +1,113 @@ +// +// DDGetOfflineFileAPI.m +// Duoduo +// +// Created by 独嘉 on 14-5-9. +// Copyright (c) 2014年 zuoye. All rights reserved. +// + +#import "DDGetOfflineFileAPI.h" + +@implementation DDGetOfflineFileAPI +/** + * 请求超时时间 + * + * @return 超时时间 + */ +- (int)requestTimeOutTimeInterval +{ + return 4; +} + +/** + * 请求的serviceID + * + * @return 对应的serviceID + */ +- (int)requestServiceID +{ + return MODULE_ID_FILETRANSFER; +} + +/** + * 请求返回的serviceID + * + * @return 对应的serviceID + */ +- (int)responseServiceID +{ + return MODULE_ID_FILETRANSFER; +} + +/** + * 请求的commendID + * + * @return 对应的commendID + */ +- (int)requestCommendID +{ + return CMD_FILE_HAS_OFFLINE_REQ; +} + +/** + * 请求返回的commendID + * + * @return 对应的commendID + */ +- (int)responseCommendID +{ + return CMD_FILE_HAS_OFFLINE_RES; +} + +/** + * 解析数据的block + * + * @return 解析数据的block + */ +- (Analysis)analysisReturnData +{ + Analysis analysis = (id)^(NSData* data) + { + DataInputStream* bodyData = [DataInputStream dataInputStreamWithData:data]; + uint32_t fileCnt = [bodyData readInt]; + NSMutableArray *fileList = [[NSMutableArray alloc] init]; + + if (fileCnt > 0) { + for (uint32_t i = 0; i < fileCnt; i++) { + NSMutableDictionary *dict = [[NSMutableDictionary alloc] init]; + NSString *fromId = [bodyData readUTF]; + uint32_t fileId = [bodyData readInt]; + uint32_t fileSize = [bodyData readInt]; + NSString *filePath = [bodyData readUTF]; + [dict setObject:fromId forKey:@"fromId"]; + [dict setObject:[NSNumber numberWithInt:fileId] forKey:@"fileId"]; + [dict setObject:[NSNumber numberWithInt:fileSize] forKey:@"fileSize"]; + [dict setObject:filePath forKey:@"filePath"]; + [fileList addObject:dict]; + } + } + + return fileList; + }; + return analysis; +} + +/** + * 打包数据的block + * + * @return 打包数据的block + */ +- (Package)packageRequestObject +{ + Package package = (id)^(id object,uint16_t seqNo) + { + DataOutputStream *dataout = [[DataOutputStream alloc] init]; + + [dataout writeInt:IM_PDU_HEADER_LEN]; + [dataout writeTcpProtocolHeader:MODULE_ID_FILETRANSFER cId:CMD_FILE_HAS_OFFLINE_REQ seqNo:seqNo]; + log4CInfo(@"serviceID:%i cmdID:%i --> get has offline file or not",MODULE_ID_FILETRANSFER,CMD_FILE_HAS_OFFLINE_REQ); + return [dataout toByteArray]; + }; + return package; +} +@end diff --git a/mac/TeamTalk/API/APIGroup/DDGroupInfoAPI.h b/mac/TeamTalk/API/APIGroup/DDGroupInfoAPI.h new file mode 100644 index 000000000..0aba2bab0 --- /dev/null +++ b/mac/TeamTalk/API/APIGroup/DDGroupInfoAPI.h @@ -0,0 +1,13 @@ +// +// DDGroupInfoAPI.h +// Duoduo +// +// Created by 独嘉 on 14-5-7. +// Copyright (c) 2014年 zuoye. All rights reserved. +// + +#import "DDSuperAPI.h" + +@interface DDGroupInfoAPI : DDSuperAPI + +@end diff --git a/mac/TeamTalk/API/APIGroup/DDGroupInfoAPI.m b/mac/TeamTalk/API/APIGroup/DDGroupInfoAPI.m new file mode 100644 index 000000000..b80d8ac3f --- /dev/null +++ b/mac/TeamTalk/API/APIGroup/DDGroupInfoAPI.m @@ -0,0 +1,122 @@ +// +// DDGroupInfoAPI.m +// Duoduo +// +// Created by 独嘉 on 14-5-7. +// Copyright (c) 2014年 zuoye. All rights reserved. +// + +#import "DDGroupInfoAPI.h" +#import "MTGroupEntity.h" +#import "IMGroup.pb.h" +@implementation DDGroupInfoAPI +/** + * 请求超时时间 + * + * @return 超时时间 + */ +- (int)requestTimeOutTimeInterval +{ + return 10; +} + +/** + * 请求的serviceID + * + * @return 对应的serviceID + */ +- (int)requestServiceID +{ + return SERVICE_GROUP; +} + +/** + * 请求返回的serviceID + * + * @return 对应的serviceID + */ +- (int)responseServiceID +{ + return SERVICE_GROUP; +} + +/** + * 请求的commendID + * + * @return 对应的commendID + */ +- (int)requestCommendID +{ + return CMD_ID_GROUP_USER_LIST_REQ; +} + +/** + * 请求返回的commendID + * + * @return 对应的commendID + */ +- (int)responseCommendID +{ + return CMD_ID_GROUP_USER_LIST_RES; +} + +/** + * 解析数据的block + * + * @return 解析数据的block + */ +- (Analysis)analysisReturnData +{ + Analysis analysis = (id)^(NSData* data) + { + IMGroupInfoListRsp* groupInfoRsp = [IMGroupInfoListRsp parseFromData:data]; + uint32_t userId = groupInfoRsp.userId; + NSMutableDictionary *groupInfoAndReqUserId = [NSMutableDictionary new]; + [groupInfoAndReqUserId setObject:@(userId) forKey:@"reqUserId"]; + NSMutableArray *groupList = [[NSMutableArray alloc] init]; + for (GroupInfo *groupInfo in groupInfoRsp.groupInfoList) { + MTGroupEntity *groupEntity = [[MTGroupEntity alloc] initWithGroupInfo:(GroupInfo *)groupInfo]; + [groupList addObject:groupEntity]; + } + + [groupInfoAndReqUserId setObject:groupList forKey:@"groupList"]; + return groupInfoAndReqUserId; + }; + return analysis; +} + +/** + * 打包数据的block + * + * @return 打包数据的block + */ +- (Package)packageRequestObject +{ + Package package = (id)^(id object,uint32_t seqNo) + { + IMGroupInfoListReqBuilder *reqBuilder = [IMGroupInfoListReq builder]; + UInt32 reqUserId = [[object objectForKey:@"reqUserId"] intValue]; + [reqBuilder setUserId:reqUserId]; + NSMutableArray* groupVersionList = [object objectForKey:@"groupVersionList"]; + NSMutableArray* groupVersionListArray = [[NSMutableArray alloc] init]; + for (NSDictionary* groupVersionInfo in groupVersionList) { + GroupVersionInfoBuilder* groupInfoReqBuilder = [GroupVersionInfo builder]; + UInt32 groupId = [[groupVersionInfo objectForKey:@"groupId"] intValue]; + UInt32 version = [[groupVersionInfo objectForKey:@"version"] intValue]; + [groupInfoReqBuilder setGroupId:groupId]; + [groupInfoReqBuilder setVersion:version]; + [groupVersionListArray addObject:groupInfoReqBuilder.build]; + } + [reqBuilder setGroupVersionListArray:groupVersionListArray]; + DataOutputStream *dataout = [[DataOutputStream alloc] init]; + [dataout writeInt:0]; + [dataout writeTcpProtocolHeader:SERVICE_GROUP + cId:CMD_ID_GROUP_USER_LIST_REQ + seqNo:seqNo]; + [dataout directWriteBytes:[reqBuilder build].data]; + [dataout writeDataCount]; + return [dataout toByteArray]; + }; + return package; +} +@end diff --git a/mac/TeamTalk/API/APIGroup/DDGroupMsgReadACKAPI.h b/mac/TeamTalk/API/APIGroup/DDGroupMsgReadACKAPI.h new file mode 100644 index 000000000..70a50b011 --- /dev/null +++ b/mac/TeamTalk/API/APIGroup/DDGroupMsgReadACKAPI.h @@ -0,0 +1,13 @@ +// +// DDGroupMsgReadACKAPI.h +// Duoduo +// +// Created by 独嘉 on 14-5-7. +// Copyright (c) 2014年 zuoye. All rights reserved. +// + +#import "DDSuperAPI.h" + +@interface DDGroupMsgReadACKAPI : DDSuperAPI + +@end diff --git a/mac/TeamTalk/API/APIGroup/DDGroupMsgReadACKAPI.m b/mac/TeamTalk/API/APIGroup/DDGroupMsgReadACKAPI.m new file mode 100644 index 000000000..fd05d7221 --- /dev/null +++ b/mac/TeamTalk/API/APIGroup/DDGroupMsgReadACKAPI.m @@ -0,0 +1,93 @@ +// +// DDGroupMsgReadACKAPI.m +// Duoduo +// +// Created by 独嘉 on 14-5-7. +// Copyright (c) 2014年 zuoye. All rights reserved. +// + +#import "DDGroupMsgReadACKAPI.h" + +@implementation DDGroupMsgReadACKAPI +/** + * 请求超时时间 + * + * @return 超时时间 + */ +- (int)requestTimeOutTimeInterval +{ + return 10; +} + +/** + * 请求的serviceID + * + * @return 对应的serviceID + */ +- (int)requestServiceID +{ + return MODULE_ID_GROUP; +} + +/** + * 请求返回的serviceID + * + * @return 对应的serviceID + */ +- (int)responseServiceID +{ + return 0; +} + +/** + * 请求的commendID + * + * @return 对应的commendID + */ +- (int)requestCommendID +{ + return CMD_ID_GROUP_MSG_READ_ACK; +} + +/** + * 请求返回的commendID + * + * @return 对应的commendID + */ +- (int)responseCommendID +{ + return 0; +} + +/** + * 解析数据的block + * + * @return 解析数据的block + */ +- (Analysis)analysisReturnData +{ + return nil; +} + +/** + * 打包数据的block + * + * @return 打包数据的block + */ +- (Package)packageRequestObject +{ + Package package = (id)^(id object,uint16_t seqNo) + { + NSString* groupId = (NSString*)object; + DataOutputStream *dataout = [[DataOutputStream alloc] init]; + uint32_t totalLen = IM_PDU_HEADER_LEN + 4 + strLen(groupId); + + [dataout writeInt:totalLen]; + [dataout writeTcpProtocolHeader:MODULE_ID_GROUP cId:CMD_ID_GROUP_MSG_READ_ACK seqNo:seqNo]; + [dataout writeUTF:groupId]; + log4CInfo(@"serviceID:%i cmdID:%i --> group msg read ACK group ID:%@",MODULE_ID_GROUP,CMD_ID_GROUP_MSG_READ_ACK,groupId); + return [dataout toByteArray]; + }; + return package; +} +@end diff --git a/mac/TeamTalk/API/APIGroup/DDGroupMsgReceivedACKAPI.h b/mac/TeamTalk/API/APIGroup/DDGroupMsgReceivedACKAPI.h new file mode 100644 index 000000000..f42e08876 --- /dev/null +++ b/mac/TeamTalk/API/APIGroup/DDGroupMsgReceivedACKAPI.h @@ -0,0 +1,13 @@ +// +// DDGroupMsgReceivedACKAPI.h +// Duoduo +// +// Created by 独嘉 on 14-5-7. +// Copyright (c) 2014年 zuoye. All rights reserved. +// + +#import "DDSuperAPI.h" + +@interface DDGroupMsgReceivedACKAPI : DDSuperAPI + +@end diff --git a/mac/TeamTalk/API/APIGroup/DDGroupMsgReceivedACKAPI.m b/mac/TeamTalk/API/APIGroup/DDGroupMsgReceivedACKAPI.m new file mode 100644 index 000000000..67eaff3ba --- /dev/null +++ b/mac/TeamTalk/API/APIGroup/DDGroupMsgReceivedACKAPI.m @@ -0,0 +1,13 @@ +// +// DDGroupMsgReceivedACKAPI.m +// Duoduo +// +// Created by 独嘉 on 14-5-7. +// Copyright (c) 2014年 zuoye. All rights reserved. +// + +#import "DDGroupMsgReceivedACKAPI.h" + +@implementation DDGroupMsgReceivedACKAPI + +@end diff --git a/mac/TeamTalk/API/APIGroup/DDHeartBeatAPI.h b/mac/TeamTalk/API/APIGroup/DDHeartBeatAPI.h new file mode 100644 index 000000000..2cff0e3e6 --- /dev/null +++ b/mac/TeamTalk/API/APIGroup/DDHeartBeatAPI.h @@ -0,0 +1,13 @@ +// +// DDHeartBeatAPI.h +// Duoduo +// +// Created by 独嘉 on 15/1/11. +// Copyright (c) 2015年 zuoye. All rights reserved. +// + +#import "DDSuperAPI.h" + +@interface DDHeartBeatAPI : DDSuperAPI + +@end diff --git a/mac/TeamTalk/API/APIGroup/DDHeartBeatAPI.m b/mac/TeamTalk/API/APIGroup/DDHeartBeatAPI.m new file mode 100644 index 000000000..1ddf52541 --- /dev/null +++ b/mac/TeamTalk/API/APIGroup/DDHeartBeatAPI.m @@ -0,0 +1,92 @@ +// +// DDHeartBeatAPI.m +// Duoduo +// +// Created by 独嘉 on 15/1/11. +// Copyright (c) 2015年 zuoye. All rights reserved. +// + +#import "DDHeartBeatAPI.h" + +@implementation DDHeartBeatAPI +/** + * 请求超时时间 + * + * @return 超时时间 + */ +- (int)requestTimeOutTimeInterval +{ + return 0; +} + +/** + * 请求的serviceID + * + * @return 对应的serviceID + */ +- (int)requestServiceID +{ + return DDSERVICE_OTHER; +} + +/** + * 请求返回的serviceID + * + * @return 对应的serviceID + */ +- (int)responseServiceID +{ + return DDSERVICE_OTHER; +} + +/** + * 请求的commendID + * + * @return 对应的commendID + */ +- (int)requestCommendID +{ + return CMD_OTHER_HEART_BEAT_REQ; +} + +/** + * 请求返回的commendID + * + * @return 对应的commendID + */ +- (int)responseCommendID +{ + return 0; +} + +/** + * 解析数据的block + * + * @return 解析数据的block + */ +- (Analysis)analysisReturnData +{ + return nil; +} + +/** + * 打包数据的block + * + * @return 打包数据的block + */ +- (Package)packageRequestObject +{ + Package package = (id)^(id object,uint32_t seqNo) + { + DataOutputStream *dataout = [[DataOutputStream alloc] init]; + [dataout writeInt:0]; + [dataout writeTcpProtocolHeader:DDSERVICE_OTHER + cId:CMD_OTHER_HEART_BEAT_REQ + seqNo:seqNo]; + [dataout writeDataCount]; + return [dataout toByteArray]; + }; + return package; +} + +@end diff --git a/mac/TeamTalk/API/APIGroup/DDHistoryMessageApi.h b/mac/TeamTalk/API/APIGroup/DDHistoryMessageApi.h new file mode 100644 index 000000000..8ef25d279 --- /dev/null +++ b/mac/TeamTalk/API/APIGroup/DDHistoryMessageApi.h @@ -0,0 +1,13 @@ +// +// DDHistoryMessageApi.h +// Duoduo +// +// Created by scorpio on 15/1/16. +// Copyright (c) 2015年 mogujie. All rights reserved. +// + +#import "DDSuperAPI.h" + +@interface DDHistoryMessageAPI : DDSuperAPI + +@end diff --git a/mac/TeamTalk/API/APIGroup/DDHistoryMessageApi.m b/mac/TeamTalk/API/APIGroup/DDHistoryMessageApi.m new file mode 100644 index 000000000..37d90897f --- /dev/null +++ b/mac/TeamTalk/API/APIGroup/DDHistoryMessageApi.m @@ -0,0 +1,114 @@ +// +// DDSendMessageAPI.m +// Duoduo +// +// Created by 独嘉 on 14-5-8. +// Copyright (c) 2014年 zuoye. All rights reserved. +// + +#import "DDHistoryMessageAPI.h" +#import "IMMessage.pb.h" +#import "MTMessageEntity.h" +@implementation DDHistoryMessageAPI +/** + * 请求超时时间 + * + * @return 超时时间 + */ +- (int)requestTimeOutTimeInterval +{ + return 5; +} + +/** + * 请求的serviceID + * + * @return 对应的serviceID + */ +- (int)requestServiceID +{ + return DDSERVICE_MESSAGE; +} + +/** + * 请求返回的serviceID + * + * @return 对应的serviceID + */ +- (int)responseServiceID +{ + return DDSERVICE_MESSAGE; +} + +/** + * 请求的commendID + * + * @return 对应的commendID + */ +- (int)requestCommendID +{ + return CID_MSG_LIST_REQUEST; +} + +/** + * 请求返回的commendID + * + * @return 对应的commendID + */ +- (int)responseCommendID +{ + return CID_MSG_LIST_RESPONSE; +} + +/** + * 解析数据的block + * + * @return 解析数据的block + */ +- (Analysis)analysisReturnData +{ + Analysis analysis = (id)^(NSData* data) + { + IMGetMsgListRsp *allMessageRsp = [IMGetMsgListRsp parseFromData:data]; + NSArray* messages = allMessageRsp.msgList; + NSString* sessionID = [NSString stringWithFormat:@"%i",allMessageRsp.sessionId]; + NSMutableArray* newMessages = [[NSMutableArray alloc] init]; + for (NSInteger index = 0; index < [messages count]; index ++) + { + MsgInfo* msgInfo = messages[index]; + MTMessageEntity* messageEntity = [[MTMessageEntity alloc] initWithMesssageInfo:msgInfo withSessionID:sessionID]; + [newMessages addObject:messageEntity]; + } + return newMessages; + }; + return analysis; +} + +/** + * 打包数据的block + * + * @return 打包数据的block + */ +- (Package)packageRequestObject +{ + Package package = (id)^(id object,uint16_t seqNo) + { + IMGetMsgListReqBuilder *req = [IMGetMsgListReq builder]; + + [req setUserId:[object[0] intValue]]; + [req setSessionType:[object[1] intValue]]; + [req setSessionId:[object[2] intValue]]; + [req setMsgIdBegin:[object[3] intValue]]; + [req setMsgCnt:[object[4] intValue]]; + DataOutputStream *dataout = [[DataOutputStream alloc] init]; + [dataout writeInt:0]; + [dataout writeTcpProtocolHeader:DDSERVICE_MESSAGE + cId:CID_MSG_LIST_REQUEST + seqNo:seqNo]; + [dataout directWriteBytes:[req build].data]; + [dataout writeDataCount]; + return [dataout toByteArray]; + }; + return package; +} +@end diff --git a/mac/TeamTalk/API/APIGroup/DDLoginAPI.h b/mac/TeamTalk/API/APIGroup/DDLoginAPI.h new file mode 100644 index 000000000..74bde0ff7 --- /dev/null +++ b/mac/TeamTalk/API/APIGroup/DDLoginAPI.h @@ -0,0 +1,12 @@ +// +// DDLoginAPI.h +// Duoduo +// +// Created by 独嘉 on 14-5-6. +// Copyright (c) 2014年 zuoye. All rights reserved. +// + +#import "DDSuperAPI.h" +@interface DDLoginAPI : DDSuperAPI + +@end diff --git a/mac/TeamTalk/API/APIGroup/DDLoginAPI.mm b/mac/TeamTalk/API/APIGroup/DDLoginAPI.mm new file mode 100644 index 000000000..17352c207 --- /dev/null +++ b/mac/TeamTalk/API/APIGroup/DDLoginAPI.mm @@ -0,0 +1,142 @@ +// +// DDLoginAPI.m +// Duoduo +// +// Created by 独嘉 on 14-5-6. +// Copyright (c) 2014年 zuoye. All rights reserved. +// + +#import "DDLoginAPI.h" +#import "MTUserEntity.h" +#import "IMLogin.pb.h" +#import "IMBaseDefine.pb.h" +#import "security.h" +#include +@implementation DDLoginAPI +/** + * 请求超时时间 + * + * @return 超时时间 + */ +- (int)requestTimeOutTimeInterval +{ + return 15; +} + +/** + * 请求的serviceID + * + * @return 对应的serviceID + */ +- (int)requestServiceID +{ + return DDSERVICE_LOGIN; +} + +/** + * 请求返回的serviceID + * + * @return 对应的serviceID + */ +- (int)responseServiceID +{ + return DDSERVICE_LOGIN; +} + +/** + * 请求的commendID + * + * @return 对应的commendID + */ +- (int)requestCommendID +{ + return CMD_LOGIN_REQ_USERLOGIN; +} + +/** + * 请求返回的commendID + * + * @return 对应的commendID + */ +- (int)responseCommendID +{ + return CMD_LOGIN_RES_USERLOGIN; +} + +/** + * 解析数据的block + * + * @return 解析数据的block + */ +- (Analysis)analysisReturnData +{ + Analysis analysis = (id)^(NSData* data) + { + + IMLoginRes *res = [IMLoginRes parseFromData:data]; + NSInteger serverTime = res.serverTime; + NSInteger loginResult = res.resultCode; + NSDictionary* result = nil; + if (loginResult !=0) { + return result; + }else + { + MTUserEntity *user = [[MTUserEntity alloc] initWithUserInfo:res.userInfo]; + result = @{@"serverTime":@(serverTime), + @"result":@(loginResult), + @"user":user, + }; + return result; + } + + }; + return analysis; +} + +/** + * 打包数据的block + * + * @return 打包数据的block + */ +- (Package)packageRequestObject +{ + Package package = (id)^(id object,uint32_t seqNo) + { + + NSString* name = object[0]; + NSString* password = object[1]; + NSString* clientVersion = object[2]; + + DataOutputStream *dataout = [[DataOutputStream alloc] init]; + [dataout writeInt:0]; + [dataout writeTcpProtocolHeader:DDSERVICE_LOGIN + cId:CMD_LOGIN_REQ_USERLOGIN + seqNo:seqNo]; + IMLoginReqBuilder *login = [IMLoginReq builder]; + [login setUserName:name]; + + std::string *strMsg =new std::string([password UTF8String]); + char* pOut; + uint32_t nLen=0; + int nRet =EncryptPass(strMsg->c_str(), (uint32_t)strMsg->length(), &pOut, nLen); + if (nRet != 0) { + printf(" **** 加密密码错误:code= %d",nRet); + password=@""; + }else{ + password = [NSString stringWithUTF8String:pOut]; + Free(pOut); + } + delete strMsg; + + + [login setPassword:password]; + [login setClientType:ClientTypeClientTypeMac]; + [login setClientVersion:clientVersion]; + [login setOnlineStatus:UserStatTypeUserStatusOnline]; + [dataout directWriteBytes:[login build].data]; + [dataout writeDataCount]; + return [dataout toByteArray]; + }; + return package; +} +@end diff --git a/mac/TeamTalk/API/APIGroup/DDModifyUserAvatarAPI.h b/mac/TeamTalk/API/APIGroup/DDModifyUserAvatarAPI.h new file mode 100644 index 000000000..e0a8b0b37 --- /dev/null +++ b/mac/TeamTalk/API/APIGroup/DDModifyUserAvatarAPI.h @@ -0,0 +1,13 @@ +// +// DDModifyUserAvatarAPI.h +// Duoduo +// +// Created by 独嘉 on 14-7-22. +// Copyright (c) 2014年 zuoye. All rights reserved. +// + +#import "DDSuperAPI.h" + +@interface DDModifyUserAvatarAPI : DDSuperAPI + +@end diff --git a/mac/TeamTalk/API/APIGroup/DDModifyUserAvatarAPI.m b/mac/TeamTalk/API/APIGroup/DDModifyUserAvatarAPI.m new file mode 100644 index 000000000..a30d1ed3b --- /dev/null +++ b/mac/TeamTalk/API/APIGroup/DDModifyUserAvatarAPI.m @@ -0,0 +1,111 @@ +// +// DDModifyUserAvatarAPI.m +// Duoduo +// +// Created by 独嘉 on 14-7-22. +// Copyright (c) 2014年 zuoye. All rights reserved. +// + +#import "DDModifyUserAvatarAPI.h" + +@implementation DDModifyUserAvatarAPI +/** + * 请求超时时间 + * + * @return 超时时间 + */ +- (int)requestTimeOutTimeInterval +{ + return 5; +} + +/** + * 请求的serviceID + * + * @return 对应的serviceID + */ +- (int)requestServiceID +{ + return ServiceIDSidBuddyList; +} + +/** + * 请求返回的serviceID + * + * @return 对应的serviceID + */ +- (int)responseServiceID +{ + return ServiceIDSidBuddyList; +} + +/** + * 请求的commendID + * + * @return 对应的commendID + */ +- (int)requestCommendID +{ + return CMD_FRI_MODIFY_USER_AVATAR_REQ; +} + +/** + * 请求返回的commendID + * + * @return 对应的commendID + */ +- (int)responseCommendID +{ + return CMD_FRI_MODIFY_USER_AVATAR_RES; +} + +/** + * 解析数据的block + * + * @return 解析数据的block + */ +- (Analysis)analysisReturnData +{ + Analysis analysis = (id)^(NSData* data) + { + DataInputStream* bodyData = [DataInputStream dataInputStreamWithData:data]; + uint32_t result = [bodyData readInt]; + if (result == 0) + { + //修改成功 + return @(YES); + } + else + { + //修改失败 + return @(NO); + } + }; + return analysis; +} + +/** + * 打包数据的block + * + * @return 打包数据的block + */ +- (Package)packageRequestObject +{ + Package package = (id)^(id object,uint16_t seqNo) + { + DataOutputStream *dataout = [[DataOutputStream alloc] init]; + NSString* userID = object[0]; + NSString* url = object[1]; + int totalLen = IM_PDU_HEADER_LEN + 4 * 2 + strLen(userID) + strLen(url); + [dataout writeInt:totalLen]; + [dataout writeTcpProtocolHeader:[self requestServiceID] + cId:CMD_FRI_MODIFY_USER_AVATAR_REQ + seqNo:seqNo]; + [dataout writeUTF:userID]; + [dataout writeUTF:url]; + return [dataout toByteArray]; + }; + return package; +} + +@end diff --git a/mac/TeamTalk/API/APIGroup/DDMsgReadACKAPI.h b/mac/TeamTalk/API/APIGroup/DDMsgReadACKAPI.h new file mode 100644 index 000000000..79eaf19fa --- /dev/null +++ b/mac/TeamTalk/API/APIGroup/DDMsgReadACKAPI.h @@ -0,0 +1,16 @@ +// +// DDUserMsgReadACKAPI.h +// Duoduo +// +// Created by 独嘉 on 14-5-7. +// Copyright (c) 2014年 zuoye. All rights reserved. +// + +#import "DDSuperAPI.h" + +/** + * 没有数据返回,object为发送消息的用户ID + */ +@interface DDMsgReadACKAPI : DDSuperAPI + +@end diff --git a/mac/TeamTalk/API/APIGroup/DDMsgReadACKAPI.m b/mac/TeamTalk/API/APIGroup/DDMsgReadACKAPI.m new file mode 100644 index 000000000..41010a464 --- /dev/null +++ b/mac/TeamTalk/API/APIGroup/DDMsgReadACKAPI.m @@ -0,0 +1,102 @@ +// +// DDUserMsgReadACKAPI.m +// Duoduo +// +// Created by 独嘉 on 14-5-7. +// Copyright (c) 2014年 zuoye. All rights reserved. +// + +#import "DDMsgReadACKAPI.h" +#import "IMMessage.pb.h" + +@implementation DDMsgReadACKAPI +/** + * 请求超时时间 + * + * @return 超时时间 + */ +- (int)requestTimeOutTimeInterval +{ + return 0; +} + +/** + * 请求的serviceID + * + * @return 对应的serviceID + */ +- (int)requestServiceID +{ + return DDSERVICE_MESSAGE; +} + +/** + * 请求返回的serviceID + * + * @return 对应的serviceID + */ +- (int)responseServiceID +{ + return DDSERVICE_MESSAGE; +} + + +/** + * 请求的commendID + * + * @return 对应的commendID + */ +- (int)requestCommendID +{ + return CMD_MSG_READ_ACK; +} + +/** + * 请求返回的commendID + * + * @return 对应的commendID + */ +- (int)responseCommendID +{ + return 0; +} + +/** + * 解析数据的block + * + * @return 解析数据的block + */ +- (Analysis)analysisReturnData +{ + return nil; +} + +/** + * 打包数据的block + * + * @return 打包数据的block + */ +- (Package)packageRequestObject +{ + Package package = (id)^(id object,uint32_t seqNo) + { + IMMsgDataReadAckBuilder *req = [IMMsgDataReadAck builder]; + + [req setUserId:0]; + [req setSessionId:(UInt32)[object[0] integerValue]]; + [req setMsgId:(UInt32)[object[1] integerValue]]; + [req setSessionType:(UInt32)[object[2] integerValue]]; + + DataOutputStream *dataout = [[DataOutputStream alloc] init]; + [dataout writeInt:0]; + [dataout writeTcpProtocolHeader:DDSERVICE_MESSAGE + cId:CMD_MSG_READ_ACK + seqNo:seqNo]; + [dataout directWriteBytes:[req build].data]; + [dataout writeDataCount]; + return [dataout toByteArray]; + }; + return package; +} + +@end diff --git a/mac/TeamTalk/API/APIGroup/DDOfflineFileUploadFinishedAPI.h b/mac/TeamTalk/API/APIGroup/DDOfflineFileUploadFinishedAPI.h new file mode 100644 index 000000000..6ba252181 --- /dev/null +++ b/mac/TeamTalk/API/APIGroup/DDOfflineFileUploadFinishedAPI.h @@ -0,0 +1,13 @@ +// +// DDOfflineFileUploadFinishedAPI.h +// Duoduo +// +// Created by 独嘉 on 14-5-12. +// Copyright (c) 2014年 zuoye. All rights reserved. +// + +#import "DDSuperAPI.h" + +@interface DDOfflineFileUploadFinishedAPI : DDSuperAPI + +@end diff --git a/mac/TeamTalk/API/APIGroup/DDOfflineFileUploadFinishedAPI.m b/mac/TeamTalk/API/APIGroup/DDOfflineFileUploadFinishedAPI.m new file mode 100644 index 000000000..4b5ee9ef7 --- /dev/null +++ b/mac/TeamTalk/API/APIGroup/DDOfflineFileUploadFinishedAPI.m @@ -0,0 +1,101 @@ +// +// DDOfflineFileUploadFinishedAPI.m +// Duoduo +// +// Created by 独嘉 on 14-5-12. +// Copyright (c) 2014年 zuoye. All rights reserved. +// + +#import "DDOfflineFileUploadFinishedAPI.h" + +@implementation DDOfflineFileUploadFinishedAPI +/** + * 请求超时时间 + * + * @return 超时时间 + */ +- (int)requestTimeOutTimeInterval +{ + return 0; +} + +/** + * 请求的serviceID + * + * @return 对应的serviceID + */ +- (int)requestServiceID +{ + return MODULE_ID_FILETRANSFER; +} + +/** + * 请求返回的serviceID + * + * @return 对应的serviceID + */ +- (int)responseServiceID +{ + return 0; +} + +/** + * 请求的commendID + * + * @return 对应的commendID + */ +- (int)requestCommendID +{ + return CMD_FILE_DOWNLOAD_OFFLINE_NOTIFY; +} + +/** + * 请求返回的commendID + * + * @return 对应的commendID + */ +- (int)responseCommendID +{ + return 0; +} + +/** + * 解析数据的block + * + * @return 解析数据的block + */ +- (Analysis)analysisReturnData +{ + return nil; +} + +/** + * 打包数据的block + * + * @return 打包数据的block + */ +- (Package)packageRequestObject +{ + Package package = (id)^(id object,uint16_t seqNo) + { + NSArray* array = (NSArray*)object; + NSString* fromUserId = array[0]; + NSString* toUserId = array[1]; + NSString* filePath = array[2]; + NSString* savePath = array[3]; + DataOutputStream *dataout = [[DataOutputStream alloc] init]; + uint32_t totalLen = IM_PDU_HEADER_LEN + 4 * 4 + + strLen(fromUserId) + strLen(toUserId) + strLen(filePath) + strLen(savePath); + + [dataout writeInt:totalLen]; + [dataout writeTcpProtocolHeader:MODULE_ID_FILETRANSFER cId:CMD_FILE_DOWNLOAD_OFFLINE_NOTIFY seqNo:seqNo]; + [dataout writeUTF:fromUserId]; + [dataout writeUTF:toUserId]; + [dataout writeUTF:filePath]; + [dataout writeUTF:savePath]; + log4CInfo(@"serviceID:%i cmdID:%i --> download offline file from user:%@ to user:%@ filePath:%@ savePath:%@",MODULE_ID_FILETRANSFER,CMD_FILE_DOWNLOAD_OFFLINE_NOTIFY,fromUserId,toUserId,filePath,savePath); + return [dataout toByteArray]; + }; + return package; +} +@end diff --git a/mac/TeamTalk/API/APIGroup/DDReadyReceiveFileAPI.h b/mac/TeamTalk/API/APIGroup/DDReadyReceiveFileAPI.h new file mode 100644 index 000000000..e62c27fe0 --- /dev/null +++ b/mac/TeamTalk/API/APIGroup/DDReadyReceiveFileAPI.h @@ -0,0 +1,13 @@ +// +// DDReadyReceiveFileAPI.h +// Duoduo +// +// Created by 独嘉 on 14-5-12. +// Copyright (c) 2014年 zuoye. All rights reserved. +// + +#import "DDSuperAPI.h" + +@interface DDReadyReceiveFileAPI : DDSuperAPI + +@end diff --git a/mac/TeamTalk/API/APIGroup/DDReadyReceiveFileAPI.m b/mac/TeamTalk/API/APIGroup/DDReadyReceiveFileAPI.m new file mode 100644 index 000000000..77a3c15e0 --- /dev/null +++ b/mac/TeamTalk/API/APIGroup/DDReadyReceiveFileAPI.m @@ -0,0 +1,98 @@ +// +// DDReadyReceiveFileAPI.m +// Duoduo +// +// Created by 独嘉 on 14-5-12. +// Copyright (c) 2014年 zuoye. All rights reserved. +// + +#import "DDReadyReceiveFileAPI.h" + +@implementation DDReadyReceiveFileAPI +/** + * 请求超时时间 + * + * @return 超时时间 + */ +- (int)requestTimeOutTimeInterval +{ + return 0; +} + +/** + * 请求的serviceID + * + * @return 对应的serviceID + */ +- (int)requestServiceID +{ + return MODULE_ID_FILETRANSFER; +} + +/** + * 请求返回的serviceID + * + * @return 对应的serviceID + */ +- (int)responseServiceID +{ + return 0; +} + +/** + * 请求的commendID + * + * @return 对应的commendID + */ +- (int)requestCommendID +{ + return CMD_FILE_RECV_READY; +} + +/** + * 请求返回的commendID + * + * @return 对应的commendID + */ +- (int)responseCommendID +{ + return 0; +} + +/** + * 解析数据的block + * + * @return 解析数据的block + */ +- (Analysis)analysisReturnData +{ + return nil; +} + +/** + * 打包数据的block + * + * @return 打包数据的block + */ +- (Package)packageRequestObject +{ + Package package = (id)^(id object,uint16_t seqNo) + { + NSArray* array = (NSArray*)object; + NSString* fromUserId = array[0]; + NSString* toUserId = array[1]; + + DataOutputStream *dataout = [[DataOutputStream alloc] init]; + uint32_t totalLen = IM_PDU_HEADER_LEN + 4 * 2 + + strLen(fromUserId) + strLen(toUserId); + + [dataout writeInt:totalLen]; + [dataout writeTcpProtocolHeader:MODULE_ID_FILETRANSFER cId:CMD_FILE_RECV_READY seqNo:seqNo]; + [dataout writeUTF:fromUserId]; + [dataout writeUTF:toUserId]; + log4CInfo(@"serviceID:%i cmdID:%i -->opposite ready receive file from user:%@ to user:%@",fromUserId,toUserId, fromUserId, toUserId); + return [dataout toByteArray]; + }; + return package; +} +@end diff --git a/mac/TeamTalk/API/APIGroup/DDRemoveSessionAPI.h b/mac/TeamTalk/API/APIGroup/DDRemoveSessionAPI.h new file mode 100644 index 000000000..d45d37db1 --- /dev/null +++ b/mac/TeamTalk/API/APIGroup/DDRemoveSessionAPI.h @@ -0,0 +1,13 @@ +// +// DDRemoveSessionAPI.h +// Duoduo +// +// Created by 独嘉 on 14-5-12. +// Copyright (c) 2014年 zuoye. All rights reserved. +// + +#import "DDSuperAPI.h" + +@interface DDRemoveSessionAPI : DDSuperAPI + +@end diff --git a/mac/TeamTalk/API/APIGroup/DDRemoveSessionAPI.m b/mac/TeamTalk/API/APIGroup/DDRemoveSessionAPI.m new file mode 100644 index 000000000..d9a7590ff --- /dev/null +++ b/mac/TeamTalk/API/APIGroup/DDRemoveSessionAPI.m @@ -0,0 +1,116 @@ +// +// DDRemoveSessionAPI.m +// Duoduo +// +// Created by 独嘉 on 14-5-12. +// Copyright (c) 2014年 zuoye. All rights reserved. +// + +#import "DDRemoveSessionAPI.h" +#import "IMBuddy.pb.h" + +@implementation DDRemoveSessionAPI + +/** + * 请求超时时间 + * + * @return 超时时间 + */ +- (int)requestTimeOutTimeInterval +{ + return 5; +} + +/** + * 请求的serviceID + * + * @return 对应的serviceID + */ +- (int)requestServiceID +{ + return MODULE_ID_SESSION; +} + +/** + * 请求返回的serviceID + * + * @return 对应的serviceID + */ +- (int)responseServiceID +{ + return MODULE_ID_SESSION; +} + +/** + * 请求的commendID + * + * @return 对应的commendID + */ +- (int)requestCommendID +{ + return REMOVE_SESSION_REQ; +} + +/** + * 请求返回的commendID + * + * @return 对应的commendID + */ +- (int)responseCommendID +{ + return REMOVE_SESSION_RES; +} + +/** + * 解析数据的block + * + * @return 解析数据的block + */ +- (Analysis)analysisReturnData +{ + Analysis analysis = (id)^(NSData* data) + { + IMRemoveSessionRsp *rsp = [IMRemoveSessionRsp parseFromData:data]; + NSMutableDictionary *dic = [NSMutableDictionary new]; + UInt32 sessionId = rsp.sessionId; + SessionType sessionType = rsp.sessionType; + UInt32 resultCode = rsp.resultCode; + + [dic setObject:@(sessionType) forKey:@"sessionType"]; + [dic setObject:@(sessionId) forKey:@"sessionId"]; + [dic setObject:@(resultCode) forKey:@"resultCode"]; + return dic; + }; + return analysis; +} + +/** + * 打包数据的block + * + * @return 打包数据的block + */ +- (Package)packageRequestObject +{ + Package package = (id)^(id object,uint16_t seqNo) + { + + NSArray* array = (NSArray*)object; + UInt32 sessionId= (UInt32)[array[0] intValue]; + SessionType sessionType = [array[1] intValue]; + IMRemoveSessionReqBuilder *removeSession = [IMRemoveSessionReq builder]; + [removeSession setUserId:0]; + [removeSession setSessionId:sessionId]; + [removeSession setSessionType:sessionType]; + DataOutputStream *dataout = [[DataOutputStream alloc] init]; + [dataout writeInt:0]; + [dataout writeTcpProtocolHeader:MODULE_ID_SESSION + cId:REMOVE_SESSION_REQ + seqNo:seqNo]; + [dataout directWriteBytes:[removeSession build].data]; + [dataout writeDataCount]; + return [dataout toByteArray]; + }; + return package; +} + +@end diff --git a/mac/TeamTalk/API/APIGroup/DDSendMessageAPI.h b/mac/TeamTalk/API/APIGroup/DDSendMessageAPI.h new file mode 100644 index 000000000..10edc931d --- /dev/null +++ b/mac/TeamTalk/API/APIGroup/DDSendMessageAPI.h @@ -0,0 +1,16 @@ +// +// DDSendMessageAPI.h +// Duoduo +// +// Created by 独嘉 on 14-5-8. +// Copyright (c) 2014年 zuoye. All rights reserved. +// + +#import "DDSuperAPI.h" + +/** + * 发送消息,object 为一个数组,index1:fromID,index2:toID,index3:content,index4:messageSeqNo,index5:type + */ +@interface DDSendMessageAPI : DDSuperAPI + +@end diff --git a/mac/TeamTalk/API/APIGroup/DDSendMessageAPI.mm b/mac/TeamTalk/API/APIGroup/DDSendMessageAPI.mm new file mode 100644 index 000000000..eb9c52c41 --- /dev/null +++ b/mac/TeamTalk/API/APIGroup/DDSendMessageAPI.mm @@ -0,0 +1,148 @@ +// +// DDSendMessageAPI.m +// Duoduo +// +// Created by 独嘉 on 14-5-8. +// Copyright (c) 2014年 zuoye. All rights reserved. +// + +#import "DDSendMessageAPI.h" +#import "IMMessage.pb.h" +#import "security.h" +#include + +@implementation DDSendMessageAPI +/** + * 请求超时时间 + * + * @return 超时时间 + */ +- (int)requestTimeOutTimeInterval +{ + return 8; +} + +/** + * 请求的serviceID + * + * @return 对应的serviceID + */ +- (int)requestServiceID +{ + return DDSERVICE_MESSAGE; +} + +/** + * 请求返回的serviceID + * + * @return 对应的serviceID + */ +- (int)responseServiceID +{ + return DDSERVICE_MESSAGE; +} + +/** + * 请求的commendID + * + * @return 对应的commendID + */ +- (int)requestCommendID +{ + return CMD_MSG_DATA; +} + +/** + * 请求返回的commendID + * + * @return 对应的commendID + */ +- (int)responseCommendID +{ + return CMD_MSG_DATA_ACK; +} + +/** + * 解析数据的block + * + * @return 解析数据的block + */ +- (Analysis)analysisReturnData +{ + Analysis analysis = (id)^(NSData* data) + { + IMMsgDataAck *allMessageRsp = [IMMsgDataAck parseFromData:data]; + NSUInteger mesageServerID = allMessageRsp.msgId; + return @(mesageServerID); + }; + return analysis; +} + +/** + * 打包数据的block + * + * @return 打包数据的block + */ +- (Package)packageRequestObject +{ + Package package = (id)^(id object,uint16_t seqNo) + { + IMMsgDataBuilder *req = [IMMsgData builder]; + NSArray* array = (NSArray*)object; + MsgType msgType; + switch ([array[2] intValue]) { + case SessionTypeSessionTypeGroup: + msgType = MsgTypeMsgTypeGroupText; + break; + case SessionTypeSessionTypeSingle: + msgType = MsgTypeMsgTypeSingleText; + break; + default: + msgType = MsgTypeMsgTypeGroupText; + NSAssert(NO, @"不知道的会话类型"); + break; + } + + NSString *strMessage = array[3]; + + //加密数据内容. + std::string *strMsg =new std::string([strMessage UTF8String]); + char* pOut; + uint32_t nLen=0; + int nRet =EncryptMsg(strMsg->c_str(), (uint32_t)strMsg->length(), &pOut, nLen); + if (nRet != 0) { + printf(" **** 加密错误:code= %d",nRet); + strMessage=@""; + } + else{ + strMessage = [NSString stringWithUTF8String:pOut]; + + Free(pOut); + } + + delete strMsg; + + NSData* messageText = [strMessage dataUsingEncoding:NSUTF8StringEncoding]; + + int fromUserID = [array[0] intValue]; + int toUserID = [array[1] intValue]; + [req setFromUserId:fromUserID]; + [req setToSessionId:toUserID]; + [req setMsgId:0]; + [req setCreateTime:0]; + [req setMsgType:msgType]; + [req setMsgData:messageText]; + + DataOutputStream *dataout = [[DataOutputStream alloc] init]; + [dataout writeInt:0]; + [dataout writeTcpProtocolHeader:DDSERVICE_MESSAGE + cId:CMD_MSG_DATA + seqNo:seqNo]; + [dataout directWriteBytes:[req build].data]; + [dataout writeDataCount]; + return [dataout toByteArray]; + }; + return package; +} + +@end diff --git a/mac/TeamTalk/API/APIGroup/DDSendOffLineFileAPI.h b/mac/TeamTalk/API/APIGroup/DDSendOffLineFileAPI.h new file mode 100644 index 000000000..1afc3059d --- /dev/null +++ b/mac/TeamTalk/API/APIGroup/DDSendOffLineFileAPI.h @@ -0,0 +1,13 @@ +// +// DDSendOffLineFileAPI.h +// Duoduo +// +// Created by 独嘉 on 14-5-12. +// Copyright (c) 2014年 zuoye. All rights reserved. +// + +#import "DDSuperAPI.h" + +@interface DDSendOffLineFileAPI : DDSuperAPI + +@end diff --git a/mac/TeamTalk/API/APIGroup/DDSendOffLineFileAPI.m b/mac/TeamTalk/API/APIGroup/DDSendOffLineFileAPI.m new file mode 100644 index 000000000..507624edd --- /dev/null +++ b/mac/TeamTalk/API/APIGroup/DDSendOffLineFileAPI.m @@ -0,0 +1,101 @@ +// +// DDSendOffLineFileAPI.m +// Duoduo +// +// Created by 独嘉 on 14-5-12. +// Copyright (c) 2014年 zuoye. All rights reserved. +// + +#import "DDSendOffLineFileAPI.h" + +@implementation DDSendOffLineFileAPI +/** + * 请求超时时间 + * + * @return 超时时间 + */ +- (int)requestTimeOutTimeInterval +{ + return 0; +} + +/** + * 请求的serviceID + * + * @return 对应的serviceID + */ +- (int)requestServiceID +{ + return MODULE_ID_FILETRANSFER; +} + +/** + * 请求返回的serviceID + * + * @return 对应的serviceID + */ +- (int)responseServiceID +{ + return 0; +} + +/** + * 请求的commendID + * + * @return 对应的commendID + */ +- (int)requestCommendID +{ + return CMD_FILE_UPLOAD_OFFLINE_NOTIFY; +} + +/** + * 请求返回的commendID + * + * @return 对应的commendID + */ +- (int)responseCommendID +{ + return 0; +} + +/** + * 解析数据的block + * + * @return 解析数据的block + */ +- (Analysis)analysisReturnData +{ + return nil; +} + +/** + * 打包数据的block + * + * @return 打包数据的block + */ +- (Package)packageRequestObject +{ + Package package = (id)^(id object,uint16_t seqNo) + { + NSArray* array = (NSArray*)object; + NSString* fromUserId = array[0]; + NSString* toUserId = array[1]; + NSString* filePath = array[2]; + DataOutputStream *dataout = [[DataOutputStream alloc] init]; + uint32_t totalLen = IM_PDU_HEADER_LEN + 4 * 3 + + strLen(fromUserId) + strLen(toUserId) + strLen(filePath); + + [dataout writeInt:totalLen]; + [dataout writeTcpProtocolHeader:MODULE_ID_FILETRANSFER cId:CMD_FILE_UPLOAD_OFFLINE_NOTIFY seqNo:seqNo]; + [dataout writeUTF:fromUserId]; + [dataout writeUTF:toUserId]; + [dataout writeUTF:filePath]; + + log4CInfo(@"serviceID:%i cmdID:%i --> uoload offline file from user:%@ to user:%@ filePath:%@",MODULE_ID_FILETRANSFER,CMD_FILE_UPLOAD_OFFLINE_NOTIFY,fromUserId,toUserId,filePath); + + return [dataout toByteArray]; + }; + return package; +} +@end diff --git a/mac/TeamTalk/API/APIGroup/DDSendP2PCmdAPI.h b/mac/TeamTalk/API/APIGroup/DDSendP2PCmdAPI.h new file mode 100644 index 000000000..51db4268b --- /dev/null +++ b/mac/TeamTalk/API/APIGroup/DDSendP2PCmdAPI.h @@ -0,0 +1,37 @@ +// +// DDSendP2PCmdAPI.h +// Duoduo +// +// Created by jianqing.du on 14-5-12. +// Copyright (c) 2014年 zuoye. All rights reserved. +// + +#import "DDSuperAPI.h" + +#define SHAKE_WINDOW @"shakewindow" +#define INPUTING @"writing" +#define STOP_INPUTING @"stop writing" + +typedef NS_ENUM(NSUInteger, P2PServiceID) +{ + SHAKE_WINDOW_SERVICEID = 1, + INPUTING_SERVICEID = 2, + INTRANET_SERVICEID = 3 +}; + +typedef NS_ENUM(NSUInteger, P2PCommand) +{ + SHAKE_WINDOW_COMMAND = SHAKE_WINDOW_SERVICEID << 16 | 1, + INPUTING_COMMAND = INPUTING_SERVICEID << 16 | 1, + STOP_INPUTTING_COMMAND = INPUTING_SERVICEID << 16 | 2, +}; + + +/* + * 发送P2P命令消息 + */ +@interface DDSendP2PCmdAPI : DDSuperAPI + ++ (NSString*)contentFor:(int)serverID commandID:(int)commandID content:(NSString*)content; + +@end diff --git a/mac/TeamTalk/API/APIGroup/DDSendP2PCmdAPI.m b/mac/TeamTalk/API/APIGroup/DDSendP2PCmdAPI.m new file mode 100644 index 000000000..18ed480ae --- /dev/null +++ b/mac/TeamTalk/API/APIGroup/DDSendP2PCmdAPI.m @@ -0,0 +1,117 @@ +// +// DDSendP2PCmdAPI.m +// Duoduo +// +// Created by jianqing.du on 14-5-12. +// Copyright (c) 2014年 zuoye. All rights reserved. +// + +#import "DDSendP2PCmdAPI.h" +#import "IMBaseDefine.pb.h" +#import "IMSwitchService.pb.h" + +@implementation DDSendP2PCmdAPI + +#pragma public ++ (NSString*)contentFor:(int)serverID commandID:(int)commandID content:(NSString*)content +{ + //@"{\"CmdID\":\"5308417\",\"Content\":\"shakewindow\",\"ServiceID\":\"1\"}" + NSString* theContent = [NSString stringWithFormat:@"{\"cmd_id\":%i,\"content\":\"%@\",\"service_id\":%i}",commandID,content,serverID]; + return theContent; +} + +#pragma APIScheduleProtocol +/** + * 请求超时时间 + * + * @return 超时时间 + */ +- (int)requestTimeOutTimeInterval +{ + return 0; +} + +/** + * 请求的serviceID + * + * @return 对应的serviceID + */ +- (int)requestServiceID +{ + return ServiceIDSidSwitchService; +} + +/** + * 请求返回的serviceID + * + * @return 对应的serviceID + */ +- (int)responseServiceID +{ + return 0; +} + +/** + * 请求的commendID + * + * @return 对应的commendID + */ +- (int)requestCommendID +{ + return SwitchServiceCmdIDCidSwitchP2PCmd; +} + +/** + * 请求返回的commendID + * + * @return 对应的commendID + */ +- (int)responseCommendID +{ + return 0; +} + +/** + * 解析数据的block + * + * @return 解析数据的block + */ +- (Analysis)analysisReturnData +{ + return nil; +} + +/** + * 打包数据的block + * + * @return 打包数据的block + */ +- (Package)packageRequestObject +{ + Package package = (id)^(id object,uint16_t seqNo) + { + IMP2PCmdMsgBuilder *req = [IMP2PCmdMsg builder]; + NSArray* array = (NSArray*)object; + NSString* fromId = array[0]; + NSString* toId = array[1]; + NSString* content = array[2]; + + + [req setFromUserId:[fromId intValue]]; + [req setToUserId:[toId intValue]]; + [req setCmdMsgData:content]; + + + DataOutputStream *dataout = [[DataOutputStream alloc] init]; + + + [dataout writeInt:0]; + [dataout writeTcpProtocolHeader:[self requestServiceID] cId:[self requestCommendID] seqNo:seqNo]; + [dataout directWriteBytes:[req build].data]; + [dataout writeDataCount]; + return [dataout toByteArray]; + }; + return package; +} + +@end diff --git a/mac/TeamTalk/API/APIGroup/DDUnreadMessageAPI.h b/mac/TeamTalk/API/APIGroup/DDUnreadMessageAPI.h new file mode 100644 index 000000000..43d5d8dd3 --- /dev/null +++ b/mac/TeamTalk/API/APIGroup/DDUnreadMessageAPI.h @@ -0,0 +1,13 @@ +// +// DDUnreadMessageAPI.h +// Duoduo +// +// Created by scorpio on 15/1/16. +// Copyright (c) 2015年 mogujie. All rights reserved. +// + +#import "DDSuperAPI.h" + +@interface DDUnreadMessageAPI : DDSuperAPI + +@end diff --git a/mac/TeamTalk/API/APIGroup/DDUnreadMessageAPI.m b/mac/TeamTalk/API/APIGroup/DDUnreadMessageAPI.m new file mode 100644 index 000000000..7306f7c34 --- /dev/null +++ b/mac/TeamTalk/API/APIGroup/DDUnreadMessageAPI.m @@ -0,0 +1,112 @@ +// +// DDUnreadMessageAPI.m +// Duoduo +// +// Created by scorpio on 15/1/16. +// Copyright (c) 2015年 mogujie. All rights reserved. +// + +#import "DDUnreadMessageAPI.h" +#import "IMMessage.pb.h" +#import "MTSessionEntity.h" + +@implementation DDUnreadMessageAPI +/** + * 请求超时时间 + * + * @return 超时时间 + */ +- (int)requestTimeOutTimeInterval +{ + return 8; +} + +/** + * 请求的serviceID + * + * @return 对应的serviceID + */ +- (int)requestServiceID +{ + return DDSERVICE_MESSAGE; +} + +/** + * 请求返回的serviceID + * + * @return 对应的serviceID + */ +- (int)responseServiceID +{ + return DDSERVICE_MESSAGE; +} + +/** + * 请求的commendID + * + * @return 对应的commendID + */ +- (int)requestCommendID +{ + return CMD_MSG_UNREAD_CNT_REQ; +} + +/** + * 请求返回的commendID + * + * @return 对应的commendID + */ +- (int)responseCommendID +{ + return CMD_MSG_UNREAD_CNT_RES; +} + +/** + * 解析数据的block + * + * @return 解析数据的block + */ +- (Analysis)analysisReturnData +{ + Analysis analysis = (id)^(NSData* data) + { + IMUnreadMsgCntRsp *allGroupRsp = [IMUnreadMsgCntRsp parseFromData:data]; + NSArray* unreadInfoList = allGroupRsp.unreadinfoList; + __block NSMutableDictionary* unreadMessageDic = [[NSMutableDictionary alloc] init]; + [unreadInfoList enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) { + UnreadInfo* unreadInfo = (UnreadInfo*)obj; + SessionType sessionType = unreadInfo.sessionType; + NSUInteger unreadCnt = unreadInfo.unreadCnt; + NSString* originID = [NSString stringWithFormat:@"%i",unreadInfo.sessionId]; + NSString* sessionID = [MTSessionEntity getSessionIDForOriginID:originID sessionType:sessionType];; + [unreadMessageDic setObject:@(unreadCnt) forKey:sessionID]; + }]; + return unreadMessageDic; + }; + return analysis; +} + +/** + * 打包数据的block + * + * @return 打包数据的block + */ +- (Package)packageRequestObject +{ + Package package = (id)^(id object,uint16_t seqNo) + { + IMUnreadMsgCntReqBuilder *req = [IMUnreadMsgCntReq builder]; + + [req setUserId:[object intValue]]; + DataOutputStream *dataout = [[DataOutputStream alloc] init]; + [dataout writeInt:0]; + [dataout writeTcpProtocolHeader:DDSERVICE_MESSAGE + cId:CMD_MSG_UNREAD_CNT_REQ + seqNo:seqNo]; + [dataout directWriteBytes:[req build].data]; + [dataout writeDataCount]; + return [dataout toByteArray]; + }; + return package; +} +@end diff --git a/mac/TeamTalk/API/APIGroup/DDUserDetailInfoAPI.h b/mac/TeamTalk/API/APIGroup/DDUserDetailInfoAPI.h new file mode 100644 index 000000000..e038825b7 --- /dev/null +++ b/mac/TeamTalk/API/APIGroup/DDUserDetailInfoAPI.h @@ -0,0 +1,13 @@ +// +// DDUserDetailInfoAPI.h +// Duoduo +// +// Created by 独嘉 on 14-5-22. +// Copyright (c) 2014年 zuoye. All rights reserved. +// + +#import "DDSuperAPI.h" + +@interface DDUserDetailInfoAPI : DDSuperAPI + +@end diff --git a/mac/TeamTalk/API/APIGroup/DDUserDetailInfoAPI.m b/mac/TeamTalk/API/APIGroup/DDUserDetailInfoAPI.m new file mode 100644 index 000000000..5ac82f26b --- /dev/null +++ b/mac/TeamTalk/API/APIGroup/DDUserDetailInfoAPI.m @@ -0,0 +1,121 @@ +// +// DDUserDetailInfoAPI.m +// Duoduo +// +// Created by 独嘉 on 14-5-22. +// Copyright (c) 2014年 zuoye. All rights reserved. +// + +#import "DDUserDetailInfoAPI.h" +#import "IMBuddy.pb.h" +#import "MTUserEntity.h" + +@implementation DDUserDetailInfoAPI +/** + * 请求超时时间 + * + * @return 超时时间 + */ +- (int)requestTimeOutTimeInterval +{ + return 5; +} + +/** + * 请求的serviceID + * + * @return 对应的serviceID + */ +- (int)requestServiceID +{ + return MODULE_ID_SESSION; +} + +/** + * 请求返回的serviceID + * + * @return 对应的serviceID + */ +- (int)responseServiceID +{ + return MODULE_ID_SESSION; +} + +/** + * 请求的commendID + * + * @return 对应的commendID + */ +- (int)requestCommendID +{ + return CMD_FRI_LIST_DETAIL_INFO_REQ; +} + +/** + * 请求返回的commendID + * + * @return 对应的commendID + */ +- (int)responseCommendID +{ + return CMD_FRI_LIST_DETAIL_INFO_RES; +} + +/** + * 解析数据的block + * + * @return 解析数据的block + */ +- (Analysis)analysisReturnData +{ + Analysis analysis = (id)^(NSData* data) + { + IMUsersInfoRsp *userInfoRsp = [IMUsersInfoRsp parseFromData:data]; +// NSString* userID = [NSString stringWithFormat:@"%i",userInfoRsp.userId]; + NSArray* usersInfoList = userInfoRsp.userInfoList; + NSMutableArray* userInfos = [[NSMutableArray alloc] init]; + for (UserInfo* userInfo in usersInfoList) + { + MTUserEntity* user = [[MTUserEntity alloc] initWithUserInfo:userInfo]; + [userInfos addObject:user]; + } + return userInfos; + + }; + return analysis; +} + +/** + * 打包数据的block + * + * @return 打包数据的block + */ +- (Package)packageRequestObject +{ + Package package = (id)^(id object,uint16_t seqNo) + { + IMUsersInfoReqBuilder *userInfoReqBuilder = [IMUsersInfoReq builder]; + int myUserID = [[DDClientState shareInstance].userID intValue]; + [userInfoReqBuilder setUserId:myUserID]; + + NSArray* toRequestUserIDs = (NSArray*)object; + NSMutableArray* userIDs = [[NSMutableArray alloc] init]; + for (NSString* userID in toRequestUserIDs) + { + int userIDInt = [userID intValue]; + [userIDs addObject:@(userIDInt)]; + } + [userInfoReqBuilder setUserIdListArray:userIDs]; + + DataOutputStream *dataout = [[DataOutputStream alloc] init]; + [dataout writeInt:0]; + [dataout writeTcpProtocolHeader:MODULE_ID_SESSION + cId:CMD_FRI_LIST_DETAIL_INFO_REQ + seqNo:seqNo]; + [dataout directWriteBytes:[userInfoReqBuilder build].data]; + [dataout writeDataCount]; + return [dataout toByteArray]; + }; + return package; +} +@end diff --git a/mac/TeamTalk/API/APIGroup/DDUserMsgReceivedACKAPI.h b/mac/TeamTalk/API/APIGroup/DDUserMsgReceivedACKAPI.h new file mode 100644 index 000000000..83f8e9cc1 --- /dev/null +++ b/mac/TeamTalk/API/APIGroup/DDUserMsgReceivedACKAPI.h @@ -0,0 +1,15 @@ +// +// DDUserMsgReceivedACKAPI.h +// Duoduo +// +// Created by 独嘉 on 14-5-7. +// Copyright (c) 2014年 zuoye. All rights reserved. +// + +#import "DDSuperAPI.h" +/** + * 发送收到消息ACK,object,为数组,index1是fromuserID,index2是seqNo + */ +@interface DDUserMsgReceivedACKAPI : DDSuperAPI + +@end diff --git a/mac/TeamTalk/API/APIGroup/DDUserMsgReceivedACKAPI.m b/mac/TeamTalk/API/APIGroup/DDUserMsgReceivedACKAPI.m new file mode 100644 index 000000000..5380240b5 --- /dev/null +++ b/mac/TeamTalk/API/APIGroup/DDUserMsgReceivedACKAPI.m @@ -0,0 +1,103 @@ +// +// DDUserMsgReceivedACKAPI.m +// Duoduo +// +// Created by 独嘉 on 14-5-7. +// Copyright (c) 2014年 zuoye. All rights reserved. +// + +#import "DDUserMsgReceivedACKAPI.h" + +@implementation DDUserMsgReceivedACKAPI + +/** + * 请求超时时间 + * + * @return 超时时间 + */ +- (int)requestTimeOutTimeInterval +{ + return 0; +} + +/** + * 请求的serviceID + * + * @return 对应的serviceID + */ +- (int)requestServiceID +{ + return MODULE_ID_SESSION; +} + +/** + * 请求返回的serviceID + * + * @return 对应的serviceID + */ +- (int)responseServiceID +{ + return 0; +} + +/** + * 请求的commendID + * + * @return 对应的commendID + */ +- (int)requestCommendID +{ + return CMD_MSG_DATA_ACK; +} + +/** + * 请求返回的commendID + * + * @return 对应的commendID + */ +- (int)responseCommendID +{ + return 0; +} + +/** + * 解析数据的block + * + * @return 解析数据的block + */ +- (Analysis)analysisReturnData +{ + return nil; +} + +/** + * 打包数据的block + * + * @return 打包数据的block + */ +- (Package)packageRequestObject +{ + Package package = (id)^(id object,uint32_t seqNo) + { + NSArray* array = (NSArray*)object; + + NSString* fromUserId = array[0]; + int theSeqNo = [array[1] intValue]; + + DataOutputStream *dataout = [[DataOutputStream alloc] init]; + uint32_t totalLen = IM_PDU_HEADER_LEN + 4 * 2 + strLen(fromUserId); + + [dataout writeInt:totalLen]; + [dataout writeTcpProtocolHeader:MODULE_ID_SESSION cId:CMD_MSG_DATA_ACK seqNo:seqNo]; + + [dataout writeInt:(int32_t)theSeqNo]; + [dataout writeUTF:fromUserId]; + + log4CInfo(@"serviceID:%i cmdID:%i --> send msgData ACK from userID:%@",MODULE_ID_SESSION,CMD_MSG_DATA_ACK,fromUserId); + + return [dataout toByteArray]; + }; + return package; +} + +@end diff --git a/mac/TeamTalk/API/APIGroup/DDUserOnlineStateAPI.h b/mac/TeamTalk/API/APIGroup/DDUserOnlineStateAPI.h new file mode 100644 index 000000000..a16e283c6 --- /dev/null +++ b/mac/TeamTalk/API/APIGroup/DDUserOnlineStateAPI.h @@ -0,0 +1,13 @@ +// +// DDUserOnlineStateAPI.h +// Duoduo +// +// Created by 独嘉 on 14-5-8. +// Copyright (c) 2014年 zuoye. All rights reserved. +// + +#import "DDSuperAPI.h" + +@interface DDUserOnlineStateAPI : DDSuperAPI + +@end diff --git a/mac/TeamTalk/API/APIGroup/DDUserOnlineStateAPI.m b/mac/TeamTalk/API/APIGroup/DDUserOnlineStateAPI.m new file mode 100644 index 000000000..18a7f8c53 --- /dev/null +++ b/mac/TeamTalk/API/APIGroup/DDUserOnlineStateAPI.m @@ -0,0 +1,108 @@ +// +// DDUserOnlineStateAPI.m +// Duoduo +// +// Created by 独嘉 on 14-5-8. +// Copyright (c) 2014年 zuoye. All rights reserved. +// + +#import "DDUserOnlineStateAPI.h" +#import "IMBuddy.pb.h" +#import "IMBaseDefine.pb.h" + +@implementation DDUserOnlineStateAPI +/** + * 请求超时时间 + * + * @return 超时时间 + */ +- (int)requestTimeOutTimeInterval +{ + return 10; +} + +/** + * 请求的serviceID + * + * @return 对应的serviceID + */ +- (int)requestServiceID +{ + return MODULE_ID_SESSION; +} + +/** + * 请求返回的serviceID + * + * @return 对应的serviceID + */ +- (int)responseServiceID +{ + return MODULE_ID_SESSION; +} + +/** + * 请求的commendID + * + * @return 对应的commendID + */ +- (int)requestCommendID +{ + return CMD_FRI_LIST_STATE_REQ; +} + +/** + * 请求返回的commendID + * + * @return 对应的commendID + */ +- (int)responseCommendID +{ + return CMD_FRI_LIST_STATE_RES; +} + +/** + * 解析数据的block + * + * @return 解析数据的block + */ +- (Analysis)analysisReturnData +{ + Analysis analysis = (id)^(NSData* data) + { + IMUsersStatRsp *rsp = [IMUsersStatRsp parseFromData:data]; + return rsp; + }; + return analysis; +} + +/** + * 打包数据的block + * + * @return 打包数据的block + */ +- (Package)packageRequestObject +{ + Package package = (id)^(id object,uint16_t seqNo) + { +// UserStatBuilder *userBuilder = [UserStat builder]; +// [userBuilder setUserId:656]; +// [userBuilder setStatus:UserStatTypeUserStatusOnline]; + + IMUsersStatReqBuilder *reqBuilder = [IMUsersStatReq builder]; + [reqBuilder setUserId:0]; + NSArray* userList = [[NSArray alloc]initWithObjects:@(656), nil]; + [reqBuilder setUserIdListArray:userList]; + + DataOutputStream *dataout = [[DataOutputStream alloc] init]; + [dataout writeInt:0]; + [dataout writeTcpProtocolHeader:MODULE_ID_SESSION + cId:CMD_FRI_LIST_STATE_REQ + seqNo:seqNo]; + [dataout directWriteBytes:[reqBuilder build].data]; + [dataout writeDataCount]; + return [dataout toByteArray]; + }; + return package; +} +@end diff --git a/mac/TeamTalk/API/APIGroup/MTGroupChangeMemberAPI.h b/mac/TeamTalk/API/APIGroup/MTGroupChangeMemberAPI.h new file mode 100644 index 000000000..bbea80d0e --- /dev/null +++ b/mac/TeamTalk/API/APIGroup/MTGroupChangeMemberAPI.h @@ -0,0 +1,13 @@ +// +// MTGroupChangeMember.h +// Duoduo +// +// Created by zuoye on 15/2/1. +// Copyright (c) 2015年 mogujie. All rights reserved. +// + +#import "DDSuperAPI.h" + +@interface MTGroupChangeMemberAPI : DDSuperAPI + +@end diff --git a/mac/TeamTalk/API/APIGroup/MTGroupChangeMemberAPI.m b/mac/TeamTalk/API/APIGroup/MTGroupChangeMemberAPI.m new file mode 100644 index 000000000..b07be0670 --- /dev/null +++ b/mac/TeamTalk/API/APIGroup/MTGroupChangeMemberAPI.m @@ -0,0 +1,106 @@ +// +// MTGroupChangeMember.m +// Duoduo +// +// Created by zuoye on 15/2/1. +// Copyright (c) 2015年 mogujie. All rights reserved. +// + +#import "MTGroupChangeMemberAPI.h" +#import "IMBaseDefine.pb.h" +#import "IMGroup.pb.h" +#import "MTGroupModule.h" +#import "IMBaseDefine.pb.h" + +@implementation MTGroupChangeMemberAPI + +-(int) requestTimeOutTimeInterval{ + return 10; +} + +-(int)requestServiceID{ + return ServiceIDSidGroup; +} + +-(int)responseServiceID{ + return ServiceIDSidGroup; +} + +-(int) requestCommendID{ + return GroupCmdIDCidGroupChangeMemberRequest; +} + +-(int)responseCommendID{ + return GroupCmdIDCidGroupChangeMemberResponse; +} + +-(Analysis) analysisReturnData{ + Analysis analysis = (id)^(NSData *data){ + /* + required uint32 user_id = 1; + required IM.BaseDefine.GroupModifyType change_type = 2; + required uint32 result_code = 3; + required uint32 group_id = 4; + repeated uint32 cur_user_id_list = 5; //现有的成员id + repeated uint32 chg_user_id_list = 6; //变动的成员id,add: 表示添加成功的id, del: 表示删除的id + optional bytes attach_data = 20; + */ + IMGroupChangeMemberRsp *rsp = [IMGroupChangeMemberRsp parseFromData:data]; + + uint32_t result = rsp.resultCode; + if (result != 0) + { + return [NSDictionary dictionary]; + } + + NSString *groupId = [NSString stringWithFormat:@"%d", rsp.groupId]; + + NSInteger userCnt =[rsp.curUserIdList count]; + NSMutableArray *newUserIds = [NSMutableArray new]; + for (uint32_t i = 0; i < userCnt; i++) { + NSInteger userIdFromServer = [rsp.curUserIdList[i] integerValue]; + NSString* userId = [NSString stringWithFormat:@"%ld", userIdFromServer]; + [newUserIds addObject:userId]; + } + NSDictionary* dic = @{@"groupID":groupId,@"userIDs":newUserIds}; + + return dic; + }; + + return analysis; +} + +-(Package)packageRequestObject{ + Package package = (id)^(id object,uint16_t seqNo){ + + NSArray* array = (NSArray*)object; + NSString* groupId = array[0]; + NSArray* userList = array[1]; + GroupModifyType type = [array[2] intValue]; //add 1,del 2. + NSString *userId = array[3]; + DataOutputStream *dataout = [[DataOutputStream alloc] init]; + IMGroupChangeMemberReqBuilder *req = [IMGroupChangeMemberReq builder]; + [req setUserId:[userId intValue]]; + [req setGroupId:[groupId intValue]]; + [req setChangeType:type]; + NSMutableArray *originalID = [NSMutableArray new]; + for (NSString *localID in userList) { + int groupId = [localID intValue]; + [originalID addObject: @(groupId)]; + } + + [req setMemberIdListArray:originalID]; + + [dataout writeInt:0]; + [dataout writeTcpProtocolHeader:[self requestServiceID] + cId:[self requestCommendID] + seqNo:seqNo]; + [dataout directWriteBytes:[req build].data]; + [dataout writeDataCount]; + return [dataout toByteArray]; + + }; + return package; +} + +@end diff --git a/mac/TeamTalk/API/DDAPISchedule.h b/mac/TeamTalk/API/DDAPISchedule.h new file mode 100644 index 000000000..1ff607b04 --- /dev/null +++ b/mac/TeamTalk/API/DDAPISchedule.h @@ -0,0 +1,70 @@ +// +// DDAPISchedule.h +// Duoduo +// +// Created by 独嘉 on 14-4-24. +// Copyright (c) 2014年 zuoye. All rights reserved. +// + +#import +#import "DDAPIScheduleProtocol.h" +#import "DDAPIUnrequestScheduleProtocol.h" +typedef struct Response_Server_Data_Head { + int serviceID; + int commandID; + int seqNo; +}ServerDataType; + +NS_INLINE ServerDataType DDMakeServerDataType(int serviceID, int commendID,int seqNo) +{ + ServerDataType type; + type.serviceID = serviceID; + type.commandID = commendID; + type.seqNo = seqNo; + return type; +} + + +//TODO:应该有自己的专属线程 + +@interface DDAPISchedule : NSObject + +@property (nonatomic,readonly)dispatch_queue_t apiScheduleQueue; + ++ (instancetype)instance; + +/** + * 注册接口,此接口只应该在DDSuperAPI中被使用 + * + * @param api 接口 + */ +- (BOOL)registerApi:(id)api; + +/** + * 注册超时的查询表,此接口只应该在DDSuperAPI中被使用 + * + * @param api 接口 + */ +- (void)registerTimeoutApi:(id)api; + +/** + * 接收到服务器端的数据进行解析,对外的接口 + * + * @param data 服务器端的数据 + */ +- (void)receiveServerData:(NSData*)data forDataType:(ServerDataType)dataType; + +/** + * 注册没有请求,只有返回的api + * + * @param api api + */ +- (BOOL)registerUnrequestAPI:(id)api; + +/** + * 发送数据包 + * + * @param data 数据包 + */ +- (void)sendData:(NSMutableData*)data; +@end diff --git a/mac/TeamTalk/API/DDAPISchedule.m b/mac/TeamTalk/API/DDAPISchedule.m new file mode 100644 index 000000000..46c9e8036 --- /dev/null +++ b/mac/TeamTalk/API/DDAPISchedule.m @@ -0,0 +1,230 @@ +// +// DDAPISchedule.m +// Duoduo +// +// Created by 独嘉 on 14-4-24. +// Copyright (c) 2014年 zuoye. All rights reserved. +// + +#import "DDAPISchedule.h" +#import "DDSuperAPI.h" +#import "DDUnrequestSuperAPI.h" + +#define MAP_REQUEST_KEY(api) [NSString stringWithFormat:@"%i-%i-%i",[api requestServiceID],[api requestCommendID],[(DDSuperAPI*)api seqNo]] + +#define MAP_RESPONSE_KEY(api) [NSString stringWithFormat:@"response_%i-%i-%i",[api responseServiceID],[api responseCommendID],[(DDSuperAPI*)api seqNo]] + +#define MAP_DATA_RESPONSE_KEY(serverData) [NSString stringWithFormat:@"response_%i-%i-%i",serverData.serviceID,serverData.commandID,serverData.seqNo] + +#define MAP_UNREQUEST_KEY(api) [NSString stringWithFormat:@"%i-%i",[api responseServiceID],[api responseCommandID]] + +#define MAP_DATA_UNREQUEST_KEY(serverData) [NSString stringWithFormat:@"%i-%i",serverData.serviceID,serverData.commandID] + +typedef NS_ENUM(NSInteger, APIErrorCode){ + Timeout = 1001, + Result = 1002 +}; + +static NSInteger const timeInterval = 1; + +@interface DDAPISchedule(PrivateAPI) + +- (void)p_requestCompletion:(id)api; +- (void)p_timeoutOnTimer:(id)timer; + +@end + +@implementation DDAPISchedule +{ + NSMutableDictionary* _apiRequestMap; + NSMutableDictionary* _apiResponseMap; + + NSMutableDictionary* _unrequestMap; + NSMutableDictionary* _timeoutMap; + + NSTimer* _timeOutTimer; +} ++ (instancetype)instance +{ + static DDAPISchedule* g_apiSchedule; + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^{ + g_apiSchedule = [[DDAPISchedule alloc] init]; + }); + return g_apiSchedule; +} + +- (id)init +{ + self = [super init]; + if (self) + { + _apiRequestMap = [[NSMutableDictionary alloc] init]; + _apiResponseMap = [[NSMutableDictionary alloc] init]; + _unrequestMap = [[NSMutableDictionary alloc] init]; + _timeoutMap = [[NSMutableDictionary alloc] init]; + _apiScheduleQueue = dispatch_queue_create("com.mogujie.duoduo.apiSchedule", NULL); +// _timeOutTimer = [NSTimer scheduledTimerWithTimeInterval:timeInterval target:self selector:@selector(p_timeoutOnTimer:) userInfo:nil repeats:YES]; + } + return self; +} + +#pragma mark public +- (BOOL)registerApi:(id)api +{ + __block BOOL registSuccess = NO; + dispatch_sync(self.apiScheduleQueue, ^{ + if (![api analysisReturnData]) + { + registSuccess = YES; + } + if (![[_apiRequestMap allKeys] containsObject:MAP_REQUEST_KEY(api)]) + { + [_apiRequestMap setObject:api forKey:MAP_REQUEST_KEY(api)]; + registSuccess = YES; + } + else + { + registSuccess = NO; + } + + //注册返回数据处理 + if (![[_apiResponseMap allKeys] containsObject:MAP_RESPONSE_KEY(api)]) + { + [_apiResponseMap setObject:api forKey:MAP_RESPONSE_KEY(api)]; + } + }); + return registSuccess; +} + +- (void)registerTimeoutApi:(id)api +{ + double delayInSeconds = [api requestTimeOutTimeInterval]; + if (delayInSeconds == 0) + { + return; + } + +// [_timeoutMap setObject:api forKey:[NSDate date]]; + dispatch_time_t popTime = dispatch_time(DISPATCH_TIME_NOW, (int64_t)(delayInSeconds * NSEC_PER_SEC)); + dispatch_after(popTime, dispatch_get_main_queue(), ^(void){ + if ([[_apiRequestMap allKeys] containsObject:MAP_REQUEST_KEY(api)]) + { + RequestCompletion completion = [(DDSuperAPI*)api completion]; + NSError* error = [NSError errorWithDomain:@"请求超时" code:Timeout userInfo:nil]; + completion(nil,error); + [self p_requestCompletion:api]; + + } + }); +} + + +- (void)receiveServerData:(NSData*)data forDataType:(ServerDataType)dataType +{ + dispatch_async(self.apiScheduleQueue, ^{ + NSString* key = MAP_DATA_RESPONSE_KEY(dataType); + if(dataType.serviceID == 82 && dataType.commandID == 6) + { + DDLog(@"asd"); + } + //根据key去调用注册api的completion + id api = _apiResponseMap[key]; + if (api) + { + RequestCompletion completion = [(DDSuperAPI*)api completion]; + Analysis analysis = [api analysisReturnData]; + id response = analysis(data); + [self p_requestCompletion:api]; + dispatch_async(dispatch_get_main_queue(), ^{ + completion(response,nil); + }); + } + else + { + NSString* unrequestKey = MAP_DATA_UNREQUEST_KEY(dataType); + id unrequestAPI = _unrequestMap[unrequestKey]; + if (unrequestAPI) + { + UnrequestAPIAnalysis unrequestAnalysis = [unrequestAPI unrequestAnalysis]; + id object = unrequestAnalysis(data); + ReceiveData received = [(DDUnrequestSuperAPI*)unrequestAPI receivedData]; + dispatch_async(dispatch_get_main_queue(), ^{ + received(object,nil); + + }); + } + } + }); + +} + +- (BOOL)registerUnrequestAPI:(id)api +{ + __block BOOL registerSuccess = NO; + dispatch_sync(self.apiScheduleQueue, ^{ + NSString* key = MAP_UNREQUEST_KEY(api); + if ([[_unrequestMap allKeys] containsObject:key]) + { + registerSuccess = NO; + } + else + { + [_unrequestMap setObject:api forKey:key]; + registerSuccess = YES; + } + }); + return registerSuccess; +} + +- (void)sendData:(NSMutableData*)data +{ + dispatch_async(self.apiScheduleQueue, ^{ + [[DDTcpClientManager instance] writeToSocket:data]; + }); +} + +#pragma mark - privateAPI + +- (void)p_requestCompletion:(id)api +{ + [_apiRequestMap removeObjectForKey:MAP_REQUEST_KEY(api)]; + + [_apiResponseMap removeObjectForKey:MAP_RESPONSE_KEY(api)]; +} + +- (void)p_timeoutOnTimer:(id)timer +{ + NSDate* date = [NSDate date]; + NSInteger count = [_timeoutMap count]; + if (count == 0) + { + return; + } + NSArray* allKeys = [_timeoutMap allKeys]; + for (int index = 0; index < count; index ++) + { + NSDate* key = allKeys[index]; + id api = (id)[_timeoutMap objectForKey:key]; + NSDate* beginDate = (NSDate*)key; + NSInteger gap = [date timeIntervalSinceDate:beginDate]; + + NSInteger apitimeval = [api requestTimeOutTimeInterval]; + if (gap > apitimeval) + { + if ([[_apiRequestMap allKeys] containsObject:MAP_REQUEST_KEY(api)]) + { + RequestCompletion completion = [(DDSuperAPI*)api completion]; + NSError* error = [NSError errorWithDomain:@"请求超时" code:Timeout userInfo:nil]; + completion(nil,error); +// [self p_requestCompletion:obj]; + } + + } + } + [_timeoutMap enumerateKeysAndObjectsUsingBlock:^(id key, id obj, BOOL *stop) { + + }]; +} + +@end diff --git a/mac/TeamTalk/API/DDAPIScheduleProtocol.h b/mac/TeamTalk/API/DDAPIScheduleProtocol.h new file mode 100644 index 000000000..4d6da4e3b --- /dev/null +++ b/mac/TeamTalk/API/DDAPIScheduleProtocol.h @@ -0,0 +1,64 @@ +// +// DDNetworkAPIProtocol.h +// Duoduo +// +// Created by 独嘉 on 14-4-24. +// Copyright (c) 2014年 zuoye. All rights reserved. +// + +#import +typedef id(^Analysis)(NSData* data); +typedef NSMutableData*(^Package)(id object,uint16_t seqNO); + +@protocol DDAPIScheduleProtocol +@required + +/** + * 请求超时时间 + * + * @return 超时时间 + */ +- (int)requestTimeOutTimeInterval; + +/** + * 请求的serviceID + * + * @return 对应的serviceID + */ +- (int)requestServiceID; + +/** + * 请求返回的serviceID + * + * @return 对应的serviceID + */ +- (int)responseServiceID; + +/** + * 请求的commendID + * + * @return 对应的commendID + */ +- (int)requestCommendID; + +/** + * 请求返回的commendID + * + * @return 对应的commendID + */ +- (int)responseCommendID; + +/** + * 解析数据的block + * + * @return 解析数据的block + */ +- (Analysis)analysisReturnData; + +/** + * 打包数据的block + * + * @return 打包数据的block + */ +- (Package)packageRequestObject; +@end diff --git a/mac/TeamTalk/API/DDAPIUnrequestScheduleProtocol.h b/mac/TeamTalk/API/DDAPIUnrequestScheduleProtocol.h new file mode 100644 index 000000000..283e96089 --- /dev/null +++ b/mac/TeamTalk/API/DDAPIUnrequestScheduleProtocol.h @@ -0,0 +1,34 @@ +// +// DDAPIUnrequestScheduleProtocol.h +// Duoduo +// +// Created by 独嘉 on 14-5-7. +// Copyright (c) 2014年 zuoye. All rights reserved. +// + +#import +typedef id(^UnrequestAPIAnalysis)(NSData* data); + +@protocol DDAPIUnrequestScheduleProtocol +@required +/** + * 数据包中的serviceID + * + * @return serviceID + */ +- (int)responseServiceID; + +/** + * 数据包中的commandID + * + * @return commandID + */ +- (int)responseCommandID; + +/** + * 解析数据包 + * + * @return 解析数据包的block + */ +- (UnrequestAPIAnalysis)unrequestAnalysis; +@end diff --git a/mac/TeamTalk/API/DDRecentConactsAPI.h b/mac/TeamTalk/API/DDRecentConactsAPI.h new file mode 100644 index 000000000..5cb940380 --- /dev/null +++ b/mac/TeamTalk/API/DDRecentConactsAPI.h @@ -0,0 +1,12 @@ +// +// DDRecentConactsAPI.h +// Duoduo +// +// Created by 独嘉 on 14-4-24. +// Copyright (c) 2014年 zuoye. All rights reserved. +// + +#import "DDSuperAPI.h" +@interface DDRecentConactsAPI : DDSuperAPI + +@end diff --git a/mac/TeamTalk/API/DDRecentConactsAPI.m b/mac/TeamTalk/API/DDRecentConactsAPI.m new file mode 100644 index 000000000..9d386cbb3 --- /dev/null +++ b/mac/TeamTalk/API/DDRecentConactsAPI.m @@ -0,0 +1,83 @@ +// +// DDRecentConactsAPI.m +// Duoduo +// +// Created by 独嘉 on 14-4-24. +// Copyright (c) 2014年 zuoye. All rights reserved. +// + +#import "DDRecentConactsAPI.h" +#import "MTUserEntity.h" +#import "IMBuddy.pb.h" +#import "MTGroupEntity.h" +#import "MTSessionEntity.h" +@implementation DDRecentConactsAPI + +#pragma mark - DDAPIScheduleProtocol + +- (int)requestTimeOutTimeInterval +{ + return 20; +} + +- (int)requestServiceID +{ + return MODULE_ID_SESSION; +} + +- (int)responseServiceID +{ + return MODULE_ID_SESSION; +} + +- (int)requestCommendID +{ + return RECENT_SESSION_REQ; +} + +- (int)responseCommendID +{ + return RECENT_SESSION_RES; +} + +- (Analysis)analysisReturnData +{ + Analysis analysis = (id)^(NSData* data) + { + IMRecentContactSessionRsp *rsp =[IMRecentContactSessionRsp parseFromData:data]; + NSMutableArray *array = [NSMutableArray new]; + + for (ContactSessionInfo *sessionInfo in rsp.contactSessionList) { + NSString *originID =[NSString stringWithFormat:@"%d",sessionInfo.sessionId]; + SessionType sessionType =sessionInfo.sessionType; + NSInteger updated_time = sessionInfo.updatedTime; + MTSessionEntity *session =[[MTSessionEntity alloc] initWithOriginID:originID type:sessionType]; + session.lastMsg=[[NSString alloc] initWithData:sessionInfo.latestMsgData encoding:NSUTF8StringEncoding]; + [session updateUpdateTime:updated_time]; + session.lastMsgID=sessionInfo.latestMsgId; + [array addObject:session]; + } + return array; + }; + return analysis; +} + +- (Package)packageRequestObject +{ + Package package = (id)^(id object,uint16_t seqNo) + { + IMRecentContactSessionReqBuilder *req = [IMRecentContactSessionReq builder]; + [req setUserId:0]; + [req setLatestUpdateTime:(UInt32)[object[0] integerValue]]; + DataOutputStream *dataout = [[DataOutputStream alloc] init]; + [dataout writeInt:0]; + [dataout writeTcpProtocolHeader:MODULE_ID_SESSION + cId:RECENT_SESSION_REQ + seqNo:seqNo]; + [dataout directWriteBytes:[req build].data]; + [dataout writeDataCount]; + return [dataout toByteArray]; + }; + return package; +} +@end diff --git a/mac/TeamTalk/API/DDSeqNoManager.h b/mac/TeamTalk/API/DDSeqNoManager.h new file mode 100644 index 000000000..15e90d0c1 --- /dev/null +++ b/mac/TeamTalk/API/DDSeqNoManager.h @@ -0,0 +1,14 @@ +// +// DDSeqNoManager.h +// Duoduo +// +// Created by 独嘉 on 14-5-7. +// Copyright (c) 2014年 zuoye. All rights reserved. +// + +#import + +@interface DDSeqNoManager : NSObject ++ (instancetype)instance; +- (uint32_t)seqNo; +@end diff --git a/mac/TeamTalk/API/DDSeqNoManager.m b/mac/TeamTalk/API/DDSeqNoManager.m new file mode 100644 index 000000000..8e938894e --- /dev/null +++ b/mac/TeamTalk/API/DDSeqNoManager.m @@ -0,0 +1,41 @@ +// +// DDSeqNoManager.m +// Duoduo +// +// Created by 独嘉 on 14-5-7. +// Copyright (c) 2014年 zuoye. All rights reserved. +// + +#import "DDSeqNoManager.h" + +@implementation DDSeqNoManager +{ + uint32_t _seqNo; +} ++ (instancetype)instance +{ + static DDSeqNoManager* g_seqNoManager; + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^{ + g_seqNoManager = [[DDSeqNoManager alloc] init]; + }); + return g_seqNoManager; +} + +- (id)init +{ + self = [super init]; + if (self) + { + _seqNo = 0; + } + return self; +} + + +- (uint32_t)seqNo +{ + _seqNo ++; + return _seqNo; +} +@end diff --git a/mac/TeamTalk/API/DDSuperAPI.h b/mac/TeamTalk/API/DDSuperAPI.h new file mode 100644 index 000000000..12ffdc596 --- /dev/null +++ b/mac/TeamTalk/API/DDSuperAPI.h @@ -0,0 +1,33 @@ +// +// DDSuperAPI.h +// Duoduo +// +// Created by 独嘉 on 14-4-24. +// Copyright (c) 2014年 zuoye. All rights reserved. +// + +#import +#import "DDAPIScheduleProtocol.h" +#import "DDTcpClientManager.h" +#import "DataOutputStream.h" +#import "DataInputStream.h" +#import "DataOutputStream+Addition.h" +#import "TcpProtocolHeader.h" +typedef void(^RequestCompletion)(id response,NSError* error); + + +static uint32_t strLen(NSString *aString) +{ + return (uint32_t)[[aString dataUsingEncoding:NSUTF8StringEncoding] length]; +} + +/** + * 这是一个超级类,不能被直接使用 + */ +@interface DDSuperAPI : NSObject +@property (nonatomic,copy)RequestCompletion completion; +@property (nonatomic,readonly)uint16_t seqNo; + +- (void)requestWithObject:(id)object Completion:(RequestCompletion)completion; + +@end diff --git a/mac/TeamTalk/API/DDSuperAPI.m b/mac/TeamTalk/API/DDSuperAPI.m new file mode 100644 index 000000000..76fc1384d --- /dev/null +++ b/mac/TeamTalk/API/DDSuperAPI.m @@ -0,0 +1,63 @@ +// +// DDSuperAPI.m +// Duoduo +// +// Created by 独嘉 on 14-4-24. +// Copyright (c) 2014年 zuoye. All rights reserved. +// + +#import "DDSuperAPI.h" +#import "DDAPISchedule.h" +#import "DDSeqNoManager.h" + +static uint16_t theSeqNo = 0; + +@implementation DDSuperAPI +- (void)requestWithObject:(id)object Completion:(RequestCompletion)completion +{ + if ([DDClientState shareInstance].networkState == DDNetWorkDisconnect) + { + //断网的话直接返回失败 + NSError* error = [NSError errorWithDomain:@"网络断开" code:1004 userInfo:nil]; + if (completion) + { + completion(nil,error); + } + return; + } + + //seqNo + theSeqNo ++; + _seqNo = theSeqNo; + + //注册接口 + BOOL registerAPI = [[DDAPISchedule instance] registerApi:(id)self]; + + if (!registerAPI) + { + return; + } + + //注册请求超时 + if ([(id)self requestTimeOutTimeInterval] > 0) + { + [[DDAPISchedule instance] registerTimeoutApi:(id)self]; + } + + //保存完成块 + self.completion = completion; + + + //数据打包 + Package package = [(id)self packageRequestObject]; + NSMutableData* requestData = package(object,_seqNo); + + //发送 + if (requestData) + { + [[DDAPISchedule instance] sendData:requestData]; +// [[DDTcpClientManager instance] writeToSocket:requestData]; + } +} + +@end diff --git a/mac/TeamTalk/API/DDUnrequestSuperAPI.h b/mac/TeamTalk/API/DDUnrequestSuperAPI.h new file mode 100644 index 000000000..6cf29b056 --- /dev/null +++ b/mac/TeamTalk/API/DDUnrequestSuperAPI.h @@ -0,0 +1,17 @@ +// +// DDUnrequestSuperAPI.h +// Duoduo +// +// Created by 独嘉 on 14-5-7. +// Copyright (c) 2014年 zuoye. All rights reserved. +// + +#import +#import "DataInputStream.h" +#import "DDAPIUnrequestScheduleProtocol.h" +typedef void(^ReceiveData)(id object,NSError* error); + +@interface DDUnrequestSuperAPI : NSObject +@property (nonatomic,copy)ReceiveData receivedData; +- (BOOL)registerAPIInAPIScheduleReceiveData:(ReceiveData)received; +@end diff --git a/mac/TeamTalk/API/DDUnrequestSuperAPI.m b/mac/TeamTalk/API/DDUnrequestSuperAPI.m new file mode 100644 index 000000000..5a7faf798 --- /dev/null +++ b/mac/TeamTalk/API/DDUnrequestSuperAPI.m @@ -0,0 +1,25 @@ +// +// DDUnrequestSuperAPI.m +// Duoduo +// +// Created by 独嘉 on 14-5-7. +// Copyright (c) 2014年 zuoye. All rights reserved. +// + +#import "DDUnrequestSuperAPI.h" +#import "DDAPISchedule.h" +@implementation DDUnrequestSuperAPI +- (BOOL)registerAPIInAPIScheduleReceiveData:(ReceiveData)received +{ + BOOL registerSuccess = [[DDAPISchedule instance] registerUnrequestAPI:(id)self]; + if (registerSuccess) + { + self.receivedData = received; + return YES; + } + else + { + return NO; + } +} +@end diff --git a/mac/TeamTalk/API/DataOutputStream+Addition.h b/mac/TeamTalk/API/DataOutputStream+Addition.h new file mode 100644 index 000000000..05ff7f3cf --- /dev/null +++ b/mac/TeamTalk/API/DataOutputStream+Addition.h @@ -0,0 +1,13 @@ +// +// DataOutputStream+Addition.h +// Duoduo +// +// Created by 独嘉 on 14-5-6. +// Copyright (c) 2014年 zuoye. All rights reserved. +// + +#import "DataOutputStream.h" + +@interface DataOutputStream (Addition) +-(void)writeTcpProtocolHeader:(int16_t)sId cId:(int16_t)cId seqNo:(uint16_t)seqNo; +@end diff --git a/mac/TeamTalk/API/DataOutputStream+Addition.m b/mac/TeamTalk/API/DataOutputStream+Addition.m new file mode 100644 index 000000000..192be7888 --- /dev/null +++ b/mac/TeamTalk/API/DataOutputStream+Addition.m @@ -0,0 +1,22 @@ +// +// DataOutputStream+Addition.m +// Duoduo +// +// Created by 独嘉 on 14-5-6. +// Copyright (c) 2014年 zuoye. All rights reserved. +// + +#import "DataOutputStream+Addition.h" +#import "NSStream+NSStreamAddition.h" +@implementation DataOutputStream (Addition) +-(void)writeTcpProtocolHeader:(int16_t)sId cId:(int16_t)cId seqNo:(uint16_t)seqNo +{ + [self writeShort:IM_PDU_VERSION]; + [self writeShort:0]; //默认值 + [self writeShort:sId]; + [self writeShort:cId]; +// [self writeShort:0]; //默认值 + [self writeShort:seqNo]; //默认值 + [self writeShort:0]; //保留 +} +@end diff --git a/mac/TeamTalk/API/UnrequestAPI/DDAbortFileSendAPI.h b/mac/TeamTalk/API/UnrequestAPI/DDAbortFileSendAPI.h new file mode 100644 index 000000000..b8f56d845 --- /dev/null +++ b/mac/TeamTalk/API/UnrequestAPI/DDAbortFileSendAPI.h @@ -0,0 +1,13 @@ +// +// DDAbortFileSendAPI.h +// Duoduo +// +// Created by 独嘉 on 14-5-12. +// Copyright (c) 2014年 zuoye. All rights reserved. +// + +#import "DDSuperAPI.h" + +@interface DDAbortFileSendAPI : DDSuperAPI + +@end diff --git a/mac/TeamTalk/API/UnrequestAPI/DDAbortFileSendAPI.m b/mac/TeamTalk/API/UnrequestAPI/DDAbortFileSendAPI.m new file mode 100644 index 000000000..7730a39a9 --- /dev/null +++ b/mac/TeamTalk/API/UnrequestAPI/DDAbortFileSendAPI.m @@ -0,0 +1,101 @@ +// +// DDAbortFileSendAPI.m +// Duoduo +// +// Created by 独嘉 on 14-5-12. +// Copyright (c) 2014年 zuoye. All rights reserved. +// + +#import "DDAbortFileSendAPI.h" + +@implementation DDAbortFileSendAPI +/** + * 请求超时时间 + * + * @return 超时时间 + */ +- (int)requestTimeOutTimeInterval +{ + return 0; +} + +/** + * 请求的serviceID + * + * @return 对应的serviceID + */ +- (int)requestServiceID +{ + return MODULE_ID_FILETRANSFER; +} + +/** + * 请求返回的serviceID + * + * @return 对应的serviceID + */ +- (int)responseServiceID +{ + return 0; +} + +/** + * 请求的commendID + * + * @return 对应的commendID + */ +- (int)requestCommendID +{ + return CMD_FILE_ABORT; +} + +/** + * 请求返回的commendID + * + * @return 对应的commendID + */ +- (int)responseCommendID +{ + return 0; +} + +/** + * 解析数据的block + * + * @return 解析数据的block + */ +- (Analysis)analysisReturnData +{ + return nil; +} + +/** + * 打包数据的block + * + * @return 打包数据的block + */ +- (Package)packageRequestObject +{ + Package package = (id)^(id object,uint16_t seqNo) + { + NSArray* array = (NSArray*)object; + NSString* fromUserId = array[0]; + NSString* toUserId = array[1]; + NSString* filePath = array[2]; + DataOutputStream *dataout = [[DataOutputStream alloc] init]; + uint32_t totalLen = IM_PDU_HEADER_LEN + 4 * 3 + + strLen(fromUserId) + strLen(toUserId) + strLen(filePath); + + [dataout writeInt:totalLen]; + [dataout writeTcpProtocolHeader:MODULE_ID_FILETRANSFER cId:CMD_FILE_ABORT seqNo:seqNo]; + [dataout writeUTF:fromUserId]; + [dataout writeUTF:toUserId]; + [dataout writeUTF:filePath]; + + log4CInfo(@"serviceID:%i cmdID:%i --> abort file transfer from user:%@ to user:%@",MODULE_ID_FILETRANSFER,CMD_FILE_ABORT,fromUserId,toUserId); + + return [dataout toByteArray]; + }; + return package; +} +@end diff --git a/mac/TeamTalk/API/UnrequestAPI/DDAddOfflineFileAPI.h b/mac/TeamTalk/API/UnrequestAPI/DDAddOfflineFileAPI.h new file mode 100644 index 000000000..598395c4b --- /dev/null +++ b/mac/TeamTalk/API/UnrequestAPI/DDAddOfflineFileAPI.h @@ -0,0 +1,13 @@ +// +// DDAddOfflineFileAPI.h +// Duoduo +// +// Created by 独嘉 on 14-5-12. +// Copyright (c) 2014年 zuoye. All rights reserved. +// + +#import "DDSuperAPI.h" + +@interface DDAddOfflineFileAPI : DDSuperAPI + +@end diff --git a/mac/TeamTalk/API/UnrequestAPI/DDAddOfflineFileAPI.m b/mac/TeamTalk/API/UnrequestAPI/DDAddOfflineFileAPI.m new file mode 100644 index 000000000..f5b8761be --- /dev/null +++ b/mac/TeamTalk/API/UnrequestAPI/DDAddOfflineFileAPI.m @@ -0,0 +1,105 @@ +// +// DDAddOfflineFileAPI.m +// Duoduo +// +// Created by 独嘉 on 14-5-12. +// Copyright (c) 2014年 zuoye. All rights reserved. +// + +#import "DDAddOfflineFileAPI.h" + +@implementation DDAddOfflineFileAPI +/** + * 请求超时时间 + * + * @return 超时时间 + */ +- (int)requestTimeOutTimeInterval +{ + return 0; +} + +/** + * 请求的serviceID + * + * @return 对应的serviceID + */ +- (int)requestServiceID +{ + return MODULE_ID_FILETRANSFER; +} + +/** + * 请求返回的serviceID + * + * @return 对应的serviceID + */ +- (int)responseServiceID +{ + return 0; +} + +/** + * 请求的commendID + * + * @return 对应的commendID + */ +- (int)requestCommendID +{ + return CMD_FILE_ADD_OFFLINE_REQ; +} + +/** + * 请求返回的commendID + * + * @return 对应的commendID + */ +- (int)responseCommendID +{ + return 0; +} + +/** + * 解析数据的block + * + * @return 解析数据的block + */ +- (Analysis)analysisReturnData +{ + return nil; +} + +/** + * 打包数据的block + * + * @return 打包数据的block + */ +- (Package)packageRequestObject +{ + Package package = (id)^(id object,uint16_t seqNo) + { + NSArray* array = (NSArray*)object; + NSString* fromUserId = array[0]; + NSString* toUserId = array[1]; + NSString* filePath = array[2]; + int fileSize = [array[3] intValue]; + + DataOutputStream *dataout = [[DataOutputStream alloc] init]; + uint32_t totalLen = IM_PDU_HEADER_LEN + 4 * 4 + + strLen(fromUserId) + strLen(toUserId) + strLen(filePath); + + [dataout writeInt:totalLen]; + [dataout writeTcpProtocolHeader:MODULE_ID_FILETRANSFER cId:CMD_FILE_ADD_OFFLINE_REQ seqNo:seqNo]; + + [dataout writeUTF:fromUserId]; + [dataout writeUTF:toUserId]; + [dataout writeUTF:filePath]; + [dataout writeInt:fileSize]; + + log4CInfo(@"serviceID:%i cmdID:%i --> save offline file to java db from user:%@ to user:%@ file path:%@ file size:%f",MODULE_ID_FILETRANSFER,CMD_FILE_ADD_OFFLINE_REQ,fromUserId,toUserId,filePath,fileSize); + + return [dataout toByteArray]; + }; + return package; +} +@end diff --git a/mac/TeamTalk/API/UnrequestAPI/DDDeleteOfflineFileAPI.h b/mac/TeamTalk/API/UnrequestAPI/DDDeleteOfflineFileAPI.h new file mode 100644 index 000000000..68a9232d5 --- /dev/null +++ b/mac/TeamTalk/API/UnrequestAPI/DDDeleteOfflineFileAPI.h @@ -0,0 +1,13 @@ +// +// DDDeleteOfflineFileAPI.h +// Duoduo +// +// Created by 独嘉 on 14-5-12. +// Copyright (c) 2014年 zuoye. All rights reserved. +// + +#import "DDSuperAPI.h" + +@interface DDDeleteOfflineFileAPI : DDSuperAPI + +@end diff --git a/mac/TeamTalk/API/UnrequestAPI/DDDeleteOfflineFileAPI.m b/mac/TeamTalk/API/UnrequestAPI/DDDeleteOfflineFileAPI.m new file mode 100644 index 000000000..fe50d2d1b --- /dev/null +++ b/mac/TeamTalk/API/UnrequestAPI/DDDeleteOfflineFileAPI.m @@ -0,0 +1,103 @@ +// +// DDDeleteOfflineFileAPI.m +// Duoduo +// +// Created by 独嘉 on 14-5-12. +// Copyright (c) 2014年 zuoye. All rights reserved. +// + +#import "DDDeleteOfflineFileAPI.h" + +@implementation DDDeleteOfflineFileAPI +/** + * 请求超时时间 + * + * @return 超时时间 + */ +- (int)requestTimeOutTimeInterval +{ + return 0; +} + +/** + * 请求的serviceID + * + * @return 对应的serviceID + */ +- (int)requestServiceID +{ + return MODULE_ID_FILETRANSFER; +} + +/** + * 请求返回的serviceID + * + * @return 对应的serviceID + */ +- (int)responseServiceID +{ + return 0; +} + +/** + * 请求的commendID + * + * @return 对应的commendID + */ +- (int)requestCommendID +{ + return CMD_FILE_DEL_OFFLINE_REQ; +} + +/** + * 请求返回的commendID + * + * @return 对应的commendID + */ +- (int)responseCommendID +{ + return 0; +} + +/** + * 解析数据的block + * + * @return 解析数据的block + */ +- (Analysis)analysisReturnData +{ + return nil; +} + +/** + * 打包数据的block + * + * @return 打包数据的block + */ +- (Package)packageRequestObject +{ + Package package = (id)^(id object,uint16_t seqNo) + { + NSArray* array = (NSArray*)object; + NSString* fromUserId = array[0]; + NSString* toUserId = array[1]; + int fileId = [array[2] intValue]; + + DataOutputStream *dataout = [[DataOutputStream alloc] init]; + uint32_t totalLen = IM_PDU_HEADER_LEN + 4 * 3 + + strLen(fromUserId) + strLen(toUserId); + + [dataout writeInt:totalLen]; + [dataout writeTcpProtocolHeader:MODULE_ID_FILETRANSFER cId:CMD_FILE_DEL_OFFLINE_REQ seqNo:seqNo]; + + [dataout writeUTF:fromUserId]; + [dataout writeUTF:toUserId]; + [dataout writeInt:fileId]; + + log4CInfo(@"serviceID:%i cmdID:%i --> delete offline file from java db from user:%@ to user:%@ fileID:%i",MODULE_ID_FILETRANSFER,CMD_FILE_DEL_OFFLINE_REQ,fromUserId,toUserId, fileId); + + return [dataout toByteArray]; + }; + return package; +} +@end diff --git a/mac/TeamTalk/API/UnrequestAPI/DDOnlineUserListAPI.h b/mac/TeamTalk/API/UnrequestAPI/DDOnlineUserListAPI.h new file mode 100644 index 000000000..6e6da24c4 --- /dev/null +++ b/mac/TeamTalk/API/UnrequestAPI/DDOnlineUserListAPI.h @@ -0,0 +1,14 @@ +// +// DDReceiveOnlineUserListAPI.h +// Duoduo +// +// Created by 独嘉 on 14-5-8. +// Copyright (c) 2014年 zuoye. All rights reserved. +// + +#import "DDSuperAPI.h" + + +@interface DDOnlineUserListAPI : DDSuperAPI + +@end diff --git a/mac/TeamTalk/API/UnrequestAPI/DDOnlineUserListAPI.m b/mac/TeamTalk/API/UnrequestAPI/DDOnlineUserListAPI.m new file mode 100644 index 000000000..2fbbbec53 --- /dev/null +++ b/mac/TeamTalk/API/UnrequestAPI/DDOnlineUserListAPI.m @@ -0,0 +1,87 @@ +// +// DDReceiveOnlineUserListAPI.m +// Duoduo +// +// Created by 独嘉 on 14-5-8. +// Copyright (c) 2014年 zuoye. All rights reserved. +// + +#import "DDOnlineUserListAPI.h" +#import "IMBuddy.pb.h" + + +@implementation DDOnlineUserListAPI + +- (int)requestServiceID +{ + return ServiceIDSidBuddyList; +} + +- (int)responseServiceID +{ + return ServiceIDSidBuddyList; +} + +- (int)requestCommendID +{ + return BuddyListCmdIDCidBuddyListUsersStatusRequest; +} + +- (int)responseCommendID +{ + return BuddyListCmdIDCidBuddyListUsersStatusResponse; +} + +- (int)requestTimeOutTimeInterval +{ + return 10; +} + + +/** + * 解析数据的block + * + * @return 解析数据的block + */ +- (Analysis)analysisReturnData +{ + + + Analysis analysis = (id)^(NSData* data) + { + IMUsersStatRsp *allUserStateRsp = [IMUsersStatRsp parseFromData:data]; + + NSArray *usersStatList = allUserStateRsp.userStatList; + + return usersStatList; + }; + return analysis; +} + +/** + * 打包数据的block + * + * @return 打包数据的block + */ +- (Package)packageRequestObject +{ + Package package = (id)^(id object,uint32_t seqNo) + { + IMUsersStatReqBuilder *reqBuilder =[IMUsersStatReq builder]; + + [reqBuilder setUserId:0]; + [reqBuilder setUserIdListArray:(NSArray *)object]; + + DataOutputStream *dataout = [[DataOutputStream alloc] init]; + [dataout writeInt:0]; + [dataout writeTcpProtocolHeader:[self requestServiceID] + cId:[self requestCommendID] + seqNo:seqNo]; + [dataout directWriteBytes:[reqBuilder build].data]; + [dataout writeDataCount]; + return [dataout toByteArray]; + }; + return package; +} + +@end diff --git a/mac/TeamTalk/API/UnrequestAPI/DDOtherFileResponseAPI.h b/mac/TeamTalk/API/UnrequestAPI/DDOtherFileResponseAPI.h new file mode 100644 index 000000000..e1f199690 --- /dev/null +++ b/mac/TeamTalk/API/UnrequestAPI/DDOtherFileResponseAPI.h @@ -0,0 +1,13 @@ +// +// DDOtherFileResponse.h +// Duoduo +// +// Created by 独嘉 on 14-5-12. +// Copyright (c) 2014年 zuoye. All rights reserved. +// + +#import "DDUnrequestSuperAPI.h" + +@interface DDOtherFileResponseAPI : DDUnrequestSuperAPI + +@end diff --git a/mac/TeamTalk/API/UnrequestAPI/DDOtherFileResponseAPI.m b/mac/TeamTalk/API/UnrequestAPI/DDOtherFileResponseAPI.m new file mode 100644 index 000000000..3913e92f0 --- /dev/null +++ b/mac/TeamTalk/API/UnrequestAPI/DDOtherFileResponseAPI.m @@ -0,0 +1,66 @@ +// +// DDOtherFileResponse.m +// Duoduo +// +// Created by 独嘉 on 14-5-12. +// Copyright (c) 2014年 zuoye. All rights reserved. +// + +#import "DDOtherFileResponseAPI.h" +#import "FileTransferEntity.h" +@implementation DDOtherFileResponseAPI + +/** + * 数据包中的serviceID + * + * @return serviceID + */ +- (int)responseServiceID +{ + return MODULE_ID_FILETRANSFER; +} + +/** + * 数据包中的commandID + * + * @return commandID + */ +- (int)responseCommandID +{ + return CMD_FILE_RESPONSE; +} + +/** + * 解析数据包 + * + * @return 解析数据包的block + */ +- (UnrequestAPIAnalysis)unrequestAnalysis +{ + UnrequestAPIAnalysis analysis = (id)^(NSData* data) + { + DataInputStream* bodyData = [DataInputStream dataInputStreamWithData:data]; + NSString *fromUserId = [bodyData readUTF]; + NSString *toUserId = [bodyData readUTF]; + NSString *fileName = [bodyData readUTF]; + uint32_t acceptFlag = [bodyData readInt]; + NSString *listenIp = [bodyData readUTF]; + uint16_t listenPort = [bodyData readShort]; + DDLog(@"handleFileResponse, %@->%@, fileName=%@, acceptFlag=%d, " + "listenIp=%@, listenPort=%d", fromUserId, toUserId, fileName, + acceptFlag, listenIp, listenPort); + + FileTransferEntity* entity = [[FileTransferEntity alloc] init]; + entity.fromUserId = fromUserId; + entity.toUserId = toUserId; + entity.fileName = fileName; + entity.acceptFlag = acceptFlag; + entity.listenIp = listenIp; + entity.listenPort = listenPort; + return entity; + + }; + return analysis; +} + +@end diff --git a/mac/TeamTalk/API/UnrequestAPI/DDOtherLinkFileServerAPI.h b/mac/TeamTalk/API/UnrequestAPI/DDOtherLinkFileServerAPI.h new file mode 100644 index 000000000..359bff59b --- /dev/null +++ b/mac/TeamTalk/API/UnrequestAPI/DDOtherLinkFileServerAPI.h @@ -0,0 +1,13 @@ +// +// DDOtherLinkFileServerAPI.h +// Duoduo +// +// Created by 独嘉 on 14-5-9. +// Copyright (c) 2014年 zuoye. All rights reserved. +// + +#import "DDUnrequestSuperAPI.h" + +@interface DDOtherLinkFileServerAPI : DDUnrequestSuperAPI + +@end diff --git a/mac/TeamTalk/API/UnrequestAPI/DDOtherLinkFileServerAPI.m b/mac/TeamTalk/API/UnrequestAPI/DDOtherLinkFileServerAPI.m new file mode 100644 index 000000000..8a3ab8595 --- /dev/null +++ b/mac/TeamTalk/API/UnrequestAPI/DDOtherLinkFileServerAPI.m @@ -0,0 +1,54 @@ +// +// DDOtherLinkFileServerAPI.m +// Duoduo +// +// Created by 独嘉 on 14-5-9. +// Copyright (c) 2014年 zuoye. All rights reserved. +// + +#import "DDOtherLinkFileServerAPI.h" +#import "FileTransferEntity.h" + +@implementation DDOtherLinkFileServerAPI +/** + * 数据包中的serviceID + * + * @return serviceID + */ +- (int)responseServiceID +{ + return MODULE_ID_FILETRANSFER; +} + +/** + * 数据包中的commandID + * + * @return commandID + */ +- (int)responseCommandID +{ + return CMD_FILE_RECV_READY; +} + +/** + * 解析数据包 + * + * @return 解析数据包的block + */ +- (UnrequestAPIAnalysis)unrequestAnalysis +{ + UnrequestAPIAnalysis analysis = (id)^(NSData* data) + { + DataInputStream* bodyData = [DataInputStream dataInputStreamWithData:data]; + NSString *fromUserId = [bodyData readUTF]; + NSString *toUserId = [bodyData readUTF]; + DDLog(@"handleFileRecvReady, %@->%@", fromUserId, toUserId); + + FileTransferEntity* entity = [[FileTransferEntity alloc] init]; + entity.fromUserId = fromUserId; + entity.toUserId = toUserId; + return entity; + }; + return analysis; +} +@end diff --git a/mac/TeamTalk/API/UnrequestAPI/DDOtherSendOfflineFileAPI.h b/mac/TeamTalk/API/UnrequestAPI/DDOtherSendOfflineFileAPI.h new file mode 100644 index 000000000..19942268d --- /dev/null +++ b/mac/TeamTalk/API/UnrequestAPI/DDOtherSendOfflineFileAPI.h @@ -0,0 +1,13 @@ +// +// DDOtherSendOfflineFileAPI.h +// Duoduo +// +// Created by 独嘉 on 14-5-12. +// Copyright (c) 2014年 zuoye. All rights reserved. +// + +#import "DDUnrequestSuperAPI.h" + +@interface DDOtherSendOfflineFileAPI : DDUnrequestSuperAPI + +@end diff --git a/mac/TeamTalk/API/UnrequestAPI/DDOtherSendOfflineFileAPI.m b/mac/TeamTalk/API/UnrequestAPI/DDOtherSendOfflineFileAPI.m new file mode 100644 index 000000000..108f8e451 --- /dev/null +++ b/mac/TeamTalk/API/UnrequestAPI/DDOtherSendOfflineFileAPI.m @@ -0,0 +1,55 @@ +// +// DDOtherSendOfflineFileAPI.m +// Duoduo +// +// Created by 独嘉 on 14-5-12. +// Copyright (c) 2014年 zuoye. All rights reserved. +// + +#import "DDOtherSendOfflineFileAPI.h" +#import "FileTransferEntity.h" +@implementation DDOtherSendOfflineFileAPI +/** + * 数据包中的serviceID + * + * @return serviceID + */ +- (int)responseServiceID +{ + return MODULE_ID_FILETRANSFER; +} + + +/** + * 数据包中的commandID + * + * @return commandID + */ +- (int)responseCommandID +{ + return CMD_FILE_UPLOAD_OFFLINE_NOTIFY; +} + +/** + * 解析数据包 + * + * @return 解析数据包的block + */ +- (UnrequestAPIAnalysis)unrequestAnalysis +{ + UnrequestAPIAnalysis analysis = (id)^(NSData* data) + { + DataInputStream* bodyData = [DataInputStream dataInputStreamWithData:data]; + NSString *fromUserId = [bodyData readUTF]; + NSString *toUserId = [bodyData readUTF]; + NSString *filePath = [bodyData readUTF]; + DDLog(@"handleFileUploadOfflineNotify, %@->%@", fromUserId, toUserId); + FileTransferEntity* entity = [[FileTransferEntity alloc] init]; + entity.fromUserId = fromUserId; + entity.toUserId = toUserId; + entity.fileName = filePath; + return entity; + }; + return analysis; +} +@end diff --git a/mac/TeamTalk/API/UnrequestAPI/DDReceiveAbortFileSendAPI.h b/mac/TeamTalk/API/UnrequestAPI/DDReceiveAbortFileSendAPI.h new file mode 100644 index 000000000..2b0cb8ad3 --- /dev/null +++ b/mac/TeamTalk/API/UnrequestAPI/DDReceiveAbortFileSendAPI.h @@ -0,0 +1,13 @@ +// +// DDReceiveAbortFileSendAPI.h +// Duoduo +// +// Created by 独嘉 on 14-5-12. +// Copyright (c) 2014年 zuoye. All rights reserved. +// + +#import "DDUnrequestSuperAPI.h" + +@interface DDReceiveAbortFileSendAPI : DDUnrequestSuperAPI + +@end diff --git a/mac/TeamTalk/API/UnrequestAPI/DDReceiveAbortFileSendAPI.m b/mac/TeamTalk/API/UnrequestAPI/DDReceiveAbortFileSendAPI.m new file mode 100644 index 000000000..29c117bff --- /dev/null +++ b/mac/TeamTalk/API/UnrequestAPI/DDReceiveAbortFileSendAPI.m @@ -0,0 +1,58 @@ +// +// DDReceiveAbortFileSendAPI.m +// Duoduo +// +// Created by 独嘉 on 14-5-12. +// Copyright (c) 2014年 zuoye. All rights reserved. +// + +#import "DDReceiveAbortFileSendAPI.h" +#import "FileTransferEntity.h" + +@implementation DDReceiveAbortFileSendAPI + +/** + * 数据包中的serviceID + * + * @return serviceID + */ +- (int)responseServiceID +{ + return MODULE_ID_FILETRANSFER; +} + +/** + * 数据包中的commandID + * + * @return commandID + */ +- (int)responseCommandID +{ + return CMD_FILE_ABORT; +} + +/** + * 解析数据包 + * + * @return 解析数据包的block + */ +- (UnrequestAPIAnalysis)unrequestAnalysis +{ + UnrequestAPIAnalysis analysis = (id)^(NSData* object) + { + DataInputStream* bodyData = [DataInputStream dataInputStreamWithData:object]; + NSString *fromUserId = [bodyData readUTF]; + NSString *toUserId = [bodyData readUTF]; + NSString *filePath = [bodyData readUTF]; + DDLog(@"handleFileAbort, %@->%@", fromUserId, toUserId); + FileTransferEntity* entity = [[FileTransferEntity alloc] init]; + entity.fromUserId = fromUserId; + entity.toUserId = toUserId; + entity.fileName = filePath; + return entity; + }; + return analysis; +} + + +@end diff --git a/mac/TeamTalk/API/UnrequestAPI/DDReceiveGroupMemberChangedAPI.h b/mac/TeamTalk/API/UnrequestAPI/DDReceiveGroupMemberChangedAPI.h new file mode 100644 index 000000000..e3f866a3d --- /dev/null +++ b/mac/TeamTalk/API/UnrequestAPI/DDReceiveGroupMemberChangedAPI.h @@ -0,0 +1,13 @@ +// +// DDReceiveGroupMemberChangedAPI.h +// Duoduo +// +// Created by 独嘉 on 15/2/2. +// Copyright (c) 2015年 mogujie. All rights reserved. +// + +#import "DDUnrequestSuperAPI.h" + +@interface DDReceiveGroupMemberChangedAPI : DDUnrequestSuperAPI + +@end diff --git a/mac/TeamTalk/API/UnrequestAPI/DDReceiveGroupMemberChangedAPI.m b/mac/TeamTalk/API/UnrequestAPI/DDReceiveGroupMemberChangedAPI.m new file mode 100644 index 000000000..3d35929fb --- /dev/null +++ b/mac/TeamTalk/API/UnrequestAPI/DDReceiveGroupMemberChangedAPI.m @@ -0,0 +1,64 @@ +// +// DDReceiveGroupMemberChangedAPI.m +// Duoduo +// +// Created by 独嘉 on 15/2/2. +// Copyright (c) 2015年 mogujie. All rights reserved. +// + +#import "DDReceiveGroupMemberChangedAPI.h" +#import "IMBaseDefine.pb.h" +#import "IMGroup.pb.h" +#import "MTGroupModule.h" +#import "IMBaseDefine.pb.h" + +@implementation DDReceiveGroupMemberChangedAPI +/** + * 数据包中的serviceID + * + * @return serviceID + */ +- (int)responseServiceID +{ + return ServiceIDSidGroup; +} + +/** + * 数据包中的commandID + * + * @return commandID + */ +- (int)responseCommandID +{ + return GroupCmdIDCidGroupChangeMemberNotify; +} + +/** + * 解析数据包 + * + * @return 解析数据包的block + */ +- (UnrequestAPIAnalysis)unrequestAnalysis +{ + UnrequestAPIAnalysis analysis = (id)^(NSData* data) + { + IMGroupChangeMemberNotify *rsp = [IMGroupChangeMemberNotify parseFromData:data]; + + NSString *groupId = [NSString stringWithFormat:@"%d", rsp.groupId]; + + PBArray* currentUserIDs = rsp.curUserIdList; + NSMutableArray* userIDs = [[NSMutableArray alloc] init]; + for (NSInteger index = 0; index < [currentUserIDs count]; index ++) + { + NSUInteger userIDint = [currentUserIDs[index] integerValue]; + NSString* userID = [NSString stringWithFormat:@"%li",userIDint]; + [userIDs addObject:userID]; + } + NSDictionary* dic = @{@"groupID":groupId,@"userIDs":userIDs}; + + return dic; + + }; + return analysis; +} +@end diff --git a/mac/TeamTalk/API/UnrequestAPI/DDReceiveKickAPI.h b/mac/TeamTalk/API/UnrequestAPI/DDReceiveKickAPI.h new file mode 100644 index 000000000..5b73b9366 --- /dev/null +++ b/mac/TeamTalk/API/UnrequestAPI/DDReceiveKickAPI.h @@ -0,0 +1,13 @@ +// +// DDReceiveKickAPI.h +// Duoduo +// +// Created by 独嘉 on 14-5-8. +// Copyright (c) 2014年 zuoye. All rights reserved. +// + +#import "DDUnrequestSuperAPI.h" + +@interface DDReceiveKickAPI : DDUnrequestSuperAPI + +@end diff --git a/mac/TeamTalk/API/UnrequestAPI/DDReceiveKickAPI.m b/mac/TeamTalk/API/UnrequestAPI/DDReceiveKickAPI.m new file mode 100644 index 000000000..75a7a1750 --- /dev/null +++ b/mac/TeamTalk/API/UnrequestAPI/DDReceiveKickAPI.m @@ -0,0 +1,55 @@ +// +// DDReceiveKickAPI.m +// Duoduo +// +// Created by 独嘉 on 14-5-8. +// Copyright (c) 2014年 zuoye. All rights reserved. +// + +#import "DDReceiveKickAPI.h" +#import "IMLogin.pb.h" +@implementation DDReceiveKickAPI +/** + * 数据包中的serviceID + * + * @return serviceID + */ +- (int)responseServiceID +{ + return ServiceIDSidLogin; +} + +/** + * 数据包中的commandID + * + * @return commandID + */ +- (int)responseCommandID +{ + return LoginCmdIDCidLoginKickUser; +} + +/** + * 解析数据包 + * + * @return 解析数据包的block + */ +- (UnrequestAPIAnalysis)unrequestAnalysis +{ + UnrequestAPIAnalysis analysis = (id)^(NSData* data) + { + IMKickUser* kickUserNotify = [IMKickUser parseFromData:data]; + NSString* userID = [NSString stringWithFormat:@"%i",kickUserNotify.userId]; + if ([userID isEqualToString:[DDClientState shareInstance].userID]) + { + KickReasonType reason = kickUserNotify.kickReason; + return @(reason); + } + else + { + return @(100); + } + }; + return analysis; +} +@end diff --git a/mac/TeamTalk/API/UnrequestAPI/DDReceiveMessageAPI.h b/mac/TeamTalk/API/UnrequestAPI/DDReceiveMessageAPI.h new file mode 100644 index 000000000..2bb579e39 --- /dev/null +++ b/mac/TeamTalk/API/UnrequestAPI/DDReceiveMessageAPI.h @@ -0,0 +1,13 @@ +// +// DDReceiveAPI.h +// Duoduo +// +// Created by 独嘉 on 14-5-7. +// Copyright (c) 2014年 zuoye. All rights reserved. +// + +#import "DDAPIUnrequestScheduleProtocol.h" +#import "DDUnrequestSuperAPI.h" +@interface DDReceiveMessageAPI : DDUnrequestSuperAPI + +@end diff --git a/mac/TeamTalk/API/UnrequestAPI/DDReceiveMessageAPI.m b/mac/TeamTalk/API/UnrequestAPI/DDReceiveMessageAPI.m new file mode 100644 index 000000000..2e39fbb05 --- /dev/null +++ b/mac/TeamTalk/API/UnrequestAPI/DDReceiveMessageAPI.m @@ -0,0 +1,54 @@ +// +// DDReceiveAPI.m +// Duoduo +// +// Created by 独嘉 on 14-5-7. +// Copyright (c) 2014年 zuoye. All rights reserved. +// + +#import "DDReceiveMessageAPI.h" +#import "MTMessageEntity.h" +#import "IMMessage.pb.h" +#import "MTSessionEntity.h" +@implementation DDReceiveMessageAPI +/** + * 数据包中的serviceID + * + * @return serviceID + */ +- (int)responseServiceID +{ + return DDSERVICE_MESSAGE; +} + + +/** + * 数据包中的commandID + * + * @return commandID + */ +- (int)responseCommandID +{ + return CMD_MSG_DATA; +} + +/** + * 解析数据包 + * + * @return 解析数据包的block + */ +- (UnrequestAPIAnalysis)unrequestAnalysis +{ + UnrequestAPIAnalysis analysis = (id)^(NSData* data) + { + IMMsgData *msgRsp = [IMMsgData parseFromData:data]; + + MTMessageEntity *message = [[MTMessageEntity alloc] initWithMessageData:msgRsp]; + + + return message; + }; + return analysis; +} + +@end diff --git a/mac/TeamTalk/API/UnrequestAPI/DDReceiveOtherOfflineFileUploadFinishedAPI.h b/mac/TeamTalk/API/UnrequestAPI/DDReceiveOtherOfflineFileUploadFinishedAPI.h new file mode 100644 index 000000000..2dca44707 --- /dev/null +++ b/mac/TeamTalk/API/UnrequestAPI/DDReceiveOtherOfflineFileUploadFinishedAPI.h @@ -0,0 +1,13 @@ +// +// DDReceiveOtherOfflineFileUploadFinishedAPI.h +// Duoduo +// +// Created by 独嘉 on 14-5-12. +// Copyright (c) 2014年 zuoye. All rights reserved. +// + +#import "DDUnrequestSuperAPI.h" + +@interface DDReceiveOtherOfflineFileUploadFinishedAPI : DDUnrequestSuperAPI + +@end diff --git a/mac/TeamTalk/API/UnrequestAPI/DDReceiveOtherOfflineFileUploadFinishedAPI.m b/mac/TeamTalk/API/UnrequestAPI/DDReceiveOtherOfflineFileUploadFinishedAPI.m new file mode 100644 index 000000000..93429c82d --- /dev/null +++ b/mac/TeamTalk/API/UnrequestAPI/DDReceiveOtherOfflineFileUploadFinishedAPI.m @@ -0,0 +1,58 @@ +// +// DDReceiveOtherOfflineFileUploadFinishedAPI.m +// Duoduo +// +// Created by 独嘉 on 14-5-12. +// Copyright (c) 2014年 zuoye. All rights reserved. +// + +#import "DDReceiveOtherOfflineFileUploadFinishedAPI.h" +#import "FileTransferEntity.h" +@implementation DDReceiveOtherOfflineFileUploadFinishedAPI +/** + * 数据包中的serviceID + * + * @return serviceID + */ +- (int)responseServiceID +{ + return MODULE_ID_FILETRANSFER; +} + +/** + * 数据包中的commandID + * + * @return commandID + */ +- (int)responseCommandID +{ + return CMD_FILE_DOWNLOAD_OFFLINE_NOTIFY; +} + +/** + * 解析数据包 + * + * @return 解析数据包的block + */ +- (UnrequestAPIAnalysis)unrequestAnalysis +{ + UnrequestAPIAnalysis analysis = (id)^(NSData* data) + { + DataInputStream* bodyData = [DataInputStream dataInputStreamWithData:data]; + NSString *fromUserId = [bodyData readUTF]; + NSString *toUserId = [bodyData readUTF]; + NSString *filePath = [bodyData readUTF]; + NSString *savePath = [bodyData readUTF]; + + DDLog(@"readFileDownloadOfflineNotifyPdu, %@->%@", fromUserId, toUserId); + FileTransferEntity* entity = [[FileTransferEntity alloc] init]; + entity.fromUserId = fromUserId; + entity.toUserId = toUserId; + entity.fileName = filePath; + entity.savePath = savePath; + + return entity; + }; + return analysis; +} +@end diff --git a/mac/TeamTalk/API/UnrequestAPI/DDReceiveOtherReadyAcceptFileAPI.h b/mac/TeamTalk/API/UnrequestAPI/DDReceiveOtherReadyAcceptFileAPI.h new file mode 100644 index 000000000..3ffaf926c --- /dev/null +++ b/mac/TeamTalk/API/UnrequestAPI/DDReceiveOtherReadyAcceptFileAPI.h @@ -0,0 +1,13 @@ +// +// DDReceiveOtherReadyAcceptFileAPI.h +// Duoduo +// +// Created by 独嘉 on 14-5-12. +// Copyright (c) 2014年 zuoye. All rights reserved. +// + +#import "DDUnrequestSuperAPI.h" + +@interface DDReceiveOtherReadyAcceptFileAPI : DDUnrequestSuperAPI + +@end diff --git a/mac/TeamTalk/API/UnrequestAPI/DDReceiveOtherReadyAcceptFileAPI.m b/mac/TeamTalk/API/UnrequestAPI/DDReceiveOtherReadyAcceptFileAPI.m new file mode 100644 index 000000000..a24a57d3f --- /dev/null +++ b/mac/TeamTalk/API/UnrequestAPI/DDReceiveOtherReadyAcceptFileAPI.m @@ -0,0 +1,53 @@ +// +// DDReceiveOtherReadyAcceptFileAPI.m +// Duoduo +// +// Created by 独嘉 on 14-5-12. +// Copyright (c) 2014年 zuoye. All rights reserved. +// + +#import "DDReceiveOtherReadyAcceptFileAPI.h" +#import "FileTransferEntity.h" +@implementation DDReceiveOtherReadyAcceptFileAPI +/** + * 数据包中的serviceID + * + * @return serviceID + */ +- (int)responseServiceID +{ + return MODULE_ID_FILETRANSFER; +} + +/** + * 数据包中的commandID + * + * @return commandID + */ +- (int)responseCommandID +{ + return CMD_FILE_RECV_READY; +} + +/** + * 解析数据包 + * + * @return 解析数据包的block + */ +- (UnrequestAPIAnalysis)unrequestAnalysis +{ + UnrequestAPIAnalysis analysis = (id)^(NSData* data) + { + DataInputStream* bodyData = [DataInputStream dataInputStreamWithData:data]; + NSString *fromUserId = [bodyData readUTF]; + NSString *toUserId = [bodyData readUTF]; + DDLog(@"handleFileRecvReady, %@->%@", fromUserId, toUserId); + FileTransferEntity* entity = [[FileTransferEntity alloc] init]; + entity.fromUserId = fromUserId; + entity.toUserId = toUserId; + return entity; + }; + return analysis; +} + +@end diff --git a/mac/TeamTalk/API/UnrequestAPI/DDReceiveOtherResponseAPI.h b/mac/TeamTalk/API/UnrequestAPI/DDReceiveOtherResponseAPI.h new file mode 100644 index 000000000..66440d88a --- /dev/null +++ b/mac/TeamTalk/API/UnrequestAPI/DDReceiveOtherResponseAPI.h @@ -0,0 +1,13 @@ +// +// DDReceiveOtherResponseAPI.h +// Duoduo +// +// Created by 独嘉 on 14-5-12. +// Copyright (c) 2014年 zuoye. All rights reserved. +// + +#import "DDUnrequestSuperAPI.h" + +@interface DDReceiveOtherResponseAPI : DDUnrequestSuperAPI + +@end diff --git a/mac/TeamTalk/API/UnrequestAPI/DDReceiveOtherResponseAPI.m b/mac/TeamTalk/API/UnrequestAPI/DDReceiveOtherResponseAPI.m new file mode 100644 index 000000000..920e76e41 --- /dev/null +++ b/mac/TeamTalk/API/UnrequestAPI/DDReceiveOtherResponseAPI.m @@ -0,0 +1,63 @@ +// +// DDReceiveOtherResponseAPI.m +// Duoduo +// +// Created by 独嘉 on 14-5-12. +// Copyright (c) 2014年 zuoye. All rights reserved. +// + +#import "DDReceiveOtherResponseAPI.h" +#import "FileTransferEntity.h" + +@implementation DDReceiveOtherResponseAPI +/** + * 数据包中的serviceID + * + * @return serviceID + */ +- (int)responseServiceID +{ + return MODULE_ID_FILETRANSFER; +} + +/** + * 数据包中的commandID + * + * @return commandID + */ +- (int)responseCommandID +{ + return CMD_FILE_RESPONSE; +} + +/** + * 解析数据包 + * + * @return 解析数据包的block + */ +- (UnrequestAPIAnalysis)unrequestAnalysis +{ + UnrequestAPIAnalysis analysis = (id)^(NSData* data) + { + DataInputStream* bodyData = [DataInputStream dataInputStreamWithData:data]; + NSString *fromUserId = [bodyData readUTF]; + NSString *toUserId = [bodyData readUTF]; + NSString *fileName = [bodyData readUTF]; + uint32_t acceptFlag = [bodyData readInt]; + NSString *listenIp = [bodyData readUTF]; + uint16_t listenPort = [bodyData readShort]; + DDLog(@"handleFileResponse, %@->%@, fileName=%@, acceptFlag=%d, " + "listenIp=%@, listenPort=%d", fromUserId, toUserId, fileName, + acceptFlag, listenIp, listenPort); + FileTransferEntity* entity = [[FileTransferEntity alloc] init]; + entity.fromUserId = fromUserId; + entity.toUserId = toUserId; + entity.fileName = fileName; + entity.acceptFlag = acceptFlag; + entity.listenIp = listenIp; + entity.listenPort = listenPort; + return entity; + }; + return analysis; +} +@end diff --git a/mac/TeamTalk/API/UnrequestAPI/DDReceiveOtherSendFileAPI.h b/mac/TeamTalk/API/UnrequestAPI/DDReceiveOtherSendFileAPI.h new file mode 100644 index 000000000..2a4c8eb4d --- /dev/null +++ b/mac/TeamTalk/API/UnrequestAPI/DDReceiveOtherSendFileAPI.h @@ -0,0 +1,13 @@ +// +// DDReceiveOtherSendFileAPI.h +// Duoduo +// +// Created by 独嘉 on 14-5-12. +// Copyright (c) 2014年 zuoye. All rights reserved. +// + +#import "DDUnrequestSuperAPI.h" + +@interface DDReceiveOtherSendFileAPI : DDUnrequestSuperAPI + +@end diff --git a/mac/TeamTalk/API/UnrequestAPI/DDReceiveOtherSendFileAPI.m b/mac/TeamTalk/API/UnrequestAPI/DDReceiveOtherSendFileAPI.m new file mode 100644 index 000000000..384ce3519 --- /dev/null +++ b/mac/TeamTalk/API/UnrequestAPI/DDReceiveOtherSendFileAPI.m @@ -0,0 +1,57 @@ +// +// DDReceiveOtherSendFileAPI.m +// Duoduo +// +// Created by 独嘉 on 14-5-12. +// Copyright (c) 2014年 zuoye. All rights reserved. +// + +#import "DDReceiveOtherSendFileAPI.h" +#import "FileTransferEntity.h" +@implementation DDReceiveOtherSendFileAPI +/** + * 数据包中的serviceID + * + * @return serviceID + */ +- (int)responseServiceID +{ + return MODULE_ID_FILETRANSFER; +} + +/** + * 数据包中的commandID + * + * @return commandID + */ +- (int)responseCommandID +{ + return CMD_FILE_REQUEST; +} + +/** + * 解析数据包 + * + * @return 解析数据包的block + */ +- (UnrequestAPIAnalysis)unrequestAnalysis +{ + UnrequestAPIAnalysis analysis = (id)^(NSData* data) + { + DataInputStream* bodyData = [DataInputStream dataInputStreamWithData:data]; + NSString *fromUserId = [bodyData readUTF]; + NSString *toUserId = [bodyData readUTF]; + NSString *fileName = [bodyData readUTF]; + uint32_t fileSize = [bodyData readInt]; + DDLog(@"handleFileRequest, %@->%@, fileName=%@, fileSize=%u", + fromUserId, toUserId, fileName, fileSize); + FileTransferEntity* entity = [[FileTransferEntity alloc] init]; + entity.fromUserId = fromUserId; + entity.toUserId = toUserId; + entity.fileName = fileName; + entity.fileSize = fileSize; + return entity; + }; + return analysis; +} +@end diff --git a/mac/TeamTalk/API/UnrequestAPI/DDReceiveP2PMessageAPI.h b/mac/TeamTalk/API/UnrequestAPI/DDReceiveP2PMessageAPI.h new file mode 100644 index 000000000..2b59b3552 --- /dev/null +++ b/mac/TeamTalk/API/UnrequestAPI/DDReceiveP2PMessageAPI.h @@ -0,0 +1,13 @@ +// +// DDReceiveP2PMessageAPI.h +// Duoduo +// +// Created by 独嘉 on 14-5-12. +// Copyright (c) 2014年 zuoye. All rights reserved. +// + +#import "DDUnrequestSuperAPI.h" + +@interface DDReceiveP2PMessageAPI : DDUnrequestSuperAPI + +@end diff --git a/mac/TeamTalk/API/UnrequestAPI/DDReceiveP2PMessageAPI.m b/mac/TeamTalk/API/UnrequestAPI/DDReceiveP2PMessageAPI.m new file mode 100644 index 000000000..e12e2b699 --- /dev/null +++ b/mac/TeamTalk/API/UnrequestAPI/DDReceiveP2PMessageAPI.m @@ -0,0 +1,57 @@ +// +// DDReceiveP2PMessageAPI.m +// Duoduo +// +// Created by 独嘉 on 14-5-12. +// Copyright (c) 2014年 zuoye. All rights reserved. +// + +#import "DDReceiveP2PMessageAPI.h" +#import "IMBaseDefine.pb.h" +#import "IMSwitchService.pb.h" + +@implementation DDReceiveP2PMessageAPI +/** + * 数据包中的serviceID + * + * @return serviceID + */ +- (int)responseServiceID +{ + return ServiceIDSidSwitchService; +} + +/** + * 数据包中的commandID + * + * @return commandID + */ +- (int)responseCommandID +{ + return SwitchServiceCmdIDCidSwitchP2PCmd; +} + +/** + * 解析数据包 + * + * @return 解析数据包的block + */ +- (UnrequestAPIAnalysis)unrequestAnalysis +{ + UnrequestAPIAnalysis analysis = (id)^(NSData* data) + { + IMP2PCmdMsg *msgRsp = [IMP2PCmdMsg parseFromData:data]; + + NSString *fromUserId = [NSString stringWithFormat:@"%i",msgRsp.fromUserId]; + NSString *toId = [NSString stringWithFormat:@"%i",msgRsp.toUserId]; + NSString *content = [msgRsp cmdMsgData]; + + return @{ + @"fromUserID":fromUserId, + @"toUserId":toId, + @"content":content}; + }; + return analysis; +} + +@end diff --git a/mac/TeamTalk/API/UnrequestAPI/DDReceiveStateChangedAPI.h b/mac/TeamTalk/API/UnrequestAPI/DDReceiveStateChangedAPI.h new file mode 100644 index 000000000..9a2da268a --- /dev/null +++ b/mac/TeamTalk/API/UnrequestAPI/DDReceiveStateChangedAPI.h @@ -0,0 +1,13 @@ +// +// DDReceiveStateChangedAPI.h +// Duoduo +// +// Created by 独嘉 on 14-5-8. +// Copyright (c) 2014年 zuoye. All rights reserved. +// + +#import "DDUnrequestSuperAPI.h" + +@interface DDReceiveStateChangedAPI : DDUnrequestSuperAPI + +@end diff --git a/mac/TeamTalk/API/UnrequestAPI/DDReceiveStateChangedAPI.m b/mac/TeamTalk/API/UnrequestAPI/DDReceiveStateChangedAPI.m new file mode 100644 index 000000000..0541cc745 --- /dev/null +++ b/mac/TeamTalk/API/UnrequestAPI/DDReceiveStateChangedAPI.m @@ -0,0 +1,47 @@ +// +// DDReceiveStateChangedAPI.m +// Duoduo +// +// Created by 独嘉 on 14-5-8. +// Copyright (c) 2014年 zuoye. All rights reserved. +// + +#import "DDReceiveStateChangedAPI.h" +#import "IMBuddy.pb.h" +@implementation DDReceiveStateChangedAPI +/** + * 数据包中的serviceID + * + * @return serviceID + */ +- (int)responseServiceID +{ + return ServiceIDSidBuddyList; +} + +/** + * 数据包中的commandID + * + * @return commandID + */ +- (int)responseCommandID +{ + return BuddyListCmdIDCidBuddyListStatusNotify; +} + +/** + * 解析数据包 + * + * @return 解析数据包的block + */ +- (UnrequestAPIAnalysis)unrequestAnalysis +{ + UnrequestAPIAnalysis analysis = (id)^(NSData* data) + { + + IMUserStatNotify *userstatNotify = [IMUserStatNotify parseFromData:data]; + return userstatNotify.userStat; + }; + return analysis; +} +@end diff --git a/mac/TeamTalk/API/UnrequestAPI/Message/DDReceiveMsgDataReadNotifyAPI.h b/mac/TeamTalk/API/UnrequestAPI/Message/DDReceiveMsgDataReadNotifyAPI.h new file mode 100644 index 000000000..9db8d7bbc --- /dev/null +++ b/mac/TeamTalk/API/UnrequestAPI/Message/DDReceiveMsgDataReadNotifyAPI.h @@ -0,0 +1,13 @@ +// +// DDReceiveMsgDataReadNotify.h +// Duoduo +// +// Created by zuoye on 15/2/4. +// Copyright (c) 2015年 mogujie. All rights reserved. +// + +#import "DDUnrequestSuperAPI.h" + +@interface DDReceiveMsgDataReadNotifyAPI : DDUnrequestSuperAPI + +@end diff --git a/mac/TeamTalk/API/UnrequestAPI/Message/DDReceiveMsgDataReadNotifyAPI.m b/mac/TeamTalk/API/UnrequestAPI/Message/DDReceiveMsgDataReadNotifyAPI.m new file mode 100644 index 000000000..8819a6cbf --- /dev/null +++ b/mac/TeamTalk/API/UnrequestAPI/Message/DDReceiveMsgDataReadNotifyAPI.m @@ -0,0 +1,56 @@ +// +// DDReceiveMsgDataReadNotify.m +// Duoduo +// +// Created by zuoye on 15/2/4. +// Copyright (c) 2015年 mogujie. All rights reserved. +// + +#import "DDReceiveMsgDataReadNotifyAPI.h" +#import "IMBaseDefine.pb.h" +#import "IMMessage.pb.h" + +@implementation DDReceiveMsgDataReadNotifyAPI + +/** + * 数据包中的serviceID + * + * @return serviceID + */ +- (int)responseServiceID +{ + return ServiceIDSidMsg; +} + +/** + * 数据包中的commandID + * + * @return commandID + */ +- (int)responseCommandID +{ + return MessageCmdIDCidMsgReadNotify; +} + +/** + * 解析数据包 + * + * @return 解析数据包的block + */ +- (UnrequestAPIAnalysis)unrequestAnalysis +{ + UnrequestAPIAnalysis analysis = (id)^(NSData* data) + { + IMMsgDataReadNotify *msgRsp = [IMMsgDataReadNotify parseFromData:data]; + NSString *userId = [NSString stringWithFormat:@"%i",msgRsp.userId]; + NSString *sessionId = [NSString stringWithFormat:@"%i",msgRsp.sessionId]; + + return @{ + @"userId":userId, + @"sessionId":sessionId, + @"msgId":@(msgRsp.msgId), + @"sessionType":@(msgRsp.sessionType)}; + }; + return analysis; +} +@end diff --git a/mac/TeamTalk/Base.lproj/MainMenu.xib b/mac/TeamTalk/Base.lproj/MainMenu.xib new file mode 100644 index 000000000..da02d2b9d --- /dev/null +++ b/mac/TeamTalk/Base.lproj/MainMenu.xib @@ -0,0 +1,407 @@ + + + + + + + + + + + + + + +

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/mac/TeamTalk/Category/NSDictionary+Safe.h b/mac/TeamTalk/Category/NSDictionary+Safe.h new file mode 100644 index 000000000..8c3a4ab36 --- /dev/null +++ b/mac/TeamTalk/Category/NSDictionary+Safe.h @@ -0,0 +1,34 @@ +// +// DDNSDictionary+Safe.m +// IOSDuoduo +// +// Created by 东邪 on 14-5-29. +// Copyright (c) 2014年 dujia. All rights reserved. +// + +#import + +@interface NSDictionary(Safe) + +- (id)safeObjectForKey:(id)key; +- (int)intValueForKey:(id)key; +- (double)doubleValueForKey:(id)key; +- (NSString*)stringValueForKey:(id)key; + +@end + + +@interface NSMutableDictionary(Safe) + +- (void)safeSetObject:(id)anObject forKey:(id)aKey; +- (void)setIntValue:(int)value forKey:(id)aKey; +- (void)setDoubleValue:(double)value forKey:(id)aKey; +- (void)setStringValueForKey:(NSString*)string forKey:(id)aKey; + +@end + +@interface NSArray (Exception) + +- (id)objectForKey:(id)key; + +@end diff --git a/mac/TeamTalk/Category/NSDictionary+Safe.m b/mac/TeamTalk/Category/NSDictionary+Safe.m new file mode 100644 index 000000000..ac23cd0bc --- /dev/null +++ b/mac/TeamTalk/Category/NSDictionary+Safe.m @@ -0,0 +1,95 @@ +// +// DDNSDictionary+Safe.m +// IOSDuoduo +// +// Created by 东邪 on 14-5-29. +// Copyright (c) 2014年 dujia. All rights reserved. +// + +#import "NSDictionary+Safe.h" +#import "NSString+Additions.h" +#define isValidKey(key) ((key) != nil && ![key isKindOfClass:[NSNull class]]) +#define isValidValue(value) (((value) != nil) && ![value isKindOfClass:[NSNull class]]) + +@implementation NSDictionary (Safe) + + +- (id)safeObjectForKey:(id)key{ + if (!isValidKey(key)) { + return nil; + } + id obj = [self objectForKey:key]; + if(!isValidValue(obj)) + return nil; + return obj; +} +- (int)intValueForKey:(id)key{ + id obj = [self safeObjectForKey:key]; + return [obj intValue]; +} +- (double)doubleValueForKey:(id)key{ + id obj = [self safeObjectForKey:key]; + return [obj doubleValue]; +} +- (NSString*)stringValueForKey:(id)key{ + id obj = [self safeObjectForKey:key]; + if ([obj respondsToSelector:@selector(stringValue)]) { + return [obj stringValue]; + } + + return nil; +} + + +@end + + + + + + +@implementation NSMutableDictionary(Safe) + +- (void)safeSetObject:(id)anObject forKey:(id)aKey{ + if (!isValidKey(aKey)) { + return; + } + if ([aKey isKindOfClass:[NSString class]]) { + [self setValue:anObject forKey:aKey]; + } + else{ + if (anObject != nil) { + [self setObject:anObject forKey:aKey]; + } + else{ + [self removeObjectForKey:aKey]; + } + } +} +- (void)setIntValue:(int)value forKey:(id)aKey{ + [self safeSetObject:[[NSNumber numberWithInt:value] stringValue] forKey:aKey]; +} +- (void)setDoubleValue:(double)value forKey:(id)aKey{ + [self safeSetObject:[[NSNumber numberWithDouble:value] stringValue] forKey:aKey]; + +} +- (void)setStringValueForKey:(NSString*)string forKey:(id)aKey{ + [self safeSetObject:string forKey:aKey]; +} + + +@end + + +@implementation NSArray(Exception) + +- (id)objectForKey:(id)key{ +#ifdef DEBUG + NSAssert(NO, @"NSArray should not call objectForKey, you should check your code!"); + return nil; +#else + return nil; +#endif +} + +@end diff --git a/mac/TeamTalk/Category/NSImage+Addition.h b/mac/TeamTalk/Category/NSImage+Addition.h new file mode 100644 index 000000000..4f6415abf --- /dev/null +++ b/mac/TeamTalk/Category/NSImage+Addition.h @@ -0,0 +1,14 @@ +// +// NSImage+Addition.h +// Duoduo +// +// Created by 独嘉 on 14-4-17. +// Copyright (c) 2014年 zuoye. All rights reserved. +// + +#import + +@interface NSImage (Addition) +- (void)saveImageToFile:(NSString*)fileName compressionFactor:(CGFloat)factor; +- (NSData*)imageDataCompressionFactor:(CGFloat)factor; +@end diff --git a/mac/TeamTalk/Category/NSImage+Addition.m b/mac/TeamTalk/Category/NSImage+Addition.m new file mode 100644 index 000000000..218e99a15 --- /dev/null +++ b/mac/TeamTalk/Category/NSImage+Addition.m @@ -0,0 +1,46 @@ +// +// NSImage+Addition.m +// Duoduo +// +// Created by 独嘉 on 14-4-17. +// Copyright (c) 2014年 zuoye. All rights reserved. +// + +#import "NSImage+Addition.h" + +@implementation NSImage (Addition) +- (void)saveImageToFile:(NSString*)fileName compressionFactor:(CGFloat)factor +{ + [self lockFocus]; + //先设置 下面一个实例 + NSBitmapImageRep *bits = [[NSBitmapImageRep alloc]initWithFocusedViewRect:NSMakeRect(0, 0, self.size.width, self.size.height)]; + [self unlockFocus]; + + //再设置后面要用到得 props属性 + NSDictionary *imageProps = [NSDictionary dictionaryWithObject:[NSNumber numberWithFloat:factor] forKey:NSImageCompressionFactor]; + + + //之后 转化为NSData 以便存到文件中 + NSData *imageData = [bits representationUsingType:NSJPEGFileType properties:imageProps]; + + //设定好文件路径后进行存储就ok了 + [imageData writeToFile:fileName atomically:YES]; +} + +- (NSData*)imageDataCompressionFactor:(CGFloat)factor +{ + [self lockFocus]; + //先设置 下面一个实例 + NSBitmapImageRep *bits = [[NSBitmapImageRep alloc]initWithFocusedViewRect:NSMakeRect(0, 0, self.size.width, self.size.height)]; + [self unlockFocus]; + + //再设置后面要用到得 props属性 + NSDictionary *imageProps = [NSDictionary dictionaryWithObject:[NSNumber numberWithFloat:factor] forKey:NSImageCompressionFactor]; + + + //之后 转化为NSData 以便存到文件中 + NSData *imageData = [bits representationUsingType:NSJPEGFileType properties:imageProps]; + return imageData; +} + +@end diff --git a/mac/TeamTalk/Category/NSImageView+MTAddition.h b/mac/TeamTalk/Category/NSImageView+MTAddition.h new file mode 100644 index 000000000..1557cd0de --- /dev/null +++ b/mac/TeamTalk/Category/NSImageView+MTAddition.h @@ -0,0 +1,13 @@ +// +// NSImageView+MTAddition.h +// Duoduo +// +// Created by 独嘉 on 15/1/24. +// Copyright (c) 2015年 mogujie. All rights reserved. +// + +#import + +@interface NSImageView (MTAddition) +- (void)setImageWithURL:(NSString*)url placeholderImage:(NSString*)placeholder; +@end diff --git a/mac/TeamTalk/Category/NSImageView+MTAddition.m b/mac/TeamTalk/Category/NSImageView+MTAddition.m new file mode 100644 index 000000000..caddf6675 --- /dev/null +++ b/mac/TeamTalk/Category/NSImageView+MTAddition.m @@ -0,0 +1,36 @@ +// +// NSImageView+MTAddition.m +// Duoduo +// +// Created by 独嘉 on 15/1/24. +// Copyright (c) 2015年 mogujie. All rights reserved. +// + +#import "NSImageView+MTAddition.h" +#import "MTImageCache.h" +#import "MTImageDownload.h" +@implementation NSImageView (MTAddition) +- (void)setImageWithURL:(NSString*)url placeholderImage:(NSString*)placeholder +{ + static int index = 0; + index ++; + NSImage* cacheImage = [[MTImageCache shareInstance] imageFromCacheWithKey:url]; + if (cacheImage) + { + [self setImage:cacheImage]; + } + else + { + NSImage* placeholderImage = [NSImage imageNamed:placeholder]; + [self setImage:placeholderImage]; + //开始下载图片 + if ([url length] > 0) + { + [[MTImageDownload shareInstance] loadImageWithURL:url completion:^(NSImage *image) { + [[MTImageCache shareInstance] cacheImage:image forKey:url toMemory:YES]; + [self setImage:image]; + }]; + } + } +} +@end diff --git a/mac/TeamTalk/Category/NSString+Additions.h b/mac/TeamTalk/Category/NSString+Additions.h new file mode 100644 index 000000000..e6dbe8f80 --- /dev/null +++ b/mac/TeamTalk/Category/NSString+Additions.h @@ -0,0 +1,29 @@ +// +// NSString+Additions.h +// IOSDuoduo +// +// Created by 东邪 on 14-5-23. +// Copyright (c) 2014年 dujia. All rights reserved. +// + +#import + +@interface NSString (mogujieString) + ++(NSString *)documentPath; ++(NSString *)cachePath; ++(NSString *)formatCurDate; ++(NSString *)formatCurDay; ++(NSString *)getAppVer; +- (NSString*)removeAllSpace; +- (NSURL *) toURL; +- (BOOL) isEmail; +- (BOOL) isEmpty; +- (NSString *) MD5; +-(NSString *)trim; + +-(BOOL) isOlderVersionThan:(NSString*)otherVersion; +-(BOOL) isNewerVersionThan:(NSString*)otherVersion; + ++ (NSString*)jsonStringFromDic:(NSDictionary*)dic; +@end diff --git a/mac/TeamTalk/Category/NSString+Additions.m b/mac/TeamTalk/Category/NSString+Additions.m new file mode 100644 index 000000000..c76e10b6d --- /dev/null +++ b/mac/TeamTalk/Category/NSString+Additions.m @@ -0,0 +1,152 @@ +// +// NSString+Additions.m +// IOSDuoduo +// +// Created by 东邪 on 14-5-23. +// Copyright (c) 2014年 dujia. All rights reserved. +// + +#import "NSString+Additions.h" + +#import + +#import + +@implementation NSString (TTString) + ++(NSString *)documentPath { + static NSString * path = nil; + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^{ + path = [[NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) + objectAtIndex:0] copy]; + [NSString addSkipBackupAttributeToItemAtURL:[NSURL fileURLWithPath:path]]; + }); + return path; +} ++(BOOL)addSkipBackupAttributeToItemAtURL:(NSURL *)URL +{ +// if (URL==nil) { +// return NO; +// } +// NSString *systemVersion=[[UIDevice currentDevice] systemVersion]; +// float version=[systemVersion floatValue]; +// if (version<5.0) { +// return YES; +// } +// if ( version>=5.1) { +// assert([[NSFileManager defaultManager] fileExistsAtPath: [URL path]]); +// +// NSError *error = nil; +// BOOL success = [URL setResourceValue: [NSNumber numberWithBool: YES] +// forKey: NSURLIsExcludedFromBackupKey error: &error]; +// if(!success){ +// } +// return success; +// } +// +// if ([systemVersion isEqual:@"5.0"]) { +// return NO; +// }else{ +// assert([[NSFileManager defaultManager] fileExistsAtPath: [URL path]]); +// +// const char* filePath = [[URL path] fileSystemRepresentation]; +// +// const char* attrName = "com.apple.MobileBackup"; +// u_int8_t attrValue = 1; +// +// int result = setxattr(filePath, attrName, &attrValue, sizeof(attrValue), 0, 0); +// return result == 0; +// } + return YES; +} ++(NSString *)cachePath { + static NSString * path = nil; + if (!path) { + path = [[NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES) + objectAtIndex:0] copy]; + } + return path; +} + ++(NSString *)formatCurDate { + NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init]; + [dateFormatter setDateFormat:@"yyyy-MM-dd HH:mm:ss"]; + NSString *result = [dateFormatter stringFromDate:[NSDate date]]; + + return result; +} ++(NSString *)formatCurDay { + NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init]; + [dateFormatter setDateFormat:@"yyyy-MM-dd"]; + NSString *result = [dateFormatter stringFromDate:[NSDate date]]; + + return result; +} ++(NSString *)getAppVer { + return [[[NSBundle mainBundle] infoDictionary] objectForKey:@"CFBundleVersion"]; +} +- (NSURL *) toURL { + return [NSURL URLWithString:[self stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding]]; +} + +- (BOOL) isEmpty { + return nil == self + || 0 == [[self stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceCharacterSet]] length]; +} + + +- (NSString *) MD5 { + // Create pointer to the string as UTF8 + const char* ptr = [self UTF8String]; + unsigned char md5Buffer[CC_MD5_DIGEST_LENGTH]; + + // Create 16 byte MD5 hash value, store in buffer + CC_MD5(ptr, strlen(ptr), md5Buffer); + + // Convert MD5 value in the buffer to NSString of hex values + NSMutableString* output = [NSMutableString stringWithCapacity:CC_MD5_DIGEST_LENGTH * 2]; + for (int i = 0; i < CC_MD5_DIGEST_LENGTH; i++) { + [output appendFormat:@"%02x",md5Buffer[i]]; + } + + return output; +} +-(NSString *)trim{ + return [self stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]]; +} + + +-(BOOL) isOlderVersionThan:(NSString*)otherVersion +{ + return ([self compare:otherVersion options:NSNumericSearch] == NSOrderedAscending); +} + +-(BOOL) isNewerVersionThan:(NSString*)otherVersion +{ + return ([self compare:otherVersion options:NSNumericSearch] == NSOrderedDescending); +} +- (NSString*)removeAllSpace +{ + NSString* result = [self stringByReplacingOccurrencesOfString:@" " withString:@""]; + result = [result stringByReplacingOccurrencesOfString:@" " withString:@""]; + return result; +} + ++ (NSString*)jsonStringFromDic:(NSDictionary*)dic +{ + NSError *error = nil; + NSData *jsonData = [NSJSONSerialization dataWithJSONObject:dic + options:NSJSONWritingPrettyPrinted + error:&error]; + + if ([jsonData length] > 0 && error == nil){ + NSString *jsonString = [[NSString alloc] initWithData:jsonData + encoding:NSUTF8StringEncoding]; + return jsonString; + }else{ + return nil; + } +} + +@end \ No newline at end of file diff --git a/mac/TeamTalk/Category/NSView+LayerAddition.h b/mac/TeamTalk/Category/NSView+LayerAddition.h new file mode 100644 index 000000000..a77edb56d --- /dev/null +++ b/mac/TeamTalk/Category/NSView+LayerAddition.h @@ -0,0 +1,15 @@ +// +// NSView+LayerAddition.h +// Duoduo +// +// Created by 独嘉 on 14-5-4. +// Copyright (c) 2014年 zuoye. All rights reserved. +// + +#import + +@interface NSView (LayerAddition) +- (void)setShadow:(NSColor*)color + offset:(NSSize)offset + opacity:(CGFloat)opacity; +@end diff --git a/mac/TeamTalk/Category/NSView+LayerAddition.m b/mac/TeamTalk/Category/NSView+LayerAddition.m new file mode 100644 index 000000000..1f0a7bd95 --- /dev/null +++ b/mac/TeamTalk/Category/NSView+LayerAddition.m @@ -0,0 +1,40 @@ +// +// NSView+LayerAddition.m +// Duoduo +// +// Created by 独嘉 on 14-5-4. +// Copyright (c) 2014年 zuoye. All rights reserved. +// + +#import "NSView+LayerAddition.h" + +@implementation NSView (LayerAddition) +- (void)setShadow:(NSColor*)color + offset:(NSSize)offset + opacity:(CGFloat)opacity +{ +// [self setWantsLayer: YES]; +// [self.layer setShadowColor:color.CGColor]; +// [self.layer setShadowOffset:offset]; +// [self.layer setShadowOpacity:opacity]; + + +// NSPoint p = [self convertPoint:[self bounds].origin +// fromView:self]; +// NSRect rect = NSMakeRect(p.x,p.y-[self bounds].size.height, +// [self bounds].size.width,[self bounds].size.height); +// NSBezierPath *myPath = [NSBezierPath bezierPathWithRect:rect]; +// [self allocateGState]; +// NSShadow *shadow = [[NSShadow alloc] init]; +// [shadow setShadowBlurRadius: 10]; +// [shadow setShadowOffset: offset]; +// [shadow setShadowColor:[color colorWithAlphaComponent:opacity]]; +// [shadow set]; +// +// [[NSColor blackColor] set]; +// [myPath stroke]; +// [[NSColor whiteColor] set]; +// [myPath fill]; +// [self releaseGState]; +} +@end diff --git a/mac/TeamTalk/Category/NSWindow+Addition.h b/mac/TeamTalk/Category/NSWindow+Addition.h new file mode 100644 index 000000000..ab167d6fa --- /dev/null +++ b/mac/TeamTalk/Category/NSWindow+Addition.h @@ -0,0 +1,13 @@ +// +// NSWindow+Addition.h +// Duoduo +// +// Created by 独嘉 on 14-5-5. +// Copyright (c) 2014年 zuoye. All rights reserved. +// + +#import + +@interface NSWindow (Addition) +- (void)addCloseButtonAtTopLeft; +@end diff --git a/mac/TeamTalk/Category/NSWindow+Addition.m b/mac/TeamTalk/Category/NSWindow+Addition.m new file mode 100644 index 000000000..bf77017d7 --- /dev/null +++ b/mac/TeamTalk/Category/NSWindow+Addition.m @@ -0,0 +1,21 @@ +// +// NSWindow+Addition.m +// Duoduo +// +// Created by 独嘉 on 14-5-5. +// Copyright (c) 2014年 zuoye. All rights reserved. +// + +#import "NSWindow+Addition.h" + +@implementation NSWindow (Addition) +- (void)addCloseButtonAtTopLeft +{ + [self setStyleMask:NSBorderlessWindowMask]; + NSButton* button = [NSWindow standardWindowButton:NSWindowCloseButton forStyleMask:self.styleMask]; + CGFloat y = [(NSView*)self.contentView bounds].size.height - button.bounds.size.height - 10; + + [button setFrame:NSMakeRect(10, y, button.bounds.size.width, button.bounds.size.height)]; + [self.contentView addSubview:button positioned:NSWindowAbove relativeTo:nil]; +} +@end diff --git a/mac/TeamTalk/Category/NSWindow+Animation.h b/mac/TeamTalk/Category/NSWindow+Animation.h new file mode 100644 index 000000000..bede8ba8f --- /dev/null +++ b/mac/TeamTalk/Category/NSWindow+Animation.h @@ -0,0 +1,13 @@ +// +// NSWindow+Animation.h +// Duoduo +// +// Created by 独嘉 on 14-3-30. +// Copyright (c) 2014年 zuoye. All rights reserved. +// + +#import +@interface NSWindow (Animation) +- (void)beginShakeAnimation; +- (void)fadeInAnimation; +@end diff --git a/mac/TeamTalk/Category/NSWindow+Animation.m b/mac/TeamTalk/Category/NSWindow+Animation.m new file mode 100644 index 000000000..b8818b748 --- /dev/null +++ b/mac/TeamTalk/Category/NSWindow+Animation.m @@ -0,0 +1,72 @@ +// +// NSWindow+Animation.m +// Duoduo +// +// Created by 独嘉 on 14-3-30. +// Copyright (c) 2014年 zuoye. All rights reserved. +// + +#import "NSWindow+Animation.h" +#import + +static NSInteger const numberOfShakes = 20; +static float const durationOfShake = 0.5f; +static float const vigourOfShake = 0.01f; +static float const halfheight = 10; + +@implementation NSWindow (Animation) +- (void)beginShakeAnimation +{ + + CGRect frame = self.frame; + CAKeyframeAnimation *shakeAnimation = [CAKeyframeAnimation animation]; + + CGMutablePathRef shakePath = CGPathCreateMutable(); + CGPathMoveToPoint(shakePath, NULL, NSMinX(frame), NSMinY(frame)); + int index; + for (index = 0; index < numberOfShakes; ++index) + { + CGPathAddLineToPoint(shakePath, NULL, NSMinX(frame) - frame.size.width * vigourOfShake, NSMinY(frame)); + CGPathAddLineToPoint(shakePath, NULL, NSMinX(frame) + frame.size.width * vigourOfShake, NSMinY(frame)); + } + CGPathCloseSubpath(shakePath); + shakeAnimation.path = shakePath; + shakeAnimation.duration = durationOfShake; + + + [self setAnimations:@{@"frameOrigin" : shakeAnimation}]; + [[self animator] setFrameOrigin:self.frame.origin]; +} + +- (void)fadeInAnimation +{ + NSViewAnimation *theAnim; + NSMutableDictionary* firstViewDict; + + { + // Create the attributes dictionary for the first view. + firstViewDict = [NSMutableDictionary dictionaryWithCapacity:3]; + + // Specify which view to modify. + [firstViewDict setObject:self forKey:NSViewAnimationTargetKey]; + + // Specify the starting position of the view. + [firstViewDict setObject:NSViewAnimationFadeInEffect + forKey:NSViewAnimationEffectKey]; + + + } + + // Create the view animation object. + theAnim = [[NSViewAnimation alloc] initWithViewAnimations:[NSArray + arrayWithObjects:firstViewDict,nil]]; + + // Set some additional attributes for the animation. + [theAnim setDuration:0.5]; // One and a half seconds. + [theAnim setAnimationCurve:NSAnimationEaseIn]; + + // Run the animation. + [theAnim startAnimation]; + +} +@end diff --git a/mac/TeamTalk/ColorfulView/DDAppBackgroundColorView.h b/mac/TeamTalk/ColorfulView/DDAppBackgroundColorView.h new file mode 100644 index 000000000..80d0ad532 --- /dev/null +++ b/mac/TeamTalk/ColorfulView/DDAppBackgroundColorView.h @@ -0,0 +1,13 @@ +// +// DDAppBackgroundColorView.h +// Duoduo +// +// Created by 独嘉 on 14-4-30. +// Copyright (c) 2014年 zuoye. All rights reserved. +// + +#import + +@interface DDAppBackgroundColorView : NSView + +@end diff --git a/mac/TeamTalk/ColorfulView/DDAppBackgroundColorView.m b/mac/TeamTalk/ColorfulView/DDAppBackgroundColorView.m new file mode 100644 index 000000000..506ea6952 --- /dev/null +++ b/mac/TeamTalk/ColorfulView/DDAppBackgroundColorView.m @@ -0,0 +1,21 @@ +// +// DDAppBackgroundColorView.m +// Duoduo +// +// Created by 独嘉 on 14-4-30. +// Copyright (c) 2014年 zuoye. All rights reserved. +// + +#import "DDAppBackgroundColorView.h" + +@implementation DDAppBackgroundColorView +- (void)drawRect:(NSRect)dirtyRect +{ + NSColor* backgroundColor = [NSColor colorWithDeviceRed:234.0 / 255.0 + green:234.0 / 255.0 + blue:234.0 / 255.0 + alpha:1]; + [backgroundColor set]; + [[NSBezierPath bezierPath] fill]; +} +@end diff --git a/mac/TeamTalk/ColorfulView/DDCornerRadiusTextField.h b/mac/TeamTalk/ColorfulView/DDCornerRadiusTextField.h new file mode 100644 index 000000000..cb9e83838 --- /dev/null +++ b/mac/TeamTalk/ColorfulView/DDCornerRadiusTextField.h @@ -0,0 +1,15 @@ +// +// DDCornerRadiusTextField.h +// Duoduo +// +// Created by 独嘉 on 14-7-15. +// Copyright (c) 2014年 zuoye. All rights reserved. +// + +#import + +@interface DDCornerRadiusTextField : NSTextField + +- (void)setCornerRadius:(float)cornerRadius; + +@end diff --git a/mac/TeamTalk/ColorfulView/DDCornerRadiusTextField.m b/mac/TeamTalk/ColorfulView/DDCornerRadiusTextField.m new file mode 100644 index 000000000..b7c7dcfa3 --- /dev/null +++ b/mac/TeamTalk/ColorfulView/DDCornerRadiusTextField.m @@ -0,0 +1,36 @@ +// +// DDCornerRadiusTextField.m +// Duoduo +// +// Created by 独嘉 on 14-7-15. +// Copyright (c) 2014年 zuoye. All rights reserved. +// + +#import "DDCornerRadiusTextField.h" + +@implementation DDCornerRadiusTextField +{ + float _cornerRadius; +} + +- (void)drawRect:(NSRect)dirtyRect +{ + [super drawRect:dirtyRect]; + //设置下填充色,这里就用灰色啦,不那么抢眼 + [[NSColor redColor] setFill]; + //根据view的框框,画个圆角矩形出来 + NSBezierPath *path = [NSBezierPath bezierPathWithRoundedRect:dirtyRect + xRadius:4 + yRadius:4]; + //填充颜色 + [path fill]; + +} + +- (void)setCornerRadius:(float)cornerRadius +{ +// _cornerRadius = cornerRadius; +// [self displayIfNeeded]; +} + +@end diff --git a/mac/TeamTalk/ColorfulView/DDCustomWindow.h b/mac/TeamTalk/ColorfulView/DDCustomWindow.h new file mode 100644 index 000000000..725cd9ffb --- /dev/null +++ b/mac/TeamTalk/ColorfulView/DDCustomWindow.h @@ -0,0 +1,13 @@ +// +// DDCustomWindow.h +// Duoduo +// +// Created by 独嘉 on 14-5-4. +// Copyright (c) 2014年 zuoye. All rights reserved. +// + +#import + +@interface DDCustomWindow : NSWindow + +@end diff --git a/mac/TeamTalk/ColorfulView/DDCustomWindow.m b/mac/TeamTalk/ColorfulView/DDCustomWindow.m new file mode 100644 index 000000000..0a60d9b99 --- /dev/null +++ b/mac/TeamTalk/ColorfulView/DDCustomWindow.m @@ -0,0 +1,16 @@ +// +// DDCustomWindow.m +// Duoduo +// +// Created by 独嘉 on 14-5-4. +// Copyright (c) 2014年 zuoye. All rights reserved. +// + +#import "DDCustomWindow.h" + +@implementation DDCustomWindow +- (BOOL)canBecomeKeyWindow +{ + return YES; +} +@end diff --git a/mac/TeamTalk/ColorfulView/DDGridBackgroundView.h b/mac/TeamTalk/ColorfulView/DDGridBackgroundView.h new file mode 100644 index 000000000..649f0286f --- /dev/null +++ b/mac/TeamTalk/ColorfulView/DDGridBackgroundView.h @@ -0,0 +1,13 @@ +// +// DDGridBackgroundView.h +// Duoduo +// +// Created by 独嘉 on 14-4-29. +// Copyright (c) 2014年 zuoye. All rights reserved. +// + +#import + +@interface DDGridBackgroundView : NSView + +@end diff --git a/mac/TeamTalk/ColorfulView/DDGridBackgroundView.m b/mac/TeamTalk/ColorfulView/DDGridBackgroundView.m new file mode 100644 index 000000000..65bd8566e --- /dev/null +++ b/mac/TeamTalk/ColorfulView/DDGridBackgroundView.m @@ -0,0 +1,31 @@ +// +// DDGridBackgroundView.m +// Duoduo +// +// Created by 独嘉 on 14-4-29. +// Copyright (c) 2014年 zuoye. All rights reserved. +// + +#import "DDGridBackgroundView.h" + +@implementation DDGridBackgroundView + +- (id)initWithFrame:(NSRect)frame +{ + self = [super initWithFrame:frame]; + if (self) { + // Initialization code here. + } + return self; +} + +- (void)drawRect:(NSRect)dirtyRect +{ + [super drawRect:dirtyRect]; + NSImage* image = [NSImage imageNamed:@"background"]; + NSColor* color = [NSColor colorWithPatternImage:image]; + [color set]; + [NSBezierPath fillRect:dirtyRect]; + // Drawing code here. +} +@end diff --git a/mac/TeamTalk/CrashReport/CrashReportManager.h b/mac/TeamTalk/CrashReport/CrashReportManager.h new file mode 100644 index 000000000..a349b7c06 --- /dev/null +++ b/mac/TeamTalk/CrashReport/CrashReportManager.h @@ -0,0 +1,15 @@ +// +// CrashReportManager.h +// Duoduo +// +// Created by 独嘉 on 14-3-13. +// Copyright (c) 2014年 zuoye. All rights reserved. +// + +#import + +@interface CrashReportManager : NSObject ++ (CrashReportManager*)instance; + +- (void)checkAndSendCrashReport; +@end diff --git a/mac/TeamTalk/CrashReport/CrashReportManager.m b/mac/TeamTalk/CrashReport/CrashReportManager.m new file mode 100644 index 000000000..07d34438e --- /dev/null +++ b/mac/TeamTalk/CrashReport/CrashReportManager.m @@ -0,0 +1,147 @@ +// +// CrashReportManager.m +// Duoduo +// +// Created by 独嘉 on 14-3-13. +// Copyright (c) 2014年 zuoye. All rights reserved. +// + +#import "CrashReportManager.h" +#import +#import +#import "AFHTTPRequestOperation.h" +NSString* GetHardwareUUID() +{ + NSString *ret = nil; + io_service_t platformExpert ; + platformExpert = IOServiceGetMatchingService(kIOMasterPortDefault, IOServiceMatching("IOPlatformExpertDevice")) ; + + if (platformExpert) { + CFTypeRef serialNumberAsCFString ; + serialNumberAsCFString = IORegistryEntryCreateCFProperty(platformExpert, CFSTR("IOPlatformUUID"), kCFAllocatorDefault, 0) ; + if (serialNumberAsCFString) { + ret = [(__bridge NSString *)(CFStringRef)serialNumberAsCFString copy]; + CFRelease(serialNumberAsCFString); serialNumberAsCFString = NULL; + } + IOObjectRelease(platformExpert); platformExpert = 0; + } + + return ret; +} + +@implementation CrashReportManager ++ (CrashReportManager*)instance +{ + static CrashReportManager* g_crashReportManager; + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^{ + g_crashReportManager = [[CrashReportManager alloc] init]; + }); + return g_crashReportManager; +} + +- (void)checkAndSendCrashReport +{ + PLCrashReporter *crashReporter = [PLCrashReporter sharedReporter]; + NSError *error; + // Check if we previously crashed + if ([crashReporter hasPendingCrashReport]) + { + + [self handleCrashReportSuccess:^{ + [crashReporter purgePendingCrashReport]; + + } failure:^{ + [crashReporter purgePendingCrashReport]; + }]; + } + // Enable the Crash Reporter + if (![crashReporter enableCrashReporterAndReturnError: &error]) + { + NSLog(@"Warning: Could not enable crash reporter: %@", error); + } +} + +- (void)handleCrashReportSuccess:(void(^)())success failure:(void(^)())failure +{ + PLCrashReporter *crashReporter = [PLCrashReporter sharedReporter]; + NSData *crashData; + NSError *error; + // Try loading the crash report + crashData = [crashReporter loadPendingCrashReportDataAndReturnError: &error]; + if (crashData == nil) + { + NSLog(@"Could not load crash report: %@", error); + [crashReporter purgePendingCrashReport]; + return; + } + [self uploadTheCrashReport:crashData success:^{ + success(); + } failure:^{ + failure(); + }]; + return; +} + +- (NSString *)applicationSupportDirectory +{ + //Path to the preferences folder + static NSString *_preferencesFolderPath = nil; + + //Determine the preferences path if neccessary + if (!_preferencesFolderPath) { + _preferencesFolderPath = [[[[NSBundle mainBundle] infoDictionary] objectForKey:@"Preference Folder Location"] stringByExpandingTildeInPath]; + if (!_preferencesFolderPath) + _preferencesFolderPath = [[[NSHomeDirectory() stringByAppendingPathComponent:@"Library"] stringByAppendingPathComponent:@"Application Support"] stringByAppendingPathComponent:@"TeamTalk"]; + } + + return _preferencesFolderPath; +} + +- (void)uploadTheCrashReport:(NSData*)crashReport success:(void(^)())success failure:(void(^)())failure +{ +// NSURL *url = [NSURL URLWithString:@"http://www.mogujie.com"]; +// NSString* fileName = [self crashFileName]; +// AFHTTPClient *httpClient = [[AFHTTPClient alloc] initWithBaseURL:url]; +// NSDictionary* parameters = @{@"platform":@"Mac"}; +// NSMutableURLRequest *request = [httpClient multipartFormRequestWithMethod:@"POST" path:@"/mtalk/client/page/dump/" parameters:parameters constructingBodyWithBlock: ^(id formData) { +// [formData appendPartWithFileData:crashReport name:@"dumpFile" fileName:fileName mimeType:@"application/octet-stream"]; +// }]; +// AFHTTPRequestOperation *operation = [[AFHTTPRequestOperation alloc] initWithRequest:request]; +// [operation setCompletionBlockWithSuccess:^(AFHTTPRequestOperation *operation, id responseObject) +// { +// DDLog(@"success with response string %@", operation); +// NSDictionary* response = [NSJSONSerialization JSONObjectWithData:responseObject options:0 error:nil]; +// NSDictionary* status = response[@"status"]; +// NSNumber* code = status[@"code"]; +// if (![code isEqualToNumber:@1001]) +// { +// DDLog(@"发送奔溃报告失败"); +// failure(); +// } +// else +// { +// success(); +// } +// } +// failure:^(AFHTTPRequestOperation *operation, NSError *error) +// { +// DDLog(@"error: %@", error.localizedDescription); +// failure(); +// }]; +// [operation start]; +} + +- (NSString*)crashFileName +{ + NSString* uuid = GetHardwareUUID(); + NSDate* now = [NSDate date]; + NSDateFormatter* dateFormatter = [[NSDateFormatter alloc] init]; + [dateFormatter setDateFormat:@"yyyyMMddHHmmss"]; + dateFormatter.locale = [[NSLocale alloc] initWithLocaleIdentifier:@"zh_CN"]; + NSString* dateString = [dateFormatter stringFromDate:now]; + NSString* fileName = [NSString stringWithFormat:@"%@-%@.crash",uuid,dateString]; + return fileName; +} + +@end diff --git a/mac/TeamTalk/DDAppDelegate.h b/mac/TeamTalk/DDAppDelegate.h new file mode 100644 index 000000000..b4b0876ed --- /dev/null +++ b/mac/TeamTalk/DDAppDelegate.h @@ -0,0 +1,25 @@ +// +// DDAppDelegate.h +// Duoduo +// +// Created by maye on 13-10-30. +// Copyright (c) 2013年 zuoye. All rights reserved. +// + +#import + +@class DDLoginWindowController; +@interface DDAppDelegate : NSObject +{ + IBOutlet DDInterfaceController *interfaceController; +} + +@property(nonatomic,strong)DDLoginWindowController* loginWindowController; +@property(nonatomic,strong)NSWindow* showWindow; +- (void)showMainWindowController; + +@end + + + + diff --git a/mac/TeamTalk/DDAppDelegate.m b/mac/TeamTalk/DDAppDelegate.m new file mode 100644 index 000000000..006a818da --- /dev/null +++ b/mac/TeamTalk/DDAppDelegate.m @@ -0,0 +1,197 @@ +// +// DDAppDelegate.m +// Duoduo +// +// Created by maye on 13-10-30. +// Copyright (c) 2013年 zuoye. All rights reserved. +// + +#import "DDAppDelegate.h" +#import "MTUserEntity.h" +#import "MTSessionModule.h" +#import "DDMainModule.h" +#import "DDMainWindowController.h" +#import "DDMainWindowController.h" +#import "MTMessageModule.h" +#import "DDApplicationUpdate.h" +#import "DDLoginWindowController.h" +#import "DDClientStateMaintenanceManager.h" +#import "DDTcpClientManager.h" +#import "PFMoveApplication.h" +#import "DDServiceAccountModule.h" +#import "StateMaintenanceManager.h" +#import "MTUserModule.h" +#import "MTGroupModule.h" +#import "MTSessionModule.h" +#import +#import "MTDepartmentManager.h" +//Portable Duoduo prefs key + +#define PORTABLE_ADIUM_KEY @"Preference Folder Location" +#define ALWAYS_RUN_SETUP_WIZARD FALSE + +@implementation DDAppDelegate +{ +} +#pragma mark Core Controllers +-(id)init{ + self =[super self]; + if (self) { + NSString *logPath = [[self applicationSupportDirectory] stringByAppendingPathComponent:@"duoduo_log.txt"]; + if (![[NSFileManager defaultManager] fileExistsAtPath:[self applicationSupportDirectory]]) { + [[NSFileManager defaultManager] createDirectoryAtPath:[self applicationSupportDirectory] + withIntermediateDirectories:YES + attributes:nil + error:NULL]; + } + + //设置默认记录级别 + [[L4Logger rootLogger] setLevel:[L4Level all]]; + //定义输出目标与日志模板 + [[L4Logger rootLogger] addAppender: [[L4RollingFileAppender alloc] initWithLayout:[L4Layout simpleLayout] fileName:logPath]]; + //自初始化并定义日志实例 + L4Logger *theLogger = [L4Logger loggerForClass:[L4FunctionLogger class]]; + [theLogger setLevel:[L4Level all]]; + + setSharedDuoduo(self); + + } + return self; +} + + + +//duoduo is almost done lauching,init +- (void)applicationWillFinishLaunching:(NSNotification *)notification{ + + PFMoveToApplicationsFolderIfNecessary(); + +// check for a recent crach log + +// Ignore SIGPIPE, which is a harmless error signal +// sent when write() or similar function calls fail due to a broken pipe in the network connection + signal(SIGPIPE, SIG_IGN); + + //cocoa程序获取url scheme传入参数 + [[NSAppleEventManager sharedAppleEventManager] setEventHandler:self + andSelector:@selector(handleURLEvent:withReplyEvent:) + forEventClass:kInternetEventClass + andEventID:kAEGetURL]; + log4CInfo(@"applicationWillFinishLaunching"); +} + + +//duoduo has finished lauching. +- (void)applicationDidFinishLaunching:(NSNotification *)aNotification +{ + [[DDApplicationUpdate instance] startAutoCheckUpdateAtOnce]; + //应用程序初始化相关 + [StateMaintenanceManager instance]; + [DDClientStateMaintenanceManager shareInstance]; + [DDServiceAccountModule shareInstance]; + + [MTSessionModule shareInstance]; + [MTGroupModule shareInsatnce]; + [MTUserModule shareInstance]; + [MTDepartmentManager shareInstance]; + [StateMaintenanceManager instance]; + + [MTMessageModule shareInstance]; + log4CInfo(@"applicationDidFinishLaunching"); + if(nil == _loginWindowController) + { + _loginWindowController = [[DDLoginWindowController alloc] initWithWindowNibName:@"LoginSelect"]; + } + [_loginWindowController showWindow:nil]; + [_loginWindowController.window makeKeyAndOrderFront:nil]; + self.showWindow = _loginWindowController.window; +} + +- (void)handleURLEvent:(NSAppleEventDescriptor *)event withReplyEvent:(NSAppleEventDescriptor *)replyEvent +{ + DDLog(@" --"); +} + +/*! + * @brief Returns the location of Duoduo's preference folder + * + * This may be specified in our bundle's info dictionary keyed as PORTABLE_ADIUM_KEY + * or, by default, be within the system's 'application support' directory. + */ +- (NSString *)applicationSupportDirectory +{ + //Path to the preferences folder + static NSString *_preferencesFolderPath = nil; + + //Determine the preferences path if neccessary + if (!_preferencesFolderPath) { + _preferencesFolderPath = [[[[NSBundle mainBundle] infoDictionary] objectForKey:PORTABLE_ADIUM_KEY] stringByExpandingTildeInPath]; + if (!_preferencesFolderPath) + _preferencesFolderPath = [[[NSHomeDirectory() stringByAppendingPathComponent:@"Library"] stringByAppendingPathComponent:@"Application Support"] stringByAppendingPathComponent:@"TeamTalk"]; + } + + return _preferencesFolderPath; +} + + +- (void)applicationWillTerminate:(NSNotification *)notification{ + +} + +- (BOOL)applicationShouldHandleReopen:(NSApplication *)theApplication hasVisibleWindows:(BOOL)flag +{ + [self.showWindow makeKeyAndOrderFront:nil]; + DDLog(@"applicationShouldHandleReopen"); + return YES; +} + +- (void)applicationWillResignActive:(NSNotification *)notification +{ + [[QLPreviewPanel sharedPreviewPanel] close]; +} + +- (void)applicationWillBecomeActive:(NSNotification *)notification +{ +// if (_showMainWindow) +// { +// DDMessageModule* messageModule = getDDMessageModule(); +// DDSessionModule* sessionModule = getDDSessionModule(); +// NSString* chattingSessionID = [sessionModule chatingSessionID]; +// if ([messageModule countMessageBySessionId:chattingSessionID] > 0) +// { +// [[DDMainWindowController instance] openChatViewByUserId:chattingSessionID]; +// } +// } +} + +- (void)showMainWindowController +{ + [_loginWindowController close]; + [[DDMainWindowController instance].window makeKeyAndOrderFront:nil]; + self.showWindow = [DDMainWindowController instance].window; +} + +- (void)p_clearOldCachePath +{ + NSString *preferencesFolderPath = nil; + if (!preferencesFolderPath) { + preferencesFolderPath = [[[[NSBundle mainBundle] infoDictionary] objectForKey:PORTABLE_ADIUM_KEY] stringByExpandingTildeInPath]; + if (!preferencesFolderPath) + preferencesFolderPath = [[[NSHomeDirectory() stringByAppendingPathComponent:@"Library"] stringByAppendingPathComponent:@"Application Support"] stringByAppendingPathComponent:@"Duoduo 1.0"]; + } + + NSFileManager* fileManager = [NSFileManager defaultManager]; + + + if ([fileManager fileExistsAtPath:preferencesFolderPath]) + { + dispatch_async(dispatch_get_global_queue(0, 0), ^{ + NSError* error = nil; + [fileManager removeItemAtPath:preferencesFolderPath error:&error]; + }); + } +} + +@end + + diff --git a/mac/TeamTalk/DDApplication.h b/mac/TeamTalk/DDApplication.h new file mode 100644 index 000000000..3ab4a931e --- /dev/null +++ b/mac/TeamTalk/DDApplication.h @@ -0,0 +1,13 @@ +// +// DDApplication.h +// Duoduo +// +// Created by jianqing.du on 14-1-24. +// Copyright (c) 2014年 zuoye. All rights reserved. +// + +#import + +@interface DDApplication : NSApplication + +@end diff --git a/mac/TeamTalk/DDApplication.m b/mac/TeamTalk/DDApplication.m new file mode 100644 index 000000000..6040d0c55 --- /dev/null +++ b/mac/TeamTalk/DDApplication.m @@ -0,0 +1,40 @@ +// +// DDApplication.m +// Duoduo +// +// Created by jianqing.du on 14-1-24. +// Copyright (c) 2014年 zuoye. All rights reserved. +// + +#import "DDApplication.h" + +@implementation DDApplication + +- (void)sendEvent:(NSEvent *)event +{ + + if ([event type] == NSKeyDown) { + if (([event modifierFlags] & NSDeviceIndependentModifierFlagsMask) == NSCommandKeyMask) { + if ([[event charactersIgnoringModifiers] isEqualToString:@"x"]) { + if ([self sendAction:@selector(cut:) to:nil from:self]) + return; + } + else if ([[event charactersIgnoringModifiers] isEqualToString:@"c"]) { + if ([self sendAction:@selector(copy:) to:nil from:self]) + return; + } + else if ([[event charactersIgnoringModifiers] isEqualToString:@"v"]) { + if ([self sendAction:@selector(paste:) to:nil from:self]) + return; + } + else if ([[event charactersIgnoringModifiers] isEqualToString:@"a"]) { + if ([self sendAction:@selector(selectAll:) to:nil from:self]) + return; + } + } + } + + [super sendEvent:event]; +} + +@end diff --git a/mac/TeamTalk/DDChattingContactListCell.h b/mac/TeamTalk/DDChattingContactListCell.h new file mode 100644 index 000000000..1013c651d --- /dev/null +++ b/mac/TeamTalk/DDChattingContactListCell.h @@ -0,0 +1,18 @@ +// +// DDChattingContactListCell.h +// Duoduo +// +// Created by 独嘉 on 14-3-14. +// Copyright (c) 2014年 zuoye. All rights reserved. +// + +#import +#import "MTUserEntity.h" +@interface DDChattingContactListCell : NSTableCellView +{ + __weak IBOutlet NSImageView* _stateImageView; + __weak IBOutlet NSTextField* _userNameTextField; +} + +- (void)configeWithUser:(MTUserEntity*)user; +@end diff --git a/mac/TeamTalk/DDChattingContactListCell.m b/mac/TeamTalk/DDChattingContactListCell.m new file mode 100644 index 000000000..42658b15f --- /dev/null +++ b/mac/TeamTalk/DDChattingContactListCell.m @@ -0,0 +1,62 @@ +// +// DDChattingContactListCell.m +// Duoduo +// +// Created by 独嘉 on 14-3-14. +// Copyright (c) 2014年 zuoye. All rights reserved. +// + +#import "DDChattingContactListCell.h" +#import "MTUserEntity.h" +#import "StateMaintenanceManager.h" +@implementation DDChattingContactListCell + +- (id)initWithFrame:(NSRect)frame +{ + self = [super initWithFrame:frame]; + if (self) { + // Initialization code here. + } + return self; +} + +- (void)drawRect:(NSRect)dirtyRect +{ + [super drawRect:dirtyRect]; + + // Drawing code here. +} + +- (void)configeWithUser:(MTUserEntity*)user +{ + NSString* name = user.name; + if (!name) + { + [_userNameTextField setStringValue: + @""]; + } + else + { + [_userNameTextField setStringValue:name]; + } + NSImage* icon; + NSString* userID = user.ID; + StateMaintenanceManager* stateMaintenanceManager = [StateMaintenanceManager instance]; + UserStatType userOnlineState = [stateMaintenanceManager getUserStateForUserID:userID]; + switch (userOnlineState) + { + case UserStatTypeUserStatusOnline: + icon = [NSImage imageNamed:@"state-online"]; + break; + case UserStatTypeUserStatusOffline: + icon = [NSImage imageNamed:@"state-offline"]; + break; + case UserStatTypeUserStatusLeave: + icon = [NSImage imageNamed:@"state-leave"]; + break; + } + + [_stateImageView setImage:icon]; +} + +@end diff --git a/mac/TeamTalk/DDChattingContactListModule.h b/mac/TeamTalk/DDChattingContactListModule.h new file mode 100644 index 000000000..e1eec1835 --- /dev/null +++ b/mac/TeamTalk/DDChattingContactListModule.h @@ -0,0 +1,21 @@ +// +// DDChattingContactListModule.h +// Duoduo +// +// Created by 独嘉 on 14-4-22. +// Copyright (c) 2014年 zuoye. All rights reserved. +// + +#import +typedef void(^Completion)(); + +@class MTGroupEntity; +@interface DDChattingContactListModule : NSObject +@property (nonatomic,retain)MTGroupEntity* groupEntity; +- (void)searchContent:(NSString*)searchContent completion:(Completion)completion; +- (void)sortGroupUserCompletion:(Completion)completion;; +- (NSMutableArray *)getGroupUserList; +-(NSUInteger)getOnlineUserListCount; +- (void)updateData; + +@end diff --git a/mac/TeamTalk/DDChattingContactListModule.m b/mac/TeamTalk/DDChattingContactListModule.m new file mode 100644 index 000000000..f5287085e --- /dev/null +++ b/mac/TeamTalk/DDChattingContactListModule.m @@ -0,0 +1,160 @@ +// +// DDChattingContactListModule.m +// Duoduo +// +// Created by 独嘉 on 14-4-22. +// Copyright (c) 2014年 zuoye. All rights reserved. +// + +#import "DDChattingContactListModule.h" +#import "DDSearch.h" +#import "MTUserEntity.h" +#import "MTUserModule.h" +#import "MTGroupEntity.h" +#import "MTGroupModule.h" +#import "StateMaintenanceManager.h" + + +@implementation DDChattingContactListModule +{ + NSMutableArray* _groupUsers; + NSMutableArray* _showUserMember; + NSString* _lastSearchContent; +} + + + +- (void)searchContent:(NSString*)searchContent completion:(Completion)completion +{ + _lastSearchContent = [searchContent copy]; + if (!self.groupEntity) + { + return; + } + + if ([searchContent length] == 0) + { + _showUserMember = [[NSMutableArray alloc] initWithArray:_groupUsers]; + [self sortGroupUserCompletion:^{ + completion(); + }]; + return; + } + + + NSArray* ranges = _groupUsers; + + [[DDSearch instance] searchContent:searchContent inRange:ranges completion:^(NSArray *result, NSError *error) { + if (!error) + { + _showUserMember = [[NSMutableArray alloc] initWithArray:result]; + + [self sortGroupUserCompletion:^{ + completion(); + }]; + + } + }]; +} + +- (void)setGroupEntity:(MTGroupEntity *)groupEntity +{ + _groupEntity = groupEntity; + + if (groupEntity) { + if(!_groupUsers){ + _groupUsers = [[NSMutableArray alloc] init]; + } + [_groupUsers removeAllObjects]; + + [groupEntity.groupUserIds enumerateObjectsUsingBlock:^(NSString *uid, NSUInteger idx, BOOL *stop) { + MTUserEntity *user =(MTUserEntity *) [[MTUserModule shareInstance] getOriginEntityWithOriginID:uid]; + if(user){ + [_groupUsers addObject:user]; + }else{ + DDLog(@" **** 取不到人:%@",uid); + } + + }]; + } + _showUserMember = [[NSMutableArray alloc] initWithArray:_groupUsers]; + +} + + +- (void)sortGroupUserCompletion:(Completion)completion +{ + [(NSMutableArray *)_showUserMember sortUsingComparator:^NSComparisonResult(id obj1, id obj2) { + NSString* uId1 = [(MTUserEntity*)obj1 ID]; + NSString* uId2 = [(MTUserEntity*)obj2 ID]; + StateMaintenanceManager* stateMaintenanceManager = [StateMaintenanceManager instance]; + UserStatType user1OnlineState = [stateMaintenanceManager getUserStateForUserID:uId1]; + UserStatType user2OnlineState = [stateMaintenanceManager getUserStateForUserID:uId2]; + if((user1OnlineState == UserStatTypeUserStatusOnline) && + (user2OnlineState == UserStatTypeUserStatusLeave || user2OnlineState == UserStatTypeUserStatusOffline)) + { + return NSOrderedAscending; + } + else if(user1OnlineState == UserStatTypeUserStatusLeave && user2OnlineState == UserStatTypeUserStatusOffline) + { + return NSOrderedAscending; + } + else if (user2OnlineState == UserStatTypeUserStatusOnline && + (user1OnlineState == UserStatTypeUserStatusLeave || user1OnlineState == UserStatTypeUserStatusOffline)) + { + return NSOrderedDescending; + } + else if(user2OnlineState == UserStatTypeUserStatusLeave && user1OnlineState == UserStatTypeUserStatusOffline) + { + return NSOrderedDescending; + } + else + { + return NSOrderedSame; + } + + }]; + +// dispatch_async(dispatch_get_main_queue(), ^{ + completion(); +// }); +} + +- (void)updateData +{ + [_groupUsers removeAllObjects]; + + [_groupEntity.groupUserIds enumerateObjectsUsingBlock:^(NSString *uid, NSUInteger idx, BOOL *stop) { + MTUserEntity *user =(MTUserEntity *) [[MTUserModule shareInstance] getOriginEntityWithOriginID:uid]; + if (user) + { + [_groupUsers addObject:user]; + } + }]; + + _showUserMember = [[NSMutableArray alloc] initWithArray:_groupUsers]; +} + +- (NSMutableArray *)getGroupUserList{ + + return _showUserMember; +} + +-(NSUInteger)getOnlineUserListCount{ + NSMutableArray *array =[self getGroupUserList]; + __block NSUInteger c =0; + [array enumerateObjectsUsingBlock:^(MTUserEntity *user, NSUInteger idx, BOOL *stop) { + UserStatType userState = [[StateMaintenanceManager instance]getUserStateForUserID:user.ID]; + if(userState!=UserStatTypeUserStatusOffline){ + c++; + } + }]; + return c; +} + +- (void)dealloc +{ + //移除观察 +} + +@end diff --git a/mac/TeamTalk/DDChattingContactListViewController.h b/mac/TeamTalk/DDChattingContactListViewController.h new file mode 100644 index 000000000..f35e4df1f --- /dev/null +++ b/mac/TeamTalk/DDChattingContactListViewController.h @@ -0,0 +1,32 @@ +// +// DDChattingContactListViewController.h +// Duoduo +// +// Created by zuoye on 14-1-9. +// Copyright (c) 2014年 zuoye. All rights reserved. +// + +#import +#import "DDTableView.h" +#import "DDUserDataWindowController.h" +#import "DDAlertWindowController.h" +@class DDChattingContactListModule,MTGroupEntity; +@interface DDChattingContactListViewController : NSObject{ +} + +@property (nonatomic,weak) IBOutlet NSTableColumn *contactListColumn; +@property (nonatomic,weak) IBOutlet DDTableView *contactListTableView; +@property (nonatomic,weak) IBOutlet NSTextField *listViewTitleTextField; +@property (nonatomic,weak) IBOutlet NSMenu *contactListMenu; +@property (nonatomic,weak) IBOutlet NSSearchField* searchField; +@property (nonatomic,retain) DDChattingContactListModule* module; +@property (assign) BOOL needForceUpdate; +@property(nonatomic,strong)MTGroupEntity* groupEntity; +@property (nonatomic,assign,readonly)BOOL observerUserOnlineState; + +-(void)updateTitle; + +- (IBAction)viewUserInfo:(id)sender; + +- (void)reloadContactListTableView; +@end diff --git a/mac/TeamTalk/DDChattingContactListViewController.m b/mac/TeamTalk/DDChattingContactListViewController.m new file mode 100644 index 000000000..473c408cf --- /dev/null +++ b/mac/TeamTalk/DDChattingContactListViewController.m @@ -0,0 +1,280 @@ +// +// DDChattingContactListViewController.m +// Duoduo +// +// Created by zuoye on 14-1-9. +// Copyright (c) 2014年 zuoye. All rights reserved. +// + +#import "DDChattingContactListViewController.h" +#import "ImageAndTextCell.h" +#import "MTSessionModule.h" +#import "DDMainModule.h" +#import "MTUserEntity.h" +#import "MTUserModule.h" +#import "MTGroupModule.h" +#import "MTSessionEntity.h" +#import "DDUserInfoManager.h" +#import "DDChattingContactListCell.h" +#import "TcpProtocolHeader.h" +#import "DDTcpClientManager.h" +#import "DDChattingContactListModule.h" +#import "MTGroupChangeMemberAPI.h" +#import "MTDatabaseUtil.h" + +@implementation DDChattingContactListViewController +-(id)init{ + self =[super init]; + if (self) { + _observerUserOnlineState=NO; + } + return self; +} + + +- (void)setGroupEntity:(MTGroupEntity *)groupEntity +{ + if (_groupEntity) + { + [_groupEntity removeObserver:self forKeyPath:@"groupUserIds"]; + _groupEntity = nil; + } + _groupEntity = groupEntity; + self.module.groupEntity = groupEntity; + + [self.module.groupEntity addObserver:self + forKeyPath:@"groupUserIds" + options:NSKeyValueObservingOptionNew | NSKeyValueObservingOptionOld + context:nil]; + + [self reloadContactListTableView]; + + +} + +- (DDChattingContactListModule*)module +{ + if (!_module) + { + _module = [[DDChattingContactListModule alloc] init]; + } + return _module; +} + +-(void)awakeFromNib{ + ImageAndTextCell *celll = [[ImageAndTextCell alloc] init]; + [[self contactListColumn] setDataCell:celll]; + [self.contactListTableView setDataSource:self]; + [self.contactListTableView setTarget:self]; + [self.contactListTableView setDoubleAction:@selector(onParticipanListDoubleClicked:)]; + [self.contactListTableView setDelegate:self]; + [self.listViewTitleTextField setEditable:NO]; + [self.listViewTitleTextField setBackgroundColor:[NSColor clearColor]]; + [self.contactListTableView setBackGroundImage:[NSImage imageNamed:@"panel_bg_theme_gray"]]; + + _observerUserOnlineState = YES; + + if (!_observerUserOnlineState) + { + [[StateMaintenanceManager instance] addObserver:self + forKeyPath:DD_USER_ONLINE_STATE_KEYPATH + options:NSKeyValueObservingOptionOld | NSKeyValueObservingOptionNew + context:nil]; + } +} + +- (void)onParticipanListDoubleClicked:(id)sender{ + NSInteger clickedRow = [_contactListTableView clickedRow]; + if (clickedRow >= 0) + { + NSArray* groupUsers = [self.module getGroupUserList]; + MTUserEntity* selectUser = [groupUsers objectAtIndex:clickedRow]; + if([[[DDClientState shareInstance]userID ] isEqualToString:selectUser.ID]){ //点击的是自己,弹出自己的用户信息面板. + + }else{ + + [[DDMainWindowController instance] openUserChatWithUser:selectUser.ID]; + + } + } +} + +-(void)updateContactList:(NSNotification*)notification +{ + NSDictionary* changedUserState = [notification object]; + __block BOOL change = NO; + [[changedUserState allKeys] enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) { + if ([self.module.getGroupUserList containsObject:obj]) + { + change = YES; + *stop = YES; + } + }]; + if (!change) + { + return; + } + [self reloadContactListTableView]; +} + +-(void)updateTitle{ + ; + NSString *title = [NSString stringWithFormat:@"参与人(%ld/%ld)",[self.module getOnlineUserListCount],[[self.module getGroupUserList] count]]; + [self.listViewTitleTextField setStringValue:title]; + [self setLabelAttribute:self.listViewTitleTextField]; +} + +-(void)setLabelAttribute:(NSTextField *)textField{ + NSMutableAttributedString *titleAttributedString = [[NSMutableAttributedString alloc] initWithAttributedString:[textField attributedStringValue]]; + + NSShadow *shadow = [[NSShadow alloc] init]; + [shadow setShadowColor:[NSColor whiteColor]]; + [shadow setShadowOffset:NSMakeSize(1, 1)]; + NSRange fullRange = NSMakeRange(0, [[textField stringValue] length]); + [titleAttributedString addAttribute:@"NSShadowAttributeName" value:shadow range:fullRange]; +} + +- (void)dealloc +{ + if (_observerUserOnlineState) { + [[StateMaintenanceManager instance] removeObserver:self forKeyPath:DD_USER_ONLINE_STATE_KEYPATH]; + } + [_contactListTableView setDataSource:nil]; + [_contactListTableView setDelegate:nil]; + [self.module.groupEntity removeObserver:self forKeyPath:@"groupUserIds"]; +} + +#pragma mark - NSSearchField +- (void)controlTextDidChange:(NSNotification *)obj +{ + [self.module searchContent:_searchField.stringValue completion:^{ + [_contactListTableView reloadData]; + }]; + +} + +#pragma mark - NSMenu Delegate +- (void)menuWillOpen:(NSMenu *)menu +{ + NSString* myID = [[DDClientState shareInstance]userID]; + MTGroupEntity* currentGroup =self.module.groupEntity; +// (MTGroupEntity *)[groupModule getOriginEntityWithOriginID:self.module.session.originID]; + //若为群主则可以移除群成员 + NSMenuItem* deleteUserMenuItem = [menu itemAtIndex:3]; + BOOL meIsGroupCreator = [myID isEqualToString:currentGroup.groupCreatorId]; + + NSUInteger clickRow = [_contactListTableView clickedRow]; + + NSArray* showGroupUsers = [self.module getGroupUserList]; + MTUserEntity* user =(MTUserEntity *)[[MTUserModule shareInstance]getOriginEntityWithOriginID:[[showGroupUsers objectAtIndex:clickRow]ID]]; + BOOL clickNotMe = ![user.ID isEqualToString:myID]; + + if (clickNotMe && meIsGroupCreator) + { + [deleteUserMenuItem setHidden:NO]; + } + else + { + [deleteUserMenuItem setHidden:YES]; + } + +} + +#pragma mark NSTableView Delegate mothed +-(NSInteger)numberOfRowsInTableView:(NSTableView *)tableView{ + + NSArray* groupUsers = [self.module getGroupUserList]; + return [groupUsers count]; +} + +- (CGFloat)tableView:(NSTableView *)tableView heightOfRow:(NSInteger)row +{ + return 20; +} + +- (NSView*)tableView:(NSTableView *)tableView viewForTableColumn:(NSTableColumn *)tableColumn row:(NSInteger)row +{ + NSString* identifier = @"DDChattingContactListCellIdentifier"; + DDChattingContactListCell* cell = (DDChattingContactListCell*)[tableView makeViewWithIdentifier:identifier owner:self]; + NSArray* groupUsers = [self.module getGroupUserList]; + MTUserEntity *userEntity = groupUsers[row] ; + [cell configeWithUser:userEntity]; + return cell; +} + +-(NSImage *)getOnlineStateIcon:(NSString *)userId{ + + return nil; +} + +- (IBAction)sendMsgToUsers:(id)sender { + [self onParticipanListDoubleClicked:self]; +} + +- (IBAction)viewUserInfo:(id)sender +{ +// NSInteger rowNumber = [_contactListTableView selectedRow]; +// if(rowNumber < 0) +// return; + NSInteger clickedRow = [_contactListTableView clickedRow]; + if (clickedRow >= 0) + { + NSArray* groupUsers = [self.module getGroupUserList]; + MTUserEntity* showUser = [groupUsers objectAtIndex:clickedRow]; + [[DDUserInfoManager instance] showUser:showUser forContext:self]; + } +} + +- (IBAction)deleteGroupMember:(id)sender +{ + NSInteger clickedRow = [_contactListTableView clickedRow]; + if (clickedRow >= 0) + { + NSArray* groupUsers = [self.module getGroupUserList]; + MTUserEntity* user = groupUsers[clickedRow]; + NSString* selectUserId = user.ID; + + MTGroupChangeMemberAPI* deleteMemberAPI = [[MTGroupChangeMemberAPI alloc] init]; + NSString* myID = [[DDClientState shareInstance]userID]; + NSArray* array = @[_groupEntity.ID,@[selectUserId],@(GroupModifyTypeGroupModifyTypeDel),myID]; + [deleteMemberAPI requestWithObject:array Completion:^(id response, NSError *error) { + + if (!error) + { + if (response) + { + NSString* groupID = response[@"groupID"]; + NSArray* userIDs = response[@"userIDs"]; + MTGroupEntity* group = (MTGroupEntity*)[[MTGroupModule shareInsatnce] getOriginEntityWithOriginID:groupID]; + group.groupUserIds = [[NSMutableArray alloc] initWithArray:userIDs]; + [[MTDatabaseUtil instance] insertGroups:@[group]]; + } + } + }]; + } +} + +- (void)reloadContactListTableView +{ + [self.module sortGroupUserCompletion:^{ + + }]; + [self updateTitle]; + [_contactListTableView reloadData]; + +} + +#pragma mark +#pragma kvo +-(void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context{ + if ([keyPath isEqualToString:DD_USER_ONLINE_STATE_KEYPATH]) { + [self reloadContactListTableView]; + } + else if ([keyPath isEqualToString:@"groupUserIds"]) + { + [self.module updateData]; + [self reloadContactListTableView]; + } +} + +@end diff --git a/mac/TeamTalk/DDChattingMyLine.h b/mac/TeamTalk/DDChattingMyLine.h new file mode 100644 index 000000000..6704e5fce --- /dev/null +++ b/mac/TeamTalk/DDChattingMyLine.h @@ -0,0 +1,15 @@ +// +// DDChattingMyLine.h +// Duoduo +// +// Created by 东邪 on 14-5-14. +// Copyright (c) 2014年 zuoye. All rights reserved. +// + +#import + +@interface DDChattingMyLine : NSView +@property(nonatomic,strong)NSColor * mBackgroundColor; +-(void)setBackgroundColor:(NSColor *)color; +-(void)setBackgroundImage:(NSImage *)image; +@end diff --git a/mac/TeamTalk/DDChattingMyLine.m b/mac/TeamTalk/DDChattingMyLine.m new file mode 100644 index 000000000..1a697875a --- /dev/null +++ b/mac/TeamTalk/DDChattingMyLine.m @@ -0,0 +1,39 @@ +// +// DDChattingMyLine.m +// Duoduo +// +// Created by 东邪 on 14-5-14. +// Copyright (c) 2014年 zuoye. All rights reserved. +// + +#import "DDChattingMyLine.h" + +@implementation DDChattingMyLine +- (id)initWithFrame:(NSRect)frame { + self = [super initWithFrame:frame]; + if (self) { + // Initialization code here. + } + return self; +} + +- (void)drawRect:(NSRect)dirtyRect { + [super drawRect:dirtyRect]; + [self.mBackgroundColor set]; + [NSBezierPath fillRect:dirtyRect]; +} +-(void)setBackgroundColor:(NSColor *)color +{ + self.mBackgroundColor=color; + +} +-(void)setBackgroundImage:(NSImage *)image +{ + NSColor *backgroundColor = [NSColor colorWithPatternImage:image]; + self.mBackgroundColor=backgroundColor; +} +- (void)awakeFromNib +{ + +} +@end diff --git a/mac/TeamTalk/DDChattingViewModule.h b/mac/TeamTalk/DDChattingViewModule.h new file mode 100644 index 000000000..68c7de66a --- /dev/null +++ b/mac/TeamTalk/DDChattingViewModule.h @@ -0,0 +1,42 @@ +// +// DDChattingViewModule.h +// Duoduo +// +// Created by 独嘉 on 14-3-18. +// Copyright (c) 2014年 zuoye. All rights reserved. +// + +#import +@protocol DDChattingViewModuleDataSource + +- (NSAttributedString*)getCurrentAttribute; + +@end +@class MTSessionEntity,MessageEntity; +@interface DDChattingViewModule : NSObject +@property (nonatomic,readonly)MTSessionEntity* session; +@property (nonatomic,assign)NSUInteger firstMessageID; +@property (nonatomic,assign)NSUInteger inputHistoryMessageIndex; +@property (nonatomic,assign)id dataSource; +@property (nonatomic,assign)BOOL loadingHistoryMessage; +@property (nonatomic,assign)BOOL firstTimeToLoadMessage; +- (id)initWithSession:(MTSessionEntity*)session; + + +- (NSAttributedString*)getAttributedStringFromInputContent:(NSAttributedString*)inputContent compress:(BOOL)compress; + +/** + * 获取上一条输入框的历史消息 + * + * @return 消息内容 + */ +- (NSAttributedString*)getLastInputHistoryMessages; + +/** + * 获取下一条输入框的历史消息 + * + * @return 消息内容 + */ +- (NSAttributedString*)getNextInputHistoryMessages; + +@end diff --git a/mac/TeamTalk/DDChattingViewModule.m b/mac/TeamTalk/DDChattingViewModule.m new file mode 100644 index 000000000..9c7945c85 --- /dev/null +++ b/mac/TeamTalk/DDChattingViewModule.m @@ -0,0 +1,222 @@ +// +// DDChattingViewModule.m +// Duoduo +// +// Created by 独嘉 on 14-3-18. +// Copyright (c) 2014年 zuoye. All rights reserved. +// + +#import "DDChattingViewModule.h" +#import "MTSessionEntity.h" +#import "DDEmotionAttachment.h" +#import "AIImageAdditions.h" +#import "EGOCache.h" +#import "NSAttributedString+Message.h" +#import "MessageEntity.h" +#import "EmotionManager.h" +#import "EGOImageLoader.h" +#import "NSImage+Addition.h" +#import "MTMessageModule.h" +@interface DDChattingViewModule(privateAPI) + +- (void)fetchGroupUsers; +- (NSAttributedString*)getTextAndEmotionAttributeFromText:(NSString*)text; + +@end + +@implementation DDChattingViewModule +{ + NSAttributedString* _currentContent; +} +- (id)initWithSession:(MTSessionEntity*)session +{ + self = [super init]; + if (self) + { + _session = session; + //获取组内成员 + _firstMessageID = [[MTMessageModule shareInstance] getLastMessageIDForSessionID:session.sessionID]; + _loadingHistoryMessage = NO; + _firstTimeToLoadMessage = YES; + + } + return self; +} + + +- (NSAttributedString*)getAttributedStringFromInputContent:(NSAttributedString*)inputContent compress:(BOOL)compress +{ + NSMutableAttributedString* resultAttributedString = [[NSMutableAttributedString alloc] init]; + + if (inputContent.length) { + NSUInteger lastTextIndex = 0; + NSUInteger i = 0; + for (i=0; i 0 ? suffixFileName : @"png"; +// NSString *imageKey =[NSString stringWithFormat:@"tem-%lu", [[image description] hash]]; +// NSString *fileName=[[[EGOCache currentCache] pathForKey:imageKey] stringByAppendingPathExtension:suffixFileName]; +// +// [image saveImageToFile:fileName compressionFactor:1.0]; +// +// NSAttributedString* imageAttribute = [NSAttributedString imageAttributedString:fileName realImageURL:nil compressImage:compress]; +// [resultAttributedString appendAttributedString:imageAttribute]; +// } + } + } + + if (lastTextIndex != i) + { + NSString *msgData = [[inputContent attributedSubstringFromRange: + NSMakeRange(lastTextIndex, i - lastTextIndex)] string]; + NSAttributedString* textAttributedString = [NSAttributedString textAttributedString:msgData]; + [resultAttributedString appendAttributedString:textAttributedString]; + } + } + return resultAttributedString; +} + +- (NSAttributedString*)getLastInputHistoryMessages +{ + if (self.inputHistoryMessageIndex == 0) + { + _currentContent = [self.dataSource getCurrentAttribute]; + } + + NSAttributedString* attribute = [[MTMessageModule shareInstance] getInputHistoryForSessionID:self.session.sessionID forIndex:self.inputHistoryMessageIndex]; + if (attribute) + { + self.inputHistoryMessageIndex ++; + } + return attribute; +} + +- (NSAttributedString*)getNextInputHistoryMessages +{ + self.inputHistoryMessageIndex --; + NSAttributedString* attribute = [[MTMessageModule shareInstance] getInputHistoryForSessionID:self.session.sessionID forIndex:self.inputHistoryMessageIndex]; + if (!attribute) + { + self.inputHistoryMessageIndex ++; + attribute = [_currentContent copy]; + } + DDLog(@"------------------------->%lu",(unsigned long)self.inputHistoryMessageIndex); + return attribute; +} + +#pragma mark - PrivateAPI +- (NSAttributedString*)getTextAndEmotionAttributeFromText:(NSString*)text +{ + NSMutableAttributedString* resultAttribute = [[NSMutableAttributedString alloc] init]; + NSMutableString *msgContent = [NSMutableString stringWithString:text]; + NSRange startRange; + while ((startRange = [msgContent rangeOfString:@"["]).location != NSNotFound) { + if (startRange.location > 0) + { + NSString *str = [msgContent substringWithRange:NSMakeRange(0, startRange.location)]; + DDLog(@"[前文本内容:%@",str); + [msgContent deleteCharactersInRange:NSMakeRange(0, startRange.location)]; + startRange.location=0; + NSAttributedString* textAttribute = [NSAttributedString textAttributedString:str]; + [resultAttribute appendAttributedString:textAttribute]; + } + + NSRange endRange = [msgContent rangeOfString:@"]"]; + if (endRange.location != NSNotFound) { + NSRange range; + range.location = 0; + range.length = endRange.location + endRange.length; + NSString *emotionText = [msgContent substringWithRange:range]; + [msgContent deleteCharactersInRange: + NSMakeRange(0, endRange.location + endRange.length)]; + + DDLog(@"类似表情字串:%@",emotionText); + NSString *emotionFile = [[EmotionManager instance] getFileFrom:emotionText]; + if (emotionFile) { + // 表情 + NSString *path = [[NSBundle mainBundle] pathForResource:emotionFile ofType:nil]; + DDEmotionAttachment* emotionAttribute = [[DDEmotionAttachment alloc] init]; + NSURL *fileUrl = [NSURL fileURLWithPath:path]; + NSFileWrapper *fileWrapper = [[NSFileWrapper alloc] initSymbolicLinkWithDestinationURL:fileUrl]; + NSImage* emotionImage = [[NSImage alloc] initWithContentsOfURL:fileUrl]; + [fileWrapper setIcon:emotionImage]; + [fileWrapper setPreferredFilename:path]; + [emotionAttribute setFileWrapper:fileWrapper]; + [emotionAttribute setEmotionFileName:emotionFile]; + [emotionAttribute setEmotionPath:path]; + [emotionAttribute setEmotionText:emotionText]; + NSMutableAttributedString *attachmentString = (NSMutableAttributedString*)[NSMutableAttributedString attributedStringWithAttachment:emotionAttribute]; + + [resultAttribute appendAttributedString:attachmentString]; + } else + { + NSAttributedString* textAttribute = [NSAttributedString textAttributedString:emotionText]; + [resultAttribute appendAttributedString:textAttribute]; + } + } else { + DDLog(@"没有[匹配的后缀"); + break; + } + } + + if ([msgContent length] > 0) + { + NSAttributedString* textAttribute = [NSAttributedString textAttributedString:msgContent]; + [resultAttribute appendAttributedString:textAttribute]; + } + return resultAttribute; +} + +- (void)fetchGroupUsers +{ +// switch (_session.type) +// { +// case SESSIONTYPE_SINGLE: +// break; +// case SESSIONTYPE_GROUP: +// case SESSIONTYPE_TEMP_GROUP: +// { +// [_session.groupUsers enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) { +// NSString* userID = (NSString*)obj; +// }]; +// } +// break; +// } +} + +@end diff --git a/mac/TeamTalk/DDCornerView.h b/mac/TeamTalk/DDCornerView.h new file mode 100644 index 000000000..29114d583 --- /dev/null +++ b/mac/TeamTalk/DDCornerView.h @@ -0,0 +1,13 @@ +// +// DDCornerView.h +// Duoduo +// +// Created by 独嘉 on 14-5-16. +// Copyright (c) 2014年 zuoye. All rights reserved. +// + +#import + +@interface DDCornerView : NSView + +@end diff --git a/mac/TeamTalk/DDCornerView.m b/mac/TeamTalk/DDCornerView.m new file mode 100644 index 000000000..ec092cca5 --- /dev/null +++ b/mac/TeamTalk/DDCornerView.m @@ -0,0 +1,20 @@ +// +// DDCornerView.m +// Duoduo +// +// Created by 独嘉 on 14-5-16. +// Copyright (c) 2014年 zuoye. All rights reserved. +// + +#import "DDCornerView.h" + +@implementation DDCornerView +- (void)drawRect:(NSRect)dirtyRect +{ + NSBezierPath * path; + path = [NSBezierPath bezierPathWithRoundedRect:dirtyRect xRadius:18 yRadius:18]; + + [[NSColor colorWithCalibratedRed:1 green:1 blue:1 alpha:0.3] set]; + [path fill]; +} +@end diff --git a/mac/TeamTalk/DDDuoduoProtocol.h b/mac/TeamTalk/DDDuoduoProtocol.h new file mode 100644 index 000000000..952c97cfb --- /dev/null +++ b/mac/TeamTalk/DDDuoduoProtocol.h @@ -0,0 +1,24 @@ +// +// DDDuoduoProtocol.h +// Duoduo +// +// Created by maye on 13-10-30. +// Copyright (c) 2013年 zuoye. All rights reserved. +// + +#import +#import "DDMainWindowController.h" +#import "DDInterfaceController.h" + +@protocol DDLoginControllerProtocol,DDAccountControllerProtocol,DDContactControllerProtocol; + +@protocol DDDuoduoProtocol + +@property(readonly, nonatomic) NSString *applicationSupportDirectory; +@property(readonly,nonatomic)DDInterfaceController *interfaceController; +@property(nonatomic,strong)DDMainWindowController* mainWindowController; + + +-(void)sendMsgToServer:(NSMutableData *)data; + +@end diff --git a/mac/TeamTalk/DDGroupViewController.xib b/mac/TeamTalk/DDGroupViewController.xib new file mode 100644 index 000000000..7a098e9a8 --- /dev/null +++ b/mac/TeamTalk/DDGroupViewController.xib @@ -0,0 +1,115 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/mac/TeamTalk/DDIntranentViewController.xib b/mac/TeamTalk/DDIntranentViewController.xib new file mode 100644 index 000000000..18881c564 --- /dev/null +++ b/mac/TeamTalk/DDIntranentViewController.xib @@ -0,0 +1,112 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/mac/TeamTalk/DDIntranetCell.h b/mac/TeamTalk/DDIntranetCell.h new file mode 100644 index 000000000..e0446310c --- /dev/null +++ b/mac/TeamTalk/DDIntranetCell.h @@ -0,0 +1,19 @@ +// +// DDIntranetCell.h +// Duoduo +// +// Created by 独嘉 on 14-6-25. +// Copyright (c) 2014年 zuoye. All rights reserved. +// + +#import +@class DDIntranetEntity; +@interface DDIntranetCell : NSTableCellView +{ + __weak IBOutlet EGOImageView* avatarImageView; + __weak IBOutlet NSTextField* nameTextField; + __weak IBOutlet NSTextField* unreadMessageLabel; + __weak IBOutlet NSImageView* unreadMessageBackgroundImageView; +} +- (void)configWithIntranet:(DDIntranetEntity*)intranet; +@end diff --git a/mac/TeamTalk/DDIntranetCell.m b/mac/TeamTalk/DDIntranetCell.m new file mode 100644 index 000000000..abe18d4e3 --- /dev/null +++ b/mac/TeamTalk/DDIntranetCell.m @@ -0,0 +1,37 @@ +// +// DDIntranetCell.m +// Duoduo +// +// Created by 独嘉 on 14-6-25. +// Copyright (c) 2014年 zuoye. All rights reserved. +// + +#import "DDIntranetCell.h" +#import "DDIntranetEntity.h" +#import "MTMessageModule.h" +@implementation DDIntranetCell + +- (id)initWithFrame:(NSRect)frame +{ + self = [super initWithFrame:frame]; + if (self) { + // Initialization code here. + } + return self; +} + +- (void)drawRect:(NSRect)dirtyRect +{ + [super drawRect:dirtyRect]; + + // Drawing code here. +} + +- (void)configWithIntranet:(DDIntranetEntity*)intranet +{ + NSImage* iconImage = [NSImage imageNamed:@"intranet_icon"]; + [avatarImageView setImage:iconImage]; + [nameTextField setStringValue:intranet.name]; +} + +@end diff --git a/mac/TeamTalk/DDIntranetContentViewController.h b/mac/TeamTalk/DDIntranetContentViewController.h new file mode 100644 index 000000000..192cd9152 --- /dev/null +++ b/mac/TeamTalk/DDIntranetContentViewController.h @@ -0,0 +1,21 @@ +// +// DDIntranetContentViewController.h +// Duoduo +// +// Created by 独嘉 on 14-6-25. +// Copyright (c) 2014年 zuoye. All rights reserved. +// + +#import +#import +@class DDIntranetEntity; +@interface DDIntranetContentViewController : NSViewController +@property (nonatomic,retain)DDIntranetEntity* intranetEntity; +@property (nonatomic,weak)IBOutlet WebView* webView; +@property (nonatomic,weak)IBOutlet NSImageView* iconImageView; +@property (nonatomic,weak)IBOutlet NSTextField* titleLabel; +@property (nonatomic,weak)IBOutlet NSButton* backButton; +@property (nonatomic,weak)IBOutlet NSButton* forwardButton; +@property (nonatomic,retain)NSProgressIndicator* progressIndicator; +@end + diff --git a/mac/TeamTalk/DDIntranetContentViewController.m b/mac/TeamTalk/DDIntranetContentViewController.m new file mode 100644 index 000000000..efa431069 --- /dev/null +++ b/mac/TeamTalk/DDIntranetContentViewController.m @@ -0,0 +1,153 @@ +// +// DDIntranetContentViewController.m +// Duoduo +// +// Created by 独嘉 on 14-6-25. +// Copyright (c) 2014年 zuoye. All rights reserved. +// + +#import "DDIntranetContentViewController.h" +#import "DDIntranetEntity.h" +@interface DDIntranetContentViewController () + +@end + +@implementation DDIntranetContentViewController + +- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil +{ + self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil]; + if (self) { + // Initialization code here. + self.progressIndicator = [[NSProgressIndicator alloc] init]; + [self.progressIndicator setStyle:NSProgressIndicatorSpinningStyle]; + [self.progressIndicator setControlSize:NSRegularControlSize]; + [self.progressIndicator.layer setBackgroundColor:[NSColor clearColor].CGColor]; + [self.progressIndicator setHidden:YES]; + } + return self; +} + +- (void)awakeFromNib +{ + [self.webView setCustomUserAgent:@"mogujieIM"]; + [self.progressIndicator setFrame:self.iconImageView.frame]; + [[self.iconImageView superview] addSubview:self.progressIndicator]; + [self.backButton setEnabled:[self.webView canGoBack]]; + [self.forwardButton setEnabled:[self.webView canGoForward]]; +} + +#pragma mark - +#pragma mark IBACtion +- (IBAction)mainWebView:(id)sender +{ + //主页 + [self.webView setMainFrameURL:self.intranetEntity.itemURL]; +} + +- (IBAction)refresh:(id)sender +{ + //刷新 + NSString* url = [self.webView mainFrameURL]; + [self.webView setMainFrameURL:url]; +} + +- (IBAction)forward:(id)sender +{ + //前进 + [self.webView goForward]; +} + +- (IBAction)back:(id)sender +{ + //后退 + [self.webView goBack]; +} + +#pragma mark - +#pragma mark WebView UIDelegate + +- (void)webView:(WebView *)sender makeFirstResponder:(NSResponder *)responder +{ + [[self.view window] makeFirstResponder:sender]; +} + +- (WebView *)webView:(WebView *)sender createWebViewWithRequest:(NSURLRequest *)request +{ + [[sender mainFrame] loadRequest:request]; + return sender; +} + +- (BOOL)webViewAreToolbarsVisible:(WebView *)sender +{ + return YES; +} + +- (void)webView:(WebView *)sender runJavaScriptAlertPanelWithMessage:(NSString *)message initiatedByFrame:(WebFrame *)frame +{ + DDLog(@"%@",message); +} + +#pragma mark - +#pragma mark WebView mainFrame Delegate +- (void)webView:(WebView *)sender didReceiveTitle:(NSString *)title forFrame:(WebFrame *)frame +{ + [self.titleLabel setStringValue:title]; +} + +- (void)webView:(WebView *)sender didReceiveIcon:(NSImage *)image forFrame:(WebFrame *)frame +{ + [self.iconImageView setImage:image]; +} + +- (void)webView:(WebView *)sender didChangeLocationWithinPageForFrame:(WebFrame *)frame +{ + DDLog(@"ascasdc"); +} + +- (void)webView:(WebView *)sender didReceiveServerRedirectForProvisionalLoadForFrame:(WebFrame *)frame +{ + DDLog(@"ascasc"); +} + +- (void)webView:(WebView *)sender didFailLoadWithError:(NSError *)error forFrame:(WebFrame *)frame +{ + DDLog(@"as"); +} + +- (void)webView:(WebView *)sender didFailProvisionalLoadWithError:(NSError *)error forFrame:(WebFrame *)frame +{ + DDLog(@"ascavc"); +} + +- (void)webView:(WebView *)sender willPerformClientRedirectToURL:(NSURL *)URL delay:(NSTimeInterval)seconds fireDate:(NSDate *)date forFrame:(WebFrame *)frame +{ + DDLog(@"asdafs"); +} + +- (void)webView:(WebView *)sender didCancelClientRedirectForFrame:(WebFrame *)frame +{ + DDLog(@"asac"); +} + +#pragma mark - +#pragma marj webView DataSource Delegate + +- (NSURLRequest *)webView:(WebView *)sender resource:(id)identifier willSendRequest:(NSURLRequest *)request redirectResponse:(NSURLResponse *)redirectResponse fromDataSource:(WebDataSource *)dataSource; +{ + [self.progressIndicator startAnimation:nil]; + [self.iconImageView setHidden:YES]; + [self.progressIndicator setHidden:NO]; + return request; +} + +- (void)webView:(WebView *)sender resource:(id)identifier didFinishLoadingFromDataSource:(WebDataSource *)dataSource +{ + [self.progressIndicator stopAnimation:nil]; + [self.progressIndicator setHidden:YES]; + [self.iconImageView setHidden:NO]; + [self.backButton setEnabled:[self.webView canGoBack]]; + [self.forwardButton setEnabled:[self.webView canGoForward]]; +} + +@end diff --git a/mac/TeamTalk/DDIntranetContentViewController.xib b/mac/TeamTalk/DDIntranetContentViewController.xib new file mode 100644 index 000000000..7bd01350b --- /dev/null +++ b/mac/TeamTalk/DDIntranetContentViewController.xib @@ -0,0 +1,110 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/mac/TeamTalk/DDIntranetEntity.h b/mac/TeamTalk/DDIntranetEntity.h new file mode 100644 index 000000000..8cb04942a --- /dev/null +++ b/mac/TeamTalk/DDIntranetEntity.h @@ -0,0 +1,19 @@ +// +// DDIntranetEntity.h +// Duoduo +// +// Created by 独嘉 on 14-6-25. +// Copyright (c) 2014年 zuoye. All rights reserved. +// + +#import + +@interface DDIntranetEntity : NSObject +@property (nonatomic,assign)NSInteger ID; +@property (nonatomic,assign)NSUInteger createdTime; +@property (nonatomic,retain)NSString* name; +@property (nonatomic,assign)NSInteger priority; +@property (nonatomic,retain)NSString* itemURL; +@property (nonatomic,assign)NSInteger status; +- (id)initWithInfo:(NSDictionary*)info; +@end diff --git a/mac/TeamTalk/DDIntranetEntity.m b/mac/TeamTalk/DDIntranetEntity.m new file mode 100644 index 000000000..a8e52f8b5 --- /dev/null +++ b/mac/TeamTalk/DDIntranetEntity.m @@ -0,0 +1,26 @@ +// +// DDIntranetEntity.m +// Duoduo +// +// Created by 独嘉 on 14-6-25. +// Copyright (c) 2014年 zuoye. All rights reserved. +// + +#import "DDIntranetEntity.h" + +@implementation DDIntranetEntity +- (id)initWithInfo:(NSDictionary*)info +{ + self = [super init]; + if (self) + { + _ID = [info[@"id"] integerValue]; + _name = info[@"itemName"]; + _priority = [info[@"itemPriority"] integerValue]; + _createdTime = [info[@"created"] integerValue]; + _itemURL = info[@"itemUrl"]; + _status = [info[@"status"] integerValue]; + } + return self; +} +@end diff --git a/mac/TeamTalk/DDIntranetModule.h b/mac/TeamTalk/DDIntranetModule.h new file mode 100644 index 000000000..1946a1061 --- /dev/null +++ b/mac/TeamTalk/DDIntranetModule.h @@ -0,0 +1,18 @@ +// +// DDIntranetModule.h +// Duoduo +// +// Created by 独嘉 on 14-6-25. +// Copyright (c) 2014年 zuoye. All rights reserved. +// + +#import +#import "DDIntranetEntity.h" + +typedef void(^DDIntranetLoadCompletion)(); + +@interface DDIntranetModule : NSObject +@property(nonatomic,retain)NSMutableArray* intranets; + +- (void)loadIntranetsCompletion:(DDIntranetLoadCompletion)completion; +@end diff --git a/mac/TeamTalk/DDIntranetModule.m b/mac/TeamTalk/DDIntranetModule.m new file mode 100644 index 000000000..385ff679c --- /dev/null +++ b/mac/TeamTalk/DDIntranetModule.m @@ -0,0 +1,70 @@ +// +// DDIntranetModule.m +// Duoduo +// +// Created by 独嘉 on 14-6-25. +// Copyright (c) 2014年 zuoye. All rights reserved. +// + +#import "DDIntranetModule.h" +#import "NSString+DDStringAdditions.h" +#import "MD5.h" +#import "MTUserEntity.h" +#import "MTUserModule.h" +#import +@interface DDIntranetModule(PrivateAPI) + +- (void)p_sortIntranet; + +@end +@implementation DDIntranetModule +- (id)init +{ + self = [super init]; + if (self) + { + _intranets = [[NSMutableArray alloc] init]; + } + return self; +} + +- (void)loadIntranetsCompletion:(DDIntranetLoadCompletion)completion +{ + AFHTTPRequestOperationManager* httpManager = [AFHTTPRequestOperationManager manager]; + httpManager.responseSerializer = [AFHTTPResponseSerializer serializer]; + [[NSURLCache sharedURLCache] removeAllCachedResponses]; + [httpManager GET:[DDClientState shareInstance].discoverURL parameters:nil success:^(AFHTTPRequestOperation *operation, id responseObject) { + NSArray* items = [NSJSONSerialization JSONObjectWithData:responseObject options:0 error:nil]; + [items enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) { + NSDictionary* info = (NSDictionary*)obj; + DDIntranetEntity* intranetEntity = [[DDIntranetEntity alloc] initWithInfo:info]; + [_intranets addObject:intranetEntity]; + }]; + [self p_sortIntranet]; + } failure:^(AFHTTPRequestOperation *operation, NSError *error) { + DDLog(@"failed"); + }]; +} + +#pragma mark private API +- (void)p_sortIntranet +{ + [_intranets sortUsingComparator:^NSComparisonResult(id obj1, id obj2) { + DDIntranetEntity* intranet1 = (DDIntranetEntity*)obj1; + DDIntranetEntity* intranet2 = (DDIntranetEntity*)obj2; + if (intranet1.priority > intranet2.priority) + { + return NSOrderedAscending; + } + else if(intranet1.priority < intranet2.priority) + { + return NSOrderedDescending; + } + else + { + return NSOrderedSame; + } + }]; +} + +@end diff --git a/mac/TeamTalk/DDIntranetViewController.h b/mac/TeamTalk/DDIntranetViewController.h new file mode 100644 index 000000000..e323af7cf --- /dev/null +++ b/mac/TeamTalk/DDIntranetViewController.h @@ -0,0 +1,25 @@ +// +// DDIntranetViewController.h +// Duoduo +// +// Created by 独嘉 on 14-6-25. +// Copyright (c) 2014年 zuoye. All rights reserved. +// + +#import +@class DDIntranetModule; +@class DDIntranetEntity; +@class DDIntranetViewController; +@protocol DDIntranetViewControllerDelegate + +- (void)intranetViewController:(DDIntranetViewController*)intranetViewCOntroller selectIntranetEntity:(DDIntranetEntity*)intranet; + +@end + +@interface DDIntranetViewController : NSViewController +@property (nonatomic,weak)IBOutlet NSTableView* tableView; +@property (nonatomic,retain)DDIntranetModule* module; +@property (nonatomic,assign)id delegate; + +- (void)selectItemAtIndex:(NSUInteger)index; +@end diff --git a/mac/TeamTalk/DDIntranetViewController.m b/mac/TeamTalk/DDIntranetViewController.m new file mode 100644 index 000000000..df6152cd2 --- /dev/null +++ b/mac/TeamTalk/DDIntranetViewController.m @@ -0,0 +1,102 @@ +// +// DDIntranetViewController.m +// Duoduo +// +// Created by 独嘉 on 14-6-25. +// Copyright (c) 2014年 zuoye. All rights reserved. +// + +#import "DDIntranetViewController.h" +#import "DDIntranetModule.h" +#import "DDIntranetCell.h" +#import "MTMessageModule.h" +@interface DDIntranetViewController(privateAPI) + +- (void)p_clickTheTableView; +- (void)n_receiveP2PIntranetMessage:(NSNotification*)notification; + +@end + +@implementation DDIntranetViewController + +- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil +{ + self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil]; + if (self) + { + [self.module loadIntranetsCompletion:^{ + [_tableView reloadData]; + }]; + } + return self; +} + +- (DDIntranetModule*)module +{ + if (!_module) + { + _module = [[DDIntranetModule alloc] init]; + } + return _module; +} + +- (void)awakeFromNib +{ + [_tableView setHeaderView:nil]; + [_tableView setTarget:self]; + [_tableView setAction:@selector(p_clickTheTableView)]; +} + +- (void)selectItemAtIndex:(NSUInteger)index +{ + DDIntranetEntity* intranetEntity = self.module.intranets[0]; + [_tableView reloadDataForRowIndexes:[NSIndexSet indexSetWithIndex:0] columnIndexes:[NSIndexSet indexSetWithIndex:0]]; +// [_tableView selectRowIndexes:[NSIndexSet indexSetWithIndex:0] byExtendingSelection:NO]; +// [_tableView scrollRowToVisible:0]; + [self.delegate intranetViewController:self selectIntranetEntity:intranetEntity]; +} + +#pragma mark DataSource +- (NSInteger)numberOfRowsInTableView:(NSTableView *)tableView +{ + return [self.module.intranets count]; +} + +- (CGFloat)tableView:(NSTableView *)tableView heightOfRow:(NSInteger)row +{ + return 50; +} + +- (NSView*)tableView:(NSTableView *)tableView viewForTableColumn:(NSTableColumn *)tableColumn row:(NSInteger)row +{ + NSString* identifier = [tableColumn identifier]; + NSString* cellIdentifier = @"IntranentCellIdentifier"; + if ([identifier isEqualToString:@"IntranentColumnIdentifier"]) + { + DDIntranetCell* cell = (DDIntranetCell*)[tableView makeViewWithIdentifier:cellIdentifier owner:self]; + DDIntranetEntity* intranet = self.module.intranets[row]; + [cell configWithIntranet:intranet]; + return cell; + } + return nil; +} + +#pragma mark - +#pragma mark KVO + +#pragma mark - +#pragma mark PrivateAPI +- (void)p_clickTheTableView +{ + NSInteger clickRow = [_tableView selectedRow]; + if (clickRow >= 0) + { + DDIntranetEntity* intranet = self.module.intranets[clickRow]; + if (self.delegate) + { + [self.delegate intranetViewController:self selectIntranetEntity:intranet]; + } + } +} + +@end diff --git a/mac/TeamTalk/DDLogic/DDLogic.h b/mac/TeamTalk/DDLogic/DDLogic.h new file mode 100644 index 000000000..57c16e94c --- /dev/null +++ b/mac/TeamTalk/DDLogic/DDLogic.h @@ -0,0 +1,50 @@ +/************************************************************ + * @file DDLogic.h + * @author 快刀 + * summery 逻辑框架接口实现:事件通知、业务数据本地序列化反序列化、逻辑任务执行、模块注册等接口 + ************************************************************/ + +#import +#import "DDLogicProtocol.h" +#import "DDModuleID.h" +#import "DDModuleManager.h" +#import "DDTaskManager.h" + +@interface DDLogic : NSObject +{ + DDModuleManager* _moduleManger; + DDTaskManager* _taskManager; +} + +#pragma -mark 模块相关 +-(BOOL) registerModule:(DDModule*) module; +-(BOOL) unRegisterModule:(DDModule*) module; +-(DDModule*) queryModuleByID:(uint16) moduleId; +//将module业务数据序列化到本地 +-(BOOL) archive; + +#pragma -mark 监听数据相关 +-(void)addObserver:(uint16)moduleId name:(NSString* const)name observer:(id)observer selector:(SEL)aSelector; +//异步通知到主线程 +-(void)uiAsyncNotify:(uint16)moduleId name:(NSString* const)name userInfo:(NSMutableDictionary*)userInfo; +//同步通知到主线程 (注:尽量避免使用这个,因为主线程会把逻辑线程给阻塞住,切记) +-(void)uisyncNotify:(uint16)moduleId name:(NSString* const)name userInfo:(NSMutableDictionary*)userInfo; +//同步通知到当前线程 +-(void)notify:(uint16)moduleId name:(NSString* const)name userInfo:(NSMutableDictionary*)userInfo; + +#pragma -mark 逻辑执行器 +-(BOOL) pushTaskWithBlock:(TaskBlock)taskBlock; +-(BOOL) pushTask:(id)task delegate:(id) delegate; +//未实现 +-(BOOL) pushTaskWithTarget:(id)target selector:(SEL)sel; + +#pragma -mark 网络 +//-(void)sendPackedData:(NSMutableData *)data; + +#pragma -mark 初始化 +-(BOOL) startup; +-(void) shutdown; +-(id)init; ++(DDLogic*) instance; + +@end diff --git a/mac/TeamTalk/DDLogic/DDLogic.m b/mac/TeamTalk/DDLogic/DDLogic.m new file mode 100644 index 000000000..33c3b9dae --- /dev/null +++ b/mac/TeamTalk/DDLogic/DDLogic.m @@ -0,0 +1,108 @@ +/************************************************************ + * @file DDLogic.m + * @author 快刀 + * summery 逻辑框架接口实现:事件通知、业务数据本地序列化反序列化、逻辑任务执行、模块注册等接口 + ************************************************************/ + +#import "DDLogic.h" + +@implementation DDLogic + +#pragma -mark 初始化 ++(DDLogic*) instance +{ + static DDLogic* _instance = nil; + static dispatch_once_t onceToken; + dispatch_once(&onceToken,^{ + _instance = [[self alloc] init]; + }); + + return _instance; +} +-(id)init +{ + if(self = [super init]) + { + _moduleManger = [[DDModuleManager alloc] init]; + _taskManager = [[DDTaskManager alloc] init]; + } + + return self; +} + +-(BOOL) startup +{ + [_moduleManger startup]; + + return YES; +} +-(void) shutdown +{ + [_taskManager shutdown]; + + [_moduleManger shutdown]; +} + +#pragma -mark 模块相关 +-(BOOL) registerModule:(DDModule*) module +{ + return [_moduleManger registerModule:module]; +} +-(BOOL) unRegisterModule:(DDModule*) module +{ + return [_moduleManger unRegisterModule:module]; +} +-(BOOL) archive +{ + return [_moduleManger archive]; +} +-(DDModule*) queryModuleByID:(uint16) moduleId +{ + return [_moduleManger queryModuleByID:moduleId]; +} + +#pragma -mark 监听数据相关 +-(void)addObserver:(uint16)moduleId name:(NSString *const)name observer:(id)observer selector:(SEL)aSelector +{ + [_moduleManger addObserver:moduleId name:name observer:observer selector:aSelector]; +} + +-(void)uiAsyncNotify:(uint16)moduleId name:(NSString* const)name userInfo:(NSMutableDictionary*)userInfo +{ + [_moduleManger uiAsyncNotify:moduleId name:name userInfo:userInfo]; +} + +-(void)uisyncNotify:(uint16)moduleId name:(NSString* const)name userInfo:(NSMutableDictionary*)userInfo +{ + [_moduleManger uiAsyncNotify:moduleId name:name userInfo:userInfo]; +} + +-(void)notify:(uint16)moduleId name:(NSString* const)name userInfo:(NSMutableDictionary*)userInfo +{ + [_moduleManger notify:moduleId name:name userInfo:userInfo]; +} + +#pragma -mark 逻辑执行器 +-(BOOL) pushTask:(id)task delegate:(id) delegate +{ + return [_taskManager pushTask:task delegate:delegate]; +} + +-(BOOL) pushTaskWithBlock:(TaskBlock)taskBlock +{ + return [_taskManager pushTaskWithBlock:taskBlock]; +} + +-(BOOL) pushTaskWithTarget:(id)target selector:(SEL)sel +{ + return NO; +} + +#pragma -mark 网络 +//-(void)sendPackedData:(NSMutableData *)data +//{ +// DDTcpLinkModule* moduleTcpLink = getDDTcpLinkModule(); +// [moduleTcpLink sendPackedData:data]; +//} + +@end diff --git a/mac/TeamTalk/DDLogic/DDLogicProtocol.h b/mac/TeamTalk/DDLogic/DDLogicProtocol.h new file mode 100644 index 000000000..ce210cc0f --- /dev/null +++ b/mac/TeamTalk/DDLogic/DDLogicProtocol.h @@ -0,0 +1,53 @@ +/************************************************************ + * @file DDLogicProtocol.h + * @author 快刀 + * summery 逻辑框架接口定义:事件通知、监听数据变更、逻辑任务执行、服务注册等接口 + ************************************************************/ + +#import +#import "DDModuleManager.h" +#import "DDTask.h" +#import "DDTaskOperation.h" + +#pragma -mark 模块相关 +@protocol DDModuleProtocol + +@required +//注册模块 +-(BOOL) registerModule:(DDModule*) module; +//反注册模块 +-(BOOL) unRegisterModule:(DDModule*) module; +//通过module id查找模块 +-(DDModule*) queryModuleByID:(uint16) moduleId; + +//监听数据相关 +-(void)addObserver:(uint16)moduleId name:(NSString* const)name observer:(id)observer selector:(SEL)aSelector; +//异步通知到主线程 +-(void)uiAsyncNotify:(uint16)moduleId name:(NSString* const)name userInfo:(NSMutableDictionary*)userInfo; +//同步通知到主线程 (注:尽量少用这个,因为主线程会把逻辑线程给阻塞住,切记) +-(void)uisyncNotify:(uint16)moduleId name:(NSString* const)name userInfo:(NSMutableDictionary*)userInfo; +//同步通知到当前线程 +-(void)notify:(uint16)moduleId name:(NSString* const)name userInfo:(NSMutableDictionary*)userInfo; + +@end + +#pragma -mark 逻辑执行器 +@protocol DDWorkerProtocol + +@required +//将一个任务FIFO推入任务执行器 +-(BOOL) pushTask:(id)task delegate:(id) delegate; +-(BOOL) pushTaskWithBlock:(TaskBlock)taskBlock; +//未实现 +-(BOOL) pushTaskWithTarget:(id)target selector:(SEL)sel; + +@end + + +@protocol DDLogicProtocol + +@required +-(BOOL) startup; +-(void) shutdown; + +@end \ No newline at end of file diff --git a/mac/TeamTalk/DDLogic/module/DDModuleDataManager.h b/mac/TeamTalk/DDLogic/module/DDModuleDataManager.h new file mode 100644 index 000000000..c535711c7 --- /dev/null +++ b/mac/TeamTalk/DDLogic/module/DDModuleDataManager.h @@ -0,0 +1,18 @@ +/************************************************************ + * @file DDModuleDataManager.h + * @author 快刀 + * summery 基于module的业务层数据的序列化、反序列化 + ************************************************************/ + +#import + +@interface DDModuleDataManager : NSObject +{ + NSArray* _moduleArray; +} + +-(id)initModuleData:(NSArray*)moduleArray; +-(BOOL)archive; +-(BOOL)unArchive; + +@end diff --git a/mac/TeamTalk/DDLogic/module/DDModuleDataManager.m b/mac/TeamTalk/DDLogic/module/DDModuleDataManager.m new file mode 100644 index 000000000..98b3c2ccc --- /dev/null +++ b/mac/TeamTalk/DDLogic/module/DDModuleDataManager.m @@ -0,0 +1,80 @@ +/************************************************************ + * @file DDModuleDataManager.h + * @author 快刀 + * summery 基于module的业务层数据的序列化、反序列化 + ************************************************************/ + +#import "DDModuleDataManager.h" +#import "DDModuleManager.h" + + +@interface DDModuleDataManager() + +-(NSString*)getDataPath; + +@end + +@implementation DDModuleDataManager + +-(NSString*)getDataPath +{ + NSString* filePath = [[duoduo applicationSupportDirectory] stringByAppendingPathComponent:@"DuoDuoModuleData"]; + return filePath; +} + +-(id)initModuleData:(NSArray*)moduleArray +{ + if(self = [super init]) + { + _moduleArray = moduleArray; + } + return self; +} + +-(BOOL)archive +{ + @autoreleasepool + { + NSMutableData* dataArchiver = [[NSMutableData alloc] init]; + NSKeyedArchiver* archiver = [[NSKeyedArchiver alloc] initForWritingWithMutableData:dataArchiver]; + for (DDModule* module in _moduleArray) + { + if([module conformsToProtocol:@protocol(NSCoding)]) + { + NSString* key = [NSString stringWithFormat:@"%d",module.moduleId]; + [archiver encodeObject:module forKey:key]; + } + } + [archiver finishEncoding]; + NSString* filePath = [self getDataPath]; + return [dataArchiver writeToFile:filePath atomically:YES]; + } +} + +-(BOOL)unArchive +{ + @autoreleasepool + { + NSString* filePath = [self getDataPath]; + NSData* dataUnArchiver = [[NSData alloc] initWithContentsOfFile:filePath]; + if(!dataUnArchiver) + return NO; + NSKeyedUnarchiver* unArchiver = [[NSKeyedUnarchiver alloc] initForReadingWithData:dataUnArchiver]; + if(!unArchiver) + return NO; + + for (DDModule* module in _moduleArray) + { + if([module conformsToProtocol:@protocol(NSCoding)]) + { + NSString* key = [NSString stringWithFormat:@"%d",module.moduleId]; + [unArchiver decodeObjectForKey:key]; + } + } + [unArchiver finishDecoding]; + } + + return YES; +} + +@end diff --git a/mac/TeamTalk/DDLogic/module/DDModuleID.h b/mac/TeamTalk/DDLogic/module/DDModuleID.h new file mode 100644 index 000000000..7503d27de --- /dev/null +++ b/mac/TeamTalk/DDLogic/module/DDModuleID.h @@ -0,0 +1,31 @@ +/************************************************************ + * @file DDModule.h + * @author 快刀 + * summery 模块ID定义 + ************************************************************/ + +#import + +//static const uint16 MODULE_ID_REMOTEBASE = 0x0000U; //与服务器端交互的module id +//static const uint16 MODULE_ID_LOCALBASE = 0x4000U; //本地业务的module id + +//enum +//{ +// MODULE_ID_NONE = 0, + + //与服务器端交互的module id +// MODULE_ID_LOGIN = MODULE_ID_REMOTEBASE | 0x0002, //登陆模块 +// MODULE_ID_FRIENDLIST = MODULE_ID_REMOTEBASE | 0x0003, //成员列表管理模块 +// MODULE_ID_MESSAGE = MODULE_ID_REMOTEBASE | 0x0004, //消息管理模块 +// MODULE_ID_HTTP = MODULE_ID_REMOTEBASE | 0x0005, //HTTP模块 +// MODULE_ID_TCPLINK = MODULE_ID_REMOTEBASE | 0x0006, //TCP长连接模块 +// MODULE_ID_MAIN = MODULE_ID_REMOTEBASE | 0x0007, //主窗口模块i +// MODULE_ID_SESSION = MODULE_ID_REMOTEBASE | 0x0050, //会话模块 +// MODULE_ID_GROUP = MODULE_ID_REMOTEBASE | 0x0052, // group module +// MODULE_ID_P2P = MODULE_ID_REMOTEBASE | 0x0051, //P2P +// MODULE_ID_FILETRANSFER = MODULE_ID_REMOTEBASE | 0x005A, //文件传输模块 + + //本地业务的module id +// MODULE_ID_CAPTURE = MODULE_ID_LOCALBASE | 0x001, //截屏模块 +// MODULE_ID_COMMON = MODULE_ID_LOCALBASE | 0X002, //多多公共函数库 +//}; diff --git a/mac/TeamTalk/DDLogic/module/DDModuleManager.h b/mac/TeamTalk/DDLogic/module/DDModuleManager.h new file mode 100644 index 000000000..8b1819bd4 --- /dev/null +++ b/mac/TeamTalk/DDLogic/module/DDModuleManager.h @@ -0,0 +1,59 @@ +/************************************************************ + * @file DDModuleManager.h + * @author 快刀 + * summery 框架服务module管理,整个工程所有的module必须要到这里注册,并且分配一个全局唯一的service id + ************************************************************/ + +#import +#import "NSNotification+DDLogic.h" + +static NSString* const USERINFO_DEFAULT_KEY = @"defaultKey"; //NSNotification通知userinfo字典默认key + +@interface DDModule : NSObject +{ + NSMutableDictionary* _observerCaches; +} + +@property(nonatomic,readonly) uint16 moduleId; + +-(id) initModule:(uint16) moduleId; + +-(void) onLoadModule; +-(void) onUnloadModule; + +-(void)addObserver:(NSString* const)name observer:(id)observer selector:(SEL)aSelector; +-(void)uiAsyncNotify:(NSString* const)name userInfo:(NSMutableDictionary*)userInfo; +-(void)uiSyncNotify:(NSString* const)name userInfo:(NSMutableDictionary*)userInfo; +-(void)notify:(NSString* const)name userInfo:(NSMutableDictionary*)userInfo; + +@end + +@interface DDTcpModule : DDModule + +-(void)onHandleTcpData:(uint16)cmdId data:(id)data; + +@end + +@class DDModuleDataManager; +@interface DDModuleManager : NSObject +{ + NSMutableArray* _moduleArray; + DDModuleDataManager* _moduleDataManager; +} + +-(id)init; +-(BOOL) startup; +-(void) shutdown; + +-(BOOL) registerModule:(DDModule*) module; +-(BOOL) unRegisterModule:(DDModule*) module; +-(DDModule*) queryModuleByID:(uint16) moduleId; +-(BOOL)archive; + + +-(void)addObserver:(uint16)moduleId name:(NSString* const)name observer:(id)observer selector:(SEL)aSelector; +-(void)uiAsyncNotify:(uint16)moduleId name:(NSString* const)name userInfo:(NSMutableDictionary*)userInfo; +-(void)uisyncNotify:(uint16)moduleId name:(NSString* const)name userInfo:(NSMutableDictionary*)userInfo; +-(void)notify:(uint16)moduleId name:(NSString* const)name userInfo:(NSMutableDictionary*)userInfo; + +@end diff --git a/mac/TeamTalk/DDLogic/module/DDModuleManager.m b/mac/TeamTalk/DDLogic/module/DDModuleManager.m new file mode 100644 index 000000000..6002ccac8 --- /dev/null +++ b/mac/TeamTalk/DDLogic/module/DDModuleManager.m @@ -0,0 +1,205 @@ +/************************************************************ + * @file DDModuleManager.m + * @author 快刀 + * summery 框架服务module管理,整个工程所有的module必须要到这里注册,并且分配一个全局唯一的service id + ************************************************************/ + +#import "DDModuleManager.h" +#import "DDModuleDataManager.h" + +@implementation DDTcpModule + +-(void)onHandleTcpData:(uint16)cmdId data:(id)data +{ +} + +@end + +@interface DDModule() + +-(void)cacheObserver:(NSString*)name observer:(id)observer; + +@end + +@implementation DDModule + +-(id) initModule:(uint16) moduleId +{ + if(self = [super init]) + { + _moduleId = moduleId; + _observerCaches = [[NSMutableDictionary alloc] init]; + } + return self; +} + +-(void) onLoadModule +{ + +} + +-(void) onUnloadModule +{ + for(NSString* name in _observerCaches) + { + NSArray* sameNameObservers = [_observerCaches objectForKey:name]; + for (id observer in sameNameObservers) + { + [[NSNotificationCenter defaultCenter] removeObserver:observer name:name object:nil]; + } + } +} + +-(void)cacheObserver:(NSString*)name observer:(id)observer +{ + NSMutableArray* sameNameObservers = [_observerCaches objectForKey:name]; + if(!sameNameObservers) + { + sameNameObservers = [[NSMutableArray alloc] init]; + } + if(![sameNameObservers containsObject:observer]) + { + [sameNameObservers addObject:observer]; + } + [_observerCaches setValue:sameNameObservers forKey:name]; +} + +-(void)addObserver:(NSString* const)name observer:(id)observer selector:(SEL)aSelector +{ + //trick 为了在多次add同一个observer的时候,不多次调用 + [[NSNotificationCenter defaultCenter] removeObserver:observer name:name object:nil]; + [[NSNotificationCenter defaultCenter] addObserver:observer selector:aSelector name:name object:nil]; + [self cacheObserver:name observer:observer]; +} + +-(void)uiAsyncNotify:(NSString* const)name userInfo:(NSMutableDictionary*)userInfo +{ + NSNotification* notification = [NSNotification notificationWithName:name object:self userInfo:userInfo]; + NSString* uid = [userInfo objectForKey:USERINFO_SID]; + if(uid) + { + [notification setSessionId:uid]; + } + [[NSNotificationCenter defaultCenter] performSelectorOnMainThread:@selector(postNotification:)withObject:notification waitUntilDone:NO]; +} + +-(void)uiSyncNotify:(NSString* const)name userInfo:(NSMutableDictionary*)userInfo +{ + NSNotification* notification = [NSNotification notificationWithName:name object:self userInfo:userInfo]; + NSString* uid = [userInfo objectForKey:USERINFO_SID]; + if(uid) + { + [notification setSessionId:uid]; + } + [[NSNotificationCenter defaultCenter] performSelectorOnMainThread:@selector(postNotification:)withObject:notification waitUntilDone:YES]; +} + +-(void)notify:(NSString* const)name userInfo:(NSMutableDictionary*)userInfo +{ +// [userInfo setObject:@"aaa" forKey:USERINFO_SID]; + NSNotification* notification = [NSNotification notificationWithName:name object:self userInfo:userInfo]; + NSString* uid = [userInfo objectForKey:USERINFO_SID]; + if(uid) + { + [notification setSessionId:uid]; + } + [[NSNotificationCenter defaultCenter] performSelector:@selector(postNotification:) withObject:notification withObject:notification]; +} + +@end + +@interface DDModuleManager() +-(void)unRegisterAllModules; +@end + +@implementation DDModuleManager + +-(id)init +{ + if(self = [super init]) + { + _moduleArray = [NSMutableArray array]; + _moduleDataManager = [[DDModuleDataManager alloc] initModuleData:_moduleArray]; + } + return self; +} + +-(BOOL) registerModule:(DDModule*) module +{ + //todo... 去重 + [_moduleArray addObject:module]; + + [module onLoadModule]; + + return YES; +} +-(BOOL) unRegisterModule:(DDModule*) module +{ + [module onUnloadModule]; + + [_moduleArray removeObject:module]; + + return YES; +} + +-(void)addObserver:(uint16)moduleId name:(NSString* const)name observer:(id)observer selector:(SEL)aSelector +{ + DDModule* module = [self queryModuleByID:moduleId]; + [module addObserver:name observer:observer selector:aSelector]; +} + +-(void)uiAsyncNotify:(uint16)moduleId name:(NSString* const)name userInfo:(NSMutableDictionary*)userInfo +{ + DDModule* module = [self queryModuleByID:moduleId]; + [module uiAsyncNotify:name userInfo:userInfo]; +} + +-(void)uisyncNotify:(uint16)moduleId name:(NSString* const)name userInfo:(NSMutableDictionary*)userInfo +{ + DDModule* module = [self queryModuleByID:moduleId]; + [module uiAsyncNotify:name userInfo:userInfo]; +} + +-(void)notify:(uint16)moduleId name:(NSString* const)name userInfo:(NSMutableDictionary*)userInfo +{ + DDModule* module = [self queryModuleByID:moduleId]; + [module notify:name userInfo:userInfo]; +} + +-(DDModule*) queryModuleByID:(uint16) moduleId +{ + for(DDModule* module in _moduleArray) + { + if(module.moduleId == moduleId) + return module; + } + + return nil; +} + +-(BOOL)archive +{ + return [_moduleDataManager archive]; +} + +-(BOOL) startup +{ + return [_moduleDataManager unArchive]; +} + +-(void) shutdown +{ + [_moduleDataManager archive]; + + [self unRegisterAllModules]; +} + +-(void)unRegisterAllModules +{ + for(DDModule* module in _moduleArray) + { + [module onUnloadModule]; + } +} + +@end diff --git a/mac/TeamTalk/DDLogic/module/DDWatch.h b/mac/TeamTalk/DDLogic/module/DDWatch.h new file mode 100644 index 000000000..20883f884 --- /dev/null +++ b/mac/TeamTalk/DDLogic/module/DDWatch.h @@ -0,0 +1,29 @@ +/************************************************************ + * @file DDWtach.h + * @author 快刀 + * summery watch实现监听service中tag的变化,通知给观察者s(废弃这块的封装,等到要做Core data的时候再来考虑) + ************************************************************/ + +#import + +@protocol WatchHandle + +@required +-(void)OnWatchHandle:(uint32)tagID; + +@end + +@interface DDWatch : NSObject +{ + NSString* _notifiName; + NSMutableArray* _observerArray; + id _delegate; +} + +-(void)addWatch:(id)observer selector:(SEL)aSelector; +-(void)uiNotify:(uint32)tagID; + +-(id) initWatch:(NSString*)nitifiName; + +@end + diff --git a/mac/TeamTalk/DDLogic/module/DDWatch.m b/mac/TeamTalk/DDLogic/module/DDWatch.m new file mode 100644 index 000000000..eec488208 --- /dev/null +++ b/mac/TeamTalk/DDLogic/module/DDWatch.m @@ -0,0 +1,45 @@ +/************************************************************ + * @file DDWtach.m + * @author 快刀 + * summery watch实现监听service中tag的变化,通知给观察者s(废弃这块的封装,等到要做Core data的时候再来考虑) + ************************************************************/ + +#import "DDWatch.h" +@interface DDWatch() + +-(void)onWatchNotify:(NSNotification*)notification; + +@end + +@implementation DDWatch + +-(void)onWatchNotify:(NSNotification*)notification +{ + [_delegate OnWatchHandle:2]; +} + +-(void)addWatch:(id)observer selector:(SEL)aSelector +{ + //todo 去重 + [_observerArray addObject:observer]; + + _delegate = observer; +} + +-(void)uiNotify:(uint32)tagID +{ + [[NSNotificationCenter defaultCenter] postNotificationName:_notifiName object:self]; +} + +-(id) initWatch:(NSString*)nitifiName +{ + if(self = [super init]) + { + _notifiName = nitifiName; + _observerArray = [NSMutableArray array]; + [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(onWatchNotify:) name:_notifiName object:self]; + } + return self; +} + +@end diff --git a/mac/TeamTalk/DDLogic/task/DDTask.h b/mac/TeamTalk/DDLogic/task/DDTask.h new file mode 100644 index 000000000..5d12e63b1 --- /dev/null +++ b/mac/TeamTalk/DDLogic/task/DDTask.h @@ -0,0 +1,33 @@ +/************************************************************ + * @file DDTask.h + * @author 快刀 + * summery task任务抽象,包括基本task、网络异步task、同步、异步回调等 + ************************************************************/ + +#import + +@protocol DDTaskProtocol + +@required +-(void) execute; + +@end + +@class DDTask; +@protocol DDTaskDelegate + +@optional +-(BOOL) didDDTaskStarted : (DDTask*) task; +-(void) didDDTaskAsyncUICallback:(DDTask*) task; +-(void) didDDTaskCallback : (DDTask*)task; +-(void) didDDTaskFinished :(DDTask*) task; + +@end + +@interface DDTask : NSObject + +@property(nonatomic,strong) NSObject* delegate; +-(void) execute; +- (void)uiNotify; + +@end diff --git a/mac/TeamTalk/DDLogic/task/DDTaskManager.h b/mac/TeamTalk/DDLogic/task/DDTaskManager.h new file mode 100644 index 000000000..c415dc324 --- /dev/null +++ b/mac/TeamTalk/DDLogic/task/DDTaskManager.h @@ -0,0 +1,24 @@ +/************************************************************ + * @file DDTaskService.h + * @author 快刀 + * summery 后台逻辑线程task机制封装,执行一些短时间的短暂的后台计算性任务 + ************************************************************/ + +#import + +#import "DDTaskOperation.h" + +@interface DDTaskManager : NSObject +{ +@private + NSOperationQueue* _queue; + NSOperation* _lastOperation; +} + +-(BOOL) pushTask:(id)task delegate:(id) delegate; +//todo task with block、target action +-(BOOL) pushTaskWithBlock:(TaskBlock)taskBlock; +-(BOOL) pushTaskWithTarget:(id)target selector:(SEL)sel; +-(void) shutdown; + +@end diff --git a/mac/TeamTalk/DDLogic/task/DDTaskManager.m b/mac/TeamTalk/DDLogic/task/DDTaskManager.m new file mode 100644 index 000000000..717b87ad7 --- /dev/null +++ b/mac/TeamTalk/DDLogic/task/DDTaskManager.m @@ -0,0 +1,70 @@ +/************************************************************ + * @file DDTaskService.m + * @author 快刀 + * summery 后台逻辑线程task机制封装,能跑一些短时间的短暂的后台计算性任务 + ************************************************************/ + +#import "DDTaskManager.h" +#import "DDTaskOperation.h" + +@implementation DDTaskManager + +-(id) init +{ + if(self = [super init]) + { + _queue = [[NSOperationQueue alloc] init]; + [_queue setMaxConcurrentOperationCount:1]; + } + + return self; +} + +-(BOOL) pushTaskWithBlock:(TaskBlock)taskBlock +{ + @synchronized(self) + { + DDTaskOperation* operation = [[DDTaskOperation alloc] initWithBlock:taskBlock]; + if(!operation) + return NO; + [_queue addOperation:operation]; + //保证FIFO + [_lastOperation addDependency:operation]; + _lastOperation = operation; + } + + return YES; +} + +-(BOOL) pushTask:(id)task delegate:(id) delegate; +{ + @synchronized(self) + { + DDTaskOperation* operation = [[DDTaskOperation alloc] initWithDDTask:task delegate:delegate]; + if(!operation) + return NO; + [_queue addOperation:operation]; + //保证FIFO + [_lastOperation addDependency:operation]; + _lastOperation = operation; + } + + return YES; +} + +-(BOOL) pushTaskWithTarget:(id)target selector:(SEL)sel +{ + @synchronized(self) + { + + } + + return YES; +} + +-(void) shutdown +{ + [_queue cancelAllOperations]; +} + +@end diff --git a/mac/TeamTalk/DDLogic/task/DDTaskOperation.h b/mac/TeamTalk/DDLogic/task/DDTaskOperation.h new file mode 100644 index 000000000..a95c3abd4 --- /dev/null +++ b/mac/TeamTalk/DDLogic/task/DDTaskOperation.h @@ -0,0 +1,25 @@ +/************************************************************ + * @file DDTaskOperation.h + * @author 快刀 + * summery 通过NSOperation包装task,用于执行后台一些短暂的计算性任务 + ************************************************************/ + +#import + +@protocol DDTaskProtocol; +@protocol DDTaskDelegate; + +typedef void(^TaskBlock)(); + +@interface DDTaskOperation : NSOperation +{ +@private + id _ddTask; + id _delegate; + TaskBlock _block; +} + +-(id) initWithDDTask:(id) task delegate : (id)delegate; +-(id) initWithBlock:(TaskBlock)taskBlock; + +@end \ No newline at end of file diff --git a/mac/TeamTalk/DDLogic/task/DDTaskOperation.m b/mac/TeamTalk/DDLogic/task/DDTaskOperation.m new file mode 100644 index 000000000..412478e5d --- /dev/null +++ b/mac/TeamTalk/DDLogic/task/DDTaskOperation.m @@ -0,0 +1,73 @@ +/************************************************************ + * @file DDTaskOperation.m + * @author 快刀 + * summery 通过NSOperation包装task,用于执行后台一些短暂的计算性任务 + ************************************************************/ + +#import "DDTask.h" +#import "DDTaskOperation.h" + +@implementation DDTaskOperation + +-(void) main +{ + if([self isCancelled]) + return; + if([_delegate respondsToSelector:@selector(didDDTaskStarted:)]) + { + if(![_delegate didDDTaskStarted:_ddTask]) + return; + } + if(_ddTask) + [_ddTask execute]; + else + _block(); + if([self isCancelled]) + return; + if([_delegate respondsToSelector:@selector(didDDTaskFinished:)]) + { + [_delegate didDDTaskFinished:_ddTask]; + } +} + +-(id) initWithBlock:(TaskBlock)taskBlock +{ + if(self = [super init]) + { + _block = taskBlock; + } + return self; +} + +-(id) initWithDDTask:(id) task delegate : (id)delegate +{ + if(self = [super init]) + { + _ddTask = task; + if([_ddTask isKindOfClass:[DDTask class]]) + { + DDTask* task = (DDTask*) _ddTask; + task.delegate = delegate; + } + _delegate = delegate ; + } + + return self; +} + +@end + +@implementation DDTask + +-(void) execute +{ +} + +- (void)uiNotify +{ + if([_delegate respondsToSelector:@selector(didDDTaskAsyncUICallback:)]) + { + [_delegate performSelectorOnMainThread:@selector(didDDTaskAsyncUICallback:) withObject:self waitUntilDone:NO]; + } +} +@end diff --git a/mac/TeamTalk/DDRecentContactRowView.h b/mac/TeamTalk/DDRecentContactRowView.h new file mode 100644 index 000000000..e3e820ff0 --- /dev/null +++ b/mac/TeamTalk/DDRecentContactRowView.h @@ -0,0 +1,13 @@ +// +// DDRecentContactRowView.h +// Duoduo +// +// Created by 独嘉 on 14-3-12. +// Copyright (c) 2014年 zuoye. All rights reserved. +// + +#import + +@interface DDRecentContactRowView : NSTableRowView + +@end diff --git a/mac/TeamTalk/DDRecentContactRowView.m b/mac/TeamTalk/DDRecentContactRowView.m new file mode 100644 index 000000000..ac24e48d6 --- /dev/null +++ b/mac/TeamTalk/DDRecentContactRowView.m @@ -0,0 +1,73 @@ +// +// DDRecentContactRowView.m +// Duoduo +// +// Created by 独嘉 on 14-3-12. +// Copyright (c) 2014年 zuoye. All rights reserved. +// + +#import "DDRecentContactRowView.h" + +@implementation DDRecentContactRowView + +- (id)initWithFrame:(NSRect)frame +{ + self = [super initWithFrame:frame]; + if (self) { + // Initialization code here. + } + return self; +} + +- (void)drawRect:(NSRect)dirtyRect +{ + [super drawRect:dirtyRect]; + + // Drawing code here. +} + +- (void)drawSelectionInRect:(NSRect)dirtyRect { + NSColor *primaryColor = [[NSColor alternateSelectedControlColor] colorWithAlphaComponent:0.5]; + NSColor *secondarySelectedControlColor = [[NSColor alternateSelectedControlColor] colorWithAlphaComponent:0.5]; + + // Implement our own custom alpha drawing + switch (self.selectionHighlightStyle) { + case NSTableViewSelectionHighlightStyleRegular: { + if (self.selected) { + if (self.emphasized) { + [primaryColor set]; + } else { + [secondarySelectedControlColor set]; + } + NSRect bounds = self.bounds; + const NSRect *rects = NULL; + NSInteger count = 0; + [self getRectsBeingDrawn:&rects count:&count]; + for (NSInteger i = 0; i < count; i++) { + NSRect rect = NSIntersectionRect(bounds, rects[i]); + NSRectFillUsingOperation(rect, NSCompositeSourceOver); + } + } + break; + } + default: { + // Do super's drawing + [super drawSelectionInRect:dirtyRect]; + break; + } + } +} + +- (void)drawSeparatorInRect:(NSRect)dirtyRect { + // Draw the grid + NSRect sepRect = self.bounds; + sepRect.origin.y = NSMaxY(sepRect) - 1; + sepRect.size.height = 1; + sepRect = NSIntersectionRect(sepRect, dirtyRect); + if (!NSIsEmptyRect(sepRect)) { + [[NSColor gridColor] set]; + NSRectFill(sepRect); + } +} + +@end diff --git a/mac/TeamTalk/DDSearchResultCell.xib b/mac/TeamTalk/DDSearchResultCell.xib new file mode 100644 index 000000000..44978644e --- /dev/null +++ b/mac/TeamTalk/DDSearchResultCell.xib @@ -0,0 +1,36 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/mac/TeamTalk/DDSetting+OffLineReadMsgManager.h b/mac/TeamTalk/DDSetting+OffLineReadMsgManager.h new file mode 100644 index 000000000..c35db58fb --- /dev/null +++ b/mac/TeamTalk/DDSetting+OffLineReadMsgManager.h @@ -0,0 +1,14 @@ +// +// DDSetting+OffLineReadMsgManager.h +// Duoduo +// +// Created by 独嘉 on 14-3-27. +// Copyright (c) 2014年 zuoye. All rights reserved. +// + +#import "DDSetting.h" + +@interface DDSetting (OffLineReadMsgManager) +- (void)addOffLineReadMsgSessionID:(NSString*)sessionID; +- (void)sendHadReadInOffStatePack; +@end diff --git a/mac/TeamTalk/DDSetting+OffLineReadMsgManager.m b/mac/TeamTalk/DDSetting+OffLineReadMsgManager.m new file mode 100644 index 000000000..ecfd353c2 --- /dev/null +++ b/mac/TeamTalk/DDSetting+OffLineReadMsgManager.m @@ -0,0 +1,36 @@ +// +// DDSetting+OffLineReadMsgManager.m +// Duoduo +// +// Created by 独嘉 on 14-3-27. +// Copyright (c) 2014年 zuoye. All rights reserved. +// + +static NSString* const kOffStateReadSession = @"offStateReadSession"; +#import "DDSetting+OffLineReadMsgManager.h" +#import "MTSessionModule.h" + +@implementation DDSetting (OffLineReadMsgManager) + +- (void)addOffLineReadMsgSessionID:(NSString*)sessionID +{ + NSArray* offStateReadSessions = [[NSUserDefaults standardUserDefaults] objectForKey:kOffStateReadSession]; + NSMutableArray* newOffStateReadSessions = [[NSMutableArray alloc] initWithArray:offStateReadSessions]; + [newOffStateReadSessions addObject:sessionID]; + [[NSUserDefaults standardUserDefaults] setObject:newOffStateReadSessions forKey:kOffStateReadSession]; + [[NSUserDefaults standardUserDefaults] synchronize]; +} + +- (void)sendHadReadInOffStatePack +{ +// NSArray* readList = [[NSUserDefaults standardUserDefaults] objectForKey:kOffStateReadSession]; +// DDSessionModule* sessionModule = getDDSessionModule(); +// for (NSString* sessionID in readList) +// { +// SessionEntity* session = [sessionModule getSessionBySId:sessionID]; +// [sessionModule tcpSendReadedAck:session]; +// } +} + + +@end diff --git a/mac/TeamTalk/DDSetting.h b/mac/TeamTalk/DDSetting.h new file mode 100644 index 000000000..028d9aacc --- /dev/null +++ b/mac/TeamTalk/DDSetting.h @@ -0,0 +1,62 @@ +// +// DDSetting.h +// Duoduo +// +// Created by 独嘉 on 14-3-25. +// Copyright (c) 2014年 zuoye. All rights reserved. +// + +#import + +@interface DDSetting : NSObject + ++ (instancetype)instance; + +/** + * 还原默认设置 + */ +- (void)restoreDefaultSetting; + +/** + * 获得置顶的会话 + * + * @return 置顶的会话ID + */ +- (NSArray*)getTopSessionIDs; + + +/** + * 会话置顶 + * + * @param sessionID 会话ID + */ +- (void)addTopSessionID:(NSString*)sessionID; + +/** + * 取消会话置顶 + * + * @param sessionID 会话ID + */ +- (void)removeTopSessionID:(NSString*)sessionID; + +/** + * 获得屏蔽的会话IDS + * + * @return 屏蔽的会话ID + */ +- (NSArray*)getShieldSessionIDs; + +/** + * 屏蔽会话 + * + * @param sessionID 会话ID + */ +- (void)addShieldSessionID:(NSString*)sessionID; + +/** + * 取消屏蔽会话 + * + * @param sessionID 会话ID + */ +- (void)removeShieldSessionID:(NSString*)sessionID; +@end diff --git a/mac/TeamTalk/DDSetting.m b/mac/TeamTalk/DDSetting.m new file mode 100644 index 000000000..5bfdde74b --- /dev/null +++ b/mac/TeamTalk/DDSetting.m @@ -0,0 +1,172 @@ +// +// DDSetting.m +// Duoduo +// +// Created by 独嘉 on 14-3-25. +// Copyright (c) 2014年 zuoye. All rights reserved. +// + +#import "DDSetting.h" + +static NSString* const kSettingVersionKey = @"SettingVersion"; + +@interface DDSetting(privateAPI) + +- (void)checkUpdateToRestoreSetting; + +@end + +static NSString* kTopKey = @"TopSession"; +static NSString* kShieldKey = @"ShieldSession"; +@implementation DDSetting ++ (instancetype)instance +{ + static DDSetting* g_setting; + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^{ + g_setting = [[DDSetting alloc] init]; + }); + return g_setting; +} + +- (id)init +{ + self = [super init]; + if (self) + { + [self checkUpdateToRestoreSetting]; + } + return self; +} + +- (void)restoreDefaultSetting +{ + [[NSUserDefaults standardUserDefaults] setObject:nil forKey:TOP_SESSION_KEY]; + [[NSUserDefaults standardUserDefaults] setObject:nil forKey:SHIELD_SESSION_KEY]; + [[NSUserDefaults standardUserDefaults] synchronize]; +} + +- (NSArray*)getTopSessionIDs +{ + NSDictionary* topSessionDic = [[NSUserDefaults standardUserDefaults] objectForKey:TOP_SESSION_KEY]; + NSString* myID = [[DDClientState shareInstance] userID]; + return topSessionDic[myID]; +} + +- (void)addTopSessionID:(NSString*)sessionID +{ + NSDictionary* topSessionDic = [[NSUserDefaults standardUserDefaults] objectForKey:TOP_SESSION_KEY]; + NSString* myID = [[DDClientState shareInstance] userID]; + NSArray* oldTopSessions = topSessionDic[myID]; + NSMutableArray* newTopSession = [[NSMutableArray alloc] initWithArray:oldTopSessions]; + if (![newTopSession containsObject:sessionID]) + { + [newTopSession addObject:sessionID]; + } + NSMutableDictionary* newTopSessionDic = [[NSMutableDictionary alloc] initWithDictionary:topSessionDic]; + [newTopSessionDic setObject:newTopSession forKey:myID]; + [[NSUserDefaults standardUserDefaults] setObject:newTopSessionDic forKey:TOP_SESSION_KEY]; + [[NSUserDefaults standardUserDefaults] synchronize]; +} + +- (void)removeTopSessionID:(NSString*)sessionID +{ + NSArray* oldTopSession = [self getTopSessionIDs]; + if (![oldTopSession containsObject:sessionID]) + { + return; + } + else + { + NSMutableArray* newTopSession = [[NSMutableArray alloc] initWithArray:oldTopSession]; + [newTopSession removeObject:sessionID]; + + + NSString* myID = [[DDClientState shareInstance] userID]; + + NSDictionary* oldTopSessionDic = [[NSUserDefaults standardUserDefaults] objectForKey:TOP_SESSION_KEY]; + NSMutableDictionary* newTopSessionDic = [[NSMutableDictionary alloc] initWithDictionary:oldTopSessionDic]; + [newTopSessionDic setObject:newTopSession forKey:myID]; + + [[NSUserDefaults standardUserDefaults] setObject:newTopSessionDic forKey:TOP_SESSION_KEY]; + [[NSUserDefaults standardUserDefaults] synchronize]; + } + +} + +- (NSArray*)getShieldSessionIDs +{ + NSDictionary* shieldSessionDic = [[NSUserDefaults standardUserDefaults] objectForKey:SHIELD_SESSION_KEY]; + NSString* myID = [[DDClientState shareInstance] userID]; + NSMutableArray* shieldSessions = [[NSMutableArray alloc] initWithArray:shieldSessionDic[myID]]; + NSNumber* boolNumber = [[NSUserDefaults standardUserDefaults]objectForKey:FIRST_TIME_SET_BUSINESS_SHIELD]; + if (!boolNumber) + { + if (![shieldSessions containsObject:@"group_1fis"]) + { + [self addShieldSessionID:@"group_1fis"]; + } + [[NSUserDefaults standardUserDefaults] setObject:@(1) forKey:FIRST_TIME_SET_BUSINESS_SHIELD]; + [[NSUserDefaults standardUserDefaults] synchronize]; + } +// [[NSUserDefaults standardUserDefaults] removeObjectForKey:FIRST_TIME_SET_BUSINESS_SHIELD]; +// [[NSUserDefaults standardUserDefaults] synchronize]; + + return shieldSessions; +} + +- (void)addShieldSessionID:(NSString*)sessionID +{ + NSDictionary* shieldSessionDic = [[NSUserDefaults standardUserDefaults] objectForKey:SHIELD_SESSION_KEY]; + + NSString* myID = [[DDClientState shareInstance] userID]; + NSArray* oldTopSessions = shieldSessionDic[myID]; + NSMutableArray* newShieldSession = [[NSMutableArray alloc] initWithArray:oldTopSessions]; + if (![newShieldSession containsObject:sessionID]) + { + [newShieldSession addObject:sessionID]; + } + + NSMutableDictionary* newShieldSessionDic = [[NSMutableDictionary alloc] initWithDictionary:shieldSessionDic]; + [newShieldSessionDic setObject:newShieldSession forKey:myID]; + + [[NSUserDefaults standardUserDefaults] setObject:newShieldSessionDic forKey:SHIELD_SESSION_KEY]; + [[NSUserDefaults standardUserDefaults] synchronize]; +} + +- (void)removeShieldSessionID:(NSString*)sessionID +{ + NSDictionary* shieldSessionDic = [[NSUserDefaults standardUserDefaults] objectForKey:SHIELD_SESSION_KEY]; + NSString* myID = [[DDClientState shareInstance] userID]; + NSArray* oldTopSessions = shieldSessionDic[myID]; + NSMutableArray* newShieldSession = [[NSMutableArray alloc] initWithArray:oldTopSessions]; + if ([newShieldSession containsObject:sessionID]) + { + [newShieldSession removeObject:sessionID]; + } + + NSMutableDictionary* newShieldSessionDic = [[NSMutableDictionary alloc] initWithDictionary:shieldSessionDic]; + [newShieldSessionDic setObject:newShieldSession forKey:myID]; + + [[NSUserDefaults standardUserDefaults] setObject:newShieldSessionDic forKey:SHIELD_SESSION_KEY]; + [[NSUserDefaults standardUserDefaults] synchronize]; +} + +#pragma mark - private API +- (void)checkUpdateToRestoreSetting +{ + NSString* version = [[NSUserDefaults standardUserDefaults] objectForKey:kSettingVersionKey]; + NSString* currentVersion = [[[NSBundle mainBundle] infoDictionary] objectForKey:@"CFBundleVersion"]; + if(!version) + { + [[NSUserDefaults standardUserDefaults] setObject:currentVersion forKey:kSettingVersionKey]; + [self restoreDefaultSetting]; + } + if (version && ![version isEqualToString:currentVersion]) + { +// [self restoreDefaultSetting]; +// [[NSUserDefaults standardUserDefaults] setObject:currentVersion forKey:kSettingVersionKey]; + } + [[NSUserDefaults standardUserDefaults] synchronize]; +} +@end diff --git a/mac/TeamTalk/DDSharedDuoduo.h b/mac/TeamTalk/DDSharedDuoduo.h new file mode 100644 index 000000000..65a2eb9ea --- /dev/null +++ b/mac/TeamTalk/DDSharedDuoduo.h @@ -0,0 +1,13 @@ +// +// DDSharedDuoduo.h +// Duoduo +// +// Created by maye on 13-10-30. +// Copyright (c) 2013年 zuoye. All rights reserved. +// + +#import "DDDuoduoProtocol.h" + +extern id duoduo; + +void setSharedDuoduo(id shared); \ No newline at end of file diff --git a/mac/TeamTalk/DDSharedDuoduo.m b/mac/TeamTalk/DDSharedDuoduo.m new file mode 100644 index 000000000..e56f0dde6 --- /dev/null +++ b/mac/TeamTalk/DDSharedDuoduo.m @@ -0,0 +1,15 @@ +// +// DDSharedDuoduo.m +// Duoduo +// +// Created by maye on 13-10-30. +// Copyright (c) 2013年 zuoye. All rights reserved. +// + +id duoduo = nil; + +void setSharedDuoduo(id shared){ + NSCAssert(duoduo == nil, @"Attempt to set the shared duoduo instance after it's already been set"); + NSCParameterAssert(shared != nil); + duoduo = shared; +} diff --git a/mac/TeamTalk/DDTcpClientManager.h b/mac/TeamTalk/DDTcpClientManager.h new file mode 100644 index 000000000..40977ba21 --- /dev/null +++ b/mac/TeamTalk/DDTcpClientManager.h @@ -0,0 +1,33 @@ +// +// DDTcpClientManager.h +// Duoduo +// +// Created by 独嘉 on 14-4-12. +// Copyright (c) 2014年 zuoye. All rights reserved. +// + +#import +@class SendBuffer; +@interface DDTcpClientManager : NSObject +{ +@private + NSInputStream *_inStream; + NSOutputStream *_outStream; + NSLock *_receiveLock; + NSMutableData *_receiveBuffer; + NSLock *_sendLock; + NSMutableArray *_sendBuffers; + SendBuffer *_lastSendBuffer; + BOOL _noDataSent; + int32_t cDataLen; + +} + ++ (instancetype)instance; + +-(void)connect:(NSString *)ipAdr port:(NSInteger)port status:(NSInteger)status; +-(void)disconnect; +-(void)writeToSocket:(NSMutableData *)data; + + +@end diff --git a/mac/TeamTalk/DDTcpClientManager.m b/mac/TeamTalk/DDTcpClientManager.m new file mode 100644 index 000000000..e350889c6 --- /dev/null +++ b/mac/TeamTalk/DDTcpClientManager.m @@ -0,0 +1,363 @@ +// +// DDTcpClientManager.m +// Duoduo +// +// Created by 独嘉 on 14-4-12. +// Copyright (c) 2014年 zuoye. All rights reserved. +// + +#import "DDTcpClientManager.h" +#import "NSStream+NSStreamAddition.h" +#import "SendBuffer.h" +#import "TcpProtocolHeader.h" +#import "DataInputStream.h" + +#import "DDAPISchedule.h" + +@interface DDTcpClientManager(PrivateAPI) + +- (void)p_handleConntectOpenCompletedStream:(NSStream *)aStream; +- (void)p_handleEventErrorOccurredStream:(NSStream *)aStream; +- (void)p_handleEventEndEncounteredStream:(NSStream *)aStream; +- (void)p_handleEventHasBytesAvailableStream:(NSStream *)aStream; +- (void)p_handleEventHasSpaceAvailableStream:(NSStream *)aStream; +@end + +@implementation DDTcpClientManager ++ (instancetype)instance +{ + static DDTcpClientManager* g_tcpClientManager; + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^{ + g_tcpClientManager = [[DDTcpClientManager alloc] init]; + }); + return g_tcpClientManager; +} + +- (instancetype)init +{ + self = [super init]; + if (self) + { + [[DDClientState shareInstance] addObserver:self + forKeyPath:DD_USER_STATE_KEYPATH + options:NSKeyValueObservingOptionNew | NSKeyValueObservingOptionOld + context:nil]; + } + return self; +} + +#pragma mark - PublicAPI +-(void)connect:(NSString *)ipAdr port:(NSInteger)port status:(NSInteger)status +{ + DDLog(@"mogujie mtalk client :connect ipAdr:%@ port:%ld",ipAdr,(long)port); + cDataLen = 0; + + _receiveBuffer = [NSMutableData data]; + _sendBuffers = [NSMutableArray array]; + _noDataSent = NO; + + _receiveLock = [[NSLock alloc] init]; + _sendLock = [[NSLock alloc] init]; + + NSInputStream *tempInput = nil; + NSOutputStream *tempOutput = nil; + + [NSStream getStreamsToHostNamed:ipAdr port:port inputStream:&tempInput outputStream:&tempOutput]; + _inStream = tempInput; + _outStream = tempOutput; + + [_inStream setDelegate:self]; + [_outStream setDelegate:self]; + + [_inStream scheduleInRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode]; + [_outStream scheduleInRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode]; + + [_inStream open]; + [_outStream open]; +} + +-(void)disconnect +{ + DDLog(@"MTalk Client:disconnect"); + + cDataLen = 0; + + _receiveLock = nil; + _sendLock = nil; + + [_inStream close]; + [_inStream removeFromRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode]; + _inStream = nil; + + [_outStream close]; + [_outStream removeFromRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode]; + _outStream = nil; + + _receiveBuffer = nil; + _sendBuffers = nil; + _lastSendBuffer = nil; + + [NotificationHelp postNotification:notificationTcpLinkDisconnect userInfo:nil object:nil]; + +} + +-(void)writeToSocket:(NSMutableData *)data{ + [_sendLock lock]; + @try { + if (_noDataSent ==YES) { + + NSInteger len; + len = [_outStream write:[data mutableBytes] maxLength:[data length]]; + _noDataSent = NO; + // DDLog(@"WRITE - Written directly to outStream len:%li", len); + if (len < [data length]) { +//DDLog(@"WRITE - Creating a new buffer for remaining data len:%li", [data length] - len); + _lastSendBuffer = [SendBuffer dataWithNSData:[data subdataWithRange:NSMakeRange([data length]-len, [data length])]]; + [_sendBuffers addObject:_lastSendBuffer]; + + } + return; + } + + if (_lastSendBuffer) { + NSInteger lastSendBufferLength; + NSInteger newDataLength; + lastSendBufferLength = [_lastSendBuffer length]; + newDataLength = [data length]; + if (lastSendBufferLength<1024) { + DDLog(@"WRITE - Have a buffer with enough space, appending data to it"); + [_lastSendBuffer appendData:data]; + return; + } + } + //DDLog(@"WRITE - Creating a new buffer"); + _lastSendBuffer = [SendBuffer dataWithNSData:data]; + [_sendBuffers addObject:_lastSendBuffer]; + + } + @catch (NSException *exception) { + DDLog(@" ***** NSException:%@ in writeToSocket of MGJMTalkClient *****",exception); + } + @finally { + [_sendLock unlock]; + } +} + +#pragma mark - +#pragma mark KVO +- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context +{ + if ([keyPath isEqualToString:DD_USER_STATE_KEYPATH]) + { + switch ([DDClientState shareInstance].userState) + { + case DDUserKickout: + case DDUserKickByMobile: + case DDUserOffLineInitiative: + [self disconnect]; + break; + + default: + break; + } + } +} + +#pragma mark - NSStream Delegate +- (void)stream:(NSStream *)aStream handleEvent:(NSStreamEvent)eventCode +{ + switch(eventCode) { + case NSStreamEventNone: + //DDLog(@"Event type: EventNone"); + break; + case NSStreamEventOpenCompleted: + [self p_handleConntectOpenCompletedStream:aStream]; + break; + case NSStreamEventHasSpaceAvailable: //发送数据 + //DDLog(@"Event type: EventHasSpaceAvailable"); + [self p_handleEventHasSpaceAvailableStream:aStream]; + break; + case NSStreamEventErrorOccurred: + //DDLog(@"Event type: EventErrorOccured"); + [self p_handleEventErrorOccurredStream:aStream]; + break; + case NSStreamEventEndEncountered: + //DDLog(@"Event type: EventEndOccured"); + [self p_handleEventEndEncounteredStream:aStream]; + break; + case NSStreamEventHasBytesAvailable: + //DDLog(@"Event type: EventHasBytesAvailable"); + [self p_handleEventHasBytesAvailableStream:aStream]; + break; + } +} + +#pragma mark - PrivateAPI +- (void)p_handleConntectOpenCompletedStream:(NSStream *)aStream +{ + if (aStream == _outStream) { + [NotificationHelp postNotification:notificationTcpLinkConnectComplete userInfo:nil object:nil]; + } +} + +- (void)p_handleEventHasSpaceAvailableStream:(NSStream *)aStream +{ + [_sendLock lock]; + + @try { + + if (![_sendBuffers count]) { + DDLog(@"WRITE - No data to send"); + _noDataSent = YES; + + return; + } + + SendBuffer *sendBuffer = [_sendBuffers objectAtIndex:0]; + + NSInteger sendBufferLength = [sendBuffer length]; + + if (!sendBufferLength) { + if (sendBuffer == _lastSendBuffer) { + _lastSendBuffer = nil; + } + + [_sendBuffers removeObjectAtIndex:0]; + + //DDLog(@"WRITE - No data to send"); + + _noDataSent = YES; + + return; + } + + NSInteger len = ((sendBufferLength - [sendBuffer sendPos] >= 1024) ? 1024 : (sendBufferLength - [sendBuffer sendPos])); + if (!len) { + if (sendBuffer == _lastSendBuffer) { + _lastSendBuffer = nil; + } + + [_sendBuffers removeObjectAtIndex:0]; + + // DDLog(@"WRITE - No data to send"); + + _noDataSent = YES; + + return; + } + + // DDLog(@"write %ld bytes", len); + len = [_outStream write:((const uint8_t *)[sendBuffer mutableBytes] + [sendBuffer sendPos]) maxLength:len]; + // DDLog(@"WRITE - Written directly to outStream len:%lid", (long)len); + [sendBuffer consumeData:len]; + + if (![sendBuffer length]) { + if (sendBuffer == _lastSendBuffer) { + _lastSendBuffer = nil; + } + + [_sendBuffers removeObjectAtIndex:0]; + } + + _noDataSent = NO; + + + return; + } + @catch (NSException *exception) { + DDLog(@" ***** NSException in MGJMTalkCleint :%@ ******* ",exception); + } + @finally { + [_sendLock unlock]; + } +} + +- (void)p_handleEventErrorOccurredStream:(NSStream *)aStream +{ + DDLog(@"handle eventErrorOccurred"); +} + +- (void)p_handleEventEndEncounteredStream:(NSStream *)aStream +{ + DDLog(@"handle eventEndEncountered"); + cDataLen = 0; + +} + +- (void)p_handleEventHasBytesAvailableStream:(NSStream *)aStream +{ + uint8_t buf[1024]; + NSInteger len = 0; + len = [(NSInputStream *)aStream read:buf maxLength:1024]; + if (len < 0) { + [self disconnect]; + return; + } + + if (len > 0) { + + // DataInputStream *dataIn = [DataInputStream dataInputStreamWithData:<#(NSData *)#> + [_receiveLock lock]; + [_receiveBuffer appendBytes:(const void *)buf length:len]; + + while ([_receiveBuffer length] >= IM_PDU_HEADER_LEN) { + NSRange range = NSMakeRange(0, IM_PDU_HEADER_LEN); +// [[DDAPISchedule instance] receiveServerData:_receiveBuffer]; + + NSData *headerData = [_receiveBuffer subdataWithRange:range]; + + DataInputStream *inputData = [DataInputStream dataInputStreamWithData:headerData]; + + uint32_t pduLen = [inputData readInt]; + if (pduLen > (uint32_t)[_receiveBuffer length]) { + break; + } + + TcpProtocolHeader* tcpHeader = [[TcpProtocolHeader alloc] init]; + tcpHeader.version = [inputData readShort]; + tcpHeader.flag = [inputData readShort]; + tcpHeader.serviceId = [inputData readShort]; + tcpHeader.commandId = [inputData readShort]; + tcpHeader.reserved = [inputData readShort]; + tcpHeader.error = [inputData readShort]; + +// DDLog(@"receive a packet serviceId=%d, commandId=%d", tcpHeader.serviceId, tcpHeader.commandId); + + range = NSMakeRange(IM_PDU_HEADER_LEN, pduLen - IM_PDU_HEADER_LEN); + NSData *payloadData = [_receiveBuffer subdataWithRange:range]; + + + + // + uint32_t remainLen = (int)[_receiveBuffer length] - pduLen; + range = NSMakeRange(pduLen, remainLen); + NSData *remainData = [_receiveBuffer subdataWithRange:range]; + [_receiveBuffer setData:remainData]; + ServerDataType dataType = DDMakeServerDataType(tcpHeader.serviceId, tcpHeader.commandId, tcpHeader.reserved); + [[DDAPISchedule instance] receiveServerData:payloadData forDataType:dataType]; + +// } +// DataInputStream *payloadInputData = [DataInputStream dataInputStreamWithData:payloadData]; +// +// // 先更新_receiveBuffer, 在处理数据包 +// uint32_t remainLen = (int)[_receiveBuffer length] - pduLen; +// range = NSMakeRange(pduLen, remainLen); +// NSData *remainData = [_receiveBuffer subdataWithRange:range]; +// [_receiveBuffer setData:remainData]; +// DDDispatchTask* task = [[DDDispatchTask alloc] initDispatchTask:tcpHeader body:payloadInputData]; +// [[DDLogic instance] pushTask:task delegate:nil]; + + //收到心跳 + [NotificationHelp postNotification:notificationServerHeartBeat userInfo:nil object:nil]; + + } + + [_receiveLock unlock]; + } + else { + DDLog(@"No buffer!"); + } + +} +@end diff --git a/mac/TeamTalk/EGOImageLoader/EGOCache.h b/mac/TeamTalk/EGOImageLoader/EGOCache.h new file mode 100644 index 000000000..4fe2dacb8 --- /dev/null +++ b/mac/TeamTalk/EGOImageLoader/EGOCache.h @@ -0,0 +1,73 @@ +// +// EGOCache.h +// enormego +// +// Created by Shaun Harrison on 7/4/09. +// Copyright (c) 2009-2010 enormego +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. +// + +#import + + +@interface EGOCache : NSObject { +@private + NSMutableDictionary* cacheDictionary; + NSOperationQueue* diskOperationQueue; + NSTimeInterval defaultTimeoutInterval; +} + ++ (EGOCache*)currentCache; + +- (void)clearCache; +- (void)removeCacheForKey:(NSString*)key; + +- (BOOL)hasCacheForKey:(NSString*)key; + +- (NSData*)dataForKey:(NSString*)key; +- (void)setData:(NSData*)data forKey:(NSString*)key; +- (void)setData:(NSData*)data forKey:(NSString*)key withTimeoutInterval:(NSTimeInterval)timeoutInterval; + +- (NSString*)stringForKey:(NSString*)key; +- (void)setString:(NSString*)aString forKey:(NSString*)key; +- (void)setString:(NSString*)aString forKey:(NSString*)key withTimeoutInterval:(NSTimeInterval)timeoutInterval; +- (NSString*)cachePathForKey:(NSString*)key; + +#if TARGET_OS_IPHONE +- (UIImage*)imageForKey:(NSString*)key; +- (void)setImage:(UIImage*)anImage forKey:(NSString*)key; +- (void)setImage:(UIImage*)anImage forKey:(NSString*)key withTimeoutInterval:(NSTimeInterval)timeoutInterval; +#else +- (NSImage*)imageForKey:(NSString*)key; +- (void)setImage:(NSImage*)anImage forKey:(NSString*)key; +- (void)setImage:(NSImage*)anImage forKey:(NSString*)key withTimeoutInterval:(NSTimeInterval)timeoutInterval; +#endif + +- (NSData*)plistForKey:(NSString*)key; +- (void)setPlist:(id)plistObject forKey:(NSString*)key; +- (void)setPlist:(id)plistObject forKey:(NSString*)key withTimeoutInterval:(NSTimeInterval)timeoutInterval; + +- (void)copyFilePath:(NSString*)filePath asKey:(NSString*)key; +- (void)copyFilePath:(NSString*)filePath asKey:(NSString*)key withTimeoutInterval:(NSTimeInterval)timeoutInterval; + +-(NSString *)pathForKey:(NSString *)key; + +@property(nonatomic,assign) NSTimeInterval defaultTimeoutInterval; // Default is 1 day +@end \ No newline at end of file diff --git a/mac/TeamTalk/EGOImageLoader/EGOCache.m b/mac/TeamTalk/EGOImageLoader/EGOCache.m new file mode 100644 index 000000000..409c523bd --- /dev/null +++ b/mac/TeamTalk/EGOImageLoader/EGOCache.m @@ -0,0 +1,315 @@ +// +// EGOCache.m +// enormego +// +// Created by Shaun Harrison on 7/4/09. +// Copyright (c) 2009-2010 enormego +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. +// + +#import "EGOCache.h" + +#if DEBUG + #define CHECK_FOR_EGOCACHE_PLIST() if([key isEqualToString:@"EGOCache.plist"]) { \ + DDLog(@"EGOCache.plist is a reserved key and can not be modified."); \ + return; } +#else + #define CHECK_FOR_EGOCACHE_PLIST() if([key isEqualToString:@"EGOCache.plist"]) return; +#endif + + + +static NSString* _EGOCacheDirectory; + +static inline NSString* EGOCacheDirectory() { + if(!_EGOCacheDirectory) { + //NSString* cachesDirectory = [NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES) objectAtIndex:0]; + + _EGOCacheDirectory =[[[duoduo applicationSupportDirectory] stringByAppendingPathComponent:@"DDCache"] copy]; + + //[[[cachesDirectory stringByAppendingPathComponent:[[NSProcessInfo processInfo] processName]] stringByAppendingPathComponent:@"DDCache"] copy]; + } + + // DDLog(@"图片缓存目录:%@",_EGOCacheDirectory); + return _EGOCacheDirectory; +} + +static inline NSString* cachePathForKey(NSString* key) { + // NSString* keyName = [NSString stringWithFormat:@"%@.png",key]; + return [EGOCacheDirectory() stringByAppendingPathComponent:key]; +} + +static EGOCache* __instance; + +@interface EGOCache () +- (void)removeItemFromCache:(NSString*)key; +- (void)performDiskWriteOperation:(NSInvocation *)invoction; +- (void)saveCacheDictionary; +@end + +#pragma mark - + +@implementation EGOCache +@synthesize defaultTimeoutInterval; + ++ (EGOCache*)currentCache { + @synchronized(self) { + if(!__instance) { + __instance = [[EGOCache alloc] init]; + __instance.defaultTimeoutInterval = 86400; + } + } + + return __instance; +} + +- (id)init { + if((self = [super init])) { + NSDictionary* dict = [NSDictionary dictionaryWithContentsOfFile:cachePathForKey(@"EGOCache.plist")]; + + if([dict isKindOfClass:[NSDictionary class]]) { + cacheDictionary = [dict mutableCopy]; + } else { + cacheDictionary = [[NSMutableDictionary alloc] init]; + } + + diskOperationQueue = [[NSOperationQueue alloc] init]; + + [[NSFileManager defaultManager] createDirectoryAtPath:EGOCacheDirectory() + withIntermediateDirectories:YES + attributes:nil + error:NULL]; + + for(NSString* key in cacheDictionary) { + NSDate* date = [cacheDictionary objectForKey:key]; + if([[[NSDate date] earlierDate:date] isEqualToDate:date]) { + [[NSFileManager defaultManager] removeItemAtPath:cachePathForKey(key) error:NULL]; + } + } + } + + return self; +} + +- (void)clearCache { + for(NSString* key in [cacheDictionary allKeys]) { + [self removeItemFromCache:key]; + } + + [self saveCacheDictionary]; +} + +- (void)removeCacheForKey:(NSString*)key { + CHECK_FOR_EGOCACHE_PLIST(); + + [self removeItemFromCache:key]; + [self saveCacheDictionary]; +} + +- (void)removeItemFromCache:(NSString*)key { + NSString* cachePath = cachePathForKey(key); + + NSInvocation* deleteInvocation = [NSInvocation invocationWithMethodSignature:[self methodSignatureForSelector:@selector(deleteDataAtPath:)]]; + [deleteInvocation setTarget:self]; + [deleteInvocation setSelector:@selector(deleteDataAtPath:)]; + [deleteInvocation setArgument:&cachePath atIndex:2]; + + [self performDiskWriteOperation:deleteInvocation]; + [cacheDictionary removeObjectForKey:key]; +} + +- (BOOL)hasCacheForKey:(NSString*)key { + NSDate* date = [cacheDictionary objectForKey:key]; + if(!date) return NO; + //if([[[NSDate date] earlierDate:date] isEqualToDate:date]) return NO; + return [[NSFileManager defaultManager] fileExistsAtPath:cachePathForKey(key)]; +} + +#pragma mark - +#pragma mark Copy file methods + +- (void)copyFilePath:(NSString*)filePath asKey:(NSString*)key { + [self copyFilePath:filePath asKey:key withTimeoutInterval:self.defaultTimeoutInterval]; +} + +- (void)copyFilePath:(NSString*)filePath asKey:(NSString*)key withTimeoutInterval:(NSTimeInterval)timeoutInterval { + [[NSFileManager defaultManager] copyItemAtPath:filePath toPath:cachePathForKey(key) error:NULL]; + [cacheDictionary setObject:[NSDate dateWithTimeIntervalSinceNow:timeoutInterval] forKey:key]; + [self performSelectorOnMainThread:@selector(saveAfterDelay) withObject:nil waitUntilDone:YES]; +} + +#pragma mark - +#pragma mark Data methods + +- (void)setData:(NSData*)data forKey:(NSString*)key { + [self setData:data forKey:key withTimeoutInterval:self.defaultTimeoutInterval]; +} + +#pragma mark 将图片本地保存 +- (void)setData:(NSData*)data forKey:(NSString*)key withTimeoutInterval:(NSTimeInterval)timeoutInterval { + CHECK_FOR_EGOCACHE_PLIST(); + +#pragma mark -这里也有本地路径. + NSString* cachePath = cachePathForKey(key); +// cachePath = [cachePath stringByAppendingPathExtension:@"png"]; + /* + NSInvocation* writeInvocation = [NSInvocation invocationWithMethodSignature:[self methodSignatureForSelector:@selector(writeData:toPath:)]]; + [writeInvocation setTarget:self]; + [writeInvocation setSelector:@selector(writeData:toPath:)]; + [writeInvocation setArgument:&data atIndex:2]; + [writeInvocation setArgument:&cachePath atIndex:3]; + + [self performDiskWriteOperation:writeInvocation]; + */ + [data writeToFile:cachePath atomically:NO]; + [cacheDictionary setObject:[NSDate dateWithTimeIntervalSinceNow:timeoutInterval] forKey:key]; + + [self performSelectorOnMainThread:@selector(saveAfterDelay) withObject:nil waitUntilDone:YES]; // Need to make sure the save delay get scheduled in the main runloop, not the current threads +} + +- (void)saveAfterDelay { // Prevents multiple-rapid saves from happening, which will slow down your app + [NSObject cancelPreviousPerformRequestsWithTarget:self selector:@selector(saveCacheDictionary) object:nil]; + [self performSelector:@selector(saveCacheDictionary) withObject:nil afterDelay:0.3]; +} + +- (NSData*)dataForKey:(NSString*)key { + if([self hasCacheForKey:key]) { + return [NSData dataWithContentsOfFile:cachePathForKey(key) options:0 error:NULL]; + } else { + return nil; + } +} + +-(NSString *)pathForKey:(NSString *)key{ + return cachePathForKey(key); +} + +- (void)writeData:(NSData*)data toPath:(NSString *)path; { + [data writeToFile:path atomically:YES]; +} + +- (void)deleteDataAtPath:(NSString *)path { + [[NSFileManager defaultManager] removeItemAtPath:path error:NULL]; +} + +- (void)saveCacheDictionary { + @synchronized(self) { + [cacheDictionary writeToFile:cachePathForKey(@"EGOCache.plist") atomically:YES]; + } +} + +#pragma mark - +#pragma mark String methods + +- (NSString*)stringForKey:(NSString*)key { + return [[[NSString alloc] initWithData:[self dataForKey:key] encoding:NSUTF8StringEncoding] autorelease]; +} + +- (void)setString:(NSString*)aString forKey:(NSString*)key { + [self setString:aString forKey:key withTimeoutInterval:self.defaultTimeoutInterval]; +} + +- (void)setString:(NSString*)aString forKey:(NSString*)key withTimeoutInterval:(NSTimeInterval)timeoutInterval { + [self setData:[aString dataUsingEncoding:NSUTF8StringEncoding] forKey:key withTimeoutInterval:timeoutInterval]; +} + +- (NSString*)cachePathForKey:(NSString*)key; +{ + return cachePathForKey(key); +} + +#pragma mark - +#pragma mark Image methds + +#if TARGET_OS_IPHONE + +- (UIImage*)imageForKey:(NSString*)key { + return [UIImage imageWithContentsOfFile:cachePathForKey(key)]; +} + +- (void)setImage:(UIImage*)anImage forKey:(NSString*)key { + [self setImage:anImage forKey:key withTimeoutInterval:self.defaultTimeoutInterval]; +} + +- (void)setImage:(UIImage*)anImage forKey:(NSString*)key withTimeoutInterval:(NSTimeInterval)timeoutInterval { + [self setData:UIImagePNGRepresentation(anImage) forKey:key withTimeoutInterval:timeoutInterval]; +} + + +#else + +- (NSImage*)imageForKey:(NSString*)key { + return [[[NSImage alloc] initWithData:[self dataForKey:key]] autorelease]; +} + +- (void)setImage:(NSImage*)anImage forKey:(NSString*)key { + [self setImage:anImage forKey:key withTimeoutInterval:self.defaultTimeoutInterval]; +} + +- (void)setImage:(NSImage*)anImage forKey:(NSString*)key withTimeoutInterval:(NSTimeInterval)timeoutInterval { + [self setData:[[[anImage representations] objectAtIndex:0] representationUsingType:NSPNGFileType properties:nil] + forKey:key withTimeoutInterval:timeoutInterval]; +} + +#endif + +#pragma mark - +#pragma mark Property List methods + +- (NSData*)plistForKey:(NSString*)key; { + NSData* plistData = [self dataForKey:key]; + + return [NSPropertyListSerialization propertyListFromData:plistData + mutabilityOption:NSPropertyListImmutable + format:nil + errorDescription:nil]; +} + +- (void)setPlist:(id)plistObject forKey:(NSString*)key; { + [self setPlist:plistObject forKey:key withTimeoutInterval:self.defaultTimeoutInterval]; +} + +- (void)setPlist:(id)plistObject forKey:(NSString*)key withTimeoutInterval:(NSTimeInterval)timeoutInterval; { + // Binary plists are used over XML for better performance + NSData* plistData = [NSPropertyListSerialization dataFromPropertyList:plistObject + format:NSPropertyListBinaryFormat_v1_0 + errorDescription:NULL]; + + [self setData:plistData forKey:key withTimeoutInterval:timeoutInterval]; +} + +#pragma mark - +#pragma mark Disk writing operations + +- (void)performDiskWriteOperation:(NSInvocation *)invoction { + NSInvocationOperation *operation = [[NSInvocationOperation alloc] initWithInvocation:invoction]; + [diskOperationQueue addOperation:operation]; + [operation release]; +} + +#pragma mark - + +- (void)dealloc { + [diskOperationQueue release]; + [cacheDictionary release]; + [super dealloc]; +} + +@end \ No newline at end of file diff --git a/mac/TeamTalk/EGOImageLoader/EGOImageLoadConnection.h b/mac/TeamTalk/EGOImageLoader/EGOImageLoadConnection.h new file mode 100644 index 000000000..c0584ab67 --- /dev/null +++ b/mac/TeamTalk/EGOImageLoader/EGOImageLoadConnection.h @@ -0,0 +1,64 @@ +// +// EGOImageLoadConnection.h +// EGOImageLoading +// +// Created by Shaun Harrison on 12/1/09. +// Copyright (c) 2009-2010 enormego +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. +// + +#import + +@protocol EGOImageLoadConnectionDelegate; + +@interface EGOImageLoadConnection : NSObject { +@private + NSURL* _imageURL; + NSURLResponse* _response; + NSMutableData* _responseData; + NSURLConnection* _connection; + NSTimeInterval _timeoutInterval; + + id _delegate; +} + +- (id)initWithImageURL:(NSURL*)aURL delegate:(id)delegate; + +- (void)start; +- (void)cancel; + +@property(nonatomic,readonly) NSData* responseData; +@property(nonatomic,readonly,getter=imageURL) NSURL* imageURL; + +@property(nonatomic,retain) NSURLResponse* response; +@property(nonatomic,assign) id delegate; + +@property(nonatomic,assign) NSTimeInterval timeoutInterval; // Default is 30 seconds + +#if __EGOIL_USE_BLOCKS +@property(nonatomic,readonly) NSMutableDictionary* handlers; +#endif + +@end + +@protocol EGOImageLoadConnectionDelegate +- (void)imageLoadConnectionDidFinishLoading:(EGOImageLoadConnection *)connection; +- (void)imageLoadConnection:(EGOImageLoadConnection *)connection didFailWithError:(NSError *)error; +@end \ No newline at end of file diff --git a/mac/TeamTalk/EGOImageLoader/EGOImageLoadConnection.m b/mac/TeamTalk/EGOImageLoader/EGOImageLoadConnection.m new file mode 100644 index 000000000..badd428b5 --- /dev/null +++ b/mac/TeamTalk/EGOImageLoader/EGOImageLoadConnection.m @@ -0,0 +1,110 @@ +// +// EGOImageLoadConnection.m +// EGOImageLoading +// +// Created by Shaun Harrison on 12/1/09. +// Copyright (c) 2009-2010 enormego +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. +// + +#import "EGOImageLoadConnection.h" + + +@implementation EGOImageLoadConnection +@synthesize imageURL=_imageURL, response=_response, delegate=_delegate, timeoutInterval=_timeoutInterval; + +#if __EGOIL_USE_BLOCKS +@synthesize handlers; +#endif + +- (id)initWithImageURL:(NSURL*)aURL delegate:(id)delegate { + if((self = [super init])) { + _imageURL = [aURL retain]; + self.delegate = delegate; + _responseData = [[NSMutableData alloc] init]; + self.timeoutInterval = 30; + + #if __EGOIL_USE_BLOCKS + handlers = [[NSMutableDictionary alloc] init]; + #endif + } + + return self; +} + +- (void)start { + NSMutableURLRequest* request = [[NSMutableURLRequest alloc] initWithURL:self.imageURL + cachePolicy:NSURLRequestReturnCacheDataElseLoad + timeoutInterval:self.timeoutInterval]; + [request setValue:@"gzip" forHTTPHeaderField:@"Accept-Encoding"]; + _connection = [[NSURLConnection alloc] initWithRequest:request delegate:self startImmediately:YES]; + [request release]; +} + +- (void)cancel { + [_connection cancel]; +} + +- (NSData*)responseData { + return _responseData; +} + +- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data { + if(connection != _connection) return; + [_responseData appendData:data]; +} + +- (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response { + if(connection != _connection) return; + self.response = response; +} + +- (void)connectionDidFinishLoading:(NSURLConnection *)connection { + if(connection != _connection) return; + + if([self.delegate respondsToSelector:@selector(imageLoadConnectionDidFinishLoading:)]) { + [self.delegate imageLoadConnectionDidFinishLoading:self]; + } +} + +- (void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error { + if(connection != _connection) return; + + if([self.delegate respondsToSelector:@selector(imageLoadConnection:didFailWithError:)]) { + [self.delegate imageLoadConnection:self didFailWithError:error]; + } +} + + +- (void)dealloc { + self.response = nil; + self.delegate = nil; + + #if __EGOIL_USE_BLOCKS + [handlers release], handlers = nil; + #endif + + [_connection release]; + [_imageURL release]; + [_responseData release]; + [super dealloc]; +} + +@end diff --git a/mac/TeamTalk/EGOImageLoader/EGOImageLoader.h b/mac/TeamTalk/EGOImageLoader/EGOImageLoader.h new file mode 100644 index 000000000..398b60114 --- /dev/null +++ b/mac/TeamTalk/EGOImageLoader/EGOImageLoader.h @@ -0,0 +1,81 @@ +// +// EGOImageLoader.h +// EGOImageLoading +// +// Created by Shaun Harrison on 9/15/09. +// Copyright (c) 2009-2010 enormego +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. +// + +#import + +#ifndef __EGOIL_USE_BLOCKS +#define __EGOIL_USE_BLOCKS 1 +#endif + +#ifndef __EGOIL_USE_NOTIF +#define __EGOIL_USE_NOTIF 1 +#endif + +@protocol EGOImageLoaderObserver; +@interface EGOImageLoader : NSObject/**/ { +@private + NSDictionary* _currentConnections; + NSMutableDictionary* currentConnections; + #if __EGOIL_USE_BLOCKS + dispatch_queue_t _operationQueue; + #endif + + NSLock* connectionsLock; +} + ++ (EGOImageLoader*)sharedImageLoader; + +- (BOOL)isLoadingImageURL:(NSURL*)aURL; + +#if __EGOIL_USE_NOTIF +- (void)loadImageForURL:(NSURL*)aURL observer:(id)observer; +- (NSImage*)imageForURL:(NSURL*)aURL shouldLoadWithObserver:(id)observer; + +- (void)removeObserver:(id)observer; +- (void)removeObserver:(id)observer forURL:(NSURL*)aURL; +#endif + +#if __EGOIL_USE_BLOCKS +- (void)loadImageForURL:(NSURL*)aURL completion:(void (^)(NSImage* image, NSURL* imageURL, NSError* error))completion; +- (void)loadImageForURL:(NSURL*)aURL style:(NSString*)style styler:(NSImage* (^)(NSImage* image))styler completion:(void (^)(NSImage* image, NSURL* imageURL, NSError* error))completion; +#endif + +- (BOOL)hasLoadedImageURL:(NSURL*)aURL; +- (void)cancelLoadForURL:(NSURL*)aURL; + +- (void)clearCacheForURL:(NSURL*)aURL; +- (void)clearCacheForURL:(NSURL*)aURL style:(NSString*)style; +- (NSImage *)imageByURL:(NSString *)url; +- (NSString*)cachePathForURL:(NSURL*)url; + +@property(nonatomic,retain) NSDictionary* currentConnections; +@end + +@protocol EGOImageLoaderObserver +@optional +- (void)imageLoaderDidLoad:(NSNotification*)notification; // Object will be EGOImageLoader, userInfo will contain imageURL and image +- (void)imageLoaderDidFailToLoad:(NSNotification*)notification; // Object will be EGOImageLoader, userInfo will contain error +@end diff --git a/mac/TeamTalk/EGOImageLoader/EGOImageLoader.m b/mac/TeamTalk/EGOImageLoader/EGOImageLoader.m new file mode 100644 index 000000000..da11eee97 --- /dev/null +++ b/mac/TeamTalk/EGOImageLoader/EGOImageLoader.m @@ -0,0 +1,382 @@ +// +// EGOImageLoader.m +// EGOImageLoading +// +// Created by Shaun Harrison on 9/15/09. +// Copyright (c) 2009-2010 enormego +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. +// + +#import "EGOImageLoader.h" +#import "EGOImageLoadConnection.h" +#import "EGOCache.h" + +static EGOImageLoader* __imageLoader; + +inline static NSString* keyForURL(NSURL* url, NSString* style) { + + NSString* urlDescription = [url description]; + if ([urlDescription isEqualToString:@""]) + { + return [NSString stringWithFormat:@"DDImageLoader-%lu.png", [urlDescription hash]]; + } + NSRange firstPoint = [urlDescription rangeOfString:@"." options:0 range:NSMakeRange(0, 15)]; + NSString* correctURLKey = [urlDescription substringFromIndex:firstPoint.location]; + + if(style) { + return [NSString stringWithFormat:@"DDImageLoader-%lu-%lu.png", [correctURLKey hash], [style hash]]; + } else { + return [NSString stringWithFormat:@"DDImageLoader-%lu.png", [correctURLKey hash]]; + + } +} + +#if __EGOIL_USE_BLOCKS + #define kNoStyle @"EGOImageLoader-nostyle" + #define kCompletionsKey @"completions" + #define kStylerKey @"styler" + #define kStylerQueue _operationQueue + #define kCompletionsQueue dispatch_get_main_queue() +#endif + +#if __EGOIL_USE_NOTIF + #define kImageNotificationLoaded(s) [@"kEGOImageLoaderNotificationLoaded-" stringByAppendingString:keyForURL(s, nil)] + #define kImageNotificationLoadFailed(s) [@"kEGOImageLoaderNotificationLoadFailed-" stringByAppendingString:keyForURL(s, nil)] +#endif + +@interface EGOImageLoader () +#if __EGOIL_USE_BLOCKS +- (void)handleCompletionsForConnection:(EGOImageLoadConnection*)connection image:(NSImage*)image error:(NSError*)error; +#endif +@end + +@implementation EGOImageLoader +@synthesize currentConnections=_currentConnections; + ++ (EGOImageLoader*)sharedImageLoader { + @synchronized(self) { + if(!__imageLoader) { + __imageLoader = [[[self class] alloc] init]; + } + } + + return __imageLoader; +} + +- (id)init { + if((self = [super init])) { + connectionsLock = [[NSLock alloc] init]; + currentConnections = [[NSMutableDictionary alloc] init]; + + #if __EGOIL_USE_BLOCKS + _operationQueue = dispatch_queue_create("com.mogujie.DDImageLoader",NULL); + dispatch_queue_t priority = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH,0); + dispatch_set_target_queue(priority, _operationQueue); + #endif + } + return self; +} + +- (EGOImageLoadConnection*)loadingConnectionForURL:(NSURL*)aURL { + EGOImageLoadConnection* connection = [[self.currentConnections objectForKey:aURL] retain]; + if(!connection) return nil; + else return [connection autorelease]; +} + +- (void)cleanUpConnection:(EGOImageLoadConnection*)connection { + if(!connection.imageURL) return; + + connection.delegate = nil; + + [connectionsLock lock]; + [currentConnections removeObjectForKey:connection.imageURL]; + self.currentConnections = [[currentConnections copy] autorelease]; + [connectionsLock unlock]; +} + +- (void)clearCacheForURL:(NSURL*)aURL { + [self clearCacheForURL:aURL style:nil]; +} + +- (void)clearCacheForURL:(NSURL*)aURL style:(NSString*)style { + [[EGOCache currentCache] removeCacheForKey:keyForURL(aURL, style)]; +} + +-(NSImage *)imageByURL:(NSString *)url{ + NSImage *image = [self imageForURL:[NSURL URLWithString:url] shouldLoadWithObserver:nil]; + if (!image) { + image=[NSImage imageNamed:@"avatar_default.jpg_48x48"]; + } + return image; +} + +- (NSString*)cachePathForURL:(NSURL*)url +{ + + NSString* key = keyForURL(url, nil); + return [[EGOCache currentCache]cachePathForKey:key]; +} + +- (BOOL)isLoadingImageURL:(NSURL*)aURL { + return [self loadingConnectionForURL:aURL] ? YES : NO; +} + +- (void)cancelLoadForURL:(NSURL*)aURL { + EGOImageLoadConnection* connection = [self loadingConnectionForURL:aURL]; + [NSObject cancelPreviousPerformRequestsWithTarget:connection selector:@selector(start) object:nil]; + [connection cancel]; + [self cleanUpConnection:connection]; +} + +- (EGOImageLoadConnection*)loadImageForURL:(NSURL*)aURL { + EGOImageLoadConnection* connection; + + + + if((connection = [self loadingConnectionForURL:aURL])) { + return connection; + } else { + connection = [[EGOImageLoadConnection alloc] initWithImageURL:aURL delegate:self]; + + [connectionsLock lock]; + [currentConnections setObject:connection forKey:aURL]; + self.currentConnections = [[currentConnections copy] autorelease]; + [connectionsLock unlock]; + [connection performSelector:@selector(start) withObject:nil afterDelay:0.01]; + [connection release]; + + return connection; + } +} + +#if __EGOIL_USE_NOTIF +- (void)loadImageForURL:(NSURL*)aURL observer:(id)observer { + if(!aURL) return; + + if([observer respondsToSelector:@selector(imageLoaderDidLoad:)]) { + [[NSNotificationCenter defaultCenter] addObserver:observer selector:@selector(imageLoaderDidLoad:) name:kImageNotificationLoaded(aURL) object:self]; + } + + if([observer respondsToSelector:@selector(imageLoaderDidFailToLoad:)]) { + [[NSNotificationCenter defaultCenter] addObserver:observer selector:@selector(imageLoaderDidFailToLoad:) name:kImageNotificationLoadFailed(aURL) object:self]; + } + + [self loadImageForURL:aURL]; +} + +- (NSImage*)imageForURL:(NSURL*)aURL shouldLoadWithObserver:(id)observer { + if(!aURL) return nil; + /* + 1.本地找得到图片.直接返回图片 + 2.本地缓存找不到图片,远程加载. + */ + + NSImage* anImage = [[EGOCache currentCache] imageForKey:keyForURL(aURL,nil)]; + + if(anImage) { + return anImage; + } else { + [self loadImageForURL:aURL observer:observer]; + return nil; + } +} + +-(NSString *)imageLocalPathForURL:(NSURL*)aURL shouldLoadWithObserver:(id)observer { + if(!aURL) return nil; + NSString *localPath=[[EGOCache currentCache] pathForKey:keyForURL(aURL,nil)]; + + if(localPath) { + return localPath; + } else { + [self loadImageForURL:aURL observer:observer]; + return nil; + } +} + + +- (void)removeObserver:(id)observer { + [[NSNotificationCenter defaultCenter] removeObserver:observer name:nil object:self]; +} + +- (void)removeObserver:(id)observer forURL:(NSURL*)aURL { + [[NSNotificationCenter defaultCenter] removeObserver:observer name:kImageNotificationLoaded(aURL) object:self]; + [[NSNotificationCenter defaultCenter] removeObserver:observer name:kImageNotificationLoadFailed(aURL) object:self]; +} + +#endif + +#if __EGOIL_USE_BLOCKS +- (void)loadImageForURL:(NSURL*)aURL completion:(void (^)(NSImage* image, NSURL* imageURL, NSError* error))completion { + [self loadImageForURL:aURL style:nil styler:nil completion:completion]; +} + +- (void)loadImageForURL:(NSURL*)aURL style:(NSString*)style styler:(NSImage* (^)(NSImage* image))styler completion:(void (^)(NSImage* image, NSURL* imageURL, NSError* error))completion { + NSImage* anImage = [[EGOCache currentCache] imageForKey:keyForURL(aURL,style)]; + + if(anImage) { + completion(anImage, aURL, nil); + } else if(!anImage && styler && style && (anImage = [[EGOCache currentCache] imageForKey:keyForURL(aURL,nil)])) { + dispatch_async(kStylerQueue, ^{ + NSImage* image = styler(anImage); + [[EGOCache currentCache] setImage:image forKey:keyForURL(aURL, style) withTimeoutInterval:604800]; + dispatch_async(kCompletionsQueue, ^{ + completion(image, aURL, nil); + }); + }); + } else { + EGOImageLoadConnection* connection = [self loadImageForURL:aURL]; + void (^completionCopy)(NSImage* image, NSURL* imageURL, NSError* error) = [completion copy]; + + NSString* handlerKey = style ? style : kNoStyle; + NSMutableDictionary* handler = [connection.handlers objectForKey:handlerKey]; + + if(!handler) { + handler = [[NSMutableDictionary alloc] initWithCapacity:2]; + [connection.handlers setObject:handler forKey:handlerKey]; + + [handler setObject:[NSMutableArray arrayWithCapacity:1] forKey:kCompletionsKey]; + if(styler) { + NSImage* (^stylerCopy)(NSImage* image) = [styler copy]; + [handler setObject:stylerCopy forKey:kStylerKey]; + [stylerCopy release]; + } + + [handler release]; + } + + [[handler objectForKey:kCompletionsKey] addObject:completionCopy]; + [completionCopy release]; + } +} +#endif + +- (BOOL)hasLoadedImageURL:(NSURL*)aURL { + return [[EGOCache currentCache] hasCacheForKey:keyForURL(aURL,nil)]; +} + +#pragma mark - +#pragma mark URL Connection delegate methods + +- (void)imageLoadConnectionDidFinishLoading:(EGOImageLoadConnection *)connection { + NSImage *anImage = [[NSImage alloc] initWithData:connection.responseData]; + //NSImage* anImage = [NSImage imageWithData:connection.responseData]; + + if(!anImage) { + NSError* error = [NSError errorWithDomain:[connection.imageURL host] code:406 userInfo:nil]; + + #if __EGOIL_USE_NOTIF + NSNotification* notification = [NSNotification notificationWithName:kImageNotificationLoadFailed(connection.imageURL) + object:self + userInfo:[NSDictionary dictionaryWithObjectsAndKeys:error,@"error",connection.imageURL,@"imageURL",nil]]; + + [[NSNotificationCenter defaultCenter] performSelectorOnMainThread:@selector(postNotification:) withObject:notification waitUntilDone:YES]; + #endif + + #if __EGOIL_USE_BLOCKS + [self handleCompletionsForConnection:connection image:nil error:error]; + #endif + } else { + [[EGOCache currentCache] setData:connection.responseData forKey:keyForURL(connection.imageURL,nil) withTimeoutInterval:604800]; + + [currentConnections removeObjectForKey:connection.imageURL]; + self.currentConnections = [[currentConnections copy] autorelease]; + + #if __EGOIL_USE_NOTIF + NSNotification* notification = [NSNotification notificationWithName:kImageNotificationLoaded(connection.imageURL) + object:self + userInfo:[NSDictionary dictionaryWithObjectsAndKeys:anImage,@"image",connection.imageURL,@"imageURL",nil]]; + + [[NSNotificationCenter defaultCenter] performSelectorOnMainThread:@selector(postNotification:) withObject:notification waitUntilDone:YES]; + + #endif + + #if __EGOIL_USE_BLOCKS + [self handleCompletionsForConnection:connection image:anImage error:nil]; + #endif + } + + [anImage release]; + + [self cleanUpConnection:connection]; +} + +- (void)imageLoadConnection:(EGOImageLoadConnection *)connection didFailWithError:(NSError *)error { + [currentConnections removeObjectForKey:connection.imageURL]; + self.currentConnections = [[currentConnections copy] autorelease]; + + #if __EGOIL_USE_NOTIF + NSNotification* notification = [NSNotification notificationWithName:kImageNotificationLoadFailed(connection.imageURL) + object:self + userInfo:[NSDictionary dictionaryWithObjectsAndKeys:error,@"error",connection.imageURL,@"imageURL",nil]]; + + [[NSNotificationCenter defaultCenter] performSelectorOnMainThread:@selector(postNotification:) withObject:notification waitUntilDone:YES]; + #endif + + #if __EGOIL_USE_BLOCKS + [self handleCompletionsForConnection:connection image:nil error:error]; + #endif + + [self cleanUpConnection:connection]; +} + +#if __EGOIL_USE_BLOCKS +- (void)handleCompletionsForConnection:(EGOImageLoadConnection*)connection image:(NSImage*)image error:(NSError*)error { + if([connection.handlers count] == 0) return; + + NSURL* imageURL = connection.imageURL; + + void (^callCompletions)(NSImage* anImage, NSArray* completions) = ^(NSImage* anImage, NSArray* completions) { + dispatch_async(kCompletionsQueue, ^{ + for(void (^completion)(NSImage* image, NSURL* imageURL, NSError* error) in completions) { + completion(anImage, connection.imageURL, error); + } + }); + }; + + for(NSString* styleKey in connection.handlers) { + NSDictionary* handler = [connection.handlers objectForKey:styleKey]; + NSImage* (^styler)(NSImage* image) = [handler objectForKey:kStylerKey]; + if(!error && image && styler) { + dispatch_async(kStylerQueue, ^{ + NSImage* anImage = styler(image); + [[EGOCache currentCache] setImage:anImage forKey:keyForURL(imageURL, styleKey) withTimeoutInterval:604800]; + callCompletions(anImage, [handler objectForKey:kCompletionsKey]); + }); + } else { + callCompletions(image, [handler objectForKey:kCompletionsKey]); + } + } +} +#endif + +#pragma mark - + +- (void)dealloc { + #if __EGOIL_USE_BLOCKS + dispatch_release(_operationQueue), _operationQueue = nil; + #endif + + self.currentConnections = nil; + [currentConnections release], currentConnections = nil; + [connectionsLock release], connectionsLock = nil; + [super dealloc]; +} + +@end \ No newline at end of file diff --git a/mac/TeamTalk/EGOImageLoader/EGOImageView.h b/mac/TeamTalk/EGOImageLoader/EGOImageView.h new file mode 100644 index 000000000..500d60630 --- /dev/null +++ b/mac/TeamTalk/EGOImageLoader/EGOImageView.h @@ -0,0 +1,58 @@ +// +// EGOImageView.h +// EGOImageLoading +// +// Created by Shaun Harrison on 9/15/09. +// Copyright (c) 2009-2010 enormego +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. +// + +#import +#import "EGOImageLoader.h" + +@protocol EGOImageViewDelegate; +@interface EGOImageView : NSImageView { +@private + NSURL* imageURL; + NSImage* placeholderImage; + id delegate; + NSInteger onlineState; + NSUInteger imageIndex; + NSString *fromUserId; +} + +- (id)initWithPlaceholderImage:(NSImage*)anImage; // delegate:nil +- (id)initWithPlaceholderImage:(NSImage*)anImage delegate:(id)aDelegate; +@property(nonatomic,retain) NSURL* imageURL; +@property(nonatomic,retain) NSImage* placeholderImage; +@property(nonatomic,assign) id delegate; +@property(nonatomic)NSInteger onlineState; +@property (nonatomic,retain) NSString *fromUserId; +@property NSUInteger imageIndex; +-(NSString *)imageLocalPath; + +- (void)loadImageWithURL:(NSURL*)url setplaceholderImage:(NSString*)placeholderImage; +@end + +@protocol EGOImageViewDelegate +@optional +- (void)imageViewLoadedImage:(EGOImageView*)imageView; +- (void)imageViewFailedToLoadImage:(EGOImageView*)imageView error:(NSError*)error; +@end \ No newline at end of file diff --git a/mac/TeamTalk/EGOImageLoader/EGOImageView.m b/mac/TeamTalk/EGOImageLoader/EGOImageView.m new file mode 100644 index 000000000..09470918d --- /dev/null +++ b/mac/TeamTalk/EGOImageLoader/EGOImageView.m @@ -0,0 +1,298 @@ +// +// EGOImageView.m +// EGOImageLoading +// +// Created by Shaun Harrison on 9/15/09. +// Copyright (c) 2009-2010 enormego +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. +// + +#import "EGOImageView.h" +#import "EGOImageLoader.h" +#import "MTUserEntity.h" +#import "EGOCache.h" + + +@implementation EGOImageView +@synthesize imageURL, placeholderImage, delegate,onlineState,imageIndex,fromUserId; + +- (id)initWithPlaceholderImage:(NSImage*)anImage { + return [self initWithPlaceholderImage:anImage delegate:nil]; +} + +- (id)initWithPlaceholderImage:(NSImage*)anImage delegate:(id)aDelegate { + if(self = [super init]) { + self.placeholderImage = anImage; + self.delegate = aDelegate; + onlineState = UserStatTypeUserStatusOffline ; + imageIndex=0; + } + + return self; +} + + +- (void)setImageURL:(NSURL *)aURL { + if(imageURL) { + [[EGOImageLoader sharedImageLoader] removeObserver:self forURL:imageURL]; + [imageURL release]; + imageURL = nil; + } + + if(!aURL) { + if(UserStatTypeUserStatusOffline==onlineState && self.placeholderImage){ + //先不用灰色处理 + // self.image = GrayImageFromNSImageWithAlpha(self.placeholderImage); + self.image = self.placeholderImage; + }else{ + self.image = self.placeholderImage; + } + + imageURL = nil; + return; + } else { + imageURL = [aURL retain]; + } + + [[EGOImageLoader sharedImageLoader] removeObserver:self]; + NSImage* anImage = [[EGOImageLoader sharedImageLoader] imageForURL:aURL shouldLoadWithObserver:self]; + + if(anImage) { + if(UserStatTypeUserStatusOffline==onlineState){ + // self.image = GrayImageFromNSImageWithAlpha(anImage); + self.image = anImage; + }else{ + self.image = anImage; + } + + // trigger the delegate callback if the image was found in the cache + if([self.delegate respondsToSelector:@selector(imageViewLoadedImage:)]) { + [self.delegate imageViewLoadedImage:self]; + } + } else { + if(UserStatTypeUserStatusOffline==onlineState){ + //self.image = GrayImageFromNSImageWithAlpha(self.placeholderImage); + self.image = self.placeholderImage; + }else{ + self.image = self.placeholderImage; + } + } +} + +#pragma mark - +#pragma mark Image loading + +- (void)cancelImageLoad { + [[EGOImageLoader sharedImageLoader] cancelLoadForURL:self.imageURL]; + [[EGOImageLoader sharedImageLoader] removeObserver:self forURL:self.imageURL]; +} + +- (void)imageLoaderDidLoad:(NSNotification*)notification { + + /* + NSNotification* notification = [NSNotification notificationWithName:kImageNotificationLoaded(connection.imageURL) + object:self + userInfo:[NSDictionary dictionaryWithObjectsAndKeys:anImage,@"image",connection.imageURL,@"imageURL",nil]]; + */ + if(![[[notification userInfo] objectForKey:@"imageURL"] isEqual:self.imageURL]) return; + + NSImage* anImage = [[notification userInfo] objectForKey:@"image"]; + // NSString *imageURL =[[notification userInfo] objectForKey:@"imageURL"]; + if(UserStatTypeUserStatusOffline==onlineState){ + // self.image = GrayImageFromNSImageWithAlpha(anImage); + self.image = anImage; + }else{ + self.image = anImage; + } + [self setNeedsDisplay]; + + if([self.delegate respondsToSelector:@selector(imageViewLoadedImage:)]) { + [self.delegate imageViewLoadedImage:self]; + } +} + +- (void)imageLoaderDidFailToLoad:(NSNotification*)notification { + if(![[[notification userInfo] objectForKey:@"imageURL"] isEqual:self.imageURL]) return; + + if([self.delegate respondsToSelector:@selector(imageViewFailedToLoadImage:error:)]) { + [self.delegate imageViewFailedToLoadImage:self error:[[notification userInfo] objectForKey:@"error"]]; + } +} + +-(NSString *)imageLocalPath{ + NSString *urlDescription =[imageURL description]; + NSRange firstPoint = [urlDescription rangeOfString:@"." options:0 range:NSMakeRange(0, 15)]; + NSString* correctURLKey = [urlDescription substringFromIndex:firstPoint.location]; + + NSString *localPath=[[EGOCache currentCache] pathForKey:[NSString stringWithFormat:@"DDImageLoader-%lu.png", [correctURLKey hash]]]; + return localPath; +} + +- (void)loadImageWithURL:(NSURL*)url setplaceholderImage:(NSString*)placeholderImageName +{ + if ([[url description] length] == 0) + { + [self setImage:[NSImage imageNamed:placeholderImageName]]; + } + else + { + [self setPlaceholderImage:[NSImage imageNamed:placeholderImageName]]; + [self setImageURL:url]; + } +} + +#pragma mark - +- (void)dealloc { + [[EGOImageLoader sharedImageLoader] removeObserver:self]; + self.delegate = nil; + self.imageURL = nil; + self.placeholderImage = nil; + self.fromUserId=nil; + [super dealloc]; +} + + +/////////////////////////////////////////// + +#pragma mark - +#pragma mark image grey + + +CGImageRef CGImageRefCopyFromNSImage(NSImage* image) +{ + NSSize size = [image size]; + if(size.width == 0 || size.height ==0) + { + NSBitmapImageRep * rep = [NSBitmapImageRep imageRepWithData:[image TIFFRepresentation]]; + NSSize imgSize = NSMakeSize([rep pixelsWide],[rep pixelsHigh]); + [image setSize:imgSize]; + } + + NSData * imageData = [image TIFFRepresentation]; + CGImageRef imageRef = nil; + if(imageData) + { + CGImageSourceRef imageSource = CGImageSourceCreateWithData((__bridge CFDataRef)(imageData), NULL); //need release + imageRef = CGImageSourceCreateImageAtIndex( imageSource, 0, NULL); //need release by caller + + CFRelease(imageSource); + } + + return imageRef; + +} + +CGImageRef SourceDataImageRefCopyFromCGImageRef(CGImageRef img) +{ + CGColorSpaceRef colorspace = NULL; + CGContextRef context = NULL; + + colorspace = CGColorSpaceCreateDeviceGray(); //need release + size_t pixelsWide = CGImageGetWidth(img); + size_t pixelsHigh = CGImageGetHeight(img); + //int bitmapBytesPerRow = pixelsWide * (enableAlaph ? 4 : 1); + size_t bitmapBytesPerRow = pixelsWide; + + context = CGBitmapContextCreate(NULL, + pixelsWide, + pixelsHigh, + 8, + bitmapBytesPerRow, + colorspace, + kCGImageAlphaNone); //need release + + CGRect rect = {{0, 0}, {pixelsWide, pixelsHigh}}; + CGContextDrawImage(context, rect, img); + + CGImageRef test = CGBitmapContextCreateImage(context) ; //need release out + + CGColorSpaceRelease(colorspace); + CGContextRelease(context); + return test; +} + +CGImageRef AlphaDataImageRefCopyFromCGImageRef(CGImageRef img) +{ + CGContextRef context = NULL; + + size_t pixelsWide = CGImageGetWidth(img); + size_t pixelsHigh = CGImageGetHeight(img); + //int bitmapBytesPerRow = pixelsWide * (enableAlaph ? 4 : 1); + size_t bitmapBytesPerRow = pixelsWide ; + + context = CGBitmapContextCreate(NULL, + pixelsWide, + pixelsHigh, + 8, + bitmapBytesPerRow, + NULL, + kCGImageAlphaOnly); //need release + + CGRect rect = {{0, 0}, {pixelsWide, pixelsHigh}}; + CGContextDrawImage(context, rect, img); + + CGImageRef test = CGBitmapContextCreateImage(context) ; //need release out + CGContextRelease(context); + return test; +} + + +NSImage* GrayImageFromNSImageWithAlpha(NSImage*image) +{ + CGImageRef inImage = CGImageRefCopyFromNSImage(image); //need release + CGImageRef imgSourceData = SourceDataImageRefCopyFromCGImageRef(inImage);//need release + CGImageRef imgAlphaData = AlphaDataImageRefCopyFromCGImageRef(inImage);//need release + + CGImageRef imgResultData = CGImageCreateWithMask(imgSourceData, imgAlphaData);//need release + + NSImage *imgResult = nsImageFromCGImageRef(imgResultData); + + CGImageRelease(inImage); + CGImageRelease(imgSourceData); + CGImageRelease(imgAlphaData); + CGImageRelease(imgResultData); + + return imgResult; +} + +NSImage* nsImageFromCGImageRef(CGImageRef image) +{ + NSRect imageRect = NSMakeRect(0.0, 0.0, 0.0, 0.0); + CGContextRef imageContext = nil; + NSImage* newImage = nil; + // Get the image dimensions. + imageRect.size.height = CGImageGetHeight(image); + imageRect.size.width = CGImageGetWidth(image); + // Create a new image to receive the Quartz image data. + if(imageRect.size.height ==0 ||imageRect.size.width ==0) + { + DDLog(@"nsImageFromCGImageRef should not be here!!!,CGImageRef is %@",image); + } + newImage = [[NSImage alloc] initWithSize:imageRect.size]; + [newImage lockFocus]; + // Get the Quartz context and draw. + imageContext = (CGContextRef)[[NSGraphicsContext currentContext] + graphicsPort]; + CGContextDrawImage(imageContext, *(CGRect*)&imageRect, image); + [newImage unlockFocus]; + return newImage; +} + +@end diff --git a/mac/TeamTalk/FileTransfer/GCDAsyncSocket.h b/mac/TeamTalk/FileTransfer/GCDAsyncSocket.h new file mode 100644 index 000000000..cf9927f77 --- /dev/null +++ b/mac/TeamTalk/FileTransfer/GCDAsyncSocket.h @@ -0,0 +1,1074 @@ +// +// GCDAsyncSocket.h +// +// This class is in the public domain. +// Originally created by Robbie Hanson in Q3 2010. +// Updated and maintained by Deusty LLC and the Apple development community. +// +// https://github.com/robbiehanson/CocoaAsyncSocket +// + +#import +#import +#import +#import + +@class GCDAsyncReadPacket; +@class GCDAsyncWritePacket; +@class GCDAsyncSocketPreBuffer; + +#if TARGET_OS_IPHONE + + // Compiling for iOS + + #if __IPHONE_OS_VERSION_MAX_ALLOWED >= 50000 // iOS 5.0 supported + + #if __IPHONE_OS_VERSION_MIN_REQUIRED >= 50000 // iOS 5.0 supported and required + + #define IS_SECURE_TRANSPORT_AVAILABLE YES + #define SECURE_TRANSPORT_MAYBE_AVAILABLE 1 + #define SECURE_TRANSPORT_MAYBE_UNAVAILABLE 0 + + #else // iOS 5.0 supported but not required + + #ifndef NSFoundationVersionNumber_iPhoneOS_5_0 + #define NSFoundationVersionNumber_iPhoneOS_5_0 881.00 + #endif + + #define IS_SECURE_TRANSPORT_AVAILABLE (NSFoundationVersionNumber >= NSFoundationVersionNumber_iPhoneOS_5_0) + #define SECURE_TRANSPORT_MAYBE_AVAILABLE 1 + #define SECURE_TRANSPORT_MAYBE_UNAVAILABLE 1 + + #endif + + #else // iOS 5.0 not supported + + #define IS_SECURE_TRANSPORT_AVAILABLE NO + #define SECURE_TRANSPORT_MAYBE_AVAILABLE 0 + #define SECURE_TRANSPORT_MAYBE_UNAVAILABLE 1 + + #endif + +#else + + // Compiling for Mac OS X + + #define IS_SECURE_TRANSPORT_AVAILABLE YES + #define SECURE_TRANSPORT_MAYBE_AVAILABLE 1 + #define SECURE_TRANSPORT_MAYBE_UNAVAILABLE 0 + +#endif + +extern NSString *const GCDAsyncSocketException; +extern NSString *const GCDAsyncSocketErrorDomain; + +extern NSString *const GCDAsyncSocketQueueName; +extern NSString *const GCDAsyncSocketThreadName; + +#if SECURE_TRANSPORT_MAYBE_AVAILABLE +extern NSString *const GCDAsyncSocketSSLCipherSuites; +#if TARGET_OS_IPHONE +extern NSString *const GCDAsyncSocketSSLProtocolVersionMin; +extern NSString *const GCDAsyncSocketSSLProtocolVersionMax; +#else +extern NSString *const GCDAsyncSocketSSLDiffieHellmanParameters; +#endif +#endif + +enum GCDAsyncSocketError +{ + GCDAsyncSocketNoError = 0, // Never used + GCDAsyncSocketBadConfigError, // Invalid configuration + GCDAsyncSocketBadParamError, // Invalid parameter was passed + GCDAsyncSocketConnectTimeoutError, // A connect operation timed out + GCDAsyncSocketReadTimeoutError, // A read operation timed out + GCDAsyncSocketWriteTimeoutError, // A write operation timed out + GCDAsyncSocketReadMaxedOutError, // Reached set maxLength without completing + GCDAsyncSocketClosedError, // The remote peer closed the connection + GCDAsyncSocketOtherError, // Description provided in userInfo +}; +typedef enum GCDAsyncSocketError GCDAsyncSocketError; + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +#pragma mark - +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +@interface GCDAsyncSocket : NSObject + +/** + * GCDAsyncSocket uses the standard delegate paradigm, + * but executes all delegate callbacks on a given delegate dispatch queue. + * This allows for maximum concurrency, while at the same time providing easy thread safety. + * + * You MUST set a delegate AND delegate dispatch queue before attempting to + * use the socket, or you will get an error. + * + * The socket queue is optional. + * If you pass NULL, GCDAsyncSocket will automatically create it's own socket queue. + * If you choose to provide a socket queue, the socket queue must not be a concurrent queue. + * If you choose to provide a socket queue, and the socket queue has a configured target queue, + * then please see the discussion for the method markSocketQueueTargetQueue. + * + * The delegate queue and socket queue can optionally be the same. +**/ +- (id)init; +- (id)initWithSocketQueue:(dispatch_queue_t)sq; +- (id)initWithDelegate:(id)aDelegate delegateQueue:(dispatch_queue_t)dq; +- (id)initWithDelegate:(id)aDelegate delegateQueue:(dispatch_queue_t)dq socketQueue:(dispatch_queue_t)sq; + +#pragma mark Configuration + +- (id)delegate; +- (void)setDelegate:(id)delegate; +- (void)synchronouslySetDelegate:(id)delegate; + +- (dispatch_queue_t)delegateQueue; +- (void)setDelegateQueue:(dispatch_queue_t)delegateQueue; +- (void)synchronouslySetDelegateQueue:(dispatch_queue_t)delegateQueue; + +- (void)getDelegate:(id *)delegatePtr delegateQueue:(dispatch_queue_t *)delegateQueuePtr; +- (void)setDelegate:(id)delegate delegateQueue:(dispatch_queue_t)delegateQueue; +- (void)synchronouslySetDelegate:(id)delegate delegateQueue:(dispatch_queue_t)delegateQueue; + +/** + * By default, both IPv4 and IPv6 are enabled. + * + * For accepting incoming connections, this means GCDAsyncSocket automatically supports both protocols, + * and can simulataneously accept incoming connections on either protocol. + * + * For outgoing connections, this means GCDAsyncSocket can connect to remote hosts running either protocol. + * If a DNS lookup returns only IPv4 results, GCDAsyncSocket will automatically use IPv4. + * If a DNS lookup returns only IPv6 results, GCDAsyncSocket will automatically use IPv6. + * If a DNS lookup returns both IPv4 and IPv6 results, the preferred protocol will be chosen. + * By default, the preferred protocol is IPv4, but may be configured as desired. +**/ +- (BOOL)isIPv4Enabled; +- (void)setIPv4Enabled:(BOOL)flag; + +- (BOOL)isIPv6Enabled; +- (void)setIPv6Enabled:(BOOL)flag; + +- (BOOL)isIPv4PreferredOverIPv6; +- (void)setPreferIPv4OverIPv6:(BOOL)flag; + +/** + * User data allows you to associate arbitrary information with the socket. + * This data is not used internally by socket in any way. +**/ +- (id)userData; +- (void)setUserData:(id)arbitraryUserData; + +#pragma mark Accepting + +/** + * Tells the socket to begin listening and accepting connections on the given port. + * When a connection is accepted, a new instance of GCDAsyncSocket will be spawned to handle it, + * and the socket:didAcceptNewSocket: delegate method will be invoked. + * + * The socket will listen on all available interfaces (e.g. wifi, ethernet, etc) +**/ +- (BOOL)acceptOnPort:(uint16_t)port error:(NSError **)errPtr; + +/** + * This method is the same as acceptOnPort:error: with the + * additional option of specifying which interface to listen on. + * + * For example, you could specify that the socket should only accept connections over ethernet, + * and not other interfaces such as wifi. + * + * The interface may be specified by name (e.g. "en1" or "lo0") or by IP address (e.g. "192.168.4.34"). + * You may also use the special strings "localhost" or "loopback" to specify that + * the socket only accept connections from the local machine. + * + * You can see the list of interfaces via the command line utility "ifconfig", + * or programmatically via the getifaddrs() function. + * + * To accept connections on any interface pass nil, or simply use the acceptOnPort:error: method. +**/ +- (BOOL)acceptOnInterface:(NSString *)interface port:(uint16_t)port error:(NSError **)errPtr; + +#pragma mark Connecting + +/** + * Connects to the given host and port. + * + * This method invokes connectToHost:onPort:viaInterface:withTimeout:error: + * and uses the default interface, and no timeout. +**/ +- (BOOL)connectToHost:(NSString *)host onPort:(uint16_t)port error:(NSError **)errPtr; + +/** + * Connects to the given host and port with an optional timeout. + * + * This method invokes connectToHost:onPort:viaInterface:withTimeout:error: and uses the default interface. +**/ +- (BOOL)connectToHost:(NSString *)host + onPort:(uint16_t)port + withTimeout:(NSTimeInterval)timeout + error:(NSError **)errPtr; + +/** + * Connects to the given host & port, via the optional interface, with an optional timeout. + * + * The host may be a domain name (e.g. "deusty.com") or an IP address string (e.g. "192.168.0.2"). + * The host may also be the special strings "localhost" or "loopback" to specify connecting + * to a service on the local machine. + * + * The interface may be a name (e.g. "en1" or "lo0") or the corresponding IP address (e.g. "192.168.4.35"). + * The interface may also be used to specify the local port (see below). + * + * To not time out use a negative time interval. + * + * This method will return NO if an error is detected, and set the error pointer (if one was given). + * Possible errors would be a nil host, invalid interface, or socket is already connected. + * + * If no errors are detected, this method will start a background connect operation and immediately return YES. + * The delegate callbacks are used to notify you when the socket connects, or if the host was unreachable. + * + * Since this class supports queued reads and writes, you can immediately start reading and/or writing. + * All read/write operations will be queued, and upon socket connection, + * the operations will be dequeued and processed in order. + * + * The interface may optionally contain a port number at the end of the string, separated by a colon. + * This allows you to specify the local port that should be used for the outgoing connection. (read paragraph to end) + * To specify both interface and local port: "en1:8082" or "192.168.4.35:2424". + * To specify only local port: ":8082". + * Please note this is an advanced feature, and is somewhat hidden on purpose. + * You should understand that 99.999% of the time you should NOT specify the local port for an outgoing connection. + * If you think you need to, there is a very good chance you have a fundamental misunderstanding somewhere. + * Local ports do NOT need to match remote ports. In fact, they almost never do. + * This feature is here for networking professionals using very advanced techniques. +**/ +- (BOOL)connectToHost:(NSString *)host + onPort:(uint16_t)port + viaInterface:(NSString *)interface + withTimeout:(NSTimeInterval)timeout + error:(NSError **)errPtr; + +/** + * Connects to the given address, specified as a sockaddr structure wrapped in a NSData object. + * For example, a NSData object returned from NSNetService's addresses method. + * + * If you have an existing struct sockaddr you can convert it to a NSData object like so: + * struct sockaddr sa -> NSData *dsa = [NSData dataWithBytes:&remoteAddr length:remoteAddr.sa_len]; + * struct sockaddr *sa -> NSData *dsa = [NSData dataWithBytes:remoteAddr length:remoteAddr->sa_len]; + * + * This method invokes connectToAdd +**/ +- (BOOL)connectToAddress:(NSData *)remoteAddr error:(NSError **)errPtr; + +/** + * This method is the same as connectToAddress:error: with an additional timeout option. + * To not time out use a negative time interval, or simply use the connectToAddress:error: method. +**/ +- (BOOL)connectToAddress:(NSData *)remoteAddr withTimeout:(NSTimeInterval)timeout error:(NSError **)errPtr; + +/** + * Connects to the given address, using the specified interface and timeout. + * + * The address is specified as a sockaddr structure wrapped in a NSData object. + * For example, a NSData object returned from NSNetService's addresses method. + * + * If you have an existing struct sockaddr you can convert it to a NSData object like so: + * struct sockaddr sa -> NSData *dsa = [NSData dataWithBytes:&remoteAddr length:remoteAddr.sa_len]; + * struct sockaddr *sa -> NSData *dsa = [NSData dataWithBytes:remoteAddr length:remoteAddr->sa_len]; + * + * The interface may be a name (e.g. "en1" or "lo0") or the corresponding IP address (e.g. "192.168.4.35"). + * The interface may also be used to specify the local port (see below). + * + * The timeout is optional. To not time out use a negative time interval. + * + * This method will return NO if an error is detected, and set the error pointer (if one was given). + * Possible errors would be a nil host, invalid interface, or socket is already connected. + * + * If no errors are detected, this method will start a background connect operation and immediately return YES. + * The delegate callbacks are used to notify you when the socket connects, or if the host was unreachable. + * + * Since this class supports queued reads and writes, you can immediately start reading and/or writing. + * All read/write operations will be queued, and upon socket connection, + * the operations will be dequeued and processed in order. + * + * The interface may optionally contain a port number at the end of the string, separated by a colon. + * This allows you to specify the local port that should be used for the outgoing connection. (read paragraph to end) + * To specify both interface and local port: "en1:8082" or "192.168.4.35:2424". + * To specify only local port: ":8082". + * Please note this is an advanced feature, and is somewhat hidden on purpose. + * You should understand that 99.999% of the time you should NOT specify the local port for an outgoing connection. + * If you think you need to, there is a very good chance you have a fundamental misunderstanding somewhere. + * Local ports do NOT need to match remote ports. In fact, they almost never do. + * This feature is here for networking professionals using very advanced techniques. +**/ +- (BOOL)connectToAddress:(NSData *)remoteAddr + viaInterface:(NSString *)interface + withTimeout:(NSTimeInterval)timeout + error:(NSError **)errPtr; + +#pragma mark Disconnecting + +/** + * Disconnects immediately (synchronously). Any pending reads or writes are dropped. + * + * If the socket is not already disconnected, an invocation to the socketDidDisconnect:withError: delegate method + * will be queued onto the delegateQueue asynchronously (behind any previously queued delegate methods). + * In other words, the disconnected delegate method will be invoked sometime shortly after this method returns. + * + * Please note the recommended way of releasing a GCDAsyncSocket instance (e.g. in a dealloc method) + * [asyncSocket setDelegate:nil]; + * [asyncSocket disconnect]; + * [asyncSocket release]; + * + * If you plan on disconnecting the socket, and then immediately asking it to connect again, + * you'll likely want to do so like this: + * [asyncSocket setDelegate:nil]; + * [asyncSocket disconnect]; + * [asyncSocket setDelegate:self]; + * [asyncSocket connect...]; +**/ +- (void)disconnect; + +/** + * Disconnects after all pending reads have completed. + * After calling this, the read and write methods will do nothing. + * The socket will disconnect even if there are still pending writes. +**/ +- (void)disconnectAfterReading; + +/** + * Disconnects after all pending writes have completed. + * After calling this, the read and write methods will do nothing. + * The socket will disconnect even if there are still pending reads. +**/ +- (void)disconnectAfterWriting; + +/** + * Disconnects after all pending reads and writes have completed. + * After calling this, the read and write methods will do nothing. +**/ +- (void)disconnectAfterReadingAndWriting; + +#pragma mark Diagnostics + +/** + * Returns whether the socket is disconnected or connected. + * + * A disconnected socket may be recycled. + * That is, it can used again for connecting or listening. + * + * If a socket is in the process of connecting, it may be neither disconnected nor connected. +**/ +- (BOOL)isDisconnected; +- (BOOL)isConnected; + +/** + * Returns the local or remote host and port to which this socket is connected, or nil and 0 if not connected. + * The host will be an IP address. +**/ +- (NSString *)connectedHost; +- (uint16_t)connectedPort; + +- (NSString *)localHost; +- (uint16_t)localPort; + +/** + * Returns the local or remote address to which this socket is connected, + * specified as a sockaddr structure wrapped in a NSData object. + * + * See also the connectedHost, connectedPort, localHost and localPort methods. +**/ +- (NSData *)connectedAddress; +- (NSData *)localAddress; + +/** + * Returns whether the socket is IPv4 or IPv6. + * An accepting socket may be both. +**/ +- (BOOL)isIPv4; +- (BOOL)isIPv6; + +/** + * Returns whether or not the socket has been secured via SSL/TLS. + * + * See also the startTLS method. +**/ +- (BOOL)isSecure; + +#pragma mark Reading + +// The readData and writeData methods won't block (they are asynchronous). +// +// When a read is complete the socket:didReadData:withTag: delegate method is dispatched on the delegateQueue. +// When a write is complete the socket:didWriteDataWithTag: delegate method is dispatched on the delegateQueue. +// +// You may optionally set a timeout for any read/write operation. (To not timeout, use a negative time interval.) +// If a read/write opertion times out, the corresponding "socket:shouldTimeout..." delegate method +// is called to optionally allow you to extend the timeout. +// Upon a timeout, the "socket:didDisconnectWithError:" method is called +// +// The tag is for your convenience. +// You can use it as an array index, step number, state id, pointer, etc. + +/** + * Reads the first available bytes that become available on the socket. + * + * If the timeout value is negative, the read operation will not use a timeout. +**/ +- (void)readDataWithTimeout:(NSTimeInterval)timeout tag:(long)tag; + +/** + * Reads the first available bytes that become available on the socket. + * The bytes will be appended to the given byte buffer starting at the given offset. + * The given buffer will automatically be increased in size if needed. + * + * If the timeout value is negative, the read operation will not use a timeout. + * If the buffer if nil, the socket will create a buffer for you. + * + * If the bufferOffset is greater than the length of the given buffer, + * the method will do nothing, and the delegate will not be called. + * + * If you pass a buffer, you must not alter it in any way while the socket is using it. + * After completion, the data returned in socket:didReadData:withTag: will be a subset of the given buffer. + * That is, it will reference the bytes that were appended to the given buffer via + * the method [NSData dataWithBytesNoCopy:length:freeWhenDone:NO]. +**/ +- (void)readDataWithTimeout:(NSTimeInterval)timeout + buffer:(NSMutableData *)buffer + bufferOffset:(NSUInteger)offset + tag:(long)tag; + +/** + * Reads the first available bytes that become available on the socket. + * The bytes will be appended to the given byte buffer starting at the given offset. + * The given buffer will automatically be increased in size if needed. + * A maximum of length bytes will be read. + * + * If the timeout value is negative, the read operation will not use a timeout. + * If the buffer if nil, a buffer will automatically be created for you. + * If maxLength is zero, no length restriction is enforced. + * + * If the bufferOffset is greater than the length of the given buffer, + * the method will do nothing, and the delegate will not be called. + * + * If you pass a buffer, you must not alter it in any way while the socket is using it. + * After completion, the data returned in socket:didReadData:withTag: will be a subset of the given buffer. + * That is, it will reference the bytes that were appended to the given buffer via + * the method [NSData dataWithBytesNoCopy:length:freeWhenDone:NO]. +**/ +- (void)readDataWithTimeout:(NSTimeInterval)timeout + buffer:(NSMutableData *)buffer + bufferOffset:(NSUInteger)offset + maxLength:(NSUInteger)length + tag:(long)tag; + +/** + * Reads the given number of bytes. + * + * If the timeout value is negative, the read operation will not use a timeout. + * + * If the length is 0, this method does nothing and the delegate is not called. +**/ +- (void)readDataToLength:(NSUInteger)length withTimeout:(NSTimeInterval)timeout tag:(long)tag; + +/** + * Reads the given number of bytes. + * The bytes will be appended to the given byte buffer starting at the given offset. + * The given buffer will automatically be increased in size if needed. + * + * If the timeout value is negative, the read operation will not use a timeout. + * If the buffer if nil, a buffer will automatically be created for you. + * + * If the length is 0, this method does nothing and the delegate is not called. + * If the bufferOffset is greater than the length of the given buffer, + * the method will do nothing, and the delegate will not be called. + * + * If you pass a buffer, you must not alter it in any way while AsyncSocket is using it. + * After completion, the data returned in socket:didReadData:withTag: will be a subset of the given buffer. + * That is, it will reference the bytes that were appended to the given buffer via + * the method [NSData dataWithBytesNoCopy:length:freeWhenDone:NO]. +**/ +- (void)readDataToLength:(NSUInteger)length + withTimeout:(NSTimeInterval)timeout + buffer:(NSMutableData *)buffer + bufferOffset:(NSUInteger)offset + tag:(long)tag; + +/** + * Reads bytes until (and including) the passed "data" parameter, which acts as a separator. + * + * If the timeout value is negative, the read operation will not use a timeout. + * + * If you pass nil or zero-length data as the "data" parameter, + * the method will do nothing (except maybe print a warning), and the delegate will not be called. + * + * To read a line from the socket, use the line separator (e.g. CRLF for HTTP, see below) as the "data" parameter. + * If you're developing your own custom protocol, be sure your separator can not occur naturally as + * part of the data between separators. + * For example, imagine you want to send several small documents over a socket. + * Using CRLF as a separator is likely unwise, as a CRLF could easily exist within the documents. + * In this particular example, it would be better to use a protocol similar to HTTP with + * a header that includes the length of the document. + * Also be careful that your separator cannot occur naturally as part of the encoding for a character. + * + * The given data (separator) parameter should be immutable. + * For performance reasons, the socket will retain it, not copy it. + * So if it is immutable, don't modify it while the socket is using it. +**/ +- (void)readDataToData:(NSData *)data withTimeout:(NSTimeInterval)timeout tag:(long)tag; + +/** + * Reads bytes until (and including) the passed "data" parameter, which acts as a separator. + * The bytes will be appended to the given byte buffer starting at the given offset. + * The given buffer will automatically be increased in size if needed. + * + * If the timeout value is negative, the read operation will not use a timeout. + * If the buffer if nil, a buffer will automatically be created for you. + * + * If the bufferOffset is greater than the length of the given buffer, + * the method will do nothing (except maybe print a warning), and the delegate will not be called. + * + * If you pass a buffer, you must not alter it in any way while the socket is using it. + * After completion, the data returned in socket:didReadData:withTag: will be a subset of the given buffer. + * That is, it will reference the bytes that were appended to the given buffer via + * the method [NSData dataWithBytesNoCopy:length:freeWhenDone:NO]. + * + * To read a line from the socket, use the line separator (e.g. CRLF for HTTP, see below) as the "data" parameter. + * If you're developing your own custom protocol, be sure your separator can not occur naturally as + * part of the data between separators. + * For example, imagine you want to send several small documents over a socket. + * Using CRLF as a separator is likely unwise, as a CRLF could easily exist within the documents. + * In this particular example, it would be better to use a protocol similar to HTTP with + * a header that includes the length of the document. + * Also be careful that your separator cannot occur naturally as part of the encoding for a character. + * + * The given data (separator) parameter should be immutable. + * For performance reasons, the socket will retain it, not copy it. + * So if it is immutable, don't modify it while the socket is using it. +**/ +- (void)readDataToData:(NSData *)data + withTimeout:(NSTimeInterval)timeout + buffer:(NSMutableData *)buffer + bufferOffset:(NSUInteger)offset + tag:(long)tag; + +/** + * Reads bytes until (and including) the passed "data" parameter, which acts as a separator. + * + * If the timeout value is negative, the read operation will not use a timeout. + * + * If maxLength is zero, no length restriction is enforced. + * Otherwise if maxLength bytes are read without completing the read, + * it is treated similarly to a timeout - the socket is closed with a GCDAsyncSocketReadMaxedOutError. + * The read will complete successfully if exactly maxLength bytes are read and the given data is found at the end. + * + * If you pass nil or zero-length data as the "data" parameter, + * the method will do nothing (except maybe print a warning), and the delegate will not be called. + * If you pass a maxLength parameter that is less than the length of the data parameter, + * the method will do nothing (except maybe print a warning), and the delegate will not be called. + * + * To read a line from the socket, use the line separator (e.g. CRLF for HTTP, see below) as the "data" parameter. + * If you're developing your own custom protocol, be sure your separator can not occur naturally as + * part of the data between separators. + * For example, imagine you want to send several small documents over a socket. + * Using CRLF as a separator is likely unwise, as a CRLF could easily exist within the documents. + * In this particular example, it would be better to use a protocol similar to HTTP with + * a header that includes the length of the document. + * Also be careful that your separator cannot occur naturally as part of the encoding for a character. + * + * The given data (separator) parameter should be immutable. + * For performance reasons, the socket will retain it, not copy it. + * So if it is immutable, don't modify it while the socket is using it. +**/ +- (void)readDataToData:(NSData *)data withTimeout:(NSTimeInterval)timeout maxLength:(NSUInteger)length tag:(long)tag; + +/** + * Reads bytes until (and including) the passed "data" parameter, which acts as a separator. + * The bytes will be appended to the given byte buffer starting at the given offset. + * The given buffer will automatically be increased in size if needed. + * + * If the timeout value is negative, the read operation will not use a timeout. + * If the buffer if nil, a buffer will automatically be created for you. + * + * If maxLength is zero, no length restriction is enforced. + * Otherwise if maxLength bytes are read without completing the read, + * it is treated similarly to a timeout - the socket is closed with a GCDAsyncSocketReadMaxedOutError. + * The read will complete successfully if exactly maxLength bytes are read and the given data is found at the end. + * + * If you pass a maxLength parameter that is less than the length of the data (separator) parameter, + * the method will do nothing (except maybe print a warning), and the delegate will not be called. + * If the bufferOffset is greater than the length of the given buffer, + * the method will do nothing (except maybe print a warning), and the delegate will not be called. + * + * If you pass a buffer, you must not alter it in any way while the socket is using it. + * After completion, the data returned in socket:didReadData:withTag: will be a subset of the given buffer. + * That is, it will reference the bytes that were appended to the given buffer via + * the method [NSData dataWithBytesNoCopy:length:freeWhenDone:NO]. + * + * To read a line from the socket, use the line separator (e.g. CRLF for HTTP, see below) as the "data" parameter. + * If you're developing your own custom protocol, be sure your separator can not occur naturally as + * part of the data between separators. + * For example, imagine you want to send several small documents over a socket. + * Using CRLF as a separator is likely unwise, as a CRLF could easily exist within the documents. + * In this particular example, it would be better to use a protocol similar to HTTP with + * a header that includes the length of the document. + * Also be careful that your separator cannot occur naturally as part of the encoding for a character. + * + * The given data (separator) parameter should be immutable. + * For performance reasons, the socket will retain it, not copy it. + * So if it is immutable, don't modify it while the socket is using it. +**/ +- (void)readDataToData:(NSData *)data + withTimeout:(NSTimeInterval)timeout + buffer:(NSMutableData *)buffer + bufferOffset:(NSUInteger)offset + maxLength:(NSUInteger)length + tag:(long)tag; + +/** + * Returns progress of the current read, from 0.0 to 1.0, or NaN if no current read (use isnan() to check). + * The parameters "tag", "done" and "total" will be filled in if they aren't NULL. +**/ +- (float)progressOfReadReturningTag:(long *)tagPtr bytesDone:(NSUInteger *)donePtr total:(NSUInteger *)totalPtr; + +#pragma mark Writing + +/** + * Writes data to the socket, and calls the delegate when finished. + * + * If you pass in nil or zero-length data, this method does nothing and the delegate will not be called. + * If the timeout value is negative, the write operation will not use a timeout. + * + * Thread-Safety Note: + * If the given data parameter is mutable (NSMutableData) then you MUST NOT alter the data while + * the socket is writing it. In other words, it's not safe to alter the data until after the delegate method + * socket:didWriteDataWithTag: is invoked signifying that this particular write operation has completed. + * This is due to the fact that GCDAsyncSocket does NOT copy the data. It simply retains it. + * This is for performance reasons. Often times, if NSMutableData is passed, it is because + * a request/response was built up in memory. Copying this data adds an unwanted/unneeded overhead. + * If you need to write data from an immutable buffer, and you need to alter the buffer before the socket + * completes writing the bytes (which is NOT immediately after this method returns, but rather at a later time + * when the delegate method notifies you), then you should first copy the bytes, and pass the copy to this method. +**/ +- (void)writeData:(NSData *)data withTimeout:(NSTimeInterval)timeout tag:(long)tag; + +/** + * Returns progress of the current write, from 0.0 to 1.0, or NaN if no current write (use isnan() to check). + * The parameters "tag", "done" and "total" will be filled in if they aren't NULL. +**/ +- (float)progressOfWriteReturningTag:(long *)tagPtr bytesDone:(NSUInteger *)donePtr total:(NSUInteger *)totalPtr; + +#pragma mark Security + +/** + * Secures the connection using SSL/TLS. + * + * This method may be called at any time, and the TLS handshake will occur after all pending reads and writes + * are finished. This allows one the option of sending a protocol dependent StartTLS message, and queuing + * the upgrade to TLS at the same time, without having to wait for the write to finish. + * Any reads or writes scheduled after this method is called will occur over the secured connection. + * + * The possible keys and values for the TLS settings are well documented. + * Standard keys are: + * + * - kCFStreamSSLLevel + * - kCFStreamSSLAllowsExpiredCertificates + * - kCFStreamSSLAllowsExpiredRoots + * - kCFStreamSSLAllowsAnyRoot + * - kCFStreamSSLValidatesCertificateChain + * - kCFStreamSSLPeerName + * - kCFStreamSSLCertificates + * - kCFStreamSSLIsServer + * + * If SecureTransport is available on iOS: + * + * - GCDAsyncSocketSSLCipherSuites + * - GCDAsyncSocketSSLProtocolVersionMin + * - GCDAsyncSocketSSLProtocolVersionMax + * + * If SecureTransport is available on Mac OS X: + * + * - GCDAsyncSocketSSLCipherSuites + * - GCDAsyncSocketSSLDiffieHellmanParameters; + * + * + * Please refer to Apple's documentation for associated values, as well as other possible keys. + * + * If you pass in nil or an empty dictionary, the default settings will be used. + * + * The default settings will check to make sure the remote party's certificate is signed by a + * trusted 3rd party certificate agency (e.g. verisign) and that the certificate is not expired. + * However it will not verify the name on the certificate unless you + * give it a name to verify against via the kCFStreamSSLPeerName key. + * The security implications of this are important to understand. + * Imagine you are attempting to create a secure connection to MySecureServer.com, + * but your socket gets directed to MaliciousServer.com because of a hacked DNS server. + * If you simply use the default settings, and MaliciousServer.com has a valid certificate, + * the default settings will not detect any problems since the certificate is valid. + * To properly secure your connection in this particular scenario you + * should set the kCFStreamSSLPeerName property to "MySecureServer.com". + * If you do not know the peer name of the remote host in advance (for example, you're not sure + * if it will be "domain.com" or "www.domain.com"), then you can use the default settings to validate the + * certificate, and then use the X509Certificate class to verify the issuer after the socket has been secured. + * The X509Certificate class is part of the CocoaAsyncSocket open source project. + **/ +- (void)startTLS:(NSDictionary *)tlsSettings; + +#pragma mark Advanced + +/** + * Traditionally sockets are not closed until the conversation is over. + * However, it is technically possible for the remote enpoint to close its write stream. + * Our socket would then be notified that there is no more data to be read, + * but our socket would still be writeable and the remote endpoint could continue to receive our data. + * + * The argument for this confusing functionality stems from the idea that a client could shut down its + * write stream after sending a request to the server, thus notifying the server there are to be no further requests. + * In practice, however, this technique did little to help server developers. + * + * To make matters worse, from a TCP perspective there is no way to tell the difference from a read stream close + * and a full socket close. They both result in the TCP stack receiving a FIN packet. The only way to tell + * is by continuing to write to the socket. If it was only a read stream close, then writes will continue to work. + * Otherwise an error will be occur shortly (when the remote end sends us a RST packet). + * + * In addition to the technical challenges and confusion, many high level socket/stream API's provide + * no support for dealing with the problem. If the read stream is closed, the API immediately declares the + * socket to be closed, and shuts down the write stream as well. In fact, this is what Apple's CFStream API does. + * It might sound like poor design at first, but in fact it simplifies development. + * + * The vast majority of the time if the read stream is closed it's because the remote endpoint closed its socket. + * Thus it actually makes sense to close the socket at this point. + * And in fact this is what most networking developers want and expect to happen. + * However, if you are writing a server that interacts with a plethora of clients, + * you might encounter a client that uses the discouraged technique of shutting down its write stream. + * If this is the case, you can set this property to NO, + * and make use of the socketDidCloseReadStream delegate method. + * + * The default value is YES. +**/ +- (BOOL)autoDisconnectOnClosedReadStream; +- (void)setAutoDisconnectOnClosedReadStream:(BOOL)flag; + +/** + * GCDAsyncSocket maintains thread safety by using an internal serial dispatch_queue. + * In most cases, the instance creates this queue itself. + * However, to allow for maximum flexibility, the internal queue may be passed in the init method. + * This allows for some advanced options such as controlling socket priority via target queues. + * However, when one begins to use target queues like this, they open the door to some specific deadlock issues. + * + * For example, imagine there are 2 queues: + * dispatch_queue_t socketQueue; + * dispatch_queue_t socketTargetQueue; + * + * If you do this (pseudo-code): + * socketQueue.targetQueue = socketTargetQueue; + * + * Then all socketQueue operations will actually get run on the given socketTargetQueue. + * This is fine and works great in most situations. + * But if you run code directly from within the socketTargetQueue that accesses the socket, + * you could potentially get deadlock. Imagine the following code: + * + * - (BOOL)socketHasSomething + * { + * __block BOOL result = NO; + * dispatch_block_t block = ^{ + * result = [self someInternalMethodToBeRunOnlyOnSocketQueue]; + * } + * if (is_executing_on_queue(socketQueue)) + * block(); + * else + * dispatch_sync(socketQueue, block); + * + * return result; + * } + * + * What happens if you call this method from the socketTargetQueue? The result is deadlock. + * This is because the GCD API offers no mechanism to discover a queue's targetQueue. + * Thus we have no idea if our socketQueue is configured with a targetQueue. + * If we had this information, we could easily avoid deadlock. + * But, since these API's are missing or unfeasible, you'll have to explicitly set it. + * + * IF you pass a socketQueue via the init method, + * AND you've configured the passed socketQueue with a targetQueue, + * THEN you should pass the end queue in the target hierarchy. + * + * For example, consider the following queue hierarchy: + * socketQueue -> ipQueue -> moduleQueue + * + * This example demonstrates priority shaping within some server. + * All incoming client connections from the same IP address are executed on the same target queue. + * And all connections for a particular module are executed on the same target queue. + * Thus, the priority of all networking for the entire module can be changed on the fly. + * Additionally, networking traffic from a single IP cannot monopolize the module. + * + * Here's how you would accomplish something like that: + * - (dispatch_queue_t)newSocketQueueForConnectionFromAddress:(NSData *)address onSocket:(GCDAsyncSocket *)sock + * { + * dispatch_queue_t socketQueue = dispatch_queue_create("", NULL); + * dispatch_queue_t ipQueue = [self ipQueueForAddress:address]; + * + * dispatch_set_target_queue(socketQueue, ipQueue); + * dispatch_set_target_queue(iqQueue, moduleQueue); + * + * return socketQueue; + * } + * - (void)socket:(GCDAsyncSocket *)sock didAcceptNewSocket:(GCDAsyncSocket *)newSocket + * { + * [clientConnections addObject:newSocket]; + * [newSocket markSocketQueueTargetQueue:moduleQueue]; + * } + * + * Note: This workaround is ONLY needed if you intend to execute code directly on the ipQueue or moduleQueue. + * This is often NOT the case, as such queues are used solely for execution shaping. +**/ +- (void)markSocketQueueTargetQueue:(dispatch_queue_t)socketQueuesPreConfiguredTargetQueue; +- (void)unmarkSocketQueueTargetQueue:(dispatch_queue_t)socketQueuesPreviouslyConfiguredTargetQueue; + +/** + * It's not thread-safe to access certain variables from outside the socket's internal queue. + * + * For example, the socket file descriptor. + * File descriptors are simply integers which reference an index in the per-process file table. + * However, when one requests a new file descriptor (by opening a file or socket), + * the file descriptor returned is guaranteed to be the lowest numbered unused descriptor. + * So if we're not careful, the following could be possible: + * + * - Thread A invokes a method which returns the socket's file descriptor. + * - The socket is closed via the socket's internal queue on thread B. + * - Thread C opens a file, and subsequently receives the file descriptor that was previously the socket's FD. + * - Thread A is now accessing/altering the file instead of the socket. + * + * In addition to this, other variables are not actually objects, + * and thus cannot be retained/released or even autoreleased. + * An example is the sslContext, of type SSLContextRef, which is actually a malloc'd struct. + * + * Although there are internal variables that make it difficult to maintain thread-safety, + * it is important to provide access to these variables + * to ensure this class can be used in a wide array of environments. + * This method helps to accomplish this by invoking the current block on the socket's internal queue. + * The methods below can be invoked from within the block to access + * those generally thread-unsafe internal variables in a thread-safe manner. + * The given block will be invoked synchronously on the socket's internal queue. + * + * If you save references to any protected variables and use them outside the block, you do so at your own peril. +**/ +- (void)performBlock:(dispatch_block_t)block; + +/** + * These methods are only available from within the context of a performBlock: invocation. + * See the documentation for the performBlock: method above. + * + * Provides access to the socket's file descriptor(s). + * If the socket is a server socket (is accepting incoming connections), + * it might actually have multiple internal socket file descriptors - one for IPv4 and one for IPv6. +**/ +- (int)socketFD; +- (int)socket4FD; +- (int)socket6FD; + +#if TARGET_OS_IPHONE + +/** + * These methods are only available from within the context of a performBlock: invocation. + * See the documentation for the performBlock: method above. + * + * Provides access to the socket's internal CFReadStream/CFWriteStream. + * + * These streams are only used as workarounds for specific iOS shortcomings: + * + * - Apple has decided to keep the SecureTransport framework private is iOS. + * This means the only supplied way to do SSL/TLS is via CFStream or some other API layered on top of it. + * Thus, in order to provide SSL/TLS support on iOS we are forced to rely on CFStream, + * instead of the preferred and faster and more powerful SecureTransport. + * + * - If a socket doesn't have backgrounding enabled, and that socket is closed while the app is backgrounded, + * Apple only bothers to notify us via the CFStream API. + * The faster and more powerful GCD API isn't notified properly in this case. + * + * See also: (BOOL)enableBackgroundingOnSocket +**/ +- (CFReadStreamRef)readStream; +- (CFWriteStreamRef)writeStream; + +/** + * This method is only available from within the context of a performBlock: invocation. + * See the documentation for the performBlock: method above. + * + * Configures the socket to allow it to operate when the iOS application has been backgrounded. + * In other words, this method creates a read & write stream, and invokes: + * + * CFReadStreamSetProperty(readStream, kCFStreamNetworkServiceType, kCFStreamNetworkServiceTypeVoIP); + * CFWriteStreamSetProperty(writeStream, kCFStreamNetworkServiceType, kCFStreamNetworkServiceTypeVoIP); + * + * Returns YES if successful, NO otherwise. + * + * Note: Apple does not officially support backgrounding server sockets. + * That is, if your socket is accepting incoming connections, Apple does not officially support + * allowing iOS applications to accept incoming connections while an app is backgrounded. + * + * Example usage: + * + * - (void)socket:(GCDAsyncSocket *)sock didConnectToHost:(NSString *)host port:(uint16_t)port + * { + * [asyncSocket performBlock:^{ + * [asyncSocket enableBackgroundingOnSocket]; + * }]; + * } +**/ +- (BOOL)enableBackgroundingOnSocket; + +#endif + +#if SECURE_TRANSPORT_MAYBE_AVAILABLE + +/** + * This method is only available from within the context of a performBlock: invocation. + * See the documentation for the performBlock: method above. + * + * Provides access to the socket's SSLContext, if SSL/TLS has been started on the socket. +**/ +- (SSLContextRef)sslContext; + +#endif + +#pragma mark Utilities + +/** + * Extracting host and port information from raw address data. +**/ ++ (NSString *)hostFromAddress:(NSData *)address; ++ (uint16_t)portFromAddress:(NSData *)address; ++ (BOOL)getHost:(NSString **)hostPtr port:(uint16_t *)portPtr fromAddress:(NSData *)address; + +/** + * A few common line separators, for use with the readDataToData:... methods. +**/ ++ (NSData *)CRLFData; // 0x0D0A ++ (NSData *)CRData; // 0x0D ++ (NSData *)LFData; // 0x0A ++ (NSData *)ZeroData; // 0x00 + +@end + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +#pragma mark - +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +@protocol GCDAsyncSocketDelegate +@optional + +/** + * This method is called immediately prior to socket:didAcceptNewSocket:. + * It optionally allows a listening socket to specify the socketQueue for a new accepted socket. + * If this method is not implemented, or returns NULL, the new accepted socket will create its own default queue. + * + * Since you cannot autorelease a dispatch_queue, + * this method uses the "new" prefix in its name to specify that the returned queue has been retained. + * + * Thus you could do something like this in the implementation: + * return dispatch_queue_create("MyQueue", NULL); + * + * If you are placing multiple sockets on the same queue, + * then care should be taken to increment the retain count each time this method is invoked. + * + * For example, your implementation might look something like this: + * dispatch_retain(myExistingQueue); + * return myExistingQueue; +**/ +- (dispatch_queue_t)newSocketQueueForConnectionFromAddress:(NSData *)address onSocket:(GCDAsyncSocket *)sock; + +/** + * Called when a socket accepts a connection. + * Another socket is automatically spawned to handle it. + * + * You must retain the newSocket if you wish to handle the connection. + * Otherwise the newSocket instance will be released and the spawned connection will be closed. + * + * By default the new socket will have the same delegate and delegateQueue. + * You may, of course, change this at any time. +**/ +- (void)socket:(GCDAsyncSocket *)sock didAcceptNewSocket:(GCDAsyncSocket *)newSocket; + +/** + * Called when a socket connects and is ready for reading and writing. + * The host parameter will be an IP address, not a DNS name. +**/ +- (void)socket:(GCDAsyncSocket *)sock didConnectToHost:(NSString *)host port:(uint16_t)port; + +/** + * Called when a socket has completed reading the requested data into memory. + * Not called if there is an error. +**/ +- (void)socket:(GCDAsyncSocket *)sock didReadData:(NSData *)data withTag:(long)tag; + +/** + * Called when a socket has read in data, but has not yet completed the read. + * This would occur if using readToData: or readToLength: methods. + * It may be used to for things such as updating progress bars. +**/ +- (void)socket:(GCDAsyncSocket *)sock didReadPartialDataOfLength:(NSUInteger)partialLength tag:(long)tag; + +/** + * Called when a socket has completed writing the requested data. Not called if there is an error. +**/ +- (void)socket:(GCDAsyncSocket *)sock didWriteDataWithTag:(long)tag; + +/** + * Called when a socket has written some data, but has not yet completed the entire write. + * It may be used to for things such as updating progress bars. +**/ +- (void)socket:(GCDAsyncSocket *)sock didWritePartialDataOfLength:(NSUInteger)partialLength tag:(long)tag; + +/** + * Called if a read operation has reached its timeout without completing. + * This method allows you to optionally extend the timeout. + * If you return a positive time interval (> 0) the read's timeout will be extended by the given amount. + * If you don't implement this method, or return a non-positive time interval (<= 0) the read will timeout as usual. + * + * The elapsed parameter is the sum of the original timeout, plus any additions previously added via this method. + * The length parameter is the number of bytes that have been read so far for the read operation. + * + * Note that this method may be called multiple times for a single read if you return positive numbers. +**/ +- (NSTimeInterval)socket:(GCDAsyncSocket *)sock shouldTimeoutReadWithTag:(long)tag + elapsed:(NSTimeInterval)elapsed + bytesDone:(NSUInteger)length; + +/** + * Called if a write operation has reached its timeout without completing. + * This method allows you to optionally extend the timeout. + * If you return a positive time interval (> 0) the write's timeout will be extended by the given amount. + * If you don't implement this method, or return a non-positive time interval (<= 0) the write will timeout as usual. + * + * The elapsed parameter is the sum of the original timeout, plus any additions previously added via this method. + * The length parameter is the number of bytes that have been written so far for the write operation. + * + * Note that this method may be called multiple times for a single write if you return positive numbers. +**/ +- (NSTimeInterval)socket:(GCDAsyncSocket *)sock shouldTimeoutWriteWithTag:(long)tag + elapsed:(NSTimeInterval)elapsed + bytesDone:(NSUInteger)length; + +/** + * Conditionally called if the read stream closes, but the write stream may still be writeable. + * + * This delegate method is only called if autoDisconnectOnClosedReadStream has been set to NO. + * See the discussion on the autoDisconnectOnClosedReadStream method for more information. +**/ +- (void)socketDidCloseReadStream:(GCDAsyncSocket *)sock; + +/** + * Called when a socket disconnects with or without error. + * + * If you call the disconnect method, and the socket wasn't already disconnected, + * this delegate method will be called before the disconnect method returns. +**/ +- (void)socketDidDisconnect:(GCDAsyncSocket *)sock withError:(NSError *)err; + +/** + * Called after the socket has successfully completed SSL/TLS negotiation. + * This method is not called unless you use the provided startTLS method. + * + * If a SSL/TLS negotiation fails (invalid certificate, etc) then the socket will immediately close, + * and the socketDidDisconnect:withError: delegate method will be called with the specific SSL error code. +**/ +- (void)socketDidSecure:(GCDAsyncSocket *)sock; + +@end diff --git a/mac/TeamTalk/FileTransfer/GCDAsyncSocket.m b/mac/TeamTalk/FileTransfer/GCDAsyncSocket.m new file mode 100644 index 000000000..f3f592bfa --- /dev/null +++ b/mac/TeamTalk/FileTransfer/GCDAsyncSocket.m @@ -0,0 +1,7416 @@ +// +// GCDAsyncSocket.m +// +// This class is in the public domain. +// Originally created by Robbie Hanson in Q4 2010. +// Updated and maintained by Deusty LLC and the Apple development community. +// +// https://github.com/robbiehanson/CocoaAsyncSocket +// + +#import "GCDAsyncSocket.h" + +#if TARGET_OS_IPHONE +#import +#endif + +#import +#import +#import +#import +#import +#import +#import +#import +#import +#import +#import +#import + +#if ! __has_feature(objc_arc) +#warning This file must be compiled with ARC. Use -fobjc-arc flag (or convert project to ARC). +// For more information see: https://github.com/robbiehanson/CocoaAsyncSocket/wiki/ARC +#endif + + +#if 0 + +// Logging Enabled - See log level below + +// Logging uses the CocoaLumberjack framework (which is also GCD based). +// https://github.com/robbiehanson/CocoaLumberjack +// +// It allows us to do a lot of logging without significantly slowing down the code. +#import "DDLog.h" + +#define LogAsync YES +#define LogContext 65535 + +#define LogObjc(flg, frmt, ...) LOG_OBJC_MAYBE(LogAsync, logLevel, flg, LogContext, frmt, ##__VA_ARGS__) +#define LogC(flg, frmt, ...) LOG_C_MAYBE(LogAsync, logLevel, flg, LogContext, frmt, ##__VA_ARGS__) + +#define LogError(frmt, ...) LogObjc(LOG_FLAG_ERROR, (@"%@: " frmt), THIS_FILE, ##__VA_ARGS__) +#define LogWarn(frmt, ...) LogObjc(LOG_FLAG_WARN, (@"%@: " frmt), THIS_FILE, ##__VA_ARGS__) +#define LogInfo(frmt, ...) LogObjc(LOG_FLAG_INFO, (@"%@: " frmt), THIS_FILE, ##__VA_ARGS__) +#define LogVerbose(frmt, ...) LogObjc(LOG_FLAG_VERBOSE, (@"%@: " frmt), THIS_FILE, ##__VA_ARGS__) + +#define LogCError(frmt, ...) LogC(LOG_FLAG_ERROR, (@"%@: " frmt), THIS_FILE, ##__VA_ARGS__) +#define LogCWarn(frmt, ...) LogC(LOG_FLAG_WARN, (@"%@: " frmt), THIS_FILE, ##__VA_ARGS__) +#define LogCInfo(frmt, ...) LogC(LOG_FLAG_INFO, (@"%@: " frmt), THIS_FILE, ##__VA_ARGS__) +#define LogCVerbose(frmt, ...) LogC(LOG_FLAG_VERBOSE, (@"%@: " frmt), THIS_FILE, ##__VA_ARGS__) + +#define LogTrace() LogObjc(LOG_FLAG_VERBOSE, @"%@: %@", THIS_FILE, THIS_METHOD) +#define LogCTrace() LogC(LOG_FLAG_VERBOSE, @"%@: %s", THIS_FILE, __FUNCTION__) + +// Log levels : off, error, warn, info, verbose +static const int logLevel = LOG_LEVEL_VERBOSE; + +#else + +// Logging Disabled + +#define LogError(frmt, ...) {} +#define LogWarn(frmt, ...) {} +#define LogInfo(frmt, ...) {} +#define LogVerbose(frmt, ...) {} + +#define LogCError(frmt, ...) {} +#define LogCWarn(frmt, ...) {} +#define LogCInfo(frmt, ...) {} +#define LogCVerbose(frmt, ...) {} + +#define LogTrace() {} +#define LogCTrace(frmt, ...) {} + +#endif + +/** + * Seeing a return statements within an inner block + * can sometimes be mistaken for a return point of the enclosing method. + * This makes inline blocks a bit easier to read. +**/ +#define return_from_block return + +/** + * A socket file descriptor is really just an integer. + * It represents the index of the socket within the kernel. + * This makes invalid file descriptor comparisons easier to read. +**/ +#define SOCKET_NULL -1 + + +NSString *const GCDAsyncSocketException = @"GCDAsyncSocketException"; +NSString *const GCDAsyncSocketErrorDomain = @"GCDAsyncSocketErrorDomain"; + +NSString *const GCDAsyncSocketQueueName = @"GCDAsyncSocket"; +NSString *const GCDAsyncSocketThreadName = @"GCDAsyncSocket-CFStream"; + +#if SECURE_TRANSPORT_MAYBE_AVAILABLE +NSString *const GCDAsyncSocketSSLCipherSuites = @"GCDAsyncSocketSSLCipherSuites"; +#if TARGET_OS_IPHONE +NSString *const GCDAsyncSocketSSLProtocolVersionMin = @"GCDAsyncSocketSSLProtocolVersionMin"; +NSString *const GCDAsyncSocketSSLProtocolVersionMax = @"GCDAsyncSocketSSLProtocolVersionMax"; +#else +NSString *const GCDAsyncSocketSSLDiffieHellmanParameters = @"GCDAsyncSocketSSLDiffieHellmanParameters"; +#endif +#endif + +enum GCDAsyncSocketFlags +{ + kSocketStarted = 1 << 0, // If set, socket has been started (accepting/connecting) + kConnected = 1 << 1, // If set, the socket is connected + kForbidReadsWrites = 1 << 2, // If set, no new reads or writes are allowed + kReadsPaused = 1 << 3, // If set, reads are paused due to possible timeout + kWritesPaused = 1 << 4, // If set, writes are paused due to possible timeout + kDisconnectAfterReads = 1 << 5, // If set, disconnect after no more reads are queued + kDisconnectAfterWrites = 1 << 6, // If set, disconnect after no more writes are queued + kSocketCanAcceptBytes = 1 << 7, // If set, we know socket can accept bytes. If unset, it's unknown. + kReadSourceSuspended = 1 << 8, // If set, the read source is suspended + kWriteSourceSuspended = 1 << 9, // If set, the write source is suspended + kQueuedTLS = 1 << 10, // If set, we've queued an upgrade to TLS + kStartingReadTLS = 1 << 11, // If set, we're waiting for TLS negotiation to complete + kStartingWriteTLS = 1 << 12, // If set, we're waiting for TLS negotiation to complete + kSocketSecure = 1 << 13, // If set, socket is using secure communication via SSL/TLS + kSocketHasReadEOF = 1 << 14, // If set, we have read EOF from socket + kReadStreamClosed = 1 << 15, // If set, we've read EOF plus prebuffer has been drained +#if TARGET_OS_IPHONE + kAddedStreamsToRunLoop = 1 << 16, // If set, CFStreams have been added to listener thread + kUsingCFStreamForTLS = 1 << 17, // If set, we're forced to use CFStream instead of SecureTransport + kSecureSocketHasBytesAvailable = 1 << 18, // If set, CFReadStream has notified us of bytes available +#endif +}; + +enum GCDAsyncSocketConfig +{ + kIPv4Disabled = 1 << 0, // If set, IPv4 is disabled + kIPv6Disabled = 1 << 1, // If set, IPv6 is disabled + kPreferIPv6 = 1 << 2, // If set, IPv6 is preferred over IPv4 + kAllowHalfDuplexConnection = 1 << 3, // If set, the socket will stay open even if the read stream closes +}; + +#if TARGET_OS_IPHONE + static NSThread *cfstreamThread; // Used for CFStreams +#endif + +@interface GCDAsyncSocket () +{ + uint32_t flags; + uint16_t config; + +#if __has_feature(objc_arc_weak) + __weak id delegate; +#else + __unsafe_unretained id delegate; +#endif + dispatch_queue_t delegateQueue; + + int socket4FD; + int socket6FD; + int connectIndex; + NSData * connectInterface4; + NSData * connectInterface6; + + dispatch_queue_t socketQueue; + + dispatch_source_t accept4Source; + dispatch_source_t accept6Source; + dispatch_source_t connectTimer; + dispatch_source_t readSource; + dispatch_source_t writeSource; + dispatch_source_t readTimer; + dispatch_source_t writeTimer; + + NSMutableArray *readQueue; + NSMutableArray *writeQueue; + + GCDAsyncReadPacket *currentRead; + GCDAsyncWritePacket *currentWrite; + + unsigned long socketFDBytesAvailable; + + GCDAsyncSocketPreBuffer *preBuffer; + +#if TARGET_OS_IPHONE + CFStreamClientContext streamContext; + CFReadStreamRef readStream; + CFWriteStreamRef writeStream; +#endif +#if SECURE_TRANSPORT_MAYBE_AVAILABLE + SSLContextRef sslContext; + GCDAsyncSocketPreBuffer *sslPreBuffer; + size_t sslWriteCachedLength; + OSStatus sslErrCode; +#endif + + void *IsOnSocketQueueOrTargetQueueKey; + + id userData; +} +// Accepting +- (BOOL)doAccept:(int)socketFD; + +// Connecting +- (void)startConnectTimeout:(NSTimeInterval)timeout; +- (void)endConnectTimeout; +- (void)doConnectTimeout; +- (void)lookup:(int)aConnectIndex host:(NSString *)host port:(uint16_t)port; +- (void)lookup:(int)aConnectIndex didSucceedWithAddress4:(NSData *)address4 address6:(NSData *)address6; +- (void)lookup:(int)aConnectIndex didFail:(NSError *)error; +- (BOOL)connectWithAddress4:(NSData *)address4 address6:(NSData *)address6 error:(NSError **)errPtr; +- (void)didConnect:(int)aConnectIndex; +- (void)didNotConnect:(int)aConnectIndex error:(NSError *)error; + +// Disconnect +- (void)closeWithError:(NSError *)error; +- (void)maybeClose; + +// Errors +- (NSError *)badConfigError:(NSString *)msg; +- (NSError *)badParamError:(NSString *)msg; +- (NSError *)gaiError:(int)gai_error; +- (NSError *)errnoError; +- (NSError *)errnoErrorWithReason:(NSString *)reason; +- (NSError *)connectTimeoutError; +- (NSError *)otherError:(NSString *)msg; + +// Diagnostics +- (NSString *)connectedHost4; +- (NSString *)connectedHost6; +- (uint16_t)connectedPort4; +- (uint16_t)connectedPort6; +- (NSString *)localHost4; +- (NSString *)localHost6; +- (uint16_t)localPort4; +- (uint16_t)localPort6; +- (NSString *)connectedHostFromSocket4:(int)socketFD; +- (NSString *)connectedHostFromSocket6:(int)socketFD; +- (uint16_t)connectedPortFromSocket4:(int)socketFD; +- (uint16_t)connectedPortFromSocket6:(int)socketFD; +- (NSString *)localHostFromSocket4:(int)socketFD; +- (NSString *)localHostFromSocket6:(int)socketFD; +- (uint16_t)localPortFromSocket4:(int)socketFD; +- (uint16_t)localPortFromSocket6:(int)socketFD; + +// Utilities +- (void)getInterfaceAddress4:(NSMutableData **)addr4Ptr + address6:(NSMutableData **)addr6Ptr + fromDescription:(NSString *)interfaceDescription + port:(uint16_t)port; +- (void)setupReadAndWriteSourcesForNewlyConnectedSocket:(int)socketFD; +- (void)suspendReadSource; +- (void)resumeReadSource; +- (void)suspendWriteSource; +- (void)resumeWriteSource; + +// Reading +- (void)maybeDequeueRead; +- (void)flushSSLBuffers; +- (void)doReadData; +- (void)doReadEOF; +- (void)completeCurrentRead; +- (void)endCurrentRead; +- (void)setupReadTimerWithTimeout:(NSTimeInterval)timeout; +- (void)doReadTimeout; +- (void)doReadTimeoutWithExtension:(NSTimeInterval)timeoutExtension; + +// Writing +- (void)maybeDequeueWrite; +- (void)doWriteData; +- (void)completeCurrentWrite; +- (void)endCurrentWrite; +- (void)setupWriteTimerWithTimeout:(NSTimeInterval)timeout; +- (void)doWriteTimeout; +- (void)doWriteTimeoutWithExtension:(NSTimeInterval)timeoutExtension; + +// Security +- (void)maybeStartTLS; +#if SECURE_TRANSPORT_MAYBE_AVAILABLE +- (void)ssl_startTLS; +- (void)ssl_continueSSLHandshake; +#endif +#if TARGET_OS_IPHONE +- (void)cf_startTLS; +#endif + +// CFStream +#if TARGET_OS_IPHONE ++ (void)startCFStreamThreadIfNeeded; +- (BOOL)createReadAndWriteStream; +- (BOOL)registerForStreamCallbacksIncludingReadWrite:(BOOL)includeReadWrite; +- (BOOL)addStreamsToRunLoop; +- (BOOL)openStreams; +- (void)removeStreamsFromRunLoop; +#endif + +// Class Methods ++ (NSString *)hostFromSockaddr4:(const struct sockaddr_in *)pSockaddr4; ++ (NSString *)hostFromSockaddr6:(const struct sockaddr_in6 *)pSockaddr6; ++ (uint16_t)portFromSockaddr4:(const struct sockaddr_in *)pSockaddr4; ++ (uint16_t)portFromSockaddr6:(const struct sockaddr_in6 *)pSockaddr6; + +@end + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +#pragma mark - +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +/** + * A PreBuffer is used when there is more data available on the socket + * than is being requested by current read request. + * In this case we slurp up all data from the socket (to minimize sys calls), + * and store additional yet unread data in a "prebuffer". + * + * The prebuffer is entirely drained before we read from the socket again. + * In other words, a large chunk of data is written is written to the prebuffer. + * The prebuffer is then drained via a series of one or more reads (for subsequent read request(s)). + * + * A ring buffer was once used for this purpose. + * But a ring buffer takes up twice as much memory as needed (double the size for mirroring). + * In fact, it generally takes up more than twice the needed size as everything has to be rounded up to vm_page_size. + * And since the prebuffer is always completely drained after being written to, a full ring buffer isn't needed. + * + * The current design is very simple and straight-forward, while also keeping memory requirements lower. +**/ + +@interface GCDAsyncSocketPreBuffer : NSObject +{ + uint8_t *preBuffer; + size_t preBufferSize; + + uint8_t *readPointer; + uint8_t *writePointer; +} + +- (id)initWithCapacity:(size_t)numBytes; + +- (void)ensureCapacityForWrite:(size_t)numBytes; + +- (size_t)availableBytes; +- (uint8_t *)readBuffer; + +- (void)getReadBuffer:(uint8_t **)bufferPtr availableBytes:(size_t *)availableBytesPtr; + +- (size_t)availableSpace; +- (uint8_t *)writeBuffer; + +- (void)getWriteBuffer:(uint8_t **)bufferPtr availableSpace:(size_t *)availableSpacePtr; + +- (void)didRead:(size_t)bytesRead; +- (void)didWrite:(size_t)bytesWritten; + +- (void)reset; + +@end + +@implementation GCDAsyncSocketPreBuffer + +- (id)initWithCapacity:(size_t)numBytes +{ + if ((self = [super init])) + { + preBufferSize = numBytes; + preBuffer = malloc(preBufferSize); + + readPointer = preBuffer; + writePointer = preBuffer; + } + return self; +} + +- (void)dealloc +{ + if (preBuffer) + free(preBuffer); +} + +- (void)ensureCapacityForWrite:(size_t)numBytes +{ + size_t availableSpace = [self availableSpace]; + + if (numBytes > availableSpace) + { + size_t additionalBytes = numBytes - availableSpace; + + size_t newPreBufferSize = preBufferSize + additionalBytes; + uint8_t *newPreBuffer = realloc(preBuffer, newPreBufferSize); + + size_t readPointerOffset = readPointer - preBuffer; + size_t writePointerOffset = writePointer - preBuffer; + + preBuffer = newPreBuffer; + preBufferSize = newPreBufferSize; + + readPointer = preBuffer + readPointerOffset; + writePointer = preBuffer + writePointerOffset; + } +} + +- (size_t)availableBytes +{ + return writePointer - readPointer; +} + +- (uint8_t *)readBuffer +{ + return readPointer; +} + +- (void)getReadBuffer:(uint8_t **)bufferPtr availableBytes:(size_t *)availableBytesPtr +{ + if (bufferPtr) *bufferPtr = readPointer; + if (availableBytesPtr) *availableBytesPtr = [self availableBytes]; +} + +- (void)didRead:(size_t)bytesRead +{ + readPointer += bytesRead; + + if (readPointer == writePointer) + { + // The prebuffer has been drained. Reset pointers. + readPointer = preBuffer; + writePointer = preBuffer; + } +} + +- (size_t)availableSpace +{ + return preBufferSize - (writePointer - preBuffer); +} + +- (uint8_t *)writeBuffer +{ + return writePointer; +} + +- (void)getWriteBuffer:(uint8_t **)bufferPtr availableSpace:(size_t *)availableSpacePtr +{ + if (bufferPtr) *bufferPtr = writePointer; + if (availableSpacePtr) *availableSpacePtr = [self availableSpace]; +} + +- (void)didWrite:(size_t)bytesWritten +{ + writePointer += bytesWritten; +} + +- (void)reset +{ + readPointer = preBuffer; + writePointer = preBuffer; +} + +@end + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +#pragma mark - +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +/** + * The GCDAsyncReadPacket encompasses the instructions for any given read. + * The content of a read packet allows the code to determine if we're: + * - reading to a certain length + * - reading to a certain separator + * - or simply reading the first chunk of available data +**/ +@interface GCDAsyncReadPacket : NSObject +{ + @public + NSMutableData *buffer; + NSUInteger startOffset; + NSUInteger bytesDone; + NSUInteger maxLength; + NSTimeInterval timeout; + NSUInteger readLength; + NSData *term; + BOOL bufferOwner; + NSUInteger originalBufferLength; + long tag; +} +- (id)initWithData:(NSMutableData *)d + startOffset:(NSUInteger)s + maxLength:(NSUInteger)m + timeout:(NSTimeInterval)t + readLength:(NSUInteger)l + terminator:(NSData *)e + tag:(long)i; + +- (void)ensureCapacityForAdditionalDataOfLength:(NSUInteger)bytesToRead; + +- (NSUInteger)optimalReadLengthWithDefault:(NSUInteger)defaultValue shouldPreBuffer:(BOOL *)shouldPreBufferPtr; + +- (NSUInteger)readLengthForNonTermWithHint:(NSUInteger)bytesAvailable; +- (NSUInteger)readLengthForTermWithHint:(NSUInteger)bytesAvailable shouldPreBuffer:(BOOL *)shouldPreBufferPtr; +- (NSUInteger)readLengthForTermWithPreBuffer:(GCDAsyncSocketPreBuffer *)preBuffer found:(BOOL *)foundPtr; + +- (NSInteger)searchForTermAfterPreBuffering:(ssize_t)numBytes; + +@end + +@implementation GCDAsyncReadPacket + +- (id)initWithData:(NSMutableData *)d + startOffset:(NSUInteger)s + maxLength:(NSUInteger)m + timeout:(NSTimeInterval)t + readLength:(NSUInteger)l + terminator:(NSData *)e + tag:(long)i +{ + if((self = [super init])) + { + bytesDone = 0; + maxLength = m; + timeout = t; + readLength = l; + term = [e copy]; + tag = i; + + if (d) + { + buffer = d; + startOffset = s; + bufferOwner = NO; + originalBufferLength = [d length]; + } + else + { + if (readLength > 0) + buffer = [[NSMutableData alloc] initWithLength:readLength]; + else + buffer = [[NSMutableData alloc] initWithLength:0]; + + startOffset = 0; + bufferOwner = YES; + originalBufferLength = 0; + } + } + return self; +} + +/** + * Increases the length of the buffer (if needed) to ensure a read of the given size will fit. +**/ +- (void)ensureCapacityForAdditionalDataOfLength:(NSUInteger)bytesToRead +{ + NSUInteger buffSize = [buffer length]; + NSUInteger buffUsed = startOffset + bytesDone; + + NSUInteger buffSpace = buffSize - buffUsed; + + if (bytesToRead > buffSpace) + { + NSUInteger buffInc = bytesToRead - buffSpace; + + [buffer increaseLengthBy:buffInc]; + } +} + +/** + * This method is used when we do NOT know how much data is available to be read from the socket. + * This method returns the default value unless it exceeds the specified readLength or maxLength. + * + * Furthermore, the shouldPreBuffer decision is based upon the packet type, + * and whether the returned value would fit in the current buffer without requiring a resize of the buffer. +**/ +- (NSUInteger)optimalReadLengthWithDefault:(NSUInteger)defaultValue shouldPreBuffer:(BOOL *)shouldPreBufferPtr +{ + NSUInteger result; + + if (readLength > 0) + { + // Read a specific length of data + + result = MIN(defaultValue, (readLength - bytesDone)); + + // There is no need to prebuffer since we know exactly how much data we need to read. + // Even if the buffer isn't currently big enough to fit this amount of data, + // it would have to be resized eventually anyway. + + if (shouldPreBufferPtr) + *shouldPreBufferPtr = NO; + } + else + { + // Either reading until we find a specified terminator, + // or we're simply reading all available data. + // + // In other words, one of: + // + // - readDataToData packet + // - readDataWithTimeout packet + + if (maxLength > 0) + result = MIN(defaultValue, (maxLength - bytesDone)); + else + result = defaultValue; + + // Since we don't know the size of the read in advance, + // the shouldPreBuffer decision is based upon whether the returned value would fit + // in the current buffer without requiring a resize of the buffer. + // + // This is because, in all likelyhood, the amount read from the socket will be less than the default value. + // Thus we should avoid over-allocating the read buffer when we can simply use the pre-buffer instead. + + if (shouldPreBufferPtr) + { + NSUInteger buffSize = [buffer length]; + NSUInteger buffUsed = startOffset + bytesDone; + + NSUInteger buffSpace = buffSize - buffUsed; + + if (buffSpace >= result) + *shouldPreBufferPtr = NO; + else + *shouldPreBufferPtr = YES; + } + } + + return result; +} + +/** + * For read packets without a set terminator, returns the amount of data + * that can be read without exceeding the readLength or maxLength. + * + * The given parameter indicates the number of bytes estimated to be available on the socket, + * which is taken into consideration during the calculation. + * + * The given hint MUST be greater than zero. +**/ +- (NSUInteger)readLengthForNonTermWithHint:(NSUInteger)bytesAvailable +{ + NSAssert(term == nil, @"This method does not apply to term reads"); + NSAssert(bytesAvailable > 0, @"Invalid parameter: bytesAvailable"); + + if (readLength > 0) + { + // Read a specific length of data + + return MIN(bytesAvailable, (readLength - bytesDone)); + + // No need to avoid resizing the buffer. + // If the user provided their own buffer, + // and told us to read a certain length of data that exceeds the size of the buffer, + // then it is clear that our code will resize the buffer during the read operation. + // + // This method does not actually do any resizing. + // The resizing will happen elsewhere if needed. + } + else + { + // Read all available data + + NSUInteger result = bytesAvailable; + + if (maxLength > 0) + { + result = MIN(result, (maxLength - bytesDone)); + } + + // No need to avoid resizing the buffer. + // If the user provided their own buffer, + // and told us to read all available data without giving us a maxLength, + // then it is clear that our code might resize the buffer during the read operation. + // + // This method does not actually do any resizing. + // The resizing will happen elsewhere if needed. + + return result; + } +} + +/** + * For read packets with a set terminator, returns the amount of data + * that can be read without exceeding the maxLength. + * + * The given parameter indicates the number of bytes estimated to be available on the socket, + * which is taken into consideration during the calculation. + * + * To optimize memory allocations, mem copies, and mem moves + * the shouldPreBuffer boolean value will indicate if the data should be read into a prebuffer first, + * or if the data can be read directly into the read packet's buffer. +**/ +- (NSUInteger)readLengthForTermWithHint:(NSUInteger)bytesAvailable shouldPreBuffer:(BOOL *)shouldPreBufferPtr +{ + NSAssert(term != nil, @"This method does not apply to non-term reads"); + NSAssert(bytesAvailable > 0, @"Invalid parameter: bytesAvailable"); + + + NSUInteger result = bytesAvailable; + + if (maxLength > 0) + { + result = MIN(result, (maxLength - bytesDone)); + } + + // Should the data be read into the read packet's buffer, or into a pre-buffer first? + // + // One would imagine the preferred option is the faster one. + // So which one is faster? + // + // Reading directly into the packet's buffer requires: + // 1. Possibly resizing packet buffer (malloc/realloc) + // 2. Filling buffer (read) + // 3. Searching for term (memcmp) + // 4. Possibly copying overflow into prebuffer (malloc/realloc, memcpy) + // + // Reading into prebuffer first: + // 1. Possibly resizing prebuffer (malloc/realloc) + // 2. Filling buffer (read) + // 3. Searching for term (memcmp) + // 4. Copying underflow into packet buffer (malloc/realloc, memcpy) + // 5. Removing underflow from prebuffer (memmove) + // + // Comparing the performance of the two we can see that reading + // data into the prebuffer first is slower due to the extra memove. + // + // However: + // The implementation of NSMutableData is open source via core foundation's CFMutableData. + // Decreasing the length of a mutable data object doesn't cause a realloc. + // In other words, the capacity of a mutable data object can grow, but doesn't shrink. + // + // This means the prebuffer will rarely need a realloc. + // The packet buffer, on the other hand, may often need a realloc. + // This is especially true if we are the buffer owner. + // Furthermore, if we are constantly realloc'ing the packet buffer, + // and then moving the overflow into the prebuffer, + // then we're consistently over-allocating memory for each term read. + // And now we get into a bit of a tradeoff between speed and memory utilization. + // + // The end result is that the two perform very similarly. + // And we can answer the original question very simply by another means. + // + // If we can read all the data directly into the packet's buffer without resizing it first, + // then we do so. Otherwise we use the prebuffer. + + if (shouldPreBufferPtr) + { + NSUInteger buffSize = [buffer length]; + NSUInteger buffUsed = startOffset + bytesDone; + + if ((buffSize - buffUsed) >= result) + *shouldPreBufferPtr = NO; + else + *shouldPreBufferPtr = YES; + } + + return result; +} + +/** + * For read packets with a set terminator, + * returns the amount of data that can be read from the given preBuffer, + * without going over a terminator or the maxLength. + * + * It is assumed the terminator has not already been read. +**/ +- (NSUInteger)readLengthForTermWithPreBuffer:(GCDAsyncSocketPreBuffer *)preBuffer found:(BOOL *)foundPtr +{ + NSAssert(term != nil, @"This method does not apply to non-term reads"); + NSAssert([preBuffer availableBytes] > 0, @"Invoked with empty pre buffer!"); + + // We know that the terminator, as a whole, doesn't exist in our own buffer. + // But it is possible that a _portion_ of it exists in our buffer. + // So we're going to look for the terminator starting with a portion of our own buffer. + // + // Example: + // + // term length = 3 bytes + // bytesDone = 5 bytes + // preBuffer length = 5 bytes + // + // If we append the preBuffer to our buffer, + // it would look like this: + // + // --------------------- + // |B|B|B|B|B|P|P|P|P|P| + // --------------------- + // + // So we start our search here: + // + // --------------------- + // |B|B|B|B|B|P|P|P|P|P| + // -------^-^-^--------- + // + // And move forwards... + // + // --------------------- + // |B|B|B|B|B|P|P|P|P|P| + // ---------^-^-^------- + // + // Until we find the terminator or reach the end. + // + // --------------------- + // |B|B|B|B|B|P|P|P|P|P| + // ---------------^-^-^- + + BOOL found = NO; + + NSUInteger termLength = [term length]; + NSUInteger preBufferLength = [preBuffer availableBytes]; + + if ((bytesDone + preBufferLength) < termLength) + { + // Not enough data for a full term sequence yet + return preBufferLength; + } + + NSUInteger maxPreBufferLength; + if (maxLength > 0) { + maxPreBufferLength = MIN(preBufferLength, (maxLength - bytesDone)); + + // Note: maxLength >= termLength + } + else { + maxPreBufferLength = preBufferLength; + } + + uint8_t seq[termLength]; + const void *termBuf = [term bytes]; + + NSUInteger bufLen = MIN(bytesDone, (termLength - 1)); + uint8_t *buf = (uint8_t *)[buffer mutableBytes] + startOffset + bytesDone - bufLen; + + NSUInteger preLen = termLength - bufLen; + const uint8_t *pre = [preBuffer readBuffer]; + + NSUInteger loopCount = bufLen + maxPreBufferLength - termLength + 1; // Plus one. See example above. + + NSUInteger result = maxPreBufferLength; + + NSUInteger i; + for (i = 0; i < loopCount; i++) + { + if (bufLen > 0) + { + // Combining bytes from buffer and preBuffer + + memcpy(seq, buf, bufLen); + memcpy(seq + bufLen, pre, preLen); + + if (memcmp(seq, termBuf, termLength) == 0) + { + result = preLen; + found = YES; + break; + } + + buf++; + bufLen--; + preLen++; + } + else + { + // Comparing directly from preBuffer + + if (memcmp(pre, termBuf, termLength) == 0) + { + NSUInteger preOffset = pre - [preBuffer readBuffer]; // pointer arithmetic + + result = preOffset + termLength; + found = YES; + break; + } + + pre++; + } + } + + // There is no need to avoid resizing the buffer in this particular situation. + + if (foundPtr) *foundPtr = found; + return result; +} + +/** + * For read packets with a set terminator, scans the packet buffer for the term. + * It is assumed the terminator had not been fully read prior to the new bytes. + * + * If the term is found, the number of excess bytes after the term are returned. + * If the term is not found, this method will return -1. + * + * Note: A return value of zero means the term was found at the very end. + * + * Prerequisites: + * The given number of bytes have been added to the end of our buffer. + * Our bytesDone variable has NOT been changed due to the prebuffered bytes. +**/ +- (NSInteger)searchForTermAfterPreBuffering:(ssize_t)numBytes +{ + NSAssert(term != nil, @"This method does not apply to non-term reads"); + + // The implementation of this method is very similar to the above method. + // See the above method for a discussion of the algorithm used here. + + uint8_t *buff = [buffer mutableBytes]; + NSUInteger buffLength = bytesDone + numBytes; + + const void *termBuff = [term bytes]; + NSUInteger termLength = [term length]; + + // Note: We are dealing with unsigned integers, + // so make sure the math doesn't go below zero. + + NSUInteger i = ((buffLength - numBytes) >= termLength) ? (buffLength - numBytes - termLength + 1) : 0; + + while (i + termLength <= buffLength) + { + uint8_t *subBuffer = buff + startOffset + i; + + if (memcmp(subBuffer, termBuff, termLength) == 0) + { + return buffLength - (i + termLength); + } + + i++; + } + + return -1; +} + + +@end + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +#pragma mark - +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +/** + * The GCDAsyncWritePacket encompasses the instructions for any given write. +**/ +@interface GCDAsyncWritePacket : NSObject +{ + @public + NSData *buffer; + NSUInteger bytesDone; + long tag; + NSTimeInterval timeout; +} +- (id)initWithData:(NSData *)d timeout:(NSTimeInterval)t tag:(long)i; +@end + +@implementation GCDAsyncWritePacket + +- (id)initWithData:(NSData *)d timeout:(NSTimeInterval)t tag:(long)i +{ + if((self = [super init])) + { + buffer = d; // Retain not copy. For performance as documented in header file. + bytesDone = 0; + timeout = t; + tag = i; + } + return self; +} + + +@end + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +#pragma mark - +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +/** + * The GCDAsyncSpecialPacket encompasses special instructions for interruptions in the read/write queues. + * This class my be altered to support more than just TLS in the future. +**/ +@interface GCDAsyncSpecialPacket : NSObject +{ + @public + NSDictionary *tlsSettings; +} +- (id)initWithTLSSettings:(NSDictionary *)settings; +@end + +@implementation GCDAsyncSpecialPacket + +- (id)initWithTLSSettings:(NSDictionary *)settings +{ + if((self = [super init])) + { + tlsSettings = [settings copy]; + } + return self; +} + + +@end + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +#pragma mark - +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +@implementation GCDAsyncSocket + +- (id)init +{ + return [self initWithDelegate:nil delegateQueue:NULL socketQueue:NULL]; +} + +- (id)initWithSocketQueue:(dispatch_queue_t)sq +{ + return [self initWithDelegate:nil delegateQueue:NULL socketQueue:sq]; +} + +- (id)initWithDelegate:(id)aDelegate delegateQueue:(dispatch_queue_t)dq +{ + return [self initWithDelegate:aDelegate delegateQueue:dq socketQueue:NULL]; +} + +- (id)initWithDelegate:(id)aDelegate delegateQueue:(dispatch_queue_t)dq socketQueue:(dispatch_queue_t)sq +{ + if((self = [super init])) + { + delegate = aDelegate; + delegateQueue = dq; + + #if !OS_OBJECT_USE_OBJC + if (dq) dispatch_retain(dq); + #endif + + socket4FD = SOCKET_NULL; + socket6FD = SOCKET_NULL; + connectIndex = 0; + + if (sq) + { + NSAssert(sq != dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_LOW, 0), + @"The given socketQueue parameter must not be a concurrent queue."); + NSAssert(sq != dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0), + @"The given socketQueue parameter must not be a concurrent queue."); + NSAssert(sq != dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), + @"The given socketQueue parameter must not be a concurrent queue."); + + socketQueue = sq; + #if !OS_OBJECT_USE_OBJC + dispatch_retain(sq); + #endif + } + else + { + socketQueue = dispatch_queue_create([GCDAsyncSocketQueueName UTF8String], NULL); + } + + // The dispatch_queue_set_specific() and dispatch_get_specific() functions take a "void *key" parameter. + // From the documentation: + // + // > Keys are only compared as pointers and are never dereferenced. + // > Thus, you can use a pointer to a static variable for a specific subsystem or + // > any other value that allows you to identify the value uniquely. + // + // We're just going to use the memory address of an ivar. + // Specifically an ivar that is explicitly named for our purpose to make the code more readable. + // + // However, it feels tedious (and less readable) to include the "&" all the time: + // dispatch_get_specific(&IsOnSocketQueueOrTargetQueueKey) + // + // So we're going to make it so it doesn't matter if we use the '&' or not, + // by assigning the value of the ivar to the address of the ivar. + // Thus: IsOnSocketQueueOrTargetQueueKey == &IsOnSocketQueueOrTargetQueueKey; + + IsOnSocketQueueOrTargetQueueKey = &IsOnSocketQueueOrTargetQueueKey; + + void *nonNullUnusedPointer = (__bridge void *)self; + dispatch_queue_set_specific(socketQueue, IsOnSocketQueueOrTargetQueueKey, nonNullUnusedPointer, NULL); + + readQueue = [[NSMutableArray alloc] initWithCapacity:5]; + currentRead = nil; + + writeQueue = [[NSMutableArray alloc] initWithCapacity:5]; + currentWrite = nil; + + preBuffer = [[GCDAsyncSocketPreBuffer alloc] initWithCapacity:(1024 * 4)]; + } + return self; +} + +- (void)dealloc +{ + LogInfo(@"%@ - %@ (start)", THIS_METHOD, self); + + if (dispatch_get_specific(IsOnSocketQueueOrTargetQueueKey)) + { + [self closeWithError:nil]; + } + else + { + dispatch_sync(socketQueue, ^{ + [self closeWithError:nil]; + }); + } + + delegate = nil; + + #if !OS_OBJECT_USE_OBJC + if (delegateQueue) dispatch_release(delegateQueue); + #endif + delegateQueue = NULL; + + #if !OS_OBJECT_USE_OBJC + if (socketQueue) dispatch_release(socketQueue); + #endif + socketQueue = NULL; + + LogInfo(@"%@ - %@ (finish)", THIS_METHOD, self); +} + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +#pragma mark Configuration +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +- (id)delegate +{ + if (dispatch_get_specific(IsOnSocketQueueOrTargetQueueKey)) + { + return delegate; + } + else + { + __block id result; + + dispatch_sync(socketQueue, ^{ + result = delegate; + }); + + return result; + } +} + +- (void)setDelegate:(id)newDelegate synchronously:(BOOL)synchronously +{ + dispatch_block_t block = ^{ + delegate = newDelegate; + }; + + if (dispatch_get_specific(IsOnSocketQueueOrTargetQueueKey)) { + block(); + } + else { + if (synchronously) + dispatch_sync(socketQueue, block); + else + dispatch_async(socketQueue, block); + } +} + +- (void)setDelegate:(id)newDelegate +{ + [self setDelegate:newDelegate synchronously:NO]; +} + +- (void)synchronouslySetDelegate:(id)newDelegate +{ + [self setDelegate:newDelegate synchronously:YES]; +} + +- (dispatch_queue_t)delegateQueue +{ + if (dispatch_get_specific(IsOnSocketQueueOrTargetQueueKey)) + { + return delegateQueue; + } + else + { + __block dispatch_queue_t result; + + dispatch_sync(socketQueue, ^{ + result = delegateQueue; + }); + + return result; + } +} + +- (void)setDelegateQueue:(dispatch_queue_t)newDelegateQueue synchronously:(BOOL)synchronously +{ + dispatch_block_t block = ^{ + + #if !OS_OBJECT_USE_OBJC + if (delegateQueue) dispatch_release(delegateQueue); + if (newDelegateQueue) dispatch_retain(newDelegateQueue); + #endif + + delegateQueue = newDelegateQueue; + }; + + if (dispatch_get_specific(IsOnSocketQueueOrTargetQueueKey)) { + block(); + } + else { + if (synchronously) + dispatch_sync(socketQueue, block); + else + dispatch_async(socketQueue, block); + } +} + +- (void)setDelegateQueue:(dispatch_queue_t)newDelegateQueue +{ + [self setDelegateQueue:newDelegateQueue synchronously:NO]; +} + +- (void)synchronouslySetDelegateQueue:(dispatch_queue_t)newDelegateQueue +{ + [self setDelegateQueue:newDelegateQueue synchronously:YES]; +} + +- (void)getDelegate:(id *)delegatePtr delegateQueue:(dispatch_queue_t *)delegateQueuePtr +{ + if (dispatch_get_specific(IsOnSocketQueueOrTargetQueueKey)) + { + if (delegatePtr) *delegatePtr = delegate; + if (delegateQueuePtr) *delegateQueuePtr = delegateQueue; + } + else + { + __block id dPtr = NULL; + __block dispatch_queue_t dqPtr = NULL; + + dispatch_sync(socketQueue, ^{ + dPtr = delegate; + dqPtr = delegateQueue; + }); + + if (delegatePtr) *delegatePtr = dPtr; + if (delegateQueuePtr) *delegateQueuePtr = dqPtr; + } +} + +- (void)setDelegate:(id)newDelegate delegateQueue:(dispatch_queue_t)newDelegateQueue synchronously:(BOOL)synchronously +{ + dispatch_block_t block = ^{ + + delegate = newDelegate; + + #if !OS_OBJECT_USE_OBJC + if (delegateQueue) dispatch_release(delegateQueue); + if (newDelegateQueue) dispatch_retain(newDelegateQueue); + #endif + + delegateQueue = newDelegateQueue; + }; + + if (dispatch_get_specific(IsOnSocketQueueOrTargetQueueKey)) { + block(); + } + else { + if (synchronously) + dispatch_sync(socketQueue, block); + else + dispatch_async(socketQueue, block); + } +} + +- (void)setDelegate:(id)newDelegate delegateQueue:(dispatch_queue_t)newDelegateQueue +{ + [self setDelegate:newDelegate delegateQueue:newDelegateQueue synchronously:NO]; +} + +- (void)synchronouslySetDelegate:(id)newDelegate delegateQueue:(dispatch_queue_t)newDelegateQueue +{ + [self setDelegate:newDelegate delegateQueue:newDelegateQueue synchronously:YES]; +} + +- (BOOL)isIPv4Enabled +{ + // Note: YES means kIPv4Disabled is OFF + + if (dispatch_get_specific(IsOnSocketQueueOrTargetQueueKey)) + { + return ((config & kIPv4Disabled) == 0); + } + else + { + __block BOOL result; + + dispatch_sync(socketQueue, ^{ + result = ((config & kIPv4Disabled) == 0); + }); + + return result; + } +} + +- (void)setIPv4Enabled:(BOOL)flag +{ + // Note: YES means kIPv4Disabled is OFF + + dispatch_block_t block = ^{ + + if (flag) + config &= ~kIPv4Disabled; + else + config |= kIPv4Disabled; + }; + + if (dispatch_get_specific(IsOnSocketQueueOrTargetQueueKey)) + block(); + else + dispatch_async(socketQueue, block); +} + +- (BOOL)isIPv6Enabled +{ + // Note: YES means kIPv6Disabled is OFF + + if (dispatch_get_specific(IsOnSocketQueueOrTargetQueueKey)) + { + return ((config & kIPv6Disabled) == 0); + } + else + { + __block BOOL result; + + dispatch_sync(socketQueue, ^{ + result = ((config & kIPv6Disabled) == 0); + }); + + return result; + } +} + +- (void)setIPv6Enabled:(BOOL)flag +{ + // Note: YES means kIPv6Disabled is OFF + + dispatch_block_t block = ^{ + + if (flag) + config &= ~kIPv6Disabled; + else + config |= kIPv6Disabled; + }; + + if (dispatch_get_specific(IsOnSocketQueueOrTargetQueueKey)) + block(); + else + dispatch_async(socketQueue, block); +} + +- (BOOL)isIPv4PreferredOverIPv6 +{ + // Note: YES means kPreferIPv6 is OFF + + if (dispatch_get_specific(IsOnSocketQueueOrTargetQueueKey)) + { + return ((config & kPreferIPv6) == 0); + } + else + { + __block BOOL result; + + dispatch_sync(socketQueue, ^{ + result = ((config & kPreferIPv6) == 0); + }); + + return result; + } +} + +- (void)setPreferIPv4OverIPv6:(BOOL)flag +{ + // Note: YES means kPreferIPv6 is OFF + + dispatch_block_t block = ^{ + + if (flag) + config &= ~kPreferIPv6; + else + config |= kPreferIPv6; + }; + + if (dispatch_get_specific(IsOnSocketQueueOrTargetQueueKey)) + block(); + else + dispatch_async(socketQueue, block); +} + +- (id)userData +{ + __block id result = nil; + + dispatch_block_t block = ^{ + + result = userData; + }; + + if (dispatch_get_specific(IsOnSocketQueueOrTargetQueueKey)) + block(); + else + dispatch_sync(socketQueue, block); + + return result; +} + +- (void)setUserData:(id)arbitraryUserData +{ + dispatch_block_t block = ^{ + + if (userData != arbitraryUserData) + { + userData = arbitraryUserData; + } + }; + + if (dispatch_get_specific(IsOnSocketQueueOrTargetQueueKey)) + block(); + else + dispatch_async(socketQueue, block); +} + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +#pragma mark Accepting +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +- (BOOL)acceptOnPort:(uint16_t)port error:(NSError **)errPtr +{ + return [self acceptOnInterface:nil port:port error:errPtr]; +} + +- (BOOL)acceptOnInterface:(NSString *)inInterface port:(uint16_t)port error:(NSError **)errPtr +{ + LogTrace(); + + // Just in-case interface parameter is immutable. + NSString *interface = [inInterface copy]; + + __block BOOL result = NO; + __block NSError *err = nil; + + // CreateSocket Block + // This block will be invoked within the dispatch block below. + + int(^createSocket)(int, NSData*) = ^int (int domain, NSData *interfaceAddr) { + + int socketFD = socket(domain, SOCK_STREAM, 0); + + if (socketFD == SOCKET_NULL) + { + NSString *reason = @"Error in socket() function"; + err = [self errnoErrorWithReason:reason]; + + return SOCKET_NULL; + } + + int status; + + // Set socket options + + status = fcntl(socketFD, F_SETFL, O_NONBLOCK); + if (status == -1) + { + NSString *reason = @"Error enabling non-blocking IO on socket (fcntl)"; + err = [self errnoErrorWithReason:reason]; + + LogVerbose(@"close(socketFD)"); + close(socketFD); + return SOCKET_NULL; + } + + int reuseOn = 1; + status = setsockopt(socketFD, SOL_SOCKET, SO_REUSEADDR, &reuseOn, sizeof(reuseOn)); + if (status == -1) + { + NSString *reason = @"Error enabling address reuse (setsockopt)"; + err = [self errnoErrorWithReason:reason]; + + LogVerbose(@"close(socketFD)"); + close(socketFD); + return SOCKET_NULL; + } + + // Bind socket + + status = bind(socketFD, (const struct sockaddr *)[interfaceAddr bytes], (socklen_t)[interfaceAddr length]); + if (status == -1) + { + NSString *reason = @"Error in bind() function"; + err = [self errnoErrorWithReason:reason]; + + LogVerbose(@"close(socketFD)"); + close(socketFD); + return SOCKET_NULL; + } + + // Listen + + status = listen(socketFD, 1024); + if (status == -1) + { + NSString *reason = @"Error in listen() function"; + err = [self errnoErrorWithReason:reason]; + + LogVerbose(@"close(socketFD)"); + close(socketFD); + return SOCKET_NULL; + } + + return socketFD; + }; + + // Create dispatch block and run on socketQueue + + dispatch_block_t block = ^{ @autoreleasepool { + + if (delegate == nil) // Must have delegate set + { + NSString *msg = @"Attempting to accept without a delegate. Set a delegate first."; + err = [self badConfigError:msg]; + + return_from_block; + } + + if (delegateQueue == NULL) // Must have delegate queue set + { + NSString *msg = @"Attempting to accept without a delegate queue. Set a delegate queue first."; + err = [self badConfigError:msg]; + + return_from_block; + } + + BOOL isIPv4Disabled = (config & kIPv4Disabled) ? YES : NO; + BOOL isIPv6Disabled = (config & kIPv6Disabled) ? YES : NO; + + if (isIPv4Disabled && isIPv6Disabled) // Must have IPv4 or IPv6 enabled + { + NSString *msg = @"Both IPv4 and IPv6 have been disabled. Must enable at least one protocol first."; + err = [self badConfigError:msg]; + + return_from_block; + } + + if (![self isDisconnected]) // Must be disconnected + { + NSString *msg = @"Attempting to accept while connected or accepting connections. Disconnect first."; + err = [self badConfigError:msg]; + + return_from_block; + } + + // Clear queues (spurious read/write requests post disconnect) + [readQueue removeAllObjects]; + [writeQueue removeAllObjects]; + + // Resolve interface from description + + NSMutableData *interface4 = nil; + NSMutableData *interface6 = nil; + + [self getInterfaceAddress4:&interface4 address6:&interface6 fromDescription:interface port:port]; + + if ((interface4 == nil) && (interface6 == nil)) + { + NSString *msg = @"Unknown interface. Specify valid interface by name (e.g. \"en1\") or IP address."; + err = [self badParamError:msg]; + + return_from_block; + } + + if (isIPv4Disabled && (interface6 == nil)) + { + NSString *msg = @"IPv4 has been disabled and specified interface doesn't support IPv6."; + err = [self badParamError:msg]; + + return_from_block; + } + + if (isIPv6Disabled && (interface4 == nil)) + { + NSString *msg = @"IPv6 has been disabled and specified interface doesn't support IPv4."; + err = [self badParamError:msg]; + + return_from_block; + } + + BOOL enableIPv4 = !isIPv4Disabled && (interface4 != nil); + BOOL enableIPv6 = !isIPv6Disabled && (interface6 != nil); + + // Create sockets, configure, bind, and listen + + if (enableIPv4) + { + LogVerbose(@"Creating IPv4 socket"); + socket4FD = createSocket(AF_INET, interface4); + + if (socket4FD == SOCKET_NULL) + { + return_from_block; + } + } + + if (enableIPv6) + { + LogVerbose(@"Creating IPv6 socket"); + + if (enableIPv4 && (port == 0)) + { + // No specific port was specified, so we allowed the OS to pick an available port for us. + // Now we need to make sure the IPv6 socket listens on the same port as the IPv4 socket. + + struct sockaddr_in6 *addr6 = (struct sockaddr_in6 *)[interface6 mutableBytes]; + addr6->sin6_port = htons([self localPort4]); + } + + socket6FD = createSocket(AF_INET6, interface6); + + if (socket6FD == SOCKET_NULL) + { + if (socket4FD != SOCKET_NULL) + { + LogVerbose(@"close(socket4FD)"); + close(socket4FD); + } + + return_from_block; + } + } + + // Create accept sources + + if (enableIPv4) + { + accept4Source = dispatch_source_create(DISPATCH_SOURCE_TYPE_READ, socket4FD, 0, socketQueue); + + int socketFD = socket4FD; + dispatch_source_t acceptSource = accept4Source; + + dispatch_source_set_event_handler(accept4Source, ^{ @autoreleasepool { + + LogVerbose(@"event4Block"); + + unsigned long i = 0; + unsigned long numPendingConnections = dispatch_source_get_data(acceptSource); + + LogVerbose(@"numPendingConnections: %lu", numPendingConnections); + + while ([self doAccept:socketFD] && (++i < numPendingConnections)); + }}); + + dispatch_source_set_cancel_handler(accept4Source, ^{ + + #if !OS_OBJECT_USE_OBJC + LogVerbose(@"dispatch_release(accept4Source)"); + dispatch_release(acceptSource); + #endif + + LogVerbose(@"close(socket4FD)"); + close(socketFD); + }); + + LogVerbose(@"dispatch_resume(accept4Source)"); + dispatch_resume(accept4Source); + } + + if (enableIPv6) + { + accept6Source = dispatch_source_create(DISPATCH_SOURCE_TYPE_READ, socket6FD, 0, socketQueue); + + int socketFD = socket6FD; + dispatch_source_t acceptSource = accept6Source; + + dispatch_source_set_event_handler(accept6Source, ^{ @autoreleasepool { + + LogVerbose(@"event6Block"); + + unsigned long i = 0; + unsigned long numPendingConnections = dispatch_source_get_data(acceptSource); + + LogVerbose(@"numPendingConnections: %lu", numPendingConnections); + + while ([self doAccept:socketFD] && (++i < numPendingConnections)); + }}); + + dispatch_source_set_cancel_handler(accept6Source, ^{ + + #if !OS_OBJECT_USE_OBJC + LogVerbose(@"dispatch_release(accept6Source)"); + dispatch_release(acceptSource); + #endif + + LogVerbose(@"close(socket6FD)"); + close(socketFD); + }); + + LogVerbose(@"dispatch_resume(accept6Source)"); + dispatch_resume(accept6Source); + } + + flags |= kSocketStarted; + + result = YES; + }}; + + if (dispatch_get_specific(IsOnSocketQueueOrTargetQueueKey)) + block(); + else + dispatch_sync(socketQueue, block); + + if (result == NO) + { + LogInfo(@"Error in accept: %@", err); + + if (errPtr) + *errPtr = err; + } + + return result; +} + +- (BOOL)doAccept:(int)parentSocketFD +{ + LogTrace(); + + BOOL isIPv4; + int childSocketFD; + NSData *childSocketAddress; + + if (parentSocketFD == socket4FD) + { + isIPv4 = YES; + + struct sockaddr_in addr; + socklen_t addrLen = sizeof(addr); + + childSocketFD = accept(parentSocketFD, (struct sockaddr *)&addr, &addrLen); + + if (childSocketFD == -1) + { + LogWarn(@"Accept failed with error: %@", [self errnoError]); + return NO; + } + + childSocketAddress = [NSData dataWithBytes:&addr length:addrLen]; + } + else // if (parentSocketFD == socket6FD) + { + isIPv4 = NO; + + struct sockaddr_in6 addr; + socklen_t addrLen = sizeof(addr); + + childSocketFD = accept(parentSocketFD, (struct sockaddr *)&addr, &addrLen); + + if (childSocketFD == -1) + { + LogWarn(@"Accept failed with error: %@", [self errnoError]); + return NO; + } + + childSocketAddress = [NSData dataWithBytes:&addr length:addrLen]; + } + + // Enable non-blocking IO on the socket + + int result = fcntl(childSocketFD, F_SETFL, O_NONBLOCK); + if (result == -1) + { + LogWarn(@"Error enabling non-blocking IO on accepted socket (fcntl)"); + return NO; + } + + // Prevent SIGPIPE signals + + int nosigpipe = 1; + setsockopt(childSocketFD, SOL_SOCKET, SO_NOSIGPIPE, &nosigpipe, sizeof(nosigpipe)); + + // Notify delegate + + if (delegateQueue) + { + __strong id theDelegate = delegate; + + dispatch_async(delegateQueue, ^{ @autoreleasepool { + + // Query delegate for custom socket queue + + dispatch_queue_t childSocketQueue = NULL; + + if ([theDelegate respondsToSelector:@selector(newSocketQueueForConnectionFromAddress:onSocket:)]) + { + childSocketQueue = [theDelegate newSocketQueueForConnectionFromAddress:childSocketAddress + onSocket:self]; + } + + // Create GCDAsyncSocket instance for accepted socket + + GCDAsyncSocket *acceptedSocket = [[GCDAsyncSocket alloc] initWithDelegate:theDelegate + delegateQueue:delegateQueue + socketQueue:childSocketQueue]; + + if (isIPv4) + acceptedSocket->socket4FD = childSocketFD; + else + acceptedSocket->socket6FD = childSocketFD; + + acceptedSocket->flags = (kSocketStarted | kConnected); + + // Setup read and write sources for accepted socket + + dispatch_async(acceptedSocket->socketQueue, ^{ @autoreleasepool { + + [acceptedSocket setupReadAndWriteSourcesForNewlyConnectedSocket:childSocketFD]; + }}); + + // Notify delegate + + if ([theDelegate respondsToSelector:@selector(socket:didAcceptNewSocket:)]) + { + [theDelegate socket:self didAcceptNewSocket:acceptedSocket]; + } + + // Release the socket queue returned from the delegate (it was retained by acceptedSocket) + #if !OS_OBJECT_USE_OBJC + if (childSocketQueue) dispatch_release(childSocketQueue); + #endif + + // The accepted socket should have been retained by the delegate. + // Otherwise it gets properly released when exiting the block. + }}); + } + + return YES; +} + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +#pragma mark Connecting +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +/** + * This method runs through the various checks required prior to a connection attempt. + * It is shared between the connectToHost and connectToAddress methods. + * +**/ +- (BOOL)preConnectWithInterface:(NSString *)interface error:(NSError **)errPtr +{ + NSAssert(dispatch_get_specific(IsOnSocketQueueOrTargetQueueKey), @"Must be dispatched on socketQueue"); + + if (delegate == nil) // Must have delegate set + { + if (errPtr) + { + NSString *msg = @"Attempting to connect without a delegate. Set a delegate first."; + *errPtr = [self badConfigError:msg]; + } + return NO; + } + + if (delegateQueue == NULL) // Must have delegate queue set + { + if (errPtr) + { + NSString *msg = @"Attempting to connect without a delegate queue. Set a delegate queue first."; + *errPtr = [self badConfigError:msg]; + } + return NO; + } + + if (![self isDisconnected]) // Must be disconnected + { + if (errPtr) + { + NSString *msg = @"Attempting to connect while connected or accepting connections. Disconnect first."; + *errPtr = [self badConfigError:msg]; + } + return NO; + } + + BOOL isIPv4Disabled = (config & kIPv4Disabled) ? YES : NO; + BOOL isIPv6Disabled = (config & kIPv6Disabled) ? YES : NO; + + if (isIPv4Disabled && isIPv6Disabled) // Must have IPv4 or IPv6 enabled + { + if (errPtr) + { + NSString *msg = @"Both IPv4 and IPv6 have been disabled. Must enable at least one protocol first."; + *errPtr = [self badConfigError:msg]; + } + return NO; + } + + if (interface) + { + NSMutableData *interface4 = nil; + NSMutableData *interface6 = nil; + + [self getInterfaceAddress4:&interface4 address6:&interface6 fromDescription:interface port:0]; + + if ((interface4 == nil) && (interface6 == nil)) + { + if (errPtr) + { + NSString *msg = @"Unknown interface. Specify valid interface by name (e.g. \"en1\") or IP address."; + *errPtr = [self badParamError:msg]; + } + return NO; + } + + if (isIPv4Disabled && (interface6 == nil)) + { + if (errPtr) + { + NSString *msg = @"IPv4 has been disabled and specified interface doesn't support IPv6."; + *errPtr = [self badParamError:msg]; + } + return NO; + } + + if (isIPv6Disabled && (interface4 == nil)) + { + if (errPtr) + { + NSString *msg = @"IPv6 has been disabled and specified interface doesn't support IPv4."; + *errPtr = [self badParamError:msg]; + } + return NO; + } + + connectInterface4 = interface4; + connectInterface6 = interface6; + } + + // Clear queues (spurious read/write requests post disconnect) + [readQueue removeAllObjects]; + [writeQueue removeAllObjects]; + + return YES; +} + +- (BOOL)connectToHost:(NSString*)host onPort:(uint16_t)port error:(NSError **)errPtr +{ + return [self connectToHost:host onPort:port withTimeout:-1 error:errPtr]; +} + +- (BOOL)connectToHost:(NSString *)host + onPort:(uint16_t)port + withTimeout:(NSTimeInterval)timeout + error:(NSError **)errPtr +{ + return [self connectToHost:host onPort:port viaInterface:nil withTimeout:timeout error:errPtr]; +} + +- (BOOL)connectToHost:(NSString *)inHost + onPort:(uint16_t)port + viaInterface:(NSString *)inInterface + withTimeout:(NSTimeInterval)timeout + error:(NSError **)errPtr +{ + LogTrace(); + + // Just in case immutable objects were passed + NSString *host = [inHost copy]; + NSString *interface = [inInterface copy]; + + __block BOOL result = NO; + __block NSError *err = nil; + + dispatch_block_t block = ^{ @autoreleasepool { + + // Check for problems with host parameter + + if ([host length] == 0) + { + NSString *msg = @"Invalid host parameter (nil or \"\"). Should be a domain name or IP address string."; + err = [self badParamError:msg]; + + return_from_block; + } + + // Run through standard pre-connect checks + + if (![self preConnectWithInterface:interface error:&err]) + { + return_from_block; + } + + // We've made it past all the checks. + // It's time to start the connection process. + + flags |= kSocketStarted; + + LogVerbose(@"Dispatching DNS lookup..."); + + // It's possible that the given host parameter is actually a NSMutableString. + // So we want to copy it now, within this block that will be executed synchronously. + // This way the asynchronous lookup block below doesn't have to worry about it changing. + + int aConnectIndex = connectIndex; + NSString *hostCpy = [host copy]; + + dispatch_queue_t globalConcurrentQueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0); + dispatch_async(globalConcurrentQueue, ^{ @autoreleasepool { + + [self lookup:aConnectIndex host:hostCpy port:port]; + }}); + + [self startConnectTimeout:timeout]; + + result = YES; + }}; + + if (dispatch_get_specific(IsOnSocketQueueOrTargetQueueKey)) + block(); + else + dispatch_sync(socketQueue, block); + + if (result == NO) + { + if (errPtr) + *errPtr = err; + } + + return result; +} + +- (BOOL)connectToAddress:(NSData *)remoteAddr error:(NSError **)errPtr +{ + return [self connectToAddress:remoteAddr viaInterface:nil withTimeout:-1 error:errPtr]; +} + +- (BOOL)connectToAddress:(NSData *)remoteAddr withTimeout:(NSTimeInterval)timeout error:(NSError **)errPtr +{ + return [self connectToAddress:remoteAddr viaInterface:nil withTimeout:timeout error:errPtr]; +} + +- (BOOL)connectToAddress:(NSData *)inRemoteAddr + viaInterface:(NSString *)inInterface + withTimeout:(NSTimeInterval)timeout + error:(NSError **)errPtr +{ + LogTrace(); + + // Just in case immutable objects were passed + NSData *remoteAddr = [inRemoteAddr copy]; + NSString *interface = [inInterface copy]; + + __block BOOL result = NO; + __block NSError *err = nil; + + dispatch_block_t block = ^{ @autoreleasepool { + + // Check for problems with remoteAddr parameter + + NSData *address4 = nil; + NSData *address6 = nil; + + if ([remoteAddr length] >= sizeof(struct sockaddr)) + { + const struct sockaddr *sockaddr = (const struct sockaddr *)[remoteAddr bytes]; + + if (sockaddr->sa_family == AF_INET) + { + if ([remoteAddr length] == sizeof(struct sockaddr_in)) + { + address4 = remoteAddr; + } + } + else if (sockaddr->sa_family == AF_INET6) + { + if ([remoteAddr length] == sizeof(struct sockaddr_in6)) + { + address6 = remoteAddr; + } + } + } + + if ((address4 == nil) && (address6 == nil)) + { + NSString *msg = @"A valid IPv4 or IPv6 address was not given"; + err = [self badParamError:msg]; + + return_from_block; + } + + BOOL isIPv4Disabled = (config & kIPv4Disabled) ? YES : NO; + BOOL isIPv6Disabled = (config & kIPv6Disabled) ? YES : NO; + + if (isIPv4Disabled && (address4 != nil)) + { + NSString *msg = @"IPv4 has been disabled and an IPv4 address was passed."; + err = [self badParamError:msg]; + + return_from_block; + } + + if (isIPv6Disabled && (address6 != nil)) + { + NSString *msg = @"IPv6 has been disabled and an IPv6 address was passed."; + err = [self badParamError:msg]; + + return_from_block; + } + + // Run through standard pre-connect checks + + if (![self preConnectWithInterface:interface error:&err]) + { + return_from_block; + } + + // We've made it past all the checks. + // It's time to start the connection process. + + if (![self connectWithAddress4:address4 address6:address6 error:&err]) + { + return_from_block; + } + + flags |= kSocketStarted; + + [self startConnectTimeout:timeout]; + + result = YES; + }}; + + if (dispatch_get_specific(IsOnSocketQueueOrTargetQueueKey)) + block(); + else + dispatch_sync(socketQueue, block); + + if (result == NO) + { + if (errPtr) + *errPtr = err; + } + + return result; +} + +- (void)lookup:(int)aConnectIndex host:(NSString *)host port:(uint16_t)port +{ + LogTrace(); + + // This method is executed on a global concurrent queue. + // It posts the results back to the socket queue. + // The lookupIndex is used to ignore the results if the connect operation was cancelled or timed out. + + NSError *error = nil; + + NSData *address4 = nil; + NSData *address6 = nil; + + + if ([host isEqualToString:@"localhost"] || [host isEqualToString:@"loopback"]) + { + // Use LOOPBACK address + struct sockaddr_in nativeAddr; + nativeAddr.sin_len = sizeof(struct sockaddr_in); + nativeAddr.sin_family = AF_INET; + nativeAddr.sin_port = htons(port); + nativeAddr.sin_addr.s_addr = htonl(INADDR_LOOPBACK); + memset(&(nativeAddr.sin_zero), 0, sizeof(nativeAddr.sin_zero)); + + struct sockaddr_in6 nativeAddr6; + nativeAddr6.sin6_len = sizeof(struct sockaddr_in6); + nativeAddr6.sin6_family = AF_INET6; + nativeAddr6.sin6_port = htons(port); + nativeAddr6.sin6_flowinfo = 0; + nativeAddr6.sin6_addr = in6addr_loopback; + nativeAddr6.sin6_scope_id = 0; + + // Wrap the native address structures + address4 = [NSData dataWithBytes:&nativeAddr length:sizeof(nativeAddr)]; + address6 = [NSData dataWithBytes:&nativeAddr6 length:sizeof(nativeAddr6)]; + } + else + { + NSString *portStr = [NSString stringWithFormat:@"%hu", port]; + + struct addrinfo hints, *res, *res0; + + memset(&hints, 0, sizeof(hints)); + hints.ai_family = PF_UNSPEC; + hints.ai_socktype = SOCK_STREAM; + hints.ai_protocol = IPPROTO_TCP; + + int gai_error = getaddrinfo([host UTF8String], [portStr UTF8String], &hints, &res0); + + if (gai_error) + { + error = [self gaiError:gai_error]; + } + else + { + for(res = res0; res; res = res->ai_next) + { + if ((address4 == nil) && (res->ai_family == AF_INET)) + { + // Found IPv4 address + // Wrap the native address structure + address4 = [NSData dataWithBytes:res->ai_addr length:res->ai_addrlen]; + } + else if ((address6 == nil) && (res->ai_family == AF_INET6)) + { + // Found IPv6 address + // Wrap the native address structure + address6 = [NSData dataWithBytes:res->ai_addr length:res->ai_addrlen]; + } + } + freeaddrinfo(res0); + + if ((address4 == nil) && (address6 == nil)) + { + error = [self gaiError:EAI_FAIL]; + } + } + } + + if (error) + { + dispatch_async(socketQueue, ^{ @autoreleasepool { + + [self lookup:aConnectIndex didFail:error]; + }}); + } + else + { + dispatch_async(socketQueue, ^{ @autoreleasepool { + + [self lookup:aConnectIndex didSucceedWithAddress4:address4 address6:address6]; + }}); + } +} + +- (void)lookup:(int)aConnectIndex didSucceedWithAddress4:(NSData *)address4 address6:(NSData *)address6 +{ + LogTrace(); + + NSAssert(dispatch_get_specific(IsOnSocketQueueOrTargetQueueKey), @"Must be dispatched on socketQueue"); + NSAssert(address4 || address6, @"Expected at least one valid address"); + + if (aConnectIndex != connectIndex) + { + LogInfo(@"Ignoring lookupDidSucceed, already disconnected"); + + // The connect operation has been cancelled. + // That is, socket was disconnected, or connection has already timed out. + return; + } + + // Check for problems + + BOOL isIPv4Disabled = (config & kIPv4Disabled) ? YES : NO; + BOOL isIPv6Disabled = (config & kIPv6Disabled) ? YES : NO; + + if (isIPv4Disabled && (address6 == nil)) + { + NSString *msg = @"IPv4 has been disabled and DNS lookup found no IPv6 address."; + + [self closeWithError:[self otherError:msg]]; + return; + } + + if (isIPv6Disabled && (address4 == nil)) + { + NSString *msg = @"IPv6 has been disabled and DNS lookup found no IPv4 address."; + + [self closeWithError:[self otherError:msg]]; + return; + } + + // Start the normal connection process + + NSError *err = nil; + if (![self connectWithAddress4:address4 address6:address6 error:&err]) + { + [self closeWithError:err]; + } +} + +/** + * This method is called if the DNS lookup fails. + * This method is executed on the socketQueue. + * + * Since the DNS lookup executed synchronously on a global concurrent queue, + * the original connection request may have already been cancelled or timed-out by the time this method is invoked. + * The lookupIndex tells us whether the lookup is still valid or not. +**/ +- (void)lookup:(int)aConnectIndex didFail:(NSError *)error +{ + LogTrace(); + + NSAssert(dispatch_get_specific(IsOnSocketQueueOrTargetQueueKey), @"Must be dispatched on socketQueue"); + + + if (aConnectIndex != connectIndex) + { + LogInfo(@"Ignoring lookup:didFail: - already disconnected"); + + // The connect operation has been cancelled. + // That is, socket was disconnected, or connection has already timed out. + return; + } + + [self endConnectTimeout]; + [self closeWithError:error]; +} + +- (BOOL)connectWithAddress4:(NSData *)address4 address6:(NSData *)address6 error:(NSError **)errPtr +{ + LogTrace(); + + NSAssert(dispatch_get_specific(IsOnSocketQueueOrTargetQueueKey), @"Must be dispatched on socketQueue"); + + LogVerbose(@"IPv4: %@:%hu", [[self class] hostFromAddress:address4], [[self class] portFromAddress:address4]); + LogVerbose(@"IPv6: %@:%hu", [[self class] hostFromAddress:address6], [[self class] portFromAddress:address6]); + + // Determine socket type + + BOOL preferIPv6 = (config & kPreferIPv6) ? YES : NO; + + BOOL useIPv6 = ((preferIPv6 && address6) || (address4 == nil)); + + // Create the socket + + int socketFD; + NSData *address; + NSData *connectInterface; + + if (useIPv6) + { + LogVerbose(@"Creating IPv6 socket"); + + socket6FD = socket(AF_INET6, SOCK_STREAM, 0); + + socketFD = socket6FD; + address = address6; + connectInterface = connectInterface6; + } + else + { + LogVerbose(@"Creating IPv4 socket"); + + socket4FD = socket(AF_INET, SOCK_STREAM, 0); + + socketFD = socket4FD; + address = address4; + connectInterface = connectInterface4; + } + + if (socketFD == SOCKET_NULL) + { + if (errPtr) + *errPtr = [self errnoErrorWithReason:@"Error in socket() function"]; + + return NO; + } + + // Bind the socket to the desired interface (if needed) + + if (connectInterface) + { + LogVerbose(@"Binding socket..."); + + if ([[self class] portFromAddress:connectInterface] > 0) + { + // Since we're going to be binding to a specific port, + // we should turn on reuseaddr to allow us to override sockets in time_wait. + + int reuseOn = 1; + setsockopt(socketFD, SOL_SOCKET, SO_REUSEADDR, &reuseOn, sizeof(reuseOn)); + } + + const struct sockaddr *interfaceAddr = (const struct sockaddr *)[connectInterface bytes]; + + int result = bind(socketFD, interfaceAddr, (socklen_t)[connectInterface length]); + if (result != 0) + { + if (errPtr) + *errPtr = [self errnoErrorWithReason:@"Error in bind() function"]; + + return NO; + } + } + + // Prevent SIGPIPE signals + + int nosigpipe = 1; + setsockopt(socketFD, SOL_SOCKET, SO_NOSIGPIPE, &nosigpipe, sizeof(nosigpipe)); + + // Start the connection process in a background queue + + int aConnectIndex = connectIndex; + + dispatch_queue_t globalConcurrentQueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0); + dispatch_async(globalConcurrentQueue, ^{ + + int result = connect(socketFD, (const struct sockaddr *)[address bytes], (socklen_t)[address length]); + if (result == 0) + { + dispatch_async(socketQueue, ^{ @autoreleasepool { + + [self didConnect:aConnectIndex]; + }}); + } + else + { + NSError *error = [self errnoErrorWithReason:@"Error in connect() function"]; + + dispatch_async(socketQueue, ^{ @autoreleasepool { + + [self didNotConnect:aConnectIndex error:error]; + }}); + } + }); + + LogVerbose(@"Connecting..."); + + return YES; +} + +- (void)didConnect:(int)aConnectIndex +{ + LogTrace(); + + NSAssert(dispatch_get_specific(IsOnSocketQueueOrTargetQueueKey), @"Must be dispatched on socketQueue"); + + + if (aConnectIndex != connectIndex) + { + LogInfo(@"Ignoring didConnect, already disconnected"); + + // The connect operation has been cancelled. + // That is, socket was disconnected, or connection has already timed out. + return; + } + + flags |= kConnected; + + [self endConnectTimeout]; + + #if TARGET_OS_IPHONE + // The endConnectTimeout method executed above incremented the connectIndex. + aConnectIndex = connectIndex; + #endif + + // Setup read/write streams (as workaround for specific shortcomings in the iOS platform) + // + // Note: + // There may be configuration options that must be set by the delegate before opening the streams. + // The primary example is the kCFStreamNetworkServiceTypeVoIP flag, which only works on an unopened stream. + // + // Thus we wait until after the socket:didConnectToHost:port: delegate method has completed. + // This gives the delegate time to properly configure the streams if needed. + + dispatch_block_t SetupStreamsPart1 = ^{ + #if TARGET_OS_IPHONE + + if (![self createReadAndWriteStream]) + { + [self closeWithError:[self otherError:@"Error creating CFStreams"]]; + return; + } + + if (![self registerForStreamCallbacksIncludingReadWrite:NO]) + { + [self closeWithError:[self otherError:@"Error in CFStreamSetClient"]]; + return; + } + + #endif + }; + dispatch_block_t SetupStreamsPart2 = ^{ + #if TARGET_OS_IPHONE + + if (aConnectIndex != connectIndex) + { + // The socket has been disconnected. + return; + } + + if (![self addStreamsToRunLoop]) + { + [self closeWithError:[self otherError:@"Error in CFStreamScheduleWithRunLoop"]]; + return; + } + + if (![self openStreams]) + { + [self closeWithError:[self otherError:@"Error creating CFStreams"]]; + return; + } + + #endif + }; + + // Notify delegate + + NSString *host = [self connectedHost]; + uint16_t port = [self connectedPort]; + + __strong id theDelegate = delegate; + + if (delegateQueue && [theDelegate respondsToSelector:@selector(socket:didConnectToHost:port:)]) + { + SetupStreamsPart1(); + + dispatch_async(delegateQueue, ^{ @autoreleasepool { + + [theDelegate socket:self didConnectToHost:host port:port]; + + dispatch_async(socketQueue, ^{ @autoreleasepool { + + SetupStreamsPart2(); + }}); + }}); + } + else + { + SetupStreamsPart1(); + SetupStreamsPart2(); + } + + // Get the connected socket + + int socketFD = (socket4FD != SOCKET_NULL) ? socket4FD : socket6FD; + + // Enable non-blocking IO on the socket + + int result = fcntl(socketFD, F_SETFL, O_NONBLOCK); + if (result == -1) + { + NSString *errMsg = @"Error enabling non-blocking IO on socket (fcntl)"; + [self closeWithError:[self otherError:errMsg]]; + + return; + } + + // Setup our read/write sources + + [self setupReadAndWriteSourcesForNewlyConnectedSocket:socketFD]; + + // Dequeue any pending read/write requests + + [self maybeDequeueRead]; + [self maybeDequeueWrite]; +} + +- (void)didNotConnect:(int)aConnectIndex error:(NSError *)error +{ + LogTrace(); + + NSAssert(dispatch_get_specific(IsOnSocketQueueOrTargetQueueKey), @"Must be dispatched on socketQueue"); + + + if (aConnectIndex != connectIndex) + { + LogInfo(@"Ignoring didNotConnect, already disconnected"); + + // The connect operation has been cancelled. + // That is, socket was disconnected, or connection has already timed out. + return; + } + + [self closeWithError:error]; +} + +- (void)startConnectTimeout:(NSTimeInterval)timeout +{ + if (timeout >= 0.0) + { + connectTimer = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0, socketQueue); + + dispatch_source_set_event_handler(connectTimer, ^{ @autoreleasepool { + + [self doConnectTimeout]; + }}); + + #if !OS_OBJECT_USE_OBJC + dispatch_source_t theConnectTimer = connectTimer; + dispatch_source_set_cancel_handler(connectTimer, ^{ + LogVerbose(@"dispatch_release(connectTimer)"); + dispatch_release(theConnectTimer); + }); + #endif + + dispatch_time_t tt = dispatch_time(DISPATCH_TIME_NOW, (int64_t)(timeout * NSEC_PER_SEC)); + dispatch_source_set_timer(connectTimer, tt, DISPATCH_TIME_FOREVER, 0); + + dispatch_resume(connectTimer); + } +} + +- (void)endConnectTimeout +{ + LogTrace(); + + if (connectTimer) + { + dispatch_source_cancel(connectTimer); + connectTimer = NULL; + } + + // Increment connectIndex. + // This will prevent us from processing results from any related background asynchronous operations. + // + // Note: This should be called from close method even if connectTimer is NULL. + // This is because one might disconnect a socket prior to a successful connection which had no timeout. + + connectIndex++; + + if (connectInterface4) + { + connectInterface4 = nil; + } + if (connectInterface6) + { + connectInterface6 = nil; + } +} + +- (void)doConnectTimeout +{ + LogTrace(); + + [self endConnectTimeout]; + [self closeWithError:[self connectTimeoutError]]; +} + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +#pragma mark Disconnecting +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +- (void)closeWithError:(NSError *)error +{ + LogTrace(); + + NSAssert(dispatch_get_specific(IsOnSocketQueueOrTargetQueueKey), @"Must be dispatched on socketQueue"); + + + [self endConnectTimeout]; + + if (currentRead != nil) [self endCurrentRead]; + if (currentWrite != nil) [self endCurrentWrite]; + + [readQueue removeAllObjects]; + [writeQueue removeAllObjects]; + + [preBuffer reset]; + + #if TARGET_OS_IPHONE + { + if (readStream || writeStream) + { + [self removeStreamsFromRunLoop]; + + if (readStream) + { + CFReadStreamSetClient(readStream, kCFStreamEventNone, NULL, NULL); + CFReadStreamClose(readStream); + CFRelease(readStream); + readStream = NULL; + } + if (writeStream) + { + CFWriteStreamSetClient(writeStream, kCFStreamEventNone, NULL, NULL); + CFWriteStreamClose(writeStream); + CFRelease(writeStream); + writeStream = NULL; + } + } + } + #endif + #if SECURE_TRANSPORT_MAYBE_AVAILABLE + { + [sslPreBuffer reset]; + sslErrCode = noErr; + + if (sslContext) + { + // Getting a linker error here about the SSLx() functions? + // You need to add the Security Framework to your application. + + SSLClose(sslContext); + + #if TARGET_OS_IPHONE + CFRelease(sslContext); + #else + SSLDisposeContext(sslContext); + #endif + + sslContext = NULL; + } + } + #endif + + // For some crazy reason (in my opinion), cancelling a dispatch source doesn't + // invoke the cancel handler if the dispatch source is paused. + // So we have to unpause the source if needed. + // This allows the cancel handler to be run, which in turn releases the source and closes the socket. + + if (!accept4Source && !accept6Source && !readSource && !writeSource) + { + LogVerbose(@"manually closing close"); + + if (socket4FD != SOCKET_NULL) + { + LogVerbose(@"close(socket4FD)"); + close(socket4FD); + socket4FD = SOCKET_NULL; + } + + if (socket6FD != SOCKET_NULL) + { + LogVerbose(@"close(socket6FD)"); + close(socket6FD); + socket6FD = SOCKET_NULL; + } + } + else + { + if (accept4Source) + { + LogVerbose(@"dispatch_source_cancel(accept4Source)"); + dispatch_source_cancel(accept4Source); + + // We never suspend accept4Source + + accept4Source = NULL; + } + + if (accept6Source) + { + LogVerbose(@"dispatch_source_cancel(accept6Source)"); + dispatch_source_cancel(accept6Source); + + // We never suspend accept6Source + + accept6Source = NULL; + } + + if (readSource) + { + LogVerbose(@"dispatch_source_cancel(readSource)"); + dispatch_source_cancel(readSource); + + [self resumeReadSource]; + + readSource = NULL; + } + + if (writeSource) + { + LogVerbose(@"dispatch_source_cancel(writeSource)"); + dispatch_source_cancel(writeSource); + + [self resumeWriteSource]; + + writeSource = NULL; + } + + // The sockets will be closed by the cancel handlers of the corresponding source + + socket4FD = SOCKET_NULL; + socket6FD = SOCKET_NULL; + } + + // If the client has passed the connect/accept method, then the connection has at least begun. + // Notify delegate that it is now ending. + BOOL shouldCallDelegate = (flags & kSocketStarted); + + // Clear stored socket info and all flags (config remains as is) + socketFDBytesAvailable = 0; + flags = 0; + + if (shouldCallDelegate) + { + __strong id theDelegate = delegate; + + if (delegateQueue && [theDelegate respondsToSelector: @selector(socketDidDisconnect:withError:)]) + { + dispatch_async(delegateQueue, ^{ @autoreleasepool { + + [theDelegate socketDidDisconnect:self withError:error]; + }}); + } + } +} + +- (void)disconnect +{ + dispatch_block_t block = ^{ @autoreleasepool { + + if (flags & kSocketStarted) + { + [self closeWithError:nil]; + } + }}; + + // Synchronous disconnection, as documented in the header file + + if (dispatch_get_specific(IsOnSocketQueueOrTargetQueueKey)) + block(); + else + dispatch_sync(socketQueue, block); +} + +- (void)disconnectAfterReading +{ + dispatch_async(socketQueue, ^{ @autoreleasepool { + + if (flags & kSocketStarted) + { + flags |= (kForbidReadsWrites | kDisconnectAfterReads); + [self maybeClose]; + } + }}); +} + +- (void)disconnectAfterWriting +{ + dispatch_async(socketQueue, ^{ @autoreleasepool { + + if (flags & kSocketStarted) + { + flags |= (kForbidReadsWrites | kDisconnectAfterWrites); + [self maybeClose]; + } + }}); +} + +- (void)disconnectAfterReadingAndWriting +{ + dispatch_async(socketQueue, ^{ @autoreleasepool { + + if (flags & kSocketStarted) + { + flags |= (kForbidReadsWrites | kDisconnectAfterReads | kDisconnectAfterWrites); + [self maybeClose]; + } + }}); +} + +/** + * Closes the socket if possible. + * That is, if all writes have completed, and we're set to disconnect after writing, + * or if all reads have completed, and we're set to disconnect after reading. +**/ +- (void)maybeClose +{ + NSAssert(dispatch_get_specific(IsOnSocketQueueOrTargetQueueKey), @"Must be dispatched on socketQueue"); + + BOOL shouldClose = NO; + + if (flags & kDisconnectAfterReads) + { + if (([readQueue count] == 0) && (currentRead == nil)) + { + if (flags & kDisconnectAfterWrites) + { + if (([writeQueue count] == 0) && (currentWrite == nil)) + { + shouldClose = YES; + } + } + else + { + shouldClose = YES; + } + } + } + else if (flags & kDisconnectAfterWrites) + { + if (([writeQueue count] == 0) && (currentWrite == nil)) + { + shouldClose = YES; + } + } + + if (shouldClose) + { + [self closeWithError:nil]; + } +} + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +#pragma mark Errors +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +- (NSError *)badConfigError:(NSString *)errMsg +{ + NSDictionary *userInfo = [NSDictionary dictionaryWithObject:errMsg forKey:NSLocalizedDescriptionKey]; + + return [NSError errorWithDomain:GCDAsyncSocketErrorDomain code:GCDAsyncSocketBadConfigError userInfo:userInfo]; +} + +- (NSError *)badParamError:(NSString *)errMsg +{ + NSDictionary *userInfo = [NSDictionary dictionaryWithObject:errMsg forKey:NSLocalizedDescriptionKey]; + + return [NSError errorWithDomain:GCDAsyncSocketErrorDomain code:GCDAsyncSocketBadParamError userInfo:userInfo]; +} + +- (NSError *)gaiError:(int)gai_error +{ + NSString *errMsg = [NSString stringWithCString:gai_strerror(gai_error) encoding:NSASCIIStringEncoding]; + NSDictionary *userInfo = [NSDictionary dictionaryWithObject:errMsg forKey:NSLocalizedDescriptionKey]; + + return [NSError errorWithDomain:@"kCFStreamErrorDomainNetDB" code:gai_error userInfo:userInfo]; +} + +- (NSError *)errnoErrorWithReason:(NSString *)reason +{ + NSString *errMsg = [NSString stringWithUTF8String:strerror(errno)]; + NSDictionary *userInfo = [NSDictionary dictionaryWithObjectsAndKeys:errMsg, NSLocalizedDescriptionKey, + reason, NSLocalizedFailureReasonErrorKey, nil]; + + return [NSError errorWithDomain:NSPOSIXErrorDomain code:errno userInfo:userInfo]; +} + +- (NSError *)errnoError +{ + NSString *errMsg = [NSString stringWithUTF8String:strerror(errno)]; + NSDictionary *userInfo = [NSDictionary dictionaryWithObject:errMsg forKey:NSLocalizedDescriptionKey]; + + return [NSError errorWithDomain:NSPOSIXErrorDomain code:errno userInfo:userInfo]; +} + +- (NSError *)sslError:(OSStatus)ssl_error +{ + NSString *msg = @"Error code definition can be found in Apple's SecureTransport.h"; + NSDictionary *userInfo = [NSDictionary dictionaryWithObject:msg forKey:NSLocalizedRecoverySuggestionErrorKey]; + + return [NSError errorWithDomain:@"kCFStreamErrorDomainSSL" code:ssl_error userInfo:userInfo]; +} + +- (NSError *)connectTimeoutError +{ + NSString *errMsg = NSLocalizedStringWithDefaultValue(@"GCDAsyncSocketConnectTimeoutError", + @"GCDAsyncSocket", [NSBundle mainBundle], + @"Attempt to connect to host timed out", nil); + + NSDictionary *userInfo = [NSDictionary dictionaryWithObject:errMsg forKey:NSLocalizedDescriptionKey]; + + return [NSError errorWithDomain:GCDAsyncSocketErrorDomain code:GCDAsyncSocketConnectTimeoutError userInfo:userInfo]; +} + +/** + * Returns a standard AsyncSocket maxed out error. +**/ +- (NSError *)readMaxedOutError +{ + NSString *errMsg = NSLocalizedStringWithDefaultValue(@"GCDAsyncSocketReadMaxedOutError", + @"GCDAsyncSocket", [NSBundle mainBundle], + @"Read operation reached set maximum length", nil); + + NSDictionary *info = [NSDictionary dictionaryWithObject:errMsg forKey:NSLocalizedDescriptionKey]; + + return [NSError errorWithDomain:GCDAsyncSocketErrorDomain code:GCDAsyncSocketReadMaxedOutError userInfo:info]; +} + +/** + * Returns a standard AsyncSocket write timeout error. +**/ +- (NSError *)readTimeoutError +{ + NSString *errMsg = NSLocalizedStringWithDefaultValue(@"GCDAsyncSocketReadTimeoutError", + @"GCDAsyncSocket", [NSBundle mainBundle], + @"Read operation timed out", nil); + + NSDictionary *userInfo = [NSDictionary dictionaryWithObject:errMsg forKey:NSLocalizedDescriptionKey]; + + return [NSError errorWithDomain:GCDAsyncSocketErrorDomain code:GCDAsyncSocketReadTimeoutError userInfo:userInfo]; +} + +/** + * Returns a standard AsyncSocket write timeout error. +**/ +- (NSError *)writeTimeoutError +{ + NSString *errMsg = NSLocalizedStringWithDefaultValue(@"GCDAsyncSocketWriteTimeoutError", + @"GCDAsyncSocket", [NSBundle mainBundle], + @"Write operation timed out", nil); + + NSDictionary *userInfo = [NSDictionary dictionaryWithObject:errMsg forKey:NSLocalizedDescriptionKey]; + + return [NSError errorWithDomain:GCDAsyncSocketErrorDomain code:GCDAsyncSocketWriteTimeoutError userInfo:userInfo]; +} + +- (NSError *)connectionClosedError +{ + NSString *errMsg = NSLocalizedStringWithDefaultValue(@"GCDAsyncSocketClosedError", + @"GCDAsyncSocket", [NSBundle mainBundle], + @"Socket closed by remote peer", nil); + + NSDictionary *userInfo = [NSDictionary dictionaryWithObject:errMsg forKey:NSLocalizedDescriptionKey]; + + return [NSError errorWithDomain:GCDAsyncSocketErrorDomain code:GCDAsyncSocketClosedError userInfo:userInfo]; +} + +- (NSError *)otherError:(NSString *)errMsg +{ + NSDictionary *userInfo = [NSDictionary dictionaryWithObject:errMsg forKey:NSLocalizedDescriptionKey]; + + return [NSError errorWithDomain:GCDAsyncSocketErrorDomain code:GCDAsyncSocketOtherError userInfo:userInfo]; +} + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +#pragma mark Diagnostics +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +- (BOOL)isDisconnected +{ + __block BOOL result = NO; + + dispatch_block_t block = ^{ + result = (flags & kSocketStarted) ? NO : YES; + }; + + if (dispatch_get_specific(IsOnSocketQueueOrTargetQueueKey)) + block(); + else + dispatch_sync(socketQueue, block); + + return result; +} + +- (BOOL)isConnected +{ + __block BOOL result = NO; + + dispatch_block_t block = ^{ + result = (flags & kConnected) ? YES : NO; + }; + + if (dispatch_get_specific(IsOnSocketQueueOrTargetQueueKey)) + block(); + else + dispatch_sync(socketQueue, block); + + return result; +} + +- (NSString *)connectedHost +{ + if (dispatch_get_specific(IsOnSocketQueueOrTargetQueueKey)) + { + if (socket4FD != SOCKET_NULL) + return [self connectedHostFromSocket4:socket4FD]; + if (socket6FD != SOCKET_NULL) + return [self connectedHostFromSocket6:socket6FD]; + + return nil; + } + else + { + __block NSString *result = nil; + + dispatch_sync(socketQueue, ^{ @autoreleasepool { + + if (socket4FD != SOCKET_NULL) + result = [self connectedHostFromSocket4:socket4FD]; + else if (socket6FD != SOCKET_NULL) + result = [self connectedHostFromSocket6:socket6FD]; + }}); + + return result; + } +} + +- (uint16_t)connectedPort +{ + if (dispatch_get_specific(IsOnSocketQueueOrTargetQueueKey)) + { + if (socket4FD != SOCKET_NULL) + return [self connectedPortFromSocket4:socket4FD]; + if (socket6FD != SOCKET_NULL) + return [self connectedPortFromSocket6:socket6FD]; + + return 0; + } + else + { + __block uint16_t result = 0; + + dispatch_sync(socketQueue, ^{ + // No need for autorelease pool + + if (socket4FD != SOCKET_NULL) + result = [self connectedPortFromSocket4:socket4FD]; + else if (socket6FD != SOCKET_NULL) + result = [self connectedPortFromSocket6:socket6FD]; + }); + + return result; + } +} + +- (NSString *)localHost +{ + if (dispatch_get_specific(IsOnSocketQueueOrTargetQueueKey)) + { + if (socket4FD != SOCKET_NULL) + return [self localHostFromSocket4:socket4FD]; + if (socket6FD != SOCKET_NULL) + return [self localHostFromSocket6:socket6FD]; + + return nil; + } + else + { + __block NSString *result = nil; + + dispatch_sync(socketQueue, ^{ @autoreleasepool { + + if (socket4FD != SOCKET_NULL) + result = [self localHostFromSocket4:socket4FD]; + else if (socket6FD != SOCKET_NULL) + result = [self localHostFromSocket6:socket6FD]; + }}); + + return result; + } +} + +- (uint16_t)localPort +{ + if (dispatch_get_specific(IsOnSocketQueueOrTargetQueueKey)) + { + if (socket4FD != SOCKET_NULL) + return [self localPortFromSocket4:socket4FD]; + if (socket6FD != SOCKET_NULL) + return [self localPortFromSocket6:socket6FD]; + + return 0; + } + else + { + __block uint16_t result = 0; + + dispatch_sync(socketQueue, ^{ + // No need for autorelease pool + + if (socket4FD != SOCKET_NULL) + result = [self localPortFromSocket4:socket4FD]; + else if (socket6FD != SOCKET_NULL) + result = [self localPortFromSocket6:socket6FD]; + }); + + return result; + } +} + +- (NSString *)connectedHost4 +{ + if (socket4FD != SOCKET_NULL) + return [self connectedHostFromSocket4:socket4FD]; + + return nil; +} + +- (NSString *)connectedHost6 +{ + if (socket6FD != SOCKET_NULL) + return [self connectedHostFromSocket6:socket6FD]; + + return nil; +} + +- (uint16_t)connectedPort4 +{ + if (socket4FD != SOCKET_NULL) + return [self connectedPortFromSocket4:socket4FD]; + + return 0; +} + +- (uint16_t)connectedPort6 +{ + if (socket6FD != SOCKET_NULL) + return [self connectedPortFromSocket6:socket6FD]; + + return 0; +} + +- (NSString *)localHost4 +{ + if (socket4FD != SOCKET_NULL) + return [self localHostFromSocket4:socket4FD]; + + return nil; +} + +- (NSString *)localHost6 +{ + if (socket6FD != SOCKET_NULL) + return [self localHostFromSocket6:socket6FD]; + + return nil; +} + +- (uint16_t)localPort4 +{ + if (socket4FD != SOCKET_NULL) + return [self localPortFromSocket4:socket4FD]; + + return 0; +} + +- (uint16_t)localPort6 +{ + if (socket6FD != SOCKET_NULL) + return [self localPortFromSocket6:socket6FD]; + + return 0; +} + +- (NSString *)connectedHostFromSocket4:(int)socketFD +{ + struct sockaddr_in sockaddr4; + socklen_t sockaddr4len = sizeof(sockaddr4); + + if (getpeername(socketFD, (struct sockaddr *)&sockaddr4, &sockaddr4len) < 0) + { + return nil; + } + return [[self class] hostFromSockaddr4:&sockaddr4]; +} + +- (NSString *)connectedHostFromSocket6:(int)socketFD +{ + struct sockaddr_in6 sockaddr6; + socklen_t sockaddr6len = sizeof(sockaddr6); + + if (getpeername(socketFD, (struct sockaddr *)&sockaddr6, &sockaddr6len) < 0) + { + return nil; + } + return [[self class] hostFromSockaddr6:&sockaddr6]; +} + +- (uint16_t)connectedPortFromSocket4:(int)socketFD +{ + struct sockaddr_in sockaddr4; + socklen_t sockaddr4len = sizeof(sockaddr4); + + if (getpeername(socketFD, (struct sockaddr *)&sockaddr4, &sockaddr4len) < 0) + { + return 0; + } + return [[self class] portFromSockaddr4:&sockaddr4]; +} + +- (uint16_t)connectedPortFromSocket6:(int)socketFD +{ + struct sockaddr_in6 sockaddr6; + socklen_t sockaddr6len = sizeof(sockaddr6); + + if (getpeername(socketFD, (struct sockaddr *)&sockaddr6, &sockaddr6len) < 0) + { + return 0; + } + return [[self class] portFromSockaddr6:&sockaddr6]; +} + +- (NSString *)localHostFromSocket4:(int)socketFD +{ + struct sockaddr_in sockaddr4; + socklen_t sockaddr4len = sizeof(sockaddr4); + + if (getsockname(socketFD, (struct sockaddr *)&sockaddr4, &sockaddr4len) < 0) + { + return nil; + } + return [[self class] hostFromSockaddr4:&sockaddr4]; +} + +- (NSString *)localHostFromSocket6:(int)socketFD +{ + struct sockaddr_in6 sockaddr6; + socklen_t sockaddr6len = sizeof(sockaddr6); + + if (getsockname(socketFD, (struct sockaddr *)&sockaddr6, &sockaddr6len) < 0) + { + return nil; + } + return [[self class] hostFromSockaddr6:&sockaddr6]; +} + +- (uint16_t)localPortFromSocket4:(int)socketFD +{ + struct sockaddr_in sockaddr4; + socklen_t sockaddr4len = sizeof(sockaddr4); + + if (getsockname(socketFD, (struct sockaddr *)&sockaddr4, &sockaddr4len) < 0) + { + return 0; + } + return [[self class] portFromSockaddr4:&sockaddr4]; +} + +- (uint16_t)localPortFromSocket6:(int)socketFD +{ + struct sockaddr_in6 sockaddr6; + socklen_t sockaddr6len = sizeof(sockaddr6); + + if (getsockname(socketFD, (struct sockaddr *)&sockaddr6, &sockaddr6len) < 0) + { + return 0; + } + return [[self class] portFromSockaddr6:&sockaddr6]; +} + +- (NSData *)connectedAddress +{ + __block NSData *result = nil; + + dispatch_block_t block = ^{ + if (socket4FD != SOCKET_NULL) + { + struct sockaddr_in sockaddr4; + socklen_t sockaddr4len = sizeof(sockaddr4); + + if (getpeername(socket4FD, (struct sockaddr *)&sockaddr4, &sockaddr4len) == 0) + { + result = [[NSData alloc] initWithBytes:&sockaddr4 length:sockaddr4len]; + } + } + + if (socket6FD != SOCKET_NULL) + { + struct sockaddr_in6 sockaddr6; + socklen_t sockaddr6len = sizeof(sockaddr6); + + if (getpeername(socket6FD, (struct sockaddr *)&sockaddr6, &sockaddr6len) == 0) + { + result = [[NSData alloc] initWithBytes:&sockaddr6 length:sockaddr6len]; + } + } + }; + + if (dispatch_get_specific(IsOnSocketQueueOrTargetQueueKey)) + block(); + else + dispatch_sync(socketQueue, block); + + return result; +} + +- (NSData *)localAddress +{ + __block NSData *result = nil; + + dispatch_block_t block = ^{ + if (socket4FD != SOCKET_NULL) + { + struct sockaddr_in sockaddr4; + socklen_t sockaddr4len = sizeof(sockaddr4); + + if (getsockname(socket4FD, (struct sockaddr *)&sockaddr4, &sockaddr4len) == 0) + { + result = [[NSData alloc] initWithBytes:&sockaddr4 length:sockaddr4len]; + } + } + + if (socket6FD != SOCKET_NULL) + { + struct sockaddr_in6 sockaddr6; + socklen_t sockaddr6len = sizeof(sockaddr6); + + if (getsockname(socket6FD, (struct sockaddr *)&sockaddr6, &sockaddr6len) == 0) + { + result = [[NSData alloc] initWithBytes:&sockaddr6 length:sockaddr6len]; + } + } + }; + + if (dispatch_get_specific(IsOnSocketQueueOrTargetQueueKey)) + block(); + else + dispatch_sync(socketQueue, block); + + return result; +} + +- (BOOL)isIPv4 +{ + if (dispatch_get_specific(IsOnSocketQueueOrTargetQueueKey)) + { + return (socket4FD != SOCKET_NULL); + } + else + { + __block BOOL result = NO; + + dispatch_sync(socketQueue, ^{ + result = (socket4FD != SOCKET_NULL); + }); + + return result; + } +} + +- (BOOL)isIPv6 +{ + if (dispatch_get_specific(IsOnSocketQueueOrTargetQueueKey)) + { + return (socket6FD != SOCKET_NULL); + } + else + { + __block BOOL result = NO; + + dispatch_sync(socketQueue, ^{ + result = (socket6FD != SOCKET_NULL); + }); + + return result; + } +} + +- (BOOL)isSecure +{ + if (dispatch_get_specific(IsOnSocketQueueOrTargetQueueKey)) + { + return (flags & kSocketSecure) ? YES : NO; + } + else + { + __block BOOL result; + + dispatch_sync(socketQueue, ^{ + result = (flags & kSocketSecure) ? YES : NO; + }); + + return result; + } +} + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +#pragma mark Utilities +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +/** + * Finds the address of an interface description. + * An inteface description may be an interface name (en0, en1, lo0) or corresponding IP (192.168.4.34). + * + * The interface description may optionally contain a port number at the end, separated by a colon. + * If a non-zero port parameter is provided, any port number in the interface description is ignored. + * + * The returned value is a 'struct sockaddr' wrapped in an NSMutableData object. +**/ +- (void)getInterfaceAddress4:(NSMutableData **)interfaceAddr4Ptr + address6:(NSMutableData **)interfaceAddr6Ptr + fromDescription:(NSString *)interfaceDescription + port:(uint16_t)port +{ + NSMutableData *addr4 = nil; + NSMutableData *addr6 = nil; + + NSString *interface = nil; + + NSArray *components = [interfaceDescription componentsSeparatedByString:@":"]; + if ([components count] > 0) + { + NSString *temp = [components objectAtIndex:0]; + if ([temp length] > 0) + { + interface = temp; + } + } + if ([components count] > 1 && port == 0) + { + long portL = strtol([[components objectAtIndex:1] UTF8String], NULL, 10); + + if (portL > 0 && portL <= UINT16_MAX) + { + port = (uint16_t)portL; + } + } + + if (interface == nil) + { + // ANY address + + struct sockaddr_in sockaddr4; + memset(&sockaddr4, 0, sizeof(sockaddr4)); + + sockaddr4.sin_len = sizeof(sockaddr4); + sockaddr4.sin_family = AF_INET; + sockaddr4.sin_port = htons(port); + sockaddr4.sin_addr.s_addr = htonl(INADDR_ANY); + + struct sockaddr_in6 sockaddr6; + memset(&sockaddr6, 0, sizeof(sockaddr6)); + + sockaddr6.sin6_len = sizeof(sockaddr6); + sockaddr6.sin6_family = AF_INET6; + sockaddr6.sin6_port = htons(port); + sockaddr6.sin6_addr = in6addr_any; + + addr4 = [NSMutableData dataWithBytes:&sockaddr4 length:sizeof(sockaddr4)]; + addr6 = [NSMutableData dataWithBytes:&sockaddr6 length:sizeof(sockaddr6)]; + } + else if ([interface isEqualToString:@"localhost"] || [interface isEqualToString:@"loopback"]) + { + // LOOPBACK address + + struct sockaddr_in sockaddr4; + memset(&sockaddr4, 0, sizeof(sockaddr4)); + + sockaddr4.sin_len = sizeof(sockaddr4); + sockaddr4.sin_family = AF_INET; + sockaddr4.sin_port = htons(port); + sockaddr4.sin_addr.s_addr = htonl(INADDR_LOOPBACK); + + struct sockaddr_in6 sockaddr6; + memset(&sockaddr6, 0, sizeof(sockaddr6)); + + sockaddr6.sin6_len = sizeof(sockaddr6); + sockaddr6.sin6_family = AF_INET6; + sockaddr6.sin6_port = htons(port); + sockaddr6.sin6_addr = in6addr_loopback; + + addr4 = [NSMutableData dataWithBytes:&sockaddr4 length:sizeof(sockaddr4)]; + addr6 = [NSMutableData dataWithBytes:&sockaddr6 length:sizeof(sockaddr6)]; + } + else + { + const char *iface = [interface UTF8String]; + + struct ifaddrs *addrs; + const struct ifaddrs *cursor; + + if ((getifaddrs(&addrs) == 0)) + { + cursor = addrs; + while (cursor != NULL) + { + if ((addr4 == nil) && (cursor->ifa_addr->sa_family == AF_INET)) + { + // IPv4 + + struct sockaddr_in nativeAddr4; + memcpy(&nativeAddr4, cursor->ifa_addr, sizeof(nativeAddr4)); + + if (strcmp(cursor->ifa_name, iface) == 0) + { + // Name match + + nativeAddr4.sin_port = htons(port); + + addr4 = [NSMutableData dataWithBytes:&nativeAddr4 length:sizeof(nativeAddr4)]; + } + else + { + char ip[INET_ADDRSTRLEN]; + + const char *conversion = inet_ntop(AF_INET, &nativeAddr4.sin_addr, ip, sizeof(ip)); + + if ((conversion != NULL) && (strcmp(ip, iface) == 0)) + { + // IP match + + nativeAddr4.sin_port = htons(port); + + addr4 = [NSMutableData dataWithBytes:&nativeAddr4 length:sizeof(nativeAddr4)]; + } + } + } + else if ((addr6 == nil) && (cursor->ifa_addr->sa_family == AF_INET6)) + { + // IPv6 + + struct sockaddr_in6 nativeAddr6; + memcpy(&nativeAddr6, cursor->ifa_addr, sizeof(nativeAddr6)); + + if (strcmp(cursor->ifa_name, iface) == 0) + { + // Name match + + nativeAddr6.sin6_port = htons(port); + + addr6 = [NSMutableData dataWithBytes:&nativeAddr6 length:sizeof(nativeAddr6)]; + } + else + { + char ip[INET6_ADDRSTRLEN]; + + const char *conversion = inet_ntop(AF_INET6, &nativeAddr6.sin6_addr, ip, sizeof(ip)); + + if ((conversion != NULL) && (strcmp(ip, iface) == 0)) + { + // IP match + + nativeAddr6.sin6_port = htons(port); + + addr6 = [NSMutableData dataWithBytes:&nativeAddr6 length:sizeof(nativeAddr6)]; + } + } + } + + cursor = cursor->ifa_next; + } + + freeifaddrs(addrs); + } + } + + if (interfaceAddr4Ptr) *interfaceAddr4Ptr = addr4; + if (interfaceAddr6Ptr) *interfaceAddr6Ptr = addr6; +} + +- (void)setupReadAndWriteSourcesForNewlyConnectedSocket:(int)socketFD +{ + readSource = dispatch_source_create(DISPATCH_SOURCE_TYPE_READ, socketFD, 0, socketQueue); + writeSource = dispatch_source_create(DISPATCH_SOURCE_TYPE_WRITE, socketFD, 0, socketQueue); + + // Setup event handlers + + dispatch_source_set_event_handler(readSource, ^{ @autoreleasepool { + + LogVerbose(@"readEventBlock"); + + socketFDBytesAvailable = dispatch_source_get_data(readSource); + LogVerbose(@"socketFDBytesAvailable: %lu", socketFDBytesAvailable); + + if (socketFDBytesAvailable > 0) + [self doReadData]; + else + [self doReadEOF]; + }}); + + dispatch_source_set_event_handler(writeSource, ^{ @autoreleasepool { + + LogVerbose(@"writeEventBlock"); + + flags |= kSocketCanAcceptBytes; + [self doWriteData]; + }}); + + // Setup cancel handlers + + __block int socketFDRefCount = 2; + + #if !OS_OBJECT_USE_OBJC + dispatch_source_t theReadSource = readSource; + dispatch_source_t theWriteSource = writeSource; + #endif + + dispatch_source_set_cancel_handler(readSource, ^{ + + LogVerbose(@"readCancelBlock"); + + #if !OS_OBJECT_USE_OBJC + LogVerbose(@"dispatch_release(readSource)"); + dispatch_release(theReadSource); + #endif + + if (--socketFDRefCount == 0) + { + LogVerbose(@"close(socketFD)"); + close(socketFD); + } + }); + + dispatch_source_set_cancel_handler(writeSource, ^{ + + LogVerbose(@"writeCancelBlock"); + + #if !OS_OBJECT_USE_OBJC + LogVerbose(@"dispatch_release(writeSource)"); + dispatch_release(theWriteSource); + #endif + + if (--socketFDRefCount == 0) + { + LogVerbose(@"close(socketFD)"); + close(socketFD); + } + }); + + // We will not be able to read until data arrives. + // But we should be able to write immediately. + + socketFDBytesAvailable = 0; + flags &= ~kReadSourceSuspended; + + LogVerbose(@"dispatch_resume(readSource)"); + dispatch_resume(readSource); + + flags |= kSocketCanAcceptBytes; + flags |= kWriteSourceSuspended; +} + +- (BOOL)usingCFStreamForTLS +{ + #if TARGET_OS_IPHONE + { + if ((flags & kSocketSecure) && (flags & kUsingCFStreamForTLS)) + { + // Due to the fact that Apple doesn't give us the full power of SecureTransport on iOS, + // we are relegated to using the slower, less powerful, and RunLoop based CFStream API. :( Boo! + // + // Thus we're not able to use the GCD read/write sources in this particular scenario. + + return YES; + } + } + #endif + + return NO; +} + +- (BOOL)usingSecureTransportForTLS +{ + #if TARGET_OS_IPHONE + { + return ![self usingCFStreamForTLS]; + } + #endif + + return YES; +} + +- (void)suspendReadSource +{ + if (!(flags & kReadSourceSuspended)) + { + LogVerbose(@"dispatch_suspend(readSource)"); + + dispatch_suspend(readSource); + flags |= kReadSourceSuspended; + } +} + +- (void)resumeReadSource +{ + if (flags & kReadSourceSuspended) + { + LogVerbose(@"dispatch_resume(readSource)"); + + dispatch_resume(readSource); + flags &= ~kReadSourceSuspended; + } +} + +- (void)suspendWriteSource +{ + if (!(flags & kWriteSourceSuspended)) + { + LogVerbose(@"dispatch_suspend(writeSource)"); + + dispatch_suspend(writeSource); + flags |= kWriteSourceSuspended; + } +} + +- (void)resumeWriteSource +{ + if (flags & kWriteSourceSuspended) + { + LogVerbose(@"dispatch_resume(writeSource)"); + + dispatch_resume(writeSource); + flags &= ~kWriteSourceSuspended; + } +} + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +#pragma mark Reading +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +- (void)readDataWithTimeout:(NSTimeInterval)timeout tag:(long)tag +{ + [self readDataWithTimeout:timeout buffer:nil bufferOffset:0 maxLength:0 tag:tag]; +} + +- (void)readDataWithTimeout:(NSTimeInterval)timeout + buffer:(NSMutableData *)buffer + bufferOffset:(NSUInteger)offset + tag:(long)tag +{ + [self readDataWithTimeout:timeout buffer:buffer bufferOffset:offset maxLength:0 tag:tag]; +} + +- (void)readDataWithTimeout:(NSTimeInterval)timeout + buffer:(NSMutableData *)buffer + bufferOffset:(NSUInteger)offset + maxLength:(NSUInteger)length + tag:(long)tag +{ + if (offset > [buffer length]) { + LogWarn(@"Cannot read: offset > [buffer length]"); + return; + } + + GCDAsyncReadPacket *packet = [[GCDAsyncReadPacket alloc] initWithData:buffer + startOffset:offset + maxLength:length + timeout:timeout + readLength:0 + terminator:nil + tag:tag]; + + dispatch_async(socketQueue, ^{ @autoreleasepool { + + LogTrace(); + + if ((flags & kSocketStarted) && !(flags & kForbidReadsWrites)) + { + [readQueue addObject:packet]; + [self maybeDequeueRead]; + } + }}); + + // Do not rely on the block being run in order to release the packet, + // as the queue might get released without the block completing. +} + +- (void)readDataToLength:(NSUInteger)length withTimeout:(NSTimeInterval)timeout tag:(long)tag +{ + [self readDataToLength:length withTimeout:timeout buffer:nil bufferOffset:0 tag:tag]; +} + +- (void)readDataToLength:(NSUInteger)length + withTimeout:(NSTimeInterval)timeout + buffer:(NSMutableData *)buffer + bufferOffset:(NSUInteger)offset + tag:(long)tag +{ + if (length == 0) { + LogWarn(@"Cannot read: length == 0"); + return; + } + if (offset > [buffer length]) { + LogWarn(@"Cannot read: offset > [buffer length]"); + return; + } + + GCDAsyncReadPacket *packet = [[GCDAsyncReadPacket alloc] initWithData:buffer + startOffset:offset + maxLength:0 + timeout:timeout + readLength:length + terminator:nil + tag:tag]; + + dispatch_async(socketQueue, ^{ @autoreleasepool { + + LogTrace(); + + if ((flags & kSocketStarted) && !(flags & kForbidReadsWrites)) + { + [readQueue addObject:packet]; + [self maybeDequeueRead]; + } + }}); + + // Do not rely on the block being run in order to release the packet, + // as the queue might get released without the block completing. +} + +- (void)readDataToData:(NSData *)data withTimeout:(NSTimeInterval)timeout tag:(long)tag +{ + [self readDataToData:data withTimeout:timeout buffer:nil bufferOffset:0 maxLength:0 tag:tag]; +} + +- (void)readDataToData:(NSData *)data + withTimeout:(NSTimeInterval)timeout + buffer:(NSMutableData *)buffer + bufferOffset:(NSUInteger)offset + tag:(long)tag +{ + [self readDataToData:data withTimeout:timeout buffer:buffer bufferOffset:offset maxLength:0 tag:tag]; +} + +- (void)readDataToData:(NSData *)data withTimeout:(NSTimeInterval)timeout maxLength:(NSUInteger)length tag:(long)tag +{ + [self readDataToData:data withTimeout:timeout buffer:nil bufferOffset:0 maxLength:length tag:tag]; +} + +- (void)readDataToData:(NSData *)data + withTimeout:(NSTimeInterval)timeout + buffer:(NSMutableData *)buffer + bufferOffset:(NSUInteger)offset + maxLength:(NSUInteger)maxLength + tag:(long)tag +{ + if ([data length] == 0) { + LogWarn(@"Cannot read: [data length] == 0"); + return; + } + if (offset > [buffer length]) { + LogWarn(@"Cannot read: offset > [buffer length]"); + return; + } + if (maxLength > 0 && maxLength < [data length]) { + LogWarn(@"Cannot read: maxLength > 0 && maxLength < [data length]"); + return; + } + + GCDAsyncReadPacket *packet = [[GCDAsyncReadPacket alloc] initWithData:buffer + startOffset:offset + maxLength:maxLength + timeout:timeout + readLength:0 + terminator:data + tag:tag]; + + dispatch_async(socketQueue, ^{ @autoreleasepool { + + LogTrace(); + + if ((flags & kSocketStarted) && !(flags & kForbidReadsWrites)) + { + [readQueue addObject:packet]; + [self maybeDequeueRead]; + } + }}); + + // Do not rely on the block being run in order to release the packet, + // as the queue might get released without the block completing. +} + +- (float)progressOfReadReturningTag:(long *)tagPtr bytesDone:(NSUInteger *)donePtr total:(NSUInteger *)totalPtr +{ + __block float result = 0.0F; + + dispatch_block_t block = ^{ + + if (!currentRead || ![currentRead isKindOfClass:[GCDAsyncReadPacket class]]) + { + // We're not reading anything right now. + + if (tagPtr != NULL) *tagPtr = 0; + if (donePtr != NULL) *donePtr = 0; + if (totalPtr != NULL) *totalPtr = 0; + + result = NAN; + } + else + { + // It's only possible to know the progress of our read if we're reading to a certain length. + // If we're reading to data, we of course have no idea when the data will arrive. + // If we're reading to timeout, then we have no idea when the next chunk of data will arrive. + + NSUInteger done = currentRead->bytesDone; + NSUInteger total = currentRead->readLength; + + if (tagPtr != NULL) *tagPtr = currentRead->tag; + if (donePtr != NULL) *donePtr = done; + if (totalPtr != NULL) *totalPtr = total; + + if (total > 0) + result = (float)done / (float)total; + else + result = 1.0F; + } + }; + + if (dispatch_get_specific(IsOnSocketQueueOrTargetQueueKey)) + block(); + else + dispatch_sync(socketQueue, block); + + return result; +} + +/** + * This method starts a new read, if needed. + * + * It is called when: + * - a user requests a read + * - after a read request has finished (to handle the next request) + * - immediately after the socket opens to handle any pending requests + * + * This method also handles auto-disconnect post read/write completion. +**/ +- (void)maybeDequeueRead +{ + LogTrace(); + NSAssert(dispatch_get_specific(IsOnSocketQueueOrTargetQueueKey), @"Must be dispatched on socketQueue"); + + // If we're not currently processing a read AND we have an available read stream + if ((currentRead == nil) && (flags & kConnected)) + { + if ([readQueue count] > 0) + { + // Dequeue the next object in the write queue + currentRead = [readQueue objectAtIndex:0]; + [readQueue removeObjectAtIndex:0]; + + + if ([currentRead isKindOfClass:[GCDAsyncSpecialPacket class]]) + { + LogVerbose(@"Dequeued GCDAsyncSpecialPacket"); + + // Attempt to start TLS + flags |= kStartingReadTLS; + + // This method won't do anything unless both kStartingReadTLS and kStartingWriteTLS are set + [self maybeStartTLS]; + } + else + { + LogVerbose(@"Dequeued GCDAsyncReadPacket"); + + // Setup read timer (if needed) + [self setupReadTimerWithTimeout:currentRead->timeout]; + + // Immediately read, if possible + [self doReadData]; + } + } + else if (flags & kDisconnectAfterReads) + { + if (flags & kDisconnectAfterWrites) + { + if (([writeQueue count] == 0) && (currentWrite == nil)) + { + [self closeWithError:nil]; + } + } + else + { + [self closeWithError:nil]; + } + } + else if (flags & kSocketSecure) + { + [self flushSSLBuffers]; + + // Edge case: + // + // We just drained all data from the ssl buffers, + // and all known data from the socket (socketFDBytesAvailable). + // + // If we didn't get any data from this process, + // then we may have reached the end of the TCP stream. + // + // Be sure callbacks are enabled so we're notified about a disconnection. + + if ([preBuffer availableBytes] == 0) + { + if ([self usingCFStreamForTLS]) { + // Callbacks never disabled + } + else { + [self resumeReadSource]; + } + } + } + } +} + +- (void)flushSSLBuffers +{ + LogTrace(); + + NSAssert((flags & kSocketSecure), @"Cannot flush ssl buffers on non-secure socket"); + + if ([preBuffer availableBytes] > 0) + { + // Only flush the ssl buffers if the prebuffer is empty. + // This is to avoid growing the prebuffer inifinitely large. + + return; + } + +#if TARGET_OS_IPHONE + + if ([self usingCFStreamForTLS]) + { + if ((flags & kSecureSocketHasBytesAvailable) && CFReadStreamHasBytesAvailable(readStream)) + { + LogVerbose(@"%@ - Flushing ssl buffers into prebuffer...", THIS_METHOD); + + CFIndex defaultBytesToRead = (1024 * 4); + + [preBuffer ensureCapacityForWrite:defaultBytesToRead]; + + uint8_t *buffer = [preBuffer writeBuffer]; + + CFIndex result = CFReadStreamRead(readStream, buffer, defaultBytesToRead); + LogVerbose(@"%@ - CFReadStreamRead(): result = %i", THIS_METHOD, (int)result); + + if (result > 0) + { + [preBuffer didWrite:result]; + } + + flags &= ~kSecureSocketHasBytesAvailable; + } + + return; + } + +#endif +#if SECURE_TRANSPORT_MAYBE_AVAILABLE + + __block NSUInteger estimatedBytesAvailable = 0; + + dispatch_block_t updateEstimatedBytesAvailable = ^{ + + // Figure out if there is any data available to be read + // + // socketFDBytesAvailable <- Number of encrypted bytes we haven't read from the bsd socket + // [sslPreBuffer availableBytes] <- Number of encrypted bytes we've buffered from bsd socket + // sslInternalBufSize <- Number of decrypted bytes SecureTransport has buffered + // + // We call the variable "estimated" because we don't know how many decrypted bytes we'll get + // from the encrypted bytes in the sslPreBuffer. + // However, we do know this is an upper bound on the estimation. + + estimatedBytesAvailable = socketFDBytesAvailable + [sslPreBuffer availableBytes]; + + size_t sslInternalBufSize = 0; + SSLGetBufferedReadSize(sslContext, &sslInternalBufSize); + + estimatedBytesAvailable += sslInternalBufSize; + }; + + updateEstimatedBytesAvailable(); + + if (estimatedBytesAvailable > 0) + { + LogVerbose(@"%@ - Flushing ssl buffers into prebuffer...", THIS_METHOD); + + BOOL done = NO; + do + { + LogVerbose(@"%@ - estimatedBytesAvailable = %lu", THIS_METHOD, (unsigned long)estimatedBytesAvailable); + + // Make sure there's enough room in the prebuffer + + [preBuffer ensureCapacityForWrite:estimatedBytesAvailable]; + + // Read data into prebuffer + + uint8_t *buffer = [preBuffer writeBuffer]; + size_t bytesRead = 0; + + OSStatus result = SSLRead(sslContext, buffer, (size_t)estimatedBytesAvailable, &bytesRead); + LogVerbose(@"%@ - read from secure socket = %u", THIS_METHOD, (unsigned)bytesRead); + + if (bytesRead > 0) + { + [preBuffer didWrite:bytesRead]; + } + + LogVerbose(@"%@ - prebuffer.length = %zu", THIS_METHOD, [preBuffer availableBytes]); + + if (result != noErr) + { + done = YES; + } + else + { + updateEstimatedBytesAvailable(); + } + + } while (!done && estimatedBytesAvailable > 0); + } + +#endif +} + +- (void)doReadData +{ + LogTrace(); + + // This method is called on the socketQueue. + // It might be called directly, or via the readSource when data is available to be read. + + if ((currentRead == nil) || (flags & kReadsPaused)) + { + LogVerbose(@"No currentRead or kReadsPaused"); + + // Unable to read at this time + + if (flags & kSocketSecure) + { + // Here's the situation: + // + // We have an established secure connection. + // There may not be a currentRead, but there might be encrypted data sitting around for us. + // When the user does get around to issuing a read, that encrypted data will need to be decrypted. + // + // So why make the user wait? + // We might as well get a head start on decrypting some data now. + // + // The other reason we do this has to do with detecting a socket disconnection. + // The SSL/TLS protocol has it's own disconnection handshake. + // So when a secure socket is closed, a "goodbye" packet comes across the wire. + // We want to make sure we read the "goodbye" packet so we can properly detect the TCP disconnection. + + [self flushSSLBuffers]; + } + + if ([self usingCFStreamForTLS]) + { + // CFReadStream only fires once when there is available data. + // It won't fire again until we've invoked CFReadStreamRead. + } + else + { + // If the readSource is firing, we need to pause it + // or else it will continue to fire over and over again. + // + // If the readSource is not firing, + // we want it to continue monitoring the socket. + + if (socketFDBytesAvailable > 0) + { + [self suspendReadSource]; + } + } + return; + } + + BOOL hasBytesAvailable = NO; + unsigned long estimatedBytesAvailable = 0; + + if ([self usingCFStreamForTLS]) + { + #if TARGET_OS_IPHONE + + // Relegated to using CFStream... :( Boo! Give us a full SecureTransport stack Apple! + + estimatedBytesAvailable = 0; + if ((flags & kSecureSocketHasBytesAvailable) && CFReadStreamHasBytesAvailable(readStream)) + hasBytesAvailable = YES; + else + hasBytesAvailable = NO; + + #endif + } + else + { + estimatedBytesAvailable = socketFDBytesAvailable; + + #if SECURE_TRANSPORT_MAYBE_AVAILABLE + + if (flags & kSocketSecure) + { + // There are 2 buffers to be aware of here. + // + // We are using SecureTransport, a TLS/SSL security layer which sits atop TCP. + // We issue a read to the SecureTranport API, which in turn issues a read to our SSLReadFunction. + // Our SSLReadFunction then reads from the BSD socket and returns the encrypted data to SecureTransport. + // SecureTransport then decrypts the data, and finally returns the decrypted data back to us. + // + // The first buffer is one we create. + // SecureTransport often requests small amounts of data. + // This has to do with the encypted packets that are coming across the TCP stream. + // But it's non-optimal to do a bunch of small reads from the BSD socket. + // So our SSLReadFunction reads all available data from the socket (optimizing the sys call) + // and may store excess in the sslPreBuffer. + + estimatedBytesAvailable += [sslPreBuffer availableBytes]; + + // The second buffer is within SecureTransport. + // As mentioned earlier, there are encrypted packets coming across the TCP stream. + // SecureTransport needs the entire packet to decrypt it. + // But if the entire packet produces X bytes of decrypted data, + // and we only asked SecureTransport for X/2 bytes of data, + // it must store the extra X/2 bytes of decrypted data for the next read. + // + // The SSLGetBufferedReadSize function will tell us the size of this internal buffer. + // From the documentation: + // + // "This function does not block or cause any low-level read operations to occur." + + size_t sslInternalBufSize = 0; + SSLGetBufferedReadSize(sslContext, &sslInternalBufSize); + + estimatedBytesAvailable += sslInternalBufSize; + } + + #endif + + hasBytesAvailable = (estimatedBytesAvailable > 0); + } + + if ((hasBytesAvailable == NO) && ([preBuffer availableBytes] == 0)) + { + LogVerbose(@"No data available to read..."); + + // No data available to read. + + if (![self usingCFStreamForTLS]) + { + // Need to wait for readSource to fire and notify us of + // available data in the socket's internal read buffer. + + [self resumeReadSource]; + } + return; + } + + if (flags & kStartingReadTLS) + { + LogVerbose(@"Waiting for SSL/TLS handshake to complete"); + + // The readQueue is waiting for SSL/TLS handshake to complete. + + if (flags & kStartingWriteTLS) + { + if ([self usingSecureTransportForTLS]) + { + #if SECURE_TRANSPORT_MAYBE_AVAILABLE + + // We are in the process of a SSL Handshake. + // We were waiting for incoming data which has just arrived. + + [self ssl_continueSSLHandshake]; + + #endif + } + } + else + { + // We are still waiting for the writeQueue to drain and start the SSL/TLS process. + // We now know data is available to read. + + if (![self usingCFStreamForTLS]) + { + // Suspend the read source or else it will continue to fire nonstop. + + [self suspendReadSource]; + } + } + + return; + } + + BOOL done = NO; // Completed read operation + NSError *error = nil; // Error occured + + NSUInteger totalBytesReadForCurrentRead = 0; + + // + // STEP 1 - READ FROM PREBUFFER + // + + if ([preBuffer availableBytes] > 0) + { + // There are 3 types of read packets: + // + // 1) Read all available data. + // 2) Read a specific length of data. + // 3) Read up to a particular terminator. + + NSUInteger bytesToCopy; + + if (currentRead->term != nil) + { + // Read type #3 - read up to a terminator + + bytesToCopy = [currentRead readLengthForTermWithPreBuffer:preBuffer found:&done]; + } + else + { + // Read type #1 or #2 + + bytesToCopy = [currentRead readLengthForNonTermWithHint:[preBuffer availableBytes]]; + } + + // Make sure we have enough room in the buffer for our read. + + [currentRead ensureCapacityForAdditionalDataOfLength:bytesToCopy]; + + // Copy bytes from prebuffer into packet buffer + + uint8_t *buffer = (uint8_t *)[currentRead->buffer mutableBytes] + currentRead->startOffset + + currentRead->bytesDone; + + memcpy(buffer, [preBuffer readBuffer], bytesToCopy); + + // Remove the copied bytes from the preBuffer + [preBuffer didRead:bytesToCopy]; + + LogVerbose(@"copied(%lu) preBufferLength(%zu)", (unsigned long)bytesToCopy, [preBuffer availableBytes]); + + // Update totals + + currentRead->bytesDone += bytesToCopy; + totalBytesReadForCurrentRead += bytesToCopy; + + // Check to see if the read operation is done + + if (currentRead->readLength > 0) + { + // Read type #2 - read a specific length of data + + done = (currentRead->bytesDone == currentRead->readLength); + } + else if (currentRead->term != nil) + { + // Read type #3 - read up to a terminator + + // Our 'done' variable was updated via the readLengthForTermWithPreBuffer:found: method + + if (!done && currentRead->maxLength > 0) + { + // We're not done and there's a set maxLength. + // Have we reached that maxLength yet? + + if (currentRead->bytesDone >= currentRead->maxLength) + { + error = [self readMaxedOutError]; + } + } + } + else + { + // Read type #1 - read all available data + // + // We're done as soon as + // - we've read all available data (in prebuffer and socket) + // - we've read the maxLength of read packet. + + done = ((currentRead->maxLength > 0) && (currentRead->bytesDone == currentRead->maxLength)); + } + + } + + // + // STEP 2 - READ FROM SOCKET + // + + BOOL socketEOF = (flags & kSocketHasReadEOF) ? YES : NO; // Nothing more to via socket (end of file) + BOOL waiting = !done && !error && !socketEOF && !hasBytesAvailable; // Ran out of data, waiting for more + + if (!done && !error && !socketEOF && !waiting && hasBytesAvailable) + { + NSAssert(([preBuffer availableBytes] == 0), @"Invalid logic"); + + // There are 3 types of read packets: + // + // 1) Read all available data. + // 2) Read a specific length of data. + // 3) Read up to a particular terminator. + + BOOL readIntoPreBuffer = NO; + NSUInteger bytesToRead; + + if ([self usingCFStreamForTLS]) + { + // Since Apple hasn't made the full power of SecureTransport available on iOS, + // we are relegated to using the slower, less powerful, RunLoop based CFStream API. + // + // This API doesn't tell us how much data is available on the socket to be read. + // If we had that information we could optimize our memory allocations, and sys calls. + // + // But alas... + // So we do it old school, and just read as much data from the socket as we can. + + NSUInteger defaultReadLength = (1024 * 32); + + bytesToRead = [currentRead optimalReadLengthWithDefault:defaultReadLength + shouldPreBuffer:&readIntoPreBuffer]; + } + else + { + if (currentRead->term != nil) + { + // Read type #3 - read up to a terminator + + bytesToRead = [currentRead readLengthForTermWithHint:estimatedBytesAvailable + shouldPreBuffer:&readIntoPreBuffer]; + } + else + { + // Read type #1 or #2 + + bytesToRead = [currentRead readLengthForNonTermWithHint:estimatedBytesAvailable]; + } + } + + if (bytesToRead > SIZE_MAX) // NSUInteger may be bigger than size_t (read param 3) + { + bytesToRead = SIZE_MAX; + } + + // Make sure we have enough room in the buffer for our read. + // + // We are either reading directly into the currentRead->buffer, + // or we're reading into the temporary preBuffer. + + uint8_t *buffer; + + if (readIntoPreBuffer) + { + [preBuffer ensureCapacityForWrite:bytesToRead]; + + buffer = [preBuffer writeBuffer]; + } + else + { + [currentRead ensureCapacityForAdditionalDataOfLength:bytesToRead]; + + buffer = (uint8_t *)[currentRead->buffer mutableBytes] + currentRead->startOffset + currentRead->bytesDone; + } + + // Read data into buffer + + size_t bytesRead = 0; + + if (flags & kSocketSecure) + { + if ([self usingCFStreamForTLS]) + { + #if TARGET_OS_IPHONE + + CFIndex result = CFReadStreamRead(readStream, buffer, (CFIndex)bytesToRead); + LogVerbose(@"CFReadStreamRead(): result = %i", (int)result); + + if (result < 0) + { + error = (__bridge_transfer NSError *)CFReadStreamCopyError(readStream); + } + else if (result == 0) + { + socketEOF = YES; + } + else + { + waiting = YES; + bytesRead = (size_t)result; + } + + // We only know how many decrypted bytes were read. + // The actual number of bytes read was likely more due to the overhead of the encryption. + // So we reset our flag, and rely on the next callback to alert us of more data. + flags &= ~kSecureSocketHasBytesAvailable; + + #endif + } + else + { + #if SECURE_TRANSPORT_MAYBE_AVAILABLE + + // The documentation from Apple states: + // + // "a read operation might return errSSLWouldBlock, + // indicating that less data than requested was actually transferred" + // + // However, starting around 10.7, the function will sometimes return noErr, + // even if it didn't read as much data as requested. So we need to watch out for that. + + OSStatus result; + do + { + void *loop_buffer = buffer + bytesRead; + size_t loop_bytesToRead = (size_t)bytesToRead - bytesRead; + size_t loop_bytesRead = 0; + + result = SSLRead(sslContext, loop_buffer, loop_bytesToRead, &loop_bytesRead); + LogVerbose(@"read from secure socket = %u", (unsigned)loop_bytesRead); + + bytesRead += loop_bytesRead; + + } while ((result == noErr) && (bytesRead < bytesToRead)); + + + if (result != noErr) + { + if (result == errSSLWouldBlock) + waiting = YES; + else + { + if (result == errSSLClosedGraceful || result == errSSLClosedAbort) + { + // We've reached the end of the stream. + // Handle this the same way we would an EOF from the socket. + socketEOF = YES; + sslErrCode = result; + } + else + { + error = [self sslError:result]; + } + } + // It's possible that bytesRead > 0, even if the result was errSSLWouldBlock. + // This happens when the SSLRead function is able to read some data, + // but not the entire amount we requested. + + if (bytesRead <= 0) + { + bytesRead = 0; + } + } + + // Do not modify socketFDBytesAvailable. + // It will be updated via the SSLReadFunction(). + + #endif + } + } + else + { + int socketFD = (socket4FD == SOCKET_NULL) ? socket6FD : socket4FD; + + ssize_t result = read(socketFD, buffer, (size_t)bytesToRead); + LogVerbose(@"read from socket = %i", (int)result); + + if (result < 0) + { + if (errno == EWOULDBLOCK) + waiting = YES; + else + error = [self errnoErrorWithReason:@"Error in read() function"]; + + socketFDBytesAvailable = 0; + } + else if (result == 0) + { + socketEOF = YES; + socketFDBytesAvailable = 0; + } + else + { + bytesRead = result; + + if (bytesRead < bytesToRead) + { + // The read returned less data than requested. + // This means socketFDBytesAvailable was a bit off due to timing, + // because we read from the socket right when the readSource event was firing. + socketFDBytesAvailable = 0; + } + else + { + if (socketFDBytesAvailable <= bytesRead) + socketFDBytesAvailable = 0; + else + socketFDBytesAvailable -= bytesRead; + } + + if (socketFDBytesAvailable == 0) + { + waiting = YES; + } + } + } + + if (bytesRead > 0) + { + // Check to see if the read operation is done + + if (currentRead->readLength > 0) + { + // Read type #2 - read a specific length of data + // + // Note: We should never be using a prebuffer when we're reading a specific length of data. + + NSAssert(readIntoPreBuffer == NO, @"Invalid logic"); + + currentRead->bytesDone += bytesRead; + totalBytesReadForCurrentRead += bytesRead; + + done = (currentRead->bytesDone == currentRead->readLength); + } + else if (currentRead->term != nil) + { + // Read type #3 - read up to a terminator + + if (readIntoPreBuffer) + { + // We just read a big chunk of data into the preBuffer + + [preBuffer didWrite:bytesRead]; + LogVerbose(@"read data into preBuffer - preBuffer.length = %zu", [preBuffer availableBytes]); + + // Search for the terminating sequence + + bytesToRead = [currentRead readLengthForTermWithPreBuffer:preBuffer found:&done]; + LogVerbose(@"copying %lu bytes from preBuffer", (unsigned long)bytesToRead); + + // Ensure there's room on the read packet's buffer + + [currentRead ensureCapacityForAdditionalDataOfLength:bytesToRead]; + + // Copy bytes from prebuffer into read buffer + + uint8_t *readBuf = (uint8_t *)[currentRead->buffer mutableBytes] + currentRead->startOffset + + currentRead->bytesDone; + + memcpy(readBuf, [preBuffer readBuffer], bytesToRead); + + // Remove the copied bytes from the prebuffer + [preBuffer didRead:bytesToRead]; + LogVerbose(@"preBuffer.length = %zu", [preBuffer availableBytes]); + + // Update totals + currentRead->bytesDone += bytesToRead; + totalBytesReadForCurrentRead += bytesToRead; + + // Our 'done' variable was updated via the readLengthForTermWithPreBuffer:found: method above + } + else + { + // We just read a big chunk of data directly into the packet's buffer. + // We need to move any overflow into the prebuffer. + + NSInteger overflow = [currentRead searchForTermAfterPreBuffering:bytesRead]; + + if (overflow == 0) + { + // Perfect match! + // Every byte we read stays in the read buffer, + // and the last byte we read was the last byte of the term. + + currentRead->bytesDone += bytesRead; + totalBytesReadForCurrentRead += bytesRead; + done = YES; + } + else if (overflow > 0) + { + // The term was found within the data that we read, + // and there are extra bytes that extend past the end of the term. + // We need to move these excess bytes out of the read packet and into the prebuffer. + + NSInteger underflow = bytesRead - overflow; + + // Copy excess data into preBuffer + + LogVerbose(@"copying %ld overflow bytes into preBuffer", (long)overflow); + [preBuffer ensureCapacityForWrite:overflow]; + + uint8_t *overflowBuffer = buffer + underflow; + memcpy([preBuffer writeBuffer], overflowBuffer, overflow); + + [preBuffer didWrite:overflow]; + LogVerbose(@"preBuffer.length = %zu", [preBuffer availableBytes]); + + // Note: The completeCurrentRead method will trim the buffer for us. + + currentRead->bytesDone += underflow; + totalBytesReadForCurrentRead += underflow; + done = YES; + } + else + { + // The term was not found within the data that we read. + + currentRead->bytesDone += bytesRead; + totalBytesReadForCurrentRead += bytesRead; + done = NO; + } + } + + if (!done && currentRead->maxLength > 0) + { + // We're not done and there's a set maxLength. + // Have we reached that maxLength yet? + + if (currentRead->bytesDone >= currentRead->maxLength) + { + error = [self readMaxedOutError]; + } + } + } + else + { + // Read type #1 - read all available data + + if (readIntoPreBuffer) + { + // We just read a chunk of data into the preBuffer + + [preBuffer didWrite:bytesRead]; + + // Now copy the data into the read packet. + // + // Recall that we didn't read directly into the packet's buffer to avoid + // over-allocating memory since we had no clue how much data was available to be read. + // + // Ensure there's room on the read packet's buffer + + [currentRead ensureCapacityForAdditionalDataOfLength:bytesRead]; + + // Copy bytes from prebuffer into read buffer + + uint8_t *readBuf = (uint8_t *)[currentRead->buffer mutableBytes] + currentRead->startOffset + + currentRead->bytesDone; + + memcpy(readBuf, [preBuffer readBuffer], bytesRead); + + // Remove the copied bytes from the prebuffer + [preBuffer didRead:bytesRead]; + + // Update totals + currentRead->bytesDone += bytesRead; + totalBytesReadForCurrentRead += bytesRead; + } + else + { + currentRead->bytesDone += bytesRead; + totalBytesReadForCurrentRead += bytesRead; + } + + done = YES; + } + + } // if (bytesRead > 0) + + } // if (!done && !error && !socketEOF && !waiting && hasBytesAvailable) + + + if (!done && currentRead->readLength == 0 && currentRead->term == nil) + { + // Read type #1 - read all available data + // + // We might arrive here if we read data from the prebuffer but not from the socket. + + done = (totalBytesReadForCurrentRead > 0); + } + + // Check to see if we're done, or if we've made progress + + if (done) + { + [self completeCurrentRead]; + + if (!error && (!socketEOF || [preBuffer availableBytes] > 0)) + { + [self maybeDequeueRead]; + } + } + else if (totalBytesReadForCurrentRead > 0) + { + // We're not done read type #2 or #3 yet, but we have read in some bytes + + __strong id theDelegate = delegate; + + if (delegateQueue && [theDelegate respondsToSelector:@selector(socket:didReadPartialDataOfLength:tag:)]) + { + long theReadTag = currentRead->tag; + + dispatch_async(delegateQueue, ^{ @autoreleasepool { + + [theDelegate socket:self didReadPartialDataOfLength:totalBytesReadForCurrentRead tag:theReadTag]; + }}); + } + } + + // Check for errors + + if (error) + { + [self closeWithError:error]; + } + else if (socketEOF) + { + [self doReadEOF]; + } + else if (waiting) + { + if (![self usingCFStreamForTLS]) + { + // Monitor the socket for readability (if we're not already doing so) + [self resumeReadSource]; + } + } + + // Do not add any code here without first adding return statements in the error cases above. +} + +- (void)doReadEOF +{ + LogTrace(); + + // This method may be called more than once. + // If the EOF is read while there is still data in the preBuffer, + // then this method may be called continually after invocations of doReadData to see if it's time to disconnect. + + flags |= kSocketHasReadEOF; + + if (flags & kSocketSecure) + { + // If the SSL layer has any buffered data, flush it into the preBuffer now. + + [self flushSSLBuffers]; + } + + BOOL shouldDisconnect = NO; + NSError *error = nil; + + if ((flags & kStartingReadTLS) || (flags & kStartingWriteTLS)) + { + // We received an EOF during or prior to startTLS. + // The SSL/TLS handshake is now impossible, so this is an unrecoverable situation. + + shouldDisconnect = YES; + + if ([self usingSecureTransportForTLS]) + { + #if SECURE_TRANSPORT_MAYBE_AVAILABLE + error = [self sslError:errSSLClosedAbort]; + #endif + } + } + else if (flags & kReadStreamClosed) + { + // The preBuffer has already been drained. + // The config allows half-duplex connections. + // We've previously checked the socket, and it appeared writeable. + // So we marked the read stream as closed and notified the delegate. + // + // As per the half-duplex contract, the socket will be closed when a write fails, + // or when the socket is manually closed. + + shouldDisconnect = NO; + } + else if ([preBuffer availableBytes] > 0) + { + LogVerbose(@"Socket reached EOF, but there is still data available in prebuffer"); + + // Although we won't be able to read any more data from the socket, + // there is existing data that has been prebuffered that we can read. + + shouldDisconnect = NO; + } + else if (config & kAllowHalfDuplexConnection) + { + // We just received an EOF (end of file) from the socket's read stream. + // This means the remote end of the socket (the peer we're connected to) + // has explicitly stated that it will not be sending us any more data. + // + // Query the socket to see if it is still writeable. (Perhaps the peer will continue reading data from us) + + int socketFD = (socket4FD == SOCKET_NULL) ? socket6FD : socket4FD; + + struct pollfd pfd[1]; + pfd[0].fd = socketFD; + pfd[0].events = POLLOUT; + pfd[0].revents = 0; + + poll(pfd, 1, 0); + + if (pfd[0].revents & POLLOUT) + { + // Socket appears to still be writeable + + shouldDisconnect = NO; + flags |= kReadStreamClosed; + + // Notify the delegate that we're going half-duplex + + __strong id theDelegate = delegate; + + if (delegateQueue && [theDelegate respondsToSelector:@selector(socketDidCloseReadStream:)]) + { + dispatch_async(delegateQueue, ^{ @autoreleasepool { + + [theDelegate socketDidCloseReadStream:self]; + }}); + } + } + else + { + shouldDisconnect = YES; + } + } + else + { + shouldDisconnect = YES; + } + + + if (shouldDisconnect) + { + if (error == nil) + { + #if SECURE_TRANSPORT_MAYBE_AVAILABLE + if ([self usingSecureTransportForTLS]) + { + if (sslErrCode != noErr && sslErrCode != errSSLClosedGraceful) + { + error = [self sslError:sslErrCode]; + } + else + { + error = [self connectionClosedError]; + } + } + else + { + error = [self connectionClosedError]; + } + #else + error = [self connectionClosedError]; + #endif + } + [self closeWithError:error]; + } + else + { + if (![self usingCFStreamForTLS]) + { + // Suspend the read source (if needed) + + [self suspendReadSource]; + } + } +} + +- (void)completeCurrentRead +{ + LogTrace(); + + NSAssert(currentRead, @"Trying to complete current read when there is no current read."); + + + NSData *result = nil; + + if (currentRead->bufferOwner) + { + // We created the buffer on behalf of the user. + // Trim our buffer to be the proper size. + [currentRead->buffer setLength:currentRead->bytesDone]; + + result = currentRead->buffer; + } + else + { + // We did NOT create the buffer. + // The buffer is owned by the caller. + // Only trim the buffer if we had to increase its size. + + if ([currentRead->buffer length] > currentRead->originalBufferLength) + { + NSUInteger readSize = currentRead->startOffset + currentRead->bytesDone; + NSUInteger origSize = currentRead->originalBufferLength; + + NSUInteger buffSize = MAX(readSize, origSize); + + [currentRead->buffer setLength:buffSize]; + } + + uint8_t *buffer = (uint8_t *)[currentRead->buffer mutableBytes] + currentRead->startOffset; + + result = [NSData dataWithBytesNoCopy:buffer length:currentRead->bytesDone freeWhenDone:NO]; + } + + __strong id theDelegate = delegate; + + if (delegateQueue && [theDelegate respondsToSelector:@selector(socket:didReadData:withTag:)]) + { + GCDAsyncReadPacket *theRead = currentRead; // Ensure currentRead retained since result may not own buffer + + dispatch_async(delegateQueue, ^{ @autoreleasepool { + + [theDelegate socket:self didReadData:result withTag:theRead->tag]; + }}); + } + + [self endCurrentRead]; +} + +- (void)endCurrentRead +{ + if (readTimer) + { + dispatch_source_cancel(readTimer); + readTimer = NULL; + } + + currentRead = nil; +} + +- (void)setupReadTimerWithTimeout:(NSTimeInterval)timeout +{ + if (timeout >= 0.0) + { + readTimer = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0, socketQueue); + + dispatch_source_set_event_handler(readTimer, ^{ @autoreleasepool { + + [self doReadTimeout]; + }}); + + #if !OS_OBJECT_USE_OBJC + dispatch_source_t theReadTimer = readTimer; + dispatch_source_set_cancel_handler(readTimer, ^{ + LogVerbose(@"dispatch_release(readTimer)"); + dispatch_release(theReadTimer); + }); + #endif + + dispatch_time_t tt = dispatch_time(DISPATCH_TIME_NOW, (int64_t)(timeout * NSEC_PER_SEC)); + + dispatch_source_set_timer(readTimer, tt, DISPATCH_TIME_FOREVER, 0); + dispatch_resume(readTimer); + } +} + +- (void)doReadTimeout +{ + // This is a little bit tricky. + // Ideally we'd like to synchronously query the delegate about a timeout extension. + // But if we do so synchronously we risk a possible deadlock. + // So instead we have to do so asynchronously, and callback to ourselves from within the delegate block. + + flags |= kReadsPaused; + + __strong id theDelegate = delegate; + + if (delegateQueue && [theDelegate respondsToSelector:@selector(socket:shouldTimeoutReadWithTag:elapsed:bytesDone:)]) + { + GCDAsyncReadPacket *theRead = currentRead; + + dispatch_async(delegateQueue, ^{ @autoreleasepool { + + NSTimeInterval timeoutExtension = 0.0; + + timeoutExtension = [theDelegate socket:self shouldTimeoutReadWithTag:theRead->tag + elapsed:theRead->timeout + bytesDone:theRead->bytesDone]; + + dispatch_async(socketQueue, ^{ @autoreleasepool { + + [self doReadTimeoutWithExtension:timeoutExtension]; + }}); + }}); + } + else + { + [self doReadTimeoutWithExtension:0.0]; + } +} + +- (void)doReadTimeoutWithExtension:(NSTimeInterval)timeoutExtension +{ + if (currentRead) + { + if (timeoutExtension > 0.0) + { + currentRead->timeout += timeoutExtension; + + // Reschedule the timer + dispatch_time_t tt = dispatch_time(DISPATCH_TIME_NOW, (int64_t)(timeoutExtension * NSEC_PER_SEC)); + dispatch_source_set_timer(readTimer, tt, DISPATCH_TIME_FOREVER, 0); + + // Unpause reads, and continue + flags &= ~kReadsPaused; + [self doReadData]; + } + else + { + LogVerbose(@"ReadTimeout"); + + [self closeWithError:[self readTimeoutError]]; + } + } +} + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +#pragma mark Writing +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +- (void)writeData:(NSData *)data withTimeout:(NSTimeInterval)timeout tag:(long)tag +{ + if ([data length] == 0) return; + + GCDAsyncWritePacket *packet = [[GCDAsyncWritePacket alloc] initWithData:data timeout:timeout tag:tag]; + + dispatch_async(socketQueue, ^{ @autoreleasepool { + + LogTrace(); + + if ((flags & kSocketStarted) && !(flags & kForbidReadsWrites)) + { + [writeQueue addObject:packet]; + [self maybeDequeueWrite]; + } + }}); + + // Do not rely on the block being run in order to release the packet, + // as the queue might get released without the block completing. +} + +- (float)progressOfWriteReturningTag:(long *)tagPtr bytesDone:(NSUInteger *)donePtr total:(NSUInteger *)totalPtr +{ + __block float result = 0.0F; + + dispatch_block_t block = ^{ + + if (!currentWrite || ![currentWrite isKindOfClass:[GCDAsyncWritePacket class]]) + { + // We're not writing anything right now. + + if (tagPtr != NULL) *tagPtr = 0; + if (donePtr != NULL) *donePtr = 0; + if (totalPtr != NULL) *totalPtr = 0; + + result = NAN; + } + else + { + NSUInteger done = currentWrite->bytesDone; + NSUInteger total = [currentWrite->buffer length]; + + if (tagPtr != NULL) *tagPtr = currentWrite->tag; + if (donePtr != NULL) *donePtr = done; + if (totalPtr != NULL) *totalPtr = total; + + result = (float)done / (float)total; + } + }; + + if (dispatch_get_specific(IsOnSocketQueueOrTargetQueueKey)) + block(); + else + dispatch_sync(socketQueue, block); + + return result; +} + +/** + * Conditionally starts a new write. + * + * It is called when: + * - a user requests a write + * - after a write request has finished (to handle the next request) + * - immediately after the socket opens to handle any pending requests + * + * This method also handles auto-disconnect post read/write completion. +**/ +- (void)maybeDequeueWrite +{ + LogTrace(); + NSAssert(dispatch_get_specific(IsOnSocketQueueOrTargetQueueKey), @"Must be dispatched on socketQueue"); + + + // If we're not currently processing a write AND we have an available write stream + if ((currentWrite == nil) && (flags & kConnected)) + { + if ([writeQueue count] > 0) + { + // Dequeue the next object in the write queue + currentWrite = [writeQueue objectAtIndex:0]; + [writeQueue removeObjectAtIndex:0]; + + + if ([currentWrite isKindOfClass:[GCDAsyncSpecialPacket class]]) + { + LogVerbose(@"Dequeued GCDAsyncSpecialPacket"); + + // Attempt to start TLS + flags |= kStartingWriteTLS; + + // This method won't do anything unless both kStartingReadTLS and kStartingWriteTLS are set + [self maybeStartTLS]; + } + else + { + LogVerbose(@"Dequeued GCDAsyncWritePacket"); + + // Setup write timer (if needed) + [self setupWriteTimerWithTimeout:currentWrite->timeout]; + + // Immediately write, if possible + [self doWriteData]; + } + } + else if (flags & kDisconnectAfterWrites) + { + if (flags & kDisconnectAfterReads) + { + if (([readQueue count] == 0) && (currentRead == nil)) + { + [self closeWithError:nil]; + } + } + else + { + [self closeWithError:nil]; + } + } + } +} + +- (void)doWriteData +{ + LogTrace(); + + // This method is called by the writeSource via the socketQueue + + if ((currentWrite == nil) || (flags & kWritesPaused)) + { + LogVerbose(@"No currentWrite or kWritesPaused"); + + // Unable to write at this time + + if ([self usingCFStreamForTLS]) + { + // CFWriteStream only fires once when there is available data. + // It won't fire again until we've invoked CFWriteStreamWrite. + } + else + { + // If the writeSource is firing, we need to pause it + // or else it will continue to fire over and over again. + + if (flags & kSocketCanAcceptBytes) + { + [self suspendWriteSource]; + } + } + return; + } + + if (!(flags & kSocketCanAcceptBytes)) + { + LogVerbose(@"No space available to write..."); + + // No space available to write. + + if (![self usingCFStreamForTLS]) + { + // Need to wait for writeSource to fire and notify us of + // available space in the socket's internal write buffer. + + [self resumeWriteSource]; + } + return; + } + + if (flags & kStartingWriteTLS) + { + LogVerbose(@"Waiting for SSL/TLS handshake to complete"); + + // The writeQueue is waiting for SSL/TLS handshake to complete. + + if (flags & kStartingReadTLS) + { + if ([self usingSecureTransportForTLS]) + { + #if SECURE_TRANSPORT_MAYBE_AVAILABLE + + // We are in the process of a SSL Handshake. + // We were waiting for available space in the socket's internal OS buffer to continue writing. + + [self ssl_continueSSLHandshake]; + + #endif + } + } + else + { + // We are still waiting for the readQueue to drain and start the SSL/TLS process. + // We now know we can write to the socket. + + if (![self usingCFStreamForTLS]) + { + // Suspend the write source or else it will continue to fire nonstop. + + [self suspendWriteSource]; + } + } + + return; + } + + // Note: This method is not called if currentWrite is a GCDAsyncSpecialPacket (startTLS packet) + + BOOL waiting = NO; + NSError *error = nil; + size_t bytesWritten = 0; + + if (flags & kSocketSecure) + { + if ([self usingCFStreamForTLS]) + { + #if TARGET_OS_IPHONE + + // + // Writing data using CFStream (over internal TLS) + // + + const uint8_t *buffer = (const uint8_t *)[currentWrite->buffer bytes] + currentWrite->bytesDone; + + NSUInteger bytesToWrite = [currentWrite->buffer length] - currentWrite->bytesDone; + + if (bytesToWrite > SIZE_MAX) // NSUInteger may be bigger than size_t (write param 3) + { + bytesToWrite = SIZE_MAX; + } + + CFIndex result = CFWriteStreamWrite(writeStream, buffer, (CFIndex)bytesToWrite); + LogVerbose(@"CFWriteStreamWrite(%lu) = %li", (unsigned long)bytesToWrite, result); + + if (result < 0) + { + error = (__bridge_transfer NSError *)CFWriteStreamCopyError(writeStream); + } + else + { + bytesWritten = (size_t)result; + + // We always set waiting to true in this scenario. + // CFStream may have altered our underlying socket to non-blocking. + // Thus if we attempt to write without a callback, we may end up blocking our queue. + waiting = YES; + } + + #endif + } + else + { + #if SECURE_TRANSPORT_MAYBE_AVAILABLE + + // We're going to use the SSLWrite function. + // + // OSStatus SSLWrite(SSLContextRef context, const void *data, size_t dataLength, size_t *processed) + // + // Parameters: + // context - An SSL session context reference. + // data - A pointer to the buffer of data to write. + // dataLength - The amount, in bytes, of data to write. + // processed - On return, the length, in bytes, of the data actually written. + // + // It sounds pretty straight-forward, + // but there are a few caveats you should be aware of. + // + // The SSLWrite method operates in a non-obvious (and rather annoying) manner. + // According to the documentation: + // + // Because you may configure the underlying connection to operate in a non-blocking manner, + // a write operation might return errSSLWouldBlock, indicating that less data than requested + // was actually transferred. In this case, you should repeat the call to SSLWrite until some + // other result is returned. + // + // This sounds perfect, but when our SSLWriteFunction returns errSSLWouldBlock, + // then the SSLWrite method returns (with the proper errSSLWouldBlock return value), + // but it sets processed to dataLength !! + // + // In other words, if the SSLWrite function doesn't completely write all the data we tell it to, + // then it doesn't tell us how many bytes were actually written. So, for example, if we tell it to + // write 256 bytes then it might actually write 128 bytes, but then report 0 bytes written. + // + // You might be wondering: + // If the SSLWrite function doesn't tell us how many bytes were written, + // then how in the world are we supposed to update our parameters (buffer & bytesToWrite) + // for the next time we invoke SSLWrite? + // + // The answer is that SSLWrite cached all the data we told it to write, + // and it will push out that data next time we call SSLWrite. + // If we call SSLWrite with new data, it will push out the cached data first, and then the new data. + // If we call SSLWrite with empty data, then it will simply push out the cached data. + // + // For this purpose we're going to break large writes into a series of smaller writes. + // This allows us to report progress back to the delegate. + + OSStatus result; + + BOOL hasCachedDataToWrite = (sslWriteCachedLength > 0); + BOOL hasNewDataToWrite = YES; + + if (hasCachedDataToWrite) + { + size_t processed = 0; + + result = SSLWrite(sslContext, NULL, 0, &processed); + + if (result == noErr) + { + bytesWritten = sslWriteCachedLength; + sslWriteCachedLength = 0; + + if ([currentWrite->buffer length] == (currentWrite->bytesDone + bytesWritten)) + { + // We've written all data for the current write. + hasNewDataToWrite = NO; + } + } + else + { + if (result == errSSLWouldBlock) + { + waiting = YES; + } + else + { + error = [self sslError:result]; + } + + // Can't write any new data since we were unable to write the cached data. + hasNewDataToWrite = NO; + } + } + + if (hasNewDataToWrite) + { + const uint8_t *buffer = (const uint8_t *)[currentWrite->buffer bytes] + + currentWrite->bytesDone + + bytesWritten; + + NSUInteger bytesToWrite = [currentWrite->buffer length] - currentWrite->bytesDone - bytesWritten; + + if (bytesToWrite > SIZE_MAX) // NSUInteger may be bigger than size_t (write param 3) + { + bytesToWrite = SIZE_MAX; + } + + size_t bytesRemaining = bytesToWrite; + + BOOL keepLooping = YES; + while (keepLooping) + { + const size_t sslMaxBytesToWrite = 32768; + size_t sslBytesToWrite = MIN(bytesRemaining, sslMaxBytesToWrite); + size_t sslBytesWritten = 0; + + result = SSLWrite(sslContext, buffer, sslBytesToWrite, &sslBytesWritten); + + if (result == noErr) + { + buffer += sslBytesWritten; + bytesWritten += sslBytesWritten; + bytesRemaining -= sslBytesWritten; + + keepLooping = (bytesRemaining > 0); + } + else + { + if (result == errSSLWouldBlock) + { + waiting = YES; + sslWriteCachedLength = sslBytesToWrite; + } + else + { + error = [self sslError:result]; + } + + keepLooping = NO; + } + + } // while (keepLooping) + + } // if (hasNewDataToWrite) + + #endif + } + } + else + { + // + // Writing data directly over raw socket + // + + int socketFD = (socket4FD == SOCKET_NULL) ? socket6FD : socket4FD; + + const uint8_t *buffer = (const uint8_t *)[currentWrite->buffer bytes] + currentWrite->bytesDone; + + NSUInteger bytesToWrite = [currentWrite->buffer length] - currentWrite->bytesDone; + + if (bytesToWrite > SIZE_MAX) // NSUInteger may be bigger than size_t (write param 3) + { + bytesToWrite = SIZE_MAX; + } + + ssize_t result = write(socketFD, buffer, (size_t)bytesToWrite); + LogVerbose(@"wrote to socket = %zd", result); + + // Check results + if (result < 0) + { + if (errno == EWOULDBLOCK) + { + waiting = YES; + } + else + { + error = [self errnoErrorWithReason:@"Error in write() function"]; + } + } + else + { + bytesWritten = result; + } + } + + // We're done with our writing. + // If we explictly ran into a situation where the socket told us there was no room in the buffer, + // then we immediately resume listening for notifications. + // + // We must do this before we dequeue another write, + // as that may in turn invoke this method again. + // + // Note that if CFStream is involved, it may have maliciously put our socket in blocking mode. + + if (waiting) + { + flags &= ~kSocketCanAcceptBytes; + + if (![self usingCFStreamForTLS]) + { + [self resumeWriteSource]; + } + } + + // Check our results + + BOOL done = NO; + + if (bytesWritten > 0) + { + // Update total amount read for the current write + currentWrite->bytesDone += bytesWritten; + LogVerbose(@"currentWrite->bytesDone = %lu", (unsigned long)currentWrite->bytesDone); + + // Is packet done? + done = (currentWrite->bytesDone == [currentWrite->buffer length]); + } + + if (done) + { + [self completeCurrentWrite]; + + if (!error) + { + [self maybeDequeueWrite]; + } + } + else + { + // We were unable to finish writing the data, + // so we're waiting for another callback to notify us of available space in the lower-level output buffer. + + if (!waiting && !error) + { + // This would be the case if our write was able to accept some data, but not all of it. + + flags &= ~kSocketCanAcceptBytes; + + if (![self usingCFStreamForTLS]) + { + [self resumeWriteSource]; + } + } + + if (bytesWritten > 0) + { + // We're not done with the entire write, but we have written some bytes + + __strong id theDelegate = delegate; + + if (delegateQueue && [theDelegate respondsToSelector:@selector(socket:didWritePartialDataOfLength:tag:)]) + { + long theWriteTag = currentWrite->tag; + + dispatch_async(delegateQueue, ^{ @autoreleasepool { + + [theDelegate socket:self didWritePartialDataOfLength:bytesWritten tag:theWriteTag]; + }}); + } + } + } + + // Check for errors + + if (error) + { + [self closeWithError:[self errnoErrorWithReason:@"Error in write() function"]]; + } + + // Do not add any code here without first adding a return statement in the error case above. +} + +- (void)completeCurrentWrite +{ + LogTrace(); + + NSAssert(currentWrite, @"Trying to complete current write when there is no current write."); + + + __strong id theDelegate = delegate; + + if (delegateQueue && [theDelegate respondsToSelector:@selector(socket:didWriteDataWithTag:)]) + { + long theWriteTag = currentWrite->tag; + + dispatch_async(delegateQueue, ^{ @autoreleasepool { + + [theDelegate socket:self didWriteDataWithTag:theWriteTag]; + }}); + } + + [self endCurrentWrite]; +} + +- (void)endCurrentWrite +{ + if (writeTimer) + { + dispatch_source_cancel(writeTimer); + writeTimer = NULL; + } + + currentWrite = nil; +} + +- (void)setupWriteTimerWithTimeout:(NSTimeInterval)timeout +{ + if (timeout >= 0.0) + { + writeTimer = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0, socketQueue); + + dispatch_source_set_event_handler(writeTimer, ^{ @autoreleasepool { + + [self doWriteTimeout]; + }}); + + #if !OS_OBJECT_USE_OBJC + dispatch_source_t theWriteTimer = writeTimer; + dispatch_source_set_cancel_handler(writeTimer, ^{ + LogVerbose(@"dispatch_release(writeTimer)"); + dispatch_release(theWriteTimer); + }); + #endif + + dispatch_time_t tt = dispatch_time(DISPATCH_TIME_NOW, (int64_t)(timeout * NSEC_PER_SEC)); + + dispatch_source_set_timer(writeTimer, tt, DISPATCH_TIME_FOREVER, 0); + dispatch_resume(writeTimer); + } +} + +- (void)doWriteTimeout +{ + // This is a little bit tricky. + // Ideally we'd like to synchronously query the delegate about a timeout extension. + // But if we do so synchronously we risk a possible deadlock. + // So instead we have to do so asynchronously, and callback to ourselves from within the delegate block. + + flags |= kWritesPaused; + + __strong id theDelegate = delegate; + + if (delegateQueue && [theDelegate respondsToSelector:@selector(socket:shouldTimeoutWriteWithTag:elapsed:bytesDone:)]) + { + GCDAsyncWritePacket *theWrite = currentWrite; + + dispatch_async(delegateQueue, ^{ @autoreleasepool { + + NSTimeInterval timeoutExtension = 0.0; + + timeoutExtension = [theDelegate socket:self shouldTimeoutWriteWithTag:theWrite->tag + elapsed:theWrite->timeout + bytesDone:theWrite->bytesDone]; + + dispatch_async(socketQueue, ^{ @autoreleasepool { + + [self doWriteTimeoutWithExtension:timeoutExtension]; + }}); + }}); + } + else + { + [self doWriteTimeoutWithExtension:0.0]; + } +} + +- (void)doWriteTimeoutWithExtension:(NSTimeInterval)timeoutExtension +{ + if (currentWrite) + { + if (timeoutExtension > 0.0) + { + currentWrite->timeout += timeoutExtension; + + // Reschedule the timer + dispatch_time_t tt = dispatch_time(DISPATCH_TIME_NOW, (int64_t)(timeoutExtension * NSEC_PER_SEC)); + dispatch_source_set_timer(writeTimer, tt, DISPATCH_TIME_FOREVER, 0); + + // Unpause writes, and continue + flags &= ~kWritesPaused; + [self doWriteData]; + } + else + { + LogVerbose(@"WriteTimeout"); + + [self closeWithError:[self writeTimeoutError]]; + } + } +} + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +#pragma mark Security +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +- (void)startTLS:(NSDictionary *)tlsSettings +{ + LogTrace(); + + if (tlsSettings == nil) + { + // Passing nil/NULL to CFReadStreamSetProperty will appear to work the same as passing an empty dictionary, + // but causes problems if we later try to fetch the remote host's certificate. + // + // To be exact, it causes the following to return NULL instead of the normal result: + // CFReadStreamCopyProperty(readStream, kCFStreamPropertySSLPeerCertificates) + // + // So we use an empty dictionary instead, which works perfectly. + + tlsSettings = [NSDictionary dictionary]; + } + + GCDAsyncSpecialPacket *packet = [[GCDAsyncSpecialPacket alloc] initWithTLSSettings:tlsSettings]; + + dispatch_async(socketQueue, ^{ @autoreleasepool { + + if ((flags & kSocketStarted) && !(flags & kQueuedTLS) && !(flags & kForbidReadsWrites)) + { + [readQueue addObject:packet]; + [writeQueue addObject:packet]; + + flags |= kQueuedTLS; + + [self maybeDequeueRead]; + [self maybeDequeueWrite]; + } + }}); + +} + +- (void)maybeStartTLS +{ + // We can't start TLS until: + // - All queued reads prior to the user calling startTLS are complete + // - All queued writes prior to the user calling startTLS are complete + // + // We'll know these conditions are met when both kStartingReadTLS and kStartingWriteTLS are set + + if ((flags & kStartingReadTLS) && (flags & kStartingWriteTLS)) + { + BOOL canUseSecureTransport = YES; + + #if TARGET_OS_IPHONE + { + GCDAsyncSpecialPacket *tlsPacket = (GCDAsyncSpecialPacket *)currentRead; + NSDictionary *tlsSettings = tlsPacket->tlsSettings; + + NSNumber *value; + + value = [tlsSettings objectForKey:(NSString *)kCFStreamSSLAllowsAnyRoot]; + if (value && [value boolValue] == YES) + canUseSecureTransport = NO; + + value = [tlsSettings objectForKey:(NSString *)kCFStreamSSLAllowsExpiredRoots]; + if (value && [value boolValue] == YES) + canUseSecureTransport = NO; + + value = [tlsSettings objectForKey:(NSString *)kCFStreamSSLValidatesCertificateChain]; + if (value && [value boolValue] == NO) + canUseSecureTransport = NO; + + value = [tlsSettings objectForKey:(NSString *)kCFStreamSSLAllowsExpiredCertificates]; + if (value && [value boolValue] == YES) + canUseSecureTransport = NO; + } + #endif + + if (IS_SECURE_TRANSPORT_AVAILABLE && canUseSecureTransport) + { + #if SECURE_TRANSPORT_MAYBE_AVAILABLE + [self ssl_startTLS]; + #endif + } + else + { + #if TARGET_OS_IPHONE + [self cf_startTLS]; + #endif + } + } +} + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +#pragma mark Security via SecureTransport +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +#if SECURE_TRANSPORT_MAYBE_AVAILABLE + +- (OSStatus)sslReadWithBuffer:(void *)buffer length:(size_t *)bufferLength +{ + LogVerbose(@"sslReadWithBuffer:%p length:%lu", buffer, (unsigned long)*bufferLength); + + if ((socketFDBytesAvailable == 0) && ([sslPreBuffer availableBytes] == 0)) + { + LogVerbose(@"%@ - No data available to read...", THIS_METHOD); + + // No data available to read. + // + // Need to wait for readSource to fire and notify us of + // available data in the socket's internal read buffer. + + [self resumeReadSource]; + + *bufferLength = 0; + return errSSLWouldBlock; + } + + size_t totalBytesRead = 0; + size_t totalBytesLeftToBeRead = *bufferLength; + + BOOL done = NO; + BOOL socketError = NO; + + // + // STEP 1 : READ FROM SSL PRE BUFFER + // + + size_t sslPreBufferLength = [sslPreBuffer availableBytes]; + + if (sslPreBufferLength > 0) + { + LogVerbose(@"%@: Reading from SSL pre buffer...", THIS_METHOD); + + size_t bytesToCopy; + if (sslPreBufferLength > totalBytesLeftToBeRead) + bytesToCopy = totalBytesLeftToBeRead; + else + bytesToCopy = sslPreBufferLength; + + LogVerbose(@"%@: Copying %zu bytes from sslPreBuffer", THIS_METHOD, bytesToCopy); + + memcpy(buffer, [sslPreBuffer readBuffer], bytesToCopy); + [sslPreBuffer didRead:bytesToCopy]; + + LogVerbose(@"%@: sslPreBuffer.length = %zu", THIS_METHOD, [sslPreBuffer availableBytes]); + + totalBytesRead += bytesToCopy; + totalBytesLeftToBeRead -= bytesToCopy; + + done = (totalBytesLeftToBeRead == 0); + + if (done) LogVerbose(@"%@: Complete", THIS_METHOD); + } + + // + // STEP 2 : READ FROM SOCKET + // + + if (!done && (socketFDBytesAvailable > 0)) + { + LogVerbose(@"%@: Reading from socket...", THIS_METHOD); + + int socketFD = (socket6FD == SOCKET_NULL) ? socket4FD : socket6FD; + + BOOL readIntoPreBuffer; + size_t bytesToRead; + uint8_t *buf; + + if (socketFDBytesAvailable > totalBytesLeftToBeRead) + { + // Read all available data from socket into sslPreBuffer. + // Then copy requested amount into dataBuffer. + + LogVerbose(@"%@: Reading into sslPreBuffer...", THIS_METHOD); + + [sslPreBuffer ensureCapacityForWrite:socketFDBytesAvailable]; + + readIntoPreBuffer = YES; + bytesToRead = (size_t)socketFDBytesAvailable; + buf = [sslPreBuffer writeBuffer]; + } + else + { + // Read available data from socket directly into dataBuffer. + + LogVerbose(@"%@: Reading directly into dataBuffer...", THIS_METHOD); + + readIntoPreBuffer = NO; + bytesToRead = totalBytesLeftToBeRead; + buf = (uint8_t *)buffer + totalBytesRead; + } + + ssize_t result = read(socketFD, buf, bytesToRead); + LogVerbose(@"%@: read from socket = %zd", THIS_METHOD, result); + + if (result < 0) + { + LogVerbose(@"%@: read errno = %i", THIS_METHOD, errno); + + if (errno != EWOULDBLOCK) + { + socketError = YES; + } + + socketFDBytesAvailable = 0; + } + else if (result == 0) + { + LogVerbose(@"%@: read EOF", THIS_METHOD); + + socketError = YES; + socketFDBytesAvailable = 0; + } + else + { + size_t bytesReadFromSocket = result; + + if (socketFDBytesAvailable > bytesReadFromSocket) + socketFDBytesAvailable -= bytesReadFromSocket; + else + socketFDBytesAvailable = 0; + + if (readIntoPreBuffer) + { + [sslPreBuffer didWrite:bytesReadFromSocket]; + + size_t bytesToCopy = MIN(totalBytesLeftToBeRead, bytesReadFromSocket); + + LogVerbose(@"%@: Copying %zu bytes out of sslPreBuffer", THIS_METHOD, bytesToCopy); + + memcpy((uint8_t *)buffer + totalBytesRead, [sslPreBuffer readBuffer], bytesToCopy); + [sslPreBuffer didRead:bytesToCopy]; + + totalBytesRead += bytesToCopy; + totalBytesLeftToBeRead -= bytesToCopy; + + LogVerbose(@"%@: sslPreBuffer.length = %zu", THIS_METHOD, [sslPreBuffer availableBytes]); + } + else + { + totalBytesRead += bytesReadFromSocket; + totalBytesLeftToBeRead -= bytesReadFromSocket; + } + + done = (totalBytesLeftToBeRead == 0); + + if (done) LogVerbose(@"%@: Complete", THIS_METHOD); + } + } + + *bufferLength = totalBytesRead; + + if (done) + return noErr; + + if (socketError) + return errSSLClosedAbort; + + return errSSLWouldBlock; +} + +- (OSStatus)sslWriteWithBuffer:(const void *)buffer length:(size_t *)bufferLength +{ + if (!(flags & kSocketCanAcceptBytes)) + { + // Unable to write. + // + // Need to wait for writeSource to fire and notify us of + // available space in the socket's internal write buffer. + + [self resumeWriteSource]; + + *bufferLength = 0; + return errSSLWouldBlock; + } + + size_t bytesToWrite = *bufferLength; + size_t bytesWritten = 0; + + BOOL done = NO; + BOOL socketError = NO; + + int socketFD = (socket4FD == SOCKET_NULL) ? socket6FD : socket4FD; + + ssize_t result = write(socketFD, buffer, bytesToWrite); + + if (result < 0) + { + if (errno != EWOULDBLOCK) + { + socketError = YES; + } + + flags &= ~kSocketCanAcceptBytes; + } + else if (result == 0) + { + flags &= ~kSocketCanAcceptBytes; + } + else + { + bytesWritten = result; + + done = (bytesWritten == bytesToWrite); + } + + *bufferLength = bytesWritten; + + if (done) + return noErr; + + if (socketError) + return errSSLClosedAbort; + + return errSSLWouldBlock; +} + +static OSStatus SSLReadFunction(SSLConnectionRef connection, void *data, size_t *dataLength) +{ + GCDAsyncSocket *asyncSocket = (__bridge GCDAsyncSocket *)connection; + + NSCAssert(dispatch_get_specific(asyncSocket->IsOnSocketQueueOrTargetQueueKey), @"What the deuce?"); + + return [asyncSocket sslReadWithBuffer:data length:dataLength]; +} + +static OSStatus SSLWriteFunction(SSLConnectionRef connection, const void *data, size_t *dataLength) +{ + GCDAsyncSocket *asyncSocket = (__bridge GCDAsyncSocket *)connection; + + NSCAssert(dispatch_get_specific(asyncSocket->IsOnSocketQueueOrTargetQueueKey), @"What the deuce?"); + + return [asyncSocket sslWriteWithBuffer:data length:dataLength]; +} + +- (void)ssl_startTLS +{ + LogTrace(); + + LogVerbose(@"Starting TLS (via SecureTransport)..."); + + OSStatus status; + + GCDAsyncSpecialPacket *tlsPacket = (GCDAsyncSpecialPacket *)currentRead; + NSDictionary *tlsSettings = tlsPacket->tlsSettings; + + // Create SSLContext, and setup IO callbacks and connection ref + + BOOL isServer = [[tlsSettings objectForKey:(NSString *)kCFStreamSSLIsServer] boolValue]; + + #if TARGET_OS_IPHONE + { + if (isServer) + sslContext = SSLCreateContext(kCFAllocatorDefault, kSSLServerSide, kSSLStreamType); + else + sslContext = SSLCreateContext(kCFAllocatorDefault, kSSLClientSide, kSSLStreamType); + + if (sslContext == NULL) + { + [self closeWithError:[self otherError:@"Error in SSLCreateContext"]]; + return; + } + } + #else + { + status = SSLNewContext(isServer, &sslContext); + if (status != noErr) + { + [self closeWithError:[self otherError:@"Error in SSLNewContext"]]; + return; + } + } + #endif + + status = SSLSetIOFuncs(sslContext, &SSLReadFunction, &SSLWriteFunction); + if (status != noErr) + { + [self closeWithError:[self otherError:@"Error in SSLSetIOFuncs"]]; + return; + } + + status = SSLSetConnection(sslContext, (__bridge SSLConnectionRef)self); + if (status != noErr) + { + [self closeWithError:[self otherError:@"Error in SSLSetConnection"]]; + return; + } + + // Configure SSLContext from given settings + // + // Checklist: + // 1. kCFStreamSSLPeerName + // 2. kCFStreamSSLAllowsAnyRoot + // 3. kCFStreamSSLAllowsExpiredRoots + // 4. kCFStreamSSLValidatesCertificateChain + // 5. kCFStreamSSLAllowsExpiredCertificates + // 6. kCFStreamSSLCertificates + // 7. kCFStreamSSLLevel (GCDAsyncSocketSSLProtocolVersionMin / GCDAsyncSocketSSLProtocolVersionMax) + // 8. GCDAsyncSocketSSLCipherSuites + // 9. GCDAsyncSocketSSLDiffieHellmanParameters (Mac) + + id value; + + // 1. kCFStreamSSLPeerName + + value = [tlsSettings objectForKey:(NSString *)kCFStreamSSLPeerName]; + if ([value isKindOfClass:[NSString class]]) + { + NSString *peerName = (NSString *)value; + + const char *peer = [peerName UTF8String]; + size_t peerLen = strlen(peer); + + status = SSLSetPeerDomainName(sslContext, peer, peerLen); + if (status != noErr) + { + [self closeWithError:[self otherError:@"Error in SSLSetPeerDomainName"]]; + return; + } + } + + // 2. kCFStreamSSLAllowsAnyRoot + + value = [tlsSettings objectForKey:(NSString *)kCFStreamSSLAllowsAnyRoot]; + if (value) + { + #if TARGET_OS_IPHONE + NSAssert(NO, @"Security option unavailable via SecureTransport in iOS - kCFStreamSSLAllowsAnyRoot"); + #else + + BOOL allowsAnyRoot = [value boolValue]; + + status = SSLSetAllowsAnyRoot(sslContext, allowsAnyRoot); + if (status != noErr) + { + [self closeWithError:[self otherError:@"Error in SSLSetAllowsAnyRoot"]]; + return; + } + + #endif + } + + // 3. kCFStreamSSLAllowsExpiredRoots + + value = [tlsSettings objectForKey:(NSString *)kCFStreamSSLAllowsExpiredRoots]; + if (value) + { + #if TARGET_OS_IPHONE + NSAssert(NO, @"Security option unavailable via SecureTransport in iOS - kCFStreamSSLAllowsExpiredRoots"); + #else + + BOOL allowsExpiredRoots = [value boolValue]; + + status = SSLSetAllowsExpiredRoots(sslContext, allowsExpiredRoots); + if (status != noErr) + { + [self closeWithError:[self otherError:@"Error in SSLSetAllowsExpiredRoots"]]; + return; + } + + #endif + } + + // 4. kCFStreamSSLValidatesCertificateChain + + value = [tlsSettings objectForKey:(NSString *)kCFStreamSSLValidatesCertificateChain]; + if (value) + { + #if TARGET_OS_IPHONE + NSAssert(NO, @"Security option unavailable via SecureTransport in iOS - kCFStreamSSLValidatesCertificateChain"); + #else + + BOOL validatesCertChain = [value boolValue]; + + status = SSLSetEnableCertVerify(sslContext, validatesCertChain); + if (status != noErr) + { + [self closeWithError:[self otherError:@"Error in SSLSetEnableCertVerify"]]; + return; + } + + #endif + } + + // 5. kCFStreamSSLAllowsExpiredCertificates + + value = [tlsSettings objectForKey:(NSString *)kCFStreamSSLAllowsExpiredCertificates]; + if (value) + { + #if TARGET_OS_IPHONE + NSAssert(NO, @"Security option unavailable via SecureTransport in iOS - kCFStreamSSLAllowsExpiredCertificates"); + #else + + BOOL allowsExpiredCerts = [value boolValue]; + + status = SSLSetAllowsExpiredCerts(sslContext, allowsExpiredCerts); + if (status != noErr) + { + [self closeWithError:[self otherError:@"Error in SSLSetAllowsExpiredCerts"]]; + return; + } + + #endif + } + + // 6. kCFStreamSSLCertificates + + value = [tlsSettings objectForKey:(NSString *)kCFStreamSSLCertificates]; + if (value) + { + CFArrayRef certs = (__bridge CFArrayRef)value; + + status = SSLSetCertificate(sslContext, certs); + if (status != noErr) + { + [self closeWithError:[self otherError:@"Error in SSLSetCertificate"]]; + return; + } + } + + // 7. kCFStreamSSLLevel + + #if TARGET_OS_IPHONE + { + NSString *sslLevel = [tlsSettings objectForKey:(NSString *)kCFStreamSSLLevel]; + + NSString *sslMinLevel = [tlsSettings objectForKey:GCDAsyncSocketSSLProtocolVersionMin]; + NSString *sslMaxLevel = [tlsSettings objectForKey:GCDAsyncSocketSSLProtocolVersionMax]; + + if (sslLevel) + { + if (sslMinLevel || sslMaxLevel) + { + LogWarn(@"kCFStreamSSLLevel security option ignored. Overriden by " + @"GCDAsyncSocketSSLProtocolVersionMin and/or GCDAsyncSocketSSLProtocolVersionMax"); + } + else + { + if ([sslLevel isEqualToString:(NSString *)kCFStreamSocketSecurityLevelSSLv3]) + { + sslMinLevel = sslMaxLevel = @"kSSLProtocol3"; + } + else if ([sslLevel isEqualToString:(NSString *)kCFStreamSocketSecurityLevelTLSv1]) + { + sslMinLevel = sslMaxLevel = @"kTLSProtocol1"; + } + else + { + LogWarn(@"Unable to match kCFStreamSSLLevel security option to valid SSL protocol min/max"); + } + } + } + + if (sslMinLevel || sslMaxLevel) + { + OSStatus status1 = noErr; + OSStatus status2 = noErr; + + SSLProtocol (^sslProtocolForString)(NSString*) = ^SSLProtocol (NSString *protocolStr) { + + if ([protocolStr isEqualToString:@"kSSLProtocol3"]) return kSSLProtocol3; + if ([protocolStr isEqualToString:@"kTLSProtocol1"]) return kTLSProtocol1; + if ([protocolStr isEqualToString:@"kTLSProtocol11"]) return kTLSProtocol11; + if ([protocolStr isEqualToString:@"kTLSProtocol12"]) return kTLSProtocol12; + + return kSSLProtocolUnknown; + }; + + SSLProtocol minProtocol = sslProtocolForString(sslMinLevel); + SSLProtocol maxProtocol = sslProtocolForString(sslMaxLevel); + + if (minProtocol != kSSLProtocolUnknown) + { + status1 = SSLSetProtocolVersionMin(sslContext, minProtocol); + } + if (maxProtocol != kSSLProtocolUnknown) + { + status2 = SSLSetProtocolVersionMax(sslContext, maxProtocol); + } + + if (status1 != noErr || status2 != noErr) + { + [self closeWithError:[self otherError:@"Error in SSLSetProtocolVersionMinMax"]]; + return; + } + } + } + #else + { + value = [tlsSettings objectForKey:(NSString *)kCFStreamSSLLevel]; + if (value) + { + NSString *sslLevel = (NSString *)value; + + OSStatus status1 = noErr; + OSStatus status2 = noErr; + OSStatus status3 = noErr; + + if ([sslLevel isEqualToString:(NSString *)kCFStreamSocketSecurityLevelSSLv2]) + { + // kCFStreamSocketSecurityLevelSSLv2: + // + // Specifies that SSL version 2 be set as the security protocol. + + status1 = SSLSetProtocolVersionEnabled(sslContext, kSSLProtocolAll, NO); + status2 = SSLSetProtocolVersionEnabled(sslContext, kSSLProtocol2, YES); + } + else if ([sslLevel isEqualToString:(NSString *)kCFStreamSocketSecurityLevelSSLv3]) + { + // kCFStreamSocketSecurityLevelSSLv3: + // + // Specifies that SSL version 3 be set as the security protocol. + // If SSL version 3 is not available, specifies that SSL version 2 be set as the security protocol. + + status1 = SSLSetProtocolVersionEnabled(sslContext, kSSLProtocolAll, NO); + status2 = SSLSetProtocolVersionEnabled(sslContext, kSSLProtocol2, YES); + status3 = SSLSetProtocolVersionEnabled(sslContext, kSSLProtocol3, YES); + } + else if ([sslLevel isEqualToString:(NSString *)kCFStreamSocketSecurityLevelTLSv1]) + { + // kCFStreamSocketSecurityLevelTLSv1: + // + // Specifies that TLS version 1 be set as the security protocol. + + status1 = SSLSetProtocolVersionEnabled(sslContext, kSSLProtocolAll, NO); + status2 = SSLSetProtocolVersionEnabled(sslContext, kTLSProtocol1, YES); + } + else if ([sslLevel isEqualToString:(NSString *)kCFStreamSocketSecurityLevelNegotiatedSSL]) + { + // kCFStreamSocketSecurityLevelNegotiatedSSL: + // + // Specifies that the highest level security protocol that can be negotiated be used. + + status1 = SSLSetProtocolVersionEnabled(sslContext, kSSLProtocolAll, YES); + } + + if (status1 != noErr || status2 != noErr || status3 != noErr) + { + [self closeWithError:[self otherError:@"Error in SSLSetProtocolVersionEnabled"]]; + return; + } + } + } + #endif + + // 8. GCDAsyncSocketSSLCipherSuites + + value = [tlsSettings objectForKey:GCDAsyncSocketSSLCipherSuites]; + if (value) + { + NSArray *cipherSuites = (NSArray *)value; + NSUInteger numberCiphers = [cipherSuites count]; + SSLCipherSuite ciphers[numberCiphers]; + + NSUInteger cipherIndex; + for (cipherIndex = 0; cipherIndex < numberCiphers; cipherIndex++) + { + NSNumber *cipherObject = [cipherSuites objectAtIndex:cipherIndex]; + ciphers[cipherIndex] = [cipherObject shortValue]; + } + + status = SSLSetEnabledCiphers(sslContext, ciphers, numberCiphers); + if (status != noErr) + { + [self closeWithError:[self otherError:@"Error in SSLSetEnabledCiphers"]]; + return; + } + } + + // 9. GCDAsyncSocketSSLDiffieHellmanParameters + + #if !TARGET_OS_IPHONE + value = [tlsSettings objectForKey:GCDAsyncSocketSSLDiffieHellmanParameters]; + if (value) + { + NSData *diffieHellmanData = (NSData *)value; + + status = SSLSetDiffieHellmanParams(sslContext, [diffieHellmanData bytes], [diffieHellmanData length]); + if (status != noErr) + { + [self closeWithError:[self otherError:@"Error in SSLSetDiffieHellmanParams"]]; + return; + } + } + #endif + + // Setup the sslPreBuffer + // + // Any data in the preBuffer needs to be moved into the sslPreBuffer, + // as this data is now part of the secure read stream. + + sslPreBuffer = [[GCDAsyncSocketPreBuffer alloc] initWithCapacity:(1024 * 4)]; + + size_t preBufferLength = [preBuffer availableBytes]; + + if (preBufferLength > 0) + { + [sslPreBuffer ensureCapacityForWrite:preBufferLength]; + + memcpy([sslPreBuffer writeBuffer], [preBuffer readBuffer], preBufferLength); + [preBuffer didRead:preBufferLength]; + [sslPreBuffer didWrite:preBufferLength]; + } + + sslErrCode = noErr; + + // Start the SSL Handshake process + + [self ssl_continueSSLHandshake]; +} + +- (void)ssl_continueSSLHandshake +{ + LogTrace(); + + // If the return value is noErr, the session is ready for normal secure communication. + // If the return value is errSSLWouldBlock, the SSLHandshake function must be called again. + // Otherwise, the return value indicates an error code. + + OSStatus status = SSLHandshake(sslContext); + + if (status == noErr) + { + LogVerbose(@"SSLHandshake complete"); + + flags &= ~kStartingReadTLS; + flags &= ~kStartingWriteTLS; + + flags |= kSocketSecure; + + __strong id theDelegate = delegate; + + if (delegateQueue && [theDelegate respondsToSelector:@selector(socketDidSecure:)]) + { + dispatch_async(delegateQueue, ^{ @autoreleasepool { + + [theDelegate socketDidSecure:self]; + }}); + } + + [self endCurrentRead]; + [self endCurrentWrite]; + + [self maybeDequeueRead]; + [self maybeDequeueWrite]; + } + else if (status == errSSLWouldBlock) + { + LogVerbose(@"SSLHandshake continues..."); + + // Handshake continues... + // + // This method will be called again from doReadData or doWriteData. + } + else + { + [self closeWithError:[self sslError:status]]; + } +} + +#endif + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +#pragma mark Security via CFStream +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +#if TARGET_OS_IPHONE + +- (void)cf_finishSSLHandshake +{ + LogTrace(); + + if ((flags & kStartingReadTLS) && (flags & kStartingWriteTLS)) + { + flags &= ~kStartingReadTLS; + flags &= ~kStartingWriteTLS; + + flags |= kSocketSecure; + + __strong id theDelegate = delegate; + + if (delegateQueue && [theDelegate respondsToSelector:@selector(socketDidSecure:)]) + { + dispatch_async(delegateQueue, ^{ @autoreleasepool { + + [theDelegate socketDidSecure:self]; + }}); + } + + [self endCurrentRead]; + [self endCurrentWrite]; + + [self maybeDequeueRead]; + [self maybeDequeueWrite]; + } +} + +- (void)cf_abortSSLHandshake:(NSError *)error +{ + LogTrace(); + + if ((flags & kStartingReadTLS) && (flags & kStartingWriteTLS)) + { + flags &= ~kStartingReadTLS; + flags &= ~kStartingWriteTLS; + + [self closeWithError:error]; + } +} + +- (void)cf_startTLS +{ + LogTrace(); + + LogVerbose(@"Starting TLS (via CFStream)..."); + + if ([preBuffer availableBytes] > 0) + { + NSString *msg = @"Invalid TLS transition. Handshake has already been read from socket."; + + [self closeWithError:[self otherError:msg]]; + return; + } + + [self suspendReadSource]; + [self suspendWriteSource]; + + socketFDBytesAvailable = 0; + flags &= ~kSocketCanAcceptBytes; + flags &= ~kSecureSocketHasBytesAvailable; + + flags |= kUsingCFStreamForTLS; + + if (![self createReadAndWriteStream]) + { + [self closeWithError:[self otherError:@"Error in CFStreamCreatePairWithSocket"]]; + return; + } + + if (![self registerForStreamCallbacksIncludingReadWrite:YES]) + { + [self closeWithError:[self otherError:@"Error in CFStreamSetClient"]]; + return; + } + + if (![self addStreamsToRunLoop]) + { + [self closeWithError:[self otherError:@"Error in CFStreamScheduleWithRunLoop"]]; + return; + } + + NSAssert([currentRead isKindOfClass:[GCDAsyncSpecialPacket class]], @"Invalid read packet for startTLS"); + NSAssert([currentWrite isKindOfClass:[GCDAsyncSpecialPacket class]], @"Invalid write packet for startTLS"); + + GCDAsyncSpecialPacket *tlsPacket = (GCDAsyncSpecialPacket *)currentRead; + CFDictionaryRef tlsSettings = (__bridge CFDictionaryRef)tlsPacket->tlsSettings; + + // Getting an error concerning kCFStreamPropertySSLSettings ? + // You need to add the CFNetwork framework to your iOS application. + + BOOL r1 = CFReadStreamSetProperty(readStream, kCFStreamPropertySSLSettings, tlsSettings); + BOOL r2 = CFWriteStreamSetProperty(writeStream, kCFStreamPropertySSLSettings, tlsSettings); + + // For some reason, starting around the time of iOS 4.3, + // the first call to set the kCFStreamPropertySSLSettings will return true, + // but the second will return false. + // + // Order doesn't seem to matter. + // So you could call CFReadStreamSetProperty and then CFWriteStreamSetProperty, or you could reverse the order. + // Either way, the first call will return true, and the second returns false. + // + // Interestingly, this doesn't seem to affect anything. + // Which is not altogether unusual, as the documentation seems to suggest that (for many settings) + // setting it on one side of the stream automatically sets it for the other side of the stream. + // + // Although there isn't anything in the documentation to suggest that the second attempt would fail. + // + // Furthermore, this only seems to affect streams that are negotiating a security upgrade. + // In other words, the socket gets connected, there is some back-and-forth communication over the unsecure + // connection, and then a startTLS is issued. + // So this mostly affects newer protocols (XMPP, IMAP) as opposed to older protocols (HTTPS). + + if (!r1 && !r2) // Yes, the && is correct - workaround for apple bug. + { + [self closeWithError:[self otherError:@"Error in CFStreamSetProperty"]]; + return; + } + + if (![self openStreams]) + { + [self closeWithError:[self otherError:@"Error in CFStreamOpen"]]; + return; + } + + LogVerbose(@"Waiting for SSL Handshake to complete..."); +} + +#endif + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +#pragma mark CFStream +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +#if TARGET_OS_IPHONE + ++ (void)ignore:(id)_ +{} + ++ (void)startCFStreamThreadIfNeeded +{ + static dispatch_once_t predicate; + dispatch_once(&predicate, ^{ + + cfstreamThread = [[NSThread alloc] initWithTarget:self + selector:@selector(cfstreamThread) + object:nil]; + [cfstreamThread start]; + }); +} + ++ (void)cfstreamThread { @autoreleasepool +{ + [[NSThread currentThread] setName:GCDAsyncSocketThreadName]; + + LogInfo(@"CFStreamThread: Started"); + + // We can't run the run loop unless it has an associated input source or a timer. + // So we'll just create a timer that will never fire - unless the server runs for decades. + [NSTimer scheduledTimerWithTimeInterval:[[NSDate distantFuture] timeIntervalSinceNow] + target:self + selector:@selector(ignore:) + userInfo:nil + repeats:YES]; + + [[NSRunLoop currentRunLoop] run]; + + LogInfo(@"CFStreamThread: Stopped"); +}} + ++ (void)scheduleCFStreams:(GCDAsyncSocket *)asyncSocket +{ + LogTrace(); + NSAssert([NSThread currentThread] == cfstreamThread, @"Invoked on wrong thread"); + + CFRunLoopRef runLoop = CFRunLoopGetCurrent(); + + if (asyncSocket->readStream) + CFReadStreamScheduleWithRunLoop(asyncSocket->readStream, runLoop, kCFRunLoopDefaultMode); + + if (asyncSocket->writeStream) + CFWriteStreamScheduleWithRunLoop(asyncSocket->writeStream, runLoop, kCFRunLoopDefaultMode); +} + ++ (void)unscheduleCFStreams:(GCDAsyncSocket *)asyncSocket +{ + LogTrace(); + NSAssert([NSThread currentThread] == cfstreamThread, @"Invoked on wrong thread"); + + CFRunLoopRef runLoop = CFRunLoopGetCurrent(); + + if (asyncSocket->readStream) + CFReadStreamUnscheduleFromRunLoop(asyncSocket->readStream, runLoop, kCFRunLoopDefaultMode); + + if (asyncSocket->writeStream) + CFWriteStreamUnscheduleFromRunLoop(asyncSocket->writeStream, runLoop, kCFRunLoopDefaultMode); +} + +static void CFReadStreamCallback (CFReadStreamRef stream, CFStreamEventType type, void *pInfo) +{ + GCDAsyncSocket *asyncSocket = (__bridge GCDAsyncSocket *)pInfo; + + switch(type) + { + case kCFStreamEventHasBytesAvailable: + { + dispatch_async(asyncSocket->socketQueue, ^{ @autoreleasepool { + + LogCVerbose(@"CFReadStreamCallback - HasBytesAvailable"); + + if (asyncSocket->readStream != stream) + return_from_block; + + if ((asyncSocket->flags & kStartingReadTLS) && (asyncSocket->flags & kStartingWriteTLS)) + { + // If we set kCFStreamPropertySSLSettings before we opened the streams, this might be a lie. + // (A callback related to the tcp stream, but not to the SSL layer). + + if (CFReadStreamHasBytesAvailable(asyncSocket->readStream)) + { + asyncSocket->flags |= kSecureSocketHasBytesAvailable; + [asyncSocket cf_finishSSLHandshake]; + } + } + else + { + asyncSocket->flags |= kSecureSocketHasBytesAvailable; + [asyncSocket doReadData]; + } + }}); + + break; + } + default: + { + NSError *error = (__bridge_transfer NSError *)CFReadStreamCopyError(stream); + + if (error == nil && type == kCFStreamEventEndEncountered) + { + error = [asyncSocket connectionClosedError]; + } + + dispatch_async(asyncSocket->socketQueue, ^{ @autoreleasepool { + + LogCVerbose(@"CFReadStreamCallback - Other"); + + if (asyncSocket->readStream != stream) + return_from_block; + + if ((asyncSocket->flags & kStartingReadTLS) && (asyncSocket->flags & kStartingWriteTLS)) + { + [asyncSocket cf_abortSSLHandshake:error]; + } + else + { + [asyncSocket closeWithError:error]; + } + }}); + + break; + } + } + +} + +static void CFWriteStreamCallback (CFWriteStreamRef stream, CFStreamEventType type, void *pInfo) +{ + GCDAsyncSocket *asyncSocket = (__bridge GCDAsyncSocket *)pInfo; + + switch(type) + { + case kCFStreamEventCanAcceptBytes: + { + dispatch_async(asyncSocket->socketQueue, ^{ @autoreleasepool { + + LogCVerbose(@"CFWriteStreamCallback - CanAcceptBytes"); + + if (asyncSocket->writeStream != stream) + return_from_block; + + if ((asyncSocket->flags & kStartingReadTLS) && (asyncSocket->flags & kStartingWriteTLS)) + { + // If we set kCFStreamPropertySSLSettings before we opened the streams, this might be a lie. + // (A callback related to the tcp stream, but not to the SSL layer). + + if (CFWriteStreamCanAcceptBytes(asyncSocket->writeStream)) + { + asyncSocket->flags |= kSocketCanAcceptBytes; + [asyncSocket cf_finishSSLHandshake]; + } + } + else + { + asyncSocket->flags |= kSocketCanAcceptBytes; + [asyncSocket doWriteData]; + } + }}); + + break; + } + default: + { + NSError *error = (__bridge_transfer NSError *)CFWriteStreamCopyError(stream); + + if (error == nil && type == kCFStreamEventEndEncountered) + { + error = [asyncSocket connectionClosedError]; + } + + dispatch_async(asyncSocket->socketQueue, ^{ @autoreleasepool { + + LogCVerbose(@"CFWriteStreamCallback - Other"); + + if (asyncSocket->writeStream != stream) + return_from_block; + + if ((asyncSocket->flags & kStartingReadTLS) && (asyncSocket->flags & kStartingWriteTLS)) + { + [asyncSocket cf_abortSSLHandshake:error]; + } + else + { + [asyncSocket closeWithError:error]; + } + }}); + + break; + } + } + +} + +- (BOOL)createReadAndWriteStream +{ + LogTrace(); + + NSAssert(dispatch_get_specific(IsOnSocketQueueOrTargetQueueKey), @"Must be dispatched on socketQueue"); + + + if (readStream || writeStream) + { + // Streams already created + return YES; + } + + int socketFD = (socket6FD == SOCKET_NULL) ? socket4FD : socket6FD; + + if (socketFD == SOCKET_NULL) + { + // Cannot create streams without a file descriptor + return NO; + } + + if (![self isConnected]) + { + // Cannot create streams until file descriptor is connected + return NO; + } + + LogVerbose(@"Creating read and write stream..."); + + CFStreamCreatePairWithSocket(NULL, (CFSocketNativeHandle)socketFD, &readStream, &writeStream); + + // The kCFStreamPropertyShouldCloseNativeSocket property should be false by default (for our case). + // But let's not take any chances. + + if (readStream) + CFReadStreamSetProperty(readStream, kCFStreamPropertyShouldCloseNativeSocket, kCFBooleanFalse); + if (writeStream) + CFWriteStreamSetProperty(writeStream, kCFStreamPropertyShouldCloseNativeSocket, kCFBooleanFalse); + + if ((readStream == NULL) || (writeStream == NULL)) + { + LogWarn(@"Unable to create read and write stream..."); + + if (readStream) + { + CFReadStreamClose(readStream); + CFRelease(readStream); + readStream = NULL; + } + if (writeStream) + { + CFWriteStreamClose(writeStream); + CFRelease(writeStream); + writeStream = NULL; + } + + return NO; + } + + return YES; +} + +- (BOOL)registerForStreamCallbacksIncludingReadWrite:(BOOL)includeReadWrite +{ + LogVerbose(@"%@ %@", THIS_METHOD, (includeReadWrite ? @"YES" : @"NO")); + + NSAssert(dispatch_get_specific(IsOnSocketQueueOrTargetQueueKey), @"Must be dispatched on socketQueue"); + NSAssert((readStream != NULL && writeStream != NULL), @"Read/Write stream is null"); + + streamContext.version = 0; + streamContext.info = (__bridge void *)(self); + streamContext.retain = nil; + streamContext.release = nil; + streamContext.copyDescription = nil; + + CFOptionFlags readStreamEvents = kCFStreamEventErrorOccurred | kCFStreamEventEndEncountered; + if (includeReadWrite) + readStreamEvents |= kCFStreamEventHasBytesAvailable; + + if (!CFReadStreamSetClient(readStream, readStreamEvents, &CFReadStreamCallback, &streamContext)) + { + return NO; + } + + CFOptionFlags writeStreamEvents = kCFStreamEventErrorOccurred | kCFStreamEventEndEncountered; + if (includeReadWrite) + writeStreamEvents |= kCFStreamEventCanAcceptBytes; + + if (!CFWriteStreamSetClient(writeStream, writeStreamEvents, &CFWriteStreamCallback, &streamContext)) + { + return NO; + } + + return YES; +} + +- (BOOL)addStreamsToRunLoop +{ + LogTrace(); + + NSAssert(dispatch_get_specific(IsOnSocketQueueOrTargetQueueKey), @"Must be dispatched on socketQueue"); + NSAssert((readStream != NULL && writeStream != NULL), @"Read/Write stream is null"); + + if (!(flags & kAddedStreamsToRunLoop)) + { + LogVerbose(@"Adding streams to runloop..."); + + [[self class] startCFStreamThreadIfNeeded]; + [[self class] performSelector:@selector(scheduleCFStreams:) + onThread:cfstreamThread + withObject:self + waitUntilDone:YES]; + + flags |= kAddedStreamsToRunLoop; + } + + return YES; +} + +- (void)removeStreamsFromRunLoop +{ + LogTrace(); + + NSAssert(dispatch_get_specific(IsOnSocketQueueOrTargetQueueKey), @"Must be dispatched on socketQueue"); + NSAssert((readStream != NULL && writeStream != NULL), @"Read/Write stream is null"); + + if (flags & kAddedStreamsToRunLoop) + { + LogVerbose(@"Removing streams from runloop..."); + + [[self class] performSelector:@selector(unscheduleCFStreams:) + onThread:cfstreamThread + withObject:self + waitUntilDone:YES]; + + flags &= ~kAddedStreamsToRunLoop; + } +} + +- (BOOL)openStreams +{ + LogTrace(); + + NSAssert(dispatch_get_specific(IsOnSocketQueueOrTargetQueueKey), @"Must be dispatched on socketQueue"); + NSAssert((readStream != NULL && writeStream != NULL), @"Read/Write stream is null"); + + CFStreamStatus readStatus = CFReadStreamGetStatus(readStream); + CFStreamStatus writeStatus = CFWriteStreamGetStatus(writeStream); + + if ((readStatus == kCFStreamStatusNotOpen) || (writeStatus == kCFStreamStatusNotOpen)) + { + LogVerbose(@"Opening read and write stream..."); + + BOOL r1 = CFReadStreamOpen(readStream); + BOOL r2 = CFWriteStreamOpen(writeStream); + + if (!r1 || !r2) + { + LogError(@"Error in CFStreamOpen"); + return NO; + } + } + + return YES; +} + +#endif + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +#pragma mark Advanced +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +/** + * See header file for big discussion of this method. +**/ +- (BOOL)autoDisconnectOnClosedReadStream +{ + // Note: YES means kAllowHalfDuplexConnection is OFF + + if (dispatch_get_specific(IsOnSocketQueueOrTargetQueueKey)) + { + return ((config & kAllowHalfDuplexConnection) == 0); + } + else + { + __block BOOL result; + + dispatch_sync(socketQueue, ^{ + result = ((config & kAllowHalfDuplexConnection) == 0); + }); + + return result; + } +} + +/** + * See header file for big discussion of this method. +**/ +- (void)setAutoDisconnectOnClosedReadStream:(BOOL)flag +{ + // Note: YES means kAllowHalfDuplexConnection is OFF + + dispatch_block_t block = ^{ + + if (flag) + config &= ~kAllowHalfDuplexConnection; + else + config |= kAllowHalfDuplexConnection; + }; + + if (dispatch_get_specific(IsOnSocketQueueOrTargetQueueKey)) + block(); + else + dispatch_async(socketQueue, block); +} + + +/** + * See header file for big discussion of this method. +**/ +- (void)markSocketQueueTargetQueue:(dispatch_queue_t)socketNewTargetQueue +{ + void *nonNullUnusedPointer = (__bridge void *)self; + dispatch_queue_set_specific(socketNewTargetQueue, IsOnSocketQueueOrTargetQueueKey, nonNullUnusedPointer, NULL); +} + +/** + * See header file for big discussion of this method. +**/ +- (void)unmarkSocketQueueTargetQueue:(dispatch_queue_t)socketOldTargetQueue +{ + dispatch_queue_set_specific(socketOldTargetQueue, IsOnSocketQueueOrTargetQueueKey, NULL, NULL); +} + +/** + * See header file for big discussion of this method. +**/ +- (void)performBlock:(dispatch_block_t)block +{ + if (dispatch_get_specific(IsOnSocketQueueOrTargetQueueKey)) + block(); + else + dispatch_sync(socketQueue, block); +} + +/** + * Questions? Have you read the header file? +**/ +- (int)socketFD +{ + if (!dispatch_get_specific(IsOnSocketQueueOrTargetQueueKey)) + { + LogWarn(@"%@ - Method only available from within the context of a performBlock: invocation", THIS_METHOD); + return SOCKET_NULL; + } + + if (socket4FD != SOCKET_NULL) + return socket4FD; + else + return socket6FD; +} + +/** + * Questions? Have you read the header file? +**/ +- (int)socket4FD +{ + if (!dispatch_get_specific(IsOnSocketQueueOrTargetQueueKey)) + { + LogWarn(@"%@ - Method only available from within the context of a performBlock: invocation", THIS_METHOD); + return SOCKET_NULL; + } + + return socket4FD; +} + +/** + * Questions? Have you read the header file? +**/ +- (int)socket6FD +{ + if (!dispatch_get_specific(IsOnSocketQueueOrTargetQueueKey)) + { + LogWarn(@"%@ - Method only available from within the context of a performBlock: invocation", THIS_METHOD); + return SOCKET_NULL; + } + + return socket6FD; +} + +#if TARGET_OS_IPHONE + +/** + * Questions? Have you read the header file? +**/ +- (CFReadStreamRef)readStream +{ + if (!dispatch_get_specific(IsOnSocketQueueOrTargetQueueKey)) + { + LogWarn(@"%@ - Method only available from within the context of a performBlock: invocation", THIS_METHOD); + return NULL; + } + + if (readStream == NULL) + [self createReadAndWriteStream]; + + return readStream; +} + +/** + * Questions? Have you read the header file? +**/ +- (CFWriteStreamRef)writeStream +{ + if (!dispatch_get_specific(IsOnSocketQueueOrTargetQueueKey)) + { + LogWarn(@"%@ - Method only available from within the context of a performBlock: invocation", THIS_METHOD); + return NULL; + } + + if (writeStream == NULL) + [self createReadAndWriteStream]; + + return writeStream; +} + +- (BOOL)enableBackgroundingOnSocketWithCaveat:(BOOL)caveat +{ + if (![self createReadAndWriteStream]) + { + // Error occured creating streams (perhaps socket isn't open) + return NO; + } + + BOOL r1, r2; + + LogVerbose(@"Enabling backgrouding on socket"); + + r1 = CFReadStreamSetProperty(readStream, kCFStreamNetworkServiceType, kCFStreamNetworkServiceTypeVoIP); + r2 = CFWriteStreamSetProperty(writeStream, kCFStreamNetworkServiceType, kCFStreamNetworkServiceTypeVoIP); + + if (!r1 || !r2) + { + return NO; + } + + if (!caveat) + { + if (![self openStreams]) + { + return NO; + } + } + + return YES; +} + +/** + * Questions? Have you read the header file? +**/ +- (BOOL)enableBackgroundingOnSocket +{ + LogTrace(); + + if (!dispatch_get_specific(IsOnSocketQueueOrTargetQueueKey)) + { + LogWarn(@"%@ - Method only available from within the context of a performBlock: invocation", THIS_METHOD); + return NO; + } + + return [self enableBackgroundingOnSocketWithCaveat:NO]; +} + +- (BOOL)enableBackgroundingOnSocketWithCaveat // Deprecated in iOS 4.??? +{ + // This method was created as a workaround for a bug in iOS. + // Apple has since fixed this bug. + // I'm not entirely sure which version of iOS they fixed it in... + + LogTrace(); + + if (!dispatch_get_specific(IsOnSocketQueueOrTargetQueueKey)) + { + LogWarn(@"%@ - Method only available from within the context of a performBlock: invocation", THIS_METHOD); + return NO; + } + + return [self enableBackgroundingOnSocketWithCaveat:YES]; +} + +#endif + +#if SECURE_TRANSPORT_MAYBE_AVAILABLE + +- (SSLContextRef)sslContext +{ + if (!dispatch_get_specific(IsOnSocketQueueOrTargetQueueKey)) + { + LogWarn(@"%@ - Method only available from within the context of a performBlock: invocation", THIS_METHOD); + return NULL; + } + + return sslContext; +} + +#endif + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +#pragma mark Class Methods +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ++ (NSString *)hostFromSockaddr4:(const struct sockaddr_in *)pSockaddr4 +{ + char addrBuf[INET_ADDRSTRLEN]; + + if (inet_ntop(AF_INET, &pSockaddr4->sin_addr, addrBuf, (socklen_t)sizeof(addrBuf)) == NULL) + { + addrBuf[0] = '\0'; + } + + return [NSString stringWithCString:addrBuf encoding:NSASCIIStringEncoding]; +} + ++ (NSString *)hostFromSockaddr6:(const struct sockaddr_in6 *)pSockaddr6 +{ + char addrBuf[INET6_ADDRSTRLEN]; + + if (inet_ntop(AF_INET6, &pSockaddr6->sin6_addr, addrBuf, (socklen_t)sizeof(addrBuf)) == NULL) + { + addrBuf[0] = '\0'; + } + + return [NSString stringWithCString:addrBuf encoding:NSASCIIStringEncoding]; +} + ++ (uint16_t)portFromSockaddr4:(const struct sockaddr_in *)pSockaddr4 +{ + return ntohs(pSockaddr4->sin_port); +} + ++ (uint16_t)portFromSockaddr6:(const struct sockaddr_in6 *)pSockaddr6 +{ + return ntohs(pSockaddr6->sin6_port); +} + ++ (NSString *)hostFromAddress:(NSData *)address +{ + NSString *host; + + if ([self getHost:&host port:NULL fromAddress:address]) + return host; + else + return nil; +} + ++ (uint16_t)portFromAddress:(NSData *)address +{ + uint16_t port; + + if ([self getHost:NULL port:&port fromAddress:address]) + return port; + else + return 0; +} + ++ (BOOL)getHost:(NSString **)hostPtr port:(uint16_t *)portPtr fromAddress:(NSData *)address +{ + if ([address length] >= sizeof(struct sockaddr)) + { + const struct sockaddr *sockaddrX = [address bytes]; + + if (sockaddrX->sa_family == AF_INET) + { + if ([address length] >= sizeof(struct sockaddr_in)) + { + struct sockaddr_in sockaddr4; + memcpy(&sockaddr4, sockaddrX, sizeof(sockaddr4)); + + if (hostPtr) *hostPtr = [self hostFromSockaddr4:&sockaddr4]; + if (portPtr) *portPtr = [self portFromSockaddr4:&sockaddr4]; + + return YES; + } + } + else if (sockaddrX->sa_family == AF_INET6) + { + if ([address length] >= sizeof(struct sockaddr_in6)) + { + struct sockaddr_in6 sockaddr6; + memcpy(&sockaddr6, sockaddrX, sizeof(sockaddr6)); + + if (hostPtr) *hostPtr = [self hostFromSockaddr6:&sockaddr6]; + if (portPtr) *portPtr = [self portFromSockaddr6:&sockaddr6]; + + return YES; + } + } + } + + return NO; +} + ++ (NSData *)CRLFData +{ + return [NSData dataWithBytes:"\x0D\x0A" length:2]; +} + ++ (NSData *)CRData +{ + return [NSData dataWithBytes:"\x0D" length:1]; +} + ++ (NSData *)LFData +{ + return [NSData dataWithBytes:"\x0A" length:1]; +} + ++ (NSData *)ZeroData +{ + return [NSData dataWithBytes:"" length:1]; +} + +@end diff --git a/mac/TeamTalk/Frameworks/ShortcutRecorder.framework/Headers b/mac/TeamTalk/Frameworks/ShortcutRecorder.framework/Headers new file mode 100644 index 000000000..a177d2a6b --- /dev/null +++ b/mac/TeamTalk/Frameworks/ShortcutRecorder.framework/Headers @@ -0,0 +1 @@ +Versions/Current/Headers \ No newline at end of file diff --git a/mac/TeamTalk/Frameworks/ShortcutRecorder.framework/Resources b/mac/TeamTalk/Frameworks/ShortcutRecorder.framework/Resources new file mode 100644 index 000000000..953ee36f3 --- /dev/null +++ b/mac/TeamTalk/Frameworks/ShortcutRecorder.framework/Resources @@ -0,0 +1 @@ +Versions/Current/Resources \ No newline at end of file diff --git a/mac/TeamTalk/Frameworks/ShortcutRecorder.framework/ShortcutRecorder b/mac/TeamTalk/Frameworks/ShortcutRecorder.framework/ShortcutRecorder new file mode 100644 index 000000000..2be0db14c --- /dev/null +++ b/mac/TeamTalk/Frameworks/ShortcutRecorder.framework/ShortcutRecorder @@ -0,0 +1 @@ +Versions/Current/ShortcutRecorder \ No newline at end of file diff --git a/mac/TeamTalk/Frameworks/ShortcutRecorder.framework/Versions/A/Headers/SRCommon.h b/mac/TeamTalk/Frameworks/ShortcutRecorder.framework/Versions/A/Headers/SRCommon.h new file mode 100755 index 000000000..bacfbd99e --- /dev/null +++ b/mac/TeamTalk/Frameworks/ShortcutRecorder.framework/Versions/A/Headers/SRCommon.h @@ -0,0 +1,185 @@ +// +// SRCommon.h +// ShortcutRecorder +// +// Copyright 2006-2007 Contributors. All rights reserved. +// +// License: BSD +// +// Contributors: +// David Dauer +// Jesper +// Jamie Kirkpatrick + +#import +#import +#import + +#pragma mark Dummy class + +@interface SRDummyClass : NSObject {} @end + +#pragma mark - +#pragma mark Typedefs + +typedef struct _KeyCombo { + NSUInteger flags; // 0 for no flags + NSInteger code; // -1 for no code +} KeyCombo; + +#pragma mark - +#pragma mark Enums + +// Unicode values of some keyboard glyphs +enum { + KeyboardTabRightGlyph = 0x21E5, + KeyboardTabLeftGlyph = 0x21E4, + KeyboardCommandGlyph = kCommandUnicode, + KeyboardOptionGlyph = kOptionUnicode, + KeyboardShiftGlyph = kShiftUnicode, + KeyboardControlGlyph = kControlUnicode, + KeyboardReturnGlyph = 0x2305, + KeyboardReturnR2LGlyph = 0x21A9, + KeyboardDeleteLeftGlyph = 0x232B, + KeyboardDeleteRightGlyph = 0x2326, + KeyboardPadClearGlyph = 0x2327, + KeyboardLeftArrowGlyph = 0x2190, + KeyboardRightArrowGlyph = 0x2192, + KeyboardUpArrowGlyph = 0x2191, + KeyboardDownArrowGlyph = 0x2193, + KeyboardPageDownGlyph = 0x21DF, + KeyboardPageUpGlyph = 0x21DE, + KeyboardNorthwestArrowGlyph = 0x2196, + KeyboardSoutheastArrowGlyph = 0x2198, + KeyboardEscapeGlyph = 0x238B, + KeyboardHelpGlyph = 0x003F, + KeyboardUpArrowheadGlyph = 0x2303, +}; + +// Special keys +enum { + kSRKeysF1 = 122, + kSRKeysF2 = 120, + kSRKeysF3 = 99, + kSRKeysF4 = 118, + kSRKeysF5 = 96, + kSRKeysF6 = 97, + kSRKeysF7 = 98, + kSRKeysF8 = 100, + kSRKeysF9 = 101, + kSRKeysF10 = 109, + kSRKeysF11 = 103, + kSRKeysF12 = 111, + kSRKeysF13 = 105, + kSRKeysF14 = 107, + kSRKeysF15 = 113, + kSRKeysF16 = 106, + kSRKeysF17 = 64, + kSRKeysF18 = 79, + kSRKeysF19 = 80, + kSRKeysSpace = 49, + kSRKeysDeleteLeft = 51, + kSRKeysDeleteRight = 117, + kSRKeysPadClear = 71, + kSRKeysLeftArrow = 123, + kSRKeysRightArrow = 124, + kSRKeysUpArrow = 126, + kSRKeysDownArrow = 125, + kSRKeysSoutheastArrow = 119, + kSRKeysNorthwestArrow = 115, + kSRKeysEscape = 53, + kSRKeysPageDown = 121, + kSRKeysPageUp = 116, + kSRKeysReturnR2L = 36, + kSRKeysReturn = 76, + kSRKeysTabRight = 48, + kSRKeysHelp = 114 +}; + +#pragma mark - +#pragma mark Macros + +// Localization macros, for use in any bundle +#define SRLoc(key) SRLocalizedString(key, nil) +#define SRLocalizedString(key, comment) NSLocalizedStringFromTableInBundle(key, @"ShortcutRecorder", [NSBundle bundleForClass: [SRDummyClass class]], comment) + +// Image macros, for use in any bundle +//#define SRImage(name) [[[NSImage alloc] initWithContentsOfFile: [[NSBundle bundleForClass: [self class]] pathForImageResource: name]] autorelease] +#define SRResIndImage(name) [SRSharedImageProvider supportingImageWithName:name] +#define SRImage(name) SRResIndImage(name) + +//#define SRCommonWriteDebugImagery + +// Macros for glyps +#define SRInt(x) [NSNumber numberWithInteger:x] +#define SRChar(x) [NSString stringWithFormat: @"%C", (unsigned short)x] + +// Some default values +#define ShortcutRecorderEmptyFlags 0 +#define ShortcutRecorderAllFlags ShortcutRecorderEmptyFlags | (NSCommandKeyMask | NSAlternateKeyMask | NSControlKeyMask | NSShiftKeyMask | NSFunctionKeyMask) +#define ShortcutRecorderEmptyCode -1 + +// These keys will cancel the recoding mode if not pressed with any modifier +#define ShortcutRecorderEscapeKey 53 +#define ShortcutRecorderBackspaceKey 51 +#define ShortcutRecorderDeleteKey 117 + +#pragma mark - +#pragma mark Getting a string of the key combination + +// +// ################### +- Returns string from keyCode like NSEvent's -characters +// # EXPLANATORY # | +- Returns string from keyCode like NSEvent's -charactersUsingModifiers +// # CHART # | | +- Returns fully readable and localized name of modifier (if modifier given) +// ################### | | | +- Returns glyph of modifier (if modifier given) +// SRString... X - - X +// SRReadableString... X - X - +// SRCharacter... - X - - +// +NSString * SRStringForKeyCode( NSInteger keyCode ); +NSString * SRStringForCarbonModifierFlags( NSUInteger flags ); +NSString * SRStringForCarbonModifierFlagsAndKeyCode( NSUInteger flags, NSInteger keyCode ); +NSString * SRStringForCocoaModifierFlags( NSUInteger flags ); +NSString * SRStringForCocoaModifierFlagsAndKeyCode( NSUInteger flags, NSInteger keyCode ); +NSString * SRReadableStringForCarbonModifierFlagsAndKeyCode( NSUInteger flags, NSInteger keyCode ); +NSString * SRReadableStringForCocoaModifierFlagsAndKeyCode( NSUInteger flags, NSInteger keyCode ); +NSString *SRCharacterForKeyCodeAndCarbonFlags(NSInteger keyCode, NSUInteger carbonFlags); +NSString *SRCharacterForKeyCodeAndCocoaFlags(NSInteger keyCode, NSUInteger cocoaFlags); + +#pragma mark Converting between Cocoa and Carbon modifier flags + +NSUInteger SRCarbonToCocoaFlags( NSUInteger carbonFlags ); +NSUInteger SRCocoaToCarbonFlags( NSUInteger cocoaFlags ); + +#pragma mark - +#pragma mark Animation pace function + +CGFloat SRAnimationEaseInOut(CGFloat t); + +#pragma mark - +#pragma mark Inlines + +FOUNDATION_STATIC_INLINE KeyCombo SRMakeKeyCombo(NSInteger code, NSUInteger flags) { + KeyCombo kc; + kc.code = code; + kc.flags = flags; + return kc; +} + +FOUNDATION_STATIC_INLINE BOOL SRIsSpecialKey(NSInteger keyCode) { + return (keyCode == kSRKeysF1 || keyCode == kSRKeysF2 || keyCode == kSRKeysF3 || keyCode == kSRKeysF4 || keyCode == kSRKeysF5 || keyCode == kSRKeysF6 || keyCode == kSRKeysF7 || keyCode == kSRKeysF8 || keyCode == kSRKeysF9 || keyCode == kSRKeysF10 || keyCode == kSRKeysF11 || keyCode == kSRKeysF12 || keyCode == kSRKeysF13 || keyCode == kSRKeysF14 || keyCode == kSRKeysF15 || keyCode == kSRKeysF16 || keyCode == kSRKeysSpace || keyCode == kSRKeysDeleteLeft || keyCode == kSRKeysDeleteRight || keyCode == kSRKeysPadClear || keyCode == kSRKeysLeftArrow || keyCode == kSRKeysRightArrow || keyCode == kSRKeysUpArrow || keyCode == kSRKeysDownArrow || keyCode == kSRKeysSoutheastArrow || keyCode == kSRKeysNorthwestArrow || keyCode == kSRKeysEscape || keyCode == kSRKeysPageDown || keyCode == kSRKeysPageUp || keyCode == kSRKeysReturnR2L || keyCode == kSRKeysReturn || keyCode == kSRKeysTabRight || keyCode == kSRKeysHelp); +} + +#pragma mark - +#pragma mark Additions + +@interface NSAlert( SRAdditions ) ++ (NSAlert *) alertWithNonRecoverableError:(NSError *)error; +@end + +#pragma mark - +#pragma mark Image provider + +@interface SRSharedImageProvider : NSObject ++ (NSImage *)supportingImageWithName:(NSString *)name; +@end diff --git a/mac/TeamTalk/Frameworks/ShortcutRecorder.framework/Versions/A/Headers/SRKeyCodeTransformer.h b/mac/TeamTalk/Frameworks/ShortcutRecorder.framework/Versions/A/Headers/SRKeyCodeTransformer.h new file mode 100755 index 000000000..6f252f375 --- /dev/null +++ b/mac/TeamTalk/Frameworks/ShortcutRecorder.framework/Versions/A/Headers/SRKeyCodeTransformer.h @@ -0,0 +1,16 @@ +// +// SRKeyCodeTransformer.h +// ShortcutRecorder +// +// Copyright 2006-2007 Contributors. All rights reserved. +// +// License: BSD +// +// Contributors: +// David Dauer +// Jesper +// Jamie Kirkpatrick + +#import + +@interface SRKeyCodeTransformer : NSValueTransformer {} @end diff --git a/mac/TeamTalk/Frameworks/ShortcutRecorder.framework/Versions/A/Headers/SRRecorderCell.h b/mac/TeamTalk/Frameworks/ShortcutRecorder.framework/Versions/A/Headers/SRRecorderCell.h new file mode 100755 index 000000000..9bd3b9a0b --- /dev/null +++ b/mac/TeamTalk/Frameworks/ShortcutRecorder.framework/Versions/A/Headers/SRRecorderCell.h @@ -0,0 +1,139 @@ +// +// SRRecorderCell.h +// ShortcutRecorder +// +// Copyright 2006-2007 Contributors. All rights reserved. +// +// License: BSD +// +// Contributors: +// David Dauer +// Jesper +// Jamie Kirkpatrick + +#import +#import "SRCommon.h" + +#define SRMinWidth 50 +#define SRMaxHeight 22 + +#define SRTransitionFPS 30.0f +#define SRTransitionDuration 0.35f +//#define SRTransitionDuration 2.35 +#define SRTransitionFrames (SRTransitionFPS*SRTransitionDuration) +#define SRAnimationAxisIsY YES +#define ShortcutRecorderNewStyleDrawing + +#define SRAnimationOffsetRect(X,Y) (SRAnimationAxisIsY ? NSOffsetRect(X,0.0f,-NSHeight(Y)) : NSOffsetRect(X,NSWidth(Y),0.0f)) + +@class SRRecorderControl, SRValidator; + +enum SRRecorderStyle { + SRGradientBorderStyle = 0, + SRGreyStyle = 1 +}; +typedef enum SRRecorderStyle SRRecorderStyle; + +@interface SRRecorderCell : NSActionCell +{ + NSGradient *recordingGradient; + NSString *autosaveName; + + BOOL isRecording; + BOOL mouseInsideTrackingArea; + BOOL mouseDown; + + SRRecorderStyle style; + + BOOL isAnimating; + CGFloat transitionProgress; + BOOL isAnimatingNow; + BOOL isAnimatingTowardsRecording; + BOOL comboJustChanged; + + NSTrackingRectTag removeTrackingRectTag; + NSTrackingRectTag snapbackTrackingRectTag; + + KeyCombo keyCombo; + BOOL hasKeyChars; + NSString *keyChars; + NSString *keyCharsIgnoringModifiers; + + NSUInteger allowedFlags; + NSUInteger requiredFlags; + NSUInteger recordingFlags; + + BOOL allowsKeyOnly; + BOOL escapeKeysRecord; + + NSSet *cancelCharacterSet; + + SRValidator *validator; + + IBOutlet id delegate; + BOOL globalHotKeys; + void *hotKeyModeToken; +} + +- (void)resetTrackingRects; + +#pragma mark *** Aesthetics *** + ++ (BOOL)styleSupportsAnimation:(SRRecorderStyle)style; + +- (BOOL)animates; +- (void)setAnimates:(BOOL)an; +- (SRRecorderStyle)style; +- (void)setStyle:(SRRecorderStyle)nStyle; + +#pragma mark *** Delegate *** + +- (id)delegate; +- (void)setDelegate:(id)aDelegate; + +#pragma mark *** Responder Control *** + +- (BOOL)becomeFirstResponder; +- (BOOL)resignFirstResponder; + +#pragma mark *** Key Combination Control *** + +- (BOOL)performKeyEquivalent:(NSEvent *)theEvent; +- (void)flagsChanged:(NSEvent *)theEvent; + +- (NSUInteger)allowedFlags; +- (void)setAllowedFlags:(NSUInteger)flags; + +- (NSUInteger)requiredFlags; +- (void)setRequiredFlags:(NSUInteger)flags; + +- (BOOL)allowsKeyOnly; +- (void)setAllowsKeyOnly:(BOOL)nAllowsKeyOnly; +- (void)setAllowsKeyOnly:(BOOL)nAllowsKeyOnly escapeKeysRecord:(BOOL)nEscapeKeysRecord; +- (BOOL)escapeKeysRecord; +- (void)setEscapeKeysRecord:(BOOL)nEscapeKeysRecord; + +- (BOOL)canCaptureGlobalHotKeys; +- (void)setCanCaptureGlobalHotKeys:(BOOL)inState; + +- (KeyCombo)keyCombo; +- (void)setKeyCombo:(KeyCombo)aKeyCombo; + +#pragma mark *** Autosave Control *** + +- (NSString *)autosaveName; +- (void)setAutosaveName:(NSString *)aName; + +// Returns the displayed key combination if set +- (NSString *)keyComboString; + +- (NSString *)keyChars; +- (NSString *)keyCharsIgnoringModifiers; + +@end + +// Delegate Methods +@interface NSObject (SRRecorderCellDelegate) +- (BOOL)shortcutRecorderCell:(SRRecorderCell *)aRecorderCell isKeyCode:(NSInteger)keyCode andFlagsTaken:(NSUInteger)flags reason:(NSString **)aReason; +- (void)shortcutRecorderCell:(SRRecorderCell *)aRecorderCell keyComboDidChange:(KeyCombo)newCombo; +@end diff --git a/mac/TeamTalk/Frameworks/ShortcutRecorder.framework/Versions/A/Headers/SRRecorderControl.h b/mac/TeamTalk/Frameworks/ShortcutRecorder.framework/Versions/A/Headers/SRRecorderControl.h new file mode 100755 index 000000000..777678e42 --- /dev/null +++ b/mac/TeamTalk/Frameworks/ShortcutRecorder.framework/Versions/A/Headers/SRRecorderControl.h @@ -0,0 +1,79 @@ +// +// SRRecorderControl.h +// ShortcutRecorder +// +// Copyright 2006-2007 Contributors. All rights reserved. +// +// License: BSD +// +// Contributors: +// David Dauer +// Jesper +// Jamie Kirkpatrick + +#import +#import "SRRecorderCell.h" + +@interface SRRecorderControl : NSControl +{ + IBOutlet id delegate; +} + +#pragma mark *** Aesthetics *** +- (BOOL)animates; +- (void)setAnimates:(BOOL)an; +- (SRRecorderStyle)style; +- (void)setStyle:(SRRecorderStyle)nStyle; + +#pragma mark *** Delegate *** +- (id)delegate; +- (void)setDelegate:(id)aDelegate; + +#pragma mark *** Key Combination Control *** + +- (NSUInteger)allowedFlags; +- (void)setAllowedFlags:(NSUInteger)flags; + +- (BOOL)allowsKeyOnly; +- (void)setAllowsKeyOnly:(BOOL)nAllowsKeyOnly escapeKeysRecord:(BOOL)nEscapeKeysRecord; +- (BOOL)escapeKeysRecord; + +- (BOOL)canCaptureGlobalHotKeys; +- (void)setCanCaptureGlobalHotKeys:(BOOL)inState; + +- (NSUInteger)requiredFlags; +- (void)setRequiredFlags:(NSUInteger)flags; + +- (KeyCombo)keyCombo; +- (void)setKeyCombo:(KeyCombo)aKeyCombo; + +- (NSString *)keyChars; +- (NSString *)keyCharsIgnoringModifiers; + +#pragma mark *** Autosave Control *** + +- (NSString *)autosaveName; +- (void)setAutosaveName:(NSString *)aName; + +#pragma mark - + +// Returns the displayed key combination if set +- (NSString *)keyComboString; + +#pragma mark *** Conversion Methods *** + +- (NSUInteger)cocoaToCarbonFlags:(NSUInteger)cocoaFlags; +- (NSUInteger)carbonToCocoaFlags:(NSUInteger)carbonFlags; + +#pragma mark *** Binding Methods *** + +- (NSDictionary *)objectValue; +- (void)setObjectValue:(NSDictionary *)shortcut; + +@end + +// Delegate Methods +@interface NSObject (SRRecorderDelegate) +- (BOOL)shortcutRecorder:(SRRecorderControl *)aRecorder isKeyCode:(NSInteger)keyCode andFlagsTaken:(NSUInteger)flags reason:(NSString **)aReason; +- (void)shortcutRecorder:(SRRecorderControl *)aRecorder keyComboDidChange:(KeyCombo)newKeyCombo; +@end diff --git a/mac/TeamTalk/Frameworks/ShortcutRecorder.framework/Versions/A/Headers/SRValidator.h b/mac/TeamTalk/Frameworks/ShortcutRecorder.framework/Versions/A/Headers/SRValidator.h new file mode 100755 index 000000000..0dd8f2832 --- /dev/null +++ b/mac/TeamTalk/Frameworks/ShortcutRecorder.framework/Versions/A/Headers/SRValidator.h @@ -0,0 +1,34 @@ +// +// SRValidator.h +// ShortcutRecorder +// +// Copyright 2006-2007 Contributors. All rights reserved. +// +// License: BSD +// +// Contributors: +// David Dauer +// Jesper +// Jamie Kirkpatrick + +#import + +@interface SRValidator : NSObject { + id delegate; +} + +- (id) initWithDelegate:(id)theDelegate; + +- (BOOL) isKeyCode:(NSInteger)keyCode andFlagsTaken:(NSUInteger)flags error:(NSError **)error; +- (BOOL) isKeyCode:(NSInteger)keyCode andFlags:(NSUInteger)flags takenInMenu:(NSMenu *)menu error:(NSError **)error; + +- (id) delegate; +- (void) setDelegate: (id) theDelegate; + +@end + +#pragma mark - + +@interface NSObject( SRValidation ) +- (BOOL) shortcutValidator:(SRValidator *)validator isKeyCode:(NSInteger)keyCode andFlagsTaken:(NSUInteger)flags reason:(NSString **)aReason; +@end diff --git a/mac/TeamTalk/Frameworks/ShortcutRecorder.framework/Versions/A/Headers/ShortcutRecorder.h b/mac/TeamTalk/Frameworks/ShortcutRecorder.framework/Versions/A/Headers/ShortcutRecorder.h new file mode 100755 index 000000000..855a2882c --- /dev/null +++ b/mac/TeamTalk/Frameworks/ShortcutRecorder.framework/Versions/A/Headers/ShortcutRecorder.h @@ -0,0 +1,17 @@ +// +// ShortcutRecorder.h +// ShortcutRecorder +// - 10.5 version only; master framework header +// +// Copyright 2007 Contributors. All rights reserved. +// +// License: BSD +// +// Contributors to this file: +// Jesper + +#import +#import +#import +#import +#import diff --git a/mac/TeamTalk/Frameworks/ShortcutRecorder.framework/Versions/A/Resources/Info.plist b/mac/TeamTalk/Frameworks/ShortcutRecorder.framework/Versions/A/Resources/Info.plist new file mode 100644 index 000000000..886c38b6f --- /dev/null +++ b/mac/TeamTalk/Frameworks/ShortcutRecorder.framework/Versions/A/Resources/Info.plist @@ -0,0 +1,36 @@ + + + + + BuildMachineOSBuild + 13B42 + CFBundleDevelopmentRegion + English + CFBundleExecutable + ShortcutRecorder + CFBundleIdentifier + net.wafflesoftware.ShortcutRecorder.framework.Leopard + CFBundleInfoDictionaryVersion + 6.0 + CFBundlePackageType + FMWK + CFBundleSignature + ???? + CFBundleVersion + 1.0 + DTCompiler + com.apple.compilers.llvm.clang.1_0 + DTPlatformBuild + 5A3005 + DTPlatformVersion + GM + DTSDKBuild + 13A595 + DTSDKName + macosx10.9 + DTXcode + 0502 + DTXcodeBuild + 5A3005 + + diff --git a/mac/TeamTalk/Frameworks/ShortcutRecorder.framework/Versions/A/Resources/SRRemoveShortcut.tif b/mac/TeamTalk/Frameworks/ShortcutRecorder.framework/Versions/A/Resources/SRRemoveShortcut.tif new file mode 100755 index 000000000..47a7b7168 Binary files /dev/null and b/mac/TeamTalk/Frameworks/ShortcutRecorder.framework/Versions/A/Resources/SRRemoveShortcut.tif differ diff --git a/mac/TeamTalk/Frameworks/ShortcutRecorder.framework/Versions/A/Resources/SRRemoveShortcutPressed.tif b/mac/TeamTalk/Frameworks/ShortcutRecorder.framework/Versions/A/Resources/SRRemoveShortcutPressed.tif new file mode 100755 index 000000000..0119610cd Binary files /dev/null and b/mac/TeamTalk/Frameworks/ShortcutRecorder.framework/Versions/A/Resources/SRRemoveShortcutPressed.tif differ diff --git a/mac/TeamTalk/Frameworks/ShortcutRecorder.framework/Versions/A/Resources/SRRemoveShortcutRollover.tif b/mac/TeamTalk/Frameworks/ShortcutRecorder.framework/Versions/A/Resources/SRRemoveShortcutRollover.tif new file mode 100755 index 000000000..3af4f0b1d Binary files /dev/null and b/mac/TeamTalk/Frameworks/ShortcutRecorder.framework/Versions/A/Resources/SRRemoveShortcutRollover.tif differ diff --git a/mac/TeamTalk/Frameworks/ShortcutRecorder.framework/Versions/A/Resources/SRSnapback.tiff b/mac/TeamTalk/Frameworks/ShortcutRecorder.framework/Versions/A/Resources/SRSnapback.tiff new file mode 100755 index 000000000..0be1e495b Binary files /dev/null and b/mac/TeamTalk/Frameworks/ShortcutRecorder.framework/Versions/A/Resources/SRSnapback.tiff differ diff --git a/mac/TeamTalk/Frameworks/ShortcutRecorder.framework/Versions/A/Resources/ca.lproj/ShortcutRecorder.strings b/mac/TeamTalk/Frameworks/ShortcutRecorder.framework/Versions/A/Resources/ca.lproj/ShortcutRecorder.strings new file mode 100755 index 000000000..ae10bf3fa Binary files /dev/null and b/mac/TeamTalk/Frameworks/ShortcutRecorder.framework/Versions/A/Resources/ca.lproj/ShortcutRecorder.strings differ diff --git a/mac/TeamTalk/Frameworks/ShortcutRecorder.framework/Versions/A/Resources/cs.lproj/ShortcutRecorder.strings b/mac/TeamTalk/Frameworks/ShortcutRecorder.framework/Versions/A/Resources/cs.lproj/ShortcutRecorder.strings new file mode 100755 index 000000000..13cde5d43 Binary files /dev/null and b/mac/TeamTalk/Frameworks/ShortcutRecorder.framework/Versions/A/Resources/cs.lproj/ShortcutRecorder.strings differ diff --git a/mac/TeamTalk/Frameworks/ShortcutRecorder.framework/Versions/A/Resources/da.lproj/ShortcutRecorder.strings b/mac/TeamTalk/Frameworks/ShortcutRecorder.framework/Versions/A/Resources/da.lproj/ShortcutRecorder.strings new file mode 100755 index 000000000..db3986a97 Binary files /dev/null and b/mac/TeamTalk/Frameworks/ShortcutRecorder.framework/Versions/A/Resources/da.lproj/ShortcutRecorder.strings differ diff --git a/mac/TeamTalk/Frameworks/ShortcutRecorder.framework/Versions/A/Resources/de.lproj/ShortcutRecorder.strings b/mac/TeamTalk/Frameworks/ShortcutRecorder.framework/Versions/A/Resources/de.lproj/ShortcutRecorder.strings new file mode 100755 index 000000000..0a406af7c Binary files /dev/null and b/mac/TeamTalk/Frameworks/ShortcutRecorder.framework/Versions/A/Resources/de.lproj/ShortcutRecorder.strings differ diff --git a/mac/TeamTalk/Frameworks/ShortcutRecorder.framework/Versions/A/Resources/el.lproj/ShortcutRecorder.strings b/mac/TeamTalk/Frameworks/ShortcutRecorder.framework/Versions/A/Resources/el.lproj/ShortcutRecorder.strings new file mode 100755 index 000000000..75ea26fde Binary files /dev/null and b/mac/TeamTalk/Frameworks/ShortcutRecorder.framework/Versions/A/Resources/el.lproj/ShortcutRecorder.strings differ diff --git a/mac/TeamTalk/Frameworks/ShortcutRecorder.framework/Versions/A/Resources/en.lproj/ShortcutRecorder.strings b/mac/TeamTalk/Frameworks/ShortcutRecorder.framework/Versions/A/Resources/en.lproj/ShortcutRecorder.strings new file mode 100755 index 000000000..ecc213764 Binary files /dev/null and b/mac/TeamTalk/Frameworks/ShortcutRecorder.framework/Versions/A/Resources/en.lproj/ShortcutRecorder.strings differ diff --git a/mac/TeamTalk/Frameworks/ShortcutRecorder.framework/Versions/A/Resources/es-MX.lproj/ShortcutRecorder.strings b/mac/TeamTalk/Frameworks/ShortcutRecorder.framework/Versions/A/Resources/es-MX.lproj/ShortcutRecorder.strings new file mode 100755 index 000000000..31daeace5 Binary files /dev/null and b/mac/TeamTalk/Frameworks/ShortcutRecorder.framework/Versions/A/Resources/es-MX.lproj/ShortcutRecorder.strings differ diff --git a/mac/TeamTalk/Frameworks/ShortcutRecorder.framework/Versions/A/Resources/es.lproj/ShortcutRecorder.strings b/mac/TeamTalk/Frameworks/ShortcutRecorder.framework/Versions/A/Resources/es.lproj/ShortcutRecorder.strings new file mode 100755 index 000000000..45028feeb Binary files /dev/null and b/mac/TeamTalk/Frameworks/ShortcutRecorder.framework/Versions/A/Resources/es.lproj/ShortcutRecorder.strings differ diff --git a/mac/TeamTalk/Frameworks/ShortcutRecorder.framework/Versions/A/Resources/fr.lproj/ShortcutRecorder.strings b/mac/TeamTalk/Frameworks/ShortcutRecorder.framework/Versions/A/Resources/fr.lproj/ShortcutRecorder.strings new file mode 100755 index 000000000..ff8488510 Binary files /dev/null and b/mac/TeamTalk/Frameworks/ShortcutRecorder.framework/Versions/A/Resources/fr.lproj/ShortcutRecorder.strings differ diff --git a/mac/TeamTalk/Frameworks/ShortcutRecorder.framework/Versions/A/Resources/it.lproj/ShortcutRecorder.strings b/mac/TeamTalk/Frameworks/ShortcutRecorder.framework/Versions/A/Resources/it.lproj/ShortcutRecorder.strings new file mode 100755 index 000000000..b49898097 Binary files /dev/null and b/mac/TeamTalk/Frameworks/ShortcutRecorder.framework/Versions/A/Resources/it.lproj/ShortcutRecorder.strings differ diff --git a/mac/TeamTalk/Frameworks/ShortcutRecorder.framework/Versions/A/Resources/ja.lproj/ShortcutRecorder.strings b/mac/TeamTalk/Frameworks/ShortcutRecorder.framework/Versions/A/Resources/ja.lproj/ShortcutRecorder.strings new file mode 100755 index 000000000..4a48483a2 Binary files /dev/null and b/mac/TeamTalk/Frameworks/ShortcutRecorder.framework/Versions/A/Resources/ja.lproj/ShortcutRecorder.strings differ diff --git a/mac/TeamTalk/Frameworks/ShortcutRecorder.framework/Versions/A/Resources/ko.lproj/ShortcutRecorder.strings b/mac/TeamTalk/Frameworks/ShortcutRecorder.framework/Versions/A/Resources/ko.lproj/ShortcutRecorder.strings new file mode 100755 index 000000000..9b43ae067 Binary files /dev/null and b/mac/TeamTalk/Frameworks/ShortcutRecorder.framework/Versions/A/Resources/ko.lproj/ShortcutRecorder.strings differ diff --git a/mac/TeamTalk/Frameworks/ShortcutRecorder.framework/Versions/A/Resources/nb.lproj/ShortcutRecorder.strings b/mac/TeamTalk/Frameworks/ShortcutRecorder.framework/Versions/A/Resources/nb.lproj/ShortcutRecorder.strings new file mode 100755 index 000000000..8ea479ec5 Binary files /dev/null and b/mac/TeamTalk/Frameworks/ShortcutRecorder.framework/Versions/A/Resources/nb.lproj/ShortcutRecorder.strings differ diff --git a/mac/TeamTalk/Frameworks/ShortcutRecorder.framework/Versions/A/Resources/nl.lproj/ShortcutRecorder.strings b/mac/TeamTalk/Frameworks/ShortcutRecorder.framework/Versions/A/Resources/nl.lproj/ShortcutRecorder.strings new file mode 100755 index 000000000..260dde804 Binary files /dev/null and b/mac/TeamTalk/Frameworks/ShortcutRecorder.framework/Versions/A/Resources/nl.lproj/ShortcutRecorder.strings differ diff --git a/mac/TeamTalk/Frameworks/ShortcutRecorder.framework/Versions/A/Resources/pl.lproj/ShortcutRecorder.strings b/mac/TeamTalk/Frameworks/ShortcutRecorder.framework/Versions/A/Resources/pl.lproj/ShortcutRecorder.strings new file mode 100755 index 000000000..fd8142609 Binary files /dev/null and b/mac/TeamTalk/Frameworks/ShortcutRecorder.framework/Versions/A/Resources/pl.lproj/ShortcutRecorder.strings differ diff --git a/mac/TeamTalk/Frameworks/ShortcutRecorder.framework/Versions/A/Resources/pt-BR.lproj/ShortcutRecorder.strings b/mac/TeamTalk/Frameworks/ShortcutRecorder.framework/Versions/A/Resources/pt-BR.lproj/ShortcutRecorder.strings new file mode 100755 index 000000000..d6bd15fd2 Binary files /dev/null and b/mac/TeamTalk/Frameworks/ShortcutRecorder.framework/Versions/A/Resources/pt-BR.lproj/ShortcutRecorder.strings differ diff --git a/mac/TeamTalk/Frameworks/ShortcutRecorder.framework/Versions/A/Resources/pt-PT.lproj/ShortcutRecorder.strings b/mac/TeamTalk/Frameworks/ShortcutRecorder.framework/Versions/A/Resources/pt-PT.lproj/ShortcutRecorder.strings new file mode 100755 index 000000000..b82a0764b Binary files /dev/null and b/mac/TeamTalk/Frameworks/ShortcutRecorder.framework/Versions/A/Resources/pt-PT.lproj/ShortcutRecorder.strings differ diff --git a/mac/TeamTalk/Frameworks/ShortcutRecorder.framework/Versions/A/Resources/pt.lproj/ShortcutRecorder.strings b/mac/TeamTalk/Frameworks/ShortcutRecorder.framework/Versions/A/Resources/pt.lproj/ShortcutRecorder.strings new file mode 100755 index 000000000..d6bd15fd2 Binary files /dev/null and b/mac/TeamTalk/Frameworks/ShortcutRecorder.framework/Versions/A/Resources/pt.lproj/ShortcutRecorder.strings differ diff --git a/mac/TeamTalk/Frameworks/ShortcutRecorder.framework/Versions/A/Resources/ro.lproj/ShortcutRecorder.strings b/mac/TeamTalk/Frameworks/ShortcutRecorder.framework/Versions/A/Resources/ro.lproj/ShortcutRecorder.strings new file mode 100755 index 000000000..db1db38f9 Binary files /dev/null and b/mac/TeamTalk/Frameworks/ShortcutRecorder.framework/Versions/A/Resources/ro.lproj/ShortcutRecorder.strings differ diff --git a/mac/TeamTalk/Frameworks/ShortcutRecorder.framework/Versions/A/Resources/ru.lproj/ShortcutRecorder.strings b/mac/TeamTalk/Frameworks/ShortcutRecorder.framework/Versions/A/Resources/ru.lproj/ShortcutRecorder.strings new file mode 100755 index 000000000..fc01d3612 Binary files /dev/null and b/mac/TeamTalk/Frameworks/ShortcutRecorder.framework/Versions/A/Resources/ru.lproj/ShortcutRecorder.strings differ diff --git a/mac/TeamTalk/Frameworks/ShortcutRecorder.framework/Versions/A/Resources/sk.lproj/ShortcutRecorder.strings b/mac/TeamTalk/Frameworks/ShortcutRecorder.framework/Versions/A/Resources/sk.lproj/ShortcutRecorder.strings new file mode 100755 index 000000000..0aed73e68 Binary files /dev/null and b/mac/TeamTalk/Frameworks/ShortcutRecorder.framework/Versions/A/Resources/sk.lproj/ShortcutRecorder.strings differ diff --git a/mac/TeamTalk/Frameworks/ShortcutRecorder.framework/Versions/A/Resources/sv.lproj/ShortcutRecorder.strings b/mac/TeamTalk/Frameworks/ShortcutRecorder.framework/Versions/A/Resources/sv.lproj/ShortcutRecorder.strings new file mode 100755 index 000000000..a8a2f71da Binary files /dev/null and b/mac/TeamTalk/Frameworks/ShortcutRecorder.framework/Versions/A/Resources/sv.lproj/ShortcutRecorder.strings differ diff --git a/mac/TeamTalk/Frameworks/ShortcutRecorder.framework/Versions/A/Resources/th.lproj/ShortcutRecorder.strings b/mac/TeamTalk/Frameworks/ShortcutRecorder.framework/Versions/A/Resources/th.lproj/ShortcutRecorder.strings new file mode 100755 index 000000000..ea7778b7f Binary files /dev/null and b/mac/TeamTalk/Frameworks/ShortcutRecorder.framework/Versions/A/Resources/th.lproj/ShortcutRecorder.strings differ diff --git a/mac/TeamTalk/Frameworks/ShortcutRecorder.framework/Versions/A/Resources/zh-Hans.lproj/ShortcutRecorder.strings b/mac/TeamTalk/Frameworks/ShortcutRecorder.framework/Versions/A/Resources/zh-Hans.lproj/ShortcutRecorder.strings new file mode 100755 index 000000000..ffcb6a0f4 Binary files /dev/null and b/mac/TeamTalk/Frameworks/ShortcutRecorder.framework/Versions/A/Resources/zh-Hans.lproj/ShortcutRecorder.strings differ diff --git a/mac/TeamTalk/Frameworks/ShortcutRecorder.framework/Versions/A/Resources/zh-Hant.lproj/ShortcutRecorder.strings b/mac/TeamTalk/Frameworks/ShortcutRecorder.framework/Versions/A/Resources/zh-Hant.lproj/ShortcutRecorder.strings new file mode 100755 index 000000000..22fff9111 Binary files /dev/null and b/mac/TeamTalk/Frameworks/ShortcutRecorder.framework/Versions/A/Resources/zh-Hant.lproj/ShortcutRecorder.strings differ diff --git a/mac/TeamTalk/Frameworks/ShortcutRecorder.framework/Versions/A/ShortcutRecorder b/mac/TeamTalk/Frameworks/ShortcutRecorder.framework/Versions/A/ShortcutRecorder new file mode 100755 index 000000000..1529bec3a Binary files /dev/null and b/mac/TeamTalk/Frameworks/ShortcutRecorder.framework/Versions/A/ShortcutRecorder differ diff --git a/mac/TeamTalk/Frameworks/ShortcutRecorder.framework/Versions/Current b/mac/TeamTalk/Frameworks/ShortcutRecorder.framework/Versions/Current new file mode 100644 index 000000000..8c7e5a667 --- /dev/null +++ b/mac/TeamTalk/Frameworks/ShortcutRecorder.framework/Versions/Current @@ -0,0 +1 @@ +A \ No newline at end of file diff --git a/mac/TeamTalk/HelpLib/DDPathHelp.h b/mac/TeamTalk/HelpLib/DDPathHelp.h new file mode 100644 index 000000000..e2eb5cf15 --- /dev/null +++ b/mac/TeamTalk/HelpLib/DDPathHelp.h @@ -0,0 +1,38 @@ +// +// DDPathHelp.h +// Duoduo +// +// Created by 独嘉 on 14-4-16. +// Copyright (c) 2014年 zuoye. All rights reserved. +// + +#import + +@interface DDPathHelp : NSObject + +/** + * 程序数据目录,暂时是TeamTalk + * + * @return 地址 + */ ++ (NSString*)applicationSupportDirectory; + + +/** + * 登录相关归档数据地址 + * + * @return 地址 + */ ++ (NSString*)loginArchivedDataPath; + +/** + * 下载目录 + * + * @return 返回下载目录 + */ ++ (NSString*)downLoadPath; + ++ (NSString*)imageCachePath; + ++ (NSString*)voiceCachePath; +@end diff --git a/mac/TeamTalk/HelpLib/DDPathHelp.m b/mac/TeamTalk/HelpLib/DDPathHelp.m new file mode 100644 index 000000000..387fe1be9 --- /dev/null +++ b/mac/TeamTalk/HelpLib/DDPathHelp.m @@ -0,0 +1,88 @@ +// +// DDPathHelp.m +// Duoduo +// +// Created by 独嘉 on 14-4-16. +// Copyright (c) 2014年 zuoye. All rights reserved. +// + +#import "DDPathHelp.h" + + +static NSString* const loginArchivedName = @"LoginArchived"; + +#define PORTABLE_ADIUM_KEY @"Preference Folder Location" + + +@implementation DDPathHelp ++ (NSString*)applicationSupportDirectory +{ + static NSString *preferencesFolderPath = nil; + + //Determine the preferences path if neccessary + if (!preferencesFolderPath) { + preferencesFolderPath = [[[[NSBundle mainBundle] infoDictionary] objectForKey:PORTABLE_ADIUM_KEY] stringByExpandingTildeInPath]; + if (!preferencesFolderPath) + preferencesFolderPath = [[[NSHomeDirectory() stringByAppendingPathComponent:@"Library"] stringByAppendingPathComponent:@"Application Support"] stringByAppendingPathComponent:@"TeamTalk"]; + } + + return preferencesFolderPath; +} + ++ (NSString*)loginArchivedDataPath +{ + NSString* applicationSupportDirectory = [DDPathHelp applicationSupportDirectory]; + NSString* loginArchivedPath = [applicationSupportDirectory stringByAppendingPathComponent:loginArchivedName]; + return loginArchivedPath; +} + ++ (NSString*)downLoadPath +{ + NSString* downLoadPath = [NSHomeDirectory() stringByAppendingPathComponent:@"Downloads"]; + return downLoadPath; +} + ++ (NSString*)imageCachePath +{ + NSString* applicationSupportDirectory = [DDPathHelp applicationSupportDirectory]; + NSString* imageCache = [applicationSupportDirectory stringByAppendingPathComponent:@"ImageCache"]; + BOOL directory; + BOOL exit = [[NSFileManager defaultManager] fileExistsAtPath:imageCache isDirectory:&directory]; + if (!exit) + { + [[NSFileManager defaultManager] createDirectoryAtPath:imageCache withIntermediateDirectories:YES attributes:nil error:nil]; + } + return imageCache; +} + ++ (NSString*)voiceCachePath +{ + NSString* applicationSupportDirectory = [DDPathHelp applicationSupportDirectory]; + + NSString* userID = [DDClientState shareInstance].userID; + + NSString* directorPath = [applicationSupportDirectory stringByAppendingPathComponent:userID]; + + NSString* voicePath = [directorPath stringByAppendingPathComponent:@"VoiceCache"]; + + NSFileManager* fileManager = [NSFileManager defaultManager]; + + //判断用户的db是否存在,若不存在则创建相应的DB目录 + BOOL isDirector = NO; + BOOL isExiting = [fileManager fileExistsAtPath:voicePath isDirectory:&isDirector]; + + if (!(isExiting && isDirector)) + { + BOOL createDirection = [fileManager createDirectoryAtPath:voicePath + withIntermediateDirectories:YES + attributes:nil + error:nil]; + if (!createDirection) + { + log4Error(@"语音缓存文件创建失败~"); + } + } + return voicePath; +} + +@end diff --git a/mac/TeamTalk/HelpLib/DDSundriesCenter.h b/mac/TeamTalk/HelpLib/DDSundriesCenter.h new file mode 100644 index 000000000..59ac390f2 --- /dev/null +++ b/mac/TeamTalk/HelpLib/DDSundriesCenter.h @@ -0,0 +1,22 @@ +// +// DDSundriesCenter.h +// Duoduo +// +// Created by 独嘉 on 14-4-23. +// Copyright (c) 2014年 zuoye. All rights reserved. +// + +#import + +typedef void(^Task)(); + +@interface DDSundriesCenter : NSObject + +@property (nonatomic,readonly)dispatch_queue_t serialQueue; +@property (nonatomic,readonly)dispatch_queue_t parallelQueue; + ++ (instancetype)instance; +- (void)pushTaskToSerialQueue:(Task)task; +- (void)pushTaskToParallelQueue:(Task)task; +- (void)pushTaskToSynchronizationSerialQUeue:(Task)task; +@end diff --git a/mac/TeamTalk/HelpLib/DDSundriesCenter.m b/mac/TeamTalk/HelpLib/DDSundriesCenter.m new file mode 100644 index 000000000..4e651bc8f --- /dev/null +++ b/mac/TeamTalk/HelpLib/DDSundriesCenter.m @@ -0,0 +1,54 @@ +// +// DDSundriesCenter.m +// Duoduo +// +// Created by 独嘉 on 14-4-23. +// Copyright (c) 2014年 zuoye. All rights reserved. +// + +#import "DDSundriesCenter.h" + +@implementation DDSundriesCenter ++ (instancetype)instance +{ + static DDSundriesCenter* g_ddSundriesCenter; + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^{ + g_ddSundriesCenter = [[DDSundriesCenter alloc] init]; + }); + return g_ddSundriesCenter; +} + +- (id)init +{ + self = [super init]; + if (self) + { + _serialQueue = dispatch_queue_create("com.mogujie.SundriesSerial", NULL); + _parallelQueue = dispatch_queue_create("com.mogujie.SundriesParallel", NULL); + } + return self; +} + +- (void)pushTaskToSerialQueue:(Task)task +{ + dispatch_async(self.serialQueue, ^{ + task(); + }); +} + +- (void)pushTaskToParallelQueue:(Task)task +{ + dispatch_async(self.parallelQueue, ^{ + task(); + }); +} + +- (void)pushTaskToSynchronizationSerialQUeue:(Task)task +{ + dispatch_sync(self.serialQueue, ^{ + task(); + }); +} + +@end diff --git a/mac/TeamTalk/HelpLib/ImageCache/MTImageCache.h b/mac/TeamTalk/HelpLib/ImageCache/MTImageCache.h new file mode 100644 index 000000000..6987fc2f1 --- /dev/null +++ b/mac/TeamTalk/HelpLib/ImageCache/MTImageCache.h @@ -0,0 +1,60 @@ +// +// MTImageCache.h +// Duoduo +// +// Created by 独嘉 on 15/1/24. +// Copyright (c) 2015年 mogujie. All rights reserved. +// + +#import + +/** + * 图片缓存类,TODO:Cache有效期 + */ +@interface MTImageCache : NSObject + +/** + * 单例 + * + * @return 图片缓存类 + */ ++ (instancetype)shareInstance; + +/** + * 缓存图片到内存或者磁盘 + * + * @param image 图片 + * @param key 作为图片的唯一标识,一般为url + * @param save 是否保存到内存,默认都保存在磁盘中 + */ +- (void)cacheImage:(NSImage*)image forKey:(NSString*)key toMemory:(BOOL)save; + +/** + * 将|filePath|路径下的图片作为|key|的缓存 + * + * @param imagePath 源文件路径 + * @param key 缓存唯一标识符 + */ +- (void)cacheImageFilePath:(NSString*)imagePath forKey:(NSString*)key; + +/** + * 根据图片的唯一标识去取图片 + * + * @param key 图片的唯一表示 + * + * @return 图片 + */ +- (NSImage*)imageFromCacheWithKey:(NSString*)key; + + +/** + * 根据key获取缓存图片的路径 + * + * @param key key + * + * @return 缓存图片的路径 + */ +- (NSString*)filePathWithKey:(NSString*)key; + + +@end diff --git a/mac/TeamTalk/HelpLib/ImageCache/MTImageCache.m b/mac/TeamTalk/HelpLib/ImageCache/MTImageCache.m new file mode 100644 index 000000000..8272701b7 --- /dev/null +++ b/mac/TeamTalk/HelpLib/ImageCache/MTImageCache.m @@ -0,0 +1,173 @@ +// +// MTImageCache.m +// Duoduo +// +// Created by 独嘉 on 15/1/24. +// Copyright (c) 2015年 mogujie. All rights reserved. +// + +#import "MTImageCache.h" +#import "DDPathHelp.h" + +#define FILE_CACHE_PLIST @"fileCache.plist" + +static NSString* hashForKey(NSString* key) { + if (![key isEqualToString:@""]) + { + return [NSString stringWithFormat:@"%lu.png", [key hash]]; + } + return nil; +} + +@interface MTImageCache(PrivateAPI) + +- (NSUInteger)p_costForData:(NSData*)data; + +- (NSString*)p_imageCachePath; + +- (void)p_initialFilePathCache; + +- (void)p_saveFilePathCache; +@end + +/** + * 最多缓存300张图片,cost1 = 500k,共计300 cost,共 150M + */ +@implementation MTImageCache +{ + NSCache* _cache; + NSMutableDictionary* _filePathCache; +} +/** + * 单例 + * + * @return 图片缓存类 + */ ++ (instancetype)shareInstance +{ + static MTImageCache* g_imageCache; + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^{ + g_imageCache = [[MTImageCache alloc] init]; + }); + return g_imageCache; +} + +- (instancetype)init +{ + self = [super init]; + if (self) + { + _cache = [[NSCache alloc] init]; + [_cache setCountLimit:300]; + [_cache setTotalCostLimit:300]; + + [self p_initialFilePathCache]; + } + return self; +} + +/** + * 缓存图片到内存或者磁盘 + * + * @param image 图片 + * @param key 作为图片的唯一标识,一般为url + * @param save 是否保存到内存,默认都保存在磁盘中 + */ +- (void)cacheImage:(NSImage*)image forKey:(NSString*)key toMemory:(BOOL)save +{ + NSData* data = [image TIFFRepresentation]; + + if (save) + { + NSUInteger cost = [self p_costForData:data]; + [_cache setObject:image forKey:key cost:cost]; + } + //保存到磁盘 + NSString* hash = hashForKey(key); + NSString* imagePath = [self p_imageCachePath]; + imagePath = [imagePath stringByAppendingPathComponent:hash]; + [data writeToFile:imagePath atomically:YES]; +} + +- (void)cacheImageFilePath:(NSString*)imagePath forKey:(NSString*)key +{ + if (imagePath && key) + { + [_filePathCache setObject:imagePath forKey:key]; + } + [self p_saveFilePathCache]; +} + +/** + * 根据图片的唯一标识去取图片 + * + * @param key 图片的唯一表示 + * + * @return 图片 + */ +- (NSImage*)imageFromCacheWithKey:(NSString*)key +{ + //先到内存 + if ([_cache objectForKey:key]) + { + return [_cache objectForKey:key]; + } + //到磁盘取数据 + NSString* hash = hashForKey(key); + NSString* imagePath = [self p_imageCachePath]; + imagePath = [imagePath stringByAppendingPathComponent:hash]; + + if ([[NSFileManager defaultManager] fileExistsAtPath:imagePath]) + { + NSData* data = [[NSData alloc] initWithContentsOfFile:imagePath]; + NSImage* image = [[NSImage alloc] initWithData:data]; + return image; + } + return nil; +} + +- (NSString*)filePathWithKey:(NSString*)key +{ + if ([[_filePathCache allKeys] containsObject:key]) + { + return _filePathCache[key]; + } + + NSString* hash = hashForKey(key); + NSString* imagePath = [self p_imageCachePath]; + imagePath = [imagePath stringByAppendingPathComponent:hash]; + + if ([[NSFileManager defaultManager] fileExistsAtPath:imagePath]) + { + return imagePath; + } + return nil; +} + +#pragma mark - +#pragma mark PrivateAPI +- (NSUInteger)p_costForData:(NSData*)data +{ + return [data length] / (500 * 1024) + 1; +} + +- (NSString*)p_imageCachePath +{ + NSString* imageCachePath = [DDPathHelp imageCachePath]; + return imageCachePath; +} + +- (void)p_initialFilePathCache +{ + NSString* plistPath = [[DDPathHelp imageCachePath] stringByAppendingPathComponent:FILE_CACHE_PLIST]; + NSDictionary* filePathCache = [[NSDictionary alloc] initWithContentsOfFile:plistPath]; + _filePathCache = [[NSMutableDictionary alloc] initWithDictionary:filePathCache]; +} + +- (void)p_saveFilePathCache +{ + NSString* plistPath = [[DDPathHelp imageCachePath] stringByAppendingPathComponent:FILE_CACHE_PLIST]; + [_filePathCache writeToFile:plistPath atomically:YES]; +} +@end diff --git a/mac/TeamTalk/HelpLib/ImageCache/MTImageDownload.h b/mac/TeamTalk/HelpLib/ImageCache/MTImageDownload.h new file mode 100644 index 000000000..8684e4f87 --- /dev/null +++ b/mac/TeamTalk/HelpLib/ImageCache/MTImageDownload.h @@ -0,0 +1,32 @@ +// +// MTImageDownload.h +// Duoduo +// +// Created by 独嘉 on 15/1/24. +// Copyright (c) 2015年 mogujie. All rights reserved. +// + +#import + +typedef void(^MTDownloadImageCompletion)(NSImage* image); +typedef void(^MTDownloadFileCompletion)(NSString* targetFilePath,NSError* error); + +@interface MTImageDownload : NSObject +/** + * 单例 + * + * @return 单例 + */ ++ (instancetype)shareInstance; + +/** + * 下载图片 + * + * @param url url + * @param completion 下周完成 + */ +- (void)loadImageWithURL:(NSString*)url completion:(MTDownloadImageCompletion)completion; + +- (void)loadFileWithURL:(NSString*)url completion:(MTDownloadFileCompletion)completion; + +@end diff --git a/mac/TeamTalk/HelpLib/ImageCache/MTImageDownload.m b/mac/TeamTalk/HelpLib/ImageCache/MTImageDownload.m new file mode 100644 index 000000000..ce555a616 --- /dev/null +++ b/mac/TeamTalk/HelpLib/ImageCache/MTImageDownload.m @@ -0,0 +1,163 @@ +// +// MTImageDownload.m +// Duoduo +// +// Created by 独嘉 on 15/1/24. +// Copyright (c) 2015年 mogujie. All rights reserved. +// + +#import "MTImageDownload.h" +#import +#import "DDPathHelp.h" +#import "MTImageCache.h" +@interface MTImageDownload(PrivateAPI) + +- (void)p_loadImageWithURL:(NSString*)url completion:(MTDownloadImageCompletion)completion; + +- (void)p_addComplection:(MTDownloadImageCompletion)completio forURL:(NSString*)url; + +- (void)p_executeCompletionForURL:(NSString*)url image:(NSImage*)image; + +@end + +@implementation MTImageDownload +{ + // AFURLSessionManager *_manager; + NSMutableArray* _downloadingImageUrls; + NSMutableDictionary* _completions; +} + ++ (instancetype)shareInstance +{ + static MTImageDownload* g_imageDownload; + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^{ + g_imageDownload = [[MTImageDownload alloc] init]; + }); + return g_imageDownload; +} + +- (instancetype)init +{ + self = [super init]; + if (self) + { + // NSURLSessionConfiguration *configuration = [NSURLSessionConfiguration defaultSessionConfiguration]; + // _manager = [[AFURLSessionManager alloc] initWithSessionConfiguration:configuration]; +// _manager.responseSerializer = [AFImageResponseSerializer serializer]; + _downloadingImageUrls = [[NSMutableArray alloc] init]; + _completions = [[NSMutableDictionary alloc] init]; + } + return self; +} + +- (void)loadImageWithURL:(NSString*)url completion:(MTDownloadImageCompletion)completion +{ + if (![[_completions allKeys] containsObject:url]) + { + [self p_addComplection:completion forURL:url]; + [self p_loadImageWithURL:url completion:completion]; + } + else + { + [self p_addComplection:completion forURL:url]; + } +} + +- (void)loadFileWithURL:(NSString*)url completion:(MTDownloadFileCompletion)completion +{ + if ([_downloadingImageUrls containsObject:url] || [[MTImageCache shareInstance] filePathWithKey:url]) + { + return; + } + + if ([url length] == 0) + { + return; + } + NSURL *URL = [NSURL URLWithString:url]; + NSURLRequest *request = [NSURLRequest requestWithURL:URL]; + + NSString* fileName = [[url componentsSeparatedByString:@"/"] lastObject]; + if (fileName) { + NSString* targetFilePath = [[DDPathHelp imageCachePath] stringByAppendingPathComponent:fileName]; + AFHTTPRequestOperation *downloadRequest = [[AFHTTPRequestOperation alloc] initWithRequest:request]; + [downloadRequest setCompletionBlockWithSuccess:^(AFHTTPRequestOperation *operation, id responseObject) { + NSData *data = [[NSData alloc] initWithData:responseObject]; + [data writeToFile:targetFilePath atomically:YES]; + [[MTImageCache shareInstance] cacheImageFilePath:targetFilePath forKey:url]; + } failure:^(AFHTTPRequestOperation *operation, NSError *error) { + log4Error(@"file downloading error : %@", [error localizedDescription]); + }]; + [downloadRequest start]; + } + else + { + NSError* error = [NSError errorWithDomain:@"url取文件名不对" code:0 userInfo:nil]; + completion(nil,error); + } +} + +#pragma mark - +#pragma mark PrivateAPI +- (void)p_loadImageWithURL:(NSString*)url completion:(MTDownloadImageCompletion)completion +{ + if ([url length] == 0) + { + return; + } + NSURL *URL = [NSURL URLWithString:url]; + NSURLRequest *request = [NSURLRequest requestWithURL:URL]; + + __weak MTImageDownload* weakSelf = self; + AFHTTPRequestOperation *downloadRequest = [[AFHTTPRequestOperation alloc] initWithRequest:request]; + [downloadRequest setCompletionBlockWithSuccess:^(AFHTTPRequestOperation *operation, id responseObject) { + NSData *data = [[NSData alloc] initWithData:responseObject]; +// [data writeToFile:targetFilePath atomically:YES]; + NSImage *img = [[NSImage alloc]initWithData:data]; + [weakSelf p_executeCompletionForURL:url image:img]; + } failure:^(AFHTTPRequestOperation *operation, NSError *error) { + log4Error(@"file downloading error : %@", [error localizedDescription]); + }]; + [downloadRequest start]; + + /* + NSURLSessionDataTask *dataTask = [_manager dataTaskWithRequest:request completionHandler:^(NSURLResponse *response, id responseObject, NSError *error) { + if (error) { + NSLog(@"Error: %@", error); + } else { + [weakSelf p_executeCompletionForURL:url image:responseObject]; + } + }]; + [dataTask resume]; + */ +} + +- (void)p_addComplection:(MTDownloadImageCompletion)completion forURL:(NSString*)url +{ + if ([[_completions allKeys] containsObject:url]) + { + NSMutableArray* completions = _completions[url]; + [completions addObject:[completion copy]]; + } + else + { + NSMutableArray* completions = [[NSMutableArray alloc] init]; + [completions addObject:[completion copy]]; + [_completions setObject:completions forKey:url]; + } +} + +- (void)p_executeCompletionForURL:(NSString*)url image:(NSImage*)image +{ + if ([[_completions allKeys] containsObject:url]) + { + NSMutableArray* completions = _completions[url]; + for (NSInteger index = 0; index < [completions count]; index ++) + { + MTDownloadImageCompletion completion = completions[index]; + completion(image); + } + } +} +@end diff --git a/mac/TeamTalk/Images.xcassets/AppIcon.appiconset/Contents.json b/mac/TeamTalk/Images.xcassets/AppIcon.appiconset/Contents.json new file mode 100644 index 000000000..2db2b1c7c --- /dev/null +++ b/mac/TeamTalk/Images.xcassets/AppIcon.appiconset/Contents.json @@ -0,0 +1,58 @@ +{ + "images" : [ + { + "idiom" : "mac", + "size" : "16x16", + "scale" : "1x" + }, + { + "idiom" : "mac", + "size" : "16x16", + "scale" : "2x" + }, + { + "idiom" : "mac", + "size" : "32x32", + "scale" : "1x" + }, + { + "idiom" : "mac", + "size" : "32x32", + "scale" : "2x" + }, + { + "idiom" : "mac", + "size" : "128x128", + "scale" : "1x" + }, + { + "idiom" : "mac", + "size" : "128x128", + "scale" : "2x" + }, + { + "idiom" : "mac", + "size" : "256x256", + "scale" : "1x" + }, + { + "idiom" : "mac", + "size" : "256x256", + "scale" : "2x" + }, + { + "idiom" : "mac", + "size" : "512x512", + "scale" : "1x" + }, + { + "idiom" : "mac", + "size" : "512x512", + "scale" : "2x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/mac/TeamTalk/Libraries/Log4Cocoa/L4AppenderAttachable.h b/mac/TeamTalk/Libraries/Log4Cocoa/L4AppenderAttachable.h new file mode 100644 index 000000000..9915b0b43 --- /dev/null +++ b/mac/TeamTalk/Libraries/Log4Cocoa/L4AppenderAttachable.h @@ -0,0 +1,22 @@ +// For copyright & license, see LICENSE. + +#import +#import "L4AppenderProtocols.h" + +extern NSString * const kL4AppenderAddedEvent; +extern NSString * const kL4AppenderRemovedEvent; + +/** + * This (poorly named) class servers as the basis for the L4AppenderAttachable protocol. + */ +@interface L4AppenderAttachable : NSObject +/** + * Appends event to appenders. + * This message sends a doAppend: message to every appender in the appnderList attribute. + * @param event the event to be appended. + * @return the number of appenders the event was appended to. + */ +- (NSUInteger)appendLoopOnAppenders:(L4LogEvent *)event; + +@end + diff --git a/mac/TeamTalk/Libraries/Log4Cocoa/L4AppenderAttachable.m b/mac/TeamTalk/Libraries/Log4Cocoa/L4AppenderAttachable.m new file mode 100644 index 000000000..7da9f4f69 --- /dev/null +++ b/mac/TeamTalk/Libraries/Log4Cocoa/L4AppenderAttachable.m @@ -0,0 +1,84 @@ +/** + * For copyright & license, see LICENSE. + */ + +#import "L4AppenderAttachable.h" + +NSString * const kL4AppenderAddedEvent = @"kL4AppenderAddedEvent"; +NSString * const kL4AppenderRemovedEvent = @"kL4AppenderRemovedEvent"; + +@implementation L4AppenderAttachable { + NSMutableArray * _appenderList; /**< The collection of log appenders.*/ +} + +- (NSUInteger)appendLoopOnAppenders:(L4LogEvent *)event +{ + @synchronized(self) { + for (id appender in _appenderList) + [appender doAppend:event]; + } + return _appenderList.count; +} + +#pragma mark Appender Attachable Methods protocol methods + +- (void)addAppender:(id )appender +{ + if (!appender) // sanity check + return; + + @synchronized(self) { + if (!_appenderList) { + // only place appenderList array is recreated if its nil. + _appenderList = [NSMutableArray arrayWithObject:appender]; + return; + } + + if(![_appenderList containsObject:appender]) { + [_appenderList addObject:appender]; + [[NSNotificationCenter defaultCenter] postNotificationName:kL4AppenderAddedEvent object:appender]; + } + } +} + +- (NSArray *)allAppenders +{ + return _appenderList; +} + +- (id )appenderWithName:(NSString *)name +{ + return [_appenderList filteredArrayUsingPredicate:[NSPredicate predicateWithFormat:@"name = %@", name]].lastObject; +} + +- (BOOL)isAttached:(id )appender +{ + if (!appender || !_appenderList) + return NO; // short circuit the test + + return [_appenderList containsObject:appender]; +} + +- (void) removeAppenderWithName:(NSString *)name +{ + [self removeAppender:[self appenderWithName:name]]; +} + +- (void) removeAppender:(id ) appender +{ + [_appenderList removeObject:appender]; + [[NSNotificationCenter defaultCenter] postNotificationName:kL4AppenderRemovedEvent object:appender]; +} + +- (void) removeAllAppenders +{ + @synchronized(self) { + for (id appender in _appenderList) { + [[NSNotificationCenter defaultCenter] postNotificationName:kL4AppenderRemovedEvent object:appender]; + } + [_appenderList removeAllObjects]; + _appenderList = nil; + } +} + +@end diff --git a/mac/TeamTalk/Libraries/Log4Cocoa/L4AppenderProtocols.h b/mac/TeamTalk/Libraries/Log4Cocoa/L4AppenderProtocols.h new file mode 100644 index 000000000..dadac0e73 --- /dev/null +++ b/mac/TeamTalk/Libraries/Log4Cocoa/L4AppenderProtocols.h @@ -0,0 +1,115 @@ +// For copyright & license, see LICENSE. + +#import + +@class L4Logger, L4Filter, L4Layout, L4LogEvent, L4Properties; + +/** + * Appenders are responsible for adding a log message to log. + * This formal protocol defines the messages a class used for appending needs to support. + */ +@protocol L4Appender + +/** + * Accessor for unique name attribute for this appender. + */ +@property (readwrite) NSString * name; + +/** + * Accessor for layout of this appender. + */ +@property (readwrite) L4Layout * layout; + +/** + * Returns if the appender requires layout. + */ +@property (readonly) BOOL requiresLayout; + +/** + * Initializes an instance from a collection of configuration properties. + * For more information on the specific appender properties, see the documentation for the particular class. + * @param initProperties the properties to use. + */ +- (id)initWithProperties:(L4Properties *)initProperties; + +/** + * Appender log this event. + * @param anEvent the event to append. + */ +- (void)doAppend:(L4LogEvent *)anEvent; + +/** + * Appends to the end of list. + * @param newFilter the filter to add. + */ +- (void)appendFilter:(L4Filter *)newFilter; + +/** + * Accessor for the head filter (the first in the list). + * @return first filter or nil if there are none. + */ +- (L4Filter *)headFilter; + +/** + * Removes all filters from list. + */ +- (void)clearFilters; + +/** + * It is a programing error to append to a close appender. + */ +- (void)close; + +@end + + +/** + * This protocol defines messages used to chain L4Appender instances together. The system supports having more than one + * logging appender, so that a single logging event can be logged in more than one place. + */ +@protocol L4AppenderAttachable +/** + * Adds an appender to be logged to. + * @param newAppender the new appender to add. + */ +- (void)addAppender:(id )newAppender; + +/** + * Accessor for the collection of log appenders. + * @return an array of al appenders. + */ +- (NSArray *)allAppenders; + +/** + * Returns the L4Appender with the given name. + * @param aName the name of the L4Appender of interest. + * @return the L4Appender with the name aName, or nil if it does not exist. + */ +- (id )appenderWithName:(NSString *)aName; + +/** + * Returns a BOOL value that indicates whether the parameter has been attached to the appender list. + * @param appender the L4Appender of interest. + * @return YES if appender has been attached, NO otherwise. + */ +- (BOOL)isAttached:(id )appender; + +/** + * Clears all L4Appender instances that have been attached. + */ +- (void)removeAllAppenders; + +/** + * Removes a given L4Appender from those attached. + * @param appender the L4Appender to remove. + */ +- (void)removeAppender:(id )appender; + +/** + * Removes a L4Appender with the given name from those attached. + * @param aName the name of the L4Appender to remove. + */ +- (void)removeAppenderWithName:(NSString *)name; + +@end + diff --git a/mac/TeamTalk/Libraries/Log4Cocoa/L4AppenderSkeleton.h b/mac/TeamTalk/Libraries/Log4Cocoa/L4AppenderSkeleton.h new file mode 100644 index 000000000..274e93ee2 --- /dev/null +++ b/mac/TeamTalk/Libraries/Log4Cocoa/L4AppenderSkeleton.h @@ -0,0 +1,52 @@ +// For copyright & license, see LICENSE. + +#import +#import "L4AppenderProtocols.h" + +@class L4Filter, L4Level, L4LogEvent, L4Properties; + +/** + * This class acts as a superclass for classes that want to log. It is not intended + * to be instantiated, but as Objective C does not have the concept of abstract classes, + * and as protocols can't have implementations, this class simply impliments some + * standard, generic logging behaviour. + */ +@interface L4AppenderSkeleton : NSObject { + L4Filter * _headFilter; /**< The first filter used by this appender.*/ + L4Filter __weak * _tailFilter; /**< The last filter used by this appender.*/ + BOOL _closed; /**< Tracks if this appender has been closed.*/ +} + +/** Accessor for the threshold attribute that tracks the level at wich this appnded will log an event.*/ +@property (nonatomic) L4Level * threshold; + +/** The layout used by this appender.*/ +@property (atomic, strong) L4Layout * layout; + +/** The name for this appender.*/ +@property (atomic, strong) NSString * name; + +/** + * Initializes an instance from properties. + * Refer to the L4PropertyConfigurator class for more information about standard configuration properties. + * @param initProperties the proterties to use. + */ +- (id)initWithProperties:(L4Properties *)initProperties; + +/** + * Appends an event to the log. + * @param anEvent the event to be appended. + */ +- (void)append:(L4LogEvent *)anEvent; + +/** + * Used to determine if a given event would be logged by this appender + * given this appensers current threshold. + * @param aLevel the level to be tested. + * @return YES if this appended would log, NO otherwise. + */ +- (BOOL)isAsSevereAsThreshold:(L4Level *)aLevel; + +@end + + diff --git a/mac/TeamTalk/Libraries/Log4Cocoa/L4AppenderSkeleton.m b/mac/TeamTalk/Libraries/Log4Cocoa/L4AppenderSkeleton.m new file mode 100644 index 000000000..0dc6a6251 --- /dev/null +++ b/mac/TeamTalk/Libraries/Log4Cocoa/L4AppenderSkeleton.m @@ -0,0 +1,216 @@ +/** + * For copyright & license, see LICENSE. + */ + +#import "L4AppenderSkeleton.h" +#import "L4Filter.h" +#import "L4Level.h" +#import "L4LogEvent.h" +#import "L4LogLog.h" +#import "L4Layout.h" +#import "L4Properties.h" + +/** + * Private methods. + */ +@interface L4AppenderSkeleton () + +/** + * Returns a new subclass of L4Filter specified by the class name, configured with the supplied properties. + * @param filterClassName the name of the L4Filter subclass to instantiate. + * @param filterProperties the properties used to configure the new instance. + */ +- (L4Filter *)filterForClassName:(NSString *)filterClassName andProperties:(L4Properties *)filterProperties; + +/** + * Returns a new subclass of L4Layout specified by the class name, configured with the supplied properties. + * @param layoutClassName the name of the L4Layout subclass to instantiate. + * @param layoutProperties the properties used to configure the new instance. + */ +- (L4Layout *)layoutForClassName:(NSString *)layoutClassName andProperties:(L4Properties *)layoutProperties; + +@end + +@implementation L4AppenderSkeleton + +- (id)initWithProperties:(L4Properties *)initProperties +{ + self = [super init]; + + if (self) { + // Configure the layout + if ([initProperties stringForKey:@"layout"]) { + L4Properties *layoutProperties = [initProperties subsetForPrefix:@"layout."]; + NSString *className = [initProperties stringForKey:@"layout"]; + L4Layout *newLayout = [self layoutForClassName:className andProperties:layoutProperties]; + + if (!newLayout) { + self.layout = newLayout; + } else { + [L4LogLog error:[NSString stringWithFormat:@"Error while creating layout \"%@\".", className]]; + return nil; + } + } + + // Support for appender.Threshold in properties configuration file + if ([initProperties stringForKey:@"Threshold"]) { + NSString *newThreshold = [[initProperties stringForKey:@"Threshold"] uppercaseString]; + [self setThreshold:[L4Level levelWithName:newThreshold]]; + } + + // Configure the filters + L4Properties *filtersProperties = [initProperties subsetForPrefix:@"filters."]; + int filterCount = 0; + while ([filtersProperties stringForKey:[@(++filterCount) stringValue]]) { + NSString *filterName = [@(filterCount) stringValue]; + L4Properties *filterProperties = [filtersProperties subsetForPrefix:[filterName stringByAppendingString:@"."]]; + NSString *className = [filtersProperties stringForKey:filterName]; + L4Filter *newFilter = [self filterForClassName:className andProperties:filterProperties]; + + if (newFilter) { + [self appendFilter:newFilter]; + } else { + [L4LogLog error:[NSString stringWithFormat:@"Error while creating filter \"%@\".", className]]; + return nil; + } + } + } + + return self; +} + + +- (void)append:(L4LogEvent *)anEvent +{ +} + +- (BOOL)isAsSevereAsThreshold:(L4Level *)aLevel +{ + @synchronized(self) { + return ((_threshold == nil) || ([aLevel isGreaterOrEqual:_threshold])); + } +} + +#pragma mark - Private methods + +- (L4Filter *)filterForClassName:(NSString *)filterClassName andProperties:(L4Properties *)filterProperties +{ + L4Filter *newFilter = nil; + Class filterClass = NSClassFromString(filterClassName); + + if ( filterClass == nil ) { + [L4LogLog error:[NSString stringWithFormat:@"Cannot find L4Filter class with name:\"%@\".", filterClassName]]; + } else { + if ( ![[[filterClass alloc] init] isKindOfClass:[L4Filter class]] ) { + [L4LogLog error:[NSString stringWithFormat:@"Failed to create instance with name \"%@\" since it is not of kind L4Filter.", filterClass]]; + } else { + newFilter = [(L4Filter *)[filterClass alloc] initWithProperties:filterProperties]; + } + } + return newFilter; +} + +- (L4Layout *)layoutForClassName:(NSString *)layoutClassName andProperties:(L4Properties *)layoutProperties +{ + L4Layout *newLayout = nil; + Class layoutClass = NSClassFromString(layoutClassName); + + if ( layoutClass == nil ) { + [L4LogLog error:[NSString stringWithFormat:@"Cannot find L4Layout class with name:\"%@\".", layoutClassName]]; + } else { + if ( ![[[layoutClass alloc] init] isKindOfClass:[L4Layout class]] ) { + [L4LogLog error: + [NSString stringWithFormat: + @"Failed to create instance with name \"%@\" since it is not of kind L4Layout.", layoutClass]]; + } else { + newLayout = [(L4Layout *)[layoutClass alloc] initWithProperties:layoutProperties]; + } + } + return newLayout; +} + +#pragma mark - L4AppenderCategory methods + +// calls [self append:anEvent] after doing threshold checks +- (void)doAppend:(L4LogEvent *)anEvent +{ + L4Filter *aFilter = [self headFilter]; + BOOL breakLoop = NO; + + if(![self isAsSevereAsThreshold:[anEvent level]]) { + return; + } + + BOOL isOkToAppend = YES; + + @synchronized(self) { + + if (_closed) { + [L4LogLog error:[NSString stringWithFormat:@"Attempted to append to closed appender named: %@", _name]]; + isOkToAppend = NO; + } + + while (aFilter && !breakLoop) { + switch([aFilter decide:anEvent]) { + case L4FilterDeny: + isOkToAppend = NO; + breakLoop = YES; + break; + case L4FilterAccept: + breakLoop = YES; + break; + case L4FilterNeutral: + default: + aFilter = [aFilter next]; + break; + } + } + + if (isOkToAppend) { + [self append:anEvent]; // passed all threshold checks, append event. + } + } +} + +- (void)appendFilter:(L4Filter *)newFilter +{ + @synchronized(self) { + if (!_headFilter) { + _headFilter = _tailFilter = newFilter; + } else { + _tailFilter.next = newFilter; + _tailFilter = newFilter; + } + } +} + +- (L4Filter *)headFilter +{ + return _headFilter; +} + +- (void)clearFilters +{ + @autoreleasepool { + + @synchronized(self) { + for (L4Filter *filter = _headFilter; filter; filter = [_headFilter next] ) { + filter.next = nil; + } + _headFilter = nil; + _tailFilter = nil; + } + + } +} + +- (void)close +{ +} + +- (BOOL)requiresLayout +{ + return NO; +} + +@end diff --git a/mac/TeamTalk/Libraries/Log4Cocoa/L4BasicConfigurator.h b/mac/TeamTalk/Libraries/Log4Cocoa/L4BasicConfigurator.h new file mode 100644 index 000000000..53f6809a2 --- /dev/null +++ b/mac/TeamTalk/Libraries/Log4Cocoa/L4BasicConfigurator.h @@ -0,0 +1,15 @@ +#import +#import "L4PropertyConfigurator.h" + +/** + * Use this class to quickly configure the package. For file based + * configuration see L4PropertyConfigurator. + */ +@interface L4BasicConfigurator : L4PropertyConfigurator + +/** + * Factory method to return an instance of the default, basic configurator. + */ ++ (L4BasicConfigurator *) basicConfigurator; + +@end diff --git a/mac/TeamTalk/Libraries/Log4Cocoa/L4BasicConfigurator.m b/mac/TeamTalk/Libraries/Log4Cocoa/L4BasicConfigurator.m new file mode 100644 index 000000000..ec1ebf65a --- /dev/null +++ b/mac/TeamTalk/Libraries/Log4Cocoa/L4BasicConfigurator.m @@ -0,0 +1,28 @@ +/** + * For copyright & license, see LICENSE. + */ + +#import "L4BasicConfigurator.h" +#import "L4Properties.h" + +@implementation L4BasicConfigurator + ++ (L4BasicConfigurator *)basicConfigurator +{ + return [[L4BasicConfigurator alloc] init]; +} + +- (id) init +{ + self = [super initWithFileName:@""]; + + if (self) { + [properties setString:@"DEBUG, STDOUT" forKey:@"rootLogger"]; + [properties setString:@"L4ConsoleAppender" forKey:@"appender.STDOUT"]; + [properties setString:@"L4SimpleLayout" forKey:@"appender.STDOUT.layout"]; + } + + return self; +} + +@end diff --git a/mac/TeamTalk/Libraries/Log4Cocoa/L4ConsoleAppender.h b/mac/TeamTalk/Libraries/Log4Cocoa/L4ConsoleAppender.h new file mode 100644 index 000000000..39b2ec569 --- /dev/null +++ b/mac/TeamTalk/Libraries/Log4Cocoa/L4ConsoleAppender.h @@ -0,0 +1,56 @@ +// For copyright & license, see LICENSE. + +#import +#import "L4WriterAppender.h" + +/** + * An implementation of L4Appender that writes messages to the console; either stdout or stderr. + */ +@interface L4ConsoleAppender : L4WriterAppender + +/** + * Creates and returns an L4ConsoleAppender on stdout with the given L4Layout. + * @param aLayout the layout to use for the created appender. + * @return the new appender. + */ ++ (L4ConsoleAppender *) standardOutWithLayout:(L4Layout *) aLayout; + +/** + * Creates and returns an L4ConsoleAppender on stderr with the given L4Layout. + * @param aLayout the layout to use for the created appender. + * @return the new appender. + */ ++ (L4ConsoleAppender *) standardErrWithLayout:(L4Layout *) aLayout; + +/** + * default init method. Returned instance isn't connected to anything. + * @return the new instance. + */ +- (id) init; + +/** + * Creates and returns a new console appender. + * @param standardOut YES to use stdout; otherwise stderr is used. + * @param aLayout the layout to use. + * @return the new instance. + */ +- (id) initTarget:(BOOL) standardOut withLayout:(L4Layout *) aLayout; + + +/** + * Initializes an instance from properties. The properties supported are: + * - LogToStandardOut: specifies if this appender should append to stdout or stderr. If the value is true, then + * stdout will be used. Otherwise stderr will be used. + * If the values are being set in a file, this is how they could look: + * log4cocoa.appender.A2.LogToStandardOut=false + * @param initProperties the proterties to use. + */ +- (id) initWithProperties:(L4Properties *) initProperties; + +/** + * Accesor for isStandardOut attribute. + * @return YES if this appender is for stdout; NO if it is for stderr. + */ +- (BOOL) isStandardOut; + +@end diff --git a/mac/TeamTalk/Libraries/Log4Cocoa/L4ConsoleAppender.m b/mac/TeamTalk/Libraries/Log4Cocoa/L4ConsoleAppender.m new file mode 100644 index 000000000..a177b4b20 --- /dev/null +++ b/mac/TeamTalk/Libraries/Log4Cocoa/L4ConsoleAppender.m @@ -0,0 +1,101 @@ +/** + * For copyright & license, see LICENSE. + */ + +#import "L4ConsoleAppender.h" +#import "L4Layout.h" +#import "L4Properties.h" + +@implementation L4ConsoleAppender { + BOOL _isStandardOut; /**< Tracks if this appender is for stdout.*/ +} + + +#pragma mark - Class methods + ++ (L4ConsoleAppender *) standardOutWithLayout:(L4Layout *)aLayout +{ + return [[L4ConsoleAppender alloc] initTarget:YES withLayout:aLayout]; +} + ++ (L4ConsoleAppender *) standardErrWithLayout:(L4Layout *)aLayout +{ + return [[L4ConsoleAppender alloc] initTarget:NO withLayout:aLayout]; +} + + +#pragma mark - Instance methods + +- (id) init +{ + return [self initTarget:YES withLayout:[L4Layout simpleLayout]]; +} + +- (id) initTarget:(BOOL)standardOut withLayout:(L4Layout *)aLayout +{ + self = [super init]; + if (self) { + if (standardOut) { + [self setStandardOut]; + } else { + [self setStandardErr]; + } + self.layout = aLayout; + } + return self; +} + +- (BOOL) isStandardOut +{ + return _isStandardOut; +} + + +#pragma mark - L4Appender protocol methods + +- (id) initWithProperties:(L4Properties *)initProperties +{ + self = [super initWithProperties:initProperties]; + if (self) { + BOOL logToStandardOut = YES; + + // Support for appender.LogToStandardOut in properties configuration file + if ([initProperties stringForKey:@"LogToStandardOut"]) { + NSString *buf = [[initProperties stringForKey:@"LogToStandardOut"] lowercaseString]; + logToStandardOut = [buf isEqualToString:@"true"]; + } + + if( logToStandardOut ) { + [self setStandardOut]; + } else { + [self setStandardErr]; + } + } + + return self; +} + + +#pragma mark - Private methods + +- (void) setStandardOut +{ + @synchronized(self) { + if (!_isStandardOut || !_fileHandle) { + _isStandardOut = YES; + _fileHandle = [NSFileHandle fileHandleWithStandardOutput]; + } + } +} + +- (void) setStandardErr +{ + @synchronized(self) { + if (_isStandardOut || !_fileHandle) { + _isStandardOut = NO; + _fileHandle = [NSFileHandle fileHandleWithStandardError]; + } + } +} + +@end diff --git a/mac/TeamTalk/Libraries/Log4Cocoa/L4DailyRollingFileAppender.h b/mac/TeamTalk/Libraries/Log4Cocoa/L4DailyRollingFileAppender.h new file mode 100644 index 000000000..8876ab329 --- /dev/null +++ b/mac/TeamTalk/Libraries/Log4Cocoa/L4DailyRollingFileAppender.h @@ -0,0 +1,69 @@ +// For copyright & license, see LICENSE. + +#import +#import "L4FileAppender.h" + +/** + * The accepted constants for L4DailyRollingFileAppenderFrequency's setFrequency: method. + */ +extern NSString *const L4RollingFrequencyKey; + +extern NSString *const L4RollingFrequencyNever; /**< Never roll the file. */ +extern NSString *const L4RollingFrequencyMonthly; /**< Roll the file over every month. */ +extern NSString *const L4RollingFrequencyWeekly; /**< Roll the file over every week. */ +extern NSString *const L4RollingFrequencyDaily; /**< Roll the file over every day. */ +extern NSString *const L4RollingFrequencyHalfDaily; /**< Roll the file over every 12 hours. */ +extern NSString *const L4RollingFrequencyHourly; /**< Roll the file over every hour. */ +extern NSString *const L4RollingFrequencyMinutely; /**< Roll the file over every minute. */ + +/** + * L4DailyRollingFileAppender extends L4FileAppender so that the underlying file is rolled over at a + * user-chosen frequency. For example, if the fileName is set to /foo/bar.log and the frequency is set + * to daily, on 2001-02-16 at midnight, the logging file /foo/bar.log will be copied to /foo/bar.log.2001-02-16 + * and logging for 2001-02-17 will continue in /foo/bar.log until it rolls over the next day. + * It is possible to specify monthly, weekly, half-daily, daily, hourly, or minutely rollover schedules. +*/ +@interface L4DailyRollingFileAppender : L4FileAppender { + NSDate *_lastRolloverDate; /**< The date the last role-over ocured.*/ +} + +/** The frequency with which the file should be rolled.*/ +@property (nonatomic, copy) NSString *rollingFrequency; + +/** + * This initializer calls the initWithLayout:fileName:rollingFrequency: method with the respective values:nil, nil, never. + */ +- (id)init; + +/** + * Initializes an instance of this class with the specified layout, file name, and rolling frequency. + * @param aLayout The layout object for this appender + * @param aName The file path to the file in which you want logging output recorded + * @param aRollingFrequency The frequency at which you want the log file rolled over + */ +- (id)initWithLayout:(L4Layout*)aLayout fileName:(NSString*)aName rollingFrequency:(NSString *)aRollingFrequency; + +/** + * Initializes an instance from properties. The properties supported are: + * - L4RollingFrequencyKey: specifies the frequency when the log file should be rolled. See L4RollingFrequency. + * If the values are being set in a file, this is how they could look: + * log4cocoa.appender.A2.L4RollingFrequency=L4RollingFrequencyDaily + * @param initProperties the proterties to use. + */ +- (id) initWithProperties:(L4Properties *) initProperties; + +@end + +/** + * These methods are "protected" methods and should not be called except by subclasses. +*/ +@interface L4DailyRollingFileAppender (ProtectedMethods) + +/** + This method overrides the implementation in L4WriterAppender. It checks if the rolling frequency has been exceeded. + * If so, it rolls the file over. + * @param event An L4LoggingEvent that contains logging specific information. + */ +- (void)subAppend: (L4LogEvent*)event; + +@end diff --git a/mac/TeamTalk/Libraries/Log4Cocoa/L4DailyRollingFileAppender.m b/mac/TeamTalk/Libraries/Log4Cocoa/L4DailyRollingFileAppender.m new file mode 100644 index 000000000..b44168799 --- /dev/null +++ b/mac/TeamTalk/Libraries/Log4Cocoa/L4DailyRollingFileAppender.m @@ -0,0 +1,207 @@ +/** + * For copyright & license, see LICENSE. + */ + +#import "L4DailyRollingFileAppender.h" +#import "L4Layout.h" +#import "L4LogLog.h" +#import "L4Properties.h" + +#import + +NSString *const L4RollingFrequencyKey = @"L4RollingFrequency"; + +NSString *const L4RollingFrequencyNever = @"L4RollingFrequencyNever"; +NSString *const L4RollingFrequencyMonthly = @"L4RollingFrequencyMonthly"; +NSString *const L4RollingFrequencyWeekly = @"L4RollingFrequencyWeekly"; +NSString *const L4RollingFrequencyDaily = @"L4RollingFrequencyDaily"; +NSString *const L4RollingFrequencyHalfDaily = @"L4RollingFrequencyHalfDaily"; +NSString *const L4RollingFrequencyHourly = @"L4RollingFrequencyHourly"; +NSString *const L4RollingFrequencyMinutely = @"L4RollingFrequencyMinutely"; + +/** + * Private methods for the L4DailyRollingFileAppender class. + */ +@interface L4DailyRollingFileAppender () +/** + * Accessor for the lastRolloverDate property. + */ +- (NSDate *)lastRolloverDate; +/** + * Mutator for the lastRolloverDate property. + */ +- (void)setLastRolloverDate:(NSDate*)date; + +/** + * Causes a new log file to be generated. + */ +- (void)rollOver; + +@end + +@implementation L4DailyRollingFileAppender + +- (id)init +{ + return [self initWithLayout:nil fileName:nil rollingFrequency:L4RollingFrequencyNever]; +} + +- (id)initWithLayout:(L4Layout*)aLayout fileName:(NSString*)aName rollingFrequency:(NSString *)aRollingFrequency +{ + self = [super initWithLayout:aLayout fileName:aName append:YES]; + + if (self != nil) { + [self setRollingFrequency:aRollingFrequency]; + } + + return self; +} + +- (void)setRollingFrequency:(NSString *)aRollingFrequency +{ + _rollingFrequency = [aRollingFrequency copy]; + [self setLastRolloverDate:[NSDate date]]; +} + +/* ********************************************************************* */ +#pragma mark L4PropertiesConfigurable protocol methods +/* ********************************************************************* */ +- (id) initWithProperties:(L4Properties *) initProperties +{ + self = [super initWithProperties:initProperties]; + + if (self) { + // Support for appender.L4RollingFrequency in properties configuration file + NSString *rollingFrequency = [initProperties stringForKey:L4RollingFrequencyKey]; + if (rollingFrequency) { + self.rollingFrequency = rollingFrequency; + } + } + + return self; +} + +/* ********************************************************************* */ +#pragma mark Protected methods +/* ********************************************************************* */ +- (void)subAppend:(L4LogEvent*)event +{ + [self rollOver]; + [super subAppend:event]; +} + +/* ********************************************************************* */ +#pragma mark Private methods +/* ********************************************************************* */ +- (NSDate*)lastRolloverDate +{ + return _lastRolloverDate; +} + +- (void)setLastRolloverDate:(NSDate*)date +{ + @synchronized(self) { + if (_lastRolloverDate != date) { + _lastRolloverDate = date; + } + } +} + +/** + * Rolls file name + */ +- (void)rollOver +{ + // if the rolling frequency is never, return + if ([self.rollingFrequency isEqualToString:L4RollingFrequencyNever]) + return; + + @synchronized(self) { + + NSDate *now = [NSDate date]; + + NSCalendar *calendar = [NSCalendar currentCalendar]; + NSDateComponents *nowDateComponents = [calendar components:(NSYearCalendarUnit | NSMonthCalendarUnit | NSWeekCalendarUnit + | NSDayCalendarUnit | NSHourCalendarUnit | NSMinuteCalendarUnit) + fromDate:now]; + + NSDateComponents *lastDateComponents = [calendar components:(NSYearCalendarUnit | NSMonthCalendarUnit | NSWeekCalendarUnit + | NSDayCalendarUnit | NSHourCalendarUnit | NSMinuteCalendarUnit) + fromDate:self.lastRolloverDate]; + + bool doRollover = NO; + NSString *format; + + if ([self.rollingFrequency isEqualToString:L4RollingFrequencyMonthly]) { + doRollover = ([nowDateComponents year] != [lastDateComponents year]) + || ([nowDateComponents month] != [lastDateComponents month]); + + format = @"yyyy"; + + } else if ([self.rollingFrequency isEqualToString:L4RollingFrequencyWeekly]) { + doRollover = ([nowDateComponents year] != [lastDateComponents year]) + || ([nowDateComponents week] != [lastDateComponents week]); + + format = @"yyyy-MM"; + + } else if ([self.rollingFrequency isEqualToString:L4RollingFrequencyDaily]) { + doRollover = ([nowDateComponents year] != [lastDateComponents year]) + || ([nowDateComponents month] != [lastDateComponents month]) + || ([nowDateComponents day] != [lastDateComponents day]); + + format = @"yyyy-MM-dd"; + + } else if ([self.rollingFrequency isEqualToString:L4RollingFrequencyHalfDaily]) { + doRollover = ([nowDateComponents year] != [lastDateComponents year]) + || ([nowDateComponents month] != [lastDateComponents month]) + || ([nowDateComponents day] != [lastDateComponents day]) + || (([nowDateComponents hour] / 12) != ([lastDateComponents hour] / 12)); + + format = @"yyyy-MM-dd-HH"; + + } else if ([self.rollingFrequency isEqualToString:L4RollingFrequencyHourly]) { + doRollover = ([nowDateComponents year] != [lastDateComponents year]) + || ([nowDateComponents month] != [lastDateComponents month]) + || ([nowDateComponents day] != [lastDateComponents day]) + || ([nowDateComponents hour] != [lastDateComponents hour]); + + format = @"yyyy-MM-dd-HH"; + + } else if ([self.rollingFrequency isEqualToString:L4RollingFrequencyMinutely]) { + doRollover = ([nowDateComponents year] != [lastDateComponents year]) + || ([nowDateComponents month] != [lastDateComponents month]) + || ([nowDateComponents day] != [lastDateComponents day]) + || ([nowDateComponents hour] != [lastDateComponents hour]) + || ([nowDateComponents minute] != [lastDateComponents minute]); + + format = @"yyyy-MM-dd-HH-mm"; + } + + if (doRollover) { + // generate the new filename extension + NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init]; + dateFormatter.dateFormat = format; + NSString *filenameExtension = [dateFormatter stringFromDate:[self lastRolloverDate]]; + + // generate the new rollover log file name + NSString *newFileName = [[self fileName] stringByAppendingPathExtension:filenameExtension]; + + // close the current log file + [self closeFile]; + + // rename the current log file to the new rollover log file name + NSFileManager *fileManager = [NSFileManager defaultManager]; + if (![fileManager moveItemAtPath:[self fileName] toPath:newFileName error:nil]) { + // if we can't rename the file, log an error + [L4LogLog error:[NSString stringWithFormat:@"Unable to move file from %@ to %@", [self fileName], newFileName]]; + } + + // re-activate this appender (this will open a new log file named [self fileName]) + [self setupFile]; + + [self setLastRolloverDate:now]; + } + + } +} +@end diff --git a/mac/TeamTalk/Libraries/Log4Cocoa/L4DenyAllFilter.h b/mac/TeamTalk/Libraries/Log4Cocoa/L4DenyAllFilter.h new file mode 100644 index 000000000..ca312ccbb --- /dev/null +++ b/mac/TeamTalk/Libraries/Log4Cocoa/L4DenyAllFilter.h @@ -0,0 +1,14 @@ +#import +#import "L4Filter.h" + +/** + * + * This filter drops all logging events. + * + * You can add this filter to the end of a filter chain to switch from the default "accept all unless instructed + * otherwise" filtering behaviour to a "deny all unless instructed otherwise" behaviour. +*/ +@interface L4DenyAllFilter : L4Filter + +@end +// For copyright & license, see LICENSE. diff --git a/mac/TeamTalk/Libraries/Log4Cocoa/L4DenyAllFilter.m b/mac/TeamTalk/Libraries/Log4Cocoa/L4DenyAllFilter.m new file mode 100644 index 000000000..3c3f09d2e --- /dev/null +++ b/mac/TeamTalk/Libraries/Log4Cocoa/L4DenyAllFilter.m @@ -0,0 +1,15 @@ +/** + * For copyright & license, see LICENSE. + */ + +#import "L4DenyAllFilter.h" + + +@implementation L4DenyAllFilter + +- (L4FilterResult) decide:(L4LogEvent *) event +{ + return L4FilterDeny; +} + +@end diff --git a/mac/TeamTalk/Libraries/Log4Cocoa/L4FileAppender.h b/mac/TeamTalk/Libraries/Log4Cocoa/L4FileAppender.h new file mode 100644 index 000000000..dff505da2 --- /dev/null +++ b/mac/TeamTalk/Libraries/Log4Cocoa/L4FileAppender.h @@ -0,0 +1,83 @@ +/** + * This appender appends logging messages to a file whose path you specify. This class is a subclass of L4WriterAppender. + * The L4FileAppender does not support buffering configuration. Any methods or arguments that refer to buffering are ignored. + * For copyright & license, see LICENSE. + */ + +#import +#import "L4WriterAppender.h" + +@interface L4FileAppender : L4WriterAppender + +/** + * Tracks if we should append or over-right. + */ + +@property (nonatomic, readonly) BOOL append; + +/** + * The path to the file to which log output should be written. + */ +@property (nonatomic, readonly) NSString * fileName; + +/** + * A basic initializer. + * This method calls initWithLayout:fileName:append:bufferIO:bufferSize: with layout and file name set to nil, + * append is NO, bufferIO is NO, bufferSize is 0 + */ +- (id)init; + +/** + * Initializes an instance from properties. The properties supported are: + * - File: the full path of the file to use. + * - Append: weather to append to the file, or create a new one. Expected values are [true|false]. + * If the values are being set in a file, this is how they could look: + * log4cocoa.appender.A2.File=/tmp/mylogfile.txt + * log4cocoa.appender.A2.Append=false + * @param initProperties the proterties to use. + */ +- (id)initWithProperties:(L4Properties *)initProperties; + +/** + * Initializes an L4FileAppender instance with the specified layout and file path name. + * This method calls initWithLayout:fileName:append:bufferIO:bufferSize: with the specified layout and file name, + * append is NO, bufferIO is NO, bufferSize is 0 + * @param aLayout The layout that this appender should use + * @param aName The file path of the file you want log output to be written to. If the file does not exist, it will be created if possible. If the file cannot be created for some reason, a FileNotFoundException will be raised. + * @throws + * @return An initialized L4FileAppender object + */ +- (id)initWithLayout:(L4Layout *)aLayout fileName:(NSString *)aName; + +/** + * Initializes an L4FileAppender instance with the specified layout, file path name, and append option. + * This method calls initWithLayout:fileName:append:bufferIO:bufferSize: with the specified layout, file name, and append + * option, bufferIO is NO, bufferSize is 0 + * @param aLayout The layout that this appender should use + * @param aName The file path of the file you want log output to be written to. If the file does not exist, it will be created if possible. If the file cannot be created for some reason, a FileNotFoundException will be raised. + * @param flag YES = log output should be appended to the file. NO = the file's previous contents should be overwritten + * @throws + * @return An initialized L4FileAppender object + */ +- (id)initWithLayout:(L4Layout *)aLayout fileName:(NSString *)aName append:(BOOL)flag; + +@end + +/** + * These methods are "protected" methods and should not be called except by subclasses. + */ +@interface L4FileAppender (ProtectedMethods) + +/** + * This method closes and releases the underlying file handle. + */ +- (void)closeFile; + +/** + * This method is called to insure the file is set up to write to. + */ +- (void)setupFile; + + +@end +// For copyright & license, see LICENSE. diff --git a/mac/TeamTalk/Libraries/Log4Cocoa/L4FileAppender.m b/mac/TeamTalk/Libraries/Log4Cocoa/L4FileAppender.m new file mode 100644 index 000000000..ec26d8420 --- /dev/null +++ b/mac/TeamTalk/Libraries/Log4Cocoa/L4FileAppender.m @@ -0,0 +1,110 @@ +/** + * For copyright & license, see LICENSE. + */ + +#import "L4FileAppender.h" +#import "L4Layout.h" +#import "L4LogLog.h" +#import "L4Properties.h" + +@implementation L4FileAppender + +- (id) init +{ + return [self initWithLayout:nil fileName:nil append:NO]; +} + +- (id) initWithProperties:(L4Properties *) initProperties +{ + self = [super initWithProperties:initProperties]; + + if (self) { + // Support for appender.File in properties configuration file + NSString *buf = [initProperties stringForKey:@"File"]; + if (!buf) { + [L4LogLog error:@"Invalid filename; L4FileAppender properties require a file be specified."]; + return nil; + } + _fileName = [buf stringByExpandingTildeInPath]; + + // Support for appender.Append in properties configuration file + _append = YES; + if ([initProperties stringForKey:@"Append"]) { + NSString *buf = [[initProperties stringForKey:@"Append"] lowercaseString]; + _append = [buf isEqualToString:@"true"]; + } + [self setupFile]; + } + + return self; +} + +- (id) initWithLayout:(L4Layout *) aLayout fileName:(NSString *) aName +{ + return [self initWithLayout:aLayout fileName:aName append:NO]; +} + +- (id) initWithLayout:(L4Layout *) aLayout fileName:(NSString *) aName append:(BOOL) flag +{ + self = [super init]; + if (self != nil) + { + [self setLayout:aLayout]; + _fileName = [aName stringByExpandingTildeInPath]; + _append = flag; + [self setupFile]; + } + return self; +} + +- (void)setupFile +{ + NSFileManager* fileManager = nil; + + @synchronized(self) { + if (!_fileName || _fileName.length == 0) { + [self closeFile]; + _fileName = nil; + [self setFileHandle:nil]; + } else { + + fileManager = [NSFileManager defaultManager]; + + // if file doesn't exist, try to create the file + if (![fileManager fileExistsAtPath:_fileName]) { + // if the we cannot create the file, raise a FileNotFoundException + if (![fileManager createFileAtPath:_fileName contents:nil attributes:nil]) { + [NSException raise:@"FileNotFoundException" format:@"Couldn't create a file at %@", _fileName]; + } + } + + // if we had a previous file name, close it and release the file handle + if (_fileName) + [self closeFile]; + + // open a file handle to the file + [self setFileHandle:[NSFileHandle fileHandleForWritingAtPath:_fileName]]; + + // check the append option + if (_append) + [_fileHandle seekToEndOfFile]; + else + [_fileHandle truncateFileAtOffset:0]; + } + } +} + + +#pragma mark - Protected methods + +- (void) closeFile +{ + @synchronized(self) { + [_fileHandle closeFile]; + + // Deallocate the file handle because trying to read from or write to a closed file raises exceptions. Sending messages to nil objects are no-ops. + _fileHandle = nil; + } +} +@end + diff --git a/mac/TeamTalk/Libraries/Log4Cocoa/L4Filter.h b/mac/TeamTalk/Libraries/Log4Cocoa/L4Filter.h new file mode 100644 index 000000000..52e567082 --- /dev/null +++ b/mac/TeamTalk/Libraries/Log4Cocoa/L4Filter.h @@ -0,0 +1,41 @@ +#import +#import "L4AppenderProtocols.h" + +@class L4LogEvent, L4Properties; + +/** + * An enumeration of the allowed L4Filter actions. + */ +typedef NS_ENUM(NSInteger, L4FilterResult) { + L4FilterDeny = -1, /**< Prevent the request to log the event. */ + L4FilterNeutral = 0, /**< Do not affect the request to log the event. */ + L4FilterAccept = 1 /**< Allow the request to log he event. */ +}; + +/** + * Filter for log events. + * This class is intended to serve as the base for filters. This class itself does nothing; + * the only way a flter would actually be used would be to subclass it and over-ride the + * decide:method. + */ +@interface L4Filter : NSObject + +@property (strong) L4Filter * next; /**< Accessor for the next filter. */ + +/** + * Initializes an instance from properties. Currently there are no properties that apply to this class. + * @param initProperties the proterties to use. + * @throw L4PropertyMissingException if a required property is missing. + */ +- (id)initWithProperties:(L4Properties *)initProperties; + +/** + * Decide what this filter should do with event. + * This method is used to determine if the event should be logged. + * @param event the event to check. + * @return one of L4FilterDeny, L4FilterNeutral, or L4FilterAccept. + */ +- (L4FilterResult)decide:(L4LogEvent *)event; + +@end +// For copyright & license, see LICENSE. diff --git a/mac/TeamTalk/Libraries/Log4Cocoa/L4Filter.m b/mac/TeamTalk/Libraries/Log4Cocoa/L4Filter.m new file mode 100644 index 000000000..dba3b3fab --- /dev/null +++ b/mac/TeamTalk/Libraries/Log4Cocoa/L4Filter.m @@ -0,0 +1,22 @@ +/** + * For copyright & license, see LICENSE. + */ + +#import "L4Filter.h" +#import "L4LogEvent.h" + + +@implementation L4Filter + +- (id)initWithProperties:(L4Properties *)initProperties +{ + return [super init]; +} + + +- (L4FilterResult)decide:(L4LogEvent *)event +{ + return L4FilterNeutral; +} + +@end diff --git a/mac/TeamTalk/Libraries/Log4Cocoa/L4JSONLayout.h b/mac/TeamTalk/Libraries/Log4Cocoa/L4JSONLayout.h new file mode 100644 index 000000000..b67b6fe5e --- /dev/null +++ b/mac/TeamTalk/Libraries/Log4Cocoa/L4JSONLayout.h @@ -0,0 +1,12 @@ +#import + +#import "L4Layout.h" + +/** + * This class represents formating a JSON object for error. + */ +@interface L4JSONLayout : L4Layout + ++ (instancetype)JSONLayout; + +@end diff --git a/mac/TeamTalk/Libraries/Log4Cocoa/L4JSONLayout.m b/mac/TeamTalk/Libraries/Log4Cocoa/L4JSONLayout.m new file mode 100644 index 000000000..59ce9d581 --- /dev/null +++ b/mac/TeamTalk/Libraries/Log4Cocoa/L4JSONLayout.m @@ -0,0 +1,52 @@ +/** + * For copyright & license, see LICENSE. + */ + +#import "L4JSONLayout.h" +#import "L4LogEvent.h" +#import "L4Properties.h" +#import "L4Logger.h" + +@implementation L4JSONLayout + ++ (instancetype)JSONLayout +{ + return [[L4JSONLayout alloc] init]; +} + +- (NSString *)format:(L4LogEvent *)event +{ + /* + { + "logger": "%@" + "level": "%@" + "time": "%ldms" + "file": "%@:%@" + "method": "%@" + "message": "%@" + } + */ + return [NSString stringWithFormat: + @"{\n" + "t\"logger\":\"%@\",\n" + "\t\"level\":\"%@\",\n" + "\t\"time\":\"%ldms\",\n" + "\t\"file\":\"%@:%@\",\n" + "\t\"method\":\"%@\",\n" + "\t\"message\":\"%@\"\n" + "}\n", + event.logger.name, + event.level.stringValue, + event.millisSinceStart, + event.fileName, + event.lineNumber.stringValue, + event.methodName, + event.renderedMessage]; +} + +- (NSString *)contentType { + return @"application/json"; +} + + +@end diff --git a/mac/TeamTalk/Libraries/Log4Cocoa/L4Layout.h b/mac/TeamTalk/Libraries/Log4Cocoa/L4Layout.h new file mode 100644 index 000000000..b9b960fb1 --- /dev/null +++ b/mac/TeamTalk/Libraries/Log4Cocoa/L4Layout.h @@ -0,0 +1,57 @@ +#import +#import "L4AppenderProtocols.h" + +@class L4LogEvent, L4SimpleLayout, L4Properties; + +/** + * This class represents formating a line of log output. + */ +@interface L4Layout : NSObject + +/** + * Create and return a simple layout. + * This factory method is used to create a simple layout. + * @return the new instance of L4SimpleLayout. + */ ++ (instancetype)simpleLayout; + +/** + * Initializes an instance from properties. Currently there are no properties that apply to this class. + * @param initProperties the proterties to use. + */ +- (id)initWithProperties:(L4Properties *) initProperties; + +/** + * Format a log event. + * This method will format a given event based on our layout and return a string reasy for writing. + * @param event the event to be formatted. + * @return a string of the formatted event. + */ +- (NSString *)format:(L4LogEvent *) event; + +/** + * The MIME type of the string returned by the format:method. + * @return the MIME type. + */ +- (NSString *)contentType; + +/** + * Any header content that should be written to the log. + * @return the string header. + */ +- (NSString *)header; + +/** + * Any footer content that should be written to the log. + * @return the string footer. + */ +- (NSString *)footer; + +/** + * Should this formatter format exceptions. + * @return YES if this formatter should format an exception; NO if it should not. + */ +- (BOOL)ignoresExceptions; + +@end +// For copyright & license, see LICENSE. diff --git a/mac/TeamTalk/Libraries/Log4Cocoa/L4Layout.m b/mac/TeamTalk/Libraries/Log4Cocoa/L4Layout.m new file mode 100644 index 000000000..d65db4504 --- /dev/null +++ b/mac/TeamTalk/Libraries/Log4Cocoa/L4Layout.m @@ -0,0 +1,46 @@ +/** + * For copyright & license, see LICENSE. + */ + +#import "L4Layout.h" +#import "L4SimpleLayout.h" +#import "L4LogEvent.h" + +@implementation L4Layout + ++ (instancetype)simpleLayout +{ + return [[L4SimpleLayout alloc] init]; +} + +- (id)initWithProperties:(L4Properties *)initProperties +{ + return [super init]; +} + +- (NSString *)format:(L4LogEvent *)event +{ + return [event description]; +} + +- (NSString *)contentType +{ + return @"text/plain"; +} + +- (NSString *)header +{ + return nil; +} + +- (NSString *)footer +{ + return nil; +} + +- (BOOL)ignoresExceptions +{ + return YES; +} + +@end diff --git a/mac/TeamTalk/Libraries/Log4Cocoa/L4Level.h b/mac/TeamTalk/Libraries/Log4Cocoa/L4Level.h new file mode 100644 index 000000000..15e31f3ab --- /dev/null +++ b/mac/TeamTalk/Libraries/Log4Cocoa/L4Level.h @@ -0,0 +1,171 @@ +// For copyright & license, see LICENSE. + +#import + +// ALL < DEBUG < INFO < WARN < ERROR < FATAL < OFF + +#define OFF_INT 99 +#define FATAL_INT 60 +#define ERROR_INT 50 +#define WARN_INT 40 +#define INFO_INT 30 +#define DEBUG_INT 20 +#define TRACE_INT 10 +#define ALL_INT 0 + +@interface L4Level : NSObject + +/** + * The int value of this log level. + */ +@property (readonly) int intValue; + +/** + * The name of this level. + */ +@property (readonly) NSString * name; + +/** + * The int equivelent for syslog. + */ +@property (readonly) int syslogEquivalent; + +/** + * Creates and returns an instance with the provided values. + * @param aLevel the level for this instance. + * @param aName the neame for this level. + * @param sysLogLevel the system log level for this instance. + * @return the new instance. + */ ++ (L4Level *)level:(int)aLevel withName:(NSString *)aName syslogEquivalent:(int)sysLogLevel; + +/** + * Accessor for the default instance with a level of off. + * @return the off instance. + */ ++ (L4Level *)off; + +/** + * Accessor for the default instance with a level of fatal. + * @return the fatal instance. + */ ++ (L4Level *)fatal; + +/** + * Accessor for the default instance with a level of error. + * @return the error instance. + */ ++ (L4Level *)error; + +/** + * Accessor for the default instance with a level of warn. + * @return the warn instance. + */ ++ (L4Level *)warn; + +/** + * Accessor for the default instance with a level of info. + * @return the info instance. + */ ++ (L4Level *)info; + +/** + * Accessor for the default instance with a level of debug. + * @return debug off instance. + */ ++ (L4Level *)debug; + +/** + * Accessor for the default instance with a level of trace. + * @return trace off instance. + */ ++ (L4Level *)trace; + +/** + * Accessor for the default instance with a level of all. + * @return the all instance. + */ ++ (L4Level *)all; + +/** + * Create and return a new instance where the level is set to the string argument. + * @param aLevel the name of the level requested. The options are: + * - ALL + * - DEBUG + * - INFO + * - WARN + * - ERROR + * - FATAL + * - OFF + * @return the new L4Level. + */ ++ (L4Level *)levelWithName:(NSString *)aLevel; + +/** + * Create and return a new instance where the level is set to the string argument. If no level matches the + * argument, the defaultLevel is rturned. + * @param aLevel the name of the level requested. The options are: + * - ALL + * - DEBUG + * - INFO + * - WARN + * - ERROR + * - FATAL + * - OFF + * @param defaultLevel the level to use if aLevel can not be dereferenced. + * @return the new L4Level. + */ ++ (L4Level *)levelWithName:(NSString *)aLevel defaultLevel:(L4Level *)defaultLevel; + +/** + * Create and return a new instance where the level is set to the int argument. + * @param aLevel the int specifier of the level requested. + * @return the new L4Level. + */ ++ (L4Level *)levelWithInt:(int)aLevel; + +/** + * Create and return a new instance where the level is set to the int argument. If no level matches the + * argument, the defaultLevel is rturned. + * @param aLevel the int specifier of the level requested. + * @param defaultLevel the level to use if aLevel can not be dereferenced. + * @return the new L4Level. + */ ++ (L4Level *)levelWithInt:(int)aLevel defaultLevel:(L4Level *)defaultLevel; + +/** + * Initializes a new instance with the parameters supplied. + * @param aLevel + * @param aName + * @param sysLogLevel + * @return the newly initialized instance. + */ +- (id)initLevel:(int)aLevel withName:(NSString *)aName syslogEquivalent:(int)sysLogLevel; + +/** + * Used to access a textual representation of this level. + * @return the string describing this instance. + */ +- (NSString *)description; + +/** + * Used to access a string representation of this level. + * @return the string describing this instance. + */ +- (NSString *)stringValue; + +/** + * Used to determine if this instance is of greator or equal level to the argument. + * @return YES if this instance is of at least equal level to he argument; NO if it is not. + */ +- (BOOL)isGreaterOrEqual:(L4Level *)aLevel; + +/** + * Used to determine if this instance is to be logged based on the level of the parameter. + * @param aLevel the level that is the minimum to be logged. + * @return YES if this level should be logged; we must be greater than the parameter to be true; NO + * if we ar eless. + */ +- (BOOL)isEnabledFor:(L4Level *)aLevel; + +@end diff --git a/mac/TeamTalk/Libraries/Log4Cocoa/L4Level.m b/mac/TeamTalk/Libraries/Log4Cocoa/L4Level.m new file mode 100644 index 000000000..8af323d15 --- /dev/null +++ b/mac/TeamTalk/Libraries/Log4Cocoa/L4Level.m @@ -0,0 +1,175 @@ +/** + * For copyright & license, see LICENSE. + */ + +#import "L4Level.h" + +@implementation L4Level + +// L4_ALL < L4_TRACE < L4_DEBUG < L4_INFO < L4_WARN < L4_ERROR < L4_FATAL < L4_OFF + +static L4Level *L4_OFF = nil; +static L4Level *L4_FATAL = nil; +static L4Level *L4_ERROR = nil; +static L4Level *L4_WARN = nil; +static L4Level *L4_INFO = nil; +static L4Level *L4_DEBUG = nil; +static L4Level *L4_TRACE = nil; +static L4Level *L4_ALL = nil; + +#pragma mark - Class methods + ++ (void)initialize +{ + L4_OFF = [L4Level level:OFF_INT withName:@"OFF" syslogEquivalent:0]; + L4_FATAL = [L4Level level:FATAL_INT withName:@"FATAL" syslogEquivalent:0]; + L4_ERROR = [L4Level level:ERROR_INT withName:@"ERROR" syslogEquivalent:3]; + L4_WARN = [L4Level level:WARN_INT withName:@"WARN" syslogEquivalent:4]; + L4_INFO = [L4Level level:INFO_INT withName:@"INFO" syslogEquivalent:6]; + L4_DEBUG = [L4Level level:DEBUG_INT withName:@"DEBUG" syslogEquivalent:7]; + L4_TRACE = [L4Level level:TRACE_INT withName:@"TRACE" syslogEquivalent:7]; + L4_ALL = [L4Level level:ALL_INT withName:@"ALL" syslogEquivalent:7]; +} + ++ (L4Level *)level:(int)aLevel withName:(NSString *)aName syslogEquivalent:(int)sysLogLevel +{ + return [[L4Level alloc] initLevel:aLevel withName:aName syslogEquivalent:sysLogLevel]; +} + ++ (L4Level *)off +{ + return L4_OFF; +} + ++ (L4Level *)fatal +{ + return L4_FATAL; +} + ++ (L4Level *)error +{ + return L4_ERROR; +} + ++ (L4Level *)warn +{ + return L4_WARN; +} + ++ (L4Level *)info +{ + return L4_INFO; +} + ++ (L4Level *)debug +{ + return L4_DEBUG; +} + ++ (L4Level *)trace +{ + return L4_TRACE; +} + ++ (L4Level *)all +{ + return L4_ALL; +} + ++ (L4Level *)levelWithName:(NSString *)aLevel +{ + return [L4Level levelWithName:aLevel defaultLevel:L4_DEBUG]; +} + ++ (L4Level *)levelWithName:(NSString *)aLevel defaultLevel:(L4Level *)defaultLevel +{ + NSString *theLevel; + + if (!aLevel) { return defaultLevel; } + + theLevel = [aLevel uppercaseString]; + + if ([theLevel isEqualToString:@"ALL"]) { return L4_ALL; } + if ([theLevel isEqualToString:@"TRACE"]) { return L4_TRACE; } + if ([theLevel isEqualToString:@"DEBUG"]) { return L4_DEBUG; } + if ([theLevel isEqualToString:@"INFO"]) { return L4_INFO; } + if ([theLevel isEqualToString:@"WARN"]) { return L4_WARN; } + if ([theLevel isEqualToString:@"ERROR"]) { return L4_ERROR; } + if ([theLevel isEqualToString:@"FATAL"]) { return L4_FATAL; } + if ([theLevel isEqualToString:@"OFF"]) { return L4_OFF; } + + return defaultLevel; +} + + ++ (L4Level *)levelWithInt:(int)aLevel +{ + return [L4Level levelWithInt:aLevel defaultLevel:L4_DEBUG]; +} + ++ (L4Level *)levelWithInt:(int) aLevel defaultLevel:(L4Level *)defaultLevel +{ + switch (aLevel) { + case ALL_INT: return L4_ALL; + case TRACE_INT:return L4_TRACE; + case DEBUG_INT:return L4_DEBUG; + case INFO_INT: return L4_INFO; + case WARN_INT: return L4_WARN; + case ERROR_INT:return L4_ERROR; + case FATAL_INT:return L4_FATAL; + case OFF_INT: return L4_OFF; + + default: + return defaultLevel; + } +} + +#pragma mark - Instance methods + +- (id)init +{ + return [L4Level debug]; // ok since not mutable and no "set" methods exist. +} + +- (id)initLevel:(int)aLevel withName:(NSString *)aName syslogEquivalent:(int)sysLogLevel +{ + self = [super init]; + if (self) { + _intValue = aLevel; + _syslogEquivalent = sysLogLevel; + _name = [aName copy]; + } + return self; +} + +- (BOOL)isEqual:(id)anotherObject +{ + if (anotherObject && [anotherObject isKindOfClass:[L4Level class]]) { + L4Level *otherLevel = (L4Level *)anotherObject; + return otherLevel.intValue == self.intValue && [otherLevel.stringValue isEqualToString:self.stringValue]; + } + return NO; +} + +- (NSString *)description +{ + return self.name; +} + +- (NSString *)stringValue +{ + return self.name; +} + +- (BOOL)isGreaterOrEqual:(L4Level *) aLevel +{ + return self.intValue >= aLevel.intValue; +} + +// ### NOTE:I think this name is more apporopriate, but not changing it right now. +- (BOOL)isEnabledFor:(L4Level *) aLevel +{ + return self.intValue >= [aLevel intValue]; +} + +@end diff --git a/mac/TeamTalk/Libraries/Log4Cocoa/L4LevelMatchFilter.h b/mac/TeamTalk/Libraries/Log4Cocoa/L4LevelMatchFilter.h new file mode 100644 index 000000000..c2d42a5f8 --- /dev/null +++ b/mac/TeamTalk/Libraries/Log4Cocoa/L4LevelMatchFilter.h @@ -0,0 +1,46 @@ +#import +#import "L4Filter.h" + +@class L4Level, L4Properties; + +/** + * This is a very simple filter based on level matching. + * + * The filter admits two properties LevelToMatch and AcceptOnMatch. + * + * If there is an exact match between the value of the LevelToMatch option and the level of the L4LoggingEvent, then the + * decide: method returns L4FilterAccept in case the AcceptOnMatch option value is set to YES/TRUE, if + * it is NO/FALSE then L4FilterDeny is returned. If there is no match, L4FilterNeutral is returned. + * + * If levelToMatch is set to ALL, then any L4LoggingEvent is a match. + */ +@interface L4LevelMatchFilter : L4Filter + +@property (nonatomic) BOOL acceptOnMatch; /**< YES to allow logging on a match of levelToMatch, NO to prevent logging on a match. */ +@property (nonatomic, weak) L4Level * levelToMatch; /**< The level to test against. */ + +/** + * Initializes an instance from properties. The properties supported are: + * - AcceptOnMatch: a string that get's converted to a BOOL. YES/NO work well. See the documentation for [NSString + * boolValue] for other options. + * - LevelToMatch: the name of the L4Level to match. See L4Level#levelWithName: for options. + * + * @param initProperties the proterties to use. + * @throw L4PropertyMissingException if the LevelToMatch property is missing. + */ +- (id) initWithProperties:(L4Properties *)initProperties; + +/** + * Initialze a new instance with the given values. + * This is the default initializer, as the instance should have these two values set. + * + * @param shouldAccept YES to allow logging on a match of levelToMatch, NO to prevent logging on a match. + * @param aLevel The level to test against. Not allowed to be nil. + * @throw NSInvalidArgumentException if aLevel is nil. + */ +- (id) initWithAcceptOnMatch:(BOOL)shouldAccept andLevelToMatch:(L4Level *)aLevel; + + + +@end +// For copyright & license, see LICENSE. diff --git a/mac/TeamTalk/Libraries/Log4Cocoa/L4LevelMatchFilter.m b/mac/TeamTalk/Libraries/Log4Cocoa/L4LevelMatchFilter.m new file mode 100644 index 000000000..90ef102bf --- /dev/null +++ b/mac/TeamTalk/Libraries/Log4Cocoa/L4LevelMatchFilter.m @@ -0,0 +1,63 @@ +/** + * For copyright & license, see LICENSE. + */ +#import "L4LevelMatchFilter.h" +#import "L4LogEvent.h" +#import "L4Level.h" +#import "L4Properties.h" + +@implementation L4LevelMatchFilter + +- (id) initWithAcceptOnMatch:(BOOL)shouldAccept andLevelToMatch:(L4Level *)aLevel +{ + self = [super init]; + if (self) { + self.acceptOnMatch = shouldAccept; + if (aLevel == nil) { + self = nil; + [NSException raise:NSInvalidArgumentException format:@"aLevel is not allowed to be nil."]; + } else { + self.levelToMatch = aLevel; + } + } + return self; +} + +- (id) initWithProperties:(L4Properties *)initProperties +{ + self = [super initWithProperties:initProperties]; + if (self) { + NSString *acceptIfMatched = [initProperties stringForKey:@"AcceptOnMatch"]; + self.acceptOnMatch = acceptIfMatched ? [acceptIfMatched boolValue] : YES; + + NSString *levelName = [initProperties stringForKey:@"LevelToMatch"]; + + if (levelName) { + // Returns nil if no level with specified name is found + self.levelToMatch = [L4Level levelWithName:levelName]; + + if (!self.levelToMatch) { + [NSException raise:L4PropertyMissingException + format:@"L4Level name [%@] not found.", levelName]; + } + } else { + [NSException raise:L4PropertyMissingException + format:@"LevelToMatch is a required property."]; + } + } + return self; +} + + +- (L4FilterResult) decide:(L4LogEvent *)event +{ + // Default stance. + L4FilterResult action = L4FilterNeutral; + if (event.level.intValue == self.levelToMatch.intValue || self.levelToMatch.intValue == [L4Level all].intValue){ + action = self.acceptOnMatch ? L4FilterAccept : L4FilterDeny; + } + + return action; +} + +@end diff --git a/mac/TeamTalk/Libraries/Log4Cocoa/L4LevelRangeFilter.h b/mac/TeamTalk/Libraries/Log4Cocoa/L4LevelRangeFilter.h new file mode 100644 index 000000000..ab74619c5 --- /dev/null +++ b/mac/TeamTalk/Libraries/Log4Cocoa/L4LevelRangeFilter.h @@ -0,0 +1,68 @@ +#import +#import "L4Filter.h" + +@class L4Level; + +/* + * This is a very simple filter based on level matching, which can be used to + * reject messages with priorities outside a certain range. + * + * The filter admits three properties LevelMin, LevelMax and AcceptOnMatch. + * + * If the level of the L4LoggingEvent is not between Min and Max (inclusive), + * then L4FilterNeutral is returned. + * + * If the L4LoggingEvent level is within the specified range, then if + * AcceptOnMatch is true, L4FilterAccept is returned, and if AcceptOnMatch is + * false, L4FilterDeny is returned. + * + * If LevelMin is not defined, then there is no minimum acceptable level + * (i.e. a level is never rejected for being too "low"/unimportant). + * If LevelMax is not defined, then there is no maximum acceptable level + * (i.e. a level is never rejected for beeing too "high"/important). + */ + +@interface L4LevelRangeFilter : L4Filter { + BOOL acceptOnMatch; /**< YES to allow logging on a match, NO to prevent logging on a match.*/ + L4Level *minimumLevelToMatch; /**< the minimum L4Level to match.*/ + L4Level *maximumLevelToMatch; /**< the minimum L4Level to match.*/ +} + +/** + * Initializes an instance from properties. The properties supported are: + * - AcceptOnMatch: a string that get's converted to a BOOL. YES/NO work well. See the documentation for [NSString + * boolValue] for other options. + * - MinimumLevel: the name of the minimum L4Level to match. See L4Level#levelWithName: for options. + * - MaximumLevel: the name of the maximum L4Level to match. See L4Level#levelWithName: for options. + * + * @param initProperties the proterties to use. + */ +- (id) initWithProperties:(L4Properties *)initProperties; + +/** + * Initialze a new instance with the given values. + * This is the default initializer, as the instance should have these two values set. + * + * @param shouldAccept YES to allow logging on a match of levelToMatch, NO to prevent logging on a match. + * @param minimumLevel: the name of the minimum L4Level to match. See L4Level#levelWithName: for options. + * @param maximumLevel: the name of the maximum L4Level to match. See L4Level#levelWithName: for options. + */ +- (id) initWithAcceptOnMatch:(BOOL)shouldAccept fromLevel:(L4Level *)minimumLevel toLevel:(L4Level *)maximumLevel; + +/** + * Accessor for the acceptOnMatch property. + */ +- (BOOL) acceptOnMatch; + +/** + * Accessor for the minimumLevelToMatch property. + */ +- (L4Level *) minimumLevelToMatch; + +/** + * Accessor for the maximumLevelToMatch property. + */ +- (L4Level *) maximumLevelToMatch; + +@end +// For copyright & license, see LICENSE. diff --git a/mac/TeamTalk/Libraries/Log4Cocoa/L4LevelRangeFilter.m b/mac/TeamTalk/Libraries/Log4Cocoa/L4LevelRangeFilter.m new file mode 100644 index 000000000..26e40d295 --- /dev/null +++ b/mac/TeamTalk/Libraries/Log4Cocoa/L4LevelRangeFilter.m @@ -0,0 +1,80 @@ +/** + * For copyright & license, see LICENSE. + */ + +#import "L4LevelRangeFilter.h" +#import "L4LogEvent.h" +#import "L4Level.h" +#import "L4LogLog.h" +#import "L4Properties.h" + +@implementation L4LevelRangeFilter +- (id) initWithAcceptOnMatch:(BOOL)shouldAccept fromLevel:(L4Level *)minimumLevel toLevel:(L4Level *)maximumLevel +{ + self = [super init]; + if (self != nil) { + acceptOnMatch = shouldAccept; + minimumLevelToMatch = minimumLevel; + maximumLevelToMatch = maximumLevel; + } + return self; +} + +- (id) initWithProperties:(L4Properties *) initProperties +{ + self = [super initWithProperties:initProperties]; + if(self != nil) { + NSString *acceptIfMatched = [initProperties stringForKey:@"AcceptOnMatch"]; + acceptOnMatch = YES; + if (acceptIfMatched) { + acceptOnMatch = [acceptIfMatched boolValue]; + } + + NSString *levelMinName = [initProperties stringForKey:@"MinimumLevel"]; + if (levelMinName != nil) { + minimumLevelToMatch = [L4Level levelWithName:levelMinName]; + } + + NSString *levelMaxName = [initProperties stringForKey:@"MaximumLevel"]; + if (levelMaxName != nil) { + maximumLevelToMatch = [L4Level levelWithName:levelMaxName]; + } + } + return self; +} + + +- (BOOL) acceptOnMatch +{ + return acceptOnMatch; +} + +- (L4Level *) minimumLevelToMatch +{ + return minimumLevelToMatch; +} + +- (L4Level *) maximumLevelToMatch +{ + return maximumLevelToMatch; +} + +- (L4FilterResult) decide:(L4LogEvent *) logEvent +{ + L4FilterResult shouldAccept = L4FilterNeutral; + BOOL matches = NO; + if (minimumLevelToMatch == nil || ([[logEvent level] isGreaterOrEqual:minimumLevelToMatch] == YES)) { + if (maximumLevelToMatch == nil || [[logEvent level] intValue] <= [maximumLevelToMatch intValue]) { + matches = YES; + } else { + matches = NO; + } + } + if (matches) { + shouldAccept = (acceptOnMatch == YES) ? L4FilterAccept :L4FilterDeny; + } + + return shouldAccept; +} + +@end diff --git a/mac/TeamTalk/Libraries/Log4Cocoa/L4LogEvent.h b/mac/TeamTalk/Libraries/Log4Cocoa/L4LogEvent.h new file mode 100644 index 000000000..e5fc9afa4 --- /dev/null +++ b/mac/TeamTalk/Libraries/Log4Cocoa/L4LogEvent.h @@ -0,0 +1,103 @@ +#import +#import "L4LoggerProtocols.h" + +@class L4Level, L4Logger; + +/** + * An event to be logged. This class embodies all of the information needed to generate a log message to an appender. + */ +@interface L4LogEvent : NSObject + +@property (readonly) L4Logger * logger; /**< The logger this event should use.*/ +@property (readonly) L4Level * level; /**< The level of this event.*/ + +@property (readonly) NSNumber * lineNumber; /**< The line number where the event was generated.*/ +@property (readonly) NSString * fileName; /**< The name of the file where the event was generated.*/ +@property (readonly) NSString * methodName; /**< The name of the method where the event was generated.*/ + +@property (readonly) NSDate * timestamp; /**< The timestamp for when this event was generated.*/ +@property (readonly) long millisSinceStart; /**< Accessor for the millisSinceStart attribute.*/ + +@property (readonly) NSException * exception; /**< Any exception that was logged as part of this event.*/ +@property (readonly) id message; /**< The message of this event.*/ +@property (readonly) NSString * renderedMessage; /**< The string version of message. */ + +/** + * Set up the class for use. To do this we simply get the time the app was started; this value + * is not exact; it is the time this class is initialized. Should be fine. + */ ++ (void) initialize; + +/** + * The time the class was initialized; used to determine how long an event + * occured into the appliction run. + * @return the start time of the application. + */ ++ (NSDate *) startTime; + +/** + * Creates a logging event with the given parameters. + * @param aLogger the logger this event should use. + * @param aLevel the level of this log event. + * @param aMessage the message to be logged. + * @return the new logging event. + */ ++ (instancetype)logger:(L4Logger *) aLogger + level:(L4Level *) aLevel + message:(id) aMessage; + +/** + * Creates a logging event with the given parameters. + * @param aLogger the logger this event should use. + * @param aLevel the level of this log event. + * @param aMessage the message to be logged. + * @param e an exception to go along with this log event. + * @return the new logging event. + */ ++ (instancetype)logger:(L4Logger *) aLogger + level:(L4Level *) aLevel + message:(id) aMessage + exception:(NSException *) e; + +/** + * Creates a logging event with the given parameters. + * @param aLogger the logger this event should use. + * @param aLevel the level of this log event. + * @param aLineNumber the line number in the file where this event was generated. + * @param aFileName the name of the file where this event was generated. + * @param aMethodName the name of the method where this event was generated. + * @param aMessage the message to be logged. + * @param e an exception to go along with this log event. + * @return the new logging event. + */ ++ (instancetype)logger:(L4Logger *) aLogger + level:(L4Level *) aLevel + lineNumber:(int) aLineNumber + fileName:(const char *) aFileName + methodName:(const char *) aMethodName + message:(id) aMessage + exception:(NSException *) e; + +/** + * Creates a logging event with the given parameters. + * @param aLogger the logger this event should use. + * @param aLevel the level of this log event. + * @param aLineNumber the line number in the file where this event was generated. + * @param aFileName the name of the file where this event was generated. + * @param aMethodName the name of the method where this event was generated. + * @param aMessage the message to be logged. + * @param e an exception to go along with this log event. + * @param aDate the time stamp for when this event was generated. + * @return the new logging event. + */ +- (id)initWithLogger:(L4Logger *) aLogger + level:(L4Level *) aLevel + lineNumber:(int) aLineNumber + fileName:(const char *) aFileName + methodName:(const char *) aMethodName + message:(id) aMessage + exception:(NSException *) e + eventTimestamp:(NSDate *) aDate; + +@end +// For copyright & license, see LICENSE. diff --git a/mac/TeamTalk/Libraries/Log4Cocoa/L4LogEvent.m b/mac/TeamTalk/Libraries/Log4Cocoa/L4LogEvent.m new file mode 100644 index 000000000..d5841d1ae --- /dev/null +++ b/mac/TeamTalk/Libraries/Log4Cocoa/L4LogEvent.m @@ -0,0 +1,122 @@ +/** + * For copyright & license, see LICENSE. + */ + +#import "L4LogEvent.h" +#import "L4Logger.h" + +static const int NO_LINE_NUMBER = -1; +static const char *NO_FILE_NAME = ""; +static const char *NO_METHOD_NAME = ""; + +static NSDate *startTime = nil; + +@implementation L4LogEvent + +@synthesize renderedMessage = _renderedMessage; + ++ (void) initialize +{ + startTime = [NSDate date]; +} + ++ (NSDate *) startTime +{ + return startTime; +} + ++ (instancetype)logger:(L4Logger *)aLogger + level:(L4Level *)aLevel + message:(id)aMessage +{ + return [self logger:aLogger + level:aLevel + lineNumber:NO_LINE_NUMBER + fileName:NO_FILE_NAME + methodName:NO_METHOD_NAME + message:aMessage + exception:nil]; +} + ++ (instancetype)logger:(L4Logger *)aLogger + level:(L4Level *)aLevel + message:(id)aMessage + exception:(NSException *)e; +{ + return [self logger:aLogger + level:aLevel + lineNumber:NO_LINE_NUMBER + fileName:NO_FILE_NAME + methodName:NO_METHOD_NAME + message:aMessage + exception:e]; +} + ++ (instancetype)logger:(L4Logger *)aLogger + level:(L4Level *)aLevel + lineNumber:(int)aLineNumber + fileName:(const char *)aFileName + methodName:(const char *)aMethodName + message:(id)aMessage + exception:(NSException *)e +{ + return [[L4LogEvent alloc] initWithLogger:aLogger + level:aLevel + lineNumber:aLineNumber + fileName:aFileName + methodName:aMethodName + message:aMessage + exception:e + eventTimestamp:[NSDate date]]; +} + +- (id) init +{ + return nil; +} + +- (id) initWithLogger:(L4Logger *) aLogger + level:(L4Level *) aLevel + lineNumber:(int) aLineNumber + fileName:(const char *) aFileName + methodName:(const char *) aMethodName + message:(id) aMessage + exception:(NSException *) e + eventTimestamp:(NSDate *) aDate +{ + self = [super init]; + if (self) { + _lineNumber = @(aLineNumber); + _fileName = @(aFileName); + _methodName = @(aMethodName); + + _logger = aLogger; + _level = aLevel; + _message = aMessage; + _exception = e; + _timestamp = aDate; + } + return self; +} + +- (long) millisSinceStart +{ + // its a double in seconds + NSTimeInterval time = [_timestamp timeIntervalSinceDate:startTime]; + return (long) (time * 1000); +} + +- (NSString *) renderedMessage +{ + if (!_renderedMessage && _message) { + if ([_message isKindOfClass:[NSString class]]) { + _renderedMessage = [_message copy]; // if its a string return it. + } else { + _renderedMessage = [_message description]; + } + } + + return _renderedMessage; +} + +@end diff --git a/mac/TeamTalk/Libraries/Log4Cocoa/L4LogLog.h b/mac/TeamTalk/Libraries/Log4Cocoa/L4LogLog.h new file mode 100644 index 000000000..1d21c186e --- /dev/null +++ b/mac/TeamTalk/Libraries/Log4Cocoa/L4LogLog.h @@ -0,0 +1,96 @@ +#import + +#define L4LogLog_PREFIX @"log4cocoa: " +#define L4LogLog_WARN_PREFIX @"log4cocoa: WARN: " +#define L4LogLog_ERROR_PREFIX @"log4cocoa: ERROR: " + +/** + * This class is used to log when the logging system could not be properly initialized. It logs to either stdout or + * stderr depending on the severity of the message. + * @note This class should not be used outside the framework. + */ +@interface L4LogLog : NSObject + +/** + * Is internal debugging enabled? + * @return YES if it is, NO if it is not. + */ ++ (BOOL)internalDebuggingEnabled; + +/** + * Changes the state of internal debugging. + * @param enabled YES to enable, NO to disable. + */ ++ (void)setInternalDebuggingEnabled:(BOOL)enabled; + +/** + * Accessor for quietModeEnabled. + * @return quietModeEnabled + */ ++ (BOOL)quietModeEnabled; + +/** + * Mutator for quietModeEnabled. + * @param enabled the new value for quietModeEnabled. + */ ++ (void)setQuietModeEnabled:(BOOL) enabled; + +/** + * If debuging & !quietMode, debug messages get sent to standard out, because Log4Cocoa classes + * can't use Log4Cocoa loggers. + * @param message the message to log. + */ ++ (void)debug:(NSString *) message; + +/** + * If debuging & !quietMode, debug messages get sent to standard out, because Log4Cocoa classes + * can't use Log4Cocoa loggers. + * @param message the message to log. + * @param exception the exception to log. + */ ++ (void)debug:(NSString *)message exception:(NSException *)exception; + +/** + * If !quietMode, warn & error messages get sent to standard error, because Log4Cocoa classes + * can't use Log4Cocoa loggers. + * @param message the message to log. + */ ++ (void)warn:(NSString *)message; + +/** + * If !quietMode, warn & error messages get sent to standard error, because Log4Cocoa classes + * can't use Log4Cocoa loggers. + * @param message the message to log. + * @param exception the exception to log. + */ ++ (void)warn:(NSString *)message exception:(NSException *)exception; + +/** + * If !quietMode, error & error messages get sent to standard error, because Log4Cocoa classes + * can't use Log4Cocoa loggers. + * @param message the message to log. + */ ++ (void)error:(NSString *)message; + +/** + * If !quietMode, error & error messages get sent to standard error, because Log4Cocoa classes + * can't use Log4Cocoa loggers. + * @param message the message to log. + * @param exception the exception to log. + */ ++ (void)error:(NSString *)message exception:(NSException *)exception; + +/** + * Writes the log message to the supplied fileHandle. + * @param message the message to write. + * @param prefix the string to write before message. + * @param fileHandle to handle to write to. + * @param exception the exsception to log. + */ ++ (void)writeMessage:(NSString *)message + withPrefix:(NSString *)prefix + toFile:(NSFileHandle *)fileHandle + exception:(NSException *)exception; + +@end +// For copyright & license, see LICENSE. diff --git a/mac/TeamTalk/Libraries/Log4Cocoa/L4LogLog.m b/mac/TeamTalk/Libraries/Log4Cocoa/L4LogLog.m new file mode 100644 index 000000000..d19717257 --- /dev/null +++ b/mac/TeamTalk/Libraries/Log4Cocoa/L4LogLog.m @@ -0,0 +1,114 @@ +/** + * For copyright & license, see LICENSE. + */ + +#import "L4LogLog.h" + + +static BOOL internalDebugging = NO; +static BOOL quietMode = NO; +static NSData *lineBreakChar; + +@implementation L4LogLog + ++ (void)initialize +{ + lineBreakChar = [@"\n" dataUsingEncoding:NSUTF8StringEncoding allowLossyConversion:YES]; +} + ++ (BOOL)internalDebuggingEnabled +{ + return internalDebugging; +} + ++ (void)setInternalDebuggingEnabled:(BOOL)enabled +{ + internalDebugging = enabled; +} + ++ (BOOL)quietModeEnabled +{ + return quietMode; +} + ++ (void)setQuietModeEnabled:(BOOL) enabled +{ + quietMode = enabled; +} + ++ (void)debug:(NSString *)message +{ + [self debug:message exception:nil]; +} + ++ (void)debug:(NSString *)message exception:(NSException *)exception +{ + if (internalDebugging && !quietMode) { + [self writeMessage:message + withPrefix:L4LogLog_PREFIX + toFile:[NSFileHandle fileHandleWithStandardOutput] + exception:exception]; + } +} + ++ (void)warn:(NSString *)message +{ + [self warn:message exception:nil]; +} + ++ (void)warn:(NSString *)message exception:(NSException *)exception +{ + if (!quietMode) { + [self writeMessage:message + withPrefix:L4LogLog_WARN_PREFIX + toFile:[NSFileHandle fileHandleWithStandardError] + exception:exception]; + } +} + ++ (void)error:(NSString *)message +{ + [self error:message exception:nil]; +} + ++ (void)error:(NSString *)message exception:(NSException *)exception +{ + if (!quietMode) { + [self writeMessage:message + withPrefix:L4LogLog_ERROR_PREFIX + toFile:[NSFileHandle fileHandleWithStandardError] + exception:exception]; + } +} + +// ### TODO *** HELP --- need a unix file expert. Should I need to flush after printf? +// it doesn't work right otherwise. +// +// Ok, I changed and just used an NSFileHandle because its easier and it just works. +// What are the performance implications, if any? +// ### TODO -- must test under heavy load and talk to performance expert. +// ++ (void)writeMessage:(NSString *)message + withPrefix:(NSString *)prefix + toFile:(NSFileHandle *)fileHandle + exception:(NSException *)exception +{ + @try { + [fileHandle writeData: + [[prefix stringByAppendingString:message] dataUsingEncoding:NSUTF8StringEncoding + allowLossyConversion:YES]]; + [fileHandle writeData:lineBreakChar]; + + if (exception) { + [fileHandle writeData: + [[prefix stringByAppendingString:exception.description] dataUsingEncoding:NSUTF8StringEncoding + allowLossyConversion:YES]]; + [fileHandle writeData:lineBreakChar]; + } + } + @catch (NSException * exception) { + // ### TODO WTF? WE'RE SCRWEDED HERE ... ABORT? EXIT? RAISE? Write Error Haiku? + } +} + +@end diff --git a/mac/TeamTalk/Libraries/Log4Cocoa/L4Logger.h b/mac/TeamTalk/Libraries/Log4Cocoa/L4Logger.h new file mode 100644 index 000000000..a39f92127 --- /dev/null +++ b/mac/TeamTalk/Libraries/Log4Cocoa/L4Logger.h @@ -0,0 +1,294 @@ +/** + * For copyright & license, see LICENSE. + */ +#import +#import "L4AppenderProtocols.h" +#import "L4LoggerProtocols.h" +#import "L4Level.h" + +@class L4AppenderAttachable, L4Level, L4LogEvent; + +/** + * This is the primary interface into the logging framework. + * The functionality of the class is broken down into the following areas: + *
+ *
Base methods
+ *
responsible for setting the level at which messages get logged.
+ *
AppenderRelatedMethods methods
+ *
responsible for adding, calling, and removing L4Appender instances.
+ *
CoreLoggingMethods methods
+ *
the methods that do the actual logging.
+ *
LogManagerCoverMethods methods
+ *
Class methods the handle the chain of L4Logger instances, and find the correct L4Logger + * instance for a given class or logger name.
+ *
+ */ +@interface L4Logger : NSObject { + L4AppenderAttachable *aai; /**< What does the actual appending for this logger.*/ +} + +/** + * The level of this logger. Nil means use parent's + */ +@property (strong) L4Level * level; + +/** + * The name of this logger. + */ +@property (readonly) NSString * name; + +/** + * The parent of this logger. + */ +@property (strong) L4Logger * parent; + +/** + * Flag for if log messages are additive. If YES, logging events are set to parent loggers. + * If NO, parents are not called. + */ +@property BOOL additivity; + +/** + * Acccessor for this loggers repository. + */ +@property (strong) id repository; + + +/** + * DON'T USE, only for use of log manager + * @param loggerName the name of this logger. + */ +- (id)initWithName:(NSString *)loggerName; + +/** + * The efective level for this logger. Events with a level below this will not be logged. + * @return the minimum level this logger will log. + */ +- (L4Level *)effectiveLevel; + +/* ********************************************************************* */ +#pragma mark AppenderRelatedMethods methods +/* ********************************************************************* */ +/** + * Appends the logging event to every appender attached to this logger. If this logger is additive, the + * message propagates up the parent chain until all of them have been called, or one is found that is + * not addative. + * If no appender could be found to append to, a warning is emited to that effect. + * @param event the logging event. + */ +- (void) callAppenders:(L4LogEvent *) event; + +/** + * Accessor for the appender attached to this logger. + */ +- (L4AppenderAttachable *) aai; + +/** + * Accessor for the appenders attached to this logger. A L4AppenderAttachableImpl can have more than one + * logger attached to it. + */ +- (NSArray *) allAppenders; + +/** + * Accessor for named appender if in list. + * @param aName the name of the appender to find. + * @return if found the appender. Otherwise, nil. + */ +- (id ) appenderWithName:(NSString *) aName; + +/** + * Adds an appender to those attached to this logger instance. + * @param appender the L4Appender to add. If nil, a new L4AppenderAttachableImpl is created and added. + */ +- (void) addAppender:(id ) appender; +/** + * Determines if a given L4Appender is attached to this logger instance. + * @param appender the L4Appender of interest. + * @return YES if it is attached, NO if it is not. + */ +- (BOOL) isAttached:(id ) appender; + +/** + * Closes all appenders attached to this logging instance. + */ +- (void) closeNestedAppenders; + +/** + * Removes all appenders attached to this logging instance. + */ +- (void) removeAllAppenders; + +/** + * Removes the given appender from those attached to this logging instance. + * @param appender to be removed. + */ +- (void) removeAppender:(id ) appender; + +/** + * Removes the appender with the given name from those attached to this logging instance. + * @param aName the name of the appender to be removed. + */ +- (void) removeAppenderWithName:(NSString *) aName; + +/* ********************************************************************* */ +#pragma mark CoreLoggingMethods methods +/* ********************************************************************* */ +/* ALL < TRACE < DEBUG < INFO < WARN < ERROR < FATAL < OFF */ + +/** + * Determines if a trace message should be logged. + * @return YES if debug messages are enabled, NO if they are not. + */ +- (BOOL)isTraceEnabled; + +/** + * Determines if a debug message should be logged. + * @return YES if debug messages are enabled, NO if they are not. + */ +- (BOOL)isDebugEnabled; + +/** + * Determines if an info message should be logged. + * @return YES if info messages are enabled, NO if they are not. + */ +- (BOOL)isInfoEnabled; + +/** + * Determines if a warn message should be logged. + * @return YES if warn messages are enabled, NO if they are not. + */ +- (BOOL)isWarnEnabled; + +/** + * Determines if an error message should be logged. + * @return YES if error messages are enabled, NO if they are not. + */ +- (BOOL)isErrorEnabled; + +/** + * Determines if a fatel message should be logged. + * @return YES if fatel messages are enabled, NO if they are not. + */ +- (BOOL)isFatalEnabled; + +/** + * Determines if aLevel should be logged. + * @param aLevel the L4Level to be checked. + * @return YES if logging is enabled for the level, NO if it is not. + */ +- (BOOL)isEnabledFor:(L4Level *) aLevel; + +/** + * Logs an error message in an NSAssert is false. + * This is considered a framework method, and probably should not be called from outside the framework. + * + * @param lineNumber the line number in the source file where the assertion is. + * @param fileName the name of the source file containing the assertion. + * @param methodName the name of the method containing the assertion. + * @param anAssertion the NSAssert to be tested. + * @param aMessage the message to be logged if the assertian is false. + */ +- (void)lineNumber:(int) lineNumber + fileName:(char *) fileName + methodName:(char *) methodName + assert:(BOOL) anAssertion + log:(NSString *) aMessage; + + +/** + * Logs a message with an excpetion at a level of fatal. + * This is considered a framework method, and probably should not be called from outside the framework. + * + * @param lineNumber the line number in the source file where the log statement is. + * @param fileName the name of the source file containing the log statement. + * @param methodName the name of the method containing the log statement. + * @param aMessage the message to be logged. + * @param aLevel the L4Level for this log message. + * @param e the exception to be logged. + */ +- (void)lineNumber:(int) lineNumber + fileName:(char *) fileName + methodName:(char *) methodName + message:(id) aMessage + level:(L4Level *) aLevel + exception:(NSException *) e; + +/* This is the designated logging method that the others invoke. */ +/** + * Forwards the L4LoggingEvent to all attached appenders; the other methods in this class create + * an L4LoggingEvent and call this method. + * This is considered a framework method, and probably should not be called from outside the framework. + * + * @param event the event to be logged. + */ +- (void) forcedLog:(L4LogEvent *) event; + + +#pragma mark - Logger management methods + +/** + * Accessor for the logger repository. + * @return the logger repository. + */ ++ (id )loggerRepository; + +/** + * Accessor for the root logger. + * @return the root logger. + */ ++ (instancetype)rootLogger; + +/** + * Accesses the logger for the given class. + * @param aClass the class we want the logger for. + * @return the logger for the class + */ ++ (instancetype)loggerForClass:(Class) aClass; + +/** + * Accesses the logger for the given name. + * @param aName the name of the logger we want. + * @return the logger for the class + */ ++ (instancetype)loggerForName:(NSString *) aName; + +/** + * Accesses the logger for the given name. + * @param aName the name of the logger we want. + * @param aFactory the factory to use to create the logger if it does not yet exist. + * @return the logger for the class + */ ++ (instancetype)loggerForName:(NSString *) aName factory:(id ) aFactory; + +/** + * The array of loggers. + * @return the current loggers. + */ ++ (NSArray *)currentLoggers; + +/** + * Shut down logging. + */ ++ (void)shutdown; + +/** + * Reset the logging configuration. + */ ++ (void)resetConfiguration; + +@end + +/** + * This class is a dummy class; its only purpose is to facilitate logging from + * methods. It serves as the 'self' argument. Log level for methods can be + * adjusted with this, but keep in mind that it applies to all function logging. + */ +@interface L4FunctionLogger :NSObject +{ + L4FunctionLogger *instance; /**< the singleon instance of this class. */ +} +/** + * Accessor for the singleton instance. + */ ++ (L4FunctionLogger *)instance; +@end diff --git a/mac/TeamTalk/Libraries/Log4Cocoa/L4Logger.m b/mac/TeamTalk/Libraries/Log4Cocoa/L4Logger.m new file mode 100644 index 000000000..509879021 --- /dev/null +++ b/mac/TeamTalk/Libraries/Log4Cocoa/L4Logger.m @@ -0,0 +1,281 @@ +/** + * For copyright & license, see LICENSE. + */ + +#import "L4Logger.h" +#import "L4AppenderAttachable.h" +#import "L4Level.h" +#import "L4LoggerStore.h" +#import "L4LogEvent.h" +#import "L4LogLog.h" +#import "L4RootLogger.h" + + +static L4LoggerStore *_loggerRepository = nil; + +@implementation L4Logger + ++ (void) initialize +{ + id rootLogger = [[L4RootLogger alloc] initWithLevel:[L4Level debug]]; + _loggerRepository = [[L4LoggerStore alloc] initWithRoot:rootLogger]; + + // Initialize Event timmer + [L4LogEvent startTime]; +} + +- (id)init +{ + return nil; // never use this constructor +} + +- (id)initWithName:(NSString *) aName +{ + self = [super init]; + + if (self) { + _name = [aName copy]; + _additivity = YES; + } + + return self; +} + +- (L4Level *) effectiveLevel +{ + @synchronized(self) { + for (L4Logger *logger = self; logger; logger = logger.parent) { + if (logger.level) + return logger.level; + } + } + + [L4LogLog error:@"Root Logger Not Found!"]; + return nil; +} + + +#pragma mark - AppenderRelatedMethods methods + +- (void)callAppenders:(L4LogEvent *) event +{ + int writes = 0; + + @synchronized(self) { + for (L4Logger *logger = self; logger; logger = logger.parent) { + if (logger.aai) + writes += [logger.aai appendLoopOnAppenders:event]; + + if (!logger.additivity) + break; + } + } + + if (writes == 0) + [self.repository emitNoAppenderWarning:self]; +} + +- (L4AppenderAttachable *) aai +{ + return aai; +} + +- (NSArray *) allAppenders +{ + return [aai allAppenders]; +} + +- (id ) appenderWithName:(NSString *) aName +{ + return [aai appenderWithName:aName]; +} + +- (void) addAppender:(id ) appender +{ + @synchronized(self) { + if (!aai) + aai = [[L4AppenderAttachable alloc] init]; + + [aai addAppender:appender]; + } +} + +- (BOOL) isAttached:(id ) appender +{ + BOOL isAttached = NO; + @synchronized(self) { + if((appender != nil) && (aai != nil)) { + isAttached = [aai isAttached:appender]; + } + } + return isAttached; +} + +- (void) closeNestedAppenders +{ + @synchronized(self) { + NSEnumerator *enumerator = [[self allAppenders] objectEnumerator]; + id anObject; + + while ((anObject = (id )[enumerator nextObject])) { + [anObject close]; + } + } +} + +- (void) removeAllAppenders +{ + @synchronized(self) { + [aai removeAllAppenders]; + aai = nil; + } +} + +- (void) removeAppender:(id ) appender +{ + [aai removeAppender:appender]; +} + +- (void) removeAppenderWithName:(NSString *) aName +{ + [aai removeAppenderWithName:aName]; +} + + +#pragma mark - CoreLoggingMethods methods + +// ALL < TRACE < DEBUG < INFO < WARN < ERROR < FATAL < OFF + +- (BOOL) isTraceEnabled +{ + return [self isEnabledFor:[L4Level trace]]; +} +- (BOOL) isDebugEnabled +{ + return [self isEnabledFor:[L4Level debug]]; +} +- (BOOL) isInfoEnabled +{ + return [self isEnabledFor:[L4Level info]]; +} +- (BOOL) isWarnEnabled +{ + return [self isEnabledFor:[L4Level warn]]; +} +- (BOOL) isErrorEnabled +{ + return [self isEnabledFor:[L4Level error]]; +} +- (BOOL) isFatalEnabled +{ + return [self isEnabledFor:[L4Level fatal]]; +} + +- (BOOL) isEnabledFor:(L4Level *) aLevel +{ + if([self.repository isDisabled:[aLevel intValue]]) { + return NO; + } + return [aLevel isGreaterOrEqual:[self effectiveLevel]]; +} + +- (void) lineNumber:(int) lineNumber + fileName:(char *) fileName + methodName:(char *) methodName + assert:(BOOL) anAssertion + log:(NSString *) aMessage +{ + if( !anAssertion ) { + [self lineNumber:lineNumber + fileName:fileName + methodName:methodName + message:aMessage + level:[L4Level error] + exception:nil]; + } +} + +- (void) lineNumber:(int) lineNumber + fileName:(char *) fileName + methodName:(char *) methodName + message:(id) aMessage + level:(L4Level *) aLevel + exception:(NSException *) e +{ + if ([self.repository isDisabled:[aLevel intValue]]) { + return; + } + + if([aLevel isGreaterOrEqual:[self effectiveLevel]]) { + [self forcedLog:[L4LogEvent logger:self + level:aLevel + lineNumber:lineNumber + fileName:fileName + methodName:methodName + message:aMessage + exception:e]]; + } +} + +- (void) forcedLog:(L4LogEvent *) event +{ + [self callAppenders:event]; +} + + +#pragma mark - Logger management methods + ++ (id ) loggerRepository +{ + return _loggerRepository; +} + ++ (instancetype)rootLogger +{ + return [_loggerRepository rootLogger]; +} + ++ (instancetype)loggerForClass:(Class) aClass +{ + return [_loggerRepository loggerForClass:aClass]; +} + ++ (instancetype)loggerForName:(NSString *) aName +{ + return [_loggerRepository loggerForName:aName]; +} + ++ (instancetype)loggerForName:(NSString *) aName factory:(id ) aFactory +{ + return [_loggerRepository loggerForName:aName factory:aFactory]; +} + ++ (NSArray *) currentLoggers +{ + return [_loggerRepository currentLoggers]; +} + ++ (void) shutdown +{ + return [_loggerRepository shutdown]; +} + ++ (void) resetConfiguration +{ + return [_loggerRepository resetConfiguration]; +} + +@end + + +@implementation L4FunctionLogger +static L4FunctionLogger *instance; ++ (L4FunctionLogger *)instance +{ + if (instance == nil) { + instance = [[L4FunctionLogger alloc] init]; + } + return instance; +} + +@end diff --git a/mac/TeamTalk/Libraries/Log4Cocoa/L4LoggerNameMatchFilter.h b/mac/TeamTalk/Libraries/Log4Cocoa/L4LoggerNameMatchFilter.h new file mode 100644 index 000000000..ef334d54a --- /dev/null +++ b/mac/TeamTalk/Libraries/Log4Cocoa/L4LoggerNameMatchFilter.h @@ -0,0 +1,52 @@ +#import +#import "L4Filter.h" + + +/* + * This is a very simple filter based on string matching of the logger name. + * + * The filter admits two options StringToMatch and AcceptOnMatch. + * + * If there is a match between the value of the StringToMatch option and the logger name of the L4LoggingEvent, then the + * decide(L4LoggingEvent) method returns L4FilterAccept if the AcceptOnMatch option value is YES/TRUE, if it is + * NO/FALSE, then L4FilterDeny is returned. If there is no match, L4FilterNeutral is returned. + */ +@interface L4LoggerNameMatchFilter : L4Filter { + BOOL acceptOnMatch; /**< YES to allow logging on a match, NO to prevent logging on a match. */ + NSString *stringToMatch; /**< The string that the logging events logger name must contain to match this filter. */ +} + +/** + * Initializes an instance from properties. The properties supported are: + * - AcceptOnMatch: a string that get's converted to a BOOL. YES/NO work well. See the documentation for [NSString + * boolValue] for other options. + * - StringToMatch: the string that the logging events logger name must contain to match this filter. + * + * @param initProperties the proterties to use. + * @throw L4PropertyMissingException if the StringToMatch property is missing. + */ +- (id) initWithProperties:(L4Properties *)initProperties; + +/** + * Initialze a new instance with the given values. + * This is the default initializer, as the instance should have these two values set. + * + * @param shouldAccept YES to allow logging on a match of levelToMatch, NO to prevent logging on a match. + * @param aString the string that the logging events logger name must contain to match this filter. + * @throw NSInvalidArgumentException if aString is nil. + */ +- (id) initWithAcceptOnMatch:(BOOL)shouldAccept stringToMatch:(NSString *)aString; + + +/** + * Accessor for the acceptOnMatch property. + */ +- (BOOL) acceptOnMatch; + +/** + * Accessor for the stringToMatch property. + */ +- (NSString *) stringToMatch; + +@end +// For copyright & license, see LICENSE. diff --git a/mac/TeamTalk/Libraries/Log4Cocoa/L4LoggerNameMatchFilter.m b/mac/TeamTalk/Libraries/Log4Cocoa/L4LoggerNameMatchFilter.m new file mode 100644 index 000000000..78e367099 --- /dev/null +++ b/mac/TeamTalk/Libraries/Log4Cocoa/L4LoggerNameMatchFilter.m @@ -0,0 +1,67 @@ +/** + * For copyright & license, see LICENSE. + */ + +#import "L4LoggerNameMatchFilter.h" +#import "L4LogEvent.h" +#import "L4Properties.h" +#import "L4Logger.h" + +@implementation L4LoggerNameMatchFilter + +- (id) initWithAcceptOnMatch:(BOOL)shouldAccept stringToMatch:(NSString *)aString +{ + self = [super init]; + if (self) { + acceptOnMatch = shouldAccept; + if (aString == nil || [aString length] == 0) { + self = nil; + [NSException raise:NSInvalidArgumentException format:@"aString is not allowed to be nil."]; + } else { + stringToMatch = aString; + } + } + return self; +} + +-(id) initWithProperties: (L4Properties *) initProperties +{ + self = [super initWithProperties: initProperties]; + if (self != nil) { + NSString *acceptIfMatched = [initProperties stringForKey:@"AcceptOnMatch"]; + acceptOnMatch = YES; + + if (acceptIfMatched) { + acceptOnMatch = [acceptIfMatched boolValue]; + } + + stringToMatch = [initProperties stringForKey:@"StringToMatch"]; + if (stringToMatch == nil) { + [NSException raise:L4PropertyMissingException format: @"StringToMatch is a required property."]; + } + } + return self; +} + + +-(BOOL) acceptOnMatch +{ + return acceptOnMatch; +} + +-(NSString *) stringToMatch +{ + return stringToMatch; +} + +-(L4FilterResult) decide:(L4LogEvent *) logEvent +{ + L4FilterResult filterResult = L4FilterNeutral; + if ([[logEvent logger] name] != nil && [[[logEvent logger] name] rangeOfString:stringToMatch].location != NSNotFound) { + filterResult = (acceptOnMatch ? L4FilterAccept : L4FilterDeny); + } + + return filterResult; +} + +@end diff --git a/mac/TeamTalk/Libraries/Log4Cocoa/L4LoggerProtocols.h b/mac/TeamTalk/Libraries/Log4Cocoa/L4LoggerProtocols.h new file mode 100644 index 000000000..16231f893 --- /dev/null +++ b/mac/TeamTalk/Libraries/Log4Cocoa/L4LoggerProtocols.h @@ -0,0 +1,90 @@ +#import + +@class L4Logger, L4Level, L4RendererMap; + +/** + * A factory to be used to instantiate L4Logging classes. + */ +@protocol L4LoggerFactory + +/** + * Creates a new logger with the given name. + * @param aName the name to use for the new logger. + * @return the newly created logger. + */ +- (L4Logger *)newLoggerInstance:(NSString *)aName; + +@end + +/** + * A repository for logger instances in the framework. + */ +@protocol L4LoggerRepository + +@property L4Level *threshold; /**< The minimum level to log.*/ + +/** + * Is the repository disabled for a given level? The answer depends on the repository threshold and the + * level parameter. + */ +- (BOOL) isDisabled:(int) aLevel; + +/** + * Mutator for the threshold property. + * @param aLevelName the name of a L4LEvel to use as the new threshold level. + */ +- (void) setThresholdByName:(NSString *)aLevelName; + +/** + * Accessor for the root logger. + * @returns the root logger for the system. + */ +- (L4Logger *)rootLogger; + +/** + * Returns the logger for a particular class. + * @param aClass the class who's logger is being requested. + * @return the logger for the given class, creating it if need be. + */ +- (L4Logger *)loggerForClass:(Class) aClass; + +/** + * Returns the logger for a particular class. + * @param aName the classes name for the logger being requested. + * @return the logger for the given class, creating it if need be. + */ +- (L4Logger *)loggerForName:(NSString *)aName; + +/** + * Returns the logger for a particular class. + * @param aName the classes name for the logger being requested. + * @param aFactory the factory to use to create the logger if it does not already exist. + * @return the logger for the given class, creating it if need be. + */ +- (L4Logger *)loggerForName:(NSString *)aName factory:(id ) aFactory; + +/** + * Returns the collection of all loggers. + * @return the loggers configured in the system. + */ +- (NSArray *)currentLoggers; + +/** + * Tells the logging system not to emi warning messages when an appender does not exist. + * @param aLogger the logger to ignore. + */ +- (void) emitNoAppenderWarning:(L4Logger *)aLogger; + +/** + * Resets the configuration of the logging system. + */ +- (void) resetConfiguration; + +/** + * Shuts down the logging system. + */ +- (void) shutdown; + +@end + +// For copyright & license, see LICENSE. diff --git a/mac/TeamTalk/Libraries/Log4Cocoa/L4LoggerStore.h b/mac/TeamTalk/Libraries/Log4Cocoa/L4LoggerStore.h new file mode 100644 index 000000000..ddb34ef0e --- /dev/null +++ b/mac/TeamTalk/Libraries/Log4Cocoa/L4LoggerStore.h @@ -0,0 +1,81 @@ +// For copyright & license, see LICENSE. +#import +#import "L4LoggerProtocols.h" + +@class L4Level, L4Logger; + +/** + * Manages all logger instances. + * TODO Add support the L4RendererSupport protocol, called from the L4LoggingEvent:renderedMessage method. + */ +@interface L4LoggerStore : NSObject + +@property (strong) L4Level *threshold; /**< The minimum level to log.*/ + +/** + * the following are L4LoggerRepository methods + * @param rootLogger the root logger. + */ +- (id)initWithRoot:(id) rootLogger; + +/** + * Is the repository disabled for a given level? The answer depends + * on the repository threshold and the parameter. + * See also setThreshold: method. + * @param aLevel the level to check. + * @return YES if logging is disabled for the specified level; NO if it is not. + */ +- (BOOL)isDisabled:(int) aLevel; + +/** + * Sets the threshold to the level with a name that matches the parameter. + * @param aLevelName the name of the level to set the threshold to. + */ +- (void)setThresholdByName:(NSString *)aLevelName; + +/** + * Accessor for the root logger. + * @return the root logger. + */ +- (L4Logger *)rootLogger; + +/** + * Gets a logger for the class object, if it doesn't exist already + * it is created by composing the pseudo-fqcn and then calling + * loggerForName:factory: which does the hard work. + */ +- (L4Logger *)loggerForClass:(Class) aClass; + +/** a wrapper for loggerForName:factory: with self as the factory */ +- (L4Logger *)loggerForName:(NSString *) aName; + +/** + * returns a logger with name or creates it & inserts it into the + * repository and hooks up all pointers to pre-existing parents + * children efficiently (thanks to the Log4J folks algorithm). + */ +- (L4Logger *)loggerForName:(NSString *) aName factory:(id ) aFactory; + +/** + * Accessor for the collection of loggers. + * @return the array of loggers. + */ +- (NSArray *)currentLoggers; + +/** + * Warn that aLogger has no appenders configured; only if no warning has already + * been given. + * @param aLogger the logger to warn about. + */ +- (void)emitNoAppenderWarning:(L4Logger *) aLogger; + +/** + * Resets the configuration of the log store. + */ +- (void)resetConfiguration; +/** + Shut down logging. + */ +- (void)shutdown; + +@end diff --git a/mac/TeamTalk/Libraries/Log4Cocoa/L4LoggerStore.m b/mac/TeamTalk/Libraries/Log4Cocoa/L4LoggerStore.m new file mode 100644 index 000000000..e2a02b861 --- /dev/null +++ b/mac/TeamTalk/Libraries/Log4Cocoa/L4LoggerStore.m @@ -0,0 +1,278 @@ +/** + * For copyright & license, see LICENSE. + */ + +#import "L4LoggerStore.h" +//#import +#import "L4Logger.h" +#import "L4Level.h" +#import "L4LogLog.h" + +/** + * Private methods. + */ +@interface L4LoggerStore () +/** + * Generates a psuedo-fully qualified class name for the class using java-esque dot "." notation seperating classes from + * their parents. For example L4Logger results in the string - NSObject.L4Logger + * NSObject.SubClass1.SubClass2.LeafClass is the format + * @param aClass the class of interest. + * @return the FQDN for the class of interest. + */ +- (NSString *) pseudoFqcnForClass:(Class) aClass; +/** + * Update parents, starts at the end of the pseudo-fqcn string and looks for the first matching logger and sets that as + * the parent. Each element in the pseudo-fqcn key path that doesn't exist is created as an NSMutableArray. + * In order to collect all the child loggers underneath that point in the hierarchy. This is important when a node in + * the middle of the tree is created. All children of that node are set to have that new logger as their parent. + * @param aLogger the logger who's parents we want to update. + */ +- (void) updateParentsOfLogger:(L4Logger *) aLogger; + +/** + * If the child already has a parent lower than this new logger leave it alone. If the parent is above this new logger, + * then insert itself inbetween. + * @param node the children to update. + * @param parent the new parent of the children. + */ +- (void) updateChildren:(NSMutableArray *) node withParent:(L4Logger *) parent; +@end + + +@implementation L4LoggerStore { + L4Logger * _root; /**< The root logger.*/ + NSMutableDictionary * _repository; /**< The collection of loggers by id.*/ + NSMutableArray * _loggers; /**< The collection of loggers.*/ + int _thresholdInt; /**< The minimum level as an int to log.*/ + + BOOL _emittedNoAppenderWarning; /**< Tracks if a warning should be created if there are no appenders configured.*/ + BOOL _emittedNoResourceBundleWarning;/**< Tracks if a warning should be created if there is no resource bundle.*/ +} + +- (id) init +{ + return nil; // don't use this method +} + +- (id) initWithRoot:(id) rootLogger +{ + self = [super init]; + if (self) { + _root = rootLogger; + + _repository = [NSMutableDictionary dictionary]; + _loggers = [NSMutableArray arrayWithObject:_root]; + + _root.repository = self; + self.threshold = [L4Level all]; + + _emittedNoAppenderWarning = NO; + _emittedNoResourceBundleWarning = NO; + } + return self; +} + + +- (BOOL) isDisabled:(int) aLevel +{ + return _thresholdInt > aLevel; +} + +- (void) setThresholdByName:(NSString *) aLevelName +{ + self.threshold = [L4Level levelWithName:aLevelName defaultLevel:self.threshold]; +} + +- (L4Logger *) rootLogger +{ + return _root; +} + +- (L4Logger *) loggerForClass:(Class) aClass +{ + if (!aClass) + return nil; + + id logger; + @synchronized(self) { + logger = _repository[NSStringFromClass(aClass)]; + + if (!logger) { + NSString *pseudoFqcn = [self pseudoFqcnForClass:aClass]; + logger = [self loggerForName:pseudoFqcn factory:self]; + _repository[NSStringFromClass(aClass)] = logger; + } + } + + return logger; +} + +- (L4Logger *) loggerForName:(NSString *) aName +{ + return [self loggerForName:aName factory:self]; +} + +- (L4Logger *) loggerForName:(NSString *) aName factory:(id ) aFactory +{ + L4Logger *theLogger = nil; + id theNode; + + @synchronized(self) { + theNode = _repository[aName]; + + if( theNode == nil ) { + // + // if the node is nil, then its a new logger & therefore + // a new leaf node, since no placeholder node was found. + // + theLogger = [aFactory newLoggerInstance:aName]; + theLogger.repository = self; + _repository[aName] = theLogger; + [self updateParentsOfLogger:theLogger]; + [_loggers addObject:theLogger]; + + } else if([theNode isKindOfClass:[L4Logger class]]) { + theLogger = (L4Logger *) theNode; + } else if([theNode isKindOfClass:[NSMutableArray class]]) { + // + // this node is a placeholder middle node, since its an NSMutableArray. It contains children and + // a parent, so when we insert this logger, we need to update all of the children to point to this node + // and to point to their parent. + // + theLogger = [aFactory newLoggerInstance:aName]; + theLogger.repository = self; + _repository[aName] = theLogger; + [self updateChildren:theNode withParent:theLogger ]; + [self updateParentsOfLogger:theLogger]; + [_loggers addObject:theLogger]; + + } else { + // We should hopefully never end up here. ### TODO ??? - Internal Consistency Error + // + NSString *one = @"Logger not found & internal repository in returned unexpected node type:"; + NSString *twoDo = @" ### TODO:Should we raise here, because we shouldn't be here."; + [L4LogLog error: + [[one stringByAppendingString: + NSStringFromClass([theNode class])] stringByAppendingString:twoDo]]; + } + } + + return (L4Logger *) theLogger; +} + +- (NSArray *)currentLoggers +{ + @synchronized(self) { + return [_loggers copy]; + } +} + +- (void) emitNoAppenderWarning:(L4Logger *) aLogger +{ + if (!_emittedNoAppenderWarning ) { + [L4LogLog warn:[NSString stringWithFormat:@"No appenders could be found for logger(%@).", [aLogger name]]]; + [L4LogLog warn:@"Please initialize the Log4Cocoa system properly."]; + + _emittedNoAppenderWarning = YES; + } +} + +- (void) resetConfiguration +{ + @synchronized(self) { + _root.level = [L4Level debug]; + self.threshold = [L4Level all]; + + [self shutdown]; + + for (L4Logger *logger in _loggers) { + logger.level = nil; + logger.additivity = YES; + } + } +} + +- (void) shutdown +{ + @synchronized(self) { + [_root closeNestedAppenders]; + + for (L4Logger *logger in _loggers) + [logger closeNestedAppenders]; + + [_root removeAllAppenders]; + + for (L4Logger *logger in _loggers) + [logger removeAllAppenders]; + } +} + + +#pragma mark - L4LoggerFactoryCategory methods + +- (L4Logger *) newLoggerInstance:(NSString *) aName +{ + return [[L4Logger alloc] initWithName:aName]; +} + + +#pragma mark - Private methods + +- (NSString *) pseudoFqcnForClass:(Class) aClass +{ + NSMutableString *pseudoFqcn = [[NSMutableString alloc] init]; + Class theClass = aClass; + + [pseudoFqcn insertString:NSStringFromClass(theClass) atIndex:0]; + + for( theClass = [theClass superclass]; theClass != nil; theClass = [theClass superclass] ) { + [pseudoFqcn insertString:@"." atIndex:0]; + [pseudoFqcn insertString:NSStringFromClass(theClass) atIndex:0]; + } + return pseudoFqcn; +} + +- (void) updateParentsOfLogger:(L4Logger *) aLogger +{ + L4Logger *parent = _root; + + // the trick here is to build up the key paths in reverse order not including + // the pseudo-fqcn (i.e the last node), to search for already existing parents + NSArray *keys = [aLogger.name componentsSeparatedByString:@"."]; + for (int i = keys.count - 1; i > 0; --i) { + NSString *keyPath = [[keys subarrayWithRange:NSMakeRange(0, i)] componentsJoinedByString:@"."]; + id node = _repository[keyPath]; + + if (!node) { + // didn't find a parent or a placeholder, create a placeholder + // node, i.e. a MutalbeArray, and add this logger as a child + // + _repository[keyPath] = [NSMutableArray arrayWithObject:aLogger]; + + } else if ([node isKindOfClass:[L4Logger class]]) { + parent = node; + break; + + } else if ([node isKindOfClass:[NSMutableArray class]]) { + [node addObject:aLogger]; // found a place holder node, add this logger as a child + } + } + aLogger.parent = parent; // found a parent, set it for this logger +} + +- (void) updateChildren:(NSArray *)node withParent:(L4Logger *)newLogger +{ + for (L4Logger *child in node) { + // If the child's parent's name starts with the name of the new logger then its a child of the new logger leave the child alone, we'll get + // to the child's parent in this list. Otherwise the parent is higher & insert the new logger. All children that go through this same + // middle node, that don't have an already lower parent, should all point to the same higher parent. If not, something is wrong. + // + if (![child.parent.name hasPrefix:newLogger.name] ) { + newLogger.parent = child.parent; + child.parent = newLogger; + } + } +} + +@end + diff --git a/mac/TeamTalk/Libraries/Log4Cocoa/L4Logging.h b/mac/TeamTalk/Libraries/Log4Cocoa/L4Logging.h new file mode 100644 index 000000000..4888e58d8 --- /dev/null +++ b/mac/TeamTalk/Libraries/Log4Cocoa/L4Logging.h @@ -0,0 +1,78 @@ +/** + * For copyright & license, see LICENSE. + */ +#import +#import "Log4CocoaDefines.h" +#import "L4Level.h" + +/** + * LOGGING MACROS: These macros are convience macros that easily allow the capturing of + * line number, source file, and method name information without interupting the flow of + * your source code. + * + * The base macros are not meant to be used directly; they are there for the other + * to use as they define the basic function call. + */ + +LOG4COCOA_EXTERN void log4Log(id object, int line, const char *file, const char *method, SEL sel, L4Level *level, BOOL isAssertion, + BOOL assertion, id exception, id message, ...); + + +#pragma mark - Base macros used for logging from objects + +#define L4_LOG(type, e) self, __LINE__, __FILE__, __PRETTY_FUNCTION__, @selector(lineNumber:fileName:methodName:message:level:exception:), type, NO, YES, e +#define L4_ASSERTION(assertion) self, __LINE__, __FILE__, __PRETTY_FUNCTION__, @selector(lineNumber:fileName:methodName:assert:log:), [L4Level error], YES, assertion, nil + + +#pragma mark - Base macros used for logging from C functions + +#define L4C_LOG(type, e) [L4FunctionLogger instance], __LINE__, __FILE__, __PRETTY_FUNCTION__, @selector(lineNumber:fileName:methodName:message:level:exception:), type, NO, YES, e +#define L4C_ASSERTION(assertion) [L4FunctionLogger instance], __LINE__, __FILE__, __PRETTY_FUNCTION__, @selector(lineNumber:fileName:methodName:assert:log:), [L4Level error], YES, assertion, nil + + +#pragma mark - Macros that log from objects + +#define log4Trace(message, ...) if([[self l4Logger] isDebugEnabled]){ log4Log(L4_LOG([L4Level trace], nil), message, ##__VA_ARGS__);} +#define log4Debug(message, ...) if([[self l4Logger] isDebugEnabled]){ log4Log(L4_LOG([L4Level debug], nil), message, ##__VA_ARGS__);} +#define log4Info(message, ...) if([[self l4Logger] isInfoEnabled]){ log4Log(L4_LOG([L4Level info], nil), message, ##__VA_ARGS__);} +#define log4Warn(message, ...) log4Log(L4_LOG([L4Level warn], nil), message, ##__VA_ARGS__) +#define log4Error(message, ...) log4Log(L4_LOG([L4Level error], nil), message, ##__VA_ARGS__) +#define log4Fatal(message, ...) log4Log(L4_LOG([L4Level fatal], nil), message, ##__VA_ARGS__) + + +#pragma mark - Macros that log from C functions + +#define log4CDebug(message, ...) if([[[L4FunctionLogger instance] l4Logger] isDebugEnabled]){ log4Log(L4C_LOG([L4Level debug], nil), message, ##__VA_ARGS__);} +#define log4CInfo(message, ...) if([[[L4FunctionLogger instance] l4Logger] isInfoEnabled]){ log4Log(L4C_LOG([L4Level info], nil), message, ##__VA_ARGS__);} +#define log4CWarn(message, ...) log4Log(L4C_LOG([L4Level warn], nil), message, ##__VA_ARGS__) +#define log4CError(message, ...) log4Log(L4C_LOG([L4Level error], nil), message, ##__VA_ARGS__) +#define log4CFatal(message, ...) log4Log(L4C_LOG([L4Level fatal], nil), message, ##__VA_ARGS__) + + +#pragma mark - Macros that log with an exception from objects + +#define log4DebugWithException(message, e, ...) if([[self l4Logger] isDebugEnabled]){ log4Log(L4_LOG([L4Level debug], e), message, ##__VA_ARGS__);} +#define log4InfoWithException(message, e, ...) if([[self l4Logger] isInfoEnabled]){ log4Log(L4_LOG([L4Level info], e), message, ##__VA_ARGS__);} +#define log4WarnWithException(message, e, ...) log4Log(L4_LOG([L4Level warn], e), message, ##__VA_ARGS__) +#define log4ErrorWithException(message, e, ...) log4Log(L4_LOG([L4Level error], e), message, ##__VA_ARGS__) +#define log4FatalWithException(message, e, ...) log4Log(L4_LOG([L4Level fatal], e), message, ##__VA_ARGS__) + + +#pragma mark Macros that log with an exception from C functions + +#define log4CDebugWithException(message, e, ...) if([[[L4FunctionLogger instance] l4Logger] isDebugEnabled]){ log4Log(L4C_LOG([L4Level debug], e), message, ##__VA_ARGS__);} +#define log4CInfoWithException(message, e, ...) if([[[L4FunctionLogger instance] l4Logger] isInfoEnabled]){ log4Log(L4C_LOG([L4Level info], e), message, ##__VA_ARGS__);} +#define log4CWarnWithException(message, e, ...) log4Log(L4C_LOG([L4Level warn], e), message, ##__VA_ARGS__) +#define log4CErrorWithException(message, e, ...) log4Log(L4C_LOG([L4Level error], e), message, ##__VA_ARGS__) +#define log4CFatalWithException(message, e, ...) log4Log(L4C_LOG([L4Level fatal], e), message, ##__VA_ARGS__) + + +#pragma mark - Macro that log when an assertion is false from objects + +#define log4Assert(assertion, message, ...) log4Log(L4_ASSERTION(assertion), message, ##__VA_ARGS__) + + +#pragma mark - Macro that log when an assertion is false from C functions + +#define log4CAssert(assertion, message, ...) log4Log(L4C_ASSERTION(assertion), message, ##__VA_ARGS__) + diff --git a/mac/TeamTalk/Libraries/Log4Cocoa/L4Logging.m b/mac/TeamTalk/Libraries/Log4Cocoa/L4Logging.m new file mode 100644 index 000000000..55459b4a5 --- /dev/null +++ b/mac/TeamTalk/Libraries/Log4Cocoa/L4Logging.m @@ -0,0 +1,27 @@ +/** + * For copyright & license, see LICENSE. + */ + +#import +#import "L4Logging.h" +#import "NSObject+Log4Cocoa.h" + +void log4Log(id object, int line, const char *file, const char *method, SEL sel, L4Level *level, BOOL isAssertion, BOOL assertion, id exception, id message, ...) +{ + NSString *combinedMessage; + if ([message isKindOfClass:[NSString class]] ) { + va_list args; + va_start(args, message); + combinedMessage = [[NSString alloc] initWithFormat:message arguments:args]; + va_end(args); + } else { + combinedMessage = message; + } + + if (isAssertion) { + objc_msgSend([object l4Logger], sel, line, file, method, assertion, combinedMessage); + } else { + objc_msgSend([object l4Logger], sel, line, file, method, combinedMessage, level, exception); + } +} + diff --git a/mac/TeamTalk/Libraries/Log4Cocoa/L4PatternLayout.h b/mac/TeamTalk/Libraries/Log4Cocoa/L4PatternLayout.h new file mode 100644 index 000000000..bc6335fa5 --- /dev/null +++ b/mac/TeamTalk/Libraries/Log4Cocoa/L4PatternLayout.h @@ -0,0 +1,337 @@ +#import +#import "L4Layout.h" + +/** + *Defines the default conversion pattern for L4PatternLayout objects created with the init method + */ +extern NSString* const L4PatternLayoutDefaultConversionPattern; + +/** + * Defines the name for invalid format specifier exceptions + */ +extern NSString* const L4InvalidSpecifierException; + +/** + *Defines the name for the no conversion pattern exception + * This exception is thrown if you try to use an L4PatternLayout before setting its conversion pattern + */ +extern NSString* const L4NoConversionPatternException; + +/** + * Defines the name for the invalid brace clause exception + * Some of the format specifiers can be followed by content surrounded by braces ({}). When this brace clause is invalid for + * any reason, the L4InvalidBraceClauseException is thrown + */ +extern NSString* const L4InvalidBraceClauseException; + +/** + * An NSCharacterSet that contains the default format specifier characters + */ +#define L4PatternLayoutDefaultSpecifiers [NSCharacterSet characterSetWithCharactersInString:@"CdFlLmMnprt%"] + +/** + * An NSCharacterSet that contains the subset of characters from L4PatternLayoutDefaultSpecifiers that can have a brace clause + * after the character + */ +#define L4PatternLayoutTrailingBracesSpecifiers [NSCharacterSet characterSetWithCharactersInString:@"Cd"] + +@class L4LogEvent; +@class L4PatternParser; + +/** + * A layout that uses a conversion pattern to format logging messages + * + * A flexible layout configurable with pattern string. + * The goal of this class is to format a LoggingEvent and return the results as a String. The results + * depend on the conversion pattern. + * + * The conversion pattern is closely related to the conversion pattern of the printf function in C. A conversion pattern is + * composed of literal text and format control expressions called format specifiers. + * You are free to insert any literal text within the conversion pattern. + * + * Each conversion specifier starts with a percent sign (%) and is followed by optional format modifiers and a specifier + * character. The specifier character specifies the type of data, e.g. priority, date. The format modifiers control such things + * as field width, padding, left and right justification. The following is a simple example. + * + * Let the conversion pattern be "%-5p :%m%n" and assume that the Log4Cocoa environment was set to use an L4PatternLayout. Then the + * statements + *
+ * log4Debug("Message 1");
+ * log4Warn("Message 2");
+ * 
+ * would yield the output + *
+ * DEBUG :Message 1
+ * WARN  :Message 2
+ * 
+ * + * Note that there is no explicit separator between text and conversion specifiers. The pattern parser knows when it has reached + * the end of a conversion specifier when it reads a specifier character. In the example, above the conversion specifier + * %-5p means the priority of the logging event should be left justified to a width of five characters. + * + * The recognized conversion characters are: + + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + *
Conversion CharacterEffect
CUsed to output the fully qualified class name of the logger issuing the logging request. This conversion specifier + * can be optionally followed by precision specifier, thatis a decimal constant in braces. + * + * If a precision specifier is given, then only the corresponding number of right most components of the logger name will be + * printed. By default the logger name is output in fully qualified form. + * + * For example, for the class name "NSObject.MyClass.SubClass.SomeClass", the pattern %C{1} will output "SomeClass". + *
dUsed to output the date of the logging event. The date conversion specifier may be followed by a date format specifier + * enclosed between braces. For example, %d{%H:%M:%S}. If no date format specifier is given, then an international format of + * "%Y-%m-%d %H:%M:%S %z" is used. + * + * The date format specifier admits the same syntax as the calendar format string in NSCalendarDate's + * descriptionWithCalendarFormat:method. + *
FUsed to output the file name where the logging request was issued.
lUsed to output location information of the caller which generated the logging event. + * + * The location information consists of the fully qualified name of the calling logger, the method the log request originated in, + * followed by the log request's source file name and line number between parentheses. + *
LUsed to output the line number from where the logging request was issued.
mUsed to output the application supplied message associated with the logging event.
MUsed to output the method name where the logging request was issued.
nOutputs the line separator character, \\n.
pUsed to output the priority (level) of the logging event.
rUsed to output the number of milliseconds elapsed since the start of the application until the creation of the logging event.
tUsed to output the name of the thread where the logging event occured.
%The sequence %% outputs a single percent sign. + *
+ * + * By default the relevant information is output as is. However, with the aid of format modifiers it is possible to change the + * minimum field width, the maximum field width and justification. + * + * The optional format modifier is placed between the percent sign and the conversion character. + * + * The first optional format modifier is the left justification flag which is just the minus (-) character. Then comes the + * optional minimum field width modifier. This is a decimal constant that represents the minimum number of characters to + * output. If the data item requires fewer characters, it is padded on either the left or the right until the minimum width is + * reached. The default is to pad on the left (right justify) but you can specify right padding with the left justification flag. The + * padding character is space. If the data item is larger than the minimum field width, the field is expanded to accommodate the + * data. The value is never truncated. + * + * This behavior can be changed using the maximum field width modifier which is designated by a period followed by a + * decimal constant. If the data item is longer than the maximum field, then the extra characters are removed from the + * beginning of the data item and not from the end. For example, it the maximum field width is eight and the data item is + * ten characters long, then the first two characters of the data item are dropped. This behavior deviates from the printf function in C + * where truncation is done from the end. + * + * Below are various format modifier examples for the category conversion specifier. + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + *
Format modifierleft justifyminimum widthmaximum widthcomment
%20Cfalse20noneLeft pad with spaces if the logger name is less than 20 characters long.
%-20Ctrue20noneRight pad with spaces if the logger name is less than 20 characters long.
%.30CNAnone30Truncate from the beginning if the logger name is longer than 30 characters.
%20.30Cfalse2030Left pad with spaces if the logger name is shorter than 20 characters. However, if logger name is longer than 30 characters, + * then truncate from the beginning.
%-20.30Ctrue2030Right pad with spaces if the logger name is shorter than 20 characters. However, if logger name is longer than 30 characters, + * then truncate from the beginning.
+ * + */ + +@protocol L4PatternLayoutConverterDelegate; +@protocol L4PatternLayoutParserDelegate; + +@interface L4PatternLayout :L4Layout + +/** + * Layout conversion pattern + */ +@property (copy) NSString * conversionPattern; + +/** + * When the pattern layout formats logging messages, it first takes the conversion + * pattern and parses it into token strings. Then, it takes each token string and + * converts it into the corresponding part of the final formatted message. + * You can provide a converter delegate to override or extend how a pattern layout + * converts its token strings. By default, the pattern layout does nothing to + * literal string tokens and converts format specifiers as explained in the description of this class. + * The converter delegate must respond to the convertTokenString:withLoggingEvent:intoString:method. + */ +@property (strong) id converterDelegate; + +/** + * When the pattern layout formats logging messages, it first takes the conversion pattern and parses it into token strings. + * You can provide a parser delegate to override how a pattern layout parses the conversion pattern into token strings. By + * default, the pattern layout divides the conversion pattern into a series of literal strings and format specifiers. + * The parser delegate must respond to the parseConversionPattern:intoArray:method. + */ +@property (strong) id parserDelegate; + +/** + * Initializes an L4PatternLayout with the default conversion pattern, %m%n + * Calls initWthConversionPattern:with the string defined by L4PatternLayoutDefaultConversionPattern + * @return A newly initialized L4PatternLayout object + */ +- (id)init; + +/** + * Initializes an instance from properties. The properties supported are: + * - ConversionPattern: the conversion pattern to use in this instance. + * @param initProperties the proterties to use. + */ +- (id) initWithProperties:(L4Properties *)initProperties; + +/** + * Initializes an L4PatternLayout with a custom conversion pattern. + * @param aConversionPattern The custom conversion pattern. + * @return A newly initialized L4PatternLayout object. + */ +- (id)initWithConversionPattern:(NSString*)aConversionPattern; + +/** + * Uses this class's conversion pattern to format logging messages + * @param event A logging event that contains information that the layout needs to format the logging message. + * @throw L4InvalidSpecifierException if the pattern layout's conversion pattern contains an invalid conversion specifier. + * @throw L4NoConversionPatternException if the pattern layout's conversion pattern is nil. This should only happen if you + * have code like the following:[patternLayout setConversionPattern:nil]; + * @throw L4InvalidBraceClauseException when a conversion specifier's brace clause is invalid for any reason. + * @return A formatted logging message that adheres to the L4PatternLayout's conversion pattern. +*/ +- (NSString *)format:(L4LogEvent *)event; + +@end + +/* + * This is here for testing purposes. Otherwise, the conversion pattern does not get parsed until a log event happens. + */ +@interface L4PatternLayout (TestMethods) + +- (NSArray *)tokenArray; + +@end + +/** + * Declares methods that an L4PatternLayout's converter delegate must implement. + */ +@protocol L4PatternLayoutConverterDelegate + +/** + * Allows an object to override or extend how an L4PatternLayout converts its token strings into pieces of the final formatted. + * logging message. + * @param token The token string to convert + * @param logEvent An L4LoggingEvent that contains information about the current logging request + * @param convertedString A reference to an NSString that will contain the result of the token string's conversion upon exiting the method + * @return Return YES to indicate that you have converted the token string. Return NO to let the pattern layout's default behavior attempt to convert it. + */ +- (BOOL)convertTokenString:(NSString*)token withLoggingEvent:(L4LogEvent*)logEvent intoString:(NSString**)convertedString; + +@end + +/** + * Declares methods that an L4PatternLayout's parser delegate must implement. + */ +@protocol L4PatternLayoutParserDelegate + +/** + * Allows an object to override how an L4PatternLayout parses its conversion pattern into a series of token strings. + * @param cp The conversion pattern to be parsed + * @param tokenStringArray A mutable array to hold the parsed tokens + */ +- (void)parseConversionPattern:(NSString*)cp intoArray:(NSMutableArray* __autoreleasing *)tokenStringArray; + +@end + +// For copyright & license, see LICENSE. diff --git a/mac/TeamTalk/Libraries/Log4Cocoa/L4PatternLayout.m b/mac/TeamTalk/Libraries/Log4Cocoa/L4PatternLayout.m new file mode 100644 index 000000000..d3d89ff7f --- /dev/null +++ b/mac/TeamTalk/Libraries/Log4Cocoa/L4PatternLayout.m @@ -0,0 +1,473 @@ +/** + * For copyright & license, see LICENSE. + */ + +#import +#import "L4PatternLayout.h" +#import "L4Layout.h" +#import "L4LogEvent.h" +#import "L4Properties.h" +#import "L4LogLog.h" +#import "L4Level.h" +#import "L4Logger.h" + +NSString* const L4PatternLayoutDefaultConversionPattern = @"%m%n"; +NSString* const L4InvalidSpecifierException = @"L4InvalidSpecifierException"; +NSString* const L4NoConversionPatternException = @"L4NoConversionPatternException"; +NSString* const L4InvalidBraceClauseException = @"L4InvalidBraceClauseException"; + +@implementation L4PatternLayout { + NSMutableArray *_tokenArray; +} + +- (id)init +{ + return [self initWithConversionPattern:L4PatternLayoutDefaultConversionPattern]; +} + +- (id) initWithProperties:(L4Properties *) initProperties +{ + self = [super initWithProperties:initProperties]; + + if (self) { + // Support for layout.ConversionPattern in properties configuration file + NSString *buf = [initProperties stringForKey:@"ConversionPattern"]; + if (!buf) { + [L4LogLog warn:@"ConversionPattern not specified in properties, will use default."]; + buf = L4PatternLayoutDefaultConversionPattern; + } + [self setConversionPattern:buf]; + _tokenArray = [[NSMutableArray alloc] initWithCapacity:3]; + } + + return self; +} + +- (id)initWithConversionPattern:(NSString*)aConversionPattern +{ + L4Properties *properties = [L4Properties properties]; + [properties setString:aConversionPattern forKey:@"ConversionPattern"]; + return [self initWithProperties:properties]; +} + +- (NSString *)format:(L4LogEvent *)event +{ + BOOL handled = NO; + NSMutableString *formattedString = nil; + int index = -1; + NSString *convertedString = nil; + + @synchronized(self) { + + // check the conversion pattern to make sure it has been set, if not, throw an L4NoConversionPatternException + if ([self conversionPattern] == nil) { + [NSException raise:L4NoConversionPatternException + format:@"L4PatternLayout's conversion pattern is nil and must be set first using either initWithConversionPattern: or setConversionPattern:"]; + } + + formattedString = [NSMutableString stringWithCapacity:10]; + + // let delegate handle it first + if ([_parserDelegate respondsToSelector:@selector(parseConversionPattern:intoArray:)]) { + if (_tokenArray.count <= 0) { + NSMutableArray *newTokenArray; + [_parserDelegate parseConversionPattern:_conversionPattern intoArray:&newTokenArray]; + _tokenArray = newTokenArray; + } + + for (index = 0; index < _tokenArray.count; index++) { + // reset converted string state to make sure we don't use an old value + convertedString = [NSString string]; + + // let delegate handle it first + if ([_converterDelegate respondsToSelector:@selector(convertTokenString:withLoggingEvent:intoString:)]) { + handled = [_converterDelegate convertTokenString:_tokenArray[index] + withLoggingEvent:event + intoString:&convertedString]; + if (!handled) { + [self convertTokenString:_tokenArray[index] + withLoggingEvent:event + intoString:&convertedString]; + } + } else { + [self convertTokenString:_tokenArray[index] + withLoggingEvent:event + intoString:&convertedString]; + } + + // only append string if it isn't nil + if (convertedString != nil) { + [formattedString appendString:convertedString]; + } + } + } else { + if (_tokenArray.count <= 0) { + NSMutableArray *newTokenArray; + [_parserDelegate parseConversionPattern:_conversionPattern intoArray:&newTokenArray]; + _tokenArray = newTokenArray; + } + + for (index = 0; index < _tokenArray.count; index++) { + // reset converted string state to make sure we don't use an old value + convertedString = nil; + + // let delegate handle it first + if ([_converterDelegate respondsToSelector:@selector(convertTokenString:withLoggingEvent:intoString:)]) { + handled = [_converterDelegate convertTokenString:_tokenArray[index] + withLoggingEvent:event + intoString:&convertedString]; + if (!handled) { + [self convertTokenString:_tokenArray[index] + withLoggingEvent:event + intoString:&convertedString]; + } + } else { + [self convertTokenString:_tokenArray[index] + withLoggingEvent:event + intoString:&convertedString]; + } + + // only append string if it isn't nil + if (convertedString != nil) { + [formattedString appendString:convertedString]; + } + } + } + } + return formattedString; +} + +- (void)parseConversionPattern:(NSString*)cp intoArray:(NSMutableArray* __autoreleasing *)tokenStringArray +{ + NSScanner* scanner = nil; + NSCharacterSet* percentCharacterSet = nil; + NSMutableCharacterSet* specifiersAndSpaceCharacterSet = nil; + NSMutableDictionary* locale = nil; + NSMutableString* token = nil, *tempString = nil; + + percentCharacterSet = [NSCharacterSet characterSetWithCharactersInString:@"%"]; + + specifiersAndSpaceCharacterSet = (NSMutableCharacterSet*)[NSCharacterSet characterSetWithCharactersInString:@" "]; + [specifiersAndSpaceCharacterSet formUnionWithCharacterSet:L4PatternLayoutDefaultSpecifiers]; + + // Get a copy of the user's default locale settings and set the NSDecimalSeparator key of the locale dictionary to + // the string ".". This way we can make sure that minimum and maximum length specifiers are scanned correctly by + // the scanner. + locale = [NSMutableDictionary + dictionaryWithDictionary:[[NSUserDefaults standardUserDefaults] dictionaryRepresentation]]; + locale[NSLocaleDecimalSeparator] = @"."; + + scanner = [NSScanner scannerWithString:cp]; + [scanner setLocale:locale]; + + // don't skip any characters when parsing the string + [scanner setCharactersToBeSkipped:[NSCharacterSet characterSetWithCharactersInString:@""]]; + + while (![scanner isAtEnd]) { + token = [NSMutableString stringWithCapacity:10]; + tempString = [NSMutableString stringWithCapacity:10]; + + // scan until % is found or end of string is reached + [scanner scanUpToCharactersFromSet:percentCharacterSet intoString:&token]; + + // if end of string reached + if ([scanner isAtEnd]) { + // do nothing, this will force the execution to the end of the while loop where the token string is added to + // the token string array + } else if ([percentCharacterSet characterIsMember:[[scanner string] characterAtIndex:[scanner scanLocation]]]) { + // if characters were scanned + if ([token length] > 0) { + // it should be a literal string and we are done for this iteration of the while loop + } else { + [token appendFormat:@"%C", [[scanner string] characterAtIndex:[scanner scanLocation]]]; + [scanner setScanLocation:([scanner scanLocation] + 1)]; + [scanner scanUpToCharactersFromSet:specifiersAndSpaceCharacterSet intoString:&tempString]; + + if ([scanner isAtEnd]) { + [NSException raise:L4InvalidSpecifierException + format:@"Expected a valid specifier character at position %d in the string '%@'", + [scanner scanLocation], [scanner string]]; + } else if ([[scanner string] characterAtIndex:[scanner scanLocation]] == (unichar)' ') { + [NSException raise:L4InvalidSpecifierException + format:@"Expected a valid specifier character at position %d in the string '%@'", + [scanner scanLocation], [scanner string]]; + } else { + [token appendString:tempString]; + [token appendFormat:@"%C", [[scanner string] characterAtIndex:[scanner scanLocation]]]; + [scanner setScanLocation:([scanner scanLocation] + 1)]; + + if ([L4PatternLayoutTrailingBracesSpecifiers + characterIsMember:[[scanner string] characterAtIndex:([scanner scanLocation] - 1)]]) { + if ([scanner isAtEnd]) { + // do nothing, this will force the execution to the end of the while loop where the token + // string is added to the token string array + } else if ([[scanner string] characterAtIndex:[scanner scanLocation]] == (unichar)'{') { + [scanner scanUpToString:@"}" intoString:&tempString]; + + if ([scanner isAtEnd]) { + [NSException raise:L4InvalidBraceClauseException + format:@"Expected a closing brace '}' character at position %d in the string '%@'", + [scanner scanLocation], [scanner string]]; + } else if ([[scanner string] characterAtIndex:[scanner scanLocation]] == (unichar)'}') { + [token appendString:tempString]; + [token appendFormat:@"%C", [[scanner string] characterAtIndex:[scanner scanLocation]]]; + [scanner setScanLocation:([scanner scanLocation] + 1)]; + } + } + } // if specifier character can be followed by brace clause + } // else + } // else + } // else if % found + + // add final token string to the token string array + [*tokenStringArray addObject:token]; + } // while + + // return YES; +} + +- (BOOL)convertTokenString:(NSString*)token + withLoggingEvent:(L4LogEvent*)logEvent + intoString:(NSString**)convertedString +{ + + if (token.length > 0 && [token characterAtIndex:0] != (unichar)'%') { + *convertedString = [NSString stringWithString:token]; + return YES; + } + NSMutableString *finalResultString = [NSMutableString stringWithCapacity:10]; + + NSCharacterSet *percentCharSet = [NSCharacterSet characterSetWithCharactersInString:@"%"]; + NSCharacterSet *specifiersCharSet = L4PatternLayoutDefaultSpecifiers; + + NSScanner *scanner = [NSScanner scannerWithString:token]; + + // don't skip any characters + scanner.charactersToBeSkipped = [NSCharacterSet characterSetWithCharactersInString:@""]; + + while (![scanner isAtEnd]) { + NSString *tempString = @""; + + // reset parser state variables + NSUInteger charsToSkip = 0; + NSInteger minLength = 0; + NSInteger maxLength = 0; + BOOL leftJustify = NO; + + // check for specifier escape sequence (a percent (%)) + //DDLog(@"Checking for a percent at index %d", [scanner scanLocation]); + if ([percentCharSet characterIsMember:[scanner.string characterAtIndex:scanner.scanLocation]]) { + // found a percent sign + charsToSkip++; + + // we will read the specifier justification and length as a string, so update scan location first + [scanner setScanLocation:([scanner scanLocation] + charsToSkip)]; + charsToSkip = 0; + + NSString *fieldLength; + if ([scanner scanUpToCharactersFromSet:specifiersCharSet intoString:&fieldLength]) { + NSArray *fieldLengthArray = [fieldLength componentsSeparatedByString:@"."]; + + // check for left justification character (-) + leftJustify = [fieldLengthArray[0] rangeOfString:@"-"].location != NSNotFound; + + // check for minimum field width + minLength = abs([fieldLengthArray[0] intValue]); + + if (fieldLengthArray.count > 1) { + maxLength = abs([fieldLengthArray[(fieldLengthArray.count - 1)] intValue]); + } + } + + // get the specifier character, if we are at the end of the string but haven't read a specifier + // character yet, throw an L4InvalidSpecifierException + //DDLog(@"Checking for the specifier character at index %d", ([scanner scanLocation] + charsToSkip)); + if ([scanner isAtEnd]) { + [NSException raise:L4InvalidSpecifierException + format:@"Expected a valid specifier character at position %d in the string '%@'", scanner.scanLocation, scanner.string]; + } + unichar specifierChar = [scanner.string characterAtIndex:(scanner.scanLocation + charsToSkip)]; + + if ([specifiersCharSet characterIsMember:specifierChar]) { + switch (specifierChar) { + case 'C': + { + // skip the 'C' + charsToSkip++; + + tempString = logEvent.logger.name; + + //DDLog(@"Checking for { after a C at index %d", ([scanner scanLocation] + charsToSkip)); + + // if skipping number of characters equal to value of charsToSkip doesn't put us at the end + // of the string and the next character (if we skipped charsToSkip characters) would be { + if ((scanner.scanLocation + charsToSkip) < scanner.string.length + && [scanner.string characterAtIndex:(scanner.scanLocation + charsToSkip)] == (unichar)'{') { + // there's an {, skip it and read the integer that follows + charsToSkip++; + + // update the scanner's scan location because the following scan operation will advance + // the scan location, also reset the charsToSkip + scanner.scanLocation += charsToSkip; + charsToSkip = 0; + + NSString *componentLengthString; + if ([scanner scanUpToString:@"}" intoString:&componentLengthString]) { + NSInteger componentLength = componentLengthString.integerValue; + + if (componentLength > 0) { + NSRange componentRange = NSMakeRange([tempString componentsSeparatedByString:@"."].count - componentLength, + componentLength); + tempString = [[[tempString componentsSeparatedByString:@"."] + subarrayWithRange:componentRange] + componentsJoinedByString:@"."]; + } else { + [NSException raise:L4InvalidBraceClauseException + format:@"Expected a nonzero positive integer at position %d in conversion specifier %@.", + scanner.scanLocation - componentLengthString.length, scanner.string]; + } + + // skip closing } + charsToSkip++; + } + } + } + break; + + case 'd': + { + // skip the 'd' + charsToSkip++; + + // if skipping number of characters equal to value of charsToSkip doesn't put us at the end + // of the string and the next character (if we skipped charsToSkip characters) would be { + if ((scanner.scanLocation + charsToSkip) < scanner.string.length + && [scanner.string characterAtIndex:(scanner.scanLocation + charsToSkip)] == (unichar)'{') { + // there's an {, skip it and read the string that follows + charsToSkip++; + + // update the scanner's scan location because the following scan operation will advance + // the scan location, also reset the charsToSkip + scanner.scanLocation += charsToSkip; + charsToSkip = 0; + + // if there's anything between the braces, get string description of the logging event's + // timestamp with the format we just found + NSString *dateFormat; + if ([scanner scanUpToString:@"}" intoString:&dateFormat]) { + // Format Date + NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init]; + dateFormatter.dateFormat = dateFormat; + tempString = [dateFormatter stringFromDate:logEvent.timestamp]; + + // skip closing brace + charsToSkip++; + } + } else { + tempString = logEvent.timestamp.description; + } + } + break; + + case 'F': + // skip the 'F' + charsToSkip++; + tempString = logEvent.fileName; + break; + + case 'l': + // skip the 'l' + charsToSkip++; + tempString = [NSString stringWithFormat:@"%@'s %@ (%@:%@)", + logEvent.logger.name, logEvent.methodName, logEvent.fileName, logEvent.lineNumber]; + break; + + case 'L': + // skip the 'L' + charsToSkip++; + tempString = [NSString stringWithFormat:@"%@", logEvent.lineNumber]; + break; + + case 'm': + // skip the 'm' + charsToSkip++; + tempString = logEvent.renderedMessage ?: @"No message!"; + break; + + case 'M': + // skip the 'M' + charsToSkip++; + tempString = logEvent.methodName; + break; + + case 'n': + // skip the 'n' + charsToSkip++; + tempString = @"\n"; + break; + + case 'p': + // skip the 'p' + charsToSkip++; + tempString = logEvent.level.description; + break; + + case 'r': + // skip the 'r' + charsToSkip++; + tempString = [NSString stringWithFormat:@"%ld", logEvent.millisSinceStart]; + break; + + case 't': + // skip the 't' + charsToSkip++; + tempString = [NSThread currentThread].name ?: [NSString stringWithFormat:@"%p", [NSThread currentThread]]; + break; + + case '%': + // skip the '%' + charsToSkip++; + tempString = @"%"; + break; + } + + if (minLength > 0 && tempString.length < minLength) { + tempString = [NSString stringWithFormat:leftJustify ? @"%*s" : @"%-*s", minLength, tempString.UTF8String]; + } + + if (maxLength > 0 && tempString.length > maxLength) { + tempString = [tempString substringToIndex:maxLength]; + } + + [finalResultString appendString:tempString]; + } + + scanner.scanLocation += charsToSkip; + continue; + } + + if ([scanner scanUpToCharactersFromSet:percentCharSet intoString:&tempString]) { + [finalResultString appendString:tempString]; + } else { + [NSException raise:L4InvalidSpecifierException + format:@"Expected a valid specifier character at position %d in the string '%@'", + [scanner scanLocation], [scanner string]]; + } + } + + *convertedString = (NSString*) finalResultString; + + return YES; +} + +/* + * This is here for testing purposes. Otherwise, the conversion pattern does not get parsed until a log event happens. + */ +- (NSArray *)tokenArray +{ + NSMutableArray *newTokenArray; + [self parseConversionPattern:_conversionPattern intoArray:&newTokenArray]; + return newTokenArray; +} + +@end diff --git a/mac/TeamTalk/Libraries/Log4Cocoa/L4Properties.h b/mac/TeamTalk/Libraries/Log4Cocoa/L4Properties.h new file mode 100644 index 000000000..38f56105d --- /dev/null +++ b/mac/TeamTalk/Libraries/Log4Cocoa/L4Properties.h @@ -0,0 +1,102 @@ +// For copyright & license, see LICENSE. + +#import + +/** + *Defines the name for the no conversion pattern exception + * This exception is thrown if you try to use an L4PatternLayout before setting its conversion pattern + */ +extern NSString* const L4PropertyMissingException; + +/** + * The L4Properties class provides a dictionary like interface to properties used to configure the logging system. Even + * though these properties would typically be read in from a file, they can also be set from an NSDictionary. + */ +@interface L4Properties : NSObject + +/** + * Returns an empty properties instance. + * @return the newly created, empty properties instance. + */ ++ (instancetype)properties; + +/** + * Creates and returns a new instance, reading in properties from the specified file. + * @param aName the name of the file containing the properties to use. + * @return the newly created, configured properties instance. + */ ++ (instancetype)propertiesWithFileName:(NSString *) aName; + +/** + * Creates and returns a new instance, using the supplied dictionary for the property values. + * @param aProperties the dictionary containing the properties to use. + * @return the newly created, configured properties instance. + */ ++ (instancetype)propertiesWithProperties:(NSDictionary *) aProperties; + +/** + * Returns all the keys in this property list. + * @return an array of all the keys in this property list. + */ +- (NSArray *)allKeys; + +/** + * Accessor for the int value of the number of entries in this collection. + * @return the int value of the number of entries in this collection. + */ +- (NSUInteger)count; + +/** + * This method initializes a new instance of this class with the specified file path. + * @param aName the file path of the properties file you want to read from. + * @return An initialized instance of this class. + */ +- (id)initWithFileName:(NSString *)aName; + +/** + * This method initializes a new instance of this class with the specified dictionary. + * @param aProperties an initialized dictionary that contains the properties you want. + * @return An initialized instance of this class. + */ +- (id)initWithProperties:(NSDictionary *)aProperties; + +/** + * Removes the property indexed by key from this property list. + * @param aKey the name of the property which is to be removed from the property list. + */ +- (void)removeStringForKey:(NSString *)aKey; + +/** + * Searches for the property with the specified key in this property list. If the key is not found in this property + * list, the default property list, and its defaults, recursively, are then checked. + * @param aKey the name of the property which is requested. + * @return the value of the requested property or nil if the specified property was not found. + */ +- (NSString *)stringForKey:(NSString *)aKey; + +/** + * Searches for the property with the specified key in this property list. If the key is not found in this property + * list, the default property list, and its defaults, recursively, are then checked. + * @param aKey the name of the property which is requested. + * @param aDefaultValue the default value to be returned if the specified property was not found. + * @return the value of the requested property or the default value argument if the specified property was not found. + */ +- (NSString *)stringForKey:(NSString *)aKey withDefaultValue:(NSString *)aDefaultValue; + +/** + * Inserts aString into this property list indexed by aKey. + * @param aString the value for the property to be inserted. + * @param aKey the name of the property which is to be inserted into the property list. + */ +- (void)setString:(NSString *)aString forKey:(NSString *)aKey; + +/** + * Returns a subset of the properties whose keys start with the specified prefix. + * The returned properties have the specified prefix trimmed from their keys. + * @param aPrefix the property name prefix to search for, and remove from the returned property list subset. + * @return a subset of the original property list which contains all the properties whose keys started with the + * specified prefix, but have had the prefix trimmed from them. + */ +- (L4Properties *)subsetForPrefix:(NSString *)aPrefix; + +@end diff --git a/mac/TeamTalk/Libraries/Log4Cocoa/L4Properties.m b/mac/TeamTalk/Libraries/Log4Cocoa/L4Properties.m new file mode 100644 index 000000000..e3c5eb0a7 --- /dev/null +++ b/mac/TeamTalk/Libraries/Log4Cocoa/L4Properties.m @@ -0,0 +1,215 @@ +/** + * For copyright & license, see LICENSE. + */ + +#import "L4Properties.h" +#import "L4LogLog.h" + +static NSString *L4PropertiesCommentChar = @"#"; +static NSString *DELIM_START = @"${"; +static int DELIM_START_LEN = 2; +static NSString *DELIM_STOP = @"}"; +static int DELIM_STOP_LEN = 1; +NSString* const L4PropertyMissingException = @"L4PropertyMissingException"; + +/** + * Private messages for the L4Properties class. + */ +@interface L4Properties () +/** + * A helper method that enumerates all the stored properties, and for each one, + * invokes the substituteEnvironmentVariablesForString: helper method on both + * its key and its value. + */ +- (void) replaceEnvironmentVariables; +/** + * A helper method that takes a string that may contain any number of named + * environment variable references, such as ${TEMP_DIR} and substitutes each + * named environment variable reference with its actual value instead. + * + * @param aString a string that may contain zero or more named environment variable references + * @return a copy of the input string, with all the named environment variable references + * having been replaced by their actual values. + */ +- (NSString *) substituteEnvironmentVariablesForString:(NSString *)aString; +@end + +@implementation L4Properties { + NSMutableDictionary *_properties; /**< The internal dictionary in which individual properties are stored.*/ +} + +#pragma mark - Class methods + ++ (instancetype)properties +{ + return [self propertiesWithProperties:[NSMutableDictionary dictionary]]; +} + ++ (instancetype)propertiesWithFileName:(NSString *)aName +{ + return [[L4Properties alloc] initWithFileName:aName]; +} + ++ (instancetype)propertiesWithProperties:(NSDictionary *)aProperties +{ + return [[L4Properties alloc] initWithProperties:aProperties]; +} + + +#pragma mark - Instance methods + +- (NSArray *) allKeys +{ + return [_properties allKeys]; +} + +- (NSUInteger) count +{ + return [_properties count]; +} + +- (NSString *) description +{ + return [_properties description]; +} + +- (id) init +{ + return [self initWithFileName:nil]; +} + +- (id) initWithFileName:(NSString *)aName +{ + self = [super init]; + if (self) { + _properties = [NSMutableDictionary dictionary]; + + NSString *fileContents = [NSString stringWithContentsOfFile:aName encoding:NSUTF8StringEncoding error:nil]; + + NSEnumerator *lineEnumerator = [[fileContents componentsSeparatedByString:@"\n"] objectEnumerator]; + NSString *currentLine = nil; + while ( ( currentLine = [lineEnumerator nextObject] ) != nil ) { + currentLine = [currentLine stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceCharacterSet]]; + + if ( ![currentLine hasPrefix:L4PropertiesCommentChar] ) { + NSRange range = [currentLine rangeOfString:@"="]; + + if ( ( range.location != NSNotFound ) && ( [currentLine length] > range.location + 1 ) ) { + _properties[[currentLine substringToIndex:range.location]] = [currentLine substringFromIndex:range.location + 1]; + } + } + } + [self replaceEnvironmentVariables]; + } + + return self; +} + +- (id) initWithProperties:(NSDictionary *)aProperties +{ + self = [super init]; + if (self) { + _properties = [[NSMutableDictionary alloc] initWithDictionary:aProperties]; + } + + return self; +} + +- (void) removeStringForKey:(NSString *)aKey +{ + [_properties removeObjectForKey:aKey]; +} + +- (void) setString:(NSString *)aString forKey:(NSString *)aKey +{ + _properties[aKey] = aString; + [self replaceEnvironmentVariables]; +} + +- (NSString *) stringForKey:(NSString *)aKey +{ + return [self stringForKey:aKey withDefaultValue:nil]; +} + +- (NSString *) stringForKey:(NSString *)aKey withDefaultValue:(NSString *)aDefaultValue +{ + return _properties[aKey] ?: aDefaultValue; +} + +- (L4Properties *) subsetForPrefix:(NSString *)aPrefix +{ + NSMutableDictionary *subset = [NSMutableDictionary dictionaryWithCapacity:[_properties count]]; + + NSEnumerator *keyEnum = [[_properties allKeys] objectEnumerator]; + NSString *key = nil; + while ( ( key = [keyEnum nextObject] ) != nil ) { + NSRange range = [key rangeOfString:aPrefix options:0 range:NSMakeRange(0, [key length])]; + if ( range.location != NSNotFound ) { + NSString *subKey = [key substringFromIndex:range.length]; + subset[subKey] = _properties[key]; + } + } + + return [L4Properties propertiesWithProperties:subset]; +} + + +#pragma mark - Private methods + +- (void) replaceEnvironmentVariables +{ + NSEnumerator *keyEnum = [[self allKeys] objectEnumerator]; + NSString *key = nil; + while ( ( key = [keyEnum nextObject] ) != nil ) { + NSString *value = [self stringForKey:key]; + NSString *subKey = [self substituteEnvironmentVariablesForString:key]; + if ( ![subKey isEqualToString:key] ) { + [self removeStringForKey:key]; + [self setString:subKey forKey:value]; + } + NSString *subVal = [self substituteEnvironmentVariablesForString:value]; + if ( ![subVal isEqualToString:value] ) { + [self setString:subVal forKey:subKey]; + } + } +} + +- (NSString *) substituteEnvironmentVariablesForString:(NSString *)aString +{ + int len = [aString length]; + NSMutableString *buf = [NSMutableString string]; + NSRange i = NSMakeRange(0, len); + NSRange j, k; + while ( true ) { + j = [aString rangeOfString:DELIM_START options:0 range:i]; + if ( j.location == NSNotFound ) { + if ( i.location == 0 ) { + return aString; + } else { + [buf appendString:[aString substringFromIndex:i.location]]; + return buf; + } + } else { + [buf appendString:[aString substringWithRange:NSMakeRange(i.location, j.location - i.location)]]; + k = [aString rangeOfString:DELIM_STOP options:0 range:NSMakeRange(j.location, len - j.location)]; + if ( k.location == NSNotFound ) { + [L4LogLog error: + [NSString stringWithFormat:@"\"%@\" has no closing brace. Opening brace at position %@.", + aString, [NSNumber numberWithInt:j.location]]]; + return aString; + } else { + j.location += DELIM_START_LEN; + j = NSMakeRange(j.location, k.location - j.location); + NSString *key = [aString substringWithRange:j]; + char *replacement = getenv([key UTF8String]); + if ( replacement != NULL ) { + [buf appendString:@(replacement)]; + } + i.location += (k.location + DELIM_STOP_LEN); + i.length -= i.location; + } + } + } +} + +@end diff --git a/mac/TeamTalk/Libraries/Log4Cocoa/L4PropertyConfigurator.h b/mac/TeamTalk/Libraries/Log4Cocoa/L4PropertyConfigurator.h new file mode 100644 index 000000000..f81ef32ea --- /dev/null +++ b/mac/TeamTalk/Libraries/Log4Cocoa/L4PropertyConfigurator.h @@ -0,0 +1,146 @@ +#import + +@class L4Properties; + +/** + * The class responsible for configuring the logging system with a properties file. + */ +@interface L4PropertyConfigurator : NSObject { + L4Properties* properties; /**< The internal collection in which individual properties are stored.*/ + NSMutableDictionary* appenders; /**< The internal collection in which individual configured appenders are stored.*/ +} + +/** + * Returns a newly created instance of L4PropertyConfigurator set to use a given file name for the properties. + * @param aName the name of the file to read the properties from, + * @return the new instance of L4PropertyConfigurator. + */ ++ (instancetype)propertyConfiguratorWithFileName:(NSString *)aName; + +/** + * Returns a newly created instance of L4PropertyConfigurator set to use a given properties instance. + * @param aProperties The properties to use in configuring the system. + * @return the new instance of L4PropertyConfigurator. + */ ++ (instancetype)propertyConfiguratorWithProperties:(L4Properties *)aProperties; + +/** + * This method initializes a new instance of this class with the specified file path. + * @param aName the file path of the properties file you want to read from. + * @return An initialized instance of this class. + */ +- (id)initWithFileName:(NSString *) aName; + +/** + * This method initializes a new instance of this class with the specified properties. + * @param aProperties an initialized properties collection that contains the properties you want. + * @return An initialized instance of this class. + */ +- (id)initWithProperties:(L4Properties *) aProperties; + +/** + * Read configuration from a file. The existing configuration is not cleared nor reset. + * + * The configuration file consists of statements in the format key=value. + * The syntax of different configuration elements are discussed below. + * + * Appender configuration + * + * Appender configuration syntax is: + * + * + * # For appender named "appenderName", set its class.\n + * log4cocoa.appender.appenderName=name_of_appender_class + * + * # Set appender specific options.\n + * log4cocoa.appender.appenderName.option1=value1\n + * ...\n + * log4cocoa.appender.appenderName.optionN=valueN\n + * + * For each named appender you can configure its layout. The syntax for configuring an appender's layout is:\n + * log4cocoa.appender.appenderName.layout=name_of_layout_class\n + * log4cocoa.appender.appenderName.layout.option1=value1\n + * ....\n + * log4cocoa.appender.appenderName.layout.optionN=valueN + * + * Configuring loggers + * + * The syntax for configuring the root logger is:\n + * log4cocoa.rootLogger=[LogLevel], appenderName, appenderName, ... + * + * This syntax means that an optional LogLevel value can be supplied followed by appender names separated by commas. + * + * The LogLevel value can consist of the string values FATAL, ERROR, WARN, INFO or DEBUG. + * + * If a LogLevel value is specified, then the root LogLevel is set to the corresponding LogLevel. If no LogLevel value + * is specified, then the root LogLevel remains untouched. + * + * The root logger can be assigned multiple appenders. + * + * Each appenderName (separated by commas) will be added to the root logger. The named appender is defined using the + * appender syntax defined above. + * + * For non-root loggers the syntax is almost the same:\n + * log4cocoa.logger.logger_name=[LogLevel|INHERITED], appenderName, appenderName, ... + * + * The meaning of the optional LogLevel value is discussed above in relation to the root logger. In addition however, + * the value INHERITED can be specified meaning that the named logger should inherit its LogLevel from the logger + * hierarchy. + * + * By default loggers inherit their LogLevel from the hierarchy. However, if you set the LogLevel of a logger and + * later decide that that logger should inherit its LogLevel, then you should specify INHERITED as the value for the + * LogLevel value. + * + * Similar to the root logger syntax, each appenderName (separated by commas) will be attached to the named + * logger. + * + * Example + * + * An example configuration is given below.\n + * + * # Set options for appender named "A1".\n + * # Appender "A1" will be a L4ConsoleAppender\n + * log4cocoa.appender.A1=L4ConsoleAppender + * + * # The console appender should write to standard out\n + * log4cocoa.appender.A1.LogToStandardOut=true + * + * # A1's layout is a L4PatternLayout, using the conversion pattern "%-5p : %m%n". Thus, the log output will include:\n + * # - the relative time since the start of the application in milliseconds, \n + * # - followed by the LogLevel of the log request,\n + * # - followed by the two rightmost components of the logger name,\n + * # - followed by the callers method name, \n + * # - followed by the line number,\n + * # - the nested disgnostic context,\n + * # - and finally the message itself.\n + * # - Refer to the documentation of L4PatternLayout for further information on the syntax of the ConversionPattern + * key.\n + * log4cocoa.appender.A1.layout=L4PatternLayout\n + * log4cocoa.appender.A1.layout.ConversionPattern=%-5p : %m%n + * + * # Set options for appender named "A2"\n + * # A2 should be a RollingFileAppender, with maximum file size of 10 MB using at most one backup file. A2's layout is\n + * #L4PatternLayout using the default conversion pattern.\n + * log4cocoa.appender.A2=L4RollingFileAppender\n + * log4cocoa.appender.A2.MaximumFileSize=10MB\n + * log4cocoa.appender.A2.MaxBackupIndex=1\n + * log4cocoa.appender.A2.layout=L4PatternLayout + * + * # Root logger set to DEBUG using the A2 appender defined above.\n + * log4cocoa.rootLogger=DEBUG, A2 + * + * # The logger "class_of_the_day" inherits its LogLevel from the\n + * # logger hierarchy. Output will go to the appender's of the root\n + * # logger, A2 in this case.\n + * log4cocoa.logger.class_of_the_day=INHERIT + * + * + * + * Refer to the initWithProperties: method in each L4Appender and L4Layout for class specific properties. + * + * Use the # character at the beginning of a line for comments. + */ +- (void) configure; + +@end +// For copyright & license, see LICENSE. diff --git a/mac/TeamTalk/Libraries/Log4Cocoa/L4PropertyConfigurator.m b/mac/TeamTalk/Libraries/Log4Cocoa/L4PropertyConfigurator.m new file mode 100644 index 000000000..1fc27ca9f --- /dev/null +++ b/mac/TeamTalk/Libraries/Log4Cocoa/L4PropertyConfigurator.m @@ -0,0 +1,222 @@ +/** + * For copyright & license, see LICENSE. + */ + +#import "L4PropertyConfigurator.h" +#import "L4AppenderProtocols.h" +#import "L4Level.h" +#import "L4LogLog.h" +#import "L4Properties.h" +#import "L4RootLogger.h" + +/** + * Private methods for the L4PropertyConfigurator class. + */ +@interface L4PropertyConfigurator (Private) +/** + * Factory method to create a new L4Appender for a given class with configuratin properties. + * @param appenderClassName the name of the class this appender is for. + * @param appenderProperties the properties used to configure the new appender. + * @return the newly configured appender. + */ +- (id)appenderForClassName:(NSString *)appenderClassName andProperties:(L4Properties *)appenderProperties; + +/** + * Reads through the properties one at a time looking for properties related to additivity. If found, they are + * used to configure the framework. + */ +- (void)configureAdditivity; + +/** + * Reads through the properties one at a time looking for a named appender. If one is found, the properties + * for that appender are seperated out, and sent to the appender to initialize & configure the appender. + */ +- (void)configureAppenders; + +/** + * Reads through the properties one at a time looking for a named loggers. If one is found, the properties + * for that logger are seperated out, and sent to the logger to initialize & configure the logger. + */ +- (void)configureLoggers; +@end + + +@implementation L4PropertyConfigurator + + +#pragma mark - Class methods + ++ (instancetype)propertyConfiguratorWithFileName:(NSString *)aName +{ + return [[self alloc] initWithFileName: aName]; +} + ++ (instancetype) propertyConfiguratorWithProperties:(L4Properties *)aProperties +{ + return [(L4PropertyConfigurator *) [self alloc] initWithProperties:aProperties]; +} + + +#pragma mark - Instance methods + +- (void) configure +{ + @synchronized(self) { + [self configureAppenders]; + [self configureLoggers]; + [self configureAdditivity]; + + // Erase the appenders to that we are not artificially retaining them. + [appenders removeAllObjects]; + } +} + +- (void) configureLogger:(L4Logger *)aLogger withProperty:(NSString *)aProperty +{ + // Remove all whitespace characters from config + NSArray *components = [aProperty componentsSeparatedByCharactersInSet:[NSCharacterSet whitespaceCharacterSet]]; + NSEnumerator *componentEnum = [components objectEnumerator]; + NSString *component = nil; + NSString *configString = @""; + while ( ( component = [componentEnum nextObject] ) != nil ) { + configString = [configString stringByAppendingString:component]; + } + + // "Tokenize" configString + components = [configString componentsSeparatedByString:@","]; + + if ( [components count] == 0 ) { + [L4LogLog error:[NSString stringWithFormat:@"Invalid config string(Logger = %@): \"%@\".", [aLogger name], aProperty]]; + return; + } + + // Set the loglevel + componentEnum = [components objectEnumerator]; + NSString *logLevel = [[componentEnum nextObject] uppercaseString]; + if ( ![logLevel isEqualToString:@"INHERITED"] ) { + [aLogger setLevel:[L4Level levelWithName:logLevel]]; + } + + // Set the Appenders + while ( ( component = [componentEnum nextObject] ) != nil ) { + id appender = appenders[component]; + if ( appender == nil ) { + [L4LogLog error:[NSString stringWithFormat:@"Invalid appender: \"%@\".", component]]; + continue; + } + [aLogger addAppender:appender]; + } +} + +- (id) init +{ + return nil; // never use this constructor +} + +- (id) initWithFileName:(NSString *)aName +{ + return [self initWithProperties:[L4Properties propertiesWithFileName:aName]]; +} + +- (id) initWithProperties:(L4Properties *)initProperties +{ + self = [super init]; + if (self) { + properties = [initProperties subsetForPrefix:@"log4cocoa."]; + appenders = [[NSMutableDictionary alloc] init]; + } + + return self; +} + + +#pragma mark - Private methods + +- (id) appenderForClassName:(NSString *)appenderClassName andProperties:(L4Properties *)appenderProperties +{ + id newAppender = nil; + Class appenderClass = NSClassFromString(appenderClassName); + Protocol *appenderProtocol = @protocol(L4Appender); + NSString *apenderProtocolName = NSStringFromProtocol(@protocol(L4Appender)); + + if ( appenderClass == nil ) { + [L4LogLog error:[NSString stringWithFormat:@"Cannot find %@ class with name: \"%@\".", + apenderProtocolName, appenderClassName]]; + } else { + if ( ![appenderClass conformsToProtocol: appenderProtocol] ) { + [L4LogLog error: + [NSString stringWithFormat: + @"Failed to create instance with name \"%@\" since it does not conform to the %@ protocol.", + apenderProtocolName, appenderProtocol]]; + } else { + newAppender = [(id )[appenderClass alloc] initWithProperties:appenderProperties]; + } + } + return newAppender; +} + +- (void) configureAdditivity +{ + L4Properties *additivityProperties = [properties subsetForPrefix: @"additivity."]; + + NSEnumerator *keyEnum = [[additivityProperties allKeys] objectEnumerator]; + NSString *key = nil; + while ( ( key = [keyEnum nextObject] ) != nil ) { + L4Logger *logger = [L4Logger loggerForName: key]; + NSString *actualValue = [additivityProperties stringForKey: key]; + NSString *value = [actualValue lowercaseString]; + if ( [value isEqualToString: @"true"] ) { + [logger setAdditivity: YES]; + } else if ( [value isEqualToString: @"false"] ) { + [logger setAdditivity: NO]; + } else { + [L4LogLog error: [NSString stringWithFormat: @"Invalid additivity value for logger %@: \"%@\".", key, actualValue]]; + } + } +} + +- (void) configureAppenders +{ + L4Properties *appendersProperties = [properties subsetForPrefix: @"appender."]; + + NSEnumerator *keyEnum = [[appendersProperties allKeys] objectEnumerator]; + NSString *key = nil; + while ( ( key = [keyEnum nextObject] ) != nil ) { + NSRange range = [key rangeOfString:@"." options:0 range:NSMakeRange(0, [key length])]; + if ( range.location == NSNotFound ) { + // NSNotFound indicates that the key is for a new appender (i.e A1 - where there is no dot after the + // appender name). We now need to get the subset of properties for the named appender. + L4Properties *appenderProperties = [appendersProperties subsetForPrefix:[key stringByAppendingString:@"."]]; + + NSString *className = [appendersProperties stringForKey:key]; + id newAppender = [self appenderForClassName:className andProperties:appenderProperties]; + + if ( newAppender != nil ) { + [newAppender setName:key]; + appenders[key] = newAppender; + } else { + [L4LogLog error: + [NSString stringWithFormat: + @"Error while creating appender \"%@\" with name \"%@\".", className, key]]; + continue; + } + } + } +} + +- (void) configureLoggers +{ + NSString *rootLoggerProperty = [properties stringForKey: @"rootLogger"]; + if ( [properties stringForKey: @"rootLogger"] != nil ) { + [self configureLogger: [L4Logger rootLogger] withProperty: rootLoggerProperty]; + } + + L4Properties *loggerProperties = [properties subsetForPrefix: @"logger."]; + NSEnumerator *keyEnum = [[loggerProperties allKeys] objectEnumerator]; + NSString *key = nil; + while ( ( key = [keyEnum nextObject] ) != nil ) { + [self configureLogger: [L4Logger loggerForName: key] withProperty: [loggerProperties stringForKey: key]]; + } +} + +@end diff --git a/mac/TeamTalk/Libraries/Log4Cocoa/L4RollingFileAppender.h b/mac/TeamTalk/Libraries/Log4Cocoa/L4RollingFileAppender.h new file mode 100644 index 000000000..181627df3 --- /dev/null +++ b/mac/TeamTalk/Libraries/Log4Cocoa/L4RollingFileAppender.h @@ -0,0 +1,101 @@ +#import +#import "L4FileAppender.h" + +@class L4Layout; +@class L4LogEvent; + +/** + * The default maximum file size, which is 10MB. +*/ +extern const unsigned long long kL4RollingFileAppenderDefaultMaxFileSize; + +/** + * This class allows you to automatically create up to a number of backup log files when the log file reaches a + * specified size. This class is a subclass of L4FileAppender. + */ +@interface L4RollingFileAppender : L4FileAppender + +/** + * The maxBackupIndex determines how many backup files are kept before the oldest is erased. This method takes a + * positive integer value. If set to zero, then there will be no backup files and the log file will be truncated when it + * reaches maxFileSize. + */ +@property NSUInteger maxBackupIndex; + +/** + * Returns the maximum file size allowed for log files. If the file grows larger than this, it will be backed up and + * any additional logging statements will be written to a new file. + * By default, this is 10MB. + */ +@property NSUInteger maxFileSize; + +/** + * This method initializes a new instance of the L4RollingFileAppender class. + * This method calls initWithLayout:fileName:append:, with the default values:nil, nil, and YES + * respectively. + * return An initialized instance of this class + */ +- (id) init; + +/** + * Initializes an instance from properties. The properties supported are: + * - MaximumFileSize: the maxamum size of the log file in bytes, before beginning a new one. A suffix of MB and + * KB can be used to specify mega and kilo bytes. + * - MaxBackupIndex: specifies how many log files to keep. + * If the values are being set in a file, this is how they could look: + * log4cocoa.appender.A2.MaximumFileSize=10MB + * log4cocoa.appender.A2.MaxBackupIndex=3 + * This specifies that three files should be maintained, in adition to the one currently being logged to, and that the + * file should be rolled at 10 MB in size. + * @param initProperties the proterties to use. + */ +- (id) initWithProperties:(L4Properties *) initProperties; + +/** + * This method initialized a new instance of this class with the specified layout and file path + * This method calls initWithLayout:fileName:append:, with the values:aLayout, aName, and YES + * respectively. + * @param aLayout The layout object you want this appender to have. + * @param aName The file path of the initial file you want created. Backup files have the same name, but with the + * backup file number appended to it (See the rollOver method). + * @return An initialized instance of this class. + */ +- (id) initWithLayout:(L4Layout *) aLayout fileName:(NSString *) aName; + +/** + * This method initialized a new instance of this class with the specified layout, file path, and append option + * This is the class's designated initializer. + * @param aLayout The layout object you want this appender to have. + * @param aName The file path of the initial file you want created. Backup files have the same name, but with the + * backup file number appended to it (See the rollOver method). + * @param flag YES = log output should be appended to the file. NO = the file's previous contents should be + * overwritten. + * @return An initialized instance of this class + */ +- (id) initWithLayout:(L4Layout *) aLayout fileName:(NSString *) aName append:(BOOL) flag; + +/** + * Explicitly rolls a file over. + * If maxBackupIndex is positive, then files {File.1, ..., File.MaxBackupIndex -1} are renamed to { + * File.2, ..., File.MaxBackupIndex}. + * Moreover, File is renamed File.1 and closed. A new file is created to receive further log output. + * If maxBackupIndex is equal to zero, then the File is truncated with no backup files created. + */ +- (void)rollOver; + +@end + +/** + *These methods are "protected" methods and should not be called except by subclasses. +*/ +@interface L4RollingFileAppender (ProtectedMethods) + +/** + * This method overrides the implementation in L4WriterAppender. It checks if the maximum file size has been exceeded. + * If so, it rolls the file over according to the maxBackupIndex setting. + * @param event An L4LoggingEvent that contains logging specific information + */ +- (void)subAppend:(L4LogEvent*)event; + +@end +// For copyright & license, see LICENSE. diff --git a/mac/TeamTalk/Libraries/Log4Cocoa/L4RollingFileAppender.m b/mac/TeamTalk/Libraries/Log4Cocoa/L4RollingFileAppender.m new file mode 100644 index 000000000..d8012e530 --- /dev/null +++ b/mac/TeamTalk/Libraries/Log4Cocoa/L4RollingFileAppender.m @@ -0,0 +1,185 @@ +/** + * For copyright & license, see LICENSE. + */ + +#import "L4RollingFileAppender.h" +#import "L4Layout.h" +#import "L4LogEvent.h" +#import "L4LogLog.h" +#import "L4Properties.h" + +const unsigned long long kL4RollingFileAppenderDefaultMaxFileSize = (1024 * 1024 * 10); + +/** + * Private methods for the L4RollingFileAppender class. + */ +@interface L4RollingFileAppender () +/** + * Renames the current log file to have a specific index. Used for rolling log files. + * @param backupIndex the index of the new file. + */ +- (void)renameLogFile:(unsigned int)backupIndex; + +@end + + +@implementation L4RollingFileAppender + +- (id) init +{ + return [self initWithLayout:nil fileName:nil append:YES]; +} + +- (id) initWithProperties:(L4Properties *)initProperties +{ + self = [super initWithProperties:initProperties]; + + if ( self != nil ) { + unsigned int newMaxFileSize = kL4RollingFileAppenderDefaultMaxFileSize; + unsigned int newMaxBackupIndex = 1; + + // Support for appender.MaximumFileSize in properties configuration file + if ( [initProperties stringForKey:@"MaximumFileSize"] != nil ) { + NSString *buf = [[initProperties stringForKey:@"MaximumFileSize"] uppercaseString]; + newMaxFileSize = atoi([buf UTF8String]); + if ( [buf rangeOfString:@"MB"].location == ([buf length] - 2) ) { + newMaxFileSize *= (1024 * 1024); // convert to megabytes + } + if ( [buf rangeOfString:@"KB"].location == ([buf length] - 2) ) { + newMaxFileSize *= 1024; // convert to kilobytes + } + } + + // Support for appender.MaxBackupIndex in properties configuration file + if ( [initProperties stringForKey:@"MaxBackupIndex"] != nil ) { + NSString *buf = [[initProperties stringForKey:@"MaxBackupIndex"] uppercaseString]; + newMaxBackupIndex = atoi([buf UTF8String]); + } + + self.maxFileSize = newMaxFileSize; + self.maxBackupIndex = newMaxBackupIndex; + } + + return self; +} + +- (id) initWithLayout:(L4Layout *)aLayout fileName:(NSString *)aName +{ + return [self initWithLayout:aLayout fileName:aName append:YES]; +} + +- (id) initWithLayout:(L4Layout *)aLayout fileName:(NSString *)aName append:(BOOL) flag +{ + self = [super initWithLayout:aLayout fileName:aName append:flag]; + + if (self) { + self.maxFileSize = 1; + self.maxFileSize = kL4RollingFileAppenderDefaultMaxFileSize; + } + + return self; +} + +- (void)rollOver +{ + @synchronized(self) { + // if maxBackupIndex is 0, truncate file and create no backups + if (self.maxBackupIndex <= 0) { + [_fileHandle truncateFileAtOffset:0]; + } else { + [self closeFile]; + [self renameLogFile:0]; + [self setupFile]; + } + } +} + + +#pragma mark - Protected methods + +- (void)subAppend:(L4LogEvent*)event +{ + @synchronized(self) { + // if the file's size has exceeded maximumFileSize, roll the file over + if ([_fileHandle offsetInFile] >= self.maxFileSize) { + [self rollOver]; + } + + // use the superclass's subAppend + [super subAppend:event]; + } +} + + +#pragma mark - Private methods + +- (void)renameLogFile:(unsigned int)backupIndex +{ + NSFileManager* fileManager = nil; + NSString* tempOldFileName = nil; + NSString* tempNewFileName = nil; + NSString* tempPathExtension = nil; + + fileManager = [NSFileManager defaultManager]; + + tempPathExtension = [self.fileName pathExtension]; + + // if we are trying to rename a backup file > maxBackupIndex + if (backupIndex >= [self maxBackupIndex]) { + if ([tempPathExtension length] <= 0) { + tempOldFileName = [NSString stringWithFormat:@"%@.%d", + [[self fileName] stringByDeletingPathExtension], + [self maxBackupIndex]]; + } else { + tempOldFileName = [NSString stringWithFormat:@"%@.%d.%@", + [[[self fileName] stringByDeletingPathExtension] stringByDeletingPathExtension], + [self maxBackupIndex], tempPathExtension]; + } + + // try to delete the oldest backup file + if (![fileManager removeItemAtPath:tempOldFileName error:nil]) { + // if we couldn't delete the file, log an error + [L4LogLog error:[NSString stringWithFormat:@"Unable to delete the file %@", tempOldFileName]]; + } + } else { + // if the backupIndex = 0, we haven't renamed this file before + if (backupIndex == 0) { + tempOldFileName = [self fileName]; + } else { + if ([tempPathExtension length] <= 0) { + // create the old name of the file + tempOldFileName = [NSString stringWithFormat:@"%@.%d", + [[self fileName] stringByDeletingPathExtension], + backupIndex]; + } else { + // create the old name of the file + tempOldFileName = [NSString stringWithFormat:@"%@.%d.%@", + [[[self fileName] stringByDeletingPathExtension] stringByDeletingPathExtension], + backupIndex, + tempPathExtension]; + } + } + + // create the new name of the file + if ([tempPathExtension length] <= 0) { + tempNewFileName = [NSString stringWithFormat:@"%@.%d", + [[self fileName] stringByDeletingPathExtension], + (backupIndex + 1)]; + } else { + tempNewFileName = [NSString stringWithFormat:@"%@.%d.%@", + [[[self fileName] stringByDeletingPathExtension] stringByDeletingPathExtension], + (backupIndex + 1), tempPathExtension]; + } + + // if the new file name already exists, recursively call this method with the new file name's backup index + if ([fileManager fileExistsAtPath:tempNewFileName]) { + [self renameLogFile:(backupIndex + 1)]; + } + + // rename the old file + if (![fileManager moveItemAtPath:tempOldFileName toPath:tempNewFileName error:nil]) { + [L4LogLog error:[NSString stringWithFormat:@"Unable to move file %@ to %@!", tempOldFileName, tempNewFileName]]; + } + } +} +@end diff --git a/mac/TeamTalk/Libraries/Log4Cocoa/L4RootLogger.h b/mac/TeamTalk/Libraries/Log4Cocoa/L4RootLogger.h new file mode 100644 index 000000000..b0d2d62e5 --- /dev/null +++ b/mac/TeamTalk/Libraries/Log4Cocoa/L4RootLogger.h @@ -0,0 +1,25 @@ +#import +#import "L4Logger.h" + +@class L4Level; + +/** + * This class serves as the root of the logging infrastructure; the logger that is typically + * the first created when the logging system is initialized. + */ +@interface L4RootLogger : L4Logger + +/** + * Initialize the new instace with a specified level. + * @param aLevel the level to use at start. + */ +- (id)initWithLevel:(L4Level *)aLevel; + +/** + * Access the level of this logger. + * @return the current level for this logger. + */ +- (L4Level *)effectiveLevel; + +@end +// For copyright & license, see LICENSE. diff --git a/mac/TeamTalk/Libraries/Log4Cocoa/L4RootLogger.m b/mac/TeamTalk/Libraries/Log4Cocoa/L4RootLogger.m new file mode 100644 index 000000000..c3618c1fd --- /dev/null +++ b/mac/TeamTalk/Libraries/Log4Cocoa/L4RootLogger.m @@ -0,0 +1,32 @@ +// For copyright & license, see LICENSE. + +#import "L4RootLogger.h" +#import "L4LogLog.h" +#import "L4Level.h" + +@implementation L4RootLogger + +- (id) initWithLevel:(L4Level *)aLevel +{ + self = [super initWithName: @"root"]; + if (self) { + self.level = aLevel; + } + return self; +} + +- (void)setLevel:(L4Level *)aLevel +{ + if (aLevel) { + super.level = aLevel; + } else { + [L4LogLog error: @"You have tried to set a null level to root"]; + } +} + +- (L4Level *) effectiveLevel +{ + return self.level; +} + +@end diff --git a/mac/TeamTalk/Libraries/Log4Cocoa/L4SimpleLayout.h b/mac/TeamTalk/Libraries/Log4Cocoa/L4SimpleLayout.h new file mode 100644 index 000000000..06a724fb0 --- /dev/null +++ b/mac/TeamTalk/Libraries/Log4Cocoa/L4SimpleLayout.h @@ -0,0 +1,22 @@ +// For copyright & license, see LICENSE. + +#import +#import "L4Layout.h" + +/** + * A simple layout. + * This class will format an event in the form: + * "%@ - %ldms (%@:%@) %@ - %@" + * the six substitutions are: + * 1) the level of the event. + * 2) the milliseconds since the app was started. + * 3) the name of the file (implementation) the event was loggged from. + * 4) the line number in the file the event was logged from. + * 5) the name of the method the event was logged from. + * 6) the message of the event, if supplied to the log message. + */ +@interface L4SimpleLayout : L4Layout + + +@end + diff --git a/mac/TeamTalk/Libraries/Log4Cocoa/L4SimpleLayout.m b/mac/TeamTalk/Libraries/Log4Cocoa/L4SimpleLayout.m new file mode 100644 index 000000000..7571e231d --- /dev/null +++ b/mac/TeamTalk/Libraries/Log4Cocoa/L4SimpleLayout.m @@ -0,0 +1,31 @@ +/** + * For copyright & license, see LICENSE. + */ + +#import "L4SimpleLayout.h" +#import "L4LogEvent.h" +#import "L4Level.h" + +@implementation L4SimpleLayout + +- (NSString *)format:(L4LogEvent *)event +{ + NSDateFormatter *df = [[NSDateFormatter alloc] init]; + [df setDateFormat:@"YYYY-MM-dd HH:mm:ss.SSS"]; + NSString *timestamp = [df stringFromDate:[NSDate date]]; + + return [NSString stringWithFormat:@"%@ - %@ - %@", + timestamp, + event.level.stringValue, + event.renderedMessage]; + + /*return [NSString stringWithFormat:@"%@ - %ldms (%@:%@) %@ - %@", + event.level.stringValue, + event.millisSinceStart, + event.fileName, + event.lineNumber, + event.methodName, + event.renderedMessage];*/ +} + +@end diff --git a/mac/TeamTalk/Libraries/Log4Cocoa/L4StringMatchFilter.h b/mac/TeamTalk/Libraries/Log4Cocoa/L4StringMatchFilter.h new file mode 100644 index 000000000..1e959e440 --- /dev/null +++ b/mac/TeamTalk/Libraries/Log4Cocoa/L4StringMatchFilter.h @@ -0,0 +1,52 @@ +#import +#import "L4Filter.h" + + +/* + * This is a very simple filter based on string matching. + * + * The filter admits two options StringToMatch and AcceptOnMatch. + * + * If there is a match between the value of the StringToMatch option and the message of the L4LoggingEvent, then the + * decide(L4LoggingEvent) method returns L4FilterAccept if the AcceptOnMatch option value is YES/TRUE, if it is + * NO/FALSE, then L4FilterDeny is returned. If there is no match, L4FilterNeutral is returned. + */ +@interface L4StringMatchFilter : L4Filter { + BOOL acceptOnMatch; /**< YES to allow logging on a match, NO to prevent logging on a match. */ + NSString *stringToMatch; /**< The string that the logging events message must contain to match this filter. */ +} + +/** + * Initializes an instance from properties. The properties supported are: + * - AcceptOnMatch: a string that get's converted to a BOOL. YES/NO work well. See the documentation for [NSString + * boolValue] for other options. + * - StringToMatch: the string that the logging events message must contain to match this filter. + * + * @param initProperties the proterties to use. + * @throw L4PropertyMissingException if the StringToMatch property is missing. + */ +- (id) initWithProperties:(L4Properties *)initProperties; + +/** + * Initialze a new instance with the given values. + * This is the default initializer, as the instance should have these two values set. + * + * @param shouldAccept YES to allow logging on a match of levelToMatch, NO to prevent logging on a match. + * @param aString the string that the logging events message must contain to match this filter. + * @throw NSInvalidArgumentException if aString is nil. + */ +- (id) initWithAcceptOnMatch:(BOOL)shouldAccept stringToMatch:(NSString *)aString; + + +/** + * Accessor for the acceptOnMatch property. + */ +- (BOOL) acceptOnMatch; + +/** + * Accessor for the stringToMatch property. + */ +- (NSString *) stringToMatch; + +@end +// For copyright & license, see LICENSE. diff --git a/mac/TeamTalk/Libraries/Log4Cocoa/L4StringMatchFilter.m b/mac/TeamTalk/Libraries/Log4Cocoa/L4StringMatchFilter.m new file mode 100644 index 000000000..82ed49731 --- /dev/null +++ b/mac/TeamTalk/Libraries/Log4Cocoa/L4StringMatchFilter.m @@ -0,0 +1,66 @@ +/** + * For copyright & license, see LICENSE. + */ + +#import "L4StringMatchFilter.h" +#import "L4LogEvent.h" +#import "L4Properties.h" + +@implementation L4StringMatchFilter + +- (id) initWithAcceptOnMatch:(BOOL)shouldAccept stringToMatch:(NSString *)aString +{ + self = [super init]; + if (self) { + acceptOnMatch = shouldAccept; + if (aString == nil || [aString length] == 0) { + self = nil; + [NSException raise:NSInvalidArgumentException format:@"aString is not allowed to be nil."]; + } else { + stringToMatch = aString; + } + } + return self; +} + +-(id) initWithProperties:(L4Properties *) initProperties +{ + self = [super initWithProperties:initProperties]; + if (self != nil) { + NSString *acceptIfMatched = [initProperties stringForKey:@"AcceptOnMatch"]; + acceptOnMatch = YES; + + if (acceptIfMatched) { + acceptOnMatch = [acceptIfMatched boolValue]; + } + + stringToMatch = [initProperties stringForKey:@"StringToMatch"]; + if (stringToMatch == nil) { + [NSException raise:L4PropertyMissingException format:@"StringToMatch is a required property."]; + } + } + return self; +} + + +-(BOOL) acceptOnMatch +{ + return acceptOnMatch; +} + +-(NSString *) stringToMatch +{ + return stringToMatch; +} + +-(L4FilterResult) decide:(L4LogEvent *) logEvent +{ + L4FilterResult filterResult = L4FilterNeutral; + if ([logEvent message] != nil && [[logEvent message] rangeOfString:stringToMatch].location != NSNotFound) { + filterResult = (acceptOnMatch ? L4FilterAccept : L4FilterDeny); + } + + return filterResult; +} + +@end diff --git a/mac/TeamTalk/Libraries/Log4Cocoa/L4WriterAppender.h b/mac/TeamTalk/Libraries/Log4Cocoa/L4WriterAppender.h new file mode 100644 index 000000000..97a2b375d --- /dev/null +++ b/mac/TeamTalk/Libraries/Log4Cocoa/L4WriterAppender.h @@ -0,0 +1,127 @@ +#import +#import "L4AppenderProtocols.h" +#import "L4AppenderSkeleton.h" + +/** + * An extension of L4Appender that knows how to append by writing to a filehandle. + */ +@interface L4WriterAppender : L4AppenderSkeleton { + NSFileHandle *_fileHandle; /**< The file we are writing to.*/ +} + +/** Flush after write; default is YES. */ +@property BOOL immediateFlush; + +/** The string encoding to use; default is lossy ASCII.*/ +@property NSStringEncoding encoding; + +/** Whether to allow lossy string encoding; default is YES.*/ +@property BOOL lossyEncoding; + +/** + * Default init method. + * @return the new instance. + */ +- (id)init; + +/** + * Creates a new appneder with the provided info. + * @param aLayout the layout to use for this appender. + * @param aFileHandle an exisiting file handle to write to. + * @return the new instance. + */ +- (id)initWithLayout:(L4Layout *)aLayout fileHandle:(NSFileHandle *)aFileHandle; + +/** + * Initializes an instance from properties. The properties supported are: + * - ImmediateFlush: see setImmediateFlush: + * If the values are being set in a file, this is how they could look: + * log4cocoa.appender.A2.ImmediateFlush=false + * @param initProperties the proterties to use. + */ +- (id)initWithProperties:(L4Properties *)initProperties; + +/** + * Reminder: the nesting of calls is: + * + * doAppend() + * - check threshold + * - filter + * - append(); + * - checkEntryConditions(); + * - subAppend(); + */ +- (void)append:(L4LogEvent *)anEvent; + +/** + * Actual writing occurs here. + * + *

Most subclasses of WriterAppender will need to + * override this method. + */ +- (void)subAppend:(L4LogEvent *)anEvent; + +/** + * NOTE --- this method adds a lineBreakChar between log messages. + * So layouts & log messages do not need to add a trailing line break. + */ +- (void)write:(NSString *)theString; + +/** + * Sets the NSFileHandle where the log output will go. + * @param fh The NSFileHandle where you want the log output to go. + */ +- (void)setFileHandle:(NSFileHandle *)fh; + +/** + * This method determines if there is a sense in attempting to append. + * + *

It checks whether there is a set output target and also if + * there is a set layout. If these checks fail, then the boolean + * value false is returned. + */ +- (BOOL) checkEntryConditions; + +/** + * Close the writer. + * This method will close the file handle associated with this appender. Any further + * use of the appender will cause an error. + */ +- (void) closeWriter; +/** + * Close the writer. + * This method will close the file handle associated with this appender. Any further + * use of the appender will cause an error. + */ +- (void) reset; + +/** + * Write the header. + * This method causes the header of the associated layout to be written to the log file. + */ +- (void) writeHeader; + +/** + * Write the footer. + * This method causes the footer of the associated layout to be written to the log file. + */ +- (void) writeFooter; + +@end + +/** + * The methods needed to conform to the L4AppenderCategory catagory. + */ +@interface L4WriterAppender (L4AppenderCategory) +/** + * Causes this writer to close. + */ +- (void) close; + +/** + * Determines if this appender requires a layout. + */ +- (BOOL) requiresLayout; + +@end +// For copyright & license, see LICENSE. diff --git a/mac/TeamTalk/Libraries/Log4Cocoa/L4WriterAppender.m b/mac/TeamTalk/Libraries/Log4Cocoa/L4WriterAppender.m new file mode 100644 index 000000000..f9029c27b --- /dev/null +++ b/mac/TeamTalk/Libraries/Log4Cocoa/L4WriterAppender.m @@ -0,0 +1,169 @@ +// For copyright & license, see LICENSE. + +#import "L4WriterAppender.h" +#import "L4Layout.h" +#import "L4LogEvent.h" +#import "L4LogLog.h" +#import "L4Properties.h" + +static NSData *lineBreakChar; + +@implementation L4WriterAppender + ++ (void)initialize +{ + lineBreakChar = [@"\n" dataUsingEncoding:NSASCIIStringEncoding allowLossyConversion:YES]; +} + +- (id) init +{ + self = [super init]; + if (self) { + _immediateFlush = YES; + _lossyEncoding = YES; + _encoding = NSUTF8StringEncoding; + } + return self; +} + +- (id) initWithProperties:(L4Properties *) initProperties +{ + self = [super initWithProperties:initProperties]; + + if (self) { + BOOL newImmediateFlush = YES; + + // Support for appender.ImmediateFlush in properties configuration file + if ([initProperties stringForKey:@"ImmediateFlush"]) { + NSString *buf = [[initProperties stringForKey:@"ImmediateFlush"] lowercaseString]; + newImmediateFlush = [buf isEqualToString:@"true"]; + } + + self.immediateFlush = newImmediateFlush; + _lossyEncoding = YES; + _encoding = NSUTF8StringEncoding; + } + + return self; +} + +- (id) initWithLayout:(L4Layout *)aLayout fileHandle:(NSFileHandle *)aFileHandle +{ + self = [super init]; + if (self) { + self.layout = aLayout; + _fileHandle = aFileHandle; + _immediateFlush = YES; + _lossyEncoding = YES; + _encoding = NSUTF8StringEncoding; + } + return self; +} + +- (void)append:(L4LogEvent *)anEvent +{ + @synchronized(self) { + if ([self checkEntryConditions]) { + [self subAppend:anEvent]; + } + } +} + +- (void)subAppend:(L4LogEvent *)anEvent +{ + [self write:[self.layout format:anEvent]]; +} + +- (BOOL) checkEntryConditions +{ + if (_closed) { + [L4LogLog warn:@"Not allowed to write to a closed appender."]; + return NO; + } + + if (!_fileHandle) { + [L4LogLog error:[@"No file handle for output stream set for the appender named:" stringByAppendingString:self.name]]; + return NO; + } + + if (!self.layout) { + [L4LogLog error:[@"No layout set for the appender named:" stringByAppendingString:self.name]]; + return NO; + } + + return YES; +} + +- (void) closeWriter +{ + @try { + [_fileHandle closeFile]; + } + @catch (NSException *localException) { + [L4LogLog error:[NSString stringWithFormat:@"Could not close file handle:%@\n%@", _fileHandle, localException]]; + } +} + +- (void)setFileHandle:(NSFileHandle*)fh +{ + @synchronized(self) { + if (_fileHandle != fh) { + [self closeWriter]; + _fileHandle = fh; + } + } +} + +- (void) reset +{ + [self closeWriter]; +} + +- (void) write:(NSString *)string +{ + if (string) { + @try { + @synchronized(self) { + // TODO ### -- NEED UNIX EXPERT IS THIS THE BEST WAY ?? + // TODO - ### - NEED TO WORK ON ENCODING ISSUES (& THEN LATER LOCALIZATION) + // + [_fileHandle writeData:[string dataUsingEncoding:_encoding allowLossyConversion:_lossyEncoding]]; + [_fileHandle writeData:lineBreakChar]; + } + } + @catch (NSException *localException) { + [L4LogLog error:[NSString stringWithFormat:@"Appender failed to write string:%@\n%@", string, localException]]; + } + } +} + +- (void) writeHeader +{ + [self write:[self.layout header]]; +} + +- (void) writeFooter +{ + [self write:[self.layout footer]]; +} + + +#pragma mark - L4AppenderCategory methods + +- (void) close +{ + @synchronized(self) { + if (!_closed) { + _closed = YES; + [self writeFooter]; + [self reset]; + } + } +} + +- (BOOL) requiresLayout +{ + return YES; +} + +@end diff --git a/mac/TeamTalk/Libraries/Log4Cocoa/L4XMLLayout.h b/mac/TeamTalk/Libraries/Log4Cocoa/L4XMLLayout.h new file mode 100644 index 000000000..1ec660e69 --- /dev/null +++ b/mac/TeamTalk/Libraries/Log4Cocoa/L4XMLLayout.h @@ -0,0 +1,10 @@ + +#import + +#import "L4Layout.h" + +@interface L4XMLLayout : L4Layout + ++ (instancetype)XMLLayout; + +@end diff --git a/mac/TeamTalk/Libraries/Log4Cocoa/L4XMLLayout.m b/mac/TeamTalk/Libraries/Log4Cocoa/L4XMLLayout.m new file mode 100644 index 000000000..0253a19dd --- /dev/null +++ b/mac/TeamTalk/Libraries/Log4Cocoa/L4XMLLayout.m @@ -0,0 +1,39 @@ +/** + * For copyright & license, see LICENSE + */ + +#import "L4XMLLayout.h" + +#import "L4LogEvent.h" +#import "L4Logger.h" + +@implementation L4XMLLayout + ++ (instancetype)XMLLayout +{ + return [[L4XMLLayout alloc] init]; +} + +- (NSString *)format:(L4LogEvent *) event +{ + NSMutableString *formattedEventString = [[NSMutableString alloc] initWithCapacity:1024]; + + [formattedEventString appendFormat:@"\n", + event.logger.name, + event.millisSinceStart, + event.level.stringValue]; + + [formattedEventString appendFormat:@"\t%@:%@\n", event.fileName, event.lineNumber]; + [formattedEventString appendFormat:@"\t%@\n", event.methodName]; + [formattedEventString appendFormat:@"\t%@\n", event.renderedMessage]; + + [formattedEventString appendFormat:@"\n"]; + + return formattedEventString; +} + +- (NSString *)contentType { + return @"application/xml"; +} + +@end diff --git a/mac/TeamTalk/Libraries/Log4Cocoa/Log4Cocoa-Prefix.pch b/mac/TeamTalk/Libraries/Log4Cocoa/Log4Cocoa-Prefix.pch new file mode 100644 index 000000000..1e196852b --- /dev/null +++ b/mac/TeamTalk/Libraries/Log4Cocoa/Log4Cocoa-Prefix.pch @@ -0,0 +1,7 @@ +// +// Prefix header for all source files of the 'Log4Cocoa' target in the 'Log4Cocoa' project +// + +#ifdef __OBJC__ + #import +#endif diff --git a/mac/TeamTalk/Libraries/Log4Cocoa/Log4Cocoa.h b/mac/TeamTalk/Libraries/Log4Cocoa/Log4Cocoa.h new file mode 100644 index 000000000..c72714df7 --- /dev/null +++ b/mac/TeamTalk/Libraries/Log4Cocoa/Log4Cocoa.h @@ -0,0 +1,36 @@ +/** + * For copyright & license, see LICENSE. + */ + +#import + +#import "L4AppenderAttachable.h" +#import "L4AppenderProtocols.h" +#import "L4AppenderSkeleton.h" +#import "L4BasicConfigurator.h" +#import "L4ConsoleAppender.h" +#import "L4DenyAllFilter.h" +#import "L4FileAppender.h" +#import "L4Filter.h" +#import "L4JSONLayout.h" +#import "L4Layout.h" +#import "L4Level.h" +#import "L4LevelMatchFilter.h" +#import "L4LevelRangeFilter.h" +#import "L4Logger.h" +#import "L4Logging.h" +#import "L4LoggerProtocols.h" +#import "L4LoggerStore.h" +#import "L4LogEvent.h" +#import "L4PatternLayout.h" +#import "L4Properties.h" +#import "L4PropertyConfigurator.h" +#import "L4RollingFileAppender.h" +#import "L4DailyRollingFileAppender.h" +#import "L4RootLogger.h" +#import "L4SimpleLayout.h" +#import "L4StringMatchFilter.h" +#import "L4WriterAppender.h" +#import "L4XMLLayout.h" +#import "Log4CocoaDefines.h" +#import "NSObject+Log4Cocoa.h" diff --git a/mac/TeamTalk/Libraries/Log4Cocoa/Log4CocoaDefines.h b/mac/TeamTalk/Libraries/Log4Cocoa/Log4CocoaDefines.h new file mode 100644 index 000000000..b0c3e4ce3 --- /dev/null +++ b/mac/TeamTalk/Libraries/Log4Cocoa/Log4CocoaDefines.h @@ -0,0 +1,24 @@ +/** + * For copyright & license, see LICENSE. + */ + +#ifndef _LOG4COCOADEFINES_H +#define _LOG4COCOADEFINES_H + +#import + + +// +// defs for externs +// + +#ifdef __cplusplus +#define LOG4COCOA_EXTERN extern "C" +#define LOG4COCOA_PRIVATE_EXTERN __private_extern__ +#else +#define LOG4COCOA_EXTERN extern +#define LOG4COCOA_PRIVATE_EXTERN __private_extern__ +#endif + +#endif // _LOG4COCOADEFINES_H + diff --git a/mac/TeamTalk/Libraries/Log4Cocoa/NSObject+Log4Cocoa.h b/mac/TeamTalk/Libraries/Log4Cocoa/NSObject+Log4Cocoa.h new file mode 100644 index 000000000..1c102c3c1 --- /dev/null +++ b/mac/TeamTalk/Libraries/Log4Cocoa/NSObject+Log4Cocoa.h @@ -0,0 +1,55 @@ +// For copyright & license, see LICENSE. + +#import +@class L4Logger; + +/** + * Convience methods for all NSObject classes. + * This catagory provedes methods to obtain an L4Logger instance from all classes and instances. + * You may want to override these methods in your local base class and provide caching local iVar, + * since these methods result in an NSDictionary lookup each time they are called. Actually it's + * not a bad hit, but in a high volume logging environment, it might make a difference. + * + * Here is an example of what that might look like: + * + * CODE TO ADD TO YOUR BASE CLASS .h file declarations + * \code + * L4Logger *myLoggerIVar; // instance variable + * \endcode + * + * CODE TO ADD TO YOUR BASE CLASS .m file + * \code + * static L4Logger *myLoggerClassVar; // static "class" variable + * + * + (L4Logger *) log + * { + * if( myLoggerClassVar == nil ) { + * myLoggerClassVar = [super l4Logger]; + * } + * + * return myLoggerClassVar; + * } + * + * - (L4Logger *) log + * { + * if( myLoggerIVar == nil ) { + * myLoggerIVar = [super l4Logger]; + * } + * + vreturn myLoggerIVar; + * } + * \endcode + */ +@interface NSObject (Log4Cocoa) + +/** + * Accessor for the L4Logger instance to be used from within class methods. + */ ++ (L4Logger *)l4Logger; + +/** + * Accessor for the L4Logger instance to be used from within instance methods. + * The default implementation returns the L4Logger for the class. + */ +- (L4Logger *)l4Logger; +@end diff --git a/mac/TeamTalk/Libraries/Log4Cocoa/NSObject+Log4Cocoa.m b/mac/TeamTalk/Libraries/Log4Cocoa/NSObject+Log4Cocoa.m new file mode 100644 index 000000000..850104ff1 --- /dev/null +++ b/mac/TeamTalk/Libraries/Log4Cocoa/NSObject+Log4Cocoa.m @@ -0,0 +1,21 @@ +/** + * For copyright & license, see LICENSE. + */ + +#import "NSObject+Log4Cocoa.h" +#import "L4Logger.h" + + +@implementation NSObject (Log4Cocoa) + ++ (L4Logger *)l4Logger +{ + return [L4Logger loggerForClass:(Class) self]; +} + +- (L4Logger *)l4Logger +{ + return [L4Logger loggerForClass:[self class]]; +} + +@end diff --git a/mac/TeamTalk/Libraries/Reachability/Reachability.h b/mac/TeamTalk/Libraries/Reachability/Reachability.h new file mode 100755 index 000000000..211b8166f --- /dev/null +++ b/mac/TeamTalk/Libraries/Reachability/Reachability.h @@ -0,0 +1,109 @@ +/* + Copyright (c) 2011, Tony Million. + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + + 1. Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + + 2. Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + POSSIBILITY OF SUCH DAMAGE. + */ + +#import +#import + +#import +#import +#import +#import +#import +#import + +/** + * Does ARC support GCD objects? + * It does if the minimum deployment target is iOS 6+ or Mac OS X 8+ + * + * @see http://opensource.apple.com/source/libdispatch/libdispatch-228.18/os/object.h + **/ +#if OS_OBJECT_USE_OBJC +#define NEEDS_DISPATCH_RETAIN_RELEASE 0 +#else +#define NEEDS_DISPATCH_RETAIN_RELEASE 1 +#endif + +/** + * Create NS_ENUM macro if it does not exist on the targeted version of iOS or OS X. + * + * @see http://nshipster.com/ns_enum-ns_options/ + **/ +#ifndef NS_ENUM +#define NS_ENUM(_type, _name) enum _name : _type _name; enum _name : _type +#endif + +extern NSString *const kReachabilityChangedNotification; + +typedef NS_ENUM(NSInteger, NetworkStatus) { + // Apple NetworkStatus Compatible Names. + NotReachable = 0, + ReachableViaWiFi = 2, + ReachableViaWWAN = 1 +}; + +@class Reachability; + +typedef void (^NetworkReachable)(Reachability * reachability); +typedef void (^NetworkUnreachable)(Reachability * reachability); + +@interface Reachability : NSObject + +@property (nonatomic, copy) NetworkReachable reachableBlock; +@property (nonatomic, copy) NetworkUnreachable unreachableBlock; + + +@property (nonatomic, assign) BOOL reachableOnWWAN; + ++(Reachability*)reachabilityWithHostname:(NSString*)hostname; ++(Reachability*)reachabilityForInternetConnection; ++(Reachability*)reachabilityWithAddress:(const struct sockaddr_in*)hostAddress; ++(Reachability*)reachabilityForLocalWiFi; + +-(Reachability *)initWithReachabilityRef:(SCNetworkReachabilityRef)ref; + +-(BOOL)startNotifier; +-(void)stopNotifier; + +-(BOOL)isReachable; +-(BOOL)isReachableViaWWAN; +-(BOOL)isReachableViaWiFi; + +// WWAN may be available, but not active until a connection has been established. +// WiFi may require a connection for VPN on Demand. +-(BOOL)isConnectionRequired; // Identical DDG variant. +-(BOOL)connectionRequired; // Apple's routine. +// Dynamic, on demand connection? +-(BOOL)isConnectionOnDemand; +// Is user intervention required? +-(BOOL)isInterventionRequired; + +-(NetworkStatus)currentReachabilityStatus; +-(SCNetworkReachabilityFlags)reachabilityFlags; +-(NSString*)currentReachabilityString; +-(NSString*)currentReachabilityFlags; + +@end diff --git a/mac/TeamTalk/Libraries/Reachability/Reachability.m b/mac/TeamTalk/Libraries/Reachability/Reachability.m new file mode 100755 index 000000000..9a1a2ff03 --- /dev/null +++ b/mac/TeamTalk/Libraries/Reachability/Reachability.m @@ -0,0 +1,527 @@ +/* + Copyright (c) 2011, Tony Million. + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + + 1. Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + + 2. Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + POSSIBILITY OF SUCH DAMAGE. + */ + +#import "Reachability.h" + + +NSString *const kReachabilityChangedNotification = @"kReachabilityChangedNotification"; + +@interface Reachability () + +@property (nonatomic, assign) SCNetworkReachabilityRef reachabilityRef; + + +#if NEEDS_DISPATCH_RETAIN_RELEASE +@property (nonatomic, assign) dispatch_queue_t reachabilitySerialQueue; +#else +@property (nonatomic, strong) dispatch_queue_t reachabilitySerialQueue; +#endif + + +@property (nonatomic, strong) id reachabilityObject; + +-(void)reachabilityChanged:(SCNetworkReachabilityFlags)flags; +-(BOOL)isReachableWithFlags:(SCNetworkReachabilityFlags)flags; + +@end + +static NSString *reachabilityFlags(SCNetworkReachabilityFlags flags) +{ + return [NSString stringWithFormat:@"%c%c %c%c%c%c%c%c%c", +#if TARGET_OS_IPHONE + (flags & kSCNetworkReachabilityFlagsIsWWAN) ? 'W' : '-', +#else + 'X', +#endif + (flags & kSCNetworkReachabilityFlagsReachable) ? 'R' : '-', + (flags & kSCNetworkReachabilityFlagsConnectionRequired) ? 'c' : '-', + (flags & kSCNetworkReachabilityFlagsTransientConnection) ? 't' : '-', + (flags & kSCNetworkReachabilityFlagsInterventionRequired) ? 'i' : '-', + (flags & kSCNetworkReachabilityFlagsConnectionOnTraffic) ? 'C' : '-', + (flags & kSCNetworkReachabilityFlagsConnectionOnDemand) ? 'D' : '-', + (flags & kSCNetworkReachabilityFlagsIsLocalAddress) ? 'l' : '-', + (flags & kSCNetworkReachabilityFlagsIsDirect) ? 'd' : '-']; +} + +// Start listening for reachability notifications on the current run loop +static void TMReachabilityCallback(SCNetworkReachabilityRef target, SCNetworkReachabilityFlags flags, void* info) +{ +#pragma unused (target) +#if __has_feature(objc_arc) + Reachability *reachability = ((__bridge Reachability*)info); +#else + Reachability *reachability = ((Reachability*)info); +#endif + + // We probably don't need an autoreleasepool here, as GCD docs state each queue has its own autorelease pool, + // but what the heck eh? + @autoreleasepool + { + [reachability reachabilityChanged:flags]; + } +} + + +@implementation Reachability + +@synthesize reachabilityRef; +@synthesize reachabilitySerialQueue; + +@synthesize reachableOnWWAN; + +@synthesize reachableBlock; +@synthesize unreachableBlock; + +@synthesize reachabilityObject; + +#pragma mark - Class Constructor Methods + ++(Reachability*)reachabilityWithHostName:(NSString*)hostname +{ + return [Reachability reachabilityWithHostname:hostname]; +} + ++(Reachability*)reachabilityWithHostname:(NSString*)hostname +{ + SCNetworkReachabilityRef ref = SCNetworkReachabilityCreateWithName(NULL, [hostname UTF8String]); + if (ref) + { + id reachability = [[self alloc] initWithReachabilityRef:ref]; + +#if __has_feature(objc_arc) + return reachability; +#else + return [reachability autorelease]; +#endif + + } + + return nil; +} + ++(Reachability *)reachabilityWithAddress:(const struct sockaddr_in *)hostAddress +{ + SCNetworkReachabilityRef ref = SCNetworkReachabilityCreateWithAddress(kCFAllocatorDefault, (const struct sockaddr*)hostAddress); + if (ref) + { + id reachability = [[self alloc] initWithReachabilityRef:ref]; + +#if __has_feature(objc_arc) + return reachability; +#else + return [reachability autorelease]; +#endif + } + + return nil; +} + ++(Reachability *)reachabilityForInternetConnection +{ + struct sockaddr_in zeroAddress; + bzero(&zeroAddress, sizeof(zeroAddress)); + zeroAddress.sin_len = sizeof(zeroAddress); + zeroAddress.sin_family = AF_INET; + + return [self reachabilityWithAddress:&zeroAddress]; +} + ++(Reachability*)reachabilityForLocalWiFi +{ + struct sockaddr_in localWifiAddress; + bzero(&localWifiAddress, sizeof(localWifiAddress)); + localWifiAddress.sin_len = sizeof(localWifiAddress); + localWifiAddress.sin_family = AF_INET; + // IN_LINKLOCALNETNUM is defined in as 169.254.0.0 + localWifiAddress.sin_addr.s_addr = htonl(IN_LINKLOCALNETNUM); + + return [self reachabilityWithAddress:&localWifiAddress]; +} + + +// Initialization methods + +-(Reachability *)initWithReachabilityRef:(SCNetworkReachabilityRef)ref +{ + self = [super init]; + if (self != nil) + { + self.reachableOnWWAN = YES; + self.reachabilityRef = ref; + } + + return self; +} + +-(void)dealloc +{ + [self stopNotifier]; + + if(self.reachabilityRef) + { + CFRelease(self.reachabilityRef); + self.reachabilityRef = nil; + } + + self.reachableBlock = nil; + self.unreachableBlock = nil; + +#if !(__has_feature(objc_arc)) + [super dealloc]; +#endif + + +} + +#pragma mark - Notifier Methods + +// Notifier +// NOTE: This uses GCD to trigger the blocks - they *WILL NOT* be called on THE MAIN THREAD +// - In other words DO NOT DO ANY UI UPDATES IN THE BLOCKS. +// INSTEAD USE dispatch_async(dispatch_get_main_queue(), ^{UISTUFF}) (or dispatch_sync if you want) + +-(BOOL)startNotifier +{ + SCNetworkReachabilityContext context = { 0, NULL, NULL, NULL, NULL }; + + // this should do a retain on ourself, so as long as we're in notifier mode we shouldn't disappear out from under ourselves + // woah + self.reachabilityObject = self; + + + + // First, we need to create a serial queue. + // We allocate this once for the lifetime of the notifier. + self.reachabilitySerialQueue = dispatch_queue_create("com.tonymillion.reachability", NULL); + if(!self.reachabilitySerialQueue) + { + return NO; + } + +#if __has_feature(objc_arc) + context.info = (__bridge void *)self; +#else + context.info = (void *)self; +#endif + + if (!SCNetworkReachabilitySetCallback(self.reachabilityRef, TMReachabilityCallback, &context)) + { +#ifdef DEBUG + DDLog(@"SCNetworkReachabilitySetCallback() failed: %s", SCErrorString(SCError())); +#endif + + // Clear out the dispatch queue + if(self.reachabilitySerialQueue) + { +#if NEEDS_DISPATCH_RETAIN_RELEASE + dispatch_release(self.reachabilitySerialQueue); +#endif + self.reachabilitySerialQueue = nil; + } + + self.reachabilityObject = nil; + + return NO; + } + + // Set it as our reachability queue, which will retain the queue + if(!SCNetworkReachabilitySetDispatchQueue(self.reachabilityRef, self.reachabilitySerialQueue)) + { +#ifdef DEBUG + DDLog(@"SCNetworkReachabilitySetDispatchQueue() failed: %s", SCErrorString(SCError())); +#endif + + // UH OH - FAILURE! + + // First stop, any callbacks! + SCNetworkReachabilitySetCallback(self.reachabilityRef, NULL, NULL); + + // Then clear out the dispatch queue. + if(self.reachabilitySerialQueue) + { +#if NEEDS_DISPATCH_RETAIN_RELEASE + dispatch_release(self.reachabilitySerialQueue); +#endif + self.reachabilitySerialQueue = nil; + } + + self.reachabilityObject = nil; + + return NO; + } + + return YES; +} + +-(void)stopNotifier +{ + // First stop, any callbacks! + SCNetworkReachabilitySetCallback(self.reachabilityRef, NULL, NULL); + + // Unregister target from the GCD serial dispatch queue. + SCNetworkReachabilitySetDispatchQueue(self.reachabilityRef, NULL); + + if(self.reachabilitySerialQueue) + { +#if NEEDS_DISPATCH_RETAIN_RELEASE + dispatch_release(self.reachabilitySerialQueue); +#endif + self.reachabilitySerialQueue = nil; + } + + self.reachabilityObject = nil; +} + +#pragma mark - reachability tests + +// This is for the case where you flick the airplane mode; +// you end up getting something like this: +//Reachability: WR ct----- +//Reachability: -- ------- +//Reachability: WR ct----- +//Reachability: -- ------- +// We treat this as 4 UNREACHABLE triggers - really apple should do better than this + +#define testcase (kSCNetworkReachabilityFlagsConnectionRequired | kSCNetworkReachabilityFlagsTransientConnection) + +-(BOOL)isReachableWithFlags:(SCNetworkReachabilityFlags)flags +{ + BOOL connectionUP = YES; + + if(!(flags & kSCNetworkReachabilityFlagsReachable)) + connectionUP = NO; + + if( (flags & testcase) == testcase ) + connectionUP = NO; + +#if TARGET_OS_IPHONE + if(flags & kSCNetworkReachabilityFlagsIsWWAN) + { + // We're on 3G. + if(!self.reachableOnWWAN) + { + // We don't want to connect when on 3G. + connectionUP = NO; + } + } +#endif + + return connectionUP; +} + +-(BOOL)isReachable +{ + SCNetworkReachabilityFlags flags; + + if(!SCNetworkReachabilityGetFlags(self.reachabilityRef, &flags)) + return NO; + + return [self isReachableWithFlags:flags]; +} + +-(BOOL)isReachableViaWWAN +{ +#if TARGET_OS_IPHONE + + SCNetworkReachabilityFlags flags = 0; + + if(SCNetworkReachabilityGetFlags(reachabilityRef, &flags)) + { + // Check we're REACHABLE + if(flags & kSCNetworkReachabilityFlagsReachable) + { + // Now, check we're on WWAN + if(flags & kSCNetworkReachabilityFlagsIsWWAN) + { + return YES; + } + } + } +#endif + + return NO; +} + +-(BOOL)isReachableViaWiFi +{ + SCNetworkReachabilityFlags flags = 0; + + if(SCNetworkReachabilityGetFlags(reachabilityRef, &flags)) + { + // Check we're reachable + if((flags & kSCNetworkReachabilityFlagsReachable)) + { +#if TARGET_OS_IPHONE + // Check we're NOT on WWAN + if((flags & kSCNetworkReachabilityFlagsIsWWAN)) + { + return NO; + } +#endif + return YES; + } + } + + return NO; +} + + +// WWAN may be available, but not active until a connection has been established. +// WiFi may require a connection for VPN on Demand. +-(BOOL)isConnectionRequired +{ + return [self connectionRequired]; +} + +-(BOOL)connectionRequired +{ + SCNetworkReachabilityFlags flags; + + if(SCNetworkReachabilityGetFlags(reachabilityRef, &flags)) + { + return (flags & kSCNetworkReachabilityFlagsConnectionRequired); + } + + return NO; +} + +// Dynamic, on demand connection? +-(BOOL)isConnectionOnDemand +{ + SCNetworkReachabilityFlags flags; + + if (SCNetworkReachabilityGetFlags(reachabilityRef, &flags)) + { + return ((flags & kSCNetworkReachabilityFlagsConnectionRequired) && + (flags & (kSCNetworkReachabilityFlagsConnectionOnTraffic | kSCNetworkReachabilityFlagsConnectionOnDemand))); + } + + return NO; +} + +// Is user intervention required? +-(BOOL)isInterventionRequired +{ + SCNetworkReachabilityFlags flags; + + if (SCNetworkReachabilityGetFlags(reachabilityRef, &flags)) + { + return ((flags & kSCNetworkReachabilityFlagsConnectionRequired) && + (flags & kSCNetworkReachabilityFlagsInterventionRequired)); + } + + return NO; +} + + +#pragma mark - reachability status stuff + +-(NetworkStatus)currentReachabilityStatus +{ + if([self isReachable]) + { + if([self isReachableViaWiFi]) + return ReachableViaWiFi; + +#if TARGET_OS_IPHONE + return ReachableViaWWAN; +#endif + } + + return NotReachable; +} + +-(SCNetworkReachabilityFlags)reachabilityFlags +{ + SCNetworkReachabilityFlags flags = 0; + + if(SCNetworkReachabilityGetFlags(reachabilityRef, &flags)) + { + return flags; + } + + return 0; +} + +-(NSString*)currentReachabilityString +{ + NetworkStatus temp = [self currentReachabilityStatus]; + + if(temp == reachableOnWWAN) + { + // Updated for the fact that we have CDMA phones now! + return NSLocalizedString(@"Cellular", @""); + } + if (temp == ReachableViaWiFi) + { + return NSLocalizedString(@"WiFi", @""); + } + + return NSLocalizedString(@"No Connection", @""); +} + +-(NSString*)currentReachabilityFlags +{ + return reachabilityFlags([self reachabilityFlags]); +} + +#pragma mark - Callback function calls this method + +-(void)reachabilityChanged:(SCNetworkReachabilityFlags)flags +{ + if([self isReachableWithFlags:flags]) + { + if(self.reachableBlock) + { + self.reachableBlock(self); + } + } + else + { + if(self.unreachableBlock) + { + self.unreachableBlock(self); + } + } + + // this makes sure the change notification happens on the MAIN THREAD + dispatch_async(dispatch_get_main_queue(), ^{ + [[NSNotificationCenter defaultCenter] postNotificationName:kReachabilityChangedNotification + object:self]; + }); +} + +#pragma mark - Debug Description + +- (NSString *) description +{ + NSString *description = [NSString stringWithFormat:@"<%@: %#x>", + NSStringFromClass([self class]), (unsigned int) self]; + return description; +} + +@end diff --git a/mac/TeamTalk/Libraries/Speex/speexdec b/mac/TeamTalk/Libraries/Speex/speexdec new file mode 100755 index 000000000..11236e6b0 Binary files /dev/null and b/mac/TeamTalk/Libraries/Speex/speexdec differ diff --git a/mac/TeamTalk/Libraries/Speex/speexenc b/mac/TeamTalk/Libraries/Speex/speexenc new file mode 100755 index 000000000..b7939a984 Binary files /dev/null and b/mac/TeamTalk/Libraries/Speex/speexenc differ diff --git a/mac/TeamTalk/Libraries/libsecurity/security.h b/mac/TeamTalk/Libraries/libsecurity/security.h new file mode 100644 index 000000000..782cee369 --- /dev/null +++ b/mac/TeamTalk/Libraries/libsecurity/security.h @@ -0,0 +1,98 @@ +/*================================================================ +* Copyright (C) 2015 All rights reserved. +* +* 文件名称:security.h +* 创 建 者:Zhang Yuanhao +* 邮 箱:bluefoxah@gmail.com +* 创建日期:2015年01月29日 +* 描 述: +* +#pragma once +================================================================*/ + +#ifndef __SECURITY_H__ +#define __SECURITY_H__ + + +#ifdef _WIN32 +typedef char int8_t; +typedef short int16_t; +typedef int int32_t; +typedef long long int64_t; +typedef unsigned char uint8_t; +typedef unsigned short uint16_t; +typedef unsigned int uint32_t; +typedef unsigned long long uint64_t; +typedef int socklen_t; +#else +#include +#endif +typedef unsigned char uchar_t; + +#ifdef WIN32 +#define DLL_MODIFIER __declspec(dllexport) +#else +#define DLL_MODIFIER +#endif + + +#ifdef __cplusplus +extern "C" { +#endif + +#ifdef __ANDROID__ + jbyteArray Java_com_mogujie_tt_Security_EncryptMsg(JNIEnv* env, jobject obj, jstring jstr); + jbyteArray Java_com_mogujie_tt_Security_DecryptMsg(JNIEnv* env, jobject obj, jstring jstr); + jbyteArray Java_com_mogujie_tt_Security_EncryptPass(JNIEnv* env, jobject obj, jstring jstr); + +#else + /** + * 对消息加密 + * + * @param pInData 待加密的消息内容指针 + * @param nInLen 待加密消息内容长度 + * @param pOutData 加密后的文本 + * @param nOutLen 加密后的文本长度 + * + * @return 返回 0-成功; 其他-失败 + */ + DLL_MODIFIER int EncryptMsg(const char* pInData, uint32_t nInLen, char** pOutData, uint32_t& nOutLen); + + /** + * 对消息解密 + * + * @param pInData 待解密的消息内容指针 + * @param nInLen 待解密消息内容长度 + * @param pOutData 解密后的文本 + * @param nOutLen 解密后的文本长度 + * + * @return 返回 0-成功; 其他-失败 + */ + DLL_MODIFIER int DecryptMsg(const char* pInData, uint32_t nInLen, char** pOutData, uint32_t& nOutLen); + + /** + * 对密码进行加密 + * + * @param pInData 待解密的消息内容指针 + * @param nInLen 待解密消息内容长度 + * @param pOutData 解密后的文本 + * @param nOutLen 解密后的文本长度 + * @param pKey 32位密钥 + * + * @return 返回 0-成功; 其他-失败 + */ + DLL_MODIFIER int EncryptPass(const char* pInData, uint32_t nInLen, char** pOutData, uint32_t& nOutLen); + /** + * 释放资源 + * + * @param pOutData 需要释放的资源 + */ + DLL_MODIFIER void Free(char* pOutData); + +#endif + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/mac/TeamTalk/MD5.h b/mac/TeamTalk/MD5.h new file mode 100755 index 000000000..6820d6fa4 --- /dev/null +++ b/mac/TeamTalk/MD5.h @@ -0,0 +1,16 @@ +// +// MD5.h +// Pet +// +// Created by Cecil on 11-1-26. +// Copyright 2011 __MyCompanyName__. All rights reserved. +// + +#import + +@interface NSString (MyExtensions) + +- (NSString *)md5; +- (NSString *)stringWithPercentEscape; + +@end \ No newline at end of file diff --git a/mac/TeamTalk/MD5.m b/mac/TeamTalk/MD5.m new file mode 100755 index 000000000..4a8912386 --- /dev/null +++ b/mac/TeamTalk/MD5.m @@ -0,0 +1,33 @@ +// +// MD5.m +// Pet +// +// Created by Cecil on 11-1-26. +// Copyright 2011 __MyCompanyName__. All rights reserved. +// + +#import "MD5.h" +#import + +@implementation NSString (MyExtensions) + +- (NSString *)md5 +{ + const char *cStr = [self UTF8String]; + unsigned char result[16]; + CC_MD5( cStr, strlen(cStr), result ); // This is the md5 call + return [NSString stringWithFormat: + @"%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x", + result[0], result[1], result[2], result[3], + result[4], result[5], result[6], result[7], + result[8], result[9], result[10], result[11], + result[12], result[13], result[14], result[15] + ]; +} + +- (NSString *)stringWithPercentEscape +{ + return CFBridgingRelease(CFURLCreateStringByAddingPercentEscapes(NULL, (__bridge CFStringRef)([self mutableCopy]), NULL, CFSTR("%"), kCFStringEncodingUTF8)); +} + +@end diff --git a/mac/TeamTalk/MTDraftManager.h b/mac/TeamTalk/MTDraftManager.h new file mode 100644 index 000000000..d8f50cb92 --- /dev/null +++ b/mac/TeamTalk/MTDraftManager.h @@ -0,0 +1,30 @@ +// +// MTDraftManager.h +// Duoduo +// +// Created by 独嘉 on 15/2/3. +// Copyright (c) 2015年 mogujie. All rights reserved. +// + +#import + +@interface MTDraftManager : NSObject + +/** + * 获取指定session ID的草稿 + * + * @param sessionID 指定session ID + * + * @return 富文本草稿 + */ +- (NSAttributedString*)getDraftForSessionID:(NSString*)sessionID; + +/** + * 设置指定session ID的草稿 + * + * @param draft 草稿 + * @param sessionID 指定sessionID + */ +- (void)setDraft:(NSAttributedString*)draft forSessionID:(NSString*)sessionID; + +@end diff --git a/mac/TeamTalk/MTDraftManager.m b/mac/TeamTalk/MTDraftManager.m new file mode 100644 index 000000000..377f8a7c2 --- /dev/null +++ b/mac/TeamTalk/MTDraftManager.m @@ -0,0 +1,38 @@ +// +// MTDraftManager.m +// Duoduo +// +// Created by 独嘉 on 15/2/3. +// Copyright (c) 2015年 mogujie. All rights reserved. +// + +#import "MTDraftManager.h" + +@implementation MTDraftManager +{ + NSMutableDictionary* _draftDic; +} + +- (instancetype)init +{ + self = [super init]; + if (self) + { + _draftDic = [[NSMutableDictionary alloc] init]; + } + return self; +} + +- (NSAttributedString*)getDraftForSessionID:(NSString *)sessionID +{ + return _draftDic[sessionID]; +} + + +- (void)setDraft:(NSAttributedString *)draft forSessionID:(NSString *)sessionID +{ + [_draftDic setObject:[draft copy] forKey:sessionID]; + NSAttributedString* session = _draftDic[sessionID]; +} + +@end diff --git a/mac/TeamTalk/MTInputHistoryManager.h b/mac/TeamTalk/MTInputHistoryManager.h new file mode 100644 index 000000000..d39442147 --- /dev/null +++ b/mac/TeamTalk/MTInputHistoryManager.h @@ -0,0 +1,29 @@ +// +// MTInputHistoryManager.h +// Duoduo +// +// Created by 独嘉 on 15/2/3. +// Copyright (c) 2015年 mogujie. All rights reserved. +// + +#import + +@interface MTInputHistoryManager : NSObject + + +/** + * 添加历史发送文本 + * + * @param historyText 历史发送文本 + */ +- (void)addInputHistory:(NSAttributedString*)historyText forSessionID:(NSString*)sessionID; + +/** + * 获取指定索引位置的历史文本 + * + * @param historyText 历史文本 + * @param index 索引 + */ +- (NSAttributedString*)getInputHistoryForSessionID:(NSString *)sessionID forIndex:(NSUInteger)index; + +@end diff --git a/mac/TeamTalk/MTInputHistoryManager.m b/mac/TeamTalk/MTInputHistoryManager.m new file mode 100644 index 000000000..8b36b8778 --- /dev/null +++ b/mac/TeamTalk/MTInputHistoryManager.m @@ -0,0 +1,55 @@ +// +// MTInputHistoryManager.m +// Duoduo +// +// Created by 独嘉 on 15/2/3. +// Copyright (c) 2015年 mogujie. All rights reserved. +// + +#import "MTInputHistoryManager.h" + +@implementation MTInputHistoryManager +{ + NSMutableDictionary* _inputHistory; +} + +- (instancetype)init +{ + self = [super init]; + if (self) + { + _inputHistory = [[NSMutableDictionary alloc] init]; + } + return self; +} + +- (void)addInputHistory:(NSAttributedString *)historyText forSessionID:(NSString *)sessionID +{ + if ([[_inputHistory allKeys] containsObject:sessionID]) + { + NSMutableArray* inputHistory = _inputHistory[sessionID]; + [inputHistory insertObject:[historyText copy] atIndex:0]; + } + else + { + NSMutableArray* historyTexts = [[NSMutableArray alloc] init]; + [historyTexts addObject:[historyText copy]]; + [_inputHistory setObject:historyTexts forKey:sessionID]; + } +} + +- (NSAttributedString*)getInputHistoryForSessionID:(NSString *)sessionID forIndex:(NSUInteger)index +{ + if ([[_inputHistory allKeys] containsObject:sessionID]) + { + NSMutableArray* historyInputs = _inputHistory[sessionID]; + if ([historyInputs count] > index) + { + return historyInputs[index]; + } + return nil; + } + return nil; +} + +@end diff --git a/mac/TeamTalk/MTPreviewItem.h b/mac/TeamTalk/MTPreviewItem.h new file mode 100644 index 000000000..ef729b497 --- /dev/null +++ b/mac/TeamTalk/MTPreviewItem.h @@ -0,0 +1,15 @@ +// +// MTPreviewItem.h +// Duoduo +// +// Created by 独嘉 on 15/2/2. +// Copyright (c) 2015年 mogujie. All rights reserved. +// + +#import +#import +@interface MTPreviewItem : NSObject + +- (instancetype)initWithItemURL:(id)url title:(NSString*)title; + +@end diff --git a/mac/TeamTalk/MTPreviewItem.m b/mac/TeamTalk/MTPreviewItem.m new file mode 100644 index 000000000..da4701f06 --- /dev/null +++ b/mac/TeamTalk/MTPreviewItem.m @@ -0,0 +1,64 @@ +// +// MTPreviewItem.m +// Duoduo +// +// Created by 独嘉 on 15/2/2. +// Copyright (c) 2015年 mogujie. All rights reserved. +// + +#import "MTPreviewItem.h" + +@implementation MTPreviewItem +{ + NSString* _urlString; + NSString* _title; + NSURL* _url; +} +- (instancetype)initWithItemURL:(id)url title:(NSString*)title +{ + self = [super init]; + if (self) + { + if ([url isKindOfClass:[NSURL class]]) + { + _url = [url copy]; + } + else + { + _urlString = [url copy]; + } + _title = [title copy]; + } + return self; +} + +#pragma mark - +#pragma mark - QLPreviewItem +- (NSURL*)previewItemURL +{ + if (_url) + { + return _url; + } + else + { + if ([_urlString hasPrefix:@"http://"]) + { + return [NSURL URLWithString:_urlString]; + } + else + { + NSURL* filePathUrl = [NSURL fileURLWithPath:_urlString]; + return filePathUrl; + } + } +} + +- (NSString*)previewItemTitle +{ + return _title; +} + + + +@end diff --git a/mac/TeamTalk/MTUnreadMessageManager.h b/mac/TeamTalk/MTUnreadMessageManager.h new file mode 100644 index 000000000..b0b5a045c --- /dev/null +++ b/mac/TeamTalk/MTUnreadMessageManager.h @@ -0,0 +1,20 @@ +// +// MTUnreadMessageManager.h +// Duoduo +// +// Created by 独嘉 on 15/1/16. +// Copyright (c) 2015年 mogujie. All rights reserved. +// + +#import + +@interface MTUnreadMessageManager : NSObject + +- (void)setUnreadMessageCounnt:(NSUInteger)count forSessionID:(NSString*)sessionID; +- (NSUInteger)getUnreadMessageCountForSessionID:(NSString*)sessionID; +- (NSUInteger)getUnreadMessageCount; +- (void)clearUnreadMesageCountForSessionID:(NSString*)sessionID; +- (void)clearAllUnreadMessageCount; +- (void)addUnreadMesageCountForSessionID:(NSString*)sessionID; +-(NSString *)getLastUnreadSessionId; +@end diff --git a/mac/TeamTalk/MTUnreadMessageManager.m b/mac/TeamTalk/MTUnreadMessageManager.m new file mode 100644 index 000000000..0331c9dac --- /dev/null +++ b/mac/TeamTalk/MTUnreadMessageManager.m @@ -0,0 +1,74 @@ +// +// MTUnreadMessageManager.m +// Duoduo +// +// Created by 独嘉 on 15/1/16. +// Copyright (c) 2015年 mogujie. All rights reserved. +// + +#import "MTUnreadMessageManager.h" + +@implementation MTUnreadMessageManager +{ + NSMutableDictionary* _unreadMessageCountDic; + NSString *_lastSessionId; +} + +- (instancetype)init +{ + self = [super init]; + if (self) + { + _unreadMessageCountDic = [[NSMutableDictionary alloc] init]; + } + return self; +} + +- (void)setUnreadMessageCounnt:(NSUInteger)count forSessionID:(NSString*)sessionID +{ + [_unreadMessageCountDic setObject:@(count) forKey:sessionID]; + _lastSessionId = sessionID; +} + +- (NSUInteger)getUnreadMessageCountForSessionID:(NSString*)sessionID +{ + return [_unreadMessageCountDic[sessionID] integerValue]; +} + +- (NSUInteger)getUnreadMessageCount +{ + __block NSUInteger count = 0; + [_unreadMessageCountDic enumerateKeysAndObjectsUsingBlock:^(id key, id obj, BOOL *stop) { + count += [obj integerValue]; + }]; + return count; +} + +- (void)clearUnreadMesageCountForSessionID:(NSString*)sessionID +{ + [_unreadMessageCountDic removeObjectForKey:sessionID]; +} + +- (void)clearAllUnreadMessageCount +{ + [_unreadMessageCountDic removeAllObjects]; +} + +- (void)addUnreadMesageCountForSessionID:(NSString*)sessionID +{ + NSUInteger count = [self getUnreadMessageCountForSessionID:sessionID]; + [self setUnreadMessageCounnt:(count + 1) forSessionID:sessionID]; +} +-(NSString *)getLastUnreadSessionId{ + NSString *_lastSID = _lastSessionId; + + [_unreadMessageCountDic enumerateKeysAndObjectsUsingBlock:^(NSString *key, id obj, BOOL *stop) { + if ([obj integerValue]>0 && ![key isEqualToString:_lastSessionId]) { + _lastSessionId=key; + } + }]; + return _lastSID; +} + + +@end diff --git a/mac/TeamTalk/MessageReview/DDMessageReviewContactsCellView.h b/mac/TeamTalk/MessageReview/DDMessageReviewContactsCellView.h new file mode 100644 index 000000000..b11037883 --- /dev/null +++ b/mac/TeamTalk/MessageReview/DDMessageReviewContactsCellView.h @@ -0,0 +1,19 @@ +// +// DDMessageReviewContactsCellView.h +// Duoduo +// +// Created by 独嘉 on 14-5-5. +// Copyright (c) 2014年 zuoye. All rights reserved. +// + +#import + +@class AvatorImageView; +@interface DDMessageReviewContactsCellView : NSTableCellView +{ + __weak IBOutlet AvatorImageView* _avatarImageView; + __weak IBOutlet NSTextField* _nameTextField; +} + +- (void)configWithObject:(id)object; +@end diff --git a/mac/TeamTalk/MessageReview/DDMessageReviewContactsCellView.m b/mac/TeamTalk/MessageReview/DDMessageReviewContactsCellView.m new file mode 100644 index 000000000..b78d37b3b --- /dev/null +++ b/mac/TeamTalk/MessageReview/DDMessageReviewContactsCellView.m @@ -0,0 +1,59 @@ +// +// DDMessageReviewContactsCellView.m +// Duoduo +// +// Created by 独嘉 on 14-5-5. +// Copyright (c) 2014年 zuoye. All rights reserved. +// + +#import "DDMessageReviewContactsCellView.h" +#import "MTUserEntity.h" +#import "MTGroupEntity.h" +#import "AvatorImageView.h" +@implementation DDMessageReviewContactsCellView + +- (id)initWithFrame:(NSRect)frame +{ + self = [super initWithFrame:frame]; + if (self) { + // Initialization code here. + } + return self; +} + +- (void)drawRect:(NSRect)dirtyRect +{ + [super drawRect:dirtyRect]; + NSView* view = [[NSView alloc] initWithFrame:NSMakeRect(0,self.frame.size.height, self.frame.size.width, 1)]; + [view setWantsLayer:YES]; + [view.layer setBackgroundColor:[NSColor colorWithCalibratedRed:232.0 / 255.0 + green:233.0 / 255.0 + blue:232.0 / 255.0 + alpha:1].CGColor]; + [self addSubview:view]; + // Drawing code here. +} + +- (void)configWithObject:(id)object +{ + if ([object isKindOfClass:NSClassFromString(@"MTUserEntity")]) + { + [_avatarImageView setUser:object]; + NSString* name = [(MTUserEntity*)object name]; + if (name) + { + [_nameTextField setStringValue:name]; + } + } + else if ([object isKindOfClass:NSClassFromString(@"MTGroupEntity")]) + { + [_avatarImageView setGroup:object]; + NSString* name = [(MTGroupEntity*)object name]; + if (name) + { + [_nameTextField setStringValue:name]; + } + } +} + +@end diff --git a/mac/TeamTalk/MessageReview/DDMessageReviewContactsViewController.h b/mac/TeamTalk/MessageReview/DDMessageReviewContactsViewController.h new file mode 100644 index 000000000..4eae76001 --- /dev/null +++ b/mac/TeamTalk/MessageReview/DDMessageReviewContactsViewController.h @@ -0,0 +1,24 @@ +// +// DDMessageReviewContactsViewController.h +// Duoduo +// +// Created by 独嘉 on 14-5-5. +// Copyright (c) 2014年 zuoye. All rights reserved. +// + +#import +@class DDMessageReviewContactsViewController; +@protocol DDMessageReviewContactsViewControllerDelegate + +- (void)contactsViewController:(DDMessageReviewContactsViewController*)viewController selectObject:(id)object; + +@end +@interface DDMessageReviewContactsViewController : NSViewController +{ + __weak IBOutlet NSTableView* _tableView; +} +@property (nonatomic,assign)IBOutlet id delegate; +- (void)updateContacts:(NSArray*)contacts; + +- (id)selectedContact; +@end diff --git a/mac/TeamTalk/MessageReview/DDMessageReviewContactsViewController.m b/mac/TeamTalk/MessageReview/DDMessageReviewContactsViewController.m new file mode 100644 index 000000000..029d7be21 --- /dev/null +++ b/mac/TeamTalk/MessageReview/DDMessageReviewContactsViewController.m @@ -0,0 +1,91 @@ +// +// DDMessageReviewContactsViewController.m +// Duoduo +// +// Created by 独嘉 on 14-5-5. +// Copyright (c) 2014年 zuoye. All rights reserved. +// + +#import "DDMessageReviewContactsViewController.h" +#import "DDMessageReviewContactsCellView.h" +//#import "DDDatabaseUtil.h" +@interface DDMessageReviewContactsViewController () + +- (void)p_clickTableView; + +@end + +@implementation DDMessageReviewContactsViewController +{ + NSMutableArray* _contacts; +} +- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil +{ + self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil]; + if (self) { + // Initialization code here. + } + return self; +} + +- (void)updateContacts:(NSArray*)contacts +{ +// if (_contacts) +// { +// _contacts = nil; +// } +// _contacts = contacts; +// [_tableView reloadData]; +// [_tableView selectRowIndexes:[NSIndexSet indexSetWithIndex:0] byExtendingSelection:NO]; +// if (self.delegate && [contacts count] > 0) +// { +// [self.delegate contactsViewController:self selectObject:contacts[0]]; +// } +} + +- (id)selectedContact +{ + NSInteger selectedRow = [_tableView selectedRow]; + id object = _contacts[selectedRow]; + return object; +} + +- (void)awakeFromNib +{ + _contacts = [[NSMutableArray alloc] init]; + [_tableView setTarget:self]; + [_tableView setAction:@selector(p_clickTableView)]; + _tableView.delegate = self; + _tableView.dataSource = self; +} + +#pragma mark NSTableView DataSource +- (NSInteger)numberOfRowsInTableView:(NSTableView *)tableView +{ + return [_contacts count]; +} + +- (CGFloat)tableView:(NSTableView *)tableView heightOfRow:(NSInteger)row +{ + return 38; +} +- (NSView*)tableView:(NSTableView *)tableView viewForTableColumn:(NSTableColumn *)tableColumn row:(NSInteger)row +{ + NSString* identifier = [tableColumn identifier]; + DDMessageReviewContactsCellView* cell = (DDMessageReviewContactsCellView*)[tableView makeViewWithIdentifier:identifier owner:self]; + id object = _contacts[row]; + [cell configWithObject:object]; + return cell; +} + +#pragma mark privateAPI +- (void)p_clickTableView +{ + NSInteger clickRow = [_tableView clickedRow]; + id object = _contacts[clickRow]; + if (self.delegate) + { + [self.delegate contactsViewController:self selectObject:object]; + } +} +@end diff --git a/mac/TeamTalk/MessageReview/DDMessageReviewModule.h b/mac/TeamTalk/MessageReview/DDMessageReviewModule.h new file mode 100644 index 000000000..8dc016960 --- /dev/null +++ b/mac/TeamTalk/MessageReview/DDMessageReviewModule.h @@ -0,0 +1,29 @@ +// +// DDMessageReviewModule.h +// Duoduo +// +// Created by 独嘉 on 14-4-18. +// Copyright (c) 2014年 zuoye. All rights reserved. +// + +#import +@class MessageEntity; +@interface DDMessageReviewModule : NSObject + +/** + * 获得所有的会话 + * + * @return 所有的会话 + */ +- (NSArray*)allSession; + +/** + * 获得对应会话的所有消息 + * + * @param sessionID 对应的会话 + * @param page 页码 + * + * @return 消息列表 + */ +- (NSArray*)messagesForSessionID:(NSString*)sessionID page:(NSInteger)page; +@end diff --git a/mac/TeamTalk/MessageReview/DDMessageReviewModule.m b/mac/TeamTalk/MessageReview/DDMessageReviewModule.m new file mode 100644 index 000000000..f17e9b8cc --- /dev/null +++ b/mac/TeamTalk/MessageReview/DDMessageReviewModule.m @@ -0,0 +1,22 @@ +// +// DDMessageReviewModule.m +// Duoduo +// +// Created by 独嘉 on 14-4-18. +// Copyright (c) 2014年 zuoye. All rights reserved. +// + +#import "DDMessageReviewModule.h" +@implementation DDMessageReviewModule + +- (NSArray*)allSession +{ + return nil; +} + +- (NSArray*)messagesForSessionID:(NSString*)sessionID page:(NSInteger)page +{ + return nil; +} + +@end diff --git a/mac/TeamTalk/MessageReview/DDMessageReviewTextView.h b/mac/TeamTalk/MessageReview/DDMessageReviewTextView.h new file mode 100644 index 000000000..bc86f7391 --- /dev/null +++ b/mac/TeamTalk/MessageReview/DDMessageReviewTextView.h @@ -0,0 +1,13 @@ +// +// DDMessageReviewTextView.h +// Duoduo +// +// Created by 独嘉 on 14-5-6. +// Copyright (c) 2014年 zuoye. All rights reserved. +// + +#import + +@interface DDMessageReviewTextView : NSTextView + +@end diff --git a/mac/TeamTalk/MessageReview/DDMessageReviewTextView.m b/mac/TeamTalk/MessageReview/DDMessageReviewTextView.m new file mode 100644 index 000000000..3b97aa9d5 --- /dev/null +++ b/mac/TeamTalk/MessageReview/DDMessageReviewTextView.m @@ -0,0 +1,33 @@ +// +// DDMessageReviewTextView.m +// Duoduo +// +// Created by 独嘉 on 14-5-6. +// Copyright (c) 2014年 zuoye. All rights reserved. +// + +#import "DDMessageReviewTextView.h" + +@implementation DDMessageReviewTextView + +- (id)initWithFrame:(NSRect)frame +{ + self = [super initWithFrame:frame]; + if (self) { + // Initialization code here. + } + return self; +} + +- (void)drawRect:(NSRect)dirtyRect +{ + [super drawRect:dirtyRect]; + + // Drawing code here. +} +- (BOOL)resignFirstResponder +{ + [self setSelectedRange:NSMakeRange(0, 0)]; + return YES; +} +@end diff --git a/mac/TeamTalk/MessageReview/DDMessageReviewWindow.xib b/mac/TeamTalk/MessageReview/DDMessageReviewWindow.xib new file mode 100644 index 000000000..a2d1e360f --- /dev/null +++ b/mac/TeamTalk/MessageReview/DDMessageReviewWindow.xib @@ -0,0 +1,313 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/mac/TeamTalk/MessageReview/DDMessageReviewWindowController.h b/mac/TeamTalk/MessageReview/DDMessageReviewWindowController.h new file mode 100644 index 000000000..e0200b946 --- /dev/null +++ b/mac/TeamTalk/MessageReview/DDMessageReviewWindowController.h @@ -0,0 +1,23 @@ +// +// DDMessageReviewWindowController.h +// Duoduo +// +// Created by 独嘉 on 14-4-18. +// Copyright (c) 2014年 zuoye. All rights reserved. +// + +#import "DDMessageReviewContactsViewController.h" +@class DDMessageReviewModule,DDMessageReviewContactsViewController,DDMessagesReviewContentViewController; +@interface DDMessageReviewWindowController : NSWindowController +{ + __weak IBOutlet NSSplitView* _splitView; + __weak IBOutlet NSSearchField* _searchTextField; + +} +@property (nonatomic,strong)DDMessageReviewModule* module; +@property (nonatomic,strong)IBOutlet DDMessageReviewContactsViewController* contactsViewController; +@property (nonatomic,strong)IBOutlet DDMessagesReviewContentViewController* contentViewController; + ++ (instancetype)instance; + +@end diff --git a/mac/TeamTalk/MessageReview/DDMessageReviewWindowController.m b/mac/TeamTalk/MessageReview/DDMessageReviewWindowController.m new file mode 100644 index 000000000..c40e40ff8 --- /dev/null +++ b/mac/TeamTalk/MessageReview/DDMessageReviewWindowController.m @@ -0,0 +1,270 @@ +// +// DDMessageReviewWindowController.m +// Duoduo +// +// Created by 独嘉 on 14-4-18. +// Copyright (c) 2014年 zuoye. All rights reserved. +// + +#import "DDMessageReviewWindowController.h" +#import "DDMessageReviewModule.h" +#import "DDMessageReviewContactsViewController.h" +#import "DDMessagesReviewContentViewController.h" +#import "MTDatabaseUtil.h" +#import "MTSessionModule.h" +#import "MTGroupModule.h" +#import "MTGroupEntity.h" +#import "MTUserEntity.h" +#import "MTUserModule.h" +#import "NSWindow+Addition.h" +@interface DDMessageReviewWindowController () + +- (void)p_ininialContacts; +- (id)p_searchUser:(NSString*)content; +- (void)p_searchContent:(NSString*)content; +@end + +@implementation DDMessageReviewWindowController +{ + NSArray* allRecent; + NSArray* _allObjects; + BOOL _showSearchContent; +} + + ++ (instancetype)instance +{ + static DDMessageReviewWindowController* g_messageReviewWindowController; + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^{ + g_messageReviewWindowController = [[DDMessageReviewWindowController alloc] initWithWindowNibName:@"DDMessageReviewWindow"]; + }); + return g_messageReviewWindowController; +} + +- (id)initWithWindow:(NSWindow *)window +{ + self = [super initWithWindow:window]; + if (self) { + // Initialization code here. + } + return self; +} + +- (void)awakeFromNib +{ + _showSearchContent = NO; + [self.window addCloseButtonAtTopLeft]; + [_splitView setPosition:100 ofDividerAtIndex:0]; + +} + +- (void)windowDidLoad +{ + [super windowDidLoad]; + [self p_ininialContacts]; + + // Implement this method to handle any initialization after your window controller's window has been loaded from its nib file. +} + +- (DDMessageReviewModule*)module +{ + if (_module) + { + _module = [[DDMessageReviewModule alloc] init]; + } + return _module; +} + +#pragma mark IBAction +- (IBAction)deleteSession:(id)sender +{ + id object = [_contactsViewController selectedContact]; + NSString* ID = nil; + if ([object isKindOfClass:NSClassFromString(@"MTUserEntity")]) + { + ID = [(MTUserEntity*)object ID]; + } + else if ([object isKindOfClass:NSClassFromString(@"MTGroupEntity")]) + { + ID = [(MTGroupEntity*)object ID]; + } + if (!ID) + { + return; + } + BOOL result = [[MTDatabaseUtil instance] deleteMessagesForSession:ID]; + if (result) { + [self p_searchContent:_searchTextField.stringValue]; + }else{ + DDLog(@"消息删除失败"); + } +} + +- (IBAction)refreshMessageReview:(id)sender +{ + [self p_searchContent:_searchTextField.stringValue]; +} + +#pragma mark NSTextField Delegate +- (void)controlTextDidChange:(NSNotification *)obj +{ + NSTextView* textView = [[obj userInfo] objectForKey:@"NSFieldEditor"]; + + if([textView.string length] == 0 && _showSearchContent) + { + [self p_ininialContacts]; + } +} + +// ------------------------------------------------------------------------------- +// control:textView:commandSelector +// +// Handle all commend selectors that we can handle here +// ------------------------------------------------------------------------------- +- (BOOL)control:(NSControl *)control textView:(NSTextView *)textView doCommandBySelector:(SEL)commandSelector +{ + if ([NSStringFromSelector(commandSelector) isEqualToString:@"insertNewline:"]) + { + NSString* stringValue = [textView string]; + if ([stringValue length] > 0) + { + //判断是不是搜索的是用户 + [self p_searchContent:stringValue]; + } + } + else + { + if ([textView respondsToSelector:commandSelector]) + { + [textView performSelector:commandSelector withObject:nil afterDelay:0]; + } + } + return YES; +} + +#pragma mark DDMessageReviewContactsViewController Delegate +- (void)contactsViewController:(DDMessageReviewContactsViewController*)viewController selectObject:(id)object +{ + NSString* sessionID = nil; + if ([object isKindOfClass:NSClassFromString(@"MTGroupEntity")]) { + sessionID = [(MTGroupEntity*)object ID]; + } + else if ([object isKindOfClass:NSClassFromString(@"MTUserEntity")]) + { + sessionID = [(MTUserEntity*)object ID]; + } + [self.contentViewController updateSession:sessionID]; +} + +#pragma mark NSSplitView + +- (CGFloat)splitView:(NSSplitView *)splitView constrainMinCoordinate:(CGFloat)proposedMinimumPosition ofSubviewAt:(NSInteger)dividerIndex { + return 185; +} + +- (CGFloat)splitView:(NSSplitView *)splitView constrainMaxCoordinate:(CGFloat)proposedMaximumPosition ofSubviewAt:(NSInteger)dividerIndex { + return 185; +} + +#pragma mark privateAPI +- (void)p_ininialContacts +{ + __weak DDMessageReviewWindowController* weakSelf = self; +// [[DDDatabaseUtil instance] loadAllSessionCompletion:^(NSArray *sessions, NSError *error) { +// //TODO:不存在的sessionID先不可见 +// NSMutableArray* objects = [NSMutableArray array]; +// [sessions enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) { +// +// if ([obj rangeOfString:@"group"].length > 0) +// { +// MTGroupEntity* group =(MTGroupEntity *)[[MTGroupModule shareInsatnce]getOriginEntityWithOriginID:obj]; +// if (group) +// { +// [objects addObject:group]; +// } +// } +// else +// { +// MTUserEntity* user =(MTUserEntity *)[[MTUserModule shareInstance]getOriginEntityWithOriginID:obj]; +// +// if (user) +// { +// [objects addObject:user]; +// } +// } +// }]; +// _allObjects = objects; +// [weakSelf.contactsViewController updateContacts:objects]; +// }]; + +} + +- (id)p_searchUser:(NSString*)content +{ + __block id object = nil; + [_allObjects enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) { + if ([obj isKindOfClass:NSClassFromString(@"MTUserEntity")]) { + NSString* name = [(MTUserEntity*)obj name]; + if ([name isEqualToString:content]) + { + object = obj; + } + } + else if ([obj isKindOfClass:NSClassFromString(@"MTGroupEntity")]) + { + NSString* name = [(MTGroupEntity*)obj name]; + if ([name isEqualToString:content]) + { + object = obj; + } + } + }]; + return object; +} + +- (void)p_searchContent:(NSString*)content +{ + if ([content length] > 0) + { + //判断是不是搜索的是用户 + if ([self p_searchUser:content]) + { + _showSearchContent = YES; + [_contactsViewController updateContacts:@[[self p_searchUser:content]]]; + } + else + { +// [[DDDatabaseUtil instance] searchMessageContent:content completion:^(NSArray *result) { +// NSMutableArray* objects = [NSMutableArray array]; +// [result enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) { +// +// if ([obj rangeOfString:@"group"].length > 0) +// { +// MTGroupEntity* group =(MTGroupEntity *)[[MTGroupModule shareInsatnce]getOriginEntityWithOriginID:obj]; +// +// if (group) +// { +// [objects addObject:group]; +// } +// } +// else +// { +// MTUserEntity* user =(MTUserEntity *)[[MTUserModule shareInstance]getOriginEntityWithOriginID:obj]; +// if (user) +// { +// [objects addObject:user]; +// } +// } +// }]; +// _showSearchContent = YES; +// [_contactsViewController updateContacts:objects]; +// }]; + } + } + else + { + [self p_ininialContacts]; + } +} +@end diff --git a/mac/TeamTalk/MessageReview/DDMessagesReviewContentModule.h b/mac/TeamTalk/MessageReview/DDMessagesReviewContentModule.h new file mode 100644 index 000000000..ddd1ba549 --- /dev/null +++ b/mac/TeamTalk/MessageReview/DDMessagesReviewContentModule.h @@ -0,0 +1,13 @@ +// +// DDMessagesReviewContentModule.h +// Duoduo +// +// Created by 独嘉 on 14-5-6. +// Copyright (c) 2014年 zuoye. All rights reserved. +// + +#import +@class MessageEntity; +@interface DDMessagesReviewContentModule : NSObject ++ (NSAttributedString*)getAttributedStringFromShowMessage:(MessageEntity*)message; +@end diff --git a/mac/TeamTalk/MessageReview/DDMessagesReviewContentModule.m b/mac/TeamTalk/MessageReview/DDMessagesReviewContentModule.m new file mode 100644 index 000000000..7c16b5c79 --- /dev/null +++ b/mac/TeamTalk/MessageReview/DDMessagesReviewContentModule.m @@ -0,0 +1,136 @@ +// +// DDMessagesReviewContentModule.m +// Duoduo +// +// Created by 独嘉 on 14-5-6. +// Copyright (c) 2014年 zuoye. All rights reserved. +// + +#import "DDMessagesReviewContentModule.h" +#import "NSAttributedString+Message.h" +#import "MessageEntity.h" +#import "DDEmotionAttachment.h" +#import "EmotionManager.h" +@implementation DDMessagesReviewContentModule ++ (NSAttributedString*)getAttributedStringFromShowMessage:(MessageEntity*)message +{ + NSMutableAttributedString* messageShowAttributed = [[NSMutableAttributedString alloc] init]; + + if ([message.msgContent length] == 0) + { + return nil; + } + + NSMutableString *msgContent = [NSMutableString stringWithString:message.msgContent]; + NSRange startRange; + while ((startRange= [msgContent rangeOfString:IMAGE_MARK_START]).location!=NSNotFound) { + if (startRange.location>0) { + NSString *str = [msgContent substringWithRange:NSMakeRange(0, startRange.location)]; + [msgContent deleteCharactersInRange:NSMakeRange(0, startRange.location)]; + startRange.location=0; + NSAttributedString* textAndEmotionAttribute = [DDMessagesReviewContentModule getTextAndEmotionAttributeFromText:str]; + [messageShowAttributed appendAttributedString:textAndEmotionAttribute]; + } + + NSRange endRange = [msgContent rangeOfString:IMAGE_MARK_END]; + if (endRange.location !=NSNotFound) { + NSRange range; + range.location = startRange.location+startRange.length; + range.length = endRange.location-startRange.length-startRange.location; + NSString *url = [msgContent substringWithRange:range]; + + DDLog(@"图片url:%@",url); + [msgContent deleteCharactersInRange:NSMakeRange(startRange.location,(startRange.length+range.length+endRange.length) )]; + + NSString *path = [[NSBundle mainBundle] pathForResource:@"tab_bg" ofType:@"png"]; + EGOImageLoader* imageLoder = [EGOImageLoader sharedImageLoader]; + NSString* imagePath = [imageLoder cachePathForURL:[NSURL URLWithString:url]]; + if (imagePath) + { + NSAttributedString* imageAttribute = [NSAttributedString imageAttributeString:imagePath compressImage:NO]; + [messageShowAttributed appendAttributedString:imageAttribute]; + } + else + { + NSAttributedString* imageAttribute = [NSAttributedString imageAttributeString:path compressImage:NO]; + [messageShowAttributed appendAttributedString:imageAttribute]; + } + + } else { + DDLog(@"没有匹配后缀:%@",msgContent); + break; + } + } + + // add remain text content + if([msgContent length] > 0){ + DDLog(@"文本."); + NSAttributedString* emotionTextAttribute = [DDMessagesReviewContentModule getTextAndEmotionAttributeFromText:msgContent]; + [messageShowAttributed appendAttributedString:emotionTextAttribute]; + } + return messageShowAttributed; +} + +#pragma mark - PrivateAPI ++ (NSAttributedString*)getTextAndEmotionAttributeFromText:(NSString*)text +{ + NSMutableAttributedString* resultAttribute = [[NSMutableAttributedString alloc] init]; + NSMutableString *msgContent = [NSMutableString stringWithString:text]; + NSRange startRange; + while ((startRange = [msgContent rangeOfString:@"["]).location != NSNotFound) { + if (startRange.location > 0) + { + NSString *str = [msgContent substringWithRange:NSMakeRange(0, startRange.location)]; + DDLog(@"[前文本内容:%@",str); + [msgContent deleteCharactersInRange:NSMakeRange(0, startRange.location)]; + startRange.location=0; + NSAttributedString* textAttribute = [NSAttributedString textAttributedString:str]; + [resultAttribute appendAttributedString:textAttribute]; + } + + NSRange endRange = [msgContent rangeOfString:@"]"]; + if (endRange.location != NSNotFound) { + NSRange range; + range.location = 0; + range.length = endRange.location + endRange.length; + NSString *emotionText = [msgContent substringWithRange:range]; + [msgContent deleteCharactersInRange: + NSMakeRange(0, endRange.location + endRange.length)]; + + DDLog(@"类似表情字串:%@",emotionText); + NSString *emotionFile = [[EmotionManager instance] getFileFrom:emotionText]; + if (emotionFile) { + // 表情 + NSString *path = [[NSBundle mainBundle] pathForResource:emotionFile ofType:nil]; + DDEmotionAttachment* emotionAttribute = [[DDEmotionAttachment alloc] init]; + NSURL *fileUrl = [NSURL fileURLWithPath:path]; + NSFileWrapper *fileWrapper = [[NSFileWrapper alloc] initSymbolicLinkWithDestinationURL:fileUrl]; + NSImage* emotionImage = [[NSImage alloc] initWithContentsOfURL:fileUrl]; + [fileWrapper setIcon:emotionImage]; + [fileWrapper setPreferredFilename:path]; + [emotionAttribute setFileWrapper:fileWrapper]; + [emotionAttribute setEmotionFileName:emotionFile]; + [emotionAttribute setEmotionPath:path]; + [emotionAttribute setEmotionText:emotionText]; + NSMutableAttributedString *attachmentString = (NSMutableAttributedString*)[NSMutableAttributedString attributedStringWithAttachment:emotionAttribute]; + + [resultAttribute appendAttributedString:attachmentString]; + } else + { + NSAttributedString* textAttribute = [NSAttributedString textAttributedString:emotionText]; + [resultAttribute appendAttributedString:textAttribute]; + } + } else { + DDLog(@"没有[匹配的后缀"); + break; + } + } + + if ([msgContent length] > 0) + { + NSAttributedString* textAttribute = [NSAttributedString textAttributedString:msgContent]; + [resultAttribute appendAttributedString:textAttribute]; + } + return resultAttribute; +} +@end diff --git a/mac/TeamTalk/MessageReview/DDMessagesReviewContentViewController.h b/mac/TeamTalk/MessageReview/DDMessagesReviewContentViewController.h new file mode 100644 index 000000000..a550fdf25 --- /dev/null +++ b/mac/TeamTalk/MessageReview/DDMessagesReviewContentViewController.h @@ -0,0 +1,38 @@ +// +// DDMessagesReviewContentViewController.h +// Duoduo +// +// Created by 独嘉 on 14-5-5. +// Copyright (c) 2014年 zuoye. All rights reserved. +// + +#import + +@interface DDMessagesReviewContentViewController : NSViewController +{ + __weak IBOutlet NSScrollView* _messageScrollView; + __weak IBOutlet NSTextField* _pageCountTextField; + __weak IBOutlet NSTextField* _currentPageTextField; + __weak IBOutlet NSTextField* _dateTextField; + + __weak IBOutlet NSButton* _nextPageButton; + __weak IBOutlet NSButton* _moreNextPageButton; + __weak IBOutlet NSButton* _lastPageButton; + __weak IBOutlet NSButton* _moreLastPageButton; +} + +/** + * 更新会话,更新总页数,页面更新到最新的历史消息 + * + * @param sessionID 会话ID + */ +- (void)updateSession:(NSString*)sessionID; + +/** + * 更新历史消息页面内容 + * + * @param page 页码 + */ +- (void)updateForPage:(NSInteger)page; + +@end diff --git a/mac/TeamTalk/MessageReview/DDMessagesReviewContentViewController.m b/mac/TeamTalk/MessageReview/DDMessagesReviewContentViewController.m new file mode 100644 index 000000000..342a120ba --- /dev/null +++ b/mac/TeamTalk/MessageReview/DDMessagesReviewContentViewController.m @@ -0,0 +1,330 @@ +// +// DDMessagesReviewContentViewController.m +// Duoduo +// +// Created by 独嘉 on 14-5-5. +// Copyright (c) 2014年 zuoye. All rights reserved. +// + +#import "DDMessagesReviewContentViewController.h" +#import "MessageEntity.h" +#import "MTDatabaseUtil.h" +#import "MTUserEntity.h" +#import "MTUserModule.h" +#import "DDMessagesReviewContentModule.h" +#import "NSTextView+Rect.h" +#import "DDMessageReviewTextView.h" +static NSInteger const perpageCount = 20; +static NSInteger const gap = 10; +static CGFloat const nameAndTimeHeight = 20; +static CGFloat const lineHeight = 2; + + +@interface DDMessagesReviewContentViewController (privateAPI) + +- (void)p_registkvo; +- (void)p_cancelRegisteKVO; + +- (void)p_addMessage:(MessageEntity*)message; +- (void)p_addNameAndTimeTextField:(MessageEntity*)message; +- (void)p_addContentViewForMessage:(MessageEntity*)message; +- (void)p_addLine; +- (void)p_resizeDocumentView; + +- (void)p_updateButton; +@end + +@implementation DDMessagesReviewContentViewController +{ + NSString* _sessionID; + CGFloat _bottom; + NSInteger _pageCount; + NSInteger _currentPage; + NSDate* _firstDateOnContent; +} +- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil +{ + self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil]; + if (self) { + // Initialization code here. + } + return self; +} + +- (void)awakeFromNib +{ + _bottom = 0; + [_messageScrollView.documentView setFlipped:YES]; + [self p_registkvo]; +} + +- (void)dealloc +{ + +} + +#pragma mark Public API +- (void)updateSession:(NSString*)sessionID +{ + __weak DDMessagesReviewContentViewController* contentViewController = self; + NSInteger messageCnt = [[MTDatabaseUtil instance] getMessagesCountForSessionID:sessionID]; +#warning DB改动 + NSInteger pagecount = messageCnt % 20 == 0 ? messageCnt / 20 : messageCnt / 20 + 1; + [self setValue:[NSNumber numberWithInteger:pagecount] forKeyPath:@"pageCount"]; + //定位到最新页 + [self setValue:[NSNumber numberWithInteger:_pageCount] forKeyPath:@"currentPage"]; + _sessionID = sessionID; + [contentViewController updateForPage:_currentPage]; +} + +- (void)updateForPage:(NSInteger)page +{ + _currentPage = page; + //移除原有的子视图 + NSMutableArray* subviews = [NSMutableArray arrayWithArray:[(NSView*)_messageScrollView.documentView subviews]]; + [subviews enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) { + [obj removeFromSuperview]; + }]; + NSClipView* contentView = _messageScrollView.contentView; + [_messageScrollView.documentView setFrameSize:contentView.bounds.size]; + _bottom = 0; + //添加消息 + __weak DDMessagesReviewContentViewController* contentViewController = self; + #warning DB改动 +// [[DDDatabaseUtil instance] loadMessageForSessionID:_sessionID pageCount:perpageCount page:(_currentPage - 1) completion:^(NSArray *messages, NSError *error) { +// for (NSInteger index = 0; index < [messages count]; index ++) +// { +// MessageEntity* message = messages[index]; +// if (index == 0) +// { +// uint32 timeInterval = message.msgTime; +// NSDate* date = [NSDate dateWithTimeIntervalSince1970:timeInterval]; +// [self setValue:date forKeyPath:@"firstDateOnContent"]; +// } +// [contentViewController p_addMessage:message]; +// } +// }]; +} + +#pragma mark NSTextField Delegate +- (BOOL)control:(NSControl *)control textView:(NSTextView *)textView doCommandBySelector:(SEL)commandSelector +{ + if ([NSStringFromSelector(commandSelector) isEqualToString:@"insertNewline:"]) + { + NSString* stringValue = [_currentPageTextField stringValue]; + NSInteger inputPageIndex = [stringValue integerValue]; + if (inputPageIndex > _pageCount) + { + [self setValue:[NSNumber numberWithInteger:_pageCount] forKeyPath:@"currentPage"]; + } + else + { + [self setValue:[NSNumber numberWithInteger:inputPageIndex] forKeyPath:@"currentPage"]; + } + [self updateForPage:_currentPage]; + } + else + { + if ([textView respondsToSelector:commandSelector]) + { + [textView performSelector:commandSelector withObject:nil afterDelay:0]; + } + } + return YES; +} +#pragma mark IBAction +- (IBAction)nextPage:(id)sender +{ + if (_pageCount > _currentPage) + { + _currentPage ++; + [self setValue:[NSNumber numberWithInteger:_currentPage] forKeyPath:@"currentPage"]; + [self updateForPage:_currentPage]; + } +} + +- (IBAction)lastPage:(id)sender +{ + if (_currentPage > 1) + { + _currentPage --; + [self setValue:[NSNumber numberWithInteger:_currentPage] forKeyPath:@"currentPage"]; + [self updateForPage:_currentPage]; + } +} + +- (IBAction)firstPage:(id)sender +{ + _currentPage = 1; + [self setValue:@1 forKeyPath:@"currentPage"]; + + [self updateForPage:_currentPage]; +} + +- (IBAction)lastestPage:(id)sender +{ + [self setValue:[NSNumber numberWithInteger:_pageCount] forKeyPath:@"currentPage"]; + + [self updateForPage:_currentPage]; +} + +#pragma mark KVO +- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context +{ + if ([keyPath isEqualToString:@"currentPage"]) + { + [self p_updateButton]; + NSString* title = [NSString stringWithFormat:@"%li",_currentPage]; + [_currentPageTextField setStringValue:title]; + } + else if ([keyPath isEqualToString:@"pageCount"]) + { + NSString* title = [NSString stringWithFormat:@"页/% li页",_pageCount]; + [_pageCountTextField setStringValue:title]; + + [self p_updateButton]; + } + else if ([keyPath isEqualToString:@"firstDateOnContent"]) + { + NSDateFormatter* dateFormate = [[NSDateFormatter alloc] init]; + [dateFormate setDateFormat:@"yyyy-MM-dd"]; + NSString* dateString = [dateFormate stringFromDate:_firstDateOnContent]; + [_dateTextField setStringValue:dateString]; + } +} + +#pragma mark private API + +- (void)p_registkvo +{ + [self addObserver:self forKeyPath:@"currentPage" options:0 context:nil]; + [self addObserver:self forKeyPath:@"pageCount" options:0 context:nil]; + [self addObserver:self forKeyPath:@"firstDateOnContent" options:0 context:nil]; +} + +- (void)p_cancelRegisteKVO +{ + [self removeObserver:self forKeyPath:@"currentPage"]; + [self removeObserver:self forKeyPath:@"pageCount"]; + [self removeObserver:self forKeyPath:@"firstDateOnContent"]; +} + +- (void)p_addNameAndTimeTextField:(MessageEntity *)message +{ + NSString* senderID = [message senderId]; + NSString* myUserID = [[DDClientState shareInstance] userID]; + NSDateFormatter* formatter = [[NSDateFormatter alloc] init]; + [formatter setDateFormat:@"yyyy-MM-dd HH:mm:ss"]; + NSString* title = nil; + NSDate* date = [NSDate dateWithTimeIntervalSince1970:message.msgTime]; + NSString* dateString = [formatter stringFromDate:date]; + + NSTextField* nameAndTimeTextField = [[NSTextField alloc] init]; + if ([senderID isEqualToString:myUserID]) + { + //是登录用户发的 + NSString* name =[[MTUserModule shareInstance] myUserEntity].name; + title = [NSString stringWithFormat:@"%@ %@",name,dateString]; + [nameAndTimeTextField setTextColor:[NSColor colorWithCalibratedRed:248.0 / 255.0 + green:150.0 / 255.0 + blue:188.0 / 255.0 alpha:1]]; + } + else + { + //是别人发的 + MTUserEntity* sender =(MTUserEntity *)[[MTUserModule shareInstance] getOriginEntityWithOriginID:senderID]; + NSString* name = sender.name; + title = [NSString stringWithFormat:@"%@ %@",name,dateString]; + [nameAndTimeTextField setTextColor:[NSColor grayColor]]; + + } + [nameAndTimeTextField setStringValue:title]; + [nameAndTimeTextField setBordered:NO]; + [nameAndTimeTextField setDrawsBackground:NO]; + [nameAndTimeTextField setEditable:NO]; + [nameAndTimeTextField setFrameSize:NSMakeSize(300, nameAndTimeHeight)]; + [nameAndTimeTextField setFrameOrigin:NSMakePoint(17, _bottom + gap)]; + _bottom += gap + nameAndTimeHeight; + [self p_resizeDocumentView]; + + [_messageScrollView.documentView addSubview:nameAndTimeTextField]; +} + +- (void)p_addContentViewForMessage:(MessageEntity *)message +{ + NSAttributedString* attribute = [DDMessagesReviewContentModule getAttributedStringFromShowMessage:message]; + DDMessageReviewTextView* textView = [[DDMessageReviewTextView alloc] initWithFrame:NSMakeRect(0, 0, 520, 1000)]; + [textView.undoManager removeAllActions]; + [textView setFont:[NSFont systemFontOfSize:13]]; + if (attribute) + { + [textView insertText:attribute]; + } + + NSRect rect = [textView contentRect]; + [textView setFrameSize:NSMakeSize(rect.size.width,rect.size.height)]; + [textView setFrameOrigin:NSMakePoint(15, _bottom + gap)]; + [textView setDrawsBackground:NO]; + [textView setEditable:NO]; + + _bottom += gap + rect.size.height; + [self p_resizeDocumentView]; + + [_messageScrollView.documentView addSubview:textView]; +} + +- (void)p_addLine +{ + NSView* view = [[NSView alloc] initWithFrame:NSMakeRect(16, _bottom + gap, 501, lineHeight)]; + [view setWantsLayer:YES]; + [view.layer setBackgroundColor:[NSColor colorWithCalibratedRed:232.0 / 255.0 + green:233.0 / 255.0 + blue:232.0 / 255.0 + alpha:1].CGColor]; + //TODO 添加颜色 + _bottom += gap + lineHeight; + [self p_resizeDocumentView]; + [_messageScrollView.documentView addSubview:view]; +} + +- (void)p_addMessage:(MessageEntity*)message +{ + [self p_addNameAndTimeTextField:message]; + [self p_addContentViewForMessage:message]; + [self p_addLine]; +} + +- (void)p_resizeDocumentView +{ + CGFloat bottomGap = 20; + if (_bottom > [(NSView*)_messageScrollView.documentView bounds].size.height - bottomGap) { + CGFloat width = self.view.bounds.size.width; + [_messageScrollView.documentView setFrameSize:NSMakeSize(width, _bottom + bottomGap)]; + } +} + +- (void)p_updateButton +{ + if (_currentPage == 1) + { + [_lastPageButton setHidden:YES]; + [_moreLastPageButton setHidden:YES]; + } + else + { + [_lastPageButton setHidden:NO]; + [_moreLastPageButton setHidden:NO]; + } + + if (_currentPage == _pageCount) + { + [_nextPageButton setHidden:YES]; + [_moreNextPageButton setHidden:YES]; + } + else + { + [_nextPageButton setHidden:NO]; + [_moreNextPageButton setHidden:NO]; + } +} +@end diff --git a/mac/TeamTalk/MessageReview/DDMessagesReviewWindow.h b/mac/TeamTalk/MessageReview/DDMessagesReviewWindow.h new file mode 100644 index 000000000..44b444471 --- /dev/null +++ b/mac/TeamTalk/MessageReview/DDMessagesReviewWindow.h @@ -0,0 +1,13 @@ +// +// DDMessagesReviewWindow.h +// Duoduo +// +// Created by 独嘉 on 14-5-6. +// Copyright (c) 2014年 zuoye. All rights reserved. +// + +#import + +@interface DDMessagesReviewWindow : NSWindow + +@end diff --git a/mac/TeamTalk/MessageReview/DDMessagesReviewWindow.m b/mac/TeamTalk/MessageReview/DDMessagesReviewWindow.m new file mode 100644 index 000000000..868536315 --- /dev/null +++ b/mac/TeamTalk/MessageReview/DDMessagesReviewWindow.m @@ -0,0 +1,33 @@ +// +// DDMessagesReviewWindow.m +// Duoduo +// +// Created by 独嘉 on 14-5-6. +// Copyright (c) 2014年 zuoye. All rights reserved. +// + +#import "DDMessagesReviewWindow.h" + +@implementation DDMessagesReviewWindow +- (BOOL)canBecomeMainWindow +{ + return YES; +} + +// Much like above method. +- (BOOL)canBecomeKeyWindow +{ + return YES; +} + +- (void)sendEvent:(NSEvent *)theEvent +{ + // Delegate wasn’t interested, so do the usual routing. + if ([theEvent type] == NSLeftMouseDragged) + { + [self setFrameOrigin:NSMakePoint(self.frame.origin.x + [theEvent deltaX], self.frame.origin.y - [theEvent deltaY])]; + } + [super sendEvent:theEvent]; +} + +@end diff --git a/mac/TeamTalk/NotificationHelp.h b/mac/TeamTalk/NotificationHelp.h new file mode 100644 index 000000000..6d015552c --- /dev/null +++ b/mac/TeamTalk/NotificationHelp.h @@ -0,0 +1,39 @@ +// +// NotificationHelp.h +// Duoduo +// +// Created by 独嘉 on 14-4-5. +// Copyright (c) 2014年 zuoye. All rights reserved. +// + +#import + +extern NSString* const notificationTcpLinkConnectComplete; //tcp连接建立完成 +extern NSString* const notificationTcpLinkConnectFailure; //tcp连接建立失败 +extern NSString* const notificationTcpLinkDisconnect; //tcp断开连接 + +extern NSString* const notificationUserLoginSuccess; //用户登录成功 +extern NSString* const notificationUserOffline; //用户离线 +extern NSString* const notificationUserKickouted; //用户被挤下线 + +extern NSString* const notificationRemoveSession; //移除会话成功之后的通知 + +/** + * 接收到服务器端的心跳 + */ +extern NSString* const notificationServerHeartBeat; + +//extern NSString* const notificationGetAllUsers; //获得所有用户 + +extern NSString* const notificationReceiveMessage; //收到一条消息 + +extern NSString* const notificationReloadTheRecentContacts; //刷新最近联系人界面 +extern NSString* const notificationReceiveP2PShakeMessage; //收到P2P消息 +extern NSString* const notificationReceiveP2PInputingMessage; //收到正在输入消息 +extern NSString* const notificationReceiveP2PStopInputingMessage; //收到停止输入消息 +extern NSString* const notificationReceiveP2PIntranetMessage; //收到内网发帖消息 +@interface NotificationHelp : NSObject + ++ (void)postNotification:(NSString*)notification userInfo:(NSDictionary*)userInfo object:(id)object; + +@end diff --git a/mac/TeamTalk/NotificationHelp.m b/mac/TeamTalk/NotificationHelp.m new file mode 100644 index 000000000..62290dd77 --- /dev/null +++ b/mac/TeamTalk/NotificationHelp.m @@ -0,0 +1,42 @@ +// +// NotificationHelp.m +// Duoduo +// +// Created by 独嘉 on 14-4-5. +// Copyright (c) 2014年 zuoye. All rights reserved. +// + +#import "NotificationHelp.h" + + + + +//NSString* const notificationLoginMsgServerSuccess = @"Notification_Login_Msg_Server_Success"; +//NSString* const notificationLoginMsgServerFailure = @"Notification_Login_Msg_Server_Success"; +NSString* const notificationRemoveSession = @"Notification_Remove_Session"; +//NSString* const notificationLoginLoginServerSuccess = @"Notification_login_login_server_success"; +//NSString* const notificationLoginLoginServerFailure = @"Notification_login_login_server_failure"; +NSString* const notificationTcpLinkConnectComplete = @"Notification_Tcp_Link_connect_complete"; +NSString* const notificationTcpLinkConnectFailure = @"Notification_Tcp_Link_conntect_Failure"; +NSString* const notificationTcpLinkDisconnect = @"Notification_Tcp_link_Disconnect"; +NSString* const notificationServerHeartBeat = @"Notification_Server_heart_beat"; +NSString* const notificationUserLoginSuccess = @"Notification_user_login_success"; +NSString* const notificationUserOffline = @"Notification_user_off_line"; +NSString* const notificationUserKickouted = @"Notification_user_kick_out"; + +NSString* const notificationReloadTheRecentContacts = @"Notification_reload_recent_contacts"; + +//NSString* const notificationGetAllUsers = @"Notification_get_all_Users"; +NSString* const notificationReceiveMessage = @"Notification_receive_message"; +NSString* const notificationReceiveP2PShakeMessage = @"Notification_receive_P2P_Shake_message"; +NSString* const notificationReceiveP2PInputingMessage = @"Notifictaion_receive_P2P_Inputing_message"; +NSString* const notificationReceiveP2PStopInputingMessage = @"Notification_receive_P2P_StopInputing_message"; +NSString* const notificationReceiveP2PIntranetMessage = @"Notification_receive_P2P_Intranet_message"; +@implementation NotificationHelp ++ (void)postNotification:(NSString*)notification userInfo:(NSDictionary*)userInfo object:(id)object +{ + dispatch_async(dispatch_get_main_queue(), ^{ + [[NSNotificationCenter defaultCenter] postNotificationName:notification object:object userInfo:userInfo]; + }); +} +@end diff --git a/mac/TeamTalk/PFMoveApplication.h b/mac/TeamTalk/PFMoveApplication.h new file mode 100755 index 000000000..38dfef7ff --- /dev/null +++ b/mac/TeamTalk/PFMoveApplication.h @@ -0,0 +1,11 @@ +// +// PFMoveApplication.h, version 1.10 +// LetsMove +// +// Created by Andy Kim at Potion Factory LLC on 9/17/09 +// +// The contents of this file are dedicated to the public domain. + +#import + +void PFMoveToApplicationsFolderIfNecessary(void); diff --git a/mac/TeamTalk/PFMoveApplication.m b/mac/TeamTalk/PFMoveApplication.m new file mode 100755 index 000000000..11527dc57 --- /dev/null +++ b/mac/TeamTalk/PFMoveApplication.m @@ -0,0 +1,483 @@ +// +// PFMoveApplication.m, version 1.10 +// LetsMove +// +// Created by Andy Kim at Potion Factory LLC on 9/17/09 +// +// The contents of this file are dedicated to the public domain. + +#import "PFMoveApplication.h" + +#import +#import +#import +#import + +// Strings +// These are macros to be able to use custom i18n tools +#define _I10NS(nsstr) NSLocalizedStringFromTable(nsstr, @"MoveApplication", nil) +#define kStrMoveApplicationCouldNotMove _I10NS(@"Could not move to Applications folder") +#define kStrMoveApplicationQuestionTitle _I10NS(@"Move to Applications folder?") +#define kStrMoveApplicationQuestionTitleHome _I10NS(@"我想住进你的应用程序文件夹,可以么?么么哒") +#define kStrMoveApplicationQuestionMessage _I10NS(@"只要你允许,我会自己钻进去哦!!") +#define kStrMoveApplicationButtonMove _I10NS(@"移动到程序文件夹") +#define kStrMoveApplicationButtonDoNotMove _I10NS(@"残忍的拒绝") +#define kStrMoveApplicationQuestionInfoWillRequirePasswd _I10NS(@"Note that this will require an administrator password.") +#define kStrMoveApplicationQuestionInfoInDownloadsFolder _I10NS(@"This will keep your Downloads folder uncluttered.") + +// Needs to be defined for compiling under 10.5 SDK +#ifndef NSAppKitVersionNumber10_5 + #define NSAppKitVersionNumber10_5 949 +#endif + +// By default, we use a small control/font for the suppression button. +// If you prefer to use the system default (to match your other alerts), +// set this to 0. +#define PFUseSmallAlertSuppressCheckbox 1 + + +static NSString *AlertSuppressKey = @"moveToApplicationsFolderAlertSuppress"; + + +// Helper functions +static NSString *PreferredInstallLocation(BOOL *isUserDirectory); +static BOOL IsInApplicationsFolder(NSString *path); +static BOOL IsInDownloadsFolder(NSString *path); +static BOOL IsApplicationAtPathRunning(NSString *path); +static NSString *ContainingDiskImageDevice(void); +static BOOL Trash(NSString *path); +static BOOL DeleteOrTrash(NSString *path); +static BOOL AuthorizedInstall(NSString *srcPath, NSString *dstPath, BOOL *canceled); +static BOOL CopyBundle(NSString *srcPath, NSString *dstPath); +static NSString *ShellQuotedString(NSString *string); +static void Relaunch(NSString *destinationPath); + +// Main worker function +void PFMoveToApplicationsFolderIfNecessary(void) { + // Skip if user suppressed the alert before + if ([[NSUserDefaults standardUserDefaults] boolForKey:AlertSuppressKey]) return; + + // Path of the bundle + NSString *bundlePath = [[NSBundle mainBundle] bundlePath]; + + // Skip if the application is already in some Applications folder + if (IsInApplicationsFolder(bundlePath)) return; + + // File Manager + NSFileManager *fm = [NSFileManager defaultManager]; + + // Are we on a disk image? + NSString *diskImageDevice = ContainingDiskImageDevice(); + + // Since we are good to go, get the preferred installation directory. + BOOL installToUserApplications = NO; + NSString *applicationsDirectory = PreferredInstallLocation(&installToUserApplications); + NSString *bundleName = [bundlePath lastPathComponent]; + NSString *destinationPath = [applicationsDirectory stringByAppendingPathComponent:bundleName]; + + // Check if we need admin password to write to the Applications directory + BOOL needAuthorization = ([fm isWritableFileAtPath:applicationsDirectory] == NO); + + // Check if the destination bundle is already there but not writable + needAuthorization |= ([fm fileExistsAtPath:destinationPath] && ![fm isWritableFileAtPath:destinationPath]); + + // Setup the alert + NSAlert *alert = [[[NSAlert alloc] init] autorelease]; + { + NSString *informativeText = nil; + + [alert setMessageText:(installToUserApplications ? kStrMoveApplicationQuestionTitleHome : kStrMoveApplicationQuestionTitle)]; + + informativeText = kStrMoveApplicationQuestionMessage; + + if (needAuthorization) { + informativeText = [informativeText stringByAppendingString:@" "]; + informativeText = [informativeText stringByAppendingString:kStrMoveApplicationQuestionInfoWillRequirePasswd]; + } + else if (IsInDownloadsFolder(bundlePath)) { + // Don't mention this stuff if we need authentication. The informative text is long enough as it is in that case. + informativeText = [informativeText stringByAppendingString:@" "]; + informativeText = [informativeText stringByAppendingString:kStrMoveApplicationQuestionInfoInDownloadsFolder]; + } + + [alert setInformativeText:informativeText]; + + // Add accept button + [alert addButtonWithTitle:kStrMoveApplicationButtonMove]; + + // Add deny button + NSButton *cancelButton = [alert addButtonWithTitle:kStrMoveApplicationButtonDoNotMove]; + [cancelButton setKeyEquivalent:@"\e"]; + + // Setup suppression button + [alert setShowsSuppressionButton:YES]; + + if (PFUseSmallAlertSuppressCheckbox) { + NSCell *cell = [[alert suppressionButton] cell]; + [cell setControlSize:NSSmallControlSize]; + [cell setFont:[NSFont systemFontOfSize:[NSFont smallSystemFontSize]]]; + } + } + + // Activate app -- work-around for focus issues related to "scary file from internet" OS dialog. + if (![NSApp isActive]) { + [NSApp activateIgnoringOtherApps:YES]; + } + + if ([alert runModal] == NSAlertFirstButtonReturn) { + NSLog(@"INFO -- Moving myself to the Applications folder"); + + // Move + if (needAuthorization) { + BOOL authorizationCanceled; + + if (!AuthorizedInstall(bundlePath, destinationPath, &authorizationCanceled)) { + if (authorizationCanceled) { + NSLog(@"INFO -- Not moving because user canceled authorization"); + return; + } + else { + NSLog(@"ERROR -- Could not copy myself to /Applications with authorization"); + goto fail; + } + } + } + else { + // If a copy already exists in the Applications folder, put it in the Trash + if ([fm fileExistsAtPath:destinationPath]) { + // But first, make sure that it's not running + if (IsApplicationAtPathRunning(destinationPath)) { + // Give the running app focus and terminate myself + NSLog(@"INFO -- Switching to an already running version"); + [[NSTask launchedTaskWithLaunchPath:@"/usr/bin/open" arguments:[NSArray arrayWithObject:destinationPath]] waitUntilExit]; + exit(0); + } + else { + if (!Trash([applicationsDirectory stringByAppendingPathComponent:bundleName])) + goto fail; + } + } + + if (!CopyBundle(bundlePath, destinationPath)) { + NSLog(@"ERROR -- Could not copy myself to %@", destinationPath); + goto fail; + } + } + + // Trash the original app. It's okay if this fails. + // NOTE: This final delete does not work if the source bundle is in a network mounted volume. + // Calling rm or file manager's delete method doesn't work either. It's unlikely to happen + // but it'd be great if someone could fix this. + if (diskImageDevice == nil && !DeleteOrTrash(bundlePath)) { + NSLog(@"WARNING -- Could not delete application after moving it to Applications folder"); + } + + // Relaunch. + Relaunch(destinationPath); + + // Launched from within a disk image? -- unmount (if no files are open after 5 seconds, + // otherwise leave it mounted). + if (diskImageDevice != nil) { + NSString *script = [NSString stringWithFormat:@"(/bin/sleep 5 && /usr/bin/hdiutil detach %@) &", ShellQuotedString(diskImageDevice)]; + [NSTask launchedTaskWithLaunchPath:@"/bin/sh" arguments:[NSArray arrayWithObjects:@"-c", script, nil]]; + } + + exit(0); + } + // Save the alert suppress preference if checked + else if ([[alert suppressionButton] state] == NSOnState) { + [[NSUserDefaults standardUserDefaults] setBool:YES forKey:AlertSuppressKey]; + } + + return; + +fail: + { + // Show failure message + alert = [[[NSAlert alloc] init] autorelease]; + [alert setMessageText:kStrMoveApplicationCouldNotMove]; + [alert runModal]; + } +} + +#pragma mark - +#pragma mark Helper Functions + +static NSString *PreferredInstallLocation(BOOL *isUserDirectory) { + // Return the preferred install location. + // Assume that if the user has a ~/Applications folder, they'd prefer their + // applications to go there. + + NSFileManager *fm = [NSFileManager defaultManager]; + + NSArray *userApplicationsDirs = NSSearchPathForDirectoriesInDomains(NSApplicationDirectory, NSUserDomainMask, YES); + + if ([userApplicationsDirs count] > 0) { + NSString *userApplicationsDir = [userApplicationsDirs objectAtIndex:0]; + BOOL isDirectory; + + if ([fm fileExistsAtPath:userApplicationsDir isDirectory:&isDirectory] && isDirectory) { + // User Applications directory exists. Get the directory contents. + NSArray *contents = [fm contentsOfDirectoryAtPath:userApplicationsDir error:NULL]; + + // Check if there is at least one ".app" inside the directory. + for (NSString *contentsPath in contents) { + if ([[contentsPath pathExtension] isEqualToString:@"app"]) { + if (isUserDirectory) *isUserDirectory = YES; + return [userApplicationsDir stringByResolvingSymlinksInPath]; + } + } + } + } + + // No user Applications directory in use. Return the machine local Applications directory + if (isUserDirectory) *isUserDirectory = NO; + + return [[NSSearchPathForDirectoriesInDomains(NSApplicationDirectory, NSLocalDomainMask, YES) lastObject] stringByResolvingSymlinksInPath]; +} + +static BOOL IsInApplicationsFolder(NSString *path) { + // Check all the normal Application directories + NSArray *applicationDirs = NSSearchPathForDirectoriesInDomains(NSApplicationDirectory, NSAllDomainsMask, YES); + for (NSString *appDir in applicationDirs) { + if ([path hasPrefix:appDir]) return YES; + } + + // Also, handle the case that the user has some other Application directory (perhaps on a separate data partition). + if ([[path pathComponents] containsObject:@"Applications"]) { + return YES; + } + + return NO; +} + +static BOOL IsInDownloadsFolder(NSString *path) { + NSArray *downloadDirs = NSSearchPathForDirectoriesInDomains(NSDownloadsDirectory, NSAllDomainsMask, YES); + for (NSString *downloadsDirPath in downloadDirs) { + if ([path hasPrefix:downloadsDirPath]) return YES; + } + + return NO; +} + +static BOOL IsApplicationAtPathRunning(NSString *path) { +#if MAC_OS_X_VERSION_MAX_ALLOWED > MAC_OS_X_VERSION_10_5 + // Use the new API on 10.6 or higher to determine if the app is already running + if (floor(NSAppKitVersionNumber) > NSAppKitVersionNumber10_5) { + for (NSRunningApplication *runningApplication in [[NSWorkspace sharedWorkspace] runningApplications]) { + NSString *executablePath = [[runningApplication executableURL] path]; + if ([executablePath hasPrefix:path]) { + return YES; + } + } + return NO; + } +#endif + // Use the shell to determine if the app is already running on systems 10.5 or lower + NSString *script = [NSString stringWithFormat:@"/bin/ps ax -o comm | /usr/bin/grep %@/ | /usr/bin/grep -v grep >/dev/null", ShellQuotedString(path)]; + NSTask *task = [NSTask launchedTaskWithLaunchPath:@"/bin/sh" arguments:[NSArray arrayWithObjects:@"-c", script, nil]]; + [task waitUntilExit]; + + // If the task terminated with status 0, it means that the final grep produced 1 or more lines of output. + // Which means that the app is already running + return [task terminationStatus] == 0; +} + +static NSString *ContainingDiskImageDevice(void) { + NSString *containingPath = [[[NSBundle mainBundle] bundlePath] stringByDeletingLastPathComponent]; + + struct statfs fs; + if (statfs([containingPath fileSystemRepresentation], &fs) || (fs.f_flags & MNT_ROOTFS)) + return nil; + + NSString *device = [[NSFileManager defaultManager] stringWithFileSystemRepresentation:fs.f_mntfromname length:strlen(fs.f_mntfromname)]; + + NSTask *hdiutil = [[[NSTask alloc] init] autorelease]; + [hdiutil setLaunchPath:@"/usr/bin/hdiutil"]; + [hdiutil setArguments:[NSArray arrayWithObjects:@"info", @"-plist", nil]]; + [hdiutil setStandardOutput:[NSPipe pipe]]; + [hdiutil launch]; + [hdiutil waitUntilExit]; + + NSData *data = [[[hdiutil standardOutput] fileHandleForReading] readDataToEndOfFile]; + id info; +#if MAC_OS_X_VERSION_MAX_ALLOWED > MAC_OS_X_VERSION_10_5 + if (floor(NSAppKitVersionNumber) > NSAppKitVersionNumber10_5) { + info = [NSPropertyListSerialization propertyListWithData:data options:NSPropertyListImmutable format:NULL error:NULL]; + } + else { +#endif + info = [NSPropertyListSerialization propertyListFromData:data mutabilityOption:NSPropertyListImmutable format:NULL errorDescription:NULL]; +#if MAC_OS_X_VERSION_MAX_ALLOWED > MAC_OS_X_VERSION_10_5 + } +#endif + + if (![info isKindOfClass:[NSDictionary class]]) + return nil; + + id images = [info objectForKey:@"images"]; + if (![images isKindOfClass:[NSArray class]]) + return nil; + + for (id image in images) { + if (![image isKindOfClass:[NSDictionary class]]) + return nil; + + id systemEntities = [image objectForKey:@"system-entities"]; + if (![systemEntities isKindOfClass:[NSArray class]]) + return nil; + + for (id systemEntity in systemEntities) { + id devEntry = [systemEntity objectForKey:@"dev-entry"]; + if (![devEntry isKindOfClass:[NSString class]]) + return nil; + if ([devEntry isEqualToString:device]) + return device; + } + } + + return nil; +} + +static BOOL Trash(NSString *path) { + if ([[NSWorkspace sharedWorkspace] performFileOperation:NSWorkspaceRecycleOperation + source:[path stringByDeletingLastPathComponent] + destination:@"" + files:[NSArray arrayWithObject:[path lastPathComponent]] + tag:NULL]) { + return YES; + } + else { + NSLog(@"ERROR -- Could not trash '%@'", path); + return NO; + } +} + +static BOOL DeleteOrTrash(NSString *path) { + NSError *error; + + if ([[NSFileManager defaultManager] removeItemAtPath:path error:&error]) { + return YES; + } + else { + NSLog(@"WARNING -- Could not delete '%@': %@", path, [error localizedDescription]); + return Trash(path); + } +} + +static BOOL AuthorizedInstall(NSString *srcPath, NSString *dstPath, BOOL *canceled) { + if (canceled) *canceled = NO; + + // Make sure that the destination path is an app bundle. We're essentially running 'sudo rm -rf' + // so we really don't want to fuck this up. + if (![dstPath hasSuffix:@".app"]) return NO; + + // Do some more checks + if ([[dstPath stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceCharacterSet]] length] == 0) return NO; + if ([[srcPath stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceCharacterSet]] length] == 0) return NO; + + int pid, status; + AuthorizationRef myAuthorizationRef; + + // Get the authorization + OSStatus err = AuthorizationCreate(NULL, kAuthorizationEmptyEnvironment, kAuthorizationFlagDefaults, &myAuthorizationRef); + if (err != errAuthorizationSuccess) return NO; + + AuthorizationItem myItems = {kAuthorizationRightExecute, 0, NULL, 0}; + AuthorizationRights myRights = {1, &myItems}; + AuthorizationFlags myFlags = kAuthorizationFlagInteractionAllowed | kAuthorizationFlagPreAuthorize | kAuthorizationFlagExtendRights; + + err = AuthorizationCopyRights(myAuthorizationRef, &myRights, NULL, myFlags, NULL); + if (err != errAuthorizationSuccess) { + if (err == errAuthorizationCanceled && canceled) + *canceled = YES; + goto fail; + } + + static OSStatus (*security_AuthorizationExecuteWithPrivileges)(AuthorizationRef authorization, const char *pathToTool, + AuthorizationFlags options, char * const *arguments, + FILE **communicationsPipe) = NULL; + if (!security_AuthorizationExecuteWithPrivileges) { + // On 10.7, AuthorizationExecuteWithPrivileges is deprecated. We want to still use it since there's no + // good alternative (without requiring code signing). We'll look up the function through dyld and fail + // if it is no longer accessible. If Apple removes the function entirely this will fail gracefully. If + // they keep the function and throw some sort of exception, this won't fail gracefully, but that's a + // risk we'll have to take for now. + security_AuthorizationExecuteWithPrivileges = dlsym(RTLD_DEFAULT, "AuthorizationExecuteWithPrivileges"); + } + if (!security_AuthorizationExecuteWithPrivileges) { + goto fail; + } + + // Delete the destination + { + char *args[] = {"-rf", (char *)[dstPath fileSystemRepresentation], NULL}; + err = security_AuthorizationExecuteWithPrivileges(myAuthorizationRef, "/bin/rm", kAuthorizationFlagDefaults, args, NULL); + if (err != errAuthorizationSuccess) goto fail; + + // Wait until it's done + pid = wait(&status); + if (pid == -1 || !WIFEXITED(status)) goto fail; // We don't care about exit status as the destination most likely does not exist + } + + // Copy + { + char *args[] = {"-pR", (char *)[srcPath fileSystemRepresentation], (char *)[dstPath fileSystemRepresentation], NULL}; + err = security_AuthorizationExecuteWithPrivileges(myAuthorizationRef, "/bin/cp", kAuthorizationFlagDefaults, args, NULL); + if (err != errAuthorizationSuccess) goto fail; + + // Wait until it's done + pid = wait(&status); + if (pid == -1 || !WIFEXITED(status) || WEXITSTATUS(status)) goto fail; + } + + AuthorizationFree(myAuthorizationRef, kAuthorizationFlagDefaults); + return YES; + +fail: + AuthorizationFree(myAuthorizationRef, kAuthorizationFlagDefaults); + return NO; +} + +static BOOL CopyBundle(NSString *srcPath, NSString *dstPath) { + NSFileManager *fm = [NSFileManager defaultManager]; + NSError *error = nil; + + if ([fm copyItemAtPath:srcPath toPath:dstPath error:&error]) { + return YES; + } + else { + NSLog(@"ERROR -- Could not copy '%@' to '%@' (%@)", srcPath, dstPath, error); + return NO; + } +} + +static NSString *ShellQuotedString(NSString *string) { + return [NSString stringWithFormat:@"'%@'", [string stringByReplacingOccurrencesOfString:@"'" withString:@"'\\''"]]; +} + +static void Relaunch(NSString *destinationPath) { + // The shell script waits until the original app process terminates. + // This is done so that the relaunched app opens as the front-most app. + int pid = [[NSProcessInfo processInfo] processIdentifier]; + + // Command run just before running open /final/path + NSString *preOpenCmd = @""; + + NSString *quotedDestinationPath = ShellQuotedString(destinationPath); + + // OS X >=10.5: + // Before we launch the new app, clear xattr:com.apple.quarantine to avoid + // duplicate "scary file from the internet" dialog. + if (floor(NSAppKitVersionNumber) > NSAppKitVersionNumber10_5) { + // Add the -r flag on 10.6 + preOpenCmd = [NSString stringWithFormat:@"/usr/bin/xattr -d -r com.apple.quarantine %@", quotedDestinationPath]; + } + else { + preOpenCmd = [NSString stringWithFormat:@"/usr/bin/xattr -d com.apple.quarantine %@", quotedDestinationPath]; + } + + NSString *script = [NSString stringWithFormat:@"(while /bin/kill -0 %d >&/dev/null; do /bin/sleep 0.1; done; %@; /usr/bin/open %@) &", pid, preOpenCmd, quotedDestinationPath]; + + [NSTask launchedTaskWithLaunchPath:@"/bin/sh" arguments:[NSArray arrayWithObjects:@"-c", script, nil]]; +} diff --git a/mac/TeamTalk/SBJson/NSObject+SBJson.h b/mac/TeamTalk/SBJson/NSObject+SBJson.h new file mode 100755 index 000000000..9a60b5936 --- /dev/null +++ b/mac/TeamTalk/SBJson/NSObject+SBJson.h @@ -0,0 +1,82 @@ +/* + Copyright (C) 2009 Stig Brautaset. All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + + * Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + + * Neither the name of the author nor the names of its contributors may be used + to endorse or promote products derived from this software without specific + prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE + FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#import + +#pragma mark JSON Writing + +/// Adds JSON generation to NSObject +@interface NSObject (NSObject_SBJsonWriting) + +/** + Encodes the receiver into a JSON string + + Although defined as a category on NSObject it is only defined for NSArray and NSDictionary. + + @return the receiver encoded in JSON, or nil on error. + + @warning Deprecated in Version 3.2; will be removed in 4.0 + + */ +- (NSString *)JSONRepresentation __attribute__ ((deprecated)); + +@end + + +#pragma mark JSON Parsing + +/// Adds JSON parsing methods to NSString +@interface NSString (NSString_SBJsonParsing) + +/** + Decodes the receiver's JSON text + + @return the NSDictionary or NSArray represented by the receiver, or nil on error. + + @warning Deprecated in Version 3.2; will be removed in 4.0 + + */ +- (id)JSONValue __attribute__ ((deprecated)); + +@end + +/// Adds JSON parsing methods to NSData +@interface NSData (NSData_SBJsonParsing) + +/** + Decodes the receiver's JSON data + + @return the NSDictionary or NSArray represented by the receiver, or nil on error. + + @warning Deprecated in Version 3.2; will be removed in 4.0 + + */ +- (id)JSONValue __attribute__ ((deprecated)); + +@end diff --git a/mac/TeamTalk/SBJson/NSObject+SBJson.m b/mac/TeamTalk/SBJson/NSObject+SBJson.m new file mode 100755 index 000000000..6557ff2f7 --- /dev/null +++ b/mac/TeamTalk/SBJson/NSObject+SBJson.m @@ -0,0 +1,76 @@ +/* + Copyright (C) 2009 Stig Brautaset. All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + + * Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + + * Neither the name of the author nor the names of its contributors may be used + to endorse or promote products derived from this software without specific + prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE + FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#if !__has_feature(objc_arc) +#error "This source file must be compiled with ARC enabled!" +#endif + +#import "NSObject+SBJson.h" +#import "SBJsonWriter.h" +#import "SBJsonParser.h" + +@implementation NSObject (NSObject_SBJsonWriting) + +- (NSString *)JSONRepresentation { + SBJsonWriter *writer = [[SBJsonWriter alloc] init]; + NSString *json = [writer stringWithObject:self]; + if (!json) + DDLog(@"-JSONRepresentation failed. Error is: %@", writer.error); + return json; +} + +@end + + + +@implementation NSString (NSString_SBJsonParsing) + +- (id)JSONValue { + SBJsonParser *parser = [[SBJsonParser alloc] init]; + id repr = [parser objectWithString:self]; + if (!repr) + DDLog(@"-JSONValue failed. Error is: %@", parser.error); + return repr; +} + +@end + + + +@implementation NSData (NSData_SBJsonParsing) + +- (id)JSONValue { + SBJsonParser *parser = [[SBJsonParser alloc] init]; + id repr = [parser objectWithData:self]; + if (!repr) + DDLog(@"-JSONValue failed. Error is: %@", parser.error); + return repr; +} + +@end diff --git a/mac/TeamTalk/SBJson/SBJson.h b/mac/TeamTalk/SBJson/SBJson.h new file mode 100755 index 000000000..d37ffcd21 --- /dev/null +++ b/mac/TeamTalk/SBJson/SBJson.h @@ -0,0 +1,36 @@ +/* + Copyright (C) 2009-2011 Stig Brautaset. All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + + * Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + + * Neither the name of the author nor the names of its contributors may be used + to endorse or promote products derived from this software without specific + prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE + FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#import "SBJsonParser.h" +#import "SBJsonWriter.h" +#import "SBJsonStreamParser.h" +#import "SBJsonStreamParserAdapter.h" +#import "SBJsonStreamWriter.h" +#import "NSObject+SBJson.h" + diff --git a/mac/TeamTalk/SBJson/SBJsonParser.h b/mac/TeamTalk/SBJson/SBJsonParser.h new file mode 100755 index 000000000..69c81c8fb --- /dev/null +++ b/mac/TeamTalk/SBJson/SBJsonParser.h @@ -0,0 +1,102 @@ +/* + Copyright (C) 2009 Stig Brautaset. All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + + * Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + + * Neither the name of the author nor the names of its contributors may be used + to endorse or promote products derived from this software without specific + prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE + FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#import + +/** + Parse JSON Strings and NSData objects + + This uses SBJsonStreamParser internally. + + */ + +@interface SBJsonParser : NSObject + +/** + The maximum recursing depth. + + Defaults to 32. If the input is nested deeper than this the input will be deemed to be + malicious and the parser returns nil, signalling an error. ("Nested too deep".) You can + turn off this security feature by setting the maxDepth value to 0. + */ +@property NSUInteger maxDepth; + +/** + Description of parse error + + This method returns the trace of the last method that failed. + You need to check the return value of the call you're making to figure out + if the call actually failed, before you know call this method. + + @return A string describing the error encountered, or nil if no error occured. + + */ +@property(copy) NSString *error; + +/** + Return the object represented by the given NSData object. + + The data *must* be UTF8 encoded. + + @param data An NSData containing UTF8 encoded data to parse. + @return The NSArray or NSDictionary represented by the object, or nil if an error occured. + + */ +- (id)objectWithData:(NSData*)data; + +/** + Return the object represented by the given string + + This method converts its input to an NSData object containing UTF8 and calls -objectWithData: with it. + + @return The NSArray or NSDictionary represented by the object, or nil if an error occured. + */ +- (id)objectWithString:(NSString *)repr; + +/** + Return the object represented by the given string + + This method calls objectWithString: internally. If an error occurs, and if error + is not nil, it creates an NSError object and returns this through its second argument. + + @param jsonText the json string to parse + @param error pointer to an NSError object to populate on error + + @return The NSArray or NSDictionary represented by the object, or nil if an error occured. + + @warning Deprecated in Version 3.2; will be removed in 4.0 + + */ + +- (id)objectWithString:(NSString*)jsonText + error:(NSError**)error __attribute__ ((deprecated)); + +@end + + diff --git a/mac/TeamTalk/SBJson/SBJsonParser.m b/mac/TeamTalk/SBJson/SBJsonParser.m new file mode 100755 index 000000000..729e896c3 --- /dev/null +++ b/mac/TeamTalk/SBJson/SBJsonParser.m @@ -0,0 +1,104 @@ +/* + Copyright (C) 2009,2010 Stig Brautaset. All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + + * Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + + * Neither the name of the author nor the names of its contributors may be used + to endorse or promote products derived from this software without specific + prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE + FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#if !__has_feature(objc_arc) +#error "This source file must be compiled with ARC enabled!" +#endif + +#import "SBJsonParser.h" +#import "SBJsonStreamParser.h" +#import "SBJsonStreamParserAdapter.h" +#import "SBJsonStreamParserAccumulator.h" + +@implementation SBJsonParser + +@synthesize maxDepth; +@synthesize error; + +- (id)init { + self = [super init]; + if (self) + self.maxDepth = 32u; + return self; +} + + +#pragma mark Methods + +- (id)objectWithData:(NSData *)data { + + if (!data) { + self.error = @"Input was 'nil'"; + return nil; + } + + SBJsonStreamParserAccumulator *accumulator = [[SBJsonStreamParserAccumulator alloc] init]; + + SBJsonStreamParserAdapter *adapter = [[SBJsonStreamParserAdapter alloc] init]; + adapter.delegate = accumulator; + + SBJsonStreamParser *parser = [[SBJsonStreamParser alloc] init]; + parser.maxDepth = self.maxDepth; + parser.delegate = adapter; + + switch ([parser parse:data]) { + case SBJsonStreamParserComplete: + return accumulator.value; + break; + + case SBJsonStreamParserWaitingForData: + self.error = @"Unexpected end of input"; + break; + + case SBJsonStreamParserError: + self.error = parser.error; + break; + } + + return nil; +} + +- (id)objectWithString:(NSString *)repr { + return [self objectWithData:[repr dataUsingEncoding:NSUTF8StringEncoding]]; +} + +- (id)objectWithString:(NSString*)repr error:(NSError**)error_ { + id tmp = [self objectWithString:repr]; + if (tmp) + return tmp; + + if (error_) { + NSDictionary *ui = [NSDictionary dictionaryWithObjectsAndKeys:error, NSLocalizedDescriptionKey, nil]; + *error_ = [NSError errorWithDomain:@"org.brautaset.SBJsonParser.ErrorDomain" code:0 userInfo:ui]; + } + + return nil; +} + +@end diff --git a/mac/TeamTalk/SBJson/SBJsonStreamParser.h b/mac/TeamTalk/SBJson/SBJsonStreamParser.h new file mode 100755 index 000000000..619cd55ba --- /dev/null +++ b/mac/TeamTalk/SBJson/SBJsonStreamParser.h @@ -0,0 +1,179 @@ +/* + Copyright (c) 2010, Stig Brautaset. + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are + met: + + Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + Neither the name of the the author nor the names of its contributors + may be used to endorse or promote products derived from this software + without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS + IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A + PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#import + +@class SBJsonTokeniser; +@class SBJsonStreamParser; +@class SBJsonStreamParserState; + +typedef enum { + SBJsonStreamParserComplete, + SBJsonStreamParserWaitingForData, + SBJsonStreamParserError, +} SBJsonStreamParserStatus; + + +/** + Delegate for interacting directly with the stream parser + + You will most likely find it much more convenient to implement the + SBJsonStreamParserAdapterDelegate protocol instead. + */ +@protocol SBJsonStreamParserDelegate + +/// Called when object start is found +- (void)parserFoundObjectStart:(SBJsonStreamParser*)parser; + +/// Called when object key is found +- (void)parser:(SBJsonStreamParser*)parser foundObjectKey:(NSString*)key; + +/// Called when object end is found +- (void)parserFoundObjectEnd:(SBJsonStreamParser*)parser; + +/// Called when array start is found +- (void)parserFoundArrayStart:(SBJsonStreamParser*)parser; + +/// Called when array end is found +- (void)parserFoundArrayEnd:(SBJsonStreamParser*)parser; + +/// Called when a boolean value is found +- (void)parser:(SBJsonStreamParser*)parser foundBoolean:(BOOL)x; + +/// Called when a null value is found +- (void)parserFoundNull:(SBJsonStreamParser*)parser; + +/// Called when a number is found +- (void)parser:(SBJsonStreamParser*)parser foundNumber:(NSNumber*)num; + +/// Called when a string is found +- (void)parser:(SBJsonStreamParser*)parser foundString:(NSString*)string; + +@end + + +/** + Parse a stream of JSON data. + + Using this class directly you can reduce the apparent latency for each + download/parse cycle of documents over a slow connection. You can start + parsing *and return chunks of the parsed document* before the entire + document is downloaded. + + Using this class is also useful to parse huge documents on disk + bit by bit so you don't have to keep them all in memory. + + JSON is mapped to Objective-C types in the following way: + + - null -> NSNull + - string -> NSString + - array -> NSMutableArray + - object -> NSMutableDictionary + - true -> NSNumber's -numberWithBool:YES + - false -> NSNumber's -numberWithBool:NO + - integer up to 19 digits -> NSNumber's -numberWithLongLong: + - all other numbers -> NSDecimalNumber + + Since Objective-C doesn't have a dedicated class for boolean values, + these turns into NSNumber instances. However, since these are + initialised with the -initWithBool: method they round-trip back to JSON + properly. In other words, they won't silently suddenly become 0 or 1; + they'll be represented as 'true' and 'false' again. + + As an optimisation integers up to 19 digits in length (the max length + for signed long long integers) turn into NSNumber instances, while + complex ones turn into NSDecimalNumber instances. We can thus avoid any + loss of precision as JSON allows ridiculously large numbers. + + See also SBJsonStreamParserAdapter for more information. + + */ +@interface SBJsonStreamParser : NSObject { +@private + SBJsonTokeniser *tokeniser; +} + +@property (nonatomic, unsafe_unretained) SBJsonStreamParserState *state; // Private +@property (nonatomic, readonly, strong) NSMutableArray *stateStack; // Private + +/** + Expect multiple documents separated by whitespace + + Normally the -parse: method returns SBJsonStreamParserComplete when it's found a complete JSON document. + Attempting to parse any more data at that point is considered an error. ("Garbage after JSON".) + + If you set this property to true the parser will never return SBJsonStreamParserComplete. Rather, + once an object is completed it will expect another object to immediately follow, separated + only by (optional) whitespace. + + */ +@property BOOL supportMultipleDocuments; + +/** + Delegate to receive messages + + The object set here receives a series of messages as the parser breaks down the JSON stream + into valid tokens. + + Usually this should be an instance of SBJsonStreamParserAdapter, but you can + substitute your own implementation of the SBJsonStreamParserDelegate protocol if you need to. + */ +@property (unsafe_unretained) id delegate; + +/** + The max parse depth + + If the input is nested deeper than this the parser will halt parsing and return an error. + + Defaults to 32. + */ +@property NSUInteger maxDepth; + +/// Holds the error after SBJsonStreamParserError was returned +@property (copy) NSString *error; + +/** + Parse some JSON + + The JSON is assumed to be UTF8 encoded. This can be a full JSON document, or a part of one. + + @param data An NSData object containing the next chunk of JSON + + @return + - SBJsonStreamParserComplete if a full document was found + - SBJsonStreamParserWaitingForData if a partial document was found and more data is required to complete it + - SBJsonStreamParserError if an error occured. (See the error property for details in this case.) + + */ +- (SBJsonStreamParserStatus)parse:(NSData*)data; + +@end diff --git a/mac/TeamTalk/SBJson/SBJsonStreamParser.m b/mac/TeamTalk/SBJson/SBJsonStreamParser.m new file mode 100755 index 000000000..57d5016b2 --- /dev/null +++ b/mac/TeamTalk/SBJson/SBJsonStreamParser.m @@ -0,0 +1,255 @@ +/* + Copyright (c) 2010, Stig Brautaset. + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are + met: + + Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + Neither the name of the the author nor the names of its contributors + may be used to endorse or promote products derived from this software + without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS + IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A + PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#if !__has_feature(objc_arc) +#error "This source file must be compiled with ARC enabled!" +#endif + +#import "SBJsonStreamParser.h" +#import "SBJsonTokeniser.h" +#import "SBJsonStreamParserState.h" + +@implementation SBJsonStreamParser + +@synthesize supportMultipleDocuments; +@synthesize error; +@synthesize delegate; +@synthesize maxDepth; +@synthesize state; +@synthesize stateStack; + +#pragma mark Housekeeping + +- (id)init { + self = [super init]; + if (self) { + maxDepth = 32u; + stateStack = [[NSMutableArray alloc] initWithCapacity:maxDepth]; + state = [SBJsonStreamParserStateStart sharedInstance]; + tokeniser = [[SBJsonTokeniser alloc] init]; + } + return self; +} + + +#pragma mark Methods + +- (NSString*)tokenName:(sbjson_token_t)token { + switch (token) { + case sbjson_token_array_start: + return @"start of array"; + break; + + case sbjson_token_array_end: + return @"end of array"; + break; + + case sbjson_token_number: + return @"number"; + break; + + case sbjson_token_string: + return @"string"; + break; + + case sbjson_token_true: + case sbjson_token_false: + return @"boolean"; + break; + + case sbjson_token_null: + return @"null"; + break; + + case sbjson_token_keyval_separator: + return @"key-value separator"; + break; + + case sbjson_token_separator: + return @"value separator"; + break; + + case sbjson_token_object_start: + return @"start of object"; + break; + + case sbjson_token_object_end: + return @"end of object"; + break; + + case sbjson_token_eof: + case sbjson_token_error: + break; + } + NSAssert(NO, @"Should not get here"); + return @""; +} + +- (void)maxDepthError { + self.error = [NSString stringWithFormat:@"Input depth exceeds max depth of %lu", (unsigned long)maxDepth]; + self.state = [SBJsonStreamParserStateError sharedInstance]; +} + +- (void)handleObjectStart { + if (stateStack.count >= maxDepth) { + [self maxDepthError]; + return; + } + + [delegate parserFoundObjectStart:self]; + [stateStack addObject:state]; + self.state = [SBJsonStreamParserStateObjectStart sharedInstance]; +} + +- (void)handleObjectEnd: (sbjson_token_t) tok { + self.state = [stateStack lastObject]; + [stateStack removeLastObject]; + [state parser:self shouldTransitionTo:tok]; + [delegate parserFoundObjectEnd:self]; +} + +- (void)handleArrayStart { + if (stateStack.count >= maxDepth) { + [self maxDepthError]; + return; + } + + [delegate parserFoundArrayStart:self]; + [stateStack addObject:state]; + self.state = [SBJsonStreamParserStateArrayStart sharedInstance]; +} + +- (void)handleArrayEnd: (sbjson_token_t) tok { + self.state = [stateStack lastObject]; + [stateStack removeLastObject]; + [state parser:self shouldTransitionTo:tok]; + [delegate parserFoundArrayEnd:self]; +} + +- (void) handleTokenNotExpectedHere: (sbjson_token_t) tok { + NSString *tokenName = [self tokenName:tok]; + NSString *stateName = [state name]; + + self.error = [NSString stringWithFormat:@"Token '%@' not expected %@", tokenName, stateName]; + self.state = [SBJsonStreamParserStateError sharedInstance]; +} + +- (SBJsonStreamParserStatus)parse:(NSData *)data_ { + @autoreleasepool { + [tokeniser appendData:data_]; + + for (;;) { + + if ([state isError]) + return SBJsonStreamParserError; + + NSObject *token; + sbjson_token_t tok = [tokeniser getToken:&token]; + switch (tok) { + case sbjson_token_eof: + return [state parserShouldReturn:self]; + break; + + case sbjson_token_error: + self.state = [SBJsonStreamParserStateError sharedInstance]; + self.error = tokeniser.error; + return SBJsonStreamParserError; + break; + + default: + + if (![state parser:self shouldAcceptToken:tok]) { + [self handleTokenNotExpectedHere: tok]; + return SBJsonStreamParserError; + } + + switch (tok) { + case sbjson_token_object_start: + [self handleObjectStart]; + break; + + case sbjson_token_object_end: + [self handleObjectEnd: tok]; + break; + + case sbjson_token_array_start: + [self handleArrayStart]; + break; + + case sbjson_token_array_end: + [self handleArrayEnd: tok]; + break; + + case sbjson_token_separator: + case sbjson_token_keyval_separator: + [state parser:self shouldTransitionTo:tok]; + break; + + case sbjson_token_true: + [delegate parser:self foundBoolean:YES]; + [state parser:self shouldTransitionTo:tok]; + break; + + case sbjson_token_false: + [delegate parser:self foundBoolean:NO]; + [state parser:self shouldTransitionTo:tok]; + break; + + case sbjson_token_null: + [delegate parserFoundNull:self]; + [state parser:self shouldTransitionTo:tok]; + break; + + case sbjson_token_number: + [delegate parser:self foundNumber:(NSNumber*)token]; + [state parser:self shouldTransitionTo:tok]; + break; + + case sbjson_token_string: + if ([state needKey]) + [delegate parser:self foundObjectKey:(NSString*)token]; + else + [delegate parser:self foundString:(NSString*)token]; + [state parser:self shouldTransitionTo:tok]; + break; + + default: + break; + } + break; + } + } + return SBJsonStreamParserComplete; + } +} + +@end diff --git a/mac/TeamTalk/SBJson/SBJsonStreamParserAccumulator.h b/mac/TeamTalk/SBJson/SBJsonStreamParserAccumulator.h new file mode 100755 index 000000000..141d6eedc --- /dev/null +++ b/mac/TeamTalk/SBJson/SBJsonStreamParserAccumulator.h @@ -0,0 +1,37 @@ +/* + Copyright (C) 2011 Stig Brautaset. All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + + * Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + + * Neither the name of the author nor the names of its contributors may be used + to endorse or promote products derived from this software without specific + prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE + FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#import +#import "SBJsonStreamParserAdapter.h" + +@interface SBJsonStreamParserAccumulator : NSObject + +@property (copy) id value; + +@end diff --git a/mac/TeamTalk/SBJson/SBJsonStreamParserAccumulator.m b/mac/TeamTalk/SBJson/SBJsonStreamParserAccumulator.m new file mode 100755 index 000000000..82d8fe80f --- /dev/null +++ b/mac/TeamTalk/SBJson/SBJsonStreamParserAccumulator.m @@ -0,0 +1,51 @@ +/* + Copyright (C) 2011 Stig Brautaset. All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + + * Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + + * Neither the name of the author nor the names of its contributors may be used + to endorse or promote products derived from this software without specific + prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE + FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#if !__has_feature(objc_arc) +#error "This source file must be compiled with ARC enabled!" +#endif + +#import "SBJsonStreamParserAccumulator.h" + +@implementation SBJsonStreamParserAccumulator + +@synthesize value; + + +#pragma mark SBJsonStreamParserAdapterDelegate + +- (void)parser:(SBJsonStreamParser*)parser foundArray:(NSArray *)array { + value = array; +} + +- (void)parser:(SBJsonStreamParser*)parser foundObject:(NSDictionary *)dict { + value = dict; +} + +@end diff --git a/mac/TeamTalk/SBJson/SBJsonStreamParserAdapter.h b/mac/TeamTalk/SBJson/SBJsonStreamParserAdapter.h new file mode 100755 index 000000000..8b4bc5d6f --- /dev/null +++ b/mac/TeamTalk/SBJson/SBJsonStreamParserAdapter.h @@ -0,0 +1,142 @@ +/* + Copyright (c) 2010, Stig Brautaset. + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are + met: + + Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + Neither the name of the the author nor the names of its contributors + may be used to endorse or promote products derived from this software + without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS + IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A + PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#import +#import "SBJsonStreamParser.h" + +typedef enum { + SBJsonStreamParserAdapterNone, + SBJsonStreamParserAdapterArray, + SBJsonStreamParserAdapterObject, +} SBJsonStreamParserAdapterType; + +/** + Delegate for getting objects & arrays from the stream parser adapter + + */ +@protocol SBJsonStreamParserAdapterDelegate + +/** + Called if a JSON array is found + + This method is called if a JSON array is found. + + */ +- (void)parser:(SBJsonStreamParser*)parser foundArray:(NSArray*)array; + +/** + Called when a JSON object is found + + This method is called if a JSON object is found. + */ +- (void)parser:(SBJsonStreamParser*)parser foundObject:(NSDictionary*)dict; + +@end + +/** + SBJsonStreamParserDelegate protocol adapter + + Rather than implementing the SBJsonStreamParserDelegate protocol yourself you will + most likely find it much more convenient to use an instance of this class and + implement the SBJsonStreamParserAdapterDelegate protocol instead. + + The default behaviour is that the delegate only receives one call from + either the -parser:foundArray: or -parser:foundObject: method when the + document is fully parsed. However, if your inputs contains multiple JSON + documents and you set the parser's -supportMultipleDocuments property to YES + you will get one call for each full method. + + SBJsonStreamParserAdapter *adapter = [[[SBJsonStreamParserAdapter alloc] init] autorelease]; + adapter.delegate = self; + + SBJsonStreamParser *parser = [[[SBJsonStreamParser alloc] init] autorelease]; + parser.delegate = adapter; + parser.supportMultipleDocuments = YES; + + // Note that this input contains multiple top-level JSON documents + NSData *json = [@"[]{}[]{}" dataWithEncoding:NSUTF8StringEncoding]; + [parser parse:data]; + + In the above example self will have the following sequence of methods called on it: + + - -parser:foundArray: + - -parser:foundObject: + - -parser:foundArray: + - -parser:foundObject: + + Often you won't have control over the input you're parsing, so can't make use of + this feature. But, all is not lost: this class will let you get the same effect by + allowing you to skip one or more of the outer enclosing objects. Thus, the next + example results in the same sequence of -parser:foundArray: / -parser:foundObject: + being called on your delegate. + + SBJsonStreamParserAdapter *adapter = [[[SBJsonStreamParserAdapter alloc] init] autorelease]; + adapter.delegate = self; + adapter.levelsToSkip = 1; + + SBJsonStreamParser *parser = [[[SBJsonStreamParser alloc] init] autorelease]; + parser.delegate = adapter; + + // Note that this input contains A SINGLE top-level document + NSData *json = [@"[[],{},[],{}]" dataWithEncoding:NSUTF8StringEncoding]; + [parser parse:data]; + +*/ +@interface SBJsonStreamParserAdapter : NSObject { +@private + NSUInteger depth; + NSMutableArray *array; + NSMutableDictionary *dict; + NSMutableArray *keyStack; + NSMutableArray *stack; + + SBJsonStreamParserAdapterType currentType; +} + +/** + How many levels to skip + + This is useful for parsing huge JSON documents, or documents coming in over a very slow link. + + If you set this to N it will skip the outer N levels and call the -parser:foundArray: + or -parser:foundObject: methods for each of the inner objects, as appropriate. + +*/ +@property NSUInteger levelsToSkip; + +/** + Your delegate object + Set this to the object you want to receive the SBJsonStreamParserAdapterDelegate messages. + */ +@property (unsafe_unretained) id delegate; + +@end diff --git a/mac/TeamTalk/SBJson/SBJsonStreamParserAdapter.m b/mac/TeamTalk/SBJson/SBJsonStreamParserAdapter.m new file mode 100755 index 000000000..7259a0603 --- /dev/null +++ b/mac/TeamTalk/SBJson/SBJsonStreamParserAdapter.m @@ -0,0 +1,168 @@ +/* + Copyright (c) 2010, Stig Brautaset. + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are + met: + + Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + Neither the name of the the author nor the names of its contributors + may be used to endorse or promote products derived from this software + without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS + IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A + PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#if !__has_feature(objc_arc) +#error "This source file must be compiled with ARC enabled!" +#endif + +#import "SBJsonStreamParserAdapter.h" + +@interface SBJsonStreamParserAdapter () + +- (void)pop; +- (void)parser:(SBJsonStreamParser*)parser found:(id)obj; + +@end + + + +@implementation SBJsonStreamParserAdapter + +@synthesize delegate; +@synthesize levelsToSkip; + +#pragma mark Housekeeping + +- (id)init { + self = [super init]; + if (self) { + keyStack = [[NSMutableArray alloc] initWithCapacity:32]; + stack = [[NSMutableArray alloc] initWithCapacity:32]; + + currentType = SBJsonStreamParserAdapterNone; + } + return self; +} + + +#pragma mark Private methods + +- (void)pop { + [stack removeLastObject]; + array = nil; + dict = nil; + currentType = SBJsonStreamParserAdapterNone; + + id value = [stack lastObject]; + + if ([value isKindOfClass:[NSArray class]]) { + array = value; + currentType = SBJsonStreamParserAdapterArray; + } else if ([value isKindOfClass:[NSDictionary class]]) { + dict = value; + currentType = SBJsonStreamParserAdapterObject; + } +} + +- (void)parser:(SBJsonStreamParser*)parser found:(id)obj { + NSParameterAssert(obj); + + switch (currentType) { + case SBJsonStreamParserAdapterArray: + [array addObject:obj]; + break; + + case SBJsonStreamParserAdapterObject: + NSParameterAssert(keyStack.count); + [dict setObject:obj forKey:[keyStack lastObject]]; + [keyStack removeLastObject]; + break; + + case SBJsonStreamParserAdapterNone: + if ([obj isKindOfClass:[NSArray class]]) { + [delegate parser:parser foundArray:obj]; + } else { + [delegate parser:parser foundObject:obj]; + } + break; + + default: + break; + } +} + + +#pragma mark Delegate methods + +- (void)parserFoundObjectStart:(SBJsonStreamParser*)parser { + if (++depth > self.levelsToSkip) { + dict = [NSMutableDictionary new]; + [stack addObject:dict]; + currentType = SBJsonStreamParserAdapterObject; + } +} + +- (void)parser:(SBJsonStreamParser*)parser foundObjectKey:(NSString*)key_ { + [keyStack addObject:key_]; +} + +- (void)parserFoundObjectEnd:(SBJsonStreamParser*)parser { + if (depth-- > self.levelsToSkip) { + id value = dict; + [self pop]; + [self parser:parser found:value]; + } +} + +- (void)parserFoundArrayStart:(SBJsonStreamParser*)parser { + if (++depth > self.levelsToSkip) { + array = [NSMutableArray new]; + [stack addObject:array]; + currentType = SBJsonStreamParserAdapterArray; + } +} + +- (void)parserFoundArrayEnd:(SBJsonStreamParser*)parser { + if (depth-- > self.levelsToSkip) { + id value = array; + [self pop]; + [self parser:parser found:value]; + } +} + +- (void)parser:(SBJsonStreamParser*)parser foundBoolean:(BOOL)x { + [self parser:parser found:[NSNumber numberWithBool:x]]; +} + +- (void)parserFoundNull:(SBJsonStreamParser*)parser { + [self parser:parser found:[NSNull null]]; +} + +- (void)parser:(SBJsonStreamParser*)parser foundNumber:(NSNumber*)num { + [self parser:parser found:num]; +} + +- (void)parser:(SBJsonStreamParser*)parser foundString:(NSString*)string { + [self parser:parser found:string]; +} + +@end diff --git a/mac/TeamTalk/SBJson/SBJsonStreamParserState.h b/mac/TeamTalk/SBJson/SBJsonStreamParserState.h new file mode 100755 index 000000000..ea893cb3b --- /dev/null +++ b/mac/TeamTalk/SBJson/SBJsonStreamParserState.h @@ -0,0 +1,83 @@ +/* + Copyright (c) 2010, Stig Brautaset. + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are + met: + + Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + Neither the name of the the author nor the names of its contributors + may be used to endorse or promote products derived from this software + without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS + IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A + PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#import + +#import "SBJsonTokeniser.h" +#import "SBJsonStreamParser.h" + +@interface SBJsonStreamParserState : NSObject ++ (id)sharedInstance; + +- (BOOL)parser:(SBJsonStreamParser*)parser shouldAcceptToken:(sbjson_token_t)token; +- (SBJsonStreamParserStatus)parserShouldReturn:(SBJsonStreamParser*)parser; +- (void)parser:(SBJsonStreamParser*)parser shouldTransitionTo:(sbjson_token_t)tok; +- (BOOL)needKey; +- (BOOL)isError; + +- (NSString*)name; + +@end + +@interface SBJsonStreamParserStateStart : SBJsonStreamParserState +@end + +@interface SBJsonStreamParserStateComplete : SBJsonStreamParserState +@end + +@interface SBJsonStreamParserStateError : SBJsonStreamParserState +@end + + +@interface SBJsonStreamParserStateObjectStart : SBJsonStreamParserState +@end + +@interface SBJsonStreamParserStateObjectGotKey : SBJsonStreamParserState +@end + +@interface SBJsonStreamParserStateObjectSeparator : SBJsonStreamParserState +@end + +@interface SBJsonStreamParserStateObjectGotValue : SBJsonStreamParserState +@end + +@interface SBJsonStreamParserStateObjectNeedKey : SBJsonStreamParserState +@end + +@interface SBJsonStreamParserStateArrayStart : SBJsonStreamParserState +@end + +@interface SBJsonStreamParserStateArrayGotValue : SBJsonStreamParserState +@end + +@interface SBJsonStreamParserStateArrayNeedValue : SBJsonStreamParserState +@end diff --git a/mac/TeamTalk/SBJson/SBJsonStreamParserState.m b/mac/TeamTalk/SBJson/SBJsonStreamParserState.m new file mode 100755 index 000000000..a59e7dc21 --- /dev/null +++ b/mac/TeamTalk/SBJson/SBJsonStreamParserState.m @@ -0,0 +1,362 @@ +/* + Copyright (c) 2010, Stig Brautaset. + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are + met: + + Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + Neither the name of the the author nor the names of its contributors + may be used to endorse or promote products derived from this software + without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS + IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A + PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#if !__has_feature(objc_arc) +#error "This source file must be compiled with ARC enabled!" +#endif + +#import "SBJsonStreamParserState.h" + +#define SINGLETON \ ++ (id)sharedInstance { \ + static id state = nil; \ + if (!state) { \ + @synchronized(self) { \ + if (!state) state = [[self alloc] init]; \ + } \ + } \ + return state; \ +} + +@implementation SBJsonStreamParserState + ++ (id)sharedInstance { return nil; } + +- (BOOL)parser:(SBJsonStreamParser*)parser shouldAcceptToken:(sbjson_token_t)token { + return NO; +} + +- (SBJsonStreamParserStatus)parserShouldReturn:(SBJsonStreamParser*)parser { + return SBJsonStreamParserWaitingForData; +} + +- (void)parser:(SBJsonStreamParser*)parser shouldTransitionTo:(sbjson_token_t)tok {} + +- (BOOL)needKey { + return NO; +} + +- (NSString*)name { + return @""; +} + +- (BOOL)isError { + return NO; +} + +@end + +#pragma mark - + +@implementation SBJsonStreamParserStateStart + +SINGLETON + +- (BOOL)parser:(SBJsonStreamParser*)parser shouldAcceptToken:(sbjson_token_t)token { + return token == sbjson_token_array_start || token == sbjson_token_object_start; +} + +- (void)parser:(SBJsonStreamParser*)parser shouldTransitionTo:(sbjson_token_t)tok { + + SBJsonStreamParserState *state = nil; + switch (tok) { + case sbjson_token_array_start: + state = [SBJsonStreamParserStateArrayStart sharedInstance]; + break; + + case sbjson_token_object_start: + state = [SBJsonStreamParserStateObjectStart sharedInstance]; + break; + + case sbjson_token_array_end: + case sbjson_token_object_end: + if (parser.supportMultipleDocuments) + state = parser.state; + else + state = [SBJsonStreamParserStateComplete sharedInstance]; + break; + + case sbjson_token_eof: + return; + + default: + state = [SBJsonStreamParserStateError sharedInstance]; + break; + } + + + parser.state = state; +} + +- (NSString*)name { return @"before outer-most array or object"; } + +@end + +#pragma mark - + +@implementation SBJsonStreamParserStateComplete + +SINGLETON + +- (NSString*)name { return @"after outer-most array or object"; } + +- (SBJsonStreamParserStatus)parserShouldReturn:(SBJsonStreamParser*)parser { + return SBJsonStreamParserComplete; +} + +@end + +#pragma mark - + +@implementation SBJsonStreamParserStateError + +SINGLETON + +- (NSString*)name { return @"in error"; } + +- (SBJsonStreamParserStatus)parserShouldReturn:(SBJsonStreamParser*)parser { + return SBJsonStreamParserError; +} + +- (BOOL)isError { + return YES; +} + +@end + +#pragma mark - + +@implementation SBJsonStreamParserStateObjectStart + +SINGLETON + +- (NSString*)name { return @"at beginning of object"; } + +- (BOOL)parser:(SBJsonStreamParser*)parser shouldAcceptToken:(sbjson_token_t)token { + switch (token) { + case sbjson_token_object_end: + case sbjson_token_string: + return YES; + break; + default: + return NO; + break; + } +} + +- (void)parser:(SBJsonStreamParser*)parser shouldTransitionTo:(sbjson_token_t)tok { + parser.state = [SBJsonStreamParserStateObjectGotKey sharedInstance]; +} + +- (BOOL)needKey { + return YES; +} + +@end + +#pragma mark - + +@implementation SBJsonStreamParserStateObjectGotKey + +SINGLETON + +- (NSString*)name { return @"after object key"; } + +- (BOOL)parser:(SBJsonStreamParser*)parser shouldAcceptToken:(sbjson_token_t)token { + return token == sbjson_token_keyval_separator; +} + +- (void)parser:(SBJsonStreamParser*)parser shouldTransitionTo:(sbjson_token_t)tok { + parser.state = [SBJsonStreamParserStateObjectSeparator sharedInstance]; +} + +@end + +#pragma mark - + +@implementation SBJsonStreamParserStateObjectSeparator + +SINGLETON + +- (NSString*)name { return @"as object value"; } + +- (BOOL)parser:(SBJsonStreamParser*)parser shouldAcceptToken:(sbjson_token_t)token { + switch (token) { + case sbjson_token_object_start: + case sbjson_token_array_start: + case sbjson_token_true: + case sbjson_token_false: + case sbjson_token_null: + case sbjson_token_number: + case sbjson_token_string: + return YES; + break; + + default: + return NO; + break; + } +} + +- (void)parser:(SBJsonStreamParser*)parser shouldTransitionTo:(sbjson_token_t)tok { + parser.state = [SBJsonStreamParserStateObjectGotValue sharedInstance]; +} + +@end + +#pragma mark - + +@implementation SBJsonStreamParserStateObjectGotValue + +SINGLETON + +- (NSString*)name { return @"after object value"; } + +- (BOOL)parser:(SBJsonStreamParser*)parser shouldAcceptToken:(sbjson_token_t)token { + switch (token) { + case sbjson_token_object_end: + case sbjson_token_separator: + return YES; + break; + default: + return NO; + break; + } +} + +- (void)parser:(SBJsonStreamParser*)parser shouldTransitionTo:(sbjson_token_t)tok { + parser.state = [SBJsonStreamParserStateObjectNeedKey sharedInstance]; +} + + +@end + +#pragma mark - + +@implementation SBJsonStreamParserStateObjectNeedKey + +SINGLETON + +- (NSString*)name { return @"in place of object key"; } + +- (BOOL)parser:(SBJsonStreamParser*)parser shouldAcceptToken:(sbjson_token_t)token { + return sbjson_token_string == token; +} + +- (void)parser:(SBJsonStreamParser*)parser shouldTransitionTo:(sbjson_token_t)tok { + parser.state = [SBJsonStreamParserStateObjectGotKey sharedInstance]; +} + +- (BOOL)needKey { + return YES; +} + +@end + +#pragma mark - + +@implementation SBJsonStreamParserStateArrayStart + +SINGLETON + +- (NSString*)name { return @"at array start"; } + +- (BOOL)parser:(SBJsonStreamParser*)parser shouldAcceptToken:(sbjson_token_t)token { + switch (token) { + case sbjson_token_object_end: + case sbjson_token_keyval_separator: + case sbjson_token_separator: + return NO; + break; + + default: + return YES; + break; + } +} + +- (void)parser:(SBJsonStreamParser*)parser shouldTransitionTo:(sbjson_token_t)tok { + parser.state = [SBJsonStreamParserStateArrayGotValue sharedInstance]; +} + +@end + +#pragma mark - + +@implementation SBJsonStreamParserStateArrayGotValue + +SINGLETON + +- (NSString*)name { return @"after array value"; } + + +- (BOOL)parser:(SBJsonStreamParser*)parser shouldAcceptToken:(sbjson_token_t)token { + return token == sbjson_token_array_end || token == sbjson_token_separator; +} + +- (void)parser:(SBJsonStreamParser*)parser shouldTransitionTo:(sbjson_token_t)tok { + if (tok == sbjson_token_separator) + parser.state = [SBJsonStreamParserStateArrayNeedValue sharedInstance]; +} + +@end + +#pragma mark - + +@implementation SBJsonStreamParserStateArrayNeedValue + +SINGLETON + +- (NSString*)name { return @"as array value"; } + + +- (BOOL)parser:(SBJsonStreamParser*)parser shouldAcceptToken:(sbjson_token_t)token { + switch (token) { + case sbjson_token_array_end: + case sbjson_token_keyval_separator: + case sbjson_token_object_end: + case sbjson_token_separator: + return NO; + break; + + default: + return YES; + break; + } +} + +- (void)parser:(SBJsonStreamParser*)parser shouldTransitionTo:(sbjson_token_t)tok { + parser.state = [SBJsonStreamParserStateArrayGotValue sharedInstance]; +} + +@end + diff --git a/mac/TeamTalk/SBJson/SBJsonStreamWriter.h b/mac/TeamTalk/SBJson/SBJsonStreamWriter.h new file mode 100755 index 000000000..7794a14f8 --- /dev/null +++ b/mac/TeamTalk/SBJson/SBJsonStreamWriter.h @@ -0,0 +1,210 @@ +/* + Copyright (c) 2010, Stig Brautaset. + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are + met: + + Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + Neither the name of the the author nor the names of its contributors + may be used to endorse or promote products derived from this software + without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS + IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A + PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#import + +/// Enable JSON writing for non-native objects +@interface NSObject (SBProxyForJson) + +/** + Allows generation of JSON for otherwise unsupported classes. + + If you have a custom class that you want to create a JSON representation + for you can implement this method in your class. It should return a + representation of your object defined in terms of objects that can be + translated into JSON. For example, a Person object might implement it like this: + + - (id)proxyForJson { + return [NSDictionary dictionaryWithObjectsAndKeys: + name, @"name", + phone, @"phone", + email, @"email", + nil]; + } + + */ +- (id)proxyForJson; + +@end + +@class SBJsonStreamWriter; + +@protocol SBJsonStreamWriterDelegate + +- (void)writer:(SBJsonStreamWriter*)writer appendBytes:(const void *)bytes length:(NSUInteger)length; + +@end + +@class SBJsonStreamWriterState; + +/** + The Stream Writer class. + + Accepts a stream of messages and writes JSON of these to its delegate object. + + This class provides a range of high-, mid- and low-level methods. You can mix + and match calls to these. For example, you may want to call -writeArrayOpen + to start an array and then repeatedly call -writeObject: with various objects + before finishing off with a -writeArrayClose call. + + Objective-C types are mapped to JSON types in the following way: + + - NSNull -> null + - NSString -> string + - NSArray -> array + - NSDictionary -> object + - NSNumber's -initWithBool:YES -> true + - NSNumber's -initWithBool:NO -> false + - NSNumber -> number + + NSNumber instances created with the -numberWithBool: method are + converted into the JSON boolean "true" and "false" values, and vice + versa. Any other NSNumber instances are converted to a JSON number the + way you would expect. + + @warning: In JSON the keys of an object must be strings. NSDictionary + keys need not be, but attempting to convert an NSDictionary with + non-string keys into JSON will throw an exception.* + + */ + +@interface SBJsonStreamWriter : NSObject { + NSMutableDictionary *cache; +} + +@property (nonatomic, unsafe_unretained) SBJsonStreamWriterState *state; // Internal +@property (nonatomic, readonly, strong) NSMutableArray *stateStack; // Internal + +/** + delegate to receive JSON output + Delegate that will receive messages with output. + */ +@property (unsafe_unretained) id delegate; + +/** + The maximum recursing depth. + + Defaults to 512. If the input is nested deeper than this the input will be deemed to be + malicious and the parser returns nil, signalling an error. ("Nested too deep".) You can + turn off this security feature by setting the maxDepth value to 0. + */ +@property NSUInteger maxDepth; + +/** + Whether we are generating human-readable (multiline) JSON. + + Set whether or not to generate human-readable JSON. The default is NO, which produces + JSON without any whitespace between tokens. If set to YES, generates human-readable + JSON with linebreaks after each array value and dictionary key/value pair, indented two + spaces per nesting level. + */ +@property BOOL humanReadable; + +/** + Whether or not to sort the dictionary keys in the output. + + If this is set to YES, the dictionary keys in the JSON output will be in sorted order. + (This is useful if you need to compare two structures, for example.) The default is NO. + */ +@property BOOL sortKeys; + +/** + An optional comparator to be used if sortKeys is YES. + + If this is nil, sorting will be done via @selector(compare:). + */ +@property (copy) NSComparator sortKeysComparator; + +/// Contains the error description after an error has occured. +@property (copy) NSString *error; + +/** + Write an NSDictionary to the JSON stream. + @return YES if successful, or NO on failure + */ +- (BOOL)writeObject:(NSDictionary*)dict; + +/** + Write an NSArray to the JSON stream. + @return YES if successful, or NO on failure + */ +- (BOOL)writeArray:(NSArray *)array; + +/** + Start writing an Object to the stream + @return YES if successful, or NO on failure +*/ +- (BOOL)writeObjectOpen; + +/** + Close the current object being written + @return YES if successful, or NO on failure +*/ +- (BOOL)writeObjectClose; + +/** Start writing an Array to the stream + @return YES if successful, or NO on failure +*/ +- (BOOL)writeArrayOpen; + +/** Close the current Array being written + @return YES if successful, or NO on failure +*/ +- (BOOL)writeArrayClose; + +/** Write a null to the stream + @return YES if successful, or NO on failure +*/ +- (BOOL)writeNull; + +/** Write a boolean to the stream + @return YES if successful, or NO on failure +*/ +- (BOOL)writeBool:(BOOL)x; + +/** Write a Number to the stream + @return YES if successful, or NO on failure +*/ +- (BOOL)writeNumber:(NSNumber*)n; + +/** Write a String to the stream + @return YES if successful, or NO on failure +*/ +- (BOOL)writeString:(NSString*)s; + +@end + +@interface SBJsonStreamWriter (Private) +- (BOOL)writeValue:(id)v; +- (void)appendBytes:(const void *)bytes length:(NSUInteger)length; +@end + diff --git a/mac/TeamTalk/SBJson/SBJsonStreamWriter.m b/mac/TeamTalk/SBJson/SBJsonStreamWriter.m new file mode 100755 index 000000000..f94cd104d --- /dev/null +++ b/mac/TeamTalk/SBJson/SBJsonStreamWriter.m @@ -0,0 +1,374 @@ +/* + Copyright (c) 2010, Stig Brautaset. + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are + met: + + Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + Neither the name of the the author nor the names of its contributors + may be used to endorse or promote products derived from this software + without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS + IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A + PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#if !__has_feature(objc_arc) +#error "This source file must be compiled with ARC enabled!" +#endif + +#import "SBJsonStreamWriter.h" +#import "SBJsonStreamWriterState.h" + +static NSNumber *kNotANumber; +static NSNumber *kTrue; +static NSNumber *kFalse; +static NSNumber *kPositiveInfinity; +static NSNumber *kNegativeInfinity; + + +@implementation SBJsonStreamWriter + +@synthesize error; +@synthesize maxDepth; +@synthesize state; +@synthesize stateStack; +@synthesize humanReadable; +@synthesize sortKeys; +@synthesize sortKeysComparator; + ++ (void)initialize { + kNotANumber = [NSDecimalNumber notANumber]; + kPositiveInfinity = [NSNumber numberWithDouble:+HUGE_VAL]; + kNegativeInfinity = [NSNumber numberWithDouble:-HUGE_VAL]; + kTrue = [NSNumber numberWithBool:YES]; + kFalse = [NSNumber numberWithBool:NO]; +} + +#pragma mark Housekeeping + +@synthesize delegate; + +- (id)init { + self = [super init]; + if (self) { + maxDepth = 32u; + stateStack = [[NSMutableArray alloc] initWithCapacity:maxDepth]; + state = [SBJsonStreamWriterStateStart sharedInstance]; + cache = [[NSMutableDictionary alloc] initWithCapacity:32]; + } + return self; +} + +#pragma mark Methods + +- (void)appendBytes:(const void *)bytes length:(NSUInteger)length { + [delegate writer:self appendBytes:bytes length:length]; +} + +- (BOOL)writeObject:(NSDictionary *)dict { + if (![self writeObjectOpen]) + return NO; + + NSArray *keys = [dict allKeys]; + + if (sortKeys) { + if (sortKeysComparator) { + keys = [keys sortedArrayWithOptions:NSSortStable usingComparator:sortKeysComparator]; + } + else{ + keys = [keys sortedArrayUsingSelector:@selector(compare:)]; + } + } + + for (id k in keys) { + if (![k isKindOfClass:[NSString class]]) { + self.error = [NSString stringWithFormat:@"JSON object key must be string: %@", k]; + return NO; + } + + if (![self writeString:k]) + return NO; + if (![self writeValue:[dict objectForKey:k]]) + return NO; + } + + return [self writeObjectClose]; +} + +- (BOOL)writeArray:(NSArray*)array { + if (![self writeArrayOpen]) + return NO; + for (id v in array) + if (![self writeValue:v]) + return NO; + return [self writeArrayClose]; +} + + +- (BOOL)writeObjectOpen { + if ([state isInvalidState:self]) return NO; + if ([state expectingKey:self]) return NO; + [state appendSeparator:self]; + if (humanReadable && stateStack.count) [state appendWhitespace:self]; + + [stateStack addObject:state]; + self.state = [SBJsonStreamWriterStateObjectStart sharedInstance]; + + if (maxDepth && stateStack.count > maxDepth) { + self.error = @"Nested too deep"; + return NO; + } + + [delegate writer:self appendBytes:"{" length:1]; + return YES; +} + +- (BOOL)writeObjectClose { + if ([state isInvalidState:self]) return NO; + + SBJsonStreamWriterState *prev = state; + + self.state = [stateStack lastObject]; + [stateStack removeLastObject]; + + if (humanReadable) [prev appendWhitespace:self]; + [delegate writer:self appendBytes:"}" length:1]; + + [state transitionState:self]; + return YES; +} + +- (BOOL)writeArrayOpen { + if ([state isInvalidState:self]) return NO; + if ([state expectingKey:self]) return NO; + [state appendSeparator:self]; + if (humanReadable && stateStack.count) [state appendWhitespace:self]; + + [stateStack addObject:state]; + self.state = [SBJsonStreamWriterStateArrayStart sharedInstance]; + + if (maxDepth && stateStack.count > maxDepth) { + self.error = @"Nested too deep"; + return NO; + } + + [delegate writer:self appendBytes:"[" length:1]; + return YES; +} + +- (BOOL)writeArrayClose { + if ([state isInvalidState:self]) return NO; + if ([state expectingKey:self]) return NO; + + SBJsonStreamWriterState *prev = state; + + self.state = [stateStack lastObject]; + [stateStack removeLastObject]; + + if (humanReadable) [prev appendWhitespace:self]; + [delegate writer:self appendBytes:"]" length:1]; + + [state transitionState:self]; + return YES; +} + +- (BOOL)writeNull { + if ([state isInvalidState:self]) return NO; + if ([state expectingKey:self]) return NO; + [state appendSeparator:self]; + if (humanReadable) [state appendWhitespace:self]; + + [delegate writer:self appendBytes:"null" length:4]; + [state transitionState:self]; + return YES; +} + +- (BOOL)writeBool:(BOOL)x { + if ([state isInvalidState:self]) return NO; + if ([state expectingKey:self]) return NO; + [state appendSeparator:self]; + if (humanReadable) [state appendWhitespace:self]; + + if (x) + [delegate writer:self appendBytes:"true" length:4]; + else + [delegate writer:self appendBytes:"false" length:5]; + [state transitionState:self]; + return YES; +} + + +- (BOOL)writeValue:(id)o { + if ([o isKindOfClass:[NSDictionary class]]) { + return [self writeObject:o]; + + } else if ([o isKindOfClass:[NSArray class]]) { + return [self writeArray:o]; + + } else if ([o isKindOfClass:[NSString class]]) { + [self writeString:o]; + return YES; + + } else if ([o isKindOfClass:[NSNumber class]]) { + return [self writeNumber:o]; + + } else if ([o isKindOfClass:[NSNull class]]) { + return [self writeNull]; + + } else if ([o respondsToSelector:@selector(proxyForJson)]) { + return [self writeValue:[o proxyForJson]]; + + } + + self.error = [NSString stringWithFormat:@"JSON serialisation not supported for %@", [o class]]; + return NO; +} + +static const char *strForChar(int c) { + switch (c) { + case 0: return "\\u0000"; break; + case 1: return "\\u0001"; break; + case 2: return "\\u0002"; break; + case 3: return "\\u0003"; break; + case 4: return "\\u0004"; break; + case 5: return "\\u0005"; break; + case 6: return "\\u0006"; break; + case 7: return "\\u0007"; break; + case 8: return "\\b"; break; + case 9: return "\\t"; break; + case 10: return "\\n"; break; + case 11: return "\\u000b"; break; + case 12: return "\\f"; break; + case 13: return "\\r"; break; + case 14: return "\\u000e"; break; + case 15: return "\\u000f"; break; + case 16: return "\\u0010"; break; + case 17: return "\\u0011"; break; + case 18: return "\\u0012"; break; + case 19: return "\\u0013"; break; + case 20: return "\\u0014"; break; + case 21: return "\\u0015"; break; + case 22: return "\\u0016"; break; + case 23: return "\\u0017"; break; + case 24: return "\\u0018"; break; + case 25: return "\\u0019"; break; + case 26: return "\\u001a"; break; + case 27: return "\\u001b"; break; + case 28: return "\\u001c"; break; + case 29: return "\\u001d"; break; + case 30: return "\\u001e"; break; + case 31: return "\\u001f"; break; + case 34: return "\\\""; break; + case 92: return "\\\\"; break; + } + DDLog(@"FUTFUTFUT: -->'%c'<---", c); + return "FUTFUTFUT"; +} + +- (BOOL)writeString:(NSString*)string { + if ([state isInvalidState:self]) return NO; + [state appendSeparator:self]; + if (humanReadable) [state appendWhitespace:self]; + + NSMutableData *buf = [cache objectForKey:string]; + if (!buf) { + + NSUInteger len = [string lengthOfBytesUsingEncoding:NSUTF8StringEncoding]; + const char *utf8 = [string UTF8String]; + NSUInteger written = 0, i = 0; + + buf = [NSMutableData dataWithCapacity:(NSUInteger)(len * 1.1f)]; + [buf appendBytes:"\"" length:1]; + + for (i = 0; i < len; i++) { + int c = utf8[i]; + BOOL isControlChar = c >= 0 && c < 32; + if (isControlChar || c == '"' || c == '\\') { + if (i - written) + [buf appendBytes:utf8 + written length:i - written]; + written = i + 1; + + const char *t = strForChar(c); + [buf appendBytes:t length:strlen(t)]; + } + } + + if (i - written) + [buf appendBytes:utf8 + written length:i - written]; + + [buf appendBytes:"\"" length:1]; + [cache setObject:buf forKey:string]; + } + + [delegate writer:self appendBytes:[buf bytes] length:[buf length]]; + [state transitionState:self]; + return YES; +} + +- (BOOL)writeNumber:(NSNumber*)number { + if (number == kTrue || number == kFalse) + return [self writeBool:[number boolValue]]; + + if ([state isInvalidState:self]) return NO; + if ([state expectingKey:self]) return NO; + [state appendSeparator:self]; + if (humanReadable) [state appendWhitespace:self]; + + if ([kPositiveInfinity isEqualToNumber:number]) { + self.error = @"+Infinity is not a valid number in JSON"; + return NO; + + } else if ([kNegativeInfinity isEqualToNumber:number]) { + self.error = @"-Infinity is not a valid number in JSON"; + return NO; + + } else if ([kNotANumber isEqualToNumber:number]) { + self.error = @"NaN is not a valid number in JSON"; + return NO; + } + + const char *objcType = [number objCType]; + char num[128]; + size_t len; + + switch (objcType[0]) { + case 'c': case 'i': case 's': case 'l': case 'q': + len = snprintf(num, sizeof num, "%lld", [number longLongValue]); + break; + case 'C': case 'I': case 'S': case 'L': case 'Q': + len = snprintf(num, sizeof num, "%llu", [number unsignedLongLongValue]); + break; + case 'f': case 'd': default: + if ([number isKindOfClass:[NSDecimalNumber class]]) { + char const *utf8 = [[number stringValue] UTF8String]; + [delegate writer:self appendBytes:utf8 length: strlen(utf8)]; + [state transitionState:self]; + return YES; + } + len = snprintf(num, sizeof num, "%.17g", [number doubleValue]); + break; + } + [delegate writer:self appendBytes:num length: len]; + [state transitionState:self]; + return YES; +} + +@end diff --git a/mac/TeamTalk/SBJson/SBJsonStreamWriterAccumulator.h b/mac/TeamTalk/SBJson/SBJsonStreamWriterAccumulator.h new file mode 100755 index 000000000..b12d0d5ca --- /dev/null +++ b/mac/TeamTalk/SBJson/SBJsonStreamWriterAccumulator.h @@ -0,0 +1,36 @@ +/* + Copyright (C) 2011 Stig Brautaset. All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + + * Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + + * Neither the name of the author nor the names of its contributors may be used + to endorse or promote products derived from this software without specific + prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE + FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#import "SBJsonStreamWriter.h" + +@interface SBJsonStreamWriterAccumulator : NSObject + +@property (readonly, copy) NSMutableData* data; + +@end diff --git a/mac/TeamTalk/SBJson/SBJsonStreamWriterAccumulator.m b/mac/TeamTalk/SBJson/SBJsonStreamWriterAccumulator.m new file mode 100755 index 000000000..d78c3176d --- /dev/null +++ b/mac/TeamTalk/SBJson/SBJsonStreamWriterAccumulator.m @@ -0,0 +1,56 @@ +/* + Copyright (C) 2011 Stig Brautaset. All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + + * Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + + * Neither the name of the author nor the names of its contributors may be used + to endorse or promote products derived from this software without specific + prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE + FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#if !__has_feature(objc_arc) +#error "This source file must be compiled with ARC enabled!" +#endif + +#import "SBJsonStreamWriterAccumulator.h" + + +@implementation SBJsonStreamWriterAccumulator + +@synthesize data; + +- (id)init { + self = [super init]; + if (self) { + data = [[NSMutableData alloc] initWithCapacity:8096u]; + } + return self; +} + + +#pragma mark SBJsonStreamWriterDelegate + +- (void)writer:(SBJsonStreamWriter *)writer appendBytes:(const void *)bytes length:(NSUInteger)length { + [data appendBytes:bytes length:length]; +} + +@end diff --git a/mac/TeamTalk/SBJson/SBJsonStreamWriterState.h b/mac/TeamTalk/SBJson/SBJsonStreamWriterState.h new file mode 100755 index 000000000..90d442a08 --- /dev/null +++ b/mac/TeamTalk/SBJson/SBJsonStreamWriterState.h @@ -0,0 +1,69 @@ +/* + Copyright (c) 2010, Stig Brautaset. + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are + met: + + Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + Neither the name of the the author nor the names of its contributors + may be used to endorse or promote products derived from this software + without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS + IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A + PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#import + +@class SBJsonStreamWriter; + +@interface SBJsonStreamWriterState : NSObject ++ (id)sharedInstance; +- (BOOL)isInvalidState:(SBJsonStreamWriter*)writer; +- (void)appendSeparator:(SBJsonStreamWriter*)writer; +- (BOOL)expectingKey:(SBJsonStreamWriter*)writer; +- (void)transitionState:(SBJsonStreamWriter*)writer; +- (void)appendWhitespace:(SBJsonStreamWriter*)writer; +@end + +@interface SBJsonStreamWriterStateObjectStart : SBJsonStreamWriterState +@end + +@interface SBJsonStreamWriterStateObjectKey : SBJsonStreamWriterStateObjectStart +@end + +@interface SBJsonStreamWriterStateObjectValue : SBJsonStreamWriterState +@end + +@interface SBJsonStreamWriterStateArrayStart : SBJsonStreamWriterState +@end + +@interface SBJsonStreamWriterStateArrayValue : SBJsonStreamWriterState +@end + +@interface SBJsonStreamWriterStateStart : SBJsonStreamWriterState +@end + +@interface SBJsonStreamWriterStateComplete : SBJsonStreamWriterState +@end + +@interface SBJsonStreamWriterStateError : SBJsonStreamWriterState +@end + diff --git a/mac/TeamTalk/SBJson/SBJsonStreamWriterState.m b/mac/TeamTalk/SBJson/SBJsonStreamWriterState.m new file mode 100755 index 000000000..a87b447d4 --- /dev/null +++ b/mac/TeamTalk/SBJson/SBJsonStreamWriterState.m @@ -0,0 +1,147 @@ +/* + Copyright (c) 2010, Stig Brautaset. + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are + met: + + Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + Neither the name of the the author nor the names of its contributors + may be used to endorse or promote products derived from this software + without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS + IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A + PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#if !__has_feature(objc_arc) +#error "This source file must be compiled with ARC enabled!" +#endif + +#import "SBJsonStreamWriterState.h" +#import "SBJsonStreamWriter.h" + +#define SINGLETON \ ++ (id)sharedInstance { \ + static id state = nil; \ + if (!state) { \ + @synchronized(self) { \ + if (!state) state = [[self alloc] init]; \ + } \ + } \ + return state; \ +} + + +@implementation SBJsonStreamWriterState ++ (id)sharedInstance { return nil; } +- (BOOL)isInvalidState:(SBJsonStreamWriter*)writer { return NO; } +- (void)appendSeparator:(SBJsonStreamWriter*)writer {} +- (BOOL)expectingKey:(SBJsonStreamWriter*)writer { return NO; } +- (void)transitionState:(SBJsonStreamWriter *)writer {} +- (void)appendWhitespace:(SBJsonStreamWriter*)writer { + [writer appendBytes:"\n" length:1]; + for (NSUInteger i = 0; i < writer.stateStack.count; i++) + [writer appendBytes:" " length:2]; +} +@end + +@implementation SBJsonStreamWriterStateObjectStart + +SINGLETON + +- (void)transitionState:(SBJsonStreamWriter *)writer { + writer.state = [SBJsonStreamWriterStateObjectValue sharedInstance]; +} +- (BOOL)expectingKey:(SBJsonStreamWriter *)writer { + writer.error = @"JSON object key must be string"; + return YES; +} +@end + +@implementation SBJsonStreamWriterStateObjectKey + +SINGLETON + +- (void)appendSeparator:(SBJsonStreamWriter *)writer { + [writer appendBytes:"," length:1]; +} +@end + +@implementation SBJsonStreamWriterStateObjectValue + +SINGLETON + +- (void)appendSeparator:(SBJsonStreamWriter *)writer { + [writer appendBytes:":" length:1]; +} +- (void)transitionState:(SBJsonStreamWriter *)writer { + writer.state = [SBJsonStreamWriterStateObjectKey sharedInstance]; +} +- (void)appendWhitespace:(SBJsonStreamWriter *)writer { + [writer appendBytes:" " length:1]; +} +@end + +@implementation SBJsonStreamWriterStateArrayStart + +SINGLETON + +- (void)transitionState:(SBJsonStreamWriter *)writer { + writer.state = [SBJsonStreamWriterStateArrayValue sharedInstance]; +} +@end + +@implementation SBJsonStreamWriterStateArrayValue + +SINGLETON + +- (void)appendSeparator:(SBJsonStreamWriter *)writer { + [writer appendBytes:"," length:1]; +} +@end + +@implementation SBJsonStreamWriterStateStart + +SINGLETON + + +- (void)transitionState:(SBJsonStreamWriter *)writer { + writer.state = [SBJsonStreamWriterStateComplete sharedInstance]; +} +- (void)appendSeparator:(SBJsonStreamWriter *)writer { +} +@end + +@implementation SBJsonStreamWriterStateComplete + +SINGLETON + +- (BOOL)isInvalidState:(SBJsonStreamWriter*)writer { + writer.error = @"Stream is closed"; + return YES; +} +@end + +@implementation SBJsonStreamWriterStateError + +SINGLETON + +@end + diff --git a/mac/TeamTalk/SBJson/SBJsonTokeniser.h b/mac/TeamTalk/SBJson/SBJsonTokeniser.h new file mode 100755 index 000000000..e484a9482 --- /dev/null +++ b/mac/TeamTalk/SBJson/SBJsonTokeniser.h @@ -0,0 +1,67 @@ +/* + Copyright (c) 2010, Stig Brautaset. + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are + met: + + Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + Neither the name of the the author nor the names of its contributors + may be used to endorse or promote products derived from this software + without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS + IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A + PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#import + +typedef enum { + sbjson_token_error = -1, + sbjson_token_eof, + + sbjson_token_array_start, + sbjson_token_array_end, + + sbjson_token_object_start, + sbjson_token_object_end, + + sbjson_token_separator, + sbjson_token_keyval_separator, + + sbjson_token_number, + sbjson_token_string, + sbjson_token_true, + sbjson_token_false, + sbjson_token_null, + +} sbjson_token_t; + +@class SBJsonUTF8Stream; + +@interface SBJsonTokeniser : NSObject + +@property (strong) SBJsonUTF8Stream *stream; +@property (copy) NSString *error; + +- (void)appendData:(NSData*)data_; + +- (sbjson_token_t)getToken:(NSObject**)token; + +@end diff --git a/mac/TeamTalk/SBJson/SBJsonTokeniser.m b/mac/TeamTalk/SBJson/SBJsonTokeniser.m new file mode 100755 index 000000000..9b68d2e6d --- /dev/null +++ b/mac/TeamTalk/SBJson/SBJsonTokeniser.m @@ -0,0 +1,477 @@ +/* + Copyright (c) 2010-2011, Stig Brautaset. All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are + met: + + Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + Neither the name of the the author nor the names of its contributors + may be used to endorse or promote products derived from this software + without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS + IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A + PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#if !__has_feature(objc_arc) +#error "This source file must be compiled with ARC enabled!" +#endif + +#import "SBJsonTokeniser.h" +#import "SBJsonUTF8Stream.h" + +#define SBStringIsIllegalSurrogateHighCharacter(character) (((character) >= 0xD800UL) && ((character) <= 0xDFFFUL)) +#define SBStringIsSurrogateLowCharacter(character) ((character >= 0xDC00UL) && (character <= 0xDFFFUL)) +#define SBStringIsSurrogateHighCharacter(character) ((character >= 0xD800UL) && (character <= 0xDBFFUL)) + +static int const DECIMAL_MAX_PRECISION = 38; +static int const DECIMAL_EXPONENT_MAX = 127; +static short const DECIMAL_EXPONENT_MIN = -128; +static int const LONG_LONG_DIGITS = 19; + +static NSCharacterSet *kDecimalDigitCharacterSet; + +@implementation SBJsonTokeniser + +@synthesize error = _error; +@synthesize stream = _stream; + ++ (void)initialize { + kDecimalDigitCharacterSet = [NSCharacterSet decimalDigitCharacterSet]; +} + +- (id)init { + self = [super init]; + if (self) { + _stream = [[SBJsonUTF8Stream alloc] init]; + + } + + return self; +} + + +- (void)appendData:(NSData *)data_ { + [_stream appendData:data_]; +} + + +- (sbjson_token_t)match:(const char *)pattern length:(NSUInteger)len retval:(sbjson_token_t)token { + if (![_stream haveRemainingCharacters:len]) + return sbjson_token_eof; + + if ([_stream skipCharacters:pattern length:len]) + return token; + + self.error = [NSString stringWithFormat:@"Expected '%s' after initial '%.1s'", pattern, pattern]; + return sbjson_token_error; +} + +- (BOOL)decodeEscape:(unichar)ch into:(unichar*)decoded { + switch (ch) { + case '\\': + case '/': + case '"': + *decoded = ch; + break; + + case 'b': + *decoded = '\b'; + break; + + case 'n': + *decoded = '\n'; + break; + + case 'r': + *decoded = '\r'; + break; + + case 't': + *decoded = '\t'; + break; + + case 'f': + *decoded = '\f'; + break; + + default: + self.error = @"Illegal escape character"; + return NO; + break; + } + return YES; +} + +- (BOOL)decodeHexQuad:(unichar*)quad { + unichar c, tmp = 0; + + for (int i = 0; i < 4; i++) { + (void)[_stream getNextUnichar:&c]; + tmp *= 16; + switch (c) { + case '0' ... '9': + tmp += c - '0'; + break; + + case 'a' ... 'f': + tmp += 10 + c - 'a'; + break; + + case 'A' ... 'F': + tmp += 10 + c - 'A'; + break; + + default: + return NO; + } + } + *quad = tmp; + return YES; +} + +- (sbjson_token_t)getStringToken:(NSObject**)token { + NSMutableString *acc = nil; + + for (;;) { + [_stream skip]; + + unichar ch; + { + NSMutableString *string = nil; + + if (![_stream getStringFragment:&string]) + return sbjson_token_eof; + + if (!string) { + self.error = @"Broken Unicode encoding"; + return sbjson_token_error; + } + + if (![_stream getUnichar:&ch]) + return sbjson_token_eof; + + if (acc) { + [acc appendString:string]; + + } else if (ch == '"') { + *token = [string copy]; + [_stream skip]; + return sbjson_token_string; + + } else { + acc = [string mutableCopy]; + } + } + + + switch (ch) { + case 0 ... 0x1F: + self.error = [NSString stringWithFormat:@"Unescaped control character [0x%0.2X]", (int)ch]; + return sbjson_token_error; + break; + + case '"': + *token = acc; + [_stream skip]; + return sbjson_token_string; + break; + + case '\\': + if (![_stream getNextUnichar:&ch]) + return sbjson_token_eof; + + if (ch == 'u') { + if (![_stream haveRemainingCharacters:5]) + return sbjson_token_eof; + + unichar hi; + if (![self decodeHexQuad:&hi]) { + self.error = @"Invalid hex quad"; + return sbjson_token_error; + } + + if (SBStringIsSurrogateHighCharacter(hi)) { + unichar lo; + + if (![_stream haveRemainingCharacters:6]) + return sbjson_token_eof; + + (void)[_stream getNextUnichar:&ch]; + (void)[_stream getNextUnichar:&lo]; + if (ch != '\\' || lo != 'u' || ![self decodeHexQuad:&lo]) { + self.error = @"Missing low character in surrogate pair"; + return sbjson_token_error; + } + + if (!SBStringIsSurrogateLowCharacter(lo)) { + self.error = @"Invalid low character in surrogate pair"; + return sbjson_token_error; + } + + [acc appendFormat:@"%C%C", hi, lo]; + } else if (SBStringIsIllegalSurrogateHighCharacter(hi)) { + self.error = @"Invalid high character in surrogate pair"; + return sbjson_token_error; + } else { + [acc appendFormat:@"%C", hi]; + } + + + } else { + unichar decoded; + if (![self decodeEscape:ch into:&decoded]) + return sbjson_token_error; + [acc appendFormat:@"%C", decoded]; + } + + break; + + default: { + self.error = [NSString stringWithFormat:@"Invalid UTF-8: '%x'", (int)ch]; + return sbjson_token_error; + break; + } + } + } + return sbjson_token_eof; +} + +- (sbjson_token_t)getNumberToken:(NSObject**)token { + + NSUInteger numberStart = _stream.index; + + unichar ch; + if (![_stream getUnichar:&ch]) + return sbjson_token_eof; + + BOOL isNegative = NO; + if (ch == '-') { + isNegative = YES; + if (![_stream getNextUnichar:&ch]) + return sbjson_token_eof; + } + + unsigned long long mantissa = 0; + int mantissa_length = 0; + + if (ch == '0') { + mantissa_length++; + if (![_stream getNextUnichar:&ch]) + return sbjson_token_eof; + + if ([kDecimalDigitCharacterSet characterIsMember:ch]) { + self.error = @"Leading zero is illegal in number"; + return sbjson_token_error; + } + } + + while ([kDecimalDigitCharacterSet characterIsMember:ch]) { + mantissa *= 10; + mantissa += (ch - '0'); + mantissa_length++; + + if (![_stream getNextUnichar:&ch]) + return sbjson_token_eof; + } + + short exponent = 0; + BOOL isFloat = NO; + + if (ch == '.') { + isFloat = YES; + if (![_stream getNextUnichar:&ch]) + return sbjson_token_eof; + + while ([kDecimalDigitCharacterSet characterIsMember:ch]) { + mantissa *= 10; + mantissa += (ch - '0'); + mantissa_length++; + exponent--; + + if (![_stream getNextUnichar:&ch]) + return sbjson_token_eof; + } + + if (!exponent) { + self.error = @"No digits after decimal point"; + return sbjson_token_error; + } + } + + BOOL hasExponent = NO; + if (ch == 'e' || ch == 'E') { + hasExponent = YES; + + if (![_stream getNextUnichar:&ch]) + return sbjson_token_eof; + + BOOL expIsNegative = NO; + if (ch == '-') { + expIsNegative = YES; + if (![_stream getNextUnichar:&ch]) + return sbjson_token_eof; + + } else if (ch == '+') { + if (![_stream getNextUnichar:&ch]) + return sbjson_token_eof; + } + + short explicit_exponent = 0; + short explicit_exponent_length = 0; + while ([kDecimalDigitCharacterSet characterIsMember:ch]) { + explicit_exponent *= 10; + explicit_exponent += (ch - '0'); + explicit_exponent_length++; + + if (![_stream getNextUnichar:&ch]) + return sbjson_token_eof; + } + + if (explicit_exponent_length == 0) { + self.error = @"No digits in exponent"; + return sbjson_token_error; + } + + if (expIsNegative) + exponent -= explicit_exponent; + else + exponent += explicit_exponent; + } + + if (!mantissa_length && isNegative) { + self.error = @"No digits after initial minus"; + return sbjson_token_error; + + } else if (mantissa_length > DECIMAL_MAX_PRECISION) { + self.error = @"Precision is too high"; + return sbjson_token_error; + + } else if (exponent > DECIMAL_EXPONENT_MAX || exponent < DECIMAL_EXPONENT_MIN) { + self.error = @"Exponent out of range"; + return sbjson_token_error; + } + + if (mantissa_length <= LONG_LONG_DIGITS) { + if (!isFloat && !hasExponent) { + *token = [NSNumber numberWithLongLong: isNegative ? -mantissa : mantissa]; + } else if (mantissa == 0) { + *token = [NSNumber numberWithFloat:-0.0f]; + } else { + *token = [NSDecimalNumber decimalNumberWithMantissa:mantissa + exponent:exponent + isNegative:isNegative]; + } + + } else { + NSString *number = [_stream stringWithRange:NSMakeRange(numberStart, _stream.index - numberStart)]; + *token = [NSDecimalNumber decimalNumberWithString:number]; + + } + + return sbjson_token_number; +} + +- (sbjson_token_t)getToken:(NSObject **)token { + + [_stream skipWhitespace]; + + unichar ch; + if (![_stream getUnichar:&ch]) + return sbjson_token_eof; + + NSUInteger oldIndexLocation = _stream.index; + sbjson_token_t tok; + + switch (ch) { + case '[': + tok = sbjson_token_array_start; + [_stream skip]; + break; + + case ']': + tok = sbjson_token_array_end; + [_stream skip]; + break; + + case '{': + tok = sbjson_token_object_start; + [_stream skip]; + break; + + case ':': + tok = sbjson_token_keyval_separator; + [_stream skip]; + break; + + case '}': + tok = sbjson_token_object_end; + [_stream skip]; + break; + + case ',': + tok = sbjson_token_separator; + [_stream skip]; + break; + + case 'n': + tok = [self match:"null" length:4 retval:sbjson_token_null]; + break; + + case 't': + tok = [self match:"true" length:4 retval:sbjson_token_true]; + break; + + case 'f': + tok = [self match:"false" length:5 retval:sbjson_token_false]; + break; + + case '"': + tok = [self getStringToken:token]; + break; + + case '0' ... '9': + case '-': + tok = [self getNumberToken:token]; + break; + + case '+': + self.error = @"Leading + is illegal in number"; + tok = sbjson_token_error; + break; + + default: + self.error = [NSString stringWithFormat:@"Illegal start of token [%c]", ch]; + tok = sbjson_token_error; + break; + } + + if (tok == sbjson_token_eof) { + // We ran out of bytes in the middle of a token. + // We don't know how to restart in mid-flight, so + // rewind to the start of the token for next attempt. + // Hopefully we'll have more data then. + _stream.index = oldIndexLocation; + } + + return tok; +} + + +@end diff --git a/mac/TeamTalk/SBJson/SBJsonUTF8Stream.h b/mac/TeamTalk/SBJson/SBJsonUTF8Stream.h new file mode 100755 index 000000000..a26f03265 --- /dev/null +++ b/mac/TeamTalk/SBJson/SBJsonUTF8Stream.h @@ -0,0 +1,58 @@ +/* + Copyright (c) 2011, Stig Brautaset. All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are + met: + + Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + Neither the name of the the author nor the names of its contributors + may be used to endorse or promote products derived from this software + without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS + IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A + PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#import + + +@interface SBJsonUTF8Stream : NSObject { +@private + const char *_bytes; + NSMutableData *_data; + NSUInteger _length; +} + +@property (assign) NSUInteger index; + +- (void)appendData:(NSData*)data_; + +- (BOOL)haveRemainingCharacters:(NSUInteger)chars; + +- (void)skip; +- (void)skipWhitespace; +- (BOOL)skipCharacters:(const char *)chars length:(NSUInteger)len; + +- (BOOL)getUnichar:(unichar*)ch; +- (BOOL)getNextUnichar:(unichar*)ch; +- (BOOL)getStringFragment:(NSString**)string; + +- (NSString*)stringWithRange:(NSRange)range; + +@end diff --git a/mac/TeamTalk/SBJson/SBJsonUTF8Stream.m b/mac/TeamTalk/SBJson/SBJsonUTF8Stream.m new file mode 100755 index 000000000..8185ee1a7 --- /dev/null +++ b/mac/TeamTalk/SBJson/SBJsonUTF8Stream.m @@ -0,0 +1,145 @@ +/* + Copyright (c) 2011, Stig Brautaset. All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are + met: + + Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + Neither the name of the the author nor the names of its contributors + may be used to endorse or promote products derived from this software + without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS + IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A + PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#if !__has_feature(objc_arc) +#error "This source file must be compiled with ARC enabled!" +#endif + +#import "SBJsonUTF8Stream.h" + + +@implementation SBJsonUTF8Stream + +@synthesize index = _index; + +- (id)init { + self = [super init]; + if (self) { + _data = [[NSMutableData alloc] initWithCapacity:4096u]; + } + return self; +} + + +- (void)appendData:(NSData *)data_ { + + if (_index) { + // Discard data we've already parsed + [_data replaceBytesInRange:NSMakeRange(0, _index) withBytes:"" length:0]; + + // Reset index to point to current position + _index = 0; + } + + [_data appendData:data_]; + + // This is an optimisation. + _bytes = (const char*)[_data bytes]; + _length = [_data length]; +} + + +- (BOOL)getUnichar:(unichar*)ch { + if (_index < _length) { + *ch = (unichar)_bytes[_index]; + return YES; + } + return NO; +} + +- (BOOL)getNextUnichar:(unichar*)ch { + if (++_index < _length) { + *ch = (unichar)_bytes[_index]; + return YES; + } + return NO; +} + +- (BOOL)getStringFragment:(NSString **)string { + NSUInteger start = _index; + while (_index < _length) { + switch (_bytes[_index]) { + case '"': + case '\\': + case 0 ... 0x1f: + *string = [[NSString alloc] initWithBytes:(_bytes + start) + length:(_index - start) + encoding:NSUTF8StringEncoding]; + return YES; + break; + default: + _index++; + break; + } + } + return NO; +} + +- (void)skip { + _index++; +} + +- (void)skipWhitespace { + while (_index < _length) { + switch (_bytes[_index]) { + case ' ': + case '\t': + case '\r': + case '\n': + _index++; + break; + default: + return; + break; + } + } +} + +- (BOOL)haveRemainingCharacters:(NSUInteger)chars { + return [_data length] - _index >= chars; +} + +- (BOOL)skipCharacters:(const char *)chars length:(NSUInteger)len { + const void *bytes = ((const char*)[_data bytes]) + _index; + if (!memcmp(bytes, chars, len)) { + _index += len; + return YES; + } + return NO; +} + +- (NSString*)stringWithRange:(NSRange)range { + return [[NSString alloc] initWithBytes:_bytes + range.location length:range.length encoding:NSUTF8StringEncoding]; + +} + + +@end diff --git a/mac/TeamTalk/SBJson/SBJsonWriter.h b/mac/TeamTalk/SBJson/SBJsonWriter.h new file mode 100755 index 000000000..8b0a059e0 --- /dev/null +++ b/mac/TeamTalk/SBJson/SBJsonWriter.h @@ -0,0 +1,119 @@ +/* + Copyright (C) 2009 Stig Brautaset. All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + + * Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + + * Neither the name of the author nor the names of its contributors may be used + to endorse or promote products derived from this software without specific + prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE + FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#import + +/** + The JSON writer class. + + This uses SBJsonStreamWriter internally. + + */ + +@interface SBJsonWriter : NSObject + +/** + The maximum recursing depth. + + Defaults to 32. If the input is nested deeper than this the input will be deemed to be + malicious and the parser returns nil, signalling an error. ("Nested too deep".) You can + turn off this security feature by setting the maxDepth value to 0. + */ +@property NSUInteger maxDepth; + +/** + Return an error trace, or nil if there was no errors. + + Note that this method returns the trace of the last method that failed. + You need to check the return value of the call you're making to figure out + if the call actually failed, before you know call this method. + */ +@property (readonly, copy) NSString *error; + +/** + Whether we are generating human-readable (multiline) JSON. + + Set whether or not to generate human-readable JSON. The default is NO, which produces + JSON without any whitespace. (Except inside strings.) If set to YES, generates human-readable + JSON with linebreaks after each array value and dictionary key/value pair, indented two + spaces per nesting level. + */ +@property BOOL humanReadable; + +/** + Whether or not to sort the dictionary keys in the output. + + If this is set to YES, the dictionary keys in the JSON output will be in sorted order. + (This is useful if you need to compare two structures, for example.) The default is NO. + */ +@property BOOL sortKeys; + +/** + An optional comparator to be used if sortKeys is YES. + + If this is nil, sorting will be done via @selector(compare:). + */ +@property (copy) NSComparator sortKeysComparator; + +/** + Return JSON representation for the given object. + + Returns a string containing JSON representation of the passed in value, or nil on error. + If nil is returned and error is not NULL, *error can be interrogated to find the cause of the error. + + @param value any instance that can be represented as JSON text. + */ +- (NSString*)stringWithObject:(id)value; + +/** + Return JSON representation for the given object. + + Returns an NSData object containing JSON represented as UTF8 text, or nil on error. + + @param value any instance that can be represented as JSON text. + */ +- (NSData*)dataWithObject:(id)value; + +/** + Return JSON representation (or fragment) for the given object. + + Returns a string containing JSON representation of the passed in value, or nil on error. + If nil is returned and error is not NULL, *error can be interrogated to find the cause of the error. + + @param value any instance that can be represented as a JSON fragment + @param error pointer to object to be populated with NSError on failure + + @warning Deprecated in Version 3.2; will be removed in 4.0 + + */ +- (NSString*)stringWithObject:(id)value + error:(NSError**)error __attribute__ ((deprecated)); + + +@end diff --git a/mac/TeamTalk/SBJson/SBJsonWriter.m b/mac/TeamTalk/SBJson/SBJsonWriter.m new file mode 100755 index 000000000..105acb93c --- /dev/null +++ b/mac/TeamTalk/SBJson/SBJsonWriter.m @@ -0,0 +1,116 @@ +/* + Copyright (C) 2009 Stig Brautaset. All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + + * Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + + * Neither the name of the author nor the names of its contributors may be used + to endorse or promote products derived from this software without specific + prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE + FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#if !__has_feature(objc_arc) +#error "This source file must be compiled with ARC enabled!" +#endif + +#import "SBJsonWriter.h" +#import "SBJsonStreamWriter.h" +#import "SBJsonStreamWriterAccumulator.h" + + +@interface SBJsonWriter () +@property (copy) NSString *error; +@end + +@implementation SBJsonWriter + +@synthesize sortKeys; +@synthesize humanReadable; + +@synthesize error; +@synthesize maxDepth; + +@synthesize sortKeysComparator; + +- (id)init { + self = [super init]; + if (self) { + self.maxDepth = 32u; + } + return self; +} + + +- (NSString*)stringWithObject:(id)value { + NSData *data = [self dataWithObject:value]; + if (data) + return [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding]; + return nil; +} + +- (NSString*)stringWithObject:(id)value error:(NSError**)error_ { + NSString *tmp = [self stringWithObject:value]; + if (tmp) + return tmp; + + if (error_) { + NSDictionary *ui = [NSDictionary dictionaryWithObjectsAndKeys:error, NSLocalizedDescriptionKey, nil]; + *error_ = [NSError errorWithDomain:@"org.brautaset.SBJsonWriter.ErrorDomain" code:0 userInfo:ui]; + } + + return nil; +} + +- (NSData*)dataWithObject:(id)object { + self.error = nil; + + SBJsonStreamWriterAccumulator *accumulator = [[SBJsonStreamWriterAccumulator alloc] init]; + + SBJsonStreamWriter *streamWriter = [[SBJsonStreamWriter alloc] init]; + streamWriter.sortKeys = self.sortKeys; + streamWriter.maxDepth = self.maxDepth; + streamWriter.sortKeysComparator = self.sortKeysComparator; + streamWriter.humanReadable = self.humanReadable; + streamWriter.delegate = accumulator; + + BOOL ok = NO; + if ([object isKindOfClass:[NSDictionary class]]) + ok = [streamWriter writeObject:object]; + + else if ([object isKindOfClass:[NSArray class]]) + ok = [streamWriter writeArray:object]; + + else if ([object respondsToSelector:@selector(proxyForJson)]) + return [self dataWithObject:[object proxyForJson]]; + else { + self.error = @"Not valid type for JSON"; + return nil; + } + + if (ok) + return accumulator.data; + + self.error = streamWriter.error; + return nil; +} + + +@end diff --git a/mac/TeamTalk/ScreenCapture/BackgroudView.h b/mac/TeamTalk/ScreenCapture/BackgroudView.h new file mode 100644 index 000000000..043969c68 --- /dev/null +++ b/mac/TeamTalk/ScreenCapture/BackgroudView.h @@ -0,0 +1,16 @@ +// +// BackgroudView.h +// Duoduo +// +// Created by jianqing.du on 14-3-26. +// Copyright (c) 2014年 zuoye. All rights reserved. +// + +#import + +/* + * display black background after screen capture buttons + */ +@interface BackgroudView : NSView + +@end diff --git a/mac/TeamTalk/ScreenCapture/BackgroudView.m b/mac/TeamTalk/ScreenCapture/BackgroudView.m new file mode 100644 index 000000000..9f527a5d7 --- /dev/null +++ b/mac/TeamTalk/ScreenCapture/BackgroudView.m @@ -0,0 +1,32 @@ +// +// BackgroudView.m +// Duoduo +// +// Created by jianqing.du on 14-3-26. +// Copyright (c) 2014年 zuoye. All rights reserved. +// + +#import "BackgroudView.h" + +@implementation BackgroudView + +- (id)initWithFrame:(NSRect)frame +{ + self = [super initWithFrame:frame]; + if (self) { + + } + return self; +} + +- (void)drawRect:(NSRect)dirtyRect +{ + [super drawRect:dirtyRect]; + + NSRect frame = [self frame]; + [[NSColor redColor] set]; + + [NSBezierPath fillRect:frame]; +} + +@end diff --git a/mac/TeamTalk/ScreenCapture/CaptureView.h b/mac/TeamTalk/ScreenCapture/CaptureView.h new file mode 100644 index 000000000..b133b687f --- /dev/null +++ b/mac/TeamTalk/ScreenCapture/CaptureView.h @@ -0,0 +1,52 @@ +// +// CaptureView.h +// MyCapture +// +// Created by jianqing.du on 13-11-25. +// Copyright (c) 2013年 ziteng. All rights reserved. +// + +#import + +#define DRAG_POINT_NUM 8 +#define DRAG_POINT_LEN 6 + +// 最多只能画32个椭圆和矩形框 +#define MAX_ELLIPSE_NUM 32 +#define MAX_RECT_NUM 32 + +@interface CaptureView : NSView +{ + NSImage *image; + NSRect drawingRect; + NSTrackingArea *trackingArea; + BOOL drawDragPoints; + + NSBezierPath *rectPath; // 截屏框 + + // 左下角空心圆开始,按顺时针顺序的8个拖动空心圆 + NSBezierPath *dragPath[DRAG_POINT_NUM]; + NSRect dragRect[DRAG_POINT_NUM]; + + // 画椭圆或矩形注释 + NSBezierPath *drawCommentPath; + BOOL drawComment; + + NSRect ellipseRect[MAX_ELLIPSE_NUM]; + NSInteger ellipseCnt; + NSRect rectRect[MAX_RECT_NUM]; + NSInteger rectCnt; +} + +- (void)setDrawImage:(NSImage* )newImage inRect: (NSRect)rect; +- (void)setDrawDragPoints:(BOOL)flag; +- (int)isInDragPoints:(NSPoint)point; + +- (void)newEllipseRect:(NSRect)rect; +- (void)setEllipseRect:(NSRect)rect; +- (void)newRectangleRect:(NSRect)rect; +- (void)setRectangleRect:(NSRect)rect; + +- (void)drawCommentRect; + +@end diff --git a/mac/TeamTalk/ScreenCapture/CaptureView.m b/mac/TeamTalk/ScreenCapture/CaptureView.m new file mode 100644 index 000000000..7f9e20705 --- /dev/null +++ b/mac/TeamTalk/ScreenCapture/CaptureView.m @@ -0,0 +1,205 @@ +// +// CaptureView.m +// MyCapture +// +// Created by jianqing.du on 13-11-25. +// Copyright (c) 2013年 ziteng. All rights reserved. +// + +#import "CaptureView.h" + + +@implementation CaptureView + +- (id)initWithFrame:(NSRect)frame +{ + self = [super initWithFrame:frame]; + if (self) { + // Initialization code here. + NSRect frame = [[NSScreen mainScreen] frame]; + [self setFrame:frame]; + + // track mouseMoved event when inactive + trackingArea = [[NSTrackingArea alloc] initWithRect:frame options:NSTrackingMouseMoved | NSTrackingActiveAlways owner:self userInfo:nil]; + [self addTrackingArea: trackingArea]; + + drawDragPoints = NO; + rectPath = [NSBezierPath bezierPath]; + [rectPath setLineWidth:1.5]; + + for (int i = 0; i < DRAG_POINT_NUM; i++) { + dragPath[i] = [NSBezierPath bezierPath]; + [dragPath[i] setLineWidth:1.0]; + + dragRect[i].size.width = DRAG_POINT_LEN; + dragRect[i].size.height = DRAG_POINT_LEN; + } + + drawCommentPath = [NSBezierPath bezierPath]; + drawComment = NO; + [drawCommentPath setLineWidth:2.0]; + ellipseCnt = rectCnt = 0; + } + + return self; +} + +- (void)drawRect:(NSRect)dirtyRect +{ + [super drawRect:dirtyRect]; + + // Drawing code here. + if (image) { + [image drawInRect:drawingRect fromRect:drawingRect operation:NSCompositeCopy fraction:1.0]; + + [[NSColor blueColor] set]; + + [rectPath removeAllPoints]; + [rectPath appendBezierPathWithRect:drawingRect]; + [rectPath stroke]; + + + if (drawDragPoints) { + [[NSColor whiteColor] set]; + for (int i = 0; i < DRAG_POINT_NUM; i++) { + [dragPath[i] removeAllPoints]; + [dragPath[i] appendBezierPathWithOvalInRect:dragRect[i]]; + [dragPath[i] fill]; + } + } + + [self drawCommentRect]; + } +} + +- (BOOL)acceptsFirstMouse:(NSEvent *)theEvent +{ + return YES; +} + +- (void)setDrawImage:(NSImage* )newImage inRect: (NSRect)rect +{ + image = newImage; + drawingRect = rect; + //DDLog(@"set new image"); + + // lower-left corner point + dragRect[0].origin.x = rect.origin.x; + dragRect[0].origin.y = rect.origin.y; + + // middle-left point + dragRect[1].origin.x = rect.origin.x; + dragRect[1].origin.y = rect.origin.y + rect.size.height / 2.0; + + // upper-left corner point + dragRect[2].origin.x = rect.origin.x; + dragRect[2].origin.y = rect.origin.y + rect.size.height; + + // middle-upper point + dragRect[3].origin.x = rect.origin.x + rect.size.width / 2.0; + dragRect[3].origin.y = rect.origin.y + rect.size.height; + + // upper-right corner point + dragRect[4].origin.x = rect.origin.x + rect.size.width; + dragRect[4].origin.y = rect.origin.y + rect.size.height; + + // middle-right point + dragRect[5].origin.x = rect.origin.x + rect.size.width; + dragRect[5].origin.y = rect.origin.y + rect.size.height / 2.0; + + // lower-right corner point + dragRect[6].origin.x = rect.origin.x + rect.size.width; + dragRect[6].origin.y = rect.origin.y; + + // middle-lower point + dragRect[7].origin.x = rect.origin.x + rect.size.width / 2.0; + dragRect[7].origin.y = rect.origin.y; + + // 修正位置,x,y都减少DRAG_POINT_LEN / 2 + for (int i = 0; i < DRAG_POINT_NUM; i++) { + dragRect[i].origin.x -= DRAG_POINT_LEN / 2; + dragRect[i].origin.y -= DRAG_POINT_LEN / 2; + } + + [self setNeedsDisplay:YES]; +} + +- (void)setDrawDragPoints:(BOOL)flag +{ + drawDragPoints = flag; + [self setNeedsDisplay:YES]; +} + +/* + * 0 - 7: scale the capture window + * 8: drag the window + * -1: do nothing + */ +- (int)isInDragPoints:(NSPoint)point +{ + for (int i = 0; i < DRAG_POINT_NUM; i++) { + if ([dragPath[i] containsPoint:point]) { + return i; + } + } + + if ([rectPath containsPoint:point]) { + return DRAG_POINT_NUM; + } + + return -1; +} + +- (void)newEllipseRect:(NSRect)rect +{ + if (ellipseCnt >= MAX_ELLIPSE_NUM) { + return; + } + + drawComment = YES; + ellipseRect[ellipseCnt++] = rect; +} + +- (void)setEllipseRect:(NSRect)rect +{ + ellipseRect[ellipseCnt - 1] = rect; + [self setNeedsDisplay:YES]; +} + +- (void)newRectangleRect:(NSRect)rect +{ + if (rectCnt >= MAX_RECT_NUM) { + return; + } + + drawComment = YES; + rectRect[rectCnt++] = rect; +} + +- (void)setRectangleRect:(NSRect)rect +{ + //DDLog(@"rectCnt=%lu, (%.0f, %.0f, %.0f, %.0f", rectCnt, rect.origin.x, + // rect.origin.y, rect.size.width, rect.size.height); + rectRect[rectCnt - 1] = rect; + [self setNeedsDisplay:YES]; +} + +- (void)drawCommentRect +{ + if (drawComment) { + [[NSColor redColor] set]; + for (NSInteger i = 0; i < ellipseCnt; i++) { + [drawCommentPath removeAllPoints]; + [drawCommentPath appendBezierPathWithOvalInRect:ellipseRect[i]]; + [drawCommentPath stroke]; + } + + for (NSInteger i = 0; i < rectCnt; i++) { + [drawCommentPath removeAllPoints]; + [drawCommentPath appendBezierPathWithRect:rectRect[i]]; + [drawCommentPath stroke]; + } + } +} + +@end diff --git a/mac/TeamTalk/ScreenCapture/CaptureWindow.h b/mac/TeamTalk/ScreenCapture/CaptureWindow.h new file mode 100644 index 000000000..feec441ed --- /dev/null +++ b/mac/TeamTalk/ScreenCapture/CaptureWindow.h @@ -0,0 +1,40 @@ +// +// CaptureWindow.h +// MyCapture +// +// Created by jianqing.du on 13-11-26. +// Copyright (c) 2013年 ziteng. All rights reserved. +// + +#import +//#import "DDScreenCaptureModule.h" + +@class BackgroudView; + +@interface CaptureWindow : NSWindow +{ + // These points are used in dragging to mark capture region + NSPoint startLocation; + NSPoint currentLocation; + + NSImage* originImage; + NSImage* darkImage; + + CFArrayRef windowList; + + int captureState; + NSRect captureWindowRect; + + int dragDirection; + + IBOutlet id myView; + NSButton *okButton; + NSButton *cancelButton; + NSButton *ellipseButton; + NSButton *rectButton; + BackgroudView *backgroundView; +} + +- (void)captureScreen; ++(CaptureWindow *)shareInsatnce; +@end diff --git a/mac/TeamTalk/ScreenCapture/CaptureWindow.m b/mac/TeamTalk/ScreenCapture/CaptureWindow.m new file mode 100644 index 000000000..6a2ac4cea --- /dev/null +++ b/mac/TeamTalk/ScreenCapture/CaptureWindow.m @@ -0,0 +1,499 @@ +// +// CaptureWindow.m +// MyCapture +// +// Created by jianqing.du on 13-11-26. +// Copyright (c) 2013年 ziteng. All rights reserved. +// + +#import "CaptureWindow.h" +#import "CaptureView.h" +#import "BackgroudView.h" +#import "MTScreenCaptureModule.h" +#import "DDInterfaceController.h" +#import "DDWindowAdditions.h" +#define BUTTON_SIZE 32 + +enum { + CAPTURE_STATE_IDLE, + CAPTURE_STATE_CAPTURING, + CAPTURE_STATE_DONE, + CAPTURE_STATE_DRAG, + CAPTURE_STATE_SCALE, + CAPTURE_STATE_DRAW_ELLIPSE, + CAPTURE_STATE_DRAW_RECT, +}; + + +@implementation CaptureWindow + ++(CaptureWindow *)shareInsatnce{ + static CaptureWindow *g_instance; + static dispatch_once_t onceToken; + dispatch_once(&onceToken,^{ + // g_instance = [[CaptureWindow alloc] initWithCoder:]; + }); + + return g_instance; +} + + +/* + In Interface Builder, the class for the window is set to this subclass. Overriding the initializer provides a mechanism for controlling how objects of this class are created. + */ +- (id)initWithContentRect:(NSRect)contentRect styleMask:(NSUInteger)aStyle backing:(NSBackingStoreType)bufferingType defer:(BOOL)flag +{ + captureState = CAPTURE_STATE_IDLE; + + // Using NSBorderlessWindowMask results in a window without a title bar. + self = [super initWithContentRect:contentRect styleMask:NSBorderlessWindowMask backing:NSBackingStoreBuffered defer:NO]; + + if (self == nil) { + return nil; + } + + // 由于setBackgroundColor时要用用darkImage,所以需要先抓整屏 + [self captureScreen]; + + [self setLevel:NSStatusWindowLevel]; + [self setBackgroundColor:[NSColor colorWithPatternImage:darkImage]]; + + NSRect screenFrame = [[NSScreen mainScreen] frame]; + [self setFrame:screenFrame display:YES animate:YES]; + + myView = [[CaptureView alloc] initWithFrame:contentRect]; + NSView *superView = [self contentView]; + [superView addSubview:myView]; + + [self setAcceptsMouseMovedEvents:YES]; + + [self captureAppScreen]; + + return self; +} + +/* + Custom windows that use the NSBorderlessWindowMask can't become key by default. Override this method so that controls in this window will be enabled. + */ +- (BOOL)canBecomeKeyWindow { + return YES; +} + +- (void)onOK +{ + DDLog(@"OK button click"); + + // 把选择的截图保存到粘贴板 + [originImage lockFocus]; + // 画上注释的框 + [myView drawCommentRect]; + + //先设置 下面一个实例 + NSBitmapImageRep *bits = [[NSBitmapImageRep alloc] initWithFocusedViewRect:captureWindowRect]; + + [originImage unlockFocus]; + + //再设置后面要用到得 props属性 + NSDictionary *imageProps = [NSDictionary dictionaryWithObject:[NSNumber numberWithFloat:1.0] forKey:NSImageCompressionFactor]; + + + //之后 转化为NSData 以便存到文件中 + NSData *imageData = [bits representationUsingType:NSJPEGFileType properties:imageProps]; + + NSImage *pasteImage = [[NSImage alloc] initWithData:imageData]; + + NSPasteboard *pasteBoard = [NSPasteboard generalPasteboard]; + [pasteBoard clearContents]; + [pasteBoard writeObjects: [NSArray arrayWithObject:pasteImage]]; + + + //发布截图确定事件. + //截图点击确定. + [self orderOut:nil]; + + [[NSNotificationCenter defaultCenter] postNotificationName:@"Notification_screen_capture_ok" object:nil]; + + +} + + + + +- (void)onCancel +{ + DDLog(@"Cancel button click"); + [self orderOut:nil]; +} + +- (void)onEllipse +{ + captureState = CAPTURE_STATE_DRAW_ELLIPSE; + [myView setDrawDragPoints:NO]; // 画注释框时就不画拖拽点了 + DDLog(@"ellipse button click"); +} + +- (void)onRect +{ + captureState = CAPTURE_STATE_DRAW_RECT; + [myView setDrawDragPoints:NO]; // 画注释框时就不画拖拽点了 + DDLog(@"rect button click"); +} + + +#pragma mark mouse/keyboard event +- (void)mouseUp:(NSEvent *)theEvent +{ + if (captureState == CAPTURE_STATE_CAPTURING) { + captureState = CAPTURE_STATE_DONE; + + currentLocation = [theEvent locationInWindow]; + DDLog(@"stop position: %@", NSStringFromPoint(currentLocation)); + + // get mouse move rectangle + NSRect mouseRect = [self currentRect]; + + // width and height are float, so use compare + if (mouseRect.size.width < 0.1 || mouseRect.size.height < 0.1) { + DDLog(@"capture app window"); + } else { + DDLog(@"capture mouse drag"); + captureWindowRect = mouseRect; + } + } else if (captureState == CAPTURE_STATE_DRAG) { + captureState = CAPTURE_STATE_DONE; + } else if (captureState == CAPTURE_STATE_SCALE) { + captureState = CAPTURE_STATE_DONE; + } else { + return; + } + + [myView setDrawDragPoints:YES]; + [myView setDrawImage:originImage inRect:captureWindowRect]; + + + NSView *superView = [self contentView]; + + // 按钮后面添加黑色背景 + float backgroundX = captureWindowRect.origin.x + captureWindowRect.size.width - 4 * BUTTON_SIZE; + float backgroundY = captureWindowRect.origin.y - BUTTON_SIZE; + if (backgroundX < 0) { + backgroundX = 0; + } + + if (backgroundY < 0) { + backgroundY = 0; + } + + NSRect backgrounRect = NSMakeRect(backgroundX, backgroundY, 4 * BUTTON_SIZE + 100, BUTTON_SIZE + 100); + backgroundView = [[BackgroudView alloc] initWithFrame:backgrounRect]; + [backgroundView setNeedsDisplay:YES]; + + + [superView addSubview:backgroundView positioned:NSWindowAbove relativeTo:myView]; + + + // 截屏后面添加ok和cancel按钮 + NSRect okRect; + float x = captureWindowRect.origin.x + captureWindowRect.size.width - BUTTON_SIZE; + float y = captureWindowRect.origin.y - BUTTON_SIZE; + if (x < 3 * BUTTON_SIZE) { + x = 3 * BUTTON_SIZE; + } + if (y < 0) { + y = 0; + } + okRect = NSMakeRect(x, y, BUTTON_SIZE, BUTTON_SIZE); + + okButton = [[NSButton alloc] initWithFrame:okRect]; + //[okButton setTitle:@"OK"]; + NSImage *okImage = [NSImage imageNamed:@"ScreenCapture_toolbar_ok"]; + [okButton setImage:okImage]; + [okButton setTarget:self]; + [okButton setAction:@selector(onOK)]; + + [superView addSubview:okButton positioned:NSWindowAbove relativeTo:backgroundView]; + + NSRect cancelRect = NSMakeRect(x - BUTTON_SIZE, y, BUTTON_SIZE, BUTTON_SIZE); + + cancelButton = [[NSButton alloc] initWithFrame:cancelRect]; + //[cancelButton setTitle:@"Cancel"]; + NSImage *cancelImage = [NSImage imageNamed:@"ScreenCapture_toolbar_cancel"]; + [cancelButton setImage:cancelImage]; + [cancelButton setTarget:self]; + [cancelButton setAction:@selector(onCancel)]; + [superView addSubview:cancelButton positioned:NSWindowAbove relativeTo:backgroundView]; + + NSRect ellipseRect = NSMakeRect(x - 2 * BUTTON_SIZE, y, BUTTON_SIZE, BUTTON_SIZE); + ellipseButton = [[NSButton alloc] initWithFrame:ellipseRect]; + [ellipseButton setImage:[NSImage imageNamed:@"ScreenCapture_toolbar_ellipse"]]; + [ellipseButton setTarget:self]; + [ellipseButton setAction:@selector(onEllipse)]; + [superView addSubview:ellipseButton positioned:NSWindowAbove relativeTo:backgroundView]; + + NSRect rectBtnRect = NSMakeRect(x - 3 * BUTTON_SIZE, y, BUTTON_SIZE, BUTTON_SIZE); + rectButton = [[NSButton alloc] initWithFrame:rectBtnRect]; + [rectButton setImage:[NSImage imageNamed:@"ScreenCapture_toolbar_rect"]]; + [rectButton setTarget:self]; + [rectButton setAction:@selector(onRect)]; + [superView addSubview:rectButton positioned:NSWindowAbove relativeTo:backgroundView]; + + [okButton setBordered:NO]; + [cancelButton setBordered:NO]; + [ellipseButton setBordered:NO]; + [rectButton setBordered:NO]; +} + +- (void)mouseDown:(NSEvent *)theEvent +{ + // 双击截屏 + if ( [theEvent clickCount] == 2 ) { + [self onOK]; + return; + } + + if (captureState == CAPTURE_STATE_CAPTURING) { + startLocation = [theEvent locationInWindow]; + DDLog(@"start position: %@", NSStringFromPoint(startLocation)); + } else if (captureState == CAPTURE_STATE_DONE) { + startLocation = [theEvent locationInWindow]; + dragDirection = [myView isInDragPoints:startLocation]; + DDLog(@"drag direction: %i", dragDirection); + + if (dragDirection != -1) { + [okButton removeFromSuperview]; + [cancelButton removeFromSuperview]; + [ellipseButton removeFromSuperview]; + [rectButton removeFromSuperview]; + [backgroundView removeFromSuperview]; + + if (dragDirection == 8) { + captureState = CAPTURE_STATE_DRAG; + } else { + captureState = CAPTURE_STATE_SCALE; + } + } + } else if (captureState == CAPTURE_STATE_DRAW_ELLIPSE) { + startLocation = [theEvent locationInWindow]; + [myView newEllipseRect:NSZeroRect]; + DDLog(@"start draw ellipse"); + } else if (captureState == CAPTURE_STATE_DRAW_RECT) { + startLocation = [theEvent locationInWindow]; + [myView newRectangleRect:NSZeroRect]; + DDLog(@"start draw rect"); + } +} + +- (void)mouseDragged:(NSEvent *)theEvent +{ + if (captureState == CAPTURE_STATE_CAPTURING) { + currentLocation = [theEvent locationInWindow]; + + NSRect rect = [self currentRect]; + [myView setDrawImage:originImage inRect:rect]; + } else if (captureState == CAPTURE_STATE_DRAG) { + currentLocation = [theEvent locationInWindow]; + CGFloat deltaX = currentLocation.x - startLocation.x; + CGFloat deltaY = currentLocation.y - startLocation.y; + + NSRect rect = captureWindowRect; + rect.origin.x += deltaX; + rect.origin.y += deltaY; + captureWindowRect = rect; + [myView setDrawImage:originImage inRect:captureWindowRect]; + + startLocation = currentLocation; + } else if (captureState == CAPTURE_STATE_SCALE) { + currentLocation = [theEvent locationInWindow]; + CGFloat deltaX = currentLocation.x - startLocation.x; + CGFloat deltaY = currentLocation.y - startLocation.y; + + switch (dragDirection) { + case 0: // user drag lower-left corner point + captureWindowRect.origin.x += deltaX; + captureWindowRect.origin.y += deltaY; + captureWindowRect.size.width -= deltaX; + captureWindowRect.size.height -= deltaY; + break; + case 1: // user drag middle-left point + captureWindowRect.origin.x += deltaX; + captureWindowRect.size.width -= deltaX; + break; + case 2: // user drag upper-left corner point + captureWindowRect.origin.x += deltaX; + captureWindowRect.size.width -= deltaX; + captureWindowRect.size.height += deltaY; + break; + case 3: // user drag middle-upper point + captureWindowRect.size.height += deltaY; + break; + case 4: // user drag upper-right corner point + captureWindowRect.size.width += deltaX; + captureWindowRect.size.height += deltaY; + break; + case 5: // user drag middle-right point + captureWindowRect.size.width += deltaX; + break; + case 6: // user drag lower-right corner point + captureWindowRect.origin.y += deltaY; + captureWindowRect.size.width += deltaX; + captureWindowRect.size.height -= deltaY; + break; + case 7: // user drag middle-lower point + captureWindowRect.origin.y += deltaY; + captureWindowRect.size.height -= deltaY; + break; + } + + [myView setDrawImage:originImage inRect:captureWindowRect]; + + startLocation = currentLocation; + } else if (captureState == CAPTURE_STATE_DRAW_ELLIPSE) { + currentLocation = [theEvent locationInWindow]; + + NSRect rect = [self currentRect]; + [myView setEllipseRect:rect]; + } else if (captureState == CAPTURE_STATE_DRAW_RECT) { + currentLocation = [theEvent locationInWindow]; + + NSRect rect = [self currentRect]; + [myView setRectangleRect:rect]; + } +} + +- (void)mouseMoved:(NSEvent *)theEvent +{ + if (captureState == CAPTURE_STATE_CAPTURING) { + [self captureAppScreen]; + } +} + +- (void)keyUp:(NSEvent *)theEvent +{ + switch([theEvent keyCode]) { + case 53: // esc + DDLog(@"ESC"); + [self orderOut:nil]; + // Call the full-screen mode method + break; + default: + [super keyDown:theEvent]; + } +} + +- (NSRect)currentRect +{ + float minX = MIN(startLocation.x, currentLocation.x); + float maxX = MAX(startLocation.x, currentLocation.x); + float minY = MIN(startLocation.y, currentLocation.y); + float maxY = MAX(startLocation.y, currentLocation.y); + + return NSMakeRect(minX, minY, maxX - minX, maxY - minY); +} + +- (CGImageRef)screenShot +{ + CFArrayRef windowsRef = CGWindowListCreate(kCGWindowListOptionOnScreenOnly, kCGNullWindowID); + + NSRect rect = [[NSScreen mainScreen] frame]; + CGImageRef imgRef = CGWindowListCreateImageFromArray(rect, windowsRef, kCGWindowImageDefault); + + CFRelease(windowsRef); + + return imgRef; +} + +- (void)captureScreen +{ + captureState = CAPTURE_STATE_CAPTURING; + + // 获取所有OnScreen的窗口 + windowList = CGWindowListCopyWindowInfo(kCGWindowListOptionOnScreenOnly |kCGWindowListExcludeDesktopElements, kCGNullWindowID); + //DDLog(CFSTR("Array: %@"), windowList); + + CGImageRef imgRef = [self screenShot]; + + NSRect mainFrame = [[NSScreen mainScreen] frame]; + originImage = [[NSImage alloc] initWithCGImage:imgRef size:mainFrame.size]; + darkImage = [[NSImage alloc] initWithCGImage:imgRef size:mainFrame.size]; + CGImageRelease(imgRef); + + // 对darkImage做暗化处理 + [darkImage lockFocus]; + [[NSColor colorWithCalibratedWhite:0 alpha:0.33] set]; + NSRectFillUsingOperation(mainFrame, NSCompositeSourceAtop); + [darkImage unlockFocus]; +} + +- (BOOL)isPoint: (NSPoint)point inRect: (NSRect)rect +{ + if ( point.x >= rect.origin.x + && point.x <= (rect.origin.x + rect.size.width) + && point.y >= rect.origin.y + && point.y <= (rect.origin.y + rect.size.height) ) { + return YES; + } else { + return NO; + } +} + +// clip the application window to the display screen, reserve 1 pixel for draw box line +- (NSRect)clipWindowRect:(NSRect)windowRect +{ + NSRect mainFrame = [[NSScreen mainScreen] frame]; + + if (windowRect.origin.x < 0) { + windowRect.size.width += windowRect.origin.x; + windowRect.origin.x = 1; + } + + if (windowRect.origin.y < 0) { + windowRect.size.height += windowRect.origin.y; + windowRect.origin.y = 1; + } + + if (windowRect.origin.x + windowRect.size.width >= mainFrame.size.width) { + windowRect.size.width = mainFrame.size.width - windowRect.origin.x -1; + } + + if (windowRect.origin.y + windowRect.size.height >= mainFrame.size.height) { + windowRect.size.height = mainFrame.size.height - windowRect.origin.y -1; + } + + return windowRect; +} + +- (void)captureAppScreen +{ + + NSPoint mouseLocation = [NSEvent mouseLocation]; + + //DDLog(@"mouse scroll wheel: %@", NSStringFromPoint(mouseLocation)); + + NSRect mainFrame = [[NSScreen mainScreen] frame]; + CFIndex cnt = CFArrayGetCount(windowList); + for (CFIndex i = 0; i < cnt; i++) { + NSDictionary *dict = (NSDictionary *)CFArrayGetValueAtIndex(windowList, i); + NSRect windowRect;; + CGRectMakeWithDictionaryRepresentation((__bridge CFDictionaryRef)[dict objectForKey:(id)kCGWindowBounds], &windowRect); + + // 转换坐标系 + windowRect.origin.y = mainFrame.size.height - windowRect.origin.y - + windowRect.size.height; + + int layer = 0; + CFNumberRef numberRef = (__bridge CFNumberRef)[dict objectForKey: (id)kCGWindowLayer]; + CFNumberGetValue(numberRef, kCFNumberSInt32Type, &layer); + if (layer == 0 && [self isPoint: mouseLocation inRect: windowRect]) { + /*DDLog(@"mouse in, %li, x=%f, y=%f, width=%f, heigth=%f, name=%@", + i, windowRect.origin.x, windowRect.origin.y,windowRect.size.width,windowRect.size.height, [dict objectForKey: (id)kCGWindowName]);*/ + + captureWindowRect = [self clipWindowRect:windowRect]; + [myView setDrawImage:originImage inRect:captureWindowRect]; + return; + } + + } + +} + +@end diff --git a/mac/TeamTalk/ScreenCapture/MTScreenCaptureModule.h b/mac/TeamTalk/ScreenCapture/MTScreenCaptureModule.h new file mode 100644 index 000000000..120a23d3a --- /dev/null +++ b/mac/TeamTalk/ScreenCapture/MTScreenCaptureModule.h @@ -0,0 +1,15 @@ +// +// MTScreenCaptureModule.h +// Duoduo +// +// Created by zuoye on 15/1/15. +// Copyright (c) 2015年 mogujie. All rights reserved. +// + +#import +@interface MTScreenCaptureModule : NSObject + ++(instancetype) shareInstance; +- (void)capture:(id)sender; + +@end diff --git a/mac/TeamTalk/ScreenCapture/MTScreenCaptureModule.m b/mac/TeamTalk/ScreenCapture/MTScreenCaptureModule.m new file mode 100644 index 000000000..e8886657c --- /dev/null +++ b/mac/TeamTalk/ScreenCapture/MTScreenCaptureModule.m @@ -0,0 +1,33 @@ +// +// MTScreenCaptureModule.m +// Duoduo +// +// Created by zuoye on 15/1/15. +// Copyright (c) 2015年 mogujie. All rights reserved. +// + +#import "MTScreenCaptureModule.h" +#import "CaptureWindow.h" + +@implementation MTScreenCaptureModule{ + NSWindow *_myWindow; +} + ++(instancetype) shareInstance{ + static MTScreenCaptureModule *g_screenCaptureModule; + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^{ + g_screenCaptureModule = [[MTScreenCaptureModule alloc] init]; + }); + return g_screenCaptureModule; +} + + +- (void)capture:(id)sender +{ + NSRect rect = NSMakeRect(100, 100, 600, 600); + _myWindow = [[CaptureWindow alloc] initWithContentRect:rect styleMask:NSBorderlessWindowMask backing:NSBackingStoreBuffered defer:NO]; + [_myWindow makeKeyAndOrderFront:nil]; +} + +@end diff --git a/mac/TeamTalk/ServiceAccount/DDServiceAccountModule.h b/mac/TeamTalk/ServiceAccount/DDServiceAccountModule.h new file mode 100644 index 000000000..99be5192d --- /dev/null +++ b/mac/TeamTalk/ServiceAccount/DDServiceAccountModule.h @@ -0,0 +1,51 @@ +// +// DDServiceAccountModule.h +// Duoduo +// +// Created by 独嘉 on 14-8-10. +// Copyright (c) 2014年 zuoye. All rights reserved. +// + +#import + +typedef NS_ENUM(NSInteger, ServiceAction) +{ + ActionNone, + ActionBang +}; + +@interface DDServiceAccountModule : NSObject ++ (instancetype)shareInstance; + +/** + * 是否是服务号 + * + * @param userID 查询的用户ID + * + * @return 结果 + */ +- (BOOL)isServiceAccount:(NSString*)userID; + +/** + * 小T发送老黄历 + */ +- (void)sendAlmanac; + +/** + * 小Test发送摇一摇 + */ +- (void)sendBang; + +/** + * Action识别 + * + * @param content 待识别内容 + * + * @return 动作 + */ +- (ServiceAction)regcognizeTheAction:(NSString*)content; + +- (NSString*)recognizeTheContent:(NSString*)sender; + +- (void)performTheAction:(ServiceAction)serviceAction withContent:(NSString*)content; +@end diff --git a/mac/TeamTalk/ServiceAccount/DDServiceAccountModule.m b/mac/TeamTalk/ServiceAccount/DDServiceAccountModule.m new file mode 100644 index 000000000..c479ba283 --- /dev/null +++ b/mac/TeamTalk/ServiceAccount/DDServiceAccountModule.m @@ -0,0 +1,188 @@ +// +// DDServiceAccountModule.m +// Duoduo +// +// Created by 独嘉 on 14-8-10. +// Copyright (c) 2014年 zuoye. All rights reserved. +// + +#import "DDServiceAccountModule.h" +#import "DDMessageSendManager.h" +#import "MTSessionModule.h" +#import "DDUserInfoManager.h" +#import "MTUserModule.h" +#import "MessageEntity.h" +#import "MTMessageModule.h" +#define DD_LAST_LOGIN_DATE_KEY @"LastLoginDate" +#define DD_TT_ACTION_KEY @"TT_Action" +#define DD_TT_ACTION_CONTENT @"TT_Content" +@interface DDServiceAccountModule(privateAPI) + +- (void)p_registerAPI; +- (void)n_receiveUserLoginSuccessNotification:(NSNotification*)notification; + +- (void)p_performActionBangWithContent:(NSString*)content; + +@end + +@implementation DDServiceAccountModule +{ + NSArray* _serviceAccountArray; +} ++ (instancetype)shareInstance +{ + static DDServiceAccountModule* g_serviceAccountModule; + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^{ + g_serviceAccountModule = [[DDServiceAccountModule alloc] init]; + }); + return g_serviceAccountModule; +} + +- (instancetype)init +{ + self = [super init]; + if (self) + { + _serviceAccountArray = @[@"11m2ec4"]; + [self p_registerAPI]; + + + } + return self; +} + +- (BOOL)isServiceAccount:(NSString*)userID +{ + return [_serviceAccountArray containsObject:userID]; +} + +- (void)sendAlmanac +{ + + /* + DDSessionModule* sessionModule = getDDSessionModule(); + SessionEntity* sessionEntity = [sessionModule getSessionBySId:@"11m2ec4"]; + NSAttributedString* content = [[NSAttributedString alloc] initWithString:@"#老黄历#"]; + [[DDMessageSendManager instance] sendMessage:content forSession:sessionEntity success:^(NSString *sendedContent) { + DDLog(@"已请求老黄历"); + } failure:^(NSString *error) { + DDLog(@"%@",error); + }]; + */ +} + +- (void)sendBang +{ + /* + DDSessionModule* sessionModule = getDDSessionModule(); + SessionEntity* sessionEntity = [sessionModule getSessionBySId:@"11m2ec4"]; + NSAttributedString* content = [[NSAttributedString alloc] initWithString:@"#摇一摇#"]; + [[DDMessageSendManager instance] sendMessage:content forSession:sessionEntity success:^(NSString *sendedContent) { + DDLog(@"已请求摇一摇"); + } failure:^(NSString *error) { + DDLog(@"%@",error); + }]; + */ +} + +- (ServiceAction)regcognizeTheAction:(NSString*)content +{ + //TT_Action:Bang;TT_Content:userId + NSData* jsonData = [content dataUsingEncoding:NSUTF8StringEncoding]; + NSDictionary* info = [NSJSONSerialization JSONObjectWithData:jsonData options:0 error:nil]; + if (info && [info count] > 0) + { + if ([info[DD_TT_ACTION_KEY] isEqualToString:@"Bang"]) + { + //摇一摇 + return ActionBang; + } + } + else + { + return ActionNone; + } + return ActionNone; +} + +- (NSString*)recognizeTheContent:(NSString*)sender +{ + NSData* jsonData = [sender dataUsingEncoding:NSUTF8StringEncoding]; + NSDictionary* info = [NSJSONSerialization JSONObjectWithData:jsonData options:0 error:nil]; + if (info && [info count] > 0) + { + return info[DD_TT_ACTION_CONTENT]; + } + else + { + return nil; + } + return nil; +} + +- (void)performTheAction:(ServiceAction)serviceAction withContent:(NSString*)content +{ + switch (serviceAction) + { + case ActionBang: + [self p_performActionBangWithContent:content]; + break; + case ActionNone: + break; + } +} + +#pragma mark privateAPI +- (void)p_registerAPI +{ + +} + +- (void)n_receiveUserLoginSuccessNotification:(NSNotification*)notification +{ + NSDate* date = [[NSUserDefaults standardUserDefaults] valueForKey:DD_LAST_LOGIN_DATE_KEY]; + NSCalendar *greCalendar = [[NSCalendar alloc] initWithCalendarIdentifier:NSGregorianCalendar]; + NSDateComponents *dateComponents = [greCalendar components:NSYearCalendarUnit | NSMonthCalendarUnit | NSDayCalendarUnit | NSHourCalendarUnit | NSMinuteCalendarUnit | NSSecondCalendarUnit | NSWeekCalendarUnit | NSWeekdayCalendarUnit | NSWeekOfMonthCalendarUnit | NSWeekOfYearCalendarUnit fromDate:date]; + + NSDate* nowDate = [NSDate date]; + NSDateComponents *nowDateComponents = [greCalendar components:NSYearCalendarUnit | NSMonthCalendarUnit | NSDayCalendarUnit | NSHourCalendarUnit | NSMinuteCalendarUnit | NSSecondCalendarUnit | NSWeekCalendarUnit | NSWeekdayCalendarUnit | NSWeekOfMonthCalendarUnit | NSWeekOfYearCalendarUnit fromDate:nowDate]; + if (!(dateComponents.year == nowDateComponents.year && dateComponents.month == nowDateComponents.month && dateComponents.day == nowDateComponents.day)) + { + //不在同一天,发老黄历 +// [self sendAlmanac]; + [[NSUserDefaults standardUserDefaults] setValue:nowDate forKey:DD_LAST_LOGIN_DATE_KEY]; + [[NSUserDefaults standardUserDefaults] synchronize]; + } + + //发送版本更新推送 + NSString* feature = @"小T温馨提醒,Mac TeamTalk发布新版本v2.65,修复以下问题:\n- 部分同学登录后历史消息无法读取\n如有疑问欢迎咨询@独嘉~"; + NSString* key = @"2.65 feature"; + if (![[NSUserDefaults standardUserDefaults] valueForKey:key]) + { + //发送推送 + MessageEntity* message = [[MessageEntity alloc] init]; + message.msgType = MESSAGE_TYPE_SINGLE; + message.msgTime = [[NSDate date] timeIntervalSince1970]; + message.seqNo = 0; + message.sessionId = @"11m2ec4"; + message.msgContent = feature; + message.senderId = message.sessionId; + + //tt_3.0 + //[getDDMessageModule() addUnreadMessage:message forSessionID:message.sessionId]; + [[NSUserDefaults standardUserDefaults] setValue:feature forKey:key]; + [[NSUserDefaults standardUserDefaults] synchronize]; + } +} + +- (void)p_performActionBangWithContent:(NSString*)content +{ + + MTUserEntity* user =(MTUserEntity *)[[MTUserModule shareInstance]getOriginEntityWithOriginID:content]; + if (user) + { + [[DDUserInfoManager instance] showUser:user forContext:nil]; + } +} +@end diff --git a/mac/TeamTalk/Services/DDApplicationUpdate.h b/mac/TeamTalk/Services/DDApplicationUpdate.h new file mode 100644 index 000000000..1d7539a90 --- /dev/null +++ b/mac/TeamTalk/Services/DDApplicationUpdate.h @@ -0,0 +1,28 @@ +// +// DDApplicationUpdate.h +// Duoduo +// +// Created by 独嘉 on 14-4-17. +// Copyright (c) 2014年 zuoye. All rights reserved. +// + +#import + +@interface DDApplicationUpdate : NSObject ++ (instancetype)instance; + +/** + * 开始自动更新,不立刻开始,而是根据定时器时间而定 + */ +- (void)startAutoCheckUpdate; + +/** + * 马上开始自动更新 + */ +- (void)startAutoCheckUpdateAtOnce; + +/** + * 在后台检测更新 + */ +- (void)checkoutUpdateInBackground; +@end diff --git a/mac/TeamTalk/Services/DDApplicationUpdate.m b/mac/TeamTalk/Services/DDApplicationUpdate.m new file mode 100644 index 000000000..44bbc3970 --- /dev/null +++ b/mac/TeamTalk/Services/DDApplicationUpdate.m @@ -0,0 +1,51 @@ +// +// DDApplicationUpdate.m +// Duoduo +// +// Created by 独嘉 on 14-4-17. +// Copyright (c) 2014年 zuoye. All rights reserved. +// + +#import "DDApplicationUpdate.h" +#import +static NSInteger const updateCheckTimeInterval = 60 * 30; + +@implementation DDApplicationUpdate +{ + NSTimer* _checkUpdateTimer; +} ++ (instancetype)instance +{ + static DDApplicationUpdate* g_applicationUpdate; + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^{ + g_applicationUpdate = [[DDApplicationUpdate alloc] init]; + }); + return g_applicationUpdate; +} + +- (void)startAutoCheckUpdate +{ + if (!_checkUpdateTimer) + { + _checkUpdateTimer = [NSTimer scheduledTimerWithTimeInterval:updateCheckTimeInterval target:self selector:@selector(checkoutUpdateInBackground) userInfo:nil repeats:YES]; + } +} + +- (void)startAutoCheckUpdateAtOnce +{ + if (_checkUpdateTimer) + { + [_checkUpdateTimer invalidate]; + _checkUpdateTimer = nil; + } + + _checkUpdateTimer = [NSTimer scheduledTimerWithTimeInterval:updateCheckTimeInterval target:self selector:@selector(checkoutUpdateInBackground) userInfo:nil repeats:YES]; + [_checkUpdateTimer fire]; +} + +- (void)checkoutUpdateInBackground +{ + [[SUUpdater sharedUpdater] checkForUpdatesInBackground]; +} +@end diff --git a/mac/TeamTalk/Services/DDSearch.h b/mac/TeamTalk/Services/DDSearch.h new file mode 100644 index 000000000..e346c3a67 --- /dev/null +++ b/mac/TeamTalk/Services/DDSearch.h @@ -0,0 +1,17 @@ +// +// DDSearch.h +// Duoduo +// +// Created by 独嘉 on 14-4-22. +// Copyright (c) 2014年 zuoye. All rights reserved. +// + +#import + +typedef void(^SearchCompletion)(NSArray* result,NSError* error); + +@interface DDSearch : NSObject ++ (instancetype)instance; +- (void)searchContent:(NSString*)content completion:(SearchCompletion)completion; +- (void)searchContent:(NSString *)content inRange:(NSArray*)ranges completion:(SearchCompletion)completion; +@end diff --git a/mac/TeamTalk/Services/DDSearch.m b/mac/TeamTalk/Services/DDSearch.m new file mode 100644 index 000000000..3a4bc8b27 --- /dev/null +++ b/mac/TeamTalk/Services/DDSearch.m @@ -0,0 +1,215 @@ + // +// DDSearch.m +// Duoduo +// +// Created by 独嘉 on 14-4-22. +// Copyright (c) 2014年 zuoye. All rights reserved. +// + +#import "DDSearch.h" +#import "MTGroupModule.h" +#import "MTUserEntity.h" +#import "MTUserModule.h" +#import "MTGroupEntity.h" +#import "MTSessionEntity.h" +#import "SpellLibrary.h" +#import "DDOriginEntity.h" + +@interface DDSearch(PrivateAPI) + +- (NSArray*)p_getAllUsersAndGroups; +- (NSString*)p_getIDForObject:(id)sender; + +@end + +@implementation DDSearch +{ + NSArray* _allUsersAndGroups; +} ++ (instancetype)instance +{ + static DDSearch* g_search; + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^{ + g_search = [[DDSearch alloc] init]; + }); + return g_search; +} + +#pragma mark - Public API +- (void)searchContent:(NSString*)content completion:(SearchCompletion)completion +{ + content = [content lowercaseString]; + + dispatch_async(dispatch_get_global_queue(0, 0), ^{ + NSMutableArray* matchesIDArray = [[NSMutableArray alloc] init]; + if (!_allUsersAndGroups || [_allUsersAndGroups count] == 0) + { + _allUsersAndGroups = [self p_getAllUsersAndGroups]; + } + NSMutableArray* matches = NULL; + NSUInteger i,count; + NSString* string; + + count = [_allUsersAndGroups count]; + matches = [NSMutableArray array]; + + // find any match in our keyword array against what was typed - + for (i=0; i< count; i++) + { + NSObject* user = [_allUsersAndGroups objectAtIndex:i]; + string = [(DDOriginEntity*)user name]; + NSString* objectID = [self p_getIDForObject:user]; + + if ([string rangeOfString:content].length > 0) + { + if (![matches containsObject:user]) + { + [matches addObject:user]; + [matchesIDArray addObject:objectID]; + } + } + } + NSString* partialSpell = [[SpellLibrary instance] getSpellForWord:content]; + NSArray* userInSpellLibaray = [[SpellLibrary instance] checkoutForWordsForSpell:partialSpell]; + + if ([userInSpellLibaray count] > 0) + { + [userInSpellLibaray enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) { + NSString* objectID = [self p_getIDForObject:obj]; + if (!objectID) + { + return; + } + if (![matches containsObject:obj] && ![matchesIDArray containsObject:objectID]) { + [matches addObject:obj]; + [matchesIDArray addObject:objectID]; + } + }]; + } + + [matches sortUsingComparator:^NSComparisonResult(id obj1, id obj2) { + if ([obj1 isKindOfClass:NSClassFromString(@"MTUserEntity")]) + { + return NSOrderedAscending; + } + else + { + return NSOrderedDescending; + } + }]; + + dispatch_async(dispatch_get_main_queue(), ^{ + completion(matches,nil); + }); + }); + + + if (!_allUsersAndGroups || [_allUsersAndGroups count] == 0) + { + _allUsersAndGroups = [self p_getAllUsersAndGroups]; + } + [self searchContent:content inRange:_allUsersAndGroups completion:completion]; +} + +- (void)searchContent:(NSString *)content inRange:(NSArray*)ranges completion:(SearchCompletion)completion +{ + dispatch_async(dispatch_get_global_queue(0, 0), ^{ + NSUInteger i,count; + NSString* string; + + count = [ranges count]; + NSMutableArray* matches = [[NSMutableArray alloc] init]; + + // find any match in our keyword array against what was typed - + for (i=0; i< count; i++) + { + MTUserEntity* user = [ranges objectAtIndex:i]; + string = user.name; + if ([string rangeOfString:content].length > 0) + { + if (![matches containsObject:user]) + + { + [matches addObject:user]; + } + } + } + NSString* partialSpell = [[SpellLibrary instance] getSpellForWord:content]; + NSArray* userInSpellLibaray = [[SpellLibrary instance] checkoutForWordsForSpell:partialSpell]; + + NSMutableArray* rangsIDs = [[NSMutableArray alloc] init]; + [ranges enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) { + NSString* ID = [self p_getIDForObject:obj]; + [rangsIDs addObject:ID]; + }]; + + if ([userInSpellLibaray count] > 0) + { + for (NSInteger index = 0; index < [userInSpellLibaray count]; index ++) + { + id object = userInSpellLibaray[index]; + NSString* objectID = [self p_getIDForObject:object]; + if (!objectID) { + continue; + } + if (![matches containsObject:object] && [rangsIDs containsObject:objectID]) { + [matches addObject:object]; + } + } + [userInSpellLibaray enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) { + NSString* objectID = [self p_getIDForObject:obj]; + if (!objectID) + { + return; + } + if (![matches containsObject:obj] && [ranges containsObject:obj]) { + [matches addObject:[obj copy]]; + } + }]; + } + dispatch_async(dispatch_get_main_queue(), ^{ + completion(matches,nil); + }); + }); + +} + +#pragma mark PrivateAPI +- (NSArray*)p_getAllUsersAndGroups +{ + //tt_3.0 + + //导入所有的用户 + NSMutableArray* allSessions = [NSMutableArray arrayWithArray:[[MTUserModule shareInstance] getAllOriginEntity]]; + + //添加所有组别 + NSArray* groups = [[MTGroupModule shareInsatnce] getAllOriginEntity]; + [groups enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) { + MTGroupEntity* group = (MTGroupEntity*)obj; + if (![allSessions containsObject:group]) + { + [allSessions addObject:group]; + } + }]; + return allSessions; +} + +- (NSString*)p_getIDForObject:(id)sender +{ + NSString* objectID = nil; + if ([sender isKindOfClass:NSClassFromString(@"MTUserEntity")]) + { + objectID = [(MTUserEntity*)sender ID]; + } + else if ([sender isKindOfClass:NSClassFromString(@"MTGroupEntity")]) + { + objectID = [(MTGroupEntity*)sender ID]; + } + else + { + DDLog(@"error"); + } + return objectID; +} +@end diff --git a/mac/TeamTalk/ShortcutRecorder.framework/Headers b/mac/TeamTalk/ShortcutRecorder.framework/Headers new file mode 100644 index 000000000..a177d2a6b --- /dev/null +++ b/mac/TeamTalk/ShortcutRecorder.framework/Headers @@ -0,0 +1 @@ +Versions/Current/Headers \ No newline at end of file diff --git a/mac/TeamTalk/ShortcutRecorder.framework/Resources b/mac/TeamTalk/ShortcutRecorder.framework/Resources new file mode 100644 index 000000000..953ee36f3 --- /dev/null +++ b/mac/TeamTalk/ShortcutRecorder.framework/Resources @@ -0,0 +1 @@ +Versions/Current/Resources \ No newline at end of file diff --git a/mac/TeamTalk/ShortcutRecorder.framework/ShortcutRecorder b/mac/TeamTalk/ShortcutRecorder.framework/ShortcutRecorder new file mode 100644 index 000000000..2be0db14c --- /dev/null +++ b/mac/TeamTalk/ShortcutRecorder.framework/ShortcutRecorder @@ -0,0 +1 @@ +Versions/Current/ShortcutRecorder \ No newline at end of file diff --git a/mac/TeamTalk/ShortcutRecorder.framework/Versions/A/Headers/SRCommon.h b/mac/TeamTalk/ShortcutRecorder.framework/Versions/A/Headers/SRCommon.h new file mode 100755 index 000000000..bacfbd99e --- /dev/null +++ b/mac/TeamTalk/ShortcutRecorder.framework/Versions/A/Headers/SRCommon.h @@ -0,0 +1,185 @@ +// +// SRCommon.h +// ShortcutRecorder +// +// Copyright 2006-2007 Contributors. All rights reserved. +// +// License: BSD +// +// Contributors: +// David Dauer +// Jesper +// Jamie Kirkpatrick + +#import +#import +#import + +#pragma mark Dummy class + +@interface SRDummyClass : NSObject {} @end + +#pragma mark - +#pragma mark Typedefs + +typedef struct _KeyCombo { + NSUInteger flags; // 0 for no flags + NSInteger code; // -1 for no code +} KeyCombo; + +#pragma mark - +#pragma mark Enums + +// Unicode values of some keyboard glyphs +enum { + KeyboardTabRightGlyph = 0x21E5, + KeyboardTabLeftGlyph = 0x21E4, + KeyboardCommandGlyph = kCommandUnicode, + KeyboardOptionGlyph = kOptionUnicode, + KeyboardShiftGlyph = kShiftUnicode, + KeyboardControlGlyph = kControlUnicode, + KeyboardReturnGlyph = 0x2305, + KeyboardReturnR2LGlyph = 0x21A9, + KeyboardDeleteLeftGlyph = 0x232B, + KeyboardDeleteRightGlyph = 0x2326, + KeyboardPadClearGlyph = 0x2327, + KeyboardLeftArrowGlyph = 0x2190, + KeyboardRightArrowGlyph = 0x2192, + KeyboardUpArrowGlyph = 0x2191, + KeyboardDownArrowGlyph = 0x2193, + KeyboardPageDownGlyph = 0x21DF, + KeyboardPageUpGlyph = 0x21DE, + KeyboardNorthwestArrowGlyph = 0x2196, + KeyboardSoutheastArrowGlyph = 0x2198, + KeyboardEscapeGlyph = 0x238B, + KeyboardHelpGlyph = 0x003F, + KeyboardUpArrowheadGlyph = 0x2303, +}; + +// Special keys +enum { + kSRKeysF1 = 122, + kSRKeysF2 = 120, + kSRKeysF3 = 99, + kSRKeysF4 = 118, + kSRKeysF5 = 96, + kSRKeysF6 = 97, + kSRKeysF7 = 98, + kSRKeysF8 = 100, + kSRKeysF9 = 101, + kSRKeysF10 = 109, + kSRKeysF11 = 103, + kSRKeysF12 = 111, + kSRKeysF13 = 105, + kSRKeysF14 = 107, + kSRKeysF15 = 113, + kSRKeysF16 = 106, + kSRKeysF17 = 64, + kSRKeysF18 = 79, + kSRKeysF19 = 80, + kSRKeysSpace = 49, + kSRKeysDeleteLeft = 51, + kSRKeysDeleteRight = 117, + kSRKeysPadClear = 71, + kSRKeysLeftArrow = 123, + kSRKeysRightArrow = 124, + kSRKeysUpArrow = 126, + kSRKeysDownArrow = 125, + kSRKeysSoutheastArrow = 119, + kSRKeysNorthwestArrow = 115, + kSRKeysEscape = 53, + kSRKeysPageDown = 121, + kSRKeysPageUp = 116, + kSRKeysReturnR2L = 36, + kSRKeysReturn = 76, + kSRKeysTabRight = 48, + kSRKeysHelp = 114 +}; + +#pragma mark - +#pragma mark Macros + +// Localization macros, for use in any bundle +#define SRLoc(key) SRLocalizedString(key, nil) +#define SRLocalizedString(key, comment) NSLocalizedStringFromTableInBundle(key, @"ShortcutRecorder", [NSBundle bundleForClass: [SRDummyClass class]], comment) + +// Image macros, for use in any bundle +//#define SRImage(name) [[[NSImage alloc] initWithContentsOfFile: [[NSBundle bundleForClass: [self class]] pathForImageResource: name]] autorelease] +#define SRResIndImage(name) [SRSharedImageProvider supportingImageWithName:name] +#define SRImage(name) SRResIndImage(name) + +//#define SRCommonWriteDebugImagery + +// Macros for glyps +#define SRInt(x) [NSNumber numberWithInteger:x] +#define SRChar(x) [NSString stringWithFormat: @"%C", (unsigned short)x] + +// Some default values +#define ShortcutRecorderEmptyFlags 0 +#define ShortcutRecorderAllFlags ShortcutRecorderEmptyFlags | (NSCommandKeyMask | NSAlternateKeyMask | NSControlKeyMask | NSShiftKeyMask | NSFunctionKeyMask) +#define ShortcutRecorderEmptyCode -1 + +// These keys will cancel the recoding mode if not pressed with any modifier +#define ShortcutRecorderEscapeKey 53 +#define ShortcutRecorderBackspaceKey 51 +#define ShortcutRecorderDeleteKey 117 + +#pragma mark - +#pragma mark Getting a string of the key combination + +// +// ################### +- Returns string from keyCode like NSEvent's -characters +// # EXPLANATORY # | +- Returns string from keyCode like NSEvent's -charactersUsingModifiers +// # CHART # | | +- Returns fully readable and localized name of modifier (if modifier given) +// ################### | | | +- Returns glyph of modifier (if modifier given) +// SRString... X - - X +// SRReadableString... X - X - +// SRCharacter... - X - - +// +NSString * SRStringForKeyCode( NSInteger keyCode ); +NSString * SRStringForCarbonModifierFlags( NSUInteger flags ); +NSString * SRStringForCarbonModifierFlagsAndKeyCode( NSUInteger flags, NSInteger keyCode ); +NSString * SRStringForCocoaModifierFlags( NSUInteger flags ); +NSString * SRStringForCocoaModifierFlagsAndKeyCode( NSUInteger flags, NSInteger keyCode ); +NSString * SRReadableStringForCarbonModifierFlagsAndKeyCode( NSUInteger flags, NSInteger keyCode ); +NSString * SRReadableStringForCocoaModifierFlagsAndKeyCode( NSUInteger flags, NSInteger keyCode ); +NSString *SRCharacterForKeyCodeAndCarbonFlags(NSInteger keyCode, NSUInteger carbonFlags); +NSString *SRCharacterForKeyCodeAndCocoaFlags(NSInteger keyCode, NSUInteger cocoaFlags); + +#pragma mark Converting between Cocoa and Carbon modifier flags + +NSUInteger SRCarbonToCocoaFlags( NSUInteger carbonFlags ); +NSUInteger SRCocoaToCarbonFlags( NSUInteger cocoaFlags ); + +#pragma mark - +#pragma mark Animation pace function + +CGFloat SRAnimationEaseInOut(CGFloat t); + +#pragma mark - +#pragma mark Inlines + +FOUNDATION_STATIC_INLINE KeyCombo SRMakeKeyCombo(NSInteger code, NSUInteger flags) { + KeyCombo kc; + kc.code = code; + kc.flags = flags; + return kc; +} + +FOUNDATION_STATIC_INLINE BOOL SRIsSpecialKey(NSInteger keyCode) { + return (keyCode == kSRKeysF1 || keyCode == kSRKeysF2 || keyCode == kSRKeysF3 || keyCode == kSRKeysF4 || keyCode == kSRKeysF5 || keyCode == kSRKeysF6 || keyCode == kSRKeysF7 || keyCode == kSRKeysF8 || keyCode == kSRKeysF9 || keyCode == kSRKeysF10 || keyCode == kSRKeysF11 || keyCode == kSRKeysF12 || keyCode == kSRKeysF13 || keyCode == kSRKeysF14 || keyCode == kSRKeysF15 || keyCode == kSRKeysF16 || keyCode == kSRKeysSpace || keyCode == kSRKeysDeleteLeft || keyCode == kSRKeysDeleteRight || keyCode == kSRKeysPadClear || keyCode == kSRKeysLeftArrow || keyCode == kSRKeysRightArrow || keyCode == kSRKeysUpArrow || keyCode == kSRKeysDownArrow || keyCode == kSRKeysSoutheastArrow || keyCode == kSRKeysNorthwestArrow || keyCode == kSRKeysEscape || keyCode == kSRKeysPageDown || keyCode == kSRKeysPageUp || keyCode == kSRKeysReturnR2L || keyCode == kSRKeysReturn || keyCode == kSRKeysTabRight || keyCode == kSRKeysHelp); +} + +#pragma mark - +#pragma mark Additions + +@interface NSAlert( SRAdditions ) ++ (NSAlert *) alertWithNonRecoverableError:(NSError *)error; +@end + +#pragma mark - +#pragma mark Image provider + +@interface SRSharedImageProvider : NSObject ++ (NSImage *)supportingImageWithName:(NSString *)name; +@end diff --git a/mac/TeamTalk/ShortcutRecorder.framework/Versions/A/Headers/SRKeyCodeTransformer.h b/mac/TeamTalk/ShortcutRecorder.framework/Versions/A/Headers/SRKeyCodeTransformer.h new file mode 100755 index 000000000..6f252f375 --- /dev/null +++ b/mac/TeamTalk/ShortcutRecorder.framework/Versions/A/Headers/SRKeyCodeTransformer.h @@ -0,0 +1,16 @@ +// +// SRKeyCodeTransformer.h +// ShortcutRecorder +// +// Copyright 2006-2007 Contributors. All rights reserved. +// +// License: BSD +// +// Contributors: +// David Dauer +// Jesper +// Jamie Kirkpatrick + +#import + +@interface SRKeyCodeTransformer : NSValueTransformer {} @end diff --git a/mac/TeamTalk/ShortcutRecorder.framework/Versions/A/Headers/SRRecorderCell.h b/mac/TeamTalk/ShortcutRecorder.framework/Versions/A/Headers/SRRecorderCell.h new file mode 100755 index 000000000..9bd3b9a0b --- /dev/null +++ b/mac/TeamTalk/ShortcutRecorder.framework/Versions/A/Headers/SRRecorderCell.h @@ -0,0 +1,139 @@ +// +// SRRecorderCell.h +// ShortcutRecorder +// +// Copyright 2006-2007 Contributors. All rights reserved. +// +// License: BSD +// +// Contributors: +// David Dauer +// Jesper +// Jamie Kirkpatrick + +#import +#import "SRCommon.h" + +#define SRMinWidth 50 +#define SRMaxHeight 22 + +#define SRTransitionFPS 30.0f +#define SRTransitionDuration 0.35f +//#define SRTransitionDuration 2.35 +#define SRTransitionFrames (SRTransitionFPS*SRTransitionDuration) +#define SRAnimationAxisIsY YES +#define ShortcutRecorderNewStyleDrawing + +#define SRAnimationOffsetRect(X,Y) (SRAnimationAxisIsY ? NSOffsetRect(X,0.0f,-NSHeight(Y)) : NSOffsetRect(X,NSWidth(Y),0.0f)) + +@class SRRecorderControl, SRValidator; + +enum SRRecorderStyle { + SRGradientBorderStyle = 0, + SRGreyStyle = 1 +}; +typedef enum SRRecorderStyle SRRecorderStyle; + +@interface SRRecorderCell : NSActionCell +{ + NSGradient *recordingGradient; + NSString *autosaveName; + + BOOL isRecording; + BOOL mouseInsideTrackingArea; + BOOL mouseDown; + + SRRecorderStyle style; + + BOOL isAnimating; + CGFloat transitionProgress; + BOOL isAnimatingNow; + BOOL isAnimatingTowardsRecording; + BOOL comboJustChanged; + + NSTrackingRectTag removeTrackingRectTag; + NSTrackingRectTag snapbackTrackingRectTag; + + KeyCombo keyCombo; + BOOL hasKeyChars; + NSString *keyChars; + NSString *keyCharsIgnoringModifiers; + + NSUInteger allowedFlags; + NSUInteger requiredFlags; + NSUInteger recordingFlags; + + BOOL allowsKeyOnly; + BOOL escapeKeysRecord; + + NSSet *cancelCharacterSet; + + SRValidator *validator; + + IBOutlet id delegate; + BOOL globalHotKeys; + void *hotKeyModeToken; +} + +- (void)resetTrackingRects; + +#pragma mark *** Aesthetics *** + ++ (BOOL)styleSupportsAnimation:(SRRecorderStyle)style; + +- (BOOL)animates; +- (void)setAnimates:(BOOL)an; +- (SRRecorderStyle)style; +- (void)setStyle:(SRRecorderStyle)nStyle; + +#pragma mark *** Delegate *** + +- (id)delegate; +- (void)setDelegate:(id)aDelegate; + +#pragma mark *** Responder Control *** + +- (BOOL)becomeFirstResponder; +- (BOOL)resignFirstResponder; + +#pragma mark *** Key Combination Control *** + +- (BOOL)performKeyEquivalent:(NSEvent *)theEvent; +- (void)flagsChanged:(NSEvent *)theEvent; + +- (NSUInteger)allowedFlags; +- (void)setAllowedFlags:(NSUInteger)flags; + +- (NSUInteger)requiredFlags; +- (void)setRequiredFlags:(NSUInteger)flags; + +- (BOOL)allowsKeyOnly; +- (void)setAllowsKeyOnly:(BOOL)nAllowsKeyOnly; +- (void)setAllowsKeyOnly:(BOOL)nAllowsKeyOnly escapeKeysRecord:(BOOL)nEscapeKeysRecord; +- (BOOL)escapeKeysRecord; +- (void)setEscapeKeysRecord:(BOOL)nEscapeKeysRecord; + +- (BOOL)canCaptureGlobalHotKeys; +- (void)setCanCaptureGlobalHotKeys:(BOOL)inState; + +- (KeyCombo)keyCombo; +- (void)setKeyCombo:(KeyCombo)aKeyCombo; + +#pragma mark *** Autosave Control *** + +- (NSString *)autosaveName; +- (void)setAutosaveName:(NSString *)aName; + +// Returns the displayed key combination if set +- (NSString *)keyComboString; + +- (NSString *)keyChars; +- (NSString *)keyCharsIgnoringModifiers; + +@end + +// Delegate Methods +@interface NSObject (SRRecorderCellDelegate) +- (BOOL)shortcutRecorderCell:(SRRecorderCell *)aRecorderCell isKeyCode:(NSInteger)keyCode andFlagsTaken:(NSUInteger)flags reason:(NSString **)aReason; +- (void)shortcutRecorderCell:(SRRecorderCell *)aRecorderCell keyComboDidChange:(KeyCombo)newCombo; +@end diff --git a/mac/TeamTalk/ShortcutRecorder.framework/Versions/A/Headers/SRRecorderControl.h b/mac/TeamTalk/ShortcutRecorder.framework/Versions/A/Headers/SRRecorderControl.h new file mode 100755 index 000000000..777678e42 --- /dev/null +++ b/mac/TeamTalk/ShortcutRecorder.framework/Versions/A/Headers/SRRecorderControl.h @@ -0,0 +1,79 @@ +// +// SRRecorderControl.h +// ShortcutRecorder +// +// Copyright 2006-2007 Contributors. All rights reserved. +// +// License: BSD +// +// Contributors: +// David Dauer +// Jesper +// Jamie Kirkpatrick + +#import +#import "SRRecorderCell.h" + +@interface SRRecorderControl : NSControl +{ + IBOutlet id delegate; +} + +#pragma mark *** Aesthetics *** +- (BOOL)animates; +- (void)setAnimates:(BOOL)an; +- (SRRecorderStyle)style; +- (void)setStyle:(SRRecorderStyle)nStyle; + +#pragma mark *** Delegate *** +- (id)delegate; +- (void)setDelegate:(id)aDelegate; + +#pragma mark *** Key Combination Control *** + +- (NSUInteger)allowedFlags; +- (void)setAllowedFlags:(NSUInteger)flags; + +- (BOOL)allowsKeyOnly; +- (void)setAllowsKeyOnly:(BOOL)nAllowsKeyOnly escapeKeysRecord:(BOOL)nEscapeKeysRecord; +- (BOOL)escapeKeysRecord; + +- (BOOL)canCaptureGlobalHotKeys; +- (void)setCanCaptureGlobalHotKeys:(BOOL)inState; + +- (NSUInteger)requiredFlags; +- (void)setRequiredFlags:(NSUInteger)flags; + +- (KeyCombo)keyCombo; +- (void)setKeyCombo:(KeyCombo)aKeyCombo; + +- (NSString *)keyChars; +- (NSString *)keyCharsIgnoringModifiers; + +#pragma mark *** Autosave Control *** + +- (NSString *)autosaveName; +- (void)setAutosaveName:(NSString *)aName; + +#pragma mark - + +// Returns the displayed key combination if set +- (NSString *)keyComboString; + +#pragma mark *** Conversion Methods *** + +- (NSUInteger)cocoaToCarbonFlags:(NSUInteger)cocoaFlags; +- (NSUInteger)carbonToCocoaFlags:(NSUInteger)carbonFlags; + +#pragma mark *** Binding Methods *** + +- (NSDictionary *)objectValue; +- (void)setObjectValue:(NSDictionary *)shortcut; + +@end + +// Delegate Methods +@interface NSObject (SRRecorderDelegate) +- (BOOL)shortcutRecorder:(SRRecorderControl *)aRecorder isKeyCode:(NSInteger)keyCode andFlagsTaken:(NSUInteger)flags reason:(NSString **)aReason; +- (void)shortcutRecorder:(SRRecorderControl *)aRecorder keyComboDidChange:(KeyCombo)newKeyCombo; +@end diff --git a/mac/TeamTalk/ShortcutRecorder.framework/Versions/A/Headers/SRValidator.h b/mac/TeamTalk/ShortcutRecorder.framework/Versions/A/Headers/SRValidator.h new file mode 100755 index 000000000..0dd8f2832 --- /dev/null +++ b/mac/TeamTalk/ShortcutRecorder.framework/Versions/A/Headers/SRValidator.h @@ -0,0 +1,34 @@ +// +// SRValidator.h +// ShortcutRecorder +// +// Copyright 2006-2007 Contributors. All rights reserved. +// +// License: BSD +// +// Contributors: +// David Dauer +// Jesper +// Jamie Kirkpatrick + +#import + +@interface SRValidator : NSObject { + id delegate; +} + +- (id) initWithDelegate:(id)theDelegate; + +- (BOOL) isKeyCode:(NSInteger)keyCode andFlagsTaken:(NSUInteger)flags error:(NSError **)error; +- (BOOL) isKeyCode:(NSInteger)keyCode andFlags:(NSUInteger)flags takenInMenu:(NSMenu *)menu error:(NSError **)error; + +- (id) delegate; +- (void) setDelegate: (id) theDelegate; + +@end + +#pragma mark - + +@interface NSObject( SRValidation ) +- (BOOL) shortcutValidator:(SRValidator *)validator isKeyCode:(NSInteger)keyCode andFlagsTaken:(NSUInteger)flags reason:(NSString **)aReason; +@end diff --git a/mac/TeamTalk/ShortcutRecorder.framework/Versions/A/Headers/ShortcutRecorder.h b/mac/TeamTalk/ShortcutRecorder.framework/Versions/A/Headers/ShortcutRecorder.h new file mode 100755 index 000000000..855a2882c --- /dev/null +++ b/mac/TeamTalk/ShortcutRecorder.framework/Versions/A/Headers/ShortcutRecorder.h @@ -0,0 +1,17 @@ +// +// ShortcutRecorder.h +// ShortcutRecorder +// - 10.5 version only; master framework header +// +// Copyright 2007 Contributors. All rights reserved. +// +// License: BSD +// +// Contributors to this file: +// Jesper + +#import +#import +#import +#import +#import diff --git a/mac/TeamTalk/ShortcutRecorder.framework/Versions/A/Resources/Info.plist b/mac/TeamTalk/ShortcutRecorder.framework/Versions/A/Resources/Info.plist new file mode 100644 index 000000000..886c38b6f --- /dev/null +++ b/mac/TeamTalk/ShortcutRecorder.framework/Versions/A/Resources/Info.plist @@ -0,0 +1,36 @@ + + + + + BuildMachineOSBuild + 13B42 + CFBundleDevelopmentRegion + English + CFBundleExecutable + ShortcutRecorder + CFBundleIdentifier + net.wafflesoftware.ShortcutRecorder.framework.Leopard + CFBundleInfoDictionaryVersion + 6.0 + CFBundlePackageType + FMWK + CFBundleSignature + ???? + CFBundleVersion + 1.0 + DTCompiler + com.apple.compilers.llvm.clang.1_0 + DTPlatformBuild + 5A3005 + DTPlatformVersion + GM + DTSDKBuild + 13A595 + DTSDKName + macosx10.9 + DTXcode + 0502 + DTXcodeBuild + 5A3005 + + diff --git a/mac/TeamTalk/ShortcutRecorder.framework/Versions/A/Resources/SRRemoveShortcut.tif b/mac/TeamTalk/ShortcutRecorder.framework/Versions/A/Resources/SRRemoveShortcut.tif new file mode 100755 index 000000000..47a7b7168 Binary files /dev/null and b/mac/TeamTalk/ShortcutRecorder.framework/Versions/A/Resources/SRRemoveShortcut.tif differ diff --git a/mac/TeamTalk/ShortcutRecorder.framework/Versions/A/Resources/SRRemoveShortcutPressed.tif b/mac/TeamTalk/ShortcutRecorder.framework/Versions/A/Resources/SRRemoveShortcutPressed.tif new file mode 100755 index 000000000..0119610cd Binary files /dev/null and b/mac/TeamTalk/ShortcutRecorder.framework/Versions/A/Resources/SRRemoveShortcutPressed.tif differ diff --git a/mac/TeamTalk/ShortcutRecorder.framework/Versions/A/Resources/SRRemoveShortcutRollover.tif b/mac/TeamTalk/ShortcutRecorder.framework/Versions/A/Resources/SRRemoveShortcutRollover.tif new file mode 100755 index 000000000..3af4f0b1d Binary files /dev/null and b/mac/TeamTalk/ShortcutRecorder.framework/Versions/A/Resources/SRRemoveShortcutRollover.tif differ diff --git a/mac/TeamTalk/ShortcutRecorder.framework/Versions/A/Resources/SRSnapback.tiff b/mac/TeamTalk/ShortcutRecorder.framework/Versions/A/Resources/SRSnapback.tiff new file mode 100755 index 000000000..0be1e495b Binary files /dev/null and b/mac/TeamTalk/ShortcutRecorder.framework/Versions/A/Resources/SRSnapback.tiff differ diff --git a/mac/TeamTalk/ShortcutRecorder.framework/Versions/A/Resources/ca.lproj/ShortcutRecorder.strings b/mac/TeamTalk/ShortcutRecorder.framework/Versions/A/Resources/ca.lproj/ShortcutRecorder.strings new file mode 100755 index 000000000..ae10bf3fa Binary files /dev/null and b/mac/TeamTalk/ShortcutRecorder.framework/Versions/A/Resources/ca.lproj/ShortcutRecorder.strings differ diff --git a/mac/TeamTalk/ShortcutRecorder.framework/Versions/A/Resources/cs.lproj/ShortcutRecorder.strings b/mac/TeamTalk/ShortcutRecorder.framework/Versions/A/Resources/cs.lproj/ShortcutRecorder.strings new file mode 100755 index 000000000..13cde5d43 Binary files /dev/null and b/mac/TeamTalk/ShortcutRecorder.framework/Versions/A/Resources/cs.lproj/ShortcutRecorder.strings differ diff --git a/mac/TeamTalk/ShortcutRecorder.framework/Versions/A/Resources/da.lproj/ShortcutRecorder.strings b/mac/TeamTalk/ShortcutRecorder.framework/Versions/A/Resources/da.lproj/ShortcutRecorder.strings new file mode 100755 index 000000000..db3986a97 Binary files /dev/null and b/mac/TeamTalk/ShortcutRecorder.framework/Versions/A/Resources/da.lproj/ShortcutRecorder.strings differ diff --git a/mac/TeamTalk/ShortcutRecorder.framework/Versions/A/Resources/de.lproj/ShortcutRecorder.strings b/mac/TeamTalk/ShortcutRecorder.framework/Versions/A/Resources/de.lproj/ShortcutRecorder.strings new file mode 100755 index 000000000..0a406af7c Binary files /dev/null and b/mac/TeamTalk/ShortcutRecorder.framework/Versions/A/Resources/de.lproj/ShortcutRecorder.strings differ diff --git a/mac/TeamTalk/ShortcutRecorder.framework/Versions/A/Resources/el.lproj/ShortcutRecorder.strings b/mac/TeamTalk/ShortcutRecorder.framework/Versions/A/Resources/el.lproj/ShortcutRecorder.strings new file mode 100755 index 000000000..75ea26fde Binary files /dev/null and b/mac/TeamTalk/ShortcutRecorder.framework/Versions/A/Resources/el.lproj/ShortcutRecorder.strings differ diff --git a/mac/TeamTalk/ShortcutRecorder.framework/Versions/A/Resources/en.lproj/ShortcutRecorder.strings b/mac/TeamTalk/ShortcutRecorder.framework/Versions/A/Resources/en.lproj/ShortcutRecorder.strings new file mode 100755 index 000000000..ecc213764 Binary files /dev/null and b/mac/TeamTalk/ShortcutRecorder.framework/Versions/A/Resources/en.lproj/ShortcutRecorder.strings differ diff --git a/mac/TeamTalk/ShortcutRecorder.framework/Versions/A/Resources/es-MX.lproj/ShortcutRecorder.strings b/mac/TeamTalk/ShortcutRecorder.framework/Versions/A/Resources/es-MX.lproj/ShortcutRecorder.strings new file mode 100755 index 000000000..31daeace5 Binary files /dev/null and b/mac/TeamTalk/ShortcutRecorder.framework/Versions/A/Resources/es-MX.lproj/ShortcutRecorder.strings differ diff --git a/mac/TeamTalk/ShortcutRecorder.framework/Versions/A/Resources/es.lproj/ShortcutRecorder.strings b/mac/TeamTalk/ShortcutRecorder.framework/Versions/A/Resources/es.lproj/ShortcutRecorder.strings new file mode 100755 index 000000000..45028feeb Binary files /dev/null and b/mac/TeamTalk/ShortcutRecorder.framework/Versions/A/Resources/es.lproj/ShortcutRecorder.strings differ diff --git a/mac/TeamTalk/ShortcutRecorder.framework/Versions/A/Resources/fr.lproj/ShortcutRecorder.strings b/mac/TeamTalk/ShortcutRecorder.framework/Versions/A/Resources/fr.lproj/ShortcutRecorder.strings new file mode 100755 index 000000000..ff8488510 Binary files /dev/null and b/mac/TeamTalk/ShortcutRecorder.framework/Versions/A/Resources/fr.lproj/ShortcutRecorder.strings differ diff --git a/mac/TeamTalk/ShortcutRecorder.framework/Versions/A/Resources/it.lproj/ShortcutRecorder.strings b/mac/TeamTalk/ShortcutRecorder.framework/Versions/A/Resources/it.lproj/ShortcutRecorder.strings new file mode 100755 index 000000000..b49898097 Binary files /dev/null and b/mac/TeamTalk/ShortcutRecorder.framework/Versions/A/Resources/it.lproj/ShortcutRecorder.strings differ diff --git a/mac/TeamTalk/ShortcutRecorder.framework/Versions/A/Resources/ja.lproj/ShortcutRecorder.strings b/mac/TeamTalk/ShortcutRecorder.framework/Versions/A/Resources/ja.lproj/ShortcutRecorder.strings new file mode 100755 index 000000000..4a48483a2 Binary files /dev/null and b/mac/TeamTalk/ShortcutRecorder.framework/Versions/A/Resources/ja.lproj/ShortcutRecorder.strings differ diff --git a/mac/TeamTalk/ShortcutRecorder.framework/Versions/A/Resources/ko.lproj/ShortcutRecorder.strings b/mac/TeamTalk/ShortcutRecorder.framework/Versions/A/Resources/ko.lproj/ShortcutRecorder.strings new file mode 100755 index 000000000..9b43ae067 Binary files /dev/null and b/mac/TeamTalk/ShortcutRecorder.framework/Versions/A/Resources/ko.lproj/ShortcutRecorder.strings differ diff --git a/mac/TeamTalk/ShortcutRecorder.framework/Versions/A/Resources/nb.lproj/ShortcutRecorder.strings b/mac/TeamTalk/ShortcutRecorder.framework/Versions/A/Resources/nb.lproj/ShortcutRecorder.strings new file mode 100755 index 000000000..8ea479ec5 Binary files /dev/null and b/mac/TeamTalk/ShortcutRecorder.framework/Versions/A/Resources/nb.lproj/ShortcutRecorder.strings differ diff --git a/mac/TeamTalk/ShortcutRecorder.framework/Versions/A/Resources/nl.lproj/ShortcutRecorder.strings b/mac/TeamTalk/ShortcutRecorder.framework/Versions/A/Resources/nl.lproj/ShortcutRecorder.strings new file mode 100755 index 000000000..260dde804 Binary files /dev/null and b/mac/TeamTalk/ShortcutRecorder.framework/Versions/A/Resources/nl.lproj/ShortcutRecorder.strings differ diff --git a/mac/TeamTalk/ShortcutRecorder.framework/Versions/A/Resources/pl.lproj/ShortcutRecorder.strings b/mac/TeamTalk/ShortcutRecorder.framework/Versions/A/Resources/pl.lproj/ShortcutRecorder.strings new file mode 100755 index 000000000..fd8142609 Binary files /dev/null and b/mac/TeamTalk/ShortcutRecorder.framework/Versions/A/Resources/pl.lproj/ShortcutRecorder.strings differ diff --git a/mac/TeamTalk/ShortcutRecorder.framework/Versions/A/Resources/pt-BR.lproj/ShortcutRecorder.strings b/mac/TeamTalk/ShortcutRecorder.framework/Versions/A/Resources/pt-BR.lproj/ShortcutRecorder.strings new file mode 100755 index 000000000..d6bd15fd2 Binary files /dev/null and b/mac/TeamTalk/ShortcutRecorder.framework/Versions/A/Resources/pt-BR.lproj/ShortcutRecorder.strings differ diff --git a/mac/TeamTalk/ShortcutRecorder.framework/Versions/A/Resources/pt-PT.lproj/ShortcutRecorder.strings b/mac/TeamTalk/ShortcutRecorder.framework/Versions/A/Resources/pt-PT.lproj/ShortcutRecorder.strings new file mode 100755 index 000000000..b82a0764b Binary files /dev/null and b/mac/TeamTalk/ShortcutRecorder.framework/Versions/A/Resources/pt-PT.lproj/ShortcutRecorder.strings differ diff --git a/mac/TeamTalk/ShortcutRecorder.framework/Versions/A/Resources/pt.lproj/ShortcutRecorder.strings b/mac/TeamTalk/ShortcutRecorder.framework/Versions/A/Resources/pt.lproj/ShortcutRecorder.strings new file mode 100755 index 000000000..d6bd15fd2 Binary files /dev/null and b/mac/TeamTalk/ShortcutRecorder.framework/Versions/A/Resources/pt.lproj/ShortcutRecorder.strings differ diff --git a/mac/TeamTalk/ShortcutRecorder.framework/Versions/A/Resources/ro.lproj/ShortcutRecorder.strings b/mac/TeamTalk/ShortcutRecorder.framework/Versions/A/Resources/ro.lproj/ShortcutRecorder.strings new file mode 100755 index 000000000..db1db38f9 Binary files /dev/null and b/mac/TeamTalk/ShortcutRecorder.framework/Versions/A/Resources/ro.lproj/ShortcutRecorder.strings differ diff --git a/mac/TeamTalk/ShortcutRecorder.framework/Versions/A/Resources/ru.lproj/ShortcutRecorder.strings b/mac/TeamTalk/ShortcutRecorder.framework/Versions/A/Resources/ru.lproj/ShortcutRecorder.strings new file mode 100755 index 000000000..fc01d3612 Binary files /dev/null and b/mac/TeamTalk/ShortcutRecorder.framework/Versions/A/Resources/ru.lproj/ShortcutRecorder.strings differ diff --git a/mac/TeamTalk/ShortcutRecorder.framework/Versions/A/Resources/sk.lproj/ShortcutRecorder.strings b/mac/TeamTalk/ShortcutRecorder.framework/Versions/A/Resources/sk.lproj/ShortcutRecorder.strings new file mode 100755 index 000000000..0aed73e68 Binary files /dev/null and b/mac/TeamTalk/ShortcutRecorder.framework/Versions/A/Resources/sk.lproj/ShortcutRecorder.strings differ diff --git a/mac/TeamTalk/ShortcutRecorder.framework/Versions/A/Resources/sv.lproj/ShortcutRecorder.strings b/mac/TeamTalk/ShortcutRecorder.framework/Versions/A/Resources/sv.lproj/ShortcutRecorder.strings new file mode 100755 index 000000000..a8a2f71da Binary files /dev/null and b/mac/TeamTalk/ShortcutRecorder.framework/Versions/A/Resources/sv.lproj/ShortcutRecorder.strings differ diff --git a/mac/TeamTalk/ShortcutRecorder.framework/Versions/A/Resources/th.lproj/ShortcutRecorder.strings b/mac/TeamTalk/ShortcutRecorder.framework/Versions/A/Resources/th.lproj/ShortcutRecorder.strings new file mode 100755 index 000000000..ea7778b7f Binary files /dev/null and b/mac/TeamTalk/ShortcutRecorder.framework/Versions/A/Resources/th.lproj/ShortcutRecorder.strings differ diff --git a/mac/TeamTalk/ShortcutRecorder.framework/Versions/A/Resources/zh-Hans.lproj/ShortcutRecorder.strings b/mac/TeamTalk/ShortcutRecorder.framework/Versions/A/Resources/zh-Hans.lproj/ShortcutRecorder.strings new file mode 100755 index 000000000..ffcb6a0f4 Binary files /dev/null and b/mac/TeamTalk/ShortcutRecorder.framework/Versions/A/Resources/zh-Hans.lproj/ShortcutRecorder.strings differ diff --git a/mac/TeamTalk/ShortcutRecorder.framework/Versions/A/Resources/zh-Hant.lproj/ShortcutRecorder.strings b/mac/TeamTalk/ShortcutRecorder.framework/Versions/A/Resources/zh-Hant.lproj/ShortcutRecorder.strings new file mode 100755 index 000000000..22fff9111 Binary files /dev/null and b/mac/TeamTalk/ShortcutRecorder.framework/Versions/A/Resources/zh-Hant.lproj/ShortcutRecorder.strings differ diff --git a/mac/TeamTalk/ShortcutRecorder.framework/Versions/A/ShortcutRecorder b/mac/TeamTalk/ShortcutRecorder.framework/Versions/A/ShortcutRecorder new file mode 100755 index 000000000..1529bec3a Binary files /dev/null and b/mac/TeamTalk/ShortcutRecorder.framework/Versions/A/ShortcutRecorder differ diff --git a/mac/TeamTalk/ShortcutRecorder.framework/Versions/Current b/mac/TeamTalk/ShortcutRecorder.framework/Versions/Current new file mode 100644 index 000000000..8c7e5a667 --- /dev/null +++ b/mac/TeamTalk/ShortcutRecorder.framework/Versions/Current @@ -0,0 +1 @@ +A \ No newline at end of file diff --git a/mac/TeamTalk/StateMaintenance/DDClientState.h b/mac/TeamTalk/StateMaintenance/DDClientState.h new file mode 100644 index 000000000..9b47053d6 --- /dev/null +++ b/mac/TeamTalk/StateMaintenance/DDClientState.h @@ -0,0 +1,183 @@ +// +// DDClientState.h +// Duoduo +// +// Created by 独嘉 on 14-4-14. +// Copyright (c) 2014年 mogujie. All rights reserved. +// + +#import + +/** + * 用户状态 + */ +typedef NS_ENUM(NSUInteger, DDUserState) +{ + /** + * 用户在线 + */ + DDUserOnline, + /** + * 用户多端登录被挤下线 + */ + DDUserKickout, + /** + * 用户被移动端踢出 + */ + DDUserKickByMobile, + /** + * 用户离线 + */ + DDUserOffLine, + /** + * 用户主动下线 + */ + DDUserOffLineInitiative, + /** + * 用户正在连接 + */ + DDUserLogining +}; + +/** + * 客户端网络状态 + */ +typedef NS_ENUM(NSUInteger, DDNetWorkState) +{ + /** + * wifi + */ + DDNetWorkWifi, + /** + * 3G + */ + DDNetWork3G, + /** + * 2G + */ + DDNetWork2G, + /** + * 无网 + */ + DDNetWorkDisconnect +}; + +/** + * Socket 连接状态 + */ +typedef NS_ENUM(NSUInteger, DDSocketState) +{ + /** + * Socket连接登录服务器 + */ + DDSocketLinkLoginServer, + /** + * Socket连接消息服务器 + */ + DDSocketLinkMessageServer, + /** + * Socket没有连接 + */ + DDSocketDisconnect +}; + +typedef NS_ENUM(NSUInteger,DDDataState) +{ + + /** + * 本地用户数据加载完成 + */ + DDLocalUserDataReady = 1, + + /** + * 远程用户数据加载完成 + */ + DDRemoteUserDataReady = 1 << 1, + + /** + * 本地群数据加载 + */ + DDLocalGroupDataReady = 1 << 2, + + /** + * 远程会话群数据加载完成 + */ + DDRemoteSessionGroupDataReady = 1 << 3, + + /** + * 远程固定群数据加载完成 + */ + DDRemoteFixGroupDataReady = 1 << 4, + + /** + * 本地session数据加载完成 + */ + DDLocalSessionDataReady = 1 << 5, + + /** + * 远程session数据加载完成 + */ + DDRemoteSessionDataReady = 1 << 6, + + /** + * 在线状态加载完成 + */ + DDOnlineDataReady = 1 << 7 +}; + +#define DD_USER_STATE_KEYPATH @"userState" +#define DD_NETWORK_STATE_KEYPATH @"networkState" +#define DD_SOCKET_STATE_KEYPATH @"socketState" +#define DD_USER_ID_KEYPATH @"userID" +#define DD_DATA_STATE_KEYPATH @"dataState" + +@class DDReachability; +@interface DDClientState : NSObject +{ + DDReachability* _reachability; +} +/** + * 当前登录用户的状态 + */ +@property(nonatomic,assign)DDUserState userState; + +/** + * 网络连接状态 + */ +@property(nonatomic,assign)DDNetWorkState networkState; + +/** + * Socket连接状态 + */ +@property(nonatomic,assign)DDSocketState socketState; + +/** + * 当前登录用户的ID + */ +@property (nonatomic,retain)NSString* userID; + +/** + * 程序数据状态 + */ +@property (nonatomic,assign)DDDataState dataState; + +/** + * msfs  文件服务器地址 + */ +@property (nonatomic,retain)NSString* msfsURL; + +/** + * 发现 地址 + */ +@property (nonatomic,retain)NSString* discoverURL; + +/** + * 单例 + * + * @return 客户端状态机 + */ ++ (instancetype)shareInstance; + +- (void)setUseStateWithoutObserver:(DDUserState)userState; + +@end diff --git a/mac/TeamTalk/StateMaintenance/DDClientState.m b/mac/TeamTalk/StateMaintenance/DDClientState.m new file mode 100644 index 000000000..3ec7eb6bb --- /dev/null +++ b/mac/TeamTalk/StateMaintenance/DDClientState.m @@ -0,0 +1,113 @@ +// +// DDClientState.m +// Duoduo +// +// Created by 独嘉 on 14-4-14. +// Copyright (c) 2014年 zuoye. All rights reserved. +// + +#import "DDClientState.h" +#import +#import "DDReceiveKickAPI.h" +@interface DDClientState(PrivateAPI) + +- (void)n_receiveReachabilityChangedNotification:(NSNotification*)notification; +- (void)p_registerAPI; + +@end + +@implementation DDClientState ++ (instancetype)shareInstance +{ + static DDClientState* g_clientState; + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^{ + g_clientState = [[DDClientState alloc] init]; + }); + return g_clientState; +} + +- (id)init +{ + self = [super init]; + if (self) + { + _userState = DDUserOffLine; + _socketState = DDSocketDisconnect; + [[AFNetworkReachabilityManager sharedManager] startMonitoring]; + [self p_registerAPI]; + [[NSNotificationCenter defaultCenter] addObserver:self + selector:@selector(n_receiveReachabilityChangedNotification:) + name:AFNetworkingReachabilityDidChangeNotification + object:nil]; + } + return self; +} + + +- (void)dealloc +{ + [[NSNotificationCenter defaultCenter] removeObserver:self]; +} + +- (void)setUseStateWithoutObserver:(DDUserState)userState +{ + _userState = userState; + if (userState == DDUserOffLine) + { + [self setValue:@(0) forKeyPath:DD_DATA_STATE_KEYPATH]; + } +} + +- (void)setUserState:(DDUserState)userState +{ + _userState = userState; + if (userState == DDUserOffLine) + { + [self setValue:@(0) forKeyPath:DD_DATA_STATE_KEYPATH]; + } +} + +#pragma mark - privateAPI +- (void)n_receiveReachabilityChangedNotification:(NSNotification*)notification +{ + AFNetworkReachabilityStatus netWorkStatus = [[AFNetworkReachabilityManager sharedManager] networkReachabilityStatus]; + switch (netWorkStatus) + { + case AFNetworkReachabilityStatusNotReachable: + [self setValue:@(DDNetWorkDisconnect) forKeyPath:DD_NETWORK_STATE_KEYPATH]; + break; + case AFNetworkReachabilityStatusReachableViaWiFi: + [self setValue:@(DDNetWorkWifi) forKeyPath:DD_NETWORK_STATE_KEYPATH]; + break; + case AFNetworkReachabilityStatusReachableViaWWAN: + [self setValue:@(DDNetWork3G) forKeyPath:DD_NETWORK_STATE_KEYPATH]; + break; + case AFNetworkReachabilityStatusUnknown: + log4Error(@"网络状态:unknow"); + break; + } +} + +- (void)p_registerAPI +{ + DDReceiveKickAPI* receiveKickAPI = [[DDReceiveKickAPI alloc] init]; + [receiveKickAPI registerAPIInAPIScheduleReceiveData:^(id object, NSError *error) { + if (!error) + { + KickReasonType reason = [object intValue]; + switch (reason) + { + case KickReasonTypeKickReasonDuplicateUser: + self.userState = DDUserKickout; + break; + case KickReasonTypeKickReasonMobileKick: + self.userState = DDUserKickByMobile; + break; + default: + break; + } + } + }]; +} +@end diff --git a/mac/TeamTalk/StateMaintenance/DDClientStateMaintenanceManager.h b/mac/TeamTalk/StateMaintenance/DDClientStateMaintenanceManager.h new file mode 100644 index 000000000..d7da26c21 --- /dev/null +++ b/mac/TeamTalk/StateMaintenance/DDClientStateMaintenanceManager.h @@ -0,0 +1,18 @@ +// +// DDClientStateMaintenanceManager.h +// Duoduo +// +// Created by 独嘉 on 14-4-12. +// Copyright (c) 2014年 mogujie. All rights reserved. +// + +#import "DDRootModule.h" + +/** + * 自身状态的维护 + */ +@interface DDClientStateMaintenanceManager : DDRootModule + ++ (instancetype)shareInstance; + +@end diff --git a/mac/TeamTalk/StateMaintenance/DDClientStateMaintenanceManager.m b/mac/TeamTalk/StateMaintenance/DDClientStateMaintenanceManager.m new file mode 100644 index 000000000..8ca00cb4d --- /dev/null +++ b/mac/TeamTalk/StateMaintenance/DDClientStateMaintenanceManager.m @@ -0,0 +1,244 @@ +// +// DDClientStateMaintenanceManager.m +// Duoduo +// +// Created by 独嘉 on 14-4-12. +// Copyright (c) 2014年 zuoye. All rights reserved. +// + +#import "DDClientStateMaintenanceManager.h" +#import "DDTcpClientManager.h" +#import "DDClientState.h" +#import "DDLoginManager.h" +#import "DDHeartBeatAPI.h" + +static NSInteger const heartBeatTimeinterval = 30; +static NSInteger const serverHeartBeatTimeinterval = 60; +static NSInteger const reloginTimeinterval = 1; + +@interface DDClientStateMaintenanceManager(PrivateAPI) + +//检验服务器端的心跳 +- (void)p_startCheckServerHeartBeat; +- (void)p_stopCheckServerHeartBeat; +- (void)p_onCheckServerHeartTimer:(NSTimer*)timer; +- (void)n_receiveServerHeartBeat; + +//客户端心跳 +- (void)p_onSendHeartBeatTimer:(NSTimer*)timer; + +//断线重连 +- (void)p_startRelogin; +- (void)p_onReloginTimer:(NSTimer*)timer; +- (void)p_onReserverHeartTimer:(NSTimer*)timer; + +@end + +@implementation DDClientStateMaintenanceManager +{ + NSTimer* _sendHeartTimer; + NSTimer* _reloginTimer; + NSTimer* _serverHeartBeatTimer; + + BOOL _receiveServerHeart; + NSUInteger _reloginInterval; +} ++ (instancetype)shareInstance +{ + static DDClientStateMaintenanceManager* g_clientStateManintenanceManager; + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^{ + g_clientStateManintenanceManager = [[DDClientStateMaintenanceManager alloc] init]; + }); + return g_clientStateManintenanceManager; +} + +- (id)init +{ + self = [super init]; + if (self) + { + [self registObserveClientState]; + [self registObserveNetWorkState]; + [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(n_receiveServerHeartBeat) name:notificationServerHeartBeat object:nil]; + + } + return self; +} + +- (void)dealloc +{ + [[DDClientState shareInstance] removeObserver:self + forKeyPath:DD_NETWORK_STATE_KEYPATH]; + + [[DDClientState shareInstance] removeObserver:self + forKeyPath:DD_USER_STATE_KEYPATH]; +} + +#pragma mark KVO +- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context +{ + DDClientState* clientState = [DDClientState shareInstance]; + //网络状态变化 + if ([keyPath isEqualToString:DD_NETWORK_STATE_KEYPATH]) + { + if ([DDClientState shareInstance].networkState != DDNetWorkDisconnect) + { + // + BOOL shouldRelogin = !_reloginTimer && clientState.userID && ![_reloginTimer isValid] && clientState.userState != DDUserKickout && clientState.userState != DDUserKickByMobile && clientState.userState != DDUserOffLineInitiative; + if (shouldRelogin) + { + _reloginTimer = [NSTimer scheduledTimerWithTimeInterval:reloginTimeinterval target:self selector:@selector(p_onReloginTimer:) userInfo:nil repeats:YES]; + _reloginInterval = 0; + [_reloginTimer fire]; + } + } + else + { + [[DDClientState shareInstance] setUseStateWithoutObserver:DDUserOffLine]; + } + } + //用户状态变化 + else if ([keyPath isEqualToString:DD_USER_STATE_KEYPATH]) + { + switch ([DDClientState shareInstance].userState) + { + case DDUserKickout: + case DDUserKickByMobile: + [self p_stopCheckServerHeartBeat]; + [self p_stopHeartBeat]; + break; + case DDUserOffLine: + [self p_stopCheckServerHeartBeat]; + [self p_stopHeartBeat]; + [self p_startRelogin]; + break; + case DDUserOffLineInitiative: + [self p_stopCheckServerHeartBeat]; + [self p_stopHeartBeat]; + break; + case DDUserOnline: + [self p_startCheckServerHeartBeat]; + [self p_startHeartBeat]; + break; + case DDUserLogining: + break; + } + } +} + +#pragma mark private API + +//开启发送心跳的Timer +-(void)p_startHeartBeat{ + + DDLog(@"begin heart beat"); + if (!_sendHeartTimer && ![_sendHeartTimer isValid]) + { + _sendHeartTimer = [NSTimer scheduledTimerWithTimeInterval: heartBeatTimeinterval + target: self + selector: @selector(p_onSendHeartBeatTimer:) + userInfo: nil + repeats: YES]; + } +} + +//关闭发送心跳的Timer +- (void)p_stopHeartBeat +{ + if (_sendHeartTimer) + { + [_sendHeartTimer invalidate]; + _sendHeartTimer = nil; + } +} + +//开启检验服务器端心跳的Timer +- (void)p_startCheckServerHeartBeat +{ + if (!_serverHeartBeatTimer) + { + DDLog(@"begin maintenance _serverHeartBeatTimer"); + _serverHeartBeatTimer = [NSTimer scheduledTimerWithTimeInterval:serverHeartBeatTimeinterval target:self selector:@selector(p_onCheckServerHeartTimer:) userInfo:nil repeats:YES]; + [_serverHeartBeatTimer fire]; + } +} + +//停止检验服务器端心跳的Timer +- (void)p_stopCheckServerHeartBeat +{ + if (_serverHeartBeatTimer) + { + [_serverHeartBeatTimer invalidate]; + _serverHeartBeatTimer = nil; + } +} + +//开启重连Timer +- (void)p_startRelogin +{ + if (!_reloginTimer) + { + _reloginTimer = [NSTimer scheduledTimerWithTimeInterval:reloginTimeinterval target:self selector:@selector(p_onReloginTimer:) userInfo:nil repeats:YES]; + [_reloginTimer fire]; + } +} + +//运行在发送心跳的Timer上 +- (void)p_onSendHeartBeatTimer:(NSTimer*)timer +{ + DDLog(@" 😂😂😂😂😂😂😂😂😂😂😂😂😂😂😂😂😂😂😂😂😂😂😂😂😂😂😂 "); + + DDHeartBeatAPI* heartBeatAPI = [[DDHeartBeatAPI alloc] init]; + [heartBeatAPI requestWithObject:nil Completion:nil]; +} + +//收到服务器端的数据包 +- (void)n_receiveServerHeartBeat +{ + _receiveServerHeart = YES; +} + +//运行在检验服务器端心跳的Timer上 +- (void)p_onCheckServerHeartTimer:(NSTimer *)timer +{ + DDLog(@"check server heart"); + if (_receiveServerHeart) + { + _receiveServerHeart = NO; + } + else + { + [_serverHeartBeatTimer invalidate]; + _serverHeartBeatTimer = nil; + //太久没收到服务器端数据包了 + DDLog(@"太久没收到服务器端数据包了~"); + [DDClientState shareInstance].userState = DDUserOffLine; + } +} + +//运行在断线重连的Timer上 +- (void)p_onReloginTimer:(NSTimer*)timer +{ + static NSUInteger time = 0; + static NSUInteger powN = 0; + time ++; + if (time >= _reloginInterval) + { + [[DDLoginManager instance] reloginSuccess:^{ + [_reloginTimer invalidate]; + _reloginTimer = nil; + time = 0; + _reloginInterval = 0; + powN = 0; + DDLog(@"relogin success"); + } failure:^(NSString *error) { + DDLog(@"relogin failure:%@",error); + powN ++; + time = 0; + _reloginInterval = pow(2, powN); + }]; + } +} + +@end diff --git a/mac/TeamTalk/StateMaintenance/DDCurrentUserState.h b/mac/TeamTalk/StateMaintenance/DDCurrentUserState.h new file mode 100644 index 000000000..6a7313765 --- /dev/null +++ b/mac/TeamTalk/StateMaintenance/DDCurrentUserState.h @@ -0,0 +1,22 @@ +// +// DDCurrentUserState.h +// Duoduo +// +// Created by 独嘉 on 14-4-9. +// Copyright (c) 2014年 zuoye. All rights reserved. +// + +#import +@class MTUserEntity; +@interface DDCurrentUserState : NSObject +@property (nonatomic,readonly)MTUserEntity* user; ++ (instancetype)instance; + +/** + * 初始化登录用户 + * + * @param user 登录用户 + */ +- (void)loginTheUser:(MTUserEntity*)user; + +@end diff --git a/mac/TeamTalk/StateMaintenance/DDCurrentUserState.m b/mac/TeamTalk/StateMaintenance/DDCurrentUserState.m new file mode 100644 index 000000000..c29be452e --- /dev/null +++ b/mac/TeamTalk/StateMaintenance/DDCurrentUserState.m @@ -0,0 +1,30 @@ +// +// DDCurrentUserState.m +// Duoduo +// +// Created by 独嘉 on 14-4-9. +// Copyright (c) 2014年 zuoye. All rights reserved. +// + +#import "DDCurrentUserState.h" +#import "MTUserEntity.h" +@implementation DDCurrentUserState ++ (instancetype)instance +{ + static DDCurrentUserState* g_currentUserState; + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^{ + g_currentUserState = [[DDCurrentUserState alloc] init]; + }); + return g_currentUserState; +} + +- (void)loginTheUser:(MTUserEntity*)user +{ + if (_user) + { + _user = nil; + } + _user = [user copy]; +} +@end diff --git a/mac/TeamTalk/StateMaintenance/StateMaintenanceManager.h b/mac/TeamTalk/StateMaintenance/StateMaintenanceManager.h new file mode 100644 index 000000000..8f84fbf84 --- /dev/null +++ b/mac/TeamTalk/StateMaintenance/StateMaintenanceManager.h @@ -0,0 +1,41 @@ +// +// StateMaintenanceManager.h +// Duoduo +// +// Created by 独嘉 on 14-4-4. +// Copyright (c) 2014年 zuoye. All rights reserved. +// + +#import "DDRootModule.h" +#import "IMBaseDefine.pb.h" + +@class DDUserStateEntity; +#define DD_USER_ONLINE_STATE_KEYPATH @"userStateEntity" + +@interface StateMaintenanceManager : DDRootModule +/** + * 用户在线状态 + */ +@property (nonatomic,strong)DDUserStateEntity *userStateEntity; + ++ (instancetype)instance; + +/** + * 获得用户的在线状态 + * + * @param userID 用户ID + * + * @return 在线状态 + */ + +-(UserStatType) getUserStateForUserID:(NSString*)userID; +@end + + +@interface DDUserStateEntity : NSObject + +@property (nonatomic,copy)NSString *userId; +@property (nonatomic,assign)NSUInteger uState; + +-(id)initWithUserId:(NSString *)userId state:(NSUInteger)uState; +@end diff --git a/mac/TeamTalk/StateMaintenance/StateMaintenanceManager.m b/mac/TeamTalk/StateMaintenance/StateMaintenanceManager.m new file mode 100644 index 000000000..5abdb8e2b --- /dev/null +++ b/mac/TeamTalk/StateMaintenance/StateMaintenanceManager.m @@ -0,0 +1,246 @@ +// +// StateMaintenanceManager.m +// Duoduo +// +// Created by 独嘉 on 14-4-4. +// Copyright (c) 2014年 zuoye. All rights reserved. +// + +#import "StateMaintenanceManager.h" +#import "LoginEntity.h" +#import "MTUserEntity.h" +#import "DDTcpClientManager.h" +#import "DDReceiveStateChangedAPI.h" +#import "DDOnlineUserListAPI.h" +#import "MTUserModule.h" + +@interface StateMaintenanceManager(PrivateAPI) + +- (void)p_maintanceOnlineStateOnTimer:(NSTimer*)timer; +- (void)p_registerStateMaintenance; + +/** + * 添加用户状态 + * + * @param userID 用户ID + * @param userState 在线,或者离开 + */ +- (void)p_addOnlineUser:(NSString*)userID state:(UserStatType)userState; + +/** + * 移除在线用户 + * + * @param userID 用户ID + */ +- (void)p_removeOnlineUser:(NSString*)userID; + +/** + * 开始维护用户在线状态 + */ +- (void)p_startMaintainUsersOnlineState; + +/** + * 停止维护用户在线状态 + */ +- (void)p_endMaintainUsersOnlineState; + +/** + * 更新用户状态for kvo + */ +-(void)p_updateUserState:(NSString *)userID state:(UserStatType)userState; + +@end + +@implementation StateMaintenanceManager +{ + NSMutableDictionary* _userStates; + NSTimer* _stateMaintenanceTimer; +} ++ (instancetype)instance +{ + static StateMaintenanceManager* g_stateMaintenanceManager; + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^{ + g_stateMaintenanceManager = [[StateMaintenanceManager alloc] init]; + }); + return g_stateMaintenanceManager; +} + +- (id)init +{ + self = [super init]; + if (self) + { + _userStates = [[NSMutableDictionary alloc] init]; + [self p_registerStateMaintenance]; + [self registObserveClientState]; + [self registObserveDataReadyState]; + } + return self; +} + +//tt_3.0 这里还有一个离线状态需要处理 @某嘉 +- (UserStatType)getUserStateForUserID:(NSString*)userID +{ + + if (![[_userStates allKeys] containsObject:userID]) + { + return UserStatTypeUserStatusOffline; + } + else + { + NSNumber* state = _userStates[userID]; + return [state intValue]; + } +} + +//- (void)setUserStateEntity:(DDUserStateEntity *)userStateEntity +//{ +// [self willChangeValueForKey:DD_USER_ONLINE_STATE_KEYPATH]; +// _userStateEntity = [[DDUserStateEntity alloc] initWithUserId:userStateEntity.userId state:userStateEntity.uState]; +// [self didChangeValueForKey:DD_USER_ONLINE_STATE_KEYPATH]; +//} +// +//+ (BOOL) automaticallyNotifiesObserversForKey:(NSString *)key { +// if ([key isEqualToString:DD_USER_ONLINE_STATE_KEYPATH]) { +// return NO; +// } +// +// return [super automaticallyNotifiesObserversForKey:key]; +//} + +- (void)dealloc +{ + +} + +#pragma mark - +#pragma mark KVO +- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context +{ + if ([keyPath isEqualToString:DD_DATA_STATE_KEYPATH]) + { + DDDataState oldDataState = [change[@"old"] integerValue]; + DDDataState newDataState = [change[@"new"] integerValue]; + if (!(oldDataState & DDRemoteUserDataReady) && (newDataState & DDRemoteUserDataReady)) + { + //用户数据加载完成,获取在线用户列表 + [self p_startMaintainUsersOnlineState]; + } + } + else if ([keyPath isEqualToString:DD_USER_STATE_KEYPATH]) + { + switch ([DDClientState shareInstance].userState) + { + case DDUserLogining: + break; + case DDUserOnline: + break; + case DDUserKickout: + case DDUserKickByMobile: + [self p_endMaintainUsersOnlineState]; + break; + case DDUserOffLine: + //离线所有用户 + [self p_endMaintainUsersOnlineState]; + break; + case DDUserOffLineInitiative: + //离线所有用户 + [self p_endMaintainUsersOnlineState]; + break; + default: + break; + } + } +} + +#pragma mark - PrivateAPI +- (void)p_registerStateMaintenance +{ + DDReceiveStateChangedAPI* api = [[DDReceiveStateChangedAPI alloc] init]; + [api registerAPIInAPIScheduleReceiveData:^(id object, NSError *error) { + if (!error) + { + //修改用户状态 + UserStat *userStat = (UserStat*)object; + NSString *strUserId = [NSString stringWithFormat:@"%i",userStat.userId]; + if(userStat.status==UserStatTypeUserStatusOffline){ + [self p_removeOnlineUser:strUserId]; + }else{ + [self p_addOnlineUser:strUserId state:userStat.status]; + } + + //通知刷新UI kvo + DDUserStateEntity *userStateEntity =[[DDUserStateEntity alloc]initWithUserId:strUserId state:userStat.status]; + [[StateMaintenanceManager instance] setValue:userStateEntity forKey:DD_USER_ONLINE_STATE_KEYPATH]; + } + }]; +} + +/** + * 添加在线用户 + * + * @param userID 用户ID + */ +- (void)p_addOnlineUser:(NSString*)userID state:(UserStatType)userState +{ + [_userStates setObject:@(userState) forKey:userID]; +} + +-(void)p_updateUserState:(NSString *)userID state:(UserStatType)userState{ + +} + +/** + * 移除在线用户 + * + * @param userID 用户ID + */ +- (void)p_removeOnlineUser:(NSString*)userID +{ + [_userStates removeObjectForKey:userID]; +} + +- (void)p_startMaintainUsersOnlineState +{ + //TODO发起请求获取当前在线用户列表 + DDOnlineUserListAPI *onlineUserListApi = [[DDOnlineUserListAPI alloc]init]; + NSArray *allUserId = [[MTUserModule shareInstance] getAllUserId]; + NSMutableArray *intAllUserId = [[NSMutableArray alloc] init]; + [allUserId enumerateObjectsUsingBlock:^(NSString *strUserId, NSUInteger idx, BOOL *stop) { + [intAllUserId addObject:@([strUserId integerValue])]; + }]; + [onlineUserListApi requestWithObject:(id)intAllUserId Completion:^(id response, NSError *error) { + if(!error){ + NSArray *allUserState = (NSArray *)response; + [allUserState enumerateObjectsUsingBlock:^(UserStat *obj, NSUInteger idx, BOOL *stop) { + if (obj.status!=UserStatTypeUserStatusOffline) { + [_userStates setObject:@(obj.status) forKey:[NSString stringWithFormat:@"%i",obj.userId]]; + } + }]; + } + }]; +} + +/** + * 停止维护用户在线状态 + */ +- (void)p_endMaintainUsersOnlineState +{ + [_userStates removeAllObjects]; +} + +@end + +@implementation DDUserStateEntity + +-(id)initWithUserId:(NSString *)userId state:(NSUInteger)uState{ + self=[super init]; + if (self) { + _userId=[userId copy]; + _uState = uState; + } + return self; +} + +@end diff --git a/mac/TeamTalk/TeamTalk-Info.plist b/mac/TeamTalk/TeamTalk-Info.plist new file mode 100644 index 000000000..a61c34c03 --- /dev/null +++ b/mac/TeamTalk/TeamTalk-Info.plist @@ -0,0 +1,40 @@ + + + + + CFBundleDevelopmentRegion + zh_CN + CFBundleExecutable + ${EXECUTABLE_NAME} + CFBundleIconFile + icon + CFBundleIdentifier + com.mogujie.${PRODUCT_NAME:rfc1034identifier} + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + ${PRODUCT_NAME} + CFBundlePackageType + APPL + CFBundleShortVersionString + 1.0 + CFBundleSignature + ???? + CFBundleVersion + 1.0.0 + LSMinimumSystemVersion + ${MACOSX_DEPLOYMENT_TARGET} + NSHumanReadableCopyright + Copyright © 2014年 mogujie. All rights reserved. + NSMainNibFile + MainMenu + NSPrincipalClass + NSApplication + SUAllowsAutomaticUpdates + + SUFeedURL + http://home.mogujie.org/download/teamtalk.xml + SUPublicDSAKeyFile + dsa_pub.pem + + diff --git a/mac/TeamTalk/TeamTalk-Prefix.pch b/mac/TeamTalk/TeamTalk-Prefix.pch new file mode 100644 index 000000000..d3a7e0e25 --- /dev/null +++ b/mac/TeamTalk/TeamTalk-Prefix.pch @@ -0,0 +1,18 @@ +// +// Prefix header +// +// The contents of this file are implicitly included at the beginning of every source file. +// + +#ifdef __OBJC__ +#import +#import "DDSharedDuoduo.h" +#import "CONSTANT.h" +#import "Log4Cocoa.h" +#import "StateMaintenanceManager.h" +#import "NotificationHelp.h" +#import "TcpProtocolHeader.h" +#import "DDSundriesCenter.h" +#import "DDClientState.h" +#endif + diff --git a/mac/TeamTalk/contacts&chats/DDListGroup.h b/mac/TeamTalk/contacts&chats/DDListGroup.h new file mode 100644 index 000000000..7f2db97f9 --- /dev/null +++ b/mac/TeamTalk/contacts&chats/DDListGroup.h @@ -0,0 +1,35 @@ +// +// DDListGroup.h +// Duoduo +// +// Created by zuoye on 13-11-20. +// Copyright (c) 2013年 zuoye. All rights reserved. +// + +#import +#import "DDListObject.h" +#import "DDContactObserverManager.h" + +@class DDContactList; + +//联系人里一组用户. duoduo 暂时只有一组用户. +@interface DDListGroup : DDListObject{ + NSMutableArray *_visibleObjects; + NSMutableArray *_containedObjects; //Manually ordered array of contents + BOOL expanded; //Exanded/Collapsed state of this object + BOOL loadedExpanded; +} +- (id)initWithUID:(NSString *)inUID; + +//Object Storage +- (DDListObject *)objectWithServiceUID:(NSString *)inUID; + +//Sorting (PRIVATE: For contact controller only) +- (void)sortListObject:(DDListObject *)inObject; +- (void)sort; + +//Visibility +@property (readonly, nonatomic) NSUInteger visibleCount; + +@property (weak, readonly, nonatomic) DDContactList *contactList; +@end diff --git a/mac/TeamTalk/contacts&chats/DDListGroup.m b/mac/TeamTalk/contacts&chats/DDListGroup.m new file mode 100644 index 000000000..16a7e5c17 --- /dev/null +++ b/mac/TeamTalk/contacts&chats/DDListGroup.m @@ -0,0 +1,57 @@ +// +// DDListGroup.m +// Duoduo +// +// Created by zuoye on 13-11-20. +// Copyright (c) 2013年 zuoye. All rights reserved. +// + +#import "DDListGroup.h" +#import "DDContactObserverManager.h" + + +@interface DDListObject () +- (void)setContainingGroup:(DDListGroup *)inGroup; +@end + +@interface DDListGroup () +- (void) rebuildVisibleCache; +@end + + +@implementation DDListGroup +@synthesize visibleCount; +@synthesize contactList; + +-(id)initWithUID:(NSString *)inUID{ + if ((self=[super initWithUID:inUID] )) { + _visibleObjects = [[NSMutableArray alloc] init]; + _containedObjects = [[NSMutableArray alloc] init]; + } + + /* + if ((self = [super initWithUID:inUID service:nil])) { + _visibleObjects = [[NSMutableArray alloc] init]; + _containedObjects = [[NSMutableArray alloc] init]; + expanded = YES; + [[DDContactObserverManager sharedManager] registerListObjectObserver:self]; + [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(rebuildVisibleCache) name:CONTACT_VISIBILITY_OPTIONS_CHANGED_NOTIFICATION object:nil]; + } + */ + + return self; +} + +-(NSUInteger)visibleIndexOfObject:(DDListObject *)object{ + return [_visibleObjects indexOfObject:object]; +} + + +- (void)dealloc +{ + //[[DDContactObserverManager sharedManager] unregisterListObjectObserver:self]; + //[[NSNotificationCenter defaultCenter] removeObserver:self]; +} + + +@end diff --git a/mac/TeamTalk/contacts&chats/DDListObject.h b/mac/TeamTalk/contacts&chats/DDListObject.h new file mode 100644 index 000000000..8c82d6532 --- /dev/null +++ b/mac/TeamTalk/contacts&chats/DDListObject.h @@ -0,0 +1,57 @@ +// +// DDListObject.h +// Duoduo +// +// Created by maye on 13-11-20. +// Copyright (c) 2013年 zuoye. All rights reserved. +// + +#import "ESObjectWithProperties.h" + +// 对列表对象的抽象封装. +@interface DDListObject : ESObjectWithProperties{ + NSString *UID; +} + +- (id)initWithUID:(NSString *)inUID; + +@property (readonly, nonatomic) NSString *UID; +@property (weak, readonly, nonatomic) NSString *longDisplayName; + +@end + + + + +@protocol DDContainingObject + +@property (readonly, copy, nonatomic) NSArray *visibleContainedObjects; +@property (readonly, copy, nonatomic) NSArray *containedObjects; +- (NSUInteger) countOfContainedObjects; +@property (readonly, nonatomic) NSArray *uniqueContainedObjects; +@property (readwrite, nonatomic, getter=isExpanded) BOOL expanded; +@property (readonly, nonatomic, getter=isExpandable) BOOL expandable; + +@property (readonly, nonatomic) NSString *contentsBasedIdentifier; +@property (readonly, nonatomic) NSUInteger visibleCount; + + +- (BOOL)containsObject:(DDListObject *)inObject; + +/*! + * As NSArray's -objectAtIndex:, except that it only looks at visible objects contained in this object + */ +- (DDListObject *)visibleObjectAtIndex:(NSUInteger)index; + +/*! + * As NSArray's -indexOfObject:, except that it looks at visible objects contained in this object + */ +- (NSUInteger)visibleIndexOfObject:(DDListObject *)object; + + +//- (DDListObject *)objectWithService:(DDService *)inService UID:(NSString *)inUID; + + + + +@end \ No newline at end of file diff --git a/mac/TeamTalk/contacts&chats/DDListObject.m b/mac/TeamTalk/contacts&chats/DDListObject.m new file mode 100644 index 000000000..f36436b72 --- /dev/null +++ b/mac/TeamTalk/contacts&chats/DDListObject.m @@ -0,0 +1,39 @@ +// +// DDListObject.m +// Duoduo +// +// Created by maye on 13-11-20. +// Copyright (c) 2013年 zuoye. All rights reserved. +// + +#import "DDListObject.h" + +#define DisplayName @"Display Name" +#define LongDisplayName @"Long Display Name" +#define Key @"Key" +#define Group @"Group" +#define DisplayServiceID @"DisplayServiceID" +#define AlwaysVisible @"alwaysVisible" + + +@implementation DDListObject +@synthesize UID; + + +-(id)initWithUID:(NSString *)inUID{ + if ((self = [super init])) { + UID=inUID; + } + + return self; +} + + + +- (NSString *)longDisplayName +{ + NSString *outName = [self displayArrayObjectForKey:LongDisplayName]; + + return outName ? outName : self.displayName; +} +@end diff --git a/mac/TeamTalk/contacts&chats/DDProxyListObject.h b/mac/TeamTalk/contacts&chats/DDProxyListObject.h new file mode 100644 index 000000000..756d7c445 --- /dev/null +++ b/mac/TeamTalk/contacts&chats/DDProxyListObject.h @@ -0,0 +1,53 @@ +// +// DDProxyListObject.h +// Duoduo +// +// Created by zuoye on 13-11-27. +// Copyright (c) 2013年 zuoye. All rights reserved. +// + +@class ESObjectWithProperties,DDListObject; +@protocol DDContainingObject; + +@interface DDProxyListObject : NSObject { + DDListObject *__weak listObject; + ESObjectWithProperties *__weak containingObject; + NSString *key; + NSString *cachedDisplayNameString; + NSAttributedString *cachedDisplayName; + NSDictionary *cachedLabelAttributes; + NSSize cachedDisplayNameSize; + NSString *nick; +} +@property (nonatomic, copy) NSDictionary *cachedLabelAttributes; +@property (nonatomic, strong) NSString *cachedDisplayNameString; +@property (nonatomic, strong) NSAttributedString *cachedDisplayName; +@property (nonatomic) NSSize cachedDisplayNameSize; + +@property (nonatomic, strong) NSString *key; +@property (nonatomic, strong) NSString *nick; + +@property (nonatomic, weak) DDListObject *listObject; +@property (nonatomic, weak) ESObjectWithProperties * containingObject; + ++ (DDProxyListObject *)proxyListObjectForListObject:(ESObjectWithProperties *)inListObject + inListObject:(ESObjectWithProperties *)containingObject; + ++ (DDProxyListObject *)existingProxyListObjectForListObject:(ESObjectWithProperties *)inListObject + inListObject:(ESObjectWithProperties *)inContainingObject; + ++ (DDProxyListObject *)proxyListObjectForListObject:(DDListObject *)inListObject + inListObject:(ESObjectWithProperties *)inContainingObject + withNick:(NSString *)inNick; + +/*! + * @brief Called when an AIListObject is done with an AIProxyListObject to remove it from the global dictionary + */ ++ (void)releaseProxyObject:(DDProxyListObject *)proxyObject; + +/*! + * @brief Clear out cached display information; should be called when the AIProxyListObject may be used later + */ +- (void)flushCache; + +@end \ No newline at end of file diff --git a/mac/TeamTalk/contacts&chats/DDProxyListObject.m b/mac/TeamTalk/contacts&chats/DDProxyListObject.m new file mode 100644 index 000000000..1ee7ca8c9 --- /dev/null +++ b/mac/TeamTalk/contacts&chats/DDProxyListObject.m @@ -0,0 +1,146 @@ +// +// DDProxyListObject.m +// Duoduo +// +// Created by zuoye on 13-11-27. +// Copyright (c) 2013年 zuoye. All rights reserved. +// + +#import "DDProxyListObject.h" +#import "DDListObject.h" +#import "ESObjectWithProperties.h" + + +@interface NSObject (PublicAPIMissingFromHeadersAndDocsButInTheReleaseNotesGoshDarnit) +- (id)forwardingTargetForSelector:(SEL)aSelector; +@end + +@implementation DDProxyListObject + +@synthesize key, cachedDisplayName, cachedDisplayNameString, cachedLabelAttributes, cachedDisplayNameSize; +@synthesize listObject, containingObject, nick; + + +static inline NSMutableDictionary *_getProxyDict() { + static NSMutableDictionary *proxyDict; + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^{ + proxyDict = [[NSMutableDictionary alloc] init]; + }); + return proxyDict; +} + +#define proxyDict _getProxyDict() + ++ (DDProxyListObject *)existingProxyListObjectForListObject:(DDListObject *)inListObject + inListObject:(ESObjectWithProperties *)inContainingObject +{ + NSString *key = (inContainingObject ? + [NSString stringWithFormat:@"%@-%@", inListObject.internalObjectID, inContainingObject.internalObjectID] : + inListObject.internalObjectID); + + return [proxyDict objectForKey:key]; +} + ++ (DDProxyListObject *)proxyListObjectForListObject:(DDListObject *)inListObject + inListObject:(ESObjectWithProperties *)inContainingObject +{ + return [self proxyListObjectForListObject:inListObject inListObject:inContainingObject withNick:nil]; +} + ++ (DDProxyListObject *)proxyListObjectForListObject:(DDListObject *)inListObject + inListObject:(ESObjectWithProperties *)inContainingObject + withNick:(NSString *)inNick +{ + DDProxyListObject *proxy; + NSString *key = (inContainingObject ? + [NSString stringWithFormat:@"%@-%@", inListObject.internalObjectID, inContainingObject.internalObjectID] : + inListObject.internalObjectID); + + if (inNick) { + key = [key stringByAppendingFormat:@"-%@", inNick]; + } + + proxy = [proxyDict objectForKey:key]; + + if (proxy && proxy.listObject != inListObject) { + /* This is generally a memory management failure; AIContactController stopped tracking a list object, but it never deallocated and + * so never called [AIProxyListObject releaseProxyObject:]. -evands 8/28/11 + */ + // AILogWithSignature(@"%@ was leaked! Meh. We'll recreate the proxy for %@.", proxy.listObject, proxy.key); + [self releaseProxyObject:proxy]; + proxy = nil; + } + + if (!proxy) { + proxy = [[DDProxyListObject alloc] init]; + proxy.listObject = inListObject; + proxy.containingObject = inContainingObject; + proxy.key = key; + proxy.nick = inNick; + [inListObject noteProxyObject:proxy]; + [proxyDict setObject:proxy + forKey:key]; + } + + return proxy; +} + +- (void)flushCache +{ + self.cachedDisplayName = nil; + self.cachedDisplayNameString = nil; + self.cachedLabelAttributes = nil; +} + +/*! + * @brief Called when an AIListObject is done with an AIProxyListObject to remove it from the global dictionary + * + * This should be called only by AIListObject when it deallocates, for each of its proxy objects + */ ++ (void)releaseProxyObject:(DDProxyListObject *)proxyObject +{ + proxyObject.listObject = nil; + [proxyObject flushCache]; + [proxyDict removeObjectForKey:proxyObject.key]; +} + +- (void)dealloc +{ + [self flushCache]; +} + +/* Pretend to be our listObject. I suspect being an NSProxy subclass could do this more cleanly, but my initial attempt + * failed and this works fine. + */ +- (Class)class +{ + return [[self listObject] class]; +} + +- (BOOL)isKindOfClass:(Class)class +{ + return [[self listObject] isKindOfClass:class]; +} + +- (BOOL)isMemberOfClass:(Class)class +{ + return [[self listObject] isMemberOfClass:class]; +} + +- (BOOL)isEqual:(id)inObject +{ + return [[self listObject] isEqual:inObject]; +} + +- (id)forwardingTargetForSelector:(SEL)aSelector +{ + return [self listObject]; +} + +- (NSString *)description +{ + return [NSString stringWithFormat:@" %@>", self, [self listObject]]; +} + +@end diff --git a/mac/TeamTalk/contacts&chats/ESObjectWithProperties.h b/mac/TeamTalk/contacts&chats/ESObjectWithProperties.h new file mode 100644 index 000000000..e48ac3568 --- /dev/null +++ b/mac/TeamTalk/contacts&chats/ESObjectWithProperties.h @@ -0,0 +1,64 @@ +// +// ESObjectWithProperties.h +// Duoduo +// +// Created by maye on 13-11-20. +// Copyright (c) 2013年 zuoye. All rights reserved. +// + + +@class DDMutableOwnerArray; + +typedef enum { + NotifyNever = -9999, + NotifyLater = NO, /* 0 */ + NotifyNow = YES /* 1 */ +} NotifyTiming; + +#define KEY_KEY @"Key" +#define KEY_VALUE @"Value" + +@interface ESObjectWithProperties : NSObject { + NSMutableDictionary *propertiesDictionary; + NSMutableSet *changedProperties; //Properties that have changed since the last notification + + NSMutableDictionary *displayDictionary; //A dictionary of values affecting this object's display + + NSMutableSet *proxyObjects; +} + +//Setting properties +- (void)setValue:(id)value forProperty:(NSString *)key notify:(NotifyTiming)notify; +- (void)setValue:(id)value forProperty:(NSString *)key afterDelay:(NSTimeInterval)delay; +- (void)notifyOfChangedPropertiesSilently:(BOOL)silent; + +//Getting properties +@property (readonly, nonatomic) NSDictionary *properties; +- (id)valueForProperty:(NSString *)key; +- (NSInteger)integerValueForProperty:(NSString *)key; +- (int)intValueForProperty:(NSString *)key; +- (BOOL)boolValueForProperty:(NSString *)key; +- (NSNumber *)numberValueForProperty:(NSString *)key; + +//Properties: Specifically for subclasses +- (void)object:(id)inObject didChangeValueForProperty:(NSString *)key notify:(NotifyTiming)notify; +- (void)didModifyProperties:(NSSet *)keys silent:(BOOL)silent; +- (void)didNotifyOfChangedPropertiesSilently:(BOOL)silent; + + +//Display array +- (DDMutableOwnerArray *)displayArrayForKey:(NSString *)inKey; +- (DDMutableOwnerArray *)displayArrayForKey:(NSString *)inKey create:(BOOL)create; +- (id)displayArrayObjectForKey:(NSString *)inKey; + +//Name +@property (readonly, nonatomic, retain) NSString *displayName; + +@property (readonly, nonatomic) NSString *internalObjectID; + +//Mutable owner array delegate method +- (void)mutableOwnerArray:(DDMutableOwnerArray *)inArray didSetObject:(id)anObject withOwner:(id)inOwner priorityLevel:(float)priority; + +- (NSSet *)proxyObjects; +- (void)noteProxyObject:(id)proxyObject; +@end diff --git a/mac/TeamTalk/contacts&chats/ESObjectWithProperties.m b/mac/TeamTalk/contacts&chats/ESObjectWithProperties.m new file mode 100644 index 000000000..d7b335bd4 --- /dev/null +++ b/mac/TeamTalk/contacts&chats/ESObjectWithProperties.m @@ -0,0 +1,444 @@ +// +// ESObjectWithProperties.m +// Duoduo +// +// Created by maye on 13-11-20. +// Copyright (c) 2013年 zuoye. All rights reserved. +// + +/* +#import +#import +#import +*/ + +#import +#import "ESObjectWithProperties.h" +#import "DDMutableOwnerArray.h" + +@interface ESObjectWithProperties (AIPrivate) +- (void)_applyDelayedProperties:(NSDictionary *)infoDict; +- (id)_valueForProperty:(NSString *)key; +@end + +/*! + * @class ESObjectWithProperties + * @brief Abstract superclass for objects with a system of properties and display arrays + * + * Properties are an abstracted NSMutableDictionary implementation with notification of changed + * keys and optional delayed, grouped notification. They allow storage of arbitrary information associate with + * an ESObjectWithProperties subclass. Such information is not persistent across sessions. + * + * Properties are KVO compliant. + * + * Display arrays utilize AIMutableOwnerArray. See its documentation in AIUtilities.framework. + */ +@implementation ESObjectWithProperties + +- (void)_clearProxyObjects +{ + /* + for (AIProxyListObject *proxy in proxyObjects) + [AIProxyListObject releaseProxyObject:proxy]; + [proxyObjects release]; proxyObjects = nil; + */ +} + + +//Setting properties --------------------------------------------------------------------------------------------------- +#pragma mark Setting Properties + +/*! + * @brief Set a property + * + * @param value The value + * @param key The property to set the value to. + * @param notify The notification timing. One of NotifyNow, NotifyLater, or NotifyNever. + */ +- (void)setValue:(id)value forProperty:(NSString *)key notify:(NotifyTiming)notify +{ + /* + NSParameterAssert(key != nil); + id oldValue = [self _valueForProperty:key]; + if (value == oldValue) { //No need to do all this work just to stay the same + return; + } + + [self willChangeValueForKey:key]; + + char property_name[256] = {0}; + + NSAssert([key length] < 256, @"Too long property!"); + + [key getCString:property_name maxLength:256 encoding:NSUTF8StringEncoding]; + + Ivar ivar = class_getInstanceVariable([self class], property_name); + + // fall back to the dictionary + if (ivar == NULL) { + + if (!propertiesDictionary && value) { + // only allocate the dictionary when we're going to actually use it + propertiesDictionary = [[NSMutableDictionary alloc] init]; + } + + if (value) { + [propertiesDictionary setObject:value forKey:key]; + } else { + [propertiesDictionary removeObjectForKey:key]; + } + + } else { + const char *ivarType = ivar_getTypeEncoding(ivar); + + // check if it's a primitive type, if so, attempt to unwrap value + if (ivarType[0] == _C_ID) { + + + object_setIvar(self, ivar, value); + + } else if (strcmp(ivarType, @encode(NSInteger)) == 0) { + + NSInteger *idx = (NSInteger*)((char *)self + ivar_getOffset(ivar)); + NSInteger iValue = [value integerValue]; + + *idx = iValue; + } else if (strcmp(ivarType, @encode(BOOL)) == 0) { + + BOOL *idx = (BOOL*)((char *)self + ivar_getOffset(ivar)); + BOOL iValue = [value boolValue]; + + *idx = iValue; + } + } + + [self object:self didChangeValueForProperty:key notify:notify]; + [self didChangeValueForKey:key]; + */ +} + +/*! + * @brief Set a property after a delay + * + * @param value The value + * @param key The property to set the value to. + * @param delay The delay until the change is made + */ +- (void)setValue:(id)value forProperty:(NSString *)key afterDelay:(NSTimeInterval)delay +{ + [self performSelector:@selector(_applyDelayedProperties:) + withObject:[NSDictionary dictionaryWithObjectsAndKeys: + key, KEY_KEY, + value, KEY_VALUE, + nil] + afterDelay:delay]; +} + +- (id)valueForUndefinedKey:(NSString *)inKey +{ + return [self valueForProperty:inKey]; +} + +/*! + * @brief Perform a delayed property change + * + * Called as a result of -[ESObjectWithProperties setValue:forProperty:afterDelay:] + */ +- (void)_applyDelayedProperties:(NSDictionary *)infoDict +{ + id object = [infoDict objectForKey:KEY_VALUE]; + NSString *key = [infoDict objectForKey:KEY_KEY]; + + [self setValue:object forProperty:key notify:NotifyNow]; +} + +/*! + * @brief Notify of any property changes made with a NotifyTiming of NotifyLater + * + * @param silent YES if the notification should be marked as silent + */ +- (void)notifyOfChangedPropertiesSilently:(BOOL)silent +{ + if (changedProperties && [changedProperties count]) { + //Clear changedProperties in case this status change invokes another, and we re-enter this code + NSSet *keys = changedProperties; + changedProperties = nil; + + [self didModifyProperties:keys silent:silent]; + + [self didNotifyOfChangedPropertiesSilently:silent]; + } +} + +//Getting properties --------------------------------------------------------------------------------------------------- +#pragma mark Getting Properties + +@synthesize properties = propertiesDictionary; + +/*! + * @brief Compatibility class + * @result A call to the private class here for safety's sake. + */ +- (id)valueForProperty:(NSString *)key +{ + return [self _valueForProperty:key]; +} + +/*! + * @brief Value for a property + * @result The value associated with the passed key, or nil if none has been set. + */ +- (id)_valueForProperty:(NSString *)key +{ + id ret = nil; + /* + id value = nil; + char property_name[256] = {0}; + + NSAssert([key length] < 256, @"Too long property!"); + + [key getCString:property_name maxLength:256 encoding:NSUTF8StringEncoding]; + + Ivar ivar = object_getInstanceVariable(self, property_name, (void **)&value); + + if (ivar == NULL) { + ret = [propertiesDictionary objectForKey:key]; + } else { + const char *ivarType = ivar_getTypeEncoding(ivar); + + // attempt to wrap it, if we know how + if (strcmp(ivarType, @encode(NSInteger)) == 0) { + ret = [NSNumber numberWithInteger:(NSInteger)value]; + } else if (strcmp(ivarType, @encode(BOOL)) == 0) { + BOOL *idx = (BOOL*)((char *)self + ivar_getOffset(ivar)); + ret = [NSNumber numberWithBool:*idx]; + } else if (ivarType[0] != _C_ID) { + AILogWithSignature(@" *** This ivar is not an object but an %s! Should not use -valueForProperty: @\"%@\" ***", ivarType, key); + } else { + ret = [[value retain] autorelease]; + } + } + */ + + return ret; +} + +/*! + * @brief Integer for a property + * + * @result int value for key, or 0 if no value is set for key + */ +- (NSInteger)integerValueForProperty:(NSString *)key +{ + NSInteger ret = 0; + /* + char property_name[256] = {0}; + + NSAssert([key length] < 256, @"Too long property!"); + + [key getCString:property_name maxLength:256 encoding:NSUTF8StringEncoding]; + + Ivar ivar = class_getInstanceVariable([self class], property_name); + + if (ivar == NULL) { + NSNumber *number = [self numberValueForProperty:key]; + ret = [number integerValue]; + } else { + + const char *ivarType = ivar_getTypeEncoding(ivar); + + if (strcmp(ivarType, @encode(NSInteger)) != 0) { + AILogWithSignature(@"%@'s %@ ivar is not an NSInteger but an %s! Will attempt to cast, but should not use -integerValueForProperty: @\"%@\"", self, key, ivarType, key); + } + + ret = (NSInteger)object_getIvar(self, ivar); + } + */ + return ret; +} + +- (int)intValueForProperty:(NSString *)key +{ + int ret = 0; + + NSNumber *number = [self numberValueForProperty:key]; + ret = [number intValue]; + + return ret; +} + +- (BOOL)boolValueForProperty:(NSString *)key +{ + BOOL ret = FALSE; + + /* + char property_name[256] = {0}; + + NSAssert([key length] < 256, @"Too long property!"); + + [key getCString:property_name maxLength:256 encoding:NSUTF8StringEncoding]; + + Ivar ivar = class_getInstanceVariable([self class], property_name); + + if (ivar == NULL) { + NSNumber *number = [self numberValueForProperty:key]; + ret = [number boolValue]; + } else { + const char *ivarType = ivar_getTypeEncoding(ivar); + + if (strcmp(ivarType, @encode(BOOL)) != 0) { + AILogWithSignature(@"%@'s %@ ivar is not a BOOL but an %s! Will attempt to cast, but should not use -boolValueForProperty: @\"%@\"", self, key, ivarType, key); + } + + BOOL *idx = (BOOL*)((char *)self + ivar_getOffset(ivar)); + ret = *idx; + } + */ + return ret; +} + +/*! + * @brief NSNumber value for a property + * + * @result The NSNumber for this key, or nil if no such key is set or the value is not an NSNumber + */ +- (NSNumber *)numberValueForProperty:(NSString *)key +{ + id obj = [self valueForProperty:key]; + return ((obj && [obj isKindOfClass:[NSNumber class]]) ? obj : nil); +} + +//For Subclasses ------------------------------------------------------------------------------------------------------- +#pragma mark For Subclasses + +/*! + * @brief Sublcasses should implement this method to take action when a property changes for this object or a contained one + * + * @param inObject An object, which may be this object or any object contained by this one + * @param key The key + * @param notify A NotifyTiming value determining when notification is desired + */ +- (void)object:(id)inObject didChangeValueForProperty:(NSString *)key notify:(NotifyTiming)notify +{ + /* If the property changed for the same object receiving this method, we should send out a notification or note it for later. + * If we get passed another object, it's just an informative message which shouldn't be triggering notification. + */ + if (inObject == self) { + switch (notify) { + case NotifyNow: { + //Send out the notification now + [self didModifyProperties:[NSSet setWithObject:key] + silent:NO]; + break; + } + case NotifyLater: { + //Add this key to changedStatusKeys for later notification + if (!changedProperties) changedProperties = [[NSMutableSet alloc] init]; + [changedProperties addObject:key]; + break; + } + case NotifyNever: break; //Take no notification action + } + } +} + +/*! + * @brief Subclasses should implement this method to respond to a change of a property. + * + * The subclass should post appropriate notifications at this time. + * + * @param keys The keys + * @param silent YES indicates that this should not trigger 'noisy' notifications - it is appropriate for notifications as an account signs on and notes tons of contacts. + */ +- (void)didModifyProperties:(NSSet *)keys silent:(BOOL)silent {}; + + +/*! + * @brief Subclasses should implement this method to respond to a change of properties after notifications have been posted. + * + * @param silent YES indicates that this should not trigger 'noisy' notifications - it is appropriate for notifications as an account signs on and notes tons of contacts. + */ +- (void)didNotifyOfChangedPropertiesSilently:(BOOL)silent {}; + +//Dynamic Display------------------------------------------------------------------------------------------------------ +#pragma mark Dynamic Display +//Access to the display arrays for this object. Will alloc and init an array if none exists. +- (DDMutableOwnerArray *)displayArrayForKey:(NSString *)inKey +{ + if(!displayDictionary) { + displayDictionary = [[NSMutableDictionary alloc] initWithCapacity:1]; + } + + DDMutableOwnerArray *array = [displayDictionary objectForKey:inKey]; + + if (!array) { + array = [[DDMutableOwnerArray alloc] init]; + [array setDelegate:self]; + [displayDictionary setObject:array forKey:inKey]; + } + + return array; +} + +//With create:YES, this is identical to displayArrayForKey: +//With create:NO, just perform the lookup and return either a mutableOwnerArray or nil +- (DDMutableOwnerArray *)displayArrayForKey:(NSString *)inKey create:(BOOL)create +{ + DDMutableOwnerArray *array; + + if (create) { + array = [self displayArrayForKey:inKey]; + } else { + array = [displayDictionary objectForKey:inKey]; + } + + return array; +} + +- (id)displayArrayObjectForKey:(NSString *)inKey +{ + return ([[displayDictionary objectForKey:inKey] objectValue]); +} + +//A mutable owner array (one of our displayArrays) set an object +- (void)mutableOwnerArray:(DDMutableOwnerArray *)inArray didSetObject:(id)anObject withOwner:(id)inOwner priorityLevel:(float)priority +{ + +} + +//Naming --------------------------------------------------------------------------------------------------------------- +#pragma mark Naming + +//Subclasses should override this to provide a general display name +- (NSString *)displayName +{ + return @""; +} + +//Subclasses should override this to provide an ID suitable for comparing using isEqual: +- (NSString *)internalObjectID +{ + return @""; +} + +#pragma mark Proxy objects + +/*! + * @brief Return a set of all proxy objects currently alive for this object + */ +- (NSSet *)proxyObjects +{ + return proxyObjects; +} + +/*! + * @brief Note that a proxy object has been created for this object + */ +- (void)noteProxyObject:(id)proxyObject +{ + if (!proxyObjects) proxyObjects = [[NSMutableSet alloc] init]; + [proxyObjects addObject:proxyObject]; +} + + +@end diff --git a/mac/TeamTalk/dsa_pub.pem b/mac/TeamTalk/dsa_pub.pem new file mode 100644 index 000000000..b29a71019 --- /dev/null +++ b/mac/TeamTalk/dsa_pub.pem @@ -0,0 +1,20 @@ +-----BEGIN PUBLIC KEY----- +MIIDOzCCAi0GByqGSM44BAEwggIgAoIBAQC92iZPbdd8mUDeAk+oiofIZAjfikZg +rUkg1Hrw9WCw9Qu/DYoUClyhGCwSvF7cYLTE1j4+HoaQMoIJYfNGHgWYKCCVxWkN +LL8zE97R0oyQQexIYe4ZAiPDq+OldqTcNZCB5QywzMM95UDfvOpLkyH4dvzEaajW +zYI60CpcGqgwBxoVJ9BSoD8/rxJO2CZq4wRwZrmthCOVt3AmAEt8AYkTFmtpFnuH +oi8R8hztax1RarJzfaS5RUZAupjcNgIzHPzPkwJm6HD6DY5uHv806bH99tvrq9XC +Jaq1TraGP5GNDn7wDnuvml515EZ0lFxhaRMenmrVfgdC9Z6S6IXHyxUtAhUAsb1U +1N9ov1Mw+MY0Os+8I9a3D5sCggEAV5uVB4gbNk3VfPUDvEgciKIrH19eItPnyQfa +UvDzif/BrMgi+z69TfFPN/NvuPI40G208vbqZ4upUmI/iNXMfQXi3QBp5i6R3Jpd +B3QIPmkmHCzgXOaw8XR97cGm2JsvC/3mEIJRVNXPx6F/3z9m6sXXvLNLb5E+ETbA +Ipv1HTCLYjDPbepKNiPQ5GpvHkq/vcKRqXN+A9T+lJqOtWkhQ+nDPZO4w6J6CqE3 +aByDRxXBb44jZm06SxmyCsgHQPvOX2s/JrTCweOjFpoW7z60Sd0Kw63oAgJZv9dI +qf3yPgaS09uOFYJc1MWZ3zufsOzGYMQl5HzR3LCvhxIwY6wPYgOCAQYAAoIBAQCK ++/QIbvphLLVMJ5PFscLqtWp5yP4zEN3HQyT4KMhInKyj+GUlh029R3kGT14NNMea +lKahsOA2XRH9F7+EfzOKwuXW5qOu7S4p3bBwtsD1Cr+/LfPRq/sNnSwIe14fvGbB +0PqaJySJc7dpO/AGsZPjcGSKzkVkWn8rh4zjpz73Q9mIaABabOCyWQ1VOY5yiCeq +JrqT+T8pH3YXPJnFPNDRkR4W5dgR+SvVObD7LT+4mhxhcUQO51s6BViPvph0QXqQ +1NcqrAx1w7U+0Op3/5jTWYAHbQNGrC+EA1yk5lY4si+YM8cwqxDxQ6cd8iOzmimY +FACyr0aHhZTmplpMU0M8 +-----END PUBLIC KEY----- diff --git a/mac/TeamTalk/en.lproj/Credits.rtf b/mac/TeamTalk/en.lproj/Credits.rtf new file mode 100644 index 000000000..46576ef21 --- /dev/null +++ b/mac/TeamTalk/en.lproj/Credits.rtf @@ -0,0 +1,29 @@ +{\rtf0\ansi{\fonttbl\f0\fswiss Helvetica;} +{\colortbl;\red255\green255\blue255;} +\paperw9840\paperh8400 +\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\ql\qnatural + +\f0\b\fs24 \cf0 Engineering: +\b0 \ + Some people\ +\ + +\b Human Interface Design: +\b0 \ + Some other people\ +\ + +\b Testing: +\b0 \ + Hopefully not nobody\ +\ + +\b Documentation: +\b0 \ + Whoever\ +\ + +\b With special thanks to: +\b0 \ + Mom\ +} diff --git a/mac/TeamTalk/en.lproj/InfoPlist.strings b/mac/TeamTalk/en.lproj/InfoPlist.strings new file mode 100644 index 000000000..477b28ff8 --- /dev/null +++ b/mac/TeamTalk/en.lproj/InfoPlist.strings @@ -0,0 +1,2 @@ +/* Localized versions of Info.plist keys */ + diff --git a/mac/TeamTalk/html/PullToLoadHistory.js b/mac/TeamTalk/html/PullToLoadHistory.js new file mode 100644 index 000000000..c4cd372bd --- /dev/null +++ b/mac/TeamTalk/html/PullToLoadHistory.js @@ -0,0 +1,152 @@ +// Setup the namespace +var pullToLoadHistory = { + + // Instance vars +eventCapable: true, +refreshCapable: false, +timeStarted: null, +scrollUpTime: null, + +init: function () { + // Inject the html onto the page + $('.J-chat-display').prepend('

载入中...
 
下拉载入更多
'); + + // Bind scroll listener + $(".J-chat-display").bind('scroll', pullToLoadHistory.monitorScroll); +}, + +monitorScroll: function () { + console.log($(".J-chat-display").scrollTop()); + + if ($(".J-chat-display").scrollTop() <= 0) { + pullToLoadHistory.runScrollCommands(); + // console.log(11111); + // window.WebViewController.scroll($(".J-chat-display").scrollTop()); + } + +// // If user is down the page, pull to refresh is not allowed +// if ($(".J-chat-display").scrollTop() > 0) { +// // reset the time +// pullToLoadHistory.scrollUpTime = null; +// pullToLoadHistory.eventCapable = false; +// } +// +// if ($(".J-chat-display").scrollTop() === 0) { +// // Start a timer if it isn't set +// if (pullToLoadHistory.scrollUpTime === null) { +// pullToLoadHistory.scrollUpTime = new Date(); +// } +// } +// +// // User is real close, let's check that timer and see if it's long enough to load more history +// if (pullToLoadHistory.scrollUpTime !== null) +// { +// var nowTime = new Date(), +// diff = nowTime.getTime() - pullToLoadHistory.scrollUpTime.getTime(); +// +// if (diff > 500) { +// pullToLoadHistory.runScrollCommands(); +// } +// } +// else +// { +// pullToLoadHistory.runScrollCommands(); +// } + +}, + +runScrollCommands: function () { + console.log($(".J-chat-display").scrollTop()); + // Scrolling up has occured, but not enough to load more history yet + if ($(".J-chat-display").scrollTop() < 0 && $(".J-chat-display").scrollTop() > -40) + { + // Set the text to pull to load more + $("#pullToLoad #pullyText").html("下拉载入更多"); + + if ($("#pullToLoad .icon").hasClass("flippedArrow")) { + $("#pullToLoad .icon").removeClass("flippedArrow"); + } + + // Set the position of the pull down bar + $("#pullToLoad").css({ top: Math.abs($(".J-chat-display").scrollTop()) - 40 }); + + // Only set the time if we pull up and if the time is null + if (pullToLoadHistory.refreshCapable === true && pullToLoadHistory.timeStarted === null) { + // Set a date for scrolling back down the way + pullToLoadHistory.timeStarted = new Date(); + } + } + + // Load threshold has passed + if ($(".J-chat-display").scrollTop() <= -40) + { + // Set the text and icon to release + $("#pullToLoad #pullyText").html("松开即可载入"); + + if ( ! $("#pullToLoad .icon").hasClass("flippedArrow")) { + $("#pullToLoad .icon").addClass("flippedArrow"); + + } + + // Set the position incase we scrolled too fast + $("#pullToLoad").css({ top: 0 }); + + // Set load capable + pullToLoadHistory.refreshCapable = true; + + // Wipe out the time + pullToLoadHistory.timeStarted = null; + } + + // We're back down below the page, let's see if we can reload + if ($(".J-chat-display").scrollTop() >= 0 && pullToLoadHistory.refreshCapable === true) + { + if (pullToLoadHistory.timeStarted !== null) { + // Check the time + var nowTime = new Date(), + diff = nowTime.getTime() - pullToLoadHistory.timeStarted.getTime(); + + // If we have taken less than a half second for the release, load more history + if (diff < 500) { + pullToLoadHistory.loadMoreHistory(); + } + } + else + { + // We haven't even got to set the time it was that fast, let's load more history. + pullToLoadHistory.loadMoreHistory(); + } + + // Set the time back to null and set release capable back to false + pullToLoadHistory.timeStarted = null; + pullToLoadHistory.refreshCapable = false; + } + + if ($(".J-chat-display").scrollTop() >= 0) + { + // Set the position to completely hidden again + $("#pullToLoad").css({ top: -40 }); + } + +}, + +loadMoreHistory: function () { + console.log('loadMoreHistory'); + var messages = $("#list dl"); + var messageID = "", messageTimestamp = ""; + for (var i = 0; i < messages.length; i++) { + messageID = $(messages[i]).attr('data-messageid'); + messageTimestamp = $(messages[i]).attr('data-messagetime'); + if (messageID && messageID != "" && + messageTimestamp && messageTimestamp != "") { + break; + } + } + if (messageID && messageID != "") { + controller.loadMoreHistory(messageID, messageTimestamp); + } +} + +}; + +$(document).ready(pullToLoadHistory.init); \ No newline at end of file diff --git a/mac/TeamTalk/html/bg.jpg b/mac/TeamTalk/html/bg.jpg new file mode 100755 index 000000000..a0ee4fed3 Binary files /dev/null and b/mac/TeamTalk/html/bg.jpg differ diff --git a/mac/TeamTalk/html/big.cur b/mac/TeamTalk/html/big.cur new file mode 100644 index 000000000..b3daf8968 Binary files /dev/null and b/mac/TeamTalk/html/big.cur differ diff --git a/mac/TeamTalk/html/blb.png b/mac/TeamTalk/html/blb.png new file mode 100644 index 000000000..35a84655e Binary files /dev/null and b/mac/TeamTalk/html/blb.png differ diff --git a/mac/TeamTalk/html/blbb.png b/mac/TeamTalk/html/blbb.png new file mode 100644 index 000000000..2ad287cc6 Binary files /dev/null and b/mac/TeamTalk/html/blbb.png differ diff --git a/mac/TeamTalk/html/brw.png b/mac/TeamTalk/html/brw.png new file mode 100644 index 000000000..e1546e417 Binary files /dev/null and b/mac/TeamTalk/html/brw.png differ diff --git a/mac/TeamTalk/html/brwb.png b/mac/TeamTalk/html/brwb.png new file mode 100644 index 000000000..e04684dae Binary files /dev/null and b/mac/TeamTalk/html/brwb.png differ diff --git a/mac/TeamTalk/html/gifffer.js b/mac/TeamTalk/html/gifffer.js new file mode 100644 index 000000000..e54834f51 --- /dev/null +++ b/mac/TeamTalk/html/gifffer.js @@ -0,0 +1,81 @@ +var Gifffer = function() { + var images, d = document, ga = 'getAttribute', sa = 'setAttribute'; + images = d && d.querySelectorAll ? d.querySelectorAll('[data-gifffer]') : []; + var createContainer = function(w, h, el) { + var con = d.createElement('DIV'), cls = el[ga]('class'), id = el[ga]('id'); + cls ? con[sa]('class', el[ga]('class')) : null; + id ? con[sa]('id', el[ga]('id')) : null; + con[sa]('style', 'position:relative;cursor:pointer;width:' + w + 'px;height:' + h + 'px;'); + // creating play button + var play = d.createElement('DIV'); + play[sa]('class','gifffer-play-button'); + play[sa]('style', 'display:none;width:60px;height:60px;border-radius:30px;background:rgba(0, 0, 0, 0.3);position:absolute;left:' + ((w/2)-30) + 'px;top:' + ((h/2)-30) + 'px;'); + var trngl = d.createElement('DIV'); + trngl[sa]('style', 'width:0;height: 0;border-top:14px solid transparent;border-bottom:14px solid transparent;border-left:14px solid rgba(0, 0, 0, 0.5);position:absolute;left:26px;top:16px;display:none;') + play.appendChild(trngl); + // dom placement + con.appendChild(play); + el.parentNode.replaceChild(con, el); + return {c: con, p: play }; + }, + i = 0, + imglen = images.length, + process = function(el) { + var url, con, c, w, h, duration,play, gif, playing = false, cc, isC, durationTimeout; + url = el[ga]('data-gifffer'); + w = el[ga]('data-gifffer-width'); + h = el[ga]('data-gifffer-height'); + duration = el[ga]('data-gifffer-duration'); + el.style.display = 'block'; + c = document.createElement('canvas'); + isC = !!(c.getContext && c.getContext('2d')); + if(w && h && isC) cc = createContainer(w, h, el); + el.onload = function() { + if(isC) { + w = w || el.width; + h = h || el.height; + // creating the container + if(!cc) cc = createContainer(w, h, el); + con = cc.c; + play = cc.p; + con.addEventListener('click', function() { + clearTimeout(durationTimeout); + if(!playing) { + playing = true; + gif = d.createElement('IMG'); + gif[sa]('style', 'width:' + w + 'px;height:' + h + 'px;'); + gif[sa]('data-uri', Math.floor(Math.random()*100000) + 1); + setTimeout(function() { + gif.src = url; + }, 0); + con.removeChild(play); + con.removeChild(c); + con.appendChild(gif); + if(parseInt(duration) > 0) { + durationTimeout = setTimeout(function() { + playing = false; + con.appendChild(play); + con.removeChild(gif); + con.appendChild(c); + gif = null; + }, duration); + } + } else { + playing = false; + con.appendChild(play); + con.removeChild(gif); + con.appendChild(c); + gif = null; + } + }); + // canvas + c.width = w; + c.height = h; + c.getContext('2d').drawImage(el, 0, 0, w, h); + con.appendChild(c); + } + } + el.src = url; + } + for(i; i + +*/ + +.hljs { + display: block; + overflow-x: auto; + padding: 0.5em; + background: #f0f0f0; + -webkit-text-size-adjust: none; +} + +.hljs, +.hljs-subst, +.hljs-tag .hljs-title, +.nginx .hljs-title { + color: black; +} + +.hljs-string, +.hljs-title, +.hljs-constant, +.hljs-parent, +.hljs-tag .hljs-value, +.hljs-rules .hljs-value, +.hljs-preprocessor, +.hljs-pragma, +.haml .hljs-symbol, +.ruby .hljs-symbol, +.ruby .hljs-symbol .hljs-string, +.hljs-template_tag, +.django .hljs-variable, +.smalltalk .hljs-class, +.hljs-addition, +.hljs-flow, +.hljs-stream, +.bash .hljs-variable, +.pf .hljs-variable, +.apache .hljs-tag, +.apache .hljs-cbracket, +.tex .hljs-command, +.tex .hljs-special, +.erlang_repl .hljs-function_or_atom, +.asciidoc .hljs-header, +.markdown .hljs-header, +.coffeescript .hljs-attribute { + color: #800; +} + +.smartquote, +.hljs-comment, +.hljs-annotation, +.diff .hljs-header, +.hljs-chunk, +.asciidoc .hljs-blockquote, +.markdown .hljs-blockquote { + color: #888; +} + +.hljs-number, +.hljs-date, +.hljs-regexp, +.hljs-literal, +.hljs-hexcolor, +.smalltalk .hljs-symbol, +.smalltalk .hljs-char, +.go .hljs-constant, +.hljs-change, +.lasso .hljs-variable, +.makefile .hljs-variable, +.asciidoc .hljs-bullet, +.markdown .hljs-bullet, +.asciidoc .hljs-link_url, +.markdown .hljs-link_url { + color: #080; +} + +.hljs-label, +.hljs-javadoc, +.ruby .hljs-string, +.hljs-decorator, +.hljs-filter .hljs-argument, +.hljs-localvars, +.hljs-array, +.hljs-attr_selector, +.hljs-important, +.hljs-pseudo, +.hljs-pi, +.haml .hljs-bullet, +.hljs-doctype, +.hljs-deletion, +.hljs-envvar, +.hljs-shebang, +.apache .hljs-sqbracket, +.nginx .hljs-built_in, +.tex .hljs-formula, +.erlang_repl .hljs-reserved, +.hljs-prompt, +.asciidoc .hljs-link_label, +.markdown .hljs-link_label, +.vhdl .hljs-attribute, +.clojure .hljs-attribute, +.asciidoc .hljs-attribute, +.lasso .hljs-attribute, +.coffeescript .hljs-property, +.hljs-phony { + color: #88f; +} + +.hljs-keyword, +.hljs-id, +.hljs-title, +.hljs-built_in, +.css .hljs-tag, +.hljs-javadoctag, +.hljs-phpdoc, +.hljs-dartdoc, +.hljs-yardoctag, +.smalltalk .hljs-class, +.hljs-winutils, +.bash .hljs-variable, +.pf .hljs-variable, +.apache .hljs-tag, +.hljs-type, +.hljs-typename, +.tex .hljs-command, +.asciidoc .hljs-strong, +.markdown .hljs-strong, +.hljs-request, +.hljs-status { + font-weight: bold; +} + +.asciidoc .hljs-emphasis, +.markdown .hljs-emphasis { + font-style: italic; +} + +.nginx .hljs-built_in { + font-weight: normal; +} + +.coffeescript .javascript, +.javascript .xml, +.lasso .markup, +.tex .hljs-formula, +.xml .javascript, +.xml .vbscript, +.xml .css, +.xml .hljs-cdata { + opacity: 0.5; +} diff --git a/mac/TeamTalk/html/highlight.min.js b/mac/TeamTalk/html/highlight.min.js new file mode 100644 index 000000000..1bd8fcadd --- /dev/null +++ b/mac/TeamTalk/html/highlight.min.js @@ -0,0 +1,2 @@ +!function(e){"undefined"!=typeof exports?e(exports):(window.hljs=e({}),"function"==typeof define&&define.amd&&define([],function(){return window.hljs}))}(function(e){function t(e){return e.replace(/&/gm,"&").replace(//gm,">")}function r(e){return e.nodeName.toLowerCase()}function n(e,t){var r=e&&e.exec(t);return r&&0==r.index}function a(e){var t=(e.className+" "+(e.parentNode?e.parentNode.className:"")).split(/\s+/);return t=t.map(function(e){return e.replace(/^lang(uage)?-/,"")}),t.filter(function(e){return N(e)||/no(-?)highlight/.test(e)})[0]}function i(e,t){var r={};for(var n in e)r[n]=e[n];if(t)for(var n in t)r[n]=t[n];return r}function s(e){var t=[];return function n(e,a){for(var i=e.firstChild;i;i=i.nextSibling)3==i.nodeType?a+=i.nodeValue.length:1==i.nodeType&&(t.push({event:"start",offset:a,node:i}),a=n(i,a),r(i).match(/br|hr|img|input/)||t.push({event:"stop",offset:a,node:i}));return a}(e,0),t}function c(e,n,a){function i(){return e.length&&n.length?e[0].offset!=n[0].offset?e[0].offset"}function c(e){u+=""}function o(e){("start"==e.event?s:c)(e.node)}for(var l=0,u="",d=[];e.length||n.length;){var b=i();if(u+=t(a.substr(l,b[0].offset-l)),l=b[0].offset,b==e){d.reverse().forEach(c);do o(b.splice(0,1)[0]),b=i();while(b==e&&b.length&&b[0].offset==l);d.reverse().forEach(s)}else"start"==b[0].event?d.push(b[0].node):d.pop(),o(b.splice(0,1)[0])}return u+t(a.substr(l))}function o(e){function t(e){return e&&e.source||e}function r(r,n){return RegExp(t(r),"m"+(e.cI?"i":"")+(n?"g":""))}function n(a,s){if(!a.compiled){if(a.compiled=!0,a.k=a.k||a.bK,a.k){var c={},o=function(t,r){e.cI&&(r=r.toLowerCase()),r.split(" ").forEach(function(e){var r=e.split("|");c[r[0]]=[t,r[1]?Number(r[1]):1]})};"string"==typeof a.k?o("keyword",a.k):Object.keys(a.k).forEach(function(e){o(e,a.k[e])}),a.k=c}a.lR=r(a.l||/\b[A-Za-z0-9_]+\b/,!0),s&&(a.bK&&(a.b="\\b("+a.bK.split(" ").join("|")+")\\b"),a.b||(a.b=/\B|\b/),a.bR=r(a.b),a.e||a.eW||(a.e=/\B|\b/),a.e&&(a.eR=r(a.e)),a.tE=t(a.e)||"",a.eW&&s.tE&&(a.tE+=(a.e?"|":"")+s.tE)),a.i&&(a.iR=r(a.i)),void 0===a.r&&(a.r=1),a.c||(a.c=[]);var l=[];a.c.forEach(function(e){e.v?e.v.forEach(function(t){l.push(i(e,t))}):l.push("self"==e?a:e)}),a.c=l,a.c.forEach(function(e){n(e,a)}),a.starts&&n(a.starts,s);var u=a.c.map(function(e){return e.bK?"\\.?("+e.b+")\\.?":e.b}).concat([a.tE,a.i]).map(t).filter(Boolean);a.t=u.length?r(u.join("|"),!0):{exec:function(){return null}}}}n(e)}function l(e,r,a,i){function s(e,t){for(var r=0;r";return i+=e+'">',i+t+s}function f(){if(!k.k)return t(S);var e="",r=0;k.lR.lastIndex=0;for(var n=k.lR.exec(S);n;){e+=t(S.substr(r,n.index-r));var a=b(k,n);a?(E+=a[1],e+=p(a[0],t(n[0]))):e+=t(n[0]),r=k.lR.lastIndex,n=k.lR.exec(S)}return e+t(S.substr(r))}function m(){if(k.sL&&!w[k.sL])return t(S);var e=k.sL?l(k.sL,S,!0,x[k.sL]):u(S);return k.r>0&&(E+=e.r),"continuous"==k.subLanguageMode&&(x[k.sL]=e.top),p(e.language,e.value,!1,!0)}function g(){return void 0!==k.sL?m():f()}function _(e,r){var n=e.cN?p(e.cN,"",!0):"";e.rB?(M+=n,S=""):e.eB?(M+=t(r)+n,S=""):(M+=n,S=r),k=Object.create(e,{parent:{value:k}})}function h(e,r){if(S+=e,void 0===r)return M+=g(),0;var n=s(r,k);if(n)return M+=g(),_(n,r),n.rB?0:r.length;var a=c(k,r);if(a){var i=k;i.rE||i.eE||(S+=r),M+=g();do k.cN&&(M+=""),E+=k.r,k=k.parent;while(k!=a.parent);return i.eE&&(M+=t(r)),S="",a.starts&&_(a.starts,""),i.rE?0:r.length}if(d(r,k))throw new Error('Illegal lexeme "'+r+'" for mode "'+(k.cN||"")+'"');return S+=r,r.length||1}var y=N(e);if(!y)throw new Error('Unknown language: "'+e+'"');o(y);for(var k=i||y,x={},M="",C=k;C!=y;C=C.parent)C.cN&&(M=p(C.cN,"",!0)+M);var S="",E=0;try{for(var B,I,L=0;;){if(k.t.lastIndex=L,B=k.t.exec(r),!B)break;I=h(r.substr(L,B.index-L),B[0]),L=B.index+I}h(r.substr(L));for(var C=k;C.parent;C=C.parent)C.cN&&(M+="");return{r:E,value:M,language:e,top:k}}catch(R){if(-1!=R.message.indexOf("Illegal"))return{r:0,value:t(r)};throw R}}function u(e,r){r=r||v.languages||Object.keys(w);var n={r:0,value:t(e)},a=n;return r.forEach(function(t){if(N(t)){var r=l(t,e,!1);r.language=t,r.r>a.r&&(a=r),r.r>n.r&&(a=n,n=r)}}),a.language&&(n.second_best=a),n}function d(e){return v.tabReplace&&(e=e.replace(/^((<[^>]+>|\t)+)/gm,function(e,t){return t.replace(/\t/g,v.tabReplace)})),v.useBR&&(e=e.replace(/\n/g,"
")),e}function b(e,t,r){var n=t?y[t]:r,a=[e.trim()];return e.match(/(\s|^)hljs(\s|$)/)||a.push("hljs"),n&&a.push(n),a.join(" ").trim()}function p(e){var t=a(e);if(!/no(-?)highlight/.test(t)){var r;v.useBR?(r=document.createElementNS("http://www.w3.org/1999/xhtml","div"),r.innerHTML=e.innerHTML.replace(/\n/g,"").replace(//g,"\n")):r=e;var n=r.textContent,i=t?l(t,n,!0):u(n),o=s(r);if(o.length){var p=document.createElementNS("http://www.w3.org/1999/xhtml","div");p.innerHTML=i.value,i.value=c(o,s(p),n)}i.value=d(i.value),e.innerHTML=i.value,e.className=b(e.className,t,i.language),e.result={language:i.language,re:i.r},i.second_best&&(e.second_best={language:i.second_best.language,re:i.second_best.r})}}function f(e){v=i(v,e)}function m(){if(!m.called){m.called=!0;var e=document.querySelectorAll("pre code");Array.prototype.forEach.call(e,p)}}function g(){addEventListener("DOMContentLoaded",m,!1),addEventListener("load",m,!1)}function _(t,r){var n=w[t]=r(e);n.aliases&&n.aliases.forEach(function(e){y[e]=t})}function h(){return Object.keys(w)}function N(e){return w[e]||w[y[e]]}var v={classPrefix:"hljs-",tabReplace:null,useBR:!1,languages:void 0},w={},y={};return e.highlight=l,e.highlightAuto=u,e.fixMarkup=d,e.highlightBlock=p,e.configure=f,e.initHighlighting=m,e.initHighlightingOnLoad=g,e.registerLanguage=_,e.listLanguages=h,e.getLanguage=N,e.inherit=i,e.IR="[a-zA-Z][a-zA-Z0-9_]*",e.UIR="[a-zA-Z_][a-zA-Z0-9_]*",e.NR="\\b\\d+(\\.\\d+)?",e.CNR="(\\b0[xX][a-fA-F0-9]+|(\\b\\d+(\\.\\d*)?|\\.\\d+)([eE][-+]?\\d+)?)",e.BNR="\\b(0b[01]+)",e.RSR="!|!=|!==|%|%=|&|&&|&=|\\*|\\*=|\\+|\\+=|,|-|-=|/=|/|:|;|<<|<<=|<=|<|===|==|=|>>>=|>>=|>=|>>>|>>|>|\\?|\\[|\\{|\\(|\\^|\\^=|\\||\\|=|\\|\\||~",e.BE={b:"\\\\[\\s\\S]",r:0},e.ASM={cN:"string",b:"'",e:"'",i:"\\n",c:[e.BE]},e.QSM={cN:"string",b:'"',e:'"',i:"\\n",c:[e.BE]},e.PWM={b:/\b(a|an|the|are|I|I'm|isn't|don't|doesn't|won't|but|just|should|pretty|simply|enough|gonna|going|wtf|so|such)\b/},e.CLCM={cN:"comment",b:"//",e:"$",c:[e.PWM]},e.CBCM={cN:"comment",b:"/\\*",e:"\\*/",c:[e.PWM]},e.HCM={cN:"comment",b:"#",e:"$",c:[e.PWM]},e.NM={cN:"number",b:e.NR,r:0},e.CNM={cN:"number",b:e.CNR,r:0},e.BNM={cN:"number",b:e.BNR,r:0},e.CSSNM={cN:"number",b:e.NR+"(%|em|ex|ch|rem|vw|vh|vmin|vmax|cm|mm|in|pt|pc|px|deg|grad|rad|turn|s|ms|Hz|kHz|dpi|dpcm|dppx)?",r:0},e.RM={cN:"regexp",b:/\//,e:/\/[gimuy]*/,i:/\n/,c:[e.BE,{b:/\[/,e:/\]/,r:0,c:[e.BE]}]},e.TM={cN:"title",b:e.IR,r:0},e.UTM={cN:"title",b:e.UIR,r:0},e}),hljs.registerLanguage("apache",function(e){var t={cN:"number",b:"[\\$%]\\d+"};return{aliases:["apacheconf"],cI:!0,c:[e.HCM,{cN:"tag",b:""},{cN:"keyword",b:/\w+/,r:0,k:{common:"order deny allow setenv rewriterule rewriteengine rewritecond documentroot sethandler errordocument loadmodule options header listen serverroot servername"},starts:{e:/$/,r:0,k:{literal:"on off all"},c:[{cN:"sqbracket",b:"\\s\\[",e:"\\]$"},{cN:"cbracket",b:"[\\$%]\\{",e:"\\}",c:["self",t]},t,e.QSM]}}],i:/\S/}}),hljs.registerLanguage("bash",function(e){var t={cN:"variable",v:[{b:/\$[\w\d#@][\w\d_]*/},{b:/\$\{(.*?)\}/}]},r={cN:"string",b:/"/,e:/"/,c:[e.BE,t,{cN:"variable",b:/\$\(/,e:/\)/,c:[e.BE]}]},n={cN:"string",b:/'/,e:/'/};return{aliases:["sh","zsh"],l:/-?[a-z\.]+/,k:{keyword:"if then else elif fi for while in do done case esac function",literal:"true false",built_in:"break cd continue eval exec exit export getopts hash pwd readonly return shift test times trap umask unset alias bind builtin caller command declare echo enable help let local logout mapfile printf read readarray source type typeset ulimit unalias set shopt autoload bg bindkey bye cap chdir clone comparguments compcall compctl compdescribe compfiles compgroups compquote comptags comptry compvalues dirs disable disown echotc echoti emulate fc fg float functions getcap getln history integer jobs kill limit log noglob popd print pushd pushln rehash sched setcap setopt stat suspend ttyctl unfunction unhash unlimit unsetopt vared wait whence where which zcompile zformat zftp zle zmodload zparseopts zprof zpty zregexparse zsocket zstyle ztcp",operator:"-ne -eq -lt -gt -f -d -e -s -l -a"},c:[{cN:"shebang",b:/^#![^\n]+sh\s*$/,r:10},{cN:"function",b:/\w[\w\d_]*\s*\(\s*\)\s*\{/,rB:!0,c:[e.inherit(e.TM,{b:/\w[\w\d_]*/})],r:0},e.HCM,e.NM,r,n,t]}}),hljs.registerLanguage("coffeescript",function(e){var t={keyword:"in if for while finally new do return else break catch instanceof throw try this switch continue typeof delete debugger super then unless until loop of by when and or is isnt not",literal:"true false null undefined yes no on off",reserved:"case default function var void with const let enum export import native __hasProp __extends __slice __bind __indexOf",built_in:"npm require console print module global window document"},r="[A-Za-z$_][0-9A-Za-z$_]*",n={cN:"subst",b:/#\{/,e:/}/,k:t},a=[e.BNM,e.inherit(e.CNM,{starts:{e:"(\\s*/)?",r:0}}),{cN:"string",v:[{b:/'''/,e:/'''/,c:[e.BE]},{b:/'/,e:/'/,c:[e.BE]},{b:/"""/,e:/"""/,c:[e.BE,n]},{b:/"/,e:/"/,c:[e.BE,n]}]},{cN:"regexp",v:[{b:"///",e:"///",c:[n,e.HCM]},{b:"//[gim]*",r:0},{b:/\/(?![ *])(\\\/|.)*?\/[gim]*(?=\W|$)/}]},{cN:"property",b:"@"+r},{b:"`",e:"`",eB:!0,eE:!0,sL:"javascript"}];n.c=a;var i=e.inherit(e.TM,{b:r}),s="(\\(.*\\))?\\s*\\B[-=]>",c={cN:"params",b:"\\([^\\(]",rB:!0,c:[{b:/\(/,e:/\)/,k:t,c:["self"].concat(a)}]};return{aliases:["coffee","cson","iced"],k:t,i:/\/\*/,c:a.concat([{cN:"comment",b:"###",e:"###",c:[e.PWM]},e.HCM,{cN:"function",b:"^\\s*"+r+"\\s*=\\s*"+s,e:"[-=]>",rB:!0,c:[i,c]},{b:/[:\(,=]\s*/,r:0,c:[{cN:"function",b:s,e:"[-=]>",rB:!0,c:[c]}]},{cN:"class",bK:"class",e:"$",i:/[:="\[\]]/,c:[{bK:"extends",eW:!0,i:/[:="\[\]]/,c:[i]},i]},{cN:"attribute",b:r+":",e:":",rB:!0,rE:!0,r:0}])}}),hljs.registerLanguage("cpp",function(e){var t={keyword:"false int float while private char catch export virtual operator sizeof dynamic_cast|10 typedef const_cast|10 const struct for static_cast|10 union namespace unsigned long volatile static protected bool template mutable if public friend do goto auto void enum else break extern using true class asm case typeid short reinterpret_cast|10 default double register explicit signed typename try this switch continue wchar_t inline delete alignof char16_t char32_t constexpr decltype noexcept nullptr static_assert thread_local restrict _Bool complex _Complex _Imaginaryintmax_t uintmax_t int8_t uint8_t int16_t uint16_t int32_t uint32_t int64_t uint64_tint_least8_t uint_least8_t int_least16_t uint_least16_t int_least32_t uint_least32_tint_least64_t uint_least64_t int_fast8_t uint_fast8_t int_fast16_t uint_fast16_t int_fast32_tuint_fast32_t int_fast64_t uint_fast64_t intptr_t uintptr_t atomic_bool atomic_char atomic_scharatomic_uchar atomic_short atomic_ushort atomic_int atomic_uint atomic_long atomic_ulong atomic_llongatomic_ullong atomic_wchar_t atomic_char16_t atomic_char32_t atomic_intmax_t atomic_uintmax_tatomic_intptr_t atomic_uintptr_t atomic_size_t atomic_ptrdiff_t atomic_int_least8_t atomic_int_least16_tatomic_int_least32_t atomic_int_least64_t atomic_uint_least8_t atomic_uint_least16_t atomic_uint_least32_tatomic_uint_least64_t atomic_int_fast8_t atomic_int_fast16_t atomic_int_fast32_t atomic_int_fast64_tatomic_uint_fast8_t atomic_uint_fast16_t atomic_uint_fast32_t atomic_uint_fast64_t",built_in:"std string cin cout cerr clog stringstream istringstream ostringstream auto_ptr deque list queue stack vector map set bitset multiset multimap unordered_set unordered_map unordered_multiset unordered_multimap array shared_ptr abort abs acos asin atan2 atan calloc ceil cosh cos exit exp fabs floor fmod fprintf fputs free frexp fscanf isalnum isalpha iscntrl isdigit isgraph islower isprint ispunct isspace isupper isxdigit tolower toupper labs ldexp log10 log malloc memchr memcmp memcpy memset modf pow printf putchar puts scanf sinh sin snprintf sprintf sqrt sscanf strcat strchr strcmp strcpy strcspn strlen strncat strncmp strncpy strpbrk strrchr strspn strstr tanh tan vfprintf vprintf vsprintf"};return{aliases:["c","h","c++","h++"],k:t,i:""]',k:"include",i:"\\n"},e.CLCM]},{cN:"stl_container",b:"\\b(deque|list|queue|stack|vector|map|set|bitset|multiset|multimap|unordered_map|unordered_set|unordered_multiset|unordered_multimap|array)\\s*<",e:">",k:t,c:["self"]},{b:e.IR+"::"},{bK:"new throw return",r:0},{cN:"function",b:"("+e.IR+"\\s+)+"+e.IR+"\\s*\\(",rB:!0,e:/[{;=]/,eE:!0,k:t,c:[{b:e.IR+"\\s*\\(",rB:!0,c:[e.TM],r:0},{cN:"params",b:/\(/,e:/\)/,k:t,r:0,c:[e.CBCM]},e.CLCM,e.CBCM]}]}}),hljs.registerLanguage("cs",function(e){var t="abstract as base bool break byte case catch char checked const continue decimal default delegate do double else enum event explicit extern false finally fixed float for foreach goto if implicit in int interface internal is lock long null object operator out override params private protected public readonly ref sbyte sealed short sizeof stackalloc static string struct switch this true try typeof uint ulong unchecked unsafe ushort using virtual volatile void while async protected public private internal ascending descending from get group into join let orderby partial select set value var where yield",r=e.IR+"(<"+e.IR+">)?";return{aliases:["csharp"],k:t,i:/::/,c:[{cN:"comment",b:"///",e:"$",rB:!0,c:[{cN:"xmlDocTag",v:[{b:"///",r:0},{b:""},{b:""}]}]},e.CLCM,e.CBCM,{cN:"preprocessor",b:"#",e:"$",k:"if else elif endif define undef warning error line region endregion pragma checksum"},{cN:"string",b:'@"',e:'"',c:[{b:'""'}]},e.ASM,e.QSM,e.CNM,{bK:"class namespace interface",e:/[{;=]/,i:/[^\s:]/,c:[e.TM,e.CLCM,e.CBCM]},{bK:"new return throw await",r:0},{cN:"function",b:"("+r+"\\s+)+"+e.IR+"\\s*\\(",rB:!0,e:/[{;=]/,eE:!0,k:t,c:[{b:e.IR+"\\s*\\(",rB:!0,c:[e.TM],r:0},{cN:"params",b:/\(/,e:/\)/,k:t,r:0,c:[e.ASM,e.QSM,e.CNM,e.CBCM]},e.CLCM,e.CBCM]}]}}),hljs.registerLanguage("css",function(e){var t="[a-zA-Z-][a-zA-Z0-9_-]*",r={cN:"function",b:t+"\\(",rB:!0,eE:!0,e:"\\("};return{cI:!0,i:"[=/|']",c:[e.CBCM,{cN:"id",b:"\\#[A-Za-z0-9_-]+"},{cN:"class",b:"\\.[A-Za-z0-9_-]+",r:0},{cN:"attr_selector",b:"\\[",e:"\\]",i:"$"},{cN:"pseudo",b:":(:)?[a-zA-Z0-9\\_\\-\\+\\(\\)\\\"\\']+"},{cN:"at_rule",b:"@(font-face|page)",l:"[a-z-]+",k:"font-face page"},{cN:"at_rule",b:"@",e:"[{;]",c:[{cN:"keyword",b:/\S+/},{b:/\s/,eW:!0,eE:!0,r:0,c:[r,e.ASM,e.QSM,e.CSSNM]}]},{cN:"tag",b:t,r:0},{cN:"rules",b:"{",e:"}",i:"[^\\s]",r:0,c:[e.CBCM,{cN:"rule",b:"[^\\s]",rB:!0,e:";",eW:!0,c:[{cN:"attribute",b:"[A-Z\\_\\.\\-]+",e:":",eE:!0,i:"[^\\s]",starts:{cN:"value",eW:!0,eE:!0,c:[r,e.CSSNM,e.QSM,e.ASM,e.CBCM,{cN:"hexcolor",b:"#[0-9A-Fa-f]+"},{cN:"important",b:"!important"}]}}]}]}]}}),hljs.registerLanguage("diff",function(){return{aliases:["patch"],c:[{cN:"chunk",r:10,v:[{b:/^\@\@ +\-\d+,\d+ +\+\d+,\d+ +\@\@$/},{b:/^\*\*\* +\d+,\d+ +\*\*\*\*$/},{b:/^\-\-\- +\d+,\d+ +\-\-\-\-$/}]},{cN:"header",v:[{b:/Index: /,e:/$/},{b:/=====/,e:/=====$/},{b:/^\-\-\-/,e:/$/},{b:/^\*{3} /,e:/$/},{b:/^\+\+\+/,e:/$/},{b:/\*{5}/,e:/\*{5}$/}]},{cN:"addition",b:"^\\+",e:"$"},{cN:"deletion",b:"^\\-",e:"$"},{cN:"change",b:"^\\!",e:"$"}]}}),hljs.registerLanguage("http",function(){return{i:"\\S",c:[{cN:"status",b:"^HTTP/[0-9\\.]+",e:"$",c:[{cN:"number",b:"\\b\\d{3}\\b"}]},{cN:"request",b:"^[A-Z]+ (.*?) HTTP/[0-9\\.]+$",rB:!0,e:"$",c:[{cN:"string",b:" ",e:" ",eB:!0,eE:!0}]},{cN:"attribute",b:"^\\w",e:": ",eE:!0,i:"\\n|\\s|=",starts:{cN:"string",e:"$"}},{b:"\\n\\n",starts:{sL:"",eW:!0}}]}}),hljs.registerLanguage("ini",function(e){return{cI:!0,i:/\S/,c:[{cN:"comment",b:";",e:"$"},{cN:"title",b:"^\\[",e:"\\]"},{cN:"setting",b:"^[a-z0-9\\[\\]_-]+[ \\t]*=[ \\t]*",e:"$",c:[{cN:"value",eW:!0,k:"on off true false yes no",c:[e.QSM,e.NM],r:0}]}]}}),hljs.registerLanguage("java",function(e){var t=e.UIR+"(<"+e.UIR+">)?",r="false synchronized int abstract float private char boolean static null if const for true while long strictfp finally protected import native final void enum else break transient catch instanceof byte super volatile case assert short package default double public try this switch continue throws protected public private",n="(\\b(0b[01_]+)|\\b0[xX][a-fA-F0-9_]+|(\\b[\\d_]+(\\.[\\d_]*)?|\\.[\\d_]+)([eE][-+]?\\d+)?)[lLfF]?",a={cN:"number",b:n,r:0};return{aliases:["jsp"],k:r,i:/<\//,c:[{cN:"javadoc",b:"/\\*\\*",e:"\\*/",r:0,c:[{cN:"javadoctag",b:"(^|\\s)@[A-Za-z]+"}]},e.CLCM,e.CBCM,e.ASM,e.QSM,{cN:"class",bK:"class interface",e:/[{;=]/,eE:!0,k:"class interface",i:/[:"\[\]]/,c:[{bK:"extends implements"},e.UTM]},{bK:"new throw return",r:0},{cN:"function",b:"("+t+"\\s+)+"+e.UIR+"\\s*\\(",rB:!0,e:/[{;=]/,eE:!0,k:r,c:[{b:e.UIR+"\\s*\\(",rB:!0,r:0,c:[e.UTM]},{cN:"params",b:/\(/,e:/\)/,k:r,r:0,c:[e.ASM,e.QSM,e.CNM,e.CBCM]},e.CLCM,e.CBCM]},a,{cN:"annotation",b:"@[A-Za-z]+"}]}}),hljs.registerLanguage("javascript",function(e){return{aliases:["js"],k:{keyword:"in if for while finally var new function do return void else break catch instanceof with throw case default try this switch continue typeof delete let yield const class",literal:"true false null undefined NaN Infinity",built_in:"eval isFinite isNaN parseFloat parseInt decodeURI decodeURIComponent encodeURI encodeURIComponent escape unescape Object Function Boolean Error EvalError InternalError RangeError ReferenceError StopIteration SyntaxError TypeError URIError Number Math Date String RegExp Array Float32Array Float64Array Int16Array Int32Array Int8Array Uint16Array Uint32Array Uint8Array Uint8ClampedArray ArrayBuffer DataView JSON Intl arguments require module console window document"},c:[{cN:"pi",r:10,v:[{b:/^\s*('|")use strict('|")/},{b:/^\s*('|")use asm('|")/}]},e.ASM,e.QSM,e.CLCM,e.CBCM,e.CNM,{b:"("+e.RSR+"|\\b(case|return|throw)\\b)\\s*",k:"return throw case",c:[e.CLCM,e.CBCM,e.RM,{b:/;/,r:0,sL:"xml"}],r:0},{cN:"function",bK:"function",e:/\{/,eE:!0,c:[e.inherit(e.TM,{b:/[A-Za-z$_][0-9A-Za-z$_]*/}),{cN:"params",b:/\(/,e:/\)/,c:[e.CLCM,e.CBCM],i:/["'\(]/}],i:/\[|%/},{b:/\$[(.]/},{b:"\\."+e.IR,r:0}]}}),hljs.registerLanguage("json",function(e){var t={literal:"true false null"},r=[e.QSM,e.CNM],n={cN:"value",e:",",eW:!0,eE:!0,c:r,k:t},a={b:"{",e:"}",c:[{cN:"attribute",b:'\\s*"',e:'"\\s*:\\s*',eB:!0,eE:!0,c:[e.BE],i:"\\n",starts:n}],i:"\\S"},i={b:"\\[",e:"\\]",c:[e.inherit(n,{cN:null})],i:"\\S"};return r.splice(r.length,0,a,i),{c:r,k:t,i:"\\S"}}),hljs.registerLanguage("makefile",function(e){var t={cN:"variable",b:/\$\(/,e:/\)/,c:[e.BE]};return{aliases:["mk","mak"],c:[e.HCM,{b:/^\w+\s*\W*=/,rB:!0,r:0,starts:{cN:"constant",e:/\s*\W*=/,eE:!0,starts:{e:/$/,r:0,c:[t]}}},{cN:"title",b:/^[\w]+:\s*$/},{cN:"phony",b:/^\.PHONY:/,e:/$/,k:".PHONY",l:/[\.\w]+/},{b:/^\t+/,e:/$/,r:0,c:[e.QSM,t]}]}}),hljs.registerLanguage("xml",function(){var e="[A-Za-z0-9\\._:-]+",t={b:/<\?(php)?(?!\w)/,e:/\?>/,sL:"php",subLanguageMode:"continuous"},r={eW:!0,i:/]+/}]}]}]};return{aliases:["html","xhtml","rss","atom","xsl","plist"],cI:!0,c:[{cN:"doctype",b:"",r:10,c:[{b:"\\[",e:"\\]"}]},{cN:"comment",b:"",r:10},{cN:"cdata",b:"<\\!\\[CDATA\\[",e:"\\]\\]>",r:10},{cN:"tag",b:"|$)",e:">",k:{title:"style"},c:[r],starts:{e:"",rE:!0,sL:"css"}},{cN:"tag",b:"|$)",e:">",k:{title:"script"},c:[r],starts:{e:"",rE:!0,sL:"javascript"}},t,{cN:"pi",b:/<\?\w+/,e:/\?>/,r:10},{cN:"tag",b:"",c:[{cN:"title",b:/[^ \/><\n\t]+/,r:0},r]}]}}),hljs.registerLanguage("markdown",function(){return{aliases:["md","mkdown","mkd"],c:[{cN:"header",v:[{b:"^#{1,6}",e:"$"},{b:"^.+?\\n[=-]{2,}$"}]},{b:"<",e:">",sL:"xml",r:0},{cN:"bullet",b:"^([*+-]|(\\d+\\.))\\s+"},{cN:"strong",b:"[*_]{2}.+?[*_]{2}"},{cN:"emphasis",v:[{b:"\\*.+?\\*"},{b:"_.+?_",r:0}]},{cN:"blockquote",b:"^>\\s+",e:"$"},{cN:"code",v:[{b:"`.+?`"},{b:"^( {4}| )",e:"$",r:0}]},{cN:"horizontal_rule",b:"^[-\\*]{3,}",e:"$"},{b:"\\[.+?\\][\\(\\[].*?[\\)\\]]",rB:!0,c:[{cN:"link_label",b:"\\[",e:"\\]",eB:!0,rE:!0,r:0},{cN:"link_url",b:"\\]\\(",e:"\\)",eB:!0,eE:!0},{cN:"link_reference",b:"\\]\\[",e:"\\]",eB:!0,eE:!0}],r:10},{b:"^\\[.+\\]:",rB:!0,c:[{cN:"link_reference",b:"\\[",e:"\\]:",eB:!0,eE:!0,starts:{cN:"link_url",e:"$"}}]}]}}),hljs.registerLanguage("nginx",function(e){var t={cN:"variable",v:[{b:/\$\d+/},{b:/\$\{/,e:/}/},{b:"[\\$\\@]"+e.UIR}]},r={eW:!0,l:"[a-z/_]+",k:{built_in:"on off yes no true false none blocked debug info notice warn error crit select break last permanent redirect kqueue rtsig epoll poll /dev/poll"},r:0,i:"=>",c:[e.HCM,{cN:"string",c:[e.BE,t],v:[{b:/"/,e:/"/},{b:/'/,e:/'/}]},{cN:"url",b:"([a-z]+):/",e:"\\s",eW:!0,eE:!0,c:[t]},{cN:"regexp",c:[e.BE,t],v:[{b:"\\s\\^",e:"\\s|{|;",rE:!0},{b:"~\\*?\\s+",e:"\\s|{|;",rE:!0},{b:"\\*(\\.[a-z\\-]+)+"},{b:"([a-z\\-]+\\.)+\\*"}]},{cN:"number",b:"\\b\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}(:\\d{1,5})?\\b"},{cN:"number",b:"\\b\\d+[kKmMgGdshdwy]*\\b",r:0},t]};return{aliases:["nginxconf"],c:[e.HCM,{b:e.UIR+"\\s",e:";|{",rB:!0,c:[{cN:"title",b:e.UIR,starts:r}],r:0}],i:"[^\\s\\}]"}}),hljs.registerLanguage("objectivec",function(e){var t={keyword:"int float while char export sizeof typedef const struct for union unsigned long volatile static bool mutable if do return goto void enum else break extern asm case short default double register explicit signed typename this switch continue wchar_t inline readonly assign readwrite self @synchronized id typeof nonatomic super unichar IBOutlet IBAction strong weak copy in out inout bycopy byref oneway __strong __weak __block __autoreleasing @private @protected @public @try @property @end @throw @catch @finally @autoreleasepool @synthesize @dynamic @selector @optional @required",literal:"false true FALSE TRUE nil YES NO NULL",built_in:"NSString NSData NSDictionary CGRect CGPoint UIButton UILabel UITextView UIWebView MKMapView NSView NSViewController NSWindow NSWindowController NSSet NSUUID NSIndexSet UISegmentedControl NSObject UITableViewDelegate UITableViewDataSource NSThread UIActivityIndicator UITabbar UIToolBar UIBarButtonItem UIImageView NSAutoreleasePool UITableView BOOL NSInteger CGFloat NSException NSLog NSMutableString NSMutableArray NSMutableDictionary NSURL NSIndexPath CGSize UITableViewCell UIView UIViewController UINavigationBar UINavigationController UITabBarController UIPopoverController UIPopoverControllerDelegate UIImage NSNumber UISearchBar NSFetchedResultsController NSFetchedResultsChangeType UIScrollView UIScrollViewDelegate UIEdgeInsets UIColor UIFont UIApplication NSNotFound NSNotificationCenter NSNotification UILocalNotification NSBundle NSFileManager NSTimeInterval NSDate NSCalendar NSUserDefaults UIWindow NSRange NSArray NSError NSURLRequest NSURLConnection NSURLSession NSURLSessionDataTask NSURLSessionDownloadTask NSURLSessionUploadTask NSURLResponseUIInterfaceOrientation MPMoviePlayerController dispatch_once_t dispatch_queue_t dispatch_sync dispatch_async dispatch_once"},r=/[a-zA-Z@][a-zA-Z0-9_]*/,n="@interface @class @protocol @implementation";return{aliases:["m","mm","objc","obj-c"],k:t,l:r,i:""}]}]},{cN:"class",b:"("+n.split(" ").join("|")+")\\b",e:"({|$)",eE:!0,k:n,l:r,c:[e.UTM]},{cN:"variable",b:"\\."+e.UIR,r:0}]}}),hljs.registerLanguage("perl",function(e){var t="getpwent getservent quotemeta msgrcv scalar kill dbmclose undef lc ma syswrite tr send umask sysopen shmwrite vec qx utime local oct semctl localtime readpipe do return format read sprintf dbmopen pop getpgrp not getpwnam rewinddir qqfileno qw endprotoent wait sethostent bless s|0 opendir continue each sleep endgrent shutdown dump chomp connect getsockname die socketpair close flock exists index shmgetsub for endpwent redo lstat msgctl setpgrp abs exit select print ref gethostbyaddr unshift fcntl syscall goto getnetbyaddr join gmtime symlink semget splice x|0 getpeername recv log setsockopt cos last reverse gethostbyname getgrnam study formline endhostent times chop length gethostent getnetent pack getprotoent getservbyname rand mkdir pos chmod y|0 substr endnetent printf next open msgsnd readdir use unlink getsockopt getpriority rindex wantarray hex system getservbyport endservent int chr untie rmdir prototype tell listen fork shmread ucfirst setprotoent else sysseek link getgrgid shmctl waitpid unpack getnetbyname reset chdir grep split require caller lcfirst until warn while values shift telldir getpwuid my getprotobynumber delete and sort uc defined srand accept package seekdir getprotobyname semop our rename seek if q|0 chroot sysread setpwent no crypt getc chown sqrt write setnetent setpriority foreach tie sin msgget map stat getlogin unless elsif truncate exec keys glob tied closedirioctl socket readlink eval xor readline binmode setservent eof ord bind alarm pipe atan2 getgrent exp time push setgrent gt lt or ne m|0 break given say state when",r={cN:"subst",b:"[$@]\\{",e:"\\}",k:t},n={b:"->{",e:"}"},a={cN:"variable",v:[{b:/\$\d/},{b:/[\$\%\@](\^\w\b|#\w+(\:\:\w+)*|{\w+}|\w+(\:\:\w*)*)/},{b:/[\$\%\@][^\s\w{]/,r:0}]},i={cN:"comment",b:"^(__END__|__DATA__)",e:"\\n$",r:5},s=[e.BE,r,a],c=[a,e.HCM,i,{cN:"comment",b:"^\\=\\w",e:"\\=cut",eW:!0},n,{cN:"string",c:s,v:[{b:"q[qwxr]?\\s*\\(",e:"\\)",r:5},{b:"q[qwxr]?\\s*\\[",e:"\\]",r:5},{b:"q[qwxr]?\\s*\\{",e:"\\}",r:5},{b:"q[qwxr]?\\s*\\|",e:"\\|",r:5},{b:"q[qwxr]?\\s*\\<",e:"\\>",r:5},{b:"qw\\s+q",e:"q",r:5},{b:"'",e:"'",c:[e.BE]},{b:'"',e:'"'},{b:"`",e:"`",c:[e.BE]},{b:"{\\w+}",c:[],r:0},{b:"-?\\w+\\s*\\=\\>",c:[],r:0}]},{cN:"number",b:"(\\b0[0-7_]+)|(\\b0x[0-9a-fA-F_]+)|(\\b[1-9][0-9_]*(\\.[0-9_]+)?)|[0_]\\b",r:0},{b:"(\\/\\/|"+e.RSR+"|\\b(split|return|print|reverse|grep)\\b)\\s*",k:"split return print reverse grep",r:0,c:[e.HCM,i,{cN:"regexp",b:"(s|tr|y)/(\\\\.|[^/])*/(\\\\.|[^/])*/[a-z]*",r:10},{cN:"regexp",b:"(m|qr)?/",e:"/[a-z]*",c:[e.BE],r:0}]},{cN:"sub",bK:"sub",e:"(\\s*\\(.*?\\))?[;{]",r:5},{cN:"operator",b:"-\\w\\b",r:0}];return r.c=c,n.c=c,{aliases:["pl"],k:t,c:c}}),hljs.registerLanguage("php",function(e){var t={cN:"variable",b:"\\$+[a-zA-Z_-ÿ][a-zA-Z0-9_-ÿ]*"},r={cN:"preprocessor",b:/<\?(php)?|\?>/},n={cN:"string",c:[e.BE,r],v:[{b:'b"',e:'"'},{b:"b'",e:"'"},e.inherit(e.ASM,{i:null}),e.inherit(e.QSM,{i:null})]},a={v:[e.BNM,e.CNM]};return{aliases:["php3","php4","php5","php6"],cI:!0,k:"and include_once list abstract global private echo interface as static endswitch array null if endwhile or const for endforeach self var while isset public protected exit foreach throw elseif include __FILE__ empty require_once do xor return parent clone use __CLASS__ __LINE__ else break print eval new catch __METHOD__ case exception default die require __FUNCTION__ enddeclare final try switch continue endfor endif declare unset true false trait goto instanceof insteadof __DIR__ __NAMESPACE__ yield finally",c:[e.CLCM,e.HCM,{cN:"comment",b:"/\\*",e:"\\*/",c:[{cN:"phpdoc",b:"\\s@[A-Za-z]+"},r]},{cN:"comment",b:"__halt_compiler.+?;",eW:!0,k:"__halt_compiler",l:e.UIR},{cN:"string",b:"<<<['\"]?\\w+['\"]?$",e:"^\\w+;",c:[e.BE]},r,t,{b:/->+[a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*/},{cN:"function",bK:"function",e:/[;{]/,eE:!0,i:"\\$|\\[|%",c:[e.UTM,{cN:"params",b:"\\(",e:"\\)",c:["self",t,e.CBCM,n,a]}]},{cN:"class",bK:"class interface",e:"{",eE:!0,i:/[:\(\$"]/,c:[{bK:"extends implements"},e.UTM]},{bK:"namespace",e:";",i:/[\.']/,c:[e.UTM]},{bK:"use",e:";",c:[e.UTM]},{b:"=>"},n,a]}}),hljs.registerLanguage("python",function(e){var t={cN:"prompt",b:/^(>>>|\.\.\.) /},r={cN:"string",c:[e.BE],v:[{b:/(u|b)?r?'''/,e:/'''/,c:[t],r:10},{b:/(u|b)?r?"""/,e:/"""/,c:[t],r:10},{b:/(u|r|ur)'/,e:/'/,r:10},{b:/(u|r|ur)"/,e:/"/,r:10},{b:/(b|br)'/,e:/'/},{b:/(b|br)"/,e:/"/},e.ASM,e.QSM]},n={cN:"number",r:0,v:[{b:e.BNR+"[lLjJ]?"},{b:"\\b(0o[0-7]+)[lLjJ]?"},{b:e.CNR+"[lLjJ]?"}]},a={cN:"params",b:/\(/,e:/\)/,c:["self",t,n,r]};return{aliases:["py","gyp"],k:{keyword:"and elif is global as in if from raise for except finally print import pass return exec else break not with class assert yield try while continue del or def lambda nonlocal|10 None True False",built_in:"Ellipsis NotImplemented"},i:/(<\/|->|\?)/,c:[t,n,r,e.HCM,{v:[{cN:"function",bK:"def",r:10},{cN:"class",bK:"class"}],e:/:/,i:/[${=;\n]/,c:[e.UTM,a]},{cN:"decorator",b:/@/,e:/$/},{b:/\b(print|exec)\(/}]}}),hljs.registerLanguage("ruby",function(e){var t="[a-zA-Z_]\\w*[!?=]?|[-+~]\\@|<<|>>|=~|===?|<=>|[<>]=?|\\*\\*|[-/+%^&*~`|]|\\[\\]=?",r="and false then defined module in return redo if BEGIN retry end for true self when next until do begin unless END rescue nil else break undef not super class case require yield alias while ensure elsif or include attr_reader attr_writer attr_accessor",n={cN:"yardoctag",b:"@[A-Za-z]+"},a={cN:"value",b:"#<",e:">"},i={cN:"comment",v:[{b:"#",e:"$",c:[n]},{b:"^\\=begin",e:"^\\=end",c:[n],r:10},{b:"^__END__",e:"\\n$"}]},s={cN:"subst",b:"#\\{",e:"}",k:r},c={cN:"string",c:[e.BE,s],v:[{b:/'/,e:/'/},{b:/"/,e:/"/},{b:/`/,e:/`/},{b:"%[qQwWx]?\\(",e:"\\)"},{b:"%[qQwWx]?\\[",e:"\\]"},{b:"%[qQwWx]?{",e:"}"},{b:"%[qQwWx]?<",e:">"},{b:"%[qQwWx]?/",e:"/"},{b:"%[qQwWx]?%",e:"%"},{b:"%[qQwWx]?-",e:"-"},{b:"%[qQwWx]?\\|",e:"\\|"},{b:/\B\?(\\\d{1,3}|\\x[A-Fa-f0-9]{1,2}|\\u[A-Fa-f0-9]{4}|\\?\S)\b/}]},o={cN:"params",b:"\\(",e:"\\)",k:r},l=[c,a,i,{cN:"class",bK:"class module",e:"$|;",i:/=/,c:[e.inherit(e.TM,{b:"[A-Za-z_]\\w*(::\\w+)*(\\?|\\!)?"}),{cN:"inheritance",b:"<\\s*",c:[{cN:"parent",b:"("+e.IR+"::)?"+e.IR}]},i]},{cN:"function",bK:"def",e:" |$|;",r:0,c:[e.inherit(e.TM,{b:t}),o,i]},{cN:"constant",b:"(::)?(\\b[A-Z]\\w*(::)?)+",r:0},{cN:"symbol",b:e.UIR+"(\\!|\\?)?:",r:0},{cN:"symbol",b:":",c:[c,{b:t}],r:0},{cN:"number",b:"(\\b0[0-7_]+)|(\\b0x[0-9a-fA-F_]+)|(\\b[1-9][0-9_]*(\\.[0-9_]+)?)|[0_]\\b",r:0},{cN:"variable",b:"(\\$\\W)|((\\$|\\@\\@?)(\\w+))"},{b:"("+e.RSR+")\\s*",c:[a,i,{cN:"regexp",c:[e.BE,s],i:/\n/,v:[{b:"/",e:"/[a-z]*"},{b:"%r{",e:"}[a-z]*"},{b:"%r\\(",e:"\\)[a-z]*"},{b:"%r!",e:"![a-z]*"},{b:"%r\\[",e:"\\][a-z]*"}]}],r:0}];s.c=l,o.c=l;var u="[>?]>",d="[\\w#]+\\(\\w+\\):\\d+:\\d+>",b="(\\w+-)?\\d+\\.\\d+\\.\\d(p\\d+)?[^>]+>",p=[{b:/^\s*=>/,cN:"status",starts:{e:"$",c:l}},{cN:"prompt",b:"^("+u+"|"+d+"|"+b+")",starts:{e:"$",c:l}}];return{aliases:["rb","gemspec","podspec","thor","irb"],k:r,c:[i].concat(p).concat(l)}}),hljs.registerLanguage("sql",function(e){var t={cN:"comment",b:"--",e:"$"};return{cI:!0,i:/[<>]/,c:[{cN:"operator",bK:"begin end start commit rollback savepoint lock alter create drop rename call delete do handler insert load replace select truncate update set show pragma grant merge describe use explain help declare prepare execute deallocate savepoint release unlock purge reset change stop analyze cache flush optimize repair kill install uninstall checksum restore check backup",e:/;/,eW:!0,k:{keyword:"abs absolute acos action add adddate addtime aes_decrypt aes_encrypt after aggregate all allocate alter analyze and any are as asc ascii asin assertion at atan atan2 atn2 authorization authors avg backup before begin benchmark between bin binlog bit_and bit_count bit_length bit_or bit_xor both by cache call cascade cascaded case cast catalog ceil ceiling chain change changed char_length character_length charindex charset check checksum checksum_agg choose close coalesce coercibility collate collation collationproperty column columns columns_updated commit compress concat concat_ws concurrent connect connection connection_id consistent constraint constraints continue contributors conv convert convert_tz corresponding cos cot count count_big crc32 create cross cume_dist curdate current current_date current_time current_timestamp current_user cursor curtime data database databases datalength date_add date_format date_sub dateadd datediff datefromparts datename datepart datetime2fromparts datetimeoffsetfromparts day dayname dayofmonth dayofweek dayofyear deallocate declare decode default deferrable deferred degrees delayed delete des_decrypt des_encrypt des_key_file desc describe descriptor diagnostics difference disconnect distinct distinctrow div do domain double drop dumpfile each else elt enclosed encode encrypt end end-exec engine engines eomonth errors escape escaped event eventdata events except exception exec execute exists exp explain export_set extended external extract fast fetch field fields find_in_set first first_value floor flush for force foreign format found found_rows from from_base64 from_days from_unixtime full function get get_format get_lock getdate getutcdate global go goto grant grants greatest group group_concat grouping grouping_id gtid_subset gtid_subtract handler having help hex high_priority hosts hour ident_current ident_incr ident_seed identified identity if ifnull ignore iif ilike immediate in index indicator inet6_aton inet6_ntoa inet_aton inet_ntoa infile initially inner innodb input insert install instr intersect into is is_free_lock is_ipv4 is_ipv4_compat is_ipv4_mapped is_not is_not_null is_used_lock isdate isnull isolation join key kill language last last_day last_insert_id last_value lcase lead leading least leaves left len lenght level like limit lines ln load load_file local localtime localtimestamp locate lock log log10 log2 logfile logs low_priority lower lpad ltrim make_set makedate maketime master master_pos_wait match matched max md5 medium merge microsecond mid min minute mod mode module month monthname mutex name_const names national natural nchar next no no_write_to_binlog not now nullif nvarchar oct octet_length of old_password on only open optimize option optionally or ord order outer outfile output pad parse partial partition password patindex percent_rank percentile_cont percentile_disc period_add period_diff pi plugin position pow power pragma precision prepare preserve primary prior privileges procedure procedure_analyze processlist profile profiles public publishingservername purge quarter query quick quote quotename radians rand read references regexp relative relaylog release release_lock rename repair repeat replace replicate reset restore restrict return returns reverse revoke right rlike rollback rollup round row row_count rows rpad rtrim savepoint schema scroll sec_to_time second section select serializable server session session_user set sha sha1 sha2 share show sign sin size slave sleep smalldatetimefromparts snapshot some soname soundex sounds_like space sql sql_big_result sql_buffer_result sql_cache sql_calc_found_rows sql_no_cache sql_small_result sql_variant_property sqlstate sqrt square start starting status std stddev stddev_pop stddev_samp stdev stdevp stop str str_to_date straight_join strcmp string stuff subdate substr substring subtime subtring_index sum switchoffset sysdate sysdatetime sysdatetimeoffset system_user sysutcdatetime table tables tablespace tan temporary terminated tertiary_weights then time time_format time_to_sec timediff timefromparts timestamp timestampadd timestampdiff timezone_hour timezone_minute to to_base64 to_days to_seconds todatetimeoffset trailing transaction translation trigger trigger_nestlevel triggers trim truncate try_cast try_convert try_parse ucase uncompress uncompressed_length unhex unicode uninstall union unique unix_timestamp unknown unlock update upgrade upped upper usage use user user_resources using utc_date utc_time utc_timestamp uuid uuid_short validate_password_strength value values var var_pop var_samp variables variance varp version view warnings week weekday weekofyear weight_string when whenever where with work write xml xor year yearweek zon",literal:"true false null",built_in:"array bigint binary bit blob boolean char character date dec decimal float int integer interval number numeric real serial smallint varchar varying int8 serial8 text"},c:[{cN:"string",b:"'",e:"'",c:[e.BE,{b:"''"}]},{cN:"string",b:'"',e:'"',c:[e.BE,{b:'""'}]},{cN:"string",b:"`",e:"`",c:[e.BE]},e.CNM,e.CBCM,t]},e.CBCM,t]} +}); \ No newline at end of file diff --git a/mac/TeamTalk/html/highlight.pack.js b/mac/TeamTalk/html/highlight.pack.js new file mode 100755 index 000000000..98fad17a6 --- /dev/null +++ b/mac/TeamTalk/html/highlight.pack.js @@ -0,0 +1,739 @@ +/* +Syntax highlighting with language autodetection. +https://highlightjs.org/ +*/ + +(function(factory) { + + // Setup highlight.js for different environments. First is Node.js or + // CommonJS. + if(typeof exports !== 'undefined') { + factory(exports); + } else { + // Export hljs globally even when using AMD for cases when this script + // is loaded with others that may still expect a global hljs. + window.hljs = factory({}); + + // Finally register the global hljs with AMD. + if(typeof define === 'function' && define.amd) { + define([], function() { + return window.hljs; + }); + } + } + +}(function(hljs) { + + /* Utility functions */ + + function escape(value) { + return value.replace(/&/gm, '&').replace(//gm, '>'); + } + + function tag(node) { + return node.nodeName.toLowerCase(); + } + + function testRe(re, lexeme) { + var match = re && re.exec(lexeme); + return match && match.index == 0; + } + + function blockLanguage(block) { + var classes = (block.className + ' ' + (block.parentNode ? block.parentNode.className : '')).split(/\s+/); + classes = classes.map(function(c) {return c.replace(/^lang(uage)?-/, '');}); + return classes.filter(function(c) {return getLanguage(c) || /no(-?)highlight|plain|text/.test(c);})[0]; + } + + function inherit(parent, obj) { + var result = {}; + for (var key in parent) + result[key] = parent[key]; + if (obj) + for (var key in obj) + result[key] = obj[key]; + return result; + }; + + /* Stream merging */ + + function nodeStream(node) { + var result = []; + (function _nodeStream(node, offset) { + for (var child = node.firstChild; child; child = child.nextSibling) { + if (child.nodeType == 3) + offset += child.nodeValue.length; + else if (child.nodeType == 1) { + result.push({ + event: 'start', + offset: offset, + node: child + }); + offset = _nodeStream(child, offset); + // Prevent void elements from having an end tag that would actually + // double them in the output. There are more void elements in HTML + // but we list only those realistically expected in code display. + if (!tag(child).match(/br|hr|img|input/)) { + result.push({ + event: 'stop', + offset: offset, + node: child + }); + } + } + } + return offset; + })(node, 0); + return result; + } + + function mergeStreams(original, highlighted, value) { + var processed = 0; + var result = ''; + var nodeStack = []; + + function selectStream() { + if (!original.length || !highlighted.length) { + return original.length ? original : highlighted; + } + if (original[0].offset != highlighted[0].offset) { + return (original[0].offset < highlighted[0].offset) ? original : highlighted; + } + + /* + To avoid starting the stream just before it should stop the order is + ensured that original always starts first and closes last: + + if (event1 == 'start' && event2 == 'start') + return original; + if (event1 == 'start' && event2 == 'stop') + return highlighted; + if (event1 == 'stop' && event2 == 'start') + return original; + if (event1 == 'stop' && event2 == 'stop') + return highlighted; + + ... which is collapsed to: + */ + return highlighted[0].event == 'start' ? original : highlighted; + } + + function open(node) { + function attr_str(a) {return ' ' + a.nodeName + '="' + escape(a.value) + '"';} + result += '<' + tag(node) + Array.prototype.map.call(node.attributes, attr_str).join('') + '>'; + } + + function close(node) { + result += ''; + } + + function render(event) { + (event.event == 'start' ? open : close)(event.node); + } + + while (original.length || highlighted.length) { + var stream = selectStream(); + result += escape(value.substr(processed, stream[0].offset - processed)); + processed = stream[0].offset; + if (stream == original) { + /* + On any opening or closing tag of the original markup we first close + the entire highlighted node stack, then render the original tag along + with all the following original tags at the same offset and then + reopen all the tags on the highlighted stack. + */ + nodeStack.reverse().forEach(close); + do { + render(stream.splice(0, 1)[0]); + stream = selectStream(); + } while (stream == original && stream.length && stream[0].offset == processed); + nodeStack.reverse().forEach(open); + } else { + if (stream[0].event == 'start') { + nodeStack.push(stream[0].node); + } else { + nodeStack.pop(); + } + render(stream.splice(0, 1)[0]); + } + } + return result + escape(value.substr(processed)); + } + + /* Initialization */ + + function compileLanguage(language) { + + function reStr(re) { + return (re && re.source) || re; + } + + function langRe(value, global) { + return RegExp( + reStr(value), + 'm' + (language.case_insensitive ? 'i' : '') + (global ? 'g' : '') + ); + } + + function compileMode(mode, parent) { + if (mode.compiled) + return; + mode.compiled = true; + + mode.keywords = mode.keywords || mode.beginKeywords; + if (mode.keywords) { + var compiled_keywords = {}; + + var flatten = function(className, str) { + if (language.case_insensitive) { + str = str.toLowerCase(); + } + str.split(' ').forEach(function(kw) { + var pair = kw.split('|'); + compiled_keywords[pair[0]] = [className, pair[1] ? Number(pair[1]) : 1]; + }); + }; + + if (typeof mode.keywords == 'string') { // string + flatten('keyword', mode.keywords); + } else { + Object.keys(mode.keywords).forEach(function (className) { + flatten(className, mode.keywords[className]); + }); + } + mode.keywords = compiled_keywords; + } + mode.lexemesRe = langRe(mode.lexemes || /\b\w+\b/, true); + + if (parent) { + if (mode.beginKeywords) { + mode.begin = '\\b(' + mode.beginKeywords.split(' ').join('|') + ')\\b'; + } + if (!mode.begin) + mode.begin = /\B|\b/; + mode.beginRe = langRe(mode.begin); + if (!mode.end && !mode.endsWithParent) + mode.end = /\B|\b/; + if (mode.end) + mode.endRe = langRe(mode.end); + mode.terminator_end = reStr(mode.end) || ''; + if (mode.endsWithParent && parent.terminator_end) + mode.terminator_end += (mode.end ? '|' : '') + parent.terminator_end; + } + if (mode.illegal) + mode.illegalRe = langRe(mode.illegal); + if (mode.relevance === undefined) + mode.relevance = 1; + if (!mode.contains) { + mode.contains = []; + } + var expanded_contains = []; + mode.contains.forEach(function(c) { + if (c.variants) { + c.variants.forEach(function(v) {expanded_contains.push(inherit(c, v));}); + } else { + expanded_contains.push(c == 'self' ? mode : c); + } + }); + mode.contains = expanded_contains; + mode.contains.forEach(function(c) {compileMode(c, mode);}); + + if (mode.starts) { + compileMode(mode.starts, parent); + } + + var terminators = + mode.contains.map(function(c) { + return c.beginKeywords ? '\\.?(' + c.begin + ')\\.?' : c.begin; + }) + .concat([mode.terminator_end, mode.illegal]) + .map(reStr) + .filter(Boolean); + mode.terminators = terminators.length ? langRe(terminators.join('|'), true) : {exec: function(s) {return null;}}; + } + + compileMode(language); + } + + /* + Core highlighting function. Accepts a language name, or an alias, and a + string with the code to highlight. Returns an object with the following + properties: + + - relevance (int) + - value (an HTML string with highlighting markup) + + */ + function highlight(name, value, ignore_illegals, continuation) { + + function subMode(lexeme, mode) { + for (var i = 0; i < mode.contains.length; i++) { + if (testRe(mode.contains[i].beginRe, lexeme)) { + return mode.contains[i]; + } + } + } + + function endOfMode(mode, lexeme) { + if (testRe(mode.endRe, lexeme)) { + return mode; + } + if (mode.endsWithParent) { + return endOfMode(mode.parent, lexeme); + } + } + + function isIllegal(lexeme, mode) { + return !ignore_illegals && testRe(mode.illegalRe, lexeme); + } + + function keywordMatch(mode, match) { + var match_str = language.case_insensitive ? match[0].toLowerCase() : match[0]; + return mode.keywords.hasOwnProperty(match_str) && mode.keywords[match_str]; + } + + function buildSpan(classname, insideSpan, leaveOpen, noPrefix) { + var classPrefix = noPrefix ? '' : options.classPrefix, + openSpan = ''; + + return openSpan + insideSpan + closeSpan; + } + + function processKeywords() { + if (!top.keywords) + return escape(mode_buffer); + var result = ''; + var last_index = 0; + top.lexemesRe.lastIndex = 0; + var match = top.lexemesRe.exec(mode_buffer); + while (match) { + result += escape(mode_buffer.substr(last_index, match.index - last_index)); + var keyword_match = keywordMatch(top, match); + if (keyword_match) { + relevance += keyword_match[1]; + result += buildSpan(keyword_match[0], escape(match[0])); + } else { + result += escape(match[0]); + } + last_index = top.lexemesRe.lastIndex; + match = top.lexemesRe.exec(mode_buffer); + } + return result + escape(mode_buffer.substr(last_index)); + } + + function processSubLanguage() { + if (top.subLanguage && !languages[top.subLanguage]) { + return escape(mode_buffer); + } + var result = top.subLanguage ? highlight(top.subLanguage, mode_buffer, true, continuations[top.subLanguage]) : highlightAuto(mode_buffer); + // Counting embedded language score towards the host language may be disabled + // with zeroing the containing mode relevance. Usecase in point is Markdown that + // allows XML everywhere and makes every XML snippet to have a much larger Markdown + // score. + if (top.relevance > 0) { + relevance += result.relevance; + } + if (top.subLanguageMode == 'continuous') { + continuations[top.subLanguage] = result.top; + } + return buildSpan(result.language, result.value, false, true); + } + + function processBuffer() { + return top.subLanguage !== undefined ? processSubLanguage() : processKeywords(); + } + + function startNewMode(mode, lexeme) { + var markup = mode.className? buildSpan(mode.className, '', true): ''; + if (mode.returnBegin) { + result += markup; + mode_buffer = ''; + } else if (mode.excludeBegin) { + result += escape(lexeme) + markup; + mode_buffer = ''; + } else { + result += markup; + mode_buffer = lexeme; + } + top = Object.create(mode, {parent: {value: top}}); + } + + function processLexeme(buffer, lexeme) { + + mode_buffer += buffer; + if (lexeme === undefined) { + result += processBuffer(); + return 0; + } + + var new_mode = subMode(lexeme, top); + if (new_mode) { + result += processBuffer(); + startNewMode(new_mode, lexeme); + return new_mode.returnBegin ? 0 : lexeme.length; + } + + var end_mode = endOfMode(top, lexeme); + if (end_mode) { + var origin = top; + if (!(origin.returnEnd || origin.excludeEnd)) { + mode_buffer += lexeme; + } + result += processBuffer(); + do { + if (top.className) { + result += ''; + } + relevance += top.relevance; + top = top.parent; + } while (top != end_mode.parent); + if (origin.excludeEnd) { + result += escape(lexeme); + } + mode_buffer = ''; + if (end_mode.starts) { + startNewMode(end_mode.starts, ''); + } + return origin.returnEnd ? 0 : lexeme.length; + } + + if (isIllegal(lexeme, top)) + throw new Error('Illegal lexeme "' + lexeme + '" for mode "' + (top.className || '') + '"'); + + /* + Parser should not reach this point as all types of lexemes should be caught + earlier, but if it does due to some bug make sure it advances at least one + character forward to prevent infinite looping. + */ + mode_buffer += lexeme; + return lexeme.length || 1; + } + + var language = getLanguage(name); + if (!language) { + throw new Error('Unknown language: "' + name + '"'); + } + + compileLanguage(language); + var top = continuation || language; + var continuations = {}; // keep continuations for sub-languages + var result = ''; + for(var current = top; current != language; current = current.parent) { + if (current.className) { + result = buildSpan(current.className, '', true) + result; + } + } + var mode_buffer = ''; + var relevance = 0; + try { + var match, count, index = 0; + while (true) { + top.terminators.lastIndex = index; + match = top.terminators.exec(value); + if (!match) + break; + count = processLexeme(value.substr(index, match.index - index), match[0]); + index = match.index + count; + } + processLexeme(value.substr(index)); + for(var current = top; current.parent; current = current.parent) { // close dangling modes + if (current.className) { + result += ''; + } + }; + return { + relevance: relevance, + value: result, + language: name, + top: top + }; + } catch (e) { + if (e.message.indexOf('Illegal') != -1) { + return { + relevance: 0, + value: escape(value) + }; + } else { + throw e; + } + } + } + + /* + Highlighting with language detection. Accepts a string with the code to + highlight. Returns an object with the following properties: + + - language (detected language) + - relevance (int) + - value (an HTML string with highlighting markup) + - second_best (object with the same structure for second-best heuristically + detected language, may be absent) + + */ + function highlightAuto(text, languageSubset) { + languageSubset = languageSubset || options.languages || Object.keys(languages); + var result = { + relevance: 0, + value: escape(text) + }; + var second_best = result; + languageSubset.forEach(function(name) { + if (!getLanguage(name)) { + return; + } + var current = highlight(name, text, false); + current.language = name; + if (current.relevance > second_best.relevance) { + second_best = current; + } + if (current.relevance > result.relevance) { + second_best = result; + result = current; + } + }); + if (second_best.language) { + result.second_best = second_best; + } + return result; + } + + /* + Post-processing of the highlighted markup: + + - replace TABs with something more useful + - replace real line-breaks with '
' for non-pre containers + + */ + function fixMarkup(value) { + if (options.tabReplace) { + value = value.replace(/^((<[^>]+>|\t)+)/gm, function(match, p1, offset, s) { + return p1.replace(/\t/g, options.tabReplace); + }); + } + if (options.useBR) { + value = value.replace(/\n/g, '
'); + } + return value; + } + + function buildClassName(prevClassName, currentLang, resultLang) { + var language = currentLang ? aliases[currentLang] : resultLang, + result = [prevClassName.trim()]; + + if (!prevClassName.match(/\bhljs\b/)) { + result.push('hljs'); + } + + if (language) { + result.push(language); + } + + return result.join(' ').trim(); + } + + /* + Applies highlighting to a DOM node containing code. Accepts a DOM node and + two optional parameters for fixMarkup. + */ + function highlightBlock(block) { + var language = blockLanguage(block); + if (/no(-?)highlight|plain|text/.test(language)) + return; + + var node; + if (options.useBR) { + node = document.createElementNS('http://www.w3.org/1999/xhtml', 'div'); + node.innerHTML = block.innerHTML.replace(/\n/g, '').replace(//g, '\n'); + } else { + node = block; + } + var text = node.textContent; + var result = language ? highlight(language, text, true) : highlightAuto(text); + + var originalStream = nodeStream(node); + if (originalStream.length) { + var resultNode = document.createElementNS('http://www.w3.org/1999/xhtml', 'div'); + resultNode.innerHTML = result.value; + result.value = mergeStreams(originalStream, nodeStream(resultNode), text); + } + result.value = fixMarkup(result.value); + + block.innerHTML = result.value; + block.className = buildClassName(block.className, language, result.language); + block.result = { + language: result.language, + re: result.relevance + }; + if (result.second_best) { + block.second_best = { + language: result.second_best.language, + re: result.second_best.relevance + }; + } + } + + var options = { + classPrefix: 'hljs-', + tabReplace: null, + useBR: false, + languages: undefined + }; + + /* + Updates highlight.js global options with values passed in the form of an object + */ + function configure(user_options) { + options = inherit(options, user_options); + } + + /* + Applies highlighting to all
..
blocks on a page. + */ + function initHighlighting() { + if (initHighlighting.called) + return; + initHighlighting.called = true; + + var blocks = document.querySelectorAll('pre code'); + Array.prototype.forEach.call(blocks, highlightBlock); + } + + /* + Attaches highlighting to the page load event. + */ + function initHighlightingOnLoad() { + addEventListener('DOMContentLoaded', initHighlighting, false); + addEventListener('load', initHighlighting, false); + } + + var languages = {}; + var aliases = {}; + + function registerLanguage(name, language) { + var lang = languages[name] = language(hljs); + if (lang.aliases) { + lang.aliases.forEach(function(alias) {aliases[alias] = name;}); + } + } + + function listLanguages() { + return Object.keys(languages); + } + + function getLanguage(name) { + return languages[name] || languages[aliases[name]]; + } + + /* Interface definition */ + + hljs.highlight = highlight; + hljs.highlightAuto = highlightAuto; + hljs.fixMarkup = fixMarkup; + hljs.highlightBlock = highlightBlock; + hljs.configure = configure; + hljs.initHighlighting = initHighlighting; + hljs.initHighlightingOnLoad = initHighlightingOnLoad; + hljs.registerLanguage = registerLanguage; + hljs.listLanguages = listLanguages; + hljs.getLanguage = getLanguage; + hljs.inherit = inherit; + + // Common regexps + hljs.IDENT_RE = '[a-zA-Z]\\w*'; + hljs.UNDERSCORE_IDENT_RE = '[a-zA-Z_]\\w*'; + hljs.NUMBER_RE = '\\b\\d+(\\.\\d+)?'; + hljs.C_NUMBER_RE = '\\b(0[xX][a-fA-F0-9]+|(\\d+(\\.\\d*)?|\\.\\d+)([eE][-+]?\\d+)?)'; // 0x..., 0..., decimal, float + hljs.BINARY_NUMBER_RE = '\\b(0b[01]+)'; // 0b... + hljs.RE_STARTERS_RE = '!|!=|!==|%|%=|&|&&|&=|\\*|\\*=|\\+|\\+=|,|-|-=|/=|/|:|;|<<|<<=|<=|<|===|==|=|>>>=|>>=|>=|>>>|>>|>|\\?|\\[|\\{|\\(|\\^|\\^=|\\||\\|=|\\|\\||~'; + + // Common modes + hljs.BACKSLASH_ESCAPE = { + begin: '\\\\[\\s\\S]', relevance: 0 + }; + hljs.APOS_STRING_MODE = { + className: 'string', + begin: '\'', end: '\'', + illegal: '\\n', + contains: [hljs.BACKSLASH_ESCAPE] + }; + hljs.QUOTE_STRING_MODE = { + className: 'string', + begin: '"', end: '"', + illegal: '\\n', + contains: [hljs.BACKSLASH_ESCAPE] + }; + hljs.PHRASAL_WORDS_MODE = { + begin: /\b(a|an|the|are|I|I'm|isn't|don't|doesn't|won't|but|just|should|pretty|simply|enough|gonna|going|wtf|so|such)\b/ + }; + hljs.C_LINE_COMMENT_MODE = { + className: 'comment', + begin: '//', end: '$', + contains: [hljs.PHRASAL_WORDS_MODE] + }; + hljs.C_BLOCK_COMMENT_MODE = { + className: 'comment', + begin: '/\\*', end: '\\*/', + contains: [hljs.PHRASAL_WORDS_MODE] + }; + hljs.HASH_COMMENT_MODE = { + className: 'comment', + begin: '#', end: '$', + contains: [hljs.PHRASAL_WORDS_MODE] + }; + hljs.NUMBER_MODE = { + className: 'number', + begin: hljs.NUMBER_RE, + relevance: 0 + }; + hljs.C_NUMBER_MODE = { + className: 'number', + begin: hljs.C_NUMBER_RE, + relevance: 0 + }; + hljs.BINARY_NUMBER_MODE = { + className: 'number', + begin: hljs.BINARY_NUMBER_RE, + relevance: 0 + }; + hljs.CSS_NUMBER_MODE = { + className: 'number', + begin: hljs.NUMBER_RE + '(' + + '%|em|ex|ch|rem' + + '|vw|vh|vmin|vmax' + + '|cm|mm|in|pt|pc|px' + + '|deg|grad|rad|turn' + + '|s|ms' + + '|Hz|kHz' + + '|dpi|dpcm|dppx' + + ')?', + relevance: 0 + }; + hljs.REGEXP_MODE = { + className: 'regexp', + begin: /\//, end: /\/[gimuy]*/, + illegal: /\n/, + contains: [ + hljs.BACKSLASH_ESCAPE, + { + begin: /\[/, end: /\]/, + relevance: 0, + contains: [hljs.BACKSLASH_ESCAPE] + } + ] + }; + hljs.TITLE_MODE = { + className: 'title', + begin: hljs.IDENT_RE, + relevance: 0 + }; + hljs.UNDERSCORE_TITLE_MODE = { + className: 'title', + begin: hljs.UNDERSCORE_IDENT_RE, + relevance: 0 + }; + + return hljs; +})); diff --git a/mac/TeamTalk/html/hook-spinner.gif b/mac/TeamTalk/html/hook-spinner.gif new file mode 100755 index 000000000..3288d1035 Binary files /dev/null and b/mac/TeamTalk/html/hook-spinner.gif differ diff --git a/mac/TeamTalk/html/hook.css b/mac/TeamTalk/html/hook.css new file mode 100755 index 000000000..63688e0b1 --- /dev/null +++ b/mac/TeamTalk/html/hook.css @@ -0,0 +1,102 @@ +/** + * Hook + * Version: 1.1 + * Author: Jordan Singer, Brandon Jacoby, Adam Girton + * Copyright (c) 2013 - Hook. All rights reserved. + * http://www.usehook.com + */ + +/* 'customizable' declares that a property can be customized without breaking functionality */ +.hook * { + -webkit-box-sizing: border-box; + -moz-box-sizing: border-box; + box-sizing: border-box; + margin: 0 auto; +} + +.hook { + display: none; + /* customizable */ height: 85px; + /* customizable */ background: url(hook-bgs.png) repeat; + /* customizable */ box-shadow: 0 -8px 5px -5px #999 inset; + clear: both; + position: relative; + z-index: 9999; + width: 100%; + overflow: hidden; + text-align: center; +} +.hook-text { + /* customizable */ font-size: 14px; + /* customizable */ font-family: Arial, Helvetica, sans-serif; + /* customizable */ color: #666; + /* customizable */ font-weight: normal; + /* customizable */ text-shadow: 0 1px #fff; +} +.hook-loader { + padding: 25px 0; +} +.hook-spinner { + margin: 0 auto; + display: block; + /* customizable */ background: url(hook-spinner.gif) no-repeat center; + /* customizable */ width: 32px; + /* customizable */ height: 32px; + -webkit-animation: spin 1s linear infinite both; + -moz-animation: spin 1s linear infinite both; + -o-animation: spin 1s linear infinite both; + animation: spin 1s linear infinite both; +} +.hook-with-text .hook-loader{ + padding: 10px 0; +} + +@media +only screen and (-webkit-min-device-pixel-ratio: 2), +only screen and ( min--moz-device-pixel-ratio: 2), +only screen and ( -o-min-device-pixel-ratio: 2/1), +only screen and ( min-device-pixel-ratio: 2), +only screen and ( min-resolution: 192dpi), +only screen and ( min-resolution: 2dppx) { + + .hook-spinner { + background: url(hook-spinner.gif) no-repeat center; + background-size: 32px 32px; + } +} + +@-webkit-keyframes spin { + 0% { + -webkit-transform: rotate(0deg); + } + 100% { + -webkit-transform: rotate(360deg); + } +} + +@-moz-keyframes spin { + 0% { + -moz-transform: rotate(0deg); + } + 100% { + -moz-transform: rotate(360deg); + } +} + +@-o-keyframes spin { + 0% { + -o-transform: rotate(0deg); + } + 100% { + -o-transform: rotate(360deg); + } +} + +@keyframes spin { + 0% { + transform: rotate(0deg); + } + 100% { + transform: rotate(360deg); + } +} diff --git a/mac/TeamTalk/html/hook.min.js b/mac/TeamTalk/html/hook.min.js new file mode 100755 index 000000000..0ebbd2e59 --- /dev/null +++ b/mac/TeamTalk/html/hook.min.js @@ -0,0 +1 @@ +(function(c,f,g,b){var d=c(this),i=d.scrollTop()||f.pageYOffset,h=false;var e=function(){return !!("ontouchstart" in f)||!!("onmsgesturechange" in f)};var a={init:function(j){return this.each(function(){var q=c(this),m=q.data("hook");if(typeof(m)==="undefined"){var p={reloadPage:true,dynamic:true,textRequired:false,scrollWheelSelected:false,swipeDistance:50,loaderClass:"hook-loader",spinnerClass:"hook-spinner",loaderTextClass:"hook-text",loaderText:"Reloading...",reloadEl:function(){}};m=c.extend({},p,j);q.data("hook",m)}else{m=c.extend({},m,j)}if(m.dynamic===true){var k="
";k+="
";k+="
";var o=""+m.loaderText+"";q.append(k);if(m.textRequired===true){q.addClass("hook-with-text");q.append(o)}}if(!e()){if(m.scrollWheelSelected===true){d.on("mousewheel",function(r,s){a.onScroll(q,m,s)})}else{d.on("scroll",function(){a.onScroll(q,m)})}}else{var n=0,l=0;d.on("touchstart",function(r){n=r.originalEvent.touches[0].pageY});d.on("touchmove",function(r){l=r.originalEvent.touches[0].pageY+n;i=c(this).scrollTop();if(lm.swipeDistance&&n<=40){a.onSwipe(q,m)}});d.on("touchend",function(){l=0})}})},onScroll:function(k,j,l){i=d.scrollTop();if(j.scrollWheelSelected===true&&(l>=150&&i<=0)){if(h===false){a.reload(k,j);h=true}}if(j.scrollWheelSelected===false&&i<=0){if(h===false){a.reload(k,j);h=true}}},onSwipe:function(k,j){if(i<=0){a.reload(k,j)}},reload:function(k,j){k.show();k.animate({marginTop:"0px"},200);k.delay(500).slideUp(200,function(){if(j.reloadPage){f.location.reload(true)}h=false});if(!j.reloadPage){j.reloadEl()}},destroy:function(){return c(this).each(function(){var j=c(this);j.empty();j.removeData("hook")})}};c.fn.hook=function(){var j=arguments[0];if(a[j]){j=a[j];arguments=Array.prototype.slice.call(arguments,1)}else{if(typeof(j)==="object"||!j){j=a.init}else{c.error("Method "+j+" does not exist on jQuery.pluginName");return this}}return j.apply(this,arguments)}})(jQuery,window,document); \ No newline at end of file diff --git a/mac/TeamTalk/html/iscroll-probe.js b/mac/TeamTalk/html/iscroll-probe.js new file mode 100755 index 000000000..538d0e387 --- /dev/null +++ b/mac/TeamTalk/html/iscroll-probe.js @@ -0,0 +1,2038 @@ +/*! iScroll v5.1.3 ~ (c) 2008-2014 Matteo Spinelli ~ http://cubiq.org/license */ +(function (window, document, Math) { +var rAF = window.requestAnimationFrame || + window.webkitRequestAnimationFrame || + window.mozRequestAnimationFrame || + window.oRequestAnimationFrame || + window.msRequestAnimationFrame || + function (callback) { window.setTimeout(callback, 1000 / 60); }; + +var utils = (function () { + var me = {}; + + var _elementStyle = document.createElement('div').style; + var _vendor = (function () { + var vendors = ['t', 'webkitT', 'MozT', 'msT', 'OT'], + transform, + i = 0, + l = vendors.length; + + for ( ; i < l; i++ ) { + transform = vendors[i] + 'ransform'; + if ( transform in _elementStyle ) return vendors[i].substr(0, vendors[i].length-1); + } + + return false; + })(); + + function _prefixStyle (style) { + if ( _vendor === false ) return false; + if ( _vendor === '' ) return style; + return _vendor + style.charAt(0).toUpperCase() + style.substr(1); + } + + me.getTime = Date.now || function getTime () { return new Date().getTime(); }; + + me.extend = function (target, obj) { + for ( var i in obj ) { + target[i] = obj[i]; + } + }; + + me.addEvent = function (el, type, fn, capture) { + el.addEventListener(type, fn, !!capture); + }; + + me.removeEvent = function (el, type, fn, capture) { + el.removeEventListener(type, fn, !!capture); + }; + + me.prefixPointerEvent = function (pointerEvent) { + return window.MSPointerEvent ? + 'MSPointer' + pointerEvent.charAt(9).toUpperCase() + pointerEvent.substr(10): + pointerEvent; + }; + + me.momentum = function (current, start, time, lowerMargin, wrapperSize, deceleration) { + var distance = current - start, + speed = Math.abs(distance) / time, + destination, + duration; + + deceleration = deceleration === undefined ? 0.0006 : deceleration; + + destination = current + ( speed * speed ) / ( 2 * deceleration ) * ( distance < 0 ? -1 : 1 ); + duration = speed / deceleration; + + if ( destination < lowerMargin ) { + destination = wrapperSize ? lowerMargin - ( wrapperSize / 2.5 * ( speed / 8 ) ) : lowerMargin; + distance = Math.abs(destination - current); + duration = distance / speed; + } else if ( destination > 0 ) { + destination = wrapperSize ? wrapperSize / 2.5 * ( speed / 8 ) : 0; + distance = Math.abs(current) + destination; + duration = distance / speed; + } + + return { + destination: Math.round(destination), + duration: duration + }; + }; + + var _transform = _prefixStyle('transform'); + + me.extend(me, { + hasTransform: _transform !== false, + hasPerspective: _prefixStyle('perspective') in _elementStyle, + hasTouch: 'ontouchstart' in window, + hasPointer: window.PointerEvent || window.MSPointerEvent, // IE10 is prefixed + hasTransition: _prefixStyle('transition') in _elementStyle + }); + + // This should find all Android browsers lower than build 535.19 (both stock browser and webview) + me.isBadAndroid = /Android /.test(window.navigator.appVersion) && !(/Chrome\/\d/.test(window.navigator.appVersion)); + + me.extend(me.style = {}, { + transform: _transform, + transitionTimingFunction: _prefixStyle('transitionTimingFunction'), + transitionDuration: _prefixStyle('transitionDuration'), + transitionDelay: _prefixStyle('transitionDelay'), + transformOrigin: _prefixStyle('transformOrigin') + }); + + me.hasClass = function (e, c) { + var re = new RegExp("(^|\\s)" + c + "(\\s|$)"); + return re.test(e.className); + }; + + me.addClass = function (e, c) { + if ( me.hasClass(e, c) ) { + return; + } + + var newclass = e.className.split(' '); + newclass.push(c); + e.className = newclass.join(' '); + }; + + me.removeClass = function (e, c) { + if ( !me.hasClass(e, c) ) { + return; + } + + var re = new RegExp("(^|\\s)" + c + "(\\s|$)", 'g'); + e.className = e.className.replace(re, ' '); + }; + + me.offset = function (el) { + var left = -el.offsetLeft, + top = -el.offsetTop; + + // jshint -W084 + while (el = el.offsetParent) { + left -= el.offsetLeft; + top -= el.offsetTop; + } + // jshint +W084 + + return { + left: left, + top: top + }; + }; + + me.preventDefaultException = function (el, exceptions) { + for ( var i in exceptions ) { + if ( exceptions[i].test(el[i]) ) { + return true; + } + } + + return false; + }; + + me.extend(me.eventType = {}, { + touchstart: 1, + touchmove: 1, + touchend: 1, + + mousedown: 2, + mousemove: 2, + mouseup: 2, + + pointerdown: 3, + pointermove: 3, + pointerup: 3, + + MSPointerDown: 3, + MSPointerMove: 3, + MSPointerUp: 3 + }); + + me.extend(me.ease = {}, { + quadratic: { + style: 'cubic-bezier(0.25, 0.46, 0.45, 0.94)', + fn: function (k) { + return k * ( 2 - k ); + } + }, + circular: { + style: 'cubic-bezier(0.1, 0.57, 0.1, 1)', // Not properly "circular" but this looks better, it should be (0.075, 0.82, 0.165, 1) + fn: function (k) { + return Math.sqrt( 1 - ( --k * k ) ); + } + }, + back: { + style: 'cubic-bezier(0.175, 0.885, 0.32, 1.275)', + fn: function (k) { + var b = 4; + return ( k = k - 1 ) * k * ( ( b + 1 ) * k + b ) + 1; + } + }, + bounce: { + style: '', + fn: function (k) { + if ( ( k /= 1 ) < ( 1 / 2.75 ) ) { + return 7.5625 * k * k; + } else if ( k < ( 2 / 2.75 ) ) { + return 7.5625 * ( k -= ( 1.5 / 2.75 ) ) * k + 0.75; + } else if ( k < ( 2.5 / 2.75 ) ) { + return 7.5625 * ( k -= ( 2.25 / 2.75 ) ) * k + 0.9375; + } else { + return 7.5625 * ( k -= ( 2.625 / 2.75 ) ) * k + 0.984375; + } + } + }, + elastic: { + style: '', + fn: function (k) { + var f = 0.22, + e = 0.4; + + if ( k === 0 ) { return 0; } + if ( k == 1 ) { return 1; } + + return ( e * Math.pow( 2, - 10 * k ) * Math.sin( ( k - f / 4 ) * ( 2 * Math.PI ) / f ) + 1 ); + } + } + }); + + me.tap = function (e, eventName) { + var ev = document.createEvent('Event'); + ev.initEvent(eventName, true, true); + ev.pageX = e.pageX; + ev.pageY = e.pageY; + e.target.dispatchEvent(ev); + }; + + me.click = function (e) { + var target = e.target, + ev; + + if ( !(/(SELECT|INPUT|TEXTAREA)/i).test(target.tagName) ) { + ev = document.createEvent('MouseEvents'); + ev.initMouseEvent('click', true, true, e.view, 1, + target.screenX, target.screenY, target.clientX, target.clientY, + e.ctrlKey, e.altKey, e.shiftKey, e.metaKey, + 0, null); + + ev._constructed = true; + target.dispatchEvent(ev); + } + }; + + return me; +})(); + +function IScroll (el, options) { + this.wrapper = typeof el == 'string' ? document.querySelector(el) : el; + this.scroller = this.wrapper.children[0]; + this.scrollerStyle = this.scroller.style; // cache style for better performance + + this.options = { + + resizeScrollbars: true, + + mouseWheelSpeed: 20, + + snapThreshold: 0.334, + +// INSERT POINT: OPTIONS + + startX: 0, + startY: 0, + scrollY: true, + directionLockThreshold: 5, + momentum: true, + + bounce: true, + bounceTime: 600, + bounceEasing: '', + + preventDefault: true, + preventDefaultException: { tagName: /^(INPUT|TEXTAREA|BUTTON|SELECT)$/ }, + + HWCompositing: true, + useTransition: true, + useTransform: true + }; + + for ( var i in options ) { + this.options[i] = options[i]; + } + + // Normalize options + this.translateZ = this.options.HWCompositing && utils.hasPerspective ? ' translateZ(0)' : ''; + + this.options.useTransition = utils.hasTransition && this.options.useTransition; + this.options.useTransform = utils.hasTransform && this.options.useTransform; + + this.options.eventPassthrough = this.options.eventPassthrough === true ? 'vertical' : this.options.eventPassthrough; + this.options.preventDefault = !this.options.eventPassthrough && this.options.preventDefault; + + // If you want eventPassthrough I have to lock one of the axes + this.options.scrollY = this.options.eventPassthrough == 'vertical' ? false : this.options.scrollY; + this.options.scrollX = this.options.eventPassthrough == 'horizontal' ? false : this.options.scrollX; + + // With eventPassthrough we also need lockDirection mechanism + this.options.freeScroll = this.options.freeScroll && !this.options.eventPassthrough; + this.options.directionLockThreshold = this.options.eventPassthrough ? 0 : this.options.directionLockThreshold; + + this.options.bounceEasing = typeof this.options.bounceEasing == 'string' ? utils.ease[this.options.bounceEasing] || utils.ease.circular : this.options.bounceEasing; + + this.options.resizePolling = this.options.resizePolling === undefined ? 60 : this.options.resizePolling; + + if ( this.options.tap === true ) { + this.options.tap = 'tap'; + } + + if ( this.options.shrinkScrollbars == 'scale' ) { + this.options.useTransition = false; + } + + this.options.invertWheelDirection = this.options.invertWheelDirection ? -1 : 1; + + if ( this.options.probeType == 3 ) { + this.options.useTransition = false; } + +// INSERT POINT: NORMALIZATION + + // Some defaults + this.x = 0; + this.y = 0; + this.directionX = 0; + this.directionY = 0; + this._events = {}; + +// INSERT POINT: DEFAULTS + + this._init(); + this.refresh(); + + this.scrollTo(this.options.startX, this.options.startY); + this.enable(); +} + +IScroll.prototype = { + version: '5.1.3', + + _init: function () { + this._initEvents(); + + if ( this.options.scrollbars || this.options.indicators ) { + this._initIndicators(); + } + + if ( this.options.mouseWheel ) { + this._initWheel(); + } + + if ( this.options.snap ) { + this._initSnap(); + } + + if ( this.options.keyBindings ) { + this._initKeys(); + } + +// INSERT POINT: _init + + }, + + destroy: function () { + this._initEvents(true); + + this._execEvent('destroy'); + }, + + _transitionEnd: function (e) { + if ( e.target != this.scroller || !this.isInTransition ) { + return; + } + + this._transitionTime(); + if ( !this.resetPosition(this.options.bounceTime) ) { + this.isInTransition = false; + this._execEvent('scrollEnd'); + } + }, + + _start: function (e) { + // React to left mouse button only + if ( utils.eventType[e.type] != 1 ) { + if ( e.button !== 0 ) { + return; + } + } + + if ( !this.enabled || (this.initiated && utils.eventType[e.type] !== this.initiated) ) { + return; + } + + if ( this.options.preventDefault && !utils.isBadAndroid && !utils.preventDefaultException(e.target, this.options.preventDefaultException) ) { + e.preventDefault(); + } + + var point = e.touches ? e.touches[0] : e, + pos; + + this.initiated = utils.eventType[e.type]; + this.moved = false; + this.distX = 0; + this.distY = 0; + this.directionX = 0; + this.directionY = 0; + this.directionLocked = 0; + + this._transitionTime(); + + this.startTime = utils.getTime(); + + if ( this.options.useTransition && this.isInTransition ) { + this.isInTransition = false; + pos = this.getComputedPosition(); + this._translate(Math.round(pos.x), Math.round(pos.y)); + this._execEvent('scrollEnd'); + } else if ( !this.options.useTransition && this.isAnimating ) { + this.isAnimating = false; + this._execEvent('scrollEnd'); + } + + this.startX = this.x; + this.startY = this.y; + this.absStartX = this.x; + this.absStartY = this.y; + this.pointX = point.pageX; + this.pointY = point.pageY; + + this._execEvent('beforeScrollStart'); + }, + + _move: function (e) { + if ( !this.enabled || utils.eventType[e.type] !== this.initiated ) { + return; + } + + if ( this.options.preventDefault ) { // increases performance on Android? TODO: check! + e.preventDefault(); + } + + var point = e.touches ? e.touches[0] : e, + deltaX = point.pageX - this.pointX, + deltaY = point.pageY - this.pointY, + timestamp = utils.getTime(), + newX, newY, + absDistX, absDistY; + + this.pointX = point.pageX; + this.pointY = point.pageY; + + this.distX += deltaX; + this.distY += deltaY; + absDistX = Math.abs(this.distX); + absDistY = Math.abs(this.distY); + + // We need to move at least 10 pixels for the scrolling to initiate + if ( timestamp - this.endTime > 300 && (absDistX < 10 && absDistY < 10) ) { + return; + } + + // If you are scrolling in one direction lock the other + if ( !this.directionLocked && !this.options.freeScroll ) { + if ( absDistX > absDistY + this.options.directionLockThreshold ) { + this.directionLocked = 'h'; // lock horizontally + } else if ( absDistY >= absDistX + this.options.directionLockThreshold ) { + this.directionLocked = 'v'; // lock vertically + } else { + this.directionLocked = 'n'; // no lock + } + } + + if ( this.directionLocked == 'h' ) { + if ( this.options.eventPassthrough == 'vertical' ) { + e.preventDefault(); + } else if ( this.options.eventPassthrough == 'horizontal' ) { + this.initiated = false; + return; + } + + deltaY = 0; + } else if ( this.directionLocked == 'v' ) { + if ( this.options.eventPassthrough == 'horizontal' ) { + e.preventDefault(); + } else if ( this.options.eventPassthrough == 'vertical' ) { + this.initiated = false; + return; + } + + deltaX = 0; + } + + deltaX = this.hasHorizontalScroll ? deltaX : 0; + deltaY = this.hasVerticalScroll ? deltaY : 0; + + newX = this.x + deltaX; + newY = this.y + deltaY; + + // Slow down if outside of the boundaries + if ( newX > 0 || newX < this.maxScrollX ) { + newX = this.options.bounce ? this.x + deltaX / 3 : newX > 0 ? 0 : this.maxScrollX; + } + if ( newY > 0 || newY < this.maxScrollY ) { + newY = this.options.bounce ? this.y + deltaY / 3 : newY > 0 ? 0 : this.maxScrollY; + } + + this.directionX = deltaX > 0 ? -1 : deltaX < 0 ? 1 : 0; + this.directionY = deltaY > 0 ? -1 : deltaY < 0 ? 1 : 0; + + if ( !this.moved ) { + this._execEvent('scrollStart'); + } + + this.moved = true; + + this._translate(newX, newY); + +/* REPLACE START: _move */ + if ( timestamp - this.startTime > 300 ) { + this.startTime = timestamp; + this.startX = this.x; + this.startY = this.y; + + if ( this.options.probeType == 1 ) { + this._execEvent('scroll'); + } + } + + if ( this.options.probeType > 1 ) { + this._execEvent('scroll'); + } +/* REPLACE END: _move */ + + }, + + _end: function (e) { + if ( !this.enabled || utils.eventType[e.type] !== this.initiated ) { + return; + } + + if ( this.options.preventDefault && !utils.preventDefaultException(e.target, this.options.preventDefaultException) ) { + e.preventDefault(); + } + + var point = e.changedTouches ? e.changedTouches[0] : e, + momentumX, + momentumY, + duration = utils.getTime() - this.startTime, + newX = Math.round(this.x), + newY = Math.round(this.y), + distanceX = Math.abs(newX - this.startX), + distanceY = Math.abs(newY - this.startY), + time = 0, + easing = ''; + + this.isInTransition = 0; + this.initiated = 0; + this.endTime = utils.getTime(); + + // reset if we are outside of the boundaries + if ( this.resetPosition(this.options.bounceTime) ) { + return; + } + + this.scrollTo(newX, newY); // ensures that the last position is rounded + + // we scrolled less than 10 pixels + if ( !this.moved ) { + if ( this.options.tap ) { + utils.tap(e, this.options.tap); + } + + if ( this.options.click ) { + utils.click(e); + } + + this._execEvent('scrollCancel'); + return; + } + + if ( this._events.flick && duration < 200 && distanceX < 100 && distanceY < 100 ) { + this._execEvent('flick'); + return; + } + + // start momentum animation if needed + if ( this.options.momentum && duration < 300 ) { + momentumX = this.hasHorizontalScroll ? utils.momentum(this.x, this.startX, duration, this.maxScrollX, this.options.bounce ? this.wrapperWidth : 0, this.options.deceleration) : { destination: newX, duration: 0 }; + momentumY = this.hasVerticalScroll ? utils.momentum(this.y, this.startY, duration, this.maxScrollY, this.options.bounce ? this.wrapperHeight : 0, this.options.deceleration) : { destination: newY, duration: 0 }; + newX = momentumX.destination; + newY = momentumY.destination; + time = Math.max(momentumX.duration, momentumY.duration); + this.isInTransition = 1; + } + + + if ( this.options.snap ) { + var snap = this._nearestSnap(newX, newY); + this.currentPage = snap; + time = this.options.snapSpeed || Math.max( + Math.max( + Math.min(Math.abs(newX - snap.x), 1000), + Math.min(Math.abs(newY - snap.y), 1000) + ), 300); + newX = snap.x; + newY = snap.y; + + this.directionX = 0; + this.directionY = 0; + easing = this.options.bounceEasing; + } + +// INSERT POINT: _end + + if ( newX != this.x || newY != this.y ) { + // change easing function when scroller goes out of the boundaries + if ( newX > 0 || newX < this.maxScrollX || newY > 0 || newY < this.maxScrollY ) { + easing = utils.ease.quadratic; + } + + this.scrollTo(newX, newY, time, easing); + return; + } + + this._execEvent('scrollEnd'); + }, + + _resize: function () { + var that = this; + + clearTimeout(this.resizeTimeout); + + this.resizeTimeout = setTimeout(function () { + that.refresh(); + }, this.options.resizePolling); + }, + + resetPosition: function (time) { + var x = this.x, + y = this.y; + + time = time || 0; + + if ( !this.hasHorizontalScroll || this.x > 0 ) { + x = 0; + } else if ( this.x < this.maxScrollX ) { + x = this.maxScrollX; + } + + if ( !this.hasVerticalScroll || this.y > 0 ) { + y = 0; + } else if ( this.y < this.maxScrollY ) { + y = this.maxScrollY; + } + + if ( x == this.x && y == this.y ) { + return false; + } + + this.scrollTo(x, y, time, this.options.bounceEasing); + + return true; + }, + + disable: function () { + this.enabled = false; + }, + + enable: function () { + this.enabled = true; + }, + + refresh: function () { + var rf = this.wrapper.offsetHeight; // Force reflow + + this.wrapperWidth = this.wrapper.clientWidth; + this.wrapperHeight = this.wrapper.clientHeight; + +/* REPLACE START: refresh */ + + this.scrollerWidth = this.scroller.offsetWidth; + this.scrollerHeight = this.scroller.offsetHeight; + + this.maxScrollX = this.wrapperWidth - this.scrollerWidth; + this.maxScrollY = this.wrapperHeight - this.scrollerHeight; + +/* REPLACE END: refresh */ + + this.hasHorizontalScroll = this.options.scrollX && this.maxScrollX < 0; + this.hasVerticalScroll = this.options.scrollY && this.maxScrollY < 0; + + if ( !this.hasHorizontalScroll ) { + this.maxScrollX = 0; + this.scrollerWidth = this.wrapperWidth; + } + + if ( !this.hasVerticalScroll ) { + this.maxScrollY = 0; + this.scrollerHeight = this.wrapperHeight; + } + + this.endTime = 0; + this.directionX = 0; + this.directionY = 0; + + this.wrapperOffset = utils.offset(this.wrapper); + + this._execEvent('refresh'); + + this.resetPosition(); + +// INSERT POINT: _refresh + + }, + + on: function (type, fn) { + if ( !this._events[type] ) { + this._events[type] = []; + } + + this._events[type].push(fn); + }, + + off: function (type, fn) { + if ( !this._events[type] ) { + return; + } + + var index = this._events[type].indexOf(fn); + + if ( index > -1 ) { + this._events[type].splice(index, 1); + } + }, + + _execEvent: function (type) { + if ( !this._events[type] ) { + return; + } + + var i = 0, + l = this._events[type].length; + + if ( !l ) { + return; + } + + for ( ; i < l; i++ ) { + this._events[type][i].apply(this, [].slice.call(arguments, 1)); + } + }, + + scrollBy: function (x, y, time, easing) { + x = this.x + x; + y = this.y + y; + time = time || 0; + + this.scrollTo(x, y, time, easing); + }, + + scrollTo: function (x, y, time, easing) { + easing = easing || utils.ease.circular; + + this.isInTransition = this.options.useTransition && time > 0; + + if ( !time || (this.options.useTransition && easing.style) ) { + this._transitionTimingFunction(easing.style); + this._transitionTime(time); + this._translate(x, y); + } else { + this._animate(x, y, time, easing.fn); + } + }, + + scrollToElement: function (el, time, offsetX, offsetY, easing) { + el = el.nodeType ? el : this.scroller.querySelector(el); + + if ( !el ) { + return; + } + + var pos = utils.offset(el); + + pos.left -= this.wrapperOffset.left; + pos.top -= this.wrapperOffset.top; + + // if offsetX/Y are true we center the element to the screen + if ( offsetX === true ) { + offsetX = Math.round(el.offsetWidth / 2 - this.wrapper.offsetWidth / 2); + } + if ( offsetY === true ) { + offsetY = Math.round(el.offsetHeight / 2 - this.wrapper.offsetHeight / 2); + } + + pos.left -= offsetX || 0; + pos.top -= offsetY || 0; + + pos.left = pos.left > 0 ? 0 : pos.left < this.maxScrollX ? this.maxScrollX : pos.left; + pos.top = pos.top > 0 ? 0 : pos.top < this.maxScrollY ? this.maxScrollY : pos.top; + + time = time === undefined || time === null || time === 'auto' ? Math.max(Math.abs(this.x-pos.left), Math.abs(this.y-pos.top)) : time; + + this.scrollTo(pos.left, pos.top, time, easing); + }, + + _transitionTime: function (time) { + time = time || 0; + + this.scrollerStyle[utils.style.transitionDuration] = time + 'ms'; + + if ( !time && utils.isBadAndroid ) { + this.scrollerStyle[utils.style.transitionDuration] = '0.001s'; + } + + + if ( this.indicators ) { + for ( var i = this.indicators.length; i--; ) { + this.indicators[i].transitionTime(time); + } + } + + +// INSERT POINT: _transitionTime + + }, + + _transitionTimingFunction: function (easing) { + this.scrollerStyle[utils.style.transitionTimingFunction] = easing; + + + if ( this.indicators ) { + for ( var i = this.indicators.length; i--; ) { + this.indicators[i].transitionTimingFunction(easing); + } + } + + +// INSERT POINT: _transitionTimingFunction + + }, + + _translate: function (x, y) { + if ( this.options.useTransform ) { + +/* REPLACE START: _translate */ + + this.scrollerStyle[utils.style.transform] = 'translate(' + x + 'px,' + y + 'px)' + this.translateZ; + +/* REPLACE END: _translate */ + + } else { + x = Math.round(x); + y = Math.round(y); + this.scrollerStyle.left = x + 'px'; + this.scrollerStyle.top = y + 'px'; + } + + this.x = x; + this.y = y; + + + if ( this.indicators ) { + for ( var i = this.indicators.length; i--; ) { + this.indicators[i].updatePosition(); + } + } + + +// INSERT POINT: _translate + + }, + + _initEvents: function (remove) { + var eventType = remove ? utils.removeEvent : utils.addEvent, + target = this.options.bindToWrapper ? this.wrapper : window; + + eventType(window, 'orientationchange', this); + eventType(window, 'resize', this); + + if ( this.options.click ) { + eventType(this.wrapper, 'click', this, true); + } + + if ( !this.options.disableMouse ) { + eventType(this.wrapper, 'mousedown', this); + eventType(target, 'mousemove', this); + eventType(target, 'mousecancel', this); + eventType(target, 'mouseup', this); + } + + if ( utils.hasPointer && !this.options.disablePointer ) { + eventType(this.wrapper, utils.prefixPointerEvent('pointerdown'), this); + eventType(target, utils.prefixPointerEvent('pointermove'), this); + eventType(target, utils.prefixPointerEvent('pointercancel'), this); + eventType(target, utils.prefixPointerEvent('pointerup'), this); + } + + if ( utils.hasTouch && !this.options.disableTouch ) { + eventType(this.wrapper, 'touchstart', this); + eventType(target, 'touchmove', this); + eventType(target, 'touchcancel', this); + eventType(target, 'touchend', this); + } + + eventType(this.scroller, 'transitionend', this); + eventType(this.scroller, 'webkitTransitionEnd', this); + eventType(this.scroller, 'oTransitionEnd', this); + eventType(this.scroller, 'MSTransitionEnd', this); + }, + + getComputedPosition: function () { + var matrix = window.getComputedStyle(this.scroller, null), + x, y; + + if ( this.options.useTransform ) { + matrix = matrix[utils.style.transform].split(')')[0].split(', '); + x = +(matrix[12] || matrix[4]); + y = +(matrix[13] || matrix[5]); + } else { + x = +matrix.left.replace(/[^-\d.]/g, ''); + y = +matrix.top.replace(/[^-\d.]/g, ''); + } + + return { x: x, y: y }; + }, + + _initIndicators: function () { + var interactive = this.options.interactiveScrollbars, + customStyle = typeof this.options.scrollbars != 'string', + indicators = [], + indicator; + + var that = this; + + this.indicators = []; + + if ( this.options.scrollbars ) { + // Vertical scrollbar + if ( this.options.scrollY ) { + indicator = { + el: createDefaultScrollbar('v', interactive, this.options.scrollbars), + interactive: interactive, + defaultScrollbars: true, + customStyle: customStyle, + resize: this.options.resizeScrollbars, + shrink: this.options.shrinkScrollbars, + fade: this.options.fadeScrollbars, + listenX: false + }; + + this.wrapper.appendChild(indicator.el); + indicators.push(indicator); + } + + // Horizontal scrollbar + if ( this.options.scrollX ) { + indicator = { + el: createDefaultScrollbar('h', interactive, this.options.scrollbars), + interactive: interactive, + defaultScrollbars: true, + customStyle: customStyle, + resize: this.options.resizeScrollbars, + shrink: this.options.shrinkScrollbars, + fade: this.options.fadeScrollbars, + listenY: false + }; + + this.wrapper.appendChild(indicator.el); + indicators.push(indicator); + } + } + + if ( this.options.indicators ) { + // TODO: check concat compatibility + indicators = indicators.concat(this.options.indicators); + } + + for ( var i = indicators.length; i--; ) { + this.indicators.push( new Indicator(this, indicators[i]) ); + } + + // TODO: check if we can use array.map (wide compatibility and performance issues) + function _indicatorsMap (fn) { + for ( var i = that.indicators.length; i--; ) { + fn.call(that.indicators[i]); + } + } + + if ( this.options.fadeScrollbars ) { + this.on('scrollEnd', function () { + _indicatorsMap(function () { + this.fade(); + }); + }); + + this.on('scrollCancel', function () { + _indicatorsMap(function () { + this.fade(); + }); + }); + + this.on('scrollStart', function () { + _indicatorsMap(function () { + this.fade(1); + }); + }); + + this.on('beforeScrollStart', function () { + _indicatorsMap(function () { + this.fade(1, true); + }); + }); + } + + + this.on('refresh', function () { + _indicatorsMap(function () { + this.refresh(); + }); + }); + + this.on('destroy', function () { + _indicatorsMap(function () { + this.destroy(); + }); + + delete this.indicators; + }); + }, + + _initWheel: function () { + utils.addEvent(this.wrapper, 'wheel', this); + utils.addEvent(this.wrapper, 'mousewheel', this); + utils.addEvent(this.wrapper, 'DOMMouseScroll', this); + + this.on('destroy', function () { + utils.removeEvent(this.wrapper, 'wheel', this); + utils.removeEvent(this.wrapper, 'mousewheel', this); + utils.removeEvent(this.wrapper, 'DOMMouseScroll', this); + }); + }, + + _wheel: function (e) { + if ( !this.enabled ) { + return; + } + + e.preventDefault(); + e.stopPropagation(); + + var wheelDeltaX, wheelDeltaY, + newX, newY, + that = this; + + if ( this.wheelTimeout === undefined ) { + that._execEvent('scrollStart'); + } + + // Execute the scrollEnd event after 400ms the wheel stopped scrolling + clearTimeout(this.wheelTimeout); + this.wheelTimeout = setTimeout(function () { + that._execEvent('scrollEnd'); + that.wheelTimeout = undefined; + }, 400); + + if ( 'deltaX' in e ) { + if (e.deltaMode === 1) { + wheelDeltaX = -e.deltaX * this.options.mouseWheelSpeed; + wheelDeltaY = -e.deltaY * this.options.mouseWheelSpeed; + } else { + wheelDeltaX = -e.deltaX; + wheelDeltaY = -e.deltaY; + } + } else if ( 'wheelDeltaX' in e ) { + wheelDeltaX = e.wheelDeltaX / 120 * this.options.mouseWheelSpeed; + wheelDeltaY = e.wheelDeltaY / 120 * this.options.mouseWheelSpeed; + } else if ( 'wheelDelta' in e ) { + wheelDeltaX = wheelDeltaY = e.wheelDelta / 120 * this.options.mouseWheelSpeed; + } else if ( 'detail' in e ) { + wheelDeltaX = wheelDeltaY = -e.detail / 3 * this.options.mouseWheelSpeed; + } else { + return; + } + + wheelDeltaX *= this.options.invertWheelDirection; + wheelDeltaY *= this.options.invertWheelDirection; + + if ( !this.hasVerticalScroll ) { + wheelDeltaX = wheelDeltaY; + wheelDeltaY = 0; + } + + if ( this.options.snap ) { + newX = this.currentPage.pageX; + newY = this.currentPage.pageY; + + if ( wheelDeltaX > 0 ) { + newX--; + } else if ( wheelDeltaX < 0 ) { + newX++; + } + + if ( wheelDeltaY > 0 ) { + newY--; + } else if ( wheelDeltaY < 0 ) { + newY++; + } + + this.goToPage(newX, newY); + + return; + } + + newX = this.x + Math.round(this.hasHorizontalScroll ? wheelDeltaX : 0); + newY = this.y + Math.round(this.hasVerticalScroll ? wheelDeltaY : 0); + + if ( newX > 0 ) { + newX = 0; + } else if ( newX < this.maxScrollX ) { + newX = this.maxScrollX; + } + + if ( newY > 0 ) { + newY = 0; + } else if ( newY < this.maxScrollY ) { + newY = this.maxScrollY; + } + + this.scrollTo(newX, newY, 0); + + if ( this.options.probeType > 1 ) { + this._execEvent('scroll'); + } + +// INSERT POINT: _wheel + }, + + _initSnap: function () { + this.currentPage = {}; + + if ( typeof this.options.snap == 'string' ) { + this.options.snap = this.scroller.querySelectorAll(this.options.snap); + } + + this.on('refresh', function () { + var i = 0, l, + m = 0, n, + cx, cy, + x = 0, y, + stepX = this.options.snapStepX || this.wrapperWidth, + stepY = this.options.snapStepY || this.wrapperHeight, + el; + + this.pages = []; + + if ( !this.wrapperWidth || !this.wrapperHeight || !this.scrollerWidth || !this.scrollerHeight ) { + return; + } + + if ( this.options.snap === true ) { + cx = Math.round( stepX / 2 ); + cy = Math.round( stepY / 2 ); + + while ( x > -this.scrollerWidth ) { + this.pages[i] = []; + l = 0; + y = 0; + + while ( y > -this.scrollerHeight ) { + this.pages[i][l] = { + x: Math.max(x, this.maxScrollX), + y: Math.max(y, this.maxScrollY), + width: stepX, + height: stepY, + cx: x - cx, + cy: y - cy + }; + + y -= stepY; + l++; + } + + x -= stepX; + i++; + } + } else { + el = this.options.snap; + l = el.length; + n = -1; + + for ( ; i < l; i++ ) { + if ( i === 0 || el[i].offsetLeft <= el[i-1].offsetLeft ) { + m = 0; + n++; + } + + if ( !this.pages[m] ) { + this.pages[m] = []; + } + + x = Math.max(-el[i].offsetLeft, this.maxScrollX); + y = Math.max(-el[i].offsetTop, this.maxScrollY); + cx = x - Math.round(el[i].offsetWidth / 2); + cy = y - Math.round(el[i].offsetHeight / 2); + + this.pages[m][n] = { + x: x, + y: y, + width: el[i].offsetWidth, + height: el[i].offsetHeight, + cx: cx, + cy: cy + }; + + if ( x > this.maxScrollX ) { + m++; + } + } + } + + this.goToPage(this.currentPage.pageX || 0, this.currentPage.pageY || 0, 0); + + // Update snap threshold if needed + if ( this.options.snapThreshold % 1 === 0 ) { + this.snapThresholdX = this.options.snapThreshold; + this.snapThresholdY = this.options.snapThreshold; + } else { + this.snapThresholdX = Math.round(this.pages[this.currentPage.pageX][this.currentPage.pageY].width * this.options.snapThreshold); + this.snapThresholdY = Math.round(this.pages[this.currentPage.pageX][this.currentPage.pageY].height * this.options.snapThreshold); + } + }); + + this.on('flick', function () { + var time = this.options.snapSpeed || Math.max( + Math.max( + Math.min(Math.abs(this.x - this.startX), 1000), + Math.min(Math.abs(this.y - this.startY), 1000) + ), 300); + + this.goToPage( + this.currentPage.pageX + this.directionX, + this.currentPage.pageY + this.directionY, + time + ); + }); + }, + + _nearestSnap: function (x, y) { + if ( !this.pages.length ) { + return { x: 0, y: 0, pageX: 0, pageY: 0 }; + } + + var i = 0, + l = this.pages.length, + m = 0; + + // Check if we exceeded the snap threshold + if ( Math.abs(x - this.absStartX) < this.snapThresholdX && + Math.abs(y - this.absStartY) < this.snapThresholdY ) { + return this.currentPage; + } + + if ( x > 0 ) { + x = 0; + } else if ( x < this.maxScrollX ) { + x = this.maxScrollX; + } + + if ( y > 0 ) { + y = 0; + } else if ( y < this.maxScrollY ) { + y = this.maxScrollY; + } + + for ( ; i < l; i++ ) { + if ( x >= this.pages[i][0].cx ) { + x = this.pages[i][0].x; + break; + } + } + + l = this.pages[i].length; + + for ( ; m < l; m++ ) { + if ( y >= this.pages[0][m].cy ) { + y = this.pages[0][m].y; + break; + } + } + + if ( i == this.currentPage.pageX ) { + i += this.directionX; + + if ( i < 0 ) { + i = 0; + } else if ( i >= this.pages.length ) { + i = this.pages.length - 1; + } + + x = this.pages[i][0].x; + } + + if ( m == this.currentPage.pageY ) { + m += this.directionY; + + if ( m < 0 ) { + m = 0; + } else if ( m >= this.pages[0].length ) { + m = this.pages[0].length - 1; + } + + y = this.pages[0][m].y; + } + + return { + x: x, + y: y, + pageX: i, + pageY: m + }; + }, + + goToPage: function (x, y, time, easing) { + easing = easing || this.options.bounceEasing; + + if ( x >= this.pages.length ) { + x = this.pages.length - 1; + } else if ( x < 0 ) { + x = 0; + } + + if ( y >= this.pages[x].length ) { + y = this.pages[x].length - 1; + } else if ( y < 0 ) { + y = 0; + } + + var posX = this.pages[x][y].x, + posY = this.pages[x][y].y; + + time = time === undefined ? this.options.snapSpeed || Math.max( + Math.max( + Math.min(Math.abs(posX - this.x), 1000), + Math.min(Math.abs(posY - this.y), 1000) + ), 300) : time; + + this.currentPage = { + x: posX, + y: posY, + pageX: x, + pageY: y + }; + + this.scrollTo(posX, posY, time, easing); + }, + + next: function (time, easing) { + var x = this.currentPage.pageX, + y = this.currentPage.pageY; + + x++; + + if ( x >= this.pages.length && this.hasVerticalScroll ) { + x = 0; + y++; + } + + this.goToPage(x, y, time, easing); + }, + + prev: function (time, easing) { + var x = this.currentPage.pageX, + y = this.currentPage.pageY; + + x--; + + if ( x < 0 && this.hasVerticalScroll ) { + x = 0; + y--; + } + + this.goToPage(x, y, time, easing); + }, + + _initKeys: function (e) { + // default key bindings + var keys = { + pageUp: 33, + pageDown: 34, + end: 35, + home: 36, + left: 37, + up: 38, + right: 39, + down: 40 + }; + var i; + + // if you give me characters I give you keycode + if ( typeof this.options.keyBindings == 'object' ) { + for ( i in this.options.keyBindings ) { + if ( typeof this.options.keyBindings[i] == 'string' ) { + this.options.keyBindings[i] = this.options.keyBindings[i].toUpperCase().charCodeAt(0); + } + } + } else { + this.options.keyBindings = {}; + } + + for ( i in keys ) { + this.options.keyBindings[i] = this.options.keyBindings[i] || keys[i]; + } + + utils.addEvent(window, 'keydown', this); + + this.on('destroy', function () { + utils.removeEvent(window, 'keydown', this); + }); + }, + + _key: function (e) { + if ( !this.enabled ) { + return; + } + + var snap = this.options.snap, // we are using this alot, better to cache it + newX = snap ? this.currentPage.pageX : this.x, + newY = snap ? this.currentPage.pageY : this.y, + now = utils.getTime(), + prevTime = this.keyTime || 0, + acceleration = 0.250, + pos; + + if ( this.options.useTransition && this.isInTransition ) { + pos = this.getComputedPosition(); + + this._translate(Math.round(pos.x), Math.round(pos.y)); + this.isInTransition = false; + } + + this.keyAcceleration = now - prevTime < 200 ? Math.min(this.keyAcceleration + acceleration, 50) : 0; + + switch ( e.keyCode ) { + case this.options.keyBindings.pageUp: + if ( this.hasHorizontalScroll && !this.hasVerticalScroll ) { + newX += snap ? 1 : this.wrapperWidth; + } else { + newY += snap ? 1 : this.wrapperHeight; + } + break; + case this.options.keyBindings.pageDown: + if ( this.hasHorizontalScroll && !this.hasVerticalScroll ) { + newX -= snap ? 1 : this.wrapperWidth; + } else { + newY -= snap ? 1 : this.wrapperHeight; + } + break; + case this.options.keyBindings.end: + newX = snap ? this.pages.length-1 : this.maxScrollX; + newY = snap ? this.pages[0].length-1 : this.maxScrollY; + break; + case this.options.keyBindings.home: + newX = 0; + newY = 0; + break; + case this.options.keyBindings.left: + newX += snap ? -1 : 5 + this.keyAcceleration>>0; + break; + case this.options.keyBindings.up: + newY += snap ? 1 : 5 + this.keyAcceleration>>0; + break; + case this.options.keyBindings.right: + newX -= snap ? -1 : 5 + this.keyAcceleration>>0; + break; + case this.options.keyBindings.down: + newY -= snap ? 1 : 5 + this.keyAcceleration>>0; + break; + default: + return; + } + + if ( snap ) { + this.goToPage(newX, newY); + return; + } + + if ( newX > 0 ) { + newX = 0; + this.keyAcceleration = 0; + } else if ( newX < this.maxScrollX ) { + newX = this.maxScrollX; + this.keyAcceleration = 0; + } + + if ( newY > 0 ) { + newY = 0; + this.keyAcceleration = 0; + } else if ( newY < this.maxScrollY ) { + newY = this.maxScrollY; + this.keyAcceleration = 0; + } + + this.scrollTo(newX, newY, 0); + + this.keyTime = now; + }, + + _animate: function (destX, destY, duration, easingFn) { + var that = this, + startX = this.x, + startY = this.y, + startTime = utils.getTime(), + destTime = startTime + duration; + + function step () { + var now = utils.getTime(), + newX, newY, + easing; + + if ( now >= destTime ) { + that.isAnimating = false; + that._translate(destX, destY); + + if ( !that.resetPosition(that.options.bounceTime) ) { + that._execEvent('scrollEnd'); + } + + return; + } + + now = ( now - startTime ) / duration; + easing = easingFn(now); + newX = ( destX - startX ) * easing + startX; + newY = ( destY - startY ) * easing + startY; + that._translate(newX, newY); + + if ( that.isAnimating ) { + rAF(step); + } + + if ( that.options.probeType == 3 ) { + that._execEvent('scroll'); + } + } + + this.isAnimating = true; + step(); + }, + + handleEvent: function (e) { + switch ( e.type ) { + case 'touchstart': + case 'pointerdown': + case 'MSPointerDown': + case 'mousedown': + this._start(e); + break; + case 'touchmove': + case 'pointermove': + case 'MSPointerMove': + case 'mousemove': + this._move(e); + break; + case 'touchend': + case 'pointerup': + case 'MSPointerUp': + case 'mouseup': + case 'touchcancel': + case 'pointercancel': + case 'MSPointerCancel': + case 'mousecancel': + this._end(e); + break; + case 'orientationchange': + case 'resize': + this._resize(); + break; + case 'transitionend': + case 'webkitTransitionEnd': + case 'oTransitionEnd': + case 'MSTransitionEnd': + this._transitionEnd(e); + break; + case 'wheel': + case 'DOMMouseScroll': + case 'mousewheel': + this._wheel(e); + break; + case 'keydown': + this._key(e); + break; + case 'click': + if ( !e._constructed ) { + e.preventDefault(); + e.stopPropagation(); + } + break; + } + } +}; +function createDefaultScrollbar (direction, interactive, type) { + var scrollbar = document.createElement('div'), + indicator = document.createElement('div'); + + if ( type === true ) { + scrollbar.style.cssText = 'position:absolute;z-index:9999'; + indicator.style.cssText = '-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box;position:absolute;background:rgba(0,0,0,0.5);border:1px solid rgba(255,255,255,0.9);border-radius:3px'; + } + + indicator.className = 'iScrollIndicator'; + + if ( direction == 'h' ) { + if ( type === true ) { + scrollbar.style.cssText += ';height:7px;left:2px;right:2px;bottom:0'; + indicator.style.height = '100%'; + } + scrollbar.className = 'iScrollHorizontalScrollbar'; + } else { + if ( type === true ) { + scrollbar.style.cssText += ';width:7px;bottom:2px;top:2px;right:1px'; + indicator.style.width = '100%'; + } + scrollbar.className = 'iScrollVerticalScrollbar'; + } + + scrollbar.style.cssText += ';overflow:hidden'; + + if ( !interactive ) { + scrollbar.style.pointerEvents = 'none'; + } + + scrollbar.appendChild(indicator); + + return scrollbar; +} + +function Indicator (scroller, options) { + this.wrapper = typeof options.el == 'string' ? document.querySelector(options.el) : options.el; + this.wrapperStyle = this.wrapper.style; + this.indicator = this.wrapper.children[0]; + this.indicatorStyle = this.indicator.style; + this.scroller = scroller; + + this.options = { + listenX: true, + listenY: true, + interactive: false, + resize: true, + defaultScrollbars: false, + shrink: false, + fade: false, + speedRatioX: 0, + speedRatioY: 0 + }; + + for ( var i in options ) { + this.options[i] = options[i]; + } + + this.sizeRatioX = 1; + this.sizeRatioY = 1; + this.maxPosX = 0; + this.maxPosY = 0; + + if ( this.options.interactive ) { + if ( !this.options.disableTouch ) { + utils.addEvent(this.indicator, 'touchstart', this); + utils.addEvent(window, 'touchend', this); + } + if ( !this.options.disablePointer ) { + utils.addEvent(this.indicator, utils.prefixPointerEvent('pointerdown'), this); + utils.addEvent(window, utils.prefixPointerEvent('pointerup'), this); + } + if ( !this.options.disableMouse ) { + utils.addEvent(this.indicator, 'mousedown', this); + utils.addEvent(window, 'mouseup', this); + } + } + + if ( this.options.fade ) { + this.wrapperStyle[utils.style.transform] = this.scroller.translateZ; + this.wrapperStyle[utils.style.transitionDuration] = utils.isBadAndroid ? '0.001s' : '0ms'; + this.wrapperStyle.opacity = '0'; + } +} + +Indicator.prototype = { + handleEvent: function (e) { + switch ( e.type ) { + case 'touchstart': + case 'pointerdown': + case 'MSPointerDown': + case 'mousedown': + this._start(e); + break; + case 'touchmove': + case 'pointermove': + case 'MSPointerMove': + case 'mousemove': + this._move(e); + break; + case 'touchend': + case 'pointerup': + case 'MSPointerUp': + case 'mouseup': + case 'touchcancel': + case 'pointercancel': + case 'MSPointerCancel': + case 'mousecancel': + this._end(e); + break; + } + }, + + destroy: function () { + if ( this.options.interactive ) { + utils.removeEvent(this.indicator, 'touchstart', this); + utils.removeEvent(this.indicator, utils.prefixPointerEvent('pointerdown'), this); + utils.removeEvent(this.indicator, 'mousedown', this); + + utils.removeEvent(window, 'touchmove', this); + utils.removeEvent(window, utils.prefixPointerEvent('pointermove'), this); + utils.removeEvent(window, 'mousemove', this); + + utils.removeEvent(window, 'touchend', this); + utils.removeEvent(window, utils.prefixPointerEvent('pointerup'), this); + utils.removeEvent(window, 'mouseup', this); + } + + if ( this.options.defaultScrollbars ) { + this.wrapper.parentNode.removeChild(this.wrapper); + } + }, + + _start: function (e) { + var point = e.touches ? e.touches[0] : e; + + e.preventDefault(); + e.stopPropagation(); + + this.transitionTime(); + + this.initiated = true; + this.moved = false; + this.lastPointX = point.pageX; + this.lastPointY = point.pageY; + + this.startTime = utils.getTime(); + + if ( !this.options.disableTouch ) { + utils.addEvent(window, 'touchmove', this); + } + if ( !this.options.disablePointer ) { + utils.addEvent(window, utils.prefixPointerEvent('pointermove'), this); + } + if ( !this.options.disableMouse ) { + utils.addEvent(window, 'mousemove', this); + } + + this.scroller._execEvent('beforeScrollStart'); + }, + + _move: function (e) { + var point = e.touches ? e.touches[0] : e, + deltaX, deltaY, + newX, newY, + timestamp = utils.getTime(); + + if ( !this.moved ) { + this.scroller._execEvent('scrollStart'); + } + + this.moved = true; + + deltaX = point.pageX - this.lastPointX; + this.lastPointX = point.pageX; + + deltaY = point.pageY - this.lastPointY; + this.lastPointY = point.pageY; + + newX = this.x + deltaX; + newY = this.y + deltaY; + + this._pos(newX, newY); + + + if ( this.scroller.options.probeType == 1 && timestamp - this.startTime > 300 ) { + this.startTime = timestamp; + this.scroller._execEvent('scroll'); + } else if ( this.scroller.options.probeType > 1 ) { + this.scroller._execEvent('scroll'); + } + + +// INSERT POINT: indicator._move + + e.preventDefault(); + e.stopPropagation(); + }, + + _end: function (e) { + if ( !this.initiated ) { + return; + } + + this.initiated = false; + + e.preventDefault(); + e.stopPropagation(); + + utils.removeEvent(window, 'touchmove', this); + utils.removeEvent(window, utils.prefixPointerEvent('pointermove'), this); + utils.removeEvent(window, 'mousemove', this); + + if ( this.scroller.options.snap ) { + var snap = this.scroller._nearestSnap(this.scroller.x, this.scroller.y); + + var time = this.options.snapSpeed || Math.max( + Math.max( + Math.min(Math.abs(this.scroller.x - snap.x), 1000), + Math.min(Math.abs(this.scroller.y - snap.y), 1000) + ), 300); + + if ( this.scroller.x != snap.x || this.scroller.y != snap.y ) { + this.scroller.directionX = 0; + this.scroller.directionY = 0; + this.scroller.currentPage = snap; + this.scroller.scrollTo(snap.x, snap.y, time, this.scroller.options.bounceEasing); + } + } + + if ( this.moved ) { + this.scroller._execEvent('scrollEnd'); + } + }, + + transitionTime: function (time) { + time = time || 0; + this.indicatorStyle[utils.style.transitionDuration] = time + 'ms'; + + if ( !time && utils.isBadAndroid ) { + this.indicatorStyle[utils.style.transitionDuration] = '0.001s'; + } + }, + + transitionTimingFunction: function (easing) { + this.indicatorStyle[utils.style.transitionTimingFunction] = easing; + }, + + refresh: function () { + this.transitionTime(); + + if ( this.options.listenX && !this.options.listenY ) { + this.indicatorStyle.display = this.scroller.hasHorizontalScroll ? 'block' : 'none'; + } else if ( this.options.listenY && !this.options.listenX ) { + this.indicatorStyle.display = this.scroller.hasVerticalScroll ? 'block' : 'none'; + } else { + this.indicatorStyle.display = this.scroller.hasHorizontalScroll || this.scroller.hasVerticalScroll ? 'block' : 'none'; + } + + if ( this.scroller.hasHorizontalScroll && this.scroller.hasVerticalScroll ) { + utils.addClass(this.wrapper, 'iScrollBothScrollbars'); + utils.removeClass(this.wrapper, 'iScrollLoneScrollbar'); + + if ( this.options.defaultScrollbars && this.options.customStyle ) { + if ( this.options.listenX ) { + this.wrapper.style.right = '8px'; + } else { + this.wrapper.style.bottom = '8px'; + } + } + } else { + utils.removeClass(this.wrapper, 'iScrollBothScrollbars'); + utils.addClass(this.wrapper, 'iScrollLoneScrollbar'); + + if ( this.options.defaultScrollbars && this.options.customStyle ) { + if ( this.options.listenX ) { + this.wrapper.style.right = '2px'; + } else { + this.wrapper.style.bottom = '2px'; + } + } + } + + var r = this.wrapper.offsetHeight; // force refresh + + if ( this.options.listenX ) { + this.wrapperWidth = this.wrapper.clientWidth; + if ( this.options.resize ) { + this.indicatorWidth = Math.max(Math.round(this.wrapperWidth * this.wrapperWidth / (this.scroller.scrollerWidth || this.wrapperWidth || 1)), 8); + this.indicatorStyle.width = this.indicatorWidth + 'px'; + } else { + this.indicatorWidth = this.indicator.clientWidth; + } + + this.maxPosX = this.wrapperWidth - this.indicatorWidth; + + if ( this.options.shrink == 'clip' ) { + this.minBoundaryX = -this.indicatorWidth + 8; + this.maxBoundaryX = this.wrapperWidth - 8; + } else { + this.minBoundaryX = 0; + this.maxBoundaryX = this.maxPosX; + } + + this.sizeRatioX = this.options.speedRatioX || (this.scroller.maxScrollX && (this.maxPosX / this.scroller.maxScrollX)); + } + + if ( this.options.listenY ) { + this.wrapperHeight = this.wrapper.clientHeight; + if ( this.options.resize ) { + this.indicatorHeight = Math.max(Math.round(this.wrapperHeight * this.wrapperHeight / (this.scroller.scrollerHeight || this.wrapperHeight || 1)), 8); + this.indicatorStyle.height = this.indicatorHeight + 'px'; + } else { + this.indicatorHeight = this.indicator.clientHeight; + } + + this.maxPosY = this.wrapperHeight - this.indicatorHeight; + + if ( this.options.shrink == 'clip' ) { + this.minBoundaryY = -this.indicatorHeight + 8; + this.maxBoundaryY = this.wrapperHeight - 8; + } else { + this.minBoundaryY = 0; + this.maxBoundaryY = this.maxPosY; + } + + this.maxPosY = this.wrapperHeight - this.indicatorHeight; + this.sizeRatioY = this.options.speedRatioY || (this.scroller.maxScrollY && (this.maxPosY / this.scroller.maxScrollY)); + } + + this.updatePosition(); + }, + + updatePosition: function () { + var x = this.options.listenX && Math.round(this.sizeRatioX * this.scroller.x) || 0, + y = this.options.listenY && Math.round(this.sizeRatioY * this.scroller.y) || 0; + + if ( !this.options.ignoreBoundaries ) { + if ( x < this.minBoundaryX ) { + if ( this.options.shrink == 'scale' ) { + this.width = Math.max(this.indicatorWidth + x, 8); + this.indicatorStyle.width = this.width + 'px'; + } + x = this.minBoundaryX; + } else if ( x > this.maxBoundaryX ) { + if ( this.options.shrink == 'scale' ) { + this.width = Math.max(this.indicatorWidth - (x - this.maxPosX), 8); + this.indicatorStyle.width = this.width + 'px'; + x = this.maxPosX + this.indicatorWidth - this.width; + } else { + x = this.maxBoundaryX; + } + } else if ( this.options.shrink == 'scale' && this.width != this.indicatorWidth ) { + this.width = this.indicatorWidth; + this.indicatorStyle.width = this.width + 'px'; + } + + if ( y < this.minBoundaryY ) { + if ( this.options.shrink == 'scale' ) { + this.height = Math.max(this.indicatorHeight + y * 3, 8); + this.indicatorStyle.height = this.height + 'px'; + } + y = this.minBoundaryY; + } else if ( y > this.maxBoundaryY ) { + if ( this.options.shrink == 'scale' ) { + this.height = Math.max(this.indicatorHeight - (y - this.maxPosY) * 3, 8); + this.indicatorStyle.height = this.height + 'px'; + y = this.maxPosY + this.indicatorHeight - this.height; + } else { + y = this.maxBoundaryY; + } + } else if ( this.options.shrink == 'scale' && this.height != this.indicatorHeight ) { + this.height = this.indicatorHeight; + this.indicatorStyle.height = this.height + 'px'; + } + } + + this.x = x; + this.y = y; + + if ( this.scroller.options.useTransform ) { + this.indicatorStyle[utils.style.transform] = 'translate(' + x + 'px,' + y + 'px)' + this.scroller.translateZ; + } else { + this.indicatorStyle.left = x + 'px'; + this.indicatorStyle.top = y + 'px'; + } + }, + + _pos: function (x, y) { + if ( x < 0 ) { + x = 0; + } else if ( x > this.maxPosX ) { + x = this.maxPosX; + } + + if ( y < 0 ) { + y = 0; + } else if ( y > this.maxPosY ) { + y = this.maxPosY; + } + + x = this.options.listenX ? Math.round(x / this.sizeRatioX) : this.scroller.x; + y = this.options.listenY ? Math.round(y / this.sizeRatioY) : this.scroller.y; + + this.scroller.scrollTo(x, y); + }, + + fade: function (val, hold) { + if ( hold && !this.visible ) { + return; + } + + clearTimeout(this.fadeTimeout); + this.fadeTimeout = null; + + var time = val ? 250 : 500, + delay = val ? 0 : 300; + + val = val ? '1' : '0'; + + this.wrapperStyle[utils.style.transitionDuration] = time + 'ms'; + + this.fadeTimeout = setTimeout((function (val) { + this.wrapperStyle.opacity = val; + this.visible = +val; + }).bind(this, val), delay); + } +}; + +IScroll.utils = utils; + +if ( typeof module != 'undefined' && module.exports ) { + module.exports = IScroll; +} else { + window.IScroll = IScroll; +} + +})(window, document, Math); \ No newline at end of file diff --git a/mac/TeamTalk/html/iscroll.js b/mac/TeamTalk/html/iscroll.js new file mode 100644 index 000000000..8222de03c --- /dev/null +++ b/mac/TeamTalk/html/iscroll.js @@ -0,0 +1,1104 @@ +/*! + * iScroll v4.2.5 ~ Copyright (c) 2012 Matteo Spinelli, http://cubiq.org + * Released under MIT license, http://cubiq.org/license + */ +(function(window, doc){ +var m = Math, + dummyStyle = doc.createElement('div').style, + vendor = (function () { + var vendors = 't,webkitT,MozT,msT,OT'.split(','), + t, + i = 0, + l = vendors.length; + + for ( ; i < l; i++ ) { + t = vendors[i] + 'ransform'; + if ( t in dummyStyle ) { + return vendors[i].substr(0, vendors[i].length - 1); + } + } + + return false; + })(), + cssVendor = vendor ? '-' + vendor.toLowerCase() + '-' : '', + + // Style properties + transform = prefixStyle('transform'), + transitionProperty = prefixStyle('transitionProperty'), + transitionDuration = prefixStyle('transitionDuration'), + transformOrigin = prefixStyle('transformOrigin'), + transitionTimingFunction = prefixStyle('transitionTimingFunction'), + transitionDelay = prefixStyle('transitionDelay'), + + // Browser capabilities + isAndroid = (/android/gi).test(navigator.appVersion), + isIDevice = (/iphone|ipad/gi).test(navigator.appVersion), + isTouchPad = (/hp-tablet/gi).test(navigator.appVersion), + + has3d = prefixStyle('perspective') in dummyStyle, + hasTouch = 'ontouchstart' in window && !isTouchPad, + hasTransform = vendor !== false, + hasTransitionEnd = prefixStyle('transition') in dummyStyle, + + RESIZE_EV = 'onorientationchange' in window ? 'orientationchange' : 'resize', + START_EV = hasTouch ? 'touchstart' : 'mousedown', + MOVE_EV = hasTouch ? 'touchmove' : 'mousemove', + END_EV = hasTouch ? 'touchend' : 'mouseup', + CANCEL_EV = hasTouch ? 'touchcancel' : 'mouseup', + TRNEND_EV = (function () { + if ( vendor === false ) return false; + + var transitionEnd = { + '' : 'transitionend', + 'webkit' : 'webkitTransitionEnd', + 'Moz' : 'transitionend', + 'O' : 'otransitionend', + 'ms' : 'MSTransitionEnd' + }; + + return transitionEnd[vendor]; + })(), + + nextFrame = (function() { + return window.requestAnimationFrame || + window.webkitRequestAnimationFrame || + window.mozRequestAnimationFrame || + window.oRequestAnimationFrame || + window.msRequestAnimationFrame || + function(callback) { return setTimeout(callback, 1); }; + })(), + cancelFrame = (function () { + return window.cancelRequestAnimationFrame || + window.webkitCancelAnimationFrame || + window.webkitCancelRequestAnimationFrame || + window.mozCancelRequestAnimationFrame || + window.oCancelRequestAnimationFrame || + window.msCancelRequestAnimationFrame || + clearTimeout; + })(), + + // Helpers + translateZ = has3d ? ' translateZ(0)' : '', + + // Constructor + iScroll = function (el, options) { + var that = this, + i; + + that.wrapper = typeof el == 'object' ? el : doc.getElementById(el); + that.wrapper.style.overflow = 'hidden'; + that.scroller = that.wrapper.children[0]; + + // Default options + that.options = { + hScroll: true, + vScroll: true, + x: 0, + y: 0, + bounce: true, + bounceLock: false, + momentum: true, + lockDirection: true, + useTransform: true, + useTransition: false, + topOffset: 0, + checkDOMChanges: false, // Experimental + handleClick: true, + + // Scrollbar + hScrollbar: true, + vScrollbar: true, + fixedScrollbar: isAndroid, + hideScrollbar: isIDevice, + fadeScrollbar: isIDevice && has3d, + scrollbarClass: '', + + // Zoom + zoom: false, + zoomMin: 1, + zoomMax: 4, + doubleTapZoom: 2, + wheelAction: 'scroll', + + // Snap + snap: false, + snapThreshold: 1, + + // Events + onRefresh: null, + onBeforeScrollStart: function (e) { e.preventDefault(); }, + onScrollStart: null, + onBeforeScrollMove: null, + onScrollMove: null, + onBeforeScrollEnd: null, + onScrollEnd: null, + onTouchEnd: null, + onDestroy: null, + onZoomStart: null, + onZoom: null, + onZoomEnd: null + }; + + // User defined options + for (i in options) that.options[i] = options[i]; + + // Set starting position + that.x = that.options.x; + that.y = that.options.y; + + // Normalize options + that.options.useTransform = hasTransform && that.options.useTransform; + that.options.hScrollbar = that.options.hScroll && that.options.hScrollbar; + that.options.vScrollbar = that.options.vScroll && that.options.vScrollbar; + that.options.zoom = that.options.useTransform && that.options.zoom; + that.options.useTransition = hasTransitionEnd && that.options.useTransition; + + // Helpers FIX ANDROID BUG! + // translate3d and scale doesn't work together! + // Ignoring 3d ONLY WHEN YOU SET that.options.zoom + if ( that.options.zoom && isAndroid ){ + translateZ = ''; + } + + // Set some default styles + that.scroller.style[transitionProperty] = that.options.useTransform ? cssVendor + 'transform' : 'top left'; + that.scroller.style[transitionDuration] = '0'; + that.scroller.style[transformOrigin] = '0 0'; + if (that.options.useTransition) that.scroller.style[transitionTimingFunction] = 'cubic-bezier(0.33,0.66,0.66,1)'; + + if (that.options.useTransform) that.scroller.style[transform] = 'translate(' + that.x + 'px,' + that.y + 'px)' + translateZ; + else that.scroller.style.cssText += ';position:absolute;top:' + that.y + 'px;left:' + that.x + 'px'; + + if (that.options.useTransition) that.options.fixedScrollbar = true; + + that.refresh(); + + that._bind(RESIZE_EV, window); + that._bind(START_EV); + if (!hasTouch) { + if (that.options.wheelAction != 'none') { + that._bind('DOMMouseScroll'); + that._bind('mousewheel'); + } + } + + if (that.options.checkDOMChanges) that.checkDOMTime = setInterval(function () { + that._checkDOMChanges(); + }, 500); + }; + +// Prototype +iScroll.prototype = { + enabled: true, + x: 0, + y: 0, + steps: [], + scale: 1, + currPageX: 0, currPageY: 0, + pagesX: [], pagesY: [], + aniTime: null, + wheelZoomCount: 0, + + handleEvent: function (e) { + var that = this; + switch(e.type) { + case START_EV: + if (!hasTouch && e.button !== 0) return; + that._start(e); + break; + case MOVE_EV: that._move(e); break; + case END_EV: + case CANCEL_EV: that._end(e); break; + case RESIZE_EV: that._resize(); break; + case 'DOMMouseScroll': case 'mousewheel': that._wheel(e); break; + case TRNEND_EV: that._transitionEnd(e); break; + } + }, + + _checkDOMChanges: function () { + if (this.moved || this.zoomed || this.animating || + (this.scrollerW == this.scroller.offsetWidth * this.scale && this.scrollerH == this.scroller.offsetHeight * this.scale)) return; + + this.refresh(); + }, + + _scrollbar: function (dir) { + var that = this, + bar; + + if (!that[dir + 'Scrollbar']) { + if (that[dir + 'ScrollbarWrapper']) { + if (hasTransform) that[dir + 'ScrollbarIndicator'].style[transform] = ''; + that[dir + 'ScrollbarWrapper'].parentNode.removeChild(that[dir + 'ScrollbarWrapper']); + that[dir + 'ScrollbarWrapper'] = null; + that[dir + 'ScrollbarIndicator'] = null; + } + + return; + } + + if (!that[dir + 'ScrollbarWrapper']) { + // Create the scrollbar wrapper + bar = doc.createElement('div'); + + if (that.options.scrollbarClass) bar.className = that.options.scrollbarClass + dir.toUpperCase(); + else bar.style.cssText = 'position:absolute;z-index:100;' + (dir == 'h' ? 'height:7px;bottom:1px;left:2px;right:' + (that.vScrollbar ? '7' : '2') + 'px' : 'width:7px;bottom:' + (that.hScrollbar ? '7' : '2') + 'px;top:2px;right:1px'); + + bar.style.cssText += ';pointer-events:none;' + cssVendor + 'transition-property:opacity;' + cssVendor + 'transition-duration:' + (that.options.fadeScrollbar ? '350ms' : '0') + ';overflow:hidden;opacity:' + (that.options.hideScrollbar ? '0' : '1'); + + that.wrapper.appendChild(bar); + that[dir + 'ScrollbarWrapper'] = bar; + + // Create the scrollbar indicator + bar = doc.createElement('div'); + if (!that.options.scrollbarClass) { + bar.style.cssText = 'position:absolute;z-index:100;background:rgba(0,0,0,0.5);border:1px solid rgba(255,255,255,0.9);' + cssVendor + 'background-clip:padding-box;' + cssVendor + 'box-sizing:border-box;' + (dir == 'h' ? 'height:100%' : 'width:100%') + ';' + cssVendor + 'border-radius:3px;border-radius:3px'; + } + bar.style.cssText += ';pointer-events:none;' + cssVendor + 'transition-property:' + cssVendor + 'transform;' + cssVendor + 'transition-timing-function:cubic-bezier(0.33,0.66,0.66,1);' + cssVendor + 'transition-duration:0;' + cssVendor + 'transform: translate(0,0)' + translateZ; + if (that.options.useTransition) bar.style.cssText += ';' + cssVendor + 'transition-timing-function:cubic-bezier(0.33,0.66,0.66,1)'; + + that[dir + 'ScrollbarWrapper'].appendChild(bar); + that[dir + 'ScrollbarIndicator'] = bar; + } + + if (dir == 'h') { + that.hScrollbarSize = that.hScrollbarWrapper.clientWidth; + that.hScrollbarIndicatorSize = m.max(m.round(that.hScrollbarSize * that.hScrollbarSize / that.scrollerW), 8); + that.hScrollbarIndicator.style.width = that.hScrollbarIndicatorSize + 'px'; + that.hScrollbarMaxScroll = that.hScrollbarSize - that.hScrollbarIndicatorSize; + that.hScrollbarProp = that.hScrollbarMaxScroll / that.maxScrollX; + } else { + that.vScrollbarSize = that.vScrollbarWrapper.clientHeight; + that.vScrollbarIndicatorSize = m.max(m.round(that.vScrollbarSize * that.vScrollbarSize / that.scrollerH), 8); + that.vScrollbarIndicator.style.height = that.vScrollbarIndicatorSize + 'px'; + that.vScrollbarMaxScroll = that.vScrollbarSize - that.vScrollbarIndicatorSize; + that.vScrollbarProp = that.vScrollbarMaxScroll / that.maxScrollY; + } + + // Reset position + that._scrollbarPos(dir, true); + }, + + _resize: function () { + var that = this; + setTimeout(function () { that.refresh(); }, isAndroid ? 200 : 0); + }, + + _pos: function (x, y) { + if (this.zoomed) return; + + x = this.hScroll ? x : 0; + y = this.vScroll ? y : 0; + + if (this.options.useTransform) { + this.scroller.style[transform] = 'translate(' + x + 'px,' + y + 'px) scale(' + this.scale + ')' + translateZ; + } else { + x = m.round(x); + y = m.round(y); + this.scroller.style.left = x + 'px'; + this.scroller.style.top = y + 'px'; + } + + this.x = x; + this.y = y; + + this._scrollbarPos('h'); + this._scrollbarPos('v'); + }, + + _scrollbarPos: function (dir, hidden) { + var that = this, + pos = dir == 'h' ? that.x : that.y, + size; + + if (!that[dir + 'Scrollbar']) return; + + pos = that[dir + 'ScrollbarProp'] * pos; + + if (pos < 0) { + if (!that.options.fixedScrollbar) { + size = that[dir + 'ScrollbarIndicatorSize'] + m.round(pos * 3); + if (size < 8) size = 8; + that[dir + 'ScrollbarIndicator'].style[dir == 'h' ? 'width' : 'height'] = size + 'px'; + } + pos = 0; + } else if (pos > that[dir + 'ScrollbarMaxScroll']) { + if (!that.options.fixedScrollbar) { + size = that[dir + 'ScrollbarIndicatorSize'] - m.round((pos - that[dir + 'ScrollbarMaxScroll']) * 3); + if (size < 8) size = 8; + that[dir + 'ScrollbarIndicator'].style[dir == 'h' ? 'width' : 'height'] = size + 'px'; + pos = that[dir + 'ScrollbarMaxScroll'] + (that[dir + 'ScrollbarIndicatorSize'] - size); + } else { + pos = that[dir + 'ScrollbarMaxScroll']; + } + } + + that[dir + 'ScrollbarWrapper'].style[transitionDelay] = '0'; + that[dir + 'ScrollbarWrapper'].style.opacity = hidden && that.options.hideScrollbar ? '0' : '1'; + that[dir + 'ScrollbarIndicator'].style[transform] = 'translate(' + (dir == 'h' ? pos + 'px,0)' : '0,' + pos + 'px)') + translateZ; + }, + + _start: function (e) { + var that = this, + point = hasTouch ? e.touches[0] : e, + matrix, x, y, + c1, c2; + + if (!that.enabled) return; + + if (that.options.onBeforeScrollStart) that.options.onBeforeScrollStart.call(that, e); + + if (that.options.useTransition || that.options.zoom) that._transitionTime(0); + + that.moved = false; + that.animating = false; + that.zoomed = false; + that.distX = 0; + that.distY = 0; + that.absDistX = 0; + that.absDistY = 0; + that.dirX = 0; + that.dirY = 0; + + // Gesture start + if (that.options.zoom && hasTouch && e.touches.length > 1) { + c1 = m.abs(e.touches[0].pageX-e.touches[1].pageX); + c2 = m.abs(e.touches[0].pageY-e.touches[1].pageY); + that.touchesDistStart = m.sqrt(c1 * c1 + c2 * c2); + + that.originX = m.abs(e.touches[0].pageX + e.touches[1].pageX - that.wrapperOffsetLeft * 2) / 2 - that.x; + that.originY = m.abs(e.touches[0].pageY + e.touches[1].pageY - that.wrapperOffsetTop * 2) / 2 - that.y; + + if (that.options.onZoomStart) that.options.onZoomStart.call(that, e); + } + + if (that.options.momentum) { + if (that.options.useTransform) { + // Very lame general purpose alternative to CSSMatrix + matrix = getComputedStyle(that.scroller, null)[transform].replace(/[^0-9\-.,]/g, '').split(','); + x = +(matrix[12] || matrix[4]); + y = +(matrix[13] || matrix[5]); + } else { + x = +getComputedStyle(that.scroller, null).left.replace(/[^0-9-]/g, ''); + y = +getComputedStyle(that.scroller, null).top.replace(/[^0-9-]/g, ''); + } + + if (x != that.x || y != that.y) { + if (that.options.useTransition) that._unbind(TRNEND_EV); + else cancelFrame(that.aniTime); + that.steps = []; + that._pos(x, y); + if (that.options.onScrollEnd) that.options.onScrollEnd.call(that); + } + } + + that.absStartX = that.x; // Needed by snap threshold + that.absStartY = that.y; + + that.startX = that.x; + that.startY = that.y; + that.pointX = point.pageX; + that.pointY = point.pageY; + + that.startTime = e.timeStamp || Date.now(); + + if (that.options.onScrollStart) that.options.onScrollStart.call(that, e); + + that._bind(MOVE_EV, window); + that._bind(END_EV, window); + that._bind(CANCEL_EV, window); + }, + + _move: function (e) { + var that = this, + point = hasTouch ? e.touches[0] : e, + deltaX = point.pageX - that.pointX, + deltaY = point.pageY - that.pointY, + newX = that.x + deltaX, + newY = that.y + deltaY, + c1, c2, scale, + timestamp = e.timeStamp || Date.now(); + + if (that.options.onBeforeScrollMove) that.options.onBeforeScrollMove.call(that, e); + + // Zoom + if (that.options.zoom && hasTouch && e.touches.length > 1) { + c1 = m.abs(e.touches[0].pageX - e.touches[1].pageX); + c2 = m.abs(e.touches[0].pageY - e.touches[1].pageY); + that.touchesDist = m.sqrt(c1*c1+c2*c2); + + that.zoomed = true; + + scale = 1 / that.touchesDistStart * that.touchesDist * this.scale; + + if (scale < that.options.zoomMin) scale = 0.5 * that.options.zoomMin * Math.pow(2.0, scale / that.options.zoomMin); + else if (scale > that.options.zoomMax) scale = 2.0 * that.options.zoomMax * Math.pow(0.5, that.options.zoomMax / scale); + + that.lastScale = scale / this.scale; + + newX = this.originX - this.originX * that.lastScale + this.x; + newY = this.originY - this.originY * that.lastScale + this.y; + + this.scroller.style[transform] = 'translate(' + newX + 'px,' + newY + 'px) scale(' + scale + ')' + translateZ; + + if (that.options.onZoom) that.options.onZoom.call(that, e); + return; + } + + that.pointX = point.pageX; + that.pointY = point.pageY; + + // Slow down if outside of the boundaries + if (newX > 0 || newX < that.maxScrollX) { + newX = that.options.bounce ? that.x + (deltaX / 2) : newX >= 0 || that.maxScrollX >= 0 ? 0 : that.maxScrollX; + } + if (newY > that.minScrollY || newY < that.maxScrollY) { + newY = that.options.bounce ? that.y + (deltaY / 2) : newY >= that.minScrollY || that.maxScrollY >= 0 ? that.minScrollY : that.maxScrollY; + } + + that.distX += deltaX; + that.distY += deltaY; + that.absDistX = m.abs(that.distX); + that.absDistY = m.abs(that.distY); + + if (that.absDistX < 6 && that.absDistY < 6) { + return; + } + + // Lock direction + if (that.options.lockDirection) { + if (that.absDistX > that.absDistY + 5) { + newY = that.y; + deltaY = 0; + } else if (that.absDistY > that.absDistX + 5) { + newX = that.x; + deltaX = 0; + } + } + + that.moved = true; + that._pos(newX, newY); + that.dirX = deltaX > 0 ? -1 : deltaX < 0 ? 1 : 0; + that.dirY = deltaY > 0 ? -1 : deltaY < 0 ? 1 : 0; + + if (timestamp - that.startTime > 300) { + that.startTime = timestamp; + that.startX = that.x; + that.startY = that.y; + } + + if (that.options.onScrollMove) that.options.onScrollMove.call(that, e); + }, + + _end: function (e) { + if (hasTouch && e.touches.length !== 0) return; + + var that = this, + point = hasTouch ? e.changedTouches[0] : e, + target, ev, + momentumX = { dist:0, time:0 }, + momentumY = { dist:0, time:0 }, + duration = (e.timeStamp || Date.now()) - that.startTime, + newPosX = that.x, + newPosY = that.y, + distX, distY, + newDuration, + snap, + scale; + + that._unbind(MOVE_EV, window); + that._unbind(END_EV, window); + that._unbind(CANCEL_EV, window); + + if (that.options.onBeforeScrollEnd) that.options.onBeforeScrollEnd.call(that, e); + + if (that.zoomed) { + scale = that.scale * that.lastScale; + scale = Math.max(that.options.zoomMin, scale); + scale = Math.min(that.options.zoomMax, scale); + that.lastScale = scale / that.scale; + that.scale = scale; + + that.x = that.originX - that.originX * that.lastScale + that.x; + that.y = that.originY - that.originY * that.lastScale + that.y; + + that.scroller.style[transitionDuration] = '200ms'; + that.scroller.style[transform] = 'translate(' + that.x + 'px,' + that.y + 'px) scale(' + that.scale + ')' + translateZ; + + that.zoomed = false; + that.refresh(); + + if (that.options.onZoomEnd) that.options.onZoomEnd.call(that, e); + return; + } + + if (!that.moved) { + if (hasTouch) { + if (that.doubleTapTimer && that.options.zoom) { + // Double tapped + clearTimeout(that.doubleTapTimer); + that.doubleTapTimer = null; + if (that.options.onZoomStart) that.options.onZoomStart.call(that, e); + that.zoom(that.pointX, that.pointY, that.scale == 1 ? that.options.doubleTapZoom : 1); + if (that.options.onZoomEnd) { + setTimeout(function() { + that.options.onZoomEnd.call(that, e); + }, 200); // 200 is default zoom duration + } + } else if (this.options.handleClick) { + that.doubleTapTimer = setTimeout(function () { + that.doubleTapTimer = null; + + // Find the last touched element + target = point.target; + while (target.nodeType != 1) target = target.parentNode; + + if (target.tagName != 'SELECT' && target.tagName != 'INPUT' && target.tagName != 'TEXTAREA') { + ev = doc.createEvent('MouseEvents'); + ev.initMouseEvent('click', true, true, e.view, 1, + point.screenX, point.screenY, point.clientX, point.clientY, + e.ctrlKey, e.altKey, e.shiftKey, e.metaKey, + 0, null); + ev._fake = true; + target.dispatchEvent(ev); + } + }, that.options.zoom ? 250 : 0); + } + } + + that._resetPos(400); + + if (that.options.onTouchEnd) that.options.onTouchEnd.call(that, e); + return; + } + + if (duration < 300 && that.options.momentum) { + momentumX = newPosX ? that._momentum(newPosX - that.startX, duration, -that.x, that.scrollerW - that.wrapperW + that.x, that.options.bounce ? that.wrapperW : 0) : momentumX; + momentumY = newPosY ? that._momentum(newPosY - that.startY, duration, -that.y, (that.maxScrollY < 0 ? that.scrollerH - that.wrapperH + that.y - that.minScrollY : 0), that.options.bounce ? that.wrapperH : 0) : momentumY; + + newPosX = that.x + momentumX.dist; + newPosY = that.y + momentumY.dist; + + if ((that.x > 0 && newPosX > 0) || (that.x < that.maxScrollX && newPosX < that.maxScrollX)) momentumX = { dist:0, time:0 }; + if ((that.y > that.minScrollY && newPosY > that.minScrollY) || (that.y < that.maxScrollY && newPosY < that.maxScrollY)) momentumY = { dist:0, time:0 }; + } + + if (momentumX.dist || momentumY.dist) { + newDuration = m.max(m.max(momentumX.time, momentumY.time), 10); + + // Do we need to snap? + if (that.options.snap) { + distX = newPosX - that.absStartX; + distY = newPosY - that.absStartY; + if (m.abs(distX) < that.options.snapThreshold && m.abs(distY) < that.options.snapThreshold) { that.scrollTo(that.absStartX, that.absStartY, 200); } + else { + snap = that._snap(newPosX, newPosY); + newPosX = snap.x; + newPosY = snap.y; + newDuration = m.max(snap.time, newDuration); + } + } + + that.scrollTo(m.round(newPosX), m.round(newPosY), newDuration); + + if (that.options.onTouchEnd) that.options.onTouchEnd.call(that, e); + return; + } + + // Do we need to snap? + if (that.options.snap) { + distX = newPosX - that.absStartX; + distY = newPosY - that.absStartY; + if (m.abs(distX) < that.options.snapThreshold && m.abs(distY) < that.options.snapThreshold) that.scrollTo(that.absStartX, that.absStartY, 200); + else { + snap = that._snap(that.x, that.y); + if (snap.x != that.x || snap.y != that.y) that.scrollTo(snap.x, snap.y, snap.time); + } + + if (that.options.onTouchEnd) that.options.onTouchEnd.call(that, e); + return; + } + + that._resetPos(200); + if (that.options.onTouchEnd) that.options.onTouchEnd.call(that, e); + }, + + _resetPos: function (time) { + var that = this, + resetX = that.x >= 0 ? 0 : that.x < that.maxScrollX ? that.maxScrollX : that.x, + resetY = that.y >= that.minScrollY || that.maxScrollY > 0 ? that.minScrollY : that.y < that.maxScrollY ? that.maxScrollY : that.y; + + if (resetX == that.x && resetY == that.y) { + if (that.moved) { + that.moved = false; + if (that.options.onScrollEnd) that.options.onScrollEnd.call(that); // Execute custom code on scroll end + } + + if (that.hScrollbar && that.options.hideScrollbar) { + if (vendor == 'webkit') that.hScrollbarWrapper.style[transitionDelay] = '300ms'; + that.hScrollbarWrapper.style.opacity = '0'; + } + if (that.vScrollbar && that.options.hideScrollbar) { + if (vendor == 'webkit') that.vScrollbarWrapper.style[transitionDelay] = '300ms'; + that.vScrollbarWrapper.style.opacity = '0'; + } + + return; + } + + that.scrollTo(resetX, resetY, time || 0); + }, + + _wheel: function (e) { + var that = this, + wheelDeltaX, wheelDeltaY, + deltaX, deltaY, + deltaScale; + + if ('wheelDeltaX' in e) { + wheelDeltaX = e.wheelDeltaX / 12; + wheelDeltaY = e.wheelDeltaY / 12; + } else if('wheelDelta' in e) { + wheelDeltaX = wheelDeltaY = e.wheelDelta / 12; + } else if ('detail' in e) { + wheelDeltaX = wheelDeltaY = -e.detail * 3; + } else { + return; + } + + if (that.options.wheelAction == 'zoom') { + deltaScale = that.scale * Math.pow(2, 1/3 * (wheelDeltaY ? wheelDeltaY / Math.abs(wheelDeltaY) : 0)); + if (deltaScale < that.options.zoomMin) deltaScale = that.options.zoomMin; + if (deltaScale > that.options.zoomMax) deltaScale = that.options.zoomMax; + + if (deltaScale != that.scale) { + if (!that.wheelZoomCount && that.options.onZoomStart) that.options.onZoomStart.call(that, e); + that.wheelZoomCount++; + + that.zoom(e.pageX, e.pageY, deltaScale, 400); + + setTimeout(function() { + that.wheelZoomCount--; + if (!that.wheelZoomCount && that.options.onZoomEnd) that.options.onZoomEnd.call(that, e); + }, 400); + } + + return; + } + + deltaX = that.x + wheelDeltaX; + deltaY = that.y + wheelDeltaY; + + if (deltaX > 0) deltaX = 0; + else if (deltaX < that.maxScrollX) deltaX = that.maxScrollX; + + if (deltaY > that.minScrollY) deltaY = that.minScrollY; + else if (deltaY < that.maxScrollY) deltaY = that.maxScrollY; + + if (that.maxScrollY < 0) { + that.scrollTo(deltaX, deltaY, 0); + } + }, + + _transitionEnd: function (e) { + var that = this; + + if (e.target != that.scroller) return; + + that._unbind(TRNEND_EV); + + that._startAni(); + }, + + + /** + * + * Utilities + * + */ + _startAni: function () { + var that = this, + startX = that.x, startY = that.y, + startTime = Date.now(), + step, easeOut, + animate; + + if (that.animating) return; + + if (!that.steps.length) { + that._resetPos(400); + return; + } + + step = that.steps.shift(); + + if (step.x == startX && step.y == startY) step.time = 0; + + that.animating = true; + that.moved = true; + + if (that.options.useTransition) { + that._transitionTime(step.time); + that._pos(step.x, step.y); + that.animating = false; + if (step.time) that._bind(TRNEND_EV); + else that._resetPos(0); + return; + } + + animate = function () { + var now = Date.now(), + newX, newY; + + if (now >= startTime + step.time) { + that._pos(step.x, step.y); + that.animating = false; + if (that.options.onAnimationEnd) that.options.onAnimationEnd.call(that); // Execute custom code on animation end + that._startAni(); + return; + } + + now = (now - startTime) / step.time - 1; + easeOut = m.sqrt(1 - now * now); + newX = (step.x - startX) * easeOut + startX; + newY = (step.y - startY) * easeOut + startY; + that._pos(newX, newY); + if (that.animating) that.aniTime = nextFrame(animate); + }; + + animate(); + }, + + _transitionTime: function (time) { + time += 'ms'; + this.scroller.style[transitionDuration] = time; + if (this.hScrollbar) this.hScrollbarIndicator.style[transitionDuration] = time; + if (this.vScrollbar) this.vScrollbarIndicator.style[transitionDuration] = time; + }, + + _momentum: function (dist, time, maxDistUpper, maxDistLower, size) { + var deceleration = 0.0006, + speed = m.abs(dist) / time, + newDist = (speed * speed) / (2 * deceleration), + newTime = 0, outsideDist = 0; + + // Proportinally reduce speed if we are outside of the boundaries + if (dist > 0 && newDist > maxDistUpper) { + outsideDist = size / (6 / (newDist / speed * deceleration)); + maxDistUpper = maxDistUpper + outsideDist; + speed = speed * maxDistUpper / newDist; + newDist = maxDistUpper; + } else if (dist < 0 && newDist > maxDistLower) { + outsideDist = size / (6 / (newDist / speed * deceleration)); + maxDistLower = maxDistLower + outsideDist; + speed = speed * maxDistLower / newDist; + newDist = maxDistLower; + } + + newDist = newDist * (dist < 0 ? -1 : 1); + newTime = speed / deceleration; + + return { dist: newDist, time: m.round(newTime) }; + }, + + _offset: function (el) { + var left = -el.offsetLeft, + top = -el.offsetTop; + + while (el = el.offsetParent) { + left -= el.offsetLeft; + top -= el.offsetTop; + } + + if (el != this.wrapper) { + left *= this.scale; + top *= this.scale; + } + + return { left: left, top: top }; + }, + + _snap: function (x, y) { + var that = this, + i, l, + page, time, + sizeX, sizeY; + + // Check page X + page = that.pagesX.length - 1; + for (i=0, l=that.pagesX.length; i= that.pagesX[i]) { + page = i; + break; + } + } + if (page == that.currPageX && page > 0 && that.dirX < 0) page--; + x = that.pagesX[page]; + sizeX = m.abs(x - that.pagesX[that.currPageX]); + sizeX = sizeX ? m.abs(that.x - x) / sizeX * 500 : 0; + that.currPageX = page; + + // Check page Y + page = that.pagesY.length-1; + for (i=0; i= that.pagesY[i]) { + page = i; + break; + } + } + if (page == that.currPageY && page > 0 && that.dirY < 0) page--; + y = that.pagesY[page]; + sizeY = m.abs(y - that.pagesY[that.currPageY]); + sizeY = sizeY ? m.abs(that.y - y) / sizeY * 500 : 0; + that.currPageY = page; + + // Snap with constant speed (proportional duration) + time = m.round(m.max(sizeX, sizeY)) || 200; + + return { x: x, y: y, time: time }; + }, + + _bind: function (type, el, bubble) { + (el || this.scroller).addEventListener(type, this, !!bubble); + }, + + _unbind: function (type, el, bubble) { + (el || this.scroller).removeEventListener(type, this, !!bubble); + }, + + + /** + * + * Public methods + * + */ + destroy: function () { + var that = this; + + that.scroller.style[transform] = ''; + + // Remove the scrollbars + that.hScrollbar = false; + that.vScrollbar = false; + that._scrollbar('h'); + that._scrollbar('v'); + + // Remove the event listeners + that._unbind(RESIZE_EV, window); + that._unbind(START_EV); + that._unbind(MOVE_EV, window); + that._unbind(END_EV, window); + that._unbind(CANCEL_EV, window); + + if (!that.options.hasTouch) { + that._unbind('DOMMouseScroll'); + that._unbind('mousewheel'); + } + + if (that.options.useTransition) that._unbind(TRNEND_EV); + + if (that.options.checkDOMChanges) clearInterval(that.checkDOMTime); + + if (that.options.onDestroy) that.options.onDestroy.call(that); + }, + + refresh: function () { + var that = this, + offset, + i, l, + els, + pos = 0, + page = 0; + + if (that.scale < that.options.zoomMin) that.scale = that.options.zoomMin; + that.wrapperW = that.wrapper.clientWidth || 1; + that.wrapperH = that.wrapper.clientHeight || 1; + + that.minScrollY = -that.options.topOffset || 0; + that.scrollerW = m.round(that.scroller.offsetWidth * that.scale); + that.scrollerH = m.round((that.scroller.offsetHeight + that.minScrollY) * that.scale); + that.maxScrollX = that.wrapperW - that.scrollerW; + that.maxScrollY = that.wrapperH - that.scrollerH + that.minScrollY; + that.dirX = 0; + that.dirY = 0; + + if (that.options.onRefresh) that.options.onRefresh.call(that); + + that.hScroll = that.options.hScroll && that.maxScrollX < 0; + that.vScroll = that.options.vScroll && (!that.options.bounceLock && !that.hScroll || that.scrollerH > that.wrapperH); + + that.hScrollbar = that.hScroll && that.options.hScrollbar; + that.vScrollbar = that.vScroll && that.options.vScrollbar && that.scrollerH > that.wrapperH; + + offset = that._offset(that.wrapper); + that.wrapperOffsetLeft = -offset.left; + that.wrapperOffsetTop = -offset.top; + + // Prepare snap + if (typeof that.options.snap == 'string') { + that.pagesX = []; + that.pagesY = []; + els = that.scroller.querySelectorAll(that.options.snap); + for (i=0, l=els.length; i= that.maxScrollX) { + that.pagesX[page] = pos; + pos = pos - that.wrapperW; + page++; + } + if (that.maxScrollX%that.wrapperW) that.pagesX[that.pagesX.length] = that.maxScrollX - that.pagesX[that.pagesX.length-1] + that.pagesX[that.pagesX.length-1]; + + pos = 0; + page = 0; + that.pagesY = []; + while (pos >= that.maxScrollY) { + that.pagesY[page] = pos; + pos = pos - that.wrapperH; + page++; + } + if (that.maxScrollY%that.wrapperH) that.pagesY[that.pagesY.length] = that.maxScrollY - that.pagesY[that.pagesY.length-1] + that.pagesY[that.pagesY.length-1]; + } + + // Prepare the scrollbars + that._scrollbar('h'); + that._scrollbar('v'); + + if (!that.zoomed) { + that.scroller.style[transitionDuration] = '0'; + that._resetPos(400); + } + }, + + scrollTo: function (x, y, time, relative) { + var that = this, + step = x, + i, l; + + that.stop(); + + if (!step.length) step = [{ x: x, y: y, time: time, relative: relative }]; + + for (i=0, l=step.length; i 0 ? 0 : pos.left < that.maxScrollX ? that.maxScrollX : pos.left; + pos.top = pos.top > that.minScrollY ? that.minScrollY : pos.top < that.maxScrollY ? that.maxScrollY : pos.top; + time = time === undefined ? m.max(m.abs(pos.left)*2, m.abs(pos.top)*2) : time; + + that.scrollTo(pos.left, pos.top, time); + }, + + scrollToPage: function (pageX, pageY, time) { + var that = this, x, y; + + time = time === undefined ? 400 : time; + + if (that.options.onScrollStart) that.options.onScrollStart.call(that); + + if (that.options.snap) { + pageX = pageX == 'next' ? that.currPageX+1 : pageX == 'prev' ? that.currPageX-1 : pageX; + pageY = pageY == 'next' ? that.currPageY+1 : pageY == 'prev' ? that.currPageY-1 : pageY; + + pageX = pageX < 0 ? 0 : pageX > that.pagesX.length-1 ? that.pagesX.length-1 : pageX; + pageY = pageY < 0 ? 0 : pageY > that.pagesY.length-1 ? that.pagesY.length-1 : pageY; + + that.currPageX = pageX; + that.currPageY = pageY; + x = that.pagesX[pageX]; + y = that.pagesY[pageY]; + } else { + x = -that.wrapperW * pageX; + y = -that.wrapperH * pageY; + if (x < that.maxScrollX) x = that.maxScrollX; + if (y < that.maxScrollY) y = that.maxScrollY; + } + + that.scrollTo(x, y, time); + }, + + disable: function () { + this.stop(); + this._resetPos(0); + this.enabled = false; + + // If disabled after touchstart we make sure that there are no left over events + this._unbind(MOVE_EV, window); + this._unbind(END_EV, window); + this._unbind(CANCEL_EV, window); + }, + + enable: function () { + this.enabled = true; + }, + + stop: function () { + if (this.options.useTransition) this._unbind(TRNEND_EV); + else cancelFrame(this.aniTime); + this.steps = []; + this.moved = false; + this.animating = false; + }, + + zoom: function (x, y, scale, time) { + var that = this, + relScale = scale / that.scale; + + if (!that.options.useTransform) return; + + that.zoomed = true; + time = time === undefined ? 200 : time; + x = x - that.wrapperOffsetLeft - that.x; + y = y - that.wrapperOffsetTop - that.y; + that.x = x - x * relScale + that.x; + that.y = y - y * relScale + that.y; + + that.scale = scale; + that.refresh(); + + that.x = that.x > 0 ? 0 : that.x < that.maxScrollX ? that.maxScrollX : that.x; + that.y = that.y > that.minScrollY ? that.minScrollY : that.y < that.maxScrollY ? that.maxScrollY : that.y; + + that.scroller.style[transitionDuration] = time + 'ms'; + that.scroller.style[transform] = 'translate(' + that.x + 'px,' + that.y + 'px) scale(' + scale + ')' + translateZ; + that.zoomed = false; + }, + + isReady: function () { + return !this.moved && !this.zoomed && !this.animating; + } +}; + +function prefixStyle (style) { + if ( vendor === '' ) return style; + + style = style.charAt(0).toUpperCase() + style.substr(1); + return vendor + style; +} + +dummyStyle = null; // for the sake of it + +if (typeof exports !== 'undefined') exports.iScroll = iScroll; +else window.iScroll = iScroll; + +})(window, document); diff --git a/mac/TeamTalk/html/jquery-2.1.1.min.js b/mac/TeamTalk/html/jquery-2.1.1.min.js new file mode 100755 index 000000000..e5ace116b --- /dev/null +++ b/mac/TeamTalk/html/jquery-2.1.1.min.js @@ -0,0 +1,4 @@ +/*! jQuery v2.1.1 | (c) 2005, 2014 jQuery Foundation, Inc. | jquery.org/license */ +!function(a,b){"object"==typeof module&&"object"==typeof module.exports?module.exports=a.document?b(a,!0):function(a){if(!a.document)throw new Error("jQuery requires a window with a document");return b(a)}:b(a)}("undefined"!=typeof window?window:this,function(a,b){var c=[],d=c.slice,e=c.concat,f=c.push,g=c.indexOf,h={},i=h.toString,j=h.hasOwnProperty,k={},l=a.document,m="2.1.1",n=function(a,b){return new n.fn.init(a,b)},o=/^[\s\uFEFF\xA0]+|[\s\uFEFF\xA0]+$/g,p=/^-ms-/,q=/-([\da-z])/gi,r=function(a,b){return b.toUpperCase()};n.fn=n.prototype={jquery:m,constructor:n,selector:"",length:0,toArray:function(){return d.call(this)},get:function(a){return null!=a?0>a?this[a+this.length]:this[a]:d.call(this)},pushStack:function(a){var b=n.merge(this.constructor(),a);return b.prevObject=this,b.context=this.context,b},each:function(a,b){return n.each(this,a,b)},map:function(a){return this.pushStack(n.map(this,function(b,c){return a.call(b,c,b)}))},slice:function(){return this.pushStack(d.apply(this,arguments))},first:function(){return this.eq(0)},last:function(){return this.eq(-1)},eq:function(a){var b=this.length,c=+a+(0>a?b:0);return this.pushStack(c>=0&&b>c?[this[c]]:[])},end:function(){return this.prevObject||this.constructor(null)},push:f,sort:c.sort,splice:c.splice},n.extend=n.fn.extend=function(){var a,b,c,d,e,f,g=arguments[0]||{},h=1,i=arguments.length,j=!1;for("boolean"==typeof g&&(j=g,g=arguments[h]||{},h++),"object"==typeof g||n.isFunction(g)||(g={}),h===i&&(g=this,h--);i>h;h++)if(null!=(a=arguments[h]))for(b in a)c=g[b],d=a[b],g!==d&&(j&&d&&(n.isPlainObject(d)||(e=n.isArray(d)))?(e?(e=!1,f=c&&n.isArray(c)?c:[]):f=c&&n.isPlainObject(c)?c:{},g[b]=n.extend(j,f,d)):void 0!==d&&(g[b]=d));return g},n.extend({expando:"jQuery"+(m+Math.random()).replace(/\D/g,""),isReady:!0,error:function(a){throw new Error(a)},noop:function(){},isFunction:function(a){return"function"===n.type(a)},isArray:Array.isArray,isWindow:function(a){return null!=a&&a===a.window},isNumeric:function(a){return!n.isArray(a)&&a-parseFloat(a)>=0},isPlainObject:function(a){return"object"!==n.type(a)||a.nodeType||n.isWindow(a)?!1:a.constructor&&!j.call(a.constructor.prototype,"isPrototypeOf")?!1:!0},isEmptyObject:function(a){var b;for(b in a)return!1;return!0},type:function(a){return null==a?a+"":"object"==typeof a||"function"==typeof a?h[i.call(a)]||"object":typeof a},globalEval:function(a){var b,c=eval;a=n.trim(a),a&&(1===a.indexOf("use strict")?(b=l.createElement("script"),b.text=a,l.head.appendChild(b).parentNode.removeChild(b)):c(a))},camelCase:function(a){return a.replace(p,"ms-").replace(q,r)},nodeName:function(a,b){return a.nodeName&&a.nodeName.toLowerCase()===b.toLowerCase()},each:function(a,b,c){var d,e=0,f=a.length,g=s(a);if(c){if(g){for(;f>e;e++)if(d=b.apply(a[e],c),d===!1)break}else for(e in a)if(d=b.apply(a[e],c),d===!1)break}else if(g){for(;f>e;e++)if(d=b.call(a[e],e,a[e]),d===!1)break}else for(e in a)if(d=b.call(a[e],e,a[e]),d===!1)break;return a},trim:function(a){return null==a?"":(a+"").replace(o,"")},makeArray:function(a,b){var c=b||[];return null!=a&&(s(Object(a))?n.merge(c,"string"==typeof a?[a]:a):f.call(c,a)),c},inArray:function(a,b,c){return null==b?-1:g.call(b,a,c)},merge:function(a,b){for(var c=+b.length,d=0,e=a.length;c>d;d++)a[e++]=b[d];return a.length=e,a},grep:function(a,b,c){for(var d,e=[],f=0,g=a.length,h=!c;g>f;f++)d=!b(a[f],f),d!==h&&e.push(a[f]);return e},map:function(a,b,c){var d,f=0,g=a.length,h=s(a),i=[];if(h)for(;g>f;f++)d=b(a[f],f,c),null!=d&&i.push(d);else for(f in a)d=b(a[f],f,c),null!=d&&i.push(d);return e.apply([],i)},guid:1,proxy:function(a,b){var c,e,f;return"string"==typeof b&&(c=a[b],b=a,a=c),n.isFunction(a)?(e=d.call(arguments,2),f=function(){return a.apply(b||this,e.concat(d.call(arguments)))},f.guid=a.guid=a.guid||n.guid++,f):void 0},now:Date.now,support:k}),n.each("Boolean Number String Function Array Date RegExp Object Error".split(" "),function(a,b){h["[object "+b+"]"]=b.toLowerCase()});function s(a){var b=a.length,c=n.type(a);return"function"===c||n.isWindow(a)?!1:1===a.nodeType&&b?!0:"array"===c||0===b||"number"==typeof b&&b>0&&b-1 in a}var t=function(a){var b,c,d,e,f,g,h,i,j,k,l,m,n,o,p,q,r,s,t,u="sizzle"+-new Date,v=a.document,w=0,x=0,y=gb(),z=gb(),A=gb(),B=function(a,b){return a===b&&(l=!0),0},C="undefined",D=1<<31,E={}.hasOwnProperty,F=[],G=F.pop,H=F.push,I=F.push,J=F.slice,K=F.indexOf||function(a){for(var b=0,c=this.length;c>b;b++)if(this[b]===a)return b;return-1},L="checked|selected|async|autofocus|autoplay|controls|defer|disabled|hidden|ismap|loop|multiple|open|readonly|required|scoped",M="[\\x20\\t\\r\\n\\f]",N="(?:\\\\.|[\\w-]|[^\\x00-\\xa0])+",O=N.replace("w","w#"),P="\\["+M+"*("+N+")(?:"+M+"*([*^$|!~]?=)"+M+"*(?:'((?:\\\\.|[^\\\\'])*)'|\"((?:\\\\.|[^\\\\\"])*)\"|("+O+"))|)"+M+"*\\]",Q=":("+N+")(?:\\((('((?:\\\\.|[^\\\\'])*)'|\"((?:\\\\.|[^\\\\\"])*)\")|((?:\\\\.|[^\\\\()[\\]]|"+P+")*)|.*)\\)|)",R=new RegExp("^"+M+"+|((?:^|[^\\\\])(?:\\\\.)*)"+M+"+$","g"),S=new RegExp("^"+M+"*,"+M+"*"),T=new RegExp("^"+M+"*([>+~]|"+M+")"+M+"*"),U=new RegExp("="+M+"*([^\\]'\"]*?)"+M+"*\\]","g"),V=new RegExp(Q),W=new RegExp("^"+O+"$"),X={ID:new RegExp("^#("+N+")"),CLASS:new RegExp("^\\.("+N+")"),TAG:new RegExp("^("+N.replace("w","w*")+")"),ATTR:new RegExp("^"+P),PSEUDO:new RegExp("^"+Q),CHILD:new RegExp("^:(only|first|last|nth|nth-last)-(child|of-type)(?:\\("+M+"*(even|odd|(([+-]|)(\\d*)n|)"+M+"*(?:([+-]|)"+M+"*(\\d+)|))"+M+"*\\)|)","i"),bool:new RegExp("^(?:"+L+")$","i"),needsContext:new RegExp("^"+M+"*[>+~]|:(even|odd|eq|gt|lt|nth|first|last)(?:\\("+M+"*((?:-\\d)?\\d*)"+M+"*\\)|)(?=[^-]|$)","i")},Y=/^(?:input|select|textarea|button)$/i,Z=/^h\d$/i,$=/^[^{]+\{\s*\[native \w/,_=/^(?:#([\w-]+)|(\w+)|\.([\w-]+))$/,ab=/[+~]/,bb=/'|\\/g,cb=new RegExp("\\\\([\\da-f]{1,6}"+M+"?|("+M+")|.)","ig"),db=function(a,b,c){var d="0x"+b-65536;return d!==d||c?b:0>d?String.fromCharCode(d+65536):String.fromCharCode(d>>10|55296,1023&d|56320)};try{I.apply(F=J.call(v.childNodes),v.childNodes),F[v.childNodes.length].nodeType}catch(eb){I={apply:F.length?function(a,b){H.apply(a,J.call(b))}:function(a,b){var c=a.length,d=0;while(a[c++]=b[d++]);a.length=c-1}}}function fb(a,b,d,e){var f,h,j,k,l,o,r,s,w,x;if((b?b.ownerDocument||b:v)!==n&&m(b),b=b||n,d=d||[],!a||"string"!=typeof a)return d;if(1!==(k=b.nodeType)&&9!==k)return[];if(p&&!e){if(f=_.exec(a))if(j=f[1]){if(9===k){if(h=b.getElementById(j),!h||!h.parentNode)return d;if(h.id===j)return d.push(h),d}else if(b.ownerDocument&&(h=b.ownerDocument.getElementById(j))&&t(b,h)&&h.id===j)return d.push(h),d}else{if(f[2])return I.apply(d,b.getElementsByTagName(a)),d;if((j=f[3])&&c.getElementsByClassName&&b.getElementsByClassName)return I.apply(d,b.getElementsByClassName(j)),d}if(c.qsa&&(!q||!q.test(a))){if(s=r=u,w=b,x=9===k&&a,1===k&&"object"!==b.nodeName.toLowerCase()){o=g(a),(r=b.getAttribute("id"))?s=r.replace(bb,"\\$&"):b.setAttribute("id",s),s="[id='"+s+"'] ",l=o.length;while(l--)o[l]=s+qb(o[l]);w=ab.test(a)&&ob(b.parentNode)||b,x=o.join(",")}if(x)try{return I.apply(d,w.querySelectorAll(x)),d}catch(y){}finally{r||b.removeAttribute("id")}}}return i(a.replace(R,"$1"),b,d,e)}function gb(){var a=[];function b(c,e){return a.push(c+" ")>d.cacheLength&&delete b[a.shift()],b[c+" "]=e}return b}function hb(a){return a[u]=!0,a}function ib(a){var b=n.createElement("div");try{return!!a(b)}catch(c){return!1}finally{b.parentNode&&b.parentNode.removeChild(b),b=null}}function jb(a,b){var c=a.split("|"),e=a.length;while(e--)d.attrHandle[c[e]]=b}function kb(a,b){var c=b&&a,d=c&&1===a.nodeType&&1===b.nodeType&&(~b.sourceIndex||D)-(~a.sourceIndex||D);if(d)return d;if(c)while(c=c.nextSibling)if(c===b)return-1;return a?1:-1}function lb(a){return function(b){var c=b.nodeName.toLowerCase();return"input"===c&&b.type===a}}function mb(a){return function(b){var c=b.nodeName.toLowerCase();return("input"===c||"button"===c)&&b.type===a}}function nb(a){return hb(function(b){return b=+b,hb(function(c,d){var e,f=a([],c.length,b),g=f.length;while(g--)c[e=f[g]]&&(c[e]=!(d[e]=c[e]))})})}function ob(a){return a&&typeof a.getElementsByTagName!==C&&a}c=fb.support={},f=fb.isXML=function(a){var b=a&&(a.ownerDocument||a).documentElement;return b?"HTML"!==b.nodeName:!1},m=fb.setDocument=function(a){var b,e=a?a.ownerDocument||a:v,g=e.defaultView;return e!==n&&9===e.nodeType&&e.documentElement?(n=e,o=e.documentElement,p=!f(e),g&&g!==g.top&&(g.addEventListener?g.addEventListener("unload",function(){m()},!1):g.attachEvent&&g.attachEvent("onunload",function(){m()})),c.attributes=ib(function(a){return a.className="i",!a.getAttribute("className")}),c.getElementsByTagName=ib(function(a){return a.appendChild(e.createComment("")),!a.getElementsByTagName("*").length}),c.getElementsByClassName=$.test(e.getElementsByClassName)&&ib(function(a){return a.innerHTML="
",a.firstChild.className="i",2===a.getElementsByClassName("i").length}),c.getById=ib(function(a){return o.appendChild(a).id=u,!e.getElementsByName||!e.getElementsByName(u).length}),c.getById?(d.find.ID=function(a,b){if(typeof b.getElementById!==C&&p){var c=b.getElementById(a);return c&&c.parentNode?[c]:[]}},d.filter.ID=function(a){var b=a.replace(cb,db);return function(a){return a.getAttribute("id")===b}}):(delete d.find.ID,d.filter.ID=function(a){var b=a.replace(cb,db);return function(a){var c=typeof a.getAttributeNode!==C&&a.getAttributeNode("id");return c&&c.value===b}}),d.find.TAG=c.getElementsByTagName?function(a,b){return typeof b.getElementsByTagName!==C?b.getElementsByTagName(a):void 0}:function(a,b){var c,d=[],e=0,f=b.getElementsByTagName(a);if("*"===a){while(c=f[e++])1===c.nodeType&&d.push(c);return d}return f},d.find.CLASS=c.getElementsByClassName&&function(a,b){return typeof b.getElementsByClassName!==C&&p?b.getElementsByClassName(a):void 0},r=[],q=[],(c.qsa=$.test(e.querySelectorAll))&&(ib(function(a){a.innerHTML="",a.querySelectorAll("[msallowclip^='']").length&&q.push("[*^$]="+M+"*(?:''|\"\")"),a.querySelectorAll("[selected]").length||q.push("\\["+M+"*(?:value|"+L+")"),a.querySelectorAll(":checked").length||q.push(":checked")}),ib(function(a){var b=e.createElement("input");b.setAttribute("type","hidden"),a.appendChild(b).setAttribute("name","D"),a.querySelectorAll("[name=d]").length&&q.push("name"+M+"*[*^$|!~]?="),a.querySelectorAll(":enabled").length||q.push(":enabled",":disabled"),a.querySelectorAll("*,:x"),q.push(",.*:")})),(c.matchesSelector=$.test(s=o.matches||o.webkitMatchesSelector||o.mozMatchesSelector||o.oMatchesSelector||o.msMatchesSelector))&&ib(function(a){c.disconnectedMatch=s.call(a,"div"),s.call(a,"[s!='']:x"),r.push("!=",Q)}),q=q.length&&new RegExp(q.join("|")),r=r.length&&new RegExp(r.join("|")),b=$.test(o.compareDocumentPosition),t=b||$.test(o.contains)?function(a,b){var c=9===a.nodeType?a.documentElement:a,d=b&&b.parentNode;return a===d||!(!d||1!==d.nodeType||!(c.contains?c.contains(d):a.compareDocumentPosition&&16&a.compareDocumentPosition(d)))}:function(a,b){if(b)while(b=b.parentNode)if(b===a)return!0;return!1},B=b?function(a,b){if(a===b)return l=!0,0;var d=!a.compareDocumentPosition-!b.compareDocumentPosition;return d?d:(d=(a.ownerDocument||a)===(b.ownerDocument||b)?a.compareDocumentPosition(b):1,1&d||!c.sortDetached&&b.compareDocumentPosition(a)===d?a===e||a.ownerDocument===v&&t(v,a)?-1:b===e||b.ownerDocument===v&&t(v,b)?1:k?K.call(k,a)-K.call(k,b):0:4&d?-1:1)}:function(a,b){if(a===b)return l=!0,0;var c,d=0,f=a.parentNode,g=b.parentNode,h=[a],i=[b];if(!f||!g)return a===e?-1:b===e?1:f?-1:g?1:k?K.call(k,a)-K.call(k,b):0;if(f===g)return kb(a,b);c=a;while(c=c.parentNode)h.unshift(c);c=b;while(c=c.parentNode)i.unshift(c);while(h[d]===i[d])d++;return d?kb(h[d],i[d]):h[d]===v?-1:i[d]===v?1:0},e):n},fb.matches=function(a,b){return fb(a,null,null,b)},fb.matchesSelector=function(a,b){if((a.ownerDocument||a)!==n&&m(a),b=b.replace(U,"='$1']"),!(!c.matchesSelector||!p||r&&r.test(b)||q&&q.test(b)))try{var d=s.call(a,b);if(d||c.disconnectedMatch||a.document&&11!==a.document.nodeType)return d}catch(e){}return fb(b,n,null,[a]).length>0},fb.contains=function(a,b){return(a.ownerDocument||a)!==n&&m(a),t(a,b)},fb.attr=function(a,b){(a.ownerDocument||a)!==n&&m(a);var e=d.attrHandle[b.toLowerCase()],f=e&&E.call(d.attrHandle,b.toLowerCase())?e(a,b,!p):void 0;return void 0!==f?f:c.attributes||!p?a.getAttribute(b):(f=a.getAttributeNode(b))&&f.specified?f.value:null},fb.error=function(a){throw new Error("Syntax error, unrecognized expression: "+a)},fb.uniqueSort=function(a){var b,d=[],e=0,f=0;if(l=!c.detectDuplicates,k=!c.sortStable&&a.slice(0),a.sort(B),l){while(b=a[f++])b===a[f]&&(e=d.push(f));while(e--)a.splice(d[e],1)}return k=null,a},e=fb.getText=function(a){var b,c="",d=0,f=a.nodeType;if(f){if(1===f||9===f||11===f){if("string"==typeof a.textContent)return a.textContent;for(a=a.firstChild;a;a=a.nextSibling)c+=e(a)}else if(3===f||4===f)return a.nodeValue}else while(b=a[d++])c+=e(b);return c},d=fb.selectors={cacheLength:50,createPseudo:hb,match:X,attrHandle:{},find:{},relative:{">":{dir:"parentNode",first:!0}," ":{dir:"parentNode"},"+":{dir:"previousSibling",first:!0},"~":{dir:"previousSibling"}},preFilter:{ATTR:function(a){return a[1]=a[1].replace(cb,db),a[3]=(a[3]||a[4]||a[5]||"").replace(cb,db),"~="===a[2]&&(a[3]=" "+a[3]+" "),a.slice(0,4)},CHILD:function(a){return a[1]=a[1].toLowerCase(),"nth"===a[1].slice(0,3)?(a[3]||fb.error(a[0]),a[4]=+(a[4]?a[5]+(a[6]||1):2*("even"===a[3]||"odd"===a[3])),a[5]=+(a[7]+a[8]||"odd"===a[3])):a[3]&&fb.error(a[0]),a},PSEUDO:function(a){var b,c=!a[6]&&a[2];return X.CHILD.test(a[0])?null:(a[3]?a[2]=a[4]||a[5]||"":c&&V.test(c)&&(b=g(c,!0))&&(b=c.indexOf(")",c.length-b)-c.length)&&(a[0]=a[0].slice(0,b),a[2]=c.slice(0,b)),a.slice(0,3))}},filter:{TAG:function(a){var b=a.replace(cb,db).toLowerCase();return"*"===a?function(){return!0}:function(a){return a.nodeName&&a.nodeName.toLowerCase()===b}},CLASS:function(a){var b=y[a+" "];return b||(b=new RegExp("(^|"+M+")"+a+"("+M+"|$)"))&&y(a,function(a){return b.test("string"==typeof a.className&&a.className||typeof a.getAttribute!==C&&a.getAttribute("class")||"")})},ATTR:function(a,b,c){return function(d){var e=fb.attr(d,a);return null==e?"!="===b:b?(e+="","="===b?e===c:"!="===b?e!==c:"^="===b?c&&0===e.indexOf(c):"*="===b?c&&e.indexOf(c)>-1:"$="===b?c&&e.slice(-c.length)===c:"~="===b?(" "+e+" ").indexOf(c)>-1:"|="===b?e===c||e.slice(0,c.length+1)===c+"-":!1):!0}},CHILD:function(a,b,c,d,e){var f="nth"!==a.slice(0,3),g="last"!==a.slice(-4),h="of-type"===b;return 1===d&&0===e?function(a){return!!a.parentNode}:function(b,c,i){var j,k,l,m,n,o,p=f!==g?"nextSibling":"previousSibling",q=b.parentNode,r=h&&b.nodeName.toLowerCase(),s=!i&&!h;if(q){if(f){while(p){l=b;while(l=l[p])if(h?l.nodeName.toLowerCase()===r:1===l.nodeType)return!1;o=p="only"===a&&!o&&"nextSibling"}return!0}if(o=[g?q.firstChild:q.lastChild],g&&s){k=q[u]||(q[u]={}),j=k[a]||[],n=j[0]===w&&j[1],m=j[0]===w&&j[2],l=n&&q.childNodes[n];while(l=++n&&l&&l[p]||(m=n=0)||o.pop())if(1===l.nodeType&&++m&&l===b){k[a]=[w,n,m];break}}else if(s&&(j=(b[u]||(b[u]={}))[a])&&j[0]===w)m=j[1];else while(l=++n&&l&&l[p]||(m=n=0)||o.pop())if((h?l.nodeName.toLowerCase()===r:1===l.nodeType)&&++m&&(s&&((l[u]||(l[u]={}))[a]=[w,m]),l===b))break;return m-=e,m===d||m%d===0&&m/d>=0}}},PSEUDO:function(a,b){var c,e=d.pseudos[a]||d.setFilters[a.toLowerCase()]||fb.error("unsupported pseudo: "+a);return e[u]?e(b):e.length>1?(c=[a,a,"",b],d.setFilters.hasOwnProperty(a.toLowerCase())?hb(function(a,c){var d,f=e(a,b),g=f.length;while(g--)d=K.call(a,f[g]),a[d]=!(c[d]=f[g])}):function(a){return e(a,0,c)}):e}},pseudos:{not:hb(function(a){var b=[],c=[],d=h(a.replace(R,"$1"));return d[u]?hb(function(a,b,c,e){var f,g=d(a,null,e,[]),h=a.length;while(h--)(f=g[h])&&(a[h]=!(b[h]=f))}):function(a,e,f){return b[0]=a,d(b,null,f,c),!c.pop()}}),has:hb(function(a){return function(b){return fb(a,b).length>0}}),contains:hb(function(a){return function(b){return(b.textContent||b.innerText||e(b)).indexOf(a)>-1}}),lang:hb(function(a){return W.test(a||"")||fb.error("unsupported lang: "+a),a=a.replace(cb,db).toLowerCase(),function(b){var c;do if(c=p?b.lang:b.getAttribute("xml:lang")||b.getAttribute("lang"))return c=c.toLowerCase(),c===a||0===c.indexOf(a+"-");while((b=b.parentNode)&&1===b.nodeType);return!1}}),target:function(b){var c=a.location&&a.location.hash;return c&&c.slice(1)===b.id},root:function(a){return a===o},focus:function(a){return a===n.activeElement&&(!n.hasFocus||n.hasFocus())&&!!(a.type||a.href||~a.tabIndex)},enabled:function(a){return a.disabled===!1},disabled:function(a){return a.disabled===!0},checked:function(a){var b=a.nodeName.toLowerCase();return"input"===b&&!!a.checked||"option"===b&&!!a.selected},selected:function(a){return a.parentNode&&a.parentNode.selectedIndex,a.selected===!0},empty:function(a){for(a=a.firstChild;a;a=a.nextSibling)if(a.nodeType<6)return!1;return!0},parent:function(a){return!d.pseudos.empty(a)},header:function(a){return Z.test(a.nodeName)},input:function(a){return Y.test(a.nodeName)},button:function(a){var b=a.nodeName.toLowerCase();return"input"===b&&"button"===a.type||"button"===b},text:function(a){var b;return"input"===a.nodeName.toLowerCase()&&"text"===a.type&&(null==(b=a.getAttribute("type"))||"text"===b.toLowerCase())},first:nb(function(){return[0]}),last:nb(function(a,b){return[b-1]}),eq:nb(function(a,b,c){return[0>c?c+b:c]}),even:nb(function(a,b){for(var c=0;b>c;c+=2)a.push(c);return a}),odd:nb(function(a,b){for(var c=1;b>c;c+=2)a.push(c);return a}),lt:nb(function(a,b,c){for(var d=0>c?c+b:c;--d>=0;)a.push(d);return a}),gt:nb(function(a,b,c){for(var d=0>c?c+b:c;++db;b++)d+=a[b].value;return d}function rb(a,b,c){var d=b.dir,e=c&&"parentNode"===d,f=x++;return b.first?function(b,c,f){while(b=b[d])if(1===b.nodeType||e)return a(b,c,f)}:function(b,c,g){var h,i,j=[w,f];if(g){while(b=b[d])if((1===b.nodeType||e)&&a(b,c,g))return!0}else while(b=b[d])if(1===b.nodeType||e){if(i=b[u]||(b[u]={}),(h=i[d])&&h[0]===w&&h[1]===f)return j[2]=h[2];if(i[d]=j,j[2]=a(b,c,g))return!0}}}function sb(a){return a.length>1?function(b,c,d){var e=a.length;while(e--)if(!a[e](b,c,d))return!1;return!0}:a[0]}function tb(a,b,c){for(var d=0,e=b.length;e>d;d++)fb(a,b[d],c);return c}function ub(a,b,c,d,e){for(var f,g=[],h=0,i=a.length,j=null!=b;i>h;h++)(f=a[h])&&(!c||c(f,d,e))&&(g.push(f),j&&b.push(h));return g}function vb(a,b,c,d,e,f){return d&&!d[u]&&(d=vb(d)),e&&!e[u]&&(e=vb(e,f)),hb(function(f,g,h,i){var j,k,l,m=[],n=[],o=g.length,p=f||tb(b||"*",h.nodeType?[h]:h,[]),q=!a||!f&&b?p:ub(p,m,a,h,i),r=c?e||(f?a:o||d)?[]:g:q;if(c&&c(q,r,h,i),d){j=ub(r,n),d(j,[],h,i),k=j.length;while(k--)(l=j[k])&&(r[n[k]]=!(q[n[k]]=l))}if(f){if(e||a){if(e){j=[],k=r.length;while(k--)(l=r[k])&&j.push(q[k]=l);e(null,r=[],j,i)}k=r.length;while(k--)(l=r[k])&&(j=e?K.call(f,l):m[k])>-1&&(f[j]=!(g[j]=l))}}else r=ub(r===g?r.splice(o,r.length):r),e?e(null,g,r,i):I.apply(g,r)})}function wb(a){for(var b,c,e,f=a.length,g=d.relative[a[0].type],h=g||d.relative[" "],i=g?1:0,k=rb(function(a){return a===b},h,!0),l=rb(function(a){return K.call(b,a)>-1},h,!0),m=[function(a,c,d){return!g&&(d||c!==j)||((b=c).nodeType?k(a,c,d):l(a,c,d))}];f>i;i++)if(c=d.relative[a[i].type])m=[rb(sb(m),c)];else{if(c=d.filter[a[i].type].apply(null,a[i].matches),c[u]){for(e=++i;f>e;e++)if(d.relative[a[e].type])break;return vb(i>1&&sb(m),i>1&&qb(a.slice(0,i-1).concat({value:" "===a[i-2].type?"*":""})).replace(R,"$1"),c,e>i&&wb(a.slice(i,e)),f>e&&wb(a=a.slice(e)),f>e&&qb(a))}m.push(c)}return sb(m)}function xb(a,b){var c=b.length>0,e=a.length>0,f=function(f,g,h,i,k){var l,m,o,p=0,q="0",r=f&&[],s=[],t=j,u=f||e&&d.find.TAG("*",k),v=w+=null==t?1:Math.random()||.1,x=u.length;for(k&&(j=g!==n&&g);q!==x&&null!=(l=u[q]);q++){if(e&&l){m=0;while(o=a[m++])if(o(l,g,h)){i.push(l);break}k&&(w=v)}c&&((l=!o&&l)&&p--,f&&r.push(l))}if(p+=q,c&&q!==p){m=0;while(o=b[m++])o(r,s,g,h);if(f){if(p>0)while(q--)r[q]||s[q]||(s[q]=G.call(i));s=ub(s)}I.apply(i,s),k&&!f&&s.length>0&&p+b.length>1&&fb.uniqueSort(i)}return k&&(w=v,j=t),r};return c?hb(f):f}return h=fb.compile=function(a,b){var c,d=[],e=[],f=A[a+" "];if(!f){b||(b=g(a)),c=b.length;while(c--)f=wb(b[c]),f[u]?d.push(f):e.push(f);f=A(a,xb(e,d)),f.selector=a}return f},i=fb.select=function(a,b,e,f){var i,j,k,l,m,n="function"==typeof a&&a,o=!f&&g(a=n.selector||a);if(e=e||[],1===o.length){if(j=o[0]=o[0].slice(0),j.length>2&&"ID"===(k=j[0]).type&&c.getById&&9===b.nodeType&&p&&d.relative[j[1].type]){if(b=(d.find.ID(k.matches[0].replace(cb,db),b)||[])[0],!b)return e;n&&(b=b.parentNode),a=a.slice(j.shift().value.length)}i=X.needsContext.test(a)?0:j.length;while(i--){if(k=j[i],d.relative[l=k.type])break;if((m=d.find[l])&&(f=m(k.matches[0].replace(cb,db),ab.test(j[0].type)&&ob(b.parentNode)||b))){if(j.splice(i,1),a=f.length&&qb(j),!a)return I.apply(e,f),e;break}}}return(n||h(a,o))(f,b,!p,e,ab.test(a)&&ob(b.parentNode)||b),e},c.sortStable=u.split("").sort(B).join("")===u,c.detectDuplicates=!!l,m(),c.sortDetached=ib(function(a){return 1&a.compareDocumentPosition(n.createElement("div"))}),ib(function(a){return a.innerHTML="","#"===a.firstChild.getAttribute("href")})||jb("type|href|height|width",function(a,b,c){return c?void 0:a.getAttribute(b,"type"===b.toLowerCase()?1:2)}),c.attributes&&ib(function(a){return a.innerHTML="",a.firstChild.setAttribute("value",""),""===a.firstChild.getAttribute("value")})||jb("value",function(a,b,c){return c||"input"!==a.nodeName.toLowerCase()?void 0:a.defaultValue}),ib(function(a){return null==a.getAttribute("disabled")})||jb(L,function(a,b,c){var d;return c?void 0:a[b]===!0?b.toLowerCase():(d=a.getAttributeNode(b))&&d.specified?d.value:null}),fb}(a);n.find=t,n.expr=t.selectors,n.expr[":"]=n.expr.pseudos,n.unique=t.uniqueSort,n.text=t.getText,n.isXMLDoc=t.isXML,n.contains=t.contains;var u=n.expr.match.needsContext,v=/^<(\w+)\s*\/?>(?:<\/\1>|)$/,w=/^.[^:#\[\.,]*$/;function x(a,b,c){if(n.isFunction(b))return n.grep(a,function(a,d){return!!b.call(a,d,a)!==c});if(b.nodeType)return n.grep(a,function(a){return a===b!==c});if("string"==typeof b){if(w.test(b))return n.filter(b,a,c);b=n.filter(b,a)}return n.grep(a,function(a){return g.call(b,a)>=0!==c})}n.filter=function(a,b,c){var d=b[0];return c&&(a=":not("+a+")"),1===b.length&&1===d.nodeType?n.find.matchesSelector(d,a)?[d]:[]:n.find.matches(a,n.grep(b,function(a){return 1===a.nodeType}))},n.fn.extend({find:function(a){var b,c=this.length,d=[],e=this;if("string"!=typeof a)return this.pushStack(n(a).filter(function(){for(b=0;c>b;b++)if(n.contains(e[b],this))return!0}));for(b=0;c>b;b++)n.find(a,e[b],d);return d=this.pushStack(c>1?n.unique(d):d),d.selector=this.selector?this.selector+" "+a:a,d},filter:function(a){return this.pushStack(x(this,a||[],!1))},not:function(a){return this.pushStack(x(this,a||[],!0))},is:function(a){return!!x(this,"string"==typeof a&&u.test(a)?n(a):a||[],!1).length}});var y,z=/^(?:\s*(<[\w\W]+>)[^>]*|#([\w-]*))$/,A=n.fn.init=function(a,b){var c,d;if(!a)return this;if("string"==typeof a){if(c="<"===a[0]&&">"===a[a.length-1]&&a.length>=3?[null,a,null]:z.exec(a),!c||!c[1]&&b)return!b||b.jquery?(b||y).find(a):this.constructor(b).find(a);if(c[1]){if(b=b instanceof n?b[0]:b,n.merge(this,n.parseHTML(c[1],b&&b.nodeType?b.ownerDocument||b:l,!0)),v.test(c[1])&&n.isPlainObject(b))for(c in b)n.isFunction(this[c])?this[c](b[c]):this.attr(c,b[c]);return this}return d=l.getElementById(c[2]),d&&d.parentNode&&(this.length=1,this[0]=d),this.context=l,this.selector=a,this}return a.nodeType?(this.context=this[0]=a,this.length=1,this):n.isFunction(a)?"undefined"!=typeof y.ready?y.ready(a):a(n):(void 0!==a.selector&&(this.selector=a.selector,this.context=a.context),n.makeArray(a,this))};A.prototype=n.fn,y=n(l);var B=/^(?:parents|prev(?:Until|All))/,C={children:!0,contents:!0,next:!0,prev:!0};n.extend({dir:function(a,b,c){var d=[],e=void 0!==c;while((a=a[b])&&9!==a.nodeType)if(1===a.nodeType){if(e&&n(a).is(c))break;d.push(a)}return d},sibling:function(a,b){for(var c=[];a;a=a.nextSibling)1===a.nodeType&&a!==b&&c.push(a);return c}}),n.fn.extend({has:function(a){var b=n(a,this),c=b.length;return this.filter(function(){for(var a=0;c>a;a++)if(n.contains(this,b[a]))return!0})},closest:function(a,b){for(var c,d=0,e=this.length,f=[],g=u.test(a)||"string"!=typeof a?n(a,b||this.context):0;e>d;d++)for(c=this[d];c&&c!==b;c=c.parentNode)if(c.nodeType<11&&(g?g.index(c)>-1:1===c.nodeType&&n.find.matchesSelector(c,a))){f.push(c);break}return this.pushStack(f.length>1?n.unique(f):f)},index:function(a){return a?"string"==typeof a?g.call(n(a),this[0]):g.call(this,a.jquery?a[0]:a):this[0]&&this[0].parentNode?this.first().prevAll().length:-1},add:function(a,b){return this.pushStack(n.unique(n.merge(this.get(),n(a,b))))},addBack:function(a){return this.add(null==a?this.prevObject:this.prevObject.filter(a))}});function D(a,b){while((a=a[b])&&1!==a.nodeType);return a}n.each({parent:function(a){var b=a.parentNode;return b&&11!==b.nodeType?b:null},parents:function(a){return n.dir(a,"parentNode")},parentsUntil:function(a,b,c){return n.dir(a,"parentNode",c)},next:function(a){return D(a,"nextSibling")},prev:function(a){return D(a,"previousSibling")},nextAll:function(a){return n.dir(a,"nextSibling")},prevAll:function(a){return n.dir(a,"previousSibling")},nextUntil:function(a,b,c){return n.dir(a,"nextSibling",c)},prevUntil:function(a,b,c){return n.dir(a,"previousSibling",c)},siblings:function(a){return n.sibling((a.parentNode||{}).firstChild,a)},children:function(a){return n.sibling(a.firstChild)},contents:function(a){return a.contentDocument||n.merge([],a.childNodes)}},function(a,b){n.fn[a]=function(c,d){var e=n.map(this,b,c);return"Until"!==a.slice(-5)&&(d=c),d&&"string"==typeof d&&(e=n.filter(d,e)),this.length>1&&(C[a]||n.unique(e),B.test(a)&&e.reverse()),this.pushStack(e)}});var E=/\S+/g,F={};function G(a){var b=F[a]={};return n.each(a.match(E)||[],function(a,c){b[c]=!0}),b}n.Callbacks=function(a){a="string"==typeof a?F[a]||G(a):n.extend({},a);var b,c,d,e,f,g,h=[],i=!a.once&&[],j=function(l){for(b=a.memory&&l,c=!0,g=e||0,e=0,f=h.length,d=!0;h&&f>g;g++)if(h[g].apply(l[0],l[1])===!1&&a.stopOnFalse){b=!1;break}d=!1,h&&(i?i.length&&j(i.shift()):b?h=[]:k.disable())},k={add:function(){if(h){var c=h.length;!function g(b){n.each(b,function(b,c){var d=n.type(c);"function"===d?a.unique&&k.has(c)||h.push(c):c&&c.length&&"string"!==d&&g(c)})}(arguments),d?f=h.length:b&&(e=c,j(b))}return this},remove:function(){return h&&n.each(arguments,function(a,b){var c;while((c=n.inArray(b,h,c))>-1)h.splice(c,1),d&&(f>=c&&f--,g>=c&&g--)}),this},has:function(a){return a?n.inArray(a,h)>-1:!(!h||!h.length)},empty:function(){return h=[],f=0,this},disable:function(){return h=i=b=void 0,this},disabled:function(){return!h},lock:function(){return i=void 0,b||k.disable(),this},locked:function(){return!i},fireWith:function(a,b){return!h||c&&!i||(b=b||[],b=[a,b.slice?b.slice():b],d?i.push(b):j(b)),this},fire:function(){return k.fireWith(this,arguments),this},fired:function(){return!!c}};return k},n.extend({Deferred:function(a){var b=[["resolve","done",n.Callbacks("once memory"),"resolved"],["reject","fail",n.Callbacks("once memory"),"rejected"],["notify","progress",n.Callbacks("memory")]],c="pending",d={state:function(){return c},always:function(){return e.done(arguments).fail(arguments),this},then:function(){var a=arguments;return n.Deferred(function(c){n.each(b,function(b,f){var g=n.isFunction(a[b])&&a[b];e[f[1]](function(){var a=g&&g.apply(this,arguments);a&&n.isFunction(a.promise)?a.promise().done(c.resolve).fail(c.reject).progress(c.notify):c[f[0]+"With"](this===d?c.promise():this,g?[a]:arguments)})}),a=null}).promise()},promise:function(a){return null!=a?n.extend(a,d):d}},e={};return d.pipe=d.then,n.each(b,function(a,f){var g=f[2],h=f[3];d[f[1]]=g.add,h&&g.add(function(){c=h},b[1^a][2].disable,b[2][2].lock),e[f[0]]=function(){return e[f[0]+"With"](this===e?d:this,arguments),this},e[f[0]+"With"]=g.fireWith}),d.promise(e),a&&a.call(e,e),e},when:function(a){var b=0,c=d.call(arguments),e=c.length,f=1!==e||a&&n.isFunction(a.promise)?e:0,g=1===f?a:n.Deferred(),h=function(a,b,c){return function(e){b[a]=this,c[a]=arguments.length>1?d.call(arguments):e,c===i?g.notifyWith(b,c):--f||g.resolveWith(b,c)}},i,j,k;if(e>1)for(i=new Array(e),j=new Array(e),k=new Array(e);e>b;b++)c[b]&&n.isFunction(c[b].promise)?c[b].promise().done(h(b,k,c)).fail(g.reject).progress(h(b,j,i)):--f;return f||g.resolveWith(k,c),g.promise()}});var H;n.fn.ready=function(a){return n.ready.promise().done(a),this},n.extend({isReady:!1,readyWait:1,holdReady:function(a){a?n.readyWait++:n.ready(!0)},ready:function(a){(a===!0?--n.readyWait:n.isReady)||(n.isReady=!0,a!==!0&&--n.readyWait>0||(H.resolveWith(l,[n]),n.fn.triggerHandler&&(n(l).triggerHandler("ready"),n(l).off("ready"))))}});function I(){l.removeEventListener("DOMContentLoaded",I,!1),a.removeEventListener("load",I,!1),n.ready()}n.ready.promise=function(b){return H||(H=n.Deferred(),"complete"===l.readyState?setTimeout(n.ready):(l.addEventListener("DOMContentLoaded",I,!1),a.addEventListener("load",I,!1))),H.promise(b)},n.ready.promise();var J=n.access=function(a,b,c,d,e,f,g){var h=0,i=a.length,j=null==c;if("object"===n.type(c)){e=!0;for(h in c)n.access(a,b,h,c[h],!0,f,g)}else if(void 0!==d&&(e=!0,n.isFunction(d)||(g=!0),j&&(g?(b.call(a,d),b=null):(j=b,b=function(a,b,c){return j.call(n(a),c)})),b))for(;i>h;h++)b(a[h],c,g?d:d.call(a[h],h,b(a[h],c)));return e?a:j?b.call(a):i?b(a[0],c):f};n.acceptData=function(a){return 1===a.nodeType||9===a.nodeType||!+a.nodeType};function K(){Object.defineProperty(this.cache={},0,{get:function(){return{}}}),this.expando=n.expando+Math.random()}K.uid=1,K.accepts=n.acceptData,K.prototype={key:function(a){if(!K.accepts(a))return 0;var b={},c=a[this.expando];if(!c){c=K.uid++;try{b[this.expando]={value:c},Object.defineProperties(a,b)}catch(d){b[this.expando]=c,n.extend(a,b)}}return this.cache[c]||(this.cache[c]={}),c},set:function(a,b,c){var d,e=this.key(a),f=this.cache[e];if("string"==typeof b)f[b]=c;else if(n.isEmptyObject(f))n.extend(this.cache[e],b);else for(d in b)f[d]=b[d];return f},get:function(a,b){var c=this.cache[this.key(a)];return void 0===b?c:c[b]},access:function(a,b,c){var d;return void 0===b||b&&"string"==typeof b&&void 0===c?(d=this.get(a,b),void 0!==d?d:this.get(a,n.camelCase(b))):(this.set(a,b,c),void 0!==c?c:b)},remove:function(a,b){var c,d,e,f=this.key(a),g=this.cache[f];if(void 0===b)this.cache[f]={};else{n.isArray(b)?d=b.concat(b.map(n.camelCase)):(e=n.camelCase(b),b in g?d=[b,e]:(d=e,d=d in g?[d]:d.match(E)||[])),c=d.length;while(c--)delete g[d[c]]}},hasData:function(a){return!n.isEmptyObject(this.cache[a[this.expando]]||{})},discard:function(a){a[this.expando]&&delete this.cache[a[this.expando]]}};var L=new K,M=new K,N=/^(?:\{[\w\W]*\}|\[[\w\W]*\])$/,O=/([A-Z])/g;function P(a,b,c){var d;if(void 0===c&&1===a.nodeType)if(d="data-"+b.replace(O,"-$1").toLowerCase(),c=a.getAttribute(d),"string"==typeof c){try{c="true"===c?!0:"false"===c?!1:"null"===c?null:+c+""===c?+c:N.test(c)?n.parseJSON(c):c}catch(e){}M.set(a,b,c)}else c=void 0;return c}n.extend({hasData:function(a){return M.hasData(a)||L.hasData(a)},data:function(a,b,c){return M.access(a,b,c)},removeData:function(a,b){M.remove(a,b) +},_data:function(a,b,c){return L.access(a,b,c)},_removeData:function(a,b){L.remove(a,b)}}),n.fn.extend({data:function(a,b){var c,d,e,f=this[0],g=f&&f.attributes;if(void 0===a){if(this.length&&(e=M.get(f),1===f.nodeType&&!L.get(f,"hasDataAttrs"))){c=g.length;while(c--)g[c]&&(d=g[c].name,0===d.indexOf("data-")&&(d=n.camelCase(d.slice(5)),P(f,d,e[d])));L.set(f,"hasDataAttrs",!0)}return e}return"object"==typeof a?this.each(function(){M.set(this,a)}):J(this,function(b){var c,d=n.camelCase(a);if(f&&void 0===b){if(c=M.get(f,a),void 0!==c)return c;if(c=M.get(f,d),void 0!==c)return c;if(c=P(f,d,void 0),void 0!==c)return c}else this.each(function(){var c=M.get(this,d);M.set(this,d,b),-1!==a.indexOf("-")&&void 0!==c&&M.set(this,a,b)})},null,b,arguments.length>1,null,!0)},removeData:function(a){return this.each(function(){M.remove(this,a)})}}),n.extend({queue:function(a,b,c){var d;return a?(b=(b||"fx")+"queue",d=L.get(a,b),c&&(!d||n.isArray(c)?d=L.access(a,b,n.makeArray(c)):d.push(c)),d||[]):void 0},dequeue:function(a,b){b=b||"fx";var c=n.queue(a,b),d=c.length,e=c.shift(),f=n._queueHooks(a,b),g=function(){n.dequeue(a,b)};"inprogress"===e&&(e=c.shift(),d--),e&&("fx"===b&&c.unshift("inprogress"),delete f.stop,e.call(a,g,f)),!d&&f&&f.empty.fire()},_queueHooks:function(a,b){var c=b+"queueHooks";return L.get(a,c)||L.access(a,c,{empty:n.Callbacks("once memory").add(function(){L.remove(a,[b+"queue",c])})})}}),n.fn.extend({queue:function(a,b){var c=2;return"string"!=typeof a&&(b=a,a="fx",c--),arguments.lengthx",k.noCloneChecked=!!b.cloneNode(!0).lastChild.defaultValue}();var U="undefined";k.focusinBubbles="onfocusin"in a;var V=/^key/,W=/^(?:mouse|pointer|contextmenu)|click/,X=/^(?:focusinfocus|focusoutblur)$/,Y=/^([^.]*)(?:\.(.+)|)$/;function Z(){return!0}function $(){return!1}function _(){try{return l.activeElement}catch(a){}}n.event={global:{},add:function(a,b,c,d,e){var f,g,h,i,j,k,l,m,o,p,q,r=L.get(a);if(r){c.handler&&(f=c,c=f.handler,e=f.selector),c.guid||(c.guid=n.guid++),(i=r.events)||(i=r.events={}),(g=r.handle)||(g=r.handle=function(b){return typeof n!==U&&n.event.triggered!==b.type?n.event.dispatch.apply(a,arguments):void 0}),b=(b||"").match(E)||[""],j=b.length;while(j--)h=Y.exec(b[j])||[],o=q=h[1],p=(h[2]||"").split(".").sort(),o&&(l=n.event.special[o]||{},o=(e?l.delegateType:l.bindType)||o,l=n.event.special[o]||{},k=n.extend({type:o,origType:q,data:d,handler:c,guid:c.guid,selector:e,needsContext:e&&n.expr.match.needsContext.test(e),namespace:p.join(".")},f),(m=i[o])||(m=i[o]=[],m.delegateCount=0,l.setup&&l.setup.call(a,d,p,g)!==!1||a.addEventListener&&a.addEventListener(o,g,!1)),l.add&&(l.add.call(a,k),k.handler.guid||(k.handler.guid=c.guid)),e?m.splice(m.delegateCount++,0,k):m.push(k),n.event.global[o]=!0)}},remove:function(a,b,c,d,e){var f,g,h,i,j,k,l,m,o,p,q,r=L.hasData(a)&&L.get(a);if(r&&(i=r.events)){b=(b||"").match(E)||[""],j=b.length;while(j--)if(h=Y.exec(b[j])||[],o=q=h[1],p=(h[2]||"").split(".").sort(),o){l=n.event.special[o]||{},o=(d?l.delegateType:l.bindType)||o,m=i[o]||[],h=h[2]&&new RegExp("(^|\\.)"+p.join("\\.(?:.*\\.|)")+"(\\.|$)"),g=f=m.length;while(f--)k=m[f],!e&&q!==k.origType||c&&c.guid!==k.guid||h&&!h.test(k.namespace)||d&&d!==k.selector&&("**"!==d||!k.selector)||(m.splice(f,1),k.selector&&m.delegateCount--,l.remove&&l.remove.call(a,k));g&&!m.length&&(l.teardown&&l.teardown.call(a,p,r.handle)!==!1||n.removeEvent(a,o,r.handle),delete i[o])}else for(o in i)n.event.remove(a,o+b[j],c,d,!0);n.isEmptyObject(i)&&(delete r.handle,L.remove(a,"events"))}},trigger:function(b,c,d,e){var f,g,h,i,k,m,o,p=[d||l],q=j.call(b,"type")?b.type:b,r=j.call(b,"namespace")?b.namespace.split("."):[];if(g=h=d=d||l,3!==d.nodeType&&8!==d.nodeType&&!X.test(q+n.event.triggered)&&(q.indexOf(".")>=0&&(r=q.split("."),q=r.shift(),r.sort()),k=q.indexOf(":")<0&&"on"+q,b=b[n.expando]?b:new n.Event(q,"object"==typeof b&&b),b.isTrigger=e?2:3,b.namespace=r.join("."),b.namespace_re=b.namespace?new RegExp("(^|\\.)"+r.join("\\.(?:.*\\.|)")+"(\\.|$)"):null,b.result=void 0,b.target||(b.target=d),c=null==c?[b]:n.makeArray(c,[b]),o=n.event.special[q]||{},e||!o.trigger||o.trigger.apply(d,c)!==!1)){if(!e&&!o.noBubble&&!n.isWindow(d)){for(i=o.delegateType||q,X.test(i+q)||(g=g.parentNode);g;g=g.parentNode)p.push(g),h=g;h===(d.ownerDocument||l)&&p.push(h.defaultView||h.parentWindow||a)}f=0;while((g=p[f++])&&!b.isPropagationStopped())b.type=f>1?i:o.bindType||q,m=(L.get(g,"events")||{})[b.type]&&L.get(g,"handle"),m&&m.apply(g,c),m=k&&g[k],m&&m.apply&&n.acceptData(g)&&(b.result=m.apply(g,c),b.result===!1&&b.preventDefault());return b.type=q,e||b.isDefaultPrevented()||o._default&&o._default.apply(p.pop(),c)!==!1||!n.acceptData(d)||k&&n.isFunction(d[q])&&!n.isWindow(d)&&(h=d[k],h&&(d[k]=null),n.event.triggered=q,d[q](),n.event.triggered=void 0,h&&(d[k]=h)),b.result}},dispatch:function(a){a=n.event.fix(a);var b,c,e,f,g,h=[],i=d.call(arguments),j=(L.get(this,"events")||{})[a.type]||[],k=n.event.special[a.type]||{};if(i[0]=a,a.delegateTarget=this,!k.preDispatch||k.preDispatch.call(this,a)!==!1){h=n.event.handlers.call(this,a,j),b=0;while((f=h[b++])&&!a.isPropagationStopped()){a.currentTarget=f.elem,c=0;while((g=f.handlers[c++])&&!a.isImmediatePropagationStopped())(!a.namespace_re||a.namespace_re.test(g.namespace))&&(a.handleObj=g,a.data=g.data,e=((n.event.special[g.origType]||{}).handle||g.handler).apply(f.elem,i),void 0!==e&&(a.result=e)===!1&&(a.preventDefault(),a.stopPropagation()))}return k.postDispatch&&k.postDispatch.call(this,a),a.result}},handlers:function(a,b){var c,d,e,f,g=[],h=b.delegateCount,i=a.target;if(h&&i.nodeType&&(!a.button||"click"!==a.type))for(;i!==this;i=i.parentNode||this)if(i.disabled!==!0||"click"!==a.type){for(d=[],c=0;h>c;c++)f=b[c],e=f.selector+" ",void 0===d[e]&&(d[e]=f.needsContext?n(e,this).index(i)>=0:n.find(e,this,null,[i]).length),d[e]&&d.push(f);d.length&&g.push({elem:i,handlers:d})}return h]*)\/>/gi,bb=/<([\w:]+)/,cb=/<|&#?\w+;/,db=/<(?:script|style|link)/i,eb=/checked\s*(?:[^=]|=\s*.checked.)/i,fb=/^$|\/(?:java|ecma)script/i,gb=/^true\/(.*)/,hb=/^\s*\s*$/g,ib={option:[1,""],thead:[1,"","
"],col:[2,"","
"],tr:[2,"","
"],td:[3,"","
"],_default:[0,"",""]};ib.optgroup=ib.option,ib.tbody=ib.tfoot=ib.colgroup=ib.caption=ib.thead,ib.th=ib.td;function jb(a,b){return n.nodeName(a,"table")&&n.nodeName(11!==b.nodeType?b:b.firstChild,"tr")?a.getElementsByTagName("tbody")[0]||a.appendChild(a.ownerDocument.createElement("tbody")):a}function kb(a){return a.type=(null!==a.getAttribute("type"))+"/"+a.type,a}function lb(a){var b=gb.exec(a.type);return b?a.type=b[1]:a.removeAttribute("type"),a}function mb(a,b){for(var c=0,d=a.length;d>c;c++)L.set(a[c],"globalEval",!b||L.get(b[c],"globalEval"))}function nb(a,b){var c,d,e,f,g,h,i,j;if(1===b.nodeType){if(L.hasData(a)&&(f=L.access(a),g=L.set(b,f),j=f.events)){delete g.handle,g.events={};for(e in j)for(c=0,d=j[e].length;d>c;c++)n.event.add(b,e,j[e][c])}M.hasData(a)&&(h=M.access(a),i=n.extend({},h),M.set(b,i))}}function ob(a,b){var c=a.getElementsByTagName?a.getElementsByTagName(b||"*"):a.querySelectorAll?a.querySelectorAll(b||"*"):[];return void 0===b||b&&n.nodeName(a,b)?n.merge([a],c):c}function pb(a,b){var c=b.nodeName.toLowerCase();"input"===c&&T.test(a.type)?b.checked=a.checked:("input"===c||"textarea"===c)&&(b.defaultValue=a.defaultValue)}n.extend({clone:function(a,b,c){var d,e,f,g,h=a.cloneNode(!0),i=n.contains(a.ownerDocument,a);if(!(k.noCloneChecked||1!==a.nodeType&&11!==a.nodeType||n.isXMLDoc(a)))for(g=ob(h),f=ob(a),d=0,e=f.length;e>d;d++)pb(f[d],g[d]);if(b)if(c)for(f=f||ob(a),g=g||ob(h),d=0,e=f.length;e>d;d++)nb(f[d],g[d]);else nb(a,h);return g=ob(h,"script"),g.length>0&&mb(g,!i&&ob(a,"script")),h},buildFragment:function(a,b,c,d){for(var e,f,g,h,i,j,k=b.createDocumentFragment(),l=[],m=0,o=a.length;o>m;m++)if(e=a[m],e||0===e)if("object"===n.type(e))n.merge(l,e.nodeType?[e]:e);else if(cb.test(e)){f=f||k.appendChild(b.createElement("div")),g=(bb.exec(e)||["",""])[1].toLowerCase(),h=ib[g]||ib._default,f.innerHTML=h[1]+e.replace(ab,"<$1>")+h[2],j=h[0];while(j--)f=f.lastChild;n.merge(l,f.childNodes),f=k.firstChild,f.textContent=""}else l.push(b.createTextNode(e));k.textContent="",m=0;while(e=l[m++])if((!d||-1===n.inArray(e,d))&&(i=n.contains(e.ownerDocument,e),f=ob(k.appendChild(e),"script"),i&&mb(f),c)){j=0;while(e=f[j++])fb.test(e.type||"")&&c.push(e)}return k},cleanData:function(a){for(var b,c,d,e,f=n.event.special,g=0;void 0!==(c=a[g]);g++){if(n.acceptData(c)&&(e=c[L.expando],e&&(b=L.cache[e]))){if(b.events)for(d in b.events)f[d]?n.event.remove(c,d):n.removeEvent(c,d,b.handle);L.cache[e]&&delete L.cache[e]}delete M.cache[c[M.expando]]}}}),n.fn.extend({text:function(a){return J(this,function(a){return void 0===a?n.text(this):this.empty().each(function(){(1===this.nodeType||11===this.nodeType||9===this.nodeType)&&(this.textContent=a)})},null,a,arguments.length)},append:function(){return this.domManip(arguments,function(a){if(1===this.nodeType||11===this.nodeType||9===this.nodeType){var b=jb(this,a);b.appendChild(a)}})},prepend:function(){return this.domManip(arguments,function(a){if(1===this.nodeType||11===this.nodeType||9===this.nodeType){var b=jb(this,a);b.insertBefore(a,b.firstChild)}})},before:function(){return this.domManip(arguments,function(a){this.parentNode&&this.parentNode.insertBefore(a,this)})},after:function(){return this.domManip(arguments,function(a){this.parentNode&&this.parentNode.insertBefore(a,this.nextSibling)})},remove:function(a,b){for(var c,d=a?n.filter(a,this):this,e=0;null!=(c=d[e]);e++)b||1!==c.nodeType||n.cleanData(ob(c)),c.parentNode&&(b&&n.contains(c.ownerDocument,c)&&mb(ob(c,"script")),c.parentNode.removeChild(c));return this},empty:function(){for(var a,b=0;null!=(a=this[b]);b++)1===a.nodeType&&(n.cleanData(ob(a,!1)),a.textContent="");return this},clone:function(a,b){return a=null==a?!1:a,b=null==b?a:b,this.map(function(){return n.clone(this,a,b)})},html:function(a){return J(this,function(a){var b=this[0]||{},c=0,d=this.length;if(void 0===a&&1===b.nodeType)return b.innerHTML;if("string"==typeof a&&!db.test(a)&&!ib[(bb.exec(a)||["",""])[1].toLowerCase()]){a=a.replace(ab,"<$1>");try{for(;d>c;c++)b=this[c]||{},1===b.nodeType&&(n.cleanData(ob(b,!1)),b.innerHTML=a);b=0}catch(e){}}b&&this.empty().append(a)},null,a,arguments.length)},replaceWith:function(){var a=arguments[0];return this.domManip(arguments,function(b){a=this.parentNode,n.cleanData(ob(this)),a&&a.replaceChild(b,this)}),a&&(a.length||a.nodeType)?this:this.remove()},detach:function(a){return this.remove(a,!0)},domManip:function(a,b){a=e.apply([],a);var c,d,f,g,h,i,j=0,l=this.length,m=this,o=l-1,p=a[0],q=n.isFunction(p);if(q||l>1&&"string"==typeof p&&!k.checkClone&&eb.test(p))return this.each(function(c){var d=m.eq(c);q&&(a[0]=p.call(this,c,d.html())),d.domManip(a,b)});if(l&&(c=n.buildFragment(a,this[0].ownerDocument,!1,this),d=c.firstChild,1===c.childNodes.length&&(c=d),d)){for(f=n.map(ob(c,"script"),kb),g=f.length;l>j;j++)h=c,j!==o&&(h=n.clone(h,!0,!0),g&&n.merge(f,ob(h,"script"))),b.call(this[j],h,j);if(g)for(i=f[f.length-1].ownerDocument,n.map(f,lb),j=0;g>j;j++)h=f[j],fb.test(h.type||"")&&!L.access(h,"globalEval")&&n.contains(i,h)&&(h.src?n._evalUrl&&n._evalUrl(h.src):n.globalEval(h.textContent.replace(hb,"")))}return this}}),n.each({appendTo:"append",prependTo:"prepend",insertBefore:"before",insertAfter:"after",replaceAll:"replaceWith"},function(a,b){n.fn[a]=function(a){for(var c,d=[],e=n(a),g=e.length-1,h=0;g>=h;h++)c=h===g?this:this.clone(!0),n(e[h])[b](c),f.apply(d,c.get());return this.pushStack(d)}});var qb,rb={};function sb(b,c){var d,e=n(c.createElement(b)).appendTo(c.body),f=a.getDefaultComputedStyle&&(d=a.getDefaultComputedStyle(e[0]))?d.display:n.css(e[0],"display");return e.detach(),f}function tb(a){var b=l,c=rb[a];return c||(c=sb(a,b),"none"!==c&&c||(qb=(qb||n("