pack ו־unpack - הדרכה#

pack ו־unpack הם הסריאלייזרים ברמה הנמוכה של Perl. הם ממירים בין ערכי Perl לבין מחרוזות הבתים הגולמיות שפורמטים בינאריים - פרוטוקולי רשת, כותרות קובץ, struct של C, רשומות ברוחב קבוע - נושאים בפועל על החוט.

רוב מתכנתי Perl נתקלים בהם לעיתים רחוקות ושוכחים אותם במהירות. הדרכה זו נמצאת כאן כדי שכאשר תיתקלו בהם, כבר תכירו את צורת הבעיה.

מתי צריך את pack ו־unpack#

פנו אליהם כאשר אתם:

  • מדברים פרוטוקול חוט - שאילתות DNS, כותרות TCP/IP, פריימים של MQTT, כל דבר עם ״big-endian 16-bit length״ במפרט שלו.

  • מפענחים פורמט קובץ בינארי - PNG, GIF, WAV, ELF, GZip, Intel HEX, כל הפורמטים שארבעת הבתים הראשונים שלהם הם מספר קסם ולאחריו שדות מספריים ידועים.

  • חותכים רשומות טקסט ברוחב קבוע - קובצי log, פנקסי הנהלת חשבונות, דוחות מ־mainframe. unpack נקי יותר מקריאות substr משורשרות ומטפל באי־בהירות של שדה ריק ש־split מקריס.

  • מעבירים נתונים לקריאת מערכת - syscall, ioctl, והבנאי הנדיר sockaddr_* מצפים לבתים מסודרים כ־struct של C.

לסריאליזציה של טקסט (JSON, YAML, CSV, XML), פנו למודול המתאים במקום. pack מיועד לבינארי.

כיצד הדרכה זו מאורגנת#

כל פרק מלמד נושא אחד ועומד בפני עצמו. אפשר לקרוא אותם לפי הסדר, או לקפוץ לזה שעונה על שאלתכם.

  • בתים ורוחבים - ספירת בתים, הוראות מספר שלם ברוחב קבוע, ההבחנה בין native ל־fixed.

  • Endianness - סדר בתים, המתאמים < / >, הקיצורים הניידים n / N / v / V.

  • מחרוזות - a / A / Z (בינארי, טקסט, C string), מחרוזות ביטים, מחרוזות hex.

  • קיבוץ ומונים - קבוצות (), מוני חזרות, צורות […], הוראת קידומת־מונה־פריטים /.

  • מיקום - x / X / @ / . לתנועה בתוך תבנית מבלי לייצר ערך.

  • פרוטוקולי רשת - בניית ופענוח כותרת שאילתת DNS.

  • פורמטים של קבצים - פענוח כותרת GIF, הקובץ הקנוני של ״מספר קסם בתוספת שדות קבועים״.

שני פרקים (network-protocols, file-formats) הם דוגמאות מלאות ומפותחות. עברו על אחד מהם לאחר שקראתם די מן הפרקים האחרים כדי לזהות את ההוראות.

סיבוב ראשון הלוך־ושוב#

הדוגמה השימושית הקצרה ביותר של pack ו־unpack עובדים יחדיו - אריזת כתובת IP מנוקדת לארבעה בתים גולמיים וקריאתה חזרה:

my $raw    = pack   "C4", 192, 168, 1, 42;   # "\xc0\xa8\x01\x2a"
my @octets = unpack "C4", $raw;              # (192, 168, 1, 42)

C אורז בית אחד ללא־סימן; C4 אורז ארבעה כאלה ברצף. בדרך החוצה, אותה תבנית מושכת אותם חזרה לרשימה של ארבעה מספרים שלמים. כל פורמט בינארי מורכב יותר בנוי כשכבה על גבי הרעיון הזה.

מוסכמות בדוגמאות#

  • פלט צפוי מופיע כהערת # באותה שורה כמו הביטוי שייצר אותו, או ישירות מתחת לבלוק הקוד.

  • הדוגמאות רצות תחת מפרש מוכוון־בתים - ללא use utf8, ללא פרגמת use open המשנה שכבות. אם מופיע מטפל קובץ, יש להניח ש־binmode $fh כבר נקרא.

  • קבועים רב־בתיים כמו "\xc0\xa8\x01\x2a" נכתבים עם hex escapes במקום ערכי בתים גולמיים כך שהטקסט המודפס תואם את מה שרואים בקוד.