合并分支 '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 | +} |
@@ -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(¶m); 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 | -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 |
-
请 注册 或 登录 后发表评论