STUDIO HAZE · image
Topaz source
Open by house policy. Topaz is our own language.
Topaz 5.9 · 42 files
topaz/src/core.tpz
Topaz · 746117 B · Original file
1
// Public CodeImage ABI facade.3
import std.bytes { Bytes }4
import std.json5
import objc_xid { 오브젝티브씨식별자시작, 오브젝티브씨식별자계속 }6
import ecc { 갈루아곱, 다항식곱 }7
import hash { 해시배열 }8
import nodes { 노드종류 }9
import plan {10
띠팔레트,11
배열에있음,12
범위씻김팔레트,13
범위코드,14
보호길이,15
이미지계획,16
이미지배치,17
이미지배치계산,18
이미지쪽계획,19
이미지팔레트,20
이미지프로필해시맞음,21
이역할팔레트,22
쪽투영문자열,23
파일프로그램코드,24
팔그물팔레트,25
프로필해시,26
픽셀글꼴,27
형식팔레트,28
}29
import print {30
고닫는구분자,31
고여는구분자,32
글자합치기,33
글평평하게,34
끝가로공백제거,35
끝공백제거,36
댓글코드,37
위치전진,38
인쇄글조각,39
인쇄조각같음,40
인쇄조각이음,41
인쇄조각자름,42
인쇄조각접두,43
인쇄조각접미,44
인쇄조각판만들기,45
인쇄조각평평하게,46
인쇄조각행수,47
인쇄호출,48
제이슨문자필드,49
제이슨정수필드,50
줄과들여쓰기,51
줄끝인가,52
}53
import render {54
글자그림,55
사각안,56
이미지머리,57
이역할변형,58
청크만들기,59
}60
import schema {61
다트댓글코드,62
다트원자본문코드,63
들여쓰기,64
러스트댓글코드,65
러스트원자본문코드,66
루비댓글코드,67
루아댓글코드,68
루아원자본문코드,69
스위프트댓글코드,70
스칼라댓글코드,71
스칼라원자본문코드,72
씨댓글코드,73
씨샵댓글코드,74
씨샵원자본문코드,75
씨플러스플러스댓글코드,76
알댓글코드,77
알원자본문코드,78
엘름댓글코드,79
엘름원자본문코드,80
엘릭서댓글코드,81
엘릭서원자본문코드,82
오캐멀댓글코드,83
오캐멀원자본문코드,84
자바댓글코드,85
자바원자본문코드,86
줄리아댓글코드,87
줄리아원자본문코드,88
코틀린댓글코드,89
코틀린원자본문코드,90
피에이치피댓글코드,91
하스켈댓글코드,92
하스켈원자본문코드,93
}94
import types { 댓글고정, 분리본문키결과, 인쇄조각판 }95
import util {96
거듭제곱이,97
문자열배열에있음,98
바이트로,99
바이트배열로,100
바이트추가,101
배열같음,102
부분배열,103
비트배타합,104
십육진숫자,105
작은값,106
큰값,107
}108
import wire {109
가변정수쓰기,110
가변정수읽기,111
갈루아표,112
널문자있음,113
대문자십육진네자리,114
대문자십육진두자리,115
사전색인,116
사전쓰기,117
사전읽기,118
사전해석,119
삼십이쓰기,120
삼십이읽기,121
안전문자열코드단위키,122
정렬고유,123
정수읽기,124
짝없는대리자있음,125
코드단위문자열,126
코드단위문자열만들기,127
코드단위사전쓰기,128
코드단위사전읽기,129
코드단위사전해석,130
코드단위키읽기,131
}133
export record 구조스칼라 {134
필드: string,135
태그: int,136
정수값: int,137
문자열값: string138
}140
export record 구조노드 {141
코드워드: int,142
부모순번: int,143
자식필드있음: bool,144
자식필드: string,145
자식색인: int,146
시작: int,147
끝: int,148
스칼라들: Array<구조스칼라>,149
식별자있음: bool,150
식별자류번호: int151
}153
export record 구조입력 {154
분리본문키해시: string,155
분리본문값수: int,156
노드들: Array<구조노드>157
}159
record 준비된구조 {160
언어번호: int,161
구조: 구조입력162
}164
function 원본문자열리터럴(스칼라: 구조스칼라) -> Result<string, string> {165
let 키 = if 스칼라.태그 == 5 { 안전문자열코드단위키(스칼라.문자열값) }166
else if 스칼라.태그 == 6 { 스칼라.문자열값 }167
else { return Err("문자열 리터럴 스칼라 태그가 틀립니다") }168
let 단위들 = 코드단위키읽기(키, true)?169
let mut 조각들: Array<string> = ["\""]170
let mut 색인 = 0171
while 색인 < 단위들.length {172
let 단위 = 단위들[색인]173
if 단위 == 34 { 조각들.push("\\\"") }174
else if 단위 == 92 { 조각들.push("\\\\") }175
else if 단위 == 8 { 조각들.push("\\b") }176
else if 단위 == 9 { 조각들.push("\\t") }177
else if 단위 == 10 { 조각들.push("\\n") }178
else if 단위 == 12 { 조각들.push("\\f") }179
else if 단위 == 13 { 조각들.push("\\r") }180
else if 단위 == 0 {181
let 다음숫자 = 색인 + 1 < 단위들.length && 단위들[색인 + 1] >= 48 && 단위들[색인 + 1] <= 57182
조각들.push(if 다음숫자 { "\\x00" } else { "\\0" })183
} else if 단위 >= 32 && 단위 <= 126 {184
match fromCodePoint(단위) {185
case Some(문자) => { 조각들.push(문자) }186
case None => return Err("ASCII 코드 단위가 유니코드 스칼라가 아닙니다")187
}188
} else if 단위 <= 255 {189
조각들.push("\\x")190
조각들.push(대문자십육진두자리(단위))191
} else {192
조각들.push("\\u")193
조각들.push(대문자십육진네자리(단위))194
}195
색인 = 색인 + 1196
}197
조각들.push("\"")198
Ok(조각들.join(""))199
}201
function 철자문자열리터럴(노드: 구조노드) -> Result<string, string> {202
let 따옴표 = if 스칼라논리(노드, "spelling.singleQuote") { "'" } else { "\"" }203
if 스칼라있음(노드, "spelling.escapeBody") {204
return Ok(따옴표 + 스칼라문자(노드, "spelling.escapeBody") + 따옴표)205
}206
if 따옴표 == "'" { return Ok("'" + 스칼라문자(노드, "value") + "'") }207
원본문자열리터럴(노드스칼라(노드, "value"))208
}210
export function 해시이백오십육(입력: Bytes) -> Result<Bytes, string> {211
바이트로(해시배열(바이트배열로(입력)))212
}214
function 구조언어번호(구조: 구조입력) -> int {215
if 구조.노드들.length == 0 { return 0 }216
let 뿌리코드 = 구조.노드들[0].코드워드217
if 노드종류(1, 뿌리코드) == 101 { return 1 }218
if 노드종류(2, 뿌리코드) == 101 { return 2 }219
if 노드종류(3, 뿌리코드) == 101 { return 3 }220
if 노드종류(4, 뿌리코드) == 101 { return 4 }221
if 노드종류(5, 뿌리코드) == 101 { return 5 }222
if 노드종류(6, 뿌리코드) == 101 { return 6 }223
if 노드종류(7, 뿌리코드) == 101 { return 7 }224
if 노드종류(8, 뿌리코드) == 101 { return 8 }225
if 노드종류(9, 뿌리코드) == 101 { return 9 }226
if 노드종류(10, 뿌리코드) == 101 { return 10 }227
if 노드종류(11, 뿌리코드) == 101 { return 11 }228
if 노드종류(12, 뿌리코드) == 101 { return 12 }229
if 노드종류(13, 뿌리코드) == 101 { return 13 }230
if 노드종류(14, 뿌리코드) == 101 { return 14 }231
if 노드종류(15, 뿌리코드) == 101 { return 15 }232
if 노드종류(16, 뿌리코드) == 101 { return 16 }233
if 노드종류(17, 뿌리코드) == 101 { return 17 }234
if 노드종류(18, 뿌리코드) == 101 { return 18 }235
if 노드종류(19, 뿌리코드) == 101 { return 19 }236
if 노드종류(21, 뿌리코드) == 101 { return 21 }237
if 노드종류(20, 뿌리코드) == 101 { return 20 }238
if 노드종류(22, 뿌리코드) == 101 { return 22 }239
if 노드종류(23, 뿌리코드) == 101 { return 23 }240
if 노드종류(24, 뿌리코드) == 101 { return 24 }241
if 노드종류(25, 뿌리코드) == 101 { return 25 }242
if 노드종류(26, 뿌리코드) == 101 { return 26 }243
if 노드종류(27, 뿌리코드) == 101 { return 27 }244
if 노드종류(28, 뿌리코드) == 101 { return 28 }245
if 노드종류(29, 뿌리코드) == 101 { return 29 }246
if 노드종류(30, 뿌리코드) == 101 { return 30 }247
0248
}250
function 코드단위태그허용(언어번호: int, 노드: 구조노드, 스칼라: 구조스칼라) -> bool {251
if 언어번호 != 1 && 언어번호 != 2 { return false }252
let 종류 = 노드종류(언어번호, 노드.코드워드)253
(종류 == 108 && 스칼라.필드 == "value") ||254
(종류 == 116 && 스칼라.필드 == "value.cooked")255
}257
function 구조스칼라검사(언어번호: int, 노드: 구조노드, 스칼라: 구조스칼라) -> Result<bool, string> {258
if 스칼라.필드 == "" || 널문자있음(스칼라.필드) {259
return Err("구조 스칼라 필드가 비었거나 영 문자를 포함합니다")260
}261
if 스칼라.필드 == "trailingFileLayout" {262
if 언어번호 != 12 || 노드.부모순번 != -1 || 노드.코드워드 != 36 ||263
스칼라.태그 != 5 || 스칼라.문자열값 == "" || 스칼라.문자열값.scalars().length > 4194304 {264
return Err("Swift 파일 끝 배치가 정규형이 아닙니다")265
}266
for 글자 in 스칼라.문자열값.scalars() {267
let 코드 = 글자.codePointAt(0) ?? 0268
if 코드 != 32 && !(코드 >= 9 && 코드 <= 13) {269
return Err("Swift 파일 끝 배치에 비배치 문자가 있습니다")270
}271
}272
}273
if 스칼라.태그 >= 0 && 스칼라.태그 <= 2 {274
if 스칼라.정수값 != 0 || 스칼라.문자열값 != "" {275
return Err("논리 구조 스칼라의 빈 본문이 정규형이 아닙니다")276
}277
return Ok(true)278
}279
if 스칼라.태그 == 3 {280
if 스칼라.정수값 < 0 || 스칼라.정수값 > 9007199254740991 || 스칼라.문자열값 != "" {281
return Err("양의 구조 스칼라가 안전 정수 정규형이 아닙니다")282
}283
return Ok(true)284
}285
if 스칼라.태그 == 4 {286
if 스칼라.정수값 < 1 || 스칼라.정수값 > 9007199254740991 || 스칼라.문자열값 != "" {287
return Err("음의 구조 스칼라가 안전 정수 정규형이 아닙니다")288
}289
return Ok(true)290
}291
if 스칼라.태그 == 5 {292
if 스칼라.정수값 != 0 { return Err("문자열 구조 스칼라 정수 본문이 0이 아닙니다") }293
return Ok(true)294
}295
if 스칼라.태그 == 6 {296
if 스칼라.정수값 != 0 { return Err("UTF-16 호스트 스칼라 정수 본문이 0이 아닙니다") }297
let 단위들 = 코드단위키읽기(스칼라.문자열값, false)?298
if !짝없는대리자있음(단위들) {299
return Err("UTF-16 호스트 스칼라에 짝없는 대리자가 없습니다")300
}301
if !코드단위태그허용(언어번호, 노드, 스칼라) {302
return Err("UTF-16 호스트 스칼라가 허용되지 않은 구조 위치에 있습니다")303
}304
return Ok(true)305
}306
Err("지원하지 않는 구조 스칼라 태그입니다")307
}309
function 구조입력검사(언어번호: int, 구조: 구조입력) -> Result<bool, string> {310
for 노드 in 구조.노드들 {311
let mut 첫필드 = true312
let mut 이전필드 = ""313
for 스칼라 in 노드.스칼라들 {314
if !첫필드 && 이전필드 >= 스칼라.필드 { return Err("구조 스칼라 필드가 정규 순서가 아닙니다") }315
구조스칼라검사(언어번호, 노드, 스칼라)?316
이전필드 = 스칼라.필드317
첫필드 = false318
}319
}320
Ok(true)321
}323
function 구조스칼라코드단위문자열(스칼라: 구조스칼라) -> Result<코드단위문자열, string> {324
if 스칼라.태그 == 5 {325
let 키 = 안전문자열코드단위키(스칼라.문자열값)326
return Ok(코드단위문자열 { 키: 키, 안전값: 스칼라.문자열값, 안전: true })327
}328
if 스칼라.태그 == 6 { return 코드단위문자열만들기(스칼라.문자열값) }329
Err("문자열이 아닌 구조 스칼라입니다")330
}332
record 압축원본행 {333
행: int,334
시작: int335
}337
function 원본기하필드인가(필드: string) -> bool {338
필드 == "startRow" || 필드 == "startColumn" ||339
필드 == "endRow" || 필드 == "endColumn"340
}342
function 압축원본행들(구조: 구조입력) -> Result<Array<압축원본행>, string> {343
let mut 행들: Array<압축원본행> = []344
for 노드 in 구조.노드들 {345
let mut 모서리 = 0346
while 모서리 < 2 {347
let 행필드 = if 모서리 == 0 { "startRow" } else { "endRow" }348
let 열필드 = if 모서리 == 0 { "startColumn" } else { "endColumn" }349
let 오프셋 = if 모서리 == 0 { 노드.시작 } else { 노드.끝 }350
let 행스칼라 = 노드스칼라(노드, 행필드)351
let 열스칼라 = 노드스칼라(노드, 열필드)352
if 행스칼라.태그 != 3 || 열스칼라.태그 != 3 ||353
행스칼라.정수값 < 0 || 열스칼라.정수값 < 0 || 열스칼라.정수값 > 오프셋 {354
return Err("JS/TS 원본 행 기하가 틀립니다")355
}356
let 행 = 행스칼라.정수값357
let 행시작 = 오프셋 - 열스칼라.정수값358
let mut 찾음 = false359
for 기존 in 행들 {360
if 기존.행 == 행 {361
if 기존.시작 != 행시작 { return Err("한 원본 행의 시작 오프셋이 서로 다릅니다") }362
찾음 = true363
}364
}365
if !찾음 { 행들.push(압축원본행 { 행: 행, 시작: 행시작 }) }366
모서리 = 모서리 + 1367
}368
}369
let mut 왼쪽 = 0370
while 왼쪽 < 행들.length {371
let mut 오른쪽 = 왼쪽 + 1372
while 오른쪽 < 행들.length {373
if 행들[오른쪽].행 < 행들[왼쪽].행 {374
let 임시 = 행들[왼쪽]375
행들[왼쪽] = 행들[오른쪽]376
행들[오른쪽] = 임시377
}378
오른쪽 = 오른쪽 + 1379
}380
왼쪽 = 왼쪽 + 1381
}382
let mut 색인 = 1383
while 색인 < 행들.length {384
if 행들[색인].시작 <= 행들[색인 - 1].시작 {385
return Err("원본 행 시작 오프셋이 엄격히 증가하지 않습니다")386
}387
색인 = 색인 + 1388
}389
Ok(행들)390
}392
function 압축원본문자위치(393
행들: Array<압축원본행>,394
오프셋: int395
) -> Result<Array<int>, string> {396
let mut 아래 = -1397
let mut 위 = 행들.length398
while 아래 + 1 < 위 {399
let 가운데 = (아래 + 위) / 2400
if 행들[가운데].시작 <= 오프셋 { 아래 = 가운데 } else { 위 = 가운데 }401
}402
if 아래 < 0 { return Err("노드 오프셋이 첫 원본 행보다 앞섭니다") }403
Ok([행들[아래].행, 오프셋 - 행들[아래].시작])404
}406
function 구조스칼라필드정렬(값들: Array<구조스칼라>) -> Array<구조스칼라> {407
let mut 결과 = 값들408
let mut 왼쪽 = 0409
while 왼쪽 < 결과.length {410
let mut 오른쪽 = 왼쪽 + 1411
while 오른쪽 < 결과.length {412
if 결과[오른쪽].필드 < 결과[왼쪽].필드 {413
let 임시 = 결과[왼쪽]414
결과[왼쪽] = 결과[오른쪽]415
결과[오른쪽] = 임시416
}417
오른쪽 = 오른쪽 + 1418
}419
왼쪽 = 왼쪽 + 1420
}421
결과422
}424
function 구조인코드배열(구조: 구조입력) -> Result<Array<int>, string> {425
let 언어번호 = 구조언어번호(구조)426
let 압축기하 = 언어번호 == 1 || 언어번호 == 2427
구조입력검사(언어번호, 구조)?428
if 구조.분리본문키해시.scalars().length != 64 { return Err("분리 본문 키 해시 길이가 틀립니다") }429
let mut 자식모음: Array<string> = []430
let mut 스칼라필드모음: Array<string> = []431
let mut 스칼라문자키들: Array<string> = []432
for 노드 in 구조.노드들 {433
if 노드.자식필드있음 { 자식모음.push(노드.자식필드) }434
for 스칼라 in 노드.스칼라들 {435
if !압축기하 || !원본기하필드인가(스칼라.필드) {436
스칼라필드모음.push(스칼라.필드)437
if 스칼라.태그 == 5 || 스칼라.태그 == 6 {438
let 코드단위문자열 = 구조스칼라코드단위문자열(스칼라)?439
스칼라문자키들.push(코드단위문자열.키)440
}441
}442
}443
}444
let mut 원본행들: Array<압축원본행> = []445
if 압축기하 { 원본행들 = 압축원본행들(구조)? }446
let 자식사전 = 정렬고유(자식모음)447
let 스칼라필드사전 = 정렬고유(스칼라필드모음)448
let 스칼라문자사전 = 정렬고유(스칼라문자키들)449
let mut 내용 = 바이트배열로(Bytes.fromHex(구조.분리본문키해시)?)450
내용 = 가변정수쓰기(내용, 구조.노드들.length)451
내용 = 가변정수쓰기(내용, 구조.분리본문값수)452
if 압축기하 {453
내용 = 가변정수쓰기(내용, 원본행들.length)454
let mut 이전행 = -1455
let mut 이전시작 = 0456
for 행 in 원본행들 {457
내용 = 가변정수쓰기(내용, 행.행 - 이전행)458
내용 = 가변정수쓰기(내용, 행.시작 - 이전시작)459
이전행 = 행.행460
이전시작 = 행.시작461
}462
}463
내용 = 사전쓰기(내용, 자식사전)?464
내용 = 사전쓰기(내용, 스칼라필드사전)?465
내용 = 코드단위사전쓰기(내용, 스칼라문자사전)?466
let mut 순번 = 0467
let mut 스칼라문자순번 = 0468
for 노드 in 구조.노드들 {469
내용 = 가변정수쓰기(내용, 노드.코드워드)470
내용 = 가변정수쓰기(내용, if 노드.부모순번 < 0 { 0 } else { 순번 - 노드.부모순번 })471
내용 = 가변정수쓰기(내용, if 노드.자식필드있음 { 사전색인(자식사전, 노드.자식필드) + 1 } else { 0 })472
내용 = 가변정수쓰기(내용, if 노드.자식색인 < 0 { 0 } else { 노드.자식색인 + 1 })473
내용 = 가변정수쓰기(내용, 노드.시작)474
내용 = 가변정수쓰기(내용, 노드.끝)475
let mut 스칼라수 = 0476
for 스칼라 in 노드.스칼라들 {477
if !압축기하 || !원본기하필드인가(스칼라.필드) { 스칼라수 = 스칼라수 + 1 }478
}479
내용 = 가변정수쓰기(내용, 스칼라수)480
for 스칼라 in 노드.스칼라들 {481
if !압축기하 || !원본기하필드인가(스칼라.필드) {482
내용 = 가변정수쓰기(내용, 사전색인(스칼라필드사전, 스칼라.필드))483
내용.push(if 스칼라.태그 == 6 { 5 } else { 스칼라.태그 })484
if 스칼라.태그 == 3 || 스칼라.태그 == 4 { 내용 = 가변정수쓰기(내용, 스칼라.정수값) }485
else if 스칼라.태그 == 5 || 스칼라.태그 == 6 {486
if 스칼라문자순번 >= 스칼라문자키들.length {487
return Err("스칼라 문자열 키 캐시가 구조보다 짧습니다")488
}489
내용 = 가변정수쓰기(490
내용,491
사전색인(스칼라문자사전, 스칼라문자키들[스칼라문자순번])492
)493
스칼라문자순번 = 스칼라문자순번 + 1494
}495
}496
}497
if 노드.식별자있음 { 내용 = 가변정수쓰기(내용, 노드.식별자류번호) }498
순번 = 순번 + 1499
}500
if 스칼라문자순번 != 스칼라문자키들.length {501
return Err("스칼라 문자열 키 캐시가 구조보다 깁니다")502
}503
let 구조버전 = if 언어번호 == 1 || 언어번호 == 2 { 4 } else { 1 }504
let mut 본문 = [67, 73, 70, 83, 구조버전, 1, 0, 0]505
본문 = 삼십이쓰기(본문, 16 + 내용.length + 32)506
본문 = 삼십이쓰기(본문, 내용.length)507
본문 = 바이트추가(본문, 내용)508
let 결과 = 바이트추가(본문, 해시배열(본문))509
Ok(결과)510
}512
export function 구조인코드(입력: string) -> Result<Bytes, string> {513
let 구조 = JSON.parseAs<구조입력>(입력)?514
바이트로(구조인코드배열(구조)?)515
}517
export function 구조디코드(와이어: Bytes, 식별자표: Array<bool>) -> Result<string, string> {518
let 전체 = 바이트배열로(와이어)519
if 전체.length < 48 { return Err("구조 와이어가 잘렸습니다") }520
if 전체.length > 2097152 { return Err("구조 와이어가 허용량을 넘습니다") }521
let 본문 = 부분배열(전체, 0, 전체.length - 32)522
let 실제해시 = 부분배열(전체, 전체.length - 32, 전체.length)523
if !배열같음(실제해시, 해시배열(본문)) { return Err("구조 와이어 검사합이 맞지 않습니다") }524
if 본문[0] != 67 || 본문[1] != 73 || 본문[2] != 70 || 본문[3] != 83 { return Err("구조 와이어 마법값이 틀립니다") }525
if (본문[4] != 1 && 본문[4] != 4) || 본문[5] != 1 || 본문[6] != 0 || 본문[7] != 0 {526
return Err("구조 와이어 버전이 틀립니다")527
}528
let 와이어버전 = 본문[4]529
if 삼십이읽기(본문, 8) != 전체.length || 삼십이읽기(본문, 12) != 본문.length - 16 { return Err("구조 와이어 길이가 틀립니다") }530
let mut 위치 = 16531
let 해시끝 = 위치 + 32532
let 분리본문키바이트 = 바이트로(부분배열(본문, 위치, 해시끝))?533
let 분리본문키해시 = 분리본문키바이트.toHex()534
위치 = 해시끝535
let 노드수읽기 = 가변정수읽기(본문, 위치)?; 위치 = 노드수읽기.다음536
let 본문수읽기 = 가변정수읽기(본문, 위치)?; 위치 = 본문수읽기.다음537
if 식별자표.length != 노드수읽기.값 { return Err("식별자 표 길이가 노드 수와 다릅니다") }538
let mut 원본행들: Array<압축원본행> = []539
if 와이어버전 == 4 {540
let 행수읽기 = 가변정수읽기(본문, 위치)?; 위치 = 행수읽기.다음541
if 행수읽기.값 == 0 || 행수읽기.값 > 노드수읽기.값 * 2 {542
return Err("원본 행 수가 허용량을 넘습니다")543
}544
let mut 이전행 = -1545
let mut 이전시작 = 0546
let mut 행색인 = 0547
while 행색인 < 행수읽기.값 {548
let 행차 = 가변정수읽기(본문, 위치)?; 위치 = 행차.다음549
let 시작차 = 가변정수읽기(본문, 위치)?; 위치 = 시작차.다음550
if 행차.값 == 0 || (행색인 > 0 && 시작차.값 == 0) {551
return Err("원본 행들이 엄격히 증가하지 않습니다")552
}553
let 행 = 이전행 + 행차.값554
let 시작 = 이전시작 + 시작차.값555
원본행들.push(압축원본행 { 행: 행, 시작: 시작 })556
이전행 = 행557
이전시작 = 시작558
행색인 = 행색인 + 1559
}560
}561
let 자식읽기 = 사전해석(본문, 위치)?; 위치 = 자식읽기.다음562
let 필드읽기 = 사전해석(본문, 위치)?; 위치 = 필드읽기.다음563
if 와이어버전 == 4 {564
for 필드 in 필드읽기.값들 {565
if 원본기하필드인가(필드) { return Err("원본 기하가 스칼라 사전에 중복되었습니다") }566
}567
}568
let 문자읽기 = 코드단위사전해석(본문, 위치)?; 위치 = 문자읽기.다음569
let mut 노드들: Array<구조노드> = []570
let mut 순번 = 0571
while 순번 < 노드수읽기.값 {572
let 코드 = 가변정수읽기(본문, 위치)?; 위치 = 코드.다음573
let 부모차 = 가변정수읽기(본문, 위치)?; 위치 = 부모차.다음574
let 자식필드코드 = 가변정수읽기(본문, 위치)?; 위치 = 자식필드코드.다음575
let 자식색인코드 = 가변정수읽기(본문, 위치)?; 위치 = 자식색인코드.다음576
let 시작읽기 = 가변정수읽기(본문, 위치)?; 위치 = 시작읽기.다음577
let 끝읽기 = 가변정수읽기(본문, 위치)?; 위치 = 끝읽기.다음578
let 스칼라수 = 가변정수읽기(본문, 위치)?; 위치 = 스칼라수.다음579
if 자식필드코드.값 > 자식읽기.값들.length { return Err("자식 필드 사전 색인이 틀립니다") }580
let mut 스칼라들: Array<구조스칼라> = []581
let mut 스칼라색인 = 0582
let mut 이전필드 = -1583
while 스칼라색인 < 스칼라수.값 {584
let 필드색인 = 가변정수읽기(본문, 위치)?; 위치 = 필드색인.다음585
if 필드색인.값 >= 필드읽기.값들.length || 필드색인.값 <= 이전필드 { return Err("스칼라 필드가 정규 순서가 아닙니다") }586
이전필드 = 필드색인.값587
if 위치 >= 본문.length { return Err("스칼라 태그가 잘렸습니다") }588
let 태그 = 본문[위치]; 위치 = 위치 + 1589
let mut 호스트태그 = 태그590
let mut 정수값 = 0591
let mut 문자열값 = ""592
if 태그 == 3 || 태그 == 4 {593
let 정수읽기값 = 가변정수읽기(본문, 위치)?; 위치 = 정수읽기값.다음594
정수값 = 정수읽기값.값595
if 태그 == 4 && 정수값 == 0 { return Err("음수 영은 허용되지 않습니다") }596
} else if 태그 == 5 {597
let 문자열색인 = 가변정수읽기(본문, 위치)?; 위치 = 문자열색인.다음598
if 문자열색인.값 >= 문자읽기.값들.length { return Err("스칼라 문자열 사전 색인이 틀립니다") }599
let 문자값 = 문자읽기.값들[문자열색인.값]600
if 문자값.안전 { 문자열값 = 문자값.안전값 }601
else { 호스트태그 = 6; 문자열값 = 문자값.키 }602
} else if 태그 < 0 || 태그 > 2 { return Err("스칼라 태그가 틀립니다") }603
스칼라들.push(구조스칼라 {604
필드: 필드읽기.값들[필드색인.값], 태그: 호스트태그,605
정수값: 정수값, 문자열값: 문자열값606
})607
스칼라색인 = 스칼라색인 + 1608
}609
if 와이어버전 == 4 {610
let 시작기하 = 압축원본문자위치(원본행들, 시작읽기.값)?611
let 끝기하 = 압축원본문자위치(원본행들, 끝읽기.값)?612
스칼라들.push(구조스칼라 { 필드: "startRow", 태그: 3, 정수값: 시작기하[0], 문자열값: "" })613
스칼라들.push(구조스칼라 { 필드: "startColumn", 태그: 3, 정수값: 시작기하[1], 문자열값: "" })614
스칼라들.push(구조스칼라 { 필드: "endRow", 태그: 3, 정수값: 끝기하[0], 문자열값: "" })615
스칼라들.push(구조스칼라 { 필드: "endColumn", 태그: 3, 정수값: 끝기하[1], 문자열값: "" })616
스칼라들 = 구조스칼라필드정렬(스칼라들)617
}618
let 식별자있음 = 식별자표[순번]619
let mut 식별자류번호 = 0620
if 식별자있음 {621
let 식별자읽기 = 가변정수읽기(본문, 위치)?; 위치 = 식별자읽기.다음622
식별자류번호 = 식별자읽기.값623
}624
노드들.push(구조노드 {625
코드워드: 코드.값,626
부모순번: if 순번 == 0 { -1 } else { 순번 - 부모차.값 },627
자식필드있음: 자식필드코드.값 != 0,628
자식필드: if 자식필드코드.값 == 0 { "" } else { 자식읽기.값들[자식필드코드.값 - 1] },629
자식색인: if 자식색인코드.값 == 0 { -1 } else { 자식색인코드.값 - 1 },630
시작: 시작읽기.값,631
끝: 끝읽기.값,632
스칼라들: 스칼라들,633
식별자있음: 식별자있음,634
식별자류번호: 식별자류번호635
})636
순번 = 순번 + 1637
}638
if 위치 != 본문.length { return Err("구조 와이어 뒤에 바이트가 남았습니다") }639
let 구조 = 구조입력 { 분리본문키해시: 분리본문키해시, 분리본문값수: 본문수읽기.값, 노드들: 노드들 }640
let 언어번호 = 구조언어번호(구조)641
let 예상버전 = if 언어번호 == 1 || 언어번호 == 2 { 4 } else { 1 }642
if 와이어버전 != 예상버전 { return Err("구조 와이어 버전이 언어와 맞지 않습니다") }643
구조입력검사(언어번호, 구조)?644
if !배열같음(구조인코드배열(구조)?, 전체) { return Err("구조 와이어가 정규 인코딩이 아닙니다") }645
JSON.stringify(구조)646
}648
let 체다항식 = 285649
let 부호바이트수 = 255650
let 자료바이트수 = 223651
let 패리티바이트수 = 32653
// 갈루아 체 GF(256)의 곱셈표. 상수를 외워 적지 않고 원시원소 2를654
// 거듭제곱하며 지수표를 기른다. 값이 넘칠 때마다 체다항식으로 줄이면655
// 255걸음 만에 0을 제외한 모든 원소를 한 번씩 지난다. 지수표를 두 배656
// 길이로 이어 두면 로그 두 개의 합이 255를 넘어도 나머지 연산 없이657
// 바로 읽을 수 있다.658
function 갈루아표만들기() -> 갈루아표 {659
let mut 지수: Array<int> = []660
let mut 로그: Array<int> = []661
let mut 색인 = 0662
while 색인 < 512 { 지수.push(0); 색인 = 색인 + 1 }663
색인 = 0664
while 색인 < 256 { 로그.push(0); 색인 = 색인 + 1 }665
let mut 값 = 1666
색인 = 0667
while 색인 < 255 {668
지수[색인] = 값669
로그[값] = 색인670
값 = 값 * 2671
if 값 >= 256 { 값 = 비트배타합(값, 체다항식, 9) }672
색인 = 색인 + 1673
}674
while 색인 < 512 { 지수[색인] = 지수[색인 - 255]; 색인 = 색인 + 1 }675
갈루아표 { 지수: 지수, 로그: 로그 }676
}678
// 생성다항식은 일차식 (x - α^i)를 근 α^0부터 α^31까지 차례로 곱해679
// 자라난다. 서른두 개의 근이 서른두 바이트의 패리티를 만든다.680
function 생성다항식(표: 갈루아표) -> Array<int> {681
let mut 생성 = [1]682
let mut 근 = 0683
while 근 < 패리티바이트수 { 생성 = 다항식곱(생성, [1, 표.지수[근]], 표); 근 = 근 + 1 }684
생성685
}687
// 패리티는 다항식 나눗셈의 나머지다. 자료를 255칸 작업대의 앞 223칸에688
// 펼치고 위치마다 생성다항식 배수를 빼 나가면 앞쪽은 전부 지워지고689
// 마지막 서른두 칸에 나머지만 남는다.690
function 패리티(자료: Array<int>, 표: 갈루아표, 생성: Array<int>) -> Result<Array<int>, string> {691
if 자료.length != 자료바이트수 { return Err("리드 솔로몬 자료 조각은 223바이트여야 합니다") }692
let mut 작업: Array<int> = []693
let mut 색인 = 0694
while 색인 < 부호바이트수 { 작업.push(if 색인 < 자료바이트수 { 자료[색인] } else { 0 }); 색인 = 색인 + 1 }695
let mut 위치 = 0696
while 위치 < 자료바이트수 {697
let 계수 = 작업[위치]698
if 계수 != 0 {699
색인 = 0700
while 색인 < 생성.length {701
작업[위치 + 색인] = 비트배타합(작업[위치 + 색인], 갈루아곱(생성[색인], 계수, 표), 8)702
색인 = 색인 + 1703
}704
}705
위치 = 위치 + 1706
}707
Ok(부분배열(작업, 자료바이트수, 부호바이트수))708
}710
// 보호 방향은 승인된 기성 부호기가 맡는다. 해제 방향은 아래에서 같은711
// 수학을 열린 토파즈로 다시 유도해 검증하므로 읽는 사람이 두 방향의712
// 일치를 직접 확인할 수 있다.713
export function 리드솔로몬보호(논리: Bytes) -> Result<Bytes, string> {714
if 논리.length() == 0 { return Err("논리 와이어는 비어 있을 수 없습니다") }715
let 조각수 = (논리.length() + 자료바이트수 - 1) / 자료바이트수716
if 조각수 > 65535 { return Err("리드 솔로몬 조각 수가 너무 많습니다") }717
Codec.reedSolomon255223Protect(논리)718
}720
export function 리드솔로몬해제(보호: Bytes, 논리길이: int) -> Result<Bytes, string> {721
let 입력 = 바이트배열로(보호)722
if 입력.length == 0 || 입력.length % 부호바이트수 != 0 { return Err("보호 와이어가 조각 경계에 맞지 않습니다") }723
let 조각수 = 입력.length / 부호바이트수724
let 최대길이 = 조각수 * 자료바이트수725
if 논리길이 <= 0 || 논리길이 > 최대길이 || 논리길이 <= 최대길이 - 자료바이트수 { return Err("논리 길이가 정규 범위가 아닙니다") }726
let 표 = 갈루아표만들기()727
let 생성 = 생성다항식(표)728
let mut 자료전체: Array<int> = []729
let mut 조각 = 0730
while 조각 < 조각수 {731
let 시작 = 조각 * 부호바이트수732
let 자료 = 부분배열(입력, 시작, 시작 + 자료바이트수)733
let 실제 = 부분배열(입력, 시작 + 자료바이트수, 시작 + 부호바이트수)734
if !배열같음(패리티(자료, 표, 생성)?, 실제) { return Err("리드 솔로몬 패리티가 맞지 않습니다") }735
자료전체 = 바이트추가(자료전체, 자료)736
조각 = 조각 + 1737
}738
let mut 색인 = 논리길이739
while 색인 < 자료전체.length {740
if 자료전체[색인] != 0 { return Err("리드 솔로몬 채움 바이트가 영이 아닙니다") }741
색인 = 색인 + 1742
}743
바이트로(부분배열(자료전체, 0, 논리길이))744
}746
// 이미지 운반체. 큰 래스터는 바이트 배열로 펼치지 않고 좌표 함수로747
// 계산하여 불변 바이트 경계를 지킨다.749
record 이미지요청 {750
언어번호: int,751
팔레트번호: int,752
프로필해시: string,753
구조해시: string,754
키해시: string,755
크롬번호: int,756
제목: string,757
원본줄수: int,758
구조: 구조입력759
}761
record 준비된이미지요청 {762
요청: 이미지요청,763
구조: 준비된구조,764
논리: Bytes765
}767
record 준비된이미지계획 {768
요청: 준비된이미지요청,769
계획: 이미지계획770
}772
export record 이미지계획출력 {773
쪽수: int,774
세트해시: string,775
높이들: Array<int>,776
노드시작들: Array<int>,777
노드수들: Array<int>,778
논리길이들: Array<int>,779
보호길이들: Array<int>,780
패리티길이들: Array<int>781
}783
record 그림준비 {784
요청: 이미지요청,785
머리: 이미지머리,786
머리바이트: ByteBuffer,787
보호바이트: ByteBuffer,788
노드시작: int,789
노드끝: int,790
수직씻김: Array<int>,791
수평씻김: Array<int>,792
이역할: Array<int>,793
팔그물: Array<int>794
}795
record 주사그림 { 준비: 그림준비, 바이트들: ByteBuffer }797
function 요청검사(요청: 이미지요청) -> Result<준비된구조, string> {798
if 요청.언어번호 != 1 && 요청.언어번호 != 2 && 요청.언어번호 != 3 &&799
요청.언어번호 != 4 && 요청.언어번호 != 5 &&800
요청.언어번호 != 6 && 요청.언어번호 != 7 &&801
요청.언어번호 != 8 && 요청.언어번호 != 9 &&802
요청.언어번호 != 10 && 요청.언어번호 != 11 &&803
요청.언어번호 != 12 && 요청.언어번호 != 13 &&804
요청.언어번호 != 14 && 요청.언어번호 != 15 &&805
요청.언어번호 != 16 && 요청.언어번호 != 17 &&806
요청.언어번호 != 18 && 요청.언어번호 != 19 &&807
요청.언어번호 != 21 && 요청.언어번호 != 20 &&808
요청.언어번호 != 22 && 요청.언어번호 != 23 &&809
요청.언어번호 != 24 && 요청.언어번호 != 25 &&810
요청.언어번호 != 26 && 요청.언어번호 != 27 &&811
요청.언어번호 != 28 && 요청.언어번호 != 29 &&812
요청.언어번호 != 30 {813
return Err("지원하지 않는 언어입니다")814
}815
if 구조언어번호(요청.구조) != 요청.언어번호 { return Err("구조 뿌리의 언어가 이미지 요청과 다릅니다") }816
인쇄구조검사(요청.언어번호, 요청.구조)?817
if 요청.팔레트번호 != 요청.언어번호 || !이미지프로필해시맞음(요청.언어번호, 요청.프로필해시) {818
return Err("언어 팔레트 프로필이 맞지 않습니다")819
}820
if 요청.프로필해시.scalars().length != 64 || 요청.구조해시.scalars().length != 64 || 요청.키해시.scalars().length != 64 {821
return Err("이미지 해시 길이가 틀립니다")822
}823
if 요청.구조.분리본문키해시 != 요청.키해시 { return Err("구조와 키 해시가 다릅니다") }824
if 요청.구조.노드들.length == 0 { return Err("이미지는 파일 뿌리 노드가 필요합니다") }825
if 요청.크롬번호 < 0 || 요청.크롬번호 > 1 { return Err("크롬 번호가 틀립니다") }826
if 요청.크롬번호 == 0 && (요청.제목 != "" || 요청.원본줄수 != 0) { return Err("민무늬 크롬에 책 메타데이터가 있습니다") }827
let 제목바이트 = Bytes.encodeUtf8(요청.제목)828
if 제목바이트.length() > 24 { return Err("책 제목이 24바이트를 넘습니다") }829
for 글자 in 요청.제목.scalars() {830
if 픽셀글꼴(글자) == "" { return Err("책 제목에 없는 픽셀 글자가 있습니다") }831
}832
Ok(준비된구조 { 언어번호: 요청.언어번호, 구조: 요청.구조 })833
}835
function 이미지요청준비(요청글: string, 논리: Bytes) -> Result<준비된이미지요청, string> {836
let 요청 = JSON.parseAs<이미지요청>(요청글)?837
let 준비된구조값 = 요청검사(요청)?838
if 논리.length() <= 0 { return Err("구조 논리 와이어가 비었습니다") }839
Ok(준비된이미지요청 {840
요청: 요청,841
구조: 준비된구조값,842
논리: 논리843
})844
}846
function 조상또는자신(노드들: Array<구조노드>, 순번: int, 조상: int) -> bool {847
let mut 현재 = 순번848
while 현재 >= 0 {849
if 현재 == 조상 { return true }850
현재 = 노드들[현재].부모순번851
}852
false853
}855
function 범위깊이(노드들: Array<구조노드>, 언어번호: int, 순번: int) -> int {856
let mut 깊이 = 0857
let mut 현재 = 순번858
while 현재 >= 0 {859
let 노드 = 노드들[현재]860
if 범위코드(언어번호, 노드.코드워드) && !파일프로그램코드(언어번호, 노드.코드워드) { 깊이 = 깊이 + 1 }861
현재 = 노드.부모순번862
}863
깊이864
}866
function 선호행경계(요청: 이미지요청) -> Array<int> {867
let 노드들 = 요청.구조.노드들868
let mut 경계들: Array<int> = []869
let mut 순번 = 0870
while 순번 < 노드들.length {871
let 노드 = 노드들[순번]872
if 범위코드(요청.언어번호, 노드.코드워드) && !파일프로그램코드(요청.언어번호, 노드.코드워드) {873
let mut 끝 = 순번874
let mut 살피기 = 순번 + 1875
while 살피기 < 노드들.length && 조상또는자신(노드들, 살피기, 순번) { 끝 = 살피기; 살피기 = 살피기 + 1 }876
if (끝 + 1) % 12 == 0 { 경계들.push((끝 + 1) / 12) }877
}878
순번 = 순번 + 1879
}880
경계들881
}883
function 이미지세트해시계산(요청: 이미지요청, 논리: Bytes, 쪽들: Array<이미지쪽계획>) -> Result<string, string> {884
let 크롬글 = if 요청.크롬번호 == 1 { "book" } else { "plain" }885
let 논리해시바이트 = 해시이백오십육(논리)?886
let 논리해시 = 논리해시바이트.toHex()887
let 투영 = "\{" + JSON.stringify("chromePreset")? + ":" + JSON.stringify(크롬글)? +888
"," + JSON.stringify("detachedTextKeySha256")? + ":" + JSON.stringify("sha256:" + 요청.키해시)? +889
"," + JSON.stringify("domain")? + ":" + JSON.stringify("codeimage.js-total-format.v2.pageset")? +890
"," + JSON.stringify("pages")? + ":" + 쪽투영문자열(쪽들)? +891
"," + JSON.stringify("sourceLineCount")? + ":" + "{요청.원본줄수}" +892
"," + JSON.stringify("structureDigest")? + ":" + JSON.stringify("sha256:" + 요청.구조해시)? +893
"," + JSON.stringify("structureLogicalSha256")? + ":" + JSON.stringify("sha256:" + 논리해시)? +894
"," + JSON.stringify("title")? + ":" + JSON.stringify(요청.제목)? + "\}"895
let 세트해시바이트 = 해시이백오십육(Bytes.encodeUtf8(투영))?896
Ok(세트해시바이트.toHex())897
}899
function 이미지계획준비(준비된요청: 준비된이미지요청) -> Result<준비된이미지계획, string> {900
let 요청 = 준비된요청.요청901
let 논리 = 준비된요청.논리902
let 전체행수 = (요청.구조.노드들.length + 11) / 12903
let 선호 = 선호행경계(요청)904
let 꼬리 = if 요청.크롬번호 == 1 { 64 } else { 24 }905
let mut 쪽수 = 1906
while 쪽수 <= 32 {907
let mut 논리시작들: Array<int> = []908
let mut 논리끝들: Array<int> = []909
let mut 보호길이들: Array<int> = []910
let mut 용량들: Array<int> = []911
let mut 유효 = true912
let mut 쪽번호 = 0913
while 쪽번호 < 쪽수 {914
let 시작 = (논리.length() * 쪽번호) / 쪽수915
let 끝 = (논리.length() * (쪽번호 + 1)) / 쪽수916
if 끝 <= 시작 { 유효 = false }917
let 길이 = 보호길이(끝 - 시작)918
let 띠행수 = 큰값(1, (길이 + 161) / 162)919
let 용량 = (2800 - (89 + 꼬리) - 띠행수 * 2) / 36920
if 용량 < 1 { 유효 = false }921
논리시작들.push(시작); 논리끝들.push(끝); 보호길이들.push(길이); 용량들.push(용량)922
쪽번호 = 쪽번호 + 1923
}924
let mut 용량합 = 0925
for 용량 in 용량들 { 용량합 = 용량합 + 용량 }926
if 유효 && 용량합 >= 전체행수 {927
let mut 행경계 = [0]928
let mut 행시작 = 0929
쪽번호 = 0930
while 쪽번호 < 쪽수 - 1 {931
let mut 남은용량 = 0932
let mut 다음 = 쪽번호 + 1933
while 다음 < 쪽수 { 남은용량 = 남은용량 + 용량들[다음]; 다음 = 다음 + 1 }934
let 최소끝 = 큰값(행시작 + 1, 전체행수 - 남은용량)935
let 최대끝 = 작은값(행시작 + 용량들[쪽번호], 전체행수 - (쪽수 - 쪽번호 - 1))936
if 최소끝 > 최대끝 { 유효 = false }937
let mut 행끝 = 최대끝938
let mut 후보 = 최대끝939
while 후보 >= 최소끝 {940
if 배열에있음(선호, 후보) { 행끝 = 후보; 후보 = 최소끝 - 1 }941
else { 후보 = 후보 - 1 }942
}943
행경계.push(행끝)944
행시작 = 행끝945
쪽번호 = 쪽번호 + 1946
}947
if 유효 {948
행경계.push(전체행수)949
let mut 쪽들: Array<이미지쪽계획> = []950
쪽번호 = 0951
while 쪽번호 < 쪽수 {952
let 노드시작 = 행경계[쪽번호] * 12953
let 노드끝 = 작은값(요청.구조.노드들.length, 행경계[쪽번호 + 1] * 12)954
let 배치 = 이미지배치계산(노드끝 - 노드시작, 보호길이들[쪽번호], 요청.크롬번호)?955
쪽들.push(이미지쪽계획 {956
쪽번호: 쪽번호, 노드시작: 노드시작, 노드끝: 노드끝,957
논리시작: 논리시작들[쪽번호], 논리끝: 논리끝들[쪽번호],958
보호길이: 보호길이들[쪽번호], 패리티길이: (보호길이들[쪽번호] / 255) * 32,959
배치: 배치960
})961
쪽번호 = 쪽번호 + 1962
}963
let 세트해시 = 이미지세트해시계산(요청, 논리, 쪽들)?964
return Ok(준비된이미지계획 {965
요청: 준비된요청,966
계획: 이미지계획 { 쪽들: 쪽들, 세트해시: 세트해시 }967
})968
}969
}970
쪽수 = 쪽수 + 1971
}972
Err("이미지 세트가 32쪽 한계를 넘습니다")973
}975
export function 이미지계획하기(요청글: string, 논리: Bytes) -> Result<string, string> {976
let 준비된요청 = 이미지요청준비(요청글, 논리)?977
let 준비된계획 = 이미지계획준비(준비된요청)?978
let 계획 = 준비된계획.계획979
let mut 높이들: Array<int> = []980
let mut 노드시작들: Array<int> = []981
let mut 노드수들: Array<int> = []982
let mut 논리길이들: Array<int> = []983
let mut 보호길이들: Array<int> = []984
let mut 패리티길이들: Array<int> = []985
for 쪽 in 계획.쪽들 {986
높이들.push(쪽.배치.높이); 노드시작들.push(쪽.노드시작); 노드수들.push(쪽.노드끝 - 쪽.노드시작)987
논리길이들.push(쪽.논리끝 - 쪽.논리시작); 보호길이들.push(쪽.보호길이); 패리티길이들.push(쪽.패리티길이)988
}989
JSON.stringify(이미지계획출력 {990
쪽수: 계획.쪽들.length, 세트해시: 계획.세트해시, 높이들: 높이들,991
노드시작들: 노드시작들, 노드수들: 노드수들, 논리길이들: 논리길이들,992
보호길이들: 보호길이들, 패리티길이들: 패리티길이들993
})994
}996
function 이미지계획복원(997
준비된요청: 준비된이미지요청,998
출력: 이미지계획출력999
) -> Result<준비된이미지계획, string> {1000
let 요청 = 준비된요청.요청SHA256 5837108d966f4fd9a31fbf7d80441b872e10bd332aef3cc2b1dbaa9329623280