2 * Copyright 2008 ZXing authors
\r
4 * Licensed under the Apache License, Version 2.0 (the "License");
\r
5 * you may not use this file except in compliance with the License.
\r
6 * You may obtain a copy of the License at
\r
8 * http://www.apache.org/licenses/LICENSE-2.0
\r
10 * Unless required by applicable law or agreed to in writing, software
\r
11 * distributed under the License is distributed on an "AS IS" BASIS,
\r
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
\r
13 * See the License for the specific language governing permissions and
\r
14 * limitations under the License.
\r
17 using WriterException = com.google.zxing.WriterException;
\r
18 using EncodeHintType = com.google.zxing.EncodeHintType;
\r
19 using ByteArray = com.google.zxing.common.ByteArray;
\r
20 using ByteMatrix = com.google.zxing.common.ByteMatrix;
\r
21 using CharacterSetECI = com.google.zxing.common.CharacterSetECI;
\r
22 using GF256 = com.google.zxing.common.reedsolomon.GF256;
\r
23 using ReedSolomonEncoder = com.google.zxing.common.reedsolomon.ReedSolomonEncoder;
\r
24 using ErrorCorrectionLevel = com.google.zxing.qrcode.decoder.ErrorCorrectionLevel;
\r
25 using Mode = com.google.zxing.qrcode.decoder.Mode;
\r
26 using Version = com.google.zxing.qrcode.decoder.Version;
\r
27 namespace com.google.zxing.qrcode.encoder
\r
30 /// <author> satorux@google.com (Satoru Takabayashi) - creator
\r
32 /// <author> dswitkin@google.com (Daniel Switkin) - ported from C++
\r
34 /// <author>www.Redivivus.in (suraj.supekar@redivivus.in) - Ported from ZXING Java Source
\r
36 public sealed class Encoder
\r
39 // The original table is defined in the table 5 of JISX0510:2004 (p.19).
\r
40 //UPGRADE_NOTE: Final was removed from the declaration of 'ALPHANUMERIC_TABLE'. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1003'"
\r
41 private static readonly int[] ALPHANUMERIC_TABLE = new int[]{- 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, 36, - 1, - 1, - 1, 37, 38, - 1, - 1, - 1, - 1, 39, 40, - 1, 41, 42, 43, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 44, - 1, - 1, - 1, - 1, - 1, - 1, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, - 1, - 1, - 1, - 1, - 1};
\r
43 internal const System.String DEFAULT_BYTE_MODE_ENCODING = "ISO-8859-1";
\r
49 // The mask penalty calculation is complicated. See Table 21 of JISX0510:2004 (p.45) for details.
\r
50 // Basically it applies four rules and summate all penalties.
\r
51 private static int calculateMaskPenalty(ByteMatrix matrix)
\r
54 penalty += MaskUtil.applyMaskPenaltyRule1(matrix);
\r
55 penalty += MaskUtil.applyMaskPenaltyRule2(matrix);
\r
56 penalty += MaskUtil.applyMaskPenaltyRule3(matrix);
\r
57 penalty += MaskUtil.applyMaskPenaltyRule4(matrix);
\r
61 /// <summary> Encode "bytes" with the error correction level "ecLevel". The encoding mode will be chosen
\r
62 /// internally by chooseMode(). On success, store the result in "qrCode".
\r
64 /// We recommend you to use QRCode.EC_LEVEL_L (the lowest level) for
\r
65 /// "getECLevel" since our primary use is to show QR code on desktop screens. We don't need very
\r
66 /// strong error correction for this purpose.
\r
68 /// Note that there is no way to encode bytes in MODE_KANJI. We might want to add EncodeWithMode()
\r
69 /// with which clients can specify the encoding mode. For now, we don't need the functionality.
\r
71 public static void encode(System.String content, ErrorCorrectionLevel ecLevel, QRCode qrCode)
\r
73 encode(content, ecLevel, null, qrCode);
\r
76 public static void encode(System.String content, ErrorCorrectionLevel ecLevel, System.Collections.Hashtable hints, QRCode qrCode)
\r
79 System.String encoding = hints == null?null:(System.String) hints[EncodeHintType.CHARACTER_SET];
\r
80 if (encoding == null)
\r
82 encoding = DEFAULT_BYTE_MODE_ENCODING;
\r
85 // Step 1: Choose the mode (encoding).
\r
86 Mode mode = chooseMode(content, encoding);
\r
88 // Step 2: Append "bytes" into "dataBits" in appropriate encoding.
\r
89 BitVector dataBits = new BitVector();
\r
90 appendBytes(content, mode, dataBits, encoding);
\r
91 // Step 3: Initialize QR code that can contain "dataBits".
\r
92 int numInputBytes = dataBits.sizeInBytes();
\r
93 initQRCode(numInputBytes, ecLevel, mode, qrCode);
\r
95 // Step 4: Build another bit vector that contains header and data.
\r
96 BitVector headerAndDataBits = new BitVector();
\r
98 // Step 4.5: Append ECI message if applicable
\r
99 if (mode == Mode.BYTE && !DEFAULT_BYTE_MODE_ENCODING.Equals(encoding))
\r
101 CharacterSetECI eci = CharacterSetECI.getCharacterSetECIByName(encoding);
\r
104 appendECI(eci, headerAndDataBits);
\r
108 appendModeInfo(mode, headerAndDataBits);
\r
110 int numLetters = mode.Equals(Mode.BYTE)?dataBits.sizeInBytes():content.Length;
\r
111 appendLengthInfo(numLetters, qrCode.Version, mode, headerAndDataBits);
\r
112 headerAndDataBits.appendBitVector(dataBits);
\r
114 // Step 5: Terminate the bits properly.
\r
115 terminateBits(qrCode.NumDataBytes, headerAndDataBits);
\r
117 // Step 6: Interleave data bits with error correction code.
\r
118 BitVector finalBits = new BitVector();
\r
119 interleaveWithECBytes(headerAndDataBits, qrCode.NumTotalBytes, qrCode.NumDataBytes, qrCode.NumRSBlocks, finalBits);
\r
121 // Step 7: Choose the mask pattern and set to "qrCode".
\r
122 ByteMatrix matrix = new ByteMatrix(qrCode.MatrixWidth, qrCode.MatrixWidth);
\r
123 qrCode.MaskPattern = chooseMaskPattern(finalBits, qrCode.ECLevel, qrCode.Version, matrix);
\r
125 // Step 8. Build the matrix and set it to "qrCode".
\r
126 MatrixUtil.buildMatrix(finalBits, qrCode.ECLevel, qrCode.Version, qrCode.MaskPattern, matrix);
\r
127 qrCode.Matrix = matrix;
\r
128 // Step 9. Make sure we have a valid QR Code.
\r
131 throw new WriterException("Invalid QR code: " + qrCode.ToString());
\r
135 /// <returns> the code point of the table used in alphanumeric mode or
\r
136 /// -1 if there is no corresponding code in the table.
\r
138 internal static int getAlphanumericCode(int code)
\r
140 if (code < ALPHANUMERIC_TABLE.Length)
\r
142 return ALPHANUMERIC_TABLE[code];
\r
147 public static Mode chooseMode(System.String content)
\r
149 return chooseMode(content, null);
\r
152 /// <summary> Choose the best mode by examining the content. Note that 'encoding' is used as a hint;
\r
153 /// if it is Shift_JIS, and the input is only double-byte Kanji, then we return {@link Mode#KANJI}.
\r
155 public static Mode chooseMode(System.String content, System.String encoding)
\r
157 if ("Shift_JIS".Equals(encoding))
\r
159 // Choose Kanji mode if all input are double-byte characters
\r
160 return isOnlyDoubleByteKanji(content)?Mode.KANJI:Mode.BYTE;
\r
162 bool hasNumeric = false;
\r
163 bool hasAlphanumeric = false;
\r
164 for (int i = 0; i < content.Length; ++i)
\r
166 char c = content[i];
\r
167 if (c >= '0' && c <= '9')
\r
171 else if (getAlphanumericCode(c) != - 1)
\r
173 hasAlphanumeric = true;
\r
180 if (hasAlphanumeric)
\r
182 return Mode.ALPHANUMERIC;
\r
184 else if (hasNumeric)
\r
186 return Mode.NUMERIC;
\r
191 private static bool isOnlyDoubleByteKanji(System.String content)
\r
196 //UPGRADE_TODO: Method 'java.lang.String.getBytes' was converted to 'System.Text.Encoding.GetEncoding(string).GetBytes(string)' which has a different behavior. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1073_javalangStringgetBytes_javalangString'"
\r
197 bytes = SupportClass.ToSByteArray(System.Text.Encoding.GetEncoding("Shift_JIS").GetBytes(content));
\r
199 catch (System.IO.IOException uee)
\r
203 int length = bytes.Length;
\r
204 if (length % 2 != 0)
\r
208 for (int i = 0; i < length; i += 2)
\r
210 int byte1 = bytes[i] & 0xFF;
\r
211 if ((byte1 < 0x81 || byte1 > 0x9F) && (byte1 < 0xE0 || byte1 > 0xEB))
\r
219 private static int chooseMaskPattern(BitVector bits, ErrorCorrectionLevel ecLevel, int version, ByteMatrix matrix)
\r
222 int minPenalty = System.Int32.MaxValue; // Lower penalty is better.
\r
223 int bestMaskPattern = - 1;
\r
224 // We try all mask patterns to choose the best one.
\r
225 for (int maskPattern = 0; maskPattern < QRCode.NUM_MASK_PATTERNS; maskPattern++)
\r
227 MatrixUtil.buildMatrix(bits, ecLevel, version, maskPattern, matrix);
\r
228 int penalty = calculateMaskPenalty(matrix);
\r
229 if (penalty < minPenalty)
\r
231 minPenalty = penalty;
\r
232 bestMaskPattern = maskPattern;
\r
235 return bestMaskPattern;
\r
238 /// <summary> Initialize "qrCode" according to "numInputBytes", "ecLevel", and "mode". On success,
\r
239 /// modify "qrCode".
\r
241 private static void initQRCode(int numInputBytes, ErrorCorrectionLevel ecLevel, Mode mode, QRCode qrCode)
\r
243 qrCode.ECLevel = ecLevel;
\r
244 qrCode.Mode = mode;
\r
246 // In the following comments, we use numbers of Version 7-H.
\r
247 for (int versionNum = 1; versionNum <= 40; versionNum++)
\r
249 Version version = Version.getVersionForNumber(versionNum);
\r
251 int numBytes = version.TotalCodewords;
\r
252 // getNumECBytes = 130
\r
253 Version.ECBlocks ecBlocks = version.getECBlocksForLevel(ecLevel);
\r
254 int numEcBytes = ecBlocks.TotalECCodewords;
\r
255 // getNumRSBlocks = 5
\r
256 int numRSBlocks = ecBlocks.NumBlocks;
\r
257 // getNumDataBytes = 196 - 130 = 66
\r
258 int numDataBytes = numBytes - numEcBytes;
\r
259 // We want to choose the smallest version which can contain data of "numInputBytes" + some
\r
260 // extra bits for the header (mode info and length info). The header can be three bytes
\r
261 // (precisely 4 + 16 bits) at most. Hence we do +3 here.
\r
262 if (numDataBytes >= numInputBytes + 3)
\r
264 // Yay, we found the proper rs block info!
\r
265 qrCode.Version = versionNum;
\r
266 qrCode.NumTotalBytes = numBytes;
\r
267 qrCode.NumDataBytes = numDataBytes;
\r
268 qrCode.NumRSBlocks = numRSBlocks;
\r
269 // getNumECBytes = 196 - 66 = 130
\r
270 qrCode.NumECBytes = numEcBytes;
\r
271 // matrix width = 21 + 6 * 4 = 45
\r
272 qrCode.MatrixWidth = version.DimensionForVersion;
\r
276 throw new WriterException("Cannot find proper rs block info (input data too big?)");
\r
279 /// <summary> Terminate bits as described in 8.4.8 and 8.4.9 of JISX0510:2004 (p.24).</summary>
\r
280 internal static void terminateBits(int numDataBytes, BitVector bits)
\r
282 int capacity = numDataBytes << 3;
\r
283 if (bits.size() > capacity)
\r
285 throw new WriterException("data bits cannot fit in the QR Code" + bits.size() + " > " + capacity);
\r
287 // Append termination bits. See 8.4.8 of JISX0510:2004 (p.24) for details.
\r
288 // TODO: srowen says we can remove this for loop, since the 4 terminator bits are optional if
\r
289 // the last byte has less than 4 bits left. So it amounts to padding the last byte with zeroes
\r
291 for (int i = 0; i < 4 && bits.size() < capacity; ++i)
\r
295 int numBitsInLastByte = bits.size() % 8;
\r
296 // If the last byte isn't 8-bit aligned, we'll add padding bits.
\r
297 if (numBitsInLastByte > 0)
\r
299 int numPaddingBits = 8 - numBitsInLastByte;
\r
300 for (int i = 0; i < numPaddingBits; ++i)
\r
305 // Should be 8-bit aligned here.
\r
306 if (bits.size() % 8 != 0)
\r
308 throw new WriterException("Number of bits is not a multiple of 8");
\r
310 // If we have more space, we'll fill the space with padding patterns defined in 8.4.9 (p.24).
\r
311 int numPaddingBytes = numDataBytes - bits.sizeInBytes();
\r
312 for (int i = 0; i < numPaddingBytes; ++i)
\r
316 bits.appendBits(0xec, 8);
\r
320 bits.appendBits(0x11, 8);
\r
323 if (bits.size() != capacity)
\r
325 throw new WriterException("Bits size does not equal capacity");
\r
329 /// <summary> Get number of data bytes and number of error correction bytes for block id "blockID". Store
\r
330 /// the result in "numDataBytesInBlock", and "numECBytesInBlock". See table 12 in 8.5.1 of
\r
331 /// JISX0510:2004 (p.30)
\r
333 internal static void getNumDataBytesAndNumECBytesForBlockID(int numTotalBytes, int numDataBytes, int numRSBlocks, int blockID, int[] numDataBytesInBlock, int[] numECBytesInBlock)
\r
335 if (blockID >= numRSBlocks)
\r
337 throw new WriterException("Block ID too large");
\r
339 // numRsBlocksInGroup2 = 196 % 5 = 1
\r
340 int numRsBlocksInGroup2 = numTotalBytes % numRSBlocks;
\r
341 // numRsBlocksInGroup1 = 5 - 1 = 4
\r
342 int numRsBlocksInGroup1 = numRSBlocks - numRsBlocksInGroup2;
\r
343 // numTotalBytesInGroup1 = 196 / 5 = 39
\r
344 int numTotalBytesInGroup1 = numTotalBytes / numRSBlocks;
\r
345 // numTotalBytesInGroup2 = 39 + 1 = 40
\r
346 int numTotalBytesInGroup2 = numTotalBytesInGroup1 + 1;
\r
347 // numDataBytesInGroup1 = 66 / 5 = 13
\r
348 int numDataBytesInGroup1 = numDataBytes / numRSBlocks;
\r
349 // numDataBytesInGroup2 = 13 + 1 = 14
\r
350 int numDataBytesInGroup2 = numDataBytesInGroup1 + 1;
\r
351 // numEcBytesInGroup1 = 39 - 13 = 26
\r
352 int numEcBytesInGroup1 = numTotalBytesInGroup1 - numDataBytesInGroup1;
\r
353 // numEcBytesInGroup2 = 40 - 14 = 26
\r
354 int numEcBytesInGroup2 = numTotalBytesInGroup2 - numDataBytesInGroup2;
\r
357 if (numEcBytesInGroup1 != numEcBytesInGroup2)
\r
359 throw new WriterException("EC bytes mismatch");
\r
362 if (numRSBlocks != numRsBlocksInGroup1 + numRsBlocksInGroup2)
\r
364 throw new WriterException("RS blocks mismatch");
\r
366 // 196 = (13 + 26) * 4 + (14 + 26) * 1
\r
367 if (numTotalBytes != ((numDataBytesInGroup1 + numEcBytesInGroup1) * numRsBlocksInGroup1) + ((numDataBytesInGroup2 + numEcBytesInGroup2) * numRsBlocksInGroup2))
\r
369 throw new WriterException("Total bytes mismatch");
\r
372 if (blockID < numRsBlocksInGroup1)
\r
374 numDataBytesInBlock[0] = numDataBytesInGroup1;
\r
375 numECBytesInBlock[0] = numEcBytesInGroup1;
\r
379 numDataBytesInBlock[0] = numDataBytesInGroup2;
\r
380 numECBytesInBlock[0] = numEcBytesInGroup2;
\r
384 /// <summary> Interleave "bits" with corresponding error correction bytes. On success, store the result in
\r
385 /// "result". The interleave rule is complicated. See 8.6 of JISX0510:2004 (p.37) for details.
\r
387 internal static void interleaveWithECBytes(BitVector bits, int numTotalBytes, int numDataBytes, int numRSBlocks, BitVector result)
\r
390 // "bits" must have "getNumDataBytes" bytes of data.
\r
391 if (bits.sizeInBytes() != numDataBytes)
\r
393 throw new WriterException("Number of bits and data bytes does not match");
\r
396 // Step 1. Divide data bytes into blocks and generate error correction bytes for them. We'll
\r
397 // store the divided data bytes blocks and error correction bytes blocks into "blocks".
\r
398 int dataBytesOffset = 0;
\r
399 int maxNumDataBytes = 0;
\r
400 int maxNumEcBytes = 0;
\r
402 // Since, we know the number of reedsolmon blocks, we can initialize the vector with the number.
\r
403 System.Collections.ArrayList blocks = System.Collections.ArrayList.Synchronized(new System.Collections.ArrayList(numRSBlocks));
\r
405 for (int i = 0; i < numRSBlocks; ++i)
\r
407 int[] numDataBytesInBlock = new int[1];
\r
408 int[] numEcBytesInBlock = new int[1];
\r
409 getNumDataBytesAndNumECBytesForBlockID(numTotalBytes, numDataBytes, numRSBlocks, i, numDataBytesInBlock, numEcBytesInBlock);
\r
411 ByteArray dataBytes = new ByteArray();
\r
412 dataBytes.set_Renamed(bits.Array, dataBytesOffset, numDataBytesInBlock[0]);
\r
413 ByteArray ecBytes = generateECBytes(dataBytes, numEcBytesInBlock[0]);
\r
414 blocks.Add(new BlockPair(dataBytes, ecBytes));
\r
416 maxNumDataBytes = System.Math.Max(maxNumDataBytes, dataBytes.size());
\r
417 maxNumEcBytes = System.Math.Max(maxNumEcBytes, ecBytes.size());
\r
418 dataBytesOffset += numDataBytesInBlock[0];
\r
420 if (numDataBytes != dataBytesOffset)
\r
422 throw new WriterException("Data bytes does not match offset");
\r
425 // First, place data blocks.
\r
426 for (int i = 0; i < maxNumDataBytes; ++i)
\r
428 for (int j = 0; j < blocks.Count; ++j)
\r
430 ByteArray dataBytes = ((BlockPair) blocks[j]).DataBytes;
\r
431 if (i < dataBytes.size())
\r
433 result.appendBits(dataBytes.at(i), 8);
\r
437 // Then, place error correction blocks.
\r
438 for (int i = 0; i < maxNumEcBytes; ++i)
\r
440 for (int j = 0; j < blocks.Count; ++j)
\r
442 ByteArray ecBytes = ((BlockPair) blocks[j]).ErrorCorrectionBytes;
\r
443 if (i < ecBytes.size())
\r
445 result.appendBits(ecBytes.at(i), 8);
\r
449 if (numTotalBytes != result.sizeInBytes())
\r
452 throw new WriterException("Interleaving error: " + numTotalBytes + " and " + result.sizeInBytes() + " differ.");
\r
456 internal static ByteArray generateECBytes(ByteArray dataBytes, int numEcBytesInBlock)
\r
458 int numDataBytes = dataBytes.size();
\r
459 int[] toEncode = new int[numDataBytes + numEcBytesInBlock];
\r
460 for (int i = 0; i < numDataBytes; i++)
\r
462 toEncode[i] = dataBytes.at(i);
\r
464 new ReedSolomonEncoder(GF256.QR_CODE_FIELD).encode(toEncode, numEcBytesInBlock);
\r
466 ByteArray ecBytes = new ByteArray(numEcBytesInBlock);
\r
467 for (int i = 0; i < numEcBytesInBlock; i++)
\r
469 ecBytes.set_Renamed(i, toEncode[numDataBytes + i]);
\r
474 /// <summary> Append mode info. On success, store the result in "bits".</summary>
\r
475 internal static void appendModeInfo(Mode mode, BitVector bits)
\r
477 bits.appendBits(mode.Bits, 4);
\r
481 /// <summary> Append length info. On success, store the result in "bits".</summary>
\r
482 internal static void appendLengthInfo(int numLetters, int version, Mode mode, BitVector bits)
\r
484 int numBits = mode.getCharacterCountBits(Version.getVersionForNumber(version));
\r
485 if (numLetters > ((1 << numBits) - 1))
\r
487 throw new WriterException(numLetters + "is bigger than" + ((1 << numBits) - 1));
\r
489 bits.appendBits(numLetters, numBits);
\r
492 /// <summary> Append "bytes" in "mode" mode (encoding) into "bits". On success, store the result in "bits".</summary>
\r
493 internal static void appendBytes(System.String content, Mode mode, BitVector bits, System.String encoding)
\r
495 if (mode.Equals(Mode.NUMERIC))
\r
497 appendNumericBytes(content, bits);
\r
499 else if (mode.Equals(Mode.ALPHANUMERIC))
\r
501 appendAlphanumericBytes(content, bits);
\r
503 else if (mode.Equals(Mode.BYTE))
\r
505 append8BitBytes(content, bits, encoding);
\r
507 else if (mode.Equals(Mode.KANJI))
\r
509 appendKanjiBytes(content, bits);
\r
513 throw new WriterException("Invalid mode: " + mode);
\r
517 internal static void appendNumericBytes(System.String content, BitVector bits)
\r
519 int length = content.Length;
\r
523 int num1 = content[i] - '0';
\r
524 if (i + 2 < length)
\r
526 // Encode three numeric letters in ten bits.
\r
527 int num2 = content[i + 1] - '0';
\r
528 int num3 = content[i + 2] - '0';
\r
529 bits.appendBits(num1 * 100 + num2 * 10 + num3, 10);
\r
532 else if (i + 1 < length)
\r
534 // Encode two numeric letters in seven bits.
\r
535 int num2 = content[i + 1] - '0';
\r
536 bits.appendBits(num1 * 10 + num2, 7);
\r
541 // Encode one numeric letter in four bits.
\r
542 bits.appendBits(num1, 4);
\r
548 internal static void appendAlphanumericBytes(System.String content, BitVector bits)
\r
550 int length = content.Length;
\r
554 int code1 = getAlphanumericCode(content[i]);
\r
557 throw new WriterException();
\r
559 if (i + 1 < length)
\r
561 int code2 = getAlphanumericCode(content[i + 1]);
\r
564 throw new WriterException();
\r
566 // Encode two alphanumeric letters in 11 bits.
\r
567 bits.appendBits(code1 * 45 + code2, 11);
\r
572 // Encode one alphanumeric letter in six bits.
\r
573 bits.appendBits(code1, 6);
\r
579 internal static void append8BitBytes(System.String content, BitVector bits, System.String encoding)
\r
584 //UPGRADE_TODO: Method 'java.lang.String.getBytes' was converted to 'System.Text.Encoding.GetEncoding(string).GetBytes(string)' which has a different behavior. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1073_javalangStringgetBytes_javalangString'"
\r
585 bytes = SupportClass.ToSByteArray(System.Text.Encoding.GetEncoding(encoding).GetBytes(content));
\r
587 catch (System.IO.IOException uee)
\r
589 //UPGRADE_TODO: The equivalent in .NET for method 'java.lang.Throwable.toString' may return a different value. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1043'"
\r
590 throw new WriterException(uee.ToString());
\r
592 for (int i = 0; i < bytes.Length; ++i)
\r
594 bits.appendBits(bytes[i], 8);
\r
598 internal static void appendKanjiBytes(System.String content, BitVector bits)
\r
603 //UPGRADE_TODO: Method 'java.lang.String.getBytes' was converted to 'System.Text.Encoding.GetEncoding(string).GetBytes(string)' which has a different behavior. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1073_javalangStringgetBytes_javalangString'"
\r
604 bytes = SupportClass.ToSByteArray(System.Text.Encoding.GetEncoding("Shift_JIS").GetBytes(content));
\r
606 catch (System.IO.IOException uee)
\r
608 //UPGRADE_TODO: The equivalent in .NET for method 'java.lang.Throwable.toString' may return a different value. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1043'"
\r
609 throw new WriterException(uee.ToString());
\r
611 int length = bytes.Length;
\r
612 for (int i = 0; i < length; i += 2)
\r
614 int byte1 = bytes[i] & 0xFF;
\r
615 int byte2 = bytes[i + 1] & 0xFF;
\r
616 int code = (byte1 << 8) | byte2;
\r
617 int subtracted = - 1;
\r
618 if (code >= 0x8140 && code <= 0x9ffc)
\r
620 subtracted = code - 0x8140;
\r
622 else if (code >= 0xe040 && code <= 0xebbf)
\r
624 subtracted = code - 0xc140;
\r
626 if (subtracted == - 1)
\r
628 throw new WriterException("Invalid byte sequence");
\r
630 int encoded = ((subtracted >> 8) * 0xc0) + (subtracted & 0xff);
\r
631 bits.appendBits(encoded, 13);
\r
635 private static void appendECI(CharacterSetECI eci, BitVector bits)
\r
637 bits.appendBits(Mode.ECI.Bits, 4);
\r
638 // This is correct for values up to 127, which is all we need now.
\r
639 bits.appendBits(eci.Value, 8);
\r