作者 陈志颖

合并分支 'dev' 到 'test'

Dev



查看合并请求 !1
正在显示 41 个修改的文件 包含 1896 行增加1683 行删除
1 -# 合伙人项目  
2 -vendor 文件夹如果不是迫不得已,请不要手动修改其中的文件!  
3 -如果手动修改vendor中的文件,需自行进行版本管理。(慎重考虑!慎重考虑!慎重考虑!)  
  1 +# 服务端工作交接事项
  2 +## 合伙人管理后台项目
  3 +
  4 +### 代码以及文档
  5 +- [代码地址](http://gitlab.fjmaimaimai.com/mmm-go/partnermg.git)
  6 +- [项目原型svn](svn://218.106.157.184/repo/项目文件/项目【合伙人】)
  7 +- [yapi-合伙人前端](http://47.97.5.102:36666/project/209/interface/api)
  8 +
  9 +服务端地址
  10 +```
  11 +测试开发环境pg数据库地址:114.55.200.59:31543,开发库:partner_dev,测试库:partner_test
  12 +正式环境pg数据库地址:114.55.200.59:31544,正式库:partner
  13 +
  14 +服务端开发环境地址:http://mmm-partnermg-dev.fjmaimaimai.com
  15 +服务端测试环境地址:http://mmm-partnermg-test.fjmaimaimai.com
  16 +服务端正式环境地址:https://public-interface.fjmaimaimai.com/mmm-partnermg
  17 +```
  18 +### 项目整体
  19 +- 项目使用框架
  20 + - http框架:beego
  21 + - orm框架:go-pg
  22 + - 数据存储:postgresql
  23 + - 项目结构分层:DDD领域驱动
  24 +
  25 +- 项目结构
  26 +```
  27 +├─conf 项目配置文件
  28 +├─deploy 项目部署文件
  29 +├─pkg
  30 +│ ├─application
  31 +│ │ ├─adminPermission 用户权限菜单
  32 +│ │ ├─businessBonus (在0.5.0后已经移除)
  33 +│ │ ├─company 企业公司功能
  34 +│ │ ├─event 事件订阅以及处理
  35 +│ │ ├─factory 工厂类,实例具体的实现(数据仓储)
  36 +│ │ ├─orderinfo 合伙人订单以及分红数据
  37 +│ │ ├─partnerCategory 合伙人分类信息
  38 +│ │ ├─partnerInfo 合伙人信息
  39 +│ │ ├─syncOrder 同步其他系统的订单数据
  40 +│ │ ├─unifiedUserCenter 从企业平台接收企业和管理员用户数据
  41 +│ │ └─users 管理员用户信息
  42 +│ ├─constant 变量配置(数据库等)
  43 +│ ├─domain 领域模型(核心数据处理,接口定义)
  44 +│ │ ├─event 领域事件定义
  45 +│ │ └─service 领域服务定义
  46 +│ ├─infrastructure 基础设施
  47 +│ │ ├─dao 特殊的数据库操作
  48 +│ │ ├─domainService 实现领域服务
  49 +│ │ ├─pg postgresql 数据库模型定义
  50 +│ │ ├─repository 数据仓储具体实现(对应domain定义数据库的数据存储接口)
  51 +│ │ ├─serviceGateway 其他系统服务调用
  52 +│ │
  53 +│ ├─lib
  54 +│ ├─log
  55 +│ └─port 数据接入层(http接入,消息)
  56 +│ ├─beego beego接入
  57 +│ └─consumer kafka消息订阅
  58 +└─vendor
  59 +```
  60 +### 系统对接的外部数据
  61 +
  62 +1. 外部数据来源,接收企业平台发送过来的数据。目前接收的是公司和员工的数据
  63 + 主要内容在文件夹
  64 + partnermg/pkg/application/unifiedUserCenter,
  65 + partnermg/pkg/port/beego/controller/sync_data_controller.go,
  66 + partnermg/pkg/port/beego/routers/routers.go,
  67 + 具体对接需要的数据格式文档地址:
  68 + [yapi-企业平台-子系统对接](http://47.97.5.102:36666/project/187/interface/api)
  69 +
  70 +2. 外部数据来源,接收香米小程序的订单,需要对接kafka消息。
  71 + 主要内容在
  72 + partnermg/pkg/application/syncOrder,
  73 + partnermg/pkg/port/consumer,
  74 + 具体对接需要的数据格式文档地址:
  75 + [yapi-合伙人-后端](http://47.97.5.102:36666/project/211/interface/api/9013)
  76 +
  77 +3. 需要调用外部的api接口,调用企业平台,统一用户中心的接口
  78 + 主要内容在
  79 + partnermg/pkg/infrastructure/serviceGateway
  80 +
  81 +### 系统入口
  82 +- [测试环境--企业平台网站地址](https://enterprise-platform-dev.fjmaimaimai.com)
  83 +- [开发环境--企业平台网站地址](https://enterprise-platform-local.fjmaimaimai.com)
  84 +- 天联共创后台自身没有独立的登录入口,需要经过企业平台进行跳转登录
  85 +
  86 +
  87 +## 建议
  88 +1. vendor 目前作用是存放依赖,加快在容器中的构建速度。
  89 +2. 有"go.mod"文件存在,可以直接删除vendor文件夹。不过相应的dockerfile 也要进行一定的修改。
  90 +3. vendor 文件夹如果不是迫不得已,请不要手动修改其中的文件!可以使用命令 “go mod vendor”。
  91 +如果手动修改vendor中的文件,需自行进行版本管理。(慎重考虑!慎重考虑!慎重考虑!)。
  92 +
  93 +
@@ -4,7 +4,6 @@ go 1.14 @@ -4,7 +4,6 @@ go 1.14
4 4
5 require ( 5 require (
6 github.com/360EntSecGroup-Skylar/excelize/v2 v2.3.1 6 github.com/360EntSecGroup-Skylar/excelize/v2 v2.3.1
7 - github.com/GeeTeam/gt3-golang-sdk v0.0.0-20200116043922-446ca8a507d2  
8 github.com/Shopify/sarama v1.23.1 7 github.com/Shopify/sarama v1.23.1
9 github.com/ajg/form v1.5.1 // indirect 8 github.com/ajg/form v1.5.1 // indirect
10 github.com/astaxie/beego v1.12.2 9 github.com/astaxie/beego v1.12.2
@@ -17,7 +17,7 @@ type CreatePartnerInfoCommand struct { @@ -17,7 +17,7 @@ type CreatePartnerInfoCommand struct {
17 // 状态(1:启用或者0:禁用) 17 // 状态(1:启用或者0:禁用)
18 Status int `json:"status"` 18 Status int `json:"status"`
19 // 合伙类别 19 // 合伙类别
20 - PartnerCategory []int64 `json:"partnerCategory,omitempty"` 20 + PartnerCategory []*domain.PartnerCategory `json:"partnerCategory,omitempty"`
21 //合作时间 21 //合作时间
22 CooperateTime time.Time `json:"cooperateTime"` 22 CooperateTime time.Time `json:"cooperateTime"`
23 // 区域 23 // 区域
@@ -26,6 +26,8 @@ type CreatePartnerInfoCommand struct { @@ -26,6 +26,8 @@ type CreatePartnerInfoCommand struct {
26 Salesman []domain.Salesman `json:"salesman,omitempty"` 26 Salesman []domain.Salesman `json:"salesman,omitempty"`
27 //公司id 27 //公司id
28 CompanyId int64 `json:"companyId"` 28 CompanyId int64 `json:"companyId"`
  29 + //备注
  30 + Remark string `json:"remark"`
29 } 31 }
30 32
31 func (command CreatePartnerInfoCommand) ValidateCommand() error { 33 func (command CreatePartnerInfoCommand) ValidateCommand() error {
  1 +/**
  2 + @author: stevechan
  3 + @date: 2020/12/29
  4 + @note:
  5 +**/
  6 +
  7 +package command
  8 +
  9 +import (
  10 + "gitlab.fjmaimaimai.com/mmm-go/partnermg/pkg/lib"
  11 +)
  12 +
  13 +// 移除合伙人
  14 +type RemovePartnerInfoCommand struct {
  15 + // 合伙人Id
  16 + Id int64 `json:"id" valid:"Required"`
  17 +}
  18 +
  19 +func (command *RemovePartnerInfoCommand) ValidateCommand() error {
  20 + if command.Id == 0 {
  21 + return lib.ThrowError(lib.ARG_ERROR, "合伙人id错误")
  22 + }
  23 + return nil
  24 +}
@@ -13,7 +13,7 @@ type UpdatePartnerInfoCommand struct { @@ -13,7 +13,7 @@ type UpdatePartnerInfoCommand struct {
13 // 状态(1:启用或者0:禁用) 13 // 状态(1:启用或者0:禁用)
14 Status int `json:"status"` 14 Status int `json:"status"`
15 // 合伙类别 (1.研发合伙人 2.业务合伙人 3.事业) 15 // 合伙类别 (1.研发合伙人 2.业务合伙人 3.事业)
16 - PartnerCategory []int64 `json:"partnerCategory,omitempty"` 16 + PartnerCategory []*domain.PartnerCategory `json:"partnerCategory,omitempty"`
17 // 区域 17 // 区域
18 RegionInfo *domain.RegionInfo `json:"regionInfo"` 18 RegionInfo *domain.RegionInfo `json:"regionInfo"`
19 //关联业务员 19 //关联业务员
@@ -22,6 +22,8 @@ type UpdatePartnerInfoCommand struct { @@ -22,6 +22,8 @@ type UpdatePartnerInfoCommand struct {
22 CooperateTime time.Time `json:"cooperateTime"` 22 CooperateTime time.Time `json:"cooperateTime"`
23 //公司id 23 //公司id
24 CompanyId int64 `json:"companyId"` 24 CompanyId int64 `json:"companyId"`
  25 + //备注
  26 + Remark string `json:"remark"`
25 } 27 }
26 28
27 func (command *UpdatePartnerInfoCommand) ValidateCommand() error { 29 func (command *UpdatePartnerInfoCommand) ValidateCommand() error {
@@ -2,12 +2,13 @@ package query @@ -2,12 +2,13 @@ package query
2 2
3 type ListPartnerInfoQuery struct { 3 type ListPartnerInfoQuery struct {
4 // 合伙人类别 4 // 合伙人类别
5 - Partnertype int `json:"partnerType"` 5 + PartnerType int `json:"partnerType"`
6 //所属区域 6 //所属区域
7 RegionInfo string `json:"regionInfo"` 7 RegionInfo string `json:"regionInfo"`
8 // 合伙人姓名 8 // 合伙人姓名
9 PartnerName string `json:"partnerName"` 9 PartnerName string `json:"partnerName"`
10 - CompanyId int64 `json:"companyId"` 10 + // 公司id
  11 + CompanyId int64 `json:"companyId"`
11 // 查询偏离量 12 // 查询偏离量
12 Offset int `json:"offset"` 13 Offset int `json:"offset"`
13 // 查询限制 14 // 查询限制
@@ -15,6 +16,5 @@ type ListPartnerInfoQuery struct { @@ -15,6 +16,5 @@ type ListPartnerInfoQuery struct {
15 } 16 }
16 17
17 func (q *ListPartnerInfoQuery) ValidateQuery() error { 18 func (q *ListPartnerInfoQuery) ValidateQuery() error {
18 -  
19 return nil 19 return nil
20 } 20 }
@@ -21,7 +21,13 @@ func NewPartnerInfoService(options map[string]interface{}) *PartnerInfoService { @@ -21,7 +21,13 @@ func NewPartnerInfoService(options map[string]interface{}) *PartnerInfoService {
21 return newPartnerInfoService 21 return newPartnerInfoService
22 } 22 }
23 23
24 -// CreatePartnerInfo 创建合伙人 24 +/**
  25 + * @Author SteveChan
  26 + * @Description // 创建合伙人
  27 + * @Date 15:42 2020/12/29
  28 + * @Param
  29 + * @return
  30 + **/
25 func (PartnerInfoService *PartnerInfoService) CreatePartnerInfo(cmd *command.CreatePartnerInfoCommand) (data *domain.PartnerInfo, err error) { 31 func (PartnerInfoService *PartnerInfoService) CreatePartnerInfo(cmd *command.CreatePartnerInfoCommand) (data *domain.PartnerInfo, err error) {
26 var ( 32 var (
27 transactionContext, _ = factory.CreateTransactionContext(nil) 33 transactionContext, _ = factory.CreateTransactionContext(nil)
@@ -35,16 +41,18 @@ func (PartnerInfoService *PartnerInfoService) CreatePartnerInfo(cmd *command.Cre @@ -35,16 +41,18 @@ func (PartnerInfoService *PartnerInfoService) CreatePartnerInfo(cmd *command.Cre
35 defer func() { 41 defer func() {
36 transactionContext.RollbackTransaction() 42 transactionContext.RollbackTransaction()
37 }() 43 }()
  44 +
38 //检查账号是否存在 45 //检查账号是否存在
39 var ( 46 var (
40 - partnerinfoDao *dao.PartnerInfoDao 47 + partnerInfoDao *dao.PartnerInfoDao
41 ) 48 )
42 - if partnerinfoDao, err = factory.CreatePartnerInfoDao(map[string]interface{}{ 49 + if partnerInfoDao, err = factory.CreatePartnerInfoDao(map[string]interface{}{
43 "transactionContext": transactionContext, 50 "transactionContext": transactionContext,
44 }); err != nil { 51 }); err != nil {
45 return nil, lib.ThrowError(lib.TRANSACTION_ERROR, err.Error()) 52 return nil, lib.ThrowError(lib.TRANSACTION_ERROR, err.Error())
46 } 53 }
47 - ok, err := partnerinfoDao.PartnerAccountExist(cmd.Account, cmd.CompanyId) 54 +
  55 + ok, err := partnerInfoDao.PartnerAccountExist(cmd.Account, cmd.CompanyId)
48 if err != nil { 56 if err != nil {
49 return nil, lib.ThrowError(lib.TRANSACTION_ERROR, err.Error()) 57 return nil, lib.ThrowError(lib.TRANSACTION_ERROR, err.Error())
50 } 58 }
@@ -52,10 +60,19 @@ func (PartnerInfoService *PartnerInfoService) CreatePartnerInfo(cmd *command.Cre @@ -52,10 +60,19 @@ func (PartnerInfoService *PartnerInfoService) CreatePartnerInfo(cmd *command.Cre
52 return nil, lib.ThrowError(lib.BUSINESS_ERROR, "账号已存在") 60 return nil, lib.ThrowError(lib.BUSINESS_ERROR, "账号已存在")
53 } 61 }
54 62
  63 + // 编号去重
  64 + for _, partnerCategory := range cmd.PartnerCategory {
  65 + if ok, err := partnerInfoDao.PartnerCodeExist(partnerCategory.Id, partnerCategory.Code, cmd.CompanyId, 0); err != nil {
  66 + return nil, lib.ThrowError(lib.TRANSACTION_ERROR, err.Error())
  67 + } else if ok {
  68 + return nil, lib.ThrowError(lib.BUSINESS_ERROR, "合伙类型"+""+"编号"+partnerCategory.Code+"已存在")
  69 + }
  70 + }
  71 +
55 var ( 72 var (
56 partnerInfoRepository domain.PartnerInfoRepository 73 partnerInfoRepository domain.PartnerInfoRepository
57 categoryRepository domain.PartnerCategoryRepository 74 categoryRepository domain.PartnerCategoryRepository
58 - categorys []domain.PartnerCategory 75 + categories []domain.PartnerCategory
59 ) 76 )
60 if partnerInfoRepository, err = factory.CreatePartnerInfoRepository(map[string]interface{}{ 77 if partnerInfoRepository, err = factory.CreatePartnerInfoRepository(map[string]interface{}{
61 "transactionContext": transactionContext, 78 "transactionContext": transactionContext,
@@ -67,13 +84,26 @@ func (PartnerInfoService *PartnerInfoService) CreatePartnerInfo(cmd *command.Cre @@ -67,13 +84,26 @@ func (PartnerInfoService *PartnerInfoService) CreatePartnerInfo(cmd *command.Cre
67 }); err != nil { 84 }); err != nil {
68 return nil, lib.ThrowError(lib.INTERNAL_SERVER_ERROR, err.Error()) 85 return nil, lib.ThrowError(lib.INTERNAL_SERVER_ERROR, err.Error())
69 } 86 }
70 - _, categorys, err = categoryRepository.Find(domain.PartnerCategoryFindQuery{  
71 - Ids: cmd.PartnerCategory, 87 +
  88 + var ids []int64
  89 + for _, partnerCategory := range cmd.PartnerCategory {
  90 + ids = append(ids, partnerCategory.Id)
  91 + }
  92 + _, categories, err = categoryRepository.Find(domain.PartnerCategoryFindQuery{
  93 + Ids: ids,
72 }) 94 })
73 if err != nil { 95 if err != nil {
74 e := fmt.Sprintf("获取合伙人分类数据失败:%s", err) 96 e := fmt.Sprintf("获取合伙人分类数据失败:%s", err)
75 return nil, lib.ThrowError(lib.INTERNAL_SERVER_ERROR, e) 97 return nil, lib.ThrowError(lib.INTERNAL_SERVER_ERROR, e)
76 } 98 }
  99 + for i, category := range categories {
  100 + for _, partnerCategory := range cmd.PartnerCategory {
  101 + if category.Id == partnerCategory.Id {
  102 + categories[i].Code = partnerCategory.Code
  103 + }
  104 + }
  105 + }
  106 +
77 newPartnerInfo := domain.PartnerInfo{ 107 newPartnerInfo := domain.PartnerInfo{
78 Partner: domain.Partner{ 108 Partner: domain.Partner{
79 Account: cmd.Account, 109 Account: cmd.Account,
@@ -86,7 +116,8 @@ func (PartnerInfoService *PartnerInfoService) CreatePartnerInfo(cmd *command.Cre @@ -86,7 +116,8 @@ func (PartnerInfoService *PartnerInfoService) CreatePartnerInfo(cmd *command.Cre
86 Salesman: cmd.Salesman, 116 Salesman: cmd.Salesman,
87 CooperateTime: cmd.CooperateTime, 117 CooperateTime: cmd.CooperateTime,
88 CompanyId: cmd.CompanyId, 118 CompanyId: cmd.CompanyId,
89 - PartnerCategoryInfos: categorys, 119 + PartnerCategoryInfos: categories,
  120 + Remark: cmd.Remark,
90 } 121 }
91 if err = partnerInfoRepository.Save(&newPartnerInfo); err != nil { 122 if err = partnerInfoRepository.Save(&newPartnerInfo); err != nil {
92 return nil, lib.ThrowError(lib.INTERNAL_SERVER_ERROR, err.Error()) 123 return nil, lib.ThrowError(lib.INTERNAL_SERVER_ERROR, err.Error())
@@ -106,11 +137,18 @@ func (PartnerInfoService *PartnerInfoService) CreatePartnerInfo(cmd *command.Cre @@ -106,11 +137,18 @@ func (PartnerInfoService *PartnerInfoService) CreatePartnerInfo(cmd *command.Cre
106 return &newPartnerInfo, nil 137 return &newPartnerInfo, nil
107 } 138 }
108 139
109 -// GetPartnerInfo 返回合伙人 140 +/**
  141 + * @Author SteveChan
  142 + * @Description // 返回合伙人,增加合伙人编号字段
  143 + * @Date 15:43 2020/12/29
  144 + * @Param
  145 + * @return
  146 + **/
110 func (PartnerInfoService *PartnerInfoService) GetPartnerInfo(q query.GetPartnerInfoQuery) (data *domain.PartnerInfo, err error) { 147 func (PartnerInfoService *PartnerInfoService) GetPartnerInfo(q query.GetPartnerInfoQuery) (data *domain.PartnerInfo, err error) {
111 var ( 148 var (
112 transactionContext, _ = factory.CreateTransactionContext(nil) 149 transactionContext, _ = factory.CreateTransactionContext(nil)
113 ) 150 )
  151 +
114 if err = q.ValidateQuery(); err != nil { 152 if err = q.ValidateQuery(); err != nil {
115 return nil, lib.ThrowError(lib.ARG_ERROR, err.Error()) 153 return nil, lib.ThrowError(lib.ARG_ERROR, err.Error())
116 } 154 }
@@ -120,17 +158,21 @@ func (PartnerInfoService *PartnerInfoService) GetPartnerInfo(q query.GetPartnerI @@ -120,17 +158,21 @@ func (PartnerInfoService *PartnerInfoService) GetPartnerInfo(q query.GetPartnerI
120 defer func() { 158 defer func() {
121 transactionContext.RollbackTransaction() 159 transactionContext.RollbackTransaction()
122 }() 160 }()
  161 +
123 var ( 162 var (
124 PartnerInfoRepository domain.PartnerInfoRepository 163 PartnerInfoRepository domain.PartnerInfoRepository
125 categoryRepository domain.PartnerCategoryRepository 164 categoryRepository domain.PartnerCategoryRepository
126 - categorys []domain.PartnerCategory 165 + categories []domain.PartnerCategory
127 partnerData *domain.PartnerInfo 166 partnerData *domain.PartnerInfo
128 ) 167 )
  168 +
129 if PartnerInfoRepository, err = factory.CreatePartnerInfoRepository(map[string]interface{}{ 169 if PartnerInfoRepository, err = factory.CreatePartnerInfoRepository(map[string]interface{}{
130 "transactionContext": transactionContext, 170 "transactionContext": transactionContext,
131 }); err != nil { 171 }); err != nil {
132 return nil, lib.ThrowError(lib.INTERNAL_SERVER_ERROR, err.Error()) 172 return nil, lib.ThrowError(lib.INTERNAL_SERVER_ERROR, err.Error())
133 } 173 }
  174 +
  175 + // 获取合伙人数据
134 partnerData, err = PartnerInfoRepository.FindOne(domain.PartnerFindOneQuery{ 176 partnerData, err = PartnerInfoRepository.FindOne(domain.PartnerFindOneQuery{
135 UserId: q.Id, CompanyId: q.CompanyId, 177 UserId: q.Id, CompanyId: q.CompanyId,
136 }) 178 })
@@ -140,33 +182,49 @@ func (PartnerInfoService *PartnerInfoService) GetPartnerInfo(q query.GetPartnerI @@ -140,33 +182,49 @@ func (PartnerInfoService *PartnerInfoService) GetPartnerInfo(q query.GetPartnerI
140 if !partnerData.IsCompany(q.CompanyId) { 182 if !partnerData.IsCompany(q.CompanyId) {
141 return nil, lib.ThrowError(lib.BUSINESS_ERROR, "企业信息异常操作") 183 return nil, lib.ThrowError(lib.BUSINESS_ERROR, "企业信息异常操作")
142 } 184 }
  185 +
  186 + // 获取合伙人类别
143 if categoryRepository, err = factory.CreatePartnerCategoryRepository(map[string]interface{}{ 187 if categoryRepository, err = factory.CreatePartnerCategoryRepository(map[string]interface{}{
144 "transactionContext": transactionContext, 188 "transactionContext": transactionContext,
145 }); err != nil { 189 }); err != nil {
146 return nil, lib.ThrowError(lib.INTERNAL_SERVER_ERROR, err.Error()) 190 return nil, lib.ThrowError(lib.INTERNAL_SERVER_ERROR, err.Error())
147 } 191 }
148 - categoryIds := []int64{} 192 + var categoryIds []int64
149 for _, v := range partnerData.PartnerCategoryInfos { 193 for _, v := range partnerData.PartnerCategoryInfos {
150 categoryIds = append(categoryIds, v.Id) 194 categoryIds = append(categoryIds, v.Id)
151 } 195 }
152 if len(categoryIds) > 0 { 196 if len(categoryIds) > 0 {
153 - _, categorys, err = categoryRepository.Find(domain.PartnerCategoryFindQuery{ 197 + _, categories, err = categoryRepository.Find(domain.PartnerCategoryFindQuery{
154 Ids: categoryIds, 198 Ids: categoryIds,
155 }) 199 })
156 if err != nil { 200 if err != nil {
157 return nil, lib.ThrowError(lib.INTERNAL_SERVER_ERROR, err.Error()) 201 return nil, lib.ThrowError(lib.INTERNAL_SERVER_ERROR, err.Error())
158 } 202 }
  203 + for i, category := range categories {
  204 + for _, partnerCategory := range partnerData.PartnerCategoryInfos {
  205 + if category.Id == partnerCategory.Id {
  206 + categories[i].Code = partnerCategory.Code
  207 + }
  208 + }
  209 + }
159 } 210 }
160 - partnerData.PartnerCategoryInfos = categorys 211 + partnerData.PartnerCategoryInfos = categories
161 err = transactionContext.CommitTransaction() 212 err = transactionContext.CommitTransaction()
162 return partnerData, nil 213 return partnerData, nil
163 } 214 }
164 215
165 -//UpdatePartnerInfo 更新合伙人 216 +/**
  217 + * @Author SteveChan
  218 + * @Description // 更新合伙人
  219 + * @Date 00:07 2020/12/30
  220 + * @Param
  221 + * @return
  222 + **/
166 func (PartnerInfoService *PartnerInfoService) UpdatePartnerInfo(cmd *command.UpdatePartnerInfoCommand) (err error) { 223 func (PartnerInfoService *PartnerInfoService) UpdatePartnerInfo(cmd *command.UpdatePartnerInfoCommand) (err error) {
167 var ( 224 var (
168 transactionContext, _ = factory.CreateTransactionContext(nil) 225 transactionContext, _ = factory.CreateTransactionContext(nil)
169 ) 226 )
  227 +
170 if err = cmd.ValidateCommand(); err != nil { 228 if err = cmd.ValidateCommand(); err != nil {
171 return application.ThrowError(application.ARG_ERROR, err.Error()) 229 return application.ThrowError(application.ARG_ERROR, err.Error())
172 } 230 }
@@ -176,30 +234,65 @@ func (PartnerInfoService *PartnerInfoService) UpdatePartnerInfo(cmd *command.Upd @@ -176,30 +234,65 @@ func (PartnerInfoService *PartnerInfoService) UpdatePartnerInfo(cmd *command.Upd
176 defer func() { 234 defer func() {
177 transactionContext.RollbackTransaction() 235 transactionContext.RollbackTransaction()
178 }() 236 }()
  237 +
179 var ( 238 var (
180 partnerInfoRepository domain.PartnerInfoRepository 239 partnerInfoRepository domain.PartnerInfoRepository
181 categoryRepository domain.PartnerCategoryRepository 240 categoryRepository domain.PartnerCategoryRepository
182 - categorys []domain.PartnerCategory 241 + categories []domain.PartnerCategory
  242 + partnerInfoDao *dao.PartnerInfoDao
183 ) 243 )
  244 +
  245 + if partnerInfoDao, err = factory.CreatePartnerInfoDao(map[string]interface{}{
  246 + "transactionContext": transactionContext,
  247 + }); err != nil {
  248 + return lib.ThrowError(lib.TRANSACTION_ERROR, err.Error())
  249 + }
  250 +
184 if partnerInfoRepository, err = factory.CreatePartnerInfoRepository(map[string]interface{}{ 251 if partnerInfoRepository, err = factory.CreatePartnerInfoRepository(map[string]interface{}{
185 "transactionContext": transactionContext, 252 "transactionContext": transactionContext,
186 }); err != nil { 253 }); err != nil {
187 return lib.ThrowError(lib.TRANSACTION_ERROR, err.Error()) 254 return lib.ThrowError(lib.TRANSACTION_ERROR, err.Error())
188 } 255 }
  256 +
189 if categoryRepository, err = factory.CreatePartnerCategoryRepository(map[string]interface{}{ 257 if categoryRepository, err = factory.CreatePartnerCategoryRepository(map[string]interface{}{
190 "transactionContext": transactionContext, 258 "transactionContext": transactionContext,
191 }); err != nil { 259 }); err != nil {
192 return lib.ThrowError(lib.INTERNAL_SERVER_ERROR, err.Error()) 260 return lib.ThrowError(lib.INTERNAL_SERVER_ERROR, err.Error())
193 } 261 }
194 - _, categorys, err = categoryRepository.Find(domain.PartnerCategoryFindQuery{  
195 - Ids: cmd.PartnerCategory, 262 +
  263 + // 编号去重
  264 + for _, partnerCategory := range cmd.PartnerCategory {
  265 + if ok, err := partnerInfoDao.PartnerCodeExist(partnerCategory.Id, partnerCategory.Code, cmd.CompanyId, cmd.Id); err != nil {
  266 + return lib.ThrowError(lib.TRANSACTION_ERROR, err.Error())
  267 + } else if ok {
  268 + return lib.ThrowError(lib.BUSINESS_ERROR, "编号"+partnerCategory.Code+"已存在")
  269 + }
  270 + }
  271 +
  272 + var ids []int64
  273 + for _, partnerCategory := range cmd.PartnerCategory {
  274 + ids = append(ids, partnerCategory.Id)
  275 + }
  276 +
  277 + _, categories, err = categoryRepository.Find(domain.PartnerCategoryFindQuery{
  278 + Ids: ids,
196 }) 279 })
197 if err != nil { 280 if err != nil {
198 e := fmt.Sprintf("获取合伙人分类数据失败:%s", err) 281 e := fmt.Sprintf("获取合伙人分类数据失败:%s", err)
199 return lib.ThrowError(lib.INTERNAL_SERVER_ERROR, e) 282 return lib.ThrowError(lib.INTERNAL_SERVER_ERROR, e)
200 } 283 }
  284 +
  285 + for i, category := range categories {
  286 + for _, partnerCategory := range cmd.PartnerCategory {
  287 + if category.Id == partnerCategory.Id {
  288 + categories[i].Code = partnerCategory.Code
  289 + }
  290 + }
  291 + }
  292 +
201 partnerInfo, err := partnerInfoRepository.FindOne(domain.PartnerFindOneQuery{ 293 partnerInfo, err := partnerInfoRepository.FindOne(domain.PartnerFindOneQuery{
202 - UserId: cmd.Id, CompanyId: cmd.CompanyId, 294 + UserId: cmd.Id,
  295 + CompanyId: cmd.CompanyId,
203 }) 296 })
204 if err != nil { 297 if err != nil {
205 return lib.ThrowError(lib.INTERNAL_SERVER_ERROR, err.Error()) 298 return lib.ThrowError(lib.INTERNAL_SERVER_ERROR, err.Error())
@@ -207,11 +300,14 @@ func (PartnerInfoService *PartnerInfoService) UpdatePartnerInfo(cmd *command.Upd @@ -207,11 +300,14 @@ func (PartnerInfoService *PartnerInfoService) UpdatePartnerInfo(cmd *command.Upd
207 if !partnerInfo.IsCompany(cmd.CompanyId) { 300 if !partnerInfo.IsCompany(cmd.CompanyId) {
208 return lib.ThrowError(lib.BUSINESS_ERROR, "异常操作") 301 return lib.ThrowError(lib.BUSINESS_ERROR, "异常操作")
209 } 302 }
  303 +
210 partnerInfo.Salesman = cmd.Salesman 304 partnerInfo.Salesman = cmd.Salesman
211 partnerInfo.Status = cmd.Status 305 partnerInfo.Status = cmd.Status
212 partnerInfo.RegionInfo = *cmd.RegionInfo 306 partnerInfo.RegionInfo = *cmd.RegionInfo
213 partnerInfo.CooperateTime = cmd.CooperateTime 307 partnerInfo.CooperateTime = cmd.CooperateTime
214 - partnerInfo.PartnerCategoryInfos = categorys 308 + partnerInfo.PartnerCategoryInfos = categories
  309 + partnerInfo.Remark = cmd.Remark
  310 +
215 if err = partnerInfoRepository.Save(partnerInfo); err != nil { 311 if err = partnerInfoRepository.Save(partnerInfo); err != nil {
216 return lib.ThrowError(lib.INTERNAL_SERVER_ERROR, err.Error()) 312 return lib.ThrowError(lib.INTERNAL_SERVER_ERROR, err.Error())
217 } 313 }
@@ -231,7 +327,13 @@ func (PartnerInfoService *PartnerInfoService) UpdatePartnerInfo(cmd *command.Upd @@ -231,7 +327,13 @@ func (PartnerInfoService *PartnerInfoService) UpdatePartnerInfo(cmd *command.Upd
231 return 327 return
232 } 328 }
233 329
234 -// ListPartnerInfo 合伙人列表 330 +/**
  331 + * @Author SteveChan
  332 + * @Description //合伙人列表,返回合伙人编号
  333 + * @Date 00:07 2020/12/30
  334 + * @Param
  335 + * @return
  336 + **/
235 func (PartnerInfoService *PartnerInfoService) ListPartnerInfo(listPartnerInfoQuery *query.ListPartnerInfoQuery) (int, []domain.PartnerInfo, error) { 337 func (PartnerInfoService *PartnerInfoService) ListPartnerInfo(listPartnerInfoQuery *query.ListPartnerInfoQuery) (int, []domain.PartnerInfo, error) {
236 var ( 338 var (
237 transactionContext, _ = factory.CreateTransactionContext(nil) 339 transactionContext, _ = factory.CreateTransactionContext(nil)
@@ -246,14 +348,13 @@ func (PartnerInfoService *PartnerInfoService) ListPartnerInfo(listPartnerInfoQue @@ -246,14 +348,13 @@ func (PartnerInfoService *PartnerInfoService) ListPartnerInfo(listPartnerInfoQue
246 return 0, nil, lib.ThrowError(lib.TRANSACTION_ERROR, err.Error()) 348 return 0, nil, lib.ThrowError(lib.TRANSACTION_ERROR, err.Error())
247 } 349 }
248 defer func() { 350 defer func() {
249 -  
250 transactionContext.RollbackTransaction() 351 transactionContext.RollbackTransaction()
251 -  
252 }() 352 }()
  353 +
253 var ( 354 var (
254 partnerInfoRepository domain.PartnerInfoRepository 355 partnerInfoRepository domain.PartnerInfoRepository
255 categoryRepository domain.PartnerCategoryRepository 356 categoryRepository domain.PartnerCategoryRepository
256 - categorys []domain.PartnerCategory 357 + categories []domain.PartnerCategory
257 ) 358 )
258 if partnerInfoRepository, err = factory.CreatePartnerInfoRepository(map[string]interface{}{ 359 if partnerInfoRepository, err = factory.CreatePartnerInfoRepository(map[string]interface{}{
259 "transactionContext": transactionContext, 360 "transactionContext": transactionContext,
@@ -271,8 +372,8 @@ func (PartnerInfoService *PartnerInfoService) ListPartnerInfo(listPartnerInfoQue @@ -271,8 +372,8 @@ func (PartnerInfoService *PartnerInfoService) ListPartnerInfo(listPartnerInfoQue
271 PartnerName: listPartnerInfoQuery.PartnerName, 372 PartnerName: listPartnerInfoQuery.PartnerName,
272 CompanyId: listPartnerInfoQuery.CompanyId, 373 CompanyId: listPartnerInfoQuery.CompanyId,
273 } 374 }
274 - if listPartnerInfoQuery.Partnertype > 0 {  
275 - queryOption.PartnerCategory = []int{listPartnerInfoQuery.Partnertype} 375 + if listPartnerInfoQuery.PartnerType > 0 {
  376 + queryOption.PartnerCategory = []int{listPartnerInfoQuery.PartnerType}
276 } 377 }
277 // RegionInfo 378 // RegionInfo
278 if len(listPartnerInfoQuery.RegionInfo) > 0 { 379 if len(listPartnerInfoQuery.RegionInfo) > 0 {
@@ -284,18 +385,19 @@ func (PartnerInfoService *PartnerInfoService) ListPartnerInfo(listPartnerInfoQue @@ -284,18 +385,19 @@ func (PartnerInfoService *PartnerInfoService) ListPartnerInfo(listPartnerInfoQue
284 if count, err = partnerInfoRepository.CountAll(queryOption); err != nil { 385 if count, err = partnerInfoRepository.CountAll(queryOption); err != nil {
285 return 0, nil, lib.ThrowError(lib.INTERNAL_SERVER_ERROR, err.Error()) 386 return 0, nil, lib.ThrowError(lib.INTERNAL_SERVER_ERROR, err.Error())
286 } 387 }
287 - _, categorys, err = categoryRepository.Find(domain.PartnerCategoryFindQuery{}) 388 + _, categories, err = categoryRepository.Find(domain.PartnerCategoryFindQuery{})
288 if err != nil { 389 if err != nil {
289 return count, partnerInfos, lib.ThrowError(lib.INTERNAL_SERVER_ERROR, err.Error()) 390 return count, partnerInfos, lib.ThrowError(lib.INTERNAL_SERVER_ERROR, err.Error())
290 } 391 }
291 - categorysMap := make(map[int64]domain.PartnerCategory)  
292 - for i := range categorys {  
293 - categorysMap[categorys[i].Id] = categorys[i] 392 + categoriesMap := make(map[int64]domain.PartnerCategory)
  393 + for i := range categories {
  394 + categoriesMap[categories[i].Id] = categories[i]
294 } 395 }
295 for i := range partnerInfos { 396 for i := range partnerInfos {
296 - categoryInPartner := []domain.PartnerCategory{} 397 + var categoryInPartner []domain.PartnerCategory
297 for _, vv := range partnerInfos[i].PartnerCategoryInfos { 398 for _, vv := range partnerInfos[i].PartnerCategoryInfos {
298 - if categoryData, ok := categorysMap[vv.Id]; ok { 399 + if categoryData, ok := categoriesMap[vv.Id]; ok {
  400 + categoryData.Code = vv.Code
299 categoryInPartner = append(categoryInPartner, categoryData) 401 categoryInPartner = append(categoryInPartner, categoryData)
300 } 402 }
301 } 403 }
@@ -307,6 +409,47 @@ func (PartnerInfoService *PartnerInfoService) ListPartnerInfo(listPartnerInfoQue @@ -307,6 +409,47 @@ func (PartnerInfoService *PartnerInfoService) ListPartnerInfo(listPartnerInfoQue
307 return count, partnerInfos, nil 409 return count, partnerInfos, nil
308 } 410 }
309 411
  412 +/**
  413 + * @Author SteveChan
  414 + * @Description //TODO 移除合伙人
  415 + * @Date 16:40 2020/12/29
  416 + * @Param
  417 + * @return
  418 + **/
  419 +func (PartnerInfoService *PartnerInfoService) RemovePartnerInfo(cmd command.RemovePartnerInfoCommand) (err error) {
  420 + var (
  421 + transactionContext, _ = factory.CreateTransactionContext(nil)
  422 + )
  423 + if err = cmd.ValidateCommand(); err != nil {
  424 + return application.ThrowError(application.ARG_ERROR, err.Error())
  425 + }
  426 + if err = transactionContext.StartTransaction(); err != nil {
  427 + return err
  428 + }
  429 + defer func() {
  430 + transactionContext.RollbackTransaction()
  431 + }()
  432 +
  433 + var (
  434 + partnerInfoRepository domain.PartnerInfoRepository
  435 + )
  436 +
  437 + if partnerInfoRepository, err = factory.CreatePartnerInfoRepository(map[string]interface{}{
  438 + "transactionContext": transactionContext,
  439 + }); err != nil {
  440 + return lib.ThrowError(lib.INTERNAL_SERVER_ERROR, err.Error())
  441 + }
  442 +
  443 + // 判断合伙人是否有业务数据
  444 +
  445 + if err = partnerInfoRepository.Remove(cmd.Id); err != nil {
  446 + return lib.ThrowError(lib.INTERNAL_SERVER_ERROR, err.Error())
  447 + }
  448 +
  449 + transactionContext.CommitTransaction()
  450 + return nil
  451 +}
  452 +
310 func (PartnerInfoService *PartnerInfoService) UpdateStatus(cmd command.StatusPartnerInfoCommand) (err error) { 453 func (PartnerInfoService *PartnerInfoService) UpdateStatus(cmd command.StatusPartnerInfoCommand) (err error) {
311 if len(cmd.Ids) == 0 { 454 if len(cmd.Ids) == 0 {
312 return nil 455 return nil
@@ -324,14 +467,14 @@ func (PartnerInfoService *PartnerInfoService) UpdateStatus(cmd command.StatusPar @@ -324,14 +467,14 @@ func (PartnerInfoService *PartnerInfoService) UpdateStatus(cmd command.StatusPar
324 transactionContext.RollbackTransaction() 467 transactionContext.RollbackTransaction()
325 }() 468 }()
326 var ( 469 var (
327 - partnerinfoDao *dao.PartnerInfoDao 470 + partnerInfoDao *dao.PartnerInfoDao
328 ) 471 )
329 - if partnerinfoDao, err = factory.CreatePartnerInfoDao(map[string]interface{}{ 472 + if partnerInfoDao, err = factory.CreatePartnerInfoDao(map[string]interface{}{
330 "transactionContext": transactionContext, 473 "transactionContext": transactionContext,
331 }); err != nil { 474 }); err != nil {
332 return lib.ThrowError(lib.TRANSACTION_ERROR, err.Error()) 475 return lib.ThrowError(lib.TRANSACTION_ERROR, err.Error())
333 } 476 }
334 - err = partnerinfoDao.UpdatePartnerStatus(cmd.Ids, cmd.CompanyId, cmd.Status) 477 + err = partnerInfoDao.UpdatePartnerStatus(cmd.Ids, cmd.CompanyId, cmd.Status)
335 if err != nil { 478 if err != nil {
336 e := fmt.Sprintf("更新合伙人(id=%v)的数据失败;%s", cmd.Ids, err) 479 e := fmt.Sprintf("更新合伙人(id=%v)的数据失败;%s", cmd.Ids, err)
337 return lib.ThrowError(lib.INTERNAL_SERVER_ERROR, e) 480 return lib.ThrowError(lib.INTERNAL_SERVER_ERROR, e)
@@ -8,14 +8,14 @@ var LOG_LEVEL = "debug" @@ -8,14 +8,14 @@ var LOG_LEVEL = "debug"
8 var LOG_File = "./logs/partnermg.log" 8 var LOG_File = "./logs/partnermg.log"
9 9
10 var ( 10 var (
11 - UCENTER_HOST = "https://suplus-ucenter-dev.fjmaimaimai.com" //统一用户中心地址 11 + UCENTER_HOST = "https://suplus-ucenter-test.fjmaimaimai.com" //统一用户中心地址
12 UCENTER_SECRET = "cykbjnfqgctn" 12 UCENTER_SECRET = "cykbjnfqgctn"
13 UCENTER_APP_KEY = "39aefef9e22744a3b2d2d3791824ae7b" 13 UCENTER_APP_KEY = "39aefef9e22744a3b2d2d3791824ae7b"
14 UCENTER_CHECK_ALT = "rsF0pL!6DwjBO735" 14 UCENTER_CHECK_ALT = "rsF0pL!6DwjBO735"
15 ) 15 )
16 16
17 var ( 17 var (
18 - BUSINESS_ADMIN_HOST = "http://suplus-business-admin-dev.fjmaimaimai.com" //企业平台的地址 18 + BUSINESS_ADMIN_HOST = "http://suplus-business-admin-test.fjmaimaimai.com" //企业平台的地址
19 ) 19 )
20 20
21 func init() { 21 func init() {
@@ -34,9 +34,7 @@ func init() { @@ -34,9 +34,7 @@ func init() {
34 if os.Getenv("UCENTER_CHECK_ALT") != "" { 34 if os.Getenv("UCENTER_CHECK_ALT") != "" {
35 UCENTER_CHECK_ALT = os.Getenv("UCENTER_CHECK_ALT") 35 UCENTER_CHECK_ALT = os.Getenv("UCENTER_CHECK_ALT")
36 } 36 }
37 -  
38 if os.Getenv("BUSINESS_ADMIN_HOST") != "" { 37 if os.Getenv("BUSINESS_ADMIN_HOST") != "" {
39 BUSINESS_ADMIN_HOST = os.Getenv("BUSINESS_ADMIN_HOST") 38 BUSINESS_ADMIN_HOST = os.Getenv("BUSINESS_ADMIN_HOST")
40 } 39 }
41 -  
42 } 40 }
@@ -14,7 +14,7 @@ var KafkaCfg KafkaConfig @@ -14,7 +14,7 @@ var KafkaCfg KafkaConfig
14 14
15 func init() { 15 func init() {
16 KafkaCfg = KafkaConfig{ 16 KafkaCfg = KafkaConfig{
17 - Servers: []string{""}, 17 + Servers: []string{"127.0.0.1:9092"},
18 ConsumerId: "partnermg_local", 18 ConsumerId: "partnermg_local",
19 } 19 }
20 if os.Getenv("KAFKA_HOST") != "" { 20 if os.Getenv("KAFKA_HOST") != "" {
@@ -2,11 +2,11 @@ package constant @@ -2,11 +2,11 @@ package constant
2 2
3 import "os" 3 import "os"
4 4
5 -var POSTGRESQL_DB_NAME = "partner_dev" 5 +var POSTGRESQL_DB_NAME = "partner_test"
6 var POSTGRESQL_USER = "postgres" 6 var POSTGRESQL_USER = "postgres"
7 -var POSTGRESQL_PASSWORD = "eagle1010"  
8 -var POSTGRESQL_HOST = "114.55.200.59"  
9 -var POSTGRESQL_PORT = "31543" 7 +var POSTGRESQL_PASSWORD = "1993618jack" // eagle1010
  8 +var POSTGRESQL_HOST = "127.0.0.1" // 114.55.200.59
  9 +var POSTGRESQL_PORT = "5432" // 31543
10 var DISABLE_CREATE_TABLE = true 10 var DISABLE_CREATE_TABLE = true
11 var DISABLE_SQL_GENERATE_PRINT = false 11 var DISABLE_SQL_GENERATE_PRINT = false
12 12
@@ -114,7 +114,7 @@ type OrderBase struct { @@ -114,7 +114,7 @@ type OrderBase struct {
114 DataFrom OrderDataFrom `json:"dataFrom"` 114 DataFrom OrderDataFrom `json:"dataFrom"`
115 //备注 115 //备注
116 Remark OrderBaseRemark `json:"remark"` 116 Remark OrderBaseRemark `json:"remark"`
117 - 117 + //合伙人类型
118 PartnerCategory PartnerCategory `json:"partnerCategory"` 118 PartnerCategory PartnerCategory `json:"partnerCategory"`
119 } 119 }
120 120
@@ -182,16 +182,16 @@ func (order *OrderBase) AddGoods(goods []OrderGood) { @@ -182,16 +182,16 @@ func (order *OrderBase) AddGoods(goods []OrderGood) {
182 order.Compute() 182 order.Compute()
183 } 183 }
184 184
185 -func (order *OrderBase) ModifyGoodNumber(goodid int64, number int64) {  
186 - for i := range order.Goods {  
187 - if order.Goods[i].Id != goodid {  
188 - continue  
189 - }  
190 - // thisGood := order.Goods[i] 185 +// func (order *OrderBase) ModifyGoodNumber(goodid int64, number int64) {
  186 +// for i := range order.Goods {
  187 +// if order.Goods[i].Id != goodid {
  188 +// continue
  189 +// }
  190 +// // thisGood := order.Goods[i]
191 191
192 - }  
193 - order.Compute()  
194 -} 192 +// }
  193 +// order.Compute()
  194 +// }
195 195
196 //Compute 数据汇总核算 196 //Compute 数据汇总核算
197 func (order *OrderBase) Compute() error { 197 func (order *OrderBase) Compute() error {
@@ -6,6 +6,8 @@ type PartnerCategory struct { @@ -6,6 +6,8 @@ type PartnerCategory struct {
6 Id int64 `json:"id"` 6 Id int64 `json:"id"`
7 // 名称 7 // 名称
8 Name string `json:"name,omitempty"` 8 Name string `json:"name,omitempty"`
  9 + // 合伙人编码
  10 + Code string `json:"code"`
9 } 11 }
10 12
11 type PartnerCategoryFindQuery struct { 13 type PartnerCategoryFindQuery struct {
@@ -48,6 +48,8 @@ type PartnerInfo struct { @@ -48,6 +48,8 @@ type PartnerInfo struct {
48 PartnerCategory int `json:"partnerCategory"` 48 PartnerCategory int `json:"partnerCategory"`
49 //公司id 49 //公司id
50 CompanyId int64 `json:"companyId"` 50 CompanyId int64 `json:"companyId"`
  51 + //备注
  52 + Remark string `json:"remark"`
51 } 53 }
52 54
53 func (p *PartnerInfo) IsUsable() bool { 55 func (p *PartnerInfo) IsUsable() bool {
@@ -72,11 +74,13 @@ type PartnerFindQuery struct { @@ -72,11 +74,13 @@ type PartnerFindQuery struct {
72 PartnerName string //合伙人姓名 74 PartnerName string //合伙人姓名
73 CompanyId int64 75 CompanyId int64
74 Ids []int64 76 Ids []int64
  77 + PartnerType []*PartnerCategory
75 } 78 }
76 79
77 type PartnerInfoRepository interface { 80 type PartnerInfoRepository interface {
78 Save(dm *PartnerInfo) error 81 Save(dm *PartnerInfo) error
79 FindOne(queryOptions PartnerFindOneQuery) (*PartnerInfo, error) 82 FindOne(queryOptions PartnerFindOneQuery) (*PartnerInfo, error)
80 Find(queryOptions PartnerFindQuery) ([]PartnerInfo, error) 83 Find(queryOptions PartnerFindQuery) ([]PartnerInfo, error)
  84 + Remove(Id int64) error
81 CountAll(queryOptions PartnerFindQuery) (int, error) 85 CountAll(queryOptions PartnerFindQuery) (int, error)
82 } 86 }
@@ -2,7 +2,7 @@ package dao @@ -2,7 +2,7 @@ package dao
2 2
3 import ( 3 import (
4 "fmt" 4 "fmt"
5 - 5 + "github.com/go-pg/pg/v10"
6 "gitlab.fjmaimaimai.com/mmm-go/partnermg/pkg/infrastructure/pg/models" 6 "gitlab.fjmaimaimai.com/mmm-go/partnermg/pkg/infrastructure/pg/models"
7 "gitlab.fjmaimaimai.com/mmm-go/partnermg/pkg/infrastructure/pg/transaction" 7 "gitlab.fjmaimaimai.com/mmm-go/partnermg/pkg/infrastructure/pg/transaction"
8 ) 8 )
@@ -28,7 +28,6 @@ func (dao PartnerInfoDao) PartnerAccountExist(account string, companyId int64) ( @@ -28,7 +28,6 @@ func (dao PartnerInfoDao) PartnerAccountExist(account string, companyId int64) (
28 Where("account=?", account). 28 Where("account=?", account).
29 Where("company_id=?", companyId). 29 Where("company_id=?", companyId).
30 Exists() 30 Exists()
31 -  
32 return ok, err 31 return ok, err
33 } 32 }
34 33
@@ -42,3 +41,21 @@ func (dao PartnerInfoDao) UpdatePartnerStatus(ids []int64, companyId int64, stat @@ -42,3 +41,21 @@ func (dao PartnerInfoDao) UpdatePartnerStatus(ids []int64, companyId int64, stat
42 Update() 41 Update()
43 return err 42 return err
44 } 43 }
  44 +
  45 +/**
  46 + * @Author SteveChan
  47 + * @Description // 编号查重
  48 + * @Date 17:55 2020/12/28
  49 + * @Param
  50 + * @return
  51 + **/
  52 +func (dao PartnerInfoDao) PartnerCodeExist(categoryId int64, code string, companyId int64, id int64) (bool, error) {
  53 + tx := dao.transactionContext.PgDd
  54 + m := &models.PartnerInfo{}
  55 + ok, err := tx.Model(m).
  56 + Where(`partner_category_infos@> '[{"id":?,"code":?}]'`, categoryId, pg.Ident(code)).
  57 + Where("company_id=?", companyId).
  58 + Where("id <> ?", id).
  59 + Exists()
  60 + return ok, err
  61 +}
@@ -35,4 +35,5 @@ type OrderBestshop struct { @@ -35,4 +35,5 @@ type OrderBestshop struct {
35 //是否将数据同步到 order_base ,order_good 35 //是否将数据同步到 order_base ,order_good
36 IsCopy bool `pg:",use_zero"` 36 IsCopy bool `pg:",use_zero"`
37 CompanyId int64 37 CompanyId int64
  38 + OrderArea string
38 } 39 }
@@ -7,4 +7,6 @@ type PartnerCategoryInfo struct { @@ -7,4 +7,6 @@ type PartnerCategoryInfo struct {
7 Id int64 7 Id int64
8 // 名称 8 // 名称
9 Name string 9 Name string
  10 + // 合伙人编码
  11 + Code string
10 } 12 }
@@ -36,6 +36,8 @@ type PartnerInfo struct { @@ -36,6 +36,8 @@ type PartnerInfo struct {
36 PartnerCategoryInfos []domain.PartnerCategory 36 PartnerCategoryInfos []domain.PartnerCategory
37 //公司id 37 //公司id
38 CompanyId int64 38 CompanyId int64
  39 + //备注
  40 + Remark string
39 } 41 }
40 42
41 var _ pg.BeforeUpdateHook = (*PartnerInfo)(nil) 43 var _ pg.BeforeUpdateHook = (*PartnerInfo)(nil)
@@ -43,6 +43,7 @@ func (respository OrderBestshopRepository) transformPgModelToDomainModel(orderMo @@ -43,6 +43,7 @@ func (respository OrderBestshopRepository) transformPgModelToDomainModel(orderMo
43 PartnerId: orderModel.PartnerId, 43 PartnerId: orderModel.PartnerId,
44 IsCopy: orderModel.IsCopy, 44 IsCopy: orderModel.IsCopy,
45 CompanyId: orderModel.CompanyId, 45 CompanyId: orderModel.CompanyId,
  46 + OrderArea: orderModel.OrderArea,
46 }, nil 47 }, nil
47 } 48 }
48 49
@@ -65,6 +66,7 @@ func (respository OrderBestshopRepository) Add(order *domain.OrderBestShop) erro @@ -65,6 +66,7 @@ func (respository OrderBestshopRepository) Add(order *domain.OrderBestShop) erro
65 PartnerId: order.PartnerId, 66 PartnerId: order.PartnerId,
66 IsCopy: order.IsCopy, 67 IsCopy: order.IsCopy,
67 CompanyId: order.CompanyId, 68 CompanyId: order.CompanyId,
  69 + OrderArea: order.OrderArea,
68 } 70 }
69 _, err := tx.Model(&m).Insert() 71 _, err := tx.Model(&m).Insert()
70 order.Id = m.Id 72 order.Id = m.Id
@@ -91,6 +93,7 @@ func (respository OrderBestshopRepository) Edit(order *domain.OrderBestShop) err @@ -91,6 +93,7 @@ func (respository OrderBestshopRepository) Edit(order *domain.OrderBestShop) err
91 PartnerId: order.PartnerId, 93 PartnerId: order.PartnerId,
92 IsCopy: order.IsCopy, 94 IsCopy: order.IsCopy,
93 CompanyId: order.CompanyId, 95 CompanyId: order.CompanyId,
  96 + OrderArea: order.OrderArea,
94 } 97 }
95 _, err := tx.Model(&m).Where("id=?", order.Id).Update() 98 _, err := tx.Model(&m).Where("id=?", order.Id).Update()
96 order.Id = m.Id 99 order.Id = m.Id
@@ -12,21 +12,6 @@ type PartnerCategoryRepository struct { @@ -12,21 +12,6 @@ type PartnerCategoryRepository struct {
12 transactionContext *transaction.TransactionContext 12 transactionContext *transaction.TransactionContext
13 } 13 }
14 14
15 -func (repository PartnerCategoryRepository) transformPgModelToDomainModel(m *models.PartnerCategoryInfo) (domain.PartnerCategory, error) {  
16 - pc := domain.PartnerCategory{  
17 - Id: m.Id,  
18 - Name: m.Name,  
19 - }  
20 - return pc, nil  
21 -}  
22 -  
23 -func NewPartnerCategoryRepository(transactionContext *transaction.TransactionContext) (*PartnerCategoryRepository, error) {  
24 - if transactionContext == nil {  
25 - return nil, fmt.Errorf("transactionContext参数不能为nil")  
26 - }  
27 - return &PartnerCategoryRepository{transactionContext: transactionContext}, nil  
28 -}  
29 -  
30 func (repository PartnerCategoryRepository) Find(queryOptions domain.PartnerCategoryFindQuery) (int, []domain.PartnerCategory, error) { 15 func (repository PartnerCategoryRepository) Find(queryOptions domain.PartnerCategoryFindQuery) (int, []domain.PartnerCategory, error) {
31 tx := repository.transactionContext.PgTx 16 tx := repository.transactionContext.PgTx
32 var ( 17 var (
@@ -48,3 +33,19 @@ func (repository PartnerCategoryRepository) Find(queryOptions domain.PartnerCate @@ -48,3 +33,19 @@ func (repository PartnerCategoryRepository) Find(queryOptions domain.PartnerCate
48 } 33 }
49 return cnt, partnerCategoryInfos, nil 34 return cnt, partnerCategoryInfos, nil
50 } 35 }
  36 +
  37 +func (repository PartnerCategoryRepository) transformPgModelToDomainModel(m *models.PartnerCategoryInfo) (domain.PartnerCategory, error) {
  38 + pc := domain.PartnerCategory{
  39 + Id: m.Id,
  40 + Name: m.Name,
  41 + Code: m.Code,
  42 + }
  43 + return pc, nil
  44 +}
  45 +
  46 +func NewPartnerCategoryRepository(transactionContext *transaction.TransactionContext) (*PartnerCategoryRepository, error) {
  47 + if transactionContext == nil {
  48 + return nil, fmt.Errorf("transactionContext参数不能为nil")
  49 + }
  50 + return &PartnerCategoryRepository{transactionContext: transactionContext}, nil
  51 +}
@@ -18,50 +18,18 @@ var ( @@ -18,50 +18,18 @@ var (
18 _ domain.PartnerInfoRepository = (*PartnerInfoRepository)(nil) 18 _ domain.PartnerInfoRepository = (*PartnerInfoRepository)(nil)
19 ) 19 )
20 20
21 -func (repository *PartnerInfoRepository) transformPgModelToDomainModel(partnerInfoModel *models.PartnerInfo) (domain.PartnerInfo, error) {  
22 - m := domain.PartnerInfo{  
23 - Partner: domain.Partner{  
24 - Id: partnerInfoModel.Id,  
25 - PartnerName: partnerInfoModel.PartnerName,  
26 - Account: partnerInfoModel.Account,  
27 - },  
28 - PartnerCategory: partnerInfoModel.PartnerCategory,  
29 - Password: partnerInfoModel.Password,  
30 - Status: partnerInfoModel.Status,  
31 - CreateAt: partnerInfoModel.CreateAt,  
32 - Salesman: partnerInfoModel.Salesman,  
33 - RegionInfo: partnerInfoModel.RegionInfo,  
34 - CooperateTime: partnerInfoModel.CooperateTime,  
35 - CompanyId: partnerInfoModel.CompanyId,  
36 - }  
37 - p := []domain.PartnerCategory{}  
38 - for _, v := range partnerInfoModel.PartnerCategoryInfos {  
39 - catagory := domain.PartnerCategory{  
40 - Id: v.Id,  
41 - }  
42 - p = append(p, catagory)  
43 - }  
44 - m.PartnerCategoryInfos = p  
45 - return m, nil  
46 -}  
47 -  
48 -func NewPartnerInfoRepository(transactionContext *transaction.TransactionContext) (*PartnerInfoRepository, error) {  
49 - if transactionContext == nil {  
50 - return nil, fmt.Errorf("transactionContext参数不能为nil")  
51 - }  
52 - return &PartnerInfoRepository{transactionContext: transactionContext}, nil  
53 -}  
54 -  
55 func (repository *PartnerInfoRepository) Save(dm *domain.PartnerInfo) error { 21 func (repository *PartnerInfoRepository) Save(dm *domain.PartnerInfo) error {
56 var ( 22 var (
57 err error 23 err error
58 tx = repository.transactionContext.PgTx 24 tx = repository.transactionContext.PgTx
59 ) 25 )
60 26
61 - categorys := []domain.PartnerCategory{} 27 + var categories []domain.PartnerCategory
62 for _, v := range dm.PartnerCategoryInfos { 28 for _, v := range dm.PartnerCategoryInfos {
63 - categorys = append(categorys, domain.PartnerCategory{  
64 - Id: v.Id, 29 + categories = append(categories, domain.PartnerCategory{
  30 + Id: v.Id,
  31 + Name: v.Name,
  32 + Code: v.Code,
65 }) 33 })
66 } 34 }
67 m := &models.PartnerInfo{ 35 m := &models.PartnerInfo{
@@ -75,7 +43,8 @@ func (repository *PartnerInfoRepository) Save(dm *domain.PartnerInfo) error { @@ -75,7 +43,8 @@ func (repository *PartnerInfoRepository) Save(dm *domain.PartnerInfo) error {
75 RegionInfo: dm.RegionInfo, 43 RegionInfo: dm.RegionInfo,
76 CooperateTime: dm.CooperateTime, 44 CooperateTime: dm.CooperateTime,
77 CompanyId: dm.CompanyId, 45 CompanyId: dm.CompanyId,
78 - PartnerCategoryInfos: categorys, 46 + PartnerCategoryInfos: categories,
  47 + Remark: dm.Remark,
79 } 48 }
80 if m.Id == 0 { 49 if m.Id == 0 {
81 err = tx.Insert(m) 50 err = tx.Insert(m)
@@ -86,7 +55,7 @@ func (repository *PartnerInfoRepository) Save(dm *domain.PartnerInfo) error { @@ -86,7 +55,7 @@ func (repository *PartnerInfoRepository) Save(dm *domain.PartnerInfo) error {
86 } else { 55 } else {
87 _, err = tx.Model(m).WherePK(). 56 _, err = tx.Model(m).WherePK().
88 Column("partner_name", "account", "password", "status", "partner_category", "salesman", 57 Column("partner_name", "account", "password", "status", "partner_category", "salesman",
89 - "region_info", "cooperate_time", "update_at", "partner_category_infos"). 58 + "region_info", "cooperate_time", "update_at", "partner_category_infos", "remark").
90 Update() 59 Update()
91 if err != nil { 60 if err != nil {
92 return err 61 return err
@@ -124,7 +93,7 @@ func (repository *PartnerInfoRepository) FindOne(queryOptions domain.PartnerFind @@ -124,7 +93,7 @@ func (repository *PartnerInfoRepository) FindOne(queryOptions domain.PartnerFind
124 93
125 func (repository *PartnerInfoRepository) Find(queryOption domain.PartnerFindQuery) ([]domain.PartnerInfo, error) { 94 func (repository *PartnerInfoRepository) Find(queryOption domain.PartnerFindQuery) ([]domain.PartnerInfo, error) {
126 db := repository.transactionContext.PgTx 95 db := repository.transactionContext.PgTx
127 - partnerModels := []models.PartnerInfo{} 96 + var partnerModels []models.PartnerInfo
128 query := db.Model(&partnerModels) 97 query := db.Model(&partnerModels)
129 if len(queryOption.PartnerName) > 0 { 98 if len(queryOption.PartnerName) > 0 {
130 query = query.Where("partner_name like ?", "%"+queryOption.PartnerName+"%") 99 query = query.Where("partner_name like ?", "%"+queryOption.PartnerName+"%")
@@ -174,7 +143,28 @@ func (repository *PartnerInfoRepository) Find(queryOption domain.PartnerFindQuer @@ -174,7 +143,28 @@ func (repository *PartnerInfoRepository) Find(queryOption domain.PartnerFindQuer
174 return partnerReturn, nil 143 return partnerReturn, nil
175 } 144 }
176 145
177 -func (repository PartnerInfoRepository) CountAll(queryOption domain.PartnerFindQuery) (int, error) { 146 +/**
  147 + * @Author SteveChan
  148 + * @Description //TODO 移除合伙人
  149 + * @Date 15:33 2020/12/29
  150 + * @Param
  151 + * @return
  152 + **/
  153 +func (repository *PartnerInfoRepository) Remove(id int64) error {
  154 + var (
  155 + err error
  156 + tx = repository.transactionContext.PgTx
  157 + )
  158 + m := &models.PartnerInfo{
  159 + Id: id,
  160 + }
  161 + _, err = tx.Model(m).
  162 + Where("id=?", id).
  163 + Delete()
  164 + return err
  165 +}
  166 +
  167 +func (repository *PartnerInfoRepository) CountAll(queryOption domain.PartnerFindQuery) (int, error) {
178 db := repository.transactionContext.PgTx 168 db := repository.transactionContext.PgTx
179 partnerModels := models.PartnerInfo{} 169 partnerModels := models.PartnerInfo{}
180 query := db.Model(&partnerModels) 170 query := db.Model(&partnerModels)
@@ -202,3 +192,40 @@ func (repository PartnerInfoRepository) CountAll(queryOption domain.PartnerFindQ @@ -202,3 +192,40 @@ func (repository PartnerInfoRepository) CountAll(queryOption domain.PartnerFindQ
202 cnt, err := query.Count() 192 cnt, err := query.Count()
203 return cnt, err 193 return cnt, err
204 } 194 }
  195 +
  196 +func (repository *PartnerInfoRepository) transformPgModelToDomainModel(partnerInfoModel *models.PartnerInfo) (domain.PartnerInfo, error) {
  197 + m := domain.PartnerInfo{
  198 + Partner: domain.Partner{
  199 + Id: partnerInfoModel.Id,
  200 + PartnerName: partnerInfoModel.PartnerName,
  201 + Account: partnerInfoModel.Account,
  202 + },
  203 + PartnerCategory: partnerInfoModel.PartnerCategory,
  204 + Password: partnerInfoModel.Password,
  205 + Status: partnerInfoModel.Status,
  206 + CreateAt: partnerInfoModel.CreateAt,
  207 + Salesman: partnerInfoModel.Salesman,
  208 + RegionInfo: partnerInfoModel.RegionInfo,
  209 + CooperateTime: partnerInfoModel.CooperateTime,
  210 + CompanyId: partnerInfoModel.CompanyId,
  211 + Remark: partnerInfoModel.Remark,
  212 + }
  213 + var p []domain.PartnerCategory
  214 + for _, v := range partnerInfoModel.PartnerCategoryInfos {
  215 + category := domain.PartnerCategory{
  216 + Id: v.Id,
  217 + Name: v.Name,
  218 + Code: v.Code,
  219 + }
  220 + p = append(p, category)
  221 + }
  222 + m.PartnerCategoryInfos = p
  223 + return m, nil
  224 +}
  225 +
  226 +func NewPartnerInfoRepository(transactionContext *transaction.TransactionContext) (*PartnerInfoRepository, error) {
  227 + if transactionContext == nil {
  228 + return nil, fmt.Errorf("transactionContext参数不能为nil")
  229 + }
  230 + return &PartnerInfoRepository{transactionContext: transactionContext}, nil
  231 +}
@@ -64,6 +64,7 @@ func (gateway MmmBusinessAdminServiceGateway) httpDo(reqURL string, mathod strin @@ -64,6 +64,7 @@ func (gateway MmmBusinessAdminServiceGateway) httpDo(reqURL string, mathod strin
64 return body, nil 64 return body, nil
65 } 65 }
66 66
  67 +// GetUserAuth 请求企业平台确认用户是否可以使用天联共创后台
67 func (gateway MmmBusinessAdminServiceGateway) GetUserAuth(userId int64) (*ResponseGetUserAuth, error) { 68 func (gateway MmmBusinessAdminServiceGateway) GetUserAuth(userId int64) (*ResponseGetUserAuth, error) {
68 param := map[string]interface{}{ 69 param := map[string]interface{}{
69 "userId": fmt.Sprint(userId), 70 "userId": fmt.Sprint(userId),
@@ -35,14 +35,15 @@ func (c *PartnerInfoController) Prepare() { @@ -35,14 +35,15 @@ func (c *PartnerInfoController) Prepare() {
35 func (c *PartnerInfoController) CreatePartnerInfo() { 35 func (c *PartnerInfoController) CreatePartnerInfo() {
36 //用与适配前端定义的数据结构 36 //用与适配前端定义的数据结构
37 type Parameter struct { 37 type Parameter struct {
38 - PartnerName string `json:"partnerName"`  
39 - PartnerType []int64 `json:"partnerType"`  
40 - Area string `json:"area"`  
41 - Account string `json:"account"`  
42 - State int `json:"state"`  
43 - CooperationTime string `json:"cooperationTime"`  
44 - SalesmanName string `json:"salesmanName"`  
45 - Phone string `json:"phone"` 38 + PartnerName string `json:"partnerName"`
  39 + PartnerType []*domain.PartnerCategory `json:"partnerType"`
  40 + Area string `json:"area"`
  41 + Account string `json:"account"`
  42 + State int `json:"state"`
  43 + CooperationTime string `json:"cooperationTime"`
  44 + SalesmanName string `json:"salesmanName"`
  45 + Phone string `json:"phone"`
  46 + Remark string `json:"remark"`
46 } 47 }
47 var ( 48 var (
48 param Parameter 49 param Parameter
@@ -69,6 +70,7 @@ func (c *PartnerInfoController) CreatePartnerInfo() { @@ -69,6 +70,7 @@ func (c *PartnerInfoController) CreatePartnerInfo() {
69 PartnerCategory: param.PartnerType, 70 PartnerCategory: param.PartnerType,
70 CooperateTime: cooperateTime, 71 CooperateTime: cooperateTime,
71 CompanyId: companyId, 72 CompanyId: companyId,
  73 + Remark: param.Remark,
72 } 74 }
73 if len(param.SalesmanName) > 0 || len(param.Phone) > 0 { 75 if len(param.SalesmanName) > 0 || len(param.Phone) > 0 {
74 cmd.Salesman = []domain.Salesman{ 76 cmd.Salesman = []domain.Salesman{
@@ -103,13 +105,14 @@ func (c *PartnerInfoController) CreatePartnerInfo() { @@ -103,13 +105,14 @@ func (c *PartnerInfoController) CreatePartnerInfo() {
103 func (c *PartnerInfoController) UpdatePartnerInfo() { 105 func (c *PartnerInfoController) UpdatePartnerInfo() {
104 //用与适配前端定义的数据结构 106 //用与适配前端定义的数据结构
105 type Parameter struct { 107 type Parameter struct {
106 - ID int64 `json:"id"`  
107 - PartnerType []int64 `json:"partnerType"`  
108 - Area string `json:"area"`  
109 - State int `json:"state"`  
110 - CooperationTime string `json:"cooperationTime"`  
111 - SalesmanName string `json:"salesmanName"`  
112 - Phone string `json:"phone"` 108 + ID int64 `json:"id"`
  109 + PartnerType []*domain.PartnerCategory `json:"partnerType"`
  110 + Area string `json:"area"`
  111 + State int `json:"state"`
  112 + CooperationTime string `json:"cooperationTime"`
  113 + SalesmanName string `json:"salesmanName"`
  114 + Phone string `json:"phone"`
  115 + Remark string `json:"remark"`
113 } 116 }
114 var ( 117 var (
115 param Parameter 118 param Parameter
@@ -142,6 +145,7 @@ func (c *PartnerInfoController) UpdatePartnerInfo() { @@ -142,6 +145,7 @@ func (c *PartnerInfoController) UpdatePartnerInfo() {
142 }, 145 },
143 }, 146 },
144 CompanyId: companyId, 147 CompanyId: companyId,
  148 + Remark: param.Remark,
145 } 149 }
146 serve := partnerInfoService.NewPartnerInfoService(nil) 150 serve := partnerInfoService.NewPartnerInfoService(nil)
147 err = serve.UpdatePartnerInfo(&cmd) 151 err = serve.UpdatePartnerInfo(&cmd)
@@ -190,16 +194,18 @@ func (c *PartnerInfoController) GetPartnerInfo() { @@ -190,16 +194,18 @@ func (c *PartnerInfoController) GetPartnerInfo() {
190 "cooperationTime": partnerInfo.CooperateTime.Local().Format("2006-01-02"), 194 "cooperationTime": partnerInfo.CooperateTime.Local().Format("2006-01-02"),
191 "state": partnerInfo.Status, 195 "state": partnerInfo.Status,
192 "id": partnerInfo.Partner.Id, 196 "id": partnerInfo.Partner.Id,
  197 + "remark": partnerInfo.Remark,
193 } 198 }
194 if len(partnerInfo.Salesman) > 0 { 199 if len(partnerInfo.Salesman) > 0 {
195 rspResult["salesmanName"] = partnerInfo.Salesman[0].Name 200 rspResult["salesmanName"] = partnerInfo.Salesman[0].Name
196 rspResult["phone"] = partnerInfo.Salesman[0].Telephone 201 rspResult["phone"] = partnerInfo.Salesman[0].Telephone
197 } 202 }
198 - partnerTypes := []map[string]interface{}{} 203 + var partnerTypes []map[string]interface{}
199 for _, v := range partnerInfo.PartnerCategoryInfos { 204 for _, v := range partnerInfo.PartnerCategoryInfos {
200 m := map[string]interface{}{ 205 m := map[string]interface{}{
201 "id": v.Id, 206 "id": v.Id,
202 "name": v.Name, 207 "name": v.Name,
  208 + "code": v.Code,
203 } 209 }
204 partnerTypes = append(partnerTypes, m) 210 partnerTypes = append(partnerTypes, m)
205 } 211 }
@@ -208,6 +214,40 @@ func (c *PartnerInfoController) GetPartnerInfo() { @@ -208,6 +214,40 @@ func (c *PartnerInfoController) GetPartnerInfo() {
208 return 214 return
209 } 215 }
210 216
  217 +/**
  218 + * @Author SteveChan
  219 + * @Description //TODO 移除合伙人
  220 + * @Date 15:31 2020/12/29
  221 + * @Param
  222 + * @return
  223 + **/
  224 +func (c *PartnerInfoController) RemovePartnerInfo() {
  225 + //用与适配前端定义的数据结构
  226 + type Parameter struct {
  227 + ID int64 `json:"id"`
  228 + }
  229 + var (
  230 + param Parameter
  231 + err error
  232 + )
  233 + if err = c.BindJsonData(&param); err != nil {
  234 + logs.Error(err)
  235 + c.ResponseError(errors.New("json数据解析失败"))
  236 + return
  237 + }
  238 + cmd := partnerInfoCmd.RemovePartnerInfoCommand{
  239 + Id: param.ID,
  240 + }
  241 + serve := partnerInfoService.NewPartnerInfoService(nil)
  242 + err = serve.RemovePartnerInfo(cmd)
  243 + if err != nil {
  244 + c.ResponseError(err)
  245 + return
  246 + }
  247 + c.ResponseData(nil)
  248 + return
  249 +}
  250 +
211 //PartnerInfoSetState 合伙人批量禁用.启用 251 //PartnerInfoSetState 合伙人批量禁用.启用
212 func (c *PartnerInfoController) PartnerInfoSetState() { 252 func (c *PartnerInfoController) PartnerInfoSetState() {
213 //用与适配前端定义的数据结构 253 //用与适配前端定义的数据结构
@@ -224,19 +264,19 @@ func (c *PartnerInfoController) PartnerInfoSetState() { @@ -224,19 +264,19 @@ func (c *PartnerInfoController) PartnerInfoSetState() {
224 c.ResponseError(errors.New("json数据解析失败")) 264 c.ResponseError(errors.New("json数据解析失败"))
225 return 265 return
226 } 266 }
227 - comanyId := c.GetUserCompany() 267 + companyId := c.GetUserCompany()
228 var cmd partnerInfoCmd.StatusPartnerInfoCommand 268 var cmd partnerInfoCmd.StatusPartnerInfoCommand
229 switch param.Status { 269 switch param.Status {
230 case 0: 270 case 0:
231 cmd = partnerInfoCmd.StatusPartnerInfoCommand{ 271 cmd = partnerInfoCmd.StatusPartnerInfoCommand{
232 Ids: param.Id, 272 Ids: param.Id,
233 - CompanyId: comanyId, 273 + CompanyId: companyId,
234 Status: domain.PARTNER_STATUS_NO, 274 Status: domain.PARTNER_STATUS_NO,
235 } 275 }
236 case 1: 276 case 1:
237 cmd = partnerInfoCmd.StatusPartnerInfoCommand{ 277 cmd = partnerInfoCmd.StatusPartnerInfoCommand{
238 Ids: param.Id, 278 Ids: param.Id,
239 - CompanyId: comanyId, 279 + CompanyId: companyId,
240 Status: domain.PARTNER_STATUS_YES, 280 Status: domain.PARTNER_STATUS_YES,
241 } 281 }
242 default: 282 default:
@@ -256,7 +296,7 @@ func (c *PartnerInfoController) PartnerInfoSetState() { @@ -256,7 +296,7 @@ func (c *PartnerInfoController) PartnerInfoSetState() {
256 //ListPartnerInfo 合伙人列表 296 //ListPartnerInfo 合伙人列表
257 func (c *PartnerInfoController) ListPartnerInfo() { 297 func (c *PartnerInfoController) ListPartnerInfo() {
258 type Parameter struct { 298 type Parameter struct {
259 - Partnertype int `json:"partnerType"` 299 + PartnerType int `json:"partnerType"`
260 Area string `json:"area"` 300 Area string `json:"area"`
261 PartnerName string `json:"partnerName"` 301 PartnerName string `json:"partnerName"`
262 PageSize int `json:"pageSize"` 302 PageSize int `json:"pageSize"`
@@ -280,7 +320,7 @@ func (c *PartnerInfoController) ListPartnerInfo() { @@ -280,7 +320,7 @@ func (c *PartnerInfoController) ListPartnerInfo() {
280 } 320 }
281 companyId := c.GetUserCompany() 321 companyId := c.GetUserCompany()
282 query := partnerQuery.ListPartnerInfoQuery{ 322 query := partnerQuery.ListPartnerInfoQuery{
283 - Partnertype: param.Partnertype, 323 + PartnerType: param.PartnerType,
284 PartnerName: param.PartnerName, 324 PartnerName: param.PartnerName,
285 RegionInfo: param.Area, 325 RegionInfo: param.Area,
286 Limit: param.PageSize, 326 Limit: param.PageSize,
@@ -294,7 +334,7 @@ func (c *PartnerInfoController) ListPartnerInfo() { @@ -294,7 +334,7 @@ func (c *PartnerInfoController) ListPartnerInfo() {
294 c.ResponseError(err) 334 c.ResponseError(err)
295 return 335 return
296 } 336 }
297 - resp := []map[string]interface{}{} 337 + var resp []map[string]interface{}
298 indexBegin := query.Offset 338 indexBegin := query.Offset
299 for i := range partners { 339 for i := range partners {
300 m := map[string]interface{}{ 340 m := map[string]interface{}{
@@ -309,6 +349,7 @@ func (c *PartnerInfoController) ListPartnerInfo() { @@ -309,6 +349,7 @@ func (c *PartnerInfoController) ListPartnerInfo() {
309 "partnerType": partners[i].PartnerCategoryInfos, 349 "partnerType": partners[i].PartnerCategoryInfos,
310 "salesmanName": "", 350 "salesmanName": "",
311 "phone": "", 351 "phone": "",
  352 + "remark": partners[i].Remark,
312 } 353 }
313 if len(partners[i].Salesman) > 0 { 354 if len(partners[i].Salesman) > 0 {
314 m["salesmanName"] = partners[i].Salesman[0].Name 355 m["salesmanName"] = partners[i].Salesman[0].Name
@@ -32,7 +32,7 @@ func (c *UserController) ListUser() { @@ -32,7 +32,7 @@ func (c *UserController) ListUser() {
32 //用与适配前端定义的数据结构 32 //用与适配前端定义的数据结构
33 type Paramter struct { 33 type Paramter struct {
34 SearchText string `json:"searchText"` 34 SearchText string `json:"searchText"`
35 - PageSize int `json::"pageSize"` 35 + PageSize int `json:"pageSize"`
36 PageNumber int `json:"pageNumber"` 36 PageNumber int `json:"pageNumber"`
37 } 37 }
38 var ( 38 var (
@@ -23,6 +23,7 @@ func init() { @@ -23,6 +23,7 @@ func init() {
23 beego.NSRouter("/edit", &controllers.PartnerInfoController{}, "POST:UpdatePartnerInfo"), 23 beego.NSRouter("/edit", &controllers.PartnerInfoController{}, "POST:UpdatePartnerInfo"),
24 beego.NSRouter("/detail", &controllers.PartnerInfoController{}, "POST:GetPartnerInfo"), 24 beego.NSRouter("/detail", &controllers.PartnerInfoController{}, "POST:GetPartnerInfo"),
25 beego.NSRouter("/batchDisabled", &controllers.PartnerInfoController{}, "POST:PartnerInfoSetState"), 25 beego.NSRouter("/batchDisabled", &controllers.PartnerInfoController{}, "POST:PartnerInfoSetState"),
  26 + beego.NSRouter("/remove", &controllers.PartnerInfoController{}, "POST:RemovePartnerInfo"),
26 ), 27 ),
27 beego.NSNamespace("/dividends", 28 beego.NSNamespace("/dividends",
28 beego.NSRouter("/list", &controllers.OrderDividendController{}, "POST:PageListOrderDividend"), 29 beego.NSRouter("/list", &controllers.OrderDividendController{}, "POST:PageListOrderDividend"),
@@ -8,7 +8,9 @@ import ( @@ -8,7 +8,9 @@ import (
8 //外部调用,企业平台,总后台调用 8 //外部调用,企业平台,总后台调用
9 func init() { 9 func init() {
10 nsPlatform := beego.NewNamespace("/platform", 10 nsPlatform := beego.NewNamespace("/platform",
  11 + //同步企业相关数据
11 beego.NSRouter("/action", &controllers.SyncDataController{}, "post:SyncData"), 12 beego.NSRouter("/action", &controllers.SyncDataController{}, "post:SyncData"),
  13 + //更换公司管理员
12 beego.NSRouter("/admins_change", &controllers.SyncDataController{}, "post:CompanyAdminChance"), 14 beego.NSRouter("/admins_change", &controllers.SyncDataController{}, "post:CompanyAdminChance"),
13 ) 15 )
14 nsUcenter := beego.NewNamespace("/ucenter", 16 nsUcenter := beego.NewNamespace("/ucenter",
@@ -51,6 +51,7 @@ func (c *MessageConsumer) ConsumeClaim(groupSession sarama.ConsumerGroupSession, @@ -51,6 +51,7 @@ func (c *MessageConsumer) ConsumeClaim(groupSession sarama.ConsumerGroupSession,
51 } 51 }
52 if err = topicHandle(message); err != nil { 52 if err = topicHandle(message); err != nil {
53 logs.Error("Message claimed: kafka消息处理错误 topic =", message.Topic, message.Offset, err) 53 logs.Error("Message claimed: kafka消息处理错误 topic =", message.Topic, message.Offset, err)
  54 +
54 } 55 }
55 groupSession.MarkMessage(message, "") 56 groupSession.MarkMessage(message, "")
56 } 57 }
@@ -30,6 +30,9 @@ func init() { @@ -30,6 +30,9 @@ func init() {
30 if runEnv == "partnermg_prd" { 30 if runEnv == "partnermg_prd" {
31 initHandleRoutersProd() 31 initHandleRoutersProd()
32 } 32 }
  33 + if runEnv == "partnermg_dev" {
  34 + initHandleRoutersDev()
  35 + }
33 } 36 }
34 37
35 func initHandleRoutersTest() { 38 func initHandleRoutersTest() {
@@ -39,3 +42,7 @@ func initHandleRoutersTest() { @@ -39,3 +42,7 @@ func initHandleRoutersTest() {
39 func initHandleRoutersProd() { 42 func initHandleRoutersProd() {
40 TopicHandleRouters["xiangmi_project"] = handles.DataFromXiangMi 43 TopicHandleRouters["xiangmi_project"] = handles.DataFromXiangMi
41 } 44 }
  45 +
  46 +func initHandleRoutersDev() {
  47 + TopicHandleRouters["xiangmi_project_dev"] = handles.DataFromXiangMi
  48 +}
1 -package geetest  
2 -  
3 -import (  
4 - "crypto/md5"  
5 - "encoding/hex"  
6 - "encoding/json"  
7 - "errors"  
8 - "io/ioutil"  
9 - "net/http"  
10 - "net/url"  
11 - "strings"  
12 - "time"  
13 -)  
14 -  
15 -type GeetestLib struct {  
16 - CaptchaID string  
17 - PrivateKey string  
18 - Client *http.Client  
19 -}  
20 -  
21 -type FailbackRegisterRespnse struct {  
22 - Success int `json:"success"`  
23 - GT string `json:"gt"`  
24 - Challenge string `json:"challenge"`  
25 - NewCaptcha int `json:"new_captcha"`  
26 -}  
27 -  
28 -const (  
29 - geetestHost = "http://api.geetest.com"  
30 - registerURL = geetestHost + "/register.php"  
31 - validateURL = geetestHost + "/validate.php"  
32 -)  
33 -  
34 -func MD5Encode(input string) string {  
35 - md5Instant := md5.New()  
36 - md5Instant.Write([]byte(input))  
37 - return hex.EncodeToString(md5Instant.Sum(nil))  
38 -}  
39 -  
40 -// 初始化 GeetestLib  
41 -func NewGeetestLib(capthcaID string, privateKey string, timeOut time.Duration) (geetest GeetestLib){  
42 - client := &http.Client{Timeout: timeOut}  
43 - geetest = GeetestLib{capthcaID, privateKey, client}  
44 - return  
45 -}  
46 -  
47 -func (g *GeetestLib) getFailBackRegisterResponse(success int, challenge string) []byte {  
48 - if challenge == "" {  
49 - challenge = hex.EncodeToString(md5.New().Sum(nil))  
50 - }  
51 -  
52 - response := FailbackRegisterRespnse{  
53 - success,  
54 - g.CaptchaID,  
55 - challenge,  
56 - 1,  
57 - }  
58 - res, _ := json.Marshal(response)  
59 - return res  
60 -}  
61 -  
62 -func (g *GeetestLib) do(req *http.Request) (body []byte, err error) {  
63 - req.Header.Set("Content-Type", "application/x-www-form-urlencoded")  
64 - var resp *http.Response  
65 - if resp, err = g.Client.Do(req); err != nil {  
66 - return  
67 - }  
68 - defer resp.Body.Close()  
69 - if resp.StatusCode >= http.StatusInternalServerError {  
70 - err = errors.New("http status code 5xx")  
71 - return  
72 - }  
73 -  
74 - if body, err = ioutil.ReadAll(resp.Body); err != nil {  
75 - return  
76 - }  
77 - return  
78 -}  
79 -  
80 -func (g *GeetestLib) PreProcess(userID string, userIP string) (int8, []byte) {  
81 - params := url.Values{}  
82 - params.Add("gt", g.CaptchaID)  
83 - params.Add("new_captcha", "1")  
84 - if userID != "" {  
85 - params.Add("user_id", userID)  
86 - }  
87 - if userIP != "" {  
88 - params.Add("ip_adress", userIP)  
89 - }  
90 - req, _ := http.NewRequest("GET", registerURL+"?"+params.Encode(), nil)  
91 - body, err := g.do(req)  
92 - if err != nil {  
93 - return 0, g.getFailBackRegisterResponse(0, "")  
94 - }  
95 - challenge := string(body)  
96 - if len(challenge) != 32 {  
97 - return 0, g.getFailBackRegisterResponse(0, "")  
98 - } else {  
99 - challenge = MD5Encode(challenge + g.PrivateKey)  
100 - return 1, g.getFailBackRegisterResponse(1, challenge)  
101 - }  
102 -}  
103 -  
104 -func (g *GeetestLib) checkParas(challenge string, validate string, seccode string) bool {  
105 - if challenge == "" || validate == "" || seccode == "" {  
106 - return false  
107 - }  
108 - return true  
109 -}  
110 -  
111 -func (g *GeetestLib) checkSuccessRes(challenge string, validate string) bool {  
112 - return MD5Encode(g.PrivateKey+"geetest"+challenge) == validate  
113 -}  
114 -  
115 -func (g *GeetestLib) checkFailbackRes(challenge string, validate string) bool {  
116 - return MD5Encode(challenge) == validate  
117 -}  
118 -  
119 -func (g *GeetestLib) SuccessValidate(challenge string, validate string, seccode string, userID string, userIP string) bool {  
120 - if !g.checkParas(challenge, validate, seccode) {  
121 - return false  
122 - }  
123 - if !g.checkSuccessRes(challenge, validate) {  
124 - return false  
125 - }  
126 - params := url.Values{}  
127 - params.Add("seccode", seccode)  
128 - params.Add("challenge", challenge)  
129 - params.Add("captchaid", g.CaptchaID)  
130 - params.Add("sdk", "golang_v1.0.0")  
131 - if userID != "" {  
132 - params.Add("user_id", userID)  
133 - }  
134 - if userIP != "" {  
135 - params.Add("ip_adress", userIP)  
136 - }  
137 - req, _ := http.NewRequest("POST", validateURL, strings.NewReader(params.Encode()))  
138 - body, err := g.do(req)  
139 - if err != nil {  
140 - return false  
141 - }  
142 - res := string(body)  
143 - return res == MD5Encode(seccode)  
144 -}  
145 -  
146 -func (g *GeetestLib) FailbackValidate(challenge string, validate string, seccode string) bool {  
147 - if !g.checkParas(challenge, validate, seccode) {  
148 - return false  
149 - }  
150 - if !g.checkFailbackRes(challenge, validate) {  
151 - return false  
152 - }  
153 - return true  
154 -}  
1 -language: go  
2 -go:  
3 - - 1.2  
4 - - stable 1 +language: go
  2 +go:
  3 + - 1.2
  4 + - stable
5 - tip 5 - tip
1 -A reader for Microsoft's Compound File Binary File Format.  
2 -  
3 -Example usage:  
4 -  
5 - file, _ := os.Open("test/test.doc")  
6 - defer file.Close()  
7 - doc, err := mscfb.New(file)  
8 - if err != nil {  
9 - log.Fatal(err)  
10 - }  
11 - for entry, err := doc.Next(); err == nil; entry, err = doc.Next() {  
12 - buf := make([]byte, 512)  
13 - i, _ := doc.Read(buf)  
14 - if i > 0 {  
15 - fmt.Println(buf[:i])  
16 - }  
17 - fmt.Println(entry.Name)  
18 - }  
19 -  
20 -The Compound File Binary File Format is also known as the Object Linking and Embedding (OLE) or Component Object Model (COM) format and was used by early MS software such as MS Office. See [http://msdn.microsoft.com/en-us/library/dd942138.aspx](http://msdn.microsoft.com/en-us/library/dd942138.aspx) for more details  
21 -  
22 -Install with `go get github.com/richardlehane/mscfb`  
23 - 1 +A reader for Microsoft's Compound File Binary File Format.
  2 +
  3 +Example usage:
  4 +
  5 + file, _ := os.Open("test/test.doc")
  6 + defer file.Close()
  7 + doc, err := mscfb.New(file)
  8 + if err != nil {
  9 + log.Fatal(err)
  10 + }
  11 + for entry, err := doc.Next(); err == nil; entry, err = doc.Next() {
  12 + buf := make([]byte, 512)
  13 + i, _ := doc.Read(buf)
  14 + if i > 0 {
  15 + fmt.Println(buf[:i])
  16 + }
  17 + fmt.Println(entry.Name)
  18 + }
  19 +
  20 +The Compound File Binary File Format is also known as the Object Linking and Embedding (OLE) or Component Object Model (COM) format and was used by early MS software such as MS Office. See [http://msdn.microsoft.com/en-us/library/dd942138.aspx](http://msdn.microsoft.com/en-us/library/dd942138.aspx) for more details
  21 +
  22 +Install with `go get github.com/richardlehane/mscfb`
  23 +
24 [![Build Status](https://travis-ci.org/richardlehane/mscfb.png?branch=master)](https://travis-ci.org/richardlehane/mscfb) 24 [![Build Status](https://travis-ci.org/richardlehane/mscfb.png?branch=master)](https://travis-ci.org/richardlehane/mscfb)
1 -// +build gofuzz  
2 -  
3 -// fuzzing with https://github.com/dvyukov/go-fuzz  
4 -package mscfb  
5 -  
6 -import (  
7 - "bytes"  
8 - "io"  
9 -)  
10 -  
11 -func Fuzz(data []byte) int {  
12 - doc, err := New(bytes.NewReader(data))  
13 - if err != nil {  
14 - if doc != nil {  
15 - panic("doc != nil on error " + err.Error())  
16 - }  
17 - return 0  
18 - }  
19 - buf := &bytes.Buffer{}  
20 - for entry, err := doc.Next(); ; entry, err = doc.Next() {  
21 - if err != nil {  
22 - if err == io.EOF {  
23 - return 1  
24 - }  
25 - if entry != nil {  
26 - panic("entry != nil on error " + err.Error())  
27 - }  
28 - }  
29 - buf.Reset()  
30 - buf.ReadFrom(entry)  
31 - }  
32 - return 1  
33 -} 1 +// +build gofuzz
  2 +
  3 +// fuzzing with https://github.com/dvyukov/go-fuzz
  4 +package mscfb
  5 +
  6 +import (
  7 + "bytes"
  8 + "io"
  9 +)
  10 +
  11 +func Fuzz(data []byte) int {
  12 + doc, err := New(bytes.NewReader(data))
  13 + if err != nil {
  14 + if doc != nil {
  15 + panic("doc != nil on error " + err.Error())
  16 + }
  17 + return 0
  18 + }
  19 + buf := &bytes.Buffer{}
  20 + for entry, err := doc.Next(); ; entry, err = doc.Next() {
  21 + if err != nil {
  22 + if err == io.EOF {
  23 + return 1
  24 + }
  25 + if entry != nil {
  26 + panic("entry != nil on error " + err.Error())
  27 + }
  28 + }
  29 + buf.Reset()
  30 + buf.ReadFrom(entry)
  31 + }
  32 + return 1
  33 +}
1 -// Copyright 2013 Richard Lehane. All rights reserved.  
2 -//  
3 -// Licensed under the Apache License, Version 2.0 (the "License");  
4 -// you may not use this file except in compliance with the License.  
5 -// You may obtain a copy of the License at  
6 -//  
7 -// http://www.apache.org/licenses/LICENSE-2.0  
8 -//  
9 -// Unless required by applicable law or agreed to in writing, software  
10 -// distributed under the License is distributed on an "AS IS" BASIS,  
11 -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  
12 -// See the License for the specific language governing permissions and  
13 -// limitations under the License.  
14 -  
15 -// Package mscfb implements a reader for Microsoft's Compound File Binary File Format (http://msdn.microsoft.com/en-us/library/dd942138.aspx).  
16 -//  
17 -// The Compound File Binary File Format is also known as the Object Linking and Embedding (OLE) or Component Object Model (COM) format and was used by many  
18 -// early MS software such as MS Office.  
19 -//  
20 -// Example:  
21 -// file, _ := os.Open("test/test.doc")  
22 -// defer file.Close()  
23 -// doc, err := mscfb.New(file)  
24 -// if err != nil {  
25 -// log.Fatal(err)  
26 -// }  
27 -// for entry, err := doc.Next(); err == nil; entry, err = doc.Next() {  
28 -// buf := make([]byte, 512)  
29 -// i, _ := entry.Read(buf)  
30 -// if i > 0 {  
31 -// fmt.Println(buf[:i])  
32 -// }  
33 -// fmt.Println(entry.Name)  
34 -// }  
35 -package mscfb  
36 -  
37 -import (  
38 - "encoding/binary"  
39 - "io"  
40 - "strconv"  
41 - "time"  
42 -)  
43 -  
44 -func fileOffset(ss, sn uint32) int64 {  
45 - return int64((sn + 1) * ss)  
46 -}  
47 -  
48 -const (  
49 - signature uint64 = 0xE11AB1A1E011CFD0  
50 - miniStreamSectorSize uint32 = 64  
51 - miniStreamCutoffSize int64 = 4096  
52 - dirEntrySize uint32 = 128 //128 bytes  
53 -)  
54 -  
55 -const (  
56 - maxRegSect uint32 = 0xFFFFFFFA // Maximum regular sector number  
57 - difatSect uint32 = 0xFFFFFFFC //Specifies a DIFAT sector in the FAT  
58 - fatSect uint32 = 0xFFFFFFFD // Specifies a FAT sector in the FAT  
59 - endOfChain uint32 = 0xFFFFFFFE // End of linked chain of sectors  
60 - freeSect uint32 = 0xFFFFFFFF // Speficies unallocated sector in the FAT, Mini FAT or DIFAT  
61 - maxRegStreamID uint32 = 0xFFFFFFFA // maximum regular stream ID  
62 - noStream uint32 = 0xFFFFFFFF // empty pointer  
63 -)  
64 -  
65 -const lenHeader int = 8 + 16 + 10 + 6 + 12 + 8 + 16 + 109*4  
66 -  
67 -type headerFields struct {  
68 - signature uint64  
69 - _ [16]byte //CLSID - ignore, must be null  
70 - minorVersion uint16 //Version number for non-breaking changes. This field SHOULD be set to 0x003E if the major version field is either 0x0003 or 0x0004.  
71 - majorVersion uint16 //Version number for breaking changes. This field MUST be set to either 0x0003 (version 3) or 0x0004 (version 4).  
72 - _ [2]byte //byte order - ignore, must be little endian  
73 - sectorSize uint16 //This field MUST be set to 0x0009, or 0x000c, depending on the Major Version field. This field specifies the sector size of the compound file as a power of 2. If Major Version is 3, then the Sector Shift MUST be 0x0009, specifying a sector size of 512 bytes. If Major Version is 4, then the Sector Shift MUST be 0x000C, specifying a sector size of 4096 bytes.  
74 - _ [2]byte // ministream sector size - ignore, must be 64 bytes  
75 - _ [6]byte // reserved - ignore, not used  
76 - numDirectorySectors uint32 //This integer field contains the count of the number of directory sectors in the compound file. If Major Version is 3, then the Number of Directory Sectors MUST be zero. This field is not supported for version 3 compound files.  
77 - numFatSectors uint32 //This integer field contains the count of the number of FAT sectors in the compound file.  
78 - directorySectorLoc uint32 //This integer field contains the starting sector number for the directory stream.  
79 - _ [4]byte // transaction - ignore, not used  
80 - _ [4]byte // mini stream size cutooff - ignore, must be 4096 bytes  
81 - miniFatSectorLoc uint32 //This integer field contains the starting sector number for the mini FAT.  
82 - numMiniFatSectors uint32 //This integer field contains the count of the number of mini FAT sectors in the compound file.  
83 - difatSectorLoc uint32 //This integer field contains the starting sector number for the DIFAT.  
84 - numDifatSectors uint32 //This integer field contains the count of the number of DIFAT sectors in the compound file.  
85 - initialDifats [109]uint32 //The first 109 difat sectors are included in the header  
86 -}  
87 -  
88 -func makeHeader(b []byte) *headerFields {  
89 - h := &headerFields{}  
90 - h.signature = binary.LittleEndian.Uint64(b[:8])  
91 - h.minorVersion = binary.LittleEndian.Uint16(b[24:26])  
92 - h.majorVersion = binary.LittleEndian.Uint16(b[26:28])  
93 - h.sectorSize = binary.LittleEndian.Uint16(b[30:32])  
94 - h.numDirectorySectors = binary.LittleEndian.Uint32(b[40:44])  
95 - h.numFatSectors = binary.LittleEndian.Uint32(b[44:48])  
96 - h.directorySectorLoc = binary.LittleEndian.Uint32(b[48:52])  
97 - h.miniFatSectorLoc = binary.LittleEndian.Uint32(b[60:64])  
98 - h.numMiniFatSectors = binary.LittleEndian.Uint32(b[64:68])  
99 - h.difatSectorLoc = binary.LittleEndian.Uint32(b[68:72])  
100 - h.numDifatSectors = binary.LittleEndian.Uint32(b[72:76])  
101 - var idx int  
102 - for i := 76; i < 512; i = i + 4 {  
103 - h.initialDifats[idx] = binary.LittleEndian.Uint32(b[i : i+4])  
104 - idx++  
105 - }  
106 - return h  
107 -}  
108 -  
109 -type header struct {  
110 - *headerFields  
111 - difats []uint32  
112 - miniFatLocs []uint32  
113 - miniStreamLocs []uint32 // chain of sectors containing the ministream  
114 -}  
115 -  
116 -func (r *Reader) setHeader() error {  
117 - buf, err := r.readAt(0, lenHeader)  
118 - if err != nil {  
119 - return err  
120 - }  
121 - r.header = &header{headerFields: makeHeader(buf)}  
122 - // sanity check - check signature  
123 - if r.header.signature != signature {  
124 - return Error{ErrFormat, "bad signature", int64(r.header.signature)}  
125 - }  
126 - // check for legal sector size  
127 - if r.header.sectorSize == 0x0009 || r.header.sectorSize == 0x000c {  
128 - r.sectorSize = uint32(1 << r.header.sectorSize)  
129 - } else {  
130 - return Error{ErrFormat, "illegal sector size", int64(r.header.sectorSize)}  
131 - }  
132 - // check for DIFAT overflow  
133 - if r.header.numDifatSectors > 0 {  
134 - sz := (r.sectorSize / 4) - 1  
135 - if int(r.header.numDifatSectors*sz+109) < 0 {  
136 - return Error{ErrFormat, "DIFAT int overflow", int64(r.header.numDifatSectors)}  
137 - }  
138 - if r.header.numDifatSectors*sz+109 > r.header.numFatSectors+sz {  
139 - return Error{ErrFormat, "num DIFATs exceeds FAT sectors", int64(r.header.numDifatSectors)}  
140 - }  
141 - }  
142 - // check for mini FAT overflow  
143 - if r.header.numMiniFatSectors > 0 {  
144 - if int(r.sectorSize/4*r.header.numMiniFatSectors) < 0 {  
145 - return Error{ErrFormat, "mini FAT int overflow", int64(r.header.numMiniFatSectors)}  
146 - }  
147 - if r.header.numMiniFatSectors > r.header.numFatSectors*(r.sectorSize/miniStreamSectorSize) {  
148 - return Error{ErrFormat, "num mini FATs exceeds FAT sectors", int64(r.header.numFatSectors)}  
149 - }  
150 - }  
151 - return nil  
152 -}  
153 -  
154 -func (r *Reader) setDifats() error {  
155 - r.header.difats = r.header.initialDifats[:]  
156 - // return early if no extra DIFAT sectors  
157 - if r.header.numDifatSectors == 0 {  
158 - return nil  
159 - }  
160 - sz := (r.sectorSize / 4) - 1  
161 - n := make([]uint32, 109, r.header.numDifatSectors*sz+109)  
162 - copy(n, r.header.difats)  
163 - r.header.difats = n  
164 - off := r.header.difatSectorLoc  
165 - for i := 0; i < int(r.header.numDifatSectors); i++ {  
166 - buf, err := r.readAt(fileOffset(r.sectorSize, off), int(r.sectorSize))  
167 - if err != nil {  
168 - return Error{ErrFormat, "error setting DIFAT(" + err.Error() + ")", int64(off)}  
169 - }  
170 - for j := 0; j < int(sz); j++ {  
171 - r.header.difats = append(r.header.difats, binary.LittleEndian.Uint32(buf[j*4:j*4+4]))  
172 - }  
173 - off = binary.LittleEndian.Uint32(buf[len(buf)-4:])  
174 - }  
175 - return nil  
176 -}  
177 -  
178 -// set the ministream FAT and sector slices in the header  
179 -func (r *Reader) setMiniStream() error {  
180 - // do nothing if there is no ministream  
181 - if r.direntries[0].startingSectorLoc == endOfChain || r.header.miniFatSectorLoc == endOfChain || r.header.numMiniFatSectors == 0 {  
182 - return nil  
183 - }  
184 - // build a slice of minifat sectors (akin to the DIFAT slice)  
185 - c := int(r.header.numMiniFatSectors)  
186 - r.header.miniFatLocs = make([]uint32, c)  
187 - r.header.miniFatLocs[0] = r.header.miniFatSectorLoc  
188 - for i := 1; i < c; i++ {  
189 - loc, err := r.findNext(r.header.miniFatLocs[i-1], false)  
190 - if err != nil {  
191 - return Error{ErrFormat, "setting mini stream (" + err.Error() + ")", int64(r.header.miniFatLocs[i-1])}  
192 - }  
193 - r.header.miniFatLocs[i] = loc  
194 - }  
195 - // build a slice of ministream sectors  
196 - c = int(r.sectorSize / 4 * r.header.numMiniFatSectors)  
197 - r.header.miniStreamLocs = make([]uint32, 0, c)  
198 - sn := r.direntries[0].startingSectorLoc  
199 - var err error  
200 - for sn != endOfChain {  
201 - r.header.miniStreamLocs = append(r.header.miniStreamLocs, sn)  
202 - sn, err = r.findNext(sn, false)  
203 - if err != nil {  
204 - return Error{ErrFormat, "setting mini stream (" + err.Error() + ")", int64(sn)}  
205 - }  
206 - }  
207 - return nil  
208 -}  
209 -  
210 -func (r *Reader) readAt(offset int64, length int) ([]byte, error) {  
211 - if r.slicer {  
212 - b, err := r.ra.(slicer).Slice(offset, length)  
213 - if err != nil {  
214 - return nil, Error{ErrRead, "slicer read error (" + err.Error() + ")", offset}  
215 - }  
216 - return b, nil  
217 - }  
218 - if length > len(r.buf) {  
219 - return nil, Error{ErrRead, "read length greater than read buffer", int64(length)}  
220 - }  
221 - if _, err := r.ra.ReadAt(r.buf[:length], offset); err != nil {  
222 - return nil, Error{ErrRead, err.Error(), offset}  
223 - }  
224 - return r.buf[:length], nil  
225 -}  
226 -  
227 -func (r *Reader) getOffset(sn uint32, mini bool) (int64, error) {  
228 - if mini {  
229 - num := r.sectorSize / 64  
230 - sec := int(sn / num)  
231 - if sec >= len(r.header.miniStreamLocs) {  
232 - return 0, Error{ErrRead, "minisector number is outside minisector range", int64(sec)}  
233 - }  
234 - dif := sn % num  
235 - return int64((r.header.miniStreamLocs[sec]+1)*r.sectorSize + dif*64), nil  
236 - }  
237 - return fileOffset(r.sectorSize, sn), nil  
238 -}  
239 -  
240 -// check the FAT sector for the next sector in a chain  
241 -func (r *Reader) findNext(sn uint32, mini bool) (uint32, error) {  
242 - entries := r.sectorSize / 4  
243 - index := int(sn / entries) // find position in DIFAT or minifat array  
244 - var sect uint32  
245 - if mini {  
246 - if index < 0 || index >= len(r.header.miniFatLocs) {  
247 - return 0, Error{ErrRead, "minisector index is outside miniFAT range", int64(index)}  
248 - }  
249 - sect = r.header.miniFatLocs[index]  
250 - } else {  
251 - if index < 0 || index >= len(r.header.difats) {  
252 - return 0, Error{ErrRead, "FAT index is outside DIFAT range", int64(index)}  
253 - }  
254 - sect = r.header.difats[index]  
255 - }  
256 - fatIndex := sn % entries // find position within FAT or MiniFAT sector  
257 - offset := fileOffset(r.sectorSize, sect) + int64(fatIndex*4)  
258 - buf, err := r.readAt(offset, 4)  
259 - if err != nil {  
260 - return 0, Error{ErrRead, "bad read finding next sector (" + err.Error() + ")", offset}  
261 - }  
262 - return binary.LittleEndian.Uint32(buf), nil  
263 -}  
264 -  
265 -// Reader provides sequential access to the contents of a MS compound file (MSCFB)  
266 -type Reader struct {  
267 - slicer bool  
268 - sectorSize uint32  
269 - buf []byte  
270 - header *header  
271 - File []*File // File is an ordered slice of final directory entries.  
272 - direntries []*File // unordered raw directory entries  
273 - entry int  
274 -  
275 - ra io.ReaderAt  
276 - wa io.WriterAt  
277 -}  
278 -  
279 -// New returns a MSCFB reader  
280 -func New(ra io.ReaderAt) (*Reader, error) {  
281 - r := &Reader{ra: ra}  
282 - if _, ok := ra.(slicer); ok {  
283 - r.slicer = true  
284 - } else {  
285 - r.buf = make([]byte, lenHeader)  
286 - }  
287 - if err := r.setHeader(); err != nil {  
288 - return nil, err  
289 - }  
290 - // resize the buffer to 4096 if sector size isn't 512  
291 - if !r.slicer && int(r.sectorSize) > len(r.buf) {  
292 - r.buf = make([]byte, r.sectorSize)  
293 - }  
294 - if err := r.setDifats(); err != nil {  
295 - return nil, err  
296 - }  
297 - if err := r.setDirEntries(); err != nil {  
298 - return nil, err  
299 - }  
300 - if err := r.setMiniStream(); err != nil {  
301 - return nil, err  
302 - }  
303 - if err := r.traverse(); err != nil {  
304 - return nil, err  
305 - }  
306 - return r, nil  
307 -}  
308 -  
309 -// ID returns the CLSID (class ID) field from the root directory entry  
310 -func (r *Reader) ID() string {  
311 - return r.File[0].ID()  
312 -}  
313 -  
314 -// Created returns the created field from the root directory entry  
315 -func (r *Reader) Created() time.Time {  
316 - return r.File[0].Created()  
317 -}  
318 -  
319 -// Modified returns the last modified field from the root directory entry  
320 -func (r *Reader) Modified() time.Time {  
321 - return r.File[0].Modified()  
322 -}  
323 -  
324 -// Next iterates to the next directory entry.  
325 -// This isn't necessarily an adjacent *File within the File slice, but is based on the Left Sibling, Right Sibling and Child information in directory entries.  
326 -func (r *Reader) Next() (*File, error) {  
327 - r.entry++  
328 - if r.entry >= len(r.File) {  
329 - return nil, io.EOF  
330 - }  
331 - return r.File[r.entry], nil  
332 -}  
333 -  
334 -// Read the current directory entry  
335 -func (r *Reader) Read(b []byte) (n int, err error) {  
336 - if r.entry >= len(r.File) {  
337 - return 0, io.EOF  
338 - }  
339 - return r.File[r.entry].Read(b)  
340 -}  
341 -  
342 -// Debug provides granular information from an mscfb file to assist with debugging  
343 -func (r *Reader) Debug() map[string][]uint32 {  
344 - ret := map[string][]uint32{  
345 - "sector size": []uint32{r.sectorSize},  
346 - "mini fat locs": r.header.miniFatLocs,  
347 - "mini stream locs": r.header.miniStreamLocs,  
348 - "directory sector": []uint32{r.header.directorySectorLoc},  
349 - "mini stream start/size": []uint32{r.File[0].startingSectorLoc, binary.LittleEndian.Uint32(r.File[0].streamSize[:])},  
350 - }  
351 - for f, err := r.Next(); err == nil; f, err = r.Next() {  
352 - ret[f.Name+" start/size"] = []uint32{f.startingSectorLoc, binary.LittleEndian.Uint32(f.streamSize[:])}  
353 - }  
354 - return ret  
355 -}  
356 -  
357 -const (  
358 - // ErrFormat reports issues with the MSCFB's header structures  
359 - ErrFormat = iota  
360 - // ErrRead reports issues attempting to read MSCFB streams  
361 - ErrRead  
362 - // ErrSeek reports seek issues  
363 - ErrSeek  
364 - // ErrWrite reports write issues  
365 - ErrWrite  
366 - // ErrTraverse reports issues attempting to traverse the child-parent-sibling relations  
367 - // between MSCFB storage objects  
368 - ErrTraverse  
369 -)  
370 -  
371 -type Error struct {  
372 - typ int  
373 - msg string  
374 - val int64  
375 -}  
376 -  
377 -func (e Error) Error() string {  
378 - return "mscfb: " + e.msg + "; " + strconv.FormatInt(e.val, 10)  
379 -}  
380 -  
381 -// Typ gives the type of MSCFB error  
382 -func (e Error) Typ() int {  
383 - return e.typ  
384 -}  
385 -  
386 -// Slicer interface avoids a copy by obtaining a byte slice directly from the underlying reader  
387 -type slicer interface {  
388 - Slice(offset int64, length int) ([]byte, error)  
389 -} 1 +// Copyright 2013 Richard Lehane. All rights reserved.
  2 +//
  3 +// Licensed under the Apache License, Version 2.0 (the "License");
  4 +// you may not use this file except in compliance with the License.
  5 +// You may obtain a copy of the License at
  6 +//
  7 +// http://www.apache.org/licenses/LICENSE-2.0
  8 +//
  9 +// Unless required by applicable law or agreed to in writing, software
  10 +// distributed under the License is distributed on an "AS IS" BASIS,
  11 +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  12 +// See the License for the specific language governing permissions and
  13 +// limitations under the License.
  14 +
  15 +// Package mscfb implements a reader for Microsoft's Compound File Binary File Format (http://msdn.microsoft.com/en-us/library/dd942138.aspx).
  16 +//
  17 +// The Compound File Binary File Format is also known as the Object Linking and Embedding (OLE) or Component Object Model (COM) format and was used by many
  18 +// early MS software such as MS Office.
  19 +//
  20 +// Example:
  21 +// file, _ := os.Open("test/test.doc")
  22 +// defer file.Close()
  23 +// doc, err := mscfb.New(file)
  24 +// if err != nil {
  25 +// log.Fatal(err)
  26 +// }
  27 +// for entry, err := doc.Next(); err == nil; entry, err = doc.Next() {
  28 +// buf := make([]byte, 512)
  29 +// i, _ := entry.Read(buf)
  30 +// if i > 0 {
  31 +// fmt.Println(buf[:i])
  32 +// }
  33 +// fmt.Println(entry.Name)
  34 +// }
  35 +package mscfb
  36 +
  37 +import (
  38 + "encoding/binary"
  39 + "io"
  40 + "strconv"
  41 + "time"
  42 +)
  43 +
  44 +func fileOffset(ss, sn uint32) int64 {
  45 + return int64((sn + 1) * ss)
  46 +}
  47 +
  48 +const (
  49 + signature uint64 = 0xE11AB1A1E011CFD0
  50 + miniStreamSectorSize uint32 = 64
  51 + miniStreamCutoffSize int64 = 4096
  52 + dirEntrySize uint32 = 128 //128 bytes
  53 +)
  54 +
  55 +const (
  56 + maxRegSect uint32 = 0xFFFFFFFA // Maximum regular sector number
  57 + difatSect uint32 = 0xFFFFFFFC //Specifies a DIFAT sector in the FAT
  58 + fatSect uint32 = 0xFFFFFFFD // Specifies a FAT sector in the FAT
  59 + endOfChain uint32 = 0xFFFFFFFE // End of linked chain of sectors
  60 + freeSect uint32 = 0xFFFFFFFF // Speficies unallocated sector in the FAT, Mini FAT or DIFAT
  61 + maxRegStreamID uint32 = 0xFFFFFFFA // maximum regular stream ID
  62 + noStream uint32 = 0xFFFFFFFF // empty pointer
  63 +)
  64 +
  65 +const lenHeader int = 8 + 16 + 10 + 6 + 12 + 8 + 16 + 109*4
  66 +
  67 +type headerFields struct {
  68 + signature uint64
  69 + _ [16]byte //CLSID - ignore, must be null
  70 + minorVersion uint16 //Version number for non-breaking changes. This field SHOULD be set to 0x003E if the major version field is either 0x0003 or 0x0004.
  71 + majorVersion uint16 //Version number for breaking changes. This field MUST be set to either 0x0003 (version 3) or 0x0004 (version 4).
  72 + _ [2]byte //byte order - ignore, must be little endian
  73 + sectorSize uint16 //This field MUST be set to 0x0009, or 0x000c, depending on the Major Version field. This field specifies the sector size of the compound file as a power of 2. If Major Version is 3, then the Sector Shift MUST be 0x0009, specifying a sector size of 512 bytes. If Major Version is 4, then the Sector Shift MUST be 0x000C, specifying a sector size of 4096 bytes.
  74 + _ [2]byte // ministream sector size - ignore, must be 64 bytes
  75 + _ [6]byte // reserved - ignore, not used
  76 + numDirectorySectors uint32 //This integer field contains the count of the number of directory sectors in the compound file. If Major Version is 3, then the Number of Directory Sectors MUST be zero. This field is not supported for version 3 compound files.
  77 + numFatSectors uint32 //This integer field contains the count of the number of FAT sectors in the compound file.
  78 + directorySectorLoc uint32 //This integer field contains the starting sector number for the directory stream.
  79 + _ [4]byte // transaction - ignore, not used
  80 + _ [4]byte // mini stream size cutooff - ignore, must be 4096 bytes
  81 + miniFatSectorLoc uint32 //This integer field contains the starting sector number for the mini FAT.
  82 + numMiniFatSectors uint32 //This integer field contains the count of the number of mini FAT sectors in the compound file.
  83 + difatSectorLoc uint32 //This integer field contains the starting sector number for the DIFAT.
  84 + numDifatSectors uint32 //This integer field contains the count of the number of DIFAT sectors in the compound file.
  85 + initialDifats [109]uint32 //The first 109 difat sectors are included in the header
  86 +}
  87 +
  88 +func makeHeader(b []byte) *headerFields {
  89 + h := &headerFields{}
  90 + h.signature = binary.LittleEndian.Uint64(b[:8])
  91 + h.minorVersion = binary.LittleEndian.Uint16(b[24:26])
  92 + h.majorVersion = binary.LittleEndian.Uint16(b[26:28])
  93 + h.sectorSize = binary.LittleEndian.Uint16(b[30:32])
  94 + h.numDirectorySectors = binary.LittleEndian.Uint32(b[40:44])
  95 + h.numFatSectors = binary.LittleEndian.Uint32(b[44:48])
  96 + h.directorySectorLoc = binary.LittleEndian.Uint32(b[48:52])
  97 + h.miniFatSectorLoc = binary.LittleEndian.Uint32(b[60:64])
  98 + h.numMiniFatSectors = binary.LittleEndian.Uint32(b[64:68])
  99 + h.difatSectorLoc = binary.LittleEndian.Uint32(b[68:72])
  100 + h.numDifatSectors = binary.LittleEndian.Uint32(b[72:76])
  101 + var idx int
  102 + for i := 76; i < 512; i = i + 4 {
  103 + h.initialDifats[idx] = binary.LittleEndian.Uint32(b[i : i+4])
  104 + idx++
  105 + }
  106 + return h
  107 +}
  108 +
  109 +type header struct {
  110 + *headerFields
  111 + difats []uint32
  112 + miniFatLocs []uint32
  113 + miniStreamLocs []uint32 // chain of sectors containing the ministream
  114 +}
  115 +
  116 +func (r *Reader) setHeader() error {
  117 + buf, err := r.readAt(0, lenHeader)
  118 + if err != nil {
  119 + return err
  120 + }
  121 + r.header = &header{headerFields: makeHeader(buf)}
  122 + // sanity check - check signature
  123 + if r.header.signature != signature {
  124 + return Error{ErrFormat, "bad signature", int64(r.header.signature)}
  125 + }
  126 + // check for legal sector size
  127 + if r.header.sectorSize == 0x0009 || r.header.sectorSize == 0x000c {
  128 + r.sectorSize = uint32(1 << r.header.sectorSize)
  129 + } else {
  130 + return Error{ErrFormat, "illegal sector size", int64(r.header.sectorSize)}
  131 + }
  132 + // check for DIFAT overflow
  133 + if r.header.numDifatSectors > 0 {
  134 + sz := (r.sectorSize / 4) - 1
  135 + if int(r.header.numDifatSectors*sz+109) < 0 {
  136 + return Error{ErrFormat, "DIFAT int overflow", int64(r.header.numDifatSectors)}
  137 + }
  138 + if r.header.numDifatSectors*sz+109 > r.header.numFatSectors+sz {
  139 + return Error{ErrFormat, "num DIFATs exceeds FAT sectors", int64(r.header.numDifatSectors)}
  140 + }
  141 + }
  142 + // check for mini FAT overflow
  143 + if r.header.numMiniFatSectors > 0 {
  144 + if int(r.sectorSize/4*r.header.numMiniFatSectors) < 0 {
  145 + return Error{ErrFormat, "mini FAT int overflow", int64(r.header.numMiniFatSectors)}
  146 + }
  147 + if r.header.numMiniFatSectors > r.header.numFatSectors*(r.sectorSize/miniStreamSectorSize) {
  148 + return Error{ErrFormat, "num mini FATs exceeds FAT sectors", int64(r.header.numFatSectors)}
  149 + }
  150 + }
  151 + return nil
  152 +}
  153 +
  154 +func (r *Reader) setDifats() error {
  155 + r.header.difats = r.header.initialDifats[:]
  156 + // return early if no extra DIFAT sectors
  157 + if r.header.numDifatSectors == 0 {
  158 + return nil
  159 + }
  160 + sz := (r.sectorSize / 4) - 1
  161 + n := make([]uint32, 109, r.header.numDifatSectors*sz+109)
  162 + copy(n, r.header.difats)
  163 + r.header.difats = n
  164 + off := r.header.difatSectorLoc
  165 + for i := 0; i < int(r.header.numDifatSectors); i++ {
  166 + buf, err := r.readAt(fileOffset(r.sectorSize, off), int(r.sectorSize))
  167 + if err != nil {
  168 + return Error{ErrFormat, "error setting DIFAT(" + err.Error() + ")", int64(off)}
  169 + }
  170 + for j := 0; j < int(sz); j++ {
  171 + r.header.difats = append(r.header.difats, binary.LittleEndian.Uint32(buf[j*4:j*4+4]))
  172 + }
  173 + off = binary.LittleEndian.Uint32(buf[len(buf)-4:])
  174 + }
  175 + return nil
  176 +}
  177 +
  178 +// set the ministream FAT and sector slices in the header
  179 +func (r *Reader) setMiniStream() error {
  180 + // do nothing if there is no ministream
  181 + if r.direntries[0].startingSectorLoc == endOfChain || r.header.miniFatSectorLoc == endOfChain || r.header.numMiniFatSectors == 0 {
  182 + return nil
  183 + }
  184 + // build a slice of minifat sectors (akin to the DIFAT slice)
  185 + c := int(r.header.numMiniFatSectors)
  186 + r.header.miniFatLocs = make([]uint32, c)
  187 + r.header.miniFatLocs[0] = r.header.miniFatSectorLoc
  188 + for i := 1; i < c; i++ {
  189 + loc, err := r.findNext(r.header.miniFatLocs[i-1], false)
  190 + if err != nil {
  191 + return Error{ErrFormat, "setting mini stream (" + err.Error() + ")", int64(r.header.miniFatLocs[i-1])}
  192 + }
  193 + r.header.miniFatLocs[i] = loc
  194 + }
  195 + // build a slice of ministream sectors
  196 + c = int(r.sectorSize / 4 * r.header.numMiniFatSectors)
  197 + r.header.miniStreamLocs = make([]uint32, 0, c)
  198 + sn := r.direntries[0].startingSectorLoc
  199 + var err error
  200 + for sn != endOfChain {
  201 + r.header.miniStreamLocs = append(r.header.miniStreamLocs, sn)
  202 + sn, err = r.findNext(sn, false)
  203 + if err != nil {
  204 + return Error{ErrFormat, "setting mini stream (" + err.Error() + ")", int64(sn)}
  205 + }
  206 + }
  207 + return nil
  208 +}
  209 +
  210 +func (r *Reader) readAt(offset int64, length int) ([]byte, error) {
  211 + if r.slicer {
  212 + b, err := r.ra.(slicer).Slice(offset, length)
  213 + if err != nil {
  214 + return nil, Error{ErrRead, "slicer read error (" + err.Error() + ")", offset}
  215 + }
  216 + return b, nil
  217 + }
  218 + if length > len(r.buf) {
  219 + return nil, Error{ErrRead, "read length greater than read buffer", int64(length)}
  220 + }
  221 + if _, err := r.ra.ReadAt(r.buf[:length], offset); err != nil {
  222 + return nil, Error{ErrRead, err.Error(), offset}
  223 + }
  224 + return r.buf[:length], nil
  225 +}
  226 +
  227 +func (r *Reader) getOffset(sn uint32, mini bool) (int64, error) {
  228 + if mini {
  229 + num := r.sectorSize / 64
  230 + sec := int(sn / num)
  231 + if sec >= len(r.header.miniStreamLocs) {
  232 + return 0, Error{ErrRead, "minisector number is outside minisector range", int64(sec)}
  233 + }
  234 + dif := sn % num
  235 + return int64((r.header.miniStreamLocs[sec]+1)*r.sectorSize + dif*64), nil
  236 + }
  237 + return fileOffset(r.sectorSize, sn), nil
  238 +}
  239 +
  240 +// check the FAT sector for the next sector in a chain
  241 +func (r *Reader) findNext(sn uint32, mini bool) (uint32, error) {
  242 + entries := r.sectorSize / 4
  243 + index := int(sn / entries) // find position in DIFAT or minifat array
  244 + var sect uint32
  245 + if mini {
  246 + if index < 0 || index >= len(r.header.miniFatLocs) {
  247 + return 0, Error{ErrRead, "minisector index is outside miniFAT range", int64(index)}
  248 + }
  249 + sect = r.header.miniFatLocs[index]
  250 + } else {
  251 + if index < 0 || index >= len(r.header.difats) {
  252 + return 0, Error{ErrRead, "FAT index is outside DIFAT range", int64(index)}
  253 + }
  254 + sect = r.header.difats[index]
  255 + }
  256 + fatIndex := sn % entries // find position within FAT or MiniFAT sector
  257 + offset := fileOffset(r.sectorSize, sect) + int64(fatIndex*4)
  258 + buf, err := r.readAt(offset, 4)
  259 + if err != nil {
  260 + return 0, Error{ErrRead, "bad read finding next sector (" + err.Error() + ")", offset}
  261 + }
  262 + return binary.LittleEndian.Uint32(buf), nil
  263 +}
  264 +
  265 +// Reader provides sequential access to the contents of a MS compound file (MSCFB)
  266 +type Reader struct {
  267 + slicer bool
  268 + sectorSize uint32
  269 + buf []byte
  270 + header *header
  271 + File []*File // File is an ordered slice of final directory entries.
  272 + direntries []*File // unordered raw directory entries
  273 + entry int
  274 +
  275 + ra io.ReaderAt
  276 + wa io.WriterAt
  277 +}
  278 +
  279 +// New returns a MSCFB reader
  280 +func New(ra io.ReaderAt) (*Reader, error) {
  281 + r := &Reader{ra: ra}
  282 + if _, ok := ra.(slicer); ok {
  283 + r.slicer = true
  284 + } else {
  285 + r.buf = make([]byte, lenHeader)
  286 + }
  287 + if err := r.setHeader(); err != nil {
  288 + return nil, err
  289 + }
  290 + // resize the buffer to 4096 if sector size isn't 512
  291 + if !r.slicer && int(r.sectorSize) > len(r.buf) {
  292 + r.buf = make([]byte, r.sectorSize)
  293 + }
  294 + if err := r.setDifats(); err != nil {
  295 + return nil, err
  296 + }
  297 + if err := r.setDirEntries(); err != nil {
  298 + return nil, err
  299 + }
  300 + if err := r.setMiniStream(); err != nil {
  301 + return nil, err
  302 + }
  303 + if err := r.traverse(); err != nil {
  304 + return nil, err
  305 + }
  306 + return r, nil
  307 +}
  308 +
  309 +// ID returns the CLSID (class ID) field from the root directory entry
  310 +func (r *Reader) ID() string {
  311 + return r.File[0].ID()
  312 +}
  313 +
  314 +// Created returns the created field from the root directory entry
  315 +func (r *Reader) Created() time.Time {
  316 + return r.File[0].Created()
  317 +}
  318 +
  319 +// Modified returns the last modified field from the root directory entry
  320 +func (r *Reader) Modified() time.Time {
  321 + return r.File[0].Modified()
  322 +}
  323 +
  324 +// Next iterates to the next directory entry.
  325 +// This isn't necessarily an adjacent *File within the File slice, but is based on the Left Sibling, Right Sibling and Child information in directory entries.
  326 +func (r *Reader) Next() (*File, error) {
  327 + r.entry++
  328 + if r.entry >= len(r.File) {
  329 + return nil, io.EOF
  330 + }
  331 + return r.File[r.entry], nil
  332 +}
  333 +
  334 +// Read the current directory entry
  335 +func (r *Reader) Read(b []byte) (n int, err error) {
  336 + if r.entry >= len(r.File) {
  337 + return 0, io.EOF
  338 + }
  339 + return r.File[r.entry].Read(b)
  340 +}
  341 +
  342 +// Debug provides granular information from an mscfb file to assist with debugging
  343 +func (r *Reader) Debug() map[string][]uint32 {
  344 + ret := map[string][]uint32{
  345 + "sector size": []uint32{r.sectorSize},
  346 + "mini fat locs": r.header.miniFatLocs,
  347 + "mini stream locs": r.header.miniStreamLocs,
  348 + "directory sector": []uint32{r.header.directorySectorLoc},
  349 + "mini stream start/size": []uint32{r.File[0].startingSectorLoc, binary.LittleEndian.Uint32(r.File[0].streamSize[:])},
  350 + }
  351 + for f, err := r.Next(); err == nil; f, err = r.Next() {
  352 + ret[f.Name+" start/size"] = []uint32{f.startingSectorLoc, binary.LittleEndian.Uint32(f.streamSize[:])}
  353 + }
  354 + return ret
  355 +}
  356 +
  357 +const (
  358 + // ErrFormat reports issues with the MSCFB's header structures
  359 + ErrFormat = iota
  360 + // ErrRead reports issues attempting to read MSCFB streams
  361 + ErrRead
  362 + // ErrSeek reports seek issues
  363 + ErrSeek
  364 + // ErrWrite reports write issues
  365 + ErrWrite
  366 + // ErrTraverse reports issues attempting to traverse the child-parent-sibling relations
  367 + // between MSCFB storage objects
  368 + ErrTraverse
  369 +)
  370 +
  371 +type Error struct {
  372 + typ int
  373 + msg string
  374 + val int64
  375 +}
  376 +
  377 +func (e Error) Error() string {
  378 + return "mscfb: " + e.msg + "; " + strconv.FormatInt(e.val, 10)
  379 +}
  380 +
  381 +// Typ gives the type of MSCFB error
  382 +func (e Error) Typ() int {
  383 + return e.typ
  384 +}
  385 +
  386 +// Slicer interface avoids a copy by obtaining a byte slice directly from the underlying reader
  387 +type slicer interface {
  388 + Slice(offset int64, length int) ([]byte, error)
  389 +}
1 -// Copyright 2014 Richard Lehane. All rights reserved.  
2 -//  
3 -// Licensed under the Apache License, Version 2.0 (the "License");  
4 -// you may not use this file except in compliance with the License.  
5 -// You may obtain a copy of the License at  
6 -//  
7 -// http://www.apache.org/licenses/LICENSE-2.0  
8 -//  
9 -// Unless required by applicable law or agreed to in writing, software  
10 -// distributed under the License is distributed on an "AS IS" BASIS,  
11 -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  
12 -// See the License for the specific language governing permissions and  
13 -// limitations under the License.  
14 -  
15 -package types  
16 -  
17 -import (  
18 - "encoding/binary"  
19 - "strconv"  
20 -)  
21 -  
22 -//The CURRENCY type specifies currency information. It is represented as an 8-byte integer, scaled by 10,000, to give a fixed-point number with 15 digits to the left of the decimal point, and four digits to the right. This representation provides a range of 922337203685477.5807 to –922337203685477.5808. For example, $5.25 is stored as the value 52500.  
23 -  
24 -type Currency int64  
25 -  
26 -func (c Currency) String() string {  
27 - return "$" + strconv.FormatFloat(float64(c)/10000, 'f', -1, 64)  
28 -}  
29 -  
30 -func (c Currency) Type() string {  
31 - return "Currency"  
32 -}  
33 -  
34 -func (c Currency) Length() int {  
35 - return 8  
36 -}  
37 -  
38 -func MakeCurrency(b []byte) (Type, error) {  
39 - if len(b) < 8 {  
40 - return Currency(0), ErrType  
41 - }  
42 - return Currency(binary.LittleEndian.Uint64(b[:8])), nil  
43 -} 1 +// Copyright 2014 Richard Lehane. All rights reserved.
  2 +//
  3 +// Licensed under the Apache License, Version 2.0 (the "License");
  4 +// you may not use this file except in compliance with the License.
  5 +// You may obtain a copy of the License at
  6 +//
  7 +// http://www.apache.org/licenses/LICENSE-2.0
  8 +//
  9 +// Unless required by applicable law or agreed to in writing, software
  10 +// distributed under the License is distributed on an "AS IS" BASIS,
  11 +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  12 +// See the License for the specific language governing permissions and
  13 +// limitations under the License.
  14 +
  15 +package types
  16 +
  17 +import (
  18 + "encoding/binary"
  19 + "strconv"
  20 +)
  21 +
  22 +//The CURRENCY type specifies currency information. It is represented as an 8-byte integer, scaled by 10,000, to give a fixed-point number with 15 digits to the left of the decimal point, and four digits to the right. This representation provides a range of 922337203685477.5807 to –922337203685477.5808. For example, $5.25 is stored as the value 52500.
  23 +
  24 +type Currency int64
  25 +
  26 +func (c Currency) String() string {
  27 + return "$" + strconv.FormatFloat(float64(c)/10000, 'f', -1, 64)
  28 +}
  29 +
  30 +func (c Currency) Type() string {
  31 + return "Currency"
  32 +}
  33 +
  34 +func (c Currency) Length() int {
  35 + return 8
  36 +}
  37 +
  38 +func MakeCurrency(b []byte) (Type, error) {
  39 + if len(b) < 8 {
  40 + return Currency(0), ErrType
  41 + }
  42 + return Currency(binary.LittleEndian.Uint64(b[:8])), nil
  43 +}
1 -// Copyright 2014 Richard Lehane. All rights reserved.  
2 -//  
3 -// Licensed under the Apache License, Version 2.0 (the "License");  
4 -// you may not use this file except in compliance with the License.  
5 -// You may obtain a copy of the License at  
6 -//  
7 -// http://www.apache.org/licenses/LICENSE-2.0  
8 -//  
9 -// Unless required by applicable law or agreed to in writing, software  
10 -// distributed under the License is distributed on an "AS IS" BASIS,  
11 -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  
12 -// See the License for the specific language governing permissions and  
13 -// limitations under the License.  
14 -  
15 -package types  
16 -  
17 -import (  
18 - "encoding/binary"  
19 - "time"  
20 -)  
21 -  
22 -// http://msdn.microsoft.com/en-us/library/cc237601.aspx  
23 -type Date float64  
24 -  
25 -func (d Date) Time() time.Time {  
26 - start := time.Date(1899, 12, 30, 0, 0, 0, 0, time.UTC)  
27 - day := float64(time.Hour * 24)  
28 - dur := time.Duration(day * float64(d))  
29 - return start.Add(dur)  
30 -}  
31 -  
32 -func (d Date) String() string {  
33 - return d.Time().String()  
34 -}  
35 -  
36 -func (d Date) Type() string {  
37 - return "Date"  
38 -}  
39 -  
40 -func (d Date) Length() int {  
41 - return 8  
42 -}  
43 -  
44 -func MakeDate(b []byte) (Type, error) {  
45 - if len(b) < 8 {  
46 - return Date(0), ErrType  
47 - }  
48 - return Date(binary.LittleEndian.Uint64(b[:8])), nil  
49 -} 1 +// Copyright 2014 Richard Lehane. All rights reserved.
  2 +//
  3 +// Licensed under the Apache License, Version 2.0 (the "License");
  4 +// you may not use this file except in compliance with the License.
  5 +// You may obtain a copy of the License at
  6 +//
  7 +// http://www.apache.org/licenses/LICENSE-2.0
  8 +//
  9 +// Unless required by applicable law or agreed to in writing, software
  10 +// distributed under the License is distributed on an "AS IS" BASIS,
  11 +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  12 +// See the License for the specific language governing permissions and
  13 +// limitations under the License.
  14 +
  15 +package types
  16 +
  17 +import (
  18 + "encoding/binary"
  19 + "time"
  20 +)
  21 +
  22 +// http://msdn.microsoft.com/en-us/library/cc237601.aspx
  23 +type Date float64
  24 +
  25 +func (d Date) Time() time.Time {
  26 + start := time.Date(1899, 12, 30, 0, 0, 0, 0, time.UTC)
  27 + day := float64(time.Hour * 24)
  28 + dur := time.Duration(day * float64(d))
  29 + return start.Add(dur)
  30 +}
  31 +
  32 +func (d Date) String() string {
  33 + return d.Time().String()
  34 +}
  35 +
  36 +func (d Date) Type() string {
  37 + return "Date"
  38 +}
  39 +
  40 +func (d Date) Length() int {
  41 + return 8
  42 +}
  43 +
  44 +func MakeDate(b []byte) (Type, error) {
  45 + if len(b) < 8 {
  46 + return Date(0), ErrType
  47 + }
  48 + return Date(binary.LittleEndian.Uint64(b[:8])), nil
  49 +}
1 -// Copyright 2014 Richard Lehane. All rights reserved.  
2 -//  
3 -// Licensed under the Apache License, Version 2.0 (the "License");  
4 -// you may not use this file except in compliance with the License.  
5 -// You may obtain a copy of the License at  
6 -//  
7 -// http://www.apache.org/licenses/LICENSE-2.0  
8 -//  
9 -// Unless required by applicable law or agreed to in writing, software  
10 -// distributed under the License is distributed on an "AS IS" BASIS,  
11 -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  
12 -// See the License for the specific language governing permissions and  
13 -// limitations under the License.  
14 -  
15 -package types  
16 -  
17 -import (  
18 - "encoding/binary"  
19 - "math"  
20 - "math/big"  
21 -)  
22 -  
23 -// http://msdn.microsoft.com/en-us/library/cc237603.aspx  
24 -type Decimal struct {  
25 - res [2]byte  
26 - scale byte  
27 - sign byte  
28 - high32 uint32  
29 - low64 uint64  
30 -}  
31 -  
32 -func (d Decimal) Type() string {  
33 - return "Decimal"  
34 -}  
35 -  
36 -func (d Decimal) Length() int {  
37 - return 16  
38 -}  
39 -  
40 -func (d Decimal) String() string {  
41 - h, l, b := new(big.Int), new(big.Int), new(big.Int)  
42 - l.SetUint64(d.low64)  
43 - h.Lsh(big.NewInt(int64(d.high32)), 64)  
44 - b.Add(h, l)  
45 - q, f, r := new(big.Rat), new(big.Rat), new(big.Rat)  
46 - q.SetFloat64(math.Pow10(int(d.scale)))  
47 - r.Quo(f.SetInt(b), q)  
48 - if d.sign == 0x80 {  
49 - r.Neg(r)  
50 - }  
51 - return r.FloatString(20)  
52 -}  
53 -  
54 -func MakeDecimal(b []byte) (Type, error) {  
55 - if len(b) < 16 {  
56 - return Decimal{}, ErrType  
57 - }  
58 - return Decimal{  
59 - res: [2]byte{b[0], b[1]},  
60 - scale: b[2],  
61 - sign: b[3],  
62 - high32: binary.LittleEndian.Uint32(b[4:8]),  
63 - low64: binary.LittleEndian.Uint64(b[8:16]),  
64 - }, nil  
65 -} 1 +// Copyright 2014 Richard Lehane. All rights reserved.
  2 +//
  3 +// Licensed under the Apache License, Version 2.0 (the "License");
  4 +// you may not use this file except in compliance with the License.
  5 +// You may obtain a copy of the License at
  6 +//
  7 +// http://www.apache.org/licenses/LICENSE-2.0
  8 +//
  9 +// Unless required by applicable law or agreed to in writing, software
  10 +// distributed under the License is distributed on an "AS IS" BASIS,
  11 +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  12 +// See the License for the specific language governing permissions and
  13 +// limitations under the License.
  14 +
  15 +package types
  16 +
  17 +import (
  18 + "encoding/binary"
  19 + "math"
  20 + "math/big"
  21 +)
  22 +
  23 +// http://msdn.microsoft.com/en-us/library/cc237603.aspx
  24 +type Decimal struct {
  25 + res [2]byte
  26 + scale byte
  27 + sign byte
  28 + high32 uint32
  29 + low64 uint64
  30 +}
  31 +
  32 +func (d Decimal) Type() string {
  33 + return "Decimal"
  34 +}
  35 +
  36 +func (d Decimal) Length() int {
  37 + return 16
  38 +}
  39 +
  40 +func (d Decimal) String() string {
  41 + h, l, b := new(big.Int), new(big.Int), new(big.Int)
  42 + l.SetUint64(d.low64)
  43 + h.Lsh(big.NewInt(int64(d.high32)), 64)
  44 + b.Add(h, l)
  45 + q, f, r := new(big.Rat), new(big.Rat), new(big.Rat)
  46 + q.SetFloat64(math.Pow10(int(d.scale)))
  47 + r.Quo(f.SetInt(b), q)
  48 + if d.sign == 0x80 {
  49 + r.Neg(r)
  50 + }
  51 + return r.FloatString(20)
  52 +}
  53 +
  54 +func MakeDecimal(b []byte) (Type, error) {
  55 + if len(b) < 16 {
  56 + return Decimal{}, ErrType
  57 + }
  58 + return Decimal{
  59 + res: [2]byte{b[0], b[1]},
  60 + scale: b[2],
  61 + sign: b[3],
  62 + high32: binary.LittleEndian.Uint32(b[4:8]),
  63 + low64: binary.LittleEndian.Uint64(b[8:16]),
  64 + }, nil
  65 +}
1 -// Copyright 2014 Richard Lehane. All rights reserved.  
2 -//  
3 -// Licensed under the Apache License, Version 2.0 (the "License");  
4 -// you may not use this file except in compliance with the License.  
5 -// You may obtain a copy of the License at  
6 -//  
7 -// http://www.apache.org/licenses/LICENSE-2.0  
8 -//  
9 -// Unless required by applicable law or agreed to in writing, software  
10 -// distributed under the License is distributed on an "AS IS" BASIS,  
11 -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  
12 -// See the License for the specific language governing permissions and  
13 -// limitations under the License.  
14 -  
15 -package types  
16 -  
17 -import (  
18 - "encoding/binary"  
19 - "time"  
20 -)  
21 -  
22 -// Win FILETIME type  
23 -// http://msdn.microsoft.com/en-us/library/cc230324.aspx  
24 -type FileTime struct {  
25 - Low uint32 // Windows FILETIME structure  
26 - High uint32 // Windows FILETIME structure  
27 -}  
28 -  
29 -const (  
30 - tick uint64 = 10000000  
31 - gregToUnix uint64 = 11644473600  
32 -)  
33 -  
34 -func winToUnix(low, high uint32) int64 {  
35 - gregTime := ((uint64(high) << 32) + uint64(low)) / tick  
36 - if gregTime < gregToUnix {  
37 - return 0  
38 - }  
39 - return int64(gregTime - gregToUnix)  
40 -}  
41 -  
42 -func (f FileTime) Time() time.Time {  
43 - return time.Unix(winToUnix(f.Low, f.High), 0)  
44 -}  
45 -  
46 -func (f FileTime) String() string {  
47 - return f.Time().String()  
48 -}  
49 -  
50 -func (f FileTime) Type() string {  
51 - return "FileTime"  
52 -}  
53 -  
54 -func (f FileTime) Length() int {  
55 - return 8  
56 -}  
57 -  
58 -func MakeFileTime(b []byte) (Type, error) {  
59 - if len(b) < 8 {  
60 - return FileTime{}, ErrType  
61 - }  
62 - return MustFileTime(b), nil  
63 -}  
64 -  
65 -func MustFileTime(b []byte) FileTime {  
66 - return FileTime{  
67 - Low: binary.LittleEndian.Uint32(b[:4]),  
68 - High: binary.LittleEndian.Uint32(b[4:8]),  
69 - }  
70 -} 1 +// Copyright 2014 Richard Lehane. All rights reserved.
  2 +//
  3 +// Licensed under the Apache License, Version 2.0 (the "License");
  4 +// you may not use this file except in compliance with the License.
  5 +// You may obtain a copy of the License at
  6 +//
  7 +// http://www.apache.org/licenses/LICENSE-2.0
  8 +//
  9 +// Unless required by applicable law or agreed to in writing, software
  10 +// distributed under the License is distributed on an "AS IS" BASIS,
  11 +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  12 +// See the License for the specific language governing permissions and
  13 +// limitations under the License.
  14 +
  15 +package types
  16 +
  17 +import (
  18 + "encoding/binary"
  19 + "time"
  20 +)
  21 +
  22 +// Win FILETIME type
  23 +// http://msdn.microsoft.com/en-us/library/cc230324.aspx
  24 +type FileTime struct {
  25 + Low uint32 // Windows FILETIME structure
  26 + High uint32 // Windows FILETIME structure
  27 +}
  28 +
  29 +const (
  30 + tick uint64 = 10000000
  31 + gregToUnix uint64 = 11644473600
  32 +)
  33 +
  34 +func winToUnix(low, high uint32) int64 {
  35 + gregTime := ((uint64(high) << 32) + uint64(low)) / tick
  36 + if gregTime < gregToUnix {
  37 + return 0
  38 + }
  39 + return int64(gregTime - gregToUnix)
  40 +}
  41 +
  42 +func (f FileTime) Time() time.Time {
  43 + return time.Unix(winToUnix(f.Low, f.High), 0)
  44 +}
  45 +
  46 +func (f FileTime) String() string {
  47 + return f.Time().String()
  48 +}
  49 +
  50 +func (f FileTime) Type() string {
  51 + return "FileTime"
  52 +}
  53 +
  54 +func (f FileTime) Length() int {
  55 + return 8
  56 +}
  57 +
  58 +func MakeFileTime(b []byte) (Type, error) {
  59 + if len(b) < 8 {
  60 + return FileTime{}, ErrType
  61 + }
  62 + return MustFileTime(b), nil
  63 +}
  64 +
  65 +func MustFileTime(b []byte) FileTime {
  66 + return FileTime{
  67 + Low: binary.LittleEndian.Uint32(b[:4]),
  68 + High: binary.LittleEndian.Uint32(b[4:8]),
  69 + }
  70 +}
1 -// Copyright 2014 Richard Lehane. All rights reserved.  
2 -//  
3 -// Licensed under the Apache License, Version 2.0 (the "License");  
4 -// you may not use this file except in compliance with the License.  
5 -// You may obtain a copy of the License at  
6 -//  
7 -// http://www.apache.org/licenses/LICENSE-2.0  
8 -//  
9 -// Unless required by applicable law or agreed to in writing, software  
10 -// distributed under the License is distributed on an "AS IS" BASIS,  
11 -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  
12 -// See the License for the specific language governing permissions and  
13 -// limitations under the License.  
14 -  
15 -package types  
16 -  
17 -import (  
18 - "encoding/binary"  
19 - "encoding/hex"  
20 - "errors"  
21 - "strings"  
22 -)  
23 -  
24 -// Win GUID and UUID type  
25 -// http://msdn.microsoft.com/en-us/library/cc230326.aspx  
26 -type Guid struct {  
27 - DataA uint32  
28 - DataB uint16  
29 - DataC uint16  
30 - DataD [8]byte  
31 -}  
32 -  
33 -func (g Guid) String() string {  
34 - buf := make([]byte, 8)  
35 - binary.BigEndian.PutUint32(buf[:4], g.DataA)  
36 - binary.BigEndian.PutUint16(buf[4:6], g.DataB)  
37 - binary.BigEndian.PutUint16(buf[6:], g.DataC)  
38 - return strings.ToUpper("{" +  
39 - hex.EncodeToString(buf[:4]) +  
40 - "-" +  
41 - hex.EncodeToString(buf[4:6]) +  
42 - "-" +  
43 - hex.EncodeToString(buf[6:]) +  
44 - "-" +  
45 - hex.EncodeToString(g.DataD[:2]) +  
46 - "-" +  
47 - hex.EncodeToString(g.DataD[2:]) +  
48 - "}")  
49 -}  
50 -  
51 -func (g Guid) Type() string {  
52 - return "Guid"  
53 -}  
54 -  
55 -func (g Guid) Length() int {  
56 - return 16  
57 -}  
58 -  
59 -func GuidFromString(str string) (Guid, error) {  
60 - gerr := "Invalid GUID: expecting in format {F29F85E0-4FF9-1068-AB91-08002B27B3D9}, got " + str  
61 - if len(str) != 38 {  
62 - return Guid{}, errors.New(gerr + "; bad length, should be 38 chars")  
63 - }  
64 - trimmed := strings.Trim(str, "{}")  
65 - parts := strings.Split(trimmed, "-")  
66 - if len(parts) != 5 {  
67 - return Guid{}, errors.New(gerr + "; expecting should five '-' separators")  
68 - }  
69 - buf, err := hex.DecodeString(strings.Join(parts, ""))  
70 - if err != nil {  
71 - return Guid{}, errors.New(gerr + "; error decoding hex: " + err.Error())  
72 - }  
73 - return makeGuid(buf, binary.BigEndian), nil  
74 -}  
75 -  
76 -func MakeGuid(b []byte) (Type, error) {  
77 - if len(b) < 16 {  
78 - return Guid{}, ErrType  
79 - }  
80 - return makeGuid(b, binary.LittleEndian), nil  
81 -}  
82 -  
83 -func makeGuid(b []byte, order binary.ByteOrder) Guid {  
84 - g := Guid{  
85 - DataA: order.Uint32(b[:4]),  
86 - DataB: order.Uint16(b[4:6]),  
87 - DataC: order.Uint16(b[6:8]),  
88 - DataD: [8]byte{},  
89 - }  
90 - copy(g.DataD[:], b[8:])  
91 - return g  
92 -}  
93 -  
94 -func MustGuidFromString(str string) Guid {  
95 - g, err := GuidFromString(str)  
96 - if err != nil {  
97 - panic(err)  
98 - }  
99 - return g  
100 -}  
101 -  
102 -func MustGuid(b []byte) Guid {  
103 - return makeGuid(b, binary.LittleEndian)  
104 -}  
105 -  
106 -func GuidFromName(n string) (Guid, error) {  
107 - n = strings.ToLower(n)  
108 - buf, err := charConvert([]byte(n))  
109 - if err != nil {  
110 - return Guid{}, err  
111 - }  
112 - return makeGuid(buf, binary.LittleEndian), nil  
113 -}  
114 -  
115 -func charConvert(in []byte) ([]byte, error) {  
116 - if len(in) != 26 {  
117 - return nil, errors.New("invalid GUID: expecting 26 characters")  
118 - }  
119 - out := make([]byte, 16)  
120 - var idx, shift uint  
121 - var b byte  
122 - for _, v := range in {  
123 - this, ok := characterMapping[v]  
124 - if !ok {  
125 - return nil, errors.New("invalid Guid: invalid character")  
126 - }  
127 - b = b | this<<shift  
128 - if shift >= 3 {  
129 - out[idx] = b  
130 - idx++  
131 - b = this >> (8 - shift) // write any remainder back to b, or 0 if shift is 3  
132 - }  
133 - shift = shift + 5  
134 - if shift > 7 {  
135 - shift = shift - 8  
136 - }  
137 - }  
138 - return out, nil  
139 -}  
140 -  
141 -const (  
142 - charA byte = iota  
143 - charB  
144 - charC  
145 - charD  
146 - charE  
147 - charF  
148 - charG  
149 - charH  
150 - charI  
151 - charJ  
152 - charK  
153 - charL  
154 - charM  
155 - charN  
156 - charO  
157 - charP  
158 - charQ  
159 - charR  
160 - charS  
161 - charT  
162 - charU  
163 - charV  
164 - charW  
165 - charX  
166 - charY  
167 - charZ  
168 - char0  
169 - char1  
170 - char2  
171 - char3  
172 - char4  
173 - char5  
174 -)  
175 -  
176 -var characterMapping = map[byte]byte{  
177 - 'a': charA,  
178 - 'b': charB,  
179 - 'c': charC,  
180 - 'd': charD,  
181 - 'e': charE,  
182 - 'f': charF,  
183 - 'g': charG,  
184 - 'h': charH,  
185 - 'i': charI,  
186 - 'j': charJ,  
187 - 'k': charK,  
188 - 'l': charL,  
189 - 'm': charM,  
190 - 'n': charN,  
191 - 'o': charO,  
192 - 'p': charP,  
193 - 'q': charQ,  
194 - 'r': charR,  
195 - 's': charS,  
196 - 't': charT,  
197 - 'u': charU,  
198 - 'v': charV,  
199 - 'w': charW,  
200 - 'x': charX,  
201 - 'y': charY,  
202 - 'z': charZ,  
203 - '0': char0,  
204 - '1': char1,  
205 - '2': char2,  
206 - '3': char3,  
207 - '4': char4,  
208 - '5': char5,  
209 -} 1 +// Copyright 2014 Richard Lehane. All rights reserved.
  2 +//
  3 +// Licensed under the Apache License, Version 2.0 (the "License");
  4 +// you may not use this file except in compliance with the License.
  5 +// You may obtain a copy of the License at
  6 +//
  7 +// http://www.apache.org/licenses/LICENSE-2.0
  8 +//
  9 +// Unless required by applicable law or agreed to in writing, software
  10 +// distributed under the License is distributed on an "AS IS" BASIS,
  11 +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  12 +// See the License for the specific language governing permissions and
  13 +// limitations under the License.
  14 +
  15 +package types
  16 +
  17 +import (
  18 + "encoding/binary"
  19 + "encoding/hex"
  20 + "errors"
  21 + "strings"
  22 +)
  23 +
  24 +// Win GUID and UUID type
  25 +// http://msdn.microsoft.com/en-us/library/cc230326.aspx
  26 +type Guid struct {
  27 + DataA uint32
  28 + DataB uint16
  29 + DataC uint16
  30 + DataD [8]byte
  31 +}
  32 +
  33 +func (g Guid) String() string {
  34 + buf := make([]byte, 8)
  35 + binary.BigEndian.PutUint32(buf[:4], g.DataA)
  36 + binary.BigEndian.PutUint16(buf[4:6], g.DataB)
  37 + binary.BigEndian.PutUint16(buf[6:], g.DataC)
  38 + return strings.ToUpper("{" +
  39 + hex.EncodeToString(buf[:4]) +
  40 + "-" +
  41 + hex.EncodeToString(buf[4:6]) +
  42 + "-" +
  43 + hex.EncodeToString(buf[6:]) +
  44 + "-" +
  45 + hex.EncodeToString(g.DataD[:2]) +
  46 + "-" +
  47 + hex.EncodeToString(g.DataD[2:]) +
  48 + "}")
  49 +}
  50 +
  51 +func (g Guid) Type() string {
  52 + return "Guid"
  53 +}
  54 +
  55 +func (g Guid) Length() int {
  56 + return 16
  57 +}
  58 +
  59 +func GuidFromString(str string) (Guid, error) {
  60 + gerr := "Invalid GUID: expecting in format {F29F85E0-4FF9-1068-AB91-08002B27B3D9}, got " + str
  61 + if len(str) != 38 {
  62 + return Guid{}, errors.New(gerr + "; bad length, should be 38 chars")
  63 + }
  64 + trimmed := strings.Trim(str, "{}")
  65 + parts := strings.Split(trimmed, "-")
  66 + if len(parts) != 5 {
  67 + return Guid{}, errors.New(gerr + "; expecting should five '-' separators")
  68 + }
  69 + buf, err := hex.DecodeString(strings.Join(parts, ""))
  70 + if err != nil {
  71 + return Guid{}, errors.New(gerr + "; error decoding hex: " + err.Error())
  72 + }
  73 + return makeGuid(buf, binary.BigEndian), nil
  74 +}
  75 +
  76 +func MakeGuid(b []byte) (Type, error) {
  77 + if len(b) < 16 {
  78 + return Guid{}, ErrType
  79 + }
  80 + return makeGuid(b, binary.LittleEndian), nil
  81 +}
  82 +
  83 +func makeGuid(b []byte, order binary.ByteOrder) Guid {
  84 + g := Guid{
  85 + DataA: order.Uint32(b[:4]),
  86 + DataB: order.Uint16(b[4:6]),
  87 + DataC: order.Uint16(b[6:8]),
  88 + DataD: [8]byte{},
  89 + }
  90 + copy(g.DataD[:], b[8:])
  91 + return g
  92 +}
  93 +
  94 +func MustGuidFromString(str string) Guid {
  95 + g, err := GuidFromString(str)
  96 + if err != nil {
  97 + panic(err)
  98 + }
  99 + return g
  100 +}
  101 +
  102 +func MustGuid(b []byte) Guid {
  103 + return makeGuid(b, binary.LittleEndian)
  104 +}
  105 +
  106 +func GuidFromName(n string) (Guid, error) {
  107 + n = strings.ToLower(n)
  108 + buf, err := charConvert([]byte(n))
  109 + if err != nil {
  110 + return Guid{}, err
  111 + }
  112 + return makeGuid(buf, binary.LittleEndian), nil
  113 +}
  114 +
  115 +func charConvert(in []byte) ([]byte, error) {
  116 + if len(in) != 26 {
  117 + return nil, errors.New("invalid GUID: expecting 26 characters")
  118 + }
  119 + out := make([]byte, 16)
  120 + var idx, shift uint
  121 + var b byte
  122 + for _, v := range in {
  123 + this, ok := characterMapping[v]
  124 + if !ok {
  125 + return nil, errors.New("invalid Guid: invalid character")
  126 + }
  127 + b = b | this<<shift
  128 + if shift >= 3 {
  129 + out[idx] = b
  130 + idx++
  131 + b = this >> (8 - shift) // write any remainder back to b, or 0 if shift is 3
  132 + }
  133 + shift = shift + 5
  134 + if shift > 7 {
  135 + shift = shift - 8
  136 + }
  137 + }
  138 + return out, nil
  139 +}
  140 +
  141 +const (
  142 + charA byte = iota
  143 + charB
  144 + charC
  145 + charD
  146 + charE
  147 + charF
  148 + charG
  149 + charH
  150 + charI
  151 + charJ
  152 + charK
  153 + charL
  154 + charM
  155 + charN
  156 + charO
  157 + charP
  158 + charQ
  159 + charR
  160 + charS
  161 + charT
  162 + charU
  163 + charV
  164 + charW
  165 + charX
  166 + charY
  167 + charZ
  168 + char0
  169 + char1
  170 + char2
  171 + char3
  172 + char4
  173 + char5
  174 +)
  175 +
  176 +var characterMapping = map[byte]byte{
  177 + 'a': charA,
  178 + 'b': charB,
  179 + 'c': charC,
  180 + 'd': charD,
  181 + 'e': charE,
  182 + 'f': charF,
  183 + 'g': charG,
  184 + 'h': charH,
  185 + 'i': charI,
  186 + 'j': charJ,
  187 + 'k': charK,
  188 + 'l': charL,
  189 + 'm': charM,
  190 + 'n': charN,
  191 + 'o': charO,
  192 + 'p': charP,
  193 + 'q': charQ,
  194 + 'r': charR,
  195 + 's': charS,
  196 + 't': charT,
  197 + 'u': charU,
  198 + 'v': charV,
  199 + 'w': charW,
  200 + 'x': charX,
  201 + 'y': charY,
  202 + 'z': charZ,
  203 + '0': char0,
  204 + '1': char1,
  205 + '2': char2,
  206 + '3': char3,
  207 + '4': char4,
  208 + '5': char5,
  209 +}
1 -// Copyright 2014 Richard Lehane. All rights reserved.  
2 -//  
3 -// Licensed under the Apache License, Version 2.0 (the "License");  
4 -// you may not use this file except in compliance with the License.  
5 -// You may obtain a copy of the License at  
6 -//  
7 -// http://www.apache.org/licenses/LICENSE-2.0  
8 -//  
9 -// Unless required by applicable law or agreed to in writing, software  
10 -// distributed under the License is distributed on an "AS IS" BASIS,  
11 -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  
12 -// See the License for the specific language governing permissions and  
13 -// limitations under the License.  
14 -  
15 -package types  
16 -  
17 -import (  
18 - "encoding/binary"  
19 - "strings"  
20 - "unicode/utf16"  
21 -)  
22 -  
23 -func nullTerminated(s string) string {  
24 - return s[:strings.Index(s, "\x00")]  
25 -}  
26 -  
27 -type UnicodeString []uint16  
28 -  
29 -func (s UnicodeString) Type() string {  
30 - return "UnicodeString"  
31 -}  
32 -  
33 -func (s UnicodeString) Length() int {  
34 - return 4 + len(s)*2  
35 -}  
36 -  
37 -func (s UnicodeString) String() string {  
38 - if len(s) == 0 {  
39 - return ""  
40 - }  
41 - return nullTerminated(string(utf16.Decode(s)))  
42 -}  
43 -  
44 -func MakeUnicode(b []byte) (Type, error) {  
45 - if len(b) < 4 {  
46 - return UnicodeString{}, ErrType  
47 - }  
48 - l := int(binary.LittleEndian.Uint32(b[:4]))  
49 - if l == 0 {  
50 - return UnicodeString{}, nil  
51 - }  
52 - if len(b) < l*2+4 {  
53 - return UnicodeString{}, ErrType  
54 - }  
55 - s := make(UnicodeString, l)  
56 - for i := range s {  
57 - start := i*2 + 4  
58 - s[i] = binary.LittleEndian.Uint16(b[start : start+2])  
59 - }  
60 - return s, nil  
61 -}  
62 -  
63 -type CodeString struct {  
64 - id CodePageID  
65 - Chars []byte  
66 -}  
67 -  
68 -func (s *CodeString) SetId(i CodePageID) {  
69 - s.id = i  
70 -}  
71 -  
72 -func (s *CodeString) Encoding() string {  
73 - return CodePageIDs[s.id]  
74 -}  
75 -  
76 -func (s *CodeString) Type() string {  
77 - return "CodeString"  
78 -}  
79 -  
80 -func (s *CodeString) Length() int {  
81 - return 4 + len(s.Chars)  
82 -}  
83 -  
84 -func (s *CodeString) String() string {  
85 - if len(s.Chars) == 0 {  
86 - return ""  
87 - }  
88 - if s.id == 1200 {  
89 - chars := make([]uint16, len(s.Chars)/2)  
90 - for i := range chars {  
91 - chars[i] = binary.LittleEndian.Uint16(s.Chars[i*2 : i*2+2])  
92 - }  
93 - return nullTerminated(string(utf16.Decode(chars)))  
94 - }  
95 - return nullTerminated(string(s.Chars))  
96 -}  
97 -  
98 -func MakeCodeString(b []byte) (Type, error) {  
99 - if len(b) < 4 {  
100 - return &CodeString{}, ErrType  
101 - }  
102 - s := &CodeString{}  
103 - l := int(binary.LittleEndian.Uint32(b[:4]))  
104 - if l == 0 {  
105 - return s, nil  
106 - }  
107 - if len(b) < l+4 {  
108 - return s, ErrType  
109 - }  
110 - s.Chars = make([]byte, l)  
111 - copy(s.Chars, b[4:l+4])  
112 - return s, nil  
113 -}  
114 -  
115 -type CodePageID uint16  
116 -  
117 -var CodePageIDs map[CodePageID]string = map[CodePageID]string{  
118 - 37: "IBM037 - IBM EBCDIC US-Canada",  
119 - 437: "IBM437 - OEM United States",  
120 - 500: "IBM500 - IBM EBCDIC International",  
121 - 708: "ASMO-708 - Arabic (ASMO 708)",  
122 - 709: "Arabic (ASMO-449+, BCON V4)",  
123 - 710: "Arabic - Transparent Arabic",  
124 - 720: "DOS-720 - Arabic (Transparent ASMO); Arabic (DOS)",  
125 - 737: "ibm737 - OEM Greek (formerly 437G); Greek (DOS)",  
126 - 775: "ibm775 - OEM Baltic; Baltic (DOS)",  
127 - 850: "ibm850 - OEM Multilingual Latin 1; Western European (DOS)",  
128 - 852: "ibm852 - OEM Latin 2; Central European (DOS)",  
129 - 855: "IBM855 - OEM Cyrillic (primarily Russian)",  
130 - 857: "ibm857 - OEM Turkish; Turkish (DOS)",  
131 - 858: "IBM00858 - OEM Multilingual Latin 1 + Euro symbol",  
132 - 860: "IBM860 - OEM Portuguese; Portuguese (DOS)",  
133 - 861: "ibm861 - OEM Icelandic; Icelandic (DOS)",  
134 - 862: "DOS-862 - OEM Hebrew; Hebrew (DOS)",  
135 - 863: "IBM863 - OEM French Canadian; French Canadian (DOS)",  
136 - 864: "IBM864 - OEM Arabic; Arabic (864)",  
137 - 865: "IBM865 - OEM Nordic; Nordic (DOS)",  
138 - 866: "cp866 - OEM Russian; Cyrillic (DOS)",  
139 - 869: "ibm869 - OEM Modern Greek; Greek, Modern (DOS)",  
140 - 870: "IBM870 - IBM EBCDIC Multilingual/ROECE (Latin 2); IBM EBCDIC Multilingual Latin 2",  
141 - 874: "windows-874 - ANSI/OEM Thai (ISO 8859-11); Thai (Windows)",  
142 - 875: "cp875 - IBM EBCDIC Greek Modern",  
143 - 932: "shift_jis - ANSI/OEM Japanese; Japanese (Shift-JIS)",  
144 - 936: "gb2312 - ANSI/OEM Simplified Chinese (PRC, Singapore); Chinese Simplified (GB2312)",  
145 - 949: "ks_c_5601-1987 - ANSI/OEM Korean (Unified Hangul Code)",  
146 - 950: "big5 - ANSI/OEM Traditional Chinese (Taiwan; Hong Kong SAR, PRC); Chinese Traditional (Big5)",  
147 - 1026: "IBM1026 - IBM EBCDIC Turkish (Latin 5)",  
148 - 1047: "IBM01047 - BM EBCDIC Latin 1/Open System",  
149 - 1140: "IBM01140 - IBM EBCDIC US-Canada (037 + Euro symbol); IBM EBCDIC (US-Canada-Euro)",  
150 - 1141: "IBM01141 - IBM EBCDIC Germany (20273 + Euro symbol); IBM EBCDIC (Germany-Euro)",  
151 - 1142: "IBM01142 - IBM EBCDIC Denmark-Norway (20277 + Euro symbol); IBM EBCDIC (Denmark-Norway-Euro)",  
152 - 1143: "IBM01143 - IBM EBCDIC Finland-Sweden (20278 + Euro symbol); IBM EBCDIC (Finland-Sweden-Euro)",  
153 - 1144: "IBM01144 - IBM EBCDIC Italy (20280 + Euro symbol); IBM EBCDIC (Italy-Euro)",  
154 - 1145: "IBM01145 - IBM EBCDIC Latin America-Spain (20284 + Euro symbol); IBM EBCDIC (Spain-Euro)",  
155 - 1146: "IBM01146 - IBM EBCDIC United Kingdom (20285 + Euro symbol); IBM EBCDIC (UK-Euro)",  
156 - 1147: "IBM01147 - IBM EBCDIC France (20297 + Euro symbol); IBM EBCDIC (France-Euro)",  
157 - 1148: "IBM01148 - IBM EBCDIC International (500 + Euro symbol); IBM EBCDIC (International-Euro)",  
158 - 1149: "IBM01149 - IBM EBCDIC Icelandic (20871 + Euro symbol); IBM EBCDIC (Icelandic-Euro)",  
159 - 1200: "utf-16 - Unicode UTF-16, little endian byte order (BMP of ISO 10646); available only to managed applications",  
160 - 1201: "unicodeFFFE - Unicode UTF-16, big endian byte order; available only to managed applications",  
161 - 1250: "windows-1250 - ANSI Central European; Central European (Windows)",  
162 - 1251: "windows-1251 - ANSI Cyrillic; Cyrillic (Windows)",  
163 - 1252: "windows-1252 - ANSI Latin 1; Western European (Windows)",  
164 - 1253: "windows-1253 - ANSI Greek; Greek (Windows)",  
165 - 1254: "windows-1254 - ANSI Turkish; Turkish (Windows)",  
166 - 1255: "windows-1255 - ANSI Hebrew; Hebrew (Windows)",  
167 - 1256: "windows-1256 - ANSI Arabic; Arabic (Windows)",  
168 - 1257: "windows-1257 - ANSI Baltic; Baltic (Windows)",  
169 - 1258: "windows-1258 - ANSI/OEM Vietnamese; Vietnamese (Windows)",  
170 - 1361: "Johab - Korean (Johab)",  
171 - 10000: "macintosh - MAC Roman; Western European (Mac)",  
172 - 10001: "x-mac-japanese - Japanese (Mac)",  
173 - 10002: "x-mac-chinesetrad - MAC Traditional Chinese (Big5); Chinese Traditional (Mac)",  
174 - 10003: "x-mac-korean - Korean (Mac)",  
175 - 10004: "x-mac-arabic - Arabic (Mac)",  
176 - 10005: "x-mac-hebrew - Hebrew (Mac)",  
177 - 10006: "x-mac-greek - Greek (Mac)",  
178 - 10007: "x-mac-cyrillic - Cyrillic (Mac)",  
179 - 10008: "x-mac-chinesesimp - MAC Simplified Chinese (GB 2312); Chinese Simplified (Mac)",  
180 - 10010: "x-mac-romanian - Romanian (Mac)",  
181 - 10017: "x-mac-ukrainian - Ukrainian (Mac)",  
182 - 10021: "x-mac-thai - Thai (Mac)",  
183 - 10029: "x-mac-ce - MAC Latin 2; Central European (Mac)",  
184 - 10079: "x-mac-icelandic - Icelandic (Mac)",  
185 - 10081: "x-mac-turkish - Turkish (Mac)",  
186 - 10082: "x-mac-croatian - Croatian (Mac)",  
187 - 12000: "utf-32 - Unicode UTF-32, little endian byte order; available only to managed applications",  
188 - 12001: "utf-32BE - Unicode UTF-32, big endian byte order; available only to managed applications",  
189 - 20000: "x-Chinese_CNS - CNS Taiwan; Chinese Traditional (CNS)",  
190 - 20001: "x-cp20001 - TCA Taiwan",  
191 - 20002: "x_Chinese-Eten - Eten Taiwan; Chinese Traditional (Eten)",  
192 - 20003: "x-cp20003 - IBM5550 Taiwan",  
193 - 20004: "x-cp20004 - TeleText Taiwan",  
194 - 20005: "x-cp20005 - Wang Taiwan",  
195 - 20105: "x-IA5 - IA5 (IRV International Alphabet No. 5, 7-bit); Western European (IA5)",  
196 - 20106: "x-IA5-German - IA5 German (7-bit)",  
197 - 20107: "x-IA5-Swedish - IA5 Swedish (7-bit)",  
198 - 20108: "x-IA5-Norwegian - IA5 Norwegian (7-bit)",  
199 - 20127: "us-ascii - US-ASCII (7-bit)",  
200 - 20261: "x-cp20261 - T.61",  
201 - 20269: "x-cp20269 - ISO 6937 Non-Spacing Accent",  
202 - 20273: "IBM273 - IBM EBCDIC Germany",  
203 - 20277: "IBM277 - IBM EBCDIC Denmark-Norway",  
204 - 20278: "IBM278 - IBM EBCDIC Finland-Sweden",  
205 - 20280: "IBM280 - IBM EBCDIC Italy",  
206 - 20284: "IBM284 - IBM EBCDIC Latin America-Spain",  
207 - 20285: "IBM285 - IBM EBCDIC United Kingdom",  
208 - 20290: "IBM290 - IBM EBCDIC Japanese Katakana Extended",  
209 - 20297: "IBM297 - IBM EBCDIC France",  
210 - 20420: "IBM420 - IBM EBCDIC Arabic",  
211 - 20423: "IBM423 - IBM EBCDIC Greek",  
212 - 20424: "IBM424 - IBM EBCDIC Hebrew",  
213 - 20833: "x-EBCDIC-KoreanExtended - IBM EBCDIC Korean Extended",  
214 - 20838: "IBM-Thai - IBM EBCDIC Thai",  
215 - 20866: "koi8-r - Russian (KOI8-R); Cyrillic (KOI8-R)",  
216 - 20871: "IBM871 - IBM EBCDIC Icelandic",  
217 - 20880: "IBM880 - IBM EBCDIC Cyrillic Russian",  
218 - 20905: "IBM905 - IBM EBCDIC Turkish",  
219 - 20924: "IBM00924 - IBM EBCDIC Latin 1/Open System (1047 + Euro symbol)",  
220 - 20932: "EUC-JP - Japanese (JIS 0208-1990 and 0212-1990)",  
221 - 20936: "x-cp20936 - Simplified Chinese (GB2312); Chinese Simplified (GB2312-80)",  
222 - 20949: "x-cp20949 - Korean Wansung",  
223 - 21025: "cp1025 - IBM EBCDIC Cyrillic Serbian-Bulgarian",  
224 - 21027: "(deprecated)",  
225 - 21866: "koi8-u - Ukrainian (KOI8-U); Cyrillic (KOI8-U)",  
226 - 28591: "iso-8859-1 - ISO 8859-1 Latin 1; Western European (ISO)",  
227 - 28592: "iso-8859-2 - ISO 8859-2 Central European; Central European (ISO)",  
228 - 28593: "iso-8859-3 - ISO 8859-3 Latin 3",  
229 - 28594: "iso-8859-4 - ISO 8859-4 Baltic",  
230 - 28595: "iso-8859-5 - ISO 8859-5 Cyrillic",  
231 - 28596: "iso-8859-6 - ISO 8859-6 Arabic",  
232 - 28597: "iso-8859-7 - ISO 8859-7 Greek",  
233 - 28598: "iso-8859-8 - ISO 8859-8 Hebrew; Hebrew (ISO-Visual)",  
234 - 28599: "iso-8859-9 - ISO 8859-9 Turkish",  
235 - 28603: "iso-8859-13 - ISO 8859-13 Estonian",  
236 - 28605: "iso-8859-15 - ISO 8859-15 Latin 9",  
237 - 29001: "x-Europa - Europa 3",  
238 - 38598: "iso-8859-8-i - ISO 8859-8 Hebrew; Hebrew (ISO-Logical)",  
239 - 50220: "iso-2022-jp - ISO 2022 Japanese with no halfwidth Katakana; Japanese (JIS)",  
240 - 50221: "csISO2022JP - ISO 2022 Japanese with halfwidth Katakana; Japanese (JIS-Allow 1 byte Kana)",  
241 - 50222: "iso-2022-jp - ISO 2022 Japanese JIS X 0201-1989; Japanese (JIS-Allow 1 byte Kana - SO/SI)",  
242 - 50225: "iso-2022-kr - ISO 2022 Korean",  
243 - 50227: "x-cp50227 - ISO 2022 Simplified Chinese; Chinese Simplified (ISO 2022)",  
244 - 50229: "ISO 2022 - Traditional Chinese",  
245 - 50930: "EBCDIC - Japanese (Katakana) Extended",  
246 - 50931: "EBCDIC - US-Canada and Japanese",  
247 - 50933: "EBCDIC - Korean Extended and Korean",  
248 - 50935: "EBCDIC - Simplified Chinese Extended and Simplified Chinese",  
249 - 50936: "EBCDIC - Simplified Chinese",  
250 - 50937: "EBCDIC - US-Canada and Traditional Chinese",  
251 - 50939: "EBCDIC - Japanese (Latin) Extended and Japanese",  
252 - 51932: "euc-jp - EUC Japanese",  
253 - 51936: "EUC-CN - EUC Simplified Chinese; Chinese Simplified (EUC)",  
254 - 51949: "euc-kr - EUC Korean",  
255 - 51950: "EUC - Traditional Chinese",  
256 - 52936: "hz-gb-2312 - HZ-GB2312 Simplified Chinese; Chinese Simplified (HZ)",  
257 - 54936: "GB18030 - Windows XP and later: GB18030 Simplified Chinese (4 byte); Chinese Simplified (GB18030)",  
258 - 57002: "x-iscii-de - ISCII Devanagari",  
259 - 57003: "x-iscii-be - ISCII Bengali",  
260 - 57004: "x-iscii-ta - ISCII Tamil",  
261 - 57005: "x-iscii-te - ISCII Telugu",  
262 - 57006: "x-iscii-as - ISCII Assamese",  
263 - 57007: "x-iscii-or - ISCII Oriya",  
264 - 57008: "x-iscii-ka - ISCII Kannada",  
265 - 57009: "x-iscii-ma - ISCII Malayalam",  
266 - 57010: "x-iscii-gu - ISCII Gujarati",  
267 - 57011: "x-iscii-pa - ISCII Punjabi",  
268 - 65000: "utf-7 - Unicode (UTF-7)",  
269 - 65001: "utf-8 - Unicode (UTF-8)",  
270 -} 1 +// Copyright 2014 Richard Lehane. All rights reserved.
  2 +//
  3 +// Licensed under the Apache License, Version 2.0 (the "License");
  4 +// you may not use this file except in compliance with the License.
  5 +// You may obtain a copy of the License at
  6 +//
  7 +// http://www.apache.org/licenses/LICENSE-2.0
  8 +//
  9 +// Unless required by applicable law or agreed to in writing, software
  10 +// distributed under the License is distributed on an "AS IS" BASIS,
  11 +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  12 +// See the License for the specific language governing permissions and
  13 +// limitations under the License.
  14 +
  15 +package types
  16 +
  17 +import (
  18 + "encoding/binary"
  19 + "strings"
  20 + "unicode/utf16"
  21 +)
  22 +
  23 +func nullTerminated(s string) string {
  24 + return s[:strings.Index(s, "\x00")]
  25 +}
  26 +
  27 +type UnicodeString []uint16
  28 +
  29 +func (s UnicodeString) Type() string {
  30 + return "UnicodeString"
  31 +}
  32 +
  33 +func (s UnicodeString) Length() int {
  34 + return 4 + len(s)*2
  35 +}
  36 +
  37 +func (s UnicodeString) String() string {
  38 + if len(s) == 0 {
  39 + return ""
  40 + }
  41 + return nullTerminated(string(utf16.Decode(s)))
  42 +}
  43 +
  44 +func MakeUnicode(b []byte) (Type, error) {
  45 + if len(b) < 4 {
  46 + return UnicodeString{}, ErrType
  47 + }
  48 + l := int(binary.LittleEndian.Uint32(b[:4]))
  49 + if l == 0 {
  50 + return UnicodeString{}, nil
  51 + }
  52 + if len(b) < l*2+4 {
  53 + return UnicodeString{}, ErrType
  54 + }
  55 + s := make(UnicodeString, l)
  56 + for i := range s {
  57 + start := i*2 + 4
  58 + s[i] = binary.LittleEndian.Uint16(b[start : start+2])
  59 + }
  60 + return s, nil
  61 +}
  62 +
  63 +type CodeString struct {
  64 + id CodePageID
  65 + Chars []byte
  66 +}
  67 +
  68 +func (s *CodeString) SetId(i CodePageID) {
  69 + s.id = i
  70 +}
  71 +
  72 +func (s *CodeString) Encoding() string {
  73 + return CodePageIDs[s.id]
  74 +}
  75 +
  76 +func (s *CodeString) Type() string {
  77 + return "CodeString"
  78 +}
  79 +
  80 +func (s *CodeString) Length() int {
  81 + return 4 + len(s.Chars)
  82 +}
  83 +
  84 +func (s *CodeString) String() string {
  85 + if len(s.Chars) == 0 {
  86 + return ""
  87 + }
  88 + if s.id == 1200 {
  89 + chars := make([]uint16, len(s.Chars)/2)
  90 + for i := range chars {
  91 + chars[i] = binary.LittleEndian.Uint16(s.Chars[i*2 : i*2+2])
  92 + }
  93 + return nullTerminated(string(utf16.Decode(chars)))
  94 + }
  95 + return nullTerminated(string(s.Chars))
  96 +}
  97 +
  98 +func MakeCodeString(b []byte) (Type, error) {
  99 + if len(b) < 4 {
  100 + return &CodeString{}, ErrType
  101 + }
  102 + s := &CodeString{}
  103 + l := int(binary.LittleEndian.Uint32(b[:4]))
  104 + if l == 0 {
  105 + return s, nil
  106 + }
  107 + if len(b) < l+4 {
  108 + return s, ErrType
  109 + }
  110 + s.Chars = make([]byte, l)
  111 + copy(s.Chars, b[4:l+4])
  112 + return s, nil
  113 +}
  114 +
  115 +type CodePageID uint16
  116 +
  117 +var CodePageIDs map[CodePageID]string = map[CodePageID]string{
  118 + 37: "IBM037 - IBM EBCDIC US-Canada",
  119 + 437: "IBM437 - OEM United States",
  120 + 500: "IBM500 - IBM EBCDIC International",
  121 + 708: "ASMO-708 - Arabic (ASMO 708)",
  122 + 709: "Arabic (ASMO-449+, BCON V4)",
  123 + 710: "Arabic - Transparent Arabic",
  124 + 720: "DOS-720 - Arabic (Transparent ASMO); Arabic (DOS)",
  125 + 737: "ibm737 - OEM Greek (formerly 437G); Greek (DOS)",
  126 + 775: "ibm775 - OEM Baltic; Baltic (DOS)",
  127 + 850: "ibm850 - OEM Multilingual Latin 1; Western European (DOS)",
  128 + 852: "ibm852 - OEM Latin 2; Central European (DOS)",
  129 + 855: "IBM855 - OEM Cyrillic (primarily Russian)",
  130 + 857: "ibm857 - OEM Turkish; Turkish (DOS)",
  131 + 858: "IBM00858 - OEM Multilingual Latin 1 + Euro symbol",
  132 + 860: "IBM860 - OEM Portuguese; Portuguese (DOS)",
  133 + 861: "ibm861 - OEM Icelandic; Icelandic (DOS)",
  134 + 862: "DOS-862 - OEM Hebrew; Hebrew (DOS)",
  135 + 863: "IBM863 - OEM French Canadian; French Canadian (DOS)",
  136 + 864: "IBM864 - OEM Arabic; Arabic (864)",
  137 + 865: "IBM865 - OEM Nordic; Nordic (DOS)",
  138 + 866: "cp866 - OEM Russian; Cyrillic (DOS)",
  139 + 869: "ibm869 - OEM Modern Greek; Greek, Modern (DOS)",
  140 + 870: "IBM870 - IBM EBCDIC Multilingual/ROECE (Latin 2); IBM EBCDIC Multilingual Latin 2",
  141 + 874: "windows-874 - ANSI/OEM Thai (ISO 8859-11); Thai (Windows)",
  142 + 875: "cp875 - IBM EBCDIC Greek Modern",
  143 + 932: "shift_jis - ANSI/OEM Japanese; Japanese (Shift-JIS)",
  144 + 936: "gb2312 - ANSI/OEM Simplified Chinese (PRC, Singapore); Chinese Simplified (GB2312)",
  145 + 949: "ks_c_5601-1987 - ANSI/OEM Korean (Unified Hangul Code)",
  146 + 950: "big5 - ANSI/OEM Traditional Chinese (Taiwan; Hong Kong SAR, PRC); Chinese Traditional (Big5)",
  147 + 1026: "IBM1026 - IBM EBCDIC Turkish (Latin 5)",
  148 + 1047: "IBM01047 - BM EBCDIC Latin 1/Open System",
  149 + 1140: "IBM01140 - IBM EBCDIC US-Canada (037 + Euro symbol); IBM EBCDIC (US-Canada-Euro)",
  150 + 1141: "IBM01141 - IBM EBCDIC Germany (20273 + Euro symbol); IBM EBCDIC (Germany-Euro)",
  151 + 1142: "IBM01142 - IBM EBCDIC Denmark-Norway (20277 + Euro symbol); IBM EBCDIC (Denmark-Norway-Euro)",
  152 + 1143: "IBM01143 - IBM EBCDIC Finland-Sweden (20278 + Euro symbol); IBM EBCDIC (Finland-Sweden-Euro)",
  153 + 1144: "IBM01144 - IBM EBCDIC Italy (20280 + Euro symbol); IBM EBCDIC (Italy-Euro)",
  154 + 1145: "IBM01145 - IBM EBCDIC Latin America-Spain (20284 + Euro symbol); IBM EBCDIC (Spain-Euro)",
  155 + 1146: "IBM01146 - IBM EBCDIC United Kingdom (20285 + Euro symbol); IBM EBCDIC (UK-Euro)",
  156 + 1147: "IBM01147 - IBM EBCDIC France (20297 + Euro symbol); IBM EBCDIC (France-Euro)",
  157 + 1148: "IBM01148 - IBM EBCDIC International (500 + Euro symbol); IBM EBCDIC (International-Euro)",
  158 + 1149: "IBM01149 - IBM EBCDIC Icelandic (20871 + Euro symbol); IBM EBCDIC (Icelandic-Euro)",
  159 + 1200: "utf-16 - Unicode UTF-16, little endian byte order (BMP of ISO 10646); available only to managed applications",
  160 + 1201: "unicodeFFFE - Unicode UTF-16, big endian byte order; available only to managed applications",
  161 + 1250: "windows-1250 - ANSI Central European; Central European (Windows)",
  162 + 1251: "windows-1251 - ANSI Cyrillic; Cyrillic (Windows)",
  163 + 1252: "windows-1252 - ANSI Latin 1; Western European (Windows)",
  164 + 1253: "windows-1253 - ANSI Greek; Greek (Windows)",
  165 + 1254: "windows-1254 - ANSI Turkish; Turkish (Windows)",
  166 + 1255: "windows-1255 - ANSI Hebrew; Hebrew (Windows)",
  167 + 1256: "windows-1256 - ANSI Arabic; Arabic (Windows)",
  168 + 1257: "windows-1257 - ANSI Baltic; Baltic (Windows)",
  169 + 1258: "windows-1258 - ANSI/OEM Vietnamese; Vietnamese (Windows)",
  170 + 1361: "Johab - Korean (Johab)",
  171 + 10000: "macintosh - MAC Roman; Western European (Mac)",
  172 + 10001: "x-mac-japanese - Japanese (Mac)",
  173 + 10002: "x-mac-chinesetrad - MAC Traditional Chinese (Big5); Chinese Traditional (Mac)",
  174 + 10003: "x-mac-korean - Korean (Mac)",
  175 + 10004: "x-mac-arabic - Arabic (Mac)",
  176 + 10005: "x-mac-hebrew - Hebrew (Mac)",
  177 + 10006: "x-mac-greek - Greek (Mac)",
  178 + 10007: "x-mac-cyrillic - Cyrillic (Mac)",
  179 + 10008: "x-mac-chinesesimp - MAC Simplified Chinese (GB 2312); Chinese Simplified (Mac)",
  180 + 10010: "x-mac-romanian - Romanian (Mac)",
  181 + 10017: "x-mac-ukrainian - Ukrainian (Mac)",
  182 + 10021: "x-mac-thai - Thai (Mac)",
  183 + 10029: "x-mac-ce - MAC Latin 2; Central European (Mac)",
  184 + 10079: "x-mac-icelandic - Icelandic (Mac)",
  185 + 10081: "x-mac-turkish - Turkish (Mac)",
  186 + 10082: "x-mac-croatian - Croatian (Mac)",
  187 + 12000: "utf-32 - Unicode UTF-32, little endian byte order; available only to managed applications",
  188 + 12001: "utf-32BE - Unicode UTF-32, big endian byte order; available only to managed applications",
  189 + 20000: "x-Chinese_CNS - CNS Taiwan; Chinese Traditional (CNS)",
  190 + 20001: "x-cp20001 - TCA Taiwan",
  191 + 20002: "x_Chinese-Eten - Eten Taiwan; Chinese Traditional (Eten)",
  192 + 20003: "x-cp20003 - IBM5550 Taiwan",
  193 + 20004: "x-cp20004 - TeleText Taiwan",
  194 + 20005: "x-cp20005 - Wang Taiwan",
  195 + 20105: "x-IA5 - IA5 (IRV International Alphabet No. 5, 7-bit); Western European (IA5)",
  196 + 20106: "x-IA5-German - IA5 German (7-bit)",
  197 + 20107: "x-IA5-Swedish - IA5 Swedish (7-bit)",
  198 + 20108: "x-IA5-Norwegian - IA5 Norwegian (7-bit)",
  199 + 20127: "us-ascii - US-ASCII (7-bit)",
  200 + 20261: "x-cp20261 - T.61",
  201 + 20269: "x-cp20269 - ISO 6937 Non-Spacing Accent",
  202 + 20273: "IBM273 - IBM EBCDIC Germany",
  203 + 20277: "IBM277 - IBM EBCDIC Denmark-Norway",
  204 + 20278: "IBM278 - IBM EBCDIC Finland-Sweden",
  205 + 20280: "IBM280 - IBM EBCDIC Italy",
  206 + 20284: "IBM284 - IBM EBCDIC Latin America-Spain",
  207 + 20285: "IBM285 - IBM EBCDIC United Kingdom",
  208 + 20290: "IBM290 - IBM EBCDIC Japanese Katakana Extended",
  209 + 20297: "IBM297 - IBM EBCDIC France",
  210 + 20420: "IBM420 - IBM EBCDIC Arabic",
  211 + 20423: "IBM423 - IBM EBCDIC Greek",
  212 + 20424: "IBM424 - IBM EBCDIC Hebrew",
  213 + 20833: "x-EBCDIC-KoreanExtended - IBM EBCDIC Korean Extended",
  214 + 20838: "IBM-Thai - IBM EBCDIC Thai",
  215 + 20866: "koi8-r - Russian (KOI8-R); Cyrillic (KOI8-R)",
  216 + 20871: "IBM871 - IBM EBCDIC Icelandic",
  217 + 20880: "IBM880 - IBM EBCDIC Cyrillic Russian",
  218 + 20905: "IBM905 - IBM EBCDIC Turkish",
  219 + 20924: "IBM00924 - IBM EBCDIC Latin 1/Open System (1047 + Euro symbol)",
  220 + 20932: "EUC-JP - Japanese (JIS 0208-1990 and 0212-1990)",
  221 + 20936: "x-cp20936 - Simplified Chinese (GB2312); Chinese Simplified (GB2312-80)",
  222 + 20949: "x-cp20949 - Korean Wansung",
  223 + 21025: "cp1025 - IBM EBCDIC Cyrillic Serbian-Bulgarian",
  224 + 21027: "(deprecated)",
  225 + 21866: "koi8-u - Ukrainian (KOI8-U); Cyrillic (KOI8-U)",
  226 + 28591: "iso-8859-1 - ISO 8859-1 Latin 1; Western European (ISO)",
  227 + 28592: "iso-8859-2 - ISO 8859-2 Central European; Central European (ISO)",
  228 + 28593: "iso-8859-3 - ISO 8859-3 Latin 3",
  229 + 28594: "iso-8859-4 - ISO 8859-4 Baltic",
  230 + 28595: "iso-8859-5 - ISO 8859-5 Cyrillic",
  231 + 28596: "iso-8859-6 - ISO 8859-6 Arabic",
  232 + 28597: "iso-8859-7 - ISO 8859-7 Greek",
  233 + 28598: "iso-8859-8 - ISO 8859-8 Hebrew; Hebrew (ISO-Visual)",
  234 + 28599: "iso-8859-9 - ISO 8859-9 Turkish",
  235 + 28603: "iso-8859-13 - ISO 8859-13 Estonian",
  236 + 28605: "iso-8859-15 - ISO 8859-15 Latin 9",
  237 + 29001: "x-Europa - Europa 3",
  238 + 38598: "iso-8859-8-i - ISO 8859-8 Hebrew; Hebrew (ISO-Logical)",
  239 + 50220: "iso-2022-jp - ISO 2022 Japanese with no halfwidth Katakana; Japanese (JIS)",
  240 + 50221: "csISO2022JP - ISO 2022 Japanese with halfwidth Katakana; Japanese (JIS-Allow 1 byte Kana)",
  241 + 50222: "iso-2022-jp - ISO 2022 Japanese JIS X 0201-1989; Japanese (JIS-Allow 1 byte Kana - SO/SI)",
  242 + 50225: "iso-2022-kr - ISO 2022 Korean",
  243 + 50227: "x-cp50227 - ISO 2022 Simplified Chinese; Chinese Simplified (ISO 2022)",
  244 + 50229: "ISO 2022 - Traditional Chinese",
  245 + 50930: "EBCDIC - Japanese (Katakana) Extended",
  246 + 50931: "EBCDIC - US-Canada and Japanese",
  247 + 50933: "EBCDIC - Korean Extended and Korean",
  248 + 50935: "EBCDIC - Simplified Chinese Extended and Simplified Chinese",
  249 + 50936: "EBCDIC - Simplified Chinese",
  250 + 50937: "EBCDIC - US-Canada and Traditional Chinese",
  251 + 50939: "EBCDIC - Japanese (Latin) Extended and Japanese",
  252 + 51932: "euc-jp - EUC Japanese",
  253 + 51936: "EUC-CN - EUC Simplified Chinese; Chinese Simplified (EUC)",
  254 + 51949: "euc-kr - EUC Korean",
  255 + 51950: "EUC - Traditional Chinese",
  256 + 52936: "hz-gb-2312 - HZ-GB2312 Simplified Chinese; Chinese Simplified (HZ)",
  257 + 54936: "GB18030 - Windows XP and later: GB18030 Simplified Chinese (4 byte); Chinese Simplified (GB18030)",
  258 + 57002: "x-iscii-de - ISCII Devanagari",
  259 + 57003: "x-iscii-be - ISCII Bengali",
  260 + 57004: "x-iscii-ta - ISCII Tamil",
  261 + 57005: "x-iscii-te - ISCII Telugu",
  262 + 57006: "x-iscii-as - ISCII Assamese",
  263 + 57007: "x-iscii-or - ISCII Oriya",
  264 + 57008: "x-iscii-ka - ISCII Kannada",
  265 + 57009: "x-iscii-ma - ISCII Malayalam",
  266 + 57010: "x-iscii-gu - ISCII Gujarati",
  267 + 57011: "x-iscii-pa - ISCII Punjabi",
  268 + 65000: "utf-7 - Unicode (UTF-7)",
  269 + 65001: "utf-8 - Unicode (UTF-8)",
  270 +}
1 -// Copyright 2014 Richard Lehane. All rights reserved.  
2 -//  
3 -// Licensed under the Apache License, Version 2.0 (the "License");  
4 -// you may not use this file except in compliance with the License.  
5 -// You may obtain a copy of the License at  
6 -//  
7 -// http://www.apache.org/licenses/LICENSE-2.0  
8 -//  
9 -// Unless required by applicable law or agreed to in writing, software  
10 -// distributed under the License is distributed on an "AS IS" BASIS,  
11 -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  
12 -// See the License for the specific language governing permissions and  
13 -// limitations under the License.  
14 -  
15 -package types  
16 -  
17 -import (  
18 - "encoding/binary"  
19 - "errors"  
20 -)  
21 -  
22 -// MakeVariant is defined in vectorArray.go. It calls Evaluate, which refers to the MakeTypes map, so must add at runtime  
23 -func init() { MakeTypes[VT_VARIANT] = MakeVariant }  
24 -  
25 -var (  
26 - ErrType = errors.New("msoleps: error coercing byte stream to type")  
27 - ErrUnknownType = errors.New("msoleps: unknown type error")  
28 -)  
29 -  
30 -type Type interface {  
31 - String() string  
32 - Type() string  
33 - Length() int  
34 -}  
35 -  
36 -const (  
37 - vector uint16 = iota + 1  
38 - array  
39 -)  
40 -  
41 -func Evaluate(b []byte) (Type, error) {  
42 - if len(b) < 4 {  
43 - return I1(0), ErrType  
44 - }  
45 - id := TypeID(binary.LittleEndian.Uint16(b[:2]))  
46 - f, ok := MakeTypes[id]  
47 - if !ok {  
48 - return I1(0), ErrUnknownType  
49 - }  
50 - switch binary.LittleEndian.Uint16(b[2:4]) {  
51 - case vector:  
52 - return MakeVector(f, b[4:])  
53 - case array:  
54 - return MakeArray(f, b[4:])  
55 - }  
56 - return f(b[4:])  
57 -}  
58 -  
59 -type TypeID uint16  
60 -  
61 -const (  
62 - VT_EMPTY TypeID = iota // 0x00  
63 - VT_NULL  
64 - VT_I2  
65 - VT_I4  
66 - VT_R4  
67 - VT_R8  
68 - VT_CY  
69 - VT_DATE  
70 - VT_BSTR  
71 - _  
72 - VT_ERROR  
73 - VT_BOOL  
74 - VT_VARIANT  
75 - _  
76 - VT_DECIMAL  
77 - _  
78 - VT_I1  
79 - VT_U1  
80 - VT_UI2  
81 - VT_UI4  
82 - VT_I8  
83 - VT_UI8  
84 - VT_INT  
85 - VT_UINT //0x17  
86 - _ = iota + 5  
87 - VT_LPSTR //0x1E  
88 - VT_LPWSTR  
89 - VT_FILETIME = iota + 0x25 // 0x40  
90 - VT_BLOB  
91 - VT_STREAM  
92 - VT_STORAGE  
93 - VT_STREAMED_OBJECT  
94 - VT_STORED_OBJECT  
95 - VT_BLOB_OBJECT  
96 - VT_CF  
97 - VT_CLSID  
98 - VT_VERSIONED_STREAM // 0x49  
99 -)  
100 -  
101 -type MakeType func([]byte) (Type, error)  
102 -  
103 -var MakeTypes map[TypeID]MakeType = map[TypeID]MakeType{  
104 - VT_I2: MakeI2,  
105 - VT_I4: MakeI4,  
106 - VT_R4: MakeR4,  
107 - VT_R8: MakeR8,  
108 - VT_CY: MakeCurrency,  
109 - VT_DATE: MakeDate,  
110 - VT_BSTR: MakeCodeString,  
111 - VT_BOOL: MakeBool,  
112 - VT_DECIMAL: MakeDecimal,  
113 - VT_I1: MakeI1,  
114 - VT_U1: MakeUI1,  
115 - VT_UI2: MakeUI2,  
116 - VT_UI4: MakeUI4,  
117 - VT_I8: MakeI8,  
118 - VT_UI8: MakeUI8,  
119 - VT_INT: MakeI4,  
120 - VT_UINT: MakeUI4,  
121 - VT_LPSTR: MakeCodeString,  
122 - VT_LPWSTR: MakeUnicode,  
123 - VT_FILETIME: MakeFileTime,  
124 - VT_CLSID: MakeGuid,  
125 -} 1 +// Copyright 2014 Richard Lehane. All rights reserved.
  2 +//
  3 +// Licensed under the Apache License, Version 2.0 (the "License");
  4 +// you may not use this file except in compliance with the License.
  5 +// You may obtain a copy of the License at
  6 +//
  7 +// http://www.apache.org/licenses/LICENSE-2.0
  8 +//
  9 +// Unless required by applicable law or agreed to in writing, software
  10 +// distributed under the License is distributed on an "AS IS" BASIS,
  11 +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  12 +// See the License for the specific language governing permissions and
  13 +// limitations under the License.
  14 +
  15 +package types
  16 +
  17 +import (
  18 + "encoding/binary"
  19 + "errors"
  20 +)
  21 +
  22 +// MakeVariant is defined in vectorArray.go. It calls Evaluate, which refers to the MakeTypes map, so must add at runtime
  23 +func init() { MakeTypes[VT_VARIANT] = MakeVariant }
  24 +
  25 +var (
  26 + ErrType = errors.New("msoleps: error coercing byte stream to type")
  27 + ErrUnknownType = errors.New("msoleps: unknown type error")
  28 +)
  29 +
  30 +type Type interface {
  31 + String() string
  32 + Type() string
  33 + Length() int
  34 +}
  35 +
  36 +const (
  37 + vector uint16 = iota + 1
  38 + array
  39 +)
  40 +
  41 +func Evaluate(b []byte) (Type, error) {
  42 + if len(b) < 4 {
  43 + return I1(0), ErrType
  44 + }
  45 + id := TypeID(binary.LittleEndian.Uint16(b[:2]))
  46 + f, ok := MakeTypes[id]
  47 + if !ok {
  48 + return I1(0), ErrUnknownType
  49 + }
  50 + switch binary.LittleEndian.Uint16(b[2:4]) {
  51 + case vector:
  52 + return MakeVector(f, b[4:])
  53 + case array:
  54 + return MakeArray(f, b[4:])
  55 + }
  56 + return f(b[4:])
  57 +}
  58 +
  59 +type TypeID uint16
  60 +
  61 +const (
  62 + VT_EMPTY TypeID = iota // 0x00
  63 + VT_NULL
  64 + VT_I2
  65 + VT_I4
  66 + VT_R4
  67 + VT_R8
  68 + VT_CY
  69 + VT_DATE
  70 + VT_BSTR
  71 + _
  72 + VT_ERROR
  73 + VT_BOOL
  74 + VT_VARIANT
  75 + _
  76 + VT_DECIMAL
  77 + _
  78 + VT_I1
  79 + VT_U1
  80 + VT_UI2
  81 + VT_UI4
  82 + VT_I8
  83 + VT_UI8
  84 + VT_INT
  85 + VT_UINT //0x17
  86 + _ = iota + 5
  87 + VT_LPSTR //0x1E
  88 + VT_LPWSTR
  89 + VT_FILETIME = iota + 0x25 // 0x40
  90 + VT_BLOB
  91 + VT_STREAM
  92 + VT_STORAGE
  93 + VT_STREAMED_OBJECT
  94 + VT_STORED_OBJECT
  95 + VT_BLOB_OBJECT
  96 + VT_CF
  97 + VT_CLSID
  98 + VT_VERSIONED_STREAM // 0x49
  99 +)
  100 +
  101 +type MakeType func([]byte) (Type, error)
  102 +
  103 +var MakeTypes map[TypeID]MakeType = map[TypeID]MakeType{
  104 + VT_I2: MakeI2,
  105 + VT_I4: MakeI4,
  106 + VT_R4: MakeR4,
  107 + VT_R8: MakeR8,
  108 + VT_CY: MakeCurrency,
  109 + VT_DATE: MakeDate,
  110 + VT_BSTR: MakeCodeString,
  111 + VT_BOOL: MakeBool,
  112 + VT_DECIMAL: MakeDecimal,
  113 + VT_I1: MakeI1,
  114 + VT_U1: MakeUI1,
  115 + VT_UI2: MakeUI2,
  116 + VT_UI4: MakeUI4,
  117 + VT_I8: MakeI8,
  118 + VT_UI8: MakeUI8,
  119 + VT_INT: MakeI4,
  120 + VT_UINT: MakeUI4,
  121 + VT_LPSTR: MakeCodeString,
  122 + VT_LPWSTR: MakeUnicode,
  123 + VT_FILETIME: MakeFileTime,
  124 + VT_CLSID: MakeGuid,
  125 +}
1 -// Copyright 2015 Richard Lehane. All rights reserved.  
2 -//  
3 -// Licensed under the Apache License, Version 2.0 (the "License");  
4 -// you may not use this file except in compliance with the License.  
5 -// You may obtain a copy of the License at  
6 -//  
7 -// http://www.apache.org/licenses/LICENSE-2.0  
8 -//  
9 -// Unless required by applicable law or agreed to in writing, software  
10 -// distributed under the License is distributed on an "AS IS" BASIS,  
11 -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  
12 -// See the License for the specific language governing permissions and  
13 -// limitations under the License.  
14 -  
15 -package types  
16 -  
17 -import (  
18 - "encoding/binary"  
19 -)  
20 -  
21 -type Vector []Type  
22 -  
23 -func (v Vector) String() string {  
24 - return ""  
25 -}  
26 -  
27 -func (v Vector) Type() string {  
28 - if len(v) > 0 {  
29 - return "Vector of " + v[0].Type()  
30 - }  
31 - return "Vector (empty)"  
32 -}  
33 -  
34 -func (v Vector) Length() int {  
35 - ret := 4  
36 - for _, t := range v {  
37 - ret += t.Length()  
38 - }  
39 - return ret  
40 -}  
41 -  
42 -func MakeVector(f MakeType, b []byte) (Type, error) {  
43 - if len(b) < 4 {  
44 - return Vector{}, ErrType  
45 - }  
46 - l := int(binary.LittleEndian.Uint32(b[:4]))  
47 - v := make(Vector, l)  
48 - place := 4  
49 - for i := 0; i < l; i++ {  
50 - t, err := f(b[place:])  
51 - if err != nil {  
52 - return Vector{}, ErrType  
53 - }  
54 - v[i] = t  
55 - place += t.Length()  
56 - }  
57 - return v, nil  
58 -}  
59 -  
60 -type Array [][]Type  
61 -  
62 -func (a Array) String() string {  
63 - return ""  
64 -}  
65 -  
66 -func (a Array) Type() string {  
67 - if len(a) > 0 && len(a[0]) > 0 {  
68 - return "Array of " + a[0][0].Type()  
69 - }  
70 - return "Array (empty)"  
71 -}  
72 -  
73 -func (a Array) Length() int {  
74 - return 0  
75 -}  
76 -  
77 -func MakeArray(f MakeType, b []byte) (Type, error) {  
78 - return Array{}, nil  
79 -}  
80 -  
81 -type Variant struct {  
82 - t Type  
83 -}  
84 -  
85 -func (v Variant) String() string {  
86 - return "Typed Property Value containing " + v.t.String()  
87 -}  
88 -  
89 -func (v Variant) Type() string {  
90 - return "Typed Property Value containing " + v.t.Type()  
91 -}  
92 -  
93 -func (v Variant) Length() int {  
94 - return 4 + v.t.Length()  
95 -}  
96 -  
97 -func MakeVariant(b []byte) (Type, error) {  
98 - t, err := Evaluate(b)  
99 - if err != nil {  
100 - return Variant{}, err  
101 - }  
102 - return Variant{t}, nil  
103 -} 1 +// Copyright 2015 Richard Lehane. All rights reserved.
  2 +//
  3 +// Licensed under the Apache License, Version 2.0 (the "License");
  4 +// you may not use this file except in compliance with the License.
  5 +// You may obtain a copy of the License at
  6 +//
  7 +// http://www.apache.org/licenses/LICENSE-2.0
  8 +//
  9 +// Unless required by applicable law or agreed to in writing, software
  10 +// distributed under the License is distributed on an "AS IS" BASIS,
  11 +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  12 +// See the License for the specific language governing permissions and
  13 +// limitations under the License.
  14 +
  15 +package types
  16 +
  17 +import (
  18 + "encoding/binary"
  19 +)
  20 +
  21 +type Vector []Type
  22 +
  23 +func (v Vector) String() string {
  24 + return ""
  25 +}
  26 +
  27 +func (v Vector) Type() string {
  28 + if len(v) > 0 {
  29 + return "Vector of " + v[0].Type()
  30 + }
  31 + return "Vector (empty)"
  32 +}
  33 +
  34 +func (v Vector) Length() int {
  35 + ret := 4
  36 + for _, t := range v {
  37 + ret += t.Length()
  38 + }
  39 + return ret
  40 +}
  41 +
  42 +func MakeVector(f MakeType, b []byte) (Type, error) {
  43 + if len(b) < 4 {
  44 + return Vector{}, ErrType
  45 + }
  46 + l := int(binary.LittleEndian.Uint32(b[:4]))
  47 + v := make(Vector, l)
  48 + place := 4
  49 + for i := 0; i < l; i++ {
  50 + t, err := f(b[place:])
  51 + if err != nil {
  52 + return Vector{}, ErrType
  53 + }
  54 + v[i] = t
  55 + place += t.Length()
  56 + }
  57 + return v, nil
  58 +}
  59 +
  60 +type Array [][]Type
  61 +
  62 +func (a Array) String() string {
  63 + return ""
  64 +}
  65 +
  66 +func (a Array) Type() string {
  67 + if len(a) > 0 && len(a[0]) > 0 {
  68 + return "Array of " + a[0][0].Type()
  69 + }
  70 + return "Array (empty)"
  71 +}
  72 +
  73 +func (a Array) Length() int {
  74 + return 0
  75 +}
  76 +
  77 +func MakeArray(f MakeType, b []byte) (Type, error) {
  78 + return Array{}, nil
  79 +}
  80 +
  81 +type Variant struct {
  82 + t Type
  83 +}
  84 +
  85 +func (v Variant) String() string {
  86 + return "Typed Property Value containing " + v.t.String()
  87 +}
  88 +
  89 +func (v Variant) Type() string {
  90 + return "Typed Property Value containing " + v.t.Type()
  91 +}
  92 +
  93 +func (v Variant) Length() int {
  94 + return 4 + v.t.Length()
  95 +}
  96 +
  97 +func MakeVariant(b []byte) (Type, error) {
  98 + t, err := Evaluate(b)
  99 + if err != nil {
  100 + return Variant{}, err
  101 + }
  102 + return Variant{t}, nil
  103 +}
@@ -3,9 +3,6 @@ @@ -3,9 +3,6 @@
3 github.com/360EntSecGroup-Skylar/excelize/v2 3 github.com/360EntSecGroup-Skylar/excelize/v2
4 # github.com/DataDog/zstd v1.3.6-0.20190409195224-796139022798 4 # github.com/DataDog/zstd v1.3.6-0.20190409195224-796139022798
5 github.com/DataDog/zstd 5 github.com/DataDog/zstd
6 -# github.com/GeeTeam/gt3-golang-sdk v0.0.0-20200116043922-446ca8a507d2  
7 -## explicit  
8 -github.com/GeeTeam/gt3-golang-sdk/geetest  
9 # github.com/Shopify/sarama v1.23.1 6 # github.com/Shopify/sarama v1.23.1
10 ## explicit 7 ## explicit
11 github.com/Shopify/sarama 8 github.com/Shopify/sarama