# (DD22) Business Logic — JKKStringUtil.subStringByte() [24 LOC]

| Field | Value |
|-------|-------|
| Fully Qualified Name | `eo.common.util.JKKStringUtil` |
| Layer | Utility / Common Component |
| Module | `util` (Package: `eo.common.util`) |

## 1. Role

### JKKStringUtil.subStringByte()

The `subStringByte` method is a shared utility for **byte-length-constrained string truncation**, used throughout the KOP system to ensure that string values never exceed a specified byte length when stored or transmitted. This is a critical concern in enterprise Japanese business software where character encodings (typically EUC-JP or Shift_JIS) use 1 byte for ASCII/half-width characters and 2 bytes for full-width Kanji, Hiragana, Katakana, and other multi-byte characters.

The method implements a **character-by-character scanning pattern**, walking through each character of the input string, determining its byte width (1 or 2 bytes), accumulating a running byte count, and returning a truncated substring once the byte limit would be exceeded. It handles four classes of single-byte characters explicitly: ASCII range (U+0000–U+007E), backslash (U+005C), tilde (U+203E — overline), and half-width katakana (U+FF61–U+FF9F). All other characters (full-width letters, Kanji, Hiragana, full-width punctuation, symbols) are treated as 2-byte characters.

Its role in the larger system is that of a **defensive data boundary guard**: it is a pure function with no side effects, no external dependencies, and no state mutation. It is designed to be called by any component that needs to enforce byte-length constraints on string values before database insertion, network transmission, or display formatting. Since no callers were found within the current codebase scope, it may be invoked by components outside this repository or may be a legacy utility retained for API compatibility.

## 2. Processing Pattern (Detailed Business Logic)

```mermaid
flowchart TD
    START(["subStringByte\(str, len\): String"])
    INIT["dstlen = 0
i = 0"]
    CHECK_I["i < str.length\?"]
    CHAR_C["c = str.charAt\(i\)"]
    COND_SINGLE["c <= 0x7E or c == 0x5C or c == 0x203E or \(c >= 0xFF61 and c <= 0xFF9F\)"]
    INC_1["dstlen += 1"]
    INC_2["dstlen += 2"]
    COND_DST["dstlen > len\?"]
    RET_SUB["return str.substring\(0, i\)"]
    INC_I["i += 1"]
    RET_ORIG["return str"]
    END(["Return"])

    START --> INIT --> CHECK_I
    CHECK_I -->|true| CHAR_C --> COND_SINGLE
    COND_SINGLE -->|true| INC_1 --> COND_DST
    COND_SINGLE -->|false| INC_2 --> COND_DST
    COND_DST -->|yes| RET_SUB --> END
    COND_DST -->|no| INC_I --> CHECK_I
    CHECK_I -->|no| RET_ORIG --> END
```

## 3. Parameter Analysis

| No | Parameter Name | Type | Business Description |
|----|---------------|------|---------------------|
| 1 | `str` | `String` | The source string to truncate. Contains any mix of ASCII, half-width katakana, full-width characters, or multi-byte Japanese text. The string is the boundary input — its total byte width is compared against `len` to determine truncation. |
| 2 | `len` | `int` | The target byte length limit. Represents the maximum number of bytes the resulting string is allowed to occupy. Common use cases include truncating text to fit database column widths (e.g., VARCHAR(100)), fixed-width file formats, or UI display bounds. |

**External state / instance fields:** None. This method is fully stateless and relies solely on its two parameters.

## 4. CRUD Operations / Called Services

| CRUD | SC / CBS | SC Code | Entity / DB | Operation Description |
|------|----------|---------|-------------|----------------------|
| N/A | `str.length()` | — | — | String method: returns the character count of the input string (not a database operation). |
| N/A | `str.charAt(i)` | — | — | String method: retrieves the character at position `i` (not a database operation). |
| N/A | `str.substring(0, i)` | — | — | String method: extracts the substring from index 0 to `i` exclusive (not a database operation). |

This method performs **no database operations, no service component calls, and no entity manipulation**. It is a pure computation utility.

## 5. Dependency Trace

| # | Caller (Screen/Batch) | Call Chain (Full Path to this Method) | Terminal (SC / CRUD / Entity) |
|---|----------------------|--------------------------------------|-------------------------------|
| 1 | N/A | *(No callers found within codebase scope)* | *(none)* |

**Note:** `subStringByte` is declared as a `public static` method on `JKKStringUtil`, indicating it is designed as a shared utility callable from anywhere. However, no callers were found within the scanned codebase (107 Java files). It may be used by components in other modules, referenced by legacy code outside this repository, or retained as part of the public API contract for downstream consumers.

### Reverse Dependencies (Downstream Calls)

| # | Called Method | Dependency Type | Description |
|---|--------------|-----------------|-------------|
| 1 | `String.length()` | JDK Core | Built-in string method to get character count for loop bounds. |
| 2 | `String.charAt(int)` | JDK Core | Built-in string method to access individual characters. |
| 3 | `String.substring(int, int)` | JDK Core | Built-in string method to extract truncated substring. |

## 6. Per-Branch Detail Blocks

**Block 1** — [VARIABLE DECLARATION] `(Initial state setup)` (L117-L118)

Initialize the byte-length accumulator and loop index.

| # | Type | Code |
|---|------|------|
| 1 | SET | `int dstlen = 0;` // Running byte-length accumulator, initialized to zero |
| 2 | SET | `for (int i = 0; i < str.length(); i++)` // Loop index starting from 0, iterating through each character |

---

**Block 2** — [CHARACTER EXCHANGE] `(Retrieve current character)` (L119-L120)

Extract the character at the current loop position.

| # | Type | Code |
|---|------|------|
| 1 | SET | `char c = str.charAt(i);` // Retrieve the character at position i |

---

**Block 3** — [IF] `(Single-byte vs multi-byte character classification)` (L121-L124)

Determine whether the current character is single-byte or multi-byte. Single-byte characters contribute 1 to the byte count; all others contribute 2.

| # | Type | Code |
|---|------|------|
| 1 | COND | `if (c <= '~'` // ASCII range: U+0000 to U+007E — [半角数字: half-width digits] |
| 2 | COND | `|| c == '¥'` // Backslash character U+005C — [\] |
| 3 | COND | `|| c == '‾'` // Overline U+203E — [~] |
| 4 | COND | `|| (c >= '｡' && c <= 'ﾟ'))` // Half-width Katakana range U+FF61–U+FF9F — [半角カナ] |
| 5 | SET | `dstlen += 1;` // Single-byte character: add 1 to running byte count |

**Block 3.1** — [ELSE] `(Multi-byte character handling)` (L125-L127)

All characters not matching the single-byte conditions are treated as 2-byte characters (full-width letters, Kanji, Hiragana, full-width punctuation, symbols, etc.).

| # | Type | Code |
|---|------|------|
| 1 | SET | `dstlen += 2;` // Multi-byte character: add 2 to running byte count |

---

**Block 4** — [IF] `(Byte limit exceeded check)` (L128-L131)

After incrementing `dstlen`, check whether the byte limit has been exceeded. If so, truncate and return.

| # | Type | Code |
|---|------|------|
| 1 | COND | `if (dstlen > len)` // Has the accumulated byte count exceeded the target byte length? |
| 2 | RETURN | `return str.substring(0, i);` // Return substring from index 0 to i (exclusive) — the character that caused the overflow is excluded |

**Block 4.1** — [Implicit FALL-THROUGH] `(Within byte limit)` (L132)

If `dstlen <= len`, continue the loop to process the next character.

| # | Type | Code |
|---|------|------|
| 1 | EXEC | *(loop continues — implicit fall-through)* |

---

**Block 5** — [RETURN] `(String fits within byte limit)` (L133)

If the loop completes without exceeding the byte limit (i.e., the entire string fits within `len` bytes), return the original unmodified string.

| # | Type | Code |
|---|------|------|
| 1 | RETURN | `return str;` // Entire string fits within the byte limit; return as-is |

## 7. Glossary

| Term | Type | Business Meaning |
|------|------|------------------|
| `subStringByte` | Method | Byte-length-constrained string truncation utility |
| `str` | Parameter | Source string to be truncated |
| `len` | Parameter | Target maximum byte length |
| `dstlen` | Variable | Running byte-length accumulator — tracks the cumulative byte count as the method scans through characters |
| `i` | Variable | Loop index — current character position in the string (0-based) |
| `c` | Variable | Character extracted from the string at position `i` |
| U+007E | Unicode | Highest code point in the ASCII range (tilde '~'); characters at or below this are single-byte |
| U+005C | Unicode | Backslash character `\`; treated as single-byte |
| U+203E | Unicode | Overline character `~` (widely used in Japanese typography as a macron or negation mark); treated as single-byte |
| U+FF61–U+FF9F | Unicode | Half-width Katakana range — Japanese phonetic characters stored in single byte |
| 半角数字 | Japanese | Half-width digits — ASCII-style numerals (0–9) stored in 1 byte |
| \ | Japanese comment | Backslash — 1-byte character in Japanese encodings |
| 半角カナ | Japanese | Half-width Katakana — narrow-width Japanese phonetic characters (U+FF61–U+FF9F) stored in 1 byte |
| Full-width | Encoding concept | Characters stored as 2 bytes in Japanese encodings (EUC-JP, Shift_JIS), including Kanji, Hiragana, full-width Katakana, full-width Latin/Cyrillic/Greek, full-width punctuation, and symbols |
| Byte length | Concept | The number of bytes a string occupies when encoded in a multi-byte encoding (e.g., Shift_JIS or EUC-JP), as opposed to character count which counts Unicode code points |
| JDK Core | Dependency category | Java Development Kit standard library methods (`String.length()`, `String.charAt()`, `String.substring()`) — no external dependencies |
